doxyfixes
[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 #include <platform.h>
29 #include <linux/if_tun.h>
30
31 /**
32  * Need 'struct GNUNET_MessageHeader'.
33  */
34 #include "gnunet_common.h"
35
36 /**
37  * Need VPN message types.
38  */
39 #include "gnunet_protocols.h"
40
41 /**
42  * Maximum size of a GNUnet message (GNUNET_SERVER_MAX_MESSAGE_SIZE)
43  */
44 #define MAX_SIZE 65536
45
46 #ifndef _LINUX_IN6_H
47 /**
48  * This is in linux/include/net/ipv6.h, but not always exported...
49  */
50 struct in6_ifreq 
51 {
52   struct in6_addr ifr6_addr;
53   uint32_t ifr6_prefixlen;
54   unsigned int ifr6_ifindex;
55 };
56 #endif
57
58
59 /**
60  * Creates a tun-interface called dev;
61  * @param dev is asumed to point to a char[IFNAMSIZ]
62  *        if *dev == '\\0', uses the name supplied by the kernel
63  * @return the fd to the tun or -1 on error
64  */
65 static int 
66 init_tun (char *dev) 
67 {
68   struct ifreq ifr;
69   int fd;
70
71   if (NULL == dev) 
72     {
73       errno = EINVAL;
74       return -1;
75     }
76
77   if (-1 == (fd = open("/dev/net/tun", O_RDWR))) 
78     {
79       fprintf (stderr, 
80                "Error opening `%s': %s\n", 
81                "/dev/net/tun",
82                strerror(errno));
83       return -1;
84     }
85
86   memset(&ifr, 0, sizeof(ifr));
87   ifr.ifr_flags = IFF_TUN;
88
89   if ('\0' == *dev)
90     strncpy(ifr.ifr_name, dev, IFNAMSIZ);
91
92   if (-1 == ioctl(fd, TUNSETIFF, (void *) &ifr))
93     {
94       fprintf (stderr, 
95                "Error with ioctl on `%s': %s\n", 
96                "/dev/net/tun",
97                strerror(errno));
98       close (fd);
99       return -1;
100     }
101   strcpy(dev, ifr.ifr_name);
102   return fd;
103 }
104
105
106 /**
107  * @brief Sets the IPv6-Address given in address on the interface dev
108  *
109  * @param dev the interface to configure
110  * @param address the IPv6-Address
111  * @param prefix_len the length of the network-prefix
112  */
113 static void
114 set_address6 (const char *dev, 
115               const char *address, 
116               unsigned long prefix_len)
117 {                           
118   struct ifreq ifr;
119   struct in6_ifreq ifr6;
120   struct sockaddr_in6 sa6;
121   int fd;
122
123   if (-1 == (fd = socket (PF_INET6, SOCK_DGRAM, 0)))
124     {
125       fprintf (stderr, 
126                "Error creating socket: %s\n",
127                strerror (errno));
128       exit (1);
129     }
130   memset (&sa6, 0, sizeof (struct sockaddr_in6));
131   sa6.sin6_family = AF_INET6;
132
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",
137                address,
138                strerror (errno));
139       exit (1);
140     }
141
142   memcpy (&ifr6.ifr6_addr, 
143           &sa6.sin6_addr,
144           sizeof (struct in6_addr));
145   strncpy (ifr.ifr_name, dev, IFNAMSIZ);
146   if (-1 == ioctl (fd, SIOGIFINDEX, &ifr))
147     {
148       fprintf (stderr, 
149                "ioctl failed at %d: %s\n",
150                __LINE__,
151                strerror (errno));
152       exit (1);
153     }
154
155   ifr6.ifr6_ifindex = ifr.ifr_ifindex;
156   ifr6.ifr6_prefixlen = prefix_len;
157   if (-1 == ioctl (fd, SIOCSIFADDR, &ifr6))
158     {
159       fprintf (stderr, 
160                "ioctl failed at line %d: %s\n",
161                __LINE__,
162                strerror (errno));
163       exit (1);
164     }
165
166   if (-1 == ioctl (fd, SIOCGIFFLAGS, &ifr))
167     {
168       fprintf (stderr, 
169                "ioctl failed at line %d: %s\n",
170                __LINE__,
171                strerror (errno));
172       exit (1);
173     }
174   ifr.ifr_flags |= IFF_UP | IFF_RUNNING;
175   if (-1 == ioctl (fd, SIOCSIFFLAGS, &ifr))
176     {
177       fprintf (stderr, 
178                "ioctl failed at line %d: %s\n",
179                __LINE__,
180                strerror (errno));
181       exit (1);
182     }
183
184   if (0 != close (fd))
185     {
186       fprintf (stderr, 
187                "close failed: %s\n",
188                strerror (errno));
189       exit (1);
190     }
191 }
192
193
194 /**
195  * @brief Sets the IPv4-Address given in address on the interface dev
196  *
197  * @param dev the interface to configure
198  * @param address the IPv4-Address
199  * @param mask the netmask
200  */
201 static void
202 set_address4 (char *dev, char *address, char *mask)
203 {
204   int fd = 0;
205   struct sockaddr_in *addr;
206   struct ifreq ifr;
207
208   memset (&ifr, 0, sizeof (struct ifreq));
209   addr = (struct sockaddr_in *) &(ifr.ifr_addr);
210   memset (addr, 0, sizeof (struct sockaddr_in));
211   addr->sin_family = AF_INET;
212   addr->sin_addr.s_addr = inet_addr (address);
213
214   int r = inet_pton (AF_INET, address, &addr->sin_addr.s_addr);
215   if (r < 0)
216     {
217       fprintf (stderr, "error at inet_pton: %m\n");
218       exit (1);
219     }
220
221   fd = socket (PF_INET, SOCK_DGRAM, 0);
222   if (fd < 0)
223     {
224       perror ("socket()");
225       return;
226     }
227
228   strncpy (ifr.ifr_name, dev, IFNAMSIZ);
229
230   if (ioctl (fd, SIOCSIFADDR, &ifr) != 0)
231     {
232       perror ("SIOCSIFADDR");
233       close (fd);
234       return;
235     }
236
237   addr = (struct sockaddr_in *) &(ifr.ifr_netmask);
238   r = inet_pton (AF_INET, mask, &addr->sin_addr.s_addr);
239   if (r < 0)
240     {
241       fprintf (stderr, "error at inet_pton: %m\n");
242       exit (1);
243     }
244
245   if (ioctl (fd, SIOCSIFNETMASK, &ifr) != 0)
246     {
247       perror ("SIOCSIFNETMASK");
248       close (fd);
249       return;
250     }
251
252   (void) ioctl (fd, SIOCGIFFLAGS, &ifr);
253   ifr.ifr_flags |= IFF_UP | IFF_RUNNING;
254   (void) ioctl (fd, SIOCSIFFLAGS, &ifr);
255   close (fd);
256 }
257
258
259 static void
260 run (int fd_tun)
261 {
262   unsigned char buf[MAX_SIZE];
263   fd_set fds_w;
264   fd_set fds_r;
265   int rea = 1;
266   int wri = 1;
267   int write_fd_possible = 0;
268   int write_stdout_possible = 0;
269   ssize_t tin;
270 outer:
271   while ((1 == rea) || (1 == wri))
272     {
273       FD_ZERO (&fds_w);
274       FD_ZERO (&fds_r);
275
276       if (rea)
277         {
278           FD_SET (fd_tun, &fds_r);
279           if (!write_stdout_possible)
280             FD_SET (1, &fds_w);
281         }
282
283       if (wri)
284         {
285           FD_SET (0, &fds_r);
286           if (!write_fd_possible)
287             FD_SET (fd_tun, &fds_w);
288         }
289
290       int r = select (fd_tun + 1, &fds_r, &fds_w, NULL, NULL);
291       /* FIXME: if error... */
292       if (r > 0)
293         {
294           if (FD_ISSET (fd_tun, &fds_w))
295             write_fd_possible = 1;
296           if (FD_ISSET (1, &fds_w))
297             write_stdout_possible = 1;
298
299           if (FD_ISSET (0, &fds_r) && write_fd_possible)
300             {
301               write_fd_possible = 0;
302               struct GNUNET_MessageHeader *pkt = ( struct GNUNET_MessageHeader *) buf;
303               tin = read (0, buf, sizeof (struct GNUNET_MessageHeader));
304               if (tin <= 0)
305                 {
306                   fprintf (stderr, "read-error: %s\n", strerror (errno));
307                   shutdown (fd_tun, SHUT_WR);
308                   shutdown (0, SHUT_RD);
309                   wri = 0;
310                   goto outer;
311                 }
312               if (pkt->type != ntohs (GNUNET_MESSAGE_TYPE_VPN_HELPER))
313                 abort ();
314               while (tin < ntohs (pkt->size))
315                 {
316                   ssize_t t = read (0, buf + tin, ntohs (pkt->size) - tin);
317                   if (t <= 0)
318                     {
319                       fprintf (stderr, "read-error: %s\n", strerror (errno));
320                       shutdown (fd_tun, SHUT_WR);
321                       shutdown (0, SHUT_RD);
322                       wri = 0;
323                       goto outer;
324                     }
325                   tin += t;
326                 }
327               tin = 0;
328               while (tin <
329                      ntohs (pkt->size) -
330                      sizeof (struct GNUNET_MessageHeader))
331                 {
332                   ssize_t t = write (fd_tun, &pkt[1],
333                                  ntohs (pkt->size) -
334                                  sizeof (struct GNUNET_MessageHeader) - tin);
335                   if (t <= 0)
336                     {
337                       fprintf (stderr, "write-error 3: %s\n",
338                                strerror (errno));
339                       shutdown (fd_tun, SHUT_WR);
340                       shutdown (0, SHUT_RD);
341                       wri = 0;
342                       goto outer;
343                     }
344                   tin += t;
345                 }
346             }
347           else if (write_stdout_possible && FD_ISSET (fd_tun, &fds_r))
348             {
349               write_stdout_possible = 0;
350               tin = read (fd_tun, buf, MAX_SIZE);
351               if (tin <= 0)
352                 {
353                   fprintf (stderr, "read-error: %s\n", strerror (errno));
354                   shutdown (fd_tun, SHUT_RD);
355                   shutdown (1, SHUT_WR);
356                   rea = 0;
357                   goto outer;
358                 }
359               struct GNUNET_MessageHeader hdr = {.size =
360                   htons (r + sizeof (struct GNUNET_MessageHeader)),.type =
361                   htons (GNUNET_MESSAGE_TYPE_VPN_HELPER)
362               };
363               tin = 0;
364               while (tin < sizeof (struct GNUNET_MessageHeader))
365                 {
366                   ssize_t t =
367                     write (1, &hdr, sizeof (struct GNUNET_MessageHeader) - tin);
368                   if (t < 0)
369                     {
370                       fprintf (stderr, "write-error 2: %s\n",
371                                strerror (errno));
372                       shutdown (fd_tun, SHUT_RD);
373                       shutdown (1, SHUT_WR);
374                       rea = 0;
375                       goto outer;
376                     }
377                   tin += t;
378                 }
379               while (tin < ntohs (hdr.size))
380                 {
381                   size_t t = write (1, buf, ntohs (hdr.size) - tin);
382                   if (t < 0)
383                     {
384                       fprintf (stderr, "write-error 1: %s, written %d/%d\n",
385                                strerror (errno), r, ntohs (hdr.size));
386                       shutdown (fd_tun, SHUT_RD);
387                       shutdown (1, SHUT_WR);
388                       rea = 0;
389                       goto outer;
390                     }
391                   tin += t;
392                 }
393             }
394         }
395     }
396 }
397
398
399 int 
400 main (int argc, 
401       char** argv) 
402 {
403   char dev[IFNAMSIZ];
404   int fd_tun;
405
406   memset (dev, 0, IFNAMSIZ);
407   if (-1 == (fd_tun = init_tun (dev)))
408     {
409       fprintf (stderr, 
410                "Fatal: could not initialize tun-interface\n");
411       return 1;
412     }
413
414   {
415     // TODO: get this out of argv
416     char address[] = "1234::1";
417     unsigned long prefix_len = 16;
418
419     set_address6 (dev, address, prefix_len);
420   }
421
422   {
423     char address[] = "10.10.10.1";
424     char mask[] = "255.255.255.252";
425
426     set_address4 (dev, address, mask);
427   }
428
429   uid_t uid = getuid ();
430   if (0 != setresuid (uid, uid, uid))
431     fprintf (stderr, 
432              "Failed to setresuid: %s\n", 
433              strerror (errno));
434   run (fd_tun);
435   close (fd_tun);
436   return 0;
437 }