GNUnet 0.21.1
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 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, 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
497 while ((1 == read_open) && (1 == write_open))
498 {
499 FD_ZERO (&fds_w);
500 FD_ZERO (&fds_r);
501
502 /*
503 * We are supposed to read and the buffer is empty
504 * -> select on read from tun
505 */
506 if (read_open && (0 == buftun_size))
507 FD_SET (fd_tun, &fds_r);
508
509 /*
510 * We are supposed to read and the buffer is not empty
511 * -> select on write to stdout
512 */
513 if (read_open && (0 != buftun_size))
514 FD_SET (1, &fds_w);
515
516 /*
517 * We are supposed to write and the buffer is empty
518 * -> select on read from stdin
519 */
520 if (write_open && (NULL == bufin_read))
521 FD_SET (0, &fds_r);
522
523 /*
524 * We are supposed to write and the buffer is not empty
525 * -> select on write to tun
526 */
527 if (write_open && (NULL != bufin_read))
528 FD_SET (fd_tun, &fds_w);
529
530 int r = select (fd_tun + 1, &fds_r, &fds_w, NULL, NULL);
531
532 if (-1 == r)
533 {
534 if (EINTR == errno)
535 continue;
536 fprintf (stderr, "select failed: %s\n", strerror (errno));
537 exit (1);
538 }
539
540 if (r > 0)
541 {
542 if (FD_ISSET (fd_tun, &fds_r))
543 {
544 buftun_size =
545 read (fd_tun, buftun + sizeof(struct GNUNET_MessageHeader),
546 MAX_SIZE - sizeof(struct GNUNET_MessageHeader));
547 if (-1 == buftun_size)
548 {
549 fprintf (stderr,
550 "read-error: %s\n",
551 strerror (errno));
552 shutdown (fd_tun, SHUT_RD);
553 shutdown (1, SHUT_WR);
554 read_open = 0;
555 buftun_size = 0;
556 }
557 else if (0 == buftun_size)
558 {
559#if DEBUG
560 fprintf (stderr, "EOF on tun\n");
561#endif
562 shutdown (fd_tun, SHUT_RD);
563 shutdown (1, SHUT_WR);
564 read_open = 0;
565 buftun_size = 0;
566 }
567 else
568 {
569 buftun_read = buftun;
570 struct GNUNET_MessageHeader *hdr =
571 (struct GNUNET_MessageHeader *) buftun;
572 buftun_size += sizeof(struct GNUNET_MessageHeader);
574 hdr->size = htons (buftun_size);
575 }
576 }
577 else if (FD_ISSET (1, &fds_w))
578 {
579 ssize_t written = write (1, buftun_read, buftun_size);
580
581 if (-1 == written)
582 {
583#if ! DEBUG
584 if (errno != EPIPE)
585#endif
586 fprintf (stderr,
587 "write-error to stdout: %s\n",
588 strerror (errno));
589 shutdown (fd_tun, SHUT_RD);
590 shutdown (1, SHUT_WR);
591 read_open = 0;
592 buftun_size = 0;
593 }
594 else if (0 == written)
595 {
596 fprintf (stderr, "write returned 0!?\n");
597 exit (1);
598 }
599 else
600 {
601 buftun_size -= written;
602 buftun_read += written;
603 }
604 }
605
606 if (FD_ISSET (0, &fds_r))
607 {
608 bufin_size = read (0, bufin + bufin_rpos, MAX_SIZE - bufin_rpos);
609 if (-1 == bufin_size)
610 {
611 fprintf (stderr, "read-error: %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 == bufin_size)
618 {
619#if DEBUG
620 fprintf (stderr, "EOF on stdin\n");
621#endif
622 shutdown (0, SHUT_RD);
623 shutdown (fd_tun, SHUT_WR);
624 write_open = 0;
625 bufin_size = 0;
626 }
627 else
628 {
629 struct GNUNET_MessageHeader *hdr;
630
631PROCESS_BUFFER:
632 bufin_rpos += bufin_size;
633 if (bufin_rpos < sizeof(struct GNUNET_MessageHeader))
634 continue;
635 hdr = (struct GNUNET_MessageHeader *) bufin;
636 if (ntohs (hdr->type) != GNUNET_MESSAGE_TYPE_VPN_HELPER)
637 {
638 fprintf (stderr, "protocol violation!\n");
639 exit (1);
640 }
641 if (ntohs (hdr->size) > bufin_rpos)
642 continue;
643 bufin_read = bufin + sizeof(struct GNUNET_MessageHeader);
644 bufin_size = ntohs (hdr->size) - sizeof(struct GNUNET_MessageHeader);
645 bufin_rpos -= bufin_size + sizeof(struct GNUNET_MessageHeader);
646 }
647 }
648 else if (FD_ISSET (fd_tun, &fds_w))
649 {
650 ssize_t written = write (fd_tun, bufin_read, bufin_size);
651
652 if (-1 == written)
653 {
654 fprintf (stderr, "write-error to tun: %s\n", strerror (errno));
655 shutdown (0, SHUT_RD);
656 shutdown (fd_tun, SHUT_WR);
657 write_open = 0;
658 bufin_size = 0;
659 }
660 else if (0 == written)
661 {
662 fprintf (stderr, "write returned 0!?\n");
663 exit (1);
664 }
665 else
666 {
667 bufin_size -= written;
668 bufin_read += written;
669 if (0 == bufin_size)
670 {
671 memmove (bufin, bufin_read, bufin_rpos);
672 bufin_read = NULL; /* start reading again */
673 bufin_size = 0;
674 goto PROCESS_BUFFER;
675 }
676 }
677 }
678 }
679 }
680}
681
682
696int
697main (int argc, char **argv)
698{
699 char dev[IFNAMSIZ];
700 int fd_tun;
701 int global_ret;
702
703 if (7 != argc)
704 {
705 fprintf (stderr, "Fatal: must supply 6 arguments!\n");
706 return 1;
707 }
708 if ((0 == strcmp (argv[3], "-")) &&
709 (0 == strcmp (argv[5], "-")))
710 {
711 fprintf (stderr, "Fatal: disabling both IPv4 and IPv6 makes no sense.\n");
712 return 1;
713 }
714 if (0 != strcmp (argv[2], "-"))
715 {
716#ifdef IPTABLES
717 if (0 == access (IPTABLES, X_OK))
718 sbin_iptables = IPTABLES;
719 else
720#endif
721 if (0 == access ("/sbin/iptables", X_OK))
722 sbin_iptables = "/sbin/iptables";
723 else if (0 == access ("/usr/sbin/iptables", X_OK))
724 sbin_iptables = "/usr/sbin/iptables";
725 else
726 {
727 fprintf (stderr,
728 "Fatal: executable iptables not found in approved directories: %s\n",
729 strerror (errno));
730 return 1;
731 }
732#ifdef SYSCTL
733 if (0 == access (SYSCTL, X_OK))
734 sbin_sysctl = SYSCTL;
735 else
736#endif
737 if (0 == access ("/sbin/sysctl", X_OK))
738 sbin_sysctl = "/sbin/sysctl";
739 else if (0 == access ("/usr/sbin/sysctl", X_OK))
740 sbin_sysctl = "/usr/sbin/sysctl";
741 else
742 {
743 fprintf (stderr,
744 "Fatal: executable sysctl not found in approved directories: %s\n",
745 strerror (errno));
746 return 1;
747 }
748 }
749
750 strncpy (dev, argv[1], IFNAMSIZ);
751 dev[IFNAMSIZ - 1] = '\0';
752
753 if (-1 == (fd_tun = init_tun (dev)))
754 {
755 fprintf (stderr,
756 "Fatal: could not initialize tun-interface `%s' with IPv6 %s/%s and IPv4 %s/%s\n",
757 dev,
758 argv[3],
759 argv[4],
760 argv[5],
761 argv[6]);
762 return 1;
763 }
764
765 if (0 != strcmp (argv[3], "-"))
766 {
767 {
768 const char *address = argv[3];
769 long prefix_len = atol (argv[4]);
770
771 if ((prefix_len < 1) || (prefix_len > 127))
772 {
773 fprintf (stderr, "Fatal: prefix_len out of range\n");
774 return 1;
775 }
776 set_address6 (dev, address, prefix_len);
777 }
778 if (0 != strcmp (argv[2], "-"))
779 {
780 char *const sysctl_args[] = {
781 "sysctl", "-w", "net.ipv6.conf.all.forwarding=1", NULL
782 };
783 if (0 != fork_and_exec (sbin_sysctl,
784 sysctl_args))
785 {
786 fprintf (stderr,
787 "Failed to enable IPv6 forwarding. Will continue anyway.\n");
788 }
789 }
790 }
791
792 if (0 != strcmp (argv[5], "-"))
793 {
794 {
795 const char *address = argv[5];
796 const char *mask = argv[6];
797
798 set_address4 (dev, address, mask);
799 }
800 if (0 != strcmp (argv[2], "-"))
801 {
802 {
803 char *const sysctl_args[] = {
804 "sysctl", "-w", "net.ipv4.ip_forward=1", NULL
805 };
806 if (0 != fork_and_exec (sbin_sysctl,
807 sysctl_args))
808 {
809 fprintf (stderr,
810 "Failed to enable IPv4 forwarding. Will continue anyway.\n");
811 }
812 }
813 {
814 char *const iptables_args[] = {
815 "iptables", "-t", "nat", "-A", "POSTROUTING", "-o", argv[2], "-j",
816 "MASQUERADE", NULL
817 };
819 iptables_args))
820 {
821 fprintf (stderr,
822 "Failed to enable IPv4 masquerading (NAT). Will continue anyway.\n");
823 }
824 }
825 }
826 }
827
828 uid_t uid = getuid ();
829#ifdef HAVE_SETRESUID
830 if (0 != setresuid (uid, uid, uid))
831 {
832 fprintf (stderr, "Failed to setresuid: %s\n", strerror (errno));
833 global_ret = 2;
834 goto cleanup;
835 }
836#else
837 if (0 != (setuid (uid) | seteuid (uid)))
838 {
839 fprintf (stderr, "Failed to setuid: %s\n", strerror (errno));
840 global_ret = 2;
841 goto cleanup;
842 }
843#endif
844
845 if (SIG_ERR == signal (SIGPIPE, SIG_IGN))
846 {
847 fprintf (stderr, "Failed to protect against SIGPIPE: %s\n",
848 strerror (errno));
849 /* no exit, we might as well die with SIGPIPE should it ever happen */
850 }
851 run (fd_tun);
852 global_ret = 0;
853cleanup:
854 (void) close (fd_tun);
855 return global_ret;
856}
857
858
859/* end of gnunet-helper-exit.c */
static int ret
Final status code.
Definition: gnunet-arm.c:94
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:131
#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.
static int fork_and_exec(const char *file, char *const cmd[])
Run the given command and wait for it to complete.
int main(int argc, char **argv)
Open VPN tunnel interface.
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