diff options
author | Nishant Chaprana <n.chaprana@samsung.com> | 2019-09-17 19:00:55 +0530 |
---|---|---|
committer | Nishant Chaprana <n.chaprana@samsung.com> | 2019-09-18 19:23:41 +0530 |
commit | 26cc90dfaf2ad149b702626f9552c81abbb26862 (patch) | |
tree | 2524c8994cf58358350fde67dfba5c3b8cb58f7d /src/dnsproxy.c | |
parent | 9e3beb21876b6e63bd8acf53e751480d7a1cc16f (diff) | |
parent | 6b2381a2adabea7d8309ff158ef675ff88184305 (diff) | |
download | connman-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-x | src/dnsproxy.c | 108 |
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); } |