5 * Copyright (C) 2007-2009 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/log.h>
40 #if __BYTE_ORDER == __LITTLE_ENDIAN
55 } __attribute__ ((packed));
56 #elif __BYTE_ORDER == __BIG_ENDIAN
71 } __attribute__ ((packed));
73 #error "Unknown byte order"
85 struct sockaddr_in sin;
97 static GSList *server_list = NULL;
98 static GSList *request_list = NULL;
99 static guint16 request_id = 0x0000;
101 static GIOChannel *listener_channel = NULL;
102 static guint listener_watch = 0;
104 static struct request_data *find_request(guint16 id)
108 for (list = request_list; list; list = list->next) {
109 struct request_data *req = list->data;
111 if (req->dstid == id || req->altid == id)
118 static struct server_data *find_server(const char *interface,
119 const char *domain, const char *server)
123 DBG("interface %s server %s", interface, server);
125 for (list = server_list; list; list = list->next) {
126 struct server_data *data = list->data;
128 if (data->interface == NULL || data->server == NULL)
131 if (g_str_equal(data->interface, interface) == TRUE &&
132 g_str_equal(data->server, server) == TRUE) {
133 if (domain == NULL) {
134 if (data->domain == NULL)
139 if (g_str_equal(data->domain, domain) == TRUE)
147 static gboolean server_event(GIOChannel *channel, GIOCondition condition,
150 struct server_data *data = user_data;
151 struct request_data *req;
152 unsigned char buf[768];
153 struct domain_hdr *hdr = (void *) &buf;
156 if (condition & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) {
157 connman_error("Error with server channel");
162 sk = g_io_channel_unix_get_fd(channel);
164 len = recv(sk, buf, sizeof(buf), 0);
168 DBG("Received %d bytes (id 0x%04x)", len, buf[0] | buf[1] << 8);
170 req = find_request(buf[0] | buf[1] << 8);
174 DBG("id 0x%04x rcode %d", hdr->id, hdr->rcode);
176 buf[0] = req->srcid & 0xff;
177 buf[1] = req->srcid >> 8;
181 if (hdr->rcode == 0 || req->resp == NULL) {
185 req->resp = g_try_malloc(len);
186 if (req->resp == NULL)
189 memcpy(req->resp, buf, len);
193 if (hdr->rcode > 0 && req->numresp < req->numserv)
196 if (req->timeout > 0)
197 g_source_remove(req->timeout);
199 request_list = g_slist_remove(request_list, req);
201 sk = g_io_channel_unix_get_fd(listener_channel);
203 err = sendto(sk, req->resp, req->resplen, 0,
204 (struct sockaddr *) &req->sin, req->len);
212 static struct server_data *create_server(const char *interface,
213 const char *domain, const char *server)
215 struct server_data *data;
216 struct sockaddr_in sin;
219 DBG("interface %s server %s", interface, server);
221 sk = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
223 connman_error("Failed to create server %s socket", server);
227 if (setsockopt(sk, SOL_SOCKET, SO_BINDTODEVICE,
228 interface, strlen(interface) + 1) < 0) {
229 connman_error("Failed to bind server %s to interface %s",
235 memset(&sin, 0, sizeof(sin));
236 sin.sin_family = AF_INET;
237 sin.sin_port = htons(53);
238 sin.sin_addr.s_addr = inet_addr(server);
240 if (connect(sk, (struct sockaddr *) &sin, sizeof(sin)) < 0) {
241 connman_error("Failed to connect server %s", server);
246 data = g_try_new0(struct server_data, 1);
248 connman_error("Failed to allocate server %s data", server);
253 data->channel = g_io_channel_unix_new(sk);
254 if (data->channel == NULL) {
255 connman_error("Failed to create server %s channel", server);
261 g_io_channel_set_close_on_unref(data->channel, TRUE);
263 data->watch = g_io_add_watch(data->channel, G_IO_IN,
266 data->interface = g_strdup(interface);
267 data->domain = g_strdup(domain);
268 data->server = g_strdup(server);
273 static void destroy_server(struct server_data *data)
275 DBG("interface %s server %s", data->interface, data->server);
278 g_source_remove(data->watch);
280 g_io_channel_unref(data->channel);
282 g_free(data->server);
283 g_free(data->domain);
284 g_free(data->interface);
288 static int dnsproxy_append(const char *interface, const char *domain,
291 struct server_data *data;
293 DBG("interface %s server %s", interface, server);
295 if (g_str_equal(server, "127.0.0.1") == TRUE)
298 data = create_server(interface, domain, server);
302 server_list = g_slist_append(server_list, data);
307 static int dnsproxy_remove(const char *interface, const char *domain,
310 struct server_data *data;
312 DBG("interface %s server %s", interface, server);
314 if (g_str_equal(server, "127.0.0.1") == TRUE)
317 data = find_server(interface, domain, server);
321 server_list = g_slist_remove(server_list, data);
323 destroy_server(data);
328 static struct connman_resolver dnsproxy_resolver = {
330 .priority = CONNMAN_RESOLVER_PRIORITY_HIGH,
331 .append = dnsproxy_append,
332 .remove = dnsproxy_remove,
335 static int parse_request(unsigned char *buf, int len,
336 char *name, unsigned int size)
338 struct domain_hdr *hdr = (void *) buf;
339 uint16_t qdcount = ntohs(hdr->qdcount);
341 char *last_label = NULL;
343 unsigned int remain, used = 0;
348 DBG("id 0x%04x qr %d opcode %d qdcount %d",
349 hdr->id, hdr->qr, hdr->opcode, qdcount);
351 if (hdr->qr != 0 || qdcount != 1)
354 memset(name, 0, size);
364 last_label = (char *) (ptr + 1);
370 if (used + len + 1 > size)
373 strncat(name, (char *) (ptr + 1), len);
382 DBG("query %s (%d labels)", name, label_count);
387 static void send_response(int sk, unsigned char *buf, int len,
388 const struct sockaddr *to, socklen_t tolen)
390 struct domain_hdr *hdr = (void *) buf;
396 DBG("id 0x%04x qr %d opcode %d", hdr->id, hdr->qr, hdr->opcode);
405 err = sendto(sk, buf, len, 0, to, tolen);
408 static int append_query(unsigned char *buf, unsigned int size,
409 const char *query, const char *domain)
411 unsigned char *ptr = buf;
414 DBG("query %s domain %s", query, domain);
416 offset = (char *) query;
417 while (offset != NULL) {
420 tmp = strchr(offset, '.');
422 if (strlen(offset) == 0)
424 *ptr = strlen(offset);
425 memcpy(ptr + 1, offset, strlen(offset));
426 ptr += strlen(offset) + 1;
431 memcpy(ptr + 1, offset, tmp - offset);
432 ptr += tmp - offset + 1;
437 offset = (char *) domain;
438 while (offset != NULL) {
441 tmp = strchr(offset, '.');
443 if (strlen(offset) == 0)
445 *ptr = strlen(offset);
446 memcpy(ptr + 1, offset, strlen(offset));
447 ptr += strlen(offset) + 1;
452 memcpy(ptr + 1, offset, tmp - offset);
453 ptr += tmp - offset + 1;
463 static gboolean request_timeout(gpointer user_data)
465 struct request_data *req = user_data;
467 DBG("id 0x%04x", req->srcid);
469 request_list = g_slist_remove(request_list, req);
471 if (req->resplen > 0 && req->resp != NULL) {
474 sk = g_io_channel_unix_get_fd(listener_channel);
476 err = sendto(sk, req->resp, req->resplen, 0,
477 (struct sockaddr *) &req->sin, req->len);
486 static gboolean listener_event(GIOChannel *channel, GIOCondition condition,
490 unsigned char buf[768];
492 struct request_data *req;
493 struct sockaddr_in sin;
494 socklen_t size = sizeof(sin);
497 if (condition & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) {
498 connman_error("Error with listener channel");
503 sk = g_io_channel_unix_get_fd(channel);
505 memset(&sin, 0, sizeof(sin));
506 len = recvfrom(sk, buf, sizeof(buf), 0,
507 (struct sockaddr *) &sin, &size);
511 DBG("Received %d bytes (id 0x%04x)", len, buf[0] | buf[1] << 8);
513 err = parse_request(buf, len, query, sizeof(query));
514 if (err < 0 || g_slist_length(server_list) == 0) {
515 send_response(sk, buf, len, (struct sockaddr *) &sin, size);
519 req = g_try_new0(struct request_data, 1);
523 memcpy(&req->sin, &sin, sizeof(sin));
527 if (request_id == 0x0000 || request_id == 0xffff)
530 req->srcid = buf[0] | (buf[1] << 8);
531 req->dstid = request_id;
532 req->altid = request_id + 1;
534 buf[0] = req->dstid & 0xff;
535 buf[1] = req->dstid >> 8;
537 request_list = g_slist_append(request_list, req);
540 req->timeout = g_timeout_add_seconds(5, request_timeout, req);
542 for (list = server_list; list; list = list->next) {
543 struct server_data *data = list->data;
545 DBG("server %s domain %s", data->server, data->domain);
547 sk = g_io_channel_unix_get_fd(data->channel);
549 err = send(sk, buf, len, 0);
553 if (data->domain != NULL) {
554 unsigned char alt[1024];
555 struct domain_hdr *hdr = (void *) &alt;
558 alt[0] = req->altid & 0xff;
559 alt[1] = req->altid >> 8;
561 memcpy(alt + 2, buf + 2, 10);
562 hdr->qdcount = htons(1);
564 altlen = append_query(alt + 12, sizeof(alt) - 12,
565 query, data->domain);
569 alt[altlen + 12] = 0x00;
570 alt[altlen + 13] = 0x01;
571 alt[altlen + 14] = 0x00;
572 alt[altlen + 15] = 0x01;
574 err = send(sk, alt, altlen + 12 + 4, 0);
583 static int create_listener(void)
585 const char *ifname = "lo";
586 struct sockaddr_in sin;
591 sk = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
593 connman_error("Failed to create listener socket");
597 //setsockopt(sk, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
598 //setsockopt(sk, SOL_IP, IP_PKTINFO, &opt, sizeof(opt));
600 if (setsockopt(sk, SOL_SOCKET, SO_BINDTODEVICE,
601 ifname, strlen(ifname) + 1) < 0) {
602 connman_error("Failed to bind listener interface");
607 memset(&sin, 0, sizeof(sin));
608 sin.sin_family = AF_INET;
609 sin.sin_port = htons(53);
610 sin.sin_addr.s_addr = inet_addr("127.0.0.1");
611 //sin.sin_addr.s_addr = INADDR_ANY;
613 if (bind(sk, (struct sockaddr *) &sin, sizeof(sin)) < 0) {
614 connman_error("Failed to bind listener socket");
619 listener_channel = g_io_channel_unix_new(sk);
620 if (listener_channel == NULL) {
621 connman_error("Failed to create listener channel");
626 g_io_channel_set_close_on_unref(listener_channel, TRUE);
628 listener_watch = g_io_add_watch(listener_channel, G_IO_IN,
629 listener_event, NULL);
631 connman_resolver_append("lo", NULL, "127.0.0.1");
636 static void destroy_listener(void)
642 connman_resolver_remove_all("lo");
644 if (listener_watch > 0)
645 g_source_remove(listener_watch);
647 for (list = request_list; list; list = list->next) {
648 struct request_data *req = list->data;
650 DBG("Dropping request (id 0x%04x -> 0x%04x)",
651 req->srcid, req->dstid);
658 g_slist_free(request_list);
661 g_io_channel_unref(listener_channel);
664 static int dnsproxy_init(void)
668 err = create_listener();
672 err = connman_resolver_register(&dnsproxy_resolver);
679 static void dnsproxy_exit(void)
683 connman_resolver_unregister(&dnsproxy_resolver);
686 CONNMAN_PLUGIN_DEFINE(dnsproxy, "DNS proxy resolver plugin", VERSION,
687 CONNMAN_PLUGIN_PRIORITY_DEFAULT, dnsproxy_init, dnsproxy_exit)