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 <linux/if_tun.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 53 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 58 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 asumed 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 81 of file gnunet-helper-vpn.c.

Referenced by main().

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

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

Referenced by main().

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

Referenced by main().

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

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

Referenced by main().

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

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

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