GNUnet debian-0.24.3-29-g453fda2cf
 
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)
 

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
346static void
347free_lal (struct LocalAddressList *lal)
348{
350 lal_tail,
351 lal);
352 if (NULL != lal->hc)
353 {
355 "Lost NATed local address %s, stopping NAT server\n",
356 GNUNET_a2s ((const struct sockaddr *) &lal->addr,
357 sizeof(struct sockaddr_in)));
358
360 lal->hc = NULL;
361 }
362 GNUNET_free (lal);
363}
364
365
369static void
371{
372 struct LocalAddressList *lal;
373
374 while (NULL != (lal = lal_head))
375 free_lal (lal);
376}
377
378
387static int
388check_register (void *cls,
389 const struct GNUNET_NAT_RegisterMessage *message)
390{
391 uint16_t num_addrs = ntohs (message->num_addrs);
392 const char *off = (const char *) &message[1];
393 size_t left = ntohs (message->header.size) - sizeof(*message);
394
395 for (unsigned int i = 0; i < num_addrs; i++)
396 {
397 size_t alen;
398 const struct sockaddr *sa = (const struct sockaddr *) off;
399
400 if (sizeof(sa_family_t) > left)
401 {
402 GNUNET_break (0);
403 return GNUNET_SYSERR;
404 }
405 switch (sa->sa_family)
406 {
407 case AF_INET:
408 alen = sizeof(struct sockaddr_in);
409 break;
410
411 case AF_INET6:
412 alen = sizeof(struct sockaddr_in6);
413 break;
414
415#if AF_UNIX
416 case AF_UNIX:
417 alen = sizeof(struct sockaddr_un);
418 break;
419#endif
420 default:
421 GNUNET_break (0);
422 return GNUNET_SYSERR;
423 }
424 if (alen > left)
425 {
426 GNUNET_break (0);
427 return GNUNET_SYSERR;
428 }
429 off += alen;
430 left -= alen;
431 }
432 if (left != ntohs (message->str_len))
433 {
434 GNUNET_break (0);
435 return GNUNET_SYSERR;
436 }
437 return GNUNET_OK;
438}
439
440
449static int
450match_ipv4 (const char *network,
451 const struct in_addr *ip,
452 uint8_t bits)
453{
454 struct in_addr net;
455
456 if (0 == ip->s_addr)
457 return GNUNET_YES;
458 if (0 == bits)
459 return GNUNET_YES;
460 GNUNET_assert (1 == inet_pton (AF_INET,
461 network,
462 &net));
463 return ! ((ip->s_addr ^ net.s_addr) & htonl (0xFFFFFFFFu << (32 - bits)));
464}
465
466
475static int
476match_ipv6 (const char *network,
477 const struct in6_addr *ip,
478 uint8_t bits)
479{
480 struct in6_addr net;
481 struct in6_addr mask;
482 unsigned int off;
483
484 if (0 == bits)
485 return GNUNET_YES;
486 GNUNET_assert (1 == inet_pton (AF_INET6,
487 network,
488 &net));
489 memset (&mask, 0, sizeof(mask));
490 if (0 == GNUNET_memcmp (&mask,
491 ip))
492 return GNUNET_YES;
493 off = 0;
494 while (bits > 8)
495 {
496 mask.s6_addr[off++] = 0xFF;
497 bits -= 8;
498 }
499 while (bits > 0)
500 {
501 mask.s6_addr[off] = (mask.s6_addr[off] >> 1) + 0x80;
502 bits--;
503 }
504 for (unsigned j = 0; j < sizeof(struct in6_addr) / sizeof(uint32_t); j++)
505 if (((((uint32_t *) ip)[j] & ((uint32_t *) &mask)[j])) !=
506 (((uint32_t *) &net)[j] & ((int *) &mask)[j]))
507 return GNUNET_NO;
508 return GNUNET_YES;
509}
510
511
519static int
520is_nat_v4 (const struct in_addr *ip)
521{
522 return
523 match_ipv4 ("10.0.0.0", ip, 8) || /* RFC 1918 */
524 match_ipv4 ("100.64.0.0", ip, 10) || /* CG-NAT, RFC 6598 */
525 match_ipv4 ("192.168.0.0", ip, 12) || /* RFC 1918 */
526 match_ipv4 ("169.254.0.0", ip, 16) || /* AUTO, RFC 3927 */
527 match_ipv4 ("172.16.0.0", ip, 16); /* RFC 1918 */
528}
529
530
538static int
539is_nat_v6 (const struct in6_addr *ip)
540{
541 return
542 match_ipv6 ("fc00::", ip, 7) || /* RFC 4193 */
543 match_ipv6 ("fec0::", ip, 10) || /* RFC 3879 */
544 match_ipv6 ("fe80::", ip, 10); /* RFC 4291, link-local */
545}
546
547
551struct IfcProcContext
552{
557
562};
563
564
578static int
579ifc_proc (void *cls,
580 const char *name,
581 int isDefault,
582 const struct sockaddr *addr,
583 const struct sockaddr *broadcast_addr,
584 const struct sockaddr *netmask,
585 socklen_t addrlen)
586{
587 struct IfcProcContext *ifc_ctx = cls;
588 struct LocalAddressList *lal;
589 size_t alen;
590 const struct in_addr *ip4;
591 const struct in6_addr *ip6;
593
594 switch (addr->sa_family)
595 {
596 case AF_INET:
597 alen = sizeof(struct sockaddr_in);
598 ip4 = &((const struct sockaddr_in *) addr)->sin_addr;
599 if (match_ipv4 ("127.0.0.0", ip4, 8))
601 else if (is_nat_v4 (ip4))
603 else
605 break;
606
607 case AF_INET6:
608 alen = sizeof(struct sockaddr_in6);
609 ip6 = &((const struct sockaddr_in6 *) addr)->sin6_addr;
610 if (match_ipv6 ("::1", ip6, 128))
612 else if (is_nat_v6 (ip6))
614 else
616 if ((ip6->s6_addr[11] == 0xFF) &&
617 (ip6->s6_addr[12] == 0xFE))
618 {
619 /* contains a MAC, be extra careful! */
621 }
622 break;
623
624#if AF_UNIX
625 case AF_UNIX:
626 GNUNET_break (0);
627 return GNUNET_OK;
628#endif
629 default:
630 GNUNET_break (0);
631 return GNUNET_OK;
632 }
633 lal = GNUNET_malloc (sizeof(*lal));
634 lal->af = addr->sa_family;
635 lal->ac = ac;
636 GNUNET_memcpy (&lal->addr,
637 addr,
638 alen);
640 ifc_ctx->lal_tail,
641 lal);
642 return GNUNET_OK;
643}
644
645
656static void
658 struct ClientHandle *ch,
659 int add,
660 const void *addr,
661 size_t addr_len)
662{
663 struct GNUNET_MQ_Envelope *env;
665
667 "Notifying client about %s of IP %s\n",
668 add ? "addition" : "removal",
669 GNUNET_a2s (addr,
670 addr_len));
672 addr_len,
674 msg->add_remove = htonl (add);
675 msg->addr_class = htonl (ac);
676 GNUNET_memcpy (&msg[1],
677 addr,
678 addr_len);
680 env);
681}
682
683
692static void
694 struct ClientHandle *ch,
695 int add)
696{
697 size_t alen;
698 struct sockaddr_in v4;
699 struct sockaddr_in6 v6;
700
701 if (0 == (ch->flags & GNUNET_NAT_RF_ADDRESSES))
702 {
704 "Not notifying client as it does not care about addresses\n");
705 return;
706 }
707 switch (delta->af)
708 {
709 case AF_INET:
710 alen = sizeof(struct sockaddr_in);
711 GNUNET_memcpy (&v4,
712 &delta->addr,
713 alen);
714
715 /* Check for client notifications */
716 for (unsigned int i = 0; i < ch->num_caddrs; i++)
717 {
718 const struct sockaddr_in *c4;
719
720 if (AF_INET != ch->caddrs[i].ss.ss_family)
721 continue; /* IPv4 not relevant */
722 c4 = (const struct sockaddr_in *) &ch->caddrs[i].ss;
723 if (match_ipv4 ("127.0.0.1", &c4->sin_addr, 8) &&
724 (0 != c4->sin_addr.s_addr) &&
725 (! match_ipv4 ("127.0.0.1", &v4.sin_addr, 8)))
726 continue; /* bound to loopback, but this is not loopback */
727 if ((! match_ipv4 ("127.0.0.1", &c4->sin_addr, 8)) &&
728 match_ipv4 ("127.0.0.1", &v4.sin_addr, 8))
729 continue; /* bound to non-loopback, but this is loopback */
730 if ((0 != (delta->ac & GNUNET_NAT_AC_EXTERN)) &&
731 (0 != c4->sin_addr.s_addr) &&
732 (! is_nat_v4 (&v4.sin_addr)))
733 continue; /* based on external-IP, but this IP is not
734 from private address range. */
735 if ((0 != GNUNET_memcmp (&v4.sin_addr,
736 &c4->sin_addr)) &&
737 (0 != c4->sin_addr.s_addr) &&
738 (! is_nat_v4 (&c4->sin_addr)))
739 continue; /* this IP is not from private address range,
740 and IP does not match. */
741
742 /* OK, IP seems relevant, notify client */
743 if (0 == htons (v4.sin_port))
744 v4.sin_port = c4->sin_port;
745 notify_client (delta->ac,
746 ch,
747 add,
748 &v4,
749 alen);
750 }
751 break;
752
753 case AF_INET6:
754 alen = sizeof(struct sockaddr_in6);
755 GNUNET_memcpy (&v6,
756 &delta->addr,
757 alen);
758 for (unsigned int i = 0; i < ch->num_caddrs; i++)
759 {
760 const struct sockaddr_in6 *c6;
761
762 if (AF_INET6 != ch->caddrs[i].ss.ss_family)
763 continue; /* IPv4 not relevant */
764 c6 = (const struct sockaddr_in6 *) &ch->caddrs[i].ss;
765 if (match_ipv6 ("::1", &c6->sin6_addr, 128) &&
766 (0 != GNUNET_memcmp (&c6->sin6_addr,
767 &in6addr_any)) &&
768 (! match_ipv6 ("::1", &v6.sin6_addr, 128)))
769 continue; /* bound to loopback, but this is not loopback */
770 if ((! match_ipv6 ("::1", &c6->sin6_addr, 128)) &&
771 match_ipv6 ("::1", &v6.sin6_addr, 128))
772 continue; /* bound to non-loopback, but this is loopback */
773 if ((0 != (delta->ac & GNUNET_NAT_AC_EXTERN)) &&
774 (0 != GNUNET_memcmp (&c6->sin6_addr,
775 &in6addr_any)) &&
776 (! is_nat_v6 (&v6.sin6_addr)))
777 continue; /* based on external-IP, but this IP is not
778 from private address range. */
779 if ((0 != GNUNET_memcmp (&v6.sin6_addr,
780 &c6->sin6_addr)) &&
781 (0 != GNUNET_memcmp (&c6->sin6_addr,
782 &in6addr_any)) &&
783 (! is_nat_v6 (&c6->sin6_addr)))
784 continue; /* this IP is not from private address range,
785 and IP does not match. */
786 if ((match_ipv6 ("fe80::", &c6->sin6_addr, 10)) &&
787 (0 != GNUNET_memcmp (&c6->sin6_addr,
788 &in6addr_any)) &&
789 (0 != GNUNET_memcmp (&v6.sin6_addr,
790 &c6->sin6_addr)) &&
791 (0 == (delta->ac & GNUNET_NAT_AC_EXTERN)))
792 continue; /* client bound to link-local, and the other address
793 does not match and is not an external IP */
794
795 /* OK, IP seems relevant, notify client */
796 if (0 == htons (v6.sin6_port))
797 v6.sin6_port = c6->sin6_port;
798 notify_client (delta->ac,
799 ch,
800 add,
801 &v6,
802 alen);
803 }
804 break;
805
806 default:
807 GNUNET_break (0);
808 return;
809 }
810}
811
812
820static void
822 int add)
823{
824 for (struct ClientHandle *ch = ch_head;
825 NULL != ch;
826 ch = ch->next)
828 ch,
829 add);
830}
831
832
841static void
843 const struct in_addr *v4,
844 int add)
845{
846 struct ClientHandle *ch = cls;
847 struct sockaddr_in sa;
848 int have_v4;
849
850 /* (0) check if this impacts 'hole_external' */
851 if ((NULL != ch->hole_external) &&
852 (0 == strcasecmp (ch->hole_external,
853 "AUTO")))
854 {
855 struct LocalAddressList lal;
856 struct sockaddr_in *s4;
857
859 "Detected eternal IP, can now back-fill AUTO:%u in hole punching specification of `%s'\n",
860 (unsigned int) ch->ext_dns_port,
861 ch->section_name);
862 memset (&lal, 0, sizeof(lal));
863 s4 = (struct sockaddr_in *) &lal.addr;
864 s4->sin_family = AF_INET;
865 s4->sin_port = htons (ch->ext_dns_port);
866 s4->sin_addr = *v4;
867 lal.af = AF_INET;
870 ch,
871 add);
872 }
873
874 /* (1) check if client cares. */
875 if (! ch->natted_address)
876 return;
877 have_v4 = GNUNET_NO;
878 for (unsigned int i = 0; i < ch->num_caddrs; i++)
879 {
880 const struct sockaddr_storage *ss = &ch->caddrs[i].ss;
881
882 if (AF_INET != ss->ss_family)
883 continue;
884 have_v4 = GNUNET_YES;
885 break;
886 }
887 if (GNUNET_NO == have_v4)
888 return; /* IPv6-only */
889
890 /* (2) build address info */
891 memset (&sa,
892 0,
893 sizeof(sa));
894 sa.sin_family = AF_INET;
895 sa.sin_addr = *v4;
896 sa.sin_port = htons (0);
897
899 "Detected eternal IP %s, notifying client of external IP (without port)\n",
900 GNUNET_a2s ((const struct sockaddr *) &sa,
901 sizeof(sa)));
902 /* (3) notify client of change */
906 ch,
907 add,
908 &sa,
909 sizeof(sa));
910}
911
912
920static void
921reversal_callback (void *cls,
922 const struct sockaddr_in *ra)
923{
924 struct LocalAddressList *lal = cls;
925 const struct sockaddr_in *l4;
926
927 GNUNET_assert (AF_INET == lal->af);
928 l4 = (const struct sockaddr_in *) &lal->addr;
929 for (struct ClientHandle *ch = ch_head;
930 NULL != ch;
931 ch = ch->next)
932 {
934 struct GNUNET_MQ_Envelope *env;
935 int match;
936
937 /* Check if client is in applicable range for ICMP NAT traversal
938 for this local address */
939 if (! ch->natted_address)
940 continue;
941 match = GNUNET_NO;
942 for (unsigned int i = 0; i < ch->num_caddrs; i++)
943 {
944 struct ClientAddress *ca = &ch->caddrs[i];
945 const struct sockaddr_in *c4;
946
947 if (AF_INET != ca->ss.ss_family)
948 continue;
949 c4 = (const struct sockaddr_in *) &ca->ss;
950 if ((0 != c4->sin_addr.s_addr) &&
951 (l4->sin_addr.s_addr != c4->sin_addr.s_addr))
952 continue;
953 match = GNUNET_YES;
954 break;
955 }
956 if (! match)
957 continue;
958
959 /* Notify applicable client about connection reversal request */
960 env = GNUNET_MQ_msg_extra (crrm,
961 sizeof(struct sockaddr_in),
963 GNUNET_memcpy (&crrm[1],
964 ra,
965 sizeof(struct sockaddr_in));
967 env);
968 }
969}
970
971
977static void
978run_scan (void *cls)
979{
980 struct IfcProcContext ifc_ctx;
981 int found;
982 int have_nat;
983 struct LocalAddressList *lnext;
984
986 &run_scan,
987 NULL);
988 memset (&ifc_ctx,
989 0,
990 sizeof(ifc_ctx));
992 &ifc_ctx);
993 /* remove addresses that disappeared */
994 for (struct LocalAddressList *lal = lal_head;
995 NULL != lal;
996 lal = lnext)
997 {
998 lnext = lal->next;
999 found = GNUNET_NO;
1000 for (struct LocalAddressList *pos = ifc_ctx.lal_head;
1001 NULL != pos;
1002 pos = pos->next)
1003 {
1004 if ((pos->af == lal->af) &&
1005 (0 == memcmp (&lal->addr,
1006 &pos->addr,
1007 (AF_INET == lal->af)
1008 ? sizeof(struct sockaddr_in)
1009 : sizeof(struct sockaddr_in6))))
1010 {
1011 found = GNUNET_YES;
1012 }
1013 }
1014 if (GNUNET_NO == found)
1015 {
1016 notify_clients (lal,
1017 GNUNET_NO);
1018 free_lal (lal);
1019 }
1020 }
1021
1022 /* add addresses that appeared */
1023 have_nat = GNUNET_NO;
1024 for (struct LocalAddressList *pos = ifc_ctx.lal_head;
1025 NULL != pos;
1026 pos = ifc_ctx.lal_head)
1027 {
1028 found = GNUNET_NO;
1029 if (GNUNET_NAT_AC_LAN == (GNUNET_NAT_AC_LAN & pos->ac))
1030 have_nat = GNUNET_YES;
1031 for (struct LocalAddressList *lal = lal_head;
1032 NULL != lal;
1033 lal = lal->next)
1034 {
1035 if ((pos->af == lal->af) &&
1036 (0 == memcmp (&lal->addr,
1037 &pos->addr,
1038 (AF_INET == lal->af)
1039 ? sizeof(struct sockaddr_in)
1040 : sizeof(struct sockaddr_in6))))
1041 found = GNUNET_YES;
1042 }
1044 ifc_ctx.lal_tail,
1045 pos);
1046 if (GNUNET_YES == found)
1047 {
1048 GNUNET_free (pos);
1049 }
1050 else
1051 {
1052 notify_clients (pos,
1053 GNUNET_YES);
1055 lal_tail,
1056 pos);
1057 if ((AF_INET == pos->af) &&
1058 (NULL == pos->hc) &&
1059 (0 != (GNUNET_NAT_AC_LAN & pos->ac)))
1060 {
1061 const struct sockaddr_in *s4
1062 = (const struct sockaddr_in *) &pos->addr;
1063
1065 "Found NATed local address %s, starting NAT server\n",
1066 GNUNET_a2s ((const struct sockaddr *) &pos->addr,
1067 sizeof(*s4)));
1068 pos->hc = GN_start_gnunet_nat_server_ (&s4->sin_addr,
1070 pos,
1071 cfg);
1072 }
1073 }
1074 }
1075 GN_nat_status_changed (have_nat);
1076}
1077
1078
1090static void
1091upnp_addr_change_cb (void *cls,
1092 int add_remove,
1093 const struct sockaddr *addr,
1094 socklen_t addrlen,
1096{
1097 struct ClientHandle *ch = cls;
1099
1100 switch (result)
1101 {
1103 GNUNET_assert (NULL != addr);
1104 break;
1105
1110 "Running upnpc failed: %d\n",
1111 result);
1112 return;
1113
1116 "external-ip binary not found\n");
1117 return;
1118
1121 "upnpc binary not found\n");
1122 return;
1123
1126 "external-ip binary could not be run\n");
1127 return;
1128
1131 "upnpc failed to create port mapping\n");
1132 return;
1133
1136 "Invalid output from upnpc\n");
1137 return;
1138
1141 "Invalid address returned by upnpc\n");
1142 return;
1143
1144 default:
1145 GNUNET_break (0); /* should not be possible */
1146 return;
1147 }
1148 switch (addr->sa_family)
1149 {
1150 case AF_INET:
1151 ac = is_nat_v4 (&((const struct sockaddr_in *) addr)->sin_addr)
1154 break;
1155
1156 case AF_INET6:
1157 ac = is_nat_v6 (&((const struct sockaddr_in6 *) addr)->sin6_addr)
1160 break;
1161
1162 default:
1163 GNUNET_break (0);
1164 return;
1165 }
1167 "upnp external address %s: %s\n",
1168 add_remove ? "added" : "removed",
1169 GNUNET_a2s (addr,
1170 addrlen));
1171 notify_client (ac,
1172 ch,
1173 add_remove,
1174 addr,
1175 addrlen);
1176}
1177
1178
1187static void
1188dyndns_lookup (void *cls);
1189
1190
1200static void
1201process_external_ip (void *cls,
1202 const struct sockaddr *addr,
1203 socklen_t addrlen)
1204{
1205 struct ClientHandle *ch = cls;
1206 struct LocalAddressList *lal;
1207 struct sockaddr_storage ss;
1208 struct sockaddr_in *v4;
1209 struct sockaddr_in6 *v6;
1210
1211 if (NULL == addr)
1212 {
1213 struct LocalAddressList *laln;
1214
1215 ch->ext_dns = NULL;
1216 ch->ext_dns_task
1219 ch);
1220 /* Current iteration is over, remove 'old' IPs now */
1221 for (lal = ch->ext_addr_head; NULL != lal; lal = laln)
1222 {
1223 laln = lal->next;
1224 if (GNUNET_YES == lal->old)
1225 {
1226 GNUNET_CONTAINER_DLL_remove (ch->ext_addr_head,
1227 ch->ext_addr_tail,
1228 lal);
1230 ch,
1231 GNUNET_NO);
1232 GNUNET_free (lal);
1233 }
1234 }
1235 return;
1236 }
1238 "Got IP `%s' for external address `%s'\n",
1240 addrlen),
1241 ch->hole_external);
1242
1243 /* build sockaddr storage with port number */
1244 memset (&ss,
1245 0,
1246 sizeof(ss));
1247 GNUNET_memcpy (&ss,
1248 addr,
1249 addrlen);
1250 switch (addr->sa_family)
1251 {
1252 case AF_INET:
1253 v4 = (struct sockaddr_in *) &ss;
1254 v4->sin_port = htons (ch->ext_dns_port);
1255 break;
1256
1257 case AF_INET6:
1258 v6 = (struct sockaddr_in6 *) &ss;
1259 v6->sin6_port = htons (ch->ext_dns_port);
1260 break;
1261
1262 default:
1263 GNUNET_break (0);
1264 return;
1265 }
1266 /* See if 'ss' matches any of our known addresses */
1267 for (lal = ch->ext_addr_head; NULL != lal; lal = lal->next)
1268 {
1269 if (GNUNET_NO == lal->old)
1270 continue; /* already processed, skip */
1271 if ((addr->sa_family == lal->addr.ss_family) &&
1272 (0 == memcmp (&ss,
1273 &lal->addr,
1274 addrlen)))
1275 {
1276 /* Address unchanged, remember so we do not remove */
1277 lal->old = GNUNET_NO;
1278 return; /* done here */
1279 }
1280 }
1281 /* notify client, and remember IP for later removal! */
1282 lal = GNUNET_new (struct LocalAddressList);
1283 lal->addr = ss;
1284 lal->af = ss.ss_family;
1286 GNUNET_CONTAINER_DLL_insert (ch->ext_addr_head,
1287 ch->ext_addr_tail,
1288 lal);
1290 ch,
1291 GNUNET_YES);
1292}
1293
1294
1303static void
1304dyndns_lookup (void *cls)
1305{
1306 struct ClientHandle *ch = cls;
1307 struct LocalAddressList *lal;
1308
1310 "Performing DNS lookup for punched hole given for `%s' as `%s:%u'\n",
1311 ch->section_name,
1312 ch->hole_external,
1313 (unsigned int) ch->ext_dns_port);
1314 for (lal = ch->ext_addr_head; NULL != lal; lal = lal->next)
1315 lal->old = GNUNET_YES;
1316 ch->ext_dns_task = NULL;
1317 ch->ext_dns = GNUNET_RESOLVER_ip_get (ch->hole_external,
1318 AF_UNSPEC,
1321 ch);
1322}
1323
1324
1336static void
1338{
1339 char *port;
1340 unsigned int pnum;
1341 struct sockaddr_in *s4;
1342 struct LocalAddressList *lal;
1343
1344 port = strrchr (ch->hole_external, ':');
1345 if (NULL == port)
1346 {
1348 _ ("Malformed punched hole specification `%s' (lacks port)\n"),
1349 ch->hole_external);
1350 return;
1351 }
1352 if ((1 != sscanf (port + 1,
1353 "%u",
1354 &pnum)) ||
1355 (pnum > 65535))
1356 {
1358 _ (
1359 "Invalid port number in punched hole specification `%s' (lacks port)\n"),
1360 port + 1);
1361 return;
1362 }
1363 ch->ext_dns_port = (uint16_t) pnum;
1364 *port = '\0';
1365
1366 lal = GNUNET_new (struct LocalAddressList);
1367 if ('[' == *ch->hole_external)
1368 {
1369 struct sockaddr_in6 *s6 = (struct sockaddr_in6 *) &lal->addr;
1370
1371 s6->sin6_family = AF_INET6;
1372 if (']' != (ch->hole_external[strlen (ch->hole_external) - 1]))
1373 {
1375 _ ("Malformed punched hole specification `%s' (lacks `]')\n"),
1376 ch->hole_external);
1377 GNUNET_free (lal);
1378 return;
1379 }
1380 ch->hole_external[strlen (ch->hole_external) - 1] = '\0';
1381 if (1 != inet_pton (AF_INET6,
1382 ch->hole_external + 1,
1383 &s6->sin6_addr))
1384 {
1386 _ (
1387 "Malformed punched hole specification `%s' (IPv6 address invalid)"),
1388 ch->hole_external + 1);
1389 GNUNET_free (lal);
1390 return;
1391 }
1392 s6->sin6_port = htons (ch->ext_dns_port);
1393 lal->af = AF_INET6;
1395 GNUNET_CONTAINER_DLL_insert (ch->ext_addr_head,
1396 ch->ext_addr_tail,
1397 lal);
1399 ch,
1400 GNUNET_YES);
1401 return;
1402 }
1403
1404 s4 = (struct sockaddr_in *) &lal->addr;
1405 s4->sin_family = AF_INET;
1406 if (1 == inet_pton (AF_INET,
1407 ch->hole_external,
1408 &s4->sin_addr))
1409 {
1411 "IPv4 punched hole given for `%s' via `%s:%u'\n",
1412 ch->section_name,
1413 ch->hole_external,
1414 (unsigned int) ch->ext_dns_port);
1415 s4->sin_port = htons (ch->ext_dns_port);
1416 lal->af = AF_INET;
1418 GNUNET_CONTAINER_DLL_insert (ch->ext_addr_head,
1419 ch->ext_addr_tail,
1420 lal);
1422 ch,
1423 GNUNET_YES);
1424 return;
1425 }
1426 if (0 == strcasecmp (ch->hole_external,
1427 "AUTO"))
1428 {
1429 /* handled in #notify_client_external_ipv4_change() */
1430 GNUNET_free (lal);
1431 return;
1432 }
1433 /* got a DNS name, trigger lookup! */
1434 GNUNET_free (lal);
1435 ch->ext_dns_task
1437 ch);
1438}
1439
1440
1448static void
1449handle_register (void *cls,
1450 const struct GNUNET_NAT_RegisterMessage *message)
1451{
1452 struct ClientHandle *ch = cls;
1453 const char *off;
1454 size_t left;
1455
1456 if ((0 != ch->proto) ||
1457 (NULL != ch->caddrs))
1458 {
1459 /* double registration not allowed */
1460 GNUNET_break (0);
1462 return;
1463 }
1464 ch->flags = message->flags;
1465 ch->proto = message->proto;
1466 ch->num_caddrs = ntohs (message->num_addrs);
1467 ch->caddrs = GNUNET_new_array (ch->num_caddrs,
1468 struct ClientAddress);
1469 left = ntohs (message->header.size) - sizeof(*message);
1470 off = (const char *) &message[1];
1471 for (unsigned int i = 0; i < ch->num_caddrs; i++)
1472 {
1473 const struct sockaddr *sa = (const struct sockaddr *) off;
1474 size_t alen;
1475 uint16_t port;
1476 int is_nat;
1477
1478 if (sizeof(sa_family_t) > left)
1479 {
1480 GNUNET_break (0);
1482 return;
1483 }
1484 is_nat = GNUNET_NO;
1485 switch (sa->sa_family)
1486 {
1487 case AF_INET:
1488 {
1489 struct sockaddr_in s4;
1490
1491 GNUNET_memcpy (&s4,
1492 off,
1493 sizeof(struct sockaddr_in));
1494 alen = sizeof(struct sockaddr_in);
1495 if (is_nat_v4 (&s4.sin_addr))
1496 is_nat = GNUNET_YES;
1497 port = ntohs (s4.sin_port);
1498 }
1499 break;
1500
1501 case AF_INET6:
1502 {
1503 struct sockaddr_in6 s6;
1504
1505 GNUNET_memcpy (&s6,
1506 off,
1507 sizeof(struct sockaddr_in6));
1508 alen = sizeof(struct sockaddr_in6);
1509 if (is_nat_v6 (&s6.sin6_addr))
1510 is_nat = GNUNET_YES;
1511 port = ntohs (s6.sin6_port);
1512 }
1513 break;
1514
1515#if AF_UNIX
1516 case AF_UNIX:
1517 alen = sizeof(struct sockaddr_un);
1518 port = 0;
1519 break;
1520#endif
1521 default:
1522 GNUNET_break (0);
1524 return;
1525 }
1526 /* store address */
1527 GNUNET_assert (alen <= left);
1528 GNUNET_assert (alen <= sizeof(struct sockaddr_storage));
1529 GNUNET_memcpy (&ch->caddrs[i].ss,
1530 off,
1531 alen);
1532
1533 /* If applicable, try UPNPC NAT punching */
1534 if ((is_nat) &&
1535 (enable_upnp) &&
1536 ((IPPROTO_TCP == ch->proto) ||
1537 (IPPROTO_UDP == ch->proto)))
1538 {
1539 ch->natted_address = GNUNET_YES;
1540 ch->caddrs[i].mh
1542 IPPROTO_TCP == ch->proto,
1544 ch);
1545 }
1546
1547 off += alen;
1548 }
1549
1550 ch->section_name
1551 = GNUNET_strndup (off,
1552 ntohs (message->str_len));
1554 "Received REGISTER message from client for subsystem `%s'\n",
1555 ch->section_name);
1556 if (GNUNET_OK ==
1558 ch->section_name,
1559 "HOLE_EXTERNAL",
1560 &ch->hole_external))
1562
1563 /* Actually send IP address list to client */
1564 for (struct LocalAddressList *lal = lal_head;
1565 NULL != lal;
1566 lal = lal->next)
1567 {
1569 ch,
1570 GNUNET_YES);
1571 }
1572 /* Also consider IPv4 determined by `external-ip` */
1573 ch->external_monitor
1575 ch);
1577}
1578
1579
1588static int
1589check_stun (void *cls,
1590 const struct GNUNET_NAT_HandleStunMessage *message)
1591{
1592 size_t sa_len = ntohs (message->sender_addr_size);
1593 size_t expect = sa_len + ntohs (message->payload_size);
1594
1595 if (ntohs (message->header.size) - sizeof(*message) != expect)
1596 {
1597 GNUNET_break (0);
1598 return GNUNET_SYSERR;
1599 }
1600 if (sa_len < sizeof(sa_family_t))
1601 {
1602 GNUNET_break (0);
1603 return GNUNET_SYSERR;
1604 }
1605 return GNUNET_OK;
1606}
1607
1608
1616static void
1617notify_clients_stun_change (const struct sockaddr_in *ip,
1618 int add)
1619{
1620 for (struct ClientHandle *ch = ch_head;
1621 NULL != ch;
1622 ch = ch->next)
1623 {
1624 struct sockaddr_in v4;
1626 struct GNUNET_MQ_Envelope *env;
1627
1628 if (! ch->natted_address)
1629 continue;
1630 v4 = *ip;
1631 v4.sin_port = htons (0);
1633 sizeof(v4),
1635 msg->add_remove = htonl ((int32_t) add);
1636 msg->addr_class = htonl (GNUNET_NAT_AC_EXTERN
1638 GNUNET_memcpy (&msg[1],
1639 &v4,
1640 sizeof(v4));
1642 env);
1643 }
1644}
1645
1646
1654static void
1655stun_ip_timeout (void *cls)
1656{
1657 struct StunExternalIP *se = cls;
1658
1659 se->timeout_task = NULL;
1661 GNUNET_NO);
1663 se_tail,
1664 se);
1665 GNUNET_free (se);
1666}
1667
1668
1676static void
1677handle_stun (void *cls,
1678 const struct GNUNET_NAT_HandleStunMessage *message)
1679{
1680 struct ClientHandle *ch = cls;
1681 const char *buf = (const char *) &message[1];
1682 const struct sockaddr *sa;
1683 const void *payload;
1684 size_t sa_len;
1685 size_t payload_size;
1686 struct sockaddr_in external_addr;
1687
1688 sa_len = ntohs (message->sender_addr_size);
1689 payload_size = ntohs (message->payload_size);
1690 sa = (const struct sockaddr *) &buf[0];
1691 payload = (const struct sockaddr *) &buf[sa_len];
1692 switch (sa->sa_family)
1693 {
1694 case AF_INET:
1695 if (sa_len != sizeof(struct sockaddr_in))
1696 {
1697 GNUNET_break (0);
1699 return;
1700 }
1701 break;
1702
1703 case AF_INET6:
1704 if (sa_len != sizeof(struct sockaddr_in6))
1705 {
1706 GNUNET_break (0);
1708 return;
1709 }
1710 break;
1711 }
1713 "Received HANDLE_STUN message from client\n");
1714 if (GNUNET_OK ==
1716 payload_size,
1717 &external_addr))
1718 {
1719 /* We now know that a server at "sa" claims that
1720 we are visible at IP "external_addr".
1721
1722 We should (for some fixed period of time) tell
1723 all of our clients that listen to a NAT'ed address
1724 that they might want to consider the given 'external_ip'
1725 as their public IP address (this includes TCP and UDP
1726 clients, even if only UDP sends STUN requests).
1727
1728 If we do not get a renewal, the "external_addr" should be
1729 removed again. The timeout frequency should be configurable
1730 (with a sane default), so that the UDP plugin can tell how
1731 often to re-request STUN.
1732 */struct StunExternalIP *se;
1733
1734 /* Check if we had a prior response from this STUN server */
1735 for (se = se_head; NULL != se; se = se->next)
1736 {
1737 if ((se->stun_server_addr_len != sa_len) ||
1738 (0 != memcmp (sa,
1739 &se->stun_server_addr,
1740 sa_len)))
1741 continue; /* different STUN server */
1742 if (0 != GNUNET_memcmp (&external_addr,
1743 &se->external_addr))
1744 {
1745 /* external IP changed, update! */
1747 GNUNET_NO);
1750 GNUNET_YES);
1751 }
1752 /* update timeout */
1754 se->timeout_task
1757 se);
1758 return;
1759 }
1760 /* STUN server is completely new, create fresh entry */
1761 se = GNUNET_new (struct StunExternalIP);
1764 sa,
1765 sa_len);
1766 se->stun_server_addr_len = sa_len;
1769 se);
1771 se_tail,
1772 se);
1774 GNUNET_NO);
1775 }
1777}
1778
1779
1789static int
1791 const struct
1793 message)
1794{
1795 size_t expect;
1796
1797 expect = ntohs (message->local_addr_size)
1798 + ntohs (message->remote_addr_size);
1799 if (ntohs (message->header.size) - sizeof(*message) != expect)
1800 {
1801 GNUNET_break (0);
1802 return GNUNET_SYSERR;
1803 }
1804 return GNUNET_OK;
1805}
1806
1807
1815static void
1817 void *cls,
1818 const struct GNUNET_NAT_RequestConnectionReversalMessage *message)
1819{
1820 struct ClientHandle *ch = cls;
1821 const char *buf = (const char *) &message[1];
1822 size_t local_sa_len = ntohs (message->local_addr_size);
1823 size_t remote_sa_len = ntohs (message->remote_addr_size);
1824 struct sockaddr_in l4;
1825 struct sockaddr_in r4;
1826 int ret;
1827
1829 "Received REQUEST CONNECTION REVERSAL message from client\n");
1830 if (local_sa_len != sizeof(struct sockaddr_in))
1831 {
1832 GNUNET_break_op (0);
1834 return;
1835 }
1836 if (remote_sa_len != sizeof(struct sockaddr_in))
1837 {
1838 GNUNET_break_op (0);
1840 return;
1841 }
1842 GNUNET_memcpy (&l4,
1843 buf,
1844 sizeof(struct sockaddr_in));
1845 GNUNET_break_op (AF_INET == l4.sin_family);
1846 buf += sizeof(struct sockaddr_in);
1847 GNUNET_memcpy (&r4,
1848 buf,
1849 sizeof(struct sockaddr_in));
1850 GNUNET_break_op (AF_INET == r4.sin_family);
1851 ret = GN_request_connection_reversal (&l4.sin_addr,
1852 ntohs (l4.sin_port),
1853 &r4.sin_addr,
1854 cfg);
1855 if (GNUNET_OK != ret)
1857 _ ("Connection reversal request failed\n"));
1859}
1860
1861
1870static enum GNUNET_GenericReturnValue
1872 void *cls,
1873 const struct GNUNET_NAT_AddGlobalAddressMessage *message)
1874{
1875 //const char *buf = (const char *) &message[1];
1876 //uint16_t blen = ntohs (message->address_length);
1877 size_t left = ntohs (message->header.size) - sizeof(*message);
1878
1879 if (left != ntohs (message->address_length))
1880 {
1881 GNUNET_break_op (0);
1882 return GNUNET_SYSERR;
1883 }
1884 /* if ('\0' != buf[blen - 1]) */
1885 /* { */
1886 /* GNUNET_break_op (0); */
1887 /* return GNUNET_SYSERR; */
1888 /* } */
1889 return GNUNET_OK;
1890}
1891
1892
1900static void
1902 void *cls,
1903 const struct GNUNET_NAT_AddGlobalAddressMessage *message)
1904{
1905 struct ClientHandle *ch = cls;
1906 const char *buf = (const char *) &message[1];
1907 //uint16_t blen = ntohs (message->address_length);
1908 struct sockaddr_in sockaddr_ipv4 = {
1909 .sin_family = AF_INET
1910 };
1911
1912 //GNUNET_assert ('\0' == buf[blen - 1]);
1913 if (1 != inet_pton (AF_INET,
1914 buf,
1915 &sockaddr_ipv4.sin_addr))
1916 {
1918 "natting address %s length %u no ipv4\n",
1919 buf,
1920 message->address_length);
1921 GNUNET_break (0);
1923 return;
1924 }
1925 notify_clients_stun_change (&sockaddr_ipv4,
1926 GNUNET_YES);
1928}
1929
1930
1936static void
1937shutdown_task (void *cls)
1938{
1939 struct StunExternalIP *se;
1940
1941 while (NULL != (se = se_head))
1942 {
1944 se_tail,
1945 se);
1947 GNUNET_free (se);
1948 }
1950 if (NULL != scan_task)
1951 {
1953 scan_task = NULL;
1954 }
1955 if (NULL != stats)
1956 {
1958 GNUNET_NO);
1959 stats = NULL;
1960 }
1961 destroy_lal ();
1962}
1963
1964
1972static void
1973run (void *cls,
1974 const struct GNUNET_CONFIGURATION_Handle *c,
1976{
1977 cfg = c;
1978 if (GNUNET_OK !=
1980 "NAT",
1981 "STUN_STALE",
1984
1985 /* Check for UPnP */
1988 "NAT",
1989 "ENABLE_UPNP");
1990 if (GNUNET_YES == enable_upnp)
1991 {
1992 /* check if it works */
1993 if (GNUNET_SYSERR ==
1995 GNUNET_NO,
1996 NULL))
1997 {
1999 _ (
2000 "UPnP enabled in configuration, but UPnP client `upnpc` command not found, disabling UPnP\n"));
2002 }
2003 }
2004 if (GNUNET_OK !=
2006 "nat",
2007 "DYNDNS_FREQUENCY",
2010
2013 "NAT",
2014 "ENABLE_IPSCAN");
2015
2017 NULL);
2019 cfg);
2022 NULL);
2023}
2024
2025
2034static void *
2035client_connect_cb (void *cls,
2036 struct GNUNET_SERVICE_Client *c,
2037 struct GNUNET_MQ_Handle *mq)
2038{
2039 struct ClientHandle *ch;
2040
2041 ch = GNUNET_new (struct ClientHandle);
2042 ch->mq = mq;
2043 ch->client = c;
2045 ch_tail,
2046 ch);
2047 return ch;
2048}
2049
2050
2058static void
2059client_disconnect_cb (void *cls,
2060 struct GNUNET_SERVICE_Client *c,
2061 void *internal_cls)
2062{
2063 struct ClientHandle *ch = internal_cls;
2064 struct LocalAddressList *lal;
2065
2067 ch_tail,
2068 ch);
2069 for (unsigned int i = 0; i < ch->num_caddrs; i++)
2070 {
2071 if (NULL != ch->caddrs[i].mh)
2072 {
2073 GNUNET_NAT_mini_map_stop (ch->caddrs[i].mh);
2074 ch->caddrs[i].mh = NULL;
2075 }
2076 }
2077 GNUNET_free (ch->caddrs);
2078 while (NULL != (lal = ch->ext_addr_head))
2079 {
2080 GNUNET_CONTAINER_DLL_remove (ch->ext_addr_head,
2081 ch->ext_addr_tail,
2082 lal);
2083 GNUNET_free (lal);
2084 }
2085 if (NULL != ch->ext_dns_task)
2086 {
2087 GNUNET_SCHEDULER_cancel (ch->ext_dns_task);
2088 ch->ext_dns_task = NULL;
2089 }
2090 if (NULL != ch->external_monitor)
2091 {
2092 GN_external_ipv4_monitor_stop (ch->external_monitor);
2093 ch->external_monitor = NULL;
2094 }
2095 if (NULL != ch->ext_dns)
2096 {
2098 ch->ext_dns = NULL;
2099 }
2100 GNUNET_free (ch->hole_external);
2101 GNUNET_free (ch->section_name);
2102 GNUNET_free (ch);
2103}
2104
2105
2111 "nat",
2113 &run,
2116 NULL,
2117 GNUNET_MQ_hd_var_size (register,
2120 NULL),
2124 NULL),
2125 GNUNET_MQ_hd_var_size (request_connection_reversal,
2128 NULL),
2129 GNUNET_MQ_hd_var_size (add_global_address,
2132 NULL),
2134
2135
2136#if defined(__linux__) && defined(__GLIBC__)
2137#include <malloc.h>
2138
2139void __attribute__ ((constructor))
2140GNUNET_NATM_memory_init (void);
2141
2145void __attribute__ ((constructor))
2146GNUNET_NATM_memory_init (void)
2147{
2148 mallopt (M_TRIM_THRESHOLD, 4 * 1024);
2149 mallopt (M_TOP_PAD, 1 * 1024);
2150 malloc_trim (0);
2151}
2152
2153
2154#endif
2155
2156/* 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 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:305
#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:1339
void * GNUNET_SCHEDULER_cancel(struct GNUNET_SCHEDULER_Task *task)
Cancel the task with the specified identifier.
Definition scheduler.c:980
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:1304
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:1277
#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:2462
void GNUNET_SERVICE_client_continue(struct GNUNET_SERVICE_Client *c)
Continue receiving further messages from the given client.
Definition service.c:2433
@ 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:136
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 348 of file gnunet-service-nat.c.

349{
351 lal_tail,
352 lal);
353 if (NULL != lal->hc)
354 {
356 "Lost NATed local address %s, stopping NAT server\n",
357 GNUNET_a2s ((const struct sockaddr *) &lal->addr,
358 sizeof(struct sockaddr_in)));
359
361 lal->hc = NULL;
362 }
363 GNUNET_free (lal);
364}

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 371 of file gnunet-service-nat.c.

372{
373 struct LocalAddressList *lal;
374
375 while (NULL != (lal = lal_head))
376 free_lal (lal);
377}

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 389 of file gnunet-service-nat.c.

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

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 451 of file gnunet-service-nat.c.

454{
455 struct in_addr net;
456
457 if (0 == ip->s_addr)
458 return GNUNET_YES;
459 if (0 == bits)
460 return GNUNET_YES;
461 GNUNET_assert (1 == inet_pton (AF_INET,
462 network,
463 &net));
464 return ! ((ip->s_addr ^ net.s_addr) & htonl (0xFFFFFFFFu << (32 - bits)));
465}

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 477 of file gnunet-service-nat.c.

480{
481 struct in6_addr net;
482 struct in6_addr mask;
483 unsigned int off;
484
485 if (0 == bits)
486 return GNUNET_YES;
487 GNUNET_assert (1 == inet_pton (AF_INET6,
488 network,
489 &net));
490 memset (&mask, 0, sizeof(mask));
491 if (0 == GNUNET_memcmp (&mask,
492 ip))
493 return GNUNET_YES;
494 off = 0;
495 while (bits > 8)
496 {
497 mask.s6_addr[off++] = 0xFF;
498 bits -= 8;
499 }
500 while (bits > 0)
501 {
502 mask.s6_addr[off] = (mask.s6_addr[off] >> 1) + 0x80;
503 bits--;
504 }
505 for (unsigned j = 0; j < sizeof(struct in6_addr) / sizeof(uint32_t); j++)
506 if (((((uint32_t *) ip)[j] & ((uint32_t *) &mask)[j])) !=
507 (((uint32_t *) &net)[j] & ((int *) &mask)[j]))
508 return GNUNET_NO;
509 return GNUNET_YES;
510}

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 521 of file gnunet-service-nat.c.

522{
523 return
524 match_ipv4 ("10.0.0.0", ip, 8) || /* RFC 1918 */
525 match_ipv4 ("100.64.0.0", ip, 10) || /* CG-NAT, RFC 6598 */
526 match_ipv4 ("192.168.0.0", ip, 12) || /* RFC 1918 */
527 match_ipv4 ("169.254.0.0", ip, 16) || /* AUTO, RFC 3927 */
528 match_ipv4 ("172.16.0.0", ip, 16); /* RFC 1918 */
529}

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 540 of file gnunet-service-nat.c.

