GNUnet  0.10.x
gnunet-service-nat_helper.c
Go to the documentation of this file.
1 /*
2  This file is part of GNUnet.
3  Copyright (C) 2009, 2010, 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 */
20 
27 #include "platform.h"
28 #include "gnunet_util_lib.h"
30 
31 
36 {
37 
41  struct in_addr internal_address;
42 
47 
51  void *cb_cls;
52 
57 
62 
67 
72 
77 
82 };
83 
84 
91 static void
92 restart_nat_server (void *cls);
93 
94 
100 static void
102 {
103  GNUNET_assert (NULL == h->server_read_task);
109  h);
110 }
111 
112 
120 static void
121 nat_server_read (void *cls)
122 {
123  struct HelperContext *h = cls;
124  char mybuf[40];
125  ssize_t bytes;
126  int port;
127  const char *port_start;
128  struct sockaddr_in sin_addr;
129 
130  h->server_read_task = NULL;
131  memset (mybuf,
132  0,
133  sizeof (mybuf));
134  bytes
136  mybuf,
137  sizeof (mybuf));
138  if (bytes < 1)
139  {
141  "Finished reading from server stdout with code: %d\n",
142  (int) bytes);
143  if (0 != GNUNET_OS_process_kill (h->server_proc,
146  "nat",
147  "kill");
150  h->server_proc = NULL;
152  h->server_stdout = NULL;
153  h->server_stdout_handle = NULL;
154  try_again (h);
155  return;
156  }
157 
158  port_start = NULL;
159  for (size_t i = 0; i < sizeof (mybuf); i++)
160  {
161  if (mybuf[i] == '\n')
162  {
163  mybuf[i] = '\0';
164  break;
165  }
166  if ((mybuf[i] == ':') && (i + 1 < sizeof (mybuf)))
167  {
168  mybuf[i] = '\0';
169  port_start = &mybuf[i + 1];
170  }
171  }
172 
173  /* construct socket address of sender */
174  memset (&sin_addr,
175  0,
176  sizeof (sin_addr));
177  sin_addr.sin_family = AF_INET;
178 #if HAVE_SOCKADDR_IN_SIN_LEN
179  sin_addr.sin_len = sizeof (sin_addr);
180 #endif
181  if ( (NULL == port_start) ||
182  (1 != SSCANF (port_start,
183  "%d",
184  &port)) ||
185  (-1 == inet_pton (AF_INET,
186  mybuf,
187  &sin_addr.sin_addr)))
188  {
189  /* should we restart gnunet-helper-nat-server? */
191  _("gnunet-helper-nat-server generated malformed address `%s'\n"),
192  mybuf);
197  h);
198  return;
199  }
200  sin_addr.sin_port = htons ((uint16_t) port);
202  "gnunet-helper-nat-server read: %s:%d\n",
203  mybuf,
204  port);
205  h->cb (h->cb_cls,
206  &sin_addr);
211  h);
212 }
213 
214 
221 static void
223 {
224  struct HelperContext *h = cls;
225  char *binary;
226  char ia[INET_ADDRSTRLEN];
227 
228  h->server_read_task = NULL;
229  GNUNET_assert (NULL !=
230  inet_ntop (AF_INET,
231  &h->internal_address,
232  ia,
233  sizeof (ia)));
234  /* Start the server process */
235  binary = GNUNET_OS_get_suid_binary_path (h->cfg, "gnunet-helper-nat-server");
236  if (GNUNET_YES !=
238  GNUNET_YES,
239  ia))
240  {
241  /* move instantly to max delay, as this is unlikely to be fixed */
244  GNUNET_free (binary);
245  try_again (h);
246  return;
247  }
248  h->server_stdout
251  if (NULL == h->server_stdout)
252  {
254  "pipe");
255  GNUNET_free (binary);
256  try_again (h);
257  return;
258  }
260  "Starting `%s' at `%s'\n",
261  "gnunet-helper-nat-server",
262  ia);
263  h->server_proc
265  0,
266  NULL,
267  h->server_stdout,
268  NULL,
269  binary,
270  "gnunet-helper-nat-server",
271  ia,
272  NULL);
273  GNUNET_free (binary);
274  if (NULL == h->server_proc)
275  {
277  _("Failed to start %s\n"),
278  "gnunet-helper-nat-server");
280  h->server_stdout = NULL;
281  try_again (h);
282  return;
283  }
284  /* Close the write end of the read pipe */
294  h);
295 }
296 
297 
308 struct HelperContext *
311  void *cb_cls,
312  const struct GNUNET_CONFIGURATION_Handle *cfg)
313 {
314  struct HelperContext *h;
315 
316  h = GNUNET_new (struct HelperContext);
317  h->cb = cb;
318  h->cb_cls = cb_cls;
320  h->cfg = cfg;
321  restart_nat_server (h);
322  if (NULL == h->server_stdout)
323  {
325  return NULL;
326  }
327  return h;
328 }
329 
330 
337 void
339 {
340  if (NULL != h->server_read_task)
341  {
343  h->server_read_task = NULL;
344  }
345  if (NULL != h->server_proc)
346  {
347  if (0 != GNUNET_OS_process_kill (h->server_proc,
350  "kill");
353  h->server_proc = NULL;
355  h->server_stdout = NULL;
356  h->server_stdout_handle = NULL;
357  }
358  if (NULL != h->server_stdout)
359  {
361  h->server_stdout = NULL;
362  h->server_stdout_handle = NULL;
363  }
364  GNUNET_free (h);
365 }
366 
367 
380 int
382  uint16_t internal_port,
383  const struct in_addr *remote_v4,
384  const struct GNUNET_CONFIGURATION_Handle *cfg)
385 {
386  char intv4[INET_ADDRSTRLEN];
387  char remv4[INET_ADDRSTRLEN];
388  char port_as_string[6];
389  struct GNUNET_OS_Process *proc;
390  char *binary;
391 
392  if (NULL == inet_ntop (AF_INET,
393  internal_address,
394  intv4,
395  INET_ADDRSTRLEN))
396  {
398  "inet_ntop");
399  return GNUNET_SYSERR;
400  }
401  if (NULL == inet_ntop (AF_INET,
402  remote_v4,
403  remv4,
404  INET_ADDRSTRLEN))
405  {
407  "inet_ntop");
408  return GNUNET_SYSERR;
409  }
410  GNUNET_snprintf (port_as_string,
411  sizeof (port_as_string),
412  "%d",
413  internal_port);
415  "Running gnunet-helper-nat-client %s %s %u\n",
416  intv4,
417  remv4,
418  internal_port);
419  binary = GNUNET_OS_get_suid_binary_path (cfg, "gnunet-helper-nat-client");
420  proc
422  0,
423  NULL,
424  NULL,
425  NULL,
426  binary,
427  "gnunet-helper-nat-client",
428  intv4,
429  remv4,
430  port_as_string,
431  NULL);
432  GNUNET_free (binary);
433  if (NULL == proc)
434  return GNUNET_SYSERR;
435  /* we know that the gnunet-helper-nat-client will terminate virtually
436  * instantly */
437  GNUNET_OS_process_wait (proc);
439  return GNUNET_OK;
440 }
441 
442 
443 /* end of gnunet-service-nat_helper.c */
struct GNUNET_OS_Process * server_proc
The process id of the server process (if behind NAT)
GN_ReversalCallback cb
Function to call if we receive a reversal request.
static void try_again(struct HelperContext *h)
Try again starting the helper later.
void GNUNET_OS_process_destroy(struct GNUNET_OS_Process *proc)
Cleans up process structure contents (OS-dependent) and deallocates it.
Definition: os_priority.c:364
#define GNUNET_log_from_strerror(level, component, cmd)
Log an error message at log-level &#39;level&#39; that indicates a failure of the command &#39;cmd&#39; with the mess...
int GNUNET_snprintf(char *buf, size_t size, const char *format,...)
Like snprintf, just aborts if the buffer is of insufficient size.
ssize_t GNUNET_DISK_file_read(const struct GNUNET_DISK_FileHandle *h, void *result, size_t len)
Read the contents of a binary file into a buffer.
Definition: disk.c:881
#define GNUNET_assert(cond)
Use this for fatal errors that cannot be handled.
struct GNUNET_OS_Process * GNUNET_OS_start_process(int pipe_control, enum GNUNET_OS_InheritStdioFlags std_inheritance, struct GNUNET_DISK_PipeHandle *pipe_stdin, struct GNUNET_DISK_PipeHandle *pipe_stdout, struct GNUNET_DISK_PipeHandle *pipe_stderr, const char *filename,...)
Start a process.
Definition: os_priority.c:1400
void GN_stop_gnunet_nat_server_(struct HelperContext *h)
Start the gnunet-helper-nat-server and process incoming requests.
#define GNUNET_NO
Definition: gnunet_common.h:81
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_read_file(struct GNUNET_TIME_Relative delay, const struct GNUNET_DISK_FileHandle *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:1643
#define GNUNET_OK
Named constants for return values.
Definition: gnunet_common.h:78
int GNUNET_OS_check_helper_binary(const char *binary, int check_suid, const char *params)
Check whether an executable exists and possibly if the suid bit is set on the file.
#define GNUNET_new(type)
Allocate a struct or union of the given type.
struct GNUNET_TIME_Relative server_retry_delay
How long do we wait for restarting a crashed gnunet-helper-nat-server?
runs the gnunet-helper-nat-server
const struct GNUNET_DISK_FileHandle * GNUNET_DISK_pipe_handle(const struct GNUNET_DISK_PipeHandle *p, enum GNUNET_DISK_PipeEnd n)
Get the handle to a particular pipe end.
Definition: disk.c:2641
static struct GNUNET_ARM_Handle * h
Connection with ARM.
Definition: gnunet-arm.c:94
struct GNUNET_SCHEDULER_Task * server_read_task
ID of select gnunet-helper-nat-server stdout read task.
#define _(String)
GNU gettext support macro.
Definition: platform.h:208
#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 * GNUNET_SCHEDULER_add_delayed(struct GNUNET_TIME_Relative delay, GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run with a specified delay.
Definition: scheduler.c:1246
#define GNUNET_TIME_STD_EXPONENTIAL_BACKOFF_THRESHOLD
Threshold after which exponential backoff should not increase (15 m).
char * GNUNET_OS_get_suid_binary_path(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *progname)
Given the name of a helper, service or daemon binary construct the full path to the binary using the ...
#define GNUNET_TIME_UNIT_FOREVER_REL
Constant used to specify "forever".
The writing-end of a pipe.
The reading-end of a pipe.
struct GNUNET_DISK_PipeHandle * GNUNET_DISK_pipe(int blocking_read, int blocking_write, int inherit_read, int inherit_write)
Creates an interprocess channel.
Definition: disk.c:2289
struct GNUNET_DISK_PipeHandle * server_stdout
stdout pipe handle for the gnunet-helper-nat-server process
#define GNUNET_SYSERR
Definition: gnunet_common.h:79
static void restart_nat_server(void *cls)
Task that restarts the gnunet-helper-nat-server process after a crash after a certain delay...
#define GNUNET_TIME_STD_BACKOFF(r)
Perform our standard exponential back-off calculation, starting at 1 ms and then going by a factor of...
int GNUNET_DISK_pipe_close(struct GNUNET_DISK_PipeHandle *p)
Closes an interprocess channel.
Definition: disk.c:2603
struct in_addr internal_address
IP address we pass to the NAT helper.
int GNUNET_DISK_pipe_close_end(struct GNUNET_DISK_PipeHandle *p, enum GNUNET_DISK_PipeEnd end)
Closes one half of an interprocess channel.
Definition: disk.c:2532
int GN_request_connection_reversal(const struct in_addr *internal_address, uint16_t internal_port, const struct in_addr *remote_v4, const struct GNUNET_CONFIGURATION_Handle *cfg)
We want to connect to a peer that is behind NAT.
static void nat_server_read(void *cls)
We have been notified that gnunet-helper-nat-server has written something to stdout.
int GNUNET_OS_process_wait(struct GNUNET_OS_Process *proc)
Wait for a process to terminate.
Definition: os_priority.c:1762
#define SSCANF
Definition: plibc.h:691
static uint16_t port
Port number.
Definition: gnunet-bcd.c:79
configuration data
Definition: configuration.c:85
void * cb_cls
Closure for cb.
static int inet_pton(int af, const char *cp, struct in_addr *buf)
Convert IPv4 address from text to binary form.
#define GNUNET_log(kind,...)
Entry in list of pending tasks.
Definition: scheduler.c:134
void(* GN_ReversalCallback)(void *cls, const struct sockaddr_in *ra)
Function called whenever we get a connection reversal request from another peer.
#define GNUNET_YES
Definition: gnunet_common.h:80
const struct GNUNET_DISK_FileHandle * server_stdout_handle
stdout file handle (for reading) for the gnunet-helper-nat-server process
#define GNUNET_TERM_SIG
The termination signal.
Definition: platform.h:282
Information we keep per NAT helper process.
Handle used to access files (and pipes).
Handle used to manage a pipe.
Definition: disk.c:66
const struct GNUNET_CONFIGURATION_Handle * cfg
Handle to the GNUnet configuration.
struct HelperContext * GN_start_gnunet_nat_server_(const struct in_addr *internal_address, GN_ReversalCallback cb, void *cb_cls, const struct GNUNET_CONFIGURATION_Handle *cfg)
Start the gnunet-helper-nat-server and process incoming requests.
#define GNUNET_free(ptr)
Wrapper around free.
Time for relative time used by GNUnet, in microseconds.
int GNUNET_OS_process_kill(struct GNUNET_OS_Process *proc, int sig)
Sends a signal to the process.
Definition: os_priority.c:251
void * GNUNET_SCHEDULER_cancel(struct GNUNET_SCHEDULER_Task *task)
Cancel the task with the specified identifier.
Definition: scheduler.c:965