From 7e2f0d10d9ac29559fb05e856621d8af38273a37 Mon Sep 17 00:00:00 2001 From: Matthias Wachs Date: Mon, 12 Dec 2011 17:11:37 +0000 Subject: [PATCH] WAN/LAN detection Mantis 1991 --- src/ats/gnunet-service-ats_addresses.c | 117 +++++++++++++++++-------- src/include/gnunet_ats_service.h | 14 +++ 2 files changed, 96 insertions(+), 35 deletions(-) diff --git a/src/ats/gnunet-service-ats_addresses.c b/src/ats/gnunet-service-ats_addresses.c index 0e4dfd6be..c1975e686 100644 --- a/src/ats/gnunet-service-ats_addresses.c +++ b/src/ats/gnunet-service-ats_addresses.c @@ -487,11 +487,28 @@ GAS_addresses_type (const struct sockaddr * addr, socklen_t addrlen) { struct GNUNET_ATS_Information ats; struct ATS_Network * cur = net_head; - int is_lan = GNUNET_NO; + int type = GNUNET_ATS_NET_UNSPECIFIED; GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Checking type of address `%s'\n", GNUNET_a2s(addr, addrlen)); - while (cur != NULL) + /* IPv4 loopback check */ + if (addr->sa_family == AF_INET) + { + struct sockaddr_in * a4 = (struct sockaddr_in *) addr; + + if (((a4->sin_addr.s_addr & htonl(0xff000000)) & htonl (0x7f000000)) == htonl (0x7f000000)) + type = GNUNET_ATS_NET_LOOPBACK; + } + /* IPv6 loopback check */ + if (addr->sa_family == AF_INET6) + { + struct sockaddr_in6 * a6 = (struct sockaddr_in6 *) addr; + if (IN6_IS_ADDR_LOOPBACK (&a6->sin6_addr)) + type = GNUNET_ATS_NET_LOOPBACK; + } + + /* Check local networks */ + while ((cur != NULL) && (type == GNUNET_ATS_NET_UNSPECIFIED)) { if (addrlen != cur->length) { @@ -508,42 +525,46 @@ GAS_addresses_type (const struct sockaddr * addr, socklen_t addrlen) if (((a4->sin_addr.s_addr & mask4->sin_addr.s_addr) & net4->sin_addr.s_addr) == net4->sin_addr.s_addr) { char * net = strdup (GNUNET_a2s ((const struct sockaddr *) net4, addrlen)); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "`%s' in network `%s': YES \n", + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "`%s' is in network `%s'\n", GNUNET_a2s ((const struct sockaddr *)a4, addrlen), net); GNUNET_free (net); - is_lan = GNUNET_YES; - } - else - { - char * net = strdup (GNUNET_a2s ((const struct sockaddr *) net4, addrlen)); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "`%s' in network `%s': NO \n", - GNUNET_a2s ((const struct sockaddr *)a4, addrlen), - net); - GNUNET_free (net); - is_lan = GNUNET_YES; + type = GNUNET_ATS_NET_LAN; } } if (addr->sa_family == AF_INET6) { + struct sockaddr_in6 * a6 = (struct sockaddr_in6 *) addr; + struct sockaddr_in6 * net6 = (struct sockaddr_in6 *) cur->network; + struct sockaddr_in6 * mask6 = (struct sockaddr_in6 *) cur->netmask; - } + int res = GNUNET_YES; + int c = 0; + for (c = 0; c < 4; c++) + { + if (((a6->sin6_addr.__in6_u.__u6_addr32[c] & mask6->sin6_addr.__in6_u.__u6_addr32[c]) | net6->sin6_addr.__in6_u.__u6_addr32[c]) != net6->sin6_addr.__in6_u.__u6_addr32[c]) + res = GNUNET_NO; + } - if (is_lan == GNUNET_YES) - break; + if (res == GNUNET_YES) + { + char * net = strdup (GNUNET_a2s ((const struct sockaddr *) net6, addrlen)); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "`%s' is in network `%s'\n", + GNUNET_a2s ((const struct sockaddr *) a6, addrlen), + net); + GNUNET_free (net); + type = GNUNET_ATS_NET_LAN; + } + } cur = cur->next; } - if (is_lan == GNUNET_NO) - { - ats.type = ntohl(GNUNET_ATS_ARRAY_TERMINATOR); - ats.value = ntohl(GNUNET_ATS_ARRAY_TERMINATOR); - } - else - { - ats.type = ntohl(GNUNET_ATS_ARRAY_TERMINATOR); - ats.value = ntohl(GNUNET_ATS_ARRAY_TERMINATOR); - } + /* local network found for this address, default: WAN */ + if (type == GNUNET_ATS_NET_UNSPECIFIED) + type = GNUNET_ATS_NET_WAN; + + ats.type = htonl (GNUNET_ATS_NETWORK_TYPE); + ats.value = htonl (type); return ats; } @@ -561,21 +582,19 @@ interface_proc (void *cls, const char *name, struct ATS_Network *net = NULL; if (addr->sa_family == AF_INET) { - struct ATS_Network *net = NULL; struct sockaddr_in *addr4 = (struct sockaddr_in *) addr; struct sockaddr_in *netmask4 = (struct sockaddr_in *) netmask; - struct sockaddr * tmp = NULL; + struct sockaddr_in *tmp = NULL; struct sockaddr_in network4; - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding %s address: %s\n", (addr->sa_family == AF_INET) ? "IPv4" : "IPv6" ,GNUNET_a2s(addr, addrlen)); - net = GNUNET_malloc(sizeof (struct ATS_Network) + 2 * sizeof (struct sockaddr_in)); - tmp = (struct sockaddr *) &net[1]; - net->network = &tmp[0]; - net->netmask = &tmp[1]; + tmp = (struct sockaddr_in *) &net[1]; + net->network = (struct sockaddr *) &tmp[0]; + net->netmask = (struct sockaddr *) &tmp[1]; net->length = addrlen; network4.sin_family = AF_INET; + network4.sin_port = htons (0); #if HAVE_SOCKADDR_IN_SIN_LEN network4.sin_len = sizeof (network4); #endif @@ -591,17 +610,45 @@ interface_proc (void *cls, const char *name, GNUNET_free (netmask); } + if (addr->sa_family == AF_INET6) { + struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *) addr; + struct sockaddr_in6 *netmask6 = (struct sockaddr_in6 *) netmask; + struct sockaddr_in6 * tmp = NULL; + struct sockaddr_in6 network6; + + net = GNUNET_malloc(sizeof (struct ATS_Network) + 2 * sizeof (struct sockaddr_in6)); + tmp = (struct sockaddr_in6 *) &net[1]; + net->network = (struct sockaddr *) &tmp[0]; + net->netmask = (struct sockaddr *) &tmp[1]; + net->length = addrlen; + network6.sin6_family = AF_INET6; + network6.sin6_port = htons (0); +#if HAVE_SOCKADDR_IN_SIN_LEN + network6.sin6_len = sizeof (network6); +#endif + int c = 0; + for (c = 0; c < 4; c++) + { + network6.sin6_addr.__in6_u.__u6_addr32[c] = addr6->sin6_addr.__in6_u.__u6_addr32[c] & netmask6->sin6_addr.__in6_u.__u6_addr32[c]; + } + + memcpy (net->netmask, netmask6, sizeof (struct sockaddr_in6)); + memcpy (net->network, &network6, sizeof (struct sockaddr_in6)); + + char * netmask = strdup (GNUNET_a2s((struct sockaddr *) net->netmask, addrlen)); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding network `%s', netmask `%s'\n", + GNUNET_a2s((struct sockaddr *) net->network, addrlen), + netmask); + GNUNET_free (netmask); } /* Store in list */ if (net != NULL) GNUNET_CONTAINER_DLL_insert(net_head, net_tail, net); - //GAS_addresses_type (addr, addrlen); - return GNUNET_OK; } diff --git a/src/include/gnunet_ats_service.h b/src/include/gnunet_ats_service.h index ecbdd2f70..898a06654 100644 --- a/src/include/gnunet_ats_service.h +++ b/src/include/gnunet_ats_service.h @@ -31,6 +31,14 @@ #include "gnunet_hello_lib.h" +enum GNUNET_ATS_Network_Type +{ + GNUNET_ATS_NET_UNSPECIFIED, + GNUNET_ATS_NET_LOOPBACK, + GNUNET_ATS_NET_LAN, + GNUNET_ATS_NET_WAN +}; + /** * Enum defining all known property types for ATS Enum values are used * in the GNUNET_ATS_Information struct as @@ -62,6 +70,12 @@ enum GNUNET_ATS_Property */ GNUNET_ATS_UTILIZATION_DOWN, + /** + * Is this address located in WAN, LAN or a loopback address + * Value is element of GNUNET_ATS_Network_Type + */ + GNUNET_ATS_NETWORK_TYPE, + /** * Delay * Time between when the time packet is sent and the packet arrives -- 2.25.1