GNUnet  0.10.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 80 of file gnunet-helper-vpn.c.

Referenced by main().

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

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

Referenced by main().

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

Referenced by main().

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

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

Referenced by main().

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

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

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