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 \
34  GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 30)
35 
39 struct NatActivity {
43  struct NatActivity *next;
44 
48  struct NatActivity *prev;
49 
54 
59 
64 };
65 
66 
70 struct ClientActivity {
74  struct ClientActivity *next;
75 
79  struct ClientActivity *prev;
80 
84  struct GNUNET_MQ_Handle *mq;
85 
90 };
91 
92 
101 
106 
110  void *report_cls;
111 
116 
121 
126 
131 
136 
141 
146 
151 
156 
160  int proto;
161 
165  uint16_t data;
166 
171 };
172 
173 
182 static void
183 reversal_cb(void *cls, const struct sockaddr *addr, socklen_t addrlen)
184 {
185  struct GNUNET_NAT_AUTO_Test *h = cls;
186  const struct sockaddr_in *sa;
187 
188  if (sizeof(struct sockaddr_in) != addrlen)
189  return;
190  sa = (const struct sockaddr_in *)addr;
191  if (h->data != sa->sin_port)
192  {
194  "Received connection reversal request for wrong port\n");
195  return; /* wrong port */
196  }
197  /* report success */
199 }
200 
201 
208 static void
209 do_udp_read(void *cls)
210 {
211  struct GNUNET_NAT_AUTO_Test *tst = cls;
212  uint16_t data;
213  const struct GNUNET_SCHEDULER_TaskContext *tc;
214 
217  tst->lsock,
218  &do_udp_read,
219  tst);
220  if ((NULL != tc->write_ready) &&
222  (sizeof(data) ==
223  GNUNET_NETWORK_socket_recv(tst->lsock, &data, sizeof(data))))
224  {
225  if (data == tst->data)
227  else
229  "Received data mismatches expected value\n");
230  }
231  else
233  "Failed to receive data from inbound connection\n");
234 }
235 
236 
243 static void
244 do_read(void *cls)
245 {
246  struct NatActivity *na = cls;
247  struct GNUNET_NAT_AUTO_Test *tst;
248  uint16_t data;
249  const struct GNUNET_SCHEDULER_TaskContext *tc;
250 
252  na->rtask = NULL;
253  tst = na->h;
255  if ((NULL != tc->write_ready) &&
257  (sizeof(data) ==
258  GNUNET_NETWORK_socket_recv(na->sock, &data, sizeof(data))))
259  {
260  if (data == tst->data)
262  else
264  "Received data does not match expected value\n");
265  }
266  else
268  "Failed to receive data from inbound connection\n");
270  GNUNET_free(na);
271 }
272 
273 
280 static void
281 do_accept(void *cls)
282 {
283  struct GNUNET_NAT_AUTO_Test *tst = cls;
284  struct GNUNET_NETWORK_Handle *s;
285  struct NatActivity *wl;
286 
288  tst->lsock,
289  &do_accept,
290  tst);
291  s = GNUNET_NETWORK_socket_accept(tst->lsock, NULL, NULL);
292  if (NULL == s)
293  {
295  return; /* odd error */
296  }
298  "Got an inbound connection, waiting for data\n");
299  wl = GNUNET_new(struct NatActivity);
300  wl->sock = s;
301  wl->h = tst;
303  wl->sock,
304  &do_read,
305  wl);
307 }
308 
309 
317 static void
318 mq_error_handler(void *cls, enum GNUNET_MQ_Error error)
319 {
320  struct ClientActivity *ca = cls;
321  struct GNUNET_NAT_AUTO_Test *tst = ca->h;
322 
324  GNUNET_MQ_destroy(ca->mq);
325  GNUNET_free(ca);
326 }
327 
328 
341 static void
342 addr_cb(void *cls,
343  void **app_ctx,
344  int add_remove,
346  const struct sockaddr *addr,
347  socklen_t addrlen)
348 {
349  struct GNUNET_NAT_AUTO_Test *h = cls;
350  struct ClientActivity *ca;
351  struct GNUNET_MQ_Envelope *env;
353  const struct sockaddr_in *sa;
354 
355  (void)app_ctx;
356  if (GNUNET_YES != add_remove)
357  return;
358  if (addrlen != sizeof(struct sockaddr_in))
359  {
361  "NAT test ignores IPv6 address `%s' returned from NAT library\n",
362  GNUNET_a2s(addr, addrlen));
363  return; /* ignore IPv6 here */
364  }
366  "Asking gnunet-nat-server to connect to `%s'\n",
367  GNUNET_a2s(addr, addrlen));
368 
369  ca = GNUNET_new(struct ClientActivity);
370  ca->h = h;
371  ca->mq = GNUNET_CLIENT_connect(h->cfg,
372  "gnunet-nat-server",
373  NULL,
375  ca);
376  if (NULL == ca->mq)
377  {
378  GNUNET_free(ca);
380  _("Failed to connect to `gnunet-nat-server'\n"));
381  return;
382  }
384  sa = (const struct sockaddr_in *)addr;
386  msg->dst_ipv4 = sa->sin_addr.s_addr;
387  msg->dport = sa->sin_port;
388  msg->data = h->data;
389  msg->is_tcp = htonl((uint32_t)(h->proto == IPPROTO_TCP));
390  GNUNET_MQ_send(ca->mq, env);
391 }
392 
393 
401 static void
402 do_fail(void *cls)
403 {
404  struct GNUNET_NAT_AUTO_Test *nh = cls;
405 
406  nh->ttask = NULL;
407  nh->report(nh->report_cls, nh->status);
408 }
409 
410 
422 struct GNUNET_NAT_AUTO_Test *
424  uint8_t proto,
425  const char *section_name,
427  void *report_cls)
428 {
429  struct GNUNET_NAT_AUTO_Test *nh;
430  unsigned long long bnd_port;
431  struct sockaddr_in sa;
432  const struct sockaddr *addrs[] = { (const struct sockaddr *)&sa };
433  const socklen_t addrlens[] = { sizeof(sa) };
434 
436  section_name,
437  "PORT",
438  &bnd_port)) ||
439  (bnd_port > 65535))
440  {
442  _("Failed to find valid PORT in section `%s'\n"),
443  section_name);
444  return NULL;
445  }
446 
447  memset(&sa, 0, sizeof(sa));
448  sa.sin_family = AF_INET;
449  sa.sin_port = htons((uint16_t)bnd_port);
450 #if HAVE_SOCKADDR_IN_SIN_LEN
451  sa.sin_len = sizeof(sa);
452 #endif
453 
454  nh = GNUNET_new(struct GNUNET_NAT_AUTO_Test);
455  nh->cfg = cfg;
456  nh->proto = proto;
457  nh->section_name = GNUNET_strdup(section_name);
458  nh->report = report;
459  nh->report_cls = report_cls;
461  if (0 == bnd_port)
462  {
463  nh->nat = GNUNET_NAT_register(cfg,
464  section_name,
465  proto,
466  0,
467  NULL,
468  NULL,
469  &addr_cb,
470  &reversal_cb,
471  nh);
472  }
473  else
474  {
475  nh->lsock =
477  (IPPROTO_UDP == proto) ? SOCK_DGRAM
478  : SOCK_STREAM,
479  proto);
480  if ((NULL == nh->lsock) ||
482  (const struct sockaddr *)&sa,
483  sizeof(sa))))
484  {
486  _("Failed to create socket bound to `%s' for NAT test: %s\n"),
487  GNUNET_a2s((const struct sockaddr *)&sa, sizeof(sa)),
488  strerror(errno));
489  if (NULL != nh->lsock)
490  {
492  nh->lsock = NULL;
493  }
496  return nh;
497  }
498  if (IPPROTO_TCP == proto)
499  {
502  nh->lsock,
503  &do_accept,
504  nh);
505  }
506  else
507  {
509  nh->lsock,
510  &do_udp_read,
511  nh);
512  }
514  "NAT test listens on port %llu (%s)\n",
515  bnd_port,
516  (IPPROTO_TCP == proto) ? "tcp" : "udp");
517  nh->nat = GNUNET_NAT_register(cfg,
518  section_name,
519  proto,
520  1,
521  addrs,
522  addrlens,
523  &addr_cb,
524  NULL,
525  nh);
526  if (NULL == nh->nat)
527  {
529  _("NAT test failed to start NAT library\n"));
530  if (NULL != nh->ltask)
531  {
533  nh->ltask = NULL;
534  }
535  if (NULL != nh->lsock)
536  {
538  nh->lsock = NULL;
539  }
542  return nh;
543  }
544  }
545  return nh;
546 }
547 
548 
554 void
556 {
557  struct NatActivity *pos;
558  struct ClientActivity *cpos;
559 
560  LOG(GNUNET_ERROR_TYPE_DEBUG, "Stopping NAT test\n");
561  while (NULL != (cpos = tst->ca_head))
562  {
563  GNUNET_CONTAINER_DLL_remove(tst->ca_head, tst->ca_tail, cpos);
564  GNUNET_MQ_destroy(cpos->mq);
565  GNUNET_free(cpos);
566  }
567  while (NULL != (pos = tst->na_head))
568  {
572  GNUNET_free(pos);
573  }
574  if (NULL != tst->ttask)
575  {
577  tst->ttask = NULL;
578  }
579  if (NULL != tst->ltask)
580  {
582  tst->ltask = NULL;
583  }
584  if (NULL != tst->lsock)
585  {
587  tst->lsock = NULL;
588  }
589  if (NULL != tst->nat)
590  {
592  tst->nat = NULL;
593  }
595  GNUNET_free(tst);
596 }
597 
598 /* 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:696
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:737
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:70
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:900
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:775
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
static struct GNUNET_SCHEDULER_TaskContext tc
Task context of the current task.
Definition: scheduler.c:410
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:474
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:75
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:181
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:420
#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:1264
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:63
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:376
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:48
struct NatActivity * na_tail
Tail of list of nat activities.
Handle to a message queue.
Definition: mq.c:84
Messages for interaction with gnunet-nat-auto-service.
const struct GNUNET_CONFIGURATION_Handle * cfg
Configuration used.
configuration data
Definition: configuration.c:83
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:131
uint16_t dport
Port to use, 0 to send dummy ICMP response.
Definition: nat-auto.h:53
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:821
#define GNUNET_YES
Definition: gnunet_common.h:77
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:1467
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:351
uint16_t data
Data to send OR advertised-port (in NBO) to use for dummy ICMP.
Definition: nat-auto.h:58
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:1017
uint32_t data
The data value.
int GNUNET_NETWORK_socket_close(struct GNUNET_NETWORK_Handle *desc)
Close a socket.
Definition: network.c:548
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:900
void * GNUNET_SCHEDULER_cancel(struct GNUNET_SCHEDULER_Task *task)
Cancel the task with the specified identifier.
Definition: scheduler.c:956
struct GNUNET_NETWORK_Handle * lsock
Handle to listen socket, or NULL.