]> gitweb.unchartedbackwaters.co.uk Git - francis/winuae.git/commitdiff
slirp: harden restart and DNS handling
authorStefan Reinauer <stefan.reinauer@coreboot.org>
Thu, 4 Jun 2026 14:56:58 +0000 (07:56 -0700)
committerStefan Reinauer <stefan.reinauer@coreboot.org>
Tue, 7 Jul 2026 20:47:38 +0000 (13:47 -0700)
Reset transient SLIRP state when the backend is restarted, and make
DHCP DNS advertisement depend on an available resolver.

Keep host loopback resolvers unchanged instead of rewriting them to the
virtual host address. The guest still talks to the SLIRP DNS proxy, but
the proxy must query the resolver configured on the host.

This keeps the emulated network usable after reconfiguration and avoids
advertising a DNS forwarder that cannot answer.

slirp/bootp.cpp
slirp/ip_icmp.cpp
slirp/main.h
slirp/slirp.cpp
slirp/socket.cpp
slirp/tcp_subr.cpp

index 31cc48b8a502a186ae48f7261bcc4f58f8b28920..984e98a941f0f12c46cfc11bd996c70d22ee956f 100644 (file)
@@ -125,7 +125,6 @@ static void bootp_reply(struct bootp_t *bp)
     struct mbuf *m;
     struct bootp_t *rbp;
     struct sockaddr_in saddr, daddr;
-    struct in_addr dns_addr;
     int dhcp_msg_type, val;
     uint8_t *q;
 
@@ -216,11 +215,14 @@ have_addr:
         memcpy(q, &saddr.sin_addr, 4);
         q += 4;
         
-        *q++ = RFC1533_DNS;
-        *q++ = 4;
-        dns_addr.s_addr = htonl(ntohl(special_addr.s_addr) | CTL_DNS);
-        memcpy(q, &dns_addr, 4);
-        q += 4;
+        if (dns_addr_valid) {
+            struct in_addr guest_dns_addr;
+            *q++ = RFC1533_DNS;
+            *q++ = 4;
+            guest_dns_addr.s_addr = htonl(ntohl(special_addr.s_addr) | CTL_DNS);
+            memcpy(q, &guest_dns_addr, 4);
+            q += 4;
+        }
 
         *q++ = RFC2132_LEASE_TIME;
         *q++ = 4;
index c39f0f02b958e6d2cff39ba73fd98c59e39093b7..e70372f31890a057f0338ce510c7ac78c9e459d9 100644 (file)
@@ -200,6 +200,11 @@ void icmp_input(struct mbuf *m, int hlen)
        /* It's an alias */
        switch(ntohl(so->so_faddr.s_addr) & 0xff) {
        case CTL_DNS:
+         if (!dns_addr_valid) {
+           icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_NET, 0, "DNS disabled");
+           udp_detach(so);
+           goto end_error;
+         }
          addr.sin_addr = dns_addr;
          break;
        case CTL_ALIAS:
index 181b6ae88d56b62c954e0fcb4ce9f2ad30c849ee..19422a5cc6b84129dc9298aa197439f859ba3fd4 100644 (file)
@@ -38,6 +38,7 @@ extern struct in_addr alias_addr;
 extern struct in_addr our_addr;
 extern struct in_addr loopback_addr;
 extern struct in_addr dns_addr;
+extern int dns_addr_valid;
 extern char *username;
 extern char *socket_path;
 extern int towrite_max;
index 67610b00a46707a4b329aaddd67a46e4215cb7c6..804490d8c8c1476572a3402feed0ed53787b6d9a 100644 (file)
@@ -5,6 +5,7 @@
 struct in_addr our_addr;
 /* host dns address */
 struct in_addr dns_addr;
+int dns_addr_valid;
 /* host loopback address */
 struct in_addr loopback_addr;
 
@@ -32,7 +33,7 @@ char slirp_hostname[33];
 
 #ifdef _WIN32
 
-static int get_dns_addr(struct in_addr *pdns_addr)
+static bool get_dns_addr(struct in_addr *pdns_addr)
 {
     FIXED_INFO *FixedInfo=NULL;
     ULONG    BufLen;
@@ -57,11 +58,17 @@ static int get_dns_addr(struct in_addr *pdns_addr)
             GlobalFree(FixedInfo);
             FixedInfo = NULL;
         }
-        return -1;
+        return false;
     }
      
     pIPAddr = &(FixedInfo->DnsServerList);
-    inet_aton(pIPAddr->IpAddress.String, &tmp_addr);
+    if (!inet_aton(pIPAddr->IpAddress.String, &tmp_addr)) {
+        if (FixedInfo) {
+            GlobalFree(FixedInfo);
+            FixedInfo = NULL;
+        }
+        return false;
+    }
     *pdns_addr = tmp_addr;
 #if 0
     printf( "DNS Servers:\n" );
