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.
128 * March 2010 Bernhard Reutner-Fischer
129 * Switch to common config parser
132 * The whole resolver code has several (severe) problems:
133 * - it doesn't even build without IPv4, i.e. !UCLIBC_HAS_IPV4 but only IPv6
134 * - it is way too big
136 * Both points above are considered bugs, patches/reimplementations welcome.
140 Whenever an octet represents a numeric quantity, the left most bit
141 in the diagram is the high order or most significant bit.
142 That is, the bit labeled 0 is the most significant bit.
145 4.1.1. Header section format
146 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
147 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
149 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
150 |QR| OPCODE |AA|TC|RD|RA| 0 0 0| RCODE |
151 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
153 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
155 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
157 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
159 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
160 ID 16 bit random identifier assigned by querying peer.
161 Used to match query/response.
162 QR message is a query (0), or a response (1).
163 OPCODE 0 standard query (QUERY)
164 1 inverse query (IQUERY)
165 2 server status request (STATUS)
166 AA Authoritative Answer - this bit is valid in responses.
167 Responding name server is an authority for the domain name
168 in question section. Answer section may have multiple owner names
169 because of aliases. The AA bit corresponds to the name which matches
170 the query name, or the first owner name in the answer section.
171 TC TrunCation - this message was truncated.
172 RD Recursion Desired - this bit may be set in a query and
173 is copied into the response. If RD is set, it directs
174 the name server to pursue the query recursively.
175 Recursive query support is optional.
176 RA Recursion Available - this be is set or cleared in a
177 response, and denotes whether recursive query support is
178 available in the name server.
182 2 Server failure - server was unable to process the query
183 due to a problem with the name server.
184 3 Name Error - meaningful only for responses from
185 an authoritative name server. The referenced domain name
189 QDCOUNT number of entries in the question section.
190 ANCOUNT number of records in the answer section.
191 NSCOUNT number of records in the authority records section.
192 ARCOUNT number of records in the additional records section.
194 4.1.2. Question section format
196 The section contains QDCOUNT (usually 1) entries, each of this format:
197 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
198 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
201 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
203 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
205 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
206 QNAME a domain name represented as a sequence of labels, where
207 each label consists of a length octet followed by that
208 number of octets. The domain name terminates with the
209 zero length octet for the null label of the root. Note
210 that this field may be an odd number of octets; no
212 QTYPE a two octet type of the query.
213 1 a host address [REQ_A const]
214 2 an authoritative name server
215 3 a mail destination (Obsolete - use MX)
216 4 a mail forwarder (Obsolete - use MX)
217 5 the canonical name for an alias
218 6 marks the start of a zone of authority
219 7 a mailbox domain name (EXPERIMENTAL)
220 8 a mail group member (EXPERIMENTAL)
221 9 a mail rename domain name (EXPERIMENTAL)
222 10 a null RR (EXPERIMENTAL)
223 11 a well known service description
224 12 a domain name pointer [REQ_PTR const]
226 14 mailbox or mail list information
230 252 a request for a transfer of an entire zone
231 253 a request for mailbox-related records (MB, MG or MR)
232 254 a request for mail agent RRs (Obsolete - see MX)
233 255 a request for all records
234 QCLASS a two octet code that specifies the class of the query.
236 (others are historic only)
239 4.1.3. Resource record format
241 The answer, authority, and additional sections all share the same format:
242 a variable number of resource records, where the number of records
243 is specified in the corresponding count field in the header.
244 Each resource record has this format:
245 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
246 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
249 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
251 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
253 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
256 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
258 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--|
261 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
262 NAME a domain name to which this resource record pertains.
263 TYPE two octets containing one of the RR type codes. This
264 field specifies the meaning of the data in the RDATA field.
265 CLASS two octets which specify the class of the data in the RDATA field.
266 TTL a 32 bit unsigned integer that specifies the time interval
267 (in seconds) that the record may be cached.
268 RDLENGTH a 16 bit integer, length in octets of the RDATA field.
269 RDATA a variable length string of octets that describes the resource.
270 The format of this information varies according to the TYPE
271 and CLASS of the resource record.
272 If the TYPE is A and the CLASS is IN, it's a 4 octet IP address.
274 4.1.4. Message compression
276 In order to reduce the size of messages, domain names can be compressed.
277 An entire domain name or a list of labels at the end of a domain name
278 is replaced with a pointer to a prior occurance of the same name.
280 The pointer takes the form of a two octet sequence:
281 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
283 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
284 The first two bits are ones. This allows a pointer to be distinguished
285 from a label, since the label must begin with two zero bits because
286 labels are restricted to 63 octets or less. The OFFSET field specifies
287 an offset from the start of the message (i.e., the first octet
288 of the ID field in the domain header).
289 A zero offset specifies the first byte of the ID field, etc.
290 Domain name in a message can be represented as either:
291 - a sequence of labels ending in a zero octet
293 - a sequence of labels ending with a pointer
296 #define __FORCE_GLIBC
297 #include <features.h>
300 #include <stdio_ext.h>
303 #include <sys/poll.h>
304 #include <sys/socket.h>
305 #include <sys/types.h>
306 #include <sys/time.h>
307 #include <netinet/in.h>
308 #include <arpa/inet.h>
316 #include <arpa/nameser.h>
317 #include <sys/utsname.h>
319 #include <sys/stat.h>
320 #include <bits/uClibc_mutex.h>
321 #include "internal/parse_config.h"
323 /* poll() is not supported in kernel <= 2.0, therefore if __NR_poll is
324 * not available, we assume an old Linux kernel is in use and we will
325 * use select() instead. */
326 #include <sys/syscall.h>
331 #if defined __UCLIBC_HAS_IPV4__ && defined __UCLIBC_HAS_IPV6__
332 #define IF_HAS_BOTH(...) __VA_ARGS__
334 #define IF_HAS_BOTH(...)
338 #define MAX_RECURSE 5
339 #define MAXALIASES (4)
340 #define BUFSZ (80) /* one line */
342 #define NS_TYPE_ELT 0x40 /*%< EDNS0 extended label type */
343 #define DNS_LABELTYPE_BITSTRING 0x41
349 #define DPRINTF(X,args...) fprintf(stderr, X, ##args)
351 #define DPRINTF(X,args...)
354 /* Make sure the incoming char * buffer is aligned enough to handle our random
355 * structures. This define is the same as we use for malloc alignment (which
356 * has same requirements). The offset is the number of bytes we need to adjust
357 * in order to attain desired alignment.
359 #define ALIGN_ATTR __alignof__(double __attribute_aligned__ (sizeof(size_t)))
360 #define ALIGN_BUFFER_OFFSET(buf) ((ALIGN_ATTR - ((size_t)buf % ALIGN_ATTR)) % ALIGN_ATTR)
364 struct resolv_header {
366 int qr, opcode, aa, tc, rd, ra, rcode;
373 struct resolv_question {
379 struct resolv_answer {
385 const unsigned char *rdata;
392 enum etc_hosts_action {
393 GET_HOSTS_BYNAME = 0,
398 typedef union sockaddr46_t {
400 #ifdef __UCLIBC_HAS_IPV4__
401 struct sockaddr_in sa4;
403 #ifdef __UCLIBC_HAS_IPV6__
404 struct sockaddr_in6 sa6;
409 __UCLIBC_MUTEX_EXTERN(__resolv_lock);
411 /* Protected by __resolv_lock */
412 extern void (*__res_sync)(void) attribute_hidden;
413 /*extern uint32_t __resolv_opts attribute_hidden; */
414 extern uint8_t __resolv_timeout attribute_hidden;
415 extern uint8_t __resolv_attempts attribute_hidden;
416 extern unsigned __nameservers attribute_hidden;
417 extern unsigned __searchdomains attribute_hidden;
418 extern sockaddr46_t *__nameserver attribute_hidden;
419 extern char **__searchdomain attribute_hidden;
420 #ifdef __UCLIBC_HAS_IPV4__
421 extern const struct sockaddr_in __local_nameserver attribute_hidden;
423 extern const struct sockaddr_in6 __local_nameserver attribute_hidden;
426 #define MAXLEN_searchdomain 128
429 /* prototypes for internal functions */
430 extern void endhostent_unlocked(void) attribute_hidden;
431 extern int __get_hosts_byname_r(const char *name,
433 struct hostent *result_buf,
436 struct hostent **result,
437 int *h_errnop) attribute_hidden;
438 extern int __get_hosts_byaddr_r(const char *addr,
441 struct hostent *result_buf,
444 struct hostent **result,
445 int *h_errnop) attribute_hidden;
446 extern parser_t *__open_etc_hosts(void) attribute_hidden;
447 extern int __read_etc_hosts_r(parser_t *parser,
450 enum etc_hosts_action action,
451 struct hostent *result_buf,
454 struct hostent **result,
455 int *h_errnop) attribute_hidden;
456 extern int __dns_lookup(const char *name,
458 unsigned char **outpacket,
459 struct resolv_answer *a) attribute_hidden;
460 extern int __encode_dotted(const char *dotted,
462 int maxlen) attribute_hidden;
463 extern int __decode_dotted(const unsigned char *packet,
467 int dest_len) attribute_hidden;
468 extern int __encode_header(struct resolv_header *h,
470 int maxlen) attribute_hidden;
471 extern void __decode_header(unsigned char *data,
472 struct resolv_header *h) attribute_hidden;
473 extern int __encode_question(const struct resolv_question *q,
475 int maxlen) attribute_hidden;
476 extern int __encode_answer(struct resolv_answer *a,
478 int maxlen) attribute_hidden;
479 extern void __open_nameservers(void) attribute_hidden;
480 extern void __close_nameservers(void) attribute_hidden;
483 * Theory of operation.
485 * gethostbyname, getaddrinfo and friends end up here, and they sometimes
486 * need to talk to DNS servers. In order to do this, we need to read /etc/resolv.conf
487 * and determine servers' addresses and the like. resolv.conf format:
489 * nameserver <IP[v6]>
490 * Address of DNS server. Cumulative.
491 * If not specified, assumed to be on localhost.
492 * search <domain1>[ <domain2>]...
493 * Append these domains to unqualified names.
494 * See ndots:n option.
495 * $LOCALDOMAIN (space-separated list) overrides this.
497 * Effectively same as "search" with one domain.
498 * If no "domain" line is present, the domain is determined
499 * from the local host name returned by gethostname();
500 * the domain part is taken to be everything after the first dot.
501 * If there are no dots, there will be no "domain".
502 * The domain and search keywords are mutually exclusive.
503 * If more than one instance of these keywords is present,
504 * the last instance wins.
505 * sortlist 130.155.160.0[/255.255.240.0] 130.155.0.0
506 * Allows addresses returned by gethostbyname to be sorted.
508 * options option[ option]...
509 * (so far we support timeout:n and attempts:n)
510 * $RES_OPTIONS (space-separated list) is to be added to "options"
511 * debug sets RES_DEBUG in _res.options
512 * ndots:n how many dots there should be so that name will be tried
513 * first as an absolute name before any search list elements
514 * are appended to it. Default 1
515 * timeout:n how long to wait for response. Default 5
516 * (sun seems to have retrans:n synonym)
517 * attempts:n number of rounds to do before giving up and returning
518 * an error. Default 2
519 * (sun seems to have retry:n synonym)
520 * rotate sets RES_ROTATE in _res.options, round robin
521 * selection of nameservers. Otherwise try
522 * the first listed server first every time
524 * sets RES_NOCHECKNAME in _res.options, which disables
525 * checking of incoming host names for invalid characters
526 * such as underscore (_), non-ASCII, or control characters
527 * inet6 sets RES_USE_INET6 in _res.options. Try a AAAA query
528 * before an A query inside the gethostbyname(), and map
529 * IPv4 responses in IPv6 "tunnelled form" if no AAAA records
530 * are found but an A record set exists
531 * no_tld_query (FreeBSDism?)
532 * do not attempt to resolve names without dots
534 * We will read and analyze /etc/resolv.conf as needed before
535 * we do a DNS request. This happens in __dns_lookup.
536 * It is reread if its mtime is changed.
538 * BSD has res_init routine which is used to initialize resolver state
539 * which is held in global structure _res.
540 * Generally, programs call res_init, then fiddle with _res.XXX
541 * (_res.options and _res.nscount, _res.nsaddr_list[N]
542 * are popular targets of fiddling) and expect subsequent calls
543 * to gethostbyname, getaddrinfo, etc to use modified information.
545 * However, historical _res structure is quite awkward.
546 * Using it for storing /etc/resolv.conf info is not desirable,
547 * and __dns_lookup does not use it.
549 * We would like to avoid using it unless absolutely necessary.
550 * If user doesn't use res_init, we should arrange it so that
551 * _res structure doesn't even *get linked in* into user's application
552 * (imagine static uclibc build here).
554 * The solution is a __res_sync function pointer, which is normally NULL.
555 * But if res_init is called, it gets set and any subsequent gethostbyname
556 * et al "syncronizes" our internal structures with potentially
557 * modified _res.XXX stuff by calling __res_sync.
558 * The trick here is that if res_init is not used and not linked in,
559 * gethostbyname itself won't reference _res and _res won't be linked in
560 * either. Other possible methods like
561 * if (__res_sync_just_an_int_flag)
562 * __sync_me_with_res()
563 * would pull in __sync_me_with_res, which pulls in _res. Bad.
569 int attribute_hidden __encode_header(struct resolv_header *h, unsigned char *dest, int maxlen)
571 if (maxlen < HFIXEDSZ)
574 dest[0] = (h->id & 0xff00) >> 8;
575 dest[1] = (h->id & 0x00ff) >> 0;
576 dest[2] = (h->qr ? 0x80 : 0) |
577 ((h->opcode & 0x0f) << 3) |
581 dest[3] = (h->ra ? 0x80 : 0) | (h->rcode & 0x0f);
582 dest[4] = (h->qdcount & 0xff00) >> 8;
583 dest[5] = (h->qdcount & 0x00ff) >> 0;
584 dest[6] = (h->ancount & 0xff00) >> 8;
585 dest[7] = (h->ancount & 0x00ff) >> 0;
586 dest[8] = (h->nscount & 0xff00) >> 8;
587 dest[9] = (h->nscount & 0x00ff) >> 0;
588 dest[10] = (h->arcount & 0xff00) >> 8;
589 dest[11] = (h->arcount & 0x00ff) >> 0;
593 #endif /* L_encodeh */
598 void attribute_hidden __decode_header(unsigned char *data,
599 struct resolv_header *h)
601 h->id = (data[0] << 8) | data[1];
602 h->qr = (data[2] & 0x80) ? 1 : 0;
603 h->opcode = (data[2] >> 3) & 0x0f;
604 h->aa = (data[2] & 0x04) ? 1 : 0;
605 h->tc = (data[2] & 0x02) ? 1 : 0;
606 h->rd = (data[2] & 0x01) ? 1 : 0;
607 h->ra = (data[3] & 0x80) ? 1 : 0;
608 h->rcode = data[3] & 0x0f;
609 h->qdcount = (data[4] << 8) | data[5];
610 h->ancount = (data[6] << 8) | data[7];
611 h->nscount = (data[8] << 8) | data[9];
612 h->arcount = (data[10] << 8) | data[11];
614 #endif /* L_decodeh */
619 /* Encode a dotted string into nameserver transport-level encoding.
620 This routine is fairly dumb, and doesn't attempt to compress
622 int attribute_hidden __encode_dotted(const char *dotted, unsigned char *dest, int maxlen)
626 while (dotted && *dotted) {
627 char *c = strchr(dotted, '.');
628 int l = c ? c - dotted : strlen(dotted);
630 /* two consecutive dots are not valid */
634 if (l >= (maxlen - used - 1))
638 memcpy(dest + used, dotted, l);
653 #endif /* L_encoded */
658 /* Decode a dotted string from nameserver transport-level encoding.
659 This routine understands compressed data. */
660 int attribute_hidden __decode_dotted(const unsigned char *packet,
675 if (offset >= packet_len)
677 b = packet[offset++];
684 if ((b & 0xc0) == 0xc0) {
685 if (offset >= packet_len)
689 /* compressed item, redirect */
690 offset = ((b & 0x3f) << 8) | packet[offset];
695 if (used + b + 1 >= dest_len)
697 if (offset + b >= packet_len)
699 memcpy(dest + used, packet + offset, b);
706 if (packet[offset] != 0)
712 /* The null byte must be counted too */
716 DPRINTF("Total decode len = %d\n", total);
720 #endif /* L_decoded */
725 int attribute_hidden __encode_question(const struct resolv_question *q,
731 i = __encode_dotted(q->dotted, dest, maxlen);
741 dest[0] = (q->qtype & 0xff00) >> 8;
742 dest[1] = (q->qtype & 0x00ff) >> 0;
743 dest[2] = (q->qclass & 0xff00) >> 8;
744 dest[3] = (q->qclass & 0x00ff) >> 0;
748 #endif /* L_encodeq */
753 int attribute_hidden __encode_answer(struct resolv_answer *a, unsigned char *dest, int maxlen)
757 i = __encode_dotted(a->dotted, dest, maxlen);
764 if (maxlen < (RRFIXEDSZ + a->rdlength))
767 *dest++ = (a->atype & 0xff00) >> 8;
768 *dest++ = (a->atype & 0x00ff) >> 0;
769 *dest++ = (a->aclass & 0xff00) >> 8;
770 *dest++ = (a->aclass & 0x00ff) >> 0;
771 *dest++ = (a->ttl & 0xff000000) >> 24;
772 *dest++ = (a->ttl & 0x00ff0000) >> 16;
773 *dest++ = (a->ttl & 0x0000ff00) >> 8;
774 *dest++ = (a->ttl & 0x000000ff) >> 0;
775 *dest++ = (a->rdlength & 0xff00) >> 8;
776 *dest++ = (a->rdlength & 0x00ff) >> 0;
777 memcpy(dest, a->rdata, a->rdlength);
779 return i + RRFIXEDSZ + a->rdlength;
781 #endif /* L_encodea */
784 #ifdef CURRENTLY_UNUSED
787 int __encode_packet(struct resolv_header *h,
788 struct resolv_question **q,
789 struct resolv_answer **an,
790 struct resolv_answer **ns,
791 struct resolv_answer **ar,
792 unsigned char *dest, int maxlen) attribute_hidden;
793 int __encode_packet(struct resolv_header *h,
794 struct resolv_question **q,
795 struct resolv_answer **an,
796 struct resolv_answer **ns,
797 struct resolv_answer **ar,
798 unsigned char *dest, int maxlen)
803 i = __encode_header(h, dest, maxlen);
811 for (j = 0; j < h->qdcount; j++) {
812 i = __encode_question(q[j], dest, maxlen);
820 for (j = 0; j < h->ancount; j++) {
821 i = __encode_answer(an[j], dest, maxlen);
828 for (j = 0; j < h->nscount; j++) {
829 i = __encode_answer(ns[j], dest, maxlen);
836 for (j = 0; j < h->arcount; j++) {
837 i = __encode_answer(ar[j], dest, maxlen);
847 #endif /* L_encodep */
852 int __decode_packet(unsigned char *data, struct resolv_header *h) attribute_hidden;
853 int __decode_packet(unsigned char *data, struct resolv_header *h)
855 __decode_header(data, h);
858 #endif /* L_decodep */
863 int __form_query(int id,
866 unsigned char *packet,
868 int __form_query(int id,
871 unsigned char *packet,
874 struct resolv_header h;
875 struct resolv_question q;
878 memset(&h, 0, sizeof(h));
882 q.dotted = (char *) name;
884 q.qclass = C_IN; /* CLASS_IN */
886 i = __encode_header(&h, packet, maxlen);
890 j = __encode_question(&q, packet + i, maxlen - i);
896 #endif /* L_formquery */
897 #endif /* CURRENTLY_UNUSED */
900 #ifdef L_opennameservers
902 # if __BYTE_ORDER == __LITTLE_ENDIAN
903 #define NAMESERVER_PORT_N (__bswap_constant_16(NAMESERVER_PORT))
905 #define NAMESERVER_PORT_N NAMESERVER_PORT
908 __UCLIBC_MUTEX_INIT(__resolv_lock, PTHREAD_MUTEX_INITIALIZER);
910 /* Protected by __resolv_lock */
911 void (*__res_sync)(void);
912 /*uint32_t __resolv_opts; */
913 uint8_t __resolv_timeout = RES_TIMEOUT;
914 uint8_t __resolv_attempts = RES_DFLRETRY;
915 unsigned __nameservers;
916 unsigned __searchdomains;
917 sockaddr46_t *__nameserver;
918 char **__searchdomain;
919 #ifdef __UCLIBC_HAS_IPV4__
920 const struct sockaddr_in __local_nameserver = {
921 .sin_family = AF_INET,
922 .sin_port = NAMESERVER_PORT_N,
925 const struct sockaddr_in6 __local_nameserver = {
926 .sin6_family = AF_INET6,
927 .sin6_port = NAMESERVER_PORT_N,
931 /* Helpers. Both stop on EOL, if it's '\n', it is converted to NUL first */
932 static char *skip_nospace(char *p)
934 while (*p != '\0' && !isspace(*p)) {
943 static char *skip_and_NUL_space(char *p)
945 /* NB: '\n' is not isspace! */
948 if (c == '\0' || !isspace(c))
951 if (c == '\n' || c == '#')
958 /* Must be called under __resolv_lock. */
959 void attribute_hidden __open_nameservers(void)
961 static uint32_t resolv_conf_mtime;
963 char szBuffer[MAXLEN_searchdomain];
969 /* Reread /etc/resolv.conf if it was modified. */
971 if (stat("/etc/resolv.conf", &sb) != 0)
973 if (resolv_conf_mtime != (uint32_t)sb.st_mtime) {
974 resolv_conf_mtime = sb.st_mtime;
975 __close_nameservers(); /* force config reread */
982 __resolv_timeout = RES_TIMEOUT;
983 __resolv_attempts = RES_DFLRETRY;
985 fp = fopen("/etc/resolv.conf", "r");
986 #ifdef FALLBACK_TO_CONFIG_RESOLVCONF
988 /* If we do not have a pre-populated /etc/resolv.conf then
989 try to use the one from /etc/config which exists on numerous
990 systems ranging from some uClinux to IRIX installations and
991 may be the only /etc dir that was mounted rw. */
992 fp = fopen("/etc/config/resolv.conf", "r");
997 while (fgets(szBuffer, sizeof(szBuffer), fp) != NULL) {
1001 keyword = p = skip_and_NUL_space(szBuffer);
1003 p = skip_nospace(p);
1004 /* find next word */
1005 p = skip_and_NUL_space(p);
1007 if (strcmp(keyword, "nameserver") == 0) {
1008 /* terminate IP addr */
1009 *skip_nospace(p) = '\0';
1010 memset(&sa, 0, sizeof(sa));
1011 if (0) /* nothing */;
1012 #ifdef __UCLIBC_HAS_IPV6__
1013 else if (inet_pton(AF_INET6, p, &sa.sa6.sin6_addr) > 0) {
1014 sa.sa6.sin6_family = AF_INET6;
1015 sa.sa6.sin6_port = htons(NAMESERVER_PORT);
1018 #ifdef __UCLIBC_HAS_IPV4__
1019 else if (inet_pton(AF_INET, p, &sa.sa4.sin_addr) > 0) {
1020 sa.sa4.sin_family = AF_INET;
1021 sa.sa4.sin_port = htons(NAMESERVER_PORT);
1025 continue; /* garbage on this line */
1026 ptr = realloc(__nameserver, (__nameservers + 1) * sizeof(__nameserver[0]));
1030 __nameserver[__nameservers++] = sa; /* struct copy */
1033 if (strcmp(keyword, "domain") == 0 || strcmp(keyword, "search") == 0) {
1036 /* free old domains ("last 'domain' or 'search' wins" rule) */
1037 while (__searchdomains)
1038 free(__searchdomain[--__searchdomains]);
1039 /*free(__searchdomain);*/
1040 /*__searchdomain = NULL; - not necessary */
1042 /* terminate current word */
1043 p1 = skip_nospace(p);
1044 /* find next word (maybe) */
1045 p1 = skip_and_NUL_space(p1);
1047 ptr = realloc(__searchdomain, (__searchdomains + 1) * sizeof(__searchdomain[0]));
1050 __searchdomain = ptr;
1051 /* NB: strlen(p) <= MAXLEN_searchdomain) because szBuffer[] is smaller */
1055 DPRINTF("adding search %s\n", (char*)ptr);
1056 __searchdomain[__searchdomains++] = (char*)ptr;
1062 /* if (strcmp(keyword, "sortlist") == 0)... */
1063 if (strcmp(keyword, "options") == 0) {
1067 if (p == NULL || (p1 = strchr(p, ':')) == NULL)
1070 if (strcmp(p, "timeout") == 0)
1071 what = &__resolv_timeout;
1072 else if (strcmp(p, "attempts") == 0)
1073 what = &__resolv_attempts;
1077 DPRINTF("option %s:%d\n", p, *what);
1082 if (__nameservers == 0) {
1083 /* Have to handle malloc failure! What a mess...
1084 * And it's not only here, we need to be careful
1085 * to never write into __nameserver[0] if it points
1086 * to constant __local_nameserver, or free it. */
1087 __nameserver = malloc(sizeof(__nameserver[0]));
1089 memcpy(__nameserver, &__local_nameserver, sizeof(__local_nameserver));
1091 __nameserver = (void*) &__local_nameserver;
1094 if (__searchdomains == 0) {
1097 i = gethostname(buf, sizeof(buf) - 1);
1098 buf[sizeof(buf) - 1] = '\0';
1099 if (i == 0 && (p = strchr(buf, '.')) != NULL && p[1]) {
1103 __searchdomain = malloc(sizeof(__searchdomain[0]));
1104 if (!__searchdomain) {
1108 __searchdomain[0] = p;
1113 DPRINTF("nameservers = %d\n", __nameservers);
1119 #endif /* L_opennameservers */
1122 #ifdef L_closenameservers
1124 /* Must be called under __resolv_lock. */
1125 void attribute_hidden __close_nameservers(void)
1127 if (__nameserver != (void*) &__local_nameserver)
1129 __nameserver = NULL;
1131 while (__searchdomains)
1132 free(__searchdomain[--__searchdomains]);
1133 free(__searchdomain);
1134 __searchdomain = NULL;
1135 /*__searchdomains = 0; - already is */
1137 #endif /* L_closenameservers */
1143 static int __length_question(const unsigned char *data, int maxlen)
1145 const unsigned char *start;
1158 if ((b & 0xc0) == 0xc0) {
1159 /* It's a "compressed" name. */
1160 data++; /* skip lsb of redirected offset */
1165 maxlen -= (b + 1); /* account for data++ above */
1167 /* Up to here we were skipping encoded name */
1169 /* Account for QTYPE and QCLASS fields */
1172 return data - start + 2 + 2;
1175 static int __decode_answer(const unsigned char *message, /* packet */
1177 int len, /* total packet len */
1178 struct resolv_answer *a)
1183 DPRINTF("decode_answer(start): off %d, len %d\n", offset, len);
1184 i = __decode_dotted(message, offset, len, temp, sizeof(temp));
1188 message += offset + i;
1189 len -= i + RRFIXEDSZ + offset;
1191 DPRINTF("decode_answer: off %d, len %d, i %d\n", offset, len, i);
1195 /* TODO: what if strdup fails? */
1196 a->dotted = strdup(temp);
1197 a->atype = (message[0] << 8) | message[1];
1199 a->aclass = (message[0] << 8) | message[1];
1201 a->ttl = (message[0] << 24) |
1202 (message[1] << 16) | (message[2] << 8) | (message[3] << 0);
1204 a->rdlength = (message[0] << 8) | message[1];
1207 a->rdoffset = offset + i + RRFIXEDSZ;
1209 DPRINTF("i=%d,rdlength=%d\n", i, a->rdlength);
1211 if (len < a->rdlength)
1213 return i + RRFIXEDSZ + a->rdlength;
1217 * a.buf(len) = auxiliary buffer for IP addresses after first one
1218 * a.add_count = how many additional addresses are there already
1219 * outpacket = where to save ptr to raw packet? can be NULL
1221 * ret < 0: error, all other data is not valid
1222 * ret >= 0: length of reply packet
1223 * a.add_count & a.buf: updated
1224 * a.rdlength: length of addresses (4 bytes for IPv4)
1225 * *outpacket: updated (packet is malloced, you need to free it)
1226 * a.rdata: points into *outpacket to 1st IP addr
1227 * NB: don't pass outpacket == NULL if you need to use a.rdata!
1228 * a.atype: type of query?
1229 * a.dotted: which name we _actually_ used. May contain search domains
1230 * appended. (why the filed is called "dotted" I have no idea)
1231 * This is a malloced string. May be NULL because strdup failed.
1233 int attribute_hidden __dns_lookup(const char *name,
1235 unsigned char **outpacket,
1236 struct resolv_answer *a)
1238 /* Protected by __resolv_lock: */
1239 static int last_ns_num = 0;
1240 static uint16_t last_id = 1;
1251 struct resolv_header h;
1252 struct resolv_question q;
1253 struct resolv_answer ma;
1254 bool first_answer = 1;
1256 unsigned char *packet = malloc(PACKETSZ);
1258 int variant = -1; /* search domain to append, -1: none */
1259 int local_ns_num = -1; /* Nth server to use */
1260 int local_id = local_id; /* for compiler */
1267 name_len = strlen(name);
1268 if ((unsigned)name_len >= MAXDNAME - MAXLEN_searchdomain - 2)
1269 goto fail; /* paranoia */
1270 lookup = malloc(name_len + 1/*for '.'*/ + MAXLEN_searchdomain + 1);
1271 if (!packet || !lookup || !name[0])
1273 ends_with_dot = (name[name_len - 1] == '.');
1274 /* no strcpy! paranoia, user might change name[] under us */
1275 memcpy(lookup, name, name_len);
1277 DPRINTF("Looking up type %d answer for '%s'\n", type, name);
1278 retries_left = 0; /* for compiler */
1281 unsigned reply_timeout;
1288 /* Mess with globals while under lock */
1289 /* NB: even data *pointed to* by globals may vanish
1290 * outside the locks. We should assume any and all
1291 * globals can completely change between locked
1292 * code regions. OTOH, this is rare, so we don't need
1293 * to handle it "nicely" (do not skip servers,
1294 * search domains, etc), we only need to ensure
1295 * we do not SEGV, use freed+overwritten data
1296 * or do other Really Bad Things. */
1297 __UCLIBC_MUTEX_LOCK(__resolv_lock);
1298 __open_nameservers();
1299 sdomains = __searchdomains;
1300 lookup[name_len] = '\0';
1301 if ((unsigned)variant < sdomains) {
1302 /* lookup is name_len + 1 + MAXLEN_searchdomain + 1 long */
1303 /* __searchdomain[] is not bigger than MAXLEN_searchdomain */
1304 lookup[name_len] = '.';
1305 strcpy(&lookup[name_len + 1], __searchdomain[variant]);
1307 /* first time? pick starting server etc */
1308 if (local_ns_num < 0) {
1310 /*TODO: implement /etc/resolv.conf's "options rotate"
1311 (a.k.a. RES_ROTATE bit in _res.options)
1313 if (_res.options & RES_ROTATE) */
1314 local_ns_num = last_ns_num;
1315 retries_left = __nameservers * __resolv_attempts;
1318 if (local_ns_num >= __nameservers)
1322 /* write new values back while still under lock */
1324 last_ns_num = local_ns_num;
1326 /* can't just take a pointer, __nameserver[x]
1327 * is not safe to use outside of locks */
1328 sa = __nameserver[local_ns_num];
1329 __UCLIBC_MUTEX_UNLOCK(__resolv_lock);
1331 memset(packet, 0, PACKETSZ);
1332 memset(&h, 0, sizeof(h));
1338 DPRINTF("encoding header\n", h.rd);
1339 i = __encode_header(&h, packet, PACKETSZ);
1343 /* encode question */
1344 DPRINTF("lookup name: %s\n", lookup);
1347 q.qclass = C_IN; /* CLASS_IN */
1348 j = __encode_question(&q, packet+i, PACKETSZ-i);
1356 const socklen_t plen = sa.sa.sa_family == AF_INET ? INET_ADDRSTRLEN : INET6_ADDRSTRLEN;
1357 char *pbuf = malloc(plen);
1358 if (pbuf == NULL) ;/* nothing */
1359 #ifdef __UCLIBC_HAS_IPV6__
1360 else if (sa.sa.sa_family == AF_INET6)
1361 pbuf = (char*)inet_ntop(AF_INET6, &sa.sa6.sin6_addr, pbuf, plen);
1363 #ifdef __UCLIBC_HAS_IPV4__
1364 else if (sa.sa.sa_family == AF_INET)
1365 pbuf = (char*)inet_ntop(AF_INET, &sa.sa4.sin_addr, pbuf, plen);
1367 DPRINTF("On try %d, sending query to %s, port %d\n",
1368 retries_left, pbuf, NAMESERVER_PORT);
1372 fd = socket(sa.sa.sa_family, SOCK_DGRAM, IPPROTO_UDP);
1373 if (fd < 0) /* paranoia */
1374 goto try_next_server;
1375 rc = connect(fd, &sa.sa, sizeof(sa));
1377 /*if (errno == ENETUNREACH) { */
1378 /* routing error, presume not transient */
1379 goto try_next_server;
1381 /*For example, what transient error this can be? Can't think of any */
1385 DPRINTF("Xmit packet len:%d id:%d qr:%d\n", packet_len, h.id, h.qr);
1386 /* no error check - if it fails, we time out on recv */
1387 send(fd, packet, packet_len, 0);
1390 reply_timeout = __resolv_timeout;
1394 tv.tv_sec = reply_timeout;
1396 if (select(fd + 1, &fds, NULL, NULL, &tv) <= 0) {
1397 DPRINTF("Timeout\n");
1398 /* timed out, so retry send and receive
1399 * to next nameserver */
1400 goto try_next_server;
1403 #else /* !USE_SELECT */
1404 reply_timeout = __resolv_timeout * 1000;
1407 fds.events = POLLIN;
1408 if (poll(&fds, 1, reply_timeout) <= 0) {
1409 DPRINTF("Timeout\n");
1410 /* timed out, so retry send and receive
1411 * to next nameserver */
1412 goto try_next_server;
1414 /*TODO: better timeout accounting?*/
1415 reply_timeout -= 1000;
1416 #endif /* USE_SELECT */
1418 /* vda: a bogus response seen in real world (caused SEGV in uclibc):
1419 * "ping www.google.com" sending AAAA query and getting
1420 * response with one answer... with answer part missing!
1421 * Fixed by thorough checks for not going past the packet's end.
1425 static const char test_query[32] = "\0\2\1\0\0\1\0\0\0\0\0\0\3www\6google\3com\0\0\34\0\1";
1426 static const char test_respn[32] = "\0\2\201\200\0\1\0\1\0\0\0\0\3www\6google\3com\0\0\34\0\1";
1427 pos = memcmp(packet + 2, test_query + 2, 30);
1428 packet_len = recv(fd, packet, PACKETSZ, MSG_DONTWAIT);
1431 memcpy(packet + 2, test_respn + 2, 30);
1435 packet_len = recv(fd, packet, PACKETSZ, MSG_DONTWAIT);
1438 if (packet_len < HFIXEDSZ) {
1440 * If the peer did shutdown then retry later,
1441 * try next peer on error.
1442 * it's just a bogus packet from somewhere */
1444 if (packet_len >= 0 && reply_timeout)
1446 goto try_next_server;
1448 __decode_header(packet, &h);
1449 DPRINTF("len:%d id:%d qr:%d\n", packet_len, h.id, h.qr);
1450 if (h.id != local_id || !h.qr) {
1455 DPRINTF("Got response (i think)!\n");
1456 DPRINTF("qrcount=%d,ancount=%d,nscount=%d,arcount=%d\n",
1457 h.qdcount, h.ancount, h.nscount, h.arcount);
1458 DPRINTF("opcode=%d,aa=%d,tc=%d,rd=%d,ra=%d,rcode=%d\n",
1459 h.opcode, h.aa, h.tc, h.rd, h.ra, h.rcode);
1461 /* bug 660 says we treat negative response as an error
1462 * and retry, which is, eh, an error. :)
1463 * We were incurring long delays because of this. */
1464 if (h.rcode == NXDOMAIN || h.rcode == SERVFAIL) {
1465 /* if possible, try next search domain */
1466 if (!ends_with_dot) {
1467 DPRINTF("variant:%d sdomains:%d\n", variant, sdomains);
1468 if (variant < sdomains - 1) {
1469 /* next search domain */
1473 /* no more search domains to try */
1475 /* dont loop, this is "no such host" situation */
1476 h_errno = HOST_NOT_FOUND;
1479 /* Insert other non-fatal errors here, which do not warrant
1480 * switching to next nameserver */
1482 /* Strange error, assuming this nameserver is feeling bad */
1484 goto try_next_server;
1486 /* Code below won't work correctly with h.ancount == 0, so... */
1487 if (h.ancount <= 0) {
1488 h_errno = NO_DATA; /* [is this correct code to check for?] */
1492 for (j = 0; j < h.qdcount; j++) {
1493 DPRINTF("Skipping question %d at %d\n", j, pos);
1494 i = __length_question(packet + pos, packet_len - pos);
1496 DPRINTF("Packet'question section "
1497 "is truncated, trying next server\n");
1498 goto try_next_server;
1501 DPRINTF("Length of question %d is %d\n", j, i);
1503 DPRINTF("Decoding answer at pos %d\n", pos);
1507 for (j = 0; j < h.ancount; j++) {
1508 i = __decode_answer(packet, pos, packet_len, &ma);
1510 DPRINTF("failed decode %d\n", i);
1511 /* If the message was truncated but we have
1512 * decoded some answers, pretend it's OK */
1515 goto try_next_server;
1521 ma.buflen = a->buflen;
1522 ma.add_count = a->add_count;
1524 memcpy(a, &ma, sizeof(ma));
1525 if (a->atype != T_SIG && (NULL == a->buf || (type != T_A && type != T_AAAA)))
1527 if (a->atype != type)
1529 a->add_count = h.ancount - j - 1;
1530 if ((a->rdlength + sizeof(struct in_addr*)) * a->add_count > a->buflen)
1536 if (ma.atype != type)
1538 if (a->rdlength != ma.rdlength) {
1540 DPRINTF("Answer address len(%u) differs from original(%u)\n",
1541 ma.rdlength, a->rdlength);
1542 goto try_next_server;
1544 memcpy(a->buf + (a->add_count * ma.rdlength), ma.rdata, ma.rdlength);
1550 DPRINTF("Answer name = |%s|\n", a->dotted);
1551 DPRINTF("Answer type = |%d|\n", a->atype);
1555 *outpacket = packet;
1562 /* Try next nameserver */
1565 } while (retries_left > 0);
1568 h_errno = NETDB_INTERNAL;
1576 #endif /* L_dnslookup */
1579 #ifdef L_read_etc_hosts_r
1581 parser_t * __open_etc_hosts(void)
1584 parser = config_open("/etc/hosts");
1585 #ifdef FALLBACK_TO_CONFIG_RESOLVCONF
1587 parser = config_open("/etc/config/hosts");
1592 #define MINTOKENS 2 /* ip address + canonical name */
1593 #define MAXTOKENS (MINTOKENS + MAXALIASES)
1594 #define HALISTOFF (sizeof(char*) * MAXTOKENS)
1595 #define INADDROFF (HALISTOFF + 2 * sizeof(char*))
1597 int attribute_hidden __read_etc_hosts_r(
1601 enum etc_hosts_action action,
1602 struct hostent *result_buf,
1603 char *buf, size_t buflen,
1604 struct hostent **result,
1608 struct in_addr *h_addr0 = NULL;
1609 const size_t aliaslen = INADDROFF +
1610 #ifdef __UCLIBC_HAS_IPV6__
1611 sizeof(struct in6_addr)
1613 sizeof(struct in_addr)
1616 int ret = HOST_NOT_FOUND;
1618 *h_errnop = NETDB_INTERNAL;
1619 if (buflen < aliaslen
1620 || (buflen - aliaslen) < BUFSZ + 1)
1623 parser = __open_etc_hosts();
1624 if (parser == NULL) {
1629 * char *alias[MAXTOKENS] = {address, name, aliases...}
1630 * char **h_addr_list[1] = {*in[6]_addr, NULL}
1632 * char line_buffer[BUFSZ+];
1635 parser->data_len = aliaslen;
1636 parser->line_len = buflen - aliaslen;
1637 *h_errnop = HOST_NOT_FOUND;
1638 /* <ip>[[:space:]][<aliases>] */
1639 while (config_read(parser, &tok, MAXTOKENS, MINTOKENS, "# \t", PARSE_NORMAL)) {
1640 result_buf->h_aliases = tok+1;
1641 if (action == GETHOSTENT) {
1642 /* Return whatever the next entry happens to be. */
1645 if (action == GET_HOSTS_BYADDR) {
1646 if (strcmp(name, *tok) != 0)
1648 } else { /* GET_HOSTS_BYNAME */
1650 char **alias = tok + 1;
1651 while (aliases < MAXALIASES) {
1652 char *tmp = *(alias+aliases++);
1653 if (tmp && strcasecmp(name, tmp) == 0)
1659 result_buf->h_name = *(result_buf->h_aliases++);
1660 result_buf->h_addr_list = (char**)(buf + HALISTOFF);
1661 *(result_buf->h_addr_list + 1) = '\0';
1662 h_addr0 = (struct in_addr*)(buf + INADDROFF);
1663 result_buf->h_addr = (char*)h_addr0;
1664 if (0) /* nothing */;
1665 #ifdef __UCLIBC_HAS_IPV4__
1666 else if (type == AF_INET
1667 && inet_pton(AF_INET, *tok, h_addr0) > 0) {
1668 DPRINTF("Found INET\n");
1669 result_buf->h_addrtype = AF_INET;
1670 result_buf->h_length = sizeof(struct in_addr);
1671 *result = result_buf;
1672 ret = NETDB_SUCCESS;
1675 #ifdef __UCLIBC_HAS_IPV6__
1676 #define in6 ((struct in6_addr *)buf)
1677 else if (type == AF_INET6
1678 && inet_pton(AF_INET6, *tok, h_addr0) > 0) {
1679 DPRINTF("Found INET6\n");
1680 result_buf->h_addrtype = AF_INET6;
1681 result_buf->h_length = sizeof(struct in6_addr);
1682 *result = result_buf;
1683 ret = NETDB_SUCCESS;
1687 /* continue parsing in the hope the user has multiple
1688 * host types listed in the database like so:
1691 * If looking for an IPv6 addr, don't bail when we got the IPv4
1693 DPRINTF("Error: Found host but different address family\n");
1694 /* NB: gethostbyname2_r depends on this feature
1695 * to avoid looking for IPv6 addr of "localhost" etc */
1701 if (action != GETHOSTENT)
1702 config_close(parser);
1706 #endif /* L_read_etc_hosts_r */
1709 #ifdef L_get_hosts_byname_r
1711 int attribute_hidden __get_hosts_byname_r(const char *name,
1713 struct hostent *result_buf,
1716 struct hostent **result,
1719 return __read_etc_hosts_r(NULL, name, type, GET_HOSTS_BYNAME,
1720 result_buf, buf, buflen, result, h_errnop);
1722 #endif /* L_get_hosts_byname_r */
1725 #ifdef L_get_hosts_byaddr_r
1727 int attribute_hidden __get_hosts_byaddr_r(const char *addr,
1730 struct hostent *result_buf,
1733 struct hostent **result,
1736 #ifndef __UCLIBC_HAS_IPV6__
1737 char ipaddr[INET_ADDRSTRLEN];
1739 char ipaddr[INET6_ADDRSTRLEN];
1743 #ifdef __UCLIBC_HAS_IPV4__
1745 if (len != sizeof(struct in_addr))
1749 #ifdef __UCLIBC_HAS_IPV6__
1751 if (len != sizeof(struct in6_addr))
1759 inet_ntop(type, addr, ipaddr, sizeof(ipaddr));
1761 return __read_etc_hosts_r(NULL, ipaddr, type, GET_HOSTS_BYADDR,
1762 result_buf, buf, buflen, result, h_errnop);
1764 #endif /* L_get_hosts_byaddr_r */
1767 #ifdef L_getnameinfo
1769 int getnameinfo(const struct sockaddr *sa,
1779 struct hostent *hoste = NULL;
1782 if (flags & ~(NI_NUMERICHOST|NI_NUMERICSERV|NI_NOFQDN|NI_NAMEREQD|NI_DGRAM))
1783 return EAI_BADFLAGS;
1785 if (sa == NULL || addrlen < sizeof(sa_family_t))
1789 if (ok == AF_LOCAL) /* valid */;
1790 #ifdef __UCLIBC_HAS_IPV4__
1791 else if (ok == AF_INET) {
1792 if (addrlen < sizeof(struct sockaddr_in))
1796 #ifdef __UCLIBC_HAS_IPV6__
1797 else if (ok == AF_INET6) {
1798 if (addrlen < sizeof(struct sockaddr_in6))
1806 if (host != NULL && hostlen > 0)
1807 switch (sa->sa_family) {
1809 #ifdef __UCLIBC_HAS_IPV6__
1812 if (!(flags & NI_NUMERICHOST)) {
1813 if (0) /* nothing */;
1814 #ifdef __UCLIBC_HAS_IPV6__
1815 else if (sa->sa_family == AF_INET6)
1816 hoste = gethostbyaddr((const void *)
1817 &(((const struct sockaddr_in6 *) sa)->sin6_addr),
1818 sizeof(struct in6_addr), AF_INET6);
1820 #ifdef __UCLIBC_HAS_IPV4__
1822 hoste = gethostbyaddr((const void *)
1823 &(((const struct sockaddr_in *)sa)->sin_addr),
1824 sizeof(struct in_addr), AF_INET);
1830 #define min(x,y) (((x) > (y)) ? (y) : (x))
1831 if ((flags & NI_NOFQDN)
1832 && (getdomainname(domain, sizeof(domain)) == 0)
1833 && (c = strstr(hoste->h_name, domain)) != NULL
1834 && (c != hoste->h_name) && (*(--c) == '.')
1836 strncpy(host, hoste->h_name,
1837 min(hostlen, (size_t) (c - hoste->h_name)));
1838 host[min(hostlen - 1, (size_t) (c - hoste->h_name))] = '\0';
1840 strncpy(host, hoste->h_name, hostlen);
1848 const char *c = NULL;
1850 if (flags & NI_NAMEREQD) {
1854 if (0) /* nothing */;
1855 #ifdef __UCLIBC_HAS_IPV6__
1856 else if (sa->sa_family == AF_INET6) {
1857 const struct sockaddr_in6 *sin6p;
1859 sin6p = (const struct sockaddr_in6 *) sa;
1860 c = inet_ntop(AF_INET6,
1861 (const void *) &sin6p->sin6_addr,
1864 /* Does scope id need to be supported? */
1866 scopeid = sin6p->sin6_scope_id;
1868 /* Buffer is >= IFNAMSIZ+1. */
1869 char scopebuf[IFNAMSIZ + 1];
1871 int ni_numericscope = 0;
1872 size_t real_hostlen = strnlen(host, hostlen);
1873 size_t scopelen = 0;
1875 scopebuf[0] = SCOPE_DELIMITER;
1877 scopeptr = &scopebuf[1];
1879 if (IN6_IS_ADDR_LINKLOCAL(&sin6p->sin6_addr)
1880 || IN6_IS_ADDR_MC_LINKLOCAL(&sin6p->sin6_addr)) {
1881 if (if_indextoname(scopeid, scopeptr) == NULL)
1884 scopelen = strlen(scopebuf);
1889 if (ni_numericscope)
1890 scopelen = 1 + snprintf(scopeptr,
1896 if (real_hostlen + scopelen + 1 > hostlen)
1898 memcpy(host + real_hostlen, scopebuf, scopelen + 1);
1902 #endif /* __UCLIBC_HAS_IPV6__ */
1903 #if defined __UCLIBC_HAS_IPV4__
1905 c = inet_ntop(AF_INET, (const void *)
1906 &(((const struct sockaddr_in *) sa)->sin_addr),
1919 if (!(flags & NI_NUMERICHOST)) {
1920 struct utsname utsname;
1922 if (!uname(&utsname)) {
1923 strncpy(host, utsname.nodename, hostlen);
1928 if (flags & NI_NAMEREQD) {
1933 strncpy(host, "localhost", hostlen);
1935 /* Already checked above
1941 if (serv && (servlen > 0)) {
1942 if (sa->sa_family == AF_LOCAL) {
1943 strncpy(serv, ((const struct sockaddr_un *) sa)->sun_path, servlen);
1944 } else { /* AF_INET || AF_INET6 */
1945 if (!(flags & NI_NUMERICSERV)) {
1947 s = getservbyport(((const struct sockaddr_in *) sa)->sin_port,
1948 ((flags & NI_DGRAM) ? "udp" : "tcp"));
1950 strncpy(serv, s->s_name, servlen);
1954 snprintf(serv, servlen, "%d",
1955 ntohs(((const struct sockaddr_in *) sa)->sin_port));
1959 if (host && (hostlen > 0))
1960 host[hostlen-1] = 0;
1961 if (serv && (servlen > 0))
1962 serv[servlen-1] = 0;
1966 libc_hidden_def(getnameinfo)
1967 #endif /* L_getnameinfo */
1970 #ifdef L_gethostbyname_r
1973 * "uClibc resolver's gethostbyname does not return the requested name
1974 * as an alias, but instead returns the canonical name. glibc's
1975 * gethostbyname has a similar bug where it returns the requested name
1976 * with the search domain name appended (to make a FQDN) as an alias,
1977 * but not the original name itself. Both contradict POSIX, which says
1978 * that the name argument passed to gethostbyname must be in the alias list"
1979 * This is fixed now, and we differ from glibc:
1981 * $ ./gethostbyname_uclibc wer.google.com
1982 * h_name:'c13-ss-2-lb.cnet.com'
1984 * h_addrtype:2 AF_INET
1985 * alias:'wer.google.com' <===
1986 * addr: 0x4174efd8 '216.239.116.65'
1988 * $ ./gethostbyname_glibc wer.google.com
1989 * h_name:'c13-ss-2-lb.cnet.com'
1991 * h_addrtype:2 AF_INET
1992 * alias:'wer.google.com.com' <===
1993 * addr:'216.239.116.65'
1995 * When examples were run, /etc/resolv.conf contained "search com" line.
1997 int gethostbyname_r(const char *name,
1998 struct hostent *result_buf,
2001 struct hostent **result,
2004 struct in_addr **addr_list;
2007 unsigned char *packet;
2008 struct resolv_answer a;
2017 /* do /etc/hosts first */
2019 int old_errno = errno; /* save the old errno and reset errno */
2020 __set_errno(0); /* to check for missing /etc/hosts. */
2021 i = __get_hosts_byname_r(name, AF_INET, result_buf,
2022 buf, buflen, result, h_errnop);
2023 if (i == NETDB_SUCCESS) {
2024 __set_errno(old_errno);
2027 switch (*h_errnop) {
2028 case HOST_NOT_FOUND:
2029 wrong_af = (i == TRY_AGAIN);
2032 case NETDB_INTERNAL:
2033 if (errno == ENOENT) {
2036 /* else fall through */
2040 __set_errno(old_errno);
2043 DPRINTF("Nothing found in /etc/hosts\n");
2045 *h_errnop = NETDB_INTERNAL;
2047 /* prepare future h_aliases[0] */
2048 i = strlen(name) + 1;
2049 if ((ssize_t)buflen <= i)
2051 memcpy(buf, name, i); /* paranoia: name might change */
2055 /* make sure pointer is aligned */
2056 i = ALIGN_BUFFER_OFFSET(buf);
2061 * struct in_addr* addr_list[NN+1];
2062 * struct in_addr* in[NN];
2064 alias = (char **)buf;
2065 buf += sizeof(alias[0]) * 2;
2066 buflen -= sizeof(alias[0]) * 2;
2067 addr_list = (struct in_addr **)buf;
2068 /* buflen may be < 0, must do signed compare */
2069 if ((ssize_t)buflen < 256)
2072 /* we store only one "alias" - the name itself */
2073 #ifdef __UCLIBC_MJN3_ONLY__
2074 #warning TODO -- generate the full list
2079 /* maybe it is already an address? */
2081 struct in_addr *in = (struct in_addr *)(buf + sizeof(addr_list[0]) * 2);
2082 if (inet_aton(name, in)) {
2084 addr_list[1] = NULL;
2085 result_buf->h_name = alias0;
2086 result_buf->h_aliases = alias;
2087 result_buf->h_addrtype = AF_INET;
2088 result_buf->h_length = sizeof(struct in_addr);
2089 result_buf->h_addr_list = (char **) addr_list;
2090 *result = result_buf;
2091 *h_errnop = NETDB_SUCCESS;
2092 return NETDB_SUCCESS;
2096 /* what if /etc/hosts has it but it's not IPv4?
2097 * F.e. "::1 localhost6". We don't do DNS query for such hosts -
2098 * "ping localhost6" should be fast even if DNS server is down! */
2100 *h_errnop = HOST_NOT_FOUND;
2104 /* talk to DNS servers */
2106 /* take into account that at least one address will be there,
2107 * we'll need space for one in_addr + two addr_list[] elems */
2108 a.buflen = buflen - ((sizeof(addr_list[0]) * 2 + sizeof(struct in_addr)));
2110 packet_len = __dns_lookup(name, T_A, &packet, &a);
2111 if (packet_len < 0) {
2112 *h_errnop = HOST_NOT_FOUND;
2113 DPRINTF("__dns_lookup returned < 0\n");
2117 if (a.atype == T_A) { /* ADDRESS */
2118 /* we need space for addr_list[] and one IPv4 address */
2119 /* + 1 accounting for 1st addr (it's in a.rdata),
2120 * another + 1 for NULL in last addr_list[]: */
2121 int need_bytes = sizeof(addr_list[0]) * (a.add_count + 1 + 1)
2122 /* for 1st addr (it's in a.rdata): */
2123 + sizeof(struct in_addr);
2124 /* how many bytes will 2nd and following addresses take? */
2125 int ips_len = a.add_count * a.rdlength;
2127 buflen -= (need_bytes + ips_len);
2128 if ((ssize_t)buflen < 0) {
2129 DPRINTF("buffer too small for all addresses\n");
2130 /* *h_errnop = NETDB_INTERNAL; - already is */
2135 /* if there are additional addresses in buf,
2136 * move them forward so that they are not destroyed */
2137 DPRINTF("a.add_count:%d a.rdlength:%d a.rdata:%p\n", a.add_count, a.rdlength, a.rdata);
2138 memmove(buf + need_bytes, buf, ips_len);
2140 /* 1st address is in a.rdata, insert it */
2141 buf += need_bytes - sizeof(struct in_addr);
2142 memcpy(buf, a.rdata, sizeof(struct in_addr));
2144 /* fill addr_list[] */
2145 for (i = 0; i <= a.add_count; i++) {
2146 addr_list[i] = (struct in_addr*)buf;
2147 buf += sizeof(struct in_addr);
2149 addr_list[i] = NULL;
2151 /* if we have enough space, we can report "better" name
2152 * (it may contain search domains attached by __dns_lookup,
2153 * or CNAME of the host if it is different from the name
2154 * we used to find it) */
2155 if (a.dotted && buflen > strlen(a.dotted)) {
2156 strcpy(buf, a.dotted);
2160 result_buf->h_name = alias0;
2161 result_buf->h_aliases = alias;
2162 result_buf->h_addrtype = AF_INET;
2163 result_buf->h_length = sizeof(struct in_addr);
2164 result_buf->h_addr_list = (char **) addr_list;
2165 *result = result_buf;
2166 *h_errnop = NETDB_SUCCESS;
2171 *h_errnop = HOST_NOT_FOUND;
2172 __set_h_errno(HOST_NOT_FOUND);
2180 libc_hidden_def(gethostbyname_r)
2181 link_warning(gethostbyname_r, "gethostbyname_r is obsolescent, use getnameinfo() instead.");
2182 #endif /* L_gethostbyname_r */
2185 #ifdef L_gethostbyname2_r
2187 int gethostbyname2_r(const char *name,
2189 struct hostent *result_buf,
2192 struct hostent **result,
2195 #ifndef __UCLIBC_HAS_IPV6__
2196 return family == (AF_INET)
2197 ? gethostbyname_r(name, result_buf, buf, buflen, result, h_errnop)
2200 struct in6_addr *in;
2201 struct in6_addr **addr_list;
2202 unsigned char *packet;
2203 struct resolv_answer a;
2208 if (family == AF_INET)
2209 return gethostbyname_r(name, result_buf, buf, buflen, result, h_errnop);
2212 if (family != AF_INET6)
2218 /* do /etc/hosts first */
2220 int old_errno = errno; /* Save the old errno and reset errno */
2221 __set_errno(0); /* to check for missing /etc/hosts. */
2223 i = __get_hosts_byname_r(name, AF_INET6 /*family*/, result_buf,
2224 buf, buflen, result, h_errnop);
2225 if (i == NETDB_SUCCESS) {
2226 __set_errno(old_errno);
2229 switch (*h_errnop) {
2230 case HOST_NOT_FOUND:
2231 wrong_af = (i == TRY_AGAIN);
2234 case NETDB_INTERNAL:
2235 if (errno == ENOENT) {
2238 /* else fall through */
2242 __set_errno(old_errno);
2244 DPRINTF("Nothing found in /etc/hosts\n");
2246 *h_errnop = NETDB_INTERNAL;
2248 /* make sure pointer is aligned */
2249 i = ALIGN_BUFFER_OFFSET(buf);
2253 * struct in6_addr* in;
2254 * struct in6_addr* addr_list[2];
2255 * char scratch_buf[256];
2257 in = (struct in6_addr*)buf;
2259 buflen -= sizeof(*in);
2260 addr_list = (struct in6_addr**)buf;
2261 buf += sizeof(*addr_list) * 2;
2262 buflen -= sizeof(*addr_list) * 2;
2263 if ((ssize_t)buflen < 256)
2266 addr_list[1] = NULL;
2267 strncpy(buf, name, buflen);
2270 /* maybe it is already an address? */
2271 if (inet_pton(AF_INET6, name, in)) {
2272 result_buf->h_name = buf;
2273 result_buf->h_addrtype = AF_INET6;
2274 result_buf->h_length = sizeof(*in);
2275 result_buf->h_addr_list = (char **) addr_list;
2276 /* result_buf->h_aliases = ??? */
2277 *result = result_buf;
2278 *h_errnop = NETDB_SUCCESS;
2279 return NETDB_SUCCESS;
2282 /* what if /etc/hosts has it but it's not IPv6?
2283 * F.e. "127.0.0.1 localhost". We don't do DNS query for such hosts -
2284 * "ping localhost" should be fast even if DNS server is down! */
2286 *h_errnop = HOST_NOT_FOUND;
2290 /* talk to DNS servers */
2291 /* TODO: why it's so different from gethostbyname_r (IPv4 case)? */
2292 memset(&a, '\0', sizeof(a));
2296 /* Hmm why we memset(a) to zeros only once? */
2297 packet_len = __dns_lookup(buf, T_AAAA, &packet, &a);
2298 if (packet_len < 0) {
2299 *h_errnop = HOST_NOT_FOUND;
2302 strncpy(buf, a.dotted, buflen);
2305 if (a.atype != T_CNAME)
2308 DPRINTF("Got a CNAME in gethostbyname()\n");
2309 if (++nest > MAX_RECURSE) {
2310 *h_errnop = NO_RECOVERY;
2313 i = __decode_dotted(packet, a.rdoffset, packet_len, buf, buflen);
2316 *h_errnop = NO_RECOVERY;
2320 if (a.atype == T_AAAA) { /* ADDRESS */
2321 memcpy(in, a.rdata, sizeof(*in));
2322 result_buf->h_name = buf;
2323 result_buf->h_addrtype = AF_INET6;
2324 result_buf->h_length = sizeof(*in);
2325 result_buf->h_addr_list = (char **) addr_list;
2326 /* result_buf->h_aliases = ??? */
2328 *result = result_buf;
2329 *h_errnop = NETDB_SUCCESS;
2330 return NETDB_SUCCESS;
2333 *h_errnop = HOST_NOT_FOUND;
2336 #endif /* __UCLIBC_HAS_IPV6__ */
2338 libc_hidden_def(gethostbyname2_r)
2339 #endif /* L_gethostbyname2_r */
2342 #ifdef L_gethostbyaddr_r
2344 int gethostbyaddr_r(const void *addr, socklen_t addrlen,
2346 struct hostent *result_buf,
2347 char *buf, size_t buflen,
2348 struct hostent **result,
2353 struct in_addr **addr_list;
2355 unsigned char *packet;
2356 struct resolv_answer a;
2366 #ifdef __UCLIBC_HAS_IPV4__
2368 if (addrlen != sizeof(struct in_addr))
2372 #ifdef __UCLIBC_HAS_IPV6__
2374 if (addrlen != sizeof(struct in6_addr))
2382 /* do /etc/hosts first */
2383 i = __get_hosts_byaddr_r(addr, addrlen, type, result_buf,
2384 buf, buflen, result, h_errnop);
2387 switch (*h_errnop) {
2388 case HOST_NOT_FOUND:
2395 *h_errnop = NETDB_INTERNAL;
2397 /* make sure pointer is aligned */
2398 i = ALIGN_BUFFER_OFFSET(buf);
2402 * char *alias[ALIAS_DIM];
2403 * struct in[6]_addr* addr_list[2];
2404 * struct in[6]_addr in;
2405 * char scratch_buffer[256+];
2407 #define in6 ((struct in6_addr *)in)
2408 alias = (char **)buf;
2409 addr_list = (struct in_addr**)buf;
2410 buf += sizeof(*addr_list) * 2;
2411 buflen -= sizeof(*addr_list) * 2;
2412 in = (struct in_addr*)buf;
2413 #ifndef __UCLIBC_HAS_IPV6__
2415 buflen -= sizeof(*in);
2416 if (addrlen > sizeof(*in))
2419 buf += sizeof(*in6);
2420 buflen -= sizeof(*in6);
2421 if (addrlen > sizeof(*in6))
2424 if ((ssize_t)buflen < 256)
2429 addr_list[1] = NULL;
2430 memcpy(in, addr, addrlen);
2432 if (0) /* nothing */;
2433 #ifdef __UCLIBC_HAS_IPV4__
2434 else IF_HAS_BOTH(if (type == AF_INET)) {
2435 unsigned char *tp = (unsigned char *)addr;
2436 sprintf(buf, "%u.%u.%u.%u.in-addr.arpa",
2437 tp[3], tp[2], tp[1], tp[0]);
2440 #ifdef __UCLIBC_HAS_IPV6__
2443 unsigned char *tp = (unsigned char *)addr + addrlen - 1;
2445 dst += sprintf(dst, "%x.%x.", tp[0] & 0xf, tp[0] >> 4);
2447 } while (tp >= (unsigned char *)addr);
2448 strcpy(dst, "ip6.arpa");
2452 memset(&a, '\0', sizeof(a));
2454 /* Hmm why we memset(a) to zeros only once? */
2455 packet_len = __dns_lookup(buf, T_PTR, &packet, &a);
2456 if (packet_len < 0) {
2457 *h_errnop = HOST_NOT_FOUND;
2461 strncpy(buf, a.dotted, buflen);
2463 if (a.atype != T_CNAME)
2466 DPRINTF("Got a CNAME in gethostbyaddr()\n");
2467 if (++nest > MAX_RECURSE) {
2468 *h_errnop = NO_RECOVERY;
2471 /* Decode CNAME into buf, feed it to __dns_lookup() again */
2472 i = __decode_dotted(packet, a.rdoffset, packet_len, buf, buflen);
2475 *h_errnop = NO_RECOVERY;
2480 if (a.atype == T_PTR) { /* ADDRESS */
2481 i = __decode_dotted(packet, a.rdoffset, packet_len, buf, buflen);
2483 result_buf->h_name = buf;
2484 result_buf->h_addrtype = type;
2485 result_buf->h_length = addrlen;
2486 result_buf->h_addr_list = (char **) addr_list;
2487 result_buf->h_aliases = alias;
2488 *result = result_buf;
2489 *h_errnop = NETDB_SUCCESS;
2490 return NETDB_SUCCESS;
2494 *h_errnop = NO_ADDRESS;
2498 libc_hidden_def(gethostbyaddr_r)
2499 link_warning(gethostbyaddr_r, "gethostbyaddr_r is obsolescent, use getaddrinfo() instead.");
2500 #endif /* L_gethostbyaddr_r */
2503 #ifdef L_gethostent_r
2505 __UCLIBC_MUTEX_STATIC(mylock, PTHREAD_MUTEX_INITIALIZER);
2507 static parser_t *hostp = NULL;
2508 static smallint host_stayopen;
2510 void endhostent_unlocked(void)
2513 config_close(hostp);
2518 void endhostent(void)
2520 __UCLIBC_MUTEX_LOCK(mylock);
2521 endhostent_unlocked();
2522 __UCLIBC_MUTEX_UNLOCK(mylock);
2525 void sethostent(int stay_open)
2527 __UCLIBC_MUTEX_LOCK(mylock);
2530 __UCLIBC_MUTEX_UNLOCK(mylock);
2533 int gethostent_r(struct hostent *result_buf, char *buf, size_t buflen,
2534 struct hostent **result, int *h_errnop)
2538 __UCLIBC_MUTEX_LOCK(mylock);
2539 if (hostp == NULL) {
2540 hostp = __open_etc_hosts();
2541 if (hostp == NULL) {
2548 ret = __read_etc_hosts_r(hostp, NULL, AF_INET, GETHOSTENT,
2549 result_buf, buf, buflen, result, h_errnop);
2551 endhostent_unlocked();
2553 __UCLIBC_MUTEX_UNLOCK(mylock);
2556 libc_hidden_def(gethostent_r)
2557 #endif /* L_gethostent_r */
2562 struct hostent *gethostent(void)
2564 static struct hostent hoste;
2566 #ifndef __UCLIBC_HAS_IPV6__
2567 sizeof(struct in_addr) + sizeof(struct in_addr *) * 2 +
2569 sizeof(struct in6_addr) + sizeof(struct in6_addr *) * 2 +
2570 #endif /* __UCLIBC_HAS_IPV6__ */
2571 BUFSZ /*namebuffer*/ + 2 /* margin */];
2572 struct hostent *host;
2574 gethostent_r(&hoste, buf, sizeof(buf), &host, &h_errno);
2577 #endif /* L_gethostent */
2580 #ifdef L_gethostbyname2
2582 struct hostent *gethostbyname2(const char *name, int family)
2584 #ifndef __UCLIBC_HAS_IPV6__
2585 return family == AF_INET ? gethostbyname(name) : (struct hostent*)NULL;
2587 static struct hostent hoste;
2588 static char buf[sizeof(struct in6_addr) +
2589 sizeof(struct in6_addr *) * 2 +
2590 /*sizeof(char *)*ALIAS_DIM +*/ 384/*namebuffer*/ + 32/* margin */];
2593 gethostbyname2_r(name, family, &hoste, buf, sizeof(buf), &hp, &h_errno);
2597 libc_hidden_def(gethostbyname2)
2598 #endif /* L_gethostbyname2 */
2601 #ifdef L_gethostbyname
2603 struct hostent *gethostbyname(const char *name)
2605 #ifndef __UCLIBC_HAS_IPV6__
2606 static struct hostent hoste;
2607 static char buf[sizeof(struct in_addr) +
2608 sizeof(struct in_addr *) * 2 +
2609 /*sizeof(char *)*ALIAS_DIM +*/ 384/*namebuffer*/ + 32/* margin */];
2612 gethostbyname_r(name, &hoste, buf, sizeof(buf), &hp, &h_errno);
2615 return gethostbyname2(name, AF_INET);
2618 libc_hidden_def(gethostbyname)
2619 link_warning(gethostbyname, "gethostbyname is obsolescent, use getnameinfo() instead.");
2620 #endif /* L_gethostbyname */
2623 #ifdef L_gethostbyaddr
2625 struct hostent *gethostbyaddr(const void *addr, socklen_t len, int type)
2627 static struct hostent hoste;
2629 #ifndef __UCLIBC_HAS_IPV6__
2630 sizeof(struct in_addr) + sizeof(struct in_addr *)*2 +
2632 sizeof(struct in6_addr) + sizeof(struct in6_addr *)*2 +
2633 #endif /* __UCLIBC_HAS_IPV6__ */
2634 /*sizeof(char *)*ALIAS_DIM +*/ 384 /*namebuffer*/ + 32 /* margin */];
2637 gethostbyaddr_r(addr, len, type, &hoste, buf, sizeof(buf), &hp, &h_errno);
2640 libc_hidden_def(gethostbyaddr)
2641 link_warning(gethostbyaddr, "gethostbyaddr is obsolescent, use getaddrinfo() instead.");
2642 #endif /* L_gethostbyaddr */
2648 * Expand compressed domain name 'comp_dn' to full domain name.
2649 * 'msg' is a pointer to the begining of the message,
2650 * 'eomorig' points to the first location after the message,
2651 * 'exp_dn' is a pointer to a buffer of size 'length' for the result.
2652 * Return size of compressed name or -1 if there was an error.
2654 int dn_expand(const u_char *msg, const u_char *eom, const u_char *src,
2655 char *dst, int dstsiz)
2657 int n = ns_name_uncompress(msg, eom, src, dst, (size_t)dstsiz);
2659 if (n > 0 && dst[0] == '.')
2663 libc_hidden_def(dn_expand)
2666 * Pack domain name 'exp_dn' in presentation form into 'comp_dn'.
2667 * Return the size of the compressed name or -1.
2668 * 'length' is the size of the array pointed to by 'comp_dn'.
2671 dn_comp(const char *src, u_char *dst, int dstsiz,
2672 u_char **dnptrs, u_char **lastdnptr)
2674 return ns_name_compress(src, dst, (size_t) dstsiz,
2675 (const u_char **) dnptrs,
2676 (const u_char **) lastdnptr);
2678 libc_hidden_def(dn_comp)
2679 #endif /* L_res_comp */
2684 /* Thinking in noninternationalized USASCII (per the DNS spec),
2685 * is this character visible and not a space when printed ?
2687 static int printable(int ch)
2689 return (ch > 0x20 && ch < 0x7f);
2691 /* Thinking in noninternationalized USASCII (per the DNS spec),
2692 * is this characted special ("in need of quoting") ?
2694 static int special(int ch)
2697 case 0x22: /* '"' */
2698 case 0x2E: /* '.' */
2699 case 0x3B: /* ';' */
2700 case 0x5C: /* '\\' */
2701 /* Special modifiers in zone files. */
2702 case 0x40: /* '@' */
2703 case 0x24: /* '$' */
2711 * ns_name_uncompress(msg, eom, src, dst, dstsiz)
2712 * Expand compressed domain name to presentation format.
2714 * Number of bytes read out of `src', or -1 (with errno set).
2716 * Root domain returns as "." not "".
2718 int ns_name_uncompress(const u_char *msg, const u_char *eom,
2719 const u_char *src, char *dst, size_t dstsiz)
2721 u_char tmp[NS_MAXCDNAME];
2724 n = ns_name_unpack(msg, eom, src, tmp, sizeof tmp);
2727 if (ns_name_ntop(tmp, dst, dstsiz) == -1)
2731 libc_hidden_def(ns_name_uncompress)
2734 * ns_name_ntop(src, dst, dstsiz)
2735 * Convert an encoded domain name to printable ascii as per RFC1035.
2737 * Number of bytes written to buffer, or -1 (with errno set)
2739 * The root is returned as "."
2740 * All other domains are returned in non absolute form
2742 int ns_name_ntop(const u_char *src, char *dst, size_t dstsiz)
2753 while ((n = *cp++) != 0) {
2754 if ((n & NS_CMPRSFLGS) != 0) {
2755 /* Some kind of compression pointer. */
2756 __set_errno(EMSGSIZE);
2761 __set_errno(EMSGSIZE);
2766 if (dn + n >= eom) {
2767 __set_errno(EMSGSIZE);
2770 for (; n > 0; n--) {
2773 if (dn + 1 >= eom) {
2774 __set_errno(EMSGSIZE);
2779 } else if (!printable(c)) {
2780 if (dn + 3 >= eom) {
2781 __set_errno(EMSGSIZE);
2785 *dn++ = "0123456789"[c / 100];
2787 *dn++ = "0123456789"[c / 10];
2788 *dn++ = "0123456789"[c % 10];
2791 __set_errno(EMSGSIZE);
2800 __set_errno(EMSGSIZE);
2806 __set_errno(EMSGSIZE);
2812 libc_hidden_def(ns_name_ntop)
2814 static int encode_bitstring(const char **bp, const char *end,
2815 unsigned char **labelp,
2816 unsigned char ** dst,
2817 unsigned const char *eom)
2820 const char *cp = *bp;
2822 const char *beg_blen;
2823 int value = 0, count = 0, tbcount = 0, blen = 0;
2827 /* a bitstring must contain at least 2 characters */
2831 /* XXX: currently, only hex strings are supported */
2834 if (!isxdigit((unsigned char) *cp)) /*%< reject '\[x/BLEN]' */
2837 for (tp = *dst + 1; cp < end && tp < eom; cp++) {
2838 unsigned char c = *cp;
2841 case ']': /*%< end of the bitstring */
2844 if (beg_blen == NULL)
2846 blen = (int)strtol(beg_blen, &end_blen, 10);
2847 if (*end_blen != ']')
2851 *tp++ = ((value << 4) & 0xff);
2852 cp++; /*%< skip ']' */
2859 if (!__isdigit_char(c))
2861 if (beg_blen == NULL) {
2863 /* blen never begings with 0 */
2869 if (!__isdigit_char(c)) {
2870 c = c | 0x20; /* lowercase */
2872 if (c > 5) /* not a-f? */
2891 if (cp >= end || tp >= eom)
2895 * bit length validation:
2896 * If a <length> is present, the number of digits in the <bit-data>
2897 * MUST be just sufficient to contain the number of bits specified
2898 * by the <length>. If there are insignificant bits in a final
2899 * hexadecimal or octal digit, they MUST be zero.
2900 * RFC2673, Section 3.2.
2905 if (((blen + 3) & ~3) != tbcount)
2907 traillen = tbcount - blen; /*%< between 0 and 3 */
2908 if (((value << (8 - traillen)) & 0xff) != 0)
2916 /* encode the type and the significant bit fields */
2917 **labelp = DNS_LABELTYPE_BITSTRING;
2926 int ns_name_pton(const char *src, u_char *dst, size_t dstsiz)
2928 static const char digits[] = "0123456789";
2929 u_char *label, *bp, *eom;
2930 int c, n, escaped, e = 0;
2938 while ((c = *src++) != 0) {
2940 if (c == '[') { /*%< start a bit string label */
2941 cp = strchr(src, ']');
2943 errno = EINVAL; /*%< ??? */
2946 e = encode_bitstring(&src, cp + 2,
2963 cp = strchr(digits, c);
2965 n = (cp - digits) * 100;
2969 cp = strchr(digits, c);
2972 n += (cp - digits) * 10;
2976 cp = strchr(digits, c);
2985 } else if (c == '\\') {
2988 } else if (c == '.') {
2989 c = (bp - label - 1);
2990 if ((c & NS_CMPRSFLGS) != 0) { /*%< Label too big. */
2997 /* Fully qualified ? */
3005 if ((bp - dst) > MAXCDNAME) {
3011 if (c == 0 || *src == '.') {
3022 c = (bp - label - 1);
3023 if ((c & NS_CMPRSFLGS) != 0) { /*%< Label too big. */
3037 if ((bp - dst) > MAXCDNAME) { /*%< src too big */
3047 libc_hidden_def(ns_name_pton)
3050 * ns_name_unpack(msg, eom, src, dst, dstsiz)
3051 * Unpack a domain name from a message, source may be compressed.
3053 * -1 if it fails, or consumed octets if it succeeds.
3055 int ns_name_unpack(const u_char *msg, const u_char *eom, const u_char *src,
3056 u_char *dst, size_t dstsiz)
3058 const u_char *srcp, *dstlim;
3060 int n, len, checked;
3066 dstlim = dst + dstsiz;
3067 if (srcp < msg || srcp >= eom) {
3068 __set_errno(EMSGSIZE);
3071 /* Fetch next label in domain name. */
3072 while ((n = *srcp++) != 0) {
3073 /* Check for indirection. */
3074 switch (n & NS_CMPRSFLGS) {
3077 if (dstp + n + 1 >= dstlim || srcp + n >= eom) {
3078 __set_errno(EMSGSIZE);
3083 memcpy(dstp, srcp, n);
3090 __set_errno(EMSGSIZE);
3094 len = srcp - src + 1;
3095 srcp = msg + (((n & 0x3f) << 8) | (*srcp & 0xff));
3096 if (srcp < msg || srcp >= eom) { /* Out of range. */
3097 __set_errno(EMSGSIZE);
3102 * Check for loops in the compressed name;
3103 * if we've looked at the whole message,
3104 * there must be a loop.
3106 if (checked >= eom - msg) {
3107 __set_errno(EMSGSIZE);
3113 __set_errno(EMSGSIZE);
3114 return -1; /* flag error */
3122 libc_hidden_def(ns_name_unpack)
3124 static int labellen(const unsigned char *lp)
3127 unsigned char l = *lp;
3129 if ((l & NS_CMPRSFLGS) == NS_CMPRSFLGS) {
3130 /* should be avoided by the caller */
3134 if ((l & NS_CMPRSFLGS) == NS_TYPE_ELT) {
3135 if (l == DNS_LABELTYPE_BITSTRING) {
3139 return ((bitlen + 7 ) / 8 + 1);
3142 return -1; /*%< unknwon ELT */
3148 static int mklower(int ch)
3150 if (ch >= 0x41 && ch <= 0x5A)
3156 static int dn_find(const unsigned char *domain,
3157 const unsigned char *msg,
3158 const unsigned char * const *dnptrs,
3159 const unsigned char * const *lastdnptr)
3161 const unsigned char *dn, *cp, *sp;
3162 const unsigned char * const *cpp;
3165 for (cpp = dnptrs; cpp < lastdnptr; cpp++) {
3168 * terminate search on:
3170 * compression pointer
3173 while (*sp != 0 && (*sp & NS_CMPRSFLGS) == 0 &&
3174 (sp - msg) < 0x4000) {
3178 while ((n = *cp++) != 0) {
3180 * check for indirection
3182 switch (n & NS_CMPRSFLGS) {
3183 case 0: /*%< normal case, n == len */
3184 n = labellen(cp - 1); /*%< XXX */
3189 if (mklower(*dn++) !=
3192 /* Is next root for both ? */
3193 if (*dn == '\0' && *cp == '\0')
3198 case NS_CMPRSFLGS: /*%< indirection */
3199 cp = msg + (((n & 0x3f) << 8) | *cp);
3202 default: /*%< illegal type */
3216 int ns_name_pack(const unsigned char *src,
3217 unsigned char *dst, int dstsiz,
3218 const unsigned char **dnptrs,
3219 const unsigned char **lastdnptr)
3221 unsigned char *dstp;
3222 const unsigned char **cpp, **lpp, *eob, *msg;
3223 const unsigned char *srcp;
3224 int n, l, first = 1;
3228 eob = dstp + dstsiz;
3231 if (dnptrs != NULL) {
3234 for (cpp = dnptrs; *cpp != NULL; cpp++)
3237 lpp = cpp; /*%< end of list to search */
3243 /* make sure the domain we are about to add is legal */
3249 if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) {
3254 l0 = labellen(srcp);
3261 if (l > MAXCDNAME) {
3269 /* from here on we need to reset compression pointer array on error */
3273 /* Look to see if we can use pointers. */
3276 if (n != 0 && msg != NULL) {
3277 l = dn_find(srcp, msg, (const unsigned char * const *) dnptrs,
3278 (const unsigned char * const *) lpp);
3280 if (dstp + 1 >= eob) {
3284 *dstp++ = ((u_int32_t)l >> 8) | NS_CMPRSFLGS;
3286 return (dstp - dst);
3289 /* Not found, save it. */
3290 if (lastdnptr != NULL && cpp < lastdnptr - 1 &&
3291 (dstp - msg) < 0x4000 && first) {
3298 /* copy label to buffer */
3299 if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) {
3300 /* Should not happen. */
3305 if (dstp + 1 + n >= eob) {
3309 memcpy(dstp, srcp, (size_t)(n + 1));
3325 libc_hidden_def(ns_name_pack)
3327 int ns_name_compress(const char *src,
3328 unsigned char *dst, size_t dstsiz,
3329 const unsigned char **dnptrs,
3330 const unsigned char **lastdnptr)
3332 unsigned char tmp[NS_MAXCDNAME];
3334 if (ns_name_pton(src, tmp, sizeof(tmp)) == -1)
3337 return ns_name_pack(tmp, dst, dstsiz, dnptrs, lastdnptr);
3339 libc_hidden_def(ns_name_compress)
3341 int ns_name_skip(const unsigned char **ptrptr,
3342 const unsigned char *eom)
3344 const unsigned char *cp;
3349 while (cp < eom && (n = *cp++) != 0) {
3350 /* Check for indirection. */
3351 switch (n & NS_CMPRSFLGS) {
3352 case 0: /*%< normal case, n == len */
3355 case NS_TYPE_ELT: /*%< EDNS0 extended label */
3356 l = labellen(cp - 1);
3358 errno = EMSGSIZE; /*%< XXX */
3363 case NS_CMPRSFLGS: /*%< indirection */
3366 default: /*%< illegal type */
3383 libc_hidden_def(ns_name_skip)
3385 int dn_skipname(const unsigned char *ptr, const unsigned char *eom)
3387 const unsigned char *saveptr = ptr;
3389 if (ns_name_skip(&ptr, eom) == -1)
3392 return ptr - saveptr;
3394 libc_hidden_def(dn_skipname)
3395 #endif /* L_ns_name */
3400 /* Will be called under __resolv_lock. */
3401 static void res_sync_func(void)
3403 struct __res_state *rp = &(_res);
3406 /* If we didn't get malloc failure earlier... */
3407 if (__nameserver != (void*) &__local_nameserver) {
3409 * if (__nameservers < rp->nscount) - try to grow __nameserver[]?
3411 #ifdef __UCLIBC_HAS_IPV6__
3412 if (__nameservers > rp->_u._ext.nscount)
3413 __nameservers = rp->_u._ext.nscount;
3416 __nameserver[n].sa6 = *rp->_u._ext.nsaddrs[n]; /* struct copy */
3417 #else /* IPv4 only */
3418 if (__nameservers > rp->nscount)
3419 __nameservers = rp->nscount;
3422 __nameserver[n].sa4 = rp->nsaddr_list[n]; /* struct copy */
3425 __resolv_timeout = rp->retrans ? : RES_TIMEOUT;
3426 __resolv_attempts = rp->retry ? : RES_DFLRETRY;
3427 /* Extend and comment what program is known
3428 * to use which _res.XXX member(s).
3430 __resolv_opts = rp->options;
3436 __res_vinit(res_state rp, int preinit)
3438 int i, n, options, retrans, retry, ndots;
3439 #ifdef __UCLIBC_HAS_IPV6__
3443 __UCLIBC_MUTEX_LOCK(__resolv_lock);
3444 __close_nameservers();
3445 __open_nameservers();
3448 options = rp->options;
3449 retrans = rp->retrans;
3454 memset(rp, 0, sizeof(*rp));
3457 rp->options = RES_DEFAULT;
3458 rp->retrans = RES_TIMEOUT;
3459 rp->retry = RES_DFLRETRY;
3462 rp->options = options;
3463 rp->retrans = retrans;
3468 #ifdef __UCLIBC_HAS_COMPAT_RES_STATE__
3469 /* Was: "rp->id = random();" but:
3470 * - random() pulls in largish static buffers
3471 * - isn't actually random unless, say, srandom(time(NULL)) was called
3472 * - is not used by uclibc anyway :)
3474 /* rp->id = 0; - memset did it */
3476 #ifdef __UCLIBC_HAS_EXTRA_COMPAT_RES_STATE__
3480 n = __searchdomains;
3481 if (n > ARRAY_SIZE(rp->dnsrch))
3482 n = ARRAY_SIZE(rp->dnsrch);
3483 for (i = 0; i < n; i++)
3484 rp->dnsrch[i] = __searchdomain[i];
3486 /* copy nameservers' addresses */
3488 #ifdef __UCLIBC_HAS_IPV4__
3490 while (n < ARRAY_SIZE(rp->nsaddr_list) && i < __nameservers) {
3491 if (__nameserver[i].sa.sa_family == AF_INET) {
3492 rp->nsaddr_list[n] = __nameserver[i].sa4; /* struct copy */
3493 #ifdef __UCLIBC_HAS_IPV6__
3494 if (m < ARRAY_SIZE(rp->_u._ext.nsaddrs)) {
3495 rp->_u._ext.nsaddrs[m] = (void*) &rp->nsaddr_list[n];
3501 #ifdef __UCLIBC_HAS_IPV6__
3502 if (__nameserver[i].sa.sa_family == AF_INET6
3503 && m < ARRAY_SIZE(rp->_u._ext.nsaddrs)
3505 struct sockaddr_in6 *sa6 = malloc(sizeof(*sa6));
3507 *sa6 = __nameserver[i].sa6; /* struct copy */
3508 rp->_u._ext.nsaddrs[m] = sa6;
3516 #ifdef __UCLIBC_HAS_IPV6__
3517 rp->_u._ext.nscount = m;
3520 #else /* IPv6 only */
3521 while (m < ARRAY_SIZE(rp->_u._ext.nsaddrs) && i < __nameservers) {
3522 struct sockaddr_in6 *sa6 = malloc(sizeof(*sa6));
3524 *sa6 = __nameserver[i].sa6; /* struct copy */
3525 rp->_u._ext.nsaddrs[m] = sa6;
3530 rp->_u._ext.nscount = m;
3533 rp->options |= RES_INIT;
3535 __UCLIBC_MUTEX_UNLOCK(__resolv_lock);
3542 __UCLIBC_MUTEX_LOCK(__resolv_lock);
3543 __close_nameservers();
3545 #ifdef __UCLIBC_HAS_IPV6__
3547 char *p1 = (char*) &(_res.nsaddr_list[0]);
3549 /* free nsaddrs[m] if they do not point to nsaddr_list[x] */
3550 while (m < ARRAY_SIZE(_res._u._ext.nsaddrs)) {
3551 char *p2 = (char*)(_res._u._ext.nsaddrs[m++]);
3552 if (p2 < p1 || (p2 - p1) > sizeof(_res.nsaddr_list))
3557 memset(&_res, 0, sizeof(_res));
3558 __UCLIBC_MUTEX_UNLOCK(__resolv_lock);
3562 * This routine is for closing the socket if a virtual circuit is used and
3563 * the program wants to close it. This provides support for endhostent()
3564 * which expects to close the socket.
3566 * This routine is not expected to be user visible.
3570 res_nclose(res_state statp)
3575 #ifdef __UCLIBC_HAS_BSD_RES_CLOSE__
3576 void res_close(void)
3582 /* This needs to be after the use of _res in res_init, above. */
3585 #ifndef __UCLIBC_HAS_THREADS__
3586 /* The resolver state for use by single-threaded programs.
3587 This differs from plain `struct __res_state _res;' in that it doesn't
3588 create a common definition, but a plain symbol that resides in .bss,
3589 which can have an alias. */
3590 struct __res_state _res __attribute__((section (".bss")));
3591 struct __res_state *__resp = &_res;
3592 #else /* __UCLIBC_HAS_THREADS__ */
3593 struct __res_state _res __attribute__((section (".bss"))) attribute_hidden;
3595 # if defined __UCLIBC_HAS_TLS__
3597 __thread struct __res_state *__resp = &_res;
3599 * FIXME: Add usage of hidden attribute for this when used in the shared
3600 * library. It currently crashes the linker when doing section
3603 extern __thread struct __res_state *__libc_resp
3604 __attribute__ ((alias ("__resp"))) attribute_hidden;
3607 struct __res_state *__resp = &_res;
3609 #endif /* !__UCLIBC_HAS_THREADS__ */
3614 return 0xffff & getpid();
3617 /* Our res_init never fails (always returns 0) */
3622 * These three fields used to be statically initialized. This made
3623 * it hard to use this code in a shared library. It is necessary,
3624 * now that we're doing dynamic initialization here, that we preserve
3625 * the old semantics: if an application modifies one of these three
3626 * fields of _res before res_init() is called, res_init() will not
3627 * alter them. Of course, if an application is setting them to
3628 * _zero_ before calling res_init(), hoping to override what used
3629 * to be the static default, we can't detect it and unexpected results
3630 * will follow. Zero for any of these fields would make no sense,
3631 * so one can safely assume that the applications were already getting
3632 * unexpected results.
3634 * _res.options is tricky since some apps were known to diddle the bits
3635 * before res_init() was first called. We can't replicate that semantic
3636 * with dynamic initialization (they may have turned bits off that are
3637 * set in RES_DEFAULT). Our solution is to declare such applications
3638 * "broken". They could fool us by setting RES_INIT but none do (yet).
3641 __UCLIBC_MUTEX_LOCK(__resolv_lock);
3644 _res.retrans = RES_TIMEOUT;
3647 if (!(_res.options & RES_INIT))
3648 _res.options = RES_DEFAULT;
3651 * This one used to initialize implicitly to zero, so unless the app
3652 * has set it to something in particular, we can randomize it now.
3655 _res.id = res_randomid();
3656 __res_sync = res_sync_func;
3658 __UCLIBC_MUTEX_UNLOCK(__resolv_lock);
3660 __res_vinit(&_res, 1);
3664 libc_hidden_def(res_init)
3667 * Set up default settings. If the configuration file exist, the values
3668 * there will have precedence. Otherwise, the server address is set to
3669 * INADDR_ANY and the default domain name comes from the gethostname().
3671 * An interrim version of this code (BIND 4.9, pre-4.4BSD) used 127.0.0.1
3672 * rather than INADDR_ANY ("0.0.0.0") as the default name server address
3673 * since it was noted that INADDR_ANY actually meant ``the first interface
3674 * you "ifconfig"'d at boot time'' and if this was a SLIP or PPP interface,
3675 * it had to be "up" in order for you to reach your own name server. It
3676 * was later decided that since the recommended practice is to always
3677 * install local static routes through 127.0.0.1 for all your network
3678 * interfaces, that we could solve this problem without a code change.
3680 * The configuration file should always be used, since it is the only way
3681 * to specify a default domain. If you are running a server on your local
3682 * machine, you should say "nameserver 0.0.0.0" or "nameserver 127.0.0.1"
3683 * in the configuration file.
3685 * Return 0 if completes successfully, -1 on error
3688 res_ninit(res_state statp)
3690 return __res_vinit(statp, 0);
3693 #endif /* L_res_init */
3696 # if defined __UCLIBC_HAS_TLS__
3697 struct __res_state *
3704 extern struct __res_state _res;
3706 /* When threaded, _res may be a per-thread variable. */
3707 struct __res_state *
3715 #endif /* L_res_state */
3720 int res_query(const char *dname, int class, int type,
3721 unsigned char *answer, int anslen)
3724 unsigned char *packet = NULL;
3725 struct resolv_answer a;
3727 if (!dname || class != 1 /* CLASS_IN */) {
3728 h_errno = NO_RECOVERY;
3732 memset(&a, '\0', sizeof(a));
3733 i = __dns_lookup(dname, type, &packet, &a);
3736 if (!h_errno) /* TODO: can this ever happen? */
3737 h_errno = TRY_AGAIN;
3743 if (a.atype == type) { /* CNAME */
3746 memcpy(answer, packet, i);
3751 libc_hidden_def(res_query)
3754 * Formulate a normal query, send, and retrieve answer in supplied buffer.
3755 * Return the size of the response on success, -1 on error.
3756 * If enabled, implement search rules until answer or unrecoverable failure
3757 * is detected. Error code, if any, is left in h_errno.
3759 #define __TRAILING_DOT (1<<0)
3760 #define __GOT_NODATA (1<<1)
3761 #define __GOT_SERVFAIL (1<<2)
3762 #define __TRIED_AS_IS (1<<3)
3763 int res_search(const char *name, int class, int type, u_char *answer,
3768 HEADER *hp = (HEADER *)(void *)answer;
3771 int ret, saved_herrno;
3772 uint32_t _res_options;
3773 unsigned _res_ndots;
3776 if (!name || !answer) {
3777 h_errno = NETDB_INTERNAL;
3782 __UCLIBC_MUTEX_LOCK(__resolv_lock);
3783 _res_options = _res.options;
3784 _res_ndots = _res.ndots;
3785 _res_dnsrch = _res.dnsrch;
3786 __UCLIBC_MUTEX_UNLOCK(__resolv_lock);
3787 if (!(_res_options & RES_INIT)) {
3788 res_init(); /* our res_init never fails */
3794 h_errno = HOST_NOT_FOUND; /* default, if we never query */
3796 for (cp = name; *cp; cp++)
3797 dots += (*cp == '.');
3799 if (cp > name && *--cp == '.')
3800 state |= __TRAILING_DOT;
3803 * If there are dots in the name already, let's just give it a try
3804 * 'as is'. The threshold can be set with the "ndots" option.
3807 if (dots >= _res_ndots) {
3808 ret = res_querydomain(name, NULL, class, type, answer, anslen);
3811 saved_herrno = h_errno;
3812 state |= __TRIED_AS_IS;
3816 * We do at least one level of search if
3817 * - there is no dot and RES_DEFNAME is set, or
3818 * - there is at least one dot, there is no trailing dot,
3819 * and RES_DNSRCH is set.
3821 if ((!dots && (_res_options & RES_DEFNAMES))
3822 || (dots && !(state & __TRAILING_DOT) && (_res_options & RES_DNSRCH))
3826 for (domain = _res_dnsrch; *domain && !done; domain++) {
3828 ret = res_querydomain(name, *domain, class, type,
3834 * If no server present, give up.
3835 * If name isn't found in this domain,
3836 * keep trying higher domains in the search list
3837 * (if that's enabled).
3838 * On a NO_DATA error, keep trying, otherwise
3839 * a wildcard entry of another type could keep us
3840 * from finding this entry higher in the domain.
3841 * If we get some other error (negative answer or
3842 * server failure), then stop searching up,
3843 * but try the input name below in case it's
3846 if (errno == ECONNREFUSED) {
3847 h_errno = TRY_AGAIN;
3853 state |= __GOT_NODATA;
3855 case HOST_NOT_FOUND:
3859 if (hp->rcode == SERVFAIL) {
3860 /* try next search element, if any */
3861 state |= __GOT_SERVFAIL;
3866 /* anything else implies that we're done */
3870 * if we got here for some reason other than DNSRCH,
3871 * we only wanted one iteration of the loop, so stop.
3873 if (!(_res_options & RES_DNSRCH))
3879 * if we have not already tried the name "as is", do that now.
3880 * note that we do this regardless of how many dots were in the
3881 * name or whether it ends with a dot.
3883 if (!(state & __TRIED_AS_IS)) {
3884 ret = res_querydomain(name, NULL, class, type, answer, anslen);
3890 * if we got here, we didn't satisfy the search.
3891 * if we did an initial full query, return that query's h_errno
3892 * (note that we wouldn't be here if that query had succeeded).
3893 * else if we ever got a nodata, send that back as the reason.
3894 * else send back meaningless h_errno, that being the one from
3895 * the last DNSRCH we did.
3897 if (saved_herrno != -1)
3898 h_errno = saved_herrno;
3899 else if (state & __GOT_NODATA)
3901 else if (state & __GOT_SERVFAIL)
3902 h_errno = TRY_AGAIN;
3905 #undef __TRAILING_DOT
3907 #undef __GOT_SERVFAIL
3908 #undef __TRIED_AS_IS
3910 * Perform a call on res_query on the concatenation of name and domain,
3911 * removing a trailing dot from name if domain is NULL.
3913 int res_querydomain(const char *name, const char *domain, int class, int type,
3914 u_char *answer, int anslen)
3916 char nbuf[MAXDNAME];
3917 const char *longname = nbuf;
3920 uint32_t _res_options;
3923 if (!name || !answer) {
3924 h_errno = NETDB_INTERNAL;
3930 __UCLIBC_MUTEX_LOCK(__resolv_lock);
3931 _res_options = _res.options;
3932 __UCLIBC_MUTEX_UNLOCK(__resolv_lock);
3933 if (!(_res_options & RES_INIT)) {
3934 res_init(); /* our res_init never fails */
3937 if (_res_options & RES_DEBUG)
3938 printf(";; res_querydomain(%s, %s, %d, %d)\n",
3939 name, (domain ? domain : "<Nil>"), class, type);
3941 if (domain == NULL) {
3943 * Check for trailing '.';
3944 * copy without '.' if present.
3947 if (n + 1 > sizeof(nbuf)) {
3948 h_errno = NO_RECOVERY;
3951 if (n > 0 && name[--n] == '.') {
3952 strncpy(nbuf, name, n);
3959 if (n + 1 + d + 1 > sizeof(nbuf)) {
3960 h_errno = NO_RECOVERY;
3963 snprintf(nbuf, sizeof(nbuf), "%s.%s", name, domain);
3965 return res_query(longname, class, type, answer, anslen);
3967 libc_hidden_def(res_querydomain)
3968 #endif /* L_res_query */
3971 unsigned int ns_get16(const unsigned char *src)
3978 unsigned long ns_get32(const unsigned char *src)
3985 void ns_put16(unsigned int src, unsigned char *dst)
3990 void ns_put32(unsigned long src, unsigned char *dst)
3994 #endif /* L_ns_netint */
3997 /* These need to be in the same order as the nres.h:ns_flag enum. */
3998 struct _ns_flagdata { unsigned short mask, shift; };
3999 static const struct _ns_flagdata _ns_flagdata[16] = {
4000 { 0x8000, 15 }, /*%< qr. */
4001 { 0x7800, 11 }, /*%< opcode. */
4002 { 0x0400, 10 }, /*%< aa. */
4003 { 0x0200, 9 }, /*%< tc. */
4004 { 0x0100, 8 }, /*%< rd. */
4005 { 0x0080, 7 }, /*%< ra. */
4006 { 0x0040, 6 }, /*%< z. */
4007 { 0x0020, 5 }, /*%< ad. */
4008 { 0x0010, 4 }, /*%< cd. */
4009 { 0x000f, 0 }, /*%< rcode. */
4010 { 0x0000, 0 }, /*%< expansion (1/6). */
4011 { 0x0000, 0 }, /*%< expansion (2/6). */
4012 { 0x0000, 0 }, /*%< expansion (3/6). */
4013 { 0x0000, 0 }, /*%< expansion (4/6). */
4014 { 0x0000, 0 }, /*%< expansion (5/6). */
4015 { 0x0000, 0 }, /*%< expansion (6/6). */
4018 static void setsection(ns_msg *msg, ns_sect sect)
4021 if (sect == ns_s_max) {
4026 msg->_ptr = msg->_sections[(int)sect];
4030 int ns_skiprr(const unsigned char *ptr,
4031 const unsigned char *eom,
4032 ns_sect section, int count)
4034 const u_char *optr = ptr;
4036 for (; count > 0; count--) {
4039 b = dn_skipname(ptr, eom);
4045 ptr += b/*Name*/ + NS_INT16SZ/*Type*/ + NS_INT16SZ/*Class*/;
4046 if (section != ns_s_qd) {
4047 if (ptr + NS_INT32SZ + NS_INT16SZ > eom) {
4052 ptr += NS_INT32SZ/*TTL*/;
4053 NS_GET16(rdlength, ptr);
4054 ptr += rdlength/*RData*/;
4065 libc_hidden_def(ns_skiprr)
4068 ns_initparse(const unsigned char *msg, int msglen, ns_msg *handle)
4070 const u_char *eom = msg + msglen;
4075 if (msg + NS_INT16SZ > eom) {
4080 NS_GET16(handle->_id, msg);
4081 if (msg + NS_INT16SZ > eom) {
4086 NS_GET16(handle->_flags, msg);
4087 for (i = 0; i < ns_s_max; i++) {
4088 if (msg + NS_INT16SZ > eom) {
4093 NS_GET16(handle->_counts[i], msg);
4095 for (i = 0; i < ns_s_max; i++)
4096 if (handle->_counts[i] == 0)
4097 handle->_sections[i] = NULL;
4099 int b = ns_skiprr(msg, eom, (ns_sect)i,
4100 handle->_counts[i]);
4104 handle->_sections[i] = msg;
4113 setsection(handle, ns_s_max);
4118 ns_parserr(ns_msg *handle, ns_sect section, int rrnum, ns_rr *rr)
4123 /* Make section right. */
4125 if (tmp < 0 || section >= ns_s_max) {
4130 if (section != handle->_sect)
4131 setsection(handle, section);
4133 /* Make rrnum right. */
4135 rrnum = handle->_rrnum;
4136 if (rrnum < 0 || rrnum >= handle->_counts[(int)section]) {
4140 if (rrnum < handle->_rrnum)
4141 setsection(handle, section);
4142 if (rrnum > handle->_rrnum) {
4143 b = ns_skiprr(handle->_ptr, handle->_eom, section,
4144 rrnum - handle->_rrnum);
4149 handle->_rrnum = rrnum;
4153 b = dn_expand(handle->_msg, handle->_eom,
4154 handle->_ptr, rr->name, NS_MAXDNAME);
4158 if (handle->_ptr + NS_INT16SZ + NS_INT16SZ > handle->_eom) {
4162 NS_GET16(rr->type, handle->_ptr);
4163 NS_GET16(rr->rr_class, handle->_ptr);
4164 if (section == ns_s_qd) {
4169 if (handle->_ptr + NS_INT32SZ + NS_INT16SZ > handle->_eom) {
4173 NS_GET32(rr->ttl, handle->_ptr);
4174 NS_GET16(rr->rdlength, handle->_ptr);
4175 if (handle->_ptr + rr->rdlength > handle->_eom) {
4179 rr->rdata = handle->_ptr;
4180 handle->_ptr += rr->rdlength;
4182 if (++handle->_rrnum > handle->_counts[(int)section])
4183 setsection(handle, (ns_sect)((int)section + 1));
4188 int ns_msg_getflag(ns_msg handle, int flag)
4190 return ((handle)._flags & _ns_flagdata[flag].mask) >> _ns_flagdata[flag].shift;
4192 #endif /* L_ns_parse */
4195 int res_mkquery(int op, const char *dname, int class, int type,
4196 const unsigned char *data, int datalen,
4197 const unsigned char *newrr_in,
4198 unsigned char *buf, int buflen)
4201 unsigned char *cp, *ep;
4202 unsigned char *dnptrs[20], **dpp, **lastdnptr;
4203 uint32_t _res_options;
4206 if (!buf || buflen < HFIXEDSZ) {
4207 h_errno = NETDB_INTERNAL;
4212 __UCLIBC_MUTEX_LOCK(__resolv_lock);
4213 _res_options = _res.options;
4214 __UCLIBC_MUTEX_UNLOCK(__resolv_lock);
4215 if (!(_res_options & RES_INIT)) {
4216 res_init(); /* our res_init never fails */
4221 if (_res_options & RES_DEBUG)
4222 printf(";; res_mkquery(%d, %s, %d, %d)\n",
4223 op, dname && *dname ? dname : "<null>", class, type);
4226 memset(buf, 0, HFIXEDSZ);
4227 hp = (HEADER *) buf;
4228 hp->id = getpid() & 0xffff;
4230 hp->rd = (_res.options & RES_RECURSE) != 0U;
4231 hp->rcode = NOERROR;
4233 cp = buf + HFIXEDSZ;
4238 lastdnptr = dnptrs + sizeof dnptrs / sizeof dnptrs[0];
4241 * perform opcode specific processing
4246 if (ep - cp < QFIXEDSZ)
4249 n = dn_comp(dname, cp, ep - cp - QFIXEDSZ, dnptrs, lastdnptr);
4255 NS_PUT16(class, cp);
4256 hp->qdcount = htons(1);
4258 if (op == QUERY || data == NULL)
4262 * Make an additional record for completion domain.
4264 if ((ep - cp) < RRFIXEDSZ)
4267 n = dn_comp((const char *)data, cp, ep - cp - RRFIXEDSZ,
4273 NS_PUT16(T_NULL, cp);
4274 NS_PUT16(class, cp);
4277 hp->arcount = htons(1);
4283 * Initialize answer section
4285 if (ep - cp < 1 + RRFIXEDSZ + datalen)
4288 *cp++ = '\0'; /*%< no domain name */
4290 NS_PUT16(class, cp);
4292 NS_PUT16(datalen, cp);
4295 memcpy(cp, data, (size_t)datalen);
4299 hp->ancount = htons(1);
4308 #endif /* L_res_data */
4310 /* Unimplemented: */