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 #ifndef _LINUX_IN6_H
63 
66 struct in6_ifreq
67 {
68  struct in6_addr ifr6_addr;
69  uint32_t ifr6_prefixlen;
70  unsigned int ifr6_ifindex;
71 };
72 #endif
73 
74 
82 static int
83 init_tun (char *dev)
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 }
134 
135 
143 static void
144 set_address6 (const char *dev,
145  const char *address,
146  unsigned long prefix_len)
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 }
252 
253 
261 static void
262 set_address4 (const char *dev,
263  const char *address,
264  const char *mask)
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 }
374 
375 
381 static void
382 run (int fd_tun)
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 }
602 
603 
615 int
616 main (int argc, char **argv)
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.
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.