GNUnet 0.26.2-113-ged4734898
 
Loading...
Searching...
No Matches
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
82
83
90static void
91restart_nat_server (void *cls);
92
93
99static void
101{
102 GNUNET_assert (NULL == h->server_read_task);
103 h->server_retry_delay = GNUNET_TIME_STD_BACKOFF (h->server_retry_delay);
104 h->server_read_task = GNUNET_SCHEDULER_add_delayed (h->server_retry_delay,
106 h);
107}
108
109
117static void
119{
120 struct HelperContext *h = cls;
121 char mybuf[40];
122 ssize_t bytes;
123 int port;
124 const char *port_start;
125 struct sockaddr_in sin_addr;
126
127 h->server_read_task = NULL;
128 memset (mybuf, 0, sizeof(mybuf));
129 bytes =
130 GNUNET_DISK_file_read (h->server_stdout_handle, mybuf, sizeof(mybuf));
131 if (bytes < 1)
132 {
134 "Finished reading from server stdout with code: %d\n",
135 (int) bytes);
136 if (GNUNET_OK !=
137 GNUNET_process_kill (h->server_proc,
140 "nat",
141 "kill");
142 GNUNET_process_wait (h->server_proc,
143 true,
144 NULL,
145 NULL);
146 GNUNET_process_destroy (h->server_proc);
147 h->server_proc = NULL;
148 GNUNET_DISK_pipe_close (h->server_stdout);
149 h->server_stdout = NULL;
150 h->server_stdout_handle = NULL;
151 try_again (h);
152 return;
153 }
154
155 port_start = NULL;
156 for (size_t i = 0; i < sizeof(mybuf); i++)
157 {
158 if (mybuf[i] == '\n')
159 {
160 mybuf[i] = '\0';
161 break;
162 }
163 if ((mybuf[i] == ':') && (i + 1 < sizeof(mybuf)))
164 {
165 mybuf[i] = '\0';
166 port_start = &mybuf[i + 1];
167 }
168 }
169
170 /* construct socket address of sender */
171 memset (&sin_addr, 0, sizeof(sin_addr));
172 sin_addr.sin_family = AF_INET;
173#if HAVE_SOCKADDR_IN_SIN_LEN
174 sin_addr.sin_len = sizeof(sin_addr);
175#endif
176 if ((NULL == port_start) || (1 != sscanf (port_start, "%d", &port)) ||
177 (-1 == inet_pton (AF_INET, mybuf, &sin_addr.sin_addr)))
178 {
179 /* should we restart gnunet-helper-nat-server? */
181 _ (
182 "gnunet-helper-nat-server generated malformed address `%s'\n")
183 ,
184 mybuf);
185 h->server_read_task =
187 h->server_stdout_handle,
189 h);
190 return;
191 }
192 sin_addr.sin_port = htons ((uint16_t) port);
194 "gnunet-helper-nat-server read: %s:%d\n",
195 mybuf,
196 port);
197 h->cb (h->cb_cls, &sin_addr);
198 h->server_read_task =
200 h->server_stdout_handle,
202 h);
203}
204
205
212static void
214{
215 struct HelperContext *h = cls;
216 char *binary;
217 char ia[INET_ADDRSTRLEN];
218
219 h->server_read_task = NULL;
220 GNUNET_assert (NULL !=
221 inet_ntop (AF_INET, &h->internal_address, ia, sizeof(ia)));
222 /* Start the server process */
224 h->cfg,
225 "gnunet-helper-nat-server");
226 if (GNUNET_YES !=
229 ia))
230 {
231 /* move instantly to max delay, as this is unlikely to be fixed */
233 GNUNET_free (binary);
234 try_again (h);
235 return;
236 }
237 h->server_stdout =
239 if (NULL == h->server_stdout)
240 {
242 GNUNET_free (binary);
243 try_again (h);
244 return;
245 }
247 "Starting `%s' at `%s'\n",
248 "gnunet-helper-nat-server",
249 ia);
253 h->server_proc,
255 STDOUT_FILENO)));
256 if (GNUNET_OK !=
257 GNUNET_process_run_command_va (h->server_proc,
258 binary,
259 "gnunet-helper-nat-server",
260 ia,
261 NULL))
262 {
263 GNUNET_process_destroy (h->server_proc);
264 h->server_proc = NULL;
265 GNUNET_free (binary);
267 _ ("Failed to start %s\n"),
268 "gnunet-helper-nat-server");
269 GNUNET_DISK_pipe_close (h->server_stdout);
270 h->server_stdout = NULL;
271 try_again (h);
272 return;
273 }
274 GNUNET_free (binary);
275 /* Close the write end of the read pipe */
276 GNUNET_DISK_pipe_close_end (h->server_stdout,
278 h->server_stdout_handle =
279 GNUNET_DISK_pipe_handle (h->server_stdout,
281 h->server_read_task =
283 h->server_stdout_handle,
285 h);
286}
287
288
289struct HelperContext *
292 void *cb_cls,
293 const struct GNUNET_CONFIGURATION_Handle *cfg)
294{
295 struct HelperContext *h;
296
297 h = GNUNET_new (struct HelperContext);
298 h->cb = cb;
299 h->cb_cls = cb_cls;
300 h->internal_address = *internal_address;
301 h->cfg = cfg;
303 if (NULL == h->server_stdout)
304 {
306 return NULL;
307 }
308 return h;
309}
310
311
318void
320{
321 if (NULL != h->server_read_task)
322 {
323 GNUNET_SCHEDULER_cancel (h->server_read_task);
324 h->server_read_task = NULL;
325 }
326 if (NULL != h->server_proc)
327 {
328 if (GNUNET_OK !=
329 GNUNET_process_kill (h->server_proc,
332 "kill");
334 GNUNET_process_wait (h->server_proc,
335 true,
336 NULL,
337 NULL));
338 GNUNET_process_destroy (h->server_proc);
339 h->server_proc = NULL;
340 GNUNET_DISK_pipe_close (h->server_stdout);
341 h->server_stdout = NULL;
342 h->server_stdout_handle = NULL;
343 }
344 if (NULL != h->server_stdout)
345 {
346 GNUNET_DISK_pipe_close (h->server_stdout);
347 h->server_stdout = NULL;
348 h->server_stdout_handle = NULL;
349 }
350 GNUNET_free (h);
351}
352
353
366int
368 uint16_t internal_port,
369 const struct in_addr *remote_v4,
370 const struct GNUNET_CONFIGURATION_Handle *cfg)
371{
372 char intv4[INET_ADDRSTRLEN];
373 char remv4[INET_ADDRSTRLEN];
374 char port_as_string[6];
375 struct GNUNET_Process *proc;
376 char *binary;
377
378 if (NULL == inet_ntop (AF_INET,
379 internal_address,
380 intv4,
381 INET_ADDRSTRLEN))
382 {
384 "inet_ntop");
385 return GNUNET_SYSERR;
386 }
387 if (NULL == inet_ntop (AF_INET,
388 remote_v4,
389 remv4,
390 INET_ADDRSTRLEN))
391 {
393 "inet_ntop");
394 return GNUNET_SYSERR;
395 }
396 GNUNET_snprintf (port_as_string,
397 sizeof(port_as_string),
398 "%d",
399 internal_port);
401 "Running gnunet-helper-nat-client %s %s %u\n",
402 intv4,
403 remv4,
404 internal_port);
406 cfg,
407 "gnunet-helper-nat-client");
409 if (GNUNET_OK !=
411 proc,
412 binary,
413 "gnunet-helper-nat-client",
414 intv4,
415 remv4,
416 port_as_string,
417 NULL))
418 {
420 GNUNET_free (binary);
421 return GNUNET_SYSERR;
422 }
423 GNUNET_free (binary);
424 /* we know that the gnunet-helper-nat-client will terminate virtually
425 * instantly */
428 true,
429 NULL,
430 NULL));
432 return GNUNET_OK;
433}
434
435
436/* end of gnunet-service-nat_helper.c */
static struct GNUNET_ARM_Handle * h
Connection with ARM.
Definition gnunet-arm.c:98
static struct GNUNET_CONFIGURATION_Handle * cfg
Our configuration.
Definition gnunet-arm.c:108
static uint16_t port
Port number.
Definition gnunet-bcd.c:146
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.
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.
static void nat_server_read(void *cls)
We have been notified that gnunet-helper-nat-server has written something to stdout.
void GN_stop_gnunet_nat_server_(struct HelperContext *h)
Start the gnunet-helper-nat-server and process incoming requests.
static void try_again(struct HelperContext *h)
Try again starting the helper later.
static void restart_nat_server(void *cls)
Task that restarts the gnunet-helper-nat-server process after a crash after a certain delay.
runs the gnunet-helper-nat-server
void(* GN_ReversalCallback)(void *cls, const struct sockaddr_in *ra)
Function called whenever we get a connection reversal request from another peer.
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:1703
struct GNUNET_DISK_PipeHandle * GNUNET_DISK_pipe(enum GNUNET_DISK_PipeFlags pf)
Creates an interprocess channel.
Definition disk.c:1524
enum GNUNET_GenericReturnValue GNUNET_DISK_pipe_close(struct GNUNET_DISK_PipeHandle *p)
Closes an interprocess channel.
Definition disk.c:1671
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:704
enum GNUNET_GenericReturnValue 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:1618
@ GNUNET_DISK_PF_BLOCKING_RW
Configure both pipe ends for blocking operations if set.
@ GNUNET_DISK_PIPE_END_WRITE
The writing-end of a pipe.
@ GNUNET_DISK_PIPE_END_READ
The reading-end of a pipe.
#define GNUNET_log(kind,...)
@ GNUNET_OK
@ GNUNET_YES
@ GNUNET_SYSERR
#define GNUNET_log_from_strerror(level, component, cmd)
Log an error message at log-level 'level' that indicates a failure of the command 'cmd' with the mess...
#define GNUNET_assert(cond)
Use this for fatal errors that cannot be handled.
#define GNUNET_break(cond)
Use this for internal assertion violations that are not fatal (can be handled) but should not occur.
#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_WARNING
@ GNUNET_ERROR_TYPE_ERROR
@ GNUNET_ERROR_TYPE_DEBUG
int GNUNET_snprintf(char *buf, size_t size, const char *format,...) __attribute__((format(printf
Like snprintf, just aborts if the buffer is of insufficient size.
#define GNUNET_new(type)
Allocate a struct or union of the given type.
#define GNUNET_free(ptr)
Wrapper around free.
const struct GNUNET_OS_ProjectData * GNUNET_OS_project_data_gnunet(void)
Return default project data used by 'libgnunetutil' for GNUnet.
enum GNUNET_GenericReturnValue GNUNET_process_run_command_va(struct GNUNET_Process *p, const char *filename,...)
Set the command and start a process.
Definition os_process.c:903
enum GNUNET_GenericReturnValue GNUNET_process_wait(struct GNUNET_Process *proc, bool blocking, enum GNUNET_OS_ProcessStatusType *type, unsigned long *code)
Wait for a process to terminate.
void GNUNET_process_destroy(struct GNUNET_Process *proc)
Cleans up process structure contents (OS-dependent) and deallocates it.
Definition os_process.c:363
#define GNUNET_process_set_options(proc,...)
Set the requested options for the process.
enum GNUNET_GenericReturnValue GNUNET_OS_check_helper_binary(const char *binary, bool check_suid, const char *params)
Check whether an executable exists and possibly if the suid bit is set on the file.
char * GNUNET_OS_get_suid_binary_path(const struct GNUNET_OS_ProjectData *pd, 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_process_option_inherit_wpipe(wpipe, child_fd)
Have child process inherit a pipe for writing.
enum GNUNET_GenericReturnValue GNUNET_process_kill(struct GNUNET_Process *proc, int sig)
Sends a signal to the process.
Definition os_process.c:307
struct GNUNET_Process * GNUNET_process_create(enum GNUNET_OS_InheritStdioFlags std_inheritance)
Create a process handle.
Definition os_process.c:462
@ GNUNET_OS_INHERIT_STD_NONE
No standard streams should be inherited.
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:1667
void * GNUNET_SCHEDULER_cancel(struct GNUNET_SCHEDULER_Task *task)
Cancel the task with the specified identifier.
Definition scheduler.c:986
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:1283
#define GNUNET_TIME_UNIT_FOREVER_REL
Constant used to specify "forever".
#define GNUNET_TIME_STD_EXPONENTIAL_BACKOFF_THRESHOLD
Threshold after which exponential backoff should not increase (15 m).
#define GNUNET_TIME_STD_BACKOFF(r)
Perform our standard exponential back-off calculation, starting at 1 ms and then going by a factor of...
#define _(String)
GNU gettext support macro.
Definition platform.h:179
#define GNUNET_TERM_SIG
The termination signal.
Definition platform.h:235
const struct GNUNET_CONFIGURATION_Handle * cfg
The configuration that we are using.
Definition arm_api.c:112
Handle used to access files (and pipes).
Handle used to manage a pipe.
Definition disk.c:69
Entry in list of pending tasks.
Definition scheduler.c:141
Time for relative time used by GNUnet, in microseconds.
Information we keep per NAT helper process.
struct GNUNET_DISK_PipeHandle * server_stdout
stdout pipe handle for the gnunet-helper-nat-server process
const struct GNUNET_CONFIGURATION_Handle * cfg
Handle to the GNUnet configuration.
struct GNUNET_TIME_Relative server_retry_delay
How long do we wait for restarting a crashed gnunet-helper-nat-server?
struct GNUNET_SCHEDULER_Task * server_read_task
ID of select gnunet-helper-nat-server stdout read task.
struct in_addr internal_address
IP address we pass to the NAT helper.
const struct GNUNET_DISK_FileHandle * server_stdout_handle
stdout file handle (for reading) for the gnunet-helper-nat-server process
GN_ReversalCallback cb
Function to call if we receive a reversal request.
void * cb_cls
Closure for cb.
struct GNUNET_Process * server_proc
The process id of the server process (if behind NAT)