/*
This file is part of GNUnet.
- Copyright (C) 2010, 2011, 2012, 2016 Christian Grothoff
+ Copyright (C) 2010, 2011, 2012, 2016, 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
*/
struct GNUNET_REGEX_Search *search;
- /**
- * Active transmission handle, NULL for none.
- */
- struct GNUNET_CADET_TransmitHandle *th;
-
/**
* Entry for this entry in the channel_heap, NULL as long as this
* channel state is not fully bound.
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Cleaning up channel state\n");
- if (NULL != ts->th)
- {
- GNUNET_CADET_notify_transmit_ready_cancel (ts->th);
- ts->th = NULL;
- }
if (NULL != (channel = ts->channel))
{
ts->channel = NULL;
}
-/**
- * Send a message from the message queue via cadet.
- *
- * @param cls the `struct ChannelState` with the message queue
- * @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 *ts = cls;
- struct ChannelMessageQueueEntry *tnq;
- size_t ret;
-
- ts->th = NULL;
- if (NULL == buf)
- return 0;
- tnq = ts->tmq_head;
- GNUNET_assert (NULL != tnq);
- GNUNET_assert (size >= tnq->len);
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Sending %u bytes via cadet channel\n",
- (unsigned int) tnq->len);
- GNUNET_CONTAINER_DLL_remove (ts->tmq_head,
- ts->tmq_tail,
- tnq);
- ts->tmq_length--;
- GNUNET_memcpy (buf, tnq->msg, tnq->len);
- ret = tnq->len;
- GNUNET_free (tnq);
- if (NULL != (tnq = ts->tmq_head))
- {
- if (NULL == ts->th)
- ts->th = GNUNET_CADET_notify_transmit_ready (ts->channel,
- GNUNET_NO /* cork */,
- GNUNET_TIME_UNIT_FOREVER_REL,
- tnq->len,
- &send_to_peer_notify_callback,
- ts);
- }
- GNUNET_STATISTICS_update (stats,
- gettext_noop ("# Bytes given to cadet for transmission"),
- ret, GNUNET_NO);
- return ret;
-}
-
-
/**
* Add the given message to the given channel and trigger the
* transmission process.
*
- * @param tnq message to queue
* @param ts channel to queue the message for
+ * @param env message to queue
*/
static void
-send_to_channel (struct ChannelMessageQueueEntry *tnq,
- struct ChannelState *ts)
+send_to_channel (struct ChannelState *ts,
+ struct GNUNET_MQ_Envelope *env)
{
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Queueing %u bytes for transmission via cadet channel\n",
- (unsigned int) tnq->len);
+ struct GNUNET_MQ_Handle *mq;
+
GNUNET_assert (NULL != ts->channel);
- GNUNET_CONTAINER_DLL_insert_tail (ts->tmq_head,
- ts->tmq_tail,
- tnq);
- ts->tmq_length++;
- if (ts->tmq_length > MAX_MESSAGE_QUEUE_SIZE)
+ mq = GNUNET_CADET_get_mq (ts->channel);
+ GNUNET_MQ_send (mq,
+ env);
+ if (GNUNET_MQ_get_length (mq) > MAX_MESSAGE_QUEUE_SIZE)
{
- struct ChannelMessageQueueEntry *dq;
-
- dq = ts->tmq_head;
- GNUNET_assert (dq != tnq);
- GNUNET_CONTAINER_DLL_remove (ts->tmq_head,
- ts->tmq_tail,
- dq);
- ts->tmq_length--;
- GNUNET_CADET_notify_transmit_ready_cancel (ts->th);
- ts->th = NULL;
+ env = GNUNET_MQ_unsent_head (mq);
+ GNUNET_assert (NULL != env);
GNUNET_STATISTICS_update (stats,
- gettext_noop ("# Bytes dropped in cadet queue (overflow)"),
- dq->len,
+ gettext_noop ("# Messages dropped in cadet queue (overflow)"),
+ 1,
GNUNET_NO);
- GNUNET_free (dq);
+ GNUNET_MQ_discard (env);
}
- if (NULL == ts->th)
- ts->th = GNUNET_CADET_notify_transmit_ready (ts->channel,
- GNUNET_NO /* cork */,
- GNUNET_TIME_UNIT_FOREVER_REL,
- tnq->len,
- &send_to_peer_notify_callback,
- ts);
}
/**
- * Regex has found a potential exit peer for us; consider using it.
+ * Function called whenever a channel is destroyed. Should clean up
+ * any associated state.
*
- * @param cls the `struct ChannelState`
- * @param id Peer providing a regex that matches the string.
- * @param get_path Path of the get request.
- * @param get_path_length Lenght of @a get_path.
- * @param put_path Path of the put request.
- * @param put_path_length Length of the @a put_path.
+ * @param cls our `struct ChannelState`
+ * @param channel connection to the other end (henceforth invalid)
*/
static void
-handle_regex_result (void *cls,
- const struct GNUNET_PeerIdentity *id,
- const struct GNUNET_PeerIdentity *get_path,
- unsigned int get_path_length,
- const struct GNUNET_PeerIdentity *put_path,
- unsigned int put_path_length)
+channel_cleaner (void *cls,
+ const struct GNUNET_CADET_Channel *channel)
{
struct ChannelState *ts = cls;
- struct GNUNET_HashCode port;
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Exit %s found for destination %s!\n",
- GNUNET_i2s (id),
- print_channel_destination (&ts->destination));
- GNUNET_REGEX_search_cancel (ts->search);
- ts->search = NULL;
- switch (ts->af)
- {
- case AF_INET:
- /* these must match the strings used in gnunet-daemon-exit */
- GNUNET_CRYPTO_hash (GNUNET_APPLICATION_PORT_IPV4_GATEWAY,
- strlen (GNUNET_APPLICATION_PORT_IPV4_GATEWAY),
- &port);
- break;
- case AF_INET6:
- /* these must match the strings used in gnunet-daemon-exit */
- GNUNET_CRYPTO_hash (GNUNET_APPLICATION_PORT_IPV6_GATEWAY,
- strlen (GNUNET_APPLICATION_PORT_IPV6_GATEWAY),
- &port);
- break;
- default:
- GNUNET_break (0);
- return;
- }
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Creating tunnel to %s for destination %s!\n",
- GNUNET_i2s (id),
+ ts->channel = NULL; /* we must not call GNUNET_CADET_channel_destroy() anymore */
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "CADET notified us about death of channel to `%s'\n",
print_channel_destination (&ts->destination));
- ts->channel = GNUNET_CADET_channel_create (cadet_handle,
- ts,
- id,
- &port,
- GNUNET_CADET_OPTION_DEFAULT);
+ free_channel_state (ts);
}
/**
- * Initialize the given destination entry's cadet channel.
+ * Synthesize a plausible ICMP payload for an ICMP error
+ * response on the given channel.
*
- * @param dt destination channel for which we need to setup a channel
- * @param client_af address family of the address returned to the client
- * @return channel state of the channel that was created
+ * @param ts channel information
+ * @param ipp IPv4 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 struct ChannelState *
-create_channel_to_destination (struct DestinationChannel *dt,
- int client_af)
+static void
+make_up_icmpv4_payload (struct ChannelState *ts,
+ struct GNUNET_TUN_IPv4Header *ipp,
+ struct GNUNET_TUN_UdpHeader *udp)
{
- struct ChannelState *ts;
-
- GNUNET_STATISTICS_update (stats,
- gettext_noop ("# Cadet channels created"),
- 1,
- GNUNET_NO);
- ts = GNUNET_new (struct ChannelState);
- ts->af = client_af;
- ts->destination = *dt->destination;
- ts->destination.heap_node = NULL; /* copy is NOT in destination heap */
- ts->destination_port = dt->destination_port;
- if (dt->destination->is_service)
- {
- struct GNUNET_HashCode cadet_port;
-
- GNUNET_TUN_compute_service_cadet_port (&ts->destination.details.service_destination.service_descriptor,
- ts->destination_port,
- &cadet_port);
- ts->channel
- = GNUNET_CADET_channel_create (cadet_handle,
- ts,
- &dt->destination->details.service_destination.target,
- &cadet_port,
- GNUNET_CADET_OPTION_DEFAULT);
- if (NULL == ts->channel)
- {
- GNUNET_break (0);
- GNUNET_free (ts);
- return NULL;
- }
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Creating channel to peer %s offering service %s on port %u\n",
- GNUNET_i2s (&dt->destination->details.service_destination.target),
- GNUNET_h2s (&ts->destination.details.service_destination.service_descriptor),
- (unsigned int) ts->destination_port);
- }
- else
- {
- char *policy;
-
- switch (dt->destination->details.exit_destination.af)
- {
- case AF_INET:
- {
- char address[GNUNET_TUN_IPV4_REGEXLEN];
-
- GNUNET_TUN_ipv4toregexsearch (&dt->destination->details.exit_destination.ip.v4,
- dt->destination_port,
- address);
- GNUNET_asprintf (&policy,
- "%s%s",
- GNUNET_APPLICATION_TYPE_EXIT_REGEX_PREFIX,
- address);
- break;
- }
- case AF_INET6:
- {
- char address[GNUNET_TUN_IPV6_REGEXLEN];
+ GNUNET_TUN_initialize_ipv4_header (ipp,
+ ts->protocol,
+ sizeof (struct GNUNET_TUN_TcpHeader),
+ &ts->source_ip.v4,
+ &ts->destination_ip.v4);
+ udp->source_port = htons (ts->source_port);
+ udp->destination_port = htons (ts->destination_port);
+ udp->len = htons (0);
+ udp->crc = htons (0);
+}
- GNUNET_TUN_ipv6toregexsearch (&dt->destination->details.exit_destination.ip.v6,
- dt->destination_port,
- address);
- GNUNET_asprintf (&policy,
- "%s%s",
- GNUNET_APPLICATION_TYPE_EXIT_REGEX_PREFIX,
- address);
- break;
- }
- default:
- GNUNET_assert (0);
- break;
- }
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Requesting connect by string: %s\n",
- policy);
- ts->search = GNUNET_REGEX_search (cfg,
- policy,
- &handle_regex_result,
- ts);
- GNUNET_free (policy);
- }
- return ts;
+/**
+ * Synthesize a plausible ICMP payload for an ICMP error
+ * response on the given channel.
+ *
+ * @param ts 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_icmpv6_payload (struct ChannelState *ts,
+ struct GNUNET_TUN_IPv6Header *ipp,
+ struct GNUNET_TUN_UdpHeader *udp)
+{
+ GNUNET_TUN_initialize_ipv6_header (ipp,
+ ts->protocol,
+ sizeof (struct GNUNET_TUN_TcpHeader),
+ &ts->source_ip.v6,
+ &ts->destination_ip.v6);
+ udp->source_port = htons (ts->source_port);
+ udp->destination_port = htons (ts->destination_port);
+ udp->len = htons (0);
+ udp->crc = htons (0);
}
/**
- * We have too many active channels. Clean up the oldest channel.
+ * We got an ICMP packet back from the CADET channel. Check it is OK.
*
- * @param except channel that must NOT be cleaned up, even if it is the oldest
+ * @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 void
-expire_channel (struct ChannelState *except)
+static int
+check_icmp_back (void *cls,
+ const struct GNUNET_EXIT_IcmpToVPNMessage *i2v)
{
- struct ChannelState *ts;
+ struct ChannelState *ts = cls;
- ts = GNUNET_CONTAINER_heap_peek (channel_heap);
- GNUNET_assert (NULL != ts);
- if (except == ts)
- return; /* can't do this */
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Tearing down expired channel to %s\n",
- print_channel_destination (&except->destination));
- free_channel_state (ts);
+ if (NULL == ts->heap_node)
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ if (AF_UNSPEC == ts->af)
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ return GNUNET_OK;
}
/**
- * Route a packet via cadet to the given destination.
+ * We got an ICMP packet back from the CADET channel. Pass it on to the
+ * local virtual interface via the helper.
*
- * @param destination description of the destination
- * @param af address family on this end (AF_INET or AF_INET6)
- * @param protocol IPPROTO_TCP or IPPROTO_UDP or IPPROTO_ICMP or IPPROTO_ICMPV6
- * @param source_ip source IP used by the sender (struct in_addr or struct in6_addr)
- * @param destination_ip destination IP used by the sender (struct in_addr or struct in6_addr)
- * @param payload payload of the packet after the IP header
- * @param payload_length number of bytes in @a payload
+ * @param cls our `struct ChannelState *`
+ * @param message the actual message
*/
static void
-route_packet (struct DestinationEntry *destination,
- int af,
- uint8_t protocol,
- const void *source_ip,
- const void *destination_ip,
- const void *payload,
- size_t payload_length)
+handle_icmp_back (void *cls,
+ const struct GNUNET_EXIT_IcmpToVPNMessage *i2v)
{
- struct GNUNET_HashCode key;
- struct ChannelState *ts;
- struct ChannelMessageQueueEntry *tnq;
- size_t alen;
+ struct ChannelState *ts = cls;
size_t mlen;
- const struct GNUNET_TUN_UdpHeader *udp;
- const struct GNUNET_TUN_TcpHeader *tcp;
- const struct GNUNET_TUN_IcmpHeader *icmp;
- struct DestinationChannel *dt;
- uint16_t source_port;
- uint16_t destination_port;
- switch (protocol)
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop ("# ICMP packets received from cadet"),
+ 1,
+ GNUNET_NO);
+ mlen = ntohs (i2v->header.size) - sizeof (struct GNUNET_EXIT_IcmpToVPNMessage);
+ {
+ char sbuf[INET6_ADDRSTRLEN];
+ char dbuf[INET6_ADDRSTRLEN];
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Received ICMP packet from cadet, sending %u bytes from %s -> %s via TUN\n",
+ (unsigned int) mlen,
+ inet_ntop (ts->af, &ts->destination_ip, sbuf, sizeof (sbuf)),
+ inet_ntop (ts->af, &ts->source_ip, dbuf, sizeof (dbuf)));
+ }
+ switch (ts->af)
+ {
+ case AF_INET:
+ {
+ size_t size = sizeof (struct GNUNET_TUN_IPv4Header)
+ + sizeof (struct GNUNET_TUN_IcmpHeader)
+ + sizeof (struct GNUNET_MessageHeader) +
+ sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
+ mlen;
+ {
+ /* reserve some extra space in case we have an ICMP type here where
+ we will need to make up the payload ourselves */
+ char buf[size + sizeof (struct GNUNET_TUN_IPv4Header) + 8] GNUNET_ALIGN;
+ struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
+ struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
+ struct GNUNET_TUN_IPv4Header *ipv4 = (struct GNUNET_TUN_IPv4Header *) &tun[1];
+ struct GNUNET_TUN_IcmpHeader *icmp = (struct GNUNET_TUN_IcmpHeader *) &ipv4[1];
+ msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
+ tun->flags = htons (0);
+ tun->proto = htons (ETH_P_IPV4);
+ GNUNET_TUN_initialize_ipv4_header (ipv4,
+ IPPROTO_ICMP,
+ sizeof (struct GNUNET_TUN_IcmpHeader) + mlen,
+ &ts->destination_ip.v4,
+ &ts->source_ip.v4);
+ *icmp = i2v->icmp_header;
+ GNUNET_memcpy (&icmp[1],
+ &i2v[1],
+ mlen);
+ /* For some ICMP types, we need to adjust (make up) the payload here.
+ Also, depending on the AF used on the other side, we have to
+ do ICMP PT (translate ICMP types) */
+ switch (ntohl (i2v->af))
+ {
+ case AF_INET:
+ 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:
+ {
+ struct GNUNET_TUN_IPv4Header *ipp = (struct GNUNET_TUN_IPv4Header *) &icmp[1];
+ struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
+
+ if (mlen != 0)
+ {
+ /* sender did not strip ICMP payload? */
+ GNUNET_break_op (0);
+ return;
+ }
+ size += sizeof (struct GNUNET_TUN_IPv4Header) + 8;
+ GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
+ make_up_icmpv4_payload (ts, ipp, udp);
+ }
+ break;
+ default:
+ GNUNET_break_op (0);
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop ("# ICMPv4 packets dropped (type not allowed)"),
+ 1, GNUNET_NO);
+ return;
+ }
+ /* end AF_INET */
+ break;
+ case AF_INET6:
+ /* ICMP PT 6-to-4 and possibly making up payloads */
+ switch (icmp->type)
+ {
+ case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE:
+ icmp->type = GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE;
+ {
+ struct GNUNET_TUN_IPv4Header *ipp = (struct GNUNET_TUN_IPv4Header *) &icmp[1];
+ struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
+
+ if (mlen != 0)
+ {
+ /* sender did not strip ICMP payload? */
+ GNUNET_break_op (0);
+ return;
+ }
+ size += sizeof (struct GNUNET_TUN_IPv4Header) + 8;
+ GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
+ make_up_icmpv4_payload (ts, ipp, udp);
+ }
+ break;
+ case GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED:
+ icmp->type = GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED;
+ {
+ struct GNUNET_TUN_IPv4Header *ipp = (struct GNUNET_TUN_IPv4Header *) &icmp[1];
+ struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
+
+ if (mlen != 0)
+ {
+ /* sender did not strip ICMP payload? */
+ GNUNET_break_op (0);
+ return;
+ }
+ size += sizeof (struct GNUNET_TUN_IPv4Header) + 8;
+ GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
+ make_up_icmpv4_payload (ts, ipp, udp);
+ }
+ break;
+ case GNUNET_TUN_ICMPTYPE6_PACKET_TOO_BIG:
+ case GNUNET_TUN_ICMPTYPE6_PARAMETER_PROBLEM:
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop ("# ICMPv6 packets dropped (impossible PT to v4)"),
+ 1, GNUNET_NO);
+ return;
+ case GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST:
+ icmp->type = GNUNET_TUN_ICMPTYPE_ECHO_REQUEST;
+ break;
+ case GNUNET_TUN_ICMPTYPE6_ECHO_REPLY:
+ icmp->type = GNUNET_TUN_ICMPTYPE_ECHO_REPLY;
+ break;
+ default:
+ GNUNET_break_op (0);
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop ("# ICMPv6 packets dropped (type not allowed)"),
+ 1, GNUNET_NO);
+ return;
+ }
+ /* end AF_INET6 */
+ break;
+ default:
+ GNUNET_break_op (0);
+ return;
+ }
+ msg->size = htons (size);
+ GNUNET_TUN_calculate_icmp_checksum (icmp,
+ &i2v[1],
+ mlen);
+ (void) GNUNET_HELPER_send (helper_handle,
+ msg,
+ GNUNET_YES,
+ NULL, NULL);
+ }
+ }
+ break;
+ case AF_INET6:
+ {
+ size_t size = sizeof (struct GNUNET_TUN_IPv6Header)
+ + sizeof (struct GNUNET_TUN_IcmpHeader)
+ + sizeof (struct GNUNET_MessageHeader) +
+ sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
+ mlen;
+ {
+ char buf[size + sizeof (struct GNUNET_TUN_IPv6Header) + 8] GNUNET_ALIGN;
+ struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
+ struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
+ struct GNUNET_TUN_IPv6Header *ipv6 = (struct GNUNET_TUN_IPv6Header *) &tun[1];
+ struct GNUNET_TUN_IcmpHeader *icmp = (struct GNUNET_TUN_IcmpHeader *) &ipv6[1];
+ msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
+ tun->flags = htons (0);
+ tun->proto = htons (ETH_P_IPV6);
+ GNUNET_TUN_initialize_ipv6_header (ipv6,
+ IPPROTO_ICMPV6,
+ sizeof (struct GNUNET_TUN_IcmpHeader) + mlen,
+ &ts->destination_ip.v6,
+ &ts->source_ip.v6);
+ *icmp = i2v->icmp_header;
+ GNUNET_memcpy (&icmp[1],
+ &i2v[1],
+ mlen);
+
+ /* For some ICMP types, we need to adjust (make up) the payload here.
+ Also, depending on the AF used on the other side, we have to
+ do ICMP PT (translate ICMP types) */
+ switch (ntohl (i2v->af))
+ {
+ case AF_INET:
+ /* ICMP PT 4-to-6 and possibly making up payloads */
+ switch (icmp->type)
+ {
+ case GNUNET_TUN_ICMPTYPE_ECHO_REPLY:
+ icmp->type = GNUNET_TUN_ICMPTYPE6_ECHO_REPLY;
+ break;
+ case GNUNET_TUN_ICMPTYPE_ECHO_REQUEST:
+ icmp->type = GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST;
+ break;
+ case GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE:
+ icmp->type = GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE;
+ {
+ struct GNUNET_TUN_IPv6Header *ipp = (struct GNUNET_TUN_IPv6Header *) &icmp[1];
+ struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
+
+ if (mlen != 0)
+ {
+ /* sender did not strip ICMP payload? */
+ GNUNET_break_op (0);
+ return;
+ }
+ size += sizeof (struct GNUNET_TUN_IPv6Header) + 8;
+ GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
+ make_up_icmpv6_payload (ts, ipp, udp);
+ }
+ break;
+ case GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED:
+ icmp->type = GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED;
+ {
+ struct GNUNET_TUN_IPv6Header *ipp = (struct GNUNET_TUN_IPv6Header *) &icmp[1];
+ struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
+
+ if (mlen != 0)
+ {
+ /* sender did not strip ICMP payload? */
+ GNUNET_break_op (0);
+ return;
+ }
+ size += sizeof (struct GNUNET_TUN_IPv6Header) + 8;
+ GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
+ make_up_icmpv6_payload (ts, ipp, udp);
+ }
+ break;
+ case GNUNET_TUN_ICMPTYPE_SOURCE_QUENCH:
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop ("# ICMPv4 packets dropped (impossible PT to v6)"),
+ 1, GNUNET_NO);
+ return;
+ default:
+ GNUNET_break_op (0);
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop ("# ICMPv4 packets dropped (type not allowed)"),
+ 1, GNUNET_NO);
+ return;
+ }
+ /* end AF_INET */
+ break;
+ case AF_INET6:
+ switch (icmp->type)
+ {
+ case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE:
+ case GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED:
+ case GNUNET_TUN_ICMPTYPE6_PACKET_TOO_BIG:
+ case GNUNET_TUN_ICMPTYPE6_PARAMETER_PROBLEM:
+ {
+ struct GNUNET_TUN_IPv6Header *ipp = (struct GNUNET_TUN_IPv6Header *) &icmp[1];
+ struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
+
+ if (mlen != 0)
+ {
+ /* sender did not strip ICMP payload? */
+ GNUNET_break_op (0);
+ return;
+ }
+ size += sizeof (struct GNUNET_TUN_IPv6Header) + 8;
+ GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
+ make_up_icmpv6_payload (ts, ipp, udp);
+ }
+ break;
+ case GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST:
+ break;
+ default:
+ GNUNET_break_op (0);
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop ("# ICMPv6 packets dropped (type not allowed)"),
+ 1, GNUNET_NO);
+ return;
+ }
+ /* end AF_INET6 */
+ break;
+ default:
+ GNUNET_break_op (0);
+ return;
+ }
+ msg->size = htons (size);
+ GNUNET_TUN_calculate_icmp_checksum (icmp,
+ &i2v[1], mlen);
+ (void) GNUNET_HELPER_send (helper_handle,
+ msg,
+ GNUNET_YES,
+ NULL, NULL);
+ }
+ }
+ break;
+ default:
+ GNUNET_assert (0);
+ }
+ GNUNET_CONTAINER_heap_update_cost (ts->heap_node,
+ GNUNET_TIME_absolute_get ().abs_value_us);
+ GNUNET_CADET_receive_done (ts->channel);
+}
+
+
+/**
+ * We got a UDP packet back from the CADET channel. Check that it is OK.
+ *
+ * @param cls our `struct ChannelState *`
+ * @param reply the actual message
+ * @return #GNUNET_OK to keep the connection open,
+ * #GNUNET_SYSERR to close it (signal serious error)
+ */
+static int
+check_udp_back (void *cls,
+ const struct GNUNET_EXIT_UdpReplyMessage *reply)
+{
+ struct ChannelState *ts = cls;
+
+ if (NULL == ts->heap_node)
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ if (AF_UNSPEC == ts->af)
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ return GNUNET_OK;
+}
+
+
+/**
+ * We got a UDP packet back from the CADET channel. Pass it on to the
+ * local virtual interface via the helper.
+ *
+ * @param cls our `struct ChannelState *`
+ * @param reply the actual message
+ */
+static void
+handle_udp_back (void *cls,
+ const struct GNUNET_EXIT_UdpReplyMessage *reply)
+{
+ struct ChannelState *ts = cls;
+ size_t mlen;
+
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop ("# UDP packets received from cadet"),
+ 1,
+ GNUNET_NO);
+ mlen = ntohs (reply->header.size) - sizeof (struct GNUNET_EXIT_UdpReplyMessage);
+ {
+ char sbuf[INET6_ADDRSTRLEN];
+ char dbuf[INET6_ADDRSTRLEN];
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Received UDP reply from cadet, sending %u bytes from [%s]:%u -> [%s]:%u via TUN\n",
+ (unsigned int) mlen,
+ inet_ntop (ts->af, &ts->destination_ip, sbuf, sizeof (sbuf)),
+ ts->destination_port,
+ inet_ntop (ts->af, &ts->source_ip, dbuf, sizeof (dbuf)),
+ ts->source_port);
+ }
+ switch (ts->af)
+ {
+ case AF_INET:
+ {
+ size_t size = sizeof (struct GNUNET_TUN_IPv4Header)
+ + sizeof (struct GNUNET_TUN_UdpHeader)
+ + sizeof (struct GNUNET_MessageHeader) +
+ sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
+ mlen;
+ {
+ char buf[size] GNUNET_ALIGN;
+ struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
+ struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
+ struct GNUNET_TUN_IPv4Header *ipv4 = (struct GNUNET_TUN_IPv4Header *) &tun[1];
+ struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipv4[1];
+ msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
+ msg->size = htons (size);
+ tun->flags = htons (0);
+ tun->proto = htons (ETH_P_IPV4);
+ GNUNET_TUN_initialize_ipv4_header (ipv4,
+ IPPROTO_UDP,
+ sizeof (struct GNUNET_TUN_UdpHeader) + mlen,
+ &ts->destination_ip.v4,
+ &ts->source_ip.v4);
+ if (0 == ntohs (reply->source_port))
+ udp->source_port = htons (ts->destination_port);
+ else
+ udp->source_port = reply->source_port;
+ if (0 == ntohs (reply->destination_port))
+ udp->destination_port = htons (ts->source_port);
+ else
+ udp->destination_port = reply->destination_port;
+ udp->len = htons (mlen + sizeof (struct GNUNET_TUN_UdpHeader));
+ GNUNET_TUN_calculate_udp4_checksum (ipv4,
+ udp,
+ &reply[1],
+ mlen);
+ GNUNET_memcpy (&udp[1],
+ &reply[1],
+ mlen);
+ (void) GNUNET_HELPER_send (helper_handle,
+ msg,
+ GNUNET_YES,
+ NULL, NULL);
+ }
+ }
+ break;
+ case AF_INET6:
+ {
+ size_t size = sizeof (struct GNUNET_TUN_IPv6Header)
+ + sizeof (struct GNUNET_TUN_UdpHeader)
+ + sizeof (struct GNUNET_MessageHeader) +
+ sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
+ mlen;
+ {
+ char buf[size] GNUNET_ALIGN;
+ struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
+ struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
+ struct GNUNET_TUN_IPv6Header *ipv6 = (struct GNUNET_TUN_IPv6Header *) &tun[1];
+ struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipv6[1];
+ msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
+ msg->size = htons (size);
+ tun->flags = htons (0);
+ tun->proto = htons (ETH_P_IPV6);
+ GNUNET_TUN_initialize_ipv6_header (ipv6,
+ IPPROTO_UDP,
+ sizeof (struct GNUNET_TUN_UdpHeader) + mlen,
+ &ts->destination_ip.v6,
+ &ts->source_ip.v6);
+ if (0 == ntohs (reply->source_port))
+ udp->source_port = htons (ts->destination_port);
+ else
+ udp->source_port = reply->source_port;
+ if (0 == ntohs (reply->destination_port))
+ udp->destination_port = htons (ts->source_port);
+ else
+ udp->destination_port = reply->destination_port;
+ udp->len = htons (mlen + sizeof (struct GNUNET_TUN_UdpHeader));
+ GNUNET_TUN_calculate_udp6_checksum (ipv6,
+ udp,
+ &reply[1], mlen);
+ GNUNET_memcpy (&udp[1],
+ &reply[1],
+ mlen);
+ (void) GNUNET_HELPER_send (helper_handle,
+ msg,
+ GNUNET_YES,
+ NULL, NULL);
+ }
+ }
+ break;
+ default:
+ GNUNET_assert (0);
+ }
+ GNUNET_CONTAINER_heap_update_cost (ts->heap_node,
+ GNUNET_TIME_absolute_get ().abs_value_us);
+ GNUNET_CADET_receive_done (ts->channel);
+}
+
+
+/**
+ * We got a TCP packet back from the CADET channel. Check it is OK.
+ *
+ * @param cls our `struct ChannelState *`
+ * @param data the actual message
+ * @return #GNUNET_OK to keep the connection open,
+ * #GNUNET_SYSERR to close it (signal serious error)
+ */
+static int
+check_tcp_back (void *cls,
+ const struct GNUNET_EXIT_TcpDataMessage *data)
+{
+ struct ChannelState *ts = cls;
+
+ if (NULL == ts->heap_node)
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ if (data->tcp_header.off * 4 < sizeof (struct GNUNET_TUN_TcpHeader))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ return GNUNET_OK;
+}
+
+
+/**
+ * We got a TCP packet back from the CADET channel. Pass it on to the
+ * local virtual interface via the helper.
+ *
+ * @param cls our `struct ChannelState *`
+ * @param data the actual message
+ */
+static void
+handle_tcp_back (void *cls,
+ const struct GNUNET_EXIT_TcpDataMessage *data)
+{
+ struct ChannelState *ts = cls;
+ size_t mlen;
+
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop ("# TCP packets received from cadet"),
+ 1,
+ GNUNET_NO);
+ mlen = ntohs (data->header.size) - sizeof (struct GNUNET_EXIT_TcpDataMessage);
+ {
+ char sbuf[INET6_ADDRSTRLEN];
+ char dbuf[INET6_ADDRSTRLEN];
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Received TCP reply from cadet, sending %u bytes from [%s]:%u -> [%s]:%u via TUN\n",
+ (unsigned int) mlen,
+ inet_ntop (ts->af, &ts->destination_ip, sbuf, sizeof (sbuf)),
+ ts->destination_port,
+ inet_ntop (ts->af, &ts->source_ip, dbuf, sizeof (dbuf)),
+ ts->source_port);
+ }
+ switch (ts->af)
{
- case IPPROTO_UDP:
- {
- if (payload_length < sizeof (struct GNUNET_TUN_UdpHeader))
- {
- /* blame kernel? */
- GNUNET_break (0);
- return;
- }
- tcp = NULL; /* make compiler happy */
- icmp = NULL; /* make compiler happy */
- udp = payload;
- if (udp->len < sizeof (struct GNUNET_TUN_UdpHeader))
- {
- GNUNET_break_op (0);
- return;
- }
- source_port = ntohs (udp->source_port);
- destination_port = ntohs (udp->destination_port);
- get_channel_key_from_ips (af,
- IPPROTO_UDP,
- source_ip,
- source_port,
- destination_ip,
- destination_port,
- &key);
- }
- break;
- case IPPROTO_TCP:
+ case AF_INET:
{
- if (payload_length < sizeof (struct GNUNET_TUN_TcpHeader))
- {
- /* blame kernel? */
- GNUNET_break (0);
- return;
- }
- udp = NULL; /* make compiler happy */
- icmp = NULL; /* make compiler happy */
- tcp = payload;
- if (tcp->off * 4 < sizeof (struct GNUNET_TUN_TcpHeader))
+ size_t size = sizeof (struct GNUNET_TUN_IPv4Header)
+ + sizeof (struct GNUNET_TUN_TcpHeader)
+ + sizeof (struct GNUNET_MessageHeader) +
+ sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
+ mlen;
{
- GNUNET_break_op (0);
- return;
+ char buf[size] GNUNET_ALIGN;
+ struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
+ struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
+ struct GNUNET_TUN_IPv4Header *ipv4 = (struct GNUNET_TUN_IPv4Header *) &tun[1];
+ struct GNUNET_TUN_TcpHeader *tcp = (struct GNUNET_TUN_TcpHeader *) &ipv4[1];
+ msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
+ msg->size = htons (size);
+ tun->flags = htons (0);
+ tun->proto = htons (ETH_P_IPV4);
+ GNUNET_TUN_initialize_ipv4_header (ipv4,
+ IPPROTO_TCP,
+ sizeof (struct GNUNET_TUN_TcpHeader) + mlen,
+ &ts->destination_ip.v4,
+ &ts->source_ip.v4);
+ *tcp = data->tcp_header;
+ tcp->source_port = htons (ts->destination_port);
+ tcp->destination_port = htons (ts->source_port);
+ GNUNET_TUN_calculate_tcp4_checksum (ipv4,
+ tcp,
+ &data[1],
+ mlen);
+ GNUNET_memcpy (&tcp[1],
+ &data[1],
+ mlen);
+ (void) GNUNET_HELPER_send (helper_handle,
+ msg,
+ GNUNET_YES,
+ NULL, NULL);
}
- source_port = ntohs (tcp->source_port);
- destination_port = ntohs (tcp->destination_port);
- get_channel_key_from_ips (af,
- IPPROTO_TCP,
- source_ip,
- source_port,
- destination_ip,
- destination_port,
- &key);
}
break;
- case IPPROTO_ICMP:
- case IPPROTO_ICMPV6:
+ case AF_INET6:
{
- if ( (AF_INET == af) ^ (protocol == IPPROTO_ICMP) )
- {
- GNUNET_break (0);
- return;
- }
- if (payload_length < sizeof (struct GNUNET_TUN_IcmpHeader))
+ size_t size = sizeof (struct GNUNET_TUN_IPv6Header)
+ + sizeof (struct GNUNET_TUN_TcpHeader)
+ + sizeof (struct GNUNET_MessageHeader) +
+ sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
+ mlen;
{
- /* blame kernel? */
- GNUNET_break (0);
- return;
+ char buf[size] GNUNET_ALIGN;
+ struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
+ struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
+ struct GNUNET_TUN_IPv6Header *ipv6 = (struct GNUNET_TUN_IPv6Header *) &tun[1];
+ struct GNUNET_TUN_TcpHeader *tcp = (struct GNUNET_TUN_TcpHeader *) &ipv6[1];
+ msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
+ msg->size = htons (size);
+ tun->flags = htons (0);
+ tun->proto = htons (ETH_P_IPV6);
+ GNUNET_TUN_initialize_ipv6_header (ipv6,
+ IPPROTO_TCP,
+ sizeof (struct GNUNET_TUN_TcpHeader) + mlen,
+ &ts->destination_ip.v6,
+ &ts->source_ip.v6);
+ *tcp = data->tcp_header;
+ tcp->source_port = htons (ts->destination_port);
+ tcp->destination_port = htons (ts->source_port);
+ GNUNET_TUN_calculate_tcp6_checksum (ipv6,
+ tcp,
+ &data[1],
+ mlen);
+ GNUNET_memcpy (&tcp[1],
+ &data[1],
+ mlen);
+ (void) GNUNET_HELPER_send (helper_handle,
+ msg,
+ GNUNET_YES,
+ NULL, NULL);
}
- tcp = NULL; /* make compiler happy */
- udp = NULL; /* make compiler happy */
- icmp = payload;
- source_port = 0;
- destination_port = 0;
- get_channel_key_from_ips (af,
- protocol,
- source_ip,
- 0,
- destination_ip,
- 0,
- &key);
}
break;
- default:
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- _("Protocol %u not supported, dropping\n"),
- (unsigned int) protocol);
- return;
}
- alen = 0;
- if (! destination->is_service)
- {
- switch (destination->details.exit_destination.af)
- {
- case AF_INET:
- alen = sizeof (struct in_addr);
- break;
- case AF_INET6:
- alen = sizeof (struct in6_addr);
- break;
- default:
- GNUNET_assert (0);
- }
+ GNUNET_CONTAINER_heap_update_cost (ts->heap_node,
+ GNUNET_TIME_absolute_get ().abs_value_us);
+ GNUNET_CADET_receive_done (ts->channel);
+}
- {
- char sbuf[INET6_ADDRSTRLEN];
- char dbuf[INET6_ADDRSTRLEN];
- char xbuf[INET6_ADDRSTRLEN];
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Routing %s packet from [%s]:%u -> [%s]:%u to destination [%s]:%u\n",
- (protocol == IPPROTO_TCP) ? "TCP" : "UDP",
- inet_ntop (af,
- source_ip,
- sbuf,
- sizeof (sbuf)),
- source_port,
- inet_ntop (af,
- destination_ip,
- dbuf,
- sizeof (dbuf)),
- destination_port,
- inet_ntop (destination->details.exit_destination.af,
- &destination->details.exit_destination.ip,
- xbuf, sizeof (xbuf)),
- destination_port);
- }
- for (dt = destination->dt_head; NULL != dt; dt = dt->next)
- if (dt->destination_port == destination_port)
- break;
- }
- else
- {
- {
- char sbuf[INET6_ADDRSTRLEN];
- char dbuf[INET6_ADDRSTRLEN];
+/**
+ * Create a channel for @a ts to @a target at @a port
+ *
+ * @param ts channel state to create the channel for
+ * @param target peer to connect to
+ * @param port destination port
+ * @return the channel handle
+ */
+static struct GNUNET_CADET_Channel *
+create_channel (struct ChannelState *ts,
+ const struct GNUNET_PeerIdentity *target,
+ const struct GNUNET_HashCode *port)
+{
+ struct GNUNET_MQ_MessageHandler cadet_handlers[] = {
+ GNUNET_MQ_hd_var_size (udp_back,
+ GNUNET_MESSAGE_TYPE_VPN_UDP_REPLY,
+ struct GNUNET_EXIT_UdpReplyMessage,
+ ts),
+ GNUNET_MQ_hd_var_size (tcp_back,
+ GNUNET_MESSAGE_TYPE_VPN_TCP_DATA_TO_VPN,
+ struct GNUNET_EXIT_TcpDataMessage,
+ ts),
+ GNUNET_MQ_hd_var_size (icmp_back,
+ GNUNET_MESSAGE_TYPE_VPN_ICMP_TO_VPN,
+ struct GNUNET_EXIT_IcmpToVPNMessage,
+ ts),
+ GNUNET_MQ_handler_end()
+ };
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Routing %s packet from [%s]:%u -> [%s]:%u to service %s at peer %s\n",
- (protocol == IPPROTO_TCP) ? "TCP" : "UDP",
- inet_ntop (af,
- source_ip,
- sbuf,
- sizeof (sbuf)),
- source_port,
- inet_ntop (af,
- destination_ip,
- dbuf,
- sizeof (dbuf)),
- destination_port,
- GNUNET_h2s (&destination->details.service_destination.service_descriptor),
- GNUNET_i2s (&destination->details.service_destination.target));
- }
- for (dt = destination->dt_head; NULL != dt; dt = dt->next)
- if (dt->destination_port == destination_port)
- break;
- }
- if (NULL == dt)
+ return GNUNET_CADET_channel_creatE (cadet_handle,
+ ts,
+ target,
+ port,
+ GNUNET_CADET_OPTION_DEFAULT,
+ NULL,
+ &channel_cleaner,
+ cadet_handlers);
+}
+
+
+/**
+ * Regex has found a potential exit peer for us; consider using it.
+ *
+ * @param cls the `struct ChannelState`
+ * @param id Peer providing a regex that matches the string.
+ * @param get_path Path of the get request.
+ * @param get_path_length Lenght of @a get_path.
+ * @param put_path Path of the put request.
+ * @param put_path_length Length of the @a put_path.
+ */
+static void
+handle_regex_result (void *cls,
+ const struct GNUNET_PeerIdentity *id,
+ const struct GNUNET_PeerIdentity *get_path,
+ unsigned int get_path_length,
+ const struct GNUNET_PeerIdentity *put_path,
+ unsigned int put_path_length)
+{
+ struct ChannelState *ts = cls;
+ struct GNUNET_HashCode port;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Exit %s found for destination %s!\n",
+ GNUNET_i2s (id),
+ print_channel_destination (&ts->destination));
+ GNUNET_REGEX_search_cancel (ts->search);
+ ts->search = NULL;
+ switch (ts->af)
{
- dt = GNUNET_new (struct DestinationChannel);
- dt->destination = destination;
- GNUNET_CONTAINER_DLL_insert (destination->dt_head,
- destination->dt_tail,
- dt);
- dt->destination_port = destination_port;
+ case AF_INET:
+ /* these must match the strings used in gnunet-daemon-exit */
+ GNUNET_CRYPTO_hash (GNUNET_APPLICATION_PORT_IPV4_GATEWAY,
+ strlen (GNUNET_APPLICATION_PORT_IPV4_GATEWAY),
+ &port);
+ break;
+ case AF_INET6:
+ /* these must match the strings used in gnunet-daemon-exit */
+ GNUNET_CRYPTO_hash (GNUNET_APPLICATION_PORT_IPV6_GATEWAY,
+ strlen (GNUNET_APPLICATION_PORT_IPV6_GATEWAY),
+ &port);
+ break;
+ default:
+ GNUNET_break (0);
+ return;
}
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Creating tunnel to %s for destination %s!\n",
+ GNUNET_i2s (id),
+ print_channel_destination (&ts->destination));
+ ts->channel = create_channel (ts,
+ id,
+ &port);
+}
- /* see if we have an existing channel for this destination */
- ts = GNUNET_CONTAINER_multihashmap_get (channel_map,
- &key);
- if (NULL == ts)
+
+/**
+ * Initialize the given destination entry's cadet channel.
+ *
+ * @param dt destination channel for which we need to setup a channel
+ * @param client_af address family of the address returned to the client
+ * @return channel state of the channel that was created
+ */
+static struct ChannelState *
+create_channel_to_destination (struct DestinationChannel *dt,
+ int client_af)
+{
+ struct ChannelState *ts;
+
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop ("# Cadet channels created"),
+ 1,
+ GNUNET_NO);
+ ts = GNUNET_new (struct ChannelState);
+ ts->af = client_af;
+ ts->destination = *dt->destination;
+ ts->destination.heap_node = NULL; /* copy is NOT in destination heap */
+ ts->destination_port = dt->destination_port;
+ if (dt->destination->is_service)
{
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Creating new channel for key %s\n",
- GNUNET_h2s (&key));
- /* need to either use the existing channel from the destination (if still
- available) or create a fresh one */
- ts = create_channel_to_destination (dt,
- af);
- if (NULL == ts)
- return;
- /* now bind existing "unbound" channel to our IP/port tuple */
- ts->protocol = protocol;
- ts->af = af;
- if (AF_INET == af)
- {
- ts->source_ip.v4 = * (const struct in_addr *) source_ip;
- ts->destination_ip.v4 = * (const struct in_addr *) destination_ip;
- }
- else
+ struct GNUNET_HashCode cadet_port;
+
+ GNUNET_TUN_compute_service_cadet_port (&ts->destination.details.service_destination.service_descriptor,
+ ts->destination_port,
+ &cadet_port);
+ ts->channel = create_channel (ts,
+ &dt->destination->details.service_destination.target,
+ &cadet_port);
+
+ if (NULL == ts->channel)
{
- ts->source_ip.v6 = * (const struct in6_addr *) source_ip;
- ts->destination_ip.v6 = * (const struct in6_addr *) destination_ip;
+ GNUNET_break (0);
+ GNUNET_free (ts);
+ return NULL;
}
- ts->source_port = source_port;
- ts->destination_port = destination_port;
- ts->heap_node = GNUNET_CONTAINER_heap_insert (channel_heap,
- ts,
- GNUNET_TIME_absolute_get ().abs_value_us);
- GNUNET_assert (GNUNET_YES ==
- GNUNET_CONTAINER_multihashmap_put (channel_map,
- &key,
- ts,
- GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
- GNUNET_STATISTICS_update (stats,
- gettext_noop ("# Active channels"),
- 1, GNUNET_NO);
- while (GNUNET_CONTAINER_multihashmap_size (channel_map) > max_channel_mappings)
- expire_channel (ts);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Creating channel to peer %s offering service %s on port %u\n",
+ GNUNET_i2s (&dt->destination->details.service_destination.target),
+ GNUNET_h2s (&ts->destination.details.service_destination.service_descriptor),
+ (unsigned int) ts->destination_port);
}
else
{
- GNUNET_CONTAINER_heap_update_cost (ts->heap_node,
- GNUNET_TIME_absolute_get ().abs_value_us);
- }
- if (NULL == ts->channel)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Packet dropped, channel to %s not yet ready (%s)\n",
- print_channel_destination (&ts->destination),
- (NULL == ts->search)
- ? "EXIT search failed"
- : "EXIT search active");
- GNUNET_STATISTICS_update (stats,
- gettext_noop ("# Packets dropped (channel not yet online)"),
- 1,
- GNUNET_NO);
- return;
- }
+ char *policy;
- /* send via channel */
- switch (protocol)
- {
- case IPPROTO_UDP:
- if (destination->is_service)
+ switch (dt->destination->details.exit_destination.af)
{
- struct GNUNET_EXIT_UdpServiceMessage *usm;
+ case AF_INET:
+ {
+ char address[GNUNET_TUN_IPV4_REGEXLEN];
- mlen = sizeof (struct GNUNET_EXIT_UdpServiceMessage) +
- payload_length - sizeof (struct GNUNET_TUN_UdpHeader);
- if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
- {
- GNUNET_break (0);
- return;
- }
- tnq = GNUNET_malloc (sizeof (struct ChannelMessageQueueEntry) + mlen);
- tnq->len = mlen;
- tnq->msg = &tnq[1];
- usm = (struct GNUNET_EXIT_UdpServiceMessage *) &tnq[1];
- usm->header.size = htons ((uint16_t) mlen);
- usm->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_UDP_TO_SERVICE);
- /* if the source port is below 32000, we assume it has a special
- meaning; if not, we pick a random port (this is a heuristic) */
- usm->source_port = (ntohs (udp->source_port) < 32000) ? udp->source_port : 0;
- usm->destination_port = udp->destination_port;
- GNUNET_memcpy (&usm[1],
- &udp[1],
- payload_length - sizeof (struct GNUNET_TUN_UdpHeader));
+ GNUNET_TUN_ipv4toregexsearch (&dt->destination->details.exit_destination.ip.v4,
+ dt->destination_port,
+ address);
+ GNUNET_asprintf (&policy,
+ "%s%s",
+ GNUNET_APPLICATION_TYPE_EXIT_REGEX_PREFIX,
+ address);
+ break;
}
- else
+ case AF_INET6:
{
- struct GNUNET_EXIT_UdpInternetMessage *uim;
- struct in_addr *ip4dst;
- struct in6_addr *ip6dst;
- void *payload;
+ char address[GNUNET_TUN_IPV6_REGEXLEN];
- mlen = sizeof (struct GNUNET_EXIT_UdpInternetMessage) +
- alen + payload_length - sizeof (struct GNUNET_TUN_UdpHeader);
- if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
- {
- GNUNET_break (0);
- return;
- }
- tnq = GNUNET_malloc (sizeof (struct ChannelMessageQueueEntry) + mlen);
- tnq->len = mlen;
- tnq->msg = &tnq[1];
- uim = (struct GNUNET_EXIT_UdpInternetMessage *) &tnq[1];
- uim->header.size = htons ((uint16_t) mlen);
- uim->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_UDP_TO_INTERNET);
- uim->af = htonl (destination->details.exit_destination.af);
- uim->source_port = (ntohs (udp->source_port) < 32000) ? udp->source_port : 0;
- uim->destination_port = udp->destination_port;
- switch (destination->details.exit_destination.af)
- {
- case AF_INET:
- ip4dst = (struct in_addr *) &uim[1];
- *ip4dst = destination->details.exit_destination.ip.v4;
- payload = &ip4dst[1];
- break;
- case AF_INET6:
- ip6dst = (struct in6_addr *) &uim[1];
- *ip6dst = destination->details.exit_destination.ip.v6;
- payload = &ip6dst[1];
- break;
- default:
- GNUNET_assert (0);
- }
- GNUNET_memcpy (payload,
- &udp[1],
- payload_length - sizeof (struct GNUNET_TUN_UdpHeader));
+ GNUNET_TUN_ipv6toregexsearch (&dt->destination->details.exit_destination.ip.v6,
+ dt->destination_port,
+ address);
+ GNUNET_asprintf (&policy,
+ "%s%s",
+ GNUNET_APPLICATION_TYPE_EXIT_REGEX_PREFIX,
+ address);
+ break;
+ }
+ default:
+ GNUNET_assert (0);
+ break;
}
- break;
- case IPPROTO_TCP:
- if (GNUNET_NO == ts->is_established)
- {
- if (destination->is_service)
- {
- struct GNUNET_EXIT_TcpServiceStartMessage *tsm;
- mlen = sizeof (struct GNUNET_EXIT_TcpServiceStartMessage) +
- payload_length - sizeof (struct GNUNET_TUN_TcpHeader);
- if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
- {
- GNUNET_break (0);
- return;
- }
- tnq = GNUNET_malloc (sizeof (struct ChannelMessageQueueEntry) + mlen);
- tnq->len = mlen;
- tnq->msg = &tnq[1];
- tsm = (struct GNUNET_EXIT_TcpServiceStartMessage *) &tnq[1];
- tsm->header.size = htons ((uint16_t) mlen);
- tsm->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_TCP_TO_SERVICE_START);
- tsm->reserved = htonl (0);
- tsm->tcp_header = *tcp;
- GNUNET_memcpy (&tsm[1],
- &tcp[1],
- payload_length - sizeof (struct GNUNET_TUN_TcpHeader));
- }
- else
- {
- struct GNUNET_EXIT_TcpInternetStartMessage *tim;
- struct in_addr *ip4dst;
- struct in6_addr *ip6dst;
- void *payload;
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Requesting connect by string: %s\n",
+ policy);
+ ts->search = GNUNET_REGEX_search (cfg,
+ policy,
+ &handle_regex_result,
+ ts);
+ GNUNET_free (policy);
+ }
+ return ts;
+}
+
+
+/**
+ * We have too many active channels. Clean up the oldest channel.
+ *
+ * @param except channel that must NOT be cleaned up, even if it is the oldest
+ */
+static void
+expire_channel (struct ChannelState *except)
+{
+ struct ChannelState *ts;
+
+ ts = GNUNET_CONTAINER_heap_peek (channel_heap);
+ GNUNET_assert (NULL != ts);
+ if (except == ts)
+ return; /* can't do this */
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Tearing down expired channel to %s\n",
+ print_channel_destination (&except->destination));
+ free_channel_state (ts);
+}
+
+
+/**
+ * Route a packet via cadet to the given destination.
+ *
+ * @param destination description of the destination
+ * @param af address family on this end (AF_INET or AF_INET6)
+ * @param protocol IPPROTO_TCP or IPPROTO_UDP or IPPROTO_ICMP or IPPROTO_ICMPV6
+ * @param source_ip source IP used by the sender (struct in_addr or struct in6_addr)
+ * @param destination_ip destination IP used by the sender (struct in_addr or struct in6_addr)
+ * @param payload payload of the packet after the IP header
+ * @param payload_length number of bytes in @a payload
+ */
+static void
+route_packet (struct DestinationEntry *destination,
+ int af,
+ uint8_t protocol,
+ const void *source_ip,
+ const void *destination_ip,
+ const void *payload,
+ size_t payload_length)
+{
+ struct GNUNET_HashCode key;
+ struct ChannelState *ts;
+ size_t alen;
+ size_t mlen;
+ struct GNUNET_MQ_Envelope *env;
+ const struct GNUNET_TUN_UdpHeader *udp;
+ const struct GNUNET_TUN_TcpHeader *tcp;
+ const struct GNUNET_TUN_IcmpHeader *icmp;
+ struct DestinationChannel *dt;
+ uint16_t source_port;
+ uint16_t destination_port;
- mlen = sizeof (struct GNUNET_EXIT_TcpInternetStartMessage) +
- alen + payload_length - sizeof (struct GNUNET_TUN_TcpHeader);
- if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
- {
- GNUNET_break (0);
- return;
- }
- tnq = GNUNET_malloc (sizeof (struct ChannelMessageQueueEntry) + mlen);
- tnq->len = mlen;
- tnq->msg = &tnq[1];
- tim = (struct GNUNET_EXIT_TcpInternetStartMessage *) &tnq[1];
- tim->header.size = htons ((uint16_t) mlen);
- tim->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_TCP_TO_INTERNET_START);
- tim->af = htonl (destination->details.exit_destination.af);
- tim->tcp_header = *tcp;
- switch (destination->details.exit_destination.af)
- {
- case AF_INET:
- ip4dst = (struct in_addr *) &tim[1];
- *ip4dst = destination->details.exit_destination.ip.v4;
- payload = &ip4dst[1];
- break;
- case AF_INET6:
- ip6dst = (struct in6_addr *) &tim[1];
- *ip6dst = destination->details.exit_destination.ip.v6;
- payload = &ip6dst[1];
- break;
- default:
- GNUNET_assert (0);
- }
- GNUNET_memcpy (payload,
- &tcp[1],
- payload_length - sizeof (struct GNUNET_TUN_TcpHeader));
- }
- }
- else
+ switch (protocol)
+ {
+ case IPPROTO_UDP:
{
- struct GNUNET_EXIT_TcpDataMessage *tdm;
-
- mlen = sizeof (struct GNUNET_EXIT_TcpDataMessage) +
- payload_length - sizeof (struct GNUNET_TUN_TcpHeader);
- if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
+ if (payload_length < sizeof (struct GNUNET_TUN_UdpHeader))
{
+ /* blame kernel? */
GNUNET_break (0);
return;
}
- tnq = GNUNET_malloc (sizeof (struct ChannelMessageQueueEntry) + mlen);
- tnq->len = mlen;
- tnq->msg = &tnq[1];
- 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_EXIT);
- tdm->reserved = htonl (0);
- tdm->tcp_header = *tcp;
- GNUNET_memcpy (&tdm[1],
- &tcp[1],
- payload_length - sizeof (struct GNUNET_TUN_TcpHeader));
- }
- break;
- case IPPROTO_ICMP:
- case IPPROTO_ICMPV6:
- if (destination->is_service)
- {
- struct GNUNET_EXIT_IcmpServiceMessage *ism;
-
- mlen = sizeof (struct GNUNET_EXIT_IcmpServiceMessage) +
- payload_length - sizeof (struct GNUNET_TUN_IcmpHeader);
- if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
+ tcp = NULL; /* make compiler happy */
+ icmp = NULL; /* make compiler happy */
+ udp = payload;
+ if (udp->len < sizeof (struct GNUNET_TUN_UdpHeader))
{
- GNUNET_break (0);
+ GNUNET_break_op (0);
return;
}
- tnq = GNUNET_malloc (sizeof (struct ChannelMessageQueueEntry) + mlen);
- tnq->msg = &tnq[1];
- ism = (struct GNUNET_EXIT_IcmpServiceMessage *) &tnq[1];
- ism->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_ICMP_TO_SERVICE);
- ism->af = htonl (af); /* need to tell destination ICMP protocol family! */
- ism->icmp_header = *icmp;
- /* ICMP protocol translation will be done by the receiver (as we don't know
- the target AF); however, we still need to possibly discard the payload
- depending on the ICMP type */
- switch (af)
- {
- case AF_INET:
- 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:
- /* throw away ICMP payload, won't be useful for the other side anyway */
- payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
- break;
- default:
- GNUNET_STATISTICS_update (stats,
- gettext_noop ("# ICMPv4 packets dropped (not allowed)"),
- 1, GNUNET_NO);
- return;
- }
- /* end of AF_INET */
- break;
- case AF_INET6:
- 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:
- /* throw away ICMP payload, won't be useful for the other side anyway */
- payload_length = 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 (not allowed)"),
- 1, GNUNET_NO);
- return;
- }
- /* end of AF_INET6 */
- break;
- default:
- GNUNET_assert (0);
- break;
- }
-
- /* update length calculations, as payload_length may have changed */
- mlen = sizeof (struct GNUNET_EXIT_IcmpServiceMessage) +
- alen + payload_length - sizeof (struct GNUNET_TUN_IcmpHeader);
- tnq->len = mlen;
- ism->header.size = htons ((uint16_t) mlen);
- /* finally, copy payload (if there is any left...) */
- GNUNET_memcpy (&ism[1],
- &icmp[1],
- payload_length - sizeof (struct GNUNET_TUN_IcmpHeader));
+ source_port = ntohs (udp->source_port);
+ destination_port = ntohs (udp->destination_port);
+ get_channel_key_from_ips (af,
+ IPPROTO_UDP,
+ source_ip,
+ source_port,
+ destination_ip,
+ destination_port,
+ &key);
}
- else
+ break;
+ case IPPROTO_TCP:
{
- struct GNUNET_EXIT_IcmpInternetMessage *iim;
- struct in_addr *ip4dst;
- struct in6_addr *ip6dst;
- void *payload;
-
- mlen = sizeof (struct GNUNET_EXIT_IcmpInternetMessage) +
- alen + payload_length - sizeof (struct GNUNET_TUN_IcmpHeader);
- if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
+ if (payload_length < sizeof (struct GNUNET_TUN_TcpHeader))
{
+ /* blame kernel? */
GNUNET_break (0);
return;
}
- tnq = GNUNET_malloc (sizeof (struct ChannelMessageQueueEntry) + mlen);
- tnq->msg = &tnq[1];
- iim = (struct GNUNET_EXIT_IcmpInternetMessage *) &tnq[1];
- iim->header.type = htons (GNUNET_MESSAGE_TYPE_VPN_ICMP_TO_INTERNET);
- iim->icmp_header = *icmp;
- /* Perform ICMP protocol-translation (depending on destination AF and source AF)
- and throw away ICMP payload depending on ICMP message type */
- switch (af)
- {
- case AF_INET:
- switch (icmp->type)
- {
- case GNUNET_TUN_ICMPTYPE_ECHO_REPLY:
- if (destination->details.exit_destination.af == AF_INET6)
- iim->icmp_header.type = GNUNET_TUN_ICMPTYPE6_ECHO_REPLY;
- break;
- case GNUNET_TUN_ICMPTYPE_ECHO_REQUEST:
- if (destination->details.exit_destination.af == AF_INET6)
- iim->icmp_header.type = GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST;
- break;
- case GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE:
- if (destination->details.exit_destination.af == AF_INET6)
- iim->icmp_header.type = GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE;
- /* throw away IP-payload, exit will have to make it up anyway */
- payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
- break;
- case GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED:
- if (destination->details.exit_destination.af == AF_INET6)
- iim->icmp_header.type = GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED;
- /* throw away IP-payload, exit will have to make it up anyway */
- payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
- break;
- case GNUNET_TUN_ICMPTYPE_SOURCE_QUENCH:
- if (destination->details.exit_destination.af == AF_INET6)
- {
- GNUNET_STATISTICS_update (stats,
- gettext_noop ("# ICMPv4 packets dropped (impossible PT to v6)"),
- 1, GNUNET_NO);
- GNUNET_free (tnq);
- return;
- }
- /* throw away IP-payload, exit will have to make it up anyway */
- payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
- break;
- default:
- GNUNET_STATISTICS_update (stats,
- gettext_noop ("# ICMPv4 packets dropped (type not allowed)"),
- 1, GNUNET_NO);
- GNUNET_free (tnq);
- return;
- }
- /* end of AF_INET */
- break;
- case AF_INET6:
- switch (icmp->type)
- {
- case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE:
- if (destination->details.exit_destination.af == AF_INET6)
- iim->icmp_header.type = GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE;
- /* throw away IP-payload, exit will have to make it up anyway */
- payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
- break;
- case GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED:
- if (destination->details.exit_destination.af == AF_INET)
- iim->icmp_header.type = GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED;
- /* throw away IP-payload, exit will have to make it up anyway */
- payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
- break;
- case GNUNET_TUN_ICMPTYPE6_PACKET_TOO_BIG:
- if (destination->details.exit_destination.af == AF_INET)
- {
- GNUNET_STATISTICS_update (stats,
- gettext_noop ("# ICMPv6 packets dropped (impossible PT to v4)"),
- 1, GNUNET_NO);
- GNUNET_free (tnq);
- return;
- }
- /* throw away IP-payload, exit will have to make it up anyway */
- payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
- break;
- case GNUNET_TUN_ICMPTYPE6_PARAMETER_PROBLEM:
- if (destination->details.exit_destination.af == AF_INET)
- {
- GNUNET_STATISTICS_update (stats,
- gettext_noop ("# ICMPv6 packets dropped (impossible PT to v4)"),
- 1, GNUNET_NO);
- GNUNET_free (tnq);
- return;
- }
- /* throw away IP-payload, exit will have to make it up anyway */
- payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
- break;
- case GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST:
- if (destination->details.exit_destination.af == AF_INET)
- iim->icmp_header.type = GNUNET_TUN_ICMPTYPE_ECHO_REQUEST;
- break;
- case GNUNET_TUN_ICMPTYPE6_ECHO_REPLY:
- if (destination->details.exit_destination.af == AF_INET)
- iim->icmp_header.type = GNUNET_TUN_ICMPTYPE_ECHO_REPLY;
- break;
- default:
- GNUNET_STATISTICS_update (stats,
- gettext_noop ("# ICMPv6 packets dropped (type not allowed)"),
- 1, GNUNET_NO);
- GNUNET_free (tnq);
- return;
- }
- /* end of AF_INET6 */
- break;
- default:
- GNUNET_assert (0);
+ udp = NULL; /* make compiler happy */
+ icmp = NULL; /* make compiler happy */
+ tcp = payload;
+ if (tcp->off * 4 < sizeof (struct GNUNET_TUN_TcpHeader))
+ {
+ GNUNET_break_op (0);
+ return;
}
- /* update length calculations, as payload_length may have changed */
- mlen = sizeof (struct GNUNET_EXIT_IcmpInternetMessage) +
- alen + payload_length - sizeof (struct GNUNET_TUN_IcmpHeader);
- tnq->len = mlen;
- iim->header.size = htons ((uint16_t) mlen);
-
- /* need to tell destination ICMP protocol family! */
- iim->af = htonl (destination->details.exit_destination.af);
- switch (destination->details.exit_destination.af)
+ source_port = ntohs (tcp->source_port);
+ destination_port = ntohs (tcp->destination_port);
+ get_channel_key_from_ips (af,
+ IPPROTO_TCP,
+ source_ip,
+ source_port,
+ destination_ip,
+ destination_port,
+ &key);
+ }
+ break;
+ case IPPROTO_ICMP:
+ case IPPROTO_ICMPV6:
+ {
+ if ( (AF_INET == af) ^ (protocol == IPPROTO_ICMP) )
{
- case AF_INET:
- ip4dst = (struct in_addr *) &iim[1];
- *ip4dst = destination->details.exit_destination.ip.v4;
- payload = &ip4dst[1];
- break;
- case AF_INET6:
- ip6dst = (struct in6_addr *) &iim[1];
- *ip6dst = destination->details.exit_destination.ip.v6;
- payload = &ip6dst[1];
- break;
- default:
- GNUNET_assert (0);
+ GNUNET_break (0);
+ return;
}
- GNUNET_memcpy (payload,
- &icmp[1],
- payload_length - sizeof (struct GNUNET_TUN_IcmpHeader));
+ if (payload_length < sizeof (struct GNUNET_TUN_IcmpHeader))
+ {
+ /* blame kernel? */
+ GNUNET_break (0);
+ return;
+ }
+ tcp = NULL; /* make compiler happy */
+ udp = NULL; /* make compiler happy */
+ icmp = payload;
+ source_port = 0;
+ destination_port = 0;
+ get_channel_key_from_ips (af,
+ protocol,
+ source_ip,
+ 0,
+ destination_ip,
+ 0,
+ &key);
}
break;
default:
- /* not supported above, how can we get here !? */
- GNUNET_assert (0);
- break;
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ _("Protocol %u not supported, dropping\n"),
+ (unsigned int) protocol);
+ return;
}
- ts->is_established = GNUNET_YES;
- send_to_channel (tnq, ts);
-}
+ alen = 0;
+ if (! destination->is_service)
+ {
+ switch (destination->details.exit_destination.af)
+ {
+ case AF_INET:
+ alen = sizeof (struct in_addr);
+ break;
+ case AF_INET6:
+ alen = sizeof (struct in6_addr);
+ break;
+ default:
+ GNUNET_assert (0);
+ }
+ {
+ char sbuf[INET6_ADDRSTRLEN];
+ char dbuf[INET6_ADDRSTRLEN];
+ char xbuf[INET6_ADDRSTRLEN];
-/**
- * Receive packets from the helper-process (someone send to the local
- * virtual channel interface). Find the destination mapping, and if it
- * exists, identify the correct CADET channel (or possibly create it)
- * and forward the packet.
- *
- * @param cls closure, NULL
- * @param client NULL
- * @param message message we got from the client (VPN channel interface)
- */
-static int
-message_token (void *cls,
- void *client,
- const struct GNUNET_MessageHeader *message)
-{
- const struct GNUNET_TUN_Layer2PacketHeader *tun;
- size_t mlen;
- struct GNUNET_HashCode key;
- struct DestinationEntry *de;
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Routing %s packet from [%s]:%u -> [%s]:%u to destination [%s]:%u\n",
+ (protocol == IPPROTO_TCP) ? "TCP" : "UDP",
+ inet_ntop (af,
+ source_ip,
+ sbuf,
+ sizeof (sbuf)),
+ source_port,
+ inet_ntop (af,
+ destination_ip,
+ dbuf,
+ sizeof (dbuf)),
+ destination_port,
+ inet_ntop (destination->details.exit_destination.af,
+ &destination->details.exit_destination.ip,
+ xbuf, sizeof (xbuf)),
+ destination_port);
+ }
+ for (dt = destination->dt_head; NULL != dt; dt = dt->next)
+ if (dt->destination_port == destination_port)
+ break;
+ }
+ else
+ {
+ {
+ char sbuf[INET6_ADDRSTRLEN];
+ char dbuf[INET6_ADDRSTRLEN];
- GNUNET_STATISTICS_update (stats,
- gettext_noop ("# Packets received from TUN interface"),
- 1, GNUNET_NO);
- mlen = ntohs (message->size);
- if ( (ntohs (message->type) != GNUNET_MESSAGE_TYPE_VPN_HELPER) ||
- (mlen < sizeof (struct GNUNET_MessageHeader) + sizeof (struct GNUNET_TUN_Layer2PacketHeader)) )
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Routing %s packet from [%s]:%u -> [%s]:%u to service %s at peer %s\n",
+ (protocol == IPPROTO_TCP) ? "TCP" : "UDP",
+ inet_ntop (af,
+ source_ip,
+ sbuf,
+ sizeof (sbuf)),
+ source_port,
+ inet_ntop (af,
+ destination_ip,
+ dbuf,
+ sizeof (dbuf)),
+ destination_port,
+ GNUNET_h2s (&destination->details.service_destination.service_descriptor),
+ GNUNET_i2s (&destination->details.service_destination.target));
+ }
+ for (dt = destination->dt_head; NULL != dt; dt = dt->next)
+ if (dt->destination_port == destination_port)
+ break;
+ }
+ if (NULL == dt)
{
- GNUNET_break (0);
- return GNUNET_OK;
+ dt = GNUNET_new (struct DestinationChannel);
+ dt->destination = destination;
+ GNUNET_CONTAINER_DLL_insert (destination->dt_head,
+ destination->dt_tail,
+ dt);
+ dt->destination_port = destination_port;
}
- tun = (const struct GNUNET_TUN_Layer2PacketHeader *) &message[1];
- mlen -= (sizeof (struct GNUNET_MessageHeader) + sizeof (struct GNUNET_TUN_Layer2PacketHeader));
- switch (ntohs (tun->proto))
+
+ /* see if we have an existing channel for this destination */
+ ts = GNUNET_CONTAINER_multihashmap_get (channel_map,
+ &key);
+ if (NULL == ts)
{
- case ETH_P_IPV6:
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Creating new channel for key %s\n",
+ GNUNET_h2s (&key));
+ /* need to either use the existing channel from the destination (if still
+ available) or create a fresh one */
+ ts = create_channel_to_destination (dt,
+ af);
+ if (NULL == ts)
+ return;
+ /* now bind existing "unbound" channel to our IP/port tuple */
+ ts->protocol = protocol;
+ ts->af = af;
+ if (AF_INET == af)
+ {
+ ts->source_ip.v4 = * (const struct in_addr *) source_ip;
+ ts->destination_ip.v4 = * (const struct in_addr *) destination_ip;
+ }
+ else
+ {
+ ts->source_ip.v6 = * (const struct in6_addr *) source_ip;
+ ts->destination_ip.v6 = * (const struct in6_addr *) destination_ip;
+ }
+ ts->source_port = source_port;
+ ts->destination_port = destination_port;
+ ts->heap_node = GNUNET_CONTAINER_heap_insert (channel_heap,
+ ts,
+ GNUNET_TIME_absolute_get ().abs_value_us);
+ GNUNET_assert (GNUNET_YES ==
+ GNUNET_CONTAINER_multihashmap_put (channel_map,
+ &key,
+ ts,
+ GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop ("# Active channels"),
+ 1, GNUNET_NO);
+ while (GNUNET_CONTAINER_multihashmap_size (channel_map) > max_channel_mappings)
+ expire_channel (ts);
+ }
+ else
+ {
+ GNUNET_CONTAINER_heap_update_cost (ts->heap_node,
+ GNUNET_TIME_absolute_get ().abs_value_us);
+ }
+ if (NULL == ts->channel)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Packet dropped, channel to %s not yet ready (%s)\n",
+ print_channel_destination (&ts->destination),
+ (NULL == ts->search)
+ ? "EXIT search failed"
+ : "EXIT search active");
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop ("# Packets dropped (channel not yet online)"),
+ 1,
+ GNUNET_NO);
+ return;
+ }
+
+ /* send via channel */
+ switch (protocol)
+ {
+ case IPPROTO_UDP:
+ if (destination->is_service)
+ {
+ struct GNUNET_EXIT_UdpServiceMessage *usm;
+
+ mlen = sizeof (struct GNUNET_EXIT_UdpServiceMessage) +
+ payload_length - sizeof (struct GNUNET_TUN_UdpHeader);
+ if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
+ {
+ GNUNET_break (0);
+ return;
+ }
+ env = GNUNET_MQ_msg_extra (usm,
+ payload_length - sizeof (struct GNUNET_TUN_UdpHeader),
+ GNUNET_MESSAGE_TYPE_VPN_UDP_TO_SERVICE);
+ /* if the source port is below 32000, we assume it has a special
+ meaning; if not, we pick a random port (this is a heuristic) */
+ usm->source_port = (ntohs (udp->source_port) < 32000) ? udp->source_port : 0;
+ usm->destination_port = udp->destination_port;
+ GNUNET_memcpy (&usm[1],
+ &udp[1],
+ payload_length - sizeof (struct GNUNET_TUN_UdpHeader));
+ }
+ else
{
- const struct GNUNET_TUN_IPv6Header *pkt6;
+ struct GNUNET_EXIT_UdpInternetMessage *uim;
+ struct in_addr *ip4dst;
+ struct in6_addr *ip6dst;
+ void *payload;
- if (mlen < sizeof (struct GNUNET_TUN_IPv6Header))
+ mlen = sizeof (struct GNUNET_EXIT_UdpInternetMessage) +
+ alen + payload_length - sizeof (struct GNUNET_TUN_UdpHeader);
+ if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
{
- /* blame kernel */
GNUNET_break (0);
- return GNUNET_OK;
+ return;
}
- pkt6 = (const struct GNUNET_TUN_IPv6Header *) &tun[1];
- get_destination_key_from_ip (AF_INET6,
- &pkt6->destination_address,
- &key);
- de = GNUNET_CONTAINER_multihashmap_get (destination_map, &key);
- if (NULL == de)
+ env = GNUNET_MQ_msg_extra (uim,
+ payload_length + alen - sizeof (struct GNUNET_TUN_UdpHeader),
+ GNUNET_MESSAGE_TYPE_VPN_UDP_TO_INTERNET);
+ uim->af = htonl (destination->details.exit_destination.af);
+ uim->source_port = (ntohs (udp->source_port) < 32000) ? udp->source_port : 0;
+ uim->destination_port = udp->destination_port;
+ switch (destination->details.exit_destination.af)
{
- char buf[INET6_ADDRSTRLEN];
-
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- _("Packet received for unmapped destination `%s' (dropping it)\n"),
- inet_ntop (AF_INET6,
- &pkt6->destination_address,
- buf,
- sizeof (buf)));
- return GNUNET_OK;
+ case AF_INET:
+ ip4dst = (struct in_addr *) &uim[1];
+ *ip4dst = destination->details.exit_destination.ip.v4;
+ payload = &ip4dst[1];
+ break;
+ case AF_INET6:
+ ip6dst = (struct in6_addr *) &uim[1];
+ *ip6dst = destination->details.exit_destination.ip.v6;
+ payload = &ip6dst[1];
+ break;
+ default:
+ GNUNET_assert (0);
}
- route_packet (de,
- AF_INET6,
- pkt6->next_header,
- &pkt6->source_address,
- &pkt6->destination_address,
- &pkt6[1],
- mlen - sizeof (struct GNUNET_TUN_IPv6Header));
+ GNUNET_memcpy (payload,
+ &udp[1],
+ payload_length - sizeof (struct GNUNET_TUN_UdpHeader));
}
break;
- case ETH_P_IPV4:
+ case IPPROTO_TCP:
+ if (GNUNET_NO == ts->is_established)
{
- struct GNUNET_TUN_IPv4Header *pkt4;
-
- if (mlen < sizeof (struct GNUNET_TUN_IPv4Header))
- {
- /* blame kernel */
- GNUNET_break (0);
- return GNUNET_OK;
- }
- pkt4 = (struct GNUNET_TUN_IPv4Header *) &tun[1];
- get_destination_key_from_ip (AF_INET,
- &pkt4->destination_address,
- &key);
- de = GNUNET_CONTAINER_multihashmap_get (destination_map, &key);
- if (NULL == de)
+ if (destination->is_service)
{
- char buf[INET_ADDRSTRLEN];
+ struct GNUNET_EXIT_TcpServiceStartMessage *tsm;
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- _("Packet received for unmapped destination `%s' (dropping it)\n"),
- inet_ntop (AF_INET,
- &pkt4->destination_address,
- buf,
- sizeof (buf)));
- return GNUNET_OK;
+ mlen = sizeof (struct GNUNET_EXIT_TcpServiceStartMessage) +
+ payload_length - sizeof (struct GNUNET_TUN_TcpHeader);
+ if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
+ {
+ GNUNET_break (0);
+ return;
+ }
+ env = GNUNET_MQ_msg_extra (tsm,
+ payload_length - sizeof (struct GNUNET_TUN_TcpHeader),
+ GNUNET_MESSAGE_TYPE_VPN_TCP_TO_SERVICE_START);
+ tsm->reserved = htonl (0);
+ tsm->tcp_header = *tcp;
+ GNUNET_memcpy (&tsm[1],
+ &tcp[1],
+ payload_length - sizeof (struct GNUNET_TUN_TcpHeader));
}
- if (pkt4->header_length * 4 != sizeof (struct GNUNET_TUN_IPv4Header))
+ else
{
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- _("Received IPv4 packet with options (dropping it)\n"));
- return GNUNET_OK;
- }
- route_packet (de,
- AF_INET,
- pkt4->protocol,
- &pkt4->source_address,
- &pkt4->destination_address,
- &pkt4[1],
- mlen - sizeof (struct GNUNET_TUN_IPv4Header));
- }
- break;
- default:
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- _("Received packet of unknown protocol %d from TUN (dropping it)\n"),
- (unsigned int) ntohs (tun->proto));
- break;
- }
- return GNUNET_OK;
-}
-
-
-/**
- * Synthesize a plausible ICMP payload for an ICMP error
- * response on the given channel.
- *
- * @param ts channel information
- * @param ipp IPv4 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 *ts,
- struct GNUNET_TUN_IPv4Header *ipp,
- struct GNUNET_TUN_UdpHeader *udp)
-{
- GNUNET_TUN_initialize_ipv4_header (ipp,
- ts->protocol,
- sizeof (struct GNUNET_TUN_TcpHeader),
- &ts->source_ip.v4,
- &ts->destination_ip.v4);
- udp->source_port = htons (ts->source_port);
- udp->destination_port = htons (ts->destination_port);
- udp->len = htons (0);
- udp->crc = htons (0);
-}
-
-
-/**
- * Synthesize a plausible ICMP payload for an ICMP error
- * response on the given channel.
- *
- * @param ts 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_icmpv6_payload (struct ChannelState *ts,
- struct GNUNET_TUN_IPv6Header *ipp,
- struct GNUNET_TUN_UdpHeader *udp)
-{
- GNUNET_TUN_initialize_ipv6_header (ipp,
- ts->protocol,
- sizeof (struct GNUNET_TUN_TcpHeader),
- &ts->source_ip.v6,
- &ts->destination_ip.v6);
- udp->source_port = htons (ts->source_port);
- udp->destination_port = htons (ts->destination_port);
- udp->len = htons (0);
- udp->crc = htons (0);
-}
-
-
-/**
- * We got an ICMP packet back from the CADET channel. Pass it on to the
- * local virtual interface via 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)
- */
-static int
-receive_icmp_back (void *cls,
- struct GNUNET_CADET_Channel *channel,
- void **channel_ctx,
- const struct GNUNET_MessageHeader *message)
-{
- struct ChannelState *ts = *channel_ctx;
- const struct GNUNET_EXIT_IcmpToVPNMessage *i2v;
- size_t mlen;
-
- GNUNET_STATISTICS_update (stats,
- gettext_noop ("# ICMP packets received from cadet"),
- 1, GNUNET_NO);
- mlen = ntohs (message->size);
- if (mlen < sizeof (struct GNUNET_EXIT_IcmpToVPNMessage))
- {
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
- if (NULL == ts->heap_node)
- {
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
- if (AF_UNSPEC == ts->af)
- {
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
- i2v = (const struct GNUNET_EXIT_IcmpToVPNMessage *) message;
- mlen -= sizeof (struct GNUNET_EXIT_IcmpToVPNMessage);
- {
- char sbuf[INET6_ADDRSTRLEN];
- char dbuf[INET6_ADDRSTRLEN];
+ struct GNUNET_EXIT_TcpInternetStartMessage *tim;
+ struct in_addr *ip4dst;
+ struct in6_addr *ip6dst;
+ void *payload;
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Received ICMP packet from cadet, sending %u bytes from %s -> %s via TUN\n",
- (unsigned int) mlen,
- inet_ntop (ts->af, &ts->destination_ip, sbuf, sizeof (sbuf)),
- inet_ntop (ts->af, &ts->source_ip, dbuf, sizeof (dbuf)));
- }
- switch (ts->af)
- {
- case AF_INET:
- {
- size_t size = sizeof (struct GNUNET_TUN_IPv4Header)
- + sizeof (struct GNUNET_TUN_IcmpHeader)
- + sizeof (struct GNUNET_MessageHeader) +
- sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
- mlen;
- {
- /* reserve some extra space in case we have an ICMP type here where
- we will need to make up the payload ourselves */
- char buf[size + sizeof (struct GNUNET_TUN_IPv4Header) + 8] GNUNET_ALIGN;
- struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
- struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
- struct GNUNET_TUN_IPv4Header *ipv4 = (struct GNUNET_TUN_IPv4Header *) &tun[1];
- struct GNUNET_TUN_IcmpHeader *icmp = (struct GNUNET_TUN_IcmpHeader *) &ipv4[1];
- msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
- tun->flags = htons (0);
- tun->proto = htons (ETH_P_IPV4);
- GNUNET_TUN_initialize_ipv4_header (ipv4,
- IPPROTO_ICMP,
- sizeof (struct GNUNET_TUN_IcmpHeader) + mlen,
- &ts->destination_ip.v4,
- &ts->source_ip.v4);
- *icmp = i2v->icmp_header;
- GNUNET_memcpy (&icmp[1],
- &i2v[1],
- mlen);
- /* For some ICMP types, we need to adjust (make up) the payload here.
- Also, depending on the AF used on the other side, we have to
- do ICMP PT (translate ICMP types) */
- switch (ntohl (i2v->af))
+ mlen = sizeof (struct GNUNET_EXIT_TcpInternetStartMessage) +
+ alen + payload_length - sizeof (struct GNUNET_TUN_TcpHeader);
+ if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
+ {
+ GNUNET_break (0);
+ return;
+ }
+ env = GNUNET_MQ_msg_extra (tim,
+ payload_length + alen - sizeof (struct GNUNET_TUN_TcpHeader),
+ GNUNET_MESSAGE_TYPE_VPN_TCP_TO_INTERNET_START);
+ tim->af = htonl (destination->details.exit_destination.af);
+ tim->tcp_header = *tcp;
+ switch (destination->details.exit_destination.af)
{
case AF_INET:
- 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:
- {
- struct GNUNET_TUN_IPv4Header *ipp = (struct GNUNET_TUN_IPv4Header *) &icmp[1];
- struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
-
- if (mlen != 0)
- {
- /* sender did not strip ICMP payload? */
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
- size += sizeof (struct GNUNET_TUN_IPv4Header) + 8;
- GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
- make_up_icmpv4_payload (ts, ipp, udp);
- }
- break;
- default:
- GNUNET_break_op (0);
- GNUNET_STATISTICS_update (stats,
- gettext_noop ("# ICMPv4 packets dropped (type not allowed)"),
- 1, GNUNET_NO);
- return GNUNET_SYSERR;
- }
- /* end AF_INET */
+ ip4dst = (struct in_addr *) &tim[1];
+ *ip4dst = destination->details.exit_destination.ip.v4;
+ payload = &ip4dst[1];
break;
case AF_INET6:
- /* ICMP PT 6-to-4 and possibly making up payloads */
- switch (icmp->type)
- {
- case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE:
- icmp->type = GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE;
- {
- struct GNUNET_TUN_IPv4Header *ipp = (struct GNUNET_TUN_IPv4Header *) &icmp[1];
- struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
-
- if (mlen != 0)
- {
- /* sender did not strip ICMP payload? */
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
- size += sizeof (struct GNUNET_TUN_IPv4Header) + 8;
- GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
- make_up_icmpv4_payload (ts, ipp, udp);
- }
- break;
- case GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED:
- icmp->type = GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED;
- {
- struct GNUNET_TUN_IPv4Header *ipp = (struct GNUNET_TUN_IPv4Header *) &icmp[1];
- struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
-
- if (mlen != 0)
- {
- /* sender did not strip ICMP payload? */
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
- size += sizeof (struct GNUNET_TUN_IPv4Header) + 8;
- GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
- make_up_icmpv4_payload (ts, ipp, udp);
- }
- break;
- case GNUNET_TUN_ICMPTYPE6_PACKET_TOO_BIG:
- case GNUNET_TUN_ICMPTYPE6_PARAMETER_PROBLEM:
- GNUNET_STATISTICS_update (stats,
- gettext_noop ("# ICMPv6 packets dropped (impossible PT to v4)"),
- 1, GNUNET_NO);
- return GNUNET_OK;
- case GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST:
- icmp->type = GNUNET_TUN_ICMPTYPE_ECHO_REQUEST;
- break;
- case GNUNET_TUN_ICMPTYPE6_ECHO_REPLY:
- icmp->type = GNUNET_TUN_ICMPTYPE_ECHO_REPLY;
- break;
- default:
- GNUNET_break_op (0);
- GNUNET_STATISTICS_update (stats,
- gettext_noop ("# ICMPv6 packets dropped (type not allowed)"),
- 1, GNUNET_NO);
- return GNUNET_SYSERR;
- }
- /* end AF_INET6 */
+ ip6dst = (struct in6_addr *) &tim[1];
+ *ip6dst = destination->details.exit_destination.ip.v6;
+ payload = &ip6dst[1];
break;
default:
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
+ GNUNET_assert (0);
}
- msg->size = htons (size);
- GNUNET_TUN_calculate_icmp_checksum (icmp,
- &i2v[1],
- mlen);
- (void) GNUNET_HELPER_send (helper_handle,
- msg,
- GNUNET_YES,
- NULL, NULL);
+ GNUNET_memcpy (payload,
+ &tcp[1],
+ payload_length - sizeof (struct GNUNET_TUN_TcpHeader));
}
}
- break;
- case AF_INET6:
+ else
{
- size_t size = sizeof (struct GNUNET_TUN_IPv6Header)
- + sizeof (struct GNUNET_TUN_IcmpHeader)
- + sizeof (struct GNUNET_MessageHeader) +
- sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
- mlen;
+ struct GNUNET_EXIT_TcpDataMessage *tdm;
+
+ mlen = sizeof (struct GNUNET_EXIT_TcpDataMessage) +
+ payload_length - sizeof (struct GNUNET_TUN_TcpHeader);
+ if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
{
- char buf[size + sizeof (struct GNUNET_TUN_IPv6Header) + 8] GNUNET_ALIGN;
- struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
- struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
- struct GNUNET_TUN_IPv6Header *ipv6 = (struct GNUNET_TUN_IPv6Header *) &tun[1];
- struct GNUNET_TUN_IcmpHeader *icmp = (struct GNUNET_TUN_IcmpHeader *) &ipv6[1];
- msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
- tun->flags = htons (0);
- tun->proto = htons (ETH_P_IPV6);
- GNUNET_TUN_initialize_ipv6_header (ipv6,
- IPPROTO_ICMPV6,
- sizeof (struct GNUNET_TUN_IcmpHeader) + mlen,
- &ts->destination_ip.v6,
- &ts->source_ip.v6);
- *icmp = i2v->icmp_header;
- GNUNET_memcpy (&icmp[1],
- &i2v[1],
- mlen);
+ GNUNET_break (0);
+ return;
+ }
+ env = GNUNET_MQ_msg_extra (tdm,
+ payload_length - sizeof (struct GNUNET_TUN_TcpHeader),
+ GNUNET_MESSAGE_TYPE_VPN_TCP_DATA_TO_EXIT);
+ tdm->reserved = htonl (0);
+ tdm->tcp_header = *tcp;
+ GNUNET_memcpy (&tdm[1],
+ &tcp[1],
+ payload_length - sizeof (struct GNUNET_TUN_TcpHeader));
+ }
+ break;
+ case IPPROTO_ICMP:
+ case IPPROTO_ICMPV6:
+ if (destination->is_service)
+ {
+ struct GNUNET_EXIT_IcmpServiceMessage *ism;
- /* For some ICMP types, we need to adjust (make up) the payload here.
- Also, depending on the AF used on the other side, we have to
- do ICMP PT (translate ICMP types) */
- switch (ntohl (i2v->af))
+ /* ICMP protocol translation will be done by the receiver (as we don't know
+ the target AF); however, we still need to possibly discard the payload
+ depending on the ICMP type */
+ switch (af)
+ {
+ case AF_INET:
+ switch (icmp->type)
{
- case AF_INET:
- /* ICMP PT 4-to-6 and possibly making up payloads */
- switch (icmp->type)
- {
- case GNUNET_TUN_ICMPTYPE_ECHO_REPLY:
- icmp->type = GNUNET_TUN_ICMPTYPE6_ECHO_REPLY;
- break;
- case GNUNET_TUN_ICMPTYPE_ECHO_REQUEST:
- icmp->type = GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST;
- break;
- case GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE:
- icmp->type = GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE;
- {
- struct GNUNET_TUN_IPv6Header *ipp = (struct GNUNET_TUN_IPv6Header *) &icmp[1];
- struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
+ 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:
+ /* throw away ICMP payload, won't be useful for the other side anyway */
+ payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
+ break;
+ default:
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop ("# ICMPv4 packets dropped (not allowed)"),
+ 1, GNUNET_NO);
+ return;
+ }
+ /* end of AF_INET */
+ break;
+ case AF_INET6:
+ 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:
+ /* throw away ICMP payload, won't be useful for the other side anyway */
+ payload_length = 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 (not allowed)"),
+ 1, GNUNET_NO);
+ return;
+ }
+ /* end of AF_INET6 */
+ break;
+ default:
+ GNUNET_assert (0);
+ break;
+ }
- if (mlen != 0)
- {
- /* sender did not strip ICMP payload? */
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
- size += sizeof (struct GNUNET_TUN_IPv6Header) + 8;
- GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
- make_up_icmpv6_payload (ts, ipp, udp);
- }
- break;
- case GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED:
- icmp->type = GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED;
+ /* update length calculations, as payload_length may have changed */
+ mlen = sizeof (struct GNUNET_EXIT_IcmpServiceMessage) +
+ alen + payload_length - sizeof (struct GNUNET_TUN_IcmpHeader);
+ if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
+ {
+ GNUNET_break (0);
+ return;
+ }
+
+ env = GNUNET_MQ_msg_extra (ism,
+ payload_length - sizeof (struct GNUNET_TUN_IcmpHeader),
+ GNUNET_MESSAGE_TYPE_VPN_ICMP_TO_SERVICE);
+ ism->af = htonl (af); /* need to tell destination ICMP protocol family! */
+ ism->icmp_header = *icmp;
+ GNUNET_memcpy (&ism[1],
+ &icmp[1],
+ payload_length - sizeof (struct GNUNET_TUN_IcmpHeader));
+ }
+ else
+ {
+ struct GNUNET_EXIT_IcmpInternetMessage *iim;
+ struct in_addr *ip4dst;
+ struct in6_addr *ip6dst;
+ void *payload;
+ uint8_t new_type;
+
+ /* Perform ICMP protocol-translation (depending on destination AF and source AF)
+ and throw away ICMP payload depending on ICMP message type */
+ switch (af)
+ {
+ case AF_INET:
+ switch (icmp->type)
+ {
+ case GNUNET_TUN_ICMPTYPE_ECHO_REPLY:
+ if (destination->details.exit_destination.af == AF_INET6)
+ new_type = GNUNET_TUN_ICMPTYPE6_ECHO_REPLY;
+ break;
+ case GNUNET_TUN_ICMPTYPE_ECHO_REQUEST:
+ if (destination->details.exit_destination.af == AF_INET6)
+ new_type = GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST;
+ break;
+ case GNUNET_TUN_ICMPTYPE_DESTINATION_UNREACHABLE:
+ if (destination->details.exit_destination.af == AF_INET6)
+ new_type = GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE;
+ /* throw away IP-payload, exit will have to make it up anyway */
+ payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
+ break;
+ case GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED:
+ if (destination->details.exit_destination.af == AF_INET6)
+ new_type = GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED;
+ /* throw away IP-payload, exit will have to make it up anyway */
+ payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
+ break;
+ case GNUNET_TUN_ICMPTYPE_SOURCE_QUENCH:
+ if (destination->details.exit_destination.af == AF_INET6)
{
- struct GNUNET_TUN_IPv6Header *ipp = (struct GNUNET_TUN_IPv6Header *) &icmp[1];
- struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
-
- if (mlen != 0)
- {
- /* sender did not strip ICMP payload? */
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
- size += sizeof (struct GNUNET_TUN_IPv6Header) + 8;
- GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
- make_up_icmpv6_payload (ts, ipp, udp);
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop ("# ICMPv4 packets dropped (impossible PT to v6)"),
+ 1, GNUNET_NO);
+ return;
}
- break;
- case GNUNET_TUN_ICMPTYPE_SOURCE_QUENCH:
- GNUNET_STATISTICS_update (stats,
- gettext_noop ("# ICMPv4 packets dropped (impossible PT to v6)"),
- 1, GNUNET_NO);
- return GNUNET_OK;
- default:
- GNUNET_break_op (0);
- GNUNET_STATISTICS_update (stats,
- gettext_noop ("# ICMPv4 packets dropped (type not allowed)"),
- 1, GNUNET_NO);
- return GNUNET_SYSERR;
- }
- /* end AF_INET */
+ /* throw away IP-payload, exit will have to make it up anyway */
+ payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
break;
- case AF_INET6:
- switch (icmp->type)
+ default:
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop ("# ICMPv4 packets dropped (type not allowed)"),
+ 1, GNUNET_NO);
+ return;
+ }
+ /* end of AF_INET */
+ break;
+ case AF_INET6:
+ switch (icmp->type)
{
case GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE:
+ if (destination->details.exit_destination.af == AF_INET6)
+ new_type = GNUNET_TUN_ICMPTYPE6_DESTINATION_UNREACHABLE;
+ /* throw away IP-payload, exit will have to make it up anyway */
+ payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
+ break;
case GNUNET_TUN_ICMPTYPE6_TIME_EXCEEDED:
+ if (destination->details.exit_destination.af == AF_INET)
+ new_type = GNUNET_TUN_ICMPTYPE_TIME_EXCEEDED;
+ /* throw away IP-payload, exit will have to make it up anyway */
+ payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
+ break;
case GNUNET_TUN_ICMPTYPE6_PACKET_TOO_BIG:
+ if (destination->details.exit_destination.af == AF_INET)
+ {
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop ("# ICMPv6 packets dropped (impossible PT to v4)"),
+ 1, GNUNET_NO);
+ return;
+ }
+ /* throw away IP-payload, exit will have to make it up anyway */
+ payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
+ break;
case GNUNET_TUN_ICMPTYPE6_PARAMETER_PROBLEM:
+ if (destination->details.exit_destination.af == AF_INET)
{
- struct GNUNET_TUN_IPv6Header *ipp = (struct GNUNET_TUN_IPv6Header *) &icmp[1];
- struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipp[1];
-
- if (mlen != 0)
- {
- /* sender did not strip ICMP payload? */
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
- size += sizeof (struct GNUNET_TUN_IPv6Header) + 8;
- GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
- make_up_icmpv6_payload (ts, ipp, udp);
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop ("# ICMPv6 packets dropped (impossible PT to v4)"),
+ 1, GNUNET_NO);
+ return;
}
+ /* throw away IP-payload, exit will have to make it up anyway */
+ payload_length = sizeof (struct GNUNET_TUN_IcmpHeader);
break;
case GNUNET_TUN_ICMPTYPE6_ECHO_REQUEST:
+ if (destination->details.exit_destination.af == AF_INET)
+ new_type = GNUNET_TUN_ICMPTYPE_ECHO_REQUEST;
break;
- default:
- GNUNET_break_op (0);
- GNUNET_STATISTICS_update (stats,
- gettext_noop ("# ICMPv6 packets dropped (type not allowed)"),
- 1, GNUNET_NO);
- return GNUNET_SYSERR;
- }
- /* end AF_INET6 */
- break;
- default:
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
- msg->size = htons (size);
- GNUNET_TUN_calculate_icmp_checksum (icmp,
- &i2v[1], mlen);
- (void) GNUNET_HELPER_send (helper_handle,
- msg,
- GNUNET_YES,
- NULL, NULL);
- }
- }
- break;
- default:
- GNUNET_assert (0);
- }
- GNUNET_CONTAINER_heap_update_cost (ts->heap_node,
- GNUNET_TIME_absolute_get ().abs_value_us);
- GNUNET_CADET_receive_done (channel);
- return GNUNET_OK;
-}
-
-
-/**
- * We got a UDP packet back from the CADET channel. Pass it on to the
- * local virtual interface via 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)
- */
-static int
-receive_udp_back (void *cls,
- struct GNUNET_CADET_Channel *channel,
- void **channel_ctx,
- const struct GNUNET_MessageHeader *message)
-{
- struct ChannelState *ts = *channel_ctx;
- const struct GNUNET_EXIT_UdpReplyMessage *reply;
- size_t mlen;
-
- GNUNET_STATISTICS_update (stats,
- gettext_noop ("# UDP packets received from cadet"),
- 1, GNUNET_NO);
- mlen = ntohs (message->size);
- if (mlen < sizeof (struct GNUNET_EXIT_UdpReplyMessage))
- {
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
- if (NULL == ts->heap_node)
- {
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
- if (AF_UNSPEC == ts->af)
- {
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
- reply = (const struct GNUNET_EXIT_UdpReplyMessage *) message;
- mlen -= sizeof (struct GNUNET_EXIT_UdpReplyMessage);
- {
- char sbuf[INET6_ADDRSTRLEN];
- char dbuf[INET6_ADDRSTRLEN];
-
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Received UDP reply from cadet, sending %u bytes from [%s]:%u -> [%s]:%u via TUN\n",
- (unsigned int) mlen,
- inet_ntop (ts->af, &ts->destination_ip, sbuf, sizeof (sbuf)),
- ts->destination_port,
- inet_ntop (ts->af, &ts->source_ip, dbuf, sizeof (dbuf)),
- ts->source_port);
- }
- switch (ts->af)
- {
- case AF_INET:
- {
- size_t size = sizeof (struct GNUNET_TUN_IPv4Header)
- + sizeof (struct GNUNET_TUN_UdpHeader)
- + sizeof (struct GNUNET_MessageHeader) +
- sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
- mlen;
- {
- char buf[size] GNUNET_ALIGN;
- struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
- struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
- struct GNUNET_TUN_IPv4Header *ipv4 = (struct GNUNET_TUN_IPv4Header *) &tun[1];
- struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipv4[1];
- msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
- msg->size = htons (size);
- tun->flags = htons (0);
- tun->proto = htons (ETH_P_IPV4);
- GNUNET_TUN_initialize_ipv4_header (ipv4,
- IPPROTO_UDP,
- sizeof (struct GNUNET_TUN_UdpHeader) + mlen,
- &ts->destination_ip.v4,
- &ts->source_ip.v4);
- if (0 == ntohs (reply->source_port))
- udp->source_port = htons (ts->destination_port);
- else
- udp->source_port = reply->source_port;
- if (0 == ntohs (reply->destination_port))
- udp->destination_port = htons (ts->source_port);
- else
- udp->destination_port = reply->destination_port;
- udp->len = htons (mlen + sizeof (struct GNUNET_TUN_UdpHeader));
- GNUNET_TUN_calculate_udp4_checksum (ipv4,
- udp,
- &reply[1],
- mlen);
- GNUNET_memcpy (&udp[1],
- &reply[1],
- mlen);
- (void) GNUNET_HELPER_send (helper_handle,
- msg,
- GNUNET_YES,
- NULL, NULL);
- }
- }
- break;
- case AF_INET6:
- {
- size_t size = sizeof (struct GNUNET_TUN_IPv6Header)
- + sizeof (struct GNUNET_TUN_UdpHeader)
- + sizeof (struct GNUNET_MessageHeader) +
- sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
- mlen;
- {
- char buf[size] GNUNET_ALIGN;
- struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
- struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
- struct GNUNET_TUN_IPv6Header *ipv6 = (struct GNUNET_TUN_IPv6Header *) &tun[1];
- struct GNUNET_TUN_UdpHeader *udp = (struct GNUNET_TUN_UdpHeader *) &ipv6[1];
- msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
- msg->size = htons (size);
- tun->flags = htons (0);
- tun->proto = htons (ETH_P_IPV6);
- GNUNET_TUN_initialize_ipv6_header (ipv6,
- IPPROTO_UDP,
- sizeof (struct GNUNET_TUN_UdpHeader) + mlen,
- &ts->destination_ip.v6,
- &ts->source_ip.v6);
- if (0 == ntohs (reply->source_port))
- udp->source_port = htons (ts->destination_port);
- else
- udp->source_port = reply->source_port;
- if (0 == ntohs (reply->destination_port))
- udp->destination_port = htons (ts->source_port);
- else
- udp->destination_port = reply->destination_port;
- udp->len = htons (mlen + sizeof (struct GNUNET_TUN_UdpHeader));
- GNUNET_TUN_calculate_udp6_checksum (ipv6,
- udp,
- &reply[1], mlen);
- GNUNET_memcpy (&udp[1],
- &reply[1],
- mlen);
- (void) GNUNET_HELPER_send (helper_handle,
- msg,
- GNUNET_YES,
- NULL, NULL);
+ case GNUNET_TUN_ICMPTYPE6_ECHO_REPLY:
+ if (destination->details.exit_destination.af == AF_INET)
+ new_type = GNUNET_TUN_ICMPTYPE_ECHO_REPLY;
+ break;
+ default:
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop ("# ICMPv6 packets dropped (type not allowed)"),
+ 1, GNUNET_NO);
+ return;
+ }
+ /* end of AF_INET6 */
+ break;
+ default:
+ GNUNET_assert (0);
+ }
+
+ /* update length calculations, as payload_length may have changed */
+ mlen = sizeof (struct GNUNET_EXIT_IcmpInternetMessage) +
+ alen + payload_length - sizeof (struct GNUNET_TUN_IcmpHeader);
+ if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
+ {
+ GNUNET_break (0);
+ return;
+ }
+ env = GNUNET_MQ_msg_extra (iim,
+ alen + payload_length - sizeof (struct GNUNET_TUN_IcmpHeader),
+ GNUNET_MESSAGE_TYPE_VPN_ICMP_TO_INTERNET);
+ iim->icmp_header = *icmp;
+ iim->icmp_header.type = new_type;
+ iim->af = htonl (destination->details.exit_destination.af);
+ switch (destination->details.exit_destination.af)
+ {
+ case AF_INET:
+ ip4dst = (struct in_addr *) &iim[1];
+ *ip4dst = destination->details.exit_destination.ip.v4;
+ payload = &ip4dst[1];
+ break;
+ case AF_INET6:
+ ip6dst = (struct in6_addr *) &iim[1];
+ *ip6dst = destination->details.exit_destination.ip.v6;
+ payload = &ip6dst[1];
+ break;
+ default:
+ GNUNET_assert (0);
}
+ GNUNET_memcpy (payload,
+ &icmp[1],
+ payload_length - sizeof (struct GNUNET_TUN_IcmpHeader));
}
break;
default:
+ /* not supported above, how can we get here !? */
GNUNET_assert (0);
+ break;
}
- GNUNET_CONTAINER_heap_update_cost (ts->heap_node,
- GNUNET_TIME_absolute_get ().abs_value_us);
- GNUNET_CADET_receive_done (channel);
- return GNUNET_OK;
+ ts->is_established = GNUNET_YES;
+ send_to_channel (ts,
+ env);
}
/**
- * We got a TCP packet back from the CADET channel. Pass it on to the
- * local virtual interface via the helper.
+ * Receive packets from the helper-process (someone send to the local
+ * virtual channel interface). Find the destination mapping, and if it
+ * exists, identify the correct CADET channel (or possibly create it)
+ * and forward the packet.
*
* @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 client NULL
+ * @param message message we got from the client (VPN channel interface)
*/
static int
-receive_tcp_back (void *cls,
- struct GNUNET_CADET_Channel *channel,
- void **channel_ctx,
- const struct GNUNET_MessageHeader *message)
+message_token (void *cls,
+ void *client,
+ const struct GNUNET_MessageHeader *message)
{
- struct ChannelState *ts = *channel_ctx;
- const struct GNUNET_EXIT_TcpDataMessage *data;
+ const struct GNUNET_TUN_Layer2PacketHeader *tun;
size_t mlen;
+ struct GNUNET_HashCode key;
+ struct DestinationEntry *de;
GNUNET_STATISTICS_update (stats,
- gettext_noop ("# TCP packets received from cadet"),
+ gettext_noop ("# Packets received from TUN interface"),
1, GNUNET_NO);
mlen = ntohs (message->size);
- if (mlen < sizeof (struct GNUNET_EXIT_TcpDataMessage))
- {
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
- if (NULL == ts->heap_node)
- {
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
- data = (const struct GNUNET_EXIT_TcpDataMessage *) message;
- mlen -= sizeof (struct GNUNET_EXIT_TcpDataMessage);
- {
- char sbuf[INET6_ADDRSTRLEN];
- char dbuf[INET6_ADDRSTRLEN];
-
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Received TCP reply from cadet, sending %u bytes from [%s]:%u -> [%s]:%u via TUN\n",
- (unsigned int) mlen,
- inet_ntop (ts->af, &ts->destination_ip, sbuf, sizeof (sbuf)),
- ts->destination_port,
- inet_ntop (ts->af, &ts->source_ip, dbuf, sizeof (dbuf)),
- ts->source_port);
- }
- if (data->tcp_header.off * 4 < sizeof (struct GNUNET_TUN_TcpHeader))
+ if ( (ntohs (message->type) != GNUNET_MESSAGE_TYPE_VPN_HELPER) ||
+ (mlen < sizeof (struct GNUNET_MessageHeader) + sizeof (struct GNUNET_TUN_Layer2PacketHeader)) )
{
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
+ GNUNET_break (0);
+ return GNUNET_OK;
}
- switch (ts->af)
+ tun = (const struct GNUNET_TUN_Layer2PacketHeader *) &message[1];
+ mlen -= (sizeof (struct GNUNET_MessageHeader) + sizeof (struct GNUNET_TUN_Layer2PacketHeader));
+ switch (ntohs (tun->proto))
{
- case AF_INET:
+ case ETH_P_IPV6:
{
- size_t size = sizeof (struct GNUNET_TUN_IPv4Header)
- + sizeof (struct GNUNET_TUN_TcpHeader)
- + sizeof (struct GNUNET_MessageHeader) +
- sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
- mlen;
+ const struct GNUNET_TUN_IPv6Header *pkt6;
+
+ if (mlen < sizeof (struct GNUNET_TUN_IPv6Header))
{
- char buf[size] GNUNET_ALIGN;
- struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
- struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
- struct GNUNET_TUN_IPv4Header *ipv4 = (struct GNUNET_TUN_IPv4Header *) &tun[1];
- struct GNUNET_TUN_TcpHeader *tcp = (struct GNUNET_TUN_TcpHeader *) &ipv4[1];
- msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
- msg->size = htons (size);
- tun->flags = htons (0);
- tun->proto = htons (ETH_P_IPV4);
- GNUNET_TUN_initialize_ipv4_header (ipv4,
- IPPROTO_TCP,
- sizeof (struct GNUNET_TUN_TcpHeader) + mlen,
- &ts->destination_ip.v4,
- &ts->source_ip.v4);
- *tcp = data->tcp_header;
- tcp->source_port = htons (ts->destination_port);
- tcp->destination_port = htons (ts->source_port);
- GNUNET_TUN_calculate_tcp4_checksum (ipv4,
- tcp,
- &data[1],
- mlen);
- GNUNET_memcpy (&tcp[1],
- &data[1],
- mlen);
- (void) GNUNET_HELPER_send (helper_handle,
- msg,
- GNUNET_YES,
- NULL, NULL);
+ /* blame kernel */
+ GNUNET_break (0);
+ return GNUNET_OK;
+ }
+ pkt6 = (const struct GNUNET_TUN_IPv6Header *) &tun[1];
+ get_destination_key_from_ip (AF_INET6,
+ &pkt6->destination_address,
+ &key);
+ de = GNUNET_CONTAINER_multihashmap_get (destination_map, &key);
+ if (NULL == de)
+ {
+ char buf[INET6_ADDRSTRLEN];
+
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ _("Packet received for unmapped destination `%s' (dropping it)\n"),
+ inet_ntop (AF_INET6,
+ &pkt6->destination_address,
+ buf,
+ sizeof (buf)));
+ return GNUNET_OK;
}
+ route_packet (de,
+ AF_INET6,
+ pkt6->next_header,
+ &pkt6->source_address,
+ &pkt6->destination_address,
+ &pkt6[1],
+ mlen - sizeof (struct GNUNET_TUN_IPv6Header));
}
break;
- case AF_INET6:
+ case ETH_P_IPV4:
{
- size_t size = sizeof (struct GNUNET_TUN_IPv6Header)
- + sizeof (struct GNUNET_TUN_TcpHeader)
- + sizeof (struct GNUNET_MessageHeader) +
- sizeof (struct GNUNET_TUN_Layer2PacketHeader) +
- mlen;
+ struct GNUNET_TUN_IPv4Header *pkt4;
+
+ if (mlen < sizeof (struct GNUNET_TUN_IPv4Header))
{
- char buf[size] GNUNET_ALIGN;
- struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) buf;
- struct GNUNET_TUN_Layer2PacketHeader *tun = (struct GNUNET_TUN_Layer2PacketHeader*) &msg[1];
- struct GNUNET_TUN_IPv6Header *ipv6 = (struct GNUNET_TUN_IPv6Header *) &tun[1];
- struct GNUNET_TUN_TcpHeader *tcp = (struct GNUNET_TUN_TcpHeader *) &ipv6[1];
- msg->type = htons (GNUNET_MESSAGE_TYPE_VPN_HELPER);
- msg->size = htons (size);
- tun->flags = htons (0);
- tun->proto = htons (ETH_P_IPV6);
- GNUNET_TUN_initialize_ipv6_header (ipv6,
- IPPROTO_TCP,
- sizeof (struct GNUNET_TUN_TcpHeader) + mlen,
- &ts->destination_ip.v6,
- &ts->source_ip.v6);
- *tcp = data->tcp_header;
- tcp->source_port = htons (ts->destination_port);
- tcp->destination_port = htons (ts->source_port);
- GNUNET_TUN_calculate_tcp6_checksum (ipv6,
- tcp,
- &data[1],
- mlen);
- GNUNET_memcpy (&tcp[1],
- &data[1],
- mlen);
- (void) GNUNET_HELPER_send (helper_handle,
- msg,
- GNUNET_YES,
- NULL, NULL);
+ /* blame kernel */
+ GNUNET_break (0);
+ return GNUNET_OK;
+ }
+ pkt4 = (struct GNUNET_TUN_IPv4Header *) &tun[1];
+ get_destination_key_from_ip (AF_INET,
+ &pkt4->destination_address,
+ &key);
+ de = GNUNET_CONTAINER_multihashmap_get (destination_map, &key);
+ if (NULL == de)
+ {
+ char buf[INET_ADDRSTRLEN];
+
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ _("Packet received for unmapped destination `%s' (dropping it)\n"),
+ inet_ntop (AF_INET,
+ &pkt4->destination_address,
+ buf,
+ sizeof (buf)));
+ return GNUNET_OK;
+ }
+ if (pkt4->header_length * 4 != sizeof (struct GNUNET_TUN_IPv4Header))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ _("Received IPv4 packet with options (dropping it)\n"));
+ return GNUNET_OK;
}
+ route_packet (de,
+ AF_INET,
+ pkt4->protocol,
+ &pkt4->source_address,
+ &pkt4->destination_address,
+ &pkt4[1],
+ mlen - sizeof (struct GNUNET_TUN_IPv4Header));
}
break;
+ default:
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ _("Received packet of unknown protocol %d from TUN (dropping it)\n"),
+ (unsigned int) ntohs (tun->proto));
+ break;
}
- GNUNET_CONTAINER_heap_update_cost (ts->heap_node,
- GNUNET_TIME_absolute_get ().abs_value_us);
- GNUNET_CADET_receive_done (channel);
return GNUNET_OK;
}
}
-/**
- * Function called whenever a 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 (our `struct ChannelState`)
- */
-static void
-channel_cleaner (void *cls,
- const struct GNUNET_CADET_Channel *channel,
- void *channel_ctx)
-{
- struct ChannelState *ts = channel_ctx;
-
- ts->channel = NULL; /* we must not call GNUNET_CADET_channel_destroy() anymore */
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "CADET notified us about death of channel to `%s'\n",
- print_channel_destination (&ts->destination));
- free_channel_state (ts);
-}
-
/**
* Free memory occupied by an entry in the destination map.
const struct GNUNET_CONFIGURATION_Handle *cfg_,
struct GNUNET_SERVICE_Handle *service)
{
- static const struct GNUNET_CADET_MessageHandler cadet_handlers[] = {
- { &receive_udp_back, GNUNET_MESSAGE_TYPE_VPN_UDP_REPLY, 0},
- { &receive_tcp_back, GNUNET_MESSAGE_TYPE_VPN_TCP_DATA_TO_VPN, 0},
- { &receive_icmp_back, GNUNET_MESSAGE_TYPE_VPN_ICMP_TO_VPN, 0},
- {NULL, 0, 0}
- };
char *ifname;
char *ipv6addr;
char *ipv6prefix_s;
}
vpn_argv[6] = NULL;
- cadet_handle
- = GNUNET_CADET_connect (cfg_,
- NULL,
- &channel_cleaner,
- cadet_handlers);
+ cadet_handle = GNUNET_CADET_connecT (cfg_);
// FIXME never opens ports???
helper_handle = GNUNET_HELPER_start (GNUNET_NO,
"gnunet-helper-vpn", vpn_argv,