diff --git a/doc/release-notes.md b/doc/release-notes.md
index d2b595570..94300f210 100644
--- a/doc/release-notes.md
+++ b/doc/release-notes.md
@@ -1,7 +1,10 @@
 # Bitcoin ABC 0.22.13 Release Notes
 
 Bitcoin ABC version 0.22.13 is now available from:
 
   <https://download.bitcoinabc.org/0.22.13/>
 
 This release includes the following features and fixes:
+ - Netmasks that contain 1-bits after 0-bits (the 1-bits are not contiguous on
+   the left side, e.g. 255.0.255.255) are no longer accepted. They are invalid
+   according to RFC 4632.
diff --git a/src/netaddress.cpp b/src/netaddress.cpp
index 01536c5ec..b0b17eec0 100644
--- a/src/netaddress.cpp
+++ b/src/netaddress.cpp
@@ -1,956 +1,938 @@
 // Copyright (c) 2009-2010 Satoshi Nakamoto
 // Copyright (c) 2009-2016 The Bitcoin Core developers
 // Distributed under the MIT software license, see the accompanying
 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
 
 #include <netaddress.h>
 
 #include <hash.h>
 #include <tinyformat.h>
 #include <util/asmap.h>
 #include <util/strencodings.h>
 
 static const uint8_t pchIPv4[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff};
 static const uint8_t pchOnionCat[] = {0xFD, 0x87, 0xD8, 0x7E, 0xEB, 0x43};
 
 // 0xFD + sha256("bitcoin")[0:5]
 static const uint8_t g_internal_prefix[] = {0xFD, 0x6B, 0x88, 0xC0, 0x87, 0x24};
 
 /**
  * Construct an unspecified IPv6 network address (::/128).
  *
  * @note This address is considered invalid by CNetAddr::IsValid()
  */
 CNetAddr::CNetAddr() {
     memset(ip, 0, sizeof(ip));
 }
 
 void CNetAddr::SetIP(const CNetAddr &ipIn) {
     m_net = ipIn.m_net;
     memcpy(ip, ipIn.ip, sizeof(ip));
 }
 
 void CNetAddr::SetLegacyIPv6(const uint8_t ipv6[16]) {
     if (memcmp(ipv6, pchIPv4, sizeof(pchIPv4)) == 0) {
         m_net = NET_IPV4;
     } else if (memcmp(ipv6, pchOnionCat, sizeof(pchOnionCat)) == 0) {
         m_net = NET_ONION;
     } else if (memcmp(ipv6, g_internal_prefix, sizeof(g_internal_prefix)) ==
                0) {
         m_net = NET_INTERNAL;
     } else {
         m_net = NET_IPV6;
     }
     memcpy(ip, ipv6, 16);
 }
 
 void CNetAddr::SetRaw(Network network, const uint8_t *ip_in) {
     switch (network) {
         case NET_IPV4:
             m_net = NET_IPV4;
             memcpy(ip, pchIPv4, 12);
             memcpy(ip + 12, ip_in, 4);
             break;
         case NET_IPV6:
             SetLegacyIPv6(ip_in);
             break;
         default:
             assert(!"invalid network");
     }
 }
 
 /**
  * Try to make this a dummy address that maps the specified name into IPv6 like
  * so: (0xFD + %sha256("bitcoin")[0:5]) + %sha256(name)[0:10]. Such dummy
  * addresses have a prefix of fd6b:88c0:8724::/48 and are guaranteed to not be
  * publicly routable as it falls under RFC4193's fc00::/7 subnet allocated to
  * unique-local addresses.
  *
  * CAddrMan uses these fake addresses to keep track of which DNS seeds were
  * used.
  *
  * @returns Whether or not the operation was successful.
  *
  * @see CNetAddr::IsInternal(), CNetAddr::IsRFC4193()
  */
 bool CNetAddr::SetInternal(const std::string &name) {
     if (name.empty()) {
         return false;
     }
     m_net = NET_INTERNAL;
     uint8_t hash[32] = {};
     CSHA256().Write((const uint8_t *)name.data(), name.size()).Finalize(hash);
     memcpy(ip, g_internal_prefix, sizeof(g_internal_prefix));
     memcpy(ip + sizeof(g_internal_prefix), hash,
            sizeof(ip) - sizeof(g_internal_prefix));
     return true;
 }
 
 /**
  * Try to make this a dummy address that maps the specified onion address into
  * IPv6 using OnionCat's range and encoding. Such dummy addresses have a prefix
  * of fd87:d87e:eb43::/48 and are guaranteed to not be publicly routable as they
  * fall under RFC4193's fc00::/7 subnet allocated to unique-local addresses.
  *
  * @returns Whether or not the operation was successful.
  *
  * @see CNetAddr::IsTor(), CNetAddr::IsRFC4193()
  */
 bool CNetAddr::SetSpecial(const std::string &strName) {
     if (strName.size() > 6 &&
         strName.substr(strName.size() - 6, 6) == ".onion") {
         std::vector<uint8_t> vchAddr =
             DecodeBase32(strName.substr(0, strName.size() - 6).c_str());
         if (vchAddr.size() != 16 - sizeof(pchOnionCat)) {
             return false;
         }
         m_net = NET_ONION;
         memcpy(ip, pchOnionCat, sizeof(pchOnionCat));
         for (unsigned int i = 0; i < 16 - sizeof(pchOnionCat); i++) {
             ip[i + sizeof(pchOnionCat)] = vchAddr[i];
         }
         return true;
     }
     return false;
 }
 
 CNetAddr::CNetAddr(const struct in_addr &ipv4Addr) {
     SetRaw(NET_IPV4, (const uint8_t *)&ipv4Addr);
 }
 
 CNetAddr::CNetAddr(const struct in6_addr &ipv6Addr, const uint32_t scope) {
     SetRaw(NET_IPV6, (const uint8_t *)&ipv6Addr);
     scopeId = scope;
 }
 
 unsigned int CNetAddr::GetByte(int n) const {
     return ip[15 - n];
 }
 
 bool CNetAddr::IsBindAny() const {
     const int cmplen = IsIPv4() ? 4 : 16;
     for (int i = 0; i < cmplen; ++i) {
         if (GetByte(i)) {
             return false;
         }
     }
 
     return true;
 }
 
 bool CNetAddr::IsIPv4() const {
     return m_net == NET_IPV4;
 }
 
 bool CNetAddr::IsIPv6() const {
     return m_net == NET_IPV6;
 }
 
 bool CNetAddr::IsRFC1918() const {
     return IsIPv4() &&
            (GetByte(3) == 10 || (GetByte(3) == 192 && GetByte(2) == 168) ||
             (GetByte(3) == 172 && (GetByte(2) >= 16 && GetByte(2) <= 31)));
 }
 
 bool CNetAddr::IsRFC2544() const {
     return IsIPv4() && GetByte(3) == 198 &&
            (GetByte(2) == 18 || GetByte(2) == 19);
 }
 
 bool CNetAddr::IsRFC3927() const {
     return IsIPv4() && (GetByte(3) == 169 && GetByte(2) == 254);
 }
 
 bool CNetAddr::IsRFC6598() const {
     return IsIPv4() && GetByte(3) == 100 && GetByte(2) >= 64 &&
            GetByte(2) <= 127;
 }
 
 bool CNetAddr::IsRFC5737() const {
     return IsIPv4() &&
            ((GetByte(3) == 192 && GetByte(2) == 0 && GetByte(1) == 2) ||
             (GetByte(3) == 198 && GetByte(2) == 51 && GetByte(1) == 100) ||
             (GetByte(3) == 203 && GetByte(2) == 0 && GetByte(1) == 113));
 }
 
 bool CNetAddr::IsRFC3849() const {
     return IsIPv6() && GetByte(15) == 0x20 && GetByte(14) == 0x01 &&
            GetByte(13) == 0x0D && GetByte(12) == 0xB8;
 }
 
 bool CNetAddr::IsRFC3964() const {
     return IsIPv6() && GetByte(15) == 0x20 && GetByte(14) == 0x02;
 }
 
 bool CNetAddr::IsRFC6052() const {
     static const uint8_t pchRFC6052[] = {0, 0x64, 0xFF, 0x9B, 0, 0,
                                          0, 0,    0,    0,    0, 0};
     return IsIPv6() && memcmp(ip, pchRFC6052, sizeof(pchRFC6052)) == 0;
 }
 
 bool CNetAddr::IsRFC4380() const {
     return IsIPv6() && GetByte(15) == 0x20 && GetByte(14) == 0x01 &&
            GetByte(13) == 0 && GetByte(12) == 0;
 }
 
 bool CNetAddr::IsRFC4862() const {
     static const uint8_t pchRFC4862[] = {0xFE, 0x80, 0, 0, 0, 0, 0, 0};
     return IsIPv6() && memcmp(ip, pchRFC4862, sizeof(pchRFC4862)) == 0;
 }
 
 bool CNetAddr::IsRFC4193() const {
     return IsIPv6() && (GetByte(15) & 0xFE) == 0xFC;
 }
 
 bool CNetAddr::IsRFC6145() const {
     static const uint8_t pchRFC6145[] = {0, 0, 0,    0,    0, 0,
                                          0, 0, 0xFF, 0xFF, 0, 0};
     return IsIPv6() && memcmp(ip, pchRFC6145, sizeof(pchRFC6145)) == 0;
 }
 
 bool CNetAddr::IsRFC4843() const {
     return IsIPv6() && GetByte(15) == 0x20 && GetByte(14) == 0x01 &&
            GetByte(13) == 0x00 && (GetByte(12) & 0xF0) == 0x10;
 }
 
 bool CNetAddr::IsRFC7343() const {
     return IsIPv6() && GetByte(15) == 0x20 && GetByte(14) == 0x01 &&
            GetByte(13) == 0x00 && (GetByte(12) & 0xF0) == 0x20;
 }
 
 bool CNetAddr::IsHeNet() const {
     return (GetByte(15) == 0x20 && GetByte(14) == 0x01 && GetByte(13) == 0x04 &&
             GetByte(12) == 0x70);
 }
 
 /**
  * @returns Whether or not this is a dummy address that maps an onion address
  *          into IPv6.
  *
  * @see CNetAddr::SetSpecial(const std::string &)
  */
 bool CNetAddr::IsTor() const {
     return m_net == NET_ONION;
 }
 
 bool CNetAddr::IsLocal() const {
     // IPv4 loopback (127.0.0.0/8 or 0.0.0.0/8)
     if (IsIPv4() && (GetByte(3) == 127 || GetByte(3) == 0)) {
         return true;
     }
 
     // IPv6 loopback (::1/128)
     static const uint8_t pchLocal[16] = {0, 0, 0, 0, 0, 0, 0, 0,
                                          0, 0, 0, 0, 0, 0, 0, 1};
     if (IsIPv6() && memcmp(ip, pchLocal, 16) == 0) {
         return true;
     }
 
     return false;
 }
 
 /**
  * @returns Whether or not this network address is a valid address that @a could
  *          be used to refer to an actual host.
  *
  * @note A valid address may or may not be publicly routable on the global
  *       internet. As in, the set of valid addresses is a superset of the set of
  *       publicly routable addresses.
  *
  * @see CNetAddr::IsRoutable()
  */
 bool CNetAddr::IsValid() const {
     // Cleanup 3-byte shifted addresses caused by garbage in size field of addr
     // messages from versions before 0.2.9 checksum.
     // Two consecutive addr messages look like this:
     // header20 vectorlen3 addr26 addr26 addr26 header20 vectorlen3 addr26
     // addr26 addr26... so if the first length field is garbled, it reads the
     // second batch of addr misaligned by 3 bytes.
     if (IsIPv6() && memcmp(ip, pchIPv4 + 3, sizeof(pchIPv4) - 3) == 0) {
         return false;
     }
 
     // unspecified IPv6 address (::/128)
     uint8_t ipNone6[16] = {};
     if (IsIPv6() && memcmp(ip, ipNone6, 16) == 0) {
         return false;
     }
 
     // documentation IPv6 address
     if (IsRFC3849()) {
         return false;
     }
 
     if (IsInternal()) {
         return false;
     }
 
     if (IsIPv4()) {
         // INADDR_NONE
         uint32_t ipNone = INADDR_NONE;
         if (memcmp(ip + 12, &ipNone, 4) == 0) {
             return false;
         }
 
         // 0
         ipNone = 0;
         if (memcmp(ip + 12, &ipNone, 4) == 0) {
             return false;
         }
     }
 
     return true;
 }
 
 /**
  * @returns Whether or not this network address is publicly routable on the
  *          global internet.
  *
  * @note A routable address is always valid. As in, the set of routable
  * addresses is a subset of the set of valid addresses.
  *
  * @see CNetAddr::IsValid()
  */
 bool CNetAddr::IsRoutable() const {
     return IsValid() &&
            !(IsRFC1918() || IsRFC2544() || IsRFC3927() || IsRFC4862() ||
              IsRFC6598() || IsRFC5737() || (IsRFC4193() && !IsTor()) ||
              IsRFC4843() || IsRFC7343() || IsLocal() || IsInternal());
 }
 
 /**
  * @returns Whether or not this is a dummy address that maps a name into IPv6.
  *
  * @see CNetAddr::SetInternal(const std::string &)
  */
 bool CNetAddr::IsInternal() const {
     return m_net == NET_INTERNAL;
 }
 
 enum Network CNetAddr::GetNetwork() const {
     if (IsInternal()) {
         return NET_INTERNAL;
     }
 
     if (!IsRoutable()) {
         return NET_UNROUTABLE;
     }
 
     return m_net;
 }
 
 std::string CNetAddr::ToStringIP() const {
     if (IsTor()) {
         return EncodeBase32(&ip[6], 10) + ".onion";
     }
     if (IsInternal()) {
         return EncodeBase32(ip + sizeof(g_internal_prefix),
                             sizeof(ip) - sizeof(g_internal_prefix)) +
                ".internal";
     }
     CService serv(*this, 0);
     struct sockaddr_storage sockaddr;
     socklen_t socklen = sizeof(sockaddr);
     if (serv.GetSockAddr((struct sockaddr *)&sockaddr, &socklen)) {
         char name[1025] = "";
         if (!getnameinfo((const struct sockaddr *)&sockaddr, socklen, name,
                          sizeof(name), nullptr, 0, NI_NUMERICHOST)) {
             return std::string(name);
         }
     }
     if (IsIPv4()) {
         return strprintf("%u.%u.%u.%u", GetByte(3), GetByte(2), GetByte(1),
                          GetByte(0));
     }
 
     return strprintf("%x:%x:%x:%x:%x:%x:%x:%x", GetByte(15) << 8 | GetByte(14),
                      GetByte(13) << 8 | GetByte(12),
                      GetByte(11) << 8 | GetByte(10),
                      GetByte(9) << 8 | GetByte(8), GetByte(7) << 8 | GetByte(6),
                      GetByte(5) << 8 | GetByte(4), GetByte(3) << 8 | GetByte(2),
                      GetByte(1) << 8 | GetByte(0));
 }
 
 std::string CNetAddr::ToString() const {
     return ToStringIP();
 }
 
 bool operator==(const CNetAddr &a, const CNetAddr &b) {
     return a.m_net == b.m_net && memcmp(a.ip, b.ip, 16) == 0;
 }
 
 bool operator<(const CNetAddr &a, const CNetAddr &b) {
     return a.m_net < b.m_net ||
            (a.m_net == b.m_net && memcmp(a.ip, b.ip, 16) < 0);
 }
 
 /**
  * Try to get our IPv4 address.
  *
  * @param[out] pipv4Addr The in_addr struct to which to copy.
  *
  * @returns Whether or not the operation was successful, in particular, whether
  *          or not our address was an IPv4 address.
  *
  * @see CNetAddr::IsIPv4()
  */
 bool CNetAddr::GetInAddr(struct in_addr *pipv4Addr) const {
     if (!IsIPv4()) {
         return false;
     }
     memcpy(pipv4Addr, ip + 12, 4);
     return true;
 }
 
 /**
  * Try to get our IPv6 address.
  *
  * @param[out] pipv6Addr The in6_addr struct to which to copy.
  *
  * @returns Whether or not the operation was successful, in particular, whether
  *          or not our address was an IPv6 address.
  *
  * @see CNetAddr::IsIPv6()
  */
 bool CNetAddr::GetIn6Addr(struct in6_addr *pipv6Addr) const {
     if (!IsIPv6()) {
         return false;
     }
     memcpy(pipv6Addr, ip, 16);
     return true;
 }
 
 bool CNetAddr::HasLinkedIPv4() const {
     return IsRoutable() && (IsIPv4() || IsRFC6145() || IsRFC6052() ||
                             IsRFC3964() || IsRFC4380());
 }
 
 uint32_t CNetAddr::GetLinkedIPv4() const {
     if (IsIPv4() || IsRFC6145() || IsRFC6052()) {
         // IPv4, mapped IPv4, SIIT translated IPv4: the IPv4 address is the last
         // 4 bytes of the address
         return ReadBE32(ip + 12);
     } else if (IsRFC3964()) {
         // 6to4 tunneled IPv4: the IPv4 address is in bytes 2-6
         return ReadBE32(ip + 2);
     } else if (IsRFC4380()) {
         // Teredo tunneled IPv4: the IPv4 address is in the last 4 bytes of the
         // address, but bitflipped
         return ~ReadBE32(ip + 12);
     }
     assert(false);
 }
 
 uint32_t CNetAddr::GetNetClass() const {
     uint32_t net_class = NET_IPV6;
     if (IsLocal()) {
         net_class = 255;
     }
     if (IsInternal()) {
         net_class = NET_INTERNAL;
     } else if (!IsRoutable()) {
         net_class = NET_UNROUTABLE;
     } else if (HasLinkedIPv4()) {
         net_class = NET_IPV4;
     } else if (IsTor()) {
         net_class = NET_ONION;
     }
     return net_class;
 }
 
 uint32_t CNetAddr::GetMappedAS(const std::vector<bool> &asmap) const {
     uint32_t net_class = GetNetClass();
     if (asmap.size() == 0 || (net_class != NET_IPV4 && net_class != NET_IPV6)) {
         return 0; // Indicates not found, safe because AS0 is reserved per
                   // RFC7607.
     }
     std::vector<bool> ip_bits(128);
     if (HasLinkedIPv4()) {
         // For lookup, treat as if it was just an IPv4 address (pchIPv4 prefix +
         // IPv4 bits)
         for (int8_t byte_i = 0; byte_i < 12; ++byte_i) {
             for (uint8_t bit_i = 0; bit_i < 8; ++bit_i) {
                 ip_bits[byte_i * 8 + bit_i] =
                     (pchIPv4[byte_i] >> (7 - bit_i)) & 1;
             }
         }
         uint32_t ipv4 = GetLinkedIPv4();
         for (int i = 0; i < 32; ++i) {
             ip_bits[96 + i] = (ipv4 >> (31 - i)) & 1;
         }
     } else {
         // Use all 128 bits of the IPv6 address otherwise
         for (int8_t byte_i = 0; byte_i < 16; ++byte_i) {
             uint8_t cur_byte = GetByte(15 - byte_i);
             for (uint8_t bit_i = 0; bit_i < 8; ++bit_i) {
                 ip_bits[byte_i * 8 + bit_i] = (cur_byte >> (7 - bit_i)) & 1;
             }
         }
     }
     uint32_t mapped_as = Interpret(asmap, ip_bits);
     return mapped_as;
 }
 
 /**
  * Get the canonical identifier of our network group
  *
  * The groups are assigned in a way where it should be costly for an attacker to
  * obtain addresses with many different group identifiers, even if it is cheap
  * to obtain addresses with the same identifier.
  *
  * @note No two connections will be attempted to addresses with the same network
  *       group.
  */
 std::vector<uint8_t> CNetAddr::GetGroup(const std::vector<bool> &asmap) const {
     std::vector<uint8_t> vchRet;
     uint32_t net_class = GetNetClass();
     // If non-empty asmap is supplied and the address is IPv4/IPv6,
     // return ASN to be used for bucketing.
     uint32_t asn = GetMappedAS(asmap);
     if (asn != 0) { // Either asmap was empty, or address has non-asmappable net
                     // class (e.g. TOR).
         vchRet.push_back(NET_IPV6); // IPv4 and IPv6 with same ASN should be in
                                     // the same bucket
         for (int i = 0; i < 4; i++) {
             vchRet.push_back((asn >> (8 * i)) & 0xFF);
         }
         return vchRet;
     }
 
     vchRet.push_back(net_class);
     int nStartByte = 0;
     int nBits = 16;
 
     if (IsLocal()) {
         // all local addresses belong to the same group
         nBits = 0;
     } else if (IsInternal()) {
         // all internal-usage addresses get their own group
         nStartByte = sizeof(g_internal_prefix);
         nBits = (sizeof(ip) - sizeof(g_internal_prefix)) * 8;
     } else if (!IsRoutable()) {
         // all other unroutable addresses belong to the same group
         nBits = 0;
     } else if (HasLinkedIPv4()) {
         // IPv4 addresses (and mapped IPv4 addresses) use /16 groups
         uint32_t ipv4 = GetLinkedIPv4();
         vchRet.push_back((ipv4 >> 24) & 0xFF);
         vchRet.push_back((ipv4 >> 16) & 0xFF);
         return vchRet;
     } else if (IsTor()) {
         nStartByte = 6;
         nBits = 4;
     } else if (IsHeNet()) {
         // for he.net, use /36 groups
         nBits = 36;
     } else {
         // for the rest of the IPv6 network, use /32 groups
         nBits = 32;
     }
 
     // push our ip onto vchRet byte by byte...
     while (nBits >= 8) {
         vchRet.push_back(GetByte(15 - nStartByte));
         nStartByte++;
         nBits -= 8;
     }
     // ...for the last byte, push nBits and for the rest of the byte push 1's
     if (nBits > 0) {
         vchRet.push_back(GetByte(15 - nStartByte) | ((1 << (8 - nBits)) - 1));
     }
 
     return vchRet;
 }
 
 uint64_t CNetAddr::GetHash() const {
     uint256 hash = Hash(ip);
     uint64_t nRet;
     memcpy(&nRet, &hash, sizeof(nRet));
     return nRet;
 }
 
 // private extensions to enum Network, only returned by GetExtNetwork, and only
 // used in GetReachabilityFrom
 static const int NET_UNKNOWN = NET_MAX + 0;
 static const int NET_TEREDO = NET_MAX + 1;
 static int GetExtNetwork(const CNetAddr *addr) {
     if (addr == nullptr) {
         return NET_UNKNOWN;
     }
     if (addr->IsRFC4380()) {
         return NET_TEREDO;
     }
     return addr->GetNetwork();
 }
 
 /** Calculates a metric for how reachable (*this) is from a given partner */
 int CNetAddr::GetReachabilityFrom(const CNetAddr *paddrPartner) const {
     enum Reachability {
         REACH_UNREACHABLE,
         REACH_DEFAULT,
         REACH_TEREDO,
         REACH_IPV6_WEAK,
         REACH_IPV4,
         REACH_IPV6_STRONG,
         REACH_PRIVATE
     };
 
     if (!IsRoutable() || IsInternal()) {
         return REACH_UNREACHABLE;
     }
 
     int ourNet = GetExtNetwork(this);
     int theirNet = GetExtNetwork(paddrPartner);
     bool fTunnel = IsRFC3964() || IsRFC6052() || IsRFC6145();
 
     switch (theirNet) {
         case NET_IPV4:
             switch (ourNet) {
                 default:
                     return REACH_DEFAULT;
                 case NET_IPV4:
                     return REACH_IPV4;
             }
         case NET_IPV6:
             switch (ourNet) {
                 default:
                     return REACH_DEFAULT;
                 case NET_TEREDO:
                     return REACH_TEREDO;
                 case NET_IPV4:
                     return REACH_IPV4;
                 // only prefer giving our IPv6 address if it's not tunnelled
                 case NET_IPV6:
                     return fTunnel ? REACH_IPV6_WEAK : REACH_IPV6_STRONG;
             }
         case NET_ONION:
             switch (ourNet) {
                 default:
                     return REACH_DEFAULT;
                 // Tor users can connect to IPv4 as well
                 case NET_IPV4:
                     return REACH_IPV4;
                 case NET_ONION:
                     return REACH_PRIVATE;
             }
         case NET_TEREDO:
             switch (ourNet) {
                 default:
                     return REACH_DEFAULT;
                 case NET_TEREDO:
                     return REACH_TEREDO;
                 case NET_IPV6:
                     return REACH_IPV6_WEAK;
                 case NET_IPV4:
                     return REACH_IPV4;
             }
         case NET_UNKNOWN:
         case NET_UNROUTABLE:
         default:
             switch (ourNet) {
                 default:
                     return REACH_DEFAULT;
                 case NET_TEREDO:
                     return REACH_TEREDO;
                 case NET_IPV6:
                     return REACH_IPV6_WEAK;
                 case NET_IPV4:
                     return REACH_IPV4;
                 // either from Tor, or don't care about our address
                 case NET_ONION:
                     return REACH_PRIVATE;
             }
     }
 }
 
 CService::CService() : port(0) {}
 
 CService::CService(const CNetAddr &cip, unsigned short portIn)
     : CNetAddr(cip), port(portIn) {}
 
 CService::CService(const struct in_addr &ipv4Addr, unsigned short portIn)
     : CNetAddr(ipv4Addr), port(portIn) {}
 
 CService::CService(const struct in6_addr &ipv6Addr, unsigned short portIn)
     : CNetAddr(ipv6Addr), port(portIn) {}
 
 CService::CService(const struct sockaddr_in &addr)
     : CNetAddr(addr.sin_addr), port(ntohs(addr.sin_port)) {
     assert(addr.sin_family == AF_INET);
 }
 
 CService::CService(const struct sockaddr_in6 &addr)
     : CNetAddr(addr.sin6_addr, addr.sin6_scope_id),
       port(ntohs(addr.sin6_port)) {
     assert(addr.sin6_family == AF_INET6);
 }
 
 bool CService::SetSockAddr(const struct sockaddr *paddr) {
     switch (paddr->sa_family) {
         case AF_INET:
             *this =
                 CService(*reinterpret_cast<const struct sockaddr_in *>(paddr));
             return true;
         case AF_INET6:
             *this =
                 CService(*reinterpret_cast<const struct sockaddr_in6 *>(paddr));
             return true;
         default:
             return false;
     }
 }
 
 unsigned short CService::GetPort() const {
     return port;
 }
 
 bool operator==(const CService &a, const CService &b) {
     return static_cast<CNetAddr>(a) == static_cast<CNetAddr>(b) &&
            a.port == b.port;
 }
 
 bool operator<(const CService &a, const CService &b) {
     return static_cast<CNetAddr>(a) < static_cast<CNetAddr>(b) ||
            (static_cast<CNetAddr>(a) == static_cast<CNetAddr>(b) &&
             a.port < b.port);
 }
 
 /**
  * Obtain the IPv4/6 socket address this represents.
  *
  * @param[out] paddr The obtained socket address.
  * @param[in,out] addrlen The size, in bytes, of the address structure pointed
  *                        to by paddr. The value that's pointed to by this
  *                        parameter might change after calling this function if
  *                        the size of the corresponding address structure
  *                        changed.
  *
  * @returns Whether or not the operation was successful.
  */
 bool CService::GetSockAddr(struct sockaddr *paddr, socklen_t *addrlen) const {
     if (IsIPv4()) {
         if (*addrlen < (socklen_t)sizeof(struct sockaddr_in)) {
             return false;
         }
         *addrlen = sizeof(struct sockaddr_in);
         struct sockaddr_in *paddrin =
             reinterpret_cast<struct sockaddr_in *>(paddr);
         memset(paddrin, 0, *addrlen);
         if (!GetInAddr(&paddrin->sin_addr)) {
             return false;
         }
         paddrin->sin_family = AF_INET;
         paddrin->sin_port = htons(port);
         return true;
     }
     if (IsIPv6()) {
         if (*addrlen < (socklen_t)sizeof(struct sockaddr_in6)) {
             return false;
         }
         *addrlen = sizeof(struct sockaddr_in6);
         struct sockaddr_in6 *paddrin6 =
             reinterpret_cast<struct sockaddr_in6 *>(paddr);
         memset(paddrin6, 0, *addrlen);
         if (!GetIn6Addr(&paddrin6->sin6_addr)) {
             return false;
         }
         paddrin6->sin6_scope_id = scopeId;
         paddrin6->sin6_family = AF_INET6;
         paddrin6->sin6_port = htons(port);
         return true;
     }
     return false;
 }
 
 /**
  * @returns An identifier unique to this service's address and port number.
  */
 std::vector<uint8_t> CService::GetKey() const {
     auto key = GetAddrBytes();
     // most significant byte of our port
     key.push_back(port / 0x100);
     // least significant byte of our port
     key.push_back(port & 0x0FF);
     return key;
 }
 
 std::string CService::ToStringPort() const {
     return strprintf("%u", port);
 }
 
 std::string CService::ToStringIPPort() const {
     if (IsIPv4() || IsTor() || IsInternal()) {
         return ToStringIP() + ":" + ToStringPort();
     } else {
         return "[" + ToStringIP() + "]:" + ToStringPort();
     }
 }
 
 std::string CService::ToString() const {
     return ToStringIPPort();
 }
 
 CSubNet::CSubNet() : valid(false) {
     memset(netmask, 0, sizeof(netmask));
 }
 
 CSubNet::CSubNet(const CNetAddr &addr, int32_t mask) {
     valid = true;
     network = addr;
     // Default to /32 (IPv4) or /128 (IPv6), i.e. match single address
     memset(netmask, 255, sizeof(netmask));
 
     // IPv4 addresses start at offset 12, and first 12 bytes must match, so just
     // offset n
     const int astartofs = network.IsIPv4() ? 12 : 0;
 
     // Only valid if in range of bits of address
     int32_t n = mask;
     if (n >= 0 && n <= (128 - astartofs * 8)) {
         n += astartofs * 8;
         // Clear bits [n..127]
         for (; n < 128; ++n) {
             netmask[n >> 3] &= ~(1 << (7 - (n & 7)));
         }
     } else {
         valid = false;
     }
 
     // Normalize network according to netmask
     for (int x = 0; x < 16; ++x) {
         network.ip[x] &= netmask[x];
     }
 }
 
