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