541{
542 return
543 match_ipv6 ("fc00::", ip, 7) || /* RFC 4193 */
544 match_ipv6 ("fec0::", ip, 10) || /* RFC 3879 */
545 match_ipv6 ("fe80::", ip, 10); /* RFC 4291, link-local */
546}

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 580 of file gnunet-service-nat.c.

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

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 658 of file gnunet-service-nat.c.

663{
664 struct GNUNET_MQ_Envelope *env;
666
668 "Notifying client about %s of IP %s\n",
669 add ? "addition" : "removal",
670 GNUNET_a2s (addr,
671 addr_len));
673 addr_len,
675 msg->add_remove = htonl (add);
676 msg->addr_class = htonl (ac);
677 GNUNET_memcpy (&msg[1],
678 addr,
679 addr_len);
681 env);
682}

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 694 of file gnunet-service-nat.c.

697{
698 size_t alen;
699 struct sockaddr_in v4;
700 struct sockaddr_in6 v6;
701
702 if (0 == (ch->flags & GNUNET_NAT_RF_ADDRESSES))
703 {
705 "Not notifying client as it does not care about addresses\n");
706 return;
707 }
708 switch (delta->af)
709 {
710 case AF_INET:
711 alen = sizeof(struct sockaddr_in);
712 GNUNET_memcpy (&v4,
713 &delta->addr,
714 alen);
715
716 /* Check for client notifications */
717 for (unsigned int i = 0; i < ch->num_caddrs; i++)
718 {
719 const struct sockaddr_in *c4;
720
721 if (AF_INET != ch->caddrs[i].ss.ss_family)
722 continue; /* IPv4 not relevant */
723 c4 = (const struct sockaddr_in *) &ch->caddrs[i].ss;
724 if (match_ipv4 ("127.0.0.1", &c4->sin_addr, 8) &&
725 (0 != c4->sin_addr.s_addr) &&
726 (! match_ipv4 ("127.0.0.1", &v4.sin_addr, 8)))
727 continue; /* bound to loopback, but this is not loopback */
728 if ((! match_ipv4 ("127.0.0.1", &c4->sin_addr, 8)) &&
729 match_ipv4 ("127.0.0.1", &v4.sin_addr, 8))
730 continue; /* bound to non-loopback, but this is loopback */
731 if ((0 != (delta->ac & GNUNET_NAT_AC_EXTERN)) &&
732 (0 != c4->sin_addr.s_addr) &&
733 (! is_nat_v4 (&v4.sin_addr)))
734 continue; /* based on external-IP, but this IP is not
735 from private address range. */
736 if ((0 != GNUNET_memcmp (&v4.sin_addr,
737 &c4->sin_addr)) &&
738 (0 != c4->sin_addr.s_addr) &&
739 (! is_nat_v4 (&c4->sin_addr)))
740 continue; /* this IP is not from private address range,
741 and IP does not match. */
742
743 /* OK, IP seems relevant, notify client */
744 if (0 == htons (v4.sin_port))
745 v4.sin_port = c4->sin_port;
746 notify_client (delta->ac,
747 ch,
748 add,
749 &v4,
750 alen);
751 }
752 break;
753
754 case AF_INET6:
755 alen = sizeof(struct sockaddr_in6);
756 GNUNET_memcpy (&v6,
757 &delta->addr,
758 alen);
759 for (unsigned int i = 0; i < ch->num_caddrs; i++)
760 {
761 const struct sockaddr_in6 *c6;
762
763 if (AF_INET6 != ch->caddrs[i].ss.ss_family)
764 continue; /* IPv4 not relevant */
765 c6 = (const struct sockaddr_in6 *) &ch->caddrs[i].ss;
766 if (match_ipv6 ("::1", &c6->sin6_addr, 128) &&
767 (0 != GNUNET_memcmp (&c6->sin6_addr,
768 &in6addr_any)) &&
769 (! match_ipv6 ("::1", &v6.sin6_addr, 128)))
770 continue; /* bound to loopback, but this is not loopback */
771 if ((! match_ipv6 ("::1", &c6->sin6_addr, 128)) &&
772 match_ipv6 ("::1", &v6.sin6_addr, 128))
773 continue; /* bound to non-loopback, but this is loopback */
774 if ((0 != (delta->ac & GNUNET_NAT_AC_EXTERN)) &&
775 (0 != GNUNET_memcmp (&c6->sin6_addr,
776 &in6addr_any)) &&
777 (! is_nat_v6 (&v6.sin6_addr)))
778 continue; /* based on external-IP, but this IP is not
779 from private address range. */
780 if ((0 != GNUNET_memcmp (&v6.sin6_addr,
781 &c6->sin6_addr)) &&
782 (0 != GNUNET_memcmp (&c6->sin6_addr,
783 &in6addr_any)) &&
784 (! is_nat_v6 (&c6->sin6_addr)))
785 continue; /* this IP is not from private address range,
786 and IP does not match. */
787 if ((match_ipv6 ("fe80::", &c6->sin6_addr, 10)) &&
788 (0 != GNUNET_memcmp (&c6->sin6_addr,
789 &in6addr_any)) &&
790 (0 != GNUNET_memcmp (&v6.sin6_addr,
791 &c6->sin6_addr)) &&
792 (0 == (delta->ac & GNUNET_NAT_AC_EXTERN)))
793 continue; /* client bound to link-local, and the other address
794 does not match and is not an external IP */
795
796 /* OK, IP seems relevant, notify client */
797 if (0 == htons (v6.sin6_port))
798 v6.sin6_port = c6->sin6_port;
799 notify_client (delta->ac,
800 ch,
801 add,
802 &v6,
803 alen);
804 }
805 break;
806
807 default:
808 GNUNET_break (0);
809 return;
810 }
811}

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

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 822 of file gnunet-service-nat.c.

