GNUnet 0.28.1-dev.5-1-gae1c02d74
 
Loading...
Searching...
No Matches
gnunet-service-nat.c File Reference

network address translation traversal service More...

Include dependency graph for gnunet-service-nat.c:

Go to the source code of this file.

Data Structures

struct  ClientAddress
 Information we track per client address. More...
 
struct  LocalAddressList
 List of local addresses this system has. More...
 
struct  ClientHandle
 Struct containing information about a client, handle to connect to it, and any pending messages that need to be sent to it. More...
 
struct  StunExternalIP
 External IP address as given to us via some STUN server. More...
 
struct  IfcProcContext
 Closure for ifc_proc. More...
 

Macros

#define SCAN_FREQ   GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15)
 How often should we ask the OS about a list of active network interfaces?
 
#define AUTOCONFIG_TIMEOUT
 How long do we wait until we forcefully terminate autoconfiguration?
 
#define DYNDNS_FREQUENCY
 How often do we scan for changes in how our external (dyndns) hostname resolves?
 

Functions

static void free_lal (struct LocalAddressList *lal)
 Remove and free an entry from the lal_head DLL.
 
static void destroy_lal ()
 Free the DLL starting at lal_head.
 
static int check_register (void *cls, const struct GNUNET_NAT_RegisterMessage *message)
 Check validity of GNUNET_MESSAGE_TYPE_NAT_REGISTER message from client.
 
static int match_ipv4 (const char *network, const struct in_addr *ip, uint8_t bits)
 Check if ip is in network with bits netmask.
 
static int match_ipv6 (const char *network, const struct in6_addr *ip, uint8_t bits)
 Check if ip is in network with bits netmask.
 
static int is_nat_v4 (const struct in_addr *ip)
 Test if the given IPv4 address is in a known range for private networks.
 
static int is_nat_v6 (const struct in6_addr *ip)
 Test if the given IPv6 address is in a known range for private networks.
 
static int ifc_proc (void *cls, const char *name, int isDefault, const struct sockaddr *addr, const struct sockaddr *broadcast_addr, const struct sockaddr *netmask, socklen_t addrlen)
 Callback function invoked for each interface found.
 
static void notify_client (enum GNUNET_NAT_AddressClass ac, struct ClientHandle *ch, int add, const void *addr, size_t addr_len)
 Notify client about a change in the list of addresses this peer has.
 
static void check_notify_client (struct LocalAddressList *delta, struct ClientHandle *ch, int add)
 Check if we should bother to notify this client about this address change, and if so, do it.
 
static void notify_clients (struct LocalAddressList *delta, int add)
 Notify all clients about a change in the list of addresses this peer has.
 
static void notify_client_external_ipv4_change (void *cls, const struct in_addr *v4, int add)
 Tell relevant client about a change in our external IPv4 address.
 
static void reversal_callback (void *cls, const struct sockaddr_in *ra)
 We got a connection reversal request from another peer.
 
static void run_scan (void *cls)
 Task we run periodically to scan for network interfaces.
 
static void upnp_addr_change_cb (void *cls, int add_remove, const struct sockaddr *addr, socklen_t addrlen, enum GNUNET_NAT_StatusCode result)
 Function called whenever our set of external addresses as created by upnpc changes.
 
static void dyndns_lookup (void *cls)
 Resolve the hole_external name to figure out our external address from a manually punched hole.
 
static void process_external_ip (void *cls, const struct sockaddr *addr, socklen_t addrlen)
 Our (external) hostname was resolved.
 
static void lookup_hole_external (struct ClientHandle *ch)
 Resolve the hole_external name to figure out our external address from a manually punched hole.
 
static void handle_register (void *cls, const struct GNUNET_NAT_RegisterMessage *message)
 Handler for GNUNET_MESSAGE_TYPE_NAT_REGISTER message from client.
 
static int check_stun (void *cls, const struct GNUNET_NAT_HandleStunMessage *message)
 Check validity of GNUNET_MESSAGE_TYPE_NAT_HANDLE_STUN message from client.
 
static void notify_clients_stun_change (const struct sockaddr_in *ip, int add)
 Notify all clients about our external IP address as reported by the STUN server.
 
static void stun_ip_timeout (void *cls)
 Function to be called when we decide that an external IP address as told to us by a STUN server has gone stale.
 
static void handle_stun (void *cls, const struct GNUNET_NAT_HandleStunMessage *message)
 Handler for GNUNET_MESSAGE_TYPE_NAT_HANDLE_STUN message from client.
 
static int check_request_connection_reversal (void *cls, const struct GNUNET_NAT_RequestConnectionReversalMessage *message)
 Check validity of GNUNET_MESSAGE_TYPE_NAT_REQUEST_CONNECTION_REVERSAL message from client.
 
static void handle_request_connection_reversal (void *cls, const struct GNUNET_NAT_RequestConnectionReversalMessage *message)
 Handler for GNUNET_MESSAGE_TYPE_NAT_REQUEST_CONNECTION_REVERSAL message from client.
 
static enum GNUNET_GenericReturnValue check_add_global_address (void *cls, const struct GNUNET_NAT_AddGlobalAddressMessage *message)
 Check validity of GNUNET_MESSAGE_TYPE_NAT_ADD_GLOBAL_ADDRESS message from client.
 
static void handle_add_global_address (void *cls, const struct GNUNET_NAT_AddGlobalAddressMessage *message)
 Handle GNUNET_MESSAGE_TYPE_NAT_ADD_GLOBAL_ADDRESS message from client.
 
static void shutdown_task (void *cls)
 Task run during shutdown.
 
static void run (void *cls, const struct GNUNET_CONFIGURATION_Handle *c, struct GNUNET_SERVICE_Handle *service)
 Setup NAT service.
 
static void * client_connect_cb (void *cls, struct GNUNET_SERVICE_Client *c, struct GNUNET_MQ_Handle *mq)
 Callback called when a client connects to the service.
 
static void client_disconnect_cb (void *cls, struct GNUNET_SERVICE_Client *c, void *internal_cls)
 Callback called when a client disconnected from the service.
 
 GNUNET_SERVICE_MAIN (GNUNET_OS_project_data_gnunet(), "nat", GNUNET_SERVICE_OPTION_NONE, &run, &client_connect_cb, &client_disconnect_cb, NULL, GNUNET_MQ_hd_var_size(register, GNUNET_MESSAGE_TYPE_NAT_REGISTER, struct GNUNET_NAT_RegisterMessage, NULL), GNUNET_MQ_hd_var_size(stun, GNUNET_MESSAGE_TYPE_NAT_HANDLE_STUN, struct GNUNET_NAT_HandleStunMessage, NULL), GNUNET_MQ_hd_var_size(request_connection_reversal, GNUNET_MESSAGE_TYPE_NAT_REQUEST_CONNECTION_REVERSAL, struct GNUNET_NAT_RequestConnectionReversalMessage, NULL), GNUNET_MQ_hd_var_size(add_global_address, GNUNET_MESSAGE_TYPE_NAT_ADD_GLOBAL_ADDRESS, struct GNUNET_NAT_AddGlobalAddressMessage, NULL), GNUNET_MQ_handler_end())
 Define "main" method using service macro.
 

Variables

static struct GNUNET_TIME_Relative stun_stale_timeout
 Timeout to use when STUN data is considered stale.
 
static struct GNUNET_TIME_Relative dyndns_frequency
 How often do we scan for changes in how our external (dyndns) hostname resolves?
 
static const struct GNUNET_CONFIGURATION_Handlecfg
 Handle to our current configuration.
 
static struct GNUNET_STATISTICS_Handlestats
 Handle to the statistics service.
 
static struct GNUNET_SCHEDULER_Taskscan_task
 Task scheduled to periodically scan our network interfaces.
 
static struct ClientHandlech_head
 Head of client DLL.
 
static struct ClientHandlech_tail
 Tail of client DLL.
 
static struct LocalAddressListlal_head
 Head of DLL of local addresses.
 
static struct LocalAddressListlal_tail
 Tail of DLL of local addresses.
 
static struct StunExternalIPse_head
 Kept in a DLL.
 
static struct StunExternalIPse_tail
 Kept in a DLL.
 
int enable_upnp
 Is UPnP enabled? GNUNET_YES if enabled, GNUNET_NO if disabled, GNUNET_SYSERR if configuration enabled but binary is unavailable.
 
int enable_ipscan
 Is IP Scanning enabled? GNUNET_YES if enabled, GNUNET_NO if disabled, without, only explicitly specified IPs will be handled (HOLE_EXTERNAL)
 
static int return_local_addresses
 Do we report addresses that are only meaningful on this host to clients that did not explicitly bind to them? GNUNET_YES only for tests that run several peers on one machine; everywhere else such an address just ends up in our HELLO, where it is at best useless and at worst points a remote peer at a service of its own.
 

Detailed Description

network address translation traversal service

Author
Christian Grothoff

The purpose of this service is to enable transports to traverse NAT routers, by providing traversal options and knowledge about the local network topology.

TODO:

  • migrate test cases to new NAT service
  • add new traceroute-based logic for external IP detection
  • implement & test STUN processing to classify NAT; basically, open port & try different methods.

Definition in file gnunet-service-nat.c.

Macro Definition Documentation

◆ SCAN_FREQ

How often should we ask the OS about a list of active network interfaces?

Definition at line 56 of file gnunet-service-nat.c.

◆ AUTOCONFIG_TIMEOUT

#define AUTOCONFIG_TIMEOUT
Value:
#define GNUNET_TIME_UNIT_SECONDS
One second.
struct GNUNET_TIME_Relative GNUNET_TIME_relative_multiply(struct GNUNET_TIME_Relative rel, unsigned long long factor)
Multiply relative time by a given factor.
Definition time.c:486

How long do we wait until we forcefully terminate autoconfiguration?

Definition at line 61 of file gnunet-service-nat.c.

