2 This file is part of GNUnet.
3 Copyright (C) 2015, 2016 GNUnet e.V.
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
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 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
22 * @file src/nat/gnunet-nat.c
23 * @brief Command-line tool to interact with the NAT service
24 * @author Christian Grothoff
25 * @author Bruno Cabral
28 #include "gnunet_util_lib.h"
29 #include "gnunet_nat_service.h"
32 * Value to return from #main().
34 static int global_ret;
37 * Handle to ongoing autoconfiguration.
39 static struct GNUNET_NAT_AutoHandle *ah;
44 static unsigned int adv_port;
47 * Flag set to 1 if we use IPPROTO_UDP.
52 * Flag set to 1 if we are to listen for connection reversal requests.
54 static int listen_reversal;
57 * Flag set to 1 if we use IPPROTO_TCP.
67 * Address we are bound to (in test), or should bind to
68 * (if #do_stun is set).
70 static char *bind_addr;
73 * External IP address and port to use for the test.
74 * If not set, use #bind_addr.
76 static char *extern_addr;
79 * Local address to use for connection reversal request.
81 static char *local_addr;
84 * Remote address to use for connection reversal request.
86 static char *remote_addr;
89 * Should we actually bind to #bind_addr and receive and process STUN requests?
91 static unsigned int do_stun;
94 * Should we run autoconfiguration?
96 static unsigned int do_auto;
99 * Handle to a NAT test operation.
101 static struct GNUNET_NAT_Test *nt;
104 * Handle to NAT operation.
106 static struct GNUNET_NAT_Handle *nh;
109 * Listen socket for STUN processing.
111 static struct GNUNET_NETWORK_Handle *ls;
114 * Task for reading STUN packets.
116 static struct GNUNET_SCHEDULER_Task *rtask;
120 * Test if all activities have finished, and if so,
134 GNUNET_SCHEDULER_shutdown ();
139 * Function to iterate over sugested changes options
142 * @param section name of the section
143 * @param option name of the option
144 * @param value value of the option
147 auto_conf_iter (void *cls,
159 * Function called with the result from the autoconfiguration.
162 * @param diff minimal suggested changes to the original configuration
163 * to make it work (as best as we can)
164 * @param result #GNUNET_NAT_ERROR_SUCCESS on success, otherwise the specific error code
165 * @param type what the situation of the NAT
168 auto_config_cb (void *cls,
169 const struct GNUNET_CONFIGURATION_Handle *diff,
170 enum GNUNET_NAT_StatusCode result,
171 enum GNUNET_NAT_Type type)
173 const char *nat_type;
174 char unknown_type[64];
179 case GNUNET_NAT_TYPE_NO_NAT:
182 case GNUNET_NAT_TYPE_UNREACHABLE_NAT:
183 nat_type = "NAT but we can traverse";
185 case GNUNET_NAT_TYPE_STUN_PUNCHED_NAT:
186 nat_type = "NAT but STUN is able to identify the correct information";
188 case GNUNET_NAT_TYPE_UPNP_NAT:
189 nat_type = "NAT but UPNP opened the ports";
192 SPRINTF (unknown_type,
193 "NAT unknown, type %u",
195 nat_type = unknown_type;
198 PRINTF ("NAT status: %s/%s\n",
199 GNUNET_NAT_status2string (result),
202 PRINTF ("SUGGESTED CHANGES:\n");
203 GNUNET_CONFIGURATION_iterate_section_values (diff,
207 // FIXME: have option to save config
213 * Function called to report success or failure for
214 * NAT configuration test.
217 * @param result #GNUNET_NAT_ERROR_SUCCESS on success, otherwise the specific error code
220 test_report_cb (void *cls,
221 enum GNUNET_NAT_StatusCode result)
224 PRINTF ("NAT test result: %s\n",
225 GNUNET_NAT_status2string (result));
231 * Signature of the callback passed to #GNUNET_NAT_register() for
232 * a function to call whenever our set of 'valid' addresses changes.
234 * @param cls closure, NULL
235 * @param add_remove #GNUNET_YES to add a new public IP address,
236 * #GNUNET_NO to remove a previous (now invalid) one
237 * @param ac address class the address belongs to
238 * @param addr either the previous or the new public IP address
239 * @param addrlen actual length of the @a addr
242 address_cb (void *cls,
244 enum GNUNET_NAT_AddressClass ac,
245 const struct sockaddr *addr,
248 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
250 add_remove ? "+" : "-",
258 * Signature of the callback passed to #GNUNET_NAT_register().
259 * for a function to call whenever someone asks us to do connection
262 * @param cls closure, NULL
263 * @param local_addr address where we received the request
264 * @param local_addrlen actual length of the @a local_addr
265 * @param remote_addr public IP address of the other peer
266 * @param remote_addrlen actual length of the @a remote_addr
269 reversal_cb (void *cls,
270 const struct sockaddr *local_addr,
271 socklen_t local_addrlen,
272 const struct sockaddr *remote_addr,
273 socklen_t remote_addrlen)
275 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
276 "Connection reversal requested by %s\n",
277 GNUNET_a2s (remote_addr,
283 * Task run on shutdown.
288 do_shutdown (void *cls)
292 GNUNET_NAT_autoconfig_cancel (ah);
297 GNUNET_NAT_test_stop (nt);
302 GNUNET_NAT_unregister (nh);
307 GNUNET_NETWORK_socket_close (ls);
312 GNUNET_SCHEDULER_cancel (rtask);
319 * Task to receive incoming packets for STUN processing.
322 stun_read_task (void *cls)
326 rtask = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
330 size = GNUNET_NETWORK_socket_recvfrom_amount (ls);
334 GNUNET_SCHEDULER_shutdown ();
340 struct sockaddr_storage sa;
341 socklen_t salen = sizeof (sa);
344 ret = GNUNET_NETWORK_socket_recvfrom (ls,
347 (struct sockaddr *) &sa,
352 GNUNET_SCHEDULER_shutdown ();
356 (void) GNUNET_NAT_stun_handle_packet (nh,
357 (const struct sockaddr *) &sa,
366 * Main function that will be run.
369 * @param args remaining command-line arguments
370 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
371 * @param c configuration
377 const struct GNUNET_CONFIGURATION_Handle *c)
380 struct sockaddr_in bind_sa;
381 struct sockaddr_in extern_sa;
382 struct sockaddr *local_sa;
383 struct sockaddr *remote_sa;
387 if (use_tcp && use_udp)
389 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
390 "Cannot use TCP and UDP\n");
401 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
402 "Must specify either TCP or UDP\n");
406 if (NULL != bind_addr)
409 GNUNET_STRINGS_to_address_ipv4 (bind_addr,
413 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
414 "Invalid socket address `%s'\n",
420 if (NULL != extern_addr)
423 GNUNET_STRINGS_to_address_ipv4 (extern_addr,
424 strlen (extern_addr),
427 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
428 "Invalid socket address `%s'\n",
434 if (NULL != local_addr)
436 local_len = GNUNET_STRINGS_parse_socket_addr (local_addr,
441 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
442 "Invalid socket address `%s'\n",
448 if (NULL != remote_addr)
450 remote_len = GNUNET_STRINGS_parse_socket_addr (remote_addr,
455 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
456 "Invalid socket address `%s'\n",
463 if (NULL != bind_addr)
465 if (NULL == extern_addr)
467 nt = GNUNET_NAT_test_start (c,
470 ntohs (bind_sa.sin_port),
472 ntohs (extern_sa.sin_port),
477 if (NULL != local_addr)
479 nh = GNUNET_NAT_register (c,
483 (const struct sockaddr **) &local_sa,
486 (listen_reversal) ? &reversal_cb : NULL,
490 GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
493 if (NULL != remote_addr)
498 (sizeof (struct sockaddr_in) != local_len) )
500 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
501 "Require IPv4 local address to initiate connection reversal\n");
503 GNUNET_SCHEDULER_shutdown ();
506 if (sizeof (struct sockaddr_in) != remote_len)
508 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
509 "Require IPv4 reversal target address\n");
511 GNUNET_SCHEDULER_shutdown ();
514 ret = GNUNET_NAT_request_reversal (nh,
515 (const struct sockaddr_in *) &local_sa,
516 (const struct sockaddr_in *) &remote_sa);
520 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
521 "Connection reversal internal error\n");
524 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
525 "Connection reversal unavailable\n");
528 /* operation in progress */
535 ah = GNUNET_NAT_autoconfig_start (c,
542 if (NULL == local_addr)
544 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
545 "Require local address to support STUN requests\n");
547 GNUNET_SCHEDULER_shutdown ();
550 if (IPPROTO_UDP != proto)
552 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
553 "STUN only supported over UDP\n");
555 GNUNET_SCHEDULER_shutdown ();
558 ls = GNUNET_NETWORK_socket_create (af,
562 GNUNET_NETWORK_socket_bind (ls,
566 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
567 "Failed to bind to %s: %s\n",
568 GNUNET_a2s (local_sa,
572 GNUNET_SCHEDULER_shutdown ();
575 rtask = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
586 * Main function of gnunet-nat
588 * @param argc number of command-line arguments
589 * @param argv command line
590 * @return 0 on success, -1 on error
596 static const struct GNUNET_GETOPT_CommandLineOption options[] = {
598 gettext_noop ("run autoconfiguration"),
599 GNUNET_NO, &GNUNET_GETOPT_set_one, &do_auto },
600 {'b', "bind", "ADDRESS",
601 gettext_noop ("which IP and port are we bound to"),
602 GNUNET_YES, &GNUNET_GETOPT_set_string, &bind_addr },
603 {'e', "external", "ADDRESS",
604 gettext_noop ("which external IP and port should be used to test"),
605 GNUNET_YES, &GNUNET_GETOPT_set_string, &extern_addr },
606 {'l', "local", "ADDRESS",
607 gettext_noop ("which IP and port are we locally using to listen to for connection reversals"),
608 GNUNET_YES, &GNUNET_GETOPT_set_string, &local_addr },
609 {'r', "remote", "ADDRESS",
610 gettext_noop ("which remote IP and port should be asked for connection reversal"),
611 GNUNET_YES, &GNUNET_GETOPT_set_string, &remote_addr },
612 {'L', "listen", NULL,
613 gettext_noop ("listen for connection reversal requests"),
614 GNUNET_NO, &GNUNET_GETOPT_set_one, &listen_reversal },
616 gettext_noop ("port to use to advertise"),
617 GNUNET_YES, &GNUNET_GETOPT_set_uint, &adv_port },
619 gettext_noop ("enable STUN processing"),
620 GNUNET_NO, &GNUNET_GETOPT_set_one, &do_stun },
622 gettext_noop ("use TCP"),
623 GNUNET_NO, &GNUNET_GETOPT_set_one, &use_tcp },
625 gettext_noop ("use UDP"),
626 GNUNET_NO, &GNUNET_GETOPT_set_one, &use_udp },
627 GNUNET_GETOPT_OPTION_END
631 GNUNET_STRINGS_get_utf8_args (argc, argv,
635 GNUNET_PROGRAM_run (argc, argv,
636 "gnunet-nat [options]",
637 _("GNUnet NAT traversal autoconfigure daemon"),
644 GNUNET_free ((void*) argv);
649 /* end of gnunet-nat.c */