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