74{
78 struct sockaddr_storage ss;
79
86};
87
88
93{
97 struct LocalAddressList *next;
98
102 struct LocalAddressList *prev;
103
108 struct HelperContext *hc;
109
114 struct sockaddr_storage addr;
115
119 int af;
120
126 int old;
127
132};
133
134
138struct ClientHandle
139{
143 struct ClientHandle *next;
144
148 struct ClientHandle *prev;
149
154
158 struct GNUNET_MQ_Handle *mq;
159
163 struct ClientAddress *caddrs;
164
173 char *hole_external;
174
178 char *section_name;
179
184
190
195
200
205
209 uint16_t ext_dns_port;
210
215
219 int natted_address;
220
225 uint16_t num_caddrs;
226
230 uint8_t proto;
231};
232
233
237struct StunExternalIP
238{
242 struct StunExternalIP *next;
243
247 struct StunExternalIP *prev;
248
253
258 struct sockaddr_in external_addr;
259
265 struct sockaddr_storage stun_server_addr;
266
271};
272
273
278
283
287static const struct GNUNET_CONFIGURATION_Handle *cfg;
288
292static struct GNUNET_STATISTICS_Handle *stats;
293
297static struct GNUNET_SCHEDULER_Task *scan_task;
298
302static struct ClientHandle *ch_head;
303
307static struct ClientHandle *ch_tail;
308
312static struct LocalAddressList *lal_head;
313
317static struct LocalAddressList *lal_tail;
318
322static struct StunExternalIP *se_head;
323
327static struct StunExternalIP *se_tail;
328
333int enable_upnp;
334
339int enable_ipscan;
340
348static int return_local_addresses;
349
355static void
356free_lal (struct LocalAddressList *lal)
357{
359 lal_tail,
360 lal);
361 if (NULL != lal->hc)
362 {
364 "Lost NATed local address %s, stopping NAT server\n",
365 GNUNET_a2s ((const struct sockaddr *) &lal->addr,
366 sizeof(struct sockaddr_in)));
367
369 lal->hc = NULL;
370 }
371 GNUNET_free (lal);
372}
373
374
378static void
380{
381 struct LocalAddressList *lal;
382
383 while (NULL != (lal = lal_head))
384 free_lal (lal);
385}
386
387
396static int
397check_register (void *cls,
398 const struct GNUNET_NAT_RegisterMessage *message)
399{
400 uint16_t num_addrs = ntohs (message->num_addrs);
401 const char *off = (const char *) &message[1];
402 size_t left = ntohs (message->header.size) - sizeof(*message);
403
404 for (unsigned int i = 0; i < num_addrs; i++)
405 {
406 size_t alen;
407 const struct sockaddr *sa = (const struct sockaddr *) off;
408
409 if (sizeof(sa_family_t) > left)
410 {
411 GNUNET_break (0);
412 return GNUNET_SYSERR;
413 }
414 switch (sa->sa_family)
415 {
416 case AF_INET:
417 alen = sizeof(struct sockaddr_in);
418 break;
419
420 case AF_INET6:
421 alen = sizeof(struct sockaddr_in6);
422 break;
423
424#if AF_UNIX
425 case AF_UNIX:
426 alen = sizeof(struct sockaddr_un);
427 break;
428#endif
429 default:
430 GNUNET_break (0);
431 return GNUNET_SYSERR;
432 }
433 if (alen > left)
434 {
435 GNUNET_break (0);
436 return GNUNET_SYSERR;
437 }
438 off += alen;
439 left -= alen;
440 }
441 if (left != ntohs (message->str_len))
442 {
443 GNUNET_break (0);
444 return GNUNET_SYSERR;
445 }
446 return GNUNET_OK;
447}
448
449
458static int
459match_ipv4 (const char *network,
460 const struct in_addr *ip,
461 uint8_t bits)
462{
463 struct in_addr net;
464
465 if (0 == ip->s_addr)
466 return GNUNET_YES;
467 if (0 == bits)
468 return GNUNET_YES;
469 GNUNET_assert (1 == inet_pton (AF_INET,
470 network,
471 &net));
472 return ! ((ip->s_addr ^ net.s_addr) & htonl (0xFFFFFFFFu << (32 - bits)));
473}
474
475
484static int
485match_ipv6 (const char *network,
486 const struct in6_addr *ip,
487 uint8_t bits)
488{
489 struct in6_addr net;
490 struct in6_addr mask;
491 unsigned int off;
492
493 if (0 == bits)
494 return GNUNET_YES;
495 GNUNET_assert (1 == inet_pton (AF_INET6,
496 network,
497 &net));
498 memset (&mask, 0, sizeof(mask));
499 if (0 == GNUNET_memcmp (&mask,
500 ip))
501 return GNUNET_YES;
502 off = 0;
503 while (bits > 8)
504 {
505 mask.s6_addr[off++] = 0xFF;
506 bits -= 8;
507 }
508 while (bits > 0)
509 {
510 mask.s6_addr[off] = (mask.s6_addr[off] >> 1) + 0x80;
511 bits--;
512 }
513 for (unsigned j = 0; j < sizeof(struct in6_addr) / sizeof(uint32_t); j++)
514 if (((((uint32_t *) ip)[j] & ((uint32_t *) &mask)[j])) !=
515 (((uint32_t *) &net)[j] & ((int *) &mask)[j]))
516 return GNUNET_NO;
517 return GNUNET_YES;
518}
519
520
528static int
529is_nat_v4 (const struct in_addr *ip)
530{
531 return
532 match_ipv4 ("10.0.0.0", ip, 8) || /* RFC 1918 */
533 match_ipv4 ("100.64.0.0", ip, 10) || /* CG-NAT, RFC 6598 */
534 match_ipv4 ("192.168.0.0", ip, 12) || /* RFC 1918 */
535 match_ipv4 ("169.254.0.0", ip, 16) || /* AUTO, RFC 3927 */
536 match_ipv4 ("172.16.0.0", ip, 16); /* RFC 1918 */
537}
538
539
547static int
548is_nat_v6 (const struct in6_addr *ip)
549{
550 return
551 match_ipv6 ("fc00::", ip, 7) || /* RFC 4193 */
552 match_ipv6 ("fec0::", ip, 10) || /* RFC 3879 */
553 match_ipv6 ("fe80::", ip, 10); /* RFC 4291, link-local */
554}
555
556
560struct IfcProcContext
561{
566
571};
572
573
587static int
588ifc_proc (void *cls,
589 const char *name,
590 int isDefault,
591 const struct sockaddr *addr,
592 const struct sockaddr *broadcast_addr,
593 const struct sockaddr *netmask,
594 socklen_t addrlen)
595{
596 struct IfcProcContext *ifc_ctx = cls;
597 struct LocalAddressList *lal;
598 size_t alen;
599 const struct in_addr *ip4;
600 const struct in6_addr *ip6;
602
603 switch (addr->sa_family)
604 {
605 case AF_INET:
606 alen = sizeof(struct sockaddr_in);
607 ip4 = &((const struct sockaddr_in *) addr)->sin_addr;
608 if (match_ipv4 ("127.0.0.0", ip4, 8))
610 else if (is_nat_v4 (ip4))
612 else
614 break;
615
616 case AF_INET6:
617 alen = sizeof(struct sockaddr_in6);
618 ip6 = &((const struct sockaddr_in6 *) addr)->sin6_addr;
619 if (match_ipv6 ("::1", ip6, 128))
621 else if (is_nat_v6 (ip6))
623 else
625 if ((ip6->s6_addr[11] == 0xFF) &&
626 (ip6->s6_addr[12] == 0xFE))
627 {
628 /* contains a MAC, be extra careful! */
630 }
631 break;
632
633#if AF_UNIX
634 case AF_UNIX:
635 GNUNET_break (0);
636 return GNUNET_OK;
637#endif
638 default:
639 GNUNET_break (0);
640 return GNUNET_OK;
641 }
642 lal = GNUNET_malloc (sizeof(*lal));
643 lal->af = addr->sa_family;
644 lal->ac = ac;
645 GNUNET_memcpy (&lal->addr,
646 addr,
647 alen);
649 ifc_ctx->lal_tail,
650 lal);
651 return GNUNET_OK;
652}
653
654
665static void
667 struct ClientHandle *ch,
668 int add,
669 const void *addr,
670 size_t addr_len)
671{
672 struct GNUNET_MQ_Envelope *env;
674
676 "Notifying client about %s of IP %s\n",
677 add ? "addition" : "removal",
678 GNUNET_a2s (addr,
679 addr_len));
681 addr_len,
683 msg->add_remove = htonl (add);
684 msg->addr_class = htonl (ac);
685 GNUNET_memcpy (&msg[1],
686 addr,
687 addr_len);
689 env);
690}
691
692
701static void
703 struct ClientHandle *ch,
704 int add)
705{
706 size_t alen;
707 struct sockaddr_in v4;
708 struct sockaddr_in6 v6;
709
710 if (0 == (ch->flags & GNUNET_NAT_RF_ADDRESSES))
711 {
713 "Not notifying client as it does not care about addresses\n");
714 return;
715 }
716 switch (delta->af)
717 {
718 case AF_INET:
719 alen = sizeof(struct sockaddr_in);
720 GNUNET_memcpy (&v4,
721 &delta->addr,
722 alen);
723
724 /* Check for client notifications */
725 for (unsigned int i = 0; i < ch->num_caddrs; i++)
726 {
727 const struct sockaddr_in *c4;
728
729 if (AF_INET != ch->caddrs[i].ss.ss_family)
730 continue; /* IPv4 not relevant */
731 c4 = (const struct sockaddr_in *) &ch->caddrs[i].ss;
733 (0 == c4->sin_addr.s_addr) &&
734 match_ipv4 ("127.0.0.1", &v4.sin_addr, 8))
735 continue; /* bound to "any", and this is loopback: nobody else
736 can reach it, so do not let it end up in a HELLO */
737 if (match_ipv4 ("127.0.0.1", &c4->sin_addr, 8) &&
738 (0 != c4->sin_addr.s_addr) &&
739 (! match_ipv4 ("127.0.0.1", &v4.sin_addr, 8)))
740 continue; /* bound to loopback, but this is not loopback */
741 if ((! match_ipv4 ("127.0.0.1", &c4->sin_addr, 8)) &&
742 match_ipv4 ("127.0.0.1", &v4.sin_addr, 8))
743 continue; /* bound to non-loopback, but this is loopback */
744 if ((0 != (delta->ac & GNUNET_NAT_AC_EXTERN)) &&
745 (0 != c4->sin_addr.s_addr) &&
746 (! is_nat_v4 (&v4.sin_addr)))
747 continue; /* based on external-IP, but this IP is not
748 from private address range. */
749 if ((0 != GNUNET_memcmp (&v4.sin_addr,
750 &c4->sin_addr)) &&
751 (0 != c4->sin_addr.s_addr) &&
752 (! is_nat_v4 (&c4->sin_addr)))
753 continue; /* this IP is not from private address range,
754 and IP does not match. */
755
756 /* OK, IP seems relevant, notify client */
757 if (0 == htons (v4.sin_port))
758 v4.sin_port = c4->sin_port;
759 notify_client (delta->ac,
760 ch,
761 add,
762 &v4,
763 alen);
764 }
765 break;
766
767 case AF_INET6:
768 alen = sizeof(struct sockaddr_in6);
769 GNUNET_memcpy (&v6,
770 &delta->addr,
771 alen);
772 for (unsigned int i = 0; i < ch->num_caddrs; i++)
773 {
774 const struct sockaddr_in6 *c6;
775
776 if (AF_INET6 != ch->caddrs[i].ss.ss_family)
777 continue; /* IPv4 not relevant */
778 c6 = (const struct sockaddr_in6 *) &ch->caddrs[i].ss;
780 (0 == GNUNET_memcmp (&c6->sin6_addr,
781 &in6addr_any)) &&
782 (match_ipv6 ("::1", &v6.sin6_addr, 128) ||
783 match_ipv6 ("fe80::", &v6.sin6_addr, 10)))
784 continue; /* bound to "any", and this address is either loopback
785 or link-local. Neither is reachable from another
786 host -- a link-local address is not even usable
787 without the scope identifier, which does not
788 survive the trip through a HELLO. */
789 if (match_ipv6 ("::1", &c6->sin6_addr, 128) &&
790 (0 != GNUNET_memcmp (&c6->sin6_addr,
791 &in6addr_any)) &&
792 (! match_ipv6 ("::1", &v6.sin6_addr, 128)))
793 continue; /* bound to loopback, but this is not loopback */
794 if ((! match_ipv6 ("::1", &c6->sin6_addr, 128)) &&
795 match_ipv6 ("::1", &v6.sin6_addr, 128))
796 continue; /* bound to non-loopback, but this is loopback */
797 if ((0 != (delta->ac & GNUNET_NAT_AC_EXTERN)) &&
798 (0 != GNUNET_memcmp (&c6->sin6_addr,
799 &in6addr_any)) &&
800 (! is_nat_v6 (&v6.sin6_addr)))
801 continue; /* based on external-IP, but this IP is not
802 from private address range. */
803 if ((0 != GNUNET_memcmp (&v6.sin6_addr,
804 &c6->sin6_addr)) &&
805 (0 != GNUNET_memcmp (&c6->sin6_addr,
806 &in6addr_any)) &&
807 (! is_nat_v6 (&c6->sin6_addr)))
808 continue; /* this IP is not from private address range,
809 and IP does not match. */
810 if ((match_ipv6 ("fe80::", &c6->sin6_addr, 10)) &&
811 (0 != GNUNET_memcmp (&c6->sin6_addr,
812 &in6addr_any)) &&
813 (0 != GNUNET_memcmp (&v6.sin6_addr,
814 &c6->sin6_addr)) &&
815 (0 == (delta->ac & GNUNET_NAT_AC_EXTERN)))
816 continue; /* client bound to link-local, and the other address
817 does not match and is not an external IP */
818
819 /* OK, IP seems relevant, notify client */
820 if (0 == htons (v6.sin6_port))
821 v6.sin6_port = c6->sin6_port;
822 notify_client (delta->ac,
823 ch,
824 add,
825 &v6,
826 alen);
827 }
828 break;
829
830 default:
831 GNUNET_break (0);
832 return;
833 }
834}
835
836
844static void
846 int add)
847{
848 for (struct ClientHandle *ch = ch_head;
849 NULL != ch;
850 ch = ch->next)
852 ch,
853 add);
854}
855
856
865static void
867 const struct in_addr *v4,
868 int add)
869{
870 struct ClientHandle *ch = cls;
871 struct sockaddr_in sa;
872 int have_v4;
873
874 /* (0) check if this impacts 'hole_external' */
875 if ((NULL != ch->hole_external) &&
876 (0 == strcasecmp (ch->hole_external,
877 "AUTO")))
878 {
879 struct LocalAddressList lal;
880 struct sockaddr_in *s4;
881
883 "Detected eternal IP, can now back-fill AUTO:%u in hole punching specification of `%s'\n",
884 (unsigned int) ch->ext_dns_port,
885 ch->section_name);
886 memset (&lal, 0, sizeof(lal));
887 s4 = (struct sockaddr_in *) &lal.addr;
888 s4->sin_family = AF_INET;
889 s4->sin_port = htons (ch->ext_dns_port);
890 s4->sin_addr = *v4;
891 lal.af = AF_INET;
894 ch,
895 add);
896 }
897
898 /* (1) check if client cares. */
899 if (! ch->natted_address)
900 return;
901 have_v4 = GNUNET_NO;
902 for (unsigned int i = 0; i < ch->num_caddrs; i++)
903 {
904 const struct sockaddr_storage *ss = &ch->caddrs[i].ss;
905
906 if (AF_INET != ss->ss_family)
907 continue;
908 have_v4 = GNUNET_YES;
909 break;
910 }
911 if (GNUNET_NO == have_v4)
912 return; /* IPv6-only */
913
914 /* (2) build address info */
915 memset (&sa,
916 0,
917 sizeof(sa));
918 sa.sin_family = AF_INET;
919 sa.sin_addr = *v4;
920 sa.sin_port = htons (0);
921
923 "Detected eternal IP %s, notifying client of external IP (without port)\n",
924 GNUNET_a2s ((const struct sockaddr *) &sa,
925 sizeof(sa)));
926 /* (3) notify client of change */
930 ch,
931 add,
932 &sa,
933 sizeof(sa));
934}
935
936
944static void
945reversal_callback (void *cls,
946 const struct sockaddr_in *ra)
947{
948 struct LocalAddressList *lal = cls;
949 const struct sockaddr_in *l4;
950
951 GNUNET_assert (AF_INET == lal->af);
952 l4 = (const struct sockaddr_in *) &lal->addr;
953 for (struct ClientHandle *ch = ch_head;
954 NULL != ch;
955 ch = ch->next)
956 {
958 struct GNUNET_MQ_Envelope *env;
959 int match;
960
961 /* Check if client is in applicable range for ICMP NAT traversal
962 for this local address */
963 if (! ch->natted_address)
964 continue;
965 match = GNUNET_NO;
966 for (unsigned int i = 0; i < ch->num_caddrs; i++)
967 {
968 struct ClientAddress *ca = &ch->caddrs[i];
969 const struct sockaddr_in *c4;
970
971 if (AF_INET != ca->ss.ss_family)
972 continue;
973 c4 = (const struct sockaddr_in *) &ca->ss;
974 if ((0 != c4->sin_addr.s_addr) &&
975 (l4->sin_addr.s_addr != c4->sin_addr.s_addr))
976 continue;
977 match = GNUNET_YES;
978 break;
979 }
980 if (! match)
981 continue;
982
983 /* Notify applicable client about connection reversal request */
984 env = GNUNET_MQ_msg_extra (crrm,
985 sizeof(struct sockaddr_in),
987 GNUNET_memcpy (&crrm[1],
988 ra,
989 sizeof(struct sockaddr_in));
991 env);
992 }
993}
994
995
1001static void
1002run_scan (void *cls)
1003{
1004 struct IfcProcContext ifc_ctx;
1005 int found;
1006 int have_nat;
1007 struct LocalAddressList *lnext;
1008
1010 &run_scan,
1011 NULL);
1012 memset (&ifc_ctx,
1013 0,
1014 sizeof(ifc_ctx));
1016 &ifc_ctx);
1017 /* remove addresses that disappeared */
1018 for (struct LocalAddressList *lal = lal_head;
1019 NULL != lal;
1020 lal = lnext)
1021 {
1022 lnext = lal->next;
1023 found = GNUNET_NO;
1024 for (struct LocalAddressList *pos = ifc_ctx.lal_head;
1025 NULL != pos;
1026 pos = pos->next)
1027 {
1028 if ((pos->af == lal->af) &&
1029 (0 == memcmp (&lal->addr,
1030 &pos->addr,
1031 (AF_INET == lal->af)
1032 ? sizeof(struct sockaddr_in)
1033 : sizeof(struct sockaddr_in6))))
1034 {
1035 found = GNUNET_YES;
1036 }
1037 }
1038 if (GNUNET_NO == found)
1039 {
1040 notify_clients (lal,
1041 GNUNET_NO);
1042 free_lal (lal);
1043 }
1044 }
1045
1046 /* add addresses that appeared */
1047 have_nat = GNUNET_NO;
1048 for (struct LocalAddressList *pos = ifc_ctx.lal_head;
1049 NULL != pos;
1050 pos = ifc_ctx.lal_head)
1051 {
1052 found = GNUNET_NO;
1053 if (GNUNET_NAT_AC_LAN == (GNUNET_NAT_AC_LAN & pos->ac))
1054 have_nat = GNUNET_YES;
1055 for (struct LocalAddressList *lal = lal_head;
1056 NULL != lal;
1057 lal = lal->next)
1058 {
1059 if ((pos->af == lal->af) &&
1060 (0 == memcmp (&lal->addr,
1061 &pos->addr,
1062 (AF_INET == lal->af)
1063 ? sizeof(struct sockaddr_in)
1064 : sizeof(struct sockaddr_in6))))
1065 found = GNUNET_YES;
1066 }
1068 ifc_ctx.lal_tail,
1069 pos);
1070 if (GNUNET_YES == found)
1071 {
1072 GNUNET_free (pos);
1073 }
1074 else
1075 {
1076 notify_clients (pos,
1077 GNUNET_YES);
1079 lal_tail,
1080 pos);
1081 if ((AF_INET == pos->af) &&
1082 (NULL == pos->hc) &&
1083 (0 != (GNUNET_NAT_AC_LAN & pos->ac)))
1084 {
1085 const struct sockaddr_in *s4
1086 = (const struct sockaddr_in *) &pos->addr;
1087
1089 "Found NATed local address %s, starting NAT server\n",
1090 GNUNET_a2s ((const struct sockaddr *) &pos->addr,
1091 sizeof(*s4)));
1092 pos->hc = GN_start_gnunet_nat_server_ (&s4->sin_addr,
1094 pos,
1095 cfg);
1096 }
1097 }
1098 }
1099 GN_nat_status_changed (have_nat);
1100}
1101
1102
1114static void
1115upnp_addr_change_cb (void *cls,
1116 int add_remove,
1117 const struct sockaddr *addr,
1118 socklen_t addrlen,
1120{
1121 struct ClientHandle *ch = cls;
1123
1124 switch (result)
1125 {
1127 GNUNET_assert (NULL != addr);
1128 break;
1129
1134 "Running upnpc failed: %d\n",
1135 result);
1136 return;
1137
1140 "external-ip binary not found\n");
1141 return;
1142
1145 "upnpc binary not found\n");
1146 return;
1147
1150 "external-ip binary could not be run\n");
1151 return;
1152
1155 "upnpc failed to create port mapping\n");
1156 return;
1157
1160 "Invalid output from upnpc\n");
1161 return;
1162
1165 "Invalid address returned by upnpc\n");
1166 return;
1167
1168 default:
1169 GNUNET_break (0); /* should not be possible */
1170 return;
1171 }
1172 switch (addr->sa_family)
1173 {
1174 case AF_INET:
1175 ac = is_nat_v4 (&((const struct sockaddr_in *) addr)->sin_addr)
1178 break;
1179
1180 case AF_INET6:
1181 ac = is_nat_v6 (&((const struct sockaddr_in6 *) addr)->sin6_addr)
1184 break;
1185
1186 default:
1187 GNUNET_break (0);
1188 return;
1189 }
1191 "upnp external address %s: %s\n",
1192 add_remove ? "added" : "removed",
1193 GNUNET_a2s (addr,
1194 addrlen));
1195 notify_client (ac,
1196 ch,
1197 add_remove,
1198 addr,
1199 addrlen);
1200}
1201
1202
1211static void
1212dyndns_lookup (void *cls);
1213
1214
1224static void
1225process_external_ip (void *cls,
1226 const struct sockaddr *addr,
1227 socklen_t addrlen)
1228{
1229 struct ClientHandle *ch = cls;
1230 struct LocalAddressList *lal;
1231 struct sockaddr_storage ss;
1232 struct sockaddr_in *v4;
1233 struct sockaddr_in6 *v6;
1234
1235 if (NULL == addr)
1236 {
1237 struct LocalAddressList *laln;
1238
1239 ch->ext_dns = NULL;
1240 ch->ext_dns_task
1243 ch);
1244 /* Current iteration is over, remove 'old' IPs now */
1245 for (lal = ch->ext_addr_head; NULL != lal; lal = laln)
1246 {
1247 laln = lal->next;
1248 if (GNUNET_YES == lal->old)
1249 {
1250 GNUNET_CONTAINER_DLL_remove (ch->ext_addr_head,
1251 ch->ext_addr_tail,
1252 lal);
1254 ch,
1255 GNUNET_NO);
1256 GNUNET_free (lal);
1257 }
1258 }
1259 return;
1260 }
1262 "Got IP `%s' for external address `%s'\n",
1264 addrlen),
1265 ch->hole_external);
1266
1267 /* build sockaddr storage with port number */
1268 memset (&ss,
1269 0,
1270 sizeof(ss));
1271 GNUNET_memcpy (&ss,
1272 addr,
1273 addrlen);
1274 switch (addr->sa_family)
1275 {
1276 case AF_INET:
1277 v4 = (struct sockaddr_in *) &ss;
1278 v4->sin_port = htons (ch->ext_dns_port);
1279 break;
1280
1281 case AF_INET6:
1282 v6 = (struct sockaddr_in6 *) &ss;
1283 v6->sin6_port = htons (ch->ext_dns_port);
1284 break;
1285
1286 default:
1287 GNUNET_break (0);
1288 return;
1289 }
1290 /* See if 'ss' matches any of our known addresses */
1291 for (lal = ch->ext_addr_head; NULL != lal; lal = lal->next)
1292 {
1293 if (GNUNET_NO == lal->old)
1294 continue; /* already processed, skip */
1295 if ((addr->sa_family == lal->addr.ss_family) &&
1296 (0 == memcmp (&ss,
1297 &lal->addr,
1298 addrlen)))
1299 {
1300 /* Address unchanged, remember so we do not remove */
1301 lal->old = GNUNET_NO;
1302 return; /* done here */
1303 }
1304 }
1305 /* notify client, and remember IP for later removal! */
1306 lal = GNUNET_new (struct LocalAddressList);
1307 lal->addr = ss;
1308 lal->af = ss.ss_family;
1310 GNUNET_CONTAINER_DLL_insert (ch->ext_addr_head,
1311 ch->ext_addr_tail,
1312 lal);
1314 ch,
1315 GNUNET_YES);
1316}
1317
1318
1327static void
1328dyndns_lookup (void *cls)
1329{
1330 struct ClientHandle *ch = cls;
1331 struct LocalAddressList *lal;
1332
1334 "Performing DNS lookup for punched hole given for `%s' as `%s:%u'\n",
1335 ch->section_name,
1336 ch->hole_external,
1337 (unsigned int) ch->ext_dns_port);
1338 for (lal = ch->ext_addr_head; NULL != lal; lal = lal->next)
1339 lal->old = GNUNET_YES;
1340 ch->ext_dns_task = NULL;
1341 ch->ext_dns = GNUNET_RESOLVER_ip_get (ch->hole_external,
1342 AF_UNSPEC,
1345 ch);
1346}
1347
1348
1360static void
1362{
1363 char *port;
1364 unsigned int pnum;
1365 struct sockaddr_in *s4;
1366 struct LocalAddressList *lal;
1367
1368 port = strrchr (ch->hole_external, ':');
1369 if (NULL == port)
1370 {
1372 _ ("Malformed punched hole specification `%s' (lacks port)\n"),
1373 ch->hole_external);
1374 return;
1375 }
1376 if ((1 != sscanf (port + 1,
1377 "%u",
1378 &pnum)) ||
1379 (pnum > 65535))
1380 {
1382 _ (
1383 "Invalid port number in punched hole specification `%s' (lacks port)\n"),
1384 port + 1);
1385 return;
1386 }
1387 ch->ext_dns_port = (uint16_t) pnum;
1388 *port = '\0';
1389
1390 lal = GNUNET_new (struct LocalAddressList);
1391 if ('[' == *ch->hole_external)
1392 {
1393 struct sockaddr_in6 *s6 = (struct sockaddr_in6 *) &lal->addr;
1394
1395 s6->sin6_family = AF_INET6;
1396 if (']' != (ch->hole_external[strlen (ch->hole_external) - 1]))
1397 {
1399 _ ("Malformed punched hole specification `%s' (lacks `]')\n"),
1400 ch->hole_external);
1401 GNUNET_free (lal);
1402 return;
1403 }
1404 ch->hole_external[strlen (ch->hole_external) - 1] = '\0';
1405 if (1 != inet_pton (AF_INET6,
1406 ch->hole_external + 1,
1407 &s6->sin6_addr))
1408 {
1410 _ (
1411 "Malformed punched hole specification `%s' (IPv6 address invalid)"),
1412 ch->hole_external + 1);
1413 GNUNET_free (lal);
1414 return;
1415 }
1416 s6->sin6_port = htons (ch->ext_dns_port);
1417 lal->af = AF_INET6;
1419 GNUNET_CONTAINER_DLL_insert (ch->ext_addr_head,
1420 ch->ext_addr_tail,
1421 lal);
1423 ch,
1424 GNUNET_YES);
1425 return;
1426 }
1427
1428 s4 = (struct sockaddr_in *) &lal->addr;
1429 s4->sin_family = AF_INET;
1430 if (1 == inet_pton (AF_INET,
1431 ch->hole_external,
1432 &s4->sin_addr))
1433 {
1435 "IPv4 punched hole given for `%s' via `%s:%u'\n",
1436 ch->section_name,
1437 ch->hole_external,
1438 (unsigned int) ch->ext_dns_port);
1439 s4->sin_port = htons (ch->ext_dns_port);
1440 lal->af = AF_INET;
1442 GNUNET_CONTAINER_DLL_insert (ch->ext_addr_head,
1443 ch->ext_addr_tail,
1444 lal);
1446 ch,
1447 GNUNET_YES);
1448 return;
1449 }
1450 if (0 == strcasecmp (ch->hole_external,
1451 "AUTO"))
1452 {
1453 /* handled in #notify_client_external_ipv4_change() */
1454 GNUNET_free (lal);
1455 return;
1456 }
1457 /* got a DNS name, trigger lookup! */
1458 GNUNET_free (lal);
1459 ch->ext_dns_task
1461 ch);
1462}
1463
1464
1472static void
1473handle_register (void *cls,
1474 const struct GNUNET_NAT_RegisterMessage *message)
1475{
1476 struct ClientHandle *ch = cls;
1477 const char *off;
1478 size_t left;
1479
1480 if ((0 != ch->proto) ||
1481 (NULL != ch->caddrs))
1482 {
1483 /* double registration not allowed */
1484 GNUNET_break (0);
1486 return;
1487 }
1488 ch->flags = message->flags;
1489 ch->proto = message->proto;
1490 ch->num_caddrs = ntohs (message->num_addrs);
1491 ch->caddrs = GNUNET_new_array (ch->num_caddrs,
1492 struct ClientAddress);
1493 left = ntohs (message->header.size) - sizeof(*message);
1494 off = (const char *) &message[1];
1495 for (unsigned int i = 0; i < ch->num_caddrs; i++)
1496 {
1497 const struct sockaddr *sa = (const struct sockaddr *) off;
1498 size_t alen;
1499 uint16_t port;
1500 int is_nat;
1501
1502 if (sizeof(sa_family_t) > left)
1503 {
1504 GNUNET_break (0);
1506 return;
1507 }
1508 is_nat = GNUNET_NO;
1509 switch (sa->sa_family)
1510 {
1511 case AF_INET:
1512 {
1513 struct sockaddr_in s4;
1514
1515 GNUNET_memcpy (&s4,
1516 off,
1517 sizeof(struct sockaddr_in));
1518 alen = sizeof(struct sockaddr_in);
1519 if (is_nat_v4 (&s4.sin_addr))
1520 is_nat = GNUNET_YES;
1521 port = ntohs (s4.sin_port);
1522 }
1523 break;
1524
1525 case AF_INET6:
1526 {
1527 struct sockaddr_in6 s6;
1528
1529 GNUNET_memcpy (&s6,
1530 off,
1531 sizeof(struct sockaddr_in6));
1532 alen = sizeof(struct sockaddr_in6);
1533 if (is_nat_v6 (&s6.sin6_addr))
1534 is_nat = GNUNET_YES;
1535 port = ntohs (s6.sin6_port);
1536 }
1537 break;
1538
1539#if AF_UNIX
1540 case AF_UNIX:
1541 alen = sizeof(struct sockaddr_un);
1542 port = 0;
1543 break;
1544#endif
1545 default:
1546 GNUNET_break (0);
1548 return;
1549 }
1550 /* store address */
1551 GNUNET_assert (alen <= left);
1552 GNUNET_assert (alen <= sizeof(struct sockaddr_storage));
1553 GNUNET_memcpy (&ch->caddrs[i].ss,
1554 off,
1555 alen);
1556
1557 /* If applicable, try UPNPC NAT punching */
1558 if ((is_nat) &&
1559 (enable_upnp) &&
1560 ((IPPROTO_TCP == ch->proto) ||
1561 (IPPROTO_UDP == ch->proto)))
1562 {
1563 ch->natted_address = GNUNET_YES;
1564 ch->caddrs[i].mh
1566 IPPROTO_TCP == ch->proto,
1568 ch);
1569 }
1570
1571 off += alen;
1572 }
1573
1574 ch->section_name
1575 = GNUNET_strndup (off,
1576 ntohs (message->str_len));
1578 "Received REGISTER message from client for subsystem `%s'\n",
1579 ch->section_name);
1580 if (GNUNET_OK ==
1582 ch->section_name,
1583 "HOLE_EXTERNAL",
1584 &ch->hole_external))
1586
1587 /* Actually send IP address list to client */
1588 for (struct LocalAddressList *lal = lal_head;
1589 NULL != lal;
1590 lal = lal->next)
1591 {
1593 ch,
1594 GNUNET_YES);
1595 }
1596 /* Also consider IPv4 determined by `external-ip` */
1597 ch->external_monitor
1599 ch);
1601}
1602
1603
1612static int
1613check_stun (void *cls,
1614 const struct GNUNET_NAT_HandleStunMessage *message)
1615{
1616 size_t sa_len = ntohs (message->sender_addr_size);
1617 size_t expect = sa_len + ntohs (message->payload_size);
1618
1619 if (ntohs (message->header.size) - sizeof(*message) != expect)
1620 {
1621 GNUNET_break (0);
1622 return GNUNET_SYSERR;
1623 }
1624 if (sa_len < sizeof(sa_family_t))
1625 {
1626 GNUNET_break (0);
1627 return GNUNET_SYSERR;
1628 }
1629 return GNUNET_OK;
1630}
1631
1632
1640static void
1641notify_clients_stun_change (const struct sockaddr_in *ip,
1642 int add)
1643{
1644 for (struct ClientHandle *ch = ch_head;
1645 NULL != ch;
1646 ch = ch->next)
1647 {
1648 struct sockaddr_in v4;
1650 struct GNUNET_MQ_Envelope *env;
1651
1652 if (! ch->natted_address)
1653 continue;
1654 v4 = *ip;
1655 v4.sin_port = htons (0);
1657 sizeof(v4),
1659 msg->add_remove = htonl ((int32_t) add);
1660 msg->addr_class = htonl (GNUNET_NAT_AC_EXTERN
1662 GNUNET_memcpy (&msg[1],
1663 &v4,
1664 sizeof(v4));
1666 env);
1667 }
1668}
1669
1670
1678static void
1679stun_ip_timeout (void *cls)
1680{
1681 struct StunExternalIP *se = cls;
1682
1683 se->timeout_task = NULL;
1685 GNUNET_NO);
1687 se_tail,
1688 se);
1689 GNUNET_free (se);
1690}
1691
1692
1700static void
1701handle_stun (void *cls,
1702 const struct GNUNET_NAT_HandleStunMessage *message)
1703{
1704 struct ClientHandle *ch = cls;
1705 const char *buf = (const char *) &message[1];
1706 const struct sockaddr *sa;
1707 const void *payload;
1708 size_t sa_len;
1709 size_t payload_size;
1710 struct sockaddr_in external_addr;
1711
1712 sa_len = ntohs (message->sender_addr_size);
1713 payload_size = ntohs (message->payload_size);
1714 sa = (const struct sockaddr *) &buf[0];
1715 payload = (const struct sockaddr *) &buf[sa_len];
1716 switch (sa->sa_family)
1717 {
1718 case AF_INET:
1719 if (sa_len != sizeof(struct sockaddr_in))
1720 {
1721 GNUNET_break (0);
1723 return;
1724 }
1725 break;
1726
1727 case AF_INET6:
1728 if (sa_len != sizeof(struct sockaddr_in6))
1729 {
1730 GNUNET_break (0);
1732 return;
1733 }
1734 break;
1735 }
1737 "Received HANDLE_STUN message from client\n");
1738 if (GNUNET_OK ==
1740 payload_size,
1741 &external_addr))
1742 {
1743 /* We now know that a server at "sa" claims that
1744 we are visible at IP "external_addr".
1745
1746 We should (for some fixed period of time) tell
1747 all of our clients that listen to a NAT'ed address
1748 that they might want to consider the given 'external_ip'
1749 as their public IP address (this includes TCP and UDP
1750 clients, even if only UDP sends STUN requests).
1751
1752 If we do not get a renewal, the "external_addr" should be
1753 removed again. The timeout frequency should be configurable
1754 (with a sane default), so that the UDP plugin can tell how
1755 often to re-request STUN.
1756 */struct StunExternalIP *se;
1757
1758 /* Check if we had a prior response from this STUN server */
1759 for (se = se_head; NULL != se; se = se->next)
1760 {
1761 if ((se->stun_server_addr_len != sa_len) ||
1762 (0 != memcmp (sa,
1763 &se->stun_server_addr,
1764 sa_len)))
1765 continue; /* different STUN server */
1766 if (0 != GNUNET_memcmp (&external_addr,
1767 &se->external_addr))
1768 {
1769 /* external IP changed, update! */
1771 GNUNET_NO);
1774 GNUNET_YES);
1775 }
1776 /* update timeout */
1778 se->timeout_task
1781 se);
1782 return;
1783 }
1784 /* STUN server is completely new, create fresh entry */
1785 se = GNUNET_new (struct StunExternalIP);
1788 sa,
1789 sa_len);
1790 se->stun_server_addr_len = sa_len;
1793 se);
1795 se_tail,
1796 se);
1798 GNUNET_NO);
1799 }
1801}
1802
1803
1813static int
1815 const struct
1817 message)
1818{
1819 size_t expect;
1820
1821 expect = ntohs (message->local_addr_size)
1822 + ntohs (message->remote_addr_size);
1823 if (ntohs (message->header.size) - sizeof(*message) != expect)
1824 {
1825 GNUNET_break (0);
1826 return GNUNET_SYSERR;
1827 }
1828 return GNUNET_OK;
1829}
1830
1831
1839static void
1841 void *cls,
1842 const struct GNUNET_NAT_RequestConnectionReversalMessage *message)
1843{
1844 struct ClientHandle *ch = cls;
1845 const char *buf = (const char *) &message[1];
1846 size_t local_sa_len = ntohs (message->local_addr_size);
1847 size_t remote_sa_len = ntohs (message->remote_addr_size);
1848 struct sockaddr_in l4;
1849 struct sockaddr_in r4;
1850 int ret;
1851
1853 "Received REQUEST CONNECTION REVERSAL message from client\n");
1854 if (local_sa_len != sizeof(struct sockaddr_in))
1855 {
1856 GNUNET_break_op (0);
1858 return;
1859 }
1860 if (remote_sa_len != sizeof(struct sockaddr_in))
1861 {
1862 GNUNET_break_op (0);
1864 return;
1865 }
1866 GNUNET_memcpy (&l4,
1867 buf,
1868 sizeof(struct sockaddr_in));
1869 GNUNET_break_op (AF_INET == l4.sin_family);
1870 buf += sizeof(struct sockaddr_in);
1871 GNUNET_memcpy (&r4,
1872 buf,
1873 sizeof(struct sockaddr_in));
1874 GNUNET_break_op (AF_INET == r4.sin_family);
1875 ret = GN_request_connection_reversal (&l4.sin_addr,
1876 ntohs (l4.sin_port),
1877 &r4.sin_addr,
1878 cfg);
1879 if (GNUNET_OK != ret)
1881 _ ("Connection reversal request failed\n"));
1883}
1884
1885
1894static enum GNUNET_GenericReturnValue
1896 void *cls,
1897 const struct GNUNET_NAT_AddGlobalAddressMessage *message)
1898{
1899 // const char *buf = (const char *) &message[1];
1900 // uint16_t blen = ntohs (message->address_length);
1901 size_t left = ntohs (message->header.size) - sizeof(*message);
1902
1903 if (left != ntohs (message->address_length))
1904 {
1905 GNUNET_break_op (0);
1906 return GNUNET_SYSERR;
1907 }
1908 /* if ('\0' != buf[blen - 1]) */
1909 /* { */
1910 /* GNUNET_break_op (0); */
1911 /* return GNUNET_SYSERR; */
1912 /* } */
1913 return GNUNET_OK;
1914}
1915
1916
1924static void
1926 void *cls,
1927 const struct GNUNET_NAT_AddGlobalAddressMessage *message)
1928{
1929 struct ClientHandle *ch = cls;
1930 const char *buf = (const char *) &message[1];
1931 size_t blen = ntohs (message->header.size) - sizeof(*message);
1932 struct sockaddr_in sockaddr_ipv4 = {
1933 .sin_family = AF_INET
1934 };
1935 char addr[INET_ADDRSTRLEN];
1936
1937 /* The address comes straight off the wire and is NOT 0-terminated (which
1938 is why the assertion that it was is commented out in
1939 #check_add_global_address()), while inet_pton() requires a C string:
1940 it used to be handed @e buf directly and so parsed whatever happened to
1941 follow in memory. Copy it out first. Anything too long to be an IPv4
1942 literal is not one, so the length check doubles as a fast reject. */
1943 if (blen >= sizeof(addr))
1944 {
1946 "Ignoring global address `%.*s': not an IPv4 address\n",
1947 (int) blen,
1948 buf);
1950 return;
1951 }
1952 GNUNET_memcpy (addr, buf, blen);
1953 addr[blen] = '\0';
1954 if (1 != inet_pton (AF_INET,
1955 addr,
1956 &sockaddr_ipv4.sin_addr))
1957 {
1958 /* Not a protocol violation: peers legitimately gossip IPv6 (and other)
1959 addresses, and this service only tracks IPv4 NAT state. This used to
1960 be a GNUNET_break(0), which turned every such peer into a steady
1961 stream of "Assertion failed" at ERROR level. */
1963 "Ignoring global address `%s': not an IPv4 address\n",
1964 addr);
1966 return;
1967 }
1968 notify_clients_stun_change (&sockaddr_ipv4,
1969 GNUNET_YES);
1971}
1972
1973
1979static void
1980shutdown_task (void *cls)
1981{
1982 struct StunExternalIP *se;
1983
1984 while (NULL != (se = se_head))
1985 {
1987 se_tail,
1988 se);
1990 GNUNET_free (se);
1991 }
1993 if (NULL != scan_task)
1994 {
1996 scan_task = NULL;
1997 }
1998 if (NULL != stats)
1999 {
2001 GNUNET_NO);
2002 stats = NULL;
2003 }
2004 destroy_lal ();
2005}
2006
2007
2015static void
2016run (void *cls,
2017 const struct GNUNET_CONFIGURATION_Handle *c,
2019{
2020 cfg = c;
2021 if (GNUNET_OK !=
2023 "NAT",
2024 "STUN_STALE",
2027
2030 "NAT",
2031 "RETURN_LOCAL_ADDRESSES");
2032 /* Check for UPnP */
2035 "NAT",
2036 "ENABLE_UPNP");
2037 if (GNUNET_YES == enable_upnp)
2038 {
2039 /* check if it works */
2040 if (GNUNET_SYSERR ==
2042 GNUNET_NO,
2043 NULL))
2044 {
2046 _ (
2047 "UPnP enabled in configuration, but UPnP client `upnpc` command not found, disabling UPnP\n"));
2049 }
2050 }
2051 if (GNUNET_OK !=
2053 "nat",
2054 "DYNDNS_FREQUENCY",
2057
2060 "NAT",
2061 "ENABLE_IPSCAN");
2062
2064 NULL);
2066 cfg);
2069 NULL);
2070}
2071
2072
2081static void *
2082client_connect_cb (void *cls,
2083 struct GNUNET_SERVICE_Client *c,
2084 struct GNUNET_MQ_Handle *mq)
2085{
2086 struct ClientHandle *ch;
2087
2088 ch = GNUNET_new (struct ClientHandle);
2089 ch->mq = mq;
2090 ch->client = c;
2092 ch_tail,
2093 ch);
2094 return ch;
2095}
2096
2097
2105static void
2106client_disconnect_cb (void *cls,
2107 struct GNUNET_SERVICE_Client *c,
2108 void *internal_cls)
2109{
2110 struct ClientHandle *ch = internal_cls;
2111 struct LocalAddressList *lal;
2112
2114 ch_tail,
2115 ch);
2116 for (unsigned int i = 0; i < ch->num_caddrs; i++)
2117 {
2118 if (NULL != ch->caddrs[i].mh)
2119 {
2120 GNUNET_NAT_mini_map_stop (ch->caddrs[i].mh);
2121 ch->caddrs[i].mh = NULL;
2122 }
2123 }
2124 GNUNET_free (ch->caddrs);
2125 while (NULL != (lal = ch->ext_addr_head))
2126 {
2127 GNUNET_CONTAINER_DLL_remove (ch->ext_addr_head,
2128 ch->ext_addr_tail,
2129 lal);
2130 GNUNET_free (lal);
2131 }
2132 if (NULL != ch->ext_dns_task)
2133 {
2134 GNUNET_SCHEDULER_cancel (ch->ext_dns_task);
2135 ch->ext_dns_task = NULL;
2136 }
2137 if (NULL != ch->external_monitor)
2138 {
2139 GN_external_ipv4_monitor_stop (ch->external_monitor);
2140 ch->external_monitor = NULL;
2141 }
2142 if (NULL != ch->ext_dns)
2143 {
2145 ch->ext_dns = NULL;
2146 }
2147 GNUNET_free (ch->hole_external);
2148 GNUNET_free (ch->section_name);
2149 GNUNET_free (ch);
2150}
2151
2152
2158 "nat",
2160 &run,
2163 NULL,
2164 GNUNET_MQ_hd_var_size (register,
2167 NULL),
2171 NULL),
2172 GNUNET_MQ_hd_var_size (request_connection_reversal,
2175 NULL),
2176 GNUNET_MQ_hd_var_size (add_global_address,
2179 NULL),
2181
2182
2183#if defined(__linux__) && defined(__GLIBC__)
2184#include <malloc.h>
2185
2186void __attribute__ ((constructor))
2187GNUNET_NATM_memory_init (void);
2188
2192void __attribute__ ((constructor))
2193GNUNET_NATM_memory_init (void)
2194{
2195 mallopt (M_TRIM_THRESHOLD, 4 * 1024);
2196 mallopt (M_TOP_PAD, 1 * 1024);
2197 malloc_trim (0);
2198}
2199
2200
2201#endif
2202
2203/* end of gnunet-service-nat.c */
struct GNUNET_MessageHeader * msg
Definition 005.c:2
struct GNUNET_MQ_Envelope * env
Definition 005.c:1
static int ret
Final status code.
Definition gnunet-arm.c:93
static uint16_t port
Port number.
Definition gnunet-bcd.c:146
static struct GNUNET_CADET_Channel * ch
Channel handle.
static struct GNUNET_CADET_Handle * mh
Cadet handle.
struct GNUNET_SCHEDULER_Task * shutdown_task
static char * name
Name (label) of the records to list.
static int add
Desired action is to add a record.
static int result
Global testing status.
static struct GNUNET_SERVICE_Handle * service
Handle to our service instance.
static unsigned long long payload
How much data are we currently storing in the database?
static void handle_stun(void *cls, const struct GNUNET_NAT_HandleStunMessage *message)
Handler for GNUNET_MESSAGE_TYPE_NAT_HANDLE_STUN message from client.
static int check_stun(void *cls, const struct GNUNET_NAT_HandleStunMessage *message)
Check validity of GNUNET_MESSAGE_TYPE_NAT_HANDLE_STUN message from client.
static struct ClientHandle * ch_head
Head of client DLL.
static struct StunExternalIP * se_head
Kept in a DLL.
static int return_local_addresses
Do we report addresses that are only meaningful on this host to clients that did not explicitly bind ...
static struct GNUNET_TIME_Relative dyndns_frequency
How often do we scan for changes in how our external (dyndns) hostname resolves?
static void upnp_addr_change_cb(void *cls, int add_remove, const struct sockaddr *addr, socklen_t addrlen, enum GNUNET_NAT_StatusCode result)
Function called whenever our set of external addresses as created by upnpc changes.
static enum GNUNET_GenericReturnValue check_add_global_address(void *cls, const struct GNUNET_NAT_AddGlobalAddressMessage *message)
Check validity of GNUNET_MESSAGE_TYPE_NAT_ADD_GLOBAL_ADDRESS message from client.
int enable_ipscan
Is IP Scanning enabled? GNUNET_YES if enabled, GNUNET_NO if disabled, without, only explicitly specif...
static void notify_clients_stun_change(const struct sockaddr_in *ip, int add)
Notify all clients about our external IP address as reported by the STUN server.
static struct GNUNET_STATISTICS_Handle * stats
Handle to the statistics service.
static const struct GNUNET_CONFIGURATION_Handle * cfg
Handle to our current configuration.
static void destroy_lal()
Free the DLL starting at lal_head.
static void notify_client_external_ipv4_change(void *cls, const struct in_addr *v4, int add)
Tell relevant client about a change in our external IPv4 address.
static int check_register(void *cls, const struct GNUNET_NAT_RegisterMessage *message)
Check validity of GNUNET_MESSAGE_TYPE_NAT_REGISTER message from client.
static void notify_client(enum GNUNET_NAT_AddressClass ac, struct ClientHandle *ch, int add, const void *addr, size_t addr_len)
Notify client about a change in the list of addresses this peer has.
static int match_ipv6(const char *network, const struct in6_addr *ip, uint8_t bits)
Check if ip is in network with bits netmask.
static void process_external_ip(void *cls, const struct sockaddr *addr, socklen_t addrlen)
Our (external) hostname was resolved.
static struct ClientHandle * ch_tail
Tail of client DLL.
static void notify_clients(struct LocalAddressList *delta, int add)
Notify all clients about a change in the list of addresses this peer has.
static void check_notify_client(struct LocalAddressList *delta, struct ClientHandle *ch, int add)
Check if we should bother to notify this client about this address change, and if so,...
static struct LocalAddressList * lal_head
Head of DLL of local addresses.
static void run_scan(void *cls)
Task we run periodically to scan for network interfaces.
static int match_ipv4(const char *network, const struct in_addr *ip, uint8_t bits)
Check if ip is in network with bits netmask.
static struct GNUNET_SCHEDULER_Task * scan_task
Task scheduled to periodically scan our network interfaces.
#define DYNDNS_FREQUENCY
How often do we scan for changes in how our external (dyndns) hostname resolves?
static void reversal_callback(void *cls, const struct sockaddr_in *ra)
We got a connection reversal request from another peer.
#define SCAN_FREQ
How often should we ask the OS about a list of active network interfaces?
static struct StunExternalIP * se_tail
Kept in a DLL.
static void handle_register(void *cls, const struct GNUNET_NAT_RegisterMessage *message)
Handler for GNUNET_MESSAGE_TYPE_NAT_REGISTER message from client.
static void stun_ip_timeout(void *cls)
Function to be called when we decide that an external IP address as told to us by a STUN server has g...
static void run(void *cls, const struct GNUNET_CONFIGURATION_Handle *c, struct GNUNET_SERVICE_Handle *service)
Setup NAT service.
static void lookup_hole_external(struct ClientHandle *ch)
Resolve the hole_external name to figure out our external address from a manually punched hole.
static int check_request_connection_reversal(void *cls, const struct GNUNET_NAT_RequestConnectionReversalMessage *message)
Check validity of GNUNET_MESSAGE_TYPE_NAT_REQUEST_CONNECTION_REVERSAL message from client.
static int ifc_proc(void *cls, const char *name, int isDefault, const struct sockaddr *addr, const struct sockaddr *broadcast_addr, const struct sockaddr *netmask, socklen_t addrlen)
Callback function invoked for each interface found.
static void handle_request_connection_reversal(void *cls, const struct GNUNET_NAT_RequestConnectionReversalMessage *message)
Handler for GNUNET_MESSAGE_TYPE_NAT_REQUEST_CONNECTION_REVERSAL message from client.
static void handle_add_global_address(void *cls, const struct GNUNET_NAT_AddGlobalAddressMessage *message)
Handle GNUNET_MESSAGE_TYPE_NAT_ADD_GLOBAL_ADDRESS message from client.
static void dyndns_lookup(void *cls)
Resolve the hole_external name to figure out our external address from a manually punched hole.
static void * client_connect_cb(void *cls, struct GNUNET_SERVICE_Client *c, struct GNUNET_MQ_Handle *mq)
Callback called when a client connects to the service.
static void client_disconnect_cb(void *cls, struct GNUNET_SERVICE_Client *c, void *internal_cls)
Callback called when a client disconnected from the service.
static int is_nat_v6(const struct in6_addr *ip)
Test if the given IPv6 address is in a known range for private networks.
static struct LocalAddressList * lal_tail
Tail of DLL of local addresses.
static void free_lal(struct LocalAddressList *lal)
Remove and free an entry from the lal_head DLL.
static int is_nat_v4(const struct in_addr *ip)
Test if the given IPv4 address is in a known range for private networks.
int enable_upnp
Is UPnP enabled? GNUNET_YES if enabled, GNUNET_NO if disabled, GNUNET_SYSERR if configuration enabled...
static struct GNUNET_TIME_Relative stun_stale_timeout
Timeout to use when STUN data is considered stale.
void GN_external_ipv4_monitor_stop(struct GN_ExternalIPMonitor *mon)
Stop calling monitor.
void GN_nat_status_changed(int have_nat)
We have changed our opinion about being NATed in the first place.
struct GN_ExternalIPMonitor * GN_external_ipv4_monitor_start(GN_NotifyExternalIPv4Change cb, void *cb_cls)
Start monitoring external IPv4 addresses.
int GN_request_connection_reversal(const struct in_addr *internal_address, uint16_t internal_port, const struct in_addr *remote_v4, const struct GNUNET_CONFIGURATION_Handle *cfg)
We want to connect to a peer that is behind NAT.
struct HelperContext * GN_start_gnunet_nat_server_(const struct in_addr *internal_address, GN_ReversalCallback cb, void *cb_cls, const struct GNUNET_CONFIGURATION_Handle *cfg)
Start the gnunet-helper-nat-server and process incoming requests.
void GN_stop_gnunet_nat_server_(struct HelperContext *h)
Start the gnunet-helper-nat-server and process incoming requests.
struct GNUNET_NAT_MiniHandle * GNUNET_NAT_mini_map_start(uint16_t port, int is_tcp, GNUNET_NAT_MiniAddressCallback ac, void *ac_cls)
Start mapping the given port using (mini)upnpc.
void GNUNET_NAT_mini_map_stop(struct GNUNET_NAT_MiniHandle *mini)
Remove a mapping created with (mini)upnpc.
int GNUNET_NAT_stun_handle_packet_(const void *data, size_t len, struct sockaddr_in *arg)
Handle an incoming STUN response.
struct GNUNET_PQ_ResultSpec __attribute__
enum GNUNET_GenericReturnValue GNUNET_CONFIGURATION_get_value_yesno(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option)
Get a configuration value that should be in a set of "YES" or "NO".
enum GNUNET_GenericReturnValue GNUNET_CONFIGURATION_get_value_time(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option, struct GNUNET_TIME_Relative *time)
Get a configuration value that should be a relative time.
enum GNUNET_GenericReturnValue GNUNET_CONFIGURATION_get_value_string(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option, char **value)
Get a configuration value that should be a string.
#define GNUNET_CONTAINER_DLL_remove(head, tail, element)
Remove an element from a DLL.
#define GNUNET_CONTAINER_DLL_insert(head, tail, element)
Insert an element at the head of a DLL.
#define GNUNET_log(kind,...)
#define GNUNET_memcmp(a, b)
Compare memory in a and b, where both must be of the same pointer type.
#define GNUNET_memcpy(dst, src, n)
Call memcpy() but check for n being 0 first.
GNUNET_GenericReturnValue
Named constants for return values.
uint16_t size
The length of the struct (in bytes, including the length field itself), in big-endian format.
@ GNUNET_OK
@ GNUNET_YES
@ GNUNET_NO
@ GNUNET_SYSERR
#define GNUNET_break_op(cond)
Use this for assertion violations caused by other peers (i.e.
#define GNUNET_assert(cond)
Use this for fatal errors that cannot be handled.
#define GNUNET_break(cond)
Use this for internal assertion violations that are not fatal (can be handled) but should not occur.
const char * GNUNET_a2s(const struct sockaddr *addr, socklen_t addrlen)
Convert a "struct sockaddr*" (IPv4 or IPv6 address) to a string (for printing debug messages).
@ GNUNET_ERROR_TYPE_WARNING
@ GNUNET_ERROR_TYPE_ERROR
@ GNUNET_ERROR_TYPE_MESSAGE
@ GNUNET_ERROR_TYPE_DEBUG
@ GNUNET_ERROR_TYPE_INFO
#define GNUNET_strndup(a, length)
Wrapper around GNUNET_xstrndup_.
#define GNUNET_new(type)
Allocate a struct or union of the given type.
#define GNUNET_malloc(size)
Wrapper around malloc.
#define GNUNET_new_array(n, type)
Allocate a size n array with structs or unions of the given type.
#define GNUNET_free(ptr)
Wrapper around free.
void GNUNET_MQ_send(struct GNUNET_MQ_Handle *mq, struct GNUNET_MQ_Envelope *ev)
Send a message with the given message queue.
Definition mq.c:337
#define GNUNET_MQ_handler_end()
End-marker for the handlers array.
#define GNUNET_MQ_msg_extra(mvar, esize, type)
Allocate an envelope, with extra space allocated after the space needed by the message struct.
#define GNUNET_MQ_hd_var_size(name, code, str, ctx)
GNUNET_NAT_StatusCode
Error Types for the NAT subsystem (which can then later be converted/resolved to a string)
GNUNET_NAT_AddressClass
Some addresses contain sensitive information or are not suitable for global distribution.
@ GNUNET_NAT_ERROR_UPNPC_NOT_FOUND
upnpc command not found
@ GNUNET_NAT_ERROR_UPNPC_TIMEOUT
‘upnpc’ command took too long, process killed
@ GNUNET_NAT_ERROR_SUCCESS
Just the default.
@ GNUNET_NAT_ERROR_EXTERNAL_IP_UTILITY_OUTPUT_INVALID
‘external-ip’ command output invalid
@ GNUNET_NAT_ERROR_UPNPC_FAILED
Failed to run upnpc command.
@ GNUNET_NAT_ERROR_EXTERNAL_IP_UTILITY_FAILED
Failed to run external-ip command.
@ GNUNET_NAT_ERROR_UPNPC_PORTMAP_FAILED
‘upnpc’ command failed to establish port mapping
@ GNUNET_NAT_ERROR_EXTERNAL_IP_UTILITY_NOT_FOUND
‘external-ip’ command not found
@ GNUNET_NAT_ERROR_IPC_FAILURE
IPC Failure.
@ GNUNET_NAT_ERROR_EXTERNAL_IP_ADDRESS_INVALID
"no valid address was returned by `external-ip'"
@ GNUNET_NAT_AC_LAN
Addresses useful in the local wired network, i.e.
@ GNUNET_NAT_AC_GLOBAL
Addresses that are global (i.e.
@ GNUNET_NAT_AC_PRIVATE
Flag for addresses that are highly sensitive (i.e.
@ GNUNET_NAT_AC_EXTERN
Addresses that should be our external IP address on the outside of a NAT.
@ GNUNET_NAT_AC_MANUAL
Addresses that were manually configured by the user.
@ GNUNET_NAT_AC_LOOPBACK
Loopback addresses, only useful under special circumstances.
const struct GNUNET_OS_ProjectData * GNUNET_OS_project_data_gnunet(void)
Return default project data used by 'libgnunetutil' for GNUnet.
void GNUNET_OS_network_interfaces_list(GNUNET_OS_NetworkInterfaceProcessor proc, void *proc_cls)
Enumerate all network interfaces.
Definition os_network.c:397
enum GNUNET_GenericReturnValue GNUNET_OS_check_helper_binary(const char *binary, bool check_suid, const char *params)
Check whether an executable exists and possibly if the suid bit is set on the file.
#define GNUNET_MESSAGE_TYPE_NAT_ADD_GLOBAL_ADDRESS
Message to ask NAT service to notify all clients about a new global address.
#define GNUNET_MESSAGE_TYPE_NAT_ADDRESS_CHANGE
Message to from NAT service notifying us that one of our addresses changed.
#define GNUNET_MESSAGE_TYPE_NAT_CONNECTION_REVERSAL_REQUESTED
Message to from NAT service notifying us that connection reversal was requested by another peer.
#define GNUNET_MESSAGE_TYPE_NAT_REQUEST_CONNECTION_REVERSAL
Message to ask NAT service to request connection reversal.
#define GNUNET_MESSAGE_TYPE_NAT_REGISTER
Message to ask NAT service to register a client.
#define GNUNET_MESSAGE_TYPE_NAT_HANDLE_STUN
Message to ask NAT service to handle a STUN packet.
struct GNUNET_RESOLVER_RequestHandle * GNUNET_RESOLVER_ip_get(const char *hostname, int af, struct GNUNET_TIME_Relative timeout, GNUNET_RESOLVER_AddressCallback callback, void *callback_cls)
Convert a string to one or more IP addresses.
void GNUNET_RESOLVER_request_cancel(struct GNUNET_RESOLVER_RequestHandle *rh)
Cancel a request that is still pending with the resolver.
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_shutdown(GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run on shutdown, that is when a CTRL-C signal is received,...
Definition scheduler.c:1345
void * GNUNET_SCHEDULER_cancel(struct GNUNET_SCHEDULER_Task *task)
Cancel the task with the specified identifier.
Definition scheduler.c:986
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_now(GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run as soon as possible.
Definition scheduler.c:1310
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_delayed(struct GNUNET_TIME_Relative delay, GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run with a specified delay.
Definition scheduler.c:1283
#define GNUNET_SERVICE_MAIN(pd, service_name, service_options, init_cb, connect_cb, disconnect_cb, cls,...)
Creates the "main" function for a GNUnet service.
void GNUNET_SERVICE_client_drop(struct GNUNET_SERVICE_Client *c)
Ask the server to disconnect from the given client.
Definition service.c:2463
void GNUNET_SERVICE_client_continue(struct GNUNET_SERVICE_Client *c)
Continue receiving further messages from the given client.
Definition service.c:2434
@ GNUNET_SERVICE_OPTION_NONE
Use defaults.
struct GNUNET_STATISTICS_Handle * GNUNET_STATISTICS_create(const char *subsystem, const struct GNUNET_CONFIGURATION_Handle *cfg)
Get handle for the statistics service.
void GNUNET_STATISTICS_destroy(struct GNUNET_STATISTICS_Handle *h, int sync_first)
Destroy a handle (free all state associated with it).
#define GNUNET_TIME_UNIT_HOURS
One hour.
#define GNUNET_TIME_UNIT_MINUTES
One minute.
GNUNET_NAT_RegisterFlags
Flags specifying the events this client would be interested in being told about.
Definition nat.h:72
@ GNUNET_NAT_RF_ADDRESSES
This client wants to be informed about changes to our applicable addresses.
Definition nat.h:82
#define _(String)
GNU gettext support macro.
Definition platform.h:179
static struct GNUNET_MQ_Handle * mq
Our connection to the resolver service, created on-demand, but then persists until error or shutdown.
static struct GNUNET_TIME_Relative delta
Definition speedup.c:36
Information we track per client address.
struct sockaddr_storage ss
Network address used by the client.
Struct containing information about a client, handle to connect to it, and any pending messages that ...
uint16_t num_caddrs
Number of addresses that this service is bound to.
enum GNUNET_NAT_RegisterFlags flags
What does this client care about?
struct LocalAddressList * ext_addr_tail
DLL of external IP addresses as given in hole_external.
uint8_t proto
Client's IPPROTO, e.g.
char * section_name
Name of the configuration section this client cares about.
struct ClientHandle * prev
Kept in a DLL.
struct ClientHandle * next
Kept in a DLL.
char * hole_external
External DNS name and port given by user due to manual hole punching.
int natted_address
Is any of the caddrs in a reserved subnet for NAT?
struct GNUNET_SERVICE_Client * client
The handle to this client.
struct ClientAddress * caddrs
Array of addresses used by the service.
uint16_t ext_dns_port
Port number we found in hole_external.
struct GNUNET_MQ_Handle * mq
The message queue to this client.
struct GNUNET_RESOLVER_RequestHandle * ext_dns
Handle for (DYN)DNS lookup of our external IP as given in hole_external.
struct LocalAddressList * ext_addr_head
DLL of external IP addresses as given in hole_external.
struct GN_ExternalIPMonitor * external_monitor
Handle for monitoring external IP changes.
struct GNUNET_SCHEDULER_Task * ext_dns_task
Task for periodically re-running the ext_dns DNS lookup.
struct GNUNET_MQ_Handle * mq
Message Queue for the channel (which we are implementing).
Definition cadet.h:142
Handle to a message queue.
Definition mq.c:87
Message sent by client to add a global address.
Definition nat.h:225
struct GNUNET_MessageHeader header
Header with type GNUNET_MESSAGE_TYPE_NAT_ADD_GLOBAL_ADDRESS.
Definition nat.h:229
unsigned int address_length
Length of the address following the struct, in NBO.
Definition nat.h:234
Service notifying the client about changes in the set of addresses it has.
Definition nat.h:202
Service telling a client that connection reversal was requested.
Definition nat.h:187
Client telling the service to (possibly) handle a STUN message.
Definition nat.h:135
struct GNUNET_MessageHeader header
Header with type GNUNET_MESSAGE_TYPE_NAT_HANDLE_STUN.
Definition nat.h:139
uint16_t payload_size
Number of bytes of payload included, in NBO.
Definition nat.h:149
uint16_t sender_addr_size
Size of the sender address included, in NBO.
Definition nat.h:144
Handle to a mapping created with upnpc.
Message sent by a client to register with its addresses.
Definition nat.h:95
uint16_t num_addrs
Number of addresses that this service is bound to that follow.
Definition nat.h:122
uint16_t str_len
Number of bytes in the string that follow which specifies a section name in the configuration.
Definition nat.h:115
struct GNUNET_MessageHeader header
Header with type GNUNET_MESSAGE_TYPE_NAT_REGISTER.
Definition nat.h:99
uint8_t flags
An enum GNUNET_NAT_RegisterFlags.
Definition nat.h:104
uint8_t proto
Client's IPPROTO, e.g.
Definition nat.h:109
Client asking the service to initiate connection reversal.
Definition nat.h:161
struct GNUNET_MessageHeader header
Header with type GNUNET_MESSAGE_TYPE_NAT_REQUEST_CONNECTION_REVERSAL.
Definition nat.h:165
uint16_t local_addr_size
Size of the local address included, in NBO.
Definition nat.h:170
uint16_t remote_addr_size
Size of the remote address included, in NBO.
Definition nat.h:175
Handle to a request given to the resolver.
Entry in list of pending tasks.
Definition scheduler.c:141
Handle to a client that is connected to a service.
Definition service.c:249
Handle to a service.
Definition service.c:116
Handle for the service.
Time for relative time used by GNUnet, in microseconds.
Handle to monitor for external IP changes.
Information we keep per NAT helper process.
Closure for ifc_proc.
struct LocalAddressList * lal_head
Head of DLL of local addresses.
struct LocalAddressList * lal_tail
Tail of DLL of local addresses.
List of local addresses this system has.
struct LocalAddressList * prev
Previous entry.
int old
GNUNET_YES if we saw this one in the previous iteration, but not in the current iteration and thus mi...
struct HelperContext * hc
Context for a gnunet-helper-nat-server used to listen for ICMP messages to this client for connection...
struct LocalAddressList * next
This is a linked list.
int af
Address family.
enum GNUNET_NAT_AddressClass ac
What type of address is this?
struct sockaddr_storage addr
The address itself (i.e.
External IP address as given to us via some STUN server.
struct GNUNET_SCHEDULER_Task * timeout_task
Task we run to remove this entry when it is stale.
size_t stun_server_addr_len
Number of bytes used in stun_server_addr.
struct sockaddr_in external_addr
Our external IP address as reported by the STUN server.
struct sockaddr_storage stun_server_addr
Address of the reporting STUN server.
struct StunExternalIP * next
Kept in a DLL.
struct StunExternalIP * prev
Kept in a DLL.

◆ DYNDNS_FREQUENCY

#define DYNDNS_FREQUENCY
Value:

How often do we scan for changes in how our external (dyndns) hostname resolves?

Definition at line 67 of file gnunet-service-nat.c.

Function Documentation

◆ free_lal()

static void free_lal ( struct LocalAddressList lal)
static

Remove and free an entry from the lal_head DLL.

Parameters
lalentry to free

Definition at line 357 of file gnunet-service-nat.c.

358{
360 lal_tail,
361 lal);
362 if (NULL != lal->hc)
363 {
365 "Lost NATed local address %s, stopping NAT server\n",
366 GNUNET_a2s ((const struct sockaddr *) &lal->addr,
367 sizeof(struct sockaddr_in)));
368
370 lal->hc = NULL;
371 }
372 GNUNET_free (lal);
373}

References LocalAddressList::addr, GN_stop_gnunet_nat_server_(), GNUNET_a2s(), GNUNET_CONTAINER_DLL_remove, GNUNET_ERROR_TYPE_MESSAGE, GNUNET_free, GNUNET_log, LocalAddressList::hc, lal_head, and lal_tail.

Referenced by destroy_lal(), and run_scan().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ destroy_lal()

static void destroy_lal ( )
static

Free the DLL starting at lal_head.

Definition at line 380 of file gnunet-service-nat.c.

381{
382 struct LocalAddressList *lal;
383
384 while (NULL != (lal = lal_head))
385 free_lal (lal);
386}

References free_lal(), and lal_head.

Referenced by shutdown_task().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ check_register()

static int check_register ( void *  cls,
const struct GNUNET_NAT_RegisterMessage message 
)
static

Check validity of GNUNET_MESSAGE_TYPE_NAT_REGISTER message from client.

Parameters
clsclient who sent the message
messagethe message received
Returns
GNUNET_OK if message is well-formed

Definition at line 398 of file gnunet-service-nat.c.

400{
401 uint16_t num_addrs = ntohs (message->num_addrs);
402 const char *off = (const char *) &message[1];
403 size_t left = ntohs (message->header.size) - sizeof(*message);
404
405 for (unsigned int i = 0; i < num_addrs; i++)
406 {
407 size_t alen;
408 const struct sockaddr *sa = (const struct sockaddr *) off;
409
410 if (sizeof(sa_family_t) > left)
411 {
412 GNUNET_break (0);
413 return GNUNET_SYSERR;
414 }
415 switch (sa->sa_family)
416 {
417 case AF_INET:
418 alen = sizeof(struct sockaddr_in);
419 break;
420
421 case AF_INET6:
422 alen = sizeof(struct sockaddr_in6);
423 break;
424
425#if AF_UNIX
426 case AF_UNIX:
427 alen = sizeof(struct sockaddr_un);
428 break;
429#endif
430 default:
431 GNUNET_break (0);
432 return GNUNET_SYSERR;
433 }
434 if (alen > left)
435 {
436 GNUNET_break (0);
437 return GNUNET_SYSERR;
438 }
439 off += alen;
440 left -= alen;
441 }
442 if (left != ntohs (message->str_len))
443 {
444 GNUNET_break (0);
445 return GNUNET_SYSERR;
446 }
447 return GNUNET_OK;
448}

References GNUNET_break, GNUNET_OK, GNUNET_SYSERR, GNUNET_NAT_RegisterMessage::header, GNUNET_NAT_RegisterMessage::num_addrs, GNUNET_MessageHeader::size, and GNUNET_NAT_RegisterMessage::str_len.

◆ match_ipv4()

static int match_ipv4 ( const char *  network,
const struct in_addr *  ip,
uint8_t  bits 
)
static

Check if ip is in network with bits netmask.

Parameters
networkto test
ipIP address to test
bitsbitmask for the network
Returns
GNUNET_YES if ip is in network

Definition at line 460 of file gnunet-service-nat.c.

463{
464 struct in_addr net;
465
466 if (0 == ip->s_addr)
467 return GNUNET_YES;
468 if (0 == bits)
469 return GNUNET_YES;
470 GNUNET_assert (1 == inet_pton (AF_INET,
471 network,
472 &net));
473 return ! ((ip->s_addr ^ net.s_addr) & htonl (0xFFFFFFFFu << (32 - bits)));
474}

References GNUNET_assert, and GNUNET_YES.

Referenced by check_notify_client(), ifc_proc(), and is_nat_v4().

Here is the caller graph for this function:

◆ match_ipv6()

static int match_ipv6 ( const char *  network,
const struct in6_addr *  ip,
uint8_t  bits 
)
static

Check if ip is in network with bits netmask.

Parameters
networkto test
ipIP address to test
bitsbitmask for the network
Returns
GNUNET_YES if ip is in network

Definition at line 486 of file gnunet-service-nat.c.

489{
490 struct in6_addr net;
491 struct in6_addr mask;
492 unsigned int off;
493
494 if (0 == bits)
495 return GNUNET_YES;
496 GNUNET_assert (1 == inet_pton (AF_INET6,
497 network,
498 &net));
499 memset (&mask, 0, sizeof(mask));
500 if (0 == GNUNET_memcmp (&mask,
501 ip))
502 return GNUNET_YES;
503 off = 0;
504 while (bits > 8)
505 {
506 mask.s6_addr[off++] = 0xFF;
507 bits -= 8;
508 }
509 while (bits > 0)
510 {
511 mask.s6_addr[off] = (mask.s6_addr[off] >> 1) + 0x80;
512 bits--;
513 }
514 for (unsigned j = 0; j < sizeof(struct in6_addr) / sizeof(uint32_t); j++)
515 if (((((uint32_t *) ip)[j] & ((uint32_t *) &mask)[j])) !=
516 (((uint32_t *) &net)[j] & ((int *) &mask)[j]))
517 return GNUNET_NO;
518 return GNUNET_YES;
519}

References GNUNET_assert, GNUNET_memcmp, GNUNET_NO, and GNUNET_YES.

Referenced by check_notify_client(), ifc_proc(), and is_nat_v6().

Here is the caller graph for this function:

◆ is_nat_v4()

static int is_nat_v4 ( const struct in_addr *  ip)
static

Test if the given IPv4 address is in a known range for private networks.

Parameters
ipaddress to test
Returns
GNUNET_YES if ip is in a NAT range

Definition at line 530 of file gnunet-service-nat.c.

531{
532 return
533 match_ipv4 ("10.0.0.0", ip, 8) || /* RFC 1918 */
534 match_ipv4 ("100.64.0.0", ip, 10) || /* CG-NAT, RFC 6598 */
535 match_ipv4 ("192.168.0.0", ip, 12) || /* RFC 1918 */
536 match_ipv4 ("169.254.0.0", ip, 16) || /* AUTO, RFC 3927 */
537 match_ipv4 ("172.16.0.0", ip, 16); /* RFC 1918 */
538}

References match_ipv4().

Referenced by check_notify_client(), handle_register(), ifc_proc(), notify_client_external_ipv4_change(), and upnp_addr_change_cb().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ is_nat_v6()

static int is_nat_v6 ( const struct in6_addr *  ip)
static

Test if the given IPv6 address is in a known range for private networks.

Parameters
ipaddress to test
Returns
GNUNET_YES if ip is in a NAT range

Definition at line 549 of file gnunet-service-nat.c.

550{
551 return
552 match_ipv6 ("fc00::", ip, 7) || /* RFC 4193 */
553 match_ipv6 ("fec0::", ip, 10) || /* RFC 3879 */
554 match_ipv6 ("fe80::", ip, 10); /* RFC 4291, link-local */
555}

References match_ipv6().

Referenced by check_notify_client(), handle_register(), ifc_proc(), and upnp_addr_change_cb().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ ifc_proc()

static int ifc_proc ( void *  cls,
const char *  name,
int  isDefault,
const struct sockaddr *  addr,
const struct sockaddr *  broadcast_addr,
const struct sockaddr *  netmask,
socklen_t  addrlen 
)
static

Callback function invoked for each interface found.

Adds them to our new address list.

Parameters
clsa struct IfcProcContext *
namename of the interface (can be NULL for unknown)
isDefaultis this presumably the default interface
addraddress of this interface (can be NULL for unknown or unassigned)
broadcast_addrthe broadcast address (can be NULL for unknown or unassigned)
netmaskthe network mask (can be NULL for unknown or unassigned)
addrlenlength of the address
Returns
GNUNET_OK to continue iteration, GNUNET_SYSERR to abort

Definition at line 589 of file gnunet-service-nat.c.

596{
597 struct IfcProcContext *ifc_ctx = cls;
598 struct LocalAddressList *lal;
599 size_t alen;
600 const struct in_addr *ip4;
601 const struct in6_addr *ip6;
603
604 switch (addr->sa_family)
605 {
606 case AF_INET:
607 alen = sizeof(struct sockaddr_in);
608 ip4 = &((const struct sockaddr_in *) addr)->sin_addr;
609 if (match_ipv4 ("127.0.0.0", ip4, 8))
611 else if (is_nat_v4 (ip4))
613 else
615 break;
616
617 case AF_INET6:
618 alen = sizeof(struct sockaddr_in6);
619 ip6 = &((const struct sockaddr_in6 *) addr)->sin6_addr;
620 if (match_ipv6 ("::1", ip6, 128))
622 else if (is_nat_v6 (ip6))
624 else
626 if ((ip6->s6_addr[11] == 0xFF) &&
627 (ip6->s6_addr[12] == 0xFE))
628 {
629 /* contains a MAC, be extra careful! */
631 }
632 break;
633
634#if AF_UNIX
635 case AF_UNIX:
636 GNUNET_break (0);
637 return GNUNET_OK;
638#endif
639 default:
640 GNUNET_break (0);
641 return GNUNET_OK;
642 }
643 lal = GNUNET_malloc (sizeof(*lal));
644 lal->af = addr->sa_family;
645 lal->ac = ac;
646 GNUNET_memcpy (&lal->addr,
647 addr,
648 alen);
650 ifc_ctx->lal_tail,
651 lal);
652 return GNUNET_OK;
653}

References LocalAddressList::ac, LocalAddressList::addr, LocalAddressList::af, GNUNET_break, GNUNET_CONTAINER_DLL_insert, GNUNET_malloc, GNUNET_memcpy, GNUNET_NAT_AC_GLOBAL, GNUNET_NAT_AC_LAN, GNUNET_NAT_AC_LOOPBACK, GNUNET_NAT_AC_PRIVATE, GNUNET_OK, is_nat_v4(), is_nat_v6(), IfcProcContext::lal_head, IfcProcContext::lal_tail, match_ipv4(), and match_ipv6().

Referenced by run_scan().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ notify_client()

static void notify_client ( enum GNUNET_NAT_AddressClass  ac,
struct ClientHandle ch,
int  add,
const void *  addr,
size_t  addr_len 
)
static

Notify client about a change in the list of addresses this peer has.

Parameters
acaddress class of the entry in the list that changed
chclient to contact
addGNUNET_YES to add, GNUNET_NO to remove
addrthe address that changed
addr_lennumber of bytes in addr

Definition at line 667 of file gnunet-service-nat.c.

672{
673 struct GNUNET_MQ_Envelope *env;
675
677 "Notifying client about %s of IP %s\n",
678 add ? "addition" : "removal",
679 GNUNET_a2s (addr,
680 addr_len));
682 addr_len,
684 msg->add_remove = htonl (add);
685 msg->addr_class = htonl (ac);
686 GNUNET_memcpy (&msg[1],
687 addr,
688 addr_len);
690 env);
691}

References add, ch, env, GNUNET_a2s(), GNUNET_ERROR_TYPE_DEBUG, GNUNET_log, GNUNET_memcpy, GNUNET_MESSAGE_TYPE_NAT_ADDRESS_CHANGE, GNUNET_MQ_msg_extra, GNUNET_MQ_send(), GNUNET_CADET_Channel::mq, and msg.

Referenced by check_notify_client(), notify_client_external_ipv4_change(), and upnp_addr_change_cb().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ check_notify_client()

static void check_notify_client ( struct LocalAddressList delta,
struct ClientHandle ch,
int  add 
)
static

Check if we should bother to notify this client about this address change, and if so, do it.

Parameters
deltathe entry in the list that changed
chclient to check
addGNUNET_YES to add, GNUNET_NO to remove

Definition at line 703 of file gnunet-service-nat.c.

706{
707 size_t alen;
708 struct sockaddr_in v4;
709 struct sockaddr_in6 v6;
710
711 if (0 == (ch->flags & GNUNET_NAT_RF_ADDRESSES))
712 {
714 "Not notifying client as it does not care about addresses\n");
715 return;
716 }
717 switch (delta->af)
718 {
719 case AF_INET:
720 alen = sizeof(struct sockaddr_in);
721 GNUNET_memcpy (&v4,
722 &delta->addr,
723 alen);
724
725 /* Check for client notifications */
726 for (unsigned int i = 0; i < ch->num_caddrs; i++)
727 {
728 const struct sockaddr_in *c4;
729
730 if (AF_INET != ch->caddrs[i].ss.ss_family)
731 continue; /* IPv4 not relevant */
732 c4 = (const struct sockaddr_in *) &ch->caddrs[i].ss;
734 (0 == c4->sin_addr.s_addr) &&
735 match_ipv4 ("127.0.0.1", &v4.sin_addr, 8))
736 continue; /* bound to "any", and this is loopback: nobody else
737 can reach it, so do not let it end up in a HELLO */
738 if (match_ipv4 ("127.0.0.1", &c4->sin_addr, 8) &&
739 (0 != c4->sin_addr.s_addr) &&
740 (! match_ipv4 ("127.0.0.1", &v4.sin_addr, 8)))
741 continue; /* bound to loopback, but this is not loopback */
742 if ((! match_ipv4 ("127.0.0.1", &c4->sin_addr, 8)) &&
743 match_ipv4 ("127.0.0.1", &v4.sin_addr, 8))
744 continue; /* bound to non-loopback, but this is loopback */
745 if ((0 != (delta->ac & GNUNET_NAT_AC_EXTERN)) &&
746 (0 != c4->sin_addr.s_addr) &&
747 (! is_nat_v4 (&v4.sin_addr)))
748 continue; /* based on external-IP, but this IP is not
749 from private address range. */
750 if ((0 != GNUNET_memcmp (&v4.sin_addr,
751 &c4->sin_addr)) &&
752 (0 != c4->sin_addr.s_addr) &&
753 (! is_nat_v4 (&c4->sin_addr)))
754 continue; /* this IP is not from private address range,
755 and IP does not match. */
756
757 /* OK, IP seems relevant, notify client */
758 if (0 == htons (v4.sin_port))
759 v4.sin_port = c4->sin_port;
760 notify_client (delta->ac,
761 ch,
762 add,
763 &v4,
764 alen);
765 }
766 break;
767
768 case AF_INET6:
769 alen = sizeof(struct sockaddr_in6);
770 GNUNET_memcpy (&v6,
771 &delta->addr,
772 alen);
773 for (unsigned int i = 0; i < ch->num_caddrs; i++)
774 {
775 const struct sockaddr_in6 *c6;
776
777 if (AF_INET6 != ch->caddrs[i].ss.ss_family)
778 continue; /* IPv4 not relevant */
779 c6 = (const struct sockaddr_in6 *) &ch->caddrs[i].ss;
781 (0 == GNUNET_memcmp (&c6->sin6_addr,
782 &in6addr_any)) &&
783 (match_ipv6 ("::1", &v6.sin6_addr, 128) ||
784 match_ipv6 ("fe80::", &v6.sin6_addr, 10)))
785 continue; /* bound to "any", and this address is either loopback
786 or link-local. Neither is reachable from another
787 host -- a link-local address is not even usable
788 without the scope identifier, which does not
789 survive the trip through a HELLO. */
790 if (match_ipv6 ("::1", &c6->sin6_addr, 128) &&
791 (0 != GNUNET_memcmp (&c6->sin6_addr,
792 &in6addr_any)) &&
793 (! match_ipv6 ("::1", &v6.sin6_addr, 128)))
794 continue; /* bound to loopback, but this is not loopback */
795 if ((! match_ipv6 ("::1", &c6->sin6_addr, 128)) &&
796 match_ipv6 ("::1", &v6.sin6_addr, 128))
797 continue; /* bound to non-loopback, but this is loopback */
798 if ((0 != (delta->ac & GNUNET_NAT_AC_EXTERN)) &&
799 (0 != GNUNET_memcmp (&c6->sin6_addr,
800 &in6addr_any)) &&
801 (! is_nat_v6 (&v6.sin6_addr)))
802 continue; /* based on external-IP, but this IP is not
803 from private address range. */
804 if ((0 != GNUNET_memcmp (&v6.sin6_addr,
805 &c6->sin6_addr)) &&
806 (0 != GNUNET_memcmp (&c6->sin6_addr,
807 &in6addr_any)) &&
808 (! is_nat_v6 (&c6->sin6_addr)))
809 continue; /* this IP is not from private address range,
810 and IP does not match. */
811 if ((match_ipv6 ("fe80::", &c6->sin6_addr, 10)) &&
812 (0 != GNUNET_memcmp (&c6->sin6_addr,
813 &in6addr_any)) &&
814 (0 != GNUNET_memcmp (&v6.sin6_addr,
815 &c6->sin6_addr)) &&
816 (0 == (delta->ac & GNUNET_NAT_AC_EXTERN)))
817 continue; /* client bound to link-local, and the other address
818 does not match and is not an external IP */
819
820 /* OK, IP seems relevant, notify client */
821 if (0 == htons (v6.sin6_port))
822 v6.sin6_port = c6->sin6_port;
823 notify_client (delta->ac,
824 ch,
825 add,
826 &v6,
827 alen);
828 }
829 break;
830
831 default:
832 GNUNET_break (0);
833 return;
834 }
835}

