supplicant: Call scan callback if needed when removing interface
[framework/connectivity/connman.git] / src / dnsproxy.c
index 83ec419..d7ef63b 100644 (file)
@@ -24,6 +24,7 @@
 #endif
 
 #include <errno.h>
+#include <stdlib.h>
 #include <unistd.h>
 #include <string.h>
 #include <stdint.h>
@@ -183,10 +184,14 @@ static int cache_refcount;
 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) {
@@ -1551,17 +1556,30 @@ static int forward_dns_reply(unsigned char *reply, int reply_len, int 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);
@@ -1654,7 +1672,7 @@ static void destroy_server(struct server_data *server)
        g_io_channel_unref(server->channel);
 
        if (server->protocol == IPPROTO_UDP)
-               connman_info("Removing DNS server %s", server->server);
+               DBG("Removing DNS server %s", server->server);
 
        g_free(server->incoming_reply);
        g_free(server->server);
@@ -2025,7 +2043,7 @@ static struct server_data *create_server(const char *interface,
        if (protocol == IPPROTO_UDP) {
                /* Enable new servers by default */
                data->enabled = TRUE;
-               connman_info("Adding DNS server %s", data->server);
+               DBG("Adding DNS server %s", data->server);
 
                server_list = g_slist_append(server_list, data);
 
@@ -2039,7 +2057,6 @@ static gboolean resolv(struct request_data *req,
                                gpointer request, gpointer name)
 {
        GSList *list;
-       int status;
 
        for (list = server_list; list; list = list->next) {
                struct server_data *data = list->data;
@@ -2054,19 +2071,11 @@ static gboolean resolv(struct request_data *req,
                                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)
@@ -2196,12 +2205,12 @@ static void dnsproxy_offline_mode(connman_bool_t enabled)
                struct server_data *data = list->data;
 
                if (enabled == FALSE) {
-                       connman_info("Enabling DNS server %s", data->server);
+                       DBG("Enabling DNS server %s", data->server);
                        data->enabled = TRUE;
                        cache_invalidate();
                        cache_refresh();
                } else {
-                       connman_info("Disabling DNS server %s", data->server);
+                       DBG("Disabling DNS server %s", data->server);
                        data->enabled = FALSE;
                        cache_invalidate();
                }
@@ -2232,10 +2241,10 @@ static void dnsproxy_default_changed(struct connman_service *service)
                struct server_data *data = list->data;
 
                if (g_strcmp0(data->interface, interface) == 0) {
-                       connman_info("Enabling DNS server %s", data->server);
+                       DBG("Enabling DNS server %s", data->server);
                        data->enabled = TRUE;
                } else {
-                       connman_info("Disabling DNS server %s", data->server);
+                       DBG("Disabling DNS server %s", data->server);
                        data->enabled = FALSE;
                }
        }
@@ -2272,7 +2281,7 @@ static int parse_request(unsigned char *buf, int len,
        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);
@@ -2379,13 +2388,9 @@ static gboolean tcp_listener_event(GIOChannel *channel, GIOCondition condition,
        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;
@@ -2498,13 +2503,9 @@ static gboolean udp_listener_event(GIOChannel *channel, GIOCondition condition,
        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;
@@ -2512,11 +2513,18 @@ static gboolean udp_listener_event(GIOChannel *channel, GIOCondition condition,
 
        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)
@@ -2775,6 +2783,8 @@ int __connman_dnsproxy_init(void)
 
        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");