GNUnet  0.10.x
nat_auto_api_test.c
Go to the documentation of this file.
1 /*
2  This file is part of GNUnet.
3  Copyright (C) 2011, 2016 GNUnet e.V.
4 
5  GNUnet is free software: you can redistribute it and/or modify it
6  under the terms of the GNU Affero General Public License as published
7  by the Free Software Foundation, either version 3 of the License,
8  or (at your option) any later version.
9 
10  GNUnet is distributed in the hope that it will be useful, but
11  WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  Affero General Public License for more details.
14 
15  You should have received a copy of the GNU Affero General Public License
16  along with this program. If not, see <http://www.gnu.org/licenses/>.
17 
18  SPDX-License-Identifier: AGPL3.0-or-later
19 */
25 #include "platform.h"
26 #include "gnunet_util_lib.h"
27 #include "gnunet_nat_service.h"
29 #include "nat-auto.h"
30 
31 #define LOG(kind,...) GNUNET_log_from (kind, "nat-auto", __VA_ARGS__)
32 
33 #define NAT_SERVER_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30)
34 
38 struct NatActivity
39 {
43  struct NatActivity *next;
44 
48  struct NatActivity *prev;
49 
54 
59 
64 };
65 
66 
70 struct ClientActivity
71 {
75  struct ClientActivity *next;
76 
80  struct ClientActivity *prev;
81 
85  struct GNUNET_MQ_Handle *mq;
86 
91 
92 };
93 
94 
99 {
100 
105 
110 
114  void *report_cls;
115 
120 
125 
130 
135 
140 
145 
150 
155 
160 
164  int proto;
165 
169  uint16_t data;
170 
175 };
176 
177 
186 static void
187 reversal_cb (void *cls,
188  const struct sockaddr *addr,
189  socklen_t addrlen)
190 {
191  struct GNUNET_NAT_AUTO_Test *h = cls;
192  const struct sockaddr_in *sa;
193 
194  if (sizeof (struct sockaddr_in) != addrlen)
195  return;
196  sa = (const struct sockaddr_in *) addr;
197  if (h->data != sa->sin_port)
198  {
200  "Received connection reversal request for wrong port\n");
201  return; /* wrong port */
202  }
203  /* report success */
204  h->report (h->report_cls,
206 }
207 
208 
215 static void
216 do_udp_read (void *cls)
217 {
218  struct GNUNET_NAT_AUTO_Test *tst = cls;
219  uint16_t data;
220  const struct GNUNET_SCHEDULER_TaskContext *tc;
221 
223  tst->ltask =
225  tst->lsock,
226  &do_udp_read,
227  tst);
228  if ((NULL != tc->write_ready) &&
230  tst->lsock)) &&
231  (sizeof (data) ==
233  &data,
234  sizeof (data))))
235  {
236  if (data == tst->data)
237  tst->report (tst->report_cls,
239  else
241  "Received data mismatches expected value\n");
242  }
243  else
245  "Failed to receive data from inbound connection\n");
246 }
247 
248 
255 static void
256 do_read (void *cls)
257 {
258  struct NatActivity *na = cls;
259  struct GNUNET_NAT_AUTO_Test *tst;
260  uint16_t data;
261  const struct GNUNET_SCHEDULER_TaskContext *tc;
262 
264  na->rtask = NULL;
265  tst = na->h;
267  tst->na_tail,
268  na);
269  if ((NULL != tc->write_ready) &&
271  na->sock)) &&
272  (sizeof (data) ==
274  &data,
275  sizeof (data))))
276  {
277  if (data == tst->data)
278  tst->report (tst->report_cls,
280  else
282  "Received data does not match expected value\n");
283  }
284  else
286  "Failed to receive data from inbound connection\n");
288  GNUNET_free (na);
289 }
290 
291 
298 static void
299 do_accept (void *cls)
300 {
301  struct GNUNET_NAT_AUTO_Test *tst = cls;
302  struct GNUNET_NETWORK_Handle *s;
303  struct NatActivity *wl;
304 
306  tst->lsock,
307  &do_accept,
308  tst);
310  NULL,
311  NULL);
312  if (NULL == s)
313  {
315  "accept");
316  return; /* odd error */
317  }
319  "Got an inbound connection, waiting for data\n");
320  wl = GNUNET_new (struct NatActivity);
321  wl->sock = s;
322  wl->h = tst;
323  wl->rtask =
325  wl->sock,
326  &do_read,
327  wl);
329  tst->na_tail,
330  wl);
331 }
332 
333 
341 static void
342 mq_error_handler (void *cls,
343  enum GNUNET_MQ_Error error)
344 {
345  struct ClientActivity *ca = cls;
346  struct GNUNET_NAT_AUTO_Test *tst = ca->h;
347 
349  tst->ca_tail,
350  ca);
351  GNUNET_MQ_destroy (ca->mq);
352  GNUNET_free (ca);
353 }
354 
355 
368 static void
369 addr_cb (void *cls,
370  void **app_ctx,
371  int add_remove,
373  const struct sockaddr *addr,
374  socklen_t addrlen)
375 {
376  struct GNUNET_NAT_AUTO_Test *h = cls;
377  struct ClientActivity *ca;
378  struct GNUNET_MQ_Envelope *env;
380  const struct sockaddr_in *sa;
381 
382  (void) app_ctx;
383  if (GNUNET_YES != add_remove)
384  return;
385  if (addrlen != sizeof (struct sockaddr_in))
386  {
388  "NAT test ignores IPv6 address `%s' returned from NAT library\n",
389  GNUNET_a2s (addr,
390  addrlen));
391  return; /* ignore IPv6 here */
392  }
394  "Asking gnunet-nat-server to connect to `%s'\n",
395  GNUNET_a2s (addr,
396  addrlen));
397 
398  ca = GNUNET_new (struct ClientActivity);
399  ca->h = h;
400  ca->mq = GNUNET_CLIENT_connect (h->cfg,
401  "gnunet-nat-server",
402  NULL,
404  ca);
405  if (NULL == ca->mq)
406  {
407  GNUNET_free (ca);
409  _("Failed to connect to `gnunet-nat-server'\n"));
410  return;
411  }
413  h->ca_tail,
414  ca);
415  sa = (const struct sockaddr_in *) addr;
416  env = GNUNET_MQ_msg (msg,
418  msg->dst_ipv4 = sa->sin_addr.s_addr;
419  msg->dport = sa->sin_port;
420  msg->data = h->data;
421  msg->is_tcp = htonl ((uint32_t) (h->proto == IPPROTO_TCP));
422  GNUNET_MQ_send (ca->mq,
423  env);
424 }
425 
426 
434 static void
435 do_fail (void *cls)
436 {
437  struct GNUNET_NAT_AUTO_Test *nh = cls;
438 
439  nh->ttask = NULL;
440  nh->report (nh->report_cls,
441  nh->status);
442 }
443 
444 
456 struct GNUNET_NAT_AUTO_Test *
458  uint8_t proto,
459  const char *section_name,
461  void *report_cls)
462 {
463  struct GNUNET_NAT_AUTO_Test *nh;
464  unsigned long long bnd_port;
465  struct sockaddr_in sa;
466  const struct sockaddr *addrs[] = {
467  (const struct sockaddr *) &sa
468  };
469  const socklen_t addrlens[] = {
470  sizeof (sa)
471  };
472 
473  if ( (GNUNET_OK !=
475  section_name,
476  "PORT",
477  &bnd_port)) ||
478  (bnd_port > 65535) )
479  {
481  _("Failed to find valid PORT in section `%s'\n"),
482  section_name);
483  return NULL;
484  }
485 
486  memset (&sa, 0, sizeof (sa));
487  sa.sin_family = AF_INET;
488  sa.sin_port = htons ((uint16_t) bnd_port);
489 #if HAVE_SOCKADDR_IN_SIN_LEN
490  sa.sin_len = sizeof (sa);
491 #endif
492 
493  nh = GNUNET_new (struct GNUNET_NAT_AUTO_Test);
494  nh->cfg = cfg;
495  nh->proto = proto;
496  nh->section_name = GNUNET_strdup (section_name);
497  nh->report = report;
498  nh->report_cls = report_cls;
500  if (0 == bnd_port)
501  {
502  nh->nat
503  = GNUNET_NAT_register (cfg,
504  section_name,
505  proto,
506  0, NULL, NULL,
507  &addr_cb,
508  &reversal_cb,
509  nh);
510  }
511  else
512  {
513  nh->lsock
514  = GNUNET_NETWORK_socket_create (AF_INET,
515  (IPPROTO_UDP == proto)
516  ? SOCK_DGRAM
517  : SOCK_STREAM,
518  proto);
519  if ( (NULL == nh->lsock) ||
520  (GNUNET_OK !=
522  (const struct sockaddr *) &sa,
523  sizeof (sa))))
524  {
526  _("Failed to create socket bound to `%s' for NAT test: %s\n"),
527  GNUNET_a2s ((const struct sockaddr *) &sa,
528  sizeof (sa)),
529  STRERROR (errno));
530  if (NULL != nh->lsock)
531  {
533  nh->lsock = NULL;
534  }
537  nh);
538  return nh;
539  }
540  if (IPPROTO_TCP == proto)
541  {
544  5));
545  nh->ltask =
547  nh->lsock,
548  &do_accept,
549  nh);
550  }
551  else
552  {
553  nh->ltask =
555  nh->lsock,
556  &do_udp_read,
557  nh);
558  }
560  "NAT test listens on port %llu (%s)\n",
561  bnd_port,
562  (IPPROTO_TCP == proto) ? "tcp" : "udp");
563  nh->nat = GNUNET_NAT_register (cfg,
564  section_name,
565  proto,
566  1,
567  addrs,
568  addrlens,
569  &addr_cb,
570  NULL,
571  nh);
572  if (NULL == nh->nat)
573  {
575  _("NAT test failed to start NAT library\n"));
576  if (NULL != nh->ltask)
577  {
579  nh->ltask = NULL;
580  }
581  if (NULL != nh->lsock)
582  {
584  nh->lsock = NULL;
585  }
588  nh);
589  return nh;
590  }
591  }
592  return nh;
593 }
594 
595 
601 void
603 {
604  struct NatActivity *pos;
605  struct ClientActivity *cpos;
606 
608  "Stopping NAT test\n");
609  while (NULL != (cpos = tst->ca_head))
610  {
612  tst->ca_tail,
613  cpos);
614  GNUNET_MQ_destroy (cpos->mq);
615  GNUNET_free (cpos);
616  }
617  while (NULL != (pos = tst->na_head))
618  {
620  tst->na_tail,
621  pos);
624  GNUNET_free (pos);
625  }
626  if (NULL != tst->ttask)
627  {
629  tst->ttask = NULL;
630  }
631  if (NULL != tst->ltask)
632  {
634  tst->ltask = NULL;
635  }
636  if (NULL != tst->lsock)
637  {
639  tst->lsock = NULL;
640  }
641  if (NULL != tst->nat)
642  {
643  GNUNET_NAT_unregister (tst->nat);
644  tst->nat = NULL;
645  }
646  GNUNET_free (tst->section_name);
647  GNUNET_free (tst);
648 }
649 
650 /* end of nat_auto_api_test.c */
#define GNUNET_CONTAINER_DLL_remove(head, tail, element)
Remove an element from a DLL.
int GNUNET_NETWORK_socket_listen(const struct GNUNET_NETWORK_Handle *desc, int backlog)
Listen on a socket.
Definition: network.c:796
NAT test failed to initiate.
const struct GNUNET_SCHEDULER_TaskContext * GNUNET_SCHEDULER_get_task_context(void)
Obtain the reasoning why the current task was started.
Definition: scheduler.c:746
char * section_name
Section name of plugin to test.
GNUNET_NAT_TestCallback report
Function to call with success report.
Handle for active NAT registrations.
Definition: nat_api.c:72
struct GNUNET_NAT_Handle * nat
Handle to NAT traversal in use.
struct GNUNET_MessageHeader * msg
Definition: 005.c:2
GNUNET_NAT_AddressClass
Some addresses contain sensitive information or are not suitable for global distribution.
static void mq_error_handler(void *cls, enum GNUNET_MQ_Error error)
We got disconnected from the NAT server.
int GNUNET_CONFIGURATION_get_value_number(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option, unsigned long long *number)
Get a configuration value that should be a number.
#define GNUNET_CONTAINER_DLL_insert(head, tail, element)
Insert an element at the head of a DLL.
#define LOG(kind,...)
struct GNUNET_MQ_Handle * GNUNET_CLIENT_connect(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *service_name, const struct GNUNET_MQ_MessageHandler *handlers, GNUNET_MQ_ErrorHandler error_handler, void *error_handler_cls)
Create a message queue to connect to a GNUnet service.
Definition: client.c:901
struct ClientActivity * ca_tail
Tail of list of client activities.
static void reversal_cb(void *cls, const struct sockaddr *addr, socklen_t addrlen)
Function called from GNUNET_NAT_register whenever someone asks us to do connection reversal...
Context information passed to each scheduler task.
GNUNET_MQ_Error
Error codes for the queue.
ssize_t GNUNET_NETWORK_socket_recv(const struct GNUNET_NETWORK_Handle *desc, void *buffer, size_t length)
Read data from a connected socket (always non-blocking).
Definition: network.c:894
struct GNUNET_MQ_Handle * mq
Socket of the incoming connection.
struct GNUNET_NETWORK_Handle * sock
Socket of the incoming connection.
static uint8_t proto
Protocol to use.
Definition: gnunet-nat.c:60
#define STRERROR(i)
Definition: plibc.h:676
static struct GNUNET_SCHEDULER_TaskContext tc
Task context of the current task.
Definition: scheduler.c:417
static void do_udp_read(void *cls)
Activity on our incoming socket.
int GNUNET_NETWORK_socket_bind(struct GNUNET_NETWORK_Handle *desc, const struct sockaddr *address, socklen_t address_len)
Bind a socket to a particular address.
Definition: network.c:522
Handle to a NAT test.
const struct GNUNET_NETWORK_FDSet * write_ready
Set of file descriptors ready for writing; note that additional bits may be set that were not in the ...
#define GNUNET_MQ_msg(mvar, type)
Allocate a GNUNET_MQ_Envelope.
Definition: gnunet_mq_lib.h:67
#define GNUNET_MESSAGE_TYPE_NAT_TEST
Message to ask NAT server to perform traversal test.
struct NatActivity * na_head
Head of list of nat activities.
void * report_cls
Closure for report.
void(* GNUNET_NAT_TestCallback)(void *cls, enum GNUNET_NAT_StatusCode result)
Function called to report success or failure for NAT configuration test.
void GNUNET_NAT_AUTO_test_stop(struct GNUNET_NAT_AUTO_Test *tst)
Stop an active NAT test.
#define GNUNET_OK
Named constants for return values.
Definition: gnunet_common.h:78
const struct GNUNET_NETWORK_FDSet * read_ready
Set of file descriptors ready for reading; note that additional bits may be set that were not in the ...
#define GNUNET_new(type)
Allocate a struct or union of the given type.
#define GNUNET_strdup(a)
Wrapper around GNUNET_xstrdup_.
#define GNUNET_break(cond)
Use this for internal assertion violations that are not fatal (can be handled) but should not occur...
struct GNUNET_SCHEDULER_Task * rtask
Task reading from the incoming connection.
#define _(String)
GNU gettext support macro.
Definition: platform.h:208
static void addr_cb(void *cls, void **app_ctx, int add_remove, enum GNUNET_NAT_AddressClass ac, const struct sockaddr *addr, socklen_t addrlen)
Address-callback, used to send message to gnunet-nat-server.
Entry we keep for each incoming connection.
struct GNUNET_NETWORK_Handle * GNUNET_NETWORK_socket_accept(const struct GNUNET_NETWORK_Handle *desc, struct sockaddr *address, socklen_t *address_len)
Accept a new connection on a socket.
Definition: network.c:468
#define GNUNET_log_strerror(level, cmd)
Log an error message at log-level &#39;level&#39; that indicates a failure of the command &#39;cmd&#39; with the mess...
struct GNUNET_SCHEDULER_Task * ltask
Identity of task for the listen socket (if any)
static void do_read(void *cls)
Activity on our incoming socket.
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:1273
GNUNET_NAT_StatusCode
Error Types for the NAT subsystem (which can then later be converted/resolved to a string) ...
uint16_t status
See PRISM_STATUS_*-constants.
uint16_t data
Data that should be transmitted or source-port.
#define GNUNET_TIME_UNIT_FOREVER_REL
Constant used to specify "forever".
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)...
int32_t is_tcp
GNUNET_YES for TCP, GNUNET_NO for UDP.
Definition: nat-auto.h:64
static void do_accept(void *cls)
Activity on our listen socket.
static struct GNUNET_NAT_Handle * nh
Handle to NAT operation.
Definition: gnunet-nat.c:80
struct GNUNET_NAT_AUTO_Test * h
Handle of the master context.
Failure in network subsystem, check permissions.
static struct GNUNET_CONFIGURATION_Handle * cfg
Our configuration.
Definition: gnunet-arm.c:104
void GNUNET_NAT_unregister(struct GNUNET_NAT_Handle *nh)
Stop port redirection and public IP address detection for the given handle.
Definition: nat_api.c:690
struct GNUNET_NAT_AUTO_Test * h
Handle to overall NAT test.
static void do_fail(void *cls)
Calls the report-callback reporting failure.
struct GNUNET_NAT_Handle * GNUNET_NAT_register(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *config_section, uint8_t proto, unsigned int num_addrs, const struct sockaddr **addrs, const socklen_t *addrlens, GNUNET_NAT_AddressCallback address_callback, GNUNET_NAT_ReversalCallback reversal_callback, void *callback_cls)
Attempt to enable port redirection and detect public IP address contacting UPnP or NAT-PMP routers on...
Definition: nat_api.c:378
static struct GNUNET_MQ_Envelope * ac
Handle to current GNUNET_PEERINFO_add_peer() operation.
struct ClientActivity * ca_head
Head of list of client activities.
struct GNUNET_MQ_Envelope * env
Definition: 005.c:1
enum GNUNET_NAT_StatusCode status
Status code to be reported to the timeout/status call.
struct GNUNET_NAT_Test * h
Handle to overall NAT test.
uint32_t dst_ipv4
IPv4 target IP address.
Definition: nat-auto.h:49
struct NatActivity * na_tail
Tail of list of nat activities.
Handle to a message queue.
Definition: mq.c:85
Messages for interaction with gnunet-nat-auto-service.
const struct GNUNET_CONFIGURATION_Handle * cfg
Configuration used.
configuration data
Definition: configuration.c:85
static char * section_name
Name of section in configuration file to use for additional options.
Definition: gnunet-nat.c:40
struct GNUNET_MQ_Handle * mq
Definition: 003.c:5
#define GNUNET_log(kind,...)
Entry in list of pending tasks.
Definition: scheduler.c:134
uint16_t dport
Port to use, 0 to send dummy ICMP response.
Definition: nat-auto.h:54
handle to a socket
Definition: network.c:46
struct NatActivity * prev
This is a doubly-linked list.
struct GNUNET_NAT_Test * h
Handle of the master context.
void GNUNET_MQ_destroy(struct GNUNET_MQ_Handle *mq)
Destroy the message queue.
Definition: mq.c:824
#define GNUNET_YES
Definition: gnunet_common.h:80
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_read_net(struct GNUNET_TIME_Relative delay, struct GNUNET_NETWORK_Handle *rfd, GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run with a specified delay or when the specified file descriptor is ready f...
Definition: scheduler.c:1478
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:353
uint16_t data
Data to send OR advertised-port (in NBO) to use for dummy ICMP.
Definition: nat-auto.h:59
int proto
IPPROTO_TCP or IPPROTO_UDP.
Entry we keep for each connection to the gnunet-nat-service.
struct NatActivity * next
This is a doubly-linked list.
struct GNUNET_NAT_AUTO_Test * GNUNET_NAT_AUTO_test_start(const struct GNUNET_CONFIGURATION_Handle *cfg, uint8_t proto, const char *section_name, GNUNET_NAT_TestCallback report, void *report_cls)
Start testing if NAT traversal works using the given configuration.
struct GNUNET_SCHEDULER_Task * ttask
Task identifier for the timeout (if any)
int GNUNET_NETWORK_fdset_isset(const struct GNUNET_NETWORK_FDSet *fds, const struct GNUNET_NETWORK_Handle *desc)
Check whether a socket is part of the fd set.
Definition: network.c:1181
uint32_t data
The data value.
int GNUNET_NETWORK_socket_close(struct GNUNET_NETWORK_Handle *desc)
Close a socket.
Definition: network.c:604
Request to test NAT traversal, sent to the gnunet-nat-server (not the service!).
Definition: nat-auto.h:39
#define GNUNET_free(ptr)
Wrapper around free.
struct GNUNET_NETWORK_Handle * GNUNET_NETWORK_socket_create(int domain, int type, int protocol)
Create a new socket.
Definition: network.c:1037
void * GNUNET_SCHEDULER_cancel(struct GNUNET_SCHEDULER_Task *task)
Cancel the task with the specified identifier.
Definition: scheduler.c:965
struct GNUNET_NETWORK_Handle * lsock
Handle to listen socket, or NULL.