References add, ch, delta, GNUNET_break, GNUNET_ERROR_TYPE_DEBUG, GNUNET_log, GNUNET_memcmp, GNUNET_memcpy, GNUNET_NAT_AC_EXTERN, GNUNET_NAT_RF_ADDRESSES, GNUNET_YES, is_nat_v4(), is_nat_v6(), match_ipv4(), match_ipv6(), notify_client(), and return_local_addresses.

Referenced by handle_register(), lookup_hole_external(), notify_client_external_ipv4_change(), notify_clients(), and process_external_ip().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ notify_clients()

static void notify_clients ( struct LocalAddressList delta,
int  add 
)
static

Notify all clients about a change in the list of addresses this peer has.

Parameters
deltathe entry in the list that changed
addGNUNET_YES to add, GNUNET_NO to remove

Definition at line 846 of file gnunet-service-nat.c.

848{
849 for (struct ClientHandle *ch = ch_head;
850 NULL != ch;
851 ch = ch->next)
853 ch,
854 add);
855}

References add, ch, ch_head, check_notify_client(), and delta.

Referenced by run_scan().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ notify_client_external_ipv4_change()

static void notify_client_external_ipv4_change ( void *  cls,
const struct in_addr *  v4,
int  add 
)
static

Tell relevant client about a change in our external IPv4 address.

