2 This file is part of GNUnet.
3 Copyright (C) 2009, 2010, 2011, 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 nat/gnunet-service-nat_helper.c
23 * @brief runs the gnunet-helper-nat-server
24 * @author Milan Bouchet-Valat
25 * @author Christian Grothoff
28 #include "gnunet_util_lib.h"
29 #include "gnunet-service-nat_helper.h"
31 #define LOG(kind,...) GNUNET_log_from (kind, "nat", __VA_ARGS__)
34 * Information we keep per NAT helper process.
40 * IP address we pass to the NAT helper.
42 struct in_addr internal_address;
45 * Function to call if we receive a reversal request.
47 GN_ReversalCallback cb;
55 * How long do we wait for restarting a crashed gnunet-helper-nat-server?
57 struct GNUNET_TIME_Relative server_retry_delay;
60 * ID of select gnunet-helper-nat-server stdout read task
62 struct GNUNET_SCHEDULER_Task *server_read_task;
65 * The process id of the server process (if behind NAT)
67 struct GNUNET_OS_Process *server_proc;
70 * stdout pipe handle for the gnunet-helper-nat-server process
72 struct GNUNET_DISK_PipeHandle *server_stdout;
75 * stdout file handle (for reading) for the gnunet-helper-nat-server process
77 const struct GNUNET_DISK_FileHandle *server_stdout_handle;
82 * Task that restarts the gnunet-helper-nat-server process after a crash
83 * after a certain delay.
85 * @param cls a `struct HelperContext`
88 restart_nat_server (void *cls);
92 * Try again starting the helper later
94 * @param h context of the helper
97 try_again (struct HelperContext *h)
99 GNUNET_assert (NULL == h->server_read_task);
100 h->server_retry_delay
101 = GNUNET_TIME_STD_BACKOFF (h->server_retry_delay);
103 = GNUNET_SCHEDULER_add_delayed (h->server_retry_delay,
110 * We have been notified that gnunet-helper-nat-server has written
111 * something to stdout. Handle the output, then reschedule this
112 * function to be called again once more is available.
114 * @param cls the `struct HelperContext`
117 nat_server_read (void *cls)
119 struct HelperContext *h = cls;
123 const char *port_start;
124 struct sockaddr_in sin_addr;
126 h->server_read_task = NULL;
131 = GNUNET_DISK_file_read (h->server_stdout_handle,
136 LOG (GNUNET_ERROR_TYPE_DEBUG,
137 "Finished reading from server stdout with code: %d\n",
139 if (0 != GNUNET_OS_process_kill (h->server_proc,
141 GNUNET_log_from_strerror (GNUNET_ERROR_TYPE_WARNING,
144 GNUNET_OS_process_wait (h->server_proc);
145 GNUNET_OS_process_destroy (h->server_proc);
146 h->server_proc = NULL;
147 GNUNET_DISK_pipe_close (h->server_stdout);
148 h->server_stdout = NULL;
149 h->server_stdout_handle = NULL;
155 for (size_t i = 0; i < sizeof (mybuf); i++)
157 if (mybuf[i] == '\n')
162 if ((mybuf[i] == ':') && (i + 1 < sizeof (mybuf)))
165 port_start = &mybuf[i + 1];
169 /* construct socket address of sender */
173 sin_addr.sin_family = AF_INET;
174 #if HAVE_SOCKADDR_IN_SIN_LEN
175 sin_addr.sin_len = sizeof (sin_addr);
177 if ( (NULL == port_start) ||
178 (1 != SSCANF (port_start,
181 (-1 == inet_pton (AF_INET,
183 &sin_addr.sin_addr)))
185 /* should we restart gnunet-helper-nat-server? */
186 LOG (GNUNET_ERROR_TYPE_WARNING,
188 _("gnunet-helper-nat-server generated malformed address `%s'\n"),
191 = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
192 h->server_stdout_handle,
197 sin_addr.sin_port = htons ((uint16_t) port);
198 LOG (GNUNET_ERROR_TYPE_DEBUG,
199 "gnunet-helper-nat-server read: %s:%d\n",
205 = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
206 h->server_stdout_handle,
213 * Task that restarts the gnunet-helper-nat-server process after a crash
214 * after a certain delay.
216 * @param cls a `struct HelperContext`
219 restart_nat_server (void *cls)
221 struct HelperContext *h = cls;
223 char ia[INET_ADDRSTRLEN];
225 h->server_read_task = NULL;
227 = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_YES,
228 GNUNET_NO, GNUNET_YES);
229 if (NULL == h->server_stdout)
231 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
236 GNUNET_assert (NULL !=
238 &h->internal_address,
241 LOG (GNUNET_ERROR_TYPE_DEBUG,
242 "Starting `%s' at `%s'\n",
243 "gnunet-helper-nat-server",
245 /* Start the server process */
247 = GNUNET_OS_get_libexec_binary_path ("gnunet-helper-nat-server");
249 = GNUNET_OS_start_process (GNUNET_NO,
255 "gnunet-helper-nat-server",
258 GNUNET_free (binary);
259 if (NULL == h->server_proc)
261 LOG (GNUNET_ERROR_TYPE_WARNING,
263 _("Failed to start %s\n"),
264 "gnunet-helper-nat-server");
265 GNUNET_DISK_pipe_close (h->server_stdout);
266 h->server_stdout = NULL;
270 /* Close the write end of the read pipe */
271 GNUNET_DISK_pipe_close_end (h->server_stdout,
272 GNUNET_DISK_PIPE_END_WRITE);
273 h->server_stdout_handle
274 = GNUNET_DISK_pipe_handle (h->server_stdout,
275 GNUNET_DISK_PIPE_END_READ);
277 = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
278 h->server_stdout_handle,
285 * Start the gnunet-helper-nat-server and process incoming
288 * @param internal_address
289 * @param cb function to call if we receive a request
290 * @param cb_cls closure for @a cb
291 * @return NULL on error
293 struct HelperContext *
294 GN_start_gnunet_nat_server_ (const struct in_addr *internal_address,
295 GN_ReversalCallback cb,
298 struct HelperContext *h;
300 h = GNUNET_new (struct HelperContext);
303 h->internal_address = *internal_address;
304 if (NULL == h->server_stdout)
306 GN_stop_gnunet_nat_server_ (h);
314 * Start the gnunet-helper-nat-server and process incoming
317 * @param h helper context to stop
320 GN_stop_gnunet_nat_server_ (struct HelperContext *h)
322 if (NULL != h->server_read_task)
324 GNUNET_SCHEDULER_cancel (h->server_read_task);
325 h->server_read_task = NULL;
327 if (NULL != h->server_proc)
329 if (0 != GNUNET_OS_process_kill (h->server_proc,
331 GNUNET_log_from_strerror (GNUNET_ERROR_TYPE_WARNING,
334 GNUNET_OS_process_wait (h->server_proc);
335 GNUNET_OS_process_destroy (h->server_proc);
336 h->server_proc = NULL;
337 GNUNET_DISK_pipe_close (h->server_stdout);
338 h->server_stdout = NULL;
339 h->server_stdout_handle = NULL;
341 if (NULL != h->server_stdout)
343 GNUNET_DISK_pipe_close (h->server_stdout);
344 h->server_stdout = NULL;
345 h->server_stdout_handle = NULL;
352 * We want to connect to a peer that is behind NAT. Run the
353 * gnunet-helper-nat-client to send dummy ICMP responses to cause
354 * that peer to connect to us (connection reversal).
356 * @param internal_address out internal address to use
357 * @param internal_port port to use
358 * @param remote_v4 the address of the peer (IPv4-only)
359 * @return #GNUNET_SYSERR on error,
360 * #GNUNET_OK otherwise
363 GN_request_connection_reversal (const struct in_addr *internal_address,
364 uint16_t internal_port,
365 const struct in_addr *remote_v4)
367 char intv4[INET_ADDRSTRLEN];
368 char remv4[INET_ADDRSTRLEN];
369 char port_as_string[6];
370 struct GNUNET_OS_Process *proc;
373 if (NULL == inet_ntop (AF_INET,
378 GNUNET_log_from_strerror (GNUNET_ERROR_TYPE_WARNING,
381 return GNUNET_SYSERR;
383 if (NULL == inet_ntop (AF_INET,
388 GNUNET_log_from_strerror (GNUNET_ERROR_TYPE_WARNING,
391 return GNUNET_SYSERR;
393 GNUNET_snprintf (port_as_string,
394 sizeof (port_as_string),
397 LOG (GNUNET_ERROR_TYPE_DEBUG,
398 _("Running gnunet-helper-nat-client %s %s %u\n"),
403 = GNUNET_OS_get_libexec_binary_path ("gnunet-helper-nat-client");
405 = GNUNET_OS_start_process (GNUNET_NO,
411 "gnunet-helper-nat-client",
416 GNUNET_free (binary);
418 return GNUNET_SYSERR;
419 /* we know that the gnunet-helper-nat-client will terminate virtually
421 GNUNET_OS_process_wait (proc);
422 GNUNET_OS_process_destroy (proc);
427 /* end of gnunet-service-nat_helper.c */