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