*
* Resolver library with GLib integration
*
- * Copyright (C) 2009-2010 Intel Corporation. All rights reserved.
+ * Copyright (C) 2009-2012 Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
#include <netdb.h>
#include <arpa/inet.h>
#include <arpa/nameser.h>
+#include <net/if.h>
#include "gresolv.h"
};
struct _GResolv {
- gint ref_count;
+ int ref_count;
+
+ int result_family;
guint next_lookup_id;
GQueue *lookup_queue;
socklen_t sl = sizeof(res->src);
int fd;
- fd = socket(res->dst.sa.sa_family, SOCK_DGRAM, IPPROTO_IP);
+ fd = socket(res->dst.sa.sa_family, SOCK_DGRAM | SOCK_CLOEXEC,
+ IPPROTO_IP);
if (fd < 0)
return;
static void sort_and_return_results(struct resolv_lookup *lookup)
{
- char buf[100];
+ char buf[INET6_ADDRSTRLEN + 1];
GResolvResultStatus status;
char **results = g_try_new0(char *, lookup->nr_results + 1);
int i, n = 0;
if (!results)
return;
+ memset(buf, 0, INET6_ADDRSTRLEN + 1);
+
rfc3484_sort_results(lookup);
for (i = 0; i < lookup->nr_results; i++) {
if (lookup->results[i].dst.sa.sa_family == AF_INET) {
if (inet_ntop(AF_INET,
&lookup->results[i].dst.sin.sin_addr,
- buf, sizeof(buf)) == NULL)
+ buf, sizeof(buf) - 1) == NULL)
continue;
} else if (lookup->results[i].dst.sa.sa_family == AF_INET6) {
if (inet_ntop(AF_INET6,
&lookup->results[i].dst.sin6.sin6_addr,
- buf, sizeof(buf)) == NULL)
+ buf, sizeof(buf) - 1) == NULL)
continue;
} else
continue;
sk = g_io_channel_unix_get_fd(nameserver->udp_channel);
sent = send(sk, buf, len, 0);
+ if (sent < 0)
+ continue;
}
return 0;
const void *data)
{
int n = lookup->nr_results++;
- lookup->results = g_realloc(lookup->results,
+ lookup->results = g_try_realloc(lookup->results,
sizeof(struct sort_result) * (n + 1));
+ if (lookup->results == NULL)
+ return;
memset(&lookup->results[n], 0, sizeof(struct sort_result));
GList *list;
ns_msg msg;
ns_rr rr;
- int i, n, rcode, count;
+ int i, rcode, count;
debug(resolv, "response from %s", nameserver->address);
lookup->ipv4_query = NULL;
}
- for (i = 0, n = 0; i < count; i++) {
+ for (i = 0; i < count; i++) {
ns_parserr(&msg, ns_s_an, i, &rr);
if (ns_rr_class(rr) != ns_c_in)
return -EIO;
}
+ /*
+ * If nameserver points to localhost ip, their is no need to
+ * bind the socket on any interface.
+ */
+ if (nameserver->resolv->index > 0 &&
+ strncmp(nameserver->address, "127.0.0.1", 9) != 0) {
+ char interface[IF_NAMESIZE];
+
+ memset(interface, 0, IF_NAMESIZE);
+ if (if_indextoname(nameserver->resolv->index,
+ interface) != NULL) {
+ if (setsockopt(sk, SOL_SOCKET, SO_BINDTODEVICE,
+ interface, IF_NAMESIZE) < 0) {
+ close(sk);
+ freeaddrinfo(rp);
+ return -EIO;
+ }
+ }
+ }
+
if (connect(sk, rp->ai_addr, rp->ai_addrlen) < 0) {
close(sk);
freeaddrinfo(rp);
resolv->ref_count = 1;
+ resolv->result_family = AF_UNSPEC;
+
resolv->next_lookup_id = 1;
resolv->query_queue = g_queue_new();
if (resolv == NULL)
return NULL;
- g_atomic_int_inc(&resolv->ref_count);
+ __sync_fetch_and_add(&resolv->ref_count, 1);
return resolv;
}
if (resolv == NULL)
return;
- if (g_atomic_int_dec_and_test(&resolv->ref_count) == FALSE)
+ if (__sync_fetch_and_sub(&resolv->ref_count, 1) != 1)
return;
while ((query = g_queue_pop_head(resolv->query_queue)))
nameserver->address = g_strdup(address);
nameserver->port = port;
nameserver->flags = flags;
+ nameserver->resolv = resolv;
if (connect_udp_channel(nameserver) < 0) {
free_nameserver(nameserver);
return FALSE;
}
- nameserver->resolv = resolv;
-
resolv->nameserver_list = g_list_append(resolv->nameserver_list,
nameserver);
query->msgid = buf[0] << 8 | buf[1];
- if (send_query(lookup->resolv, buf, len) < 0)
+ if (send_query(lookup->resolv, buf, len) < 0) {
+ g_free(query);
return -EIO;
+ }
query->resolv = lookup->resolv;
query->lookup = lookup;
lookup->result_data = user_data;
lookup->id = resolv->next_lookup_id++;
- if (add_query(lookup, hostname, ns_t_a)) {
- g_free(lookup);
- return -EIO;
+ if (resolv->result_family != AF_INET6) {
+ if (add_query(lookup, hostname, ns_t_a)) {
+ g_free(lookup);
+ return -EIO;
+ }
}
- if (add_query(lookup, hostname, ns_t_aaaa)) {
- destroy_query(lookup->ipv4_query);
- g_queue_remove(resolv->query_queue, lookup->ipv4_query);
- g_free(lookup);
- return -EIO;
+ if (resolv->result_family != AF_INET) {
+ if (add_query(lookup, hostname, ns_t_aaaa)) {
+ if (resolv->result_family != AF_INET6) {
+ destroy_query(lookup->ipv4_query);
+ g_queue_remove(resolv->query_queue,
+ lookup->ipv4_query);
+ }
+
+ g_free(lookup);
+ return -EIO;
+ }
}
g_queue_push_tail(resolv->lookup_queue, lookup);
return TRUE;
}
+
+gboolean g_resolv_set_address_family(GResolv *resolv, int family)
+{
+ if (resolv == NULL)
+ return FALSE;
+
+ if (family != AF_UNSPEC && family != AF_INET && family != AF_INET6)
+ return FALSE;
+
+ resolv->result_family = family;
+
+ return TRUE;
+}