Skip to content

Commit b3a0e7b

Browse files
committed
fix extension header traversal
1 parent 8594507 commit b3a0e7b

File tree

2 files changed

+100
-86
lines changed

2 files changed

+100
-86
lines changed

mongoose.c

Lines changed: 50 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -5172,59 +5172,65 @@ static void rx_ip(struct mg_tcpip_if *ifp, struct pkt *pkt) {
51725172
mg_ntohs(pkt->tcp->dport), (int) pkt->pay.len));
51735173
rx_tcp(ifp, pkt);
51745174
} else {
5175-
MG_DEBUG(("Unknown IP proto %x", mg_htons(pkt->ip->proto)));
5176-
if (mg_log_level >= MG_LL_VERBOSE) mg_hexdump(pkt->ip, pkt->pay.len >= 32 ? 32 : pkt->pay.len);
5177-
}
5178-
}
5179-
5180-
static bool ip6_handle_opt(struct ip6 *h) {
5181-
switch(h->next) {
5182-
case 0:
5183-
case 43:
5184-
case 44:
5185-
case 50:
5186-
case 51:
5187-
case 60:
5188-
case 135:
5189-
case 139:
5190-
case 140:
5191-
case 253:
5192-
case 254:
5193-
MG_INFO(("IPv6 extension header %d", (int) h->next));
5194-
break;
5195-
default:
5196-
return false;
5175+
MG_DEBUG(("Unknown IP proto %x", (int) pkt->ip->proto));
5176+
if (mg_log_level >= MG_LL_VERBOSE)
5177+
mg_hexdump(pkt->ip, pkt->pay.len >= 32 ? 32 : pkt->pay.len);
51975178
}
5198-
return true;
51995179
}
52005180

