GNUnet  0.10.x
gnunet-helper-exit.c
Go to the documentation of this file.
1 /*
2  This file is part of GNUnet.
3  Copyright (C) 2010, 2011, 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 
44 #include "platform.h"
45 #include <linux/if_tun.h>
46 
50 #include "gnunet_crypto_lib.h"
51 #include "gnunet_common.h"
52 
56 #include "gnunet_protocols.h"
57 
62 #define DEBUG GNUNET_NO
63 
67 #define MAX_SIZE 65536
68 
72 static const char *sbin_sysctl;
73 
77 static const char *sbin_iptables;
78 
79 
80 #ifndef _LINUX_IN6_H
81 
84 struct in6_ifreq {
85  struct in6_addr ifr6_addr;
86  uint32_t ifr6_prefixlen; /* __u32 in the original */
88 };
89 #endif
90 
91 
99 static void
100 open_dev_null(int target_fd,
101  int flags)
102 {
103  int fd;
104 
105  fd = open("/dev/null", flags);
106  if (-1 == fd)
107  abort();
108  if (fd == target_fd)
109  return;
110  if (-1 == dup2(fd, target_fd))
111  {
112  (void)close(fd);
113  abort();
114  }
115  (void)close(fd);
116 }
117 
118 
126 static int
127 fork_and_exec(const char *file,
128  char *const cmd[])
129 {
130  int status;
131  pid_t pid;
132  pid_t ret;
133 
134  pid = fork();
135  if (-1 == pid)
136  {
137  fprintf(stderr,
138  "fork failed: %s\n",
139  strerror(errno));
140  return 1;
141  }
142  if (0 == pid)
143  {
144  /* we are the child process */
145  /* close stdin/stdout to not cause interference
146  with the helper's main protocol! */
147  (void)close(0);
148  open_dev_null(0, O_RDONLY);
149  (void)close(1);
150  open_dev_null(1, O_WRONLY);
151  (void)execv(file, cmd);
152  /* can only get here on error */
153  fprintf(stderr,
154  "exec `%s' failed: %s\n",
155  file,
156  strerror(errno));
157  _exit(1);
158  }
159  /* keep running waitpid as long as the only error we get is 'EINTR' */
160  while ((-1 == (ret = waitpid(pid, &status, 0))) &&
161  (errno == EINTR))
162  ;
163  if (-1 == ret)
164  {
165  fprintf(stderr,
166  "waitpid failed: %s\n",
167  strerror(errno));
168  return 1;
169  }
170  if (!(WIFEXITED(status) && (0 == WEXITSTATUS(status))))
171  return 1;
172  /* child process completed and returned success, we're happy */
173  return 0;
174 }
175 
176 
184 static int
185 init_tun(char *dev)
186 {
187  struct ifreq ifr;
188  int fd;
189 
190  if (NULL == dev)
191  {
192  errno = EINVAL;
193  return -1;
194  }
195 
196  if (-1 == (fd = open("/dev/net/tun", O_RDWR)))
197  {
198  fprintf(stderr, "Error opening `%s': %s\n", "/dev/net/tun",
199  strerror(errno));
200  return -1;
201  }
202 
203  if (fd >= FD_SETSIZE)
204  {
205  fprintf(stderr, "File descriptor to large: %d", fd);
206  (void)close(fd);
207  return -1;
208  }
209 
210  memset(&ifr, 0, sizeof(ifr));
211  ifr.ifr_flags = IFF_TUN;
212 
213  if ('\0' != *dev)
214  strncpy(ifr.ifr_name, dev, IFNAMSIZ);
215 
216  if (-1 == ioctl(fd, TUNSETIFF, (void *)&ifr))
217  {
218  fprintf(stderr,
219  "Error with ioctl on `%s': %s\n", "/dev/net/tun",
220  strerror(errno));
221  (void)close(fd);
222  return -1;
223  }
224  strcpy(dev, ifr.ifr_name);
225  return fd;
226 }
227 
228 
236 static void
237 set_address6(const char *dev, const char *address, unsigned long prefix_len)
238 {
239  struct ifreq ifr;
240  struct sockaddr_in6 sa6;
241  int fd;
242  struct in6_ifreq ifr6;
243 
244  /*
245  * parse the new address
246  */
247  memset(&sa6, 0, sizeof(struct sockaddr_in6));
248  sa6.sin6_family = AF_INET6;
249  if (1 != inet_pton(AF_INET6, address, &sa6.sin6_addr))
250  {
251  fprintf(stderr, "Failed to parse address `%s': %s\n", address,
252  strerror(errno));
253  exit(1);
254  }
255 
256  if (-1 == (fd = socket(PF_INET6, SOCK_DGRAM, 0)))
257  {
258  fprintf(stderr, "Error creating socket: %s\n", strerror(errno));
259  exit(1);
260  }
261 
262  memset(&ifr, 0, sizeof(struct ifreq));
263  /*
264  * Get the index of the if
265  */
266  strncpy(ifr.ifr_name, dev, IFNAMSIZ);
267  if (-1 == ioctl(fd, SIOGIFINDEX, &ifr))
268  {
269  fprintf(stderr, "ioctl failed at %d: %s\n", __LINE__, strerror(errno));
270  (void)close(fd);
271  exit(1);
272  }
273 
274  memset(&ifr6, 0, sizeof(struct in6_ifreq));
275  ifr6.ifr6_addr = sa6.sin6_addr;
276  ifr6.ifr6_ifindex = ifr.ifr_ifindex;
277  ifr6.ifr6_prefixlen = prefix_len;
278 
279  /*
280  * Set the address
281  */
282  if (-1 == ioctl(fd, SIOCSIFADDR, &ifr6))
283  {
284  fprintf(stderr, "ioctl failed at line %d: %s\n", __LINE__,
285  strerror(errno));
286  (void)close(fd);
287  exit(1);
288  }
289 
290  /*
291  * Get the flags
292  */
293  if (-1 == ioctl(fd, SIOCGIFFLAGS, &ifr))
294  {
295  fprintf(stderr, "ioctl failed at line %d: %s\n", __LINE__,
296  strerror(errno));
297  (void)close(fd);
298  exit(1);
299  }
300 
301  /*
302  * Add the UP and RUNNING flags
303  */
304  ifr.ifr_flags |= IFF_UP | IFF_RUNNING;
305  if (-1 == ioctl(fd, SIOCSIFFLAGS, &ifr))
306  {
307  fprintf(stderr, "ioctl failed at line %d: %s\n", __LINE__,
308  strerror(errno));
309  (void)close(fd);
310  exit(1);
311  }
312 
313  if (0 != close(fd))
314  {
315  fprintf(stderr, "close failed: %s\n", strerror(errno));
316  exit(1);
317  }
318 }
319 
320 
328 static void
329 set_address4(const char *dev, const char *address, const char *mask)
330 {
331  int fd;
332  struct sockaddr_in *addr;
333  struct ifreq ifr;
334 
335  memset(&ifr, 0, sizeof(struct ifreq));
336  addr = (struct sockaddr_in *)&(ifr.ifr_addr);
337  addr->sin_family = AF_INET;
338 
339  /*
340  * Parse the address
341  */
342  if (1 != inet_pton(AF_INET, address, &addr->sin_addr.s_addr))
343  {
344  fprintf(stderr, "Failed to parse address `%s': %s\n", address,
345  strerror(errno));
346  exit(1);
347  }
348 
349  if (-1 == (fd = socket(PF_INET, SOCK_DGRAM, 0)))
350  {
351  fprintf(stderr, "Error creating socket: %s\n", strerror(errno));
352  exit(1);
353  }
354 
355  strncpy(ifr.ifr_name, dev, IFNAMSIZ);
356 
357  /*
358  * Set the address
359  */
360  if (-1 == ioctl(fd, SIOCSIFADDR, &ifr))
361  {
362  fprintf(stderr, "ioctl failed at %d: %s\n", __LINE__, strerror(errno));
363  (void)close(fd);
364  exit(1);
365  }
366 
367  /*
368  * Parse the netmask
369  */
370  addr = (struct sockaddr_in *)&(ifr.ifr_netmask);
371  if (1 != inet_pton(AF_INET, mask, &addr->sin_addr.s_addr))
372  {
373  fprintf(stderr, "Failed to parse address `%s': %s\n", mask,
374  strerror(errno));
375  (void)close(fd);
376  exit(1);
377  }
378 
379  /*
380  * Set the netmask
381  */
382  if (-1 == ioctl(fd, SIOCSIFNETMASK, &ifr))
383  {
384  fprintf(stderr, "ioctl failed at line %d: %s\n", __LINE__,
385  strerror(errno));
386  (void)close(fd);
387  exit(1);
388  }
389 
390  /*
391  * Get the flags
392  */
393  if (-1 == ioctl(fd, SIOCGIFFLAGS, &ifr))
394  {
395  fprintf(stderr, "ioctl failed at line %d: %s\n", __LINE__,
396  strerror(errno));
397  (void)close(fd);
398  exit(1);
399  }
400 
401  /*
402  * Add the UP and RUNNING flags
403  */
404  ifr.ifr_flags |= IFF_UP | IFF_RUNNING;
405  if (-1 == ioctl(fd, SIOCSIFFLAGS, &ifr))
406  {
407  fprintf(stderr, "ioctl failed at line %d: %s\n", __LINE__,
408  strerror(errno));
409  (void)close(fd);
410  exit(1);
411  }
412 
413  if (0 != close(fd))
414  {
415  fprintf(stderr, "close failed: %s\n", strerror(errno));
416  (void)close(fd);
417  exit(1);
418  }
419 }
420 
421 
427 static void
428 run(int fd_tun)
429 {
430  /*
431  * The buffer filled by reading from fd_tun
432  */
433  unsigned char buftun[MAX_SIZE];
434  ssize_t buftun_size = 0;
435  unsigned char *buftun_read = NULL;
436 
437  /*
438  * The buffer filled by reading from stdin
439  */
440  unsigned char bufin[MAX_SIZE];
441  ssize_t bufin_size = 0;
442  size_t bufin_rpos = 0;
443  unsigned char *bufin_read = NULL;
444 
445  fd_set fds_w;
446  fd_set fds_r;
447 
448  /* read refers to reading from fd_tun, writing to stdout */
449  int read_open = 1;
450 
451  /* write refers to reading from stdin, writing to fd_tun */
452  int write_open = 1;
453 
454  while ((1 == read_open) && (1 == write_open))
455  {
456  FD_ZERO(&fds_w);
457  FD_ZERO(&fds_r);
458 
459  /*
460  * We are supposed to read and the buffer is empty
461  * -> select on read from tun
462  */
463  if (read_open && (0 == buftun_size))
464  FD_SET(fd_tun, &fds_r);
465 
466  /*
467  * We are supposed to read and the buffer is not empty
468  * -> select on write to stdout
469  */
470  if (read_open && (0 != buftun_size))
471  FD_SET(1, &fds_w);
472 
473  /*
474  * We are supposed to write and the buffer is empty
475  * -> select on read from stdin
476  */
477  if (write_open && (NULL == bufin_read))
478  FD_SET(0, &fds_r);
479 
480  /*
481  * We are supposed to write and the buffer is not empty
482  * -> select on write to tun
483  */
484  if (write_open && (NULL != bufin_read))
485  FD_SET(fd_tun, &fds_w);
486 
487  int r = select(fd_tun + 1, &fds_r, &fds_w, NULL, NULL);
488 
489  if (-1 == r)
490  {
491  if (EINTR == errno)
492  continue;
493  fprintf(stderr, "select failed: %s\n", strerror(errno));
494  exit(1);
495  }
496 
497  if (r > 0)
498  {
499  if (FD_ISSET(fd_tun, &fds_r))
500  {
501  buftun_size =
502  read(fd_tun, buftun + sizeof(struct GNUNET_MessageHeader),
503  MAX_SIZE - sizeof(struct GNUNET_MessageHeader));
504  if (-1 == buftun_size)
505  {
506  fprintf(stderr,
507  "read-error: %s\n",
508  strerror(errno));
509  shutdown(fd_tun, SHUT_RD);
510  shutdown(1, SHUT_WR);
511  read_open = 0;
512  buftun_size = 0;
513  }
514  else if (0 == buftun_size)
515  {
516 #if DEBUG
517  fprintf(stderr, "EOF on tun\n");
518 #endif
519  shutdown(fd_tun, SHUT_RD);
520  shutdown(1, SHUT_WR);
521  read_open = 0;
522  buftun_size = 0;
523  }
524  else
525  {
526  buftun_read = buftun;
527  struct GNUNET_MessageHeader *hdr =
528  (struct GNUNET_MessageHeader *)buftun;
529  buftun_size += sizeof(struct GNUNET_MessageHeader);
530  hdr->type = htons(GNUNET_MESSAGE_TYPE_VPN_HELPER);
531  hdr->size = htons(buftun_size);
532  }
533  }
534  else if (FD_ISSET(1, &fds_w))
535  {
536  ssize_t written = write(1, buftun_read, buftun_size);
537 
538  if (-1 == written)
539  {
540 #if !DEBUG
541  if (errno != EPIPE)
542 #endif
543  fprintf(stderr,
544  "write-error to stdout: %s\n",
545  strerror(errno));
546  shutdown(fd_tun, SHUT_RD);
547  shutdown(1, SHUT_WR);
548  read_open = 0;
549  buftun_size = 0;
550  }
551  else if (0 == written)
552  {
553  fprintf(stderr, "write returned 0!?\n");
554  exit(1);
555  }
556  else
557  {
558  buftun_size -= written;
559  buftun_read += written;
560  }
561  }
562 
563  if (FD_ISSET(0, &fds_r))
564  {
565  bufin_size = read(0, bufin + bufin_rpos, MAX_SIZE - bufin_rpos);
566  if (-1 == bufin_size)
567  {
568  fprintf(stderr, "read-error: %s\n", strerror(errno));
569  shutdown(0, SHUT_RD);
570  shutdown(fd_tun, SHUT_WR);
571  write_open = 0;
572  bufin_size = 0;
573  }
574  else if (0 == bufin_size)
575  {
576 #if DEBUG
577  fprintf(stderr, "EOF on stdin\n");
578 #endif
579  shutdown(0, SHUT_RD);
580  shutdown(fd_tun, SHUT_WR);
581  write_open = 0;
582  bufin_size = 0;
583  }
584  else
585  {
586  struct GNUNET_MessageHeader *hdr;
587 
588 PROCESS_BUFFER:
589  bufin_rpos += bufin_size;
590  if (bufin_rpos < sizeof(struct GNUNET_MessageHeader))
591  continue;
592  hdr = (struct GNUNET_MessageHeader *)bufin;
593  if (ntohs(hdr->type) != GNUNET_MESSAGE_TYPE_VPN_HELPER)
594  {
595  fprintf(stderr, "protocol violation!\n");
596  exit(1);
597  }
598  if (ntohs(hdr->size) > bufin_rpos)
599  continue;
600  bufin_read = bufin + sizeof(struct GNUNET_MessageHeader);
601  bufin_size = ntohs(hdr->size) - sizeof(struct GNUNET_MessageHeader);
602  bufin_rpos -= bufin_size + sizeof(struct GNUNET_MessageHeader);
603  }
604  }
605  else if (FD_ISSET(fd_tun, &fds_w))
606  {
607  ssize_t written = write(fd_tun, bufin_read, bufin_size);
608 
609  if (-1 == written)
610  {
611  fprintf(stderr, "write-error to tun: %s\n", strerror(errno));
612  shutdown(0, SHUT_RD);
613  shutdown(fd_tun, SHUT_WR);
614  write_open = 0;
615  bufin_size = 0;
616  }
617  else if (0 == written)
618  {
619  fprintf(stderr, "write returned 0!?\n");
620  exit(1);
621  }
622  else
623  {
624  bufin_size -= written;
625  bufin_read += written;
626  if (0 == bufin_size)
627  {
628  memmove(bufin, bufin_read, bufin_rpos);
629  bufin_read = NULL; /* start reading again */
630  bufin_size = 0;
631  goto PROCESS_BUFFER;
632  }
633  }
634  }
635  }
636  }
637 }
638 
639 
653 int
654 main(int argc, char **argv)
655 {
656  char dev[IFNAMSIZ];
657  int fd_tun;
658  int global_ret;
659 
660  if (7 != argc)
661  {
662  fprintf(stderr, "Fatal: must supply 6 arguments!\n");
663  return 1;
664  }
665  if ((0 == strcmp(argv[3], "-")) &&
666  (0 == strcmp(argv[5], "-")))
667  {
668  fprintf(stderr, "Fatal: disabling both IPv4 and IPv6 makes no sense.\n");
669  return 1;
670  }
671  if (0 != strcmp(argv[2], "-"))
672  {
673 #ifdef IPTABLES
674  if (0 == access(IPTABLES, X_OK))
675  sbin_iptables = IPTABLES;
676  else
677 #endif
678  if (0 == access("/sbin/iptables", X_OK))
679  sbin_iptables = "/sbin/iptables";
680  else if (0 == access("/usr/sbin/iptables", X_OK))
681  sbin_iptables = "/usr/sbin/iptables";
682  else
683  {
684  fprintf(stderr,
685  "Fatal: executable iptables not found in approved directories: %s\n",
686  strerror(errno));
687  return 1;
688  }
689 #ifdef SYSCTL
690  if (0 == access(SYSCTL, X_OK))
691  sbin_sysctl = SYSCTL;
692  else
693 #endif
694  if (0 == access("/sbin/sysctl", X_OK))
695  sbin_sysctl = "/sbin/sysctl";
696  else if (0 == access("/usr/sbin/sysctl", X_OK))
697  sbin_sysctl = "/usr/sbin/sysctl";
698  else
699  {
700  fprintf(stderr,
701  "Fatal: executable sysctl not found in approved directories: %s\n",
702  strerror(errno));
703  return 1;
704  }
705  }
706 
707  strncpy(dev, argv[1], IFNAMSIZ);
708  dev[IFNAMSIZ - 1] = '\0';
709 
710  if (-1 == (fd_tun = init_tun(dev)))
711  {
712  fprintf(stderr,
713  "Fatal: could not initialize tun-interface `%s' with IPv6 %s/%s and IPv4 %s/%s\n",
714  dev,
715  argv[3],
716  argv[4],
717  argv[5],
718  argv[6]);
719  return 1;
720  }
721 
722  if (0 != strcmp(argv[3], "-"))
723  {
724  {
725  const char *address = argv[3];
726  long prefix_len = atol(argv[4]);
727 
728  if ((prefix_len < 1) || (prefix_len > 127))
729  {
730  fprintf(stderr, "Fatal: prefix_len out of range\n");
731  return 1;
732  }
733  set_address6(dev, address, prefix_len);
734  }
735  if (0 != strcmp(argv[2], "-"))
736  {
737  char *const sysctl_args[] =
738  {
739  "sysctl", "-w", "net.ipv6.conf.all.forwarding=1", NULL
740  };
741  if (0 != fork_and_exec(sbin_sysctl,
742  sysctl_args))
743  {
744  fprintf(stderr,
745  "Failed to enable IPv6 forwarding. Will continue anyway.\n");
746  }
747  }
748  }
749 
750  if (0 != strcmp(argv[5], "-"))
751  {
752  {
753  const char *address = argv[5];
754  const char *mask = argv[6];
755 
756  set_address4(dev, address, mask);
757  }
758  if (0 != strcmp(argv[2], "-"))
759  {
760  {
761  char *const sysctl_args[] =
762  {
763  "sysctl", "-w", "net.ipv4.ip_forward=1", NULL
764  };
765  if (0 != fork_and_exec(sbin_sysctl,
766  sysctl_args))
767  {
768  fprintf(stderr,
769  "Failed to enable IPv4 forwarding. Will continue anyway.\n");
770  }
771  }
772  {
773  char *const iptables_args[] =
774  {
775  "iptables", "-t", "nat", "-A", "POSTROUTING", "-o", argv[2], "-j", "MASQUERADE", NULL
776  };
777  if (0 != fork_and_exec(sbin_iptables,
778  iptables_args))
779  {
780  fprintf(stderr,
781  "Failed to enable IPv4 masquerading (NAT). Will continue anyway.\n");
782  }
783  }
784  }
785  }
786 
787  uid_t uid = getuid();
788 #ifdef HAVE_SETRESUID
789  if (0 != setresuid(uid, uid, uid))
790  {
791  fprintf(stderr, "Failed to setresuid: %s\n", strerror(errno));
792  global_ret = 2;
793  goto cleanup;
794  }
795 #else
796  if (0 != (setuid(uid) | seteuid(uid)))
797  {
798  fprintf(stderr, "Failed to setuid: %s\n", strerror(errno));
799  global_ret = 2;
800  goto cleanup;
801  }
802 #endif
803 
804  if (SIG_ERR == signal(SIGPIPE, SIG_IGN))
805  {
806  fprintf(stderr, "Failed to protect against SIGPIPE: %s\n",
807  strerror(errno));
808  /* no exit, we might as well die with SIGPIPE should it ever happen */
809  }
810  run(fd_tun);
811  global_ret = 0;
812 cleanup:
813  (void)close(fd_tun);
814  return global_ret;
815 }
816 
817 /* end of gnunet-helper-exit.c */
static int init_tun(char *dev)
Creates a tun-interface called dev;.
uint32_t ifr6_prefixlen
static const char * sbin_iptables
Path to &#39;iptables&#39; binary.
static void run(int fd_tun)
Start forwarding to and from the tunnel.
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 ret
Final status code.
Definition: gnunet-arm.c:89
cryptographic primitives for GNUnet
uint16_t type
The type of the message (GNUNET_MESSAGE_TYPE_XXXX), in big-endian format.
#define MAX_SIZE
Maximum size of a GNUnet message (GNUNET_MAX_MESSAGE_SIZE)
static void open_dev_null(int target_fd, int flags)
Open &#39;/dev/null&#39; and make the result the given file descriptor.
uint16_t status
See PRISM_STATUS_*-constants.
static void cleanup(void *cls)
Function scheduled as very last function, cleans up after us.
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 set_address4(const char *dev, const char *address, const char *mask)
Sets the IPv4-Address given in address on the interface dev.
int main(int argc, char **argv)
Open VPN tunnel interface.
This is in linux/include/net/ipv6.h, but not always exported...
static const char * sbin_sysctl
Path to &#39;sysctl&#39; binary.
Header for all communications.
commonly used definitions; globals in this file are exempt from the rule that the module name ("commo...
static int fork_and_exec(const char *file, char *const cmd[])
Run the given command and wait for it to complete.
unsigned int ifr6_ifindex
static struct GNUNET_PeerIdentity pid
Identity of the peer we transmit to / connect to.
static char * address
GNS address for this phone.
static int global_ret
Return value from main.
#define GNUNET_MESSAGE_TYPE_VPN_HELPER
Type of messages between the gnunet-vpn-helper and the daemon.