]> git.netwichtig.de Git - user/henk/code/inspircd.git/commitdiff
Convert CIDR matching and wildcard matching to operate on std::strings
authorbrain <brain@e03df62e-2008-0410-955e-edbf42e46eb7>
Fri, 9 May 2008 17:24:50 +0000 (17:24 +0000)
committerbrain <brain@e03df62e-2008-0410-955e-edbf42e46eb7>
Fri, 9 May 2008 17:24:50 +0000 (17:24 +0000)
git-svn-id: http://svn.inspircd.org/repository/trunk/inspircd@9681 e03df62e-2008-0410-955e-edbf42e46eb7

include/socket.h
include/testsuite.h
include/wildcard.h
src/cidr.cpp
src/inspircd.cpp
src/testsuite.cpp
src/wildcard.cpp

index 7ff40794c7928574f6e15af9555164466d461297..e6ea1615df0e79fe2adfa6b37090084e5c17dedb 100644 (file)
@@ -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.
                 * 
index 27472faa95f3a9e254b9880f21484c335946a25b..45456aa4714a5247ac67cf6bbf0f6cf662d7452f 100644 (file)
@@ -25,6 +25,7 @@ class TestSuite : public Extensible
        ~TestSuite();
 
        bool DoThreadTests();
+       bool DoWildTests();
 };
 
 #endif
index 0d5e3e0aa119d09c5979251f514b43294d2b6b5e..8c99b8dcaf5abbf1eaff12ef621657411f530189 100644 (file)
  * @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);
 
index 1288d269b1b4b3aa95d78cfbfb3ef6cafefaec55..90654ee820e70da4a5d95c27bd4c8dc00868cb49 100644 (file)
@@ -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);
 }
 
 
-
index d152e5d1a24b934cd4c44fc464329fc95bda416d..97e2c77e352d9da2fecc4f477caaf606687b4484 100644 (file)
@@ -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);
index 02d806480781e99d3e93cac1c8b0926b43ce1d80..a4d8c871c29f507cb6a5412307e24640c85a3d92 100644 (file)
@@ -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;
index 0e6e8a874eaf4e3d6e309b1fe9ba0a51c3636137..9846b7d4f4213ee603cc6766cbacaad4b6afdf96 100644 (file)
 
 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);
 }