GNUnet 0.26.2-106-g126384b46
 
Loading...
Searching...
No Matches
gnunet-service-nat_mini.c File Reference

functions for interaction with miniupnp; tested with miniupnpc 1.5 More...

#include "platform.h"
#include "gnunet_util_lib.h"
#include "gnunet_nat_service.h"
#include "gnunet-service-nat_mini.h"
#include "nat.h"
Include dependency graph for gnunet-service-nat_mini.c:

Go to the source code of this file.

Data Structures

struct  GNUNET_NAT_ExternalHandle
 Opaque handle to cancel "GNUNET_NAT_mini_get_external_ipv4" operation. More...
 
struct  GNUNET_NAT_MiniHandle
 Handle to a mapping created with upnpc. More...
 

Macros

#define LOG(kind, ...)   GNUNET_log_from (kind, "nat", __VA_ARGS__)
 
#define MAP_TIMEOUT   GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15)
 How long do we give upnpc to create a mapping?
 
#define UNMAP_TIMEOUT    GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1)
 How long do we give upnpc to remove a mapping?
 
#define MAP_REFRESH_FREQ    GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5)
 How often do we check for changes in the mapping?
 

Functions

static void read_external_ipv4 (void *cls)
 Read the output of external-ip into buf.
 
static void signal_external_ip_error (void *cls)
 (Asynchronously) signal error invoking external-ip to client.
 
struct GNUNET_NAT_ExternalHandleGNUNET_NAT_mini_get_external_ipv4_ (GNUNET_NAT_IPCallback cb, void *cb_cls)
 Try to get the external IPv4 address of this peer.
 
void GNUNET_NAT_mini_get_external_ipv4_cancel_ (struct GNUNET_NAT_ExternalHandle *eh)
 Cancel operation.
 
static void do_refresh (void *cls)
 Run "upnpc -l" to find out if our mapping changed.
 
static void process_map_output (void *cls, const char *line)
 Process the output from the "upnpc -r" command.
 
static void run_upnpc_r (struct GNUNET_NAT_MiniHandle *mini)
 Run "upnpc -r" to map our internal port.
 
static void process_refresh_output (void *cls, const char *line)
 Process the output from "upnpc -l" to see if our external mapping changed.
 
struct GNUNET_NAT_MiniHandleGNUNET_NAT_mini_map_start (uint16_t port, int is_tcp, GNUNET_NAT_MiniAddressCallback ac, void *ac_cls)
 Start mapping the given port using (mini)upnpc.
 
static void process_unmap_output (void *cls, const char *line)
 Process output from our 'unmap' command.
 
void GNUNET_NAT_mini_map_stop (struct GNUNET_NAT_MiniHandle *mini)
 Remove a mapping created with (mini)upnpc.
 

Detailed Description

functions for interaction with miniupnp; tested with miniupnpc 1.5

Author
Christian Grothoff

Definition in file gnunet-service-nat_mini.c.

Macro Definition Documentation

◆ LOG

#define LOG (   kind,
  ... 
)    GNUNET_log_from (kind, "nat", __VA_ARGS__)

Definition at line 32 of file gnunet-service-nat_mini.c.

◆ MAP_TIMEOUT

How long do we give upnpc to create a mapping?

Definition at line 37 of file gnunet-service-nat_mini.c.

◆ UNMAP_TIMEOUT

#define UNMAP_TIMEOUT    GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1)

How long do we give upnpc to remove a mapping?

Definition at line 42 of file gnunet-service-nat_mini.c.

