summaryrefslogtreecommitdiff
path: root/gweb
diff options
context:
space:
mode:
authorDavid Woodhouse <David.Woodhouse@intel.com>2010-12-01 16:40:52 +0000
committerDavid Woodhouse <David.Woodhouse@intel.com>2010-12-01 21:47:46 +0000
commit40fca394d11b9e6104e5f9c8ff6090c5af719a1b (patch)
treed8c3ae0f84ae0b8a2afdd185f9fc1b622b4be65b /gweb
parent3c9edd5e215d2939b0f61c7f6cd87d30c6965f6d (diff)
downloadconnman-40fca394d11b9e6104e5f9c8ff6090c5af719a1b.tar.gz
connman-40fca394d11b9e6104e5f9c8ff6090c5af719a1b.tar.bz2
connman-40fca394d11b9e6104e5f9c8ff6090c5af719a1b.zip
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.
Diffstat (limited to 'gweb')
-rw-r--r--gweb/gresolv.c57
1 files changed, 43 insertions, 14 deletions
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 <stdarg.h>
#include <string.h>
#include <resolv.h>
+#include <sys/types.h>
#include <sys/socket.h>
+#include <netdb.h>
#include <arpa/inet.h>
#include <arpa/nameser.h>
@@ -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)