diff options
author | Lorenzo Colitti <lorenzo@google.com> | 2014-03-08 20:30:06 +0000 |
---|---|---|
committer | Lorenzo Colitti <lorenzo@google.com> | 2014-03-08 20:30:06 +0000 |
commit | 2636ea7d40cb9ac04571d580df62e2ebfe269d7d (patch) | |
tree | 6f97e747edc1d66ff314f496a7e1bb6ac5a4d73a | |
parent | 866b4af18d8e9ef1020adc9accbb9f9de4c873dc (diff) | |
download | android_external_android-clat-2636ea7d40cb9ac04571d580df62e2ebfe269d7d.tar.gz android_external_android-clat-2636ea7d40cb9ac04571d580df62e2ebfe269d7d.tar.bz2 android_external_android-clat-2636ea7d40cb9ac04571d580df62e2ebfe269d7d.zip |
Revert "DO NOT MERGE: Support translating fragmented packets."
This reverts commit 866b4af18d8e9ef1020adc9accbb9f9de4c873dc.
Change-Id: I864dc0cbf3ad0dc04b86ed4e84a46aaf02778429
-rw-r--r-- | clatd.c | 8 | ||||
-rw-r--r-- | dump.c | 1 | ||||
-rw-r--r-- | ipv4.c | 33 | ||||
-rw-r--r-- | ipv6.c | 52 | ||||
-rw-r--r-- | translate.c | 54 | ||||
-rw-r--r-- | translate.h | 13 |
6 files changed, 35 insertions, 126 deletions
@@ -51,9 +51,6 @@ #define DEVICENAME6 "clat" #define DEVICENAME4 "clat4" -/* 40 bytes IPv6 header - 20 bytes IPv4 header + 8 bytes fragment header */ -#define MTU_DELTA 28 - int forwarding_fd = -1; volatile sig_atomic_t running = 1; @@ -274,9 +271,8 @@ void configure_interface(const char *uplink_interface, const char *plat_prefix, Global_Clatd_Config.mtu = 1280; } - if(Global_Clatd_Config.ipv4mtu <= 0 || - Global_Clatd_Config.ipv4mtu > Global_Clatd_Config.mtu - MTU_DELTA) { - Global_Clatd_Config.ipv4mtu = Global_Clatd_Config.mtu - MTU_DELTA; + if(Global_Clatd_Config.ipv4mtu <= 0 || (Global_Clatd_Config.ipv4mtu > Global_Clatd_Config.mtu - 20)) { + Global_Clatd_Config.ipv4mtu = Global_Clatd_Config.mtu-20; logmsg(ANDROID_LOG_WARN,"ipv4mtu now set to = %d",Global_Clatd_Config.ipv4mtu); } @@ -220,7 +220,6 @@ void logcat_hexdump(const char *info, const char *data, size_t len) { char output[PACKETLEN*3+2]; size_t i; - output[0] = '\0'; for(i = 0; i < len && i < PACKETLEN; i++) { snprintf(output + i*3, 4, " %02x", (uint8_t)data[i]); } @@ -57,8 +57,7 @@ int icmp_packet(clat_packet out, int pos, const struct icmphdr *icmp, uint32_t c int ipv4_packet(clat_packet out, int pos, const char *packet, size_t len) { const struct iphdr *header = (struct iphdr *) packet; struct ip6_hdr *ip6_targ = (struct ip6_hdr *) out[pos].iov_base; - struct ip6_frag *frag_hdr; - size_t frag_hdr_len; + uint16_t frag_flags; uint8_t nxthdr; const char *next_header; size_t len_left; @@ -70,6 +69,12 @@ int ipv4_packet(clat_packet out, int pos, const char *packet, size_t len) { return 0; } + frag_flags = ntohs(header->frag_off); + if(frag_flags & IP_MF) { // this could theoretically be supported, but isn't + logmsg_dbg(ANDROID_LOG_ERROR, "ip_packet/more fragments set, dropping"); + return 0; + } + if(header->ihl < 5) { logmsg_dbg(ANDROID_LOG_ERROR, "ip_packet/ip header length set to less than 5: %x", header->ihl); return 0; @@ -106,32 +111,20 @@ int ipv4_packet(clat_packet out, int pos, const char *packet, size_t len) { fill_ip6_header(ip6_targ, 0, nxthdr, header); out[pos].iov_len = sizeof(struct ip6_hdr); - /* Calculate the pseudo-header checksum. - * Technically, the length that is used in the pseudo-header checksum is the transport layer - * length, which is not the same as len_left in the case of fragmented packets. But since - * translation does not change the transport layer length, the checksum is unaffected. - */ + // Calculate the pseudo-header checksum. old_sum = ipv4_pseudo_header_checksum(header, len_left); new_sum = ipv6_pseudo_header_checksum(ip6_targ, len_left, nxthdr); - // If the IPv4 packet is fragmented, add a Fragment header. - frag_hdr = (struct ip6_frag *) out[pos + 1].iov_base; - frag_hdr_len = maybe_fill_frag_header(frag_hdr, ip6_targ, header); - out[pos + 1].iov_len = frag_hdr_len; - - if (frag_hdr_len && frag_hdr->ip6f_offlg & IP6F_OFF_MASK) { - // Non-first fragment. Copy the rest of the packet as is. - iov_len = generic_packet(out, pos + 2, next_header, len_left); - } else if (nxthdr == IPPROTO_ICMPV6) { - iov_len = icmp_packet(out, pos + 2, (const struct icmphdr *) next_header, new_sum, len_left); + if (nxthdr == IPPROTO_ICMPV6) { + iov_len = icmp_packet(out, pos + 1, (const struct icmphdr *) next_header, new_sum, len_left); } else if (nxthdr == IPPROTO_TCP) { - iov_len = tcp_packet(out, pos + 2, (const struct tcphdr *) next_header, old_sum, new_sum, + iov_len = tcp_packet(out, pos + 1, (const struct tcphdr *) next_header, old_sum, new_sum, len_left); } else if (nxthdr == IPPROTO_UDP) { - iov_len = udp_packet(out, pos + 2, (const struct udphdr *) next_header, old_sum, new_sum, + iov_len = udp_packet(out, pos + 1, (const struct udphdr *) next_header, old_sum, new_sum, len_left); } else if (nxthdr == IPPROTO_GRE) { - iov_len = generic_packet(out, pos + 2, next_header, len_left); + iov_len = generic_packet(out, pos + 1, next_header, len_left); } else { #if CLAT_DEBUG logmsg_dbg(ANDROID_LOG_ERROR, "ip_packet/unknown protocol: %x",header->protocol); @@ -77,7 +77,6 @@ void log_bad_address(const char *fmt, const struct in6_addr *src, const struct i int ipv6_packet(clat_packet out, int pos, const char *packet, size_t len) { const struct ip6_hdr *ip6 = (struct ip6_hdr *) packet; struct iphdr *ip_targ = (struct iphdr *) out[pos].iov_base; - struct ip6_frag *frag_hdr = NULL; uint8_t protocol; const char *next_header; size_t len_left; @@ -113,6 +112,10 @@ int ipv6_packet(clat_packet out, int pos, const char *packet, size_t len) { len_left = len - sizeof(struct ip6_hdr); protocol = ip6->ip6_nxt; + if (protocol == IPPROTO_ICMPV6) { + // ICMP and ICMPv6 have different protocol numbers. + protocol = IPPROTO_ICMP; + } /* Fill in the IPv4 header. We need to do this before we translate the packet because TCP and * UDP include parts of the IP header in the checksum. Set the length to zero because we don't @@ -121,48 +124,21 @@ int ipv6_packet(clat_packet out, int pos, const char *packet, size_t len) { fill_ip_header(ip_targ, 0, protocol, ip6); out[pos].iov_len = sizeof(struct iphdr); - // If there's a Fragment header, parse it and decide what the next header is. - // Do this before calculating the pseudo-header checksum because it updates the next header value. - if (protocol == IPPROTO_FRAGMENT) { - frag_hdr = (struct ip6_frag *) next_header; - if (len_left < sizeof(*frag_hdr)) { - logmsg_dbg(ANDROID_LOG_ERROR, "ipv6_packet/too short for fragment header: %d", len); - return 0; - } - - next_header += sizeof(*frag_hdr); - len_left -= sizeof(*frag_hdr); - - protocol = parse_frag_header(frag_hdr, ip_targ); - } - - // ICMP and ICMPv6 have different protocol numbers. - if (protocol == IPPROTO_ICMPV6) { - protocol = IPPROTO_ICMP; - ip_targ->protocol = IPPROTO_ICMP; - } - - /* Calculate the pseudo-header checksum. - * Technically, the length that is used in the pseudo-header checksum is the transport layer - * length, which is not the same as len_left in the case of fragmented packets. But since - * translation does not change the transport layer length, the checksum is unaffected. - */ + // Calculate the pseudo-header checksum. old_sum = ipv6_pseudo_header_checksum(ip6, len_left, protocol); new_sum = ipv4_pseudo_header_checksum(ip_targ, len_left); - // Does not support IPv6 extension headers except Fragment. - if (frag_hdr && (frag_hdr->ip6f_offlg & IP6F_OFF_MASK)) { - iov_len = generic_packet(out, pos + 2, next_header, len_left); - } else if (protocol == IPPROTO_ICMP) { - iov_len = icmp6_packet(out, pos + 2, (const struct icmp6_hdr *) next_header, len_left); - } else if (protocol == IPPROTO_TCP) { - iov_len = tcp_packet(out, pos + 2, (const struct tcphdr *) next_header, old_sum, new_sum, + // does not support IPv6 extension headers, this will drop any packet with them + if (protocol == IPPROTO_ICMP) { + iov_len = icmp6_packet(out, pos + 1, (const struct icmp6_hdr *) next_header, len_left); + } else if (ip6->ip6_nxt == IPPROTO_TCP) { + iov_len = tcp_packet(out, pos + 1, (const struct tcphdr *) next_header, old_sum, new_sum, len_left); - } else if (protocol == IPPROTO_UDP) { - iov_len = udp_packet(out, pos + 2, (const struct udphdr *) next_header, old_sum, new_sum, + } else if (ip6->ip6_nxt == IPPROTO_UDP) { + iov_len = udp_packet(out, pos + 1, (const struct udphdr *) next_header, old_sum, new_sum, len_left); - } else if (protocol == IPPROTO_GRE) { - iov_len = generic_packet(out, pos + 2, next_header, len_left); + } else if (ip6->ip6_nxt == IPPROTO_GRE) { + iov_len = generic_packet(out, pos + 1, next_header, len_left); } else { #if CLAT_DEBUG logmsg(ANDROID_LOG_ERROR, "ipv6_packet/unknown next header type: %x", ip6->ip6_nxt); diff --git a/translate.c b/translate.c index 7585092..f7f09cb 100644 --- a/translate.c +++ b/translate.c @@ -167,53 +167,6 @@ void fill_ip6_header(struct ip6_hdr *ip6, uint16_t payload_len, uint8_t protocol ip6->ip6_dst = ipv4_addr_to_ipv6_addr(old_header->daddr); } -/* function: maybe_fill_frag_header - * fills a fragmentation header - * generate an ipv6 fragment header from an ipv4 header - * frag_hdr - target (ipv6) fragmentation header - * ip6_targ - target (ipv6) header - * old_header - (ipv4) source packet header - * returns: the length of the fragmentation header if present, or zero if not present - */ -size_t maybe_fill_frag_header(struct ip6_frag *frag_hdr, struct ip6_hdr *ip6_targ, - const struct iphdr *old_header) { - uint16_t frag_flags = ntohs(old_header->frag_off); - uint16_t frag_off = frag_flags & IP_OFFMASK; - if (frag_off == 0 && (frag_flags & IP_MF) == 0) { - // Not a fragment. - return 0; - } - - frag_hdr->ip6f_nxt = ip6_targ->ip6_nxt; - frag_hdr->ip6f_reserved = 0; - // In IPv4, the offset is the bottom 13 bits; in IPv6 it's the top 13 bits. - frag_hdr->ip6f_offlg = htons(frag_off << 3); - if (frag_flags & IP_MF) { - frag_hdr->ip6f_offlg |= IP6F_MORE_FRAG; - } - frag_hdr->ip6f_ident = htonl(ntohs(old_header->id)); - ip6_targ->ip6_nxt = IPPROTO_FRAGMENT; - - return sizeof(*frag_hdr); -} - -/* function: parse_frag_header - * return the length of the fragmentation header if present, or zero if not present - * generate an ipv6 fragment header from an ipv4 header - * frag_hdr - (ipv6) fragmentation header - * ip_targ - target (ipv4) header - * returns: the next header value - */ -uint8_t parse_frag_header(const struct ip6_frag *frag_hdr, struct iphdr *ip_targ) { - uint16_t frag_off = (ntohs(frag_hdr->ip6f_offlg & IP6F_OFF_MASK) >> 3); - if (frag_hdr->ip6f_offlg & IP6F_MORE_FRAG) { - frag_off |= IP_MF; - } - ip_targ->frag_off = htons(frag_off); - ip_targ->id = htons(ntohl(frag_hdr->ip6f_ident) & 0xffff); - ip_targ->protocol = frag_hdr->ip6f_nxt; - return frag_hdr->ip6f_nxt; -} /* function: icmp_to_icmp6 * translate ipv4 icmp to ipv6 icmp @@ -440,6 +393,9 @@ int udp_translate(clat_packet out, int pos, const struct udphdr *udp, uint32_t o * payload - tcp payload * payload_size - size of payload * returns: the highest position in the output clat_packet that's filled in + * + * TODO: mss rewrite + * TODO: hosts without pmtu discovery - non DF packets will rely on fragmentation (unimplemented) */ int tcp_translate(clat_packet out, int pos, const struct tcphdr *tcp, size_t header_size, uint32_t old_sum, uint32_t new_sum, const char *payload, size_t payload_size) { @@ -479,20 +435,16 @@ void translate_packet(const struct tun_data *tunnel, struct tun_pi *tun_header, // Allocate buffers for all packet headers. struct tun_pi tun_targ; char iphdr[sizeof(struct ip6_hdr)]; - char fraghdr[sizeof(struct ip6_frag)]; char transporthdr[MAX_TCP_HDR]; char icmp_iphdr[sizeof(struct ip6_hdr)]; - char icmp_fraghdr[sizeof(struct ip6_frag)]; char icmp_transporthdr[MAX_TCP_HDR]; // iovec of the packets we'll send. This gets passed down to the translation functions. clat_packet out = { { &tun_targ, sizeof(tun_targ) }, // Tunnel header. { iphdr, 0 }, // IP header. - { fraghdr, 0 }, // Fragment header. { transporthdr, 0 }, // Transport layer header. { icmp_iphdr, 0 }, // ICMP error inner IP header. - { icmp_fraghdr, 0 }, // ICMP error fragmentation header. { icmp_transporthdr, 0 }, // ICMP error transport layer header. { NULL, 0 }, // Payload. No buffer, it's a pointer to the original payload. }; diff --git a/translate.h b/translate.h index 5efa817..3378254 100644 --- a/translate.h +++ b/translate.h @@ -36,11 +36,9 @@ // The CLAT_POS_XXX constants represent the array indices within the clat_packet that contain // specific parts of the packet. The packet_* functions operate on all the packet segments past a // given position. -enum clat_packet_index { - CLAT_POS_TUNHDR, CLAT_POS_IPHDR, CLAT_POS_FRAGHDR, CLAT_POS_TRANSPORTHDR, - CLAT_POS_ICMPERR_IPHDR, CLAT_POS_ICMPERR_FRAGHDR, CLAT_POS_ICMPERR_TRANSPORTHDR, - CLAT_POS_PAYLOAD, CLAT_POS_MAX -}; +enum clat_packet_index { CLAT_POS_TUNHDR, CLAT_POS_IPHDR, CLAT_POS_TRANSPORTHDR, + CLAT_POS_ICMPERR_IPHDR, CLAT_POS_ICMPERR_TRANSPORTHDR, + CLAT_POS_PAYLOAD, CLAT_POS_MAX }; typedef struct iovec clat_packet[CLAT_POS_MAX]; // Calculates the checksum over all the packet components starting from pos. @@ -67,11 +65,6 @@ void translate_packet(const struct tun_data *tunnel, struct tun_pi *tun_header, int ipv4_packet(clat_packet out, int pos, const char *packet, size_t len); int ipv6_packet(clat_packet out, int pos, const char *packet, size_t len); -// Deal with fragmented packets. -size_t maybe_fill_frag_header(struct ip6_frag *frag_hdr, struct ip6_hdr *ip6_targ, - const struct iphdr *old_header); -uint8_t parse_frag_header(const struct ip6_frag *frag_hdr, struct iphdr *ip_targ); - // Translate ICMP packets. int icmp_to_icmp6(clat_packet out, int pos, const struct icmphdr *icmp, uint32_t checksum, const char *payload, size_t payload_size); |