aboutsummaryrefslogtreecommitdiff
path: root/src/service/vpn
diff options
context:
space:
mode:
Diffstat (limited to 'src/service/vpn')
-rw-r--r--src/service/vpn/.gitignore3
-rw-r--r--src/service/vpn/Makefile.am53
-rw-r--r--src/service/vpn/gnunet-helper-vpn.c707
-rw-r--r--src/service/vpn/gnunet-service-vpn.c3130
-rw-r--r--src/service/vpn/meson.build52
-rw-r--r--src/service/vpn/tests/expectedbin0 -> 112 bytes
-rw-r--r--src/service/vpn/tests/pingbin0 -> 112 bytes
-rwxr-xr-xsrc/service/vpn/tests/test-helper-icmp.sh17
-rwxr-xr-xsrc/service/vpn/tests/test-helper-ifaddr.sh41
-rw-r--r--src/service/vpn/vpn.conf.in19
-rw-r--r--src/service/vpn/vpn.h153
-rw-r--r--src/service/vpn/vpn_api.c529
12 files changed, 4704 insertions, 0 deletions
diff --git a/src/service/vpn/.gitignore b/src/service/vpn/.gitignore
new file mode 100644
index 000000000..b76ea0f93
--- /dev/null
+++ b/src/service/vpn/.gitignore
@@ -0,0 +1,3 @@
1gnunet-vpn
2gnunet-helper-vpn
3gnunet-service-vpn
diff --git a/src/service/vpn/Makefile.am b/src/service/vpn/Makefile.am
new file mode 100644
index 000000000..af500a0b8
--- /dev/null
+++ b/src/service/vpn/Makefile.am
@@ -0,0 +1,53 @@
1# This Makefile.am is in the public domain
2AM_CPPFLAGS = -I$(top_srcdir)/src/include -I$(top_builddir)/src/include
3
4if USE_COVERAGE
5 AM_CFLAGS = --coverage -O0
6endif
7
8pkgcfgdir= $(pkgdatadir)/config.d/
9
10libexecdir= $(pkglibdir)/libexec/
11
12plugindir = $(libdir)/gnunet
13
14pkgcfg_DATA = \
15 vpn.conf
16
17if LINUX
18VPNBIN = gnunet-helper-vpn
19endif
20
21
22lib_LTLIBRARIES = \
23 libgnunetvpn.la
24
25
26libexec_PROGRAMS = \
27 $(VPNBIN) \
28 gnunet-service-vpn
29
30gnunet_helper_vpn_SOURCES = \
31 gnunet-helper-vpn.c
32gnunet_helper_vpn_LDADD = \
33 $(top_builddir)/src/lib/util/libgnunetutil.la \
34 $(GN_LIBINTL)
35
36gnunet_service_vpn_SOURCES = \
37 gnunet-service-vpn.c
38gnunet_service_vpn_LDADD = \
39 $(top_builddir)/src/service/statistics/libgnunetstatistics.la \
40 $(top_builddir)/src/lib/util/libgnunetutil.la \
41 $(top_builddir)/src/service/cadet/libgnunetcadet.la \
42 $(top_builddir)/src/service/regex/libgnunetregex.la \
43 $(GN_LIBINTL)
44gnunet_service_vpn_CFLAGS = \
45 -I$(top_srcdir)/src/service/exit $(CFLAGS)
46
47libgnunetvpn_la_SOURCES = \
48 vpn_api.c vpn.h
49libgnunetvpn_la_LIBADD = \
50 $(top_builddir)/src/lib/util/libgnunetutil.la $(XLIB)
51libgnunetvpn_la_LDFLAGS = \
52 $(GN_LIBINTL) \
53 $(GN_LIB_LDFLAGS)
diff --git a/src/service/vpn/gnunet-helper-vpn.c b/src/service/vpn/gnunet-helper-vpn.c
new file mode 100644
index 000000000..30901da45
--- /dev/null
+++ b/src/service/vpn/gnunet-helper-vpn.c
@@ -0,0 +1,707 @@
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_util_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}
diff --git a/src/service/vpn/gnunet-service-vpn.c b/src/service/vpn/gnunet-service-vpn.c
new file mode 100644
index 000000000..aa3f6ffe3
--- /dev/null
+++ b/src/service/vpn/gnunet-service-vpn.c
@@ -0,0 +1,3130 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2010, 2011, 2012, 2016, 2017 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-service-vpn.c
23 * @brief service that opens a virtual interface and allows its clients
24 * to allocate IPs on the virtual interface and to then redirect
25 * IP traffic received on those IPs via the GNUnet cadet
26 * @author Philipp Toelke
27 * @author Christian Grothoff
28 *
29 * TODO:
30 * - keep multiple peers/cadet channels ready as alternative exits /
31 * detect & recover from channel-to-exit failure gracefully
32 */
33#include "platform.h"
34#include "gnunet_util_lib.h"
35#include "gnunet_common.h"
36#include "gnunet_protocols.h"
37#include "gnunet_applications.h"
38#include "gnunet_cadet_service.h"
39#include "gnunet_statistics_service.h"
40#include "gnunet_constants.h"
41#include "gnunet_regex_service.h"
42#include "vpn.h"
43#include "exit.h"
44
45
46/**
47 * Maximum number of messages we allow in the queue for cadet.
48 */
49#define MAX_MESSAGE_QUEUE_SIZE 4
50
51
52/**
53 * State we keep for each of our channels.
54 */
55struct ChannelState;
56
57/**
58 * Information we track for each IP address to determine which channel
59 * to send the traffic over to the destination.
60 */
61struct DestinationEntry;
62
63/**
64 * List of channels we keep for each destination port for a given
65 * destination entry.
66 */
67struct DestinationChannel
68{
69 /**
70 * Kept in a DLL.
71 */
72 struct DestinationChannel *next;
73
74 /**
75 * Kept in a DLL.
76 */
77 struct DestinationChannel *prev;
78
79 /**
80 * Destination entry list this `struct DestinationChannel` belongs with.
81 */
82 struct DestinationEntry *destination;
83
84 /**
85 * Destination port this channel state is used for.
86 */
87 uint16_t destination_port;
88};
89
90
91/**
92 * Information we track for each IP address to determine which channel
93 * to send the traffic over to the destination.
94 */
95struct DestinationEntry
96{
97 /**
98 * Key under which this entry is in the 'destination_map' (only valid
99 * if 'heap_node != NULL').
100 */
101 struct GNUNET_HashCode key;
102
103 /**
104 * Head of DLL of channels associated with this destination.
105 */
106 struct DestinationChannel *dt_head;
107
108 /**
109 * Tail of DLL of channels associated with this destination.
110 */
111 struct DestinationChannel *dt_tail;
112
113 /**
114 * Entry for this entry in the destination_heap.
115 */
116 struct GNUNET_CONTAINER_HeapNode *heap_node;
117
118 /**
119 * #GNUNET_NO if this is a channel to an Internet-exit,
120 * #GNUNET_YES if this channel is to a service.
121 */
122 int is_service;
123
124 /**
125 * Details about the connection (depending on is_service).
126 */
127 union
128 {
129 struct
130 {
131 /**
132 * The description of the service (only used for service channels).
133 */
134 struct GNUNET_HashCode service_descriptor;
135
136 /**
137 * Peer offering the service.
138 */
139 struct GNUNET_PeerIdentity target;
140 } service_destination;
141
142 struct
143 {
144 /**
145 * Address family used (AF_INET or AF_INET6).
146 */
147 int af;
148
149 /**
150 * IP address of the ultimate destination (only used for exit channels).
151 */
152 union
153 {
154 /**
155 * Address if af is AF_INET.
156 */
157 struct in_addr v4;
158
159 /**
160 * Address if af is AF_INET6.
161 */
162 struct in6_addr v6;
163 } ip;
164 } exit_destination;
165 } details;
166};
167
168
169/**
170 * A messages we have in queue for a particular channel.
171 */
172struct ChannelMessageQueueEntry
173{
174 /**
175 * This is a doubly-linked list.
176 */
177 struct ChannelMessageQueueEntry *next;
178
179 /**
180 * This is a doubly-linked list.
181 */
182 struct ChannelMessageQueueEntry *prev;
183
184 /**
185 * Number of bytes in @e msg.
186 */
187 size_t len;
188
189 /**
190 * Message to transmit, allocated at the end of this struct.
191 */
192 const void *msg;
193};
194
195
196/**
197 * State we keep for each of our channels.
198 */
199struct ChannelState
200{
201 /**
202 * Information about the channel to use, NULL if no channel
203 * is available right now.
204 */
205 struct GNUNET_CADET_Channel *channel;
206
207 /**
208 * Active query with REGEX to locate exit.
209 */
210 struct GNUNET_REGEX_Search *search;
211
212 /**
213 * Entry for this entry in the channel_heap, NULL as long as this
214 * channel state is not fully bound.
215 */
216 struct GNUNET_CONTAINER_HeapNode *heap_node;
217
218 /**
219 * Head of list of messages scheduled for transmission.
220 */
221 struct ChannelMessageQueueEntry *tmq_head;
222
223 /**
224 * Tail of list of messages scheduled for transmission.
225 */
226 struct ChannelMessageQueueEntry *tmq_tail;
227
228 /**
229 * Destination to which this channel leads. Note that
230 * this struct is NOT in the destination_map (but a
231 * local copy) and that the 'heap_node' should always
232 * be NULL.
233 */
234 struct DestinationEntry destination;
235
236 /**
237 * Address family used for this channel on the local TUN interface.
238 */
239 int af;
240
241 /**
242 * Is this channel new (#GNUNET_NO), or did we exchange messages with the
243 * other side already (#GNUNET_YES)?
244 */
245 int is_established;
246
247 /**
248 * Length of the doubly linked 'tmq_head/tmq_tail' list.
249 */
250 unsigned int tmq_length;
251
252 /**
253 * IPPROTO_TCP or IPPROTO_UDP once bound.
254 */
255 uint8_t protocol;
256
257 /**
258 * IP address of the source on our end, initially uninitialized.
259 */
260 union
261 {
262 /**
263 * Address if af is AF_INET.
264 */
265 struct in_addr v4;
266
267 /**
268 * Address if af is AF_INET6.
269 */
270 struct in6_addr v6;
271 } source_ip;
272
273 /**
274 * Destination IP address used by the source on our end (this is the IP
275 * that we pick freely within the VPN's channel IP range).
276 */
277 union
278 {
279 /**
280 * Address if af is AF_INET.
281 */
282 struct in_addr v4;
283
284 /**
285 * Address if af is AF_INET6.
286 */
287 struct in6_addr v6;
288 } destination_ip;
289
290 /**
291 * Source port used by the sender on our end; 0 for uninitialized.
292 */
293 uint16_t source_port;
294
295 /**
296 * Destination port used by the sender on our end; 0 for uninitialized.
297 */
298 uint16_t destination_port;
299};
300
301
302/**
303 * Return value from #main().
304 */
305static int global_ret;
306
307/**
308 * Configuration we use.
309 */
310static const struct GNUNET_CONFIGURATION_Handle *cfg;
311
312/**
313 * Handle to the cadet service.
314 */
315static struct GNUNET_CADET_Handle *cadet_handle;
316
317/**
318 * Map from IP address to destination information (possibly with a
319 * CADET channel handle for fast setup).
320 */
321static struct GNUNET_CONTAINER_MultiHashMap *destination_map;
322
323/**
324 * Min-Heap sorted by activity time to expire old mappings.
325 */
326static struct GNUNET_CONTAINER_Heap *destination_heap;
327
328/**
329 * Map from source and destination address (IP+port) to connection
330 * information (mostly with the respective CADET channel handle).
331 */
332static struct GNUNET_CONTAINER_MultiHashMap *channel_map;
333
334/**
335 * Min-Heap sorted by activity time to expire old mappings; values are
336 * of type 'struct ChannelState'.
337 */
338static struct GNUNET_CONTAINER_Heap *channel_heap;
339
340/**
341 * Statistics.
342 */
343static struct GNUNET_STATISTICS_Handle *stats;
344
345/**
346 * The handle to the VPN helper process "gnunet-helper-vpn".
347 */
348static struct GNUNET_HELPER_Handle *helper_handle;
349
350/**
351 * Arguments to the vpn helper.
352 */
353static char *vpn_argv[7];
354
355/**
356 * Length of the prefix of the VPN's IPv6 network.
357 */
358static unsigned long long ipv6prefix;
359
360/**
361 * If there are more than this number of address-mappings, old ones
362 * will be removed
363 */
364static unsigned long long max_destination_mappings;
365
366/**
367 * If there are more than this number of open channels, old ones
368 * will be removed
369 */
370static unsigned long long max_channel_mappings;
371
372
373/**
374 * Compute the key under which we would store an entry in the
375 * #destination_map for the given IP address.
376 *
377 * @param af address family (AF_INET or AF_INET6)
378 * @param address IP address, struct in_addr or struct in6_addr
379 * @param key where to store the key
380 */
381static void
382get_destination_key_from_ip (int af,
383 const void *address,
384 struct GNUNET_HashCode *key)
385{
386 switch (af)
387 {
388 case AF_INET:
389 GNUNET_CRYPTO_hash (address, sizeof(struct in_addr), key);
390 break;
391
392 case AF_INET6:
393 GNUNET_CRYPTO_hash (address, sizeof(struct in6_addr), key);
394 break;
395
396 default:
397 GNUNET_assert (0);
398 break;
399 }
400}
401
402
403/**
404 * Compute the key under which we would store an entry in the
405 * channel_map for the given socket address pair.
406 *
407 * @param af address family (AF_INET or AF_INET6)
408 * @param protocol IPPROTO_TCP or IPPROTO_UDP
409 * @param source_ip sender's source IP, struct in_addr or struct in6_addr
410 * @param source_port sender's source port
411 * @param destination_ip sender's destination IP, struct in_addr or struct in6_addr
412 * @param destination_port sender's destination port
413 * @param key where to store the key
414 */
415static void
416get_channel_key_from_ips (int af,
417 uint8_t protocol,
418 const void *source_ip,
419 uint16_t source_port,
420 const void *destination_ip,
421 uint16_t destination_port,
422 struct GNUNET_HashCode *key)
423{
424 char *off;
425
426 memset (key, 0, sizeof(struct GNUNET_HashCode));
427 /* the GNUnet hashmap only uses the first sizeof(unsigned int) of the hash,
428 so we put the ports in there (and hope for few collisions) */
429 off = (char *) key;
430 GNUNET_memcpy (off, &source_port, sizeof(uint16_t));
431 off += sizeof(uint16_t);
432 GNUNET_memcpy (off, &destination_port, sizeof(uint16_t));
433 off += sizeof(uint16_t);
434 switch (af)
435 {
436 case AF_INET:
437 GNUNET_memcpy (off, source_ip, sizeof(struct in_addr));
438 off += sizeof(struct in_addr);
439 GNUNET_memcpy (off, destination_ip, sizeof(struct in_addr));
440 off += sizeof(struct in_addr);
441 break;
442
443 case AF_INET6:
444 GNUNET_memcpy (off, source_ip, sizeof(struct in6_addr));
445 off += sizeof(struct in6_addr);
446 GNUNET_memcpy (off, destination_ip, sizeof(struct in6_addr));
447 off += sizeof(struct in6_addr);
448 break;
449
450 default:
451 GNUNET_assert (0);
452 break;
453 }
454 GNUNET_memcpy (off, &protocol, sizeof(uint8_t));
455 /* off += sizeof (uint8_t); */
456}
457
458
459/**
460 * Notify the client about the result of its request.
461 *
462 * @param client client to notify
463 * @param request_id original request ID to include in response
464 * @param result_af resulting address family
465 * @param addr resulting IP address
466 */
467static void
468send_client_reply (struct GNUNET_SERVICE_Client *client,
469 uint64_t request_id,
470 int result_af,
471 const void *addr)
472{
473 struct GNUNET_MQ_Envelope *env;
474 struct RedirectToIpResponseMessage *res;
475 size_t rlen;
476
477 switch (result_af)
478 {
479 case AF_INET:
480 rlen = sizeof(struct in_addr);
481 break;
482
483 case AF_INET6:
484 rlen = sizeof(struct in6_addr);
485 break;
486
487 case AF_UNSPEC:
488 rlen = 0;
489 break;
490
491 default:
492 GNUNET_assert (0);
493 return;
494 }
495 env = GNUNET_MQ_msg_extra (res, rlen, GNUNET_MESSAGE_TYPE_VPN_CLIENT_USE_IP);
496 res->result_af = htonl (result_af);
497 res->request_id = request_id;
498 GNUNET_memcpy (&res[1], addr, rlen);
499 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client), env);
500}
501
502
503/**
504 * Free resources associated with a channel state.
505 *
506 * @param ts state to free
507 */
508static void
509free_channel_state (struct ChannelState *ts)
510{
511 struct GNUNET_HashCode key;
512 struct ChannelMessageQueueEntry *tnq;
513 struct GNUNET_CADET_Channel *channel;
514
515 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Cleaning up channel state\n");
516 if (NULL != (channel = ts->channel))
517 {
518 ts->channel = NULL;
519 GNUNET_CADET_channel_destroy (channel);
520 return;
521 }
522 GNUNET_STATISTICS_update (stats,
523 gettext_noop ("# Active channels"),
524 -1,
525 GNUNET_NO);
526 while (NULL != (tnq = ts->tmq_head))
527 {
528 GNUNET_CONTAINER_DLL_remove (ts->tmq_head, ts->tmq_tail, tnq);
529 ts->tmq_length--;
530 GNUNET_free (tnq);
531 }
532 GNUNET_assert (0 == ts->tmq_length);
533 GNUNET_assert (NULL == ts->destination.heap_node);
534 if (NULL != ts->search)
535 {
536 GNUNET_REGEX_search_cancel (ts->search);
537 ts->search = NULL;
538 }
539 if (NULL != ts->heap_node)
540 {
541 GNUNET_CONTAINER_heap_remove_node (ts->heap_node);
542 ts->heap_node = NULL;
543 get_channel_key_from_ips (ts->af,
544 ts->protocol,
545 &ts->source_ip,
546 ts->source_port,
547 &ts->destination_ip,
548 ts->destination_port,
549 &key);
550 GNUNET_assert (
551 GNUNET_YES ==
552 GNUNET_CONTAINER_multihashmap_remove (channel_map, &key, ts));
553 }
554 GNUNET_free (ts);
555}
556
557
558/**
559 * Add the given message to the given channel and trigger the
560 * transmission process.
561 *
562 * @param ts channel to queue the message for
563 * @param env message to queue
564 */
565static void
566send_to_channel (struct ChannelState *ts, struct GNUNET_MQ_Envelope *env)
567{
568 struct GNUNET_MQ_Handle *mq;
569
570 GNUNET_assert (NULL != ts->channel);
571 mq = GNUNET_CADET_get_mq (ts->channel);
572 GNUNET_MQ_env_set_options (env,
573 GNUNET_MQ_PRIO_BEST_EFFORT
574 | GNUNET_MQ_PREF_OUT_OF_ORDER);
575 GNUNET_MQ_send (mq, env);
576 if (GNUNET_MQ_get_length (mq) > MAX_MESSAGE_QUEUE_SIZE)
577 {
578 env = GNUNET_MQ_unsent_head (mq);
579 GNUNET_assert (NULL != env);
580 GNUNET_STATISTICS_update (stats,
581 gettext_noop (
582 "# Messages dropped in cadet queue (overflow)"),
583 1,
584 GNUNET_NO);
585 GNUNET_MQ_discard (env);
586 }
587}
588
589
590/**
591 * Output destination of a channel for diagnostics.
592 *
593 * @param de destination to process
594 * @return diagnostic string describing destination
595 */
596static const char *
597print_channel_destination (const struct DestinationEntry *de)
598{
599 static char dest[256];
600
601 if (de->is_service)
602 {
603 GNUNET_snprintf (dest,
604 sizeof(dest),
605 "HS: %s-%s",
606 GNUNET_i2s (&de->details.service_destination.target),
607 GNUNET_h2s (
608 &de->details.service_destination.service_descriptor));
609 }
610 else
611 {
612 inet_ntop (de->details.exit_destination.af,
613 &de->details.exit_destination.ip,
614 dest,
615 sizeof(dest));
616 }
617 return dest;
618}
619
620
621/**
622 * Function called whenever a channel is destroyed. Should clean up
623 * any associated state.
624 *
625 * @param cls our `struct ChannelState`
626 * @param channel connection to the other end (henceforth invalid)
627 */
628static void
629channel_cleaner (void *cls, const struct GNUNET_CADET_Channel *channel)
630{
631 struct ChannelState *ts = cls;
632
633 ts->channel =
634 NULL; /* we must not call GNUNET_CADET_channel_destroy() anymore */
635 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
636 "CADET notified us about death of channel to `%s'\n",
637 print_channel_destination (&ts->destination));
638 free_channel_state (ts);
639}
640
641
642/**
643 * Synthesize a plausible ICMP payload for an ICMP error
644 * response on the given channel.
645 *
646 * @param ts channel information
647 * @param ipp IPv4 header to fill in (ICMP payload)
648 * @param udp "UDP" header to fill in (ICMP payload); might actually
649 * also be the first 8 bytes of the TCP header
650 */
651static void
652make_up_icmpv4_payload (struct ChannelState *ts,
653 struct GNUNET_TUN_IPv4Header *ipp,
654 struct GNUNET_TUN_UdpHeader *udp)
655{
656 GNUNET_TUN_initialize_ipv4_header (ipp,
657 ts->protocol,
658 sizeof(struct GNUNET_TUN_TcpHeader),
659 &ts->source_ip.v4,
660 &ts->destination_ip.v4);
661 udp->source_port = htons (ts->source_port);
662 udp->destination_port = htons (ts->destination_port);
663 udp->len = htons (0);
664 udp->crc = htons (0);
665}
666
667
668/**
669 * Synthesize a plausible ICMP payload for an ICMP error
670 * response on the given channel.
671 *
672 * @param ts channel information
673 * @param ipp IPv6 header to fill in (ICMP payload)
674 * @param udp "UDP" header to fill in (ICMP payload); might actually
675 * also be the first 8 bytes of the TCP header
676 */
677static void
678make_up_icmpv6_payload (struct ChannelState *ts,
679 struct GNUNET_TUN_IPv6Header *ipp,
680 struct GNUNET_TUN_UdpHeader *udp)
681{
682 GNUNET_TUN_initialize_ipv6_header (ipp,
683 ts->protocol,
684 sizeof(struct GNUNET_TUN_TcpHeader),
685 &ts->source_ip.v6,
686 &ts->destination_ip.v6);
687 udp->source_port = htons (ts->source_port);
688 udp->destination_port = htons (ts->destination_port);
689 udp->len = htons (0);
690 udp->crc = htons (0);
691}
692
693
694/**
695 * We got an ICMP packet back from the CADET channel. Check it is OK.
696 *
697 * @param cls our `struct ChannelState *`
698 * @param i2v the actual message
699 * @return #GNUNET_OK to keep the connection open,
700 * #GNUNET_SYSERR to close it (signal serious error)
701 */
702static int
703check_icmp_back (void *cls, const struct GNUNET_EXIT_IcmpToVPNMessage *i2v)
704{
705 struct ChannelState *ts = cls;
706
707 if (NULL == ts->heap_node)
708 {
709 GNUNET_break_op (0);
710 return GNUNET_SYSERR;
711 }
712 if (AF_UNSPEC == ts->af)
713 {
714 GNUNET_break_op (0);
715 return GNUNET_SYSERR;
716 }
717 return GNUNET_OK;
718}
719
720
721/**
722 * We got an ICMP packet back from the CADET channel. Pass it on to the
723 * local virtual interface via the helper.
724 *
725 * @param cls our `struct ChannelState *`
726 * @param i2v the actual message
727 */
728static void
729handle_icmp_back (void *cls, const struct GNUNET_EXIT_IcmpToVPNMessage *i2v)
730{
731 struct ChannelState *ts = cls;
732 size_t mlen;
733
734 GNUNET_STATISTICS_update (stats,
735 gettext_noop ("# ICMP packets received from cadet"),
736 1,
737 GNUNET_NO);
738 mlen =
739 ntohs (i2v->header.size) - sizeof(struct GNUNET_EXIT_IcmpToVPNMessage);
740 {
741 char sbuf[INET6_ADDRSTRLEN];
742 char dbuf[INET6_ADDRSTRLEN];
743
744 GNUNET_log (
745 GNUNET_ERROR_TYPE_DEBUG,
746 "Received ICMP packet from cadet, sending %u bytes from %s -> %s via TUN\n",
747 (unsigned int) mlen,
748 inet_ntop (ts->af, &ts->destination_ip, sbuf, sizeof(sbuf)),
749 inet_ntop (ts->af, &ts->source_ip, dbuf, sizeof(dbuf)));
750 }
751 switch (ts->af)
752 {
753 case AF_INET: {
754 size_t size = sizeof(struct GNUNET_TUN_IPv4Header)
755 + sizeof(struct GNUNET_TUN_IcmpHeader)
756 + sizeof(struct GNUNET_MessageHeader)
757 + sizeof(struct GNUNET_TUN_Layer2PacketHeader) + mlen;
758 {
759 /* reserve some extra space in case we have an ICMP type here where
760 we will need to make up the payload ourselves */
761 char buf[size + sizeof(struct GNUNET_TUN_IPv4Header) + 8] GNUNET_ALIGN;
762 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
763 struct GNUNET_TUN_Layer2PacketHeader *tun =
764 (struct GNUNET_TUN_Layer2PacketHeader *) &msg[1];
765 struct GNUNET_TUN_IPv4Header *ipv4 =
766 (struct GNUNET_TUN_IPv4Header *) &tun[1];
767 struct GNUNET_TUN_IcmpHeader *icmp =
768 (struct GNUNET_TUN_IcmpHeader *) &ipv4[1];
769 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
770 tun->flags = htons (0);
771 tun->proto = htons (ETH_P_IPV4);
772 GNUNET_TUN_initialize_ipv4_header (ipv4,
773 IPPROTO_ICMP,
774 sizeof(struct GNUNET_TUN_IcmpHeader)
775 + mlen,
776 &ts->destination_ip.v4,
777 &ts->source_ip.v4);
778 *icmp = i2v->icmp_header;
779 GNUNET_memcpy (&icmp[1], &i2v[1], mlen);
780 /* For some ICMP types, we need to adjust (make up) the payload here.
781 Also, depending on the AF used on the other side, we have to
782 do ICMP PT (translate ICMP types) */
783 switch (ntohl (i2v->af))
784 {
785 case AF_INET:
786 switch (icmp->type)
787 {
788 case GNUNET_TUN_ICMPTYPE_ECHO_REPLY:
789 case GNUNET_TUN_ICMPTYPE_ECHO_REQUEST:
790 break;
791
792 case GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE:
793 case GNUNET_TUN_ICMPTYPE_SOURCE_QUENCH:
794 case GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED: {
795 struct GNUNET_TUN_IPv4Header *ipp =
796 (struct GNUNET_TUN_IPv4Header *) &icmp[1];
797 struct GNUNET_TUN_UdpHeader *udp =
798 (struct GNUNET_TUN_UdpHeader *) &ipp[1];
799
800 if (mlen != 0)
801 {
802 /* sender did not strip ICMP payload? */
803 GNUNET_break_op (0);
804 return;
805 }
806 size += sizeof(struct GNUNET_TUN_IPv4Header) + 8;
807 GNUNET_assert (8 == sizeof(struct GNUNET_TUN_UdpHeader));
808 make_up_icmpv4_payload (ts, ipp, udp);
809 }
810 break;
811
812 default:
813 GNUNET_break_op (0);
814 GNUNET_STATISTICS_update (
815 stats,
816 gettext_noop ("# ICMPv4 packets dropped (type not allowed)"),
817 1,
818 GNUNET_NO);
819 return;
820 }
821 /* end AF_INET */
822 break;
823
824 case AF_INET6:
825 /* ICMP PT 6-to-4 and possibly making up payloads */
826 switch (icmp->type)
827 {
828 case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE:
829 icmp->type = GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE;
830 {
831 struct GNUNET_TUN_IPv4Header *ipp =
832 (struct GNUNET_TUN_IPv4Header *) &icmp[1];
833 struct GNUNET_TUN_UdpHeader *udp =
834 (struct GNUNET_TUN_UdpHeader *) &ipp[1];
835
836 if (mlen != 0)
837 {
838 /* sender did not strip ICMP payload? */
839 GNUNET_break_op (0);
840 return;
841 }
842 size += sizeof(struct GNUNET_TUN_IPv4Header) + 8;
843 GNUNET_assert (8 == sizeof(struct GNUNET_TUN_UdpHeader));
844 make_up_icmpv4_payload (ts, ipp, udp);
845 }
846 break;
847
848 case GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED:
849 icmp->type = GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED;
850 {
851 struct GNUNET_TUN_IPv4Header *ipp =
852 (struct GNUNET_TUN_IPv4Header *) &icmp[1];
853 struct GNUNET_TUN_UdpHeader *udp =
854 (struct GNUNET_TUN_UdpHeader *) &ipp[1];
855
856 if (mlen != 0)
857 {
858 /* sender did not strip ICMP payload? */
859 GNUNET_break_op (0);
860 return;
861 }
862 size += sizeof(struct GNUNET_TUN_IPv4Header) + 8;
863 GNUNET_assert (8 == sizeof(struct GNUNET_TUN_UdpHeader));
864 make_up_icmpv4_payload (ts, ipp, udp);
865 }
866 break;
867
868 case GNUNET_TUN_ICMPTYPE6_PACKET_TOO_BIG:
869 case GNUNET_TUN_ICMPTYPE6_PARAMETER_PROBLEM:
870 GNUNET_STATISTICS_update (
871 stats,
872 gettext_noop ("# ICMPv6 packets dropped (impossible PT to v4)"),
873 1,
874 GNUNET_NO);
875 return;
876
877 case GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST:
878 icmp->type = GNUNET_TUN_ICMPTYPE_ECHO_REQUEST;
879 break;
880
881 case GNUNET_TUN_ICMPTYPE6_ECHO_REPLY:
882 icmp->type = GNUNET_TUN_ICMPTYPE_ECHO_REPLY;
883 break;
884
885 default:
886 GNUNET_break_op (0);
887 GNUNET_STATISTICS_update (
888 stats,
889 gettext_noop ("# ICMPv6 packets dropped (type not allowed)"),
890 1,
891 GNUNET_NO);
892 return;
893 }
894 /* end AF_INET6 */
895 break;
896
897 default:
898 GNUNET_break_op (0);
899 return;
900 }
901 msg->size = htons (size);
902 GNUNET_TUN_calculate_icmp_checksum (icmp, &i2v[1], mlen);
903 (void) GNUNET_HELPER_send (helper_handle, msg, GNUNET_YES, NULL, NULL);
904 }
905 }
906 break;
907
908 case AF_INET6: {
909 size_t size = sizeof(struct GNUNET_TUN_IPv6Header)
910 + sizeof(struct GNUNET_TUN_IcmpHeader)
911 + sizeof(struct GNUNET_MessageHeader)
912 + sizeof(struct GNUNET_TUN_Layer2PacketHeader) + mlen;
913 {
914 char buf[size + sizeof(struct GNUNET_TUN_IPv6Header) + 8] GNUNET_ALIGN;
915 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
916 struct GNUNET_TUN_Layer2PacketHeader *tun =
917 (struct GNUNET_TUN_Layer2PacketHeader *) &msg[1];
918 struct GNUNET_TUN_IPv6Header *ipv6 =
919 (struct GNUNET_TUN_IPv6Header *) &tun[1];
920 struct GNUNET_TUN_IcmpHeader *icmp =
921 (struct GNUNET_TUN_IcmpHeader *) &ipv6[1];
922 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
923 tun->flags = htons (0);
924 tun->proto = htons (ETH_P_IPV6);
925 GNUNET_TUN_initialize_ipv6_header (ipv6,
926 IPPROTO_ICMPV6,
927 sizeof(struct GNUNET_TUN_IcmpHeader)
928 + mlen,
929 &ts->destination_ip.v6,
930 &ts->source_ip.v6);
931 *icmp = i2v->icmp_header;
932 GNUNET_memcpy (&icmp[1], &i2v[1], mlen);
933
934 /* For some ICMP types, we need to adjust (make up) the payload here.
935 Also, depending on the AF used on the other side, we have to
936 do ICMP PT (translate ICMP types) */
937 switch (ntohl (i2v->af))
938 {
939 case AF_INET:
940 /* ICMP PT 4-to-6 and possibly making up payloads */
941 switch (icmp->type)
942 {
943 case GNUNET_TUN_ICMPTYPE_ECHO_REPLY:
944 icmp->type = GNUNET_TUN_ICMPTYPE6_ECHO_REPLY;
945 break;
946
947 case GNUNET_TUN_ICMPTYPE_ECHO_REQUEST:
948 icmp->type = GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST;
949 break;
950
951 case GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE:
952 icmp->type = GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE;
953 {
954 struct GNUNET_TUN_IPv6Header *ipp =
955 (struct GNUNET_TUN_IPv6Header *) &icmp[1];
956 struct GNUNET_TUN_UdpHeader *udp =
957 (struct GNUNET_TUN_UdpHeader *) &ipp[1];
958
959 if (mlen != 0)
960 {
961 /* sender did not strip ICMP payload? */
962 GNUNET_break_op (0);
963 return;
964 }
965 size += sizeof(struct GNUNET_TUN_IPv6Header) + 8;
966 GNUNET_assert (8 == sizeof(struct GNUNET_TUN_UdpHeader));
967 make_up_icmpv6_payload (ts, ipp, udp);
968 }
969 break;
970
971 case GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED:
972 icmp->type = GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED;
973 {
974 struct GNUNET_TUN_IPv6Header *ipp =
975 (struct GNUNET_TUN_IPv6Header *) &icmp[1];
976 struct GNUNET_TUN_UdpHeader *udp =
977 (struct GNUNET_TUN_UdpHeader *) &ipp[1];
978
979 if (mlen != 0)
980 {
981 /* sender did not strip ICMP payload? */
982 GNUNET_break_op (0);
983 return;
984 }
985 size += sizeof(struct GNUNET_TUN_IPv6Header) + 8;
986 GNUNET_assert (8 == sizeof(struct GNUNET_TUN_UdpHeader));
987 make_up_icmpv6_payload (ts, ipp, udp);
988 }
989 break;
990
991 case GNUNET_TUN_ICMPTYPE_SOURCE_QUENCH:
992 GNUNET_STATISTICS_update (
993 stats,
994 gettext_noop ("# ICMPv4 packets dropped (impossible PT to v6)"),
995 1,
996 GNUNET_NO);
997 return;
998
999 default:
1000 GNUNET_break_op (0);
1001 GNUNET_STATISTICS_update (
1002 stats,
1003 gettext_noop ("# ICMPv4 packets dropped (type not allowed)"),
1004 1,
1005 GNUNET_NO);
1006 return;
1007 }
1008 /* end AF_INET */
1009 break;
1010
1011 case AF_INET6:
1012 switch (icmp->type)
1013 {
1014 case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE:
1015 case GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED:
1016 case GNUNET_TUN_ICMPTYPE6_PACKET_TOO_BIG:
1017 case GNUNET_TUN_ICMPTYPE6_PARAMETER_PROBLEM: {
1018 struct GNUNET_TUN_IPv6Header *ipp =
1019 (struct GNUNET_TUN_IPv6Header *) &icmp[1];
1020 struct GNUNET_TUN_UdpHeader *udp =
1021 (struct GNUNET_TUN_UdpHeader *) &ipp[1];
1022
1023 if (mlen != 0)
1024 {
1025 /* sender did not strip ICMP payload? */
1026 GNUNET_break_op (0);
1027 return;
1028 }
1029 size += sizeof(struct GNUNET_TUN_IPv6Header) + 8;
1030 GNUNET_assert (8 == sizeof(struct GNUNET_TUN_UdpHeader));
1031 make_up_icmpv6_payload (ts, ipp, udp);
1032 }
1033 break;
1034
1035 case GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST:
1036 break;
1037
1038 default:
1039 GNUNET_break_op (0);
1040 GNUNET_STATISTICS_update (
1041 stats,
1042 gettext_noop ("# ICMPv6 packets dropped (type not allowed)"),
1043 1,
1044 GNUNET_NO);
1045 return;
1046 }
1047 /* end AF_INET6 */
1048 break;
1049
1050 default:
1051 GNUNET_break_op (0);
1052 return;
1053 }
1054 msg->size = htons (size);
1055 GNUNET_TUN_calculate_icmp_checksum (icmp, &i2v[1], mlen);
1056 (void) GNUNET_HELPER_send (helper_handle, msg, GNUNET_YES, NULL, NULL);
1057 }
1058 }
1059 break;
1060
1061 default:
1062 GNUNET_assert (0);
1063 }
1064 GNUNET_CONTAINER_heap_update_cost (ts->heap_node,
1065 GNUNET_TIME_absolute_get ().abs_value_us);
1066 GNUNET_CADET_receive_done (ts->channel);
1067}
1068
1069
1070/**
1071 * We got a UDP packet back from the CADET channel. Check that it is OK.
1072 *
1073 * @param cls our `struct ChannelState *`
1074 * @param reply the actual message
1075 * @return #GNUNET_OK to keep the connection open,
1076 * #GNUNET_SYSERR to close it (signal serious error)
1077 */
1078static int
1079check_udp_back (void *cls, const struct GNUNET_EXIT_UdpReplyMessage *reply)
1080{
1081 struct ChannelState *ts = cls;
1082
1083 if (NULL == ts->heap_node)
1084 {
1085 GNUNET_break_op (0);
1086 return GNUNET_SYSERR;
1087 }
1088 if (AF_UNSPEC == ts->af)
1089 {
1090 GNUNET_break_op (0);
1091 return GNUNET_SYSERR;
1092 }
1093 return GNUNET_OK;
1094}
1095
1096
1097/**
1098 * We got a UDP packet back from the CADET channel. Pass it on to the
1099 * local virtual interface via the helper.
1100 *
1101 * @param cls our `struct ChannelState *`
1102 * @param reply the actual message
1103 */
1104static void
1105handle_udp_back (void *cls, const struct GNUNET_EXIT_UdpReplyMessage *reply)
1106{
1107 struct ChannelState *ts = cls;
1108 size_t mlen;
1109
1110 GNUNET_STATISTICS_update (stats,
1111 gettext_noop ("# UDP packets received from cadet"),
1112 1,
1113 GNUNET_NO);
1114 mlen =
1115 ntohs (reply->header.size) - sizeof(struct GNUNET_EXIT_UdpReplyMessage);
1116 {
1117 char sbuf[INET6_ADDRSTRLEN];
1118 char dbuf[INET6_ADDRSTRLEN];
1119
1120 GNUNET_log (
1121 GNUNET_ERROR_TYPE_DEBUG,
1122 "Received UDP reply from cadet, sending %u bytes from [%s]:%u -> [%s]:%u via TUN\n",
1123 (unsigned int) mlen,
1124 inet_ntop (ts->af, &ts->destination_ip, sbuf, sizeof(sbuf)),
1125 ts->destination_port,
1126 inet_ntop (ts->af, &ts->source_ip, dbuf, sizeof(dbuf)),
1127 ts->source_port);
1128 }
1129 switch (ts->af)
1130 {
1131 case AF_INET: {
1132 size_t size = sizeof(struct GNUNET_TUN_IPv4Header)
1133 + sizeof(struct GNUNET_TUN_UdpHeader)
1134 + sizeof(struct GNUNET_MessageHeader)
1135 + sizeof(struct GNUNET_TUN_Layer2PacketHeader) + mlen;
1136 {
1137 char buf[size] GNUNET_ALIGN;
1138 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
1139 struct GNUNET_TUN_Layer2PacketHeader *tun =
1140 (struct GNUNET_TUN_Layer2PacketHeader *) &msg[1];
1141 struct GNUNET_TUN_IPv4Header *ipv4 =
1142 (struct GNUNET_TUN_IPv4Header *) &tun[1];
1143 struct GNUNET_TUN_UdpHeader *udp =
1144 (struct GNUNET_TUN_UdpHeader *) &ipv4[1];
1145 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
1146 msg->size = htons (size);
1147 tun->flags = htons (0);
1148 tun->proto = htons (ETH_P_IPV4);
1149 GNUNET_TUN_initialize_ipv4_header (ipv4,
1150 IPPROTO_UDP,
1151 sizeof(struct GNUNET_TUN_UdpHeader)
1152 + mlen,
1153 &ts->destination_ip.v4,
1154 &ts->source_ip.v4);
1155 if (0 == ntohs (reply->source_port))
1156 udp->source_port = htons (ts->destination_port);
1157 else
1158 udp->source_port = reply->source_port;
1159 if (0 == ntohs (reply->destination_port))
1160 udp->destination_port = htons (ts->source_port);
1161 else
1162 udp->destination_port = reply->destination_port;
1163 udp->len = htons (mlen + sizeof(struct GNUNET_TUN_UdpHeader));
1164 GNUNET_TUN_calculate_udp4_checksum (ipv4, udp, &reply[1], mlen);
1165 GNUNET_memcpy (&udp[1], &reply[1], mlen);
1166 (void) GNUNET_HELPER_send (helper_handle, msg, GNUNET_YES, NULL, NULL);
1167 }
1168 }
1169 break;
1170
1171 case AF_INET6: {
1172 size_t size = sizeof(struct GNUNET_TUN_IPv6Header)
1173 + sizeof(struct GNUNET_TUN_UdpHeader)
1174 + sizeof(struct GNUNET_MessageHeader)
1175 + sizeof(struct GNUNET_TUN_Layer2PacketHeader) + mlen;
1176 {
1177 char buf[size] GNUNET_ALIGN;
1178 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
1179 struct GNUNET_TUN_Layer2PacketHeader *tun =
1180 (struct GNUNET_TUN_Layer2PacketHeader *) &msg[1];
1181 struct GNUNET_TUN_IPv6Header *ipv6 =
1182 (struct GNUNET_TUN_IPv6Header *) &tun[1];
1183 struct GNUNET_TUN_UdpHeader *udp =
1184 (struct GNUNET_TUN_UdpHeader *) &ipv6[1];
1185 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
1186 msg->size = htons (size);
1187 tun->flags = htons (0);
1188 tun->proto = htons (ETH_P_IPV6);
1189 GNUNET_TUN_initialize_ipv6_header (ipv6,
1190 IPPROTO_UDP,
1191 sizeof(struct GNUNET_TUN_UdpHeader)
1192 + mlen,
1193 &ts->destination_ip.v6,
1194 &ts->source_ip.v6);
1195 if (0 == ntohs (reply->source_port))
1196 udp->source_port = htons (ts->destination_port);
1197 else
1198 udp->source_port = reply->source_port;
1199 if (0 == ntohs (reply->destination_port))
1200 udp->destination_port = htons (ts->source_port);
1201 else
1202 udp->destination_port = reply->destination_port;
1203 udp->len = htons (mlen + sizeof(struct GNUNET_TUN_UdpHeader));
1204 GNUNET_TUN_calculate_udp6_checksum (ipv6, udp, &reply[1], mlen);
1205 GNUNET_memcpy (&udp[1], &reply[1], mlen);
1206 (void) GNUNET_HELPER_send (helper_handle, msg, GNUNET_YES, NULL, NULL);
1207 }
1208 }
1209 break;
1210
1211 default:
1212 GNUNET_assert (0);
1213 }
1214 GNUNET_CONTAINER_heap_update_cost (ts->heap_node,
1215 GNUNET_TIME_absolute_get ().abs_value_us);
1216 GNUNET_CADET_receive_done (ts->channel);
1217}
1218
1219
1220/**
1221 * We got a TCP packet back from the CADET channel. Check it is OK.
1222 *
1223 * @param cls our `struct ChannelState *`
1224 * @param data the actual message
1225 * @return #GNUNET_OK to keep the connection open,
1226 * #GNUNET_SYSERR to close it (signal serious error)
1227 */
1228static int
1229check_tcp_back (void *cls, const struct GNUNET_EXIT_TcpDataMessage *data)
1230{
1231 struct ChannelState *ts = cls;
1232
1233 if (NULL == ts->heap_node)
1234 {
1235 GNUNET_break_op (0);
1236 return GNUNET_SYSERR;
1237 }
1238 if (data->tcp_header.off * 4 < sizeof(struct GNUNET_TUN_TcpHeader))
1239 {
1240 GNUNET_break_op (0);
1241 return GNUNET_SYSERR;
1242 }
1243 return GNUNET_OK;
1244}
1245
1246
1247/**
1248 * We got a TCP packet back from the CADET channel. Pass it on to the
1249 * local virtual interface via the helper.
1250 *
1251 * @param cls our `struct ChannelState *`
1252 * @param data the actual message
1253 */
1254static void
1255handle_tcp_back (void *cls, const struct GNUNET_EXIT_TcpDataMessage *data)
1256{
1257 struct ChannelState *ts = cls;
1258 size_t mlen;
1259
1260 GNUNET_STATISTICS_update (stats,
1261 gettext_noop ("# TCP packets received from cadet"),
1262 1,
1263 GNUNET_NO);
1264 mlen = ntohs (data->header.size) - sizeof(struct GNUNET_EXIT_TcpDataMessage);
1265 {
1266 char sbuf[INET6_ADDRSTRLEN];
1267 char dbuf[INET6_ADDRSTRLEN];
1268
1269 GNUNET_log (
1270 GNUNET_ERROR_TYPE_DEBUG,
1271 "Received TCP reply from cadet, sending %u bytes from [%s]:%u -> [%s]:%u via TUN\n",
1272 (unsigned int) mlen,
1273 inet_ntop (ts->af, &ts->destination_ip, sbuf, sizeof(sbuf)),
1274 ts->destination_port,
1275 inet_ntop (ts->af, &ts->source_ip, dbuf, sizeof(dbuf)),
1276 ts->source_port);
1277 }
1278 switch (ts->af)
1279 {
1280 case AF_INET: {
1281 size_t size = sizeof(struct GNUNET_TUN_IPv4Header)
1282 + sizeof(struct GNUNET_TUN_TcpHeader)
1283 + sizeof(struct GNUNET_MessageHeader)
1284 + sizeof(struct GNUNET_TUN_Layer2PacketHeader) + mlen;
1285 {
1286 char buf[size] GNUNET_ALIGN;
1287 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
1288 struct GNUNET_TUN_Layer2PacketHeader *tun =
1289 (struct GNUNET_TUN_Layer2PacketHeader *) &msg[1];
1290 struct GNUNET_TUN_IPv4Header *ipv4 =
1291 (struct GNUNET_TUN_IPv4Header *) &tun[1];
1292 struct GNUNET_TUN_TcpHeader *tcp =
1293 (struct GNUNET_TUN_TcpHeader *) &ipv4[1];
1294 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
1295 msg->size = htons (size);
1296 tun->flags = htons (0);
1297 tun->proto = htons (ETH_P_IPV4);
1298 GNUNET_TUN_initialize_ipv4_header (ipv4,
1299 IPPROTO_TCP,
1300 sizeof(struct GNUNET_TUN_TcpHeader)
1301 + mlen,
1302 &ts->destination_ip.v4,
1303 &ts->source_ip.v4);
1304 *tcp = data->tcp_header;
1305 tcp->source_port = htons (ts->destination_port);
1306 tcp->destination_port = htons (ts->source_port);
1307 GNUNET_TUN_calculate_tcp4_checksum (ipv4, tcp, &data[1], mlen);
1308 GNUNET_memcpy (&tcp[1], &data[1], mlen);
1309 (void) GNUNET_HELPER_send (helper_handle, msg, GNUNET_YES, NULL, NULL);
1310 }
1311 }
1312 break;
1313
1314 case AF_INET6: {
1315 size_t size = sizeof(struct GNUNET_TUN_IPv6Header)
1316 + sizeof(struct GNUNET_TUN_TcpHeader)
1317 + sizeof(struct GNUNET_MessageHeader)
1318 + sizeof(struct GNUNET_TUN_Layer2PacketHeader) + mlen;
1319 {
1320 char buf[size] GNUNET_ALIGN;
1321 struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
1322 struct GNUNET_TUN_Layer2PacketHeader *tun =
1323 (struct GNUNET_TUN_Layer2PacketHeader *) &msg[1];
1324 struct GNUNET_TUN_IPv6Header *ipv6 =
1325 (struct GNUNET_TUN_IPv6Header *) &tun[1];
1326 struct GNUNET_TUN_TcpHeader *tcp =
1327 (struct GNUNET_TUN_TcpHeader *) &ipv6[1];
1328 msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
1329 msg->size = htons (size);
1330 tun->flags = htons (0);
1331 tun->proto = htons (ETH_P_IPV6);
1332 GNUNET_TUN_initialize_ipv6_header (ipv6,
1333 IPPROTO_TCP,
1334 sizeof(struct GNUNET_TUN_TcpHeader)
1335 + mlen,
1336 &ts->destination_ip.v6,
1337 &ts->source_ip.v6);
1338 *tcp = data->tcp_header;
1339 tcp->source_port = htons (ts->destination_port);
1340 tcp->destination_port = htons (ts->source_port);
1341 GNUNET_TUN_calculate_tcp6_checksum (ipv6, tcp, &data[1], mlen);
1342 GNUNET_memcpy (&tcp[1], &data[1], mlen);
1343 (void) GNUNET_HELPER_send (helper_handle, msg, GNUNET_YES, NULL, NULL);
1344 }
1345 }
1346 break;
1347 }
1348 GNUNET_CONTAINER_heap_update_cost (ts->heap_node,
1349 GNUNET_TIME_absolute_get ().abs_value_us);
1350 GNUNET_CADET_receive_done (ts->channel);
1351}
1352
1353
1354/**
1355 * Create a channel for @a ts to @a target at @a port
1356 *
1357 * @param ts channel state to create the channel for
1358 * @param target peer to connect to
1359 * @param port destination port
1360 * @return the channel handle
1361 */
1362static struct GNUNET_CADET_Channel *
1363create_channel (struct ChannelState *ts,
1364 const struct GNUNET_PeerIdentity *target,
1365 const struct GNUNET_HashCode *port)
1366{
1367 struct GNUNET_MQ_MessageHandler cadet_handlers[] =
1368 { GNUNET_MQ_hd_var_size (udp_back,
1369 GNUNET_MESSAGE_TYPE_VPN_UDP_REPLY,
1370 struct GNUNET_EXIT_UdpReplyMessage,
1371 ts),
1372 GNUNET_MQ_hd_var_size (tcp_back,
1373 GNUNET_MESSAGE_TYPE_VPN_TCP_DATA_TO_VPN,
1374 struct GNUNET_EXIT_TcpDataMessage,
1375 ts),
1376 GNUNET_MQ_hd_var_size (icmp_back,
1377 GNUNET_MESSAGE_TYPE_VPN_ICMP_TO_VPN,
1378 struct GNUNET_EXIT_IcmpToVPNMessage,
1379 ts),
1380 GNUNET_MQ_handler_end () };
1381
1382 return GNUNET_CADET_channel_create (cadet_handle,
1383 ts,
1384 target,
1385 port,
1386 NULL,
1387 &channel_cleaner,
1388 cadet_handlers);
1389}
1390
1391
1392/**
1393 * Regex has found a potential exit peer for us; consider using it.
1394 *
1395 * @param cls the `struct ChannelState`
1396 * @param id Peer providing a regex that matches the string.
1397 * @param get_path Path of the get request.
1398 * @param get_path_length Length of @a get_path.
1399 * @param put_path Path of the put request.
1400 * @param put_path_length Length of the @a put_path.
1401 */
1402static void
1403handle_regex_result (void *cls,
1404 const struct GNUNET_PeerIdentity *id,
1405 const struct GNUNET_PeerIdentity *get_path,
1406 unsigned int get_path_length,
1407 const struct GNUNET_PeerIdentity *put_path,
1408 unsigned int put_path_length)
1409{
1410 struct ChannelState *ts = cls;
1411 struct GNUNET_HashCode port;
1412
1413 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1414 "Exit %s found for destination %s!\n",
1415 GNUNET_i2s (id),
1416 print_channel_destination (&ts->destination));
1417 GNUNET_REGEX_search_cancel (ts->search);
1418 ts->search = NULL;
1419 switch (ts->af)
1420 {
1421 case AF_INET:
1422 /* these must match the strings used in gnunet-daemon-exit */
1423 GNUNET_CRYPTO_hash (GNUNET_APPLICATION_PORT_IPV4_GATEWAY,
1424 strlen (GNUNET_APPLICATION_PORT_IPV4_GATEWAY),
1425 &port);
1426 break;
1427
1428 case AF_INET6:
1429 /* these must match the strings used in gnunet-daemon-exit */
1430 GNUNET_CRYPTO_hash (GNUNET_APPLICATION_PORT_IPV6_GATEWAY,
1431 strlen (GNUNET_APPLICATION_PORT_IPV6_GATEWAY),
1432 &port);
1433 break;
1434
1435 default:
1436 GNUNET_break (0);
1437 return;
1438 }
1439 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1440 "Creating tunnel to %s for destination %s!\n",
1441 GNUNET_i2s (id),
1442 print_channel_destination (&ts->destination));
1443 ts->channel = create_channel (ts, id, &port);
1444}
1445
1446
1447/**
1448 * Initialize the given destination entry's cadet channel.
1449 *
1450 * @param dt destination channel for which we need to setup a channel
1451 * @param client_af address family of the address returned to the client
1452 * @return channel state of the channel that was created
1453 */
1454static struct ChannelState *
1455create_channel_to_destination (struct DestinationChannel *dt, int client_af)
1456{
1457 struct ChannelState *ts;
1458
1459 GNUNET_STATISTICS_update (stats,
1460 gettext_noop ("# Cadet channels created"),
1461 1,
1462 GNUNET_NO);
1463 ts = GNUNET_new (struct ChannelState);
1464 ts->af = client_af;
1465 ts->destination = *dt->destination;
1466 ts->destination.heap_node = NULL; /* copy is NOT in destination heap */
1467 ts->destination_port = dt->destination_port;
1468 if (dt->destination->is_service)
1469 {
1470 struct GNUNET_HashCode cadet_port;
1471
1472 GNUNET_TUN_compute_service_cadet_port (&ts->destination.details
1473 .service_destination
1474 .service_descriptor,
1475 ts->destination_port,
1476 &cadet_port);
1477 ts->channel =
1478 create_channel (ts,
1479 &dt->destination->details.service_destination.target,
1480 &cadet_port);
1481
1482 if (NULL == ts->channel)
1483 {
1484 GNUNET_break (0);
1485 GNUNET_free (ts);
1486 return NULL;
1487 }
1488 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1489 "Creating channel to peer %s offering service %s on port %u\n",
1490 GNUNET_i2s (
1491 &dt->destination->details.service_destination.target),
1492 GNUNET_h2s (&ts->destination.details.service_destination
1493 .service_descriptor),
1494 (unsigned int) ts->destination_port);
1495 }
1496 else
1497 {
1498 char *policy;
1499
1500 switch (dt->destination->details.exit_destination.af)
1501 {
1502 case AF_INET: {
1503 char address[GNUNET_TUN_IPV4_REGEXLEN];
1504
1505 GNUNET_TUN_ipv4toregexsearch (&dt->destination->details.exit_destination
1506 .ip.v4,
1507 dt->destination_port,
1508 address);
1509 GNUNET_asprintf (&policy,
1510 "%s%s",
1511 GNUNET_APPLICATION_TYPE_EXIT_REGEX_PREFIX,
1512 address);
1513 break;
1514 }
1515
1516 case AF_INET6: {
1517 char address[GNUNET_TUN_IPV6_REGEXLEN];
1518
1519 GNUNET_TUN_ipv6toregexsearch (&dt->destination->details.exit_destination
1520 .ip.v6,
1521 dt->destination_port,
1522 address);
1523 GNUNET_asprintf (&policy,
1524 "%s%s",
1525 GNUNET_APPLICATION_TYPE_EXIT_REGEX_PREFIX,
1526 address);
1527 break;
1528 }
1529
1530 default:
1531 GNUNET_assert (0);
1532 break;
1533 }
1534
1535 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1536 "Requesting connect by string: %s\n",
1537 policy);
1538 ts->search = GNUNET_REGEX_search (cfg, policy, &handle_regex_result, ts);
1539 GNUNET_free (policy);
1540 }
1541 return ts;
1542}
1543
1544
1545/**
1546 * We have too many active channels. Clean up the oldest channel.
1547 *
1548 * @param except channel that must NOT be cleaned up, even if it is the oldest
1549 */
1550static void
1551expire_channel (struct ChannelState *except)
1552{
1553 struct ChannelState *ts;
1554
1555 ts = GNUNET_CONTAINER_heap_peek (channel_heap);
1556 GNUNET_assert (NULL != ts);
1557 if (except == ts)
1558 return; /* can't do this */
1559 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1560 "Tearing down expired channel to %s\n",
1561 print_channel_destination (&except->destination));
1562 free_channel_state (ts);
1563}
1564
1565
1566/**
1567 * Route a packet via cadet to the given destination.
1568 *
1569 * @param destination description of the destination
1570 * @param af address family on this end (AF_INET or AF_INET6)
1571 * @param protocol IPPROTO_TCP or IPPROTO_UDP or IPPROTO_ICMP or IPPROTO_ICMPV6
1572 * @param source_ip source IP used by the sender (struct in_addr or struct in6_addr)
1573 * @param destination_ip destination IP used by the sender (struct in_addr or struct in6_addr)
1574 * @param payload payload of the packet after the IP header
1575 * @param payload_length number of bytes in @a payload
1576 */
1577static void
1578route_packet (struct DestinationEntry *destination,
1579 int af,
1580 uint8_t protocol,
1581 const void *source_ip,
1582 const void *destination_ip,
1583 const void *payload,
1584 size_t payload_length)
1585{
1586 struct GNUNET_HashCode key;
1587 struct ChannelState *ts;
1588 size_t alen;
1589 size_t mlen;
1590 struct GNUNET_MQ_Envelope *env;
1591 const struct GNUNET_TUN_UdpHeader *udp;
1592 const struct GNUNET_TUN_TcpHeader *tcp;
1593 const struct GNUNET_TUN_IcmpHeader *icmp;
1594 struct DestinationChannel *dt;
1595 uint16_t source_port;
1596 uint16_t destination_port;
1597
1598 switch (protocol)
1599 {
1600 case IPPROTO_UDP: {
1601 if (payload_length < sizeof(struct GNUNET_TUN_UdpHeader))
1602 {
1603 /* blame kernel? */
1604 GNUNET_break (0);
1605 return;
1606 }
1607 tcp = NULL; /* make compiler happy */
1608 icmp = NULL; /* make compiler happy */
1609 udp = payload;
1610 if (udp->len < sizeof(struct GNUNET_TUN_UdpHeader))
1611 {
1612 GNUNET_break_op (0);
1613 return;
1614 }
1615 source_port = ntohs (udp->source_port);
1616 destination_port = ntohs (udp->destination_port);
1617 get_channel_key_from_ips (af,
1618 IPPROTO_UDP,
1619 source_ip,
1620 source_port,
1621 destination_ip,
1622 destination_port,
1623 &key);
1624 }
1625 break;
1626
1627 case IPPROTO_TCP: {
1628 if (payload_length < sizeof(struct GNUNET_TUN_TcpHeader))
1629 {
1630 /* blame kernel? */
1631 GNUNET_break (0);
1632 return;
1633 }
1634 udp = NULL; /* make compiler happy */
1635 icmp = NULL; /* make compiler happy */
1636 tcp = payload;
1637 if (tcp->off * 4 < sizeof(struct GNUNET_TUN_TcpHeader))
1638 {
1639 GNUNET_break_op (0);
1640 return;
1641 }
1642 source_port = ntohs (tcp->source_port);
1643 destination_port = ntohs (tcp->destination_port);
1644 get_channel_key_from_ips (af,
1645 IPPROTO_TCP,
1646 source_ip,
1647 source_port,
1648 destination_ip,
1649 destination_port,
1650 &key);
1651 }
1652 break;
1653
1654 case IPPROTO_ICMP:
1655 case IPPROTO_ICMPV6: {
1656 if ((AF_INET == af) ^ (protocol == IPPROTO_ICMP))
1657 {
1658 GNUNET_break (0);
1659 return;
1660 }
1661 if (payload_length < sizeof(struct GNUNET_TUN_IcmpHeader))
1662 {
1663 /* blame kernel? */
1664 GNUNET_break (0);
1665 return;
1666 }
1667 tcp = NULL; /* make compiler happy */
1668 udp = NULL; /* make compiler happy */
1669 icmp = payload;
1670 source_port = 0;
1671 destination_port = 0;
1672 get_channel_key_from_ips (af,
1673 protocol,
1674 source_ip,
1675 0,
1676 destination_ip,
1677 0,
1678 &key);
1679 }
1680 break;
1681
1682 default:
1683 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1684 _ ("Protocol %u not supported, dropping\n"),
1685 (unsigned int) protocol);
1686 return;
1687 }
1688 alen = 0;
1689 if (! destination->is_service)
1690 {
1691 switch (destination->details.exit_destination.af)
1692 {
1693 case AF_INET:
1694 alen = sizeof(struct in_addr);
1695 break;
1696
1697 case AF_INET6:
1698 alen = sizeof(struct in6_addr);
1699 break;
1700
1701 default:
1702 GNUNET_assert (0);
1703 }
1704
1705 {
1706 char sbuf[INET6_ADDRSTRLEN];
1707 char dbuf[INET6_ADDRSTRLEN];
1708 char xbuf[INET6_ADDRSTRLEN];
1709
1710 GNUNET_log (
1711 GNUNET_ERROR_TYPE_DEBUG,
1712 "Routing %s packet from [%s]:%u -> [%s]:%u to destination [%s]:%u\n",
1713 (protocol == IPPROTO_TCP) ? "TCP" : "UDP",
1714 inet_ntop (af, source_ip, sbuf, sizeof(sbuf)),
1715 source_port,
1716 inet_ntop (af, destination_ip, dbuf, sizeof(dbuf)),
1717 destination_port,
1718 inet_ntop (destination->details.exit_destination.af,
1719 &destination->details.exit_destination.ip,
1720 xbuf,
1721 sizeof(xbuf)),
1722 destination_port);
1723 }
1724 for (dt = destination->dt_head; NULL != dt; dt = dt->next)
1725 if (dt->destination_port == destination_port)
1726 break;
1727 }
1728 else
1729 {
1730 {
1731 char sbuf[INET6_ADDRSTRLEN];
1732 char dbuf[INET6_ADDRSTRLEN];
1733
1734 GNUNET_log (
1735 GNUNET_ERROR_TYPE_DEBUG,
1736 "Routing %s packet from [%s]:%u -> [%s]:%u to service %s at peer %s\n",
1737 (protocol == IPPROTO_TCP) ? "TCP" : "UDP",
1738 inet_ntop (af, source_ip, sbuf, sizeof(sbuf)),
1739 source_port,
1740 inet_ntop (af, destination_ip, dbuf, sizeof(dbuf)),
1741 destination_port,
1742 GNUNET_h2s (
1743 &destination->details.service_destination.service_descriptor),
1744 GNUNET_i2s (&destination->details.service_destination.target));
1745 }
1746 for (dt = destination->dt_head; NULL != dt; dt = dt->next)
1747 if (dt->destination_port == destination_port)
1748 break;
1749 }
1750 if (NULL == dt)
1751 {
1752 dt = GNUNET_new (struct DestinationChannel);
1753 dt->destination = destination;
1754 GNUNET_CONTAINER_DLL_insert (destination->dt_head,
1755 destination->dt_tail,
1756 dt);
1757 dt->destination_port = destination_port;
1758 }
1759
1760 /* see if we have an existing channel for this destination */
1761 ts = GNUNET_CONTAINER_multihashmap_get (channel_map, &key);
1762 if (NULL == ts)
1763 {
1764 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1765 "Creating new channel for key %s\n",
1766 GNUNET_h2s (&key));
1767 /* need to either use the existing channel from the destination (if still
1768 available) or create a fresh one */
1769 ts = create_channel_to_destination (dt, af);
1770 if (NULL == ts)
1771 return;
1772 /* now bind existing "unbound" channel to our IP/port tuple */
1773 ts->protocol = protocol;
1774 ts->af = af;
1775 if (AF_INET == af)
1776 {
1777 ts->source_ip.v4 = *(const struct in_addr *) source_ip;
1778 ts->destination_ip.v4 = *(const struct in_addr *) destination_ip;
1779 }
1780 else
1781 {
1782 ts->source_ip.v6 = *(const struct in6_addr *) source_ip;
1783 ts->destination_ip.v6 = *(const struct in6_addr *) destination_ip;
1784 }
1785 ts->source_port = source_port;
1786 ts->destination_port = destination_port;
1787 ts->heap_node =
1788 GNUNET_CONTAINER_heap_insert (channel_heap,
1789 ts,
1790 GNUNET_TIME_absolute_get ().abs_value_us);
1791 GNUNET_assert (GNUNET_YES ==
1792 GNUNET_CONTAINER_multihashmap_put (
1793 channel_map,
1794 &key,
1795 ts,
1796 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1797 GNUNET_STATISTICS_update (stats,
1798 gettext_noop ("# Active channels"),
1799 1,
1800 GNUNET_NO);
1801 while (GNUNET_CONTAINER_multihashmap_size (channel_map) >
1802 max_channel_mappings)
1803 expire_channel (ts);
1804 }
1805 else
1806 {
1807 GNUNET_CONTAINER_heap_update_cost (ts->heap_node,
1808 GNUNET_TIME_absolute_get ()
1809 .abs_value_us);
1810 }
1811 if (NULL == ts->channel)
1812 {
1813 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1814 "Packet dropped, channel to %s not yet ready (%s)\n",
1815 print_channel_destination (&ts->destination),
1816 (NULL == ts->search) ? "EXIT search failed"
1817 : "EXIT search active");
1818 GNUNET_STATISTICS_update (stats,
1819 gettext_noop (
1820 "# Packets dropped (channel not yet online)"),
1821 1,
1822 GNUNET_NO);
1823 return;
1824 }
1825
1826 /* send via channel */
1827 switch (protocol)
1828 {
1829 case IPPROTO_UDP:
1830 if (destination->is_service)
1831 {
1832 struct GNUNET_EXIT_UdpServiceMessage *usm;
1833
1834 mlen = sizeof(struct GNUNET_EXIT_UdpServiceMessage) + payload_length
1835 - sizeof(struct GNUNET_TUN_UdpHeader);
1836 if (mlen >= GNUNET_MAX_MESSAGE_SIZE)
1837 {
1838 GNUNET_break (0);
1839 return;
1840 }
1841 env = GNUNET_MQ_msg_extra (usm,
1842 payload_length
1843 - sizeof(struct GNUNET_TUN_UdpHeader),
1844 GNUNET_MESSAGE_TYPE_VPN_UDP_TO_SERVICE);
1845 /* if the source port is below 32000, we assume it has a special
1846 meaning; if not, we pick a random port (this is a heuristic) */
1847 usm->source_port =
1848 (ntohs (udp->source_port) < 32000) ? udp->source_port : 0;
1849 usm->destination_port = udp->destination_port;
1850 GNUNET_memcpy (&usm[1],
1851 &udp[1],
1852 payload_length - sizeof(struct GNUNET_TUN_UdpHeader));
1853 }
1854 else
1855 {
1856 struct GNUNET_EXIT_UdpInternetMessage *uim;
1857 struct in_addr *ip4dst;
1858 struct in6_addr *ip6dst;
1859 void *payload;
1860
1861 mlen = sizeof(struct GNUNET_EXIT_UdpInternetMessage) + alen
1862 + payload_length - sizeof(struct GNUNET_TUN_UdpHeader);
1863 if (mlen >= GNUNET_MAX_MESSAGE_SIZE)
1864 {
1865 GNUNET_break (0);
1866 return;
1867 }
1868 env = GNUNET_MQ_msg_extra (uim,
1869 payload_length + alen
1870 - sizeof(struct GNUNET_TUN_UdpHeader),
1871 GNUNET_MESSAGE_TYPE_VPN_UDP_TO_INTERNET);
1872 uim->af = htonl (destination->details.exit_destination.af);
1873 uim->source_port =
1874 (ntohs (udp->source_port) < 32000) ? udp->source_port : 0;
1875 uim->destination_port = udp->destination_port;
1876 switch (destination->details.exit_destination.af)
1877 {
1878 case AF_INET:
1879 ip4dst = (struct in_addr *) &uim[1];
1880 *ip4dst = destination->details.exit_destination.ip.v4;
1881 payload = &ip4dst[1];
1882 break;
1883
1884 case AF_INET6:
1885 ip6dst = (struct in6_addr *) &uim[1];
1886 *ip6dst = destination->details.exit_destination.ip.v6;
1887 payload = &ip6dst[1];
1888 break;
1889
1890 default:
1891 GNUNET_assert (0);
1892 }
1893 GNUNET_memcpy (payload,
1894 &udp[1],
1895 payload_length - sizeof(struct GNUNET_TUN_UdpHeader));
1896 }
1897 break;
1898
1899 case IPPROTO_TCP:
1900 if (GNUNET_NO == ts->is_established)
1901 {
1902 if (destination->is_service)
1903 {
1904 struct GNUNET_EXIT_TcpServiceStartMessage *tsm;
1905
1906 mlen = sizeof(struct GNUNET_EXIT_TcpServiceStartMessage)
1907 + payload_length - sizeof(struct GNUNET_TUN_TcpHeader);
1908 if (mlen >= GNUNET_MAX_MESSAGE_SIZE)
1909 {
1910 GNUNET_break (0);
1911 return;
1912 }
1913 env =
1914 GNUNET_MQ_msg_extra (tsm,
1915 payload_length
1916 - sizeof(struct GNUNET_TUN_TcpHeader),
1917 GNUNET_MESSAGE_TYPE_VPN_TCP_TO_SERVICE_START);
1918 tsm->reserved = htonl (0);
1919 tsm->tcp_header = *tcp;
1920 GNUNET_memcpy (&tsm[1],
1921 &tcp[1],
1922 payload_length - sizeof(struct GNUNET_TUN_TcpHeader));
1923 }
1924 else
1925 {
1926 struct GNUNET_EXIT_TcpInternetStartMessage *tim;
1927 struct in_addr *ip4dst;
1928 struct in6_addr *ip6dst;
1929 void *payload;
1930
1931 mlen = sizeof(struct GNUNET_EXIT_TcpInternetStartMessage) + alen
1932 + payload_length - sizeof(struct GNUNET_TUN_TcpHeader);
1933 if (mlen >= GNUNET_MAX_MESSAGE_SIZE)
1934 {
1935 GNUNET_break (0);
1936 return;
1937 }
1938 env =
1939 GNUNET_MQ_msg_extra (tim,
1940 payload_length + alen
1941 - sizeof(struct GNUNET_TUN_TcpHeader),
1942 GNUNET_MESSAGE_TYPE_VPN_TCP_TO_INTERNET_START);
1943 tim->af = htonl (destination->details.exit_destination.af);
1944 tim->tcp_header = *tcp;
1945 switch (destination->details.exit_destination.af)
1946 {
1947 case AF_INET:
1948 ip4dst = (struct in_addr *) &tim[1];
1949 *ip4dst = destination->details.exit_destination.ip.v4;
1950 payload = &ip4dst[1];
1951 break;
1952
1953 case AF_INET6:
1954 ip6dst = (struct in6_addr *) &tim[1];
1955 *ip6dst = destination->details.exit_destination.ip.v6;
1956 payload = &ip6dst[1];
1957 break;
1958
1959 default:
1960 GNUNET_assert (0);
1961 }
1962 GNUNET_memcpy (payload,
1963 &tcp[1],
1964 payload_length - sizeof(struct GNUNET_TUN_TcpHeader));
1965 }
1966 }
1967 else
1968 {
1969 struct GNUNET_EXIT_TcpDataMessage *tdm;
1970
1971 mlen = sizeof(struct GNUNET_EXIT_TcpDataMessage) + payload_length
1972 - sizeof(struct GNUNET_TUN_TcpHeader);
1973 if (mlen >= GNUNET_MAX_MESSAGE_SIZE)
1974 {
1975 GNUNET_break (0);
1976 return;
1977 }
1978 env = GNUNET_MQ_msg_extra (tdm,
1979 payload_length
1980 - sizeof(struct GNUNET_TUN_TcpHeader),
1981 GNUNET_MESSAGE_TYPE_VPN_TCP_DATA_TO_EXIT);
1982 tdm->reserved = htonl (0);
1983 tdm->tcp_header = *tcp;
1984 GNUNET_memcpy (&tdm[1],
1985 &tcp[1],
1986 payload_length - sizeof(struct GNUNET_TUN_TcpHeader));
1987 }
1988 break;
1989
1990 case IPPROTO_ICMP:
1991 case IPPROTO_ICMPV6:
1992 if (destination->is_service)
1993 {
1994 struct GNUNET_EXIT_IcmpServiceMessage *ism;
1995
1996 /* ICMP protocol translation will be done by the receiver (as we don't know
1997 the target AF); however, we still need to possibly discard the payload
1998 depending on the ICMP type */
1999 switch (af)
2000 {
2001 case AF_INET:
2002 switch (icmp->type)
2003 {
2004 case GNUNET_TUN_ICMPTYPE_ECHO_REPLY:
2005 case GNUNET_TUN_ICMPTYPE_ECHO_REQUEST:
2006 break;
2007
2008 case GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE:
2009 case GNUNET_TUN_ICMPTYPE_SOURCE_QUENCH:
2010 case GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED:
2011 /* throw away ICMP payload, won't be useful for the other side anyway */
2012 payload_length = sizeof(struct GNUNET_TUN_IcmpHeader);
2013 break;
2014
2015 default:
2016 GNUNET_STATISTICS_update (stats,
2017 gettext_noop (
2018 "# ICMPv4 packets dropped (not allowed)"),
2019 1,
2020 GNUNET_NO);
2021 return;
2022 }
2023 /* end of AF_INET */
2024 break;
2025
2026 case AF_INET6:
2027 switch (icmp->type)
2028 {
2029 case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE:
2030 case GNUNET_TUN_ICMPTYPE6_PACKET_TOO_BIG:
2031 case GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED:
2032 case GNUNET_TUN_ICMPTYPE6_PARAMETER_PROBLEM:
2033 /* throw away ICMP payload, won't be useful for the other side anyway */
2034 payload_length = sizeof(struct GNUNET_TUN_IcmpHeader);
2035 break;
2036
2037 case GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST:
2038 case GNUNET_TUN_ICMPTYPE6_ECHO_REPLY:
2039 break;
2040
2041 default:
2042 GNUNET_STATISTICS_update (stats,
2043 gettext_noop (
2044 "# ICMPv6 packets dropped (not allowed)"),
2045 1,
2046 GNUNET_NO);
2047 return;
2048 }
2049 /* end of AF_INET6 */
2050 break;
2051
2052 default:
2053 GNUNET_assert (0);
2054 break;
2055 }
2056
2057 /* update length calculations, as payload_length may have changed */
2058 mlen = sizeof(struct GNUNET_EXIT_IcmpServiceMessage) + alen
2059 + payload_length - sizeof(struct GNUNET_TUN_IcmpHeader);
2060 if (mlen >= GNUNET_MAX_MESSAGE_SIZE)
2061 {
2062 GNUNET_break (0);
2063 return;
2064 }
2065
2066 env = GNUNET_MQ_msg_extra (ism,
2067 payload_length
2068 - sizeof(struct GNUNET_TUN_IcmpHeader),
2069 GNUNET_MESSAGE_TYPE_VPN_ICMP_TO_SERVICE);
2070 ism->af = htonl (af); /* need to tell destination ICMP protocol family! */
2071 ism->icmp_header = *icmp;
2072 GNUNET_memcpy (&ism[1],
2073 &icmp[1],
2074 payload_length - sizeof(struct GNUNET_TUN_IcmpHeader));
2075 }
2076 else
2077 {
2078 struct GNUNET_EXIT_IcmpInternetMessage *iim;
2079 struct in_addr *ip4dst;
2080 struct in6_addr *ip6dst;
2081 void *payload;
2082 uint8_t new_type;
2083
2084 new_type = icmp->type;
2085 /* Perform ICMP protocol-translation (depending on destination AF and source AF)
2086 and throw away ICMP payload depending on ICMP message type */
2087 switch (af)
2088 {
2089 case AF_INET:
2090 switch (icmp->type)
2091 {
2092 case GNUNET_TUN_ICMPTYPE_ECHO_REPLY:
2093 if (destination->details.exit_destination.af == AF_INET6)
2094 new_type = GNUNET_TUN_ICMPTYPE6_ECHO_REPLY;
2095 break;
2096
2097 case GNUNET_TUN_ICMPTYPE_ECHO_REQUEST:
2098 if (destination->details.exit_destination.af == AF_INET6)
2099 new_type = GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST;
2100 break;
2101
2102 case GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE:
2103 if (destination->details.exit_destination.af == AF_INET6)
2104 new_type = GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE;
2105 /* throw away IP-payload, exit will have to make it up anyway */
2106 payload_length = sizeof(struct GNUNET_TUN_IcmpHeader);
2107 break;
2108
2109 case GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED:
2110 if (destination->details.exit_destination.af == AF_INET6)
2111 new_type = GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED;
2112 /* throw away IP-payload, exit will have to make it up anyway */
2113 payload_length = sizeof(struct GNUNET_TUN_IcmpHeader);
2114 break;
2115
2116 case GNUNET_TUN_ICMPTYPE_SOURCE_QUENCH:
2117 if (destination->details.exit_destination.af == AF_INET6)
2118 {
2119 GNUNET_STATISTICS_update (
2120 stats,
2121 gettext_noop ("# ICMPv4 packets dropped (impossible PT to v6)"),
2122 1,
2123 GNUNET_NO);
2124 return;
2125 }
2126 /* throw away IP-payload, exit will have to make it up anyway */
2127 payload_length = sizeof(struct GNUNET_TUN_IcmpHeader);
2128 break;
2129
2130 default:
2131 GNUNET_STATISTICS_update (
2132 stats,
2133 gettext_noop ("# ICMPv4 packets dropped (type not allowed)"),
2134 1,
2135 GNUNET_NO);
2136 return;
2137 }
2138 /* end of AF_INET */
2139 break;
2140
2141 case AF_INET6:
2142 switch (icmp->type)
2143 {
2144 case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE:
2145 if (destination->details.exit_destination.af == AF_INET)
2146 new_type = GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE;
2147 /* throw away IP-payload, exit will have to make it up anyway */
2148 payload_length = sizeof(struct GNUNET_TUN_IcmpHeader);
2149 break;
2150
2151 case GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED:
2152 if (destination->details.exit_destination.af == AF_INET)
2153 new_type = GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED;
2154 /* throw away IP-payload, exit will have to make it up anyway */
2155 payload_length = sizeof(struct GNUNET_TUN_IcmpHeader);
2156 break;
2157
2158 case GNUNET_TUN_ICMPTYPE6_PACKET_TOO_BIG:
2159 if (destination->details.exit_destination.af == AF_INET)
2160 {
2161 GNUNET_STATISTICS_update (
2162 stats,
2163 gettext_noop ("# ICMPv6 packets dropped (impossible PT to v4)"),
2164 1,
2165 GNUNET_NO);
2166 return;
2167 }
2168 /* throw away IP-payload, exit will have to make it up anyway */
2169 payload_length = sizeof(struct GNUNET_TUN_IcmpHeader);
2170 break;
2171
2172 case GNUNET_TUN_ICMPTYPE6_PARAMETER_PROBLEM:
2173 if (destination->details.exit_destination.af == AF_INET)
2174 {
2175 GNUNET_STATISTICS_update (
2176 stats,
2177 gettext_noop ("# ICMPv6 packets dropped (impossible PT to v4)"),
2178 1,
2179 GNUNET_NO);
2180 return;
2181 }
2182 /* throw away IP-payload, exit will have to make it up anyway */
2183 payload_length = sizeof(struct GNUNET_TUN_IcmpHeader);
2184 break;
2185
2186 case GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST:
2187 if (destination->details.exit_destination.af == AF_INET)
2188 new_type = GNUNET_TUN_ICMPTYPE_ECHO_REQUEST;
2189 break;
2190
2191 case GNUNET_TUN_ICMPTYPE6_ECHO_REPLY:
2192 if (destination->details.exit_destination.af == AF_INET)
2193 new_type = GNUNET_TUN_ICMPTYPE_ECHO_REPLY;
2194 break;
2195
2196 default:
2197 GNUNET_STATISTICS_update (
2198 stats,
2199 gettext_noop ("# ICMPv6 packets dropped (type not allowed)"),
2200 1,
2201 GNUNET_NO);
2202 return;
2203 }
2204 /* end of AF_INET6 */
2205 break;
2206
2207 default:
2208 GNUNET_assert (0);
2209 }
2210
2211 /* update length calculations, as payload_length may have changed */
2212 mlen = sizeof(struct GNUNET_EXIT_IcmpInternetMessage) + alen
2213 + payload_length - sizeof(struct GNUNET_TUN_IcmpHeader);
2214 if (mlen >= GNUNET_MAX_MESSAGE_SIZE)
2215 {
2216 GNUNET_break (0);
2217 return;
2218 }
2219 env = GNUNET_MQ_msg_extra (iim,
2220 alen + payload_length
2221 - sizeof(struct GNUNET_TUN_IcmpHeader),
2222 GNUNET_MESSAGE_TYPE_VPN_ICMP_TO_INTERNET);
2223 iim->icmp_header = *icmp;
2224 iim->icmp_header.type = new_type;
2225 iim->af = htonl (destination->details.exit_destination.af);
2226 switch (destination->details.exit_destination.af)
2227 {
2228 case AF_INET:
2229 ip4dst = (struct in_addr *) &iim[1];
2230 *ip4dst = destination->details.exit_destination.ip.v4;
2231 payload = &ip4dst[1];
2232 break;
2233
2234 case AF_INET6:
2235 ip6dst = (struct in6_addr *) &iim[1];
2236 *ip6dst = destination->details.exit_destination.ip.v6;
2237 payload = &ip6dst[1];
2238 break;
2239
2240 default:
2241 GNUNET_assert (0);
2242 }
2243 GNUNET_memcpy (payload,
2244 &icmp[1],
2245 payload_length - sizeof(struct GNUNET_TUN_IcmpHeader));
2246 }
2247 break;
2248
2249 default:
2250 /* not supported above, how can we get here !? */
2251 GNUNET_assert (0);
2252 break;
2253 }
2254 ts->is_established = GNUNET_YES;
2255 send_to_channel (ts, env);
2256}
2257
2258
2259/**
2260 * Receive packets from the helper-process (someone send to the local
2261 * virtual channel interface). Find the destination mapping, and if it
2262 * exists, identify the correct CADET channel (or possibly create it)
2263 * and forward the packet.
2264 *
2265 * @param cls closure, NULL
2266 * @param message message we got from the client (VPN channel interface)
2267 * @return #GNUNET_OK on success,
2268 * #GNUNET_NO to stop further processing (no error)
2269 * #GNUNET_SYSERR to stop further processing with error
2270 */
2271static int
2272message_token (void *cls, const struct GNUNET_MessageHeader *message)
2273{
2274 const struct GNUNET_TUN_Layer2PacketHeader *tun;
2275 size_t mlen;
2276 struct GNUNET_HashCode key;
2277 struct DestinationEntry *de;
2278
2279 GNUNET_STATISTICS_update (stats,
2280 gettext_noop (
2281 "# Packets received from TUN interface"),
2282 1,
2283 GNUNET_NO);
2284 mlen = ntohs (message->size);
2285 if ((ntohs (message->type) != GNUNET_MESSAGE_TYPE_VPN_HELPER) ||
2286 (mlen < sizeof(struct GNUNET_MessageHeader)
2287 + sizeof(struct GNUNET_TUN_Layer2PacketHeader)))
2288 {
2289 GNUNET_break (0);
2290 return GNUNET_OK;
2291 }
2292 tun = (const struct GNUNET_TUN_Layer2PacketHeader *) &message[1];
2293 mlen -= (sizeof(struct GNUNET_MessageHeader)
2294 + sizeof(struct GNUNET_TUN_Layer2PacketHeader));
2295 switch (ntohs (tun->proto))
2296 {
2297 case ETH_P_IPV6: {
2298 const struct GNUNET_TUN_IPv6Header *pkt6;
2299
2300 if (mlen < sizeof(struct GNUNET_TUN_IPv6Header))
2301 {
2302 /* blame kernel */
2303 GNUNET_break (0);
2304 return GNUNET_OK;
2305 }
2306 pkt6 = (const struct GNUNET_TUN_IPv6Header *) &tun[1];
2307 get_destination_key_from_ip (AF_INET6, &pkt6->destination_address, &key);
2308 de = GNUNET_CONTAINER_multihashmap_get (destination_map, &key);
2309 if (NULL == de)
2310 {
2311 char buf[INET6_ADDRSTRLEN];
2312
2313 GNUNET_log (
2314 GNUNET_ERROR_TYPE_INFO,
2315 _ ("Packet received for unmapped destination `%s' (dropping it)\n"),
2316 inet_ntop (AF_INET6, &pkt6->destination_address, buf, sizeof(buf)));
2317 return GNUNET_OK;
2318 }
2319 route_packet (de,
2320 AF_INET6,
2321 pkt6->next_header,
2322 &pkt6->source_address,
2323 &pkt6->destination_address,
2324 &pkt6[1],
2325 mlen - sizeof(struct GNUNET_TUN_IPv6Header));
2326 }
2327 break;
2328
2329 case ETH_P_IPV4: {
2330 struct GNUNET_TUN_IPv4Header *pkt4;
2331
2332 if (mlen < sizeof(struct GNUNET_TUN_IPv4Header))
2333 {
2334 /* blame kernel */
2335 GNUNET_break (0);
2336 return GNUNET_OK;
2337 }
2338 pkt4 = (struct GNUNET_TUN_IPv4Header *) &tun[1];
2339 get_destination_key_from_ip (AF_INET, &pkt4->destination_address, &key);
2340 de = GNUNET_CONTAINER_multihashmap_get (destination_map, &key);
2341 if (NULL == de)
2342 {
2343 char buf[INET_ADDRSTRLEN];
2344
2345 GNUNET_log (
2346 GNUNET_ERROR_TYPE_INFO,
2347 _ ("Packet received for unmapped destination `%s' (dropping it)\n"),
2348 inet_ntop (AF_INET, &pkt4->destination_address, buf, sizeof(buf)));
2349 return GNUNET_OK;
2350 }
2351 if (pkt4->header_length * 4 != sizeof(struct GNUNET_TUN_IPv4Header))
2352 {
2353 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2354 _ ("Received IPv4 packet with options (dropping it)\n"));
2355 return GNUNET_OK;
2356 }
2357 route_packet (de,
2358 AF_INET,
2359 pkt4->protocol,
2360 &pkt4->source_address,
2361 &pkt4->destination_address,
2362 &pkt4[1],
2363 mlen - sizeof(struct GNUNET_TUN_IPv4Header));
2364 }
2365 break;
2366
2367 default:
2368 GNUNET_log (
2369 GNUNET_ERROR_TYPE_INFO,
2370 _ ("Received packet of unknown protocol %d from TUN (dropping it)\n"),
2371 (unsigned int) ntohs (tun->proto));
2372 break;
2373 }
2374 return GNUNET_OK;
2375}
2376
2377
2378/**
2379 * Allocate an IPv4 address from the range of the channel
2380 * for a new redirection.
2381 *
2382 * @param v4 where to store the address
2383 * @return #GNUNET_OK on success,
2384 * #GNUNET_SYSERR on error
2385 */
2386static int
2387allocate_v4_address (struct in_addr *v4)
2388{
2389 const char *ipv4addr = vpn_argv[4];
2390 const char *ipv4mask = vpn_argv[5];
2391 struct in_addr addr;
2392 struct in_addr mask;
2393 struct in_addr rnd;
2394 struct GNUNET_HashCode key;
2395 unsigned int tries;
2396
2397 GNUNET_assert (1 == inet_pton (AF_INET, ipv4addr, &addr));
2398 GNUNET_assert (1 == inet_pton (AF_INET, ipv4mask, &mask));
2399 /* Given 192.168.0.1/255.255.0.0, we want a mask
2400 of '192.168.255.255', thus: */
2401 mask.s_addr = addr.s_addr | ~mask.s_addr;
2402 tries = 0;
2403 do
2404 {
2405 tries++;
2406 if (tries > 16)
2407 {
2408 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2409 _ (
2410 "Failed to find unallocated IPv4 address in VPN's range\n"));
2411 return GNUNET_SYSERR;
2412 }
2413 /* Pick random IPv4 address within the subnet, except 'addr' or 'mask' itself */
2414 rnd.s_addr =
2415 GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, UINT32_MAX);
2416 v4->s_addr = (addr.s_addr | rnd.s_addr) & mask.s_addr;
2417 get_destination_key_from_ip (AF_INET, v4, &key);
2418 }
2419 while ((GNUNET_YES ==
2420 GNUNET_CONTAINER_multihashmap_contains (destination_map, &key)) ||
2421 (v4->s_addr == addr.s_addr) || (v4->s_addr == mask.s_addr));
2422 return GNUNET_OK;
2423}
2424
2425
2426/**
2427 * Allocate an IPv6 address from the range of the channel
2428 * for a new redirection.
2429 *
2430 * @param v6 where to store the address
2431 * @return #GNUNET_OK on success,
2432 * #GNUNET_SYSERR on error
2433 */
2434static int
2435allocate_v6_address (struct in6_addr *v6)
2436{
2437 const char *ipv6addr = vpn_argv[2];
2438 struct in6_addr addr;
2439 struct in6_addr mask;
2440 struct in6_addr rnd;
2441 int i;
2442 struct GNUNET_HashCode key;
2443 unsigned int tries;
2444
2445 GNUNET_assert (1 == inet_pton (AF_INET6, ipv6addr, &addr));
2446 GNUNET_assert (ipv6prefix < 128);
2447 /* Given ABCD::/96, we want a mask of 'ABCD::FFFF:FFFF,
2448 thus: */
2449 mask = addr;
2450 for (i = 127; i >= ipv6prefix; i--)
2451 mask.s6_addr[i / 8] |= (1 << (i % 8));
2452
2453 /* Pick random IPv6 address within the subnet, except 'addr' or 'mask' itself */
2454 tries = 0;
2455 do
2456 {
2457 tries++;
2458 if (tries > 16)
2459 {
2460 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2461 _ (
2462 "Failed to find unallocated IPv6 address in VPN's range\n"));
2463 return GNUNET_SYSERR;
2464 }
2465 for (i = 0; i < 16; i++)
2466 {
2467 rnd.s6_addr[i] =
2468 (unsigned char) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
2469 256);
2470 v6->s6_addr[i] = (addr.s6_addr[i] | rnd.s6_addr[i]) & mask.s6_addr[i];
2471 }
2472 get_destination_key_from_ip (AF_INET6, v6, &key);
2473 }
2474 while ((GNUNET_YES ==
2475 GNUNET_CONTAINER_multihashmap_contains (destination_map, &key)) ||
2476 (0 == GNUNET_memcmp (v6, &addr)) ||
2477 (0 == GNUNET_memcmp (v6, &mask)));
2478 return GNUNET_OK;
2479}
2480
2481
2482/**
2483 * Free resources occupied by a destination entry.
2484 *
2485 * @param de entry to free
2486 */
2487static void
2488free_destination_entry (struct DestinationEntry *de)
2489{
2490 struct DestinationChannel *dt;
2491
2492 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2493 "Cleaning up destination entry `%s'\n",
2494 print_channel_destination (de));
2495 GNUNET_STATISTICS_update (stats,
2496 gettext_noop ("# Active destinations"),
2497 -1,
2498 GNUNET_NO);
2499 while (NULL != (dt = de->dt_head))
2500 {
2501 GNUNET_CONTAINER_DLL_remove (de->dt_head, de->dt_tail, dt);
2502 GNUNET_free (dt);
2503 }
2504 if (NULL != de->heap_node)
2505 {
2506 GNUNET_CONTAINER_heap_remove_node (de->heap_node);
2507 de->heap_node = NULL;
2508 GNUNET_assert (
2509 GNUNET_YES ==
2510 GNUNET_CONTAINER_multihashmap_remove (destination_map, &de->key, de));
2511 }
2512 GNUNET_free (de);
2513}
2514
2515
2516/**
2517 * We have too many active destinations. Clean up the oldest destination.
2518 *
2519 * @param except destination that must NOT be cleaned up, even if it is the oldest
2520 */
2521static void
2522expire_destination (struct DestinationEntry *except)
2523{
2524 struct DestinationEntry *de;
2525
2526 de = GNUNET_CONTAINER_heap_peek (destination_heap);
2527 GNUNET_assert (NULL != de);
2528 if (except == de)
2529 return; /* can't do this */
2530 free_destination_entry (de);
2531}
2532
2533
2534/**
2535 * Allocate an IP address for the response.
2536 *
2537 * @param result_af desired address family; set to the actual
2538 * address family; can initially be AF_UNSPEC if there
2539 * is no preference; will be set to AF_UNSPEC if the
2540 * allocation failed
2541 * @param addr set to either v4 or v6 depending on which
2542 * storage location was used; set to NULL if allocation failed
2543 * @param v4 storage space for an IPv4 address
2544 * @param v6 storage space for an IPv6 address
2545 * @return #GNUNET_OK normally, #GNUNET_SYSERR if `* result_af` was
2546 * an unsupported address family (not AF_INET, AF_INET6 or AF_UNSPEC)
2547 */
2548static int
2549allocate_response_ip (int *result_af,
2550 void **addr,
2551 struct in_addr *v4,
2552 struct in6_addr *v6)
2553{
2554 *addr = NULL;
2555 switch (*result_af)
2556 {
2557 case AF_INET:
2558 if (GNUNET_OK != allocate_v4_address (v4))
2559 *result_af = AF_UNSPEC;
2560 else
2561 *addr = v4;
2562 break;
2563
2564 case AF_INET6:
2565 if (GNUNET_OK != allocate_v6_address (v6))
2566 *result_af = AF_UNSPEC;
2567 else
2568 *addr = v6;
2569 break;
2570
2571 case AF_UNSPEC:
2572 if (GNUNET_OK == allocate_v4_address (v4))
2573 {
2574 *addr = v4;
2575 *result_af = AF_INET;
2576 }
2577 else if (GNUNET_OK == allocate_v6_address (v6))
2578 {
2579 *addr = v6;
2580 *result_af = AF_INET6;
2581 }
2582 break;
2583
2584 default:
2585 GNUNET_break (0);
2586 return GNUNET_SYSERR;
2587 }
2588 return GNUNET_OK;
2589}
2590
2591
2592/**
2593 * A client asks us to setup a redirection via some exit node to a
2594 * particular IP. Check if @a msg is well-formed.
2595 * allocated IP.
2596 *
2597 * @param cls client requesting client
2598 * @param msg redirection request
2599 * @return #GNUNET_OK if @a msg is well-formed
2600 */
2601static int
2602check_client_redirect_to_ip (void *cls,
2603 const struct RedirectToIpRequestMessage *msg)
2604{
2605 size_t alen;
2606 int addr_af;
2607
2608 alen = ntohs (msg->header.size) - sizeof(struct RedirectToIpRequestMessage);
2609 addr_af = (int) htonl (msg->addr_af);
2610 switch (addr_af)
2611 {
2612 case AF_INET:
2613 if (alen != sizeof(struct in_addr))
2614 {
2615 GNUNET_break (0);
2616 return GNUNET_SYSERR;
2617 }
2618 break;
2619
2620 case AF_INET6:
2621 if (alen != sizeof(struct in6_addr))
2622 {
2623 GNUNET_break (0);
2624 return GNUNET_SYSERR;
2625 }
2626 break;
2627
2628 default:
2629 GNUNET_break (0);
2630 return GNUNET_SYSERR;
2631 }
2632 return GNUNET_OK;
2633}
2634
2635
2636/**
2637 * A client asks us to setup a redirection via some exit node to a
2638 * particular IP. Setup the redirection and give the client the
2639 * allocated IP.
2640 *
2641 * @param cls client requesting client
2642 * @param msg redirection request
2643 */
2644static void
2645handle_client_redirect_to_ip (void *cls,
2646 const struct RedirectToIpRequestMessage *msg)
2647{
2648 struct GNUNET_SERVICE_Client *client = cls;
2649 size_t alen;
2650 int addr_af;
2651 int result_af;
2652 struct in_addr v4;
2653 struct in6_addr v6;
2654 void *addr;
2655 struct DestinationEntry *de;
2656 struct GNUNET_HashCode key;
2657
2658 alen = ntohs (msg->header.size) - sizeof(struct RedirectToIpRequestMessage);
2659 addr_af = (int) htonl (msg->addr_af);
2660 /* allocate response IP */
2661 result_af = (int) htonl (msg->result_af);
2662 if (GNUNET_OK != allocate_response_ip (&result_af, &addr, &v4, &v6))
2663 {
2664 GNUNET_SERVICE_client_drop (client);
2665 return;
2666 }
2667 /* send reply with our IP address */
2668 send_client_reply (client, msg->request_id, result_af, addr);
2669 if (result_af == AF_UNSPEC)
2670 {
2671 /* failure, we're done */
2672 GNUNET_SERVICE_client_continue (client);
2673 return;
2674 }
2675
2676 {
2677 char sbuf[INET6_ADDRSTRLEN];
2678 char dbuf[INET6_ADDRSTRLEN];
2679
2680 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2681 "Allocated address %s for redirection via exit to %s\n",
2682 inet_ntop (result_af, addr, sbuf, sizeof(sbuf)),
2683 inet_ntop (addr_af, &msg[1], dbuf, sizeof(dbuf)));
2684 }
2685
2686 /* setup destination record */
2687 de = GNUNET_new (struct DestinationEntry);
2688 de->is_service = GNUNET_NO;
2689 de->details.exit_destination.af = addr_af;
2690 GNUNET_memcpy (&de->details.exit_destination.ip, &msg[1], alen);
2691 get_destination_key_from_ip (result_af, addr, &key);
2692 de->key = key;
2693 GNUNET_assert (GNUNET_OK == GNUNET_CONTAINER_multihashmap_put (
2694 destination_map,
2695 &key,
2696 de,
2697 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
2698 de->heap_node = GNUNET_CONTAINER_heap_insert (destination_heap,
2699 de,
2700 GNUNET_TIME_absolute_ntoh (
2701 msg->expiration_time)
2702 .abs_value_us);
2703 GNUNET_STATISTICS_update (stats,
2704 gettext_noop ("# Active destinations"),
2705 1,
2706 GNUNET_NO);
2707 while (GNUNET_CONTAINER_multihashmap_size (destination_map) >
2708 max_destination_mappings)
2709 expire_destination (de);
2710 GNUNET_SERVICE_client_continue (client);
2711}
2712
2713
2714/**
2715 * A client asks us to setup a redirection to a particular peer
2716 * offering a service. Setup the redirection and give the client the
2717 * allocated IP.
2718 *
2719 * @param cls requesting client
2720 * @param msg redirection request
2721 */
2722static void
2723handle_client_redirect_to_service (
2724 void *cls,
2725 const struct RedirectToServiceRequestMessage *msg)
2726{
2727 struct GNUNET_SERVICE_Client *client = cls;
2728 int result_af;
2729 struct in_addr v4;
2730 struct in6_addr v6;
2731 void *addr;
2732 struct DestinationEntry *de;
2733 struct GNUNET_HashCode key;
2734 struct DestinationChannel *dt;
2735
2736 /* allocate response IP */
2737 result_af = (int) htonl (msg->result_af);
2738 if (GNUNET_OK != allocate_response_ip (&result_af, &addr, &v4, &v6))
2739 {
2740 GNUNET_break (0);
2741 GNUNET_SERVICE_client_drop (client);
2742 return;
2743 }
2744 send_client_reply (client, msg->request_id, result_af, addr);
2745 if (result_af == AF_UNSPEC)
2746 {
2747 /* failure, we're done */
2748 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2749 _ ("Failed to allocate IP address for new destination\n"));
2750 GNUNET_SERVICE_client_continue (client);
2751 return;
2752 }
2753
2754 {
2755 char sbuf[INET6_ADDRSTRLEN];
2756
2757 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2758 "Allocated address %s for redirection to service %s on peer %s\n",
2759 inet_ntop (result_af, addr, sbuf, sizeof(sbuf)),
2760 GNUNET_h2s (&msg->service_descriptor),
2761 GNUNET_i2s (&msg->target));
2762 }
2763
2764 /* setup destination record */
2765 de = GNUNET_new (struct DestinationEntry);
2766 de->is_service = GNUNET_YES;
2767 de->details.service_destination.target = msg->target;
2768 de->details.service_destination.service_descriptor = msg->service_descriptor;
2769 get_destination_key_from_ip (result_af, addr, &key);
2770 de->key = key;
2771 GNUNET_assert (GNUNET_OK == GNUNET_CONTAINER_multihashmap_put (
2772 destination_map,
2773 &key,
2774 de,
2775 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
2776 de->heap_node = GNUNET_CONTAINER_heap_insert (destination_heap,
2777 de,
2778 GNUNET_TIME_absolute_ntoh (
2779 msg->expiration_time)
2780 .abs_value_us);
2781 while (GNUNET_CONTAINER_multihashmap_size (destination_map) >
2782 max_destination_mappings)
2783 expire_destination (de);
2784
2785 dt = GNUNET_new (struct DestinationChannel);
2786 dt->destination = de;
2787 GNUNET_CONTAINER_DLL_insert (de->dt_head, de->dt_tail, dt);
2788 /* we're done */
2789 GNUNET_SERVICE_client_continue (client);
2790}
2791
2792
2793/**
2794 * Free memory occupied by an entry in the destination map.
2795 *
2796 * @param cls unused
2797 * @param key unused
2798 * @param value a `struct DestinationEntry *`
2799 * @return #GNUNET_OK (continue to iterate)
2800 */
2801static int
2802cleanup_destination (void *cls, const struct GNUNET_HashCode *key, void *value)
2803{
2804 struct DestinationEntry *de = value;
2805
2806 free_destination_entry (de);
2807 return GNUNET_OK;
2808}
2809
2810
2811/**
2812 * Free memory occupied by an entry in the channel map.
2813 *
2814 * @param cls unused
2815 * @param key unused
2816 * @param value a `struct ChannelState *`
2817 * @return #GNUNET_OK (continue to iterate)
2818 */
2819static int
2820cleanup_channel (void *cls, const struct GNUNET_HashCode *key, void *value)
2821{
2822 struct ChannelState *ts = value;
2823
2824 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2825 "Tearing down channel to `%s' during cleanup\n",
2826 print_channel_destination (&ts->destination));
2827 free_channel_state (ts);
2828 return GNUNET_OK;
2829}
2830
2831
2832/**
2833 * Function scheduled as very last function, cleans up after us
2834 *
2835 * @param cls unused
2836 */
2837static void
2838cleanup (void *cls)
2839{
2840 unsigned int i;
2841
2842 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "VPN is shutting down\n");
2843 if (NULL != destination_map)
2844 {
2845 GNUNET_CONTAINER_multihashmap_iterate (destination_map,
2846 &cleanup_destination,
2847 NULL);
2848 GNUNET_CONTAINER_multihashmap_destroy (destination_map);
2849 destination_map = NULL;
2850 }
2851 if (NULL != destination_heap)
2852 {
2853 GNUNET_CONTAINER_heap_destroy (destination_heap);
2854 destination_heap = NULL;
2855 }
2856 if (NULL != channel_map)
2857 {
2858 GNUNET_CONTAINER_multihashmap_iterate (channel_map, &cleanup_channel, NULL);
2859 GNUNET_CONTAINER_multihashmap_destroy (channel_map);
2860 channel_map = NULL;
2861 }
2862 if (NULL != channel_heap)
2863 {
2864 GNUNET_CONTAINER_heap_destroy (channel_heap);
2865 channel_heap = NULL;
2866 }
2867 if (NULL != cadet_handle)
2868 {
2869 GNUNET_CADET_disconnect (cadet_handle);
2870 cadet_handle = NULL;
2871 }
2872 if (NULL != helper_handle)
2873 {
2874 GNUNET_HELPER_kill (helper_handle, GNUNET_NO);
2875 GNUNET_HELPER_wait (helper_handle);
2876 helper_handle = NULL;
2877 }
2878 if (NULL != stats)
2879 {
2880 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
2881 stats = NULL;
2882 }
2883 for (i = 0; i < 5; i++)
2884 GNUNET_free (vpn_argv[i]);
2885}
2886
2887
2888/**
2889 * Callback called when a client connects to the service.
2890 *
2891 * @param cls closure for the service
2892 * @param c the new client that connected to the service
2893 * @param mq the message queue used to send messages to the client
2894 * @return @a c
2895 */
2896static void *
2897client_connect_cb (void *cls,
2898 struct GNUNET_SERVICE_Client *c,
2899 struct GNUNET_MQ_Handle *mq)
2900{
2901 return c;
2902}
2903
2904
2905/**
2906 * Callback called when a client disconnected from the service
2907 *
2908 * @param cls closure for the service
2909 * @param c the client that disconnected
2910 * @param internal_cls should be equal to @a c
2911 */
2912static void
2913client_disconnect_cb (void *cls,
2914 struct GNUNET_SERVICE_Client *c,
2915 void *internal_cls)
2916{
2917 GNUNET_assert (c == internal_cls);
2918}
2919
2920
2921/**
2922 * Main function that will be run by the scheduler.
2923 *
2924 * @param cls closure
2925 * @param cfg_ configuration
2926 * @param service the initialized service
2927 */
2928static void
2929run (void *cls,
2930 const struct GNUNET_CONFIGURATION_Handle *cfg_,
2931 struct GNUNET_SERVICE_Handle *service)
2932{
2933 char *ifname;
2934 char *ipv6addr;
2935 char *ipv6prefix_s;
2936 char *ipv4addr;
2937 char *ipv4mask;
2938 struct in_addr v4;
2939 struct in6_addr v6;
2940 char *binary;
2941
2942 cfg = cfg_;
2943 binary = GNUNET_OS_get_suid_binary_path (cfg, "gnunet-helper-vpn");
2944
2945 if (GNUNET_YES !=
2946 GNUNET_OS_check_helper_binary (
2947 binary,
2948 GNUNET_YES,
2949 "-d gnunet-vpn - - 169.1.3.3.7 255.255.255.0")) // ipv4 only please!
2950 {
2951 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2952 "`%s' is not SUID or the path is invalid, refusing to run.\n",
2953 binary);
2954 GNUNET_free (binary);
2955 global_ret = 1;
2956 /* we won't "really" exit here, as the 'service' is still running;
2957 however, as no handlers are registered, the service won't do
2958 anything either */
2959 return;
2960 }
2961 stats = GNUNET_STATISTICS_create ("vpn", cfg);
2962 if (GNUNET_OK !=
2963 GNUNET_CONFIGURATION_get_value_number (cfg,
2964 "VPN",
2965 "MAX_MAPPING",
2966 &max_destination_mappings))
2967 max_destination_mappings = 200;
2968 if (GNUNET_OK !=
2969 GNUNET_CONFIGURATION_get_value_number (cfg,
2970 "VPN",
2971 "MAX_TUNNELS",
2972 &max_channel_mappings))
2973 max_channel_mappings = 200;
2974
2975 destination_map =
2976 GNUNET_CONTAINER_multihashmap_create (max_destination_mappings * 2,
2977 GNUNET_NO);
2978 destination_heap =
2979 GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
2980 channel_map =
2981 GNUNET_CONTAINER_multihashmap_create (max_channel_mappings * 2, GNUNET_NO);
2982 channel_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
2983
2984
2985 vpn_argv[0] = GNUNET_strdup ("vpn-gnunet");
2986 if (GNUNET_SYSERR ==
2987 GNUNET_CONFIGURATION_get_value_string (cfg, "VPN", "IFNAME", &ifname))
2988 {
2989 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, "VPN", "IFNAME");
2990 GNUNET_free (binary);
2991 GNUNET_SCHEDULER_shutdown ();
2992 return;
2993 }
2994 vpn_argv[1] = ifname;
2995 ipv6addr = NULL;
2996 if (GNUNET_OK == GNUNET_NETWORK_test_pf (PF_INET6))
2997 {
2998 if (((GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string (cfg,
2999 "VPN",
3000 "IPV6ADDR",
3001 &ipv6addr)) ||
3002 (1 != inet_pton (AF_INET6, ipv6addr, &v6))))
3003 {
3004 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
3005 "VPN",
3006 "IPV6ADDR",
3007 _ ("Must specify valid IPv6 address"));
3008 GNUNET_free (binary);
3009 GNUNET_SCHEDULER_shutdown ();
3010 GNUNET_free (ipv6addr);
3011 return;
3012 }
3013 vpn_argv[2] = ipv6addr;
3014 ipv6prefix_s = NULL;
3015 if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string (cfg,
3016 "VPN",
3017 "IPV6PREFIX",
3018 &ipv6prefix_s))
3019 {
3020 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, "VPN", "IPV6PREFIX");
3021 GNUNET_SCHEDULER_shutdown ();
3022 GNUNET_free (ipv6prefix_s);
3023 return;
3024 }
3025 vpn_argv[3] = ipv6prefix_s;
3026 if ((GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (cfg,
3027 "VPN",
3028 "IPV6PREFIX",
3029 &ipv6prefix)) ||
3030 (ipv6prefix >= 127))
3031 {
3032 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
3033 "VPN",
3034 "IPV4MASK",
3035 _ ("Must specify valid IPv6 mask"));
3036 GNUNET_free (binary);
3037 GNUNET_SCHEDULER_shutdown ();
3038 return;
3039 }
3040 }
3041 else
3042 {
3043 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3044 _ (
3045 "IPv6 support disabled as this system does not support IPv6\n"));
3046 vpn_argv[2] = GNUNET_strdup ("-");
3047 vpn_argv[3] = GNUNET_strdup ("-");
3048 }
3049 if (GNUNET_OK == GNUNET_NETWORK_test_pf (PF_INET))
3050 {
3051 ipv4addr = NULL;
3052 if (((GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string (cfg,
3053 "vpn",
3054 "IPV4ADDR",
3055 &ipv4addr)) ||
3056 (1 != inet_pton (AF_INET, ipv4addr, &v4))))
3057 {
3058 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
3059 "VPN",
3060 "IPV4ADDR",
3061 _ ("Must specify valid IPv4 address"));
3062 GNUNET_free (binary);
3063 GNUNET_SCHEDULER_shutdown ();
3064 GNUNET_free (ipv4addr);
3065 return;
3066 }
3067 vpn_argv[4] = ipv4addr;
3068 ipv4mask = NULL;
3069 if (((GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string (cfg,
3070 "vpn",
3071 "IPV4MASK",
3072 &ipv4mask)) ||
3073 (1 != inet_pton (AF_INET, ipv4mask, &v4))))
3074 {
3075 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
3076 "VPN",
3077 "IPV4MASK",
3078 _ ("Must specify valid IPv4 mask"));
3079 GNUNET_free (binary);
3080 GNUNET_SCHEDULER_shutdown ();
3081 GNUNET_free (ipv4mask);
3082 return;
3083 }
3084 vpn_argv[5] = ipv4mask;
3085 }
3086 else
3087 {
3088 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3089 _ (
3090 "IPv4 support disabled as this system does not support IPv4\n"));
3091 vpn_argv[4] = GNUNET_strdup ("-");
3092 vpn_argv[5] = GNUNET_strdup ("-");
3093 }
3094 vpn_argv[6] = NULL;
3095
3096 cadet_handle = GNUNET_CADET_connect (cfg_);
3097 // FIXME never opens ports???
3098 helper_handle = GNUNET_HELPER_start (GNUNET_NO,
3099 binary,
3100 vpn_argv,
3101 &message_token,
3102 NULL,
3103 NULL);
3104 GNUNET_free (binary);
3105 GNUNET_SCHEDULER_add_shutdown (&cleanup, NULL);
3106}
3107
3108
3109/**
3110 * Define "main" method using service macro.
3111 */
3112GNUNET_SERVICE_MAIN (
3113 "vpn",
3114 GNUNET_SERVICE_OPTION_NONE,
3115 &run,
3116 &client_connect_cb,
3117 &client_disconnect_cb,
3118 NULL,
3119 GNUNET_MQ_hd_var_size (client_redirect_to_ip,
3120 GNUNET_MESSAGE_TYPE_VPN_CLIENT_REDIRECT_TO_IP,
3121 struct RedirectToIpRequestMessage,
3122 NULL),
3123 GNUNET_MQ_hd_fixed_size (client_redirect_to_service,
3124 GNUNET_MESSAGE_TYPE_VPN_CLIENT_REDIRECT_TO_SERVICE,
3125 struct RedirectToServiceRequestMessage,
3126 NULL),
3127 GNUNET_MQ_handler_end ());
3128
3129
3130/* end of gnunet-service-vpn.c */
diff --git a/src/service/vpn/meson.build b/src/service/vpn/meson.build
new file mode 100644
index 000000000..ededbc68e
--- /dev/null
+++ b/src/service/vpn/meson.build
@@ -0,0 +1,52 @@
1libgnunetvpn_src = ['vpn_api.c']
2
3gnunetservicevpn_src = ['gnunet-service-vpn.c']
4
5exitdir = include_directories('../exit')
6
7configure_file(input : 'vpn.conf.in',
8 output : 'vpn.conf',
9 configuration : cdata,
10 install: true,
11 install_dir: pkgcfgdir)
12
13
14if get_option('monolith')
15 foreach p : libgnunetvpn_src + gnunetservicevpn_src
16 gnunet_src += 'vpn/' + p
17 endforeach
18endif
19
20libgnunetvpn = library('gnunetvpn',
21 libgnunetvpn_src,
22 soversion: '0',
23 version: '0.0.0',
24 dependencies: libgnunetutil_dep,
25 include_directories: [incdir, configuration_inc],
26 install: true,
27 install_dir: get_option('libdir'))
28pkg.generate(libgnunetvpn, url: 'https://www.gnunet.org',
29 description : 'Provides API for accessing the VPN service')
30libgnunetvpn_dep = declare_dependency(link_with : libgnunetvpn)
31
32executable ('gnunet-service-vpn',
33 gnunetservicevpn_src,
34 dependencies: [libgnunetvpn_dep,
35 libgnunetutil_dep,
36 libgnunetstatistics_dep,
37 libgnunetregex_dep,
38 libgnunetcore_dep,
39 libgnunetcadet_dep,
40 libgnunetblock_dep],
41 include_directories: [incdir, configuration_inc, exitdir],
42 install: true,
43 install_dir: get_option('libdir') / 'gnunet' / 'libexec')
44if host_machine.system() == 'linux'
45 executable ('gnunet-helper-vpn',
46 ['gnunet-helper-vpn.c'],
47 dependencies: [libgnunetvpn_dep,
48 libgnunetutil_dep],
49 include_directories: [incdir, configuration_inc, exitdir],
50 install: true,
51 install_dir: get_option('libdir') / 'gnunet' / 'libexec')
52endif
diff --git a/src/service/vpn/tests/expected b/src/service/vpn/tests/expected
new file mode 100644
index 000000000..26ed82af9
--- /dev/null
+++ b/src/service/vpn/tests/expected
Binary files differ
diff --git a/src/service/vpn/tests/ping b/src/service/vpn/tests/ping
new file mode 100644
index 000000000..ccc855538
--- /dev/null
+++ b/src/service/vpn/tests/ping
Binary files differ
diff --git a/src/service/vpn/tests/test-helper-icmp.sh b/src/service/vpn/tests/test-helper-icmp.sh
new file mode 100755
index 000000000..2d0c8425a
--- /dev/null
+++ b/src/service/vpn/tests/test-helper-icmp.sh
@@ -0,0 +1,17 @@
1#!/bin/sh
2
3/opt/gnunet/bin/gnunet-helper-vpn < ping > result 2>/dev/null &
4
5PID=$!
6
7sleep 1
8
9kill $PID
10
11if cmp result expected; then
12 echo OK
13 exit 0
14else
15 echo FAILED: ICMP-Reply
16 exit 1
17fi
diff --git a/src/service/vpn/tests/test-helper-ifaddr.sh b/src/service/vpn/tests/test-helper-ifaddr.sh
new file mode 100755
index 000000000..b8fde999d
--- /dev/null
+++ b/src/service/vpn/tests/test-helper-ifaddr.sh
@@ -0,0 +1,41 @@
1#!/bin/sh
2
3FIFO=$(mktemp)
4
5rm $FIFO
6
7mkfifo $FIFO
8
9/opt/gnunet/bin/gnunet-helper-vpn > $FIFO 2>&1 &
10
11PID=$!
12
13sleep 1
14
15IF=""
16while read line < $FIFO; do
17 IF=$(echo $line | grep interface | sed -e 's/.*interface \([^ ]*\).*/\1/')
18 if [ "$IF" != "" ]; then
19 break
20 fi
21done
22
23r=0
24if /sbin/ifconfig $IF | grep inet6 | grep -q '1234::1/16'; then
25 echo OK
26else
27 echo FAILED: Interface-Address not set for IPv6!
28 r=1
29fi
30
31if /sbin/ifconfig $IF | grep "inet " | grep -q '10.10.10.1'; then
32 echo OK
33else
34 echo FAILED: Interface-Address not set for IPv4!
35 r=1
36fi
37
38rm $FIFO
39kill $PID
40
41exit $r
diff --git a/src/service/vpn/vpn.conf.in b/src/service/vpn/vpn.conf.in
new file mode 100644
index 000000000..c0f4c59ed
--- /dev/null
+++ b/src/service/vpn/vpn.conf.in
@@ -0,0 +1,19 @@
1[vpn]
2START_ON_DEMAND = @START_ON_DEMAND@
3@UNIXONLY@ PORT = 2105
4HOSTNAME = localhost
5BINARY = gnunet-service-vpn
6ACCEPT_FROM = 127.0.0.1;
7ACCEPT_FROM6 = ::1;
8UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-vpn.sock
9UNIX_MATCH_UID = NO
10UNIX_MATCH_GID = YES
11
12IPV6ADDR = 1234::1
13IPV6PREFIX = 32
14IPV4ADDR = 10.11.10.1
15IPV4MASK = 255.255.0.0
16VIRTDNS = 10.11.10.2
17VIRTDNS6 = 1234::17
18IFNAME = vpn-gnunet
19
diff --git a/src/service/vpn/vpn.h b/src/service/vpn/vpn.h
new file mode 100644
index 000000000..77cfd34e6
--- /dev/null
+++ b/src/service/vpn/vpn.h
@@ -0,0 +1,153 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 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/vpn.h
23 * @brief IPC messages between VPN library and VPN service
24 * @author Christian Grothoff
25 */
26#ifndef VPN_H
27#define VPN_H
28
29#include "gnunet_util_lib.h"
30
31GNUNET_NETWORK_STRUCT_BEGIN
32
33/**
34 * Message send by the VPN client to the VPN service requesting
35 * the setup of a redirection from some IP via an exit node to
36 * some global Internet address.
37 */
38struct RedirectToIpRequestMessage
39{
40 /**
41 * Type is #GNUNET_MESSAGE_TYPE_VPN_CLIENT_REDIRECT_TO_IP
42 */
43 struct GNUNET_MessageHeader header;
44
45 /**
46 * Always zero.
47 */
48 uint32_t reserved GNUNET_PACKED;
49
50 /**
51 * How long should the redirection be maintained at most?
52 */
53 struct GNUNET_TIME_AbsoluteNBO expiration_time;
54
55 /**
56 * Address family desired for the result (AF_INET or AF_INET6 or AF_UNSPEC, in nbo)
57 */
58 int32_t result_af GNUNET_PACKED;
59
60 /**
61 * Address family used for the destination address (AF_INET or AF_INET6, in nbo)
62 */
63 int32_t addr_af GNUNET_PACKED;
64
65 /**
66 * Unique ID to match a future response to this request.
67 * Picked by the client.
68 */
69 uint64_t request_id GNUNET_PACKED;
70
71 /* followed by destination address ('struct in_addr' or 'struct in6_addr') */
72};
73
74
75/**
76 * Message send by the VPN client to the VPN service requesting
77 * the setup of a redirection from some IP to a service running
78 * at a particular peer.
79 */
80struct RedirectToServiceRequestMessage
81{
82 /**
83 * Type is #GNUNET_MESSAGE_TYPE_VPN_CLIENT_REDIRECT_TO_SERVICE
84 */
85 struct GNUNET_MessageHeader header;
86
87 /**
88 * Always zero.
89 */
90 uint32_t reserved GNUNET_PACKED;
91
92 /**
93 * How long should the redirection be maintained at most?
94 */
95 struct GNUNET_TIME_AbsoluteNBO expiration_time;
96
97 /**
98 * Desired protocol (IPPROTO_UDP or IPPROTO_TCP)
99 */
100 int32_t protocol GNUNET_PACKED;
101
102 /**
103 * Address family desired for the result (AF_INET or AF_INET6 or AF_UNSPEC, in nbo)
104 */
105 int32_t result_af GNUNET_PACKED;
106
107 /**
108 * Target peer offering the service.
109 */
110 struct GNUNET_PeerIdentity target;
111
112 /**
113 * Service descriptor identifying the service.
114 */
115 struct GNUNET_HashCode service_descriptor;
116
117 /**
118 * Unique ID to match a future response to this request.
119 * Picked by the client.
120 */
121 uint64_t request_id GNUNET_PACKED;
122};
123
124
125/**
126 * Response from the VPN service to a VPN client informing about
127 * the IP that was assigned for the requested redirection.
128 */
129struct RedirectToIpResponseMessage
130{
131 /**
132 * Type is #GNUNET_MESSAGE_TYPE_VPN_CLIENT_USE_IP
133 */
134 struct GNUNET_MessageHeader header;
135
136 /**
137 * Address family of the allocated address that follows; will match
138 * "result_af" from the request, of be "AF_UNSPEC" on errors.
139 */
140 int32_t result_af GNUNET_PACKED;
141
142 /**
143 * Unique ID to match the response to a request.
144 */
145 uint64_t request_id GNUNET_PACKED;
146
147 /* followed by destination address ('struct in_addr' or 'struct in6_addr') */
148};
149
150GNUNET_NETWORK_STRUCT_END
151
152
153#endif
diff --git a/src/service/vpn/vpn_api.c b/src/service/vpn/vpn_api.c
new file mode 100644
index 000000000..8a3464786
--- /dev/null
+++ b/src/service/vpn/vpn_api.c
@@ -0,0 +1,529 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2012, 2016 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/vpn_api.c
23 * @brief library to access the VPN service and tell it how to redirect traffic
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27#include "gnunet_vpn_service.h"
28#include "vpn.h"
29
30
31/**
32 * Opaque VPN handle
33 */
34struct GNUNET_VPN_Handle
35{
36 /**
37 * Configuration we use.
38 */
39 const struct GNUNET_CONFIGURATION_Handle *cfg;
40
41 /**
42 * Connection to VPN service.
43 */
44 struct GNUNET_MQ_Handle *mq;
45
46 /**
47 * Head of list of active redirection requests.
48 */
49 struct GNUNET_VPN_RedirectionRequest *rr_head;
50
51 /**
52 * Tail of list of active redirection requests.
53 */
54 struct GNUNET_VPN_RedirectionRequest *rr_tail;
55
56 /**
57 * Identifier of a reconnect task.
58 */
59 struct GNUNET_SCHEDULER_Task *rt;
60
61 /**
62 * How long do we wait until we try to reconnect?
63 */
64 struct GNUNET_TIME_Relative backoff;
65
66 /**
67 * ID of the last request that was submitted to the service.
68 */
69 uint64_t request_id_gen;
70};
71
72
73/**
74 * Opaque redirection request handle.
75 */
76struct GNUNET_VPN_RedirectionRequest
77{
78 /**
79 * Element in DLL.
80 */
81 struct GNUNET_VPN_RedirectionRequest *next;
82
83 /**
84 * Element in DLL.
85 */
86 struct GNUNET_VPN_RedirectionRequest *prev;
87
88 /**
89 * Pointer to the VPN struct.
90 */
91 struct GNUNET_VPN_Handle *vh;
92
93 /**
94 * Target IP address for the redirection, or NULL for
95 * redirection to service. Allocated after this struct.
96 */
97 const void *addr;
98
99 /**
100 * Function to call with the designated IP address.
101 */
102 GNUNET_VPN_AllocationCallback cb;
103
104 /**
105 * Closure for @e cb.
106 */
107 void *cb_cls;
108
109 /**
110 * For service redirection, identity of the peer offering the service.
111 */
112 struct GNUNET_PeerIdentity peer;
113
114 /**
115 * For service redirection, service descriptor.
116 */
117 struct GNUNET_HashCode serv;
118
119 /**
120 * At what time should the created service mapping expire?
121 */
122 struct GNUNET_TIME_Absolute expiration_time;
123
124 /**
125 * non-zero if this request has been sent to the service.
126 */
127 uint64_t request_id;
128
129 /**
130 * Desired address family for the result.
131 */
132 int result_af;
133
134 /**
135 * Address family of @e addr. AF_INET or AF_INET6.
136 */
137 int addr_af;
138
139 /**
140 * For service redirection, IPPROT_UDP or IPPROTO_TCP.
141 */
142 uint8_t protocol;
143};
144
145
146/**
147 * Disconnect from the service (communication error) and reconnect later.
148 *
149 * @param vh handle to reconnect.
150 */
151static void
152reconnect (struct GNUNET_VPN_Handle *vh);
153
154
155/**
156 * Check a #GNUNET_MESSAGE_TYPE_VPN_CLIENT_USE_IP message from the
157 * VPN service.
158 *
159 * @param cls the `struct GNUNET_VPN_Handle`
160 * @param rm message received
161 * @return #GNUNET_OK if @a rm is well-formed
162 */
163static int
164check_use_ip (void *cls,
165 const struct RedirectToIpResponseMessage *rm)
166{
167 size_t alen;
168 int af;
169
170 af = (int) ntohl (rm->result_af);
171 switch (af)
172 {
173 case AF_UNSPEC:
174 alen = 0;
175 break;
176
177 case AF_INET:
178 alen = sizeof(struct in_addr);
179 break;
180
181 case AF_INET6:
182 alen = sizeof(struct in6_addr);
183 break;
184
185 default:
186 GNUNET_break (0);
187 return GNUNET_SYSERR;
188 }
189 if ((ntohs (rm->header.size) != alen + sizeof(*rm)) ||
190 (0 == rm->request_id))
191 {
192 GNUNET_break (0);
193 return GNUNET_SYSERR;
194 }
195 return GNUNET_OK;
196}
197
198
199/**
200 * Handle a #GNUNET_MESSAGE_TYPE_VPN_CLIENT_USE_IP message from the
201 * VPN service.
202 *
203 * @param cls the `struct GNUNET_VPN_Handle`
204 * @param rm message received
205 */
206static void
207handle_use_ip (void *cls,
208 const struct RedirectToIpResponseMessage *rm)
209{
210 struct GNUNET_VPN_Handle *vh = cls;
211 struct GNUNET_VPN_RedirectionRequest *rr;
212 int af;
213
214 af = (int) ntohl (rm->result_af);
215 for (rr = vh->rr_head; NULL != rr; rr = rr->next)
216 {
217 if (rr->request_id == rm->request_id)
218 {
219 GNUNET_CONTAINER_DLL_remove (vh->rr_head,
220 vh->rr_tail,
221 rr);
222 rr->cb (rr->cb_cls,
223 af,
224 (af == AF_UNSPEC) ? NULL : &rm[1]);
225 GNUNET_free (rr);
226 break;
227 }
228 }
229}
230
231
232/**
233 * Add a request to our request queue and transmit it.
234 *
235 * @param rr request to queue and transmit.
236 */
237static void
238send_request (struct GNUNET_VPN_RedirectionRequest *rr)
239{
240 struct GNUNET_VPN_Handle *vh = rr->vh;
241 struct RedirectToIpRequestMessage *rip;
242 struct RedirectToServiceRequestMessage *rs;
243 struct GNUNET_MQ_Envelope *env;
244 size_t alen;
245
246 if (NULL == vh->mq)
247 return;
248 if (NULL == rr->addr)
249 {
250 env = GNUNET_MQ_msg (rs,
251 GNUNET_MESSAGE_TYPE_VPN_CLIENT_REDIRECT_TO_SERVICE);
252 rs->reserved = htonl (0);
253 rs->expiration_time = GNUNET_TIME_absolute_hton (rr->expiration_time);
254 rs->protocol = htonl (rr->protocol);
255 rs->result_af = htonl (rr->result_af);
256 rs->target = rr->peer;
257 rs->service_descriptor = rr->serv;
258 rs->request_id = rr->request_id = ++vh->request_id_gen;
259 }
260 else
261 {
262 switch (rr->addr_af)
263 {
264 case AF_INET:
265 alen = sizeof(struct in_addr);
266 break;
267
268 case AF_INET6:
269 alen = sizeof(struct in6_addr);
270 break;
271
272 default:
273 GNUNET_assert (0);
274 return;
275 }
276 env = GNUNET_MQ_msg_extra (rip,
277 alen,
278 GNUNET_MESSAGE_TYPE_VPN_CLIENT_REDIRECT_TO_IP);
279 rip->reserved = htonl (0);
280 rip->expiration_time = GNUNET_TIME_absolute_hton (rr->expiration_time);
281 rip->result_af = htonl (rr->result_af);
282 rip->addr_af = htonl (rr->addr_af);
283 rip->request_id = rr->request_id = ++vh->request_id_gen;
284 GNUNET_memcpy (&rip[1],
285 rr->addr,
286 alen);
287 }
288 GNUNET_MQ_send (vh->mq,
289 env);
290}
291
292
293/**
294 * Generic error handler, called with the appropriate error code and
295 * the same closure specified at the creation of the message queue.
296 * Not every message queue implementation supports an error handler.
297 *
298 * @param cls closure with the `struct GNUNET_VPN_Handle *`
299 * @param error error code
300 */
301static void
302mq_error_handler (void *cls,
303 enum GNUNET_MQ_Error error)
304{
305 struct GNUNET_VPN_Handle *vh = cls;
306
307 reconnect (vh);
308}
309
310
311/**
312 * Connect to the VPN service and start again to transmit our requests.
313 *
314 * @param cls the `struct GNUNET_VPN_Handle *`
315 */
316static void
317connect_task (void *cls)
318{
319 struct GNUNET_VPN_Handle *vh = cls;
320 struct GNUNET_MQ_MessageHandler handlers[] = {
321 GNUNET_MQ_hd_var_size (use_ip,
322 GNUNET_MESSAGE_TYPE_VPN_CLIENT_USE_IP,
323 struct RedirectToIpResponseMessage,
324 cls),
325 GNUNET_MQ_handler_end ()
326 };
327 struct GNUNET_VPN_RedirectionRequest *rr;
328
329 vh->rt = NULL;
330 vh->mq = GNUNET_CLIENT_connect (vh->cfg,
331 "vpn",
332 handlers,
333 &mq_error_handler,
334 vh);
335 if (NULL == vh->mq)
336 return;
337 for (rr = vh->rr_head; NULL != rr; rr = rr->next)
338 send_request (rr);
339}
340
341
342/**
343 * Disconnect from the service (communication error) and reconnect later.
344 *
345 * @param vh handle to reconnect.
346 */
347static void
348reconnect (struct GNUNET_VPN_Handle *vh)
349{
350 struct GNUNET_VPN_RedirectionRequest *rr;
351
352 GNUNET_MQ_destroy (vh->mq);
353 vh->mq = NULL;
354 vh->request_id_gen = 0;
355 for (rr = vh->rr_head; NULL != rr; rr = rr->next)
356 rr->request_id = 0;
357 vh->backoff = GNUNET_TIME_relative_max (GNUNET_TIME_UNIT_MILLISECONDS,
358 GNUNET_TIME_relative_min (
359 GNUNET_TIME_relative_saturating_multiply (
360 vh->backoff, 2),
361 GNUNET_TIME_relative_multiply (
362 GNUNET_TIME_UNIT_SECONDS, 30)));
363 vh->rt = GNUNET_SCHEDULER_add_delayed (vh->backoff,
364 &connect_task,
365 vh);
366}
367
368
369/**
370 * Cancel redirection request with the service.
371 *
372 * @param rr request to cancel
373 */
374void
375GNUNET_VPN_cancel_request (struct GNUNET_VPN_RedirectionRequest *rr)
376{
377 struct GNUNET_VPN_Handle *vh;
378
379 vh = rr->vh;
380 GNUNET_CONTAINER_DLL_remove (vh->rr_head,
381 vh->rr_tail,
382 rr);
383 GNUNET_free (rr);
384}
385
386
387struct GNUNET_VPN_RedirectionRequest *
388GNUNET_VPN_redirect_to_peer (struct GNUNET_VPN_Handle *vh,
389 int result_af,
390 uint8_t protocol,
391 const struct GNUNET_PeerIdentity *peer,
392 const struct GNUNET_HashCode *serv,
393 struct GNUNET_TIME_Absolute expiration_time,
394 GNUNET_VPN_AllocationCallback cb,
395 void *cb_cls)
396{
397 struct GNUNET_VPN_RedirectionRequest *rr;
398
399 rr = GNUNET_new (struct GNUNET_VPN_RedirectionRequest);
400 rr->vh = vh;
401 rr->cb = cb;
402 rr->cb_cls = cb_cls;
403 rr->peer = *peer;
404 rr->serv = *serv;
405 rr->expiration_time = expiration_time;
406 rr->result_af = result_af;
407 rr->protocol = protocol;
408 GNUNET_CONTAINER_DLL_insert_tail (vh->rr_head,
409 vh->rr_tail,
410 rr);
411 send_request (rr);
412 return rr;
413}
414
415
416/**
417 * Tell the VPN that forwarding to the Internet via some exit node is
418 * requested. Note that both UDP and TCP traffic will be forwarded,
419 * but possibly to different exit nodes. The VPN is to reserve a
420 * particular IP for the redirection and return it. The VPN will
421 * begin the redirection as soon as possible and maintain it as long
422 * as it is actively used and keeping it is feasible. Given resource
423 * limitations, the longest inactive mappings will be destroyed.
424 *
425 * @param vh VPN handle
426 * @param result_af desired address family for the returned allocation
427 * @param addr_af address family for @a addr, AF_INET or AF_INET6
428 * @param addr destination IP address on the Internet; destination
429 * port is to be taken from the VPN packet itself
430 * @param expiration_time at what time should the redirection expire?
431 * (this should not impact connections that are active at that time)
432 * @param cb function to call with the IP
433 * @param cb_cls closure for @a cb
434 * @return handle to cancel the request (means the callback won't be
435 * invoked anymore; the mapping may or may not be established
436 * anyway)
437 */
438struct GNUNET_VPN_RedirectionRequest *
439GNUNET_VPN_redirect_to_ip (struct GNUNET_VPN_Handle *vh,
440 int result_af,
441 int addr_af,
442 const void *addr,
443 struct GNUNET_TIME_Absolute expiration_time,
444 GNUNET_VPN_AllocationCallback cb,
445 void *cb_cls)
446{
447 struct GNUNET_VPN_RedirectionRequest *rr;
448 size_t alen;
449
450 switch (addr_af)
451 {
452 case AF_INET:
453 alen = sizeof(struct in_addr);
454 break;
455
456 case AF_INET6:
457 alen = sizeof(struct in6_addr);
458 break;
459
460 default:
461 GNUNET_break (0);
462 return NULL;
463 }
464 rr = GNUNET_malloc (sizeof(struct GNUNET_VPN_RedirectionRequest) + alen);
465 rr->vh = vh;
466 rr->addr = &rr[1];
467 rr->cb = cb;
468 rr->cb_cls = cb_cls;
469 rr->expiration_time = expiration_time;
470 rr->result_af = result_af;
471 rr->addr_af = addr_af;
472 GNUNET_memcpy (&rr[1],
473 addr,
474 alen);
475 GNUNET_CONTAINER_DLL_insert_tail (vh->rr_head,
476 vh->rr_tail,
477 rr);
478 send_request (rr);
479 return rr;
480}
481
482
483/**
484 * Connect to the VPN service
485 *
486 * @param cfg configuration to use
487 * @return VPN handle
488 */
489struct GNUNET_VPN_Handle *
490GNUNET_VPN_connect (const struct GNUNET_CONFIGURATION_Handle *cfg)
491{
492 struct GNUNET_VPN_Handle *vh
493 = GNUNET_new (struct GNUNET_VPN_Handle);
494
495 vh->cfg = cfg;
496 connect_task (vh);
497 if (NULL == vh->mq)
498 {
499 GNUNET_free (vh);
500 return NULL;
501 }
502 return vh;
503}
504
505
506/**
507 * Disconnect from the VPN service.
508 *
509 * @param vh VPN handle
510 */
511void
512GNUNET_VPN_disconnect (struct GNUNET_VPN_Handle *vh)
513{
514 GNUNET_assert (NULL == vh->rr_head);
515 if (NULL != vh->mq)
516 {
517 GNUNET_MQ_destroy (vh->mq);
518 vh->mq = NULL;
519 }
520 if (NULL != vh->rt)
521 {
522 GNUNET_SCHEDULER_cancel (vh->rt);
523 vh->rt = NULL;
524 }
525 GNUNET_free (vh);
526}
527
528
529/* end of vpn_api.c */