stuff
[oweals/gnunet.git] / src / transport / plugin_transport_tcp.c
index 18aad989c68dece175636b526ef2cc25e1a6fcdf..e796dacf4ffe20cce4c1a2427ca7ca744153bda0 100644 (file)
@@ -24,6 +24,7 @@
  */
 #include "platform.h"
 #include "gnunet_hello_lib.h"
+#include "gnunet_constants.h"
 #include "gnunet_connection_lib.h"
 #include "gnunet_container_lib.h"
 #include "gnunet_nat_lib.h"
 
 #define DEBUG_TCP_NAT GNUNET_NO
 
-/**
- * How long until we give up on transmitting the welcome message?
- */
-#define HOSTNAME_RESOLVE_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
-
-
 /**
  * Initial handshake message for a session.
  */
@@ -136,7 +131,7 @@ struct IPv4TcpAddress
   /**
    * Port number, in network byte order.
    */
-  uint16_t t_port GNUNET_PACKED;
+  uint16_t t4_port GNUNET_PACKED;
 
 };
 
@@ -165,52 +160,6 @@ struct IPv6TcpAddress
 struct Plugin;
 
 
-/**
- * Local network addresses (actual IP address follows this struct).
- * PORT is NOT included!
- */
-struct LocalAddrList
-{
-
-  /**
-   * This is a doubly linked list.
-   */
-  struct LocalAddrList *next;
-
-  /**
-   * This is a doubly linked list.
-   */
-  struct LocalAddrList *prev;
-
-  /**
-   * Link to plugin.
-   */
-  struct Plugin *plugin;
-
-  /**
-   * Handle to NAT holes we've tried to punch for this address.
-   */
-  struct GNUNET_NAT_Handle *nat;
-
-  /**
-   * Pointer to a 'struct IPv4/V6TcpAddress' describing our external IP and port
-   * as obtained from the NAT by automatic port mapping.
-   */
-  void *external_nat_address;
-
-  /**
-   * Number of bytes in 'external_nat_address'
-   */
-  size_t ena_size;
-
-  /**
-   * Number of bytes of the address that follow
-   */
-  size_t size;
-
-};
-
-
 /**
  * Information kept for each message that is yet to
  * be transmitted.
@@ -365,24 +314,9 @@ struct Plugin
   struct GNUNET_CONNECTION_Handle *lsock;
 
   /**
-   * stdout pipe handle for the gnunet-nat-server process
-   */
-  struct GNUNET_DISK_PipeHandle *server_stdout;
-
-  /**
-   * stdout file handle (for reading) for the gnunet-nat-server process
+   * Our handle to the NAT module.
    */
-  const struct GNUNET_DISK_FileHandle *server_stdout_handle;
-
-  /**
-   * ID of select gnunet-nat-server stdout read task
-   */
-  GNUNET_SCHEDULER_TaskIdentifier server_read_task;
-
-  /**
-   * The process id of the server process (if behind NAT)
-   */
-  struct GNUNET_OS_Process *server_proc;
+  struct GNUNET_NAT_Handle *nat;
 
   /**
    * List of open TCP sessions.
@@ -405,53 +339,30 @@ struct Plugin
    */
   struct GNUNET_SERVER_MessageHandler *handlers;
 
-  /**
-   * Handle for request of hostname resolution, non-NULL if pending.
-   */
-  struct GNUNET_RESOLVER_RequestHandle *hostname_dns;
-
   /**
    * Map of peers we have tried to contact behind a NAT
    */
   struct GNUNET_CONTAINER_MultiHashMap *nat_wait_conns;
-
-  /**
-   * The external address given to us by the user.  Used for HELLOs
-   * and address validation.
-   */
-  char *external_address;
-
-  /**
-   * The internal address given to us by the user (or discovered).
-   * Used for NAT traversal (ICMP method), but not as a 'validateable'
-   * address in HELLOs.
-   */
-  char *internal_address;
-
-  /**
-   * Address given for us to bind to (ONLY).
-   */
-  char *bind_address;
-
+  
   /**
-   * List of our IP addresses.
+   * List of active TCP probes.
    */
-  struct LocalAddrList *lal_head;
+  struct TCPProbeContext *probe_head;
 
   /**
-   * Tail of our IP address list.
+   * List of active TCP probes.
    */
-  struct LocalAddrList *lal_tail;
+  struct TCPProbeContext *probe_tail;
 
   /**
-   * List of active TCP probes.
+   * Handle for (DYN)DNS lookup of our external IP.
    */
-  struct TCPProbeContext *probe_head;
-
+  struct GNUNET_RESOLVER_RequestHandle *ext_dns;
+  
   /**
-   * List of active TCP probes.
+   * How many more TCP sessions are we allowed to open right now?
    */
-  struct TCPProbeContext *probe_tail;
+  unsigned long long max_connections;
 
   /**
    * ID of task used to update our addresses when one expires.
@@ -469,22 +380,34 @@ struct Plugin
    */
   uint16_t adv_port;
 
-  /**
-   * Is this transport configured to be behind a NAT?
-   */
-  int behind_nat;
+};
 
-  /**
-   * Is this transport configured to allow connections to NAT'd peers?
-   */
-  int allow_nat;
 
-  /**
-   * Are we allowed to try UPnP/PMP for NAT traversal?
-   */
-  int allow_upnp;
+/**
+ * Function to check if an inbound connection is acceptable.
+ * Mostly used to limit the total number of open connections 
+ * we can have.
+ *
+ * @param cls the 'struct Plugin'
+ * @param ucred credentials, if available, otherwise NULL
+ * @param addr address
+ * @param addrlen length of address
+ * @return GNUNET_YES to allow, GNUNET_NO to deny, GNUNET_SYSERR
+ *   for unknown address family (will be denied).
+ */
+static int
+plugin_tcp_access_check (void *cls,
+                        const struct GNUNET_CONNECTION_Credentials *ucred,
+                        const struct sockaddr *addr,
+                        socklen_t addrlen)
+{
+  struct Plugin *plugin = cls;
 
-};
+  if (0 == plugin->max_connections)
+    return GNUNET_NO;
+  plugin->max_connections--;
+  return GNUNET_YES;
+}
 
 
 /**
@@ -497,30 +420,34 @@ struct Plugin
  * @param addrlen actual lenght of the address
  */
 static void
-nat_port_map_callback (void *cls,
-                      int add_remove,
-                      const struct sockaddr *addr,
-                      socklen_t addrlen)
+tcp_nat_port_map_callback (void *cls,
+                          int add_remove,
+                          const struct sockaddr *addr,
+                          socklen_t addrlen)
 {
-  struct LocalAddrList *lal = cls;
-  struct Plugin *plugin = lal->plugin;
-  int af;
+  struct Plugin *plugin = cls;
   struct IPv4TcpAddress t4;
   struct IPv6TcpAddress t6;
   void *arg;
-  uint16_t args;
+  size_t args;
 
+  GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
+                  "tcp",
+                  "NPMC called with %d for address `%s'\n",
+                  add_remove,
+                  GNUNET_a2s (addr, addrlen));
   /* convert 'addr' to our internal format */
