#endif
#include <errno.h>
+#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdint.h>
static GSList *server_list = NULL;
static GSList *request_list = NULL;
static GSList *request_pending_list = NULL;
-static guint16 request_id = 0x0000;
static GHashTable *listener_table = NULL;
static time_t next_refresh;
+static guint16 get_id()
+{
+ return random();
+}
+
static int protocol_offset(int protocol)
{
switch (protocol) {
*/
ptr = reply + offset + sizeof(struct domain_hdr);
host_len = *ptr;
- domain_len = strlen((const char *)ptr) - host_len - 1;
+ domain_len = strlen((const char *)ptr + host_len + 1);
/*
- * remove the domain name and replaced it by the end
- * of reply.
+ * Remove the domain name and replace it by the end
+ * of reply. Check if the domain is really there
+ * before trying to copy the data. The domain_len can
+ * be 0 because if the original query did not contain
+ * a domain name, then we are sending two packets,
+ * first without the domain name and the second packet
+ * with domain name. The append_domain is set to true
+ * even if we sent the first packet without domain
+ * name. In this case we end up in this branch.
*/
- memmove(ptr + host_len + 1,
- ptr + host_len + domain_len + 1,
- reply_len - (ptr - reply + domain_len));
+ if (domain_len > 0) {
+ /*
+ * Note that we must use memmove() here,
+ * because the memory areas can overlap.
+ */
+ memmove(ptr + host_len + 1,
+ ptr + host_len + domain_len + 1,
+ reply_len - (ptr - reply + domain_len));
- reply_len = reply_len - domain_len;
+ reply_len = reply_len - domain_len;
+ }
}
g_free(req->resp);
gpointer request, gpointer name)
{
GSList *list;
- int status;
for (list = server_list; list; list = list->next) {
struct server_data *data = list->data;
G_IO_IN | G_IO_NVAL | G_IO_ERR | G_IO_HUP,
udp_server_event, data);
- status = ns_resolv(data, req, request, name);
- if (status < 0)
- continue;
-
- if (status > 0) {
- if (req->timeout > 0) {
- g_source_remove(req->timeout);
- req->timeout = 0;
- }
- }
+ if (ns_resolv(data, req, request, name) > 0)
+ return TRUE;
}
- return TRUE;
+ return FALSE;
}
static void append_domain(const char *interface, const char *domain)
if (hdr->qr != 0 || qdcount != 1)
return -EINVAL;
- memset(name, 0, size);
+ name[0] = '\0';
ptr = buf + sizeof(struct domain_hdr);
remain = len - sizeof(struct domain_hdr);
req->client_sk = client_sk;
req->protocol = IPPROTO_TCP;
- request_id += 2;
- if (request_id == 0x0000 || request_id == 0xffff)
- request_id += 2;
-
req->srcid = buf[2] | (buf[3] << 8);
- req->dstid = request_id;
- req->altid = request_id + 1;
+ req->dstid = get_id();
+ req->altid = get_id();
req->request_len = len;
buf[2] = req->dstid & 0xff;
req->client_sk = 0;
req->protocol = IPPROTO_UDP;
- request_id += 2;
- if (request_id == 0x0000 || request_id == 0xffff)
- request_id += 2;
-
req->srcid = buf[0] | (buf[1] << 8);
- req->dstid = request_id;
- req->altid = request_id + 1;
+ req->dstid = get_id();
+ req->altid = get_id();
req->request_len = len;
buf[0] = req->dstid & 0xff;
req->numserv = 0;
req->ifdata = (struct listener_data *) ifdata;
- req->timeout = g_timeout_add_seconds(5, request_timeout, req);
req->append_domain = FALSE;
+
+ if (resolv(req, buf, query) == TRUE) {
+ /* a cached result was sent, so the request can be released */
+ g_free(req);
+ return TRUE;
+ }
+
+ req->timeout = g_timeout_add_seconds(5, request_timeout, req);
request_list = g_slist_append(request_list, req);
- return resolv(req, buf, query);
+ return TRUE;
}
static int create_dns_listener(int protocol, struct listener_data *ifdata)
DBG("");
+ srandom(time(NULL));
+
listener_table = g_hash_table_new_full(g_str_hash, g_str_equal,
g_free, g_free);
err = __connman_dnsproxy_add_listener("lo");