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 40b4f15..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
@@ -79,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;
@@ -194,7 +204,11 @@ struct domain_rr {
  * By default the TTL (time-to-live) of the DNS response is used
  * when setting the cache entry life time. The value is in seconds.
  */
+#if defined TIZEN_EXT
+#define MAX_CACHE_TTL (60 * 60)
+#else
 #define MAX_CACHE_TTL (60 * 30)
+#endif
 /*
  * Also limit the other end, cache at least for 30 seconds.
  */
@@ -213,12 +227,22 @@ static int cache_size;
 static GHashTable *cache;
 static int cache_refcount;
 static GSList *server_list = NULL;
+#if defined TIZEN_EXT
+static GSList *server_list_sec = NULL;
+#endif
 static GSList *request_list = NULL;
 static GHashTable *listener_table = NULL;
 static time_t next_refresh;
 static GHashTable *partial_tcp_req_table;
 static guint cache_timer = 0;
 
+#if defined TIZEN_EXT
+static void destroy_server_sec(struct server_data *server);
+static struct server_data *create_server_sec(int index,
+               const char *domain, const char *server,
+               int protocol);
+#endif
+
 static guint16 get_id(void)
 {
        uint64_t rand;
@@ -448,7 +472,7 @@ 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
@@ -470,7 +494,7 @@ static void send_cached_response(int sk, unsigned char *buf, int len,
                        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)
 {
@@ -482,21 +506,34 @@ static void send_response(int sk, unsigned char *buf, int len,
        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
 
        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));
@@ -1642,6 +1679,31 @@ static int ns_resolv(struct server_data *server, struct request_data *req,
                }
        }
 
+#if defined TIZEN_EXT
+       if (server->protocol == IPPROTO_UDP) {
+               GList *domains;
+               struct server_data *new_server = NULL;
+
+               new_server = create_server_sec(server->index, NULL,
+                                               server->server, IPPROTO_UDP);
+
+               if (new_server != NULL) {
+                       for (domains = server->domains; domains;
+                                               domains = domains->next) {
+                               char *dom = domains->data;
+
+                               DBG("Adding domain %s to %s",
+                                               dom, new_server->server);
+
+                               new_server->domains = g_list_append(
+                                               new_server->domains,
+                                                       g_strdup(dom));
+                       }
+
+                       server = new_server;
+               }
+       }
+#endif
        sk = g_io_channel_unix_get_fd(server->channel);
 
        err = sendto(sk, request, req->request_len, MSG_NOSIGNAL,
@@ -2115,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;
@@ -2221,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)) {
@@ -2233,12 +2302,22 @@ 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;
+
+       for (list = server_list_sec; list; list = list->next) {
+               struct server_data *new_data = list->data;
+
+               if (new_data == data) {
+                       destroy_server_sec(data);
+                       return TRUE;
+               }
+       }
+#endif
 
        return TRUE;
 }
@@ -2550,6 +2629,177 @@ static void enable_fallback(bool enable)
        }
 }
 
