2 This file is part of GNUnet.
3 (C) 2010, 2012 Christian Grothoff
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.
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.
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.
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
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>
37 /* see http://www.iana.org/assignments/ethernet-numbers */
39 #define ETH_P_IPV4 0x0800
43 #define ETH_P_IPV6 0x86DD
47 GNUNET_NETWORK_STRUCT_BEGIN
49 * Header from Linux TUN interface.
54 * Some flags (unused).
59 * Here we get an ETH_P_-number.
65 * Standard IPv4 header.
69 unsigned header_length:4 GNUNET_PACKED;
70 unsigned version:4 GNUNET_PACKED;
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;
78 uint16_t checksum GNUNET_PACKED;
79 struct in_addr source_address GNUNET_PACKED;
80 struct in_addr destination_address GNUNET_PACKED;
84 * Standard IPv6 header.
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;
95 struct in6_addr source_address GNUNET_PACKED;
96 struct in6_addr destination_address GNUNET_PACKED;
99 #define TCP_FLAG_SYN 2
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;
120 uint16_t spt GNUNET_PACKED;
121 uint16_t dpt GNUNET_PACKED;
122 uint16_t len GNUNET_PACKED;
123 uint16_t crc GNUNET_PACKED;
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;
138 GNUNET_NETWORK_STRUCT_END
141 * Information about a remote address.
146 * AF_INET or AF_INET6.
151 * Remote address information.
156 * Address, if af is AF_INET.
161 * Address, if af is AF_INET6.
163 struct in6_addr ipv6;
167 * Remote port, in host byte order!
172 * IPPROTO_TCP or IPPROTO_UDP;
179 * This struct is saved into the services-hashmap
181 struct redirect_service
185 * Remote address to use for the service.
187 struct remote_addr address;
190 * Descriptor for this service (also key of this entry in the service hash map).
192 GNUNET_HashCode desc;
195 * Port I am listening on within GNUnet for this service, in host byte order.
202 * Information we use to track a connection.
208 * Address information for the other party.
210 struct remote_addr remote_address;
213 * The source-port of this connection, in host byte order
215 uint16_t source_port;
220 * This struct is saved into {tcp,udp}_connections;
222 struct redirect_state
225 * Mesh tunnel that is used for this connection.
227 struct GNUNET_MESH_Tunnel *tunnel;
230 * Heap node for this state in the connections_heap.
232 struct GNUNET_CONTAINER_HeapNode *heap_node;
235 * Key this state has in the connections_map.
237 GNUNET_HashCode state_key;
240 * Associated service record, or NULL for no service.
242 struct redirect_service *serv;
245 * Source port we use for this connection. FIXME: needed? used?
247 uint16_t source_port__;
252 * Queue of messages to a tunnel.
254 struct tunnel_notify_queue
257 * This is a doubly-linked list.
259 struct tunnel_notify_queue *next;
262 * This is a doubly-linked list.
264 struct tunnel_notify_queue *prev;
267 * Payload to send via the tunnel.
272 * Number of bytes in 'cls'.
279 * Information we track per mesh tunnel.
283 struct tunnel_notify_queue *head;
284 struct tunnel_notify_queue *tail;
285 struct GNUNET_MESH_TransmitHandle *th;
286 struct GNUNET_MESH_Tunnel *tunnel;
291 * The handle to the configuration used throughout the process
293 static const struct GNUNET_CONFIGURATION_Handle *cfg;
296 * The handle to the helper
298 static struct GNUNET_HELPER_Handle *helper_handle;
301 * Arguments to the exit helper.
303 static char *exit_argv[7];
306 * IPv6 prefix (0..127) from configuration file.
308 static unsigned long long ipv6prefix;
318 static struct GNUNET_MESH_Handle *mesh_handle;
321 * This hashmaps contains the mapping from peer, service-descriptor,
322 * source-port and destination-port to a struct redirect_state
324 static struct GNUNET_CONTAINER_MultiHashMap *connections_map;
327 * Heap so we can quickly find "old" connections.
329 static struct GNUNET_CONTAINER_Heap *connections_heap;
332 * If there are at least this many connections, old ones will be removed
334 static long long unsigned int max_connections = 200;
337 * This hashmaps saves interesting things about the configured UDP services
339 static struct GNUNET_CONTAINER_MultiHashMap *udp_services;
342 * This hashmaps saves interesting things about the configured TCP services
344 static struct GNUNET_CONTAINER_MultiHashMap *tcp_services;
348 * Given IP information about a connection, calculate the respective
349 * hash we would use for the 'connections_map'.
351 * @param hash resulting hash
352 * @param ri information about the connection
355 hash_redirect_info (GNUNET_HashCode * hash,
356 const struct redirect_info *ri)
360 memset (hash, 0, sizeof (GNUNET_HashCode));
361 /* the GNUnet hashmap only uses the first sizeof(unsigned int) of the hash */
363 switch (ri->remote_address.af)
366 memcpy (off, &ri->remote_address.address.ipv4, sizeof (struct in_addr));
367 off += sizeof (struct in_addr);
370 memcpy (off, &ri->remote_address.address.ipv6, sizeof (struct in6_addr));
371 off += sizeof (struct in_addr);
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));
383 * Given a service descriptor and a destination port, find the
384 * respective service entry.
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
391 struct redirect_service *
392 find_service (struct GNUNET_CONTAINER_MultiHashMap *service_map,
393 const GNUNET_HashCode *desc,
396 char key[sizeof (GNUNET_HashCode) + sizeof (uint16_t)];
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);
406 * Free memory associated with a service record.
409 * @param key service descriptor
410 * @param value service record to free
414 free_service_record (void *cls,
415 const GNUNET_HashCode *key,
418 struct redirect_service *service = value;
420 GNUNET_free (service);
426 * Given a service descriptor and a destination port, find the
427 * respective service entry.
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).
435 store_service (struct GNUNET_CONTAINER_MultiHashMap *service_map,
438 struct redirect_service *service)
440 char key[sizeof (GNUNET_HashCode) + sizeof (uint16_t)];
441 GNUNET_HashCode desc;
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));
448 GNUNET_CONTAINER_multihashmap_put (service_map,
449 (GNUNET_HashCode *) key,
451 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
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"),
463 * MESH is ready to receive a message for the tunnel. Transmit it.
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
471 send_to_peer_notify_callback (void *cls, size_t size, void *buf)
473 struct tunnel_state *s = cls;
474 struct GNUNET_MESH_Tunnel *tunnel = s->tunnel;
475 struct tunnel_notify_queue *tnq;
479 GNUNET_assert (size >= tnq->len);
480 memcpy (buf, tnq->payload, tnq->len);
482 GNUNET_CONTAINER_DLL_remove (s->head,
486 if (NULL != (tnq = s->head))
487 s->th = GNUNET_MESH_notify_transmit_ready (tunnel,
488 GNUNET_NO /* corking */,
490 GNUNET_TIME_UNIT_FOREVER_REL,
493 &send_to_peer_notify_callback,
500 * Send the given packet via the mesh tunnel.
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
509 send_packet_to_mesh_tunnel (struct GNUNET_MESH_Tunnel *mesh_tunnel,
511 size_t payload_length,
512 const GNUNET_HashCode *desc,
515 struct tunnel_state *s;
516 struct tunnel_notify_queue *tnq;
517 struct GNUNET_MessageHeader *msg;
521 len = sizeof (struct GNUNET_MessageHeader) + sizeof (GNUNET_HashCode) + payload_length;
522 if (len >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
527 tnq = GNUNET_malloc (sizeof (struct tunnel_notify_queue) + len);
528 tnq->payload = &tnq[1];
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];
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);
540 s->th = GNUNET_MESH_notify_transmit_ready (mesh_tunnel, GNUNET_NO /* cork */, 0 /* priority */,
541 GNUNET_TIME_UNIT_FOREVER_REL,
543 &send_to_peer_notify_callback,
549 * Get our connection tracking state. Warns if it does not exists,
550 * refreshes the timestamp if it does exist.
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
559 static struct redirect_state *
560 get_redirect_state (int af,
562 const void *destination_ip,
563 uint16_t destination_port,
564 uint16_t source_port)
566 struct redirect_info ri;
567 GNUNET_HashCode state_key;
568 struct redirect_state *state;
570 ri.remote_address.af = af;
572 ri.remote_address.address.ipv4 = *((struct in_addr*) destination_ip);
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;
579 hash_redirect_info (&state_key, &ri);
580 state = GNUNET_CONTAINER_multihashmap_get (connections_map, &state_key);
583 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
584 _("Packet dropped, have no matching connection information\n"));
587 /* Mark this connection as freshly used */
588 GNUNET_CONTAINER_heap_update_cost (connections_heap,
590 GNUNET_TIME_absolute_get ().abs_value);
596 * @brief Handles an UDP packet received from the helper.
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)
604 udp_from_helper (const struct udp_packet *udp,
606 const void *destination_ip, int af)
608 struct redirect_state *state;
609 struct GNUNET_MESH_Tunnel *tunnel;
610 GNUNET_HashCode desc;
612 if (pktlen < sizeof (struct udp_packet))
618 if (pktlen != ntohs (udp->len))
624 state = get_redirect_state (af, IPPROTO_UDP,
630 tunnel = state->tunnel;
634 if (state->type == SERVICE)
636 /* check if spt == serv.remote if yes: set spt = serv.myport ("nat") */
637 if (ntohs (udp->spt) == state->serv->remote_port)
639 udp->spt = htons (state->serv->my_port);
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
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);
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,
661 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
667 if (state->type == SERVICE)
668 memcpy (&desc, &state->desc, sizeof (GNUNET_HashCode));
670 memcpy (&desc, &state->remote, sizeof (struct remote_addr));
672 memset (&desc, 0, sizeof (desc));
675 /* send udp-packet back */
676 send_packet_to_mesh_tunnel (tunnel,
680 ? GNUNET_MESSAGE_TYPE_VPN_SERVICE_UDP_BACK
681 : GNUNET_MESSAGE_TYPE_VPN_REMOTE_UDP_BACK);
686 * @brief Handles a TCP packet received from the helper.
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)
694 tcp_from_helper (const struct tcp_packet *tcp,
696 const void *destination_ip, int af)
698 struct redirect_state *state;
699 struct GNUNET_MESH_Tunnel *tunnel;
700 GNUNET_HashCode desc;
702 if (pktlen < sizeof (struct tcp_packet))
708 state = get_redirect_state (af, IPPROTO_TCP,
714 tunnel = state->tunnel;
718 if (state->type == SERVICE)
720 /* check if spt == serv.remote if yes: set spt = serv.myport ("nat") */
721 if (ntohs (tcp->spt) == state->serv->remote_port)
723 tcp->spt = htons (state->serv->my_port);
727 // This is an illegal packet.
732 /* send tcp-packet back */
733 if (state->type == SERVICE)
734 memcpy (&desc, &state->desc, sizeof (GNUNET_HashCode));
736 memcpy (&desc, &state->remote, sizeof (struct remote_addr));
738 memset (&desc, 0, sizeof (desc));
742 send_packet_to_mesh_tunnel (tunnel,
746 ? GNUNET_MESSAGE_TYPE_VPN_SERVICE_TCP_BACK
747 : GNUNET_MESSAGE_TYPE_VPN_REMOTE_TCP_BACK);
752 * Receive packets from the helper-process
755 * @param client unsued
756 * @param message message received from helper
759 message_token (void *cls GNUNET_UNUSED, void *client GNUNET_UNUSED,
760 const struct GNUNET_MessageHeader *message)
762 const struct tun_header *pkt_tun;
765 if (ntohs (message->type) != GNUNET_MESSAGE_TYPE_VPN_HELPER)
770 size = ntohs (message->size);
771 if (size < sizeof (struct tun_header) + sizeof (struct GNUNET_MessageHeader))
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))
782 const struct ip6_header *pkt6;
784 if (size < sizeof (struct ip6_header))
786 /* Kernel to blame? */
790 pkt6 = (struct ip6_header *) &pkt_tun[1];
791 if (size != ntohs (pkt6->payload_length))
793 /* Kernel to blame? */
797 size -= sizeof (struct ip6_header);
798 switch (pkt6->next_header)
801 udp_from_helper ( (const struct udp_packet *) &pkt6[1], size,
802 &pkt6->destination_address,
806 tcp_from_helper ((const struct tcp_packet *) &pkt6[1], size,
807 &pkt6->destination_address,
811 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
812 _("IPv6 packet with unsupported next header received. Ignored.\n"));
819 const struct ip4_header *pkt4;
821 if (size < sizeof (struct ip4_header))
823 /* Kernel to blame? */
827 pkt4 = (const struct ip4_header *) &pkt_tun[1];
828 if (size != ntohs (pkt4->total_length))
830 /* Kernel to blame? */
834 if (pkt4->header_length * 4 != sizeof (struct ip4_header))
836 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
837 _("IPv4 packet options received. Ignored.\n"));
840 size -= sizeof (struct ip4_header);
841 switch (pkt4->protocol)
844 udp_from_helper ((const struct udp_packet *) &pkt4[1], size,
845 &pkt4->destination_address, AF_INET);
848 tcp_from_helper ((const struct tcp_packet *) &pkt4[1], size,
849 &pkt4->destination_address, AF_INET);
852 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
853 _("IPv4 packet with unsupported next header received. Ignored.\n"));
859 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
860 _("Packet from unknown protocol %u received. Ignored.\n"),
861 ntohs (pkt_tun->proto));
870 prepare_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)
874 const char *ipv4addr = exit_argv[4];
875 const char *ipv4mask = exit_argv[5];
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);
883 pkt4->header_length = sizeof (struct ip4_header) / 4;
885 pkt4->total_length = htons (sizeof (struct ip4_header) + pktlen);
886 pkt4->identification = 0; // FIXME!
888 pkt4->fragmentation_offset = 0;
890 pkt4->protocol = protocol;
891 pkt4->checksum = 0; /* Will be calculated later */
893 memcpy (&pkt4->destination_address, ipaddress, sizeof (struct in_addr));
895 /* Generate a new src-address -- FIXME: not always, right!? */
897 /* This should be a noop */
899 tmp |= ntohl (*((uint32_t *) tunnel)) & (~tmp2);
901 pkt4->source_address.s_addr = tmp;
902 pkt4->checksum = GNUNET_CRYPTO_crc16_n (pkt4, sizeof (struct ip4_header));
904 // FIXME: memcpy (&state->addr, &tmp, 4);
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 */
917 struct tcp_packet *pkt4_tcp = (struct tcp_packet *) &pkt4[1];
919 // FIXME: state->pt = pkt4_tcp->spt;
922 sum = GNUNET_CRYPTO_crc16_step (sum,
923 &pkt4->source_address,
924 sizeof (struct in_addr) * 2);
925 tmp = (protocol << 16) | (0xffff & pktlen);
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);
939 prepare_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)
943 const char *ipv6addr = exit_argv[2];
947 memcpy (&pkt6[1], payload, pktlen);
950 pkt6->next_header = protocol;
951 pkt6->payload_length = htons (pktlen);
952 pkt6->hop_limit = 64;
954 memcpy (&pkt6->destination_address, ipaddress, sizeof (struct in6_addr));
956 /* Generate a new src-address
957 * This takes as much from the address of the tunnel as fits into
960 unsigned long long ipv6prefix_r = (ipv6prefix + 7) / 8;
962 inet_pton (AF_INET6, ipv6addr, &pkt6->source_address);
964 if (ipv6prefix_r < (16 - sizeof (void *)))
965 ipv6prefix_r = 16 - sizeof (void *);
967 unsigned int offset = ipv6prefix_r - (16 - sizeof (void *));
969 memcpy ((((char *) &pkt6->source_address)) + ipv6prefix_r,
970 ((char *) &tunnel) + offset, 16 - ipv6prefix_r);
972 /* copy the needed information into the state */
973 // FIXME: memcpy (&state->addr, &pkt6->source_address, 16);
979 struct udp_packet *pkt6_udp = (struct udp_packet *) &pkt6[1];
981 // FIXME: state->pt = pkt6_udp->spt;
985 GNUNET_CRYPTO_crc16_step (sum, & pkt6->source_address,
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);
992 GNUNET_CRYPTO_crc16_step (sum, pkt6_udp,
993 ntohs (pkt6_udp->len));
994 pkt6_udp->crc = GNUNET_CRYPTO_crc16_finish (sum);
999 struct tcp_packet *pkt6_tcp = (struct tcp_packet *) pkt6;
1001 // FIXME: state->pt = pkt6_tcp->spt;
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);
1013 GNUNET_CRYPTO_crc16_step (sum, pkt6_tcp,
1014 ntohs (pkt6->payload_length));
1015 pkt6_tcp->crc = GNUNET_CRYPTO_crc16_finish (sum);
1026 * We've just experienced a connection in use. Track it, or if it is
1027 * already tracked, update the tracking.
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
1035 update_state_map (const struct redirect_info *ri,
1036 struct GNUNET_MESH_Tunnel *tunnel,
1037 const GNUNET_HashCode *desc,
1038 struct redirect_service *serv)
1040 struct redirect_state *state;
1041 GNUNET_HashCode state_key;
1043 hash_redirect_info (&state_key,
1045 state = GNUNET_CONTAINER_multihashmap_get (connections_map, &state_key);
1048 state = GNUNET_malloc (sizeof (struct redirect_state));
1049 state->tunnel = tunnel;
1050 state->state_key = state_key;
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));
1058 GNUNET_CONTAINER_heap_insert (connections_heap,
1060 GNUNET_TIME_absolute_get ().abs_value);
1064 if (state->tunnel != tunnel)
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"));
1071 GNUNET_CONTAINER_heap_update_cost (connections_heap,
1073 GNUNET_TIME_absolute_get ().abs_value);
1075 while (GNUNET_CONTAINER_heap_get_size (connections_heap) > max_connections)
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,
1084 GNUNET_free (state);
1092 * The messages are one GNUNET_HashCode for the service followed by a struct tcp_packet
1095 receive_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)
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;
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))
1112 GNUNET_break_op (0);
1115 pkt_len -= (sizeof (struct GNUNET_MessageHeader) + sizeof (GNUNET_HashCode));
1117 if (NULL == (serv = find_service (tcp_services, desc, ntohs (pkt->dpt))))
1119 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1120 _("No service found for %s on port %d!\n"),
1125 pkt->dpt = htons (serv->remote_port);
1127 /* At this point it would be possible to check against some kind of ACL. */
1129 switch (serv->version)
1134 sizeof (struct GNUNET_MessageHeader) + sizeof (struct tun_header) +
1135 sizeof (struct ip4_header) + pkt_len;
1137 struct tun_header *hdr;
1138 struct GNUNET_MessageHeader *mhdr;
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);
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,
1159 sizeof (struct GNUNET_MessageHeader) + sizeof (struct tun_header) +
1160 sizeof (struct ip6_header) + pkt_len;
1162 struct tun_header *hdr;
1163 struct GNUNET_MessageHeader *mhdr;
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);
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,
1188 update_state_map (&u_i, desc, tunnel, serv);
1195 receive_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)
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;
1209 ntohs (message->size) - sizeof (struct GNUNET_MessageHeader) -
1210 sizeof (GNUNET_HashCode);
1212 struct redirect_state *state = GNUNET_malloc (sizeof (struct redirect_state));
1214 state->tunnel = tunnel;
1215 state->type = REMOTE;
1216 state->hashmap = tcp_connections;
1217 memcpy (&state->remote, s, sizeof (struct remote_addr));
1219 hash_redirect_info (&state->hash, &state->redirect_info, s->addrlen);
1222 GNUNET_CONTAINER_multihashmap_contains (tcp_connections, &state->hash))
1224 GNUNET_CONTAINER_multihashmap_put (tcp_connections, &state->hash, state,
1225 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
1228 GNUNET_CONTAINER_heap_insert (tcp_connections_heap, state,
1229 GNUNET_TIME_absolute_get ().abs_value);
1231 if (GNUNET_CONTAINER_heap_get_size (tcp_connections_heap) >
1232 max_tcp_connections)
1233 GNUNET_SCHEDULER_add_now (collect_connections, tcp_connections_heap);
1236 GNUNET_free (state);
1241 sizeof (struct GNUNET_MessageHeader) + sizeof (struct pkt_tun) +
1242 sizeof (struct ip6_hdr) + pkt_len;
1245 memset (buf, 0, len);
1250 prepare_ipv4_packet (len, pkt_len, pkt, IPPROTO_TCP, &s->addr, tunnel,
1251 state, (struct ip4_header *) buf);
1254 prepare_ipv6_packet (len, pkt_len, pkt, IPPROTO_TCP, &s->addr, tunnel,
1255 state, (struct ip6_header *) buf);
1258 GNUNET_free (state);
1259 return GNUNET_SYSERR;
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,
1273 receive_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)
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;
1287 GNUNET_assert (ntohs (pkt->len) ==
1288 ntohs (message->size) - sizeof (struct GNUNET_MessageHeader) -
1289 sizeof (GNUNET_HashCode));
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.
1295 struct redirect_state *state = GNUNET_malloc (sizeof (struct redirect_state));
1297 state->tunnel = tunnel;
1298 state->hashmap = udp_connections;
1299 state->type = REMOTE;
1300 memcpy (&state->remote, s, sizeof (struct remote_addr));
1303 sizeof (struct GNUNET_MessageHeader) + sizeof (struct pkt_tun) +
1304 sizeof (struct ip6_hdr) + ntohs (pkt->len);
1307 memset (buf, 0, len);
1312 prepare_ipv4_packet (len, ntohs (pkt->len), pkt, IPPROTO_UDP, &s->addr,
1313 tunnel, state, (struct ip4_header *) buf);
1316 prepare_ipv6_packet (len, ntohs (pkt->len), pkt, IPPROTO_UDP, &s->addr,
1317 tunnel, state, (struct ip6_header *) buf);
1324 hash_redirect_info (&state->hash, &state->redirect_info, s->addrlen);
1326 (void) GNUNET_HELPER_send (helper_handle,
1327 (const struct GNUNET_MessageHeader*) buf,
1333 GNUNET_CONTAINER_multihashmap_contains (udp_connections, &state->hash))
1335 GNUNET_CONTAINER_multihashmap_put (udp_connections, &state->hash, state,
1336 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
1339 GNUNET_CONTAINER_heap_insert (udp_connections_heap, state,
1340 GNUNET_TIME_absolute_get ().abs_value);
1342 if (GNUNET_CONTAINER_heap_get_size (udp_connections_heap) >
1343 max_udp_connections)
1344 GNUNET_SCHEDULER_add_now (collect_connections, udp_connections_heap);
1347 GNUNET_free (state);
1353 * The messages are one GNUNET_HashCode for the service, followed by a struct udp_packet
1356 receive_udp_service (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel,
1358 const struct GNUNET_PeerIdentity *sender GNUNET_UNUSED,
1359 const struct GNUNET_MessageHeader *message,
1360 const struct GNUNET_ATS_Information *atsi GNUNET_UNUSED)
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;
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))
1372 GNUNET_break_op (0);
1375 pkt_len -= (sizeof (struct GNUNET_MessageHeader) + sizeof (GNUNET_HashCode));
1377 GNUNET_assert (ntohs (pkt->len) ==
1378 ntohs (message->size) - sizeof (struct GNUNET_MessageHeader) -
1379 sizeof (GNUNET_HashCode));
1381 if (NULL == (serv = find_service (udp_services, desc, ntohs (pkt->dpt))))
1383 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1384 _("No service found for %s on port %d!\n"),
1389 pkt->dpt = htons (serv->remote_port);
1392 * At this point it would be possible to check against some kind of ACL.
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.
1402 struct redirect_state *state = GNUNET_malloc (sizeof (struct redirect_state));
1404 state->tunnel = tunnel;
1406 state->type = SERVICE;
1407 state->hashmap = udp_connections;
1408 memcpy (&state->desc, desc, sizeof (GNUNET_HashCode));
1411 sizeof (struct GNUNET_MessageHeader) + sizeof (struct pkt_tun) +
1412 sizeof (struct ip6_hdr) + ntohs (pkt->len);
1415 memset (buf, 0, len);
1417 switch (serv->version)
1420 prepare_ipv4_packet (len, ntohs (pkt->len), pkt, IPPROTO_UDP,
1421 &serv->v4.ip4address, tunnel, state,
1422 (struct ip4_header *) buf);
1425 prepare_ipv6_packet (len, ntohs (pkt->len), pkt, IPPROTO_UDP,
1426 &serv->v6.ip6address, tunnel, state,
1427 (struct ip6_header *) buf);
1435 hash_redirect_info (&state->hash, &state->redirect_info,
1436 serv->version == 4 ? 4 : 16);
1439 GNUNET_CONTAINER_multihashmap_contains (udp_connections, &state->hash))
1441 GNUNET_CONTAINER_multihashmap_put (udp_connections, &state->hash, state,
1442 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
1445 GNUNET_CONTAINER_heap_insert (udp_connections_heap, state,
1446 GNUNET_TIME_absolute_get ().abs_value);
1448 if (GNUNET_CONTAINER_heap_get_size (udp_connections_heap) >
1449 max_udp_connections)
1450 GNUNET_SCHEDULER_add_now (collect_connections, udp_connections_heap);
1453 GNUNET_free (state);
1455 (void) GNUNET_HELPER_send (helper_handle,
1456 (const struct GNUNET_MessageHeader*) buf,
1470 * Callback from GNUNET_MESH for new tunnels.
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
1479 new_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)
1483 struct tunnel_state *s = GNUNET_malloc (sizeof (struct tunnel_state));
1491 * Function called by mesh whenever an inbound tunnel is destroyed.
1492 * Should clean up any associated state.
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
1500 clean_tunnel (void *cls GNUNET_UNUSED, const struct GNUNET_MESH_Tunnel *tunnel,
1503 struct tunnel_state *s = tunnel_ctx;
1504 struct tunnel_notify_queue *tnq;
1506 while (NULL != (tnq = s->head))
1508 GNUNET_CONTAINER_DLL_remove (s->head,
1515 GNUNET_MESH_notify_transmit_ready_cancel (s->th);
1523 * Function that frees everything from a hashmap
1527 * @param value value to free
1530 free_iterate (void *cls GNUNET_UNUSED,
1531 const GNUNET_HashCode * hash GNUNET_UNUSED, void *value)
1533 GNUNET_free (value);
1539 * Function scheduled as very last function, cleans up after us
1542 cleanup (void *cls GNUNET_UNUSED,
1543 const struct GNUNET_SCHEDULER_TaskContext *tskctx)
1547 if (helper_handle != NULL)
1549 GNUNET_HELPER_stop (helper_handle);
1550 helper_handle = NULL;
1552 if (mesh_handle != NULL)
1554 GNUNET_MESH_disconnect (mesh_handle);
1557 if (NULL != connections_map)
1559 GNUNET_CONTAINER_multihashmap_iterate (connections_map, &free_iterate, NULL);
1560 GNUNET_CONTAINER_multihashmap_destroy (connections_map);
1561 connections_map = NULL;
1563 if (NULL != connections_heap)
1565 GNUNET_CONTAINER_heap_destroy (connections_heap);
1566 connections_heap = NULL;
1568 if (NULL != tcp_services)
1570 GNUNET_CONTAINER_multihashmap_iterate (tcp_services, &free_service_record, NULL);
1571 GNUNET_CONTAINER_multihashmap_destroy (tcp_services);
1572 tcp_services = NULL;
1574 if (NULL != udp_services)
1576 GNUNET_CONTAINER_multihashmap_iterate (udp_services, &free_service_record, NULL);
1577 GNUNET_CONTAINER_multihashmap_destroy (udp_services);
1578 udp_services = NULL;
1581 GNUNET_free_non_null (exit_argv[i]);
1586 * Add services to the service map.
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
1593 add_services (int proto,
1600 struct redirect_service *serv;
1602 for (redirect = strtok (cpy, " "); redirect != NULL;
1603 redirect = strtok (NULL, " "))
1605 if (NULL == (hostname = strstr (redirect, ":")))
1607 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1608 "option `%s' for domain `%s' is not formatted correctly!\n",
1615 if (NULL == (hostport = strstr (hostname, ":")))
1617 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1618 "option `%s' for domain `%s' is not formatted correctly!\n",
1626 int local_port = atoi (redirect);
1627 int remote_port = atoi (hostport);
1629 if (!((local_port > 0) && (local_port < 65536)))
1631 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1632 "`%s' is not a valid port number (for domain `%s')!", redirect,
1636 if (!((remote_port > 0) && (remote_port < 65536)))
1638 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1639 "`%s' is not a valid port number (for domain `%s')!", hostport,
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))
1649 const char *ip4addr = exit_argv[4];
1651 serv->address.af = AF_INET;
1652 GNUNET_assert (1 != inet_pton (AF_INET, ip4addr, &serv->address.address.ipv4));
1654 else if (0 == strcmp ("localhost6", hostname))
1656 const char *ip6addr = exit_argv[2];
1658 serv->address.af = AF_INET6;
1659 GNUNET_assert (1 == inet_pton (AF_INET6, ip6addr, &serv->address.address.ipv6));
1663 struct addrinfo *res;
1666 ret = getaddrinfo (hostname, NULL, NULL, &res);
1667 if ( (ret != 0) || (res == NULL) )
1669 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1670 _("No addresses found for hostname `%s' of service `%s'!\n"),
1677 serv->address.af = res->ai_family;
1678 switch (res->ai_family)
1681 serv->address.address.ipv4 = ((struct sockaddr_in *) res->ai_addr)->sin_addr;
1684 serv->address.address.ipv6 = ((struct sockaddr_in6 *) res->ai_addr)->sin6_addr;
1688 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1689 _("No IP addresses found for hostname `%s' of service `%s'!\n"),
1697 store_service ((IPPROTO_UDP == proto) ? udp_services : tcp_services,
1706 * Reads the configuration servicecfg and populates udp_services
1709 * @param section name of section in config, equal to hostname
1712 read_service_conf (void *cls GNUNET_UNUSED, const char *section)
1716 if ((strlen (section) < 8) ||
1717 (0 != strcmp (".gnunet.", section + (strlen (section) - 8))))
1720 GNUNET_CONFIGURATION_get_value_string (cfg, section, "UDP_REDIRECTS",
1723 add_services (IPPROTO_UDP, cpy, section);
1727 GNUNET_CONFIGURATION_get_value_string (cfg, section, "TCP_REDIRECTS",
1730 add_services (IPPROTO_TCP, cpy, section);
1737 * @brief Main function that will be run by the scheduler.
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
1745 run (void *cls, char *const *args GNUNET_UNUSED,
1746 const char *cfgfile GNUNET_UNUSED,
1747 const struct GNUNET_CONFIGURATION_Handle *cfg_)
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},
1757 static GNUNET_MESH_ApplicationType apptypes[] = {
1758 GNUNET_APPLICATION_TYPE_END,
1759 GNUNET_APPLICATION_TYPE_END,
1760 GNUNET_APPLICATION_TYPE_END
1762 unsigned int handler_idx;
1763 unsigned int app_idx;
1775 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &cleanup, cls);
1777 GNUNET_CONFIGURATION_get_value_number (cfg, "exit", "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))
1784 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1785 "No entry 'IFNAME' in configuration!\n");
1786 GNUNET_SCHEDULER_shutdown ();
1789 exit_argv[1] = ifname;
1790 if ( (GNUNET_SYSERR ==
1791 GNUNET_CONFIGURATION_get_value_string (cfg, "exit", "IPV6ADDR",
1793 (1 != inet_pton (AF_INET6, ipv6addr, &v6))) )
1795 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1796 "No valid entry 'IPV6ADDR' in configuration!\n");
1797 GNUNET_SCHEDULER_shutdown ();
1800 exit_argv[2] = ipv6addr;
1801 if (GNUNET_SYSERR ==
1802 GNUNET_CONFIGURATION_get_value_string (cfg, "exit", "IPV6PREFIX",
1805 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1806 "No entry 'IPV6PREFIX' in configuration!\n");
1807 GNUNET_SCHEDULER_shutdown ();
1810 exit_argv[3] = ipv6prefix_s;
1812 GNUNET_CONFIGURATION_get_value_number (cfg, "exit",
1815 (ipv6prefix >= 127) )
1817 GNUNET_SCHEDULER_shutdown ();
1821 if ( (GNUNET_SYSERR ==
1822 GNUNET_CONFIGURATION_get_value_string (cfg, "exit", "IPV4ADDR",
1824 (1 != inet_pton (AF_INET, ipv4addr, &v4))) )
1826 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1827 "No valid entry for 'IPV4ADDR' in configuration!\n");
1828 GNUNET_SCHEDULER_shutdown ();
1831 exit_argv[4] = ipv4addr;
1832 if ( (GNUNET_SYSERR ==
1833 GNUNET_CONFIGURATION_get_value_string (cfg, "exit", "IPV4MASK",
1835 (1 != inet_pton (AF_INET, ipv4mask, &v4))) )
1837 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1838 "No valid entry 'IPV4MASK' in configuration!\n");
1839 GNUNET_SCHEDULER_shutdown ();
1842 exit_argv[5] = ipv4mask;
1843 exit_argv[6] = NULL;
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)
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;
1859 if (GNUNET_YES == tcp)
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;
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);
1872 connections_map = GNUNET_CONTAINER_multihashmap_create (65536);
1873 connections_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
1875 = GNUNET_MESH_connect (cfg, 42 /* queue size */, NULL,
1877 &clean_tunnel, handlers,
1879 if (NULL == mesh_handle)
1881 GNUNET_SCHEDULER_shutdown ();
1884 helper_handle = GNUNET_HELPER_start ("gnunet-helper-vpn",
1886 &message_token, NULL);
1893 * @param argc number of arguments from the command line
1894 * @param argv command line arguments
1895 * @return 0 ok, 1 on error
1898 main (int argc, char *const *argv)
1900 static const struct GNUNET_GETOPT_CommandLineOption options[] = {
1901 GNUNET_GETOPT_OPTION_END
1904 return (GNUNET_OK ==
1905 GNUNET_PROGRAM_run (argc, argv, "gnunet-daemon-exit",
1907 ("Daemon to run to provide an IP exit node for the VPN"),
1908 options, &run, NULL)) ? ret : 1;
1912 /* end of gnunet-daemon-exit.c */