diff --git a/mongoose.c b/mongoose.c index 2a16b6f5..cbe9114f 100644 --- a/mongoose.c +++ b/mongoose.c @@ -4977,6 +4977,22 @@ struct dhcp6 { uint8_t options[30 + sizeof(((struct mg_tcpip_if *) 0)->dhcp_name)]; }; +struct pseudoip { + uint32_t src; // Source IP + uint32_t dst; // Destination IP + uint8_t zero; + uint8_t proto; // Upper level protocol + uint16_t len; // Datagram length +}; + +struct pseudoip6 { + uint64_t src[2]; // Source IP + uint64_t dst[2]; // Destination IP + uint32_t plen; // Payload length + uint8_t zero[3]; + uint8_t next; // Upper level protocol +}; + #if defined(__DCC__) #pragma pack(0) #else @@ -5060,7 +5076,71 @@ static uint16_t ipcsum(const void *buf, size_t len) { return csumfin(sum); } +static bool ipcsum_ok(const void *d) { + struct ip *ip = (struct ip *) d; + return (ipcsum(d, (ip->ver & 0x0F) * 4) == 0); +} + +static bool icmpcsum_ok(const void *d, size_t len) { + return (ipcsum(d, len) == 0); +} + +static uint16_t pcsum(void *d, void *p, size_t plen) { + uint32_t sum; + struct ip *ip = (struct ip *) d; + struct pseudoip pip; + pip.src = ip->src; + pip.dst = ip->dst; + pip.zero = 0; + pip.proto = ip->proto; + pip.len = mg_htons((uint16_t) plen); + sum = csumup(0, &pip, sizeof(pip)); // even length + sum = csumup(sum, p, plen); // possibly odd length: last + return csumfin(sum); +} + +static bool udpcsum_ok(void *d, void *u) { + struct udp *udp = (struct udp *) u; + if (udp->csum == 0) return true; + if (udp->csum == 0xFFFF) udp->csum = 0; + return (pcsum(d, u, (size_t) mg_ntohs(udp->len)) == 0); +} + +static bool tcpcsum_ok(void *d, void *t) { + struct ip *ip = (struct ip *) d; + return (pcsum(d, t, (size_t)(mg_ntohs(ip->len) - (ip->ver & 0x0F) * 4)) == 0); +} + #if MG_ENABLE_IPV6 +static uint16_t p6csum(void *d, void *p, size_t plen) { + uint32_t sum; + struct ip6 *ip6 = (struct ip6 *) d; + struct pseudoip6 pip6; + pip6.src[0] = ip6->src[0], pip6.src[1] = ip6->src[1]; + 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; + sum = csumup(0, &pip6, sizeof(pip6)); // even length + sum = csumup(sum, p, plen); // possibly odd length: last + return csumfin(sum); +} + +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); +} +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 void ip6sn(uint64_t *addr, uint64_t *sn_addr) { // Build solicited-node multicast address from a given unicast IP // RFC-4291 2.7 @@ -5172,7 +5252,6 @@ static bool tx_udp(struct mg_tcpip_if *ifp, uint8_t *l2_dst, size_t l2_len; struct ip *ip = NULL; struct udp *udp; - uint32_t cs; #if MG_ENABLE_IPV6 struct ip6 *ip6 = NULL; if (ip_dst->is_ip6) { @@ -5192,28 +5271,15 @@ static bool tx_udp(struct mg_tcpip_if *ifp, uint8_t *l2_dst, udp->dport = ip_dst->port; udp->len = mg_htons((uint16_t) (sizeof(*udp) + len)); udp->csum = 0; - cs = csumup(0, udp, sizeof(*udp)); + memmove(udp + 1, buf, len); #if MG_ENABLE_IPV6 if (ip_dst->is_ip6) { - uint32_t pseudo[2]; - cs = csumup(cs, &ip6->src, sizeof(ip6->src)); - cs = csumup(cs, &ip6->dst, sizeof(ip6->dst)); - pseudo[0] = mg_htonl((uint32_t) (sizeof(*udp) + len)); - pseudo[1] = mg_htonl(17); - cs = csumup(cs, pseudo, 2 * sizeof(uint32_t)); + udp->csum = p6csum(ip6, udp, sizeof(*udp) + len); } else #endif { - uint16_t pseudo[2]; - cs = csumup(cs, &ip->src, sizeof(ip->src)); - cs = csumup(cs, &ip->dst, sizeof(ip->dst)); - pseudo[0] = mg_htons(17); - pseudo[1] = udp->len; - cs = csumup(cs, pseudo, 2 * sizeof(uint16_t)); + udp->csum = pcsum(ip, udp, sizeof(*udp) + len); } - cs = csumup(cs, buf, len); // possibly odd length must be last - udp->csum = csumfin(cs); - memmove(udp + 1, buf, len); l2_len = mg_l2_footer(ifp->l2type, l2_len, l2p); return (driver_output(ifp, l2_len) == l2_len); } @@ -5307,10 +5373,10 @@ static struct mg_connection *getpeer(struct mg_mgr *mgr, struct pkt *pkt, } #endif if (c->is_udp && pkt->udp && c->loc.port == pkt->udp->dport && - (!c->loc.is_ip6 || pkt->ip6)) + !(c->loc.is_ip6 ^ (pkt->ip6 != NULL))) // IP or IPv6 to same dest break; if (!c->is_udp && pkt->tcp && c->loc.port == pkt->tcp->dport && - (!c->loc.is_ip6 || pkt->ip6) && lsn == (bool) c->is_listening && + !(c->loc.is_ip6 ^ (pkt->ip6 != NULL)) && lsn == (bool) c->is_listening && (lsn || c->rem.port == pkt->tcp->sport)) break; } @@ -5366,10 +5432,12 @@ static void rx_arp(struct mg_tcpip_if *ifp, struct pkt *pkt) { static void rx_icmp(struct mg_tcpip_if *ifp, struct pkt *pkt) { uint8_t *l2p = (uint8_t *) ifp->tx.buf; + size_t plen = pkt->pay.len; + if (!icmpcsum_ok(pkt->icmp, sizeof(struct icmp) + plen)) return; if (pkt->icmp->type == 8 && pkt->ip != NULL && pkt->ip->dst == ifp->ip) { size_t l2_max_overhead = ifp->framesize - ifp->mtu; size_t hlen = sizeof(struct ip) + sizeof(struct icmp); - size_t room = ifp->tx.len - hlen - l2_max_overhead, plen = pkt->pay.len; + size_t room = ifp->tx.len - hlen - l2_max_overhead; uint8_t *l2addr; struct ip *ip; struct icmp *icmp; @@ -5527,8 +5595,6 @@ static void tx_icmp6(struct mg_tcpip_if *ifp, uint8_t *l2_dst, uint64_t *ip_src, uint8_t *l2p = (uint8_t *) ifp->tx.buf; struct ip6 *ip6; struct icmp6 *icmp6; - uint32_t cs; - uint16_t pseudo[2]; ip6 = tx_ip6(ifp, l2_dst, 58, ip_src, ip_dst, sizeof(*icmp6) + len); icmp6 = (struct icmp6 *) (ip6 + 1); memset(icmp6, 0, sizeof(*icmp6)); // Set csum to 0 @@ -5536,14 +5602,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 - cs = csumup(0, icmp6, sizeof(*icmp6)); - cs = csumup(cs, ip_src, 16); - cs = csumup(cs, ip_dst, 16); - pseudo[0] = htons(58); - pseudo[1] = htons((uint16_t) (sizeof(*icmp6) + len)); - cs = csumup(cs, pseudo, 4); - cs = csumup(cs, buf, len); // possibly odd length must be last - icmp6->csum = csumfin(cs); + icmp6->csum = p6csum(ip6, icmp6, sizeof(*icmp6) + len); driver_output( ifp, mg_l2_footer(ifp->l2type, sizeof(*ip6) + sizeof(*icmp6) + len, l2p)); } @@ -5763,6 +5822,7 @@ 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; switch (pkt->icmp6->type) { case 128: { // Echo Request, RFC-4443 4.1 uint64_t target[2]; @@ -5864,12 +5924,14 @@ static bool rx_udp(struct mg_tcpip_if *ifp, struct pkt *pkt) { s = (struct connstate *) (c + 1); c->rem.port = pkt->udp->sport; #if MG_ENABLE_IPV6 - if (c->loc.is_ip6) { + if (c->loc.is_ip6) { // matching of v4/v6 to dest is done bt getpeer() + if (!udp6csum_ok(pkt->ip6, pkt->udp)) return false; c->rem.addr.ip6[0] = pkt->ip6->src[0], c->rem.addr.ip6[1] = pkt->ip6->src[1], c->rem.is_ip6 = true; } else #endif { + if (!udpcsum_ok(pkt->ip, pkt->udp)) return false; c->rem.addr.ip4 = pkt->ip->src; } if ((l2addr = get_return_l2addr(ifp, &c->rem, true, pkt)) == NULL) @@ -5895,69 +5957,57 @@ static size_t tx_tcp(struct mg_tcpip_if *ifp, uint8_t *l2_dst, uint8_t *l2p = (uint8_t *) ifp->tx.buf; struct ip *ip = NULL; struct tcp *tcp; - uint16_t opts[4 / 2], mss; + uint16_t opts[4 / 2]; + size_t hlen = sizeof(*tcp); #if MG_ENABLE_IPV6 struct ip6 *ip6 = NULL; - mss = (uint16_t) (ifp->mtu - 60); // RFC-9293 3.7.1; RFC-6691 2 -#else - mss = (uint16_t) (ifp->mtu - 40); // RFC-9293 3.7.1; RFC-6691 2 #endif + + // Handle any options first, here, to determine header size if (flags & TH_SYN) { // Send MSS + uint16_t mss; +#if MG_ENABLE_IPV6 // RFC-9293 3.7.1; RFC-6691 2 + mss = (uint16_t) (ifp->mtu - 60); +#else + mss = (uint16_t) (ifp->mtu - 40); +#endif opts[0] = mg_htons(0x0204); // RFC-9293 3.2 opts[1] = mg_htons(mss); - buf = opts; - len = sizeof(opts); + hlen += sizeof(opts); // always whole number of 32-bit words } + #if MG_ENABLE_IPV6 if (ip_dst->is_ip6) { - ip6 = tx_ip6(ifp, l2_dst, 6, ip_src->addr.ip6, ip_dst->addr.ip6, - sizeof(struct tcp) + len); + ip6 = tx_ip6(ifp, l2_dst, 6, ip_src->addr.ip6, ip_dst->addr.ip6, hlen + len); tcp = (struct tcp *) (ip6 + 1); } else #endif { - ip = tx_ip(ifp, l2_dst, 6, ip_src->addr.ip4, ip_dst->addr.ip4, - sizeof(struct tcp) + len); + ip = tx_ip(ifp, l2_dst, 6, ip_src->addr.ip4, ip_dst->addr.ip4, hlen + len); tcp = (struct tcp *) (ip + 1); } memset(tcp, 0, sizeof(*tcp)); - if (buf != NULL && len) memmove(tcp + 1, buf, len); + memmove(tcp + 1, opts, hlen - sizeof(*tcp)); // copy opts if any + if (buf != NULL && len) memmove((uint8_t *)tcp + hlen, buf, len); tcp->sport = ip_src->port; tcp->dport = ip_dst->port; tcp->seq = seq; tcp->ack = ack; tcp->flags = flags; tcp->win = mg_htons(MG_TCPIP_WIN); - tcp->off = (uint8_t) (sizeof(*tcp) / 4 << 4); - if (flags & TH_SYN) tcp->off += (uint8_t) (sizeof(opts) / 4 << 4); - { - uint32_t cs = 0; - uint16_t n = (uint16_t) (sizeof(*tcp) + len); + tcp->off = (uint8_t) (hlen / 4 << 4); #if MG_ENABLE_IPV6 - if (ip_dst->is_ip6) { - uint32_t pseudo[2]; - cs = csumup(cs, &ip6->src, sizeof(ip6->src)); - cs = csumup(cs, &ip6->dst, sizeof(ip6->dst)); - pseudo[0] = mg_htonl((uint32_t) n); - pseudo[1] = mg_htonl(6); - cs = csumup(cs, pseudo, 2 * sizeof(uint32_t)); - } else + if (ip_dst->is_ip6) { + tcp->csum = p6csum(ip6, tcp, hlen + len); + } else #endif - { - uint16_t pseudo[2]; - cs = csumup(cs, &ip->src, sizeof(ip->src)); - cs = csumup(cs, &ip->dst, sizeof(ip->dst)); - pseudo[0] = mg_htons(6); - pseudo[1] = mg_htons(n); - cs = csumup(cs, pseudo, 2 * sizeof(uint16_t)); - } - cs = csumup(cs, tcp, n); // possibly odd length must be last - tcp->csum = csumfin(cs); + { + tcp->csum = pcsum(ip, tcp, hlen + len); } MG_VERBOSE(("TCP %M -> %M fl %x len %u", mg_print_ip_port, ip_src, mg_print_ip_port, ip_dst, tcp->flags, len)); return driver_output( - ifp, mg_l2_footer(ifp->l2type, PDIFF(ifp->tx.buf, tcp + 1) + len, l2p)); + ifp, mg_l2_footer(ifp->l2type, PDIFF(l2p, tcp) + hlen + len, l2p)); } static size_t tx_tcp_ctrlresp(struct mg_tcpip_if *ifp, struct pkt *pkt, @@ -6291,6 +6341,10 @@ static void handle_opt(struct connstate *s, struct tcp *tcp, bool ip6) { 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 bt getpeer() + if (pkt->ip6 != NULL && !tcp6csum_ok(pkt->ip6, pkt->tcp)) return; +#endif + if (pkt->ip != NULL && !tcpcsum_ok(pkt->ip, pkt->tcp)) return; pkt->tcp->flags &= TH_STDFLAGS; // tolerate creative usage (ECN, ?) // Order is VERY important; RFC-9293 3.5.2 // - check clients (Group 1) and established connections (Group 3) @@ -6376,6 +6430,7 @@ static void rx_ip(struct mg_tcpip_if *ifp, struct pkt *pkt) { if (len < (uint16_t) (ihl * 4) || len > pkt->pay.len) return; // malformed pkt->pay.len = len; // strip padding mkpay(pkt, (uint32_t *) pkt->ip + ihl); // account for opts + if (!ipcsum_ok(pkt->ip)) return; frag = mg_ntohs(pkt->ip->frag); if (frag & IP_MORE_FRAGS_MSK || frag & IP_FRAG_OFFSET_MSK) { struct mg_connection *c; diff --git a/src/net_builtin.c b/src/net_builtin.c index a8103105..ad530c30 100644 --- a/src/net_builtin.c +++ b/src/net_builtin.c @@ -151,6 +151,22 @@ struct dhcp6 { uint8_t options[30 + sizeof(((struct mg_tcpip_if *) 0)->dhcp_name)]; }; +struct pseudoip { + uint32_t src; // Source IP + uint32_t dst; // Destination IP + uint8_t zero; + uint8_t proto; // Upper level protocol + uint16_t len; // Datagram length +}; + +struct pseudoip6 { + uint64_t src[2]; // Source IP + uint64_t dst[2]; // Destination IP + uint32_t plen; // Payload length + uint8_t zero[3]; + uint8_t next; // Upper level protocol +}; + #if defined(__DCC__) #pragma pack(0) #else @@ -234,7 +250,71 @@ static uint16_t ipcsum(const void *buf, size_t len) { return csumfin(sum); } +static bool ipcsum_ok(const void *d) { + struct ip *ip = (struct ip *) d; + return (ipcsum(d, (ip->ver & 0x0F) * 4) == 0); +} + +static bool icmpcsum_ok(const void *d, size_t len) { + return (ipcsum(d, len) == 0); +} + +static uint16_t pcsum(void *d, void *p, size_t plen) { + uint32_t sum; + struct ip *ip = (struct ip *) d; + struct pseudoip pip; + pip.src = ip->src; + pip.dst = ip->dst; + pip.zero = 0; + pip.proto = ip->proto; + pip.len = mg_htons((uint16_t) plen); + sum = csumup(0, &pip, sizeof(pip)); // even length + sum = csumup(sum, p, plen); // possibly odd length: last + return csumfin(sum); +} + +static bool udpcsum_ok(void *d, void *u) { + struct udp *udp = (struct udp *) u; + if (udp->csum == 0) return true; + if (udp->csum == 0xFFFF) udp->csum = 0; + return (pcsum(d, u, (size_t) mg_ntohs(udp->len)) == 0); +} + +static bool tcpcsum_ok(void *d, void *t) { + struct ip *ip = (struct ip *) d; + return (pcsum(d, t, (size_t)(mg_ntohs(ip->len) - (ip->ver & 0x0F) * 4)) == 0); +} + #if MG_ENABLE_IPV6 +static uint16_t p6csum(void *d, void *p, size_t plen) { + uint32_t sum; + struct ip6 *ip6 = (struct ip6 *) d; + struct pseudoip6 pip6; + pip6.src[0] = ip6->src[0], pip6.src[1] = ip6->src[1]; + 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; + sum = csumup(0, &pip6, sizeof(pip6)); // even length + sum = csumup(sum, p, plen); // possibly odd length: last + return csumfin(sum); +} + +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); +} +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 void ip6sn(uint64_t *addr, uint64_t *sn_addr) { // Build solicited-node multicast address from a given unicast IP // RFC-4291 2.7 @@ -346,7 +426,6 @@ static bool tx_udp(struct mg_tcpip_if *ifp, uint8_t *l2_dst, size_t l2_len; struct ip *ip = NULL; struct udp *udp; - uint32_t cs; #if MG_ENABLE_IPV6 struct ip6 *ip6 = NULL; if (ip_dst->is_ip6) { @@ -366,28 +445,15 @@ static bool tx_udp(struct mg_tcpip_if *ifp, uint8_t *l2_dst, udp->dport = ip_dst->port; udp->len = mg_htons((uint16_t) (sizeof(*udp) + len)); udp->csum = 0; - cs = csumup(0, udp, sizeof(*udp)); + memmove(udp + 1, buf, len); #if MG_ENABLE_IPV6 if (ip_dst->is_ip6) { - uint32_t pseudo[2]; - cs = csumup(cs, &ip6->src, sizeof(ip6->src)); - cs = csumup(cs, &ip6->dst, sizeof(ip6->dst)); - pseudo[0] = mg_htonl((uint32_t) (sizeof(*udp) + len)); - pseudo[1] = mg_htonl(17); - cs = csumup(cs, pseudo, 2 * sizeof(uint32_t)); + udp->csum = p6csum(ip6, udp, sizeof(*udp) + len); } else #endif { - uint16_t pseudo[2]; - cs = csumup(cs, &ip->src, sizeof(ip->src)); - cs = csumup(cs, &ip->dst, sizeof(ip->dst)); - pseudo[0] = mg_htons(17); - pseudo[1] = udp->len; - cs = csumup(cs, pseudo, 2 * sizeof(uint16_t)); + udp->csum = pcsum(ip, udp, sizeof(*udp) + len); } - cs = csumup(cs, buf, len); // possibly odd length must be last - udp->csum = csumfin(cs); - memmove(udp + 1, buf, len); l2_len = mg_l2_footer(ifp->l2type, l2_len, l2p); return (driver_output(ifp, l2_len) == l2_len); } @@ -481,10 +547,10 @@ static struct mg_connection *getpeer(struct mg_mgr *mgr, struct pkt *pkt, } #endif if (c->is_udp && pkt->udp && c->loc.port == pkt->udp->dport && - (!c->loc.is_ip6 || pkt->ip6)) + !(c->loc.is_ip6 ^ (pkt->ip6 != NULL))) // IP or IPv6 to same dest break; if (!c->is_udp && pkt->tcp && c->loc.port == pkt->tcp->dport && - (!c->loc.is_ip6 || pkt->ip6) && lsn == (bool) c->is_listening && + !(c->loc.is_ip6 ^ (pkt->ip6 != NULL)) && lsn == (bool) c->is_listening && (lsn || c->rem.port == pkt->tcp->sport)) break; } @@ -540,10 +606,12 @@ static void rx_arp(struct mg_tcpip_if *ifp, struct pkt *pkt) { static void rx_icmp(struct mg_tcpip_if *ifp, struct pkt *pkt) { uint8_t *l2p = (uint8_t *) ifp->tx.buf; + size_t plen = pkt->pay.len; + if (!icmpcsum_ok(pkt->icmp, sizeof(struct icmp) + plen)) return; if (pkt->icmp->type == 8 && pkt->ip != NULL && pkt->ip->dst == ifp->ip) { size_t l2_max_overhead = ifp->framesize - ifp->mtu; size_t hlen = sizeof(struct ip) + sizeof(struct icmp); - size_t room = ifp->tx.len - hlen - l2_max_overhead, plen = pkt->pay.len; + size_t room = ifp->tx.len - hlen - l2_max_overhead; uint8_t *l2addr; struct ip *ip; struct icmp *icmp; @@ -701,8 +769,6 @@ static void tx_icmp6(struct mg_tcpip_if *ifp, uint8_t *l2_dst, uint64_t *ip_src, uint8_t *l2p = (uint8_t *) ifp->tx.buf; struct ip6 *ip6; struct icmp6 *icmp6; - uint32_t cs; - uint16_t pseudo[2]; ip6 = tx_ip6(ifp, l2_dst, 58, ip_src, ip_dst, sizeof(*icmp6) + len); icmp6 = (struct icmp6 *) (ip6 + 1); memset(icmp6, 0, sizeof(*icmp6)); // Set csum to 0 @@ -710,14 +776,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 - cs = csumup(0, icmp6, sizeof(*icmp6)); - cs = csumup(cs, ip_src, 16); - cs = csumup(cs, ip_dst, 16); - pseudo[0] = htons(58); - pseudo[1] = htons((uint16_t) (sizeof(*icmp6) + len)); - cs = csumup(cs, pseudo, 4); - cs = csumup(cs, buf, len); // possibly odd length must be last - icmp6->csum = csumfin(cs); + icmp6->csum = p6csum(ip6, icmp6, sizeof(*icmp6) + len); driver_output( ifp, mg_l2_footer(ifp->l2type, sizeof(*ip6) + sizeof(*icmp6) + len, l2p)); } @@ -937,6 +996,7 @@ 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; switch (pkt->icmp6->type) { case 128: { // Echo Request, RFC-4443 4.1 uint64_t target[2]; @@ -1038,12 +1098,14 @@ static bool rx_udp(struct mg_tcpip_if *ifp, struct pkt *pkt) { s = (struct connstate *) (c + 1); c->rem.port = pkt->udp->sport; #if MG_ENABLE_IPV6 - if (c->loc.is_ip6) { + if (c->loc.is_ip6) { // matching of v4/v6 to dest is done bt getpeer() + if (!udp6csum_ok(pkt->ip6, pkt->udp)) return false; c->rem.addr.ip6[0] = pkt->ip6->src[0], c->rem.addr.ip6[1] = pkt->ip6->src[1], c->rem.is_ip6 = true; } else #endif { + if (!udpcsum_ok(pkt->ip, pkt->udp)) return false; c->rem.addr.ip4 = pkt->ip->src; } if ((l2addr = get_return_l2addr(ifp, &c->rem, true, pkt)) == NULL) @@ -1069,69 +1131,57 @@ static size_t tx_tcp(struct mg_tcpip_if *ifp, uint8_t *l2_dst, uint8_t *l2p = (uint8_t *) ifp->tx.buf; struct ip *ip = NULL; struct tcp *tcp; - uint16_t opts[4 / 2], mss; + uint16_t opts[4 / 2]; + size_t hlen = sizeof(*tcp); #if MG_ENABLE_IPV6 struct ip6 *ip6 = NULL; - mss = (uint16_t) (ifp->mtu - 60); // RFC-9293 3.7.1; RFC-6691 2 -#else - mss = (uint16_t) (ifp->mtu - 40); // RFC-9293 3.7.1; RFC-6691 2 #endif + + // Handle any options first, here, to determine header size if (flags & TH_SYN) { // Send MSS + uint16_t mss; +#if MG_ENABLE_IPV6 // RFC-9293 3.7.1; RFC-6691 2 + mss = (uint16_t) (ifp->mtu - 60); +#else + mss = (uint16_t) (ifp->mtu - 40); +#endif opts[0] = mg_htons(0x0204); // RFC-9293 3.2 opts[1] = mg_htons(mss); - buf = opts; - len = sizeof(opts); + hlen += sizeof(opts); // always whole number of 32-bit words } + #if MG_ENABLE_IPV6 if (ip_dst->is_ip6) { - ip6 = tx_ip6(ifp, l2_dst, 6, ip_src->addr.ip6, ip_dst->addr.ip6, - sizeof(struct tcp) + len); + ip6 = tx_ip6(ifp, l2_dst, 6, ip_src->addr.ip6, ip_dst->addr.ip6, hlen + len); tcp = (struct tcp *) (ip6 + 1); } else #endif { - ip = tx_ip(ifp, l2_dst, 6, ip_src->addr.ip4, ip_dst->addr.ip4, - sizeof(struct tcp) + len); + ip = tx_ip(ifp, l2_dst, 6, ip_src->addr.ip4, ip_dst->addr.ip4, hlen + len); tcp = (struct tcp *) (ip + 1); } memset(tcp, 0, sizeof(*tcp)); - if (buf != NULL && len) memmove(tcp + 1, buf, len); + memmove(tcp + 1, opts, hlen - sizeof(*tcp)); // copy opts if any + if (buf != NULL && len) memmove((uint8_t *)tcp + hlen, buf, len); tcp->sport = ip_src->port; tcp->dport = ip_dst->port; tcp->seq = seq; tcp->ack = ack; tcp->flags = flags; tcp->win = mg_htons(MG_TCPIP_WIN); - tcp->off = (uint8_t) (sizeof(*tcp) / 4 << 4); - if (flags & TH_SYN) tcp->off += (uint8_t) (sizeof(opts) / 4 << 4); - { - uint32_t cs = 0; - uint16_t n = (uint16_t) (sizeof(*tcp) + len); + tcp->off = (uint8_t) (hlen / 4 << 4); #if MG_ENABLE_IPV6 - if (ip_dst->is_ip6) { - uint32_t pseudo[2]; - cs = csumup(cs, &ip6->src, sizeof(ip6->src)); - cs = csumup(cs, &ip6->dst, sizeof(ip6->dst)); - pseudo[0] = mg_htonl((uint32_t) n); - pseudo[1] = mg_htonl(6); - cs = csumup(cs, pseudo, 2 * sizeof(uint32_t)); - } else + if (ip_dst->is_ip6) { + tcp->csum = p6csum(ip6, tcp, hlen + len); + } else #endif - { - uint16_t pseudo[2]; - cs = csumup(cs, &ip->src, sizeof(ip->src)); - cs = csumup(cs, &ip->dst, sizeof(ip->dst)); - pseudo[0] = mg_htons(6); - pseudo[1] = mg_htons(n); - cs = csumup(cs, pseudo, 2 * sizeof(uint16_t)); - } - cs = csumup(cs, tcp, n); // possibly odd length must be last - tcp->csum = csumfin(cs); + { + tcp->csum = pcsum(ip, tcp, hlen + len); } MG_VERBOSE(("TCP %M -> %M fl %x len %u", mg_print_ip_port, ip_src, mg_print_ip_port, ip_dst, tcp->flags, len)); return driver_output( - ifp, mg_l2_footer(ifp->l2type, PDIFF(ifp->tx.buf, tcp + 1) + len, l2p)); + ifp, mg_l2_footer(ifp->l2type, PDIFF(l2p, tcp) + hlen + len, l2p)); } static size_t tx_tcp_ctrlresp(struct mg_tcpip_if *ifp, struct pkt *pkt, @@ -1465,6 +1515,10 @@ static void handle_opt(struct connstate *s, struct tcp *tcp, bool ip6) { 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; +#endif + if (pkt->ip != NULL && !tcpcsum_ok(pkt->ip, pkt->tcp)) return; pkt->tcp->flags &= TH_STDFLAGS; // tolerate creative usage (ECN, ?) // Order is VERY important; RFC-9293 3.5.2 // - check clients (Group 1) and established connections (Group 3) @@ -1550,6 +1604,7 @@ static void rx_ip(struct mg_tcpip_if *ifp, struct pkt *pkt) { if (len < (uint16_t) (ihl * 4) || len > pkt->pay.len) return; // malformed pkt->pay.len = len; // strip padding mkpay(pkt, (uint32_t *) pkt->ip + ihl); // account for opts + if (!ipcsum_ok(pkt->ip)) return; frag = mg_ntohs(pkt->ip->frag); if (frag & IP_MORE_FRAGS_MSK || frag & IP_FRAG_OFFSET_MSK) { struct mg_connection *c; diff --git a/test/mip_port_test.c b/test/mip_port_test.c index f7129215..e384e536 100644 --- a/test/mip_port_test.c +++ b/test/mip_port_test.c @@ -38,6 +38,7 @@ int main(void) { const char *debug_level = getenv("V"); // Setup interface const uint16_t port = 0xAA55; // UDP port + const uint16_t tap_port = 0x55AA; // UDP port for TAP socket const char *mac = "02:00:01:02:03:78"; // MAC address struct port_driver_data pdd; @@ -46,13 +47,13 @@ int main(void) { pdd.port_addr.sin_addr.s_addr = htonl(INADDR_ANY); pdd.port_addr.sin_port = htons(port); if (bind(pdd.sockfd, (struct sockaddr *) &pdd.port_addr, sizeof(pdd.port_addr)) < 0) return EXIT_FAILURE; - printf("Opened UDP socket\n"); + printf("Opened UDP socket: 127.0.0.1:%u (0x%04x)\n", port, port); pdd.tap_addr.sin_family = AF_INET; pdd.tap_addr.sin_addr.s_addr = htonl(0x7f000001U); // 127.0.0.1 pdd.tap_addr.sin_port = htons(0x55AA); if (connect(pdd.sockfd, (struct sockaddr *) &pdd.tap_addr, sizeof(pdd.tap_addr)) < 0) return EXIT_FAILURE; - printf("Connected to TAP UDP socket\n"); + printf("Connected to TAP UDP socket: 127.0.0.1:%u (0x%04x)\n", tap_port, tap_port); usleep(200000); // 200 ms diff --git a/test/mip_test.c b/test/mip_test.c index 3781a749..49dd8813 100644 --- a/test/mip_test.c +++ b/test/mip_test.c @@ -41,7 +41,7 @@ struct ipp { static void test_csum(void) { uint8_t ip[20] = {0x45, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x28, 0x11, 0x94, 0xcf, 0x7f, 0x00, 0x00, 0x01, 0x7f, 0x00, 0x00, 0x01}; - uint8_t udp_odd[53] = {0xc0, 0xa8, 0x45, 0x58, 0x08, 0x08, 0x08, 0x08, 0x00, + uint8_t pseudo_udp_odd[53] = {0xc0, 0xa8, 0x45, 0x58, 0x08, 0x08, 0x08, 0x08, 0x00, 0x11, 0x00, 0x29, 0xad, 0x67, 0x00, 0x35, 0x00, 0x29, 0xaf, 0xf8, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x74, 0x69, 0x6d, @@ -49,92 +49,16 @@ static void test_csum(void) { 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01}; ASSERT(ipcsum(ip, 20) == 0); - ASSERT(ipcsum(udp_odd, 53) == 0); + ASSERT(ipcsum(pseudo_udp_odd, 53) == 0); // UDP and TCP checksum calc funcions use the same basic calls as ipcsum() } -#if defined(__DCC__) -#pragma pack(1) -#else -#pragma pack(push, 1) + +#if !MG_ENABLE_IPV6 +#define udp6csum_ok(d, u) true +#define tcp6csum_ok(d, t) true #endif -struct pseudoip { - uint32_t src; // Source IP - uint32_t dst; // Destination IP - uint8_t zero; - uint8_t proto; // Upper level protocol - uint16_t len; // Datagram length -}; - -struct pseudoip6 { - uint64_t src[2]; // Source IP - uint64_t dst[2]; // Destination IP - uint32_t plen; // Payload length - uint8_t zero[3]; - uint8_t next; // Upper level protocol -}; - -#if defined(__DCC__) -#pragma pack(0) -#else -#pragma pack(pop) -#endif - -static bool test_udp_csum(void *d, void *u) { - struct ip *ip = (struct ip *) d; - struct udp *udp = (struct udp *) u; - struct pseudoip pseudo, *pip; - pseudo.src = ip->src; - pseudo.dst = ip->dst; - pseudo.zero = 0; - pseudo.proto = ip->proto; - pseudo.len = udp->len; - pip = (struct pseudoip *)((size_t) u - sizeof(*pip)); - memcpy(pip, &pseudo, sizeof(*pip)); - return (ipcsum(pip, sizeof(*pip) + mg_ntohs(udp->len)) == 0); -} - -static bool test_udp6_csum(void *d, void *u) { - struct ip6 *ip = (struct ip6 *) d; - struct udp *udp = (struct udp *) u; - struct pseudoip6 pseudo, *pip; - pseudo.src[0] = ip->src[0], pseudo.src[1] = ip->src[1]; - pseudo.dst[0] = ip->dst[0], pseudo.dst[1] = ip->dst[1]; - pseudo.zero[0] = 0, pseudo.zero[1] = 0, pseudo.zero[2] = 0; - pseudo.plen = mg_htonl((uint32_t) mg_ntohs(udp->len)); - pseudo.next = ip->next; - pip = (struct pseudoip6 *) ((size_t) u - sizeof(*pip)); - memcpy(pip, &pseudo, sizeof(*pip)); - return (ipcsum(pip, sizeof(*pip) + mg_ntohs(udp->len)) == 0); -} - -static bool test_tcp_csum(void *d, void *t) { - struct ip *ip = (struct ip *) d; - struct pseudoip pseudo, *pip; - pseudo.src = ip->src; - pseudo.dst = ip->dst; - pseudo.zero = 0; - pseudo.proto = ip->proto; - pseudo.len = mg_htons((uint16_t)(mg_ntohs(ip->len) - (ip->ver & 0x0F) * 4)); - pip = (struct pseudoip *)((size_t) t - sizeof(*pip)); - memcpy(pip, &pseudo, sizeof(*pip)); - return (ipcsum(pip, sizeof(*pip) + mg_ntohs(pip->len)) == 0); -} - -static bool test_tcp6_csum(void *d, void *t) { - struct ip6 *ip = (struct ip6 *) d; - struct pseudoip6 pseudo, *pip; - pseudo.src[0] = ip->src[0], pseudo.src[1] = ip->src[1]; - pseudo.dst[0] = ip->dst[0], pseudo.dst[1] = ip->dst[1]; - pseudo.zero[0] = 0, pseudo.zero[1] = 0, pseudo.zero[2] = 0; - pseudo.plen = mg_htonl((uint32_t) mg_ntohs(ip->plen)); - pseudo.next = ip->next; - pip = (struct pseudoip6 *) ((size_t) t - sizeof(*pip)); - memcpy(pip, &pseudo, sizeof(*pip)); - return (ipcsum(pip, sizeof(*pip) + mg_ntohl(pip->plen)) == 0); -} - static bool executed = false; static void mif_fn(struct mg_tcpip_if *ifp, int ev, void *ev_data) { @@ -285,7 +209,7 @@ static void create_tcp_seg(struct eth *e, struct ipp *ipp, uint32_t seq, uint16_t dport, size_t payload_len, void *opts, unsigned int opts_len) { struct tcp t; - memset(&t, 0, sizeof(struct tcp)); + memset(&t, 0, sizeof(t)); t.flags = flags; t.seq = mg_htonl(seq); t.ack = mg_htonl(ack); @@ -296,25 +220,31 @@ static void create_tcp_seg(struct eth *e, struct ipp *ipp, uint32_t seq, #if MG_ENABLE_IPV6 if (ipp->ip6 != NULL) { struct ip6 *ip = ipp->ip6; + struct tcp *tcp = (struct tcp *) (s_driver_data.buf + sizeof(*e) + sizeof(*ip)); ip->plen = mg_htons((uint16_t) (4 * (t.off >> 4) + payload_len)); memcpy(s_driver_data.buf + sizeof(*e), ip, sizeof(*ip)); - memcpy(s_driver_data.buf + sizeof(*e) + sizeof(*ip), &t, sizeof(t)); + memcpy(tcp, &t, sizeof(t)); 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)); s_driver_data.len = sizeof(*e) + sizeof(*ip) + sizeof(t) + payload_len + opts_len; } else #endif { struct ip *ip = ipp->ip4; + struct tcp *tcp = (struct tcp *) (s_driver_data.buf + sizeof(*e) + sizeof(*ip)); ip->len = mg_htons((uint16_t) (sizeof(*ip) + 4 * (t.off >> 4) + payload_len)); + ip->csum = ipcsum(ip, sizeof(*ip)); // no options memcpy(s_driver_data.buf + sizeof(*e), ip, sizeof(*ip)); - memcpy(s_driver_data.buf + sizeof(*e) + sizeof(*ip), &t, sizeof(t)); + ip->csum = 0; + memcpy(tcp, &t, sizeof(t)); if (opts != NULL && opts_len) memcpy(s_driver_data.buf + sizeof(*e) + sizeof(*ip) + sizeof(t), opts, opts_len); + tcp->csum = pcsum(ip, tcp, (4 * (t.off >> 4) + payload_len)); s_driver_data.len = sizeof(*e) + sizeof(*ip) + sizeof(t) + payload_len + opts_len; } @@ -454,13 +384,12 @@ static void test_tcp_basics(bool ipv6) { ASSERT(t->flags == (TH_RST | TH_ACK)); ASSERT(t->seq == mg_htonl(0)); ASSERT(t->ack == mg_htonl(1235)); - mg_hexdump(s_driver_data.buf, s_driver_data.len); if (ipv6) { - ASSERT(i6->src[0] == 1 && i6->dst[0] == 2); - ASSERT(test_tcp6_csum(i6, t)); + ASSERT(i6->src[0] == mg_htonll(1ULL << 56) && i6->src[1] == 0 && i6->dst[0] == mg_htonll(2ULL << 56) && i6->dst[1] == 0); + ASSERT(tcp6csum_ok(i6, t)); } else { ASSERT(i->src == mg_htonl(0x1000000) && i->dst == mg_htonl(0x2000000)); - ASSERT(test_tcp_csum(i, t)); + ASSERT(tcpcsum_ok(i, t)); } // send SYN+ACK, expect RST @@ -512,7 +441,7 @@ static void test_tcp_basics(bool ipv6) { ASSERT(t->flags == TH_RST); ASSERT(t->seq == mg_htonl(4321)); if (ipv6) { - ASSERT(i6->src[0] == 1 && i6->dst[0] == 2); + ASSERT(i6->src[0] == mg_htonll(1ULL << 56) && i6->src[1] == 0 && i6->dst[0] == mg_htonll(2ULL << 56) && i6->dst[1] == 0); } else { ASSERT(i->src == mg_htonl(0x1000000) && i->dst == mg_htonl(0x2000000)); } @@ -550,7 +479,7 @@ static void test_tcp_basics(bool ipv6) { ASSERT((t->flags == TH_ACK)); ASSERT((t->ack == mg_htonl(1001))); // expecting 1001, dude if (ipv6) { - ASSERT(i6->src[0] == 1 && i6->dst[0] == 2); + ASSERT(i6->src[0] == mg_htonll(1ULL << 56) && i6->src[1] == 0 && i6->dst[0] == mg_htonll(2ULL << 56) && i6->dst[1] == 0); } else { ASSERT(i->src == mg_htonl(0x1000000) && i->dst == mg_htonl(0x2000000)); } @@ -769,9 +698,11 @@ static void test_tcp_basics(bool ipv6) { ASSERT((t->flags == TH_SYN)); ASSERT(event == 255); if (ipv6) { - ASSERT(i6->src[0] == 1 && i6->dst[0] == 2); + ASSERT(i6->src[0] == mg_htonll(1ULL << 56) && i6->src[1] == 0 && i6->dst[0] == mg_htonll(2ULL << 56) && i6->dst[1] == 0); + ASSERT(tcp6csum_ok(i6, t)); } else { ASSERT(i->src == mg_htonl(0x1000000) && i->dst == mg_htonl(0x2000000)); + ASSERT(tcpcsum_ok(i, t)); } // invalid SYN + ACK to connecting client (after SYN...), send ACK != seq @@ -1083,7 +1014,7 @@ static void udp_fn(struct mg_connection *c, int ev, void *ev_data) { static void create_udp_dat(struct eth *e, struct ipp *ipp, uint16_t sport, uint16_t dport, size_t payload_len) { struct udp u; - memset(&u, 0, sizeof(struct udp)); + memset(&u, 0, sizeof(u)); u.sport = mg_htons(sport); u.dport = mg_htons(dport); u.len = mg_htons((uint16_t) (sizeof(u) + payload_len)); @@ -1091,19 +1022,25 @@ static void create_udp_dat(struct eth *e, struct ipp *ipp, uint16_t sport, #if MG_ENABLE_IPV6 if (ipp->ip6 != NULL) { struct ip6 *ip = ipp->ip6; + struct udp *udp = (struct udp *) (s_driver_data.buf + sizeof(*e) + sizeof(*ip)); ip->plen = mg_htons((uint16_t) (sizeof(u) + payload_len)); memcpy(s_driver_data.buf + sizeof(*e), ip, sizeof(*ip)); - memcpy(s_driver_data.buf + sizeof(*e) + sizeof(*ip), &u, sizeof(u)); + 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)); s_driver_data.len = sizeof(*e) + sizeof(*ip) + sizeof(u) + payload_len; } else #endif { struct ip *ip = ipp->ip4; + struct udp *udp = (struct udp *) (s_driver_data.buf + sizeof(*e) + sizeof(*ip)); ip->len = mg_htons((uint16_t) (sizeof(*ip) + sizeof(u) + payload_len)); + ip->csum = ipcsum(ip, sizeof(*ip)); // no options memcpy(s_driver_data.buf + sizeof(*e), ip, sizeof(*ip)); - memcpy(s_driver_data.buf + sizeof(*e) + sizeof(*ip), &u, sizeof(u)); + ip->csum = 0; + memcpy(udp, &u, sizeof(u)); *(s_driver_data.buf + sizeof(*e) + sizeof(*ip) + sizeof(u)) = 'p'; + udp->csum = pcsum(ip, udp, (sizeof(u) + payload_len)); s_driver_data.len = sizeof(*e) + sizeof(*ip) + sizeof(u) + payload_len; } if (s_driver_data.len < 64) s_driver_data.len = 64; // add padding if needed @@ -1160,11 +1097,11 @@ static void test_udp(bool ipv6) { ASSERT(u->len == mg_htons(sizeof(*u) + 3)); ASSERT(*((char *) (u + 1)) == 'P'); if (ipv6) { - ASSERT(i6->src[0] == 1 && i6->dst[0] == 2); - ASSERT(test_udp6_csum(i6, u)); + ASSERT(i6->src[0] == mg_htonll(1ULL << 56) && i6->src[1] == 0 && i6->dst[0] == mg_htonll(2ULL << 56) && i6->dst[1] == 0); + ASSERT(udp6csum_ok(i6, u)); } else { ASSERT(i->src == mg_htonl(0x1000000) && i->dst == mg_htonl(0x2000000)); - ASSERT(test_udp_csum(i, u)); + ASSERT(udpcsum_ok(i, u)); } s_driver_data.len = 0; @@ -1173,17 +1110,19 @@ static void test_udp(bool ipv6) { static void create_icmp_dat(struct eth *e, struct ipp *ipp, uint8_t type, uint8_t code, size_t payload_len) { - struct icmp icmp; struct ip *ip = ipp->ip4; - memset(&icmp, 0, sizeof(struct icmp)); - icmp.type = type; - icmp.code = code; + struct icmp i, *icmp = (struct icmp *)(s_driver_data.buf + sizeof(*e) + sizeof(*ip)); + memset(&i, 0, sizeof(i)); + i.type = type; + i.code = code; memcpy(s_driver_data.buf, e, sizeof(*e)); - ip->len = mg_htons((uint16_t) (sizeof(*ip) + sizeof(icmp) + payload_len)); + ip->len = mg_htons((uint16_t) (sizeof(*ip) + sizeof(*icmp) + payload_len)); + ip->csum = ipcsum(ip, sizeof(*ip)); memcpy(s_driver_data.buf + sizeof(*e), ip, sizeof(*ip)); - memcpy(s_driver_data.buf + sizeof(*e) + sizeof(*ip), &icmp, sizeof(icmp)); - s_driver_data.len = sizeof(*e) + sizeof(*ip) + sizeof(icmp) + payload_len; - icmp.csum = ipcsum(s_driver_data.buf + sizeof(*e), sizeof(icmp) + payload_len); + ip->csum = 0; + memcpy(icmp, &i, sizeof(i)); + icmp->csum = ipcsum(icmp, sizeof(*icmp) + payload_len); + s_driver_data.len = sizeof(*e) + sizeof(*ip) + sizeof(*icmp) + payload_len; if (s_driver_data.len < 64) s_driver_data.len = 64; // add padding if needed } @@ -1217,10 +1156,10 @@ static void test_icmp_basics(void) { ASSERT(i->src == mg_htonl(0x1000000) && i->dst == mg_htonl(0x2000000)); ASSERT(i->proto == 1); ASSERT(i->len == mg_htons(sizeof(*i) + sizeof(*icmp) + 0)); - ASSERT(ipcsum(i, sizeof(*i)) == 0); // Bonus, not tested elsewhere + ASSERT(ipcsum_ok(i)); // Bonus, not tested elsewhere ASSERT(icmp->type == 0); // Echo Reply ASSERT(icmp->code == 0); - ASSERT(ipcsum(icmp, sizeof(*icmp) + 0) == 0); + ASSERT(icmpcsum_ok(icmp, sizeof(*icmp) + 0)); create_icmp_dat(&e, &ipp, 8, 0, 69); // Echo Request mg_mgr_poll(&mgr, 0); // make sure we clean former stuff in buffer @@ -1242,32 +1181,21 @@ static void test_icmp(void) { #if MG_ENABLE_IPV6 -static uint16_t icmp6csum(struct ip6 *ip6, size_t len) { - uint32_t cs; - struct icmp6 *icmp6 = (struct icmp6 *) (ip6 + 1); - cs = csumup(0, icmp6, sizeof(*icmp6)); - cs = csumup(cs, icmp6 + 1, len); - cs = csumup(cs, ip6->src, 16); - cs = csumup(cs, ip6->dst, 16); - cs += (uint32_t) (58 + sizeof(*icmp6) + len); - return csumfin(cs); -} - static void create_icmp6_dat(struct eth *e, struct ipp *ipp, uint8_t type, uint8_t code, uint8_t *payload, size_t payload_len) { - struct icmp6 icmp6; struct ip6 *ip6 = ipp->ip6; - memset(&icmp6, 0, sizeof(icmp6)); - icmp6.type = type; - icmp6.code = code; - memcpy(s_driver_data.buf, e, sizeof(*e)); - ip6->plen = mg_htons((uint16_t) (sizeof(icmp6) + payload_len)); - memcpy(s_driver_data.buf + sizeof(*e), ip6, sizeof(*ip6)); - memcpy(s_driver_data.buf + sizeof(*e) + sizeof(*ip6), &icmp6, sizeof(icmp6)); + struct icmp6 i6, *icmp6 = (struct icmp6 *)(s_driver_data.buf + sizeof(*e) + sizeof(*ip6)); + memset(&i6, 0, sizeof(i6)); + i6.type = type; + i6.code = code; if (payload != NULL) - memcpy(s_driver_data.buf + sizeof(*e) + sizeof(*ip6) + sizeof(icmp6), payload, payload_len); - s_driver_data.len = sizeof(*e) + sizeof(*ip6) + sizeof(icmp6) + payload_len; - icmp6.csum = icmp6csum((struct ip6 *)(s_driver_data.buf + sizeof(*e)), payload_len); + memcpy(s_driver_data.buf + sizeof(*e) + sizeof(*ip6) + sizeof(*icmp6), payload, payload_len); + ip6->plen = mg_htons((uint16_t) (sizeof(*icmp6) + payload_len)); + 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); + 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 } @@ -1301,7 +1229,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(i, 0) == 0); + ASSERT(icmp6csum_ok(i, icmp6)); create_icmp6_dat(&e, &ipp, 128, 0, NULL, 69); // Echo Request mg_mgr_poll(&mgr, 0); // make sure we clean former stuff in buffer @@ -1311,7 +1239,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(i, 69) == 0); + ASSERT(icmp6csum_ok(i, icmp6)); // Neighbor Solicitation memset(payload, 0, sizeof(payload)); diff --git a/test/port_tap_bridge.c b/test/port_tap_bridge.c index 92057ef8..af96b0c3 100644 --- a/test/port_tap_bridge.c +++ b/test/port_tap_bridge.c @@ -58,7 +58,7 @@ int main(void) { tap_addr.sin_addr.s_addr = htonl(0x7f000001U); // 127.0.0.1 tap_addr.sin_port = htons(port); if (bind(sockfd, (struct sockaddr *) &tap_addr, sizeof(tap_addr)) < 0) return EXIT_FAILURE; - printf("Opened UDP socket\n"); + printf("Opened UDP socket: 127.0.0.1:%u (0x%04x)\n", port, port); memset(&port_addr, 0, sizeof(port_addr));