summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2011-07-08 11:44:52 +0000
committerChristian Grothoff <christian@grothoff.org>2011-07-08 11:44:52 +0000
commite43aa53ca452e5c8a5be19be6212f0618e06a895 (patch)
treed3f0255e1a1475dd970a10821b89a368adec3b7f
parentceefc6de0ed40c33a644c571422d0b558aa851ca (diff)
integrating miniupnp with nat library
-rw-r--r--TODO2
-rw-r--r--contrib/defaults.conf4
-rw-r--r--src/nat/nat.c146
3 files changed, 145 insertions, 7 deletions
diff --git a/TODO b/TODO
index 2e41bbcc5..8a101f43d 100644
--- a/TODO
+++ b/TODO
@@ -8,8 +8,6 @@
0.9.0pre4:
* NAT library: [CG/MW]
- - UPnP support
- - testcase
- more testing
* Transport:
- UDP fragmentation [MW]
diff --git a/contrib/defaults.conf b/contrib/defaults.conf
index 4a9b44dc8..f6b0e0c87 100644
--- a/contrib/defaults.conf
+++ b/contrib/defaults.conf
@@ -28,7 +28,7 @@ BEHIND_NAT = NO
# Is the NAT hole-punched?
PUNCHED_NAT = NO
-# Disable UPNP by default until it gets cleaner!
+# Enable UPNP by default?
ENABLE_UPNP = NO
# Use addresses from the local network interfaces (inluding loopback, but also others)
@@ -69,7 +69,7 @@ IFC_SCAN_FREQUENCY = 3000000
DYNDNS_FREQUENCY = 140000
[gnunet-nat-server]
-HOSTNAME = nat.gnunet.org
+HOSTNAME = gnunet.org
PORT = 5724
[transport-tcp]
diff --git a/src/nat/nat.c b/src/nat/nat.c
index 2f38998e5..9d7d3ee72 100644
--- a/src/nat/nat.c
+++ b/src/nat/nat.c
@@ -86,7 +86,10 @@ enum LocalAddressSource
*/
LAL_BINDTO_ADDRESS,
- /* TODO: add UPnP, etc. */
+ /**
+ * Addresses from UPnP or PMP
+ */
+ LAL_UPNP,
/**
* End of the list.
@@ -128,6 +131,35 @@ struct LocalAddressList
/**
+ * Handle for miniupnp-based NAT traversal actions.
+ */
+struct MiniList
+{
+
+ /**
+ * Doubly-linked list.
+ */
+ struct MiniList *next;
+
+ /**
+ * Doubly-linked list.
+ */
+ struct MiniList *prev;
+
+ /**
+ * Handle to mini-action.
+ */
+ struct GNUNET_NAT_MiniHandle *mini;
+
+ /**
+ * Local port number that was mapped.
+ */
+ uint16_t port;
+
+};
+
+
+/**
* Handle for active NAT registrations.
*/
struct GNUNET_NAT_Handle
@@ -246,6 +278,18 @@ struct GNUNET_NAT_Handle
socklen_t *local_addrlens;
/**
+ * List of handles for UPnP-traversal, one per local port (if
+ * not IPv6-only).
+ */
+ struct MiniList *mini_head;
+
+ /**
+ * List of handles for UPnP-traversal, one per local port (if
+ * not IPv6-only).
+ */
+ struct MiniList *mini_tail;
+
+ /**
* Number of entries in 'local_addrs' array.
*/
unsigned int num_local_addrs;
@@ -924,6 +968,89 @@ resolve_dns (void *cls,
/**
+ * Add or remove UPnP-mapped addresses.
+ *
+ * @param cls the GNUNET_NAT_Handle
+ * @param add_remove GNUNET_YES to mean the new public IP address, GNUNET_NO to mean
+ * the previous (now invalid) one
+ * @param addr either the previous or the new public IP address
+ * @param addrlen actual lenght of the address
+ */
+static void
+upnp_add (void *cls,
+ int add_remove,
+ const struct sockaddr *addr,
+ socklen_t addrlen)
+{
+ struct GNUNET_NAT_Handle *h = cls;
+ struct LocalAddressList *pos;
+ struct LocalAddressList *next;
+
+ if (GNUNET_YES == add_remove)
+ {
+ add_to_address_list (h,
+ LAL_UPNP,
+ addr, addrlen);
+ return;
+ }
+ /* remove address */
+ next = h->lal_head;
+ while (NULL != (pos = next))
+ {
+ next = pos->next;
+ if ( (pos->source != LAL_UPNP) ||
+ (pos->addrlen != addrlen) ||
+ (0 != memcmp (&pos[1],
+ addr,
+ addrlen)) )
+ continue;
+ GNUNET_CONTAINER_DLL_remove (h->lal_head,
+ h->lal_tail,
+ pos);
+ if (NULL != h->address_callback)
+ h->address_callback (h->callback_cls,
+ GNUNET_NO,
+ (const struct sockaddr* ) &pos[1],
+ pos->addrlen);
+ GNUNET_free (pos);
+ return; /* only remove once */
+ }
+ /* asked to remove address that does not exist */
+ GNUNET_break (0);
+}
+
+
+/**
+ * Try to add a port mapping using UPnP.
+ *
+ * @param h overall NAT handle
+ * @param port port to map with UPnP
+ */
+static void
+add_minis (struct GNUNET_NAT_Handle *h,
+ uint16_t port)
+{
+ struct MiniList *ml;
+
+ ml = h->mini_head;
+ while (NULL != ml)
+ {
+ if (port == ml->port)
+ return; /* already got this port */
+ ml = ml->next;
+ }
+ ml = GNUNET_malloc (sizeof (struct MiniList));
+ ml->port = port;
+ ml->mini = GNUNET_NAT_mini_map_start (port,
+ h->is_tcp,
+ &upnp_add, h);
+ GNUNET_CONTAINER_DLL_insert (h->mini_head,
+ h->mini_tail,
+ ml);
+}
+
+
+/**
* Task to add addresses from original bind to set of valid addrs.
*
* @param cls the NAT handle
@@ -931,12 +1058,13 @@ resolve_dns (void *cls,
*/
static void
add_from_bind (void *cls,
- const struct GNUNET_SCHEDULER_TaskContext *tc)
+ const struct GNUNET_SCHEDULER_TaskContext *tc)
{
static struct in6_addr any = IN6ADDR_ANY_INIT;
struct GNUNET_NAT_Handle *h = cls;
unsigned int i;
struct sockaddr *sa;
+ const struct sockaddr_in *v4;
h->bind_task = GNUNET_SCHEDULER_NO_TASK;
for (i=0;i<h->num_local_addrs;i++)
@@ -950,8 +1078,11 @@ add_from_bind (void *cls,
GNUNET_break (0);
break;
}
- if (0 != ((const struct sockaddr_in*) sa)->sin_addr.s_addr)
+ v4 = (const struct sockaddr_in*) sa;
+ if (0 != v4->sin_addr.s_addr)
add_to_address_list (h, LAL_BINDTO_ADDRESS, sa, sizeof (struct sockaddr_in));
+ if (h->enable_upnp)
+ add_minis (h, ntohs (v4->sin_port));
break;
case AF_INET6:
if (sizeof (struct sockaddr_in6) != h->local_addrlens[i])
@@ -1178,7 +1309,16 @@ GNUNET_NAT_unregister (struct GNUNET_NAT_Handle *h)
{
unsigned int i;
struct LocalAddressList *lal;
+ struct MiniList *ml;
+ while (NULL != (ml = h->mini_head))
+ {
+ GNUNET_CONTAINER_DLL_remove (h->mini_head,
+ h->mini_tail,
+ ml);
+ GNUNET_NAT_mini_map_stop (ml->mini);
+ GNUNET_free (ml);
+ }
if (h->ext_dns != NULL)
{
GNUNET_RESOLVER_request_cancel (h->ext_dns);