aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEd Swierk <eswierk@aristanetworks.com>2009-08-20 19:00:31 -0700
committerAnthony Liguori <aliguori@us.ibm.com>2009-08-27 20:46:58 -0500
commitdf7a86ed735eafefbd046c8cad7134652fe3f600 (patch)
tree585563918d17462f707cebdae337d5fcde45d927
parentce0bd027df9c62766a5417521d0f08f27359d43f (diff)
downloadqemu-df7a86ed735eafefbd046c8cad7134652fe3f600.zip
qemu-df7a86ed735eafefbd046c8cad7134652fe3f600.tar.gz
qemu-df7a86ed735eafefbd046c8cad7134652fe3f600.tar.bz2
slirp: Read host DNS config on demand
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 for at most 1 second to avoid unnecessary overhead if name lookups occur in rapid succession. On non-Windows hosts, /etc/resolv.conf is re-read only if the file has been replaced or if its size or mtime has changed. Signed-off-by: Ed Swierk <eswierk@aristanetworks.com> Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
-rw-r--r--slirp/ip_icmp.c3
-rw-r--r--slirp/libslirp.h2
-rw-r--r--slirp/main.h1
-rw-r--r--slirp/slirp.c46
-rw-r--r--slirp/socket.c3
-rw-r--r--slirp/tcp_subr.c3
6 files changed, 44 insertions, 14 deletions
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;
}