@@ -4205,7 +4205,7 @@ struct eth {
4205
4205
struct ip {
4206
4206
uint8_t ver; // Version
4207
4207
uint8_t tos; // Unused
4208
- uint16_t len; // Length
4208
+ uint16_t len; // Datagram length
4209
4209
uint16_t id; // Unused
4210
4210
uint16_t frag; // Fragmentation
4211
4211
#define IP_FRAG_OFFSET_MSK 0x1fff
@@ -4218,13 +4218,13 @@ struct ip {
4218
4218
};
4219
4219
4220
4220
struct ip6 {
4221
- uint8_t ver; // Version
4222
- uint8_t opts [3]; // Options
4223
- uint16_t len ; // Length
4224
- uint8_t proto; // Upper level protocol
4225
- uint8_t ttl ; // Time to live
4226
- uint8_t src[16]; // Source IP
4227
- uint8_t dst[16]; // Destination IP
4221
+ uint8_t ver; // Version
4222
+ uint8_t label [3]; // Flow label
4223
+ uint16_t plen ; // Payload length
4224
+ uint8_t next; // Upper level protocol
4225
+ uint8_t hops ; // Hop limit
4226
+ uint8_t src[16]; // Source IP
4227
+ uint8_t dst[16]; // Destination IP
4228
4228
};
4229
4229
4230
4230
struct icmp {
@@ -4233,6 +4233,12 @@ struct icmp {
4233
4233
uint16_t csum;
4234
4234
};
4235
4235
4236
+ struct icmp6 {
4237
+ uint8_t type;
4238
+ uint8_t code;
4239
+ uint16_t csum;
4240
+ };
4241
+
4236
4242
struct arp {
4237
4243
uint16_t fmt; // Format of hardware address
4238
4244
uint16_t pro; // Format of protocol address
@@ -4282,6 +4288,14 @@ struct dhcp {
4282
4288
uint8_t options[30 + sizeof(((struct mg_tcpip_if *) 0)->dhcp_name)];
4283
4289
};
4284
4290
4291
+ struct dhcp6 {
4292
+ union {
4293
+ uint8_t type;
4294
+ uint32_t xid;
4295
+ };
4296
+ uint8_t options[30 + sizeof(((struct mg_tcpip_if *) 0)->dhcp_name)];
4297
+ };
4298
+
4285
4299
#pragma pack(pop)
4286
4300
4287
4301
struct pkt {
@@ -4293,9 +4307,11 @@ struct pkt {
4293
4307
struct ip *ip;
4294
4308
struct ip6 *ip6;
4295
4309
struct icmp *icmp;
4310
+ struct icmp6 *icmp6;
4296
4311
struct tcp *tcp;
4297
4312
struct udp *udp;
4298
4313
struct dhcp *dhcp;
4314
+ struct dhcp6 *dhcp6;
4299
4315
};
4300
4316
4301
4317
static void mg_tcpip_call(struct mg_tcpip_if *ifp, int ev, void *ev_data) {
@@ -4306,7 +4322,7 @@ static void send_syn(struct mg_connection *c);
4306
4322
4307
4323
static void mkpay(struct pkt *pkt, void *p) {
4308
4324
pkt->pay =
4309
- mg_str_n((char *) p, (size_t) (&pkt->raw .buf[pkt->raw .len] - (char *) p));
4325
+ mg_str_n((char *) p, (size_t) (&pkt->pay .buf[pkt->pay .len] - (char *) p));
4310
4326
}
4311
4327
4312
4328
static uint32_t csumup(uint32_t sum, const void *buf, size_t len) {
@@ -4569,7 +4585,7 @@ static void rx_dhcp_client(struct mg_tcpip_if *ifp, struct pkt *pkt) {
4569
4585
uint8_t msgtype = 0, state = ifp->state;
4570
4586
// perform size check first, then access fields
4571
4587
uint8_t *p = pkt->dhcp->options,
4572
- *end = (uint8_t *) &pkt->raw .buf[pkt->raw .len];
4588
+ *end = (uint8_t *) &pkt->pay .buf[pkt->pay .len];
4573
4589
if (end < (uint8_t *) (pkt->dhcp + 1)) return;
4574
4590
if (memcmp(&pkt->dhcp->xid, ifp->mac + 2, sizeof(pkt->dhcp->xid))) return;
4575
4591
while (p + 1 < end && p[0] != 255) { // Parse options RFC-1533 #9
@@ -4629,7 +4645,7 @@ static void rx_dhcp_client(struct mg_tcpip_if *ifp, struct pkt *pkt) {
4629
4645
// Simple DHCP server that assigns a next IP address: ifp->ip + 1
4630
4646
static void rx_dhcp_server(struct mg_tcpip_if *ifp, struct pkt *pkt) {
4631
4647
uint8_t op = 0, *p = pkt->dhcp->options,
4632
- *end = (uint8_t *) &pkt->raw .buf[pkt->raw .len];
4648
+ *end = (uint8_t *) &pkt->pay .buf[pkt->pay .len];
4633
4649
// struct dhcp *req = pkt->dhcp;
4634
4650
struct dhcp res = {2, 1, 6, 0, 0, 0, 0, 0, 0, 0, 0, {0}, 0, {0}};
4635
4651
if (end < (uint8_t *) (pkt->dhcp + 1)) return;
@@ -4666,26 +4682,25 @@ static void rx_dhcp_server(struct mg_tcpip_if *ifp, struct pkt *pkt) {
4666
4682
}
4667
4683
}
4668
4684
4669
- static void rx_udp(struct mg_tcpip_if *ifp, struct pkt *pkt) {
4685
+ static bool rx_udp(struct mg_tcpip_if *ifp, struct pkt *pkt) {
4670
4686
struct mg_connection *c = getpeer(ifp->mgr, pkt, true);
4671
- if (c == NULL) {
4672
- // No UDP listener on this port. Should send ICMP, but keep silent.
4687
+ struct connstate *s;
4688
+ if (c == NULL) return false; // No UDP listener on this port
4689
+ s = (struct connstate *) (c + 1);
4690
+ c->rem.port = pkt->udp->sport;
4691
+ memcpy(c->rem.ip, &pkt->ip->src, sizeof(uint32_t));
4692
+ memcpy(s->mac, pkt->eth->src, sizeof(s->mac));
4693
+ if (c->recv.len >= MG_MAX_RECV_SIZE) {
4694
+ mg_error(c, "max_recv_buf_size reached");
4695
+ } else if (c->recv.size - c->recv.len < pkt->pay.len &&
4696
+ !mg_iobuf_resize(&c->recv, c->recv.len + pkt->pay.len)) {
4697
+ mg_error(c, "oom");
4673
4698
} else {
4674
- struct connstate *s = (struct connstate *) (c + 1);
4675
- c->rem.port = pkt->udp->sport;
4676
- memcpy(c->rem.ip, &pkt->ip->src, sizeof(uint32_t));
4677
- memcpy(s->mac, pkt->eth->src, sizeof(s->mac));
4678
- if (c->recv.len >= MG_MAX_RECV_SIZE) {
4679
- mg_error(c, "max_recv_buf_size reached");
4680
- } else if (c->recv.size - c->recv.len < pkt->pay.len &&
4681
- !mg_iobuf_resize(&c->recv, c->recv.len + pkt->pay.len)) {
4682
- mg_error(c, "oom");
4683
- } else {
4684
- memcpy(&c->recv.buf[c->recv.len], pkt->pay.buf, pkt->pay.len);
4685
- c->recv.len += pkt->pay.len;
4686
- mg_call(c, MG_EV_READ, &pkt->pay.len);
4687
- }
4699
+ memcpy(&c->recv.buf[c->recv.len], pkt->pay.buf, pkt->pay.len);
4700
+ c->recv.len += pkt->pay.len;
4701
+ mg_call(c, MG_EV_READ, &pkt->pay.len);
4688
4702
}
4703
+ return true;
4689
4704
}
4690
4705
4691
4706
static size_t tx_tcp(struct mg_tcpip_if *ifp, uint8_t *dst_mac, uint32_t dst_ip,
@@ -4725,7 +4740,6 @@ static size_t tx_tcp(struct mg_tcpip_if *ifp, uint8_t *dst_mac, uint32_t dst_ip,
4725
4740
MG_VERBOSE(("TCP %M:%hu -> %M:%hu fl %x len %u", mg_print_ip4, &ip->src,
4726
4741
mg_ntohs(tcp->sport), mg_print_ip4, &ip->dst,
4727
4742
mg_ntohs(tcp->dport), tcp->flags, len));
4728
- // mg_hexdump(ifp->tx.buf, PDIFF(ifp->tx.buf, tcp + 1) + len);
4729
4743
return ether_output(ifp, PDIFF(ifp->tx.buf, tcp + 1) + len);
4730
4744
}
4731
4745
@@ -5081,23 +5095,38 @@ static void rx_tcp(struct mg_tcpip_if *ifp, struct pkt *pkt) {
5081
5095
}
5082
5096
5083
5097
static void rx_ip(struct mg_tcpip_if *ifp, struct pkt *pkt) {
5084
- uint16_t frag = mg_ntohs(pkt->ip->frag);
5098
+ uint8_t ihl;
5099
+ uint16_t frag, len;
5100
+ if (pkt->pay.len < sizeof(*pkt->ip)) return; // Truncated
5101
+ if ((pkt->ip->ver >> 4) != 4) return; // Not IP
5102
+ ihl = pkt->ip->ver & 0x0F;
5103
+ if (ihl < 5) return; // bad IHL
5104
+ if (pkt->pay.len < (ihl * 4)) return; // Truncated / malformed
5105
+ // There can be link padding, take length from IP header
5106
+ len = mg_ntohs(pkt->ip->len); // IP datagram length
5107
+ if (len < (ihl * 4) || len > pkt->pay.len) return; // malformed
5108
+ pkt->pay.len = len; // strip padding
5109
+ mkpay(pkt, (uint32_t *) pkt->ip + ihl); // account for opts
5110
+ frag = mg_ntohs(pkt->ip->frag);
5085
5111
if (frag & IP_MORE_FRAGS_MSK || frag & IP_FRAG_OFFSET_MSK) {
5086
5112
struct mg_connection *c;
5087
- if (pkt->ip->proto == 17) pkt->udp = (struct udp *) (pkt->ip + 1 );
5088
- if (pkt->ip->proto == 6) pkt->tcp = (struct tcp *) (pkt->ip + 1 );
5113
+ if (pkt->ip->proto == 17) pkt->udp = (struct udp *) (pkt->pay.buf );
5114
+ if (pkt->ip->proto == 6) pkt->tcp = (struct tcp *) (pkt->pay.buf );
5089
5115
c = getpeer(ifp->mgr, pkt, false);
5090
5116
if (c) mg_error(c, "Received fragmented packet");
5091
5117
} else if (pkt->ip->proto == 1) {
5092
- pkt->icmp = (struct icmp *) (pkt->ip + 1 );
5118
+ pkt->icmp = (struct icmp *) (pkt->pay.buf );
5093
5119
if (pkt->pay.len < sizeof(*pkt->icmp)) return;
5094
5120
mkpay(pkt, pkt->icmp + 1);
5095
5121
rx_icmp(ifp, pkt);
5096
5122
} else if (pkt->ip->proto == 17) {
5097
- pkt->udp = (struct udp *) (pkt->ip + 1);
5098
- if (pkt->pay.len < sizeof(*pkt->udp)) return;
5123
+ pkt->udp = (struct udp *) (pkt->pay.buf);
5124
+ if (pkt->pay.len < sizeof(*pkt->udp)) return; // truncated
5125
+ // Take length from UDP header
5126
+ len = mg_ntohs(pkt->udp->len); // UDP datagram length
5127
+ if (len < sizeof(*pkt->udp) || len > pkt->pay.len) return; // malformed
5128
+ pkt->pay.len = len; // strip excess data
5099
5129
mkpay(pkt, pkt->udp + 1);
5100
- if (pkt->udp->len < pkt->pay.len) pkt->pay.len = pkt->udp->len;
5101
5130
MG_VERBOSE(("UDP %M:%hu -> %M:%hu len %u", mg_print_ip4, &pkt->ip->src,
5102
5131
mg_ntohs(pkt->udp->sport), mg_print_ip4, &pkt->ip->dst,
5103
5132
mg_ntohs(pkt->udp->dport), (int) pkt->pay.len));
@@ -5109,47 +5138,108 @@ static void rx_ip(struct mg_tcpip_if *ifp, struct pkt *pkt) {
5109
5138
pkt->dhcp = (struct dhcp *) (pkt->udp + 1);
5110
5139
mkpay(pkt, pkt->dhcp + 1);
5111
5140
rx_dhcp_server(ifp, pkt);
5112
- } else {
5113
- rx_udp(ifp, pkt);
5141
+ } else if (!rx_udp(ifp, pkt)) {
5142
+ // Should send ICMP Destination Unreachable for unicasts, but keep silent
5114
5143
}
5115
5144
} else if (pkt->ip->proto == 6) {
5116
- uint16_t iplen, off;
5117
- pkt->tcp = (struct tcp *) (pkt->ip + 1 );
5145
+ uint8_t off;
5146
+ pkt->tcp = (struct tcp *) (pkt->pay.buf );
5118
5147
if (pkt->pay.len < sizeof(*pkt->tcp)) return;
5119
- mkpay(pkt, (uint32_t *) pkt->tcp + (pkt->tcp->off >> 4)); // may have opts
5120
- iplen = mg_ntohs(pkt->ip->len);
5121
- off = (uint16_t) (sizeof(*pkt->ip) + ((pkt->tcp->off >> 4) * 4U));
5122
- if (iplen >= off) pkt->pay.len = (size_t) (iplen - off);
5148
+ off = pkt->tcp->off >> 4; // account for opts
5149
+ if (pkt->pay.len < (4 * off)) return;
5150
+ mkpay(pkt, (uint32_t *) pkt->tcp + off);
5123
5151
MG_VERBOSE(("TCP %M:%hu -> %M:%hu len %u", mg_print_ip4, &pkt->ip->src,
5124
5152
mg_ntohs(pkt->tcp->sport), mg_print_ip4, &pkt->ip->dst,
5125
5153
mg_ntohs(pkt->tcp->dport), (int) pkt->pay.len));
5126
5154
rx_tcp(ifp, pkt);
5155
+ } else {
5156
+ MG_DEBUG(("Unknown IP proto %x", mg_htons(pkt->ip->proto)));
5157
+ if (mg_log_level >= MG_LL_VERBOSE) mg_hexdump(pkt->ip, pkt->pay.len >= 32 ? 32 : pkt->pay.len);
5158
+ }
5159
+ }
5160
+
5161
+ static bool ip6_handle_opt(struct ip6 *h) {
5162
+ switch(h->next) {
5163
+ case 0:
5164
+ case 43:
5165
+ case 44:
5166
+ case 50:
5167
+ case 51:
5168
+ case 60:
5169
+ case 135:
5170
+ case 139:
5171
+ case 140:
5172
+ case 253:
5173
+ case 254:
5174
+ MG_INFO(("IPv6 extension header %d", (int) h->next));
5175
+ break;
5176
+ default:
5177
+ return false;
5127
5178
}
5179
+ return true;
5128
5180
}
5129
5181
5130
5182
static void rx_ip6(struct mg_tcpip_if *ifp, struct pkt *pkt) {
5131
- // MG_DEBUG(("IP %d", (int) len));
5132
- if (pkt->ip6->proto == 1 || pkt->ip6->proto == 58) {
5133
- pkt->icmp = (struct icmp *) (pkt->ip6 + 1);
5134
- if (pkt->pay.len < sizeof(*pkt->icmp)) return;
5135
- mkpay(pkt, pkt->icmp + 1);
5136
- rx_icmp(ifp, pkt);
5137
- } else if (pkt->ip6->proto == 17) {
5138
- pkt->udp = (struct udp *) (pkt->ip6 + 1);
5183
+ struct ip6 *hdr;
5184
+ uint16_t len;
5185
+ if (pkt->pay.len < sizeof(*pkt->ip6)) return; // Truncated
5186
+ if ((pkt->ip6->ver >> 4) != 0x6) return; // Not IPv6
5187
+ hdr = pkt->ip6;
5188
+ while (ip6_handle_opt(hdr)) ++hdr;
5189
+ // There can be link padding, take payload length from IPv6 last header
5190
+ len = mg_ntohs(hdr->plen); // IPv6 datagram reported payload length
5191
+ if ((len + (size_t) hdr - (size_t) pkt->ip6) > pkt->pay.len) return;
5192
+ pkt->pay.buf = (char *)(hdr + 1);
5193
+ pkt->pay.len = len; // strip padding
5194
+ if (hdr->next == 58) {
5195
+ pkt->icmp6 = (struct icmp6 *) (pkt->pay.buf);
5196
+ if (pkt->pay.len < sizeof(*pkt->icmp6)) return;
5197
+ mkpay(pkt, pkt->icmp6 + 1);
5198
+ MG_DEBUG(("ICMPv6 %M -> %M len %u", mg_print_ip6, &pkt->ip6->src,
5199
+ mg_print_ip6, &pkt->ip6->dst,
5200
+ (int) pkt->pay.len));
5201
+ // rx_icmp6(ifp, pkt);
5202
+ } else if (hdr->next == 17) {
5203
+ pkt->udp = (struct udp *) (pkt->pay.buf);
5139
5204
if (pkt->pay.len < sizeof(*pkt->udp)) return;
5140
- // MG_DEBUG((" UDP %u %u -> %u", len, mg_htons(udp->sport),
5141
- // mg_htons(udp->dport)));
5142
5205
mkpay(pkt, pkt->udp + 1);
5206
+ MG_DEBUG(("UDP %M:%hu -> %M:%hu len %u", mg_print_ip6, &pkt->ip6->src,
5207
+ mg_ntohs(pkt->udp->sport), mg_print_ip6, &pkt->ip6->dst,
5208
+ mg_ntohs(pkt->udp->dport), (int) pkt->pay.len));
5209
+ if (ifp->enable_dhcp_client && pkt->udp->dport == mg_htons(546)) {
5210
+ pkt->dhcp6 = (struct dhcp6 *) (pkt->udp + 1);
5211
+ mkpay(pkt, pkt->dhcp6 + 1);
5212
+ // rx_dhcp6_client(ifp, pkt);
5213
+ } else if (ifp->enable_dhcp_server && pkt->udp->dport == mg_htons(547)) {
5214
+ pkt->dhcp6 = (struct dhcp6 *) (pkt->udp + 1);
5215
+ mkpay(pkt, pkt->dhcp6 + 1);
5216
+ // rx_dhcp6_server(ifp, pkt);
5217
+ } else if (!rx_udp(ifp, pkt)) {
5218
+ // Should send ICMPv6 Destination Unreachable for unicasts, keep silent
5219
+ }
5220
+ } else if (hdr->next == 6) {
5221
+ uint8_t off;
5222
+ pkt->tcp = (struct tcp *) (pkt->pay.buf);
5223
+ if (pkt->pay.len < sizeof(*pkt->tcp)) return;
5224
+ off = pkt->tcp->off >> 4; // account for opts
5225
+ if (pkt->pay.len < sizeof(*pkt->tcp) + 4 * off) return;
5226
+ mkpay(pkt, (uint32_t *) pkt->tcp + off);
5227
+ MG_DEBUG(("TCP %M:%hu -> %M:%hu len %u", mg_print_ip6, &pkt->ip6->src,
5228
+ mg_ntohs(pkt->tcp->sport), mg_print_ip6, &pkt->ip6->dst,
5229
+ mg_ntohs(pkt->tcp->dport), (int) pkt->pay.len));
5230
+ rx_tcp(ifp, pkt);
5231
+ } else {
5232
+ MG_DEBUG(("Unknown IPv6 next hdr %x", mg_htons(hdr->next)));
5233
+ if (mg_log_level >= MG_LL_VERBOSE) mg_hexdump(pkt->ip6, pkt->pay.len >= 32 ? 32 : pkt->pay.len);
5143
5234
}
5144
5235
}
5145
5236
5146
5237
static void mg_tcpip_rx(struct mg_tcpip_if *ifp, void *buf, size_t len) {
5147
5238
struct pkt pkt;
5148
5239
memset(&pkt, 0, sizeof(pkt));
5149
- pkt.raw.buf = (char *) buf;
5150
- pkt.raw.len = len;
5151
- pkt.eth = (struct eth *) buf;
5152
- // mg_hexdump(buf, len > 16 ? 16: len);
5240
+ pkt.pay.buf = pkt.raw.buf = (char *) buf;
5241
+ pkt.pay.len = pkt.raw.len = len; // payload = raw
5242
+ pkt.eth = (struct eth *) buf; // Ethernet = raw
5153
5243
if (pkt.raw.len < sizeof(*pkt.eth)) return; // Truncated - runt?
5154
5244
if (ifp->enable_mac_check &&
5155
5245
memcmp(pkt.eth->dst, ifp->mac, sizeof(pkt.eth->dst)) != 0 &&
@@ -5160,28 +5250,19 @@ static void mg_tcpip_rx(struct mg_tcpip_if *ifp, void *buf, size_t len) {
5160
5250
len -= 4; // TODO(scaprile): check on bigendian
5161
5251
crc = mg_crc32(0, (const char *) buf, len);
5162
5252
if (memcmp((void *) ((size_t) buf + len), &crc, sizeof(crc))) return;
5253
+ pkt.pay.len = len;
5163
5254
}
5255
+ mkpay(&pkt, pkt.eth + 1);
5164
5256
if (pkt.eth->type == mg_htons(0x806)) {
5165
- pkt.arp = (struct arp *) (pkt.eth + 1 );
5166
- if (sizeof(*pkt.eth) + sizeof(*pkt.arp) > pkt.raw .len) return; // Truncated
5257
+ pkt.arp = (struct arp *) (pkt.pay.buf );
5258
+ if (sizeof(*pkt.eth) + sizeof(*pkt.arp) > pkt.pay .len) return; // Truncated
5167
5259
mg_tcpip_call(ifp, MG_TCPIP_EV_ARP, &pkt.raw);
5168
5260
rx_arp(ifp, &pkt);
5169
5261
} else if (pkt.eth->type == mg_htons(0x86dd)) {
5170
- pkt.ip6 = (struct ip6 *) (pkt.eth + 1);
5171
- if (pkt.raw.len < sizeof(*pkt.eth) + sizeof(*pkt.ip6)) return; // Truncated
5172
- if ((pkt.ip6->ver >> 4) != 0x6) return; // Not IP
5173
- mkpay(&pkt, pkt.ip6 + 1);
5262
+ pkt.ip6 = (struct ip6 *) (pkt.pay.buf);
5174
5263
rx_ip6(ifp, &pkt);
5175
5264
} else if (pkt.eth->type == mg_htons(0x800)) {
5176
- pkt.ip = (struct ip *) (pkt.eth + 1);
5177
- if (pkt.raw.len < sizeof(*pkt.eth) + sizeof(*pkt.ip)) return; // Truncated
5178
- // Truncate frame to what IP header tells us
5179
- if ((size_t) mg_ntohs(pkt.ip->len) + sizeof(struct eth) < pkt.raw.len) {
5180
- pkt.raw.len = (size_t) mg_ntohs(pkt.ip->len) + sizeof(struct eth);
5181
- }
5182
- if (pkt.raw.len < sizeof(*pkt.eth) + sizeof(*pkt.ip)) return; // Truncated
5183
- if ((pkt.ip->ver >> 4) != 4) return; // Not IP
5184
- mkpay(&pkt, pkt.ip + 1);
5265
+ pkt.ip = (struct ip *) (pkt.pay.buf);
5185
5266
rx_ip(ifp, &pkt);
5186
5267
} else {
5187
5268
MG_DEBUG(("Unknown eth type %x", mg_htons(pkt.eth->type)));
0 commit comments