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