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