From 367e76ba89bde0e3fb6c4ae0e64cd3927e0db2f2 Mon Sep 17 00:00:00 2001 From: Ben Longbons Date: Sat, 7 Sep 2013 17:17:55 -0700 Subject: Add IPv4 classes --- src/common/ip.cpp | 111 +++++++++++++++++ src/common/ip.hpp | 150 ++++++++++++++++++++++ src/common/ip_test.cpp | 332 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 593 insertions(+) create mode 100644 src/common/ip.cpp create mode 100644 src/common/ip.hpp create mode 100644 src/common/ip_test.cpp (limited to 'src') diff --git a/src/common/ip.cpp b/src/common/ip.cpp new file mode 100644 index 0000000..4734a8b --- /dev/null +++ b/src/common/ip.cpp @@ -0,0 +1,111 @@ +#include "ip.hpp" +// ip.cpp - Implementation of IP address functions. +// +// Copyright © 2013 Ben Longbons +// +// This file is part of The Mana World (Athena server) +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include "cxxstdio.hpp" + +#include "../poison.hpp" + +bool extract(XString str, IP4Address *rv) +{ + if (str.endswith('.')) + return false; + uint8_t buf[4]; + if (extract(str, record<'.'>(&buf[0], &buf[1], &buf[2], &buf[3]))) + { + *rv = IP4Address(buf); + return true; + } + return false; +} + +bool extract(XString str, IP4Mask *rv) +{ + IP4Address a, m; + unsigned b; + XString l, r; + if (str.endswith('/')) + return false; + if (extract(str, record<'/'>(&l, &r))) + { + // a.b.c.d/e.f.g.h or a.b.c.d/n + if (!extract(l, &a)) + return false; + if (extract(r, &m)) + { + *rv = IP4Mask(a, m); + return true; + } + if (!extract(r, &b) || b > 32) + return false; + } + else + { + // a.b.c.d or a.b.c.d. or a.b.c. or a.b. or a. + if (extract(str, &a)) + { + *rv = IP4Mask(a, IP4_BROADCAST); + return true; + } + if (!str.endswith('.')) + return false; + uint8_t d[4] {}; + if (extract(str, record<'.'>(&d[0], &d[1], &d[2], &d[3]))) + b = 32; + else if (extract(str, record<'.'>(&d[0], &d[1], &d[2]))) + b = 24; + else if (extract(str, record<'.'>(&d[0], &d[1]))) + b = 16; + else if (extract(str, record<'.'>(&d[0]))) + b = 8; + else + return false; + a = IP4Address(d); + } + // a is set; need to construct m from b + if (b == 0) + m = IP4Address(); + else if (b == 32) + m = IP4_BROADCAST; + else + { + uint32_t s = -1; + s <<= (32 - b); + m = IP4Address({ + static_cast(s >> 24), + static_cast(s >> 16), + static_cast(s >> 8), + static_cast(s >> 0), + }); + } + *rv = IP4Mask(a, m); + return true; +} + +VString<15> convert_for_printf(IP4Address a_) +{ + const uint8_t *a = a_.bytes(); + return STRNPRINTF(16, "%hhu.%hhu.%hhu.%hhu", a[0], a[1], a[2], a[3]); +} + +VString<31> convert_for_printf(IP4Mask a) +{ + return STRNPRINTF(32, "%s/%s", + a.addr(), a.mask()); +} diff --git a/src/common/ip.hpp b/src/common/ip.hpp new file mode 100644 index 0000000..e67056c --- /dev/null +++ b/src/common/ip.hpp @@ -0,0 +1,150 @@ +#ifndef TMWA_COMMON_IP_HPP +#define TMWA_COMMON_IP_HPP +// ip.hpp - classes to deal with IP addresses. +// +// Copyright © 2013 Ben Longbons +// +// This file is part of The Mana World (Athena server) +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include "sanity.hpp" + +#include "extract.hpp" +#include "strings.hpp" + +// TODO - in the long run ports belong here also +// and of course, IPv6 stuff. +// But what about unix socket addresses? + +/// Helper function +template +constexpr +bool _ce_a_lt(T (&a)[n], T (&b)[n], size_t i=0) +{ + return (i != n + && (a[i] < b[i] + || (a[i] == b[i] + && _ce_a_lt(a, b, i + 1)))); +} + +/// A 32-bit Ipv4 address. Does not include a port. +/// Guaranteed to be laid out like the network wants. +class IP4Address +{ + uint8_t _addr[4]; +public: + constexpr + IP4Address() + : _addr{} + {} + constexpr explicit + IP4Address(const uint8_t (&a)[4]) + : _addr{a[0], a[1], a[2], a[3]} + {} + + constexpr friend + IP4Address operator & (IP4Address l, IP4Address r) + { + return IP4Address({ + static_cast(l._addr[0] & r._addr[0]), + static_cast(l._addr[1] & r._addr[1]), + static_cast(l._addr[2] & r._addr[2]), + static_cast(l._addr[3] & r._addr[3]), + }); + } + + IP4Address& operator &= (IP4Address m) + { return *this = *this & m; } + + const uint8_t *bytes() const + { return _addr; } + + constexpr friend + bool operator < (IP4Address l, IP4Address r) + { + return _ce_a_lt(l._addr, r._addr); + } + + constexpr friend + bool operator > (IP4Address l, IP4Address r) + { + return _ce_a_lt(r._addr, l._addr); + } + + constexpr friend + bool operator >= (IP4Address l, IP4Address r) + { + return !_ce_a_lt(l._addr, r._addr); + } + + constexpr friend + bool operator <= (IP4Address l, IP4Address r) + { + return !_ce_a_lt(r._addr, l._addr); + } + + constexpr friend + bool operator == (IP4Address l, IP4Address r) + { + return !(l < r || r < l); + } + + constexpr friend + bool operator != (IP4Address l, IP4Address r) + { + return (l < r || r < l); + } +}; + +class IP4Mask +{ + IP4Address _addr, _mask; +public: + constexpr + IP4Mask() : _addr(), _mask() + {} + constexpr + IP4Mask(IP4Address a, IP4Address m) : _addr(a & m), _mask(m) + {} + + constexpr + IP4Address addr() const + { return _addr; } + constexpr + IP4Address mask() const + { return _mask; } + + constexpr + bool covers(IP4Address a) const + { + return (a & _mask) == _addr; + } +}; + + +constexpr +IP4Address IP4_LOCALHOST({127, 0, 0, 1}); +constexpr +IP4Address IP4_BROADCAST({255, 255, 255, 255}); + + +VString<15> convert_for_printf(IP4Address a); +VString<31> convert_for_printf(IP4Mask m); + +bool extract(XString str, IP4Address *iv); + +bool extract(XString str, IP4Mask *iv); + +#endif // TMWA_COMMON_IP_HPP diff --git a/src/common/ip_test.cpp b/src/common/ip_test.cpp new file mode 100644 index 0000000..64a537f --- /dev/null +++ b/src/common/ip_test.cpp @@ -0,0 +1,332 @@ +#include "ip.hpp" + +#include + +#include "cxxstdio.hpp" + +#define CB(X) (std::integral_constant::value) +TEST(ip4addr, cmp) +{ + constexpr static + IP4Address a = IP4_LOCALHOST; + constexpr static + IP4Address b = IP4_BROADCAST; + + EXPECT_FALSE(CB(a < a)); + EXPECT_TRUE (CB(a < b)); + EXPECT_FALSE(CB(b < a)); + EXPECT_FALSE(CB(b < b)); + + EXPECT_FALSE(CB(a > a)); + EXPECT_FALSE(CB(a > b)); + EXPECT_TRUE (CB(b > a)); + EXPECT_FALSE(CB(b > b)); + + EXPECT_TRUE (CB(a <= a)); + EXPECT_TRUE (CB(a <= b)); + EXPECT_FALSE(CB(b <= a)); + EXPECT_TRUE (CB(b <= b)); + + EXPECT_TRUE (CB(a >= a)); + EXPECT_FALSE(CB(a >= b)); + EXPECT_TRUE (CB(b >= a)); + EXPECT_TRUE (CB(b >= b)); + + EXPECT_TRUE (CB(a == a)); + EXPECT_FALSE(CB(a == b)); + EXPECT_FALSE(CB(b == a)); + EXPECT_TRUE (CB(b == b)); + + EXPECT_FALSE(CB(a != a)); + EXPECT_TRUE (CB(a != b)); + EXPECT_TRUE (CB(b != a)); + EXPECT_FALSE(CB(b != b)); +} + +TEST(ip4addr, str) +{ + IP4Address a; + EXPECT_EQ("0.0.0.0", STRNPRINTF(17, "%s", a)); + EXPECT_EQ("127.0.0.1", STRNPRINTF(17, "%s", IP4_LOCALHOST)); + EXPECT_EQ("255.255.255.255", STRNPRINTF(17, "%s", IP4_BROADCAST)); +} + +TEST(ip4addr, extract) +{ + IP4Address a; + EXPECT_TRUE(extract("0.0.0.0", &a)); + EXPECT_EQ("0.0.0.0", STRNPRINTF(16, "%s", a)); + EXPECT_TRUE(extract("127.0.0.1", &a)); + EXPECT_EQ("127.0.0.1", STRNPRINTF(16, "%s", a)); + EXPECT_TRUE(extract("255.255.255.255", &a)); + EXPECT_EQ("255.255.255.255", STRNPRINTF(16, "%s", a)); + EXPECT_TRUE(extract("1.2.3.4", &a)); + EXPECT_EQ("1.2.3.4", STRNPRINTF(16, "%s", a)); + + EXPECT_FALSE(extract("1.2.3.4.5", &a)); + EXPECT_FALSE(extract("1.2.3.4.", &a)); + EXPECT_FALSE(extract("1.2.3.", &a)); + EXPECT_FALSE(extract("1.2.3", &a)); + EXPECT_FALSE(extract("1.2.", &a)); + EXPECT_FALSE(extract("1.2", &a)); + EXPECT_FALSE(extract("1.", &a)); + EXPECT_FALSE(extract("1", &a)); + EXPECT_FALSE(extract("", &a)); +} + + +TEST(ip4mask, body) +{ + IP4Mask m; + EXPECT_EQ(IP4Address(), m.addr()); + EXPECT_EQ(IP4Address(), m.mask()); + m = IP4Mask(IP4_LOCALHOST, IP4_BROADCAST); + EXPECT_EQ(IP4_LOCALHOST, m.addr()); + EXPECT_EQ(IP4_BROADCAST, m.mask()); +} + +TEST(ip4mask, str) +{ + IP4Mask m; + EXPECT_EQ("0.0.0.0/0.0.0.0", STRNPRINTF(33, "%s", m)); + m = IP4Mask(IP4_LOCALHOST, IP4_BROADCAST); + EXPECT_EQ("127.0.0.1/255.255.255.255", STRNPRINTF(33, "%s", m)); +} + +TEST(ip4mask, extract) +{ + IP4Mask m; + EXPECT_FALSE(extract("9.8.7.6/33", &m)); + EXPECT_FALSE(extract("9.8.7.6.5", &m)); + EXPECT_FALSE(extract("9.8.7.6/", &m)); + EXPECT_FALSE(extract("9.8.7", &m)); + EXPECT_FALSE(extract("9.8", &m)); + EXPECT_FALSE(extract("9", &m)); + + EXPECT_TRUE(extract("127.0.0.1", &m)); + EXPECT_EQ("127.0.0.1/255.255.255.255", STRNPRINTF(32, "%s", m)); + EXPECT_TRUE(extract("127.0.0.1.", &m)); + EXPECT_EQ("127.0.0.1/255.255.255.255", STRNPRINTF(32, "%s", m)); + EXPECT_TRUE(extract("127.0.0.", &m)); + EXPECT_EQ("127.0.0.0/255.255.255.0", STRNPRINTF(32, "%s", m)); + EXPECT_TRUE(extract("127.0.", &m)); + EXPECT_EQ("127.0.0.0/255.255.0.0", STRNPRINTF(32, "%s", m)); + EXPECT_TRUE(extract("127.", &m)); + EXPECT_EQ("127.0.0.0/255.0.0.0", STRNPRINTF(32, "%s", m)); + + EXPECT_TRUE(extract("1.2.3.4/255.255.255.255", &m)); + EXPECT_EQ("1.2.3.4/255.255.255.255", STRNPRINTF(32, "%s", m)); + EXPECT_TRUE(extract("1.2.3.0/255.255.255.0", &m)); + EXPECT_EQ("1.2.3.0/255.255.255.0", STRNPRINTF(32, "%s", m)); + EXPECT_TRUE(extract("1.2.0.4/255.255.0.255", &m)); + EXPECT_EQ("1.2.0.4/255.255.0.255", STRNPRINTF(32, "%s", m)); + EXPECT_TRUE(extract("1.2.0.0/255.255.0.0", &m)); + EXPECT_EQ("1.2.0.0/255.255.0.0", STRNPRINTF(32, "%s", m)); + EXPECT_TRUE(extract("1.0.3.4/255.0.255.255", &m)); + EXPECT_EQ("1.0.3.4/255.0.255.255", STRNPRINTF(32, "%s", m)); + EXPECT_TRUE(extract("1.0.3.0/255.0.255.0", &m)); + EXPECT_EQ("1.0.3.0/255.0.255.0", STRNPRINTF(32, "%s", m)); + EXPECT_TRUE(extract("1.0.0.4/255.0.0.255", &m)); + EXPECT_EQ("1.0.0.4/255.0.0.255", STRNPRINTF(32, "%s", m)); + EXPECT_TRUE(extract("1.0.0.0/255.0.0.0", &m)); + EXPECT_EQ("1.0.0.0/255.0.0.0", STRNPRINTF(32, "%s", m)); + EXPECT_TRUE(extract("0.2.3.4/0.255.255.255", &m)); + EXPECT_EQ("0.2.3.4/0.255.255.255", STRNPRINTF(32, "%s", m)); + EXPECT_TRUE(extract("0.2.3.0/0.255.255.0", &m)); + EXPECT_EQ("0.2.3.0/0.255.255.0", STRNPRINTF(32, "%s", m)); + EXPECT_TRUE(extract("0.2.0.4/0.255.0.255", &m)); + EXPECT_EQ("0.2.0.4/0.255.0.255", STRNPRINTF(32, "%s", m)); + EXPECT_TRUE(extract("0.2.0.0/0.255.0.0", &m)); + EXPECT_EQ("0.2.0.0/0.255.0.0", STRNPRINTF(32, "%s", m)); + EXPECT_TRUE(extract("0.0.3.4/0.0.255.255", &m)); + EXPECT_EQ("0.0.3.4/0.0.255.255", STRNPRINTF(32, "%s", m)); + EXPECT_TRUE(extract("0.0.3.0/0.0.255.0", &m)); + EXPECT_EQ("0.0.3.0/0.0.255.0", STRNPRINTF(32, "%s", m)); + EXPECT_TRUE(extract("0.0.0.4/0.0.0.255", &m)); + EXPECT_EQ("0.0.0.4/0.0.0.255", STRNPRINTF(32, "%s", m)); + EXPECT_TRUE(extract("0.0.0.0/0.0.0.0", &m)); + EXPECT_EQ("0.0.0.0/0.0.0.0", STRNPRINTF(32, "%s", m)); + + // please don't do this + EXPECT_TRUE(extract("120.248.200.217/89.57.126.5", &m)); + EXPECT_EQ("88.56.72.1/89.57.126.5", STRNPRINTF(32, "%s", m)); + + EXPECT_TRUE(extract("0.0.0.0/32", &m)); + EXPECT_EQ("0.0.0.0/255.255.255.255", STRNPRINTF(32, "%s", m)); + + EXPECT_TRUE(extract("0.0.0.0/31", &m)); + EXPECT_EQ("0.0.0.0/255.255.255.254", STRNPRINTF(32, "%s", m)); + EXPECT_TRUE(extract("0.0.0.0/30", &m)); + EXPECT_EQ("0.0.0.0/255.255.255.252", STRNPRINTF(32, "%s", m)); + EXPECT_TRUE(extract("0.0.0.0/29", &m)); + EXPECT_EQ("0.0.0.0/255.255.255.248", STRNPRINTF(32, "%s", m)); + EXPECT_TRUE(extract("0.0.0.0/28", &m)); + EXPECT_EQ("0.0.0.0/255.255.255.240", STRNPRINTF(32, "%s", m)); + EXPECT_TRUE(extract("0.0.0.0/27", &m)); + EXPECT_EQ("0.0.0.0/255.255.255.224", STRNPRINTF(32, "%s", m)); + EXPECT_TRUE(extract("0.0.0.0/26", &m)); + EXPECT_EQ("0.0.0.0/255.255.255.192", STRNPRINTF(32, "%s", m)); + EXPECT_TRUE(extract("0.0.0.0/25", &m)); + EXPECT_EQ("0.0.0.0/255.255.255.128", STRNPRINTF(32, "%s", m)); + EXPECT_TRUE(extract("0.0.0.0/24", &m)); + EXPECT_EQ("0.0.0.0/255.255.255.0", STRNPRINTF(32, "%s", m)); + + EXPECT_TRUE(extract("0.0.0.0/23", &m)); + EXPECT_EQ("0.0.0.0/255.255.254.0", STRNPRINTF(32, "%s", m)); + EXPECT_TRUE(extract("0.0.0.0/22", &m)); + EXPECT_EQ("0.0.0.0/255.255.252.0", STRNPRINTF(32, "%s", m)); + EXPECT_TRUE(extract("0.0.0.0/21", &m)); + EXPECT_EQ("0.0.0.0/255.255.248.0", STRNPRINTF(32, "%s", m)); + EXPECT_TRUE(extract("0.0.0.0/20", &m)); + EXPECT_EQ("0.0.0.0/255.255.240.0", STRNPRINTF(32, "%s", m)); + EXPECT_TRUE(extract("0.0.0.0/19", &m)); + EXPECT_EQ("0.0.0.0/255.255.224.0", STRNPRINTF(32, "%s", m)); + EXPECT_TRUE(extract("0.0.0.0/18", &m)); + EXPECT_EQ("0.0.0.0/255.255.192.0", STRNPRINTF(32, "%s", m)); + EXPECT_TRUE(extract("0.0.0.0/17", &m)); + EXPECT_EQ("0.0.0.0/255.255.128.0", STRNPRINTF(32, "%s", m)); + EXPECT_TRUE(extract("0.0.0.0/16", &m)); + EXPECT_EQ("0.0.0.0/255.255.0.0", STRNPRINTF(32, "%s", m)); + + EXPECT_TRUE(extract("0.0.0.0/15", &m)); + EXPECT_EQ("0.0.0.0/255.254.0.0", STRNPRINTF(32, "%s", m)); + EXPECT_TRUE(extract("0.0.0.0/14", &m)); + EXPECT_EQ("0.0.0.0/255.252.0.0", STRNPRINTF(32, "%s", m)); + EXPECT_TRUE(extract("0.0.0.0/13", &m)); + EXPECT_EQ("0.0.0.0/255.248.0.0", STRNPRINTF(32, "%s", m)); + EXPECT_TRUE(extract("0.0.0.0/12", &m)); + EXPECT_EQ("0.0.0.0/255.240.0.0", STRNPRINTF(32, "%s", m)); + EXPECT_TRUE(extract("0.0.0.0/11", &m)); + EXPECT_EQ("0.0.0.0/255.224.0.0", STRNPRINTF(32, "%s", m)); + EXPECT_TRUE(extract("0.0.0.0/10", &m)); + EXPECT_EQ("0.0.0.0/255.192.0.0", STRNPRINTF(32, "%s", m)); + EXPECT_TRUE(extract("0.0.0.0/9", &m)); + EXPECT_EQ("0.0.0.0/255.128.0.0", STRNPRINTF(32, "%s", m)); + EXPECT_TRUE(extract("0.0.0.0/8", &m)); + EXPECT_EQ("0.0.0.0/255.0.0.0", STRNPRINTF(32, "%s", m)); + + EXPECT_TRUE(extract("0.0.0.0/7", &m)); + EXPECT_EQ("0.0.0.0/254.0.0.0", STRNPRINTF(32, "%s", m)); + EXPECT_TRUE(extract("0.0.0.0/6", &m)); + EXPECT_EQ("0.0.0.0/252.0.0.0", STRNPRINTF(32, "%s", m)); + EXPECT_TRUE(extract("0.0.0.0/5", &m)); + EXPECT_EQ("0.0.0.0/248.0.0.0", STRNPRINTF(32, "%s", m)); + EXPECT_TRUE(extract("0.0.0.0/4", &m)); + EXPECT_EQ("0.0.0.0/240.0.0.0", STRNPRINTF(32, "%s", m)); + EXPECT_TRUE(extract("0.0.0.0/3", &m)); + EXPECT_EQ("0.0.0.0/224.0.0.0", STRNPRINTF(32, "%s", m)); + EXPECT_TRUE(extract("0.0.0.0/2", &m)); + EXPECT_EQ("0.0.0.0/192.0.0.0", STRNPRINTF(32, "%s", m)); + EXPECT_TRUE(extract("0.0.0.0/1", &m)); + EXPECT_EQ("0.0.0.0/128.0.0.0", STRNPRINTF(32, "%s", m)); + EXPECT_TRUE(extract("0.0.0.0/0", &m)); + EXPECT_EQ("0.0.0.0/0.0.0.0", STRNPRINTF(32, "%s", m)); +} + +TEST(ip4mask, cover) +{ + IP4Address a; + IP4Address b = IP4_BROADCAST; + IP4Address l = IP4_LOCALHOST; + IP4Address h({127, 255, 255, 255}); + IP4Address p24l({10, 0, 0, 0}); + IP4Address p24h({10, 255, 255, 255}); + IP4Address p20l({172, 16, 0, 0}); + IP4Address p20h({172, 31, 255, 255}); + IP4Address p16l({192, 168, 0, 0}); + IP4Address p16h({192, 168, 255, 255}); + IP4Mask m; + EXPECT_TRUE(m.covers(a)); + EXPECT_TRUE(m.covers(b)); + EXPECT_TRUE(m.covers(l)); + EXPECT_TRUE(m.covers(h)); + EXPECT_TRUE(m.covers(p24l)); + EXPECT_TRUE(m.covers(p24h)); + EXPECT_TRUE(m.covers(p20l)); + EXPECT_TRUE(m.covers(p20h)); + EXPECT_TRUE(m.covers(p16l)); + EXPECT_TRUE(m.covers(p16h)); + m = IP4Mask(l, a); + EXPECT_TRUE(m.covers(a)); + EXPECT_TRUE(m.covers(b)); + EXPECT_TRUE(m.covers(l)); + EXPECT_TRUE(m.covers(h)); + EXPECT_TRUE(m.covers(p24l)); + EXPECT_TRUE(m.covers(p24h)); + EXPECT_TRUE(m.covers(p20l)); + EXPECT_TRUE(m.covers(p20h)); + EXPECT_TRUE(m.covers(p16l)); + EXPECT_TRUE(m.covers(p16h)); + m = IP4Mask(l, b); + EXPECT_FALSE(m.covers(a)); + EXPECT_FALSE(m.covers(b)); + EXPECT_TRUE(m.covers(l)); + EXPECT_FALSE(m.covers(h)); + EXPECT_FALSE(m.covers(p24l)); + EXPECT_FALSE(m.covers(p24h)); + EXPECT_FALSE(m.covers(p20l)); + EXPECT_FALSE(m.covers(p20h)); + EXPECT_FALSE(m.covers(p16l)); + EXPECT_FALSE(m.covers(p16h)); + + // but the really useful ones are with partial masks + m = IP4Mask(IP4Address({10, 0, 0, 0}), IP4Address({255, 0, 0, 0})); + EXPECT_FALSE(m.covers(a)); + EXPECT_FALSE(m.covers(b)); + EXPECT_FALSE(m.covers(l)); + EXPECT_FALSE(m.covers(h)); + EXPECT_TRUE(m.covers(p24l)); + EXPECT_TRUE(m.covers(p24h)); + EXPECT_FALSE(m.covers(p20l)); + EXPECT_FALSE(m.covers(p20h)); + EXPECT_FALSE(m.covers(p16l)); + EXPECT_FALSE(m.covers(p16h)); + EXPECT_FALSE(m.covers(IP4Address({9, 255, 255, 255}))); + EXPECT_FALSE(m.covers(IP4Address({11, 0, 0, 0}))); + m = IP4Mask(IP4Address({127, 0, 0, 0}), IP4Address({255, 0, 0, 0})); + EXPECT_FALSE(m.covers(a)); + EXPECT_FALSE(m.covers(b)); + EXPECT_TRUE(m.covers(l)); + EXPECT_TRUE(m.covers(h)); + EXPECT_FALSE(m.covers(p24l)); + EXPECT_FALSE(m.covers(p24h)); + EXPECT_FALSE(m.covers(p20l)); + EXPECT_FALSE(m.covers(p20h)); + EXPECT_FALSE(m.covers(p16l)); + EXPECT_FALSE(m.covers(p16h)); + EXPECT_FALSE(m.covers(IP4Address({126, 255, 255, 255}))); + EXPECT_FALSE(m.covers(IP4Address({128, 0, 0, 0}))); + m = IP4Mask(IP4Address({172, 16, 0, 0}), IP4Address({255, 240, 0, 0})); + EXPECT_FALSE(m.covers(a)); + EXPECT_FALSE(m.covers(b)); + EXPECT_FALSE(m.covers(l)); + EXPECT_FALSE(m.covers(h)); + EXPECT_FALSE(m.covers(p24l)); + EXPECT_FALSE(m.covers(p24h)); + EXPECT_TRUE(m.covers(p20l)); + EXPECT_TRUE(m.covers(p20h)); + EXPECT_FALSE(m.covers(p16l)); + EXPECT_FALSE(m.covers(p16h)); + EXPECT_FALSE(m.covers(IP4Address({172, 15, 255, 255}))); + EXPECT_FALSE(m.covers(IP4Address({172, 32, 0, 0}))); + m = IP4Mask(IP4Address({192, 168, 0, 0}), IP4Address({255, 255, 0, 0})); + EXPECT_FALSE(m.covers(a)); + EXPECT_FALSE(m.covers(b)); + EXPECT_FALSE(m.covers(l)); + EXPECT_FALSE(m.covers(h)); + EXPECT_FALSE(m.covers(p24l)); + EXPECT_FALSE(m.covers(p24h)); + EXPECT_FALSE(m.covers(p20l)); + EXPECT_FALSE(m.covers(p20h)); + EXPECT_TRUE(m.covers(p16l)); + EXPECT_TRUE(m.covers(p16h)); + EXPECT_FALSE(m.covers(IP4Address({192, 167, 255, 255}))); + EXPECT_FALSE(m.covers(IP4Address({192, 169, 0, 0}))); + + // OTOH this is crazy + EXPECT_TRUE(extract("120.248.200.217/89.57.126.5", &m)); + EXPECT_TRUE(m.covers(IP4Address({120, 248, 200, 217}))); + EXPECT_TRUE(m.covers(IP4Address({88, 56, 72, 1}))); + EXPECT_FALSE(m.covers(IP4Address({88, 56, 72, 0}))); + EXPECT_FALSE(m.covers(IP4Address({88, 56, 72, 255}))); +} -- cgit v1.2.3-60-g2f50