824{
825 for (struct ClientHandle *ch = ch_head;
826 NULL != ch;
827 ch = ch->next)
829 ch,
830 add);
831}

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 843 of file gnunet-service-nat.c.

846{
847 struct ClientHandle *ch = cls;
848 struct sockaddr_in sa;
849 int have_v4;
850
851 /* (0) check if this impacts 'hole_external' */
852 if ((NULL != ch->hole_external) &&
853 (0 == strcasecmp (ch->hole_external,
854 "AUTO")))
855 {
856 struct LocalAddressList lal;
857 struct sockaddr_in *s4;
858
860 "Detected eternal IP, can now back-fill AUTO:%u in hole punching specification of `%s'\n",
861 (unsigned int) ch->ext_dns_port,
862 ch->section_name);
863 memset (&lal, 0, sizeof(lal));
864 s4 = (struct sockaddr_in *) &lal.addr;
865 s4->sin_family = AF_INET;
866 s4->sin_port = htons (ch->ext_dns_port);
867 s4->sin_addr = *v4;
868 lal.af = AF_INET;
871 ch,
872 add);
873 }
874
875 /* (1) check if client cares. */
876 if (! ch->natted_address)
877 return;
878 have_v4 = GNUNET_NO;
879 for (unsigned int i = 0; i < ch->num_caddrs; i++)
880 {
881 const struct sockaddr_storage *ss = &ch->caddrs[i].ss;
882
883 if (AF_INET != ss->ss_family)
884 continue;
885 have_v4 = GNUNET_YES;
886 break;
887 }
888 if (GNUNET_NO == have_v4)
889 return; /* IPv6-only */
890
891 /* (2) build address info */
892 memset (&sa,
893 0,
894 sizeof(sa));
895 sa.sin_family = AF_INET;
896 sa.sin_addr = *v4;
897 sa.sin_port = htons (0);
898
900 "Detected eternal IP %s, notifying client of external IP (without port)\n",
901 GNUNET_a2s ((const struct sockaddr *) &sa,
902 sizeof(sa)));
903 /* (3) notify client of change */
907 ch,
908 add,
909 &sa,
910 sizeof(sa));
911}

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 922 of file gnunet-service-nat.c.

