mirror of
https://github.com/cesanta/mongoose.git
synced 2026-10-25 12:04:47 +00:00
account for extension headers in IPv6 transported protocols checksums
This commit is contained in:
1 parent
3fde04137c
commit
cd05b162a8
3 files changed
+50
-42
No files matched your search
+21
-17
@@ -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
@@ -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
@@ -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));
|
||||
|
||||
Reference in new issue
Block a user