@@ -5172,59 +5172,65 @@ static void rx_ip(struct mg_tcpip_if *ifp, struct pkt *pkt) {
5172
5172
mg_ntohs(pkt->tcp->dport), (int) pkt->pay.len));
5173
5173
rx_tcp(ifp, pkt);
5174
5174
} 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);
5197
5178
}
5198
- return true;
5199
5179
}
5200
5180
5201
5181
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;
5204
5185
if (pkt->pay.len < sizeof(*pkt->ip6)) return; // Truncated
5205
5186
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) {
5214
5221
pkt->icmp6 = (struct icmp6 *) (pkt->pay.buf);
5215
5222
if (pkt->pay.len < sizeof(*pkt->icmp6)) return;
5216
5223
mkpay(pkt, pkt->icmp6 + 1);
5217
5224
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));
5220
5226
// rx_icmp6(ifp, pkt);
5221
- } else if (hdr-> next == 17) {
5227
+ } else if (next == 17) {
5222
5228
pkt->udp = (struct udp *) (pkt->pay.buf);
5223
5229
if (pkt->pay.len < sizeof(*pkt->udp)) return;
5224
5230
mkpay(pkt, pkt->udp + 1);
5225
5231
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));
5228
5234
if (ifp->enable_dhcp_client && pkt->udp->dport == mg_htons(546)) {
5229
5235
pkt->dhcp6 = (struct dhcp6 *) (pkt->udp + 1);
5230
5236
mkpay(pkt, pkt->dhcp6 + 1);
@@ -5236,20 +5242,21 @@ static void rx_ip6(struct mg_tcpip_if *ifp, struct pkt *pkt) {
5236
5242
} else if (!rx_udp(ifp, pkt)) {
5237
5243
// Should send ICMPv6 Destination Unreachable for unicasts, keep silent
5238
5244
}
5239
- } else if (hdr-> next == 6) {
5245
+ } else if (next == 6) {
5240
5246
uint8_t off;
5241
5247
pkt->tcp = (struct tcp *) (pkt->pay.buf);
5242
5248
if (pkt->pay.len < sizeof(*pkt->tcp)) return;
5243
5249
off = pkt->tcp->off >> 4; // account for opts
5244
5250
if (pkt->pay.len < sizeof(*pkt->tcp) + 4 * off) return;
5245
5251
mkpay(pkt, (uint32_t *) pkt->tcp + off);
5246
5252
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));
5249
5255
rx_tcp(ifp, pkt);
5250
5256
} 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);
5253
5260
}
5254
5261
}
5255
5262
0 commit comments