From f33e3a7752b55e88f8627c784e39634c82ec4dab Mon Sep 17 00:00:00 2001 From: robert Date: Wed, 30 Aug 2023 06:43:38 -0400 Subject: [PATCH] closing connection if a fragmented packet is received --- mongoose.c | 10 ++++- src/net_builtin.c | 10 ++++- test/mip_test.c | 96 +++++++++++++++++++++++++++++++++++++---------- 3 files changed, 95 insertions(+), 21 deletions(-) diff --git a/mongoose.c b/mongoose.c index 9edde71d4b..31fcbe4044 100644 --- a/mongoose.c +++ b/mongoose.c @@ -3876,6 +3876,8 @@ struct ip { uint16_t len; // Length uint16_t id; // Unused uint16_t frag; // Fragmentation +#define IP_FRAG_OFFSET_MSK 0xFF1F +#define IP_MORE_FRAGS_MSK 0x20 uint8_t ttl; // Time to live uint8_t proto; // Upper level protocol uint16_t csum; // Checksum @@ -4552,7 +4554,13 @@ static void rx_tcp(struct mg_tcpip_if *ifp, struct pkt *pkt) { } static void rx_ip(struct mg_tcpip_if *ifp, struct pkt *pkt) { - if (pkt->ip->proto == 1) { + if (pkt->ip->frag & IP_MORE_FRAGS_MSK || + pkt->ip->frag & IP_FRAG_OFFSET_MSK) { + if (pkt->ip->proto == 17) pkt->udp = (struct udp *) (pkt->ip + 1); + if (pkt->ip->proto == 6) pkt->tcp = (struct tcp *) (pkt->ip + 1); + struct mg_connection *c = getpeer(ifp->mgr, pkt, false); + if (c) mg_error(c, "Received fragmented packet"); + } else if (pkt->ip->proto == 1) { pkt->icmp = (struct icmp *) (pkt->ip + 1); if (pkt->pay.len < sizeof(*pkt->icmp)) return; mkpay(pkt, pkt->icmp + 1); diff --git a/src/net_builtin.c b/src/net_builtin.c index 47049f1429..f2d5ff757a 100644 --- a/src/net_builtin.c +++ b/src/net_builtin.c @@ -45,6 +45,8 @@ struct ip { uint16_t len; // Length uint16_t id; // Unused uint16_t frag; // Fragmentation +#define IP_FRAG_OFFSET_MSK 0xFF1F +#define IP_MORE_FRAGS_MSK 0x20 uint8_t ttl; // Time to live uint8_t proto; // Upper level protocol uint16_t csum; // Checksum @@ -721,7 +723,13 @@ static void rx_tcp(struct mg_tcpip_if *ifp, struct pkt *pkt) { } static void rx_ip(struct mg_tcpip_if *ifp, struct pkt *pkt) { - if (pkt->ip->proto == 1) { + if (pkt->ip->frag & IP_MORE_FRAGS_MSK || + pkt->ip->frag & IP_FRAG_OFFSET_MSK) { + if (pkt->ip->proto == 17) pkt->udp = (struct udp *) (pkt->ip + 1); + if (pkt->ip->proto == 6) pkt->tcp = (struct tcp *) (pkt->ip + 1); + struct mg_connection *c = getpeer(ifp->mgr, pkt, false); + if (c) mg_error(c, "Received fragmented packet"); + } else if (pkt->ip->proto == 1) { pkt->icmp = (struct icmp *) (pkt->ip + 1); if (pkt->pay.len < sizeof(*pkt->icmp)) return; mkpay(pkt, pkt->icmp + 1); diff --git a/test/mip_test.c b/test/mip_test.c index be44cf775e..4a9f70e82d 100644 --- a/test/mip_test.c +++ b/test/mip_test.c @@ -7,6 +7,7 @@ #include "driver_mock.c" static int s_num_tests = 0; +static bool s_sent_fragment = 0; #define ASSERT(expr) \ do { \ @@ -33,6 +34,15 @@ static void ph(struct mg_connection *c, int ev, void *ev_data, void *fn_data) { (void) c, (void) ev_data; } +static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) { + if (ev == MG_EV_ERROR) { + if (s_sent_fragment) { + ASSERT(strcmp((char*) ev_data, "Received fragmented packet") == 0); + } + } + (void) c, (void) ev_data, (void) fn_data; +} + static void test_poll(void) { int count = 0, i; struct mg_mgr mgr; @@ -101,16 +111,33 @@ static void create_tcp_pkt(struct eth *e, struct ip *ip, uint32_t seq, + sizeof(struct tcp) + payload_len; } +static void init_tcp_handshake(struct eth *e, struct ip *ip, struct tcp *tcp, + struct mg_mgr *mgr) { + // SYN + create_tcp_pkt(e, ip, 1000, 0, TH_SYN | TH_ACK, 0); + mg_mgr_poll(mgr, 0); + + // SYN-ACK + while(!received_response(&s_driver_data)) mg_mgr_poll(mgr, 0); + tcp = (struct tcp *) (s_driver_data.buf + sizeof(struct eth) + + sizeof(struct ip)); + ASSERT((tcp->flags == (TH_SYN | TH_ACK))); + ASSERT((tcp->ack == mg_htonl(1001))); + + // ACK + create_tcp_pkt(e, ip, 1001, 1, TH_ACK, 0); + mg_mgr_poll(mgr, 0); +} + static void test_retransmit(void) { struct mg_mgr mgr; struct eth e; struct ip ip; - struct tcp *t; + struct tcp *t = NULL; uint64_t start, now; bool response_recv = true; struct mg_tcpip_driver driver; struct mg_tcpip_if mif; - struct mg_connection *c; mg_mgr_init(&mgr); memset(&mif, 0, sizeof(mif)); @@ -119,9 +146,8 @@ static void test_retransmit(void) { mif.driver = &driver; mif.driver_data = &s_driver_data; mg_tcpip_init(&mgr, &mif); - c = mg_alloc_conn(&mgr); // create dummy connection - LIST_ADD_HEAD(struct mg_connection, &mgr.conns, c); - c->is_listening = 1; + mg_http_listen(&mgr, "http://0.0.0.0:0", fn, NULL); + mgr.conns->pfn = NULL; // HTTP handler not needed mg_mgr_poll(&mgr, 0); // setting the Ethernet header @@ -134,20 +160,7 @@ static void test_retransmit(void) { ip.ver = 4 << 4, ip.proto = 6; ip.len = mg_htons(sizeof(ip) + sizeof(struct tcp)); - // SYN - create_tcp_pkt(&e, &ip, 1000, 0, TH_SYN | TH_ACK, 0); - mg_mgr_poll(&mgr, 0); - - // SYN-ACK - while(!received_response(&s_driver_data)) mg_mgr_poll(&mgr, 0); - t = (struct tcp *) (s_driver_data.buf + sizeof(struct eth) + - sizeof(struct ip)); - ASSERT((t->flags == (TH_SYN | TH_ACK))); - ASSERT((t->ack == mg_htonl(1001))); - - // ACK - create_tcp_pkt(&e, &ip, 1001, 1, TH_ACK, 0); - mg_mgr_poll(&mgr, 0); + init_tcp_handshake(&e, &ip, t, &mgr); // packet with seq_no = 1001 ip.len = @@ -204,10 +217,55 @@ static void test_retransmit(void) { mg_tcpip_free(&mif); } +static void test_fragmentation(void) { + struct mg_mgr mgr; + struct eth e; + struct ip ip; + struct tcp *t = NULL; + struct mg_tcpip_driver driver; + struct mg_tcpip_if mif; + + mg_mgr_init(&mgr); + memset(&mif, 0, sizeof(mif)); + memset(&s_driver_data, 0, sizeof(struct driver_data)); + driver.init = NULL, driver.tx = if_tx, driver.up = if_up, driver.rx = if_rx; + mif.driver = &driver; + mif.driver_data = &s_driver_data; + mg_tcpip_init(&mgr, &mif); + mg_http_listen(&mgr, "http://0.0.0.0:0", fn, NULL); + mgr.conns->pfn = NULL; + mg_mgr_poll(&mgr, 0); + + // setting the Ethernet header + memset(&e, 0, sizeof(e)); + memcpy(e.dst, mif.mac, 6 * sizeof(uint8_t)); + e.type = mg_htons(0x800); + + // setting the IP header + memset(&ip, 0, sizeof(ip)); + ip.ver = 0x45, ip.proto = 6; + ip.len = mg_htons(sizeof(ip) + sizeof(struct tcp)); + + init_tcp_handshake(&e, &ip, t, &mgr); + + // send fragmented TCP packet + ip.len = + mg_htons(sizeof(struct ip) + sizeof(struct tcp) + 1000); + ip.frag |= IP_MORE_FRAGS_MSK; // setting More Fragments bit to 1 + create_tcp_pkt(&e, &ip, 1001, 1, TH_PUSH | TH_ACK, 1000); + s_sent_fragment = true; + mg_mgr_poll(&mgr, 0); + + s_driver_data.len = 0; + mg_mgr_free(&mgr); + mg_tcpip_free(&mif); +} + int main(void) { test_statechange(); test_poll(); test_retransmit(); + test_fragmentation(); printf("SUCCESS. Total tests: %d\n", s_num_tests); return 0; }