Merge "Imported Upstream connman version 1.38" into tizen
[platform/upstream/connman.git] / src / dnsproxy.c
old mode 100644 (file)
new mode 100755 (executable)
index d1752a7..7956e7f
 
 #include "connman.h"
 
+#if defined TIZEN_EXT
+#include <sys/smack.h>
+#include <systemd/sd-daemon.h>
+#endif
+
+#define debug(fmt...) do { } while (0)
+
 #if __BYTE_ORDER == __LITTLE_ENDIAN
 struct domain_hdr {
        uint16_t id;
@@ -77,6 +84,11 @@ struct domain_hdr {
 #error "Unknown byte order"
 #endif
 
+struct qtype_qclass {
+       uint16_t qtype;
+       uint16_t qclass;
+} __attribute__ ((packed));
+
 struct partial_reply {
        uint16_t len;
        uint16_t received;
@@ -233,7 +245,11 @@ static struct server_data *create_server_sec(int index,
 
 static guint16 get_id(void)
 {
-       return random();
+       uint64_t rand;
+
+       __connman_util_get_random(&rand);
+
+       return rand;
 }
 
 static int protocol_offset(int protocol)
@@ -292,7 +308,7 @@ static struct server_data *find_server(int index,
 {
        GSList *list;
 
-       DBG("index %d server %s proto %d", index, server, protocol);
+       debug("index %d server %s proto %d", index, server, protocol);
 
        for (list = server_list; list; list = list->next) {
                struct server_data *data = list->data;
@@ -343,14 +359,14 @@ static void refresh_dns_entry(struct cache_entry *entry, char *name)
        }
 
        if (!entry->ipv4) {
-               DBG("Refresing A record for %s", name);
+               debug("Refreshing A record for %s", name);
                g_resolv_lookup_hostname(ipv4_resolve, name,
                                        dummy_resolve_func, NULL);
                age = 4;
        }
 
        if (!entry->ipv6) {
-               DBG("Refresing AAAA record for %s", name);
+               debug("Refreshing AAAA record for %s", name);
                g_resolv_lookup_hostname(ipv6_resolve, name,
                                        dummy_resolve_func, NULL);
                age = 4;
@@ -365,7 +381,7 @@ static int dns_name_length(unsigned char *buf)
 {
        if ((buf[0] & NS_CMPRSFLGS) == NS_CMPRSFLGS) /* compressed name */
                return 2;
-       return strlen((char *)buf);
+       return strlen((char *)buf) + 1;
 }
 
 static void update_cached_ttl(unsigned char *buf, int len, int new_ttl)
@@ -456,13 +472,13 @@ static void send_cached_response(int sk, unsigned char *buf, int len,
        hdr->nscount = 0;
        hdr->arcount = 0;
 
-       /* if this is a negative reply, we are authorative */
+       /* if this is a negative reply, we are authoritative */
        if (answers == 0)
                hdr->aa = 1;
        else
                update_cached_ttl((unsigned char *)hdr, adj_len, ttl);
 
-       DBG("sk %d id 0x%04x answers %d ptr %p length %d dns %d",
+       debug("sk %d id 0x%04x answers %d ptr %p length %d dns %d",
                sk, hdr->id, answers, ptr, len, dns_len);
 
        err = sendto(sk, ptr, len, MSG_NOSIGNAL, to, tolen);
@@ -474,37 +490,50 @@ static void send_cached_response(int sk, unsigned char *buf, int len,
 
        if (err != len || (dns_len != (len - 2) && protocol == IPPROTO_TCP) ||
                                (dns_len != len && protocol == IPPROTO_UDP))
-               DBG("Packet length mismatch, sent %d wanted %d dns %d",
+               debug("Packet length mismatch, sent %d wanted %d dns %d",
                        err, len, dns_len);
 }
 
-static void send_response(int sk, unsigned char *buf, int len,
+static void send_response(int sk, unsigned char *buf, size_t len,
                                const struct sockaddr *to, socklen_t tolen,
                                int protocol)
 {
        struct domain_hdr *hdr;
        int err, offset = protocol_offset(protocol);
 
-       DBG("sk %d", sk);
+       debug("sk %d", sk);
 
        if (offset < 0)
                return;
 
-       if (len < 12)
+       if (len < sizeof(*hdr) + offset)
                return;
 
        hdr = (void *) (buf + offset);
+#if !defined TIZEN_EXT
+       if (offset) {
+               buf[0] = 0;
+               buf[1] = sizeof(*hdr);
+       }
+#endif
 
-       DBG("id 0x%04x qr %d opcode %d", hdr->id, hdr->qr, hdr->opcode);
+       debug("id 0x%04x qr %d opcode %d", hdr->id, hdr->qr, hdr->opcode);
 
        hdr->qr = 1;
        hdr->rcode = ns_r_servfail;
 
+#if !defined TIZEN_EXT
+       hdr->qdcount = 0;
+#endif
        hdr->ancount = 0;
        hdr->nscount = 0;
        hdr->arcount = 0;
 
+#if defined TIZEN_EXT
        err = sendto(sk, buf, len, MSG_NOSIGNAL, to, tolen);
+#else
+       err = sendto(sk, buf, sizeof(*hdr) + offset, MSG_NOSIGNAL, to, tolen);
+#endif
        if (err < 0) {
                connman_error("Failed to send DNS response to %d: %s",
                                sk, strerror(errno));
@@ -541,54 +570,47 @@ static void destroy_request_data(struct request_data *req)
 static gboolean request_timeout(gpointer user_data)
 {
        struct request_data *req = user_data;
+       struct sockaddr *sa;
+       int sk;
 
        if (!req)
                return FALSE;
 
-       DBG("id 0x%04x", req->srcid);
+       debug("id 0x%04x", req->srcid);
 
        request_list = g_slist_remove(request_list, req);
-       req->numserv--;
 
-       if (req->resplen > 0 && req->resp) {
-               int sk, err;
+       if (req->protocol == IPPROTO_UDP) {
+               sk = get_req_udp_socket(req);
+               sa = &req->sa;
+       } else if (req->protocol == IPPROTO_TCP) {
+               sk = req->client_sk;
+               sa = NULL;
+       } else
+               goto out;
 
-               if (req->protocol == IPPROTO_UDP) {
-                       sk = get_req_udp_socket(req);
-                       if (sk < 0)
-                               return FALSE;
+       if (req->resplen > 0 && req->resp) {
+               /*
+                * Here we have received at least one reply (probably telling
+                * "not found" result), so send that back to client instead
+                * of more fatal server failed error.
+                */
+               if (sk >= 0)
+                       sendto(sk, req->resp, req->resplen, MSG_NOSIGNAL,
+                               sa, req->sa_len);
 
-                       err = sendto(sk, req->resp, req->resplen, MSG_NOSIGNAL,
-                               &req->sa, req->sa_len);
-               } else {
-                       sk = req->client_sk;
-                       err = send(sk, req->resp, req->resplen, MSG_NOSIGNAL);
-                       if (err < 0)
-                               close(sk);
-               }
-               if (err < 0)
-                       return FALSE;
-       } else if (req->request && req->numserv == 0) {
+       } else if (req->request) {
+               /*
+                * There was not reply from server at all.
+                */
                struct domain_hdr *hdr;
 
-               if (req->protocol == IPPROTO_TCP) {
-                       hdr = (void *) (req->request + 2);
-                       hdr->id = req->srcid;
-                       send_response(req->client_sk, req->request,
-                               req->request_len, NULL, 0, IPPROTO_TCP);
-
-               } else if (req->protocol == IPPROTO_UDP) {
-                       int sk;
+               hdr = (void *)(req->request + protocol_offset(req->protocol));
+               hdr->id = req->srcid;
 
-                       hdr = (void *) (req->request);
-                       hdr->id = req->srcid;
-
-                       sk = get_req_udp_socket(req);
-                       if (sk >= 0)
-                               send_response(sk, req->request,
-                                       req->request_len, &req->sa,
-                                       req->sa_len, IPPROTO_UDP);
-               }
+               if (sk >= 0)
+                       send_response(sk, req->request, req->request_len,
+                               sa, req->sa_len, req->protocol);
        }
 
        /*
@@ -596,11 +618,12 @@ static gboolean request_timeout(gpointer user_data)
         * if we get a request timeout from server.
         */
        if (req->protocol == IPPROTO_TCP) {
-               DBG("client %d removed", req->client_sk);
+               debug("client %d removed", req->client_sk);
                g_hash_table_remove(partial_tcp_req_table,
                                GINT_TO_POINTER(req->client_sk));
        }
 
+out:
        req->timeout = 0;
        destroy_request_data(req);
 
@@ -613,7 +636,7 @@ static int append_query(unsigned char *buf, unsigned int size,
        unsigned char *ptr = buf;
        int len;
 
-       DBG("query %s domain %s", query, domain);
+       debug("query %s domain %s", query, domain);
 
        while (query) {
                const char *tmp;
@@ -683,7 +706,7 @@ static void cache_enforce_validity(struct cache_entry *entry)
 
        if (!cache_check_is_valid(entry->ipv4, current_time)
                                                        && entry->ipv4) {
-               DBG("cache timeout \"%s\" type A", entry->key);
+               debug("cache timeout \"%s\" type A", entry->key);
                g_free(entry->ipv4->data);
                g_free(entry->ipv4);
                entry->ipv4 = NULL;
@@ -692,7 +715,7 @@ static void cache_enforce_validity(struct cache_entry *entry)
 
        if (!cache_check_is_valid(entry->ipv6, current_time)
                                                        && entry->ipv6) {
-               DBG("cache timeout \"%s\" type AAAA", entry->key);
+               debug("cache timeout \"%s\" type AAAA", entry->key);
                g_free(entry->ipv6->data);
                g_free(entry->ipv6);
                entry->ipv6 = NULL;
@@ -717,7 +740,7 @@ static uint16_t cache_check_validity(char *question, uint16_t type,
        switch (type) {
        case 1:         /* IPv4 */
                if (!cache_check_is_valid(entry->ipv4, current_time)) {
-                       DBG("cache %s \"%s\" type A", entry->ipv4 ?
+                       debug("cache %s \"%s\" type A", entry->ipv4 ?
                                        "timeout" : "entry missing", question);
 
                        if (want_refresh)
@@ -736,7 +759,7 @@ static uint16_t cache_check_validity(char *question, uint16_t type,
 
        case 28:        /* IPv6 */
                if (!cache_check_is_valid(entry->ipv6, current_time)) {
-                       DBG("cache %s \"%s\" type AAAA", entry->ipv6 ?
+                       debug("cache %s \"%s\" type AAAA", entry->ipv6 ?
                                        "timeout" : "entry missing", question);
 
                        if (want_refresh)
@@ -779,8 +802,10 @@ static void cache_element_destroy(gpointer value)
 
 static gboolean try_remove_cache(gpointer user_data)
 {
+       cache_timer = 0;
+
        if (__sync_fetch_and_sub(&cache_refcount, 1) == 1) {
-               DBG("No cache users, removing it.");
+               debug("No cache users, removing it.");
 
                g_hash_table_destroy(cache);
                cache = NULL;
@@ -850,7 +875,7 @@ static struct cache_entry *cache_check(gpointer request, int *qtype, int proto)
 static int get_name(int counter,
                unsigned char *pkt, unsigned char *start, unsigned char *max,
                unsigned char *output, int output_max, int *output_len,
-               unsigned char **end, char *name, int *name_len)
+               unsigned char **end, char *name, size_t max_name, int *name_len)
 {
        unsigned char *p;
 
@@ -871,7 +896,7 @@ static int get_name(int counter,
 
                        return get_name(counter + 1, pkt, pkt + offset, max,
                                        output, output_max, output_len, end,
-                                       name, name_len);
+                                       name, max_name, name_len);
                } else {
                        unsigned label_len = *p;
 
@@ -881,6 +906,9 @@ static int get_name(int counter,
                        if (*output_len > output_max)
                                return -ENOBUFS;
 
+                       if ((*name_len + 1 + label_len + 1) > max_name)
+                               return -ENOBUFS;
+
                        /*
                         * We need the original name in order to check
                         * if this answer is the correct one.
@@ -912,14 +940,14 @@ static int parse_rr(unsigned char *buf, unsigned char *start,
                        unsigned char *response, unsigned int *response_size,
                        uint16_t *type, uint16_t *class, int *ttl, int *rdlen,
                        unsigned char **end,
-                       char *name)
+                       char *name, size_t max_name)
 {
        struct domain_rr *rr;
        int err, offset;
        int name_len = 0, output_len = 0, max_rsp = *response_size;
 
        err = get_name(0, buf, start, max, response, max_rsp,
-               &output_len, end, name, &name_len);
+                       &output_len, end, name, max_name, &name_len);
        if (err < 0)
                return err;
 
@@ -994,7 +1022,7 @@ static int parse_response(unsigned char *buf, int buflen,
        if (buflen < 12)
                return -EINVAL;
 
-       DBG("qr %d qdcount %d", hdr->qr, qdcount);
+       debug("qr %d qdcount %d", hdr->qr, qdcount);
 
        /* We currently only cache responses where question count is 1 */
        if (hdr->qr != 1 || qdcount != 1)
@@ -1045,7 +1073,8 @@ static int parse_response(unsigned char *buf, int buflen,
                memset(rsp, 0, sizeof(rsp));
 
                ret = parse_rr(buf, ptr, buf + buflen, rsp, &rsp_len,
-                       type, class, ttl, &rdlen, &next, name);
+                       type, class, ttl, &rdlen, &next, name,
+                       sizeof(name) - 1);
                if (ret != 0) {
                        err = ret;
                        goto out;
@@ -1111,7 +1140,7 @@ static int parse_response(unsigned char *buf, int buflen,
                         */
                        ret = get_name(0, buf, next - rdlen, buf + buflen,
                                        rsp, rsp_len, &output_len, &end,
-                                       name, &name_len);
+                                       name, sizeof(name) - 1, &name_len);
                        if (ret != 0) {
                                /* just ignore the error at this point */
                                ptr = next;
@@ -1239,7 +1268,7 @@ static void cache_cleanup(void)
                count = g_hash_table_foreach_remove(cache, cache_check_entry,
                                                &data);
        }
-       DBG("removed %d in the first pass", count);
+       debug("removed %d in the first pass", count);
 
        /*
         * In the second pass, if the first pass turned up blank,
@@ -1303,7 +1332,7 @@ static gboolean cache_invalidate_entry(gpointer key, gpointer value,
  */
 static void cache_invalidate(void)
 {
-       DBG("Invalidating the DNS cache %p", cache);
+       debug("Invalidating the DNS cache %p", cache);
 
        if (!cache)
                return;
@@ -1335,7 +1364,7 @@ static void cache_refresh_entry(struct cache_entry *entry)
                        *c = '.';
                        c += jump + 1;
                }
-               DBG("Refreshing %s\n", dns_name);
+               debug("Refreshing %s\n", dns_name);
                /* then refresh the hostname */
                refresh_dns_entry(entry, &dns_name[1]);
        }
@@ -1371,7 +1400,7 @@ static int reply_query_type(unsigned char *msg, int len)
                return 0;
 
        /* now the query, which is a name and 2 16 bit words */
-       l = dns_name_length(c) + 1;
+       l = dns_name_length(c);
        c += l;
        type = c[0] << 8 | c[1];
 
@@ -1412,7 +1441,7 @@ static int cache_update(struct server_data *srv, unsigned char *msg,
        if (offset < 0)
                return 0;
 
-       DBG("offset %d hdr %p msg %p rcode %d", offset, hdr, msg, hdr->rcode);
+       debug("offset %d hdr %p msg %p rcode %d", offset, hdr, msg, hdr->rcode);
 
        /* Continue only if response code is 0 (=ok) */
        if (hdr->rcode != ns_r_noerror)
@@ -1592,7 +1621,7 @@ static int cache_update(struct server_data *srv, unsigned char *msg,
                cache_size++;
        }
 
-       DBG("cache %d %squestion \"%s\" type %d ttl %d size %zd packet %u "
+       debug("cache %d %squestion \"%s\" type %d ttl %d size %zd packet %u "
                                                                "dns len %u",
                cache_size, new_entry ? "new " : "old ",
                question, type, ttl,
@@ -1618,7 +1647,7 @@ static int ns_resolv(struct server_data *server, struct request_data *req,
                int ttl_left = 0;
                struct cache_data *data;
 
-               DBG("cache hit %s type %s", lookup, type == 1 ? "A" : "AAAA");
+               debug("cache hit %s type %s", lookup, type == 1 ? "A" : "AAAA");
                if (type == 1)
                        data = entry->ipv4;
                else
@@ -1680,7 +1709,7 @@ static int ns_resolv(struct server_data *server, struct request_data *req,
        err = sendto(sk, request, req->request_len, MSG_NOSIGNAL,
                        server->server_addr, server->server_addr_len);
        if (err < 0) {
-               DBG("Cannot send message to server %s sock %d "
+               debug("Cannot send message to server %s sock %d "
                        "protocol %d (%s/%d)",
                        server->server, sk, server->protocol,
                        strerror(errno), errno);
@@ -1740,7 +1769,7 @@ static int ns_resolv(struct server_data *server, struct request_data *req,
                        alt[1] = req_len & 0xff;
                }
 
-               DBG("req %p dstid 0x%04x altid 0x%04x", req, req->dstid,
+               debug("req %p dstid 0x%04x altid 0x%04x", req, req->dstid,
                                req->altid);
 
                err = send(sk, alt, req->request_len + domlen, MSG_NOSIGNAL);
@@ -1762,7 +1791,7 @@ static char *convert_label(char *start, char *end, char *ptr, char *uptr,
        pos = dn_expand((u_char *)start, (u_char *)end, (u_char *)ptr,
                        name, NS_MAXLABEL);
        if (pos < 0) {
-               DBG("uncompress error [%d/%s]", errno, strerror(errno));
+               debug("uncompress error [%d/%s]", errno, strerror(errno));
                goto out;
        }
 
@@ -1772,7 +1801,7 @@ static char *convert_label(char *start, char *end, char *ptr, char *uptr,
         */
        comp_pos = dn_comp(name, (u_char *)uptr, remaining_len, NULL, NULL);
        if (comp_pos < 0) {
-               DBG("compress error [%d/%s]", errno, strerror(errno));
+               debug("compress error [%d/%s]", errno, strerror(errno));
                goto out;
        }
 
@@ -1791,7 +1820,7 @@ static char *uncompress(int16_t field_count, char *start, char *end,
 {
        char *uptr = *uncompressed_ptr; /* position in result buffer */
 
-       DBG("count %d ptr %p end %p uptr %p", field_count, ptr, end, uptr);
+       debug("count %d ptr %p end %p uptr %p", field_count, ptr, end, uptr);
 
        while (field_count-- > 0 && ptr < end) {
                int dlen;               /* data field length */
@@ -1813,7 +1842,7 @@ static char *uncompress(int16_t field_count, char *start, char *end,
                ulen = strlen(name);
                strncpy(uptr, name, uncomp_len - (uptr - uncompressed));
 
-               DBG("pos %d ulen %d left %d name %s", pos, ulen,
+               debug("pos %d ulen %d left %d name %s", pos, ulen,
                        (int)(uncomp_len - (uptr - uncompressed)), uptr);
 
                uptr += ulen;
@@ -1857,7 +1886,7 @@ static char *uncompress(int16_t field_count, char *start, char *end,
                        dlen = uptr[-2] << 8 | uptr[-1];
 
                        if (ptr + dlen > end) {
-                               DBG("data len %d too long", dlen);
+                               debug("data len %d too long", dlen);
                                goto out;
                        }
 
@@ -1968,13 +1997,13 @@ static int forward_dns_reply(unsigned char *reply, int reply_len, int protocol,
        hdr = (void *)(reply + offset);
        dns_id = reply[offset] | reply[offset + 1] << 8;
 
-       DBG("Received %d bytes (id 0x%04x)", reply_len, dns_id);
+       debug("Received %d bytes (id 0x%04x)", reply_len, dns_id);
 
        req = find_request(dns_id);
        if (!req)
                return -EINVAL;
 
-       DBG("req %p dstid 0x%04x altid 0x%04x rcode %d",
+       debug("req %p dstid 0x%04x altid 0x%04x rcode %d",
                        req, req->dstid, req->altid, hdr->rcode);
 
        reply[offset] = req->srcid & 0xff;
@@ -2030,7 +2059,7 @@ static int forward_dns_reply(unsigned char *reply, int reply_len, int protocol,
                                                        ptr[dns_type_pos + 3];
                        if (dns_type != ns_t_a && dns_type != ns_t_aaaa &&
                                        dns_class != ns_c_in) {
-                               DBG("Pass msg dns type %d class %d",
+                               debug("Pass msg dns type %d class %d",
                                        dns_type, dns_class);
                                goto pass;
                        }
@@ -2089,21 +2118,21 @@ static int forward_dns_reply(unsigned char *reply, int reply_len, int protocol,
                                                (char *)reply + offset, eom,
                                                ptr, uncompressed, NS_MAXDNAME,
                                                &uptr);
-                               if (ptr == NULL)
+                               if (!ptr)
                                        goto out;
 
                                ptr = uncompress(ntohs(hdr->nscount),
                                                (char *)reply + offset, eom,
                                                ptr, uncompressed, NS_MAXDNAME,
                                                &uptr);
-                               if (ptr == NULL)
+                               if (!ptr)
                                        goto out;
 
                                ptr = uncompress(ntohs(hdr->arcount),
                                                (char *)reply + offset, eom,
                                                ptr, uncompressed, NS_MAXDNAME,
                                                &uptr);
-                               if (ptr == NULL)
+                               if (!ptr)
                                        goto out;
 
                                /*
@@ -2119,7 +2148,7 @@ static int forward_dns_reply(unsigned char *reply, int reply_len, int protocol,
                                new_len = strip_domains(uncompressed, answers,
                                                        uptr - answers);
                                if (new_len < 0) {
-                                       DBG("Corrupted packet");
+                                       debug("Corrupted packet");
                                        return -EINVAL;
                                }
 
@@ -2148,8 +2177,15 @@ static int forward_dns_reply(unsigned char *reply, int reply_len, int protocol,
                req->resplen = 0;
 
                req->resp = g_try_malloc(reply_len);
+#if defined TIZEN_EXT
+               if (!req->resp) {
+                       g_free(new_reply);
+                       return -ENOMEM;
+               }
+#else
                if (!req->resp)
                        return -ENOMEM;
+#endif
 
                memcpy(req->resp, reply, reply_len);
                req->resplen = reply_len;
@@ -2184,10 +2220,10 @@ out:
        }
 
        if (err < 0)
-               DBG("Cannot send msg, sk %d proto %d errno %d/%s", sk,
+               debug("Cannot send msg, sk %d proto %d errno %d/%s", sk,
                        protocol, errno, strerror(errno));
        else
-               DBG("proto %d sent %d bytes to %d", protocol, err, sk);
+               debug("proto %d sent %d bytes to %d", protocol, err, sk);
 
        destroy_request_data(req);
 
@@ -2196,7 +2232,7 @@ out:
 
 static void server_destroy_socket(struct server_data *data)
 {
-       DBG("index %d server %s proto %d", data->index,
+       debug("index %d server %s proto %d", data->index,
                                        data->server, data->protocol);
 
        if (data->watch > 0) {
@@ -2221,7 +2257,7 @@ static void server_destroy_socket(struct server_data *data)
 
 static void destroy_server(struct server_data *server)
 {
-       DBG("index %d server %s sock %d", server->index, server->server,
+       debug("index %d server %s sock %d", server->index, server->server,
                        server->channel ?
                        g_io_channel_unix_get_fd(server->channel): -1);
 
@@ -2229,7 +2265,7 @@ static void destroy_server(struct server_data *server)
        server_destroy_socket(server);
 
        if (server->protocol == IPPROTO_UDP && server->enabled)
-               DBG("Removing DNS server %s", server->server);
+               debug("Removing DNS server %s", server->server);
 
        g_free(server->server);
        g_list_free_full(server->domains, g_free);
@@ -2244,8 +2280,8 @@ static void destroy_server(struct server_data *server)
         * without any good reason. The small delay allows the new RDNSS to
         * create a new DNS server instance and the refcount does not go to 0.
         */
-       if (cache)
-               g_timeout_add_seconds(3, try_remove_cache, NULL);
+       if (cache && !cache_timer)
+               cache_timer = g_timeout_add_seconds(3, try_remove_cache, NULL);
 
        g_free(server);
 }
@@ -2254,7 +2290,7 @@ static gboolean udp_server_event(GIOChannel *channel, GIOCondition condition,
                                                        gpointer user_data)
 {
        unsigned char buf[4096];
-       int sk, err, len;
+       int sk, len;
        struct server_data *data = user_data;
 
        if (condition & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) {
@@ -2266,12 +2302,9 @@ static gboolean udp_server_event(GIOChannel *channel, GIOCondition condition,
        sk = g_io_channel_unix_get_fd(channel);
 
        len = recv(sk, buf, sizeof(buf), 0);
-       if (len < 12)
-               return TRUE;
 
-       err = forward_dns_reply(buf, len, IPPROTO_UDP, data);
-       if (err < 0)
-               return TRUE;
+       if (len >= 12)
+               forward_dns_reply(buf, len, IPPROTO_UDP, data);
 
 #if defined TIZEN_EXT
        GSList *list;
@@ -2302,7 +2335,7 @@ static gboolean tcp_server_event(GIOChannel *channel, GIOCondition condition,
        if (condition & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) {
                GSList *list;
 hangup:
-               DBG("TCP server channel closed, sk %d", sk);
+               debug("TCP server channel closed, sk %d", sk);
 
                /*
                 * Discard any partial response which is buffered; better
@@ -2311,9 +2344,11 @@ hangup:
                g_free(server->incoming_reply);
                server->incoming_reply = NULL;
 
-               for (list = request_list; list; list = list->next) {
+               list = request_list;
+               while (list) {
                        struct request_data *req = list->data;
                        struct domain_hdr *hdr;
+                       list = list->next;
 
                        if (req->protocol == IPPROTO_UDP)
                                continue;
@@ -2355,7 +2390,7 @@ hangup:
                                                domains = domains->next) {
                                char *dom = domains->data;
 
-                               DBG("Adding domain %s to %s",
+                               debug("Adding domain %s to %s",
                                                dom, server->server);
 
                                server->domains = g_list_append(server->domains,
@@ -2380,7 +2415,7 @@ hangup:
                                continue;
                        }
 
-                       DBG("Sending req %s over TCP", (char *)req->name);
+                       debug("Sending req %s over TCP", (char *)req->name);
 
                        status = ns_resolv(server, req,
                                                req->request, req->name);
@@ -2439,7 +2474,7 @@ hangup:
                        reply_len = reply_len_buf[1] | reply_len_buf[0] << 8;
                        reply_len += 2;
 
-                       DBG("TCP reply %d bytes from %d", reply_len, sk);
+                       debug("TCP reply %d bytes from %d", reply_len, sk);
 
                        reply = g_try_malloc(sizeof(*reply) + reply_len + 2);
                        if (!reply)
@@ -2486,7 +2521,7 @@ static gboolean tcp_idle_timeout(gpointer user_data)
 {
        struct server_data *server = user_data;
 
-       DBG("");
+       debug("");
 
        if (!server)
                return FALSE;
@@ -2501,7 +2536,7 @@ static int server_create_socket(struct server_data *data)
        int sk, err;
        char *interface;
 
-       DBG("index %d server %s proto %d", data->index,
+       debug("index %d server %s proto %d", data->index,
                                        data->server, data->protocol);
 
        sk = socket(data->server_addr->sa_family,
@@ -2515,7 +2550,7 @@ static int server_create_socket(struct server_data *data)
                return -err;
        }
 
-       DBG("sk %d", sk);
+       debug("sk %d", sk);
 
        interface = connman_inet_ifname(data->index);
        if (interface) {
@@ -2575,18 +2610,44 @@ static int server_create_socket(struct server_data *data)
        return 0;
 }
 
+static void enable_fallback(bool enable)
+{
+       GSList *list;
+
+       for (list = server_list; list; list = list->next) {
+               struct server_data *data = list->data;
+
+               if (data->index != -1)
+                       continue;
+
+               if (enable)
+                       DBG("Enabling fallback DNS server %s", data->server);
+               else
+                       DBG("Disabling fallback DNS server %s", data->server);
+
+               data->enabled = enable;
+       }
+}
+
 #if defined TIZEN_EXT
 
 static void destroy_server_sec(struct server_data *server)
 {
        GList *list;
+       int fd;
 
-       DBG("index %d server %s sock %d", server->index, server->server,
-                       server->channel != NULL ?
-                       g_io_channel_unix_get_fd(server->channel): -1);
+       if (server->channel)
+               fd = g_io_channel_unix_get_fd(server->channel);
+       else
+               fd = -1;
+
+       DBG("index %d server %s sock %d", server->index, server->server, fd);
 
        server_list_sec = g_slist_remove(server_list_sec, server);
-       close(g_io_channel_unix_get_fd(server->channel));
+
+       if (fd > 0)
+               close(fd);
+
        server_destroy_socket(server);
 
        if (server->protocol == IPPROTO_UDP && server->enabled)
@@ -2687,6 +2748,7 @@ static struct server_data *create_server_sec(int index,
        if (ret) {
                connman_error("Failed to parse server %s address: %s\n",
                                data->server, gai_strerror(ret));
+               freeaddrinfo(rp);
                destroy_server_sec(data);
                return NULL;
        }
@@ -2824,6 +2886,8 @@ static struct server_data *create_server(int index,
                                                                data->index)) {
                        data->enabled = true;
                        DBG("Adding DNS server %s", data->server);
+
+                       enable_fallback(false);
                }
 
                server_list = g_slist_append(server_list, data);
@@ -2845,7 +2909,7 @@ static bool resolv(struct request_data *req,
                        continue;
                }
 
-               DBG("server %s enabled %d", data->server, data->enabled);
+               debug("server %s enabled %d", data->server, data->enabled);
 
                if (!data->enabled)
                        continue;
@@ -2864,7 +2928,7 @@ static bool resolv(struct request_data *req,
        return false;
 }
 
-static void append_domain(int index, const char *domain)
+static void update_domain(int index, const char *domain, bool append)
 {
        GSList *list;
 
@@ -2895,13 +2959,55 @@ static void append_domain(int index, const char *domain)
                        }
                }
 
-               if (!dom_found) {
+               if (!dom_found && append) {
                        data->domains =
                                g_list_append(data->domains, g_strdup(domain));
+               } else if (dom_found && !append) {
+                       data->domains =
+                               g_list_remove(data->domains, dom);
+                       g_free(dom);
                }
        }
 }
 
+static void append_domain(int index, const char *domain)
+{
+       update_domain(index, domain, true);
+}
+
+static void remove_domain(int index, const char *domain)
+{
+       update_domain(index, domain, false);
+}
+
+static void flush_requests(struct server_data *server)
+{
+       GSList *list;
+
+       list = request_list;
+       while (list) {
+               struct request_data *req = list->data;
+
+               list = list->next;
+
+               if (ns_resolv(server, req, req->request, req->name)) {
+                       /*
+                        * A cached result was sent,
+                        * so the request can be released
+                        */
+                       request_list =
+                               g_slist_remove(request_list, req);
+                       destroy_request_data(req);
+                       continue;
+               }
+
+               if (req->timeout > 0)
+                       g_source_remove(req->timeout);
+
+               req->timeout = g_timeout_add_seconds(5, request_timeout, req);
+       }
+}
+
 int __connman_dnsproxy_append(int index, const char *domain,
                                                        const char *server)
 {
@@ -2934,6 +3040,8 @@ int __connman_dnsproxy_append(int index, const char *domain,
        if (!data)
                return -EIO;
 
+       flush_requests(data);
+
        return 0;
 }
 
@@ -2941,12 +3049,22 @@ static void remove_server(int index, const char *domain,
                        const char *server, int protocol)
 {
        struct server_data *data;
+       GSList *list;
 
        data = find_server(index, server, protocol);
        if (!data)
                return;
 
        destroy_server(data);
+
+       for (list = server_list; list; list = list->next) {
+               struct server_data *data = list->data;
+
+               if (data->index != -1 && data->enabled == true)
+                       return;
+       }
+
+       enable_fallback(true);
 }
 
 int __connman_dnsproxy_remove(int index, const char *domain,
@@ -2954,9 +3072,15 @@ int __connman_dnsproxy_remove(int index, const char *domain,
 {
        DBG("index %d server %s", index, server);
 
-       if (!server)
+       if (!server && !domain)
                return -EINVAL;
 
+       if (!server) {
+               remove_domain(index, domain);
+
+               return 0;
+       }
+
        if (g_str_equal(server, "127.0.0.1"))
                return -ENODEV;
 
@@ -2973,33 +3097,6 @@ int __connman_dnsproxy_remove(int index, const char *domain,
        return 0;
 }
 
-void __connman_dnsproxy_flush(void)
-{
-       GSList *list;
-
-       list = request_list;
-       while (list) {
-               struct request_data *req = list->data;
-
-               list = list->next;
-
-               if (resolv(req, req->request, req->name)) {
-                       /*
-                        * A cached result was sent,
-                        * so the request can be released
-                        */
-                       request_list =
-                               g_slist_remove(request_list, req);
-                       destroy_request_data(req);
-                       continue;
-               }
-
-               if (req->timeout > 0)
-                       g_source_remove(req->timeout);
-               req->timeout = g_timeout_add_seconds(5, request_timeout, req);
-       }
-}
-
 static void dnsproxy_offline_mode(bool enabled)
 {
        GSList *list;
@@ -3024,6 +3121,7 @@ static void dnsproxy_offline_mode(bool enabled)
 
 static void dnsproxy_default_changed(struct connman_service *service)
 {
+       bool server_enabled = false;
        GSList *list;
        int index;
 
@@ -3048,43 +3146,90 @@ static void dnsproxy_default_changed(struct connman_service *service)
                if (data->index == index) {
                        DBG("Enabling DNS server %s", data->server);
                        data->enabled = true;
+                       server_enabled = true;
                } else {
                        DBG("Disabling DNS server %s", data->server);
                        data->enabled = false;
                }
        }
 
+       if (!server_enabled)
+               enable_fallback(true);
+
        cache_refresh();
 }
 
-static struct connman_notifier dnsproxy_notifier = {
+static void dnsproxy_service_state_changed(struct connman_service *service,
+                       enum connman_service_state state)
+{
+       GSList *list;
+       int index;
+
+       switch (state) {
+       case CONNMAN_SERVICE_STATE_DISCONNECT:
+       case CONNMAN_SERVICE_STATE_IDLE:
+               break;
+       case CONNMAN_SERVICE_STATE_ASSOCIATION:
+       case CONNMAN_SERVICE_STATE_CONFIGURATION:
+       case CONNMAN_SERVICE_STATE_FAILURE:
+       case CONNMAN_SERVICE_STATE_ONLINE:
+       case CONNMAN_SERVICE_STATE_READY:
+       case CONNMAN_SERVICE_STATE_UNKNOWN:
+               return;
+       }
+
+       index = __connman_service_get_index(service);
+       list = server_list;
+
+       while (list) {
+               struct server_data *data = list->data;
+
+               /* Get next before the list is changed by destroy_server() */
+               list = list->next;
+
+               if (data->index == index) {
+                       DBG("removing server data of index %d", index);
+                       destroy_server(data);
+               }
+       }
+}
+
+static const struct connman_notifier dnsproxy_notifier = {
        .name                   = "dnsproxy",
        .default_changed        = dnsproxy_default_changed,
        .offline_mode           = dnsproxy_offline_mode,
+       .service_state_changed  = dnsproxy_service_state_changed,
 };
 
-static unsigned char opt_edns0_type[2] = { 0x00, 0x29 };
+static const unsigned char opt_edns0_type[2] = { 0x00, 0x29 };
 
-static int parse_request(unsigned char *buf, int len,
+static int parse_request(unsigned char *buf, size_t len,
                                        char *name, unsigned int size)
 {
        struct domain_hdr *hdr = (void *) buf;
        uint16_t qdcount = ntohs(hdr->qdcount);
+       uint16_t ancount = ntohs(hdr->ancount);
+       uint16_t nscount = ntohs(hdr->nscount);
        uint16_t arcount = ntohs(hdr->arcount);
        unsigned char *ptr;
-       char *last_label = NULL;
        unsigned int remain, used = 0;
 
-       if (len < 12)
+       if (len < sizeof(*hdr) + sizeof(struct qtype_qclass) ||
+                       hdr->qr || qdcount != 1 || ancount || nscount) {
+               DBG("Dropped DNS request qr %d with len %zd qdcount %d "
+                       "ancount %d nscount %d", hdr->qr, len, qdcount, ancount,
+                       nscount);
+
+               return -EINVAL;
+       }
+
+       if (!name || !size)
                return -EINVAL;
 
-       DBG("id 0x%04x qr %d opcode %d qdcount %d arcount %d",
+       debug("id 0x%04x qr %d opcode %d qdcount %d arcount %d",
                                        hdr->id, hdr->qr, hdr->opcode,
                                                        qdcount, arcount);
 
-       if (hdr->qr != 0 || qdcount != 1)
-               return -EINVAL;
-
        name[0] = '\0';
 
        ptr = buf + sizeof(struct domain_hdr);
@@ -3094,7 +3239,23 @@ static int parse_request(unsigned char *buf, int len,
                uint8_t label_len = *ptr;
 
                if (label_len == 0x00) {
-                       last_label = (char *) (ptr + 1);
+                       uint8_t class;
+                       struct qtype_qclass *q =
+                               (struct qtype_qclass *)(ptr + 1);
+
+                       if (remain < sizeof(*q)) {
+                               DBG("Dropped malformed DNS query");
+                               return -EINVAL;
+                       }
+
+                       class = ntohs(q->qclass);
+                       if (class != 1 && class != 255) {
+                               DBG("Dropped non-IN DNS class %d", class);
+                               return -EINVAL;
+                       }
+
+                       ptr += sizeof(*q) + 1;
+                       remain -= (sizeof(*q) + 1);
                        break;
                }
 
@@ -3110,44 +3271,16 @@ static int parse_request(unsigned char *buf, int len,
                remain -= label_len + 1;
        }
 
-#if defined TIZEN_EXT
-       /* parse DNS query type either A or AAAA
-        * enforce to drop AAAA temporarily (IPv6 not supported)
-        */
-       if (last_label != NULL) {
-               uint16_t *type_p = (uint16_t *)last_label;
-               uint16_t type = ntohs(*type_p);
-
-               if (type == 0x1c) {
-                       DBG("query %s is type AAAA(0x%x)", name, type);
-                       return -ENOENT;
-               }
-       }
-#endif
-
-       if (last_label && arcount && remain >= 9 && last_label[4] == 0 &&
-                               !memcmp(last_label + 5, opt_edns0_type, 2)) {
-               uint16_t edns0_bufsize;
-
-               edns0_bufsize = last_label[7] << 8 | last_label[8];
+       if (arcount && remain >= sizeof(struct domain_rr) + 1 && !ptr[0] &&
+               ptr[1] == opt_edns0_type[0] && ptr[2] == opt_edns0_type[1]) {
+               struct domain_rr *edns0 = (struct domain_rr *)(ptr + 1);
 
-               DBG("EDNS0 buffer size %u", edns0_bufsize);
-
-               /* This is an evil hack until full TCP support has been
-                * implemented.
-                *
-                * Somtimes the EDNS0 request gets send with a too-small
-                * buffer size. Since glibc doesn't seem to crash when it
-                * gets a response biffer then it requested, just bump
-                * the buffer size up to 4KiB.
-                */
-               if (edns0_bufsize < 0x1000) {
-                       last_label[7] = 0x10;
-                       last_label[8] = 0x00;
-               }
+               DBG("EDNS0 buffer size %u", ntohs(edns0->class));
+       } else if (!arcount && remain) {
+               DBG("DNS request with %d garbage bytes", remain);
        }
 
-       DBG("query %s", name);
+       debug("query %s", name);
 
        return 0;
 }
@@ -3158,7 +3291,7 @@ static void client_reset(struct tcp_partial_client_data *client)
                return;
 
        if (client->channel) {
-               DBG("client %d closing",
+               debug("client %d closing",
                        g_io_channel_unix_get_fd(client->channel));
 
                g_io_channel_unref(client->channel);
@@ -3202,14 +3335,14 @@ static bool read_tcp_data(struct tcp_partial_client_data *client,
        client_sk = g_io_channel_unix_get_fd(client->channel);
 
        if (read_len == 0) {
-               DBG("client %d closed, pending %d bytes",
+               debug("client %d closed, pending %d bytes",
                        client_sk, client->buf_end);
                g_hash_table_remove(partial_tcp_req_table,
                                        GINT_TO_POINTER(client_sk));
                return false;
        }
 
-       DBG("client %d received %d bytes", client_sk, read_len);
+       debug("client %d received %d bytes", client_sk, read_len);
 
        client->buf_end += read_len;
 
@@ -3218,24 +3351,24 @@ static bool read_tcp_data(struct tcp_partial_client_data *client,
 
        msg_len = get_msg_len(client->buf);
        if (msg_len > TCP_MAX_BUF_LEN) {
-               DBG("client %d sent too much data %d", client_sk, msg_len);
+               debug("client %d sent too much data %d", client_sk, msg_len);
                g_hash_table_remove(partial_tcp_req_table,
                                        GINT_TO_POINTER(client_sk));
                return false;
        }
 
 read_another:
-       DBG("client %d msg len %d end %d past end %d", client_sk, msg_len,
+       debug("client %d msg len %d end %d past end %d", client_sk, msg_len,
                client->buf_end, client->buf_end - (msg_len + 2));
 
        if (client->buf_end < (msg_len + 2)) {
-               DBG("client %d still missing %d bytes",
+               debug("client %d still missing %d bytes",
                        client_sk,
                        msg_len + 2 - client->buf_end);
                return true;
        }
 
-       DBG("client %d all data %d received", client_sk, msg_len);
+       debug("client %d all data %d received", client_sk, msg_len);
 
        err = parse_request(client->buf + 2, msg_len,
                        query, sizeof(query));
@@ -3276,7 +3409,7 @@ read_another:
                int ttl_left = 0;
                struct cache_data *data;
 
-               DBG("cache hit %s type %s", query, qtype == 1 ? "A" : "AAAA");
+               debug("cache hit %s type %s", query, qtype == 1 ? "A" : "AAAA");
                if (qtype == 1)
                        data = entry->ipv4;
                else
@@ -3293,7 +3426,7 @@ read_another:
                        g_free(req);
                        goto out;
                } else
-                       DBG("data missing, ignoring cache for this query");
+                       debug("data missing, ignoring cache for this query");
        }
 
        for (list = server_list; list; list = list->next) {
@@ -3348,7 +3481,7 @@ read_another:
 
 out:
        if (client->buf_end > (msg_len + 2)) {
-               DBG("client %d buf %p -> %p end %d len %d new %d",
+               debug("client %d buf %p -> %p end %d len %d new %d",
                        client_sk,
                        client->buf + msg_len + 2,
                        client->buf, client->buf_end,
@@ -3364,12 +3497,12 @@ out:
                 */
                msg_len = get_msg_len(client->buf);
                if ((msg_len + 2) == client->buf_end) {
-                       DBG("client %d reading another %d bytes", client_sk,
+                       debug("client %d reading another %d bytes", client_sk,
                                                                msg_len + 2);
                        goto read_another;
                }
        } else {
-               DBG("client %d clearing reading buffer", client_sk);
+               debug("client %d clearing reading buffer", client_sk);
 
                client->buf_end = 0;
                memset(client->buf, 0, TCP_MAX_BUF_LEN);
@@ -3431,7 +3564,7 @@ static gboolean tcp_client_event(GIOChannel *channel, GIOCondition condition,
                if (errno == EAGAIN || errno == EWOULDBLOCK)
                        return TRUE;
 
-               DBG("client %d cannot read errno %d/%s", client_sk, -errno,
+               debug("client %d cannot read errno %d/%s", client_sk, -errno,
                        strerror(errno));
                g_hash_table_remove(partial_tcp_req_table,
                                        GINT_TO_POINTER(client_sk));
@@ -3448,7 +3581,7 @@ static gboolean client_timeout(gpointer user_data)
 
        sock = g_io_channel_unix_get_fd(client->channel);
 
-       DBG("client %d timeout pending %d bytes", sock, client->buf_end);
+       debug("client %d timeout pending %d bytes", sock, client->buf_end);
 
        g_hash_table_remove(partial_tcp_req_table, GINT_TO_POINTER(sock));
 
@@ -3488,7 +3621,7 @@ static bool tcp_listener_event(GIOChannel *channel, GIOCondition condition,
        struct timeval tv;
        fd_set readfds;
 
-       DBG("condition 0x%02x channel %p ifdata %p family %d",
+       debug("condition 0x%02x channel %p ifdata %p family %d",
                condition, channel, ifdata, family);
 
        if (condition & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) {
@@ -3524,9 +3657,9 @@ static bool tcp_listener_event(GIOChannel *channel, GIOCondition condition,
        select(sk + 1, &readfds, NULL, NULL, &tv);
        if (FD_ISSET(sk, &readfds)) {
                client_sk = accept(sk, client_addr, client_addr_len);
-               DBG("client %d accepted", client_sk);
+               debug("client %d accepted", client_sk);
        } else {
-               DBG("No data to read from master %d, waiting.", sk);
+               debug("No data to read from master %d, waiting.", sk);
                return true;
        }
 
@@ -3560,9 +3693,9 @@ static bool tcp_listener_event(GIOChannel *channel, GIOCondition condition,
 
                client->ifdata = ifdata;
 
-               DBG("client %d created %p", client_sk, client);
+               debug("client %d created %p", client_sk, client);
        } else {
-               DBG("client %d already exists %p", client_sk, client);
+               debug("client %d already exists %p", client_sk, client);
        }
 
        if (!client->buf) {
@@ -3586,11 +3719,11 @@ static bool tcp_listener_event(GIOChannel *channel, GIOCondition condition,
        len = recv(client_sk, client->buf, TCP_MAX_BUF_LEN, 0);
        if (len < 0) {
                if (errno == EAGAIN || errno == EWOULDBLOCK) {
-                       DBG("client %d no data to read, waiting", client_sk);
+                       debug("client %d no data to read, waiting", client_sk);
                        return true;
                }
 
-               DBG("client %d cannot read errno %d/%s", client_sk, -errno,
+               debug("client %d cannot read errno %d/%s", client_sk, -errno,
                        strerror(errno));
                g_hash_table_remove(partial_tcp_req_table,
                                        GINT_TO_POINTER(client_sk));
@@ -3598,14 +3731,14 @@ static bool tcp_listener_event(GIOChannel *channel, GIOCondition condition,
        }
 
        if (len < 2) {
-               DBG("client %d not enough data to read, waiting", client_sk);
+               debug("client %d not enough data to read, waiting", client_sk);
                client->buf_end += len;
                return true;
        }
 
        msg_len = get_msg_len(client->buf);
        if (msg_len > TCP_MAX_BUF_LEN) {
-               DBG("client %d invalid message length %u ignoring packet",
+               debug("client %d invalid message length %u ignoring packet",
                        client_sk, msg_len);
                g_hash_table_remove(partial_tcp_req_table,
                                        GINT_TO_POINTER(client_sk));
@@ -3621,7 +3754,7 @@ static bool tcp_listener_event(GIOChannel *channel, GIOCondition condition,
 #else
        if (msg_len != (unsigned int)(len - 2)) {
 #endif
-               DBG("client %d sent %d bytes but expecting %u pending %d",
+               debug("client %d sent %d bytes but expecting %u pending %d",
                        client_sk, len, msg_len + 2, msg_len + 2 - len);
 
                client->buf_end += len;
@@ -3650,37 +3783,35 @@ static gboolean tcp6_listener_event(GIOChannel *channel, GIOCondition condition,
 }
 
 #if defined TIZEN_EXT
-/* Temporarily disable AAAA type to enhance performance (IPv6 not supported) */
-static void __send_response_not_implemented(int sk, unsigned char *buf, int len,
-                               const struct sockaddr *to, socklen_t tolen,
-                               int protocol)
+struct request_data * create_request(int sk, unsigned char *buf, size_t len,
+                                const struct sockaddr *to, socklen_t tolen,
+                                int protocol)
 {
-       struct domain_hdr *hdr;
-       int err, offset = protocol_offset(protocol);
-
-       DBG("sk %d", sk);
-
-       if (offset < 0)
-               return;
-
-       if (len < 12)
-               return;
-
-       hdr = (void *) (buf + offset);
+       struct request_data *req;
+       req = g_try_new0(struct request_data, 1);
+       if (!req)
+               return NULL;
+       memcpy(&req->sa, to, tolen);
+       req->sa_len = tolen;
+       req->client_sk = sk;
+       req->protocol = protocol;
+       req->request_len = len;
+       req->request = g_malloc(len);
+       memcpy(req->request, buf, len);
+       return req;
 
-       DBG("id 0x%04x qr %d opcode %d", hdr->id, hdr->qr, hdr->opcode);
+}
+static gboolean send_response_timeout (gpointer user_data)
+{
+       struct request_data *req = user_data;
 
-       hdr->qr = 1;
-       hdr->rcode = 4;
+       send_response(req->client_sk, req->request,(size_t) req->request_len, (const struct sockaddr *)&req->sa,
+                             (socklen_t)req->sa_len, req->protocol);
+       g_free(req->request);
+       g_free(req);
 
-       hdr->ancount = 0;
-       hdr->nscount = 0;
-       hdr->arcount = 0;
+       return FALSE;
 
-       err = sendto(sk, buf, len, MSG_NOSIGNAL, to, tolen);
-       if (err < 0)
-               connman_error("Failed to send DNS response to %d: %s",
-                               sk, strerror(errno));
 }
 #endif
 
@@ -3726,22 +3857,26 @@ static bool udp_listener_event(GIOChannel *channel, GIOCondition condition,
        if (len < 2)
                return true;
 
-       DBG("Received %d bytes (id 0x%04x)", len, buf[0] | buf[1] << 8);
+       debug("Received %d bytes (id 0x%04x)", len, buf[0] | buf[1] << 8);
 
        err = parse_request(buf, len, query, sizeof(query));
        if (err < 0 || (g_slist_length(server_list) == 0)) {
 #if defined TIZEN_EXT
-               if (err == -ENOENT) {
-                       /* Temporarily disable AAAA type to enhance performance
-                        * (IPv6 not supported)
-                        */
-                       __send_response_not_implemented(sk, buf, len, client_addr,
-                                                                       *client_addr_len, IPPROTO_UDP);
-                       return TRUE;
-               }
-#endif
+               /** TEMP Fix
+               * Reason: In tizen6.0 same code working fine because it seems some delay in 6.0 platform
+               * where as in tizen6.5 this loop is continuously executing due to this unable to receive
+               * the response from telephony deamon and wpa_supplicant. To stop continuously execution
+               * of this code added 10ms delay.
+               */
+               req = create_request(sk, buf, len, client_addr,
+                               *client_addr_len, IPPROTO_UDP);
+               if(!req)
+                       return true;;
+               g_timeout_add(10, send_response_timeout, req);
+#else
                send_response(sk, buf, len, client_addr,
                                *client_addr_len, IPPROTO_UDP);
+#endif
                return true;
        }
 
@@ -3809,21 +3944,26 @@ static GIOChannel *get_listener(int family, int protocol, int index)
 {
        GIOChannel *channel;
        const char *proto;
+#if !defined TIZEN_EXT
        union {
                struct sockaddr sa;
                struct sockaddr_in6 sin6;
                struct sockaddr_in sin;
        } s;
        socklen_t slen;
+#endif
        int sk, type;
 #if !defined TIZEN_EXT
        char *interface;
 #endif
 #if defined TIZEN_EXT
        int option;
+       int sd_num = 0;
+       int rv;
+       int is_socket_inet = 0;
 #endif
 
-       DBG("family %d protocol %d index %d", family, protocol, index);
+       debug("family %d protocol %d index %d", family, protocol, index);
 
        switch (protocol) {
        case IPPROTO_UDP:
@@ -3839,7 +3979,33 @@ static GIOChannel *get_listener(int family, int protocol, int index)
        default:
                return NULL;
        }
+#if defined TIZEN_EXT
+       sd_num = sd_listen_fds(0);
+       DBG("socket type(%s) systemd number of fds(%d)", proto, sd_num);
+       if(sd_num < 1){
+               DBG("fail to get the fd from systemd");
+               return NULL;
+       }
 
+       if(protocol == IPPROTO_TCP)
+               type = SOCK_STREAM;
+       else
+               type = SOCK_DGRAM;
+
+       for(sk = SD_LISTEN_FDS_START; sk < SD_LISTEN_FDS_START+sd_num; ++sk){
+               rv = sd_is_socket_inet(sk, family, type, -1, 53);
+               if(rv > 0){
+                       DBG("socket fd (%d) is passed by systemd", sk);
+                       is_socket_inet = 1;
+                       break;
+               }
+       }
+
+       if (!is_socket_inet) {
+               DBG("socket fd is not matched what connman requests");
+               return NULL;
+       }
+#else
        sk = socket(family, type, protocol);
        if (sk < 0 && family == AF_INET6 && errno == EAFNOSUPPORT) {
                connman_error("No IPv6 support");
@@ -3851,10 +4017,6 @@ static GIOChannel *get_listener(int family, int protocol, int index)
                return NULL;
        }
 
-#if !defined TIZEN_EXT
-       /* ConnMan listens DNS from multiple interfaces
-        * E.g. various technology based and tethering interfaces
-        */
        interface = connman_inet_ifname(index);
        if (!interface || setsockopt(sk, SOL_SOCKET, SO_BINDTODEVICE,
                                        interface,
@@ -3868,16 +4030,13 @@ static GIOChannel *get_listener(int family, int protocol, int index)
                return NULL;
        }
        g_free(interface);
-#endif
 
        if (family == AF_INET6) {
                memset(&s.sin6, 0, sizeof(s.sin6));
                s.sin6.sin6_family = AF_INET6;
                s.sin6.sin6_port = htons(53);
                slen = sizeof(s.sin6);
-#if defined TIZEN_EXT
-               s.sin6.sin6_addr = in6addr_any;
-#else
+
                if (__connman_inet_get_interface_address(index,
                                                AF_INET6,
                                                &s.sin6.sin6_addr) < 0) {
@@ -3888,42 +4047,46 @@ static GIOChannel *get_listener(int family, int protocol, int index)
                        close(sk);
                        return NULL;
                }
-#endif
 
        } else if (family == AF_INET) {
                memset(&s.sin, 0, sizeof(s.sin));
                s.sin.sin_family = AF_INET;
                s.sin.sin_port = htons(53);
                slen = sizeof(s.sin);
-#if defined TIZEN_EXT
-               s.sin.sin_addr.s_addr = htonl(INADDR_ANY);
-#else
+
                if (__connman_inet_get_interface_address(index,
                                                AF_INET,
                                                &s.sin.sin_addr) < 0) {
                        close(sk);
                        return NULL;
                }
-#endif
        } else {
                close(sk);
                return NULL;
        }
+#endif
 
 #if defined TIZEN_EXT
        /* When ConnMan crashed,
         * probably DNS listener cannot bind existing address */
        option = 1;
-       setsockopt(sk, SOL_SOCKET, SO_REUSEADDR, &option, sizeof(option));
+       if (setsockopt(sk, SOL_SOCKET, SO_REUSEADDR, &option, sizeof(option)) < 0) {
+               connman_error("Failed to set socket option SO_REUSEADDR");
+               close(sk);
+               return NULL;
+       }
 #endif
+#if !defined TIZEN_EXT
        if (bind(sk, &s.sa, slen) < 0) {
                connman_error("Failed to bind %s listener socket", proto);
                close(sk);
                return NULL;
        }
+#endif
 
        if (protocol == IPPROTO_TCP) {
 
+#if !defined TIZEN_EXT
                if (listen(sk, 10) < 0) {
                        connman_error("Failed to listen on TCP socket %d/%s",
                                -errno, strerror(errno));
@@ -3931,6 +4094,7 @@ static GIOChannel *get_listener(int family, int protocol, int index)
                        return NULL;
                }
 
+#endif
                fcntl(sk, F_SETFL, O_NONBLOCK);
        }
 
@@ -4103,7 +4267,7 @@ static void destroy_listener(struct listener_data *ifdata)
        for (list = request_list; list; list = list->next) {
                struct request_data *req = list->data;
 
-               DBG("Dropping request (id 0x%04x -> 0x%04x)",
+               debug("Dropping request (id 0x%04x -> 0x%04x)",
                                                req->srcid, req->dstid);
                destroy_request_data(req);
                list->data = NULL;
@@ -4200,8 +4364,6 @@ int __connman_dnsproxy_init(void)
 
        DBG("");
 
-       srandom(time(NULL));
-
        listener_table = g_hash_table_new_full(g_direct_hash, g_direct_equal,
                                                        NULL, g_free);
 
@@ -4229,10 +4391,25 @@ destroy:
        return err;
 }
 
+int __connman_dnsproxy_set_mdns(int index, bool enabled)
+{
+       return -ENOTSUP;
+}
+
 void __connman_dnsproxy_cleanup(void)
 {
        DBG("");
 
+       if (cache_timer) {
+               g_source_remove(cache_timer);
+               cache_timer = 0;
+       }
+
+       if (cache) {
+               g_hash_table_destroy(cache);
+               cache = NULL;
+       }
+
        connman_notifier_unregister(&dnsproxy_notifier);
 
        g_hash_table_foreach(listener_table, remove_listener, NULL);
@@ -4240,4 +4417,9 @@ void __connman_dnsproxy_cleanup(void)
        g_hash_table_destroy(listener_table);
 
        g_hash_table_destroy(partial_tcp_req_table);
+
+       if (ipv4_resolve)
+               g_resolv_unref(ipv4_resolve);
+       if (ipv6_resolve)
+               g_resolv_unref(ipv6_resolve);
 }