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