GNUnet 0.21.1
gnunet-service-nat.c File Reference

network address translation traversal service More...

#include "platform.h"
#include <math.h>
#include "gnunet_util_lib.h"
#include "gnunet_protocols.h"
#include "gnunet_signatures.h"
#include "gnunet_statistics_service.h"
#include "gnunet_resolver_service.h"
#include "gnunet_nat_service.h"
#include "gnunet-service-nat.h"
#include "gnunet-service-nat_externalip.h"
#include "gnunet-service-nat_stun.h"
#include "gnunet-service-nat_mini.h"
#include "gnunet-service-nat_helper.h"
#include "nat.h"
#include <gcrypt.h>
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? More...
 
#define AUTOCONFIG_TIMEOUT
 How long do we wait until we forcefully terminate autoconfiguration? More...
 
#define DYNDNS_FREQUENCY
 How often do we scan for changes in how our external (dyndns) hostname resolves? More...
 

Functions

static void free_lal (struct LocalAddressList *lal)
 Remove and free an entry from the lal_head DLL. More...
 
static void destroy_lal ()
 Free the DLL starting at lal_head. More...
 
static int check_register (void *cls, const struct GNUNET_NAT_RegisterMessage *message)
 Check validity of GNUNET_MESSAGE_TYPE_NAT_REGISTER message from client. More...
 
static int match_ipv4 (const char *network, const struct in_addr *ip, uint8_t bits)
 Check if ip is in network with bits netmask. More...
 
static int match_ipv6 (const char *network, const struct in6_addr *ip, uint8_t bits)
 Check if ip is in network with bits netmask. More...
 
static int is_nat_v4 (const struct in_addr *ip)
 Test if the given IPv4 address is in a known range for private networks. More...
 
static int is_nat_v6 (const struct in6_addr *ip)
 Test if the given IPv6 address is in a known range for private networks. More...
 
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. More...
 
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. More...
 
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. More...
 
static void notify_clients (struct LocalAddressList *delta, int add)
 Notify all clients about a change in the list of addresses this peer has. More...
 
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. More...
 
static void reversal_callback (void *cls, const struct sockaddr_in *ra)
 We got a connection reversal request from another peer. More...
 
static void run_scan (void *cls)
 Task we run periodically to scan for network interfaces. More...
 
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. More...
 
static void dyndns_lookup (void *cls)
 Resolve the hole_external name to figure out our external address from a manually punched hole. More...
 
static void process_external_ip (void *cls, const struct sockaddr *addr, socklen_t addrlen)
 Our (external) hostname was resolved. More...
 
static void lookup_hole_external (struct ClientHandle *ch)
 Resolve the hole_external name to figure out our external address from a manually punched hole. More...
 
static void handle_register (void *cls, const struct GNUNET_NAT_RegisterMessage *message)
 Handler for GNUNET_MESSAGE_TYPE_NAT_REGISTER message from client. More...
 
static int check_stun (void *cls, const struct GNUNET_NAT_HandleStunMessage *message)
 Check validity of GNUNET_MESSAGE_TYPE_NAT_HANDLE_STUN message from client. More...
 
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. More...
 
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. More...
 
static void handle_stun (void *cls, const struct GNUNET_NAT_HandleStunMessage *message)
 Handler for GNUNET_MESSAGE_TYPE_NAT_HANDLE_STUN message from client. More...
 
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. More...
 
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. More...
 
static int 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. More...
 
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. More...
 
static void shutdown_task (void *cls)
 Task run during shutdown. More...
 
static void run (void *cls, const struct GNUNET_CONFIGURATION_Handle *c, struct GNUNET_SERVICE_Handle *service)
 Setup NAT service. More...
 
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. More...
 
static void client_disconnect_cb (void *cls, struct GNUNET_SERVICE_Client *c, void *internal_cls)
 Callback called when a client disconnected from the service. More...
 
 GNUNET_SERVICE_MAIN ("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. More...
 

Variables

static struct GNUNET_TIME_Relative stun_stale_timeout
 Timeout to use when STUN data is considered stale. More...
 
static struct GNUNET_TIME_Relative dyndns_frequency
 How often do we scan for changes in how our external (dyndns) hostname resolves? More...
 
static const struct GNUNET_CONFIGURATION_Handlecfg
 Handle to our current configuration. More...
 
static struct GNUNET_STATISTICS_Handlestats
 Handle to the statistics service. More...
 
static struct GNUNET_SCHEDULER_Taskscan_task
 Task scheduled to periodically scan our network interfaces. More...
 
static struct ClientHandlech_head
 Head of client DLL. More...
 
static struct ClientHandlech_tail
 Tail of client DLL. More...
 
static struct LocalAddressListlal_head
 Head of DLL of local addresses. More...
 
static struct LocalAddressListlal_tail
 Tail of DLL of local addresses. More...
 
static struct StunExternalIPse_head
 Kept in a DLL. More...
 
static struct StunExternalIPse_tail
 Kept in a DLL. More...
 
int enable_upnp
 Is UPnP enabled? GNUNET_YES if enabled, GNUNET_NO if disabled, GNUNET_SYSERR if configuration enabled but binary is unavailable. More...
 
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) More...
 

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 58 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:484

How long do we wait until we forcefully terminate autoconfiguration?

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

◆ DYNDNS_FREQUENCY

#define DYNDNS_FREQUENCY
Value:
#define GNUNET_TIME_UNIT_MINUTES
One minute.

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

Definition at line 69 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 350 of file gnunet-service-nat.c.

