blob: 9d1016ca1561f118e4d2e478a1fc286a869f5120 [file] [log] [blame]
lh9ed821d2023-04-07 01:36:19 -07001/* vi: set sw=4 ts=4: */
2/* resolv.c: DNS Resolver
3 *
4 * Copyright (C) 1998 Kenneth Albanowski <kjahds@kjahds.com>,
5 * The Silver Hammer Group, Ltd.
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
11 */
12/*
13 * Portions Copyright (c) 1985, 1993
14 * The Regents of the University of California. All rights reserved.
15 *
16 * Redistribution and use in source and binary forms, with or without
17 * modification, are permitted provided that the following conditions
18 * are met:
19 * 1. Redistributions of source code must retain the above copyright
20 * notice, this list of conditions and the following disclaimer.
21 * 2. Redistributions in binary form must reproduce the above copyright
22 * notice, this list of conditions and the following disclaimer in the
23 * documentation and/or other materials provided with the distribution.
24 * 4. Neither the name of the University nor the names of its contributors
25 * may be used to endorse or promote products derived from this software
26 * without specific prior written permission.
27 *
28 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
29 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
32 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38 * SUCH DAMAGE.
39 */
40/*
41 * Portions Copyright (c) 1993 by Digital Equipment Corporation.
42 *
43 * Permission to use, copy, modify, and distribute this software for any
44 * purpose with or without fee is hereby granted, provided that the above
45 * copyright notice and this permission notice appear in all copies, and that
46 * the name of Digital Equipment Corporation not be used in advertising or
47 * publicity pertaining to distribution of the document or software without
48 * specific, written prior permission.
49 *
50 * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
51 * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
52 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
53 * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
54 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
55 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
56 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
57 * SOFTWARE.
58 */
59/*
60 * Portions Copyright (c) 1996-1999 by Internet Software Consortium.
61 *
62 * Permission to use, copy, modify, and distribute this software for any
63 * purpose with or without fee is hereby granted, provided that the above
64 * copyright notice and this permission notice appear in all copies.
65 *
66 * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
67 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
68 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
69 * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
70 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
71 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
72 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
73 * SOFTWARE.
74 */
75/*
76 * 5-Oct-2000 W. Greathouse wgreathouse@smva.com
77 * Fix memory leak and memory corruption.
78 * -- Every name resolution resulted in
79 * a new parse of resolv.conf and new
80 * copy of nameservers allocated by
81 * strdup.
82 * -- Every name resolution resulted in
83 * a new read of resolv.conf without
84 * resetting index from prior read...
85 * resulting in exceeding array bounds.
86 *
87 * Limit nameservers read from resolv.conf.
88 * Add "search" domains from resolv.conf.
89 * Some systems will return a security
90 * signature along with query answer for
91 * dynamic DNS entries -- skip/ignore this answer.
92 * Include arpa/nameser.h for defines.
93 * General cleanup.
94 *
95 * 20-Jun-2001 Michal Moskal <malekith@pld.org.pl>
96 * partial IPv6 support (i.e. gethostbyname2() and resolve_address2()
97 * functions added), IPv6 nameservers are also supported.
98 *
99 * 6-Oct-2001 Jari Korva <jari.korva@iki.fi>
100 * more IPv6 support (IPv6 support for gethostbyaddr();
101 * address family parameter and improved IPv6 support for get_hosts_byname
102 * and read_etc_hosts; getnameinfo() port from glibc; defined
103 * defined ip6addr_any and in6addr_loopback)
104 *
105 * 2-Feb-2002 Erik Andersen <andersen@codepoet.org>
106 * Added gethostent(), sethostent(), and endhostent()
107 *
108 * 17-Aug-2002 Manuel Novoa III <mjn3@codepoet.org>
109 * Fixed __read_etc_hosts_r to return alias list, and modified buffer
110 * allocation accordingly. See MAX_ALIASES and ALIAS_DIM below.
111 * This fixes the segfault in the Python 2.2.1 socket test.
112 *
113 * 04-Jan-2003 Jay Kulpinski <jskulpin@berkshire.rr.com>
114 * Fixed __decode_dotted to count the terminating null character
115 * in a host name.
116 *
117 * 02-Oct-2003 Tony J. White <tjw@tjw.org>
118 * Lifted dn_expand() and dependent ns_name_uncompress(), ns_name_unpack(),
119 * and ns_name_ntop() from glibc 2.3.2 for compatibility with ipsec-tools
120 * and openldap.
121 *
122 * 7-Sep-2004 Erik Andersen <andersen@codepoet.org>
123 * Added gethostent_r()
124 *
125 * 2008, 2009 Denys Vlasenko <vda.linux@googlemail.com>
126 * Cleanups, fixes, readability, more cleanups and more fixes.
127 *
128 * March 2010 Bernhard Reutner-Fischer
129 * Switch to common config parser
130 */
131/* Nota bene:
132 * The whole resolver code has several (severe) problems:
133 * - it doesn't even build without IPv4, i.e. !UCLIBC_HAS_IPV4 but only IPv6
134 * - it is way too big
135 *
136 * Both points above are considered bugs, patches/reimplementations welcome.
137 */
138/* RFC 1035
139...
140Whenever an octet represents a numeric quantity, the left most bit
141in the diagram is the high order or most significant bit.
142That is, the bit labeled 0 is the most significant bit.
143...
144
1454.1.1. Header section format
146 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
147 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
148 | ID |
149 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
150 |QR| OPCODE |AA|TC|RD|RA| 0 0 0| RCODE |
151 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
152 | QDCOUNT |
153 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
154 | ANCOUNT |
155 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
156 | NSCOUNT |
157 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
158 | ARCOUNT |
159 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
160ID 16 bit random identifier assigned by querying peer.
161 Used to match query/response.
162QR message is a query (0), or a response (1).
163OPCODE 0 standard query (QUERY)
164 1 inverse query (IQUERY)
165 2 server status request (STATUS)
166AA Authoritative Answer - this bit is valid in responses.
167 Responding name server is an authority for the domain name
168 in question section. Answer section may have multiple owner names
169 because of aliases. The AA bit corresponds to the name which matches
170 the query name, or the first owner name in the answer section.
171TC TrunCation - this message was truncated.
172RD Recursion Desired - this bit may be set in a query and
173 is copied into the response. If RD is set, it directs
174 the name server to pursue the query recursively.
175 Recursive query support is optional.
176RA Recursion Available - this be is set or cleared in a
177 response, and denotes whether recursive query support is
178 available in the name server.
179RCODE Response code.
180 0 No error condition
181 1 Format error
182 2 Server failure - server was unable to process the query
183 due to a problem with the name server.
184 3 Name Error - meaningful only for responses from
185 an authoritative name server. The referenced domain name
186 does not exist.
187 4 Not Implemented.
188 5 Refused.
189QDCOUNT number of entries in the question section.
190ANCOUNT number of records in the answer section.
191NSCOUNT number of records in the authority records section.
192ARCOUNT number of records in the additional records section.
193
1944.1.2. Question section format
195
196The section contains QDCOUNT (usually 1) entries, each of this format:
197 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
198 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
199 / QNAME /
200 / /
201 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
202 | QTYPE |
203 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
204 | QCLASS |
205 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
206QNAME a domain name represented as a sequence of labels, where
207 each label consists of a length octet followed by that
208 number of octets. The domain name terminates with the
209 zero length octet for the null label of the root. Note
210 that this field may be an odd number of octets; no
211 padding is used.
212QTYPE a two octet type of the query.
213 1 a host address [REQ_A const]
214 2 an authoritative name server
215 3 a mail destination (Obsolete - use MX)
216 4 a mail forwarder (Obsolete - use MX)
217 5 the canonical name for an alias
218 6 marks the start of a zone of authority
219 7 a mailbox domain name (EXPERIMENTAL)
220 8 a mail group member (EXPERIMENTAL)
221 9 a mail rename domain name (EXPERIMENTAL)
222 10 a null RR (EXPERIMENTAL)
223 11 a well known service description
224 12 a domain name pointer [REQ_PTR const]
225 13 host information
226 14 mailbox or mail list information
227 15 mail exchange
228 16 text strings
229 0x1c IPv6?
230 252 a request for a transfer of an entire zone
231 253 a request for mailbox-related records (MB, MG or MR)
232 254 a request for mail agent RRs (Obsolete - see MX)
233 255 a request for all records
234QCLASS a two octet code that specifies the class of the query.
235 1 the Internet
236 (others are historic only)
237 255 any class
238
2394.1.3. Resource record format
240
241The answer, authority, and additional sections all share the same format:
242a variable number of resource records, where the number of records
243is specified in the corresponding count field in the header.
244Each resource record has this format:
245 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
246 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
247 / /
248 / NAME /
249 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
250 | TYPE |
251 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
252 | CLASS |
253 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
254 | TTL |
255 | |
256 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
257 | RDLENGTH |
258 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--|
259 / RDATA /
260 / /
261 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
262NAME a domain name to which this resource record pertains.
263TYPE two octets containing one of the RR type codes. This
264 field specifies the meaning of the data in the RDATA field.
265CLASS two octets which specify the class of the data in the RDATA field.
266TTL a 32 bit unsigned integer that specifies the time interval
267 (in seconds) that the record may be cached.
268RDLENGTH a 16 bit integer, length in octets of the RDATA field.
269RDATA a variable length string of octets that describes the resource.
270 The format of this information varies according to the TYPE
271 and CLASS of the resource record.
272 If the TYPE is A and the CLASS is IN, it's a 4 octet IP address.
273
2744.1.4. Message compression
275
276In order to reduce the size of messages, domain names can be compressed.
277An entire domain name or a list of labels at the end of a domain name
278is replaced with a pointer to a prior occurance of the same name.
279
280The pointer takes the form of a two octet sequence:
281 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
282 | 1 1| OFFSET |
283 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
284The first two bits are ones. This allows a pointer to be distinguished
285from a label, since the label must begin with two zero bits because
286labels are restricted to 63 octets or less. The OFFSET field specifies
287an offset from the start of the message (i.e., the first octet
288of the ID field in the domain header).
289A zero offset specifies the first byte of the ID field, etc.
290Domain name in a message can be represented as either:
291 - a sequence of labels ending in a zero octet
292 - a pointer
293 - a sequence of labels ending with a pointer
294 */
295
296#define __FORCE_GLIBC
297#include <features.h>
298#include <string.h>
299#include <stdio.h>
300#include <stdio_ext.h>
301#include <signal.h>
302#include <errno.h>
303#include <sys/poll.h>
304#include <sys/socket.h>
305#include <sys/types.h>
306#include <sys/time.h>
307#include <netinet/in.h>
308#include <arpa/inet.h>
309#include <stdlib.h>
310#include <unistd.h>
311#include <resolv.h>
312#include <netdb.h>
313#include <ctype.h>
314#include <stdbool.h>
315#include <time.h>
316#include <arpa/nameser.h>
317#include <sys/utsname.h>
318#include <sys/un.h>
319#include <sys/stat.h>
320#include <bits/uClibc_mutex.h>
321#include <fcntl.h>
322#include "internal/parse_config.h"
323
324/* poll() is not supported in kernel <= 2.0, therefore if __NR_poll is
325 * not available, we assume an old Linux kernel is in use and we will
326 * use select() instead. */
327#include <sys/syscall.h>
328#ifndef __NR_poll
329# define USE_SELECT
330#endif
331
332#if defined __UCLIBC_HAS_IPV4__ && defined __UCLIBC_HAS_IPV6__
333#define IF_HAS_BOTH(...) __VA_ARGS__
334#else
335#define IF_HAS_BOTH(...)
336#endif
337
338
339#define MAX_RECURSE 5
340#define MAXALIASES (4)
341#define BUFSZ (80) /* one line */
342
343#define NS_TYPE_ELT 0x40 /*%< EDNS0 extended label type */
344#define DNS_LABELTYPE_BITSTRING 0x41
345
346#undef DEBUG
347/* #define DEBUG */
348
349#ifdef DEBUG
350#define DPRINTF(X,args...) fprintf(stderr, X, ##args)
351#else
352#define DPRINTF(X,args...)
353#endif
354
355/* Make sure the incoming char * buffer is aligned enough to handle our random
356 * structures. This define is the same as we use for malloc alignment (which
357 * has same requirements). The offset is the number of bytes we need to adjust
358 * in order to attain desired alignment.
359 */
360#define ALIGN_ATTR __alignof__(double __attribute_aligned__ (sizeof(size_t)))
361#define ALIGN_BUFFER_OFFSET(buf) ((ALIGN_ATTR - ((size_t)buf % ALIGN_ATTR)) % ALIGN_ATTR)
362
363
364/* Structs */
365struct resolv_header {
366 int id;
367 int qr, opcode, aa, tc, rd, ra, rcode;
368 int qdcount;
369 int ancount;
370 int nscount;
371 int arcount;
372};
373
374struct resolv_question {
375 char *dotted;
376 int qtype;
377 int qclass;
378};
379
380struct resolv_answer {
381 char *dotted;
382 int atype;
383 int aclass;
384 int ttl;
385 int rdlength;
386 const unsigned char *rdata;
387 int rdoffset;
388 char* buf;
389 size_t buflen;
390 size_t add_count;
391};
392
393enum etc_hosts_action {
394 GET_HOSTS_BYNAME = 0,
395 GETHOSTENT,
396 GET_HOSTS_BYADDR,
397};
398
399typedef union sockaddr46_t {
400 struct sockaddr sa;
401#ifdef __UCLIBC_HAS_IPV4__
402 struct sockaddr_in sa4;
403#endif
404#ifdef __UCLIBC_HAS_IPV6__
405 struct sockaddr_in6 sa6;
406#endif
407} sockaddr46_t;
408
409
410__UCLIBC_MUTEX_EXTERN(__resolv_lock);
411
412/* Protected by __resolv_lock */
413extern void (*__res_sync)(void) attribute_hidden;
414/*extern uint32_t __resolv_opts attribute_hidden; */
415extern uint8_t __resolv_timeout attribute_hidden;
416extern uint8_t __resolv_attempts attribute_hidden;
417extern unsigned __nameservers attribute_hidden;
418extern unsigned __searchdomains attribute_hidden;
419extern sockaddr46_t *__nameserver attribute_hidden;
420extern char **__searchdomain attribute_hidden;
421#ifdef __UCLIBC_HAS_IPV4__
422extern const struct sockaddr_in __local_nameserver attribute_hidden;
423#else
424extern const struct sockaddr_in6 __local_nameserver attribute_hidden;
425#endif
426/* Arbitrary */
427#define MAXLEN_searchdomain 128
428
429
430/* prototypes for internal functions */
431extern void endhostent_unlocked(void) attribute_hidden;
432extern int __get_hosts_byname_r(const char *name,
433 int type,
434 struct hostent *result_buf,
435 char *buf,
436 size_t buflen,
437 struct hostent **result,
438 int *h_errnop) attribute_hidden;
439extern int __get_hosts_byaddr_r(const char *addr,
440 int len,
441 int type,
442 struct hostent *result_buf,
443 char *buf,
444 size_t buflen,
445 struct hostent **result,
446 int *h_errnop) attribute_hidden;
447extern parser_t *__open_etc_hosts(void) attribute_hidden;
448extern int __read_etc_hosts_r(parser_t *parser,
449 const char *name,
450 int type,
451 enum etc_hosts_action action,
452 struct hostent *result_buf,
453 char *buf,
454 size_t buflen,
455 struct hostent **result,
456 int *h_errnop) attribute_hidden;
457extern int __dns_lookup(const char *name,
458 int type,
459 unsigned char **outpacket,
460 struct resolv_answer *a) attribute_hidden;
461extern int __encode_dotted(const char *dotted,
462 unsigned char *dest,
463 int maxlen) attribute_hidden;
464extern int __decode_dotted(const unsigned char *packet,
465 int offset,
466 int packet_len,
467 char *dest,
468 int dest_len) attribute_hidden;
469extern int __encode_header(struct resolv_header *h,
470 unsigned char *dest,
471 int maxlen) attribute_hidden;
472extern void __decode_header(unsigned char *data,
473 struct resolv_header *h) attribute_hidden;
474extern int __encode_question(const struct resolv_question *q,
475 unsigned char *dest,
476 int maxlen) attribute_hidden;
477extern int __encode_answer(struct resolv_answer *a,
478 unsigned char *dest,
479 int maxlen) attribute_hidden;
480extern void __open_nameservers(void) attribute_hidden;
481extern void __close_nameservers(void) attribute_hidden;
482extern int __hnbad(const char *dotted) attribute_hidden;
483
484/*
485 * Theory of operation.
486 *
487 * gethostbyname, getaddrinfo and friends end up here, and they sometimes
488 * need to talk to DNS servers. In order to do this, we need to read /etc/resolv.conf
489 * and determine servers' addresses and the like. resolv.conf format:
490 *
491 * nameserver <IP[v6]>
492 * Address of DNS server. Cumulative.
493 * If not specified, assumed to be on localhost.
494 * search <domain1>[ <domain2>]...
495 * Append these domains to unqualified names.
496 * See ndots:n option.
497 * $LOCALDOMAIN (space-separated list) overrides this.
498 * domain <domain>
499 * Effectively same as "search" with one domain.
500 * If no "domain" line is present, the domain is determined
501 * from the local host name returned by gethostname();
502 * the domain part is taken to be everything after the first dot.
503 * If there are no dots, there will be no "domain".
504 * The domain and search keywords are mutually exclusive.
505 * If more than one instance of these keywords is present,
506 * the last instance wins.
507 * sortlist 130.155.160.0[/255.255.240.0] 130.155.0.0
508 * Allows addresses returned by gethostbyname to be sorted.
509 * Not supported.
510 * options option[ option]...
511 * (so far we support timeout:n and attempts:n)
512 * $RES_OPTIONS (space-separated list) is to be added to "options"
513 * debug sets RES_DEBUG in _res.options
514 * ndots:n how many dots there should be so that name will be tried
515 * first as an absolute name before any search list elements
516 * are appended to it. Default 1
517 * timeout:n how long to wait for response. Default 5
518 * (sun seems to have retrans:n synonym)
519 * attempts:n number of rounds to do before giving up and returning
520 * an error. Default 2
521 * (sun seems to have retry:n synonym)
522 * rotate sets RES_ROTATE in _res.options, round robin
523 * selection of nameservers. Otherwise try
524 * the first listed server first every time
525 * no-check-names
526 * sets RES_NOCHECKNAME in _res.options, which disables
527 * checking of incoming host names for invalid characters
528 * such as underscore (_), non-ASCII, or control characters
529 * inet6 sets RES_USE_INET6 in _res.options. Try a AAAA query
530 * before an A query inside the gethostbyname(), and map
531 * IPv4 responses in IPv6 "tunnelled form" if no AAAA records
532 * are found but an A record set exists
533 * no_tld_query (FreeBSDism?)
534 * do not attempt to resolve names without dots
535 *
536 * We will read and analyze /etc/resolv.conf as needed before
537 * we do a DNS request. This happens in __dns_lookup.
538 * It is reread if its mtime is changed.
539 *
540 * BSD has res_init routine which is used to initialize resolver state
541 * which is held in global structure _res.
542 * Generally, programs call res_init, then fiddle with _res.XXX
543 * (_res.options and _res.nscount, _res.nsaddr_list[N]
544 * are popular targets of fiddling) and expect subsequent calls
545 * to gethostbyname, getaddrinfo, etc to use modified information.
546 *
547 * However, historical _res structure is quite awkward.
548 * Using it for storing /etc/resolv.conf info is not desirable,
549 * and __dns_lookup does not use it.
550 *
551 * We would like to avoid using it unless absolutely necessary.
552 * If user doesn't use res_init, we should arrange it so that
553 * _res structure doesn't even *get linked in* into user's application
554 * (imagine static uclibc build here).
555 *
556 * The solution is a __res_sync function pointer, which is normally NULL.
557 * But if res_init is called, it gets set and any subsequent gethostbyname
558 * et al "syncronizes" our internal structures with potentially
559 * modified _res.XXX stuff by calling __res_sync.
560 * The trick here is that if res_init is not used and not linked in,
561 * gethostbyname itself won't reference _res and _res won't be linked in
562 * either. Other possible methods like
563 * if (__res_sync_just_an_int_flag)
564 * __sync_me_with_res()
565 * would pull in __sync_me_with_res, which pulls in _res. Bad.
566 */
567
568
569#ifdef L_encodeh
570
571int attribute_hidden __encode_header(struct resolv_header *h, unsigned char *dest, int maxlen)
572{
573 if (maxlen < HFIXEDSZ)
574 return -1;
575
576 dest[0] = (h->id & 0xff00) >> 8;
577 dest[1] = (h->id & 0x00ff) >> 0;
578 dest[2] = (h->qr ? 0x80 : 0) |
579 ((h->opcode & 0x0f) << 3) |
580 (h->aa ? 0x04 : 0) |
581 (h->tc ? 0x02 : 0) |
582 (h->rd ? 0x01 : 0);
583 dest[3] = (h->ra ? 0x80 : 0) | (h->rcode & 0x0f);
584 dest[4] = (h->qdcount & 0xff00) >> 8;
585 dest[5] = (h->qdcount & 0x00ff) >> 0;
586 dest[6] = (h->ancount & 0xff00) >> 8;
587 dest[7] = (h->ancount & 0x00ff) >> 0;
588 dest[8] = (h->nscount & 0xff00) >> 8;
589 dest[9] = (h->nscount & 0x00ff) >> 0;
590 dest[10] = (h->arcount & 0xff00) >> 8;
591 dest[11] = (h->arcount & 0x00ff) >> 0;
592
593 return HFIXEDSZ;
594}
595#endif /* L_encodeh */
596
597
598#ifdef L_decodeh
599
600void attribute_hidden __decode_header(unsigned char *data,
601 struct resolv_header *h)
602{
603 h->id = (data[0] << 8) | data[1];
604 h->qr = (data[2] & 0x80) ? 1 : 0;
605 h->opcode = (data[2] >> 3) & 0x0f;
606 h->aa = (data[2] & 0x04) ? 1 : 0;
607 h->tc = (data[2] & 0x02) ? 1 : 0;
608 h->rd = (data[2] & 0x01) ? 1 : 0;
609 h->ra = (data[3] & 0x80) ? 1 : 0;
610 h->rcode = data[3] & 0x0f;
611 h->qdcount = (data[4] << 8) | data[5];
612 h->ancount = (data[6] << 8) | data[7];
613 h->nscount = (data[8] << 8) | data[9];
614 h->arcount = (data[10] << 8) | data[11];
615}
616#endif /* L_decodeh */
617
618
619#ifdef L_encoded
620
621/* Encode a dotted string into nameserver transport-level encoding.
622 This routine is fairly dumb, and doesn't attempt to compress
623 the data */
624int attribute_hidden __encode_dotted(const char *dotted, unsigned char *dest, int maxlen)
625{
626 unsigned used = 0;
627
628 while (dotted && *dotted) {
629 char *c = strchr(dotted, '.');
630 int l = c ? c - dotted : strlen(dotted);
631
632 /* two consecutive dots are not valid */
633 if (l == 0)
634 return -1;
635
636 if (l >= (maxlen - used - 1))
637 return -1;
638
639 dest[used++] = l;
640 memcpy(dest + used, dotted, l);
641 used += l;
642
643 if (!c)
644 break;
645 dotted = c + 1;
646 }
647
648 if (maxlen < 1)
649 return -1;
650
651 dest[used++] = 0;
652
653 return used;
654}
655#endif /* L_encoded */
656
657
658#ifdef L_decoded
659
660/* Decode a dotted string from nameserver transport-level encoding.
661 This routine understands compressed data. */
662int attribute_hidden __decode_dotted(const unsigned char *packet,
663 int offset,
664 int packet_len,
665 char *dest,
666 int dest_len)
667{
668 unsigned b;
669 bool measure = 1;
670 unsigned total = 0;
671 unsigned used = 0;
672
673 if (!packet)
674 return -1;
675
676 while (1) {
677 if (offset >= packet_len)
678 return -1;
679 b = packet[offset++];
680 if (b == 0)
681 break;
682
683 if (measure)
684 total++;
685
686 if ((b & 0xc0) == 0xc0) {
687 if (offset >= packet_len)
688 return -1;
689 if (measure)
690 total++;
691 /* compressed item, redirect */
692 offset = ((b & 0x3f) << 8) | packet[offset];
693 measure = 0;
694 continue;
695 }
696
697 if (used + b + 1 >= dest_len)
698 return -1;
699 if (offset + b >= packet_len)
700 return -1;
701 memcpy(dest + used, packet + offset, b);
702 offset += b;
703 used += b;
704
705 if (measure)
706 total += b;
707
708 if (packet[offset] != 0)
709 dest[used++] = '.';
710 else
711 dest[used++] = '\0';
712 }
713
714 /* The null byte must be counted too */
715 if (measure)
716 total++;
717
718 DPRINTF("Total decode len = %d\n", total);
719
720 return total;
721}
722#endif /* L_decoded */
723
724
725#ifdef L_encodeq
726
727int attribute_hidden __encode_question(const struct resolv_question *q,
728 unsigned char *dest,
729 int maxlen)
730{
731 int i;
732
733 i = __encode_dotted(q->dotted, dest, maxlen);
734 if (i < 0)
735 return i;
736
737 dest += i;
738 maxlen -= i;
739
740 if (maxlen < 4)
741 return -1;
742
743 dest[0] = (q->qtype & 0xff00) >> 8;
744 dest[1] = (q->qtype & 0x00ff) >> 0;
745 dest[2] = (q->qclass & 0xff00) >> 8;
746 dest[3] = (q->qclass & 0x00ff) >> 0;
747
748 return i + 4;
749}
750#endif /* L_encodeq */
751
752
753#ifdef L_encodea
754
755int attribute_hidden __encode_answer(struct resolv_answer *a, unsigned char *dest, int maxlen)
756{
757 int i;
758
759 i = __encode_dotted(a->dotted, dest, maxlen);
760 if (i < 0)
761 return i;
762
763 dest += i;
764 maxlen -= i;
765
766 if (maxlen < (RRFIXEDSZ + a->rdlength))
767 return -1;
768
769 *dest++ = (a->atype & 0xff00) >> 8;
770 *dest++ = (a->atype & 0x00ff) >> 0;
771 *dest++ = (a->aclass & 0xff00) >> 8;
772 *dest++ = (a->aclass & 0x00ff) >> 0;
773 *dest++ = (a->ttl & 0xff000000) >> 24;
774 *dest++ = (a->ttl & 0x00ff0000) >> 16;
775 *dest++ = (a->ttl & 0x0000ff00) >> 8;
776 *dest++ = (a->ttl & 0x000000ff) >> 0;
777 *dest++ = (a->rdlength & 0xff00) >> 8;
778 *dest++ = (a->rdlength & 0x00ff) >> 0;
779 memcpy(dest, a->rdata, a->rdlength);
780
781 return i + RRFIXEDSZ + a->rdlength;
782}
783#endif /* L_encodea */
784
785
786#ifdef CURRENTLY_UNUSED
787#ifdef L_encodep
788
789int __encode_packet(struct resolv_header *h,
790 struct resolv_question **q,
791 struct resolv_answer **an,
792 struct resolv_answer **ns,
793 struct resolv_answer **ar,
794 unsigned char *dest, int maxlen) attribute_hidden;
795int __encode_packet(struct resolv_header *h,
796 struct resolv_question **q,
797 struct resolv_answer **an,
798 struct resolv_answer **ns,
799 struct resolv_answer **ar,
800 unsigned char *dest, int maxlen)
801{
802 int i, total = 0;
803 unsigned j;
804
805 i = __encode_header(h, dest, maxlen);
806 if (i < 0)
807 return i;
808
809 dest += i;
810 maxlen -= i;
811 total += i;
812
813 for (j = 0; j < h->qdcount; j++) {
814 i = __encode_question(q[j], dest, maxlen);
815 if (i < 0)
816 return i;
817 dest += i;
818 maxlen -= i;
819 total += i;
820 }
821
822 for (j = 0; j < h->ancount; j++) {
823 i = __encode_answer(an[j], dest, maxlen);
824 if (i < 0)
825 return i;
826 dest += i;
827 maxlen -= i;
828 total += i;
829 }
830 for (j = 0; j < h->nscount; j++) {
831 i = __encode_answer(ns[j], dest, maxlen);
832 if (i < 0)
833 return i;
834 dest += i;
835 maxlen -= i;
836 total += i;
837 }
838 for (j = 0; j < h->arcount; j++) {
839 i = __encode_answer(ar[j], dest, maxlen);
840 if (i < 0)
841 return i;
842 dest += i;
843 maxlen -= i;
844 total += i;
845 }
846
847 return total;
848}
849#endif /* L_encodep */
850
851
852#ifdef L_decodep
853
854int __decode_packet(unsigned char *data, struct resolv_header *h) attribute_hidden;
855int __decode_packet(unsigned char *data, struct resolv_header *h)
856{
857 __decode_header(data, h);
858 return HFIXEDSZ;
859}
860#endif /* L_decodep */
861
862
863#ifdef L_formquery
864
865int __form_query(int id,
866 const char *name,
867 int type,
868 unsigned char *packet,
869 int maxlen);
870int __form_query(int id,
871 const char *name,
872 int type,
873 unsigned char *packet,
874 int maxlen)
875{
876 struct resolv_header h;
877 struct resolv_question q;
878 int i, j;
879
880 memset(&h, 0, sizeof(h));
881 h.id = id;
882 h.qdcount = 1;
883
884 q.dotted = (char *) name;
885 q.qtype = type;
886 q.qclass = C_IN; /* CLASS_IN */
887
888 i = __encode_header(&h, packet, maxlen);
889 if (i < 0)
890 return i;
891
892 j = __encode_question(&q, packet + i, maxlen - i);
893 if (j < 0)
894 return j;
895
896 return i + j;
897}
898#endif /* L_formquery */
899#endif /* CURRENTLY_UNUSED */
900
901
902#ifdef L_opennameservers
903
904# if __BYTE_ORDER == __LITTLE_ENDIAN
905#define NAMESERVER_PORT_N (__bswap_constant_16(NAMESERVER_PORT))
906#else
907#define NAMESERVER_PORT_N NAMESERVER_PORT
908#endif
909
910__UCLIBC_MUTEX_INIT(__resolv_lock, PTHREAD_MUTEX_INITIALIZER);
911
912/* Protected by __resolv_lock */
913void (*__res_sync)(void);
914/*uint32_t __resolv_opts; */
915uint8_t __resolv_timeout = RES_TIMEOUT;
916uint8_t __resolv_attempts = RES_DFLRETRY;
917unsigned __nameservers;
918unsigned __searchdomains;
919sockaddr46_t *__nameserver;
920char **__searchdomain;
921#ifdef __UCLIBC_HAS_IPV4__
922const struct sockaddr_in __local_nameserver = {
923 .sin_family = AF_INET,
924 .sin_port = NAMESERVER_PORT_N,
925};
926#else
927const struct sockaddr_in6 __local_nameserver = {
928 .sin6_family = AF_INET6,
929 .sin6_port = NAMESERVER_PORT_N,
930};
931#endif
932
933/* Helpers. Both stop on EOL, if it's '\n', it is converted to NUL first */
934static char *skip_nospace(char *p)
935{
936 while (*p != '\0' && !isspace(*p)) {
937 if (*p == '\n') {
938 *p = '\0';
939 break;
940 }
941 p++;
942 }
943 return p;
944}
945static char *skip_and_NUL_space(char *p)
946{
947 /* NB: '\n' is not isspace! */
948 while (1) {
949 char c = *p;
950 if (c == '\0' || !isspace(c))
951 break;
952 *p = '\0';
953 if (c == '\n' || c == '#')
954 break;
955 p++;
956 }
957 return p;
958}
959
960/* Must be called under __resolv_lock. */
961void attribute_hidden __open_nameservers(void)
962{
963 static uint32_t resolv_conf_mtime;
964
965 char szBuffer[MAXLEN_searchdomain];
966 FILE *fp;
967 int i;
968 sockaddr46_t sa;
969
970 if (!__res_sync) {
971 /* Reread /etc/resolv.conf if it was modified. */
972 struct stat sb;
973 if (stat("/etc/resolv.conf", &sb) != 0)
974 sb.st_mtime = 0;
975 if (resolv_conf_mtime != (uint32_t)sb.st_mtime) {
976 resolv_conf_mtime = sb.st_mtime;
977 __close_nameservers(); /* force config reread */
978 }
979 }
980
981 if (__nameservers)
982 goto sync;
983
984 __resolv_timeout = RES_TIMEOUT;
985 __resolv_attempts = RES_DFLRETRY;
986
987 fp = fopen("/etc/resolv.conf", "r");
988#ifdef FALLBACK_TO_CONFIG_RESOLVCONF
989 if (!fp) {
990 /* If we do not have a pre-populated /etc/resolv.conf then
991 try to use the one from /etc/config which exists on numerous
992 systems ranging from some uClinux to IRIX installations and
993 may be the only /etc dir that was mounted rw. */
994 fp = fopen("/etc/config/resolv.conf", "r");
995 }
996#endif
997
998 if (fp) {
999 while (fgets(szBuffer, sizeof(szBuffer), fp) != NULL) {
1000 void *ptr;
1001 char *keyword, *p;
1002
1003 keyword = p = skip_and_NUL_space(szBuffer);
1004 /* skip keyword */
1005 p = skip_nospace(p);
1006 /* find next word */
1007 p = skip_and_NUL_space(p);
1008
1009 if (strcmp(keyword, "nameserver") == 0) {
1010 /* terminate IP addr */
1011 *skip_nospace(p) = '\0';
1012 memset(&sa, 0, sizeof(sa));
1013 if (0) /* nothing */;
1014#ifdef __UCLIBC_HAS_IPV6__
1015 else if (inet_pton(AF_INET6, p, &sa.sa6.sin6_addr) > 0) {
1016 sa.sa6.sin6_family = AF_INET6;
1017 sa.sa6.sin6_port = htons(NAMESERVER_PORT);
1018 }
1019#endif
1020#ifdef __UCLIBC_HAS_IPV4__
1021 else if (inet_pton(AF_INET, p, &sa.sa4.sin_addr) > 0) {
1022 sa.sa4.sin_family = AF_INET;
1023 sa.sa4.sin_port = htons(NAMESERVER_PORT);
1024 }
1025#endif
1026 else
1027 continue; /* garbage on this line */
1028 ptr = realloc(__nameserver, (__nameservers + 1) * sizeof(__nameserver[0]));
1029 if (!ptr)
1030 continue;
1031 __nameserver = ptr;
1032 __nameserver[__nameservers++] = sa; /* struct copy */
1033 continue;
1034 }
1035 if (strcmp(keyword, "domain") == 0 || strcmp(keyword, "search") == 0) {
1036 char *p1;
1037
1038 /* free old domains ("last 'domain' or 'search' wins" rule) */
1039 while (__searchdomains)
1040 free(__searchdomain[--__searchdomains]);
1041 /*free(__searchdomain);*/
1042 /*__searchdomain = NULL; - not necessary */
1043 next_word:
1044 /* terminate current word */
1045 p1 = skip_nospace(p);
1046 /* find next word (maybe) */
1047 p1 = skip_and_NUL_space(p1);
1048 /* add it */
1049 ptr = realloc(__searchdomain, (__searchdomains + 1) * sizeof(__searchdomain[0]));
1050 if (!ptr)
1051 continue;
1052 __searchdomain = ptr;
1053 /* NB: strlen(p) <= MAXLEN_searchdomain) because szBuffer[] is smaller */
1054 ptr = strdup(p);
1055 if (!ptr)
1056 continue;
1057 DPRINTF("adding search %s\n", (char*)ptr);
1058 __searchdomain[__searchdomains++] = (char*)ptr;
1059 p = p1;
1060 if (*p)
1061 goto next_word;
1062 continue;
1063 }
1064 /* if (strcmp(keyword, "sortlist") == 0)... */
1065 if (strcmp(keyword, "options") == 0) {
1066 char *p1;
1067 uint8_t *what;
1068
1069 if (p == NULL || (p1 = strchr(p, ':')) == NULL)
1070 continue;
1071 *p1++ = '\0';
1072 if (strcmp(p, "timeout") == 0)
1073 what = &__resolv_timeout;
1074 else if (strcmp(p, "attempts") == 0)
1075 what = &__resolv_attempts;
1076 else
1077 continue;
1078 *what = atoi(p1);
1079 DPRINTF("option %s:%d\n", p, *what);
1080 }
1081 }
1082 fclose(fp);
1083 }
1084 if (__nameservers == 0) {
1085 /* Have to handle malloc failure! What a mess...
1086 * And it's not only here, we need to be careful
1087 * to never write into __nameserver[0] if it points
1088 * to constant __local_nameserver, or free it. */
1089 __nameserver = malloc(sizeof(__nameserver[0]));
1090 if (__nameserver)
1091 memcpy(__nameserver, &__local_nameserver, sizeof(__local_nameserver));
1092 else
1093 __nameserver = (void*) &__local_nameserver;
1094 __nameservers++;
1095 }
1096 if (__searchdomains == 0) {
1097 char buf[256];
1098 char *p;
1099 i = gethostname(buf, sizeof(buf) - 1);
1100 buf[sizeof(buf) - 1] = '\0';
1101 if (i == 0 && (p = strchr(buf, '.')) != NULL && p[1]) {
1102 p = strdup(p + 1);
1103 if (!p)
1104 goto err;
1105 __searchdomain = malloc(sizeof(__searchdomain[0]));
1106 if (!__searchdomain) {
1107 free(p);
1108 goto err;
1109 }
1110 __searchdomain[0] = p;
1111 __searchdomains++;
1112 err: ;
1113 }
1114 }
1115 DPRINTF("nameservers = %d\n", __nameservers);
1116
1117 sync:
1118 if (__res_sync)
1119 __res_sync();
1120}
1121#endif /* L_opennameservers */
1122
1123
1124#ifdef L_closenameservers
1125
1126/* Must be called under __resolv_lock. */
1127void attribute_hidden __close_nameservers(void)
1128{
1129 if (__nameserver != (void*) &__local_nameserver)
1130 free(__nameserver);
1131 __nameserver = NULL;
1132 __nameservers = 0;
1133 while (__searchdomains)
1134 free(__searchdomain[--__searchdomains]);
1135 free(__searchdomain);
1136 __searchdomain = NULL;
1137 /*__searchdomains = 0; - already is */
1138}
1139#endif /* L_closenameservers */
1140
1141
1142#ifdef L_dnslookup
1143
1144/* Helpers */
1145static int __length_question(const unsigned char *data, int maxlen)
1146{
1147 const unsigned char *start;
1148 unsigned b;
1149
1150 if (!data)
1151 return -1;
1152
1153 start = data;
1154 while (1) {
1155 if (maxlen <= 0)
1156 return -1;
1157 b = *data++;
1158 if (b == 0)
1159 break;
1160 if ((b & 0xc0) == 0xc0) {
1161 /* It's a "compressed" name. */
1162 data++; /* skip lsb of redirected offset */
1163 maxlen -= 2;
1164 break;
1165 }
1166 data += b;
1167 maxlen -= (b + 1); /* account for data++ above */
1168 }
1169 /* Up to here we were skipping encoded name */
1170
1171 /* Account for QTYPE and QCLASS fields */
1172 if (maxlen < 4)
1173 return -1;
1174 return data - start + 2 + 2;
1175}
1176
1177static int __decode_answer(const unsigned char *message, /* packet */
1178 int offset,
1179 int len, /* total packet len */
1180 struct resolv_answer *a)
1181{
1182 char temp[256];
1183 int i;
1184
1185 DPRINTF("decode_answer(start): off %d, len %d\n", offset, len);
1186 i = __decode_dotted(message, offset, len, temp, sizeof(temp));
1187 if (i < 0)
1188 return i;
1189
1190 message += offset + i;
1191 len -= i + RRFIXEDSZ + offset;
1192 if (len < 0) {
1193 DPRINTF("decode_answer: off %d, len %d, i %d\n", offset, len, i);
1194 return len;
1195 }
1196
1197/* TODO: what if strdup fails? */
1198 a->dotted = strdup(temp);
1199 a->atype = (message[0] << 8) | message[1];
1200 message += 2;
1201 a->aclass = (message[0] << 8) | message[1];
1202 message += 2;
1203 a->ttl = (message[0] << 24) |
1204 (message[1] << 16) | (message[2] << 8) | (message[3] << 0);
1205 message += 4;
1206 a->rdlength = (message[0] << 8) | message[1];
1207 message += 2;
1208 a->rdata = message;
1209 a->rdoffset = offset + i + RRFIXEDSZ;
1210
1211 DPRINTF("i=%d,rdlength=%d\n", i, a->rdlength);
1212
1213 if (len < a->rdlength)
1214 return -1;
1215 return i + RRFIXEDSZ + a->rdlength;
1216}
1217
1218#define __UCLIBC_DNSRAND_MODE_URANDOM__ 1
1219
1220#if defined __UCLIBC_DNSRAND_MODE_URANDOM__ || defined __UCLIBC_DNSRAND_MODE_PRNGPLUS__
1221
1222/*
1223 * Get a random int from urandom.
1224 * Return 0 on success and -1 on failure.
1225 *
1226 * This will dip into the entropy pool maintaind by the system.
1227 */
1228int _dnsrand_getrandom_urandom(int *rand_value) {
1229 static int urand_fd = -1;
1230 static int errCnt = 0;
1231 if (urand_fd == -1) {
1232 urand_fd = open("/dev/urandom", O_RDONLY);
1233 if (urand_fd == -1) {
1234 if ((errCnt % 16) == 0) {
1235 DPRINTF("uCLibC:WARN:DnsRandGetRand: urandom is unavailable...\n");
1236 }
1237 errCnt += 1;
1238 return -1;
1239 }
1240 }
1241 if (read(urand_fd, rand_value, sizeof(int)) == sizeof(int)) { /* small reads like few bytes here should be safe in general. */
1242 DPRINTF("uCLibC:DBUG:DnsRandGetRand: URandom:0x%lx\n", *rand_value);
1243 return 0;
1244 }
1245 return -1;
1246}
1247
1248#endif
1249
1250#if defined __UCLIBC_DNSRAND_MODE_CLOCK__ || defined __UCLIBC_DNSRAND_MODE_PRNGPLUS__
1251
1252/*
1253 * Try get a sort of random int by looking at current time in system realtime clock.
1254 * Return 0 on success and -1 on failure.
1255 *
1256 * This requries the realtime related uclibc feature to be enabled and also
1257 * the system should have a clock source with nanosec resolution to be mapped
1258 * to CLOCK_REALTIME, for this to generate values that appear random plausibly.
1259 */
1260int _dnsrand_getrandom_clock(int *rand_value) {
1261#if defined __USE_POSIX199309 && defined __UCLIBC_HAS_REALTIME__
1262 struct timespec ts;
1263 if (clock_gettime(CLOCK_REALTIME, &ts) == 0) {
1264 *rand_value = (ts.tv_sec + ts.tv_nsec) % INT_MAX;
1265 DPRINTF("uCLibC:DBUG:DnsRandGetRand: Clock:0x%lx\n", *rand_value);
1266 return 0;
1267 }
1268#endif
1269 return -1;
1270}
1271
1272#endif
1273
1274#ifdef __UCLIBC_DNSRAND_MODE_PRNGPLUS__
1275
1276/*
1277 * Try get a random int by first checking at urandom and then at realtime clock.
1278 * Return 0 on success and -1 on failure.
1279 *
1280 * Chances are most embedded targets using linux/bsd/... could have urandom and
1281 * also it can potentially give better random values, so try urandom first.
1282 * However if there is failure wrt urandom, then try realtime clock based helper.
1283 */
1284int _dnsrand_getrandom_urcl(int *rand_value) {
1285 if (_dnsrand_getrandom_urandom(rand_value) == 0) {
1286 return 0;
1287 }
1288 if (_dnsrand_getrandom_clock(rand_value) == 0) {
1289 return 0;
1290 }
1291 DPRINTF("uCLibC:DBUG:DnsRandGetRand: URCL:Nothing:0x%lx\n", *rand_value);
1292 return -1;
1293}
1294
1295#define DNSRAND_PRNGSTATE_INT32LEN 32
1296#undef DNSRAND_PRNGRUN_SHORT
1297#ifdef DNSRAND_PRNGRUN_SHORT
1298#define DNSRAND_RESEED_OP1 (DNSRAND_PRNGSTATE_INT32LEN/2)
1299#define DNSRAND_RESEED_OP2 (DNSRAND_PRNGSTATE_INT32LEN/4)
1300#else
1301#define DNSRAND_RESEED_OP1 (DNSRAND_PRNGSTATE_INT32LEN*6)
1302#define DNSRAND_RESEED_OP2 DNSRAND_PRNGSTATE_INT32LEN
1303#endif
1304/*
1305 * This logic uses uclibc's random PRNG to generate random int. This keeps the
1306 * logic fast by not depending on a more involved CPRNG kind of logic nor on a
1307 * kernel to user space handshake at the core.
1308 *
1309 * However to ensure that pseudo random sequences based on a given seeding of the
1310 * PRNG logic, is not generated for too long so as to allow a advarsary to try guess
1311 * the internal states of the prng logic and inturn the next number, srandom is
1312 * used periodically to reseed PRNG logic, when and where possible.
1313 *
1314 * To help with this periodic reseeding, by default the logic will first try to
1315 * see if it can get some relatively random number using /dev/urandom. If not it
1316 * will try use the current time to generate plausibly random value as substitute.
1317 * If neither of these sources are available, then the prng itself is used to seed
1318 * a new state, so that the pseudo random sequence can continue, which is better
1319 * than the fallback simple counter.
1320 *
1321 * Also to add bit more of variance wrt this periodic reseeding, the period interval
1322 * at which this reseeding occurs keeps changing within a predefined window. The
1323 * window is controlled based on how often this logic is called (which currently
1324 * will depend on how often requests for dns query (and inturn dnsrand_next) occurs,
1325 * as well as a self driven periodically changing request count boundry.
1326 *
1327 * The internally generated random values are not directly exposed, instead result
1328 * of adjacent values large mult with mod is used to greatly reduce the possibility
1329 * of trying to infer the internal values from externally exposed random values.
1330 * This should also make longer run of prng ok to an extent.
1331 *
1332 * NOTE: The Random PRNG used here maintains its own internal state data, so that
1333 * it doesnt impact any other users of random prng calls in the system/program
1334 * compiled against uclibc.
1335 *
1336 * NOTE: If your target doesnt support int64_t, then the code uses XOR instead of
1337 * mult with mod based transform on the internal random sequence, to generate the
1338 * random number that is returned. However as XOR is not a one way transform, this
1339 * is supported only in DNSRAND_PRNGRUN_SHORT mode by default, which needs to be
1340 * explicitly enabled by the platform developer, by defining the same.
1341 *
1342 */
1343int _dnsrand_getrandom_prng(int *rand_value) {
1344 static int cnt = -1;
1345 static int nextReSeedWindow = DNSRAND_RESEED_OP1;
1346 static int32_t prngState[DNSRAND_PRNGSTATE_INT32LEN]; /* prng logic internally assumes int32_t wrt state array, so to help align if required */
1347 static struct random_data prngData;
1348 int32_t val, val2;
1349 int calc;
1350 int prngSeed = 0x19481869;
1351
1352 if (cnt == -1) {
1353 _dnsrand_getrandom_urcl(&prngSeed);
1354 memset(&prngData, 0, sizeof(prngData));
1355 initstate_r(prngSeed, (char*)&prngState, DNSRAND_PRNGSTATE_INT32LEN*4, &prngData);
1356 }
1357 cnt += 1;
1358 if ((cnt % nextReSeedWindow) == 0) {
1359 if (_dnsrand_getrandom_urcl(&prngSeed) != 0) {
1360 random_r(&prngData, &prngSeed);
1361 }
1362 srandom_r(prngSeed, &prngData);
1363 random_r(&prngData, &val);
1364 nextReSeedWindow = DNSRAND_RESEED_OP1 + (val % DNSRAND_RESEED_OP2);
1365 DPRINTF("uCLibC:DBUG:DnsRandNext: PRNGWindow:%d\n", nextReSeedWindow);
1366 cnt = 0;
1367 }
1368 random_r(&prngData, &val);
1369 random_r(&prngData, &val2);
1370#ifdef INT64_MAX
1371 calc = ((int64_t)val * (int64_t)val2) % INT_MAX;
1372#else
1373# ifdef DNSRAND_PRNGRUN_SHORT
1374 calc = val ^ val2;
1375# warning "[No int64] using xor based random number transform logic in short prng run mode, bcas int64_t not supported on this target"
1376# else
1377# error "[No int64] using xor based random number transform logic only supported with short prng runs, you may want to define DNSRAND_PRNGRUN_SHORT"
1378# endif
1379#endif
1380 *rand_value = calc;
1381 DPRINTF("uCLibC:DBUG:DnsRandGetRand: PRNGPlus: %d, 0x%lx 0x%lx 0x%lx\n", cnt, val, val2, *rand_value);
1382 return 0;
1383}
1384
1385#endif
1386
1387/**
1388 * If DNS query's id etal is generated using a simple counter, then it can be
1389 * subjected to dns poisoning relatively easily, so adding some randomness can
1390 * increase the difficulty wrt dns poisoning and is thus desirable.
1391 *
1392 * However given that embedded targets may or may not have different sources available
1393 * with them to try generate random values, this logic tries to provides flexibility
1394 * to the platform developer to decide, how they may want to handle this.
1395 *
1396 * If a given target doesnt support urandom nor realtime clock OR for some reason
1397 * if the platform developer doesnt want to use random dns query id etal, then
1398 * they can define __UCLIBC_DNSRAND_MODE_SIMPLECOUNTER__ so that a simple incrementing
1399 * counter is used.
1400 *
1401 * However if the target has support for urandom or realtime clock, then the prngplus
1402 * based random generation tries to give a good balance between randomness and performance.
1403 * This is the default and is enabled when no other mode is defined. It is also indirectly
1404 * enabled by defining __UCLIBC_DNSRAND_MODE_PRNGPLUS__ instead of the other modes.
1405 *
1406 * If urandom is available on the target and one wants to keep things simple and use
1407 * it directly, then one can define __UCLIBC_DNSRAND_MODE_URANDOM__. Do note that this
1408 * will be relatively slower compared to other options. But it can normally generate
1409 * good random values/ids by dipping into the entropy pool available in the system.
1410 *
1411 * If system realtime clock is available on target and enabled, then if one wants to
1412 * keep things simple and use it directly, then define __UCLIBC_DNSRAND_MODE_CLOCK__.
1413 * Do note that this requires nanosecond resolution / granularity wrt the realtime
1414 * clock source to generate plausibly random values/ids. As processor &/ io performance
1415 * improves, the effectiveness of this strategy can be impacted in some cases.
1416 *
1417 * If either the URandom or Clock based get random fails, then the logic is setup to
1418 * try fallback to the simple counter mode, with the help of the def_value, which is
1419 * setup to be the next increment wrt the previously generated / used value, by the
1420 * caller of dnsrand_next.
1421 *
1422 */
1423int dnsrand_next(int def_value) {
1424 int val = def_value;
1425#if defined __UCLIBC_DNSRAND_MODE_SIMPLECOUNTER__
1426 return val;
1427#elif defined __UCLIBC_DNSRAND_MODE_URANDOM__
1428 if (_dnsrand_getrandom_urandom(&val) == 0) {
1429 return val;
1430 }
1431 return def_value;
1432#elif defined __UCLIBC_DNSRAND_MODE_CLOCK__
1433 if (_dnsrand_getrandom_clock(&val) == 0) {
1434 return val;
1435 }
1436 return def_value;
1437#else
1438 if (_dnsrand_getrandom_prng(&val) == 0) {
1439 return val;
1440 }
1441 return def_value;
1442#endif
1443}
1444
1445int dnsrand_setup(int def_value) {
1446 return def_value;
1447}
1448
1449/* On entry:
1450 * a.buf(len) = auxiliary buffer for IP addresses after first one
1451 * a.add_count = how many additional addresses are there already
1452 * outpacket = where to save ptr to raw packet? can be NULL
1453 * On exit:
1454 * ret < 0: error, all other data is not valid
1455 * ret >= 0: length of reply packet
1456 * a.add_count & a.buf: updated
1457 * a.rdlength: length of addresses (4 bytes for IPv4)
1458 * *outpacket: updated (packet is malloced, you need to free it)
1459 * a.rdata: points into *outpacket to 1st IP addr
1460 * NB: don't pass outpacket == NULL if you need to use a.rdata!
1461 * a.atype: type of query?
1462 * a.dotted: which name we _actually_ used. May contain search domains
1463 * appended. (why the filed is called "dotted" I have no idea)
1464 * This is a malloced string. May be NULL because strdup failed.
1465 */
1466int attribute_hidden __dns_lookup(const char *name,
1467 int type,
1468 unsigned char **outpacket,
1469 struct resolv_answer *a)
1470{
1471 /* Protected by __resolv_lock: */
1472 static int last_ns_num = 0;
1473 static uint16_t last_id = 1;
1474
1475 int i, j, fd, rc;
1476 int packet_len;
1477 int name_len;
1478#ifdef USE_SELECT
1479 struct timeval tv;
1480 fd_set fds;
1481#else
1482 struct pollfd fds;
1483#endif
1484 struct resolv_header h;
1485 struct resolv_question q;
1486 struct resolv_answer ma;
1487 bool first_answer = 1;
1488 int retries_left;
1489 unsigned char *packet = malloc(PACKETSZ);
1490 char *lookup;
1491 int variant = -1; /* search domain to append, -1: none */
1492 int local_ns_num = -1; /* Nth server to use */
1493 int local_id = local_id; /* for compiler */
1494 int sdomains;
1495 bool ends_with_dot;
1496 sockaddr46_t sa;
1497 int num_answers;
1498
1499 fd = -1;
1500 lookup = NULL;
1501 name_len = strlen(name);
1502 if ((unsigned)name_len >= MAXDNAME - MAXLEN_searchdomain - 2)
1503 goto fail; /* paranoia */
1504 lookup = malloc(name_len + 1/*for '.'*/ + MAXLEN_searchdomain + 1);
1505 if (!packet || !lookup || !name[0])
1506 goto fail;
1507 ends_with_dot = (name[name_len - 1] == '.');
1508 /* no strcpy! paranoia, user might change name[] under us */
1509 memcpy(lookup, name, name_len);
1510
1511 DPRINTF("Looking up type %d answer for '%s'\n", type, name);
1512 retries_left = 0; /* for compiler */
1513 do {
1514 int pos;
1515 unsigned reply_timeout;
1516
1517 if (fd != -1) {
1518 close(fd);
1519 fd = -1;
1520 }
1521
1522 /* Mess with globals while under lock */
1523 /* NB: even data *pointed to* by globals may vanish
1524 * outside the locks. We should assume any and all
1525 * globals can completely change between locked
1526 * code regions. OTOH, this is rare, so we don't need
1527 * to handle it "nicely" (do not skip servers,
1528 * search domains, etc), we only need to ensure
1529 * we do not SEGV, use freed+overwritten data
1530 * or do other Really Bad Things. */
1531 __UCLIBC_MUTEX_LOCK(__resolv_lock);
1532 __open_nameservers();
1533 sdomains = __searchdomains;
1534 lookup[name_len] = '\0';
1535 if ((unsigned)variant < sdomains) {
1536 /* lookup is name_len + 1 + MAXLEN_searchdomain + 1 long */
1537 /* __searchdomain[] is not bigger than MAXLEN_searchdomain */
1538 lookup[name_len] = '.';
1539 strcpy(&lookup[name_len + 1], __searchdomain[variant]);
1540 }
1541 /* first time? pick starting server etc */
1542 if (local_ns_num < 0) {
1543 local_id = dnsrand_setup(last_id);
1544/*TODO: implement /etc/resolv.conf's "options rotate"
1545 (a.k.a. RES_ROTATE bit in _res.options)
1546 local_ns_num = 0;
1547 if (_res.options & RES_ROTATE) */
1548 local_ns_num = last_ns_num;
1549 retries_left = __nameservers * __resolv_attempts;
1550 }
1551 retries_left--;
1552 if (local_ns_num >= __nameservers)
1553 local_ns_num = 0;
1554 local_id = dnsrand_next(++local_id);
1555 local_id &= 0xffff;
1556 /* write new values back while still under lock */
1557 last_id = local_id;
1558 last_ns_num = local_ns_num;
1559 /* struct copy */
1560 /* can't just take a pointer, __nameserver[x]
1561 * is not safe to use outside of locks */
1562 sa = __nameserver[local_ns_num];
1563 __UCLIBC_MUTEX_UNLOCK(__resolv_lock);
1564
1565 memset(packet, 0, PACKETSZ);
1566 memset(&h, 0, sizeof(h));
1567
1568 /* encode header */
1569 h.id = local_id;
1570 h.qdcount = 1;
1571 h.rd = 1;
1572 DPRINTF("encoding header\n", h.rd);
1573 i = __encode_header(&h, packet, PACKETSZ);
1574 if (i < 0)
1575 goto fail;
1576
1577 /* encode question */
1578 DPRINTF("lookup name: %s\n", lookup);
1579 q.dotted = lookup;
1580 q.qtype = type;
1581 q.qclass = C_IN; /* CLASS_IN */
1582 j = __encode_question(&q, packet+i, PACKETSZ-i);
1583 if (j < 0)
1584 goto fail;
1585 packet_len = i + j;
1586
1587 /* send packet */
1588#ifdef DEBUG
1589 {
1590 const socklen_t plen = sa.sa.sa_family == AF_INET ? INET_ADDRSTRLEN : INET6_ADDRSTRLEN;
1591 char *pbuf = malloc(plen);
1592 if (pbuf == NULL) ;/* nothing */
1593#ifdef __UCLIBC_HAS_IPV6__
1594 else if (sa.sa.sa_family == AF_INET6)
1595 pbuf = (char*)inet_ntop(AF_INET6, &sa.sa6.sin6_addr, pbuf, plen);
1596#endif
1597#ifdef __UCLIBC_HAS_IPV4__
1598 else if (sa.sa.sa_family == AF_INET)
1599 pbuf = (char*)inet_ntop(AF_INET, &sa.sa4.sin_addr, pbuf, plen);
1600#endif
1601 DPRINTF("On try %d, sending query to %s, port %d\n",
1602 retries_left, pbuf, NAMESERVER_PORT);
1603 free(pbuf);
1604 }
1605#endif
1606 fd = socket(sa.sa.sa_family, SOCK_DGRAM, IPPROTO_UDP);
1607 if (fd < 0) /* paranoia */
1608 goto try_next_server;
1609 rc = connect(fd, &sa.sa, sizeof(sa));
1610 if (rc < 0) {
1611 /*if (errno == ENETUNREACH) { */
1612 /* routing error, presume not transient */
1613 goto try_next_server;
1614 /*} */
1615/*For example, what transient error this can be? Can't think of any */
1616 /* retry */
1617 /*continue; */
1618 }
1619 DPRINTF("Xmit packet len:%d id:%d qr:%d\n", packet_len, h.id, h.qr);
1620 /* no error check - if it fails, we time out on recv */
1621 send(fd, packet, packet_len, 0);
1622
1623#ifdef USE_SELECT
1624 reply_timeout = __resolv_timeout;
1625 wait_again:
1626 FD_ZERO(&fds);
1627 FD_SET(fd, &fds);
1628 tv.tv_sec = reply_timeout;
1629 tv.tv_usec = 0;
1630 if (select(fd + 1, &fds, NULL, NULL, &tv) <= 0) {
1631 DPRINTF("Timeout\n");
1632 /* timed out, so retry send and receive
1633 * to next nameserver */
1634 goto try_next_server;
1635 }
1636 reply_timeout--;
1637#else /* !USE_SELECT */
1638 reply_timeout = __resolv_timeout * 1000;
1639 wait_again:
1640 fds.fd = fd;
1641 fds.events = POLLIN;
1642 if (poll(&fds, 1, reply_timeout) <= 0) {
1643 DPRINTF("Timeout\n");
1644 /* timed out, so retry send and receive
1645 * to next nameserver */
1646 goto try_next_server;
1647 }
1648/*TODO: better timeout accounting?*/
1649 reply_timeout -= 1000;
1650#endif /* USE_SELECT */
1651
1652/* vda: a bogus response seen in real world (caused SEGV in uclibc):
1653 * "ping www.google.com" sending AAAA query and getting
1654 * response with one answer... with answer part missing!
1655 * Fixed by thorough checks for not going past the packet's end.
1656 */
1657#ifdef DEBUG
1658 {
1659 static const char test_query[32] = "\0\2\1\0\0\1\0\0\0\0\0\0\3www\6google\3com\0\0\34\0\1";
1660 static const char test_respn[32] = "\0\2\201\200\0\1\0\1\0\0\0\0\3www\6google\3com\0\0\34\0\1";
1661 pos = memcmp(packet + 2, test_query + 2, 30);
1662 packet_len = recv(fd, packet, PACKETSZ, MSG_DONTWAIT);
1663 if (pos == 0) {
1664 packet_len = 32;
1665 memcpy(packet + 2, test_respn + 2, 30);
1666 }
1667 }
1668#else
1669 packet_len = recv(fd, packet, PACKETSZ, MSG_DONTWAIT);
1670#endif
1671
1672 if (packet_len < HFIXEDSZ) {
1673 /* too short!
1674 * If the peer did shutdown then retry later,
1675 * try next peer on error.
1676 * it's just a bogus packet from somewhere */
1677 bogus_packet:
1678 if (packet_len >= 0 && reply_timeout)
1679 goto wait_again;
1680 goto try_next_server;
1681 }
1682 __decode_header(packet, &h);
1683 DPRINTF("len:%d id:%d qr:%d\n", packet_len, h.id, h.qr);
1684 if (h.id != local_id || !h.qr) {
1685 /* unsolicited */
1686 goto bogus_packet;
1687 }
1688
1689 DPRINTF("Got response (i think)!\n");
1690 DPRINTF("qrcount=%d,ancount=%d,nscount=%d,arcount=%d\n",
1691 h.qdcount, h.ancount, h.nscount, h.arcount);
1692 DPRINTF("opcode=%d,aa=%d,tc=%d,rd=%d,ra=%d,rcode=%d\n",
1693 h.opcode, h.aa, h.tc, h.rd, h.ra, h.rcode);
1694
1695 /* bug 660 says we treat negative response as an error
1696 * and retry, which is, eh, an error. :)
1697 * We were incurring long delays because of this. */
1698 if (h.rcode == NXDOMAIN || h.rcode == SERVFAIL) {
1699 /* if possible, try next search domain */
1700 if (!ends_with_dot) {
1701 DPRINTF("variant:%d sdomains:%d\n", variant, sdomains);
1702 if (variant < sdomains - 1) {
1703 /* next search domain */
1704 variant++;
1705 continue;
1706 }
1707 /* no more search domains to try */
1708 }
1709 /* dont loop, this is "no such host" situation */
1710 h_errno = HOST_NOT_FOUND;
1711 goto fail1;
1712 }
1713 /* Insert other non-fatal errors here, which do not warrant
1714 * switching to next nameserver */
1715
1716 /* Strange error, assuming this nameserver is feeling bad */
1717 if (h.rcode != 0)
1718 goto try_next_server;
1719
1720 /* Code below won't work correctly with h.ancount == 0, so... */
1721 if (h.ancount <= 0) {
1722 h_errno = NO_DATA; /* [is this correct code to check for?] */
1723 goto fail1;
1724 }
1725 pos = HFIXEDSZ;
1726 /*XXX TODO: check that question matches query (and qdcount==1?) */
1727 for (j = 0; j < h.qdcount; j++) {
1728 DPRINTF("Skipping question %d at %d\n", j, pos);
1729 i = __length_question(packet + pos, packet_len - pos);
1730 if (i < 0) {
1731 DPRINTF("Packet'question section "
1732 "is truncated, trying next server\n");
1733 goto try_next_server;
1734 }
1735 pos += i;
1736 DPRINTF("Length of question %d is %d\n", j, i);
1737 }
1738 DPRINTF("Decoding answer at pos %d\n", pos);
1739
1740 first_answer = 1;
1741 num_answers = 0;
1742 a->dotted = NULL;
1743 for (j = 0; j < h.ancount; j++) {
1744 i = __decode_answer(packet, pos, packet_len, &ma);
1745 if (i < 0) {
1746 DPRINTF("failed decode %d\n", i);
1747 /* If the message was truncated but we have
1748 * decoded some answers, pretend it's OK */
1749 if (num_answers && h.tc)
1750 break;
1751 goto try_next_server;
1752 }
1753 pos += i;
1754
1755 if (__hnbad(ma.dotted))
1756 break;
1757 ++num_answers;
1758 if (first_answer) {
1759 ma.buf = a->buf;
1760 ma.buflen = a->buflen;
1761 ma.add_count = a->add_count;
1762 free(a->dotted);
1763 memcpy(a, &ma, sizeof(ma));
1764 if (a->atype != T_SIG && (NULL == a->buf || (type != T_A && type != T_AAAA)))
1765 break;
1766 if (a->atype != type)
1767 continue;
1768 a->add_count = h.ancount - j - 1;
1769 if ((a->rdlength + sizeof(struct in_addr*)) * a->add_count > a->buflen)
1770 break;
1771 a->add_count = 0;
1772 first_answer = 0;
1773 } else {
1774 free(ma.dotted);
1775 if (ma.atype != type)
1776 continue;
1777 if (a->rdlength != ma.rdlength) {
1778 free(a->dotted);
1779 DPRINTF("Answer address len(%u) differs from original(%u)\n",
1780 ma.rdlength, a->rdlength);
1781 goto try_next_server;
1782 }
1783 memcpy(a->buf + (a->add_count * ma.rdlength), ma.rdata, ma.rdlength);
1784 ++a->add_count;
1785 }
1786 }
1787 if (!num_answers) {
1788 h_errno = NO_RECOVERY;
1789 goto fail1;
1790 }
1791
1792 /* Success! */
1793 DPRINTF("Answer name = |%s|\n", a->dotted);
1794 DPRINTF("Answer type = |%d|\n", a->atype);
1795 if (fd != -1)
1796 close(fd);
1797 if (outpacket)
1798 *outpacket = packet;
1799 else
1800 free(packet);
1801 free(lookup);
1802 return packet_len;
1803
1804 try_next_server:
1805 /* Try next nameserver */
1806 local_ns_num++;
1807 variant = -1;
1808 } while (retries_left > 0);
1809
1810 fail:
1811 h_errno = NETDB_INTERNAL;
1812 fail1:
1813 if (fd != -1)
1814 close(fd);
1815 free(lookup);
1816 free(packet);
1817 return -1;
1818}
1819#endif /* L_dnslookup */
1820
1821
1822#ifdef L_read_etc_hosts_r
1823
1824parser_t * __open_etc_hosts(void)
1825{
1826 parser_t *parser;
1827 parser = config_open("/etc/hosts");
1828#ifdef FALLBACK_TO_CONFIG_RESOLVCONF
1829 if (parser == NULL)
1830 parser = config_open("/etc/config/hosts");
1831#endif
1832 return parser;
1833}
1834
1835#define MINTOKENS 2 /* ip address + canonical name */
1836#define MAXTOKENS (MINTOKENS + MAXALIASES)
1837#define HALISTOFF (sizeof(char*) * MAXTOKENS)
1838#define INADDROFF (HALISTOFF + 2 * sizeof(char*))
1839
1840int attribute_hidden __read_etc_hosts_r(
1841 parser_t * parser,
1842 const char *name,
1843 int type,
1844 enum etc_hosts_action action,
1845 struct hostent *result_buf,
1846 char *buf, size_t buflen,
1847 struct hostent **result,
1848 int *h_errnop)
1849{
1850 char **tok = NULL;
1851 struct in_addr *h_addr0 = NULL;
1852 const size_t aliaslen = INADDROFF +
1853#ifdef __UCLIBC_HAS_IPV6__
1854 sizeof(struct in6_addr)
1855#else
1856 sizeof(struct in_addr)
1857#endif
1858 ;
1859 int ret = HOST_NOT_FOUND;
1860
1861 *h_errnop = NETDB_INTERNAL;
1862 if (buflen < aliaslen
1863 || (buflen - aliaslen) < BUFSZ + 1)
1864 return ERANGE;
1865 if (parser == NULL)
1866 parser = __open_etc_hosts();
1867 if (parser == NULL) {
1868 *result = NULL;
1869 return errno;
1870 }
1871 /* Layout in buf:
1872 * char *alias[MAXTOKENS] = {address, name, aliases...}
1873 * char **h_addr_list[1] = {*in[6]_addr, NULL}
1874 * struct in[6]_addr
1875 * char line_buffer[BUFSZ+];
1876 */
1877 parser->data = buf;
1878 parser->data_len = aliaslen;
1879 parser->line_len = buflen - aliaslen;
1880 *h_errnop = HOST_NOT_FOUND;
1881 /* <ip>[[:space:]][<aliases>] */
1882 while (config_read(parser, &tok, MAXTOKENS, MINTOKENS, "# \t", PARSE_NORMAL)) {
1883 result_buf->h_aliases = tok+1;
1884 if (action == GETHOSTENT) {
1885 /* Return whatever the next entry happens to be. */
1886 break;
1887 }
1888 if (action == GET_HOSTS_BYADDR) {
1889 if (strcmp(name, *tok) != 0)
1890 continue;
1891 } else { /* GET_HOSTS_BYNAME */
1892 int aliases = 0;
1893 char **alias = tok + 1;
1894 while (aliases < MAXALIASES) {
1895 char *tmp = *(alias+aliases++);
1896 if (tmp && strcasecmp(name, tmp) == 0)
1897 goto found;
1898 }
1899 continue;
1900 }
1901found:
1902 result_buf->h_name = *(result_buf->h_aliases++);
1903 result_buf->h_addr_list = (char**)(buf + HALISTOFF);
1904 *(result_buf->h_addr_list + 1) = '\0';
1905 h_addr0 = (struct in_addr*)(buf + INADDROFF);
1906 result_buf->h_addr = (char*)h_addr0;
1907 if (0) /* nothing */;
1908#ifdef __UCLIBC_HAS_IPV4__
1909 else if (type == AF_INET
1910 && inet_pton(AF_INET, *tok, h_addr0) > 0) {
1911 DPRINTF("Found INET\n");
1912 result_buf->h_addrtype = AF_INET;
1913 result_buf->h_length = sizeof(struct in_addr);
1914 *result = result_buf;
1915 ret = NETDB_SUCCESS;
1916 }
1917#endif
1918#ifdef __UCLIBC_HAS_IPV6__
1919#define in6 ((struct in6_addr *)buf)
1920 else if (type == AF_INET6
1921 && inet_pton(AF_INET6, *tok, h_addr0) > 0) {
1922 DPRINTF("Found INET6\n");
1923 result_buf->h_addrtype = AF_INET6;
1924 result_buf->h_length = sizeof(struct in6_addr);
1925 *result = result_buf;
1926 ret = NETDB_SUCCESS;
1927 }
1928#endif
1929 else {
1930 /* continue parsing in the hope the user has multiple
1931 * host types listed in the database like so:
1932 * <ipv4 addr> host
1933 * <ipv6 addr> host
1934 * If looking for an IPv6 addr, don't bail when we got the IPv4
1935 */
1936 DPRINTF("Error: Found host but different address family\n");
1937 /* NB: gethostbyname2_r depends on this feature
1938 * to avoid looking for IPv6 addr of "localhost" etc */
1939 ret = TRY_AGAIN;
1940 continue;
1941 }
1942 break;
1943 }
1944 if (action != GETHOSTENT)
1945 config_close(parser);
1946 return ret;
1947#undef in6
1948}
1949#endif /* L_read_etc_hosts_r */
1950
1951
1952#ifdef L_get_hosts_byname_r
1953
1954int attribute_hidden __get_hosts_byname_r(const char *name,
1955 int type,
1956 struct hostent *result_buf,
1957 char *buf,
1958 size_t buflen,
1959 struct hostent **result,
1960 int *h_errnop)
1961{
1962 return __read_etc_hosts_r(NULL, name, type, GET_HOSTS_BYNAME,
1963 result_buf, buf, buflen, result, h_errnop);
1964}
1965#endif /* L_get_hosts_byname_r */
1966
1967
1968#ifdef L_get_hosts_byaddr_r
1969
1970int attribute_hidden __get_hosts_byaddr_r(const char *addr,
1971 int len,
1972 int type,
1973 struct hostent *result_buf,
1974 char *buf,
1975 size_t buflen,
1976 struct hostent **result,
1977 int *h_errnop)
1978{
1979#ifndef __UCLIBC_HAS_IPV6__
1980 char ipaddr[INET_ADDRSTRLEN];
1981#else
1982 char ipaddr[INET6_ADDRSTRLEN];
1983#endif
1984
1985 switch (type) {
1986#ifdef __UCLIBC_HAS_IPV4__
1987 case AF_INET:
1988 if (len != sizeof(struct in_addr))
1989 return 0;
1990 break;
1991#endif
1992#ifdef __UCLIBC_HAS_IPV6__
1993 case AF_INET6:
1994 if (len != sizeof(struct in6_addr))
1995 return 0;
1996 break;
1997#endif
1998 default:
1999 return 0;
2000 }
2001
2002 inet_ntop(type, addr, ipaddr, sizeof(ipaddr));
2003
2004 return __read_etc_hosts_r(NULL, ipaddr, type, GET_HOSTS_BYADDR,
2005 result_buf, buf, buflen, result, h_errnop);
2006}
2007#endif /* L_get_hosts_byaddr_r */
2008
2009
2010#ifdef L_getnameinfo
2011
2012int getnameinfo(const struct sockaddr *sa,
2013 socklen_t addrlen,
2014 char *host,
2015 socklen_t hostlen,
2016 char *serv,
2017 socklen_t servlen,
2018 unsigned flags)
2019{
2020 int serrno = errno;
2021 unsigned ok;
2022 struct hostent *hoste = NULL;
2023 char domain[256];
2024
2025 if (flags & ~(NI_NUMERICHOST|NI_NUMERICSERV|NI_NOFQDN|NI_NAMEREQD|NI_DGRAM))
2026 return EAI_BADFLAGS;
2027
2028 if (sa == NULL || addrlen < sizeof(sa_family_t))
2029 return EAI_FAMILY;
2030
2031 ok = sa->sa_family;
2032 if (ok == AF_LOCAL) /* valid */;
2033#ifdef __UCLIBC_HAS_IPV4__
2034 else if (ok == AF_INET) {
2035 if (addrlen < sizeof(struct sockaddr_in))
2036 return EAI_FAMILY;
2037 }
2038#endif
2039#ifdef __UCLIBC_HAS_IPV6__
2040 else if (ok == AF_INET6) {
2041 if (addrlen < sizeof(struct sockaddr_in6))
2042 return EAI_FAMILY;
2043 }
2044#endif
2045 else
2046 return EAI_FAMILY;
2047
2048 ok = 0;
2049 if (host != NULL && hostlen > 0)
2050 switch (sa->sa_family) {
2051 case AF_INET:
2052#ifdef __UCLIBC_HAS_IPV6__
2053 case AF_INET6:
2054#endif
2055 if (!(flags & NI_NUMERICHOST)) {
2056 if (0) /* nothing */;
2057#ifdef __UCLIBC_HAS_IPV6__
2058 else if (sa->sa_family == AF_INET6)
2059 hoste = gethostbyaddr((const void *)
2060 &(((const struct sockaddr_in6 *) sa)->sin6_addr),
2061 sizeof(struct in6_addr), AF_INET6);
2062#endif
2063#ifdef __UCLIBC_HAS_IPV4__
2064 else
2065 hoste = gethostbyaddr((const void *)
2066 &(((const struct sockaddr_in *)sa)->sin_addr),
2067 sizeof(struct in_addr), AF_INET);
2068#endif
2069
2070 if (hoste) {
2071 char *c;
2072#undef min
2073#define min(x,y) (((x) > (y)) ? (y) : (x))
2074 if ((flags & NI_NOFQDN)
2075 && (getdomainname(domain, sizeof(domain)) == 0)
2076 && (c = strstr(hoste->h_name, domain)) != NULL
2077 && (c != hoste->h_name) && (*(--c) == '.')
2078 ) {
2079 strncpy(host, hoste->h_name,
2080 min(hostlen, (size_t) (c - hoste->h_name)));
2081 host[min(hostlen - 1, (size_t) (c - hoste->h_name))] = '\0';
2082 } else {
2083 strncpy(host, hoste->h_name, hostlen);
2084 }
2085 ok = 1;
2086#undef min
2087 }
2088 }
2089
2090 if (!ok) {
2091 const char *c = NULL;
2092
2093 if (flags & NI_NAMEREQD) {
2094 errno = serrno;
2095 return EAI_NONAME;
2096 }
2097 if (0) /* nothing */;
2098#ifdef __UCLIBC_HAS_IPV6__
2099 else if (sa->sa_family == AF_INET6) {
2100 const struct sockaddr_in6 *sin6p;
2101
2102 sin6p = (const struct sockaddr_in6 *) sa;
2103 c = inet_ntop(AF_INET6,
2104 (const void *) &sin6p->sin6_addr,
2105 host, hostlen);
2106#if 0
2107 /* Does scope id need to be supported? */
2108 uint32_t scopeid;
2109 scopeid = sin6p->sin6_scope_id;
2110 if (scopeid != 0) {
2111 /* Buffer is >= IFNAMSIZ+1. */
2112 char scopebuf[IFNAMSIZ + 1];
2113 char *scopeptr;
2114 int ni_numericscope = 0;
2115 size_t real_hostlen = strnlen(host, hostlen);
2116 size_t scopelen = 0;
2117
2118 scopebuf[0] = SCOPE_DELIMITER;
2119 scopebuf[1] = '\0';
2120 scopeptr = &scopebuf[1];
2121
2122 if (IN6_IS_ADDR_LINKLOCAL(&sin6p->sin6_addr)
2123 || IN6_IS_ADDR_MC_LINKLOCAL(&sin6p->sin6_addr)) {
2124 if (if_indextoname(scopeid, scopeptr) == NULL)
2125 ++ni_numericscope;
2126 else
2127 scopelen = strlen(scopebuf);
2128 } else {
2129 ++ni_numericscope;
2130 }
2131
2132 if (ni_numericscope)
2133 scopelen = 1 + snprintf(scopeptr,
2134 (scopebuf
2135 + sizeof scopebuf
2136 - scopeptr),
2137 "%u", scopeid);
2138
2139 if (real_hostlen + scopelen + 1 > hostlen)
2140 return EAI_SYSTEM;
2141 memcpy(host + real_hostlen, scopebuf, scopelen + 1);
2142 }
2143#endif
2144 }
2145#endif /* __UCLIBC_HAS_IPV6__ */
2146#if defined __UCLIBC_HAS_IPV4__
2147 else {
2148 c = inet_ntop(AF_INET, (const void *)
2149 &(((const struct sockaddr_in *) sa)->sin_addr),
2150 host, hostlen);
2151 }
2152#endif
2153 if (c == NULL) {
2154 errno = serrno;
2155 return EAI_SYSTEM;
2156 }
2157 ok = 1;
2158 }
2159 break;
2160
2161 case AF_LOCAL:
2162 if (!(flags & NI_NUMERICHOST)) {
2163 struct utsname utsname;
2164
2165 if (!uname(&utsname)) {
2166 strncpy(host, utsname.nodename, hostlen);
2167 break;
2168 };
2169 };
2170
2171 if (flags & NI_NAMEREQD) {
2172 errno = serrno;
2173 return EAI_NONAME;
2174 }
2175
2176 strncpy(host, "localhost", hostlen);
2177 break;
2178/* Already checked above
2179 default:
2180 return EAI_FAMILY;
2181*/
2182 }
2183
2184 if (serv && (servlen > 0)) {
2185 if (sa->sa_family == AF_LOCAL) {
2186 strncpy(serv, ((const struct sockaddr_un *) sa)->sun_path, servlen);
2187 } else { /* AF_INET || AF_INET6 */
2188 if (!(flags & NI_NUMERICSERV)) {
2189 struct servent *s;
2190 s = getservbyport(((const struct sockaddr_in *) sa)->sin_port,
2191 ((flags & NI_DGRAM) ? "udp" : "tcp"));
2192 if (s) {
2193 strncpy(serv, s->s_name, servlen);
2194 goto DONE;
2195 }
2196 }
2197 snprintf(serv, servlen, "%d",
2198 ntohs(((const struct sockaddr_in *) sa)->sin_port));
2199 }
2200 }
2201DONE:
2202 if (host && (hostlen > 0))
2203 host[hostlen-1] = 0;
2204 if (serv && (servlen > 0))
2205 serv[servlen-1] = 0;
2206 errno = serrno;
2207 return 0;
2208}
2209libc_hidden_def(getnameinfo)
2210#endif /* L_getnameinfo */
2211
2212
2213#ifdef L_gethostbyname_r
2214
2215/* Bug 671 says:
2216 * "uClibc resolver's gethostbyname does not return the requested name
2217 * as an alias, but instead returns the canonical name. glibc's
2218 * gethostbyname has a similar bug where it returns the requested name
2219 * with the search domain name appended (to make a FQDN) as an alias,
2220 * but not the original name itself. Both contradict POSIX, which says
2221 * that the name argument passed to gethostbyname must be in the alias list"
2222 * This is fixed now, and we differ from glibc:
2223 *
2224 * $ ./gethostbyname_uclibc wer.google.com
2225 * h_name:'c13-ss-2-lb.cnet.com'
2226 * h_length:4
2227 * h_addrtype:2 AF_INET
2228 * alias:'wer.google.com' <===
2229 * addr: 0x4174efd8 '216.239.116.65'
2230 *
2231 * $ ./gethostbyname_glibc wer.google.com
2232 * h_name:'c13-ss-2-lb.cnet.com'
2233 * h_length:4
2234 * h_addrtype:2 AF_INET
2235 * alias:'wer.google.com.com' <===
2236 * addr:'216.239.116.65'
2237 *
2238 * When examples were run, /etc/resolv.conf contained "search com" line.
2239 */
2240int gethostbyname_r(const char *name,
2241 struct hostent *result_buf,
2242 char *buf,
2243 size_t buflen,
2244 struct hostent **result,
2245 int *h_errnop)
2246{
2247 struct in_addr **addr_list;
2248 char **alias;
2249 char *alias0;
2250 unsigned char *packet;
2251 struct resolv_answer a;
2252 int i;
2253 int packet_len;
2254 int wrong_af = 0;
2255
2256 *result = NULL;
2257 if (!name)
2258 return EINVAL;
2259
2260 /* do /etc/hosts first */
2261 {
2262 int old_errno = errno; /* save the old errno and reset errno */
2263 __set_errno(0); /* to check for missing /etc/hosts. */
2264 i = __get_hosts_byname_r(name, AF_INET, result_buf,
2265 buf, buflen, result, h_errnop);
2266 if (i == NETDB_SUCCESS) {
2267 __set_errno(old_errno);
2268 return i;
2269 }
2270 switch (*h_errnop) {
2271 case HOST_NOT_FOUND:
2272 wrong_af = (i == TRY_AGAIN);
2273 case NO_ADDRESS:
2274 break;
2275 case NETDB_INTERNAL:
2276 if (errno == ENOENT) {
2277 break;
2278 }
2279 /* else fall through */
2280 default:
2281 return i;
2282 }
2283 __set_errno(old_errno);
2284 }
2285
2286 DPRINTF("Nothing found in /etc/hosts\n");
2287
2288 *h_errnop = NETDB_INTERNAL;
2289
2290 /* prepare future h_aliases[0] */
2291 i = strlen(name) + 1;
2292 if ((ssize_t)buflen <= i)
2293 return ERANGE;
2294 memcpy(buf, name, i); /* paranoia: name might change */
2295 alias0 = buf;
2296 buf += i;
2297 buflen -= i;
2298 /* make sure pointer is aligned */
2299 i = ALIGN_BUFFER_OFFSET(buf);
2300 buf += i;
2301 buflen -= i;
2302 /* Layout in buf:
2303 * char *alias[2];
2304 * struct in_addr* addr_list[NN+1];
2305 * struct in_addr* in[NN];
2306 */
2307 alias = (char **)buf;
2308 buf += sizeof(alias[0]) * 2;
2309 buflen -= sizeof(alias[0]) * 2;
2310 addr_list = (struct in_addr **)buf;
2311 /* buflen may be < 0, must do signed compare */
2312 if ((ssize_t)buflen < 256)
2313 return ERANGE;
2314
2315 /* we store only one "alias" - the name itself */
2316#ifdef __UCLIBC_MJN3_ONLY__
2317#warning TODO -- generate the full list
2318#endif
2319 alias[0] = alias0;
2320 alias[1] = NULL;
2321
2322 /* maybe it is already an address? */
2323 {
2324 struct in_addr *in = (struct in_addr *)(buf + sizeof(addr_list[0]) * 2);
2325 if (inet_aton(name, in)) {
2326 addr_list[0] = in;
2327 addr_list[1] = NULL;
2328 result_buf->h_name = alias0;
2329 result_buf->h_aliases = alias;
2330 result_buf->h_addrtype = AF_INET;
2331 result_buf->h_length = sizeof(struct in_addr);
2332 result_buf->h_addr_list = (char **) addr_list;
2333 *result = result_buf;
2334 *h_errnop = NETDB_SUCCESS;
2335 return NETDB_SUCCESS;
2336 }
2337 }
2338
2339 /* what if /etc/hosts has it but it's not IPv4?
2340 * F.e. "::1 localhost6". We don't do DNS query for such hosts -
2341 * "ping localhost6" should be fast even if DNS server is down! */
2342 if (wrong_af) {
2343 *h_errnop = HOST_NOT_FOUND;
2344 return TRY_AGAIN;
2345 }
2346
2347 /* talk to DNS servers */
2348 a.buf = buf;
2349 /* take into account that at least one address will be there,
2350 * we'll need space for one in_addr + two addr_list[] elems */
2351 a.buflen = buflen - ((sizeof(addr_list[0]) * 2 + sizeof(struct in_addr)));
2352 a.add_count = 0;
2353 packet_len = __dns_lookup(name, T_A, &packet, &a);
2354 if (packet_len < 0) {
2355 *h_errnop = HOST_NOT_FOUND;
2356 DPRINTF("__dns_lookup returned < 0\n");
2357 return TRY_AGAIN;
2358 }
2359
2360 if (a.atype == T_A) { /* ADDRESS */
2361 /* we need space for addr_list[] and one IPv4 address */
2362 /* + 1 accounting for 1st addr (it's in a.rdata),
2363 * another + 1 for NULL in last addr_list[]: */
2364 int need_bytes = sizeof(addr_list[0]) * (a.add_count + 1 + 1)
2365 /* for 1st addr (it's in a.rdata): */
2366 + sizeof(struct in_addr);
2367 /* how many bytes will 2nd and following addresses take? */
2368 int ips_len = a.add_count * a.rdlength;
2369
2370 buflen -= (need_bytes + ips_len);
2371 if ((ssize_t)buflen < 0) {
2372 DPRINTF("buffer too small for all addresses\n");
2373 /* *h_errnop = NETDB_INTERNAL; - already is */
2374 i = ERANGE;
2375 goto free_and_ret;
2376 }
2377
2378 /* if there are additional addresses in buf,
2379 * move them forward so that they are not destroyed */
2380 DPRINTF("a.add_count:%d a.rdlength:%d a.rdata:%p\n", a.add_count, a.rdlength, a.rdata);
2381 memmove(buf + need_bytes, buf, ips_len);
2382
2383 /* 1st address is in a.rdata, insert it */
2384 buf += need_bytes - sizeof(struct in_addr);
2385 memcpy(buf, a.rdata, sizeof(struct in_addr));
2386
2387 /* fill addr_list[] */
2388 for (i = 0; i <= a.add_count; i++) {
2389 addr_list[i] = (struct in_addr*)buf;
2390 buf += sizeof(struct in_addr);
2391 }
2392 addr_list[i] = NULL;
2393
2394 /* if we have enough space, we can report "better" name
2395 * (it may contain search domains attached by __dns_lookup,
2396 * or CNAME of the host if it is different from the name
2397 * we used to find it) */
2398 if (a.dotted && buflen > strlen(a.dotted)) {
2399 strcpy(buf, a.dotted);
2400 alias0 = buf;
2401 }
2402
2403 result_buf->h_name = alias0;
2404 result_buf->h_aliases = alias;
2405 result_buf->h_addrtype = AF_INET;
2406 result_buf->h_length = sizeof(struct in_addr);
2407 result_buf->h_addr_list = (char **) addr_list;
2408 *result = result_buf;
2409 *h_errnop = NETDB_SUCCESS;
2410 i = NETDB_SUCCESS;
2411 goto free_and_ret;
2412 }
2413
2414 *h_errnop = HOST_NOT_FOUND;
2415 __set_h_errno(HOST_NOT_FOUND);
2416 i = TRY_AGAIN;
2417
2418 free_and_ret:
2419 free(a.dotted);
2420 free(packet);
2421 return i;
2422}
2423libc_hidden_def(gethostbyname_r)
2424link_warning(gethostbyname_r, "gethostbyname_r is obsolescent, use getnameinfo() instead.");
2425#endif /* L_gethostbyname_r */
2426
2427
2428#ifdef L_gethostbyname2_r
2429
2430int gethostbyname2_r(const char *name,
2431 int family,
2432 struct hostent *result_buf,
2433 char *buf,
2434 size_t buflen,
2435 struct hostent **result,
2436 int *h_errnop)
2437{
2438#ifndef __UCLIBC_HAS_IPV6__
2439 return family == (AF_INET)
2440 ? gethostbyname_r(name, result_buf, buf, buflen, result, h_errnop)
2441 : HOST_NOT_FOUND;
2442#else
2443 struct in6_addr *in;
2444 struct in6_addr **addr_list;
2445 unsigned char *packet;
2446 struct resolv_answer a;
2447 int i;
2448 int nest = 0;
2449 int wrong_af = 0;
2450
2451 if (family == AF_INET)
2452 return gethostbyname_r(name, result_buf, buf, buflen, result, h_errnop);
2453
2454 *result = NULL;
2455 if (family != AF_INET6)
2456 return EINVAL;
2457
2458 if (!name)
2459 return EINVAL;
2460
2461 /* do /etc/hosts first */
2462 {
2463 int old_errno = errno; /* Save the old errno and reset errno */
2464 __set_errno(0); /* to check for missing /etc/hosts. */
2465
2466 i = __get_hosts_byname_r(name, AF_INET6 /*family*/, result_buf,
2467 buf, buflen, result, h_errnop);
2468 if (i == NETDB_SUCCESS) {
2469 __set_errno(old_errno);
2470 return i;
2471 }
2472 switch (*h_errnop) {
2473 case HOST_NOT_FOUND:
2474 wrong_af = (i == TRY_AGAIN);
2475 case NO_ADDRESS:
2476 break;
2477 case NETDB_INTERNAL:
2478 if (errno == ENOENT) {
2479 break;
2480 }
2481 /* else fall through */
2482 default:
2483 return i;
2484 }
2485 __set_errno(old_errno);
2486 }
2487 DPRINTF("Nothing found in /etc/hosts\n");
2488
2489 *h_errnop = NETDB_INTERNAL;
2490
2491 /* make sure pointer is aligned */
2492 i = ALIGN_BUFFER_OFFSET(buf);
2493 buf += i;
2494 buflen -= i;
2495 /* Layout in buf:
2496 * struct in6_addr* in;
2497 * struct in6_addr* addr_list[2];
2498 * char scratch_buf[256];
2499 */
2500 in = (struct in6_addr*)buf;
2501 buf += sizeof(*in);
2502 buflen -= sizeof(*in);
2503 addr_list = (struct in6_addr**)buf;
2504 buf += sizeof(*addr_list) * 2;
2505 buflen -= sizeof(*addr_list) * 2;
2506 if ((ssize_t)buflen < 256)
2507 return ERANGE;
2508 addr_list[0] = in;
2509 addr_list[1] = NULL;
2510 strncpy(buf, name, buflen);
2511 buf[buflen] = '\0';
2512
2513 /* maybe it is already an address? */
2514 if (inet_pton(AF_INET6, name, in)) {
2515 result_buf->h_name = buf;
2516 result_buf->h_addrtype = AF_INET6;
2517 result_buf->h_length = sizeof(*in);
2518 result_buf->h_addr_list = (char **) addr_list;
2519 /* result_buf->h_aliases = ??? */
2520 *result = result_buf;
2521 *h_errnop = NETDB_SUCCESS;
2522 return NETDB_SUCCESS;
2523 }
2524
2525 /* what if /etc/hosts has it but it's not IPv6?
2526 * F.e. "127.0.0.1 localhost". We don't do DNS query for such hosts -
2527 * "ping localhost" should be fast even if DNS server is down! */
2528 if (wrong_af) {
2529 *h_errnop = HOST_NOT_FOUND;
2530 return TRY_AGAIN;
2531 }
2532
2533 /* talk to DNS servers */
2534/* TODO: why it's so different from gethostbyname_r (IPv4 case)? */
2535 memset(&a, '\0', sizeof(a));
2536 for (;;) {
2537 int packet_len;
2538
2539/* Hmm why we memset(a) to zeros only once? */
2540 packet_len = __dns_lookup(buf, T_AAAA, &packet, &a);
2541 if (packet_len < 0) {
2542 *h_errnop = HOST_NOT_FOUND;
2543 return TRY_AGAIN;
2544 }
2545 strncpy(buf, a.dotted, buflen);
2546 free(a.dotted);
2547
2548 if (a.atype != T_CNAME)
2549 break;
2550
2551 DPRINTF("Got a CNAME in gethostbyname()\n");
2552 if (++nest > MAX_RECURSE) {
2553 *h_errnop = NO_RECOVERY;
2554 return -1;
2555 }
2556 i = __decode_dotted(packet, a.rdoffset, packet_len, buf, buflen);
2557 free(packet);
2558 if (i < 0) {
2559 *h_errnop = NO_RECOVERY;
2560 return -1;
2561 }
2562 }
2563 if (a.atype == T_AAAA) { /* ADDRESS */
2564 memcpy(in, a.rdata, sizeof(*in));
2565 result_buf->h_name = buf;
2566 result_buf->h_addrtype = AF_INET6;
2567 result_buf->h_length = sizeof(*in);
2568 result_buf->h_addr_list = (char **) addr_list;
2569 /* result_buf->h_aliases = ??? */
2570 free(packet);
2571 *result = result_buf;
2572 *h_errnop = NETDB_SUCCESS;
2573 return NETDB_SUCCESS;
2574 }
2575 free(packet);
2576 *h_errnop = HOST_NOT_FOUND;
2577 return TRY_AGAIN;
2578
2579#endif /* __UCLIBC_HAS_IPV6__ */
2580}
2581libc_hidden_def(gethostbyname2_r)
2582#endif /* L_gethostbyname2_r */
2583
2584
2585#ifdef L_gethostbyaddr_r
2586
2587int gethostbyaddr_r(const void *addr, socklen_t addrlen,
2588 int type,
2589 struct hostent *result_buf,
2590 char *buf, size_t buflen,
2591 struct hostent **result,
2592 int *h_errnop)
2593
2594{
2595 struct in_addr *in;
2596 struct in_addr **addr_list;
2597 char **alias;
2598 unsigned char *packet;
2599 struct resolv_answer a;
2600 int i;
2601 int packet_len;
2602 int nest = 0;
2603
2604 *result = NULL;
2605 if (!addr)
2606 return EINVAL;
2607
2608 switch (type) {
2609#ifdef __UCLIBC_HAS_IPV4__
2610 case AF_INET:
2611 if (addrlen != sizeof(struct in_addr))
2612 return EINVAL;
2613 break;
2614#endif
2615#ifdef __UCLIBC_HAS_IPV6__
2616 case AF_INET6:
2617 if (addrlen != sizeof(struct in6_addr))
2618 return EINVAL;
2619 break;
2620#endif
2621 default:
2622 return EINVAL;
2623 }
2624
2625 /* do /etc/hosts first */
2626 i = __get_hosts_byaddr_r(addr, addrlen, type, result_buf,
2627 buf, buflen, result, h_errnop);
2628 if (i == 0)
2629 return i;
2630 switch (*h_errnop) {
2631 case HOST_NOT_FOUND:
2632 case NO_ADDRESS:
2633 break;
2634 default:
2635 return i;
2636 }
2637
2638 *h_errnop = NETDB_INTERNAL;
2639
2640 /* make sure pointer is aligned */
2641 i = ALIGN_BUFFER_OFFSET(buf);
2642 buf += i;
2643 buflen -= i;
2644 /* Layout in buf:
2645 * char *alias[ALIAS_DIM];
2646 * struct in[6]_addr* addr_list[2];
2647 * struct in[6]_addr in;
2648 * char scratch_buffer[256+];
2649 */
2650#define in6 ((struct in6_addr *)in)
2651 alias = (char **)buf;
2652 addr_list = (struct in_addr**)buf;
2653 buf += sizeof(*addr_list) * 2;
2654 buflen -= sizeof(*addr_list) * 2;
2655 in = (struct in_addr*)buf;
2656#ifndef __UCLIBC_HAS_IPV6__
2657 buf += sizeof(*in);
2658 buflen -= sizeof(*in);
2659 if (addrlen > sizeof(*in))
2660 return ERANGE;
2661#else
2662 buf += sizeof(*in6);
2663 buflen -= sizeof(*in6);
2664 if (addrlen > sizeof(*in6))
2665 return ERANGE;
2666#endif
2667 if ((ssize_t)buflen < 256)
2668 return ERANGE;
2669 alias[0] = buf;
2670 alias[1] = NULL;
2671 addr_list[0] = in;
2672 addr_list[1] = NULL;
2673 memcpy(in, addr, addrlen);
2674
2675 if (0) /* nothing */;
2676#ifdef __UCLIBC_HAS_IPV4__
2677 else IF_HAS_BOTH(if (type == AF_INET)) {
2678 unsigned char *tp = (unsigned char *)addr;
2679 sprintf(buf, "%u.%u.%u.%u.in-addr.arpa",
2680 tp[3], tp[2], tp[1], tp[0]);
2681 }
2682#endif
2683#ifdef __UCLIBC_HAS_IPV6__
2684 else {
2685 char *dst = buf;
2686 unsigned char *tp = (unsigned char *)addr + addrlen - 1;
2687 do {
2688 dst += sprintf(dst, "%x.%x.", tp[0] & 0xf, tp[0] >> 4);
2689 tp--;
2690 } while (tp >= (unsigned char *)addr);
2691 strcpy(dst, "ip6.arpa");
2692 }
2693#endif
2694
2695 memset(&a, '\0', sizeof(a));
2696 for (;;) {
2697/* Hmm why we memset(a) to zeros only once? */
2698 packet_len = __dns_lookup(buf, T_PTR, &packet, &a);
2699 if (packet_len < 0) {
2700 *h_errnop = HOST_NOT_FOUND;
2701 return TRY_AGAIN;
2702 }
2703
2704 strncpy(buf, a.dotted, buflen);
2705 free(a.dotted);
2706 if (a.atype != T_CNAME)
2707 break;
2708
2709 DPRINTF("Got a CNAME in gethostbyaddr()\n");
2710 if (++nest > MAX_RECURSE) {
2711 *h_errnop = NO_RECOVERY;
2712 return -1;
2713 }
2714 /* Decode CNAME into buf, feed it to __dns_lookup() again */
2715 i = __decode_dotted(packet, a.rdoffset, packet_len, buf, buflen);
2716 free(packet);
2717 if (i < 0 || __hnbad(buf)) {
2718 *h_errnop = NO_RECOVERY;
2719 return -1;
2720 }
2721 }
2722
2723 if (a.atype == T_PTR) { /* ADDRESS */
2724 i = __decode_dotted(packet, a.rdoffset, packet_len, buf, buflen);
2725 free(packet);
2726 if (__hnbad(buf)) {
2727 *h_errnop = NO_RECOVERY;
2728 return -1;
2729 }
2730 result_buf->h_name = buf;
2731 result_buf->h_addrtype = type;
2732 result_buf->h_length = addrlen;
2733 result_buf->h_addr_list = (char **) addr_list;
2734 result_buf->h_aliases = alias;
2735 *result = result_buf;
2736 *h_errnop = NETDB_SUCCESS;
2737 return NETDB_SUCCESS;
2738 }
2739
2740 free(packet);
2741 *h_errnop = NO_ADDRESS;
2742 return TRY_AGAIN;
2743#undef in6
2744}
2745libc_hidden_def(gethostbyaddr_r)
2746link_warning(gethostbyaddr_r, "gethostbyaddr_r is obsolescent, use getaddrinfo() instead.");
2747#endif /* L_gethostbyaddr_r */
2748
2749
2750#ifdef L_gethostent_r
2751
2752__UCLIBC_MUTEX_STATIC(mylock, PTHREAD_MUTEX_INITIALIZER);
2753
2754static parser_t *hostp = NULL;
2755static smallint host_stayopen;
2756
2757void endhostent_unlocked(void)
2758{
2759 if (hostp) {
2760 config_close(hostp);
2761 hostp = NULL;
2762 }
2763 host_stayopen = 0;
2764}
2765void endhostent(void)
2766{
2767 __UCLIBC_MUTEX_LOCK(mylock);
2768 endhostent_unlocked();
2769 __UCLIBC_MUTEX_UNLOCK(mylock);
2770}
2771
2772void sethostent(int stay_open)
2773{
2774 __UCLIBC_MUTEX_LOCK(mylock);
2775 if (stay_open)
2776 host_stayopen = 1;
2777 __UCLIBC_MUTEX_UNLOCK(mylock);
2778}
2779
2780int gethostent_r(struct hostent *result_buf, char *buf, size_t buflen,
2781 struct hostent **result, int *h_errnop)
2782{
2783 int ret;
2784
2785 __UCLIBC_MUTEX_LOCK(mylock);
2786 if (hostp == NULL) {
2787 hostp = __open_etc_hosts();
2788 if (hostp == NULL) {
2789 *result = NULL;
2790 ret = TRY_AGAIN;
2791 goto DONE;
2792 }
2793 }
2794
2795 ret = __read_etc_hosts_r(hostp, NULL, AF_INET, GETHOSTENT,
2796 result_buf, buf, buflen, result, h_errnop);
2797 if (!host_stayopen)
2798 endhostent_unlocked();
2799DONE:
2800 __UCLIBC_MUTEX_UNLOCK(mylock);
2801 return ret;
2802}
2803libc_hidden_def(gethostent_r)
2804#endif /* L_gethostent_r */
2805
2806
2807#ifdef L_gethostent
2808
2809struct hostent *gethostent(void)
2810{
2811 static struct hostent hoste;
2812 static char buf[
2813#ifndef __UCLIBC_HAS_IPV6__
2814 sizeof(struct in_addr) + sizeof(struct in_addr *) * 2 +
2815#else
2816 sizeof(struct in6_addr) + sizeof(struct in6_addr *) * 2 +
2817#endif /* __UCLIBC_HAS_IPV6__ */
2818 BUFSZ /*namebuffer*/ + 2 /* margin */];
2819 struct hostent *host;
2820
2821 gethostent_r(&hoste, buf, sizeof(buf), &host, &h_errno);
2822 return host;
2823}
2824#endif /* L_gethostent */
2825
2826
2827#ifdef L_gethostbyname2
2828
2829struct hostent *gethostbyname2(const char *name, int family)
2830{
2831#ifndef __UCLIBC_HAS_IPV6__
2832 return family == AF_INET ? gethostbyname(name) : (struct hostent*)NULL;
2833#else
2834 static struct hostent hoste;
2835 static char buf[sizeof(struct in6_addr) +
2836 sizeof(struct in6_addr *) * 2 +
2837 /*sizeof(char *)*ALIAS_DIM +*/ 384/*namebuffer*/ + 32/* margin */];
2838 struct hostent *hp;
2839
2840 gethostbyname2_r(name, family, &hoste, buf, sizeof(buf), &hp, &h_errno);
2841 return hp;
2842#endif
2843}
2844libc_hidden_def(gethostbyname2)
2845#endif /* L_gethostbyname2 */
2846
2847
2848#ifdef L_gethostbyname
2849
2850struct hostent *gethostbyname(const char *name)
2851{
2852#ifndef __UCLIBC_HAS_IPV6__
2853 static struct hostent hoste;
2854 static char buf[sizeof(struct in_addr) +
2855 sizeof(struct in_addr *) * 2 +
2856 /*sizeof(char *)*ALIAS_DIM +*/ 384/*namebuffer*/ + 32/* margin */];
2857 struct hostent *hp;
2858
2859 gethostbyname_r(name, &hoste, buf, sizeof(buf), &hp, &h_errno);
2860 return hp;
2861#else
2862 return gethostbyname2(name, AF_INET);
2863#endif
2864}
2865libc_hidden_def(gethostbyname)
2866link_warning(gethostbyname, "gethostbyname is obsolescent, use getnameinfo() instead.");
2867#endif /* L_gethostbyname */
2868
2869
2870#ifdef L_gethostbyaddr
2871
2872struct hostent *gethostbyaddr(const void *addr, socklen_t len, int type)
2873{
2874 static struct hostent hoste;
2875 static char buf[
2876#ifndef __UCLIBC_HAS_IPV6__
2877 sizeof(struct in_addr) + sizeof(struct in_addr *)*2 +
2878#else
2879 sizeof(struct in6_addr) + sizeof(struct in6_addr *)*2 +
2880#endif /* __UCLIBC_HAS_IPV6__ */
2881 /*sizeof(char *)*ALIAS_DIM +*/ 384 /*namebuffer*/ + 32 /* margin */];
2882 struct hostent *hp;
2883
2884 gethostbyaddr_r(addr, len, type, &hoste, buf, sizeof(buf), &hp, &h_errno);
2885 return hp;
2886}
2887libc_hidden_def(gethostbyaddr)
2888link_warning(gethostbyaddr, "gethostbyaddr is obsolescent, use getaddrinfo() instead.");
2889#endif /* L_gethostbyaddr */
2890
2891
2892#ifdef L_res_comp
2893
2894/*
2895 * Expand compressed domain name 'comp_dn' to full domain name.
2896 * 'msg' is a pointer to the begining of the message,
2897 * 'eomorig' points to the first location after the message,
2898 * 'exp_dn' is a pointer to a buffer of size 'length' for the result.
2899 * Return size of compressed name or -1 if there was an error.
2900 */
2901int dn_expand(const u_char *msg, const u_char *eom, const u_char *src,
2902 char *dst, int dstsiz)
2903{
2904 int n = ns_name_uncompress(msg, eom, src, dst, (size_t)dstsiz);
2905
2906 if (n > 0 && dst[0] == '.')
2907 dst[0] = '\0';
2908 return n;
2909}
2910libc_hidden_def(dn_expand)
2911
2912/*
2913 * Pack domain name 'exp_dn' in presentation form into 'comp_dn'.
2914 * Return the size of the compressed name or -1.
2915 * 'length' is the size of the array pointed to by 'comp_dn'.
2916 */
2917int
2918dn_comp(const char *src, u_char *dst, int dstsiz,
2919 u_char **dnptrs, u_char **lastdnptr)
2920{
2921 return ns_name_compress(src, dst, (size_t) dstsiz,
2922 (const u_char **) dnptrs,
2923 (const u_char **) lastdnptr);
2924}
2925libc_hidden_def(dn_comp)
2926#endif /* L_res_comp */
2927
2928
2929#ifdef L_ns_name
2930
2931/* Thinking in noninternationalized USASCII (per the DNS spec),
2932 * is this character visible and not a space when printed ?
2933 */
2934static int printable(int ch)
2935{
2936 return (ch > 0x20 && ch < 0x7f);
2937}
2938/* Thinking in noninternationalized USASCII (per the DNS spec),
2939 * is this characted special ("in need of quoting") ?
2940 */
2941static int special(int ch)
2942{
2943 switch (ch) {
2944 case 0x22: /* '"' */
2945 case 0x2E: /* '.' */
2946 case 0x3B: /* ';' */
2947 case 0x5C: /* '\\' */
2948 /* Special modifiers in zone files. */
2949 case 0x40: /* '@' */
2950 case 0x24: /* '$' */
2951 return 1;
2952 default:
2953 return 0;
2954 }
2955}
2956
2957/*
2958 * ns_name_uncompress(msg, eom, src, dst, dstsiz)
2959 * Expand compressed domain name to presentation format.
2960 * return:
2961 * Number of bytes read out of `src', or -1 (with errno set).
2962 * note:
2963 * Root domain returns as "." not "".
2964 */
2965int ns_name_uncompress(const u_char *msg, const u_char *eom,
2966 const u_char *src, char *dst, size_t dstsiz)
2967{
2968 u_char tmp[NS_MAXCDNAME];
2969 int n;
2970
2971 n = ns_name_unpack(msg, eom, src, tmp, sizeof tmp);
2972 if (n == -1)
2973 return -1;
2974 if (ns_name_ntop(tmp, dst, dstsiz) == -1)
2975 return -1;
2976 return n;
2977}
2978libc_hidden_def(ns_name_uncompress)
2979
2980/*
2981 * ns_name_ntop(src, dst, dstsiz)
2982 * Convert an encoded domain name to printable ascii as per RFC1035.
2983 * return:
2984 * Number of bytes written to buffer, or -1 (with errno set)
2985 * notes:
2986 * The root is returned as "."
2987 * All other domains are returned in non absolute form
2988 */
2989int ns_name_ntop(const u_char *src, char *dst, size_t dstsiz)
2990{
2991 const u_char *cp;
2992 char *dn, *eom;
2993 u_char c;
2994 u_int n;
2995
2996 cp = src;
2997 dn = dst;
2998 eom = dst + dstsiz;
2999
3000 while ((n = *cp++) != 0) {
3001 if ((n & NS_CMPRSFLGS) != 0) {
3002 /* Some kind of compression pointer. */
3003 __set_errno(EMSGSIZE);
3004 return -1;
3005 }
3006 if (dn != dst) {
3007 if (dn >= eom) {
3008 __set_errno(EMSGSIZE);
3009 return -1;
3010 }
3011 *dn++ = '.';
3012 }
3013 if (dn + n >= eom) {
3014 __set_errno(EMSGSIZE);
3015 return -1;
3016 }
3017 for (; n > 0; n--) {
3018 c = *cp++;
3019 if (special(c)) {
3020 if (dn + 1 >= eom) {
3021 __set_errno(EMSGSIZE);
3022 return -1;
3023 }
3024 *dn++ = '\\';
3025 *dn++ = (char)c;
3026 } else if (!printable(c)) {
3027 if (dn + 3 >= eom) {
3028 __set_errno(EMSGSIZE);
3029 return -1;
3030 }
3031 *dn++ = '\\';
3032 *dn++ = "0123456789"[c / 100];
3033 c = c % 100;
3034 *dn++ = "0123456789"[c / 10];
3035 *dn++ = "0123456789"[c % 10];
3036 } else {
3037 if (dn >= eom) {
3038 __set_errno(EMSGSIZE);
3039 return -1;
3040 }
3041 *dn++ = (char)c;
3042 }
3043 }
3044 }
3045 if (dn == dst) {
3046 if (dn >= eom) {
3047 __set_errno(EMSGSIZE);
3048 return -1;
3049 }
3050 *dn++ = '.';
3051 }
3052 if (dn >= eom) {
3053 __set_errno(EMSGSIZE);
3054 return -1;
3055 }
3056 *dn++ = '\0';
3057 return (dn - dst);
3058}
3059libc_hidden_def(ns_name_ntop)
3060
3061static int encode_bitstring(const char **bp, const char *end,
3062 unsigned char **labelp,
3063 unsigned char ** dst,
3064 unsigned const char *eom)
3065{
3066 int afterslash = 0;
3067 const char *cp = *bp;
3068 unsigned char *tp;
3069 const char *beg_blen;
3070 int value = 0, count = 0, tbcount = 0, blen = 0;
3071
3072 beg_blen = NULL;
3073
3074 /* a bitstring must contain at least 2 characters */
3075 if (end - cp < 2)
3076 return EINVAL;
3077
3078 /* XXX: currently, only hex strings are supported */
3079 if (*cp++ != 'x')
3080 return EINVAL;
3081 if (!isxdigit((unsigned char) *cp)) /*%< reject '\[x/BLEN]' */
3082 return EINVAL;
3083
3084 for (tp = *dst + 1; cp < end && tp < eom; cp++) {
3085 unsigned char c = *cp;
3086
3087 switch (c) {
3088 case ']': /*%< end of the bitstring */
3089 if (afterslash) {
3090 char *end_blen;
3091 if (beg_blen == NULL)
3092 return EINVAL;
3093 blen = (int)strtol(beg_blen, &end_blen, 10);
3094 if (*end_blen != ']')
3095 return EINVAL;
3096 }
3097 if (count)
3098 *tp++ = ((value << 4) & 0xff);
3099 cp++; /*%< skip ']' */
3100 goto done;
3101 case '/':
3102 afterslash = 1;
3103 break;
3104 default:
3105 if (afterslash) {
3106 if (!__isdigit_char(c))
3107 return EINVAL;
3108 if (beg_blen == NULL) {
3109 if (c == '0') {
3110 /* blen never begings with 0 */
3111 return EINVAL;
3112 }
3113 beg_blen = cp;
3114 }
3115 } else {
3116 if (!__isdigit_char(c)) {
3117 c = c | 0x20; /* lowercase */
3118 c = c - 'a';
3119 if (c > 5) /* not a-f? */
3120 return EINVAL;
3121 c += 10 + '0';
3122 }
3123 value <<= 4;
3124 value += (c - '0');
3125 count += 4;
3126 tbcount += 4;
3127 if (tbcount > 256)
3128 return EINVAL;
3129 if (count == 8) {
3130 *tp++ = value;
3131 count = 0;
3132 }
3133 }
3134 break;
3135 }
3136 }
3137 done:
3138 if (cp >= end || tp >= eom)
3139 return EMSGSIZE;
3140
3141 /*
3142 * bit length validation:
3143 * If a <length> is present, the number of digits in the <bit-data>
3144 * MUST be just sufficient to contain the number of bits specified
3145 * by the <length>. If there are insignificant bits in a final
3146 * hexadecimal or octal digit, they MUST be zero.
3147 * RFC2673, Section 3.2.
3148 */
3149 if (blen > 0) {
3150 int traillen;
3151
3152 if (((blen + 3) & ~3) != tbcount)
3153 return EINVAL;
3154 traillen = tbcount - blen; /*%< between 0 and 3 */
3155 if (((value << (8 - traillen)) & 0xff) != 0)
3156 return EINVAL;
3157 }
3158 else
3159 blen = tbcount;
3160 if (blen == 256)
3161 blen = 0;
3162
3163 /* encode the type and the significant bit fields */
3164 **labelp = DNS_LABELTYPE_BITSTRING;
3165 **dst = blen;
3166
3167 *bp = cp;
3168 *dst = tp;
3169
3170 return 0;
3171}
3172
3173int ns_name_pton(const char *src, u_char *dst, size_t dstsiz)
3174{
3175 static const char digits[] = "0123456789";
3176 u_char *label, *bp, *eom;
3177 int c, n, escaped, e = 0;
3178 char *cp;
3179
3180 escaped = 0;
3181 bp = dst;
3182 eom = dst + dstsiz;
3183 label = bp++;
3184
3185 while ((c = *src++) != 0) {
3186 if (escaped) {
3187 if (c == '[') { /*%< start a bit string label */
3188 cp = strchr(src, ']');
3189 if (cp == NULL) {
3190 errno = EINVAL; /*%< ??? */
3191 return -1;
3192 }
3193 e = encode_bitstring(&src, cp + 2,
3194 &label, &bp, eom);
3195 if (e != 0) {
3196 errno = e;
3197 return -1;
3198 }
3199 escaped = 0;
3200 label = bp++;
3201 c = *src++;
3202 if (c == '\0')
3203 goto done;
3204 if (c != '.') {
3205 errno = EINVAL;
3206 return -1;
3207 }
3208 continue;
3209 }
3210 cp = strchr(digits, c);
3211 if (cp != NULL) {
3212 n = (cp - digits) * 100;
3213 c = *src++;
3214 if (c == '\0')
3215 goto ret_EMSGSIZE;
3216 cp = strchr(digits, c);
3217 if (cp == NULL)
3218 goto ret_EMSGSIZE;
3219 n += (cp - digits) * 10;
3220 c = *src++;
3221 if (c == '\0')
3222 goto ret_EMSGSIZE;
3223 cp = strchr(digits, c);
3224 if (cp == NULL)
3225 goto ret_EMSGSIZE;
3226 n += (cp - digits);
3227 if (n > 255)
3228 goto ret_EMSGSIZE;
3229 c = n;
3230 }
3231 escaped = 0;
3232 } else if (c == '\\') {
3233 escaped = 1;
3234 continue;
3235 } else if (c == '.') {
3236 c = (bp - label - 1);
3237 if ((c & NS_CMPRSFLGS) != 0) { /*%< Label too big. */
3238 goto ret_EMSGSIZE;
3239 }
3240 if (label >= eom) {
3241 goto ret_EMSGSIZE;
3242 }
3243 *label = c;
3244 /* Fully qualified ? */
3245 if (*src == '\0') {
3246 if (c != 0) {
3247 if (bp >= eom) {
3248 goto ret_EMSGSIZE;
3249 }
3250 *bp++ = '\0';
3251 }
3252 if ((bp - dst) > MAXCDNAME) {
3253 goto ret_EMSGSIZE;
3254 }
3255
3256 return 1;
3257 }
3258 if (c == 0 || *src == '.') {
3259 goto ret_EMSGSIZE;
3260 }
3261 label = bp++;
3262 continue;
3263 }
3264 if (bp >= eom) {
3265 goto ret_EMSGSIZE;
3266 }
3267 *bp++ = (u_char)c;
3268 }
3269 c = (bp - label - 1);
3270 if ((c & NS_CMPRSFLGS) != 0) { /*%< Label too big. */
3271 goto ret_EMSGSIZE;
3272 }
3273 done:
3274 if (label >= eom) {
3275 goto ret_EMSGSIZE;
3276 }
3277 *label = c;
3278 if (c != 0) {
3279 if (bp >= eom) {
3280 goto ret_EMSGSIZE;
3281 }
3282 *bp++ = 0;
3283 }
3284 if ((bp - dst) > MAXCDNAME) { /*%< src too big */
3285 goto ret_EMSGSIZE;
3286 }
3287
3288 return 0;
3289
3290 ret_EMSGSIZE:
3291 errno = EMSGSIZE;
3292 return -1;
3293}
3294libc_hidden_def(ns_name_pton)
3295
3296/*
3297 * __hnbad(dotted)
3298 * Check whether a name is valid enough for DNS. The rules, as
3299 * laid down by glibc, are:
3300 * - printable input string
3301 * - converts to label notation
3302 * - each label only contains [0-9a-zA-Z_-], up to 63 octets
3303 * - first label doesn¡¯t begin with ¡®-¡¯
3304 * This both is weaker than Unix hostnames (e.g. it allows
3305 * underscores and leading/trailing hyphen-minus) and stronger
3306 * than general (e.g. a leading ¡°*.¡± is valid sometimes), take care.
3307 * return:
3308 * 0 if the name is ok
3309 */
3310int __hnbad(const char *dotted)
3311{
3312 unsigned char c, n, *cp;
3313 unsigned char buf[NS_MAXCDNAME];
3314
3315 cp = (unsigned char *)dotted;
3316 while ((c = *cp++))
3317 if (c < 0x21 || c > 0x7E)
3318 return (1);
3319 if (ns_name_pton(dotted, buf, sizeof(buf)) < 0)
3320 return (2);
3321 if (buf[0] > 0 && buf[1] == '-')
3322 return (3);
3323 cp = buf;
3324 while ((n = *cp++)) {
3325 if (n > 63)
3326 return (4);
3327 while (n--) {
3328 c = *cp++;
3329 if (c < '-' ||
3330 (c > '-' && c < '0') ||
3331 (c > '9' && c < 'A') ||
3332 (c > 'Z' && c < '_') ||
3333 (c > '_' && c < 'a') ||
3334 c > 'z')
3335 return (5);
3336 }
3337 }
3338 return (0);
3339}
3340
3341/*
3342 * ns_name_unpack(msg, eom, src, dst, dstsiz)
3343 * Unpack a domain name from a message, source may be compressed.
3344 * return:
3345 * -1 if it fails, or consumed octets if it succeeds.
3346 */
3347int ns_name_unpack(const u_char *msg, const u_char *eom, const u_char *src,
3348 u_char *dst, size_t dstsiz)
3349{
3350 const u_char *srcp, *dstlim;
3351 u_char *dstp;
3352 int n, len, checked;
3353
3354 len = -1;
3355 checked = 0;
3356 dstp = dst;
3357 srcp = src;
3358 dstlim = dst + dstsiz;
3359 if (srcp < msg || srcp >= eom) {
3360 __set_errno(EMSGSIZE);
3361 return -1;
3362 }
3363 /* Fetch next label in domain name. */
3364 while ((n = *srcp++) != 0) {
3365 /* Check for indirection. */
3366 switch (n & NS_CMPRSFLGS) {
3367 case 0:
3368 /* Limit checks. */
3369 if (dstp + n + 1 >= dstlim || srcp + n >= eom) {
3370 __set_errno(EMSGSIZE);
3371 return -1;
3372 }
3373 checked += n + 1;
3374 *dstp++ = n;
3375 memcpy(dstp, srcp, n);
3376 dstp += n;
3377 srcp += n;
3378 break;
3379
3380 case NS_CMPRSFLGS:
3381 if (srcp >= eom) {
3382 __set_errno(EMSGSIZE);
3383 return -1;
3384 }
3385 if (len < 0)
3386 len = srcp - src + 1;
3387 srcp = msg + (((n & 0x3f) << 8) | (*srcp & 0xff));
3388 if (srcp < msg || srcp >= eom) { /* Out of range. */
3389 __set_errno(EMSGSIZE);
3390 return -1;
3391 }
3392 checked += 2;
3393 /*
3394 * Check for loops in the compressed name;
3395 * if we've looked at the whole message,
3396 * there must be a loop.
3397 */
3398 if (checked >= eom - msg) {
3399 __set_errno(EMSGSIZE);
3400 return -1;
3401 }
3402 break;
3403
3404 default:
3405 __set_errno(EMSGSIZE);
3406 return -1; /* flag error */
3407 }
3408 }
3409 *dstp = '\0';
3410 if (len < 0)
3411 len = srcp - src;
3412 return len;
3413}
3414libc_hidden_def(ns_name_unpack)
3415
3416static int labellen(const unsigned char *lp)
3417{
3418 unsigned bitlen;
3419 unsigned char l = *lp;
3420
3421 if ((l & NS_CMPRSFLGS) == NS_CMPRSFLGS) {
3422 /* should be avoided by the caller */
3423 return -1;
3424 }
3425
3426 if ((l & NS_CMPRSFLGS) == NS_TYPE_ELT) {
3427 if (l == DNS_LABELTYPE_BITSTRING) {
3428 bitlen = lp[1];
3429 if (bitlen == 0)
3430 bitlen = 256;
3431 return ((bitlen + 7 ) / 8 + 1);
3432 }
3433
3434 return -1; /*%< unknwon ELT */
3435 }
3436
3437 return l;
3438}
3439
3440static int mklower(int ch)
3441{
3442 if (ch >= 0x41 && ch <= 0x5A)
3443 return (ch + 0x20);
3444
3445 return ch;
3446}
3447
3448static int dn_find(const unsigned char *domain,
3449 const unsigned char *msg,
3450 const unsigned char * const *dnptrs,
3451 const unsigned char * const *lastdnptr)
3452{
3453 const unsigned char *dn, *cp, *sp;
3454 const unsigned char * const *cpp;
3455 u_int n;
3456
3457 for (cpp = dnptrs; cpp < lastdnptr; cpp++) {
3458 sp = *cpp;
3459 /*
3460 * terminate search on:
3461 * root label
3462 * compression pointer
3463 * unusable offset
3464 */
3465 while (*sp != 0 && (*sp & NS_CMPRSFLGS) == 0 &&
3466 (sp - msg) < 0x4000) {
3467 dn = domain;
3468 cp = sp;
3469
3470 while ((n = *cp++) != 0) {
3471 /*
3472 * check for indirection
3473 */
3474 switch (n & NS_CMPRSFLGS) {
3475 case 0: /*%< normal case, n == len */
3476 n = labellen(cp - 1); /*%< XXX */
3477 if (n != *dn++)
3478 goto next;
3479
3480 for (; n > 0; n--)
3481 if (mklower(*dn++) !=
3482 mklower(*cp++))
3483 goto next;
3484 /* Is next root for both ? */
3485 if (*dn == '\0' && *cp == '\0')
3486 return (sp - msg);
3487 if (*dn)
3488 continue;
3489 goto next;
3490 case NS_CMPRSFLGS: /*%< indirection */
3491 cp = msg + (((n & 0x3f) << 8) | *cp);
3492 break;
3493
3494 default: /*%< illegal type */
3495 errno = EMSGSIZE;
3496 return -1;
3497 }
3498 }
3499next:
3500 sp += *sp + 1;
3501 }
3502 }
3503
3504 errno = ENOENT;
3505 return -1;
3506}
3507
3508int ns_name_pack(const unsigned char *src,
3509 unsigned char *dst, int dstsiz,
3510 const unsigned char **dnptrs,
3511 const unsigned char **lastdnptr)
3512{
3513 unsigned char *dstp;
3514 const unsigned char **cpp, **lpp, *eob, *msg;
3515 const unsigned char *srcp;
3516 int n, l, first = 1;
3517
3518 srcp = src;
3519 dstp = dst;
3520 eob = dstp + dstsiz;
3521 lpp = cpp = NULL;
3522
3523 if (dnptrs != NULL) {
3524 msg = *dnptrs++;
3525 if (msg != NULL) {
3526 for (cpp = dnptrs; *cpp != NULL; cpp++)
3527 continue;
3528
3529 lpp = cpp; /*%< end of list to search */
3530 }
3531 } else {
3532 msg = NULL;
3533 }
3534
3535 /* make sure the domain we are about to add is legal */
3536 l = 0;
3537 do {
3538 int l0;
3539
3540 n = *srcp;
3541 if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) {
3542 errno = EMSGSIZE;
3543 return -1;
3544 }
3545
3546 l0 = labellen(srcp);
3547 if (l0 < 0) {
3548 errno = EINVAL;
3549 return -1;
3550 }
3551
3552 l += l0 + 1;
3553 if (l > MAXCDNAME) {
3554 errno = EMSGSIZE;
3555 return -1;
3556 }
3557
3558 srcp += l0 + 1;
3559 } while (n != 0);
3560
3561 /* from here on we need to reset compression pointer array on error */
3562 srcp = src;
3563
3564 do {
3565 /* Look to see if we can use pointers. */
3566 n = *srcp;
3567
3568 if (n != 0 && msg != NULL) {
3569 l = dn_find(srcp, msg, (const unsigned char * const *) dnptrs,
3570 (const unsigned char * const *) lpp);
3571 if (l >= 0) {
3572 if (dstp + 1 >= eob) {
3573 goto cleanup;
3574 }
3575
3576 *dstp++ = ((u_int32_t)l >> 8) | NS_CMPRSFLGS;
3577 *dstp++ = l % 256;
3578 return (dstp - dst);
3579 }
3580
3581 /* Not found, save it. */
3582 if (lastdnptr != NULL && cpp < lastdnptr - 1 &&
3583 (dstp - msg) < 0x4000 && first) {
3584 *cpp++ = dstp;
3585 *cpp = NULL;
3586 first = 0;
3587 }
3588 }
3589
3590 /* copy label to buffer */
3591 if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) {
3592 /* Should not happen. */
3593 goto cleanup;
3594 }
3595
3596 n = labellen(srcp);
3597 if (dstp + 1 + n >= eob) {
3598 goto cleanup;
3599 }
3600
3601 memcpy(dstp, srcp, (size_t)(n + 1));
3602 srcp += n + 1;
3603 dstp += n + 1;
3604 } while (n != 0);
3605
3606 if (dstp > eob) {
3607cleanup:
3608 if (msg != NULL)
3609 *lpp = NULL;
3610
3611 errno = EMSGSIZE;
3612 return -1;
3613 }
3614
3615 return dstp - dst;
3616}
3617libc_hidden_def(ns_name_pack)
3618
3619int ns_name_compress(const char *src,
3620 unsigned char *dst, size_t dstsiz,
3621 const unsigned char **dnptrs,
3622 const unsigned char **lastdnptr)
3623{
3624 unsigned char tmp[NS_MAXCDNAME];
3625
3626 if (ns_name_pton(src, tmp, sizeof(tmp)) == -1)
3627 return -1;
3628
3629 return ns_name_pack(tmp, dst, dstsiz, dnptrs, lastdnptr);
3630}
3631libc_hidden_def(ns_name_compress)
3632
3633int ns_name_skip(const unsigned char **ptrptr,
3634 const unsigned char *eom)
3635{
3636 const unsigned char *cp;
3637 u_int n;
3638 int l;
3639
3640 cp = *ptrptr;
3641 while (cp < eom && (n = *cp++) != 0) {
3642 /* Check for indirection. */
3643 switch (n & NS_CMPRSFLGS) {
3644 case 0: /*%< normal case, n == len */
3645 cp += n;
3646 continue;
3647 case NS_TYPE_ELT: /*%< EDNS0 extended label */
3648 l = labellen(cp - 1);
3649 if (l < 0) {
3650 errno = EMSGSIZE; /*%< XXX */
3651 return -1;
3652 }
3653 cp += l;
3654 continue;
3655 case NS_CMPRSFLGS: /*%< indirection */
3656 cp++;
3657 break;
3658 default: /*%< illegal type */
3659 errno = EMSGSIZE;
3660 return -1;
3661 }
3662
3663 break;
3664 }
3665
3666 if (cp > eom) {
3667 errno = EMSGSIZE;
3668 return -1;
3669 }
3670
3671 *ptrptr = cp;
3672
3673 return 0;
3674}
3675libc_hidden_def(ns_name_skip)
3676
3677int dn_skipname(const unsigned char *ptr, const unsigned char *eom)
3678{
3679 const unsigned char *saveptr = ptr;
3680
3681 if (ns_name_skip(&ptr, eom) == -1)
3682 return -1;
3683
3684 return ptr - saveptr;
3685}
3686libc_hidden_def(dn_skipname)
3687#endif /* L_ns_name */
3688
3689
3690#ifdef L_res_init
3691
3692/* Will be called under __resolv_lock. */
3693static void res_sync_func(void)
3694{
3695 struct __res_state *rp = &(_res);
3696 int n;
3697
3698 /* If we didn't get malloc failure earlier... */
3699 if (__nameserver != (void*) &__local_nameserver) {
3700 /* TODO:
3701 * if (__nameservers < rp->nscount) - try to grow __nameserver[]?
3702 */
3703#ifdef __UCLIBC_HAS_IPV6__
3704 if (__nameservers > rp->_u._ext.nscount)
3705 __nameservers = rp->_u._ext.nscount;
3706 n = __nameservers;
3707 while (--n >= 0)
3708 __nameserver[n].sa6 = *rp->_u._ext.nsaddrs[n]; /* struct copy */
3709#else /* IPv4 only */
3710 if (__nameservers > rp->nscount)
3711 __nameservers = rp->nscount;
3712 n = __nameservers;
3713 while (--n >= 0)
3714 __nameserver[n].sa4 = rp->nsaddr_list[n]; /* struct copy */
3715#endif
3716 }
3717 __resolv_timeout = rp->retrans ? : RES_TIMEOUT;
3718 __resolv_attempts = rp->retry ? : RES_DFLRETRY;
3719 /* Extend and comment what program is known
3720 * to use which _res.XXX member(s).
3721
3722 __resolv_opts = rp->options;
3723 ...
3724 */
3725}
3726
3727static int
3728__res_vinit(res_state rp, int preinit)
3729{
3730 int i, n, options, retrans, retry, ndots;
3731#ifdef __UCLIBC_HAS_IPV6__
3732 int m = 0;
3733#endif
3734
3735 __UCLIBC_MUTEX_LOCK(__resolv_lock);
3736 __close_nameservers();
3737 __open_nameservers();
3738
3739 if (preinit) {
3740 options = rp->options;
3741 retrans = rp->retrans;
3742 retry = rp->retry;
3743 ndots = rp->ndots;
3744 }
3745
3746 memset(rp, 0, sizeof(*rp));
3747
3748 if (!preinit) {
3749 rp->options = RES_DEFAULT;
3750 rp->retrans = RES_TIMEOUT;
3751 rp->retry = RES_DFLRETRY;
3752 rp->ndots = 1;
3753 } else {
3754 rp->options = options;
3755 rp->retrans = retrans;
3756 rp->retry = retry;
3757 rp->ndots = ndots;
3758 }
3759
3760#ifdef __UCLIBC_HAS_COMPAT_RES_STATE__
3761 /* Was: "rp->id = random();" but:
3762 * - random() pulls in largish static buffers
3763 * - isn't actually random unless, say, srandom(time(NULL)) was called
3764 * - is not used by uclibc anyway :)
3765 */
3766 /* rp->id = 0; - memset did it */
3767#endif
3768#ifdef __UCLIBC_HAS_EXTRA_COMPAT_RES_STATE__
3769 rp->_vcsock = -1;
3770#endif
3771
3772 n = __searchdomains;
3773 if (n > ARRAY_SIZE(rp->dnsrch))
3774 n = ARRAY_SIZE(rp->dnsrch);
3775 for (i = 0; i < n; i++)
3776 rp->dnsrch[i] = __searchdomain[i];
3777
3778 /* copy nameservers' addresses */
3779 i = 0;
3780#ifdef __UCLIBC_HAS_IPV4__
3781 n = 0;
3782 while (n < ARRAY_SIZE(rp->nsaddr_list) && i < __nameservers) {
3783 if (__nameserver[i].sa.sa_family == AF_INET) {
3784 rp->nsaddr_list[n] = __nameserver[i].sa4; /* struct copy */
3785#ifdef __UCLIBC_HAS_IPV6__
3786 if (m < ARRAY_SIZE(rp->_u._ext.nsaddrs)) {
3787 rp->_u._ext.nsaddrs[m] = (void*) &rp->nsaddr_list[n];
3788 m++;
3789 }
3790#endif
3791 n++;
3792 }
3793#ifdef __UCLIBC_HAS_IPV6__
3794 if (__nameserver[i].sa.sa_family == AF_INET6
3795 && m < ARRAY_SIZE(rp->_u._ext.nsaddrs)
3796 ) {
3797 struct sockaddr_in6 *sa6 = malloc(sizeof(*sa6));
3798 if (sa6) {
3799 *sa6 = __nameserver[i].sa6; /* struct copy */
3800 rp->_u._ext.nsaddrs[m] = sa6;
3801 m++;
3802 }
3803 }
3804#endif
3805 i++;
3806 }
3807 rp->nscount = n;
3808#ifdef __UCLIBC_HAS_IPV6__
3809 rp->_u._ext.nscount = m;
3810#endif
3811
3812#else /* IPv6 only */
3813 while (m < ARRAY_SIZE(rp->_u._ext.nsaddrs) && i < __nameservers) {
3814 struct sockaddr_in6 *sa6 = malloc(sizeof(*sa6));
3815 if (sa6) {
3816 *sa6 = __nameserver[i].sa6; /* struct copy */
3817 rp->_u._ext.nsaddrs[m] = sa6;
3818 m++;
3819 }
3820 i++;
3821 }
3822 rp->_u._ext.nscount = m;
3823#endif
3824
3825 rp->options |= RES_INIT;
3826
3827 __UCLIBC_MUTEX_UNLOCK(__resolv_lock);
3828 return 0;
3829}
3830
3831static void
3832__res_iclose(void)
3833{
3834 __UCLIBC_MUTEX_LOCK(__resolv_lock);
3835 __close_nameservers();
3836 __res_sync = NULL;
3837#ifdef __UCLIBC_HAS_IPV6__
3838 {
3839 char *p1 = (char*) &(_res.nsaddr_list[0]);
3840 int m = 0;
3841 /* free nsaddrs[m] if they do not point to nsaddr_list[x] */
3842 while (m < ARRAY_SIZE(_res._u._ext.nsaddrs)) {
3843 char *p2 = (char*)(_res._u._ext.nsaddrs[m++]);
3844 if (p2 < p1 || (p2 - p1) > sizeof(_res.nsaddr_list))
3845 free(p2);
3846 }
3847 }
3848#endif
3849 memset(&_res, 0, sizeof(_res));
3850 __UCLIBC_MUTEX_UNLOCK(__resolv_lock);
3851}
3852
3853/*
3854 * This routine is for closing the socket if a virtual circuit is used and
3855 * the program wants to close it. This provides support for endhostent()
3856 * which expects to close the socket.
3857 *
3858 * This routine is not expected to be user visible.
3859 */
3860
3861void
3862res_nclose(res_state statp)
3863{
3864 __res_iclose();
3865}
3866
3867#ifdef __UCLIBC_HAS_BSD_RES_CLOSE__
3868void res_close(void)
3869{
3870 __res_iclose();
3871}
3872#endif
3873
3874/* This needs to be after the use of _res in res_init, above. */
3875#undef _res
3876
3877#ifndef __UCLIBC_HAS_THREADS__
3878/* The resolver state for use by single-threaded programs.
3879 This differs from plain `struct __res_state _res;' in that it doesn't
3880 create a common definition, but a plain symbol that resides in .bss,
3881 which can have an alias. */
3882struct __res_state _res __attribute__((section (".bss")));
3883struct __res_state *__resp = &_res;
3884#else /* __UCLIBC_HAS_THREADS__ */
3885struct __res_state _res __attribute__((section (".bss"))) attribute_hidden;
3886
3887# if defined __UCLIBC_HAS_TLS__
3888# undef __resp
3889__thread struct __res_state *__resp = &_res;
3890/*
3891 * FIXME: Add usage of hidden attribute for this when used in the shared
3892 * library. It currently crashes the linker when doing section
3893 * relocations.
3894 */
3895extern __thread struct __res_state *__libc_resp
3896 __attribute__ ((alias ("__resp"))) attribute_hidden;
3897# else
3898# undef __resp
3899struct __res_state *__resp = &_res;
3900# endif
3901#endif /* !__UCLIBC_HAS_THREADS__ */
3902
3903static unsigned int
3904res_randomid(void)
3905{
3906 return 0xffff & getpid();
3907}
3908
3909/* Our res_init never fails (always returns 0) */
3910int
3911res_init(void)
3912{
3913 /*
3914 * These three fields used to be statically initialized. This made
3915 * it hard to use this code in a shared library. It is necessary,
3916 * now that we're doing dynamic initialization here, that we preserve
3917 * the old semantics: if an application modifies one of these three
3918 * fields of _res before res_init() is called, res_init() will not
3919 * alter them. Of course, if an application is setting them to
3920 * _zero_ before calling res_init(), hoping to override what used
3921 * to be the static default, we can't detect it and unexpected results
3922 * will follow. Zero for any of these fields would make no sense,
3923 * so one can safely assume that the applications were already getting
3924 * unexpected results.
3925 *
3926 * _res.options is tricky since some apps were known to diddle the bits
3927 * before res_init() was first called. We can't replicate that semantic
3928 * with dynamic initialization (they may have turned bits off that are
3929 * set in RES_DEFAULT). Our solution is to declare such applications
3930 * "broken". They could fool us by setting RES_INIT but none do (yet).
3931 */
3932
3933 __UCLIBC_MUTEX_LOCK(__resolv_lock);
3934
3935 if (!_res.retrans)
3936 _res.retrans = RES_TIMEOUT;
3937 if (!_res.retry)
3938 _res.retry = 4;
3939 if (!(_res.options & RES_INIT))
3940 _res.options = RES_DEFAULT;
3941
3942 /*
3943 * This one used to initialize implicitly to zero, so unless the app
3944 * has set it to something in particular, we can randomize it now.
3945 */
3946 if (!_res.id)
3947 _res.id = res_randomid();
3948 __res_sync = res_sync_func;
3949
3950 __UCLIBC_MUTEX_UNLOCK(__resolv_lock);
3951
3952 __res_vinit(&_res, 1);
3953
3954 return 0;
3955}
3956libc_hidden_def(res_init)
3957
3958/*
3959 * Set up default settings. If the configuration file exist, the values
3960 * there will have precedence. Otherwise, the server address is set to
3961 * INADDR_ANY and the default domain name comes from the gethostname().
3962 *
3963 * An interrim version of this code (BIND 4.9, pre-4.4BSD) used 127.0.0.1
3964 * rather than INADDR_ANY ("0.0.0.0") as the default name server address
3965 * since it was noted that INADDR_ANY actually meant ``the first interface
3966 * you "ifconfig"'d at boot time'' and if this was a SLIP or PPP interface,
3967 * it had to be "up" in order for you to reach your own name server. It
3968 * was later decided that since the recommended practice is to always
3969 * install local static routes through 127.0.0.1 for all your network
3970 * interfaces, that we could solve this problem without a code change.
3971 *
3972 * The configuration file should always be used, since it is the only way
3973 * to specify a default domain. If you are running a server on your local
3974 * machine, you should say "nameserver 0.0.0.0" or "nameserver 127.0.0.1"
3975 * in the configuration file.
3976 *
3977 * Return 0 if completes successfully, -1 on error
3978 */
3979int
3980res_ninit(res_state statp)
3981{
3982 return __res_vinit(statp, 0);
3983}
3984
3985#endif /* L_res_init */
3986
3987#ifdef L_res_state
3988# if defined __UCLIBC_HAS_TLS__
3989struct __res_state *
3990__res_state (void)
3991{
3992 return __resp;
3993}
3994# else
3995# undef _res
3996extern struct __res_state _res;
3997
3998/* When threaded, _res may be a per-thread variable. */
3999struct __res_state *
4000weak_const_function
4001__res_state (void)
4002{
4003 return &_res;
4004}
4005# endif
4006
4007#endif /* L_res_state */
4008
4009
4010#ifdef L_res_query
4011
4012int res_query(const char *dname, int class, int type,
4013 unsigned char *answer, int anslen)
4014{
4015 int i;
4016 unsigned char *packet = NULL;
4017 struct resolv_answer a;
4018
4019 if (!dname || class != 1 /* CLASS_IN */) {
4020 h_errno = NO_RECOVERY;
4021 return -1;
4022 }
4023
4024 memset(&a, '\0', sizeof(a));
4025 i = __dns_lookup(dname, type, &packet, &a);
4026
4027 if (i < 0) {
4028 if (!h_errno) /* TODO: can this ever happen? */
4029 h_errno = TRY_AGAIN;
4030 return -1;
4031 }
4032
4033 free(a.dotted);
4034
4035 if (a.atype == type) { /* CNAME */
4036 if (i > anslen)
4037 i = anslen;
4038 memcpy(answer, packet, i);
4039 }
4040 free(packet);
4041 return i;
4042}
4043libc_hidden_def(res_query)
4044
4045/*
4046 * Formulate a normal query, send, and retrieve answer in supplied buffer.
4047 * Return the size of the response on success, -1 on error.
4048 * If enabled, implement search rules until answer or unrecoverable failure
4049 * is detected. Error code, if any, is left in h_errno.
4050 */
4051#define __TRAILING_DOT (1<<0)
4052#define __GOT_NODATA (1<<1)
4053#define __GOT_SERVFAIL (1<<2)
4054#define __TRIED_AS_IS (1<<3)
4055int res_search(const char *name, int class, int type, u_char *answer,
4056 int anslen)
4057{
4058 const char *cp;
4059 char **domain;
4060 HEADER *hp = (HEADER *)(void *)answer;
4061 unsigned dots;
4062 unsigned state;
4063 int ret, saved_herrno;
4064 uint32_t _res_options;
4065 unsigned _res_ndots;
4066 char **_res_dnsrch;
4067
4068 if (!name || !answer) {
4069 h_errno = NETDB_INTERNAL;
4070 return -1;
4071 }
4072
4073 again:
4074 __UCLIBC_MUTEX_LOCK(__resolv_lock);
4075 _res_options = _res.options;
4076 _res_ndots = _res.ndots;
4077 _res_dnsrch = _res.dnsrch;
4078 __UCLIBC_MUTEX_UNLOCK(__resolv_lock);
4079 if (!(_res_options & RES_INIT)) {
4080 res_init(); /* our res_init never fails */
4081 goto again;
4082 }
4083
4084 state = 0;
4085 errno = 0;
4086 h_errno = HOST_NOT_FOUND; /* default, if we never query */
4087 dots = 0;
4088 for (cp = name; *cp; cp++)
4089 dots += (*cp == '.');
4090
4091 if (cp > name && *--cp == '.')
4092 state |= __TRAILING_DOT;
4093
4094 /*
4095 * If there are dots in the name already, let's just give it a try
4096 * 'as is'. The threshold can be set with the "ndots" option.
4097 */
4098 saved_herrno = -1;
4099 if (dots >= _res_ndots) {
4100 ret = res_querydomain(name, NULL, class, type, answer, anslen);
4101 if (ret > 0)
4102 return ret;
4103 saved_herrno = h_errno;
4104 state |= __TRIED_AS_IS;
4105 }
4106
4107 /*
4108 * We do at least one level of search if
4109 * - there is no dot and RES_DEFNAME is set, or
4110 * - there is at least one dot, there is no trailing dot,
4111 * and RES_DNSRCH is set.
4112 */
4113 if ((!dots && (_res_options & RES_DEFNAMES))
4114 || (dots && !(state & __TRAILING_DOT) && (_res_options & RES_DNSRCH))
4115 ) {
4116 bool done = 0;
4117
4118 for (domain = _res_dnsrch; *domain && !done; domain++) {
4119
4120 ret = res_querydomain(name, *domain, class, type,
4121 answer, anslen);
4122 if (ret > 0)
4123 return ret;
4124
4125 /*
4126 * If no server present, give up.
4127 * If name isn't found in this domain,
4128 * keep trying higher domains in the search list
4129 * (if that's enabled).
4130 * On a NO_DATA error, keep trying, otherwise
4131 * a wildcard entry of another type could keep us
4132 * from finding this entry higher in the domain.
4133 * If we get some other error (negative answer or
4134 * server failure), then stop searching up,
4135 * but try the input name below in case it's
4136 * fully-qualified.
4137 */
4138 if (errno == ECONNREFUSED) {
4139 h_errno = TRY_AGAIN;
4140 return -1;
4141 }
4142
4143 switch (h_errno) {
4144 case NO_DATA:
4145 state |= __GOT_NODATA;
4146 /* FALLTHROUGH */
4147 case HOST_NOT_FOUND:
4148 /* keep trying */
4149 break;
4150 case TRY_AGAIN:
4151 if (hp->rcode == SERVFAIL) {
4152 /* try next search element, if any */
4153 state |= __GOT_SERVFAIL;
4154 break;
4155 }
4156 /* FALLTHROUGH */
4157 default:
4158 /* anything else implies that we're done */
4159 done = 1;
4160 }
4161 /*
4162 * if we got here for some reason other than DNSRCH,
4163 * we only wanted one iteration of the loop, so stop.
4164 */
4165 if (!(_res_options & RES_DNSRCH))
4166 done = 1;
4167 }
4168 }
4169
4170 /*
4171 * if we have not already tried the name "as is", do that now.
4172 * note that we do this regardless of how many dots were in the
4173 * name or whether it ends with a dot.
4174 */
4175 if (!(state & __TRIED_AS_IS)) {
4176 ret = res_querydomain(name, NULL, class, type, answer, anslen);
4177 if (ret > 0)
4178 return ret;
4179 }
4180
4181 /*
4182 * if we got here, we didn't satisfy the search.
4183 * if we did an initial full query, return that query's h_errno
4184 * (note that we wouldn't be here if that query had succeeded).
4185 * else if we ever got a nodata, send that back as the reason.
4186 * else send back meaningless h_errno, that being the one from
4187 * the last DNSRCH we did.
4188 */
4189 if (saved_herrno != -1)
4190 h_errno = saved_herrno;
4191 else if (state & __GOT_NODATA)
4192 h_errno = NO_DATA;
4193 else if (state & __GOT_SERVFAIL)
4194 h_errno = TRY_AGAIN;
4195 return -1;
4196}
4197#undef __TRAILING_DOT
4198#undef __GOT_NODATA
4199#undef __GOT_SERVFAIL
4200#undef __TRIED_AS_IS
4201/*
4202 * Perform a call on res_query on the concatenation of name and domain,
4203 * removing a trailing dot from name if domain is NULL.
4204 */
4205int res_querydomain(const char *name, const char *domain, int class, int type,
4206 u_char *answer, int anslen)
4207{
4208 char nbuf[MAXDNAME];
4209 const char *longname = nbuf;
4210 size_t n, d;
4211#ifdef DEBUG
4212 uint32_t _res_options;
4213#endif
4214
4215 if (!name || !answer) {
4216 h_errno = NETDB_INTERNAL;
4217 return -1;
4218 }
4219
4220#ifdef DEBUG
4221 again:
4222 __UCLIBC_MUTEX_LOCK(__resolv_lock);
4223 _res_options = _res.options;
4224 __UCLIBC_MUTEX_UNLOCK(__resolv_lock);
4225 if (!(_res_options & RES_INIT)) {
4226 res_init(); /* our res_init never fails */
4227 goto again;
4228 }
4229 if (_res_options & RES_DEBUG)
4230 printf(";; res_querydomain(%s, %s, %d, %d)\n",
4231 name, (domain ? domain : "<Nil>"), class, type);
4232#endif
4233 if (domain == NULL) {
4234 /*
4235 * Check for trailing '.';
4236 * copy without '.' if present.
4237 */
4238 n = strlen(name);
4239 if (n + 1 > sizeof(nbuf)) {
4240 h_errno = NO_RECOVERY;
4241 return -1;
4242 }
4243 if (n > 0 && name[--n] == '.') {
4244 strncpy(nbuf, name, n);
4245 nbuf[n] = '\0';
4246 } else
4247 longname = name;
4248 } else {
4249 n = strlen(name);
4250 d = strlen(domain);
4251 if (n + 1 + d + 1 > sizeof(nbuf)) {
4252 h_errno = NO_RECOVERY;
4253 return -1;
4254 }
4255 snprintf(nbuf, sizeof(nbuf), "%s.%s", name, domain);
4256 }
4257 return res_query(longname, class, type, answer, anslen);
4258}
4259libc_hidden_def(res_querydomain)
4260#endif /* L_res_query */
4261
4262#ifdef L_ns_netint
4263unsigned int ns_get16(const unsigned char *src)
4264{
4265 unsigned int dst;
4266 NS_GET16(dst, src);
4267 return dst;
4268}
4269
4270unsigned long ns_get32(const unsigned char *src)
4271{
4272 unsigned long dst;
4273 NS_GET32(dst, src);
4274 return dst;
4275}
4276
4277void ns_put16(unsigned int src, unsigned char *dst)
4278{
4279 NS_PUT16(src, dst);
4280}
4281
4282void ns_put32(unsigned long src, unsigned char *dst)
4283{
4284 NS_PUT32(src, dst);
4285}
4286#endif /* L_ns_netint */
4287
4288#ifdef L_ns_parse
4289/* These need to be in the same order as the nres.h:ns_flag enum. */
4290struct _ns_flagdata { unsigned short mask, shift; };
4291static const struct _ns_flagdata _ns_flagdata[16] = {
4292 { 0x8000, 15 }, /*%< qr. */
4293 { 0x7800, 11 }, /*%< opcode. */
4294 { 0x0400, 10 }, /*%< aa. */
4295 { 0x0200, 9 }, /*%< tc. */
4296 { 0x0100, 8 }, /*%< rd. */
4297 { 0x0080, 7 }, /*%< ra. */
4298 { 0x0040, 6 }, /*%< z. */
4299 { 0x0020, 5 }, /*%< ad. */
4300 { 0x0010, 4 }, /*%< cd. */
4301 { 0x000f, 0 }, /*%< rcode. */
4302 { 0x0000, 0 }, /*%< expansion (1/6). */
4303 { 0x0000, 0 }, /*%< expansion (2/6). */
4304 { 0x0000, 0 }, /*%< expansion (3/6). */
4305 { 0x0000, 0 }, /*%< expansion (4/6). */
4306 { 0x0000, 0 }, /*%< expansion (5/6). */
4307 { 0x0000, 0 }, /*%< expansion (6/6). */
4308};
4309
4310static void setsection(ns_msg *msg, ns_sect sect)
4311{
4312 msg->_sect = sect;
4313 if (sect == ns_s_max) {
4314 msg->_rrnum = -1;
4315 msg->_ptr = NULL;
4316 } else {
4317 msg->_rrnum = 0;
4318 msg->_ptr = msg->_sections[(int)sect];
4319 }
4320}
4321
4322int ns_skiprr(const unsigned char *ptr,
4323 const unsigned char *eom,
4324 ns_sect section, int count)
4325{
4326 const u_char *optr = ptr;
4327
4328 for (; count > 0; count--) {
4329 int b, rdlength;
4330
4331 b = dn_skipname(ptr, eom);
4332 if (b < 0) {
4333 errno = EMSGSIZE;
4334 return -1;
4335 }
4336
4337 ptr += b/*Name*/ + NS_INT16SZ/*Type*/ + NS_INT16SZ/*Class*/;
4338 if (section != ns_s_qd) {
4339 if (ptr + NS_INT32SZ + NS_INT16SZ > eom) {
4340 errno = EMSGSIZE;
4341 return -1;
4342 }
4343
4344 ptr += NS_INT32SZ/*TTL*/;
4345 NS_GET16(rdlength, ptr);
4346 ptr += rdlength/*RData*/;
4347 }
4348 }
4349
4350 if (ptr > eom) {
4351 errno = EMSGSIZE;
4352 return -1;
4353 }
4354
4355 return ptr - optr;
4356}
4357libc_hidden_def(ns_skiprr)
4358
4359int
4360ns_initparse(const unsigned char *msg, int msglen, ns_msg *handle)
4361{
4362 const u_char *eom = msg + msglen;
4363 int i;
4364
4365 handle->_msg = msg;
4366 handle->_eom = eom;
4367 if (msg + NS_INT16SZ > eom) {
4368 errno = EMSGSIZE;
4369 return -1;
4370 }
4371
4372 NS_GET16(handle->_id, msg);
4373 if (msg + NS_INT16SZ > eom) {
4374 errno = EMSGSIZE;
4375 return -1;
4376 }
4377
4378 NS_GET16(handle->_flags, msg);
4379 for (i = 0; i < ns_s_max; i++) {
4380 if (msg + NS_INT16SZ > eom) {
4381 errno = EMSGSIZE;
4382 return -1;
4383 }
4384
4385 NS_GET16(handle->_counts[i], msg);
4386 }
4387 for (i = 0; i < ns_s_max; i++)
4388 if (handle->_counts[i] == 0)
4389 handle->_sections[i] = NULL;
4390 else {
4391 int b = ns_skiprr(msg, eom, (ns_sect)i,
4392 handle->_counts[i]);
4393
4394 if (b < 0)
4395 return -1;
4396 handle->_sections[i] = msg;
4397 msg += b;
4398 }
4399
4400 if (msg != eom) {
4401 errno = EMSGSIZE;
4402 return -1;
4403 }
4404
4405 setsection(handle, ns_s_max);
4406 return 0;
4407}
4408
4409int
4410ns_parserr(ns_msg *handle, ns_sect section, int rrnum, ns_rr *rr)
4411{
4412 int b;
4413 int tmp;
4414
4415 /* Make section right. */
4416 tmp = section;
4417 if (tmp < 0 || section >= ns_s_max) {
4418 errno = ENODEV;
4419 return -1;
4420 }
4421
4422 if (section != handle->_sect)
4423 setsection(handle, section);
4424
4425 /* Make rrnum right. */
4426 if (rrnum == -1)
4427 rrnum = handle->_rrnum;
4428 if (rrnum < 0 || rrnum >= handle->_counts[(int)section]) {
4429 errno = ENODEV;
4430 return -1;
4431 }
4432 if (rrnum < handle->_rrnum)
4433 setsection(handle, section);
4434 if (rrnum > handle->_rrnum) {
4435 b = ns_skiprr(handle->_ptr, handle->_eom, section,
4436 rrnum - handle->_rrnum);
4437
4438 if (b < 0)
4439 return -1;
4440 handle->_ptr += b;
4441 handle->_rrnum = rrnum;
4442 }
4443
4444 /* Do the parse. */
4445 b = dn_expand(handle->_msg, handle->_eom,
4446 handle->_ptr, rr->name, NS_MAXDNAME);
4447 if (b < 0)
4448 return -1;
4449 handle->_ptr += b;
4450 if (handle->_ptr + NS_INT16SZ + NS_INT16SZ > handle->_eom) {
4451 errno = EMSGSIZE;
4452 return -1;
4453 }
4454 NS_GET16(rr->type, handle->_ptr);
4455 NS_GET16(rr->rr_class, handle->_ptr);
4456 if (section == ns_s_qd) {
4457 rr->ttl = 0;
4458 rr->rdlength = 0;
4459 rr->rdata = NULL;
4460 } else {
4461 if (handle->_ptr + NS_INT32SZ + NS_INT16SZ > handle->_eom) {
4462 errno = EMSGSIZE;
4463 return -1;
4464 }
4465 NS_GET32(rr->ttl, handle->_ptr);
4466 NS_GET16(rr->rdlength, handle->_ptr);
4467 if (handle->_ptr + rr->rdlength > handle->_eom) {
4468 errno = EMSGSIZE;
4469 return -1;
4470 }
4471 rr->rdata = handle->_ptr;
4472 handle->_ptr += rr->rdlength;
4473 }
4474 if (++handle->_rrnum > handle->_counts[(int)section])
4475 setsection(handle, (ns_sect)((int)section + 1));
4476
4477 return 0;
4478}
4479
4480int ns_msg_getflag(ns_msg handle, int flag)
4481{
4482 return ((handle)._flags & _ns_flagdata[flag].mask) >> _ns_flagdata[flag].shift;
4483}
4484#endif /* L_ns_parse */
4485
4486#ifdef L_res_data
4487int res_mkquery(int op, const char *dname, int class, int type,
4488 const unsigned char *data, int datalen,
4489 const unsigned char *newrr_in,
4490 unsigned char *buf, int buflen)
4491{
4492 HEADER *hp;
4493 unsigned char *cp, *ep;
4494 unsigned char *dnptrs[20], **dpp, **lastdnptr;
4495 uint32_t _res_options;
4496 int n;
4497
4498 if (!buf || buflen < HFIXEDSZ) {
4499 h_errno = NETDB_INTERNAL;
4500 return -1;
4501 }
4502
4503 again:
4504 __UCLIBC_MUTEX_LOCK(__resolv_lock);
4505 _res_options = _res.options;
4506 __UCLIBC_MUTEX_UNLOCK(__resolv_lock);
4507 if (!(_res_options & RES_INIT)) {
4508 res_init(); /* our res_init never fails */
4509 goto again;
4510 }
4511
4512#ifdef DEBUG
4513 if (_res_options & RES_DEBUG)
4514 printf(";; res_mkquery(%d, %s, %d, %d)\n",
4515 op, dname && *dname ? dname : "<null>", class, type);
4516#endif
4517
4518 memset(buf, 0, HFIXEDSZ);
4519 hp = (HEADER *) buf;
4520 hp->id = getpid() & 0xffff;
4521 hp->opcode = op;
4522 hp->rd = (_res.options & RES_RECURSE) != 0U;
4523 hp->rcode = NOERROR;
4524
4525 cp = buf + HFIXEDSZ;
4526 ep = buf + buflen;
4527 dpp = dnptrs;
4528 *dpp++ = buf;
4529 *dpp++ = NULL;
4530 lastdnptr = dnptrs + sizeof dnptrs / sizeof dnptrs[0];
4531
4532 /*
4533 * perform opcode specific processing
4534 */
4535 switch (op) {
4536 case QUERY:
4537 case NS_NOTIFY_OP:
4538 if (ep - cp < QFIXEDSZ)
4539 return -1;
4540
4541 n = dn_comp(dname, cp, ep - cp - QFIXEDSZ, dnptrs, lastdnptr);
4542 if (n < 0)
4543 return -1;
4544
4545 cp += n;
4546 NS_PUT16(type, cp);
4547 NS_PUT16(class, cp);
4548 hp->qdcount = htons(1);
4549
4550 if (op == QUERY || data == NULL)
4551 break;
4552
4553 /*
4554 * Make an additional record for completion domain.
4555 */
4556 if ((ep - cp) < RRFIXEDSZ)
4557 return -1;
4558
4559 n = dn_comp((const char *)data, cp, ep - cp - RRFIXEDSZ,
4560 dnptrs, lastdnptr);
4561 if (n < 0)
4562 return -1;
4563
4564 cp += n;
4565 NS_PUT16(T_NULL, cp);
4566 NS_PUT16(class, cp);
4567 NS_PUT32(0, cp);
4568 NS_PUT16(0, cp);
4569 hp->arcount = htons(1);
4570
4571 break;
4572
4573 case IQUERY:
4574 /*
4575 * Initialize answer section
4576 */
4577 if (ep - cp < 1 + RRFIXEDSZ + datalen)
4578 return -1;
4579
4580 *cp++ = '\0'; /*%< no domain name */
4581 NS_PUT16(type, cp);
4582 NS_PUT16(class, cp);
4583 NS_PUT32(0, cp);
4584 NS_PUT16(datalen, cp);
4585
4586 if (datalen) {
4587 memcpy(cp, data, (size_t)datalen);
4588 cp += datalen;
4589 }
4590
4591 hp->ancount = htons(1);
4592 break;
4593
4594 default:
4595 return -1;
4596 }
4597
4598 return cp - buf;
4599}
4600#endif /* L_res_data */
4601
4602/* Unimplemented: */
4603/* res_send */