From 61b479ac0ad609646ee3dd1fa3ba84205ee95f09 Mon Sep 17 00:00:00 2001 From: "Nathan S. Evans" Date: Thu, 10 Jun 2010 14:09:14 +0000 Subject: [PATCH] working TCP PWNAT implementation (at least on my machine), also base testcase and reliability testcase --- src/transport/Makefile.am | 19 ++- src/transport/plugin_transport_tcp.c | 133 +++++++++++------- src/transport/test_transport_api.c | 32 +++-- .../test_transport_api_reliability.c | 62 +++++--- 4 files changed, 165 insertions(+), 81 deletions(-) diff --git a/src/transport/Makefile.am b/src/transport/Makefile.am index 42952fa6c..4a91fd975 100644 --- a/src/transport/Makefile.am +++ b/src/transport/Makefile.am @@ -129,11 +129,12 @@ endif check_PROGRAMS = \ test_transport_api_tcp \ - test_transport_api_tcp \ + test_transport_api_tcp_nat \ test_transport_api_udp \ $(HTTP_PLUGIN_CHECK) \ test_transport_api_udp_nat \ - test_transport_api_reliability_tcp + test_transport_api_reliability_tcp \ + test_transport_api_reliability_tcp_nat # test_transport_api_http \ # TODO: add tests for http, nat, etc. @@ -145,12 +146,24 @@ test_transport_api_tcp_LDADD = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/util/libgnunetutil.la +test_transport_api_tcp_nat_SOURCES = \ + test_transport_api.c +test_transport_api_tcp_nat_LDADD = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/util/libgnunetutil.la + test_transport_api_reliability_tcp_SOURCES = \ test_transport_api_reliability.c test_transport_api_reliability_tcp_LDADD = \ $(top_builddir)/src/transport/libgnunettransport.la \ $(top_builddir)/src/util/libgnunetutil.la +test_transport_api_reliability_tcp_nat_SOURCES = \ + test_transport_api_reliability.c +test_transport_api_reliability_tcp_nat_LDADD = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/util/libgnunetutil.la + test_transport_api_udp_SOURCES = \ test_transport_api.c test_transport_api_udp_LDADD = \ @@ -186,5 +199,7 @@ EXTRA_DIST = \ test_transport_api_udp_peer2.conf \ test_transport_api_udp_nat_peer1.conf \ test_transport_api_udp_nat_peer2.conf \ + test_transport_api_tcp_nat_peer1.conf \ + test_transport_api_tcp_nat_peer2.conf \ test_plugin_transport_data.conf \ test_plugin_transport_data_http.conf diff --git a/src/transport/plugin_transport_tcp.c b/src/transport/plugin_transport_tcp.c index 7fa586588..cdaef4b48 100644 --- a/src/transport/plugin_transport_tcp.c +++ b/src/transport/plugin_transport_tcp.c @@ -38,6 +38,7 @@ #include "transport.h" #define DEBUG_TCP GNUNET_NO +#define DEBUG_TCP_NAT GNUNET_NO /** * How long until we give up on transmitting the welcome message? @@ -838,9 +839,14 @@ run_gnunet_nat_client (struct Plugin *plugin, const char *addr, size_t addrlen) char *port_as_string; pid_t pid; const struct sockaddr *sa = (const struct sockaddr *)addr; +#if DEBUG_TCP_NAT + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp", + _("called run_gnunet_nat_client addrlen %d others are %d and %d\n"), addrlen, sizeof (struct sockaddr), sizeof (struct sockaddr_in)); +#endif if (addrlen < sizeof (struct sockaddr)) return; + switch (sa->sa_family) { case AF_INET: @@ -857,7 +863,7 @@ run_gnunet_nat_client (struct Plugin *plugin, const char *addr, size_t addrlen) } GNUNET_asprintf(&port_as_string, "%d", plugin->adv_port); -#if DEBUG_UDP_NAT +#if DEBUG_TCP_NAT GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp", _("Running gnunet-nat-client with arguments: %s %s %d\n"), plugin->external_address, address_as_string, plugin->adv_port); #endif @@ -1046,9 +1052,15 @@ tcp_plugin_send (void *cls, if ((is_natd == GNUNET_YES) && (addrlen == sizeof (struct IPv6TcpAddress))) return -1; /* NAT client only works with IPv4 addresses */ + if ( (plugin->allow_nat == GNUNET_YES) && (is_natd == GNUNET_YES) && (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains(plugin->nat_wait_conns, &target->hashPubKey))) { +#if DEBUG_TCP_NAT + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, + "tcp", + _("Found valid IPv4 NAT address!\n")); +#endif session = create_session (plugin, target, NULL, is_natd); @@ -1069,13 +1081,14 @@ tcp_plugin_send (void *cls, pm); GNUNET_CONTAINER_multihashmap_put(plugin->nat_wait_conns, &target->hashPubKey, session, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY); +#if DEBUG_TCP_NAT GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp", "Created NAT WAIT connection to `%4s' at `%s'\n", GNUNET_i2s (target), GNUNET_a2s (sb, sbs)); - - run_gnunet_nat_client(plugin, addr, addrlen); +#endif + run_gnunet_nat_client(plugin, sb, sbs); return 0; } else if ((plugin->allow_nat == GNUNET_YES) && (is_natd == GNUNET_YES) && (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains(plugin->nat_wait_conns, &target->hashPubKey))) @@ -1412,6 +1425,9 @@ handle_tcp_nat_probe (void *cls, const struct sockaddr_in *s4; const struct sockaddr_in6 *s6; +#if DEBUG_TCP_NAT + GNUNET_log_from(GNUNET_ERROR_TYPE_DEBUG, "tcp", "received tcp NAT probe\n"); +#endif /* We have received a TCP NAT probe, meaning we (hopefully) initiated * a connection to this peer by running gnunet-nat-client. This peer * received the punch message and now wants us to use the new connection @@ -1420,28 +1436,34 @@ handle_tcp_nat_probe (void *cls, */ if (ntohs(message->size) != sizeof(struct TCP_NAT_ProbeMessage)) { +#if DEBUG_TCP_NAT + GNUNET_log_from(GNUNET_ERROR_TYPE_DEBUG, "tcp", "Bad size fo tcp NAT probe, expected %d got %d.\n", sizeof(struct TCP_NAT_ProbeMessage), ntohs(message->size)); +#endif GNUNET_break_op(0); - GNUNET_SERVER_receive_done (client, GNUNET_OK); return; } tcp_nat_probe = (struct TCP_NAT_ProbeMessage *)message; if (GNUNET_CONTAINER_multihashmap_contains(plugin->nat_wait_conns, &tcp_nat_probe->clientIdentity.hashPubKey) == GNUNET_YES) { +#if DEBUG_TCP_NAT + GNUNET_log_from(GNUNET_ERROR_TYPE_DEBUG, "tcp", "Found session for NAT probe!\n"); +#endif session = GNUNET_CONTAINER_multihashmap_get(plugin->nat_wait_conns, &tcp_nat_probe->clientIdentity.hashPubKey); GNUNET_assert(session != NULL); GNUNET_SERVER_client_keep (client); session->client = client; + session->last_activity = GNUNET_TIME_absolute_get (); if (GNUNET_OK == GNUNET_SERVER_client_get_address (client, &vaddr, &alen)) { -#if DEBUG_TCP - GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, - "tcp", - "Found address `%s' for incoming connection %p\n", - GNUNET_a2s (vaddr, alen), - client); +#if DEBUG_TCP_NAT + GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, + "tcp", + "Found address `%s' for incoming connection %p\n", + GNUNET_a2s (vaddr, alen), + client); #endif if (alen == sizeof (struct sockaddr_in)) { @@ -1476,7 +1498,6 @@ handle_tcp_nat_probe (void *cls, /* FIXME: free partial session? */ } - session->next = plugin->sessions; plugin->sessions = session; @@ -1485,9 +1506,16 @@ handle_tcp_nat_probe (void *cls, 1, GNUNET_NO); /*GNUNET_SERVER_connect_socket (plugin->server, - client);*/ + client->);*/ + + process_pending_messages (session); + } + else + { +#if DEBUG_TCP_NAT + GNUNET_log_from(GNUNET_ERROR_TYPE_DEBUG, "tcp", "Did NOT find session for NAT probe!\n"); +#endif } - GNUNET_SERVER_receive_done (client, GNUNET_OK); } /** @@ -1639,7 +1667,7 @@ handle_tcp_data (void *cls, if ((GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_WELCOME == ntohs(message->type)) || (ntohs(message->type) == GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_NAT_PROBE)) { - /* We don't want to propagate WELCOME messages up! */ + /* We don't want to propagate WELCOME and NAT Probe messages up! */ GNUNET_SERVER_receive_done (client, GNUNET_OK); return; } @@ -1870,7 +1898,7 @@ tcp_plugin_server_read (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc if (bytes < 1) { -#if DEBUG_UDP_NAT +#if DEBUG_TCP_NAT GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp", _("Finished reading from server stdout with code: %d\n"), bytes); #endif @@ -1921,13 +1949,14 @@ tcp_plugin_server_read (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc return; } + in_addr.sin_family = AF_INET; + in_addr.sin_port = htons(port); /** * We have received an ICMP response, ostensibly from a non-NAT'd peer * that wants to connect to us! Send a message to establish a connection. */ sock = GNUNET_CONNECTION_create_from_sockaddr (plugin->env->sched, AF_INET, (struct sockaddr *)&in_addr, sizeof(in_addr), GNUNET_SERVER_MAX_MESSAGE_SIZE); - if (sock == NULL) { plugin->server_read_task = @@ -1944,7 +1973,7 @@ tcp_plugin_server_read (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc tcp_probe_ctx->message.header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_NAT_PROBE); memcpy(&tcp_probe_ctx->message.clientIdentity, plugin->env->my_identity, sizeof(struct GNUNET_PeerIdentity)); tcp_probe_ctx->plugin = plugin; - + tcp_probe_ctx->sock = sock; tcp_probe_ctx->transmit_handle = GNUNET_CONNECTION_notify_transmit_ready (sock, ntohs(tcp_probe_ctx->message.header.size), GNUNET_TIME_UNIT_FOREVER_REL, @@ -2107,18 +2136,20 @@ libgnunet_plugin_transport_tcp_init (void *cls) if (GNUNET_YES == GNUNET_CONFIGURATION_get_value_yesno (env->cfg, "transport-tcp", "BEHIND_NAT")) - { - /* We are behind nat (according to the user) */ - if (check_gnunet_nat_binary("gnunet-nat-server") == GNUNET_YES) + { + /* We are behind nat (according to the user) */ + if (check_gnunet_nat_binary("gnunet-nat-server") == GNUNET_YES) + { behind_nat = GNUNET_YES; - else - { - behind_nat = GNUNET_NO; - GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, "tcp", "Configuration specified you are behind a NAT, but gnunet-nat-server is not installed properly (suid bit not set)!\n"); - } - } - else - behind_nat = GNUNET_NO; /* We are not behind nat! */ + } + else + { + behind_nat = GNUNET_NO; + GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, "tcp", "Configuration specified you are behind a NAT, but gnunet-nat-server is not installed properly (suid bit not set)!\n"); + } + } + else + behind_nat = GNUNET_NO; /* We are not behind nat! */ if (GNUNET_YES == GNUNET_CONFIGURATION_get_value_yesno (env->cfg, "transport-tcp", @@ -2194,29 +2225,6 @@ libgnunet_plugin_transport_tcp_init (void *cls) return NULL; } - if (behind_nat) - { - if (GNUNET_YES != tcp_transport_start_nat_server(plugin)) - { - GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, - "tcp", - _ - ("Failed to start %s required for NAT in %s!\n"), - "gnunet-nat-server" - "transport-tcp"); - GNUNET_free_non_null(external_address); - GNUNET_free_non_null(internal_address); - GNUNET_SERVICE_stop (service); - return NULL; - } - } - - if (allow_nat) - { - plugin->nat_wait_conns = GNUNET_CONTAINER_multihashmap_create(100); - GNUNET_assert(plugin->nat_wait_conns != NULL); - } - if (aport == 0) aport = bport; plugin = GNUNET_malloc (sizeof (struct Plugin)); @@ -2246,6 +2254,29 @@ libgnunet_plugin_transport_tcp_init (void *cls) plugin->handlers[i].callback_cls = plugin; GNUNET_SERVER_add_handlers (plugin->server, plugin->handlers); + if (behind_nat == GNUNET_YES) + { + if (GNUNET_YES != tcp_transport_start_nat_server(plugin)) + { + GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, + "tcp", + _ + ("Failed to start %s required for NAT in %s!\n"), + "gnunet-nat-server" + "transport-tcp"); + GNUNET_free_non_null(external_address); + GNUNET_free_non_null(internal_address); + GNUNET_SERVICE_stop (service); + return NULL; + } + } + + if (allow_nat == GNUNET_YES) + { + plugin->nat_wait_conns = GNUNET_CONTAINER_multihashmap_create(100); + GNUNET_assert(plugin->nat_wait_conns != NULL); + } + GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, "tcp", _("TCP transport listening on port %llu\n"), bport); if (aport != bport) diff --git a/src/transport/test_transport_api.c b/src/transport/test_transport_api.c index dace6a5e9..50d0d36e0 100644 --- a/src/transport/test_transport_api.c +++ b/src/transport/test_transport_api.c @@ -69,6 +69,8 @@ static int ok; static int is_tcp; +static int is_tcp_nat; + static int is_udp; static int is_udp_nat; @@ -230,13 +232,6 @@ exchange_hello_last (void *cls, GNUNET_assert (GNUNET_OK == GNUNET_HELLO_get_id ((const struct GNUNET_HELLO_Message *) message, &me->id)); - - /* Can't we get away with only offering one hello? */ - /* GNUNET_TRANSPORT_offer_hello (p1.th, message); */ - - /*sleep(1);*/ /* Make sure we are not falling prey to the "favorable timing" bug... */ - - /* both HELLOs exchanged, get ready to test transmission! */ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Finished exchanging HELLOs, now waiting for transmission!\n"); } @@ -287,12 +282,17 @@ run (void *cls, setup_peer (&p1, "test_transport_api_tcp_peer1.conf"); setup_peer (&p2, "test_transport_api_tcp_peer2.conf"); } - if (is_udp_nat) + else if (is_tcp_nat) + { + setup_peer (&p1, "test_transport_api_tcp_nat_peer1.conf"); + setup_peer (&p2, "test_transport_api_tcp_nat_peer2.conf"); + } + else if (is_udp_nat) { setup_peer (&p1, "test_transport_api_udp_nat_peer1.conf"); setup_peer (&p2, "test_transport_api_udp_nat_peer2.conf"); } - if (is_http) + else if (is_http) { setup_peer (&p1, "test_transport_api_http_peer1.conf"); setup_peer (&p2, "test_transport_api_http_peer2.conf"); @@ -402,7 +402,18 @@ main (int argc, char *argv[]) #ifdef MINGW return GNUNET_SYSERR; #endif - if (strstr(argv[0], "tcp") != NULL) + if (strstr(argv[0], "tcp_nat") != NULL) + { + is_tcp_nat = GNUNET_YES; + if (check_gnunet_nat_server() != GNUNET_OK) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "`%s' not properly installed, cannot run NAT test!\n", + "gnunet-nat-server"); + return 0; + } + } + else if (strstr(argv[0], "tcp") != NULL) { is_tcp = GNUNET_YES; } @@ -426,7 +437,6 @@ main (int argc, char *argv[]) is_http = GNUNET_YES; } - GNUNET_log_setup ("test-transport-api", #if VERBOSE "DEBUG", diff --git a/src/transport/test_transport_api_reliability.c b/src/transport/test_transport_api_reliability.c index 6be737309..755d5a576 100644 --- a/src/transport/test_transport_api_reliability.c +++ b/src/transport/test_transport_api_reliability.c @@ -75,8 +75,12 @@ static int ok; static int is_tcp; +static int is_tcp_nat; + static int is_http; +static int connected; + static unsigned long long total_bytes; static struct GNUNET_TIME_Absolute start_time; @@ -193,10 +197,13 @@ notify_receive (void *cls, return; } #if VERBOSE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Got message %u of size %u\n", - ntohl (hdr->num), - ntohs (message->size)); + if (ntohl(hdr->num) % 5000 == 0) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Got message %u of size %u\n", + ntohl (hdr->num), + ntohs (message->size)); + } #endif n++; if (0 == (n % (TOTAL_MSGS/100))) @@ -243,10 +250,13 @@ notify_ready (void *cls, size_t size, void *buf) memset (&cbuf[ret], n, s - sizeof (struct TestMessage)); ret += s - sizeof (struct TestMessage); #if VERBOSE - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Sending message %u of size %u\n", - n, - s); + if (n % 5000 == 0) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Sending message %u of size %u\n", + n, + s); + } #endif n++; s = get_size (n); @@ -260,9 +270,12 @@ notify_ready (void *cls, size_t size, void *buf) s, 0, TIMEOUT, ¬ify_ready, NULL); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Returning total message block of size %u\n", - ret); + if (n % 5000 == 0) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Returning total message block of size %u\n", + ret); + } total_bytes += ret; return ret; } @@ -283,11 +296,7 @@ notify_connect (void *cls, GNUNET_TIME_UNIT_FOREVER_REL, NULL, NULL); start_time = GNUNET_TIME_absolute_get (); - GNUNET_TRANSPORT_notify_transmit_ready (p1.th, - &p2.id, - get_size (0), 0, TIMEOUT, - ¬ify_ready, - NULL); + connected++; } else { @@ -297,6 +306,16 @@ notify_connect (void *cls, GNUNET_BANDWIDTH_value_init (1024 * 1024 * 1024), GNUNET_TIME_UNIT_FOREVER_REL, NULL, NULL); + connected++; + } + + if (connected == 2) + { + GNUNET_TRANSPORT_notify_transmit_ready (p1.th, + &p2.id, + get_size (0), 0, TIMEOUT, + ¬ify_ready, + NULL); } #if VERBOSE GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, @@ -413,6 +432,11 @@ run (void *cls, setup_peer (&p1, "test_transport_api_http_peer1.conf"); setup_peer (&p2, "test_transport_api_http_peer2.conf"); } + else if (is_tcp_nat) + { + setup_peer (&p1, "test_transport_api_tcp_nat_peer1.conf"); + setup_peer (&p2, "test_transport_api_tcp_nat_peer2.conf"); + } else GNUNET_assert (0); GNUNET_assert(p1.th != NULL); @@ -456,7 +480,11 @@ main (int argc, char *argv[]) #ifdef MINGW return GNUNET_SYSERR; #endif - if (strstr(argv[0], "tcp") != NULL) + if (strstr(argv[0], "tcp_nat") != NULL) + { + is_tcp_nat = GNUNET_YES; + } + else if (strstr(argv[0], "tcp") != NULL) { is_tcp = GNUNET_YES; } -- 2.25.1