351{
353 lal_tail,
354 lal);
355 if (NULL != lal->hc)
356 {
358 "Lost NATed local address %s, stopping NAT server\n",
359 GNUNET_a2s ((const struct sockaddr *) &lal->addr,
360 sizeof(struct sockaddr_in)));
361
363 lal->hc = NULL;
364 }
365 GNUNET_free (lal);
366}
static struct LocalAddressList * lal_head
Head of DLL of local addresses.
static struct LocalAddressList * lal_tail
Tail of DLL of local addresses.
void GN_stop_gnunet_nat_server_(struct HelperContext *h)
Start the gnunet-helper-nat-server and process incoming requests.
#define GNUNET_CONTAINER_DLL_remove(head, tail, element)
Remove an element from a DLL.
#define GNUNET_log(kind,...)
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_MESSAGE
#define GNUNET_free(ptr)
Wrapper around free.
struct HelperContext * hc
Context for a gnunet-helper-nat-server used to listen for ICMP messages to this client for connection...
struct sockaddr_storage addr
The address itself (i.e.

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

374{
375 struct LocalAddressList *lal;
376
377 while (NULL != (lal = lal_head))
378 free_lal (lal);
379}
static void free_lal(struct LocalAddressList *lal)
Remove and free an entry from the lal_head DLL.
List of local addresses this system has.

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

393{
394 uint16_t num_addrs = ntohs (message->num_addrs);
395 const char *off = (const char *) &message[1];
396 size_t left = ntohs (message->header.size) - sizeof(*message);
397
398 for (unsigned int i = 0; i < num_addrs; i++)
399 {
400 size_t alen;
401 const struct sockaddr *sa = (const struct sockaddr *) off;
402
403 if (sizeof(sa_family_t) > left)
404 {
405 GNUNET_break (0);
406 return GNUNET_SYSERR;
407 }
408 switch (sa->sa_family)
409 {
410 case AF_INET:
411 alen = sizeof(struct sockaddr_in);
412 break;
413
414 case AF_INET6:
415 alen = sizeof(struct sockaddr_in6);
416 break;
417
418#if AF_UNIX
419 case AF_UNIX:
420 alen = sizeof(struct sockaddr_un);
421 break;
422#endif
423 default:
424 GNUNET_break (0);
425 return GNUNET_SYSERR;
426 }
427 if (alen > left)
428 {
429 GNUNET_break (0);
430 return GNUNET_SYSERR;
431 }
432 off += alen;
433 left -= alen;
434 }
435 if (left != ntohs (message->str_len))
436 {
437 GNUNET_break (0);
438 return GNUNET_SYSERR;
439 }
440 return GNUNET_OK;
441}
@ GNUNET_OK
@ GNUNET_SYSERR
#define GNUNET_break(cond)
Use this for internal assertion violations that are not fatal (can be handled) but should not occur.
uint16_t size
The length of the struct (in bytes, including the length field itself), in big-endian format.
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

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

456{
457 struct in_addr net;
458
459 if (0 == ip->s_addr)
460 return GNUNET_YES;
461 if (0 == bits)
462 return GNUNET_YES;
463 GNUNET_assert (1 == inet_pton (AF_INET,
464 network,
465 &net));
466 return ! ((ip->s_addr ^ net.s_addr) & htonl (0xFFFFFFFFu << (32 - bits)));
467}
@ GNUNET_YES
#define GNUNET_assert(cond)
Use this for fatal errors that cannot be handled.

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

482{
483 struct in6_addr net;
484 struct in6_addr mask;
485 unsigned int off;
486
487 if (0 == bits)
488 return GNUNET_YES;
489 GNUNET_assert (1 == inet_pton (AF_INET6,
490 network,
491 &net));
492 memset (&mask, 0, sizeof(mask));
493 if (0 == GNUNET_memcmp (&mask,
494 ip))
495 return GNUNET_YES;
496 off = 0;
497 while (bits > 8)
498 {
499 mask.s6_addr[off++] = 0xFF;
500 bits -= 8;
501 }
502 while (bits > 0)
503 {
504 mask.s6_addr[off] = (mask.s6_addr[off] >> 1) + 0x80;
505 bits--;
506 }
507 for (unsigned j = 0; j < sizeof(struct in6_addr) / sizeof(uint32_t); j++)
508 if (((((uint32_t *) ip)[j] & ((uint32_t *) &mask)[j])) !=
509 (((uint32_t *) &net)[j] & ((int *) &mask)[j]))
510 return GNUNET_NO;
511 return GNUNET_YES;
512}
#define GNUNET_memcmp(a, b)
Compare memory in a and b, where both must be of the same pointer type.
@ GNUNET_NO

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

524{
525 return
526 match_ipv4 ("10.0.0.0", ip, 8) || /* RFC 1918 */
527 match_ipv4 ("100.64.0.0", ip, 10) || /* CG-NAT, RFC 6598 */
528 match_ipv4 ("192.168.0.0", ip, 12) || /* RFC 1918 */
529 match_ipv4 ("169.254.0.0", ip, 16) || /* AUTO, RFC 3927 */
530 match_ipv4 ("172.16.0.0", ip, 16); /* RFC 1918 */
531}
static int match_ipv4(const char *network, const struct in_addr *ip, uint8_t bits)
Check if ip is in network with bits netmask.

References match_ipv4().

Referenced by check_notify_client(), handle_add_global_address(), 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 542 of file gnunet-service-nat.c.

543{
544 return
545 match_ipv6 ("fc00::", ip, 7) || /* RFC 4193 */
546 match_ipv6 ("fec0::", ip, 10) || /* RFC 3879 */
547 match_ipv6 ("fe80::", ip, 10); /* RFC 4291, link-local */
548}
static int match_ipv6(const char *network, const struct in6_addr *ip, uint8_t bits)
Check if ip is in network with bits netmask.

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

589{
590 struct IfcProcContext *ifc_ctx = cls;
591 struct LocalAddressList *lal;
592 size_t alen;
593 const struct in_addr *ip4;
594 const struct in6_addr *ip6;
596
597 switch (addr->sa_family)
598 {
599 case AF_INET:
600 alen = sizeof(struct sockaddr_in);
601 ip4 = &((const struct sockaddr_in *) addr)->sin_addr;
602 if (match_ipv4 ("127.0.0.0", ip4, 8))
604 else if (is_nat_v4 (ip4))
606 else
608 break;
609
610 case AF_INET6:
611 alen = sizeof(struct sockaddr_in6);
612 ip6 = &((const struct sockaddr_in6 *) addr)->sin6_addr;
613 if (match_ipv6 ("::1", ip6, 128))
615 else if (is_nat_v6 (ip6))
617 else
619 if ((ip6->s6_addr[11] == 0xFF) &&
620 (ip6->s6_addr[12] == 0xFE))
621 {
622 /* contains a MAC, be extra careful! */
624 }
625 break;
626
627#if AF_UNIX
628 case AF_UNIX:
629 GNUNET_break (0);
630 return GNUNET_OK;
631#endif
632 default:
633 GNUNET_break (0);
634 return GNUNET_OK;
635 }
636 lal = GNUNET_malloc (sizeof(*lal));
637 lal->af = addr->sa_family;
638 lal->ac = ac;
639 GNUNET_memcpy (&lal->addr,
640 addr,
641 alen);
643 ifc_ctx->lal_tail,
644 lal);
645 return GNUNET_OK;
646}
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 is_nat_v4(const struct in_addr *ip)
Test if the given IPv4 address is in a known range for private networks.
#define GNUNET_CONTAINER_DLL_insert(head, tail, element)
Insert an element at the head of a DLL.
#define GNUNET_memcpy(dst, src, n)
Call memcpy() but check for n being 0 first.
#define GNUNET_malloc(size)
Wrapper around malloc.
GNUNET_NAT_AddressClass
Some addresses contain sensitive information or are not suitable for global distribution.
@ 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_LOOPBACK
Loopback addresses, only useful under special circumstances.
Closure for ifc_proc.
struct LocalAddressList * lal_head
Head of DLL of local addresses.
struct LocalAddressList * lal_tail
Tail of DLL of local addresses.
int af
Address family.
enum GNUNET_NAT_AddressClass ac
What type of address is this?

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

