-remove debug message
[oweals/gnunet.git] / src / vpn / gnunet-helper-vpn.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2010, 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 vpn/gnunet-helper-vpn.c
23  * @brief the helper for the VPN service. Opens a virtual network-interface,
24  * sends data received on the if to stdout, sends data received on stdin to the
25  * interface
26  * @author Philipp Tölke
27  * @author Christian Grothoff
28  *
29  * The following list of people have reviewed this code and considered
30  * it safe since the last modification (if you reviewed it, please
31  * have your name added to the list):
32  *
33  * - Philipp Tölke
34  */
35 #include "platform.h"
36 #ifdef IF_TUN_HDR
37 #include IF_TUN_HDR
38 #endif
39
40 /**
41  * Need 'struct GNUNET_MessageHeader'.
42  */
43 #include "gnunet_crypto_lib.h"
44 #include "gnunet_common.h"
45
46 /**
47  * Need VPN message types.
48  */
49 #include "gnunet_protocols.h"
50
51 /**
52  * Should we print (interesting|debug) messages that can happen during
53  * normal operation?
54  */
55 #define DEBUG GNUNET_NO
56
57 /**
58  * Maximum size of a GNUnet message (GNUNET_MAX_MESSAGE_SIZE)
59  */
60 #define MAX_SIZE 65536
61
62 #if ! defined(__ANDROID__)
63 #ifndef _LINUX_IN6_H
64 /**
65  * This is in linux/include/net/ipv6.h, but not always exported...
66  */
67 struct in6_ifreq
68 {
69   struct in6_addr ifr6_addr;
70   uint32_t ifr6_prefixlen;
71   unsigned int ifr6_ifindex;
72 };
73 #endif
74 #endif
75
76
77 /**
78  * Creates a tun-interface called dev;
79  *
80  * @param dev is asumed to point to a char[IFNAMSIZ]
81  *        if *dev == '\\0', uses the name supplied by the kernel;
82  * @return the fd to the tun or -1 on error
83  */
84 static int
85 init_tun (char *dev)
86 {
87   struct ifreq ifr;
88   int fd;
89
90   if (NULL == dev)
91   {
92     errno = EINVAL;
93     return -1;
94   }
95
96   if (-1 == (fd = open ("/dev/net/tun", O_RDWR)))
97   {
98     fprintf (stderr,
99              "Error opening `%s': %s\n",
100              "/dev/net/tun",
101              strerror (errno));
102     return -1;
103   }
104
105   if (fd >= FD_SETSIZE)
106   {
107     fprintf (stderr,
108              "File descriptor to large: %d",
109              fd);
110     (void) close (fd);
111     return -1;
112   }
113
114   memset (&ifr, 0, sizeof(ifr));
115   ifr.ifr_flags = IFF_TUN;
116
117   if ('\0' != *dev)
118     strncpy (ifr.ifr_name,
119              dev,
120              IFNAMSIZ);
121
122   if (-1 == ioctl (fd,
123                    TUNSETIFF,
124                    (void *) &ifr))
125   {
126     fprintf (stderr,
127              "Error with ioctl on `%s': %s\n",
128              "/dev/net/tun",
129              strerror (errno));
130     (void) close (fd);
131     return -1;
132   }
133   strcpy (dev, ifr.ifr_name);
134   return fd;
135 }
136
137
138 /**
139  * @brief Sets the IPv6-Address given in address on the interface dev
140  *
141  * @param dev the interface to configure
142  * @param address the IPv6-Address
143  * @param prefix_len the length of the network-prefix
144  */
145 static void
146 set_address6 (const char *dev,
147               const char *address,
148               unsigned long prefix_len)
149 {
150   struct ifreq ifr;
151   struct in6_ifreq ifr6;
152   struct sockaddr_in6 sa6;
153   int fd;
154
155   /*
156    * parse the new address
157    */
158   memset (&sa6, 0, sizeof(struct sockaddr_in6));
159   sa6.sin6_family = AF_INET6;
160   if (1 != inet_pton (AF_INET6, address, sa6.sin6_addr.s6_addr))
161   {
162     fprintf (stderr,
163              "Failed to parse IPv6 address `%s'\n",
164              address);
165     exit (1);
166   }
167
168   if (-1 == (fd = socket (PF_INET6, SOCK_DGRAM, 0)))
169   {
170     fprintf (stderr,
171              "Error creating socket: %s\n",
172              strerror (errno));
173     exit (1);
174   }
175
176   memset (&ifr, 0, sizeof(struct ifreq));
177   /*
178    * Get the index of the if
179    */
180   strncpy (ifr.ifr_name,
181            dev,
182            IFNAMSIZ);
183   if (-1 == ioctl (fd,
184                    SIOGIFINDEX,
185                    &ifr))
186   {
187     fprintf (stderr,
188              "ioctl failed at %d: %s\n",
189              __LINE__,
190              strerror (errno));
191     (void) close (fd);
192     exit (1);
193   }
194
195   memset (&ifr6, 0, sizeof(struct in6_ifreq));
196   ifr6.ifr6_addr = sa6.sin6_addr;
197   ifr6.ifr6_ifindex = ifr.ifr_ifindex;
198   ifr6.ifr6_prefixlen = prefix_len;
199
200   /*
201    * Set the address
202    */
203   if (-1 == ioctl (fd,
204                    SIOCSIFADDR,
205                    &ifr6))
206   {
207     fprintf (stderr,
208              "ioctl failed at line %d: %s\n",
209              __LINE__,
210              strerror (errno));
211     (void) close (fd);
212     exit (1);
213   }
214
215   /*
216    * Get the flags
217    */
218   if (-1 == ioctl (fd,
219                    SIOCGIFFLAGS,
220                    &ifr))
221   {
222     fprintf (stderr,
223              "ioctl failed at line %d: %s\n",
224              __LINE__,
225              strerror (errno));
226     (void) close (fd);
227     exit (1);
228   }
229
230   /*
231    * Add the UP and RUNNING flags
232    */
233   ifr.ifr_flags |= IFF_UP | IFF_RUNNING;
234   if (-1 == ioctl (fd,
235                    SIOCSIFFLAGS,
236                    &ifr))
237   {
238     fprintf (stderr,
239              "ioctl failed at line %d: %s\n",
240              __LINE__,
241              strerror (errno));
242     (void) close (fd);
243     exit (1);
244   }
245
246   if (0 != close (fd))
247   {
248     fprintf (stderr,
249              "close failed: %s\n",
250              strerror (errno));
251     exit (1);
252   }
253 }
254
255
256 /**
257  * @brief Sets the IPv4-Address given in address on the interface dev
258  *
259  * @param dev the interface to configure
260  * @param address the IPv4-Address
261  * @param mask the netmask
262  */
263 static void
264 set_address4 (const char *dev,
265               const char *address,
266               const char *mask)
267 {
268   int fd;
269   struct sockaddr_in *addr;
270   struct ifreq ifr;
271
272   memset (&ifr, 0, sizeof(struct ifreq));
273   addr = (struct sockaddr_in *) &(ifr.ifr_addr);
274   addr->sin_family = AF_INET;
275
276   /*
277    * Parse the address
278    */
279   if (1 != inet_pton (AF_INET,
280                       address,
281                       &addr->sin_addr.s_addr))
282   {
283     fprintf (stderr,
284              "Failed to parse IPv4 address `%s'\n",
285              address);
286     exit (1);
287   }
288
289   if (-1 == (fd = socket (PF_INET, SOCK_DGRAM, 0)))
290   {
291     fprintf (stderr,
292              "Error creating socket: %s\n",
293              strerror (errno));
294     exit (1);
295   }
296
297   strncpy (ifr.ifr_name, dev, IFNAMSIZ);
298
299   /*
300    * Set the address
301    */
302   if (-1 == ioctl (fd, SIOCSIFADDR, &ifr))
303   {
304     fprintf (stderr,
305              "ioctl failed at %d: %s\n",
306              __LINE__,
307              strerror (errno));
308     (void) close (fd);
309     exit (1);
310   }
311
312   /*
313    * Parse the netmask
314    */
315   addr = (struct sockaddr_in *) &(ifr.ifr_netmask);
316   if (1 != inet_pton (AF_INET,
317                       mask,
318                       &addr->sin_addr.s_addr))
319   {
320     fprintf (stderr,
321              "Failed to parse IPv4 address mask `%s'\n",
322              mask);
323     (void) close (fd);
324     exit (1);
325   }
326
327   /*
328    * Set the netmask
329    */
330   if (-1 == ioctl (fd, SIOCSIFNETMASK, &ifr))
331   {
332     fprintf (stderr,
333              "ioctl failed at line %d: %s\n",
334              __LINE__,
335              strerror (errno));
336     (void) close (fd);
337     exit (1);
338   }
339
340   /*
341    * Get the flags
342    */
343   if (-1 == ioctl (fd, SIOCGIFFLAGS, &ifr))
344   {
345     fprintf (stderr,
346              "ioctl failed at line %d: %s\n",
347              __LINE__,
348              strerror (errno));
349     (void) close (fd);
350     exit (1);
351   }
352
353   /*
354    * Add the UP and RUNNING flags
355    */
356   ifr.ifr_flags |= IFF_UP | IFF_RUNNING;
357   if (-1 == ioctl (fd, SIOCSIFFLAGS, &ifr))
358   {
359     fprintf (stderr,
360              "ioctl failed at line %d: %s\n",
361              __LINE__,
362              strerror (errno));
363     (void) close (fd);
364     exit (1);
365   }
366
367   if (0 != close (fd))
368   {
369     fprintf (stderr,
370              "close failed: %s\n",
371              strerror (errno));
372     (void) close (fd);
373     exit (1);
374   }
375 }
376
377
378 /**
379  * Start forwarding to and from the tunnel.
380  *
381  * @param fd_tun tunnel FD
382  */
383 static void
384 run (int fd_tun)
385 {
386   /*
387    * The buffer filled by reading from fd_tun
388    */
389   unsigned char buftun[MAX_SIZE];
390   ssize_t buftun_size = 0;
391   unsigned char *buftun_read = NULL;
392
393   /*
394    * The buffer filled by reading from stdin
395    */
396   unsigned char bufin[MAX_SIZE];
397   ssize_t bufin_size = 0;
398   size_t bufin_rpos = 0;
399   unsigned char *bufin_read = NULL;
400
401   fd_set fds_w;
402   fd_set fds_r;
403
404   /* read refers to reading from fd_tun, writing to stdout */
405   int read_open = 1;
406
407   /* write refers to reading from stdin, writing to fd_tun */
408   int write_open = 1;
409
410   while ((1 == read_open) && (1 == write_open))
411   {
412     FD_ZERO (&fds_w);
413     FD_ZERO (&fds_r);
414
415     /*
416      * We are supposed to read and the buffer is empty
417      * -> select on read from tun
418      */
419     if (read_open && (0 == buftun_size))
420       FD_SET (fd_tun, &fds_r);
421
422     /*
423      * We are supposed to read and the buffer is not empty
424      * -> select on write to stdout
425      */
426     if (read_open && (0 != buftun_size))
427       FD_SET (1, &fds_w);
428
429     /*
430      * We are supposed to write and the buffer is empty
431      * -> select on read from stdin
432      */
433     if (write_open && (NULL == bufin_read))
434       FD_SET (0, &fds_r);
435
436     /*
437      * We are supposed to write and the buffer is not empty
438      * -> select on write to tun
439      */
440     if (write_open && (NULL != bufin_read))
441       FD_SET (fd_tun, &fds_w);
442
443     int r = select (fd_tun + 1, &fds_r, &fds_w, NULL, NULL);
444
445     if (-1 == r)
446     {
447       if (EINTR == errno)
448         continue;
449       fprintf (stderr,
450                "select failed: %s\n",
451                strerror (errno));
452       exit (1);
453     }
454
455     if (r > 0)
456     {
457       if (FD_ISSET (fd_tun, &fds_r))
458       {
459         buftun_size =
460           read (fd_tun, buftun + sizeof(struct GNUNET_MessageHeader),
461                 MAX_SIZE - sizeof(struct GNUNET_MessageHeader));
462         if (-1 == buftun_size)
463         {
464           fprintf (stderr,
465                    "read-error: %s\n",
466                    strerror (errno));
467           shutdown (fd_tun, SHUT_RD);
468           shutdown (1, SHUT_WR);
469           read_open = 0;
470           buftun_size = 0;
471         }
472         else if (0 == buftun_size)
473         {
474           fprintf (stderr, "EOF on tun\n");
475           shutdown (fd_tun, SHUT_RD);
476           shutdown (1, SHUT_WR);
477           read_open = 0;
478           buftun_size = 0;
479         }
480         else
481         {
482           buftun_read = buftun;
483           struct GNUNET_MessageHeader *hdr =
484             (struct GNUNET_MessageHeader *) buftun;
485           buftun_size += sizeof(struct GNUNET_MessageHeader);
486           hdr->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
487           hdr->size = htons (buftun_size);
488         }
489       }
490       else if (FD_ISSET (1, &fds_w))
491       {
492         ssize_t written = write (1,
493                                  buftun_read,
494                                  buftun_size);
495
496         if (-1 == written)
497         {
498 #if ! DEBUG
499           if (errno != EPIPE)
500 #endif
501           fprintf (stderr,
502                    "write-error to stdout: %s\n",
503                    strerror (errno));
504           shutdown (fd_tun, SHUT_RD);
505           shutdown (1, SHUT_WR);
506           read_open = 0;
507           buftun_size = 0;
508         }
509         else if (0 == written)
510         {
511           fprintf (stderr,
512                    "write returned 0!?\n");
513           exit (1);
514         }
515         else
516         {
517           buftun_size -= written;
518           buftun_read += written;
519         }
520       }
521
522       if (FD_ISSET (0, &fds_r))
523       {
524         bufin_size = read (0, bufin + bufin_rpos, MAX_SIZE - bufin_rpos);
525         if (-1 == bufin_size)
526         {
527           fprintf (stderr,
528                    "read-error: %s\n",
529                    strerror (errno));
530           shutdown (0, SHUT_RD);
531           shutdown (fd_tun, SHUT_WR);
532           write_open = 0;
533           bufin_size = 0;
534         }
535         else if (0 == bufin_size)
536         {
537 #if DEBUG
538           fprintf (stderr, "EOF on stdin\n");
539 #endif
540           shutdown (0, SHUT_RD);
541           shutdown (fd_tun, SHUT_WR);
542           write_open = 0;
543           bufin_size = 0;
544         }
545         else
546         {
547           struct GNUNET_MessageHeader *hdr;
548
549 PROCESS_BUFFER:
550           bufin_rpos += bufin_size;
551           if (bufin_rpos < sizeof(struct GNUNET_MessageHeader))
552             continue;
553           hdr = (struct GNUNET_MessageHeader *) bufin;
554           if (ntohs (hdr->type) != GNUNET_MESSAGE_TYPE_VPN_HELPER)
555           {
556             fprintf (stderr,
557                      "protocol violation!\n");
558             exit (1);
559           }
560           if (ntohs (hdr->size) > bufin_rpos)
561             continue;
562           bufin_read = bufin + sizeof(struct GNUNET_MessageHeader);
563           bufin_size = ntohs (hdr->size) - sizeof(struct GNUNET_MessageHeader);
564           bufin_rpos -= bufin_size + sizeof(struct GNUNET_MessageHeader);
565         }
566       }
567       else if (FD_ISSET (fd_tun, &fds_w))
568       {
569         ssize_t written = write (fd_tun,
570                                  bufin_read,
571                                  bufin_size);
572
573         if (-1 == written)
574         {
575           fprintf (stderr,
576                    "write-error to tun: %s\n",
577                    strerror (errno));
578           shutdown (0, SHUT_RD);
579           shutdown (fd_tun, SHUT_WR);
580           write_open = 0;
581           bufin_size = 0;
582         }
583         else if (0 == written)
584         {
585           fprintf (stderr, "write returned 0!?\n");
586           exit (1);
587         }
588         else
589         {
590           bufin_size -= written;
591           bufin_read += written;
592           if (0 == bufin_size)
593           {
594             memmove (bufin, bufin_read, bufin_rpos);
595             bufin_read = NULL;           /* start reading again */
596             bufin_size = 0;
597             goto PROCESS_BUFFER;
598           }
599         }
600       }
601     }
602   }
603 }
604
605
606 /**
607  * Open VPN tunnel interface.
608  *
609  * @param argc must be 6
610  * @param argv 0: binary name (gnunet-helper-vpn)
611  *             1: tunnel interface name (gnunet-vpn)
612  *             2: IPv6 address (::1), "-" to disable
613  *             3: IPv6 netmask length in bits (64), ignored if #2 is "-"
614  *             4: IPv4 address (1.2.3.4), "-" to disable
615  *             5: IPv4 netmask (255.255.0.0), ignored if #4 is "-"
616  */
617 int
618 main (int argc, char **argv)
619 {
620   char dev[IFNAMSIZ];
621   int fd_tun;
622   int global_ret;
623
624   if (6 != argc)
625   {
626     fprintf (stderr, "Fatal: must supply 5 arguments!\n");
627     return 1;
628   }
629
630   strncpy (dev,
631            argv[1],
632            IFNAMSIZ);
633   dev[IFNAMSIZ - 1] = '\0';
634
635   if (-1 == (fd_tun = init_tun (dev)))
636   {
637     fprintf (stderr,
638              "Fatal: could not initialize tun-interface `%s'  with IPv6 %s/%s and IPv4 %s/%s\n",
639              dev,
640              argv[2],
641              argv[3],
642              argv[4],
643              argv[5]);
644     return 1;
645   }
646
647   if (0 != strcmp (argv[2], "-"))
648   {
649     const char *address = argv[2];
650     long prefix_len = atol (argv[3]);
651
652     if ((prefix_len < 1) || (prefix_len > 127))
653     {
654       fprintf (stderr,
655                "Fatal: prefix_len out of range\n");
656       close (fd_tun);
657       return 1;
658     }
659
660     set_address6 (dev,
661                   address,
662                   prefix_len);
663   }
664
665   if (0 != strcmp (argv[4], "-"))
666   {
667     const char *address = argv[4];
668     const char *mask = argv[5];
669
670     set_address4 (dev, address, mask);
671   }
672
673   uid_t uid = getuid ();
674 #ifdef HAVE_SETRESUID
675   if (0 != setresuid (uid, uid, uid))
676   {
677     fprintf (stderr,
678              "Failed to setresuid: %s\n",
679              strerror (errno));
680     global_ret = 2;
681     goto cleanup;
682   }
683 #else
684   if (0 != (setuid (uid) | seteuid (uid)))
685   {
686     fprintf (stderr,
687              "Failed to setuid: %s\n",
688              strerror (errno));
689     global_ret = 2;
690     goto cleanup;
691   }
692 #endif
693
694   if (SIG_ERR == signal (SIGPIPE, SIG_IGN))
695   {
696     fprintf (stderr,
697              "Failed to protect against SIGPIPE: %s\n",
698              strerror (errno));
699     /* no exit, we might as well die with SIGPIPE should it ever happen */
700   }
701   run (fd_tun);
702   global_ret = 0;
703 cleanup:
704   close (fd_tun);
705   return global_ret;
706 }