57{
62
66 void *cb_cls;
67
71 struct GNUNET_SCHEDULER_Task *task;
72
76 struct GNUNET_Process *eip;
77
81 struct GNUNET_DISK_PipeHandle *opipe;
82
86 const struct GNUNET_DISK_FileHandle *r;
87
91 size_t off;
92
96 char buf[17];
97
102};
103
104
111static void
112read_external_ipv4 (void *cls)
113{
114 struct GNUNET_NAT_ExternalHandle *eh = cls;
115 ssize_t ret;
116 struct in_addr addr;
117
118 eh->task = NULL;
120 &eh->buf[eh->off],
121 sizeof(eh->buf) - eh->off);
122 if (ret > 0)
123 {
124 /* try to read more */
125 eh->off += ret;
127 eh->r,
129 eh);
130 return;
131 }
133 if ((eh->off > 7) && (eh->buf[eh->off - 1] == '\n'))
134 {
135 eh->buf[eh->off - 1] = '\0';
136 if (1 == inet_pton (AF_INET, eh->buf, &addr))
137 {
138 if (0 == addr.s_addr)
139 eh->ret =
141 else
143 }
144 }
145 eh->cb (eh->cb_cls,
146 (GNUNET_NAT_ERROR_SUCCESS == eh->ret) ? &addr : NULL,
147 eh->ret);
149}
150
151
157static void
158signal_external_ip_error (void *cls)
159{
160 struct GNUNET_NAT_ExternalHandle *eh = cls;
161
162 eh->task = NULL;
163 eh->cb (eh->cb_cls, NULL, eh->ret);
164 GNUNET_free (eh);
165}
166
167
177{
178 struct GNUNET_NAT_ExternalHandle *eh;
179
181 eh->cb = cb;
182 eh->cb_cls = cb_cls;
184 if (GNUNET_SYSERR ==
186 {
187 LOG (GNUNET_ERROR_TYPE_INFO, _ ("`external-ip' command not found\n"));
190 return eh;
191 }
193 "Running `external-ip' to determine our external IP\n");
195 if (NULL == eh->opipe)
196 {
199 return eh;
200 }
204 eh->eip,
206 STDOUT_FILENO)));
207 if (GNUNET_OK !=
209 "external-ip"))
210 {
212 eh->eip = NULL;
216 eh);
217 return eh;
218 }
224 eh->r,
226 eh);
227 return eh;
228}
229
230
236void
238{
239 if (NULL != eh->eip)
240 {
242 SIGKILL);
245 true,
246 NULL,
247 NULL));
249 }
250 if (NULL != eh->opipe)
251 {
253 eh->opipe = NULL;
254 }
255 if (NULL != eh->task)
256 {
258 eh->task = NULL;
259 }
260 GNUNET_free (eh);
261}
262
263
264/* ************************* upnpc calling ************************ */
265
266
271{
276
280 void *ac_cls;
281
286
291
296
300 struct sockaddr_in current_addr;
301
307
311 int is_tcp;
312
316 int did_map;
317
321 int found;
322
326 uint16_t port;
327};
328
329
335static void
336do_refresh (void *cls);
337
338
345static void
346process_map_output (void *cls, const char *line);
347
348
354static void
356{
357 char pstr[6];
358
359 GNUNET_snprintf (pstr, sizeof(pstr), "%u", (unsigned int) mini->port);
361 mini,
363 "upnpc",
364 "upnpc",
365 "-r",
366 pstr,
367 mini->is_tcp ? "tcp" : "udp",
368 NULL);
369 if (NULL == mini->map_cmd)
370 {
371 mini->ac (mini->ac_cls,
373 NULL,
374 0,
376 return;
377 }
378}
379
380
388static void
389process_refresh_output (void *cls, const char *line)
390{
391 struct GNUNET_NAT_MiniHandle *mini = cls;
392 char pstr[9];
393 const char *s;
394 unsigned int nport;
395 struct in_addr exip;
396
397 if (NULL == line)
398 {
400 mini->refresh_cmd = NULL;
401 if (GNUNET_NO == mini->found)
402 {
403 /* mapping disappeared, try to re-create */
404 if (GNUNET_YES == mini->did_map)
405 {
406 mini->ac (mini->ac_cls,
407 GNUNET_NO,
408 (const struct sockaddr *) &mini->current_addr,
409 sizeof(mini->current_addr),
411 mini->did_map = GNUNET_NO;
412 }
413 run_upnpc_r (mini);
414 }
415 return;
416 }
417 if (! mini->did_map)
418 return; /* never mapped, won't find our mapping anyway */
419
420 /* we're looking for output of the form:
421 * "ExternalIPAddress = 12.134.41.124" */
422
423 s = strstr (line, "ExternalIPAddress = ");
424 if (NULL != s)
425 {
426 s += strlen ("ExternalIPAddress = ");
427 if (1 != inet_pton (AF_INET, s, &exip))
428 return; /* skip */
429 if (exip.s_addr == mini->current_addr.sin_addr.s_addr)
430 return; /* no change */
431 /* update mapping */
432 mini->ac (mini->ac_cls,
433 GNUNET_NO,
434 (const struct sockaddr *) &mini->current_addr,
435 sizeof(mini->current_addr),
437 mini->current_addr.sin_addr = exip;
438 mini->ac (mini->ac_cls,
440 (const struct sockaddr *) &mini->current_addr,
441 sizeof(mini->current_addr),
443 return;
444 }
445 /*
446 * we're looking for output of the form:
447 *
448 * "0 TCP 3000->192.168.2.150:3000 'libminiupnpc' ''"
449 * "1 UDP 3001->192.168.2.150:3001 'libminiupnpc' ''"
450 *
451 * the pattern we look for is:
452 *
453 * "%s TCP PORT->STRING:OURPORT *" or
454 * "%s UDP PORT->STRING:OURPORT *"
455 */GNUNET_snprintf (pstr, sizeof(pstr), ":%u ", mini->port);
456 if (NULL == (s = strstr (line, "->")))
457 return; /* skip */
458 if (NULL == strstr (s, pstr))
459 return; /* skip */
460 if (1 != sscanf (line,
461 (mini->is_tcp) ? "%*u TCP %u->%*s:%*u %*s"
462 : "%*u UDP %u->%*s:%*u %*s",
463 &nport))
464 return; /* skip */
465 mini->found = GNUNET_YES;
466 if (nport == ntohs (mini->current_addr.sin_port))
467 return; /* no change */
468
469 /* external port changed, update mapping */
470 mini->ac (mini->ac_cls,
471 GNUNET_NO,
472 (const struct sockaddr *) &mini->current_addr,
473 sizeof(mini->current_addr),
475 mini->current_addr.sin_port = htons ((uint16_t) nport);
476 mini->ac (mini->ac_cls,
478 (const struct sockaddr *) &mini->current_addr,
479 sizeof(mini->current_addr),
481}
482
483
484static void
485do_refresh (void *cls)
486{
487 struct GNUNET_NAT_MiniHandle *mini = cls;
488 int ac;
489
490 mini->refresh_task =
493 "Running `upnpc' to check if our mapping still exists\n");
494 mini->found = GNUNET_NO;
495 ac = GNUNET_NO;
496 if (NULL != mini->map_cmd)
497 {
498 /* took way too long, abort it! */
500 mini->map_cmd = NULL;
501 ac = GNUNET_YES;
502 }
503 if (NULL != mini->refresh_cmd)
504 {
505 /* took way too long, abort it! */
507 mini->refresh_cmd = NULL;
508 ac = GNUNET_YES;
509 }
511 mini,
513 "upnpc",
514 "upnpc",
515 "-l",
516 NULL);
517 if (GNUNET_YES == ac)
518 mini->ac (mini->ac_cls,
520 NULL,
521 0,
523}
524
525
532static void
533process_map_output (void *cls, const char *line)
534{
535 struct GNUNET_NAT_MiniHandle *mini = cls;
536 const char *ipaddr;
537 char *ipa;
538 const char *pstr;
539 unsigned int port;
540
541 if (NULL == line)
542 {
544 mini->map_cmd = NULL;
545 if (GNUNET_YES != mini->did_map)
546 mini->ac (mini->ac_cls,
548 NULL,
549 0,
551 if (NULL == mini->refresh_task)
552 mini->refresh_task =
554 return;
555 }
556 /*
557 * The upnpc output we're after looks like this:
558 *
559 * "external 87.123.42.204:3000 TCP is redirected to internal 192.168.2.150:3000"
560 */if ((NULL == (ipaddr = strstr (line, " "))) ||
561 (NULL == (pstr = strstr (ipaddr, ":"))) ||
562 (1 != sscanf (pstr + 1, "%u", &port)))
563 {
564 return; /* skip line */
565 }
566 ipa = GNUNET_strdup (ipaddr + 1);
567 strstr (ipa, ":")[0] = '\0';
568 if (1 != inet_pton (AF_INET, ipa, &mini->current_addr.sin_addr))
569 {
570 GNUNET_free (ipa);
571 return; /* skip line */
572 }
573 GNUNET_free (ipa);
574
575 mini->current_addr.sin_port = htons (port);
576 mini->current_addr.sin_family = AF_INET;
577#if HAVE_SOCKADDR_IN_SIN_LEN
578 mini->current_addr.sin_len = sizeof(struct sockaddr_in);
579#endif
580 mini->did_map = GNUNET_YES;
581 mini->ac (mini->ac_cls,
583 (const struct sockaddr *) &mini->current_addr,
584 sizeof(mini->current_addr),
586}
587
588
604 int is_tcp,
606 void *ac_cls)
607{
609
611 {
612 LOG (GNUNET_ERROR_TYPE_INFO, _ ("`upnpc' command not found\n"));
614 return NULL;
615 }
616 LOG (GNUNET_ERROR_TYPE_DEBUG, "Running `upnpc' to install mapping\n");
618 ret->ac = ac;
619 ret->ac_cls = ac_cls;
620 ret->is_tcp = is_tcp;
621 ret->port = port;
622 ret->refresh_task =
625 return ret;
626}
627
628
635static void
636process_unmap_output (void *cls, const char *line)
637{
638 struct GNUNET_NAT_MiniHandle *mini = cls;
639
640 if (NULL == line)
641 {
642 LOG (GNUNET_ERROR_TYPE_DEBUG, "UPnP unmap done\n");
644 mini->unmap_cmd = NULL;
645 GNUNET_free (mini);
646 return;
647 }
648 /* we don't really care about the output... */
649}
650
651
652void
654{
655 char pstr[6];
656
657 if (NULL != mini->refresh_task)
658 {
660 mini->refresh_task = NULL;
661 }
662 if (NULL != mini->refresh_cmd)
663 {
665 mini->refresh_cmd = NULL;
666 }
667 if (NULL != mini->map_cmd)
668 {
670 mini->map_cmd = NULL;
671 }
672 if (GNUNET_NO == mini->did_map)
673 {
674 GNUNET_free (mini);
675 return;
676 }
677 mini->ac (mini->ac_cls,
678 GNUNET_NO,
679 (const struct sockaddr *) &mini->current_addr,
680 sizeof(mini->current_addr),
682 /* Note: oddly enough, deletion uses the external port whereas
683 * addition uses the internal port; this rarely matters since they
684 * often are the same, but it might... */
685 GNUNET_snprintf (pstr,
686 sizeof(pstr),
687 "%u",
688 (unsigned int) ntohs (mini->current_addr.sin_port));
690 "Unmapping port %u with UPnP\n",
691 ntohs (mini->current_addr.sin_port));
693 mini,
695 "upnpc",
696 "upnpc",
697 "-d",
698 pstr,
699 mini->is_tcp ? "tcp" : "udp",
700 NULL);
701}
702
703
704/* end of gnunet-service-nat_mini.c */
static int ret
Final status code.
Definition gnunet-arm.c:93
static uint16_t port
Port number.
Definition gnunet-bcd.c:146
static char * line
Desired phone line (string to be converted to a hash).
struct GNUNET_NAT_MiniHandle * GNUNET_NAT_mini_map_start(uint16_t port, int is_tcp, GNUNET_NAT_MiniAddressCallback ac, void *ac_cls)
Start mapping the given port using (mini)upnpc.
static void run_upnpc_r(struct GNUNET_NAT_MiniHandle *mini)
Run "upnpc -r" to map our internal port.
void GNUNET_NAT_mini_get_external_ipv4_cancel_(struct GNUNET_NAT_ExternalHandle *eh)
Cancel operation.
static void process_map_output(void *cls, const char *line)
Process the output from the "upnpc -r" command.
static void signal_external_ip_error(void *cls)
(Asynchronously) signal error invoking external-ip to client.
#define MAP_TIMEOUT
How long do we give upnpc to create a mapping?
#define MAP_REFRESH_FREQ
How often do we check for changes in the mapping?
void GNUNET_NAT_mini_map_stop(struct GNUNET_NAT_MiniHandle *mini)
Remove a mapping created with (mini)upnpc.
static void process_refresh_output(void *cls, const char *line)
Process the output from "upnpc -l" to see if our external mapping changed.
static void do_refresh(void *cls)
Run "upnpc -l" to find out if our mapping changed.
#define LOG(kind,...)
struct GNUNET_NAT_ExternalHandle * GNUNET_NAT_mini_get_external_ipv4_(GNUNET_NAT_IPCallback cb, void *cb_cls)
Try to get the external IPv4 address of this peer.
#define UNMAP_TIMEOUT
How long do we give upnpc to remove a mapping?
static void process_unmap_output(void *cls, const char *line)
Process output from our 'unmap' command.
static void read_external_ipv4(void *cls)
Read the output of external-ip into buf.
void(* GNUNET_NAT_MiniAddressCallback)(void *cls, int add_remove, const struct sockaddr *addr, socklen_t addrlen, enum GNUNET_NAT_StatusCode result)
Signature of the callback passed to GNUNET_NAT_register() for a function to call whenever our set of ...
void(* GNUNET_NAT_IPCallback)(void *cls, const struct in_addr *addr, enum GNUNET_NAT_StatusCode result)
Signature of a callback that is given an IP address.
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.
@ GNUNET_OK
@ GNUNET_YES
@ GNUNET_NO
@ GNUNET_SYSERR
#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.
@ GNUNET_ERROR_TYPE_DEBUG
@ GNUNET_ERROR_TYPE_INFO
#define GNUNET_strdup(a)
Wrapper around GNUNET_xstrdup_.
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.
GNUNET_NAT_StatusCode
Error Types for the NAT subsystem (which can then later be converted/resolved to a string)
@ GNUNET_NAT_ERROR_UPNPC_NOT_FOUND
upnpc command not found
@ GNUNET_NAT_ERROR_UPNPC_TIMEOUT
‘upnpc’ command took too long, process killed
@ GNUNET_NAT_ERROR_SUCCESS
Just the default.
@ GNUNET_NAT_ERROR_EXTERNAL_IP_UTILITY_OUTPUT_INVALID
‘external-ip’ command output invalid
@ GNUNET_NAT_ERROR_UPNPC_FAILED
Failed to run upnpc command.
@ GNUNET_NAT_ERROR_EXTERNAL_IP_UTILITY_FAILED
Failed to run external-ip command.
@ GNUNET_NAT_ERROR_UPNPC_PORTMAP_FAILED
‘upnpc’ command failed to establish port mapping
@ GNUNET_NAT_ERROR_EXTERNAL_IP_UTILITY_NOT_FOUND
‘external-ip’ command not found
@ GNUNET_NAT_ERROR_IPC_FAILURE
IPC Failure.
@ GNUNET_NAT_ERROR_EXTERNAL_IP_ADDRESS_INVALID
"no valid address was returned by `external-ip'"
enum GNUNET_GenericReturnValue GNUNET_process_run_command(struct GNUNET_Process *p, const char *command)
Set the command and start a process.
Definition os_process.c:921
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
void GNUNET_OS_command_stop(struct GNUNET_OS_CommandHandle *cmd)
Stop/kill a command.
struct GNUNET_OS_CommandHandle * GNUNET_OS_command_run(GNUNET_OS_LineProcessor proc, void *proc_cls, struct GNUNET_TIME_Relative timeout, const char *binary,...)
Run the given command line and call the given function for each line of the output.
#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.
#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_now(GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run as soon as possible.
Definition scheduler.c:1310
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 _(String)
GNU gettext support macro.
Definition platform.h:179
Handle used to access files (and pipes).
Handle used to manage a pipe.
Definition disk.c:69
Opaque handle to cancel "GNUNET_NAT_mini_get_external_ipv4" operation.
size_t off
Number of bytes in buf that are valid.
GNUNET_NAT_IPCallback cb
Function to call with the result.
struct GNUNET_DISK_PipeHandle * opipe
Handle to stdout pipe of external-ip.
const struct GNUNET_DISK_FileHandle * r
Read handle of opipe.
enum GNUNET_NAT_StatusCode ret
Error code for better debugging and user feedback.
char buf[17]
Destination of our read operation (output of 'external-ip').
struct GNUNET_SCHEDULER_Task * task
Read task.
struct GNUNET_Process * eip
Handle to external-ip process.
Handle to a mapping created with upnpc.
struct GNUNET_OS_CommandHandle * unmap_cmd
Command used to remove the mapping.
struct GNUNET_OS_CommandHandle * map_cmd
Command used to install the map.
struct GNUNET_OS_CommandHandle * refresh_cmd
Command used to refresh our map information.
int did_map
Did we succeed with creating a mapping?
void * ac_cls
Closure for ac.
uint16_t port
Which port are we mapping?
int is_tcp
Are we mapping TCP or UDP?
GNUNET_NAT_MiniAddressCallback ac
Function to call on mapping changes.
struct GNUNET_SCHEDULER_Task * refresh_task
We check the mapping periodically to see if it still works.
int found
Did we find our mapping during refresh scan?
struct sockaddr_in current_addr
Our current external mapping (if we have one).
Handle to a command.
Entry in list of pending tasks.
Definition scheduler.c:141

◆ MAP_REFRESH_FREQ

#define MAP_REFRESH_FREQ    GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5)

How often do we check for changes in the mapping?

Definition at line 48 of file gnunet-service-nat_mini.c.

Function Documentation

◆ read_external_ipv4()

static void read_external_ipv4 ( void *  cls)
static

Read the output of external-ip into buf.

When complete, parse the address and call our callback.

Parameters
clsthe struct GNUNET_NAT_ExternalHandle

Definition at line 113 of file gnunet-service-nat_mini.c.

114{
115 struct GNUNET_NAT_ExternalHandle *eh = cls;
116 ssize_t ret;
117 struct in_addr addr;
118
119 eh->task = NULL;
121 &eh->buf[eh->off],
122 sizeof(eh->buf) - eh->off);
123 if (ret > 0)
124 {
125 /* try to read more */
126 eh->off += ret;
128 eh->r,
130 eh);
131 return;
132 }
134 if ((eh->off > 7) && (eh->buf[eh->off - 1] == '\n'))
135 {
136 eh->buf[eh->off - 1] = '\0';
137 if (1 == inet_pton (AF_INET, eh->buf, &addr))
138 {
139 if (0 == addr.s_addr)
140 eh->ret =
142 else
144 }
145 }
146 eh->cb (eh->cb_cls,
147 (GNUNET_NAT_ERROR_SUCCESS == eh->ret) ? &addr : NULL,
148 eh->ret);
150}

References GNUNET_NAT_ExternalHandle::buf, GNUNET_NAT_ExternalHandle::cb, GNUNET_NAT_ExternalHandle::cb_cls, GNUNET_DISK_file_read(), GNUNET_NAT_ERROR_EXTERNAL_IP_ADDRESS_INVALID, GNUNET_NAT_ERROR_EXTERNAL_IP_UTILITY_OUTPUT_INVALID, GNUNET_NAT_ERROR_SUCCESS, GNUNET_NAT_mini_get_external_ipv4_cancel_(), GNUNET_SCHEDULER_add_read_file(), GNUNET_TIME_UNIT_FOREVER_REL, GNUNET_NAT_ExternalHandle::off, GNUNET_NAT_ExternalHandle::r, read_external_ipv4(), ret, GNUNET_NAT_ExternalHandle::ret, and GNUNET_NAT_ExternalHandle::task.

Referenced by GNUNET_NAT_mini_get_external_ipv4_(), and read_external_ipv4().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ signal_external_ip_error()

static void signal_external_ip_error ( void *  cls)
static

(Asynchronously) signal error invoking external-ip to client.

Parameters
clsthe struct GNUNET_NAT_ExternalHandle (freed)

Definition at line 159 of file gnunet-service-nat_mini.c.

160{
161 struct GNUNET_NAT_ExternalHandle *eh = cls;
162
163 eh->task = NULL;
164 eh->cb (eh->cb_cls, NULL, eh->ret);
165 GNUNET_free (eh);
166}

References GNUNET_NAT_ExternalHandle::cb, GNUNET_NAT_ExternalHandle::cb_cls, GNUNET_free, GNUNET_NAT_ExternalHandle::off, GNUNET_NAT_ExternalHandle::ret, and GNUNET_NAT_ExternalHandle::task.

Referenced by GNUNET_NAT_mini_get_external_ipv4_().

Here is the caller graph for this function:

◆ GNUNET_NAT_mini_get_external_ipv4_()

struct GNUNET_NAT_ExternalHandle * GNUNET_NAT_mini_get_external_ipv4_ ( GNUNET_NAT_IPCallback  cb,
void *  cb_cls 
)

Try to get the external IPv4 address of this peer.

Parameters
cbfunction to call with result
cb_clsclosure for cb
Returns
handle for cancellation (can only be used until cb is called), never NULL

Definition at line 177 of file gnunet-service-nat_mini.c.

178{
179 struct GNUNET_NAT_ExternalHandle *eh;
180
182 eh->cb = cb;
183 eh->cb_cls = cb_cls;
185 if (GNUNET_SYSERR ==
187 {
188 LOG (GNUNET_ERROR_TYPE_INFO, _ ("`external-ip' command not found\n"));
191 return eh;
192 }
194 "Running `external-ip' to determine our external IP\n");
196 if (NULL == eh->opipe)
197 {
200 return eh;
201 }
205 eh->eip,
207 STDOUT_FILENO)));
208 if (GNUNET_OK !=
210 "external-ip"))
211 {
213 eh->eip = NULL;
217 eh);
218 return eh;
219 }
225 eh->r,
227 eh);
228 return eh;
229}

