Skip to content

Commit 04d6d05

Browse files
authored
Merge pull request #3258 from cesanta/tcput
Fix TCP error handling
2 parents c1152f5 + 7339c7d commit 04d6d05

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)