diff options
author | Christian Grothoff <christian@grothoff.org> | 2017-01-05 13:49:57 +0100 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2017-01-05 13:49:57 +0100 |
commit | 89c7072fdc236c92fd7c252fb0efdc97fcb1367e (patch) | |
tree | f338f17592d5d667beddfc928ca1c9940ffe66fb /src/nat | |
parent | c605302fdaa911911e33c666ce6bad6a24c25064 (diff) | |
download | gnunet-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.c | 238 |
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; | |||
327 | static struct GNUNET_TIME_Relative stun_stale_timeout; | 360 | static 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 | */ | ||
365 | static struct GNUNET_TIME_Relative dyndns_frequency; | ||
366 | |||
367 | /** | ||
330 | * Handle to our current configuration. | 368 | * Handle to our current configuration. |
331 | */ | 369 | */ |
332 | static const struct GNUNET_CONFIGURATION_Handle *cfg; | 370 | static 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 | */ | ||
1365 | static void | ||
1366 | dyndns_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 | */ | ||
1378 | static void | ||
1379 | process_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 | */ | ||
1414 | static void | ||
1415 | dyndns_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 | */ | ||
1439 | static void | ||
1440 | lookup_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 | } |