GNUnet  0.10.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 #include <linux/if_tun.h>
37 
41 #include "gnunet_crypto_lib.h"
42 #include "gnunet_common.h"
43 
47 #include "gnunet_protocols.h"
48 
53 #define DEBUG GNUNET_NO
54 
58 #define MAX_SIZE 65536
59 
60 #ifndef _LINUX_IN6_H
61 
64 struct in6_ifreq
65 {
66  struct in6_addr ifr6_addr;
67  uint32_t ifr6_prefixlen;
68  unsigned int ifr6_ifindex;
69 };
70 #endif
71 
72 
80 static int
81 init_tun (char *dev)
82 {
83  struct ifreq ifr;
84  int fd;
85 
86  if (NULL == dev)
87  {
88  errno = EINVAL;
89  return -1;
90  }
91 
92  if (-1 == (fd = open ("/dev/net/tun", O_RDWR)))
93  {
94  fprintf (stderr,
95  "Error opening `%s': %s\n",
96  "/dev/net/tun",
97  strerror (errno));
98  return -1;
99  }
100 
101  if (fd >= FD_SETSIZE)
102  {
103  fprintf (stderr,
104  "File descriptor to large: %d",
105  fd);
106  (void) close (fd);
107  return -1;
108  }
109 
110  memset (&ifr, 0, sizeof (ifr));
111  ifr.ifr_flags = IFF_TUN;
112 
113  if ('\0' != *dev)
114  strncpy (ifr.ifr_name,
115  dev,
116  IFNAMSIZ);
117 
118  if (-1 == ioctl (fd,
119  TUNSETIFF,
120  (void *) &ifr))
121  {
122  fprintf (stderr,
123  "Error with ioctl on `%s': %s\n",
124  "/dev/net/tun",
125  strerror (errno));
126  (void) close (fd);
127  return -1;
128  }
129  strcpy (dev, ifr.ifr_name);
130  return fd;
131 }
132 
133 
141 static void
142 set_address6 (const char *dev,
143  const char *address,
144  unsigned long prefix_len)
145 {
146  struct ifreq ifr;
147  struct in6_ifreq ifr6;
148  struct sockaddr_in6 sa6;
149  int fd;
150 
151  /*
152  * parse the new address
153  */
154  memset (&sa6, 0, sizeof (struct sockaddr_in6));
155  sa6.sin6_family = AF_INET6;
156  if (1 != inet_pton (AF_INET6, address, sa6.sin6_addr.s6_addr))
157  {
158  fprintf (stderr,
159  "Failed to parse IPv6 address `%s'\n",
160  address);
161  exit (1);
162  }
163 
164  if (-1 == (fd = socket (PF_INET6, SOCK_DGRAM, 0)))
165  {
166  fprintf (stderr,
167  "Error creating socket: %s\n",
168  strerror (errno));
169  exit (1);
170  }
171 
172  memset (&ifr, 0, sizeof (struct ifreq));
173  /*
174  * Get the index of the if
175  */
176  strncpy (ifr.ifr_name,
177  dev,
178  IFNAMSIZ);
179  if (-1 == ioctl (fd,
180  SIOGIFINDEX,
181  &ifr))
182  {
183  fprintf (stderr,
184  "ioctl failed at %d: %s\n",
185  __LINE__,
186  strerror (errno));
187  (void) close (fd);
188  exit (1);
189  }
190 
191  memset (&ifr6, 0, sizeof (struct in6_ifreq));
192  ifr6.ifr6_addr = sa6.sin6_addr;
193  ifr6.ifr6_ifindex = ifr.ifr_ifindex;
194  ifr6.ifr6_prefixlen = prefix_len;
195 
196  /*
197  * Set the address
198  */
199  if (-1 == ioctl (fd,
200  SIOCSIFADDR,
201  &ifr6))
202  {
203  fprintf (stderr,
204  "ioctl failed at line %d: %s\n",
205  __LINE__,
206  strerror (errno));
207  (void) close (fd);
208  exit (1);
209  }
210 
211  /*
212  * Get the flags
213  */
214  if (-1 == ioctl (fd,
215  SIOCGIFFLAGS,
216  &ifr))
217  {
218  fprintf (stderr,
219  "ioctl failed at line %d: %s\n",
220  __LINE__,
221  strerror (errno));
222  (void) close (fd);
223  exit (1);
224  }
225 
226  /*
227  * Add the UP and RUNNING flags
228  */
229  ifr.ifr_flags |= IFF_UP | IFF_RUNNING;
230  if (-1 == ioctl (fd,
231  SIOCSIFFLAGS,
232  &ifr))
233  {
234  fprintf (stderr,
235  "ioctl failed at line %d: %s\n",
236  __LINE__,
237  strerror (errno));
238  (void) close (fd);
239  exit (1);
240  }
241 
242  if (0 != close (fd))
243  {
244  fprintf (stderr,
245  "close failed: %s\n",
246  strerror (errno));
247  exit (1);
248  }
249 }
250 
251 
259 static void
260 set_address4 (const char *dev,
261  const char *address,
262  const char *mask)
263 {
264  int fd;
265  struct sockaddr_in *addr;
266  struct ifreq ifr;
267 
268  memset (&ifr, 0, sizeof (struct ifreq));
269  addr = (struct sockaddr_in *) &(ifr.ifr_addr);
270  addr->sin_family = AF_INET;
271 
272  /*
273  * Parse the address
274  */
275  if (1 != inet_pton (AF_INET,
276  address,
277  &addr->sin_addr.s_addr))
278  {
279  fprintf (stderr,
280  "Failed to parse IPv4 address `%s'\n",
281  address);
282  exit (1);
283  }
284 
285  if (-1 == (fd = socket (PF_INET, SOCK_DGRAM, 0)))
286  {
287  fprintf (stderr,
288  "Error creating socket: %s\n",
289  strerror (errno));
290  exit (1);
291  }
292 
293  strncpy (ifr.ifr_name, dev, IFNAMSIZ);
294 
295  /*
296  * Set the address
297  */
298  if (-1 == ioctl (fd, SIOCSIFADDR, &ifr))
299  {
300  fprintf (stderr,
301  "ioctl failed at %d: %s\n",
302  __LINE__,
303  strerror (errno));
304  (void) close (fd);
305  exit (1);
306  }
307 
308  /*
309  * Parse the netmask
310  */
311  addr = (struct sockaddr_in *) &(ifr.ifr_netmask);
312  if (1 != inet_pton (AF_INET,
313  mask,
314  &addr->sin_addr.s_addr))
315  {
316  fprintf (stderr,
317  "Failed to parse IPv4 address mask `%s'\n",
318  mask);
319  (void) close (fd);
320  exit (1);
321  }
322 
323  /*
324  * Set the netmask
325  */
326  if (-1 == ioctl (fd, SIOCSIFNETMASK, &ifr))
327  {
328  fprintf (stderr,
329  "ioctl failed at line %d: %s\n",
330  __LINE__,
331  strerror (errno));
332  (void) close (fd);
333  exit (1);
334  }
335 
336  /*
337  * Get the flags
338  */
339  if (-1 == ioctl (fd, SIOCGIFFLAGS, &ifr))
340  {
341  fprintf (stderr,
342  "ioctl failed at line %d: %s\n",
343  __LINE__,
344  strerror (errno));
345  (void) close (fd);
346  exit (1);
347  }
348 
349  /*
350  * Add the UP and RUNNING flags
351  */
352  ifr.ifr_flags |= IFF_UP | IFF_RUNNING;
353  if (-1 == ioctl (fd, SIOCSIFFLAGS, &ifr))
354  {
355  fprintf (stderr,
356  "ioctl failed at line %d: %s\n",
357  __LINE__,
358  strerror (errno));
359  (void) close (fd);
360  exit (1);
361  }
362 
363  if (0 != close (fd))
364  {
365  fprintf (stderr,
366  "close failed: %s\n",
367  strerror (errno));
368  (void) close (fd);
369  exit (1);
370  }
371 }
372 
373 
379 static void
380 run (int fd_tun)
381 {
382  /*
383  * The buffer filled by reading from fd_tun
384  */
385  unsigned char buftun[MAX_SIZE];
386  ssize_t buftun_size = 0;
387  unsigned char *buftun_read = NULL;
388 
389  /*
390  * The buffer filled by reading from stdin
391  */
392  unsigned char bufin[MAX_SIZE];
393  ssize_t bufin_size = 0;
394  size_t bufin_rpos = 0;
395  unsigned char *bufin_read = NULL;
396 
397  fd_set fds_w;
398  fd_set fds_r;
399 
400  /* read refers to reading from fd_tun, writing to stdout */
401  int read_open = 1;
402 
403  /* write refers to reading from stdin, writing to fd_tun */
404  int write_open = 1;
405 
406  while ((1 == read_open) && (1 == write_open))
407  {
408  FD_ZERO (&fds_w);
409  FD_ZERO (&fds_r);
410 
411  /*
412  * We are supposed to read and the buffer is empty
413  * -> select on read from tun
414  */
415  if (read_open && (0 == buftun_size))
416  FD_SET (fd_tun, &fds_r);
417 
418  /*
419  * We are supposed to read and the buffer is not empty
420  * -> select on write to stdout
421  */
422  if (read_open && (0 != buftun_size))
423  FD_SET (1, &fds_w);
424 
425  /*
426  * We are supposed to write and the buffer is empty
427  * -> select on read from stdin
428  */
429  if (write_open && (NULL == bufin_read))
430  FD_SET (0, &fds_r);
431 
432  /*
433  * We are supposed to write and the buffer is not empty
434  * -> select on write to tun
435  */
436  if (write_open && (NULL != bufin_read))
437  FD_SET (fd_tun, &fds_w);
438 
439  int r = select (fd_tun + 1, &fds_r, &fds_w, NULL, NULL);
440 
441  if (-1 == r)
442  {
443  if (EINTR == errno)
444  continue;
445  fprintf (stderr,
446  "select failed: %s\n",
447  strerror (errno));
448  exit (1);
449  }
450 
451  if (r > 0)
452  {
453  if (FD_ISSET (fd_tun, &fds_r))
454  {
455  buftun_size =
456  read (fd_tun, buftun + sizeof (struct GNUNET_MessageHeader),
457  MAX_SIZE - sizeof (struct GNUNET_MessageHeader));
458  if (-1 == buftun_size)
459  {
460  fprintf (stderr,
461  "read-error: %s\n",
462  strerror (errno));
463  shutdown (fd_tun, SHUT_RD);
464  shutdown (1, SHUT_WR);
465  read_open = 0;
466  buftun_size = 0;
467  }
468  else if (0 == buftun_size)
469  {
470  fprintf (stderr, "EOF on tun\n");
471  shutdown (fd_tun, SHUT_RD);
472  shutdown (1, SHUT_WR);
473  read_open = 0;
474  buftun_size = 0;
475  }
476  else
477  {
478  buftun_read = buftun;
479  struct GNUNET_MessageHeader *hdr =
480  (struct GNUNET_MessageHeader *) buftun;
481  buftun_size += sizeof (struct GNUNET_MessageHeader);
482  hdr->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
483  hdr->size = htons (buftun_size);
484  }
485  }
486  else if (FD_ISSET (1, &fds_w))
487  {
488  ssize_t written = write (1,
489  buftun_read,
490  buftun_size);
491 
492  if (-1 == written)
493  {
494 #if !DEBUG
495  if (errno != EPIPE)
496 #endif
497  fprintf (stderr,
498  "write-error to stdout: %s\n",
499  strerror (errno));
500  shutdown (fd_tun, SHUT_RD);
501  shutdown (1, SHUT_WR);
502  read_open = 0;
503  buftun_size = 0;
504  }
505  else if (0 == written)
506  {
507  fprintf (stderr,
508  "write returned 0!?\n");
509  exit (1);
510  }
511  else
512  {
513  buftun_size -= written;
514  buftun_read += written;
515  }
516  }
517 
518  if (FD_ISSET (0, &fds_r))
519  {
520  bufin_size = read (0, bufin + bufin_rpos, MAX_SIZE - bufin_rpos);
521  if (-1 == bufin_size)
522  {
523  fprintf (stderr,
524  "read-error: %s\n",
525  strerror (errno));
526  shutdown (0, SHUT_RD);
527  shutdown (fd_tun, SHUT_WR);
528  write_open = 0;
529  bufin_size = 0;
530  }
531  else if (0 == bufin_size)
532  {
533 #if DEBUG
534  fprintf (stderr, "EOF on stdin\n");
535 #endif
536  shutdown (0, SHUT_RD);
537  shutdown (fd_tun, SHUT_WR);
538  write_open = 0;
539  bufin_size = 0;
540  }
541  else
542  {
543  struct GNUNET_MessageHeader *hdr;
544 
545 PROCESS_BUFFER:
546  bufin_rpos += bufin_size;
547  if (bufin_rpos < sizeof (struct GNUNET_MessageHeader))
548  continue;
549  hdr = (struct GNUNET_MessageHeader *) bufin;
550  if (ntohs (hdr->type) != GNUNET_MESSAGE_TYPE_VPN_HELPER)
551  {
552  fprintf (stderr,
553  "protocol violation!\n");
554  exit (1);
555  }
556  if (ntohs (hdr->size) > bufin_rpos)
557  continue;
558  bufin_read = bufin + sizeof (struct GNUNET_MessageHeader);
559  bufin_size = ntohs (hdr->size) - sizeof (struct GNUNET_MessageHeader);
560  bufin_rpos -= bufin_size + sizeof (struct GNUNET_MessageHeader);
561  }
562  }
563  else if (FD_ISSET (fd_tun, &fds_w))
564  {
565  ssize_t written = write (fd_tun,
566  bufin_read,
567  bufin_size);
568 
569  if (-1 == written)
570  {
571  fprintf (stderr,
572  "write-error to tun: %s\n",
573  strerror (errno));
574  shutdown (0, SHUT_RD);
575  shutdown (fd_tun, SHUT_WR);
576  write_open = 0;
577  bufin_size = 0;
578  }
579  else if (0 == written)
580  {
581  fprintf (stderr, "write returned 0!?\n");
582  exit (1);
583  }
584  else
585  {
586  bufin_size -= written;
587  bufin_read += written;
588  if (0 == bufin_size)
589  {
590  memmove (bufin, bufin_read, bufin_rpos);
591  bufin_read = NULL; /* start reading again */
592  bufin_size = 0;
593  goto PROCESS_BUFFER;
594  }
595  }
596  }
597  }
598  }
599 }
600 
601 
613 int
614 main (int argc, char **argv)
615 {
616  char dev[IFNAMSIZ];
617  int fd_tun;
618  int global_ret;
619 
620  if (6 != argc)
621  {
622  fprintf (stderr, "Fatal: must supply 5 arguments!\n");
623  return 1;
624  }
625 
626  strncpy (dev,
627  argv[1],
628  IFNAMSIZ);
629  dev[IFNAMSIZ - 1] = '\0';
630 
631  if (-1 == (fd_tun = init_tun (dev)))
632  {
633  fprintf (stderr,
634  "Fatal: could not initialize tun-interface `%s' with IPv6 %s/%s and IPv4 %s/%s\n",
635  dev,
636  argv[2],
637  argv[3],
638  argv[4],
639  argv[5]);
640  return 1;
641  }
642 
643  if (0 != strcmp (argv[2], "-"))
644  {
645  const char *address = argv[2];
646  long prefix_len = atol (argv[3]);
647 
648  if ((prefix_len < 1) || (prefix_len > 127))
649  {
650  fprintf (stderr,
651  "Fatal: prefix_len out of range\n");
652  close (fd_tun);
653  return 1;
654  }
655 
656  set_address6 (dev,
657  address,
658  prefix_len);
659  }
660 
661  if (0 != strcmp (argv[4], "-"))
662  {
663  const char *address = argv[4];
664  const char *mask = argv[5];
665 
666  set_address4 (dev, address, mask);
667  }
668 
669  uid_t uid = getuid ();
670 #ifdef HAVE_SETRESUID
671  if (0 != setresuid (uid, uid, uid))
672  {
673  fprintf (stderr,
674  "Failed to setresuid: %s\n",
675  strerror (errno));
676  global_ret = 2;
677  goto cleanup;
678  }
679 #else
680  if (0 != (setuid (uid) | seteuid (uid)))
681  {
682  fprintf (stderr,
683  "Failed to setuid: %s\n",
684  strerror (errno));
685  global_ret = 2;
686  goto cleanup;
687  }
688 #endif
689 
690  if (SIG_ERR == signal (SIGPIPE, SIG_IGN))
691  {
692  fprintf (stderr,
693  "Failed to protect against SIGPIPE: %s\n",
694  strerror (errno));
695  /* no exit, we might as well die with SIGPIPE should it ever happen */
696  }
697  run (fd_tun);
698  global_ret = 0;
699  cleanup:
700  close (fd_tun);
701  return global_ret;
702 }
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;.
#define FD_SETSIZE
Definition: winproc.h:39
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...
static int inet_pton(int af, const char *cp, struct in_addr *buf)
Convert IPv4 address from text to binary form.
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.