GNUnet  0.20.0
gnunet-helper-vpn.c File Reference

the helper for the VPN service. More...

#include "platform.h"
#include "gnunet_util_lib.h"
#include "gnunet_common.h"
#include "gnunet_protocols.h"
Include dependency graph for gnunet-helper-vpn.c:

Go to the source code of this file.

Data Structures

struct  in6_ifreq
 This is in linux/include/net/ipv6.h, but not always exported... More...
 

Macros

#define DEBUG   GNUNET_NO
 Need 'struct GNUNET_MessageHeader'. More...
 
#define MAX_SIZE   65536
 Maximum size of a GNUnet message (GNUNET_MAX_MESSAGE_SIZE) More...
 

Functions

static int init_tun (char *dev)
 Creates a tun-interface called dev;. More...
 
static void set_address6 (const char *dev, const char *address, unsigned long prefix_len)
 Sets the IPv6-Address given in address on the interface dev. More...
 
static void set_address4 (const char *dev, const char *address, const char *mask)
 Sets the IPv4-Address given in address on the interface dev. More...
 
static void run (int fd_tun)
 Start forwarding to and from the tunnel. More...
 
int main (int argc, char **argv)
 Open VPN tunnel interface. More...
 

Detailed Description

the helper for the VPN service.

Opens a virtual network-interface, sends data received on the if to stdout, sends data received on stdin to the interface

Author
Philipp Tölke
Christian Grothoff

The following list of people have reviewed this code and considered it safe since the last modification (if you reviewed it, please have your name added to the list):

  • Philipp Tölke

Definition in file gnunet-helper-vpn.c.

Macro Definition Documentation

◆ DEBUG

#define DEBUG   GNUNET_NO

Need 'struct GNUNET_MessageHeader'.

Need VPN message types. Should we print (interesting|debug) messages that can happen during normal operation?

Definition at line 55 of file gnunet-helper-vpn.c.

◆ MAX_SIZE

#define MAX_SIZE   65536

Maximum size of a GNUnet message (GNUNET_MAX_MESSAGE_SIZE)

Definition at line 60 of file gnunet-helper-vpn.c.

Function Documentation

◆ init_tun()

static int init_tun ( char *  dev)
static

Creates a tun-interface called dev;.

Parameters
devis assumed to point to a char[IFNAMSIZ] if *dev == '\0', uses the name supplied by the kernel;
Returns
the fd to the tun or -1 on error

Definition at line 85 of file gnunet-helper-vpn.c.

86 {
87  struct ifreq ifr;
88  int fd;
89 
90  if (NULL == dev)
91  {
92  errno = EINVAL;
93  return -1;
94  }
95 
96  if (-1 == (fd = open ("/dev/net/tun", O_RDWR)))
97  {
98  fprintf (stderr,
99  "Error opening `%s': %s\n",
100  "/dev/net/tun",
101  strerror (errno));
102  return -1;
103  }
104 
105  if (fd >= FD_SETSIZE)
106  {
107  fprintf (stderr,
108  "File descriptor to large: %d",
109  fd);
110  (void) close (fd);
111  return -1;
112  }
113 
114  memset (&ifr, 0, sizeof(ifr));
115  ifr.ifr_flags = IFF_TUN;
116 
117  if ('\0' != *dev)
118  strncpy (ifr.ifr_name,
119  dev,
120  IFNAMSIZ);
121 
122  if (-1 == ioctl (fd,
123  TUNSETIFF,
124  (void *) &ifr))
125  {
126  fprintf (stderr,
127  "Error with ioctl on `%s': %s\n",
128  "/dev/net/tun",
129  strerror (errno));
130  (void) close (fd);
131  return -1;
132  }
133  strcpy (dev, ifr.ifr_name);
134  return fd;
135 }

Referenced by main().

Here is the caller graph for this function:

◆ set_address6()

static void set_address6 ( const char *  dev,
const char *  address,
unsigned long  prefix_len 
)
static

Sets the IPv6-Address given in address on the interface dev.

Parameters
devthe interface to configure
addressthe IPv6-Address
prefix_lenthe length of the network-prefix

Definition at line 146 of file gnunet-helper-vpn.c.

