diff options
Diffstat (limited to 'src/vpn/gnunet-service-vpn.c')
-rw-r--r-- | src/vpn/gnunet-service-vpn.c | 3131 |
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 | */ | ||
56 | struct 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 | */ | ||
62 | struct DestinationEntry; | ||
63 | |||
64 | /** | ||
65 | * List of channels we keep for each destination port for a given | ||
66 | * destination entry. | ||
67 | */ | ||
68 | struct 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 | */ | ||
96 | struct 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 | */ | ||
173 | struct 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 | */ | ||
200 | struct 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 | */ | ||
306 | static int global_ret; | ||
307 | |||
308 | /** | ||
309 | * Configuration we use. | ||
310 | */ | ||
311 | static const struct GNUNET_CONFIGURATION_Handle *cfg; | ||
312 | |||
313 | /** | ||
314 | * Handle to the cadet service. | ||
315 | */ | ||
316 | static 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 | */ | ||
322 | static struct GNUNET_CONTAINER_MultiHashMap *destination_map; | ||
323 | |||
324 | /** | ||
325 | * Min-Heap sorted by activity time to expire old mappings. | ||
326 | */ | ||
327 | static 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 | */ | ||
333 | static 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 | */ | ||
339 | static struct GNUNET_CONTAINER_Heap *channel_heap; | ||
340 | |||
341 | /** | ||
342 | * Statistics. | ||
343 | */ | ||
344 | static struct GNUNET_STATISTICS_Handle *stats; | ||
345 | |||
346 | /** | ||
347 | * The handle to the VPN helper process "gnunet-helper-vpn". | ||
348 | */ | ||
349 | static struct GNUNET_HELPER_Handle *helper_handle; | ||
350 | |||
351 | /** | ||
352 | * Arguments to the vpn helper. | ||
353 | */ | ||
354 | static char *vpn_argv[7]; | ||
355 | |||
356 | /** | ||
357 | * Length of the prefix of the VPN's IPv6 network. | ||
358 | */ | ||
359 | static unsigned long long ipv6prefix; | ||
360 | |||
361 | /** | ||
362 | * If there are more than this number of address-mappings, old ones | ||
363 | * will be removed | ||
364 | */ | ||
365 | static 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 | */ | ||
371 | static 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 | */ | ||
382 | static void | ||
383 | get_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 | */ | ||
416 | static void | ||
417 | get_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 | */ | ||
468 | static void | ||
469 | send_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 | */ | ||
509 | static void | ||
510 | free_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 | */ | ||
566 | static void | ||
567 | send_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 | */ | ||
597 | static const char * | ||
598 | print_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 | */ | ||
629 | static void | ||
630 | channel_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 | */ | ||
652 | static void | ||
653 | make_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 | */ | ||
678 | static void | ||
679 | make_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 | */ | ||
703 | static int | ||
704 | check_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 | */ | ||
729 | static void | ||
730 | handle_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 | */ | ||
1079 | static int | ||
1080 | check_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 | */ | ||
1105 | static void | ||
1106 | handle_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 | */ | ||
1229 | static int | ||
1230 | check_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 | */ | ||
1255 | static void | ||
1256 | handle_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 | */ | ||
1363 | static struct GNUNET_CADET_Channel * | ||
1364 | create_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 | */ | ||
1403 | static void | ||
1404 | handle_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 | */ | ||
1455 | static struct ChannelState * | ||
1456 | create_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 | */ | ||
1551 | static void | ||
1552 | expire_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 | */ | ||
1578 | static void | ||
1579 | route_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 | */ | ||
2272 | static int | ||
2273 | message_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 | */ | ||
2387 | static int | ||
2388 | allocate_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 | */ | ||
2435 | static int | ||
2436 | allocate_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 | */ | ||
2488 | static void | ||
2489 | free_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 | */ | ||
2522 | static void | ||
2523 | expire_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 | */ | ||
2549 | static int | ||
2550 | allocate_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 | */ | ||
2602 | static int | ||
2603 | check_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 | */ | ||
2645 | static void | ||
2646 | handle_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 | */ | ||
2723 | static void | ||
2724 | handle_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 | */ | ||
2802 | static int | ||
2803 | cleanup_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 | */ | ||
2820 | static int | ||
2821 | cleanup_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 | */ | ||
2838 | static void | ||
2839 | cleanup (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 | */ | ||
2897 | static void * | ||
2898 | client_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 | */ | ||
2913 | static void | ||
2914 | client_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 | */ | ||
2929 | static void | ||
2930 | run (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 | */ | ||
3113 | GNUNET_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 */ | ||