1 /* vi: set sw=4 ts=4: */
2 /* resolv.c: DNS Resolver
4 * Copyright (C) 1998 Kenneth Albanowski <kjahds@kjahds.com>,
5 * The Silver Hammer Group, Ltd.
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.
13 * Portions Copyright (c) 1985, 1993
14 * The Regents of the University of California. All rights reserved.
16 * Redistribution and use in source and binary forms, with or without
17 * modification, are permitted provided that the following conditions
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.
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
41 * Portions Copyright (c) 1993 by Digital Equipment Corporation.
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.
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
60 * Portions Copyright (c) 1996-1999 by Internet Software Consortium.
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.
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
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
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.
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.
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.
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)
105 * 2-Feb-2002 Erik Andersen <andersen@codepoet.org>
106 * Added gethostent(), sethostent(), and endhostent()
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.
113 * 04-Jan-2003 Jay Kulpinski <jskulpin@berkshire.rr.com>
114 * Fixed __decode_dotted to count the terminating null character
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
122 * 7-Sep-2004 Erik Andersen <andersen@codepoet.org>
123 * Added gethostent_r()
125 * 2008, 2009 Denys Vlasenko <vda.linux@googlemail.com>
126 * Cleanups, fixes, readability, more cleanups and more fixes.
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
133 * Both points above are considered bugs, patches/reimplementations welcome.
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.
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 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
146 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
147 |QR| OPCODE |AA|TC|RD|RA| 0 0 0| RCODE |
148 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
150 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
152 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
154 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
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.
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
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.
191 4.1.2. Question section format
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 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
198 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
200 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
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
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]
223 14 mailbox or mail list information
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.
233 (others are historic only)
236 4.1.3. Resource record format
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 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
246 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
248 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
250 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
253 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
255 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--|
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.
271 4.1.4. Message compression
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.
277 The pointer takes the form of a two octet sequence:
278 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
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
290 - a sequence of labels ending with a pointer
293 #define __FORCE_GLIBC
294 #include <features.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>
312 #include <arpa/nameser.h>
313 #include <sys/utsname.h>
315 #include <bits/uClibc_mutex.h>
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>
325 #if defined __UCLIBC_HAS_IPV4__ && defined __UCLIBC_HAS_IPV6__
326 #define IF_HAS_BOTH(...) __VA_ARGS__
328 #define IF_HAS_BOTH(...)
331 #define MAX_RECURSE 5
332 #define MAX_ALIASES 5
334 /* 1:ip + 1:full + MAX_ALIASES:aliases + 1:NULL */
335 #define ALIAS_DIM (2 + MAX_ALIASES + 1)
341 #define DPRINTF(X,args...) fprintf(stderr, X, ##args)
343 #define DPRINTF(X,args...)
347 #define ARRAY_SIZE(v) (sizeof(v) / sizeof((v)[0]))
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.
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)
359 struct resolv_header {
361 int qr, opcode, aa, tc, rd, ra, rcode;
368 struct resolv_question {
374 struct resolv_answer {
380 const unsigned char *rdata;
387 enum etc_hosts_action {
388 GET_HOSTS_BYNAME = 0,
393 typedef union sockaddr46_t {
395 #ifdef __UCLIBC_HAS_IPV4__
396 struct sockaddr_in sa4;
398 #ifdef __UCLIBC_HAS_IPV6__
399 struct sockaddr_in6 sa6;
404 __UCLIBC_MUTEX_EXTERN(__resolv_lock);
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;
416 extern const struct sockaddr_in6 __local_nameserver attribute_hidden;
419 #define MAXLEN_searchdomain 128
422 /* function prototypes */
423 extern int __get_hosts_byname_r(const char *name,
425 struct hostent *result_buf,
428 struct hostent **result,
429 int *h_errnop) attribute_hidden;
430 extern int __get_hosts_byaddr_r(const char *addr,
433 struct hostent *result_buf,
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,
442 enum etc_hosts_action action,
443 struct hostent *result_buf,
446 struct hostent **result,
447 int *h_errnop) attribute_hidden;
448 extern int __dns_lookup(const char *name,
450 unsigned char **outpacket,
451 struct resolv_answer *a) attribute_hidden;
452 extern int __encode_dotted(const char *dotted,
454 int maxlen) attribute_hidden;
455 extern int __decode_dotted(const unsigned char *packet,
459 int dest_len) attribute_hidden;
460 extern int __encode_header(struct resolv_header *h,
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,
467 int maxlen) attribute_hidden;
468 extern int __encode_answer(struct resolv_answer *a,
470 int maxlen) attribute_hidden;
471 extern void __open_nameservers(void) attribute_hidden;
472 extern void __close_nameservers(void) attribute_hidden;
475 * Theory of operation.
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:
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.
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.
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
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
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).
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.
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.
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).
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.
561 int attribute_hidden __encode_header(struct resolv_header *h, unsigned char *dest, int maxlen)
563 if (maxlen < HFIXEDSZ)
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) |
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;
590 void attribute_hidden __decode_header(unsigned char *data,
591 struct resolv_header *h)
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];
611 /* Encode a dotted string into nameserver transport-level encoding.
612 This routine is fairly dumb, and doesn't attempt to compress
614 int attribute_hidden __encode_dotted(const char *dotted, unsigned char *dest, int maxlen)
618 while (dotted && *dotted) {
619 char *c = strchr(dotted, '.');
620 int l = c ? c - dotted : strlen(dotted);
622 /* two consecutive dots are not valid */
626 if (l >= (maxlen - used - 1))
630 memcpy(dest + used, dotted, l);
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,
667 if (offset >= packet_len)
669 b = packet[offset++];
676 if ((b & 0xc0) == 0xc0) {
677 if (offset >= packet_len)
681 /* compressed item, redirect */
682 offset = ((b & 0x3f) << 8) | packet[offset];
687 if (used + b + 1 >= dest_len)
689 if (offset + b + 1 >= packet_len)
691 memcpy(dest + used, packet + offset, b);
698 if (packet[offset] != 0)
704 /* The null byte must be counted too */
708 DPRINTF("Total decode len = %d\n", total);
717 int attribute_hidden __encode_question(const struct resolv_question *q,
723 i = __encode_dotted(q->dotted, dest, maxlen);
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;
745 int attribute_hidden __encode_answer(struct resolv_answer *a, unsigned char *dest, int maxlen)
749 i = __encode_dotted(a->dotted, dest, maxlen);
756 if (maxlen < (RRFIXEDSZ + a->rdlength))
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);
771 return i + RRFIXEDSZ + a->rdlength;
776 #ifdef CURRENTLY_UNUSED
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)
795 i = __encode_header(h, dest, maxlen);
803 for (j = 0; j < h->qdcount; j++) {
804 i = __encode_question(q[j], dest, maxlen);
812 for (j = 0; j < h->ancount; j++) {
813 i = __encode_answer(an[j], dest, maxlen);
820 for (j = 0; j < h->nscount; j++) {
821 i = __encode_answer(ns[j], dest, maxlen);
828 for (j = 0; j < h->arcount; j++) {
829 i = __encode_answer(ar[j], dest, maxlen);
844 int __decode_packet(unsigned char *data, struct resolv_header *h) attribute_hidden;
845 int __decode_packet(unsigned char *data, struct resolv_header *h)
847 __decode_header(data, h);
855 int __form_query(int id,
858 unsigned char *packet,
860 int __form_query(int id,
863 unsigned char *packet,
866 struct resolv_header h;
867 struct resolv_question q;
870 memset(&h, 0, sizeof(h));
874 q.dotted = (char *) name;
876 q.qclass = C_IN; /* CLASS_IN */
878 i = __encode_header(&h, packet, maxlen);
882 j = __encode_question(&q, packet + i, maxlen - i);
889 #endif /* CURRENTLY_UNUSED */
892 #ifdef L_opennameservers
894 # if __BYTE_ORDER == __LITTLE_ENDIAN
895 #define NAMESERVER_PORT_N (__bswap_constant_16(NAMESERVER_PORT))
897 #define NAMESERVER_PORT_N NAMESERVER_PORT
900 __UCLIBC_MUTEX_INIT(__resolv_lock, PTHREAD_MUTEX_INITIALIZER);
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,
915 const struct sockaddr_in6 __local_nameserver = {
916 .sin6_family = AF_INET6,
917 .sin6_port = NAMESERVER_PORT_N,
921 /* Helpers. Both stop on EOL, if it's '\n', it is converted to NUL first */
922 static char *skip_nospace(char *p)
924 while (*p != '\0' && !isspace(*p)) {
933 static char *skip_and_NUL_space(char *p)
935 /* NB: '\n' is not isspace! */
938 if (c == '\0' || !isspace(c))
941 if (c == '\n' || c == '#')
948 /* Must be called under __resolv_lock. */
949 void attribute_hidden __open_nameservers(void)
951 static uint8_t last_time;
953 char szBuffer[MAXLEN_searchdomain];
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 */
971 fp = fopen("/etc/resolv.conf", "r");
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");
981 while (fgets(szBuffer, sizeof(szBuffer), fp) != NULL) {
985 keyword = p = skip_and_NUL_space(szBuffer);
989 p = skip_and_NUL_space(p);
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);
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);
1009 continue; /* garbage on this line */
1010 ptr = realloc(__nameserver, (__nameservers + 1) * sizeof(__nameserver[0]));
1014 __nameserver[__nameservers++] = sa; /* struct copy */
1017 if (strcmp(keyword, "domain") == 0 || strcmp(keyword, "search") == 0) {
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 */
1026 /* terminate current word */
1027 p1 = skip_nospace(p);
1028 /* find next word (maybe) */
1029 p1 = skip_and_NUL_space(p1);
1031 ptr = realloc(__searchdomain, (__searchdomains + 1) * sizeof(__searchdomain[0]));
1034 __searchdomain = ptr;
1035 /* NB: strlen(p) <= MAXLEN_searchdomain) because szBuffer[] is smaller */
1039 DPRINTF("adding search %s\n", (char*)ptr);
1040 __searchdomain[__searchdomains++] = (char*)ptr;
1046 /* if (strcmp(keyword, "sortlist") == 0)... */
1047 /* if (strcmp(keyword, "options") == 0)... */
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]));
1058 memcpy(__nameserver, &__local_nameserver, sizeof(__local_nameserver));
1060 __nameserver = (void*) &__local_nameserver;
1063 if (__searchdomains == 0) {
1066 i = gethostname(buf, sizeof(buf) - 1);
1067 buf[sizeof(buf) - 1] = '\0';
1068 if (i == 0 && (p = strchr(buf, '.')) != NULL && p[1]) {
1072 __searchdomain = malloc(sizeof(__searchdomain[0]));
1073 if (!__searchdomain) {
1077 __searchdomain[0] = p;
1082 DPRINTF("nameservers = %d\n", __nameservers);
1091 #ifdef L_closenameservers
1093 /* Must be called under __resolv_lock. */
1094 void attribute_hidden __close_nameservers(void)
1096 if (__nameserver != (void*) &__local_nameserver)
1098 __nameserver = NULL;
1100 while (__searchdomains)
1101 free(__searchdomain[--__searchdomains]);
1102 free(__searchdomain);
1103 __searchdomain = NULL;
1104 /*__searchdomains = 0; - already is */
1112 static int __length_question(const unsigned char *data, int maxlen)
1114 const unsigned char *start;
1127 if ((b & 0xc0) == 0xc0) {
1128 /* It's a "compressed" name. */
1129 data++; /* skip lsb of redirected offset */
1134 maxlen -= (b + 1); /* account for data++ above */
1136 /* Up to here we were skipping encoded name */
1138 /* Account for QTYPE and QCLASS fields */
1141 return data - start + 2 + 2;
1144 static int __decode_answer(const unsigned char *message, /* packet */
1146 int len, /* total packet len */
1147 struct resolv_answer *a)
1152 DPRINTF("decode_answer(start): off %d, len %d\n", offset, len);
1153 i = __decode_dotted(message, offset, len, temp, sizeof(temp));
1157 message += offset + i;
1158 len -= i + RRFIXEDSZ + offset;
1160 DPRINTF("decode_answer: off %d, len %d, i %d\n", offset, len, i);
1164 /* TODO: what if strdup fails? */
1165 a->dotted = strdup(temp);
1166 a->atype = (message[0] << 8) | message[1];
1168 a->aclass = (message[0] << 8) | message[1];
1170 a->ttl = (message[0] << 24) |
1171 (message[1] << 16) | (message[2] << 8) | (message[3] << 0);
1173 a->rdlength = (message[0] << 8) | message[1];
1176 a->rdoffset = offset + i + RRFIXEDSZ;
1178 DPRINTF("i=%d,rdlength=%d\n", i, a->rdlength);
1180 if (len < a->rdlength)
1182 return i + RRFIXEDSZ + a->rdlength;
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
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.
1202 int attribute_hidden __dns_lookup(const char *name,
1204 unsigned char **outpacket,
1205 struct resolv_answer *a)
1207 /* Protected by __resolv_lock: */
1208 static int last_ns_num = 0;
1209 static uint16_t last_id = 1;
1220 struct resolv_header h;
1221 struct resolv_question q;
1222 struct resolv_answer ma;
1223 bool first_answer = 1;
1225 unsigned char *packet = malloc(PACKETSZ);
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 */
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])
1242 ends_with_dot = (name[name_len - 1] == '.');
1243 /* no strcpy! paranoia, user might change name[] under us */
1244 memcpy(lookup, name, name_len);
1246 DPRINTF("Looking up type %d answer for '%s'\n", type, name);
1247 retries_left = 0; /* for compiler */
1250 unsigned reply_timeout;
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]);
1276 /* first time? pick starting server etc */
1277 if (local_ns_num < 0) {
1279 /*TODO: implement /etc/resolv.conf's "options rotate"
1280 (a.k.a. RES_ROTATE bit in _res.options)
1282 if (_res.options & RES_ROTATE) */
1283 local_ns_num = last_ns_num;
1284 /*TODO: use _res.retry */
1285 retries_left = __nameservers * RES_DFLRETRY;
1288 if (local_ns_num >= __nameservers)
1292 /* write new values back while still under lock */
1294 last_ns_num = local_ns_num;
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);
1301 memset(packet, 0, PACKETSZ);
1302 memset(&h, 0, sizeof(h));
1308 DPRINTF("encoding header\n", h.rd);
1309 i = __encode_header(&h, packet, PACKETSZ);
1313 /* encode question */
1314 DPRINTF("lookup name: %s\n", lookup);
1317 q.qclass = C_IN; /* CLASS_IN */
1318 j = __encode_question(&q, packet+i, PACKETSZ-i);
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));
1331 /*if (errno == ENETUNREACH) { */
1332 /* routing error, presume not transient */
1333 goto try_next_server;
1335 /*For example, what transient error this can be? Can't think of any */
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);
1344 /*TODO: use _res.retrans*/
1345 reply_timeout = RES_TIMEOUT;
1349 tv.tv_sec = reply_timeout;
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;
1359 reply_timeout = RES_TIMEOUT * 1000;
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;
1369 /*TODO: better timeout accounting?*/
1370 reply_timeout -= 1000;
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.
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);
1386 memcpy(packet + 2, test_respn + 2, 30);
1390 packet_len = recv(fd, packet, PACKETSZ, MSG_DONTWAIT);
1393 if (packet_len < HFIXEDSZ) {
1395 * it's just a bogus packet from somewhere */
1399 goto try_next_server;
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) {
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);
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 */
1426 /* no more search domains to try */
1428 /* dont loop, this is "no such host" situation */
1429 h_errno = HOST_NOT_FOUND;
1432 /* Insert other non-fatal errors here, which do not warrant
1433 * switching to next nameserver */
1435 /* Strange error, assuming this nameserver is feeling bad */
1437 goto try_next_server;
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?] */
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);
1449 DPRINTF("Packet'question section "
1450 "is truncated, trying next server\n");
1451 goto try_next_server;
1454 DPRINTF("Length of question %d is %d\n", j, i);
1456 DPRINTF("Decoding answer at pos %d\n", pos);
1459 for (j = 0; j < h.ancount; j++) {
1460 i = __decode_answer(packet, pos, packet_len, &ma);
1462 DPRINTF("failed decode %d\n", i);
1463 /* If the message was truncated but we have
1464 * decoded some answers, pretend it's OK */
1467 goto try_next_server;
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)))
1478 if (a->atype != type) {
1482 a->add_count = h.ancount - j - 1;
1483 if ((a->rdlength + sizeof(struct in_addr*)) * a->add_count > a->buflen)
1489 if (ma.atype != type)
1491 if (a->rdlength != ma.rdlength) {
1493 DPRINTF("Answer address len(%u) differs from original(%u)\n",
1494 ma.rdlength, a->rdlength);
1495 goto try_next_server;
1497 memcpy(a->buf + (a->add_count * ma.rdlength), ma.rdata, ma.rdlength);
1503 DPRINTF("Answer name = |%s|\n", a->dotted);
1504 DPRINTF("Answer type = |%d|\n", a->atype);
1508 *outpacket = packet;
1515 /* Try next nameserver */
1518 } while (retries_left > 0);
1521 h_errno = NETDB_INTERNAL;
1532 #ifdef L_read_etc_hosts_r
1534 FILE * __open_etc_hosts(void)
1537 if ((fp = fopen("/etc/hosts", "r")) == NULL) {
1538 fp = fopen("/etc/config/hosts", "r");
1543 int attribute_hidden __read_etc_hosts_r(
1547 enum etc_hosts_action action,
1548 struct hostent *result_buf,
1549 char *buf, size_t buflen,
1550 struct hostent **result,
1553 struct in_addr **addr_list = NULL;
1554 struct in_addr *in = NULL;
1556 int aliases, i, ret = HOST_NOT_FOUND;
1558 *h_errnop = NETDB_INTERNAL;
1560 /* make sure pointer is aligned */
1561 i = ALIGN_BUFFER_OFFSET(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+];
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)
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__
1583 buflen -= sizeof(*in);
1585 buf += sizeof(*in6);
1586 buflen -= sizeof(*in6);
1588 if ((ssize_t)buflen < 80)
1591 fp = __open_etc_hosts();
1597 addr_list[1] = NULL;
1600 *h_errnop = HOST_NOT_FOUND;
1601 while (fgets(buf, buflen, fp)) {
1602 *strchrnul(buf, '#') = '\0';
1603 DPRINTF("Looking at: %s\n", buf);
1608 while (*cp && isspace(*cp))
1612 if (aliases < (2 + MAX_ALIASES))
1613 alias[aliases++] = cp;
1614 while (*cp && !isspace(*cp))
1617 alias[aliases] = NULL;
1620 continue; /* syntax error really */
1622 if (action == GETHOSTENT) {
1623 /* Return whatever the next entry happens to be. */
1626 if (action == GET_HOSTS_BYADDR) {
1627 if (strcmp(name, alias[0]) != 0)
1630 /* GET_HOSTS_BYNAME */
1631 for (i = 1; i < aliases; i++)
1632 if (strcasecmp(name, alias[i]) == 0)
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;
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;
1664 /* continue parsing in the hope the user has multiple
1665 * host types listed in the database like so:
1668 * If looking for an IPv6 addr, don't bail when we got the IPv4
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 */
1678 if (action != GETHOSTENT)
1686 #ifdef L_get_hosts_byname_r
1688 int attribute_hidden __get_hosts_byname_r(const char *name,
1690 struct hostent *result_buf,
1693 struct hostent **result,
1696 return __read_etc_hosts_r(NULL, name, type, GET_HOSTS_BYNAME,
1697 result_buf, buf, buflen, result, h_errnop);
1702 #ifdef L_get_hosts_byaddr_r
1704 int attribute_hidden __get_hosts_byaddr_r(const char *addr,
1707 struct hostent *result_buf,
1710 struct hostent **result,
1713 #ifndef __UCLIBC_HAS_IPV6__
1714 char ipaddr[INET_ADDRSTRLEN];
1716 char ipaddr[INET6_ADDRSTRLEN];
1720 #ifdef __UCLIBC_HAS_IPV4__
1722 if (len != sizeof(struct in_addr))
1726 #ifdef __UCLIBC_HAS_IPV6__
1728 if (len != sizeof(struct in6_addr))
1736 inet_ntop(type, addr, ipaddr, sizeof(ipaddr));
1738 return __read_etc_hosts_r(NULL, ipaddr, type, GET_HOSTS_BYADDR,
1739 result_buf, buf, buflen, result, h_errnop);
1744 #ifdef L_getnameinfo
1746 int getnameinfo(const struct sockaddr *sa,
1756 struct hostent *h = NULL;
1759 if (flags & ~(NI_NUMERICHOST|NI_NUMERICSERV|NI_NOFQDN|NI_NAMEREQD|NI_DGRAM))
1760 return EAI_BADFLAGS;
1762 if (sa == NULL || addrlen < sizeof(sa_family_t))
1766 if (ok == AF_LOCAL) /* valid */;
1767 #ifdef __UCLIBC_HAS_IPV4__
1768 else if (ok == AF_INET) {
1769 if (addrlen < sizeof(struct sockaddr_in))
1773 #ifdef __UCLIBC_HAS_IPV6__
1774 else if (ok == AF_INET6) {
1775 if (addrlen < sizeof(struct sockaddr_in6))
1783 if (host != NULL && hostlen > 0)
1784 switch (sa->sa_family) {
1786 #ifdef __UCLIBC_HAS_IPV6__
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);
1797 #ifdef __UCLIBC_HAS_IPV4__
1799 h = gethostbyaddr((const void *)
1800 &(((const struct sockaddr_in *)sa)->sin_addr),
1801 sizeof(struct in_addr), AF_INET);
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) == '.')
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';
1817 strncpy(host, h->h_name, hostlen);
1825 const char *c = NULL;
1827 if (flags & NI_NAMEREQD) {
1831 if (0) /* nothing */;
1832 #ifdef __UCLIBC_HAS_IPV6__
1833 else if (sa->sa_family == AF_INET6) {
1834 const struct sockaddr_in6 *sin6p;
1836 sin6p = (const struct sockaddr_in6 *) sa;
1837 c = inet_ntop(AF_INET6,
1838 (const void *) &sin6p->sin6_addr,
1841 /* Does scope id need to be supported? */
1843 scopeid = sin6p->sin6_scope_id;
1845 /* Buffer is >= IFNAMSIZ+1. */
1846 char scopebuf[IFNAMSIZ + 1];
1848 int ni_numericscope = 0;
1849 size_t real_hostlen = strnlen(host, hostlen);
1850 size_t scopelen = 0;
1852 scopebuf[0] = SCOPE_DELIMITER;
1854 scopeptr = &scopebuf[1];
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)
1861 scopelen = strlen(scopebuf);
1866 if (ni_numericscope)
1867 scopelen = 1 + snprintf(scopeptr,
1873 if (real_hostlen + scopelen + 1 > hostlen)
1875 memcpy(host + real_hostlen, scopebuf, scopelen + 1);
1879 #endif /* __UCLIBC_HAS_IPV6__ */
1880 #if defined __UCLIBC_HAS_IPV4__
1882 c = inet_ntop(AF_INET, (const void *)
1883 &(((const struct sockaddr_in *) sa)->sin_addr),
1896 if (!(flags & NI_NUMERICHOST)) {
1897 struct utsname utsname;
1899 if (!uname(&utsname)) {
1900 strncpy(host, utsname.nodename, hostlen);
1905 if (flags & NI_NAMEREQD) {
1910 strncpy(host, "localhost", hostlen);
1912 /* Already checked above
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)) {
1924 s = getservbyport(((const struct sockaddr_in *) sa)->sin_port,
1925 ((flags & NI_DGRAM) ? "udp" : "tcp"));
1927 strncpy(serv, s->s_name, servlen);
1931 snprintf(serv, servlen, "%d",
1932 ntohs(((const struct sockaddr_in *) sa)->sin_port));
1936 if (host && (hostlen > 0))
1937 host[hostlen-1] = 0;
1938 if (serv && (servlen > 0))
1939 serv[servlen-1] = 0;
1943 libc_hidden_def(getnameinfo)
1947 #ifdef L_gethostbyname_r
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:
1958 * $ ./gethostbyname_uclibc wer.google.com
1959 * h_name:'c13-ss-2-lb.cnet.com'
1961 * h_addrtype:2 AF_INET
1962 * alias:'wer.google.com' <===
1963 * addr: 0x4174efd8 '216.239.116.65'
1965 * $ ./gethostbyname_glibc wer.google.com
1966 * h_name:'c13-ss-2-lb.cnet.com'
1968 * h_addrtype:2 AF_INET
1969 * alias:'wer.google.com.com' <===
1970 * addr:'216.239.116.65'
1972 * When examples were run, /etc/resolv.conf contained "search com" line.
1974 int gethostbyname_r(const char *name,
1975 struct hostent *result_buf,
1978 struct hostent **result,
1981 struct in_addr **addr_list;
1984 unsigned char *packet;
1985 struct resolv_answer a;
1994 /* do /etc/hosts first */
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);
2004 switch (*h_errnop) {
2005 case HOST_NOT_FOUND:
2006 wrong_af = (i == TRY_AGAIN);
2009 case NETDB_INTERNAL:
2010 if (errno == ENOENT) {
2013 /* else fall through */
2017 __set_errno(old_errno);
2020 DPRINTF("Nothing found in /etc/hosts\n");
2022 *h_errnop = NETDB_INTERNAL;
2024 /* prepare future h_aliases[0] */
2025 i = strlen(name) + 1;
2026 if ((ssize_t)buflen <= i)
2028 memcpy(buf, name, i); /* paranoia: name might change */
2032 /* make sure pointer is aligned */
2033 i = ALIGN_BUFFER_OFFSET(buf);
2038 * struct in_addr* addr_list[NN+1];
2039 * struct in_addr* in[NN];
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)
2049 /* we store only one "alias" - the name itself */
2050 #ifdef __UCLIBC_MJN3_ONLY__
2051 #warning TODO -- generate the full list
2056 /* maybe it is already an address? */
2058 struct in_addr *in = (struct in_addr *)(buf + sizeof(addr_list[0]) * 2);
2059 if (inet_aton(name, 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;
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! */
2077 *h_errnop = HOST_NOT_FOUND;
2081 /* talk to DNS servers */
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)));
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");
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;
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 */
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);
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));
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);
2126 addr_list[i] = NULL;
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);
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;
2148 *h_errnop = HOST_NOT_FOUND;
2156 libc_hidden_def(gethostbyname_r)
2160 #ifdef L_gethostbyname2_r
2162 int gethostbyname2_r(const char *name,
2164 struct hostent *result_buf,
2167 struct hostent **result,
2170 #ifndef __UCLIBC_HAS_IPV6__
2171 return family == (AF_INET)
2172 ? gethostbyname_r(name, result_buf, buf, buflen, result, h_errnop)
2175 struct in6_addr *in;
2176 struct in6_addr **addr_list;
2177 unsigned char *packet;
2178 struct resolv_answer a;
2183 if (family == AF_INET)
2184 return gethostbyname_r(name, result_buf, buf, buflen, result, h_errnop);
2187 if (family != AF_INET6)
2193 /* do /etc/hosts first */
2195 int old_errno = errno; /* Save the old errno and reset errno */
2196 __set_errno(0); /* to check for missing /etc/hosts. */
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);
2204 switch (*h_errnop) {
2205 case HOST_NOT_FOUND:
2206 wrong_af = (i == TRY_AGAIN);
2209 case NETDB_INTERNAL:
2210 if (errno == ENOENT) {
2213 /* else fall through */
2217 __set_errno(old_errno);
2219 DPRINTF("Nothing found in /etc/hosts\n");
2221 *h_errnop = NETDB_INTERNAL;
2223 /* make sure pointer is aligned */
2224 i = ALIGN_BUFFER_OFFSET(buf);
2228 * struct in6_addr* in;
2229 * struct in6_addr* addr_list[2];
2230 * char scratch_buf[256];
2232 in = (struct in6_addr*)buf;
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)
2241 addr_list[1] = NULL;
2242 strncpy(buf, name, buflen);
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;
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! */
2261 *h_errnop = HOST_NOT_FOUND;
2265 /* talk to DNS servers */
2266 /* TODO: why it's so different from gethostbyname_r (IPv4 case)? */
2267 memset(&a, '\0', sizeof(a));
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;
2277 strncpy(buf, a.dotted, buflen);
2280 if (a.atype != T_CNAME)
2283 DPRINTF("Got a CNAME in gethostbyname()\n");
2284 if (++nest > MAX_RECURSE) {
2285 *h_errnop = NO_RECOVERY;
2288 i = __decode_dotted(packet, a.rdoffset, packet_len, buf, buflen);
2291 *h_errnop = NO_RECOVERY;
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 = ??? */
2303 *result = result_buf;
2304 *h_errnop = NETDB_SUCCESS;
2305 return NETDB_SUCCESS;
2308 *h_errnop = HOST_NOT_FOUND;
2311 #endif /* __UCLIBC_HAS_IPV6__ */
2313 libc_hidden_def(gethostbyname2_r)
2317 #ifdef L_gethostbyaddr_r
2319 int gethostbyaddr_r(const void *addr, socklen_t addrlen,
2321 struct hostent *result_buf,
2322 char *buf, size_t buflen,
2323 struct hostent **result,
2328 struct in_addr **addr_list;
2330 unsigned char *packet;
2331 struct resolv_answer a;
2341 #ifdef __UCLIBC_HAS_IPV4__
2343 if (addrlen != sizeof(struct in_addr))
2347 #ifdef __UCLIBC_HAS_IPV6__
2349 if (addrlen != sizeof(struct in6_addr))
2357 /* do /etc/hosts first */
2358 i = __get_hosts_byaddr_r(addr, addrlen, type, result_buf,
2359 buf, buflen, result, h_errnop);
2362 switch (*h_errnop) {
2363 case HOST_NOT_FOUND:
2370 *h_errnop = NETDB_INTERNAL;
2372 /* make sure pointer is aligned */
2373 i = ALIGN_BUFFER_OFFSET(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+];
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__
2392 buflen -= sizeof(*in);
2394 buf += sizeof(*in6);
2395 buflen -= sizeof(*in6);
2397 if ((ssize_t)buflen < 256)
2402 addr_list[1] = NULL;
2403 memcpy(&in, addr, addrlen);
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]);
2413 #ifdef __UCLIBC_HAS_IPV6__
2416 unsigned char *tp = (unsigned char *)addr + addrlen - 1;
2418 dst += sprintf(dst, "%x.%x.", tp[i] & 0xf, tp[i] >> 4);
2420 } while (tp >= (unsigned char *)addr);
2421 strcpy(dst, "ip6.arpa");
2425 memset(&a, '\0', sizeof(a));
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;
2434 strncpy(buf, a.dotted, buflen);
2436 if (a.atype != T_CNAME)
2439 DPRINTF("Got a CNAME in gethostbyaddr()\n");
2440 if (++nest > MAX_RECURSE) {
2441 *h_errnop = NO_RECOVERY;
2444 /* Decode CNAME into buf, feed it to __dns_lookup() again */
2445 i = __decode_dotted(packet, a.rdoffset, packet_len, buf, buflen);
2448 *h_errnop = NO_RECOVERY;
2453 if (a.atype == T_PTR) { /* ADDRESS */
2454 i = __decode_dotted(packet, a.rdoffset, packet_len, buf, buflen);
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;
2467 *h_errnop = NO_ADDRESS;
2471 libc_hidden_def(gethostbyaddr_r)
2475 #ifdef L_gethostent_r
2477 __UCLIBC_MUTEX_STATIC(mylock, PTHREAD_MUTEX_INITIALIZER);
2479 static smallint __stay_open;
2480 static FILE * __gethostent_fp;
2482 void endhostent(void)
2484 __UCLIBC_MUTEX_LOCK(mylock);
2486 if (__gethostent_fp) {
2487 fclose(__gethostent_fp);
2488 __gethostent_fp = NULL;
2490 __UCLIBC_MUTEX_UNLOCK(mylock);
2493 void sethostent(int stay_open)
2495 __UCLIBC_MUTEX_LOCK(mylock);
2496 __stay_open = (stay_open != 0);
2497 __UCLIBC_MUTEX_UNLOCK(mylock);
2500 int gethostent_r(struct hostent *result_buf, char *buf, size_t buflen,
2501 struct hostent **result, int *h_errnop)
2505 __UCLIBC_MUTEX_LOCK(mylock);
2506 if (__gethostent_fp == NULL) {
2507 __gethostent_fp = __open_etc_hosts();
2508 if (__gethostent_fp == NULL) {
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;
2522 __UCLIBC_MUTEX_UNLOCK(mylock);
2525 libc_hidden_def(gethostent_r)
2531 struct hostent *gethostent(void)
2533 static struct hostent h;
2535 #ifndef __UCLIBC_HAS_IPV6__
2536 sizeof(struct in_addr) + sizeof(struct in_addr *) * 2 +
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;
2544 gethostent_r(&h, buf, sizeof(buf), &host, &h_errno);
2550 #ifdef L_gethostbyname2
2552 struct hostent *gethostbyname2(const char *name, int family)
2554 #ifndef __UCLIBC_HAS_IPV6__
2555 return family == AF_INET ? gethostbyname(name) : (struct hostent*)NULL;
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 */];
2563 gethostbyname2_r(name, family, &h, buf, sizeof(buf), &hp, &h_errno);
2567 libc_hidden_def(gethostbyname2)
2571 #ifdef L_gethostbyname
2573 struct hostent *gethostbyname(const char *name)
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 */];
2582 gethostbyname_r(name, &h, buf, sizeof(buf), &hp, &h_errno);
2585 return gethostbyname2(name, AF_INET);
2588 libc_hidden_def(gethostbyname)
2592 #ifdef L_gethostbyaddr
2594 struct hostent *gethostbyaddr(const void *addr, socklen_t len, int type)
2596 static struct hostent h;
2598 #ifndef __UCLIBC_HAS_IPV6__
2599 sizeof(struct in_addr) + sizeof(struct in_addr *)*2 +
2601 sizeof(struct in6_addr) + sizeof(struct in6_addr *)*2 +
2602 #endif /* __UCLIBC_HAS_IPV6__ */
2603 sizeof(char *)*ALIAS_DIM + 384 /*namebuffer*/ + 32 /* margin */];
2606 gethostbyaddr_r(addr, len, type, &h, buf, sizeof(buf), &hp, &h_errno);
2609 libc_hidden_def(gethostbyaddr)
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.
2622 int dn_expand(const u_char *msg, const u_char *eom, const u_char *src,
2623 char *dst, int dstsiz)
2625 int n = ns_name_uncompress(msg, eom, src, dst, (size_t)dstsiz);
2627 if (n > 0 && dst[0] == '.')
2631 #endif /* L_res_comp */
2636 /* Thinking in noninternationalized USASCII (per the DNS spec),
2637 * is this character visible and not a space when printed ?
2639 static int printable(int ch)
2641 return (ch > 0x20 && ch < 0x7f);
2643 /* Thinking in noninternationalized USASCII (per the DNS spec),
2644 * is this characted special ("in need of quoting") ?
2646 static int special(int 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: /* '$' */
2663 * ns_name_uncompress(msg, eom, src, dst, dstsiz)
2664 * Expand compressed domain name to presentation format.
2666 * Number of bytes read out of `src', or -1 (with errno set).
2668 * Root domain returns as "." not "".
2670 int ns_name_uncompress(const u_char *msg, const u_char *eom,
2671 const u_char *src, char *dst, size_t dstsiz)
2673 u_char tmp[NS_MAXCDNAME];
2676 n = ns_name_unpack(msg, eom, src, tmp, sizeof tmp);
2679 if (ns_name_ntop(tmp, dst, dstsiz) == -1)
2683 libc_hidden_def(ns_name_uncompress)
2686 * ns_name_ntop(src, dst, dstsiz)
2687 * Convert an encoded domain name to printable ascii as per RFC1035.
2689 * Number of bytes written to buffer, or -1 (with errno set)
2691 * The root is returned as "."
2692 * All other domains are returned in non absolute form
2694 int ns_name_ntop(const u_char *src, char *dst, size_t dstsiz)
2696 static const char digits[] = "0123456789";
2707 while ((n = *cp++) != 0) {
2708 if ((n & NS_CMPRSFLGS) != 0) {
2709 /* Some kind of compression pointer. */
2710 __set_errno(EMSGSIZE);
2715 __set_errno(EMSGSIZE);
2720 if (dn + n >= eom) {
2721 __set_errno(EMSGSIZE);
2724 for (; n > 0; n--) {
2727 if (dn + 1 >= eom) {
2728 __set_errno(EMSGSIZE);
2733 } else if (!printable(c)) {
2734 if (dn + 3 >= eom) {
2735 __set_errno(EMSGSIZE);
2739 *dn++ = digits[c / 100];
2740 *dn++ = digits[(c % 100) / 10];
2741 *dn++ = digits[c % 10];
2744 __set_errno(EMSGSIZE);
2753 __set_errno(EMSGSIZE);
2759 __set_errno(EMSGSIZE);
2765 libc_hidden_def(ns_name_ntop)
2768 * ns_name_unpack(msg, eom, src, dst, dstsiz)
2769 * Unpack a domain name from a message, source may be compressed.
2771 * -1 if it fails, or consumed octets if it succeeds.
2773 int ns_name_unpack(const u_char *msg, const u_char *eom, const u_char *src,
2774 u_char *dst, size_t dstsiz)
2776 const u_char *srcp, *dstlim;
2778 int n, len, checked;
2784 dstlim = dst + dstsiz;
2785 if (srcp < msg || srcp >= eom) {
2786 __set_errno(EMSGSIZE);
2789 /* Fetch next label in domain name. */
2790 while ((n = *srcp++) != 0) {
2791 /* Check for indirection. */
2792 switch (n & NS_CMPRSFLGS) {
2795 if (dstp + n + 1 >= dstlim || srcp + n >= eom) {
2796 __set_errno(EMSGSIZE);
2801 memcpy(dstp, srcp, n);
2808 __set_errno(EMSGSIZE);
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);
2820 * Check for loops in the compressed name;
2821 * if we've looked at the whole message,
2822 * there must be a loop.
2824 if (checked >= eom - msg) {
2825 __set_errno(EMSGSIZE);
2831 __set_errno(EMSGSIZE);
2832 return -1; /* flag error */
2840 libc_hidden_def(ns_name_unpack)
2841 #endif /* L_ns_name */
2846 /* Will be called under __resolv_lock. */
2847 static void res_sync_func(void)
2849 struct __res_state *rp = &(_res);
2852 /* If we didn't get malloc failure earlier... */
2853 if (__nameserver != (void*) &__local_nameserver) {
2855 * if (__nameservers < rp->nscount) - try to grow __nameserver[]?
2857 #ifdef __UCLIBC_HAS_IPV6__
2858 if (__nameservers > rp->_u._ext.nscount)
2859 __nameservers = rp->_u._ext.nscount;
2862 __nameserver[n].sa6 = *rp->_u._ext.nsaddrs[n]; /* struct copy */
2863 #else /* IPv4 only */
2864 if (__nameservers > rp->nscount)
2865 __nameservers = rp->nscount;
2868 __nameserver[n].sa4 = rp->nsaddr_list[n]; /* struct copy */
2871 /* Extend and comment what program is known
2872 * to use which _res.XXX member(s).
2874 __resolv_opts = rp->options;
2879 /* Our res_init never fails (always returns 0) */
2882 struct __res_state *rp = &(_res);
2885 #ifdef __UCLIBC_HAS_IPV6__
2889 __UCLIBC_MUTEX_LOCK(__resolv_lock);
2890 __close_nameservers();
2891 __open_nameservers();
2893 __res_sync = res_sync_func;
2895 memset(rp, 0, sizeof(*rp));
2896 rp->options = RES_INIT;
2897 #ifdef __UCLIBC_HAS_COMPAT_RES_STATE__
2898 rp->retrans = RES_TIMEOUT;
2900 /*TODO: pulls in largish static buffers... use simpler one? */
2904 #ifdef __UCLIBC_HAS_EXTRA_COMPAT_RES_STATE__
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];
2914 /* copy nameservers' addresses */
2916 #ifdef __UCLIBC_HAS_IPV4__
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];
2929 #ifdef __UCLIBC_HAS_IPV6__
2930 if (__nameserver[i].sa.sa_family == AF_INET6
2931 && m < ARRAY_SIZE(rp->_u._ext.nsaddrs)
2933 struct sockaddr_in6 *sa6 = malloc(sizeof(sa6));
2935 *sa6 = __nameserver[i].sa6; /* struct copy */
2936 rp->_u._ext.nsaddrs[m] = sa6;
2944 #ifdef __UCLIBC_HAS_IPV6__
2945 rp->_u._ext.nscount = m;
2948 #else /* IPv6 only */
2949 while (m < ARRAY_SIZE(rp->_u._ext.nsaddrs) && i < __nameservers) {
2950 struct sockaddr_in6 *sa6 = malloc(sizeof(sa6));
2952 *sa6 = __nameserver[i].sa6; /* struct copy */
2953 rp->_u._ext.nsaddrs[m] = sa6;
2958 rp->_u._ext.nscount = m;
2961 __UCLIBC_MUTEX_UNLOCK(__resolv_lock);
2964 libc_hidden_def(res_init)
2966 #ifdef __UCLIBC_HAS_BSD_RES_CLOSE__
2967 void res_close(void)
2969 __UCLIBC_MUTEX_LOCK(__resolv_lock);
2970 __close_nameservers();
2972 #ifdef __UCLIBC_HAS_IPV6__
2974 char *p1 = (char*) &(_res.nsaddr_list[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))
2984 memset(&_res, 0, sizeof(_res));
2985 __UCLIBC_MUTEX_UNLOCK(__resolv_lock);
2989 /* This needs to be after the use of _res in res_init, above. */
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;
3002 # if defined __UCLIBC_HAS_TLS__
3004 __thread struct __res_state *__resp = &_res;
3006 * FIXME: Add usage of hidden attribute for this when used in the shared
3007 * library. It currently crashes the linker when doing section
3010 extern __thread struct __res_state *__libc_resp
3011 __attribute__ ((alias ("__resp")));
3014 struct __res_state *__resp = &_res;
3018 #endif /* L_res_init */
3021 # if defined __UCLIBC_HAS_TLS__
3022 struct __res_state *
3029 extern struct __res_state _res;
3031 /* When threaded, _res may be a per-thread variable. */
3032 struct __res_state *
3045 int res_query(const char *dname, int class, int type,
3046 unsigned char *answer, int anslen)
3049 unsigned char *packet = NULL;
3050 struct resolv_answer a;
3052 if (!dname || class != 1 /* CLASS_IN */) {
3053 h_errno = NO_RECOVERY;
3057 memset(&a, '\0', sizeof(a));
3058 i = __dns_lookup(dname, type, &packet, &a);
3061 if (!h_errno) /* TODO: can this ever happen? */
3062 h_errno = TRY_AGAIN;
3068 if (a.atype == type) { /* CNAME */
3071 memcpy(answer, packet, i);
3076 libc_hidden_def(res_query)
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.
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,
3093 HEADER *hp = (HEADER *)(void *)answer;
3096 int ret, saved_herrno;
3097 uint32_t _res_options;
3098 unsigned _res_ndots;
3101 if (!name || !answer) {
3102 h_errno = NETDB_INTERNAL;
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 */
3119 h_errno = HOST_NOT_FOUND; /* default, if we never query */
3121 for (cp = name; *cp; cp++)
3122 dots += (*cp == '.');
3124 if (cp > name && *--cp == '.')
3125 state |= __TRAILING_DOT;
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.
3132 if (dots >= _res_ndots) {
3133 ret = res_querydomain(name, NULL, class, type, answer, anslen);
3136 saved_herrno = h_errno;
3137 state |= __TRIED_AS_IS;
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.
3146 if ((!dots && (_res_options & RES_DEFNAMES))
3147 || (dots && !(state & __TRAILING_DOT) && (_res_options & RES_DNSRCH))
3151 for (domain = _res_dnsrch; *domain && !done; domain++) {
3153 ret = res_querydomain(name, *domain, class, type,
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
3171 if (errno == ECONNREFUSED) {
3172 h_errno = TRY_AGAIN;
3178 state |= __GOT_NODATA;
3180 case HOST_NOT_FOUND:
3184 if (hp->rcode == SERVFAIL) {
3185 /* try next search element, if any */
3186 state |= __GOT_SERVFAIL;
3191 /* anything else implies that we're done */
3195 * if we got here for some reason other than DNSRCH,
3196 * we only wanted one iteration of the loop, so stop.
3198 if (!(_res_options & RES_DNSRCH))
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.
3208 if (!(state & __TRIED_AS_IS)) {
3209 ret = res_querydomain(name, NULL, class, type, answer, anslen);
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.
3222 if (saved_herrno != -1)
3223 h_errno = saved_herrno;
3224 else if (state & __GOT_NODATA)
3226 else if (state & __GOT_SERVFAIL)
3227 h_errno = TRY_AGAIN;
3230 #undef __TRAILING_DOT
3232 #undef __GOT_SERVFAIL
3233 #undef __TRIED_AS_IS
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.
3238 int res_querydomain(const char *name, const char *domain, int class, int type,
3239 u_char *answer, int anslen)
3241 char nbuf[MAXDNAME];
3242 const char *longname = nbuf;
3245 uint32_t _res_options;
3248 if (!name || !answer) {
3249 h_errno = NETDB_INTERNAL;
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 */
3262 if (_res_options & RES_DEBUG)
3263 printf(";; res_querydomain(%s, %s, %d, %d)\n",
3264 name, (domain ? domain : "<Nil>"), class, type);
3266 if (domain == NULL) {
3268 * Check for trailing '.';
3269 * copy without '.' if present.
3272 if (n + 1 > sizeof(nbuf)) {
3273 h_errno = NO_RECOVERY;
3276 if (n > 0 && name[--n] == '.') {
3277 strncpy(nbuf, name, n);
3284 if (n + 1 + d + 1 > sizeof(nbuf)) {
3285 h_errno = NO_RECOVERY;
3288 snprintf(nbuf, sizeof(nbuf), "%s.%s", name, domain);
3290 return res_query(longname, class, type, answer, anslen);
3292 libc_hidden_def(res_querydomain)
3295 /* Unimplemented: */