diff options
-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__ */ |