Make sure entry for 127.0.0.1 is written to /etc/resolv.conf
[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 struct server_data {
41         char *interface;
42         char *server;
43         GIOChannel *channel;
44         guint watch;
45 };
46
47 struct request_data {
48         struct sockaddr_in sin;
49         socklen_t len;
50         guint16 id;
51 };
52
53 static GSList *server_list = NULL;
54 static GSList *request_list = NULL;
55
56 static GIOChannel *listener_channel = NULL;
57 static guint listener_watch = 0;
58
59 static struct request_data *find_request(guint16 id)
60 {
61         GSList *list;
62
63         for (list = request_list; list; list = list->next) {
64                 struct request_data *data = list->data;
65
66                 if (data->id == id)
67                         return data;
68         }
69
70         return NULL;
71 }
72
73 static struct server_data *find_server(const char *interface,
74                                                         const char *server)
75 {
76         GSList *list;
77
78         DBG("interface %s server %s", interface, server);
79
80         for (list = server_list; list; list = list->next) {
81                 struct server_data *data = list->data;
82
83                 if (data->interface == NULL || data->server == NULL)
84                         continue;
85
86                 if (g_str_equal(data->interface, interface) == TRUE &&
87                                 g_str_equal(data->server, server) == TRUE)
88                         return data;
89         }
90
91         return NULL;
92 }
93
94 static gboolean server_event(GIOChannel *channel, GIOCondition condition,
95                                                         gpointer user_data)
96 {
97         struct server_data *data = user_data;
98         struct request_data *req;
99         unsigned char buf[768];
100         int sk, err, len;
101
102         if (condition & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) {
103                 connman_error("Error with server channel");
104                 data->watch = 0;
105                 return FALSE;
106         }
107
108         sk = g_io_channel_unix_get_fd(channel);
109
110         len = recv(sk, buf, sizeof(buf), 0);
111         if (len < 2)
112                 return TRUE;
113
114         DBG("Received %d bytes (id 0x%04x)", len, buf[0] | buf[1] << 8);
115
116         req = find_request(buf[0] | buf[1] << 8);
117         if (req == NULL)
118                 return TRUE;
119
120         request_list = g_slist_remove(request_list, req);
121
122         sk = g_io_channel_unix_get_fd(listener_channel);
123
124         err = sendto(sk, buf, len, 0, (struct sockaddr *) &req->sin, req->len);
125
126         g_free(req);
127
128         return TRUE;
129 }
130
131 static struct server_data *create_server(const char *interface,
132                                                         const char *server)
133 {
134         struct server_data *data;
135         struct sockaddr_in sin;
136         int sk;
137
138         DBG("interface %s server %s", interface, server);
139
140         sk = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
141         if (sk < 0) {
142                 connman_error("Failed to create server %s socket", server);
143                 return NULL;
144         }
145
146         if (setsockopt(sk, SOL_SOCKET, SO_BINDTODEVICE,
147                                 interface, strlen(interface) + 1) < 0) {
148                 connman_error("Failed to bind server %s to interface %s",
149                                                         server, interface);
150                 close(sk);
151                 return NULL;
152         }
153
154         memset(&sin, 0, sizeof(sin));
155         sin.sin_family = AF_INET;
156         sin.sin_port = htons(53);
157         sin.sin_addr.s_addr = inet_addr(server);
158
159         if (connect(sk, (struct sockaddr *) &sin, sizeof(sin)) < 0) {
160                 connman_error("Failed to connect server %s", server);
161                 close(sk);
162                 return NULL;
163         }
164
165         data = g_try_new0(struct server_data, 1);
166         if (data == NULL) {
167                 connman_error("Failed to allocate server %s data", server);
168                 close(sk);
169                 return NULL;
170         }
171
172         data->channel = g_io_channel_unix_new(sk);
173         if (data->channel == NULL) {
174                 connman_error("Failed to create server %s channel", server);
175                 close(sk);
176                 g_free(data);
177                 return NULL;
178         }
179
180         g_io_channel_set_close_on_unref(data->channel, TRUE);
181
182         data->watch = g_io_add_watch(data->channel, G_IO_IN,
183                                                         server_event, data);
184
185         data->interface = g_strdup(interface);
186         data->server = g_strdup(server);
187
188         return data;
189 }
190
191 static void destroy_server(struct server_data *data)
192 {
193         DBG("interface %s server %s", data->interface, data->server);
194
195         if (data->watch > 0)
196                 g_source_remove(data->watch);
197
198         g_io_channel_unref(data->channel);
199
200         g_free(data->interface);
201         g_free(data->server);
202         g_free(data);
203 }
204
205 static int dnsproxy_append(const char *interface, const char *domain,
206                                                         const char *server)
207 {
208         struct server_data *data;
209
210         DBG("interface %s server %s", interface, server);
211
212         if (g_str_equal(server, "127.0.0.1") == TRUE)
213                 return -ENODEV;
214
215         data = create_server(interface, server);
216         if (data == NULL)
217                 return -EIO;
218
219         server_list = g_slist_append(server_list, data);
220
221         return 0;
222 }
223
224 static int dnsproxy_remove(const char *interface, const char *domain,
225                                                         const char *server)
226 {
227         struct server_data *data;
228
229         DBG("interface %s server %s", interface, server);
230
231         if (g_str_equal(server, "127.0.0.1") == TRUE)
232                 return -ENODEV;
233
234         data = find_server(interface, server);
235         if (data == NULL)
236                 return 0;
237
238         server_list = g_slist_remove(server_list, data);
239
240         destroy_server(data);
241
242         return 0;
243 }
244
245 static struct connman_resolver dnsproxy_resolver = {
246         .name           = "dnsproxy",
247         .priority       = CONNMAN_RESOLVER_PRIORITY_HIGH,
248         .append         = dnsproxy_append,
249         .remove         = dnsproxy_remove,
250 };
251
252 #if __BYTE_ORDER == __LITTLE_ENDIAN
253 struct domain_hdr {
254         uint16_t id;
255         uint8_t rd:1;
256         uint8_t tc:1;
257         uint8_t aa:1;
258         uint8_t opcode:4;
259         uint8_t qr:1;
260         uint8_t rcode:4;
261         uint8_t z:3;
262         uint8_t ra:1;
263         uint16_t qdcount;
264         uint16_t ancount;
265         uint16_t nscount;
266         uint16_t arcount;
267 } __attribute__ ((packed));
268 #elif __BYTE_ORDER == __BIG_ENDIAN
269 struct domain_hdr {
270         uint16_t id;
271         uint8_t qr:1;
272         uint8_t opcode:4;
273         uint8_t aa:1;
274         uint8_t tc:1;
275         uint8_t rd:1;
276         uint8_t ra:1;
277         uint8_t z:3;
278         uint8_t rcode:4;
279         uint16_t qdcount;
280         uint16_t ancount;
281         uint16_t nscount;
282         uint16_t arcount;
283 } __attribute__ ((packed));
284 #else
285 #error "Unknown byte order"
286 #endif
287
288 static void parse_request(unsigned char *buf, int len)
289 {
290         struct domain_hdr *hdr = (void *) buf;
291         uint16_t qdcount = ntohs(hdr->qdcount);
292         unsigned char *ptr;
293         char name[512];
294         unsigned int remain, used = 0;
295
296         if (len < 12)
297                 return;
298
299         DBG("id 0x%04x qr %d opcode %d qdcount %d",
300                                 hdr->id, hdr->qr, hdr->opcode, qdcount);
301
302         if (hdr->qr != 0 || qdcount != 1)
303                 return;
304
305         memset(name, 0, sizeof(name));
306
307         ptr = buf + 12;
308         remain = len - 12;
309
310         while (remain > 0) {
311                 uint8_t len = *ptr;
312
313                 if (len == 0x00)
314                         break;
315
316                 if (used + len + 1 > sizeof(name))
317                         return;
318
319                 strncat(name, (char *) (ptr + 1), len);
320                 strcat(name, ".");
321
322                 used += len + 1;
323
324                 ptr += len + 1;
325                 remain -= len + 1;
326         }
327
328         DBG("domain name %s", name);
329 }
330
331 static gboolean listener_event(GIOChannel *channel, GIOCondition condition,
332                                                         gpointer user_data)
333 {
334         GSList *list;
335         unsigned char buf[768];
336         struct request_data *req;
337         struct sockaddr_in sin;
338         socklen_t size = sizeof(sin);
339         int sk, err, len;
340
341         if (condition & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) {
342                 connman_error("Error with listener channel");
343                 listener_watch = 0;
344                 return FALSE;
345         }
346
347         sk = g_io_channel_unix_get_fd(channel);
348
349         memset(&sin, 0, sizeof(sin));
350         len = recvfrom(sk, buf, sizeof(buf), 0,
351                                         (struct sockaddr *) &sin, &size);
352         if (len < 2)
353                 return TRUE;
354
355         DBG("Received %d bytes (id 0x%04x)", len, buf[0] | buf[1] << 8);
356
357         parse_request(buf, len);
358
359         if (g_slist_length(server_list) == 0)
360                 return TRUE;
361
362         req = find_request(buf[0] | (buf[1] << 8));
363         if (req == NULL) {
364                 req = g_try_new0(struct request_data, 1);
365                 if (req == NULL)
366                         return TRUE;
367
368                 memcpy(&req->sin, &sin, sizeof(sin));
369                 req->len = size;
370                 req->id = buf[0] | (buf[1] << 8);
371
372                 request_list = g_slist_append(request_list, req);
373         } else {
374                 memcpy(&req->sin, &sin, sizeof(sin));
375                 req->len = size;
376         }
377
378         for (list = server_list; list; list = list->next) {
379                 struct server_data *data = list->data;
380
381                 sk = g_io_channel_unix_get_fd(data->channel);
382
383                 err = send(sk, buf, len, 0);
384         }
385
386         return TRUE;
387 }
388
389 static int create_listener(void)
390 {
391         const char *ifname = "lo";
392         struct sockaddr_in sin;
393         int sk;
394
395         DBG("");
396
397         sk = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
398         if (sk < 0) {
399                 connman_error("Failed to create listener socket");
400                 return -EIO;
401         }
402
403         //setsockopt(sk, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
404         //setsockopt(sk, SOL_IP, IP_PKTINFO, &opt, sizeof(opt));
405
406         if (setsockopt(sk, SOL_SOCKET, SO_BINDTODEVICE,
407                                         ifname, strlen(ifname) + 1) < 0) {
408                 connman_error("Failed to bind listener interface");
409                 close(sk);
410                 return -EIO;
411         }
412
413         memset(&sin, 0, sizeof(sin));
414         sin.sin_family = AF_INET;
415         sin.sin_port = htons(53);
416         sin.sin_addr.s_addr = inet_addr("127.0.0.1");
417         //sin.sin_addr.s_addr = INADDR_ANY;
418
419         if (bind(sk, (struct sockaddr *) &sin, sizeof(sin)) < 0) {
420                 connman_error("Failed to bind listener socket");
421                 close(sk);
422                 return -EIO;
423         }
424
425         listener_channel = g_io_channel_unix_new(sk);
426         if (listener_channel == NULL) {
427                 connman_error("Failed to create listener channel");
428                 close(sk);
429                 return -EIO;
430         }
431
432         g_io_channel_set_close_on_unref(listener_channel, TRUE);
433
434         listener_watch = g_io_add_watch(listener_channel, G_IO_IN,
435                                                         listener_event, NULL);
436
437         connman_resolver_append("lo", NULL, "127.0.0.1");
438
439         return 0;
440 }
441
442 static void destroy_listener(void)
443 {
444         GSList *list;
445
446         DBG("");
447
448         connman_resolver_remove_all("lo");
449
450         if (listener_watch > 0)
451                 g_source_remove(listener_watch);
452
453         for (list = request_list; list; list = list->next) {
454                 struct request_data *data = list->data;
455
456                 DBG("Dropping request (id 0x%04x)", data->id);
457
458                 g_free(data);
459                 list->data = NULL;
460         }
461
462         g_slist_free(request_list);
463         request_list = NULL;
464
465         g_io_channel_unref(listener_channel);
466 }
467
468 static int dnsproxy_init(void)
469 {
470         int err;
471
472         err = create_listener();
473         if (err < 0)
474                 return err;
475
476         err = connman_resolver_register(&dnsproxy_resolver);
477         if (err < 0)
478                 destroy_listener();
479
480         return err;
481 }
482
483 static void dnsproxy_exit(void)
484 {
485         destroy_listener();
486
487         connman_resolver_unregister(&dnsproxy_resolver);
488 }
489
490 CONNMAN_PLUGIN_DEFINE(dnsproxy, "DNS proxy resolver plugin", VERSION,
491                  CONNMAN_PLUGIN_PRIORITY_DEFAULT, dnsproxy_init, dnsproxy_exit)