Check for socket errors and cancel gracefully
[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         data = create_server(interface, server);
213         if (data == NULL)
214                 return -EIO;
215
216         server_list = g_slist_append(server_list, data);
217
218         return 0;
219 }
220
221 static int dnsproxy_remove(const char *interface, const char *domain,
222                                                         const char *server)
223 {
224         struct server_data *data;
225
226         DBG("interface %s server %s", interface, server);
227
228         data = find_server(interface, server);
229         if (data == NULL)
230                 return 0;
231
232         server_list = g_slist_remove(server_list, data);
233
234         destroy_server(data);
235
236         return 0;
237 }
238
239 static struct connman_resolver dnsproxy_resolver = {
240         .name           = "dnsproxy",
241         .priority       = CONNMAN_RESOLVER_PRIORITY_HIGH,
242         .append         = dnsproxy_append,
243         .remove         = dnsproxy_remove,
244 };
245
246 #if __BYTE_ORDER == __LITTLE_ENDIAN
247 struct domain_hdr {
248         uint16_t id;
249         uint8_t rd:1;
250         uint8_t tc:1;
251         uint8_t aa:1;
252         uint8_t opcode:4;
253         uint8_t qr:1;
254         uint8_t rcode:4;
255         uint8_t z:3;
256         uint8_t ra:1;
257         uint16_t qdcount;
258         uint16_t ancount;
259         uint16_t nscount;
260         uint16_t arcount;
261 } __attribute__ ((packed));
262 #elif __BYTE_ORDER == __BIG_ENDIAN
263 struct domain_hdr {
264         uint16_t id;
265         uint8_t qr:1;
266         uint8_t opcode:4;
267         uint8_t aa:1;
268         uint8_t tc:1;
269         uint8_t rd:1;
270         uint8_t ra:1;
271         uint8_t z:3;
272         uint8_t rcode:4;
273         uint16_t qdcount;
274         uint16_t ancount;
275         uint16_t nscount;
276         uint16_t arcount;
277 } __attribute__ ((packed));
278 #else
279 #error "Unknown byte order"
280 #endif
281
282 static void parse_request(unsigned char *buf, int len)
283 {
284         struct domain_hdr *hdr = (void *) buf;
285         uint16_t qdcount = ntohs(hdr->qdcount);
286         unsigned char *ptr;
287         char name[512];
288         unsigned int remain, used = 0;
289
290         if (len < 12)
291                 return;
292
293         DBG("id 0x%04x qr %d opcode %d qdcount %d",
294                                 hdr->id, hdr->qr, hdr->opcode, qdcount);
295
296         if (hdr->qr != 0 || qdcount != 1)
297                 return;
298
299         memset(name, 0, sizeof(name));
300
301         ptr = buf + 12;
302         remain = len - 12;
303
304         while (remain > 0) {
305                 uint8_t len = *ptr;
306
307                 if (len == 0x00)
308                         break;
309
310                 if (used + len + 1 > sizeof(name))
311                         return;
312
313                 strncat(name, (char *) (ptr + 1), len);
314                 strcat(name, ".");
315
316                 used += len + 1;
317
318                 ptr += len + 1;
319                 remain -= len + 1;
320         }
321
322         DBG("domain name %s", name);
323 }
324
325 static gboolean listener_event(GIOChannel *channel, GIOCondition condition,
326                                                         gpointer user_data)
327 {
328         GSList *list;
329         unsigned char buf[768];
330         struct request_data *req;
331         struct sockaddr_in sin;
332         socklen_t size = sizeof(sin);
333         int sk, err, len;
334
335         if (condition & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) {
336                 connman_error("Error with listener channel");
337                 listener_watch = 0;
338                 return FALSE;
339         }
340
341         sk = g_io_channel_unix_get_fd(channel);
342
343         memset(&sin, 0, sizeof(sin));
344         len = recvfrom(sk, buf, sizeof(buf), 0,
345                                         (struct sockaddr *) &sin, &size);
346         if (len < 2)
347                 return TRUE;
348
349         DBG("Received %d bytes (id 0x%04x)", len, buf[0] | buf[1] << 8);
350
351         parse_request(buf, len);
352
353         if (g_slist_length(server_list) == 0)
354                 return TRUE;
355
356         req = find_request(buf[0] | (buf[1] << 8));
357         if (req == NULL) {
358                 req = g_try_new0(struct request_data, 1);
359                 if (req == NULL)
360                         return TRUE;
361
362                 memcpy(&req->sin, &sin, sizeof(sin));
363                 req->len = size;
364                 req->id = buf[0] | (buf[1] << 8);
365
366                 request_list = g_slist_append(request_list, req);
367         } else {
368                 memcpy(&req->sin, &sin, sizeof(sin));
369                 req->len = size;
370         }
371
372         for (list = server_list; list; list = list->next) {
373                 struct server_data *data = list->data;
374
375                 sk = g_io_channel_unix_get_fd(data->channel);
376
377                 err = send(sk, buf, len, 0);
378         }
379
380         return TRUE;
381 }
382
383 static int create_listener(void)
384 {
385         const char *ifname = "lo";
386         struct sockaddr_in sin;
387         int sk;
388
389         DBG("");
390
391         sk = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
392         if (sk < 0) {
393                 connman_error("Failed to create listener socket");
394                 return -EIO;
395         }
396
397         //setsockopt(sk, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
398         //setsockopt(sk, SOL_IP, IP_PKTINFO, &opt, sizeof(opt));
399
400         if (setsockopt(sk, SOL_SOCKET, SO_BINDTODEVICE,
401                                         ifname, strlen(ifname) + 1) < 0) {
402                 connman_error("Failed to bind listener interface");
403                 close(sk);
404                 return -EIO;
405         }
406
407         memset(&sin, 0, sizeof(sin));
408         sin.sin_family = AF_INET;
409         sin.sin_port = htons(53);
410         sin.sin_addr.s_addr = inet_addr("127.0.0.1");
411         //sin.sin_addr.s_addr = INADDR_ANY;
412
413         if (bind(sk, (struct sockaddr *) &sin, sizeof(sin)) < 0) {
414                 connman_error("Failed to bind listener socket");
415                 close(sk);
416                 return -EIO;
417         }
418
419         listener_channel = g_io_channel_unix_new(sk);
420         if (listener_channel == NULL) {
421                 connman_error("Failed to create listener channel");
422                 close(sk);
423                 return -EIO;
424         }
425
426         g_io_channel_set_close_on_unref(listener_channel, TRUE);
427
428         listener_watch = g_io_add_watch(listener_channel, G_IO_IN,
429                                                         listener_event, NULL);
430
431         return 0;
432 }
433
434 static void destroy_listener(void)
435 {
436         GSList *list;
437
438         DBG("");
439
440         if (listener_watch > 0)
441                 g_source_remove(listener_watch);
442
443         for (list = request_list; list; list = list->next) {
444                 struct request_data *data = list->data;
445
446                 DBG("Dropping request (id 0x%04x)", data->id);
447
448                 g_free(data);
449                 list->data = NULL;
450         }
451
452         g_slist_free(request_list);
453         request_list = NULL;
454
455         g_io_channel_unref(listener_channel);
456 }
457
458 static int dnsproxy_init(void)
459 {
460         int err;
461
462         err = create_listener();
463         if (err < 0)
464                 return err;
465
466         err = connman_resolver_register(&dnsproxy_resolver);
467         if (err < 0)
468                 destroy_listener();
469
470         return err;
471 }
472
473 static void dnsproxy_exit(void)
474 {
475         destroy_listener();
476
477         connman_resolver_unregister(&dnsproxy_resolver);
478 }
479
480 CONNMAN_PLUGIN_DEFINE(dnsproxy, "DNS proxy resolver plugin", VERSION,
481                  CONNMAN_PLUGIN_PRIORITY_DEFAULT, dnsproxy_init, dnsproxy_exit)