+#if defined TIZEN_EXT
+
+static void destroy_server_sec(struct server_data *server)
+{
+       GList *list;
+       int fd;
+
+       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);
+
+       if (fd > 0)
+               close(fd);
+
+       server_destroy_socket(server);
+
+       if (server->protocol == IPPROTO_UDP && server->enabled)
+               DBG("Removing DNS server %s", server->server);
+
+       g_free(server->server);
+       for (list = server->domains; list; list = list->next) {
+               char *domain = list->data;
+
+               server->domains = g_list_remove(server->domains, domain);
+               g_free(domain);
+       }
+       g_free(server->server_addr);
+
+       /*
+        * We do not remove cache right away but delay it few seconds.
+        * The idea is that when IPv6 DNS server is added via RDNSS, it has a
+        * lifetime. When the lifetime expires we decrease the refcount so it
+        * is possible that the cache is then removed. Because a new DNS server
+        * is usually created almost immediately we would then loose the cache
+        * 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.
+        */
+       /* TODO: Need to check this */
+       /* g_timeout_add_seconds(3, try_remove_cache, NULL); */
+
+       g_free(server);
+}
+
+static void destroy_all_server_sec()
+{
+       GSList *list;
+
+       DBG("remove all dns server");
+
+       for (list = server_list_sec; list; list = list->next) {
+               struct server_data *server = list->data;
+               destroy_server_sec(server);
+       }
+       server_list_sec = NULL;
+}
+
+static gboolean sec_udp_idle_timeout(gpointer user_data)
+{
+       struct server_data *server = user_data;
+
+       DBG("");
+
+       if (server == NULL)
+               return FALSE;
+
+       destroy_server_sec(server);
+
+       return FALSE;
+}
+
+static struct server_data *create_server_sec(int index,
+                                       const char *domain, const char *server,
+                                       int protocol)
+{
+       struct server_data *data;
+       struct addrinfo hints, *rp;
+       int ret;
+
+       DBG("index %d server %s", index, server);
+
+       data = g_try_new0(struct server_data, 1);
+       if (data == NULL) {
+               connman_error("Failed to allocate server %s data", server);
+               return NULL;
+       }
+
+       data->index = index;
+       if (domain)
+               data->domains = g_list_append(data->domains, g_strdup(domain));
+       data->server = g_strdup(server);
+       data->protocol = protocol;
+
+       memset(&hints, 0, sizeof(hints));
+
+       switch (protocol) {
+       case IPPROTO_UDP:
+               hints.ai_socktype = SOCK_DGRAM;
+               break;
+
+       case IPPROTO_TCP:
+               hints.ai_socktype = SOCK_STREAM;
+               break;
+
+       default:
+               destroy_server_sec(data);
+               return NULL;
+       }
+       hints.ai_family = AF_UNSPEC;
+       hints.ai_flags = AI_NUMERICSERV | AI_NUMERICHOST;
+
+       ret = getaddrinfo(data->server, "53", &hints, &rp);
+       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;
+       }
+
+       /* 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. */
+
+       data->server_addr_len = rp->ai_addrlen;
+
+       switch (rp->ai_family) {
+       case AF_INET:
+               data->server_addr = (struct sockaddr *)
+                                       g_try_new0(struct sockaddr_in, 1);
+               break;
+       case AF_INET6:
+               data->server_addr = (struct sockaddr *)
+                                       g_try_new0(struct sockaddr_in6, 1);
+               break;
+       default:
+               connman_error("Wrong address family %d", rp->ai_family);
+               break;
+       }
+       if (data->server_addr == NULL) {
+               freeaddrinfo(rp);
+               destroy_server_sec(data);
+               return NULL;
+       }
+       memcpy(data->server_addr, rp->ai_addr, rp->ai_addrlen);
+       freeaddrinfo(rp);
+
+       if (server_create_socket(data) != 0) {
+               destroy_server_sec(data);
+               return NULL;
+       }
+
+       if (protocol == IPPROTO_UDP) {
+               /* Enable new servers by default */
+               data->enabled = TRUE;
+               DBG("Adding DNS server %s", data->server);
+
+               data->timeout = g_timeout_add_seconds(30, sec_udp_idle_timeout,
+                                                               data);
+
+               server_list_sec = g_slist_append(server_list_sec, data);
+       }
+
+       return data;
+}
+#endif
+
 static struct server_data *create_server(int index,
                                        const char *domain, const char *server,
                                        int protocol)
@@ -2840,6 +3090,10 @@ int __connman_dnsproxy_remove(int index, const char *domain,
        remove_server(index, domain, server, IPPROTO_UDP);
        remove_server(index, domain, server, IPPROTO_TCP);
 
+#if defined TIZEN_EXT
+       destroy_all_server_sec();
+#endif
+
        return 0;
 }
 
@@ -2905,34 +3159,77 @@ static void dnsproxy_default_changed(struct connman_service *service)
        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;
 
        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);
@@ -2942,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;
                }
 
@@ -2958,26 +3271,13 @@ static int parse_request(unsigned char *buf, int len,
                remain -= label_len + 1;
        }
 
