Skip to content

Commit

Permalink
slirp: Read host DNS config on demand
Browse files Browse the repository at this point in the history
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 <[email protected]>
Signed-off-by: Anthony Liguori <[email protected]>
  • Loading branch information
Ed Swierk authored and Anthony Liguori committed Aug 28, 2009
1 parent ce0bd02 commit df7a86e
Show file tree
Hide file tree
Showing 6 changed files with 44 additions and 14 deletions.
3 changes: 2 additions & 1 deletion slirp/ip_icmp.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
2 changes: 2 additions & 0 deletions slirp/libslirp.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
1 change: 0 additions & 1 deletion slirp/main.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
46 changes: 36 additions & 10 deletions slirp/slirp.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -49,16 +47,24 @@ 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;
DWORD ret;
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);

Expand All @@ -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;
Expand All @@ -96,14 +104,34 @@ 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];
FILE *f;
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;
Expand All @@ -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(", ");
Expand Down Expand Up @@ -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);
Expand Down
3 changes: 2 additions & 1 deletion slirp/socket.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
3 changes: 2 additions & 1 deletion slirp/tcp_subr.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down

0 comments on commit df7a86e

Please sign in to comment.