-  af = addr->sa_family;
-  switch (af)
+  switch (addr->sa_family)
     {
     case AF_INET:
+      GNUNET_assert (addrlen == sizeof (struct sockaddr_in));
       t4.ipv4_addr = ((struct sockaddr_in *) addr)->sin_addr.s_addr;
-      t6.t6_port = ((struct sockaddr_in *) addr)->sin_port;
+      t4.t4_port = ((struct sockaddr_in *) addr)->sin_port;
       arg = &t4;
       args = sizeof (t4);
       break;
     case AF_INET6:
+      GNUNET_assert (addrlen == sizeof (struct sockaddr_in6));
       memcpy (&t6.ipv6_addr,
              &((struct sockaddr_in6 *) addr)->sin6_addr,
              sizeof (struct in6_addr));
@@ -531,152 +458,11 @@ nat_port_map_callback (void *cls,
     default:
       GNUNET_break (0);
       return;
-    } 
-
-  /* modify our published address list */
-  if (GNUNET_YES == add_remove)
-    {
-      plugin->env->notify_address (plugin->env->cls,
-                                   "tcp",
-                                   arg, args, GNUNET_TIME_UNIT_FOREVER_REL);
-      GNUNET_free_non_null (lal->external_nat_address);
-      lal->external_nat_address = GNUNET_memdup (arg, args);
-      lal->ena_size = args;
-    }
-  else
-    {
-      plugin->env->notify_address (plugin->env->cls,
-                                   "tcp",
-                                   arg, args, GNUNET_TIME_UNIT_ZERO);
-      GNUNET_free_non_null (lal->external_nat_address);
-      lal->ena_size = 0;
-    }
-}
-
-
-/**
- * Add the given address to the list of 'local' addresses, thereby
- * making it a 'legal' address for this peer to have.  
- * 
- * @param plugin the plugin
- * @param arg the address, either an IPv4 or an IPv6 IP address
- * @param arg_size number of bytes in arg
- */
-static void
-add_to_address_list (struct Plugin *plugin,
-                    const void *arg,
-                    size_t arg_size)
-{
-  struct LocalAddrList *lal;
-  struct sockaddr_in v4;
-  struct sockaddr_in6 v6;
-  const struct sockaddr *sa;
-  socklen_t salen;
-
-  lal = plugin->lal_head;
-  while (NULL != lal)
-    {
-      if ( (lal->size == arg_size) &&
-          (0 == memcmp (&lal[1], arg, arg_size)) )
-       return;
-      lal = lal->next;
-    }
-  lal = GNUNET_malloc (sizeof (struct LocalAddrList) + arg_size);
-  lal->plugin = plugin;
-  lal->size = arg_size;
-  memcpy (&lal[1], arg, arg_size);
-  GNUNET_CONTAINER_DLL_insert (plugin->lal_head,
-                              plugin->lal_tail,
-                              lal);
-  if (plugin->open_port == 0)
-    return; /* we're not listening at all... */
-  if (arg_size == sizeof (struct in_addr))
-    {
-      memset (&v4, 0, sizeof (v4));
-      v4.sin_family = AF_INET;
-      v4.sin_port = htons (plugin->open_port);
-      memcpy (&v4.sin_addr, arg, arg_size);
-#if HAVE_SOCKADDR_IN_SIN_LEN
-      v4.sin_len = sizeof (struct sockaddr_in);
-#endif
-      sa = (const struct sockaddr*) &v4;
-      salen = sizeof (v4);
     }
-  else if (arg_size == sizeof (struct in6_addr))
-    {     
-      memset (&v6, 0, sizeof (v6));
-      v6.sin6_family = AF_INET6;
-      v6.sin6_port = htons (plugin->open_port);
-      memcpy (&v6.sin6_addr, arg, arg_size);
-#if HAVE_SOCKADDR_IN_SIN_LEN
-      v6.sin6_len = sizeof (struct sockaddr_in6);
-#endif
-      sa = (const struct sockaddr*) &v6;
-      salen = sizeof (v6);
-    }
-  else
-    {
-      GNUNET_break (0);
-      return;
-    }
-  if (plugin->allow_upnp)
-    lal->nat = GNUNET_NAT_register (sa, salen,
-                                   &nat_port_map_callback,
-                                   lal);
-}
-
-
-/**
- * Check if the given address is in the list of 'local' addresses.
- * 
- * @param plugin the plugin
- * @param arg the address, either an IPv4 or an IPv6 IP address
- * @param arg_size number of bytes in arg
- * @return GNUNET_OK if this is one of our IPs, GNUNET_SYSERR if not
- */
-static int
-check_local_addr (struct Plugin *plugin,
-                 const void *arg,
-                 size_t arg_size)
-{
-  struct LocalAddrList *lal;
-
-  lal = plugin->lal_head;
-  while (NULL != lal)
-    {
-      if ( (lal->size == arg_size) &&
-          (0 == memcmp (&lal[1], arg, arg_size)) )
-       return GNUNET_OK;
-      lal = lal->next;
-    }
-  return GNUNET_SYSERR;
-}
-
-
-/**
- * Check if the given address is in the list of 'mapped' addresses.
- * 
- * @param plugin the plugin
- * @param arg the address, either a 'struct IPv4TcpAddress' or a 'struct IPv6TcpAddress'
- * @param arg_size number of bytes in arg
- * @return GNUNET_OK if this is one of our IPs, GNUNET_SYSERR if not
- */
-static int
-check_mapped_addr (struct Plugin *plugin,
-                  const void *arg,
-                  size_t arg_size)
-{
-  struct LocalAddrList *lal;
-
-  lal = plugin->lal_head;
-  while (NULL != lal)
-    {
-      if ( (lal->ena_size == arg_size) &&
-          (0 == memcmp (lal->external_nat_address, arg, arg_size)) )
-       return GNUNET_OK;
-      lal = lal->next;
-    }
-  return GNUNET_SYSERR;
+  /* modify our published address list */
+  plugin->env->notify_address (plugin->env->cls,
+                              add_remove,
+                              arg, args);
 }
 
 
@@ -718,7 +504,7 @@ tcp_address_to_string (void *cls,
     {
       t4 = addr;
       af = AF_INET;
-      port = ntohs (t4->t_port);
+      port = ntohs (t4->t4_port);
       memcpy (&a4, &t4->ipv4_addr, sizeof (a4));
       sb = &a4;
     }
@@ -726,8 +512,8 @@ tcp_address_to_string (void *cls,
     {
       GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR,
                       "tcp",
-                      _("Unexpected address length: %u\n"),
-                      addrlen);
+                      _("Unexpected address length: %u bytes\n"),
+                      (unsigned int) addrlen);
       GNUNET_break (0);
       return NULL;
     }
@@ -865,6 +651,7 @@ do_transmit (void *cls, size_t size, void *buf)
   char *cbuf;
   size_t ret;
 
+  GNUNET_assert (session != NULL);
   session->transmit_handle = NULL;
   plugin = session->plugin;
   if (buf == NULL)
@@ -1039,9 +826,7 @@ disconnect_session (struct Session *session)
     session->plugin->sessions = session->next;
   else
     prev->next = session->next;