924{
925 struct LocalAddressList *lal = cls;
926 const struct sockaddr_in *l4;
927
928 GNUNET_assert (AF_INET == lal->af);
929 l4 = (const struct sockaddr_in *) &lal->addr;
930 for (struct ClientHandle *ch = ch_head;
931 NULL != ch;
932 ch = ch->next)
933 {
935 struct GNUNET_MQ_Envelope *env;
936 int match;
937
938 /* Check if client is in applicable range for ICMP NAT traversal
939 for this local address */
940 if (! ch->natted_address)
941 continue;
942 match = GNUNET_NO;
943 for (unsigned int i = 0; i < ch->num_caddrs; i++)
944 {
945 struct ClientAddress *ca = &ch->caddrs[i];
946 const struct sockaddr_in *c4;
947
948 if (AF_INET != ca->ss.ss_family)
949 continue;
950 c4 = (const struct sockaddr_in *) &ca->ss;
951 if ((0 != c4->sin_addr.s_addr) &&
952 (l4->sin_addr.s_addr != c4->sin_addr.s_addr))
953 continue;
954 match = GNUNET_YES;
955 break;
956 }
957 if (! match)
958 continue;
959
960 /* Notify applicable client about connection reversal request */
961 env = GNUNET_MQ_msg_extra (crrm,
962 sizeof(struct sockaddr_in),
964 GNUNET_memcpy (&crrm[1],
965 ra,
966 sizeof(struct sockaddr_in));
968 env);
969 }
970}

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 979 of file gnunet-service-nat.c.