665{
666 struct GNUNET_MQ_Envelope *env;
668
670 "Notifying client about %s of IP %s\n",
671 add ? "addition" : "removal",
672 GNUNET_a2s (addr,
673 addr_len));
675 addr_len,
677 msg->add_remove = htonl (add);
678 msg->addr_class = htonl (ac);
679 GNUNET_memcpy (&msg[1],
680 addr,
681 addr_len);
683 env);
684}
struct GNUNET_MessageHeader * msg
Definition: 005.c:2
struct GNUNET_MQ_Envelope * env
Definition: 005.c:1
static struct GNUNET_CADET_Channel * ch
Channel handle.
Definition: gnunet-cadet.c:117
static int add
Desired action is to add a record.
@ GNUNET_ERROR_TYPE_DEBUG
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:304
#define GNUNET_MQ_msg_extra(mvar, esize, type)
Allocate an envelope, with extra space allocated after the space needed by the message struct.
Definition: gnunet_mq_lib.h:63
#define GNUNET_MESSAGE_TYPE_NAT_ADDRESS_CHANGE
Message to from NAT service notifying us that one of our addresses changed.
struct GNUNET_MQ_Handle * mq
Message Queue for the channel (which we are implementing).
Definition: cadet.h:142
Service notifying the client about changes in the set of addresses it has.
Definition: nat.h:202

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

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

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

826{
827 for (struct ClientHandle *ch = ch_head;
828 NULL != ch;
829 ch = ch->next)
831 ch,
832 add);
833}
static struct ClientHandle * ch_head
Head of client DLL.
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,...
Struct containing information about a client, handle to connect to it, and any pending messages that ...

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

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

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

926{
927 struct LocalAddressList *lal = cls;
928 const struct sockaddr_in *l4;
929
930 GNUNET_assert (AF_INET == lal->af);
931 l4 = (const struct sockaddr_in *) &lal->addr;
932 for (struct ClientHandle *ch = ch_head;
933 NULL != ch;
934 ch = ch->next)
935 {
937 struct GNUNET_MQ_Envelope *env;
938 int match;
939
940 /* Check if client is in applicable range for ICMP NAT traversal
941 for this local address */
942 if (! ch->natted_address)
943 continue;
944 match = GNUNET_NO;
945 for (unsigned int i = 0; i < ch->num_caddrs; i++)
946 {
947 struct ClientAddress *ca = &ch->caddrs[i];
948 const struct sockaddr_in *c4;
949
950 if (AF_INET != ca->ss.ss_family)
951 continue;
952 c4 = (const struct sockaddr_in *) &ca->ss;
953 if ((0 != c4->sin_addr.s_addr) &&
954 (l4->sin_addr.s_addr != c4->sin_addr.s_addr))
955 continue;
956 match = GNUNET_YES;
957 break;
958 }
959 if (! match)
960 continue;
961
962 /* Notify applicable client about connection reversal request */
963 env = GNUNET_MQ_msg_extra (crrm,
964 sizeof(struct sockaddr_in),
966 GNUNET_memcpy (&crrm[1],
967 ra,
968 sizeof(struct sockaddr_in));
970 env);
971 }
972}
#define GNUNET_MESSAGE_TYPE_NAT_CONNECTION_REVERSAL_REQUESTED
Message to from NAT service notifying us that connection reversal was requested by another peer.
Information we track per client address.
struct sockaddr_storage ss
Network address used by the client.
Service telling a client that connection reversal was requested.
Definition: nat.h:187

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

