GNUnet  0.20.0
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_util_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
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 at line %d: %s\n",
250  __LINE__,
251  strerror (errno));
252  exit (1);
253  }
254 }
255 
256 
264 static void
265 set_address4 (const char *dev,
266  const char *address,
267  const char *mask)
268 {
269  int fd;
270  struct sockaddr_in *addr;
271  struct ifreq ifr;
272 
273  memset (&ifr, 0, sizeof(struct ifreq));
274  addr = (struct sockaddr_in *) &(ifr.ifr_addr);
275  addr->sin_family = AF_INET;
276 
277  /*
278  * Parse the address
279  */
280  if (1 != inet_pton (AF_INET,
281  address,
282  &addr->sin_addr.s_addr))
283  {
284  fprintf (stderr,
285  "Failed to parse IPv4 address `%s'\n",
286  address);
287  exit (1);
288  }
289 
290  if (-1 == (fd = socket (PF_INET, SOCK_DGRAM, 0)))
291  {
292  fprintf (stderr,
293  "Error creating socket: %s\n",
294  strerror (errno));
295  exit (1);
296  }
297 
298  strncpy (ifr.ifr_name, dev, IFNAMSIZ);
299 
300  /*
301  * Set the address
302  */
303  if (-1 == ioctl (fd, SIOCSIFADDR, &ifr))
304  {
305  fprintf (stderr,
306  "ioctl failed at %d: %s\n",
307  __LINE__,
308  strerror (errno));
309  (void) close (fd);
310  exit (1);
311  }
312 
313  /*
314  * Parse the netmask
315  */
316  addr = (struct sockaddr_in *) &(ifr.ifr_netmask);
317  if (1 != inet_pton (AF_INET,
318  mask,
319  &addr->sin_addr.s_addr))
320  {
321  fprintf (stderr,
322  "Failed to parse IPv4 address mask `%s'\n",
323  mask);
324  (void) close (fd);
325  exit (1);
326  }
327 
328  /*
329  * Set the netmask
330  */
331  if (-1 == ioctl (fd, SIOCSIFNETMASK, &ifr))
332  {
333  fprintf (stderr,
334  "ioctl failed at line %d: %s\n",
335  __LINE__,
336  strerror (errno));
337  (void) close (fd);
338  exit (1);
339  }
340 
341  /*
342  * Get the flags
343  */
344  if (-1 == ioctl (fd, SIOCGIFFLAGS, &ifr))
345  {
346  fprintf (stderr,
347  "ioctl failed at line %d: %s\n",
348  __LINE__,
349  strerror (errno));
350  (void) close (fd);
351  exit (1);
352  }
353 
354  /*
355  * Add the UP and RUNNING flags
356  */
357  ifr.ifr_flags |= IFF_UP | IFF_RUNNING;
358  if (-1 == ioctl (fd, SIOCSIFFLAGS, &ifr))
359  {
360  fprintf (stderr,
361  "ioctl failed at line %d: %s\n",
362  __LINE__,
363  strerror (errno));
364  (void) close (fd);
365  exit (1);
366  }
367 
368  if (0 != close (fd))
369  {
370  fprintf (stderr,
371  "close failed at line %d: %s\n",
372  __LINE__,
373  strerror (errno));
374  exit (1);
375  }
376 }
377 
378 
384 static void
385 run (int fd_tun)
386 {
387  /*
388  * The buffer filled by reading from fd_tun
389  */
390  unsigned char buftun[MAX_SIZE];
391  ssize_t buftun_size = 0;
392  unsigned char *buftun_read = NULL;
393 
394  /*
395  * The buffer filled by reading from stdin
396  */
397  unsigned char bufin[MAX_SIZE];
398  ssize_t bufin_size = 0;
399  size_t bufin_rpos = 0;
400  unsigned char *bufin_read = NULL;
401 
402  fd_set fds_w;
403  fd_set fds_r;
404 
405  /* read refers to reading from fd_tun, writing to stdout */
406  int read_open = 1;
407 
408  /* write refers to reading from stdin, writing to fd_tun */
409  int write_open = 1;
410 
411  while ((1 == read_open) && (1 == write_open))
412  {
413  FD_ZERO (&fds_w);
414  FD_ZERO (&fds_r);
415 
416  /*
417  * We are supposed to read and the buffer is empty
418  * -> select on read from tun
419  */
420  if (read_open && (0 == buftun_size))
421  FD_SET (fd_tun, &fds_r);
422 
423  /*
424  * We are supposed to read and the buffer is not empty
425  * -> select on write to stdout
426  */
427  if (read_open && (0 != buftun_size))
428  FD_SET (1, &fds_w);
429 
430  /*
431  * We are supposed to write and the buffer is empty
432  * -> select on read from stdin
433  */
434  if (write_open && (NULL == bufin_read))
435  FD_SET (0, &fds_r);
436 
437  /*
438  * We are supposed to write and the buffer is not empty
439  * -> select on write to tun
440  */
441  if (write_open && (NULL != bufin_read))
442  FD_SET (fd_tun, &fds_w);
443 
444  int r = select (fd_tun + 1, &fds_r, &fds_w, NULL, NULL);
445 
446  if (-1 == r)
447  {
448  if (EINTR == errno)
449  continue;
450  fprintf (stderr,
451  "select failed: %s\n",
452  strerror (errno));
453  exit (1);
454  }
455 
456  if (r > 0)
457  {
458  if (FD_ISSET (fd_tun, &fds_r))
459  {
460  buftun_size =
461  read (fd_tun, buftun + sizeof(struct GNUNET_MessageHeader),
462  MAX_SIZE - sizeof(struct GNUNET_MessageHeader));
463  if (-1 == buftun_size)
464  {
465  fprintf (stderr,
466  "read-error: %s\n",
467  strerror (errno));
468  shutdown (fd_tun, SHUT_RD);
469  shutdown (1, SHUT_WR);
470  read_open = 0;
471  buftun_size = 0;
472  }
473  else if (0 == buftun_size)
474  {
475  fprintf (stderr, "EOF on tun\n");
476  shutdown (fd_tun, SHUT_RD);
477  shutdown (1, SHUT_WR);
478  read_open = 0;
479  buftun_size = 0;
480  }
481  else
482  {
483  buftun_read = buftun;
484  struct GNUNET_MessageHeader *hdr =
485  (struct GNUNET_MessageHeader *) buftun;
486  buftun_size += sizeof(struct GNUNET_MessageHeader);
487  hdr->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
488  hdr->size = htons (buftun_size);
489  }
490  }
491  else if (FD_ISSET (1, &fds_w))
492  {
493  ssize_t written = write (1,
494  buftun_read,
495  buftun_size);
496 
497  if (-1 == written)
498  {
499 #if ! DEBUG
500  if (errno != EPIPE)
501 #endif
502  fprintf (stderr,
503  "write-error to stdout: %s\n",
504  strerror (errno));
505  shutdown (fd_tun, SHUT_RD);
506  shutdown (1, SHUT_WR);
507  read_open = 0;
508  buftun_size = 0;
509  }
510  else if (0 == written)
511  {
512  fprintf (stderr,
513  "write returned 0!?\n");
514  exit (1);
515  }
516  else
517  {
518  buftun_size -= written;
519  buftun_read += written;
520  }
521  }
522 
523  if (FD_ISSET (0, &fds_r))
524  {
525  bufin_size = read (0, bufin + bufin_rpos, MAX_SIZE - bufin_rpos);
526  if (-1 == bufin_size)
527  {
528  fprintf (stderr,
529  "read-error: %s\n",
530  strerror (errno));
531  shutdown (0, SHUT_RD);
532  shutdown (fd_tun, SHUT_WR);
533  write_open = 0;
534  bufin_size = 0;
535  }
536  else if (0 == bufin_size)
537  {
538 #if DEBUG
539  fprintf (stderr, "EOF on stdin\n");
540 #endif
541  shutdown (0, SHUT_RD);
542  shutdown (fd_tun, SHUT_WR);
543  write_open = 0;
544  bufin_size = 0;
545  }
546  else
547  {
548  struct GNUNET_MessageHeader *hdr;
549 
550 PROCESS_BUFFER:
551  bufin_rpos += bufin_size;
552  if (bufin_rpos < sizeof(struct GNUNET_MessageHeader))
553  continue;
554  hdr = (struct GNUNET_MessageHeader *) bufin;
555  if (ntohs (hdr->type) != GNUNET_MESSAGE_TYPE_VPN_HELPER)
556  {
557  fprintf (stderr,
558  "protocol violation!\n");
559  exit (1);
560  }
561  if (ntohs (hdr->size) > bufin_rpos)
562  continue;
563  bufin_read = bufin + sizeof(struct GNUNET_MessageHeader);
564  bufin_size = ntohs (hdr->size) - sizeof(struct GNUNET_MessageHeader);
565  bufin_rpos -= bufin_size + sizeof(struct GNUNET_MessageHeader);
566  }
567  }
568  else if (FD_ISSET (fd_tun, &fds_w))
569  {
570  ssize_t written = write (fd_tun,
571  bufin_read,
572  bufin_size);
573 
574  if (-1 == written)
575  {
576  fprintf (stderr,
577  "write-error to tun: %s\n",
578  strerror (errno));
579  shutdown (0, SHUT_RD);
580  shutdown (fd_tun, SHUT_WR);
581  write_open = 0;
582  bufin_size = 0;
583  }
584  else if (0 == written)
585  {
586  fprintf (stderr, "write returned 0!?\n");
587  exit (1);
588  }
589  else
590  {
591  bufin_size -= written;
592  bufin_read += written;
593  if (0 == bufin_size)
594  {
595  memmove (bufin, bufin_read, bufin_rpos);
596  bufin_read = NULL; /* start reading again */
597  bufin_size = 0;
598  goto PROCESS_BUFFER;
599  }
600  }
601  }
602  }
603  }
604 }
605 
606 
618 int
619 main (int argc, char **argv)
620 {
621  char dev[IFNAMSIZ];
622  int fd_tun;
623  int global_ret;
624 
625  if (6 != argc)
626  {
627  fprintf (stderr, "Fatal: must supply 5 arguments!\n");
628  return 1;
629  }
630 
631  strncpy (dev,
632  argv[1],
633  IFNAMSIZ);
634  dev[IFNAMSIZ - 1] = '\0';
635 
636  if (-1 == (fd_tun = init_tun (dev)))
637  {
638  fprintf (stderr,
639  "Fatal: could not initialize tun-interface `%s' with IPv6 %s/%s and IPv4 %s/%s\n",
640  dev,
641  argv[2],
642  argv[3],
643  argv[4],
644  argv[5]);
645  return 1;
646  }
647 
648  if (0 != strcmp (argv[2], "-"))
649  {
650  const char *address = argv[2];
651  long prefix_len = atol (argv[3]);
652 
653  if ((prefix_len < 1) || (prefix_len > 127))
654  {
655  fprintf (stderr,
656  "Fatal: prefix_len out of range\n");
657  (void) close (fd_tun);
658  return 1;
659  }
660 
661  set_address6 (dev,
662  address,
663  prefix_len);
664  }
665 
666  if (0 != strcmp (argv[4], "-"))
667  {
668  const char *address = argv[4];
669  const char *mask = argv[5];
670 
671  set_address4 (dev, address, mask);
672  }
673 
674  uid_t uid = getuid ();
675 #ifdef HAVE_SETRESUID
676  if (0 != setresuid (uid, uid, uid))
677  {
678  fprintf (stderr,
679  "Failed to setresuid: %s\n",
680  strerror (errno));
681  global_ret = 2;
682  goto cleanup;
683  }
684 #else
685  if (0 != (setuid (uid) | seteuid (uid)))
686  {
687  fprintf (stderr,
688  "Failed to setuid: %s\n",
689  strerror (errno));
690  global_ret = 2;
691  goto cleanup;
692  }
693 #endif
694 
695  if (SIG_ERR == signal (SIGPIPE, SIG_IGN))
696  {
697  fprintf (stderr,
698  "Failed to protect against SIGPIPE: %s\n",
699  strerror (errno));
700  /* no exit, we might as well die with SIGPIPE should it ever happen */
701  }
702  run (fd_tun);
703  global_ret = 0;
704 cleanup:
705  (void) close (fd_tun);
706  return global_ret;
707 }
static char * address
GNS address for this phone.
static void cleanup(void *cls)
Function scheduled as very last function, cleans up after us.
#define MAX_SIZE
Maximum size of a GNUnet message (GNUNET_MAX_MESSAGE_SIZE)
static void run(int fd_tun)
Start forwarding to and from the tunnel.
int main(int argc, char **argv)
Open VPN tunnel interface.
static int init_tun(char *dev)
Creates a tun-interface called dev;.
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 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 int global_ret
Return value from main.
commonly used definitions; globals in this file are exempt from the rule that the module name ("commo...
Constants for network protocols.
#define GNUNET_MESSAGE_TYPE_VPN_HELPER
Type of messages between the gnunet-vpn-helper and the daemon.
Header for all communications.
uint16_t type
The type of the message (GNUNET_MESSAGE_TYPE_XXXX), in big-endian format.
uint16_t size
The length of the struct (in bytes, including the length field itself), in big-endian format.
This is in linux/include/net/ipv6.h, but not always exported...
uint32_t ifr6_prefixlen
struct in6_addr ifr6_addr
unsigned int ifr6_ifindex