diff options
-rw-r--r-- | src/nat/gnunet-service-nat.c | 225 |
1 files changed, 155 insertions, 70 deletions
diff --git a/src/nat/gnunet-service-nat.c b/src/nat/gnunet-service-nat.c index 27e16820f..ffc0f6742 100644 --- a/src/nat/gnunet-service-nat.c +++ b/src/nat/gnunet-service-nat.c | |||
@@ -29,15 +29,17 @@ | |||
29 | * | 29 | * |
30 | * TODO: | 30 | * TODO: |
31 | * - test and document (!) ICMP based NAT traversal | 31 | * - test and document (!) ICMP based NAT traversal |
32 | * - implement manual hole punching support (incl. DNS | 32 | * - implement NEW logic for external IP detection; |
33 | * lookup for DynDNS setups!) | 33 | * => introduce higher-level abstraction for external-IPs |
34 | * for subsystems to hook into! | ||
35 | * - implement manual hole punching support (AUTO missing) | ||
36 | * - test manual hole punching support | ||
34 | * - implement "more" autoconfig: | 37 | * - implement "more" autoconfig: |
35 | * + re-work gnunet-nat-server & integrate! | ||
36 | * + consider moving autoconfig-logic into separate service! | 38 | * + consider moving autoconfig-logic into separate service! |
39 | * + re-work gnunet-nat-server & integrate! | ||
37 | * + test manually punched NAT (how?) | 40 | * + test manually punched NAT (how?) |
38 | * - implement & test STUN processing to classify NAT; | 41 | * - implement & test STUN processing to classify NAT; |
39 | * basically, open port & try different methods. | 42 | * basically, open port & try different methods. |
40 | * - implement NEW logic for external IP detection | ||
41 | */ | 43 | */ |
42 | #include "platform.h" | 44 | #include "platform.h" |
43 | #include <math.h> | 45 | #include <math.h> |
@@ -110,6 +112,53 @@ struct ClientAddress | |||
110 | 112 | ||
111 | 113 | ||
112 | /** | 114 | /** |
115 | * List of local addresses this system has. | ||
116 | */ | ||
117 | struct LocalAddressList | ||
118 | { | ||
119 | /** | ||
120 | * This is a linked list. | ||
121 | */ | ||
122 | struct LocalAddressList *next; | ||
123 | |||
124 | /** | ||
125 | * Previous entry. | ||
126 | */ | ||
127 | struct LocalAddressList *prev; | ||
128 | |||
129 | /** | ||
130 | * Context for a gnunet-helper-nat-server used to listen | ||
131 | * for ICMP messages to this client for connection reversal. | ||
132 | */ | ||
133 | struct HelperContext *hc; | ||
134 | |||
135 | /** | ||
136 | * The address itself (i.e. `struct sockaddr_in` or `struct | ||
137 | * sockaddr_in6`, in the respective byte order). | ||
138 | */ | ||
139 | struct sockaddr_storage addr; | ||
140 | |||
141 | /** | ||
142 | * Address family. (FIXME: redundant, addr.ss_family! Remove!?) | ||
143 | */ | ||
144 | int af; | ||
145 | |||
146 | /** | ||
147 | * #GNUNET_YES if we saw this one in the previous iteration, | ||
148 | * but not in the current iteration and thus might need to | ||
149 | * remove it at the end. | ||
150 | */ | ||
151 | int old; | ||
152 | |||
153 | /** | ||
154 | * What type of address is this? | ||
155 | */ | ||
156 | enum GNUNET_NAT_AddressClass ac; | ||
157 | |||
158 | }; | ||
159 | |||
160 | |||
161 | /** | ||
113 | * Internal data structure we track for each of our clients. | 162 | * Internal data structure we track for each of our clients. |
114 | */ | 163 | */ |
115 | struct ClientHandle | 164 | struct ClientHandle |
@@ -162,15 +211,14 @@ struct ClientHandle | |||
162 | struct GNUNET_RESOLVER_RequestHandle *ext_dns; | 211 | struct GNUNET_RESOLVER_RequestHandle *ext_dns; |
163 | 212 | ||
164 | /** | 213 | /** |
165 | * External IP address as given in @e hole_external. | 214 | * DLL of external IP addresses as given in @e hole_external. |
166 | */ | 215 | */ |
167 | struct sockaddr_storage ext_addr; | 216 | struct LocalAddressList *ext_addr_head; |
168 | 217 | ||
169 | /** | 218 | /** |
170 | * Do we currently have a valid @e ext_addr which we told the | 219 | * DLL of external IP addresses as given in @e hole_external. |
171 | * client about? | ||
172 | */ | 220 | */ |
173 | int ext_addr_set; | 221 | struct LocalAddressList *ext_addr_tail; |
174 | 222 | ||
175 | /** | 223 | /** |
176 | * Port number we found in @e hole_external. | 224 | * Port number we found in @e hole_external. |
@@ -202,46 +250,6 @@ struct ClientHandle | |||
202 | 250 | ||
203 | 251 | ||
204 | /** | 252 | /** |
205 | * List of local addresses this system has. | ||
206 | */ | ||
207 | struct LocalAddressList | ||
208 | { | ||
209 | /** | ||
210 | * This is a linked list. | ||
211 | */ | ||
212 | struct LocalAddressList *next; | ||
213 | |||
214 | /** | ||
215 | * Previous entry. | ||
216 | */ | ||
217 | struct LocalAddressList *prev; | ||
218 | |||
219 | /** | ||
220 | * Context for a gnunet-helper-nat-server used to listen | ||
221 | * for ICMP messages to this client for connection reversal. | ||
222 | */ | ||
223 | struct HelperContext *hc; | ||
224 | |||
225 | /** | ||
226 | * The address itself (i.e. `struct sockaddr_in` or `struct | ||
227 | * sockaddr_in6`, in the respective byte order). | ||
228 | */ | ||
229 | struct sockaddr_storage addr; | ||
230 | |||
231 | /** | ||
232 | * Address family. | ||
233 | */ | ||
234 | int af; | ||
235 | |||
236 | /** | ||
237 | * What type of address is this? | ||
238 | */ | ||
239 | enum GNUNET_NAT_AddressClass ac; | ||
240 | |||
241 | }; | ||
242 | |||
243 | |||
244 | /** | ||
245 | * External IP address as given to us via some STUN server. | 253 | * External IP address as given to us via some STUN server. |
246 | */ | 254 | */ |
247 | struct StunExternalIP | 255 | struct StunExternalIP |
@@ -1382,17 +1390,35 @@ process_external_ip (void *cls, | |||
1382 | socklen_t addrlen) | 1390 | socklen_t addrlen) |
1383 | { | 1391 | { |
1384 | struct ClientHandle *ch = cls; | 1392 | struct ClientHandle *ch = cls; |
1393 | struct LocalAddressList *lal; | ||
1394 | struct sockaddr_storage ss; | ||
1395 | struct sockaddr_in *v4; | ||
1396 | struct sockaddr_in6 *v6; | ||
1385 | 1397 | ||
1386 | if (NULL == addr) | 1398 | if (NULL == addr) |
1387 | { | 1399 | { |
1400 | struct LocalAddressList *laln; | ||
1401 | |||
1388 | ch->ext_dns = NULL; | 1402 | ch->ext_dns = NULL; |
1389 | ch->ext_dns_task | 1403 | ch->ext_dns_task |
1390 | = GNUNET_SCHEDULER_add_delayed (dyndns_frequency, | 1404 | = GNUNET_SCHEDULER_add_delayed (dyndns_frequency, |
1391 | &dyndns_lookup, | 1405 | &dyndns_lookup, |
1392 | ch); | 1406 | ch); |
1393 | /* Current iteration is over, remove 'old' IPs now */ | 1407 | /* Current iteration is over, remove 'old' IPs now */ |
1394 | // FIXME: remove IPs we did NOT find! | 1408 | for (lal = ch->ext_addr_head; NULL != lal; lal = laln) |
1395 | GNUNET_break (0); | 1409 | { |
1410 | laln = lal->next; | ||
1411 | if (GNUNET_YES == lal->old) | ||
1412 | { | ||
1413 | GNUNET_CONTAINER_DLL_remove (ch->ext_addr_head, | ||
1414 | ch->ext_addr_tail, | ||
1415 | lal); | ||
1416 | check_notify_client (lal, | ||
1417 | ch, | ||
1418 | GNUNET_NO); | ||
1419 | GNUNET_free (lal); | ||
1420 | } | ||
1421 | } | ||
1396 | return; | 1422 | return; |
1397 | } | 1423 | } |
1398 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 1424 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
@@ -1400,7 +1426,50 @@ process_external_ip (void *cls, | |||
1400 | GNUNET_a2s (addr, | 1426 | GNUNET_a2s (addr, |
1401 | addrlen), | 1427 | addrlen), |
1402 | ch->hole_external); | 1428 | ch->hole_external); |
1403 | // FIXME: notify client, and remember IP for later removal! | 1429 | |
1430 | /* build sockaddr storage with port number */ | ||
1431 | memset (&ss, 0, sizeof (ss)); | ||
1432 | memcpy (&ss, addr, addrlen); | ||
1433 | switch (addr->sa_family) | ||
1434 | { | ||
1435 | case AF_INET: | ||
1436 | v4 = (struct sockaddr_in *) &ss; | ||
1437 | v4->sin_port = htons (ch->ext_dns_port); | ||
1438 | break; | ||
1439 | case AF_INET6: | ||
1440 | v6 = (struct sockaddr_in6 *) &ss; | ||
1441 | v6->sin6_port = htons (ch->ext_dns_port); | ||
1442 | break; | ||
1443 | default: | ||
1444 | GNUNET_break (0); | ||
1445 | return; | ||
1446 | } | ||
1447 | /* See if 'ss' matches any of our known addresses */ | ||
1448 | for (lal = ch->ext_addr_head; NULL != lal; lal = lal->next) | ||
1449 | { | ||
1450 | if (GNUNET_NO == lal->old) | ||
1451 | continue; /* already processed, skip */ | ||
1452 | if ( (addr->sa_family == lal->addr.ss_family) && | ||
1453 | (0 == memcmp (&ss, | ||
1454 | &lal->addr, | ||
1455 | addrlen)) ) | ||
1456 | { | ||
1457 | /* Address unchanged, remember so we do not remove */ | ||
1458 | lal->old = GNUNET_NO; | ||
1459 | return; /* done here */ | ||
1460 | } | ||
1461 | } | ||
1462 | /* notify client, and remember IP for later removal! */ | ||
1463 | lal = GNUNET_new (struct LocalAddressList); | ||
1464 | lal->addr = ss; | ||
1465 | lal->af = ss.ss_family; | ||
1466 | lal->ac = GNUNET_NAT_AC_GLOBAL | GNUNET_NAT_AC_MANUAL; | ||
1467 | GNUNET_CONTAINER_DLL_insert (ch->ext_addr_head, | ||
1468 | ch->ext_addr_tail, | ||
1469 | lal); | ||
1470 | check_notify_client (lal, | ||
1471 | ch, | ||
1472 | GNUNET_YES); | ||
1404 | } | 1473 | } |
1405 | 1474 | ||
1406 | 1475 | ||
@@ -1416,7 +1485,10 @@ static void | |||
1416 | dyndns_lookup (void *cls) | 1485 | dyndns_lookup (void *cls) |
1417 | { | 1486 | { |
1418 | struct ClientHandle *ch = cls; | 1487 | struct ClientHandle *ch = cls; |
1488 | struct LocalAddressList *lal; | ||
1419 | 1489 | ||
1490 | for (lal = ch->ext_addr_head; NULL != lal; lal = lal->next) | ||
1491 | lal->old = GNUNET_YES; | ||
1420 | ch->ext_dns_task = NULL; | 1492 | ch->ext_dns_task = NULL; |
1421 | ch->ext_dns = GNUNET_RESOLVER_ip_get (ch->hole_external, | 1493 | ch->ext_dns = GNUNET_RESOLVER_ip_get (ch->hole_external, |
1422 | AF_UNSPEC, | 1494 | AF_UNSPEC, |
@@ -1443,7 +1515,7 @@ lookup_hole_external (struct ClientHandle *ch) | |||
1443 | char *port; | 1515 | char *port; |
1444 | unsigned int pnum; | 1516 | unsigned int pnum; |
1445 | struct sockaddr_in *s4; | 1517 | struct sockaddr_in *s4; |
1446 | struct LocalAddressList lal; | 1518 | struct LocalAddressList *lal; |
1447 | 1519 | ||
1448 | port = strrchr (ch->hole_external, ':'); | 1520 | port = strrchr (ch->hole_external, ':'); |
1449 | if (NULL == port) | 1521 | if (NULL == port) |
@@ -1465,17 +1537,19 @@ lookup_hole_external (struct ClientHandle *ch) | |||
1465 | } | 1537 | } |
1466 | ch->ext_dns_port = (uint16_t) pnum; | 1538 | ch->ext_dns_port = (uint16_t) pnum; |
1467 | *port = '\0'; | 1539 | *port = '\0'; |
1540 | |||
1541 | lal = GNUNET_new (struct LocalAddressList); | ||
1468 | if ('[' == *ch->hole_external) | 1542 | if ('[' == *ch->hole_external) |
1469 | { | 1543 | { |
1470 | struct sockaddr_in6 *s6 = (struct sockaddr_in6 *) &ch->ext_addr; | 1544 | struct sockaddr_in6 *s6 = (struct sockaddr_in6 *) &lal->addr; |
1471 | 1545 | ||
1472 | memset (s6, 0, sizeof (*s6)); | ||
1473 | s6->sin6_family = AF_INET6; | 1546 | s6->sin6_family = AF_INET6; |
1474 | if (']' != (ch->hole_external[strlen(ch->hole_external)-1])) | 1547 | if (']' != (ch->hole_external[strlen(ch->hole_external)-1])) |
1475 | { | 1548 | { |
1476 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | 1549 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, |
1477 | _("Malformed punched hole specification `%s' (lacks `]')\n"), | 1550 | _("Malformed punched hole specification `%s' (lacks `]')\n"), |
1478 | ch->hole_external); | 1551 | ch->hole_external); |
1552 | GNUNET_free (lal); | ||
1479 | return; | 1553 | return; |
1480 | } | 1554 | } |
1481 | ch->hole_external[strlen(ch->hole_external)-1] = '\0'; | 1555 | ch->hole_external[strlen(ch->hole_external)-1] = '\0'; |
@@ -1486,35 +1560,36 @@ lookup_hole_external (struct ClientHandle *ch) | |||
1486 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | 1560 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, |
1487 | _("Malformed punched hole specification `%s' (IPv6 address invalid)"), | 1561 | _("Malformed punched hole specification `%s' (IPv6 address invalid)"), |
1488 | ch->hole_external + 1); | 1562 | ch->hole_external + 1); |
1563 | GNUNET_free (lal); | ||
1489 | return; | 1564 | return; |
1490 | } | 1565 | } |
1491 | s6->sin6_port = htons (ch->ext_dns_port); | 1566 | s6->sin6_port = htons (ch->ext_dns_port); |
1492 | memset (&lal, 0, sizeof (lal)); | 1567 | lal->af = AF_INET6; |
1493 | GNUNET_memcpy (&lal.addr, s6, sizeof (*s6)); | 1568 | lal->ac = GNUNET_NAT_AC_GLOBAL | GNUNET_NAT_AC_MANUAL; |
1494 | lal.af = AF_INET6; | 1569 | GNUNET_CONTAINER_DLL_insert (ch->ext_addr_head, |
1495 | lal.ac = GNUNET_NAT_AC_GLOBAL | GNUNET_NAT_AC_MANUAL; | 1570 | ch->ext_addr_tail, |
1496 | check_notify_client (&lal, | 1571 | lal); |
1572 | check_notify_client (lal, | ||
1497 | ch, | 1573 | ch, |
1498 | GNUNET_YES); | 1574 | GNUNET_YES); |
1499 | ch->ext_addr_set = GNUNET_YES; | ||
1500 | return; | 1575 | return; |
1501 | } | 1576 | } |
1502 | s4 = (struct sockaddr_in *) &ch->ext_addr; | 1577 | |
1503 | memset (s4, 0, sizeof (*s4)); | 1578 | s4 = (struct sockaddr_in *) &lal->addr; |
1504 | s4->sin_family = AF_INET; | 1579 | s4->sin_family = AF_INET; |
1505 | if (1 == inet_pton (AF_INET, | 1580 | if (1 == inet_pton (AF_INET, |
1506 | ch->hole_external, | 1581 | ch->hole_external, |
1507 | &s4->sin_addr)) | 1582 | &s4->sin_addr)) |
1508 | { | 1583 | { |
1509 | s4->sin_port = htons (ch->ext_dns_port); | 1584 | s4->sin_port = htons (ch->ext_dns_port); |
1510 | memset (&lal, 0, sizeof (lal)); | 1585 | lal->af = AF_INET; |
1511 | GNUNET_memcpy (&lal.addr, s4, sizeof (*s4)); | 1586 | lal->ac = GNUNET_NAT_AC_GLOBAL | GNUNET_NAT_AC_MANUAL; |
1512 | lal.af = AF_INET; | 1587 | GNUNET_CONTAINER_DLL_insert (ch->ext_addr_head, |
1513 | lal.ac = GNUNET_NAT_AC_GLOBAL | GNUNET_NAT_AC_MANUAL; | 1588 | ch->ext_addr_tail, |
1514 | check_notify_client (&lal, | 1589 | lal); |
1590 | check_notify_client (lal, | ||
1515 | ch, | 1591 | ch, |
1516 | GNUNET_YES); | 1592 | GNUNET_YES); |
1517 | ch->ext_addr_set = GNUNET_YES; | ||
1518 | return; | 1593 | return; |
1519 | } | 1594 | } |
1520 | if (0 == strcasecmp (ch->hole_external, | 1595 | if (0 == strcasecmp (ch->hole_external, |
@@ -1522,9 +1597,11 @@ lookup_hole_external (struct ClientHandle *ch) | |||
1522 | { | 1597 | { |
1523 | // FIXME: use `external-ip` address(es)! | 1598 | // FIXME: use `external-ip` address(es)! |
1524 | GNUNET_break (0); // not implemented! | 1599 | GNUNET_break (0); // not implemented! |
1600 | GNUNET_free (lal); | ||
1525 | return; | 1601 | return; |
1526 | } | 1602 | } |
1527 | /* got a DNS name, trigger lookup! */ | 1603 | /* got a DNS name, trigger lookup! */ |
1604 | GNUNET_free (lal); | ||
1528 | ch->ext_dns_task | 1605 | ch->ext_dns_task |
1529 | = GNUNET_SCHEDULER_add_now (&dyndns_lookup, | 1606 | = GNUNET_SCHEDULER_add_now (&dyndns_lookup, |
1530 | ch); | 1607 | ch); |
@@ -2386,6 +2463,7 @@ client_disconnect_cb (void *cls, | |||
2386 | void *internal_cls) | 2463 | void *internal_cls) |
2387 | { | 2464 | { |
2388 | struct ClientHandle *ch = internal_cls; | 2465 | struct ClientHandle *ch = internal_cls; |
2466 | struct LocalAddressList *lal; | ||
2389 | 2467 | ||
2390 | GNUNET_CONTAINER_DLL_remove (ch_head, | 2468 | GNUNET_CONTAINER_DLL_remove (ch_head, |
2391 | ch_tail, | 2469 | ch_tail, |
@@ -2399,6 +2477,13 @@ client_disconnect_cb (void *cls, | |||
2399 | } | 2477 | } |
2400 | } | 2478 | } |
2401 | GNUNET_free_non_null (ch->caddrs); | 2479 | GNUNET_free_non_null (ch->caddrs); |
2480 | while (NULL != (lal = ch->ext_addr_head)) | ||
2481 | { | ||
2482 | GNUNET_CONTAINER_DLL_remove (ch->ext_addr_head, | ||
2483 | ch->ext_addr_tail, | ||
2484 | lal); | ||
2485 | GNUNET_free (lal); | ||
2486 | } | ||
2402 | if (NULL != ch->ext_dns_task) | 2487 | if (NULL != ch->ext_dns_task) |
2403 | { | 2488 | { |
2404 | GNUNET_SCHEDULER_cancel (ch->ext_dns_task); | 2489 | GNUNET_SCHEDULER_cancel (ch->ext_dns_task); |