Parameters
clsclient to check if it cares and possibly notify
v4the external address that changed
addGNUNET_YES to add, GNUNET_NO to remove

Definition at line 867 of file gnunet-service-nat.c.

870{
871 struct ClientHandle *ch = cls;
872 struct sockaddr_in sa;
873 int have_v4;
874
875 /* (0) check if this impacts 'hole_external' */
876 if ((NULL != ch->hole_external) &&
877 (0 == strcasecmp (ch->hole_external,
878 "AUTO")))
879 {
880 struct LocalAddressList lal;
881 struct sockaddr_in *s4;
882
884 "Detected eternal IP, can now back-fill AUTO:%u in hole punching specification of `%s'\n",
885 (unsigned int) ch->ext_dns_port,
886 ch->section_name);
887 memset (&lal, 0, sizeof(lal));
888 s4 = (struct sockaddr_in *) &lal.addr;
889 s4->sin_family = AF_INET;
890 s4->sin_port = htons (ch->ext_dns_port);
891 s4->sin_addr = *v4;
892 lal.af = AF_INET;
895 ch,
896 add);
897 }
898
899 /* (1) check if client cares. */
900 if (! ch->natted_address)
901 return;
902 have_v4 = GNUNET_NO;
903 for (unsigned int i = 0; i < ch->num_caddrs; i++)
904 {
905 const struct sockaddr_storage *ss = &ch->caddrs[i].ss;
906
907 if (AF_INET != ss->ss_family)
908 continue;
909 have_v4 = GNUNET_YES;
910 break;
911 }
912 if (GNUNET_NO == have_v4)
913 return; /* IPv6-only */
914
915 /* (2) build address info */
916 memset (&sa,
917 0,
918 sizeof(sa));
919 sa.sin_family = AF_INET;
920 sa.sin_addr = *v4;
921 sa.sin_port = htons (0);
922
924 "Detected eternal IP %s, notifying client of external IP (without port)\n",
925 GNUNET_a2s ((const struct sockaddr *) &sa,
926 sizeof(sa)));
927 /* (3) notify client of change */
931 ch,
932 add,
933 &sa,
934 sizeof(sa));
935}