-  session->plugin->env->session_end (session->plugin->env->cls,
-                                    &session->target,
-                                    session);
+
   /* clean up state */
   if (session->transmit_handle != NULL)
     {
@@ -1083,13 +868,20 @@ disconnect_session (struct Session *session)
        GNUNET_SERVER_receive_done (session->client,
                                    GNUNET_SYSERR);     
     }
-  if (session->client != NULL) 
-    GNUNET_SERVER_client_drop (session->client);
+  if (session->client != NULL)
+    {
+      GNUNET_SERVER_client_drop (session->client);
+      session->client = NULL;
+    }
   GNUNET_STATISTICS_update (session->plugin->env->stats,
                            gettext_noop ("# TCP sessions active"),
                            -1,
                            GNUNET_NO);
   GNUNET_free_non_null (session->connect_addr);
+  session->plugin->env->session_end (session->plugin->env->cls,
+                                     &session->target,
+                                     session);
+  GNUNET_assert (NULL == session->transmit_handle);
   GNUNET_free (session);
 }
 
@@ -1129,62 +921,6 @@ select_better_session (struct Session *s1,
 }
 
 
-/**
- * We learned about a peer (possibly behind NAT) so run the
- * gnunet-nat-client to send dummy ICMP responses.
- *
- * @param plugin the plugin for this transport
- * @param addr the address of the peer (IPv4-only)
- */
-static void
-run_gnunet_nat_client (struct Plugin *plugin, 
-                      const struct sockaddr_in *sa)
-{
-  char inet4[INET_ADDRSTRLEN];
-  char port_as_string[6];
-  struct GNUNET_OS_Process *proc;
-
-  if (plugin->internal_address == NULL)
-    {
-      GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING,
-                      "tcp",
-                      _("Internal IP address not known, cannot use ICMP NAT traversal method\n"));
-      return;
-    }
-  GNUNET_assert (sa->sin_family == AF_INET);
-  if (NULL == inet_ntop (AF_INET,
-                        &sa->sin_addr,
-                        inet4, INET_ADDRSTRLEN))
-    {
-      GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "inet_ntop");
-      return;
-    }
-  GNUNET_snprintf(port_as_string, 
-                 sizeof (port_as_string),
-                 "%d", 
-                 plugin->adv_port);
-#if DEBUG_TCP_NAT
-  GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
-                  "tcp",
-                  _("Running gnunet-nat-client %s %s %u\n"), 
-                  plugin->internal_address,
-                  inet4,
-                  (unsigned int) plugin->adv_port);
-#endif
-  proc = GNUNET_OS_start_process (NULL, 
-                                 NULL, 
-                                 "gnunet-nat-client",
-                                 "gnunet-nat-client",
-                                 plugin->internal_address, 
-                                 inet4,
-                                 port_as_string, 
-                                 NULL);
-  /* we know that the gnunet-nat-client will terminate virtually
-     instantly */
-  GNUNET_OS_process_wait (proc);
-  GNUNET_OS_process_close (proc);
-}
-
 
 /**
  * Function that can be used by the transport service to transmit
@@ -1341,8 +1077,8 @@ tcp_plugin_send (void *cls,
           a4.sin_len = sizeof (a4);
 #endif
          a4.sin_family = AF_INET;
-         a4.sin_port = t4->t_port;
-         if (t4->t_port == 0)
+         a4.sin_port = t4->t4_port;
+         if (t4->t4_port == 0)
            is_natd = GNUNET_YES;
          a4.sin_addr.s_addr = t4->ipv4_addr;
          sb = &a4;
@@ -1360,10 +1096,13 @@ tcp_plugin_send (void *cls,
 
       if ((is_natd == GNUNET_YES) && (addrlen == sizeof (struct IPv6TcpAddress)))
         return -1; /* NAT client only works with IPv4 addresses */
+      if (0 == plugin->max_connections)
+       return -1; /* saturated */
 
-
-      if ((plugin->allow_nat == GNUNET_YES) && (is_natd == GNUNET_YES) &&
-           (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains(plugin->nat_wait_conns, &target->hashPubKey)))
+      if ( (is_natd == GNUNET_YES) &&
+          (NULL != plugin->nat) &&
+           (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains(plugin->nat_wait_conns,
+                                                               &target->hashPubKey)) )
         {
 #if DEBUG_TCP_NAT
           GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
@@ -1374,6 +1113,7 @@ tcp_plugin_send (void *cls,
                                     target,
                                     NULL, 
                                    GNUNET_YES);
+          GNUNET_assert (session != NULL);
 
           /* create new message entry */
           pm = GNUNET_malloc (sizeof (struct PendingMessage) + msgbuf_size);
@@ -1404,12 +1144,12 @@ tcp_plugin_send (void *cls,
                            GNUNET_i2s (target),
                            GNUNET_a2s (sb, sbs));
 #endif
-          run_gnunet_nat_client (plugin, &a4);
+          GNUNET_NAT_run_client (plugin->nat, &a4);
           return 0;
         }
-      if ( (plugin->allow_nat == GNUNET_YES) && 
-          (is_natd == GNUNET_YES) && 
-          (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains(plugin->nat_wait_conns, &target->hashPubKey)) )
+      if ( (is_natd == GNUNET_YES) && 
+          (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains(plugin->nat_wait_conns, 
+                                                                &target->hashPubKey)) )
         {
           /* Only do one NAT punch attempt per peer identity */
           return -1;
@@ -1430,6 +1170,8 @@ tcp_plugin_send (void *cls,
                                    GNUNET_NO);
          return -1;
        }
+      GNUNET_assert (0 != plugin->max_connections);
+      plugin->max_connections--;
 #if DEBUG_TCP_NAT
       GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
                       "tcp",
@@ -1448,8 +1190,23 @@ tcp_plugin_send (void *cls,
              addrlen);
       session->connect_alen = addrlen;
     }
+  else  /* session != NULL */
+    {
+      /* check if session is valid */
+      struct Session * ses = plugin->sessions;
+      while ((ses != NULL) && (ses != session))
+        ses = ses->next;
+      if (ses == NULL)
+       {
+         GNUNET_break (0);
+         return -1;
+       }
+    }
   GNUNET_assert (session != NULL);
   GNUNET_assert (session->client != NULL);
+
+
+  GNUNET_SERVER_client_set_timeout(session->client, GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
   GNUNET_STATISTICS_update (plugin->env->stats,
                            gettext_noop ("# bytes currently in TCP buffers"),
                            msgbuf_size,
@@ -1526,6 +1283,10 @@ tcp_plugin_disconnect (void *cls,
          pm->transmit_cont_cls = NULL;
          pm = pm->next;
        }
+      GNUNET_STATISTICS_update (session->plugin->env->stats,
+                               gettext_noop ("# transport-service disconnect requests for TCP"),
+                               1,
+                               GNUNET_NO);
       disconnect_session (session);
     }
 }
