Skip to content

Commit

Permalink
closing connection if a fragmented packet is received
Browse files Browse the repository at this point in the history
  • Loading branch information
robert committed Aug 30, 2023
1 parent d5b5cec commit f33e3a7
Show file tree
Hide file tree
Showing 3 changed files with 95 additions and 21 deletions.
10 changes: 9 additions & 1 deletion mongoose.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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);
Expand Down
10 changes: 9 additions & 1 deletion src/net_builtin.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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);
Expand Down
96 changes: 77 additions & 19 deletions test/mip_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include "driver_mock.c"

static int s_num_tests = 0;
static bool s_sent_fragment = 0;

#define ASSERT(expr) \
do { \
Expand All @@ -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;
Expand Down Expand Up @@ -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));
Expand All @@ -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
Expand All @@ -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 =
Expand Down Expand Up @@ -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;
}

0 comments on commit f33e3a7

Please sign in to comment.