From 6aa3cedfa5e9df7aacbbdcf62c977e09b0e7f6c3 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Sun, 27 Nov 2016 23:43:46 +0100 Subject: [PATCH] expand logic for address class detection, including private and sensitive IP classification --- src/include/gnunet_nat_service.h | 25 +++++++-- src/nat/gnunet-service-nat.c | 94 ++++++++++++++++++++++++++++++++ 2 files changed, 115 insertions(+), 4 deletions(-) diff --git a/src/include/gnunet_nat_service.h b/src/include/gnunet_nat_service.h index ad3438538..a59069545 100644 --- a/src/include/gnunet_nat_service.h +++ b/src/include/gnunet_nat_service.h @@ -64,16 +64,21 @@ enum GNUNET_NAT_AddressClass GNUNET_NAT_AC_OTHER = 1, /** - * Addresses that are global and are insensitive - * (i.e. IPv4). + * Addresses that are highly sensitive + * (i.e. IPv6 with our MAC). + */ + GNUNET_NAT_AC_PRIVATE = 2, + + /** + * Addresses that are global (i.e. IPv4). */ - GNUNET_NAT_AC_GLOBAL = 2, + GNUNET_NAT_AC_GLOBAL = 4, /** * Addresses that are global and are sensitive * (i.e. IPv6 with our MAC). */ - GNUNET_NAT_AC_GLOBAL_PRIVATE = 4, + GNUNET_NAT_AC_GLOBAL_PRIVATE = 6, /** * Addresses useful in the local wired network, @@ -81,6 +86,13 @@ enum GNUNET_NAT_AddressClass * Useful for broadcasts. */ GNUNET_NAT_AC_LAN = 8, + + /** + * Addresses useful in the local wired network, + * i.e. a MAC. Sensitive, but obvious to people nearby. + * Useful for broadcasts. + */ + GNUNET_NAT_AC_LAN_PRIVATE = 10, /** * Addresses useful in the local wireless network, @@ -95,6 +107,11 @@ enum GNUNET_NAT_AddressClass */ GNUNET_NAT_AC_BT = 32, + /** + * Loopback addresses, only useful under special cirumstances. + */ + GNUNET_NAT_AC_LOOPBACK = 64, + /** * Bitmask for "any" address. */ diff --git a/src/nat/gnunet-service-nat.c b/src/nat/gnunet-service-nat.c index e42a94ea4..a6aa21cd1 100644 --- a/src/nat/gnunet-service-nat.c +++ b/src/nat/gnunet-service-nat.c @@ -603,6 +603,72 @@ struct IfcProcContext }; +/** + * Check if @a ip is in @a network with @a bits netmask. + * + * @param network to test + * @param ip IP address to test + * @param bits bitmask for the network + * @return #GNUNET_YES if @a ip is in @a network + */ +static int +match_ipv4 (const char *network, + const struct in_addr *ip, + uint8_t bits) +{ + struct in_addr net; + + if (0 == bits) + return GNUNET_YES; + GNUNET_assert (1 == inet_pton (AF_INET, + network, + &net)); + return ! ((ip->s_addr ^ net.s_addr) & htonl (0xFFFFFFFFu << (32 - bits))); +} + + +/** + * Check if @a ip is in @a network with @a bits netmask. + * + * @param network to test + * @param ip IP address to test + * @param bits bitmask for the network + * @return #GNUNET_YES if @a ip is in @a network + */ +static int +match_ipv6 (const char *network, + const struct in6_addr *ip, + uint8_t bits) +{ + struct in6_addr net; + struct in6_addr mask; + unsigned int off; + + if (0 == bits) + return GNUNET_YES; + GNUNET_assert (1 == inet_pton (AF_INET, + network, + &net)); + memset (&mask, 0, sizeof (mask)); + off = 0; + while (bits > 8) + { + mask.s6_addr[off++] = 0xFF; + bits -= 8; + } + while (bits > 0) + { + mask.s6_addr[off] = (mask.s6_addr[off] >> 1) + 0x80; + bits--; + } + for (unsigned j = 0; j < sizeof (struct in6_addr) / sizeof (uint32_t); j++) + if (((((uint32_t *) ip)[j] & ((uint32_t *) &mask)[j])) != + (((uint32_t *) &net)[j] & ((int *) &mask)[j])) + return GNUNET_NO; + return GNUNET_YES; +} + + /** * Callback function invoked for each interface found. Adds them * to our new address list. @@ -629,16 +695,43 @@ ifc_proc (void *cls, struct LocalAddressList *lal; size_t alen; const void *ip; + const struct in6_addr *v6; + enum GNUNET_NAT_AddressClass ac; switch (addr->sa_family) { case AF_INET: alen = sizeof (struct in_addr); ip = &((const struct sockaddr_in *) addr)->sin_addr; + if (match_ipv4 ("127.0.0.0", ip, 8)) + ac = GNUNET_NAT_AC_LOOPBACK; + else if (match_ipv4 ("10.0.0.0", ip, 8) || /* RFC 1918 */ + match_ipv4 ("100.64.0.0", ip, 10) || /* CG-NAT, RFC 6598 */ + match_ipv4 ("192.168.0.0", ip, 12) || /* RFC 1918 */ + match_ipv4 ("169.254.0.0", ip, 16) || /* AUTO, RFC 3927 */ + match_ipv4 ("172.16.0.0", ip, 16)) /* RFC 1918 */ + ac = GNUNET_NAT_AC_LAN; + else + ac = GNUNET_NAT_AC_GLOBAL; break; case AF_INET6: alen = sizeof (struct in6_addr); ip = &((const struct sockaddr_in6 *) addr)->sin6_addr; + if (match_ipv6 ("::1", ip, 128)) + ac = GNUNET_NAT_AC_LOOPBACK; + else if (match_ipv6 ("fc00::", ip, 7) || /* RFC 4193 */ + match_ipv6 ("fec0::", ip, 10) || /* RFC 3879 */ + match_ipv6 ("fe80::", ip, 10)) /* RFC 4291, link-local */ + ac = GNUNET_NAT_AC_LAN; + else + ac = GNUNET_NAT_AC_GLOBAL; + v6 = ip; + if ( (v6->s6_addr[11] == 0xFF) && + (v6->s6_addr[12] == 0xFE) ) + { + /* contains a MAC, be extra careful! */ + ac |= GNUNET_NAT_AC_PRIVATE; + } break; #if AF_UNIX case AF_UNIX: @@ -652,6 +745,7 @@ ifc_proc (void *cls, lal = GNUNET_malloc (sizeof (*lal) + alen); lal->af = addr->sa_family; lal->addr = &lal[1]; + lal->ac = ac; GNUNET_memcpy (&lal[1], ip, alen); -- 2.25.1