mirror of
https://github.com/cesanta/mongoose.git
synced 2026-10-20 11:19:56 +00:00
Add checksum validation
This commit is contained in:
1 parent
ece3f43f34
commit
b1878dc9d0
5 files changed
+306
-267
No files matched your search
+121
-66
@@ -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;
|
||||
|
||||
+121
-66
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
+60
-132
@@ -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));
|
||||
|
||||
@@ -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));
|
||||
|
||||
|
||||
Reference in new issue
Block a user