References _, GNUNET_NAT_ExternalHandle::cb, GNUNET_NAT_ExternalHandle::cb_cls, GNUNET_NAT_ExternalHandle::eip, GNUNET_assert, GNUNET_DISK_PF_BLOCKING_RW, GNUNET_DISK_pipe(), GNUNET_DISK_pipe_close(), GNUNET_DISK_pipe_close_end(), GNUNET_DISK_PIPE_END_READ, GNUNET_DISK_PIPE_END_WRITE, GNUNET_DISK_pipe_handle(), GNUNET_ERROR_TYPE_DEBUG, GNUNET_ERROR_TYPE_INFO, GNUNET_NAT_ERROR_EXTERNAL_IP_UTILITY_FAILED, GNUNET_NAT_ERROR_EXTERNAL_IP_UTILITY_NOT_FOUND, GNUNET_NAT_ERROR_IPC_FAILURE, GNUNET_NAT_ERROR_SUCCESS, GNUNET_new, GNUNET_NO, GNUNET_OK, GNUNET_OS_check_helper_binary(), GNUNET_OS_INHERIT_STD_NONE, GNUNET_process_create(), GNUNET_process_destroy(), GNUNET_process_option_inherit_wpipe, GNUNET_process_run_command(), GNUNET_process_set_options, GNUNET_SCHEDULER_add_now(), GNUNET_SCHEDULER_add_read_file(), GNUNET_SYSERR, GNUNET_TIME_UNIT_FOREVER_REL, LOG, GNUNET_NAT_ExternalHandle::off, GNUNET_NAT_ExternalHandle::opipe, GNUNET_NAT_ExternalHandle::r, read_external_ipv4(), GNUNET_NAT_ExternalHandle::ret, signal_external_ip_error(), and GNUNET_NAT_ExternalHandle::task.

