summaryrefslogtreecommitdiff
path: root/src/dnsproxy.c
diff options
context:
space:
mode:
authorNishant Chaprana <n.chaprana@samsung.com>2019-09-17 19:00:55 +0530
committerNishant Chaprana <n.chaprana@samsung.com>2019-09-18 19:23:41 +0530
commit26cc90dfaf2ad149b702626f9552c81abbb26862 (patch)
tree2524c8994cf58358350fde67dfba5c3b8cb58f7d /src/dnsproxy.c
parent9e3beb21876b6e63bd8acf53e751480d7a1cc16f (diff)
parent6b2381a2adabea7d8309ff158ef675ff88184305 (diff)
downloadconnman-26cc90dfaf2ad149b702626f9552c81abbb26862.tar.gz
connman-26cc90dfaf2ad149b702626f9552c81abbb26862.tar.bz2
connman-26cc90dfaf2ad149b702626f9552c81abbb26862.zip
Imported Upstream version 1.37submit/tizen/20190920.082459
Change-Id: Idb47c1ddbedc9f97181b8e9a5eeac04ddd832a2c Signed-off-by: Nishant Chaprana <n.chaprana@samsung.com>
Diffstat (limited to 'src/dnsproxy.c')
-rwxr-xr-xsrc/dnsproxy.c108
1 files changed, 68 insertions, 40 deletions
diff --git a/src/dnsproxy.c b/src/dnsproxy.c
index 72c0d8f1..cb583251 100755
--- a/src/dnsproxy.c
+++ b/src/dnsproxy.c
@@ -84,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;
@@ -489,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)
{
@@ -501,21 +506,26 @@ 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 (offset) {
+ buf[0] = 0;
+ buf[1] = sizeof(*hdr);
+ }
debug("id 0x%04x qr %d opcode %d", hdr->id, hdr->qr, hdr->opcode);
hdr->qr = 1;
hdr->rcode = ns_r_servfail;
+ hdr->qdcount = 0;
hdr->ancount = 0;
hdr->nscount = 0;
hdr->arcount = 0;
- err = sendto(sk, buf, len, MSG_NOSIGNAL, to, tolen);
+ err = sendto(sk, buf, sizeof(*hdr) + offset, MSG_NOSIGNAL, to, tolen);
if (err < 0) {
connman_error("Failed to send DNS response to %d: %s",
sk, strerror(errno));
@@ -2265,7 +2275,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)) {
@@ -2277,12 +2287,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;
@@ -3137,34 +3144,41 @@ static void dnsproxy_default_changed(struct connman_service *service)
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;
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);
@@ -3174,7 +3188,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;
}
@@ -3190,26 +3220,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];
+ 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);
- debug("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);
}
debug("query %s", name);
@@ -3902,9 +3919,6 @@ static GIOChannel *get_listener(int family, int protocol, int index)
return NULL;
}
- /* 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,
@@ -3941,6 +3955,7 @@ static GIOChannel *get_listener(int family, int protocol, int index)
s.sin.sin_family = AF_INET;
s.sin.sin_port = htons(53);
slen = sizeof(s.sin);
+
if (__connman_inet_get_interface_address(index,
AF_INET,
&s.sin.sin_addr) < 0) {
@@ -3952,6 +3967,7 @@ static GIOChannel *get_listener(int family, int protocol, int index)
return NULL;
}
#endif
+
#if defined TIZEN_EXT
/* When ConnMan crashed,
* probably DNS listener cannot bind existing address */
@@ -3971,6 +3987,7 @@ static GIOChannel *get_listener(int family, int protocol, int index)
#endif
if (protocol == IPPROTO_TCP) {
+
#if !defined TIZEN_EXT
if (listen(sk, 10) < 0) {
connman_error("Failed to listen on TCP socket %d/%s",
@@ -3978,6 +3995,7 @@ static GIOChannel *get_listener(int family, int protocol, int index)
close(sk);
return NULL;
}
+
#endif
fcntl(sk, F_SETFL, O_NONBLOCK);
}
@@ -4275,6 +4293,11 @@ destroy:
return err;
}
+int __connman_dnsproxy_set_mdns(int index, bool enabled)
+{
+ return -ENOTSUP;
+}
+
void __connman_dnsproxy_cleanup(void)
{
DBG("");
@@ -4296,4 +4319,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);
}