Testing and core related changes.
[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, 
123               const char *address, 
124               unsigned long prefix_len)
125 {
126   struct ifreq ifr;
127   struct in6_ifreq ifr6;
128   struct sockaddr_in6 sa6;
129   int fd;
130
131   /*
132    * parse the new address
133    */
134   memset (&sa6, 0, sizeof (struct sockaddr_in6));
135   if (1 != inet_pton (AF_INET6, address, sa6.sin6_addr.s6_addr))
136     {
137       fprintf (stderr,
138                "Failed to parse address `%s': %s\n",
139                address, strerror (errno));
140       exit (1);
141     }
142
143   if (-1 == (fd = socket (PF_INET6, SOCK_DGRAM, 0)))
144     {
145       fprintf (stderr,
146                "Error creating socket: %s\n", 
147                strerror (errno));
148       exit (1);
149     }
150
151   sa6.sin6_family = AF_INET6;
152   memcpy (&ifr6.ifr6_addr, 
153           &sa6.sin6_addr, 
154           sizeof (struct in6_addr));
155
156
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,
164                "ioctl failed at %d: %s\n",
165                __LINE__, 
166                strerror (errno));
167       exit (1);
168     }
169   ifr6.ifr6_ifindex = ifr.ifr_ifindex;
170
171   ifr6.ifr6_prefixlen = prefix_len;
172
173   /*
174    * Set the address
175    */
176   if (-1 == ioctl (fd, SIOCSIFADDR, &ifr6))
177     {
178       fprintf (stderr,
179                "ioctl failed at line %d: %s\n", __LINE__, strerror (errno));
180       exit (1);
181     }
182
183   /*
184    * Get the flags
185    */
186   if (-1 == ioctl (fd, SIOCGIFFLAGS, &ifr))
187     {
188       fprintf (stderr,
189                "ioctl failed at line %d: %s\n", __LINE__, strerror (errno));
190       exit (1);
191     }
192
193   /*
194    * Add the UP and RUNNING flags
195    */
196   ifr.ifr_flags |= IFF_UP | IFF_RUNNING;
197   if (-1 == ioctl (fd, SIOCSIFFLAGS, &ifr))
198     {
199       fprintf (stderr,
200                "ioctl failed at line %d: %s\n", __LINE__, strerror (errno));
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, 
221               const char *address, 
222               const char *mask)
223 {
224   int fd;
225   struct sockaddr_in *addr;
226   struct ifreq ifr;
227
228   memset (&ifr, 0, sizeof (struct ifreq));
229   addr = (struct sockaddr_in *) &(ifr.ifr_addr);
230   memset (addr, 0, sizeof (struct sockaddr_in));
231   addr->sin_family = AF_INET;
232   addr->sin_addr.s_addr = inet_addr (address);
233
234   /*
235    * Parse the address
236    */
237   if (1 != inet_pton (AF_INET, address, &addr->sin_addr.s_addr))
238     {
239       fprintf (stderr,
240                "Failed to parse address `%s': %s\n",
241                address, strerror (errno));
242       exit (1);
243     }
244
245   
246   if (-1 == (fd = socket (PF_INET, SOCK_DGRAM, 0)))
247     {
248       fprintf (stderr, 
249                "Error creating socket: %s\n", 
250                strerror (errno));
251       exit (1);
252     }
253
254   strncpy (ifr.ifr_name, dev, IFNAMSIZ);
255
256   /*
257    * Set the address
258    */
259   if (-1 == ioctl (fd, SIOCSIFADDR, &ifr))
260     {
261       fprintf (stderr,
262                "ioctl failed at %d: %s\n",
263                __LINE__, 
264                strerror (errno));
265       exit (1);
266     }
267
268   /*
269    * Parse the netmask
270    */
271   addr = (struct sockaddr_in *) &(ifr.ifr_netmask);
272   if (1 != inet_pton (AF_INET, mask, &addr->sin_addr.s_addr))
273     {
274       fprintf (stderr,
275                "Failed to parse address `%s': %s\n",
276                mask, 
277                strerror (errno));
278       exit (1);
279     }
280
281   /*
282    * Set the netmask
283    */
284   if (-1 == ioctl (fd, SIOCSIFNETMASK, &ifr))
285     {
286       fprintf (stderr,
287                "ioctl failed at line %d: %s\n", __LINE__, strerror (errno));
288       exit (1);
289     }
290
291   /*
292    * Get the flags
293    */
294   if (-1 == ioctl (fd, SIOCGIFFLAGS, &ifr))
295     {
296       fprintf (stderr,
297                "ioctl failed at line %d: %s\n", __LINE__, strerror (errno));
298       exit (1);
299     }
300
301   /*
302    * Add the UP and RUNNING flags
303    */
304   ifr.ifr_flags |= IFF_UP | IFF_RUNNING;
305   if (-1 == ioctl (fd, SIOCSIFFLAGS, &ifr))
306     {
307       fprintf (stderr,
308                "ioctl failed at line %d: %s\n", __LINE__, strerror (errno));
309       exit (1);
310     }
311
312   if (0 != close (fd))
313     {
314       fprintf (stderr, "close failed: %s\n", strerror (errno));
315       exit (1);
316     }
317 }
318
319
320 static void
321 run (int fd_tun)
322 {
323   /*
324    * The buffer filled by reading from fd_tun
325    */
326   unsigned char buftun[MAX_SIZE];
327   ssize_t buftun_size = 0;
328   unsigned char *buftun_read;
329
330   /*
331    * The buffer filled by reading from stdin
332    */
333   unsigned char bufin[MAX_SIZE];
334   ssize_t bufin_size = 0;
335   size_t bufin_rpos = 0;
336   unsigned char *bufin_read = NULL;
337
338   fd_set fds_w;
339   fd_set fds_r;
340
341   /* read refers to reading from fd_tun, writing to stdout */
342   int read_open = 1;
343   /* write refers to reading from stdin, writing to fd_tun */
344   int write_open = 1;
345
346   while ((1 == read_open) || (1 == write_open))
347     {
348       FD_ZERO (&fds_w);
349       FD_ZERO (&fds_r);
350
351       /*
352        * We are supposed to read and the buffer is empty
353        * -> select on read from tun
354        */
355       if (read_open && (0 == buftun_size))
356         FD_SET (fd_tun, &fds_r);        
357
358       /*
359        * We are supposed to read and the buffer is not empty
360        * -> select on write to stdout
361        */
362       if (read_open && (0 != buftun_size))
363         FD_SET (1, &fds_w);
364
365       /*
366        * We are supposed to write and the buffer is empty
367        * -> select on read from stdin
368        */
369       if (write_open && (NULL == bufin_read))
370         FD_SET (0, &fds_r);
371
372       /*
373        * We are supposed to write and the buffer is not empty
374        * -> select on write to tun
375        */
376       if (write_open && (NULL != bufin_read))
377         FD_SET (fd_tun, &fds_w);        
378
379       int r = select (fd_tun + 1, &fds_r, &fds_w, NULL, NULL);
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               if (-1 == written)
425                 {
426                   fprintf (stderr, 
427                            "write-error to stdout: %s\n",
428                            strerror (errno));
429                   shutdown (fd_tun, SHUT_RD);
430                   shutdown (1, SHUT_WR);
431                   read_open = 0;
432                   buftun_size = 0;
433                 }
434               else if (0 == written)
435                 {
436                   fprintf (stderr, 
437                            "write returned 0!?\n");
438                   exit (1);
439                 }
440               else
441                 {
442                   buftun_size -= written;
443                   buftun_read += written;
444                 }
445             }
446
447           if (FD_ISSET (0, &fds_r))
448             {
449               bufin_size = read (0, bufin + bufin_rpos, MAX_SIZE - bufin_rpos);
450               if (-1 == bufin_size)
451                 {
452                   fprintf (stderr, 
453                            "read-error: %s\n", 
454                            strerror (errno));
455                   shutdown (0, SHUT_RD);
456                   shutdown (fd_tun, SHUT_WR);
457                   write_open = 0;
458                   bufin_size = 0;
459                 }
460               else if (0 == bufin_size)
461                 {
462                   fprintf (stderr, 
463                            "EOF on stdin\n");
464                   shutdown (0, SHUT_RD);
465                   shutdown (fd_tun, SHUT_WR);
466                   write_open = 0;
467                   bufin_size = 0;
468                 }
469               else
470                 {
471                   struct GNUNET_MessageHeader *hdr;
472
473                 PROCESS_BUFFER:
474                   bufin_rpos += bufin_size;
475                   if (bufin_rpos < sizeof (struct GNUNET_MessageHeader))
476                     continue;
477                   hdr = (struct GNUNET_MessageHeader *) bufin;
478                   if (ntohs (hdr->type) != GNUNET_MESSAGE_TYPE_VPN_HELPER)
479                     {
480                       fprintf (stderr, "protocol violation!\n");
481                       exit (1);
482                     }
483                   if (ntohs (hdr->size) > bufin_rpos)
484                     continue;
485                   bufin_read = bufin + sizeof (struct GNUNET_MessageHeader);
486                   bufin_size = ntohs (hdr->size) - sizeof (struct GNUNET_MessageHeader);
487                   bufin_rpos -= bufin_size + sizeof (struct GNUNET_MessageHeader);
488                 }
489             }
490           else if (FD_ISSET (fd_tun, &fds_w))
491             {
492               ssize_t written = write (fd_tun, bufin_read, bufin_size);
493               if (-1 == written)
494                 {
495                   fprintf (stderr, "write-error to tun: %s\n",
496                            strerror (errno));
497                   shutdown (0, SHUT_RD);
498                   shutdown (fd_tun, SHUT_WR);
499                   write_open = 0;
500                   bufin_size = 0;
501                 }
502               else if (0 == written)
503                 {
504                   fprintf (stderr, 
505                            "write returned 0!?\n");
506                   exit (1);
507                 }
508               else
509                 {
510                   bufin_size -= written;
511                   bufin_read += written;
512                   if (0 == bufin_size)
513                     {
514                       memmove (bufin, 
515                                bufin_read,
516                                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 int
529 main (int argc, char **argv)
530 {
531   char dev[IFNAMSIZ];
532   int fd_tun;
533
534   if (6 != argc)
535     {
536       fprintf (stderr, 
537                "Fatal: must supply 5 arguments!\n");
538       return 1;
539     }
540
541   strncpy(dev, argv[1], IFNAMSIZ);
542   dev[IFNAMSIZ - 1] = '\0';
543
544   if (-1 == (fd_tun = init_tun (dev)))
545     {
546       fprintf (stderr, 
547                "Fatal: could not initialize tun-interface\n");
548       return 1;
549     }
550
551   {
552     const char *address = argv[2];
553     long prefix_len = atol(argv[3]);
554
555     if ( (prefix_len < 1) || (prefix_len > 127) )
556       {
557         fprintf(stderr, "Fatal: prefix_len out of range\n");
558         return 1;
559       }
560
561     set_address6 (dev, address, prefix_len);
562   }
563   
564   {
565     const char *address = argv[4];
566     const char *mask = argv[5];
567
568     set_address4 (dev, address, mask);
569   }
570
571   uid_t uid = getuid ();
572   if (0 != setresuid (uid, uid, uid))
573     fprintf (stderr, 
574              "Failed to setresuid: %s\n",
575              strerror (errno));
576   if (SIG_ERR == signal (SIGPIPE, SIG_IGN))
577     fprintf (stderr, 
578              "Failed to protect against SIGPIPE: %s\n", 
579              strerror (errno));
580   run (fd_tun);
581   close (fd_tun);
582   return 0;
583 }