Referenced by run_external_ip().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ GNUNET_NAT_mini_get_external_ipv4_cancel_()

void GNUNET_NAT_mini_get_external_ipv4_cancel_ ( struct GNUNET_NAT_ExternalHandle eh)

Cancel operation.

Parameters
ehoperation to cancel

Definition at line 238 of file gnunet-service-nat_mini.c.

239{
240 if (NULL != eh->eip)
241 {
242 (void) GNUNET_process_kill (eh->eip,
243 SIGKILL);
246 true,
247 NULL,
248 NULL));
250 }
251 if (NULL != eh->opipe)
252 {
254 eh->opipe = NULL;
255 }
256 if (NULL != eh->task)
257 {
259 eh->task = NULL;
260 }
261 GNUNET_free (eh);
262}

References GNUNET_NAT_ExternalHandle::eip, GNUNET_break, GNUNET_DISK_pipe_close(), GNUNET_free, GNUNET_OK, GNUNET_process_destroy(), GNUNET_process_kill(), GNUNET_process_wait(), GNUNET_SCHEDULER_cancel(), GNUNET_NAT_ExternalHandle::off, GNUNET_NAT_ExternalHandle::opipe, and GNUNET_NAT_ExternalHandle::task.

Referenced by GN_nat_status_changed(), read_external_ipv4(), and run_external_ip().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ do_refresh()

