GNUnet  0.11.x
Data Structures | Macros | Functions
gnunet-helper-vpn.c File Reference

the helper for the VPN service. More...

#include "platform.h"
#include "gnunet_crypto_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):

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.

Referenced by run().

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.

Referenced by main().

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 }
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.

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

Referenced by main().

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: %s\n",
250  strerror (errno));
251  exit (1);
252  }
253 }
This is in linux/include/net/ipv6.h, but not always exported...
static char * address
GNS address for this phone.
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 264 of file gnunet-helper-vpn.c.

Referenced by main().

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

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

Referenced by main().

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

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

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