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