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