982{
983 struct IfcProcContext ifc_ctx;
984 int found;
985 int have_nat;
986 struct LocalAddressList *lnext;
987
989 &run_scan,
990 NULL);
991 memset (&ifc_ctx,
992 0,
993 sizeof(ifc_ctx));
995 &ifc_ctx);
996 /* remove addresses that disappeared */
997 for (struct LocalAddressList *lal = lal_head;
998 NULL != lal;
999 lal = lnext)
1000 {
1001 lnext = lal->next;
1002 found = GNUNET_NO;
1003 for (struct LocalAddressList *pos = ifc_ctx.lal_head;
1004 NULL != pos;
1005 pos = pos->next)
1006 {
1007 if ((pos->af == lal->af) &&
1008 (0 == memcmp (&lal->addr,
1009 &pos->addr,
1010 (AF_INET == lal->af)
1011 ? sizeof(struct sockaddr_in)
1012 : sizeof(struct sockaddr_in6))))
1013 {
1014 found = GNUNET_YES;
1015 }
1016 }
1017 if (GNUNET_NO == found)
1018 {
1019 notify_clients (lal,
1020 GNUNET_NO);
1021 free_lal (lal);
1022 }
1023 }
1024
1025 /* add addresses that appeared */
1026 have_nat = GNUNET_NO;
1027 for (struct LocalAddressList *pos = ifc_ctx.lal_head;
1028 NULL != pos;
1029 pos = ifc_ctx.lal_head)
1030 {
1031 found = GNUNET_NO;
1032 if (GNUNET_NAT_AC_LAN == (GNUNET_NAT_AC_LAN & pos->ac))
1033 have_nat = GNUNET_YES;
1034 for (struct LocalAddressList *lal = lal_head;
1035 NULL != lal;
1036 lal = lal->next)
1037 {
1038 if ((pos->af == lal->af) &&
1039 (0 == memcmp (&lal->addr,
1040 &pos->addr,
1041 (AF_INET == lal->af)
1042 ? sizeof(struct sockaddr_in)
1043 : sizeof(struct sockaddr_in6))))
1044 found = GNUNET_YES;
1045 }
1046 GNUNET_CONTAINER_DLL_remove (ifc_ctx.lal_head,
1047 ifc_ctx.lal_tail,
1048 pos);
1049 if (GNUNET_YES == found)
1050 {
1051 GNUNET_free (pos);
1052 }
1053 else
1054 {
1055 notify_clients (pos,
1056 GNUNET_YES);
1058 lal_tail,
1059 pos);
1060 if ((AF_INET == pos->af) &&
1061 (NULL == pos->hc) &&
1062 (0 != (GNUNET_NAT_AC_LAN & pos->ac)))
1063 {
1064 const struct sockaddr_in *s4
1065 = (const struct sockaddr_in *) &pos->addr;
1066
1068 "Found NATed local address %s, starting NAT server\n",
1069 GNUNET_a2s ((const struct sockaddr *) &pos->addr,
1070 sizeof(*s4)));
1071 pos->hc = GN_start_gnunet_nat_server_ (&s4->sin_addr,
1073 pos,
1074 cfg);
1075 }
1076 }
1077 }
1078 GN_nat_status_changed (have_nat);
1079}
static const struct GNUNET_CONFIGURATION_Handle * cfg
Handle to our current configuration.
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 run_scan(void *cls)
Task we run periodically to scan for network interfaces.
static struct GNUNET_SCHEDULER_Task * scan_task
Task scheduled to periodically scan our network interfaces.
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 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.
void GN_nat_status_changed(int have_nat)
We have changed our opinion about being NATed in the first place.
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 GNUNET_OS_network_interfaces_list(GNUNET_OS_NetworkInterfaceProcessor proc, void *proc_cls)
Enumerate all network interfaces.
Definition: os_network.c:397
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:1278
struct LocalAddressList * next
This is a linked list.

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

1099{
1100 struct ClientHandle *ch = cls;
1102
1103 switch (result)
1104 {
1106 GNUNET_assert (NULL != addr);
1107 break;
1108
1113 "Running upnpc failed: %d\n",
1114 result);
1115 return;
1116
1119 "external-ip binary not found\n");
1120 return;
1121
1124 "upnpc binary not found\n");
1125 return;
1126
1129 "external-ip binary could not be run\n");
1130 return;
1131
1134 "upnpc failed to create port mapping\n");
1135 return;
1136
1139 "Invalid output from upnpc\n");
1140 return;
1141
1144 "Invalid address returned by upnpc\n");
1145 return;
1146
1147 default:
1148 GNUNET_break (0); /* should not be possible */
1149 return;
1150 }
1151 switch (addr->sa_family)
1152 {
1153 case AF_INET:
1154 ac = is_nat_v4 (&((const struct sockaddr_in *) addr)->sin_addr)
1157 break;
1158
1159 case AF_INET6:
1160 ac = is_nat_v6 (&((const struct sockaddr_in6 *) addr)->sin6_addr)
1163 break;
1164
1165 default:
1166 GNUNET_break (0);
1167 return;
1168 }
1170 "upnp external address %s: %s\n",
1171 add_remove ? "added" : "removed",
1172 GNUNET_a2s (addr,
1173 addrlen));
1174 notify_client (ac,
1175 ch,
1176 add_remove,
1177 addr,
1178 addrlen);
1179}
static int result
Global testing status.
@ GNUNET_ERROR_TYPE_WARNING
@ GNUNET_ERROR_TYPE_INFO
@ 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'"

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

1308{
1309 struct ClientHandle *ch = cls;
1310 struct LocalAddressList *lal;
1311
1313 "Performing DNS lookup for punched hole given for `%s' as `%s:%u'\n",
1314 ch->section_name,
1315 ch->hole_external,
1316 (unsigned int) ch->ext_dns_port);
1317 for (lal = ch->ext_addr_head; NULL != lal; lal = lal->next)
1318 lal->old = GNUNET_YES;
1319 ch->ext_dns_task = NULL;
1320 ch->ext_dns = GNUNET_RESOLVER_ip_get (ch->hole_external,
1321 AF_UNSPEC,
1324 ch);
1325}
static void process_external_ip(void *cls, const struct sockaddr *addr, socklen_t addrlen)
Our (external) hostname was resolved.
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.
Definition: resolver_api.c:940
int old
GNUNET_YES if we saw this one in the previous iteration, but not in the current iteration and thus mi...

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

