fix free of statically allocated value
[oweals/gnunet.git] / src / nat / gnunet-nat.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2015, 2016 GNUnet e.V.
4
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.
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      General Public License for more details.
14
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.
19 */
20
21 /**
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
26  */
27 #include "platform.h"
28 #include "gnunet_util_lib.h"
29 #include "gnunet_nat_service.h"
30
31 /**
32  * Value to return from #main().
33  */
34 static int global_ret;
35
36 /**
37  * Name of section in configuration file to use for 
38  * additional options.
39  */ 
40 static char *section_name;
41
42 /**
43  * Flag set to 1 if we use IPPROTO_UDP.
44  */
45 static int use_udp;
46
47 /**
48  * Flag set to 1 if we are to listen for connection reversal requests.
49  */
50 static int listen_reversal;
51
52 /**
53  * Flag set to 1 if we use IPPROTO_TCP.
54  */
55 static int use_tcp;
56
57 /**
58  * Protocol to use.
59  */
60 static uint8_t proto;
61
62 /**
63  * Local address to use for connection reversal request.
64  */
65 static char *local_addr;
66
67 /**
68  * Remote address to use for connection reversal request.
69  */
70 static char *remote_addr;
71
72 /**
73  * Should we actually bind to #bind_addr and receive and process STUN requests?
74  */
75 static unsigned int do_stun;
76
77 /**
78  * Handle to NAT operation.
79  */
80 static struct GNUNET_NAT_Handle *nh;
81
82 /**
83  * Listen socket for STUN processing.
84  */ 
85 static struct GNUNET_NETWORK_Handle *ls;
86
87 /**
88  * Task for reading STUN packets.
89  */
90 static struct GNUNET_SCHEDULER_Task *rtask;
91
92
93 /**
94  * Test if all activities have finished, and if so,
95  * terminate.
96  */
97 static void
98 test_finished ()
99 {
100   if (NULL != nh)
101     return;
102   if (NULL != rtask)
103     return;
104   GNUNET_SCHEDULER_shutdown ();
105 }
106
107
108 /**
109  * Signature of the callback passed to #GNUNET_NAT_register() for
110  * a function to call whenever our set of 'valid' addresses changes.
111  *
112  * @param cls closure, NULL
113  * @param add_remove #GNUNET_YES to add a new public IP address, 
114  *                   #GNUNET_NO to remove a previous (now invalid) one
115  * @param ac address class the address belongs to
116  * @param addr either the previous or the new public IP address
117  * @param addrlen actual length of the @a addr
118  */
119 static void
120 address_cb (void *cls,
121             int add_remove,
122             enum GNUNET_NAT_AddressClass ac,
123             const struct sockaddr *addr,
124             socklen_t addrlen)
125 {
126   GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
127               "%s %s (%d)\n",
128               add_remove ? "+" : "-",
129               GNUNET_a2s (addr,
130                           addrlen),
131               (int) ac);
132 }
133
134
135 /**
136  * Signature of the callback passed to #GNUNET_NAT_register().
137  * for a function to call whenever someone asks us to do connection
138  * reversal.
139  *
140  * @param cls closure, NULL
141  * @param remote_addr public IP address of the other peer
142  * @param remote_addrlen actual length of the @a remote_addr
143  */
144 static void
145 reversal_cb (void *cls,
146              const struct sockaddr *remote_addr,
147              socklen_t remote_addrlen)
148 {
149   GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
150               "Connection reversal requested by %s\n",
151               GNUNET_a2s (remote_addr,
152                           remote_addrlen));
153 }
154
155
156 /**
157  * Task run on shutdown.
158  *
159  * @param cls NULL
160  */
161 static void
162 do_shutdown (void *cls)
163 {
164   if (NULL != nh)
165   {
166     GNUNET_NAT_unregister (nh);
167     nh = NULL;
168   }
169   if (NULL != ls)
170   {
171     GNUNET_NETWORK_socket_close (ls);
172     ls = NULL;
173   }
174   if (NULL != rtask)
175   {
176     GNUNET_SCHEDULER_cancel (rtask);
177     rtask = NULL;
178   }
179 }
180
181
182 /**
183  * Task to receive incoming packets for STUN processing.
184  */
185 static void
186 stun_read_task (void *cls)
187 {
188   ssize_t size;
189   
190   rtask = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
191                                          ls,
192                                          &stun_read_task,
193                                          NULL);
194   size = GNUNET_NETWORK_socket_recvfrom_amount (ls);
195   if (size > 0)
196   {
197     GNUNET_break (0);
198     GNUNET_SCHEDULER_shutdown ();
199     global_ret = 1;
200     return;
201   }
202   {
203     char buf[size + 1];
204     struct sockaddr_storage sa;
205     socklen_t salen = sizeof (sa);
206     ssize_t ret;
207     
208     ret = GNUNET_NETWORK_socket_recvfrom (ls,
209                                           buf,
210                                           size + 1,
211                                           (struct sockaddr *) &sa,
212                                           &salen);
213     if (ret != size)
214     {
215       GNUNET_break (0);
216       GNUNET_SCHEDULER_shutdown ();
217       global_ret = 1;
218       return;
219     }
220     (void) GNUNET_NAT_stun_handle_packet (nh,
221                                           (const struct sockaddr *) &sa,
222                                           salen,
223                                           buf,
224                                           ret);
225   }
226 }
227
228
229 /**
230  * Main function that will be run.
231  *
232  * @param cls closure
233  * @param args remaining command-line arguments
234  * @param cfgfile name of the configuration file used (for saving, can be NULL!)
235  * @param c configuration
236  */
237 static void
238 run (void *cls,
239      char *const *args,
240      const char *cfgfile,
241      const struct GNUNET_CONFIGURATION_Handle *c)
242 {
243   uint8_t af;
244   struct sockaddr *local_sa;
245   struct sockaddr *remote_sa;
246   socklen_t local_len;
247   size_t remote_len;
248
249   if (use_tcp && use_udp)
250   {
251     GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
252                 "Cannot use TCP and UDP\n");
253     global_ret = 1;
254     return;
255   }
256   proto = 0;
257   if (use_tcp)
258     proto = IPPROTO_TCP;
259   if (use_udp)
260     proto = IPPROTO_UDP;
261
262   GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
263                                  NULL);
264
265   if (0 == proto)
266   {
267     GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
268                 "Must specify either TCP or UDP\n");
269     global_ret = 1;
270     return;
271   }
272   if (NULL != local_addr)
273   {
274     local_len = (socklen_t) GNUNET_STRINGS_parse_socket_addr (local_addr,
275                                                               &af,
276                                                               &local_sa);
277     if (0 == local_len)
278     {
279       GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
280                   "Invalid socket address `%s'\n",
281                   local_addr);
282       global_ret = 1;
283       return;
284     }
285   }
286   if (NULL != remote_addr)
287   {
288     remote_len = GNUNET_STRINGS_parse_socket_addr (remote_addr,
289                                                    &af,
290                                                    &remote_sa);
291     if (0 == remote_len)
292     {
293       GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
294                   "Invalid socket address `%s'\n",
295                   remote_addr);
296       global_ret = 1;
297       return;
298     }
299   }
300
301   if (NULL != local_addr)
302   {
303     if (NULL == section_name)
304       section_name = GNUNET_strdup ("undefined");
305     nh = GNUNET_NAT_register (c,
306                               section_name,
307                               proto,
308                               1,
309                               (const struct sockaddr **) &local_sa,
310                               &local_len,
311                               &address_cb,
312                               (listen_reversal) ? &reversal_cb : NULL,
313                               NULL);
314   }
315   else if (listen_reversal)
316   {
317     GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
318                 "Use of `-W` only effective in combination with `-i`\n");    
319     global_ret = 1;
320     GNUNET_SCHEDULER_shutdown ();
321     return;
322   }
323
324   if (NULL != remote_addr)
325   {
326     int ret;
327     
328     if ( (NULL == nh) ||
329          (sizeof (struct sockaddr_in) != local_len) )
330     {
331       GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
332                   "Require IPv4 local address to initiate connection reversal\n");
333       global_ret = 1;
334       GNUNET_SCHEDULER_shutdown ();
335       return;
336     }
337     if (sizeof (struct sockaddr_in) != remote_len)
338     {
339       GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
340                   "Require IPv4 reversal target address\n");
341       global_ret = 1;
342       GNUNET_SCHEDULER_shutdown ();
343       return;
344     }
345     GNUNET_assert (AF_INET == local_sa->sa_family);
346     GNUNET_assert (AF_INET == remote_sa->sa_family);
347     ret = GNUNET_NAT_request_reversal (nh,
348                                        (const struct sockaddr_in *) local_sa,
349                                        (const struct sockaddr_in *) remote_sa);
350     switch (ret)
351     {
352     case GNUNET_SYSERR:
353       GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
354                   "Connection reversal internal error\n");
355       break;
356     case GNUNET_NO:
357       GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
358                   "Connection reversal unavailable\n");
359       break;
360     case GNUNET_OK:
361       /* operation in progress */
362       break;
363     }
364   }
365   
366   if (do_stun)
367   {
368     if (NULL == local_addr)
369     {
370       GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
371                   "Require local address to support STUN requests\n");
372       global_ret = 1;
373       GNUNET_SCHEDULER_shutdown ();
374       return;
375     }
376     if (IPPROTO_UDP != proto)
377     {
378       GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
379                   "STUN only supported over UDP\n");
380       global_ret = 1;
381       GNUNET_SCHEDULER_shutdown ();
382       return;
383     }
384     ls = GNUNET_NETWORK_socket_create (af,
385                                        SOCK_DGRAM,
386                                        IPPROTO_UDP);
387     if (GNUNET_OK !=
388         GNUNET_NETWORK_socket_bind (ls,
389                                     local_sa,
390                                     local_len))
391     {
392       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
393                   "Failed to bind to %s: %s\n",
394                   GNUNET_a2s (local_sa,
395                               local_len),
396                   STRERROR (errno));
397       global_ret = 1;
398       GNUNET_SCHEDULER_shutdown ();
399       return;
400     }
401     rtask = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
402                                            ls,
403                                            &stun_read_task,
404                                            NULL);
405   }
406
407   test_finished ();
408 }
409
410
411 /**
412  * Main function of gnunet-nat
413  *
414  * @param argc number of command-line arguments
415  * @param argv command line
416  * @return 0 on success, -1 on error
417  */
418 int
419 main (int argc,
420       char *const argv[])
421 {
422   static const struct GNUNET_GETOPT_CommandLineOption options[] = {
423     {'i', "in", "ADDRESS",
424      gettext_noop ("which IP and port are we locally using to bind/listen to"),
425      GNUNET_YES, &GNUNET_GETOPT_set_string, &local_addr },
426     {'r', "remote", "ADDRESS",
427      gettext_noop ("which remote IP and port should be asked for connection reversal"),
428      GNUNET_YES, &GNUNET_GETOPT_set_string, &remote_addr },
429     {'S', "section", NULL,
430      gettext_noop ("name of configuration section to find additional options, such as manual host punching data"),
431      GNUNET_YES, &GNUNET_GETOPT_set_string, &section_name },
432     {'s', "stun", NULL,
433      gettext_noop ("enable STUN processing"),
434      GNUNET_NO, &GNUNET_GETOPT_set_one, &do_stun },
435     {'t', "tcp", NULL,
436      gettext_noop ("use TCP"),
437      GNUNET_NO, &GNUNET_GETOPT_set_one, &use_tcp },
438     {'u', "udp", NULL,
439      gettext_noop ("use UDP"),
440      GNUNET_NO, &GNUNET_GETOPT_set_one, &use_udp },
441     {'W', "watch", NULL,
442      gettext_noop ("watch for connection reversal requests"),
443      GNUNET_NO, &GNUNET_GETOPT_set_one, &listen_reversal },
444    GNUNET_GETOPT_OPTION_END
445   };
446
447   if (GNUNET_OK !=
448       GNUNET_STRINGS_get_utf8_args (argc, argv,
449                                     &argc, &argv))
450     return 2;
451   if (GNUNET_OK !=
452       GNUNET_PROGRAM_run (argc, argv,
453                           "gnunet-nat [options]",
454                           _("GNUnet NAT traversal autoconfigure daemon"),
455                           options,
456                           &run,
457                           NULL))
458   {
459     global_ret = 1;
460   }
461   GNUNET_free ((void*) argv);
462   return global_ret;
463 }
464
465
466 /* end of gnunet-nat.c */