@@ -1601,7 +1362,6 @@ tcp_plugin_address_pretty_printer (void *cls,
                                    GNUNET_TRANSPORT_AddressStringCallback asc,
                                    void *asc_cls)
 {
-  struct Plugin *plugin = cls;
   struct PrettyPrinterContext *ppc;
   const void *sb;
   size_t sbs;
@@ -1629,9 +1389,9 @@ tcp_plugin_address_pretty_printer (void *cls,
       t4 = addr;
       memset (&a4, 0, sizeof (a4));
       a4.sin_family = AF_INET;
-      a4.sin_port = t4->t_port;
+      a4.sin_port = t4->t4_port;
       a4.sin_addr.s_addr = t4->ipv4_addr;
-      port = ntohs (t4->t_port);
+      port = ntohs (t4->t4_port);
       sb = &a4;
       sbs = sizeof (a4);
     }
@@ -1646,8 +1406,7 @@ tcp_plugin_address_pretty_printer (void *cls,
   ppc->asc = asc;
   ppc->asc_cls = asc_cls;
   ppc->port = port;
-  GNUNET_RESOLVER_hostname_get (plugin->env->cfg,
-                                sb,
+  GNUNET_RESOLVER_hostname_get (sb,
                                 sbs,
                                 !numeric, timeout, &append_port, ppc);
 }
@@ -1706,14 +1465,12 @@ tcp_plugin_check_address (void *cls,
   if (addrlen == sizeof (struct IPv4TcpAddress))
     {
       v4 = (struct IPv4TcpAddress *) addr;
-      if (GNUNET_OK ==
-         check_mapped_addr (plugin, v4, sizeof (struct IPv4TcpAddress)))
-       return GNUNET_OK;
       if (GNUNET_OK !=
-         check_port (plugin, ntohs (v4->t_port)))
+         check_port (plugin, ntohs (v4->t4_port)))
        return GNUNET_SYSERR;
       if (GNUNET_OK !=
-         check_local_addr (plugin, &v4->ipv4_addr, sizeof (struct in_addr)))
+         GNUNET_NAT_test_address (plugin->nat,
+                                  &v4->ipv4_addr, sizeof (struct in_addr)))
        return GNUNET_SYSERR;   
     }
   else
@@ -1724,14 +1481,12 @@ tcp_plugin_check_address (void *cls,
          GNUNET_break_op (0);
          return GNUNET_SYSERR;
        }
-      if (GNUNET_OK ==
-         check_mapped_addr (plugin, v6, sizeof (struct IPv6TcpAddress)))
-       return GNUNET_OK;
       if (GNUNET_OK !=
          check_port (plugin, ntohs (v6->t6_port)))
        return GNUNET_SYSERR;
       if (GNUNET_OK !=
-         check_local_addr (plugin, &v6->ipv6_addr, sizeof (struct in6_addr)))
+         GNUNET_NAT_test_address (plugin->nat,
+                                  &v6->ipv6_addr, sizeof (struct in6_addr)))
        return GNUNET_SYSERR;
     }
   return GNUNET_OK;
