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