[svn-inject] Applying Debian modifications to trunk
[debian/iodine.git] / dns.c
1 /*
2  * Copyright (c) 2006 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
3  *
4  * Permission to use, copy, modify, and distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16
17 #include <sys/types.h>
18 #include <sys/socket.h>
19 #include <netinet/in.h>
20 #include <arpa/inet.h>
21 #include <arpa/nameser.h>
22 #ifdef DARWIN
23 #include <arpa/nameser8_compat.h>
24 #endif
25 #include <netdb.h>
26 #include <time.h>
27 #include <err.h>
28 #include <stdio.h>
29 #include <stdint.h>
30 #include <stdlib.h>
31 #include <stdint.h>
32 #include <unistd.h>
33 #include <string.h>
34 #include <ctype.h>
35
36 #include "structs.h"
37 #include "dns.h"
38 #include "encoding.h"
39 #include "read.h"
40
41 // For FreeBSD
42 #ifndef MIN
43 #define MIN(a,b) ((a)<(b)?(a):(b))
44 #endif
45
46
47 static int dns_write(int, int, char *, int, char);
48 static void dns_query(int, int, char *, int);
49
50 struct sockaddr_in peer;
51 char topdomain[256];
52
53 // Current IP packet
54 char activepacket[4096];
55 int lastlen;
56 int packetpos;
57 int packetlen;
58 uint16_t chunkid;
59
60 uint16_t pingid;
61
62
63 int 
64 open_dns(const char *domain, int localport, in_addr_t listen_ip) 
65 {
66         int fd;
67         int flag;
68         struct sockaddr_in addr;
69
70         memset(&addr, 0, sizeof(addr));
71         addr.sin_family = AF_INET;
72         addr.sin_port = htons(localport);
73         /* listen_ip already in network byte order from inet_addr, or 0 */
74         addr.sin_addr.s_addr = listen_ip; 
75
76         fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
77         if(fd < 0) {
78                 warn("socket");
79                 return -1;
80         }
81
82         flag = 1;
83 #ifdef SO_REUSEPORT
84         setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &flag, sizeof(flag));
85 #endif
86         setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(flag));
87
88         if(bind(fd, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
89                 warn("bind");
90                 return -1;
91         }
92
93         // Save top domain used
94         strncpy(topdomain, domain, sizeof(topdomain) - 1);
95         topdomain[sizeof(topdomain) - 1] = '\0';
96
97         printf("Opened UDP socket\n");
98
99         return fd;
100 }
101
102 int 
103 dns_settarget(const char *host) 
104 {
105         struct hostent *h;
106
107         // Init dns target struct
108         h = gethostbyname(host);
109         if (!h) {
110                 printf("Could not resolve name %s, exiting\n", host);
111                 return -1;
112         }
113
114         memset(&peer, 0, sizeof(peer));
115         peer.sin_family = AF_INET;
116         peer.sin_port = htons(53);
117         peer.sin_addr = *((struct in_addr *) h->h_addr);
118
119         // Init chunk id
120         chunkid = 0;
121         pingid = 0;
122
123         return 0;
124 }
125
126 void
127 close_dns(int fd)
128 {
129         close(fd);
130 }
131
132 int
133 dns_sending()
134 {
135         return (packetlen != 0);
136 }
137
138 static void
139 dns_send_chunk(int fd)
140 {
141         int avail;
142         char *p;
143
144         p = activepacket;
145         p += packetpos;
146         avail = packetlen - packetpos;
147         lastlen = dns_write(fd, ++chunkid, p, avail, 0);
148 }
149
150 void
151 dns_handle_tun(int fd, char *data, int len)
152 {
153         memcpy(activepacket, data, MIN(len, sizeof(activepacket)));
154         lastlen = 0;
155         packetpos = 0;
156         packetlen = len;
157
158         dns_send_chunk(fd);
159 }
160
161 void
162 dns_ping(int dns_fd)
163 {
164         char data[2];
165         if (dns_sending()) {
166                 lastlen = 0;
167                 packetpos = 0;
168                 packetlen = 0;
169         }
170         data[0] = (pingid & 0xFF00) >> 8;
171         data[1] = (pingid & 0xFF);
172         dns_write(dns_fd, ++pingid, data, 2, 'P');
173 }
174
175 void 
176 dns_handshake(int dns_fd)
177 {
178         char data[2];
179         data[0] = (pingid & 0xFF00) >> 8;
180         data[1] = (pingid & 0xFF);
181         dns_write(dns_fd, ++pingid, data, 2, 'H');
182 }
183
184 static void 
185 dns_query(int fd, int id, char *host, int type)
186 {
187         char *p;
188         int len;
189         int peerlen;
190         char buf[1024];
191         HEADER *header;
192         
193         len = 0;
194         memset(buf, 0, sizeof(buf));
195
196         header = (HEADER*)buf;  
197         
198         header->id = htons(id);
199         header->qr = 0;
200         header->opcode = 0;
201         header->aa = 0;
202         header->tc = 0;
203         header->rd = 1;
204         header->ra = 0;
205
206         header->qdcount = htons(1);
207         header->arcount = htons(1);
208
209         p = buf + sizeof(HEADER);
210         p += dns_encode_hostname(host, p, strlen(host));        
211
212         putshort(&p, type);
213         putshort(&p, C_IN);
214
215         // EDNS0
216         putbyte(&p, 0x00); //Root
217         putshort(&p, 0x0029); // OPT
218         putshort(&p, 0x1000); // Payload size: 4096
219         putshort(&p, 0x0000); // Higher bits/edns version
220         putshort(&p, 0x8000); // Z
221         putshort(&p, 0x0000); // Data length
222
223         peerlen = sizeof(peer);
224
225         len = p - buf;
226         sendto(fd, buf, len, 0, (struct sockaddr*)&peer, peerlen);
227 }
228
229 static int
230 dns_write(int fd, int id, char *buf, int len, char flag)
231 {
232         int avail;
233         int written;
234         int encoded;
235         char data[257];
236         char *d;
237
238         avail = 0xFF - strlen(topdomain) - 2;
239         memset(data, 0, sizeof(data));
240         d = data;
241         written = encode_data(buf, len, avail, d, flag);
242         encoded = strlen(data);
243         d += encoded;
244         if (*d != '.') {
245                 *d++ = '.';
246         }
247         strncpy(d, topdomain, strlen(topdomain)+1);
248         
249         dns_query(fd, id, data, T_NULL);
250         return written;
251 }
252
253 int
254 dns_read(int fd, char *buf, int buflen)
255 {
256         int r;
257         socklen_t addrlen;
258         char packet[64*1024];
259         struct sockaddr_in from;
260         HEADER *header;
261
262         addrlen = sizeof(struct sockaddr);
263         r = recvfrom(fd, packet, sizeof(packet), 0, (struct sockaddr*)&from, &addrlen);
264         if(r == -1) {
265                 perror("recvfrom");
266                 return 0;
267         }
268
269         header = (HEADER*)packet;
270         if (dns_sending() && chunkid == ntohs(header->id)) {
271                 /* Got ACK on sent packet */
272                 packetpos += lastlen;
273                 if (packetpos == packetlen) {
274                         /* Packet completed */
275                         packetpos = 0;
276                         packetlen = 0;
277                         lastlen = 0;
278                 } else {
279                         /* More to send */
280                         dns_send_chunk(fd);
281                 }
282         }
283         return dns_parse_reply(buf, buflen, packet, r);
284 }
285
286 int
287 dns_parse_reply(char *outbuf, int buflen, char *packet, int packetlen)
288 {
289         int rv;
290         uint32_t ttl;
291         short rlen;
292         short type;
293         short class;
294         short qdcount;
295         short ancount;
296         char *data;
297         char name[255];
298         char rdata[4*1024];
299         HEADER *header;
300
301         rv = 0;
302         header = (HEADER*)packet;
303         
304         data = packet + sizeof(HEADER);
305
306         if(header->qr) { /* qr=1 => response */
307                 qdcount = ntohs(header->qdcount);
308                 ancount = ntohs(header->ancount);
309
310                 rlen = 0;
311
312                 if(qdcount == 1) {
313                         readname(packet, packetlen, &data, name, sizeof(name));
314                         readshort(packet, &data, &type);
315                         readshort(packet, &data, &class);
316                 }
317                 if(ancount == 1) {
318                         readname(packet, packetlen, &data, name, sizeof(name));
319                         readshort(packet, &data, &type);
320                         readshort(packet, &data, &class);
321                         readlong(packet, &data, &ttl);
322                         readshort(packet, &data, &rlen);
323                         rv = MIN(rlen, sizeof(rdata));
324                         readdata(packet, &data, rdata, rv);
325                 }
326
327                 if(type == T_NULL && rv > 2) {
328                         rv = MIN(rv, buflen);
329                         memcpy(outbuf, rdata, rv);
330                 }
331         }
332
333         return rv;
334 }
335
336 int
337 dns_encode_hostname(const char *host, char *buffer, int size)
338 {
339         char *h;
340         char *p;
341         char *word;
342         int left;
343
344         h = strdup(host);
345         memset(buffer, 0, size);
346         p = buffer;
347         left = size;
348         
349         word = strtok(h, ".");
350         while(word) {
351                 if (strlen(word) > 63 || strlen(word) > left) {
352                         return -1;
353                 }
354                 left -= (strlen(word) + 1);
355                 *p++ = (char)strlen(word);
356                 memcpy(p, word, strlen(word));
357                 p += strlen(word);
358
359                 word = strtok(NULL, ".");
360         }
361
362         *p++ = 0;
363
364         free(h);
365
366         return p - buffer;
367 }
368
369 void
370 dnsd_send(int fd, struct query *q, char *data, int datalen)
371 {
372         int len;
373         char *p;
374         char buf[64*1024];
375         short name;
376         HEADER *header;
377
378         memset(buf, 0, sizeof(buf));
379
380         len = 0;
381         header = (HEADER*)buf;  
382
383         header->id = htons(q->id);
384         header->qr = 1;
385         header->opcode = 0;
386         header->aa = 1;
387         header->tc = 0;
388         header->rd = 0;
389         header->ra = 0;
390
391         header->qdcount = htons(1);
392         header->ancount = htons(1);
393
394         p = buf + sizeof(HEADER);
395         
396         name = 0xc000 | ((p - buf) & 0x3fff);
397         p += dns_encode_hostname(q->name, p, strlen(q->name));
398         putshort(&p, q->type);
399         putshort(&p, C_IN);
400
401         putshort(&p, name);     
402         putshort(&p, q->type);
403         putshort(&p, C_IN);
404         putlong(&p, 0);
405
406         q->id = 0;
407
408         putshort(&p, datalen);
409         putdata(&p, data, datalen);
410
411         len = p - buf;
412         sendto(fd, buf, len, 0, (struct sockaddr*)&q->from, q->fromlen);
413 }
414
415 static int
416 decodepacket(const char *name, char *buf, int buflen)
417 {
418         int len;
419         char *domain;
420
421         domain = strstr(name, topdomain);
422
423         len = decode_data(buf, buflen, name, domain);
424         if (len == buflen)
425                 return -1; 
426         return len;
427 }
428
429 int
430 dnsd_read(int fd, struct query *q, char *buf, int buflen)
431 {
432         int r;
433         int rv;
434         short id;
435         short type;
436         short class;
437         short qdcount;
438         char *data;
439         char name[257];
440         HEADER *header;
441         socklen_t addrlen;
442         char packet[64*1024];
443         struct sockaddr_in from;
444
445         addrlen = sizeof(struct sockaddr);
446         r = recvfrom(fd, packet, sizeof(packet), 0, (struct sockaddr*)&from, &addrlen);
447
448         if (r >= sizeof(HEADER)) {
449                 header = (HEADER*)packet;
450
451                 id = ntohs(header->id);
452
453                 data = packet + sizeof(HEADER);
454
455                 if(!header->qr) {
456                         qdcount = ntohs(header->qdcount);
457
458                         if(qdcount == 1) {
459                                 readname(packet, r, &data, name, sizeof(name) -1);
460                                 name[256] = 0;
461                                 readshort(packet, &data, &type);
462                                 readshort(packet, &data, &class);
463
464                                 strncpy(q->name, name, 257);
465                                 q->type = type;
466                                 q->id = id;
467                                 q->fromlen = addrlen;
468                                 memcpy((struct sockaddr*)&q->from, (struct sockaddr*)&from, addrlen);
469
470                                 rv = decodepacket(name, buf, buflen);
471                         }
472                 }
473         } else if (r < 0) {     // Error
474                 perror("recvfrom");
475                 rv = 0;
476         } else {                // Packet too small to be dns protocol
477                 rv = 0;
478         }
479
480         return rv;
481 }