summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbrain <brain@e03df62e-2008-0410-955e-edbf42e46eb7>2008-05-09 17:24:50 +0000
committerbrain <brain@e03df62e-2008-0410-955e-edbf42e46eb7>2008-05-09 17:24:50 +0000
commit03ef675c0dd4742464d8ad93888e98721a044108 (patch)
treeb3c65ebc4118b415a3f339f5ac852d5b58bc9f8b
parentfc349c873818311b6a45aeaace624a3cd3ec96f2 (diff)
Convert CIDR matching and wildcard matching to operate on std::strings
git-svn-id: http://svn.inspircd.org/repository/trunk/inspircd@9681 e03df62e-2008-0410-955e-edbf42e46eb7
-rw-r--r--include/socket.h6
-rw-r--r--include/testsuite.h1
-rw-r--r--include/wildcard.h8
-rw-r--r--src/cidr.cpp73
-rw-r--r--src/inspircd.cpp2
-rw-r--r--src/testsuite.cpp48
-rw-r--r--src/wildcard.cpp88
7 files changed, 114 insertions, 112 deletions
diff --git a/include/socket.h b/include/socket.h
index 7ff40794c..e6ea1615d 100644
--- a/include/socket.h
+++ b/include/socket.h
@@ -81,7 +81,7 @@ namespace irc
* @returns True if the first mask_bits of address matches the first
* mask_bits of mask.
*/
- CoreExport bool MatchCIDRBits(unsigned char* address, unsigned char* mask, unsigned int mask_bits);
+ CoreExport bool MatchCIDRBits(const unsigned char* address, const unsigned char* mask, unsigned int mask_bits);
/** Match CIDR, without matching username/nickname parts.
*
@@ -92,7 +92,7 @@ namespace irc
* @param cidr_mask The human readable mask, e.g. 1.2.0.0/16
* @return True if the mask matches the address
*/
- CoreExport bool MatchCIDR(const char* address, const char* cidr_mask);
+ CoreExport bool MatchCIDR(const std::string &address, const std::string &cidr_mask);
/** Match CIDR, including an optional username/nickname part.
*
@@ -105,7 +105,7 @@ namespace irc
* @param cidr_mask The human readable mask, e.g. *\@1.2.0.0/16
* @return True if the mask matches the address
*/
- CoreExport bool MatchCIDR(const char* address, const char* cidr_mask, bool match_with_username);
+ CoreExport bool MatchCIDR(const std::string &address, const std::string &cidr_mask, bool match_with_username);
/** Convert an insp_inaddr into human readable form.
*
diff --git a/include/testsuite.h b/include/testsuite.h
index 27472faa9..45456aa47 100644
--- a/include/testsuite.h
+++ b/include/testsuite.h
@@ -25,6 +25,7 @@ class TestSuite : public Extensible
~TestSuite();
bool DoThreadTests();
+ bool DoWildTests();
};
#endif
diff --git a/include/wildcard.h b/include/wildcard.h
index 0d5e3e0aa..8c99b8dca 100644
--- a/include/wildcard.h
+++ b/include/wildcard.h
@@ -16,21 +16,21 @@
* @param mask the mask to check against
* @return true if the strings match
*/
-CoreExport bool match(const char *str, const char *mask);
+CoreExport bool match(const std::string &str, const std::string &mask);
/** Match a string against a mask, and define wether or not to use CIDR rules
* @param str The string to check
* @param mask the mask to check against
* @param use_cidr_match True if CIDR matching rules should be applied first
* @return true if the strings match
*/
-CoreExport bool match(const char *str, const char *mask, bool use_cidr_match);
+CoreExport bool match(const std::string &str, const std::string &mask, bool use_cidr_match);
/** Match a string against a mask, defining wether case sensitivity applies.
* @param str The string to check
* @param mask the mask to check against
* @param case_sensitive True if the match is case sensitive
* @return True if the strings match
*/
-CoreExport bool match(bool case_sensitive, const char *str, const char *mask);
+CoreExport bool match(bool case_sensitive, const std::string &str, const std::string &mask);
/** Match a string against a mask, defining wether case sensitivity applies,
* and defining wether or not to use CIDR rules first.
* @param case_sensitive True if the match is case sensitive
@@ -39,5 +39,5 @@ CoreExport bool match(bool case_sensitive, const char *str, const char *mask);
* @param use_cidr_match True if CIDR matching rules should be applied first
* @return true if the strings match
*/
-CoreExport bool match(bool case_sensitive, const char *str, const char *mask, bool use_cidr_match);
+CoreExport bool match(bool case_sensitive, const std::string &str, const std::string &mask, bool use_cidr_match);
diff --git a/src/cidr.cpp b/src/cidr.cpp
index 1288d269b..90654ee82 100644
--- a/src/cidr.cpp
+++ b/src/cidr.cpp
@@ -33,7 +33,7 @@ const unsigned char inverted_bits[8] = { 0x00, /* 00000000 - 0 bits - never actu
/* Match raw bytes using CIDR bit matching, used by higher level MatchCIDR() */
-bool irc::sockets::MatchCIDRBits(unsigned char* address, unsigned char* mask, unsigned int mask_bits)
+bool irc::sockets::MatchCIDRBits(const unsigned char* address, const unsigned char* mask, unsigned int mask_bits)
{
unsigned int divisor = mask_bits / 8; /* Number of whole bytes in the mask */
unsigned int modulus = mask_bits % 8; /* Remaining bits in the mask after whole bytes are dealt with */
@@ -53,7 +53,7 @@ bool irc::sockets::MatchCIDRBits(unsigned char* address, unsigned char* mask, un
}
/* Match CIDR, but dont attempt to match() against leading *!*@ sections */
-bool irc::sockets::MatchCIDR(const char* address, const char* cidr_mask)
+bool irc::sockets::MatchCIDR(const std::string &address, const std::string &cidr_mask)
{
return MatchCIDR(address, cidr_mask, false);
}
@@ -65,12 +65,14 @@ bool irc::sockets::MatchCIDR(const char* address, const char* cidr_mask)
* This will also attempt to match any leading usernames or nicknames on the mask, using
* match(), when match_with_username is true.
*/
-bool irc::sockets::MatchCIDR(const char* address, const char* cidr_mask, bool match_with_username)
+bool irc::sockets::MatchCIDR(const std::string &address, const std::string &cidr_mask, bool match_with_username)
{
unsigned char addr_raw[16];
unsigned char mask_raw[16];
unsigned int bits = 0;
- char* mask = NULL;
+
+ std::string address_copy;
+ std::string cidr_copy;
/* The caller is trying to match ident@<mask>/bits.
* Chop off the ident@ portion, use match() on it
@@ -78,69 +80,39 @@ bool irc::sockets::MatchCIDR(const char* address, const char* cidr_mask, bool ma
*/
if (match_with_username)
{
- /* Duplicate the strings, and try to find the position
- * of the @ symbol in each
- */
- char* address_dupe = strdup(address);
- char* cidr_dupe = strdup(cidr_mask);
-
/* Use strchr not strrchr, because its going to be nearer to the left */
- char* username_mask_pos = strrchr(cidr_dupe, '@');
- char* username_addr_pos = strrchr(address_dupe, '@');
+ std::string::size_type username_mask_pos = cidr_mask.rfind('@');
+ std::string::size_type username_addr_pos = address.rfind('@');
/* Both strings have an @ symbol in them */
- if (username_mask_pos && username_addr_pos)
+ if (username_mask_pos != std::string::npos && username_addr_pos != std::string::npos)
{
- /* Zero out the location of the @ symbol */
- *username_mask_pos = *username_addr_pos = 0;
-
/* Try and match() the strings before the @
* symbols, and recursively call MatchCIDR without
* username matching enabled to match the host part.
*/
- bool result = (match(address_dupe, cidr_dupe) && MatchCIDR(username_addr_pos + 1, username_mask_pos + 1, false));
-
- /* Free the stuff we created */
- free(address_dupe);
- free(cidr_dupe);
-
- /* Return a result */
- return result;
+ return (match(address.substr(0, username_addr_pos), cidr_mask.substr(0, username_mask_pos)) &&
+ MatchCIDR(address.substr(username_addr_pos + 1), cidr_mask.substr(username_mask_pos + 1), false));
}
else
{
- /* One or both didnt have an @ in,
- * just match as CIDR
- */
- free(address_dupe);
- free(cidr_dupe);
- mask = strdup(cidr_mask);
+ address_copy = address.substr(username_addr_pos + 1);
+ cidr_copy = cidr_mask.substr(username_mask_pos + 1);
}
}
- else
- {
- /* Make a copy of the cidr mask string,
- * we're going to change it
- */
- mask = strdup(cidr_mask);
- }
in_addr address_in4;
in_addr mask_in4;
+ std::string::size_type bits_chars = cidr_copy.rfind('/');
- /* Use strrchr for this, its nearer to the right */
- char* bits_chars = strrchr(mask,'/');
-
- if (bits_chars)
+ if (bits_chars != std::string::npos)
{
- bits = atoi(bits_chars + 1);
- *bits_chars = 0;
+ bits = atoi(cidr_copy.substr(bits_chars + 1).c_str());
}
else
{
/* No 'number of bits' field! */
- free(mask);
return false;
}
@@ -148,9 +120,9 @@ bool irc::sockets::MatchCIDR(const char* address, const char* cidr_mask, bool ma
in6_addr address_in6;
in6_addr mask_in6;
- if (inet_pton(AF_INET6, address, &address_in6) > 0)
+ if (inet_pton(AF_INET6, address_copy.c_str(), &address_in6) > 0)
{
- if (inet_pton(AF_INET6, mask, &mask_in6) > 0)
+ if (inet_pton(AF_INET6, cidr_copy.c_str(), &mask_in6) > 0)
{
memcpy(&addr_raw, &address_in6.s6_addr, 16);
memcpy(&mask_raw, &mask_in6.s6_addr, 16);
@@ -163,15 +135,14 @@ bool irc::sockets::MatchCIDR(const char* address, const char* cidr_mask, bool ma
/* The address was valid ipv6, but the mask
* that goes with it wasnt.
*/
- free(mask);
return false;
}
}
else
#endif
- if (inet_pton(AF_INET, address, &address_in4) > 0)
+ if (inet_pton(AF_INET, address_copy.c_str(), &address_in4) > 0)
{
- if (inet_pton(AF_INET, mask, &mask_in4) > 0)
+ if (inet_pton(AF_INET, cidr_copy.c_str(), &mask_in4) > 0)
{
memcpy(&addr_raw, &address_in4.s_addr, 4);
memcpy(&mask_raw, &mask_in4.s_addr, 4);
@@ -184,21 +155,17 @@ bool irc::sockets::MatchCIDR(const char* address, const char* cidr_mask, bool ma
/* The address was valid ipv4,
* but the mask that went with it wasnt.
*/
- free(mask);
return false;
}
}
else
{
/* The address was neither ipv4 or ipv6 */
- free(mask);
return false;
}
/* Low-level-match the bits in the raw data */
- free(mask);
return MatchCIDRBits(addr_raw, mask_raw, bits);
}
-
diff --git a/src/inspircd.cpp b/src/inspircd.cpp
index d152e5d1a..97e2c77e3 100644
--- a/src/inspircd.cpp
+++ b/src/inspircd.cpp
@@ -705,7 +705,7 @@ InspIRCd::InspIRCd(int argc, char** argv)
* e.g. we are restarting, or being launched by cron. Dont kill parent, and dont
* close stdin/stdout
*/
- if (!do_nofork)
+ if ((!do_nofork) && (!do_testsuite))
{
fclose(stdin);
fclose(stderr);
diff --git a/src/testsuite.cpp b/src/testsuite.cpp
index 02d806480..a4d8c871c 100644
--- a/src/testsuite.cpp
+++ b/src/testsuite.cpp
@@ -16,6 +16,7 @@
#include "inspircd.h"
#include "testsuite.h"
#include "threadengine.h"
+#include "wildcard.h"
#include <iostream>
using namespace std;
@@ -46,9 +47,7 @@ TestSuite::TestSuite(InspIRCd* Instance) : ServerInstance(Instance)
cout << "\n\n*** STARTING TESTSUITE ***\n";
std::string modname;
- std::string choice;
-
- ServerInstance->SE->Blocking(fileno(stdin));
+ char choice;
while (1)
{
@@ -56,13 +55,17 @@ TestSuite::TestSuite(InspIRCd* Instance) : ServerInstance(Instance)
cout << "(2) Load a module\n";
cout << "(3) Unload a module\n";
cout << "(4) Threading tests\n";
+ cout << "(5) Wildcard and CIDR tests\n";
cout << endl << "(X) Exit test suite\n";
cout << "\nChoice: ";
cin >> choice;
- switch (*choice.begin())
+ if (!choice)
+ continue;
+
+ switch (choice)
{
case '1':
FOREACH_MOD(I_OnRunTestSuite, OnRunTestSuite());
@@ -80,6 +83,9 @@ TestSuite::TestSuite(InspIRCd* Instance) : ServerInstance(Instance)
case '4':
cout << (DoThreadTests() ? "\nSUCCESS!\n" : "\nFAILURE\n");
break;
+ case '5':
+ cout << (DoWildTests() ? "\nSUCCESS!\n" : "\nFAILURE\n");
+ break;
case 'X':
return;
break;
@@ -91,6 +97,40 @@ TestSuite::TestSuite(InspIRCd* Instance) : ServerInstance(Instance)
}
}
+/* Test that x matches y with match() */
+#define WCTEST(x, y) cout << "match(\"" << x << "\",\"" << y "\") " << ((passed = (match(x, y) || passed)) ? " SUCCESS!\n" : " FAILURE\n")
+/* Test that x does not match y with match() */
+#define WCTESTNOT(x, y) cout << "!match(\"" << x << "\",\"" << y "\") " << ((passed = ((!match(x, y)) || passed)) ? " SUCCESS!\n" : " FAILURE\n")
+
+/* Test that x matches y with match() and cidr enabled */
+#define CIDRTEST(x, y) cout << "match(\"" << x << "\",\"" << y "\", true) " << ((passed = (match(x, y, true) || passed)) ? " SUCCESS!\n" : " FAILURE\n")
+/* Test that x does not match y with match() and cidr enabled */
+#define CIDRTESTNOT(x, y) cout << "!match(\"" << x << "\",\"" << y "\", true) " << ((passed = ((!match(x, y, true)) || passed)) ? " SUCCESS!\n" : " FAILURE\n")
+
+bool TestSuite::DoWildTests()
+{
+ cout << "\n\nWildcard and CIDR tests\n\n";
+ bool passed = false;
+
+ WCTEST("foobar", "*");
+ WCTEST("foobar", "foo*");
+ WCTEST("foobar", "*bar");
+ WCTEST("foobar", "foo??r");
+
+ WCTESTNOT("foobar", "bazqux");
+ WCTESTNOT("foobar", "*qux");
+ WCTESTNOT("foobar", "foo*x");
+ WCTESTNOT("foobar", "baz*");
+
+ CIDRTEST("brain@1.2.3.4", "*@1.2.0.0/16");
+ CIDRTEST("brain@1.2.3.4", "*@1.2.3.0/24");
+
+ CIDRTESTNOT("brain@1.2.3.4", "x*@1.2.0.0/16");
+ CIDRTESTNOT("brain@1.2.3.4", "*@1.3.4.0/24");
+
+ return passed;
+}
+
bool TestSuite::DoThreadTests()
{
std::string anything;
diff --git a/src/wildcard.cpp b/src/wildcard.cpp
index 0e6e8a874..9846b7d4f 100644
--- a/src/wildcard.cpp
+++ b/src/wildcard.cpp
@@ -19,42 +19,41 @@
using irc::sockets::MatchCIDR;
-// Wed 27 Apr 2005 - Brain
-// I've taken our our old wildcard routine -
-// although comprehensive, it was topheavy and very
-// slow, and ate masses of cpu when doing lots of
-// comparisons. This is the 'de-facto' routine used
-// by many, nobody really knows who wrote it first
-// or what license its under, i've seen examples of it
-// (unattributed to any author) all over the 'net.
-// For now, we'll just consider this public domain.
-
-CoreExport bool csmatch(const char *str, const char *mask)
+/* Rewritten to operate on more effective C++ std::string types
+ * rather than char* to avoid data copies.
+ * - Brain
+ */
+
+CoreExport bool csmatch(const std::string &str, const std::string &mask)
{
- unsigned char *cp = NULL, *mp = NULL;
- unsigned char* string = (unsigned char*)str;
- unsigned char* wild = (unsigned char*)mask;
+ std::string::const_iterator cp, mp;
+
+ //unsigned char *cp = NULL, *mp = NULL;
+ //unsigned char* string = (unsigned char*)str;
+ //unsigned char* wild = (unsigned char*)mask;
+
+ std::string::const_iterator wild = mask.begin();
+ std::string::const_iterator string = str.begin();
- while ((*string) && (*wild != '*'))
+ while ((string != str.end()) && (wild != mask.end()) && (*wild != '*'))
{
if ((*wild != *string) && (*wild != '?'))
- {
return 0;
- }
+
wild++;
string++;
}
- while (*string)
+ while (string != str.end())
{
if (*wild == '*')
{
- if (!*++wild)
- {
+ if (++wild == mask.end())
return 1;
- }
+
mp = wild;
- cp = string+1;
+ cp = string;
+ cp++;
}
else
if ((*wild == *string) || (*wild == '?'))
@@ -70,43 +69,40 @@ CoreExport bool csmatch(const char *str, const char *mask)
}
- while (*wild == '*')
- {
+ while ((wild != mask.end()) && (*wild == '*'))
wild++;
- }
- return !*wild;
+ return wild == mask.end();
}
-CoreExport bool match(const char *str, const char *mask)
+CoreExport bool match(const std::string &str, const std::string &mask)
{
- unsigned char *cp = NULL, *mp = NULL;
- unsigned char* string = (unsigned char*)str;
- unsigned char* wild = (unsigned char*)mask;
+ std::string::const_iterator cp, mp;
+ std::string::const_iterator wild = mask.begin();
+ std::string::const_iterator string = str.begin();
- while ((*string) && (*wild != '*'))
+ while ((string != str.end()) && (wild != mask.end()) && (*wild != '*'))
{
- if ((lowermap[*wild] != lowermap[*string]) && (*wild != '?'))
- {
+ if ((lowermap[(unsigned char)*wild] != lowermap[(unsigned char)*string]) && (*wild != '?'))
return 0;
- }
+
wild++;
string++;
}
- while (*string)
+ while (string != str.end())
{
if (*wild == '*')
{
- if (!*++wild)
- {
+ if (++wild == mask.end())
return 1;
- }
+
mp = wild;
- cp = string+1;
+ cp = string;
+ cp++;
}
else
- if ((lowermap[*wild] == lowermap[*string]) || (*wild == '?'))
+ if ((lowermap[(unsigned char)*wild] == lowermap[(unsigned char)*string]) || (*wild == '?'))
{
wild++;
string++;
@@ -119,23 +115,21 @@ CoreExport bool match(const char *str, const char *mask)
}
- while (*wild == '*')
- {
+ while ((wild != mask.end()) && (*wild == '*'))
wild++;
- }
- return !*wild;
+ return wild == mask.end();
}
/* Overloaded function that has the option of using cidr */
-CoreExport bool match(const char *str, const char *mask, bool use_cidr_match)
+CoreExport bool match(const std::string &str, const std::string &mask, bool use_cidr_match)
{
if (use_cidr_match && MatchCIDR(str, mask, true))
return true;
return match(str, mask);
}
-CoreExport bool match(bool case_sensitive, const char *str, const char *mask, bool use_cidr_match)
+CoreExport bool match(bool case_sensitive, const std::string &str, const std::string &mask, bool use_cidr_match)
{
if (use_cidr_match && MatchCIDR(str, mask, true))
return true;
@@ -143,7 +137,7 @@ CoreExport bool match(bool case_sensitive, const char *str, const char *mask, bo
return case_sensitive ? csmatch(str, mask) : match(str, mask);
}
-CoreExport bool match(bool case_sensitive, const char *str, const char *mask)
+CoreExport bool match(bool case_sensitive, const std::string &str, const std::string &mask)
{
return case_sensitive ? csmatch(str, mask) : match(str, mask);
}