1207{
1208 struct ClientHandle *ch = cls;
1209 struct LocalAddressList *lal;
1210 struct sockaddr_storage ss;
1211 struct sockaddr_in *v4;
1212 struct sockaddr_in6 *v6;
1213
1214 if (NULL == addr)
1215 {
1216 struct LocalAddressList *laln;
1217
1218 ch->ext_dns = NULL;
1219 ch->ext_dns_task
1222 ch);
1223 /* Current iteration is over, remove 'old' IPs now */
1224 for (lal = ch->ext_addr_head; NULL != lal; lal = laln)
1225 {
1226 laln = lal->next;
1227 if (GNUNET_YES == lal->old)
1228 {
1229 GNUNET_CONTAINER_DLL_remove (ch->ext_addr_head,
1230 ch->ext_addr_tail,
1231 lal);
1233 ch,
1234 GNUNET_NO);
1235 GNUNET_free (lal);
1236 }
1237 }
1238 return;
1239 }
1241 "Got IP `%s' for external address `%s'\n",
1243 addrlen),
1244 ch->hole_external);
1245
1246 /* build sockaddr storage with port number */
1247 memset (&ss,
1248 0,
1249 sizeof(ss));
1250 GNUNET_memcpy (&ss,
1251 addr,
1252 addrlen);
1253 switch (addr->sa_family)
1254 {
1255 case AF_INET:
1256 v4 = (struct sockaddr_in *) &ss;
1257 v4->sin_port = htons (ch->ext_dns_port);
1258 break;
1259
1260 case AF_INET6:
1261 v6 = (struct sockaddr_in6 *) &ss;
1262 v6->sin6_port = htons (ch->ext_dns_port);
1263 break;
1264
1265 default:
1266 GNUNET_break (0);
1267 return;
1268 }
1269 /* See if 'ss' matches any of our known addresses */
1270 for (lal = ch->ext_addr_head; NULL != lal; lal = lal->next)
1271 {
1272 if (GNUNET_NO == lal->old)
1273 continue; /* already processed, skip */
1274 if ((addr->sa_family == lal->addr.ss_family) &&
1275 (0 == memcmp (&ss,
1276 &lal->addr,
1277 addrlen)))
1278 {
1279 /* Address unchanged, remember so we do not remove */
1280 lal->old = GNUNET_NO;
1281 return; /* done here */
1282 }
1283 }
1284 /* notify client, and remember IP for later removal! */
1285 lal = GNUNET_new (struct LocalAddressList);
1286 lal->addr = ss;
1287 lal->af = ss.ss_family;
1289 GNUNET_CONTAINER_DLL_insert (ch->ext_addr_head,
1290 ch->ext_addr_tail,
1291 lal);
1293 ch,
1294 GNUNET_YES);
1295}
static struct GNUNET_TIME_Relative dyndns_frequency
How often do we scan for changes in how our external (dyndns) hostname resolves?
static void dyndns_lookup(void *cls)
Resolve the hole_external name to figure out our external address from a manually punched hole.
#define GNUNET_new(type)
Allocate a struct or union of the given type.

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

1341{
1342 char *port;
1343 unsigned int pnum;
1344 struct sockaddr_in *s4;
1345 struct LocalAddressList *lal;
1346
1347 port = strrchr (ch->hole_external, ':');
1348 if (NULL == port)
1349 {
1351 _ ("Malformed punched hole specification `%s' (lacks port)\n"),
1352 ch->hole_external);
1353 return;
1354 }
1355 if ((1 != sscanf (port + 1,
1356 "%u",
1357 &pnum)) ||
1358 (pnum > 65535))
1359 {
1361 _ (
1362 "Invalid port number in punched hole specification `%s' (lacks port)\n"),
1363 port + 1);
1364 return;
1365 }
1366 ch->ext_dns_port = (uint16_t) pnum;
1367 *port = '\0';
1368
1369 lal = GNUNET_new (struct LocalAddressList);
1370 if ('[' == *ch->hole_external)
1371 {
1372 struct sockaddr_in6 *s6 = (struct sockaddr_in6 *) &lal->addr;
1373
1374 s6->sin6_family = AF_INET6;
1375 if (']' != (ch->hole_external[strlen (ch->hole_external) - 1]))
1376 {
1378 _ ("Malformed punched hole specification `%s' (lacks `]')\n"),
1379 ch->hole_external);
1380 GNUNET_free (lal);
1381 return;
1382 }
1383 ch->hole_external[strlen (ch->hole_external) - 1] = '\0';
1384 if (1 != inet_pton (AF_INET6,
1385 ch->hole_external + 1,
1386 &s6->sin6_addr))
1387 {
1389 _ (
1390 "Malformed punched hole specification `%s' (IPv6 address invalid)"),
1391 ch->hole_external + 1);
1392 GNUNET_free (lal);
1393 return;
1394 }
1395 s6->sin6_port = htons (ch->ext_dns_port);
1396 lal->af = AF_INET6;
1398 GNUNET_CONTAINER_DLL_insert (ch->ext_addr_head,
1399 ch->ext_addr_tail,
1400 lal);
1402 ch,
1403 GNUNET_YES);
1404 return;
1405 }
1406
1407 s4 = (struct sockaddr_in *) &lal->addr;
1408 s4->sin_family = AF_INET;
1409 if (1 == inet_pton (AF_INET,
1410 ch->hole_external,
1411 &s4->sin_addr))
1412 {
1414 "IPv4 punched hole given for `%s' via `%s:%u'\n",
1415 ch->section_name,
1416 ch->hole_external,
1417 (unsigned int) ch->ext_dns_port);
1418 s4->sin_port = htons (ch->ext_dns_port);
1419 lal->af = AF_INET;
1421 GNUNET_CONTAINER_DLL_insert (ch->ext_addr_head,
1422 ch->ext_addr_tail,
1423 lal);
1425 ch,
1426 GNUNET_YES);
1427 return;
1428 }
1429 if (0 == strcasecmp (ch->hole_external,
1430 "AUTO"))
1431 {
1432 /* handled in #notify_client_external_ipv4_change() */
1433 GNUNET_free (lal);
1434 return;
1435 }
1436 /* got a DNS name, trigger lookup! */
1437 GNUNET_free (lal);
1438 ch->ext_dns_task
1440 ch);
1441}
static uint16_t port
Port number.
Definition: gnunet-bcd.c:147
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:1305
#define _(String)
GNU gettext support macro.
Definition: platform.h:178

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