References LocalAddressList::ac, add, LocalAddressList::addr, LocalAddressList::af, ch, check_notify_client(), GNUNET_a2s(), GNUNET_ERROR_TYPE_DEBUG, GNUNET_log, GNUNET_NAT_AC_EXTERN, GNUNET_NAT_AC_GLOBAL, GNUNET_NAT_AC_LAN, GNUNET_NAT_AC_MANUAL, GNUNET_NO, GNUNET_YES, is_nat_v4(), and notify_client().

Referenced by handle_register().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ reversal_callback()

static void reversal_callback ( void *  cls,
const struct sockaddr_in *  ra 
)
static

We got a connection reversal request from another peer.

Notify applicable clients.

Parameters
clsclosure with the struct LocalAddressList
raIP address of the peer who wants us to connect to it

Definition at line 946 of file gnunet-service-nat.c.

948{
949 struct LocalAddressList *lal = cls;
950 const struct sockaddr_in *l4;
951
952 GNUNET_assert (AF_INET == lal->af);
953 l4 = (const struct sockaddr_in *) &lal->addr;
954 for (struct ClientHandle *ch = ch_head;
955 NULL != ch;
956 ch = ch->next)
957 {
959 struct GNUNET_MQ_Envelope *env;
960 int match;
961
962 /* Check if client is in applicable range for ICMP NAT traversal
963 for this local address */
964 if (! ch->natted_address)
965 continue;
966 match = GNUNET_NO;
967 for (unsigned int i = 0; i < ch->num_caddrs; i++)
968 {
969 struct ClientAddress *ca = &ch->caddrs[i];
970 const struct sockaddr_in *c4;
971
972 if (AF_INET != ca->ss.ss_family)
973 continue;
974 c4 = (const struct sockaddr_in *) &ca->ss;
975 if ((0 != c4->sin_addr.s_addr) &&
976 (l4->sin_addr.s_addr != c4->sin_addr.s_addr))
977 continue;
978 match = GNUNET_YES;
979 break;
980 }
981 if (! match)
982 continue;
983
984 /* Notify applicable client about connection reversal request */
985 env = GNUNET_MQ_msg_extra (crrm,
986 sizeof(struct sockaddr_in),
988 GNUNET_memcpy (&crrm[1],
989 ra,
990 sizeof(struct sockaddr_in));
992 env);
993 }
994}

