#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;
#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;
{
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;
}
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;
{
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)
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);
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));
if (!req)
return FALSE;
- DBG("id 0x%04x", req->srcid);
+ debug("id 0x%04x", req->srcid);
request_list = g_slist_remove(request_list, req);
* 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));
}
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;
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;
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;
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)
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)
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;
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;
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;
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.
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;
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)
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;
*/
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;
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,
*/
static void cache_invalidate(void)
{
- DBG("Invalidating the DNS cache %p", cache);
+ debug("Invalidating the DNS cache %p", cache);
if (!cache)
return;
*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]);
}
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];
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)
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,
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
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);
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);
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;
}
*/
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;
}
{
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 */
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;
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;
}
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;
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;
}
(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;
/*
new_len = strip_domains(uncompressed, answers,
uptr - answers);
if (new_len < 0) {
- DBG("Corrupted packet");
+ debug("Corrupted packet");
return -EINVAL;
}
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;
}
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);
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) {
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);
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);
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)) {
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;
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
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;
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,
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);
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)
{
struct server_data *server = user_data;
- DBG("");
+ debug("");
if (!server)
return FALSE;
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,
return -err;
}
- DBG("sk %d", sk);
+ debug("sk %d", sk);
interface = connman_inet_ifname(data->index);
if (interface) {
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)
data->index)) {
data->enabled = true;
DBG("Adding DNS server %s", data->server);
+
+ enable_fallback(false);
}
server_list = g_slist_append(server_list, data);
continue;
}
- DBG("server %s enabled %d", data->server, data->enabled);
+ debug("server %s enabled %d", data->server, data->enabled);
if (!data->enabled)
continue;
return false;
}
-static void append_domain(int index, const char *domain)
+static void update_domain(int index, const char *domain, bool append)
{
GSList *list;
}
}
- 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;
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,
{
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;
static void dnsproxy_default_changed(struct connman_service *service)
{
+ bool server_enabled = false;
GSList *list;
int index;
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 const struct connman_notifier dnsproxy_notifier = {
.name = "dnsproxy",
.default_changed = dnsproxy_default_changed,
.offline_mode = dnsproxy_offline_mode,
};
-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);
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;
}
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;
}
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);
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;
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));
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
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) {
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,
*/
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);
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));
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));
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)) {
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;
}
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) {
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));
}
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));
#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;
&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)
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
send_response(sk, buf, len, client_addr,
*client_addr_len, IPPROTO_UDP);
return true;
{
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:
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");
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;
}
+#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));
return NULL;
}
+#endif
fcntl(sk, F_SETFL, O_NONBLOCK);
}
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;
return err;
}
+int __connman_dnsproxy_set_mdns(int index, bool enabled)
+{
+ return -ENOTSUP;
+}
+
void __connman_dnsproxy_cleanup(void)
{
DBG("");
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);
}