gnunet

Main GNUnet Logic
Log | Files | Refs | Submodules | README | LICENSE

commit 6c83690184e6f258e61d8187ad5999f4f87f2e49
parent c787d89df7c64eceb6145b0a8847736641ea73ca
Author: Christian Grothoff <christian@grothoff.org>
Date:   Wed,  7 Oct 2015 10:11:29 +0000

enable clean up of NAT STUN state, prevents test_plugin_udp from segfaulting

Diffstat:
Msrc/include/gnunet_dnsstub_lib.h | 15++++++++-------
Msrc/include/gnunet_nat_lib.h | 83++++++++++++++++++++++++++++++++++++++++++++++++-------------------------------
Msrc/nat/nat.c | 74+++++++++++++++++++++++++++++++++++++++++++++-----------------------------
Msrc/nat/nat_stun.c | 91+++++++++++++++++++++++++++++++++++++++++++++++++-------------------------------
Msrc/util/connection.c | 10+++++-----
5 files changed, 165 insertions(+), 108 deletions(-)

diff --git a/src/include/gnunet_dnsstub_lib.h b/src/include/gnunet_dnsstub_lib.h @@ -65,12 +65,13 @@ GNUNET_DNSSTUB_stop (struct GNUNET_DNSSTUB_Context *ctx); * @param cls closure * @param rs socket that received the response * @param dns dns response, never NULL - * @param dns_len number of bytes in 'dns' + * @param dns_len number of bytes in @a dns */ -typedef void (*GNUNET_DNSSTUB_ResultCallback)(void *cls, - struct GNUNET_DNSSTUB_RequestSocket *rs, - const struct GNUNET_TUN_DnsHeader *dns, - size_t dns_len); +typedef void +(*GNUNET_DNSSTUB_ResultCallback)(void *cls, + struct GNUNET_DNSSTUB_RequestSocket *rs, + const struct GNUNET_TUN_DnsHeader *dns, + size_t dns_len); /** @@ -82,7 +83,7 @@ typedef void (*GNUNET_DNSSTUB_ResultCallback)(void *cls, * @param request DNS request to transmit * @param request_len number of bytes in msg * @param rc function to call with result - * @param rc_cls closure for 'rc' + * @param rc_cls closure for @a rc * @return socket used for the request, NULL on error */ struct GNUNET_DNSSTUB_RequestSocket * @@ -102,7 +103,7 @@ GNUNET_DNSSTUB_resolve (struct GNUNET_DNSSTUB_Context *ctx, * @param request DNS request to transmit * @param request_len number of bytes in msg * @param rc function to call with result - * @param rc_cls closure for 'rc' + * @param rc_cls closure for @a rc * @return socket used for the request, NULL on error */ struct GNUNET_DNSSTUB_RequestSocket * diff --git a/src/include/gnunet_nat_lib.h b/src/include/gnunet_nat_lib.h @@ -506,46 +506,65 @@ typedef void /** - * Make Generic STUN request and - * Send a generic stun request to the server specified using the specified socket. - * possibly waiting for a reply and filling the 'reply' field with - * the externally visible address. - * + * Handle to a request given to the resolver. Can be used to cancel + * the request prior to the timeout or successful execution. Also + * used to track our internal state for the request. + */ +struct GNUNET_NAT_STUN_Handle; + - * @param server, the address of the stun server - * @param port, port of the stun server +/** + * Make generic STUN request. Sends a generic stun request to the + * server specified using the specified socket. The caller must + * wait for a reply on the @a sock and call + * #GNUNET_NAT_stun_handle_packet() if a reply is received. + * + * @param server the address of the stun server + * @param port port of the stun server * @param sock the socket used to send the request - * @param cb callback in case of error - * @return #GNUNET_OK success, #GNUNET_NO on error. + * @param cb callback in case of error (or completion) + * @param cb_cls closure for @a cb + * @return NULL on error */ -int -GNUNET_NAT_stun_make_request(char * server, - int port, - struct GNUNET_NETWORK_Handle * sock, GNUNET_NAT_STUN_ErrorCallback cb, - void *cb_cls); +struct GNUNET_NAT_STUN_Handle * +GNUNET_NAT_stun_make_request (const char *server, + uint16_t port, + struct GNUNET_NETWORK_Handle *sock, + GNUNET_NAT_STUN_ErrorCallback cb, + void *cb_cls); /** + * Cancel active STUN request. Frees associated resources + * and ensures that the callback is no longer invoked. * - * Handle an incoming STUN message, Do some basic sanity checks on packet size and content, - * try to extract a bit of information, and possibly reply. - * At the moment this only processes BIND requests, and returns - * the externally visible address of the request. - * If a callback is specified, invoke it with the attribute. - * - * @param data, the packet - * @param len, the length of the packet - * @param arg, sockaddr_in where we will set our discovered packet + * @param rh request to cancel + */ +void +GNUNET_NAT_stun_make_request_cancel (struct GNUNET_NAT_STUN_Handle *rh); + + +/** + * Handle an incoming STUN message. Do some basic sanity checks on + * packet size and content, try to extract a bit of information, and + * possibly reply. At the moment this only processes BIND requests, + * and returns the externally visible address of the request. If a + * callback is specified, invoke it with the attribute. * - * @return, #GNUNET_OK on OK, #GNUNET_NO if the packet is invalid ( not a stun packet) + * @param data the packet + * @param len the length of the packet + * @param arg sockaddr_in where we will set our discovered packet + * @return #GNUNET_OK on OK, + * #GNUNET_NO if the packet is not a stun packet */ int -GNUNET_NAT_stun_handle_packet(const void *data, - size_t len, - struct sockaddr_in *arg); +GNUNET_NAT_stun_handle_packet (const void *data, + size_t len, + struct sockaddr_in *arg); + /** - * CHECK if is a valid STUN packet sending to GNUNET_NAT_stun_handle_packet. + * CHECK if is a valid STUN packet sending to #GNUNET_NAT_stun_handle_packet(). * It also check if it can handle the packet based on the NAT handler. * You don't need to call anything else to check if the packet is valid, * @@ -553,12 +572,12 @@ GNUNET_NAT_stun_handle_packet(const void *data, * @param data, packet * @param len, packet length * - * @return #GNUNET_NO if it can't decode,# GNUNET_YES if is a packet + * @return #GNUNET_NO if it can't decode, #GNUNET_YES if is a packet */ int -GNUNET_NAT_is_valid_stun_packet(void *cls, - const void *data, - size_t len); +GNUNET_NAT_is_valid_stun_packet (void *cls, + const void *data, + size_t len); diff --git a/src/nat/nat.c b/src/nat/nat.c @@ -270,17 +270,17 @@ struct GNUNET_NAT_Handle /** * ID of select gnunet-helper-nat-server stdout read task */ - struct GNUNET_SCHEDULER_Task * server_read_task; + struct GNUNET_SCHEDULER_Task *server_read_task; /** * ID of interface IP-scan task */ - struct GNUNET_SCHEDULER_Task * ifc_task; + struct GNUNET_SCHEDULER_Task *ifc_task; /** * ID of hostname DNS lookup task */ - struct GNUNET_SCHEDULER_Task * hostname_task; + struct GNUNET_SCHEDULER_Task *hostname_task; /** * ID of DynDNS lookup task @@ -288,6 +288,11 @@ struct GNUNET_NAT_Handle struct GNUNET_SCHEDULER_Task *dns_task; /** + * Active STUN request, if any. + */ + struct GNUNET_NAT_STUN_Handle *stun_request; + + /** * How often do we scan for changes in our IP address from our local * interfaces? */ @@ -1109,12 +1114,11 @@ list_interfaces (void *cls, } - /** - * Callback if the STun request have a error + * Callback with the result from the STUN request. * * @param cls the NAT handle - * @param result , the status + * @param result the status */ static void stun_request_callback (void *cls, @@ -1122,14 +1126,15 @@ stun_request_callback (void *cls, { struct GNUNET_NAT_Handle *h = cls; - if (NULL == h) - return; - h->waiting_stun = GNUNET_NO; - - if(result != GNUNET_OK) + h->stun_request = NULL; + if (GNUNET_NAT_ERROR_SUCCESS != result) { LOG (GNUNET_ERROR_TYPE_WARNING, - "Error processing a STUN request"); + "Error processing a STUN request"); + } + else + { + h->waiting_stun = GNUNET_YES; } } @@ -1153,7 +1158,7 @@ GNUNET_NAT_is_valid_stun_packet (void *cls, struct sockaddr_in answer; /* We are not expecting a STUN message */ - if (! h->waiting_stun) + if (GNUNET_YES != h->waiting_stun) return GNUNET_NO; /* We dont have STUN installed */ @@ -1166,14 +1171,14 @@ GNUNET_NAT_is_valid_stun_packet (void *cls, sizeof(struct sockaddr_in)); /*Lets handle the packet*/ - int valid = GNUNET_NAT_stun_handle_packet (data, - len, - &answer); - if (! valid) + if (GNUNET_NO == + GNUNET_NAT_stun_handle_packet (data, + len, + &answer)) return GNUNET_NO; LOG (GNUNET_ERROR_TYPE_INFO, - "Stun server returned %s:%d\n", + "STUN server returned %s:%d\n", inet_ntoa (answer.sin_addr), ntohs (answer.sin_port)); /* Remove old IPs from previous STUN calls */ @@ -1208,16 +1213,19 @@ process_stun (void *cls, "I will request the stun server %s:%i\n", elem->address, elem->port); - if (GNUNET_OK == - GNUNET_NAT_stun_make_request (elem->address, + if (NULL != h->stun_request) + { + GNUNET_NAT_stun_make_request_cancel (h->stun_request); + h->stun_request = NULL; + } + h->waiting_stun = GNUNET_NO; + h->stun_request + = GNUNET_NAT_stun_make_request (elem->address, elem->port, h->socket, &stun_request_callback, - NULL)) - { - h->waiting_stun = GNUNET_YES; - } - else + h); + if (NULL == h->stun_request) { LOG (GNUNET_ERROR_TYPE_ERROR, "STUN request to %s:%i failed\n", @@ -1226,7 +1234,8 @@ process_stun (void *cls, } h->stun_task = GNUNET_SCHEDULER_add_delayed (h->stun_frequency, - &process_stun, h); + &process_stun, + h); /* Set actual Server*/ if (NULL != elem->next) @@ -1709,7 +1718,6 @@ GNUNET_NAT_register (const struct GNUNET_CONFIGURATION_Handle *cfg, /* Set the actual STUN server*/ h->actual_stun_server = h->stun_servers_head; } - h->stun_task = GNUNET_SCHEDULER_add_now (&process_stun, h); } @@ -1821,10 +1829,18 @@ GNUNET_NAT_unregister (struct GNUNET_NAT_Handle *h) GNUNET_SCHEDULER_cancel (h->stun_task); h->stun_task = NULL; } + if (NULL != h->stun_request) + { + GNUNET_NAT_stun_make_request_cancel (h->stun_request); + h->stun_request = NULL; + } if (NULL != h->server_proc) { - if (0 != GNUNET_OS_process_kill (h->server_proc, GNUNET_TERM_SIG)) - GNUNET_log_from_strerror (GNUNET_ERROR_TYPE_WARNING, "nat", "kill"); + if (0 != GNUNET_OS_process_kill (h->server_proc, + GNUNET_TERM_SIG)) + GNUNET_log_from_strerror (GNUNET_ERROR_TYPE_WARNING, + "nat", + "kill"); GNUNET_OS_process_wait (h->server_proc); GNUNET_OS_process_destroy (h->server_proc); h->server_proc = NULL; diff --git a/src/nat/nat_stun.c b/src/nat/nat_stun.c @@ -154,14 +154,20 @@ encode_message (enum StunClasses msg_class, static const char * stun_msg2str(int msg) { - static const struct { enum StunClasses value; const char *name; } classes[] = { + static const struct { + enum StunClasses value; + const char *name; + } classes[] = { { STUN_REQUEST, "Request" }, { STUN_INDICATION, "Indication" }, { STUN_RESPONSE, "Response" }, { STUN_ERROR_RESPONSE, "Error Response" }, { 0, NULL } }; - static const struct { enum StunMethods value; const char *name; } methods[] = { + static const struct { + enum StunMethods value; + const char *name; + } methods[] = { { STUN_BINDING, "Binding" }, { 0, NULL } }; @@ -201,9 +207,12 @@ stun_msg2str(int msg) * @return string with the attribute name */ static const char * -stun_attr2str(int msg) +stun_attr2str (int msg) { - const struct { enum StunAttributes value; const char *name; } attrs[] = { + static const struct { + enum StunAttributes value; + const char *name; + } attrs[] = { { STUN_MAPPED_ADDRESS, "Mapped Address" }, { STUN_RESPONSE_ADDRESS, "Response Address" }, { STUN_CHANGE_ADDRESS, "Change Address" }, @@ -242,7 +251,7 @@ stun_attr2str(int msg) * @param req, stun header to be filled */ static void -generate_request_id(struct stun_header *req) +generate_request_id (struct stun_header *req) { unsigned int x; @@ -292,7 +301,8 @@ stun_get_mapped (struct StunState *st, default: return 1; } - if (ntohs(attr->len) < 8 && returned_addr->family != 1) + if ( (ntohs(attr->len) < 8) && + (returned_addr->family != 1) ) { return 1; } @@ -371,10 +381,7 @@ GNUNET_NAT_stun_handle_packet (const void *data, (int)len); return GNUNET_NO; } - else - { - len = advertised_message_size; - } + len = advertised_message_size; memset (&st,0, sizeof(st)); while (len > 0) @@ -415,15 +422,21 @@ GNUNET_NAT_stun_handle_packet (const void *data, /** - * Clean-up used memory + * Cancel active STUN request. Frees associated resources + * and ensures that the callback is no longer invoked. * - * @param handle handle to release memory for + * @param rh request to cancel */ -static void -clean (struct GNUNET_NAT_STUN_Handle *handle) +void +GNUNET_NAT_stun_make_request_cancel (struct GNUNET_NAT_STUN_Handle *rh) { - GNUNET_free (handle->stun_server); - GNUNET_free (handle); + if (NULL != rh->dns_active) + { + GNUNET_RESOLVER_request_cancel (rh->dns_active); + rh->dns_active = NULL; + } + GNUNET_free (rh->stun_server); + GNUNET_free (rh); } @@ -439,32 +452,35 @@ stun_dns_callback (void *cls, const struct sockaddr *addr, socklen_t addrlen) { - struct GNUNET_NAT_STUN_Handle *request = cls; + struct GNUNET_NAT_STUN_Handle *rh = cls; struct stun_header *req; uint8_t reqdata[1024]; int reqlen; struct sockaddr_in server; + rh->dns_active = NULL; if (NULL == addr) { - request->dns_active = NULL; - if (GNUNET_NO == request->dns_success) + if (GNUNET_NO == rh->dns_success) { LOG (GNUNET_ERROR_TYPE_INFO, "Error resolving host %s\n", - request->stun_server); - request->cb (request->cb_cls, - GNUNET_NAT_ERROR_NOT_ONLINE); - clean (request); + rh->stun_server); + rh->cb (rh->cb_cls, + GNUNET_NAT_ERROR_NOT_ONLINE); + GNUNET_NAT_stun_make_request_cancel (rh); } return; } - request->dns_success= GNUNET_YES; - memset(&server,0, sizeof(server)); + rh->dns_success = GNUNET_YES; + memset (&server,0, sizeof(server)); server.sin_family = AF_INET; server.sin_addr = ((struct sockaddr_in *)addr)->sin_addr; - server.sin_port = htons(request->stun_port); + server.sin_port = htons(rh->stun_port); +#if HAVE_SOCKADDR_IN_SIN_LEN + server.sin_len = (u_char) sizeof (struct sockaddr_in); +#endif /*Craft the simplest possible STUN packet. A request binding*/ req = (struct stun_header *)reqdata; @@ -476,7 +492,7 @@ stun_dns_callback (void *cls, req->msgtype = htons(encode_message(STUN_REQUEST, STUN_BINDING)); /* Send the packet */ - if (-1 == GNUNET_NETWORK_socket_sendto (request->sock, + if (-1 == GNUNET_NETWORK_socket_sendto (rh->sock, req, ntohs(req->msglen) + sizeof(*req), (const struct sockaddr *) &server, @@ -484,11 +500,14 @@ stun_dns_callback (void *cls, { GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "Fail to sendto"); - request->cb (request->cb_cls, - GNUNET_NAT_ERROR_INTERNAL_NETWORK_ERROR); - clean (request); + rh->cb (rh->cb_cls, + GNUNET_NAT_ERROR_INTERNAL_NETWORK_ERROR); + GNUNET_NAT_stun_make_request_cancel (rh); return; } + /* sending STUN request done, let's wait for replies... */ + rh->cb (rh->cb_cls, + GNUNET_NAT_ERROR_SUCCESS); } @@ -503,9 +522,9 @@ stun_dns_callback (void *cls, * @param sock the socket used to send the request * @param cb callback in case of error * @param cb_cls closure for @a cb - * @return #GNUNET_OK success, #GNUNET_NO on error. + * @return NULL on error */ -int +struct GNUNET_NAT_STUN_Handle * GNUNET_NAT_stun_make_request (const char *server, uint16_t port, struct GNUNET_NETWORK_Handle *sock, @@ -529,8 +548,10 @@ GNUNET_NAT_stun_make_request (const char *server, { GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "Failed DNS"); - clean (rh); - return GNUNET_NO; + GNUNET_NAT_stun_make_request_cancel (rh); + return NULL; } - return GNUNET_OK; + return rh; } + +/* end of nat_stun.c */ diff --git a/src/util/connection.c b/src/util/connection.c @@ -738,9 +738,9 @@ try_connect_using_address (void *cls, if (NULL == addr) { connection->dns_active = NULL; - if ((NULL == connection->ap_head) && + if ((NULL == connection->ap_head) && (NULL == connection->sock) && - (NULL == connection->proxy_handshake)) + (NULL == connection->proxy_handshake)) connect_fail_continuation (connection); return; } @@ -991,8 +991,8 @@ GNUNET_CONNECTION_create_from_sockaddr (int af_family, int GNUNET_CONNECTION_check (struct GNUNET_CONNECTION_Handle *connection) { - if ((NULL != connection->ap_head) || - (NULL != connection->dns_active) || + if ((NULL != connection->ap_head) || + (NULL != connection->dns_active) || (NULL != connection->proxy_handshake)) return GNUNET_YES; /* still trying to connect */ if ( (0 != connection->destroy_later) || @@ -1588,7 +1588,7 @@ GNUNET_CONNECTION_create_proxied_from_handshake (struct GNUNET_CONNECTION_Handle /** - * Activate proxied connection and destroy initial proxy handshake connection. + * Activate proxied connection and destroy initial proxy handshake connection. * There must not be any pending requests for reading or writing to the * proxy hadshake connection at this time. *