References LocalAddressList::addr, LocalAddressList::af, ch, ch_head, env, GNUNET_assert, GNUNET_memcpy, GNUNET_MESSAGE_TYPE_NAT_CONNECTION_REVERSAL_REQUESTED, GNUNET_MQ_msg_extra, GNUNET_MQ_send(), GNUNET_NO, GNUNET_YES, GNUNET_CADET_Channel::mq, and ClientAddress::ss.

Referenced by GNUNET_NAT_register(), and run_scan().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ run_scan()

static void run_scan ( void *  cls)
static

Task we run periodically to scan for network interfaces.

Parameters
clsNULL

Definition at line 1003 of file gnunet-service-nat.c.

1004{
1005 struct IfcProcContext ifc_ctx;
1006 int found;
1007 int have_nat;
1008 struct LocalAddressList *lnext;
1009
1011 &run_scan,
1012 NULL);
1013 memset (&ifc_ctx,
1014 0,
1015 sizeof(ifc_ctx));
1017 &ifc_ctx);
1018 /* remove addresses that disappeared */
1019 for (struct LocalAddressList *lal = lal_head;
1020 NULL != lal;
1021 lal = lnext)
1022 {
1023 lnext = lal->next;
1024 found = GNUNET_NO;
1025 for (struct LocalAddressList *pos = ifc_ctx.lal_head;
1026 NULL != pos;
1027 pos = pos->next)
1028 {
1029 if ((pos->af == lal->af) &&
1030 (0 == memcmp (&lal->addr,
1031 &pos->addr,
1032 (AF_INET == lal->af)
1033 ? sizeof(struct sockaddr_in)
1034 : sizeof(struct sockaddr_in6))))
1035 {
1036 found = GNUNET_YES;
1037 }
1038 }
1039 if (GNUNET_NO == found)
1040 {
1041 notify_clients (lal,
1042 GNUNET_NO);
1043 free_lal (lal);
1044 }
1045 }
1046
1047 /* add addresses that appeared */
1048 have_nat = GNUNET_NO;
1049 for (struct LocalAddressList *pos = ifc_ctx.lal_head;
1050 NULL != pos;
1051 pos = ifc_ctx.lal_head)
1052 {
1053 found = GNUNET_NO;
1054 if (GNUNET_NAT_AC_LAN == (GNUNET_NAT_AC_LAN & pos->ac))
1055 have_nat = GNUNET_YES;
1056 for (struct LocalAddressList *lal = lal_head;
1057 NULL != lal;
1058 lal = lal->next)
1059 {
1060 if ((pos->af == lal->af) &&
1061 (0 == memcmp (&lal->addr,
1062 &pos->addr,
1063 (AF_INET == lal->af)
1064 ? sizeof(struct sockaddr_in)
1065 : sizeof(struct sockaddr_in6))))
1066 found = GNUNET_YES;
1067 }
1068 GNUNET_CONTAINER_DLL_remove (ifc_ctx.lal_head,
1069 ifc_ctx.lal_tail,
1070 pos);
1071 if (GNUNET_YES == found)
1072 {
1073 GNUNET_free (pos);
1074 }
1075 else
1076 {
1077 notify_clients (pos,
1078 GNUNET_YES);
1080 lal_tail,
1081 pos);
1082 if ((AF_INET == pos->af) &&
1083 (NULL == pos->hc) &&
1084 (0 != (GNUNET_NAT_AC_LAN & pos->ac)))
1085 {
1086 const struct sockaddr_in *s4
1087 = (const struct sockaddr_in *) &pos->addr;
1088
1090 "Found NATed local address %s, starting NAT server\n",
1091 GNUNET_a2s ((const struct sockaddr *) &pos->addr,
1092 sizeof(*s4)));
1093 pos->hc = GN_start_gnunet_nat_server_ (&s4->sin_addr,
1095 pos,
1096 cfg);
1097 }
1098 }
1099 }
1100 GN_nat_status_changed (have_nat);
1101}

References cfg, free_lal(), GN_nat_status_changed(), GN_start_gnunet_nat_server_(), GNUNET_a2s(), GNUNET_CONTAINER_DLL_insert, GNUNET_CONTAINER_DLL_remove, GNUNET_ERROR_TYPE_DEBUG, GNUNET_free, GNUNET_log, GNUNET_NAT_AC_LAN, GNUNET_NO, GNUNET_OS_network_interfaces_list(), GNUNET_SCHEDULER_add_delayed(), GNUNET_YES, ifc_proc(), lal_head, IfcProcContext::lal_head, lal_tail, IfcProcContext::lal_tail, LocalAddressList::next, notify_clients(), reversal_callback(), run_scan(), SCAN_FREQ, and scan_task.

Referenced by run(), and run_scan().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ upnp_addr_change_cb()

static void upnp_addr_change_cb ( void *  cls,
int  add_remove,
const struct sockaddr *  addr,
socklen_t  addrlen,
enum GNUNET_NAT_StatusCode  result 
)
static

Function called whenever our set of external addresses as created by upnpc changes.

Parameters
clsclosure with our struct ClientHandle *
add_removeGNUNET_YES to mean the new public IP address, GNUNET_NO to mean the previous (now invalid) one, GNUNET_SYSERR indicates an error
addreither the previous or the new public IP address
addrlenactual length of the addr
resultGNUNET_NAT_ERROR_SUCCESS on success, otherwise the specific error code

Definition at line 1116 of file gnunet-service-nat.c.

1121{
1122 struct ClientHandle *ch = cls;
1124
1125 switch (result)
1126 {
1128 GNUNET_assert (NULL != addr);
1129 break;
1130
1135 "Running upnpc failed: %d\n",
1136 result);
1137 return;
1138
1141 "external-ip binary not found\n");
1142 return;
1143
1146 "upnpc binary not found\n");
1147 return;
1148
1151 "external-ip binary could not be run\n");
1152 return;
1153
1156 "upnpc failed to create port mapping\n");
1157 return;
1158
1161 "Invalid output from upnpc\n");
1162 return;
1163
1166 "Invalid address returned by upnpc\n");
1167 return;
1168
1169 default:
1170 GNUNET_break (0); /* should not be possible */
1171 return;
1172 }
1173 switch (addr->sa_family)
1174 {
1175 case AF_INET:
1176 ac = is_nat_v4 (&((const struct sockaddr_in *) addr)->sin_addr)
1179 break;
1180
1181 case AF_INET6:
1182 ac = is_nat_v6 (&((const struct sockaddr_in6 *) addr)->sin6_addr)
1185 break;
1186
1187 default:
1188 GNUNET_break (0);
1189 return;
1190 }
1192 "upnp external address %s: %s\n",
1193 add_remove ? "added" : "removed",
1194 GNUNET_a2s (addr,
1195 addrlen));
1196 notify_client (ac,
1197 ch,
1198 add_remove,
1199 addr,
1200 addrlen);
1201}

References ch, GNUNET_a2s(), GNUNET_assert, GNUNET_break, GNUNET_ERROR_TYPE_DEBUG, GNUNET_ERROR_TYPE_INFO, GNUNET_ERROR_TYPE_WARNING, GNUNET_log, GNUNET_NAT_AC_EXTERN, GNUNET_NAT_AC_LAN, GNUNET_NAT_ERROR_EXTERNAL_IP_ADDRESS_INVALID, GNUNET_NAT_ERROR_EXTERNAL_IP_UTILITY_FAILED, GNUNET_NAT_ERROR_EXTERNAL_IP_UTILITY_NOT_FOUND, GNUNET_NAT_ERROR_EXTERNAL_IP_UTILITY_OUTPUT_INVALID, GNUNET_NAT_ERROR_IPC_FAILURE, GNUNET_NAT_ERROR_SUCCESS, GNUNET_NAT_ERROR_UPNPC_FAILED, GNUNET_NAT_ERROR_UPNPC_NOT_FOUND, GNUNET_NAT_ERROR_UPNPC_PORTMAP_FAILED, GNUNET_NAT_ERROR_UPNPC_TIMEOUT, is_nat_v4(), is_nat_v6(), notify_client(), and result.

Referenced by handle_register().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ dyndns_lookup()

static void dyndns_lookup ( void *  cls)
static

Resolve the hole_external name to figure out our external address from a manually punched hole.

The port number has already been parsed, this task is responsible for periodically doing a DNS lookup.

Parameters
clsclient handle to act upon

The port number has already been parsed, this task is responsible for periodically doing a DNS lookup.

Parameters
chclient handle to act upon

Definition at line 1329 of file gnunet-service-nat.c.

1330{
1331 struct ClientHandle *ch = cls;
1332 struct LocalAddressList *lal;
1333
1335 "Performing DNS lookup for punched hole given for `%s' as `%s:%u'\n",
1336 ch->section_name,
1337 ch->hole_external,
1338 (unsigned int) ch->ext_dns_port);
1339 for (lal = ch->ext_addr_head; NULL != lal; lal = lal->next)
1340 lal->old = GNUNET_YES;
1341 ch->ext_dns_task = NULL;
1342 ch->ext_dns = GNUNET_RESOLVER_ip_get (ch->hole_external,
1343 AF_UNSPEC,
1346 ch);
1347}

References ch, GNUNET_ERROR_TYPE_DEBUG, GNUNET_log, GNUNET_RESOLVER_ip_get(), GNUNET_TIME_UNIT_MINUTES, GNUNET_YES, LocalAddressList::next, LocalAddressList::old, and process_external_ip().

