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 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 83 of file gnunet-helper-vpn.c.

Referenced by main().

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

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

Referenced by main().

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

Referenced by main().

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

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

Referenced by main().

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

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

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