149 {
150  struct ifreq ifr;
151  struct in6_ifreq ifr6;
152  struct sockaddr_in6 sa6;
153  int fd;
154 
155  /*
156  * parse the new address
157  */
158  memset (&sa6, 0, sizeof(struct sockaddr_in6));
159  sa6.sin6_family = AF_INET6;
160  if (1 != inet_pton (AF_INET6, address, sa6.sin6_addr.s6_addr))
161  {
162  fprintf (stderr,
163  "Failed to parse IPv6 address `%s'\n",
164  address);
165  exit (1);
166  }
167 
168  if (-1 == (fd = socket (PF_INET6, SOCK_DGRAM, 0)))
169  {
170  fprintf (stderr,
171  "Error creating socket: %s\n",
172  strerror (errno));
173  exit (1);
174  }
175 
176  memset (&ifr, 0, sizeof(struct ifreq));
177  /*
178  * Get the index of the if
179  */
180  strncpy (ifr.ifr_name,
181  dev,
182  IFNAMSIZ);
183  if (-1 == ioctl (fd,
184  SIOGIFINDEX,
185  &ifr))
186  {
187  fprintf (stderr,
188  "ioctl failed at %d: %s\n",
189  __LINE__,
190  strerror (errno));
191  (void) close (fd);
192  exit (1);
193  }
194 
195  memset (&ifr6, 0, sizeof(struct in6_ifreq));
196  ifr6.ifr6_addr = sa6.sin6_addr;
197  ifr6.ifr6_ifindex = ifr.ifr_ifindex;
198  ifr6.ifr6_prefixlen = prefix_len;
199 
200  /*
201  * Set the address
202  */
203  if (-1 == ioctl (fd,
204  SIOCSIFADDR,
205  &ifr6))
206  {
207  fprintf (stderr,
208  "ioctl failed at line %d: %s\n",
209  __LINE__,
210  strerror (errno));
211  (void) close (fd);
212  exit (1);
213  }
214 
215  /*
216  * Get the flags
217  */
218  if (-1 == ioctl (fd,
219  SIOCGIFFLAGS,
220  &ifr))
221  {
222  fprintf (stderr,
223  "ioctl failed at line %d: %s\n",
224  __LINE__,
225  strerror (errno));
226  (void) close (fd);
227  exit (1);
228  }
229 
230  /*
231  * Add the UP and RUNNING flags
232  */
233  ifr.ifr_flags |= IFF_UP | IFF_RUNNING;
234  if (-1 == ioctl (fd,
235  SIOCSIFFLAGS,
236  &ifr))
237  {
238  fprintf (stderr,
239  "ioctl failed at line %d: %s\n",
240  __LINE__,
241  strerror (errno));
242  (void) close (fd);
243  exit (1);
244  }
245 
246  if (0 != close (fd))
247  {
248  fprintf (stderr,
249  "close failed at line %d: %s\n",
250  __LINE__,
251  strerror (errno));
252  exit (1);
253  }
254 }
static char * address
GNS address for this phone.
This is in linux/include/net/ipv6.h, but not always exported...

References address, in6_ifreq::ifr6_addr, in6_ifreq::ifr6_ifindex, and in6_ifreq::ifr6_prefixlen.

Referenced by main().

Here is the caller graph for this function:

◆ set_address4()

static void set_address4 ( const char *  dev,
const char *  address,
const char *  mask 
)
static

Sets the IPv4-Address given in address on the interface dev.

Parameters
devthe interface to configure
addressthe IPv4-Address
maskthe netmask

Definition at line 265 of file gnunet-helper-vpn.c.