Referenced by lookup_hole_external(), and process_external_ip().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ process_external_ip()

static void process_external_ip ( void *  cls,
const struct sockaddr *  addr,
socklen_t  addrlen 
)
static

Our (external) hostname was resolved.

Update lists of current external IPs (note that DNS may return multiple addresses!) and notify client accordingly.

Parameters
clsthe struct ClientHandle
addrNULL on error, otherwise result of DNS lookup
addrlennumber of bytes in addr

Definition at line 1226 of file gnunet-service-nat.c.

1229{
1230 struct ClientHandle *ch = cls;
1231 struct LocalAddressList *lal;
1232 struct sockaddr_storage ss;
1233 struct sockaddr_in *v4;
1234 struct sockaddr_in6 *v6;
1235
1236 if (NULL == addr)
1237 {
1238 struct LocalAddressList *laln;
1239
1240 ch->ext_dns = NULL;
1241 ch->ext_dns_task
1244 ch);
1245 /* Current iteration is over, remove 'old' IPs now */
1246 for (lal = ch->ext_addr_head; NULL != lal; lal = laln)
1247 {
1248 laln = lal->next;
1249 if (GNUNET_YES == lal->old)
1250 {
1251 GNUNET_CONTAINER_DLL_remove (ch->ext_addr_head,
1252 ch->ext_addr_tail,
1253 lal);
1255 ch,
1256 GNUNET_NO);
1257 GNUNET_free (lal);
1258 }
1259 }
1260 return;
1261 }
1263 "Got IP `%s' for external address `%s'\n",
1265 addrlen),
1266 ch->hole_external);
1267
1268 /* build sockaddr storage with port number */
1269 memset (&ss,
1270 0,
1271 sizeof(ss));
1272 GNUNET_memcpy (&ss,
1273 addr,
1274 addrlen);
1275 switch (addr->sa_family)
1276 {
1277 case AF_INET:
1278 v4 = (struct sockaddr_in *) &ss;
1279 v4->sin_port = htons (ch->ext_dns_port);
1280 break;
1281
1282 case AF_INET6:
1283 v6 = (struct sockaddr_in6 *) &ss;
1284 v6->sin6_port = htons (ch->ext_dns_port);
1285 break;
1286
1287 default:
1288 GNUNET_break (0);
1289 return;
1290 }
1291 /* See if 'ss' matches any of our known addresses */
1292 for (lal = ch->ext_addr_head; NULL != lal; lal = lal->next)
1293 {
1294 if (GNUNET_NO == lal->old)
1295 continue; /* already processed, skip */
1296 if ((addr->sa_family == lal->addr.ss_family) &&
1297 (0 == memcmp (&ss,
1298 &lal->addr,
1299 addrlen)))
1300 {
1301 /* Address unchanged, remember so we do not remove */
1302 lal->old = GNUNET_NO;
1303 return; /* done here */
1304 }
1305 }
1306 /* notify client, and remember IP for later removal! */
1307 lal = GNUNET_new (struct LocalAddressList);
1308 lal->addr = ss;
1309 lal->af = ss.ss_family;
1311 GNUNET_CONTAINER_DLL_insert (ch->ext_addr_head,
1312 ch->ext_addr_tail,
1313 lal);
1315 ch,
1316 GNUNET_YES);
1317}

References LocalAddressList::ac, LocalAddressList::addr, LocalAddressList::af, ch, check_notify_client(), dyndns_frequency, dyndns_lookup(), GNUNET_a2s(), GNUNET_break, GNUNET_CONTAINER_DLL_insert, GNUNET_CONTAINER_DLL_remove, GNUNET_ERROR_TYPE_DEBUG, GNUNET_free, GNUNET_log, GNUNET_memcpy, GNUNET_NAT_AC_GLOBAL, GNUNET_NAT_AC_MANUAL, GNUNET_new, GNUNET_NO, GNUNET_SCHEDULER_add_delayed(), GNUNET_YES, LocalAddressList::next, and LocalAddressList::old.

Referenced by dyndns_lookup().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ lookup_hole_external()

static void lookup_hole_external ( struct ClientHandle ch)
static

Resolve the hole_external name to figure out our external address from a manually punched hole.

The given name may be "AUTO" in which case we should use the IP address(es) we have from upnpc or other methods. The name can also be an IP address, in which case we do not need to do DNS resolution. Finally, we also need to parse the port number.

Parameters
chclient handle to act upon

Definition at line 1362 of file gnunet-service-nat.c.

1363{
1364 char *port;
1365 unsigned int pnum;
1366 struct sockaddr_in *s4;
1367 struct LocalAddressList *lal;
1368
1369 port = strrchr (ch->hole_external, ':');
1370 if (NULL == port)
1371 {
1373 _ ("Malformed punched hole specification `%s' (lacks port)\n"),
1374 ch->hole_external);
1375 return;
1376 }
1377 if ((1 != sscanf (port + 1,
1378 "%u",
1379 &pnum)) ||
1380 (pnum > 65535))
1381 {
1383 _ (
1384 "Invalid port number in punched hole specification `%s' (lacks port)\n"),
1385 port + 1);
1386 return;
1387 }
1388 ch->ext_dns_port = (uint16_t) pnum;
1389 *port = '\0';
1390
1391 lal = GNUNET_new (struct LocalAddressList);
1392 if ('[' == *ch->hole_external)
1393 {
1394 struct sockaddr_in6 *s6 = (struct sockaddr_in6 *) &lal->addr;
1395
1396 s6->sin6_family = AF_INET6;
1397 if (']' != (ch->hole_external[strlen (ch->hole_external) - 1]))
1398 {
1400 _ ("Malformed punched hole specification `%s' (lacks `]')\n"),
1401 ch->hole_external);
1402 GNUNET_free (lal);
1403 return;
1404 }
1405 ch->hole_external[strlen (ch->hole_external) - 1] = '\0';
1406 if (1 != inet_pton (AF_INET6,
1407 ch->hole_external + 1,
1408 &s6->sin6_addr))
1409 {
1411 _ (
1412 "Malformed punched hole specification `%s' (IPv6 address invalid)"),
1413 ch->hole_external + 1);
1414 GNUNET_free (lal);
1415 return;
1416 }
1417 s6->sin6_port = htons (ch->ext_dns_port);
1418 lal->af = AF_INET6;
1420 GNUNET_CONTAINER_DLL_insert (ch->ext_addr_head,
1421 ch->ext_addr_tail,
1422 lal);
1424 ch,
1425 GNUNET_YES);
1426 return;
1427 }
1428
1429 s4 = (struct sockaddr_in *) &lal->addr;
1430 s4->sin_family = AF_INET;
1431 if (1 == inet_pton (AF_INET,
1432 ch->hole_external,
1433 &s4->sin_addr))
1434 {
1436 "IPv4 punched hole given for `%s' via `%s:%u'\n",
1437 ch->section_name,
1438 ch->hole_external,
1439 (unsigned int) ch->ext_dns_port);
1440 s4->sin_port = htons (ch->ext_dns_port);
1441 lal->af = AF_INET;
1443 GNUNET_CONTAINER_DLL_insert (ch->ext_addr_head,
1444 ch->ext_addr_tail,
1445 lal);
1447 ch,
1448 GNUNET_YES);
1449 return;
1450 }
1451 if (0 == strcasecmp (ch->hole_external,
1452 "AUTO"))
1453 {
1454 /* handled in #notify_client_external_ipv4_change() */
1455 GNUNET_free (lal);
1456 return;
1457 }
1458 /* got a DNS name, trigger lookup! */
1459 GNUNET_free (lal);
1460 ch->ext_dns_task
1462 ch);
1463}

References _, LocalAddressList::ac, LocalAddressList::addr, LocalAddressList::af, ch, check_notify_client(), dyndns_lookup(), GNUNET_CONTAINER_DLL_insert, GNUNET_ERROR_TYPE_DEBUG, GNUNET_ERROR_TYPE_WARNING, GNUNET_free, GNUNET_log, GNUNET_NAT_AC_GLOBAL, GNUNET_NAT_AC_MANUAL, GNUNET_new, GNUNET_SCHEDULER_add_now(), GNUNET_YES, and port.

Referenced by handle_register().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ handle_register()

static void handle_register ( void *  cls,
const struct GNUNET_NAT_RegisterMessage message 
)
static

Handler for GNUNET_MESSAGE_TYPE_NAT_REGISTER message from client.

We remember the client for updates upon future NAT events.

Parameters
clsclient who sent the message
messagethe message received

Definition at line 1474 of file gnunet-service-nat.c.

1476{
1477 struct ClientHandle *ch = cls;
1478 const char *off;
1479 size_t left;
1480
1481 if ((0 != ch->proto) ||
1482 (NULL != ch->caddrs))
1483 {
1484 /* double registration not allowed */
1485 GNUNET_break (0);
1487 return;
1488 }
1489 ch->flags = message->flags;
1490 ch->proto = message->proto;
1491 ch->num_caddrs = ntohs (message->num_addrs);
1492 ch->caddrs = GNUNET_new_array (ch->num_caddrs,
1493 struct ClientAddress);
1494 left = ntohs (message->header.size) - sizeof(*message);
1495 off = (const char *) &message[1];
1496 for (unsigned int i = 0; i < ch->num_caddrs; i++)
1497 {
1498 const struct sockaddr *sa = (const struct sockaddr *) off;
1499 size_t alen;
1500 uint16_t port;
1501 int is_nat;
1502
1503 if (sizeof(sa_family_t) > left)
1504 {
1505 GNUNET_break (0);
1507 return;
1508 }
1509 is_nat = GNUNET_NO;
1510 switch (sa->sa_family)
1511 {
1512 case AF_INET:
1513 {
1514 struct sockaddr_in s4;
1515
1516 GNUNET_memcpy (&s4,
1517 off,
1518 sizeof(struct sockaddr_in));
1519 alen = sizeof(struct sockaddr_in);
1520 if (is_nat_v4 (&s4.sin_addr))
1521 is_nat = GNUNET_YES;
1522 port = ntohs (s4.sin_port);
1523 }
1524 break;
1525
1526 case AF_INET6:
1527 {
1528 struct sockaddr_in6 s6;
1529
1530 GNUNET_memcpy (&s6,
1531 off,
1532 sizeof(struct sockaddr_in6));
1533 alen = sizeof(struct sockaddr_in6);
1534 if (is_nat_v6 (&s6.sin6_addr))
1535 is_nat = GNUNET_YES;
1536 port = ntohs (s6.sin6_port);
1537 }
1538 break;
1539
1540#if AF_UNIX
1541 case AF_UNIX:
1542 alen = sizeof(struct sockaddr_un);
1543 port = 0;
1544 break;
1545#endif
1546 default:
1547 GNUNET_break (0);
1549 return;
1550 }
1551 /* store address */
1552 GNUNET_assert (alen <= left);
1553 GNUNET_assert (alen <= sizeof(struct sockaddr_storage));
1554 GNUNET_memcpy (&ch->caddrs[i].ss,
1555 off,
1556 alen);
1557
1558 /* If applicable, try UPNPC NAT punching */
1559 if ((is_nat) &&
1560 (enable_upnp) &&
1561 ((IPPROTO_TCP == ch->proto) ||
1562 (IPPROTO_UDP == ch->proto)))
1563 {
1564 ch->natted_address = GNUNET_YES;
1565 ch->caddrs[i].mh
1567 IPPROTO_TCP == ch->proto,
1569 ch);
1570 }
1571
1572 off += alen;
1573 }
1574
1575 ch->section_name
1576 = GNUNET_strndup (off,
1577 ntohs (message->str_len));
1579 "Received REGISTER message from client for subsystem `%s'\n",
1580 ch->section_name);
1581 if (GNUNET_OK ==
1583 ch->section_name,
1584 "HOLE_EXTERNAL",
1585 &ch->hole_external))
1587
1588 /* Actually send IP address list to client */
1589 for (struct LocalAddressList *lal = lal_head;
1590 NULL != lal;
1591 lal = lal->next)
1592 {
1594 ch,
1595 GNUNET_YES);
1596 }
1597 /* Also consider IPv4 determined by `external-ip` */
1598 ch->external_monitor
1600 ch);
1602}

References cfg, ch, check_notify_client(), enable_upnp, GNUNET_NAT_RegisterMessage::flags, GN_external_ipv4_monitor_start(), GNUNET_assert, GNUNET_break, GNUNET_CONFIGURATION_get_value_string(), GNUNET_ERROR_TYPE_DEBUG, GNUNET_log, GNUNET_memcpy, GNUNET_NAT_mini_map_start(), GNUNET_new_array, GNUNET_NO, GNUNET_OK, GNUNET_SERVICE_client_continue(), GNUNET_SERVICE_client_drop(), GNUNET_strndup, GNUNET_YES, GNUNET_NAT_RegisterMessage::header, is_nat_v4(), is_nat_v6(), lal_head, lookup_hole_external(), LocalAddressList::next, notify_client_external_ipv4_change(), GNUNET_NAT_RegisterMessage::num_addrs, port, GNUNET_NAT_RegisterMessage::proto, GNUNET_MessageHeader::size, GNUNET_NAT_RegisterMessage::str_len, and upnp_addr_change_cb().

Here is the call graph for this function:

◆ check_stun()

static int check_stun ( void *  cls,
const struct GNUNET_NAT_HandleStunMessage message 
)
static

Check validity of GNUNET_MESSAGE_TYPE_NAT_HANDLE_STUN message from client.

Parameters
clsclient who sent the message
messagethe message received
Returns
GNUNET_OK if message is well-formed

Definition at line 1614 of file gnunet-service-nat.c.

1616{
1617 size_t sa_len = ntohs (message->sender_addr_size);
1618 size_t expect = sa_len + ntohs (message->payload_size);
1619
1620 if (ntohs (message->header.size) - sizeof(*message) != expect)
1621 {
1622 GNUNET_break (0);
1623 return GNUNET_SYSERR;
1624 }
1625 if (sa_len < sizeof(sa_family_t))
1626 {
1627 GNUNET_break (0);
1628 return GNUNET_SYSERR;
1629 }
1630 return GNUNET_OK;
1631}

References GNUNET_break, GNUNET_OK, GNUNET_SYSERR, GNUNET_NAT_HandleStunMessage::header, GNUNET_NAT_HandleStunMessage::payload_size, GNUNET_NAT_HandleStunMessage::sender_addr_size, and GNUNET_MessageHeader::size.

◆ notify_clients_stun_change()

static void notify_clients_stun_change ( const struct sockaddr_in *  ip,
int  add 
)
static

Notify all clients about our external IP address as reported by the STUN server.

Parameters
ipthe external IP
addGNUNET_YES to add, GNUNET_NO to remove

Definition at line 1642 of file gnunet-service-nat.c.

1644{
1645 for (struct ClientHandle *ch = ch_head;
1646 NULL != ch;
1647 ch = ch->next)
1648 {
1649 struct sockaddr_in v4;
1651 struct GNUNET_MQ_Envelope *env;
1652
1653 if (! ch->natted_address)
1654 continue;
1655 v4 = *ip;
1656 v4.sin_port = htons (0);
1658 sizeof(v4),
1660 msg->add_remove = htonl ((int32_t) add);
1661 msg->addr_class = htonl (GNUNET_NAT_AC_EXTERN
1663 GNUNET_memcpy (&msg[1],
1664 &v4,
1665 sizeof(v4));
1667 env);
1668 }
1669}

References add, ch, ch_head, env, GNUNET_memcpy, GNUNET_MESSAGE_TYPE_NAT_ADDRESS_CHANGE, GNUNET_MQ_msg_extra, GNUNET_MQ_send(), GNUNET_NAT_AC_EXTERN, GNUNET_NAT_AC_GLOBAL, GNUNET_CADET_Channel::mq, and msg.

Referenced by handle_add_global_address(), handle_stun(), and stun_ip_timeout().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ stun_ip_timeout()

static void stun_ip_timeout ( void *  cls)
static

Function to be called when we decide that an external IP address as told to us by a STUN server has gone stale.

Parameters
clsthe struct StunExternalIP to drop

Definition at line 1680 of file gnunet-service-nat.c.

1681{
1682 struct StunExternalIP *se = cls;
1683
1684 se->timeout_task = NULL;
1686 GNUNET_NO);
1688 se_tail,
1689 se);
1690 GNUNET_free (se);
1691}

References StunExternalIP::external_addr, GNUNET_CONTAINER_DLL_remove, GNUNET_free, GNUNET_NO, notify_clients_stun_change(), se_head, se_tail, and StunExternalIP::timeout_task.

Referenced by handle_stun().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ handle_stun()

static void handle_stun ( void *  cls,
const struct GNUNET_NAT_HandleStunMessage message 
)
static

Handler for GNUNET_MESSAGE_TYPE_NAT_HANDLE_STUN message from client.

Parameters
clsclient who sent the message
messagethe message received

Definition at line 1702 of file gnunet-service-nat.c.

1704{
1705 struct ClientHandle *ch = cls;
1706 const char *buf = (const char *) &message[1];
1707 const struct sockaddr *sa;
1708 const void *payload;
1709 size_t sa_len;
1710 size_t payload_size;
1711 struct sockaddr_in external_addr;
1712
1713 sa_len = ntohs (message->sender_addr_size);
1714 payload_size = ntohs (message->payload_size);
1715 sa = (const struct sockaddr *) &buf[0];
1716 payload = (const struct sockaddr *) &buf[sa_len];
1717 switch (sa->sa_family)
1718 {
1719 case AF_INET:
1720 if (sa_len != sizeof(struct sockaddr_in))
1721 {
1722 GNUNET_break (0);
1724 return;
1725 }
1726 break;
1727
1728 case AF_INET6:
1729 if (sa_len != sizeof(struct sockaddr_in6))
1730 {
1731 GNUNET_break (0);
1733 return;
1734 }
1735 break;
1736 }
1738 "Received HANDLE_STUN message from client\n");
1739 if (GNUNET_OK ==
1741 payload_size,
1742 &external_addr))
1743 {
1744 /* We now know that a server at "sa" claims that
1745 we are visible at IP "external_addr".
1746
1747 We should (for some fixed period of time) tell
1748 all of our clients that listen to a NAT'ed address
1749 that they might want to consider the given 'external_ip'
1750 as their public IP address (this includes TCP and UDP
1751 clients, even if only UDP sends STUN requests).
1752
1753 If we do not get a renewal, the "external_addr" should be
1754 removed again. The timeout frequency should be configurable
1755 (with a sane default), so that the UDP plugin can tell how
1756 often to re-request STUN.
1757 */struct StunExternalIP *se;
1758
1759 /* Check if we had a prior response from this STUN server */
1760 for (se = se_head; NULL != se; se = se->next)
1761 {
1762 if ((se->stun_server_addr_len != sa_len) ||
1763 (0 != memcmp (sa,
1764 &se->stun_server_addr,
1765 sa_len)))
1766 continue; /* different STUN server */
1767 if (0 != GNUNET_memcmp (&external_addr,
1768 &se->external_addr))
1769 {
1770 /* external IP changed, update! */
1772 GNUNET_NO);
1775 GNUNET_YES);
1776 }
1777 /* update timeout */
1779 se->timeout_task
1782 se);
1783 return;
1784 }
1785 /* STUN server is completely new, create fresh entry */
1786 se = GNUNET_new (struct StunExternalIP);
1789 sa,
1790 sa_len);
1791 se->stun_server_addr_len = sa_len;
1794 se);
1796 se_tail,
1797 se);
1799 GNUNET_NO);
1800 }
1802}

