aboutsummaryrefslogtreecommitdiff
path: root/src/nat
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2017-01-05 13:49:57 +0100
committerChristian Grothoff <christian@grothoff.org>2017-01-05 13:49:57 +0100
commit89c7072fdc236c92fd7c252fb0efdc97fcb1367e (patch)
treef338f17592d5d667beddfc928ca1c9940ffe66fb /src/nat
parentc605302fdaa911911e33c666ce6bad6a24c25064 (diff)
downloadgnunet-89c7072fdc236c92fd7c252fb0efdc97fcb1367e.tar.gz
gnunet-89c7072fdc236c92fd7c252fb0efdc97fcb1367e.zip
work towards supporting manual hole punching in new NAT service
Diffstat (limited to 'src/nat')
-rw-r--r--src/nat/gnunet-service-nat.c238
1 files changed, 235 insertions, 3 deletions
diff --git a/src/nat/gnunet-service-nat.c b/src/nat/gnunet-service-nat.c
index e29f37108..5037f52d3 100644
--- a/src/nat/gnunet-service-nat.c
+++ b/src/nat/gnunet-service-nat.c
@@ -44,6 +44,7 @@
44#include "gnunet_protocols.h" 44#include "gnunet_protocols.h"
45#include "gnunet_signatures.h" 45#include "gnunet_signatures.h"
46#include "gnunet_statistics_service.h" 46#include "gnunet_statistics_service.h"
47#include "gnunet_resolver_service.h"
47#include "gnunet_nat_service.h" 48#include "gnunet_nat_service.h"
48#include "gnunet-service-nat_stun.h" 49#include "gnunet-service-nat_stun.h"
49#include "gnunet-service-nat_mini.h" 50#include "gnunet-service-nat_mini.h"
@@ -81,6 +82,11 @@
81 */ 82 */
82#define EXTERN_IP_RETRY_SUCCESS GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5) 83#define EXTERN_IP_RETRY_SUCCESS GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5)
83 84
85/**
86 * How often do we scan for changes in how our external (dyndns) hostname resolves?
87 */
88#define DYNDNS_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 7)
89
84 90
85/** 91/**
86 * Information we track per client address. 92 * Information we track per client address.
@@ -142,6 +148,33 @@ struct ClientHandle
142 * have a hole punched). 148 * have a hole punched).
143 */ 149 */
144 char *hole_external; 150 char *hole_external;
151
152 /**
153 * Task for periodically re-running the @e ext_dns DNS lookup.
154 */
155 struct GNUNET_SCHEDULER_Task *ext_dns_task;
156
157 /**
158 * Handle for (DYN)DNS lookup of our external IP as given in
159 * @e hole_external.
160 */
161 struct GNUNET_RESOLVER_RequestHandle *ext_dns;
162
163 /**
164 * External IP address as given in @e hole_external.
165 */
166 struct sockaddr_storage ext_addr;
167
168 /**
169 * Do we currently have a valid @e ext_addr which we told the
170 * client about?
171 */
172 int ext_addr_set;
173
174 /**
175 * Port number we found in @e hole_external.
176 */
177 uint16_t ext_dns_port;
145 178
146 /** 179 /**
147 * What does this client care about? 180 * What does this client care about?
@@ -327,6 +360,11 @@ static struct AutoconfigContext *ac_tail;
327static struct GNUNET_TIME_Relative stun_stale_timeout; 360static struct GNUNET_TIME_Relative stun_stale_timeout;
328 361
329/** 362/**
363 * How often do we scan for changes in how our external (dyndns) hostname resolves?
364 */
365static struct GNUNET_TIME_Relative dyndns_frequency;
366
367/**
330 * Handle to our current configuration. 368 * Handle to our current configuration.
331 */ 369 */
332static const struct GNUNET_CONFIGURATION_Handle *cfg; 370static const struct GNUNET_CONFIGURATION_Handle *cfg;
@@ -765,7 +803,7 @@ check_notify_client (struct LocalAddressList *delta,
765 const struct sockaddr_in *c4; 803 const struct sockaddr_in *c4;
766 804
767 if (AF_INET != ch->caddrs[i].ss.ss_family) 805 if (AF_INET != ch->caddrs[i].ss.ss_family)
768 return; /* IPv4 not relevant */ 806 continue; /* IPv4 not relevant */
769 c4 = (const struct sockaddr_in *) &ch->caddrs[i].ss; 807 c4 = (const struct sockaddr_in *) &ch->caddrs[i].ss;
770 if ( match_ipv4 ("127.0.0.1", &c4->sin_addr, 8) && 808 if ( match_ipv4 ("127.0.0.1", &c4->sin_addr, 8) &&
771 (0 != c4->sin_addr.s_addr) && 809 (0 != c4->sin_addr.s_addr) &&
@@ -808,7 +846,7 @@ check_notify_client (struct LocalAddressList *delta,
808 const struct sockaddr_in6 *c6; 846 const struct sockaddr_in6 *c6;
809 847
810 if (AF_INET6 != ch->caddrs[i].ss.ss_family) 848 if (AF_INET6 != ch->caddrs[i].ss.ss_family)
811 return; /* IPv4 not relevant */ 849 continue; /* IPv4 not relevant */
812 c6 = (const struct sockaddr_in6 *) &ch->caddrs[i].ss; 850 c6 = (const struct sockaddr_in6 *) &ch->caddrs[i].ss;
813 if ( match_ipv6 ("::1", &c6->sin6_addr, 128) && 851 if ( match_ipv6 ("::1", &c6->sin6_addr, 128) &&
814 (0 != memcmp (&c6->sin6_addr, 852 (0 != memcmp (&c6->sin6_addr,
@@ -1317,6 +1355,182 @@ upnp_addr_change_cb (void *cls,
1317 1355
1318 1356
1319/** 1357/**
1358 * Resolve the `hole_external` name to figure out our
1359 * external address from a manually punched hole. The
1360 * port number has already been parsed, this task is
1361 * responsible for periodically doing a DNS lookup.
1362 *
1363 * @param ch client handle to act upon
1364 */
1365static void
1366dyndns_lookup (void *cls);
1367
1368
1369/**
1370 * Our (external) hostname was resolved. Update lists of
1371 * current external IPs (note that DNS may return multiple
1372 * addresses!) and notify client accordingly.
1373 *
1374 * @param cls the `struct ClientHandle`
1375 * @param addr NULL on error, otherwise result of DNS lookup
1376 * @param addrlen number of bytes in @a addr
1377 */
1378static void
1379process_external_ip (void *cls,
1380 const struct sockaddr *addr,
1381 socklen_t addrlen)
1382{
1383 struct ClientHandle *ch = cls;
1384
1385 if (NULL == addr)
1386 {
1387 ch->ext_dns = NULL;
1388 ch->ext_dns_task
1389 = GNUNET_SCHEDULER_add_delayed (dyndns_frequency,
1390 &dyndns_lookup,
1391 ch);
1392 /* Current iteration is over, remove 'old' IPs now */
1393 // FIXME: remove IPs we did NOT find!
1394 GNUNET_break (0);
1395 return;
1396 }
1397 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1398 "Got IP `%s' for external address `%s'\n",
1399 GNUNET_a2s (addr,
1400 addrlen),
1401 ch->hole_external);
1402 // FIXME: notify client, and remember IP for later removal!
1403}
1404
1405
1406/**
1407 * Resolve the `hole_external` name to figure out our
1408 * external address from a manually punched hole. The
1409 * port number has already been parsed, this task is
1410 * responsible for periodically doing a DNS lookup.
1411 *
1412 * @param ch client handle to act upon
1413 */
1414static void
1415dyndns_lookup (void *cls)
1416{
1417 struct ClientHandle *ch = cls;
1418
1419 ch->ext_dns_task = NULL;
1420 ch->ext_dns = GNUNET_RESOLVER_ip_get (ch->hole_external,
1421 AF_UNSPEC,
1422 GNUNET_TIME_UNIT_MINUTES,
1423 &process_external_ip,
1424 ch);
1425}
1426
1427
1428/**
1429 * Resolve the `hole_external` name to figure out our
1430 * external address from a manually punched hole. The
1431 * given name may be "AUTO" in which case we should use
1432 * the IP address(es) we have from upnpc or other methods.
1433 * The name can also be an IP address, in which case we
1434 * do not need to do DNS resolution. Finally, we also
1435 * need to parse the port number.
1436 *
1437 * @param ch client handle to act upon
1438 */
1439static void
1440lookup_hole_external (struct ClientHandle *ch)
1441{
1442 char *port;
1443 unsigned int pnum;
1444 struct sockaddr_in *s4;
1445 struct LocalAddressList lal;
1446
1447 port = strrchr (ch->hole_external, ':');
1448 if (NULL == port)
1449 {
1450 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1451 _("Malformed punched hole specification `%s' (lacks port)\n"),
1452 ch->hole_external);
1453 return;
1454 }
1455 if ( (1 != sscanf (port + 1,
1456 "%u",
1457 &pnum)) ||
1458 (pnum > 65535) )
1459 {
1460 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1461 _("Invalid port number in punched hole specification `%s' (lacks port)\n"),
1462 port + 1);
1463 return;
1464 }
1465 ch->ext_dns_port = (uint16_t) pnum;
1466 *port = '\0';
1467 if ('[' == *ch->hole_external)
1468 {
1469 struct sockaddr_in6 *s6 = (struct sockaddr_in6 *) &ch->ext_addr;
1470
1471 memset (s6, 0, sizeof (*s6));
1472 s6->sin6_family = AF_INET6;
1473 if (']' != (ch->hole_external[strlen(ch->hole_external)-1]))
1474 {
1475 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1476 _("Malformed punched hole specification `%s' (lacks `]')\n"),
1477 ch->hole_external);
1478 return;
1479 }
1480 ch->hole_external[strlen(ch->hole_external)-1] = '\0';
1481 if (1 != inet_pton (AF_INET6,
1482 ch->hole_external + 1,
1483 &s6->sin6_addr))
1484 {
1485 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1486 _("Malformed punched hole specification `%s' (IPv6 address invalid)"),
1487 ch->hole_external + 1);
1488 return;
1489 }
1490 s6->sin6_port = htons (ch->ext_dns_port);
1491 memset (&lal, 0, sizeof (lal));
1492 GNUNET_memcpy (&lal.addr, s6, sizeof (*s6));
1493 lal.af = AF_INET6;
1494 lal.ac = GNUNET_NAT_AC_GLOBAL | GNUNET_NAT_AC_MANUAL;
1495 check_notify_client (&lal,
1496 ch,
1497 GNUNET_YES);
1498 ch->ext_addr_set = GNUNET_YES;
1499 return;
1500 }
1501 s4 = (struct sockaddr_in *) &ch->ext_addr;
1502 memset (s4, 0, sizeof (*s4));
1503 s4->sin_family = AF_INET;
1504 if (1 == inet_pton (AF_INET,
1505 ch->hole_external,
1506 &s4->sin_addr))
1507 {
1508 s4->sin_port = htons (ch->ext_dns_port);
1509 memset (&lal, 0, sizeof (lal));
1510 GNUNET_memcpy (&lal.addr, s4, sizeof (*s4));
1511 lal.af = AF_INET;
1512 lal.ac = GNUNET_NAT_AC_GLOBAL | GNUNET_NAT_AC_MANUAL;
1513 check_notify_client (&lal,
1514 ch,
1515 GNUNET_YES);
1516 ch->ext_addr_set = GNUNET_YES;
1517 return;
1518 }
1519 if (0 == strcasecmp (ch->hole_external,
1520 "AUTO"))
1521 {
1522 // FIXME: use `external-ip` address(es)!
1523 GNUNET_break (0); // not implemented!
1524 return;
1525 }
1526 /* got a DNS name, trigger lookup! */
1527 ch->ext_dns_task
1528 = GNUNET_SCHEDULER_add_now (&dyndns_lookup,
1529 ch);
1530}
1531
1532
1533/**
1320 * Handler for #GNUNET_MESSAGE_TYPE_NAT_REGISTER message from client. 1534 * Handler for #GNUNET_MESSAGE_TYPE_NAT_REGISTER message from client.
1321 * We remember the client for updates upon future NAT events. 1535 * We remember the client for updates upon future NAT events.
1322 * 1536 *
@@ -1422,7 +1636,9 @@ handle_register (void *cls,
1422 ch->hole_external 1636 ch->hole_external
1423 = GNUNET_strndup (off, 1637 = GNUNET_strndup (off,
1424 ntohs (message->hole_external_len)); 1638 ntohs (message->hole_external_len));
1425 1639 if (0 != ntohs (message->hole_external_len))
1640 lookup_hole_external (ch);
1641
1426 /* Actually send IP address list to client */ 1642 /* Actually send IP address list to client */
1427 for (struct LocalAddressList *lal = lal_head; 1643 for (struct LocalAddressList *lal = lal_head;
1428 NULL != lal; 1644 NULL != lal;
@@ -2115,6 +2331,12 @@ run (void *cls,
2115 enable_upnp = GNUNET_SYSERR; 2331 enable_upnp = GNUNET_SYSERR;
2116 } 2332 }
2117 } 2333 }
2334 if (GNUNET_OK !=
2335 GNUNET_CONFIGURATION_get_value_time (cfg,
2336 "nat",
2337 "DYNDNS_FREQUENCY",
2338 &dyndns_frequency))
2339 dyndns_frequency = DYNDNS_FREQUENCY;
2118 2340
2119 GNUNET_SCHEDULER_add_shutdown (&shutdown_task, 2341 GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
2120 NULL); 2342 NULL);
@@ -2176,6 +2398,16 @@ client_disconnect_cb (void *cls,
2176 } 2398 }
2177 } 2399 }
2178 GNUNET_free_non_null (ch->caddrs); 2400 GNUNET_free_non_null (ch->caddrs);
2401 if (NULL != ch->ext_dns_task)
2402 {
2403 GNUNET_SCHEDULER_cancel (ch->ext_dns_task);
2404 ch->ext_dns_task = NULL;
2405 }
2406 if (NULL != ch->ext_dns)
2407 {
2408 GNUNET_RESOLVER_request_cancel (ch->ext_dns);
2409 ch->ext_dns = NULL;
2410 }
2179 GNUNET_free (ch->hole_external); 2411 GNUNET_free (ch->hole_external);
2180 GNUNET_free (ch); 2412 GNUNET_free (ch);
2181} 2413}