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