From: Christian Grothoff Date: Thu, 23 Feb 2017 13:08:07 +0000 (+0100) Subject: convert EXIT to new CADET MQ API X-Git-Tag: taler-0.2.1~70^2~26 X-Git-Url: https://git.librecmc.org/?a=commitdiff_plain;h=450f962ef7349f2f08fbda705e92acb87884af71;p=oweals%2Fgnunet.git convert EXIT to new CADET MQ API --- diff --git a/src/exit/Makefile.am b/src/exit/Makefile.am index 6c4cbf114..271b4ebd7 100644 --- a/src/exit/Makefile.am +++ b/src/exit/Makefile.am @@ -30,11 +30,11 @@ endif libexec_PROGRAMS = \ gnunet-daemon-exit \ - $(EXITBIN) + $(EXITBIN) if MINGW gnunet_helper_exit_LDFLAGS = \ - -no-undefined -Wl,--export-all-symbols + -no-undefined -Wl,--export-all-symbols gnunet_helper_exit_LDADD = \ -lsetupapi -lnewdev -lshell32 -liconv -lstdc++ \ @@ -47,13 +47,13 @@ else gnunet-helper-exit.c endif gnunet_daemon_exit_SOURCES = \ - gnunet-daemon-exit.c exit.h + gnunet-daemon-exit.c exit.h gnunet_daemon_exit_LDADD = \ $(top_builddir)/src/dns/libgnunetdnsstub.la \ $(top_builddir)/src/dht/libgnunetdht.la \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ $(top_builddir)/src/tun/libgnunettun.la \ $(top_builddir)/src/util/libgnunetutil.la \ - $(top_builddir)/src/cadet/libgnunetcadet.la \ + $(top_builddir)/src/cadet/libgnunetcadetnew.la \ $(top_builddir)/src/regex/libgnunetregex.la \ $(GN_LIBINTL) diff --git a/src/exit/gnunet-daemon-exit.c b/src/exit/gnunet-daemon-exit.c index 92acc61cd..09576e393 100644 --- a/src/exit/gnunet-daemon-exit.c +++ b/src/exit/gnunet-daemon-exit.c @@ -1,6 +1,6 @@ /* This file is part of GNUnet. - Copyright (C) 2010-2013 Christian Grothoff + Copyright (C) 2010-2013, 2017 Christian Grothoff GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published @@ -194,33 +194,6 @@ struct RedirectInformation }; -/** - * Queue of messages to a channel. - */ -struct ChannelMessageQueue -{ - /** - * This is a doubly-linked list. - */ - struct ChannelMessageQueue *next; - - /** - * This is a doubly-linked list. - */ - struct ChannelMessageQueue *prev; - - /** - * Payload to send via the channel. - */ - const void *payload; - - /** - * Number of bytes in @e payload. - */ - size_t len; -}; - - /** * This struct is saved into #connections_map to allow finding the * right channel given an IP packet from TUN. It is also associated @@ -240,11 +213,6 @@ struct ChannelState */ struct GNUNET_PeerIdentity peer; - /** - * Active channel transmission request (or NULL). - */ - struct GNUNET_CADET_TransmitHandle *th; - /** * #GNUNET_NO if this is a channel for TCP/UDP, * #GNUNET_YES if this is a channel for DNS, @@ -272,16 +240,6 @@ struct ChannelState */ struct LocalService *serv; - /** - * Head of DLL of messages for this channel. - */ - struct ChannelMessageQueue *head; - - /** - * Tail of DLL of messages for this channel. - */ - struct ChannelMessageQueue *tail; - /** * Primary redirection information for this connection. */ @@ -291,22 +249,12 @@ struct ChannelState struct { - /** - * DNS reply ready for transmission. - */ - char *reply; - /** * Socket we are using to transmit this request (must match if we receive * a response). */ struct GNUNET_DNSSTUB_RequestSocket *rs; - /** - * Number of bytes in 'reply'. - */ - size_t reply_length; - /** * Original DNS request ID as used by the client. */ @@ -428,7 +376,7 @@ static struct GNUNET_DHT_Handle *dht; /** * Task for doing DHT PUTs to advertise exit service. */ -static struct GNUNET_SCHEDULER_Task * dht_task; +static struct GNUNET_SCHEDULER_Task *dht_task; /** * Advertisement message we put into the DHT to advertise us @@ -446,6 +394,21 @@ static struct GNUNET_HashCode dht_put_key; */ static struct GNUNET_CRYPTO_EddsaPrivateKey *peer_key; +/** + * Port for DNS exit. + */ +static struct GNUNET_CADET_Port *dns_port; + +/** + * Port for IPv4 exit. + */ +static struct GNUNET_CADET_Port *cadet_port4; + +/** + * Port for IPv6 exit. + */ +static struct GNUNET_CADET_Port *cadet_port6; + /** * Are we an IPv4-exit? */ @@ -467,51 +430,27 @@ static int ipv4_enabled; static int ipv6_enabled; +GNUNET_NETWORK_STRUCT_BEGIN + /** - * We got a reply from DNS for a request of a CADET channel. Send it - * via the channel (after changing the request ID back). - * - * @param cls the `struct ChannelState` - * @param size number of bytes available in @a buf - * @param buf where to copy the reply - * @return number of bytes written to @a buf - */ -static size_t -transmit_reply_to_cadet (void *cls, - size_t size, - void *buf) + * Message with a DNS response. + */ +struct DnsResponseMessage { - struct ChannelState *ts = cls; - size_t off; - size_t ret; - char *cbuf = buf; - struct GNUNET_MessageHeader hdr; + /** + * GNUnet header, of type #GNUNET_MESSAGE_TYPE_VPN_DNS_FROM_INTERNET + */ + struct GNUNET_MessageHeader header; + + /** + * DNS header. + */ struct GNUNET_TUN_DnsHeader dns; - GNUNET_assert (GNUNET_YES == ts->is_dns); - ts->th = NULL; - GNUNET_assert (ts->specifics.dns.reply != NULL); - if (size == 0) - return 0; - ret = sizeof (struct GNUNET_MessageHeader) + ts->specifics.dns.reply_length; - GNUNET_assert (ret <= size); - hdr.size = htons (ret); - hdr.type = htons (GNUNET_MESSAGE_TYPE_VPN_DNS_FROM_INTERNET); - GNUNET_memcpy (&dns, ts->specifics.dns.reply, sizeof (dns)); - dns.id = ts->specifics.dns.original_id; - off = 0; - GNUNET_memcpy (&cbuf[off], &hdr, sizeof (hdr)); - off += sizeof (hdr); - GNUNET_memcpy (&cbuf[off], &dns, sizeof (dns)); - off += sizeof (dns); - GNUNET_memcpy (&cbuf[off], &ts->specifics.dns.reply[sizeof (dns)], ts->specifics.dns.reply_length - sizeof (dns)); - off += ts->specifics.dns.reply_length - sizeof (dns); - GNUNET_free (ts->specifics.dns.reply); - ts->specifics.dns.reply = NULL; - ts->specifics.dns.reply_length = 0; - GNUNET_assert (ret == off); - return ret; -} + /* Followed by more DNS payload */ +}; + +GNUNET_NETWORK_STRUCT_END /** @@ -521,7 +460,7 @@ transmit_reply_to_cadet (void *cls, * @param cls NULL * @param rs the socket that received the response * @param dns the response itself - * @param r number of bytes in dns + * @param r number of bytes in @a dns */ static void process_dns_result (void *cls, @@ -530,6 +469,8 @@ process_dns_result (void *cls, size_t r) { struct ChannelState *ts; + struct GNUNET_MQ_Envelope *env; + struct DnsResponseMessage *resp; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Processing DNS result from stub resolver\n"); @@ -542,48 +483,35 @@ process_dns_result (void *cls, LOG (GNUNET_ERROR_TYPE_DEBUG, "Got a response from the stub resolver for DNS request received via CADET!\n"); channels[dns->id] = NULL; - GNUNET_free_non_null (ts->specifics.dns.reply); - ts->specifics.dns.reply = GNUNET_malloc (r); - ts->specifics.dns.reply_length = r; - GNUNET_memcpy (ts->specifics.dns.reply, dns, r); - if (NULL != ts->th) - GNUNET_CADET_notify_transmit_ready_cancel (ts->th); - ts->th = GNUNET_CADET_notify_transmit_ready (ts->channel, - GNUNET_NO, - GNUNET_TIME_UNIT_FOREVER_REL, - sizeof (struct GNUNET_MessageHeader) + r, - &transmit_reply_to_cadet, - ts); + env = GNUNET_MQ_msg_extra (resp, + r - sizeof (struct GNUNET_TUN_DnsHeader), + GNUNET_MESSAGE_TYPE_VPN_DNS_FROM_INTERNET); + GNUNET_memcpy (&resp->dns, + dns, + r); + resp->dns.id = ts->specifics.dns.original_id; + GNUNET_MQ_send (GNUNET_CADET_get_mq (ts->channel), + env); } /** - * Process a request via cadet to perform a DNS query. - * - * @param cls closure, NULL - * @param channel connection to the other end - * @param channel_ctx pointer to our `struct ChannelState *` - * @param message the actual message + * Check a request via cadet to perform a DNS query. * + * @param cls our `struct ChannelState *` + * @param msg the actual message * @return #GNUNET_OK to keep the connection open, * #GNUNET_SYSERR to close it (signal serious error) */ static int -receive_dns_request (void *cls GNUNET_UNUSED, - struct GNUNET_CADET_Channel *channel, - void **channel_ctx, - const struct GNUNET_MessageHeader *message) +check_dns_request (void *cls, + const struct DnsResponseMessage *msg) { - struct ChannelState *ts = *channel_ctx; - const struct GNUNET_TUN_DnsHeader *dns; - size_t mlen = ntohs (message->size); - size_t dlen = mlen - sizeof (struct GNUNET_MessageHeader); - char buf[dlen] GNUNET_ALIGN; - struct GNUNET_TUN_DnsHeader *dout; + struct ChannelState *ts = cls; if (NULL == dnsstub) { - GNUNET_break_op (0); + GNUNET_break (0); return GNUNET_SYSERR; } if (GNUNET_NO == ts->is_dns) @@ -591,34 +519,53 @@ receive_dns_request (void *cls GNUNET_UNUSED, GNUNET_break_op (0); return GNUNET_SYSERR; } + return GNUNET_OK; +} + + +/** + * Process a request via cadet to perform a DNS query. + * + * @param cls our `struct ChannelState *` + * @param msg the actual message + */ +static void +handle_dns_request (void *cls, + const struct DnsResponseMessage *msg) +{ + struct ChannelState *ts = cls; + size_t mlen = ntohs (msg->header.size); + size_t dlen = mlen - sizeof (struct GNUNET_MessageHeader); + char buf[dlen] GNUNET_ALIGN; + struct GNUNET_TUN_DnsHeader *dout; + if (GNUNET_SYSERR == ts->is_dns) { /* channel is DNS from now on */ ts->is_dns = GNUNET_YES; } - if (dlen < sizeof (struct GNUNET_TUN_DnsHeader)) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - dns = (const struct GNUNET_TUN_DnsHeader *) &message[1]; - ts->specifics.dns.original_id = dns->id; + ts->specifics.dns.original_id = msg->dns.id; if (channels[ts->specifics.dns.my_id] == ts) channels[ts->specifics.dns.my_id] = NULL; ts->specifics.dns.my_id = (uint16_t) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, - UINT16_MAX + 1); + UINT16_MAX + 1); channels[ts->specifics.dns.my_id] = ts; - GNUNET_memcpy (buf, dns, dlen); + GNUNET_memcpy (buf, + &msg->dns, + dlen); dout = (struct GNUNET_TUN_DnsHeader *) buf; dout->id = ts->specifics.dns.my_id; ts->specifics.dns.rs = GNUNET_DNSSTUB_resolve2 (dnsstub, - buf, dlen, + buf, + dlen, &process_dns_result, NULL); if (NULL == ts->specifics.dns.rs) - return GNUNET_SYSERR; - GNUNET_CADET_receive_done (channel); - return GNUNET_OK; + { + GNUNET_break_op (0); + return; + } + GNUNET_CADET_receive_done (ts->channel); } @@ -753,706 +700,445 @@ get_redirect_state (int af, } + /** - * Free memory associated with a service record. + * Check a request via cadet to send a request to a TCP service + * offered by this system. * - * @param cls unused - * @param key service descriptor - * @param value service record to free - * @return #GNUNET_OK + * @param cls our `struct ChannelState *` + * @param start the actual message + * @return #GNUNET_OK to keep the connection open, + * #GNUNET_SYSERR to close it (signal serious error) */ static int -free_service_record (void *cls, - const struct GNUNET_HashCode *key, - void *value) +check_tcp_service (void *cls, + const struct GNUNET_EXIT_TcpServiceStartMessage *start) { - struct LocalService *service = value; + struct ChannelState *state = cls; - GNUNET_assert (GNUNET_YES == - GNUNET_CONTAINER_multihashmap_remove (services, - key, - service)); - GNUNET_CADET_close_port (service->port); - GNUNET_free_non_null (service->name); - GNUNET_free (service); + if (NULL == state) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + if (GNUNET_YES == state->is_dns) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + if (NULL == state->specifics.tcp_udp.serv) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + if (NULL != state->specifics.tcp_udp.heap_node) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + if (start->tcp_header.off * 4 < sizeof (struct GNUNET_TUN_TcpHeader)) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } return GNUNET_OK; } /** - * Callback from CADET for new channels. - * - * @param cls closure - * @param channel new handle to the channel - * @param initiator peer that started the channel - * @param port destination port - * @param options channel options flags - * @return initial channel context for the channel - */ -static void * -new_service_channel (void *cls, - struct GNUNET_CADET_Channel *channel, - const struct GNUNET_PeerIdentity *initiator, - const struct GNUNET_HashCode *port, - enum GNUNET_CADET_ChannelOption options) -{ - struct LocalService *ls = cls; - struct ChannelState *s = GNUNET_new (struct ChannelState); - - s->peer = *initiator; - GNUNET_STATISTICS_update (stats, - gettext_noop ("# Inbound CADET channels created"), - 1, - GNUNET_NO); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Received inbound channel from `%s'\n", - GNUNET_i2s (initiator)); - s->channel = channel; - s->specifics.tcp_udp.serv = ls; - s->specifics.tcp_udp.ri.remote_address = ls->address; - return s; -} - - -/** - * Given a service descriptor and a destination port, find the - * respective service entry. + * 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 proto IPPROTO_TCP or IPPROTO_UDP - * @param name name of the service - * @param destination_port destination port - * @param service service information record to store (service->name will be set). + * @param payload payload of the packet (starting with UDP payload or + * TCP header, depending on protocol) + * @param payload_length number of bytes in @a payload + * @param protocol IPPROTO_UDP or IPPROTO_TCP + * @param tcp_header skeleton of the TCP header, NULL for UDP + * @param src_address source address to use (IP and port) + * @param dst_address destination address to use (IP and port) + * @param pkt4 where to write the assembled packet; must + * contain enough space for the IP header, UDP/TCP header + * AND the payload */ static void -store_service (int proto, - const char *name, - uint16_t destination_port, - struct LocalService *service) +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 GNUNET_TUN_IPv4Header *pkt4) { - struct GNUNET_HashCode cadet_port; + size_t len; - service->name = GNUNET_strdup (name); - GNUNET_TUN_service_name_to_hash (name, - &service->descriptor); - GNUNET_TUN_compute_service_cadet_port (&service->descriptor, - destination_port, - &cadet_port); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Opening CADET port %s for SERVICE exit %s on port %u\n", - GNUNET_h2s (&cadet_port), - name, - (unsigned int) destination_port); - service->port = GNUNET_CADET_open_port (cadet_handle, - &cadet_port, - &new_service_channel, - service); - service->is_udp = (IPPROTO_UDP == proto); - if (GNUNET_OK != - GNUNET_CONTAINER_multihashmap_put (services, - &cadet_port, - service, - GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)) + len = payload_length; + switch (protocol) { - GNUNET_CADET_close_port (service->port); - GNUNET_free_non_null (service->name); - GNUNET_free (service); - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - _("Got duplicate service records for `%s:%u'\n"), - name, - (unsigned int) destination_port); + case IPPROTO_UDP: + len += sizeof (struct GNUNET_TUN_UdpHeader); + break; + case IPPROTO_TCP: + len += sizeof (struct GNUNET_TUN_TcpHeader); + GNUNET_assert (NULL != tcp_header); + break; + default: + GNUNET_break (0); + return; + } + if (len + sizeof (struct GNUNET_TUN_IPv4Header) > UINT16_MAX) + { + GNUNET_break (0); + return; } -} + GNUNET_TUN_initialize_ipv4_header (pkt4, + protocol, + len, + &src_address->address.ipv4, + &dst_address->address.ipv4); + switch (protocol) + { + case IPPROTO_UDP: + { + struct GNUNET_TUN_UdpHeader *pkt4_udp = (struct GNUNET_TUN_UdpHeader *) &pkt4[1]; -/** - * CADET is ready to receive a message for the channel. Transmit it. - * - * @param cls the `struct ChannelState`. - * @param size number of bytes available in @a buf - * @param buf where to copy the message - * @return number of bytes copied to @a buf - */ -static size_t -send_to_peer_notify_callback (void *cls, - size_t size, - void *buf) -{ - struct ChannelState *s = cls; - struct GNUNET_CADET_Channel *channel = s->channel; - struct ChannelMessageQueue *tnq; - - s->th = NULL; - tnq = s->specifics.tcp_udp.head; - if (NULL == tnq) - return 0; - if (0 == size) - { - s->th = GNUNET_CADET_notify_transmit_ready (channel, - GNUNET_NO /* corking */, - GNUNET_TIME_UNIT_FOREVER_REL, - tnq->len, - &send_to_peer_notify_callback, - s); - return 0; - } - GNUNET_assert (size >= tnq->len); - GNUNET_memcpy (buf, tnq->payload, tnq->len); - size = tnq->len; - GNUNET_CONTAINER_DLL_remove (s->specifics.tcp_udp.head, - s->specifics.tcp_udp.tail, - tnq); - GNUNET_free (tnq); - if (NULL != (tnq = s->specifics.tcp_udp.head)) - s->th = GNUNET_CADET_notify_transmit_ready (channel, - GNUNET_NO /* corking */, - GNUNET_TIME_UNIT_FOREVER_REL, - tnq->len, - &send_to_peer_notify_callback, - s); - GNUNET_STATISTICS_update (stats, - gettext_noop ("# Bytes transmitted via cadet channels"), - size, GNUNET_NO); - return size; + pkt4_udp->source_port = htons (src_address->port); + pkt4_udp->destination_port = htons (dst_address->port); + pkt4_udp->len = htons ((uint16_t) payload_length); + GNUNET_TUN_calculate_udp4_checksum (pkt4, + pkt4_udp, + payload, + payload_length); + GNUNET_memcpy (&pkt4_udp[1], + payload, + payload_length); + } + break; + case IPPROTO_TCP: + { + struct GNUNET_TUN_TcpHeader *pkt4_tcp = (struct GNUNET_TUN_TcpHeader *) &pkt4[1]; + + *pkt4_tcp = *tcp_header; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Sending TCP packet from port %u to port %u\n", + src_address->port, + dst_address->port); + pkt4_tcp->source_port = htons (src_address->port); + pkt4_tcp->destination_port = htons (dst_address->port); + GNUNET_TUN_calculate_tcp4_checksum (pkt4, + pkt4_tcp, + payload, + payload_length); + GNUNET_memcpy (&pkt4_tcp[1], + payload, + payload_length); + } + break; + default: + GNUNET_assert (0); + } } /** - * Send the given packet via the cadet channel. + * 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 s channel destination - * @param tnq message to queue + * @param payload payload of the packet (starting with UDP payload or + * TCP header, depending on protocol) + * @param payload_length number of bytes in @a payload + * @param protocol IPPROTO_UDP or IPPROTO_TCP + * @param tcp_header skeleton TCP header data to send, NULL for UDP + * @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 -send_packet_to_cadet_channel (struct ChannelState *s, - struct ChannelMessageQueue *tnq) +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 GNUNET_TUN_IPv6Header *pkt6) { - struct GNUNET_CADET_Channel *cadet_channel; + size_t len; - cadet_channel = s->channel; - GNUNET_assert (NULL != s); - GNUNET_CONTAINER_DLL_insert_tail (s->specifics.tcp_udp.head, - s->specifics.tcp_udp.tail, - tnq); - if (NULL == s->th) - s->th = GNUNET_CADET_notify_transmit_ready (cadet_channel, - GNUNET_NO /* cork */, - GNUNET_TIME_UNIT_FOREVER_REL, - tnq->len, - &send_to_peer_notify_callback, - s); + len = payload_length; + switch (protocol) + { + case IPPROTO_UDP: + len += sizeof (struct GNUNET_TUN_UdpHeader); + break; + case IPPROTO_TCP: + len += sizeof (struct GNUNET_TUN_TcpHeader); + break; + default: + GNUNET_break (0); + return; + } + if (len > UINT16_MAX) + { + GNUNET_break (0); + return; + } + + GNUNET_TUN_initialize_ipv6_header (pkt6, + protocol, + len, + &src_address->address.ipv6, + &dst_address->address.ipv6); + + switch (protocol) + { + case IPPROTO_UDP: + { + struct GNUNET_TUN_UdpHeader *pkt6_udp = (struct GNUNET_TUN_UdpHeader *) &pkt6[1]; + + pkt6_udp->source_port = htons (src_address->port); + pkt6_udp->destination_port = htons (dst_address->port); + pkt6_udp->len = htons ((uint16_t) payload_length); + GNUNET_TUN_calculate_udp6_checksum (pkt6, + pkt6_udp, + payload, + payload_length); + GNUNET_memcpy (&pkt6_udp[1], + payload, + payload_length); + } + break; + case IPPROTO_TCP: + { + struct GNUNET_TUN_TcpHeader *pkt6_tcp = (struct GNUNET_TUN_TcpHeader *) &pkt6[1]; + + /* GNUNET_memcpy first here as some TCP header fields are initialized this way! */ + *pkt6_tcp = *tcp_header; + pkt6_tcp->source_port = htons (src_address->port); + pkt6_tcp->destination_port = htons (dst_address->port); + GNUNET_TUN_calculate_tcp6_checksum (pkt6, + pkt6_tcp, + payload, + payload_length); + GNUNET_memcpy (&pkt6_tcp[1], + payload, + payload_length); + } + break; + default: + GNUNET_assert (0); + break; + } } /** - * @brief Handles an ICMP packet received from the helper. + * Send a TCP packet via the TUN interface. * - * @param icmp A pointer to the Packet - * @param pktlen number of bytes in @a icmp - * @param af address family (AFINET or AF_INET6) - * @param destination_ip destination IP-address of the IP packet (should - * be our local address) - * @param source_ip original source IP-address of the IP packet (should - * be the original destination address) + * @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 header template to use + * @param payload payload of the TCP packet + * @param payload_length number of bytes in @a payload */ static void -icmp_from_helper (const struct GNUNET_TUN_IcmpHeader *icmp, - size_t pktlen, - int af, - const void *destination_ip, - const void *source_ip) +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) { - struct ChannelState *state; - struct ChannelMessageQueue *tnq; - struct GNUNET_EXIT_IcmpToVPNMessage *i2v; - const struct GNUNET_TUN_IPv4Header *ipv4; - const struct GNUNET_TUN_IPv6Header *ipv6; - const struct GNUNET_TUN_UdpHeader *udp; - size_t mlen; - uint16_t source_port; - uint16_t destination_port; - uint8_t protocol; + size_t len; + 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) { - char sbuf[INET6_ADDRSTRLEN]; - char dbuf[INET6_ADDRSTRLEN]; - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Received ICMP packet going from %s to %s\n", - inet_ntop (af, - source_ip, - sbuf, sizeof (sbuf)), - inet_ntop (af, - destination_ip, - dbuf, sizeof (dbuf))); + case AF_INET: + len += sizeof (struct GNUNET_TUN_IPv4Header); + break; + case AF_INET6: + len += sizeof (struct GNUNET_TUN_IPv6Header); + break; + default: + GNUNET_break (0); + return; } - if (pktlen < sizeof (struct GNUNET_TUN_IcmpHeader)) + len += sizeof (struct GNUNET_TUN_TcpHeader); + len += payload_length; + if (len >= GNUNET_SERVER_MAX_MESSAGE_SIZE) { - /* blame kernel */ GNUNET_break (0); return; } - - /* Find out if this is an ICMP packet in response to an existing - TCP/UDP packet and if so, figure out ports / protocol of the - existing session from the IP data in the ICMP payload */ - source_port = 0; - destination_port = 0; - switch (af) { - case AF_INET: - protocol = IPPROTO_ICMP; - switch (icmp->type) - { - case GNUNET_TUN_ICMPTYPE_ECHO_REPLY: - case GNUNET_TUN_ICMPTYPE_ECHO_REQUEST: - break; - case GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE: - case GNUNET_TUN_ICMPTYPE_SOURCE_QUENCH: - case GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED: - if (pktlen < - sizeof (struct GNUNET_TUN_IcmpHeader) + - sizeof (struct GNUNET_TUN_IPv4Header) + 8) - { - /* blame kernel */ - GNUNET_break (0); - return; - } - ipv4 = (const struct GNUNET_TUN_IPv4Header *) &icmp[1]; - protocol = ipv4->protocol; - /* could be TCP or UDP, but both have the ports in the right - place, so that doesn't matter here */ - udp = (const struct GNUNET_TUN_UdpHeader *) &ipv4[1]; - /* swap ports, as they are from the original message */ - destination_port = ntohs (udp->source_port); - source_port = ntohs (udp->destination_port); - /* throw away ICMP payload, won't be useful for the other side anyway */ - pktlen = sizeof (struct GNUNET_TUN_IcmpHeader); - break; - default: - GNUNET_STATISTICS_update (stats, - gettext_noop ("# ICMPv4 packets dropped (type not allowed)"), - 1, GNUNET_NO); - return; - } - break; - case AF_INET6: - protocol = IPPROTO_ICMPV6; - switch (icmp->type) + char buf[len] GNUNET_ALIGN; + struct GNUNET_MessageHeader *hdr; + struct GNUNET_TUN_Layer2PacketHeader *tun; + + hdr = (struct GNUNET_MessageHeader *) buf; + hdr->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER); + hdr->size = htons (len); + tun = (struct GNUNET_TUN_Layer2PacketHeader*) &hdr[1]; + tun->flags = htons (0); + switch (source_address->af) + { + case AF_INET: { - case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE: - case GNUNET_TUN_ICMPTYPE6_PACKET_TOO_BIG: - case GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED: - case GNUNET_TUN_ICMPTYPE6_PARAMETER_PROBLEM: - if (pktlen < - sizeof (struct GNUNET_TUN_IcmpHeader) + - sizeof (struct GNUNET_TUN_IPv6Header) + 8) - { - /* blame kernel */ - GNUNET_break (0); - return; - } - ipv6 = (const struct GNUNET_TUN_IPv6Header *) &icmp[1]; - protocol = ipv6->next_header; - /* could be TCP or UDP, but both have the ports in the right - place, so that doesn't matter here */ - udp = (const struct GNUNET_TUN_UdpHeader *) &ipv6[1]; - /* swap ports, as they are from the original message */ - destination_port = ntohs (udp->source_port); - source_port = ntohs (udp->destination_port); - /* throw away ICMP payload, won't be useful for the other side anyway */ - pktlen = sizeof (struct GNUNET_TUN_IcmpHeader); - break; - case GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST: - case GNUNET_TUN_ICMPTYPE6_ECHO_REPLY: - break; - default: - GNUNET_STATISTICS_update (stats, - gettext_noop ("# ICMPv6 packets dropped (type not allowed)"), - 1, GNUNET_NO); - return; + 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, + tcp_header, + source_address, + destination_address, + ipv4); } - break; - default: - GNUNET_assert (0); - } - switch (protocol) - { - case IPPROTO_ICMP: - state = get_redirect_state (af, - IPPROTO_ICMP, - source_ip, - 0, - destination_ip, - 0, - NULL); - break; - case IPPROTO_ICMPV6: - state = get_redirect_state (af, - IPPROTO_ICMPV6, - source_ip, - 0, - destination_ip, - 0, - NULL); - break; - case IPPROTO_UDP: - state = get_redirect_state (af, - IPPROTO_UDP, - source_ip, - source_port, - destination_ip, - destination_port, - NULL); - break; - case IPPROTO_TCP: - state = get_redirect_state (af, - IPPROTO_TCP, - source_ip, - source_port, - destination_ip, - destination_port, - NULL); - break; - default: - GNUNET_STATISTICS_update (stats, - gettext_noop ("# ICMP packets dropped (not allowed)"), - 1, - GNUNET_NO); - return; - } - if (NULL == state) - { - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - _("ICMP Packet dropped, have no matching connection information\n")); - return; + break; + case AF_INET6: + { + 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, + tcp_header, + source_address, + destination_address, + ipv6); + } + break; + default: + GNUNET_assert (0); + break; + } + if (NULL != helper_handle) + (void) GNUNET_HELPER_send (helper_handle, + (const struct GNUNET_MessageHeader*) buf, + GNUNET_YES, + NULL, + NULL); } - mlen = sizeof (struct GNUNET_EXIT_IcmpToVPNMessage) + pktlen - sizeof (struct GNUNET_TUN_IcmpHeader); - tnq = GNUNET_malloc (sizeof (struct ChannelMessageQueue) + mlen); - tnq->payload = &tnq[1]; - tnq->len = mlen; - i2v = (struct GNUNET_EXIT_IcmpToVPNMessage *) &tnq[1]; - i2v->header.size = htons ((uint16_t) mlen); - i2v->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_ICMP_TO_VPN); - i2v->af = htonl (af); - GNUNET_memcpy (&i2v->icmp_header, - icmp, - pktlen); - send_packet_to_cadet_channel (state, tnq); } /** - * @brief Handles an UDP packet received from the helper. + * Send an ICMP packet via the TUN interface. * - * @param udp A pointer to the Packet - * @param pktlen number of bytes in 'udp' - * @param af address family (AFINET or AF_INET6) - * @param destination_ip destination IP-address of the IP packet (should - * be our local address) - * @param source_ip original source IP-address of the IP packet (should - * be the original destination address) + * @param destination_address IP to use for the ICMP packet's destination + * @param source_address IP to use for the ICMP packet's source + * @param icmp_header ICMP header to send + * @param payload payload of the ICMP packet (does NOT include ICMP header) + * @param payload_length number of bytes of data in @a payload */ static void -udp_from_helper (const struct GNUNET_TUN_UdpHeader *udp, - size_t pktlen, - int af, - const void *destination_ip, - const void *source_ip) +send_icmp_packet_via_tun (const struct SocketAddress *destination_address, + const struct SocketAddress *source_address, + const struct GNUNET_TUN_IcmpHeader *icmp_header, + const void *payload, size_t payload_length) { - struct ChannelState *state; - struct ChannelMessageQueue *tnq; - struct GNUNET_EXIT_UdpReplyMessage *urm; - size_t mlen; + size_t len; + struct GNUNET_TUN_IcmpHeader *icmp; + GNUNET_STATISTICS_update (stats, + gettext_noop ("# ICMP packets sent via TUN"), + 1, GNUNET_NO); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Sending packet with %u bytes ICMP payload via TUN\n", + (unsigned int) payload_length); + len = sizeof (struct GNUNET_MessageHeader) + sizeof (struct GNUNET_TUN_Layer2PacketHeader); + switch (destination_address->af) { - 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->source_port), - inet_ntop (af, - destination_ip, - dbuf, sizeof (dbuf)), - (unsigned int) ntohs (udp->destination_port)); - } - if (pktlen < sizeof (struct GNUNET_TUN_UdpHeader)) - { - /* blame kernel */ + case AF_INET: + len += sizeof (struct GNUNET_TUN_IPv4Header); + break; + case AF_INET6: + len += sizeof (struct GNUNET_TUN_IPv6Header); + break; + default: GNUNET_break (0); return; } - if (pktlen != ntohs (udp->len)) + len += sizeof (struct GNUNET_TUN_IcmpHeader); + len += payload_length; + if (len >= GNUNET_SERVER_MAX_MESSAGE_SIZE) { - /* blame kernel */ GNUNET_break (0); return; } - state = get_redirect_state (af, - IPPROTO_UDP, - source_ip, - ntohs (udp->source_port), - destination_ip, - ntohs (udp->destination_port), - NULL); - if (NULL == state) { - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - _("UDP Packet dropped, have no matching connection information\n")); - return; + char buf[len] GNUNET_ALIGN; + struct GNUNET_MessageHeader *hdr; + struct GNUNET_TUN_Layer2PacketHeader *tun; + + hdr= (struct GNUNET_MessageHeader *) buf; + hdr->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER); + hdr->size = htons (len); + tun = (struct GNUNET_TUN_Layer2PacketHeader*) &hdr[1]; + tun->flags = htons (0); + switch (source_address->af) + { + case AF_INET: + { + struct GNUNET_TUN_IPv4Header * ipv4 = (struct GNUNET_TUN_IPv4Header*) &tun[1]; + + tun->proto = htons (ETH_P_IPV4); + GNUNET_TUN_initialize_ipv4_header (ipv4, + IPPROTO_ICMP, + sizeof (struct GNUNET_TUN_IcmpHeader) + payload_length, + &source_address->address.ipv4, + &destination_address->address.ipv4); + icmp = (struct GNUNET_TUN_IcmpHeader*) &ipv4[1]; + } + break; + case AF_INET6: + { + struct GNUNET_TUN_IPv6Header * ipv6 = (struct GNUNET_TUN_IPv6Header*) &tun[1]; + + tun->proto = htons (ETH_P_IPV6); + GNUNET_TUN_initialize_ipv6_header (ipv6, + IPPROTO_ICMPV6, + sizeof (struct GNUNET_TUN_IcmpHeader) + payload_length, + &source_address->address.ipv6, + &destination_address->address.ipv6); + icmp = (struct GNUNET_TUN_IcmpHeader*) &ipv6[1]; + } + break; + default: + GNUNET_assert (0); + break; + } + *icmp = *icmp_header; + GNUNET_memcpy (&icmp[1], + payload, + payload_length); + GNUNET_TUN_calculate_icmp_checksum (icmp, + payload, + payload_length); + if (NULL != helper_handle) + (void) GNUNET_HELPER_send (helper_handle, + (const struct GNUNET_MessageHeader*) buf, + GNUNET_YES, + NULL, NULL); } - mlen = sizeof (struct GNUNET_EXIT_UdpReplyMessage) + pktlen - sizeof (struct GNUNET_TUN_UdpHeader); - tnq = GNUNET_malloc (sizeof (struct ChannelMessageQueue) + 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); - GNUNET_memcpy (&urm[1], - &udp[1], - pktlen - sizeof (struct GNUNET_TUN_UdpHeader)); - send_packet_to_cadet_channel (state, tnq); -} - - -/** - * @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 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) - * @param source_ip original source IP-address of the IP packet (should - * be the original destination address) - */ -static void -tcp_from_helper (const struct GNUNET_TUN_TcpHeader *tcp, - size_t pktlen, - int af, - const void *destination_ip, - const void *source_ip) -{ - struct ChannelState *state; - char buf[pktlen] GNUNET_ALIGN; - struct GNUNET_TUN_TcpHeader *mtcp; - struct GNUNET_EXIT_TcpDataMessage *tdm; - struct ChannelMessageQueue *tnq; - size_t mlen; - - { - char sbuf[INET6_ADDRSTRLEN]; - char dbuf[INET6_ADDRSTRLEN]; - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Received TCP packet with %u bytes going from %s:%u to %s:%u\n", - (unsigned int) (pktlen - sizeof (struct GNUNET_TUN_TcpHeader)), - inet_ntop (af, - source_ip, - sbuf, sizeof (sbuf)), - (unsigned int) ntohs (tcp->source_port), - inet_ntop (af, - destination_ip, - dbuf, sizeof (dbuf)), - (unsigned int) ntohs (tcp->destination_port)); - } - if (pktlen < sizeof (struct GNUNET_TUN_TcpHeader)) - { - /* blame kernel */ - GNUNET_break (0); - return; - } - state = get_redirect_state (af, - IPPROTO_TCP, - source_ip, - ntohs (tcp->source_port), - destination_ip, - ntohs (tcp->destination_port), - NULL); - if (NULL == state) - { - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - _("TCP Packet dropped, have no matching connection information\n")); - - return; - } - /* mug port numbers and crc to avoid information leakage; - sender will need to lookup the correct values anyway */ - GNUNET_memcpy (buf, tcp, pktlen); - mtcp = (struct GNUNET_TUN_TcpHeader *) buf; - mtcp->source_port = 0; - mtcp->destination_port = 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 ChannelMessageQueue) + 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_TO_VPN); - tdm->reserved = htonl (0); - GNUNET_memcpy (&tdm->tcp_header, - buf, - pktlen); - send_packet_to_cadet_channel (state, tnq); -} - - -/** - * Receive packets from the helper-process - * - * @param cls unused - * @param client unsued - * @param message message received from helper - */ -static int -message_token (void *cls GNUNET_UNUSED, - void *client GNUNET_UNUSED, - const struct GNUNET_MessageHeader *message) -{ - const struct GNUNET_TUN_Layer2PacketHeader *pkt_tun; - size_t size; - - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Got %u-byte message of type %u from gnunet-helper-exit\n", - ntohs (message->size), - ntohs (message->type)); - 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 GNUNET_OK; - } - size = ntohs (message->size); - if (size < sizeof (struct GNUNET_TUN_Layer2PacketHeader) + sizeof (struct GNUNET_MessageHeader)) - { - GNUNET_break (0); - return GNUNET_OK; - } - 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_IPV4: - { - const struct GNUNET_TUN_IPv4Header *pkt4; - - if (size < sizeof (struct GNUNET_TUN_IPv4Header)) - { - /* Kernel to blame? */ - GNUNET_break (0); - return GNUNET_OK; - } - pkt4 = (const struct GNUNET_TUN_IPv4Header *) &pkt_tun[1]; - if (size != ntohs (pkt4->total_length)) - { - /* Kernel to blame? */ - GNUNET_break (0); - return GNUNET_OK; - } - if (pkt4->header_length * 4 != sizeof (struct GNUNET_TUN_IPv4Header)) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - _("IPv4 packet options received. Ignored.\n")); - return GNUNET_OK; - } - - size -= sizeof (struct GNUNET_TUN_IPv4Header); - switch (pkt4->protocol) - { - case IPPROTO_UDP: - udp_from_helper ((const struct GNUNET_TUN_UdpHeader *) &pkt4[1], size, - AF_INET, - &pkt4->destination_address, - &pkt4->source_address); - break; - case IPPROTO_TCP: - tcp_from_helper ((const struct GNUNET_TUN_TcpHeader *) &pkt4[1], size, - AF_INET, - &pkt4->destination_address, - &pkt4->source_address); - break; - case IPPROTO_ICMP: - icmp_from_helper ((const struct GNUNET_TUN_IcmpHeader *) &pkt4[1], size, - AF_INET, - &pkt4->destination_address, - &pkt4->source_address); - break; - default: - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - _("IPv4 packet with unsupported next header %u received. Ignored.\n"), - (int) pkt4->protocol); - return GNUNET_OK; - } - } - break; - case ETH_P_IPV6: - { - const struct GNUNET_TUN_IPv6Header *pkt6; - - if (size < sizeof (struct GNUNET_TUN_IPv6Header)) - { - /* Kernel to blame? */ - GNUNET_break (0); - return GNUNET_OK; - } - pkt6 = (struct GNUNET_TUN_IPv6Header *) &pkt_tun[1]; - if (size != ntohs (pkt6->payload_length) + sizeof (struct GNUNET_TUN_IPv6Header)) - { - /* Kernel to blame? */ - GNUNET_break (0); - return GNUNET_OK; - } - size -= sizeof (struct GNUNET_TUN_IPv6Header); - switch (pkt6->next_header) - { - case IPPROTO_UDP: - 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 GNUNET_TUN_TcpHeader *) &pkt6[1], size, - AF_INET6, - &pkt6->destination_address, - &pkt6->source_address); - break; - case IPPROTO_ICMPV6: - icmp_from_helper ((const struct GNUNET_TUN_IcmpHeader *) &pkt6[1], size, - AF_INET6, - &pkt6->destination_address, - &pkt6->source_address); - break; - default: - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - _("IPv6 packet with unsupported next header %d received. Ignored.\n"), - pkt6->next_header); - return GNUNET_OK; - } - } - break; - default: - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - _("Packet from unknown protocol %u received. Ignored.\n"), - ntohs (pkt_tun->proto)); - break; - } - return GNUNET_OK; } @@ -1637,223 +1323,25 @@ setup_state_record (struct ChannelState *state) /** - * 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. + * Send a UDP packet via the TUN interface. * - * @param payload payload of the packet (starting with UDP payload or - * TCP header, depending on protocol) - * @param payload_length number of bytes in @a payload - * @param protocol IPPROTO_UDP or IPPROTO_TCP - * @param tcp_header skeleton of the TCP header, NULL for UDP - * @param src_address source address to use (IP and port) - * @param dst_address destination address to use (IP and port) - * @param pkt4 where to write the assembled packet; must - * contain enough space for the IP header, UDP/TCP header - * AND the payload + * @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 @a 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 GNUNET_TUN_IPv4Header *pkt4) -{ - size_t len; - - len = payload_length; - switch (protocol) - { - case IPPROTO_UDP: - len += sizeof (struct GNUNET_TUN_UdpHeader); - break; - case IPPROTO_TCP: - len += sizeof (struct GNUNET_TUN_TcpHeader); - GNUNET_assert (NULL != tcp_header); - break; - default: - GNUNET_break (0); - return; - } - if (len + sizeof (struct GNUNET_TUN_IPv4Header) > UINT16_MAX) - { - GNUNET_break (0); - return; - } - - GNUNET_TUN_initialize_ipv4_header (pkt4, - protocol, - len, - &src_address->address.ipv4, - &dst_address->address.ipv4); - switch (protocol) - { - case IPPROTO_UDP: - { - struct GNUNET_TUN_UdpHeader *pkt4_udp = (struct GNUNET_TUN_UdpHeader *) &pkt4[1]; - - pkt4_udp->source_port = htons (src_address->port); - pkt4_udp->destination_port = htons (dst_address->port); - pkt4_udp->len = htons ((uint16_t) payload_length); - GNUNET_TUN_calculate_udp4_checksum (pkt4, - pkt4_udp, - payload, - payload_length); - GNUNET_memcpy (&pkt4_udp[1], - payload, - payload_length); - } - break; - case IPPROTO_TCP: - { - struct GNUNET_TUN_TcpHeader *pkt4_tcp = (struct GNUNET_TUN_TcpHeader *) &pkt4[1]; - - *pkt4_tcp = *tcp_header; - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Sending TCP packet from port %u to port %u\n", - src_address->port, - dst_address->port); - pkt4_tcp->source_port = htons (src_address->port); - pkt4_tcp->destination_port = htons (dst_address->port); - GNUNET_TUN_calculate_tcp4_checksum (pkt4, - pkt4_tcp, - payload, - payload_length); - GNUNET_memcpy (&pkt4_tcp[1], - payload, - payload_length); - } - break; - default: - GNUNET_assert (0); - } -} - - -/** - * 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 @a payload - * @param protocol IPPROTO_UDP or IPPROTO_TCP - * @param tcp_header skeleton TCP header data to send, NULL for UDP - * @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 GNUNET_TUN_IPv6Header *pkt6) -{ - size_t len; - - len = payload_length; - switch (protocol) - { - case IPPROTO_UDP: - len += sizeof (struct GNUNET_TUN_UdpHeader); - break; - case IPPROTO_TCP: - len += sizeof (struct GNUNET_TUN_TcpHeader); - break; - default: - GNUNET_break (0); - return; - } - if (len > UINT16_MAX) - { - GNUNET_break (0); - return; - } - - GNUNET_TUN_initialize_ipv6_header (pkt6, - protocol, - len, - &src_address->address.ipv6, - &dst_address->address.ipv6); - - switch (protocol) - { - case IPPROTO_UDP: - { - struct GNUNET_TUN_UdpHeader *pkt6_udp = (struct GNUNET_TUN_UdpHeader *) &pkt6[1]; - - pkt6_udp->source_port = htons (src_address->port); - pkt6_udp->destination_port = htons (dst_address->port); - pkt6_udp->len = htons ((uint16_t) payload_length); - GNUNET_TUN_calculate_udp6_checksum (pkt6, - pkt6_udp, - payload, - payload_length); - GNUNET_memcpy (&pkt6_udp[1], - payload, - payload_length); - } - break; - case IPPROTO_TCP: - { - struct GNUNET_TUN_TcpHeader *pkt6_tcp = (struct GNUNET_TUN_TcpHeader *) &pkt6[1]; - - /* GNUNET_memcpy first here as some TCP header fields are initialized this way! */ - *pkt6_tcp = *tcp_header; - pkt6_tcp->source_port = htons (src_address->port); - pkt6_tcp->destination_port = htons (dst_address->port); - GNUNET_TUN_calculate_tcp6_checksum (pkt6, - pkt6_tcp, - payload, - payload_length); - GNUNET_memcpy (&pkt6_tcp[1], - payload, - payload_length); - } - break; - default: - GNUNET_assert (0); - break; - } -} - - -/** - * Send a TCP packet via the TUN interface. - * - * @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 header template to use - * @param payload payload of the TCP packet - * @param payload_length number of bytes in @a 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) +send_udp_packet_via_tun (const struct SocketAddress *destination_address, + const struct SocketAddress *source_address, + const void *payload, size_t payload_length) { size_t len; GNUNET_STATISTICS_update (stats, - gettext_noop ("# TCP packets sent via TUN"), - 1, - GNUNET_NO); + gettext_noop ("# UDP packets sent via TUN"), + 1, GNUNET_NO); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Sending packet with %u bytes TCP payload via TUN\n", + "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) @@ -1868,7 +1356,7 @@ send_tcp_packet_via_tun (const struct SocketAddress *destination_address, GNUNET_break (0); return; } - len += sizeof (struct GNUNET_TUN_TcpHeader); + len += sizeof (struct GNUNET_TUN_UdpHeader); len += payload_length; if (len >= GNUNET_SERVER_MAX_MESSAGE_SIZE) { @@ -1880,7 +1368,7 @@ send_tcp_packet_via_tun (const struct SocketAddress *destination_address, struct GNUNET_MessageHeader *hdr; struct GNUNET_TUN_Layer2PacketHeader *tun; - hdr = (struct GNUNET_MessageHeader *) buf; + hdr= (struct GNUNET_MessageHeader *) buf; hdr->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER); hdr->size = htons (len); tun = (struct GNUNET_TUN_Layer2PacketHeader*) &hdr[1]; @@ -1889,14 +1377,13 @@ send_tcp_packet_via_tun (const struct SocketAddress *destination_address, { case AF_INET: { - struct GNUNET_TUN_IPv4Header *ipv4 - = (struct GNUNET_TUN_IPv4Header*) &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, - tcp_header, + IPPROTO_UDP, + NULL, source_address, destination_address, ipv4); @@ -1904,14 +1391,13 @@ send_tcp_packet_via_tun (const struct SocketAddress *destination_address, break; case AF_INET6: { - struct GNUNET_TUN_IPv6Header *ipv6 - = (struct GNUNET_TUN_IPv6Header*) &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, - tcp_header, + IPPROTO_UDP, + NULL, source_address, destination_address, ipv6); @@ -1925,79 +1411,215 @@ send_tcp_packet_via_tun (const struct SocketAddress *destination_address, (void) GNUNET_HELPER_send (helper_handle, (const struct GNUNET_MessageHeader*) buf, GNUNET_YES, - NULL, - NULL); + NULL, NULL); } } /** - * Process a request via cadet to send a request to a TCP service - * offered by this system. + * Check a request to forward UDP data to the Internet via this peer. * - * @param cls closure, NULL - * @param channel connection to the other end - * @param channel_ctx pointer to our `struct ChannelState *` - * @param message the actual message + * @param cls our `struct ChannelState *` + * @param msg the actual message * @return #GNUNET_OK to keep the connection open, * #GNUNET_SYSERR to close it (signal serious error) */ static int -receive_tcp_service (void *cls, - struct GNUNET_CADET_Channel *channel, - void **channel_ctx, - const struct GNUNET_MessageHeader *message) +check_udp_remote (void *cls, + const struct GNUNET_EXIT_UdpInternetMessage *msg) { - struct ChannelState *state = *channel_ctx; - const struct GNUNET_EXIT_TcpServiceStartMessage *start; - uint16_t pkt_len = ntohs (message->size); + struct ChannelState *state = cls; - if (NULL == state) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } if (GNUNET_YES == state->is_dns) { GNUNET_break_op (0); return GNUNET_SYSERR; } - if (NULL == state->specifics.tcp_udp.serv) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } + return GNUNET_OK; +} + + +/** + * Process a request to forward UDP data to the Internet via this peer. + * + * @param cls our `struct ChannelState *` + * @param msg the actual message + */ +static void +handle_udp_remote (void *cls, + const struct GNUNET_EXIT_UdpInternetMessage *msg) +{ + struct ChannelState *state = cls; + uint16_t pkt_len = ntohs (msg->header.size) - sizeof (struct GNUNET_EXIT_UdpInternetMessage); + const struct in_addr *v4; + const struct in6_addr *v6; + const void *payload; + int af; + if (GNUNET_SYSERR == state->is_dns) { /* channel is UDP/TCP from now on */ state->is_dns = GNUNET_NO; } - GNUNET_STATISTICS_update (stats, - gettext_noop ("# TCP service creation requests received via cadet"), - 1, - GNUNET_NO); GNUNET_STATISTICS_update (stats, gettext_noop ("# Bytes received from CADET"), - pkt_len, - GNUNET_NO); - /* check that we got at least a valid header */ - if (pkt_len < sizeof (struct GNUNET_EXIT_TcpServiceStartMessage)) + pkt_len, GNUNET_NO); + GNUNET_STATISTICS_update (stats, + gettext_noop ("# UDP IP-exit requests received via cadet"), + 1, GNUNET_NO); + af = (int) ntohl (msg->af); + state->specifics.tcp_udp.ri.remote_address.af = af; + switch (af) { - GNUNET_break_op (0); - return GNUNET_SYSERR; + case AF_INET: + if (pkt_len < sizeof (struct in_addr)) + { + GNUNET_break_op (0); + return; + } + if (! ipv4_exit) + { + GNUNET_break_op (0); + return; + } + v4 = (const struct in_addr*) &msg[1]; + payload = &v4[1]; + pkt_len -= sizeof (struct in_addr); + state->specifics.tcp_udp.ri.remote_address.address.ipv4 = *v4; + break; + case AF_INET6: + if (pkt_len < sizeof (struct in6_addr)) + { + GNUNET_break_op (0); + return; + } + if (! ipv6_exit) + { + GNUNET_break_op (0); + return; + } + v6 = (const struct in6_addr*) &msg[1]; + payload = &v6[1]; + pkt_len -= sizeof (struct in6_addr); + state->specifics.tcp_udp.ri.remote_address.address.ipv6 = *v6; + break; + default: + GNUNET_break_op (0); + return; } - start = (const struct GNUNET_EXIT_TcpServiceStartMessage*) message; - pkt_len -= sizeof (struct GNUNET_EXIT_TcpServiceStartMessage); - if (NULL != state->specifics.tcp_udp.heap_node) { - 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 (&state->peer), + inet_ntop (af, + &state->specifics.tcp_udp.ri.remote_address.address, + buf, sizeof (buf)), + (unsigned int) ntohs (msg->destination_port)); } - if (start->tcp_header.off * 4 < sizeof (struct GNUNET_TUN_TcpHeader)) + state->specifics.tcp_udp.ri.remote_address.proto = IPPROTO_UDP; + state->specifics.tcp_udp.ri.remote_address.port = msg->destination_port; + if (NULL == state->specifics.tcp_udp.heap_node) + setup_state_record (state); + if (0 != ntohs (msg->source_port)) + state->specifics.tcp_udp.ri.local_address.port = msg->source_port; + send_udp_packet_via_tun (&state->specifics.tcp_udp.ri.remote_address, + &state->specifics.tcp_udp.ri.local_address, + payload, + pkt_len); + GNUNET_CADET_receive_done (state->channel); +} + + +/** + * Check a request via cadet to send a request to a UDP service + * offered by this system. + * + * @param cls our `struct ChannelState *` + * @param msg the actual message + * @return #GNUNET_OK to keep the connection open, + * #GNUNET_SYSERR to close it (signal serious error) + */ +static int +check_udp_service (void *cls, + const struct GNUNET_EXIT_UdpServiceMessage *msg) +{ + struct ChannelState *state = cls; + + if (NULL == state->specifics.tcp_udp.serv) { GNUNET_break_op (0); return GNUNET_SYSERR; } + return GNUNET_OK; +} + + +/** + * Process a request via cadet to send a request to a UDP service + * offered by this system. + * + * @param cls our `struct ChannelState *` + * @param msg the actual message + */ +static void +handle_udp_service (void *cls, + const struct GNUNET_EXIT_UdpServiceMessage *msg) +{ + struct ChannelState *state = cls; + uint16_t pkt_len = ntohs (msg->header.size) - sizeof (struct GNUNET_EXIT_UdpServiceMessage); + + GNUNET_STATISTICS_update (stats, + gettext_noop ("# Bytes received from CADET"), + pkt_len, GNUNET_NO); + GNUNET_STATISTICS_update (stats, + gettext_noop ("# UDP service requests received via cadet"), + 1, GNUNET_NO); + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Received data from %s for forwarding to UDP service %s on port %u\n", + GNUNET_i2s (&state->peer), + GNUNET_h2s (&state->specifics.tcp_udp.serv->descriptor), + (unsigned int) ntohs (msg->destination_port)); + setup_state_record (state); + if (0 != ntohs (msg->source_port)) + state->specifics.tcp_udp.ri.local_address.port = msg->source_port; + send_udp_packet_via_tun (&state->specifics.tcp_udp.ri.remote_address, + &state->specifics.tcp_udp.ri.local_address, + &msg[1], + pkt_len); + GNUNET_CADET_receive_done (state->channel); +} + + +/** + * Process a request via cadet to send a request to a TCP service + * offered by this system. + * + * @param cls our `struct ChannelState *` + * @param start the actual message + * @return #GNUNET_OK to keep the connection open, + * #GNUNET_SYSERR to close it (signal serious error) + */ +static void +handle_tcp_service (void *cls, + const struct GNUNET_EXIT_TcpServiceStartMessage *start) +{ + struct ChannelState *state = cls; + uint16_t pkt_len = ntohs (start->header.size) - sizeof (struct GNUNET_EXIT_TcpServiceStartMessage); + + if (GNUNET_SYSERR == state->is_dns) + { + /* channel is UDP/TCP from now on */ + state->is_dns = GNUNET_NO; + } + GNUNET_STATISTICS_update (stats, + gettext_noop ("# TCP service creation requests received via cadet"), + 1, + GNUNET_NO); + GNUNET_STATISTICS_update (stats, + gettext_noop ("# Bytes received from CADET"), + pkt_len, + GNUNET_NO); GNUNET_break_op (ntohl (start->reserved) == 0); /* setup fresh connection */ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, @@ -2011,34 +1633,23 @@ receive_tcp_service (void *cls, &start->tcp_header, &start[1], pkt_len); - GNUNET_CADET_receive_done (channel); - return GNUNET_YES; + GNUNET_CADET_receive_done (state->channel); } /** - * Process a request to forward TCP data to the Internet via this peer. + * Check a request to forward TCP data to the Internet via this peer. * - * @param cls closure, NULL - * @param channel connection to the other end - * @param channel_ctx pointer to our `struct ChannelState *` - * @param message the actual message + * @param cls our `struct ChannelState *` + * @param start the actual message * @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_CADET_Channel *channel, - void **channel_ctx GNUNET_UNUSED, - const struct GNUNET_MessageHeader *message) +check_tcp_remote (void *cls, + const struct GNUNET_EXIT_TcpInternetStartMessage *start) { - struct ChannelState *state = *channel_ctx; - 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; + struct ChannelState *state = cls; if (NULL == state) { @@ -2050,24 +1661,6 @@ receive_tcp_remote (void *cls GNUNET_UNUSED, GNUNET_break_op (0); return GNUNET_SYSERR; } - if (GNUNET_SYSERR == state->is_dns) - { - /* channel is UDP/TCP from now on */ - state->is_dns = GNUNET_NO; - } - GNUNET_STATISTICS_update (stats, - gettext_noop ("# Bytes received from CADET"), - pkt_len, GNUNET_NO); - GNUNET_STATISTICS_update (stats, - gettext_noop ("# TCP IP-exit creation requests received via cadet"), - 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->specifics.tcp_udp.serv) || (NULL != state->specifics.tcp_udp.heap_node) ) { @@ -2079,6 +1672,38 @@ receive_tcp_remote (void *cls GNUNET_UNUSED, GNUNET_break_op (0); return GNUNET_SYSERR; } + return GNUNET_OK; +} + + +/** + * Process a request to forward TCP data to the Internet via this peer. + * + * @param cls our `struct ChannelState *` + * @param start the actual message + */ +static void +handle_tcp_remote (void *cls, + const struct GNUNET_EXIT_TcpInternetStartMessage *start) +{ + struct ChannelState *state = cls; + uint16_t pkt_len = ntohs (start->header.size) - sizeof (struct GNUNET_EXIT_TcpInternetStartMessage); + const struct in_addr *v4; + const struct in6_addr *v6; + const void *payload; + int af; + + if (GNUNET_SYSERR == state->is_dns) + { + /* channel is UDP/TCP from now on */ + state->is_dns = GNUNET_NO; + } + GNUNET_STATISTICS_update (stats, + gettext_noop ("# Bytes received from CADET"), + pkt_len, GNUNET_NO); + GNUNET_STATISTICS_update (stats, + gettext_noop ("# TCP IP-exit creation requests received via cadet"), + 1, GNUNET_NO); af = (int) ntohl (start->af); state->specifics.tcp_udp.ri.remote_address.af = af; switch (af) @@ -2087,12 +1712,12 @@ receive_tcp_remote (void *cls GNUNET_UNUSED, if (pkt_len < sizeof (struct in_addr)) { GNUNET_break_op (0); - return GNUNET_SYSERR; + return; } if (! ipv4_exit) { GNUNET_break_op (0); - return GNUNET_SYSERR; + return; } v4 = (const struct in_addr*) &start[1]; payload = &v4[1]; @@ -2103,12 +1728,12 @@ receive_tcp_remote (void *cls GNUNET_UNUSED, if (pkt_len < sizeof (struct in6_addr)) { GNUNET_break_op (0); - return GNUNET_SYSERR; + return; } if (! ipv6_exit) { GNUNET_break_op (0); - return GNUNET_SYSERR; + return; } v6 = (const struct in6_addr*) &start[1]; payload = &v6[1]; @@ -2117,7 +1742,7 @@ receive_tcp_remote (void *cls GNUNET_UNUSED, break; default: GNUNET_break_op (0); - return GNUNET_SYSERR; + return; } { char buf[INET6_ADDRSTRLEN]; @@ -2135,46 +1760,27 @@ receive_tcp_remote (void *cls GNUNET_UNUSED, send_tcp_packet_via_tun (&state->specifics.tcp_udp.ri.remote_address, &state->specifics.tcp_udp.ri.local_address, &start->tcp_header, - payload, pkt_len); - GNUNET_CADET_receive_done (channel); - return GNUNET_YES; + payload, + pkt_len); + GNUNET_CADET_receive_done (state->channel); } /** - * Process a request to forward TCP data on an established + * Check a request to forward TCP data on an established * connection via this peer. * - * @param cls closure, NULL - * @param channel connection to the other end - * @param channel_ctx pointer to our `struct ChannelState *` + * @param cls our `struct ChannelState *` * @param message the actual message * @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_CADET_Channel *channel, - void **channel_ctx GNUNET_UNUSED, - const struct GNUNET_MessageHeader *message) +check_tcp_data (void *cls, + const struct GNUNET_EXIT_TcpDataMessage *data) { - struct ChannelState *state = *channel_ctx; - const struct GNUNET_EXIT_TcpDataMessage *data; - uint16_t pkt_len = ntohs (message->size); + struct ChannelState *state = cls; - GNUNET_STATISTICS_update (stats, - gettext_noop ("# Bytes received from CADET"), - pkt_len, GNUNET_NO); - GNUNET_STATISTICS_update (stats, - gettext_noop ("# TCP data requests received via cadet"), - 1, GNUNET_NO); - if (pkt_len < sizeof (struct GNUNET_EXIT_TcpDataMessage)) - { - 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->specifics.tcp_udp.heap_node) ) { @@ -2195,6 +1801,30 @@ receive_tcp_data (void *cls GNUNET_UNUSED, GNUNET_break_op (0); return GNUNET_SYSERR; } + return GNUNET_OK; +} + + +/** + * Process a request to forward TCP data on an established + * connection via this peer. + * + * @param cls our `struct ChannelState *` + * @param message the actual message + */ +static void +handle_tcp_data (void *cls, + const struct GNUNET_EXIT_TcpDataMessage *data) +{ + struct ChannelState *state = cls; + uint16_t pkt_len = ntohs (data->header.size) - sizeof (struct GNUNET_EXIT_TcpDataMessage); + + GNUNET_STATISTICS_update (stats, + gettext_noop ("# Bytes received from CADET"), + pkt_len, GNUNET_NO); + GNUNET_STATISTICS_update (stats, + gettext_noop ("# TCP data requests received via cadet"), + 1, GNUNET_NO); if (GNUNET_SYSERR == state->is_dns) { /* channel is UDP/TCP from now on */ @@ -2218,137 +1848,34 @@ receive_tcp_data (void *cls GNUNET_UNUSED, &state->specifics.tcp_udp.ri.local_address, &data->tcp_header, &data[1], pkt_len); - GNUNET_CADET_receive_done (channel); - return GNUNET_YES; + GNUNET_CADET_receive_done (state->channel); } /** - * Send an ICMP packet via the TUN interface. + * Synthesize a plausible ICMP payload for an ICMPv4 error + * response on the given channel. * - * @param destination_address IP to use for the ICMP packet's destination - * @param source_address IP to use for the ICMP packet's source - * @param icmp_header ICMP header to send - * @param payload payload of the ICMP packet (does NOT include ICMP header) - * @param payload_length number of bytes of data in @a payload + * @param state channel information + * @param ipp IPv6 header to fill in (ICMP payload) + * @param udp "UDP" header to fill in (ICMP payload); might actually + * also be the first 8 bytes of the TCP header */ static void -send_icmp_packet_via_tun (const struct SocketAddress *destination_address, - const struct SocketAddress *source_address, - const struct GNUNET_TUN_IcmpHeader *icmp_header, - const void *payload, size_t payload_length) +make_up_icmpv4_payload (struct ChannelState *state, + struct GNUNET_TUN_IPv4Header *ipp, + struct GNUNET_TUN_UdpHeader *udp) { - size_t len; - struct GNUNET_TUN_IcmpHeader *icmp; - - GNUNET_STATISTICS_update (stats, - gettext_noop ("# ICMP packets sent via TUN"), - 1, GNUNET_NO); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Sending packet with %u bytes ICMP payload via TUN\n", - (unsigned int) payload_length); - len = sizeof (struct GNUNET_MessageHeader) + sizeof (struct GNUNET_TUN_Layer2PacketHeader); - switch (destination_address->af) - { - case AF_INET: - len += sizeof (struct GNUNET_TUN_IPv4Header); - break; - case AF_INET6: - len += sizeof (struct GNUNET_TUN_IPv6Header); - break; - default: - GNUNET_break (0); - return; - } - len += sizeof (struct GNUNET_TUN_IcmpHeader); - len += payload_length; - if (len >= GNUNET_SERVER_MAX_MESSAGE_SIZE) - { - GNUNET_break (0); - return; - } - { - char buf[len] GNUNET_ALIGN; - struct GNUNET_MessageHeader *hdr; - struct GNUNET_TUN_Layer2PacketHeader *tun; - - hdr= (struct GNUNET_MessageHeader *) buf; - hdr->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER); - hdr->size = htons (len); - tun = (struct GNUNET_TUN_Layer2PacketHeader*) &hdr[1]; - tun->flags = htons (0); - switch (source_address->af) - { - case AF_INET: - { - struct GNUNET_TUN_IPv4Header * ipv4 = (struct GNUNET_TUN_IPv4Header*) &tun[1]; - - tun->proto = htons (ETH_P_IPV4); - GNUNET_TUN_initialize_ipv4_header (ipv4, - IPPROTO_ICMP, - sizeof (struct GNUNET_TUN_IcmpHeader) + payload_length, - &source_address->address.ipv4, - &destination_address->address.ipv4); - icmp = (struct GNUNET_TUN_IcmpHeader*) &ipv4[1]; - } - break; - case AF_INET6: - { - struct GNUNET_TUN_IPv6Header * ipv6 = (struct GNUNET_TUN_IPv6Header*) &tun[1]; - - tun->proto = htons (ETH_P_IPV6); - GNUNET_TUN_initialize_ipv6_header (ipv6, - IPPROTO_ICMPV6, - sizeof (struct GNUNET_TUN_IcmpHeader) + payload_length, - &source_address->address.ipv6, - &destination_address->address.ipv6); - icmp = (struct GNUNET_TUN_IcmpHeader*) &ipv6[1]; - } - break; - default: - GNUNET_assert (0); - break; - } - *icmp = *icmp_header; - GNUNET_memcpy (&icmp[1], - payload, - payload_length); - GNUNET_TUN_calculate_icmp_checksum (icmp, - payload, - payload_length); - if (NULL != helper_handle) - (void) GNUNET_HELPER_send (helper_handle, - (const struct GNUNET_MessageHeader*) buf, - GNUNET_YES, - NULL, NULL); - } -} - - -/** - * Synthesize a plausible ICMP payload for an ICMPv4 error - * response on the given channel. - * - * @param state channel information - * @param ipp IPv6 header to fill in (ICMP payload) - * @param udp "UDP" header to fill in (ICMP payload); might actually - * also be the first 8 bytes of the TCP header - */ -static void -make_up_icmpv4_payload (struct ChannelState *state, - struct GNUNET_TUN_IPv4Header *ipp, - struct GNUNET_TUN_UdpHeader *udp) -{ - GNUNET_TUN_initialize_ipv4_header (ipp, - state->specifics.tcp_udp.ri.remote_address.proto, - sizeof (struct GNUNET_TUN_TcpHeader), - &state->specifics.tcp_udp.ri.remote_address.address.ipv4, - &state->specifics.tcp_udp.ri.local_address.address.ipv4); - udp->source_port = htons (state->specifics.tcp_udp.ri.remote_address.port); - udp->destination_port = htons (state->specifics.tcp_udp.ri.local_address.port); - udp->len = htons (0); - udp->crc = htons (0); -} + GNUNET_TUN_initialize_ipv4_header (ipp, + state->specifics.tcp_udp.ri.remote_address.proto, + sizeof (struct GNUNET_TUN_TcpHeader), + &state->specifics.tcp_udp.ri.remote_address.address.ipv4, + &state->specifics.tcp_udp.ri.local_address.address.ipv4); + udp->source_port = htons (state->specifics.tcp_udp.ri.remote_address.port); + udp->destination_port = htons (state->specifics.tcp_udp.ri.local_address.port); + udp->len = htons (0); + udp->crc = htons (0); +} /** @@ -2378,35 +1905,46 @@ make_up_icmpv6_payload (struct ChannelState *state, /** - * Process a request to forward ICMP data to the Internet via this peer. + * Check a request to forward ICMP data to the Internet via this peer. * - * @param cls closure, NULL - * @param channel connection to the other end - * @param channel_ctx pointer to our 'struct ChannelState *' - * @param message the actual message + * @param cls our `struct ChannelState *` + * @param msg the actual message * @return #GNUNET_OK to keep the connection open, * #GNUNET_SYSERR to close it (signal serious error) */ static int -receive_icmp_remote (void *cls, - struct GNUNET_CADET_Channel *channel, - void **channel_ctx, - const struct GNUNET_MessageHeader *message) +check_icmp_remote (void *cls, + const struct GNUNET_EXIT_IcmpInternetMessage *msg) { - struct ChannelState *state = *channel_ctx; - const struct GNUNET_EXIT_IcmpInternetMessage *msg; - uint16_t pkt_len = ntohs (message->size); - const struct in_addr *v4; - const struct in6_addr *v6; - const void *payload; - char buf[sizeof (struct GNUNET_TUN_IPv6Header) + 8] GNUNET_ALIGN; - int af; + struct ChannelState *state = cls; if (GNUNET_YES == state->is_dns) { GNUNET_break_op (0); return GNUNET_SYSERR; } + return GNUNET_OK; +} + + +/** + * Process a request to forward ICMP data to the Internet via this peer. + * + * @param cls our `struct ChannelState *` + * @param msg the actual message + */ +static void +handle_icmp_remote (void *cls, + const struct GNUNET_EXIT_IcmpInternetMessage *msg) +{ + struct ChannelState *state = cls; + uint16_t pkt_len = ntohs (msg->header.size) - sizeof (struct GNUNET_EXIT_IcmpInternetMessage); + const struct in_addr *v4; + const struct in6_addr *v6; + const void *payload; + char buf[sizeof (struct GNUNET_TUN_IPv6Header) + 8] GNUNET_ALIGN; + int af; + if (GNUNET_SYSERR == state->is_dns) { /* channel is UDP/TCP from now on */ @@ -2418,13 +1956,6 @@ receive_icmp_remote (void *cls, GNUNET_STATISTICS_update (stats, gettext_noop ("# ICMP IP-exit requests received via cadet"), 1, GNUNET_NO); - if (pkt_len < sizeof (struct GNUNET_EXIT_IcmpInternetMessage)) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - msg = (const struct GNUNET_EXIT_IcmpInternetMessage*) message; - pkt_len -= sizeof (struct GNUNET_EXIT_IcmpInternetMessage); af = (int) ntohl (msg->af); if ( (NULL != state->specifics.tcp_udp.heap_node) && @@ -2432,7 +1963,7 @@ receive_icmp_remote (void *cls, { /* other peer switched AF on this channel; not allowed */ GNUNET_break_op (0); - return GNUNET_SYSERR; + return; } switch (af) @@ -2441,12 +1972,12 @@ receive_icmp_remote (void *cls, if (pkt_len < sizeof (struct in_addr)) { GNUNET_break_op (0); - return GNUNET_SYSERR; + return; } if (! ipv4_exit) { GNUNET_break_op (0); - return GNUNET_SYSERR; + return; } v4 = (const struct in_addr*) &msg[1]; payload = &v4[1]; @@ -2471,7 +2002,7 @@ receive_icmp_remote (void *cls, if (0 != pkt_len) { GNUNET_break_op (0); - return GNUNET_SYSERR; + return; } /* make up payload */ { @@ -2491,7 +2022,7 @@ receive_icmp_remote (void *cls, GNUNET_STATISTICS_update (stats, gettext_noop ("# ICMPv4 packets dropped (type not allowed)"), 1, GNUNET_NO); - return GNUNET_SYSERR; + return; } /* end AF_INET */ break; @@ -2499,12 +2030,12 @@ receive_icmp_remote (void *cls, if (pkt_len < sizeof (struct in6_addr)) { GNUNET_break_op (0); - return GNUNET_SYSERR; + return; } if (! ipv6_exit) { GNUNET_break_op (0); - return GNUNET_SYSERR; + return; } v6 = (const struct in6_addr*) &msg[1]; payload = &v6[1]; @@ -2530,7 +2061,7 @@ receive_icmp_remote (void *cls, if (0 != pkt_len) { GNUNET_break_op (0); - return GNUNET_SYSERR; + return; } /* make up payload */ { @@ -2550,14 +2081,14 @@ receive_icmp_remote (void *cls, GNUNET_STATISTICS_update (stats, gettext_noop ("# ICMPv6 packets dropped (type not allowed)"), 1, GNUNET_NO); - return GNUNET_SYSERR; + return; } /* end AF_INET6 */ break; default: /* bad AF */ GNUNET_break_op (0); - return GNUNET_SYSERR; + return; } { @@ -2573,8 +2104,7 @@ receive_icmp_remote (void *cls, &state->specifics.tcp_udp.ri.local_address, &msg->icmp_header, payload, pkt_len); - GNUNET_CADET_receive_done (channel); - return GNUNET_YES; + GNUNET_CADET_receive_done (state->channel); } @@ -2629,28 +2159,19 @@ make_up_icmp_service_payload (struct ChannelState *state, /** - * Process a request via cadet to send ICMP data to a service + * Check a request via cadet to send ICMP data to a service * offered by this system. * - * @param cls closure, NULL - * @param channel connection to the other end - * @param channel_ctx pointer to our 'struct ChannelState *' - * @param message the actual message + * @param cls our `struct ChannelState *` + * @param msg the actual message * @return #GNUNET_OK to keep the connection open, * #GNUNET_SYSERR to close it (signal serious error) */ static int -receive_icmp_service (void *cls, - struct GNUNET_CADET_Channel *channel, - void **channel_ctx, - const struct GNUNET_MessageHeader *message) +check_icmp_service (void *cls, + const struct GNUNET_EXIT_IcmpServiceMessage *msg) { - struct ChannelState *state = *channel_ctx; - const struct GNUNET_EXIT_IcmpServiceMessage *msg; - uint16_t pkt_len = ntohs (message->size); - struct GNUNET_TUN_IcmpHeader icmp; - char buf[sizeof (struct GNUNET_TUN_IPv6Header) + 8] GNUNET_ALIGN; - const void *payload; + struct ChannelState *state = cls; if (GNUNET_YES == state->is_dns) { @@ -2662,6 +2183,27 @@ receive_icmp_service (void *cls, GNUNET_break_op (0); return GNUNET_SYSERR; } + return GNUNET_OK; +} + + +/** + * Process a request via cadet to send ICMP data to a service + * offered by this system. + * + * @param cls our `struct ChannelState *` + * @param msg the actual message + */ +static void +handle_icmp_service (void *cls, + const struct GNUNET_EXIT_IcmpServiceMessage *msg) +{ + struct ChannelState *state = cls; + uint16_t pkt_len = ntohs (msg->header.size) - sizeof (struct GNUNET_EXIT_IcmpServiceMessage); + struct GNUNET_TUN_IcmpHeader icmp; + char buf[sizeof (struct GNUNET_TUN_IPv6Header) + 8] GNUNET_ALIGN; + const void *payload; + GNUNET_STATISTICS_update (stats, gettext_noop ("# Bytes received from CADET"), pkt_len, GNUNET_NO); @@ -2669,13 +2211,6 @@ receive_icmp_service (void *cls, gettext_noop ("# ICMP service requests received via cadet"), 1, GNUNET_NO); /* check that we got at least a valid header */ - if (pkt_len < sizeof (struct GNUNET_EXIT_IcmpServiceMessage)) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - msg = (const struct GNUNET_EXIT_IcmpServiceMessage*) message; - pkt_len -= sizeof (struct GNUNET_EXIT_IcmpServiceMessage); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received data from %s for forwarding to ICMP service %s\n", GNUNET_i2s (&state->peer), @@ -2707,7 +2242,7 @@ receive_icmp_service (void *cls, if (0 != pkt_len) { GNUNET_break_op (0); - return GNUNET_SYSERR; + return; } payload = buf; pkt_len = make_up_icmp_service_payload (state, buf); @@ -2718,7 +2253,7 @@ receive_icmp_service (void *cls, if (0 != pkt_len) { GNUNET_break_op (0); - return GNUNET_SYSERR; + return; } payload = buf; pkt_len = make_up_icmp_service_payload (state, buf); @@ -2729,12 +2264,12 @@ receive_icmp_service (void *cls, GNUNET_STATISTICS_update (stats, gettext_noop ("# ICMPv4 packets dropped (impossible PT to v6)"), 1, GNUNET_NO); - return GNUNET_OK; + return; } if (0 != pkt_len) { GNUNET_break_op (0); - return GNUNET_SYSERR; + return; } payload = buf; pkt_len = make_up_icmp_service_payload (state, buf); @@ -2744,7 +2279,7 @@ receive_icmp_service (void *cls, GNUNET_STATISTICS_update (stats, gettext_noop ("# ICMPv4 packets dropped (type not allowed)"), 1, GNUNET_NO); - return GNUNET_SYSERR; + return; } /* end of AF_INET */ break; @@ -2765,7 +2300,7 @@ receive_icmp_service (void *cls, if (0 != pkt_len) { GNUNET_break_op (0); - return GNUNET_SYSERR; + return; } payload = buf; pkt_len = make_up_icmp_service_payload (state, buf); @@ -2776,7 +2311,7 @@ receive_icmp_service (void *cls, if (0 != pkt_len) { GNUNET_break_op (0); - return GNUNET_SYSERR; + return; } payload = buf; pkt_len = make_up_icmp_service_payload (state, buf); @@ -2788,12 +2323,12 @@ receive_icmp_service (void *cls, GNUNET_STATISTICS_update (stats, gettext_noop ("# ICMPv6 packets dropped (impossible PT to v4)"), 1, GNUNET_NO); - return GNUNET_OK; + return; } if (0 != pkt_len) { GNUNET_break_op (0); - return GNUNET_SYSERR; + return; } payload = buf; pkt_len = make_up_icmp_service_payload (state, buf); @@ -2803,283 +2338,715 @@ receive_icmp_service (void *cls, GNUNET_STATISTICS_update (stats, gettext_noop ("# ICMPv6 packets dropped (type not allowed)"), 1, GNUNET_NO); - return GNUNET_SYSERR; + return; } /* end of AF_INET6 */ break; default: - GNUNET_break_op (0); - return GNUNET_SYSERR; + GNUNET_break_op (0); + return; + } + + send_icmp_packet_via_tun (&state->specifics.tcp_udp.ri.remote_address, + &state->specifics.tcp_udp.ri.local_address, + &icmp, + payload, + pkt_len); + GNUNET_CADET_receive_done (state->channel); +} + + +/** + * Free memory associated with a service record. + * + * @param cls unused + * @param key service descriptor + * @param value service record to free + * @return #GNUNET_OK + */ +static int +free_service_record (void *cls, + const struct GNUNET_HashCode *key, + void *value) +{ + struct LocalService *service = value; + + GNUNET_assert (GNUNET_YES == + GNUNET_CONTAINER_multihashmap_remove (services, + key, + service)); + GNUNET_CADET_close_port (service->port); + GNUNET_free_non_null (service->name); + GNUNET_free (service); + return GNUNET_OK; +} + + +/** + * Callback from CADET for new channels. + * + * @param cls closure + * @param channel new handle to the channel + * @param initiator peer that started the channel + * @return initial channel context for the channel + */ +static void * +new_service_channel (void *cls, + struct GNUNET_CADET_Channel *channel, + const struct GNUNET_PeerIdentity *initiator) +{ + struct LocalService *ls = cls; + struct ChannelState *s = GNUNET_new (struct ChannelState); + + s->peer = *initiator; + GNUNET_STATISTICS_update (stats, + gettext_noop ("# Inbound CADET channels created"), + 1, + GNUNET_NO); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received inbound channel from `%s'\n", + GNUNET_i2s (initiator)); + s->channel = channel; + s->specifics.tcp_udp.serv = ls; + s->specifics.tcp_udp.ri.remote_address = ls->address; + return s; +} + + +/** + * Function called by cadet whenever an inbound channel is destroyed. + * Should clean up any associated state. + * + * @param cls our `struct ChannelState *` + * @param channel connection to the other end (henceforth invalid) + */ +static void +clean_channel (void *cls, + const struct GNUNET_CADET_Channel *channel) +{ + struct ChannelState *s = cls; + + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Channel destroyed\n"); + if (GNUNET_SYSERR == s->is_dns) + { + GNUNET_free (s); + return; + } + if (GNUNET_YES == s->is_dns) + { + if (channels[s->specifics.dns.my_id] == s) + channels[s->specifics.dns.my_id] = NULL; + } + else + { + if (NULL != s->specifics.tcp_udp.heap_node) + { + GNUNET_assert (GNUNET_YES == + GNUNET_CONTAINER_multihashmap_remove (connections_map, + &s->specifics.tcp_udp.state_key, + s)); + GNUNET_CONTAINER_heap_remove_node (s->specifics.tcp_udp.heap_node); + s->specifics.tcp_udp.heap_node = NULL; + } + } + GNUNET_free (s); +} + + +/** + * Given a service descriptor and a destination port, find the + * respective service entry. + * + * @param proto IPPROTO_TCP or IPPROTO_UDP + * @param name name of the service + * @param destination_port destination port + * @param service service information record to store (service->name will be set). + */ +static void +store_service (int proto, + const char *name, + uint16_t destination_port, + struct LocalService *service) +{ + struct GNUNET_MQ_MessageHandler handlers[] = { + GNUNET_MQ_hd_var_size (icmp_service, + GNUNET_MESSAGE_TYPE_VPN_ICMP_TO_SERVICE, + struct GNUNET_EXIT_IcmpServiceMessage, + service), + GNUNET_MQ_hd_var_size (udp_service, + GNUNET_MESSAGE_TYPE_VPN_UDP_TO_SERVICE, + struct GNUNET_EXIT_UdpServiceMessage, + service), + GNUNET_MQ_hd_var_size (tcp_service, + GNUNET_MESSAGE_TYPE_VPN_TCP_TO_SERVICE_START, + struct GNUNET_EXIT_TcpServiceStartMessage, + service), + GNUNET_MQ_hd_var_size (tcp_data, + GNUNET_MESSAGE_TYPE_VPN_TCP_DATA_TO_EXIT, + struct GNUNET_EXIT_TcpDataMessage, + service), + GNUNET_MQ_handler_end () + }; + + struct GNUNET_HashCode cadet_port; + + service->name = GNUNET_strdup (name); + GNUNET_TUN_service_name_to_hash (name, + &service->descriptor); + GNUNET_TUN_compute_service_cadet_port (&service->descriptor, + destination_port, + &cadet_port); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Opening CADET port %s for SERVICE exit %s on port %u\n", + GNUNET_h2s (&cadet_port), + name, + (unsigned int) destination_port); + service->port = GNUNET_CADET_open_porT (cadet_handle, + &cadet_port, + &new_service_channel, + service, + NULL, + &clean_channel, + handlers); + service->is_udp = (IPPROTO_UDP == proto); + if (GNUNET_OK != + GNUNET_CONTAINER_multihashmap_put (services, + &cadet_port, + service, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)) + { + GNUNET_CADET_close_port (service->port); + GNUNET_free_non_null (service->name); + GNUNET_free (service); + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _("Got duplicate service records for `%s:%u'\n"), + name, + (unsigned int) destination_port); + } +} + + +/** + * Send the given packet via the cadet channel. + * + * @param s channel destination + * @param env message to queue + */ +static void +send_packet_to_cadet_channel (struct ChannelState *s, + struct GNUNET_MQ_Envelope *env) +{ + GNUNET_assert (NULL != s); + GNUNET_STATISTICS_update (stats, + gettext_noop ("# Messages transmitted via cadet channels"), + 1, + GNUNET_NO); + GNUNET_MQ_send (GNUNET_CADET_get_mq (s->channel), + env); +} + + +/** + * @brief Handles an ICMP packet received from the helper. + * + * @param icmp A pointer to the Packet + * @param pktlen number of bytes in @a icmp + * @param af address family (AFINET or AF_INET6) + * @param destination_ip destination IP-address of the IP packet (should + * be our local address) + * @param source_ip original source IP-address of the IP packet (should + * be the original destination address) + */ +static void +icmp_from_helper (const struct GNUNET_TUN_IcmpHeader *icmp, + size_t pktlen, + int af, + const void *destination_ip, + const void *source_ip) +{ + struct ChannelState *state; + struct GNUNET_MQ_Envelope *env; + struct GNUNET_EXIT_IcmpToVPNMessage *i2v; + const struct GNUNET_TUN_IPv4Header *ipv4; + const struct GNUNET_TUN_IPv6Header *ipv6; + const struct GNUNET_TUN_UdpHeader *udp; + uint16_t source_port; + uint16_t destination_port; + uint8_t protocol; + + { + char sbuf[INET6_ADDRSTRLEN]; + char dbuf[INET6_ADDRSTRLEN]; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received ICMP packet going from %s to %s\n", + inet_ntop (af, + source_ip, + sbuf, sizeof (sbuf)), + inet_ntop (af, + destination_ip, + dbuf, sizeof (dbuf))); + } + if (pktlen < sizeof (struct GNUNET_TUN_IcmpHeader)) + { + /* blame kernel */ + GNUNET_break (0); + return; + } + + /* Find out if this is an ICMP packet in response to an existing + TCP/UDP packet and if so, figure out ports / protocol of the + existing session from the IP data in the ICMP payload */ + source_port = 0; + destination_port = 0; + switch (af) + { + case AF_INET: + protocol = IPPROTO_ICMP; + switch (icmp->type) + { + case GNUNET_TUN_ICMPTYPE_ECHO_REPLY: + case GNUNET_TUN_ICMPTYPE_ECHO_REQUEST: + break; + case GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE: + case GNUNET_TUN_ICMPTYPE_SOURCE_QUENCH: + case GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED: + if (pktlen < + sizeof (struct GNUNET_TUN_IcmpHeader) + + sizeof (struct GNUNET_TUN_IPv4Header) + 8) + { + /* blame kernel */ + GNUNET_break (0); + return; + } + ipv4 = (const struct GNUNET_TUN_IPv4Header *) &icmp[1]; + protocol = ipv4->protocol; + /* could be TCP or UDP, but both have the ports in the right + place, so that doesn't matter here */ + udp = (const struct GNUNET_TUN_UdpHeader *) &ipv4[1]; + /* swap ports, as they are from the original message */ + destination_port = ntohs (udp->source_port); + source_port = ntohs (udp->destination_port); + /* throw away ICMP payload, won't be useful for the other side anyway */ + pktlen = sizeof (struct GNUNET_TUN_IcmpHeader); + break; + default: + GNUNET_STATISTICS_update (stats, + gettext_noop ("# ICMPv4 packets dropped (type not allowed)"), + 1, GNUNET_NO); + return; + } + break; + case AF_INET6: + protocol = IPPROTO_ICMPV6; + switch (icmp->type) + { + case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE: + case GNUNET_TUN_ICMPTYPE6_PACKET_TOO_BIG: + case GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED: + case GNUNET_TUN_ICMPTYPE6_PARAMETER_PROBLEM: + if (pktlen < + sizeof (struct GNUNET_TUN_IcmpHeader) + + sizeof (struct GNUNET_TUN_IPv6Header) + 8) + { + /* blame kernel */ + GNUNET_break (0); + return; + } + ipv6 = (const struct GNUNET_TUN_IPv6Header *) &icmp[1]; + protocol = ipv6->next_header; + /* could be TCP or UDP, but both have the ports in the right + place, so that doesn't matter here */ + udp = (const struct GNUNET_TUN_UdpHeader *) &ipv6[1]; + /* swap ports, as they are from the original message */ + destination_port = ntohs (udp->source_port); + source_port = ntohs (udp->destination_port); + /* throw away ICMP payload, won't be useful for the other side anyway */ + pktlen = sizeof (struct GNUNET_TUN_IcmpHeader); + break; + case GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST: + case GNUNET_TUN_ICMPTYPE6_ECHO_REPLY: + break; + default: + GNUNET_STATISTICS_update (stats, + gettext_noop ("# ICMPv6 packets dropped (type not allowed)"), + 1, GNUNET_NO); + return; + } + break; + default: + GNUNET_assert (0); + } + switch (protocol) + { + case IPPROTO_ICMP: + state = get_redirect_state (af, + IPPROTO_ICMP, + source_ip, + 0, + destination_ip, + 0, + NULL); + break; + case IPPROTO_ICMPV6: + state = get_redirect_state (af, + IPPROTO_ICMPV6, + source_ip, + 0, + destination_ip, + 0, + NULL); + break; + case IPPROTO_UDP: + state = get_redirect_state (af, + IPPROTO_UDP, + source_ip, + source_port, + destination_ip, + destination_port, + NULL); + break; + case IPPROTO_TCP: + state = get_redirect_state (af, + IPPROTO_TCP, + source_ip, + source_port, + destination_ip, + destination_port, + NULL); + break; + default: + GNUNET_STATISTICS_update (stats, + gettext_noop ("# ICMP packets dropped (not allowed)"), + 1, + GNUNET_NO); + return; } - - send_icmp_packet_via_tun (&state->specifics.tcp_udp.ri.remote_address, - &state->specifics.tcp_udp.ri.local_address, - &icmp, - payload, pkt_len); - GNUNET_CADET_receive_done (channel); - return GNUNET_YES; + if (NULL == state) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _("ICMP Packet dropped, have no matching connection information\n")); + return; + } + env = GNUNET_MQ_msg_extra (i2v, + pktlen - sizeof (struct GNUNET_TUN_IcmpHeader), + GNUNET_MESSAGE_TYPE_VPN_ICMP_TO_VPN); + i2v->af = htonl (af); + GNUNET_memcpy (&i2v->icmp_header, + icmp, + pktlen); + send_packet_to_cadet_channel (state, + env); } /** - * Send a UDP packet via the TUN interface. + * @brief Handles an UDP packet received from the helper. * - * @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 @a payload + * @param udp A pointer to the Packet + * @param pktlen number of bytes in 'udp' + * @param af address family (AFINET or AF_INET6) + * @param destination_ip destination IP-address of the IP packet (should + * be our local address) + * @param source_ip original source IP-address of the IP packet (should + * be the original destination address) */ static void -send_udp_packet_via_tun (const struct SocketAddress *destination_address, - const struct SocketAddress *source_address, - const void *payload, size_t payload_length) +udp_from_helper (const struct GNUNET_TUN_UdpHeader *udp, + size_t pktlen, + int af, + const void *destination_ip, + const void *source_ip) { - size_t len; + struct ChannelState *state; + struct GNUNET_MQ_Envelope *env; + struct GNUNET_EXIT_UdpReplyMessage *urm; - 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 GNUNET_TUN_IPv4Header); - break; - case AF_INET6: - len += sizeof (struct GNUNET_TUN_IPv6Header); - break; - default: + 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->source_port), + inet_ntop (af, + destination_ip, + dbuf, sizeof (dbuf)), + (unsigned int) ntohs (udp->destination_port)); + } + if (pktlen < sizeof (struct GNUNET_TUN_UdpHeader)) + { + /* blame kernel */ GNUNET_break (0); return; } - len += sizeof (struct GNUNET_TUN_UdpHeader); - len += payload_length; - if (len >= GNUNET_SERVER_MAX_MESSAGE_SIZE) + if (pktlen != ntohs (udp->len)) { + /* blame kernel */ GNUNET_break (0); return; } + state = get_redirect_state (af, + IPPROTO_UDP, + source_ip, + ntohs (udp->source_port), + destination_ip, + ntohs (udp->destination_port), + NULL); + if (NULL == state) { - char buf[len] GNUNET_ALIGN; - struct GNUNET_MessageHeader *hdr; - struct GNUNET_TUN_Layer2PacketHeader *tun; - - hdr= (struct GNUNET_MessageHeader *) buf; - hdr->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER); - hdr->size = htons (len); - tun = (struct GNUNET_TUN_Layer2PacketHeader*) &hdr[1]; - tun->flags = htons (0); - switch (source_address->af) - { - case AF_INET: - { - 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, - NULL, - source_address, - destination_address, - ipv4); - } - break; - case AF_INET6: - { - 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, - NULL, - source_address, - destination_address, - ipv6); - } - break; - default: - GNUNET_assert (0); - break; - } - if (NULL != helper_handle) - (void) GNUNET_HELPER_send (helper_handle, - (const struct GNUNET_MessageHeader*) buf, - GNUNET_YES, - NULL, NULL); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _("UDP Packet dropped, have no matching connection information\n")); + return; } + env = GNUNET_MQ_msg_extra (urm, + pktlen - sizeof (struct GNUNET_TUN_UdpHeader), + GNUNET_MESSAGE_TYPE_VPN_UDP_REPLY); + urm->source_port = htons (0); + urm->destination_port = htons (0); + GNUNET_memcpy (&urm[1], + &udp[1], + pktlen - sizeof (struct GNUNET_TUN_UdpHeader)); + send_packet_to_cadet_channel (state, + env); } /** - * Process a request to forward UDP data to the Internet via this peer. + * @brief Handles a TCP packet received from the helper. * - * @param cls closure, NULL - * @param channel connection to the other end - * @param channel_ctx pointer to our 'struct ChannelState *' - * @param message the actual message - * @return #GNUNET_OK to keep the connection open, - * #GNUNET_SYSERR to close it (signal serious error) + * @param tcp A pointer to the Packet + * @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) + * @param source_ip original source IP-address of the IP packet (should + * be the original destination address) */ -static int -receive_udp_remote (void *cls, - struct GNUNET_CADET_Channel *channel, - void **channel_ctx, - const struct GNUNET_MessageHeader *message) +static void +tcp_from_helper (const struct GNUNET_TUN_TcpHeader *tcp, + size_t pktlen, + int af, + const void *destination_ip, + const void *source_ip) { - struct ChannelState *state = *channel_ctx; - 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; + struct ChannelState *state; + char buf[pktlen] GNUNET_ALIGN; + struct GNUNET_TUN_TcpHeader *mtcp; + struct GNUNET_EXIT_TcpDataMessage *tdm; + struct GNUNET_MQ_Envelope *env; + size_t mlen; - if (GNUNET_YES == state->is_dns) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - if (GNUNET_SYSERR == state->is_dns) { - /* channel is UDP/TCP from now on */ - state->is_dns = GNUNET_NO; + char sbuf[INET6_ADDRSTRLEN]; + char dbuf[INET6_ADDRSTRLEN]; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received TCP packet with %u bytes going from %s:%u to %s:%u\n", + (unsigned int) (pktlen - sizeof (struct GNUNET_TUN_TcpHeader)), + inet_ntop (af, + source_ip, + sbuf, sizeof (sbuf)), + (unsigned int) ntohs (tcp->source_port), + inet_ntop (af, + destination_ip, + dbuf, sizeof (dbuf)), + (unsigned int) ntohs (tcp->destination_port)); } - GNUNET_STATISTICS_update (stats, - gettext_noop ("# Bytes received from CADET"), - pkt_len, GNUNET_NO); - GNUNET_STATISTICS_update (stats, - gettext_noop ("# UDP IP-exit requests received via cadet"), - 1, GNUNET_NO); - if (pkt_len < sizeof (struct GNUNET_EXIT_UdpInternetMessage)) + if (pktlen < sizeof (struct GNUNET_TUN_TcpHeader)) { - GNUNET_break_op (0); - return GNUNET_SYSERR; + /* blame kernel */ + GNUNET_break (0); + return; } - msg = (const struct GNUNET_EXIT_UdpInternetMessage*) message; - pkt_len -= sizeof (struct GNUNET_EXIT_UdpInternetMessage); - af = (int) ntohl (msg->af); - state->specifics.tcp_udp.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*) &msg[1]; - payload = &v4[1]; - pkt_len -= sizeof (struct in_addr); - state->specifics.tcp_udp.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 in6_addr); - state->specifics.tcp_udp.ri.remote_address.address.ipv6 = *v6; - break; - default: - GNUNET_break_op (0); - return GNUNET_SYSERR; + state = get_redirect_state (af, + IPPROTO_TCP, + source_ip, + ntohs (tcp->source_port), + destination_ip, + ntohs (tcp->destination_port), + NULL); + if (NULL == state) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _("TCP Packet dropped, have no matching connection information\n")); + + return; } + /* mug port numbers and crc to avoid information leakage; + sender will need to lookup the correct values anyway */ + GNUNET_memcpy (buf, tcp, pktlen); + mtcp = (struct GNUNET_TUN_TcpHeader *) buf; + mtcp->source_port = 0; + mtcp->destination_port = 0; + mtcp->crc = 0; + + mlen = sizeof (struct GNUNET_EXIT_TcpDataMessage) + (pktlen - sizeof (struct GNUNET_TUN_TcpHeader)); + if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE) { - char buf[INET6_ADDRSTRLEN]; - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Received data from %s for forwarding to UDP %s:%u\n", - GNUNET_i2s (&state->peer), - inet_ntop (af, - &state->specifics.tcp_udp.ri.remote_address.address, - buf, sizeof (buf)), - (unsigned int) ntohs (msg->destination_port)); + GNUNET_break (0); + return; } - state->specifics.tcp_udp.ri.remote_address.proto = IPPROTO_UDP; - state->specifics.tcp_udp.ri.remote_address.port = msg->destination_port; - if (NULL == state->specifics.tcp_udp.heap_node) - setup_state_record (state); - if (0 != ntohs (msg->source_port)) - state->specifics.tcp_udp.ri.local_address.port = msg->source_port; - send_udp_packet_via_tun (&state->specifics.tcp_udp.ri.remote_address, - &state->specifics.tcp_udp.ri.local_address, - payload, pkt_len); - GNUNET_CADET_receive_done (channel); - return GNUNET_YES; + env = GNUNET_MQ_msg_extra (tdm, + pktlen - sizeof (struct GNUNET_TUN_TcpHeader), + GNUNET_MESSAGE_TYPE_VPN_TCP_DATA_TO_VPN); + tdm->reserved = htonl (0); + GNUNET_memcpy (&tdm->tcp_header, + buf, + pktlen); + send_packet_to_cadet_channel (state, + env); } /** - * Process a request via cadet to send a request to a UDP service - * offered by this system. + * Receive packets from the helper-process * - * @param cls closure, NULL - * @param channel connection to the other end - * @param channel_ctx pointer to our 'struct ChannelState *' - * @param message the actual message - * @return #GNUNET_OK to keep the connection open, - * #GNUNET_SYSERR to close it (signal serious error) + * @param cls unused + * @param client unsued + * @param message message received from helper */ static int -receive_udp_service (void *cls, - struct GNUNET_CADET_Channel *channel, - void **channel_ctx, - const struct GNUNET_MessageHeader *message) +message_token (void *cls GNUNET_UNUSED, + void *client GNUNET_UNUSED, + const struct GNUNET_MessageHeader *message) { - struct ChannelState *state = *channel_ctx; - const struct GNUNET_EXIT_UdpServiceMessage *msg; - uint16_t pkt_len = ntohs (message->size); + const struct GNUNET_TUN_Layer2PacketHeader *pkt_tun; + size_t size; - if (NULL == state->specifics.tcp_udp.serv) + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Got %u-byte message of type %u from gnunet-helper-exit\n", + ntohs (message->size), + ntohs (message->type)); + GNUNET_STATISTICS_update (stats, + gettext_noop ("# Packets received from TUN"), + 1, GNUNET_NO); + if (ntohs (message->type) != GNUNET_MESSAGE_TYPE_VPN_HELPER) { - GNUNET_break_op (0); - return GNUNET_SYSERR; + GNUNET_break (0); + return GNUNET_OK; + } + size = ntohs (message->size); + if (size < sizeof (struct GNUNET_TUN_Layer2PacketHeader) + sizeof (struct GNUNET_MessageHeader)) + { + GNUNET_break (0); + return GNUNET_OK; } GNUNET_STATISTICS_update (stats, - gettext_noop ("# Bytes received from CADET"), - pkt_len, GNUNET_NO); - GNUNET_STATISTICS_update (stats, - gettext_noop ("# UDP service requests received via cadet"), - 1, GNUNET_NO); - /* check that we got at least a valid header */ - if (pkt_len < sizeof (struct GNUNET_EXIT_UdpServiceMessage)) + 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)) { - GNUNET_break_op (0); - return GNUNET_SYSERR; + case ETH_P_IPV4: + { + const struct GNUNET_TUN_IPv4Header *pkt4; + + if (size < sizeof (struct GNUNET_TUN_IPv4Header)) + { + /* Kernel to blame? */ + GNUNET_break (0); + return GNUNET_OK; + } + pkt4 = (const struct GNUNET_TUN_IPv4Header *) &pkt_tun[1]; + if (size != ntohs (pkt4->total_length)) + { + /* Kernel to blame? */ + GNUNET_break (0); + return GNUNET_OK; + } + if (pkt4->header_length * 4 != sizeof (struct GNUNET_TUN_IPv4Header)) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _("IPv4 packet options received. Ignored.\n")); + return GNUNET_OK; + } + + size -= sizeof (struct GNUNET_TUN_IPv4Header); + switch (pkt4->protocol) + { + case IPPROTO_UDP: + udp_from_helper ((const struct GNUNET_TUN_UdpHeader *) &pkt4[1], size, + AF_INET, + &pkt4->destination_address, + &pkt4->source_address); + break; + case IPPROTO_TCP: + tcp_from_helper ((const struct GNUNET_TUN_TcpHeader *) &pkt4[1], size, + AF_INET, + &pkt4->destination_address, + &pkt4->source_address); + break; + case IPPROTO_ICMP: + icmp_from_helper ((const struct GNUNET_TUN_IcmpHeader *) &pkt4[1], size, + AF_INET, + &pkt4->destination_address, + &pkt4->source_address); + break; + default: + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _("IPv4 packet with unsupported next header %u received. Ignored.\n"), + (int) pkt4->protocol); + return GNUNET_OK; + } + } + break; + case ETH_P_IPV6: + { + const struct GNUNET_TUN_IPv6Header *pkt6; + + if (size < sizeof (struct GNUNET_TUN_IPv6Header)) + { + /* Kernel to blame? */ + GNUNET_break (0); + return GNUNET_OK; + } + pkt6 = (struct GNUNET_TUN_IPv6Header *) &pkt_tun[1]; + if (size != ntohs (pkt6->payload_length) + sizeof (struct GNUNET_TUN_IPv6Header)) + { + /* Kernel to blame? */ + GNUNET_break (0); + return GNUNET_OK; + } + size -= sizeof (struct GNUNET_TUN_IPv6Header); + switch (pkt6->next_header) + { + case IPPROTO_UDP: + 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 GNUNET_TUN_TcpHeader *) &pkt6[1], size, + AF_INET6, + &pkt6->destination_address, + &pkt6->source_address); + break; + case IPPROTO_ICMPV6: + icmp_from_helper ((const struct GNUNET_TUN_IcmpHeader *) &pkt6[1], size, + AF_INET6, + &pkt6->destination_address, + &pkt6->source_address); + break; + default: + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _("IPv6 packet with unsupported next header %d received. Ignored.\n"), + pkt6->next_header); + return GNUNET_OK; + } + } + break; + default: + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _("Packet from unknown protocol %u received. Ignored.\n"), + ntohs (pkt_tun->proto)); + break; } - msg = (const struct GNUNET_EXIT_UdpServiceMessage*) message; - pkt_len -= sizeof (struct GNUNET_EXIT_UdpServiceMessage); - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Received data from %s for forwarding to UDP service %s on port %u\n", - GNUNET_i2s (&state->peer), - GNUNET_h2s (&state->specifics.tcp_udp.serv->descriptor), - (unsigned int) ntohs (msg->destination_port)); - setup_state_record (state); - if (0 != ntohs (msg->source_port)) - state->specifics.tcp_udp.ri.local_address.port = msg->source_port; - send_udp_packet_via_tun (&state->specifics.tcp_udp.ri.remote_address, - &state->specifics.tcp_udp.ri.local_address, - &msg[1], - pkt_len); - GNUNET_CADET_receive_done (channel); - return GNUNET_YES; + return GNUNET_OK; } @@ -3089,16 +3056,12 @@ receive_udp_service (void *cls, * @param cls closure * @param channel new handle to the channel * @param initiator peer that started the channel - * @param port destination port - * @param options channel options flags * @return initial channel context for the channel */ static void * new_channel (void *cls, struct GNUNET_CADET_Channel *channel, - const struct GNUNET_PeerIdentity *initiator, - const struct GNUNET_HashCode *port, - enum GNUNET_CADET_ChannelOption options) + const struct GNUNET_PeerIdentity *initiator) { struct ChannelState *s = GNUNET_new (struct ChannelState); @@ -3106,7 +3069,8 @@ new_channel (void *cls, s->peer = *initiator; GNUNET_STATISTICS_update (stats, gettext_noop ("# Inbound CADET channels created"), - 1, GNUNET_NO); + 1, + GNUNET_NO); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received inbound channel from `%s'\n", GNUNET_i2s (initiator)); @@ -3115,64 +3079,6 @@ new_channel (void *cls, } -/** - * Function called by cadet whenever an inbound channel is destroyed. - * Should clean up any associated state. - * - * @param cls closure (set from #GNUNET_CADET_connect) - * @param channel connection to the other end (henceforth invalid) - * @param channel_ctx place where local state associated - * with the channel is stored - */ -static void -clean_channel (void *cls, - const struct GNUNET_CADET_Channel *channel, - void *channel_ctx) -{ - struct ChannelState *s = channel_ctx; - struct ChannelMessageQueue *tnq; - - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Channel destroyed\n"); - if (GNUNET_SYSERR == s->is_dns) - { - GNUNET_free (s); - return; - } - if (GNUNET_YES == s->is_dns) - { - if (channels[s->specifics.dns.my_id] == s) - channels[s->specifics.dns.my_id] = NULL; - GNUNET_free_non_null (s->specifics.dns.reply); - } - else - { - while (NULL != (tnq = s->specifics.tcp_udp.head)) - { - GNUNET_CONTAINER_DLL_remove (s->specifics.tcp_udp.head, - s->specifics.tcp_udp.tail, - tnq); - GNUNET_free (tnq); - } - if (NULL != s->specifics.tcp_udp.heap_node) - { - GNUNET_assert (GNUNET_YES == - GNUNET_CONTAINER_multihashmap_remove (connections_map, - &s->specifics.tcp_udp.state_key, - s)); - GNUNET_CONTAINER_heap_remove_node (s->specifics.tcp_udp.heap_node); - s->specifics.tcp_udp.heap_node = NULL; - } - } - if (NULL != s->th) - { - GNUNET_CADET_notify_transmit_ready_cancel (s->th); - s->th = NULL; - } - GNUNET_free (s); -} - - /** * Function that frees everything from a hashmap * @@ -3241,6 +3147,21 @@ cleanup (void *cls) NULL); GNUNET_CONTAINER_multihashmap_destroy (services); } + if (NULL != dns_port) + { + GNUNET_CADET_close_port (dns_port); + dns_port = NULL; + } + if (NULL != cadet_port4) + { + GNUNET_CADET_close_port (cadet_port4); + cadet_port4 = NULL; + } + if (NULL != cadet_port6) + { + GNUNET_CADET_close_port (cadet_port6); + cadet_port6 = NULL; + } if (NULL != cadet_handle) { GNUNET_CADET_disconnect (cadet_handle); @@ -3286,7 +3207,8 @@ cleanup (void *cls) } if (NULL != stats) { - GNUNET_STATISTICS_destroy (stats, GNUNET_NO); + GNUNET_STATISTICS_destroy (stats, + GNUNET_NO); stats = NULL; } for (i=0;i<8;i++) @@ -3614,6 +3536,13 @@ parse_ip_options () static void advertise_dns_exit () { + struct GNUNET_MQ_MessageHandler handlers[] = { + GNUNET_MQ_hd_var_size (dns_request, + GNUNET_MESSAGE_TYPE_VPN_DNS_TO_INTERNET, + struct DnsResponseMessage, + NULL), + GNUNET_MQ_handler_end () + }; char *dns_exit; struct GNUNET_HashCode port; struct in_addr dns_exit4; @@ -3650,10 +3579,13 @@ advertise_dns_exit () GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Opening CADET port %s for DNS exit service\n", GNUNET_h2s (&port)); - GNUNET_CADET_open_port (cadet_handle, - &port, - &new_channel, - NULL); + dns_port = GNUNET_CADET_open_porT (cadet_handle, + &port, + &new_channel, + NULL, + NULL, + &clean_channel, + handlers); /* advertise exit */ dht = GNUNET_DHT_connect (cfg, 1); @@ -3833,16 +3765,24 @@ run (void *cls, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg_) { - static struct GNUNET_CADET_MessageHandler handlers[] = { - {&receive_icmp_service, GNUNET_MESSAGE_TYPE_VPN_ICMP_TO_SERVICE, 0}, - {&receive_icmp_remote, GNUNET_MESSAGE_TYPE_VPN_ICMP_TO_INTERNET, 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_TO_EXIT, 0}, - {&receive_dns_request, GNUNET_MESSAGE_TYPE_VPN_DNS_TO_INTERNET, 0}, - {NULL, 0, 0} + struct GNUNET_MQ_MessageHandler handlers[] = { + GNUNET_MQ_hd_var_size (icmp_remote, + GNUNET_MESSAGE_TYPE_VPN_ICMP_TO_INTERNET, + struct GNUNET_EXIT_IcmpInternetMessage, + NULL), + GNUNET_MQ_hd_var_size (udp_remote, + GNUNET_MESSAGE_TYPE_VPN_UDP_TO_INTERNET, + struct GNUNET_EXIT_UdpInternetMessage, + NULL), + GNUNET_MQ_hd_var_size (tcp_remote, + GNUNET_MESSAGE_TYPE_VPN_TCP_TO_INTERNET_START, + struct GNUNET_EXIT_TcpInternetStartMessage, + NULL), + GNUNET_MQ_hd_var_size (tcp_data, + GNUNET_MESSAGE_TYPE_VPN_TCP_DATA_TO_EXIT, + struct GNUNET_EXIT_TcpDataMessage, + NULL), + GNUNET_MQ_handler_end () }; struct GNUNET_HashCode port; char *policy; @@ -3889,10 +3829,7 @@ run (void *cls, NULL); stats = GNUNET_STATISTICS_create ("exit", cfg); - cadet_handle = GNUNET_CADET_connect (cfg, - NULL, - &clean_channel, - handlers); + cadet_handle = GNUNET_CADET_connecT (cfg); if (NULL == cadet_handle) { GNUNET_SCHEDULER_shutdown (); @@ -3925,10 +3862,13 @@ run (void *cls, GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Opening CADET port %s for IPv4 gateway service\n", GNUNET_h2s (&port)); - GNUNET_CADET_open_port (cadet_handle, - &port, - &new_channel, - NULL); + cadet_port4 = GNUNET_CADET_open_porT (cadet_handle, + &port, + &new_channel, + NULL, + NULL, + &clean_channel, + handlers); policy = NULL; if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg, @@ -3962,10 +3902,13 @@ run (void *cls, GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Opening CADET port %s for IPv6 gateway service\n", GNUNET_h2s (&port)); - GNUNET_CADET_open_port (cadet_handle, - &port, - &new_channel, - NULL); + cadet_port6 = GNUNET_CADET_open_porT (cadet_handle, + &port, + &new_channel, + NULL, + NULL, + &clean_channel, + handlers); policy = NULL; if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg,