diff options
-rw-r--r-- | include/socket.h | 6 | ||||
-rw-r--r-- | include/testsuite.h | 1 | ||||
-rw-r--r-- | include/wildcard.h | 8 | ||||
-rw-r--r-- | src/cidr.cpp | 73 | ||||
-rw-r--r-- | src/inspircd.cpp | 2 | ||||
-rw-r--r-- | src/testsuite.cpp | 48 | ||||
-rw-r--r-- | src/wildcard.cpp | 88 |
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); } |