diff options
author | David Gibson <david@gibson.dropbear.id.au> | 2024-05-01 16:53:48 +1000 |
---|---|---|
committer | Stefano Brivio <sbrivio@redhat.com> | 2024-05-02 16:13:21 +0200 |
commit | 9e22c53aa92552bd5c015c2597512056f8def4d8 (patch) | |
tree | b4068984c67af419bbeaf6aad34c9d6921b5d034 | |
parent | 1095a7b0c9a150cb488ff5bd5fd74c897dd9236e (diff) | |
download | passt-9e22c53aa92552bd5c015c2597512056f8def4d8.tar passt-9e22c53aa92552bd5c015c2597512056f8def4d8.tar.gz passt-9e22c53aa92552bd5c015c2597512056f8def4d8.tar.bz2 passt-9e22c53aa92552bd5c015c2597512056f8def4d8.tar.lz passt-9e22c53aa92552bd5c015c2597512056f8def4d8.tar.xz passt-9e22c53aa92552bd5c015c2597512056f8def4d8.tar.zst passt-9e22c53aa92552bd5c015c2597512056f8def4d8.zip |
checksum: Make csum_ip4_header() take a host endian length
csum_ip4_header() takes the packet length as a network endian value. In
general it's very error-prone to pass non-native-endian values as a raw
integer. It's particularly bad here because this differs from other
checksum functions (e.g. proto_ipv4_header_psum()) which take host native
lengths.
It turns out all the callers have easy access to the native endian value,
so switch it to use host order like everything else.
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
-rw-r--r-- | checksum.c | 4 | ||||
-rw-r--r-- | tap.c | 6 | ||||
-rw-r--r-- | tcp.c | 2 | ||||
-rw-r--r-- | udp.c | 2 |
4 files changed, 8 insertions, 6 deletions
@@ -116,7 +116,7 @@ uint16_t csum_fold(uint32_t sum) /** * csum_ip4_header() - Calculate IPv4 header checksum - * @tot_len: IPv4 payload length (data + IP header, network order) + * @tot_len: IPv4 packet length (data + IP header, host order) * @protocol: Protocol number * @saddr: IPv4 source address * @daddr: IPv4 destination address @@ -128,7 +128,7 @@ uint16_t csum_ip4_header(uint16_t tot_len, uint8_t protocol, { uint32_t sum = L2_BUF_IP4_PSUM(protocol); - sum += tot_len; + sum += htons(tot_len); sum += (saddr.s_addr >> 16) & 0xffff; sum += saddr.s_addr & 0xffff; sum += (daddr.s_addr >> 16) & 0xffff; @@ -149,17 +149,19 @@ static void *tap_push_l2h(const struct ctx *c, void *buf, uint16_t proto) static void *tap_push_ip4h(struct iphdr *ip4h, struct in_addr src, struct in_addr dst, size_t len, uint8_t proto) { + uint16_t tot_len = len + sizeof(*ip4h); + ip4h->version = 4; ip4h->ihl = sizeof(struct iphdr) / 4; ip4h->tos = 0; - ip4h->tot_len = htons(len + sizeof(*ip4h)); + ip4h->tot_len = htons(tot_len); ip4h->id = 0; ip4h->frag_off = 0; ip4h->ttl = 255; ip4h->protocol = proto; ip4h->saddr = src.s_addr; ip4h->daddr = dst.s_addr; - ip4h->check = csum_ip4_header(ip4h->tot_len, proto, src, dst); + ip4h->check = csum_ip4_header(tot_len, proto, src, dst); return ip4h + 1; } @@ -1359,7 +1359,7 @@ static size_t tcp_fill_headers4(const struct ctx *c, iph->daddr = c->ip4.addr_seen.s_addr; iph->check = check ? *check : - csum_ip4_header(iph->tot_len, IPPROTO_TCP, + csum_ip4_header(ip_len, IPPROTO_TCP, *a4, c->ip4.addr_seen); tcp_fill_header(th, conn, seq); @@ -605,7 +605,7 @@ static size_t udp_update_hdr4(const struct ctx *c, struct udp4_l2_buf_t *b, b->iph.tot_len = htons(ip_len); b->iph.daddr = c->ip4.addr_seen.s_addr; b->iph.saddr = src.s_addr; - b->iph.check = csum_ip4_header(b->iph.tot_len, IPPROTO_UDP, + b->iph.check = csum_ip4_header(ip_len, IPPROTO_UDP, src, c->ip4.addr_seen); b->uh.source = b->s_in.sin_port; |