summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSadie Powell <sadie@witchery.services>2020-12-22 05:48:53 +0000
committerSadie Powell <sadie@witchery.services>2020-12-22 05:49:23 +0000
commit744efed4e2ca5b1957e541238ed14e9931019479 (patch)
tree62ec85c0ede95c9e9150708fae3893d2ab911fc7
parent79cc3caeb8f485ab0bdc405ab4ead54a25ab097c (diff)
Add support for multiple hostmasks in <cgiirc:mask>.
-rw-r--r--docs/conf/modules.conf.example21
-rw-r--r--src/modules/m_cgiirc.cpp70
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
{