X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=src%2Fexit%2Fgnunet-daemon-exit.c;h=d6f0dadadd25be4684f046dc7ec800fb01dc3705;hb=9b92f989917954c26ff9aef76c105dd89a60f001;hp=7097d71a0ce90c152506b0230bb999d02f1448e9;hpb=79a1640fc8d082b7f61a0b00ee070c8717009a1f;p=oweals%2Fgnunet.git diff --git a/src/exit/gnunet-daemon-exit.c b/src/exit/gnunet-daemon-exit.c index 7097d71a0..d6f0dadad 100644 --- a/src/exit/gnunet-daemon-exit.c +++ b/src/exit/gnunet-daemon-exit.c @@ -25,123 +25,24 @@ * @author Christian Grothoff * * TODO: - * - setup_fresh_address is not implemented - * - various functions are not documented - * - update_state_map is dead, do we need something like it still? - * - need proper message headers for mesh P2P messages - */ -#include -#include -#include -#include -#include -#include -#include -#include - - -/* see http://www.iana.org/assignments/ethernet-numbers */ -#ifndef ETH_P_IPV4 -#define ETH_P_IPV4 0x0800 -#endif - -#ifndef ETH_P_IPV6 -#define ETH_P_IPV6 0x86DD -#endif - - -GNUNET_NETWORK_STRUCT_BEGIN -/** - * Header from Linux TUN interface. - */ -struct tun_header -{ - /** - * Some flags (unused). - */ - uint16_t flags; - - /** - * Here we get an ETH_P_-number. - */ - uint16_t proto; -}; - -/** - * Standard IPv4 header. - */ -struct ip4_header -{ - unsigned header_length:4 GNUNET_PACKED; - unsigned version:4 GNUNET_PACKED; - uint8_t diff_serv; - uint16_t total_length GNUNET_PACKED; - uint16_t identification GNUNET_PACKED; - unsigned flags:3 GNUNET_PACKED; - unsigned fragmentation_offset:13 GNUNET_PACKED; - uint8_t ttl; - uint8_t protocol; - uint16_t checksum GNUNET_PACKED; - struct in_addr source_address GNUNET_PACKED; - struct in_addr destination_address GNUNET_PACKED; -}; - -/** - * Standard IPv6 header. - */ -struct ip6_header -{ - unsigned traffic_class_h:4 GNUNET_PACKED; - unsigned version:4 GNUNET_PACKED; - unsigned traffic_class_l:4 GNUNET_PACKED; - unsigned flow_label:20 GNUNET_PACKED; - uint16_t payload_length GNUNET_PACKED; - uint8_t next_header; - uint8_t hop_limit; - struct in6_addr source_address GNUNET_PACKED; - struct in6_addr destination_address GNUNET_PACKED; -}; - -#define TCP_FLAG_SYN 2 - -struct tcp_packet -{ - unsigned spt:16 GNUNET_PACKED; - unsigned dpt:16 GNUNET_PACKED; - unsigned seq:32 GNUNET_PACKED; - unsigned ack:32 GNUNET_PACKED; - unsigned off:4 GNUNET_PACKED; - unsigned rsv:4 GNUNET_PACKED; - unsigned flg:8 GNUNET_PACKED; - unsigned wsz:16 GNUNET_PACKED; - unsigned crc:16 GNUNET_PACKED; - unsigned urg:16 GNUNET_PACKED; -}; - -/** - * UDP packet header. - */ -struct udp_packet -{ - uint16_t spt GNUNET_PACKED; - uint16_t dpt GNUNET_PACKED; - uint16_t len GNUNET_PACKED; - uint16_t crc GNUNET_PACKED; -}; - -/** - * DNS header. + * - test + * + * Design: + * - which code should advertise services? the service model is right + * now a bit odd, especially as this code DOES the exit and knows + * the DNS "name", but OTOH this is clearly NOT the place to advertise + * the service's existence; maybe the daemon should turn into a + * service with an API to add local-exit services dynamically? */ -struct dns_header -{ - uint16_t id GNUNET_PACKED; - uint16_t flags GNUNET_PACKED; - uint16_t qdcount GNUNET_PACKED; - uint16_t ancount GNUNET_PACKED; - uint16_t nscount GNUNET_PACKED; - uint16_t arcount GNUNET_PACKED; -}; -GNUNET_NETWORK_STRUCT_END +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_protocols.h" +#include "gnunet_applications.h" +#include "gnunet_mesh_service.h" +#include "gnunet_statistics_service.h" +#include "gnunet_constants.h" +#include "gnunet_tun_lib.h" +#include "exit.h" /** * Information about an address. @@ -333,11 +234,32 @@ static struct GNUNET_HELPER_Handle *helper_handle; */ static char *exit_argv[7]; +/** + * IPv6 address of our TUN interface. + */ +static struct in6_addr exit_ipv6addr; + /** * IPv6 prefix (0..127) from configuration file. */ static unsigned long long ipv6prefix; +/** + * IPv4 address of our TUN interface. + */ +static struct in_addr exit_ipv4addr; + +/** + * IPv4 netmask of our TUN interface. + */ +static struct in_addr exit_ipv4mask; + + +/** + * Statistics. + */ +static struct GNUNET_STATISTICS_Handle *stats; + /** * The handle to mesh */ @@ -357,7 +279,7 @@ static struct GNUNET_CONTAINER_Heap *connections_heap; /** * If there are at least this many connections, old ones will be removed */ -static long long unsigned int max_connections = 200; +static long long unsigned int max_connections; /** * This hashmaps saves interesting things about the configured UDP services @@ -369,6 +291,26 @@ static struct GNUNET_CONTAINER_MultiHashMap *udp_services; */ static struct GNUNET_CONTAINER_MultiHashMap *tcp_services; +/** + * Are we an IPv4-exit? + */ +static int ipv4_exit; + +/** + * Are we an IPv6-exit? + */ +static int ipv6_exit; + +/** + * Do we support IPv4 at all on the TUN interface? + */ +static int ipv4_enabled; + +/** + * Do we support IPv6 at all on the TUN interface? + */ +static int ipv6_enabled; + /** * Given IP information about a connection, calculate the respective @@ -591,6 +533,9 @@ send_to_peer_notify_callback (void *cls, size_t size, void *buf) tnq->len, &send_to_peer_notify_callback, s); + GNUNET_STATISTICS_update (stats, + gettext_noop ("# Bytes transmitted via mesh tunnels"), + size, GNUNET_NO); return size; } @@ -599,53 +544,21 @@ send_to_peer_notify_callback (void *cls, size_t size, void *buf) * Send the given packet via the mesh tunnel. * * @param mesh_tunnel destination - * @param payload message to transmit - * @param payload_length number of bytes in payload - * @param desc descriptor to add before payload (optional) - * @param mtype message type to use + * @param tnq message to queue */ static void send_packet_to_mesh_tunnel (struct GNUNET_MESH_Tunnel *mesh_tunnel, - const void *payload, - size_t payload_length, - const GNUNET_HashCode *desc, - uint16_t mtype) + struct TunnelMessageQueue *tnq) { struct TunnelState *s; - struct TunnelMessageQueue *tnq; - struct GNUNET_MessageHeader *msg; - size_t len; - GNUNET_HashCode *dp; - len = sizeof (struct GNUNET_MessageHeader) + sizeof (GNUNET_HashCode) + payload_length; - if (len >= GNUNET_SERVER_MAX_MESSAGE_SIZE) - { - GNUNET_break (0); - return; - } - tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueue) + len); - tnq->payload = &tnq[1]; - tnq->len = len; - msg = (struct GNUNET_MessageHeader *) &tnq[1]; - msg->size = htons ((uint16_t) len); - msg->type = htons (mtype); - if (NULL != desc) - { - dp = (GNUNET_HashCode *) &msg[1]; - *dp = *desc; - memcpy (&dp[1], payload, payload_length); - } - else - { - memcpy (&msg[1], payload, payload_length); - } s = GNUNET_MESH_tunnel_get_data (mesh_tunnel); GNUNET_assert (NULL != s); GNUNET_CONTAINER_DLL_insert_tail (s->head, s->tail, tnq); if (NULL == s->th) s->th = GNUNET_MESH_notify_transmit_ready (mesh_tunnel, GNUNET_NO /* cork */, 0 /* priority */, GNUNET_TIME_UNIT_FOREVER_REL, - NULL, len, + NULL, tnq->len, &send_to_peer_notify_callback, s); } @@ -663,15 +576,32 @@ send_packet_to_mesh_tunnel (struct GNUNET_MESH_Tunnel *mesh_tunnel, * be the original destination address) */ static void -udp_from_helper (const struct udp_packet *udp, +udp_from_helper (const struct GNUNET_TUN_UdpHeader *udp, size_t pktlen, int af, const void *destination_ip, const void *source_ip) { struct TunnelState *state; + struct TunnelMessageQueue *tnq; + struct GNUNET_EXIT_UdpReplyMessage *urm; + size_t mlen; - if (pktlen < sizeof (struct udp_packet)) + { + char sbuf[INET6_ADDRSTRLEN]; + char dbuf[INET6_ADDRSTRLEN]; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received UDP packet going from %s:%u to %s:%u\n", + inet_ntop (af, + source_ip, + sbuf, sizeof (sbuf)), + (unsigned int) ntohs (udp->spt), + inet_ntop (af, + source_ip, + dbuf, sizeof (dbuf)), + (unsigned int) ntohs (udp->dpt)); + } + if (pktlen < sizeof (struct GNUNET_TUN_UdpHeader)) { /* blame kernel */ GNUNET_break (0); @@ -695,12 +625,20 @@ udp_from_helper (const struct udp_packet *udp, _("Packet dropped, have no matching connection information\n")); return; } + mlen = sizeof (struct GNUNET_EXIT_UdpReplyMessage) + pktlen - sizeof (struct GNUNET_TUN_UdpHeader); + tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueue) + mlen); + tnq->payload = &tnq[1]; + tnq->len = mlen; + urm = (struct GNUNET_EXIT_UdpReplyMessage *) &tnq[1]; + urm->header.size = htons ((uint16_t) mlen); + urm->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_UDP_REPLY); + urm->source_port = htons (0); + urm->destination_port = htons (0); + memcpy (&urm[1], + &udp[1], + pktlen - sizeof (struct GNUNET_TUN_UdpHeader)); send_packet_to_mesh_tunnel (state->tunnel, - &udp[1], pktlen - sizeof (struct udp_packet), - NULL, - state->serv != NULL - ? GNUNET_MESSAGE_TYPE_VPN_SERVICE_UDP_BACK - : GNUNET_MESSAGE_TYPE_VPN_REMOTE_UDP_BACK); + tnq); } @@ -708,7 +646,7 @@ udp_from_helper (const struct udp_packet *udp, * @brief Handles a TCP packet received from the helper. * * @param tcp A pointer to the Packet - * @param pktlen the length of the packet, including its header + * @param pktlen the length of the packet, including its TCP header * @param af address family (AFINET or AF_INET6) * @param destination_ip destination IP-address of the IP packet (should * be our local address) @@ -716,7 +654,7 @@ udp_from_helper (const struct udp_packet *udp, * be the original destination address) */ static void -tcp_from_helper (const struct tcp_packet *tcp, +tcp_from_helper (const struct GNUNET_TUN_TcpHeader *tcp, size_t pktlen, int af, const void *destination_ip, @@ -724,9 +662,26 @@ tcp_from_helper (const struct tcp_packet *tcp, { struct TunnelState *state; char buf[pktlen]; - struct tcp_packet *mtcp; + struct GNUNET_TUN_TcpHeader *mtcp; + struct GNUNET_EXIT_TcpDataMessage *tdm; + struct TunnelMessageQueue *tnq; + size_t mlen; - if (pktlen < sizeof (struct tcp_packet)) + { + char sbuf[INET6_ADDRSTRLEN]; + char dbuf[INET6_ADDRSTRLEN]; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received TCP packet going from %s:%u to %s:%u\n", + inet_ntop (af, + source_ip, + sbuf, sizeof (sbuf)), + (unsigned int) ntohs (tcp->spt), + inet_ntop (af, + source_ip, + dbuf, sizeof (dbuf)), + (unsigned int) ntohs (tcp->dpt)); + } + if (pktlen < sizeof (struct GNUNET_TUN_TcpHeader)) { /* blame kernel */ GNUNET_break (0); @@ -748,16 +703,30 @@ tcp_from_helper (const struct tcp_packet *tcp, /* mug port numbers and crc to avoid information leakage; sender will need to lookup the correct values anyway */ memcpy (buf, tcp, pktlen); - mtcp = (struct tcp_packet *) buf; + mtcp = (struct GNUNET_TUN_TcpHeader *) buf; mtcp->spt = 0; mtcp->dpt = 0; mtcp->crc = 0; + + mlen = sizeof (struct GNUNET_EXIT_TcpDataMessage) + (pktlen - sizeof (struct GNUNET_TUN_TcpHeader)); + if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE) + { + GNUNET_break (0); + return; + } + + tnq = GNUNET_malloc (sizeof (struct TunnelMessageQueue) + mlen); + tnq->payload = &tnq[1]; + tnq->len = mlen; + tdm = (struct GNUNET_EXIT_TcpDataMessage *) &tnq[1]; + tdm->header.size = htons ((uint16_t) mlen); + tdm->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_TCP_DATA); + tdm->reserved = htonl (0); + memcpy (&tdm->tcp_header, + buf, + pktlen); send_packet_to_mesh_tunnel (state->tunnel, - mtcp, pktlen, - NULL, - state->serv != NULL - ? GNUNET_MESSAGE_TYPE_VPN_SERVICE_TCP_BACK - : GNUNET_MESSAGE_TYPE_VPN_REMOTE_TCP_BACK); + tnq); } @@ -772,52 +741,58 @@ static void message_token (void *cls GNUNET_UNUSED, void *client GNUNET_UNUSED, const struct GNUNET_MessageHeader *message) { - const struct tun_header *pkt_tun; + const struct GNUNET_TUN_Layer2PacketHeader *pkt_tun; size_t size; + GNUNET_STATISTICS_update (stats, + gettext_noop ("# Packets received from TUN"), + 1, GNUNET_NO); if (ntohs (message->type) != GNUNET_MESSAGE_TYPE_VPN_HELPER) { GNUNET_break (0); return; } size = ntohs (message->size); - if (size < sizeof (struct tun_header) + sizeof (struct GNUNET_MessageHeader)) + if (size < sizeof (struct GNUNET_TUN_Layer2PacketHeader) + sizeof (struct GNUNET_MessageHeader)) { GNUNET_break (0); return; } - pkt_tun = (const struct tun_header *) &message[1]; - size -= sizeof (struct tun_header) + sizeof (struct GNUNET_MessageHeader); + GNUNET_STATISTICS_update (stats, + gettext_noop ("# Bytes received from TUN"), + size, GNUNET_NO); + pkt_tun = (const struct GNUNET_TUN_Layer2PacketHeader *) &message[1]; + size -= sizeof (struct GNUNET_TUN_Layer2PacketHeader) + sizeof (struct GNUNET_MessageHeader); switch (ntohs (pkt_tun->proto)) { case ETH_P_IPV6: { - const struct ip6_header *pkt6; + const struct GNUNET_TUN_IPv6Header *pkt6; - if (size < sizeof (struct ip6_header)) + if (size < sizeof (struct GNUNET_TUN_IPv6Header)) { /* Kernel to blame? */ GNUNET_break (0); return; } - pkt6 = (struct ip6_header *) &pkt_tun[1]; + pkt6 = (struct GNUNET_TUN_IPv6Header *) &pkt_tun[1]; if (size != ntohs (pkt6->payload_length)) { /* Kernel to blame? */ GNUNET_break (0); return; } - size -= sizeof (struct ip6_header); + size -= sizeof (struct GNUNET_TUN_IPv6Header); switch (pkt6->next_header) { case IPPROTO_UDP: - udp_from_helper ((const struct udp_packet *) &pkt6[1], size, + udp_from_helper ((const struct GNUNET_TUN_UdpHeader *) &pkt6[1], size, AF_INET6, &pkt6->destination_address, &pkt6->source_address); break; case IPPROTO_TCP: - tcp_from_helper ((const struct tcp_packet *) &pkt6[1], size, + tcp_from_helper ((const struct GNUNET_TUN_TcpHeader *) &pkt6[1], size, AF_INET6, &pkt6->destination_address, &pkt6->source_address); @@ -831,37 +806,37 @@ message_token (void *cls GNUNET_UNUSED, void *client GNUNET_UNUSED, break; case ETH_P_IPV4: { - const struct ip4_header *pkt4; + const struct GNUNET_TUN_IPv4Header *pkt4; - if (size < sizeof (struct ip4_header)) + if (size < sizeof (struct GNUNET_TUN_IPv4Header)) { /* Kernel to blame? */ GNUNET_break (0); return; } - pkt4 = (const struct ip4_header *) &pkt_tun[1]; + pkt4 = (const struct GNUNET_TUN_IPv4Header *) &pkt_tun[1]; if (size != ntohs (pkt4->total_length)) { /* Kernel to blame? */ GNUNET_break (0); return; } - if (pkt4->header_length * 4 != sizeof (struct ip4_header)) + if (pkt4->header_length * 4 != sizeof (struct GNUNET_TUN_IPv4Header)) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _("IPv4 packet options received. Ignored.\n")); return; } - size -= sizeof (struct ip4_header); + size -= sizeof (struct GNUNET_TUN_IPv4Header); switch (pkt4->protocol) { case IPPROTO_UDP: - udp_from_helper ((const struct udp_packet *) &pkt4[1], size, + udp_from_helper ((const struct GNUNET_TUN_UdpHeader *) &pkt4[1], size, AF_INET, &pkt4->destination_address, &pkt4->source_address); case IPPROTO_TCP: - tcp_from_helper ((const struct tcp_packet *) &pkt4[1], size, + tcp_from_helper ((const struct GNUNET_TUN_TcpHeader *) &pkt4[1], size, AF_INET, &pkt4->destination_address, &pkt4->source_address); @@ -892,42 +867,84 @@ message_token (void *cls GNUNET_UNUSED, void *client GNUNET_UNUSED, */ static void setup_fresh_address (int af, - int proto, + uint8_t proto, struct SocketAddress *local_address) { + local_address->af = af; + local_address->proto = (uint8_t) proto; + /* default "local" port range is often 32768--61000, + so we pick a random value in that range */ + local_address->port + = (uint16_t) 32768 + GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, + 28232); switch (af) { case AF_INET: { - const char *ipv4addr = exit_argv[4]; - const char *ipv4mask = exit_argv[5]; - uint32_t tmp; - uint32_t tmp2; - - GNUNET_assert (1 == inet_pton (AF_INET, ipv4addr, &tmp)); - GNUNET_assert (1 == inet_pton (AF_INET, ipv4mask, &tmp2)); - // FIXME - /* This should be a noop */ - tmp = tmp & tmp2; - tmp |= ntohl (*((uint32_t *) /*tunnel*/ 42)) & (~tmp2); - - // pkt4->source_address.s_addr = tmp; + struct in_addr addr; + struct in_addr mask; + struct in_addr rnd; + + addr = exit_ipv4addr; + mask = exit_ipv4mask; + if (0 == ~mask.s_addr) + { + /* only one valid IP anyway */ + local_address->address.ipv4 = addr; + return; + } + /* Given 192.168.0.1/255.255.0.0, we want a mask + of '192.168.255.255', thus: */ + mask.s_addr = addr.s_addr | ~mask.s_addr; + /* Pick random IPv4 address within the subnet, except 'addr' or 'mask' itself */ + do + { + rnd.s_addr = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, + UINT32_MAX); + local_address->address.ipv4.s_addr = (addr.s_addr | rnd.s_addr) & mask.s_addr; + } + while ( (local_address->address.ipv4.s_addr == addr.s_addr) || + (local_address->address.ipv4.s_addr == mask.s_addr) ); } break; case AF_INET6: { - const char *ipv6addr = exit_argv[2]; - /* Generate a new src-address - * This takes as much from the address of the tunnel as fits into - * the host-mask*/ - unsigned long long ipv6prefix_r = (ipv6prefix + 7) / 8; - inet_pton (AF_INET6, ipv6addr, &local_address->address.ipv6); - if (ipv6prefix_r < (16 - sizeof (void *))) - ipv6prefix_r = 16 - sizeof (void *); + struct in6_addr addr; + struct in6_addr mask; + struct in6_addr rnd; + int i; - unsigned int offset = ipv6prefix_r - (16 - sizeof (void *)); - // memcpy ((((char *) &pkt6->source_address)) + ipv6prefix_r, ((char *) &tunnel) + offset, 16 - ipv6prefix_r); - offset++; + addr = exit_ipv6addr; + GNUNET_assert (ipv6prefix < 128); + if (ipv6prefix == 127) + { + /* only one valid IP anyway */ + local_address->address.ipv6 = addr; + return; + } + /* Given ABCD::/96, we want a mask of 'ABCD::FFFF:FFFF, + thus: */ + mask = addr; + for (i=127;i>=128-ipv6prefix;i--) + mask.s6_addr[i / 8] |= (1 << (i % 8)); + + /* Pick random IPv6 address within the subnet, except 'addr' or 'mask' itself */ + do + { + for (i=0;i<16;i++) + { + rnd.s6_addr[i] = (unsigned char) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, + 256); + local_address->address.ipv6.s6_addr[i] + = (addr.s6_addr[i] | rnd.s6_addr[i]) & mask.s6_addr[i]; + } + } + while ( (0 == memcmp (&local_address->address.ipv6, + &addr, + sizeof (struct in6_addr))) || + (0 == memcmp (&local_address->address.ipv6, + &mask, + sizeof (struct in6_addr))) ); } break; default: @@ -937,7 +954,25 @@ setup_fresh_address (int af, /** - * FIXME: document! + * We are starting a fresh connection (TCP or UDP) and need + * to pick a source port and IP address (within the correct + * range and address family) to associate replies with the + * connection / correct mesh tunnel. This function generates + * a "fresh" source IP and source port number for a connection + * After picking a good source address, this function sets up + * the state in the 'connections_map' and 'connections_heap' + * to allow finding the state when needed later. The function + * also makes sure that we remain within memory limits by + * cleaning up 'old' states. + * + * @param state skeleton state to setup a record for; should + * 'state->ri.remote_address' filled in so that + * this code can determine which AF/protocol is + * going to be used (the 'tunnel' should also + * already be set); after calling this function, + * heap_node and the local_address will be + * also initialized (heap_node != NULL can be + * used to test if a state has been fully setup). */ static void setup_state_record (struct TunnelState *state) @@ -948,16 +983,31 @@ setup_state_record (struct TunnelState *state) /* generate fresh, unique address */ do { - setup_fresh_address (state->serv->address.af, - state->serv->address.proto, - &state->ri.local_address); - } while (NULL != get_redirect_state (state->serv->address.af, - IPPROTO_UDP, + if (NULL == state->serv) + setup_fresh_address (state->ri.remote_address.af, + state->ri.remote_address.proto, + &state->ri.local_address); + else + setup_fresh_address (state->serv->address.af, + state->serv->address.proto, + &state->ri.local_address); + } while (NULL != get_redirect_state (state->ri.remote_address.af, + state->ri.remote_address.proto, &state->ri.remote_address.address, state->ri.remote_address.port, &state->ri.local_address.address, state->ri.local_address.port, &key)); + { + char buf[INET6_ADDRSTRLEN]; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Picked local address %s:%u for new connection\n", + inet_ntop (state->ri.local_address.af, + &state->ri.local_address.address, + buf, sizeof (buf)), + (unsigned int) state->ri.local_address.port); + } + state->state_key = key; GNUNET_assert (GNUNET_OK == GNUNET_CONTAINER_multihashmap_put (connections_map, &key, state, @@ -981,14 +1031,29 @@ setup_state_record (struct TunnelState *state) /** - * FIXME: document + * Prepare an IPv4 packet for transmission via the TUN interface. + * Initializes the IP header and calculates checksums (IP+UDP/TCP). + * For UDP, the UDP header will be fully created, whereas for TCP + * only the ports and checksum will be filled in. So for TCP, + * a skeleton TCP header must be part of the provided payload. + * + * @param payload payload of the packet (starting with UDP payload or + * TCP header, depending on protocol) + * @param payload_length number of bytes in 'payload' + * @param protocol IPPROTO_UDP or IPPROTO_TCP + * @param src_address source address to use (IP and port) + * @param dst_address destination address to use (IP and port) + * @param pkt6 where to write the assembled packet; must + * contain enough space for the IP header, UDP/TCP header + * AND the payload */ static void prepare_ipv4_packet (const void *payload, size_t payload_length, int protocol, + const struct GNUNET_TUN_TcpHeader *tcp_header, const struct SocketAddress *src_address, const struct SocketAddress *dst_address, - struct ip4_header *pkt4) + struct GNUNET_TUN_IPv4Header *pkt4) { size_t len; @@ -996,70 +1061,54 @@ prepare_ipv4_packet (const void *payload, size_t payload_length, switch (protocol) { case IPPROTO_UDP: - len += sizeof (struct udp_packet); + len += sizeof (struct GNUNET_TUN_UdpHeader); break; case IPPROTO_TCP: - /* tcp_header (with port/crc not set) must be part of payload! */ - if (len < sizeof (struct tcp_packet)) - { - GNUNET_break (0); - return; - } + len += sizeof (struct GNUNET_TUN_TcpHeader); + GNUNET_assert (NULL != tcp_header); break; default: GNUNET_break (0); return; } - if (len + sizeof (struct ip4_header) > UINT16_MAX) + if (len + sizeof (struct GNUNET_TUN_IPv4Header) > UINT16_MAX) { GNUNET_break (0); return; } - pkt4->version = 4; - pkt4->header_length = sizeof (struct ip4_header) / 4; - pkt4->diff_serv = 0; - pkt4->total_length = htons ((uint16_t) (sizeof (struct ip4_header) + len)); - pkt4->identification = (uint16_t) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, - 65536); - pkt4->flags = 0; - pkt4->fragmentation_offset = 0; - pkt4->ttl = 255; - pkt4->protocol = protocol; - pkt4->checksum = 0; - pkt4->destination_address = dst_address->address.ipv4; - pkt4->source_address = src_address->address.ipv4; - pkt4->checksum = GNUNET_CRYPTO_crc16_n (pkt4, sizeof (struct ip4_header)); - + GNUNET_TUN_initialize_ipv4_header (pkt4, + protocol, + len, + &src_address->address.ipv4, + &dst_address->address.ipv4); switch (protocol) { case IPPROTO_UDP: { - struct udp_packet *pkt4_udp = (struct udp_packet *) &pkt4[1]; + struct GNUNET_TUN_UdpHeader *pkt4_udp = (struct GNUNET_TUN_UdpHeader *) &pkt4[1]; pkt4_udp->spt = htons (src_address->port); pkt4_udp->dpt = htons (dst_address->port); - pkt4_udp->crc = 0; /* Optional for IPv4 */ pkt4_udp->len = htons ((uint16_t) payload_length); + GNUNET_TUN_calculate_udp4_checksum (pkt4, + pkt4_udp, + payload, payload_length); memcpy (&pkt4_udp[1], payload, payload_length); } break; case IPPROTO_TCP: { - struct tcp_packet *pkt4_tcp = (struct tcp_packet *) &pkt4[1]; + struct GNUNET_TUN_TcpHeader *pkt4_tcp = (struct GNUNET_TUN_TcpHeader *) &pkt4[1]; - memcpy (pkt4_tcp, payload, payload_length); + memcpy (pkt4_tcp, tcp_header, sizeof (struct GNUNET_TUN_TcpHeader)); pkt4_tcp->spt = htons (src_address->port); pkt4_tcp->dpt = htons (dst_address->port); - pkt4_tcp->crc = 0; - uint32_t sum = 0; - sum = GNUNET_CRYPTO_crc16_step (sum, - &pkt4->source_address, - sizeof (struct in_addr) * 2); - uint32_t tmp = htonl ((protocol << 16) | (0xffff & len)); - sum = GNUNET_CRYPTO_crc16_step (sum, & tmp, sizeof (uint32_t)); - sum = GNUNET_CRYPTO_crc16_step (sum, & pkt4_tcp, len); - pkt4_tcp->crc = GNUNET_CRYPTO_crc16_finish (sum); + GNUNET_TUN_calculate_tcp4_checksum (pkt4, + pkt4_tcp, + payload, + payload_length); + memcpy (&pkt4_tcp[1], payload, payload_length); } break; default: @@ -1069,14 +1118,29 @@ prepare_ipv4_packet (const void *payload, size_t payload_length, /** - * FIXME: document + * Prepare an IPv6 packet for transmission via the TUN interface. + * Initializes the IP header and calculates checksums (IP+UDP/TCP). + * For UDP, the UDP header will be fully created, whereas for TCP + * only the ports and checksum will be filled in. So for TCP, + * a skeleton TCP header must be part of the provided payload. + * + * @param payload payload of the packet (starting with UDP payload or + * TCP header, depending on protocol) + * @param payload_length number of bytes in 'payload' + * @param protocol IPPROTO_UDP or IPPROTO_TCP + * @param src_address source address to use (IP and port) + * @param dst_address destination address to use (IP and port) + * @param pkt6 where to write the assembled packet; must + * contain enough space for the IP header, UDP/TCP header + * AND the payload */ static void prepare_ipv6_packet (const void *payload, size_t payload_length, int protocol, + const struct GNUNET_TUN_TcpHeader *tcp_header, const struct SocketAddress *src_address, const struct SocketAddress *dst_address, - struct ip6_header *pkt6) + struct GNUNET_TUN_IPv6Header *pkt6) { size_t len; @@ -1084,11 +1148,11 @@ prepare_ipv6_packet (const void *payload, size_t payload_length, switch (protocol) { case IPPROTO_UDP: - len += sizeof (struct udp_packet); + len += sizeof (struct GNUNET_TUN_UdpHeader); break; case IPPROTO_TCP: /* tcp_header (with port/crc not set) must be part of payload! */ - if (len < sizeof (struct tcp_packet)) + if (len < sizeof (struct GNUNET_TUN_TcpHeader)) { GNUNET_break (0); return; @@ -1104,55 +1168,41 @@ prepare_ipv6_packet (const void *payload, size_t payload_length, return; } - pkt6->version = 6; - pkt6->next_header = protocol; - pkt6->payload_length = htons ((uint16_t) (len + sizeof (struct ip6_header))); - pkt6->hop_limit = 255; - pkt6->destination_address = dst_address->address.ipv6; - pkt6->source_address = src_address->address.ipv6; + GNUNET_TUN_initialize_ipv6_header (pkt6, + protocol, + len, + &dst_address->address.ipv6, + &src_address->address.ipv6); switch (protocol) { case IPPROTO_UDP: { - struct udp_packet *pkt6_udp = (struct udp_packet *) &pkt6[1]; + struct GNUNET_TUN_UdpHeader *pkt6_udp = (struct GNUNET_TUN_UdpHeader *) &pkt6[1]; - memcpy (&pkt6[1], payload, payload_length); - pkt6_udp->crc = 0; pkt6_udp->spt = htons (src_address->port); pkt6_udp->dpt = htons (dst_address->port); pkt6_udp->len = htons ((uint16_t) payload_length); - - uint32_t sum = 0; - sum = GNUNET_CRYPTO_crc16_step (sum, - &pkt6->source_address, - sizeof (struct in6_addr) * 2); - uint32_t tmp = htons (len); - sum = GNUNET_CRYPTO_crc16_step (sum, &tmp, sizeof (uint32_t)); - tmp = htonl (pkt6->next_header); - sum = GNUNET_CRYPTO_crc16_step (sum, &tmp, sizeof (uint32_t)); - sum = GNUNET_CRYPTO_crc16_step (sum, pkt6_udp, len); - pkt6_udp->crc = GNUNET_CRYPTO_crc16_finish (sum); + pkt6_udp->crc = 0; + GNUNET_TUN_calculate_udp6_checksum (pkt6, + pkt6_udp, + payload, + payload_length); + memcpy (&pkt6[1], payload, payload_length); } break; case IPPROTO_TCP: { - struct tcp_packet *pkt6_tcp = (struct tcp_packet *) pkt6; - + struct GNUNET_TUN_TcpHeader *pkt6_tcp = (struct GNUNET_TUN_TcpHeader *) pkt6; + + /* memcpy first here as some TCP header fields are initialized this way! */ memcpy (pkt6_tcp, payload, payload_length); - pkt6_tcp->crc = 0; pkt6_tcp->spt = htons (src_address->port); pkt6_tcp->dpt = htons (dst_address->port); - - uint32_t sum = 0; - sum = GNUNET_CRYPTO_crc16_step (sum, &pkt6->source_address, - sizeof (struct in6_addr) * 2); - uint32_t tmp = htonl (len); - sum = GNUNET_CRYPTO_crc16_step (sum, &tmp, sizeof (uint32_t)); - tmp = htonl (pkt6->next_header); - sum = GNUNET_CRYPTO_crc16_step (sum, &tmp, sizeof (uint32_t)); - sum = GNUNET_CRYPTO_crc16_step (sum, pkt6_tcp, len); - pkt6_tcp->crc = GNUNET_CRYPTO_crc16_finish (sum); + GNUNET_TUN_calculate_tcp6_checksum (pkt6, + pkt6_tcp, + payload, + payload_length); } break; default: @@ -1163,89 +1213,36 @@ prepare_ipv6_packet (const void *payload, size_t payload_length, /** - * We've just experienced a connection in use. Track it, or if it is - * already tracked, update the tracking. - * - * @param u_i IP-level connection tracking state - * @param tunnel associated mesh tunnel - * @param desc service descriptor (or NULL) - * @param serv service information - */ -void -update_state_map (const struct RedirectInformation *ri, - struct GNUNET_MESH_Tunnel *tunnel, - const GNUNET_HashCode *desc, - struct LocalService *serv) -{ - struct TunnelState *state; - GNUNET_HashCode state_key; - - hash_redirect_info (&state_key, - ri); - state = GNUNET_CONTAINER_multihashmap_get (connections_map, &state_key); - if (NULL == state) - { - state = GNUNET_malloc (sizeof (struct TunnelState)); - state->tunnel = tunnel; - state->state_key = state_key; - state->serv = serv; - // FIXME? if (NULL != desc) state->desc = *desc; - // FIXME? state->redirect_info = *ri; - GNUNET_assert (GNUNET_OK == - GNUNET_CONTAINER_multihashmap_put (connections_map, &state_key, state, - GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); - state->heap_node = - GNUNET_CONTAINER_heap_insert (connections_heap, - state, - GNUNET_TIME_absolute_get ().abs_value); - } - else - { - if (state->tunnel != tunnel) - { - /* Stats / warning: two tunnels got exactly the same connection state!? */ - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - _("Two different mesh tunnels got the same connection state. Oops.\n")); - return; - } - GNUNET_CONTAINER_heap_update_cost (connections_heap, - state->heap_node, - GNUNET_TIME_absolute_get ().abs_value); - } - while (GNUNET_CONTAINER_heap_get_size (connections_heap) > max_connections) - { - state = GNUNET_CONTAINER_heap_remove_root (connections_heap); - state->heap_node = NULL; - GNUNET_MESH_tunnel_destroy (state->tunnel); - GNUNET_assert (GNUNET_OK == - GNUNET_CONTAINER_multihashmap_remove (connections_map, - &state->state_key, - state)); - GNUNET_free (state); - } -} - - -/** - * FIXME: document! + * Send a TCP packet via the TUN interface. * - * @param payload payload of the IP header (includes TCP header) + * @param destination_address IP and port to use for the TCP packet's destination + * @param source_address IP and port to use for the TCP packet's source + * @param tcp header template to use + * @param payload payload of the TCP packet + * @param payload_length number of bytes in 'payload' */ static void send_tcp_packet_via_tun (const struct SocketAddress *destination_address, const struct SocketAddress *source_address, + const struct GNUNET_TUN_TcpHeader *tcp_header, const void *payload, size_t payload_length) { size_t len; - len = sizeof (struct GNUNET_MessageHeader) + sizeof (struct tun_header); + GNUNET_STATISTICS_update (stats, + gettext_noop ("# TCP packets sent via TUN"), + 1, GNUNET_NO); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Sending packet with %u bytes TCP payload via TUN\n", + (unsigned int) payload_length); + len = sizeof (struct GNUNET_MessageHeader) + sizeof (struct GNUNET_TUN_Layer2PacketHeader); switch (source_address->af) { case AF_INET: - len += sizeof (struct ip4_header); + len += sizeof (struct GNUNET_TUN_IPv4Header); break; case AF_INET6: - len += sizeof (struct ip6_header); + len += sizeof (struct GNUNET_TUN_IPv6Header); break; default: GNUNET_break (0); @@ -1260,21 +1257,23 @@ send_tcp_packet_via_tun (const struct SocketAddress *destination_address, { char buf[len]; struct GNUNET_MessageHeader *hdr; - struct tun_header *tun; + struct GNUNET_TUN_Layer2PacketHeader *tun; hdr= (struct GNUNET_MessageHeader *) buf; - hdr->type = htons (42); + hdr->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER); hdr->size = htons (len); - tun = (struct tun_header*) &hdr[1]; + tun = (struct GNUNET_TUN_Layer2PacketHeader*) &hdr[1]; tun->flags = htons (0); switch (source_address->af) { case AF_INET: { - struct ip4_header * ipv4 = (struct ip4_header*) &tun[1]; + struct GNUNET_TUN_IPv4Header * ipv4 = (struct GNUNET_TUN_IPv4Header*) &tun[1]; tun->proto = htons (ETH_P_IPV4); - prepare_ipv4_packet (payload, payload_length, IPPROTO_TCP, + prepare_ipv4_packet (payload, payload_length, + IPPROTO_TCP, + tcp_header, source_address, destination_address, ipv4); @@ -1282,10 +1281,12 @@ send_tcp_packet_via_tun (const struct SocketAddress *destination_address, break; case AF_INET6: { - struct ip6_header * ipv6 = (struct ip6_header*) &tun[1]; + struct GNUNET_TUN_IPv6Header * ipv6 = (struct GNUNET_TUN_IPv6Header*) &tun[1]; tun->proto = htons (ETH_P_IPV6); - prepare_ipv6_packet (payload, payload_length, IPPROTO_TCP, + prepare_ipv6_packet (payload, payload_length, + IPPROTO_TCP, + tcp_header, source_address, destination_address, ipv6); @@ -1304,8 +1305,17 @@ send_tcp_packet_via_tun (const struct SocketAddress *destination_address, /** - * The messages are one GNUNET_HashCode for the service followed by a struct tcp_packet - * FIXME: document! + * Process a request via mesh to send a request to a TCP service + * offered by this system. + * + * @param cls closure, NULL + * @param tunnel connection to the other end + * @param tunnel_ctx pointer to our 'struct TunnelState *' + * @param sender who sent the message + * @param message the actual message + * @param atsi performance data for the connection + * @return GNUNET_OK to keep the connection open, + * GNUNET_SYSERR to close it (signal serious error) */ static int receive_tcp_service (void *unused GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel, @@ -1315,45 +1325,70 @@ receive_tcp_service (void *unused GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunn const struct GNUNET_ATS_Information *atsi GNUNET_UNUSED) { struct TunnelState *state = *tunnel_ctx; - // FIXME: write proper request struct (we don't need the descriptor EACH time here!) - const GNUNET_HashCode *desc = (const GNUNET_HashCode *) &message[1]; - const struct tcp_packet *pkt = (const struct tcp_packet *) &desc[1]; + const struct GNUNET_EXIT_TcpServiceStartMessage *start; uint16_t pkt_len = ntohs (message->size); - + GNUNET_STATISTICS_update (stats, + gettext_noop ("# TCP service creation requests received via mesh"), + 1, GNUNET_NO); + GNUNET_STATISTICS_update (stats, + gettext_noop ("# Bytes received from MESH"), + pkt_len, GNUNET_NO); /* check that we got at least a valid header */ - if (pkt_len < sizeof (struct GNUNET_MessageHeader) + sizeof (GNUNET_HashCode) + sizeof (struct tcp_packet)) + if (pkt_len < sizeof (struct GNUNET_EXIT_TcpServiceStartMessage)) { GNUNET_break_op (0); - return GNUNET_YES; + return GNUNET_SYSERR; } - pkt_len -= (sizeof (struct GNUNET_MessageHeader) + sizeof (GNUNET_HashCode)); - - if (NULL == state->serv) + start = (const struct GNUNET_EXIT_TcpServiceStartMessage*) message; + pkt_len -= sizeof (struct GNUNET_EXIT_TcpServiceStartMessage); + if ( (NULL == state) || + (NULL != state->serv) || + (NULL != state->heap_node) ) { - /* setup fresh connection */ - GNUNET_assert (NULL == state->heap_node); - if (NULL == (state->serv = find_service (tcp_services, desc, ntohs (pkt->dpt)))) - { - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - _("No service found for %s on port %d!\n"), - "TCP", - ntohs (pkt->dpt)); - GNUNET_MESH_tunnel_destroy (state->tunnel); - return GNUNET_YES; - } - state->ri.remote_address = state->serv->address; - setup_state_record (state); + GNUNET_break_op (0); + return GNUNET_SYSERR; } + GNUNET_break_op (ntohl (start->reserved) == 0); + /* setup fresh connection */ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received data from %s for forwarding to TCP service %s on port %u\n", + GNUNET_i2s (sender), + GNUNET_h2s (&start->service_descriptor), + (unsigned int) ntohs (start->tcp_header.dpt)); + if (NULL == (state->serv = find_service (tcp_services, &start->service_descriptor, + ntohs (start->tcp_header.dpt)))) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _("No service found for %s on port %d!\n"), + "TCP", + ntohs (start->tcp_header.dpt)); + GNUNET_STATISTICS_update (stats, + gettext_noop ("# TCP requests dropped (no such service)"), + 1, GNUNET_NO); + return GNUNET_SYSERR; + } + state->ri.remote_address = state->serv->address; + setup_state_record (state); send_tcp_packet_via_tun (&state->ri.remote_address, &state->ri.local_address, - pkt, pkt_len); + &start->tcp_header, + &start[1], pkt_len); return GNUNET_YES; } /** - * FIXME: document! + * Process a request to forward TCP data to the Internet via this peer. + * + * @param cls closure, NULL + * @param tunnel connection to the other end + * @param tunnel_ctx pointer to our 'struct TunnelState *' + * @param sender who sent the message + * @param message the actual message + * @param atsi performance data for the connection + * @return GNUNET_OK to keep the connection open, + * GNUNET_SYSERR to close it (signal serious error) */ static int receive_tcp_remote (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel, @@ -1363,36 +1398,168 @@ receive_tcp_remote (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel, const struct GNUNET_ATS_Information *atsi GNUNET_UNUSED) { struct TunnelState *state = *tunnel_ctx; - // FIXME: write proper request struct (!) - const GNUNET_HashCode *desc = (const GNUNET_HashCode *) &message[1]; - const struct tcp_packet *pkt = (const struct tcp_packet *) &desc[1]; - const struct SocketAddress *s = (const struct SocketAddress *) desc; + const struct GNUNET_EXIT_TcpInternetStartMessage *start; uint16_t pkt_len = ntohs (message->size); + const struct in_addr *v4; + const struct in6_addr *v6; + const void *payload; + int af; - if (pkt_len < sizeof (struct GNUNET_MessageHeader) + sizeof (GNUNET_HashCode) + sizeof (struct tcp_packet)) + GNUNET_STATISTICS_update (stats, + gettext_noop ("# Bytes received from MESH"), + pkt_len, GNUNET_NO); + GNUNET_STATISTICS_update (stats, + gettext_noop ("# TCP IP-exit creation requests received via mesh"), + 1, GNUNET_NO); + if (pkt_len < sizeof (struct GNUNET_EXIT_TcpInternetStartMessage)) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + start = (const struct GNUNET_EXIT_TcpInternetStartMessage*) message; + pkt_len -= sizeof (struct GNUNET_EXIT_TcpInternetStartMessage); + if ( (NULL == state) || + (NULL != state->serv) || + (NULL != state->heap_node) ) { GNUNET_break_op (0); - return GNUNET_YES; + return GNUNET_SYSERR; + } + af = (int) ntohl (start->af); + state->ri.remote_address.af = af; + switch (af) + { + case AF_INET: + if (pkt_len < sizeof (struct in_addr)) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + if (! ipv4_exit) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + v4 = (const struct in_addr*) &start[1]; + payload = &v4[1]; + pkt_len -= sizeof (struct in_addr); + state->ri.remote_address.address.ipv4 = *v4; + break; + case AF_INET6: + if (pkt_len < sizeof (struct in6_addr)) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + if (! ipv6_exit) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + v6 = (const struct in6_addr*) &start[1]; + payload = &v6[1]; + pkt_len -= sizeof (struct in_addr); + state->ri.remote_address.address.ipv6 = *v6; + break; + default: + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + { + char buf[INET6_ADDRSTRLEN]; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received data from %s for starting TCP stream to %s:%u\n", + GNUNET_i2s (sender), + inet_ntop (af, + &state->ri.remote_address.address, + buf, sizeof (buf)), + (unsigned int) ntohs (start->tcp_header.dpt)); } - pkt_len -= (sizeof (struct GNUNET_MessageHeader) + sizeof (GNUNET_HashCode)); - if (NULL == state->heap_node) + state->ri.remote_address.proto = IPPROTO_TCP; + state->ri.remote_address.port = ntohs (start->tcp_header.dpt); + setup_state_record (state); + send_tcp_packet_via_tun (&state->ri.remote_address, + &state->ri.local_address, + &start->tcp_header, + payload, pkt_len); + return GNUNET_YES; +} + + +/** + * Process a request to forward TCP data on an established + * connection via this peer. + * + * @param cls closure, NULL + * @param tunnel connection to the other end + * @param tunnel_ctx pointer to our 'struct TunnelState *' + * @param sender who sent the message + * @param message the actual message + * @param atsi performance data for the connection + * @return GNUNET_OK to keep the connection open, + * GNUNET_SYSERR to close it (signal serious error) + */ +static int +receive_tcp_data (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel, + void **tunnel_ctx GNUNET_UNUSED, + const struct GNUNET_PeerIdentity *sender GNUNET_UNUSED, + const struct GNUNET_MessageHeader *message, + const struct GNUNET_ATS_Information *atsi GNUNET_UNUSED) +{ + struct TunnelState *state = *tunnel_ctx; + const struct GNUNET_EXIT_TcpDataMessage *data; + uint16_t pkt_len = ntohs (message->size); + + GNUNET_STATISTICS_update (stats, + gettext_noop ("# Bytes received from MESH"), + pkt_len, GNUNET_NO); + GNUNET_STATISTICS_update (stats, + gettext_noop ("# TCP data requests received via mesh"), + 1, GNUNET_NO); + if (pkt_len < sizeof (struct GNUNET_EXIT_TcpDataMessage)) { - /* first packet, setup record */ - state->ri.remote_address = *s; - setup_state_record (state); + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + data = (const struct GNUNET_EXIT_TcpDataMessage*) message; + pkt_len -= sizeof (struct GNUNET_EXIT_TcpDataMessage); + if ( (NULL == state) || + (NULL == state->heap_node) ) + { + /* connection should have been up! */ + GNUNET_STATISTICS_update (stats, + gettext_noop ("# TCP DATA requests dropped (no session)"), + 1, GNUNET_NO); + return GNUNET_SYSERR; + } + GNUNET_break_op (ntohl (data->reserved) == 0); + { + char buf[INET6_ADDRSTRLEN]; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received additional data from %s for TCP stream to %s:%u\n", + GNUNET_i2s (sender), + inet_ntop (state->ri.remote_address.af, + &state->ri.remote_address.address, + buf, sizeof (buf)), + (unsigned int) state->ri.remote_address.port); } send_tcp_packet_via_tun (&state->ri.remote_address, &state->ri.local_address, - pkt, pkt_len); + &data->tcp_header, + &data[1], pkt_len); return GNUNET_YES; } /** - * FIXME: document! + * Send a UDP packet via the TUN interface. + * + * @param destination_address IP and port to use for the UDP packet's destination + * @param source_address IP and port to use for the UDP packet's source * @param payload payload of the UDP packet (does NOT include UDP header) + * @param payload_length number of bytes of data in payload */ static void send_udp_packet_via_tun (const struct SocketAddress *destination_address, @@ -1401,20 +1568,26 @@ send_udp_packet_via_tun (const struct SocketAddress *destination_address, { size_t len; - len = sizeof (struct GNUNET_MessageHeader) + sizeof (struct tun_header); + GNUNET_STATISTICS_update (stats, + gettext_noop ("# UDP packets sent via TUN"), + 1, GNUNET_NO); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Sending packet with %u bytes UDP payload via TUN\n", + (unsigned int) payload_length); + len = sizeof (struct GNUNET_MessageHeader) + sizeof (struct GNUNET_TUN_Layer2PacketHeader); switch (source_address->af) { case AF_INET: - len += sizeof (struct ip4_header); + len += sizeof (struct GNUNET_TUN_IPv4Header); break; case AF_INET6: - len += sizeof (struct ip6_header); + len += sizeof (struct GNUNET_TUN_IPv6Header); break; default: GNUNET_break (0); return; } - len += sizeof (struct udp_packet); + len += sizeof (struct GNUNET_TUN_UdpHeader); len += payload_length; if (len >= GNUNET_SERVER_MAX_MESSAGE_SIZE) { @@ -1424,21 +1597,23 @@ send_udp_packet_via_tun (const struct SocketAddress *destination_address, { char buf[len]; struct GNUNET_MessageHeader *hdr; - struct tun_header *tun; + struct GNUNET_TUN_Layer2PacketHeader *tun; hdr= (struct GNUNET_MessageHeader *) buf; - hdr->type = htons (42); + hdr->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER); hdr->size = htons (len); - tun = (struct tun_header*) &hdr[1]; + tun = (struct GNUNET_TUN_Layer2PacketHeader*) &hdr[1]; tun->flags = htons (0); switch (source_address->af) { case AF_INET: { - struct ip4_header * ipv4 = (struct ip4_header*) &tun[1]; + struct GNUNET_TUN_IPv4Header * ipv4 = (struct GNUNET_TUN_IPv4Header*) &tun[1]; tun->proto = htons (ETH_P_IPV4); - prepare_ipv4_packet (payload, payload_length, IPPROTO_UDP, + prepare_ipv4_packet (payload, payload_length, + IPPROTO_UDP, + NULL, source_address, destination_address, ipv4); @@ -1446,10 +1621,12 @@ send_udp_packet_via_tun (const struct SocketAddress *destination_address, break; case AF_INET6: { - struct ip6_header * ipv6 = (struct ip6_header*) &tun[1]; + struct GNUNET_TUN_IPv6Header * ipv6 = (struct GNUNET_TUN_IPv6Header*) &tun[1]; tun->proto = htons (ETH_P_IPV6); - prepare_ipv6_packet (payload, payload_length, IPPROTO_UDP, + prepare_ipv6_packet (payload, payload_length, + IPPROTO_UDP, + NULL, source_address, destination_address, ipv6); @@ -1468,7 +1645,16 @@ send_udp_packet_via_tun (const struct SocketAddress *destination_address, /** - * FIXME: document! + * Process a request to forward UDP data to the Internet via this peer. + * + * @param cls closure, NULL + * @param tunnel connection to the other end + * @param tunnel_ctx pointer to our 'struct TunnelState *' + * @param sender who sent the message + * @param message the actual message + * @param atsi performance data for the connection + * @return GNUNET_OK to keep the connection open, + * GNUNET_SYSERR to close it (signal serious error) */ static int receive_udp_remote (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel, @@ -1478,35 +1664,101 @@ receive_udp_remote (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel, const struct GNUNET_ATS_Information *atsi GNUNET_UNUSED) { struct TunnelState *state = *tunnel_ctx; - // FIXME: write proper request struct (!) - const GNUNET_HashCode *desc = (const GNUNET_HashCode *) &message[1]; - const struct udp_packet *pkt = (const struct udp_packet *) &desc[1]; - const struct SocketAddress *s = (const struct SocketAddress *) desc; + const struct GNUNET_EXIT_UdpInternetMessage *msg; uint16_t pkt_len = ntohs (message->size); + const struct in_addr *v4; + const struct in6_addr *v6; + const void *payload; + int af; - if (pkt_len < sizeof (struct GNUNET_MessageHeader) + sizeof (GNUNET_HashCode) + sizeof (struct udp_packet)) + GNUNET_STATISTICS_update (stats, + gettext_noop ("# Bytes received from MESH"), + pkt_len, GNUNET_NO); + GNUNET_STATISTICS_update (stats, + gettext_noop ("# UDP IP-exit requests received via mesh"), + 1, GNUNET_NO); + if (pkt_len < sizeof (struct GNUNET_EXIT_UdpInternetMessage)) { GNUNET_break_op (0); - return GNUNET_YES; + return GNUNET_SYSERR; } - pkt_len -= (sizeof (struct GNUNET_MessageHeader) + sizeof (GNUNET_HashCode)); - - if (NULL == state->heap_node) + msg = (const struct GNUNET_EXIT_UdpInternetMessage*) message; + pkt_len -= sizeof (struct GNUNET_EXIT_UdpInternetMessage); + af = (int) ntohl (msg->af); + state->ri.remote_address.af = af; + switch (af) { - /* first packet, setup record */ - state->ri.remote_address = *s; - setup_state_record (state); + case AF_INET: + if (pkt_len < sizeof (struct in_addr)) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + if (! ipv4_exit) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + v4 = (const struct in_addr*) &msg[1]; + payload = &v4[1]; + pkt_len -= sizeof (struct in_addr); + state->ri.remote_address.address.ipv4 = *v4; + break; + case AF_INET6: + if (pkt_len < sizeof (struct in6_addr)) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + if (! ipv6_exit) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + v6 = (const struct in6_addr*) &msg[1]; + payload = &v6[1]; + pkt_len -= sizeof (struct in_addr); + state->ri.remote_address.address.ipv6 = *v6; + break; + default: + GNUNET_break_op (0); + return GNUNET_SYSERR; } - + { + char buf[INET6_ADDRSTRLEN]; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received data from %s for forwarding to UDP %s:%u\n", + GNUNET_i2s (sender), + inet_ntop (af, + &state->ri.remote_address.address, + buf, sizeof (buf)), + (unsigned int) ntohs (msg->destination_port)); + } + state->ri.remote_address.proto = IPPROTO_UDP; + state->ri.remote_address.port = msg->destination_port; + if (NULL == state->heap_node) + setup_state_record (state); + if (0 != ntohs (msg->source_port)) + state->ri.local_address.port = msg->source_port; send_udp_packet_via_tun (&state->ri.remote_address, &state->ri.local_address, - &pkt[1], pkt_len - sizeof (struct udp_packet)); + payload, pkt_len); return GNUNET_YES; } /** - * FIXME: document! + * Process a request via mesh to send a request to a UDP service + * offered by this system. + * + * @param cls closure, NULL + * @param tunnel connection to the other end + * @param tunnel_ctx pointer to our 'struct TunnelState *' + * @param sender who sent the message + * @param message the actual message + * @param atsi performance data for the connection + * @return GNUNET_OK to keep the connection open, + * GNUNET_SYSERR to close it (signal serious error) */ static int receive_udp_service (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel, @@ -1516,43 +1768,47 @@ receive_udp_service (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel, const struct GNUNET_ATS_Information *atsi GNUNET_UNUSED) { struct TunnelState *state = *tunnel_ctx; - // FIXME: write proper request struct (we don't need UDP except dpt either!) - const GNUNET_HashCode *desc = (const GNUNET_HashCode *) &message[1]; - const struct udp_packet *pkt = (const struct udp_packet *) &desc[1]; + const struct GNUNET_EXIT_UdpServiceMessage *msg; uint16_t pkt_len = ntohs (message->size); - + GNUNET_STATISTICS_update (stats, + gettext_noop ("# Bytes received from MESH"), + pkt_len, GNUNET_NO); + GNUNET_STATISTICS_update (stats, + gettext_noop ("# UDP service requests received via mesh"), + 1, GNUNET_NO); /* check that we got at least a valid header */ - if (pkt_len < sizeof (struct GNUNET_MessageHeader) + sizeof (GNUNET_HashCode) + sizeof (struct udp_packet)) + if (pkt_len < sizeof (struct GNUNET_EXIT_UdpServiceMessage)) { GNUNET_break_op (0); - return GNUNET_YES; + return GNUNET_SYSERR; } - pkt_len -= (sizeof (struct GNUNET_MessageHeader) + sizeof (GNUNET_HashCode)); - - GNUNET_assert (ntohs (pkt->len) == - ntohs (message->size) - sizeof (struct GNUNET_MessageHeader) - - sizeof (GNUNET_HashCode)); - - if (NULL == state->serv) + msg = (const struct GNUNET_EXIT_UdpServiceMessage*) message; + pkt_len -= sizeof (struct GNUNET_EXIT_UdpServiceMessage); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received data from %s for forwarding to UDP service %s on port %u\n", + GNUNET_i2s (sender), + GNUNET_h2s (&msg->service_descriptor), + (unsigned int) ntohs (msg->destination_port)); + if (NULL == (state->serv = find_service (udp_services, &msg->service_descriptor, + ntohs (msg->destination_port)))) { - /* setup fresh connection */ - GNUNET_assert (NULL == state->heap_node); - if (NULL == (state->serv = find_service (udp_services, desc, ntohs (pkt->dpt)))) - { - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - _("No service found for %s on port %d!\n"), - "UDP", - ntohs (pkt->dpt)); - GNUNET_MESH_tunnel_destroy (state->tunnel); - return GNUNET_YES; - } - state->ri.remote_address = state->serv->address; - setup_state_record (state); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _("No service found for %s on port %d!\n"), + "UDP", + ntohs (msg->destination_port)); + GNUNET_STATISTICS_update (stats, + gettext_noop ("# UDP requests dropped (no such service)"), + 1, GNUNET_NO); + return GNUNET_SYSERR; } + state->ri.remote_address = state->serv->address; + setup_state_record (state); + if (0 != ntohs (msg->source_port)) + state->ri.local_address.port = msg->source_port; send_udp_packet_via_tun (&state->ri.remote_address, &state->ri.local_address, - &pkt[1], pkt_len - sizeof (struct udp_packet)); + &msg[1], pkt_len); return GNUNET_YES; } @@ -1572,7 +1828,13 @@ new_tunnel (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel, const struct GNUNET_ATS_Information *ats GNUNET_UNUSED) { struct TunnelState *s = GNUNET_malloc (sizeof (struct TunnelState)); - + + GNUNET_STATISTICS_update (stats, + gettext_noop ("# Inbound MESH tunnels created"), + 1, GNUNET_NO); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received inbound tunnel from `%s'\n", + GNUNET_i2s (initiator)); s->tunnel = tunnel; return s; } @@ -1594,6 +1856,8 @@ clean_tunnel (void *cls GNUNET_UNUSED, const struct GNUNET_MESH_Tunnel *tunnel, struct TunnelState *s = tunnel_ctx; struct TunnelMessageQueue *tnq; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Tunnel destroyed\n"); while (NULL != (tnq = s->head)) { GNUNET_CONTAINER_DLL_remove (s->head, @@ -1644,6 +1908,8 @@ cleanup (void *cls GNUNET_UNUSED, { unsigned int i; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Exit service is shutting down now\n"); if (helper_handle != NULL) { GNUNET_HELPER_stop (helper_handle); @@ -1677,6 +1943,11 @@ cleanup (void *cls GNUNET_UNUSED, GNUNET_CONTAINER_multihashmap_destroy (udp_services); udp_services = NULL; } + if (stats != NULL) + { + GNUNET_STATISTICS_destroy (stats, GNUNET_YES); + stats = NULL; + } for (i=0;i<5;i++) GNUNET_free_non_null (exit_argv[i]); } @@ -1777,12 +2048,30 @@ add_services (int proto, serv->address.af = res->ai_family; switch (res->ai_family) { - case AF_INET: - serv->address.address.ipv4 = ((struct sockaddr_in *) res->ai_addr)->sin_addr; - break; - case AF_INET6: - serv->address.address.ipv6 = ((struct sockaddr_in6 *) res->ai_addr)->sin6_addr; - break; + case AF_INET: + if (! ipv4_enabled) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _("Service `%s' configured for IPv4, but IPv4 is disabled!\n"), + name); + freeaddrinfo (res); + GNUNET_free (serv); + continue; + } + serv->address.address.ipv4 = ((struct sockaddr_in *) res->ai_addr)->sin_addr; + break; + case AF_INET6: + if (! ipv6_enabled) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _("Service `%s' configured for IPv4, but IPv4 is disabled!\n"), + name); + freeaddrinfo (res); + GNUNET_free (serv); + continue; + } + serv->address.address.ipv6 = ((struct sockaddr_in6 *) res->ai_addr)->sin6_addr; + break; default: freeaddrinfo (res); GNUNET_log (GNUNET_ERROR_TYPE_WARNING, @@ -1847,10 +2136,11 @@ run (void *cls, char *const *args GNUNET_UNUSED, const struct GNUNET_CONFIGURATION_Handle *cfg_) { static struct GNUNET_MESH_MessageHandler handlers[] = { - {&receive_udp_service, GNUNET_MESSAGE_TYPE_VPN_SERVICE_UDP, 0}, - {&receive_tcp_service, GNUNET_MESSAGE_TYPE_VPN_SERVICE_TCP, 0}, - {NULL, 0, 0}, - {NULL, 0, 0}, + {&receive_udp_service, GNUNET_MESSAGE_TYPE_VPN_UDP_TO_SERVICE, 0}, + {&receive_udp_remote, GNUNET_MESSAGE_TYPE_VPN_UDP_TO_INTERNET, 0}, + {&receive_tcp_service, GNUNET_MESSAGE_TYPE_VPN_TCP_TO_SERVICE_START, 0}, + {&receive_tcp_remote, GNUNET_MESSAGE_TYPE_VPN_TCP_TO_INTERNET_START, 0}, + {&receive_tcp_data, GNUNET_MESSAGE_TYPE_VPN_TCP_DATA, 0}, {NULL, 0, 0} }; @@ -1859,112 +2149,155 @@ run (void *cls, char *const *args GNUNET_UNUSED, GNUNET_APPLICATION_TYPE_END, GNUNET_APPLICATION_TYPE_END }; - unsigned int handler_idx; unsigned int app_idx; - int udp; - int tcp; - char *ifname; + char *exit_ifname; + char *tun_ifname; char *ipv6addr; char *ipv6prefix_s; char *ipv4addr; char *ipv4mask; - struct in_addr v4; - struct in6_addr v6; cfg = cfg_; - GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &cleanup, cls); - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_number (cfg, "exit", "MAX_CONNECTIONS", - &max_connections)) - max_connections = 1024; - exit_argv[0] = GNUNET_strdup ("exit-gnunet"); - if (GNUNET_SYSERR == - GNUNET_CONFIGURATION_get_value_string (cfg, "exit", "IFNAME", &ifname)) + stats = GNUNET_STATISTICS_create ("exit", cfg); + ipv4_exit = GNUNET_CONFIGURATION_get_value_yesno (cfg, "exit", "EXIT_IPV4"); + ipv6_exit = GNUNET_CONFIGURATION_get_value_yesno (cfg, "exit", "EXIT_IPV6"); + ipv4_enabled = GNUNET_CONFIGURATION_get_value_yesno (cfg, "exit", "ENABLE_IPV4"); + ipv6_enabled = GNUNET_CONFIGURATION_get_value_yesno (cfg, "exit", "ENABLE_IPV6"); + if (ipv4_exit && (! ipv4_enabled)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "No entry 'IFNAME' in configuration!\n"); - GNUNET_SCHEDULER_shutdown (); - return; + _("Cannot enable IPv4 exit but disable IPv4 on TUN interface, will use ENABLE_IPv4=YES\n")); + ipv4_enabled = GNUNET_YES; } - exit_argv[1] = ifname; - if ( (GNUNET_SYSERR == - GNUNET_CONFIGURATION_get_value_string (cfg, "exit", "IPV6ADDR", - &ipv6addr) || - (1 != inet_pton (AF_INET6, ipv6addr, &v6))) ) + if (ipv6_exit && (! ipv6_enabled)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "No valid entry 'IPV6ADDR' in configuration!\n"); - GNUNET_SCHEDULER_shutdown (); - return; + _("Cannot enable IPv6 exit but disable IPv6 on TUN interface, will use ENABLE_IPv6=YES\n")); + ipv6_enabled = GNUNET_YES; } - exit_argv[2] = ipv6addr; - if (GNUNET_SYSERR == - GNUNET_CONFIGURATION_get_value_string (cfg, "exit", "IPV6PREFIX", - &ipv6prefix_s)) + if (! (ipv4_enabled || ipv6_enabled)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "No entry 'IPV6PREFIX' in configuration!\n"); + _("No useful service enabled. Exiting.\n")); GNUNET_SCHEDULER_shutdown (); - return; + return; } - exit_argv[3] = ipv6prefix_s; - if ( (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_number (cfg, "exit", - "IPV6PREFIX", - &ipv6prefix)) || - (ipv6prefix >= 127) ) + app_idx = 0; + if (GNUNET_YES == ipv4_exit) { - GNUNET_SCHEDULER_shutdown (); - return; + apptypes[app_idx] = GNUNET_APPLICATION_TYPE_IPV4_GATEWAY; + app_idx++; } + if (GNUNET_YES == ipv6_exit) + { + apptypes[app_idx] = GNUNET_APPLICATION_TYPE_IPV6_GATEWAY; + app_idx++; + } + + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &cleanup, cls); - if ( (GNUNET_SYSERR == - GNUNET_CONFIGURATION_get_value_string (cfg, "exit", "IPV4ADDR", - &ipv4addr) || - (1 != inet_pton (AF_INET, ipv4addr, &v4))) ) + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_number (cfg, "exit", "MAX_CONNECTIONS", + &max_connections)) + max_connections = 1024; + exit_argv[0] = GNUNET_strdup ("exit-gnunet"); + if (GNUNET_SYSERR == + GNUNET_CONFIGURATION_get_value_string (cfg, "exit", "TUN_IFNAME", &tun_ifname)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "No valid entry for 'IPV4ADDR' in configuration!\n"); + "No entry 'TUN_IFNAME' in configuration!\n"); GNUNET_SCHEDULER_shutdown (); return; } - exit_argv[4] = ipv4addr; - if ( (GNUNET_SYSERR == - GNUNET_CONFIGURATION_get_value_string (cfg, "exit", "IPV4MASK", - &ipv4mask) || - (1 != inet_pton (AF_INET, ipv4mask, &v4))) ) + exit_argv[1] = tun_ifname; + if (ipv4_enabled) { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "No valid entry 'IPV4MASK' in configuration!\n"); - GNUNET_SCHEDULER_shutdown (); - return; + if (GNUNET_SYSERR == + GNUNET_CONFIGURATION_get_value_string (cfg, "exit", "EXIT_IFNAME", &exit_ifname)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "No entry 'EXIT_IFNAME' in configuration!\n"); + GNUNET_SCHEDULER_shutdown (); + return; + } + exit_argv[2] = exit_ifname; } - exit_argv[5] = ipv4mask; - exit_argv[6] = NULL; - - app_idx = 0; - handler_idx = 2; - udp = GNUNET_CONFIGURATION_get_value_yesno (cfg, "exit", "ENABLE_UDP"); - tcp = GNUNET_CONFIGURATION_get_value_yesno (cfg, "exit", "ENABLE_TCP"); - if (GNUNET_YES == udp) - { - handlers[handler_idx].callback = &receive_udp_remote; - handlers[handler_idx].expected_size = 0; - handlers[handler_idx].type = GNUNET_MESSAGE_TYPE_VPN_REMOTE_UDP; - apptypes[app_idx] = GNUNET_APPLICATION_TYPE_INTERNET_UDP_GATEWAY; - handler_idx++; - app_idx++; + else + { + exit_argv[2] = GNUNET_strdup ("%"); } - - if (GNUNET_YES == tcp) + if (GNUNET_YES == ipv6_enabled) { - handlers[handler_idx].callback = &receive_tcp_remote; - handlers[handler_idx].expected_size = 0; - handlers[handler_idx].type = GNUNET_MESSAGE_TYPE_VPN_REMOTE_TCP; - apptypes[app_idx] = GNUNET_APPLICATION_TYPE_INTERNET_TCP_GATEWAY; - handler_idx++; - app_idx++; + if ( (GNUNET_SYSERR == + GNUNET_CONFIGURATION_get_value_string (cfg, "exit", "IPV6ADDR", + &ipv6addr) || + (1 != inet_pton (AF_INET6, ipv6addr, &exit_ipv6addr))) ) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "No valid entry 'IPV6ADDR' in configuration!\n"); + GNUNET_SCHEDULER_shutdown (); + return; + } + exit_argv[3] = ipv6addr; + if (GNUNET_SYSERR == + GNUNET_CONFIGURATION_get_value_string (cfg, "exit", "IPV6PREFIX", + &ipv6prefix_s)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "No entry 'IPV6PREFIX' in configuration!\n"); + GNUNET_SCHEDULER_shutdown (); + return; + } + exit_argv[4] = ipv6prefix_s; + if ( (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_number (cfg, "exit", + "IPV6PREFIX", + &ipv6prefix)) || + (ipv6prefix >= 127) ) + { + GNUNET_SCHEDULER_shutdown (); + return; + } + } + else + { + /* IPv6 explicitly disabled */ + exit_argv[3] = GNUNET_strdup ("-"); + exit_argv[4] = GNUNET_strdup ("-"); } + if (GNUNET_YES == ipv4_enabled) + { + if ( (GNUNET_SYSERR == + GNUNET_CONFIGURATION_get_value_string (cfg, "exit", "IPV4ADDR", + &ipv4addr) || + (1 != inet_pton (AF_INET, ipv4addr, &exit_ipv4addr))) ) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "No valid entry for 'IPV4ADDR' in configuration!\n"); + GNUNET_SCHEDULER_shutdown (); + return; + } + exit_argv[5] = ipv4addr; + if ( (GNUNET_SYSERR == + GNUNET_CONFIGURATION_get_value_string (cfg, "exit", "IPV4MASK", + &ipv4mask) || + (1 != inet_pton (AF_INET, ipv4mask, &exit_ipv4mask))) ) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "No valid entry 'IPV4MASK' in configuration!\n"); + GNUNET_SCHEDULER_shutdown (); + return; + } + exit_argv[6] = ipv4mask; + } + else + { + /* IPv4 explicitly disabled */ + exit_argv[5] = GNUNET_strdup ("-"); + exit_argv[6] = GNUNET_strdup ("-"); + } + exit_argv[7] = NULL; + udp_services = GNUNET_CONTAINER_multihashmap_create (65536); tcp_services = GNUNET_CONTAINER_multihashmap_create (65536); GNUNET_CONFIGURATION_iterate_sections (cfg, &read_service_conf, NULL); @@ -1981,7 +2314,7 @@ run (void *cls, char *const *args GNUNET_UNUSED, GNUNET_SCHEDULER_shutdown (); return; } - helper_handle = GNUNET_HELPER_start ("gnunet-helper-vpn", + helper_handle = GNUNET_HELPER_start ("gnunet-helper-exit", exit_argv, &message_token, NULL); }