From f4b1f639e8799d29e823a7cd563a97d314d4f471 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Sun, 2 May 2010 11:48:52 +0000 Subject: [PATCH] fixing major issue with how IP addresses go over the network (previously ill-defined) -- thanks amatus --- src/transport/gnunet-service-transport.c | 77 +++-- src/transport/plugin_transport.h | 27 ++ src/transport/plugin_transport_tcp.c | 293 +++++++++++++++---- src/transport/plugin_transport_template.c | 24 ++ src/transport/plugin_transport_udp.c | 325 +++++++++++++++++---- src/transport/test_plugin_transport_http.c | 16 +- 6 files changed, 612 insertions(+), 150 deletions(-) diff --git a/src/transport/gnunet-service-transport.c b/src/transport/gnunet-service-transport.c index bb6686a42..e927a11f5 100644 --- a/src/transport/gnunet-service-transport.c +++ b/src/transport/gnunet-service-transport.c @@ -45,9 +45,9 @@ #include "plugin_transport.h" #include "transport.h" -#define DEBUG_BLACKLIST GNUNET_NO +#define DEBUG_BLACKLIST GNUNET_YES -#define DEBUG_PING_PONG GNUNET_NO +#define DEBUG_PING_PONG GNUNET_YES /** * Should we do some additional checks (to validate behavior @@ -1392,6 +1392,32 @@ transmit_send_continuation (void *cls, } +/** + * Convert an address to a string. + * + * @param plugin name of the plugin responsible for the address + * @param addr binary address + * @param addr_len number of bytes in addr + * @return NULL on error, otherwise address string + */ +static const char* +a2s (const char *plugin, + const void *addr, + size_t addr_len) +{ + struct TransportPlugin *p; + + if (plugin == NULL) + return NULL; + p = find_transport (plugin); + if (p == NULL) + return NULL; + return p->api->address_to_string (p->api->cls, + addr, + addr_len); +} + + /** * Find an address in any of the available transports for * the given neighbour that would be good for message @@ -1439,8 +1465,9 @@ find_ready_address(struct NeighbourList *neighbour) if (addresses->addr != NULL) GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Have address `%s' for peer `%4s' (status: %d, %d, %d, %u, %llums, %u)\n", - GNUNET_a2s (addresses->addr, - addresses->addrlen), + a2s (head->plugin->short_name, + addresses->addr, + addresses->addrlen), GNUNET_i2s (&neighbour->id), addresses->connected, addresses->in_transmit, @@ -1601,8 +1628,9 @@ try_transmission_to_peer (struct NeighbourList *neighbour) mq->message_buf_size, GNUNET_i2s (&neighbour->id), (mq->specific_address->addr != NULL) - ? GNUNET_a2s (mq->specific_address->addr, - mq->specific_address->addrlen) + ? a2s (mq->specific_address->plugin->short_name, + mq->specific_address->addr, + mq->specific_address->addrlen) : "", rl->plugin->short_name); #endif @@ -2426,7 +2454,7 @@ add_to_foreign_address_list (void *cls, #if DEBUG_TRANSPORT GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding address `%s' (%s) for peer `%4s' due to peerinfo data for %llums.\n", - GNUNET_a2s (addr, addrlen), + a2s (tname, addr, addrlen), tname, GNUNET_i2s (&n->id), expiration.value); @@ -3001,8 +3029,9 @@ send_periodic_ping (void *cls, GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Some validation of address `%s' via `%s' for peer `%4s' already in progress.\n", (peer_address->addr != NULL) - ? GNUNET_a2s (peer_address->addr, - peer_address->addrlen) + ? a2s (peer_address->plugin->short_name, + peer_address->addr, + peer_address->addrlen) : "", tp->short_name, GNUNET_i2s (&neighbour->id)); @@ -3049,8 +3078,9 @@ send_periodic_ping (void *cls, GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Performing re-validation of address `%s' via `%s' for peer `%4s' sending `%s' (%u bytes) and `%s' (%u bytes)\n", (peer_address->addr != NULL) - ? GNUNET_a2s (peer_address->addr, - peer_address->addrlen) + ? a2s (peer_address->plugin->short_name, + peer_address->addr, + peer_address->addrlen) : "", tp->short_name, GNUNET_i2s (&neighbour->id), @@ -3231,8 +3261,9 @@ check_pending_validation (void *cls, "Confirmed validity of address, peer `%4s' has address `%s' (%s).\n", GNUNET_h2s (key), (ve->addr != NULL) - ? GNUNET_a2s ((const struct sockaddr *) ve->addr, - ve->addrlen) + ? a2s (ve->transport_name, + (const struct sockaddr *) ve->addr, + ve->addrlen) : "", ve->transport_name); #endif @@ -3368,15 +3399,6 @@ handle_pong (void *cls, const struct GNUNET_MessageHeader *message, return; } -#if 0 - /* FIXME: add given address to potential pool of our addresses - (for voting) */ - GNUNET_log (GNUNET_ERROR_TYPE_INFO | GNUNET_ERROR_TYPE_BULK, - _("Another peer saw us using the address `%s' via `%s'.\n"), - GNUNET_a2s ((const struct sockaddr *) &pong[1], - ntohs(pong->addrlen)), - va->transport_name); -#endif } @@ -3434,7 +3456,8 @@ transmit_hello_and_ping (void *cls, #if DEBUG_TRANSPORT GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Performing validation of address `%s' via `%s' for peer `%4s' sending `%s' (%u bytes) and `%s' (%u bytes)\n", - GNUNET_a2s ((const void*) &va[1], va->addrlen), + a2s (va->transport_name, + (const void*) &va[1], va->addrlen), va->transport_name, GNUNET_i2s (&neighbour->id), "HELLO", hello_size, @@ -3548,7 +3571,7 @@ run_validation (void *cls, #if DEBUG_TRANSPORT > 1 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Validation of address `%s' via `%s' for peer `%4s' already in progress.\n", - GNUNET_a2s (addr, addrlen), + a2s (tname, addr, addrlen), tname, GNUNET_i2s (&id)); #endif @@ -3939,8 +3962,9 @@ handle_ping(void *cls, const struct GNUNET_MessageHeader *message, "Processing `%s' from `%s'\n", "PING", (sender_address != NULL) - ? GNUNET_a2s ((const struct sockaddr *)sender_address, - sender_address_len) + ? a2s (plugin->short_name, + (const struct sockaddr *)sender_address, + sender_address_len) : ""); #endif GNUNET_STATISTICS_update (stats, @@ -4895,6 +4919,7 @@ run (void *cls, int main (int argc, char *const *argv) { + a2s (NULL, NULL, 0); /* make compiler happy */ return (GNUNET_OK == GNUNET_SERVICE_run (argc, argv, diff --git a/src/transport/plugin_transport.h b/src/transport/plugin_transport.h index 2b7017036..034520cb3 100644 --- a/src/transport/plugin_transport.h +++ b/src/transport/plugin_transport.h @@ -346,6 +346,23 @@ typedef int (*GNUNET_TRANSPORT_CheckAddress) (void *cls, void *addr, size_t addrlen); + +/** + * Function called for a quick conversion of the binary address to + * a numeric address. Note that the caller must not free the + * address and that the next call to this function is allowed + * to override the address again. + * + * @param cls closure + * @param addr binary address + * @param addr_len length of the address + * @return string representing the same address + */ +typedef const char* (*GNUNET_TRANSPORT_AddressToString) (void *cls, + const void *addr, + size_t addrlen); + + /** * Each plugin is required to return a pointer to a struct of this * type as the return value from its entry point. @@ -387,9 +404,19 @@ struct GNUNET_TRANSPORT_PluginFunctions * Function that will be called to check if a binary address * for this plugin is well-formed. If clearly needed, patch * up information such as port numbers. + * FIXME: this API will likely change in the near future since + * it currently does not allow the size of the patched address + * to be different! */ GNUNET_TRANSPORT_CheckAddress check_address; + + /** + * Function that will be called to convert a binary address + * to a string (numeric conversion only). + */ + GNUNET_TRANSPORT_AddressToString address_to_string; + }; diff --git a/src/transport/plugin_transport_tcp.c b/src/transport/plugin_transport_tcp.c index e71e751f6..2e7d3dadd 100644 --- a/src/transport/plugin_transport_tcp.c +++ b/src/transport/plugin_transport_tcp.c @@ -63,6 +63,42 @@ struct WelcomeMessage }; +/** + * Network format for IPv4 addresses. + */ +struct IPv4TcpAddress +{ + /** + * IPv4 address, in network byte order. + */ + uint32_t ipv4_addr; + + /** + * Port number, in network byte order. + */ + uint16_t t_port; + +}; + + +/** + * Network format for IPv6 addresses. + */ +struct IPv6TcpAddress +{ + /** + * IPv6 address. + */ + unsigned char ipv6_addr[16]; + + /** + * Port number, in network byte order. + */ + uint16_t t6_port; + +}; + + /** * Encapsulation of all of the state of the plugin. */ @@ -262,6 +298,60 @@ struct Plugin }; + + +/** + * Function called for a quick conversion of the binary address to + * a numeric address. Note that the caller must not free the + * address and that the next call to this function is allowed + * to override the address again. + * + * @param cls closure ('struct Plugin*') + * @param addr binary address + * @param addr_len length of the address + * @return string representing the same address + */ +static const char* +tcp_address_to_string (void *cls, + const void *addr, + size_t addrlen) +{ + static char buf[INET6_ADDRSTRLEN]; + const void *sb; + struct sockaddr_in a4; + struct sockaddr_in6 a6; + const struct IPv4TcpAddress *t4; + const struct IPv6TcpAddress *t6; + int af; + + if (addrlen == sizeof (struct IPv6TcpAddress)) + { + t6 = addr; + af = AF_INET6; + memset (&a6, 0, sizeof (a6)); + a6.sin6_family = AF_INET6; + a6.sin6_port = t6->t6_port; + memcpy (a6.sin6_addr.s6_addr, + t6->ipv6_addr, + 16); + sb = &a6; + } + else if (addrlen == sizeof (struct IPv4TcpAddress)) + { + t4 = addr; + af = AF_INET; + memset (&a4, 0, sizeof (a4)); + a4.sin_family = AF_INET; + a4.sin_port = t4->t_port; + a4.sin_addr.s_addr = t4->ipv4_addr; + sb = &a4; + } + else + return NULL; + return inet_ntop (af, sb, buf, INET6_ADDRSTRLEN); +} + + /** * Find the session handle for the given client. * @@ -520,8 +610,10 @@ disconnect_session (struct Session *session) "Disconnecting from `%4s' at %s (session %p).\n", GNUNET_i2s (&session->target), (session->connect_addr != NULL) ? - GNUNET_a2s (session->connect_addr, - session->connect_alen) : "*", session); + tcp_address_to_string (session->plugin, + session->connect_addr, + session->connect_alen) : "*", + session); #endif /* remove from session list */ prev = NULL; @@ -680,6 +772,12 @@ tcp_plugin_send (void *cls, struct PendingMessage *pm; struct GNUNET_CONNECTION_Handle *sa; int af; + const void *sb; + size_t sbs; + struct sockaddr_in a4; + struct sockaddr_in6 a6; + const struct IPv4TcpAddress *t4; + const struct IPv6TcpAddress *t6; GNUNET_STATISTICS_update (plugin->env->stats, gettext_noop ("# bytes TCP was asked to transmit"), @@ -746,13 +844,29 @@ tcp_plugin_send (void *cls, } if (session == NULL) { - if (sizeof (struct sockaddr_in) == addrlen) + if (addrlen == sizeof (struct IPv6TcpAddress)) { - af = AF_INET; + t6 = addr; + af = AF_INET6; + memset (&a6, 0, sizeof (a6)); + a6.sin6_family = AF_INET6; + a6.sin6_port = t6->t6_port; + memcpy (a6.sin6_addr.s6_addr, + t6->ipv6_addr, + 16); + sb = &a6; + sbs = sizeof (a6); } - else if (sizeof (struct sockaddr_in6) == addrlen) + else if (addrlen == sizeof (struct IPv4TcpAddress)) { - af = AF_INET6; + t4 = addr; + af = AF_INET; + memset (&a4, 0, sizeof (a4)); + a4.sin_family = AF_INET; + a4.sin_port = t4->t_port; + a4.sin_addr.s_addr = t4->ipv4_addr; + sb = &a4; + sbs = sizeof (a4); } else { @@ -760,7 +874,7 @@ tcp_plugin_send (void *cls, return -1; } sa = GNUNET_CONNECTION_create_from_sockaddr (plugin->env->sched, - af, addr, addrlen, + af, sb, sbs, GNUNET_SERVER_MAX_MESSAGE_SIZE); if (sa == NULL) { @@ -769,7 +883,7 @@ tcp_plugin_send (void *cls, "tcp", "Failed to create connection to `%4s' at `%s'\n", GNUNET_i2s (target), - GNUNET_a2s (addr, addrlen)); + GNUNET_a2s (sb, sbs)); #endif GNUNET_STATISTICS_update (plugin->env->stats, gettext_noop ("# bytes discarded by TCP (failed to connect)"), @@ -782,7 +896,7 @@ tcp_plugin_send (void *cls, "tcp", "Asked to transmit to `%4s', creating fresh session using address `%s'.\n", GNUNET_i2s (target), - GNUNET_a2s (addr, addrlen)); + GNUNET_a2s (sb, sbs)); #endif session = create_session (plugin, target, @@ -948,12 +1062,43 @@ tcp_plugin_address_pretty_printer (void *cls, void *asc_cls) { struct Plugin *plugin = cls; - const struct sockaddr_in *v4; - const struct sockaddr_in6 *v6; struct PrettyPrinterContext *ppc; + const void *sb; + size_t sbs; + struct sockaddr_in a4; + struct sockaddr_in6 a6; + const struct IPv4TcpAddress *t4; + const struct IPv6TcpAddress *t6; + int af; + uint16_t port; - if ((addrlen != sizeof (struct sockaddr_in)) && - (addrlen != sizeof (struct sockaddr_in6))) + if (addrlen == sizeof (struct IPv6TcpAddress)) + { + t6 = addr; + af = AF_INET6; + memset (&a6, 0, sizeof (a6)); + a6.sin6_family = AF_INET6; + a6.sin6_port = t6->t6_port; + memcpy (a6.sin6_addr.s6_addr, + t6->ipv6_addr, + 16); + port = ntohs (t6->t6_port); + sb = &a6; + sbs = sizeof (a6); + } + else if (addrlen == sizeof (struct IPv4TcpAddress)) + { + t4 = addr; + af = AF_INET; + memset (&a4, 0, sizeof (a4)); + a4.sin_family = AF_INET; + a4.sin_port = t4->t_port; + a4.sin_addr.s_addr = t4->ipv4_addr; + port = ntohs (t4->t_port); + sb = &a4; + sbs = sizeof (a4); + } + else { /* invalid address */ GNUNET_break_op (0); @@ -963,21 +1108,11 @@ tcp_plugin_address_pretty_printer (void *cls, ppc = GNUNET_malloc (sizeof (struct PrettyPrinterContext)); ppc->asc = asc; ppc->asc_cls = asc_cls; - if (addrlen == sizeof (struct sockaddr_in)) - { - v4 = (const struct sockaddr_in *) addr; - ppc->port = ntohs (v4->sin_port); - } - else - { - v6 = (const struct sockaddr_in6 *) addr; - ppc->port = ntohs (v6->sin6_port); - - } + ppc->port = port; GNUNET_RESOLVER_hostname_get (plugin->env->sched, plugin->env->cfg, - addr, - addrlen, + sb, + sbs, !numeric, timeout, &append_port, ppc); } @@ -1004,45 +1139,40 @@ check_port (struct Plugin *plugin, uint16_t in_port) /** * Another peer has suggested an address for this peer and transport - * plugin. Check that this could be a valid address. + * plugin. Check that this could be a valid address. This function + * is not expected to 'validate' the address in the sense of trying to + * connect to it but simply to see if the binary format is technically + * legal for establishing a connection. * * @param cls closure, our 'struct Plugin*' * @param addr pointer to the address * @param addrlen length of addr * @return GNUNET_OK if this is a plausible address for this peer - * and transport + * and transport, GNUNET_SYSERR if not */ static int tcp_plugin_check_address (void *cls, void *addr, size_t addrlen) { struct Plugin *plugin = cls; - char buf[sizeof (struct sockaddr_in6)]; - struct sockaddr_in *v4; - struct sockaddr_in6 *v6; + struct IPv4TcpAddress *v4; + struct IPv6TcpAddress *v6; - if ((addrlen != sizeof (struct sockaddr_in)) && - (addrlen != sizeof (struct sockaddr_in6))) + if ((addrlen != sizeof (struct IPv4TcpAddress)) && + (addrlen != sizeof (struct IPv6TcpAddress))) { GNUNET_break_op (0); return GNUNET_SYSERR; } - memcpy (buf, addr, sizeof (struct sockaddr_in6)); - if (addrlen == sizeof (struct sockaddr_in)) + if (addrlen == sizeof (struct IPv4TcpAddress)) { - v4 = (struct sockaddr_in *) buf; - v4->sin_port = htons (check_port (plugin, ntohs (v4->sin_port))); + v4 = (struct IPv4TcpAddress *) addr; + v4->t_port = htons (check_port (plugin, ntohs (v4->t_port))); } else { - v6 = (struct sockaddr_in6 *) buf; - v6->sin6_port = htons (check_port (plugin, ntohs (v6->sin6_port))); + v6 = (struct IPv6TcpAddress *) addr; + v6->t6_port = htons (check_port (plugin, ntohs (v6->t6_port))); } -#if DEBUG_TCP - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, - "tcp", - "Informing transport service about my address `%s'.\n", - GNUNET_a2s (addr, addrlen)); -#endif return GNUNET_OK; } @@ -1065,6 +1195,11 @@ handle_tcp_welcome (void *cls, struct Session *session; size_t alen; void *vaddr; + struct IPv4TcpAddress *t4; + struct IPv6TcpAddress *t6; + const struct sockaddr_in *s4; + const struct sockaddr_in6 *s6; + #if DEBUG_TCP GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, @@ -1094,8 +1229,27 @@ handle_tcp_welcome (void *cls, GNUNET_a2s (vaddr, alen), client); #endif - session->connect_addr = vaddr; - session->connect_alen = alen; + if (alen == sizeof (struct sockaddr_in)) + { + s4 = vaddr; + t4 = GNUNET_malloc (sizeof (struct IPv4TcpAddress)); + t4->t_port = s4->sin_port; + t4->ipv4_addr = s4->sin_addr.s_addr; + session->connect_addr = t4; + session->connect_alen = sizeof (struct IPv4TcpAddress); + } + else if (alen == sizeof (struct sockaddr_in6)) + { + s6 = vaddr; + t6 = GNUNET_malloc (sizeof (struct IPv6TcpAddress)); + t6->t6_port = s6->sin6_port; + memcpy (t6->ipv6_addr, + s6->sin6_addr.s6_addr, + 16); + session->connect_addr = t6; + session->connect_alen = sizeof (struct IPv6TcpAddress); + } + GNUNET_free (vaddr); } else { @@ -1227,7 +1381,8 @@ static struct GNUNET_SERVER_MessageHandler my_handlers[] = { * @param client identification of the client */ static void -disconnect_notify (void *cls, struct GNUNET_SERVER_Client *client) +disconnect_notify (void *cls, + struct GNUNET_SERVER_Client *client) { struct Plugin *plugin = cls; struct Session *session; @@ -1243,8 +1398,10 @@ disconnect_notify (void *cls, struct GNUNET_SERVER_Client *client) "Destroying session of `%4s' with %s (%p) due to network-level disconnect.\n", GNUNET_i2s (&session->target), (session->connect_addr != NULL) ? - GNUNET_a2s (session->connect_addr, - session->connect_alen) : "*", client); + tcp_address_to_string (session->plugin, + session->connect_addr, + session->connect_alen) : "*", + client); #endif disconnect_session (session); } @@ -1259,6 +1416,7 @@ disconnect_notify (void *cls, struct GNUNET_SERVER_Client *client) * @param isDefault do we think this may be our default interface * @param addr address of the interface * @param addrlen number of bytes in addr + * @return GNUNET_OK to continue iterating */ static int process_interfaces (void *cls, @@ -1268,28 +1426,41 @@ process_interfaces (void *cls, { struct Plugin *plugin = cls; int af; - struct sockaddr_in *v4; - struct sockaddr_in6 *v6; + struct IPv4TcpAddress t4; + struct IPv6TcpAddress t6; + void *arg; + uint16_t args; af = addr->sa_family; if (af == AF_INET) { - v4 = (struct sockaddr_in *) addr; - v4->sin_port = htons (plugin->adv_port); + t4.ipv4_addr = ((struct sockaddr_in *) addr)->sin_addr.s_addr; + t4.t_port = htons (plugin->adv_port); + arg = &t4; + args = sizeof (t4); + } + else if (af == AF_INET6) + { + memcpy (t6.ipv6_addr, + ((struct sockaddr_in6 *) addr)->sin6_addr.s6_addr, + 16); + t6.t6_port = htons (plugin->adv_port); + arg = &t6; + args = sizeof (t6); } else { - GNUNET_assert (af == AF_INET6); - v6 = (struct sockaddr_in6 *) addr; - v6->sin6_port = htons (plugin->adv_port); + GNUNET_break (0); + return GNUNET_OK; } GNUNET_log_from (GNUNET_ERROR_TYPE_INFO | GNUNET_ERROR_TYPE_BULK, - "tcp", _("Found address `%s' (%s)\n"), + "tcp", + _("Found address `%s' (%s)\n"), GNUNET_a2s (addr, addrlen), name); plugin->env->notify_address (plugin->env->cls, "tcp", - addr, addrlen, GNUNET_TIME_UNIT_FOREVER_REL); + arg, args, GNUNET_TIME_UNIT_FOREVER_REL); return GNUNET_OK; } @@ -1320,6 +1491,9 @@ process_hostname_ips (void *cls, /** * Entry point for the plugin. + * + * @param cls closure, the 'struct GNUNET_TRANSPORT_PluginEnvironment*' + * @return the 'struct GNUNET_TRANSPORT_PluginFunctions*' or NULL on error */ void * libgnunet_plugin_transport_tcp_init (void *cls) @@ -1377,6 +1551,7 @@ libgnunet_plugin_transport_tcp_init (void *cls) api->disconnect = &tcp_plugin_disconnect; api->address_pretty_printer = &tcp_plugin_address_pretty_printer; api->check_address = &tcp_plugin_check_address; + api->address_to_string = &tcp_address_to_string; plugin->service = service; plugin->server = GNUNET_SERVICE_get_server (service); plugin->handlers = GNUNET_malloc (sizeof (my_handlers)); diff --git a/src/transport/plugin_transport_template.c b/src/transport/plugin_transport_template.c index f09503b9b..1ca4d018f 100644 --- a/src/transport/plugin_transport_template.c +++ b/src/transport/plugin_transport_template.c @@ -247,6 +247,29 @@ template_plugin_address_suggested (void *cls, } +/** + * Function called for a quick conversion of the binary address to + * a numeric address. Note that the caller must not free the + * address and that the next call to this function is allowed + * to override the address again. + * + * @param cls closure + * @param addr binary address + * @param addr_len length of the address + * @return string representing the same address + */ +static const char* +template_plugin_address_to_string (void *cls, + const void *addr, + size_t addrlen) +{ + GNUNET_break (0); + return NULL; +} + + + + /** * Entry point for the plugin. */ @@ -266,6 +289,7 @@ gnunet_plugin_transport_template_init (void *cls) api->disconnect = &template_plugin_disconnect; api->address_pretty_printer = &template_plugin_address_pretty_printer; api->check_address = &template_plugin_address_suggested; + api->address_to_string = &template_plugin_address_to_string; return api; } diff --git a/src/transport/plugin_transport_udp.c b/src/transport/plugin_transport_udp.c index 3e59f89dc..c7be2e18e 100644 --- a/src/transport/plugin_transport_udp.c +++ b/src/transport/plugin_transport_udp.c @@ -71,13 +71,64 @@ struct UDPMessage }; +/** + * Network format for IPv4 addresses. + */ +struct IPv4UdpAddress +{ + /** + * IPv4 address, in network byte order. + */ + uint32_t ipv4_addr; + + /** + * Port number, in network byte order. + */ + uint16_t u_port; + +}; + + +/** + * Network format for IPv6 addresses. + */ +struct IPv6UdpAddress +{ + /** + * IPv6 address. + */ + unsigned char ipv6_addr[16]; + + /** + * Port number, in network byte order. + */ + uint16_t u6_port; + +}; + + +/** + * + */ struct PrettyPrinterContext { + /** + * + */ GNUNET_TRANSPORT_AddressStringCallback asc; + + /** + * Closure for 'asc'. + */ void *asc_cls; + + /** + * + */ uint16_t port; }; + /** * Encapsulation of all of the state of the plugin. */ @@ -134,7 +185,7 @@ struct Plugin /* *********** globals ************* */ /** - * the socket that we transmit all data with + * The socket that we transmit all data with */ static struct GNUNET_NETWORK_Handle *udp_sock; @@ -146,7 +197,8 @@ static struct GNUNET_NETWORK_Handle *udp_sock; * @return GNUNET_OK on success, GNUNET_SYSERR if the operation failed */ void -udp_disconnect (void *cls, const struct GNUNET_PeerIdentity *target) +udp_disconnect (void *cls, + const struct GNUNET_PeerIdentity *target) { /* nothing to do, UDP is stateless */ } @@ -154,6 +206,8 @@ udp_disconnect (void *cls, const struct GNUNET_PeerIdentity *target) /** * Shutdown the server process (stop receiving inbound traffic). Maybe * restarted later! + * + * @param cls closure, the 'struct Plugin*' */ static int udp_transport_server_stop (void *cls) @@ -178,7 +232,7 @@ udp_transport_server_stop (void *cls) * Function that can be used by the transport service to transmit * a message using the plugin. * - * @param cls closure + * @param cls closure, the 'struct Plugin*' * @param target who should receive this message (ignored by UDP) * @param msgbuf one or more GNUNET_MessageHeader(s) strung together * @param msgbuf_size the size of the msgbuf to send @@ -217,6 +271,13 @@ udp_plugin_send (void *cls, struct UDPMessage *message; int ssize; ssize_t sent; + int af; + const void *sb; + size_t sbs; + struct sockaddr_in a4; + struct sockaddr_in6 a6; + const struct IPv4UdpAddress *t4; + const struct IPv6UdpAddress *t6; GNUNET_assert (NULL == session); GNUNET_assert(udp_sock != NULL); @@ -231,13 +292,45 @@ udp_plugin_send (void *cls, if (force_address == GNUNET_SYSERR) return -1; /* never reliable */ + if (addrlen == sizeof (struct IPv6UdpAddress)) + { + t6 = addr; + af = AF_INET6; + memset (&a6, 0, sizeof (a6)); + a6.sin6_family = AF_INET6; + a6.sin6_port = t6->u6_port; + memcpy (a6.sin6_addr.s6_addr, + t6->ipv6_addr, + 16); + sb = &a6; + sbs = sizeof (a6); + } + else if (addrlen == sizeof (struct IPv4UdpAddress)) + { + t4 = addr; + af = AF_INET; + memset (&a4, 0, sizeof (a4)); + a4.sin_family = AF_INET; + a4.sin_port = t4->u_port; + a4.sin_addr.s_addr = t4->ipv4_addr; + sb = &a4; + sbs = sizeof (a4); + } + else + { + GNUNET_break_op (0); + return -1; + } + /* Build the message to be sent */ message = GNUNET_malloc (sizeof (struct UDPMessage) + msgbuf_size); ssize = sizeof (struct UDPMessage) + msgbuf_size; #if DEBUG_UDP - GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, "udp", _ - ("In udp_send, ssize is %d, sending message to %s\n"), ssize, GNUNET_a2s((const struct sockaddr *)addr, addrlen)); + GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, "udp", + "In udp_send, ssize is %d, sending message to `%s'\n", + ssize, + GNUNET_a2s(sb, sbs)); #endif message->header.size = htons (ssize); message->header.type = htons (0); @@ -246,8 +339,7 @@ udp_plugin_send (void *cls, memcpy (&message[1], msgbuf, msgbuf_size); sent = GNUNET_NETWORK_socket_sendto (udp_sock, message, ssize, - addr, - addrlen); + sb, sbs); if ( (cont != NULL) && (sent != -1) ) cont (cont_cls, target, GNUNET_OK); @@ -259,6 +351,13 @@ udp_plugin_send (void *cls, /** * Add the IP of our network interface to the list of * our external IP addresses. + * + * @param cls closure (the 'struct Plugin*') + * @param name name of the interface (can be NULL for unknown) + * @param isDefault is this presumably the default interface + * @param addr address of this interface (can be NULL for unknown or unassigned) + * @param addrlen length of the address + * @return GNUNET_OK to continue iterating */ static int process_interfaces (void *cls, @@ -268,29 +367,42 @@ process_interfaces (void *cls, { struct Plugin *plugin = cls; int af; - struct sockaddr_in *v4; - struct sockaddr_in6 *v6; + struct IPv4UdpAddress t4; + struct IPv6UdpAddress t6; + void *arg; + uint16_t args; af = addr->sa_family; if (af == AF_INET) { - v4 = (struct sockaddr_in *) addr; - v4->sin_port = htons (plugin->adv_port); + t4.ipv4_addr = ((struct sockaddr_in *) addr)->sin_addr.s_addr; + t4.u_port = htons (plugin->adv_port); + arg = &t4; + args = sizeof (t4); + } + else if (af == AF_INET6) + { + memcpy (t6.ipv6_addr, + ((struct sockaddr_in6 *) addr)->sin6_addr.s6_addr, + 16); + t6.u6_port = htons (plugin->adv_port); + arg = &t6; + args = sizeof (t6); } else { - GNUNET_assert (af == AF_INET6); - v6 = (struct sockaddr_in6 *) addr; - v6->sin6_port = htons (plugin->adv_port); + GNUNET_break (0); + return GNUNET_OK; } GNUNET_log_from (GNUNET_ERROR_TYPE_INFO | GNUNET_ERROR_TYPE_BULK, - "udp", _("Found address `%s' (%s)\n"), - GNUNET_a2s (addr, addrlen), name); + "udp", + _("Found address `%s' (%s)\n"), + GNUNET_a2s (addr, addrlen), + name); plugin->env->notify_address (plugin->env->cls, "udp", - addr, addrlen, GNUNET_TIME_UNIT_FOREVER_REL); - + arg, args, GNUNET_TIME_UNIT_FOREVER_REL); return GNUNET_OK; } @@ -346,6 +458,12 @@ udp_plugin_select (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) int tsize; char *msgbuf; const struct GNUNET_MessageHeader *currhdr; + struct IPv4UdpAddress t4; + struct IPv6UdpAddress t6; + const struct sockaddr_in *s4; + const struct sockaddr_in6 *s6; + const void *ca; + size_t calen; #if DEBUG_UDP GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, "udp", _ @@ -411,6 +529,31 @@ udp_plugin_select (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) ("offset is %d, tsize is %d (UDPMessage size is %d)\n"), offset, tsize, sizeof(struct UDPMessage)); #endif + + if (fromlen == sizeof (struct sockaddr_in)) + { + s4 = (const struct sockaddr_in*) &addr; + t4.u_port = s4->sin_port; + t4.ipv4_addr = s4->sin_addr.s_addr; + ca = &t4; + calen = sizeof (struct IPv4UdpAddress); + } + else if (fromlen == sizeof (struct sockaddr_in6)) + { + s6 = (const struct sockaddr_in6*) &addr; + t6.u6_port = s6->sin6_port; + memcpy (t6.ipv6_addr, + s6->sin6_addr.s6_addr, + 16); + ca = &t6; + calen = sizeof (struct IPv6UdpAddress); + } + else + { + GNUNET_break (0); + ca = NULL; + calen = 0; + } while (offset < tsize) { currhdr = (struct GNUNET_MessageHeader *)&msgbuf[offset]; @@ -421,7 +564,7 @@ udp_plugin_select (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) #endif plugin->env->receive (plugin->env->cls, sender, currhdr, UDP_DIRECT_DISTANCE, - NULL, (const char *)&addr, fromlen); + NULL, ca, calen); offset += ntohs(currhdr->size); #if DEBUG_UDP GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, "udp", _ @@ -446,6 +589,7 @@ udp_plugin_select (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) /** * Create a UDP socket. If possible, use IPv6, otherwise * try IPv4. + * @param cls closure, the 'struct Plugin*' */ static struct GNUNET_NETWORK_Handle * udp_transport_server_start (void *cls) @@ -550,43 +694,30 @@ check_port (struct Plugin *plugin, uint16_t in_port) * @param addrlen length of addr * @return GNUNET_OK if this is a plausible address for this peer * and transport, GNUNET_SYSERR if not - * - * TODO: perhaps make everything work with sockaddr_storage, it may - * be a cleaner way to handle addresses in UDP */ static int udp_check_address (void *cls, void *addr, size_t addrlen) { struct Plugin *plugin = cls; - char buf[sizeof (struct sockaddr_in6)]; - - struct sockaddr_in *v4; - struct sockaddr_in6 *v6; + struct IPv4UdpAddress *v4; + struct IPv6UdpAddress *v6; - if ((addrlen != sizeof (struct sockaddr_in)) && - (addrlen != sizeof (struct sockaddr_in6))) + if ((addrlen != sizeof (struct IPv4UdpAddress)) && + (addrlen != sizeof (struct IPv6UdpAddress))) { GNUNET_break_op (0); return GNUNET_SYSERR; } - memcpy (buf, addr, sizeof (struct sockaddr_in6)); - if (addrlen == sizeof (struct sockaddr_in)) + if (addrlen == sizeof (struct IPv4UdpAddress)) { - v4 = (struct sockaddr_in *) buf; - v4->sin_port = htons (check_port (plugin, ntohs (v4->sin_port))); + v4 = (struct IPv4UdpAddress *) addr; + v4->u_port = htons (check_port (plugin, ntohs (v4->u_port))); } else { - v6 = (struct sockaddr_in6 *) buf; - v6->sin6_port = htons (check_port (plugin, ntohs (v6->sin6_port))); + v6 = (struct IPv6UdpAddress *) addr; + v6->u6_port = htons (check_port (plugin, ntohs (v6->u6_port))); } -#if DEBUG_UDP - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, - "tcp", - "Informing transport service about my address `%s'.\n", - GNUNET_a2s (addr, addrlen)); -#endif - return GNUNET_OK; return GNUNET_OK; } @@ -637,12 +768,43 @@ udp_plugin_address_pretty_printer (void *cls, void *asc_cls) { struct Plugin *plugin = cls; - const struct sockaddr_in *v4; - const struct sockaddr_in6 *v6; struct PrettyPrinterContext *ppc; + const void *sb; + struct sockaddr_in a4; + struct sockaddr_in6 a6; + const struct IPv4UdpAddress *t4; + const struct IPv6UdpAddress *t6; + int af; + size_t sbs; + uint16_t port; - if ((addrlen != sizeof (struct sockaddr_in)) && - (addrlen != sizeof (struct sockaddr_in6))) + if (addrlen == sizeof (struct IPv6UdpAddress)) + { + t6 = addr; + af = AF_INET6; + memset (&a6, 0, sizeof (a6)); + a6.sin6_family = AF_INET6; + a6.sin6_port = t6->u6_port; + port = ntohs (t6->u6_port); + memcpy (a6.sin6_addr.s6_addr, + t6->ipv6_addr, + 16); + sb = &a6; + sbs = sizeof (a6); + } + else if (addrlen == sizeof (struct IPv4UdpAddress)) + { + t4 = addr; + af = AF_INET; + memset (&a4, 0, sizeof (a4)); + a4.sin_family = AF_INET; + a4.sin_port = t4->u_port; + a4.sin_addr.s_addr = t4->ipv4_addr; + port = ntohs (t4->u_port); + sb = &a4; + sbs = sizeof (a4); + } + else { /* invalid address */ GNUNET_break_op (0); @@ -652,28 +814,75 @@ udp_plugin_address_pretty_printer (void *cls, ppc = GNUNET_malloc (sizeof (struct PrettyPrinterContext)); ppc->asc = asc; ppc->asc_cls = asc_cls; - if (addrlen == sizeof (struct sockaddr_in)) + ppc->port = port; + GNUNET_RESOLVER_hostname_get (plugin->env->sched, + plugin->env->cfg, + sb, + sbs, + !numeric, timeout, &append_port, ppc); +} + + + +/** + * Function called for a quick conversion of the binary address to + * a numeric address. Note that the caller must not free the + * address and that the next call to this function is allowed + * to override the address again. + * + * @param cls closure + * @param addr binary address + * @param addr_len length of the address + * @return string representing the same address + */ +static const char* +udp_address_to_string (void *cls, + const void *addr, + size_t addrlen) +{ + static char buf[INET6_ADDRSTRLEN]; + const void *sb; + struct sockaddr_in a4; + struct sockaddr_in6 a6; + const struct IPv4UdpAddress *t4; + const struct IPv6UdpAddress *t6; + int af; + + if (addrlen == sizeof (struct IPv6UdpAddress)) { - v4 = (const struct sockaddr_in *) addr; - ppc->port = ntohs (v4->sin_port); + t6 = addr; + af = AF_INET6; + memset (&a6, 0, sizeof (a6)); + a6.sin6_family = AF_INET6; + a6.sin6_port = t6->u6_port; + memcpy (a6.sin6_addr.s6_addr, + t6->ipv6_addr, + 16); + sb = &a6; } - else + else if (addrlen == sizeof (struct IPv4UdpAddress)) { - v6 = (const struct sockaddr_in6 *) addr; - ppc->port = ntohs (v6->sin6_port); - + t4 = addr; + af = AF_INET; + memset (&a4, 0, sizeof (a4)); + a4.sin_family = AF_INET; + a4.sin_port = t4->u_port; + a4.sin_addr.s_addr = t4->ipv4_addr; + sb = &a4; } - GNUNET_RESOLVER_hostname_get (plugin->env->sched, - plugin->env->cfg, - addr, - addrlen, - !numeric, timeout, &append_port, ppc); + else + return NULL; + + return inet_ntop (af, sb, buf, INET6_ADDRSTRLEN); } /** * The exported method. Makes the core api available via a global and * returns the udp transport API. + * + * @param cls closure, the 'struct GNUNET_TRANSPORT_PluginEnvironment*' + * @return the 'struct GNUNET_TRANSPORT_PluginFunctions*' or NULL on error */ void * libgnunet_plugin_transport_udp_init (void *cls) @@ -737,7 +946,7 @@ libgnunet_plugin_transport_udp_init (void *cls) api->disconnect = &udp_disconnect; api->address_pretty_printer = &udp_plugin_address_pretty_printer; api->check_address = &udp_check_address; - + api->address_to_string = &udp_address_to_string; plugin->service = service; /* FIXME: do the two calls below periodically again and diff --git a/src/transport/test_plugin_transport_http.c b/src/transport/test_plugin_transport_http.c index 1e9f36286..328e70683 100644 --- a/src/transport/test_plugin_transport_http.c +++ b/src/transport/test_plugin_transport_http.c @@ -36,7 +36,7 @@ #include "plugin_transport.h" #include "transport.h" -#define VERBOSE GNUNET_YES +#define VERBOSE GNUNET_NO /** * How long until we give up on transmitting the message? @@ -91,15 +91,17 @@ static int ok; /** * Initialize Environment for this plugin */ -static void +static struct GNUNET_TIME_Relative receive (void *cls, - const struct GNUNET_PeerIdentity * peer, - const struct GNUNET_MessageHeader * message, - uint32_t distance, - const char *sender_address, - size_t sender_address_len) + const struct GNUNET_PeerIdentity * peer, + const struct GNUNET_MessageHeader * message, + uint32_t distance, + struct Session *session, + const char *sender_address, + size_t sender_address_len) { /* do nothing */ + return GNUNET_TIME_UNIT_ZERO; } void -- 2.25.1