-       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];
-
-               debug("EDNS0 buffer size %u", edns0_bufsize);
+       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);
 
-               /* 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);
        }
 
        debug("query %s", name);
@@ -3288,6 +3588,23 @@ static gboolean client_timeout(gpointer user_data)
        return FALSE;
 }
 
+#if defined TIZEN_EXT
+static void recover_listener(GIOChannel *channel, struct listener_data *ifdata)
+{
+       int sk, index;
+
+       index = ifdata->index;
+
+       sk = g_io_channel_unix_get_fd(channel);
+       close(sk);
+
+       __connman_dnsproxy_remove_listener(index);
+
+       if (__connman_dnsproxy_add_listener(index) == 0)
+               DBG("listener %d successfully recovered", index);
+}
+#endif
+
 static bool tcp_listener_event(GIOChannel *channel, GIOCondition condition,
                                struct listener_data *ifdata, int family,
                                guint *listener_watch)
@@ -3308,11 +3625,17 @@ static bool tcp_listener_event(GIOChannel *channel, GIOCondition condition,
                condition, channel, ifdata, family);
 
        if (condition & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) {
+#if defined TIZEN_EXT
+               connman_error("Error %d with TCP listener channel", condition);
+
+               recover_listener(channel, ifdata);
+#else
                if (*listener_watch > 0)
                        g_source_remove(*listener_watch);
                *listener_watch = 0;
 
                connman_error("Error with TCP listener channel");
+#endif
 
                return false;
        }
@@ -3426,7 +3749,11 @@ static bool tcp_listener_event(GIOChannel *channel, GIOCondition condition,
         * The packet length bytes do not contain the total message length,
         * that is the reason to -2 below.
         */
+#if defined TIZEN_EXT
+       if (msg_len > (unsigned int)(len - 2)) {
+#else
        if (msg_len != (unsigned int)(len - 2)) {
+#endif
                debug("client %d sent %d bytes but expecting %u pending %d",
                        client_sk, len, msg_len + 2, msg_len + 2 - len);
 
@@ -3455,6 +3782,39 @@ static gboolean tcp6_listener_event(GIOChannel *channel, GIOCondition condition,
                                &ifdata->tcp6_listener_watch);
 }
 
+#if defined TIZEN_EXT
+struct request_data * create_request(int sk, unsigned char *buf, size_t len,
+                                const struct sockaddr *to, socklen_t tolen,
+                                int protocol)
+{
+       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;
+
+}
+static gboolean send_response_timeout (gpointer user_data)
+{
+       struct request_data *req = user_data;
+
+       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);
+
+       return FALSE;
+
+}
+#endif
+
 static bool udp_listener_event(GIOChannel *channel, GIOCondition condition,
                                struct listener_data *ifdata, int family,
                                guint *listener_watch)
@@ -3471,8 +3831,14 @@ static bool udp_listener_event(GIOChannel *channel, GIOCondition condition,
        int sk, err, len;
 
        if (condition & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) {
+#if defined TIZEN_EXT
+               connman_error("Error %d with UDP listener channel", condition);
+
+               recover_listener(channel, ifdata);
+#else
                connman_error("Error with UDP listener channel");
                *listener_watch = 0;
+#endif
                return false;
        }
 
@@ -3495,8 +3861,22 @@ static bool udp_listener_event(GIOChannel *channel, GIOCondition condition,
 
        err = parse_request(buf, len, query, sizeof(query));
        if (err < 0 || (g_slist_length(server_list) == 0)) {
+#if defined TIZEN_EXT
+               /** 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;
        }
 
@@ -3531,7 +3911,12 @@ static bool udp_listener_event(GIOChannel *channel, GIOCondition condition,
        req->name = g_strdup(query);
        req->request = g_malloc(len);
        memcpy(req->request, buf, len);
+#if defined TIZEN_EXT
+       DBG("req %p dstid 0x%04x altid 0x%04x", req, req->dstid, req->altid);
+       req->timeout = g_timeout_add_seconds(30, request_timeout, req);
+#else
        req->timeout = g_timeout_add_seconds(5, request_timeout, req);
+#endif
        request_list = g_slist_append(request_list, req);
 
        return true;
@@ -3559,14 +3944,24 @@ 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
 
        debug("family %d protocol %d index %d", family, protocol, index);
 
@@ -3584,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");
@@ -3643,15 +4064,29 @@ static GIOChannel *get_listener(int family, int protocol, int index)
                close(sk);
                return NULL;
        }
+#endif
 
+#if defined TIZEN_EXT
+       /* When ConnMan crashed,
+        * probably DNS listener cannot bind existing address */
+       option = 1;
+       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));
@@ -3659,6 +4094,7 @@ static GIOChannel *get_listener(int family, int protocol, int index)
                        return NULL;
                }
 