980{
981 struct IfcProcContext ifc_ctx;
982 int found;
983 int have_nat;
984 struct LocalAddressList *lnext;
985
987 &run_scan,
988 NULL);
989 memset (&ifc_ctx,
990 0,
991 sizeof(ifc_ctx));
993 &ifc_ctx);
994 /* remove addresses that disappeared */
995 for (struct LocalAddressList *lal = lal_head;
996 NULL != lal;
997 lal = lnext)
998 {
999 lnext = lal->next;
1000 found = GNUNET_NO;
1001 for (struct LocalAddressList *pos = ifc_ctx.lal_head;
1002 NULL != pos;
1003 pos = pos->next)
1004 {
1005 if ((pos->af == lal->af) &&
1006 (0 == memcmp (&lal->addr,
1007 &pos->addr,
1008 (AF_INET == lal->af)
1009 ? sizeof(struct sockaddr_in)
1010 : sizeof(struct sockaddr_in6))))
1011 {
1012 found = GNUNET_YES;
1013 }
1014 }
1015 if (GNUNET_NO == found)
1016 {
1017 notify_clients (lal,
1018 GNUNET_NO);
1019 free_lal (lal);
1020 }
1021 }
1022
1023 /* add addresses that appeared */
1024 have_nat = GNUNET_NO;
1025 for (struct LocalAddressList *pos = ifc_ctx.lal_head;
1026 NULL != pos;
1027 pos = ifc_ctx.lal_head)
1028 {
1029 found = GNUNET_NO;
1030 if (GNUNET_NAT_AC_LAN == (GNUNET_NAT_AC_LAN & pos->ac))
1031 have_nat = GNUNET_YES;
1032 for (struct LocalAddressList *lal = lal_head;
1033 NULL != lal;
1034 lal = lal->next)
1035 {
1036 if ((pos->af == lal->af) &&
1037 (0 == memcmp (&lal->addr,
1038 &pos->addr,
1039 (AF_INET == lal->af)
1040 ? sizeof(struct sockaddr_in)
1041 : sizeof(struct sockaddr_in6))))
1042 found = GNUNET_YES;
1043 }
1044 GNUNET_CONTAINER_DLL_remove (ifc_ctx.lal_head,
1045 ifc_ctx.lal_tail,
1046 pos);
1047 if (GNUNET_YES == found)
1048 {
1049 GNUNET_free (pos);
1050 }
1051 else
1052 {
1053 notify_clients (pos,
1054 GNUNET_YES);
1056 lal_tail,
1057 pos);
1058 if ((AF_INET == pos->af) &&
1059 (NULL == pos->hc) &&
1060 (0 != (GNUNET_NAT_AC_LAN & pos->ac)))
1061 {
1062 const struct sockaddr_in *s4
1063 = (const struct sockaddr_in *) &pos->addr;
1064
1066 "Found NATed local address %s, starting NAT server\n",
1067 GNUNET_a2s ((const struct sockaddr *) &pos->addr,
1068 sizeof(*s4)));
1069 pos->hc = GN_start_gnunet_nat_server_ (&s4->sin_addr,
1071 pos,
1072 cfg);
1073 }
1074 }
1075 }
1076 GN_nat_status_changed (have_nat);
1077}

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 1092 of file gnunet-service-nat.c.

