5dbaec1ebe15861fd0d2c1daef3a91d0ee1afb00
[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  */
140 static char *table_lookup(struct dns_entry *d,
141                 uint16_t type,
142                 char* query_string)
143 {
144         while (d) {
145                 unsigned len = d->name[0];
146                 /* d->name[len] is the last (non NUL) char */
147 #if DEBUG
148                 char *p, *q;
149                 q = query_string + 1;
150                 p = d->name + 1;
151                 fprintf(stderr, "%d/%d p:%s q:%s %d\n",
152                         (int)strlen(p), len,
153                         p, q, (int)strlen(q)
154                 );
155 #endif
156                 if (type == htons(REQ_A)) {
157                         /* search by host name */
158                         if (len != 1 || d->name[1] != '*') {
159 /* we are lax, hope no name component is ever >64 so that length
160  * (which will be represented as 'A','B'...) matches a lowercase letter.
161  * Actually, I think false matches are hard to construct.
162  * Example.
163  * [31] len is represented as '1', [65] as 'A', [65+32] as 'a'.
164  * [65]   <65 same chars>[31]<31 same chars>NUL
165  * [65+32]<65 same chars>1   <31 same chars>NUL
166  * This example seems to be the minimal case when false match occurs.
167  */
168                                 if (strcasecmp(d->name, query_string) != 0)
169                                         goto next;
170                         }
171                         return (char *)&d->ip;
172 #if DEBUG
173                         fprintf(stderr, "Found IP:%x\n", (int)d->ip);
174 #endif
175                         return 0;
176                 }
177                 /* search by IP-address */
178                 if ((len != 1 || d->name[1] != '*')
179                 /* we assume (do not check) that query_string
180                  * ends in ".in-addr.arpa" */
181                  && strncmp(d->rip, query_string, strlen(d->rip)) == 0
182                 ) {
183 #if DEBUG
184                         fprintf(stderr, "Found name:%s\n", d->name);
185 #endif
186                         return d->name;
187                 }
188  next:
189                 d = d->next;
190         }
191
192         return NULL;
193 }
194
195 /*
196  * Decode message and generate answer
197  */
198 /* RFC 1035
199 ...
200 Whenever an octet represents a numeric quantity, the left most bit
201 in the diagram is the high order or most significant bit.
202 That is, the bit labeled 0 is the most significant bit.
203 ...
204
205 4.1.1. Header section format
206       0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15
207     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
208     |                      ID                       |
209     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
210     |QR|   OPCODE  |AA|TC|RD|RA| 0  0  0|   RCODE   |
211     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
212     |                    QDCOUNT                    |
213     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
214     |                    ANCOUNT                    |
215     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
216     |                    NSCOUNT                    |
217     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
218     |                    ARCOUNT                    |
219     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
220 ID      16 bit random identifier assigned by querying peer.
221         Used to match query/response.
222 QR      message is a query (0), or a response (1).
223 OPCODE  0   standard query (QUERY)
224         1   inverse query (IQUERY)
225         2   server status request (STATUS)
226 AA      Authoritative Answer - this bit is valid in responses.
227         Responding name server is an authority for the domain name
228         in question section. Answer section may have multiple owner names
229         because of aliases.  The AA bit corresponds to the name which matches
230         the query name, or the first owner name in the answer section.
231 TC      TrunCation - this message was truncated.
232 RD      Recursion Desired - this bit may be set in a query and
233         is copied into the response.  If RD is set, it directs
234         the name server to pursue the query recursively.
235         Recursive query support is optional.
236 RA      Recursion Available - this be is set or cleared in a
237         response, and denotes whether recursive query support is
238         available in the name server.
239 RCODE   Response code.
240         0   No error condition
241         1   Format error
242         2   Server failure - server was unable to process the query
243             due to a problem with the name server.
244         3   Name Error - meaningful only for responses from
245             an authoritative name server. The referenced domain name
246             does  not exist.
247         4   Not Implemented.
248         5   Refused.
249 QDCOUNT number of entries in the question section.
250 ANCOUNT number of records in the answer section.
251 NSCOUNT number of records in the authority records section.
252 ARCOUNT number of records in the additional records section.
253
254 4.1.2. Question section format
255
256 The section contains QDCOUNT (usually 1) entries, each of this format:
257       0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15
258     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
259     /                     QNAME                     /
260     /                                               /
261     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
262     |                     QTYPE                     |
263     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
264     |                     QCLASS                    |
265     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
266 QNAME   a domain name represented as a sequence of labels, where
267         each label consists of a length octet followed by that
268         number of octets. The domain name terminates with the
269         zero length octet for the null label of the root. Note
270         that this field may be an odd number of octets; no
271         padding is used.
272 QTYPE   a two octet type of the query.
273           1 a host address [REQ_A const]
274           2 an authoritative name server
275           3 a mail destination (Obsolete - use MX)
276           4 a mail forwarder (Obsolete - use MX)
277           5 the canonical name for an alias
278           6 marks the start of a zone of authority
279           7 a mailbox domain name (EXPERIMENTAL)
280           8 a mail group member (EXPERIMENTAL)
281           9 a mail rename domain name (EXPERIMENTAL)
282          10 a null RR (EXPERIMENTAL)
283          11 a well known service description
284          12 a domain name pointer [REQ_PTR const]
285          13 host information
286          14 mailbox or mail list information
287          15 mail exchange
288          16 text strings
289        0x1c IPv6?
290         252 a request for a transfer of an entire zone
291         253 a request for mailbox-related records (MB, MG or MR)
292         254 a request for mail agent RRs (Obsolete - see MX)
293         255 a request for all records
294 QCLASS  a two octet code that specifies the class of the query.
295           1 the Internet
296         (others are historic only)
297         255 any class
298
299 4.1.3. Resource record format
300
301 The answer, authority, and additional sections all share the same format:
302 a variable number of resource records, where the number of records
303 is specified in the corresponding count field in the header.
304 Each resource record has this format:
305       0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15
306     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
307     /                                               /
308     /                      NAME                     /
309     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
310     |                      TYPE                     |
311     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
312     |                     CLASS                     |
313     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
314     |                      TTL                      |
315     |                                               |
316     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
317     |                   RDLENGTH                    |
318     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--|
319     /                     RDATA                     /
320     /                                               /
321     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
322 NAME    a domain name to which this resource record pertains.
323 TYPE    two octets containing one of the RR type codes.  This
324         field specifies the meaning of the data in the RDATA field.
325 CLASS   two octets which specify the class of the data in the RDATA field.
326 TTL     a 32 bit unsigned integer that specifies the time interval
327         (in seconds) that the record may be cached.
328 RDLENGTH a 16 bit integer, length in octets of the RDATA field.
329 RDATA   a variable length string of octets that describes the resource.
330         The format of this information varies according to the TYPE
331         and CLASS of the resource record.
332         If the TYPE is A and the CLASS is IN, it's a 4 octet IP address.
333
334 4.1.4. Message compression
335
336 In order to reduce the size of messages, domain names coan be compressed.
337 An entire domain name or a list of labels at the end of a domain name
338 is replaced with a pointer to a prior occurance of the same name.
339
340 The pointer takes the form of a two octet sequence:
341     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
342     | 1  1|                OFFSET                   |
343     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
344 The first two bits are ones.  This allows a pointer to be distinguished
345 from a label, since the label must begin with two zero bits because
346 labels are restricted to 63 octets or less.  The OFFSET field specifies
347 an offset from the start of the message (i.e., the first octet
348 of the ID field in the domain header).
349 A zero offset specifies the first byte of the ID field, etc.
350 Domain name in a message can be represented as either:
351    - a sequence of labels ending in a zero octet
352    - a pointer
353    - a sequence of labels ending with a pointer
354  */
355 static int process_packet(struct dns_entry *conf_data,
356                 uint32_t conf_ttl,
357                 uint8_t *buf)
358 {
359         char *answstr;
360         struct dns_head *head;
361         struct dns_prop *unaligned_qprop;
362         char *query_string;
363         uint8_t *answb;
364         uint16_t outr_rlen;
365         uint16_t outr_flags;
366         uint16_t type;
367         uint16_t class;
368         int querystr_len;
369
370         head = (struct dns_head *)buf;
371         if (head->nquer == 0) {
372                 bb_error_msg("packet has 0 queries, ignored");
373                 return -1;
374         }
375
376         if (head->flags & htons(0x8000)) { /* QR bit */
377                 bb_error_msg("response packet, ignored");
378                 return -1;
379         }
380
381         /* start of query string */
382         query_string = (void *)(head + 1);
383         /* caller guarantees strlen is <= MAX_PACK_LEN */
384         querystr_len = strlen(query_string) + 1;
385         /* may be unaligned! */
386         unaligned_qprop = (void *)(query_string + querystr_len);
387         querystr_len += sizeof(unaligned_qprop);
388         /* where to append answer block */
389         answb = (void *)(unaligned_qprop + 1);
390
391         /* QR = 1 "response", RCODE = 4 "Not Implemented" */
392         outr_flags = htons(0x8000 | 4);
393
394         move_from_unaligned16(type, &unaligned_qprop->type);
395         if (type != htons(REQ_A) && type != htons(REQ_PTR)) {
396                 /* we can't handle the query type */
397                 goto empty_packet;
398         }
399         move_from_unaligned16(class, &unaligned_qprop->class);
400         if (class != htons(1)) { /* not class INET? */
401                 goto empty_packet;
402         }
403         /* OPCODE != 0 "standard query" ? */
404         if ((head->flags & htons(0x7800)) != 0) {
405                 goto empty_packet;
406         }
407
408         /* look up the name */
409 #if DEBUG
410         /* need to convert lengths to dots before we can use it in non-debug */
411         bb_info_msg("%s", query_string);
412 #endif
413         answstr = table_lookup(conf_data, type, query_string);
414         outr_rlen = 4;
415         if (answstr && type == htons(REQ_PTR)) {
416                 /* return a host name */
417                 outr_rlen = strlen(answstr) + 1;
418         }
419         if (!answstr
420          || (unsigned)(answb - buf) + querystr_len + 4 + 2 + outr_rlen > MAX_PACK_LEN
421         ) {
422                 /* QR = 1 "response"
423                  * AA = 1 "Authoritative Answer"
424                  * RCODE = 3 "Name Error" */
425                 outr_flags = htons(0x8000 | 0x0400 | 3);
426                 goto empty_packet;
427         }
428
429         /* copy query block to answer block */
430         memcpy(answb, query_string, querystr_len);
431         answb += querystr_len;
432         /* append answer Resource Record */
433         move_to_unaligned32((uint32_t *)answb, htonl(conf_ttl));
434         answb += 4;
435         move_to_unaligned32((uint16_t *)answb, htons(outr_rlen));
436         answb += 2;
437         memcpy(answb, answstr, outr_rlen);
438         answb += outr_rlen;
439
440         /* QR = 1 "response",
441          * AA = 1 "Authoritative Answer",
442          * RCODE = 0 "success" */
443         outr_flags = htons(0x8000 | 0x0400 | 0);
444         /* we have one answer */
445         head->nansw = htons(1);
446
447  empty_packet:
448         head->flags |= outr_flags;
449         head->nauth = head->nadd = 0;
450         head->nquer = htons(1); // why???
451
452         return answb - buf;
453 }
454
455 int dnsd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
456 int dnsd_main(int argc UNUSED_PARAM, char **argv)
457 {
458         const char *listen_interface = "0.0.0.0";
459         const char *fileconf = "/etc/dnsd.conf";
460         struct dns_entry *conf_data;
461         uint32_t conf_ttl = DEFAULT_TTL;
462         char *sttl, *sport;
463         len_and_sockaddr *lsa, *from, *to;
464         unsigned lsa_size;
465         int udps, opts;
466         uint16_t port = 53;
467         /* Paranoid sizing: querystring x2 + ttl + outr_rlen + answstr */
468         /* I'd rather see process_packet() fixed instead... */
469         uint8_t buf[MAX_PACK_LEN * 2 + 4 + 2 + (MAX_NAME_LEN+1)];
470
471         opts = getopt32(argv, "vi:c:t:p:d", &listen_interface, &fileconf, &sttl, &sport);
472         //if (opts & 0x1) // -v
473         //if (opts & 0x2) // -i
474         //if (opts & 0x4) // -c
475         if (opts & 0x8) // -t
476                 conf_ttl = xatou_range(sttl, 1, 0xffffffff);
477         if (opts & 0x10) // -p
478                 port = xatou_range(sport, 1, 0xffff);
479         if (opts & 0x20) { // -d
480                 bb_daemonize_or_rexec(DAEMON_CLOSE_EXTRA_FDS, argv);
481                 openlog(applet_name, LOG_PID, LOG_DAEMON);
482                 logmode = LOGMODE_SYSLOG;
483         }
484         /* Clear all except "verbose" bit */
485         option_mask32 &= 1;
486
487         conf_data = parse_conf_file(fileconf);
488
489         lsa = xdotted2sockaddr(listen_interface, port);
490         udps = xsocket(lsa->u.sa.sa_family, SOCK_DGRAM, 0);
491         xbind(udps, &lsa->u.sa, lsa->len);
492         socket_want_pktinfo(udps); /* needed for recv_from_to to work */
493         lsa_size = LSA_LEN_SIZE + lsa->len;
494         from = xzalloc(lsa_size);
495         to = xzalloc(lsa_size);
496
497         {
498                 char *p = xmalloc_sockaddr2dotted(&lsa->u.sa);
499                 bb_info_msg("Accepting UDP packets on %s", p);
500                 free(p);
501         }
502
503         while (1) {
504                 int r;
505                 /* Try to get *DEST* address (to which of our addresses
506                  * this query was directed), and reply from the same address.
507                  * Or else we can exhibit usual UDP ugliness:
508                  * [ip1.multihomed.ip2] <=  query to ip1  <= peer
509                  * [ip1.multihomed.ip2] => reply from ip2 => peer (confused) */
510                 memcpy(to, lsa, lsa_size);
511                 r = recv_from_to(udps, buf, MAX_PACK_LEN + 1, 0, &from->u.sa, &to->u.sa, lsa->len);
512                 if (r < 12 || r > MAX_PACK_LEN) {
513                         bb_error_msg("packet size %d, ignored", r);
514                         continue;
515                 }
516                 if (OPT_verbose)
517                         bb_info_msg("Got UDP packet");
518                 buf[r] = '\0'; /* paranoia */
519                 r = process_packet(conf_data, conf_ttl, buf);
520                 if (r <= 0)
521                         continue;
522                 send_to_from(udps, buf, r, 0, &from->u.sa, &to->u.sa, lsa->len);
523         }
524         return 0;
525 }