From 40fca394d11b9e6104e5f9c8ff6090c5af719a1b Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Wed, 1 Dec 2010 16:40:52 +0000 Subject: gresolv: Fix handling of IPv6 nameservers If IPv6 nameservers were specified in /etc/resolv.conf, we would end up sending NS queries to 0.0.0.0 because we weren't parsing the __res_state structure correctly. We were assuming that all listed nameservers would be Legacy IP. Also fix connect_udp_channel() to generate the address correctly instead of just asssuming Legacy IP. --- gweb/gresolv.c | 57 +++++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 43 insertions(+), 14 deletions(-) (limited to 'gweb') diff --git a/gweb/gresolv.c b/gweb/gresolv.c index 99dc57a1..539eb2d7 100644 --- a/gweb/gresolv.c +++ b/gweb/gresolv.c @@ -28,7 +28,9 @@ #include #include #include +#include #include +#include #include #include @@ -303,23 +305,40 @@ static gboolean received_udp_data(GIOChannel *channel, GIOCondition cond, static int connect_udp_channel(struct resolv_nameserver *nameserver) { - struct sockaddr_in sin; - int sk; - - sk = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); - if (sk < 0) + struct addrinfo hints, *rp; + char portnr[6]; + int err, sk; + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_DGRAM; + hints.ai_flags = AI_PASSIVE | AI_NUMERICSERV | AI_NUMERICHOST; + + sprintf(portnr, "%d", nameserver->port); + err = getaddrinfo(nameserver->address, portnr, &hints, &rp); + if (err) + return -EINVAL; + + /* Do not blindly copy this code elsewhere; it doesn't loop over the + results using ->ai_next as it should. That's OK in *this* case + because it was a numeric lookup; we *know* there's only one. */ + if (!rp) + return -EINVAL; + + sk = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); + if (sk < 0) { + freeaddrinfo(rp); return -EIO; + } - memset(&sin, 0, sizeof(sin)); - sin.sin_family = AF_INET; - sin.sin_port = htons(nameserver->port); - sin.sin_addr.s_addr = inet_addr(nameserver->address); - - if (connect(sk, (struct sockaddr *) &sin, sizeof(sin)) < 0) { + if (connect(sk, rp->ai_addr, rp->ai_addrlen) < 0) { close(sk); + freeaddrinfo(rp); return -EIO; } + freeaddrinfo(rp); + nameserver->udp_channel = g_io_channel_unix_new(sk); if (nameserver->udp_channel == NULL) { close(sk); @@ -461,9 +480,19 @@ guint g_resolv_lookup_hostname(GResolv *resolv, const char *hostname, int i; for (i = 0; i < resolv->res.nscount; i++) { - struct sockaddr_in *addr = &resolv->res.nsaddr_list[i]; - g_resolv_add_nameserver(resolv, - inet_ntoa(addr->sin_addr), 53, 0); + char buf[100]; + int family = resolv->res.nsaddr_list[i].sin_family; + void *sa_addr = &resolv->res.nsaddr_list[i].sin_addr; + + if (family != AF_INET && resolv->res._u._ext.nsaddrs[i]) { + family = AF_INET6; + sa_addr = &resolv->res._u._ext.nsaddrs[i]->sin6_addr; + } + if (family != AF_INET && family != AF_INET6) + continue; + + if (inet_ntop(family, sa_addr, buf, sizeof(buf))) + g_resolv_add_nameserver(resolv, buf, 53, 0); } if (resolv->nameserver_list == NULL) -- cgit v1.2.3