From patchwork Mon Aug 3 20:25:08 2009 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ed Swierk X-Patchwork-Id: 30687 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [199.232.76.165]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client did not present a certificate) by bilbo.ozlabs.org (Postfix) with ESMTPS id 0CCD7B6F1F for ; Tue, 4 Aug 2009 08:55:09 +1000 (EST) Received: from localhost ([127.0.0.1]:43566 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1MY6Qq-0002eH-RV for incoming@patchwork.ozlabs.org; Mon, 03 Aug 2009 18:55:05 -0400 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1MY460-00022R-No for qemu-devel@nongnu.org; Mon, 03 Aug 2009 16:25:24 -0400 Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1MY45v-0001yw-CH for qemu-devel@nongnu.org; Mon, 03 Aug 2009 16:25:23 -0400 Received: from [199.232.76.173] (port=36629 helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1MY45v-0001yi-6I for qemu-devel@nongnu.org; Mon, 03 Aug 2009 16:25:19 -0400 Received: from mail-pz0-f196.google.com ([209.85.222.196]:41292) by monty-python.gnu.org with esmtp (Exim 4.60) (envelope-from ) id 1MY45u-0004ji-3w for qemu-devel@nongnu.org; Mon, 03 Aug 2009 16:25:18 -0400 Received: by pzk34 with SMTP id 34so2602296pzk.4 for ; Mon, 03 Aug 2009 13:25:14 -0700 (PDT) Received: by 10.114.102.16 with SMTP id z16mr9850197wab.35.1249331113828; Mon, 03 Aug 2009 13:25:13 -0700 (PDT) Received: from ?172.17.2.29? (65-119-47-100.dia.static.qwest.net [65.119.47.100]) by mx.google.com with ESMTPS id m6sm11597632wag.68.2009.08.03.13.25.11 (version=SSLv3 cipher=RC4-MD5); Mon, 03 Aug 2009 13:25:12 -0700 (PDT) From: Ed Swierk To: qemu-devel@nongnu.org Date: Mon, 03 Aug 2009 13:25:08 -0700 Message-Id: <1249331108.5541.9.camel@localhost.localdomain> Mime-Version: 1.0 X-Mailer: Evolution 2.26.3 (2.26.3-1.fc11) X-detected-operating-system: by monty-python.gnu.org: GNU/Linux 2.6 (newer, 2) Subject: [Qemu-devel] [PATCH] slirp: Read host DNS config on demand (v2) X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Currently the qemu user-mode networking stack reads the host DNS configuration (/etc/resolv.conf or the Windows equivalent) only once when qemu starts. This causes name lookups in the guest to fail if the host is moved to a different network from which the original DNS servers are unreachable, a common occurrence when the host is a laptop. This patch changes the slirp code to read the host DNS configuration on demand, caching the results to avoid unnecessary overhead if name lookups occur in rapid succession. v2: Cache the DNS server address for 1 second instead of 10 seconds; on non-Windows hosts, reread /etc/resolv.conf only if the file has been replaced or if its size or mtime has changed. Signed-off-by: Ed Swierk diff --git a/slirp/ip_icmp.c b/slirp/ip_icmp.c index 95a4b39..751a8e2 100644 --- a/slirp/ip_icmp.c +++ b/slirp/ip_icmp.c @@ -127,7 +127,8 @@ icmp_input(struct mbuf *m, int hlen) slirp->vnetwork_addr.s_addr) { /* It's an alias */ if (so->so_faddr.s_addr == slirp->vnameserver_addr.s_addr) { - addr.sin_addr = dns_addr; + if (get_dns_addr(&addr.sin_addr) < 0) + addr.sin_addr = loopback_addr; } else { addr.sin_addr = loopback_addr; } diff --git a/slirp/libslirp.h b/slirp/libslirp.h index 93087ed..67c70e3 100644 --- a/slirp/libslirp.h +++ b/slirp/libslirp.h @@ -8,6 +8,8 @@ struct Slirp; typedef struct Slirp Slirp; +int get_dns_addr(struct in_addr *pdns_addr); + Slirp *slirp_init(int restricted, struct in_addr vnetwork, struct in_addr vnetmask, struct in_addr vhost, const char *vhostname, const char *tftp_path, diff --git a/slirp/main.h b/slirp/main.h index 9f22fe1..8d09df9 100644 --- a/slirp/main.h +++ b/slirp/main.h @@ -31,7 +31,6 @@ extern char *exec_shell; extern u_int curtime; extern fd_set *global_readfds, *global_writefds, *global_xfds; extern struct in_addr loopback_addr; -extern struct in_addr dns_addr; extern char *username; extern char *socket_path; extern int towrite_max; diff --git a/slirp/slirp.c b/slirp/slirp.c index da04ad1..b5335a5 100644 --- a/slirp/slirp.c +++ b/slirp/slirp.c @@ -27,8 +27,6 @@ #include "slirp.h" #include "hw/hw.h" -/* host dns address */ -struct in_addr dns_addr; /* host loopback address */ struct in_addr loopback_addr; @@ -49,9 +47,12 @@ static int do_slowtimo; static TAILQ_HEAD(slirp_instances, Slirp) slirp_instances = TAILQ_HEAD_INITIALIZER(slirp_instances); +struct in_addr dns_addr = { 0 }; +u_int dns_addr_time = 0; + #ifdef _WIN32 -static int get_dns_addr(struct in_addr *pdns_addr) +int get_dns_addr(struct in_addr *pdns_addr) { FIXED_INFO *FixedInfo=NULL; ULONG BufLen; @@ -59,6 +60,11 @@ static int get_dns_addr(struct in_addr *pdns_addr) IP_ADDR_STRING *pIPAddr; struct in_addr tmp_addr; + if (dns_addr.s_addr != 0 && (curtime - dns_addr_time) < 1000) { + *pdns_addr = dns_addr; + return 0; + } + FixedInfo = (FIXED_INFO *)GlobalAlloc(GPTR, sizeof(FIXED_INFO)); BufLen = sizeof(FIXED_INFO); @@ -82,6 +88,8 @@ static int get_dns_addr(struct in_addr *pdns_addr) pIPAddr = &(FixedInfo->DnsServerList); inet_aton(pIPAddr->IpAddress.String, &tmp_addr); *pdns_addr = tmp_addr; + dns_addr = tmp_addr; + dns_addr_time = curtime; if (FixedInfo) { GlobalFree(FixedInfo); FixedInfo = NULL; @@ -96,7 +104,9 @@ static void winsock_cleanup(void) #else -static int get_dns_addr(struct in_addr *pdns_addr) +struct stat dns_addr_stat; + +int get_dns_addr(struct in_addr *pdns_addr) { char buff[512]; char buff2[257]; @@ -104,6 +114,24 @@ static int get_dns_addr(struct in_addr *pdns_addr) int found = 0; struct in_addr tmp_addr; + if (dns_addr.s_addr != 0) { + struct stat old_stat; + if ((curtime - dns_addr_time) < 1000) { + *pdns_addr = dns_addr; + return 0; + } + old_stat = dns_addr_stat; + if (stat("/etc/resolv.conf", &dns_addr_stat) != 0) + return -1; + if ((dns_addr_stat.st_dev == old_stat.st_dev) + && (dns_addr_stat.st_ino == old_stat.st_ino) + && (dns_addr_stat.st_size == old_stat.st_size) + && (dns_addr_stat.st_mtime == old_stat.st_mtime)) { + *pdns_addr = dns_addr; + return 0; + } + } + f = fopen("/etc/resolv.conf", "r"); if (!f) return -1; @@ -116,8 +144,11 @@ static int get_dns_addr(struct in_addr *pdns_addr) if (!inet_aton(buff2, &tmp_addr)) continue; /* If it's the first one, set it to dns_addr */ - if (!found) + if (!found) { *pdns_addr = tmp_addr; + dns_addr = tmp_addr; + dns_addr_time = curtime; + } #ifdef DEBUG else lprint(", "); @@ -160,11 +191,6 @@ static void slirp_init_once(void) #endif loopback_addr.s_addr = htonl(INADDR_LOOPBACK); - - /* FIXME: This address may change during runtime */ - if (get_dns_addr(&dns_addr) < 0) { - dns_addr = loopback_addr; - } } static void slirp_state_save(QEMUFile *f, void *opaque); diff --git a/slirp/socket.c b/slirp/socket.c index d8fbe89..207109c 100644 --- a/slirp/socket.c +++ b/slirp/socket.c @@ -552,7 +552,8 @@ sosendto(struct socket *so, struct mbuf *m) slirp->vnetwork_addr.s_addr) { /* It's an alias */ if (so->so_faddr.s_addr == slirp->vnameserver_addr.s_addr) { - addr.sin_addr = dns_addr; + if (get_dns_addr(&addr.sin_addr) < 0) + addr.sin_addr = loopback_addr; } else { addr.sin_addr = loopback_addr; } diff --git a/slirp/tcp_subr.c b/slirp/tcp_subr.c index 51b3834..0417345 100644 --- a/slirp/tcp_subr.c +++ b/slirp/tcp_subr.c @@ -340,7 +340,8 @@ int tcp_fconnect(struct socket *so) slirp->vnetwork_addr.s_addr) { /* It's an alias */ if (so->so_faddr.s_addr == slirp->vnameserver_addr.s_addr) { - addr.sin_addr = dns_addr; + if (get_dns_addr(&addr.sin_addr) < 0) + addr.sin_addr = loopback_addr; } else { addr.sin_addr = loopback_addr; }