+/**
+ * @returns The number of 1-bits in the prefix of the specified subnet mask. If
+ *          the specified subnet mask is not a valid one, -1.
+ */
+static inline int NetmaskBits(uint8_t x) {
+    switch (x) {
+        case 0x00:
+            return 0;
+        case 0x80:
+            return 1;
+        case 0xc0:
+            return 2;
+        case 0xe0:
+            return 3;
+        case 0xf0:
+            return 4;
+        case 0xf8:
+            return 5;
+        case 0xfc:
+            return 6;
+        case 0xfe:
+            return 7;
+        case 0xff:
+            return 8;
+        default:
+            return -1;
+    }
+}
+
 CSubNet::CSubNet(const CNetAddr &addr, const CNetAddr &mask) {
     valid = true;
+    // Check if `mask` contains 1-bits after 0-bits (which is an invalid
+    // netmask).
+    bool zeros_found = false;
+    for (size_t i = mask.IsIPv4() ? 12 : 0; i < sizeof(mask.ip); ++i) {
+        const int num_bits = NetmaskBits(mask.ip[i]);
+        if (num_bits == -1 || (zeros_found && num_bits != 0)) {
+            valid = false;
+            return;
+        }
+        if (num_bits < 8) {
+            zeros_found = true;
+        }
+    }
     network = addr;
     // Default to /32 (IPv4) or /128 (IPv6), i.e. match single address
     memset(netmask, 255, sizeof(netmask));
 
     // IPv4 addresses start at offset 12, and first 12 bytes must match, so just
     // offset n
     const int astartofs = network.IsIPv4() ? 12 : 0;
 
     for (int x = astartofs; x < 16; ++x) {
         netmask[x] = mask.ip[x];
     }
 
     // Normalize network according to netmask
     for (int x = 0; x < 16; ++x) {
         network.ip[x] &= netmask[x];
     }
 }
 
 CSubNet::CSubNet(const CNetAddr &addr) : valid(addr.IsValid()) {
     memset(netmask, 255, sizeof(netmask));
     network = addr;
 }
 
 /**
  * @returns True if this subnet is valid, the specified address is valid, and
  *          the specified address belongs in this subnet.
  */
 bool CSubNet::Match(const CNetAddr &addr) const {
     if (!valid || !addr.IsValid() || network.m_net != addr.m_net) {
         return false;
     }
     for (int x = 0; x < 16; ++x) {
         if ((addr.ip[x] & netmask[x]) != network.ip[x]) {
             return false;
         }
     }
     return true;
 }
 
