+ sa2cidr(*this, sa, range);
+}
+
+irc::sockets::cidr_mask::cidr_mask(const std::string& mask)
+{
+ std::string::size_type bits_chars = mask.rfind('/');
+ irc::sockets::sockaddrs sa;
+
+ if (bits_chars == std::string::npos)
+ {
+ irc::sockets::aptosa(mask, 0, sa);
+ sa2cidr(*this, sa, 128);
+ }
+ else
+ {
+ unsigned char range = ConvToNum<unsigned char>(mask.substr(bits_chars + 1));
+ irc::sockets::aptosa(mask.substr(0, bits_chars), 0, sa);
+ sa2cidr(*this, sa, range);
+ }
+}
+
+std::string irc::sockets::cidr_mask::str() const
+{
+ irc::sockets::sockaddrs sa;
+ sa.sa.sa_family = type;
+
+ unsigned char* base;
+ size_t len;
+ switch (type)
+ {
+ case AF_INET:
+ base = (unsigned char*)&sa.in4.sin_addr;
+ len = 4;
+ break;
+
+ case AF_INET6:
+ base = (unsigned char*)&sa.in6.sin6_addr;
+ len = 16;
+ break;
+
+ case AF_UNIX:
+ return sa.un.sun_path;
+
+ default:
+ // If we have reached this point then we have encountered a bug.
+ ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "BUG: irc::sockets::cidr_mask::str(): socket type %d is unknown!", type);
+ return "<unknown>";
+ }
+
+ memcpy(base, bits, len);
+ return sa.addr() + "/" + ConvToStr((int)length);
+}
+
+bool irc::sockets::cidr_mask::operator==(const cidr_mask& other) const
+{
+ return type == other.type && length == other.length &&
+ 0 == memcmp(bits, other.bits, 16);
+}
+
+bool irc::sockets::cidr_mask::operator<(const cidr_mask& other) const
+{
+ if (type != other.type)
+ return type < other.type;
+ if (length != other.length)
+ return length < other.length;
+ return memcmp(bits, other.bits, 16) < 0;
+}
+
+bool irc::sockets::cidr_mask::match(const irc::sockets::sockaddrs& addr) const
+{
+ if (addr.family() != type)
+ return false;
+ irc::sockets::cidr_mask tmp(addr, length);
+ return tmp == *this;