268 {
269  int fd;
270  struct sockaddr_in *addr;
271  struct ifreq ifr;
272 
273  memset (&ifr, 0, sizeof(struct ifreq));
274  addr = (struct sockaddr_in *) &(ifr.ifr_addr);
275  addr->sin_family = AF_INET;
276 
277  /*
278  * Parse the address
279  */
280  if (1 != inet_pton (AF_INET,
281  address,
282  &addr->sin_addr.s_addr))
283  {
284  fprintf (stderr,
285  "Failed to parse IPv4 address `%s'\n",
286  address);
287  exit (1);
288  }
289 
290  if (-1 == (fd = socket (PF_INET, SOCK_DGRAM, 0)))
291  {
292  fprintf (stderr,
293  "Error creating socket: %s\n",
294  strerror (errno));
295  exit (1);
296  }
297 
298  strncpy (ifr.ifr_name, dev, IFNAMSIZ);
299 
300  /*
301  * Set the address
302  */
303  if (-1 == ioctl (fd, SIOCSIFADDR, &ifr))
304  {
305  fprintf (stderr,
306  "ioctl failed at %d: %s\n",
307  __LINE__,
308  strerror (errno));
309  (void) close (fd);
310  exit (1);
311  }
312 
313  /*
314  * Parse the netmask
315  */
316  addr = (struct sockaddr_in *) &(ifr.ifr_netmask);
317  if (1 != inet_pton (AF_INET,
318  mask,
319  &addr->sin_addr.s_addr))
320  {
321  fprintf (stderr,
322  "Failed to parse IPv4 address mask `%s'\n",
323  mask);
324  (void) close (fd);
325  exit (1);
326  }
327 
328  /*
329  * Set the netmask
330  */
331  if (-1 == ioctl (fd, SIOCSIFNETMASK, &ifr))
332  {
333  fprintf (stderr,
334  "ioctl failed at line %d: %s\n",
335  __LINE__,
336  strerror (errno));
337  (void) close (fd);
338  exit (1);
339  }
340 
341  /*
342  * Get the flags
343  */
344  if (-1 == ioctl (fd, SIOCGIFFLAGS, &ifr))
345  {
346  fprintf (stderr,
347  "ioctl failed at line %d: %s\n",
348  __LINE__,
349  strerror (errno));
350  (void) close (fd);
351  exit (1);
352  }
353 
354  /*
355  * Add the UP and RUNNING flags
356  */
357  ifr.ifr_flags |= IFF_UP | IFF_RUNNING;
358  if (-1 == ioctl (fd, SIOCSIFFLAGS, &ifr))
359  {
360  fprintf (stderr,
361  "ioctl failed at line %d: %s\n",
362  __LINE__,
363  strerror (errno));
364  (void) close (fd);
365  exit (1);
366  }
367 
368  if (0 != close (fd))
369  {
370  fprintf (stderr,
371  "close failed at line %d: %s\n",
372  __LINE__,
373  strerror (errno));
374  exit (1);
375  }
376 }

References address.

Referenced by main().

Here is the caller graph for this function:

◆ run()

static void run ( int  fd_tun)
static

Start forwarding to and from the tunnel.

Parameters
fd_tuntunnel FD

Definition at line 385 of file gnunet-helper-vpn.c.