1097{
1098 struct ClientHandle *ch = cls;
1100
1101 switch (result)
1102 {
1104 GNUNET_assert (NULL != addr);
1105 break;
1106
1111 "Running upnpc failed: %d\n",
1112 result);
1113 return;
1114
1117 "external-ip binary not found\n");
1118 return;
1119
1122 "upnpc binary not found\n");
1123 return;
1124
1127 "external-ip binary could not be run\n");
1128 return;
1129
1132 "upnpc failed to create port mapping\n");
1133 return;
1134
1137 "Invalid output from upnpc\n");
1138 return;
1139
1142 "Invalid address returned by upnpc\n");
1143 return;
1144
1145 default:
1146 GNUNET_break (0); /* should not be possible */
1147 return;
1148 }
1149 switch (addr->sa_family)
1150 {
1151 case AF_INET:
1152 ac = is_nat_v4 (&((const struct sockaddr_in *) addr)->sin_addr)
1155 break;
1156
1157 case AF_INET6:
1158 ac = is_nat_v6 (&((const struct sockaddr_in6 *) addr)->sin6_addr)
1161 break;
1162
1163 default:
1164 GNUNET_break (0);
1165 return;
1166 }
1168 "upnp external address %s: %s\n",
1169 add_remove ? "added" : "removed",
1170 GNUNET_a2s (addr,
1171 addrlen));
1172 notify_client (ac,
1173 ch,
1174 add_remove,
1175 addr,
1176 addrlen);
1177}

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 1305 of file gnunet-service-nat.c.

1306{
1307 struct ClientHandle *ch = cls;
1308 struct LocalAddressList *lal;
1309
1311 "Performing DNS lookup for punched hole given for `%s' as `%s:%u'\n",
1312 ch->section_name,
1313 ch->hole_external,
1314 (unsigned int) ch->ext_dns_port);
1315 for (lal = ch->ext_addr_head; NULL != lal; lal = lal->next)
1316 lal->old = GNUNET_YES;
1317 ch->ext_dns_task = NULL;
1318 ch->ext_dns = GNUNET_RESOLVER_ip_get (ch->hole_external,
1319 AF_UNSPEC,
1322 ch);
1323}

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 1202 of file gnunet-service-nat.c.

