diff options
author | Sadie Powell <sadie@witchery.services> | 2020-12-22 05:48:53 +0000 |
---|---|---|
committer | Sadie Powell <sadie@witchery.services> | 2020-12-22 05:49:23 +0000 |
commit | 744efed4e2ca5b1957e541238ed14e9931019479 (patch) | |
tree | 62ec85c0ede95c9e9150708fae3893d2ab911fc7 | |
parent | 79cc3caeb8f485ab0bdc405ab4ead54a25ab097c (diff) |
Add support for multiple hostmasks in <cgiirc:mask>.
-rw-r--r-- | docs/conf/modules.conf.example | 21 | ||||
-rw-r--r-- | src/modules/m_cgiirc.cpp | 70 |
2 files changed, 52 insertions, 39 deletions
diff --git a/docs/conf/modules.conf.example b/docs/conf/modules.conf.example index 7b80c902b..30082ead2 100644 --- a/docs/conf/modules.conf.example +++ b/docs/conf/modules.conf.example @@ -375,14 +375,14 @@ # message to the server on connection. For more details please read the # IRCv3 WebIRC specification at: https://ircv3.net/specs/extensions/webirc.html # -# When using this method you must specify a wildcard mask or CIDR range -# to allow gateway connections from and at least one of either a TLS (SSL) -# client certificate fingerprint for the gateway or a password to be -# sent in the WEBIRC command. +# When using this method you must specify one or more wildcard masks +# or CIDR ranges to allow gateway connections from and at least one of +# either a TLS (SSL) client certificate fingerprint for the gateway or +# a password to be sent in the WEBIRC command. # # <cgihost type="webirc" # fingerprint="bd90547b59c1942b85f382bc059318f4c6ca54c5" -# mask="192.0.2.0/24"> +# mask="192.0.2.0/24 198.51.100.*"> # <cgihost type="webirc" # password="$2a$10$WEUpX9GweJiEF1WxBDSkeODBstIBMlVPweQTG9cKM8/Vd58BeM5cW" # hash="bcrypt" @@ -393,13 +393,14 @@ # address in the ident sent by the user. This is not recommended as it # only works with IPv4 connections. # -# When using this method you must specify a wildcard mask or CIDR range to allow -# gateway connections from. You can also optionally configure the static value -# that replaces the IP in the ident to avoid leaking the real IP address of -# gateway clients (defaults to "gateway" if not set). +# When using this method you must specify one or more wildcard masks +# or CIDR ranges to allow gateway connections from. You can also +# optionally configure the static value that replaces the IP in the +# ident to avoid leaking the real IP address of gateway clients +# (defaults to "gateway" if not set). # # <cgihost type="ident" -# mask="198.51.100.0/24" +# mask="198.51.100.0/24 203.0.113.*" # newident="wibble"> # <cgihost type="ident" # mask="*.ident.gateway.example.com" diff --git a/src/modules/m_cgiirc.cpp b/src/modules/m_cgiirc.cpp index 52c24e50a..da89b33eb 100644 --- a/src/modules/m_cgiirc.cpp +++ b/src/modules/m_cgiirc.cpp @@ -39,16 +39,19 @@ enum RPL_WHOISGATEWAY = 350 }; +// One or more hostmask globs or CIDR ranges. +typedef std::vector<std::string> MaskList; + // Encapsulates information about an ident host. class IdentHost { private: - std::string hostmask; + MaskList hostmasks; std::string newident; public: - IdentHost(const std::string& mask, const std::string& ident) - : hostmask(mask) + IdentHost(const MaskList& masks, const std::string& ident) + : hostmasks(masks) , newident(ident) { } @@ -60,10 +63,19 @@ class IdentHost bool Matches(LocalUser* user) const { - if (!InspIRCd::Match(user->GetRealHost(), hostmask, ascii_case_insensitive_map)) - return false; + for (MaskList::const_iterator iter = hostmasks.begin(); iter != hostmasks.end(); ++iter) + { + // Does the user's hostname match this hostmask? + if (InspIRCd::Match(user->GetRealHost(), *iter, ascii_case_insensitive_map)) + return true; - return InspIRCd::MatchCIDR(user->GetIPString(), hostmask, ascii_case_insensitive_map); + // Does the user's IP address match this hostmask? + if (InspIRCd::MatchCIDR(user->GetIPString(), *iter, ascii_case_insensitive_map)) + return true; + } + + // The user didn't match any hostmasks. + return false; } }; @@ -71,14 +83,14 @@ class IdentHost class WebIRCHost { private: - std::string hostmask; + MaskList hostmasks; std::string fingerprint; std::string password; std::string passhash; public: - WebIRCHost(const std::string& mask, const std::string& fp, const std::string& pass, const std::string& hash) - : hostmask(mask) + WebIRCHost(const MaskList& masks, const std::string& fp, const std::string& pass, const std::string& hash) + : hostmasks(masks) , fingerprint(fp) , password(pass) , passhash(hash) @@ -96,26 +108,22 @@ class WebIRCHost if (!fingerprint.empty() && !InspIRCd::TimingSafeCompare(fp, fingerprint)) return false; - // Does the user's hostname match our hostmask? - if (InspIRCd::Match(user->GetRealHost(), hostmask, ascii_case_insensitive_map)) - return true; + for (MaskList::const_iterator iter = hostmasks.begin(); iter != hostmasks.end(); ++iter) + { + // Does the user's hostname match this hostmask? + if (InspIRCd::Match(user->GetRealHost(), *iter, ascii_case_insensitive_map)) + return true; + + // Does the user's IP address match this hostmask? + if (InspIRCd::MatchCIDR(user->GetIPString(), *iter, ascii_case_insensitive_map)) + return true; + } - // Does the user's IP address match our hostmask? - return InspIRCd::MatchCIDR(user->GetIPString(), hostmask, ascii_case_insensitive_map); + // The user didn't match any hostmasks. + return false; } }; -/* - * WEBIRC - * This is used for the webirc method of CGIIRC auth, and is (really) the best way to do these things. - * Syntax: WEBIRC password gateway hostname ip - * Where password is a shared key, gateway is the name of the WebIRC gateway and version (e.g. cgiirc), hostname - * is the resolved host of the client issuing the command and IP is the real IP of the client. - * - * How it works: - * To tie in with the rest of cgiirc module, and to avoid race conditions, /webirc is only processed locally - * and simply sets metadata on the user, which is later decoded on full connect to give something meaningful. - */ class CommandWebIRC : public SplitCommand { public: @@ -289,9 +297,13 @@ class ModuleCgiIRC { ConfigTag* tag = i->second; + MaskList masks; + irc::spacesepstream maskstream(tag->getString("mask")); + for (std::string mask; maskstream.GetToken(mask); ) + masks.push_back(mask); + // Ensure that we have the <cgihost:mask> parameter. - const std::string mask = tag->getString("mask"); - if (mask.empty()) + if (masks.empty()) throw ModuleException("<cgihost:mask> is a mandatory field, at " + tag->getTagLocation()); // Determine what lookup type this host uses. @@ -300,7 +312,7 @@ class ModuleCgiIRC { // The IP address should be looked up from the hex IP address. const std::string newident = tag->getString("newident", "gateway", ServerInstance->IsIdent); - identhosts.push_back(IdentHost(mask, newident)); + identhosts.push_back(IdentHost(masks, newident)); } else if (stdalgo::string::equalsci(type, "webirc")) { @@ -319,7 +331,7 @@ class ModuleCgiIRC tag->getTagLocation().c_str()); } - webirchosts.push_back(WebIRCHost(mask, fingerprint, password, passwordhash)); + webirchosts.push_back(WebIRCHost(masks, fingerprint, password, passwordhash)); } else { |