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