Skip to content

Commit 7339c7d

Browse files
committed
Fix TCP error handling
Add unit tests for TCP error handling Account for options in TCP header for payload start address calculation Take UDP payload length from UDP header
1 parent c1152f5 commit 7339c7d

File tree

3 files changed

+472
-139
lines changed

3 files changed

+472
-139
lines changed

mongoose.c

Lines changed: 66 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -4729,13 +4729,17 @@ static size_t tx_tcp(struct mg_tcpip_if *ifp, uint8_t *dst_mac, uint32_t dst_ip,
47294729
return ether_output(ifp, PDIFF(ifp->tx.buf, tcp + 1) + len);
47304730
}
47314731

4732-
static size_t tx_tcp_pkt(struct mg_tcpip_if *ifp, struct pkt *pkt,
4733-
uint8_t flags, uint32_t seq, const void *buf,
4734-
size_t len) {
4735-
uint32_t delta = (pkt->tcp->flags & (TH_SYN | TH_FIN)) ? 1 : 0;
4732+
static size_t tx_tcp_ctrlresp(struct mg_tcpip_if *ifp, struct pkt *pkt,
4733+
uint8_t flags, uint32_t seqno) {
4734+
uint32_t ackno = mg_htonl(mg_ntohl(pkt->tcp->seq) + (uint32_t) pkt->pay.len +
4735+
((pkt->tcp->flags & (TH_SYN | TH_FIN)) ? 1 : 0));
47364736
return tx_tcp(ifp, pkt->eth->src, pkt->ip->src, flags, pkt->tcp->dport,
4737-
pkt->tcp->sport, seq, mg_htonl(mg_ntohl(pkt->tcp->seq) + delta),
4738-
buf, len);
4737+
pkt->tcp->sport, seqno, ackno, NULL, 0);
4738+
}
4739+
4740+
static size_t tx_tcp_rst(struct mg_tcpip_if *ifp, struct pkt *pkt, bool toack) {
4741+
return tx_tcp_ctrlresp(ifp, pkt, toack ? TH_RST : (TH_RST | TH_ACK),
4742+
toack ? pkt->tcp->ack : 0);
47394743
}
47404744

47414745
static struct mg_connection *accept_conn(struct mg_connection *lsn,
@@ -4934,10 +4938,9 @@ static void read_conn(struct mg_connection *c, struct pkt *pkt) {
49344938
}
49354939
}
49364940

4937-
49384941
// TCP backlog
49394942
struct mg_backlog {
4940-
uint16_t port, mss; // use port=0 for available entries
4943+
uint16_t port, mss; // use port=0 for available entries
49414944
uint8_t age;
49424945
};
49434946