52015181
static void rx_ip6(struct mg_tcpip_if *ifp, struct pkt *pkt) {
5202-
struct ip6 *hdr;
5203-
uint16_t len;
5182+
uint16_t len = 0;
5183+
uint8_t next, *nhdr;
5184+
bool loop = true;
52045185
if (pkt->pay.len < sizeof(*pkt->ip6)) return; // Truncated
52055186
if ((pkt->ip6->ver >> 4) != 0x6) return; // Not IPv6
5206-
hdr = pkt->ip6;
5207-
while (ip6_handle_opt(hdr)) ++hdr;
5208-
// There can be link padding, take payload length from IPv6 last header
5209-
len = mg_ntohs(hdr->plen); // IPv6 datagram reported payload length
5210-
if ((len + (size_t) hdr - (size_t) pkt->ip6) > pkt->pay.len) return;
5211-
pkt->pay.buf = (char *)(hdr + 1);
5212-
pkt->pay.len = len; // strip padding
5213-
if (hdr->next == 58) {
5187+
next = pkt->ip6->next;
5188+
nhdr = (uint8_t *) (pkt->ip6 + 1);
5189+
while (loop) {
5190+
switch (next) {
5191+
case 0: // Hop-by-Hop 4.3
5192+
case 43: // Routing 4.4
5193+
case 60: // Destination Options 4.6
5194+
case 51: // Authentication RFC-4302
5195+
MG_INFO(("IPv6 extension header %d", (int) next));
5196+
next = nhdr[0];
5197+
len += 8 * (nhdr[1] + 1);
5198+
nhdr += 8 * (nhdr[1] + 1);
5199+
break;
5200+
case 44: // Fragment 4.5
5201+
{
5202+
struct mg_connection *c;
5203+
if (nhdr[0] == 17) pkt->udp = (struct udp *) (pkt->pay.buf);
5204+
if (nhdr[0] == 6) pkt->tcp = (struct tcp *) (pkt->pay.buf);
5205+
c = getpeer(ifp->mgr, pkt, false);
5206+
if (c) mg_error(c, "Received fragmented packet");
5207+
}
5208+
return;
5209+
case 59: // No Next Header 4.7
5210+
return;
5211+
case 50: // IPsec ESP RFC-4303, unsupported
5212+
default:
5213+
loop = false;
5214+
break;
5215+
}
5216+
}
5217+
// There can be link padding, take payload length from IPv6 header - options
5218+
pkt->pay.buf = nhdr;
5219+
pkt->pay.len = mg_ntohs(pkt->ip6->plen) - len;
5220+
if (next == 58) {
52145221
pkt->icmp6 = (struct icmp6 *) (pkt->pay.buf);
52155222
if (pkt->pay.len < sizeof(*pkt->icmp6)) return;
52165223
mkpay(pkt, pkt->icmp6 + 1);
52175224
MG_DEBUG(("ICMPv6 %M -> %M len %u", mg_print_ip6, &pkt->ip6->src,
5218-
mg_print_ip6, &pkt->ip6->dst,
5219-
(int) pkt->pay.len));
5225+
mg_print_ip6, &pkt->ip6->dst, (int) pkt->pay.len));
52205226
// rx_icmp6(ifp, pkt);
5221-
} else if (hdr->next == 17) {
5227+
} else if (next == 17) {
52225228
pkt->udp = (struct udp *) (pkt->pay.buf);
52235229
if (pkt->pay.len < sizeof(*pkt->udp)) return;
52245230
mkpay(pkt, pkt->udp + 1);
52255231
MG_DEBUG(("UDP %M:%hu -> %M:%hu len %u", mg_print_ip6, &pkt->ip6->src,
5226-
mg_ntohs(pkt->udp->sport), mg_print_ip6, &pkt->ip6->dst,
5227-
mg_ntohs(pkt->udp->dport), (int) pkt->pay.len));
5232+
mg_ntohs(pkt->udp->sport), mg_print_ip6, &pkt->ip6->dst,
5233+
mg_ntohs(pkt->udp->dport), (int) pkt->pay.len));
52285234
if (ifp->enable_dhcp_client && pkt->udp->dport == mg_htons(546)) {
52295235
pkt->dhcp6 = (struct dhcp6 *) (pkt->udp + 1);
52305236
mkpay(pkt, pkt->dhcp6 + 1);
@@ -5236,20 +5242,21 @@ static void rx_ip6(struct mg_tcpip_if *ifp, struct pkt *pkt) {
52365242
} else if (!rx_udp(ifp, pkt)) {
52375243
// Should send ICMPv6 Destination Unreachable for unicasts, keep silent
52385244
}
5239-
} else if (hdr->next == 6) {
5245+
} else if (next == 6) {
52405246
uint8_t off;
52415247
pkt->tcp = (struct tcp *) (pkt->pay.buf);
52425248
if (pkt->pay.len < sizeof(*pkt->tcp)) return;
52435249
off = pkt->tcp->off >> 4; // account for opts
52445250
if (pkt->pay.len < sizeof(*pkt->tcp) + 4 * off) return;
52455251
mkpay(pkt, (uint32_t *) pkt->tcp + off);
52465252
MG_DEBUG(("TCP %M:%hu -> %M:%hu len %u", mg_print_ip6, &pkt->ip6->src,
5247-
mg_ntohs(pkt->tcp->sport), mg_print_ip6, &pkt->ip6->dst,
5248-
mg_ntohs(pkt->tcp->dport), (int) pkt->pay.len));
5253+
mg_ntohs(pkt->tcp->sport), mg_print_ip6, &pkt->ip6->dst,
5254+
mg_ntohs(pkt->tcp->dport), (int) pkt->pay.len));
52495255
rx_tcp(ifp, pkt);
52505256
} else {
5251-
MG_DEBUG(("Unknown IPv6 next hdr %x", mg_htons(hdr->next)));
5252-
if (mg_log_level >= MG_LL_VERBOSE) mg_hexdump(pkt->ip6, pkt->pay.len >= 32 ? 32 : pkt->pay.len);
5257+
MG_DEBUG(("Unknown IPv6 next hdr %x", (int) next));
5258+
if (mg_log_level >= MG_LL_VERBOSE)
5259+
mg_hexdump(pkt->ip6, pkt->pay.len >= 32 ? 32 : pkt->pay.len);
52535260
}
52545261
}
52555262

