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