GNUnet  0.19.5
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 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_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_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 struct GNUNET_MQ_Envelope * ac
Handle to current GNUNET_PEERINFO_add_peer() operation.
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, 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);
682  GNUNET_MQ_send (ch->mq,
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:62
#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 ac, 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;
872  check_notify_client (&lal,
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));
969  GNUNET_MQ_send (ch->mq,
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:1272
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(), SCAN_FREQ, and scan_task.

Referenced by run().

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 ac, 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
1221  &dyndns_lookup,
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);
1232  check_notify_client (lal,
1233  ch,
1234  GNUNET_NO);
1235  GNUNET_free (lal);
1236  }
1237  }
1238  return;
1239  }
1241  "Got IP `%s' for external address `%s'\n",
1242  GNUNET_a2s (addr,
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);
1292  check_notify_client (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);
1401  check_notify_client (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);
1424  check_notify_client (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:1299
#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);
1464  GNUNET_SERVICE_client_drop (ch->client);
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);
1484  GNUNET_SERVICE_client_drop (ch->client);
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);
1526  GNUNET_SERVICE_client_drop (ch->client);
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  {
1571  check_notify_client (lal,
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:2330
void GNUNET_SERVICE_client_continue(struct GNUNET_SERVICE_Client *c)
Continue receiving further messages from the given client.
Definition: service.c:2249
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));
1644  GNUNET_MQ_send (ch->mq,
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_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);
1701  GNUNET_SERVICE_client_drop (ch->client);
1702  return;
1703  }
1704  break;
1705 
1706  case AF_INET6:
1707  if (sa_len != sizeof(struct sockaddr_in6))
1708  {
1709  GNUNET_break (0);
1710  GNUNET_SERVICE_client_drop (ch->client);
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
1759  &stun_ip_timeout,
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;
1771  &stun_ip_timeout,
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.
static char buf[2048]
void * GNUNET_SCHEDULER_cancel(struct GNUNET_SCHEDULER_Task *task)
Cancel the task with the specified identifier.
Definition: scheduler.c:975
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 buf, 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);
1837  GNUNET_SERVICE_client_drop (ch->client);
1838  return;
1839  }
1840  if (remote_sa_len != sizeof(struct sockaddr_in))
1841  {
1842  GNUNET_break_op (0);
1843  GNUNET_SERVICE_client_drop (ch->client);
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
Return value of the commandline.
Definition: gnunet-abd.c:81
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 _, buf, 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:

◆ shutdown_task()

static void shutdown_task ( void *  cls)
static

Task run during shutdown.

Parameters
clsunused

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

1873 {
1874  struct StunExternalIP *se;
1875 
1876  while (NULL != (se = se_head))
1877  {
1879  se_tail,
1880  se);
1882  GNUNET_free (se);
1883  }
1885  if (NULL != scan_task)
1886  {
1888  scan_task = NULL;
1889  }
1890  if (NULL != stats)
1891  {
1893  GNUNET_NO);
1894  stats = NULL;
1895  }
1896  destroy_lal ();
1897 }
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 1908 of file gnunet-service-nat.c.

1911 {
1912  cfg = c;
1913  if (GNUNET_OK !=
1915  "NAT",
1916  "STUN_STALE",
1919 
1920  /* Check for UPnP */
1921  enable_upnp
1923  "NAT",
1924  "ENABLE_UPNP");
1925  if (GNUNET_YES == enable_upnp)
1926  {
1927  /* check if it works */
1928  if (GNUNET_SYSERR ==
1930  GNUNET_NO,
1931  NULL))
1932  {
1934  _ (
1935  "UPnP enabled in configuration, but UPnP client `upnpc` command not found, disabling UPnP\n"));
1937  }
1938  }
1939  if (GNUNET_OK !=
1941  "nat",
1942  "DYNDNS_FREQUENCY",
1943  &dyndns_frequency))
1945 
1948  "NAT",
1949  "ENABLE_IPSCAN");
1950 
1952  NULL);
1954  cfg);
1955  if (GNUNET_YES == enable_ipscan)
1957  NULL);
1958 }
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:1334
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 1970 of file gnunet-service-nat.c.

1973 {
1974  struct ClientHandle *ch;
1975 
1976  ch = GNUNET_new (struct ClientHandle);
1977  ch->mq = mq;
1978  ch->client = c;
1980  ch_tail,
1981  ch);
1982  return ch;
1983 }
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 1994 of file gnunet-service-nat.c.

1997 {
1998  struct ClientHandle *ch = internal_cls;
1999  struct LocalAddressList *lal;
2000 
2002  ch_tail,
2003  ch);
2004  for (unsigned int i = 0; i < ch->num_caddrs; i++)
2005  {
2006  if (NULL != ch->caddrs[i].mh)
2007  {
2008  GNUNET_NAT_mini_map_stop (ch->caddrs[i].mh);
2009  ch->caddrs[i].mh = NULL;
2010  }
2011  }
2012  GNUNET_free (ch->caddrs);
2013  while (NULL != (lal = ch->ext_addr_head))
2014  {
2015  GNUNET_CONTAINER_DLL_remove (ch->ext_addr_head,
2016  ch->ext_addr_tail,
2017  lal);
2018  GNUNET_free (lal);
2019  }
2020  if (NULL != ch->ext_dns_task)
2021  {
2022  GNUNET_SCHEDULER_cancel (ch->ext_dns_task);
2023  ch->ext_dns_task = NULL;
2024  }
2025  if (NULL != ch->external_monitor)
2026  {
2027  GN_external_ipv4_monitor_stop (ch->external_monitor);
2028  ch->external_monitor = NULL;
2029  }
2030  if (NULL != ch->ext_dns)
2031  {
2033  ch->ext_dns = NULL;
2034  }
2035  GNUNET_free (ch->hole_external);
2036  GNUNET_free (ch->section_name);
2037  GNUNET_free (ch);
2038 }
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()

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

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