GNUnet 0.21.1
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
39struct NatActivity
40{
44 struct NatActivity *next;
45
49 struct NatActivity *prev;
50
55
60
65};
66
67
71struct ClientActivity
72{
76 struct ClientActivity *next;
77
81 struct ClientActivity *prev;
82
86 struct GNUNET_MQ_Handle *mq;
87
92};
93
94
99{
104
109
114
119
124
129
134
139
144
149
154
159
163 int proto;
164
168 uint16_t data;
169
174};
175
176
185static void
186reversal_cb (void *cls, const struct sockaddr *addr, socklen_t addrlen)
187{
188 struct GNUNET_NAT_AUTO_Test *h = cls;
189 const struct sockaddr_in *sa;
190
191 if (sizeof(struct sockaddr_in) != addrlen)
192 return;
193 sa = (const struct sockaddr_in *) addr;
194 if (h->data != sa->sin_port)
195 {
197 "Received connection reversal request for wrong port\n");
198 return; /* wrong port */
199 }
200 /* report success */
201 h->report (h->report_cls, GNUNET_NAT_ERROR_SUCCESS);
202}
203
204
211static void
212do_udp_read (void *cls)
213{
214 struct GNUNET_NAT_AUTO_Test *tst = cls;
215 uint16_t data;
216 const struct GNUNET_SCHEDULER_TaskContext *tc;
217
220 tst->lsock,
222 tst);
223 if ((NULL != tc->write_ready) &&
225 (sizeof(data) ==
226 GNUNET_NETWORK_socket_recv (tst->lsock, &data, sizeof(data))))
227 {
228 if (data == tst->data)
230 else
232 "Received data mismatches expected value\n");
233 }
234 else
236 "Failed to receive data from inbound connection\n");
237}
238
239
246static void
247do_read (void *cls)
248{
249 struct NatActivity *na = cls;
250 struct GNUNET_NAT_AUTO_Test *tst;
251 uint16_t data;
252 const struct GNUNET_SCHEDULER_TaskContext *tc;
253
255 na->rtask = NULL;
256 tst = na->h;
258 if ((NULL != tc->write_ready) &&
260 (sizeof(data) ==
261 GNUNET_NETWORK_socket_recv (na->sock, &data, sizeof(data))))
262 {
263 if (data == tst->data)
265 else
267 "Received data does not match expected value\n");
268 }
269 else
271 "Failed to receive data from inbound connection\n");
273 GNUNET_free (na);
274}
275
276
283static void
284do_accept (void *cls)
285{
286 struct GNUNET_NAT_AUTO_Test *tst = cls;
287 struct GNUNET_NETWORK_Handle *s;
288 struct NatActivity *wl;
289
291 tst->lsock,
292 &do_accept,
293 tst);
294 s = GNUNET_NETWORK_socket_accept (tst->lsock, NULL, NULL);
295 if (NULL == s)
296 {
298 return; /* odd error */
299 }
301 "Got an inbound connection, waiting for data\n");
302 wl = GNUNET_new (struct NatActivity);
303 wl->sock = s;
304 wl->h = tst;
306 wl->sock,
307 &do_read,
308 wl);
310}
311
312
320static void
321mq_error_handler (void *cls, enum GNUNET_MQ_Error error)
322{
323 struct ClientActivity *ca = cls;
324 struct GNUNET_NAT_AUTO_Test *tst = ca->h;
325
327 GNUNET_MQ_destroy (ca->mq);
328 GNUNET_free (ca);
329}
330
331
344static void
345addr_cb (void *cls,
346 void **app_ctx,
347 int add_remove,
349 const struct sockaddr *addr,
350 socklen_t addrlen)
351{
352 struct GNUNET_NAT_AUTO_Test *h = cls;
353 struct ClientActivity *ca;
354 struct GNUNET_MQ_Envelope *env;
356 const struct sockaddr_in *sa;
357
358 (void) app_ctx;
359 if (GNUNET_YES != add_remove)
360 return;
361 if (addrlen != sizeof(struct sockaddr_in))
362 {
364 "NAT test ignores IPv6 address `%s' returned from NAT library\n",
365 GNUNET_a2s (addr, addrlen));
366 return; /* ignore IPv6 here */
367 }
369 "Asking gnunet-nat-server to connect to `%s'\n",
370 GNUNET_a2s (addr, addrlen));
371
372 ca = GNUNET_new (struct ClientActivity);
373 ca->h = h;
375 "gnunet-nat-server",
376 NULL,
378 ca);
379 if (NULL == ca->mq)
380 {
381 GNUNET_free (ca);
383 _ ("Failed to connect to `gnunet-nat-server'\n"));
384 return;
385 }
386 GNUNET_CONTAINER_DLL_insert (h->ca_head, h->ca_tail, ca);
387 sa = (const struct sockaddr_in *) addr;
389 msg->dst_ipv4 = sa->sin_addr.s_addr;
390 msg->dport = sa->sin_port;
391 msg->data = h->data;
392 msg->is_tcp = htonl ((uint32_t) (h->proto == IPPROTO_TCP));
393 GNUNET_MQ_send (ca->mq, env);
394}
395
396
404static void
405do_fail (void *cls)
406{
407 struct GNUNET_NAT_AUTO_Test *nh = cls;
408
409 nh->ttask = NULL;
410 nh->report (nh->report_cls, nh->status);
411}
412
413
427 uint8_t proto,
428 const char *section_name,
430 void *report_cls)
431{
432 struct GNUNET_NAT_AUTO_Test *nh;
433 unsigned long long bnd_port;
434 struct sockaddr_in sa;
435 const struct sockaddr *addrs[] = { (const struct sockaddr *) &sa };
436 const socklen_t addrlens[] = { sizeof(sa) };
437
440 "PORT",
441 &bnd_port)) ||
442 (bnd_port > 65535))
443 {
445 _ ("Failed to find valid PORT in section `%s'\n"),
447 return NULL;
448 }
449
450 memset (&sa, 0, sizeof(sa));
451 sa.sin_family = AF_INET;
452 sa.sin_port = htons ((uint16_t) bnd_port);
453#if HAVE_SOCKADDR_IN_SIN_LEN
454 sa.sin_len = sizeof(sa);
455#endif
456
458 nh->cfg = cfg;
459 nh->proto = proto;
460 nh->section_name = GNUNET_strdup (section_name);
461 nh->report = report;
462 nh->report_cls = report_cls;
464 if (0 == bnd_port)
465 {
466 nh->nat = GNUNET_NAT_register (cfg,
468 proto,
469 0,
470 NULL,
471 NULL,
472 &addr_cb,
474 nh);
475 }
476 else
477 {
478 nh->lsock =
480 (IPPROTO_UDP == proto) ? SOCK_DGRAM
481 : SOCK_STREAM,
482 proto);
483 if ((NULL == nh->lsock) ||
485 (const struct sockaddr *) &sa,
486 sizeof(sa))))
487 {
489 _ ("Failed to create socket bound to `%s' for NAT test: %s\n"),
490 GNUNET_a2s ((const struct sockaddr *) &sa, sizeof(sa)),
491 strerror (errno));
492 if (NULL != nh->lsock)
493 {
495 nh->lsock = NULL;
496 }
499 return nh;
500 }
501 if (IPPROTO_TCP == proto)
502 {
505 nh->lsock,
506 &do_accept,
507 nh);
508 }
509 else
510 {
512 nh->lsock,
514 nh);
515 }
517 "NAT test listens on port %llu (%s)\n",
518 bnd_port,
519 (IPPROTO_TCP == proto) ? "tcp" : "udp");
520 nh->nat = GNUNET_NAT_register (cfg,
522 proto,
523 1,
524 addrs,
525 addrlens,
526 &addr_cb,
527 NULL,
528 nh);
529 if (NULL == nh->nat)
530 {
532 _ ("NAT test failed to start NAT library\n"));
533 if (NULL != nh->ltask)
534 {
536 nh->ltask = NULL;
537 }
538 if (NULL != nh->lsock)
539 {
541 nh->lsock = NULL;
542 }
545 return nh;
546 }
547 }
548 return nh;
549}
550
551
557void
559{
560 struct NatActivity *pos;
561 struct ClientActivity *cpos;
562
563 LOG (GNUNET_ERROR_TYPE_DEBUG, "Stopping NAT test\n");
564 while (NULL != (cpos = tst->ca_head))
565 {
567 GNUNET_MQ_destroy (cpos->mq);
568 GNUNET_free (cpos);
569 }
570 while (NULL != (pos = tst->na_head))
571 {
575 GNUNET_free (pos);
576 }
577 if (NULL != tst->ttask)
578 {
580 tst->ttask = NULL;
581 }
582 if (NULL != tst->ltask)
583 {
585 tst->ltask = NULL;
586 }
587 if (NULL != tst->lsock)
588 {
590 tst->lsock = NULL;
591 }
592 if (NULL != tst->nat)
593 {
595 tst->nat = NULL;
596 }
598 GNUNET_free (tst);
599}
600
601
602/* end of nat_auto_api_test.c */
struct GNUNET_MessageHeader * msg
Definition: 005.c:2
struct GNUNET_MQ_Envelope * env
Definition: 005.c:1
static struct GNUNET_ARM_Handle * h
Connection with ARM.
Definition: gnunet-arm.c:99
static struct GNUNET_CONFIGURATION_Handle * cfg
Our configuration.
Definition: gnunet-arm.c:109
static char * data
The data to insert into the dht.
static char * section_name
Adapter we are supposed to test.
static uint8_t proto
Protocol to use.
struct GNUNET_NAT_Handle * nh
Handle for connect to the NAT service.
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:1057
enum GNUNET_GenericReturnValue 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_remove(head, tail, element)
Remove an element from a DLL.
#define GNUNET_CONTAINER_DLL_insert(head, tail, element)
Insert an element at the head of a DLL.
#define GNUNET_log(kind,...)
@ GNUNET_OK
@ GNUNET_YES
#define GNUNET_break(cond)
Use this for internal assertion violations that are not fatal (can be handled) but should not occur.
const char * GNUNET_a2s(const struct sockaddr *addr, socklen_t addrlen)
Convert a "struct sockaddr*" (IPv4 or IPv6 address) to a string (for printing debug messages).
#define GNUNET_log_strerror(level, cmd)
Log an error message at log-level 'level' that indicates a failure of the command 'cmd' with the mess...
@ GNUNET_ERROR_TYPE_ERROR
@ GNUNET_ERROR_TYPE_DEBUG
@ GNUNET_ERROR_TYPE_INFO
#define GNUNET_strdup(a)
Wrapper around GNUNET_xstrdup_.
#define GNUNET_new(type)
Allocate a struct or union of the given type.
#define GNUNET_free(ptr)
Wrapper around free.
GNUNET_MQ_Error
Error codes for the queue.
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(mvar, type)
Allocate a GNUNET_MQ_Envelope.
Definition: gnunet_mq_lib.h:78
void GNUNET_MQ_destroy(struct GNUNET_MQ_Handle *mq)
Destroy the message queue.
Definition: mq.c:683
void GNUNET_NAT_AUTO_test_stop(struct GNUNET_NAT_AUTO_Test *tst)
Stop an active NAT test.
GNUNET_NAT_StatusCode
Error Types for the NAT subsystem (which can then later be converted/resolved to a string)
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:366
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:727
void(* GNUNET_NAT_TestCallback)(void *cls, enum GNUNET_NAT_StatusCode result)
Function called to report success or failure for NAT configuration test.
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.
GNUNET_NAT_AddressClass
Some addresses contain sensitive information or are not suitable for global distribution.
@ GNUNET_NAT_ERROR_SUCCESS
Just the default.
@ GNUNET_NAT_ERROR_INTERNAL_NETWORK_ERROR
Failure in network subsystem, check permissions.
@ GNUNET_NAT_ERROR_NAT_REGISTER_FAILED
NAT test failed to initiate.
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:392
enum GNUNET_GenericReturnValue GNUNET_NETWORK_socket_close(struct GNUNET_NETWORK_Handle *desc)
Close a socket.
Definition: network.c:508
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:716
struct GNUNET_NETWORK_Handle * GNUNET_NETWORK_socket_create(int domain, int type, int protocol)
Create a new socket.
Definition: network.c:832
enum GNUNET_GenericReturnValue 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:439
enum GNUNET_GenericReturnValue GNUNET_NETWORK_socket_listen(const struct GNUNET_NETWORK_Handle *desc, int backlog)
Listen on a socket.
Definition: network.c:651
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:949
#define GNUNET_MESSAGE_TYPE_NAT_TEST
Message to ask NAT server to perform traversal test.
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:1512
const struct GNUNET_SCHEDULER_TaskContext * GNUNET_SCHEDULER_get_task_context(void)
Obtain the reasoning why the current task was started.
Definition: scheduler.c:758
void * GNUNET_SCHEDULER_cancel(struct GNUNET_SCHEDULER_Task *task)
Cancel the task with the specified identifier.
Definition: scheduler.c:981
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_now(GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run as soon as possible.
Definition: scheduler.c:1305
#define GNUNET_TIME_UNIT_FOREVER_REL
Constant used to specify "forever".
static void do_read(void *cls)
Activity on our incoming socket.
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.
static void do_fail(void *cls)
Calls the report-callback reporting failure.
static void mq_error_handler(void *cls, enum GNUNET_MQ_Error error)
We got disconnected from the NAT server.
static void do_accept(void *cls)
Activity on our listen socket.
static void do_udp_read(void *cls)
Activity on our incoming socket.
#define LOG(kind,...)
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.
#define _(String)
GNU gettext support macro.
Definition: platform.h:178
static struct GNUNET_SCHEDULER_TaskContext tc
Task context of the current task.
Definition: scheduler.c:431
Entry we keep for each connection to the gnunet-nat-service.
struct GNUNET_MQ_Handle * mq
Socket of the incoming connection.
struct ClientActivity * next
This is a doubly-linked list.
struct GNUNET_NAT_Test * h
Handle to overall NAT test.
struct GNUNET_NAT_AUTO_Test * h
Handle to overall NAT test.
struct ClientActivity * prev
This is a doubly-linked list.
const struct GNUNET_CONFIGURATION_Handle * cfg
The configuration that we are using.
Definition: arm_api.c:112
Handle to a message queue.
Definition: mq.c:87
Request to test NAT traversal, sent to the gnunet-nat-server (not the service!).
Definition: nat-auto.h:39
Handle to a NAT test.
char * section_name
Section name of plugin to test.
int proto
IPPROTO_TCP or IPPROTO_UDP.
GNUNET_NAT_TestCallback report
Function to call with success report.
struct NatActivity * na_tail
Tail of list of nat activities.
struct GNUNET_NAT_Handle * nat
Handle to NAT traversal in use.
struct GNUNET_NETWORK_Handle * lsock
Handle to listen socket, or NULL.
uint16_t data
Data that should be transmitted or source-port.
struct NatActivity * na_head
Head of list of nat activities.
const struct GNUNET_CONFIGURATION_Handle * cfg
Configuration used.
void * report_cls
Closure for report.
struct GNUNET_SCHEDULER_Task * ttask
Task identifier for the timeout (if any)
struct ClientActivity * ca_head
Head of list of client activities.
struct ClientActivity * ca_tail
Tail of list of client activities.
enum GNUNET_NAT_StatusCode status
Status code to be reported to the timeout/status call.
struct GNUNET_SCHEDULER_Task * ltask
Identity of task for the listen socket (if any)
Handle for active NAT registrations.
Definition: nat_api.c:72
const struct GNUNET_CONFIGURATION_Handle * cfg
Configuration we use.
Definition: nat_api.c:76
handle to a socket
Definition: network.c:53
Context information passed to each scheduler task.
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 ...
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 ...
Entry in list of pending tasks.
Definition: scheduler.c:136
Entry we keep for each incoming connection.
struct NatActivity * prev
This is a doubly-linked list.
struct GNUNET_SCHEDULER_Task * rtask
Task reading from the incoming connection.
struct GNUNET_NAT_Test * h
Handle of the master context.
struct GNUNET_NETWORK_Handle * sock
Socket of the incoming connection.
struct NatActivity * next
This is a doubly-linked list.
struct GNUNET_NAT_AUTO_Test * h
Handle of the master context.