aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2012-01-05 20:31:05 +0000
committerChristian Grothoff <christian@grothoff.org>2012-01-05 20:31:05 +0000
commitdb910978a32ed36a72ee29fa1b7ace15c699b158 (patch)
treefcc86be16b389865a6e667ada07c55c98a9d25e3 /src
parentf4b1a87c847292e2d7432307f6d7a994fb2aa733 (diff)
downloadgnunet-db910978a32ed36a72ee29fa1b7ace15c699b158.tar.gz
gnunet-db910978a32ed36a72ee29fa1b7ace15c699b158.zip
-towards new exit daemon
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am1
-rw-r--r--src/exit/exit.conf12
-rw-r--r--src/exit/gnunet-daemon-exit.c1912
-rw-r--r--src/exit/gnunet-helper-exit.c596
-rw-r--r--src/vpn/vpn.conf11
5 files changed, 2521 insertions, 11 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 6022f0733..4e1c338aa 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -31,6 +31,7 @@ SUBDIRS = \
31 fs \ 31 fs \
32 mesh \ 32 mesh \
33 dns \ 33 dns \
34 exit \
34 vpn \ 35 vpn \
35 integration-tests \ 36 integration-tests \
36 $(EXP_DIR) 37 $(EXP_DIR)
diff --git a/src/exit/exit.conf b/src/exit/exit.conf
new file mode 100644
index 000000000..83dfae888
--- /dev/null
+++ b/src/exit/exit.conf
@@ -0,0 +1,12 @@
1[exit]
2CONFIG = $DEFAULTCONFIG
3BINARY = gnunet-daemon-exit
4IPV6ADDR = 1234:1::1
5IPV6PREFIX = 32
6IPV4ADDR = 10.10.1.1
7IPV4MASK = 255.255.0.0
8IFNAME = exit-gnunet
9ENABLE_UDP = NO
10ENABLE_TCP = NO
11
12# MAX_CONNECTIONS = 256
diff --git a/src/exit/gnunet-daemon-exit.c b/src/exit/gnunet-daemon-exit.c
new file mode 100644
index 000000000..7f502cddf
--- /dev/null
+++ b/src/exit/gnunet-daemon-exit.c
@@ -0,0 +1,1912 @@
1/*
2 This file is part of GNUnet.
3 (C) 2010, 2012 Christian Grothoff
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 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 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20
21/**
22 * @file exit/gnunet-daemon-exit.c
23 * @brief tool to allow IP traffic exit from the GNUnet mesh to the Internet
24 * @author Philipp Toelke
25 * @author Christian Grothoff
26 */
27#include <platform.h>
28#include <gnunet_common.h>
29#include <gnunet_program_lib.h>
30#include <gnunet_protocols.h>
31#include <gnunet_applications.h>
32#include <gnunet_mesh_service.h>
33#include <gnunet_constants.h>
34#include <string.h>
35
36
37/* see http://www.iana.org/assignments/ethernet-numbers */
38#ifndef ETH_P_IPV4
39#define ETH_P_IPV4 0x0800
40#endif
41
42#ifndef ETH_P_IPV6
43#define ETH_P_IPV6 0x86DD
44#endif
45
46
47GNUNET_NETWORK_STRUCT_BEGIN
48/**
49 * Header from Linux TUN interface.
50 */
51struct tun_header
52{
53 /**
54 * Some flags (unused).
55 */
56 uint16_t flags;
57
58 /**
59 * Here we get an ETH_P_-number.
60 */
61 uint16_t proto;
62};
63
64/**
65 * Standard IPv4 header.
66 */
67struct ip4_header
68{
69 unsigned header_length:4 GNUNET_PACKED;
70 unsigned version:4 GNUNET_PACKED;
71 uint8_t diff_serv;
72 uint16_t total_length GNUNET_PACKED;
73 uint16_t identification GNUNET_PACKED;
74 unsigned flags:3 GNUNET_PACKED;
75 unsigned fragmentation_offset:13 GNUNET_PACKED;
76 uint8_t ttl;
77 uint8_t protocol;
78 uint16_t checksum GNUNET_PACKED;
79 struct in_addr source_address GNUNET_PACKED;
80 struct in_addr destination_address GNUNET_PACKED;
81};
82
83/**
84 * Standard IPv6 header.
85 */
86struct ip6_header
87{
88 unsigned traffic_class_h:4 GNUNET_PACKED;
89 unsigned version:4 GNUNET_PACKED;
90 unsigned traffic_class_l:4 GNUNET_PACKED;
91 unsigned flow_label:20 GNUNET_PACKED;
92 uint16_t payload_length GNUNET_PACKED;
93 uint8_t next_header;
94 uint8_t hop_limit;
95 struct in6_addr source_address GNUNET_PACKED;
96 struct in6_addr destination_address GNUNET_PACKED;
97};
98
99#define TCP_FLAG_SYN 2
100
101struct tcp_packet
102{
103 unsigned spt:16 GNUNET_PACKED;
104 unsigned dpt:16 GNUNET_PACKED;
105 unsigned seq:32 GNUNET_PACKED;
106 unsigned ack:32 GNUNET_PACKED;
107 unsigned off:4 GNUNET_PACKED;
108 unsigned rsv:4 GNUNET_PACKED;
109 unsigned flg:8 GNUNET_PACKED;
110 unsigned wsz:16 GNUNET_PACKED;
111 unsigned crc:16 GNUNET_PACKED;
112 unsigned urg:16 GNUNET_PACKED;
113};
114
115/**
116 * UDP packet header.
117 */
118struct udp_packet
119{
120 uint16_t spt GNUNET_PACKED;
121 uint16_t dpt GNUNET_PACKED;
122 uint16_t len GNUNET_PACKED;
123 uint16_t crc GNUNET_PACKED;
124};
125
126/**
127 * DNS header.
128 */
129struct dns_header
130{
131 uint16_t id GNUNET_PACKED;
132 uint16_t flags GNUNET_PACKED;
133 uint16_t qdcount GNUNET_PACKED;
134 uint16_t ancount GNUNET_PACKED;
135 uint16_t nscount GNUNET_PACKED;
136 uint16_t arcount GNUNET_PACKED;
137};
138GNUNET_NETWORK_STRUCT_END
139
140/**
141 * Information about a remote address.
142 */
143struct remote_addr
144{
145 /**
146 * AF_INET or AF_INET6.
147 */
148 int af;
149
150 /**
151 * Remote address information.
152 */
153 union
154 {
155 /**
156 * Address, if af is AF_INET.
157 */
158 struct in_addr ipv4;
159
160 /**
161 * Address, if af is AF_INET6.
162 */
163 struct in6_addr ipv6;
164 } address;
165
166 /**
167 * Remote port, in host byte order!
168 */
169 uint16_t port;
170
171 /**
172 * IPPROTO_TCP or IPPROTO_UDP;
173 */
174 uint8_t proto;
175
176};
177
178/**
179 * This struct is saved into the services-hashmap
180 */
181struct redirect_service
182{
183
184 /**
185 * Remote address to use for the service.
186 */
187 struct remote_addr address;
188
189 /**
190 * Descriptor for this service (also key of this entry in the service hash map).
191 */
192 GNUNET_HashCode desc;
193
194 /**
195 * Port I am listening on within GNUnet for this service, in host byte order.
196 */
197 uint16_t my_port;
198
199};
200
201/**
202 * Information we use to track a connection.
203 */
204struct redirect_info
205{
206
207 /**
208 * Address information for the other party.
209 */
210 struct remote_addr remote_address;
211
212 /**
213 * The source-port of this connection, in host byte order
214 */
215 uint16_t source_port;
216
217};
218
219/**
220 * This struct is saved into {tcp,udp}_connections;
221 */
222struct redirect_state
223{
224 /**
225 * Mesh tunnel that is used for this connection.
226 */
227 struct GNUNET_MESH_Tunnel *tunnel;
228
229 /**
230 * Heap node for this state in the connections_heap.
231 */
232 struct GNUNET_CONTAINER_HeapNode *heap_node;
233
234 /**
235 * Key this state has in the connections_map.
236 */
237 GNUNET_HashCode state_key;
238
239 /**
240 * Associated service record, or NULL for no service.
241 */
242 struct redirect_service *serv;
243
244 /**
245 * Source port we use for this connection. FIXME: needed? used?
246 */
247 uint16_t source_port__;
248
249};
250
251/**
252 * Queue of messages to a tunnel.
253 */
254struct tunnel_notify_queue
255{
256 /**
257 * This is a doubly-linked list.
258 */
259 struct tunnel_notify_queue *next;
260
261 /**
262 * This is a doubly-linked list.
263 */
264 struct tunnel_notify_queue *prev;
265
266 /**
267 * Payload to send via the tunnel.
268 */
269 const void *payload;
270
271 /**
272 * Number of bytes in 'cls'.
273 */
274 size_t len;
275};
276
277
278/**
279 * Information we track per mesh tunnel.
280 */
281struct tunnel_state
282{
283 struct tunnel_notify_queue *head;
284 struct tunnel_notify_queue *tail;
285 struct GNUNET_MESH_TransmitHandle *th;
286 struct GNUNET_MESH_Tunnel *tunnel;
287};
288
289
290/**
291 * The handle to the configuration used throughout the process
292 */
293static const struct GNUNET_CONFIGURATION_Handle *cfg;
294
295/**
296 * The handle to the helper
297 */
298static struct GNUNET_HELPER_Handle *helper_handle;
299
300/**
301 * Arguments to the exit helper.
302 */
303static char *exit_argv[7];
304
305/**
306 * IPv6 prefix (0..127) from configuration file.
307 */
308static unsigned long long ipv6prefix;
309
310/**
311 * Final status code.
312 */
313static int ret;
314
315/**
316 * The handle to mesh
317 */
318static struct GNUNET_MESH_Handle *mesh_handle;
319
320/**
321 * This hashmaps contains the mapping from peer, service-descriptor,
322 * source-port and destination-port to a struct redirect_state
323 */
324static struct GNUNET_CONTAINER_MultiHashMap *connections_map;
325
326/**
327 * Heap so we can quickly find "old" connections.
328 */
329static struct GNUNET_CONTAINER_Heap *connections_heap;
330
331/**
332 * If there are at least this many connections, old ones will be removed
333 */
334static long long unsigned int max_connections = 200;
335
336/**
337 * This hashmaps saves interesting things about the configured UDP services
338 */
339static struct GNUNET_CONTAINER_MultiHashMap *udp_services;
340
341/**
342 * This hashmaps saves interesting things about the configured TCP services
343 */
344static struct GNUNET_CONTAINER_MultiHashMap *tcp_services;
345
346
347/**
348 * Given IP information about a connection, calculate the respective
349 * hash we would use for the 'connections_map'.
350 *
351 * @param hash resulting hash
352 * @param ri information about the connection
353 */
354static void
355hash_redirect_info (GNUNET_HashCode * hash,
356 const struct redirect_info *ri)
357{
358 char *off;
359
360 memset (hash, 0, sizeof (GNUNET_HashCode));
361 /* the GNUnet hashmap only uses the first sizeof(unsigned int) of the hash */
362 off = (char*) hash;
363 switch (ri->remote_address.af)
364 {
365 case AF_INET:
366 memcpy (off, &ri->remote_address.address.ipv4, sizeof (struct in_addr));
367 off += sizeof (struct in_addr);
368 break;
369 case AF_INET6:
370 memcpy (off, &ri->remote_address.address.ipv6, sizeof (struct in6_addr));
371 off += sizeof (struct in_addr);
372 break;
373 default:
374 GNUNET_assert (0);
375 }
376 memcpy (off, &ri->remote_address.port, sizeof (uint16_t));
377 memcpy (off, &ri->remote_address.proto, sizeof (uint8_t));
378 memcpy (off, &ri->source_port, sizeof (uint8_t));
379}
380
381
382/**
383 * Given a service descriptor and a destination port, find the
384 * respective service entry.
385 *
386 * @param service_map map of services (TCP or UDP)
387 * @param desc service descriptor
388 * @param dpt destination port
389 * @return NULL if we are not aware of such a service
390 */
391static struct redirect_service *
392find_service (struct GNUNET_CONTAINER_MultiHashMap *service_map,
393 const GNUNET_HashCode *desc,
394 uint16_t dpt)
395{
396 char key[sizeof (GNUNET_HashCode) + sizeof (uint16_t)];
397
398 memcpy (&key[0], &dpt, sizeof (uint16_t));
399 memcpy (&key[sizeof(uint16_t)], desc, sizeof (GNUNET_HashCode));
400 return GNUNET_CONTAINER_multihashmap_get (service_map,
401 (GNUNET_HashCode *) key);
402}
403
404
405/**
406 * Free memory associated with a service record.
407 *
408 * @param cls unused
409 * @param key service descriptor
410 * @param value service record to free
411 * @return GNUNET_OK
412 */
413static int
414free_service_record (void *cls,
415 const GNUNET_HashCode *key,
416 void *value)
417{
418 struct redirect_service *service = value;
419
420 GNUNET_free (service);
421 return GNUNET_OK;
422}
423
424
425/**
426 * Given a service descriptor and a destination port, find the
427 * respective service entry.
428 *
429 * @param service_map map of services (TCP or UDP)
430 * @param name name of the service
431 * @param dpt destination port
432 * @param service service information record to store (service->desc will be set).
433 */
434static void
435store_service (struct GNUNET_CONTAINER_MultiHashMap *service_map,
436 const char *name,
437 uint16_t dpt,
438 struct redirect_service *service)
439{
440 char key[sizeof (GNUNET_HashCode) + sizeof (uint16_t)];
441 GNUNET_HashCode desc;
442
443 GNUNET_CRYPTO_hash (name, strlen (name) + 1, &desc);
444 service->desc = desc;
445 memcpy (&key[0], &dpt, sizeof (uint16_t));
446 memcpy (&key[sizeof(uint16_t)], &desc, sizeof (GNUNET_HashCode));
447 if (GNUNET_OK !=
448 GNUNET_CONTAINER_multihashmap_put (service_map,
449 (GNUNET_HashCode *) key,
450 service,
451 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
452 {
453 free_service_record (NULL, (GNUNET_HashCode *) key, service);
454 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
455 _("Got duplicate service records for `%s:%u'\n"),
456 name,
457 (unsigned int) dpt);
458 }
459}
460
461
462/**
463 * MESH is ready to receive a message for the tunnel. Transmit it.
464 *
465 * @param cls the 'struct tunnel_state'.
466 * @param size number of bytes available in buf
467 * @param buf where to copy the message
468 * @return number of bytes copied to buf
469 */
470static size_t
471send_to_peer_notify_callback (void *cls, size_t size, void *buf)
472{
473 struct tunnel_state *s = cls;
474 struct GNUNET_MESH_Tunnel *tunnel = s->tunnel;
475 struct tunnel_notify_queue *tnq;
476
477 s->th = NULL;
478 tnq = s->head;
479 GNUNET_assert (size >= tnq->len);
480 memcpy (buf, tnq->payload, tnq->len);
481 size = tnq->len;
482 GNUNET_CONTAINER_DLL_remove (s->head,
483 s->tail,
484 tnq);
485 GNUNET_free (tnq);
486 if (NULL != (tnq = s->head))
487 s->th = GNUNET_MESH_notify_transmit_ready (tunnel,
488 GNUNET_NO /* corking */,
489 0 /* priority */,
490 GNUNET_TIME_UNIT_FOREVER_REL,
491 NULL,
492 tnq->len,
493 &send_to_peer_notify_callback,
494 s);
495 return size;
496}
497
498
499/**
500 * Send the given packet via the mesh tunnel.
501 *
502 * @param mesh_tunnel destination
503 * @param payload message to transmit
504 * @param payload_length number of bytes in payload
505 * @param desc descriptor to add
506 * @param mtype message type to use
507 */
508static void
509send_packet_to_mesh_tunnel (struct GNUNET_MESH_Tunnel *mesh_tunnel,
510 const void *payload,
511 size_t payload_length,
512 const GNUNET_HashCode *desc,
513 uint16_t mtype)
514{
515 struct tunnel_state *s;
516 struct tunnel_notify_queue *tnq;
517 struct GNUNET_MessageHeader *msg;
518 size_t len;
519 GNUNET_HashCode *dp;
520
521 len = sizeof (struct GNUNET_MessageHeader) + sizeof (GNUNET_HashCode) + payload_length;
522 if (len >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
523 {
524 GNUNET_break (0);
525 return;
526 }
527 tnq = GNUNET_malloc (sizeof (struct tunnel_notify_queue) + len);
528 tnq->payload = &tnq[1];
529 tnq->len = len;
530 msg = (struct GNUNET_MessageHeader *) &tnq[1];
531 msg->size = htons ((uint16_t) len);
532 msg->type = htons (mtype);
533 dp = (GNUNET_HashCode *) &msg[1];
534 *dp = *desc;
535 memcpy (&dp[1], payload, payload_length);
536 s = GNUNET_MESH_tunnel_get_data (mesh_tunnel);
537 GNUNET_assert (NULL != s);
538 GNUNET_CONTAINER_DLL_insert_tail (s->head, s->tail, tnq);
539 if (NULL == s->th)
540 s->th = GNUNET_MESH_notify_transmit_ready (mesh_tunnel, GNUNET_NO /* cork */, 0 /* priority */,
541 GNUNET_TIME_UNIT_FOREVER_REL,
542 NULL, len,
543 &send_to_peer_notify_callback,
544 s);
545}
546
547
548/**
549 * Get our connection tracking state. Warns if it does not exists,
550 * refreshes the timestamp if it does exist.
551 *
552 * @param af address family
553 * @param protocol IPPROTO_UDP or IPPROTO_TCP
554 * @param destination_ip target IP
555 * @param destination_port target port
556 * @param source_port source port
557 * @return NULL if we have no tracking information for this tuple
558 */
559static struct redirect_state *
560get_redirect_state (int af,
561 int protocol,
562 const void *destination_ip,
563 uint16_t destination_port,
564 uint16_t source_port)
565{
566 struct redirect_info ri;
567 GNUNET_HashCode state_key;
568 struct redirect_state *state;
569
570 ri.remote_address.af = af;
571 if (af == AF_INET)
572 ri.remote_address.address.ipv4 = *((struct in_addr*) destination_ip);
573 else
574 ri.remote_address.address.ipv6 = * ((struct in6_addr*) destination_ip);
575 ri.remote_address.port = destination_port;
576 ri.remote_address.proto = IPPROTO_UDP;
577 ri.source_port = source_port;
578
579 hash_redirect_info (&state_key, &ri);
580 state = GNUNET_CONTAINER_multihashmap_get (connections_map, &state_key);
581 if (NULL == state)
582 {
583 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
584 _("Packet dropped, have no matching connection information\n"));
585 return NULL;
586 }
587 /* Mark this connection as freshly used */
588 GNUNET_CONTAINER_heap_update_cost (connections_heap,
589 state->heap_node,
590 GNUNET_TIME_absolute_get ().abs_value);
591 return state;
592}
593
594
595/**
596 * @brief Handles an UDP packet received from the helper.
597 *
598 * @param udp A pointer to the Packet
599 * @param pktlen number of bytes in 'udp'
600 * @param destination_ip destination IP-address
601 * @param af address family (AFINET or AF_INET6)
602 */
603static void
604udp_from_helper (const struct udp_packet *udp,
605 size_t pktlen,
606 const void *destination_ip, int af)
607{
608 struct redirect_state *state;
609 struct GNUNET_MESH_Tunnel *tunnel;
610 GNUNET_HashCode desc;
611
612 if (pktlen < sizeof (struct udp_packet))
613 {
614 /* blame kernel */
615 GNUNET_break (0);
616 return;
617 }
618 if (pktlen != ntohs (udp->len))
619 {
620 /* blame kernel */
621 GNUNET_break (0);
622 return;
623 }
624 state = get_redirect_state (af, IPPROTO_UDP,
625 destination_ip,
626 ntohs (udp->dpt),
627 ntohs (udp->spt));
628 if (NULL == state)
629 return;
630 tunnel = state->tunnel;
631
632 // FIXME...
633#if 0
634 if (state->type == SERVICE)
635 {
636 /* check if spt == serv.remote if yes: set spt = serv.myport ("nat") */
637 if (ntohs (udp->spt) == state->serv->remote_port)
638 {
639 udp->spt = htons (state->serv->my_port);
640 }
641 else
642 {
643 /* otherwise the answer came from a different port (tftp does this)
644 * add this new port to the list of all services, so that the packets
645 * coming back from the client to this new port will be routed correctly
646 */
647 struct redirect_service *serv =
648 GNUNET_malloc (sizeof (struct redirect_service));
649 memcpy (serv, state->serv, sizeof (struct redirect_service));
650 serv->my_port = ntohs (udp->spt);
651 serv->remote_port = ntohs (udp->spt);
652 uint16_t *desc = alloca (sizeof (GNUNET_HashCode) + 2);
653
654 memcpy ((GNUNET_HashCode *) (desc + 1), &state->desc,
655 sizeof (GNUNET_HashCode));
656 *desc = ntohs (udp->spt);
657 GNUNET_assert (GNUNET_OK ==
658 GNUNET_CONTAINER_multihashmap_put (udp_services,
659 (GNUNET_HashCode *)
660 desc, serv,
661 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
662
663 state->serv = serv;
664 }
665 }
666
667 if (state->type == SERVICE)
668 memcpy (&desc, &state->desc, sizeof (GNUNET_HashCode));
669 else
670 memcpy (&desc, &state->remote, sizeof (struct remote_addr));
671#else
672 memset (&desc, 0, sizeof (desc));
673#endif
674
675 /* send udp-packet back */
676 send_packet_to_mesh_tunnel (tunnel,
677 udp, pktlen,
678 &desc,
679 state->serv != NULL
680 ? GNUNET_MESSAGE_TYPE_VPN_SERVICE_UDP_BACK
681 : GNUNET_MESSAGE_TYPE_VPN_REMOTE_UDP_BACK);
682}
683
684
685/**
686 * @brief Handles a TCP packet received from the helper.
687 *
688 * @param tcp A pointer to the Packet
689 * @param pktlen the length of the packet, including its header
690 * @param destination_ip destination IP-address
691 * @param af address family (AFINET or AF_INET6)
692 */
693static void
694tcp_from_helper (const struct tcp_packet *tcp,
695 size_t pktlen,
696 const void *destination_ip, int af)
697{
698 struct redirect_state *state;
699 struct GNUNET_MESH_Tunnel *tunnel;
700 GNUNET_HashCode desc;
701
702 if (pktlen < sizeof (struct tcp_packet))
703 {
704 /* blame kernel */
705 GNUNET_break (0);
706 return;
707 }
708 state = get_redirect_state (af, IPPROTO_TCP,
709 destination_ip,
710 ntohs (tcp->dpt),
711 ntohs (tcp->spt));
712 if (NULL == state)
713 return;
714 tunnel = state->tunnel;
715
716 // FIXME...
717#if 0
718 if (state->type == SERVICE)
719 {
720 /* check if spt == serv.remote if yes: set spt = serv.myport ("nat") */
721 if (ntohs (tcp->spt) == state->serv->remote_port)
722 {
723 tcp->spt = htons (state->serv->my_port);
724 }
725 else
726 {
727 // This is an illegal packet.
728 return;
729 }
730 }
731
732 /* send tcp-packet back */
733 if (state->type == SERVICE)
734 memcpy (&desc, &state->desc, sizeof (GNUNET_HashCode));
735 else
736 memcpy (&desc, &state->remote, sizeof (struct remote_addr));
737#else
738 memset (&desc, 0, sizeof (desc));
739#endif
740
741
742 send_packet_to_mesh_tunnel (tunnel,
743 tcp, pktlen,
744 &desc,
745 state->serv != NULL
746 ? GNUNET_MESSAGE_TYPE_VPN_SERVICE_TCP_BACK
747 : GNUNET_MESSAGE_TYPE_VPN_REMOTE_TCP_BACK);
748}
749
750
751/**
752 * Receive packets from the helper-process
753 *
754 * @param cls unused
755 * @param client unsued
756 * @param message message received from helper
757 */
758static void
759message_token (void *cls GNUNET_UNUSED, void *client GNUNET_UNUSED,
760 const struct GNUNET_MessageHeader *message)
761{
762 const struct tun_header *pkt_tun;
763 size_t size;
764
765 if (ntohs (message->type) != GNUNET_MESSAGE_TYPE_VPN_HELPER)
766 {
767 GNUNET_break (0);
768 return;
769 }
770 size = ntohs (message->size);
771 if (size < sizeof (struct tun_header) + sizeof (struct GNUNET_MessageHeader))
772 {
773 GNUNET_break (0);
774 return;
775 }
776 pkt_tun = (const struct tun_header *) &message[1];
777 size -= sizeof (struct tun_header) + sizeof (struct GNUNET_MessageHeader);
778 switch (ntohs (pkt_tun->proto))
779 {
780 case ETH_P_IPV6:
781 {
782 const struct ip6_header *pkt6;
783
784 if (size < sizeof (struct ip6_header))
785 {
786 /* Kernel to blame? */
787 GNUNET_break (0);
788 return;
789 }
790 pkt6 = (struct ip6_header *) &pkt_tun[1];
791 if (size != ntohs (pkt6->payload_length))
792 {
793 /* Kernel to blame? */
794 GNUNET_break (0);
795 return;
796 }
797 size -= sizeof (struct ip6_header);
798 switch (pkt6->next_header)
799 {
800 case IPPROTO_UDP:
801 udp_from_helper ( (const struct udp_packet *) &pkt6[1], size,
802 &pkt6->destination_address,
803 AF_INET6);
804 break;
805 case IPPROTO_TCP:
806 tcp_from_helper ((const struct tcp_packet *) &pkt6[1], size,
807 &pkt6->destination_address,
808 AF_INET6);
809 break;
810 default:
811 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
812 _("IPv6 packet with unsupported next header received. Ignored.\n"));
813 return;
814 }
815 }
816 break;
817 case ETH_P_IPV4:
818 {
819 const struct ip4_header *pkt4;
820
821 if (size < sizeof (struct ip4_header))
822 {
823 /* Kernel to blame? */
824 GNUNET_break (0);
825 return;
826 }
827 pkt4 = (const struct ip4_header *) &pkt_tun[1];
828 if (size != ntohs (pkt4->total_length))
829 {
830 /* Kernel to blame? */
831 GNUNET_break (0);
832 return;
833 }
834 if (pkt4->header_length * 4 != sizeof (struct ip4_header))
835 {
836 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
837 _("IPv4 packet options received. Ignored.\n"));
838 return;
839 }
840 size -= sizeof (struct ip4_header);
841 switch (pkt4->protocol)
842 {
843 case IPPROTO_UDP:
844 udp_from_helper ((const struct udp_packet *) &pkt4[1], size,
845 &pkt4->destination_address, AF_INET);
846 break;
847 case IPPROTO_TCP:
848 tcp_from_helper ((const struct tcp_packet *) &pkt4[1], size,
849 &pkt4->destination_address, AF_INET);
850 break;
851 default:
852 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
853 _("IPv4 packet with unsupported next header received. Ignored.\n"));
854 return;
855 }
856 }
857 break;
858 default:
859 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
860 _("Packet from unknown protocol %u received. Ignored.\n"),
861 ntohs (pkt_tun->proto));
862 break;
863 }
864}
865
866
867
868
869static void
870prepare_ipv4_packet (size_t len, uint16_t pktlen, void *payload,
871 uint8_t protocol, void *ipaddress, void *tunnel,
872 struct redirect_info *state, struct ip4_header *pkt4)
873{
874 const char *ipv4addr = exit_argv[4];
875 const char *ipv4mask = exit_argv[5];
876 uint32_t tmp;
877 uint32_t tmp2;
878
879 GNUNET_assert (1 == inet_pton (AF_INET, ipv4addr, &tmp));
880 GNUNET_assert (1 == inet_pton (AF_INET, ipv4mask, &tmp2));
881 memcpy (&pkt4[1], payload, pktlen);
882 pkt4->version = 4;
883 pkt4->header_length = sizeof (struct ip4_header) / 4;
884 pkt4->diff_serv = 0;
885 pkt4->total_length = htons (sizeof (struct ip4_header) + pktlen);
886 pkt4->identification = 0; // FIXME!
887 pkt4->flags = 0;
888 pkt4->fragmentation_offset = 0;
889 pkt4->ttl = 255;
890 pkt4->protocol = protocol;
891 pkt4->checksum = 0; /* Will be calculated later */
892
893 memcpy (&pkt4->destination_address, ipaddress, sizeof (struct in_addr));
894
895 /* Generate a new src-address -- FIXME: not always, right!? */
896
897 /* This should be a noop */
898 tmp = tmp & tmp2;
899 tmp |= ntohl (*((uint32_t *) tunnel)) & (~tmp2);
900
901 pkt4->source_address.s_addr = tmp;
902 pkt4->checksum = GNUNET_CRYPTO_crc16_n (pkt4, sizeof (struct ip4_header));
903
904 // FIXME: memcpy (&state->addr, &tmp, 4);
905
906 switch (protocol)
907 {
908 case IPPROTO_UDP:
909 {
910 struct udp_packet *pkt4_udp = (struct udp_packet *) &pkt4[1];
911 // FIXME: state->pt = pkt4_udp->spt;
912 pkt4_udp->crc = 0; /* Optional for IPv4 */
913 }
914 break;
915 case IPPROTO_TCP:
916 {
917 struct tcp_packet *pkt4_tcp = (struct tcp_packet *) &pkt4[1];
918
919 // FIXME: state->pt = pkt4_tcp->spt;
920 pkt4_tcp->crc = 0;
921 uint32_t sum = 0;
922 sum = GNUNET_CRYPTO_crc16_step (sum,
923 &pkt4->source_address,
924 sizeof (struct in_addr) * 2);
925 tmp = (protocol << 16) | (0xffff & pktlen);
926 tmp = htonl (tmp);
927 sum = GNUNET_CRYPTO_crc16_step (sum, & tmp, 4);
928 sum = GNUNET_CRYPTO_crc16_step (sum, & pkt4_tcp, pktlen);
929 pkt4_tcp->crc = GNUNET_CRYPTO_crc16_finish (sum);
930 }
931 break;
932 default:
933 GNUNET_assert (0);
934 }
935}
936
937
938static void
939prepare_ipv6_packet (size_t len, uint16_t pktlen, void *payload,
940 uint16_t protocol, void *ipaddress, void *tunnel,
941 struct redirect_info *state, struct ip6_header *pkt6)
942{
943 const char *ipv6addr = exit_argv[2];
944 uint32_t tmp;
945
946
947 memcpy (&pkt6[1], payload, pktlen);
948
949 pkt6->version = 6;
950 pkt6->next_header = protocol;
951 pkt6->payload_length = htons (pktlen);
952 pkt6->hop_limit = 64;
953
954 memcpy (&pkt6->destination_address, ipaddress, sizeof (struct in6_addr));
955
956 /* Generate a new src-address
957 * This takes as much from the address of the tunnel as fits into
958 * the host-mask*/
959
960 unsigned long long ipv6prefix_r = (ipv6prefix + 7) / 8;
961
962 inet_pton (AF_INET6, ipv6addr, &pkt6->source_address);
963
964 if (ipv6prefix_r < (16 - sizeof (void *)))
965 ipv6prefix_r = 16 - sizeof (void *);
966
967 unsigned int offset = ipv6prefix_r - (16 - sizeof (void *));
968
969 memcpy ((((char *) &pkt6->source_address)) + ipv6prefix_r,
970 ((char *) &tunnel) + offset, 16 - ipv6prefix_r);
971
972 /* copy the needed information into the state */
973 // FIXME: memcpy (&state->addr, &pkt6->source_address, 16);
974
975 switch (protocol)
976 {
977 case IPPROTO_UDP:
978 {
979 struct udp_packet *pkt6_udp = (struct udp_packet *) &pkt6[1];
980
981 // FIXME: state->pt = pkt6_udp->spt;
982 pkt6_udp->crc = 0;
983 uint32_t sum = 0;
984 sum =
985 GNUNET_CRYPTO_crc16_step (sum, & pkt6->source_address,
986 16 * 2);
987 tmp = (htons (pktlen) & 0xffff);
988 sum = GNUNET_CRYPTO_crc16_step (sum, & tmp, 4);
989 tmp = htons (pkt6->next_header & 0x00ff);
990 sum = GNUNET_CRYPTO_crc16_step (sum, & tmp, 4);
991 sum =
992 GNUNET_CRYPTO_crc16_step (sum, pkt6_udp,
993 ntohs (pkt6_udp->len));
994 pkt6_udp->crc = GNUNET_CRYPTO_crc16_finish (sum);
995 }
996 break;
997 case IPPROTO_TCP:
998 {
999 struct tcp_packet *pkt6_tcp = (struct tcp_packet *) pkt6;
1000
1001 // FIXME: state->pt = pkt6_tcp->spt;
1002 pkt6_tcp->crc = 0;
1003 uint32_t sum = 0;
1004
1005 sum =
1006 GNUNET_CRYPTO_crc16_step (sum, & pkt6->source_address, 16 * 2);
1007 tmp = htonl (pktlen);
1008 sum = GNUNET_CRYPTO_crc16_step (sum, & tmp, 4);
1009 tmp = htonl (((pkt6->next_header & 0x000000ff)));
1010 sum = GNUNET_CRYPTO_crc16_step (sum, & tmp, 4);
1011
1012 sum =
1013 GNUNET_CRYPTO_crc16_step (sum, pkt6_tcp,
1014 ntohs (pkt6->payload_length));
1015 pkt6_tcp->crc = GNUNET_CRYPTO_crc16_finish (sum);
1016 }
1017 break;
1018 default:
1019 GNUNET_assert (0);
1020 break;
1021 }
1022}
1023
1024
1025/**
1026 * We've just experienced a connection in use. Track it, or if it is
1027 * already tracked, update the tracking.
1028 *
1029 * @param u_i IP-level connection tracking state
1030 * @param tunnel associated mesh tunnel
1031 * @param desc service descriptor (or NULL)
1032 * @param serv service information
1033 */
1034static void
1035update_state_map (const struct redirect_info *ri,
1036 struct GNUNET_MESH_Tunnel *tunnel,
1037 const GNUNET_HashCode *desc,
1038 struct redirect_service *serv)
1039{
1040 struct redirect_state *state;
1041 GNUNET_HashCode state_key;
1042
1043 hash_redirect_info (&state_key,
1044 ri);
1045 state = GNUNET_CONTAINER_multihashmap_get (connections_map, &state_key);
1046 if (NULL == state)
1047 {
1048 state = GNUNET_malloc (sizeof (struct redirect_state));
1049 state->tunnel = tunnel;
1050 state->state_key = state_key;
1051 state->serv = serv;
1052 // FIXME? if (NULL != desc) state->desc = *desc;
1053 // FIXME? state->redirect_info = *ri;
1054 GNUNET_assert (GNUNET_OK ==
1055 GNUNET_CONTAINER_multihashmap_put (connections_map, &state_key, state,
1056 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1057 state->heap_node =
1058 GNUNET_CONTAINER_heap_insert (connections_heap,
1059 state,
1060 GNUNET_TIME_absolute_get ().abs_value);
1061 }
1062 else
1063 {
1064 if (state->tunnel != tunnel)
1065 {
1066 /* Stats / warning: two tunnels got exactly the same connection state!? */
1067 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1068 _("Two different mesh tunnels got the same connection state. Oops.\n"));
1069 return;
1070 }
1071 GNUNET_CONTAINER_heap_update_cost (connections_heap,
1072 state->heap_node,
1073 GNUNET_TIME_absolute_get ().abs_value);
1074 }
1075 while (GNUNET_CONTAINER_heap_get_size (connections_heap) > max_connections)
1076 {
1077 state = GNUNET_CONTAINER_heap_remove_root (connections_heap);
1078 state->heap_node = NULL;
1079 GNUNET_MESH_tunnel_destroy (state->tunnel);
1080 GNUNET_assert (GNUNET_OK ==
1081 GNUNET_CONTAINER_multihashmap_remove (connections_map,
1082 &state->state_key,
1083 state));
1084 GNUNET_free (state);
1085 }
1086}
1087
1088
1089
1090
1091/**
1092 * The messages are one GNUNET_HashCode for the service followed by a struct tcp_packet
1093 */
1094static int
1095receive_tcp_service (void *unused GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel,
1096 void **tunnel_ctx GNUNET_UNUSED,
1097 const struct GNUNET_PeerIdentity *sender GNUNET_UNUSED,
1098 const struct GNUNET_MessageHeader *message,
1099 const struct GNUNET_ATS_Information *atsi GNUNET_UNUSED)
1100{
1101#if 0
1102 const GNUNET_HashCode *desc = (const GNUNET_HashCode *) &message[1];
1103 const struct tcp_packet *pkt = (const struct tcp_packet *) &desc[1];
1104 uint16_t pkt_len = ntohs (message->size);
1105 struct redirect_service *serv;
1106 struct redirect_info u_i;
1107 GNUNET_HashCode state_key;
1108
1109 /* check that we got at least a valid header */
1110 if (pkt_len < sizeof (struct GNUNET_MessageHeader) + sizeof (GNUNET_HashCode) + sizeof (struct tcp_packet))
1111 {
1112 GNUNET_break_op (0);
1113 return GNUNET_YES;
1114 }
1115 pkt_len -= (sizeof (struct GNUNET_MessageHeader) + sizeof (GNUNET_HashCode));
1116
1117 if (NULL == (serv = find_service (tcp_services, desc, ntohs (pkt->dpt))))
1118 {
1119 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1120 _("No service found for %s on port %d!\n"),
1121 "TCP",
1122 ntohs (pkt->dpt));
1123 return GNUNET_YES;
1124 }
1125 pkt->dpt = htons (serv->remote_port);
1126
1127 /* At this point it would be possible to check against some kind of ACL. */
1128
1129 switch (serv->version)
1130 {
1131 case 4:
1132 {
1133 size_t len =
1134 sizeof (struct GNUNET_MessageHeader) + sizeof (struct tun_header) +
1135 sizeof (struct ip4_header) + pkt_len;
1136 char buf[len];
1137 struct tun_header *hdr;
1138 struct GNUNET_MessageHeader *mhdr;
1139
1140 memset (buf, 0, len);
1141 mhdr = (struct GNUNET_MessageHeader*) buf;
1142 hdr = (struct tun_header *) &mhdr[1];
1143 mhdr->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
1144 mhdr->size = htons (len);
1145 hdr->flags = 0;
1146 hdr->proto = htons (0x0800);
1147 prepare_ipv4_packet (len, pkt_len, pkt, IPPROTO_TCP, &serv->v4.ip4address,
1148 tunnel, &u_i, (struct ip4_header *) &hdr[1]);
1149 /* FIXME: here, flow-control with mesh would be nice to have... */
1150 (void) GNUNET_HELPER_send (helper_handle,
1151 mhdr,
1152 GNUNET_YES,
1153 NULL, NULL);
1154 break;
1155 }
1156 case 6:
1157 {
1158 size_t len =
1159 sizeof (struct GNUNET_MessageHeader) + sizeof (struct tun_header) +
1160 sizeof (struct ip6_header) + pkt_len;
1161 char buf[len];
1162 struct tun_header *hdr;
1163 struct GNUNET_MessageHeader *mhdr;
1164
1165 memset (buf, 0, len);
1166 mhdr = (struct GNUNET_MessageHeader*) buf;
1167 hdr = (struct tun_header *) &mhdr[1];
1168 mhdr->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
1169 mhdr->size = htons (len);
1170 hdr->flags = 0;
1171 hdr->proto = htons (0x86dd);
1172 prepare_ipv6_packet (len, pkt_len, pkt, IPPROTO_TCP, &serv->v6.ip6address,
1173 tunnel, &u_i, (struct ip6_header *) buf);
1174 /* FIXME: here, flow-control with mesh would be nice to have... */
1175 (void) GNUNET_HELPER_send (helper_handle,
1176 (const struct GNUNET_MessageHeader*) buf,
1177 GNUNET_YES,
1178 NULL, NULL);
1179
1180 break;
1181 }
1182 default:
1183 GNUNET_assert (0);
1184 break;
1185 }
1186
1187
1188 update_state_map (&u_i, desc, tunnel, serv);
1189#endif
1190 return GNUNET_YES;
1191}
1192
1193
1194static int
1195receive_tcp_remote (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel,
1196 void **tunnel_ctx GNUNET_UNUSED,
1197 const struct GNUNET_PeerIdentity *sender GNUNET_UNUSED,
1198 const struct GNUNET_MessageHeader *message,
1199 const struct GNUNET_ATS_Information *atsi GNUNET_UNUSED)
1200{
1201 // FIXME
1202#if 0
1203 GNUNET_HashCode *desc = (GNUNET_HashCode *) (message + 1);
1204 struct tcp_packet *pkt = (struct tcp_packet *) (desc + 1);
1205 struct remote_addr *s = (struct remote_addr *) desc;
1206 char *buf;
1207 size_t len;
1208 uint16_t pkt_len =
1209 ntohs (message->size) - sizeof (struct GNUNET_MessageHeader) -
1210 sizeof (GNUNET_HashCode);
1211
1212 struct redirect_state *state = GNUNET_malloc (sizeof (struct redirect_state));
1213
1214 state->tunnel = tunnel;
1215 state->type = REMOTE;
1216 state->hashmap = tcp_connections;
1217 memcpy (&state->remote, s, sizeof (struct remote_addr));
1218
1219 hash_redirect_info (&state->hash, &state->redirect_info, s->addrlen);
1220
1221 if (GNUNET_NO ==
1222 GNUNET_CONTAINER_multihashmap_contains (tcp_connections, &state->hash))
1223 {
1224 GNUNET_CONTAINER_multihashmap_put (tcp_connections, &state->hash, state,
1225 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
1226
1227 state->heap_node =
1228 GNUNET_CONTAINER_heap_insert (tcp_connections_heap, state,
1229 GNUNET_TIME_absolute_get ().abs_value);
1230
1231 if (GNUNET_CONTAINER_heap_get_size (tcp_connections_heap) >
1232 max_tcp_connections)
1233 GNUNET_SCHEDULER_add_now (collect_connections, tcp_connections_heap);
1234 }
1235 else
1236 GNUNET_free (state);
1237
1238
1239
1240 len =
1241 sizeof (struct GNUNET_MessageHeader) + sizeof (struct pkt_tun) +
1242 sizeof (struct ip6_hdr) + pkt_len;
1243 buf = alloca (len);
1244
1245 memset (buf, 0, len);
1246
1247 switch (s->addrlen)
1248 {
1249 case 4:
1250 prepare_ipv4_packet (len, pkt_len, pkt, IPPROTO_TCP, &s->addr, tunnel,
1251 state, (struct ip4_header *) buf);
1252 break;
1253 case 16:
1254 prepare_ipv6_packet (len, pkt_len, pkt, IPPROTO_TCP, &s->addr, tunnel,
1255 state, (struct ip6_header *) buf);
1256 break;
1257 default:
1258 GNUNET_free (state);
1259 return GNUNET_SYSERR;
1260 }
1261
1262 /* FIXME: here, flow-control with mesh would be nice to have... */
1263 (void) GNUNET_HELPER_send (helper_handle,
1264 (const struct GNUNET_MessageHeader*) buf,
1265 GNUNET_YES,
1266 NULL, NULL);
1267
1268#endif
1269 return GNUNET_YES;
1270}
1271
1272static int
1273receive_udp_remote (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel,
1274 void **tunnel_ctx GNUNET_UNUSED,
1275 const struct GNUNET_PeerIdentity *sender GNUNET_UNUSED,
1276 const struct GNUNET_MessageHeader *message,
1277 const struct GNUNET_ATS_Information *atsi GNUNET_UNUSED)
1278{
1279 // FIXME
1280#if 0
1281 GNUNET_HashCode *desc = (GNUNET_HashCode *) (message + 1);
1282 struct udp_packet *pkt = (struct udp_packet *) (desc + 1);
1283 struct remote_addr *s = (struct remote_addr *) desc;
1284 char *buf;
1285 size_t len;
1286
1287 GNUNET_assert (ntohs (pkt->len) ==
1288 ntohs (message->size) - sizeof (struct GNUNET_MessageHeader) -
1289 sizeof (GNUNET_HashCode));
1290
1291 /* Prepare the state.
1292 * This will be saved in the hashmap, so that the receiving procedure knows
1293 * through which tunnel this connection has to be routed.
1294 */
1295 struct redirect_state *state = GNUNET_malloc (sizeof (struct redirect_state));
1296
1297 state->tunnel = tunnel;
1298 state->hashmap = udp_connections;
1299 state->type = REMOTE;
1300 memcpy (&state->remote, s, sizeof (struct remote_addr));
1301
1302 len =
1303 sizeof (struct GNUNET_MessageHeader) + sizeof (struct pkt_tun) +
1304 sizeof (struct ip6_hdr) + ntohs (pkt->len);
1305 buf = alloca (len);
1306
1307 memset (buf, 0, len);
1308
1309 switch (s->addrlen)
1310 {
1311 case 4:
1312 prepare_ipv4_packet (len, ntohs (pkt->len), pkt, IPPROTO_UDP, &s->addr,
1313 tunnel, state, (struct ip4_header *) buf);
1314 break;
1315 case 16:
1316 prepare_ipv6_packet (len, ntohs (pkt->len), pkt, IPPROTO_UDP, &s->addr,
1317 tunnel, state, (struct ip6_header *) buf);
1318 break;
1319 default:
1320 GNUNET_assert (0);
1321 break;
1322 }
1323
1324 hash_redirect_info (&state->hash, &state->redirect_info, s->addrlen);
1325
1326 (void) GNUNET_HELPER_send (helper_handle,
1327 (const struct GNUNET_MessageHeader*) buf,
1328 GNUNET_YES,
1329 NULL, NULL);
1330
1331
1332 if (GNUNET_NO ==
1333 GNUNET_CONTAINER_multihashmap_contains (udp_connections, &state->hash))
1334 {
1335 GNUNET_CONTAINER_multihashmap_put (udp_connections, &state->hash, state,
1336 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
1337
1338 state->heap_node =
1339 GNUNET_CONTAINER_heap_insert (udp_connections_heap, state,
1340 GNUNET_TIME_absolute_get ().abs_value);
1341
1342 if (GNUNET_CONTAINER_heap_get_size (udp_connections_heap) >
1343 max_udp_connections)
1344 GNUNET_SCHEDULER_add_now (collect_connections, udp_connections_heap);
1345 }
1346 else
1347 GNUNET_free (state);
1348#endif
1349 return GNUNET_YES;
1350}
1351
1352/**
1353 * The messages are one GNUNET_HashCode for the service, followed by a struct udp_packet
1354 */
1355static int
1356receive_udp_service (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel,
1357 void **tunnel_ctx,
1358 const struct GNUNET_PeerIdentity *sender GNUNET_UNUSED,
1359 const struct GNUNET_MessageHeader *message,
1360 const struct GNUNET_ATS_Information *atsi GNUNET_UNUSED)
1361{
1362 // FIXME
1363#if 0
1364 GNUNET_HashCode *desc = (GNUNET_HashCode *) (message + 1);
1365 struct udp_packet *pkt = (struct udp_packet *) (desc + 1);
1366 uint16_t pkt_len = ntohs (message->size);
1367 struct redirect_service *serv;
1368
1369 /* check that we got at least a valid header */
1370 if (pkt_len < sizeof (struct GNUNET_MessageHeader) + sizeof (GNUNET_HashCode) + sizeof (struct udp_packet))
1371 {
1372 GNUNET_break_op (0);
1373 return GNUNET_YES;
1374 }
1375 pkt_len -= (sizeof (struct GNUNET_MessageHeader) + sizeof (GNUNET_HashCode));
1376
1377 GNUNET_assert (ntohs (pkt->len) ==
1378 ntohs (message->size) - sizeof (struct GNUNET_MessageHeader) -
1379 sizeof (GNUNET_HashCode));
1380
1381 if (NULL == (serv = find_service (udp_services, desc, ntohs (pkt->dpt))))
1382 {
1383 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1384 _("No service found for %s on port %d!\n"),
1385 "UDP",
1386 ntohs (pkt->dpt));
1387 return GNUNET_YES;
1388 }
1389 pkt->dpt = htons (serv->remote_port);
1390
1391 /*
1392 * At this point it would be possible to check against some kind of ACL.
1393 */
1394
1395 char *buf;
1396 size_t len;
1397
1398 /* Prepare the state.
1399 * This will be saved in the hashmap, so that the receiving procedure knows
1400 * through which tunnel this connection has to be routed.
1401 */
1402 struct redirect_state *state = GNUNET_malloc (sizeof (struct redirect_state));
1403
1404 state->tunnel = tunnel;
1405 state->serv = serv;
1406 state->type = SERVICE;
1407 state->hashmap = udp_connections;
1408 memcpy (&state->desc, desc, sizeof (GNUNET_HashCode));
1409
1410 len =
1411 sizeof (struct GNUNET_MessageHeader) + sizeof (struct pkt_tun) +
1412 sizeof (struct ip6_hdr) + ntohs (pkt->len);
1413 buf = alloca (len);
1414
1415 memset (buf, 0, len);
1416
1417 switch (serv->version)
1418 {
1419 case 4:
1420 prepare_ipv4_packet (len, ntohs (pkt->len), pkt, IPPROTO_UDP,
1421 &serv->v4.ip4address, tunnel, state,
1422 (struct ip4_header *) buf);
1423 break;
1424 case 6:
1425 prepare_ipv6_packet (len, ntohs (pkt->len), pkt, IPPROTO_UDP,
1426 &serv->v6.ip6address, tunnel, state,
1427 (struct ip6_header *) buf);
1428
1429 break;
1430 default:
1431 GNUNET_assert (0);
1432 break;
1433 }
1434
1435 hash_redirect_info (&state->hash, &state->redirect_info,
1436 serv->version == 4 ? 4 : 16);
1437
1438 if (GNUNET_NO ==
1439 GNUNET_CONTAINER_multihashmap_contains (udp_connections, &state->hash))
1440 {
1441 GNUNET_CONTAINER_multihashmap_put (udp_connections, &state->hash, state,
1442 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
1443
1444 state->heap_node =
1445 GNUNET_CONTAINER_heap_insert (udp_connections_heap, state,
1446 GNUNET_TIME_absolute_get ().abs_value);
1447
1448 if (GNUNET_CONTAINER_heap_get_size (udp_connections_heap) >
1449 max_udp_connections)
1450 GNUNET_SCHEDULER_add_now (collect_connections, udp_connections_heap);
1451 }
1452 else
1453 GNUNET_free (state);
1454
1455 (void) GNUNET_HELPER_send (helper_handle,
1456 (const struct GNUNET_MessageHeader*) buf,
1457 GNUNET_YES,
1458 NULL, NULL);
1459#endif
1460 return GNUNET_YES;
1461}
1462
1463
1464
1465
1466
1467
1468
1469/**
1470 * Callback from GNUNET_MESH for new tunnels.
1471 *
1472 * @param cls closure
1473 * @param tunnel new handle to the tunnel
1474 * @param initiator peer that started the tunnel
1475 * @param atsi performance information for the tunnel
1476 * @return initial tunnel context for the tunnel
1477 */
1478static void *
1479new_tunnel (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel,
1480 const struct GNUNET_PeerIdentity *initiator GNUNET_UNUSED,
1481 const struct GNUNET_ATS_Information *ats GNUNET_UNUSED)
1482{
1483 struct tunnel_state *s = GNUNET_malloc (sizeof (struct tunnel_state));
1484
1485 s->tunnel = tunnel;
1486 return s;
1487}
1488
1489
1490/**
1491 * Function called by mesh whenever an inbound tunnel is destroyed.
1492 * Should clean up any associated state.
1493 *
1494 * @param cls closure (set from GNUNET_MESH_connect)
1495 * @param tunnel connection to the other end (henceforth invalid)
1496 * @param tunnel_ctx place where local state associated
1497 * with the tunnel is stored
1498 */
1499static void
1500clean_tunnel (void *cls GNUNET_UNUSED, const struct GNUNET_MESH_Tunnel *tunnel,
1501 void *tunnel_ctx)
1502{
1503 struct tunnel_state *s = tunnel_ctx;
1504 struct tunnel_notify_queue *tnq;
1505
1506 while (NULL != (tnq = s->head))
1507 {
1508 GNUNET_CONTAINER_DLL_remove (s->head,
1509 s->tail,
1510 tnq);
1511 GNUNET_free (tnq);
1512 }
1513 if (NULL != s->th)
1514 {
1515 GNUNET_MESH_notify_transmit_ready_cancel (s->th);
1516 s->th = NULL;
1517 }
1518 GNUNET_free (s);
1519}
1520
1521
1522/**
1523 * Function that frees everything from a hashmap
1524 *
1525 * @param cls unused
1526 * @param hash key
1527 * @param value value to free
1528 */
1529static int
1530free_iterate (void *cls GNUNET_UNUSED,
1531 const GNUNET_HashCode * hash GNUNET_UNUSED, void *value)
1532{
1533 GNUNET_free (value);
1534 return GNUNET_YES;
1535}
1536
1537
1538/**
1539 * Function scheduled as very last function, cleans up after us
1540 */
1541static void
1542cleanup (void *cls GNUNET_UNUSED,
1543 const struct GNUNET_SCHEDULER_TaskContext *tskctx)
1544{
1545 unsigned int i;
1546
1547 if (helper_handle != NULL)
1548 {
1549 GNUNET_HELPER_stop (helper_handle);
1550 helper_handle = NULL;
1551 }
1552 if (mesh_handle != NULL)
1553 {
1554 GNUNET_MESH_disconnect (mesh_handle);
1555 mesh_handle = NULL;
1556 }
1557 if (NULL != connections_map)
1558 {
1559 GNUNET_CONTAINER_multihashmap_iterate (connections_map, &free_iterate, NULL);
1560 GNUNET_CONTAINER_multihashmap_destroy (connections_map);
1561 connections_map = NULL;
1562 }
1563 if (NULL != connections_heap)
1564 {
1565 GNUNET_CONTAINER_heap_destroy (connections_heap);
1566 connections_heap = NULL;
1567 }
1568 if (NULL != tcp_services)
1569 {
1570 GNUNET_CONTAINER_multihashmap_iterate (tcp_services, &free_service_record, NULL);
1571 GNUNET_CONTAINER_multihashmap_destroy (tcp_services);
1572 tcp_services = NULL;
1573 }
1574 if (NULL != udp_services)
1575 {
1576 GNUNET_CONTAINER_multihashmap_iterate (udp_services, &free_service_record, NULL);
1577 GNUNET_CONTAINER_multihashmap_destroy (udp_services);
1578 udp_services = NULL;
1579 }
1580 for (i=0;i<5;i++)
1581 GNUNET_free_non_null (exit_argv[i]);
1582}
1583
1584
1585/**
1586 * Add services to the service map.
1587 *
1588 * @param proto IPPROTO_TCP or IPPROTO_UDP
1589 * @param cpy copy of the service descriptor (can be mutilated)
1590 * @param name DNS name of the service
1591 */
1592static void
1593add_services (int proto,
1594 char *cpy,
1595 const char *name)
1596{
1597 char *redirect;
1598 char *hostname;
1599 char *hostport;
1600 struct redirect_service *serv;
1601
1602 for (redirect = strtok (cpy, " "); redirect != NULL;
1603 redirect = strtok (NULL, " "))
1604 {
1605 if (NULL == (hostname = strstr (redirect, ":")))
1606 {
1607 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1608 "option `%s' for domain `%s' is not formatted correctly!\n",
1609 redirect,
1610 name);
1611 continue;
1612 }
1613 hostname[0] = '\0';
1614 hostname++;
1615 if (NULL == (hostport = strstr (hostname, ":")))
1616 {
1617 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1618 "option `%s' for domain `%s' is not formatted correctly!\n",
1619 redirect,
1620 name);
1621 continue;
1622 }
1623 hostport[0] = '\0';
1624 hostport++;
1625
1626 int local_port = atoi (redirect);
1627 int remote_port = atoi (hostport);
1628
1629 if (!((local_port > 0) && (local_port < 65536)))
1630 {
1631 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1632 "`%s' is not a valid port number (for domain `%s')!", redirect,
1633 name);
1634 continue;
1635 }
1636 if (!((remote_port > 0) && (remote_port < 65536)))
1637 {
1638 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1639 "`%s' is not a valid port number (for domain `%s')!", hostport,
1640 name);
1641 continue;
1642 }
1643
1644 serv = GNUNET_malloc (sizeof (struct redirect_service));
1645 serv->my_port = (uint16_t) local_port;
1646 serv->address.port = remote_port;
1647 if (0 == strcmp ("localhost4", hostname))
1648 {
1649 const char *ip4addr = exit_argv[4];
1650
1651 serv->address.af = AF_INET;
1652 GNUNET_assert (1 != inet_pton (AF_INET, ip4addr, &serv->address.address.ipv4));
1653 }
1654 else if (0 == strcmp ("localhost6", hostname))
1655 {
1656 const char *ip6addr = exit_argv[2];
1657
1658 serv->address.af = AF_INET6;
1659 GNUNET_assert (1 == inet_pton (AF_INET6, ip6addr, &serv->address.address.ipv6));
1660 }
1661 else
1662 {
1663 struct addrinfo *res;
1664 int ret;
1665
1666 ret = getaddrinfo (hostname, NULL, NULL, &res);
1667 if ( (ret != 0) || (res == NULL) )
1668 {
1669 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1670 _("No addresses found for hostname `%s' of service `%s'!\n"),
1671 hostname,
1672 name);
1673 GNUNET_free (serv);
1674 continue;
1675 }
1676
1677 serv->address.af = res->ai_family;
1678 switch (res->ai_family)
1679 {
1680 case AF_INET:
1681 serv->address.address.ipv4 = ((struct sockaddr_in *) res->ai_addr)->sin_addr;
1682 break;
1683 case AF_INET6:
1684 serv->address.address.ipv6 = ((struct sockaddr_in6 *) res->ai_addr)->sin6_addr;
1685 break;
1686 default:
1687 freeaddrinfo (res);
1688 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1689 _("No IP addresses found for hostname `%s' of service `%s'!\n"),
1690 hostname,
1691 name);
1692 GNUNET_free (serv);
1693 continue;
1694 }
1695 freeaddrinfo (res);
1696 }
1697 store_service ((IPPROTO_UDP == proto) ? udp_services : tcp_services,
1698 name,
1699 local_port,
1700 serv);
1701 }
1702}
1703
1704
1705/**
1706 * Reads the configuration servicecfg and populates udp_services
1707 *
1708 * @param cls unused
1709 * @param section name of section in config, equal to hostname
1710 */
1711static void
1712read_service_conf (void *cls GNUNET_UNUSED, const char *section)
1713{
1714 char *cpy;
1715
1716 if ((strlen (section) < 8) ||
1717 (0 != strcmp (".gnunet.", section + (strlen (section) - 8))))
1718 return;
1719 if (GNUNET_OK ==
1720 GNUNET_CONFIGURATION_get_value_string (cfg, section, "UDP_REDIRECTS",
1721 &cpy))
1722 {
1723 add_services (IPPROTO_UDP, cpy, section);
1724 GNUNET_free (cpy);
1725 }
1726 if (GNUNET_OK ==
1727 GNUNET_CONFIGURATION_get_value_string (cfg, section, "TCP_REDIRECTS",
1728 &cpy))
1729 {
1730 add_services (IPPROTO_TCP, cpy, section);
1731 GNUNET_free (cpy);
1732 }
1733}
1734
1735
1736/**
1737 * @brief Main function that will be run by the scheduler.
1738 *
1739 * @param cls closure
1740 * @param args remaining command-line arguments
1741 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
1742 * @param cfg_ configuration
1743 */
1744static void
1745run (void *cls, char *const *args GNUNET_UNUSED,
1746 const char *cfgfile GNUNET_UNUSED,
1747 const struct GNUNET_CONFIGURATION_Handle *cfg_)
1748{
1749 static struct GNUNET_MESH_MessageHandler handlers[] = {
1750 {&receive_udp_service, GNUNET_MESSAGE_TYPE_VPN_SERVICE_UDP, 0},
1751 {&receive_tcp_service, GNUNET_MESSAGE_TYPE_VPN_SERVICE_TCP, 0},
1752 {NULL, 0, 0},
1753 {NULL, 0, 0},
1754 {NULL, 0, 0}
1755 };
1756
1757 static GNUNET_MESH_ApplicationType apptypes[] = {
1758 GNUNET_APPLICATION_TYPE_END,
1759 GNUNET_APPLICATION_TYPE_END,
1760 GNUNET_APPLICATION_TYPE_END
1761 };
1762 unsigned int handler_idx;
1763 unsigned int app_idx;
1764 int udp;
1765 int tcp;
1766 char *ifname;
1767 char *ipv6addr;
1768 char *ipv6prefix_s;
1769 char *ipv4addr;
1770 char *ipv4mask;
1771 struct in_addr v4;
1772 struct in6_addr v6;
1773
1774 cfg = cfg_;
1775 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &cleanup, cls);
1776 if (GNUNET_OK !=
1777 GNUNET_CONFIGURATION_get_value_number (cfg, "exit", "MAX_CONNECTIONS",
1778 &max_connections))
1779 max_connections = 1024;
1780 exit_argv[0] = GNUNET_strdup ("exit-gnunet");
1781 if (GNUNET_SYSERR ==
1782 GNUNET_CONFIGURATION_get_value_string (cfg, "exit", "IFNAME", &ifname))
1783 {
1784 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1785 "No entry 'IFNAME' in configuration!\n");
1786 GNUNET_SCHEDULER_shutdown ();
1787 return;
1788 }
1789 exit_argv[1] = ifname;
1790 if ( (GNUNET_SYSERR ==
1791 GNUNET_CONFIGURATION_get_value_string (cfg, "exit", "IPV6ADDR",
1792 &ipv6addr) ||
1793 (1 != inet_pton (AF_INET6, ipv6addr, &v6))) )
1794 {
1795 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1796 "No valid entry 'IPV6ADDR' in configuration!\n");
1797 GNUNET_SCHEDULER_shutdown ();
1798 return;
1799 }
1800 exit_argv[2] = ipv6addr;
1801 if (GNUNET_SYSERR ==
1802 GNUNET_CONFIGURATION_get_value_string (cfg, "exit", "IPV6PREFIX",
1803 &ipv6prefix_s))
1804 {
1805 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1806 "No entry 'IPV6PREFIX' in configuration!\n");
1807 GNUNET_SCHEDULER_shutdown ();
1808 return;
1809 }
1810 exit_argv[3] = ipv6prefix_s;
1811 if ( (GNUNET_OK !=
1812 GNUNET_CONFIGURATION_get_value_number (cfg, "exit",
1813 "IPV6PREFIX",
1814 &ipv6prefix)) ||
1815 (ipv6prefix >= 127) )
1816 {
1817 GNUNET_SCHEDULER_shutdown ();
1818 return;
1819 }
1820
1821 if ( (GNUNET_SYSERR ==
1822 GNUNET_CONFIGURATION_get_value_string (cfg, "exit", "IPV4ADDR",
1823 &ipv4addr) ||
1824 (1 != inet_pton (AF_INET, ipv4addr, &v4))) )
1825 {
1826 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1827 "No valid entry for 'IPV4ADDR' in configuration!\n");
1828 GNUNET_SCHEDULER_shutdown ();
1829 return;
1830 }
1831 exit_argv[4] = ipv4addr;
1832 if ( (GNUNET_SYSERR ==
1833 GNUNET_CONFIGURATION_get_value_string (cfg, "exit", "IPV4MASK",
1834 &ipv4mask) ||
1835 (1 != inet_pton (AF_INET, ipv4mask, &v4))) )
1836 {
1837 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1838 "No valid entry 'IPV4MASK' in configuration!\n");
1839 GNUNET_SCHEDULER_shutdown ();
1840 return;
1841 }
1842 exit_argv[5] = ipv4mask;
1843 exit_argv[6] = NULL;
1844
1845 app_idx = 0;
1846 handler_idx = 2;
1847 udp = GNUNET_CONFIGURATION_get_value_yesno (cfg, "exit", "ENABLE_UDP");
1848 tcp = GNUNET_CONFIGURATION_get_value_yesno (cfg, "exit", "ENABLE_TCP");
1849 if (GNUNET_YES == udp)
1850 {
1851 handlers[handler_idx].callback = &receive_udp_remote;
1852 handlers[handler_idx].expected_size = 0;
1853 handlers[handler_idx].type = GNUNET_MESSAGE_TYPE_VPN_REMOTE_UDP;
1854 apptypes[app_idx] = GNUNET_APPLICATION_TYPE_INTERNET_UDP_GATEWAY;
1855 handler_idx++;
1856 app_idx++;
1857 }
1858
1859 if (GNUNET_YES == tcp)
1860 {
1861 handlers[handler_idx].callback = &receive_tcp_remote;
1862 handlers[handler_idx].expected_size = 0;
1863 handlers[handler_idx].type = GNUNET_MESSAGE_TYPE_VPN_REMOTE_TCP;
1864 apptypes[app_idx] = GNUNET_APPLICATION_TYPE_INTERNET_TCP_GATEWAY;
1865 handler_idx++;
1866 app_idx++;
1867 }
1868 udp_services = GNUNET_CONTAINER_multihashmap_create (65536);
1869 tcp_services = GNUNET_CONTAINER_multihashmap_create (65536);
1870 GNUNET_CONFIGURATION_iterate_sections (cfg, &read_service_conf, NULL);
1871
1872 connections_map = GNUNET_CONTAINER_multihashmap_create (65536);
1873 connections_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
1874 mesh_handle
1875 = GNUNET_MESH_connect (cfg, 42 /* queue size */, NULL,
1876 &new_tunnel,
1877 &clean_tunnel, handlers,
1878 apptypes);
1879 if (NULL == mesh_handle)
1880 {
1881 GNUNET_SCHEDULER_shutdown ();
1882 return;
1883 }
1884 helper_handle = GNUNET_HELPER_start ("gnunet-helper-vpn",
1885 exit_argv,
1886 &message_token, NULL);
1887}
1888
1889
1890/**
1891 * The main function
1892 *
1893 * @param argc number of arguments from the command line
1894 * @param argv command line arguments
1895 * @return 0 ok, 1 on error
1896 */
1897int
1898main (int argc, char *const *argv)
1899{
1900 static const struct GNUNET_GETOPT_CommandLineOption options[] = {
1901 GNUNET_GETOPT_OPTION_END
1902 };
1903
1904 return (GNUNET_OK ==
1905 GNUNET_PROGRAM_run (argc, argv, "gnunet-daemon-exit",
1906 gettext_noop
1907 ("Daemon to run to provide an IP exit node for the VPN"),
1908 options, &run, NULL)) ? ret : 1;
1909}
1910
1911
1912/* end of gnunet-daemon-exit.c */
diff --git a/src/exit/gnunet-helper-exit.c b/src/exit/gnunet-helper-exit.c
new file mode 100644
index 000000000..b93ce2382
--- /dev/null
+++ b/src/exit/gnunet-helper-exit.c
@@ -0,0 +1,596 @@
1/*
2 This file is part of GNUnet.
3 (C) 2010 Christian Grothoff
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 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 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20
21/**
22 * @file vpn/gnunet-daemon-vpn.c
23 * @brief the helper for various vpn-daemons. Opens a virtual network-interface,
24 * sends data received on the if to stdout, sends data received on stdin to the
25 * interface
26 * @author Philipp Tölke
27 *
28 * The following list of people have reviewed this code and considered
29 * it safe since the last modification (if you reviewed it, please
30 * have your name added to the list):
31 *
32 * - Philipp Tölke
33 */
34#include "platform.h"
35#include <linux/if_tun.h>
36
37/**
38 * Need 'struct GNUNET_MessageHeader'.
39 */
40#include "gnunet_common.h"
41
42/**
43 * Need VPN message types.
44 */
45#include "gnunet_protocols.h"
46
47/**
48 * Maximum size of a GNUnet message (GNUNET_SERVER_MAX_MESSAGE_SIZE)
49 */
50#define MAX_SIZE 65536
51
52#ifndef _LINUX_IN6_H
53/**
54 * This is in linux/include/net/ipv6.h, but not always exported...
55 */
56struct in6_ifreq
57{
58 struct in6_addr ifr6_addr;
59 uint32_t ifr6_prefixlen;
60 unsigned int ifr6_ifindex;
61};
62#endif
63
64
65/**
66 * Creates a tun-interface called dev;
67 *
68 * @param dev is asumed to point to a char[IFNAMSIZ]
69 * if *dev == '\\0', uses the name supplied by the kernel;
70 * @return the fd to the tun or -1 on error
71 */
72static int
73init_tun (char *dev)
74{
75 struct ifreq ifr;
76 int fd;
77
78 if (NULL == dev)
79 {
80 errno = EINVAL;
81 return -1;
82 }
83
84 if (-1 == (fd = open ("/dev/net/tun", O_RDWR)))
85 {
86 fprintf (stderr, "Error opening `%s': %s\n", "/dev/net/tun",
87 strerror (errno));
88 return -1;
89 }
90
91 if (fd >= FD_SETSIZE)
92 {
93 fprintf (stderr, "File descriptor to large: %d", fd);
94 return -1;
95 }
96
97 memset (&ifr, 0, sizeof (ifr));
98 ifr.ifr_flags = IFF_TUN;
99
100 if ('\0' != *dev)
101 strncpy (ifr.ifr_name, dev, IFNAMSIZ);
102
103 if (-1 == ioctl (fd, TUNSETIFF, (void *) &ifr))
104 {
105 fprintf (stderr, "Error with ioctl on `%s': %s\n", "/dev/net/tun",
106 strerror (errno));
107 (void) close (fd);
108 return -1;
109 }
110 strcpy (dev, ifr.ifr_name);
111 return fd;
112}
113
114
115/**
116 * @brief Sets the IPv6-Address given in address on the interface dev
117 *
118 * @param dev the interface to configure
119 * @param address the IPv6-Address
120 * @param prefix_len the length of the network-prefix
121 */
122static void
123set_address6 (const char *dev, const char *address, unsigned long prefix_len)
124{
125 struct ifreq ifr;
126 struct in6_ifreq ifr6;
127 struct sockaddr_in6 sa6;
128 int fd;
129
130 /*
131 * parse the new address
132 */
133 memset (&sa6, 0, sizeof (struct sockaddr_in6));
134 sa6.sin6_family = AF_INET6;
135 if (1 != inet_pton (AF_INET6, address, sa6.sin6_addr.s6_addr))
136 {
137 fprintf (stderr, "Failed to parse address `%s': %s\n", address,
138 strerror (errno));
139 exit (1);
140 }
141
142 if (-1 == (fd = socket (PF_INET6, SOCK_DGRAM, 0)))
143 {
144 fprintf (stderr, "Error creating socket: %s\n", strerror (errno));
145 exit (1);
146 }
147
148 memset (&ifr, 0, sizeof (struct ifreq));
149 /*
150 * Get the index of the if
151 */
152 strncpy (ifr.ifr_name, dev, IFNAMSIZ);
153 if (-1 == ioctl (fd, SIOGIFINDEX, &ifr))
154 {
155 fprintf (stderr, "ioctl failed at %d: %s\n", __LINE__, strerror (errno));
156 (void) close (fd);
157 exit (1);
158 }
159
160 memset (&ifr6, 0, sizeof (struct in6_ifreq));
161 ifr6.ifr6_addr = sa6.sin6_addr;
162 ifr6.ifr6_ifindex = ifr.ifr_ifindex;
163 ifr6.ifr6_prefixlen = prefix_len;
164
165 /*
166 * Set the address
167 */
168 if (-1 == ioctl (fd, SIOCSIFADDR, &ifr6))
169 {
170 fprintf (stderr, "ioctl failed at line %d: %s\n", __LINE__,
171 strerror (errno));
172 (void) close (fd);
173 exit (1);
174 }
175
176 /*
177 * Get the flags
178 */
179 if (-1 == ioctl (fd, SIOCGIFFLAGS, &ifr))
180 {
181 fprintf (stderr, "ioctl failed at line %d: %s\n", __LINE__,
182 strerror (errno));
183 (void) close (fd);
184 exit (1);
185 }
186
187 /*
188 * Add the UP and RUNNING flags
189 */
190 ifr.ifr_flags |= IFF_UP | IFF_RUNNING;
191 if (-1 == ioctl (fd, SIOCSIFFLAGS, &ifr))
192 {
193 fprintf (stderr, "ioctl failed at line %d: %s\n", __LINE__,
194 strerror (errno));
195 (void) close (fd);
196 exit (1);
197 }
198
199 if (0 != close (fd))
200 {
201 fprintf (stderr, "close failed: %s\n", strerror (errno));
202 exit (1);
203 }
204}
205
206
207/**
208 * @brief Sets the IPv4-Address given in address on the interface dev
209 *
210 * @param dev the interface to configure
211 * @param address the IPv4-Address
212 * @param mask the netmask
213 */
214static void
215set_address4 (const char *dev, const char *address, const char *mask)
216{
217 int fd;
218 struct sockaddr_in *addr;
219 struct ifreq ifr;
220
221 memset (&ifr, 0, sizeof (struct ifreq));
222 addr = (struct sockaddr_in *) &(ifr.ifr_addr);
223 addr->sin_family = AF_INET;
224
225 /*
226 * Parse the address
227 */
228 if (1 != inet_pton (AF_INET, address, &addr->sin_addr.s_addr))
229 {
230 fprintf (stderr, "Failed to parse address `%s': %s\n", address,
231 strerror (errno));
232 exit (1);
233 }
234
235 if (-1 == (fd = socket (PF_INET, SOCK_DGRAM, 0)))
236 {
237 fprintf (stderr, "Error creating socket: %s\n", strerror (errno));
238 exit (1);
239 }
240
241 strncpy (ifr.ifr_name, dev, IFNAMSIZ);
242
243 /*
244 * Set the address
245 */
246 if (-1 == ioctl (fd, SIOCSIFADDR, &ifr))
247 {
248 fprintf (stderr, "ioctl failed at %d: %s\n", __LINE__, strerror (errno));
249 (void) close (fd);
250 exit (1);
251 }
252
253 /*
254 * Parse the netmask
255 */
256 addr = (struct sockaddr_in *) &(ifr.ifr_netmask);
257 if (1 != inet_pton (AF_INET, mask, &addr->sin_addr.s_addr))
258 {
259 fprintf (stderr, "Failed to parse address `%s': %s\n", mask,
260 strerror (errno));
261 (void) close (fd);
262 exit (1);
263 }
264
265 /*
266 * Set the netmask
267 */
268 if (-1 == ioctl (fd, SIOCSIFNETMASK, &ifr))
269 {
270 fprintf (stderr, "ioctl failed at line %d: %s\n", __LINE__,
271 strerror (errno));
272 (void) close (fd);
273 exit (1);
274 }
275
276 /*
277 * Get the flags
278 */
279 if (-1 == ioctl (fd, SIOCGIFFLAGS, &ifr))
280 {
281 fprintf (stderr, "ioctl failed at line %d: %s\n", __LINE__,
282 strerror (errno));
283 (void) close (fd);
284 exit (1);
285 }
286
287 /*
288 * Add the UP and RUNNING flags
289 */
290 ifr.ifr_flags |= IFF_UP | IFF_RUNNING;
291 if (-1 == ioctl (fd, SIOCSIFFLAGS, &ifr))
292 {
293 fprintf (stderr, "ioctl failed at line %d: %s\n", __LINE__,
294 strerror (errno));
295 (void) close (fd);
296 exit (1);
297 }
298
299 if (0 != close (fd))
300 {
301 fprintf (stderr, "close failed: %s\n", strerror (errno));
302 (void) close (fd);
303 exit (1);
304 }
305}
306
307
308/**
309 * Start forwarding to and from the tunnel.
310 *
311 * @param fd_tun tunnel FD
312 */
313static void
314run (int fd_tun)
315{
316 /*
317 * The buffer filled by reading from fd_tun
318 */
319 unsigned char buftun[MAX_SIZE];
320 ssize_t buftun_size = 0;
321 unsigned char *buftun_read = NULL;
322
323 /*
324 * The buffer filled by reading from stdin
325 */
326 unsigned char bufin[MAX_SIZE];
327 ssize_t bufin_size = 0;
328 size_t bufin_rpos = 0;
329 unsigned char *bufin_read = NULL;
330
331 fd_set fds_w;
332 fd_set fds_r;
333
334 /* read refers to reading from fd_tun, writing to stdout */
335 int read_open = 1;
336
337 /* write refers to reading from stdin, writing to fd_tun */
338 int write_open = 1;
339
340 while ((1 == read_open) || (1 == write_open))
341 {
342 FD_ZERO (&fds_w);
343 FD_ZERO (&fds_r);
344
345 /*
346 * We are supposed to read and the buffer is empty
347 * -> select on read from tun
348 */
349 if (read_open && (0 == buftun_size))
350 FD_SET (fd_tun, &fds_r);
351
352 /*
353 * We are supposed to read and the buffer is not empty
354 * -> select on write to stdout
355 */
356 if (read_open && (0 != buftun_size))
357 FD_SET (1, &fds_w);
358
359 /*
360 * We are supposed to write and the buffer is empty
361 * -> select on read from stdin
362 */
363 if (write_open && (NULL == bufin_read))
364 FD_SET (0, &fds_r);
365
366 /*
367 * We are supposed to write and the buffer is not empty
368 * -> select on write to tun
369 */
370 if (write_open && (NULL != bufin_read))
371 FD_SET (fd_tun, &fds_w);
372
373 int r = select (fd_tun + 1, &fds_r, &fds_w, NULL, NULL);
374
375 if (-1 == r)
376 {
377 if (EINTR == errno)
378 continue;
379 fprintf (stderr, "select failed: %s\n", strerror (errno));
380 exit (1);
381 }
382
383 if (r > 0)
384 {
385 if (FD_ISSET (fd_tun, &fds_r))
386 {
387 buftun_size =
388 read (fd_tun, buftun + sizeof (struct GNUNET_MessageHeader),
389 MAX_SIZE - sizeof (struct GNUNET_MessageHeader));
390 if (-1 == buftun_size)
391 {
392 fprintf (stderr, "read-error: %s\n", strerror (errno));
393 shutdown (fd_tun, SHUT_RD);
394 shutdown (1, SHUT_WR);
395 read_open = 0;
396 buftun_size = 0;
397 }
398 else if (0 == buftun_size)
399 {
400 fprintf (stderr, "EOF on tun\n");
401 shutdown (fd_tun, SHUT_RD);
402 shutdown (1, SHUT_WR);
403 read_open = 0;
404 buftun_size = 0;
405 }
406 else
407 {
408 buftun_read = buftun;
409 struct GNUNET_MessageHeader *hdr =
410 (struct GNUNET_MessageHeader *) buftun;
411 buftun_size += sizeof (struct GNUNET_MessageHeader);
412 hdr->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
413 hdr->size = htons (buftun_size);
414 }
415 }
416 else if (FD_ISSET (1, &fds_w))
417 {
418 ssize_t written = write (1, buftun_read, buftun_size);
419
420 if (-1 == written)
421 {
422 fprintf (stderr, "write-error to stdout: %s\n", strerror (errno));
423 shutdown (fd_tun, SHUT_RD);
424 shutdown (1, SHUT_WR);
425 read_open = 0;
426 buftun_size = 0;
427 }
428 else if (0 == written)
429 {
430 fprintf (stderr, "write returned 0!?\n");
431 exit (1);
432 }
433 else
434 {
435 buftun_size -= written;
436 buftun_read += written;
437 }
438 }
439
440 if (FD_ISSET (0, &fds_r))
441 {
442 bufin_size = read (0, bufin + bufin_rpos, MAX_SIZE - bufin_rpos);
443 if (-1 == bufin_size)
444 {
445 fprintf (stderr, "read-error: %s\n", strerror (errno));
446 shutdown (0, SHUT_RD);
447 shutdown (fd_tun, SHUT_WR);
448 write_open = 0;
449 bufin_size = 0;
450 }
451 else if (0 == bufin_size)
452 {
453 fprintf (stderr, "EOF on stdin\n");
454 shutdown (0, SHUT_RD);
455 shutdown (fd_tun, SHUT_WR);
456 write_open = 0;
457 bufin_size = 0;
458 }
459 else
460 {
461 struct GNUNET_MessageHeader *hdr;
462
463PROCESS_BUFFER:
464 bufin_rpos += bufin_size;
465 if (bufin_rpos < sizeof (struct GNUNET_MessageHeader))
466 continue;
467 hdr = (struct GNUNET_MessageHeader *) bufin;
468 if (ntohs (hdr->type) != GNUNET_MESSAGE_TYPE_VPN_HELPER)
469 {
470 fprintf (stderr, "protocol violation!\n");
471 exit (1);
472 }
473 if (ntohs (hdr->size) > bufin_rpos)
474 continue;
475 bufin_read = bufin + sizeof (struct GNUNET_MessageHeader);
476 bufin_size = ntohs (hdr->size) - sizeof (struct GNUNET_MessageHeader);
477 bufin_rpos -= bufin_size + sizeof (struct GNUNET_MessageHeader);
478 }
479 }
480 else if (FD_ISSET (fd_tun, &fds_w))
481 {
482 ssize_t written = write (fd_tun, bufin_read, bufin_size);
483
484 if (-1 == written)
485 {
486 fprintf (stderr, "write-error to tun: %s\n", strerror (errno));
487 shutdown (0, SHUT_RD);
488 shutdown (fd_tun, SHUT_WR);
489 write_open = 0;
490 bufin_size = 0;
491 }
492 else if (0 == written)
493 {
494 fprintf (stderr, "write returned 0!?\n");
495 exit (1);
496 }
497 else
498 {
499 bufin_size -= written;
500 bufin_read += written;
501 if (0 == bufin_size)
502 {
503 memmove (bufin, bufin_read, bufin_rpos);
504 bufin_read = NULL; /* start reading again */
505 bufin_size = 0;
506 goto PROCESS_BUFFER;
507 }
508 }
509 }
510 }
511 }
512}
513
514
515/**
516 * Open VPN tunnel interface.
517 *
518 * @param argc must be 6
519 * @param argv 0: binary name (gnunet-helper-vpn)
520 * 1: tunnel interface name (gnunet-vpn)
521 * 2: IPv6 address (::1)
522 * 3: IPv6 netmask length in bits (64)
523 * 4: IPv4 address (1.2.3.4)
524 * 5: IPv4 netmask (255.255.0.0)
525 */
526int
527main (int argc, char **argv)
528{
529 char dev[IFNAMSIZ];
530 int fd_tun;
531 int global_ret;
532
533 if (6 != argc)
534 {
535 fprintf (stderr, "Fatal: must supply 5 arguments!\n");
536 return 1;
537 }
538
539 strncpy (dev, argv[1], IFNAMSIZ);
540 dev[IFNAMSIZ - 1] = '\0';
541
542 if (-1 == (fd_tun = init_tun (dev)))
543 {
544 fprintf (stderr, "Fatal: could not initialize tun-interface\n");
545 return 1;
546 }
547
548 {
549 const char *address = argv[2];
550 long prefix_len = atol (argv[3]);
551
552 if ((prefix_len < 1) || (prefix_len > 127))
553 {
554 fprintf (stderr, "Fatal: prefix_len out of range\n");
555 return 1;
556 }
557
558 set_address6 (dev, address, prefix_len);
559 }
560
561 {
562 const char *address = argv[4];
563 const char *mask = argv[5];
564
565 set_address4 (dev, address, mask);
566 }
567
568 uid_t uid = getuid ();
569#ifdef HAVE_SETRESUID
570 if (0 != setresuid (uid, uid, uid))
571 {
572 fprintf (stderr, "Failed to setresuid: %s\n", strerror (errno));
573 global_ret = 2;
574 goto cleanup;
575 }
576#else
577 if (0 != (setuid (uid) | seteuid (uid)))
578 {
579 fprintf (stderr, "Failed to setuid: %s\n", strerror (errno));
580 global_ret = 2;
581 goto cleanup;
582 }
583#endif
584
585 if (SIG_ERR == signal (SIGPIPE, SIG_IGN))
586 {
587 fprintf (stderr, "Failed to protect against SIGPIPE: %s\n",
588 strerror (errno));
589 /* no exit, we might as well die with SIGPIPE should it ever happen */
590 }
591 run (fd_tun);
592 global_ret = 0;
593 cleanup:
594 close (fd_tun);
595 return global_ret;
596}
diff --git a/src/vpn/vpn.conf b/src/vpn/vpn.conf
index 7b7ff2788..149a25703 100644
--- a/src/vpn/vpn.conf
+++ b/src/vpn/vpn.conf
@@ -9,14 +9,3 @@ VIRTDNS = 10.11.10.2
9VIRTDNS6 = 1234::17 9VIRTDNS6 = 1234::17
10IFNAME = vpn-gnunet 10IFNAME = vpn-gnunet
11 11
12[exit]
13CONFIG = $DEFAULTCONFIG
14BINARY = gnunet-daemon-exit
15IPV6ADDR = 1234:1::1
16IPV6PREFIX = 32
17IPV4ADDR = 10.10.1.1
18IPV4MASK = 255.255.0.0
19IFNAME = exit-gnunet
20ENABLE_UDP = NO
21ENABLE_TCP = NO
22