OSDN Git Service

resolv.c: add support for per thread res_state
[uclinux-h8/uClibc.git] / 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 /* Nota bene:
129  * The whole resolver code has several (severe) problems:
130  * - it doesn't even build without IPv4, i.e. !UCLIBC_HAS_IPV4 but only IPv6
131  * - it is way too big
132  *
133  * Both points above are considered bugs, patches/reimplementations welcome.
134  */
135 /* RFC 1035
136 ...
137 Whenever an octet represents a numeric quantity, the left most bit
138 in the diagram is the high order or most significant bit.
139 That is, the bit labeled 0 is the most significant bit.
140 ...
141
142 4.1.1. Header section format
143       0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15
144     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
145     |                      ID                       |
146     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
147     |QR|   OPCODE  |AA|TC|RD|RA| 0  0  0|   RCODE   |
148     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
149     |                    QDCOUNT                    |
150     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
151     |                    ANCOUNT                    |
152     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
153     |                    NSCOUNT                    |
154     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
155     |                    ARCOUNT                    |
156     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
157 ID      16 bit random identifier assigned by querying peer.
158         Used to match query/response.
159 QR      message is a query (0), or a response (1).
160 OPCODE  0   standard query (QUERY)
161         1   inverse query (IQUERY)
162         2   server status request (STATUS)
163 AA      Authoritative Answer - this bit is valid in responses.
164         Responding name server is an authority for the domain name
165         in question section. Answer section may have multiple owner names
166         because of aliases.  The AA bit corresponds to the name which matches
167         the query name, or the first owner name in the answer section.
168 TC      TrunCation - this message was truncated.
169 RD      Recursion Desired - this bit may be set in a query and
170         is copied into the response.  If RD is set, it directs
171         the name server to pursue the query recursively.
172         Recursive query support is optional.
173 RA      Recursion Available - this be is set or cleared in a
174         response, and denotes whether recursive query support is
175         available in the name server.
176 RCODE   Response code.
177         0   No error condition
178         1   Format error
179         2   Server failure - server was unable to process the query
180             due to a problem with the name server.
181         3   Name Error - meaningful only for responses from
182             an authoritative name server. The referenced domain name
183             does not exist.
184         4   Not Implemented.
185         5   Refused.
186 QDCOUNT number of entries in the question section.
187 ANCOUNT number of records in the answer section.
188 NSCOUNT number of records in the authority records section.
189 ARCOUNT number of records in the additional records section.
190
191 4.1.2. Question section format
192
193 The section contains QDCOUNT (usually 1) entries, each of this format:
194       0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15
195     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
196     /                     QNAME                     /
197     /                                               /
198     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
199     |                     QTYPE                     |
200     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
201     |                     QCLASS                    |
202     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
203 QNAME   a domain name represented as a sequence of labels, where
204         each label consists of a length octet followed by that
205         number of octets. The domain name terminates with the
206         zero length octet for the null label of the root. Note
207         that this field may be an odd number of octets; no
208         padding is used.
209 QTYPE   a two octet type of the query.
210           1 a host address [REQ_A const]
211           2 an authoritative name server
212           3 a mail destination (Obsolete - use MX)
213           4 a mail forwarder (Obsolete - use MX)
214           5 the canonical name for an alias
215           6 marks the start of a zone of authority
216           7 a mailbox domain name (EXPERIMENTAL)
217           8 a mail group member (EXPERIMENTAL)
218           9 a mail rename domain name (EXPERIMENTAL)
219          10 a null RR (EXPERIMENTAL)
220          11 a well known service description
221          12 a domain name pointer [REQ_PTR const]
222          13 host information
223          14 mailbox or mail list information
224          15 mail exchange
225          16 text strings
226        0x1c IPv6?
227         252 a request for a transfer of an entire zone
228         253 a request for mailbox-related records (MB, MG or MR)
229         254 a request for mail agent RRs (Obsolete - see MX)
230         255 a request for all records
231 QCLASS  a two octet code that specifies the class of the query.
232           1 the Internet
233         (others are historic only)
234         255 any class
235
236 4.1.3. Resource record format
237
238 The answer, authority, and additional sections all share the same format:
239 a variable number of resource records, where the number of records
240 is specified in the corresponding count field in the header.
241 Each resource record has this format:
242       0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15
243     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
244     /                                               /
245     /                      NAME                     /
246     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
247     |                      TYPE                     |
248     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
249     |                     CLASS                     |
250     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
251     |                      TTL                      |
252     |                                               |
253     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
254     |                   RDLENGTH                    |
255     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--|
256     /                     RDATA                     /
257     /                                               /
258     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
259 NAME    a domain name to which this resource record pertains.
260 TYPE    two octets containing one of the RR type codes.  This
261         field specifies the meaning of the data in the RDATA field.
262 CLASS   two octets which specify the class of the data in the RDATA field.
263 TTL     a 32 bit unsigned integer that specifies the time interval
264         (in seconds) that the record may be cached.
265 RDLENGTH a 16 bit integer, length in octets of the RDATA field.
266 RDATA   a variable length string of octets that describes the resource.
267         The format of this information varies according to the TYPE
268         and CLASS of the resource record.
269         If the TYPE is A and the CLASS is IN, it's a 4 octet IP address.
270
271 4.1.4. Message compression
272
273 In order to reduce the size of messages, domain names can be compressed.
274 An entire domain name or a list of labels at the end of a domain name
275 is replaced with a pointer to a prior occurance of the same name.
276
277 The pointer takes the form of a two octet sequence:
278     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
279     | 1  1|                OFFSET                   |
280     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
281 The first two bits are ones.  This allows a pointer to be distinguished
282 from a label, since the label must begin with two zero bits because
283 labels are restricted to 63 octets or less.  The OFFSET field specifies
284 an offset from the start of the message (i.e., the first octet
285 of the ID field in the domain header).
286 A zero offset specifies the first byte of the ID field, etc.
287 Domain name in a message can be represented as either:
288    - a sequence of labels ending in a zero octet
289    - a pointer
290    - a sequence of labels ending with a pointer
291  */
292
293 #define __FORCE_GLIBC
294 #include <features.h>
295 #include <string.h>
296 #include <stdio.h>
297 #include <signal.h>
298 #include <errno.h>
299 #include <sys/poll.h>
300 #include <sys/socket.h>
301 #include <sys/types.h>
302 #include <sys/time.h>
303 #include <netinet/in.h>
304 #include <arpa/inet.h>
305 #include <stdlib.h>
306 #include <unistd.h>
307 #include <resolv.h>
308 #include <netdb.h>
309 #include <ctype.h>
310 #include <stdbool.h>
311 #include <time.h>
312 #include <arpa/nameser.h>
313 #include <sys/utsname.h>
314 #include <sys/un.h>
315 #include <bits/uClibc_mutex.h>
316
317 /* poll() is not supported in kernel <= 2.0, therefore if __NR_poll is
318  * not available, we assume an old Linux kernel is in use and we will
319  * use select() instead. */
320 #include <sys/syscall.h>
321 #ifndef __NR_poll
322 # define USE_SELECT
323 #endif
324
325 #if defined __UCLIBC_HAS_IPV4__ && defined __UCLIBC_HAS_IPV6__
326 #define IF_HAS_BOTH(...) __VA_ARGS__
327 #else
328 #define IF_HAS_BOTH(...)
329 #endif
330
331 #define MAX_RECURSE    5
332 #define MAX_ALIASES    5
333
334 /* 1:ip + 1:full + MAX_ALIASES:aliases + 1:NULL */
335 #define ALIAS_DIM      (2 + MAX_ALIASES + 1)
336
337 #undef DEBUG
338 /* #define DEBUG */
339
340 #ifdef DEBUG
341 #define DPRINTF(X,args...) fprintf(stderr, X, ##args)
342 #else
343 #define DPRINTF(X,args...)
344 #endif
345
346 #undef ARRAY_SIZE
347 #define ARRAY_SIZE(v) (sizeof(v) / sizeof((v)[0]))
348
349 /* Make sure the incoming char * buffer is aligned enough to handle our random
350  * structures.  This define is the same as we use for malloc alignment (which
351  * has same requirements).  The offset is the number of bytes we need to adjust
352  * in order to attain desired alignment.
353  */
354 #define ALIGN_ATTR __alignof__(double __attribute_aligned__ (sizeof(size_t)))
355 #define ALIGN_BUFFER_OFFSET(buf) ((ALIGN_ATTR - ((size_t)buf % ALIGN_ATTR)) % ALIGN_ATTR)
356
357
358 /* Structs */
359 struct resolv_header {
360         int id;
361         int qr, opcode, aa, tc, rd, ra, rcode;
362         int qdcount;
363         int ancount;
364         int nscount;
365         int arcount;
366 };
367
368 struct resolv_question {
369         char *dotted;
370         int qtype;
371         int qclass;
372 };
373
374 struct resolv_answer {
375         char *dotted;
376         int atype;
377         int aclass;
378         int ttl;
379         int rdlength;
380         const unsigned char *rdata;
381         int rdoffset;
382         char* buf;
383         size_t buflen;
384         size_t add_count;
385 };
386
387 enum etc_hosts_action {
388         GET_HOSTS_BYNAME = 0,
389         GETHOSTENT,
390         GET_HOSTS_BYADDR,
391 };
392
393 typedef union sockaddr46_t {
394         struct sockaddr sa;
395 #ifdef __UCLIBC_HAS_IPV4__
396         struct sockaddr_in sa4;
397 #endif
398 #ifdef __UCLIBC_HAS_IPV6__
399         struct sockaddr_in6 sa6;
400 #endif
401 } sockaddr46_t;
402
403
404 __UCLIBC_MUTEX_EXTERN(__resolv_lock);
405
406 /* Protected by __resolv_lock */
407 extern void (*__res_sync)(void) attribute_hidden;
408 /*extern uint32_t __resolv_opts attribute_hidden; */
409 extern unsigned __nameservers attribute_hidden;
410 extern unsigned __searchdomains attribute_hidden;
411 extern sockaddr46_t *__nameserver attribute_hidden;
412 extern char **__searchdomain attribute_hidden;
413 #ifdef __UCLIBC_HAS_IPV4__
414 extern const struct sockaddr_in __local_nameserver attribute_hidden;
415 #else
416 extern const struct sockaddr_in6 __local_nameserver attribute_hidden;
417 #endif
418 /* Arbitrary */
419 #define MAXLEN_searchdomain 128
420
421
422 /* function prototypes */
423 extern int __get_hosts_byname_r(const char *name,
424                 int type,
425                 struct hostent *result_buf,
426                 char *buf,
427                 size_t buflen,
428                 struct hostent **result,
429                 int *h_errnop) attribute_hidden;
430 extern int __get_hosts_byaddr_r(const char *addr,
431                 int len,
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 FILE *__open_etc_hosts(void) attribute_hidden;
439 extern int __read_etc_hosts_r(FILE *fp,
440                 const char *name,
441                 int type,
442                 enum etc_hosts_action action,
443                 struct hostent *result_buf,
444                 char *buf,
445                 size_t buflen,
446                 struct hostent **result,
447                 int *h_errnop) attribute_hidden;
448 extern int __dns_lookup(const char *name,
449                 int type,
450                 unsigned char **outpacket,
451                 struct resolv_answer *a) attribute_hidden;
452 extern int __encode_dotted(const char *dotted,
453                 unsigned char *dest,
454                 int maxlen) attribute_hidden;
455 extern int __decode_dotted(const unsigned char *packet,
456                 int offset,
457                 int packet_len,
458                 char *dest,
459                 int dest_len) attribute_hidden;
460 extern int __encode_header(struct resolv_header *h,
461                 unsigned char *dest,
462                 int maxlen) attribute_hidden;
463 extern void __decode_header(unsigned char *data,
464                 struct resolv_header *h) attribute_hidden;
465 extern int __encode_question(const struct resolv_question *q,
466                 unsigned char *dest,
467                 int maxlen) attribute_hidden;
468 extern int __encode_answer(struct resolv_answer *a,
469                 unsigned char *dest,
470                 int maxlen) attribute_hidden;
471 extern void __open_nameservers(void) attribute_hidden;
472 extern void __close_nameservers(void) attribute_hidden;
473
474 /*
475  * Theory of operation.
476  *
477  * gethostbyname, getaddrinfo and friends end up here, and they sometimes
478  * need to talk to DNS servers. In order to do this, we need to read /etc/resolv.conf
479  * and determine servers' addresses and the like. resolv.conf format:
480  *
481  * nameserver <IP[v6]>
482  *              Address of DNS server. Cumulative.
483  *              If not specified, assumed to be on localhost.
484  * search <domain1>[ <domain2>]...
485  *              Append these domains to unqualified names.
486  *              See ndots:n option.
487  *              $LOCALDOMAIN (space-separated list) overrides this.
488  * domain <domain>
489  *              Effectively same as "search" with one domain.
490  *              If no "domain" line is present, the domain is determined
491  *              from the local host name returned by gethostname();
492  *              the domain part is taken to be everything after the first dot.
493  *              If there are no dots, there will be no "domain".
494  *              The domain and search keywords are mutually exclusive.
495  *              If more than one instance of these keywords is present,
496  *              the last instance wins.
497  * sortlist 130.155.160.0[/255.255.240.0] 130.155.0.0
498  *              Allows addresses returned by gethostbyname to be sorted.
499  *              Not supported.
500  * options option[ option]...
501  *              (so far we support none)
502  *              $RES_OPTIONS (space-separated list) is to be added to "options"
503  *  debug       sets RES_DEBUG in _res.options
504  *  ndots:n     how many dots there should be so that name will be tried
505  *              first as an absolute name before any search list elements
506  *              are appended to it. Default 1
507  *  timeout:n   how long to wait for response. Default 5
508  *              (sun seems to have retrans:n synonym)
509  *  attempts:n  number of rounds to do before giving up and returning
510  *              an error. Default 2
511  *              (sun seems to have retry:n synonym)
512  *  rotate      sets RES_ROTATE in _res.options, round robin
513  *              selection of nameservers. Otherwise try
514  *              the first listed server first every time
515  *  no-check-names
516  *              sets RES_NOCHECKNAME in _res.options, which disables
517  *              checking of incoming host names for invalid characters
518  *              such as underscore (_), non-ASCII, or control characters
519  *  inet6       sets RES_USE_INET6 in _res.options. Try a AAAA query
520  *              before an A query inside the gethostbyname(), and map
521  *              IPv4 responses in IPv6 "tunnelled form" if no AAAA records
522  *              are found but an A record set exists
523  *  no_tld_query (FreeBSDism?)
524  *              do not attempt to resolve names without dots
525  *
526  * We will read and analyze /etc/resolv.conf as needed before
527  * we do a DNS request. This happens in __dns_lookup.
528  * (TODO: also re-parse it after a timeout, to catch updates).
529  *
530  * BSD has res_init routine which is used to initialize resolver state
531  * which is held in global structure _res.
532  * Generally, programs call res_init, then fiddle with _res.XXX
533  * (_res.options and _res.nscount, _res.nsaddr_list[N]
534  * are popular targets of fiddling) and expect subsequent calls
535  * to gethostbyname, getaddrinfo, etc to use modified information.
536  *
537  * However, historical _res structure is quite awkward.
538  * Using it for storing /etc/resolv.conf info is not desirable,
539  * and __dns_lookup does not use it.
540  *
541  * We would like to avoid using it unless absolutely necessary.
542  * If user doesn't use res_init, we should arrange it so that
543  * _res structure doesn't even *get linked in* into user's application
544  * (imagine static uclibc build here).
545  *
546  * The solution is a __res_sync function pointer, which is normally NULL.
547  * But if res_init is called, it gets set and any subsequent gethostbyname
548  * et al "syncronizes" our internal structures with potentially
549  * modified _res.XXX stuff by calling __res_sync.
550  * The trick here is that if res_init is not used and not linked in,
551  * gethostbyname itself won't reference _res and _res won't be linked in
552  * either. Other possible methods like
553  * if (__res_sync_just_an_int_flag)
554  *      __sync_me_with_res()
555  * would pull in __sync_me_with_res, which pulls in _res. Bad.
556  */
557
558
559 #ifdef L_encodeh
560
561 int attribute_hidden __encode_header(struct resolv_header *h, unsigned char *dest, int maxlen)
562 {
563         if (maxlen < HFIXEDSZ)
564                 return -1;
565
566         dest[0] = (h->id & 0xff00) >> 8;
567         dest[1] = (h->id & 0x00ff) >> 0;
568         dest[2] = (h->qr ? 0x80 : 0) |
569                 ((h->opcode & 0x0f) << 3) |
570                 (h->aa ? 0x04 : 0) |
571                 (h->tc ? 0x02 : 0) |
572                 (h->rd ? 0x01 : 0);
573         dest[3] = (h->ra ? 0x80 : 0) | (h->rcode & 0x0f);
574         dest[4] = (h->qdcount & 0xff00) >> 8;
575         dest[5] = (h->qdcount & 0x00ff) >> 0;
576         dest[6] = (h->ancount & 0xff00) >> 8;
577         dest[7] = (h->ancount & 0x00ff) >> 0;
578         dest[8] = (h->nscount & 0xff00) >> 8;
579         dest[9] = (h->nscount & 0x00ff) >> 0;
580         dest[10] = (h->arcount & 0xff00) >> 8;
581         dest[11] = (h->arcount & 0x00ff) >> 0;
582
583         return HFIXEDSZ;
584 }
585 #endif
586
587
588 #ifdef L_decodeh
589
590 void attribute_hidden __decode_header(unsigned char *data,
591                 struct resolv_header *h)
592 {
593         h->id = (data[0] << 8) | data[1];
594         h->qr = (data[2] & 0x80) ? 1 : 0;
595         h->opcode = (data[2] >> 3) & 0x0f;
596         h->aa = (data[2] & 0x04) ? 1 : 0;
597         h->tc = (data[2] & 0x02) ? 1 : 0;
598         h->rd = (data[2] & 0x01) ? 1 : 0;
599         h->ra = (data[3] & 0x80) ? 1 : 0;
600         h->rcode = data[3] & 0x0f;
601         h->qdcount = (data[4] << 8) | data[5];
602         h->ancount = (data[6] << 8) | data[7];
603         h->nscount = (data[8] << 8) | data[9];
604         h->arcount = (data[10] << 8) | data[11];
605 }
606 #endif
607
608
609 #ifdef L_encoded
610
611 /* Encode a dotted string into nameserver transport-level encoding.
612    This routine is fairly dumb, and doesn't attempt to compress
613    the data */
614 int attribute_hidden __encode_dotted(const char *dotted, unsigned char *dest, int maxlen)
615 {
616         unsigned used = 0;
617
618         while (dotted && *dotted) {
619                 char *c = strchr(dotted, '.');
620                 int l = c ? c - dotted : strlen(dotted);
621
622                 /* two consecutive dots are not valid */
623                 if (l == 0)
624                         return -1;
625
626                 if (l >= (maxlen - used - 1))
627                         return -1;
628
629                 dest[used++] = l;
630                 memcpy(dest + used, dotted, l);
631                 used += l;
632
633                 if (!c)
634                         break;
635                 dotted = c + 1;
636         }
637
638         if (maxlen < 1)
639                 return -1;
640
641         dest[used++] = 0;
642
643         return used;
644 }
645 #endif
646
647
648 #ifdef L_decoded
649
650 /* Decode a dotted string from nameserver transport-level encoding.
651    This routine understands compressed data. */
652 int attribute_hidden __decode_dotted(const unsigned char *packet,
653                 int offset,
654                 int packet_len,
655                 char *dest,
656                 int dest_len)
657 {
658         unsigned b;
659         bool measure = 1;
660         unsigned total = 0;
661         unsigned used = 0;
662
663         if (!packet)
664                 return -1;
665
666         while (1) {
667                 if (offset >= packet_len)
668                         return -1;
669                 b = packet[offset++];
670                 if (b == 0)
671                         break;
672
673                 if (measure)
674                         total++;
675
676                 if ((b & 0xc0) == 0xc0) {
677                         if (offset >= packet_len)
678                                 return -1;
679                         if (measure)
680                                 total++;
681                         /* compressed item, redirect */
682                         offset = ((b & 0x3f) << 8) | packet[offset];
683                         measure = 0;
684                         continue;
685                 }
686
687                 if (used + b + 1 >= dest_len)
688                         return -1;
689                 if (offset + b + 1 >= packet_len)
690                         return -1;
691                 memcpy(dest + used, packet + offset, b);
692                 offset += b;
693                 used += b;
694
695                 if (measure)
696                         total += b;
697
698                 if (packet[offset] != 0)
699                         dest[used++] = '.';
700                 else
701                         dest[used++] = '\0';
702         }
703
704         /* The null byte must be counted too */
705         if (measure)
706                 total++;
707
708         DPRINTF("Total decode len = %d\n", total);
709
710         return total;
711 }
712 #endif
713
714
715 #ifdef L_encodeq
716
717 int attribute_hidden __encode_question(const struct resolv_question *q,
718                 unsigned char *dest,
719                 int maxlen)
720 {
721         int i;
722
723         i = __encode_dotted(q->dotted, dest, maxlen);
724         if (i < 0)
725                 return i;
726
727         dest += i;
728         maxlen -= i;
729
730         if (maxlen < 4)
731                 return -1;
732
733         dest[0] = (q->qtype & 0xff00) >> 8;
734         dest[1] = (q->qtype & 0x00ff) >> 0;
735         dest[2] = (q->qclass & 0xff00) >> 8;
736         dest[3] = (q->qclass & 0x00ff) >> 0;
737
738         return i + 4;
739 }
740 #endif
741
742
743 #ifdef L_encodea
744
745 int attribute_hidden __encode_answer(struct resolv_answer *a, unsigned char *dest, int maxlen)
746 {
747         int i;
748
749         i = __encode_dotted(a->dotted, dest, maxlen);
750         if (i < 0)
751                 return i;
752
753         dest += i;
754         maxlen -= i;
755
756         if (maxlen < (RRFIXEDSZ + a->rdlength))
757                 return -1;
758
759         *dest++ = (a->atype & 0xff00) >> 8;
760         *dest++ = (a->atype & 0x00ff) >> 0;
761         *dest++ = (a->aclass & 0xff00) >> 8;
762         *dest++ = (a->aclass & 0x00ff) >> 0;
763         *dest++ = (a->ttl & 0xff000000) >> 24;
764         *dest++ = (a->ttl & 0x00ff0000) >> 16;
765         *dest++ = (a->ttl & 0x0000ff00) >> 8;
766         *dest++ = (a->ttl & 0x000000ff) >> 0;
767         *dest++ = (a->rdlength & 0xff00) >> 8;
768         *dest++ = (a->rdlength & 0x00ff) >> 0;
769         memcpy(dest, a->rdata, a->rdlength);
770
771         return i + RRFIXEDSZ + a->rdlength;
772 }
773 #endif
774
775
776 #ifdef CURRENTLY_UNUSED
777 #ifdef L_encodep
778
779 int __encode_packet(struct resolv_header *h,
780                 struct resolv_question **q,
781                 struct resolv_answer **an,
782                 struct resolv_answer **ns,
783                 struct resolv_answer **ar,
784                 unsigned char *dest, int maxlen) attribute_hidden;
785 int __encode_packet(struct resolv_header *h,
786                 struct resolv_question **q,
787                 struct resolv_answer **an,
788                 struct resolv_answer **ns,
789                 struct resolv_answer **ar,
790                 unsigned char *dest, int maxlen)
791 {
792         int i, total = 0;
793         unsigned j;
794
795         i = __encode_header(h, dest, maxlen);
796         if (i < 0)
797                 return i;
798
799         dest += i;
800         maxlen -= i;
801         total += i;
802
803         for (j = 0; j < h->qdcount; j++) {
804                 i = __encode_question(q[j], dest, maxlen);
805                 if (i < 0)
806                         return i;
807                 dest += i;
808                 maxlen -= i;
809                 total += i;
810         }
811
812         for (j = 0; j < h->ancount; j++) {
813                 i = __encode_answer(an[j], dest, maxlen);
814                 if (i < 0)
815                         return i;
816                 dest += i;
817                 maxlen -= i;
818                 total += i;
819         }
820         for (j = 0; j < h->nscount; j++) {
821                 i = __encode_answer(ns[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->arcount; j++) {
829                 i = __encode_answer(ar[j], dest, maxlen);
830                 if (i < 0)
831                         return i;
832                 dest += i;
833                 maxlen -= i;
834                 total += i;
835         }
836
837         return total;
838 }
839 #endif
840
841
842 #ifdef L_decodep
843
844 int __decode_packet(unsigned char *data, struct resolv_header *h) attribute_hidden;
845 int __decode_packet(unsigned char *data, struct resolv_header *h)
846 {
847         __decode_header(data, h);
848         return HFIXEDSZ;
849 }
850 #endif
851
852
853 #ifdef L_formquery
854
855 int __form_query(int id,
856                 const char *name,
857                 int type,
858                 unsigned char *packet,
859                 int maxlen);
860 int __form_query(int id,
861                 const char *name,
862                 int type,
863                 unsigned char *packet,
864                 int maxlen)
865 {
866         struct resolv_header h;
867         struct resolv_question q;
868         int i, j;
869
870         memset(&h, 0, sizeof(h));
871         h.id = id;
872         h.qdcount = 1;
873
874         q.dotted = (char *) name;
875         q.qtype = type;
876         q.qclass = C_IN; /* CLASS_IN */
877
878         i = __encode_header(&h, packet, maxlen);
879         if (i < 0)
880                 return i;
881
882         j = __encode_question(&q, packet + i, maxlen - i);
883         if (j < 0)
884                 return j;
885
886         return i + j;
887 }
888 #endif
889 #endif /* CURRENTLY_UNUSED */
890
891
892 #ifdef L_opennameservers
893
894 # if __BYTE_ORDER == __LITTLE_ENDIAN
895 #define NAMESERVER_PORT_N (__bswap_constant_16(NAMESERVER_PORT))
896 #else
897 #define NAMESERVER_PORT_N NAMESERVER_PORT
898 #endif
899
900 __UCLIBC_MUTEX_INIT(__resolv_lock, PTHREAD_MUTEX_INITIALIZER);
901
902 /* Protected by __resolv_lock */
903 void (*__res_sync)(void);
904 /*uint32_t __resolv_opts; */
905 unsigned __nameservers;
906 unsigned __searchdomains;
907 sockaddr46_t *__nameserver;
908 char **__searchdomain;
909 #ifdef __UCLIBC_HAS_IPV4__
910 const struct sockaddr_in __local_nameserver = {
911         .sin_family = AF_INET,
912         .sin_port = NAMESERVER_PORT_N,
913 };
914 #else
915 const struct sockaddr_in6 __local_nameserver = {
916         .sin6_family = AF_INET6,
917         .sin6_port = NAMESERVER_PORT_N,
918 };
919 #endif
920
921 /* Helpers. Both stop on EOL, if it's '\n', it is converted to NUL first */
922 static char *skip_nospace(char *p)
923 {
924         while (*p != '\0' && !isspace(*p)) {
925                 if (*p == '\n') {
926                         *p = '\0';
927                         break;
928                 }
929                 p++;
930         }
931         return p;
932 }
933 static char *skip_and_NUL_space(char *p)
934 {
935         /* NB: '\n' is not isspace! */
936         while (1) {
937                 char c = *p;
938                 if (c == '\0' || !isspace(c))
939                         break;
940                 *p = '\0';
941                 if (c == '\n' || c == '#')
942                         break;
943                 p++;
944         }
945         return p;
946 }
947
948 /* Must be called under __resolv_lock. */
949 void attribute_hidden __open_nameservers(void)
950 {
951         static uint8_t last_time;
952
953         char szBuffer[MAXLEN_searchdomain];
954         FILE *fp;
955         int i;
956         sockaddr46_t sa;
957
958         if (!__res_sync) {
959                 /* Provide for periodic reread of /etc/resolv.conf */
960                 /* cur_time "ticks" every 256 seconds */
961                 uint8_t cur_time = ((unsigned)time(NULL)) >> 8;
962                 if (last_time != cur_time) {
963                         last_time = cur_time;
964                         __close_nameservers(); /* force config reread */
965                 }
966         }
967
968         if (__nameservers)
969                 goto sync;
970
971         fp = fopen("/etc/resolv.conf", "r");
972         if (!fp) {
973                 /* If we do not have a pre-populated /etc/resolv.conf then
974                    try to use the one from /etc/config which exists on numerous
975                    systems ranging from some uClinux to IRIX installations and
976                    may be the only /etc dir that was mounted rw.  */
977                 fp = fopen("/etc/config/resolv.conf", "r");
978         }
979
980         if (fp) {
981                 while (fgets(szBuffer, sizeof(szBuffer), fp) != NULL) {
982                         void *ptr;
983                         char *keyword, *p;
984
985                         keyword = p = skip_and_NUL_space(szBuffer);
986                         /* skip keyword */
987                         p = skip_nospace(p);
988                         /* find next word */
989                         p = skip_and_NUL_space(p);
990
991                         if (strcmp(keyword, "nameserver") == 0) {
992                                 /* terminate IP addr */
993                                 *skip_nospace(p) = '\0';
994                                 memset(&sa, 0, sizeof(sa));
995                                 if (0) /* nothing */;
996 #ifdef __UCLIBC_HAS_IPV6__
997                                 else if (inet_pton(AF_INET6, p, &sa.sa6.sin6_addr) > 0) {
998                                         sa.sa6.sin6_family = AF_INET6;
999                                         sa.sa6.sin6_port = htons(NAMESERVER_PORT);
1000                                 }
1001 #endif
1002 #ifdef __UCLIBC_HAS_IPV4__
1003                                 else if (inet_pton(AF_INET, p, &sa.sa4.sin_addr) > 0) {
1004                                         sa.sa4.sin_family = AF_INET;
1005                                         sa.sa4.sin_port = htons(NAMESERVER_PORT);
1006                                 }
1007 #endif
1008                                 else
1009                                         continue; /* garbage on this line */
1010                                 ptr = realloc(__nameserver, (__nameservers + 1) * sizeof(__nameserver[0]));
1011                                 if (!ptr)
1012                                         continue;
1013                                 __nameserver = ptr;
1014                                 __nameserver[__nameservers++] = sa; /* struct copy */
1015                                 continue;
1016                         }
1017                         if (strcmp(keyword, "domain") == 0 || strcmp(keyword, "search") == 0) {
1018                                 char *p1;
1019
1020                                 /* free old domains ("last 'domain' or 'search' wins" rule) */
1021                                 while (__searchdomains)
1022                                         free(__searchdomain[--__searchdomains]);
1023                                 /*free(__searchdomain);*/
1024                                 /*__searchdomain = NULL; - not necessary */
1025  next_word:
1026                                 /* terminate current word */
1027                                 p1 = skip_nospace(p);
1028                                 /* find next word (maybe) */
1029                                 p1 = skip_and_NUL_space(p1);
1030                                 /* add it */
1031                                 ptr = realloc(__searchdomain, (__searchdomains + 1) * sizeof(__searchdomain[0]));
1032                                 if (!ptr)
1033                                         continue;
1034                                 __searchdomain = ptr;
1035                                 /* NB: strlen(p) <= MAXLEN_searchdomain) because szBuffer[] is smaller */
1036                                 ptr = strdup(p);
1037                                 if (!ptr)
1038                                         continue;
1039                                 DPRINTF("adding search %s\n", (char*)ptr);
1040                                 __searchdomain[__searchdomains++] = (char*)ptr;
1041                                 p = p1;
1042                                 if (*p)
1043                                         goto next_word;
1044                                 continue;
1045                         }
1046                         /* if (strcmp(keyword, "sortlist") == 0)... */
1047                         /* if (strcmp(keyword, "options") == 0)... */
1048                 }
1049                 fclose(fp);
1050         }
1051         if (__nameservers == 0) {
1052                 /* Have to handle malloc failure! What a mess...
1053                  * And it's not only here, we need to be careful
1054                  * to never write into __nameserver[0] if it points
1055                  * to constant __local_nameserver, or free it. */
1056                 __nameserver = malloc(sizeof(__nameserver[0]));
1057                 if (__nameserver)
1058                         memcpy(__nameserver, &__local_nameserver, sizeof(__local_nameserver));
1059                 else
1060                         __nameserver = (void*) &__local_nameserver;
1061                 __nameservers++;
1062         }
1063         if (__searchdomains == 0) {
1064                 char buf[256];
1065                 char *p;
1066                 i = gethostname(buf, sizeof(buf) - 1);
1067                 buf[sizeof(buf) - 1] = '\0';
1068                 if (i == 0 && (p = strchr(buf, '.')) != NULL && p[1]) {
1069                         p = strdup(p + 1);
1070                         if (!p)
1071                                 goto err;
1072                         __searchdomain = malloc(sizeof(__searchdomain[0]));
1073                         if (!__searchdomain) {
1074                                 free(p);
1075                                 goto err;
1076                         }
1077                         __searchdomain[0] = p;
1078                         __searchdomains++;
1079  err: ;
1080                 }
1081         }
1082         DPRINTF("nameservers = %d\n", __nameservers);
1083
1084  sync:
1085         if (__res_sync)
1086                 __res_sync();
1087 }
1088 #endif
1089
1090
1091 #ifdef L_closenameservers
1092
1093 /* Must be called under __resolv_lock. */
1094 void attribute_hidden __close_nameservers(void)
1095 {
1096         if (__nameserver != (void*) &__local_nameserver)
1097                 free(__nameserver);
1098         __nameserver = NULL;
1099         __nameservers = 0;
1100         while (__searchdomains)
1101                 free(__searchdomain[--__searchdomains]);
1102         free(__searchdomain);
1103         __searchdomain = NULL;
1104         /*__searchdomains = 0; - already is */
1105 }
1106 #endif
1107
1108
1109 #ifdef L_dnslookup
1110
1111 /* Helpers */
1112 static int __length_question(const unsigned char *data, int maxlen)
1113 {
1114         const unsigned char *start;
1115         unsigned b;
1116
1117         if (!data)
1118                 return -1;
1119
1120         start = data;
1121         while (1) {
1122                 if (maxlen <= 0)
1123                         return -1;
1124                 b = *data++;
1125                 if (b == 0)
1126                         break;
1127                 if ((b & 0xc0) == 0xc0) {
1128                         /* It's a "compressed" name. */
1129                         data++; /* skip lsb of redirected offset */
1130                         maxlen -= 2;
1131                         break;
1132                 }
1133                 data += b;
1134                 maxlen -= (b + 1); /* account for data++ above */
1135         }
1136         /* Up to here we were skipping encoded name */
1137
1138         /* Account for QTYPE and QCLASS fields */
1139         if (maxlen < 4)
1140                 return -1;
1141         return data - start + 2 + 2;
1142 }
1143
1144 static int __decode_answer(const unsigned char *message, /* packet */
1145                 int offset,
1146                 int len, /* total packet len */
1147                 struct resolv_answer *a)
1148 {
1149         char temp[256];
1150         int i;
1151
1152         DPRINTF("decode_answer(start): off %d, len %d\n", offset, len);
1153         i = __decode_dotted(message, offset, len, temp, sizeof(temp));
1154         if (i < 0)
1155                 return i;
1156
1157         message += offset + i;
1158         len -= i + RRFIXEDSZ + offset;
1159         if (len < 0) {
1160                 DPRINTF("decode_answer: off %d, len %d, i %d\n", offset, len, i);
1161                 return len;
1162         }
1163
1164 /* TODO: what if strdup fails? */
1165         a->dotted = strdup(temp);
1166         a->atype = (message[0] << 8) | message[1];
1167         message += 2;
1168         a->aclass = (message[0] << 8) | message[1];
1169         message += 2;
1170         a->ttl = (message[0] << 24) |
1171                 (message[1] << 16) | (message[2] << 8) | (message[3] << 0);
1172         message += 4;
1173         a->rdlength = (message[0] << 8) | message[1];
1174         message += 2;
1175         a->rdata = message;
1176         a->rdoffset = offset + i + RRFIXEDSZ;
1177
1178         DPRINTF("i=%d,rdlength=%d\n", i, a->rdlength);
1179
1180         if (len < a->rdlength)
1181                 return -1;
1182         return i + RRFIXEDSZ + a->rdlength;
1183 }
1184
1185 /* On entry:
1186  *  a.buf(len) = auxiliary buffer for IP addresses after first one
1187  *  a.add_count = how many additional addresses are there already
1188  *  outpacket = where to save ptr to raw packet? can be NULL
1189  * On exit:
1190  *  ret < 0: error, all other data is not valid
1191  *  ret >= 0: length of reply packet
1192  *  a.add_count & a.buf: updated
1193  *  a.rdlength: length of addresses (4 bytes for IPv4)
1194  *  *outpacket: updated (packet is malloced, you need to free it)
1195  *  a.rdata: points into *outpacket to 1st IP addr
1196  *      NB: don't pass outpacket == NULL if you need to use a.rdata!
1197  *  a.atype: type of query?
1198  *  a.dotted: which name we _actually_ used. May contain search domains
1199  *      appended. (why the filed is called "dotted" I have no idea)
1200  *      This is a malloced string. May be NULL because strdup failed.
1201  */
1202 int attribute_hidden __dns_lookup(const char *name,
1203                 int type,
1204                 unsigned char **outpacket,
1205                 struct resolv_answer *a)
1206 {
1207         /* Protected by __resolv_lock: */
1208         static int last_ns_num = 0;
1209         static uint16_t last_id = 1;
1210
1211         int i, j, fd, rc;
1212         int packet_len;
1213         int name_len;
1214 #ifdef USE_SELECT
1215         struct timeval tv;
1216         fd_set fds;
1217 #else
1218         struct pollfd fds;
1219 #endif
1220         struct resolv_header h;
1221         struct resolv_question q;
1222         struct resolv_answer ma;
1223         bool first_answer = 1;
1224         int retries_left;
1225         unsigned char *packet = malloc(PACKETSZ);
1226         char *lookup;
1227         int variant = -1;  /* search domain to append, -1: none */
1228         int local_ns_num = -1; /* Nth server to use */
1229         int local_id = local_id; /* for compiler */
1230         int sdomains;
1231         bool ends_with_dot;
1232         sockaddr46_t sa;
1233
1234         fd = -1;
1235         lookup = NULL;
1236         name_len = strlen(name);
1237         if ((unsigned)name_len >= MAXDNAME - MAXLEN_searchdomain - 2)
1238                 goto fail; /* paranoia */
1239         lookup = malloc(name_len + 1/*for '.'*/ + MAXLEN_searchdomain + 1);
1240         if (!packet || !lookup || !name[0])
1241                 goto fail;
1242         ends_with_dot = (name[name_len - 1] == '.');
1243         /* no strcpy! paranoia, user might change name[] under us */
1244         memcpy(lookup, name, name_len);
1245
1246         DPRINTF("Looking up type %d answer for '%s'\n", type, name);
1247         retries_left = 0; /* for compiler */
1248         do {
1249                 int pos;
1250                 unsigned reply_timeout;
1251
1252                 if (fd != -1) {
1253                         close(fd);
1254                         fd = -1;
1255                 }
1256
1257                 /* Mess with globals while under lock */
1258                 /* NB: even data *pointed to* by globals may vanish
1259                  * outside the locks. We should assume any and all
1260                  * globals can completely change between locked
1261                  * code regions. OTOH, this is rare, so we don't need
1262                  * to handle it "nicely" (do not skip servers,
1263                  * search domains, etc), we only need to ensure
1264                  * we do not SEGV, use freed+overwritten data
1265                  * or do other Really Bad Things. */
1266                 __UCLIBC_MUTEX_LOCK(__resolv_lock);
1267                 __open_nameservers();
1268                 sdomains = __searchdomains;
1269                 lookup[name_len] = '\0';
1270                 if ((unsigned)variant < sdomains) {
1271                         /* lookup is name_len + 1 + MAXLEN_searchdomain + 1 long */
1272                         /* __searchdomain[] is not bigger than MAXLEN_searchdomain */
1273                         lookup[name_len] = '.';
1274                         strcpy(&lookup[name_len + 1], __searchdomain[variant]);
1275                 }
1276                 /* first time? pick starting server etc */
1277                 if (local_ns_num < 0) {
1278                         local_id = last_id;
1279 /*TODO: implement /etc/resolv.conf's "options rotate"
1280  (a.k.a. RES_ROTATE bit in _res.options)
1281                         local_ns_num = 0;
1282                         if (_res.options & RES_ROTATE) */
1283                                 local_ns_num = last_ns_num;
1284 /*TODO: use _res.retry */
1285                         retries_left = __nameservers * RES_DFLRETRY;
1286                 }
1287                 retries_left--;
1288                 if (local_ns_num >= __nameservers)
1289                         local_ns_num = 0;
1290                 local_id++;
1291                 local_id &= 0xffff;
1292                 /* write new values back while still under lock */
1293                 last_id = local_id;
1294                 last_ns_num = local_ns_num;
1295                 /* struct copy */
1296                 /* can't just take a pointer, __nameserver[x]
1297                  * is not safe to use outside of locks */
1298                 sa = __nameserver[local_ns_num];
1299                 __UCLIBC_MUTEX_UNLOCK(__resolv_lock);
1300
1301                 memset(packet, 0, PACKETSZ);
1302                 memset(&h, 0, sizeof(h));
1303
1304                 /* encode header */
1305                 h.id = local_id;
1306                 h.qdcount = 1;
1307                 h.rd = 1;
1308                 DPRINTF("encoding header\n", h.rd);
1309                 i = __encode_header(&h, packet, PACKETSZ);
1310                 if (i < 0)
1311                         goto fail;
1312
1313                 /* encode question */
1314                 DPRINTF("lookup name: %s\n", lookup);
1315                 q.dotted = lookup;
1316                 q.qtype = type;
1317                 q.qclass = C_IN; /* CLASS_IN */
1318                 j = __encode_question(&q, packet+i, PACKETSZ-i);
1319                 if (j < 0)
1320                         goto fail;
1321                 packet_len = i + j;
1322
1323                 /* send packet */
1324                 DPRINTF("On try %d, sending query to port %d\n",
1325                                 retries_left, NAMESERVER_PORT);
1326                 fd = socket(sa.sa.sa_family, SOCK_DGRAM, IPPROTO_UDP);
1327                 if (fd < 0) /* paranoia */
1328                         goto try_next_server;
1329                 rc = connect(fd, &sa.sa, sizeof(sa));
1330                 if (rc < 0) {
1331                         /*if (errno == ENETUNREACH) { */
1332                                 /* routing error, presume not transient */
1333                                 goto try_next_server;
1334                         /*} */
1335 /*For example, what transient error this can be? Can't think of any */
1336                         /* retry */
1337                         /*continue; */
1338                 }
1339                 DPRINTF("Xmit packet len:%d id:%d qr:%d\n", packet_len, h.id, h.qr);
1340                 /* no error check - if it fails, we time out on recv */
1341                 send(fd, packet, packet_len, 0);
1342
1343 #ifdef USE_SELECT
1344 /*TODO: use _res.retrans*/
1345                 reply_timeout = RES_TIMEOUT;
1346  wait_again:
1347                 FD_ZERO(&fds);
1348                 FD_SET(fd, &fds);
1349                 tv.tv_sec = reply_timeout;
1350                 tv.tv_usec = 0;
1351                 if (select(fd + 1, &fds, NULL, NULL, &tv) <= 0) {
1352                         DPRINTF("Timeout\n");
1353                         /* timed out, so retry send and receive
1354                          * to next nameserver */
1355                         goto try_next_server;
1356                 }
1357                 reply_timeout--;
1358 #else
1359                 reply_timeout = RES_TIMEOUT * 1000;
1360  wait_again:
1361                 fds.fd = fd;
1362                 fds.events = POLLIN;
1363                 if (poll(&fds, 1, reply_timeout) <= 0) {
1364                         DPRINTF("Timeout\n");
1365                         /* timed out, so retry send and receive
1366                          * to next nameserver */
1367                         goto try_next_server;
1368                 }
1369 /*TODO: better timeout accounting?*/
1370                 reply_timeout -= 1000;
1371 #endif
1372
1373 /* vda: a bogus response seen in real world (caused SEGV in uclibc):
1374  * "ping www.google.com" sending AAAA query and getting
1375  * response with one answer... with answer part missing!
1376  * Fixed by thorough checks for not going past the packet's end.
1377  */
1378 #ifdef DEBUG
1379                 {
1380                         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";
1381                         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";
1382                         pos = memcmp(packet + 2, test_query + 2, 30);
1383                 packet_len = recv(fd, packet, PACKETSZ, MSG_DONTWAIT);
1384                         if (pos == 0) {
1385                                 packet_len = 32;
1386                                 memcpy(packet + 2, test_respn + 2, 30);
1387                         }
1388                 }
1389 #else
1390                 packet_len = recv(fd, packet, PACKETSZ, MSG_DONTWAIT);
1391 #endif
1392
1393                 if (packet_len < HFIXEDSZ) {
1394                         /* too short!
1395                          * it's just a bogus packet from somewhere */
1396  bogus_packet:
1397                         if (reply_timeout)
1398                                 goto wait_again;
1399                         goto try_next_server;
1400                 }
1401                 __decode_header(packet, &h);
1402                 DPRINTF("len:%d id:%d qr:%d\n", packet_len, h.id, h.qr);
1403                 if (h.id != local_id || !h.qr) {
1404                         /* unsolicited */
1405                         goto bogus_packet;
1406                 }
1407
1408                 DPRINTF("Got response (i think)!\n");
1409                 DPRINTF("qrcount=%d,ancount=%d,nscount=%d,arcount=%d\n",
1410                                 h.qdcount, h.ancount, h.nscount, h.arcount);
1411                 DPRINTF("opcode=%d,aa=%d,tc=%d,rd=%d,ra=%d,rcode=%d\n",
1412                                 h.opcode, h.aa, h.tc, h.rd, h.ra, h.rcode);
1413
1414                 /* bug 660 says we treat negative response as an error
1415                  * and retry, which is, eh, an error. :)
1416                  * We were incurring long delays because of this. */
1417                 if (h.rcode == NXDOMAIN) {
1418                         /* if possible, try next search domain */
1419                         if (!ends_with_dot) {
1420                                 DPRINTF("variant:%d sdomains:%d\n", variant, sdomains);
1421                                 if (variant < sdomains - 1) {
1422                                         /* next search domain */
1423                                         variant++;
1424                                         continue;
1425                                 }
1426                                 /* no more search domains to try */
1427                         }
1428                         /* dont loop, this is "no such host" situation */
1429                         h_errno = HOST_NOT_FOUND;
1430                         goto fail1;
1431                 }
1432                 /* Insert other non-fatal errors here, which do not warrant
1433                  * switching to next nameserver */
1434
1435                 /* Strange error, assuming this nameserver is feeling bad */
1436                 if (h.rcode != 0)
1437                         goto try_next_server;
1438
1439                 /* Code below won't work correctly with h.ancount == 0, so... */
1440                 if (h.ancount <= 0) {
1441                         h_errno = NO_DATA; /* [is this correct code to check for?] */
1442                         goto fail1;
1443                 }
1444                 pos = HFIXEDSZ;
1445                 for (j = 0; j < h.qdcount; j++) {
1446                         DPRINTF("Skipping question %d at %d\n", j, pos);
1447                         i = __length_question(packet + pos, packet_len - pos);
1448                         if (i < 0) {
1449                                 DPRINTF("Packet'question section "
1450                                         "is truncated, trying next server\n");
1451                                 goto try_next_server;
1452                         }
1453                         pos += i;
1454                         DPRINTF("Length of question %d is %d\n", j, i);
1455                 }
1456                 DPRINTF("Decoding answer at pos %d\n", pos);
1457
1458                 first_answer = 1;
1459                 for (j = 0; j < h.ancount; j++) {
1460                         i = __decode_answer(packet, pos, packet_len, &ma);
1461                         if (i < 0) {
1462                                 DPRINTF("failed decode %d\n", i);
1463                                 /* If the message was truncated but we have
1464                                  * decoded some answers, pretend it's OK */
1465                                 if (j && h.tc)
1466                                         break;
1467                                 goto try_next_server;
1468                         }
1469                         pos += i;
1470
1471                         if (first_answer) {
1472                                 ma.buf = a->buf;
1473                                 ma.buflen = a->buflen;
1474                                 ma.add_count = a->add_count;
1475                                 memcpy(a, &ma, sizeof(ma));
1476                                 if (a->atype != T_SIG && (NULL == a->buf || (type != T_A && type != T_AAAA)))
1477                                         break;
1478                                 if (a->atype != type) {
1479                                         free(a->dotted);
1480                                         continue;
1481                                 }
1482                                 a->add_count = h.ancount - j - 1;
1483                                 if ((a->rdlength + sizeof(struct in_addr*)) * a->add_count > a->buflen)
1484                                         break;
1485                                 a->add_count = 0;
1486                                 first_answer = 0;
1487                         } else {
1488                                 free(ma.dotted);
1489                                 if (ma.atype != type)
1490                                         continue;
1491                                 if (a->rdlength != ma.rdlength) {
1492                                         free(a->dotted);
1493                                         DPRINTF("Answer address len(%u) differs from original(%u)\n",
1494                                                         ma.rdlength, a->rdlength);
1495                                         goto try_next_server;
1496                                 }
1497                                 memcpy(a->buf + (a->add_count * ma.rdlength), ma.rdata, ma.rdlength);
1498                                 ++a->add_count;
1499                         }
1500                 }
1501
1502                 /* Success! */
1503                 DPRINTF("Answer name = |%s|\n", a->dotted);
1504                 DPRINTF("Answer type = |%d|\n", a->atype);
1505                 if (fd != -1)
1506                         close(fd);
1507                 if (outpacket)
1508                         *outpacket = packet;
1509                 else
1510                         free(packet);
1511                 free(lookup);
1512                 return packet_len;
1513
1514  try_next_server:
1515                 /* Try next nameserver */
1516                 local_ns_num++;
1517                 variant = -1;
1518         } while (retries_left > 0);
1519
1520  fail:
1521         h_errno = NETDB_INTERNAL;
1522  fail1:
1523         if (fd != -1)
1524                 close(fd);
1525         free(lookup);
1526         free(packet);
1527         return -1;
1528 }
1529 #endif
1530
1531
1532 #ifdef L_read_etc_hosts_r
1533
1534 FILE * __open_etc_hosts(void)
1535 {
1536         FILE * fp;
1537         if ((fp = fopen("/etc/hosts", "r")) == NULL) {
1538                 fp = fopen("/etc/config/hosts", "r");
1539         }
1540         return fp;
1541 }
1542
1543 int attribute_hidden __read_etc_hosts_r(
1544                 FILE * fp,
1545                 const char *name,
1546                 int type,
1547                 enum etc_hosts_action action,
1548                 struct hostent *result_buf,
1549                 char *buf, size_t buflen,
1550                 struct hostent **result,
1551                 int *h_errnop)
1552 {
1553         struct in_addr **addr_list = NULL;
1554         struct in_addr *in = NULL;
1555         char *cp, **alias;
1556         int aliases, i, ret = HOST_NOT_FOUND;
1557
1558         *h_errnop = NETDB_INTERNAL;
1559
1560         /* make sure pointer is aligned */
1561         i = ALIGN_BUFFER_OFFSET(buf);
1562         buf += i;
1563         buflen -= i;
1564         /* Layout in buf:
1565          * char *alias[ALIAS_DIM];
1566          * struct in[6]_addr* addr_list[2];
1567          * struct in[6]_addr* in;
1568          * char line_buffer[80+];
1569          */
1570 #define in6 ((struct in6_addr *)in)
1571         alias = (char **)buf;
1572         buf += sizeof(char **) * ALIAS_DIM;
1573         buflen -= sizeof(char **) * ALIAS_DIM;
1574         if ((ssize_t)buflen < 0)
1575                 return ERANGE;
1576         if (action != GETHOSTENT) {
1577                 addr_list = (struct in_addr**)buf;
1578                 buf += sizeof(*addr_list) * 2;
1579                 buflen -= sizeof(*addr_list) * 2;
1580                 in = (struct in_addr*)buf;
1581 #ifndef __UCLIBC_HAS_IPV6__
1582                 buf += sizeof(*in);
1583                 buflen -= sizeof(*in);
1584 #else
1585                 buf += sizeof(*in6);
1586                 buflen -= sizeof(*in6);
1587 #endif
1588                 if ((ssize_t)buflen < 80)
1589                         return ERANGE;
1590
1591                 fp = __open_etc_hosts();
1592                 if (fp == NULL) {
1593                         *result = NULL;
1594                         return errno;
1595                 }
1596                 addr_list[0] = in;
1597                 addr_list[1] = NULL;
1598         }
1599
1600         *h_errnop = HOST_NOT_FOUND;
1601         while (fgets(buf, buflen, fp)) {
1602                 *strchrnul(buf, '#') = '\0';
1603                 DPRINTF("Looking at: %s\n", buf);
1604                 aliases = 0;
1605
1606                 cp = buf;
1607                 while (*cp) {
1608                         while (*cp && isspace(*cp))
1609                                 *cp++ = '\0';
1610                         if (!*cp)
1611                                 break;
1612                         if (aliases < (2 + MAX_ALIASES))
1613                                 alias[aliases++] = cp;
1614                         while (*cp && !isspace(*cp))
1615                                 cp++;
1616                 }
1617                 alias[aliases] = NULL;
1618
1619                 if (aliases < 2)
1620                         continue; /* syntax error really */
1621
1622                 if (action == GETHOSTENT) {
1623                         /* Return whatever the next entry happens to be. */
1624                         break;
1625                 }
1626                 if (action == GET_HOSTS_BYADDR) {
1627                         if (strcmp(name, alias[0]) != 0)
1628                                 continue;
1629                 } else {
1630                         /* GET_HOSTS_BYNAME */
1631                         for (i = 1; i < aliases; i++)
1632                                 if (strcasecmp(name, alias[i]) == 0)
1633                                         goto found;
1634                         continue;
1635  found: ;
1636                 }
1637
1638                 if (0) /* nothing */;
1639 #ifdef __UCLIBC_HAS_IPV4__
1640                 else if (type == AF_INET && inet_pton(AF_INET, alias[0], in) > 0) {
1641                         DPRINTF("Found INET\n");
1642                         result_buf->h_addrtype = AF_INET;
1643                         result_buf->h_length = sizeof(*in);
1644                         result_buf->h_name = alias[1];
1645                         result_buf->h_addr_list = (char**) addr_list;
1646                         result_buf->h_aliases = alias + 2;
1647                         *result = result_buf;
1648                         ret = NETDB_SUCCESS;
1649                 }
1650 #endif
1651 #ifdef __UCLIBC_HAS_IPV6__
1652                 else if (type == AF_INET6 && inet_pton(AF_INET6, alias[0], in6) > 0) {
1653                         DPRINTF("Found INET6\n");
1654                         result_buf->h_addrtype = AF_INET6;
1655                         result_buf->h_length = sizeof(*in6);
1656                         result_buf->h_name = alias[1];
1657                         result_buf->h_addr_list = (char**) addr_list;
1658                         result_buf->h_aliases = alias + 2;
1659                         *result = result_buf;
1660                         ret = NETDB_SUCCESS;
1661                 }
1662 #endif
1663                 else {
1664                         /* continue parsing in the hope the user has multiple
1665                          * host types listed in the database like so:
1666                          * <ipv4 addr> host
1667                          * <ipv6 addr> host
1668                          * If looking for an IPv6 addr, don't bail when we got the IPv4
1669                          */
1670                         DPRINTF("Error: Found host but diff network type\n");
1671                         /* NB: gethostbyname2_r depends on this feature
1672                          * to avoid looking for IPv6 addr of "localhost" etc */
1673                         ret = TRY_AGAIN;
1674                         continue;
1675                 }
1676                 break;
1677         }
1678         if (action != GETHOSTENT)
1679                 fclose(fp);
1680         return ret;
1681 #undef in6
1682 }
1683 #endif
1684
1685
1686 #ifdef L_get_hosts_byname_r
1687
1688 int attribute_hidden __get_hosts_byname_r(const char *name,
1689                 int type,
1690                 struct hostent *result_buf,
1691                 char *buf,
1692                 size_t buflen,
1693                 struct hostent **result,
1694                 int *h_errnop)
1695 {
1696         return __read_etc_hosts_r(NULL, name, type, GET_HOSTS_BYNAME,
1697                                   result_buf, buf, buflen, result, h_errnop);
1698 }
1699 #endif
1700
1701
1702 #ifdef L_get_hosts_byaddr_r
1703
1704 int attribute_hidden __get_hosts_byaddr_r(const char *addr,
1705                 int len,
1706                 int type,
1707                 struct hostent *result_buf,
1708                 char *buf,
1709                 size_t buflen,
1710                 struct hostent **result,
1711                 int *h_errnop)
1712 {
1713 #ifndef __UCLIBC_HAS_IPV6__
1714         char    ipaddr[INET_ADDRSTRLEN];
1715 #else
1716         char    ipaddr[INET6_ADDRSTRLEN];
1717 #endif
1718
1719         switch (type) {
1720 #ifdef __UCLIBC_HAS_IPV4__
1721                 case AF_INET:
1722                         if (len != sizeof(struct in_addr))
1723                                 return 0;
1724                         break;
1725 #endif
1726 #ifdef __UCLIBC_HAS_IPV6__
1727                 case AF_INET6:
1728                         if (len != sizeof(struct in6_addr))
1729                                 return 0;
1730                         break;
1731 #endif
1732                 default:
1733                         return 0;
1734         }
1735
1736         inet_ntop(type, addr, ipaddr, sizeof(ipaddr));
1737
1738         return __read_etc_hosts_r(NULL, ipaddr, type, GET_HOSTS_BYADDR,
1739                                 result_buf, buf, buflen, result, h_errnop);
1740 }
1741 #endif
1742
1743
1744 #ifdef L_getnameinfo
1745
1746 int getnameinfo(const struct sockaddr *sa,
1747                 socklen_t addrlen,
1748                 char *host,
1749                 socklen_t hostlen,
1750                 char *serv,
1751                 socklen_t servlen,
1752                 unsigned flags)
1753 {
1754         int serrno = errno;
1755         unsigned ok;
1756         struct hostent *h = NULL;
1757         char domain[256];
1758
1759         if (flags & ~(NI_NUMERICHOST|NI_NUMERICSERV|NI_NOFQDN|NI_NAMEREQD|NI_DGRAM))
1760                 return EAI_BADFLAGS;
1761
1762         if (sa == NULL || addrlen < sizeof(sa_family_t))
1763                 return EAI_FAMILY;
1764
1765         ok = sa->sa_family;
1766         if (ok == AF_LOCAL) /* valid */;
1767 #ifdef __UCLIBC_HAS_IPV4__
1768         else if (ok == AF_INET) {
1769                 if (addrlen < sizeof(struct sockaddr_in))
1770                         return EAI_FAMILY;
1771         }
1772 #endif
1773 #ifdef __UCLIBC_HAS_IPV6__
1774         else if (ok == AF_INET6) {
1775                 if (addrlen < sizeof(struct sockaddr_in6))
1776                         return EAI_FAMILY;
1777         }
1778 #endif
1779         else
1780                 return EAI_FAMILY;
1781
1782         ok = 0;
1783         if (host != NULL && hostlen > 0)
1784                 switch (sa->sa_family) {
1785                 case AF_INET:
1786 #ifdef __UCLIBC_HAS_IPV6__
1787                 case AF_INET6:
1788 #endif
1789                         if (!(flags & NI_NUMERICHOST)) {
1790                                 if (0) /* nothing */;
1791 #ifdef __UCLIBC_HAS_IPV6__
1792                                 else if (sa->sa_family == AF_INET6)
1793                                         h = gethostbyaddr((const void *)
1794                                                 &(((const struct sockaddr_in6 *) sa)->sin6_addr),
1795                                                 sizeof(struct in6_addr), AF_INET6);
1796 #endif
1797 #ifdef __UCLIBC_HAS_IPV4__
1798                                 else
1799                                         h = gethostbyaddr((const void *)
1800                                                 &(((const struct sockaddr_in *)sa)->sin_addr),
1801                                                 sizeof(struct in_addr), AF_INET);
1802 #endif
1803
1804                                 if (h) {
1805                                         char *c;
1806 #undef min
1807 #define min(x,y) (((x) > (y)) ? (y) : (x))
1808                                         if ((flags & NI_NOFQDN)
1809                                          && (getdomainname(domain, sizeof(domain)) == 0)
1810                                          && (c = strstr(h->h_name, domain)) != NULL
1811                                          && (c != h->h_name) && (*(--c) == '.')
1812                                         ) {
1813                                                 strncpy(host, h->h_name,
1814                                                         min(hostlen, (size_t) (c - h->h_name)));
1815                                                 host[min(hostlen - 1, (size_t) (c - h->h_name))] = '\0';
1816                                         } else {
1817                                                 strncpy(host, h->h_name, hostlen);
1818                                         }
1819                                         ok = 1;
1820 #undef min
1821                                 }
1822                         }
1823
1824                         if (!ok) {
1825                                 const char *c = NULL;
1826
1827                                 if (flags & NI_NAMEREQD) {
1828                                         errno = serrno;
1829                                         return EAI_NONAME;
1830                                 }
1831                                 if (0) /* nothing */;
1832 #ifdef __UCLIBC_HAS_IPV6__
1833                                 else if (sa->sa_family == AF_INET6) {
1834                                         const struct sockaddr_in6 *sin6p;
1835
1836                                         sin6p = (const struct sockaddr_in6 *) sa;
1837                                         c = inet_ntop(AF_INET6,
1838                                                 (const void *) &sin6p->sin6_addr,
1839                                                 host, hostlen);
1840 #if 0
1841                                         /* Does scope id need to be supported? */
1842                                         uint32_t scopeid;
1843                                         scopeid = sin6p->sin6_scope_id;
1844                                         if (scopeid != 0) {
1845                                                 /* Buffer is >= IFNAMSIZ+1.  */
1846                                                 char scopebuf[IFNAMSIZ + 1];
1847                                                 char *scopeptr;
1848                                                 int ni_numericscope = 0;
1849                                                 size_t real_hostlen = strnlen(host, hostlen);
1850                                                 size_t scopelen = 0;
1851
1852                                                 scopebuf[0] = SCOPE_DELIMITER;
1853                                                 scopebuf[1] = '\0';
1854                                                 scopeptr = &scopebuf[1];
1855
1856                                                 if (IN6_IS_ADDR_LINKLOCAL(&sin6p->sin6_addr)
1857                                                     || IN6_IS_ADDR_MC_LINKLOCAL(&sin6p->sin6_addr)) {
1858                                                         if (if_indextoname(scopeid, scopeptr) == NULL)
1859                                                                 ++ni_numericscope;
1860                                                         else
1861                                                                 scopelen = strlen(scopebuf);
1862                                                 } else {
1863                                                         ++ni_numericscope;
1864                                                 }
1865
1866                                                 if (ni_numericscope)
1867                                                         scopelen = 1 + snprintf(scopeptr,
1868                                                                 (scopebuf
1869                                                                 + sizeof scopebuf
1870                                                                 - scopeptr),
1871                                                                 "%u", scopeid);
1872
1873                                                 if (real_hostlen + scopelen + 1 > hostlen)
1874                                                         return EAI_SYSTEM;
1875                                                 memcpy(host + real_hostlen, scopebuf, scopelen + 1);
1876                                         }
1877 #endif
1878                                 }
1879 #endif /* __UCLIBC_HAS_IPV6__ */
1880 #if defined __UCLIBC_HAS_IPV4__
1881                                 else {
1882                                         c = inet_ntop(AF_INET, (const void *)
1883                                                 &(((const struct sockaddr_in *) sa)->sin_addr),
1884                                                 host, hostlen);
1885                                 }
1886 #endif
1887                                 if (c == NULL) {
1888                                         errno = serrno;
1889                                         return EAI_SYSTEM;
1890                                 }
1891                                 ok = 1;
1892                         }
1893                         break;
1894
1895                 case AF_LOCAL:
1896                         if (!(flags & NI_NUMERICHOST)) {
1897                                 struct utsname utsname;
1898
1899                                 if (!uname(&utsname)) {
1900                                         strncpy(host, utsname.nodename, hostlen);
1901                                         break;
1902                                 };
1903                         };
1904
1905                         if (flags & NI_NAMEREQD) {
1906                                 errno = serrno;
1907                                 return EAI_NONAME;
1908                         }
1909
1910                         strncpy(host, "localhost", hostlen);
1911                         break;
1912 /* Already checked above
1913                 default:
1914                         return EAI_FAMILY;
1915 */
1916         }
1917
1918         if (serv && (servlen > 0)) {
1919                 if (sa->sa_family == AF_LOCAL) {
1920                         strncpy(serv, ((const struct sockaddr_un *) sa)->sun_path, servlen);
1921                 } else { /* AF_INET || AF_INET6 */
1922                         if (!(flags & NI_NUMERICSERV)) {
1923                                 struct servent *s;
1924                                 s = getservbyport(((const struct sockaddr_in *) sa)->sin_port,
1925                                       ((flags & NI_DGRAM) ? "udp" : "tcp"));
1926                                 if (s) {
1927                                         strncpy(serv, s->s_name, servlen);
1928                                         goto DONE;
1929                                 }
1930                         }
1931                         snprintf(serv, servlen, "%d",
1932                                 ntohs(((const struct sockaddr_in *) sa)->sin_port));
1933                 }
1934         }
1935 DONE:
1936         if (host && (hostlen > 0))
1937                 host[hostlen-1] = 0;
1938         if (serv && (servlen > 0))
1939                 serv[servlen-1] = 0;
1940         errno = serrno;
1941         return 0;
1942 }
1943 libc_hidden_def(getnameinfo)
1944 #endif
1945
1946
1947 #ifdef L_gethostbyname_r
1948
1949 /* Bug 671 says:
1950  * "uClibc resolver's gethostbyname does not return the requested name
1951  * as an alias, but instead returns the canonical name. glibc's
1952  * gethostbyname has a similar bug where it returns the requested name
1953  * with the search domain name appended (to make a FQDN) as an alias,
1954  * but not the original name itself. Both contradict POSIX, which says
1955  * that the name argument passed to gethostbyname must be in the alias list"
1956  * This is fixed now, and we differ from glibc:
1957  *
1958  * $ ./gethostbyname_uclibc wer.google.com
1959  * h_name:'c13-ss-2-lb.cnet.com'
1960  * h_length:4
1961  * h_addrtype:2 AF_INET
1962  * alias:'wer.google.com' <===
1963  * addr: 0x4174efd8 '216.239.116.65'
1964  *
1965  * $ ./gethostbyname_glibc wer.google.com
1966  * h_name:'c13-ss-2-lb.cnet.com'
1967  * h_length:4
1968  * h_addrtype:2 AF_INET
1969  * alias:'wer.google.com.com' <===
1970  * addr:'216.239.116.65'
1971  *
1972  * When examples were run, /etc/resolv.conf contained "search com" line.
1973  */
1974 int gethostbyname_r(const char *name,
1975                 struct hostent *result_buf,
1976                 char *buf,
1977                 size_t buflen,
1978                 struct hostent **result,
1979                 int *h_errnop)
1980 {
1981         struct in_addr **addr_list;
1982         char **alias;
1983         char *alias0;
1984         unsigned char *packet;
1985         struct resolv_answer a;
1986         int i;
1987         int packet_len;
1988         int wrong_af = 0;
1989
1990         *result = NULL;
1991         if (!name)
1992                 return EINVAL;
1993
1994         /* do /etc/hosts first */
1995         {
1996                 int old_errno = errno;  /* save the old errno and reset errno */
1997                 __set_errno(0);         /* to check for missing /etc/hosts. */
1998                 i = __get_hosts_byname_r(name, AF_INET, result_buf,
1999                                 buf, buflen, result, h_errnop);
2000                 if (i == NETDB_SUCCESS) {
2001                         __set_errno(old_errno);
2002                         return i;
2003                 }
2004                 switch (*h_errnop) {
2005                         case HOST_NOT_FOUND:
2006                                 wrong_af = (i == TRY_AGAIN);
2007                         case NO_ADDRESS:
2008                                 break;
2009                         case NETDB_INTERNAL:
2010                                 if (errno == ENOENT) {
2011                                         break;
2012                                 }
2013                                 /* else fall through */
2014                         default:
2015                                 return i;
2016                 }
2017                 __set_errno(old_errno);
2018         }
2019
2020         DPRINTF("Nothing found in /etc/hosts\n");
2021
2022         *h_errnop = NETDB_INTERNAL;
2023
2024         /* prepare future h_aliases[0] */
2025         i = strlen(name) + 1;
2026         if ((ssize_t)buflen <= i)
2027                 return ERANGE;
2028         memcpy(buf, name, i); /* paranoia: name might change */
2029         alias0 = buf;
2030         buf += i;
2031         buflen -= i;
2032         /* make sure pointer is aligned */
2033         i = ALIGN_BUFFER_OFFSET(buf);
2034         buf += i;
2035         buflen -= i;
2036         /* Layout in buf:
2037          * char *alias[2];
2038          * struct in_addr* addr_list[NN+1];
2039          * struct in_addr* in[NN];
2040          */
2041         alias = (char **)buf;
2042         buf += sizeof(alias[0]) * 2;
2043         buflen -= sizeof(alias[0]) * 2;
2044         addr_list = (struct in_addr **)buf;
2045         /* buflen may be < 0, must do signed compare */
2046         if ((ssize_t)buflen < 256)
2047                 return ERANGE;
2048
2049         /* we store only one "alias" - the name itself */
2050 #ifdef __UCLIBC_MJN3_ONLY__
2051 #warning TODO -- generate the full list
2052 #endif
2053         alias[0] = alias0;
2054         alias[1] = NULL;
2055
2056         /* maybe it is already an address? */
2057         {
2058                 struct in_addr *in = (struct in_addr *)(buf + sizeof(addr_list[0]) * 2);
2059                 if (inet_aton(name, in)) {
2060                         addr_list[0] = in;
2061                         addr_list[1] = NULL;
2062                         result_buf->h_name = alias0;
2063                         result_buf->h_aliases = alias;
2064                         result_buf->h_addrtype = AF_INET;
2065                         result_buf->h_length = sizeof(struct in_addr);
2066                         result_buf->h_addr_list = (char **) addr_list;
2067                         *result = result_buf;
2068                         *h_errnop = NETDB_SUCCESS;
2069                         return NETDB_SUCCESS;
2070                 }
2071         }
2072
2073         /* what if /etc/hosts has it but it's not IPv4?
2074          * F.e. "::1 localhost6". We don't do DNS query for such hosts -
2075          * "ping localhost6" should be fast even if DNS server is down! */
2076         if (wrong_af) {
2077                 *h_errnop = HOST_NOT_FOUND;
2078                 return TRY_AGAIN;
2079         }
2080
2081         /* talk to DNS servers */
2082         a.buf = buf;
2083         /* take into account that at least one address will be there,
2084          * we'll need space of one in_addr + two addr_list[] elems */
2085         a.buflen = buflen - ((sizeof(addr_list[0]) * 2 + sizeof(struct in_addr)));
2086         a.add_count = 0;
2087         packet_len = __dns_lookup(name, T_A, &packet, &a);
2088         if (packet_len < 0) {
2089                 *h_errnop = HOST_NOT_FOUND;
2090                 DPRINTF("__dns_lookup returned < 0\n");
2091                 return TRY_AGAIN;
2092         }
2093
2094         if (a.atype == T_A) { /* ADDRESS */
2095                 /* we need space for addr_list[] and one IPv4 address */
2096                 /* + 1 accounting for 1st addr (it's in a.rdata),
2097                  * another + 1 for NULL in last addr_list[]: */
2098                 int need_bytes = sizeof(addr_list[0]) * (a.add_count + 1 + 1)
2099                                 /* for 1st addr (it's in a.rdata): */
2100                                 + sizeof(struct in_addr);
2101                 /* how many bytes will 2nd and following addresses take? */
2102                 int ips_len = a.add_count * a.rdlength;
2103
2104                 buflen -= (need_bytes + ips_len);
2105                 if ((ssize_t)buflen < 0) {
2106                         DPRINTF("buffer too small for all addresses\n");
2107                         /* *h_errnop = NETDB_INTERNAL; - already is */
2108                         i = ERANGE;
2109                         goto free_and_ret;
2110                 }
2111
2112                 /* if there are additional addresses in buf,
2113                  * move them forward so that they are not destroyed */
2114                 DPRINTF("a.add_count:%d a.rdlength:%d a.rdata:%p\n", a.add_count, a.rdlength, a.rdata);
2115                 memmove(buf + need_bytes, buf, ips_len);
2116
2117                 /* 1st address is in a.rdata, insert it  */
2118                 buf += need_bytes - sizeof(struct in_addr);
2119                 memcpy(buf, a.rdata, sizeof(struct in_addr));
2120
2121                 /* fill addr_list[] */
2122                 for (i = 0; i <= a.add_count; i++) {
2123                         addr_list[i] = (struct in_addr*)buf;
2124                         buf += sizeof(struct in_addr);
2125                 }
2126                 addr_list[i] = NULL;
2127
2128                 /* if we have enough space, we can report "better" name
2129                  * (it may contain search domains attached by __dns_lookup,
2130                  * or CNAME of the host if it is different from the name
2131                  * we used to find it) */
2132                 if (a.dotted && buflen > strlen(a.dotted)) {
2133                         strcpy(buf, a.dotted);
2134                         alias0 = buf;
2135                 }
2136
2137                 result_buf->h_name = alias0;
2138                 result_buf->h_aliases = alias;
2139                 result_buf->h_addrtype = AF_INET;
2140                 result_buf->h_length = sizeof(struct in_addr);
2141                 result_buf->h_addr_list = (char **) addr_list;
2142                 *result = result_buf;
2143                 *h_errnop = NETDB_SUCCESS;
2144                 i = NETDB_SUCCESS;
2145                 goto free_and_ret;
2146         }
2147
2148         *h_errnop = HOST_NOT_FOUND;
2149         i = TRY_AGAIN;
2150
2151  free_and_ret:
2152         free(a.dotted);
2153         free(packet);
2154         return i;
2155 }
2156 libc_hidden_def(gethostbyname_r)
2157 #endif
2158
2159
2160 #ifdef L_gethostbyname2_r
2161
2162 int gethostbyname2_r(const char *name,
2163                 int family,
2164                 struct hostent *result_buf,
2165                 char *buf,
2166                 size_t buflen,
2167                 struct hostent **result,
2168                 int *h_errnop)
2169 {
2170 #ifndef __UCLIBC_HAS_IPV6__
2171         return family == (AF_INET)
2172                 ? gethostbyname_r(name, result_buf, buf, buflen, result, h_errnop)
2173                 : HOST_NOT_FOUND;
2174 #else
2175         struct in6_addr *in;
2176         struct in6_addr **addr_list;
2177         unsigned char *packet;
2178         struct resolv_answer a;
2179         int i;
2180         int nest = 0;
2181         int wrong_af = 0;
2182
2183         if (family == AF_INET)
2184                 return gethostbyname_r(name, result_buf, buf, buflen, result, h_errnop);
2185
2186         *result = NULL;
2187         if (family != AF_INET6)
2188                 return EINVAL;
2189
2190         if (!name)
2191                 return EINVAL;
2192
2193         /* do /etc/hosts first */
2194         {
2195                 int old_errno = errno;  /* Save the old errno and reset errno */
2196                 __set_errno(0);                 /* to check for missing /etc/hosts. */
2197
2198                 i = __get_hosts_byname_r(name, AF_INET6 /*family*/, result_buf,
2199                                 buf, buflen, result, h_errnop);
2200                 if (i == NETDB_SUCCESS) {
2201                         __set_errno(old_errno);
2202                         return i;
2203                 }
2204                 switch (*h_errnop) {
2205                         case HOST_NOT_FOUND:
2206                                 wrong_af = (i == TRY_AGAIN);
2207                         case NO_ADDRESS:
2208                                 break;
2209                         case NETDB_INTERNAL:
2210                                 if (errno == ENOENT) {
2211                                         break;
2212                                 }
2213                                 /* else fall through */
2214                         default:
2215                                 return i;
2216                 }
2217                 __set_errno(old_errno);
2218         }
2219         DPRINTF("Nothing found in /etc/hosts\n");
2220
2221         *h_errnop = NETDB_INTERNAL;
2222
2223         /* make sure pointer is aligned */
2224         i = ALIGN_BUFFER_OFFSET(buf);
2225         buf += i;
2226         buflen -= i;
2227         /* Layout in buf:
2228          * struct in6_addr* in;
2229          * struct in6_addr* addr_list[2];
2230          * char scratch_buf[256];
2231          */
2232         in = (struct in6_addr*)buf;
2233         buf += sizeof(*in);
2234         buflen -= sizeof(*in);
2235         addr_list = (struct in6_addr**)buf;
2236         buf += sizeof(*addr_list) * 2;
2237         buflen -= sizeof(*addr_list) * 2;
2238         if ((ssize_t)buflen < 256)
2239                 return ERANGE;
2240         addr_list[0] = in;
2241         addr_list[1] = NULL;
2242         strncpy(buf, name, buflen);
2243         buf[buflen] = '\0';
2244
2245         /* maybe it is already an address? */
2246         if (inet_pton(AF_INET6, name, in)) {
2247                 result_buf->h_name = buf;
2248                 result_buf->h_addrtype = AF_INET6;
2249                 result_buf->h_length = sizeof(*in);
2250                 result_buf->h_addr_list = (char **) addr_list;
2251                 /* result_buf->h_aliases = ??? */
2252                 *result = result_buf;
2253                 *h_errnop = NETDB_SUCCESS;
2254                 return NETDB_SUCCESS;
2255         }
2256
2257         /* what if /etc/hosts has it but it's not IPv6?
2258          * F.e. "127.0.0.1 localhost". We don't do DNS query for such hosts -
2259          * "ping localhost" should be fast even if DNS server is down! */
2260         if (wrong_af) {
2261                 *h_errnop = HOST_NOT_FOUND;
2262                 return TRY_AGAIN;
2263         }
2264
2265         /* talk to DNS servers */
2266 /* TODO: why it's so different from gethostbyname_r (IPv4 case)? */
2267         memset(&a, '\0', sizeof(a));
2268         for (;;) {
2269                 int packet_len;
2270
2271 /* Hmm why we memset(a) to zeros only once? */
2272                 packet_len = __dns_lookup(buf, T_AAAA, &packet, &a);
2273                 if (packet_len < 0) {
2274                         *h_errnop = HOST_NOT_FOUND;
2275                         return TRY_AGAIN;
2276                 }
2277                 strncpy(buf, a.dotted, buflen);
2278                 free(a.dotted);
2279
2280                 if (a.atype != T_CNAME)
2281                         break;
2282
2283                 DPRINTF("Got a CNAME in gethostbyname()\n");
2284                 if (++nest > MAX_RECURSE) {
2285                         *h_errnop = NO_RECOVERY;
2286                         return -1;
2287                 }
2288                 i = __decode_dotted(packet, a.rdoffset, packet_len, buf, buflen);
2289                 free(packet);
2290                 if (i < 0) {
2291                         *h_errnop = NO_RECOVERY;
2292                         return -1;
2293                 }
2294         }
2295         if (a.atype == T_AAAA) {        /* ADDRESS */
2296                 memcpy(in, a.rdata, sizeof(*in));
2297                 result_buf->h_name = buf;
2298                 result_buf->h_addrtype = AF_INET6;
2299                 result_buf->h_length = sizeof(*in);
2300                 result_buf->h_addr_list = (char **) addr_list;
2301                 /* result_buf->h_aliases = ??? */
2302                 free(packet);
2303                 *result = result_buf;
2304                 *h_errnop = NETDB_SUCCESS;
2305                 return NETDB_SUCCESS;
2306         }
2307         free(packet);
2308         *h_errnop = HOST_NOT_FOUND;
2309         return TRY_AGAIN;
2310
2311 #endif /* __UCLIBC_HAS_IPV6__ */
2312 }
2313 libc_hidden_def(gethostbyname2_r)
2314 #endif
2315
2316
2317 #ifdef L_gethostbyaddr_r
2318
2319 int gethostbyaddr_r(const void *addr, socklen_t addrlen,
2320                 int type,
2321                 struct hostent *result_buf,
2322                 char *buf, size_t buflen,
2323                 struct hostent **result,
2324                 int *h_errnop)
2325
2326 {
2327         struct in_addr *in;
2328         struct in_addr **addr_list;
2329         char **alias;
2330         unsigned char *packet;
2331         struct resolv_answer a;
2332         int i;
2333         int packet_len;
2334         int nest = 0;
2335
2336         *result = NULL;
2337         if (!addr)
2338                 return EINVAL;
2339
2340         switch (type) {
2341 #ifdef __UCLIBC_HAS_IPV4__
2342                 case AF_INET:
2343                         if (addrlen != sizeof(struct in_addr))
2344                                 return EINVAL;
2345                         break;
2346 #endif
2347 #ifdef __UCLIBC_HAS_IPV6__
2348                 case AF_INET6:
2349                         if (addrlen != sizeof(struct in6_addr))
2350                                 return EINVAL;
2351                         break;
2352 #endif
2353                 default:
2354                         return EINVAL;
2355         }
2356
2357         /* do /etc/hosts first */
2358         i = __get_hosts_byaddr_r(addr, addrlen, type, result_buf,
2359                                 buf, buflen, result, h_errnop);
2360         if (i == 0)
2361                 return i;
2362         switch (*h_errnop) {
2363                 case HOST_NOT_FOUND:
2364                 case NO_ADDRESS:
2365                         break;
2366                 default:
2367                         return i;
2368         }
2369
2370         *h_errnop = NETDB_INTERNAL;
2371
2372         /* make sure pointer is aligned */
2373         i = ALIGN_BUFFER_OFFSET(buf);
2374         buf += i;
2375         buflen -= i;
2376         /* Layout in buf:
2377          * char *alias[ALIAS_DIM];
2378          * struct in[6]_addr* addr_list[2];
2379          * struct in[6]_addr* in;
2380          * char scratch_buffer[256+];
2381          */
2382 #define in6 ((struct in6_addr *)in)
2383         alias = (char **)buf;
2384         buf += sizeof(*alias) * ALIAS_DIM;
2385         buflen -= sizeof(*alias) * ALIAS_DIM;
2386         addr_list = (struct in_addr**)buf;
2387         buf += sizeof(*addr_list) * 2;
2388         buflen -= sizeof(*addr_list) * 2;
2389         in = (struct in_addr*)buf;
2390 #ifndef __UCLIBC_HAS_IPV6__
2391         buf += sizeof(*in);
2392         buflen -= sizeof(*in);
2393 #else
2394         buf += sizeof(*in6);
2395         buflen -= sizeof(*in6);
2396 #endif
2397         if ((ssize_t)buflen < 256)
2398                 return ERANGE;
2399         alias[0] = buf;
2400         alias[1] = NULL;
2401         addr_list[0] = in;
2402         addr_list[1] = NULL;
2403         memcpy(&in, addr, addrlen);
2404
2405         if (0) /* nothing */;
2406 #ifdef __UCLIBC_HAS_IPV4__
2407         else IF_HAS_BOTH(if (type == AF_INET)) {
2408                 unsigned char *tp = (unsigned char *)addr;
2409                 sprintf(buf, "%u.%u.%u.%u.in-addr.arpa",
2410                                 tp[3], tp[2], tp[1], tp[0]);
2411         }
2412 #endif
2413 #ifdef __UCLIBC_HAS_IPV6__
2414         else {
2415                 char *dst = buf;
2416                 unsigned char *tp = (unsigned char *)addr + addrlen - 1;
2417                 do {
2418                         dst += sprintf(dst, "%x.%x.", tp[i] & 0xf, tp[i] >> 4);
2419                         tp--;
2420                 } while (tp >= (unsigned char *)addr);
2421                 strcpy(dst, "ip6.arpa");
2422         }
2423 #endif
2424
2425         memset(&a, '\0', sizeof(a));
2426         for (;;) {
2427 /* Hmm why we memset(a) to zeros only once? */
2428                 packet_len = __dns_lookup(buf, T_PTR, &packet, &a);
2429                 if (packet_len < 0) {
2430                         *h_errnop = HOST_NOT_FOUND;
2431                         return TRY_AGAIN;
2432                 }
2433
2434                 strncpy(buf, a.dotted, buflen);
2435                 free(a.dotted);
2436                 if (a.atype != T_CNAME)
2437                         break;
2438
2439                 DPRINTF("Got a CNAME in gethostbyaddr()\n");
2440                 if (++nest > MAX_RECURSE) {
2441                         *h_errnop = NO_RECOVERY;
2442                         return -1;
2443                 }
2444                 /* Decode CNAME into buf, feed it to __dns_lookup() again */
2445                 i = __decode_dotted(packet, a.rdoffset, packet_len, buf, buflen);
2446                 free(packet);
2447                 if (i < 0) {
2448                         *h_errnop = NO_RECOVERY;
2449                         return -1;
2450                 }
2451         }
2452
2453         if (a.atype == T_PTR) { /* ADDRESS */
2454                 i = __decode_dotted(packet, a.rdoffset, packet_len, buf, buflen);
2455                 free(packet);
2456                 result_buf->h_name = buf;
2457                 result_buf->h_addrtype = type;
2458                 result_buf->h_length = addrlen;
2459                 result_buf->h_addr_list = (char **) addr_list;
2460                 result_buf->h_aliases = alias;
2461                 *result = result_buf;
2462                 *h_errnop = NETDB_SUCCESS;
2463                 return NETDB_SUCCESS;
2464         }
2465
2466         free(packet);
2467         *h_errnop = NO_ADDRESS;
2468         return TRY_AGAIN;
2469 #undef in6
2470 }
2471 libc_hidden_def(gethostbyaddr_r)
2472 #endif
2473
2474
2475 #ifdef L_gethostent_r
2476
2477 __UCLIBC_MUTEX_STATIC(mylock, PTHREAD_MUTEX_INITIALIZER);
2478
2479 static smallint __stay_open;
2480 static FILE * __gethostent_fp;
2481
2482 void endhostent(void)
2483 {
2484         __UCLIBC_MUTEX_LOCK(mylock);
2485         __stay_open = 0;
2486         if (__gethostent_fp) {
2487                 fclose(__gethostent_fp);
2488                 __gethostent_fp = NULL;
2489         }
2490         __UCLIBC_MUTEX_UNLOCK(mylock);
2491 }
2492
2493 void sethostent(int stay_open)
2494 {
2495         __UCLIBC_MUTEX_LOCK(mylock);
2496         __stay_open = (stay_open != 0);
2497         __UCLIBC_MUTEX_UNLOCK(mylock);
2498 }
2499
2500 int gethostent_r(struct hostent *result_buf, char *buf, size_t buflen,
2501         struct hostent **result, int *h_errnop)
2502 {
2503         int ret;
2504
2505         __UCLIBC_MUTEX_LOCK(mylock);
2506         if (__gethostent_fp == NULL) {
2507                 __gethostent_fp = __open_etc_hosts();
2508                 if (__gethostent_fp == NULL) {
2509                         *result = NULL;
2510                         ret = TRY_AGAIN;
2511                         goto DONE;
2512                 }
2513         }
2514
2515         ret = __read_etc_hosts_r(__gethostent_fp, NULL, AF_INET, GETHOSTENT,
2516                    result_buf, buf, buflen, result, h_errnop);
2517         if (__stay_open == 0) {
2518                 fclose(__gethostent_fp);
2519                 __gethostent_fp = NULL;
2520         }
2521 DONE:
2522         __UCLIBC_MUTEX_UNLOCK(mylock);
2523         return ret;
2524 }
2525 libc_hidden_def(gethostent_r)
2526 #endif
2527
2528
2529 #ifdef L_gethostent
2530
2531 struct hostent *gethostent(void)
2532 {
2533         static struct hostent h;
2534         static char buf[
2535 #ifndef __UCLIBC_HAS_IPV6__
2536                         sizeof(struct in_addr) + sizeof(struct in_addr *) * 2 +
2537 #else
2538                         sizeof(struct in6_addr) + sizeof(struct in6_addr *) * 2 +
2539 #endif /* __UCLIBC_HAS_IPV6__ */
2540                         sizeof(char *) * ALIAS_DIM +
2541                         80 /*namebuffer*/ + 2 /* margin */];
2542         struct hostent *host;
2543
2544         gethostent_r(&h, buf, sizeof(buf), &host, &h_errno);
2545         return host;
2546 }
2547 #endif
2548
2549
2550 #ifdef L_gethostbyname2
2551
2552 struct hostent *gethostbyname2(const char *name, int family)
2553 {
2554 #ifndef __UCLIBC_HAS_IPV6__
2555         return family == AF_INET ? gethostbyname(name) : (struct hostent*)NULL;
2556 #else
2557         static struct hostent h;
2558         static char buf[sizeof(struct in6_addr) +
2559                         sizeof(struct in6_addr *) * 2 +
2560                         sizeof(char *)*ALIAS_DIM + 384/*namebuffer*/ + 32/* margin */];
2561         struct hostent *hp;
2562
2563         gethostbyname2_r(name, family, &h, buf, sizeof(buf), &hp, &h_errno);
2564         return hp;
2565 #endif
2566 }
2567 libc_hidden_def(gethostbyname2)
2568 #endif
2569
2570
2571 #ifdef L_gethostbyname
2572
2573 struct hostent *gethostbyname(const char *name)
2574 {
2575 #ifndef __UCLIBC_HAS_IPV6__
2576         static struct hostent h;
2577         static char buf[sizeof(struct in_addr) +
2578                         sizeof(struct in_addr *) * 2 +
2579                         sizeof(char *)*ALIAS_DIM + 384/*namebuffer*/ + 32/* margin */];
2580         struct hostent *hp;
2581
2582         gethostbyname_r(name, &h, buf, sizeof(buf), &hp, &h_errno);
2583         return hp;
2584 #else
2585         return gethostbyname2(name, AF_INET);
2586 #endif
2587 }
2588 libc_hidden_def(gethostbyname)
2589 #endif
2590
2591
2592 #ifdef L_gethostbyaddr
2593
2594 struct hostent *gethostbyaddr(const void *addr, socklen_t len, int type)
2595 {
2596         static struct hostent h;
2597         static char buf[
2598 #ifndef __UCLIBC_HAS_IPV6__
2599                         sizeof(struct in_addr) + sizeof(struct in_addr *)*2 +
2600 #else
2601                         sizeof(struct in6_addr) + sizeof(struct in6_addr *)*2 +
2602 #endif /* __UCLIBC_HAS_IPV6__ */
2603                         sizeof(char *)*ALIAS_DIM + 384 /*namebuffer*/ + 32 /* margin */];
2604         struct hostent *hp;
2605
2606         gethostbyaddr_r(addr, len, type, &h, buf, sizeof(buf), &hp, &h_errno);
2607         return hp;
2608 }
2609 libc_hidden_def(gethostbyaddr)
2610 #endif
2611
2612
2613 #ifdef L_res_comp
2614
2615 /*
2616  * Expand compressed domain name 'comp_dn' to full domain name.
2617  * 'msg' is a pointer to the begining of the message,
2618  * 'eomorig' points to the first location after the message,
2619  * 'exp_dn' is a pointer to a buffer of size 'length' for the result.
2620  * Return size of compressed name or -1 if there was an error.
2621  */
2622 int dn_expand(const u_char *msg, const u_char *eom, const u_char *src,
2623                                 char *dst, int dstsiz)
2624 {
2625         int n = ns_name_uncompress(msg, eom, src, dst, (size_t)dstsiz);
2626
2627         if (n > 0 && dst[0] == '.')
2628                 dst[0] = '\0';
2629         return n;
2630 }
2631 #endif /* L_res_comp */
2632
2633
2634 #ifdef L_ns_name
2635
2636 /* Thinking in noninternationalized USASCII (per the DNS spec),
2637  * is this character visible and not a space when printed ?
2638  */
2639 static int printable(int ch)
2640 {
2641         return (ch > 0x20 && ch < 0x7f);
2642 }
2643 /* Thinking in noninternationalized USASCII (per the DNS spec),
2644  * is this characted special ("in need of quoting") ?
2645  */
2646 static int special(int ch)
2647 {
2648         switch (ch) {
2649                 case 0x22: /* '"' */
2650                 case 0x2E: /* '.' */
2651                 case 0x3B: /* ';' */
2652                 case 0x5C: /* '\\' */
2653                         /* Special modifiers in zone files. */
2654                 case 0x40: /* '@' */
2655                 case 0x24: /* '$' */
2656                         return 1;
2657                 default:
2658                         return 0;
2659         }
2660 }
2661
2662 /*
2663  * ns_name_uncompress(msg, eom, src, dst, dstsiz)
2664  *      Expand compressed domain name to presentation format.
2665  * return:
2666  *      Number of bytes read out of `src', or -1 (with errno set).
2667  * note:
2668  *      Root domain returns as "." not "".
2669  */
2670 int ns_name_uncompress(const u_char *msg, const u_char *eom,
2671                 const u_char *src, char *dst, size_t dstsiz)
2672 {
2673         u_char tmp[NS_MAXCDNAME];
2674         int n;
2675
2676         n = ns_name_unpack(msg, eom, src, tmp, sizeof tmp);
2677         if (n == -1)
2678                 return -1;
2679         if (ns_name_ntop(tmp, dst, dstsiz) == -1)
2680                 return -1;
2681         return n;
2682 }
2683 libc_hidden_def(ns_name_uncompress)
2684
2685 /*
2686  * ns_name_ntop(src, dst, dstsiz)
2687  *      Convert an encoded domain name to printable ascii as per RFC1035.
2688  * return:
2689  *      Number of bytes written to buffer, or -1 (with errno set)
2690  * notes:
2691  *      The root is returned as "."
2692  *      All other domains are returned in non absolute form
2693  */
2694 int ns_name_ntop(const u_char *src, char *dst, size_t dstsiz)
2695 {
2696         static const char digits[] = "0123456789";
2697
2698         const u_char *cp;
2699         char *dn, *eom;
2700         u_char c;
2701         u_int n;
2702
2703         cp = src;
2704         dn = dst;
2705         eom = dst + dstsiz;
2706
2707         while ((n = *cp++) != 0) {
2708                 if ((n & NS_CMPRSFLGS) != 0) {
2709                         /* Some kind of compression pointer. */
2710                         __set_errno(EMSGSIZE);
2711                         return -1;
2712                 }
2713                 if (dn != dst) {
2714                         if (dn >= eom) {
2715                                 __set_errno(EMSGSIZE);
2716                                 return -1;
2717                         }
2718                         *dn++ = '.';
2719                 }
2720                 if (dn + n >= eom) {
2721                         __set_errno(EMSGSIZE);
2722                         return -1;
2723                 }
2724                 for (; n > 0; n--) {
2725                         c = *cp++;
2726                         if (special(c)) {
2727                                 if (dn + 1 >= eom) {
2728                                         __set_errno(EMSGSIZE);
2729                                         return -1;
2730                                 }
2731                                 *dn++ = '\\';
2732                                 *dn++ = (char)c;
2733                         } else if (!printable(c)) {
2734                                 if (dn + 3 >= eom) {
2735                                         __set_errno(EMSGSIZE);
2736                                         return -1;
2737                                 }
2738                                 *dn++ = '\\';
2739                                 *dn++ = digits[c / 100];
2740                                 *dn++ = digits[(c % 100) / 10];
2741                                 *dn++ = digits[c % 10];
2742                         } else {
2743                                 if (dn >= eom) {
2744                                         __set_errno(EMSGSIZE);
2745                                         return -1;
2746                                 }
2747                                 *dn++ = (char)c;
2748                         }
2749                 }
2750         }
2751         if (dn == dst) {
2752                 if (dn >= eom) {
2753                         __set_errno(EMSGSIZE);
2754                         return -1;
2755                 }
2756                 *dn++ = '.';
2757         }
2758         if (dn >= eom) {
2759                 __set_errno(EMSGSIZE);
2760                 return -1;
2761         }
2762         *dn++ = '\0';
2763         return (dn - dst);
2764 }
2765 libc_hidden_def(ns_name_ntop)
2766
2767 /*
2768  * ns_name_unpack(msg, eom, src, dst, dstsiz)
2769  *      Unpack a domain name from a message, source may be compressed.
2770  * return:
2771  *      -1 if it fails, or consumed octets if it succeeds.
2772  */
2773 int ns_name_unpack(const u_char *msg, const u_char *eom, const u_char *src,
2774                u_char *dst, size_t dstsiz)
2775 {
2776         const u_char *srcp, *dstlim;
2777         u_char *dstp;
2778         int n, len, checked;
2779
2780         len = -1;
2781         checked = 0;
2782         dstp = dst;
2783         srcp = src;
2784         dstlim = dst + dstsiz;
2785         if (srcp < msg || srcp >= eom) {
2786                 __set_errno(EMSGSIZE);
2787                 return -1;
2788         }
2789         /* Fetch next label in domain name. */
2790         while ((n = *srcp++) != 0) {
2791                 /* Check for indirection. */
2792                 switch (n & NS_CMPRSFLGS) {
2793                         case 0:
2794                                 /* Limit checks. */
2795                                 if (dstp + n + 1 >= dstlim || srcp + n >= eom) {
2796                                         __set_errno(EMSGSIZE);
2797                                         return -1;
2798                                 }
2799                                 checked += n + 1;
2800                                 *dstp++ = n;
2801                                 memcpy(dstp, srcp, n);
2802                                 dstp += n;
2803                                 srcp += n;
2804                                 break;
2805
2806                         case NS_CMPRSFLGS:
2807                                 if (srcp >= eom) {
2808                                         __set_errno(EMSGSIZE);
2809                                         return -1;
2810                                 }
2811                                 if (len < 0)
2812                                         len = srcp - src + 1;
2813                                 srcp = msg + (((n & 0x3f) << 8) | (*srcp & 0xff));
2814                                 if (srcp < msg || srcp >= eom) {  /* Out of range. */
2815                                         __set_errno(EMSGSIZE);
2816                                         return -1;
2817                                 }
2818                                 checked += 2;
2819                                 /*
2820                                  * Check for loops in the compressed name;
2821                                  * if we've looked at the whole message,
2822                                  * there must be a loop.
2823                                  */
2824                                 if (checked >= eom - msg) {
2825                                         __set_errno(EMSGSIZE);
2826                                         return -1;
2827                                 }
2828                                 break;
2829
2830                         default:
2831                                 __set_errno(EMSGSIZE);
2832                                 return -1;                    /* flag error */
2833                 }
2834         }
2835         *dstp = '\0';
2836         if (len < 0)
2837                 len = srcp - src;
2838         return len;
2839 }
2840 libc_hidden_def(ns_name_unpack)
2841 #endif /* L_ns_name */
2842
2843
2844 #ifdef L_res_init
2845
2846 /* Will be called under __resolv_lock. */
2847 static void res_sync_func(void)
2848 {
2849         struct __res_state *rp = &(_res);
2850         int n;
2851
2852         /* If we didn't get malloc failure earlier... */
2853         if (__nameserver != (void*) &__local_nameserver) {
2854                 /* TODO:
2855                  * if (__nameservers < rp->nscount) - try to grow __nameserver[]?
2856                  */
2857 #ifdef __UCLIBC_HAS_IPV6__
2858                 if (__nameservers > rp->_u._ext.nscount)
2859                         __nameservers = rp->_u._ext.nscount;
2860                 n = __nameservers;
2861                 while (--n >= 0)
2862                         __nameserver[n].sa6 = *rp->_u._ext.nsaddrs[n]; /* struct copy */
2863 #else /* IPv4 only */
2864                 if (__nameservers > rp->nscount)
2865                         __nameservers = rp->nscount;
2866                 n = __nameservers;
2867                 while (--n >= 0)
2868                         __nameserver[n].sa4 = rp->nsaddr_list[n]; /* struct copy */
2869 #endif
2870         }
2871         /* Extend and comment what program is known
2872          * to use which _res.XXX member(s).
2873
2874            __resolv_opts = rp->options;
2875            ...
2876          */
2877 }
2878
2879 /* Our res_init never fails (always returns 0) */
2880 int res_init(void)
2881 {
2882         struct __res_state *rp = &(_res);
2883         int i;
2884         int n;
2885 #ifdef __UCLIBC_HAS_IPV6__
2886         int m = 0;
2887 #endif
2888
2889         __UCLIBC_MUTEX_LOCK(__resolv_lock);
2890         __close_nameservers();
2891         __open_nameservers();
2892
2893         __res_sync = res_sync_func;
2894
2895         memset(rp, 0, sizeof(*rp));
2896         rp->options = RES_INIT;
2897 #ifdef __UCLIBC_HAS_COMPAT_RES_STATE__
2898         rp->retrans = RES_TIMEOUT;
2899         rp->retry = 4;
2900 /*TODO: pulls in largish static buffers... use simpler one? */
2901         rp->id = random();
2902 #endif
2903         rp->ndots = 1;
2904 #ifdef __UCLIBC_HAS_EXTRA_COMPAT_RES_STATE__
2905         rp->_vcsock = -1;
2906 #endif
2907
2908         n = __searchdomains;
2909         if (n > ARRAY_SIZE(rp->dnsrch))
2910                 n = ARRAY_SIZE(rp->dnsrch);
2911         for (i = 0; i < n; i++)
2912                 rp->dnsrch[i] = __searchdomain[i];
2913
2914         /* copy nameservers' addresses */
2915         i = 0;
2916 #ifdef __UCLIBC_HAS_IPV4__
2917         n = 0;
2918         while (n < ARRAY_SIZE(rp->nsaddr_list) && i < __nameservers) {
2919                 if (__nameserver[i].sa.sa_family == AF_INET) {
2920                         rp->nsaddr_list[n] = __nameserver[i].sa4; /* struct copy */
2921 #ifdef __UCLIBC_HAS_IPV6__
2922                         if (m < ARRAY_SIZE(rp->_u._ext.nsaddrs)) {
2923                                 rp->_u._ext.nsaddrs[m] = (void*) &rp->nsaddr_list[n];
2924                                 m++;
2925                         }
2926 #endif
2927                         n++;
2928                 }
2929 #ifdef __UCLIBC_HAS_IPV6__
2930                 if (__nameserver[i].sa.sa_family == AF_INET6
2931                  && m < ARRAY_SIZE(rp->_u._ext.nsaddrs)
2932                 ) {
2933                         struct sockaddr_in6 *sa6 = malloc(sizeof(sa6));
2934                         if (sa6) {
2935                                 *sa6 = __nameserver[i].sa6; /* struct copy */
2936                                 rp->_u._ext.nsaddrs[m] = sa6;
2937                                 m++;
2938                         }
2939                 }
2940 #endif
2941                 i++;
2942         }
2943         rp->nscount = n;
2944 #ifdef __UCLIBC_HAS_IPV6__
2945         rp->_u._ext.nscount = m;
2946 #endif
2947
2948 #else /* IPv6 only */
2949         while (m < ARRAY_SIZE(rp->_u._ext.nsaddrs) && i < __nameservers) {
2950                 struct sockaddr_in6 *sa6 = malloc(sizeof(sa6));
2951                 if (sa6) {
2952                         *sa6 = __nameserver[i].sa6; /* struct copy */
2953                         rp->_u._ext.nsaddrs[m] = sa6;
2954                         m++;
2955                 }
2956                 i++;
2957         }
2958         rp->_u._ext.nscount = m;
2959 #endif
2960
2961         __UCLIBC_MUTEX_UNLOCK(__resolv_lock);
2962         return 0;
2963 }
2964 libc_hidden_def(res_init)
2965
2966 #ifdef __UCLIBC_HAS_BSD_RES_CLOSE__
2967 void res_close(void)
2968 {
2969         __UCLIBC_MUTEX_LOCK(__resolv_lock);
2970         __close_nameservers();
2971         __res_sync = NULL;
2972 #ifdef __UCLIBC_HAS_IPV6__
2973         {
2974                 char *p1 = (char*) &(_res.nsaddr_list[0]);
2975                 int m = 0;
2976                 /* free nsaddrs[m] if they do not point to nsaddr_list[x] */
2977                 while (m < ARRAY_SIZE(_res._u._ext.nsaddrs)) {
2978                         char *p2 = (char*)(_res._u._ext.nsaddrs[m]);
2979                         if (p2 < p1 || (p2 - p1) > sizeof(_res.nsaddr_list))
2980                                 free(p2);
2981                 }
2982         }
2983 #endif
2984         memset(&_res, 0, sizeof(_res));
2985         __UCLIBC_MUTEX_UNLOCK(__resolv_lock);
2986 }
2987 #endif
2988
2989 /* This needs to be after the use of _res in res_init, above.  */
2990 #undef _res
2991
2992 #ifndef __UCLIBC_HAS_THREADS__
2993 /* The resolver state for use by single-threaded programs.
2994    This differs from plain `struct __res_state _res;' in that it doesn't
2995    create a common definition, but a plain symbol that resides in .bss,
2996    which can have an alias.  */
2997 struct __res_state _res __attribute__((section (".bss")));
2998 struct __res_state *__resp = &_res;
2999 #else //__UCLIBC_HAS_THREADS__
3000 struct __res_state _res __attribute__((section (".bss"))) attribute_hidden;
3001
3002 # if defined __UCLIBC_HAS_TLS__
3003 #  undef __resp
3004 __thread struct __res_state *__resp = &_res;
3005 /*
3006  * FIXME: Add usage of hidden attribute for this when used in the shared
3007  *        library. It currently crashes the linker when doing section
3008  *        relocations.
3009  */
3010 extern __thread struct __res_state *__libc_resp
3011        __attribute__ ((alias ("__resp")));
3012 # else
3013 #  undef __resp
3014 struct __res_state *__resp = &_res;
3015 # endif
3016 #endif
3017
3018 #endif /* L_res_init */
3019
3020 #ifdef L_res_state
3021 # if defined __UCLIBC_HAS_TLS__
3022 struct __res_state *
3023 __res_state (void)
3024 {
3025        return __resp;
3026 }
3027 # else
3028 #  undef _res
3029 extern struct __res_state _res;
3030
3031 /* When threaded, _res may be a per-thread variable.  */
3032 struct __res_state *
3033 weak_const_function
3034 __res_state (void)
3035 {
3036        return &_res;
3037 }
3038 # endif
3039
3040 #endif
3041
3042
3043 #ifdef L_res_query
3044
3045 int res_query(const char *dname, int class, int type,
3046               unsigned char *answer, int anslen)
3047 {
3048         int i;
3049         unsigned char *packet = NULL;
3050         struct resolv_answer a;
3051
3052         if (!dname || class != 1 /* CLASS_IN */) {
3053                 h_errno = NO_RECOVERY;
3054                 return -1;
3055         }
3056
3057         memset(&a, '\0', sizeof(a));
3058         i = __dns_lookup(dname, type, &packet, &a);
3059
3060         if (i < 0) {
3061                 if (!h_errno) /* TODO: can this ever happen? */
3062                         h_errno = TRY_AGAIN;
3063                 return -1;
3064         }
3065
3066         free(a.dotted);
3067
3068         if (a.atype == type) { /* CNAME */
3069                 if (i > anslen)
3070                         i = anslen;
3071                 memcpy(answer, packet, i);
3072         }
3073         free(packet);
3074         return i;
3075 }
3076 libc_hidden_def(res_query)
3077
3078 /*
3079  * Formulate a normal query, send, and retrieve answer in supplied buffer.
3080  * Return the size of the response on success, -1 on error.
3081  * If enabled, implement search rules until answer or unrecoverable failure
3082  * is detected.  Error code, if any, is left in h_errno.
3083  */
3084 #define __TRAILING_DOT  (1<<0)
3085 #define __GOT_NODATA    (1<<1)
3086 #define __GOT_SERVFAIL  (1<<2)
3087 #define __TRIED_AS_IS   (1<<3)
3088 int res_search(const char *name, int class, int type, u_char *answer,
3089                 int anslen)
3090 {
3091         const char *cp;
3092         char **domain;
3093         HEADER *hp = (HEADER *)(void *)answer;
3094         unsigned dots;
3095         unsigned state;
3096         int ret, saved_herrno;
3097         uint32_t _res_options;
3098         unsigned _res_ndots;
3099         char **_res_dnsrch;
3100
3101         if (!name || !answer) {
3102                 h_errno = NETDB_INTERNAL;
3103                 return -1;
3104         }
3105
3106  again:
3107         __UCLIBC_MUTEX_LOCK(__resolv_lock);
3108         _res_options = _res.options;
3109         _res_ndots = _res.ndots;
3110         _res_dnsrch = _res.dnsrch;
3111         __UCLIBC_MUTEX_UNLOCK(__resolv_lock);
3112         if (!(_res_options & RES_INIT)) {
3113                 res_init(); /* our res_init never fails */
3114                 goto again;
3115         }
3116
3117         state = 0;
3118         errno = 0;
3119         h_errno = HOST_NOT_FOUND;       /* default, if we never query */
3120         dots = 0;
3121         for (cp = name; *cp; cp++)
3122                 dots += (*cp == '.');
3123
3124         if (cp > name && *--cp == '.')
3125                 state |= __TRAILING_DOT;
3126
3127         /*
3128          * If there are dots in the name already, let's just give it a try
3129          * 'as is'.  The threshold can be set with the "ndots" option.
3130          */
3131         saved_herrno = -1;
3132         if (dots >= _res_ndots) {
3133                 ret = res_querydomain(name, NULL, class, type, answer, anslen);
3134                 if (ret > 0)
3135                         return ret;
3136                 saved_herrno = h_errno;
3137                 state |= __TRIED_AS_IS;
3138         }
3139
3140         /*
3141          * We do at least one level of search if
3142          *      - there is no dot and RES_DEFNAME is set, or
3143          *      - there is at least one dot, there is no trailing dot,
3144          *        and RES_DNSRCH is set.
3145          */
3146         if ((!dots && (_res_options & RES_DEFNAMES))
3147          || (dots && !(state & __TRAILING_DOT) && (_res_options & RES_DNSRCH))
3148         ) {
3149                 bool done = 0;
3150
3151                 for (domain = _res_dnsrch; *domain && !done; domain++) {
3152
3153                         ret = res_querydomain(name, *domain, class, type,
3154                                                                   answer, anslen);
3155                         if (ret > 0)
3156                                 return ret;
3157
3158                         /*
3159                          * If no server present, give up.
3160                          * If name isn't found in this domain,
3161                          * keep trying higher domains in the search list
3162                          * (if that's enabled).
3163                          * On a NO_DATA error, keep trying, otherwise
3164                          * a wildcard entry of another type could keep us
3165                          * from finding this entry higher in the domain.
3166                          * If we get some other error (negative answer or
3167                          * server failure), then stop searching up,
3168                          * but try the input name below in case it's
3169                          * fully-qualified.
3170                          */
3171                         if (errno == ECONNREFUSED) {
3172                                 h_errno = TRY_AGAIN;
3173                                 return -1;
3174                         }
3175
3176                         switch (h_errno) {
3177                                 case NO_DATA:
3178                                         state |= __GOT_NODATA;
3179                                         /* FALLTHROUGH */
3180                                 case HOST_NOT_FOUND:
3181                                         /* keep trying */
3182                                         break;
3183                                 case TRY_AGAIN:
3184                                         if (hp->rcode == SERVFAIL) {
3185                                                 /* try next search element, if any */
3186                                                 state |= __GOT_SERVFAIL;
3187                                                 break;
3188                                         }
3189                                         /* FALLTHROUGH */
3190                                 default:
3191                                         /* anything else implies that we're done */
3192                                         done = 1;
3193                         }
3194                         /*
3195                          * if we got here for some reason other than DNSRCH,
3196                          * we only wanted one iteration of the loop, so stop.
3197                          */
3198                         if (!(_res_options & RES_DNSRCH))
3199                                 done = 1;
3200                 }
3201         }
3202
3203         /*
3204          * if we have not already tried the name "as is", do that now.
3205          * note that we do this regardless of how many dots were in the
3206          * name or whether it ends with a dot.
3207          */
3208         if (!(state & __TRIED_AS_IS)) {
3209                 ret = res_querydomain(name, NULL, class, type, answer, anslen);
3210                 if (ret > 0)
3211                         return ret;
3212         }
3213
3214         /*
3215          * if we got here, we didn't satisfy the search.
3216          * if we did an initial full query, return that query's h_errno
3217          * (note that we wouldn't be here if that query had succeeded).
3218          * else if we ever got a nodata, send that back as the reason.
3219          * else send back meaningless h_errno, that being the one from
3220          * the last DNSRCH we did.
3221          */
3222         if (saved_herrno != -1)
3223                 h_errno = saved_herrno;
3224         else if (state & __GOT_NODATA)
3225                 h_errno = NO_DATA;
3226         else if (state & __GOT_SERVFAIL)
3227                 h_errno = TRY_AGAIN;
3228         return -1;
3229 }
3230 #undef __TRAILING_DOT
3231 #undef __GOT_NODATA
3232 #undef __GOT_SERVFAIL
3233 #undef __TRIED_AS_IS
3234 /*
3235  * Perform a call on res_query on the concatenation of name and domain,
3236  * removing a trailing dot from name if domain is NULL.
3237  */
3238 int res_querydomain(const char *name, const char *domain, int class, int type,
3239                         u_char *answer, int anslen)
3240 {
3241         char nbuf[MAXDNAME];
3242         const char *longname = nbuf;
3243         size_t n, d;
3244 #ifdef DEBUG
3245         uint32_t _res_options;
3246 #endif
3247
3248         if (!name || !answer) {
3249                 h_errno = NETDB_INTERNAL;
3250                 return -1;
3251         }
3252
3253 #ifdef DEBUG
3254  again:
3255         __UCLIBC_MUTEX_LOCK(__resolv_lock);
3256         _res_options = _res.options;
3257         __UCLIBC_MUTEX_UNLOCK(__resolv_lock);
3258         if (!(_res_options & RES_INIT)) {
3259                 res_init(); /* our res_init never fails */
3260                 goto again;
3261         }
3262         if (_res_options & RES_DEBUG)
3263                 printf(";; res_querydomain(%s, %s, %d, %d)\n",
3264                            name, (domain ? domain : "<Nil>"), class, type);
3265 #endif
3266         if (domain == NULL) {
3267                 /*
3268                  * Check for trailing '.';
3269                  * copy without '.' if present.
3270                  */
3271                 n = strlen(name);
3272                 if (n + 1 > sizeof(nbuf)) {
3273                         h_errno = NO_RECOVERY;
3274                         return -1;
3275                 }
3276                 if (n > 0 && name[--n] == '.') {
3277                         strncpy(nbuf, name, n);
3278                         nbuf[n] = '\0';
3279                 } else
3280                         longname = name;
3281         } else {
3282                 n = strlen(name);
3283                 d = strlen(domain);
3284                 if (n + 1 + d + 1 > sizeof(nbuf)) {
3285                         h_errno = NO_RECOVERY;
3286                         return -1;
3287                 }
3288                 snprintf(nbuf, sizeof(nbuf), "%s.%s", name, domain);
3289         }
3290         return res_query(longname, class, type, answer, anslen);
3291 }
3292 libc_hidden_def(res_querydomain)
3293 #endif
3294
3295 /* Unimplemented: */
3296 /* res_mkquery */
3297 /* res_send */
3298 /* dn_comp */