@@ -4872,6 +4872,8 @@ static struct mg_connection *getpeer(struct mg_mgr *mgr, struct pkt *pkt,
48724872}
48734873
48744874static void mac_resolved(struct mg_connection *c);
4875+ static uint8_t *get_return_mac(struct mg_tcpip_if *ifp, struct mg_addr *rem,
4876+ bool is_udp, struct pkt *pkt);
48754877
48764878static void rx_arp(struct mg_tcpip_if *ifp, struct pkt *pkt) {
48774879 if (pkt->arp->op == mg_htons(1) && pkt->arp->tpa == ifp->ip) {
@@ -4897,6 +4899,7 @@ static void rx_arp(struct mg_tcpip_if *ifp, struct pkt *pkt) {
48974899 if (pkt->arp->spa == ifp->gw) {
48984900 // Got response for the GW ARP request. Set ifp->gwmac and IP -> READY
48994901 memcpy(ifp->gwmac, pkt->arp->sha, sizeof(ifp->gwmac));
4902+ ifp->gw_ready = true;
49004903 if (ifp->state == MG_TCPIP_STATE_IP) {
49014904 ifp->state = MG_TCPIP_STATE_READY;
49024905 onstatechange(ifp);
@@ -4921,6 +4924,11 @@ static void rx_icmp(struct mg_tcpip_if *ifp, struct pkt *pkt) {
49214924 size_t space = ifp->tx.len - hlen, plen = pkt->pay.len;
49224925 struct ip *ip;
49234926 struct icmp *icmp;
4927+ struct mg_addr ips;
4928+ ips.ip4 = pkt->ip->src;
4929+ ips.is_ip6 = false;
4930+ if (get_return_mac(ifp, &ips, false, pkt) == NULL)
4931+ return; // safety net for lousy networks
49244932 if (plen > space) plen = space;
49254933 ip = tx_ip(ifp, pkt->eth->src, 1, ifp->ip, pkt->ip->src,
49264934 sizeof(*icmp) + plen);
@@ -4940,7 +4948,7 @@ static void rx_dhcp_client(struct mg_tcpip_if *ifp, struct pkt *pkt) {
49404948 // perform size check first, then access fields
49414949 uint8_t *p = pkt->dhcp->options,
49424950 *end = (uint8_t *) &pkt->pay.buf[pkt->pay.len];
4943- if (end < p) return; // options are optional, check min header length
4951+ if (end < p) return; // options are optional, check min header length
49444952 if (memcmp(&pkt->dhcp->xid, ifp->mac + 2, sizeof(pkt->dhcp->xid))) return;
49454953 while (p + 1 < end && p[0] != 255) { // Parse options RFC-1533 #9
49464954 if (p[0] == 1 && p[1] == sizeof(ifp->mask) && p + 6 < end) { // Mask
@@ -4978,6 +4986,7 @@ static void rx_dhcp_client(struct mg_tcpip_if *ifp, struct pkt *pkt) {
49784986 MG_INFO(("Lease: %u sec (%lld)", lease, ifp->lease_expire / 1000));
49794987 // assume DHCP server = router until ARP resolves
49804988 memcpy(ifp->gwmac, pkt->eth->src, sizeof(ifp->gwmac));
4989+ ifp->gw_ready = true; // NOTE(): actual gw ARP won't retry now
49814990 ifp->ip = ip, ifp->gw = gw, ifp->mask = mask;
49824991 ifp->state = MG_TCPIP_STATE_IP; // BOUND state
49834992 mg_random(&rand, sizeof(rand));
@@ -5002,7 +5011,7 @@ static void rx_dhcp_server(struct mg_tcpip_if *ifp, struct pkt *pkt) {
50025011 *end = (uint8_t *) &pkt->pay.buf[pkt->pay.len];
50035012 // struct dhcp *req = pkt->dhcp;
50045013 struct dhcp res = {2, 1, 6, 0, 0, 0, 0, 0, 0, 0, 0, {0}, 0, {0}};
5005- if (end < p) return; // options are optional, check min header length
5014+ if (end < p) return; // options are optional, check min header length
50065015 res.yiaddr = ifp->ip;
50075016 ((uint8_t *) (&res.yiaddr))[3]++; // Offer our IP + 1
50085017 while (p + 1 < end && p[0] != 255) { // Parse options
@@ -5106,6 +5115,7 @@ static void rx_ndp_na(struct mg_tcpip_if *ifp, struct pkt *pkt) {
51065115 if (MG_IP6MATCH(na->addr, ifp->gw6)) {
51075116 // Got response for the GW NS request. Set ifp->gw6mac and IP6 -> READY
51085117 memcpy(ifp->gw6mac, opts, sizeof(ifp->gw6mac));
5118+ ifp->gw6_ready = true;
51095119 if (ifp->state6 == MG_TCPIP_STATE_IP) {
51105120 ifp->state6 = MG_TCPIP_STATE_READY;
51115121 onstate6change(ifp);
@@ -5226,6 +5236,7 @@ static void rx_ndp_ra(struct mg_tcpip_if *ifp, struct pkt *pkt) {
52265236 // Received router's MAC address
52275237 ifp->state6 = MG_TCPIP_STATE_READY;
52285238 memcpy(ifp->gw6mac, opts + 2, 6);
5239+ ifp->gw6_ready = true;
52295240 } else if (type == 5 && length >= 8) {
52305241 // process MTU if available
52315242 uint32_t mtu = mg_ntohl(*(uint32_t *) (opts + 4));
@@ -5272,6 +5283,11 @@ static void rx_icmp6(struct mg_tcpip_if *ifp, struct pkt *pkt) {
52725283 size_t hlen =
52735284 sizeof(struct eth) + sizeof(struct ip6) + sizeof(struct icmp6);
52745285 size_t space = ifp->tx.len - hlen, plen = pkt->pay.len;
5286+ struct mg_addr ips;
5287+ ips.ip6[0] = pkt->ip6->src[0], ips.ip6[1] = pkt->ip6->src[1];
5288+ ips.is_ip6 = true;
5289+ if (get_return_mac(ifp, &ips, false, pkt) == NULL)
5290+ return; // safety net for lousy networks
52755291 if (plen > space) plen = space; // Copy (truncated) RX payload to TX
52765292 // Echo Reply, 4.2
52775293 tx_icmp6(ifp, pkt->eth->src, pkt->ip6->dst, pkt->ip6->src, 129, 0,
@@ -5296,7 +5312,7 @@ static void onstate6change(struct mg_tcpip_if *ifp) {
52965312 MG_INFO((" GW: %M", mg_print_ip6, &ifp->gw6));
52975313 MG_INFO((" MAC: %M", mg_print_mac, &ifp->mac));
52985314 } else if (ifp->state6 == MG_TCPIP_STATE_IP) {
5299- if (ifp->gw6[0] != 0 || ifp->gw6[1] != 0)
5315+ if (ifp->gw6[0] != 0 || ifp->gw6[1] != 0)
53005316 tx_ndp_ns(ifp, ifp->gw6, ifp->gw6mac); // unsolicited GW MAC resolution
53015317 } else if (ifp->state6 == MG_TCPIP_STATE_UP) {
53025318 MG_INFO(("IP: %M", mg_print_ip6, &ifp->ip6ll));
@@ -5306,9 +5322,43 @@ static void onstate6change(struct mg_tcpip_if *ifp) {
53065322}
53075323#endif
53085324
5325+ static uint8_t *get_return_mac(struct mg_tcpip_if *ifp, struct mg_addr *rem,
5326+ bool is_udp, struct pkt *pkt) {
5327+ #if MG_ENABLE_IPV6
5328+ if (rem->is_ip6) {
5329+ if (is_udp && MG_IP6MATCH(rem->ip6, ip6_allnodes.u)) // local broadcast
5330+ return (uint8_t *) ip6mac_allnodes;
5331+ if (rem->ip6[0] == ifp->ip6[0]) // TODO(): HANDLE PREFIX ***
5332+ return pkt->eth->src; // we're on the same LAN, get MAC from frame
5333+ if (is_udp && *((uint8_t *) rem->ip6) == 0xFF) // multicast
5334+ {
5335+ } // TODO(): ip6_mcastmac(s->mac, c->rem.ip6), l2 PR handles this better
5336+ if (ifp->gw6_ready) // use the router
5337+ return ifp->gw6mac; // ignore source MAC in frame
5338+ } else
5339+ #endif
5340+ {
5341+ uint32_t rem_ip = rem->ip4;
5342+ if (is_udp && (rem_ip == 0xffffffff || rem_ip == (ifp->ip | ~ifp->mask)))
5343+ return (uint8_t *) broadcast; // global or local broadcast
5344+ if (ifp->ip != 0 && ((rem_ip & ifp->mask) == (ifp->ip & ifp->mask)))
5345+ return pkt->eth->src; // we're on the same LAN, get MAC from frame
5346+ if (is_udp &&
5347+ (*((uint8_t *) &rem_ip) & 0xE0) == 0xE0) // 224 to 239, E0 to EF
5348+ {
5349+ } // TODO(): ip4_mcastmac(s->mac, &rem_ip); // multicast group, l2 PR
5350+ if (ifp->gw_ready) // use the router, ignore source MAC
5351+ return ifp->gwmac;
5352+ }
5353+ MG_ERROR(("%M %s: No way back, can't respond", mg_print_ip_port, rem,
5354+ is_udp ? "UDP" : "TCP"));
5355+ return NULL;
5356+ }
5357+
53095358static bool rx_udp(struct mg_tcpip_if *ifp, struct pkt *pkt) {
53105359 struct mg_connection *c = getpeer(ifp->mgr, pkt, true);
53115360 struct connstate *s;
5361+ uint8_t *mac;
53125362 if (c == NULL) return false; // No UDP listener on this port
53135363 s = (struct connstate *) (c + 1);
53145364 c->rem.port = pkt->udp->sport;
@@ -5321,7 +5371,9 @@ static bool rx_udp(struct mg_tcpip_if *ifp, struct pkt *pkt) {
53215371 {
53225372 c->rem.ip4 = pkt->ip->src;
53235373 }
5324- memcpy(s->mac, pkt->eth->src, sizeof(s->mac));
5374+ if ((mac = get_return_mac(ifp, &c->rem, true, pkt)) == NULL)
5375+ return false; // safety net for lousy networks
5376+ memcpy(s->mac, mac, sizeof(s->mac));
53255377 if (c->recv.len >= MG_MAX_RECV_SIZE) {
53265378 mg_error(c, "max_recv_buf_size reached");
53275379 } else if (c->recv.size - c->recv.len < pkt->pay.len &&
@@ -5410,6 +5462,7 @@ static size_t tx_tcp_ctrlresp(struct mg_tcpip_if *ifp, struct pkt *pkt,
54105462 uint32_t ackno = mg_htonl(mg_ntohl(pkt->tcp->seq) + (uint32_t) pkt->pay.len +
54115463 ((pkt->tcp->flags & (TH_SYN | TH_FIN)) ? 1 : 0));
54125464 struct mg_addr ips, ipd;
5465+ uint8_t *mac;
54135466 memset(&ips, 0, sizeof(ips));
54145467 memset(&ipd, 0, sizeof(ipd));
54155468 if (pkt->ip != NULL) {
@@ -5423,7 +5476,9 @@ static size_t tx_tcp_ctrlresp(struct mg_tcpip_if *ifp, struct pkt *pkt,
54235476 }
54245477 ips.port = pkt->tcp->dport;
54255478 ipd.port = pkt->tcp->sport;
5426- return tx_tcp(ifp, pkt->eth->src, &ips, &ipd, flags, seqno, ackno, NULL, 0);
5479+ if ((mac = get_return_mac(ifp, &ipd, false, pkt)) == NULL)
5480+ return 0; // safety net for lousy networks
5481+ return tx_tcp(ifp, mac, &ips, &ipd, flags, seqno, ackno, NULL, 0);
54275482}
54285483
54295484static size_t tx_tcp_rst(struct mg_tcpip_if *ifp, struct pkt *pkt, bool toack) {
@@ -5435,15 +5490,14 @@ static struct mg_connection *accept_conn(struct mg_connection *lsn,
54355490 struct pkt *pkt, uint16_t mss) {
54365491 struct mg_connection *c = mg_alloc_conn(lsn->mgr);
54375492 struct connstate *s;
5493+ uint8_t *mac;
54385494 if (c == NULL) {
54395495 MG_ERROR(("OOM"));
54405496 return NULL;
54415497 }
54425498 s = (struct connstate *) (c + 1);
54435499 s->dmss = mss; // from options in client SYN
54445500 s->seq = mg_ntohl(pkt->tcp->ack), s->ack = mg_ntohl(pkt->tcp->seq);
5445- memcpy(s->mac, pkt->eth->src, sizeof(s->mac));
5446- settmout(c, MIP_TTYPE_KEEPALIVE);
54475501#if MG_ENABLE_IPV6
54485502 if (lsn->loc.is_ip6) {
54495503 c->rem.ip6[0] = pkt->ip6->src[0], c->rem.ip6[1] = pkt->ip6->src[1],
@@ -5459,6 +5513,12 @@ static struct mg_connection *accept_conn(struct mg_connection *lsn,
54595513 }
54605514 c->rem.port = pkt->tcp->sport;
54615515 c->loc.port = lsn->loc.port;
5516+ if ((mac = get_return_mac(lsn->mgr->ifp, &c->rem, false, pkt)) == NULL) {
5517+ free(c); // safety net for lousy networks, not actually needed
5518+ return NULL; // as path has already been checked at SYN (sending SYN+ACK)
5519+ }
5520+ memcpy(s->mac, mac, sizeof(s->mac));
5521+ settmout(c, MIP_TTYPE_KEEPALIVE);
54625522 MG_DEBUG(("%lu accepted %M", c->id, mg_print_ip_port, &c->rem));
54635523 LIST_ADD_HEAD(struct mg_connection, &lsn->mgr->conns, c);
54645524 c->is_accepted = 1;
@@ -5770,7 +5830,8 @@ static void rx_tcp(struct mg_tcpip_if *ifp, struct pkt *pkt) {
57705830 // Use peer's src port and bl key as ISN, to later identify the
57715831 // handshake
57725832 isn = (mg_htonl(((uint32_t) key << 16) | mg_ntohs(pkt->tcp->sport)));
5773- tx_tcp_ctrlresp(ifp, pkt, TH_SYN | TH_ACK, isn);
5833+ if (tx_tcp_ctrlresp(ifp, pkt, TH_SYN | TH_ACK, isn) == 0)
5834+ backlog_remove(c, (uint16_t) key); // safety net for lousy networks
57745835 } // what should we do when port=0 ? Linux takes port 0 as any other
57755836 // port
57765837 } else if (pkt->tcp->flags == TH_ACK) {
@@ -5804,10 +5865,10 @@ static void rx_ip(struct mg_tcpip_if *ifp, struct pkt *pkt) {
58045865 if (ihl < 5) return; // bad IHL
58055866 if (pkt->pay.len < (uint16_t) (ihl * 4)) return; // Truncated / malformed
58065867 // There can be link padding, take length from IP header
5807- len = mg_ntohs(pkt->ip->len); // IP datagram length
5868+ len = mg_ntohs(pkt->ip->len); // IP datagram length
58085869 if (len < (uint16_t) (ihl * 4) || len > pkt->pay.len) return; // malformed
5809- pkt->pay.len = len; // strip padding
5810- mkpay(pkt, (uint32_t *) pkt->ip + ihl); // account for opts
5870+ pkt->pay.len = len; // strip padding
5871+ mkpay(pkt, (uint32_t *) pkt->ip + ihl); // account for opts
58115872 frag = mg_ntohs(pkt->ip->frag);
58125873 if (frag & IP_MORE_FRAGS_MSK || frag & IP_FRAG_OFFSET_MSK) {
58135874 struct mg_connection *c;
@@ -6074,15 +6135,21 @@ static void mg_tcpip_poll(struct mg_tcpip_if *ifp, uint64_t now) {
60746135 }
60756136 // Handle gw ARP request timeout, order is important
60766137 if (expired_1000ms && ifp->state == MG_TCPIP_STATE_IP) {
6077- ifp->state = MG_TCPIP_STATE_READY; // keep best-effort MAC
6138+ ifp->state = MG_TCPIP_STATE_READY; // keep best-effort MAC or poison mark
60786139 onstatechange(ifp);
60796140 }
6141+ if (expired_1000ms && ifp->state == MG_TCPIP_STATE_READY && !ifp->gw_ready &&
6142+ ifp->gw != 0)
6143+ mg_tcpip_arp_request(ifp, ifp->gw, NULL); // retry GW ARP request
60806144#if MG_ENABLE_IPV6
60816145 // Handle gw NS/NA req/resp timeout, order is important
60826146 if (expired_1000ms && ifp->state6 == MG_TCPIP_STATE_IP) {
6083- ifp->state6 = MG_TCPIP_STATE_READY; // keep best-effort MAC
6147+ ifp->state6 = MG_TCPIP_STATE_READY; // keep best-effort MAC or poison mark
60846148 onstate6change(ifp);
60856149 }
6150+ if (expired_1000ms && ifp->state == MG_TCPIP_STATE_READY && !ifp->gw6_ready &&
6151+ (ifp->gw6[0] != 0 || ifp->gw6[1] != 0))
6152+ tx_ndp_ns(ifp, ifp->gw6, ifp->gw6mac); // retry GW MAC resolution
60866153#endif
60876154
60886155 // poll driver
@@ -6196,9 +6263,8 @@ void mg_tcpip_init(struct mg_mgr *mgr, struct mg_tcpip_if *ifp) {
61966263 ifp->mtu = MG_TCPIP_MTU_DEFAULT;
61976264 mgr->extraconnsize = sizeof(struct connstate);
61986265 if (ifp->ip == 0) ifp->enable_dhcp_client = true;
6199- memset(ifp->gwmac, 255, sizeof(ifp->gwmac)); // Set best-effort to bcast
6200- mg_random(&ifp->eport, sizeof(ifp->eport)); // Random from 0 to 65535
6201- ifp->eport |= MG_EPHEMERAL_PORT_BASE; // Random from
6266+ mg_random(&ifp->eport, sizeof(ifp->eport)); // Random from 0 to 65535
6267+ ifp->eport |= MG_EPHEMERAL_PORT_BASE; // Random from
62026268 // MG_EPHEMERAL_PORT_BASE to 65535
62036269 if (ifp->tx.buf == NULL || ifp->recv_queue.buf == NULL) MG_ERROR(("OOM"));
62046270#if MG_ENABLE_IPV6
@@ -6208,7 +6274,6 @@ void mg_tcpip_init(struct mg_mgr *mgr, struct mg_tcpip_if *ifp) {
62086274 ifp->enable_slaac = true;
62096275 ip6genll((uint8_t *) ifp->ip6ll, ifp->mac); // build link-local address
62106276 }
6211- memset(ifp->gw6mac, 255, sizeof(ifp->gw6mac)); // Set best-effort to bcast
62126277#endif
62136278 }
62146279}
@@ -6267,19 +6332,19 @@ void mg_connect_resolved(struct mg_connection *c) {
62676332 struct connstate *s = (struct connstate *) (c + 1);
62686333 memcpy(s->mac, ip6mac_allnodes, sizeof(s->mac));
62696334 mac_resolved(c);
6270- } else if (c->rem.ip6[0] == ifp->ip6[0] &&
6335+ } else if (c->rem.ip6[0] == ifp->ip6[0] && // TODO(): HANDLE PREFIX ***
62716336 !MG_IP6MATCH(c->rem.ip6,
62726337 ifp->gw6)) { // skip if gw (onstate6change -> NS)
62736338 // If we're in the same LAN, fire a Neighbor Solicitation
62746339 MG_DEBUG(("%lu NS lookup...", c->id));
62756340 tx_ndp_ns(ifp, c->rem.ip6, ifp->mac);
62766341 settmout(c, MIP_TTYPE_ARP);
62776342 c->is_arplooking = 1;
6278- } else if (*((uint8_t *) c->rem.ip6) == 0xFF) { // multicast
6343+ } else if (c->is_udp && *((uint8_t *) c->rem.ip6) == 0xFF) { // multicast
62796344 struct connstate *s = (struct connstate *) (c + 1);
62806345 ip6_mcastmac(s->mac, c->rem.ip6);
62816346 mac_resolved(c);
6282- } else if (ifp->gw6[0] != 0 || ifp->gw6[1] != 0 ) {
6347+ } else if (ifp->gw6_ready ) {
62836348 struct connstate *s = (struct connstate *) (c + 1);
62846349 memcpy(s->mac, ifp->gw6mac, sizeof(s->mac));
62856350 mac_resolved(c);
@@ -6302,14 +6367,14 @@ void mg_connect_resolved(struct mg_connection *c) {
63026367 mg_tcpip_arp_request(ifp, rem_ip, NULL);
63036368 settmout(c, MIP_TTYPE_ARP);
63046369 c->is_arplooking = 1;
6305- } else if ((*((uint8_t *) &rem_ip) & 0xE0) == 0xE0) {
6370+ } else if (c->is_udp && (*((uint8_t *) &rem_ip) & 0xE0) == 0xE0) {
63066371 struct connstate *s =
63076372 (struct connstate *) (c + 1); // 224 to 239, E0 to EF
63086373 ip4_mcastmac(s->mac, &rem_ip); // multicast group
63096374 mac_resolved(c);
6310- } else if (ifp->gw != 0 ) {
6375+ } else if (ifp->gw_ready ) {
63116376 struct connstate *s = (struct connstate *) (c + 1);
6312- memcpy(s->mac, ifp->gwmac, sizeof(ifp->gwmac ));
6377+ memcpy(s->mac, ifp->gwmac, sizeof(s->mac ));
63136378 mac_resolved(c);
63146379 } else {
63156380 MG_ERROR(("No gateway, can't connect"));
0 commit comments