@@ -1765,7 +1520,7 @@ handle_tcp_nat_probe (void *cls,
 #if DEBUG_TCP_NAT
   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, 
                   "tcp",
-                  "received tcp NAT probe\n");
+                  "received 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
@@ -1776,9 +1531,20 @@ handle_tcp_nat_probe (void *cls,
   if (ntohs(message->size) != sizeof(struct TCP_NAT_ProbeMessage))
     {
       GNUNET_break_op(0);
+      GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
       return;
     }
+
   tcp_nat_probe = (const struct TCP_NAT_ProbeMessage *)message;
+  if (0 == memcmp (&tcp_nat_probe->clientIdentity,
+                   plugin->env->my_identity,
+                   sizeof (struct GNUNET_PeerIdentity)))
+    {
+      /* refuse connections from ourselves */
+      GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+      return;
+    }
+
   session = GNUNET_CONTAINER_multihashmap_get(plugin->nat_wait_conns, 
                                              &tcp_nat_probe->clientIdentity.hashPubKey);
   if (session == NULL)
@@ -1824,7 +1590,7 @@ handle_tcp_nat_probe (void *cls,
     case AF_INET:
       s4 = vaddr;
       t4 = GNUNET_malloc (sizeof (struct IPv4TcpAddress));
-      t4->t_port = s4->sin_port;
+      t4->t4_port = s4->sin_port;
       t4->ipv4_addr = s4->sin_addr.s_addr;
       session->connect_addr = t4;
       session->connect_alen = sizeof (struct IPv4TcpAddress);
@@ -1887,7 +1653,15 @@ handle_tcp_welcome (void *cls,
   struct IPv6TcpAddress *t6;
   const struct sockaddr_in *s4;
   const struct sockaddr_in6 *s6;
-
+  
+  if (0 == memcmp (&wm->clientIdentity,
+                  plugin->env->my_identity,
+                  sizeof (struct GNUNET_PeerIdentity)))
+    {
+      /* refuse connections from ourselves */
+      GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+      return;
+    }
 #if DEBUG_TCP
   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
                   "tcp",
@@ -1929,7 +1703,7 @@ handle_tcp_welcome (void *cls,
            {
              s4 = vaddr;
              t4 = GNUNET_malloc (sizeof (struct IPv4TcpAddress));
-             t4->t_port = s4->sin_port;
+             t4->t4_port = s4->sin_port;
              t4->ipv4_addr = s4->sin_addr.s_addr;
              session->connect_addr = t4;
              session->connect_alen = sizeof (struct IPv4TcpAddress);
@@ -1968,6 +1742,7 @@ handle_tcp_welcome (void *cls,
                         "tcp",
                         "Found address `%s' (already have session)\n",
                         GNUNET_a2s (vaddr, alen));
+       GNUNET_free (vaddr);
       }
 #endif
     }
@@ -1980,6 +1755,7 @@ handle_tcp_welcome (void *cls,
     }
   session->last_activity = GNUNET_TIME_absolute_get ();
   session->expecting_welcome = GNUNET_NO;
+  GNUNET_SERVER_client_set_timeout(client, GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
   GNUNET_SERVER_receive_done (client, GNUNET_OK);
 }
 
@@ -2001,6 +1777,7 @@ delayed_done (void *cls,
   session->receive_delay_task = GNUNET_SCHEDULER_NO_TASK;
   delay = session->plugin->env->receive (session->plugin->env->cls,
                                         &session->target,
+                                        NULL,
                                         NULL, 0,
                                         session,
                                         NULL, 0);
@@ -2057,15 +1834,34 @@ handle_tcp_data (void *cls,
                            gettext_noop ("# bytes received via TCP"),
                            ntohs (message->size),
                            GNUNET_NO);
-  delay = plugin->env->receive (plugin->env->cls, &session->target, message, 1,
+  struct GNUNET_TRANSPORT_ATS_Information distance[2];
+  distance[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
+  distance[0].value = htonl (1);
+  distance[1].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
+  distance[1].value = htonl (0);
+  delay = plugin->env->receive (plugin->env->cls, &session->target, message,
+                               (const struct GNUNET_TRANSPORT_ATS_Information *) &distance,
+                               2,
                                session,
                                (GNUNET_YES == session->inbound) ? NULL : session->connect_addr,
                                (GNUNET_YES == session->inbound) ? 0 : session->connect_alen);
   if (delay.rel_value == 0)
-    GNUNET_SERVER_receive_done (client, GNUNET_OK);
+    {
+      GNUNET_SERVER_receive_done (client, GNUNET_OK);
+    }
   else
-    session->receive_delay_task =
-      GNUNET_SCHEDULER_add_delayed (delay, &delayed_done, session);
+    {
+#if DEBUG_TCP 
+      GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
+                      "tcp",
+                      "Throttling receiving from `%s' for %llu ms\n",
+                      GNUNET_i2s (&session->target),
+                      (unsigned long long) delay.rel_value);
+#endif
+      GNUNET_SERVER_disable_receive_done_warning (client);
+      session->receive_delay_task =
+       GNUNET_SCHEDULER_add_delayed (delay, &delayed_done, session);
+    }
 }
 
 
@@ -2085,6 +1881,7 @@ disconnect_notify (void *cls,
 
   if (client == NULL)
     return;
+  plugin->max_connections++;
   session = find_session_by_client (plugin, client);
   if (session == NULL)
     return;                     /* unknown, nothing to do */
@@ -2098,156 +1895,14 @@ disconnect_notify (void *cls,
                                          session->connect_addr,
                                          session->connect_alen) : "*");
 #endif
+  GNUNET_STATISTICS_update (session->plugin->env->stats,
+                           gettext_noop ("# network-level TCP disconnect events"),
+                           1,
+                           GNUNET_NO);
   disconnect_session (session);
 }
 
 
-/**
- * Add the IP of our network interface to the list of
- * our internal IP addresses.
- *
- * @param cls the 'struct Plugin*'
- * @param name name of the interface
- * @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,
-                    const char *name,
-                    int isDefault,
-                    const struct sockaddr *addr, socklen_t addrlen)
-{
-  struct Plugin *plugin = cls;
-  int af;
-  struct IPv4TcpAddress t4;
-  struct IPv6TcpAddress t6;
-  struct IPv4TcpAddress t4_nat;
-  struct IPv6TcpAddress t6_nat;
-  void *arg;
-  uint16_t args;
-  void *arg_nat;
-  char buf[INET_ADDRSTRLEN];
-
-  af = addr->sa_family;
-  arg_nat = NULL;
-  switch (af)
-    {
-    case AF_INET:
-      t4.ipv4_addr = ((struct sockaddr_in *) addr)->sin_addr.s_addr;
-      GNUNET_assert (NULL != inet_ntop(AF_INET, 
-                                      &t4.ipv4_addr, 
-                                      buf, 
-                                      sizeof (buf)));
-      if ( (plugin->bind_address != NULL) && 
-          (0 != strcmp(buf, plugin->bind_address)) )
-        {
-#if DEBUG_TCP
-          GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, 
-                          "tcp",
-                          "Not notifying transport of address `%s' (redundant)\n",
-                          GNUNET_a2s (addr, addrlen));
-#endif
-          return GNUNET_OK;
-        }
-      if ( (plugin->internal_address == NULL) &&
-          (isDefault) )        
-       plugin->internal_address = GNUNET_strdup (buf); 
-      add_to_address_list (plugin, &t4.ipv4_addr, sizeof (struct in_addr));
-      if (plugin->behind_nat == GNUNET_YES) 
-        {
-         /* Also advertise as NAT (with port 0) */
-          t4_nat.ipv4_addr = ((struct sockaddr_in *) addr)->sin_addr.s_addr;
-          t4_nat.t_port = htons(0);
-          arg_nat = &t4_nat;
-        }      
-      t4.t_port = htons (plugin->adv_port);    
-      arg = &t4;
-      args = sizeof (t4);
-      break;
-    case AF_INET6:      
-      if ( (IN6_IS_ADDR_LINKLOCAL (&((struct sockaddr_in6 *) addr)->sin6_addr)) || 
-          (GNUNET_YES == GNUNET_CONFIGURATION_get_value_yesno(plugin->env->cfg, 
-                                                              "transport-tcp", 
-                                                              "DISABLEV6")) )
-       {
-         /* skip link local addresses */
-         return GNUNET_OK;
-       }
-      memcpy (&t6.ipv6_addr,
-             &((struct sockaddr_in6 *) addr)->sin6_addr,
-             sizeof (struct in6_addr));
-      add_to_address_list (plugin, 
-                          &t6.ipv6_addr, 
-                          sizeof (struct in6_addr));
-      if (plugin->behind_nat == GNUNET_YES)
-        {
-         /* Also advertise as NAT (with port 0) */
-          memcpy (&t6_nat.ipv6_addr,
-                  &((struct sockaddr_in6 *) addr)->sin6_addr,
-                  sizeof (struct in6_addr));
-          t6_nat.t6_port = htons(0);
-          arg_nat = &t6;
-        }
-      t6.t6_port = htons (plugin->adv_port);
-      arg = &t6;
-      args = sizeof (t6);
-      break;
-    default:
-      GNUNET_break (0);
-      return GNUNET_OK;
-    }
-#if DEBUG_TCP
-  GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
-                  "tcp",
-                  "Found address `%s' (%s) len %d\n",
-                   GNUNET_a2s (addr, addrlen), name, args);
-#endif
-  plugin->env->notify_address (plugin->env->cls,
-                               "tcp",
-                               arg, args, GNUNET_TIME_UNIT_FOREVER_REL);
-
-  if (arg_nat != NULL)
-    {
-      GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
-                      "tcp",
-                      _("Found address `%s' (%s) len %d\n"),
-                      GNUNET_a2s (addr, addrlen), name, args);
-      plugin->env->notify_address (plugin->env->cls,
-                                   "tcp",
-                                   arg_nat, args, GNUNET_TIME_UNIT_FOREVER_REL);
-    }
-
-  return GNUNET_OK;
-}
-
-
-/**
- * Function called by the resolver for each address obtained from DNS
- * for our own hostname.  Add the addresses to the list of our
- * external IP addresses.
- *
- * @param cls closure
- * @param addr one of the addresses of the host, NULL for the last address
- * @param addrlen length of the address
- */
-static void
-process_hostname_ips (void *cls,
-                      const struct sockaddr *addr, socklen_t addrlen)
-{
-  struct Plugin *plugin = cls;
-
-  if (addr == NULL)
-    {
-      plugin->hostname_dns = NULL;
-      return;
-    }
-  /* FIXME: Can we figure out our external address here so it doesn't need to be user specified? */
-  process_interfaces (plugin, "<hostname>", GNUNET_YES, addr, addrlen);
-}
-
-
 /**
  * We can now send a probe message, copy into buffer to really send.
  *
@@ -2286,112 +1941,36 @@ notify_send_probe (void *cls,
 
 
 /**
- * We have been notified that gnunet-nat-server has written something to stdout.
- * Handle the output, then reschedule this function to be called again once
- * more is available.
+ * Function called by the NAT subsystem suggesting another peer wants
+ * to connect to us via connection reversal.  Try to connect back to the
+ * given IP.
  *
- * @param cls the plugin handle
- * @param tc the scheduling context
+ * @param cls closure
+ * @param addr address to try
+ * @param addrlen number of bytes in addr
  */
 static void
