diff options
author | Christian Grothoff <christian@grothoff.org> | 2016-12-16 10:53:58 +0100 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2016-12-16 10:53:58 +0100 |
commit | 8108e41d89bb771fe8bcf887919de3f581f1cc0d (patch) | |
tree | 970c382485c663f8c8516b59e34790d33878dbfb | |
parent | f88d55e43f3d3a4468c2faa0621044ad17594e5f (diff) |
add PORT to NAT configuration, generate nat.conf from nat.conf.in, implement more of new NAT service
-rw-r--r-- | configure.ac | 1 | ||||
-rw-r--r-- | src/conversation/conversation.conf.in | 2 | ||||
-rw-r--r-- | src/include/gnunet_nat_service.h | 10 | ||||
-rw-r--r-- | src/nat/Makefile.am | 2 | ||||
-rw-r--r-- | src/nat/gnunet-service-nat.c | 274 | ||||
-rw-r--r-- | src/nat/gnunet-service-nat_helper.c | 40 | ||||
-rw-r--r-- | src/nat/gnunet-service-nat_helper.h | 8 | ||||
-rw-r--r-- | src/nat/nat.conf.in (renamed from src/nat/nat.conf) | 10 | ||||
-rw-r--r-- | src/rps/rps.conf.in | 2 |
9 files changed, 217 insertions, 132 deletions
diff --git a/configure.ac b/configure.ac index ebe5753aaa..faf058849b 100644 --- a/configure.ac +++ b/configure.ac @@ -1595,6 +1595,7 @@ src/namecache/namecache.conf src/namestore/Makefile src/namestore/namestore.conf src/nat/Makefile +src/nat/nat.conf src/nse/Makefile src/nse/nse.conf src/peerinfo/Makefile diff --git a/src/conversation/conversation.conf.in b/src/conversation/conversation.conf.in index fb0478f4ed..e966ed6d9f 100644 --- a/src/conversation/conversation.conf.in +++ b/src/conversation/conversation.conf.in @@ -3,7 +3,7 @@ AUTOSTART = @AUTOSTART@ BINARY = gnunet-service-conversation UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-conversation.sock HOSTNAME = localhost -@UNIXONLY@ PORT = 2106 +@UNIXONLY@ PORT = 2120 # Desired phone line. Change if multiple users are using # the same peer and we thus need disjoint phone lines. diff --git a/src/include/gnunet_nat_service.h b/src/include/gnunet_nat_service.h index 378f5a8cbd..b66b442405 100644 --- a/src/include/gnunet_nat_service.h +++ b/src/include/gnunet_nat_service.h @@ -64,7 +64,7 @@ enum GNUNET_NAT_AddressClass GNUNET_NAT_AC_OTHER = 1, /** - * Addresses that are highly sensitive + * Flag for addresses that are highly sensitive * (i.e. IPv6 with our MAC). */ GNUNET_NAT_AC_PRIVATE = 2, @@ -83,6 +83,7 @@ enum GNUNET_NAT_AddressClass /** * Addresses useful in the local wired network, * i.e. a MAC. Sensitive, but obvious to people nearby. + * Useful for broadcasts. */ GNUNET_NAT_AC_LAN = 8, @@ -113,6 +114,13 @@ enum GNUNET_NAT_AddressClass GNUNET_NAT_AC_LOOPBACK = 64, /** + * Addresses that should be our global external IP address + * on the outside of a NAT. Might be incorrectly determined. + * Used as a bit in combination with #GNUNET_NAT_AC_GLOBAL. + */ + GNUNET_NAT_AC_GLOBAL_EXTERN = 128, + + /** * Bitmask for "any" address. */ GNUNET_NAT_AC_ANY = 65535 diff --git a/src/nat/Makefile.am b/src/nat/Makefile.am index d304a57d07..c62a8d2cf9 100644 --- a/src/nat/Makefile.am +++ b/src/nat/Makefile.am @@ -12,7 +12,7 @@ libexecdir= $(pkglibdir)/libexec/ pkgcfgdir= $(pkgdatadir)/config.d/ -dist_pkgcfg_DATA = \ +pkgcfg_DATA = \ nat.conf if LINUX diff --git a/src/nat/gnunet-service-nat.c b/src/nat/gnunet-service-nat.c index f4755659f2..1ebf75608e 100644 --- a/src/nat/gnunet-service-nat.c +++ b/src/nat/gnunet-service-nat.c @@ -28,10 +28,8 @@ * knowledge about the local network topology. * * TODO: - * - call GN_start_gnunet_nat_server_() if possible (i.e. - * when we find we have a non-global IPv4 address) + * - implement UPnPC/PMP-based NAT traversal * - implement autoconfig - * - implmeent UPnPC/PMP-based NAT traversal * - implement NEW logic for external IP detection */ #include "platform.h" @@ -91,6 +89,11 @@ struct ClientHandle enum GNUNET_NAT_RegisterFlags flags; /** + * Is any of the @e addrs in a reserved subnet for NAT? + */ + int natted_address; + + /** * Port we would like as we are configured to use this one for * advertising (in addition to the one we are binding to). */ @@ -306,6 +309,108 @@ check_register (void *cls, /** + * 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; +} + + +/** + * Test if the given IPv4 address is in a known range + * for private networks. + * + * @param ip address to test + * @return #GNUNET_YES if @a ip is in a NAT range + */ +static int +is_nat_v4 (const struct in_addr *ip) +{ + return + 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 */ +} + + +/** + * Test if the given IPv6 address is in a known range + * for private networks. + * + * @param ip address to test + * @return #GNUNET_YES if @a ip is in a NAT range + */ +static int +is_nat_v6 (const struct in6_addr *ip) +{ + return + match_ipv6 ("fc00::", ip, 7) || /* RFC 4193 */ + match_ipv6 ("fec0::", ip, 10) || /* RFC 3879 */ + match_ipv6 ("fe80::", ip, 10); /* RFC 4291, link-local */ +} + + +/** * Handler for #GNUNET_MESSAGE_TYPE_NAT_REGISTER message from client. * We remember the client for updates upon future NAT events. * @@ -352,10 +457,22 @@ handle_register (void *cls, switch (sa->sa_family) { case AF_INET: - alen = sizeof (struct sockaddr_in); + { + const struct sockaddr_in *s4 = (const struct sockaddr_in *) sa; + + alen = sizeof (struct sockaddr_in); + if (is_nat_v4 (&s4->sin_addr)) + ch->natted_address = GNUNET_YES; + } break; case AF_INET6: - alen = sizeof (struct sockaddr_in6); + { + const struct sockaddr_in6 *s6 = (const struct sockaddr_in6 *) sa; + + alen = sizeof (struct sockaddr_in6); + if (is_nat_v6 (&s6->sin6_addr)) + ch->natted_address = GNUNET_YES; + } break; #if AF_UNIX case AF_UNIX: @@ -418,7 +535,30 @@ static void notify_clients_stun_change (const struct sockaddr_in *ip, int add) { - /* FIXME: notify clients about add/drop */ + for (struct ClientHandle *ch = ch_head; + NULL != ch; + ch = ch->next) + { + struct sockaddr_in v4; + struct GNUNET_NAT_AddressChangeNotificationMessage *msg; + struct GNUNET_MQ_Envelope *env; + + if (! ch->natted_address) + continue; + v4 = *ip; + v4.sin_port = htons (ch->adv_port); + env = GNUNET_MQ_msg_extra (msg, + sizeof (v4), + GNUNET_MESSAGE_TYPE_NAT_ADDRESS_CHANGE); + msg->add_remove = htonl ((int32_t) add); + msg->addr_class = htonl (GNUNET_NAT_AC_GLOBAL_EXTERN | + GNUNET_NAT_AC_GLOBAL); + GNUNET_memcpy (&msg[1], + &v4, + sizeof (v4)); + GNUNET_MQ_send (ch->mq, + env); + } } @@ -599,6 +739,9 @@ handle_request_connection_reversal (void *cls, size_t remote_sa_len = ntohs (message->remote_addr_size); const struct sockaddr *local_sa = (const struct sockaddr *) &buf[0]; const struct sockaddr *remote_sa = (const struct sockaddr *) &buf[local_sa_len]; + const struct sockaddr_in *l4 = NULL; + const struct sockaddr_in *r4; + int ret; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received REQUEST CONNECTION REVERSAL message from client\n"); @@ -611,6 +754,7 @@ handle_request_connection_reversal (void *cls, GNUNET_SERVICE_client_drop (ch->client); return; } + l4 = (const struct sockaddr_in *) local_sa; break; case AF_INET6: if (local_sa_len != sizeof (struct sockaddr_in6)) @@ -619,6 +763,9 @@ handle_request_connection_reversal (void *cls, GNUNET_SERVICE_client_drop (ch->client); return; } + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Connection reversal for IPv6 not supported yet\n")); + ret = GNUNET_SYSERR; break; default: GNUNET_break (0); @@ -634,6 +781,10 @@ handle_request_connection_reversal (void *cls, GNUNET_SERVICE_client_drop (ch->client); return; } + r4 = (const struct sockaddr_in *) remote_sa; + ret = GN_request_connection_reversal (&l4->sin_addr, + ntohs (l4->sin_port), + &r4->sin_addr); break; case AF_INET6: if (remote_sa_len != sizeof (struct sockaddr_in6)) @@ -642,15 +793,18 @@ handle_request_connection_reversal (void *cls, GNUNET_SERVICE_client_drop (ch->client); return; } + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Connection reversal for IPv6 not supported yet\n")); + ret = GNUNET_SYSERR; break; default: GNUNET_break (0); GNUNET_SERVICE_client_drop (ch->client); return; } - /* FIXME: actually run the logic by - calling 'GN_request_connection_reversal()' */ - + if (GNUNET_OK != ret) + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _("Connection reversal request failed\n")); GNUNET_SERVICE_client_continue (ch->client); } @@ -757,108 +911,6 @@ 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; -} - - -/** - * Test if the given IPv4 address is in a known range - * for private networks. - * - * @param ip address to test - * @return #GNUNET_YES if @a ip is in a NAT range - */ -static int -is_nat_v4 (const struct in_addr *ip) -{ - return - 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 */ -} - - -/** - * Test if the given IPv6 address is in a known range - * for private networks. - * - * @param ip address to test - * @return #GNUNET_YES if @a ip is in a NAT range - */ -static int -is_nat_v6 (const struct in6_addr *ip) -{ - return - match_ipv6 ("fc00::", ip, 7) || /* RFC 4193 */ - match_ipv6 ("fec0::", ip, 10) || /* RFC 3879 */ - match_ipv6 ("fe80::", ip, 10); /* RFC 4291, link-local */ -} - - -/** * Callback function invoked for each interface found. Adds them * to our new address list. * diff --git a/src/nat/gnunet-service-nat_helper.c b/src/nat/gnunet-service-nat_helper.c index e476da12d2..379603ae27 100644 --- a/src/nat/gnunet-service-nat_helper.c +++ b/src/nat/gnunet-service-nat_helper.c @@ -319,7 +319,7 @@ GN_stop_gnunet_nat_server_ (struct HelperContext *h) GNUNET_SCHEDULER_cancel (h->server_read_task); h->server_read_task = NULL; } - if (NULL != h->server_proc) + if (NULL != h->server_proc) { if (0 != GNUNET_OS_process_kill (h->server_proc, GNUNET_TERM_SIG)) @@ -349,23 +349,25 @@ GN_stop_gnunet_nat_server_ (struct HelperContext *h) * that peer to connect to us (connection reversal). * * @param internal_address out internal address to use - * @param sa the address of the peer (IPv4-only) + * @param internal_port port to use + * @param remote_v4 the address of the peer (IPv4-only) * @return #GNUNET_SYSERR on error, * #GNUNET_OK otherwise */ int -GN_request_connection_reversal (const char *internal_address, - const struct sockaddr_in *sa) +GN_request_connection_reversal (const struct in_addr *internal_address, + uint16_t internal_port, + const struct in_addr *remote_v4) { - char inet4[INET_ADDRSTRLEN]; + char intv4[INET_ADDRSTRLEN]; + char remv4[INET_ADDRSTRLEN]; char port_as_string[6]; struct GNUNET_OS_Process *proc; char *binary; - GNUNET_assert (sa->sin_family == AF_INET); if (NULL == inet_ntop (AF_INET, - &sa->sin_addr, - inet4, + internal_address, + intv4, INET_ADDRSTRLEN)) { GNUNET_log_from_strerror (GNUNET_ERROR_TYPE_WARNING, @@ -373,15 +375,25 @@ GN_request_connection_reversal (const char *internal_address, "inet_ntop"); return GNUNET_SYSERR; } + if (NULL == inet_ntop (AF_INET, + remote_v4, + remv4, + INET_ADDRSTRLEN)) + { + GNUNET_log_from_strerror (GNUNET_ERROR_TYPE_WARNING, + "nat", + "inet_ntop"); + return GNUNET_SYSERR; + } GNUNET_snprintf (port_as_string, sizeof (port_as_string), "%d", - ntohs (sa->sin_port)); + internal_port); LOG (GNUNET_ERROR_TYPE_DEBUG, _("Running gnunet-helper-nat-client %s %s %u\n"), - internal_address, - inet4, - ntohs (sa->sin_port)); + intv4, + remv4, + internal_port); binary = GNUNET_OS_get_libexec_binary_path ("gnunet-helper-nat-client"); proc @@ -392,8 +404,8 @@ GN_request_connection_reversal (const char *internal_address, NULL, binary, "gnunet-helper-nat-client", - internal_address, - inet4, + intv4, + remv4, port_as_string, NULL); GNUNET_free (binary); diff --git a/src/nat/gnunet-service-nat_helper.h b/src/nat/gnunet-service-nat_helper.h index 861d62c1d5..d3f1a757c7 100644 --- a/src/nat/gnunet-service-nat_helper.h +++ b/src/nat/gnunet-service-nat_helper.h @@ -77,13 +77,15 @@ GN_stop_gnunet_nat_server_ (struct HelperContext *h); * that peer to connect to us (connection reversal). * * @param internal_address out internal address to use - * @param sa the address of the peer (IPv4-only) + * @param internal_port internal port to use + * @param remote_v4 the address of the peer (IPv4-only) * @return #GNUNET_SYSERR on error, * #GNUNET_OK otherwise */ int -GN_request_connection_reversal (const char *internal_address, - const struct sockaddr_in *sa); +GN_request_connection_reversal (const struct in_addr *internal_address, + uint16_t internal_port, + const struct in_addr *sa); /* end of gnunet-service-nat_helper.h */ diff --git a/src/nat/nat.conf b/src/nat/nat.conf.in index 4493a6ec95..304db3c153 100644 --- a/src/nat/nat.conf +++ b/src/nat/nat.conf.in @@ -1,4 +1,14 @@ [nat] +AUTOSTART = @AUTOSTART@ +@UNIXONLY@ PORT = 2121 +HOSTNAME = localhost +BINARY = gnunet-service-nat +ACCEPT_FROM = 127.0.0.1; +ACCEPT_FROM6 = ::1; +UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-nat.sock +UNIX_MATCH_UID = YES +UNIX_MATCH_GID = YES + # Are we behind NAT? BEHIND_NAT = NO diff --git a/src/rps/rps.conf.in b/src/rps/rps.conf.in index 046a8b5d93..b5feb1bd25 100644 --- a/src/rps/rps.conf.in +++ b/src/rps/rps.conf.in @@ -8,7 +8,7 @@ UNIX_MATCH_GID = YES HOSTNAME = localhost ACCEPT_FROM = 127.0.0.1; ACCEPT_FROM6 = ::1; -# PORT = 2106 +# PORT = 2119 @UNIXONLY@ PORT = 2119 # This is the timeinterval between the rounds |