-remove debug message
[oweals/gnunet.git] / src / exit / gnunet-helper-exit.c
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
21 /**
22  * @file exit/gnunet-helper-exit.c
23  *
24  * @brief the helper for exit nodes. Opens a virtual
25  * network-interface, sends data received on the if to stdout, sends
26  * data received on stdin to the interface.  The code also enables
27  * IPv4/IPv6 forwarding and NAT on the current system (the latter on
28  * an interface specified on the command-line); these changes to the
29  * network configuration are NOT automatically undone when the program
30  * is stopped (this is because we cannot be sure that some other
31  * application didn't enable them before or after us; also, these
32  * changes should be mostly harmless as it simply turns the system
33  * into a router).
34  *
35  * @author Philipp Tölke
36  * @author Christian Grothoff
37  *
38  * The following list of people have reviewed this code and considered
39  * it safe since the last modification (if you reviewed it, please
40  * have your name added to the list):
41  *
42  * - Philipp Tölke
43  */
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
55 /**
56  * Need 'struct GNUNET_MessageHeader'.
57  */
58 #include "gnunet_crypto_lib.h"
59 #include "gnunet_common.h"
60
61 /**
62  * Need VPN message types.
63  */
64 #include "gnunet_protocols.h"
65
66 /**
67  * Should we print (interesting|debug) messages that can happen during
68  * normal operation?
69  */
70 #define DEBUG GNUNET_NO
71
72 /**
73  * Maximum size of a GNUnet message (GNUNET_MAX_MESSAGE_SIZE)
74  */
75 #define MAX_SIZE 65536
76
77 /**
78  * Path to 'sysctl' binary.
79  */
80 static const char *sbin_sysctl;
81
82 /**
83  * Path to 'iptables' binary.
84  */
85 static const char *sbin_iptables;
86
87
88 #if ! defined(__ANDROID__)
89 #if ! defined(_LINUX_IN6_H) && defined(__linux__)
90 /**
91  * This is in linux/include/net/ipv6.h, but not always exported.
92  */
93 struct 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
103 /**
104  * Open '/dev/null' and make the result the given
105  * file descriptor.
106  *
107  * @param target_fd desired FD to point to /dev/null
108  * @param flags open flags (O_RDONLY, O_WRONLY)
109  */
110 static void
111 open_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
130 /**
131  * Run the given command and wait for it to complete.
132  *
133  * @param file name of the binary to run
134  * @param cmd command line arguments (as given to 'execv')
135  * @return 0 on success, 1 on any error
136  */
137 static int
138 fork_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
188 /**
189  * Creates a tun-interface called dev;
190  *
191  * @param dev is asumed to point to a char[IFNAMSIZ]
192  *        if *dev == '\\0', uses the name supplied by the kernel;
193  * @return the fd to the tun or -1 on error
194  */
195 #ifdef IFF_TUN /* LINUX */
196 static int
197 init_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
244 static int
245 init_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
272 /**
273  * @brief Sets the IPv6-Address given in address on the interface dev
274  *
275  * @param dev the interface to configure
276  * @param address the IPv6-Address
277  * @param prefix_len the length of the network-prefix
278  */
279 static void
280 set_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
364 /**
365  * @brief Sets the IPv4-Address given in address on the interface dev
366  *
367  * @param dev the interface to configure
368  * @param address the IPv4-Address
369  * @param mask the netmask
370  */
371 static void
372 set_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
465 /**
466  * Start forwarding to and from the tunnel.
467  *
468  * @param fd_tun tunnel FD
469  */
470 static void
471 run (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);
573           hdr->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
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
631 PROCESS_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
683 /**
684  * Open VPN tunnel interface.
685  *
686  * @param argc must be 6
687  * @param argv 0: binary name ("gnunet-helper-exit")
688  *             1: tunnel interface name ("gnunet-exit")
689  *             2: "physical" interface name ("eth0"), or "-" to not setup NAT
690  *                and routing
691  *             3: IPv6 address ("::1"), or "-" to skip IPv6
692  *             4: IPv6 netmask length in bits ("64") [ignored if #4 is "-"]
693  *             5: IPv4 address ("1.2.3.4"), or "-" to skip IPv4
694  *             6: IPv4 netmask ("255.255.0.0") [ignored if #4 is "-"]
695  */
696 int
697 main (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         };
818         if (0 != fork_and_exec (sbin_iptables,
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;
853 cleanup:
854   (void) close (fd_tun);
855   return global_ret;
856 }
857
858
859 /* end of gnunet-helper-exit.c */