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  struct in6_addr ifr6_addr;
66  uint32_t ifr6_prefixlen;
67  unsigned int ifr6_ifindex;
68 };
69 #endif
70 
71 
79 static int
80 init_tun(char *dev)
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 }
131 
132 
140 static void
141 set_address6(const char *dev,
142  const char *address,
143  unsigned long prefix_len)
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 }
249 
250 
258 static void
259 set_address4(const char *dev,
260  const char *address,
261  const char *mask)
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 }
371 
372 
378 static void
379 run(int fd_tun)
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 }
599 
600 
612 int
613 main(int argc, char **argv)
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.
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.