account for extension headers in IPv6 transported protocols checksums

This commit is contained in:
Sergio R. Caprile committed 2026-09-01 21:33:48 -03:00
1 parent 3fde04137c
commit cd05b162a8
3 files changed
+50 -42

No files matched your search

+21 -17
View File
@@ -8543,7 +8543,7 @@ static bool tcpcsum_ok(void *d, void *t) {
}
#if MG_ENABLE_IPV6
static uint16_t p6csum(void *d, void *p, size_t plen) {
static uint16_t p6csum(void *d, void *p, uint8_t proto, size_t plen) {
uint32_t sum;
struct ip6 *ip6 = (struct ip6 *) d;
#if defined(__DCC__)
@@ -8554,7 +8554,7 @@ static uint16_t p6csum(void *d, void *p, size_t plen) {
pip6.dst[0] = ip6->dst[0], pip6.dst[1] = ip6->dst[1];
pip6.zero[0] = 0, pip6.zero[1] = 0, pip6.zero[2] = 0;
pip6.plen = mg_htonl((uint32_t) plen);
pip6.next = ip6->next;
pip6.next = proto;
sum = csumup(0, &pip6, sizeof(pip6)); // even length
sum = csumup(sum, p, plen); // possibly odd length: last
return csumfin(sum);
@@ -8564,17 +8564,15 @@ static bool udp6csum_ok(void *d, void *u) {
struct udp *udp = (struct udp *) u;
if (udp->csum == 0) return false; // mandatory in IPv6
if (udp->csum == 0xFFFF) udp->csum = 0;
return (p6csum(d, u, (size_t) mg_ntohs(udp->len)) == 0);
return (p6csum(d, u, 17, (size_t) mg_ntohs(udp->len)) == 0);
}
static bool tcp6csum_ok(void *d, void *t) {
struct ip6 *ip6 = (struct ip6 *) d;
return (p6csum(d, t, (size_t) mg_ntohs(ip6->plen)) == 0);
}
static bool icmp6csum_ok(void *d, void *i) {
struct ip6 *ip6 = (struct ip6 *) d;
return (p6csum(d, i, (size_t) mg_ntohs(ip6->plen)) == 0);
static bool tcp6csum_ok(void *d, void *t, size_t len) {
return p6csum(d, t, 6, len) == 0;
}
static bool icmp6csum_ok(void *d, void *i, size_t len) {
return p6csum(d, i, 58, len) == 0;
}
static void ip6sn(uint64_t *addr, uint64_t *sn_addr) {
// Build solicited-node multicast address from a given unicast IP
// RFC-4291 2.7
@@ -8719,7 +8717,7 @@ static bool tx_udp(struct mg_tcpip_if *ifp, uint8_t *l2_dst,
memmove(udp + 1, buf, len);
#if MG_ENABLE_IPV6
if (ip_dst->is_ip6) {
udp->csum = p6csum(ip6, udp, sizeof(*udp) + len);
udp->csum = p6csum(ip6, udp, 17, sizeof(*udp) + len);
} else
#endif
{
@@ -9067,7 +9065,7 @@ static void tx_icmp6(struct mg_tcpip_if *ifp, uint8_t *l2_dst, uint64_t *ip_src,
icmp6->code = code;
memcpy(icmp6 + 1, buf, len); // Copy payload
icmp6->csum = 0; // RFC-4443 2.3, RFC-8200 8.1
icmp6->csum = p6csum(ip6, icmp6, sizeof(*icmp6) + len);
icmp6->csum = p6csum(ip6, icmp6, 58, sizeof(*icmp6) + len);
driver_output(ifp,
mg_l2_trailer(ifp, sizeof(*ip6) + sizeof(*icmp6) + len,
(uint8_t *) (ip6 + 1) + sizeof(*icmp6) + len));
@@ -9306,7 +9304,8 @@ static void rx_ndp_ra(struct mg_tcpip_if *ifp, struct pkt *pkt) {
}
static void rx_icmp6(struct mg_tcpip_if *ifp, struct pkt *pkt) {
if (!icmp6csum_ok(pkt->ip6, pkt->icmp6)) return;
if (!icmp6csum_ok(pkt->ip6, pkt->icmp6, sizeof(*pkt->icmp6) + pkt->pay.len))
return;
switch (pkt->icmp6->type) {
case 128: { // Echo Request, RFC-4443 4.1
uint64_t target[2];
@@ -9511,7 +9510,7 @@ static size_t tx_tcp(struct mg_tcpip_if *ifp, uint8_t *l2_dst,
tcp->off = (uint8_t) (hlen / 4 << 4);
#if MG_ENABLE_IPV6
if (ip_dst->is_ip6) {
tcp->csum = p6csum(ip6, tcp, hlen + len);
tcp->csum = p6csum(ip6, tcp, 6, hlen + len);
} else
#endif
{
@@ -9881,7 +9880,10 @@ static void rx_tcp(struct mg_tcpip_if *ifp, struct pkt *pkt) {
struct mg_connection *c = getpeer(ifp->mgr, pkt, false);
struct connstate *s = c == NULL ? NULL : (struct connstate *) (c + 1);
#if MG_ENABLE_IPV6 // matching of v4/v6 to dest is done by getpeer()
if (pkt->ip6 != NULL && !tcp6csum_ok(pkt->ip6, pkt->tcp)) return;
if (pkt->ip6 != NULL &&
!tcp6csum_ok(pkt->ip6, pkt->tcp,
PDIFF(pkt->tcp, pkt->pay.buf) + pkt->pay.len))
return;
#endif
if (pkt->ip != NULL && !tcpcsum_ok(pkt->ip, pkt->tcp)) return;
pkt->tcp->flags &= TH_STDFLAGS; // tolerate creative usage (ECN, ?)
@@ -10016,7 +10018,8 @@ static void rx_ip(struct mg_tcpip_if *ifp, struct pkt *pkt) {
pkt->tcp = (struct tcp *) (pkt->pay.buf);
if (pkt->pay.len < sizeof(*pkt->tcp)) return;
off = pkt->tcp->off >> 4; // account for opts
if (pkt->pay.len < (uint16_t) (4 * off)) return;
if (off < sizeof(*pkt->tcp) / 4 || pkt->pay.len < (uint16_t) (4 * off))
return;
mkpay(pkt, (uint32_t *) pkt->tcp + off);
MG_VERBOSE(("TCP %M:%hu -> %M:%hu len %u", mg_print_ip4, &pkt->ip->src,
mg_ntohs(pkt->tcp->sport), mg_print_ip4, &pkt->ip->dst,
@@ -10112,7 +10115,8 @@ static void rx_ip6(struct mg_tcpip_if *ifp, struct pkt *pkt) {
pkt->tcp = (struct tcp *) (pkt->pay.buf);
if (pkt->pay.len < sizeof(*pkt->tcp)) return;
off = pkt->tcp->off >> 4; // account for opts
if (pkt->pay.len < (uint16_t) (4 * off)) return;
if (off < sizeof(*pkt->tcp) / 4 || pkt->pay.len < (uint16_t) (4 * off))
return;
mkpay(pkt, (uint32_t *) pkt->tcp + off);
MG_DEBUG(("TCP %M:%hu -> %M:%hu len %u", mg_print_ip6, &pkt->ip6->src,
mg_ntohs(pkt->tcp->sport), mg_print_ip6, &pkt->ip6->dst,
+21 -17
View File
@@ -292,7 +292,7 @@ static bool tcpcsum_ok(void *d, void *t) {
}
#if MG_ENABLE_IPV6
static uint16_t p6csum(void *d, void *p, size_t plen) {
static uint16_t p6csum(void *d, void *p, uint8_t proto, size_t plen) {
uint32_t sum;
struct ip6 *ip6 = (struct ip6 *) d;
#if defined(__DCC__)
@@ -303,7 +303,7 @@ static uint16_t p6csum(void *d, void *p, size_t plen) {
pip6.dst[0] = ip6->dst[0], pip6.dst[1] = ip6->dst[1];
pip6.zero[0] = 0, pip6.zero[1] = 0, pip6.zero[2] = 0;
pip6.plen = mg_htonl((uint32_t) plen);
pip6.next = ip6->next;
pip6.next = proto;
sum = csumup(0, &pip6, sizeof(pip6)); // even length
sum = csumup(sum, p, plen); // possibly odd length: last
return csumfin(sum);
@@ -313,17 +313,15 @@ static bool udp6csum_ok(void *d, void *u) {
struct udp *udp = (struct udp *) u;
if (udp->csum == 0) return false; // mandatory in IPv6
if (udp->csum == 0xFFFF) udp->csum = 0;
return (p6csum(d, u, (size_t) mg_ntohs(udp->len)) == 0);
return (p6csum(d, u, 17, (size_t) mg_ntohs(udp->len)) == 0);
}
static bool tcp6csum_ok(void *d, void *t) {
struct ip6 *ip6 = (struct ip6 *) d;
return (p6csum(d, t, (size_t) mg_ntohs(ip6->plen)) == 0);
}
static bool icmp6csum_ok(void *d, void *i) {
struct ip6 *ip6 = (struct ip6 *) d;
return (p6csum(d, i, (size_t) mg_ntohs(ip6->plen)) == 0);
static bool tcp6csum_ok(void *d, void *t, size_t len) {
return p6csum(d, t, 6, len) == 0;
}
static bool icmp6csum_ok(void *d, void *i, size_t len) {
return p6csum(d, i, 58, len) == 0;
}
static void ip6sn(uint64_t *addr, uint64_t *sn_addr) {
// Build solicited-node multicast address from a given unicast IP
// RFC-4291 2.7
@@ -468,7 +466,7 @@ static bool tx_udp(struct mg_tcpip_if *ifp, uint8_t *l2_dst,
memmove(udp + 1, buf, len);
#if MG_ENABLE_IPV6
if (ip_dst->is_ip6) {
udp->csum = p6csum(ip6, udp, sizeof(*udp) + len);
udp->csum = p6csum(ip6, udp, 17, sizeof(*udp) + len);
} else
#endif
{
@@ -816,7 +814,7 @@ static void tx_icmp6(struct mg_tcpip_if *ifp, uint8_t *l2_dst, uint64_t *ip_src,
icmp6->code = code;
memcpy(icmp6 + 1, buf, len); // Copy payload
icmp6->csum = 0; // RFC-4443 2.3, RFC-8200 8.1
icmp6->csum = p6csum(ip6, icmp6, sizeof(*icmp6) + len);
icmp6->csum = p6csum(ip6, icmp6, 58, sizeof(*icmp6) + len);
driver_output(ifp,
mg_l2_trailer(ifp, sizeof(*ip6) + sizeof(*icmp6) + len,
(uint8_t *) (ip6 + 1) + sizeof(*icmp6) + len));
@@ -1055,7 +1053,8 @@ static void rx_ndp_ra(struct mg_tcpip_if *ifp, struct pkt *pkt) {
}
static void rx_icmp6(struct mg_tcpip_if *ifp, struct pkt *pkt) {
if (!icmp6csum_ok(pkt->ip6, pkt->icmp6)) return;
if (!icmp6csum_ok(pkt->ip6, pkt->icmp6, sizeof(*pkt->icmp6) + pkt->pay.len))
return;
switch (pkt->icmp6->type) {
case 128: { // Echo Request, RFC-4443 4.1
uint64_t target[2];
@@ -1260,7 +1259,7 @@ static size_t tx_tcp(struct mg_tcpip_if *ifp, uint8_t *l2_dst,
tcp->off = (uint8_t) (hlen / 4 << 4);
#if MG_ENABLE_IPV6
if (ip_dst->is_ip6) {
tcp->csum = p6csum(ip6, tcp, hlen + len);
tcp->csum = p6csum(ip6, tcp, 6, hlen + len);
} else
#endif
{
@@ -1630,7 +1629,10 @@ static void rx_tcp(struct mg_tcpip_if *ifp, struct pkt *pkt) {
struct mg_connection *c = getpeer(ifp->mgr, pkt, false);
struct connstate *s = c == NULL ? NULL : (struct connstate *) (c + 1);
#if MG_ENABLE_IPV6 // matching of v4/v6 to dest is done by getpeer()
if (pkt->ip6 != NULL && !tcp6csum_ok(pkt->ip6, pkt->tcp)) return;
if (pkt->ip6 != NULL &&
!tcp6csum_ok(pkt->ip6, pkt->tcp,
PDIFF(pkt->tcp, pkt->pay.buf) + pkt->pay.len))
return;
#endif
if (pkt->ip != NULL && !tcpcsum_ok(pkt->ip, pkt->tcp)) return;
pkt->tcp->flags &= TH_STDFLAGS; // tolerate creative usage (ECN, ?)
@@ -1765,7 +1767,8 @@ static void rx_ip(struct mg_tcpip_if *ifp, struct pkt *pkt) {
pkt->tcp = (struct tcp *) (pkt->pay.buf);
if (pkt->pay.len < sizeof(*pkt->tcp)) return;
off = pkt->tcp->off >> 4; // account for opts
if (pkt->pay.len < (uint16_t) (4 * off)) return;
if (off < sizeof(*pkt->tcp) / 4 || pkt->pay.len < (uint16_t) (4 * off))
return;
mkpay(pkt, (uint32_t *) pkt->tcp + off);
MG_VERBOSE(("TCP %M:%hu -> %M:%hu len %u", mg_print_ip4, &pkt->ip->src,
mg_ntohs(pkt->tcp->sport), mg_print_ip4, &pkt->ip->dst,
@@ -1861,7 +1864,8 @@ static void rx_ip6(struct mg_tcpip_if *ifp, struct pkt *pkt) {
pkt->tcp = (struct tcp *) (pkt->pay.buf);
if (pkt->pay.len < sizeof(*pkt->tcp)) return;
off = pkt->tcp->off >> 4; // account for opts
if (pkt->pay.len < (uint16_t) (4 * off)) return;
if (off < sizeof(*pkt->tcp) / 4 || pkt->pay.len < (uint16_t) (4 * off))
return;
mkpay(pkt, (uint32_t *) pkt->tcp + off);
MG_DEBUG(("TCP %M:%hu -> %M:%hu len %u", mg_print_ip6, &pkt->ip6->src,
mg_ntohs(pkt->tcp->sport), mg_print_ip6, &pkt->ip6->dst,
+8 -8
View File
@@ -57,7 +57,7 @@ static void test_csum(void) {
#if !MG_ENABLE_IPV6
#define udp6csum_ok(d, u) true
#define tcp6csum_ok(d, t) true
#define tcp6csum_ok(d, t, l) true
#endif
static bool executed = false;
@@ -269,7 +269,7 @@ static void create_tcp_seg(struct eth *e, struct ipp *ipp, uint32_t seq,
if (opts != NULL && opts_len)
memcpy(s_driver_data.buf + sizeof(*e) + sizeof(*ip) + sizeof(t), opts,
opts_len);
tcp->csum = p6csum(ip, tcp, (4 * (t.off >> 4) + payload_len));
tcp->csum = p6csum(ip, tcp, 6, (4 * (t.off >> 4) + payload_len));
s_driver_data.len =
sizeof(*e) + sizeof(*ip) + sizeof(t) + payload_len + opts_len;
} else
@@ -431,7 +431,7 @@ static void test_tcp_basics(bool ipv6) {
if (ipv6) {
ASSERT(i6->src[0] == mg_htonll(0x100000000000000) && i6->src[1] == 0 &&
i6->dst[0] == mg_htonll(0x200000000000000) && i6->dst[1] == 0);
ASSERT(tcp6csum_ok(i6, t));
ASSERT(tcp6csum_ok(i6, t, mg_ntohs(i6->plen)));
} else {
ASSERT(i->src == mg_htonl(0x1000000) && i->dst == mg_htonl(0x2000000));
ASSERT(tcpcsum_ok(i, t));
@@ -817,7 +817,7 @@ static void test_tcp_basics(bool ipv6) {
if (ipv6) {
ASSERT(i6->src[0] == mg_htonll(0x100000000000000) && i6->src[1] == 0 &&
i6->dst[0] == mg_htonll(0x200000000000000) && i6->dst[1] == 0);
ASSERT(tcp6csum_ok(i6, t));
ASSERT(tcp6csum_ok(i6, t, mg_ntohs(i6->plen)));
} else {
ASSERT(i->src == mg_htonl(0x1000000) && i->dst == mg_htonl(0x2000000));
ASSERT(tcpcsum_ok(i, t));
@@ -1281,7 +1281,7 @@ static void create_udp_dat(struct eth *e, struct ipp *ipp, uint16_t sport,
memcpy(s_driver_data.buf + sizeof(*e), ip, sizeof(*ip));
memcpy(udp, &u, sizeof(u));
*(s_driver_data.buf + sizeof(*e) + sizeof(*ip) + sizeof(u)) = 'p';
udp->csum = p6csum(ip, udp, (sizeof(u) + payload_len));
udp->csum = p6csum(ip, udp, 17, (sizeof(u) + payload_len));
s_driver_data.len = sizeof(*e) + sizeof(*ip) + sizeof(u) + payload_len;
} else
#endif
@@ -1458,7 +1458,7 @@ static void create_icmp6_dat(struct eth *e, struct ipp *ipp, uint8_t type,
memcpy(s_driver_data.buf, e, sizeof(*e));
memcpy(s_driver_data.buf + sizeof(*e), ip6, sizeof(*ip6));
memcpy(icmp6, &i6, sizeof(i6));
icmp6->csum = p6csum(ip6, icmp6, sizeof(*icmp6) + payload_len);
icmp6->csum = p6csum(ip6, icmp6, 58, sizeof(*icmp6) + payload_len);
s_driver_data.len = sizeof(*e) + sizeof(*ip6) + sizeof(*icmp6) + payload_len;
if (s_driver_data.len < 64) s_driver_data.len = 64; // add padding if needed
}
@@ -1494,7 +1494,7 @@ static void test_icmp6_basics(void) {
ASSERT(i->plen == mg_htons(sizeof(*icmp6) + 0));
ASSERT(icmp6->type == 129); // Echo Reply
ASSERT(icmp6->code == 0);
ASSERT(icmp6csum_ok(i, icmp6));
ASSERT(icmp6csum_ok(i, icmp6, mg_ntohs(i->plen)));
create_icmp6_dat(&e, &ipp, 128, 0, NULL, 69); // Echo Request
mg_mgr_poll(&mgr, 0); // make sure we clean former stuff in buffer
@@ -1505,7 +1505,7 @@ static void test_icmp6_basics(void) {
ASSERT(i->plen == mg_htons(sizeof(*icmp6) + 69));
ASSERT(icmp6->type == 129); // Echo Reply
ASSERT(icmp6->code == 0);
ASSERT(icmp6csum_ok(i, icmp6));
ASSERT(icmp6csum_ok(i, icmp6, mg_ntohs(i->plen)));
// Neighbor Solicitation
memset(payload, 0, sizeof(payload));