src/net_builtin.c

Lines changed: 50 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1015,59 +1015,65 @@ static void rx_ip(struct mg_tcpip_if *ifp, struct pkt *pkt) {
10151015
mg_ntohs(pkt->tcp->dport), (int) pkt->pay.len));
10161016
rx_tcp(ifp, pkt);
10171017
} else {
1018-
MG_DEBUG(("Unknown IP proto %x", mg_htons(pkt->ip->proto)));
1019-
if (mg_log_level >= MG_LL_VERBOSE) mg_hexdump(pkt->ip, pkt->pay.len >= 32 ? 32 : pkt->pay.len);
1018+
MG_DEBUG(("Unknown IP proto %x", (int) pkt->ip->proto));
1019+
if (mg_log_level >= MG_LL_VERBOSE)
1020+
mg_hexdump(pkt->ip, pkt->pay.len >= 32 ? 32 : pkt->pay.len);
10201021
}
10211022
}
10221023

1023-
static bool ip6_handle_opt(struct ip6 *h) {
1024-
switch(h->next) {
1025-
case 0:
1026-
case 43:
1027-
case 44:
1028-
case 50:
1029-
case 51:
1030-
case 60:
1031-
case 135:
1032-
case 139:
1033-
case 140:
1034-
case 253:
1035-
case 254:
1036-
MG_INFO(("IPv6 extension header %d", (int) h->next));
1037-
break;
1038-
default:
1039-
return false;
1040-
}
1041-
return true;
1042-
}
1043-
10441024
static void rx_ip6(struct mg_tcpip_if *ifp, struct pkt *pkt) {
1045-
struct ip6 *hdr;
1046-
uint16_t len;
1025+
uint16_t len = 0;
1026+
uint8_t next, *nhdr;
1027+
bool loop = true;
10471028
if (pkt->pay.len < sizeof(*pkt->ip6)) return; // Truncated
10481029
if ((pkt->ip6->ver >> 4) != 0x6) return; // Not IPv6
1049-
hdr = pkt->ip6;
1050-
while (ip6_handle_opt(hdr)) ++hdr;
1051-
// There can be link padding, take payload length from IPv6 last header
1052-
len = mg_ntohs(hdr->plen); // IPv6 datagram reported payload length
1053-
if ((len + (size_t) hdr - (size_t) pkt->ip6) > pkt->pay.len) return;
1054-
pkt->pay.buf = (char *)(hdr + 1);
1055-
pkt->pay.len = len; // strip padding
1056-
if (hdr->next == 58) {
1030+
next = pkt->ip6->next;
1031+
nhdr = (uint8_t *) (pkt->ip6 + 1);
1032+
while (loop) {
1033+
switch (next) {
1034+
case 0: // Hop-by-Hop 4.3
1035+
case 43: // Routing 4.4
1036+
case 60: // Destination Options 4.6
1037+
case 51: // Authentication RFC-4302
1038+
MG_INFO(("IPv6 extension header %d", (int) next));
1039+
next = nhdr[0];
1040+
len += 8 * (nhdr[1] + 1);
1041+
nhdr += 8 * (nhdr[1] + 1);
1042+
break;
1043+
case 44: // Fragment 4.5
1044+
{
1045+
struct mg_connection *c;
1046+
if (nhdr[0] == 17) pkt->udp = (struct udp *) (pkt->pay.buf);
1047+
if (nhdr[0] == 6) pkt->tcp = (struct tcp *) (pkt->pay.buf);
1048+
c = getpeer(ifp->mgr, pkt, false);
1049+
if (c) mg_error(c, "Received fragmented packet");
1050+
}
1051+
return;
1052+
case 59: // No Next Header 4.7
1053+
return;
1054+
case 50: // IPsec ESP RFC-4303, unsupported
1055+
default:
1056+
loop = false;
1057+
break;
1058+
}
1059+
}
1060+
// There can be link padding, take payload length from IPv6 header - options
1061+
pkt->pay.buf = nhdr;
1062+
pkt->pay.len = mg_ntohs(pkt->ip6->plen) - len;
1063+
if (next == 58) {
10571064
pkt->icmp6 = (struct icmp6 *) (pkt->pay.buf);
10581065
if (pkt->pay.len < sizeof(*pkt->icmp6)) return;
10591066
mkpay(pkt, pkt->icmp6 + 1);
10601067
MG_DEBUG(("ICMPv6 %M -> %M len %u", mg_print_ip6, &pkt->ip6->src,
1061-
mg_print_ip6, &pkt->ip6->dst,
1062-
(int) pkt->pay.len));
1068+
mg_print_ip6, &pkt->ip6->dst, (int) pkt->pay.len));
10631069
// rx_icmp6(ifp, pkt);
1064-
} else if (hdr->next == 17) {
1070+
} else if (next == 17) {
10651071
pkt->udp = (struct udp *) (pkt->pay.buf);
10661072
if (pkt->pay.len < sizeof(*pkt->udp)) return;
10671073
mkpay(pkt, pkt->udp + 1);
10681074
MG_DEBUG(("UDP %M:%hu -> %M:%hu len %u", mg_print_ip6, &pkt->ip6->src,
1069-
mg_ntohs(pkt->udp->sport), mg_print_ip6, &pkt->ip6->dst,
1070-
mg_ntohs(pkt->udp->dport), (int) pkt->pay.len));
1075+
mg_ntohs(pkt->udp->sport), mg_print_ip6, &pkt->ip6->dst,
1076+
mg_ntohs(pkt->udp->dport), (int) pkt->pay.len));
10711077
if (ifp->enable_dhcp_client && pkt->udp->dport == mg_htons(546)) {
10721078
pkt->dhcp6 = (struct dhcp6 *) (pkt->udp + 1);
10731079
mkpay(pkt, pkt->dhcp6 + 1);
@@ -1079,20 +1085,21 @@ static void rx_ip6(struct mg_tcpip_if *ifp, struct pkt *pkt) {
10791085
} else if (!rx_udp(ifp, pkt)) {
10801086
// Should send ICMPv6 Destination Unreachable for unicasts, keep silent
10811087
}
1082-
} else if (hdr->next == 6) {
1088+
} else if (next == 6) {
10831089
uint8_t off;
10841090
pkt->tcp = (struct tcp *) (pkt->pay.buf);
10851091
if (pkt->pay.len < sizeof(*pkt->tcp)) return;
10861092
off = pkt->tcp->off >> 4; // account for opts
10871093
if (pkt->pay.len < sizeof(*pkt->tcp) + 4 * off) return;
10881094
mkpay(pkt, (uint32_t *) pkt->tcp + off);
10891095
MG_DEBUG(("TCP %M:%hu -> %M:%hu len %u", mg_print_ip6, &pkt->ip6->src,
1090-
mg_ntohs(pkt->tcp->sport), mg_print_ip6, &pkt->ip6->dst,
1091-
mg_ntohs(pkt->tcp->dport), (int) pkt->pay.len));
1096+
mg_ntohs(pkt->tcp->sport), mg_print_ip6, &pkt->ip6->dst,
1097+
mg_ntohs(pkt->tcp->dport), (int) pkt->pay.len));
10921098
rx_tcp(ifp, pkt);
10931099
} else {
1094-
MG_DEBUG(("Unknown IPv6 next hdr %x", mg_htons(hdr->next)));
1095-
if (mg_log_level >= MG_LL_VERBOSE) mg_hexdump(pkt->ip6, pkt->pay.len >= 32 ? 32 : pkt->pay.len);
1100+
MG_DEBUG(("Unknown IPv6 next hdr %x", (int) next));
1101+
if (mg_log_level >= MG_LL_VERBOSE)
1102+
mg_hexdump(pkt->ip6, pkt->pay.len >= 32 ? 32 : pkt->pay.len);
10961103
}
10971104
}
10981105

0 commit comments

Comments
 (0)