5 * Copyright (C) 2007-2010 Intel Corporation. All rights reserved.
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
30 #include <arpa/inet.h>
31 #include <netinet/in.h>
33 #define CONNMAN_API_SUBJECT_TO_CHANGE
34 #include <connman/plugin.h>
35 #include <connman/resolver.h>
36 #include <connman/notifier.h>
37 #include <connman/log.h>
41 #if __BYTE_ORDER == __LITTLE_ENDIAN
56 } __attribute__ ((packed));
57 #elif __BYTE_ORDER == __BIG_ENDIAN
72 } __attribute__ ((packed));
74 #error "Unknown byte order"
87 struct sockaddr_in sin;
102 static GSList *server_list = NULL;
103 static GSList *request_list = NULL;
104 static GSList *request_pending_list = NULL;
105 static guint16 request_id = 0x0000;
107 static GIOChannel *listener_channel = NULL;
108 static guint listener_watch = 0;
110 static struct request_data *find_request(guint16 id)
114 for (list = request_list; list; list = list->next) {
115 struct request_data *req = list->data;
117 if (req->dstid == id || req->altid == id)
124 static struct server_data *find_server(const char *interface,
125 const char *domain, const char *server)
129 DBG("interface %s server %s", interface, server);
131 for (list = server_list; list; list = list->next) {
132 struct server_data *data = list->data;
134 if (data->interface == NULL || data->server == NULL)
137 if (g_str_equal(data->interface, interface) == TRUE &&
138 g_str_equal(data->server, server) == TRUE) {
139 if (domain == NULL) {
140 if (data->domain == NULL)
145 if (g_str_equal(data->domain, domain) == TRUE)
153 static gboolean server_event(GIOChannel *channel, GIOCondition condition,
156 struct server_data *data = user_data;
157 struct request_data *req;
158 unsigned char buf[4096];
159 struct domain_hdr *hdr = (void *) &buf;
162 if (condition & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) {
163 connman_error("Error with server channel");
168 sk = g_io_channel_unix_get_fd(channel);
170 len = recv(sk, buf, sizeof(buf), 0);
174 DBG("Received %d bytes (id 0x%04x)", len, buf[0] | buf[1] << 8);
176 req = find_request(buf[0] | buf[1] << 8);
180 DBG("id 0x%04x rcode %d", hdr->id, hdr->rcode);
182 buf[0] = req->srcid & 0xff;
183 buf[1] = req->srcid >> 8;
187 if (hdr->rcode == 0 || req->resp == NULL) {
191 req->resp = g_try_malloc(len);
192 if (req->resp == NULL)
195 memcpy(req->resp, buf, len);
199 if (hdr->rcode > 0 && req->numresp < req->numserv)
202 if (req->timeout > 0)
203 g_source_remove(req->timeout);
205 request_list = g_slist_remove(request_list, req);
207 sk = g_io_channel_unix_get_fd(listener_channel);
209 err = sendto(sk, req->resp, req->resplen, 0,
210 (struct sockaddr *) &req->sin, req->len);
218 static struct server_data *create_server(const char *interface,
219 const char *domain, const char *server)
221 struct server_data *data;
222 struct sockaddr_in sin;
225 DBG("interface %s server %s", interface, server);
227 sk = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
229 connman_error("Failed to create server %s socket", server);
233 if (interface != NULL) {
234 if (setsockopt(sk, SOL_SOCKET, SO_BINDTODEVICE,
235 interface, strlen(interface) + 1) < 0) {
236 connman_error("Failed to bind server %s "
244 memset(&sin, 0, sizeof(sin));
245 sin.sin_family = AF_INET;
246 sin.sin_port = htons(53);
247 sin.sin_addr.s_addr = inet_addr(server);
249 if (connect(sk, (struct sockaddr *) &sin, sizeof(sin)) < 0) {
250 connman_error("Failed to connect server %s", server);
255 data = g_try_new0(struct server_data, 1);
257 connman_error("Failed to allocate server %s data", server);
262 data->channel = g_io_channel_unix_new(sk);
263 if (data->channel == NULL) {
264 connman_error("Failed to create server %s channel", server);
270 g_io_channel_set_close_on_unref(data->channel, TRUE);
272 data->watch = g_io_add_watch(data->channel, G_IO_IN,
275 data->interface = g_strdup(interface);
276 data->domain = g_strdup(domain);
277 data->server = g_strdup(server);
279 /* Enable new servers by default */
280 data->enabled = TRUE;
282 connman_info("Adding DNS server %s", data->server);
287 static void destroy_server(struct server_data *data)
289 DBG("interface %s server %s", data->interface, data->server);
292 g_source_remove(data->watch);
294 g_io_channel_unref(data->channel);
296 connman_info("Removing DNS server %s", data->server);
298 g_free(data->server);
299 g_free(data->domain);
300 g_free(data->interface);
304 static int append_query(unsigned char *buf, unsigned int size,
305 const char *query, const char *domain)
307 unsigned char *ptr = buf;
310 DBG("query %s domain %s", query, domain);
312 offset = (char *) query;
313 while (offset != NULL) {
316 tmp = strchr(offset, '.');
318 if (strlen(offset) == 0)
320 *ptr = strlen(offset);
321 memcpy(ptr + 1, offset, strlen(offset));
322 ptr += strlen(offset) + 1;
327 memcpy(ptr + 1, offset, tmp - offset);
328 ptr += tmp - offset + 1;
333 offset = (char *) domain;
334 while (offset != NULL) {
337 tmp = strchr(offset, '.');
339 if (strlen(offset) == 0)
341 *ptr = strlen(offset);
342 memcpy(ptr + 1, offset, strlen(offset));
343 ptr += strlen(offset) + 1;
348 memcpy(ptr + 1, offset, tmp - offset);
349 ptr += tmp - offset + 1;
359 static gboolean request_timeout(gpointer user_data)
361 struct request_data *req = user_data;
363 DBG("id 0x%04x", req->srcid);
365 request_list = g_slist_remove(request_list, req);
367 if (req->resplen > 0 && req->resp != NULL) {
370 sk = g_io_channel_unix_get_fd(listener_channel);
372 err = sendto(sk, req->resp, req->resplen, 0,
373 (struct sockaddr *) &req->sin, req->len);
382 static gboolean resolv(struct request_data *req,
383 gpointer request, gpointer name)
388 request_list = g_slist_append(request_list, req);
391 req->timeout = g_timeout_add_seconds(5, request_timeout, req);
393 for (list = server_list; list; list = list->next) {
394 struct server_data *data = list->data;
396 DBG("server %s domain %s enabled %d",
397 data->server, data->domain, data->enabled);
399 if (data->enabled == FALSE)
402 sk = g_io_channel_unix_get_fd(data->channel);
404 err = send(sk, request, req->request_len, 0);
408 if (data->domain != NULL) {
409 unsigned char alt[1024];
410 struct domain_hdr *hdr = (void *) &alt;
413 domlen = strlen(data->domain) + 1;
417 alt[0] = req->altid & 0xff;
418 alt[1] = req->altid >> 8;
420 memcpy(alt + 2, request + 2, 10);
421 hdr->qdcount = htons(1);
423 altlen = append_query(alt + 12, sizeof(alt) - 12,
430 memcpy(alt + altlen, request + altlen - domlen,
431 req->request_len - altlen + domlen);
433 err = send(sk, alt, req->request_len + domlen + 1, 0);
442 static int dnsproxy_append(const char *interface, const char *domain,
445 struct server_data *data;
447 DBG("interface %s server %s", interface, server);
449 if (g_str_equal(server, "127.0.0.1") == TRUE)
452 data = create_server(interface, domain, server);
456 server_list = g_slist_append(server_list, data);
461 static int dnsproxy_remove(const char *interface, const char *domain,
464 struct server_data *data;
466 DBG("interface %s server %s", interface, server);
468 if (g_str_equal(server, "127.0.0.1") == TRUE)
471 data = find_server(interface, domain, server);
475 server_list = g_slist_remove(server_list, data);
477 destroy_server(data);
482 static void dnsproxy_flush(void)
486 list = request_pending_list;
488 struct request_data *req = list->data;
492 request_pending_list =
493 g_slist_remove(request_pending_list, req);
494 resolv(req, req->request, req->name);
495 g_free(req->request);
500 static struct connman_resolver dnsproxy_resolver = {
502 .priority = CONNMAN_RESOLVER_PRIORITY_HIGH,
503 .append = dnsproxy_append,
504 .remove = dnsproxy_remove,
505 .flush = dnsproxy_flush,
508 static void dnsproxy_offline_mode(connman_bool_t enabled)
512 DBG("enabled %d", enabled);
514 for (list = server_list; list; list = list->next) {
515 struct server_data *data = list->data;
517 if (enabled == FALSE) {
518 connman_info("Enabling DNS server %s", data->server);
519 data->enabled = TRUE;
521 connman_info("Disabling DNS server %s", data->server);
522 data->enabled = FALSE;
527 static void dnsproxy_default_changed(struct connman_service *service)
532 DBG("service %p", service);
534 if (service == NULL) {
535 /* When no services are active, then disable DNS proxying */
536 dnsproxy_offline_mode(TRUE);
540 interface = connman_service_get_interface(service);
541 if (interface == NULL)
544 for (list = server_list; list; list = list->next) {
545 struct server_data *data = list->data;
547 if (g_strcmp0(data->interface, interface) == 0) {
548 connman_info("Enabling DNS server %s", data->server);
549 data->enabled = TRUE;
551 connman_info("Disabling DNS server %s", data->server);
552 data->enabled = FALSE;
559 static struct connman_notifier dnsproxy_notifier = {
561 .default_changed = dnsproxy_default_changed,
562 .offline_mode = dnsproxy_offline_mode,
565 static unsigned char opt_edns0_type[2] = { 0x00, 0x29 };
567 static int parse_request(unsigned char *buf, int len,
568 char *name, unsigned int size)
570 struct domain_hdr *hdr = (void *) buf;
571 uint16_t qdcount = ntohs(hdr->qdcount);
572 uint16_t arcount = ntohs(hdr->arcount);
574 char *last_label = NULL;
575 unsigned int remain, used = 0;
580 DBG("id 0x%04x qr %d opcode %d qdcount %d arcount %d",
581 hdr->id, hdr->qr, hdr->opcode,
584 if (hdr->qr != 0 || qdcount != 1)
587 memset(name, 0, size);
589 ptr = buf + sizeof(struct domain_hdr);
590 remain = len - sizeof(struct domain_hdr);
596 last_label = (char *) (ptr + 1);
600 if (used + len + 1 > size)
603 strncat(name, (char *) (ptr + 1), len);
612 if (last_label && arcount && remain >= 9 && last_label[4] == 0 &&
613 !memcmp(last_label + 5, opt_edns0_type, 2)) {
614 uint16_t edns0_bufsize;
616 edns0_bufsize = last_label[7] << 8 | last_label[8];
618 DBG("EDNS0 buffer size %u", edns0_bufsize);
620 /* This is an evil hack until full TCP support has been
623 * Somtimes the EDNS0 request gets send with a too-small
624 * buffer size. Since glibc doesn't seem to crash when it
625 * gets a response biffer then it requested, just bump
626 * the buffer size up to 4KiB.
628 if (edns0_bufsize < 0x1000) {
629 last_label[7] = 0x10;
630 last_label[8] = 0x00;
634 DBG("query %s", name);
639 static void send_response(int sk, unsigned char *buf, int len,
640 const struct sockaddr *to, socklen_t tolen)
642 struct domain_hdr *hdr = (void *) buf;
648 DBG("id 0x%04x qr %d opcode %d", hdr->id, hdr->qr, hdr->opcode);
657 err = sendto(sk, buf, len, 0, to, tolen);
660 static gboolean listener_event(GIOChannel *channel, GIOCondition condition,
663 unsigned char buf[768];
665 struct request_data *req;
666 struct sockaddr_in sin;
667 socklen_t size = sizeof(sin);
670 if (condition & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) {
671 connman_error("Error with listener channel");
676 sk = g_io_channel_unix_get_fd(channel);
678 memset(&sin, 0, sizeof(sin));
679 len = recvfrom(sk, buf, sizeof(buf), 0,
680 (struct sockaddr *) &sin, &size);
684 DBG("Received %d bytes (id 0x%04x)", len, buf[0] | buf[1] << 8);
686 err = parse_request(buf, len, query, sizeof(query));
687 if (err < 0 || g_slist_length(server_list) == 0) {
688 send_response(sk, buf, len, (struct sockaddr *) &sin, size);
692 req = g_try_new0(struct request_data, 1);
696 memcpy(&req->sin, &sin, sizeof(sin));
700 if (request_id == 0x0000 || request_id == 0xffff)
703 req->srcid = buf[0] | (buf[1] << 8);
704 req->dstid = request_id;
705 req->altid = request_id + 1;
706 req->request_len = len;
708 buf[0] = req->dstid & 0xff;
709 buf[1] = req->dstid >> 8;
711 return resolv(req, buf, query);
714 static int create_listener(void)
716 const char *ifname = "lo";
717 struct sockaddr_in sin;
722 sk = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
724 connman_error("Failed to create listener socket");
728 //setsockopt(sk, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
729 //setsockopt(sk, SOL_IP, IP_PKTINFO, &opt, sizeof(opt));
731 if (setsockopt(sk, SOL_SOCKET, SO_BINDTODEVICE,
732 ifname, strlen(ifname) + 1) < 0) {
733 connman_error("Failed to bind listener interface");
738 memset(&sin, 0, sizeof(sin));
739 sin.sin_family = AF_INET;
740 sin.sin_port = htons(53);
741 sin.sin_addr.s_addr = inet_addr("127.0.0.1");
742 //sin.sin_addr.s_addr = INADDR_ANY;
744 if (bind(sk, (struct sockaddr *) &sin, sizeof(sin)) < 0) {
745 connman_error("Failed to bind listener socket");
750 listener_channel = g_io_channel_unix_new(sk);
751 if (listener_channel == NULL) {
752 connman_error("Failed to create listener channel");
757 g_io_channel_set_close_on_unref(listener_channel, TRUE);
759 listener_watch = g_io_add_watch(listener_channel, G_IO_IN,
760 listener_event, NULL);
762 connman_resolver_append("lo", NULL, "127.0.0.1");
767 static void destroy_listener(void)
773 connman_resolver_remove_all("lo");
775 if (listener_watch > 0)
776 g_source_remove(listener_watch);
778 for (list = request_pending_list; list; list = list->next) {
779 struct request_data *req = list->data;
781 DBG("Dropping pending request (id 0x%04x -> 0x%04x)",
782 req->srcid, req->dstid);
785 g_free(req->request);
791 g_slist_free(request_pending_list);
792 request_pending_list = NULL;
794 for (list = request_list; list; list = list->next) {
795 struct request_data *req = list->data;
797 DBG("Dropping request (id 0x%04x -> 0x%04x)",
798 req->srcid, req->dstid);
801 g_free(req->request);
807 g_slist_free(request_list);
810 g_io_channel_unref(listener_channel);
813 static int dnsproxy_init(void)
817 err = create_listener();
821 err = connman_resolver_register(&dnsproxy_resolver);
825 err = connman_notifier_register(&dnsproxy_notifier);
832 connman_resolver_unregister(&dnsproxy_resolver);
840 static void dnsproxy_exit(void)
842 connman_notifier_unregister(&dnsproxy_notifier);
844 connman_resolver_unregister(&dnsproxy_resolver);
849 CONNMAN_PLUGIN_DEFINE(dnsproxy, "DNS proxy resolver plugin", VERSION,
850 CONNMAN_PLUGIN_PRIORITY_DEFAULT, dnsproxy_init, dnsproxy_exit)