1454{
1455 struct ClientHandle *ch = cls;
1456 const char *off;
1457 size_t left;
1458
1459 if ((0 != ch->proto) ||
1460 (NULL != ch->caddrs))
1461 {
1462 /* double registration not allowed */
1463 GNUNET_break (0);
1465 return;
1466 }
1467 ch->flags = message->flags;
1468 ch->proto = message->proto;
1469 ch->num_caddrs = ntohs (message->num_addrs);
1470 ch->caddrs = GNUNET_new_array (ch->num_caddrs,
1471 struct ClientAddress);
1472 left = ntohs (message->header.size) - sizeof(*message);
1473 off = (const char *) &message[1];
1474 for (unsigned int i = 0; i < ch->num_caddrs; i++)
1475 {
1476 const struct sockaddr *sa = (const struct sockaddr *) off;
1477 size_t alen;
1478 uint16_t port;
1479 int is_nat;
1480
1481 if (sizeof(sa_family_t) > left)
1482 {
1483 GNUNET_break (0);
1485 return;
1486 }
1487 is_nat = GNUNET_NO;
1488 switch (sa->sa_family)
1489 {
1490 case AF_INET:
1491 {
1492 struct sockaddr_in s4;
1493
1494 GNUNET_memcpy (&s4,
1495 off,
1496 sizeof(struct sockaddr_in));
1497 alen = sizeof(struct sockaddr_in);
1498 if (is_nat_v4 (&s4.sin_addr))
1499 is_nat = GNUNET_YES;
1500 port = ntohs (s4.sin_port);
1501 }
1502 break;
1503
1504 case AF_INET6:
1505 {
1506 struct sockaddr_in6 s6;
1507
1508 GNUNET_memcpy (&s6,
1509 off,
1510 sizeof(struct sockaddr_in6));
1511 alen = sizeof(struct sockaddr_in6);
1512 if (is_nat_v6 (&s6.sin6_addr))
1513 is_nat = GNUNET_YES;
1514 port = ntohs (s6.sin6_port);
1515 }
1516 break;
1517
1518#if AF_UNIX
1519 case AF_UNIX:
1520 alen = sizeof(struct sockaddr_un);
1521 port = 0;
1522 break;
1523#endif
1524 default:
1525 GNUNET_break (0);
1527 return;
1528 }
1529 /* store address */
1530 GNUNET_assert (alen <= left);
1531 GNUNET_assert (alen <= sizeof(struct sockaddr_storage));
1532 GNUNET_memcpy (&ch->caddrs[i].ss,
1533 off,
1534 alen);
1535
1536 /* If applicable, try UPNPC NAT punching */
1537 if ((is_nat) &&
1538 (enable_upnp) &&
1539 ((IPPROTO_TCP == ch->proto) ||
1540 (IPPROTO_UDP == ch->proto)))
1541 {
1542 ch->natted_address = GNUNET_YES;
1543 ch->caddrs[i].mh
1545 IPPROTO_TCP == ch->proto,
1547 ch);
1548 }
1549
1550 off += alen;
1551 }
1552
1553 ch->section_name
1554 = GNUNET_strndup (off,
1555 ntohs (message->str_len));
1557 "Received REGISTER message from client for subsystem `%s'\n",
1558 ch->section_name);
1559 if (GNUNET_OK ==
1561 ch->section_name,
1562 "HOLE_EXTERNAL",
1563 &ch->hole_external))
1565
1566 /* Actually send IP address list to client */
1567 for (struct LocalAddressList *lal = lal_head;
1568 NULL != lal;
1569 lal = lal->next)
1570 {
1572 ch,
1573 GNUNET_YES);
1574 }
1575 /* Also consider IPv4 determined by `external-ip` */
1576 ch->external_monitor
1578 ch);
1580}
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 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 lookup_hole_external(struct ClientHandle *ch)
Resolve the hole_external name to figure out our external address from a manually punched hole.
int enable_upnp
Is UPnP enabled? GNUNET_YES if enabled, GNUNET_NO if disabled, GNUNET_SYSERR if configuration enabled...
struct GN_ExternalIPMonitor * GN_external_ipv4_monitor_start(GN_NotifyExternalIPv4Change cb, void *cb_cls)
Start monitoring external IPv4 addresses.
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.
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_strndup(a, length)
Wrapper around GNUNET_xstrndup_.
#define GNUNET_new_array(n, type)
Allocate a size n array with structs or unions of the given type.
void GNUNET_SERVICE_client_drop(struct GNUNET_SERVICE_Client *c)
Ask the server to disconnect from the given client.
Definition: service.c:2489
void GNUNET_SERVICE_client_continue(struct GNUNET_SERVICE_Client *c)
Continue receiving further messages from the given client.
Definition: service.c:2408
uint8_t flags
An enum GNUNET_NAT_RegisterFlags.
Definition: nat.h:104
uint8_t proto
Client's IPPROTO, e.g.
Definition: nat.h:109

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

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

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

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

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

1659{
1660 struct StunExternalIP *se = cls;
1661
1662 se->timeout_task = NULL;
1664 GNUNET_NO);
1666 se_tail,
1667 se);
1668 GNUNET_free (se);
1669}
static struct StunExternalIP * se_head
Kept in a DLL.
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 StunExternalIP * se_tail
Kept in a DLL.
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.
struct sockaddr_in external_addr
Our external IP address as reported by the STUN server.

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