-/**
- * @returns The number of 1-bits in the prefix of the specified subnet mask. If
- *          the specified subnet mask is not a valid one, -1.
- */
-static inline int NetmaskBits(uint8_t x) {
-    switch (x) {
-        case 0x00:
-            return 0;
-        case 0x80:
-            return 1;
-        case 0xc0:
-            return 2;
-        case 0xe0:
-            return 3;
-        case 0xf0:
-            return 4;
-        case 0xf8:
-            return 5;
-        case 0xfc:
-            return 6;
-        case 0xfe:
-            return 7;
-        case 0xff:
-            return 8;
-        default:
-            return -1;
-    }
-}
-
 std::string CSubNet::ToString() const {
-    /* Parse binary 1{n}0{N-n} to see if mask can be represented as /n */
-    int cidr = 0;
-    bool valid_cidr = true;
-    int n = network.IsIPv4() ? 12 : 0;
-    for (; n < 16 && netmask[n] == 0xff; ++n) {
-        cidr += 8;
-    }
-    if (n < 16) {
-        int bits = NetmaskBits(netmask[n]);
-        if (bits < 0) {
-            valid_cidr = false;
-        } else {
-            cidr += bits;
-        }
-        ++n;
-    }
-    for (; n < 16 && valid_cidr; ++n) {
-        if (netmask[n] != 0x00) {
-            valid_cidr = false;
-        }
-    }
+    uint8_t cidr = 0;
 
-    /* Format output */
-    std::string strNetmask;
-    if (valid_cidr) {
-        strNetmask = strprintf("%u", cidr);
-    } else {
-        if (network.IsIPv4()) {
-            strNetmask = strprintf("%u.%u.%u.%u", netmask[12], netmask[13],
-                                   netmask[14], netmask[15]);
-        } else {
-            strNetmask = strprintf(
-                "%x:%x:%x:%x:%x:%x:%x:%x", netmask[0] << 8 | netmask[1],
-                netmask[2] << 8 | netmask[3], netmask[4] << 8 | netmask[5],
-                netmask[6] << 8 | netmask[7], netmask[8] << 8 | netmask[9],
-                netmask[10] << 8 | netmask[11], netmask[12] << 8 | netmask[13],
-                netmask[14] << 8 | netmask[15]);
+    for (size_t i = network.IsIPv4() ? 12 : 0; i < sizeof(netmask); ++i) {
+        if (netmask[i] == 0x00) {
+            break;
         }
+        cidr += NetmaskBits(netmask[i]);
     }
 
-    return network.ToString() + "/" + strNetmask;
+    return network.ToString() + strprintf("/%u", cidr);
 }
 
 bool CSubNet::IsValid() const {
     return valid;
 }
 
 bool operator==(const CSubNet &a, const CSubNet &b) {
     return a.valid == b.valid && a.network == b.network &&
            !memcmp(a.netmask, b.netmask, 16);
 }
 
 bool operator<(const CSubNet &a, const CSubNet &b) {
     return (a.network < b.network ||
             (a.network == b.network && memcmp(a.netmask, b.netmask, 16) < 0));
 }
 
 bool SanityCheckASMap(const std::vector<bool> &asmap) {
     // For IP address lookups, the input is 128 bits
     return SanityCheckASMap(asmap, 128);
 }
diff --git a/src/test/netbase_tests.cpp b/src/test/netbase_tests.cpp
index a835137a2..5ceb756aa 100644
--- a/src/test/netbase_tests.cpp
+++ b/src/test/netbase_tests.cpp
@@ -1,514 +1,515 @@
 // Copyright (c) 2012-2019 The Bitcoin Core developers
 // Distributed under the MIT software license, see the accompanying
 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
 
 #include <netbase.h>
 
 #include <net_permissions.h>
 #include <util/strencodings.h>
 #include <util/translation.h>
 
 #include <test/util/setup_common.h>
 
 #include <boost/test/unit_test.hpp>
 
 #include <string>
 
 BOOST_FIXTURE_TEST_SUITE(netbase_tests, BasicTestingSetup)
 
 static CNetAddr ResolveIP(const std::string &ip) {
     CNetAddr addr;
     LookupHost(ip, addr, false);
     return addr;
 }
 
 static CSubNet ResolveSubNet(const std::string &subnet) {
     CSubNet ret;
     LookupSubNet(subnet, ret);
     return ret;
 }
 
 static CNetAddr CreateInternal(const std::string &host) {
     CNetAddr addr;
     addr.SetInternal(host);
     return addr;
 }
 
 BOOST_AUTO_TEST_CASE(netbase_networks) {
     BOOST_CHECK(ResolveIP("127.0.0.1").GetNetwork() == NET_UNROUTABLE);
     BOOST_CHECK(ResolveIP("::1").GetNetwork() == NET_UNROUTABLE);
     BOOST_CHECK(ResolveIP("8.8.8.8").GetNetwork() == NET_IPV4);
     BOOST_CHECK(ResolveIP("2001::8888").GetNetwork() == NET_IPV6);
     BOOST_CHECK(
         ResolveIP("FD87:D87E:EB43:edb1:8e4:3588:e546:35ca").GetNetwork() ==
         NET_ONION);
     BOOST_CHECK(CreateInternal("foo.com").GetNetwork() == NET_INTERNAL);
 }
 
 BOOST_AUTO_TEST_CASE(netbase_properties) {
     BOOST_CHECK(ResolveIP("127.0.0.1").IsIPv4());
     BOOST_CHECK(ResolveIP("::FFFF:192.168.1.1").IsIPv4());
     BOOST_CHECK(ResolveIP("::1").IsIPv6());
     BOOST_CHECK(ResolveIP("10.0.0.1").IsRFC1918());
     BOOST_CHECK(ResolveIP("192.168.1.1").IsRFC1918());
     BOOST_CHECK(ResolveIP("172.31.255.255").IsRFC1918());
     BOOST_CHECK(ResolveIP("198.18.0.0").IsRFC2544());
     BOOST_CHECK(ResolveIP("198.19.255.255").IsRFC2544());
     BOOST_CHECK(ResolveIP("2001:0DB8::").IsRFC3849());
     BOOST_CHECK(ResolveIP("169.254.1.1").IsRFC3927());
     BOOST_CHECK(ResolveIP("2002::1").IsRFC3964());
     BOOST_CHECK(ResolveIP("FC00::").IsRFC4193());
     BOOST_CHECK(ResolveIP("2001::2").IsRFC4380());
     BOOST_CHECK(ResolveIP("2001:10::").IsRFC4843());
     BOOST_CHECK(ResolveIP("2001:20::").IsRFC7343());
     BOOST_CHECK(ResolveIP("FE80::").IsRFC4862());
     BOOST_CHECK(ResolveIP("64:FF9B::").IsRFC6052());
     BOOST_CHECK(ResolveIP("FD87:D87E:EB43:edb1:8e4:3588:e546:35ca").IsTor());
     BOOST_CHECK(ResolveIP("127.0.0.1").IsLocal());
     BOOST_CHECK(ResolveIP("::1").IsLocal());
     BOOST_CHECK(ResolveIP("8.8.8.8").IsRoutable());
     BOOST_CHECK(ResolveIP("2001::1").IsRoutable());
     BOOST_CHECK(ResolveIP("127.0.0.1").IsValid());
     BOOST_CHECK(
         CreateInternal("FD6B:88C0:8724:edb1:8e4:3588:e546:35ca").IsInternal());
     BOOST_CHECK(CreateInternal("bar.com").IsInternal());
 }
 
 static bool TestSplitHost(std::string test, std::string host, int port) {
     std::string hostOut;
     int portOut = -1;
     SplitHostPort(test, portOut, hostOut);
     return hostOut == host && port == portOut;
 }
 
 BOOST_AUTO_TEST_CASE(netbase_splithost) {
     BOOST_CHECK(TestSplitHost("www.bitcoin.org", "www.bitcoin.org", -1));
     BOOST_CHECK(TestSplitHost("[www.bitcoin.org]", "www.bitcoin.org", -1));
     BOOST_CHECK(TestSplitHost("www.bitcoin.org:80", "www.bitcoin.org", 80));
     BOOST_CHECK(TestSplitHost("[www.bitcoin.org]:80", "www.bitcoin.org", 80));
     BOOST_CHECK(TestSplitHost("127.0.0.1", "127.0.0.1", -1));
     BOOST_CHECK(TestSplitHost("127.0.0.1:8333", "127.0.0.1", 8333));
     BOOST_CHECK(TestSplitHost("[127.0.0.1]", "127.0.0.1", -1));
     BOOST_CHECK(TestSplitHost("[127.0.0.1]:8333", "127.0.0.1", 8333));
     BOOST_CHECK(TestSplitHost("::ffff:127.0.0.1", "::ffff:127.0.0.1", -1));
     BOOST_CHECK(
         TestSplitHost("[::ffff:127.0.0.1]:8333", "::ffff:127.0.0.1", 8333));
     BOOST_CHECK(TestSplitHost("[::]:8333", "::", 8333));
     BOOST_CHECK(TestSplitHost("::8333", "::8333", -1));
     BOOST_CHECK(TestSplitHost(":8333", "", 8333));
     BOOST_CHECK(TestSplitHost("[]:8333", "", 8333));
     BOOST_CHECK(TestSplitHost("", "", -1));
 }
 
 static bool TestParse(std::string src, std::string canon) {
     CService addr(LookupNumeric(src, 65535));
     return canon == addr.ToString();
 }
 
 BOOST_AUTO_TEST_CASE(netbase_lookupnumeric) {
     BOOST_CHECK(TestParse("127.0.0.1", "127.0.0.1:65535"));
     BOOST_CHECK(TestParse("127.0.0.1:8333", "127.0.0.1:8333"));
     BOOST_CHECK(TestParse("::ffff:127.0.0.1", "127.0.0.1:65535"));
     BOOST_CHECK(TestParse("::", "[::]:65535"));
     BOOST_CHECK(TestParse("[::]:8333", "[::]:8333"));
     BOOST_CHECK(TestParse("[127.0.0.1]", "127.0.0.1:65535"));
     BOOST_CHECK(TestParse(":::", "[::]:0"));
 
     // verify that an internal address fails to resolve
     BOOST_CHECK(TestParse("[fd6b:88c0:8724:1:2:3:4:5]", "[::]:0"));
     // and that a one-off resolves correctly
     BOOST_CHECK(TestParse("[fd6c:88c0:8724:1:2:3:4:5]",
                           "[fd6c:88c0:8724:1:2:3:4:5]:65535"));
 }
 
 BOOST_AUTO_TEST_CASE(onioncat_test) {
     // values from
     // https://web.archive.org/web/20121122003543/http://www.cypherpunk.at/onioncat/wiki/OnionCat
     CNetAddr addr1(ResolveIP("5wyqrzbvrdsumnok.onion"));
     CNetAddr addr2(ResolveIP("FD87:D87E:EB43:edb1:8e4:3588:e546:35ca"));
     BOOST_CHECK(addr1 == addr2);
     BOOST_CHECK(addr1.IsTor());
     BOOST_CHECK(addr1.ToStringIP() == "5wyqrzbvrdsumnok.onion");
     BOOST_CHECK(addr1.IsRoutable());
 }
 
 BOOST_AUTO_TEST_CASE(embedded_test) {
     CNetAddr addr1(ResolveIP("1.2.3.4"));
     CNetAddr addr2(ResolveIP("::FFFF:0102:0304"));
     BOOST_CHECK(addr2.IsIPv4());
     BOOST_CHECK_EQUAL(addr1.ToString(), addr2.ToString());
 }
 
 BOOST_AUTO_TEST_CASE(subnet_test) {
     BOOST_CHECK(ResolveSubNet("1.2.3.0/24") ==
                 ResolveSubNet("1.2.3.0/255.255.255.0"));
     BOOST_CHECK(ResolveSubNet("1.2.3.0/24") !=
                 ResolveSubNet("1.2.4.0/255.255.255.0"));
     BOOST_CHECK(ResolveSubNet("1.2.3.0/24").Match(ResolveIP("1.2.3.4")));
     BOOST_CHECK(!ResolveSubNet("1.2.2.0/24").Match(ResolveIP("1.2.3.4")));
     BOOST_CHECK(ResolveSubNet("1.2.3.4").Match(ResolveIP("1.2.3.4")));
     BOOST_CHECK(ResolveSubNet("1.2.3.4/32").Match(ResolveIP("1.2.3.4")));
     BOOST_CHECK(!ResolveSubNet("1.2.3.4").Match(ResolveIP("5.6.7.8")));
     BOOST_CHECK(!ResolveSubNet("1.2.3.4/32").Match(ResolveIP("5.6.7.8")));
     BOOST_CHECK(
         ResolveSubNet("::ffff:127.0.0.1").Match(ResolveIP("127.0.0.1")));
     BOOST_CHECK(
         ResolveSubNet("1:2:3:4:5:6:7:8").Match(ResolveIP("1:2:3:4:5:6:7:8")));
     BOOST_CHECK(
         !ResolveSubNet("1:2:3:4:5:6:7:8").Match(ResolveIP("1:2:3:4:5:6:7:9")));
     BOOST_CHECK(ResolveSubNet("1:2:3:4:5:6:7:0/112")
                     .Match(ResolveIP("1:2:3:4:5:6:7:1234")));
     BOOST_CHECK(
         ResolveSubNet("192.168.0.1/24").Match(ResolveIP("192.168.0.2")));
     BOOST_CHECK(
         ResolveSubNet("192.168.0.20/29").Match(ResolveIP("192.168.0.18")));
     BOOST_CHECK(ResolveSubNet("1.2.2.1/24").Match(ResolveIP("1.2.2.4")));
     BOOST_CHECK(ResolveSubNet("1.2.2.110/31").Match(ResolveIP("1.2.2.111")));
     BOOST_CHECK(ResolveSubNet("1.2.2.20/26").Match(ResolveIP("1.2.2.63")));
     // All-Matching IPv6 Matches arbitrary IPv6
     BOOST_CHECK(ResolveSubNet("::/0").Match(ResolveIP("1:2:3:4:5:6:7:1234")));
     // But not `::` or `0.0.0.0` because they are considered invalid addresses
     BOOST_CHECK(!ResolveSubNet("::/0").Match(ResolveIP("::")));
     BOOST_CHECK(!ResolveSubNet("::/0").Match(ResolveIP("0.0.0.0")));
     // Addresses from one network (IPv4) don't belong to subnets of another
     // network (IPv6)
     BOOST_CHECK(!ResolveSubNet("::/0").Match(ResolveIP("1.2.3.4")));
     // All-Matching IPv4 does not Match IPv6
     BOOST_CHECK(
         !ResolveSubNet("0.0.0.0/0").Match(ResolveIP("1:2:3:4:5:6:7:1234")));
     // Invalid subnets Match nothing (not even invalid addresses)
     BOOST_CHECK(!CSubNet().Match(ResolveIP("1.2.3.4")));
     BOOST_CHECK(!ResolveSubNet("").Match(ResolveIP("4.5.6.7")));
     BOOST_CHECK(!ResolveSubNet("bloop").Match(ResolveIP("0.0.0.0")));
     BOOST_CHECK(!ResolveSubNet("bloop").Match(ResolveIP("hab")));
     // Check valid/invalid
     BOOST_CHECK(ResolveSubNet("1.2.3.0/0").IsValid());
     BOOST_CHECK(!ResolveSubNet("1.2.3.0/-1").IsValid());
     BOOST_CHECK(ResolveSubNet("1.2.3.0/32").IsValid());
     BOOST_CHECK(!ResolveSubNet("1.2.3.0/33").IsValid());
     BOOST_CHECK(ResolveSubNet("1:2:3:4:5:6:7:8/0").IsValid());
     BOOST_CHECK(ResolveSubNet("1:2:3:4:5:6:7:8/33").IsValid());
     BOOST_CHECK(!ResolveSubNet("1:2:3:4:5:6:7:8/-1").IsValid());
     BOOST_CHECK(ResolveSubNet("1:2:3:4:5:6:7:8/128").IsValid());
     BOOST_CHECK(!ResolveSubNet("1:2:3:4:5:6:7:8/129").IsValid());
     BOOST_CHECK(!ResolveSubNet("fuzzy").IsValid());
 
     // CNetAddr constructor test
     BOOST_CHECK(CSubNet(ResolveIP("127.0.0.1")).IsValid());
     BOOST_CHECK(CSubNet(ResolveIP("127.0.0.1")).Match(ResolveIP("127.0.0.1")));
     BOOST_CHECK(!CSubNet(ResolveIP("127.0.0.1")).Match(ResolveIP("127.0.0.2")));
     BOOST_CHECK(CSubNet(ResolveIP("127.0.0.1")).ToString() == "127.0.0.1/32");
 
     CSubNet subnet = CSubNet(ResolveIP("1.2.3.4"), 32);
     BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.3.4/32");
     subnet = CSubNet(ResolveIP("1.2.3.4"), 8);
     BOOST_CHECK_EQUAL(subnet.ToString(), "1.0.0.0/8");
     subnet = CSubNet(ResolveIP("1.2.3.4"), 0);
     BOOST_CHECK_EQUAL(subnet.ToString(), "0.0.0.0/0");
 
     subnet = CSubNet(ResolveIP("1.2.3.4"), ResolveIP("255.255.255.255"));
     BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.3.4/32");
     subnet = CSubNet(ResolveIP("1.2.3.4"), ResolveIP("255.0.0.0"));
     BOOST_CHECK_EQUAL(subnet.ToString(), "1.0.0.0/8");
     subnet = CSubNet(ResolveIP("1.2.3.4"), ResolveIP("0.0.0.0"));
     BOOST_CHECK_EQUAL(subnet.ToString(), "0.0.0.0/0");
 
     BOOST_CHECK(CSubNet(ResolveIP("1:2:3:4:5:6:7:8")).IsValid());
     BOOST_CHECK(CSubNet(ResolveIP("1:2:3:4:5:6:7:8"))
                     .Match(ResolveIP("1:2:3:4:5:6:7:8")));
     BOOST_CHECK(!CSubNet(ResolveIP("1:2:3:4:5:6:7:8"))
                      .Match(ResolveIP("1:2:3:4:5:6:7:9")));
     BOOST_CHECK(CSubNet(ResolveIP("1:2:3:4:5:6:7:8")).ToString() ==
                 "1:2:3:4:5:6:7:8/128");
 
     subnet = ResolveSubNet("1.2.3.4/255.255.255.255");
     BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.3.4/32");
     subnet = ResolveSubNet("1.2.3.4/255.255.255.254");
     BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.3.4/31");
     subnet = ResolveSubNet("1.2.3.4/255.255.255.252");
     BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.3.4/30");
     subnet = ResolveSubNet("1.2.3.4/255.255.255.248");
     BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.3.0/29");
     subnet = ResolveSubNet("1.2.3.4/255.255.255.240");
     BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.3.0/28");
     subnet = ResolveSubNet("1.2.3.4/255.255.255.224");
     BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.3.0/27");
     subnet = ResolveSubNet("1.2.3.4/255.255.255.192");
     BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.3.0/26");
     subnet = ResolveSubNet("1.2.3.4/255.255.255.128");
     BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.3.0/25");
     subnet = ResolveSubNet("1.2.3.4/255.255.255.0");
     BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.3.0/24");
     subnet = ResolveSubNet("1.2.3.4/255.255.254.0");
     BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.2.0/23");
     subnet = ResolveSubNet("1.2.3.4/255.255.252.0");
     BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.0.0/22");
     subnet = ResolveSubNet("1.2.3.4/255.255.248.0");
     BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.0.0/21");
     subnet = ResolveSubNet("1.2.3.4/255.255.240.0");
     BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.0.0/20");
     subnet = ResolveSubNet("1.2.3.4/255.255.224.0");
     BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.0.0/19");
     subnet = ResolveSubNet("1.2.3.4/255.255.192.0");
     BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.0.0/18");
     subnet = ResolveSubNet("1.2.3.4/255.255.128.0");
     BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.0.0/17");
     subnet = ResolveSubNet("1.2.3.4/255.255.0.0");
     BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.0.0/16");
     subnet = ResolveSubNet("1.2.3.4/255.254.0.0");
     BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.0.0/15");
     subnet = ResolveSubNet("1.2.3.4/255.252.0.0");
     BOOST_CHECK_EQUAL(subnet.ToString(), "1.0.0.0/14");
     subnet = ResolveSubNet("1.2.3.4/255.248.0.0");
     BOOST_CHECK_EQUAL(subnet.ToString(), "1.0.0.0/13");
     subnet = ResolveSubNet("1.2.3.4/255.240.0.0");
     BOOST_CHECK_EQUAL(subnet.ToString(), "1.0.0.0/12");
     subnet = ResolveSubNet("1.2.3.4/255.224.0.0");
     BOOST_CHECK_EQUAL(subnet.ToString(), "1.0.0.0/11");
     subnet = ResolveSubNet("1.2.3.4/255.192.0.0");
     BOOST_CHECK_EQUAL(subnet.ToString(), "1.0.0.0/10");
     subnet = ResolveSubNet("1.2.3.4/255.128.0.0");
     BOOST_CHECK_EQUAL(subnet.ToString(), "1.0.0.0/9");
     subnet = ResolveSubNet("1.2.3.4/255.0.0.0");
     BOOST_CHECK_EQUAL(subnet.ToString(), "1.0.0.0/8");
     subnet = ResolveSubNet("1.2.3.4/254.0.0.0");
     BOOST_CHECK_EQUAL(subnet.ToString(), "0.0.0.0/7");
     subnet = ResolveSubNet("1.2.3.4/252.0.0.0");
     BOOST_CHECK_EQUAL(subnet.ToString(), "0.0.0.0/6");
     subnet = ResolveSubNet("1.2.3.4/248.0.0.0");
     BOOST_CHECK_EQUAL(subnet.ToString(), "0.0.0.0/5");
     subnet = ResolveSubNet("1.2.3.4/240.0.0.0");
     BOOST_CHECK_EQUAL(subnet.ToString(), "0.0.0.0/4");
     subnet = ResolveSubNet("1.2.3.4/224.0.0.0");
     BOOST_CHECK_EQUAL(subnet.ToString(), "0.0.0.0/3");
     subnet = ResolveSubNet("1.2.3.4/192.0.0.0");
     BOOST_CHECK_EQUAL(subnet.ToString(), "0.0.0.0/2");
     subnet = ResolveSubNet("1.2.3.4/128.0.0.0");
     BOOST_CHECK_EQUAL(subnet.ToString(), "0.0.0.0/1");
     subnet = ResolveSubNet("1.2.3.4/0.0.0.0");
     BOOST_CHECK_EQUAL(subnet.ToString(), "0.0.0.0/0");
 
     subnet = ResolveSubNet(
         "1:2:3:4:5:6:7:8/ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff");
     BOOST_CHECK_EQUAL(subnet.ToString(), "1:2:3:4:5:6:7:8/128");
     subnet = ResolveSubNet(
         "1:2:3:4:5:6:7:8/ffff:0000:0000:0000:0000:0000:0000:0000");
     BOOST_CHECK_EQUAL(subnet.ToString(), "1::/16");
     subnet = ResolveSubNet(
         "1:2:3:4:5:6:7:8/0000:0000:0000:0000:0000:0000:0000:0000");
     BOOST_CHECK_EQUAL(subnet.ToString(), "::/0");
+    // Invalid netmasks (with 1-bits after 0-bits)
     subnet = ResolveSubNet("1.2.3.4/255.255.232.0");
-    BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.0.0/255.255.232.0");
+    BOOST_CHECK(!subnet.IsValid());
+    subnet = ResolveSubNet("1.2.3.4/255.0.255.255");
+    BOOST_CHECK(!subnet.IsValid());
     subnet = ResolveSubNet(
         "1:2:3:4:5:6:7:8/ffff:ffff:ffff:fffe:ffff:ffff:ffff:ff0f");
-    BOOST_CHECK_EQUAL(
-        subnet.ToString(),
-        "1:2:3:4:5:6:7:8/ffff:ffff:ffff:fffe:ffff:ffff:ffff:ff0f");
+    BOOST_CHECK(!subnet.IsValid());
 }
 
 BOOST_AUTO_TEST_CASE(netbase_getgroup) {
     // use /16
     std::vector<bool> asmap;
     typedef std::vector<uint8_t> Vec8;
     // Local -> !Routable()
     BOOST_CHECK(ResolveIP("127.0.0.1").GetGroup(asmap) == Vec8{0});
     // !Valid -> !Routable()
     BOOST_CHECK(ResolveIP("257.0.0.1").GetGroup(asmap) == Vec8{0});
     // RFC1918 -> !Routable()
     BOOST_CHECK(ResolveIP("10.0.0.1").GetGroup(asmap) == Vec8{0});
     // RFC3927 -> !Routable()
     BOOST_CHECK(ResolveIP("169.254.1.1").GetGroup(asmap) == Vec8{0});
     // IPv4
     BOOST_CHECK(ResolveIP("1.2.3.4").GetGroup(asmap) == Vec8({NET_IPV4, 1, 2}));
     // RFC6145
     BOOST_CHECK(ResolveIP("::FFFF:0:102:304").GetGroup(asmap) ==
                 Vec8({NET_IPV4, 1, 2}));
     // RFC6052
     BOOST_CHECK(ResolveIP("64:FF9B::102:304").GetGroup(asmap) ==
                 Vec8({NET_IPV4, 1, 2}));
     // RFC3964
     BOOST_CHECK(
         ResolveIP("2002:102:304:9999:9999:9999:9999:9999").GetGroup(asmap) ==
         Vec8({NET_IPV4, 1, 2}));
     // RFC4380
     BOOST_CHECK(
         ResolveIP("2001:0:9999:9999:9999:9999:FEFD:FCFB").GetGroup(asmap) ==
         Vec8({NET_IPV4, 1, 2}));
     // Tor
     BOOST_CHECK(
         ResolveIP("FD87:D87E:EB43:edb1:8e4:3588:e546:35ca").GetGroup(asmap) ==
         Vec8({NET_ONION, 239}));
     // he.net
     BOOST_CHECK(
         ResolveIP("2001:470:abcd:9999:9999:9999:9999:9999").GetGroup(asmap) ==
         Vec8({NET_IPV6, 32, 1, 4, 112, 175}));
     // IPv6
     BOOST_CHECK(
         ResolveIP("2001:2001:9999:9999:9999:9999:9999:9999").GetGroup(asmap) ==
         Vec8({NET_IPV6, 32, 1, 32, 1}));
 
     // baz.net sha256 hash:
     // 12929400eb4607c4ac075f087167e75286b179c693eb059a01774b864e8fe505
     Vec8 internal_group = {NET_INTERNAL, 0x12, 0x92, 0x94, 0x00, 0xeb,
                            0x46,         0x07, 0xc4, 0xac, 0x07};
     BOOST_CHECK(CreateInternal("baz.net").GetGroup(asmap) == internal_group);
 }
 
 BOOST_AUTO_TEST_CASE(netbase_parsenetwork) {
     BOOST_CHECK_EQUAL(ParseNetwork("ipv4"), NET_IPV4);
     BOOST_CHECK_EQUAL(ParseNetwork("ipv6"), NET_IPV6);
     BOOST_CHECK_EQUAL(ParseNetwork("onion"), NET_ONION);
     BOOST_CHECK_EQUAL(ParseNetwork("tor"), NET_ONION);
 
     BOOST_CHECK_EQUAL(ParseNetwork("IPv4"), NET_IPV4);
     BOOST_CHECK_EQUAL(ParseNetwork("IPv6"), NET_IPV6);
     BOOST_CHECK_EQUAL(ParseNetwork("ONION"), NET_ONION);
     BOOST_CHECK_EQUAL(ParseNetwork("TOR"), NET_ONION);
 
     BOOST_CHECK_EQUAL(ParseNetwork(":)"), NET_UNROUTABLE);
     BOOST_CHECK_EQUAL(ParseNetwork("tÖr"), NET_UNROUTABLE);
     BOOST_CHECK_EQUAL(ParseNetwork("\xfe\xff"), NET_UNROUTABLE);
     BOOST_CHECK_EQUAL(ParseNetwork(""), NET_UNROUTABLE);
 }
 
 BOOST_AUTO_TEST_CASE(netpermissions_test) {
     bilingual_str error;
     NetWhitebindPermissions whitebindPermissions;
     NetWhitelistPermissions whitelistPermissions;
 
     // Detect invalid white bind
     BOOST_CHECK(
         !NetWhitebindPermissions::TryParse("", whitebindPermissions, error));
     BOOST_CHECK(error.original.find("Cannot resolve -whitebind address") !=
                 std::string::npos);
     BOOST_CHECK(!NetWhitebindPermissions::TryParse(
         "127.0.0.1", whitebindPermissions, error));
     BOOST_CHECK(error.original.find("Need to specify a port with -whitebind") !=
                 std::string::npos);
     BOOST_CHECK(
         !NetWhitebindPermissions::TryParse("", whitebindPermissions, error));
 
     // If no permission flags, assume backward compatibility
     BOOST_CHECK(NetWhitebindPermissions::TryParse("1.2.3.4:32",
                                                   whitebindPermissions, error));
     BOOST_CHECK(error.empty());
     BOOST_CHECK_EQUAL(whitebindPermissions.m_flags, PF_ISIMPLICIT);
     BOOST_CHECK(
         NetPermissions::HasFlag(whitebindPermissions.m_flags, PF_ISIMPLICIT));
     NetPermissions::ClearFlag(whitebindPermissions.m_flags, PF_ISIMPLICIT);
     BOOST_CHECK(
         !NetPermissions::HasFlag(whitebindPermissions.m_flags, PF_ISIMPLICIT));
     BOOST_CHECK_EQUAL(whitebindPermissions.m_flags, PF_NONE);
     NetPermissions::AddFlag(whitebindPermissions.m_flags, PF_ISIMPLICIT);
     BOOST_CHECK(
         NetPermissions::HasFlag(whitebindPermissions.m_flags, PF_ISIMPLICIT));
 
     // Can set one permission
     BOOST_CHECK(NetWhitebindPermissions::TryParse("bloom@1.2.3.4:32",
                                                   whitebindPermissions, error));
     BOOST_CHECK_EQUAL(whitebindPermissions.m_flags, PF_BLOOMFILTER);
     BOOST_CHECK(NetWhitebindPermissions::TryParse("@1.2.3.4:32",
                                                   whitebindPermissions, error));
     BOOST_CHECK_EQUAL(whitebindPermissions.m_flags, PF_NONE);
 
     // Happy path, can parse flags
     BOOST_CHECK(NetWhitebindPermissions::TryParse("bloom,forcerelay@1.2.3.4:32",
                                                   whitebindPermissions, error));
     // forcerelay should also activate the relay permission
     BOOST_CHECK_EQUAL(whitebindPermissions.m_flags,
                       PF_BLOOMFILTER | PF_FORCERELAY | PF_RELAY);
     BOOST_CHECK(NetWhitebindPermissions::TryParse(
         "bloom,relay,noban@1.2.3.4:32", whitebindPermissions, error));
     BOOST_CHECK_EQUAL(whitebindPermissions.m_flags,
                       PF_BLOOMFILTER | PF_RELAY | PF_NOBAN);
     BOOST_CHECK(NetWhitebindPermissions::TryParse(
         "bloom,forcerelay,noban@1.2.3.4:32", whitebindPermissions, error));
     BOOST_CHECK(NetWhitebindPermissions::TryParse("all@1.2.3.4:32",
                                                   whitebindPermissions, error));
     BOOST_CHECK_EQUAL(whitebindPermissions.m_flags, PF_ALL);
 
     // Allow dups
     BOOST_CHECK(NetWhitebindPermissions::TryParse(
         "bloom,relay,noban,noban@1.2.3.4:32", whitebindPermissions, error));
     BOOST_CHECK_EQUAL(whitebindPermissions.m_flags,
                       PF_BLOOMFILTER | PF_RELAY | PF_NOBAN);
 
     // Allow empty
     BOOST_CHECK(NetWhitebindPermissions::TryParse(
         "bloom,relay,,noban@1.2.3.4:32", whitebindPermissions, error));
     BOOST_CHECK_EQUAL(whitebindPermissions.m_flags,
                       PF_BLOOMFILTER | PF_RELAY | PF_NOBAN);
     BOOST_CHECK(NetWhitebindPermissions::TryParse(",@1.2.3.4:32",
                                                   whitebindPermissions, error));
     BOOST_CHECK_EQUAL(whitebindPermissions.m_flags, PF_NONE);
     BOOST_CHECK(NetWhitebindPermissions::TryParse(",,@1.2.3.4:32",
                                                   whitebindPermissions, error));
     BOOST_CHECK_EQUAL(whitebindPermissions.m_flags, PF_NONE);
 
     // Detect invalid flag
     BOOST_CHECK(!NetWhitebindPermissions::TryParse(
         "bloom,forcerelay,oopsie@1.2.3.4:32", whitebindPermissions, error));
     BOOST_CHECK(error.original.find("Invalid P2P permission") !=
                 std::string::npos);
 
     // Check whitelist error
     BOOST_CHECK(!NetWhitelistPermissions::TryParse(
         "bloom,forcerelay,noban@1.2.3.4:32", whitelistPermissions, error));
     BOOST_CHECK(
         error.original.find("Invalid netmask specified in -whitelist") !=
         std::string::npos);
 
     // Happy path for whitelist parsing
     BOOST_CHECK(NetWhitelistPermissions::TryParse("noban@1.2.3.4",
                                                   whitelistPermissions, error));
     BOOST_CHECK_EQUAL(whitelistPermissions.m_flags, PF_NOBAN);
     BOOST_CHECK(NetWhitelistPermissions::TryParse(
         "bloom,forcerelay,noban,relay@1.2.3.4/32", whitelistPermissions,
         error));
     BOOST_CHECK_EQUAL(whitelistPermissions.m_flags,
                       PF_BLOOMFILTER | PF_FORCERELAY | PF_NOBAN | PF_RELAY);
     BOOST_CHECK(error.empty());
     BOOST_CHECK_EQUAL(whitelistPermissions.m_subnet.ToString(), "1.2.3.4/32");
     BOOST_CHECK(NetWhitelistPermissions::TryParse(
         "bloom,forcerelay,noban,relay,mempool@1.2.3.4/32", whitelistPermissions,
         error));
 
     const auto strings = NetPermissions::ToStrings(PF_ALL);
     BOOST_CHECK_EQUAL(strings.size(), 5);
     BOOST_CHECK(std::find(strings.begin(), strings.end(), "bloomfilter") !=
                 strings.end());
     BOOST_CHECK(std::find(strings.begin(), strings.end(), "forcerelay") !=
                 strings.end());
     BOOST_CHECK(std::find(strings.begin(), strings.end(), "relay") !=
                 strings.end());
     BOOST_CHECK(std::find(strings.begin(), strings.end(), "noban") !=
                 strings.end());
     BOOST_CHECK(std::find(strings.begin(), strings.end(), "mempool") !=
                 strings.end());
 }
 
 BOOST_AUTO_TEST_CASE(
     netbase_dont_resolve_strings_with_embedded_nul_characters) {
     CNetAddr addr;
     BOOST_CHECK(LookupHost(std::string("127.0.0.1", 9), addr, false));
     BOOST_CHECK(!LookupHost(std::string("127.0.0.1\0", 10), addr, false));
     BOOST_CHECK(
         !LookupHost(std::string("127.0.0.1\0example.com", 21), addr, false));
     BOOST_CHECK(
         !LookupHost(std::string("127.0.0.1\0example.com\0", 22), addr, false));
     CSubNet ret;
     BOOST_CHECK(LookupSubNet(std::string("1.2.3.0/24", 10), ret));
     BOOST_CHECK(!LookupSubNet(std::string("1.2.3.0/24\0", 11), ret));
     BOOST_CHECK(!LookupSubNet(std::string("1.2.3.0/24\0example.com", 22), ret));
     BOOST_CHECK(
         !LookupSubNet(std::string("1.2.3.0/24\0example.com\0", 23), ret));
     BOOST_CHECK(LookupSubNet(std::string("5wyqrzbvrdsumnok.onion", 22), ret));
     BOOST_CHECK(
         !LookupSubNet(std::string("5wyqrzbvrdsumnok.onion\0", 23), ret));
     BOOST_CHECK(!LookupSubNet(
         std::string("5wyqrzbvrdsumnok.onion\0example.com", 34), ret));
     BOOST_CHECK(!LookupSubNet(
         std::string("5wyqrzbvrdsumnok.onion\0example.com\0", 35), ret));
 }
 
 BOOST_AUTO_TEST_SUITE_END()