From 8a5c5861114433d0d267885bb29f21a0c160d1f4 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Wed, 30 Nov 2016 12:17:19 +0100 Subject: [PATCH] implement keeping and timeout of NAT STUN data --- src/nat/gnunet-service-nat.c | 156 ++++++++++++++++++++++++++++++++++- src/nat/nat.conf | 3 + src/nat/nat_api_stun.c | 3 +- 3 files changed, 158 insertions(+), 4 deletions(-) diff --git a/src/nat/gnunet-service-nat.c b/src/nat/gnunet-service-nat.c index d8a343857..f4755659f 100644 --- a/src/nat/gnunet-service-nat.c +++ b/src/nat/gnunet-service-nat.c @@ -143,6 +143,51 @@ struct LocalAddressList }; +/** + * External IP address as given to us via some STUN server. + */ +struct StunExternalIP +{ + /** + * Kept in a DLL. + */ + struct StunExternalIP *next; + + /** + * Kept in a DLL. + */ + struct StunExternalIP *prev; + + /** + * Task we run to remove this entry when it is stale. + */ + struct GNUNET_SCHEDULER_Task *timeout_task; + + /** + * Our external IP address as reported by the + * STUN server. + */ + struct sockaddr_in external_addr; + + /** + * Address of the reporting STUN server. Used to + * detect when a STUN server changes its opinion + * to more quickly remove stale results. + */ + struct sockaddr_storage stun_server_addr; + + /** + * Number of bytes used in @e stun_server_addr. + */ + size_t stun_server_addr_len; +}; + + +/** + * Timeout to use when STUN data is considered stale. + */ +static struct GNUNET_TIME_Relative stun_stale_timeout; + /** * Handle to our current configuration. */ @@ -178,6 +223,16 @@ static struct LocalAddressList *lal_head; */ static struct LocalAddressList *lal_tail; +/** + * Kept in a DLL. + */ +static struct StunExternalIP *se_head; + +/** + * Kept in a DLL. + */ +static struct StunExternalIP *se_tail; + /** * Free the DLL starting at #lal_head. @@ -352,6 +407,43 @@ check_stun (void *cls, } +/** + * Notify all clients about our external IP address + * as reported by the STUN server. + * + * @param ip the external IP + * @param add #GNUNET_YES to add, #GNUNET_NO to remove + */ +static void +notify_clients_stun_change (const struct sockaddr_in *ip, + int add) +{ + /* FIXME: notify clients about add/drop */ +} + + +/** + * Function to be called when we decide that an + * external IP address as told to us by a STUN + * server has gone stale. + * + * @param cls the `struct StunExternalIP` to drop + */ +static void +stun_ip_timeout (void *cls) +{ + struct StunExternalIP *se = cls; + + se->timeout_task = NULL; + notify_clients_stun_change (&se->external_addr, + GNUNET_NO); + GNUNET_CONTAINER_DLL_remove (se_head, + se_tail, + se); + GNUNET_free (se); +} + + /** * Handler for #GNUNET_MESSAGE_TYPE_NAT_HANDLE_STUN message from * client. @@ -401,8 +493,7 @@ handle_stun (void *cls, payload_size, &external_addr)) { - /* FIXME: do something with "external_addr"! We - now know that a server at "sa" claims that + /* We now know that a server at "sa" claims that we are visible at IP "external_addr". We should (for some fixed period of time) tell @@ -416,7 +507,50 @@ handle_stun (void *cls, (with a sane default), so that the UDP plugin can tell how often to re-request STUN. */ - + struct StunExternalIP *se; + + /* Check if we had a prior response from this STUN server */ + for (se = se_head; NULL != se; se = se->next) + { + if ( (se->stun_server_addr_len != sa_len) || + (0 != memcmp (sa, + &se->stun_server_addr, + sa_len)) ) + continue; /* different STUN server */ + if (0 != memcmp (&external_addr, + &se->external_addr, + sizeof (struct sockaddr_in))) + { + /* external IP changed, update! */ + notify_clients_stun_change (&se->external_addr, + GNUNET_NO); + se->external_addr = external_addr; + notify_clients_stun_change (&se->external_addr, + GNUNET_YES); + } + /* update timeout */ + GNUNET_SCHEDULER_cancel (se->timeout_task); + se->timeout_task + = GNUNET_SCHEDULER_add_delayed (stun_stale_timeout, + &stun_ip_timeout, + se); + return; + } + /* STUN server is completely new, create fresh entry */ + se = GNUNET_new (struct StunExternalIP); + se->external_addr = external_addr; + GNUNET_memcpy (&se->stun_server_addr, + sa, + sa_len); + se->stun_server_addr_len = sa_len; + se->timeout_task = GNUNET_SCHEDULER_add_delayed (stun_stale_timeout, + &stun_ip_timeout, + se); + GNUNET_CONTAINER_DLL_insert (se_head, + se_tail, + se); + notify_clients_stun_change (&se->external_addr, + GNUNET_NO); } GNUNET_SERVICE_client_continue (ch->client); } @@ -579,6 +713,16 @@ handle_autoconfig_request (void *cls, static void shutdown_task (void *cls) { + struct StunExternalIP *se; + + while (NULL != (se = se_head)) + { + GNUNET_CONTAINER_DLL_remove (se_head, + se_tail, + se); + GNUNET_SCHEDULER_cancel (se->timeout_task); + GNUNET_free (se); + } if (NULL != scan_task) { GNUNET_SCHEDULER_cancel (scan_task); @@ -979,6 +1123,12 @@ run (void *cls, struct GNUNET_SERVICE_Handle *service) { cfg = c; + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_time (cfg, + "NAT", + "STUN_STALE", + &stun_stale_timeout)) + stun_stale_timeout = GNUNET_TIME_UNIT_HOURS; GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL); stats = GNUNET_STATISTICS_create ("nat", diff --git a/src/nat/nat.conf b/src/nat/nat.conf index 4b1add109..4493a6ec9 100644 --- a/src/nat/nat.conf +++ b/src/nat/nat.conf @@ -54,6 +54,9 @@ STUN_FREQUENCY = 5 min # Default list of stun servers STUN_SERVERS = stun.gnunet.org stun.services.mozilla.com:3478 stun.ekiga.net:3478 +# After how long do we consider STUN data stale? +STUN_STALE = 60 min + [gnunet-nat-server] HOSTNAME = gnunet.org diff --git a/src/nat/nat_api_stun.c b/src/nat/nat_api_stun.c index 0d4ba86d1..8f5a5f8f6 100644 --- a/src/nat/nat_api_stun.c +++ b/src/nat/nat_api_stun.c @@ -229,7 +229,8 @@ GNUNET_NAT_stun_make_request (const char *server, rh->dns_active = GNUNET_RESOLVER_ip_get (rh->stun_server, AF_INET, TIMEOUT, - &stun_dns_callback, rh); + &stun_dns_callback, + rh); if (NULL == rh->dns_active) { GNUNET_NAT_stun_make_request_cancel (rh); -- 2.25.1