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