#include "connman.h"
+#if defined TIZEN_EXT
+#include <sys/smack.h>
+#endif
+
#if __BYTE_ORDER == __LITTLE_ENDIAN
struct domain_hdr {
uint16_t id;
* 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.
*/
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)
{
- return random();
+ uint64_t rand;
+
+ __connman_util_get_random(&rand);
+
+ return rand;
}
static int protocol_offset(int protocol)
static void update_cached_ttl(unsigned char *buf, int len, int new_ttl)
{
unsigned char *c;
- uint32_t *i;
- uint16_t *w;
+ uint16_t w;
int l;
/* skip the header */
break;
/* now the 4 byte TTL field */
- i = (uint32_t *)c;
- *i = htonl(new_ttl);
+ c[0] = new_ttl >> 24 & 0xff;
+ c[1] = new_ttl >> 16 & 0xff;
+ c[2] = new_ttl >> 8 & 0xff;
+ c[3] = new_ttl & 0xff;
c += 4;
len -= 4;
if (len < 0)
break;
/* now the 2 byte rdlen field */
- w = (uint16_t *)c;
- c += ntohs(*w) + 2;
- len -= ntohs(*w) + 2;
+ w = c[0] << 8 | c[1];
+ c += w + 2;
+ len -= w + 2;
}
}
hdr->id = id;
hdr->qr = 1;
- hdr->rcode = 0;
+ hdr->rcode = ns_r_noerror;
hdr->ancount = htons(answers);
hdr->nscount = 0;
hdr->arcount = 0;
DBG("id 0x%04x qr %d opcode %d", hdr->id, hdr->qr, hdr->opcode);
hdr->qr = 1;
- hdr->rcode = 2;
+ hdr->rcode = ns_r_servfail;
hdr->ancount = 0;
hdr->nscount = 0;
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);
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);
- hdr->id = req->srcid;
+ hdr = (void *)(req->request + protocol_offset(req->protocol));
+ 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);
}
/*
GINT_TO_POINTER(req->client_sk));
}
+out:
req->timeout = 0;
destroy_request_data(req);
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.");
static int reply_query_type(unsigned char *msg, int len)
{
unsigned char *c;
- uint16_t *w;
int l;
int type;
/* now the query, which is a name and 2 16 bit words */
l = dns_name_length(c) + 1;
c += l;
- w = (uint16_t *) c;
- type = ntohs(*w);
+ type = c[0] << 8 | c[1];
return type;
}
DBG("offset %d hdr %p msg %p rcode %d", offset, hdr, msg, hdr->rcode);
/* Continue only if response code is 0 (=ok) */
- if (hdr->rcode != 0)
+ if (hdr->rcode != ns_r_noerror)
return 0;
if (!cache)
}
}
+#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,
int pos; /* position in compressed string */
char name[NS_MAXLABEL]; /* tmp label */
uint16_t dns_type, dns_class;
+ int comp_pos;
- pos = dn_expand((const u_char *)start, (u_char *)end,
- (u_char *)ptr, name, NS_MAXLABEL);
- if (pos < 0) {
- DBG("uncompress error [%d/%s]", errno,
- strerror(errno));
+ if (!convert_label(start, end, ptr, name, NS_MAXLABEL,
+ &pos, &comp_pos))
goto out;
- }
/*
* Copy the uncompressed resource record, type, class and \0 to
*/
ulen = strlen(name);
- *uptr++ = ulen;
strncpy(uptr, name, uncomp_len - (uptr - uncompressed));
DBG("pos %d ulen %d left %d name %s", pos, ulen,
* so we need to uncompress it also when necessary.
*/
if (dns_type == ns_t_cname) {
- int comp_pos;
-
if (!convert_label(start, end, ptr, uptr,
uncomp_len - (uptr - uncompressed),
&pos, &comp_pos))
ptr += dlen;
} else if (dns_type == ns_t_soa) {
- int comp_pos;
int total_len = 0;
char *len_ptr;
return NULL;
}
+static int strip_domains(char *name, char *answers, int maxlen)
+{
+ uint16_t data_len;
+ int name_len = strlen(name);
+ char *ptr, *start = answers, *end = answers + maxlen;
+
+ while (maxlen > 0) {
+ ptr = strstr(answers, name);
+ if (ptr) {
+ char *domain = ptr + name_len;
+
+ if (*domain) {
+ int domain_len = strlen(domain);
+
+ memmove(answers + name_len,
+ domain + domain_len,
+ end - (domain + domain_len));
+
+ end -= domain_len;
+ maxlen -= domain_len;
+ }
+ }
+
+ answers += strlen(answers) + 1;
+ answers += 2 + 2 + 4; /* skip type, class and ttl fields */
+
+ data_len = answers[0] << 8 | answers[1];
+ answers += 2; /* skip the length field */
+
+ if (answers + data_len > end)
+ return -EINVAL;
+
+ answers += data_len;
+ maxlen -= answers - ptr;
+ }
+
+ return end - start;
+}
+
static int forward_dns_reply(unsigned char *reply, int reply_len, int protocol,
struct server_data *data)
{
req->numresp++;
- if (hdr->rcode == 0 || !req->resp) {
+ if (hdr->rcode == ns_r_noerror || !req->resp) {
unsigned char *new_reply = NULL;
/*
*/
if (domain_len > 0) {
int len = host_len + 1;
+ int new_len, fixed_len;
+ char *answers;
/*
* First copy host (without domain name) into
*/
ptr += NS_QFIXEDSZ;
uptr += NS_QFIXEDSZ;
+ answers = uptr;
+ fixed_len = answers - uncompressed;
/*
* We then uncompress the result to buffer
goto out;
/*
+ * The uncompressed buffer now contains almost
+ * valid response. Final step is to get rid of
+ * the domain name because at least glibc
+ * gethostbyname() implementation does extra
+ * checks and expects to find an answer without
+ * domain name if we asked a query without
+ * domain part. Note that glibc getaddrinfo()
+ * works differently and accepts FQDN in answer
+ */
+ new_len = strip_domains(uncompressed, answers,
+ uptr - answers);
+ if (new_len < 0) {
+ DBG("Corrupted packet");
+ return -EINVAL;
+ }
+
+ /*
* Because we have now uncompressed the answers
- * we must create a bigger buffer to hold all
- * that data.
+ * we might have to create a bigger buffer to
+ * hold all that data.
*/
- new_reply = g_try_malloc(header_len +
- uptr - uncompressed);
+ reply_len = header_len + new_len + fixed_len;
+
+ new_reply = g_try_malloc(reply_len);
if (!new_reply)
return -ENOMEM;
memcpy(new_reply, reply, header_len);
memcpy(new_reply + header_len, uncompressed,
- uptr - uncompressed);
+ new_len + fixed_len);
reply = new_reply;
- reply_len = header_len + uptr - uncompressed;
}
}
}
out:
- if (hdr->rcode > 0 && req->numresp < req->numserv)
- return -EINVAL;
+ if (req->numresp < req->numserv) {
+ if (hdr->rcode > ns_r_noerror) {
+ return -EINVAL;
+ } else if (hdr->ancount == 0 && req->append_domain) {
+ return -EINVAL;
+ }
+ }
request_list = g_slist_remove(request_list, req);
* 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.
*/
- 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);
}
if (err < 0)
return TRUE;
+#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;
}
return 0;
}
+#if defined TIZEN_EXT
+
+static void destroy_server_sec(struct server_data *server)
+{
+ GList *list;
+
+ DBG("index %d server %s sock %d", server->index, server->server,
+ server->channel != NULL ?
+ g_io_channel_unix_get_fd(server->channel): -1);
+
+ server_list_sec = g_slist_remove(server_list_sec, server);
+ close(g_io_channel_unix_get_fd(server->channel));
+ 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));
+ 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)
}
}
+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)
{
if (!data)
return -EIO;
+ flush_requests(data);
+
return 0;
}
remove_server(index, domain, server, IPPROTO_UDP);
remove_server(index, domain, server, IPPROTO_TCP);
- 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 defined TIZEN_EXT
+ destroy_all_server_sec();
+#endif
- if (req->timeout > 0)
- g_source_remove(req->timeout);
- req->timeout = g_timeout_add_seconds(5, request_timeout, req);
- }
+ return 0;
}
static void dnsproxy_offline_mode(bool enabled)
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;
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)
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;
}
* 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
DBG("client %d sent %d bytes but expecting %u pending %d",
client_sk, len, msg_len + 2, msg_len + 2 - len);
&ifdata->tcp6_listener_watch);
}
+#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 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);
+
+ DBG("id 0x%04x qr %d opcode %d", hdr->id, hdr->qr, hdr->opcode);
+
+ hdr->qr = 1;
+ hdr->rcode = 4;
+
+ hdr->ancount = 0;
+ hdr->nscount = 0;
+ hdr->arcount = 0;
+
+ 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
+
static bool udp_listener_event(GIOChannel *channel, GIOCondition condition,
struct listener_data *ifdata, int family,
guint *listener_watch)
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;
}
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
send_response(sk, buf, len, client_addr,
*client_addr_len, IPPROTO_UDP);
return true;
return true;
}
+ 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;
} s;
socklen_t slen;
int sk, type;
+#if !defined TIZEN_EXT
char *interface;
+#endif
+#if defined TIZEN_EXT
+ int option;
+#endif
DBG("family %d protocol %d index %d", family, protocol, 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,
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) {
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;
}
+#if defined TIZEN_EXT
+ if (smack_fsetlabel(sk, "system::use_internet", SMACK_LABEL_IPOUT) != 0)
+ connman_error("Failed to label system::use_internet");
+
+ if (smack_fsetlabel(sk, "system::use_internet", SMACK_LABEL_IPIN) != 0)
+ connman_error("Failed to label system::use_internet");
+#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));
+#endif
if (bind(sk, &s.sa, slen) < 0) {
connman_error("Failed to bind %s listener socket", proto);
close(sk);
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;
}
DBG("");
- srandom(time(NULL));
-
listener_table = g_hash_table_new_full(g_direct_hash, g_direct_equal,
NULL, g_free);
{
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);