1205{
1206 struct ClientHandle *ch = cls;
1207 struct LocalAddressList *lal;
1208 struct sockaddr_storage ss;
1209 struct sockaddr_in *v4;
1210 struct sockaddr_in6 *v6;
1211
1212 if (NULL == addr)
1213 {
1214 struct LocalAddressList *laln;
1215
1216 ch->ext_dns = NULL;
1217 ch->ext_dns_task
1220 ch);
1221 /* Current iteration is over, remove 'old' IPs now */
1222 for (lal = ch->ext_addr_head; NULL != lal; lal = laln)
1223 {
1224 laln = lal->next;
1225 if (GNUNET_YES == lal->old)
1226 {
1227 GNUNET_CONTAINER_DLL_remove (ch->ext_addr_head,
1228 ch->ext_addr_tail,
1229 lal);
1231 ch,
1232 GNUNET_NO);
1233 GNUNET_free (lal);
1234 }
1235 }
1236 return;
1237 }
1239 "Got IP `%s' for external address `%s'\n",
1241 addrlen),
1242 ch->hole_external);
1243
1244 /* build sockaddr storage with port number */
1245 memset (&ss,
1246 0,
1247 sizeof(ss));
1248 GNUNET_memcpy (&ss,
1249 addr,
1250 addrlen);
1251 switch (addr->sa_family)
1252 {
1253 case AF_INET:
1254 v4 = (struct sockaddr_in *) &ss;
1255 v4->sin_port = htons (ch->ext_dns_port);
1256 break;
1257
1258 case AF_INET6:
1259 v6 = (struct sockaddr_in6 *) &ss;
1260 v6->sin6_port = htons (ch->ext_dns_port);
1261 break;
1262
1263 default:
1264 GNUNET_break (0);
1265 return;
1266 }
1267 /* See if 'ss' matches any of our known addresses */
1268 for (lal = ch->ext_addr_head; NULL != lal; lal = lal->next)
1269 {
1270 if (GNUNET_NO == lal->old)
1271 continue; /* already processed, skip */
1272 if ((addr->sa_family == lal->addr.ss_family) &&
1273 (0 == memcmp (&ss,
1274 &lal->addr,
1275 addrlen)))
1276 {
1277 /* Address unchanged, remember so we do not remove */
1278 lal->old = GNUNET_NO;
1279 return; /* done here */
1280 }
1281 }
1282 /* notify client, and remember IP for later removal! */
1283 lal = GNUNET_new (struct LocalAddressList);
1284 lal->addr = ss;
1285 lal->af = ss.ss_family;
1287 GNUNET_CONTAINER_DLL_insert (ch->ext_addr_head,
1288 ch->ext_addr_tail,
1289 lal);
1291 ch,
1292 GNUNET_YES);
1293}

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 1338 of file gnunet-service-nat.c.

1339{
1340 char *port;
1341 unsigned int pnum;
1342 struct sockaddr_in *s4;
1343 struct LocalAddressList *lal;
1344
1345 port = strrchr (ch->hole_external, ':');
1346 if (NULL == port)
1347 {
1349 _ ("Malformed punched hole specification `%s' (lacks port)\n"),
1350 ch->hole_external);
1351 return;
1352 }
1353 if ((1 != sscanf (port + 1,
1354 "%u",
1355 &pnum)) ||
1356 (pnum > 65535))
1357 {
1359 _ (
1360 "Invalid port number in punched hole specification `%s' (lacks port)\n"),
1361 port + 1);
1362 return;
1363 }
1364 ch->ext_dns_port = (uint16_t) pnum;
1365 *port = '\0';
1366
1367 lal = GNUNET_new (struct LocalAddressList);
1368 if ('[' == *ch->hole_external)
1369 {
1370 struct sockaddr_in6 *s6 = (struct sockaddr_in6 *) &lal->addr;
1371
1372 s6->sin6_family = AF_INET6;
1373 if (']' != (ch->hole_external[strlen (ch->hole_external) - 1]))
1374 {
1376 _ ("Malformed punched hole specification `%s' (lacks `]')\n"),
1377 ch->hole_external);
1378 GNUNET_free (lal);
1379 return;
1380 }
1381 ch->hole_external[strlen (ch->hole_external) - 1] = '\0';
1382 if (1 != inet_pton (AF_INET6,
1383 ch->hole_external + 1,
1384 &s6->sin6_addr))
1385 {
1387 _ (
1388 "Malformed punched hole specification `%s' (IPv6 address invalid)"),
1389 ch->hole_external + 1);
1390 GNUNET_free (lal);
1391 return;
1392 }
1393 s6->sin6_port = htons (ch->ext_dns_port);
1394 lal->af = AF_INET6;
1396 GNUNET_CONTAINER_DLL_insert (ch->ext_addr_head,
1397 ch->ext_addr_tail,
1398 lal);
1400 ch,
1401 GNUNET_YES);
1402 return;
1403 }
1404
1405 s4 = (struct sockaddr_in *) &lal->addr;
1406 s4->sin_family = AF_INET;
1407 if (1 == inet_pton (AF_INET,
1408 ch->hole_external,
1409 &s4->sin_addr))
1410 {
1412 "IPv4 punched hole given for `%s' via `%s:%u'\n",
1413 ch->section_name,
1414 ch->hole_external,
1415 (unsigned int) ch->ext_dns_port);
1416 s4->sin_port = htons (ch->ext_dns_port);
1417 lal->af = AF_INET;
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 if (0 == strcasecmp (ch->hole_external,
1428 "AUTO"))
1429 {
1430 /* handled in #notify_client_external_ipv4_change() */
1431 GNUNET_free (lal);
1432 return;
1433 }
1434 /* got a DNS name, trigger lookup! */
1435 GNUNET_free (lal);
1436 ch->ext_dns_task
1438 ch);
1439}

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 1450 of file gnunet-service-nat.c.

1452{
1453 struct ClientHandle *ch = cls;
1454 const char *off;
1455 size_t left;
1456
1457 if ((0 != ch->proto) ||
1458 (NULL != ch->caddrs))
1459 {
1460 /* double registration not allowed */
1461 GNUNET_break (0);
1463 return;
1464 }
1465 ch->flags = message->flags;
1466 ch->proto = message->proto;
1467 ch->num_caddrs = ntohs (message->num_addrs);
1468 ch->caddrs = GNUNET_new_array (ch->num_caddrs,
1469 struct ClientAddress);
1470 left = ntohs (message->header.size) - sizeof(*message);
1471 off = (const char *) &message[1];
1472 for (unsigned int i = 0; i < ch->num_caddrs; i++)
1473 {
1474 const struct sockaddr *sa = (const struct sockaddr *) off;
1475 size_t alen;
1476 uint16_t port;
1477 int is_nat;
1478
1479 if (sizeof(sa_family_t) > left)
1480 {
1481 GNUNET_break (0);
1483 return;
1484 }
1485 is_nat = GNUNET_NO;
1486 switch (sa->sa_family)
1487 {
1488 case AF_INET:
1489 {
1490 struct sockaddr_in s4;
1491
1492 GNUNET_memcpy (&s4,
1493 off,
1494 sizeof(struct sockaddr_in));
1495 alen = sizeof(struct sockaddr_in);
1496 if (is_nat_v4 (&s4.sin_addr))
1497 is_nat = GNUNET_YES;
1498 port = ntohs (s4.sin_port);
1499 }
1500 break;
1501
1502 case AF_INET6:
1503 {
1504 struct sockaddr_in6 s6;
1505
1506 GNUNET_memcpy (&s6,
1507 off,
1508 sizeof(struct sockaddr_in6));
1509 alen = sizeof(struct sockaddr_in6);
1510 if (is_nat_v6 (&s6.sin6_addr))
1511 is_nat = GNUNET_YES;
1512 port = ntohs (s6.sin6_port);
1513 }
1514 break;
1515
1516#if AF_UNIX
1517 case AF_UNIX:
1518 alen = sizeof(struct sockaddr_un);
1519 port = 0;
1520 break;
1521#endif
1522 default:
1523 GNUNET_break (0);
1525 return;
1526 }
1527 /* store address */
1528 GNUNET_assert (alen <= left);
1529 GNUNET_assert (alen <= sizeof(struct sockaddr_storage));
1530 GNUNET_memcpy (&ch->caddrs[i].ss,
1531 off,
1532 alen);
1533
1534 /* If applicable, try UPNPC NAT punching */
1535 if ((is_nat) &&
1536 (enable_upnp) &&
1537 ((IPPROTO_TCP == ch->proto) ||
1538 (IPPROTO_UDP == ch->proto)))
1539 {
1540 ch->natted_address = GNUNET_YES;
1541 ch->caddrs[i].mh
1543 IPPROTO_TCP == ch->proto,
1545 ch);
1546 }
1547
1548 off += alen;
1549 }
1550
1551 ch->section_name
1552 = GNUNET_strndup (off,
1553 ntohs (message->str_len));
1555 "Received REGISTER message from client for subsystem `%s'\n",
1556 ch->section_name);
1557 if (GNUNET_OK ==
1559 ch->section_name,
1560 "HOLE_EXTERNAL",
1561 &ch->hole_external))
1563
1564 /* Actually send IP address list to client */
1565 for (struct LocalAddressList *lal = lal_head;
1566 NULL != lal;
1567 lal = lal->next)
1568 {
1570 ch,
1571 GNUNET_YES);
1572 }
1573 /* Also consider IPv4 determined by `external-ip` */
1574 ch->external_monitor
1576 ch);
1578}

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 1590 of file gnunet-service-nat.c.

1592{
1593 size_t sa_len = ntohs (message->sender_addr_size);
1594 size_t expect = sa_len + ntohs (message->payload_size);
1595
1596 if (ntohs (message->header.size) - sizeof(*message) != expect)
1597 {
1598 GNUNET_break (0);
1599 return GNUNET_SYSERR;
1600 }
1601 if (sa_len < sizeof(sa_family_t))
1602 {
1603 GNUNET_break (0);
1604 return GNUNET_SYSERR;
1605 }
1606 return GNUNET_OK;
1607}

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 1618 of file gnunet-service-nat.c.