static void do_refresh ( void *  cls)
static

Run "upnpc -l" to find out if our mapping changed.

Parameters
clsthe struct GNUNET_NAT_MiniHandle

Definition at line 486 of file gnunet-service-nat_mini.c.

487{
488 struct GNUNET_NAT_MiniHandle *mini = cls;
489 int ac;
490
491 mini->refresh_task =
494 "Running `upnpc' to check if our mapping still exists\n");
495 mini->found = GNUNET_NO;
496 ac = GNUNET_NO;
497 if (NULL != mini->map_cmd)
498 {
499 /* took way too long, abort it! */
501 mini->map_cmd = NULL;
502 ac = GNUNET_YES;
503 }
504 if (NULL != mini->refresh_cmd)
505 {
506 /* took way too long, abort it! */
508 mini->refresh_cmd = NULL;
509 ac = GNUNET_YES;
510 }
512 mini,
514 "upnpc",
515 "upnpc",
516 "-l",
517 NULL);
518 if (GNUNET_YES == ac)
519 mini->ac (mini->ac_cls,
521 NULL,
522 0,
524}

References GNUNET_NAT_MiniHandle::ac, GNUNET_NAT_MiniHandle::ac_cls, do_refresh(), GNUNET_NAT_MiniHandle::found, GNUNET_ERROR_TYPE_DEBUG, GNUNET_NAT_ERROR_UPNPC_TIMEOUT, GNUNET_NO, GNUNET_OS_command_run(), GNUNET_OS_command_stop(), GNUNET_SCHEDULER_add_delayed(), GNUNET_SYSERR, GNUNET_YES, LOG, GNUNET_NAT_MiniHandle::map_cmd, MAP_REFRESH_FREQ, MAP_TIMEOUT, process_refresh_output(), GNUNET_NAT_MiniHandle::refresh_cmd, and GNUNET_NAT_MiniHandle::refresh_task.

