X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=src%2Fnat%2Fgnunet-service-nat.c;h=f4755659f2cbd5f940e7df1d44dfc40e2dbce002;hb=8a5c5861114433d0d267885bb29f21a0c160d1f4;hp=1ae0ef2c0c6fd566817c747552d82c42d6983d91;hpb=1466de299c038c5ef738271bd8040276f029e695;p=oweals%2Fgnunet.git diff --git a/src/nat/gnunet-service-nat.c b/src/nat/gnunet-service-nat.c index 1ae0ef2c0..f4755659f 100644 --- a/src/nat/gnunet-service-nat.c +++ b/src/nat/gnunet-service-nat.c @@ -30,7 +30,6 @@ * TODO: * - call GN_start_gnunet_nat_server_() if possible (i.e. * when we find we have a non-global IPv4 address) - * - implement handle_test * - implement autoconfig * - implmeent UPnPC/PMP-based NAT traversal * - implement NEW logic for external IP detection @@ -144,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. */ @@ -179,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. @@ -353,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. @@ -402,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 @@ -417,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); } @@ -580,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); @@ -980,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",