dnsd: fix a number of bugs. Ideas by Ming-Ching Tiew (mctiew AT yahoo.com)
[oweals/busybox.git] / networking / dnsd.c
1 /* vi: set sw=4 ts=4: */
2 /*
3  * Mini DNS server implementation for busybox
4  *
5  * Copyright (C) 2005 Roberto A. Foglietta (me@roberto.foglietta.name)
6  * Copyright (C) 2005 Odd Arild Olsen (oao at fibula dot no)
7  * Copyright (C) 2003 Paul Sheer
8  *
9  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
10  *
11  * Odd Arild Olsen started out with the sheerdns [1] of Paul Sheer and rewrote
12  * it into a shape which I believe is both easier to understand and maintain.
13  * I also reused the input buffer for output and removed services he did not
14  * need.  [1] http://threading.2038bug.com/sheerdns/
15  *
16  * Some bugfix and minor changes was applied by Roberto A. Foglietta who made
17  * the first porting of oao' scdns to busybox also.
18  */
19
20 #include "libbb.h"
21 #include <syslog.h>
22
23 //#define DEBUG 1
24 #define DEBUG 0
25
26 enum {
27         /* Can tweak this */
28         DEFAULT_TTL = 120,
29
30 /* Cannot get bigger packets than 512 per RFC1035.
31  * In practice this can be set considerably smaller:
32  * Length of response packet is header (12B) + 2*type(4B) + 2*class(4B) +
33  * ttl(4B) + rlen(2B) + r (MAX_NAME_LEN = 21B) +
34  * 2*querystring (2 MAX_NAME_LEN = 42B), all together 90 Bytes
35  */
36         MAX_PACK_LEN = 512,
37         IP_STRING_LEN = sizeof(".xxx.xxx.xxx.xxx"),
38         MAX_NAME_LEN = IP_STRING_LEN - 1 + sizeof(".in-addr.arpa"),
39         REQ_A = 1,
40         REQ_PTR = 12,
41 };
42
43 /* the message from client and first part of response msg */
44 struct dns_head {
45         uint16_t id;
46         uint16_t flags;
47         uint16_t nquer;
48         uint16_t nansw;
49         uint16_t nauth;
50         uint16_t nadd;
51 };
52 struct dns_prop {
53         uint16_t type;
54         uint16_t class;
55 };
56 /* element of known name, ip address and reversed ip address */
57 struct dns_entry {
58         struct dns_entry *next;
59         uint32_t ip;
60         char rip[IP_STRING_LEN]; /* length decimal reversed IP */
61         char name[1];
62 };
63
64 #define OPT_verbose (option_mask32)
65
66
67 /*
68  * Insert length of substrings instead of dots
69  */
70 static void undot(char *rip)
71 {
72         int i = 0;
73         int s = 0;
74
75         while (rip[i])
76                 i++;
77         for (--i; i >= 0; i--) {
78                 if (rip[i] == '.') {
79                         rip[i] = s;
80                         s = 0;
81                 } else {
82                         s++;
83                 }
84         }
85 }
86
87 /*
88  * Read hostname/IP records from file
89  */
90 static struct dns_entry *parse_conf_file(const char *fileconf)
91 {
92         char *token[2];
93         parser_t *parser;
94         struct dns_entry *m, *conf_data;
95         struct dns_entry **nextp;
96
97         conf_data = NULL;
98         nextp = &conf_data;
99
100         parser = config_open(fileconf);
101         while (config_read(parser, token, 2, 2, "# \t", PARSE_NORMAL)) {
102                 struct in_addr ip;
103                 uint32_t v32;
104
105                 if (inet_aton(token[1], &ip) == 0) {
106                         bb_error_msg("error at line %u, skipping", parser->lineno);
107                         continue;
108                 }
109
110                 if (OPT_verbose)
111                         bb_error_msg("name:%s, ip:%s", token[0], token[1]);
112
113                 /* sizeof(*m) includes 1 byte for m->name[0] */
114                 m = xzalloc(sizeof(*m) + strlen(token[0]) + 1);
115                 /*m->next = NULL;*/
116                 *nextp = m;
117                 nextp = &m->next;
118
119                 m->name[0] = '.';
120                 strcpy(m->name + 1, token[0]);
121                 undot(m->name);
122                 m->ip = ip.s_addr; /* in network order */
123                 v32 = ntohl(m->ip);
124                 /* inverted order */
125                 sprintf(m->rip, ".%u.%u.%u.%u",
126                         (uint8_t)(v32),
127                         (uint8_t)(v32 >> 8),
128                         (uint8_t)(v32 >> 16),
129                         (v32 >> 24)
130                 );
131                 undot(m->rip);
132         }
133         config_close(parser);
134         return conf_data;
135 }
136
137 /*
138  * Look query up in dns records and return answer if found.
139  * qs is the query string.
140  */
141 static int table_lookup(uint8_t *as, struct dns_entry *d, uint16_t type, uint8_t *qs)
142 {
143         while (d) {
144                 unsigned len = d->name[0];
145                 /* d->name[len] is the last (non NUL) char */
146 #if DEBUG
147                 char *p, *q;
148                 q = (char *)&(qs[1]);
149                 p = &(d->name[1]);
150                 fprintf(stderr, "%d/%d p:%s q:%s %d\n",
151                         (int)strlen(p), len,
152                         p, q, (int)strlen(q)
153                 );
154 #endif
155                 if (type == htons(REQ_A)) {
156                         /* search by host name */
157                         if (len != 1 || d->name[1] != '*') {
158                                 if (strcasecmp(d->name, (char*)qs) != 0)
159                                         goto next;
160                         }
161                         move_to_unaligned32((uint32_t *)as, d->ip);
162 #if DEBUG
163                         fprintf(stderr, "OK as:%x\n", (int)d->ip);
164 #endif
165                         return 0;
166                 }
167                 /* search by IP-address */
168                 if ((len != 1 || d->name[1] != '*')
169                 /* assume (do not check) that qs ends in ".in-addr.arpa" */
170                  && strncmp(d->rip, (char*)qs, strlen(d->rip)) == 0
171                 ) {
172                         strcpy((char *)as, d->name);
173 #if DEBUG
174                         fprintf(stderr, "OK as:%s\n", as);
175 #endif
176                         return 0;
177                 }
178  next:
179                 d = d->next;
180         }
181
182         return -1;
183 }
184
185 /*
186  * Decode message and generate answer
187  */
188 /* RFC 1035
189 ...
190 Whenever an octet represents a numeric quantity, the left most bit
191 in the diagram is the high order or most significant bit.
192 That is, the bit labeled 0 is the most significant bit.
193 ...
194
195 4.1.1. Header section format
196                                     1  1  1  1  1  1
197       0  1  2  3  4  5  6  7  8  9  0  1  2  3  4  5
198     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
199     |                      ID                       |
200     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
201     |QR|   OPCODE  |AA|TC|RD|RA|   Z    |   RCODE   |
202     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
203     |                    QDCOUNT                    |
204     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
205     |                    ANCOUNT                    |
206     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
207     |                    NSCOUNT                    |
208     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
209     |                    ARCOUNT                    |
210     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
211 ID      16 bit random identifier assigned by query.
212         Used to match query/response.
213 QR      message is a query (0), or a response (1).
214 OPCODE  0   standard query (QUERY)
215         1   inverse query (IQUERY)
216         2   server status request (STATUS)
217 AA      Authoritative Answer - this bit is valid in responses,
218         and specifies that the responding name server is an
219         authority for the domain name in question section.
220         Note that the contents of the answer section may have
221         multiple owner names because of aliases.  The AA bit
222         corresponds to the name which matches the query name, or
223         the first owner name in the answer section.
224 TC      TrunCation - specifies that this message was truncated.
225 RD      Recursion Desired - this bit may be set in a query and
226         is copied into the response.  If RD is set, it directs
227         the name server to pursue the query recursively.
228         Recursive query support is optional.
229 RA      Recursion Available - this be is set or cleared in a
230         response, and denotes whether recursive query support is
231         available in the name server.
232 Z       Reserved for future use.  Must be zero.
233 RCODE   Response code.
234         0   No error condition
235         1   Format error
236         2   Server failure - The name server was
237             unable to process this query due to a
238             problem with the name server.
239         3   Name Error - Meaningful only for
240             responses from an authoritative name
241             server, this code signifies that the
242             domain name referenced in the query does
243             not exist.
244         4   Not Implemented.
245         5   Refused.
246 QDCOUNT number of entries in the question section.
247 ANCOUNT number of resource records in the answer section.
248 NSCOUNT number of name server resource records in the authority records section.
249 ARCOUNT number of resource records in the additional records section.
250
251 4.1.2. Question section format
252
253 The section contains QDCOUNT (usually 1) entries, each of the following format:
254                                     1  1  1  1  1  1
255       0  1  2  3  4  5  6  7  8  9  0  1  2  3  4  5
256     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
257     /                     QNAME                     /
258     /                                               /
259     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
260     |                     QTYPE                     |
261     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
262     |                     QCLASS                    |
263     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
264 QNAME   a domain name represented as a sequence of labels, where
265         each label consists of a length octet followed by that
266         number of octets. The domain name terminates with the
267         zero length octet for the null label of the root. Note
268         that this field may be an odd number of octets; no
269         padding is used.
270 QTYPE   a two octet type of the query.
271           1 a host address [REQ_A const]
272           2 an authoritative name server
273           3 a mail destination (Obsolete - use MX)
274           4 a mail forwarder (Obsolete - use MX)
275           5 the canonical name for an alias
276           6 marks the start of a zone of authority
277           7 a mailbox domain name (EXPERIMENTAL)
278           8 a mail group member (EXPERIMENTAL)
279           9 a mail rename domain name (EXPERIMENTAL)
280          10 a null RR (EXPERIMENTAL)
281          11 a well known service description
282          12 a domain name pointer [REQ_PTR const]
283          13 host information
284          14 mailbox or mail list information
285          15 mail exchange
286          16 text strings
287        0x1c IPv6?
288         252 a request for a transfer of an entire zone
289         253 a request for mailbox-related records (MB, MG or MR)
290         254 a request for mail agent RRs (Obsolete - see MX)
291         255 a request for all records
292 QCLASS  a two octet code that specifies the class of the query.
293           1 the Internet
294         (others are historic only)
295         255 any class
296
297 4.1.3. Resource record format
298
299 The answer, authority, and additional sections all share the same
300 format: a variable number of resource records, where the number of
301 records is specified in the corresponding count field in the header.
302 Each resource record has the following format:
303                                     1  1  1  1  1  1
304       0  1  2  3  4  5  6  7  8  9  0  1  2  3  4  5
305     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
306     /                                               /
307     /                      NAME                     /
308     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
309     |                      TYPE                     |
310     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
311     |                     CLASS                     |
312     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
313     |                      TTL                      |
314     |                                               |
315     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
316     |                   RDLENGTH                    |
317     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--|
318     /                     RDATA                     /
319     /                                               /
320     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
321 NAME    a domain name to which this resource record pertains.
322 TYPE    two octets containing one of the RR type codes.  This
323         field specifies the meaning of the data in the RDATA
324         field.
325 CLASS   two octets which specify the class of the data in the
326         RDATA field.
327 TTL     a 32 bit unsigned integer that specifies the time
328         interval (in seconds) that the resource record may be
329         cached before it should be discarded.  Zero values are
330         interpreted to mean that the RR can only be used for the
331         transaction in progress, and should not be cached.
332 RDLENGTH an unsigned 16 bit integer that specifies the length in
333         octets of the RDATA field.
334 RDATA   a variable length string of octets that describes the
335         resource.  The format of this information varies
336         according to the TYPE and CLASS of the resource record.
337         For example, if the TYPE is A and the CLASS is IN,
338         the RDATA field is a 4 octet ARPA Internet address.
339
340 4.1.4. Message compression
341
342 In order to reduce the size of messages, the domain system utilizes a
343 compression scheme which eliminates the repetition of domain names in a
344 message.  In this scheme, an entire domain name or a list of labels at
345 the end of a domain name is replaced with a pointer to a prior occurance
346 of the same name.
347
348 The pointer takes the form of a two octet sequence:
349     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
350     | 1  1|                OFFSET                   |
351     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
352 The first two bits are ones.  This allows a pointer to be distinguished
353 from a label, since the label must begin with two zero bits because
354 labels are restricted to 63 octets or less.  The OFFSET field specifies
355 an offset from the start of the message (i.e., the first octet
356 of the ID field in the domain header).
357 A zero offset specifies the first byte of the ID field, etc.
358
359 The compression scheme allows a domain name in a message to be
360 represented as either:
361    - a sequence of labels ending in a zero octet
362    - a pointer
363    - a sequence of labels ending with a pointer
364  */
365 static int process_packet(struct dns_entry *conf_data, uint32_t conf_ttl, uint8_t *buf)
366 {
367         uint8_t answstr[MAX_NAME_LEN + 1];
368         struct dns_head *head;
369         struct dns_prop *unaligned_qprop;
370         uint8_t *from, *answb;
371         uint16_t outr_rlen;
372         uint16_t outr_flags;
373         uint16_t type;
374         uint16_t class;
375         int querystr_len;
376
377         answstr[0] = '\0';
378
379         head = (struct dns_head *)buf;
380         if (head->nquer == 0) {
381                 bb_error_msg("packet has 0 queries, ignored");
382                 return -1;
383         }
384
385         if (head->flags & htons(0x8000)) { /* QR bit */
386                 bb_error_msg("response packet, ignored");
387                 return -1;
388         }
389
390         /* start of query string */
391         from = (void *)(head + 1);
392         /* caller guarantees strlen is <= MAX_PACK_LEN */
393         querystr_len = strlen((char *)from) + 1;
394         /* may be unaligned! */
395         unaligned_qprop = (void *)(from + querystr_len);
396         /* where to append answer block */
397         answb = (void *)(unaligned_qprop + 1);
398
399         outr_rlen = 0;
400         /* QR = 1 "response", RCODE = 4 "Not Implemented" */
401         outr_flags = htons(0x8000 | 4);
402
403         move_from_unaligned16(type, &unaligned_qprop->type);
404         if (type != htons(REQ_A) && type != htons(REQ_PTR)) {
405                 /* we can't handle the query type */
406                 goto empty_packet;
407         }
408         move_from_unaligned16(class, &unaligned_qprop->class);
409         if (class != htons(1)) { /* not class INET? */
410                 goto empty_packet;
411         }
412         /* OPCODE != 0 "standard query" ? */
413         if ((head->flags & htons(0x7800)) != 0) {
414                 goto empty_packet;
415         }
416
417         bb_info_msg("%s", (char *)from);
418         if (table_lookup(answstr, conf_data, type, from) != 0) {
419                 /* QR = 1 "response"
420                  * AA = 1 "Authoritative Answer"
421                  * RCODE = 3 "Name Error" */
422                 outr_flags = htons(0x8000 | 0x0400 | 3);
423                 goto empty_packet;
424         }
425         /* return an address */
426         outr_rlen = 4;
427         if (type == htons(REQ_PTR)) {
428                 /* return a host name */
429                 outr_rlen = strlen((char *)answstr) + 1;
430         }
431         /* QR = 1 "response",
432          * AA = 1 "Authoritative Answer",
433          * RCODE = 0 "success" */
434         outr_flags = htons(0x8000 | 0x0400 | 0);
435         /* we have one answer */
436         head->nansw = htons(1);
437         /* copy query block to answer block */
438         querystr_len += sizeof(unaligned_qprop);
439         memcpy(answb, from, querystr_len);
440         answb += querystr_len;
441         /* append answer Resource Record */
442         move_to_unaligned32((uint32_t *)answb, htonl(conf_ttl));
443         answb += 4;
444         move_to_unaligned32((uint16_t *)answb, htons(outr_rlen));
445         answb += 2;
446         memcpy(answb, answstr, outr_rlen);
447         answb += outr_rlen;
448
449  empty_packet:
450         head->flags |= outr_flags;
451         head->nauth = head->nadd = 0;
452         head->nquer = htons(1); // why???
453
454         return answb - buf;
455 }
456
457 int dnsd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
458 int dnsd_main(int argc UNUSED_PARAM, char **argv)
459 {
460         const char *listen_interface = "0.0.0.0";
461         const char *fileconf = "/etc/dnsd.conf";
462         struct dns_entry *conf_data;
463         uint32_t conf_ttl = DEFAULT_TTL;
464         char *sttl, *sport;
465         len_and_sockaddr *lsa, *from, *to;
466         unsigned lsa_size;
467         int udps, opts;
468         uint16_t port = 53;
469         /* Paranoid sizing: querystring x2 + ttl + outr_rlen + answstr */
470         /* I'd rather see process_packet() fixed instead... */
471         uint8_t buf[MAX_PACK_LEN * 2 + 4 + 2 + (MAX_NAME_LEN+1)];
472
473         opts = getopt32(argv, "vi:c:t:p:d", &listen_interface, &fileconf, &sttl, &sport);
474         //if (opts & 0x1) // -v
475         //if (opts & 0x2) // -i
476         //if (opts & 0x4) // -c
477         if (opts & 0x8) // -t
478                 conf_ttl = xatou_range(sttl, 1, 0xffffffff);
479         if (opts & 0x10) // -p
480                 port = xatou_range(sport, 1, 0xffff);
481         if (opts & 0x20) { // -d
482                 bb_daemonize_or_rexec(DAEMON_CLOSE_EXTRA_FDS, argv);
483                 openlog(applet_name, LOG_PID, LOG_DAEMON);
484                 logmode = LOGMODE_SYSLOG;
485         }
486         /* Clear all except "verbose" bit */
487         option_mask32 &= 1;
488
489         conf_data = parse_conf_file(fileconf);
490
491         bb_signals(0
492                 /* why? + (1 << SIGPIPE) */
493                 + (1 << SIGHUP)
494 #ifdef SIGTSTP
495                 + (1 << SIGTSTP)
496 #endif
497 #ifdef SIGURG
498                 + (1 << SIGURG)
499 #endif
500                 , SIG_IGN);
501
502         lsa = xdotted2sockaddr(listen_interface, port);
503         udps = xsocket(lsa->u.sa.sa_family, SOCK_DGRAM, 0);
504         xbind(udps, &lsa->u.sa, lsa->len);
505         socket_want_pktinfo(udps); /* needed for recv_from_to to work */
506         lsa_size = LSA_LEN_SIZE + lsa->len;
507         from = xzalloc(lsa_size);
508         to = xzalloc(lsa_size);
509
510         {
511                 char *p = xmalloc_sockaddr2dotted(&lsa->u.sa);
512                 bb_info_msg("Accepting UDP packets on %s", p);
513                 free(p);
514         }
515
516         while (1) {
517                 int r;
518                 /* Try to get *DEST* address (to which of our addresses
519                  * this query was directed), and reply from the same address.
520                  * Or else we can exhibit usual UDP ugliness:
521                  * [ip1.multihomed.ip2] <=  query to ip1  <= peer
522                  * [ip1.multihomed.ip2] => reply from ip2 => peer (confused) */
523                 memcpy(to, lsa, lsa_size);
524                 r = recv_from_to(udps, buf, MAX_PACK_LEN + 1, 0, &from->u.sa, &to->u.sa, lsa->len);
525                 if (r < 12 || r > MAX_PACK_LEN) {
526                         bb_error_msg("packet size %d, ignored", r);
527                         continue;
528                 }
529                 if (OPT_verbose)
530                         bb_info_msg("Got UDP packet");
531                 buf[r] = '\0'; /* paranoia */
532                 r = process_packet(conf_data, conf_ttl, buf);
533                 if (r <= 0)
534                         continue;
535                 send_to_from(udps, buf, r, 0, &from->u.sa, &to->u.sa, lsa->len);
536         }
537         return 0;
538 }