Referenced by do_refresh(), GNUNET_NAT_mini_map_start(), and process_map_output().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ process_map_output()

static void process_map_output ( void *  cls,
const char *  line 
)
static

Process the output from the "upnpc -r" command.

Process the output from the 'upnpc -r' command.

Parameters
clsthe struct GNUNET_NAT_MiniHandle
lineline of output, NULL at the end

Definition at line 534 of file gnunet-service-nat_mini.c.

535{
536 struct GNUNET_NAT_MiniHandle *mini = cls;
537 const char *ipaddr;
538 char *ipa;
539 const char *pstr;
540 unsigned int port;
541
542 if (NULL == line)
543 {
545 mini->map_cmd = NULL;
546 if (GNUNET_YES != mini->did_map)
547 mini->ac (mini->ac_cls,
549 NULL,
550 0,
552 if (NULL == mini->refresh_task)
553 mini->refresh_task =
555 return;
556 }
557 /*
558 * The upnpc output we're after looks like this:
559 *
560 * "external 87.123.42.204:3000 TCP is redirected to internal 192.168.2.150:3000"
561 */if ((NULL == (ipaddr = strstr (line, " "))) ||
562 (NULL == (pstr = strstr (ipaddr, ":"))) ||
563 (1 != sscanf (pstr + 1, "%u", &port)))
564 {
565 return; /* skip line */
566 }
567 ipa = GNUNET_strdup (ipaddr + 1);
568 strstr (ipa, ":")[0] = '\0';
569 if (1 != inet_pton (AF_INET, ipa, &mini->current_addr.sin_addr))
570 {
571 GNUNET_free (ipa);
572 return; /* skip line */
573 }
574 GNUNET_free (ipa);
575
576 mini->current_addr.sin_port = htons (port);
577 mini->current_addr.sin_family = AF_INET;
578#if HAVE_SOCKADDR_IN_SIN_LEN
579 mini->current_addr.sin_len = sizeof(struct sockaddr_in);
580#endif
581 mini->did_map = GNUNET_YES;
582 mini->ac (mini->ac_cls,
584 (const struct sockaddr *) &mini->current_addr,
585 sizeof(mini->current_addr),
587}

References GNUNET_NAT_MiniHandle::ac, GNUNET_NAT_MiniHandle::ac_cls, GNUNET_NAT_MiniHandle::current_addr, GNUNET_NAT_MiniHandle::did_map, do_refresh(), GNUNET_free, GNUNET_NAT_ERROR_SUCCESS, GNUNET_NAT_ERROR_UPNPC_PORTMAP_FAILED, GNUNET_OS_command_stop(), GNUNET_SCHEDULER_add_delayed(), GNUNET_strdup, GNUNET_SYSERR, GNUNET_YES, line, GNUNET_NAT_MiniHandle::map_cmd, MAP_REFRESH_FREQ, port, and GNUNET_NAT_MiniHandle::refresh_task.

Referenced by run_upnpc_r().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ run_upnpc_r()

static void run_upnpc_r ( struct GNUNET_NAT_MiniHandle mini)
static

Run "upnpc -r" to map our internal port.

Parameters
miniour handle

Definition at line 356 of file gnunet-service-nat_mini.c.

357{
358 char pstr[6];
359
360 GNUNET_snprintf (pstr, sizeof(pstr), "%u", (unsigned int) mini->port);
362 mini,
364 "upnpc",
365 "upnpc",
366 "-r",
367 pstr,
368 mini->is_tcp ? "tcp" : "udp",
369 NULL);
370 if (NULL == mini->map_cmd)
371 {
372 mini->ac (mini->ac_cls,
374 NULL,
375 0,
377 return;
378 }
379}

References GNUNET_NAT_MiniHandle::ac, GNUNET_NAT_MiniHandle::ac_cls, GNUNET_NAT_ERROR_UPNPC_FAILED, GNUNET_OS_command_run(), GNUNET_snprintf(), GNUNET_SYSERR, GNUNET_NAT_MiniHandle::is_tcp, GNUNET_NAT_MiniHandle::map_cmd, MAP_TIMEOUT, GNUNET_NAT_MiniHandle::port, and process_map_output().

Referenced by GNUNET_NAT_mini_map_start(), and process_refresh_output().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ process_refresh_output()

static void process_refresh_output ( void *  cls,
const char *  line 
)
static

Process the output from "upnpc -l" to see if our external mapping changed.

If so, do the notifications.

Parameters
clsthe struct GNUNET_NAT_MiniHandle
lineline of output, NULL at the end

Definition at line 390 of file gnunet-service-nat_mini.c.

391{
392 struct GNUNET_NAT_MiniHandle *mini = cls;
393 char pstr[9];
394 const char *s;
395 unsigned int nport;
396 struct in_addr exip;
397
398 if (NULL == line)
399 {
401 mini->refresh_cmd = NULL;
402 if (GNUNET_NO == mini->found)
403 {
404 /* mapping disappeared, try to re-create */
405 if (GNUNET_YES == mini->did_map)
406 {
407 mini->ac (mini->ac_cls,
408 GNUNET_NO,
409 (const struct sockaddr *) &mini->current_addr,
410 sizeof(mini->current_addr),
412 mini->did_map = GNUNET_NO;
413 }
414 run_upnpc_r (mini);
415 }
416 return;
417 }
418 if (! mini->did_map)
419 return; /* never mapped, won't find our mapping anyway */
420
421 /* we're looking for output of the form:
422 * "ExternalIPAddress = 12.134.41.124" */
423
424 s = strstr (line, "ExternalIPAddress = ");
425 if (NULL != s)
426 {
427 s += strlen ("ExternalIPAddress = ");
428 if (1 != inet_pton (AF_INET, s, &exip))
429 return; /* skip */
430 if (exip.s_addr == mini->current_addr.sin_addr.s_addr)
431 return; /* no change */
432 /* update mapping */
433 mini->ac (mini->ac_cls,
434 GNUNET_NO,
435 (const struct sockaddr *) &mini->current_addr,
436 sizeof(mini->current_addr),
438 mini->current_addr.sin_addr = exip;
439 mini->ac (mini->ac_cls,
441 (const struct sockaddr *) &mini->current_addr,
442 sizeof(mini->current_addr),
444 return;
445 }
446 /*
447 * we're looking for output of the form:
448 *
449 * "0 TCP 3000->192.168.2.150:3000 'libminiupnpc' ''"
450 * "1 UDP 3001->192.168.2.150:3001 'libminiupnpc' ''"
451 *
452 * the pattern we look for is:
453 *
454 * "%s TCP PORT->STRING:OURPORT *" or
455 * "%s UDP PORT->STRING:OURPORT *"
456 */GNUNET_snprintf (pstr, sizeof(pstr), ":%u ", mini->port);
457 if (NULL == (s = strstr (line, "->")))
458 return; /* skip */
459 if (NULL == strstr (s, pstr))
460 return; /* skip */
461 if (1 != sscanf (line,
462 (mini->is_tcp) ? "%*u TCP %u->%*s:%*u %*s"
463 : "%*u UDP %u->%*s:%*u %*s",
464 &nport))
465 return; /* skip */
466 mini->found = GNUNET_YES;
467 if (nport == ntohs (mini->current_addr.sin_port))
468 return; /* no change */
469
470 /* external port changed, update mapping */
471 mini->ac (mini->ac_cls,
472 GNUNET_NO,
473 (const struct sockaddr *) &mini->current_addr,
474 sizeof(mini->current_addr),
476 mini->current_addr.sin_port = htons ((uint16_t) nport);
477 mini->ac (mini->ac_cls,
479 (const struct sockaddr *) &mini->current_addr,
480 sizeof(mini->current_addr),
482}

References GNUNET_NAT_MiniHandle::ac, GNUNET_NAT_MiniHandle::ac_cls, GNUNET_NAT_MiniHandle::current_addr, GNUNET_NAT_MiniHandle::did_map, GNUNET_NAT_MiniHandle::found, GNUNET_NAT_ERROR_SUCCESS, GNUNET_NO, GNUNET_OS_command_stop(), GNUNET_snprintf(), GNUNET_YES, GNUNET_NAT_MiniHandle::is_tcp, line, GNUNET_NAT_MiniHandle::port, GNUNET_NAT_MiniHandle::refresh_cmd, and run_upnpc_r().

Referenced by do_refresh().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ GNUNET_NAT_mini_map_start()

struct GNUNET_NAT_MiniHandle * GNUNET_NAT_mini_map_start ( uint16_t  port,
int  is_tcp,
GNUNET_NAT_MiniAddressCallback  ac,
void *  ac_cls 
)

Start mapping the given port using (mini)upnpc.

This function should typically not be used directly (it is used within the general-purpose GNUNET_NAT_register() code). However, it can be used if specifically UPnP-based NAT traversal is to be used or tested.

Parameters
portport to map
is_tcpGNUNET_YES to map TCP, GNUNET_NO for UDP
acfunction to call with mapping result
ac_clsclosure for ac
Returns
NULL on error (no 'upnpc' installed)

Definition at line 604 of file gnunet-service-nat_mini.c.

608{
610
612 {
613 LOG (GNUNET_ERROR_TYPE_INFO, _ ("`upnpc' command not found\n"));
615 return NULL;
616 }
617 LOG (GNUNET_ERROR_TYPE_DEBUG, "Running `upnpc' to install mapping\n");
619 ret->ac = ac;
620 ret->ac_cls = ac_cls;
621 ret->is_tcp = is_tcp;
622 ret->port = port;
623 ret->refresh_task =
626 return ret;
627}

References _, GNUNET_NAT_MiniHandle::ac, GNUNET_NAT_MiniHandle::ac_cls, do_refresh(), GNUNET_ERROR_TYPE_DEBUG, GNUNET_ERROR_TYPE_INFO, GNUNET_NAT_ERROR_UPNPC_NOT_FOUND, GNUNET_new, GNUNET_NO, GNUNET_OS_check_helper_binary(), GNUNET_SCHEDULER_add_delayed(), GNUNET_SYSERR, GNUNET_NAT_MiniHandle::is_tcp, LOG, MAP_REFRESH_FREQ, port, ret, and run_upnpc_r().

Referenced by handle_register().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ process_unmap_output()

static void process_unmap_output ( void *  cls,
const char *  line 
)
static

Process output from our 'unmap' command.

Parameters
clsthe struct GNUNET_NAT_MiniHandle
lineline of output, NULL at the end

Definition at line 637 of file gnunet-service-nat_mini.c.

638{
639 struct GNUNET_NAT_MiniHandle *mini = cls;
640
641 if (NULL == line)
642 {
643 LOG (GNUNET_ERROR_TYPE_DEBUG, "UPnP unmap done\n");
645 mini->unmap_cmd = NULL;
646 GNUNET_free (mini);
647 return;
648 }
649 /* we don't really care about the output... */
650}

References GNUNET_ERROR_TYPE_DEBUG, GNUNET_free, GNUNET_OS_command_stop(), line, LOG, and GNUNET_NAT_MiniHandle::unmap_cmd.

Referenced by GNUNET_NAT_mini_map_stop().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ GNUNET_NAT_mini_map_stop()

void GNUNET_NAT_mini_map_stop ( struct GNUNET_NAT_MiniHandle mini)

Remove a mapping created with (mini)upnpc.

Calling this function will give 'upnpc' 1s to remove the mapping, so while this function is non-blocking, a task will be left with the scheduler for up to 1s past this call.

Parameters
minithe handle

Definition at line 654 of file gnunet-service-nat_mini.c.

655{
656 char pstr[6];
657
658 if (NULL != mini->refresh_task)
659 {
661 mini->refresh_task = NULL;
662 }
663 if (NULL != mini->refresh_cmd)
664 {
666 mini->refresh_cmd = NULL;
667 }
668 if (NULL != mini->map_cmd)
669 {
671 mini->map_cmd = NULL;
672 }
673 if (GNUNET_NO == mini->did_map)
674 {
675 GNUNET_free (mini);
676 return;
677 }
678 mini->ac (mini->ac_cls,
679 GNUNET_NO,
680 (const struct sockaddr *) &mini->current_addr,
681 sizeof(mini->current_addr),
683 /* Note: oddly enough, deletion uses the external port whereas
684 * addition uses the internal port; this rarely matters since they
685 * often are the same, but it might... */
686 GNUNET_snprintf (pstr,
687 sizeof(pstr),
688 "%u",
689 (unsigned int) ntohs (mini->current_addr.sin_port));
691 "Unmapping port %u with UPnP\n",
692 ntohs (mini->current_addr.sin_port));
694 mini,
696 "upnpc",
697 "upnpc",
698 "-d",
699 pstr,
700 mini->is_tcp ? "tcp" : "udp",
701 NULL);
702}

References GNUNET_NAT_MiniHandle::ac, GNUNET_NAT_MiniHandle::ac_cls, GNUNET_NAT_MiniHandle::current_addr, GNUNET_NAT_MiniHandle::did_map, GNUNET_ERROR_TYPE_DEBUG, GNUNET_free, GNUNET_NAT_ERROR_SUCCESS, GNUNET_NO, GNUNET_OS_command_run(), GNUNET_OS_command_stop(), GNUNET_SCHEDULER_cancel(), GNUNET_snprintf(), GNUNET_NAT_MiniHandle::is_tcp, LOG, GNUNET_NAT_MiniHandle::map_cmd, process_unmap_output(), GNUNET_NAT_MiniHandle::refresh_cmd, GNUNET_NAT_MiniHandle::refresh_task, GNUNET_NAT_MiniHandle::unmap_cmd, and UNMAP_TIMEOUT.

Referenced by client_disconnect_cb().

Here is the call graph for this function:
Here is the caller graph for this function: