GNUnet  0.11.x
gnunet-helper-vpn.c
Go to the documentation of this file.
1 /*
2  This file is part of GNUnet.
3  Copyright (C) 2010, 2012 Christian Grothoff
4 
5  GNUnet is free software: you can redistribute it and/or modify it
6  under the terms of the GNU Affero General Public License as published
7  by the Free Software Foundation, either version 3 of the License,
8  or (at your option) any later version.
9 
10  GNUnet is distributed in the hope that it will be useful, but
11  WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  Affero General Public License for more details.
14 
15  You should have received a copy of the GNU Affero General Public License
16  along with this program. If not, see <http://www.gnu.org/licenses/>.
17 
18  SPDX-License-Identifier: AGPL3.0-or-later
19  */
20 
35 #include "platform.h"
36 #ifdef IF_TUN_HDR
37 #include IF_TUN_HDR
38 #endif
39 
43 #include "gnunet_crypto_lib.h"
44 #include "gnunet_common.h"
45 
49 #include "gnunet_protocols.h"
50 
55 #define DEBUG GNUNET_NO
56 
60 #define MAX_SIZE 65536
61 
62 #if ! defined(__ANDROID__)
63 #ifndef _LINUX_IN6_H
64 
67 struct in6_ifreq
68 {
69  struct in6_addr ifr6_addr;
70  uint32_t ifr6_prefixlen;
71  unsigned int ifr6_ifindex;
72 };
73 #endif
74 #endif
75 
76 
84 static int
85 init_tun (char *dev)
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 }
136 
137 
145 static void
146 set_address6 (const char *dev,
147  const char *address,
148  unsigned long prefix_len)
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 }
254 
255 
263 static void
264 set_address4 (const char *dev,
265  const char *address,
266  const char *mask)
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 }
376 
377 
383 static void
384 run (int fd_tun)
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 }
604 
605 
617 int
618 main (int argc, char **argv)
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.
uint32_t ifr6_prefixlen
static void set_address4(const char *dev, const char *address, const char *mask)
Sets the IPv4-Address given in address on the interface dev.
struct in6_addr ifr6_addr
uint16_t size
The length of the struct (in bytes, including the length field itself), in big-endian format...
static int init_tun(char *dev)
Creates a tun-interface called dev;.
cryptographic primitives for GNUnet
uint16_t type
The type of the message (GNUNET_MESSAGE_TYPE_XXXX), in big-endian format.
static void cleanup(void *cls)
Function scheduled as very last function, cleans up after us.
This is in linux/include/net/ipv6.h, but not always exported...
int main(int argc, char **argv)
Open VPN tunnel interface.
Header for all communications.
commonly used definitions; globals in this file are exempt from the rule that the module name ("commo...
unsigned int ifr6_ifindex
static char * address
GNS address for this phone.
static int global_ret
Return value from main.
#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.