@@ -4947,7 +4950,7 @@ static int backlog_insert(struct mg_connection *c, uint16_t port,
49474950
size_t i;
49484951
for (i = 0; i < sizeof(c->data) / sizeof(*p); i++) {
49494952
if (p[i].port != 0) continue;
4950-
p[i].age = 2; // remove after two calls, average 1.5 call rate
4953+
p[i].age = 2; // remove after two calls, average 1.5 call rate
49514954
p[i].port = port, p[i].mss = mss;
49524955
return (int) i;
49534956
}
@@ -4970,7 +4973,7 @@ static void backlog_remove(struct mg_connection *c, uint16_t key) {
49704973

49714974
static void backlog_maintain(struct mg_connection *c) {
49724975
struct mg_backlog *p = (struct mg_backlog *) c->data;
4973-
size_t i; // dec age and remove those where it reaches 0
4976+
size_t i; // dec age and remove those where it reaches 0
49744977
for (i = 0; i < sizeof(c->data) / sizeof(*p); i++) {
49754978
if (p[i].port == 0) continue;
49764979
if (p[i].age != 0) --p[i].age;
@@ -5007,70 +5010,74 @@ static void handle_opt(struct connstate *s, struct tcp *tcp) {
50075010
static void rx_tcp(struct mg_tcpip_if *ifp, struct pkt *pkt) {
50085011
struct mg_connection *c = getpeer(ifp->mgr, pkt, false);
50095012
struct connstate *s = c == NULL ? NULL : (struct connstate *) (c + 1);
5010-
#if 0
5011-
MG_INFO(("%lu %hhu %d", c ? c->id : 0, pkt->tcp->flags, (int) pkt->pay.len));
5012-
#endif
5013+
// Order is VERY important; RFC-9293 3.5.2
5014+
// - check clients (Group 1) and established connections (Group 3)
50135015
if (c != NULL && c->is_connecting && pkt->tcp->flags == (TH_SYN | TH_ACK)) {
5016+
// client got a server connection accept
50145017
handle_opt(s, pkt->tcp); // process options (MSS)
50155018
s->seq = mg_ntohl(pkt->tcp->ack), s->ack = mg_ntohl(pkt->tcp->seq) + 1;
5016-
tx_tcp_pkt(ifp, pkt, TH_ACK, pkt->tcp->ack, NULL, 0);
5019+
tx_tcp_ctrlresp(ifp, pkt, TH_ACK, pkt->tcp->ack);
50175020
c->is_connecting = 0; // Client connected
50185021
settmout(c, MIP_TTYPE_KEEPALIVE);
50195022
mg_call(c, MG_EV_CONNECT, NULL); // Let user know
50205023
if (c->is_tls_hs) mg_tls_handshake(c);
50215024
if (!c->is_tls_hs) c->is_tls = 0; // user did not call mg_tls_init()
50225025
} else if (c != NULL && c->is_connecting && pkt->tcp->flags != TH_ACK) {
5023-
// mg_hexdump(pkt->raw.buf, pkt->raw.len);
5024-
tx_tcp_pkt(ifp, pkt, TH_RST | TH_ACK, pkt->tcp->ack, NULL, 0);
5026+
mg_error(c, "connection refused");
50255027
} else if (c != NULL && pkt->tcp->flags & TH_RST) {
5028+
// TODO(): validate RST is within window (and optional with proper ACK)
50265029
mg_error(c, "peer RST"); // RFC-1122 4.2.2.13
50275030
} else if (c != NULL) {
5028-
#if 0
5029-
MG_DEBUG(("%lu %d %M:%hu -> %M:%hu", c->id, (int) pkt->raw.len,
5030-
mg_print_ip4, &pkt->ip->src, mg_ntohs(pkt->tcp->sport),
5031-
mg_print_ip4, &pkt->ip->dst, mg_ntohs(pkt->tcp->dport)));
5032-
mg_hexdump(pkt->pay.buf, pkt->pay.len);
5033-
#endif
5031+
// process segment
50345032
s->tmiss = 0; // Reset missed keep-alive counter
50355033
if (s->ttype == MIP_TTYPE_KEEPALIVE) // Advance keep-alive timer
50365034
settmout(c,
50375035
MIP_TTYPE_KEEPALIVE); // unless a former ACK timeout is pending
50385036
read_conn(c, pkt); // Override timer with ACK timeout if needed
5039-
} else if ((c = getpeer(ifp->mgr, pkt, true)) == NULL) {
5040-
tx_tcp_pkt(ifp, pkt, TH_RST | TH_ACK, pkt->tcp->ack, NULL, 0);
5041-
} else if (pkt->tcp->flags & TH_RST) {
5042-
if (c->is_accepted) mg_error(c, "peer RST"); // RFC-1122 4.2.2.13
5043-
// ignore RST if not connected
5044-
} else if (pkt->tcp->flags & TH_SYN) {
5045-
struct connstate cs; // At this point, s = NULL, there is no connection
5046-
int key;
5047-
uint32_t isn;
5048-
if (pkt->tcp->sport != 0) {
5049-
handle_opt(&cs, pkt->tcp); // process options (MSS)
5050-
key = backlog_insert(c, pkt->tcp->sport, cs.dmss); // backlog options (MSS)
5051-
if (key < 0) return; // no room in backlog, discard SYN, client retries
5052-
// Use peer's src port and bl key as ISN, to later identify the handshake
5053-
isn = (mg_htonl(((uint32_t)key << 16) | mg_ntohs(pkt->tcp->sport)));
5054-
tx_tcp_pkt(ifp, pkt, TH_SYN | TH_ACK, isn, NULL, 0);
5055-
} // what should we do when port=0 ? Linux takes port 0 as any other port
5056-
} else if (pkt->tcp->flags & TH_FIN) {
5057-
tx_tcp_pkt(ifp, pkt, TH_FIN | TH_ACK, pkt->tcp->ack, NULL, 0);
5058-
} else if ((uint16_t) (mg_htonl(pkt->tcp->ack) - 1) ==
5059-
mg_htons(pkt->tcp->sport)) {
5060-
uint16_t key = (uint16_t) ((mg_htonl(pkt->tcp->ack) - 1) >> 16);
5061-
struct mg_backlog *b = backlog_retrieve(c, key, pkt->tcp->sport);
5062-
if (b != NULL) {
5063-
accept_conn(c, pkt, b->mss); // pass options
5064-
backlog_remove(c, key);
5065-
} else if (!c->is_accepted) { // not an actual match, reset
5066-
tx_tcp_pkt(ifp, pkt, TH_RST | TH_ACK, pkt->tcp->ack, NULL, 0);
5067-
// TODO(scaprile): revisit this and below, weird scenarios
5068-
}
5069-
} else if (!c->is_accepted) { // no peer
5070-
tx_tcp_pkt(ifp, pkt, TH_RST | TH_ACK, pkt->tcp->ack, NULL, 0);
5071-
} else {
5072-
// MG_VERBOSE(("dropped silently.."));
5073-
}
5037+
} else
5038+
// - we don't listen on that port; RFC-9293 3.5.2 Group 1
5039+
// - check listening connections; RFC-9293 3.5.2 Group 2
5040+
if ((c = getpeer(ifp->mgr, pkt, true)) == NULL) {
5041+
// not listening on that port
5042+
if (!(pkt->tcp->flags & TH_RST)) {
5043+
tx_tcp_rst(ifp, pkt, pkt->tcp->flags & TH_ACK);
5044+
} // else silently discard
5045+
} else if (pkt->tcp->flags == TH_SYN) {
5046+
// listener receives a connection request
5047+
struct connstate cs; // At this point, s = NULL, there is no connection
5048+
int key;
5049+
uint32_t isn;
5050+
if (pkt->tcp->sport != 0) {
5051+
handle_opt(&cs, pkt->tcp); // process options (MSS)
5052+
key = backlog_insert(c, pkt->tcp->sport,
5053+
cs.dmss); // backlog options (MSS)
5054+
if (key < 0) return; // no room in backlog, discard SYN, client retries
5055+
// Use peer's src port and bl key as ISN, to later identify the
5056+
// handshake
5057+
isn = (mg_htonl(((uint32_t) key << 16) | mg_ntohs(pkt->tcp->sport)));
5058+
tx_tcp_ctrlresp(ifp, pkt, TH_SYN | TH_ACK, isn);
5059+
} // what should we do when port=0 ? Linux takes port 0 as any other
5060+
// port
5061+
} else if (pkt->tcp->flags == TH_ACK) {
5062+
// listener receives an ACK
5063+
struct mg_backlog *b = NULL;
5064+
if ((uint16_t) (mg_htonl(pkt->tcp->ack) - 1) ==
5065+
mg_htons(pkt->tcp->sport)) {
5066+
uint16_t key = (uint16_t) ((mg_htonl(pkt->tcp->ack) - 1) >> 16);
5067+
b = backlog_retrieve(c, key, pkt->tcp->sport);
5068+
if (b != NULL) { // ACK is a response to a SYN+ACK
5069+
accept_conn(c, pkt, b->mss); // pass options
5070+
backlog_remove(c, key);
5071+
} // else not an actual match, reset
5072+
}
5073+
if (b == NULL) tx_tcp_rst(ifp, pkt, true);
5074+
} else if (pkt->tcp->flags & TH_RST) {
5075+
// silently discard
5076+
} else if (pkt->tcp->flags & TH_ACK) { // ACK + something else != RST
5077+
tx_tcp_rst(ifp, pkt, true);
5078+
} else if (pkt->tcp->flags & TH_SYN) { // SYN + something else != ACK
5079+
tx_tcp_rst(ifp, pkt, false);
5080+
} // else silently discard
50745081
}
50755082

50765083
static void rx_ip(struct mg_tcpip_if *ifp, struct pkt *pkt) {
@@ -5090,6 +5097,7 @@ static void rx_ip(struct mg_tcpip_if *ifp, struct pkt *pkt) {
50905097
pkt->udp = (struct udp *) (pkt->ip + 1);
50915098
if (pkt->pay.len < sizeof(*pkt->udp)) return;
50925099
mkpay(pkt, pkt->udp + 1);
5100+
if (pkt->udp->len < pkt->pay.len) pkt->pay.len = pkt->udp->len;
50935101
MG_VERBOSE(("UDP %M:%hu -> %M:%hu len %u", mg_print_ip4, &pkt->ip->src,
50945102
mg_ntohs(pkt->udp->sport), mg_print_ip4, &pkt->ip->dst,
50955103
mg_ntohs(pkt->udp->dport), (int) pkt->pay.len));
@@ -5108,7 +5116,7 @@ static void rx_ip(struct mg_tcpip_if *ifp, struct pkt *pkt) {
51085116
uint16_t iplen, off;
51095117
pkt->tcp = (struct tcp *) (pkt->ip + 1);
51105118
if (pkt->pay.len < sizeof(*pkt->tcp)) return;
5111-
mkpay(pkt, pkt->tcp + 1);
5119+
mkpay(pkt, (uint32_t *) pkt->tcp + (pkt->tcp->off >> 4)); // may have opts
51125120
iplen = mg_ntohs(pkt->ip->len);
51135121
off = (uint16_t) (sizeof(*pkt->ip) + ((pkt->tcp->off >> 4) * 4U));
51145122
if (iplen >= off) pkt->pay.len = (size_t) (iplen - off);

src/net_builtin.c

Lines changed: 66 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -572,13 +572,17 @@ static size_t tx_tcp(struct mg_tcpip_if *ifp, uint8_t *dst_mac, uint32_t dst_ip,
572572
return ether_output(ifp, PDIFF(ifp->tx.buf, tcp + 1) + len);
573573
}
574574

575-
static size_t tx_tcp_pkt(struct mg_tcpip_if *ifp, struct pkt *pkt,
576-
uint8_t flags, uint32_t seq, const void *buf,
577-
size_t len) {
578-
uint32_t delta = (pkt->tcp->flags & (TH_SYN | TH_FIN)) ? 1 : 0;
575+
static size_t tx_tcp_ctrlresp(struct mg_tcpip_if *ifp, struct pkt *pkt,
576+
uint8_t flags, uint32_t seqno) {
577+
uint32_t ackno = mg_htonl(mg_ntohl(pkt->tcp->seq) + (uint32_t) pkt->pay.len +
578+
((pkt->tcp->flags & (TH_SYN | TH_FIN)) ? 1 : 0));
579579
return tx_tcp(ifp, pkt->eth->src, pkt->ip->src, flags, pkt->tcp->dport,
580-
pkt->tcp->sport, seq, mg_htonl(mg_ntohl(pkt->tcp->seq) + delta),
581-
buf, len);
580+
pkt->tcp->sport, seqno, ackno, NULL, 0);
581+
}
582+
583+
static size_t tx_tcp_rst(struct mg_tcpip_if *ifp, struct pkt *pkt, bool toack) {
584+
return tx_tcp_ctrlresp(ifp, pkt, toack ? TH_RST : (TH_RST | TH_ACK),
585+
toack ? pkt->tcp->ack : 0);
582586
}
583587

584588
static struct mg_connection *accept_conn(struct mg_connection *lsn,
@@ -777,10 +781,9 @@ static void read_conn(struct mg_connection *c, struct pkt *pkt) {
777781
}
778782
}
779783

780-
781784
// TCP backlog
782785
struct mg_backlog {
783-
uint16_t port, mss; // use port=0 for available entries
786+
uint16_t port, mss; // use port=0 for available entries
784787
uint8_t age;
785788
};
786789

@@ -790,7 +793,7 @@ static int backlog_insert(struct mg_connection *c, uint16_t port,
790793
size_t i;
791794
for (i = 0; i < sizeof(c->data) / sizeof(*p); i++) {
792795
if (p[i].port != 0) continue;
793-
p[i].age = 2; // remove after two calls, average 1.5 call rate
796+
p[i].age = 2; // remove after two calls, average 1.5 call rate
794797
p[i].port = port, p[i].mss = mss;
795798
return (int) i;
796799
}
@@ -813,7 +816,7 @@ static void backlog_remove(struct mg_connection *c, uint16_t key) {
813816

814817
static void backlog_maintain(struct mg_connection *c) {
815818
struct mg_backlog *p = (struct mg_backlog *) c->data;
816-
size_t i; // dec age and remove those where it reaches 0
819+
size_t i; // dec age and remove those where it reaches 0
817820
for (i = 0; i < sizeof(c->data) / sizeof(*p); i++) {
818821
if (p[i].port == 0) continue;
819822
if (p[i].age != 0) --p[i].age;
@@ -850,70 +853,74 @@ static void handle_opt(struct connstate *s, struct tcp *tcp) {
850853
static void rx_tcp(struct mg_tcpip_if *ifp, struct pkt *pkt) {
851854
struct mg_connection *c = getpeer(ifp->mgr, pkt, false);
852855
struct connstate *s = c == NULL ? NULL : (struct connstate *) (c + 1);
853-
#if 0
854-
MG_INFO(("%lu %hhu %d", c ? c->id : 0, pkt->tcp->flags, (int) pkt->pay.len));
855-
#endif
856+
// Order is VERY important; RFC-9293 3.5.2
857+
// - check clients (Group 1) and established connections (Group 3)
856858
if (c != NULL && c->is_connecting && pkt->tcp->flags == (TH_SYN | TH_ACK)) {
859+
// client got a server connection accept
857860
handle_opt(s, pkt->tcp); // process options (MSS)
858861
s->seq = mg_ntohl(pkt->tcp->ack), s->ack = mg_ntohl(pkt->tcp->seq) + 1;
859-
tx_tcp_pkt(ifp, pkt, TH_ACK, pkt->tcp->ack, NULL, 0);
862+
tx_tcp_ctrlresp(ifp, pkt, TH_ACK, pkt->tcp->ack);
860863
c->is_connecting = 0; // Client connected
861864
settmout(c, MIP_TTYPE_KEEPALIVE);
862865
mg_call(c, MG_EV_CONNECT, NULL); // Let user know
863866
if (c->is_tls_hs) mg_tls_handshake(c);
864867
if (!c->is_tls_hs) c->is_tls = 0; // user did not call mg_tls_init()
865868
} else if (c != NULL && c->is_connecting && pkt->tcp->flags != TH_ACK) {
866-
// mg_hexdump(pkt->raw.buf, pkt->raw.len);
867-
tx_tcp_pkt(ifp, pkt, TH_RST | TH_ACK, pkt->tcp->ack, NULL, 0);
869+
mg_error(c, "connection refused");
868870
} else if (c != NULL && pkt->tcp->flags & TH_RST) {
871+
// TODO(): validate RST is within window (and optional with proper ACK)
869872
mg_error(c, "peer RST"); // RFC-1122 4.2.2.13
870873
} else if (c != NULL) {
871-
#if 0
872-
MG_DEBUG(("%lu %d %M:%hu -> %M:%hu", c->id, (int) pkt->raw.len,
873-
mg_print_ip4, &pkt->ip->src, mg_ntohs(pkt->tcp->sport),
874-
mg_print_ip4, &pkt->ip->dst, mg_ntohs(pkt->tcp->dport)));
875-
mg_hexdump(pkt->pay.buf, pkt->pay.len);
876-
#endif
874+
// process segment
877875
s->tmiss = 0; // Reset missed keep-alive counter
878876
if (s->ttype == MIP_TTYPE_KEEPALIVE) // Advance keep-alive timer
879877
settmout(c,
880878
MIP_TTYPE_KEEPALIVE); // unless a former ACK timeout is pending
881879
read_conn(c, pkt); // Override timer with ACK timeout if needed
882-
} else if ((c = getpeer(ifp->mgr, pkt, true)) == NULL) {
883-
tx_tcp_pkt(ifp, pkt, TH_RST | TH_ACK, pkt->tcp->ack, NULL, 0);
884-
} else if (pkt->tcp->flags & TH_RST) {
885-
if (c->is_accepted) mg_error(c, "peer RST"); // RFC-1122 4.2.2.13
886-
// ignore RST if not connected
887-
} else if (pkt->tcp->flags & TH_SYN) {
888-
struct connstate cs; // At this point, s = NULL, there is no connection
889-
int key;
890-
uint32_t isn;
891-
if (pkt->tcp->sport != 0) {
892-
handle_opt(&cs, pkt->tcp); // process options (MSS)
893-
key = backlog_insert(c, pkt->tcp->sport, cs.dmss); // backlog options (MSS)
894-
if (key < 0) return; // no room in backlog, discard SYN, client retries
895-
// Use peer's src port and bl key as ISN, to later identify the handshake
896-
isn = (mg_htonl(((uint32_t)key << 16) | mg_ntohs(pkt->tcp->sport)));
897-
tx_tcp_pkt(ifp, pkt, TH_SYN | TH_ACK, isn, NULL, 0);
898-
} // what should we do when port=0 ? Linux takes port 0 as any other port
899-
} else if (pkt->tcp->flags & TH_FIN) {
900-
tx_tcp_pkt(ifp, pkt, TH_FIN | TH_ACK, pkt->tcp->ack, NULL, 0);
901-
} else if ((uint16_t) (mg_htonl(pkt->tcp->ack) - 1) ==
902-
mg_htons(pkt->tcp->sport)) {
903-
uint16_t key = (uint16_t) ((mg_htonl(pkt->tcp->ack) - 1) >> 16);
904-
struct mg_backlog *b = backlog_retrieve(c, key, pkt->tcp->sport);
905-
if (b != NULL) {
906-
accept_conn(c, pkt, b->mss); // pass options
907-
backlog_remove(c, key);
908-
} else if (!c->is_accepted) { // not an actual match, reset
909-
tx_tcp_pkt(ifp, pkt, TH_RST | TH_ACK, pkt->tcp->ack, NULL, 0);
910-
// TODO(scaprile): revisit this and below, weird scenarios
911-
}
912-
} else if (!c->is_accepted) { // no peer
913-
tx_tcp_pkt(ifp, pkt, TH_RST | TH_ACK, pkt->tcp->ack, NULL, 0);
914-
} else {
915-
// MG_VERBOSE(("dropped silently.."));
916-
}
880+
} else
881+
// - we don't listen on that port; RFC-9293 3.5.2 Group 1
882+
// - check listening connections; RFC-9293 3.5.2 Group 2
883+
if ((c = getpeer(ifp->mgr, pkt, true)) == NULL) {
884+
// not listening on that port
885+
if (!(pkt->tcp->flags & TH_RST)) {
886+
tx_tcp_rst(ifp, pkt, pkt->tcp->flags & TH_ACK);
887+
} // else silently discard
888+
} else if (pkt->tcp->flags == TH_SYN) {
889+
// listener receives a connection request
890+
struct connstate cs; // At this point, s = NULL, there is no connection
891+
int key;
892+
uint32_t isn;
893+
if (pkt->tcp->sport != 0) {
894+
handle_opt(&cs, pkt->tcp); // process options (MSS)
895+
key = backlog_insert(c, pkt->tcp->sport,
896+
cs.dmss); // backlog options (MSS)
897+
if (key < 0) return; // no room in backlog, discard SYN, client retries
898+
// Use peer's src port and bl key as ISN, to later identify the
899+
// handshake
900+
isn = (mg_htonl(((uint32_t) key << 16) | mg_ntohs(pkt->tcp->sport)));
901+
tx_tcp_ctrlresp(ifp, pkt, TH_SYN | TH_ACK, isn);
902+
} // what should we do when port=0 ? Linux takes port 0 as any other
903+
// port
904+
} else if (pkt->tcp->flags == TH_ACK) {
905+
// listener receives an ACK
906+
struct mg_backlog *b = NULL;
907+
if ((uint16_t) (mg_htonl(pkt->tcp->ack) - 1) ==
908+
mg_htons(pkt->tcp->sport)) {
909+
uint16_t key = (uint16_t) ((mg_htonl(pkt->tcp->ack) - 1) >> 16);
910+
b = backlog_retrieve(c, key, pkt->tcp->sport);
911+
if (b != NULL) { // ACK is a response to a SYN+ACK
912+
accept_conn(c, pkt, b->mss); // pass options
913+
backlog_remove(c, key);
914+
} // else not an actual match, reset
915+
}
916+
if (b == NULL) tx_tcp_rst(ifp, pkt, true);
917+
} else if (pkt->tcp->flags & TH_RST) {
918+
// silently discard
919+
} else if (pkt->tcp->flags & TH_ACK) { // ACK + something else != RST
920+
tx_tcp_rst(ifp, pkt, true);
921+
} else if (pkt->tcp->flags & TH_SYN) { // SYN + something else != ACK
922+
tx_tcp_rst(ifp, pkt, false);
923+
} // else silently discard
917924
}
918925

919926
static void rx_ip(struct mg_tcpip_if *ifp, struct pkt *pkt) {
@@ -933,6 +940,7 @@ static void rx_ip(struct mg_tcpip_if *ifp, struct pkt *pkt) {
933940
pkt->udp = (struct udp *) (pkt->ip + 1);
934941
if (pkt->pay.len < sizeof(*pkt->udp)) return;
935942
mkpay(pkt, pkt->udp + 1);
943+
if (pkt->udp->len < pkt->pay.len) pkt->pay.len = pkt->udp->len;
936944
MG_VERBOSE(("UDP %M:%hu -> %M:%hu len %u", mg_print_ip4, &pkt->ip->src,
937945
mg_ntohs(pkt->udp->sport), mg_print_ip4, &pkt->ip->dst,
938946
mg_ntohs(pkt->udp->dport), (int) pkt->pay.len));
@@ -951,7 +959,7 @@ static void rx_ip(struct mg_tcpip_if *ifp, struct pkt *pkt) {
951959
uint16_t iplen, off;
952960
pkt->tcp = (struct tcp *) (pkt->ip + 1);
953961
if (pkt->pay.len < sizeof(*pkt->tcp)) return;
954-
mkpay(pkt, pkt->tcp + 1);
962+
mkpay(pkt, (uint32_t *) pkt->tcp + (pkt->tcp->off >> 4)); // may have opts
955963
iplen = mg_ntohs(pkt->ip->len);
956964
off = (uint16_t) (sizeof(*pkt->ip) + ((pkt->tcp->off >> 4) * 4U));
957965
if (iplen >= off) pkt->pay.len = (size_t) (iplen - off);

0 commit comments

Comments
 (0)