diff options
author | rubidium <rubidium@openttd.org> | 2009-04-04 00:47:08 +0000 |
---|---|---|
committer | rubidium <rubidium@openttd.org> | 2009-04-04 00:47:08 +0000 |
commit | 2fd9f0fffa0d7e13d098f29fc04b8028adce8acf (patch) | |
tree | a96b39b4df230207ef70cb1fad7e6f23b98e34b5 /src/network/core | |
parent | e460d3f4d02c72f6b661a722b70ddaaa48bc5e92 (diff) | |
download | openttd-2fd9f0fffa0d7e13d098f29fc04b8028adce8acf.tar.xz |
(svn r15946) -Codechange: move netmask matching to NetworkAddress and add some support for IPv6 netmask matching.
Diffstat (limited to 'src/network/core')
-rw-r--r-- | src/network/core/address.cpp | 56 | ||||
-rw-r--r-- | src/network/core/address.h | 8 |
2 files changed, 63 insertions, 1 deletions
diff --git a/src/network/core/address.cpp b/src/network/core/address.cpp index 316a8b98a..a8ba5c076 100644 --- a/src/network/core/address.cpp +++ b/src/network/core/address.cpp @@ -89,6 +89,60 @@ const sockaddr_storage *NetworkAddress::GetAddress() return &this->address; } +bool NetworkAddress::IsInNetmask(char *netmask) +{ + /* Resolve it if we didn't do it already */ + if (!this->IsResolved()) this->GetAddress(); + + int cidr = this->address.ss_family == AF_INET ? 32 : 128; + + NetworkAddress mask_address; + + /* Check for CIDR separator */ + char *chr_cidr = strchr(netmask, '/'); + if (chr_cidr != NULL) { + int tmp_cidr = atoi(chr_cidr + 1); + + /* Invalid CIDR, treat as single host */ + if (tmp_cidr > 0 || tmp_cidr < cidr) cidr = tmp_cidr; + + /* Remove and then replace the / so that NetworkAddress works on the IP portion */ + *chr_cidr = '\0'; + mask_address = NetworkAddress(netmask, 0, this->address.ss_family); + *chr_cidr = '/'; + } else { + mask_address = NetworkAddress(netmask, 0, this->address.ss_family); + } + + if (mask_address.GetAddressLength() == 0) return false; + + uint32 *ip; + uint32 *mask; + switch (this->address.ss_family) { + case AF_INET: + ip = &((struct sockaddr_in*)&this->address)->sin_addr.s_addr; + mask = &((struct sockaddr_in*)&mask_address.address)->sin_addr.s_addr; + break; + + case AF_INET6: + ip = ((struct sockaddr_in6*)&this->address)->sin6_addr.s6_addr32; + mask = ((struct sockaddr_in6*)&mask_address.address)->sin6_addr.s6_addr32; + break; + + default: + NOT_REACHED(); + } + + while (cidr > 0) { + uint32 msk = cidr >= 32 ? -1 : htonl(-(1 << (32 - cidr))); + if ((*mask & msk) != (*ip & msk)) return false; + + cidr -= 32; + } + + return true; +} + SOCKET NetworkAddress::Resolve(int family, int socktype, int flags, LoopProc func) { struct addrinfo *ai; @@ -104,7 +158,7 @@ SOCKET NetworkAddress::Resolve(int family, int socktype, int flags, LoopProc fun int e = getaddrinfo(this->GetHostname(), port_name, &hints, &ai); if (e != 0) { - DEBUG(net, 0, "getaddrinfo failed: %s", FS2OTTD(gai_strerror(e))); + DEBUG(net, 0, "getaddrinfo(%s, %s) failed: %s", this->GetHostname(), port_name, FS2OTTD(gai_strerror(e))); return INVALID_SOCKET; } diff --git a/src/network/core/address.h b/src/network/core/address.h index 2b5f7444f..f972a0397 100644 --- a/src/network/core/address.h +++ b/src/network/core/address.h @@ -159,6 +159,14 @@ public: } /** + * Checks whether this IP address is contained by the given netmask. + * @param netmask the netmask in CIDR notation to test against. + * @note netmask without /n assumes all bits need to match. + * @return true if this IP is within the netmask. + */ + bool IsInNetmask(char *netmask); + + /** * Compare the address of this class with the address of another. * @param address the other address. */ |