386 {
387  /*
388  * The buffer filled by reading from fd_tun
389  */
390  unsigned char buftun[MAX_SIZE];
391  ssize_t buftun_size = 0;
392  unsigned char *buftun_read = NULL;
393 
394  /*
395  * The buffer filled by reading from stdin
396  */
397  unsigned char bufin[MAX_SIZE];
398  ssize_t bufin_size = 0;
399  size_t bufin_rpos = 0;
400  unsigned char *bufin_read = NULL;
401 
402  fd_set fds_w;
403  fd_set fds_r;
404 
405  /* read refers to reading from fd_tun, writing to stdout */
406  int read_open = 1;
407 
408  /* write refers to reading from stdin, writing to fd_tun */
409  int write_open = 1;
410 
411  while ((1 == read_open) && (1 == write_open))
412  {
413  FD_ZERO (&fds_w);
414  FD_ZERO (&fds_r);
415 
416  /*
417  * We are supposed to read and the buffer is empty
418  * -> select on read from tun
419  */
420  if (read_open && (0 == buftun_size))
421  FD_SET (fd_tun, &fds_r);
422 
423  /*
424  * We are supposed to read and the buffer is not empty
425  * -> select on write to stdout
426  */
427  if (read_open && (0 != buftun_size))
428  FD_SET (1, &fds_w);
429 
430  /*
431  * We are supposed to write and the buffer is empty
432  * -> select on read from stdin
433  */
434  if (write_open && (NULL == bufin_read))
435  FD_SET (0, &fds_r);
436 
437  /*
438  * We are supposed to write and the buffer is not empty
439  * -> select on write to tun
440  */
441  if (write_open && (NULL != bufin_read))
442  FD_SET (fd_tun, &fds_w);
443 
444  int r = select (fd_tun + 1, &fds_r, &fds_w, NULL, NULL);
445 
446  if (-1 == r)
447  {
448  if (EINTR == errno)
449  continue;
450  fprintf (stderr,
451  "select failed: %s\n",
452  strerror (errno));
453  exit (1);
454  }
455 
456  if (r > 0)
457  {
458  if (FD_ISSET (fd_tun, &fds_r))
459  {
460  buftun_size =
461  read (fd_tun, buftun + sizeof(struct GNUNET_MessageHeader),
462  MAX_SIZE - sizeof(struct GNUNET_MessageHeader));
463  if (-1 == buftun_size)
464  {
465  fprintf (stderr,
466  "read-error: %s\n",
467  strerror (errno));
468  shutdown (fd_tun, SHUT_RD);
469  shutdown (1, SHUT_WR);
470  read_open = 0;
471  buftun_size = 0;
472  }
473  else if (0 == buftun_size)
474  {
475  fprintf (stderr, "EOF on tun\n");
476  shutdown (fd_tun, SHUT_RD);
477  shutdown (1, SHUT_WR);
478  read_open = 0;
479  buftun_size = 0;
480  }
481  else
482  {
483  buftun_read = buftun;
484  struct GNUNET_MessageHeader *hdr =
485  (struct GNUNET_MessageHeader *) buftun;
486  buftun_size += sizeof(struct GNUNET_MessageHeader);
487  hdr->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
488  hdr->size = htons (buftun_size);
489  }
490  }
491  else if (FD_ISSET (1, &fds_w))
492  {
493  ssize_t written = write (1,
494  buftun_read,
495  buftun_size);
496 
497  if (-1 == written)
498  {
499 #if ! DEBUG
500  if (errno != EPIPE)
501 #endif
502  fprintf (stderr,
503  "write-error to stdout: %s\n",
504  strerror (errno));
505  shutdown (fd_tun, SHUT_RD);
506  shutdown (1, SHUT_WR);
507  read_open = 0;
508  buftun_size = 0;
509  }
510  else if (0 == written)
511  {
512  fprintf (stderr,
513  "write returned 0!?\n");
514  exit (1);
515  }
516  else
517  {
518  buftun_size -= written;
519  buftun_read += written;
520  }
521  }
522 
523  if (FD_ISSET (0, &fds_r))
524  {
525  bufin_size = read (0, bufin + bufin_rpos, MAX_SIZE - bufin_rpos);
526  if (-1 == bufin_size)
527  {
528  fprintf (stderr,
529  "read-error: %s\n",
530  strerror (errno));
531  shutdown (0, SHUT_RD);
532  shutdown (fd_tun, SHUT_WR);
533  write_open = 0;
534  bufin_size = 0;
535  }
536  else if (0 == bufin_size)
537  {
538 #if DEBUG
539  fprintf (stderr, "EOF on stdin\n");
540 #endif
541  shutdown (0, SHUT_RD);
542  shutdown (fd_tun, SHUT_WR);
543  write_open = 0;
544  bufin_size = 0;
545  }
546  else
547  {
548  struct GNUNET_MessageHeader *hdr;
549 
550 PROCESS_BUFFER:
551  bufin_rpos += bufin_size;
552  if (bufin_rpos < sizeof(struct GNUNET_MessageHeader))
553  continue;
554  hdr = (struct GNUNET_MessageHeader *) bufin;
555  if (ntohs (hdr->type) != GNUNET_MESSAGE_TYPE_VPN_HELPER)
556  {
557  fprintf (stderr,
558  "protocol violation!\n");
559  exit (1);
560  }
561  if (ntohs (hdr->size) > bufin_rpos)
562  continue;
563  bufin_read = bufin + sizeof(struct GNUNET_MessageHeader);
564  bufin_size = ntohs (hdr->size) - sizeof(struct GNUNET_MessageHeader);
565  bufin_rpos -= bufin_size + sizeof(struct GNUNET_MessageHeader);
566  }
567  }
568  else if (FD_ISSET (fd_tun, &fds_w))
569  {
570  ssize_t written = write (fd_tun,
571  bufin_read,
572  bufin_size);
573 
574  if (-1 == written)
575  {
576  fprintf (stderr,
577  "write-error to tun: %s\n",
578  strerror (errno));
579  shutdown (0, SHUT_RD);
580  shutdown (fd_tun, SHUT_WR);
581  write_open = 0;
582  bufin_size = 0;
583  }
584  else if (0 == written)
585  {
586  fprintf (stderr, "write returned 0!?\n");
587  exit (1);
588  }
589  else
590  {
591  bufin_size -= written;
592  bufin_read += written;
593  if (0 == bufin_size)
594  {
595  memmove (bufin, bufin_read, bufin_rpos);
596  bufin_read = NULL; /* start reading again */
597  bufin_size = 0;
598  goto PROCESS_BUFFER;
599  }
600  }
601  }
602  }
603  }
604 }
#define MAX_SIZE
Maximum size of a GNUnet message (GNUNET_MAX_MESSAGE_SIZE)
#define GNUNET_MESSAGE_TYPE_VPN_HELPER
Type of messages between the gnunet-vpn-helper and the daemon.
Header for all communications.
uint16_t type
The type of the message (GNUNET_MESSAGE_TYPE_XXXX), in big-endian format.
uint16_t size
The length of the struct (in bytes, including the length field itself), in big-endian format.

