diff options
-rw-r--r-- | include/users.h | 9 | ||||
-rw-r--r-- | src/users.cpp | 113 |
2 files changed, 117 insertions, 5 deletions
diff --git a/include/users.h b/include/users.h index f098500e3..3edb9a99e 100644 --- a/include/users.h +++ b/include/users.h @@ -661,6 +661,15 @@ class CoreExport User : public connection */ const char* GetIPString(bool translate4in6 = true); + /** Get a CIDR mask from the IP of this user, using a static internal buffer. + * e.g., GetCIDRMask(16) for 223.254.214.52 returns 223.254.0.0/16 + * This may be used for CIDR clone detection, etc. + * + * (XXX, brief note: when we do the sockets rewrite, this should move down a + * level so it may be used on more derived objects. -- w00t) + */ + const char *GetCIDRMask(int range); + /* Write error string */ std::string WriteError; diff --git a/src/users.cpp b/src/users.cpp index f532b60d1..c82c351ab 100644 --- a/src/users.cpp +++ b/src/users.cpp @@ -1098,13 +1098,116 @@ int User::GetProtocolFamily() return sin->sin_family; } -/* - * XXX the duplication here is horrid.. - * do we really need two methods doing essentially the same thing? - */ +const char* User::GetCIDRMask(int range) +{ + static char buf[40]; + + if (this->ip == NULL) + return ""; + + if (range < 0) + throw "Negative range, sorry, no."; + + /* + * Original code written by Oliver Lupton (Om). + * Integrated by me. Thanks. :) -- w00t + */ + switch (this->GetProtocolFamily()) + { +#ifdef SUPPORT_IP6LINKS + case AF_INET6: + { + struct in6_addr v6; + + if(range > 128) + { + printf("Error, range given (%d) larger than address length (128)\n", range); + return 0; + } + + if(inet_pton(AF_INET6, this->GetIPString(), &v6)) + { + /* unsigned char s6_addr[16]; */ + int i; + int bytestoblank; + int extrabits; + char buffer[64]; + + if(range > 0) + { + /* (128 - range) bits must be blanked, so ((128 - range) / 8) of the bytes, working backwards, must be blanked. */ + bytestoblank = (128 - range) / 8; + + /* ((128 - range) % 8) bits of the next byte must also be blanked. */ + extrabits = (128 - range) % 8; + v6.s6_addr[15 - bytestoblank] = (v6.s6_addr[15 - bytestoblank] >> extrabits) << extrabits; + + for(i = 0; i < bytestoblank; i++) + { + v6.s6_addr[15 - i] = 0; + } + } + else + { + for(i = 0; i < 15; i++) + { + v6.s6_addr[i] = 0; + } + } + + sprintf(buf, "%s/%d\n", inet_ntop(AF_INET6, &v6, buffer, 64), range); + return buf; + } + else + { + throw "CIDR mask for v6 failed"; + } + + } + break; +#endif + case AF_INET: + { + struct in_addr v4; + + if (range > 32) + throw "more than 32 bits on an ipv4 connection, can't do that.."; + + if(inet_pton(AF_INET, this->GetIPString(), &v4)) + { + char buffer[16]; + uint32_t temp; + + /* (32 - range) is the number of bits we are *ignoring*. We shift this left and then right to wipe off these bits. */ + + if(range > 0) + { + temp = ntohl(v4.s_addr); + temp = (temp >> (32 - range)) << (32 - range); + v4.s_addr = htonl(temp); + } + else + { + v4.s_addr = 0; + } + + sprintf(buf, "%s/%d\n", inet_ntop(AF_INET, &v4, buffer, 16), range); + return buf; + } + else + { + throw "CIDR mask for v4 failed"; + } + } + break; + } + + return ""; // unused, but oh well +} + const char* User::GetIPString(bool translate4in6) { - static char buf[1024]; + static char buf[40]; if (this->ip == NULL) return ""; |