summaryrefslogtreecommitdiff
path: root/src/network/core
diff options
context:
space:
mode:
authorrubidium <rubidium@openttd.org>2009-04-04 00:47:08 +0000
committerrubidium <rubidium@openttd.org>2009-04-04 00:47:08 +0000
commit2fd9f0fffa0d7e13d098f29fc04b8028adce8acf (patch)
treea96b39b4df230207ef70cb1fad7e6f23b98e34b5 /src/network/core
parente460d3f4d02c72f6b661a722b70ddaaa48bc5e92 (diff)
downloadopenttd-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.cpp56
-rw-r--r--src/network/core/address.h8
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.
*/