Remove magic constants from dns request parsing code
[framework/connectivity/connman.git] / plugins / dnsproxy.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2007-2010  Intel Corporation. All rights reserved.
6  *
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.
10  *
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.
15  *
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
19  *
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <errno.h>
27 #include <unistd.h>
28 #include <string.h>
29 #include <stdint.h>
30 #include <arpa/inet.h>
31 #include <netinet/in.h>
32
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>
38
39 #include <glib.h>
40
41 #if __BYTE_ORDER == __LITTLE_ENDIAN
42 struct domain_hdr {
43         uint16_t id;
44         uint8_t rd:1;
45         uint8_t tc:1;
46         uint8_t aa:1;
47         uint8_t opcode:4;
48         uint8_t qr:1;
49         uint8_t rcode:4;
50         uint8_t z:3;
51         uint8_t ra:1;
52         uint16_t qdcount;
53         uint16_t ancount;
54         uint16_t nscount;
55         uint16_t arcount;
56 } __attribute__ ((packed));
57 #elif __BYTE_ORDER == __BIG_ENDIAN
58 struct domain_hdr {
59         uint16_t id;
60         uint8_t qr:1;
61         uint8_t opcode:4;
62         uint8_t aa:1;
63         uint8_t tc:1;
64         uint8_t rd:1;
65         uint8_t ra:1;
66         uint8_t z:3;
67         uint8_t rcode:4;
68         uint16_t qdcount;
69         uint16_t ancount;
70         uint16_t nscount;
71         uint16_t arcount;
72 } __attribute__ ((packed));
73 #else
74 #error "Unknown byte order"
75 #endif
76
77 struct server_data {
78         char *interface;
79         char *domain;
80         char *server;
81         GIOChannel *channel;
82         guint watch;
83         gboolean enabled;
84 };
85
86 struct request_data {
87         struct sockaddr_in sin;
88         socklen_t len;
89         guint16 srcid;
90         guint16 dstid;
91         guint16 altid;
92         guint timeout;
93         guint numserv;
94         guint numresp;
95         gpointer resp;
96         gsize resplen;
97 };
98
99 static GSList *server_list = NULL;
100 static GSList *request_list = NULL;
101 static guint16 request_id = 0x0000;
102
103 static GIOChannel *listener_channel = NULL;
104 static guint listener_watch = 0;
105
106 static struct request_data *find_request(guint16 id)
107 {
108         GSList *list;
109
110         for (list = request_list; list; list = list->next) {
111                 struct request_data *req = list->data;
112
113                 if (req->dstid == id || req->altid == id)
114                         return req;
115         }
116
117         return NULL;
118 }
119
120 static struct server_data *find_server(const char *interface,
121                                         const char *domain, const char *server)
122 {
123         GSList *list;
124
125         DBG("interface %s server %s", interface, server);
126
127         for (list = server_list; list; list = list->next) {
128                 struct server_data *data = list->data;
129
130                 if (data->interface == NULL || data->server == NULL)
131                         continue;
132
133                 if (g_str_equal(data->interface, interface) == TRUE &&
134                                 g_str_equal(data->server, server) == TRUE) {
135                         if (domain == NULL) {
136                                 if (data->domain == NULL)
137                                         return data;
138                                 continue;
139                         }
140
141                         if (g_str_equal(data->domain, domain) == TRUE)
142                                 return data;
143                 }
144         }
145
146         return NULL;
147 }
148
149 static gboolean server_event(GIOChannel *channel, GIOCondition condition,
150                                                         gpointer user_data)
151 {
152         struct server_data *data = user_data;
153         struct request_data *req;
154         unsigned char buf[4096];
155         struct domain_hdr *hdr = (void *) &buf;
156         int sk, err, len;
157
158         if (condition & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) {
159                 connman_error("Error with server channel");
160                 data->watch = 0;
161                 return FALSE;
162         }
163
164         sk = g_io_channel_unix_get_fd(channel);
165
166         len = recv(sk, buf, sizeof(buf), 0);
167         if (len < 12)
168                 return TRUE;
169
170         DBG("Received %d bytes (id 0x%04x)", len, buf[0] | buf[1] << 8);
171
172         req = find_request(buf[0] | buf[1] << 8);
173         if (req == NULL)
174                 return TRUE;
175
176         DBG("id 0x%04x rcode %d", hdr->id, hdr->rcode);
177
178         buf[0] = req->srcid & 0xff;
179         buf[1] = req->srcid >> 8;
180
181         req->numresp++;
182
183         if (hdr->rcode == 0 || req->resp == NULL) {
184                 g_free(req->resp);
185                 req->resplen = 0;
186
187                 req->resp = g_try_malloc(len);
188                 if (req->resp == NULL)
189                         return TRUE;
190
191                 memcpy(req->resp, buf, len);
192                 req->resplen = len;
193         }
194
195         if (hdr->rcode > 0 && req->numresp < req->numserv)
196                 return TRUE;
197
198         if (req->timeout > 0)
199                 g_source_remove(req->timeout);
200
201         request_list = g_slist_remove(request_list, req);
202
203         sk = g_io_channel_unix_get_fd(listener_channel);
204
205         err = sendto(sk, req->resp, req->resplen, 0,
206                                 (struct sockaddr *) &req->sin, req->len);
207
208         g_free(req->resp);
209         g_free(req);
210
211         return TRUE;
212 }
213
214 static struct server_data *create_server(const char *interface,
215                                         const char *domain, const char *server)
216 {
217         struct server_data *data;
218         struct sockaddr_in sin;
219         int sk;
220
221         DBG("interface %s server %s", interface, server);
222
223         sk = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
224         if (sk < 0) {
225                 connman_error("Failed to create server %s socket", server);
226                 return NULL;
227         }
228
229         if (interface != NULL) {
230                 if (setsockopt(sk, SOL_SOCKET, SO_BINDTODEVICE,
231                                 interface, strlen(interface) + 1) < 0) {
232                         connman_error("Failed to bind server %s "
233                                                 "to interface %s",
234                                                         server, interface);
235                         close(sk);
236                         return NULL;
237                 }
238         }
239
240         memset(&sin, 0, sizeof(sin));
241         sin.sin_family = AF_INET;
242         sin.sin_port = htons(53);
243         sin.sin_addr.s_addr = inet_addr(server);
244
245         if (connect(sk, (struct sockaddr *) &sin, sizeof(sin)) < 0) {
246                 connman_error("Failed to connect server %s", server);
247                 close(sk);
248                 return NULL;
249         }
250
251         data = g_try_new0(struct server_data, 1);
252         if (data == NULL) {
253                 connman_error("Failed to allocate server %s data", server);
254                 close(sk);
255                 return NULL;
256         }
257
258         data->channel = g_io_channel_unix_new(sk);
259         if (data->channel == NULL) {
260                 connman_error("Failed to create server %s channel", server);
261                 close(sk);
262                 g_free(data);
263                 return NULL;
264         }
265
266         g_io_channel_set_close_on_unref(data->channel, TRUE);
267
268         data->watch = g_io_add_watch(data->channel, G_IO_IN,
269                                                 server_event, data);
270
271         data->interface = g_strdup(interface);
272         data->domain = g_strdup(domain);
273         data->server = g_strdup(server);
274
275         /* Enable new servers by default */
276         data->enabled = TRUE;
277
278         connman_info("Adding DNS server %s", data->server);
279
280         return data;
281 }
282
283 static void destroy_server(struct server_data *data)
284 {
285         DBG("interface %s server %s", data->interface, data->server);
286
287         if (data->watch > 0)
288                 g_source_remove(data->watch);
289
290         g_io_channel_unref(data->channel);
291
292         connman_info("Removing DNS server %s", data->server);
293
294         g_free(data->server);
295         g_free(data->domain);
296         g_free(data->interface);
297         g_free(data);
298 }
299
300 static int dnsproxy_append(const char *interface, const char *domain,
301                                                         const char *server)
302 {
303         struct server_data *data;
304
305         DBG("interface %s server %s", interface, server);
306
307         if (g_str_equal(server, "127.0.0.1") == TRUE)
308                 return -ENODEV;
309
310         data = create_server(interface, domain, server);
311         if (data == NULL)
312                 return -EIO;
313
314         server_list = g_slist_append(server_list, data);
315
316         return 0;
317 }
318
319 static int dnsproxy_remove(const char *interface, const char *domain,
320                                                         const char *server)
321 {
322         struct server_data *data;
323
324         DBG("interface %s server %s", interface, server);
325
326         if (g_str_equal(server, "127.0.0.1") == TRUE)
327                 return -ENODEV;
328
329         data = find_server(interface, domain, server);
330         if (data == NULL)
331                 return 0;
332
333         server_list = g_slist_remove(server_list, data);
334
335         destroy_server(data);
336
337         return 0;
338 }
339
340 static struct connman_resolver dnsproxy_resolver = {
341         .name           = "dnsproxy",
342         .priority       = CONNMAN_RESOLVER_PRIORITY_HIGH,
343         .append         = dnsproxy_append,
344         .remove         = dnsproxy_remove,
345 };
346
347 static void dnsproxy_offline_mode(connman_bool_t enabled)
348 {
349         GSList *list;
350
351         DBG("enabled %d", enabled);
352
353         for (list = server_list; list; list = list->next) {
354                 struct server_data *data = list->data;
355
356                 if (enabled == FALSE) {
357                         connman_info("Enabling DNS server %s", data->server);
358                         data->enabled = TRUE;
359                 } else {
360                         connman_info("Disabling DNS server %s", data->server);
361                         data->enabled = FALSE;
362                 }
363         }
364 }
365
366 static void dnsproxy_default_changed(struct connman_service *service)
367 {
368         GSList *list;
369         char *interface;
370
371         DBG("service %p", service);
372
373         if (service == NULL) {
374                 /* When no services are active, then disable DNS proxying */
375                 dnsproxy_offline_mode(TRUE);
376                 return;
377         }
378
379         interface = connman_service_get_interface(service);
380         if (interface == NULL)
381                 return;
382
383         for (list = server_list; list; list = list->next) {
384                 struct server_data *data = list->data;
385
386                 if (g_strcmp0(data->interface, interface) == 0) {
387                         connman_info("Enabling DNS server %s", data->server);
388                         data->enabled = TRUE;
389                 } else {
390                         connman_info("Disabling DNS server %s", data->server);
391                         data->enabled = FALSE;
392                 }
393         }
394
395         g_free(interface);
396 }
397
398 static struct connman_notifier dnsproxy_notifier = {
399         .name                   = "dnsproxy",
400         .default_changed        = dnsproxy_default_changed,
401         .offline_mode           = dnsproxy_offline_mode,
402 };
403
404 static unsigned char opt_edns0_type[2] = { 0x00, 0x29 };
405
406 static int parse_request(unsigned char *buf, int len,
407                                         char *name, unsigned int size)
408 {
409         struct domain_hdr *hdr = (void *) buf;
410         uint16_t qdcount = ntohs(hdr->qdcount);
411         uint16_t arcount = ntohs(hdr->arcount);
412         unsigned char *ptr;
413         char *last_label = NULL;
414         unsigned int remain, used = 0;
415
416         if (len < 12)
417                 return -EINVAL;
418
419         DBG("id 0x%04x qr %d opcode %d qdcount %d arcount %d",
420                                         hdr->id, hdr->qr, hdr->opcode,
421                                                         qdcount, arcount);
422
423         if (hdr->qr != 0 || qdcount != 1)
424                 return -EINVAL;
425
426         memset(name, 0, size);
427
428         ptr = buf + sizeof(struct domain_hdr);
429         remain = len - sizeof(struct domain_hdr);
430
431         while (remain > 0) {
432                 uint8_t len = *ptr;
433
434                 if (len == 0x00) {
435                         last_label = (char *) (ptr + 1);
436                         break;
437                 }
438
439                 if (used + len + 1 > size)
440                         return -ENOBUFS;
441
442                 strncat(name, (char *) (ptr + 1), len);
443                 strcat(name, ".");
444
445                 used += len + 1;
446
447                 ptr += len + 1;
448                 remain -= len + 1;
449         }
450
451         if (last_label && arcount && remain >= 9 && last_label[4] == 0 &&
452                                 !memcmp(last_label + 5, opt_edns0_type, 2)) {
453                 uint16_t edns0_bufsize;
454
455                 edns0_bufsize = last_label[7] << 8 | last_label[8];
456
457                 DBG("EDNS0 buffer size %u", edns0_bufsize);
458
459                 /* This is an evil hack until full TCP support has been
460                  * implemented.
461                  *
462                  * Somtimes the EDNS0 request gets send with a too-small
463                  * buffer size. Since glibc doesn't seem to crash when it
464                  * gets a response biffer then it requested, just bump
465                  * the buffer size up to 4KiB.
466                  */
467                 if (edns0_bufsize < 0x1000) {
468                         last_label[7] = 0x10;
469                         last_label[8] = 0x00;
470                 }
471         }
472
473         DBG("query %s", name);
474
475         return 0;
476 }
477
478 static void send_response(int sk, unsigned char *buf, int len,
479                                 const struct sockaddr *to, socklen_t tolen)
480 {
481         struct domain_hdr *hdr = (void *) buf;
482         int err;
483
484         if (len < 12)
485                 return;
486
487         DBG("id 0x%04x qr %d opcode %d", hdr->id, hdr->qr, hdr->opcode);
488
489         hdr->qr = 1;
490         hdr->rcode = 2;
491
492         hdr->ancount = 0;
493         hdr->nscount = 0;
494         hdr->arcount = 0;
495
496         err = sendto(sk, buf, len, 0, to, tolen);
497 }
498
499 static int append_query(unsigned char *buf, unsigned int size,
500                                 const char *query, const char *domain)
501 {
502         unsigned char *ptr = buf;
503         char *offset;
504
505         DBG("query %s domain %s", query, domain);
506
507         offset = (char *) query;
508         while (offset != NULL) {
509                 char *tmp;
510
511                 tmp = strchr(offset, '.');
512                 if (tmp == NULL) {
513                         if (strlen(offset) == 0)
514                                 break;
515                         *ptr = strlen(offset);
516                         memcpy(ptr + 1, offset, strlen(offset));
517                         ptr += strlen(offset) + 1;
518                         break;
519                 }
520
521                 *ptr = tmp - offset;
522                 memcpy(ptr + 1, offset, tmp - offset);
523                 ptr += tmp - offset + 1;
524
525                 offset = tmp + 1;
526         }
527
528         offset = (char *) domain;
529         while (offset != NULL) {
530                 char *tmp;
531
532                 tmp = strchr(offset, '.');
533                 if (tmp == NULL) {
534                         if (strlen(offset) == 0)
535                                 break;
536                         *ptr = strlen(offset);
537                         memcpy(ptr + 1, offset, strlen(offset));
538                         ptr += strlen(offset) + 1;
539                         break;
540                 }
541
542                 *ptr = tmp - offset;
543                 memcpy(ptr + 1, offset, tmp - offset);
544                 ptr += tmp - offset + 1;
545
546                 offset = tmp + 1;
547         }
548
549         *ptr++ = 0x00;
550
551         return ptr - buf;
552 }
553
554 static gboolean request_timeout(gpointer user_data)
555 {
556         struct request_data *req = user_data;
557
558         DBG("id 0x%04x", req->srcid);
559
560         request_list = g_slist_remove(request_list, req);
561
562         if (req->resplen > 0 && req->resp != NULL) {
563                 int sk, err;
564
565                 sk = g_io_channel_unix_get_fd(listener_channel);
566
567                 err = sendto(sk, req->resp, req->resplen, 0,
568                                 (struct sockaddr *) &req->sin, req->len);
569         }
570
571         g_free(req->resp);
572         g_free(req);
573
574         return FALSE;
575 }
576
577 static gboolean listener_event(GIOChannel *channel, GIOCondition condition,
578                                                         gpointer user_data)
579 {
580         GSList *list;
581         unsigned char buf[768];
582         char query[512];
583         struct request_data *req;
584         struct sockaddr_in sin;
585         socklen_t size = sizeof(sin);
586         int sk, err, len;
587
588         if (condition & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) {
589                 connman_error("Error with listener channel");
590                 listener_watch = 0;
591                 return FALSE;
592         }
593
594         sk = g_io_channel_unix_get_fd(channel);
595
596         memset(&sin, 0, sizeof(sin));
597         len = recvfrom(sk, buf, sizeof(buf), 0,
598                                         (struct sockaddr *) &sin, &size);
599         if (len < 2)
600                 return TRUE;
601
602         DBG("Received %d bytes (id 0x%04x)", len, buf[0] | buf[1] << 8);
603
604         err = parse_request(buf, len, query, sizeof(query));
605         if (err < 0 || g_slist_length(server_list) == 0) {
606                 send_response(sk, buf, len, (struct sockaddr *) &sin, size);
607                 return TRUE;
608         }
609
610         req = g_try_new0(struct request_data, 1);
611         if (req == NULL)
612                 return TRUE;
613
614         memcpy(&req->sin, &sin, sizeof(sin));
615         req->len = size;
616
617         request_id += 2;
618         if (request_id == 0x0000 || request_id == 0xffff)
619                 request_id += 2;
620
621         req->srcid = buf[0] | (buf[1] << 8);
622         req->dstid = request_id;
623         req->altid = request_id + 1;
624
625         buf[0] = req->dstid & 0xff;
626         buf[1] = req->dstid >> 8;
627
628         request_list = g_slist_append(request_list, req);
629
630         req->numserv = 0;
631         req->timeout = g_timeout_add_seconds(5, request_timeout, req);
632
633         for (list = server_list; list; list = list->next) {
634                 struct server_data *data = list->data;
635
636                 DBG("server %s domain %s enabled %d",
637                                 data->server, data->domain, data->enabled);
638
639                 if (data->enabled == FALSE)
640                         continue;
641
642                 sk = g_io_channel_unix_get_fd(data->channel);
643
644                 err = send(sk, buf, len, 0);
645
646                 req->numserv++;
647
648                 if (data->domain != NULL) {
649                         unsigned char alt[1024];
650                         struct domain_hdr *hdr = (void *) &alt;
651                         int altlen, domlen;
652
653                         domlen = strlen(data->domain) + 1;
654                         if (domlen < 5)
655                                 continue;
656
657                         alt[0] = req->altid & 0xff;
658                         alt[1] = req->altid >> 8;
659
660                         memcpy(alt + 2, buf + 2, 10);
661                         hdr->qdcount = htons(1);
662
663                         altlen = append_query(alt + 12, sizeof(alt) - 12,
664                                                         query, data->domain);
665                         if (altlen < 0)
666                                 continue;
667
668                         altlen += 12;
669
670                         memcpy(alt + altlen, buf + altlen - domlen,
671                                                         len - altlen + domlen);
672
673                         err = send(sk, alt, len + domlen + 1, 0);
674
675                         req->numserv++;
676                 }
677         }
678
679         return TRUE;
680 }
681
682 static int create_listener(void)
683 {
684         const char *ifname = "lo";
685         struct sockaddr_in sin;
686         int sk;
687
688         DBG("");
689
690         sk = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
691         if (sk < 0) {
692                 connman_error("Failed to create listener socket");
693                 return -EIO;
694         }
695
696         //setsockopt(sk, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
697         //setsockopt(sk, SOL_IP, IP_PKTINFO, &opt, sizeof(opt));
698
699         if (setsockopt(sk, SOL_SOCKET, SO_BINDTODEVICE,
700                                         ifname, strlen(ifname) + 1) < 0) {
701                 connman_error("Failed to bind listener interface");
702                 close(sk);
703                 return -EIO;
704         }
705
706         memset(&sin, 0, sizeof(sin));
707         sin.sin_family = AF_INET;
708         sin.sin_port = htons(53);
709         sin.sin_addr.s_addr = inet_addr("127.0.0.1");
710         //sin.sin_addr.s_addr = INADDR_ANY;
711
712         if (bind(sk, (struct sockaddr *) &sin, sizeof(sin)) < 0) {
713                 connman_error("Failed to bind listener socket");
714                 close(sk);
715                 return -EIO;
716         }
717
718         listener_channel = g_io_channel_unix_new(sk);
719         if (listener_channel == NULL) {
720                 connman_error("Failed to create listener channel");
721                 close(sk);
722                 return -EIO;
723         }
724
725         g_io_channel_set_close_on_unref(listener_channel, TRUE);
726
727         listener_watch = g_io_add_watch(listener_channel, G_IO_IN,
728                                                         listener_event, NULL);
729
730         connman_resolver_append("lo", NULL, "127.0.0.1");
731
732         return 0;
733 }
734
735 static void destroy_listener(void)
736 {
737         GSList *list;
738
739         DBG("");
740
741         connman_resolver_remove_all("lo");
742
743         if (listener_watch > 0)
744                 g_source_remove(listener_watch);
745
746         for (list = request_list; list; list = list->next) {
747                 struct request_data *req = list->data;
748
749                 DBG("Dropping request (id 0x%04x -> 0x%04x)",
750                                                 req->srcid, req->dstid);
751
752                 g_free(req->resp);
753                 g_free(req);
754                 list->data = NULL;
755         }
756
757         g_slist_free(request_list);
758         request_list = NULL;
759
760         g_io_channel_unref(listener_channel);
761 }
762
763 static int dnsproxy_init(void)
764 {
765         int err;
766
767         err = create_listener();
768         if (err < 0)
769                 return err;
770
771         err = connman_resolver_register(&dnsproxy_resolver);
772         if (err < 0)
773                 goto destroy;
774
775         err = connman_notifier_register(&dnsproxy_notifier);
776         if (err < 0)
777                 goto unregister;
778
779         return 0;
780
781 unregister:
782         connman_resolver_unregister(&dnsproxy_resolver);
783
784 destroy:
785         destroy_listener();
786
787         return err;
788 }
789
790 static void dnsproxy_exit(void)
791 {
792         connman_notifier_unregister(&dnsproxy_notifier);
793
794         connman_resolver_unregister(&dnsproxy_resolver);
795
796         destroy_listener();
797 }
798
799 CONNMAN_PLUGIN_DEFINE(dnsproxy, "DNS proxy resolver plugin", VERSION,
800                  CONNMAN_PLUGIN_PRIORITY_DEFAULT, dnsproxy_init, dnsproxy_exit)