diff options
author | Lorenzo Colitti <lorenzo@google.com> | 2013-04-08 19:12:43 +0900 |
---|---|---|
committer | Lorenzo Colitti <lorenzo@google.com> | 2013-04-12 09:59:11 +0900 |
commit | 5cc877d4fc20d66ca5a057a3dc445adb998409bd (patch) | |
tree | 04c07f58d75f425022269f6a441e59fa890f5729 | |
parent | f913fe49272286a7f1e58d94a208b6dc06a51fd2 (diff) | |
download | android_external_android-clat-5cc877d4fc20d66ca5a057a3dc445adb998409bd.tar.gz android_external_android-clat-5cc877d4fc20d66ca5a057a3dc445adb998409bd.tar.bz2 android_external_android-clat-5cc877d4fc20d66ca5a057a3dc445adb998409bd.zip |
Treat the options as part of the TCP header.
This simplifies the code and makes UDP and TCP look the same. It
will also make it easier to implement nested translation in the
future because there will only be one iovec array entry for the
transport layer header, regardless of whether we are translating
UDP or TCP and regardless of the presence of options.
Also get rid of a couple of memcpy statements by pointing to the
original data instead.
Bug: 8276725
Change-Id: I6a702aefdf3a070eedfc6f7d3ebec21880ecc22b
-rw-r--r-- | ipv4.c | 30 | ||||
-rw-r--r-- | ipv6.c | 30 | ||||
-rw-r--r-- | translate.c | 77 | ||||
-rw-r--r-- | translate.h | 6 |
4 files changed, 61 insertions, 82 deletions
@@ -64,40 +64,30 @@ void icmp_packet(int fd, const char *packet, size_t len, struct iphdr *ip) { * ip - ip header */ void tcp_packet(int fd, const char *packet, size_t len, struct iphdr *ip) { - struct tcphdr tcp; + const struct tcphdr *tcp = (const struct tcphdr *) packet; const char *payload; - const char *options; - size_t payload_size, options_size; + size_t payload_size, header_size; if(len < sizeof(tcp)) { logmsg_dbg(ANDROID_LOG_ERROR,"tcp_packet/(too small)"); return; } - memcpy(&tcp, packet, sizeof(tcp)); - - if(tcp.doff < 5) { - logmsg_dbg(ANDROID_LOG_ERROR,"tcp_packet/tcp header length set to less than 5: %x",tcp.doff); + if(tcp->doff < 5) { + logmsg_dbg(ANDROID_LOG_ERROR,"tcp_packet/tcp header length set to less than 5: %x", tcp->doff); return; } - if((size_t)tcp.doff*4 > len) { - logmsg_dbg(ANDROID_LOG_ERROR,"tcp_packet/tcp header length set too large: %x",tcp.doff); + if((size_t) tcp->doff*4 > len) { + logmsg_dbg(ANDROID_LOG_ERROR,"tcp_packet/tcp header length set too large: %x", tcp->doff); return; } - if(tcp.doff > 5) { - options = packet + sizeof(tcp); - options_size = tcp.doff*4 - sizeof(tcp); - } else { - options = NULL; - options_size = 0; - } - - payload = packet + tcp.doff*4; - payload_size = len - tcp.doff*4; + header_size = tcp->doff * 4; + payload = packet + header_size; + payload_size = len - header_size; - tcp_to_tcp6(fd,ip,&tcp,payload,payload_size,options,options_size); + tcp_to_tcp6(fd, ip, tcp, header_size, payload, payload_size); } /* function: udp_packet @@ -66,40 +66,30 @@ void icmp6_packet(int fd, const char *packet, size_t len, struct ip6_hdr *ip6) { * ip6 - ip6 header */ void tcp6_packet(int fd, const char *packet, size_t len, struct ip6_hdr *ip6) { - struct tcphdr tcp; + const struct tcphdr *tcp = (const struct tcphdr *) packet; const char *payload; - const char *options; - size_t payload_size, options_size; + size_t payload_size, header_size; if(len < sizeof(tcp)) { logmsg_dbg(ANDROID_LOG_ERROR,"tcp6_packet/(too small)"); return; } - memcpy(&tcp, packet, sizeof(tcp)); - - if(tcp.doff < 5) { - logmsg_dbg(ANDROID_LOG_ERROR,"tcp6_packet/tcp header length set to less than 5: %x",tcp.doff); + if(tcp->doff < 5) { + logmsg_dbg(ANDROID_LOG_ERROR,"tcp6_packet/tcp header length set to less than 5: %x", tcp->doff); return; } - if((size_t)tcp.doff*4 > len) { - logmsg_dbg(ANDROID_LOG_ERROR,"tcp6_packet/tcp header length set too large: %x",tcp.doff); + if((size_t) tcp->doff*4 > len) { + logmsg_dbg(ANDROID_LOG_ERROR,"tcp6_packet/tcp header length set too large: %x", tcp->doff); return; } - if(tcp.doff > 5) { - options = packet + sizeof(tcp); - options_size = tcp.doff*4 - sizeof(tcp); - } else { - options = NULL; - options_size = 0; - } - - payload = packet + tcp.doff*4; - payload_size = len - tcp.doff*4; + header_size = tcp->doff * 4; + payload = packet + header_size; + payload_size = len - header_size; - tcp6_to_tcp(fd,ip6,&tcp,payload,payload_size,options,options_size); + tcp6_to_tcp(fd, ip6, tcp, header_size, payload, payload_size); } /* function: udp6_packet diff --git a/translate.c b/translate.c index 89a7e7b..936c781 100644 --- a/translate.c +++ b/translate.c @@ -303,44 +303,41 @@ void udp6_to_udp(int fd, const struct ip6_hdr *ip6, const struct udphdr *udp, co * array position 0 - tun header * array position 1 - ipv4/ipv6 header * array position 2 - empty (will be tcp header) - * array position 3 - empty (will be tcp options or payload) - * array position 4 - empty (can be payload) + * array position 3 - empty (will be payload) * checksum - partial checksum covering ipv4/ipv6 header - * options - pointer to tcp option buffer - * options_size - size of tcp option buffer * * TODO: mss rewrite * TODO: hosts without pmtu discovery - non DF packets will rely on fragmentation (unimplemented) */ -void tcp_translate(int fd, const struct tcphdr *tcp, const char *payload, size_t payload_size, struct iovec *io_targ, uint32_t checksum, const char *options, size_t options_size) { - struct tcphdr tcp_targ; - int targ_index = 2; - - memcpy(&tcp_targ, tcp, sizeof(tcp_targ)); - tcp_targ.check = 0; - - checksum = ip_checksum_add(checksum, &tcp_targ, sizeof(tcp_targ)); - if(options) { - checksum = ip_checksum_add(checksum, options, options_size); +void tcp_translate(int fd, const struct tcphdr *tcp, size_t header_size, const char *payload, + size_t payload_size, struct iovec *io_targ, uint32_t checksum) { + union { + // Reserve space for the maximum size of the TCP header, including options. The TCP header + // length field is 4 bits long and counts 4-byte words, so it can be at most 60 bytes. + char buf[15 * 4]; + struct tcphdr tcp; + } header; + + if (header_size > sizeof(header.buf)) { + // A TCP header cannot be more than 60 bytes long, so this can never happen unless there is a + // bug in the caller. + logmsg(ANDROID_LOG_ERROR, "tcp_translate: header too long %d > %d, truncating", + header_size, sizeof(header.buf)); + header_size = sizeof(header.buf); } - checksum = ip_checksum_add(checksum, payload, payload_size); - tcp_targ.check = ip_checksum_finish(checksum); - io_targ[targ_index].iov_base = &tcp_targ; - io_targ[targ_index].iov_len = sizeof(tcp_targ); - targ_index++; + memcpy(&header, tcp, header_size); - if(options) { - io_targ[targ_index].iov_base = (char *)options; - io_targ[targ_index].iov_len = options_size; - targ_index++; - } + header.tcp.check = 0; + checksum = ip_checksum_add(checksum, &header, header_size); + checksum = ip_checksum_add(checksum, payload, payload_size); + header.tcp.check = ip_checksum_finish(checksum); - io_targ[targ_index].iov_base = (char *)payload; - io_targ[targ_index].iov_len = payload_size; - targ_index++; + io_targ[2].iov_base = &header; + io_targ[2].iov_len = header_size; - writev(fd, io_targ, targ_index); + io_targ[3].iov_base = (char *)payload; + io_targ[3].iov_len = payload_size; } /* function: tcp_to_tcp6 @@ -348,12 +345,12 @@ void tcp_translate(int fd, const struct tcphdr *tcp, const char *payload, size_t * fd - tun interface fd * ip - source packet ipv4 header * tcp - source packet tcp header + * header_size - size of tcp header including options * payload - tcp payload * payload_size - size of payload - * options - tcp options - * options_size - size of options */ -void tcp_to_tcp6(int fd,const struct iphdr *ip, const struct tcphdr *tcp, const char *payload, size_t payload_size, const char *options, size_t options_size) { +void tcp_to_tcp6(int fd, const struct iphdr *ip, const struct tcphdr *tcp, size_t header_size, + const char *payload, size_t payload_size) { struct ip6_hdr ip6_targ; struct iovec io_targ[5]; struct tun_pi tun_header; @@ -361,16 +358,16 @@ void tcp_to_tcp6(int fd,const struct iphdr *ip, const struct tcphdr *tcp, const fill_tun_header(&tun_header,ETH_P_IPV6); - fill_ip6_header(&ip6_targ,payload_size+options_size+sizeof(struct tcphdr),IPPROTO_TCP,ip); + fill_ip6_header(&ip6_targ, header_size + payload_size, IPPROTO_TCP, ip); - checksum = ipv6_pseudo_header_checksum(0, &ip6_targ, sizeof(*tcp) + options_size + payload_size); + checksum = ipv6_pseudo_header_checksum(0, &ip6_targ, header_size + payload_size); io_targ[0].iov_base = &tun_header; io_targ[0].iov_len = sizeof(tun_header); io_targ[1].iov_base = &ip6_targ; io_targ[1].iov_len = sizeof(ip6_targ); - tcp_translate(fd,tcp,payload,payload_size,io_targ,checksum,options,options_size); + tcp_translate(fd, tcp, header_size, payload, payload_size, io_targ, checksum); } /* function: tcp6_to_tcp @@ -378,12 +375,12 @@ void tcp_to_tcp6(int fd,const struct iphdr *ip, const struct tcphdr *tcp, const * fd - tun interface fd * ip6 - source packet ipv6 header * tcp - source packet tcp header + * header_size - size of tcp header including options * payload - tcp payload * payload_size - size of payload - * options - tcp options - * options_size - size of options */ -void tcp6_to_tcp(int fd,const struct ip6_hdr *ip6, const struct tcphdr *tcp, const char *payload, size_t payload_size, const char *options, size_t options_size) { +void tcp6_to_tcp(int fd, const struct ip6_hdr *ip6, const struct tcphdr *tcp, size_t header_size, + const char *payload, size_t payload_size) { struct iphdr ip_targ; struct iovec io_targ[5]; struct tun_pi tun_header; @@ -391,14 +388,14 @@ void tcp6_to_tcp(int fd,const struct ip6_hdr *ip6, const struct tcphdr *tcp, con fill_tun_header(&tun_header,ETH_P_IP); - fill_ip_header(&ip_targ,payload_size+options_size+sizeof(struct tcphdr),IPPROTO_TCP,ip6); + fill_ip_header(&ip_targ, header_size + payload_size, IPPROTO_TCP, ip6); - checksum = ipv4_pseudo_header_checksum(0, &ip_targ, sizeof(*tcp) + payload_size + options_size); + checksum = ipv4_pseudo_header_checksum(0, &ip_targ, header_size + payload_size); io_targ[0].iov_base = &tun_header; io_targ[0].iov_len = sizeof(tun_header); io_targ[1].iov_base = &ip_targ; io_targ[1].iov_len = sizeof(ip_targ); - tcp_translate(fd,tcp,payload,payload_size,io_targ,checksum,options,options_size); + tcp_translate(fd, tcp, header_size, payload, payload_size, io_targ, checksum); } diff --git a/translate.h b/translate.h index 6fc3c79..641768e 100644 --- a/translate.h +++ b/translate.h @@ -24,7 +24,9 @@ void icmp6_to_icmp(int fd, const struct ip6_hdr *ip6, const struct icmp6_hdr *ic void udp_to_udp6(int fd, const struct iphdr *ip, const struct udphdr *udp, const char *payload, size_t payload_size); void udp6_to_udp(int fd, const struct ip6_hdr *ip6, const struct udphdr *udp, const char *payload, size_t payload_size); -void tcp_to_tcp6(int fd,const struct iphdr *ip, const struct tcphdr *tcp, const char *payload, size_t payload_size, const char *options, size_t options_size); -void tcp6_to_tcp(int fd,const struct ip6_hdr *ip6, const struct tcphdr *tcp, const char *payload, size_t payload_size, const char *options, size_t options_size); +void tcp_to_tcp6(int fd,const struct iphdr *ip, const struct tcphdr *tcp, size_t header_size, + const char *payload, size_t payload_size); +void tcp6_to_tcp(int fd,const struct ip6_hdr *ip6, const struct tcphdr *tcp, size_t header_size, + const char *payload, size_t payload_size); #endif /* __TRANSLATE_H__ */ |