aboutsummaryrefslogtreecommitdiff
path: root/src/vpn/gnunet-service-vpn.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/vpn/gnunet-service-vpn.c')
-rw-r--r--src/vpn/gnunet-service-vpn.c3131
1 files changed, 0 insertions, 3131 deletions
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 */