+#endif
                fcntl(sk, F_SETFL, O_NONBLOCK);
        }
 
@@ -3691,40 +4127,68 @@ static int create_dns_listener(int protocol, struct listener_data *ifdata)
                ifdata->tcp4_listener_channel = get_listener(AF_INET, protocol,
                                                        ifdata->index);
                if (ifdata->tcp4_listener_channel)
+#if defined TIZEN_EXT
+                       ifdata->tcp4_listener_watch =
+                               g_io_add_watch(ifdata->tcp4_listener_channel,
+                                       G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
+                                       tcp4_listener_event, (gpointer)ifdata);
+#else
                        ifdata->tcp4_listener_watch =
                                g_io_add_watch(ifdata->tcp4_listener_channel,
                                        G_IO_IN, tcp4_listener_event,
                                        (gpointer)ifdata);
+#endif
                else
                        ret |= TCP_IPv4_FAILED;
 
                ifdata->tcp6_listener_channel = get_listener(AF_INET6, protocol,
                                                        ifdata->index);
                if (ifdata->tcp6_listener_channel)
+#if defined TIZEN_EXT
+                       ifdata->tcp6_listener_watch =
+                               g_io_add_watch(ifdata->tcp6_listener_channel,
+                                       G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
+                                       tcp6_listener_event, (gpointer)ifdata);
+#else
                        ifdata->tcp6_listener_watch =
                                g_io_add_watch(ifdata->tcp6_listener_channel,
                                        G_IO_IN, tcp6_listener_event,
                                        (gpointer)ifdata);
+#endif
                else
                        ret |= TCP_IPv6_FAILED;
        } else {
                ifdata->udp4_listener_channel = get_listener(AF_INET, protocol,
                                                        ifdata->index);
                if (ifdata->udp4_listener_channel)
+#if defined TIZEN_EXT
+                       ifdata->udp4_listener_watch =
+                               g_io_add_watch(ifdata->udp4_listener_channel,
+                                       G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
+                                       udp4_listener_event, (gpointer)ifdata);
+#else
                        ifdata->udp4_listener_watch =
                                g_io_add_watch(ifdata->udp4_listener_channel,
                                        G_IO_IN, udp4_listener_event,
                                        (gpointer)ifdata);
+#endif
                else
                        ret |= UDP_IPv4_FAILED;
 
                ifdata->udp6_listener_channel = get_listener(AF_INET6, protocol,
                                                        ifdata->index);
                if (ifdata->udp6_listener_channel)
+#if defined TIZEN_EXT
+                       ifdata->udp6_listener_watch =
+                               g_io_add_watch(ifdata->udp6_listener_channel,
+                                       G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
+                                       udp6_listener_event, (gpointer)ifdata);
+#else
                        ifdata->udp6_listener_watch =
                                g_io_add_watch(ifdata->udp6_listener_channel,
                                        G_IO_IN, udp6_listener_event,
                                        (gpointer)ifdata);
+#endif
                else
                        ret |= UDP_IPv6_FAILED;
        }
@@ -3927,6 +4391,11 @@ destroy:
        return err;
 }
 
+int __connman_dnsproxy_set_mdns(int index, bool enabled)
+{
+       return -ENOTSUP;
+}
+
 void __connman_dnsproxy_cleanup(void)
 {
        DBG("");
@@ -3948,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);
 }