From 11cbed2558f43f11a4329266ecfb46bf916c5a4a Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Tue, 17 Jan 2012 20:19:03 +0000 Subject: -moving remaining checksum calculations to tun library, fixing #2066 --- src/dns/gnunet-service-dns.c | 70 ++++++++----------------- src/exit/gnunet-daemon-exit.c | 45 ++++++---------- src/include/gnunet_tun_lib.h | 45 +++++++++++++++- src/tun/tun.c | 116 +++++++++++++++++++++++++++++++++++++++++- src/vpn/gnunet-service-vpn.c | 58 ++++++--------------- 5 files changed, 212 insertions(+), 122 deletions(-) diff --git a/src/dns/gnunet-service-dns.c b/src/dns/gnunet-service-dns.c index 288304600..690b4887e 100644 --- a/src/dns/gnunet-service-dns.c +++ b/src/dns/gnunet-service-dns.c @@ -20,6 +20,7 @@ /** * @file dns/gnunet-service-dns.c + * @brief service to intercept and modify DNS queries (and replies) of this system * @author Christian Grothoff */ #include "platform.h" @@ -351,7 +352,8 @@ request_done (struct RequestRecord *rr) { char buf[reply_len]; size_t off; - uint32_t udp_crc_sum; + struct GNUNET_TUN_IPv4Header ip4; + struct GNUNET_TUN_IPv6Header ip6; /* first, GNUnet message header */ hdr = (struct GNUNET_MessageHeader*) buf; @@ -373,71 +375,38 @@ request_done (struct RequestRecord *rr) } /* now IP header */ - udp_crc_sum = 0; switch (rr->src_addr.ss_family) { case AF_INET: { struct sockaddr_in *src = (struct sockaddr_in *) &rr->src_addr; struct sockaddr_in *dst = (struct sockaddr_in *) &rr->dst_addr; - struct GNUNET_TUN_IPv4Header ip; spt = dst->sin_port; dpt = src->sin_port; - GNUNET_TUN_initialize_ipv4_header (&ip, + GNUNET_TUN_initialize_ipv4_header (&ip4, IPPROTO_UDP, reply_len - off - sizeof (struct GNUNET_TUN_IPv4Header), &dst->sin_addr, &src->sin_addr); - - - - udp_crc_sum = GNUNET_CRYPTO_crc16_step (udp_crc_sum, - &ip.source_address, - sizeof (struct in_addr) * 2); - { - uint16_t tmp; - - tmp = htons (IPPROTO_UDP); - udp_crc_sum = GNUNET_CRYPTO_crc16_step (udp_crc_sum, - &tmp, - sizeof (uint16_t)); - tmp = htons (rr->payload_length + sizeof (struct GNUNET_TUN_UdpHeader)); - udp_crc_sum = GNUNET_CRYPTO_crc16_step (udp_crc_sum, - &tmp, - sizeof (uint16_t)); - } - memcpy (&buf[off], &ip, sizeof (ip)); - off += sizeof (ip); + memcpy (&buf[off], &ip4, sizeof (ip4)); + off += sizeof (ip4); } break; case AF_INET6: { struct sockaddr_in6 *src = (struct sockaddr_in6 *) &rr->src_addr; struct sockaddr_in6 *dst = (struct sockaddr_in6 *) &rr->dst_addr; - struct GNUNET_TUN_IPv6Header ip; spt = dst->sin6_port; dpt = src->sin6_port; - GNUNET_TUN_initialize_ipv6_header (&ip, + GNUNET_TUN_initialize_ipv6_header (&ip6, IPPROTO_UDP, reply_len - sizeof (struct GNUNET_TUN_IPv6Header), &dst->sin6_addr, &src->sin6_addr); - { - uint32_t tmp; - - tmp = htons (rr->payload_length + sizeof (struct GNUNET_TUN_UdpHeader)); - udp_crc_sum = GNUNET_CRYPTO_crc16_step (udp_crc_sum, - &tmp, - sizeof (uint32_t)); - tmp = htons (IPPROTO_UDP); - udp_crc_sum = GNUNET_CRYPTO_crc16_step (udp_crc_sum, - &tmp, - sizeof (uint32_t)); - } - memcpy (&buf[off], &ip, sizeof (ip)); - off += sizeof (ip); + memcpy (&buf[off], &ip6, sizeof (ip6)); + off += sizeof (ip6); } break; default: @@ -451,17 +420,20 @@ request_done (struct RequestRecord *rr) udp.spt = spt; udp.dpt = dpt; udp.len = htons (reply_len - off); - udp.crc = 0; - udp_crc_sum = GNUNET_CRYPTO_crc16_step (udp_crc_sum, - &udp, - sizeof (udp)); - udp_crc_sum = GNUNET_CRYPTO_crc16_step (udp_crc_sum, - rr->payload, - rr->payload_length); - udp.crc = GNUNET_CRYPTO_crc16_finish (udp_crc_sum); + if (AF_INET == rr->src_addr.ss_family) + GNUNET_TUN_calculate_udp4_checksum (&ip4, + &udp, + rr->payload, + rr->payload_length); + else + GNUNET_TUN_calculate_udp6_checksum (&ip6, + &udp, + rr->payload, + rr->payload_length); memcpy (&buf[off], &udp, sizeof (udp)); off += sizeof (udp); } + /* now DNS payload */ { memcpy (&buf[off], rr->payload, rr->payload_length); @@ -1273,4 +1245,4 @@ main (int argc, char *const *argv) } -/* end of gnunet-service-dns_new.c */ +/* end of gnunet-service-dns.c */ diff --git a/src/exit/gnunet-daemon-exit.c b/src/exit/gnunet-daemon-exit.c index 482eaae7e..2a8c746f2 100644 --- a/src/exit/gnunet-daemon-exit.c +++ b/src/exit/gnunet-daemon-exit.c @@ -27,9 +27,6 @@ * TODO: * - test * - * Code cleanup: - * - factor out crc computations from DNS/EXIT/VPN into shared library? - * * Design: * - which code should advertise services? the service model is right * now a bit odd, especially as this code DOES the exit and knows @@ -1078,8 +1075,10 @@ prepare_ipv4_packet (const void *payload, size_t payload_length, pkt4_udp->spt = htons (src_address->port); pkt4_udp->dpt = htons (dst_address->port); - pkt4_udp->crc = 0; /* Optional for IPv4 */ pkt4_udp->len = htons ((uint16_t) payload_length); + GNUNET_TUN_calculate_udp4_checksum (pkt4, + pkt4_udp, + payload, payload_length); memcpy (&pkt4_udp[1], payload, payload_length); } break; @@ -1088,19 +1087,13 @@ prepare_ipv4_packet (const void *payload, size_t payload_length, struct GNUNET_TUN_TcpHeader *pkt4_tcp = (struct GNUNET_TUN_TcpHeader *) &pkt4[1]; memcpy (pkt4_tcp, tcp_header, sizeof (struct GNUNET_TUN_TcpHeader)); - memcpy (&pkt4_tcp[1], payload, payload_length); pkt4_tcp->spt = htons (src_address->port); pkt4_tcp->dpt = htons (dst_address->port); - - pkt4_tcp->crc = 0; - uint32_t sum = 0; - sum = GNUNET_CRYPTO_crc16_step (sum, - &pkt4->source_address, - sizeof (struct in_addr) * 2); - uint32_t tmp = htonl ((protocol << 16) | (0xffff & len)); - sum = GNUNET_CRYPTO_crc16_step (sum, & tmp, sizeof (uint32_t)); - sum = GNUNET_CRYPTO_crc16_step (sum, & pkt4_tcp, len); - pkt4_tcp->crc = GNUNET_CRYPTO_crc16_finish (sum); + GNUNET_TUN_calculate_tcp4_checksum (pkt4, + pkt4_tcp, + payload, + payload_length); + memcpy (&pkt4_tcp[1], payload, payload_length); } break; default: @@ -1172,28 +1165,22 @@ prepare_ipv6_packet (const void *payload, size_t payload_length, { struct GNUNET_TUN_UdpHeader *pkt6_udp = (struct GNUNET_TUN_UdpHeader *) &pkt6[1]; - memcpy (&pkt6[1], payload, payload_length); - pkt6_udp->crc = 0; pkt6_udp->spt = htons (src_address->port); pkt6_udp->dpt = htons (dst_address->port); pkt6_udp->len = htons ((uint16_t) payload_length); - - uint32_t sum = 0; - sum = GNUNET_CRYPTO_crc16_step (sum, - &pkt6->source_address, - sizeof (struct in6_addr) * 2); - uint32_t tmp = htons (len); - sum = GNUNET_CRYPTO_crc16_step (sum, &tmp, sizeof (uint32_t)); - tmp = htonl (pkt6->next_header); - sum = GNUNET_CRYPTO_crc16_step (sum, &tmp, sizeof (uint32_t)); - sum = GNUNET_CRYPTO_crc16_step (sum, pkt6_udp, len); - pkt6_udp->crc = GNUNET_CRYPTO_crc16_finish (sum); + pkt6_udp->crc = 0; + GNUNET_TUN_calculate_udp6_checksum (pkt6, + pkt6_udp, + payload, + payload_length); + memcpy (&pkt6[1], payload, payload_length); } break; case IPPROTO_TCP: { struct GNUNET_TUN_TcpHeader *pkt6_tcp = (struct GNUNET_TUN_TcpHeader *) pkt6; - + + /* memcpy first here as some TCP header fields are initialized this way! */ memcpy (pkt6_tcp, payload, payload_length); pkt6_tcp->spt = htons (src_address->port); pkt6_tcp->dpt = htons (dst_address->port); diff --git a/src/include/gnunet_tun_lib.h b/src/include/gnunet_tun_lib.h index b30b2b03a..5fddf70b2 100644 --- a/src/include/gnunet_tun_lib.h +++ b/src/include/gnunet_tun_lib.h @@ -181,11 +181,25 @@ GNUNET_TUN_initialize_ipv6_header (struct GNUNET_TUN_IPv6Header *ip, const struct in6_addr *src, const struct in6_addr *dst); +/** + * Calculate IPv4 TCP checksum. + * + * @param ipv4 header fully initialized + * @param tcp TCP header (initialized except for CRC) + * @param payload the TCP payload + * @param payload_length number of bytes of TCP payload + */ +void +GNUNET_TUN_calculate_tcp4_checksum (const struct GNUNET_TUN_IPv4Header *ip, + struct GNUNET_TUN_TcpHeader *tcp, + const void *payload, + uint16_t payload_length); + /** * Calculate IPv6 TCP checksum. * * @param ipv6 header fully initialized - * @param tcp header (initialized except for CRC) + * @param tcp TCP header (initialized except for CRC) * @param payload the TCP payload * @param payload_length number of bytes of TCP payload */ @@ -195,5 +209,34 @@ GNUNET_TUN_calculate_tcp6_checksum (const struct GNUNET_TUN_IPv6Header *ip, const void *payload, uint16_t payload_length); +/** + * Calculate IPv4 UDP checksum. + * + * @param ipv4 header fully initialized + * @param udp UDP header (initialized except for CRC) + * @param payload the UDP payload + * @param payload_length number of bytes of UDP payload + */ +void +GNUNET_TUN_calculate_udp4_checksum (const struct GNUNET_TUN_IPv4Header *ip, + struct GNUNET_TUN_UdpHeader *udp, + const void *payload, + uint16_t payload_length); + + +/** + * Calculate IPv6 UDP checksum. + * + * @param ipv6 header fully initialized + * @param udp UDP header (initialized except for CRC) + * @param payload the UDP payload + * @param payload_length number of bytes of UDP payload + */ +void +GNUNET_TUN_calculate_udp6_checksum (const struct GNUNET_TUN_IPv6Header *ip, + struct GNUNET_TUN_UdpHeader *udp, + const void *payload, + uint16_t payload_length); + #endif diff --git a/src/tun/tun.c b/src/tun/tun.c index c30861cce..009fdd952 100644 --- a/src/tun/tun.c +++ b/src/tun/tun.c @@ -19,7 +19,7 @@ */ /** - * @file tun/tun. + * @file tun/tun.c * @brief standard IP calculations for TUN interaction * @author Philipp Toelke * @author Christian Grothoff @@ -32,6 +32,7 @@ */ #define FRESH_TTL 255 + /** * Initialize an IPv4 header. * @@ -95,6 +96,39 @@ GNUNET_TUN_initialize_ipv6_header (struct GNUNET_TUN_IPv6Header *ip, } +/** + * Calculate IPv4 TCP checksum. + * + * @param ipv4 header fully initialized + * @param tcp TCP header (initialized except for CRC) + * @param payload the TCP payload + * @param payload_length number of bytes of TCP payload + */ +void +GNUNET_TUN_calculate_tcp4_checksum (const struct GNUNET_TUN_IPv4Header *ip, + struct GNUNET_TUN_TcpHeader *tcp, + const void *payload, + uint16_t payload_length) +{ + uint32_t sum; + uint32_t tmp; + + GNUNET_assert (payload_length + sizeof (struct GNUNET_TUN_IPv4Header) + sizeof (struct GNUNET_TUN_TcpHeader) == + ntohs (ip->total_length)); + GNUNET_assert (IPPROTO_TCP == ip->protocol); + + tcp->crc = 0; + sum = GNUNET_CRYPTO_crc16_step (0, + &ip->source_address, + sizeof (struct in_addr) * 2); + tmp = htonl ((IPPROTO_TCP << 16) | (payload_length + sizeof (struct GNUNET_TUN_TcpHeader))); + sum = GNUNET_CRYPTO_crc16_step (sum, &tmp, sizeof (uint32_t)); + sum = GNUNET_CRYPTO_crc16_step (sum, tcp, sizeof (struct GNUNET_TUN_TcpHeader)); + sum = GNUNET_CRYPTO_crc16_step (sum, payload, payload_length); + tcp->crc = GNUNET_CRYPTO_crc16_finish (sum); +} + + /** * Calculate IPv6 TCP checksum. * @@ -114,6 +148,7 @@ GNUNET_TUN_calculate_tcp6_checksum (const struct GNUNET_TUN_IPv6Header *ip, GNUNET_assert (payload_length + sizeof (struct GNUNET_TUN_IPv6Header) + sizeof (struct GNUNET_TUN_TcpHeader) == ntohs (ip->payload_length)); + GNUNET_assert (IPPROTO_TCP == ip->next_header); tcp->crc = 0; sum = GNUNET_CRYPTO_crc16_step (0, &ip->source_address, 2 * sizeof (struct in6_addr)); tmp = htonl (sizeof (struct GNUNET_TUN_TcpHeader) + payload_length); @@ -127,5 +162,84 @@ GNUNET_TUN_calculate_tcp6_checksum (const struct GNUNET_TUN_IPv6Header *ip, } +/** + * Calculate IPv4 UDP checksum. + * + * @param ipv4 header fully initialized + * @param udp UDP header (initialized except for CRC) + * @param payload the UDP payload + * @param payload_length number of bytes of UDP payload + */ +void +GNUNET_TUN_calculate_udp4_checksum (const struct GNUNET_TUN_IPv4Header *ip, + struct GNUNET_TUN_UdpHeader *udp, + const void *payload, + uint16_t payload_length) +{ + uint32_t sum; + uint16_t tmp; + + GNUNET_assert (payload_length + sizeof (struct GNUNET_TUN_IPv4Header) + sizeof (struct GNUNET_TUN_UdpHeader) == + ntohs (ip->total_length)); + GNUNET_assert (IPPROTO_UDP == ip->protocol); + + udp->crc = 0; /* technically optional, but we calculate it anyway, just to be sure */ + sum = GNUNET_CRYPTO_crc16_step (0, + &ip->source_address, + sizeof (struct in_addr) * 2); + tmp = htons (IPPROTO_UDP); + sum = GNUNET_CRYPTO_crc16_step (sum, + &tmp, + sizeof (uint16_t)); + tmp = htons (sizeof (struct GNUNET_TUN_UdpHeader) + payload_length); + sum = GNUNET_CRYPTO_crc16_step (sum, + &tmp, + sizeof (uint16_t)); + sum = GNUNET_CRYPTO_crc16_step (sum, + udp, + sizeof (struct GNUNET_TUN_UdpHeader)); + sum = GNUNET_CRYPTO_crc16_step (sum, + payload, + payload_length); + udp->crc = GNUNET_CRYPTO_crc16_finish (sum); +} + + +/** + * Calculate IPv6 UDP checksum. + * + * @param ipv6 header fully initialized + * @param udp UDP header (initialized except for CRC) + * @param payload the UDP payload + * @param payload_length number of bytes of UDP payload + */ +void +GNUNET_TUN_calculate_udp6_checksum (const struct GNUNET_TUN_IPv6Header *ip, + struct GNUNET_TUN_UdpHeader *udp, + const void *payload, + uint16_t payload_length) +{ + uint32_t sum; + uint32_t tmp; + + GNUNET_assert (payload_length + sizeof (struct GNUNET_TUN_IPv6Header) + sizeof (struct GNUNET_TUN_UdpHeader) == + ntohs (ip->payload_length)); + GNUNET_assert (payload_length + sizeof (struct GNUNET_TUN_UdpHeader) == + ntohs (udp->len)); + GNUNET_assert (IPPROTO_UDP == ip->next_header); + + udp->crc = 0; + sum = GNUNET_CRYPTO_crc16_step (0, + &ip->source_address, + sizeof (struct in6_addr) * 2); + tmp = htons (sizeof (struct GNUNET_TUN_UdpHeader) + payload_length); /* aka udp->len */ + sum = GNUNET_CRYPTO_crc16_step (sum, &tmp, sizeof (uint32_t)); + tmp = htons (ip->next_header); + sum = GNUNET_CRYPTO_crc16_step (sum, &tmp, sizeof (uint32_t)); + sum = GNUNET_CRYPTO_crc16_step (sum, udp, sizeof (struct GNUNET_TUN_UdpHeader)); + sum = GNUNET_CRYPTO_crc16_step (sum, payload, payload_length); + udp->crc = GNUNET_CRYPTO_crc16_finish (sum); +} + /* end of tun.c */ diff --git a/src/vpn/gnunet-service-vpn.c b/src/vpn/gnunet-service-vpn.c index 0d236975e..153327b9b 100644 --- a/src/vpn/gnunet-service-vpn.c +++ b/src/vpn/gnunet-service-vpn.c @@ -32,10 +32,6 @@ * * Features: * - add back ICMP support (especially needed for IPv6) - * - * Code cleanup: - * - consider moving IP-header building / checksumming code into shared library - * with dns/exit/vpn (libgnunettun_tcpip?) */ #include "platform.h" #include "gnunet_util_lib.h" @@ -1436,7 +1432,10 @@ receive_udp_back (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel, else udp->dpt = reply->destination_port; udp->len = htons (mlen + sizeof (struct GNUNET_TUN_UdpHeader)); - udp->crc = 0; // FIXME: optional, but we might want to calculate this one anyway + GNUNET_TUN_calculate_udp4_checksum (ipv4, + udp, + &reply[1], + mlen); memcpy (&udp[1], &reply[1], mlen); @@ -1464,15 +1463,11 @@ receive_udp_back (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel, msg->size = htons (size); tun->flags = htons (0); tun->proto = htons (ETH_P_IPV6); - ipv6->traffic_class_h = 0; - ipv6->version = 6; - ipv6->traffic_class_l = 0; - ipv6->flow_label = 0; - ipv6->payload_length = htons (sizeof (struct GNUNET_TUN_UdpHeader) + sizeof (struct GNUNET_TUN_IPv6Header) + mlen); - ipv6->next_header = IPPROTO_UDP; - ipv6->hop_limit = 255; - ipv6->source_address = ts->destination_ip.v6; - ipv6->destination_address = ts->source_ip.v6; + 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->spt = htons (ts->destination_port); else @@ -1482,24 +1477,12 @@ receive_udp_back (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel, else udp->dpt = reply->destination_port; udp->len = htons (mlen + sizeof (struct GNUNET_TUN_UdpHeader)); - udp->crc = 0; + GNUNET_TUN_calculate_udp6_checksum (ipv6, + udp, + &reply[1], mlen); memcpy (&udp[1], &reply[1], mlen); - { - uint32_t sum = 0; - sum = - GNUNET_CRYPTO_crc16_step (sum, &ipv6->source_address, - sizeof (struct in6_addr) * 2); - uint32_t tmp = udp->len; - sum = GNUNET_CRYPTO_crc16_step (sum, &tmp, sizeof (uint32_t)); - tmp = htons (IPPROTO_UDP); - sum = GNUNET_CRYPTO_crc16_step (sum, &tmp, sizeof (uint32_t)); - sum = GNUNET_CRYPTO_crc16_step (sum, - udp, - ntohs (udp->len)); - udp->crc = GNUNET_CRYPTO_crc16_finish (sum); - } (void) GNUNET_HELPER_send (helper_handle, msg, GNUNET_YES, @@ -1596,22 +1579,13 @@ receive_tcp_back (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel, *tcp = data->tcp_header; tcp->spt = htons (ts->destination_port); tcp->dpt = htons (ts->source_port); - tcp->crc = 0; + GNUNET_TUN_calculate_tcp4_checksum (ipv4, + tcp, + &data[1], + mlen); memcpy (&tcp[1], &data[1], mlen); - { - uint32_t sum = 0; - uint32_t tmp; - - sum = GNUNET_CRYPTO_crc16_step (sum, - &ipv4->source_address, - 2 * sizeof (struct in_addr)); - tmp = htonl ((IPPROTO_TCP << 16) | (mlen + sizeof (struct GNUNET_TUN_TcpHeader))); - sum = GNUNET_CRYPTO_crc16_step (sum, &tmp, sizeof (uint32_t)); - sum = GNUNET_CRYPTO_crc16_step (sum, tcp, mlen + sizeof (struct GNUNET_TUN_TcpHeader)); - tcp->crc = GNUNET_CRYPTO_crc16_finish (sum); - } (void) GNUNET_HELPER_send (helper_handle, msg, GNUNET_YES, -- cgit v1.2.3