1682{
1683 struct ClientHandle *ch = cls;
1684 const char *buf = (const char *) &message[1];
1685 const struct sockaddr *sa;
1686 const void *payload;
1687 size_t sa_len;
1688 size_t payload_size;
1689 struct sockaddr_in external_addr;
1690
1691 sa_len = ntohs (message->sender_addr_size);
1692 payload_size = ntohs (message->payload_size);
1693 sa = (const struct sockaddr *) &buf[0];
1694 payload = (const struct sockaddr *) &buf[sa_len];
1695 switch (sa->sa_family)
1696 {
1697 case AF_INET:
1698 if (sa_len != sizeof(struct sockaddr_in))
1699 {
1700 GNUNET_break (0);
1702 return;
1703 }
1704 break;
1705
1706 case AF_INET6:
1707 if (sa_len != sizeof(struct sockaddr_in6))
1708 {
1709 GNUNET_break (0);
1711 return;
1712 }
1713 break;
1714 }
1716 "Received HANDLE_STUN message from client\n");
1717 if (GNUNET_OK ==
1719 payload_size,
1720 &external_addr))
1721 {
1722 /* We now know that a server at "sa" claims that
1723 we are visible at IP "external_addr".
1724
1725 We should (for some fixed period of time) tell
1726 all of our clients that listen to a NAT'ed address
1727 that they might want to consider the given 'external_ip'
1728 as their public IP address (this includes TCP and UDP
1729 clients, even if only UDP sends STUN requests).
1730
1731 If we do not get a renewal, the "external_addr" should be
1732 removed again. The timeout frequency should be configurable
1733 (with a sane default), so that the UDP plugin can tell how
1734 often to re-request STUN.
1735 */struct StunExternalIP *se;
1736
1737 /* Check if we had a prior response from this STUN server */
1738 for (se = se_head; NULL != se; se = se->next)
1739 {
1740 if ((se->stun_server_addr_len != sa_len) ||
1741 (0 != memcmp (sa,
1742 &se->stun_server_addr,
1743 sa_len)))
1744 continue; /* different STUN server */
1745 if (0 != GNUNET_memcmp (&external_addr,
1746 &se->external_addr))
1747 {
1748 /* external IP changed, update! */
1750 GNUNET_NO);
1753 GNUNET_YES);
1754 }
1755 /* update timeout */
1757 se->timeout_task
1760 se);
1761 return;
1762 }
1763 /* STUN server is completely new, create fresh entry */
1764 se = GNUNET_new (struct StunExternalIP);
1767 sa,
1768 sa_len);
1769 se->stun_server_addr_len = sa_len;
1772 se);
1774 se_tail,
1775 se);
1777 GNUNET_NO);
1778 }
1780}
static unsigned long long payload
How much data are we currently storing in the database?
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 struct GNUNET_TIME_Relative stun_stale_timeout
Timeout to use when STUN data is considered stale.
int GNUNET_NAT_stun_handle_packet_(const void *data, size_t len, struct sockaddr_in *arg)
Handle an incoming STUN response.
void * GNUNET_SCHEDULER_cancel(struct GNUNET_SCHEDULER_Task *task)
Cancel the task with the specified identifier.
Definition: scheduler.c:981
size_t stun_server_addr_len
Number of bytes used in stun_server_addr.
struct sockaddr_storage stun_server_addr
Address of the reporting STUN server.
struct StunExternalIP * next
Kept in a DLL.

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

1797{
1798 size_t expect;
1799
1800 expect = ntohs (message->local_addr_size)
1801 + ntohs (message->remote_addr_size);
1802 if (ntohs (message->header.size) - sizeof(*message) != expect)
1803 {
1804 GNUNET_break (0);
1805 return GNUNET_SYSERR;
1806 }
1807 return GNUNET_OK;
1808}
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

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

1823{
1824 struct ClientHandle *ch = cls;
1825 const char *buf = (const char *) &message[1];
1826 size_t local_sa_len = ntohs (message->local_addr_size);
1827 size_t remote_sa_len = ntohs (message->remote_addr_size);
1828 struct sockaddr_in l4;
1829 struct sockaddr_in r4;
1830 int ret;
1831
1833 "Received REQUEST CONNECTION REVERSAL message from client\n");
1834 if (local_sa_len != sizeof(struct sockaddr_in))
1835 {
1836 GNUNET_break_op (0);
1838 return;
1839 }
1840 if (remote_sa_len != sizeof(struct sockaddr_in))
1841 {
1842 GNUNET_break_op (0);
1844 return;
1845 }
1846 GNUNET_memcpy (&l4,
1847 buf,
1848 sizeof(struct sockaddr_in));
1849 GNUNET_break_op (AF_INET == l4.sin_family);
1850 buf += sizeof(struct sockaddr_in);
1851 GNUNET_memcpy (&r4,
1852 buf,
1853 sizeof(struct sockaddr_in));
1854 GNUNET_break_op (AF_INET == r4.sin_family);
1855 ret = GN_request_connection_reversal (&l4.sin_addr,
1856 ntohs (l4.sin_port),
1857 &r4.sin_addr,
1858 cfg);
1859 if (GNUNET_OK != ret)
1861 _ ("Connection reversal request failed\n"));
1863}
static int ret
Final status code.
Definition: gnunet-arm.c:94
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.
#define GNUNET_break_op(cond)
Use this for assertion violations caused by other peers (i.e.

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

1877{
1878 char *addr = GNUNET_malloc (ntohs (message->address_length));
1879 size_t left = ntohs (message->header.size) - sizeof(*message);
1880
1881 GNUNET_memcpy (addr, (const char *) &message[1], ntohs (message->address_length));
1883 "message size %u natting address %s length %u left %u\n",
1884 ntohs (message->header.size),
1885 addr,
1886 ntohs (message->address_length),
1887 left);
1888
1889 if (left != ntohs (message->address_length))
1890 {
1891 GNUNET_break (0);
1892 return GNUNET_SYSERR;
1893 }
1894 GNUNET_free (addr);
1895 return GNUNET_OK;
1896}
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

References GNUNET_NAT_AddGlobalAddressMessage::address_length, GNUNET_break, GNUNET_ERROR_TYPE_DEBUG, GNUNET_free, GNUNET_log, GNUNET_malloc, GNUNET_memcpy, 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 1923 of file gnunet-service-nat.c.

1925{
1926 struct ClientHandle *ch = cls;
1927 char *buf = GNUNET_malloc (ntohs (message->address_length));
1928 //= (const char *) &message[1];
1929 struct sockaddr *sockaddr = NULL;
1930 socklen_t addr_len;
1931 struct sockaddr_in *sockaddr_ipv4 = GNUNET_malloc(sizeof(struct sockaddr_in));
1933
1934 GNUNET_memcpy (buf, (const char *) &message[1], ntohs (message->address_length));
1935 memset(sockaddr_ipv4, 0, sizeof(struct sockaddr_in));
1936 sockaddr_ipv4->sin_family = AF_INET;
1937
1938 if (1 == inet_pton(AF_INET, buf, &(sockaddr_ipv4->sin_addr)))
1939 {
1940 sockaddr = (struct sockaddr *)sockaddr_ipv4;
1941 addr_len = sizeof(struct sockaddr_in);
1942 ac = is_nat_v4 (&((const struct sockaddr_in *)sockaddr_ipv4)->sin_addr)
1945 }
1946 else
1947 {
1948 GNUNET_free(sockaddr_ipv4);
1949 sockaddr_ipv4 = NULL;
1950 }
1951
1952 if (NULL == sockaddr)
1953 {
1954 struct sockaddr_in6 *sockaddr_ipv6 = malloc(sizeof(struct sockaddr_in6));
1955
1956 if (sockaddr_ipv6 != NULL)
1957 {
1958 memset(sockaddr_ipv6, 0, sizeof(struct sockaddr_in6));
1959 sockaddr_ipv6->sin6_family = AF_INET6;
1960
1961 if (1 == inet_pton(AF_INET6, buf, &(sockaddr_ipv6->sin6_addr)))
1962 {
1963 GNUNET_break (0);
1965 GNUNET_free (buf);
1966 return;
1967 }
1968 else
1969 {
1970 GNUNET_free(sockaddr_ipv6);
1971 sockaddr_ipv6 = NULL;
1972 }
1973 }
1974 }
1975
1977 "3 natting address %s\n",
1978 buf);
1979 if (NULL == sockaddr)
1980 {
1981 GNUNET_break (0);
1983 GNUNET_free (buf);
1984 return;
1985 }
1986 notify_clients_stun_change (sockaddr_ipv4, GNUNET_YES);
1988 GNUNET_free (buf);
1989}