References GNUNET_MESSAGE_TYPE_VPN_HELPER, MAX_SIZE, GNUNET_MessageHeader::size, and GNUNET_MessageHeader::type.

Referenced by main().

Here is the caller graph for this function:

◆ main()

int main ( int  argc,
char **  argv 
)

Open VPN tunnel interface.

Parameters
argcmust be 6
argv0: binary name (gnunet-helper-vpn) 1: tunnel interface name (gnunet-vpn) 2: IPv6 address (::1), "-" to disable 3: IPv6 netmask length in bits (64), ignored if #2 is "-" 4: IPv4 address (1.2.3.4), "-" to disable 5: IPv4 netmask (255.255.0.0), ignored if #4 is "-"

Definition at line 619 of file gnunet-helper-vpn.c.

620 {
621  char dev[IFNAMSIZ];
622  int fd_tun;
623  int global_ret;
624 
625  if (6 != argc)
626  {
627  fprintf (stderr, "Fatal: must supply 5 arguments!\n");
628  return 1;
629  }
630 
631  strncpy (dev,
632  argv[1],
633  IFNAMSIZ);
634  dev[IFNAMSIZ - 1] = '\0';
635 
636  if (-1 == (fd_tun = init_tun (dev)))
637  {
638  fprintf (stderr,
639  "Fatal: could not initialize tun-interface `%s' with IPv6 %s/%s and IPv4 %s/%s\n",
640  dev,
641  argv[2],
642  argv[3],
643  argv[4],
644  argv[5]);
645  return 1;
646  }
647 
648  if (0 != strcmp (argv[2], "-"))
649  {
650  const char *address = argv[2];
651  long prefix_len = atol (argv[3]);
652 
653  if ((prefix_len < 1) || (prefix_len > 127))
654  {
655  fprintf (stderr,
656  "Fatal: prefix_len out of range\n");
657  (void) close (fd_tun);
658  return 1;
659  }
660 
661  set_address6 (dev,
662  address,
663  prefix_len);
664  }
665 
666  if (0 != strcmp (argv[4], "-"))
667  {
668  const char *address = argv[4];
669  const char *mask = argv[5];
670 
671  set_address4 (dev, address, mask);
672  }
673 
674  uid_t uid = getuid ();
675 #ifdef HAVE_SETRESUID
676  if (0 != setresuid (uid, uid, uid))
677  {
678  fprintf (stderr,
679  "Failed to setresuid: %s\n",
680  strerror (errno));
681  global_ret = 2;
682  goto cleanup;
683  }
684 #else
685  if (0 != (setuid (uid) | seteuid (uid)))
686  {
687  fprintf (stderr,
688  "Failed to setuid: %s\n",
689  strerror (errno));
690  global_ret = 2;
691  goto cleanup;
692  }
693 #endif
694 
695  if (SIG_ERR == signal (SIGPIPE, SIG_IGN))
696  {
697  fprintf (stderr,
698  "Failed to protect against SIGPIPE: %s\n",
699  strerror (errno));
700  /* no exit, we might as well die with SIGPIPE should it ever happen */
701  }
702  run (fd_tun);
703  global_ret = 0;
704 cleanup:
705  (void) close (fd_tun);
706  return global_ret;
707 }
static void cleanup(void *cls)
Function scheduled as very last function, cleans up after us.
static void run(int fd_tun)
Start forwarding to and from the tunnel.
static int init_tun(char *dev)
Creates a tun-interface called dev;.
static void set_address4(const char *dev, const char *address, const char *mask)
Sets the IPv4-Address given in address on the interface dev.
static void set_address6(const char *dev, const char *address, unsigned long prefix_len)
Sets the IPv6-Address given in address on the interface dev.
static int global_ret
Return value from main.

References address, cleanup(), global_ret, init_tun(), run(), set_address4(), and set_address6().

Here is the call graph for this function: