dnsd: fix 64-bit bug 2539.
[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 source tree.
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         MAX_PACK_LEN = 512,
32         IP_STRING_LEN = sizeof(".xxx.xxx.xxx.xxx"),
33         MAX_NAME_LEN = IP_STRING_LEN - 1 + sizeof(".in-addr.arpa"),
34         REQ_A = 1,
35         REQ_PTR = 12,
36 };
37
38 /* the message from client and first part of response msg */
39 struct dns_head {
40         uint16_t id;
41         uint16_t flags;
42         uint16_t nquer;
43         uint16_t nansw;
44         uint16_t nauth;
45         uint16_t nadd;
46 };
47 /* Structure used to access type and class fields.
48  * They are totally unaligned, but gcc 4.3.4 thinks that pointer of type uint16_t*
49  * is 16-bit aligned and replaces 16-bit memcpy (in move_from_unaligned16 macro)
50  * with aligned halfword access on arm920t!
51  * Oh well. Slapping PACKED everywhere seems to help: */
52 struct type_and_class {
53         uint16_t type PACKED;
54         uint16_t class PACKED;
55 } PACKED;
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 & 1)
65 #define OPT_silent  (option_mask32 & 2)
66
67
68 /*
69  * Insert length of substrings instead of dots
70  */
71 static void undot(char *rip)
72 {
73         int i = 0;
74         int s = 0;
75
76         while (rip[i])
77                 i++;
78         for (--i; i >= 0; i--) {
79                 if (rip[i] == '.') {
80                         rip[i] = s;
81                         s = 0;
82                 } else {
83                         s++;
84                 }
85         }
86 }
87
88 /*
89  * Read hostname/IP records from file
90  */
91 static struct dns_entry *parse_conf_file(const char *fileconf)
92 {
93         char *token[2];
94         parser_t *parser;
95         struct dns_entry *m, *conf_data;
96         struct dns_entry **nextp;
97
98         conf_data = NULL;
99         nextp = &conf_data;
100
101         parser = config_open(fileconf);
102         while (config_read(parser, token, 2, 2, "# \t", PARSE_NORMAL)) {
103                 struct in_addr ip;
104                 uint32_t v32;
105
106                 if (inet_aton(token[1], &ip) == 0) {
107                         bb_error_msg("error at line %u, skipping", parser->lineno);
108                         continue;
109                 }
110
111                 if (OPT_verbose)
112                         bb_error_msg("name:%s, ip:%s", token[0], token[1]);
113
114                 /* sizeof(*m) includes 1 byte for m->name[0] */
115                 m = xzalloc(sizeof(*m) + strlen(token[0]) + 1);
116                 /*m->next = NULL;*/
117                 *nextp = m;
118                 nextp = &m->next;
119
120                 m->name[0] = '.';
121                 strcpy(m->name + 1, token[0]);
122                 undot(m->name);
123                 m->ip = ip.s_addr; /* in network order */
124                 v32 = ntohl(m->ip);
125                 /* inverted order */
126                 sprintf(m->rip, ".%u.%u.%u.%u",
127                         (uint8_t)(v32),
128                         (uint8_t)(v32 >> 8),
129                         (uint8_t)(v32 >> 16),
130                         (v32 >> 24)
131                 );
132                 undot(m->rip);
133         }
134         config_close(parser);
135         return conf_data;
136 }
137
138 /*
139  * Look query up in dns records and return answer if found.
140  */
141 static char *table_lookup(struct dns_entry *d,
142                 uint16_t type,
143                 char* query_string)
144 {
145         while (d) {
146                 unsigned len = d->name[0];
147                 /* d->name[len] is the last (non NUL) char */
148 #if DEBUG
149                 char *p, *q;
150                 q = query_string + 1;
151                 p = d->name + 1;
152                 fprintf(stderr, "%d/%d p:%s q:%s %d\n",
153                         (int)strlen(p), len,
154                         p, q, (int)strlen(q)
155                 );
156 #endif
157                 if (type == htons(REQ_A)) {
158                         /* search by host name */
159                         if (len != 1 || d->name[1] != '*') {
160 /* we are lax, hope no name component is ever >64 so that length
161  * (which will be represented as 'A','B'...) matches a lowercase letter.
162  * Actually, I think false matches are hard to construct.
163  * Example.
164  * [31] len is represented as '1', [65] as 'A', [65+32] as 'a'.
165  * [65]   <65 same chars>[31]<31 same chars>NUL
166  * [65+32]<65 same chars>1   <31 same chars>NUL
167  * This example seems to be the minimal case when false match occurs.
168  */
169                                 if (strcasecmp(d->name, query_string) != 0)
170                                         goto next;
171                         }
172                         return (char *)&d->ip;
173 #if DEBUG
174                         fprintf(stderr, "Found IP:%x\n", (int)d->ip);
175 #endif
176                         return 0;
177                 }
178                 /* search by IP-address */
179                 if ((len != 1 || d->name[1] != '*')
180                 /* we assume (do not check) that query_string
181                  * ends in ".in-addr.arpa" */
182                  && strncmp(d->rip, query_string, strlen(d->rip)) == 0
183                 ) {
184 #if DEBUG
185                         fprintf(stderr, "Found name:%s\n", d->name);
186 #endif
187                         return d->name;
188                 }
189  next:
190                 d = d->next;
191         }
192
193         return NULL;
194 }
195
196 /*
197  * Decode message and generate answer
198  */
199 /* RFC 1035
200 ...
201 Whenever an octet represents a numeric quantity, the left most bit
202 in the diagram is the high order or most significant bit.
203 That is, the bit labeled 0 is the most significant bit.
204 ...
205
206 4.1.1. Header section format
207       0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15
208     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
209     |                      ID                       |
210     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
211     |QR|   OPCODE  |AA|TC|RD|RA| 0  0  0|   RCODE   |
212     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
213     |                    QDCOUNT                    |
214     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
215     |                    ANCOUNT                    |
216     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
217     |                    NSCOUNT                    |
218     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
219     |                    ARCOUNT                    |
220     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
221 ID      16 bit random identifier assigned by querying peer.
222         Used to match query/response.
223 QR      message is a query (0), or a response (1).
224 OPCODE  0   standard query (QUERY)
225         1   inverse query (IQUERY)
226         2   server status request (STATUS)
227 AA      Authoritative Answer - this bit is valid in responses.
228         Responding name server is an authority for the domain name
229         in question section. Answer section may have multiple owner names
230         because of aliases.  The AA bit corresponds to the name which matches
231         the query name, or the first owner name in the answer section.
232 TC      TrunCation - this message was truncated.
233 RD      Recursion Desired - this bit may be set in a query and
234         is copied into the response.  If RD is set, it directs
235         the name server to pursue the query recursively.
236         Recursive query support is optional.
237 RA      Recursion Available - this be is set or cleared in a
238         response, and denotes whether recursive query support is
239         available in the name server.
240 RCODE   Response code.
241         0   No error condition
242         1   Format error
243         2   Server failure - server was unable to process the query
244             due to a problem with the name server.
245         3   Name Error - meaningful only for responses from
246             an authoritative name server. The referenced domain name
247             does not exist.
248         4   Not Implemented.
249         5   Refused.
250 QDCOUNT number of entries in the question section.
251 ANCOUNT number of records in the answer section.
252 NSCOUNT number of records in the authority records section.
253 ARCOUNT number of records in the additional records section.
254
255 4.1.2. Question section format
256
257 The section contains QDCOUNT (usually 1) entries, each of this format:
258       0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15
259     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
260     /                     QNAME                     /
261     /                                               /
262     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
263     |                     QTYPE                     |
264     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
265     |                     QCLASS                    |
266     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
267 QNAME   a domain name represented as a sequence of labels, where
268         each label consists of a length octet followed by that
269         number of octets. The domain name terminates with the
270         zero length octet for the null label of the root. Note
271         that this field may be an odd number of octets; no
272         padding is used.
273 QTYPE   a two octet type of the query.
274           1 a host address [REQ_A const]
275           2 an authoritative name server
276           3 a mail destination (Obsolete - use MX)
277           4 a mail forwarder (Obsolete - use MX)
278           5 the canonical name for an alias
279           6 marks the start of a zone of authority
280           7 a mailbox domain name (EXPERIMENTAL)
281           8 a mail group member (EXPERIMENTAL)
282           9 a mail rename domain name (EXPERIMENTAL)
283          10 a null RR (EXPERIMENTAL)
284          11 a well known service description
285          12 a domain name pointer [REQ_PTR const]
286          13 host information
287          14 mailbox or mail list information
288          15 mail exchange
289          16 text strings
290        0x1c IPv6?
291         252 a request for a transfer of an entire zone
292         253 a request for mailbox-related records (MB, MG or MR)
293         254 a request for mail agent RRs (Obsolete - see MX)
294         255 a request for all records
295 QCLASS  a two octet code that specifies the class of the query.
296           1 the Internet
297         (others are historic only)
298         255 any class
299
300 4.1.3. Resource Record format
301
302 The answer, authority, and additional sections all share the same format:
303 a variable number of resource records, where the number of records
304 is specified in the corresponding count field in the header.
305 Each resource record has this format:
306       0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15
307     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
308     /                                               /
309     /                      NAME                     /
310     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
311     |                      TYPE                     |
312     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
313     |                     CLASS                     |
314     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
315     |                      TTL                      |
316     |                                               |
317     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
318     |                   RDLENGTH                    |
319     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--|
320     /                     RDATA                     /
321     /                                               /
322     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
323 NAME    a domain name to which this resource record pertains.
324 TYPE    two octets containing one of the RR type codes.  This
325         field specifies the meaning of the data in the RDATA field.
326 CLASS   two octets which specify the class of the data in the RDATA field.
327 TTL     a 32 bit unsigned integer that specifies the time interval
328         (in seconds) that the record may be cached.
329 RDLENGTH a 16 bit integer, length in octets of the RDATA field.
330 RDATA   a variable length string of octets that describes the resource.
331         The format of this information varies according to the TYPE
332         and CLASS of the resource record.
333         If the TYPE is A and the CLASS is IN, it's a 4 octet IP address.
334
335 4.1.4. Message compression
336
337 In order to reduce the size of messages, domain names coan be compressed.
338 An entire domain name or a list of labels at the end of a domain name
339 is replaced with a pointer to a prior occurance of the same name.
340
341 The pointer takes the form of a two octet sequence:
342     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
343     | 1  1|                OFFSET                   |
344     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
345 The first two bits are ones.  This allows a pointer to be distinguished
346 from a label, since the label must begin with two zero bits because
347 labels are restricted to 63 octets or less.  The OFFSET field specifies
348 an offset from the start of the message (i.e., the first octet
349 of the ID field in the domain header).
350 A zero offset specifies the first byte of the ID field, etc.
351 Domain name in a message can be represented as either:
352    - a sequence of labels ending in a zero octet
353    - a pointer
354    - a sequence of labels ending with a pointer
355  */
356 static int process_packet(struct dns_entry *conf_data,
357                 uint32_t conf_ttl,
358                 uint8_t *buf)
359 {
360         struct dns_head *head;
361         struct type_and_class *unaligned_type_class;
362         const char *err_msg;
363         char *query_string;
364         char *answstr;
365         uint8_t *answb;
366         uint16_t outr_rlen;
367         uint16_t outr_flags;
368         uint16_t type;
369         uint16_t class;
370         int query_len;
371
372         head = (struct dns_head *)buf;
373         if (head->nquer == 0) {
374                 bb_error_msg("packet has 0 queries, ignored");
375                 return 0; /* don't reply */
376         }
377         if (head->flags & htons(0x8000)) { /* QR bit */
378                 bb_error_msg("response packet, ignored");
379                 return 0; /* don't reply */
380         }
381         /* QR = 1 "response", RCODE = 4 "Not Implemented" */
382         outr_flags = htons(0x8000 | 4);
383         err_msg = NULL;
384
385         /* start of query string */
386         query_string = (void *)(head + 1);
387         /* caller guarantees strlen is <= MAX_PACK_LEN */
388         query_len = strlen(query_string) + 1;
389         /* may be unaligned! */
390         unaligned_type_class = (void *)(query_string + query_len);
391         query_len += sizeof(*unaligned_type_class);
392         /* where to append answer block */
393         answb = (void *)(unaligned_type_class + 1);
394
395         /* OPCODE != 0 "standard query"? */
396         if ((head->flags & htons(0x7800)) != 0) {
397                 err_msg = "opcode != 0";
398                 goto empty_packet;
399         }
400         move_from_unaligned16(class, &unaligned_type_class->class);
401         if (class != htons(1)) { /* not class INET? */
402                 err_msg = "class != 1";
403                 goto empty_packet;
404         }
405         move_from_unaligned16(type, &unaligned_type_class->type);
406         if (type != htons(REQ_A) && type != htons(REQ_PTR)) {
407                 /* we can't handle this query type */
408 //TODO: happens all the time with REQ_AAAA (0x1c) requests - implement those?
409                 err_msg = "type is !REQ_A and !REQ_PTR";
410                 goto empty_packet;
411         }
412
413         /* look up the name */
414         answstr = table_lookup(conf_data, type, query_string);
415 #if DEBUG
416         /* Shows lengths instead of dots, unusable for !DEBUG */
417         bb_error_msg("'%s'->'%s'", query_string, answstr);
418 #endif
419         outr_rlen = 4;
420         if (answstr && type == htons(REQ_PTR)) {
421                 /* returning a host name */
422                 outr_rlen = strlen(answstr) + 1;
423         }
424         if (!answstr
425          || (unsigned)(answb - buf) + query_len + 4 + 2 + outr_rlen > MAX_PACK_LEN
426         ) {
427                 /* QR = 1 "response"
428                  * AA = 1 "Authoritative Answer"
429                  * RCODE = 3 "Name Error" */
430                 err_msg = "name is not found";
431                 outr_flags = htons(0x8000 | 0x0400 | 3);
432                 goto empty_packet;
433         }
434
435         /* Append answer Resource Record */
436         memcpy(answb, query_string, query_len); /* name, type, class */
437         answb += query_len;
438         move_to_unaligned32((uint32_t *)answb, htonl(conf_ttl));
439         answb += 4;
440         move_to_unaligned16((uint16_t *)answb, htons(outr_rlen));
441         answb += 2;
442         memcpy(answb, answstr, outr_rlen);
443         answb += outr_rlen;
444
445         /* QR = 1 "response",
446          * AA = 1 "Authoritative Answer",
447          * TODO: need to set RA bit 0x80? One user says nslookup complains
448          * "Got recursion not available from SERVER, trying next server"
449          * "** server can't find HOSTNAME"
450          * RCODE = 0 "success"
451          */
452         if (OPT_verbose)
453                 bb_error_msg("returning positive reply");
454         outr_flags = htons(0x8000 | 0x0400 | 0);
455         /* we have one answer */
456         head->nansw = htons(1);
457
458  empty_packet:
459         if ((outr_flags & htons(0xf)) != 0) { /* not a positive response */
460                 if (OPT_verbose) {
461                         bb_error_msg("%s, %s",
462                                 err_msg,
463                                 OPT_silent ? "dropping query" : "sending error reply"
464                         );
465                 }
466                 if (OPT_silent)
467                         return 0;
468         }
469         head->flags |= outr_flags;
470         head->nauth = head->nadd = 0;
471         head->nquer = htons(1); // why???
472
473         return answb - buf;
474 }
475
476 int dnsd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
477 int dnsd_main(int argc UNUSED_PARAM, char **argv)
478 {
479         const char *listen_interface = "0.0.0.0";
480         const char *fileconf = "/etc/dnsd.conf";
481         struct dns_entry *conf_data;
482         uint32_t conf_ttl = DEFAULT_TTL;
483         char *sttl, *sport;
484         len_and_sockaddr *lsa, *from, *to;
485         unsigned lsa_size;
486         int udps, opts;
487         uint16_t port = 53;
488         /* Ensure buf is 32bit aligned (we need 16bit, but 32bit can't hurt) */
489         uint8_t buf[MAX_PACK_LEN + 1] ALIGN4;
490
491         opts = getopt32(argv, "vsi:c:t:p:d", &listen_interface, &fileconf, &sttl, &sport);
492         //if (opts & (1 << 0)) // -v
493         //if (opts & (1 << 1)) // -s
494         //if (opts & (1 << 2)) // -i
495         //if (opts & (1 << 3)) // -c
496         if (opts & (1 << 4)) // -t
497                 conf_ttl = xatou_range(sttl, 1, 0xffffffff);
498         if (opts & (1 << 5)) // -p
499                 port = xatou_range(sport, 1, 0xffff);
500         if (opts & (1 << 6)) { // -d
501                 bb_daemonize_or_rexec(DAEMON_CLOSE_EXTRA_FDS, argv);
502                 openlog(applet_name, LOG_PID, LOG_DAEMON);
503                 logmode = LOGMODE_SYSLOG;
504         }
505
506         conf_data = parse_conf_file(fileconf);
507
508         lsa = xdotted2sockaddr(listen_interface, port);
509         udps = xsocket(lsa->u.sa.sa_family, SOCK_DGRAM, 0);
510         xbind(udps, &lsa->u.sa, lsa->len);
511         socket_want_pktinfo(udps); /* needed for recv_from_to to work */
512         lsa_size = LSA_LEN_SIZE + lsa->len;
513         from = xzalloc(lsa_size);
514         to = xzalloc(lsa_size);
515
516         {
517                 char *p = xmalloc_sockaddr2dotted(&lsa->u.sa);
518                 bb_error_msg("accepting UDP packets on %s", p);
519                 free(p);
520         }
521
522         while (1) {
523                 int r;
524                 /* Try to get *DEST* address (to which of our addresses
525                  * this query was directed), and reply from the same address.
526                  * Or else we can exhibit usual UDP ugliness:
527                  * [ip1.multihomed.ip2] <=  query to ip1  <= peer
528                  * [ip1.multihomed.ip2] => reply from ip2 => peer (confused) */
529                 memcpy(to, lsa, lsa_size);
530                 r = recv_from_to(udps, buf, MAX_PACK_LEN + 1, 0, &from->u.sa, &to->u.sa, lsa->len);
531                 if (r < 12 || r > MAX_PACK_LEN) {
532                         bb_error_msg("packet size %d, ignored", r);
533                         continue;
534                 }
535                 if (OPT_verbose)
536                         bb_error_msg("got UDP packet");
537                 buf[r] = '\0'; /* paranoia */
538                 r = process_packet(conf_data, conf_ttl, buf);
539                 if (r <= 0)
540                         continue;
541                 send_to_from(udps, buf, r, 0, &from->u.sa, &to->u.sa, lsa->len);
542         }
543         return 0;
544 }