-tcp_plugin_server_read (void *cls, 
-                       const struct GNUNET_SCHEDULER_TaskContext *tc)
+try_connection_reversal (void *cls,
+                        const struct sockaddr *addr,
+                        socklen_t addrlen)
 {
   struct Plugin *plugin = cls;
-  char mybuf[40];
-  ssize_t bytes;
-  size_t i;
-  int port;
-  const char *port_start;
-  struct sockaddr_in sin_addr;
-  struct TCPProbeContext *tcp_probe_ctx;
   struct GNUNET_CONNECTION_Handle *sock;
-
-  if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN)
-    return;
-  memset (mybuf, 0, sizeof(mybuf));
-  bytes = GNUNET_DISK_file_read(plugin->server_stdout_handle, 
-                               mybuf,
-                               sizeof(mybuf));
-  if (bytes < 1)
-    {
-#if DEBUG_TCP_NAT
-      GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
-                      "tcp",
-                      "Finished reading from server stdout with code: %d\n", 
-                      bytes);
-#endif
-      return;
-    }
-
-  port_start = NULL;
-  for (i = 0; i < sizeof(mybuf); i++)
-    {
-      if (mybuf[i] == '\n')
-       {
-         mybuf[i] = '\0';
-         break;
-       }
-      if ( (mybuf[i] == ':') && (i + 1 < sizeof(mybuf)) )
-        {
-          mybuf[i] = '\0';
-          port_start = &mybuf[i + 1];
-        }
-    }
-
-  /* construct socket address of sender */
-  memset (&sin_addr, 0, sizeof (sin_addr));
-  sin_addr.sin_family = AF_INET;
-  sin_addr.sin_port = htons((uint16_t) port);
-#if HAVE_SOCKADDR_IN_SIN_LEN
-  sin_addr.sin_len = sizeof (sin_addr);
-#endif
-  if ( (NULL == port_start) ||
-       (1 != sscanf (port_start, "%d", &port)) ||
-       (-1 == inet_pton(AF_INET, mybuf, &sin_addr.sin_addr)) )
-    {
-      /* should we restart gnunet-nat-server? */
-      GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING,
-                      "tcp",
-                      _("gnunet-nat-server generated malformed address `%s'\n"),
-                      mybuf);
-      plugin->server_read_task 
-       = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
-                                         plugin->server_stdout_handle,
-                                         &tcp_plugin_server_read, 
-                                         plugin);
-      return;
-    }
-
-#if DEBUG_TCP_NAT
-  GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
-                  "tcp",
-                  "gnunet-nat-server read: %s:%d\n", 
-                  mybuf, port);
-#endif
+  struct TCPProbeContext *tcp_probe_ctx;
 
   /**
    * We have received an ICMP response, ostensibly from a peer
    * that wants to connect to us! Send a message to establish a connection.
    */
   sock = GNUNET_CONNECTION_create_from_sockaddr (AF_INET, 
-                                                (const struct sockaddr *)&sin_addr,
-                                                 sizeof (sin_addr));
+                                                addr,
+                                                addrlen);
   if (sock == NULL)
     {
       /* failed for some odd reason (out of sockets?); ignore attempt */
-      plugin->server_read_task =
-          GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
-                                          plugin->server_stdout_handle, 
-                                         &tcp_plugin_server_read, 
-                                         plugin);
       return;
     }
 
-  GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
-                  "Sending TCP probe message to `%s:%u'!\n", 
-                  mybuf,
-                  (unsigned int) port);  
   /* FIXME: do we need to track these probe context objects so that
      we can clean them up on plugin unload? */
   tcp_probe_ctx
@@ -2414,181 +1993,6 @@ tcp_plugin_server_read (void *cls,
                                               GNUNET_TIME_UNIT_FOREVER_REL,
                                               &notify_send_probe, tcp_probe_ctx);
   
-  plugin->server_read_task =
-      GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
-                                      plugin->server_stdout_handle,
-                                     &tcp_plugin_server_read,
-                                     plugin);
-}
-
-
-/**
- * Start the gnunet-nat-server process for users behind NAT.
- *
- * @param plugin the transport plugin
- * @return GNUNET_YES if process was started, GNUNET_SYSERR on error
- */
-static int
-tcp_transport_start_nat_server (struct Plugin *plugin)
-{
-  if (plugin->internal_address == NULL)
-    return GNUNET_SYSERR;
-  plugin->server_stdout = GNUNET_DISK_pipe (GNUNET_YES,
-                                           GNUNET_NO,
-                                           GNUNET_YES);
-  if (plugin->server_stdout == NULL)
-    return GNUNET_SYSERR;
-#if DEBUG_TCP_NAT
-  GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
-                  "tcp"
-                   "Starting %s %s\n", 
-                  "gnunet-nat-server", 
-                  plugin->internal_address);
-#endif
-  /* Start the server process */
-  plugin->server_proc = GNUNET_OS_start_process (NULL,
-                                                plugin->server_stdout,
-                                                "gnunet-nat-server", 
-                                                "gnunet-nat-server", 
-                                                plugin->internal_address, 
-                                                NULL);
-  if (plugin->server_proc == NULL)
-    {
-      GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING,
-                      "tcp",
-                      _("Failed to start %s\n"),
-                      "gnunet-nat-server");
-      GNUNET_DISK_pipe_close (plugin->server_stdout);
-      plugin->server_stdout = NULL;    
-      return GNUNET_SYSERR;
-    }
-  /* Close the write end of the read pipe */
-  GNUNET_DISK_pipe_close_end(plugin->server_stdout, 
-                            GNUNET_DISK_PIPE_END_WRITE);
-  plugin->server_stdout_handle 
-    = GNUNET_DISK_pipe_handle (plugin->server_stdout, 
-                              GNUNET_DISK_PIPE_END_READ);
-  plugin->server_read_task 
-    = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
-                                      plugin->server_stdout_handle,
-                                     &tcp_plugin_server_read, 
-                                     plugin);
-  return GNUNET_YES;
-}
-
-
-/**
- * Return the actual path to a file found in the current
- * PATH environment variable.
- *
- * @param binary the name of the file to find
- * @return path to binary, NULL if not found
- */
-static char *
-get_path_from_PATH (const char *binary)
-{
-  char *path;
-  char *pos;
-  char *end;
-  char *buf;
-  const char *p;
-
-  p = getenv ("PATH");
-  if (p == NULL)
-    {
-      GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR,
-                      "tcp",
-                      _("PATH environment variable is unset.\n"));
-      return NULL;
-    }
-  path = GNUNET_strdup (p);     /* because we write on it */
-  buf = GNUNET_malloc (strlen (path) + 20);
-  pos = path;
-
-  while (NULL != (end = strchr (pos, PATH_SEPARATOR)))
-    {
-      *end = '\0';
-      sprintf (buf, "%s/%s", pos, binary);
-      if (GNUNET_DISK_file_test (buf) == GNUNET_YES)
-        {
-          GNUNET_free (path);
-          return buf;
-        }
-      pos = end + 1;
-    }
-  sprintf (buf, "%s/%s", pos, binary);
-  if (GNUNET_DISK_file_test (buf) == GNUNET_YES)
-    {
-      GNUNET_free (path);
-      return buf;
-    }
-  GNUNET_free (buf);
-  GNUNET_free (path);
-  return NULL;
-}
-
-
-/**
- * Check whether the suid bit is set on a file.
- * Attempts to find the file using the current
- * PATH environment variable as a search path.
- *
- * @param binary the name of the file to check
- * @return GNUNET_YES if the file is SUID, 
- *         GNUNET_NO if not, 
- *         GNUNET_SYSERR on error
- */
-static int
-check_gnunet_nat_binary (const char *binary)
-{
-  struct stat statbuf;
-  char *p;
-#ifdef MINGW
-  SOCKET rawsock;
-  char *binaryexe;
-
-  GNUNET_asprintf (&binaryexe, "%s.exe", binary);
-  p = get_path_from_PATH (binaryexe);
-  free (binaryexe);
-#else
-  p = get_path_from_PATH (binary);
-#endif
-  if (p == NULL)
-    {
-      GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR,
-                      "tcp",
-                      _("Could not find binary `%s' in PATH!\n"),
-                      binary);
-      return GNUNET_NO;
-    }
-  if (0 != STAT (p, &statbuf))
-    {
-      GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 
-                 _("stat (%s) failed: %s\n"), 
-                 p,
-                 STRERROR (errno));
-      GNUNET_free (p);
-      return GNUNET_SYSERR;
-    }
-  GNUNET_free (p);
-#ifndef MINGW
-  if ( (0 != (statbuf.st_mode & S_ISUID)) &&
-       (statbuf.st_uid == 0) )
-    return GNUNET_YES;
-  return GNUNET_NO;
-#else
-  rawsock = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP);
-  if (INVALID_SOCKET == rawsock)
-    {
-      DWORD err = GetLastError ();
-      GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, 
-                      "tcp",
-                      "socket (AF_INET, SOCK_RAW, IPPROTO_ICMP) failed! GLE = %d\n", err);
-      return GNUNET_NO; /* not running as administrator */
-    }
-  closesocket (rawsock);
-  return GNUNET_YES;
-#endif
 }
 
 
