aboutsummaryrefslogtreecommitdiff
path: root/src/transport/plugin_transport_tcp.c
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2011-06-25 06:24:01 +0000
committerChristian Grothoff <christian@grothoff.org>2011-06-25 06:24:01 +0000
commit8a3016481ba6aeb36de3950a56e641dda53ca544 (patch)
tree0c5468ec6e5d2165ad5931940e0b8439d09398de /src/transport/plugin_transport_tcp.c
parentb6d4eeb39fd0cd41df164bd0959f58b08aa45e83 (diff)
downloadgnunet-8a3016481ba6aeb36de3950a56e641dda53ca544.tar.gz
gnunet-8a3016481ba6aeb36de3950a56e641dda53ca544.zip
the big NAT change
Diffstat (limited to 'src/transport/plugin_transport_tcp.c')
-rw-r--r--src/transport/plugin_transport_tcp.c1259
1 files changed, 99 insertions, 1160 deletions
diff --git a/src/transport/plugin_transport_tcp.c b/src/transport/plugin_transport_tcp.c
index 491c536ca..a8eee970c 100644
--- a/src/transport/plugin_transport_tcp.c
+++ b/src/transport/plugin_transport_tcp.c
@@ -38,15 +38,10 @@
38#include "gnunet_transport_plugin.h" 38#include "gnunet_transport_plugin.h"
39#include "transport.h" 39#include "transport.h"
40 40
41#define DEBUG_TCP GNUNET_NO 41#define DEBUG_TCP GNUNET_YES
42 42
43#define DEBUG_TCP_NAT GNUNET_YES 43#define DEBUG_TCP_NAT GNUNET_YES
44 44
45/**
46 * How long until we give up on transmitting the welcome message?
47 */
48#define HOSTNAME_RESOLVE_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
49
50 45
51/** 46/**
52 * Initial handshake message for a session. 47 * Initial handshake message for a session.
@@ -136,7 +131,7 @@ struct IPv4TcpAddress
136 /** 131 /**
137 * Port number, in network byte order. 132 * Port number, in network byte order.
138 */ 133 */
139 uint16_t t_port GNUNET_PACKED; 134 uint16_t t4_port GNUNET_PACKED;
140 135
141}; 136};
142 137
@@ -166,52 +161,6 @@ struct Plugin;
166 161
167 162
168/** 163/**
169 * Local network addresses (actual IP address follows this struct).
170 * PORT is NOT included!
171 */
172struct LocalAddrList
173{
174
175 /**
176 * This is a doubly linked list.
177 */
178 struct LocalAddrList *next;
179
180 /**
181 * This is a doubly linked list.
182 */
183 struct LocalAddrList *prev;
184
185 /**
186 * Link to plugin.
187 */
188 struct Plugin *plugin;
189
190 /**
191 * Handle to NAT holes we've tried to punch for this address.
192 */
193 struct GNUNET_NAT_Handle *nat;
194
195 /**
196 * Pointer to a 'struct IPv4/V6TcpAddress' describing our external IP and port
197 * as obtained from the NAT by automatic port mapping.
198 */
199 void *external_nat_address;
200
201 /**
202 * Number of bytes in 'external_nat_address'
203 */
204 size_t ena_size;
205
206 /**
207 * Number of bytes of the address that follow
208 */
209 size_t size;
210
211};
212
213
214/**
215 * Information kept for each message that is yet to 164 * Information kept for each message that is yet to
216 * be transmitted. 165 * be transmitted.
217 */ 166 */
@@ -365,24 +314,9 @@ struct Plugin
365 struct GNUNET_CONNECTION_Handle *lsock; 314 struct GNUNET_CONNECTION_Handle *lsock;
366 315
367 /** 316 /**
368 * stdout pipe handle for the gnunet-nat-server process 317 * Our handle to the NAT module.
369 */
370 struct GNUNET_DISK_PipeHandle *server_stdout;
371
372 /**
373 * stdout file handle (for reading) for the gnunet-nat-server process
374 */ 318 */
375 const struct GNUNET_DISK_FileHandle *server_stdout_handle; 319 struct GNUNET_NAT_Handle *nat;
376
377 /**
378 * ID of select gnunet-nat-server stdout read task
379 */
380 GNUNET_SCHEDULER_TaskIdentifier server_read_task;
381
382 /**
383 * The process id of the server process (if behind NAT)
384 */
385 struct GNUNET_OS_Process *server_proc;
386 320
387 /** 321 /**
388 * List of open TCP sessions. 322 * List of open TCP sessions.
@@ -406,48 +340,10 @@ struct Plugin
406 struct GNUNET_SERVER_MessageHandler *handlers; 340 struct GNUNET_SERVER_MessageHandler *handlers;
407 341
408 /** 342 /**
409 * Handle for request of hostname resolution, non-NULL if pending.
410 */
411 struct GNUNET_RESOLVER_RequestHandle *hostname_dns;
412
413 /**
414 * Map of peers we have tried to contact behind a NAT 343 * Map of peers we have tried to contact behind a NAT
415 */ 344 */
416 struct GNUNET_CONTAINER_MultiHashMap *nat_wait_conns; 345 struct GNUNET_CONTAINER_MultiHashMap *nat_wait_conns;
417 346
418 /**
419 * The external address given to us by the user. Used for HELLOs
420 * and address validation.
421 */
422 char *external_address;
423
424 /**
425 * The internal address given to us by the user (or discovered).
426 * Used for NAT traversal (ICMP method), but not as a 'validateable'
427 * address in HELLOs.
428 */
429 char *internal_address;
430
431 /**
432 * Address given for us to bind to (ONLY).
433 */
434 char *bind_address;
435
436 /**
437 * use local addresses?
438 */
439 int use_localaddresses;
440
441 /**
442 * List of our IP addresses.
443 */
444 struct LocalAddrList *lal_head;
445
446 /**
447 * Tail of our IP address list.
448 */
449 struct LocalAddrList *lal_tail;
450
451 /** 347 /**
452 * List of active TCP probes. 348 * List of active TCP probes.
453 */ 349 */
@@ -484,31 +380,6 @@ struct Plugin
484 */ 380 */
485 uint16_t adv_port; 381 uint16_t adv_port;
486 382
487 /**
488 * Is this transport configured to be behind a NAT?
489 */
490 int behind_nat;
491
492 /**
493 * Has the NAT been punched?
494 */
495 int nat_punched;
496
497 /**
498 * Is this transport configured to allow connections to NAT'd peers?
499 */
500 int enable_nat_client;
501
502 /**
503 * Should we run the gnunet-nat-server?
504 */
505 int enable_nat_server;
506
507 /**
508 * Are we allowed to try UPnP/PMP for NAT traversal?
509 */
510 int enable_upnp;
511
512}; 383};
513 384
514 385
@@ -549,30 +420,34 @@ plugin_tcp_access_check (void *cls,
549 * @param addrlen actual lenght of the address 420 * @param addrlen actual lenght of the address
550 */ 421 */
551static void 422static void
552nat_port_map_callback (void *cls, 423tcp_nat_port_map_callback (void *cls,
553 int add_remove, 424 int add_remove,
554 const struct sockaddr *addr, 425 const struct sockaddr *addr,
555 socklen_t addrlen) 426 socklen_t addrlen)
556{ 427{
557 struct LocalAddrList *lal = cls; 428 struct Plugin *plugin = cls;
558 struct Plugin *plugin = lal->plugin;
559 int af;
560 struct IPv4TcpAddress t4; 429 struct IPv4TcpAddress t4;
561 struct IPv6TcpAddress t6; 430 struct IPv6TcpAddress t6;
562 void *arg; 431 void *arg;
563 uint16_t args; 432 size_t args;
564 433
434 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
435 "tcp",
436 "NPMC called with %d for address `%s'\n",
437 add_remove,
438 GNUNET_a2s (addr, addrlen));
565 /* convert 'addr' to our internal format */ 439 /* convert 'addr' to our internal format */
566 af = addr->sa_family; 440 switch (addr->sa_family)
567 switch (af)
568 { 441 {
569 case AF_INET: 442 case AF_INET:
443 GNUNET_assert (addrlen == sizeof (struct sockaddr_in));
570 t4.ipv4_addr = ((struct sockaddr_in *) addr)->sin_addr.s_addr; 444 t4.ipv4_addr = ((struct sockaddr_in *) addr)->sin_addr.s_addr;
571 t4.t_port = ((struct sockaddr_in *) addr)->sin_port; 445 t4.t4_port = ((struct sockaddr_in *) addr)->sin_port;
572 arg = &t4; 446 arg = &t4;
573 args = sizeof (t4); 447 args = sizeof (t4);
574 break; 448 break;
575 case AF_INET6: 449 case AF_INET6:
450 GNUNET_assert (addrlen == sizeof (struct sockaddr_in6));
576 memcpy (&t6.ipv6_addr, 451 memcpy (&t6.ipv6_addr,
577 &((struct sockaddr_in6 *) addr)->sin6_addr, 452 &((struct sockaddr_in6 *) addr)->sin6_addr,
578 sizeof (struct in6_addr)); 453 sizeof (struct in6_addr));
@@ -583,154 +458,11 @@ nat_port_map_callback (void *cls,
583 default: 458 default:
584 GNUNET_break (0); 459 GNUNET_break (0);
585 return; 460 return;
586 }
587
588 /* modify our published address list */
589 if (GNUNET_YES == add_remove)
590 {
591 plugin->env->notify_address (plugin->env->cls,
592 "tcp",
593 arg, args, GNUNET_TIME_UNIT_FOREVER_REL);
594 GNUNET_free_non_null (lal->external_nat_address);
595 lal->external_nat_address = GNUNET_memdup (arg, args);
596 lal->ena_size = args;
597 }
598 else
599 {
600 plugin->env->notify_address (plugin->env->cls,
601 "tcp",
602 arg, args, GNUNET_TIME_UNIT_ZERO);
603 GNUNET_free_non_null (lal->external_nat_address);
604 lal->ena_size = 0;
605 }
606}
607
608
609/**
610 * Add the given address to the list of 'local' addresses, thereby
611 * making it a 'legal' address for this peer to have.
612 *
613 * @param plugin the plugin
614 * @param arg the address, either an IPv4 or an IPv6 IP address
615 * @param arg_size number of bytes in arg
616 */
617static void
618add_to_address_list (struct Plugin *plugin,
619 const void *arg,
620 size_t arg_size)
621{
622 struct LocalAddrList *lal;
623 struct sockaddr_in v4;
624 struct sockaddr_in6 v6;
625 const struct sockaddr *sa;
626 socklen_t salen;
627
628 lal = plugin->lal_head;
629 while (NULL != lal)
630 {
631 if ( (lal->size == arg_size) &&
632 (0 == memcmp (&lal[1], arg, arg_size)) )
633 return;
634 lal = lal->next;
635 }
636 lal = GNUNET_malloc (sizeof (struct LocalAddrList) + arg_size);
637 lal->plugin = plugin;
638 lal->size = arg_size;
639 memcpy (&lal[1], arg, arg_size);
640 GNUNET_CONTAINER_DLL_insert (plugin->lal_head,
641 plugin->lal_tail,
642 lal);
643 if (plugin->open_port == 0)
644 return; /* we're not listening at all... */
645 if (arg_size == sizeof (struct in_addr))
646 {
647 memset (&v4, 0, sizeof (v4));
648 v4.sin_family = AF_INET;
649 v4.sin_port = htons (plugin->open_port);
650 memcpy (&v4.sin_addr, arg, arg_size);
651#if HAVE_SOCKADDR_IN_SIN_LEN
652 v4.sin_len = sizeof (struct sockaddr_in);
653#endif
654 sa = (const struct sockaddr*) &v4;
655 salen = sizeof (v4);
656 }
657 else if (arg_size == sizeof (struct in6_addr))
658 {
659 memset (&v6, 0, sizeof (v6));
660 v6.sin6_family = AF_INET6;
661 v6.sin6_port = htons (plugin->open_port);
662 memcpy (&v6.sin6_addr, arg, arg_size);
663#if HAVE_SOCKADDR_IN_SIN_LEN
664 v6.sin6_len = sizeof (struct sockaddr_in6);
665#endif
666 sa = (const struct sockaddr*) &v6;
667 salen = sizeof (v6);
668 }
669 else
670 {
671 GNUNET_break (0);
672 return;
673 } 461 }
674 if ( (plugin->behind_nat == GNUNET_YES) && 462 /* modify our published address list */
675 (plugin->enable_upnp == GNUNET_YES) ) 463 plugin->env->notify_address (plugin->env->cls,
676 lal->nat = GNUNET_NAT_register (plugin->env->cfg, 464 add_remove,
677 sa, salen, 465 arg, args);
678 &nat_port_map_callback,
679 lal);
680}
681
682
683/**
684 * Check if the given address is in the list of 'local' addresses.
685 *
686 * @param plugin the plugin
687 * @param arg the address, either an IPv4 or an IPv6 IP address
688 * @param arg_size number of bytes in arg
689 * @return GNUNET_OK if this is one of our IPs, GNUNET_SYSERR if not
690 */
691static int
692check_local_addr (struct Plugin *plugin,
693 const void *arg,
694 size_t arg_size)
695{
696 struct LocalAddrList *lal;
697
698 lal = plugin->lal_head;
699 while (NULL != lal)
700 {
701 if ( (lal->size == arg_size) &&
702 (0 == memcmp (&lal[1], arg, arg_size)) )
703 return GNUNET_OK;
704 lal = lal->next;
705 }
706 return GNUNET_SYSERR;
707}
708
709
710/**
711 * Check if the given address is in the list of 'mapped' addresses.
712 *
713 * @param plugin the plugin
714 * @param arg the address, either a 'struct IPv4TcpAddress' or a 'struct IPv6TcpAddress'
715 * @param arg_size number of bytes in arg
716 * @return GNUNET_OK if this is one of our IPs, GNUNET_SYSERR if not
717 */
718static int
719check_mapped_addr (struct Plugin *plugin,
720 const void *arg,
721 size_t arg_size)
722{
723 struct LocalAddrList *lal;
724
725 lal = plugin->lal_head;
726 while (NULL != lal)
727 {
728 if ( (lal->ena_size == arg_size) &&
729 (0 == memcmp (lal->external_nat_address, arg, arg_size)) )
730 return GNUNET_OK;
731 lal = lal->next;
732 }
733 return GNUNET_SYSERR;
734} 466}
735 467
736 468
@@ -772,7 +504,7 @@ tcp_address_to_string (void *cls,
772 { 504 {
773 t4 = addr; 505 t4 = addr;
774 af = AF_INET; 506 af = AF_INET;
775 port = ntohs (t4->t_port); 507 port = ntohs (t4->t4_port);
776 memcpy (&a4, &t4->ipv4_addr, sizeof (a4)); 508 memcpy (&a4, &t4->ipv4_addr, sizeof (a4));
777 sb = &a4; 509 sb = &a4;
778 } 510 }
@@ -1186,64 +918,6 @@ select_better_session (struct Session *s1,
1186} 918}
1187 919
1188 920
1189/**
1190 * We learned about a peer (possibly behind NAT) so run the
1191 * gnunet-nat-client to send dummy ICMP responses.
1192 *
1193 * @param plugin the plugin for this transport
1194 * @param sa the address of the peer (IPv4-only)
1195 */
1196static void
1197run_gnunet_nat_client (struct Plugin *plugin,
1198 const struct sockaddr_in *sa)
1199{
1200 char inet4[INET_ADDRSTRLEN];
1201 char port_as_string[6];
1202 struct GNUNET_OS_Process *proc;
1203
1204 if (plugin->internal_address == NULL)
1205 {
1206 GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING,
1207 "tcp",
1208 _("Internal IP address not known, cannot use ICMP NAT traversal method\n"));
1209 return;
1210 }
1211 GNUNET_assert (sa->sin_family == AF_INET);
1212 if (NULL == inet_ntop (AF_INET,
1213 &sa->sin_addr,
1214 inet4, INET_ADDRSTRLEN))
1215 {
1216 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "inet_ntop");
1217 return;
1218 }
1219 GNUNET_snprintf(port_as_string,
1220 sizeof (port_as_string),
1221 "%d",
1222 plugin->adv_port);
1223#if DEBUG_TCP_NAT
1224 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
1225 "tcp",
1226 _("Running gnunet-nat-client %s %s %u\n"),
1227 plugin->internal_address,
1228 inet4,
1229 (unsigned int) plugin->adv_port);
1230#endif
1231 proc = GNUNET_OS_start_process (NULL,
1232 NULL,
1233 "gnunet-nat-client",
1234 "gnunet-nat-client",
1235 plugin->internal_address,
1236 inet4,
1237 port_as_string,
1238 NULL);
1239 if (NULL == proc)
1240 return;
1241 /* we know that the gnunet-nat-client will terminate virtually
1242 instantly */
1243 GNUNET_OS_process_wait (proc);
1244 GNUNET_OS_process_close (proc);
1245}
1246
1247 921
1248/** 922/**
1249 * Function that can be used by the transport service to transmit 923 * Function that can be used by the transport service to transmit
@@ -1400,8 +1074,8 @@ tcp_plugin_send (void *cls,
1400 a4.sin_len = sizeof (a4); 1074 a4.sin_len = sizeof (a4);
1401#endif 1075#endif
1402 a4.sin_family = AF_INET; 1076 a4.sin_family = AF_INET;
1403 a4.sin_port = t4->t_port; 1077 a4.sin_port = t4->t4_port;
1404 if (t4->t_port == 0) 1078 if (t4->t4_port == 0)
1405 is_natd = GNUNET_YES; 1079 is_natd = GNUNET_YES;
1406 a4.sin_addr.s_addr = t4->ipv4_addr; 1080 a4.sin_addr.s_addr = t4->ipv4_addr;
1407 sb = &a4; 1081 sb = &a4;
@@ -1422,8 +1096,8 @@ tcp_plugin_send (void *cls,
1422 if (0 == plugin->max_connections) 1096 if (0 == plugin->max_connections)
1423 return -1; /* saturated */ 1097 return -1; /* saturated */
1424 1098
1425 if ( (plugin->enable_nat_client == GNUNET_YES) && 1099 if ( (is_natd == GNUNET_YES) &&
1426 (is_natd == GNUNET_YES) && 1100 (NULL != plugin->nat) &&
1427 (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains(plugin->nat_wait_conns, 1101 (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains(plugin->nat_wait_conns,
1428 &target->hashPubKey)) ) 1102 &target->hashPubKey)) )
1429 { 1103 {
@@ -1466,11 +1140,10 @@ tcp_plugin_send (void *cls,
1466 GNUNET_i2s (target), 1140 GNUNET_i2s (target),
1467 GNUNET_a2s (sb, sbs)); 1141 GNUNET_a2s (sb, sbs));
1468#endif 1142#endif
1469 run_gnunet_nat_client (plugin, &a4); 1143 GNUNET_NAT_run_client (plugin->nat, &a4);
1470 return 0; 1144 return 0;
1471 } 1145 }
1472 if ( (plugin->enable_nat_client == GNUNET_YES) && 1146 if ( (is_natd == GNUNET_YES) &&
1473 (is_natd == GNUNET_YES) &&
1474 (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains(plugin->nat_wait_conns, 1147 (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains(plugin->nat_wait_conns,
1475 &target->hashPubKey)) ) 1148 &target->hashPubKey)) )
1476 { 1149 {
@@ -1697,9 +1370,9 @@ tcp_plugin_address_pretty_printer (void *cls,
1697 t4 = addr; 1370 t4 = addr;
1698 memset (&a4, 0, sizeof (a4)); 1371 memset (&a4, 0, sizeof (a4));
1699 a4.sin_family = AF_INET; 1372 a4.sin_family = AF_INET;
1700 a4.sin_port = t4->t_port; 1373 a4.sin_port = t4->t4_port;
1701 a4.sin_addr.s_addr = t4->ipv4_addr; 1374 a4.sin_addr.s_addr = t4->ipv4_addr;
1702 port = ntohs (t4->t_port); 1375 port = ntohs (t4->t4_port);
1703 sb = &a4; 1376 sb = &a4;
1704 sbs = sizeof (a4); 1377 sbs = sizeof (a4);
1705 } 1378 }
@@ -1773,14 +1446,12 @@ tcp_plugin_check_address (void *cls,
1773 if (addrlen == sizeof (struct IPv4TcpAddress)) 1446 if (addrlen == sizeof (struct IPv4TcpAddress))
1774 { 1447 {
1775 v4 = (struct IPv4TcpAddress *) addr; 1448 v4 = (struct IPv4TcpAddress *) addr;
1776 if (GNUNET_OK ==
1777 check_mapped_addr (plugin, v4, sizeof (struct IPv4TcpAddress)))
1778 return GNUNET_OK;
1779 if (GNUNET_OK != 1449 if (GNUNET_OK !=
1780 check_port (plugin, ntohs (v4->t_port))) 1450 check_port (plugin, ntohs (v4->t4_port)))
1781 return GNUNET_SYSERR; 1451 return GNUNET_SYSERR;
1782 if (GNUNET_OK != 1452 if (GNUNET_OK !=
1783 check_local_addr (plugin, &v4->ipv4_addr, sizeof (struct in_addr))) 1453 GNUNET_NAT_test_address (plugin->nat,
1454 &v4->ipv4_addr, sizeof (struct in_addr)))
1784 return GNUNET_SYSERR; 1455 return GNUNET_SYSERR;
1785 } 1456 }
1786 else 1457 else
@@ -1791,14 +1462,12 @@ tcp_plugin_check_address (void *cls,
1791 GNUNET_break_op (0); 1462 GNUNET_break_op (0);
1792 return GNUNET_SYSERR; 1463 return GNUNET_SYSERR;
1793 } 1464 }
1794 if (GNUNET_OK ==
1795 check_mapped_addr (plugin, v6, sizeof (struct IPv6TcpAddress)))
1796 return GNUNET_OK;
1797 if (GNUNET_OK != 1465 if (GNUNET_OK !=
1798 check_port (plugin, ntohs (v6->t6_port))) 1466 check_port (plugin, ntohs (v6->t6_port)))
1799 return GNUNET_SYSERR; 1467 return GNUNET_SYSERR;
1800 if (GNUNET_OK != 1468 if (GNUNET_OK !=
1801 check_local_addr (plugin, &v6->ipv6_addr, sizeof (struct in6_addr))) 1469 GNUNET_NAT_test_address (plugin->nat,
1470 &v6->ipv6_addr, sizeof (struct in6_addr)))
1802 return GNUNET_SYSERR; 1471 return GNUNET_SYSERR;
1803 } 1472 }
1804 return GNUNET_OK; 1473 return GNUNET_OK;
@@ -1903,7 +1572,7 @@ handle_tcp_nat_probe (void *cls,
1903 case AF_INET: 1572 case AF_INET:
1904 s4 = vaddr; 1573 s4 = vaddr;
1905 t4 = GNUNET_malloc (sizeof (struct IPv4TcpAddress)); 1574 t4 = GNUNET_malloc (sizeof (struct IPv4TcpAddress));
1906 t4->t_port = s4->sin_port; 1575 t4->t4_port = s4->sin_port;
1907 t4->ipv4_addr = s4->sin_addr.s_addr; 1576 t4->ipv4_addr = s4->sin_addr.s_addr;
1908 session->connect_addr = t4; 1577 session->connect_addr = t4;
1909 session->connect_alen = sizeof (struct IPv4TcpAddress); 1578 session->connect_alen = sizeof (struct IPv4TcpAddress);
@@ -2016,7 +1685,7 @@ handle_tcp_welcome (void *cls,
2016 { 1685 {
2017 s4 = vaddr; 1686 s4 = vaddr;
2018 t4 = GNUNET_malloc (sizeof (struct IPv4TcpAddress)); 1687 t4 = GNUNET_malloc (sizeof (struct IPv4TcpAddress));
2019 t4->t_port = s4->sin_port; 1688 t4->t4_port = s4->sin_port;
2020 t4->ipv4_addr = s4->sin_addr.s_addr; 1689 t4->ipv4_addr = s4->sin_addr.s_addr;
2021 session->connect_addr = t4; 1690 session->connect_addr = t4;
2022 session->connect_alen = sizeof (struct IPv4TcpAddress); 1691 session->connect_alen = sizeof (struct IPv4TcpAddress);
@@ -2215,228 +1884,6 @@ disconnect_notify (void *cls,
2215} 1884}
2216 1885
2217 1886
2218static int check_localaddress (const struct sockaddr *addr, socklen_t addrlen)
2219{
2220 uint32_t res = 0;
2221 int local = GNUNET_NO;
2222 int af = addr->sa_family;
2223 switch (af)
2224 {
2225 case AF_INET:
2226 {
2227 uint32_t netmask = 0x7F000000;
2228 uint32_t address = ntohl (((struct sockaddr_in *) addr)->sin_addr.s_addr);
2229 res = (address >> 24) ^ (netmask >> 24);
2230 if (res != 0)
2231 local = GNUNET_NO;
2232 else
2233 local = GNUNET_YES;
2234#if DEBUG_TCP
2235 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2236 "Checking IPv4 address `%s': %s\n", GNUNET_a2s (addr, addrlen), (local==GNUNET_YES) ? "local" : "global");
2237#endif
2238 break;
2239 }
2240 case AF_INET6:
2241 {
2242 if (IN6_IS_ADDR_LOOPBACK (&((struct sockaddr_in6 *) addr)->sin6_addr) ||
2243 IN6_IS_ADDR_LINKLOCAL (&((struct sockaddr_in6 *) addr)->sin6_addr))
2244 local = GNUNET_YES;
2245 else
2246 local = GNUNET_NO;
2247#if DEBUG_TCP
2248 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2249 "Checking IPv6 address `%s' : %s\n", GNUNET_a2s (addr, addrlen), (local==GNUNET_YES) ? "local" : "global");
2250#endif
2251 break;
2252 }
2253 }
2254 return local;
2255}
2256
2257/**
2258 * Add the IP of our network interface to the list of
2259 * our internal IP addresses.
2260 *
2261 * @param cls the 'struct Plugin*'
2262 * @param name name of the interface
2263 * @param isDefault do we think this may be our default interface
2264 * @param addr address of the interface
2265 * @param addrlen number of bytes in addr
2266 * @return GNUNET_OK to continue iterating
2267 */
2268static int
2269process_interfaces (void *cls,
2270 const char *name,
2271 int isDefault,
2272 const struct sockaddr *addr, socklen_t addrlen)
2273{
2274 struct Plugin *plugin = cls;
2275 int af;
2276 struct IPv4TcpAddress t4;
2277 struct IPv6TcpAddress t6;
2278 struct IPv4TcpAddress t4_nat;
2279 struct IPv6TcpAddress t6_nat;
2280 void *arg;
2281 uint16_t args;
2282 void *arg_nat;
2283 char buf[INET6_ADDRSTRLEN];
2284
2285 af = addr->sa_family;
2286 arg_nat = NULL;
2287
2288 if (plugin->use_localaddresses == GNUNET_NO)
2289 {
2290 if (GNUNET_YES == check_localaddress (addr, addrlen))
2291 {
2292#if DEBUG_TCP
2293 GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR,
2294 "tcp",
2295 "Not notifying transport of address `%s' (local address)\n",
2296 GNUNET_a2s (addr, addrlen));
2297#endif
2298 return GNUNET_OK;
2299 }
2300 }
2301
2302 switch (af)
2303 {
2304 case AF_INET:
2305 t4.ipv4_addr = ((struct sockaddr_in *) addr)->sin_addr.s_addr;
2306 GNUNET_assert (NULL != inet_ntop(AF_INET,
2307 &t4.ipv4_addr,
2308 buf,
2309 sizeof (buf)));
2310 if ( (plugin->bind_address != NULL) &&
2311 (0 != strcmp(buf, plugin->bind_address)) )
2312 {
2313#if DEBUG_TCP
2314 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
2315 "tcp",
2316 "Not notifying transport of address `%s' (does not match bind address)\n",
2317 GNUNET_a2s (addr, addrlen));
2318#endif
2319 return GNUNET_OK;
2320 }
2321 if ( (plugin->internal_address == NULL) &&
2322 (isDefault) )
2323 plugin->internal_address = GNUNET_strdup (buf);
2324 add_to_address_list (plugin, &t4.ipv4_addr, sizeof (struct in_addr));
2325 if (plugin->behind_nat == GNUNET_YES)
2326 {
2327 /* Also advertise as NAT (with port 0) */
2328 t4_nat.ipv4_addr = ((struct sockaddr_in *) addr)->sin_addr.s_addr;
2329 t4_nat.t_port = htons(0);
2330 arg_nat = &t4_nat;
2331 }
2332 t4.t_port = htons (plugin->adv_port);
2333 arg = &t4;
2334 args = sizeof (t4);
2335 break;
2336 case AF_INET6:
2337 if ( (IN6_IS_ADDR_LINKLOCAL (&((struct sockaddr_in6 *) addr)->sin6_addr)) ||
2338 (GNUNET_YES == GNUNET_CONFIGURATION_get_value_yesno(plugin->env->cfg,
2339 "nat",
2340 "DISABLEV6")) )
2341 {
2342 /* skip link local addresses */
2343 return GNUNET_OK;
2344 }
2345 memcpy (&t6.ipv6_addr,
2346 &((struct sockaddr_in6 *) addr)->sin6_addr,
2347 sizeof (struct in6_addr));
2348
2349 /* check bind address */
2350 GNUNET_assert (NULL != inet_ntop(AF_INET6,
2351 &t6.ipv6_addr,
2352 buf,
2353 sizeof (buf)));
2354
2355 if ( (plugin->bind_address != NULL) &&
2356 (0 != strcmp(buf, plugin->bind_address)) )
2357 {
2358#if DEBUG_TCP
2359 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
2360 "tcp",
2361 "Not notifying transport of address `%s' (does not match bind address)\n",
2362 GNUNET_a2s (addr, addrlen));
2363#endif
2364 return GNUNET_OK;
2365 }
2366
2367 add_to_address_list (plugin,
2368 &t6.ipv6_addr,
2369 sizeof (struct in6_addr));
2370 if (plugin->behind_nat == GNUNET_YES)
2371 {
2372 /* Also advertise as NAT (with port 0) */
2373 memcpy (&t6_nat.ipv6_addr,
2374 &((struct sockaddr_in6 *) addr)->sin6_addr,
2375 sizeof (struct in6_addr));
2376 t6_nat.t6_port = htons(0);
2377 arg_nat = &t6;
2378 }
2379 t6.t6_port = htons (plugin->adv_port);
2380 arg = &t6;
2381 args = sizeof (t6);
2382 break;
2383 default:
2384 GNUNET_break (0);
2385 return GNUNET_OK;
2386 }
2387 if (plugin->adv_port != 0)
2388 {
2389#if DEBUG_TCP
2390 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
2391 "tcp",
2392 "Found address `%s' (%s) len %d\n",
2393 GNUNET_a2s (addr, addrlen), name, args);
2394#endif
2395 plugin->env->notify_address (plugin->env->cls,
2396 "tcp",
2397 arg, args, GNUNET_TIME_UNIT_FOREVER_REL);
2398 }
2399
2400 if (arg_nat != NULL)
2401 {
2402 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
2403 "tcp",
2404 _("Found address `%s' (%s) len %d\n"),
2405 GNUNET_a2s (addr, addrlen), name, args);
2406 plugin->env->notify_address (plugin->env->cls,
2407 "tcp",
2408 arg_nat, args, GNUNET_TIME_UNIT_FOREVER_REL);
2409 }
2410
2411 return GNUNET_OK;
2412}
2413
2414
2415/**
2416 * Function called by the resolver for each address obtained from DNS
2417 * for our own hostname. Add the addresses to the list of our
2418 * external IP addresses.
2419 *
2420 * @param cls closure
2421 * @param addr one of the addresses of the host, NULL for the last address
2422 * @param addrlen length of the address
2423 */
2424static void
2425process_hostname_ips (void *cls,
2426 const struct sockaddr *addr, socklen_t addrlen)
2427{
2428 struct Plugin *plugin = cls;
2429
2430 if (addr == NULL)
2431 {
2432 plugin->hostname_dns = NULL;
2433 return;
2434 }
2435 /* FIXME: Can we figure out our external address here so it doesn't need to be user specified? */
2436 process_interfaces (plugin, "<hostname>", GNUNET_YES, addr, addrlen);
2437}
2438
2439
2440/** 1887/**
2441 * We can now send a probe message, copy into buffer to really send. 1888 * We can now send a probe message, copy into buffer to really send.
2442 * 1889 *
@@ -2475,112 +1922,36 @@ notify_send_probe (void *cls,
2475 1922
2476 1923
2477/** 1924/**
2478 * We have been notified that gnunet-nat-server has written something to stdout. 1925 * Function called by the NAT subsystem suggesting another peer wants
2479 * Handle the output, then reschedule this function to be called again once 1926 * to connect to us via connection reversal. Try to connect back to the
2480 * more is available. 1927 * given IP.
2481 * 1928 *
2482 * @param cls the plugin handle 1929 * @param cls closure
2483 * @param tc the scheduling context 1930 * @param addr address to try
1931 * @param addrlen number of bytes in addr
2484 */ 1932 */
2485static void 1933static void
2486tcp_plugin_server_read (void *cls, 1934try_connection_reversal (void *cls,
2487 const struct GNUNET_SCHEDULER_TaskContext *tc) 1935 const struct sockaddr *addr,
1936 socklen_t addrlen)
2488{ 1937{
2489 struct Plugin *plugin = cls; 1938 struct Plugin *plugin = cls;
2490 char mybuf[40];
2491 ssize_t bytes;
2492 size_t i;
2493 int port;
2494 const char *port_start;
2495 struct sockaddr_in sin_addr;
2496 struct TCPProbeContext *tcp_probe_ctx;
2497 struct GNUNET_CONNECTION_Handle *sock; 1939 struct GNUNET_CONNECTION_Handle *sock;
2498 1940 struct TCPProbeContext *tcp_probe_ctx;
2499 if ( (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
2500 return;
2501 memset (mybuf, 0, sizeof(mybuf));
2502 bytes = GNUNET_DISK_file_read(plugin->server_stdout_handle,
2503 mybuf,
2504 sizeof(mybuf));
2505 if (bytes < 1)
2506 {
2507#if DEBUG_TCP_NAT
2508 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
2509 "tcp",
2510 "Finished reading from server stdout with code: %d\n",
2511 bytes);
2512#endif
2513 /* FIXME: consider process_wait here? */
2514 return;
2515 }
2516
2517 port_start = NULL;
2518 for (i = 0; i < sizeof(mybuf); i++)
2519 {
2520 if (mybuf[i] == '\n')
2521 {
2522 mybuf[i] = '\0';
2523 break;
2524 }
2525 if ( (mybuf[i] == ':') && (i + 1 < sizeof(mybuf)) )
2526 {
2527 mybuf[i] = '\0';
2528 port_start = &mybuf[i + 1];
2529 }
2530 }
2531
2532 /* construct socket address of sender */
2533 memset (&sin_addr, 0, sizeof (sin_addr));
2534 sin_addr.sin_family = AF_INET;
2535#if HAVE_SOCKADDR_IN_SIN_LEN
2536 sin_addr.sin_len = sizeof (sin_addr);
2537#endif
2538 if ( (NULL == port_start) ||
2539 (1 != sscanf (port_start, "%d", &port)) ||
2540 (-1 == inet_pton(AF_INET, mybuf, &sin_addr.sin_addr)) )
2541 {
2542 /* should we restart gnunet-nat-server? */
2543 GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING,
2544 "tcp",
2545 _("gnunet-nat-server generated malformed address `%s'\n"),
2546 mybuf);
2547 plugin->server_read_task
2548 = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
2549 plugin->server_stdout_handle,
2550 &tcp_plugin_server_read,
2551 plugin);
2552 return;
2553 }
2554 sin_addr.sin_port = htons((uint16_t) port);
2555#if DEBUG_TCP_NAT
2556 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
2557 "tcp",
2558 "gnunet-nat-server read: %s:%d\n",
2559 mybuf, port);
2560#endif
2561 1941
2562 /** 1942 /**
2563 * We have received an ICMP response, ostensibly from a peer 1943 * We have received an ICMP response, ostensibly from a peer
2564 * that wants to connect to us! Send a message to establish a connection. 1944 * that wants to connect to us! Send a message to establish a connection.
2565 */ 1945 */
2566 sock = GNUNET_CONNECTION_create_from_sockaddr (AF_INET, 1946 sock = GNUNET_CONNECTION_create_from_sockaddr (AF_INET,
2567 (const struct sockaddr *)&sin_addr, 1947 addr,
2568 sizeof (sin_addr)); 1948 addrlen);
2569 if (sock == NULL) 1949 if (sock == NULL)
2570 { 1950 {
2571 /* failed for some odd reason (out of sockets?); ignore attempt */ 1951 /* failed for some odd reason (out of sockets?); ignore attempt */
2572 plugin->server_read_task =
2573 GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
2574 plugin->server_stdout_handle,
2575 &tcp_plugin_server_read,
2576 plugin);
2577 return; 1952 return;
2578 } 1953 }
2579 1954
2580 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
2581 "Sending TCP probe message to `%s:%u'!\n",
2582 mybuf,
2583 (unsigned int) port);
2584 /* FIXME: do we need to track these probe context objects so that 1955 /* FIXME: do we need to track these probe context objects so that
2585 we can clean them up on plugin unload? */ 1956 we can clean them up on plugin unload? */
2586 tcp_probe_ctx 1957 tcp_probe_ctx
@@ -2603,251 +1974,6 @@ tcp_plugin_server_read (void *cls,
2603 GNUNET_TIME_UNIT_FOREVER_REL, 1974 GNUNET_TIME_UNIT_FOREVER_REL,
2604 &notify_send_probe, tcp_probe_ctx); 1975 &notify_send_probe, tcp_probe_ctx);
2605 1976
2606 plugin->server_read_task =
2607 GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
2608 plugin->server_stdout_handle,
2609 &tcp_plugin_server_read,
2610 plugin);
2611}
2612
2613
2614/**
2615 * Start the gnunet-nat-server process for users behind NAT.
2616 *
2617 * @param plugin the transport plugin
2618 * @return GNUNET_YES if process was started, GNUNET_SYSERR on error
2619 */
2620static int
2621tcp_transport_start_nat_server (struct Plugin *plugin)
2622{
2623 if (plugin->internal_address == NULL)
2624 return GNUNET_SYSERR;
2625 plugin->server_stdout = GNUNET_DISK_pipe (GNUNET_YES,
2626 GNUNET_NO,
2627 GNUNET_YES);
2628 if (plugin->server_stdout == NULL)
2629 return GNUNET_SYSERR;
2630#if DEBUG_TCP_NAT
2631 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
2632 "tcp"
2633 "Starting %s %s\n", "gnunet-nat-server", plugin->internal_address);
2634#endif
2635 /* Start the server process */
2636 plugin->server_proc = GNUNET_OS_start_process (NULL,
2637 plugin->server_stdout,
2638 "gnunet-nat-server",
2639 "gnunet-nat-server",
2640 plugin->internal_address,
2641 NULL);
2642 if (plugin->server_proc == NULL)
2643 {
2644 GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING,
2645 "tcp",
2646 _("Failed to start %s\n"),
2647 "gnunet-nat-server");
2648 GNUNET_DISK_pipe_close (plugin->server_stdout);
2649 plugin->server_stdout = NULL;
2650 return GNUNET_SYSERR;
2651 }
2652 /* Close the write end of the read pipe */
2653 GNUNET_DISK_pipe_close_end(plugin->server_stdout,
2654 GNUNET_DISK_PIPE_END_WRITE);
2655 plugin->server_stdout_handle
2656 = GNUNET_DISK_pipe_handle (plugin->server_stdout,
2657 GNUNET_DISK_PIPE_END_READ);
2658 plugin->server_read_task
2659 = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
2660 plugin->server_stdout_handle,
2661 &tcp_plugin_server_read,
2662 plugin);
2663 return GNUNET_YES;
2664}
2665
2666
2667/**
2668 * Return the actual path to a file found in the current
2669 * PATH environment variable.
2670 *
2671 * @param binary the name of the file to find
2672 * @return path to binary, NULL if not found
2673 */
2674static char *
2675get_path_from_PATH (const char *binary)
2676{
2677 char *path;
2678 char *pos;
2679 char *end;
2680 char *buf;
2681 const char *p;
2682
2683 p = getenv ("PATH");
2684 if (p == NULL)
2685 {
2686 GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR,
2687 "tcp",
2688 _("PATH environment variable is unset.\n"));
2689 return NULL;
2690 }
2691 path = GNUNET_strdup (p); /* because we write on it */
2692 buf = GNUNET_malloc (strlen (path) + 20);
2693 pos = path;
2694
2695 while (NULL != (end = strchr (pos, PATH_SEPARATOR)))
2696 {
2697 *end = '\0';
2698 sprintf (buf, "%s/%s", pos, binary);
2699 if (GNUNET_DISK_file_test (buf) == GNUNET_YES)
2700 {
2701 GNUNET_free (path);
2702 return buf;
2703 }
2704 pos = end + 1;
2705 }
2706 sprintf (buf, "%s/%s", pos, binary);
2707 if (GNUNET_DISK_file_test (buf) == GNUNET_YES)
2708 {
2709 GNUNET_free (path);
2710 return buf;
2711 }
2712 GNUNET_free (buf);
2713 GNUNET_free (path);
2714 return NULL;
2715}
2716
2717
2718/**
2719 * Check whether the suid bit is set on a file.
2720 * Attempts to find the file using the current
2721 * PATH environment variable as a search path.
2722 *
2723 * @param binary the name of the file to check
2724 * @return GNUNET_YES if the file is SUID,
2725 * GNUNET_NO if not,
2726 * GNUNET_SYSERR on error
2727 */
2728static int
2729check_gnunet_nat_binary (const char *binary)
2730{
2731 struct stat statbuf;
2732 char *p;
2733#ifdef MINGW
2734 SOCKET rawsock;
2735 char *binaryexe;
2736
2737 GNUNET_asprintf (&binaryexe, "%s.exe", binary);
2738 p = get_path_from_PATH (binaryexe);
2739 free (binaryexe);
2740#else
2741 p = get_path_from_PATH (binary);
2742#endif
2743 if (p == NULL)
2744 {
2745 GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR,
2746 "tcp",
2747 _("Could not find binary `%s' in PATH!\n"),
2748 binary);
2749 return GNUNET_NO;
2750 }
2751 if (0 != STAT (p, &statbuf))
2752 {
2753 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2754 _("stat (%s) failed: %s\n"),
2755 p,
2756 STRERROR (errno));
2757 GNUNET_free (p);
2758 return GNUNET_SYSERR;
2759 }
2760 GNUNET_free (p);
2761#ifndef MINGW
2762 if ( (0 != (statbuf.st_mode & S_ISUID)) &&
2763 (statbuf.st_uid == 0) )
2764 return GNUNET_YES;
2765 return GNUNET_NO;
2766#else
2767 rawsock = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP);
2768 if (INVALID_SOCKET == rawsock)
2769 {
2770 DWORD err = GetLastError ();
2771 GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING,
2772 "tcp",
2773 "socket (AF_INET, SOCK_RAW, IPPROTO_ICMP) failed! GLE = %d\n", err);
2774 return GNUNET_NO; /* not running as administrator */
2775 }
2776 closesocket (rawsock);
2777 return GNUNET_YES;
2778#endif
2779}
2780
2781
2782/**
2783 * Our (external) hostname was resolved.
2784 *
2785 * @param cls the 'struct Plugin'
2786 * @param addr NULL on error, otherwise result of DNS lookup
2787 * @param addrlen number of bytes in addr
2788 */
2789static void
2790process_external_ip (void *cls,
2791 const struct sockaddr *addr,
2792 socklen_t addrlen)
2793{
2794 struct Plugin *plugin = cls;
2795 const struct sockaddr_in *s;
2796 struct IPv4TcpAddress t4;
2797 char buf[INET_ADDRSTRLEN];
2798
2799 plugin->ext_dns = NULL;
2800 if (addr == NULL)
2801 return;
2802 GNUNET_assert (addrlen == sizeof (struct sockaddr_in));
2803 s = (const struct sockaddr_in *) addr;
2804 t4.ipv4_addr = s->sin_addr.s_addr;
2805 if ( (plugin->behind_nat == GNUNET_YES) &&
2806 (plugin->enable_nat_server == GNUNET_YES) )
2807 {
2808 t4.t_port = htons(0);
2809 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
2810 "tcp",
2811 "Notifying transport of address %s:%d\n",
2812 plugin->external_address,
2813 0);
2814 }
2815 else
2816 {
2817 t4.t_port = htons(plugin->adv_port);
2818 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
2819 "tcp",
2820 "Notifying transport of address %s:%d\n",
2821 plugin->external_address,
2822 (int) plugin->adv_port);
2823 }
2824
2825 if ((plugin->bind_address != NULL) && (plugin->behind_nat == GNUNET_NO))
2826 {
2827 GNUNET_assert (NULL != inet_ntop(AF_INET,
2828 &t4.ipv4_addr,
2829 buf,
2830 sizeof (buf)));
2831 if (0 != strcmp (plugin->bind_address, buf))
2832 {
2833 GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR,
2834 "tcp",
2835 "NAT is not enabled and specific bind address `%s' differs from external address `%s'! Not notifying about external address `%s'\n",
2836 plugin->bind_address,
2837 plugin->external_address,
2838 plugin->external_address);
2839 return;
2840 }
2841 }
2842
2843 add_to_address_list (plugin,
2844 &t4.ipv4_addr,
2845 sizeof (struct in_addr));
2846
2847 plugin->env->notify_address (plugin->env->cls,
2848 "tcp",
2849 &t4, sizeof(t4),
2850 GNUNET_TIME_UNIT_FOREVER_REL);
2851} 1977}
2852 1978
2853 1979
@@ -2875,146 +2001,16 @@ libgnunet_plugin_transport_tcp_init (void *cls)
2875 unsigned long long bport; 2001 unsigned long long bport;
2876 unsigned long long max_connections; 2002 unsigned long long max_connections;
2877 unsigned int i; 2003 unsigned int i;
2878 int behind_nat;
2879 int nat_punched;
2880 int enable_nat_client;
2881 int enable_nat_server;
2882 int enable_upnp;
2883 int use_localaddresses;
2884 char *internal_address;
2885 char *external_address;
2886 char *bind_address;
2887 struct sockaddr_in in_addr;
2888 struct GNUNET_TIME_Relative idle_timeout; 2004 struct GNUNET_TIME_Relative idle_timeout;
2005 int ret;
2006 struct sockaddr **addrs;
2007 socklen_t *addrlens;
2889 2008
2890 behind_nat = GNUNET_CONFIGURATION_get_value_yesno (env->cfg,
2891 "nat",
2892 "BEHIND_NAT");
2893 nat_punched = GNUNET_CONFIGURATION_get_value_yesno (env->cfg,
2894 "nat",
2895 "NAT_PUNCHED");
2896 enable_nat_client = GNUNET_CONFIGURATION_get_value_yesno (env->cfg,
2897 "nat",
2898 "ENABLE_NAT_CLIENT");
2899 enable_nat_server = GNUNET_CONFIGURATION_get_value_yesno (env->cfg,
2900 "nat",
2901 "ENABLE_NAT_SERVER");
2902 enable_upnp = GNUNET_CONFIGURATION_get_value_yesno (env->cfg,
2903 "nat",
2904 "ENABLE_UPNP");
2905
2906 if ( (GNUNET_YES == enable_nat_server) &&
2907 (GNUNET_YES != check_gnunet_nat_binary("gnunet-nat-server")) )
2908 {
2909 enable_nat_server = GNUNET_NO;
2910 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2911 _("Configuration requires `%s', but binary is not installed properly (SUID bit not set). Option disabled.\n"),
2912 "gnunet-nat-server");
2913 }
2914
2915 if ( (GNUNET_YES == enable_nat_client) &&
2916 (GNUNET_YES != check_gnunet_nat_binary("gnunet-nat-client")) )
2917 {
2918 enable_nat_client = GNUNET_NO;
2919 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2920 _("Configuration requires `%s', but binary is not installed properly (SUID bit not set). Option disabled.\n"),
2921 "gnunet-nat-client");
2922 }
2923
2924 external_address = NULL;
2925 if (GNUNET_OK ==
2926 GNUNET_CONFIGURATION_have_value (env->cfg,
2927 "nat",
2928 "EXTERNAL_ADDRESS"))
2929 {
2930 (void) GNUNET_CONFIGURATION_get_value_string (env->cfg,
2931 "nat",
2932 "EXTERNAL_ADDRESS",
2933 &external_address);
2934 }
2935
2936 if ( (external_address != NULL) &&
2937 (inet_pton(AF_INET, external_address, &in_addr.sin_addr) != 1) )
2938 {
2939
2940 GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING,
2941 "tcp",
2942 _("Malformed %s `%s' given in configuration!\n"),
2943 "EXTERNAL_ADDRESS",
2944 external_address);
2945 return NULL;
2946 }
2947 if ( (external_address == NULL) &&
2948 (nat_punched == GNUNET_YES) )
2949 {
2950 nat_punched = GNUNET_NO;
2951 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2952 _("Configuration says NAT was punched, but `%s' is not given. Option ignored.\n"),
2953 "EXTERNAL_ADDRESS");
2954 }
2955
2956 if (GNUNET_YES == nat_punched)
2957 {
2958 enable_nat_server = GNUNET_NO;
2959 enable_upnp = GNUNET_NO;
2960 }
2961
2962 bind_address = NULL;
2963 if (GNUNET_YES == GNUNET_CONFIGURATION_get_value_string (env->cfg,
2964 "nat",
2965 "BINDTO",
2966 &bind_address))
2967 {
2968 GNUNET_log_from (GNUNET_ERROR_TYPE_INFO,
2969 "tcp",
2970 _("Binding TCP plugin to specific address: `%s'\n"),
2971 bind_address);
2972 }
2973
2974 internal_address = NULL;
2975 if (GNUNET_OK ==
2976 GNUNET_CONFIGURATION_have_value (env->cfg,
2977 "nat",
2978 "INTERNAL_ADDRESS"))
2979 {
2980 (void) GNUNET_CONFIGURATION_get_value_string (env->cfg,
2981 "nat",
2982 "INTERNAL_ADDRESS",
2983 &internal_address);
2984 }
2985
2986 if ( (internal_address != NULL) &&
2987 (inet_pton(AF_INET, internal_address, &in_addr.sin_addr) != 1) )
2988 {
2989 GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING,
2990 "tcp",
2991 _("Malformed %s `%s' given in configuration!\n"),
2992 "INTERNAL_ADDRESS",
2993 internal_address);
2994 GNUNET_free_non_null(internal_address);
2995 GNUNET_free_non_null(external_address);
2996 return NULL;
2997 }
2998
2999 if ((bind_address != NULL) && (internal_address != NULL))
3000 {
3001 if (0 != strcmp(internal_address, bind_address ))
3002 {
3003 GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR,
3004 "tcp",
3005 "Specific bind address `%s' and internal address `%s' must not differ, forcing internal address to bind address!\n",
3006 bind_address, internal_address);
3007 GNUNET_free (internal_address);
3008 internal_address = bind_address;
3009 GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR,
3010 "tcp","New internal address `%s'\n", internal_address);
3011 }
3012 }
3013 if (GNUNET_OK != 2009 if (GNUNET_OK !=
3014 GNUNET_CONFIGURATION_get_value_number (env->cfg, 2010 GNUNET_CONFIGURATION_get_value_number (env->cfg,
3015 "transport-tcp", 2011 "transport-tcp",
3016 "MAX_CONNECTIONS", 2012 "MAX_CONNECTIONS",
3017 &max_connections)) 2013 &max_connections))
3018 max_connections = 128; 2014 max_connections = 128;
3019 2015
3020 aport = 0; 2016 aport = 0;
@@ -3035,25 +2031,15 @@ libgnunet_plugin_transport_tcp_init (void *cls)
3035 "tcp", 2031 "tcp",
3036 _("Require valid port number for service `%s' in configuration!\n"), 2032 _("Require valid port number for service `%s' in configuration!\n"),
3037 "transport-tcp"); 2033 "transport-tcp");
3038 GNUNET_free_non_null(external_address);
3039 GNUNET_free_non_null(internal_address);
3040 return NULL; 2034 return NULL;
3041 } 2035 }
3042
3043 use_localaddresses = GNUNET_CONFIGURATION_get_value_yesno (env->cfg,
3044 "transport-tcp",
3045 "USE_LOCALADDR");
3046 if (use_localaddresses == GNUNET_SYSERR)
3047 use_localaddresses = GNUNET_NO;
3048
3049 if (aport == 0) 2036 if (aport == 0)
3050 aport = bport; 2037 aport = bport;
3051 if (bport == 0) 2038 if (bport == 0)
3052 aport = 0; 2039 aport = 0;
3053
3054 if (bport != 0) 2040 if (bport != 0)
3055 { 2041 {
3056 service = GNUNET_SERVICE_start ("transport-tcp", env->cfg); 2042 service = GNUNET_SERVICE_start ("transport-tcp", env->cfg);
3057 if (service == NULL) 2043 if (service == NULL)
3058 { 2044 {
3059 GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, 2045 GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING,
@@ -3065,21 +2051,45 @@ libgnunet_plugin_transport_tcp_init (void *cls)
3065 else 2051 else
3066 service = NULL; 2052 service = NULL;
3067 2053
2054
2055
3068 plugin = GNUNET_malloc (sizeof (struct Plugin)); 2056 plugin = GNUNET_malloc (sizeof (struct Plugin));
3069 plugin->max_connections = max_connections; 2057 plugin->max_connections = max_connections;
3070 plugin->open_port = bport; 2058 plugin->open_port = bport;
3071 plugin->adv_port = aport; 2059 plugin->adv_port = aport;
3072 plugin->bind_address = bind_address;
3073 plugin->external_address = external_address;
3074 plugin->internal_address = internal_address;
3075 plugin->behind_nat = behind_nat;
3076 plugin->nat_punched = nat_punched;
3077 plugin->enable_nat_client = enable_nat_client;
3078 plugin->enable_nat_server = enable_nat_server;
3079 plugin->enable_upnp = enable_upnp;
3080 plugin->use_localaddresses = use_localaddresses;
3081 plugin->env = env; 2060 plugin->env = env;
3082 plugin->lsock = NULL; 2061 plugin->lsock = NULL;
2062 if ( (service != NULL) &&
2063 (GNUNET_SYSERR !=
2064 (ret = GNUNET_SERVICE_get_server_addresses ("transport-tcp",
2065 env->cfg,
2066 &addrs,
2067 &addrlens))) )
2068 {
2069 plugin->nat = GNUNET_NAT_register (env->cfg,
2070 GNUNET_YES,
2071 aport,
2072 (unsigned int) ret,
2073 (const struct sockaddr **) addrs,
2074 addrlens,
2075 &tcp_nat_port_map_callback,
2076 &try_connection_reversal,
2077 plugin);
2078 while (ret > 0)
2079 GNUNET_free (addrs[--ret]);
2080 GNUNET_free_non_null (addrs);
2081 GNUNET_free_non_null (addrlens);
2082 }
2083 else
2084 {
2085 plugin->nat = GNUNET_NAT_register (env->cfg,
2086 GNUNET_YES,
2087 0,
2088 0, NULL, NULL,
2089 NULL,
2090 &try_connection_reversal,
2091 plugin);
2092 }
3083 api = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PluginFunctions)); 2093 api = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PluginFunctions));
3084 api->cls = plugin; 2094 api->cls = plugin;
3085 api->send = &tcp_plugin_send; 2095 api->send = &tcp_plugin_send;
@@ -3105,8 +2115,9 @@ libgnunet_plugin_transport_tcp_init (void *cls)
3105 _("Failed to find option %s in section %s!\n"), 2115 _("Failed to find option %s in section %s!\n"),
3106 "TIMEOUT", 2116 "TIMEOUT",
3107 "transport-tcp"); 2117 "transport-tcp");
3108 GNUNET_free_non_null(external_address); 2118 if (plugin->nat != NULL)
3109 GNUNET_free_non_null(internal_address); 2119 GNUNET_NAT_unregister (plugin->nat);
2120 GNUNET_free (plugin);
3110 GNUNET_free (api); 2121 GNUNET_free (api);
3111 return NULL; 2122 return NULL;
3112 } 2123 }
@@ -3123,33 +2134,7 @@ libgnunet_plugin_transport_tcp_init (void *cls)
3123 GNUNET_SERVER_disconnect_notify (plugin->server, 2134 GNUNET_SERVER_disconnect_notify (plugin->server,
3124 &disconnect_notify, 2135 &disconnect_notify,
3125 plugin); 2136 plugin);
3126 GNUNET_OS_network_interfaces_list (&process_interfaces, plugin); 2137 plugin->nat_wait_conns = GNUNET_CONTAINER_multihashmap_create(16);
3127
3128 if ( (plugin->behind_nat == GNUNET_YES) &&
3129 (plugin->enable_nat_server == GNUNET_YES) &&
3130 (GNUNET_YES != tcp_transport_start_nat_server(plugin)) )
3131 {
3132 GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR,
3133 "tcp",
3134 _("Failed to start %s required for NAT in %s!\n"),
3135 "gnunet-nat-server"
3136 "transport-tcp");
3137 GNUNET_free_non_null(external_address);
3138 GNUNET_free_non_null(internal_address);
3139 if (service != NULL)
3140 GNUNET_SERVICE_stop (service);
3141 else
3142 GNUNET_SERVER_destroy (plugin->server);
3143 GNUNET_free (api);
3144 return NULL;
3145 }
3146
3147 if (enable_nat_client == GNUNET_YES)
3148 {
3149 plugin->nat_wait_conns = GNUNET_CONTAINER_multihashmap_create(16);
3150 GNUNET_assert (plugin->nat_wait_conns != NULL);
3151 }
3152
3153 if (bport != 0) 2138 if (bport != 0)
3154 GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, 2139 GNUNET_log_from (GNUNET_ERROR_TYPE_INFO,
3155 "tcp", 2140 "tcp",
@@ -3164,20 +2149,6 @@ libgnunet_plugin_transport_tcp_init (void *cls)
3164 "tcp", 2149 "tcp",
3165 _("TCP transport advertises itself as being on port %llu\n"), 2150 _("TCP transport advertises itself as being on port %llu\n"),
3166 aport); 2151 aport);
3167
3168 plugin->hostname_dns = GNUNET_RESOLVER_hostname_resolve (AF_UNSPEC,
3169 HOSTNAME_RESOLVE_TIMEOUT,
3170 &process_hostname_ips,
3171 plugin);
3172
3173 if (plugin->external_address != NULL)
3174 {
3175 plugin->ext_dns = GNUNET_RESOLVER_ip_get (plugin->external_address,
3176 AF_INET,
3177 GNUNET_TIME_UNIT_MINUTES,
3178 &process_external_ip,
3179 plugin);
3180 }
3181 return api; 2152 return api;
3182} 2153}
3183 2154
@@ -3191,36 +2162,17 @@ libgnunet_plugin_transport_tcp_done (void *cls)
3191 struct GNUNET_TRANSPORT_PluginFunctions *api = cls; 2162 struct GNUNET_TRANSPORT_PluginFunctions *api = cls;
3192 struct Plugin *plugin = api->cls; 2163 struct Plugin *plugin = api->cls;
3193 struct Session *session; 2164 struct Session *session;
3194 struct LocalAddrList *lal;
3195 struct TCPProbeContext *tcp_probe; 2165 struct TCPProbeContext *tcp_probe;
3196 2166
3197 if (plugin->ext_dns != NULL)
3198 {
3199 GNUNET_RESOLVER_request_cancel (plugin->ext_dns);
3200 plugin->ext_dns = NULL;
3201 }
3202 while (NULL != (session = plugin->sessions)) 2167 while (NULL != (session = plugin->sessions))
3203 disconnect_session (session); 2168 disconnect_session (session);
3204 if (NULL != plugin->hostname_dns)
3205 {
3206 GNUNET_RESOLVER_request_cancel (plugin->hostname_dns);
3207 plugin->hostname_dns = NULL;
3208 }
3209 if (plugin->service != NULL) 2169 if (plugin->service != NULL)
3210 GNUNET_SERVICE_stop (plugin->service); 2170 GNUNET_SERVICE_stop (plugin->service);
3211 else 2171 else
3212 GNUNET_SERVER_destroy (plugin->server); 2172 GNUNET_SERVER_destroy (plugin->server);
3213 GNUNET_free (plugin->handlers); 2173 GNUNET_free (plugin->handlers);
3214 while (NULL != (lal = plugin->lal_head)) 2174 if (plugin->nat != NULL)
3215 { 2175 GNUNET_NAT_unregister (plugin->nat);
3216 GNUNET_CONTAINER_DLL_remove (plugin->lal_head,
3217 plugin->lal_tail,
3218 lal);
3219 if (lal->nat != NULL)
3220 GNUNET_NAT_unregister (lal->nat);
3221 GNUNET_free_non_null (lal->external_nat_address);
3222 GNUNET_free (lal);
3223 }
3224 while (NULL != (tcp_probe = plugin->probe_head)) 2176 while (NULL != (tcp_probe = plugin->probe_head))
3225 { 2177 {
3226 GNUNET_CONTAINER_DLL_remove (plugin->probe_head, 2178 GNUNET_CONTAINER_DLL_remove (plugin->probe_head,
@@ -3229,19 +2181,6 @@ libgnunet_plugin_transport_tcp_done (void *cls)
3229 GNUNET_CONNECTION_destroy (tcp_probe->sock, GNUNET_NO); 2181 GNUNET_CONNECTION_destroy (tcp_probe->sock, GNUNET_NO);
3230 GNUNET_free (tcp_probe); 2182 GNUNET_free (tcp_probe);
3231 } 2183 }
3232
3233 if ((plugin->behind_nat == GNUNET_YES) &&
3234 (plugin->enable_nat_server == GNUNET_YES))
3235 {
3236 if (0 != GNUNET_OS_process_kill (plugin->server_proc, SIGTERM))
3237 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
3238 GNUNET_OS_process_wait (plugin->server_proc);
3239 GNUNET_OS_process_close (plugin->server_proc);
3240 plugin->server_proc = NULL;
3241 }
3242 GNUNET_free_non_null(plugin->bind_address);
3243 GNUNET_free_non_null(plugin->internal_address);
3244 GNUNET_free_non_null(plugin->external_address);
3245 GNUNET_free (plugin); 2184 GNUNET_free (plugin);
3246 GNUNET_free (api); 2185 GNUNET_free (api);
3247 return NULL; 2186 return NULL;