diff options
Diffstat (limited to 'translate.c')
-rw-r--r-- | translate.c | 77 |
1 files changed, 37 insertions, 40 deletions
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); } |