@@ -2614,87 +2018,20 @@ libgnunet_plugin_transport_tcp_init (void *cls)
   struct GNUNET_SERVICE_Context *service;
   unsigned long long aport;
   unsigned long long bport;
+  unsigned long long max_connections;
   unsigned int i;
-  int behind_nat;
-  int allow_nat;
-  char *internal_address;
-  char *external_address;
-  struct sockaddr_in in_addr;
-  struct IPv4TcpAddress t4;
   struct GNUNET_TIME_Relative idle_timeout;
+  int ret;
+  struct sockaddr **addrs;
+  socklen_t *addrlens;
 
-  behind_nat = GNUNET_CONFIGURATION_get_value_yesno (env->cfg,
-                                                    "transport-tcp",
-                                                    "BEHIND_NAT");
-  if ( (GNUNET_YES == behind_nat) &&
-       (GNUNET_YES != check_gnunet_nat_binary("gnunet-nat-server")) )
-    {
-      behind_nat = GNUNET_NO;
-      GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
-                 _("Configuration requires `%s', but binary is not installed properly (SUID bit not set).  Option disabled.\n"),
-                 "gnunet-nat-server");        
-    }
-
-  allow_nat = GNUNET_CONFIGURATION_get_value_yesno (env->cfg,
-                                                   "transport-tcp",
-                                                   "ALLOW_NAT");
-  if ( (GNUNET_YES == allow_nat) &&
-       (GNUNET_YES != check_gnunet_nat_binary("gnunet-nat-client")) )
-    {
-      allow_nat = GNUNET_NO;
-      GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
-                 _("Configuration requires `%s', but binary is not installed properly (SUID bit not set).  Option disabled.\n"),
-                 "gnunet-nat-client"); 
-    }
+  if (GNUNET_OK !=
+      GNUNET_CONFIGURATION_get_value_number (env->cfg,
+                                             "transport-tcp",
+                                             "MAX_CONNECTIONS",
+                                             &max_connections))
+    max_connections = 128;
   
-  external_address = NULL;
-  if (GNUNET_OK ==
-      GNUNET_CONFIGURATION_have_value (env->cfg,
-                                      "transport-tcp",
-                                      "EXTERNAL_ADDRESS"))
-    {
-      (void) GNUNET_CONFIGURATION_get_value_string (env->cfg,
-                                                   "transport-tcp",
-                                                   "EXTERNAL_ADDRESS",
-                                                   &external_address);
-    }
-
-  if ( (external_address != NULL) && 
-       (inet_pton(AF_INET, external_address, &in_addr.sin_addr) != 1) ) 
-    {
-      GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING,
-                      "tcp",
-                      _("Malformed %s `%s' given in configuration!\n"), 
-                      "EXTERNAL_ADDRESS",
-                      external_address);
-      return NULL;   
-    }
-
-  internal_address = NULL;
-  if (GNUNET_OK ==
-      GNUNET_CONFIGURATION_have_value (env->cfg,
-                                      "transport-tcp",
-                                      "INTERNAL_ADDRESS"))
-    {
-      (void) GNUNET_CONFIGURATION_get_value_string (env->cfg,
-                                                   "transport-tcp",
-                                                   "INTERNAL_ADDRESS",
-                                                   &internal_address);
-    }
-
-  if ( (internal_address != NULL) && 
-       (inet_pton(AF_INET, internal_address, &in_addr.sin_addr) != 1) )
-    {
-      GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING,
-                      "tcp",
-                      _("Malformed %s `%s' given in configuration!\n"), 
-                      "INTERNAL_ADDRESS",
-                      internal_address);      
-      GNUNET_free_non_null(internal_address);
-      GNUNET_free_non_null(external_address);
-      return NULL;
-    }
-
   aport = 0;
   if ( (GNUNET_OK !=
        GNUNET_CONFIGURATION_get_value_number (env->cfg,
@@ -2713,19 +2050,15 @@ libgnunet_plugin_transport_tcp_init (void *cls)
                       "tcp",
                        _("Require valid port number for service `%s' in configuration!\n"),
                        "transport-tcp");
-      GNUNET_free_non_null(external_address);
-      GNUNET_free_non_null(internal_address);
       return NULL;
-    }
-
+    } 
   if (aport == 0)
     aport = bport;
   if (bport == 0)
     aport = 0;
-
   if (bport != 0)
     {
-      service = GNUNET_SERVICE_start ("transport-tcp", env->cfg);
+      service = GNUNET_SERVICE_start ("transport-tcp", env->cfg);      
       if (service == NULL)
        {
          GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING,
@@ -2737,18 +2070,49 @@ libgnunet_plugin_transport_tcp_init (void *cls)
   else
     service = NULL;
 
+
+
   plugin = GNUNET_malloc (sizeof (struct Plugin));
+  plugin->max_connections = max_connections;
   plugin->open_port = bport;
   plugin->adv_port = aport;
-  plugin->external_address = external_address;
-  plugin->internal_address = internal_address;
-  plugin->behind_nat = behind_nat;
-  plugin->allow_nat = allow_nat;
-  plugin->allow_upnp = GNUNET_CONFIGURATION_get_value_yesno (env->cfg,
-                                                            "transport-tcp",
-                                                            "ENABLE_UPNP");
   plugin->env = env;
   plugin->lsock = NULL;
+  if ( (service != NULL) &&
+       (GNUNET_SYSERR !=
+       (ret = GNUNET_SERVICE_get_server_addresses ("transport-tcp",
+                                                   env->cfg,
+                                                   &addrs,
+                                                   &addrlens))) )
+    {
+      plugin->nat = GNUNET_NAT_register (env->cfg,
+                                        GNUNET_YES,
+                                        aport,
+                                        (unsigned int) ret,
+                                        (const struct sockaddr **) addrs,
+                                        addrlens,
+                                        &tcp_nat_port_map_callback,
+                                        &try_connection_reversal,
+                                        plugin);
+      while (ret > 0)
+      {
+        ret--;
+        GNUNET_assert (addrs[ret] != NULL);
+       GNUNET_free (addrs[ret]);
+      }
+      GNUNET_free_non_null (addrs);
+      GNUNET_free_non_null (addrlens);
+    }
+  else
+    {
+      plugin->nat = GNUNET_NAT_register (env->cfg,
+                                        GNUNET_YES,
+                                        0,
+                                        0, NULL, NULL,
+                                        NULL,
+                                        &try_connection_reversal,
+                                        plugin);
+    }
   api = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PluginFunctions));
   api->cls = plugin;
   api->send = &tcp_plugin_send;