References ch, StunExternalIP::external_addr, GNUNET_break, GNUNET_CONTAINER_DLL_insert, GNUNET_ERROR_TYPE_DEBUG, GNUNET_log, GNUNET_memcmp, GNUNET_memcpy, GNUNET_NAT_stun_handle_packet_(), GNUNET_new, GNUNET_NO, GNUNET_OK, GNUNET_SCHEDULER_add_delayed(), GNUNET_SCHEDULER_cancel(), GNUNET_SERVICE_client_continue(), GNUNET_SERVICE_client_drop(), GNUNET_YES, StunExternalIP::next, notify_clients_stun_change(), payload, GNUNET_NAT_HandleStunMessage::payload_size, se_head, se_tail, GNUNET_NAT_HandleStunMessage::sender_addr_size, stun_ip_timeout(), StunExternalIP::stun_server_addr, StunExternalIP::stun_server_addr_len, stun_stale_timeout, and StunExternalIP::timeout_task.

Here is the call graph for this function:

◆ check_request_connection_reversal()

static int check_request_connection_reversal ( void *  cls,
const struct GNUNET_NAT_RequestConnectionReversalMessage message 
)
static

Check validity of GNUNET_MESSAGE_TYPE_NAT_REQUEST_CONNECTION_REVERSAL message from client.

Parameters
clsclient who sent the message
messagethe message received
Returns
GNUNET_OK if message is well-formed

Definition at line 1815 of file gnunet-service-nat.c.

1819{
1820 size_t expect;
1821
1822 expect = ntohs (message->local_addr_size)
1823 + ntohs (message->remote_addr_size);
1824 if (ntohs (message->header.size) - sizeof(*message) != expect)
1825 {
1826 GNUNET_break (0);
1827 return GNUNET_SYSERR;
1828 }
1829 return GNUNET_OK;
1830}

References GNUNET_break, GNUNET_OK, GNUNET_SYSERR, GNUNET_NAT_RequestConnectionReversalMessage::header, GNUNET_NAT_RequestConnectionReversalMessage::local_addr_size, GNUNET_NAT_RequestConnectionReversalMessage::remote_addr_size, and GNUNET_MessageHeader::size.

◆ handle_request_connection_reversal()

static void handle_request_connection_reversal ( void *  cls,
const struct GNUNET_NAT_RequestConnectionReversalMessage message 
)
static

Handler for GNUNET_MESSAGE_TYPE_NAT_REQUEST_CONNECTION_REVERSAL message from client.

Parameters
clsclient who sent the message
messagethe message received

Definition at line 1841 of file gnunet-service-nat.c.

1844{
1845 struct ClientHandle *ch = cls;
1846 const char *buf = (const char *) &message[1];
1847 size_t local_sa_len = ntohs (message->local_addr_size);
1848 size_t remote_sa_len = ntohs (message->remote_addr_size);
1849 struct sockaddr_in l4;
1850 struct sockaddr_in r4;
1851 int ret;
1852
1854 "Received REQUEST CONNECTION REVERSAL message from client\n");
1855 if (local_sa_len != sizeof(struct sockaddr_in))
1856 {
1857 GNUNET_break_op (0);
1859 return;
1860 }
1861 if (remote_sa_len != sizeof(struct sockaddr_in))
1862 {
1863 GNUNET_break_op (0);
1865 return;
1866 }
1867 GNUNET_memcpy (&l4,
1868 buf,
1869 sizeof(struct sockaddr_in));
1870 GNUNET_break_op (AF_INET == l4.sin_family);
1871 buf += sizeof(struct sockaddr_in);
1872 GNUNET_memcpy (&r4,
1873 buf,
1874 sizeof(struct sockaddr_in));
1875 GNUNET_break_op (AF_INET == r4.sin_family);
1876 ret = GN_request_connection_reversal (&l4.sin_addr,
1877 ntohs (l4.sin_port),
1878 &r4.sin_addr,
1879 cfg);
1880 if (GNUNET_OK != ret)
1882 _ ("Connection reversal request failed\n"));
1884}

References _, cfg, ch, GN_request_connection_reversal(), GNUNET_break_op, GNUNET_ERROR_TYPE_DEBUG, GNUNET_ERROR_TYPE_WARNING, GNUNET_log, GNUNET_memcpy, GNUNET_OK, GNUNET_SERVICE_client_continue(), GNUNET_SERVICE_client_drop(), GNUNET_NAT_RequestConnectionReversalMessage::local_addr_size, GNUNET_NAT_RequestConnectionReversalMessage::remote_addr_size, and ret.

Here is the call graph for this function:

◆ check_add_global_address()

static enum GNUNET_GenericReturnValue check_add_global_address ( void *  cls,
const struct GNUNET_NAT_AddGlobalAddressMessage message 
)
static

Check validity of GNUNET_MESSAGE_TYPE_NAT_ADD_GLOBAL_ADDRESS message from client.

Parameters
clsclient who sent the message
messagethe message received
Returns
GNUNET_OK if message is well-formed

Definition at line 1896 of file gnunet-service-nat.c.

1899{
1900 // const char *buf = (const char *) &message[1];
1901 // uint16_t blen = ntohs (message->address_length);
1902 size_t left = ntohs (message->header.size) - sizeof(*message);
1903
1904 if (left != ntohs (message->address_length))
1905 {
1906 GNUNET_break_op (0);
1907 return GNUNET_SYSERR;
1908 }
1909 /* if ('\0' != buf[blen - 1]) */
1910 /* { */
1911 /* GNUNET_break_op (0); */
1912 /* return GNUNET_SYSERR; */
1913 /* } */
1914 return GNUNET_OK;
1915}

References GNUNET_NAT_AddGlobalAddressMessage::address_length, GNUNET_break_op, GNUNET_OK, GNUNET_SYSERR, GNUNET_NAT_AddGlobalAddressMessage::header, and GNUNET_MessageHeader::size.

◆ handle_add_global_address()

static void handle_add_global_address ( void *  cls,
const struct GNUNET_NAT_AddGlobalAddressMessage message 
)
static

Handle GNUNET_MESSAGE_TYPE_NAT_ADD_GLOBAL_ADDRESS message from client.

Parameters
clsclient who sent the message
messagethe message received

Definition at line 1926 of file gnunet-service-nat.c.

1929{
1930 struct ClientHandle *ch = cls;
1931 const char *buf = (const char *) &message[1];
1932 size_t blen = ntohs (message->header.size) - sizeof(*message);
1933 struct sockaddr_in sockaddr_ipv4 = {
1934 .sin_family = AF_INET
1935 };
1936 char addr[INET_ADDRSTRLEN];
1937
1938 /* The address comes straight off the wire and is NOT 0-terminated (which
1939 is why the assertion that it was is commented out in
1940 #check_add_global_address()), while inet_pton() requires a C string:
1941 it used to be handed @e buf directly and so parsed whatever happened to
1942 follow in memory. Copy it out first. Anything too long to be an IPv4
1943 literal is not one, so the length check doubles as a fast reject. */
1944 if (blen >= sizeof(addr))
1945 {
1947 "Ignoring global address `%.*s': not an IPv4 address\n",
1948 (int) blen,
1949 buf);
1951 return;
1952 }
1953 GNUNET_memcpy (addr, buf, blen);
1954 addr[blen] = '\0';
1955 if (1 != inet_pton (AF_INET,
1956 addr,
1957 &sockaddr_ipv4.sin_addr))
1958 {
1959 /* Not a protocol violation: peers legitimately gossip IPv6 (and other)
1960 addresses, and this service only tracks IPv4 NAT state. This used to
1961 be a GNUNET_break(0), which turned every such peer into a steady
1962 stream of "Assertion failed" at ERROR level. */
1964 "Ignoring global address `%s': not an IPv4 address\n",
1965 addr);
1967 return;
1968 }
1969 notify_clients_stun_change (&sockaddr_ipv4,
1970 GNUNET_YES);
1972}

References ch, GNUNET_ERROR_TYPE_DEBUG, GNUNET_log, GNUNET_memcpy, GNUNET_SERVICE_client_continue(), GNUNET_YES, GNUNET_NAT_AddGlobalAddressMessage::header, notify_clients_stun_change(), and GNUNET_MessageHeader::size.

Here is the call graph for this function:

◆ shutdown_task()

static void shutdown_task ( void *  cls)
static

Task run during shutdown.

Parameters
clsunused

Definition at line 1981 of file gnunet-service-nat.c.

1982{
1983 struct StunExternalIP *se;
1984
1985 while (NULL != (se = se_head))
1986 {
1988 se_tail,
1989 se);
1991 GNUNET_free (se);
1992 }
1994 if (NULL != scan_task)
1995 {
1997 scan_task = NULL;
1998 }
1999 if (NULL != stats)
2000 {
2002 GNUNET_NO);
2003 stats = NULL;
2004 }
2005 destroy_lal ();
2006}

References destroy_lal(), GN_nat_status_changed(), GNUNET_CONTAINER_DLL_remove, GNUNET_free, GNUNET_NO, GNUNET_SCHEDULER_cancel(), GNUNET_STATISTICS_destroy(), scan_task, se_head, se_tail, stats, and StunExternalIP::timeout_task.

Here is the call graph for this function:

◆ run()

static void run ( void *  cls,
const struct GNUNET_CONFIGURATION_Handle c,
struct GNUNET_SERVICE_Handle service 
)
static

Setup NAT service.

Parameters
clsclosure
cconfiguration to use
servicethe initialized service

Definition at line 2017 of file gnunet-service-nat.c.

2020{
2021 cfg = c;
2022 if (GNUNET_OK !=
2024 "NAT",
2025 "STUN_STALE",
2028
2031 "NAT",
2032 "RETURN_LOCAL_ADDRESSES");
2033 /* Check for UPnP */
2036 "NAT",
2037 "ENABLE_UPNP");
2038 if (GNUNET_YES == enable_upnp)
2039 {
2040 /* check if it works */
2041 if (GNUNET_SYSERR ==
2043 GNUNET_NO,
2044 NULL))
2045 {
2047 _ (
2048 "UPnP enabled in configuration, but UPnP client `upnpc` command not found, disabling UPnP\n"));
2050 }
2051 }
2052 if (GNUNET_OK !=
2054 "nat",
2055 "DYNDNS_FREQUENCY",
2058
2061 "NAT",
2062 "ENABLE_IPSCAN");
2063
2065 NULL);
2067 cfg);
2070 NULL);
2071}

References _, cfg, DYNDNS_FREQUENCY, dyndns_frequency, enable_ipscan, enable_upnp, GNUNET_CONFIGURATION_get_value_time(), GNUNET_CONFIGURATION_get_value_yesno(), GNUNET_ERROR_TYPE_ERROR, GNUNET_log, GNUNET_NO, GNUNET_OK, GNUNET_OS_check_helper_binary(), GNUNET_SCHEDULER_add_now(), GNUNET_SCHEDULER_add_shutdown(), GNUNET_STATISTICS_create(), GNUNET_SYSERR, GNUNET_TIME_UNIT_HOURS, GNUNET_YES, return_local_addresses, run_scan(), scan_task, shutdown_task, stats, and stun_stale_timeout.

Here is the call graph for this function:

◆ client_connect_cb()

static void * client_connect_cb ( void *  cls,
struct GNUNET_SERVICE_Client c,
struct GNUNET_MQ_Handle mq 
)
static

Callback called when a client connects to the service.

Parameters
clsclosure for the service
cthe new client that connected to the service
mqthe message queue used to send messages to the client
Returns
a struct ClientHandle

Definition at line 2083 of file gnunet-service-nat.c.

2086{
2087 struct ClientHandle *ch;
2088
2089 ch = GNUNET_new (struct ClientHandle);
2090 ch->mq = mq;
2091 ch->client = c;
2093 ch_tail,
2094 ch);
2095 return ch;
2096}

References ch, ch_head, ch_tail, GNUNET_CONTAINER_DLL_insert, GNUNET_new, mq, and GNUNET_CADET_Channel::mq.

◆ client_disconnect_cb()

static void client_disconnect_cb ( void *  cls,
struct GNUNET_SERVICE_Client c,
void *  internal_cls 
)
static

Callback called when a client disconnected from the service.

Parameters
clsclosure for the service
cthe client that disconnected
internal_clsa struct ClientHandle *

Definition at line 2107 of file gnunet-service-nat.c.

2110{
2111 struct ClientHandle *ch = internal_cls;
2112 struct LocalAddressList *lal;
2113
2115 ch_tail,
2116 ch);
2117 for (unsigned int i = 0; i < ch->num_caddrs; i++)
2118 {
2119 if (NULL != ch->caddrs[i].mh)
2120 {
2121 GNUNET_NAT_mini_map_stop (ch->caddrs[i].mh);
2122 ch->caddrs[i].mh = NULL;
2123 }
2124 }
2125 GNUNET_free (ch->caddrs);
2126 while (NULL != (lal = ch->ext_addr_head))
2127 {
2128 GNUNET_CONTAINER_DLL_remove (ch->ext_addr_head,
2129 ch->ext_addr_tail,
2130 lal);
2131 GNUNET_free (lal);
2132 }
2133 if (NULL != ch->ext_dns_task)
2134 {
2135 GNUNET_SCHEDULER_cancel (ch->ext_dns_task);
2136 ch->ext_dns_task = NULL;
2137 }
2138 if (NULL != ch->external_monitor)
2139 {
2140 GN_external_ipv4_monitor_stop (ch->external_monitor);
2141 ch->external_monitor = NULL;
2142 }
2143 if (NULL != ch->ext_dns)
2144 {
2146 ch->ext_dns = NULL;
2147 }
2148 GNUNET_free (ch->hole_external);
2149 GNUNET_free (ch->section_name);
2150 GNUNET_free (ch);
2151}

References ch, ch_head, ch_tail, GN_external_ipv4_monitor_stop(), GNUNET_CONTAINER_DLL_remove, GNUNET_free, GNUNET_NAT_mini_map_stop(), GNUNET_RESOLVER_request_cancel(), and GNUNET_SCHEDULER_cancel().

Here is the call graph for this function:

◆ GNUNET_SERVICE_MAIN()

Define "main" method using service macro.

Variable Documentation

◆ stun_stale_timeout

struct GNUNET_TIME_Relative stun_stale_timeout
static

Timeout to use when STUN data is considered stale.

Definition at line 278 of file gnunet-service-nat.c.

Referenced by handle_stun(), and run().

◆ dyndns_frequency

struct GNUNET_TIME_Relative dyndns_frequency
static

How often do we scan for changes in how our external (dyndns) hostname resolves?

Definition at line 283 of file gnunet-service-nat.c.

Referenced by process_external_ip(), and run().

◆ cfg

const struct GNUNET_CONFIGURATION_Handle* cfg
static

Handle to our current configuration.

Definition at line 288 of file gnunet-service-nat.c.

Referenced by handle_register(), handle_request_connection_reversal(), run(), and run_scan().

◆ stats

struct GNUNET_STATISTICS_Handle* stats
static

Handle to the statistics service.

Definition at line 293 of file gnunet-service-nat.c.

Referenced by run(), and shutdown_task().

◆ scan_task

struct GNUNET_SCHEDULER_Task* scan_task
static

Task scheduled to periodically scan our network interfaces.

Definition at line 298 of file gnunet-service-nat.c.

Referenced by run(), run_scan(), and shutdown_task().

◆ ch_head

struct ClientHandle* ch_head
static

◆ ch_tail

struct ClientHandle* ch_tail
static

Tail of client DLL.

Definition at line 308 of file gnunet-service-nat.c.

Referenced by client_connect_cb(), and client_disconnect_cb().

◆ lal_head

struct LocalAddressList* lal_head
static

Head of DLL of local addresses.

Definition at line 313 of file gnunet-service-nat.c.

Referenced by destroy_lal(), free_lal(), handle_register(), and run_scan().

◆ lal_tail

struct LocalAddressList* lal_tail
static

Tail of DLL of local addresses.

Definition at line 318 of file gnunet-service-nat.c.

Referenced by free_lal(), and run_scan().

◆ se_head

struct StunExternalIP* se_head
static

Kept in a DLL.

Definition at line 323 of file gnunet-service-nat.c.

Referenced by handle_stun(), shutdown_task(), and stun_ip_timeout().

◆ se_tail

struct StunExternalIP* se_tail
static

Kept in a DLL.

Definition at line 328 of file gnunet-service-nat.c.

Referenced by handle_stun(), shutdown_task(), and stun_ip_timeout().

◆ enable_upnp

int enable_upnp

Is UPnP enabled? GNUNET_YES if enabled, GNUNET_NO if disabled, GNUNET_SYSERR if configuration enabled but binary is unavailable.

Definition at line 334 of file gnunet-service-nat.c.

Referenced by GN_nat_status_changed(), handle_register(), and run().

◆ enable_ipscan

int enable_ipscan

Is IP Scanning enabled? GNUNET_YES if enabled, GNUNET_NO if disabled, without, only explicitly specified IPs will be handled (HOLE_EXTERNAL)

Definition at line 340 of file gnunet-service-nat.c.

Referenced by run().

◆ return_local_addresses

int return_local_addresses
static

Do we report addresses that are only meaningful on this host to clients that did not explicitly bind to them? GNUNET_YES only for tests that run several peers on one machine; everywhere else such an address just ends up in our HELLO, where it is at best useless and at worst points a remote peer at a service of its own.

Definition at line 349 of file gnunet-service-nat.c.

Referenced by check_notify_client(), and run().