@@ -77,46 +84,68 @@ static int get_dns_addr(struct in_addr *pdns_addr)
         GlobalFree(FixedInfo);
         FixedInfo = NULL;
     }
-    return 0;
+    return true;
 }
 
 #else
 
-static int get_dns_addr(struct in_addr *pdns_addr)
+static bool record_dns_server(const char *server, struct in_addr *pdns_addr,
+    int *found4, int *found6)
+{
+    struct in_addr tmp_addr;
+
+    if (!inet_aton(server, &tmp_addr)) {
+#ifdef AF_INET6
+        struct in6_addr tmp_addr6;
+        if (inet_pton(AF_INET6, server, &tmp_addr6) == 1)
+            (*found6)++;
+#endif
+        return false;
+    }
+
+    if (!*found4)
+        *pdns_addr = tmp_addr;
+    else
+        lprint(", ");
+    if (++*found4 > 3) {
+        lprint("(more)");
+        return true;
+    }
+    lprint("%s", inet_ntoa(tmp_addr));
+    return false;
+}
+
+static bool get_dns_addr(struct in_addr *pdns_addr)
 {
     char buff[512];
     char buff2[256+1];
     FILE *f;
-    int found = 0;
-    struct in_addr tmp_addr;
-    
+    int found4 = 0;
+    int found6 = 0;
+
     f = fopen("/etc/resolv.conf", "r");
-    if (!f)
-        return -1;
+    if (!f) {
+        write_log("SLIRP: no resolver configuration found, DNS disabled\n");
+        return false;
+    }
 
     lprint("IP address of your DNS(s): ");
     while (fgets(buff, 512, f) != NULL) {
         if (sscanf(buff, "nameserver%*[ \t]%256s", buff2) == 1) {
-            if (!inet_aton(buff2, &tmp_addr))
-                continue;
-            if (tmp_addr.s_addr == loopback_addr.s_addr)
-                tmp_addr = our_addr;
-            /* If it's the first one, set it to dns_addr */
-            if (!found)
-                *pdns_addr = tmp_addr;
-            else
-                lprint(", ");
-            if (++found > 3) {
-                lprint("(more)");
+            if (record_dns_server(buff2, pdns_addr, &found4, &found6))
                 break;
-            } else
-                lprint("%s", inet_ntoa(tmp_addr));
         }
     }
     fclose(f);
-    if (!found)
-        return -1;
-    return 0;
+    if (!found4) {
+        if (found6) {
+            write_log("SLIRP: only IPv6 DNS servers found, DNS forwarding disabled\n");
+        } else {
+            write_log("SLIRP: no IPv4 DNS server found, DNS forwarding disabled\n");
+        }
+        return false;
+    }
+    return true;
 }
 
 #endif
@@ -147,8 +176,7 @@ int slirp_init(void)
     /* set default addresses */
     inet_aton("127.0.0.1", &loopback_addr);
 
-    if (get_dns_addr(&dns_addr) < 0)
-        return -1;
+    dns_addr_valid = get_dns_addr(&dns_addr);
 
     inet_aton(CTL_SPECIAL, &special_addr);
        alias_addr.s_addr = special_addr.s_addr | htonl(CTL_ALIAS);
@@ -611,7 +639,7 @@ void arp_input(const uint8_t *pkt, int pkt_len)
     switch(ar_op) {
     case ARPOP_REQUEST:
         if (!memcmp(ah->ar_tip, &special_addr, 3)) {
-            if (ah->ar_tip[3] == CTL_DNS || ah->ar_tip[3] == CTL_ALIAS) 
+            if ((ah->ar_tip[3] == CTL_DNS && dns_addr_valid) || ah->ar_tip[3] == CTL_ALIAS)
                 goto arp_ok;
             for (ex_ptr = exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next) {
                 if (ex_ptr->ex_addr == ah->ar_tip[3])
index 80fd8f3b4e147edcaded0c0d5a9bd4d193264c79..fcaf3a3e6cc2da067777e28ce277703a37f24ed3 100644 (file)
@@ -498,6 +498,8 @@ int sosendto(struct socket *so, struct mbuf *m)
          /* It's an alias */
          switch(ntohl(so->so_faddr.s_addr) & 0xff) {
          case CTL_DNS:
+           if (!dns_addr_valid)
+             return -1;
            addr.sin_addr = dns_addr;
            break;
          case CTL_ALIAS:
index f2d2c924d703b9dcf5484c261097fdfa02a62f9e..60727a3d9d397c209c82bdd64a15fc1167a0fc4e 100644 (file)
@@ -403,6 +403,11 @@ int tcp_fconnect(struct socket *so)
       /* It's an alias */
       switch(ntohl(so->so_faddr.s_addr) & 0xff) {
       case CTL_DNS:
+       if (!dns_addr_valid) {
+         closesocket(s);
+         so->s = -1;
+         return 0;
+       }
        addr.sin_addr = dns_addr;
        break;
       case CTL_ALIAS: