diff --git a/mongoose.c b/mongoose.c index 5352bca4..cd763321 100644 --- a/mongoose.c +++ b/mongoose.c @@ -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, diff --git a/src/net_builtin.c b/src/net_builtin.c index f6af5202..2563f37d 100644 --- a/src/net_builtin.c +++ b/src/net_builtin.c @@ -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, diff --git a/test/mip_test.c b/test/mip_test.c index f7d1a49a..263f6362 100644 --- a/test/mip_test.c +++ b/test/mip_test.c @@ -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));