1620{
1621 for (struct ClientHandle *ch = ch_head;
1622 NULL != ch;
1623 ch = ch->next)
1624 {
1625 struct sockaddr_in v4;
1627 struct GNUNET_MQ_Envelope *env;
1628
1629 if (! ch->natted_address)
1630 continue;
1631 v4 = *ip;
1632 v4.sin_port = htons (0);
1634 sizeof(v4),
1636 msg->add_remove = htonl ((int32_t) add);
1637 msg->addr_class = htonl (GNUNET_NAT_AC_EXTERN
1639 GNUNET_memcpy (&msg[1],
1640 &v4,
1641 sizeof(v4));
1643 env);
1644 }
1645}

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 1656 of file gnunet-service-nat.c.

1657{
1658 struct StunExternalIP *se = cls;
1659
1660 se->timeout_task = NULL;
1662 GNUNET_NO);
1664 se_tail,
1665 se);
1666 GNUNET_free (se);
1667}

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 1678 of file gnunet-service-nat.c.

1680{
1681 struct ClientHandle *ch = cls;
1682 const char *buf = (const char *) &message[1];
1683 const struct sockaddr *sa;
1684 const void *payload;
1685 size_t sa_len;
1686 size_t payload_size;
1687 struct sockaddr_in external_addr;
1688
1689 sa_len = ntohs (message->sender_addr_size);
1690 payload_size = ntohs (message->payload_size);
1691 sa = (const struct sockaddr *) &buf[0];
1692 payload = (const struct sockaddr *) &buf[sa_len];
1693 switch (sa->sa_family)
1694 {
1695 case AF_INET:
1696 if (sa_len != sizeof(struct sockaddr_in))
1697 {
1698 GNUNET_break (0);
1700 return;
1701 }
1702 break;
1703
1704 case AF_INET6:
1705 if (sa_len != sizeof(struct sockaddr_in6))
1706 {
1707 GNUNET_break (0);
1709 return;
1710 }
1711 break;
1712 }
1714 "Received HANDLE_STUN message from client\n");
1715 if (GNUNET_OK ==
1717 payload_size,
1718 &external_addr))
1719 {
1720 /* We now know that a server at "sa" claims that
1721 we are visible at IP "external_addr".
1722
1723 We should (for some fixed period of time) tell
1724 all of our clients that listen to a NAT'ed address
1725 that they might want to consider the given 'external_ip'
1726 as their public IP address (this includes TCP and UDP
1727 clients, even if only UDP sends STUN requests).
1728
1729 If we do not get a renewal, the "external_addr" should be
1730 removed again. The timeout frequency should be configurable
1731 (with a sane default), so that the UDP plugin can tell how
1732 often to re-request STUN.
1733 */struct StunExternalIP *se;
1734
1735 /* Check if we had a prior response from this STUN server */
1736 for (se = se_head; NULL != se; se = se->next)
1737 {
1738 if ((se->stun_server_addr_len != sa_len) ||
1739 (0 != memcmp (sa,
1740 &se->stun_server_addr,
1741 sa_len)))
1742 continue; /* different STUN server */
1743 if (0 != GNUNET_memcmp (&external_addr,
1744 &se->external_addr))
1745 {
1746 /* external IP changed, update! */
1748 GNUNET_NO);
1751 GNUNET_YES);
1752 }
1753 /* update timeout */
1755 se->timeout_task
1758 se);
1759 return;
1760 }
1761 /* STUN server is completely new, create fresh entry */
1762 se = GNUNET_new (struct StunExternalIP);
1765 sa,
1766 sa_len);
1767 se->stun_server_addr_len = sa_len;
1770 se);
1772 se_tail,
1773 se);
1775 GNUNET_NO);
1776 }
1778}

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 1791 of file gnunet-service-nat.c.

1795{
1796 size_t expect;
1797
1798 expect = ntohs (message->local_addr_size)
1799 + ntohs (message->remote_addr_size);
1800 if (ntohs (message->header.size) - sizeof(*message) != expect)
1801 {
1802 GNUNET_break (0);
1803 return GNUNET_SYSERR;
1804 }
1805 return GNUNET_OK;
1806}

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 1817 of file gnunet-service-nat.c.

1820{
1821 struct ClientHandle *ch = cls;
1822 const char *buf = (const char *) &message[1];
1823 size_t local_sa_len = ntohs (message->local_addr_size);
1824 size_t remote_sa_len = ntohs (message->remote_addr_size);
1825 struct sockaddr_in l4;
1826 struct sockaddr_in r4;
1827 int ret;
1828
1830 "Received REQUEST CONNECTION REVERSAL message from client\n");
1831 if (local_sa_len != sizeof(struct sockaddr_in))
1832 {
1833 GNUNET_break_op (0);
1835 return;
1836 }
1837 if (remote_sa_len != sizeof(struct sockaddr_in))
1838 {
1839 GNUNET_break_op (0);
1841 return;
1842 }
1843 GNUNET_memcpy (&l4,
1844 buf,
1845 sizeof(struct sockaddr_in));
1846 GNUNET_break_op (AF_INET == l4.sin_family);
1847 buf += sizeof(struct sockaddr_in);
1848 GNUNET_memcpy (&r4,
1849 buf,
1850 sizeof(struct sockaddr_in));
1851 GNUNET_break_op (AF_INET == r4.sin_family);
1852 ret = GN_request_connection_reversal (&l4.sin_addr,
1853 ntohs (l4.sin_port),
1854 &r4.sin_addr,
1855 cfg);
1856 if (GNUNET_OK != ret)
1858 _ ("Connection reversal request failed\n"));
1860}

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 1872 of file gnunet-service-nat.c.

1875{
1876 //const char *buf = (const char *) &message[1];
1877 //uint16_t blen = ntohs (message->address_length);
1878 size_t left = ntohs (message->header.size) - sizeof(*message);
1879
1880 if (left != ntohs (message->address_length))
1881 {
1882 GNUNET_break_op (0);
1883 return GNUNET_SYSERR;
1884 }
1885 /* if ('\0' != buf[blen - 1]) */
1886 /* { */
1887 /* GNUNET_break_op (0); */
1888 /* return GNUNET_SYSERR; */
1889 /* } */
1890 return GNUNET_OK;
1891}

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 1902 of file gnunet-service-nat.c.

1905{
1906 struct ClientHandle *ch = cls;
1907 const char *buf = (const char *) &message[1];
1908 //uint16_t blen = ntohs (message->address_length);
1909 struct sockaddr_in sockaddr_ipv4 = {
1910 .sin_family = AF_INET
1911 };
1912
1913 //GNUNET_assert ('\0' == buf[blen - 1]);
1914 if (1 != inet_pton (AF_INET,
1915 buf,
1916 &sockaddr_ipv4.sin_addr))
1917 {
1919 "natting address %s length %u no ipv4\n",
1920 buf,
1921 message->address_length);
1922 GNUNET_break (0);
1924 return;
1925 }
1926 notify_clients_stun_change (&sockaddr_ipv4,
1927 GNUNET_YES);
1929}

References GNUNET_NAT_AddGlobalAddressMessage::address_length, ch, GNUNET_break, GNUNET_ERROR_TYPE_DEBUG, GNUNET_log, GNUNET_SERVICE_client_continue(), GNUNET_YES, and notify_clients_stun_change().

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 1938 of file gnunet-service-nat.c.

1939{
1940 struct StunExternalIP *se;
1941
1942 while (NULL != (se = se_head))
1943 {
1945 se_tail,
1946 se);
1948 GNUNET_free (se);
1949 }
1951 if (NULL != scan_task)
1952 {
1954 scan_task = NULL;
1955 }
1956 if (NULL != stats)
1957 {
1959 GNUNET_NO);
1960 stats = NULL;
1961 }
1962 destroy_lal ();
1963}

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 1974 of file gnunet-service-nat.c.

1977{
1978 cfg = c;
1979 if (GNUNET_OK !=
1981 "NAT",
1982 "STUN_STALE",
1985
1986 /* Check for UPnP */
1989 "NAT",
1990 "ENABLE_UPNP");
1991 if (GNUNET_YES == enable_upnp)
1992 {
1993 /* check if it works */
1994 if (GNUNET_SYSERR ==
1996 GNUNET_NO,
1997 NULL))
1998 {
2000 _ (
2001 "UPnP enabled in configuration, but UPnP client `upnpc` command not found, disabling UPnP\n"));
2003 }
2004 }
2005 if (GNUNET_OK !=
2007 "nat",
2008 "DYNDNS_FREQUENCY",
2011
2014 "NAT",
2015 "ENABLE_IPSCAN");
2016
2018 NULL);
2020 cfg);
2023 NULL);
2024}

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, 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 2036 of file gnunet-service-nat.c.

2039{
2040 struct ClientHandle *ch;
2041
2042 ch = GNUNET_new (struct ClientHandle);
2043 ch->mq = mq;
2044 ch->client = c;
2046 ch_tail,
2047 ch);
2048 return ch;
2049}

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 2060 of file gnunet-service-nat.c.

2063{
2064 struct ClientHandle *ch = internal_cls;
2065 struct LocalAddressList *lal;
2066
2068 ch_tail,
2069 ch);
2070 for (unsigned int i = 0; i < ch->num_caddrs; i++)
2071 {
2072 if (NULL != ch->caddrs[i].mh)
2073 {
2074 GNUNET_NAT_mini_map_stop (ch->caddrs[i].mh);
2075 ch->caddrs[i].mh = NULL;
2076 }
2077 }
2078 GNUNET_free (ch->caddrs);
2079 while (NULL != (lal = ch->ext_addr_head))
2080 {
2081 GNUNET_CONTAINER_DLL_remove (ch->ext_addr_head,
2082 ch->ext_addr_tail,
2083 lal);
2084 GNUNET_free (lal);
2085 }
2086 if (NULL != ch->ext_dns_task)
2087 {
2088 GNUNET_SCHEDULER_cancel (ch->ext_dns_task);
2089 ch->ext_dns_task = NULL;
2090 }
2091 if (NULL != ch->external_monitor)
2092 {
2093 GN_external_ipv4_monitor_stop (ch->external_monitor);
2094 ch->external_monitor = NULL;
2095 }
2096 if (NULL != ch->ext_dns)
2097 {
2099 ch->ext_dns = NULL;
2100 }
2101 GNUNET_free (ch->hole_external);
2102 GNUNET_free (ch->section_name);
2103 GNUNET_free (ch);
2104}

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().