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