@@ -2774,12 +2138,13 @@ libgnunet_plugin_transport_tcp_init (void *cls)
                           _("Failed to find option %s in section %s!\n"),
                           "TIMEOUT",
                           "transport-tcp");
-         GNUNET_free_non_null(external_address);
-         GNUNET_free_non_null(internal_address);
+         if (plugin->nat != NULL)
+           GNUNET_NAT_unregister (plugin->nat);
+         GNUNET_free (plugin);
          GNUNET_free (api);
          return NULL;
        }
-      plugin->server = GNUNET_SERVER_create_with_sockets (NULL, NULL, NULL,
+      plugin->server = GNUNET_SERVER_create_with_sockets (&plugin_tcp_access_check, plugin, NULL,
                                                          idle_timeout, GNUNET_YES);
     }
   plugin->handlers = GNUNET_malloc (sizeof (my_handlers));
@@ -2792,32 +2157,7 @@ libgnunet_plugin_transport_tcp_init (void *cls)
   GNUNET_SERVER_disconnect_notify (plugin->server,
                                   &disconnect_notify,
                                   plugin);    
-  GNUNET_OS_network_interfaces_list (&process_interfaces, plugin);
-
-  if ( (plugin->behind_nat == GNUNET_YES) &&
-       (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);
-      if (service != NULL)
-       GNUNET_SERVICE_stop (service);
-      else
-       GNUNET_SERVER_destroy (plugin->server);
-      GNUNET_free (api);
-      return NULL;
-    }
-
-  if (allow_nat == GNUNET_YES)
-    {
-      plugin->nat_wait_conns = GNUNET_CONTAINER_multihashmap_create(16);
-      GNUNET_assert (plugin->nat_wait_conns != NULL);
-    }
-
+  plugin->nat_wait_conns = GNUNET_CONTAINER_multihashmap_create(16);
   if (bport != 0)
     GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, 
                     "tcp",
@@ -2832,51 +2172,6 @@ libgnunet_plugin_transport_tcp_init (void *cls)
                     "tcp",
                      _("TCP transport advertises itself as being on port %llu\n"),
                      aport);
-
-  if (GNUNET_YES == GNUNET_CONFIGURATION_get_value_string (env->cfg,
-                                                          "transport-tcp", 
-                                                          "BINDTO", 
-                                                          &plugin->bind_address))
-    {
-      GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, 
-                      "tcp",
-                      _("Binding TCP plugin to specific address: `%s'\n"), 
-                      plugin->bind_address);
-    }
-
-  plugin->hostname_dns = GNUNET_RESOLVER_hostname_resolve (env->cfg,
-                                                           AF_UNSPEC,
-                                                           HOSTNAME_RESOLVE_TIMEOUT,
-                                                           &process_hostname_ips,
-                                                           plugin);
-
-  if ( (plugin->external_address != NULL) && 
-       (inet_pton(AF_INET,
-                 plugin->external_address, 
-                 &t4.ipv4_addr) == 1) )
-    {
-      if (plugin->behind_nat == GNUNET_YES) 
-       {
-         GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, 
-                          "tcp",
-                          "Notifying transport of address %s:0\n", 
-                          plugin->external_address);
-         t4.t_port = htons(0);
-       }
-      else
-       {
-         t4.t_port = htons(plugin->adv_port);
-         GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, 
-                          "tcp",
-                          "Notifying transport of address %s:%d\n",
-                          plugin->external_address, 
-                          plugin->adv_port);
-       }
-      add_to_address_list (plugin, &t4.ipv4_addr, sizeof (struct in_addr));
-      plugin->env->notify_address (plugin->env->cls,
-                                  "tcp",
-                                  &t4, sizeof(t4), GNUNET_TIME_UNIT_FOREVER_REL);
-    }
   return api;
 }
 
@@ -2890,31 +2185,17 @@ libgnunet_plugin_transport_tcp_done (void *cls)
   struct GNUNET_TRANSPORT_PluginFunctions *api = cls;
   struct Plugin *plugin = api->cls;
   struct Session *session;
-  struct LocalAddrList *lal;
   struct TCPProbeContext *tcp_probe;
 
   while (NULL != (session = plugin->sessions))
     disconnect_session (session);
-  if (NULL != plugin->hostname_dns)
-    {
-      GNUNET_RESOLVER_request_cancel (plugin->hostname_dns);
-      plugin->hostname_dns = NULL;
-    }
   if (plugin->service != NULL)
     GNUNET_SERVICE_stop (plugin->service);
   else
     GNUNET_SERVER_destroy (plugin->server);
   GNUNET_free (plugin->handlers);
-  while (NULL != (lal = plugin->lal_head))
-    {
-      GNUNET_CONTAINER_DLL_remove (plugin->lal_head,
-                                  plugin->lal_tail,
-                                  lal);
-      if (lal->nat != NULL)
-       GNUNET_NAT_unregister (lal->nat);
-      GNUNET_free_non_null (lal->external_nat_address);
-      GNUNET_free (lal);
-    }
+  if (plugin->nat != NULL)
+    GNUNET_NAT_unregister (plugin->nat);
   while (NULL != (tcp_probe = plugin->probe_head))
     {
       GNUNET_CONTAINER_DLL_remove (plugin->probe_head,
@@ -2923,16 +2204,7 @@ libgnunet_plugin_transport_tcp_done (void *cls)
       GNUNET_CONNECTION_destroy (tcp_probe->sock, GNUNET_NO);
       GNUNET_free (tcp_probe);
     }
-
-  if (plugin->behind_nat == GNUNET_YES)
-    {
-      if (0 != GNUNET_OS_process_kill (plugin->server_proc, SIGTERM))
-        GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
-      GNUNET_OS_process_wait (plugin->server_proc);
-      GNUNET_OS_process_close (plugin->server_proc);
-      plugin->server_proc = NULL;
-    }
-  GNUNET_free_non_null(plugin->bind_address);
+  GNUNET_CONTAINER_multihashmap_destroy (plugin->nat_wait_conns);
   GNUNET_free (plugin);
   GNUNET_free (api);
   return NULL;