OSDN Git Service

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