References GNUNET_NAT_AddGlobalAddressMessage::address_length, ch, GNUNET_break, GNUNET_ERROR_TYPE_DEBUG, GNUNET_free, GNUNET_log, GNUNET_malloc, GNUNET_memcpy, GNUNET_NAT_AC_EXTERN, GNUNET_NAT_AC_LAN, GNUNET_SERVICE_client_continue(), GNUNET_YES, is_nat_v4(), 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 1998 of file gnunet-service-nat.c.

1999{
2000 struct StunExternalIP *se;
2001
2002 while (NULL != (se = se_head))
2003 {
2005 se_tail,
2006 se);
2008 GNUNET_free (se);
2009 }
2011 if (NULL != scan_task)
2012 {
2014 scan_task = NULL;
2015 }
2016 if (NULL != stats)
2017 {
2019 GNUNET_NO);
2020 stats = NULL;
2021 }
2022 destroy_lal ();
2023}
static struct GNUNET_STATISTICS_Handle * stats
Handle to the statistics service.
static void destroy_lal()
Free the DLL starting at lal_head.
void GNUNET_STATISTICS_destroy(struct GNUNET_STATISTICS_Handle *h, int sync_first)
Destroy a handle (free all state associated with it).

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.

Referenced by run().

Here is the call graph for this function:
Here is the caller 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 2034 of file gnunet-service-nat.c.

2037{
2038 cfg = c;
2039 if (GNUNET_OK !=
2041 "NAT",
2042 "STUN_STALE",
2045
2046 /* Check for UPnP */
2049 "NAT",
2050 "ENABLE_UPNP");
2051 if (GNUNET_YES == enable_upnp)
2052 {
2053 /* check if it works */
2054 if (GNUNET_SYSERR ==
2056 GNUNET_NO,
2057 NULL))
2058 {
2060 _ (
2061 "UPnP enabled in configuration, but UPnP client `upnpc` command not found, disabling UPnP\n"));
2063 }
2064 }
2065 if (GNUNET_OK !=
2067 "nat",
2068 "DYNDNS_FREQUENCY",
2071
2074 "NAT",
2075 "ENABLE_IPSCAN");
2076
2078 NULL);
2080 cfg);
2083 NULL);
2084}
int enable_ipscan
Is IP Scanning enabled? GNUNET_YES if enabled, GNUNET_NO if disabled, without, only explicitly specif...
static void shutdown_task(void *cls)
Task run during shutdown.
#define DYNDNS_FREQUENCY
How often do we scan for changes in how our external (dyndns) hostname resolves?
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.
@ GNUNET_ERROR_TYPE_ERROR
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.
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:1340
struct GNUNET_STATISTICS_Handle * GNUNET_STATISTICS_create(const char *subsystem, const struct GNUNET_CONFIGURATION_Handle *cfg)
Get handle for the statistics service.
#define GNUNET_TIME_UNIT_HOURS
One hour.

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

2099{
2100 struct ClientHandle *ch;
2101
2102 ch = GNUNET_new (struct ClientHandle);
2103 ch->mq = mq;
2104 ch->client = c;
2106 ch_tail,
2107 ch);
2108 return ch;
2109}
struct GNUNET_MQ_Handle * mq
Definition: 003.c:5
static struct ClientHandle * ch_tail
Tail of client DLL.

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

2123{
2124 struct ClientHandle *ch = internal_cls;
2125 struct LocalAddressList *lal;
2126
2128 ch_tail,
2129 ch);
2130 for (unsigned int i = 0; i < ch->num_caddrs; i++)
2131 {
2132 if (NULL != ch->caddrs[i].mh)
2133 {
2134 GNUNET_NAT_mini_map_stop (ch->caddrs[i].mh);
2135 ch->caddrs[i].mh = NULL;
2136 }
2137 }
2138 GNUNET_free (ch->caddrs);
2139 while (NULL != (lal = ch->ext_addr_head))
2140 {
2141 GNUNET_CONTAINER_DLL_remove (ch->ext_addr_head,
2142 ch->ext_addr_tail,
2143 lal);
2144 GNUNET_free (lal);
2145 }
2146 if (NULL != ch->ext_dns_task)
2147 {
2148 GNUNET_SCHEDULER_cancel (ch->ext_dns_task);
2149 ch->ext_dns_task = NULL;
2150 }
2151 if (NULL != ch->external_monitor)
2152 {
2153 GN_external_ipv4_monitor_stop (ch->external_monitor);
2154 ch->external_monitor = NULL;
2155 }
2156 if (NULL != ch->ext_dns)
2157 {
2159 ch->ext_dns = NULL;
2160 }
2161 GNUNET_free (ch->hole_external);
2162 GNUNET_free (ch->section_name);
2163 GNUNET_free (ch);
2164}
void GN_external_ipv4_monitor_stop(struct GN_ExternalIPMonitor *mon)
Stop calling monitor.
void GNUNET_NAT_mini_map_stop(struct GNUNET_NAT_MiniHandle *mini)
Remove a mapping created with (mini)upnpc.
void GNUNET_RESOLVER_request_cancel(struct GNUNET_RESOLVER_RequestHandle *rh)
Cancel a request that is still pending with the resolver.

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 280 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 285 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 290 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 295 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 300 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 310 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 315 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 320 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 325 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 330 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 336 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 342 of file gnunet-service-nat.c.

Referenced by run().