Remove obsolete file.
[connman] / plugins / dnsproxy.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2007-2009  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/log.h>
37
38 #include <glib.h>
39
40 #if __BYTE_ORDER == __LITTLE_ENDIAN
41 struct domain_hdr {
42         uint16_t id;
43         uint8_t rd:1;
44         uint8_t tc:1;
45         uint8_t aa:1;
46         uint8_t opcode:4;
47         uint8_t qr:1;
48         uint8_t rcode:4;
49         uint8_t z:3;
50         uint8_t ra:1;
51         uint16_t qdcount;
52         uint16_t ancount;
53         uint16_t nscount;
54         uint16_t arcount;
55 } __attribute__ ((packed));
56 #elif __BYTE_ORDER == __BIG_ENDIAN
57 struct domain_hdr {
58         uint16_t id;
59         uint8_t qr:1;
60         uint8_t opcode:4;
61         uint8_t aa:1;
62         uint8_t tc:1;
63         uint8_t rd:1;
64         uint8_t ra:1;
65         uint8_t z:3;
66         uint8_t rcode:4;
67         uint16_t qdcount;
68         uint16_t ancount;
69         uint16_t nscount;
70         uint16_t arcount;
71 } __attribute__ ((packed));
72 #else
73 #error "Unknown byte order"
74 #endif
75
76 struct server_data {
77         char *interface;
78         char *domain;
79         char *server;
80         GIOChannel *channel;
81         guint watch;
82 };
83
84 struct request_data {
85         struct sockaddr_in sin;
86         socklen_t len;
87         guint16 srcid;
88         guint16 dstid;
89         guint16 altid;
90         guint timeout;
91         guint numserv;
92         guint numresp;
93         gpointer resp;
94         gsize resplen;
95 };
96
97 static GSList *server_list = NULL;
98 static GSList *request_list = NULL;
99 static guint16 request_id = 0x0000;
100
101 static GIOChannel *listener_channel = NULL;
102 static guint listener_watch = 0;
103
104 static struct request_data *find_request(guint16 id)
105 {
106         GSList *list;
107
108         for (list = request_list; list; list = list->next) {
109                 struct request_data *req = list->data;
110
111                 if (req->dstid == id || req->altid == id)
112                         return req;
113         }
114
115         return NULL;
116 }
117
118 static struct server_data *find_server(const char *interface,
119                                         const char *domain, const char *server)
120 {
121         GSList *list;
122
123         DBG("interface %s server %s", interface, server);
124
125         for (list = server_list; list; list = list->next) {
126                 struct server_data *data = list->data;
127
128                 if (data->interface == NULL || data->server == NULL)
129                         continue;
130
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)
135                                         return data;
136                                 continue;
137                         }
138
139                         if (g_str_equal(data->domain, domain) == TRUE)
140                                 return data;
141                 }
142         }
143
144         return NULL;
145 }
146
147 static gboolean server_event(GIOChannel *channel, GIOCondition condition,
148                                                         gpointer user_data)
149 {
150         struct server_data *data = user_data;
151         struct request_data *req;
152         unsigned char buf[768];
153         struct domain_hdr *hdr = (void *) &buf;
154         int sk, err, len;
155
156         if (condition & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) {
157                 connman_error("Error with server channel");
158                 data->watch = 0;
159                 return FALSE;
160         }
161
162         sk = g_io_channel_unix_get_fd(channel);
163
164         len = recv(sk, buf, sizeof(buf), 0);
165         if (len < 12)
166                 return TRUE;
167
168         DBG("Received %d bytes (id 0x%04x)", len, buf[0] | buf[1] << 8);
169
170         req = find_request(buf[0] | buf[1] << 8);
171         if (req == NULL)
172                 return TRUE;
173
174         DBG("id 0x%04x rcode %d", hdr->id, hdr->rcode);
175
176         buf[0] = req->srcid & 0xff;
177         buf[1] = req->srcid >> 8;
178
179         req->numresp++;
180
181         if (hdr->rcode == 0 || req->resp == NULL) {
182                 g_free(req->resp);
183                 req->resplen = 0;
184
185                 req->resp = g_try_malloc(len);
186                 if (req->resp == NULL)
187                         return TRUE;
188
189                 memcpy(req->resp, buf, len);
190                 req->resplen = len;
191         }
192
193         if (hdr->rcode > 0 && req->numresp < req->numserv)
194                 return TRUE;
195
196         if (req->timeout > 0)
197                 g_source_remove(req->timeout);
198
199         request_list = g_slist_remove(request_list, req);
200
201         sk = g_io_channel_unix_get_fd(listener_channel);
202
203         err = sendto(sk, req->resp, req->resplen, 0,
204                                 (struct sockaddr *) &req->sin, req->len);
205
206         g_free(req->resp);
207         g_free(req);
208
209         return TRUE;
210 }
211
212 static struct server_data *create_server(const char *interface,
213                                         const char *domain, const char *server)
214 {
215         struct server_data *data;
216         struct sockaddr_in sin;
217         int sk;
218
219         DBG("interface %s server %s", interface, server);
220
221         sk = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
222         if (sk < 0) {
223                 connman_error("Failed to create server %s socket", server);
224                 return NULL;
225         }
226
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",
230                                                         server, interface);
231                 close(sk);
232                 return NULL;
233         }
234
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);
239
240         if (connect(sk, (struct sockaddr *) &sin, sizeof(sin)) < 0) {
241                 connman_error("Failed to connect server %s", server);
242                 close(sk);
243                 return NULL;
244         }
245
246         data = g_try_new0(struct server_data, 1);
247         if (data == NULL) {
248                 connman_error("Failed to allocate server %s data", server);
249                 close(sk);
250                 return NULL;
251         }
252
253         data->channel = g_io_channel_unix_new(sk);
254         if (data->channel == NULL) {
255                 connman_error("Failed to create server %s channel", server);
256                 close(sk);
257                 g_free(data);
258                 return NULL;
259         }
260
261         g_io_channel_set_close_on_unref(data->channel, TRUE);
262
263         data->watch = g_io_add_watch(data->channel, G_IO_IN,
264                                                         server_event, data);
265
266         data->interface = g_strdup(interface);
267         data->domain = g_strdup(domain);
268         data->server = g_strdup(server);
269
270         return data;
271 }
272
273 static void destroy_server(struct server_data *data)
274 {
275         DBG("interface %s server %s", data->interface, data->server);
276
277         if (data->watch > 0)
278                 g_source_remove(data->watch);
279
280         g_io_channel_unref(data->channel);
281
282         g_free(data->server);
283         g_free(data->domain);
284         g_free(data->interface);
285         g_free(data);
286 }
287
288 static int dnsproxy_append(const char *interface, const char *domain,
289                                                         const char *server)
290 {
291         struct server_data *data;
292
293         DBG("interface %s server %s", interface, server);
294
295         if (g_str_equal(server, "127.0.0.1") == TRUE)
296                 return -ENODEV;
297
298         data = create_server(interface, domain, server);
299         if (data == NULL)
300                 return -EIO;
301
302         server_list = g_slist_append(server_list, data);
303
304         return 0;
305 }
306
307 static int dnsproxy_remove(const char *interface, const char *domain,
308                                                         const char *server)
309 {
310         struct server_data *data;
311
312         DBG("interface %s server %s", interface, server);
313
314         if (g_str_equal(server, "127.0.0.1") == TRUE)
315                 return -ENODEV;
316
317         data = find_server(interface, domain, server);
318         if (data == NULL)
319                 return 0;
320
321         server_list = g_slist_remove(server_list, data);
322
323         destroy_server(data);
324
325         return 0;
326 }
327
328 static struct connman_resolver dnsproxy_resolver = {
329         .name           = "dnsproxy",
330         .priority       = CONNMAN_RESOLVER_PRIORITY_HIGH,
331         .append         = dnsproxy_append,
332         .remove         = dnsproxy_remove,
333 };
334
335 static int parse_request(unsigned char *buf, int len,
336                                         char *name, unsigned int size)
337 {
338         struct domain_hdr *hdr = (void *) buf;
339         uint16_t qdcount = ntohs(hdr->qdcount);
340         unsigned char *ptr;
341         char *last_label = NULL;
342         int label_count = 0;
343         unsigned int remain, used = 0;
344
345         if (len < 12)
346                 return -EINVAL;
347
348         DBG("id 0x%04x qr %d opcode %d qdcount %d",
349                                 hdr->id, hdr->qr, hdr->opcode, qdcount);
350
351         if (hdr->qr != 0 || qdcount != 1)
352                 return -EINVAL;
353
354         memset(name, 0, size);
355
356         ptr = buf + 12;
357         remain = len - 12;
358
359         while (remain > 0) {
360                 uint8_t len = *ptr;
361
362                 if (len == 0x00) {
363                         if (label_count > 0)
364                                 last_label = (char *) (ptr + 1);
365                         break;
366                 }
367
368                 label_count++;
369
370                 if (used + len + 1 > size)
371                         return -ENOBUFS;
372
373                 strncat(name, (char *) (ptr + 1), len);
374                 strcat(name, ".");
375
376                 used += len + 1;
377
378                 ptr += len + 1;
379                 remain -= len + 1;
380         }
381
382         DBG("query %s (%d labels)", name, label_count);
383
384         return 0;
385 }
386
387 static void send_response(int sk, unsigned char *buf, int len,
388                                 const struct sockaddr *to, socklen_t tolen)
389 {
390         struct domain_hdr *hdr = (void *) buf;
391         int err;
392
393         if (len < 12)
394                 return;
395
396         DBG("id 0x%04x qr %d opcode %d", hdr->id, hdr->qr, hdr->opcode);
397
398         hdr->qr = 1;
399         hdr->rcode = 2;
400
401         hdr->ancount = 0;
402         hdr->nscount = 0;
403         hdr->arcount = 0;
404
405         err = sendto(sk, buf, len, 0, to, tolen);
406 }
407
408 static int append_query(unsigned char *buf, unsigned int size,
409                                 const char *query, const char *domain)
410 {
411         unsigned char *ptr = buf;
412         char *offset;
413
414         DBG("query %s domain %s", query, domain);
415
416         offset = (char *) query;
417         while (offset != NULL) {
418                 char *tmp;
419
420                 tmp = strchr(offset, '.');
421                 if (tmp == NULL) {
422                         if (strlen(offset) == 0)
423                                 break;
424                         *ptr = strlen(offset);
425                         memcpy(ptr + 1, offset, strlen(offset));
426                         ptr += strlen(offset) + 1;
427                         break;
428                 }
429
430                 *ptr = tmp - offset;
431                 memcpy(ptr + 1, offset, tmp - offset);
432                 ptr += tmp - offset + 1;
433
434                 offset = tmp + 1;
435         }
436
437         offset = (char *) domain;
438         while (offset != NULL) {
439                 char *tmp;
440
441                 tmp = strchr(offset, '.');
442                 if (tmp == NULL) {
443                         if (strlen(offset) == 0)
444                                 break;
445                         *ptr = strlen(offset);
446                         memcpy(ptr + 1, offset, strlen(offset));
447                         ptr += strlen(offset) + 1;
448                         break;
449                 }
450
451                 *ptr = tmp - offset;
452                 memcpy(ptr + 1, offset, tmp - offset);
453                 ptr += tmp - offset + 1;
454
455                 offset = tmp + 1;
456         }
457
458         *ptr++ = 0x00;
459
460         return ptr - buf;
461 }
462
463 static gboolean request_timeout(gpointer user_data)
464 {
465         struct request_data *req = user_data;
466
467         DBG("id 0x%04x", req->srcid);
468
469         request_list = g_slist_remove(request_list, req);
470
471         if (req->resplen > 0 && req->resp != NULL) {
472                 int sk, err;
473
474                 sk = g_io_channel_unix_get_fd(listener_channel);
475
476                 err = sendto(sk, req->resp, req->resplen, 0,
477                                 (struct sockaddr *) &req->sin, req->len);
478         }
479
480         g_free(req->resp);
481         g_free(req);
482
483         return FALSE;
484 }
485
486 static gboolean listener_event(GIOChannel *channel, GIOCondition condition,
487                                                         gpointer user_data)
488 {
489         GSList *list;
490         unsigned char buf[768];
491         char query[512];
492         struct request_data *req;
493         struct sockaddr_in sin;
494         socklen_t size = sizeof(sin);
495         int sk, err, len;
496
497         if (condition & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) {
498                 connman_error("Error with listener channel");
499                 listener_watch = 0;
500                 return FALSE;
501         }
502
503         sk = g_io_channel_unix_get_fd(channel);
504
505         memset(&sin, 0, sizeof(sin));
506         len = recvfrom(sk, buf, sizeof(buf), 0,
507                                         (struct sockaddr *) &sin, &size);
508         if (len < 2)
509                 return TRUE;
510
511         DBG("Received %d bytes (id 0x%04x)", len, buf[0] | buf[1] << 8);
512
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);
516                 return TRUE;
517         }
518
519         req = g_try_new0(struct request_data, 1);
520         if (req == NULL)
521                 return TRUE;
522
523         memcpy(&req->sin, &sin, sizeof(sin));
524         req->len = size;
525
526         request_id += 2;
527         if (request_id == 0x0000 || request_id == 0xffff)
528                 request_id += 2;
529
530         req->srcid = buf[0] | (buf[1] << 8);
531         req->dstid = request_id;
532         req->altid = request_id + 1;
533
534         buf[0] = req->dstid & 0xff;
535         buf[1] = req->dstid >> 8;
536
537         request_list = g_slist_append(request_list, req);
538
539         req->numserv = 0;
540         req->timeout = g_timeout_add_seconds(5, request_timeout, req);
541
542         for (list = server_list; list; list = list->next) {
543                 struct server_data *data = list->data;
544
545                 DBG("server %s domain %s", data->server, data->domain);
546
547                 sk = g_io_channel_unix_get_fd(data->channel);
548
549                 err = send(sk, buf, len, 0);
550
551                 req->numserv++;
552
553                 if (data->domain != NULL) {
554                         unsigned char alt[1024];
555                         struct domain_hdr *hdr = (void *) &alt;
556                         int altlen;
557
558                         alt[0] = req->altid & 0xff;
559                         alt[1] = req->altid >> 8;
560
561                         memcpy(alt + 2, buf + 2, 10);
562                         hdr->qdcount = htons(1);
563
564                         altlen = append_query(alt + 12, sizeof(alt) - 12,
565                                                         query, data->domain);
566                         if (altlen < 0)
567                                 continue;
568
569                         alt[altlen + 12] = 0x00;
570                         alt[altlen + 13] = 0x01;
571                         alt[altlen + 14] = 0x00;
572                         alt[altlen + 15] = 0x01;
573
574                         err = send(sk, alt, altlen + 12 + 4, 0);
575
576                         req->numserv++;
577                 }
578         }
579
580         return TRUE;
581 }
582
583 static int create_listener(void)
584 {
585         const char *ifname = "lo";
586         struct sockaddr_in sin;
587         int sk;
588
589         DBG("");
590
591         sk = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
592         if (sk < 0) {
593                 connman_error("Failed to create listener socket");
594                 return -EIO;
595         }
596
597         //setsockopt(sk, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
598         //setsockopt(sk, SOL_IP, IP_PKTINFO, &opt, sizeof(opt));
599
600         if (setsockopt(sk, SOL_SOCKET, SO_BINDTODEVICE,
601                                         ifname, strlen(ifname) + 1) < 0) {
602                 connman_error("Failed to bind listener interface");
603                 close(sk);
604                 return -EIO;
605         }
606
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;
612
613         if (bind(sk, (struct sockaddr *) &sin, sizeof(sin)) < 0) {
614                 connman_error("Failed to bind listener socket");
615                 close(sk);
616                 return -EIO;
617         }
618
619         listener_channel = g_io_channel_unix_new(sk);
620         if (listener_channel == NULL) {
621                 connman_error("Failed to create listener channel");
622                 close(sk);
623                 return -EIO;
624         }
625
626         g_io_channel_set_close_on_unref(listener_channel, TRUE);
627
628         listener_watch = g_io_add_watch(listener_channel, G_IO_IN,
629                                                         listener_event, NULL);
630
631         connman_resolver_append("lo", NULL, "127.0.0.1");
632
633         return 0;
634 }
635
636 static void destroy_listener(void)
637 {
638         GSList *list;
639
640         DBG("");
641
642         connman_resolver_remove_all("lo");
643
644         if (listener_watch > 0)
645                 g_source_remove(listener_watch);
646
647         for (list = request_list; list; list = list->next) {
648                 struct request_data *req = list->data;
649
650                 DBG("Dropping request (id 0x%04x -> 0x%04x)",
651                                                 req->srcid, req->dstid);
652
653                 g_free(req->resp);
654                 g_free(req);
655                 list->data = NULL;
656         }
657
658         g_slist_free(request_list);
659         request_list = NULL;
660
661         g_io_channel_unref(listener_channel);
662 }
663
664 static int dnsproxy_init(void)
665 {
666         int err;
667
668         err = create_listener();
669         if (err < 0)
670                 return err;
671
672         err = connman_resolver_register(&dnsproxy_resolver);
673         if (err < 0)
674                 destroy_listener();
675
676         return err;
677 }
678
679 static void dnsproxy_exit(void)
680 {
681         destroy_listener();
682
683         connman_resolver_unregister(&dnsproxy_resolver);
684 }
685
686 CONNMAN_PLUGIN_DEFINE(dnsproxy, "DNS proxy resolver plugin", VERSION,
687                  CONNMAN_PLUGIN_PRIORITY_DEFAULT, dnsproxy_init, dnsproxy_exit)