From 7a74f5ada1cbac42a68166070edef5d408703707 Mon Sep 17 00:00:00 2001 From: "Sergio R. Caprile" Date: Wed, 17 Dec 2025 19:01:03 -0300 Subject: [PATCH] close TCP connections on DHCP/SLAAC IP address changes --- mongoose.c | 19 ++++++++++++++++++- mongoose.h | 2 ++ src/net_builtin.c | 19 ++++++++++++++++++- src/net_builtin.h | 2 ++ 4 files changed, 40 insertions(+), 2 deletions(-) diff --git a/mongoose.c b/mongoose.c index e1bb248d02..db40f96117 100644 --- a/mongoose.c +++ b/mongoose.c @@ -6846,6 +6846,13 @@ static void onstatechange(struct mg_tcpip_if *ifp) { MG_INFO((" MAC: %M", mg_print_mac, ifp->mac)); if (ifp->l2type == MG_TCPIP_L2_ETH) mg_tcpip_arp_request(ifp, ifp->ip, ifp->mac); // gratuitous ARP annc + if (ifp->is_ip_changed) { + struct mg_connection *c; + for (c = ifp->mgr->conns; c != NULL; c = c->next) { + if (!c->is_listening && !c->is_udp) c->is_closing = 1; + } + ifp->is_ip_changed = false; + } } else if (ifp->state == MG_TCPIP_STATE_IP) { if (ifp->gw != 0 && ifp->l2type == MG_TCPIP_L2_ETH) mg_tcpip_arp_request(ifp, ifp->gw, NULL); // unsolicited GW ARP request @@ -7155,6 +7162,7 @@ static void rx_dhcp_client(struct mg_tcpip_if *ifp, struct pkt *pkt) { // assume DHCP server = router until ARP resolves memcpy(ifp->gwmac, mg_l2_getaddr(ifp, pkt->l2), sizeof(ifp->gwmac)); ifp->gw_ready = true; // NOTE(): actual gw ARP won't retry now + if (ifp->ip != ip) ifp->is_ip_changed = true; ifp->ip = ip, ifp->gw = gw, ifp->mask = mask; ifp->state = MG_TCPIP_STATE_IP; // BOUND state mg_random(&rand, sizeof(rand)); @@ -7410,7 +7418,7 @@ static void rx_ndp_ra(struct mg_tcpip_if *ifp, struct pkt *pkt) { struct ndp_ra *ra = (struct ndp_ra *) (pkt->icmp6 + 1); uint8_t *opts = (uint8_t *) (ra + 1); size_t opt_left = pkt->pay.len - 12; - bool gotl2addr = false, gotprefix = false; + bool gotl2addr = false, gotprefix = false, changed = false; uint8_t l2[sizeof(struct mg_l2addr)]; uint32_t mtu = 0; uint8_t *prefix, prefix_len; @@ -7443,6 +7451,8 @@ static void rx_ndp_ra(struct mg_tcpip_if *ifp, struct pkt *pkt) { (void) pref_lifetime; gotprefix = true; + if (prefix_len != ifp->prefix || !match_prefix(prefix, ifp->prefix, ifp->prefix_len)) + changed = true; } opts += length; opt_left -= length; @@ -7450,6 +7460,7 @@ static void rx_ndp_ra(struct mg_tcpip_if *ifp, struct pkt *pkt) { // fill prefix and global if (gotprefix && !fill_global(ifp, prefix, prefix_len)) return; + if (changed) ifp->is_ip6_changed = true; ifp->gw6[0] = pkt->ip6->src[0], ifp->gw6[1] = pkt->ip6->src[1]; if (gotl2addr) memcpy(ifp->gw6mac, l2, sizeof(ifp->gw6mac)); if (gotl2addr || ifp->l2type == MG_TCPIP_L2_PPP || ifp->l2type == MG_TCPIP_L2_PPPoE) { @@ -7528,6 +7539,12 @@ static void onstate6change(struct mg_tcpip_if *ifp) { (struct mg_addr *) &ip6_allrouters), ifp->ip6, (uint64_t *) ip6_allrouters.addr.ip6, false, ifp->mac); + if (ifp->is_ip6_changed) { + struct mg_connection *c; + for (c = ifp->mgr->conns; c != NULL; c = c->next) { + if (!c->is_listening && !c->is_udp) c->is_closing = 1; + } + ifp->is_ip6_changed = false; } } else if (ifp->state6 == MG_TCPIP_STATE_IP) { if ((ifp->gw6[0] != 0 || ifp->gw6[1] != 0) && (ifp->l2type != MG_TCPIP_L2_PPP && ifp->l2type != MG_TCPIP_L2_PPPoE)) diff --git a/mongoose.h b/mongoose.h index 1684c72a5a..037985c0a8 100644 --- a/mongoose.h +++ b/mongoose.h @@ -3452,6 +3452,7 @@ struct mg_tcpip_if { bool enable_fcs_check; // Do a FCS check on RX frames and strip it bool enable_mac_check; // Do a hw addr check on RX frames bool update_mac_hash_table; // Signal drivers to update MAC controller + bool is_ip_changed; // IP address changed, close/restart conns struct mg_tcpip_driver *driver; // Low level driver void *driver_data; // Driver-specific data mg_tcpip_event_handler_t pfn; // Driver-specific event handler function @@ -3468,6 +3469,7 @@ struct mg_tcpip_if { uint64_t gw6[2]; // default gateway. bool enable_slaac; // Enable IPv6 address autoconfiguration bool enable_dhcp6_client; // Enable DCHPv6 client TODO() + bool is_ip6_changed; // IPv6 address changed, close/restart conns #endif // Internal state, user can use it but should not change it diff --git a/src/net_builtin.c b/src/net_builtin.c index bea2bc7272..d98adb7cd2 100644 --- a/src/net_builtin.c +++ b/src/net_builtin.c @@ -391,6 +391,13 @@ static void onstatechange(struct mg_tcpip_if *ifp) { MG_INFO((" MAC: %M", mg_print_mac, ifp->mac)); if (ifp->l2type == MG_TCPIP_L2_ETH) mg_tcpip_arp_request(ifp, ifp->ip, ifp->mac); // gratuitous ARP annc + if (ifp->is_ip_changed) { + struct mg_connection *c; + for (c = ifp->mgr->conns; c != NULL; c = c->next) { + if (!c->is_listening && !c->is_udp) c->is_closing = 1; + } + ifp->is_ip_changed = false; + } } else if (ifp->state == MG_TCPIP_STATE_IP) { if (ifp->gw != 0 && ifp->l2type == MG_TCPIP_L2_ETH) mg_tcpip_arp_request(ifp, ifp->gw, NULL); // unsolicited GW ARP request @@ -700,6 +707,7 @@ static void rx_dhcp_client(struct mg_tcpip_if *ifp, struct pkt *pkt) { // assume DHCP server = router until ARP resolves memcpy(ifp->gwmac, mg_l2_getaddr(ifp, pkt->l2), sizeof(ifp->gwmac)); ifp->gw_ready = true; // NOTE(): actual gw ARP won't retry now + if (ifp->ip != ip) ifp->is_ip_changed = true; ifp->ip = ip, ifp->gw = gw, ifp->mask = mask; ifp->state = MG_TCPIP_STATE_IP; // BOUND state mg_random(&rand, sizeof(rand)); @@ -955,7 +963,7 @@ static void rx_ndp_ra(struct mg_tcpip_if *ifp, struct pkt *pkt) { struct ndp_ra *ra = (struct ndp_ra *) (pkt->icmp6 + 1); uint8_t *opts = (uint8_t *) (ra + 1); size_t opt_left = pkt->pay.len - 12; - bool gotl2addr = false, gotprefix = false; + bool gotl2addr = false, gotprefix = false, changed = false; uint8_t l2[sizeof(struct mg_l2addr)]; uint32_t mtu = 0; uint8_t *prefix, prefix_len; @@ -988,6 +996,8 @@ static void rx_ndp_ra(struct mg_tcpip_if *ifp, struct pkt *pkt) { (void) pref_lifetime; gotprefix = true; + if (prefix_len != ifp->prefix || !match_prefix(prefix, ifp->prefix, ifp->prefix_len)) + changed = true; } opts += length; opt_left -= length; @@ -995,6 +1005,7 @@ static void rx_ndp_ra(struct mg_tcpip_if *ifp, struct pkt *pkt) { // fill prefix and global if (gotprefix && !fill_global(ifp, prefix, prefix_len)) return; + if (changed) ifp->is_ip6_changed = true; ifp->gw6[0] = pkt->ip6->src[0], ifp->gw6[1] = pkt->ip6->src[1]; if (gotl2addr) memcpy(ifp->gw6mac, l2, sizeof(ifp->gw6mac)); if (gotl2addr || ifp->l2type == MG_TCPIP_L2_PPP || ifp->l2type == MG_TCPIP_L2_PPPoE) { @@ -1073,6 +1084,12 @@ static void onstate6change(struct mg_tcpip_if *ifp) { (struct mg_addr *) &ip6_allrouters), ifp->ip6, (uint64_t *) ip6_allrouters.addr.ip6, false, ifp->mac); + if (ifp->is_ip6_changed) { + struct mg_connection *c; + for (c = ifp->mgr->conns; c != NULL; c = c->next) { + if (!c->is_listening && !c->is_udp) c->is_closing = 1; + } + ifp->is_ip6_changed = false; } } else if (ifp->state6 == MG_TCPIP_STATE_IP) { if ((ifp->gw6[0] != 0 || ifp->gw6[1] != 0) && (ifp->l2type != MG_TCPIP_L2_PPP && ifp->l2type != MG_TCPIP_L2_PPPoE)) diff --git a/src/net_builtin.h b/src/net_builtin.h index d9e93547b9..1e74a606de 100644 --- a/src/net_builtin.h +++ b/src/net_builtin.h @@ -50,6 +50,7 @@ struct mg_tcpip_if { bool enable_fcs_check; // Do a FCS check on RX frames and strip it bool enable_mac_check; // Do a hw addr check on RX frames bool update_mac_hash_table; // Signal drivers to update MAC controller + bool is_ip_changed; // IP address changed, close/restart conns struct mg_tcpip_driver *driver; // Low level driver void *driver_data; // Driver-specific data mg_tcpip_event_handler_t pfn; // Driver-specific event handler function @@ -66,6 +67,7 @@ struct mg_tcpip_if { uint64_t gw6[2]; // default gateway. bool enable_slaac; // Enable IPv6 address autoconfiguration bool enable_dhcp6_client; // Enable DCHPv6 client TODO() + bool is_ip6_changed; // IPv6 address changed, close/restart conns #endif // Internal state, user can use it but should not change it