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
298 #include <stdio_ext.h>
301 #include <sys/poll.h>
302 #include <sys/socket.h>
303 #include <sys/types.h>
304 #include <sys/time.h>
305 #include <netinet/in.h>
306 #include <arpa/inet.h>
314 #include <arpa/nameser.h>
315 #include <sys/utsname.h>
317 #include <sys/stat.h>
318 #include <sys/param.h>
319 #include <bits/uClibc_mutex.h>
320 #include "internal/parse_config.h"
322 /* poll() is not supported in kernel <= 2.0, therefore if __NR_poll is
323 * not available, we assume an old Linux kernel is in use and we will
324 * use select() instead. */
325 #include <sys/syscall.h>
330 #if defined __UCLIBC_HAS_IPV4__ && defined __UCLIBC_HAS_IPV6__
331 #define IF_HAS_BOTH(...) __VA_ARGS__
333 #define IF_HAS_BOTH(...)
337 #define MAX_RECURSE 5
338 #define MAXALIASES (4)
339 #define BUFSZ (80) /* one line */
341 #define NS_TYPE_ELT 0x40 /*%< EDNS0 extended label type */
342 #define DNS_LABELTYPE_BITSTRING 0x41
348 #define DPRINTF(X,args...) fprintf(stderr, X, ##args)
350 #define DPRINTF(X,args...)
353 /* Make sure the incoming char * buffer is aligned enough to handle our random
354 * structures. This define is the same as we use for malloc alignment (which
355 * has same requirements). The offset is the number of bytes we need to adjust
356 * in order to attain desired alignment.
358 #define ALIGN_ATTR __alignof__(double __attribute_aligned__ (sizeof(size_t)))
359 #define ALIGN_BUFFER_OFFSET(buf) ((ALIGN_ATTR - ((size_t)buf % ALIGN_ATTR)) % ALIGN_ATTR)
363 struct resolv_header
{
365 int qr
, opcode
, aa
, tc
, rd
, ra
, rcode
;
372 struct resolv_question
{
378 struct resolv_answer
{
384 const unsigned char *rdata
;
391 enum etc_hosts_action
{
392 GET_HOSTS_BYNAME
= 0,
397 typedef union sockaddr46_t
{
399 #ifdef __UCLIBC_HAS_IPV4__
400 struct sockaddr_in sa4
;
402 #ifdef __UCLIBC_HAS_IPV6__
403 struct sockaddr_in6 sa6
;
408 __UCLIBC_MUTEX_EXTERN(__resolv_lock
) attribute_hidden
;
410 /* Protected by __resolv_lock */
411 extern void (*__res_sync
)(void) attribute_hidden
;
412 /*extern uint32_t __resolv_opts attribute_hidden; */
413 extern uint8_t __resolv_timeout attribute_hidden
;
414 extern uint8_t __resolv_attempts attribute_hidden
;
415 extern unsigned __nameservers attribute_hidden
;
416 extern unsigned __searchdomains attribute_hidden
;
417 extern sockaddr46_t
*__nameserver attribute_hidden
;
418 extern char **__searchdomain attribute_hidden
;
419 #ifdef __UCLIBC_HAS_IPV4__
420 extern const struct sockaddr_in __local_nameserver attribute_hidden
;
422 extern const struct sockaddr_in6 __local_nameserver attribute_hidden
;
425 #define MAXLEN_searchdomain 128
428 /* prototypes for internal functions */
429 extern void endhostent_unlocked(void) attribute_hidden
;
430 extern int __get_hosts_byname_r(const char *name
,
432 struct hostent
*result_buf
,
435 struct hostent
**result
,
436 int *h_errnop
) attribute_hidden
;
437 extern int __get_hosts_byaddr_r(const char *addr
,
440 struct hostent
*result_buf
,
443 struct hostent
**result
,
444 int *h_errnop
) attribute_hidden
;
445 extern parser_t
*__open_etc_hosts(void) attribute_hidden
;
446 extern int __read_etc_hosts_r(parser_t
*parser
,
449 enum etc_hosts_action action
,
450 struct hostent
*result_buf
,
453 struct hostent
**result
,
454 int *h_errnop
) attribute_hidden
;
455 extern int __dns_lookup(const char *name
,
457 unsigned char **outpacket
,
458 struct resolv_answer
*a
) attribute_hidden
;
459 extern int __encode_dotted(const char *dotted
,
461 int maxlen
) attribute_hidden
;
462 extern int __decode_dotted(const unsigned char *packet
,
466 int dest_len
) attribute_hidden
;
467 extern int __encode_header(struct resolv_header
*h
,
469 int maxlen
) attribute_hidden
;
470 extern void __decode_header(unsigned char *data
,
471 struct resolv_header
*h
) attribute_hidden
;
472 extern int __encode_question(const struct resolv_question
*q
,
474 int maxlen
) attribute_hidden
;
475 extern int __encode_answer(struct resolv_answer
*a
,
477 int maxlen
) attribute_hidden
;
478 extern void __open_nameservers(void) attribute_hidden
;
479 extern void __close_nameservers(void) attribute_hidden
;
482 * Theory of operation.
484 * gethostbyname, getaddrinfo and friends end up here, and they sometimes
485 * need to talk to DNS servers. In order to do this, we need to read /etc/resolv.conf
486 * and determine servers' addresses and the like. resolv.conf format:
488 * nameserver <IP[v6]>
489 * Address of DNS server. Cumulative.
490 * If not specified, assumed to be on localhost.
491 * search <domain1>[ <domain2>]...
492 * Append these domains to unqualified names.
493 * See ndots:n option.
494 * $LOCALDOMAIN (space-separated list) overrides this.
496 * Effectively same as "search" with one domain.
497 * If no "domain" line is present, the domain is determined
498 * from the local host name returned by gethostname();
499 * the domain part is taken to be everything after the first dot.
500 * If there are no dots, there will be no "domain".
501 * The domain and search keywords are mutually exclusive.
502 * If more than one instance of these keywords is present,
503 * the last instance wins.
504 * sortlist 130.155.160.0[/255.255.240.0] 130.155.0.0
505 * Allows addresses returned by gethostbyname to be sorted.
507 * options option[ option]...
508 * (so far we support timeout:n and attempts:n)
509 * $RES_OPTIONS (space-separated list) is to be added to "options"
510 * debug sets RES_DEBUG in _res.options
511 * ndots:n how many dots there should be so that name will be tried
512 * first as an absolute name before any search list elements
513 * are appended to it. Default 1
514 * timeout:n how long to wait for response. Default 5
515 * (sun seems to have retrans:n synonym)
516 * attempts:n number of rounds to do before giving up and returning
517 * an error. Default 2
518 * (sun seems to have retry:n synonym)
519 * rotate sets RES_ROTATE in _res.options, round robin
520 * selection of nameservers. Otherwise try
521 * the first listed server first every time
523 * sets RES_NOCHECKNAME in _res.options, which disables
524 * checking of incoming host names for invalid characters
525 * such as underscore (_), non-ASCII, or control characters
526 * inet6 sets RES_USE_INET6 in _res.options. Try a AAAA query
527 * before an A query inside the gethostbyname(), and map
528 * IPv4 responses in IPv6 "tunnelled form" if no AAAA records
529 * are found but an A record set exists
530 * no_tld_query (FreeBSDism?)
531 * do not attempt to resolve names without dots
533 * We will read and analyze /etc/resolv.conf as needed before
534 * we do a DNS request. This happens in __dns_lookup.
535 * It is reread if its mtime is changed.
537 * BSD has res_init routine which is used to initialize resolver state
538 * which is held in global structure _res.
539 * Generally, programs call res_init, then fiddle with _res.XXX
540 * (_res.options and _res.nscount, _res.nsaddr_list[N]
541 * are popular targets of fiddling) and expect subsequent calls
542 * to gethostbyname, getaddrinfo, etc to use modified information.
544 * However, historical _res structure is quite awkward.
545 * Using it for storing /etc/resolv.conf info is not desirable,
546 * and __dns_lookup does not use it.
548 * We would like to avoid using it unless absolutely necessary.
549 * If user doesn't use res_init, we should arrange it so that
550 * _res structure doesn't even *get linked in* into user's application
551 * (imagine static uclibc build here).
553 * The solution is a __res_sync function pointer, which is normally NULL.
554 * But if res_init is called, it gets set and any subsequent gethostbyname
555 * et al "syncronizes" our internal structures with potentially
556 * modified _res.XXX stuff by calling __res_sync.
557 * The trick here is that if res_init is not used and not linked in,
558 * gethostbyname itself won't reference _res and _res won't be linked in
559 * either. Other possible methods like
560 * if (__res_sync_just_an_int_flag)
561 * __sync_me_with_res()
562 * would pull in __sync_me_with_res, which pulls in _res. Bad.
568 int __encode_header(struct resolv_header
*h
, unsigned char *dest
, int maxlen
)
570 if (maxlen
< HFIXEDSZ
)
573 dest
[0] = (h
->id
& 0xff00) >> 8;
574 dest
[1] = (h
->id
& 0x00ff) >> 0;
575 dest
[2] = (h
->qr
? 0x80 : 0) |
576 ((h
->opcode
& 0x0f) << 3) |
580 dest
[3] = (h
->ra
? 0x80 : 0) | (h
->rcode
& 0x0f);
581 dest
[4] = (h
->qdcount
& 0xff00) >> 8;
582 dest
[5] = (h
->qdcount
& 0x00ff) >> 0;
583 dest
[6] = (h
->ancount
& 0xff00) >> 8;
584 dest
[7] = (h
->ancount
& 0x00ff) >> 0;
585 dest
[8] = (h
->nscount
& 0xff00) >> 8;
586 dest
[9] = (h
->nscount
& 0x00ff) >> 0;
587 dest
[10] = (h
->arcount
& 0xff00) >> 8;
588 dest
[11] = (h
->arcount
& 0x00ff) >> 0;
592 #endif /* L_encodeh */
597 void __decode_header(unsigned char *data
,
598 struct resolv_header
*h
)
600 h
->id
= (data
[0] << 8) | data
[1];
601 h
->qr
= (data
[2] & 0x80) ? 1 : 0;
602 h
->opcode
= (data
[2] >> 3) & 0x0f;
603 h
->aa
= (data
[2] & 0x04) ? 1 : 0;
604 h
->tc
= (data
[2] & 0x02) ? 1 : 0;
605 h
->rd
= (data
[2] & 0x01) ? 1 : 0;
606 h
->ra
= (data
[3] & 0x80) ? 1 : 0;
607 h
->rcode
= data
[3] & 0x0f;
608 h
->qdcount
= (data
[4] << 8) | data
[5];
609 h
->ancount
= (data
[6] << 8) | data
[7];
610 h
->nscount
= (data
[8] << 8) | data
[9];
611 h
->arcount
= (data
[10] << 8) | data
[11];
613 #endif /* L_decodeh */
618 /* Encode a dotted string into nameserver transport-level encoding.
619 This routine is fairly dumb, and doesn't attempt to compress
621 int __encode_dotted(const char *dotted
, unsigned char *dest
, int maxlen
)
625 while (dotted
&& *dotted
) {
626 char *c
= strchr(dotted
, '.');
627 int l
= c
? c
- dotted
: strlen(dotted
);
629 /* two consecutive dots are not valid */
633 if (l
>= (maxlen
- used
- 1))
637 memcpy(dest
+ used
, dotted
, l
);
652 #endif /* L_encoded */
657 /* Decode a dotted string from nameserver transport-level encoding.
658 This routine understands compressed data. */
659 int __decode_dotted(const unsigned char *packet
,
674 if (offset
>= packet_len
)
676 b
= packet
[offset
++];
683 if ((b
& 0xc0) == 0xc0) {
684 if (offset
>= packet_len
)
688 /* compressed item, redirect */
689 offset
= ((b
& 0x3f) << 8) | packet
[offset
];
694 if (used
+ b
+ 1 >= dest_len
)
696 if (offset
+ b
>= packet_len
)
698 memcpy(dest
+ used
, packet
+ offset
, b
);
705 if (packet
[offset
] != 0)
711 /* The null byte must be counted too */
715 DPRINTF("Total decode len = %d\n", total
);
719 #endif /* L_decoded */
724 int __encode_question(const struct resolv_question
*q
,
730 i
= __encode_dotted(q
->dotted
, dest
, maxlen
);
740 dest
[0] = (q
->qtype
& 0xff00) >> 8;
741 dest
[1] = (q
->qtype
& 0x00ff) >> 0;
742 dest
[2] = (q
->qclass
& 0xff00) >> 8;
743 dest
[3] = (q
->qclass
& 0x00ff) >> 0;
747 #endif /* L_encodeq */
752 int __encode_answer(struct resolv_answer
*a
, unsigned char *dest
, int maxlen
)
756 i
= __encode_dotted(a
->dotted
, dest
, maxlen
);
763 if (maxlen
< (RRFIXEDSZ
+ a
->rdlength
))
766 *dest
++ = (a
->atype
& 0xff00) >> 8;
767 *dest
++ = (a
->atype
& 0x00ff) >> 0;
768 *dest
++ = (a
->aclass
& 0xff00) >> 8;
769 *dest
++ = (a
->aclass
& 0x00ff) >> 0;
770 *dest
++ = (a
->ttl
& 0xff000000) >> 24;
771 *dest
++ = (a
->ttl
& 0x00ff0000) >> 16;
772 *dest
++ = (a
->ttl
& 0x0000ff00) >> 8;
773 *dest
++ = (a
->ttl
& 0x000000ff) >> 0;
774 *dest
++ = (a
->rdlength
& 0xff00) >> 8;
775 *dest
++ = (a
->rdlength
& 0x00ff) >> 0;
776 memcpy(dest
, a
->rdata
, a
->rdlength
);
778 return i
+ RRFIXEDSZ
+ a
->rdlength
;
780 #endif /* L_encodea */
783 #ifdef CURRENTLY_UNUSED
786 int __encode_packet(struct resolv_header
*h
,
787 struct resolv_question
**q
,
788 struct resolv_answer
**an
,
789 struct resolv_answer
**ns
,
790 struct resolv_answer
**ar
,
791 unsigned char *dest
, int maxlen
) attribute_hidden
;
792 int __encode_packet(struct resolv_header
*h
,
793 struct resolv_question
**q
,
794 struct resolv_answer
**an
,
795 struct resolv_answer
**ns
,
796 struct resolv_answer
**ar
,
797 unsigned char *dest
, int maxlen
)
802 i
= __encode_header(h
, dest
, maxlen
);
810 for (j
= 0; j
< h
->qdcount
; j
++) {
811 i
= __encode_question(q
[j
], dest
, maxlen
);
819 for (j
= 0; j
< h
->ancount
; j
++) {
820 i
= __encode_answer(an
[j
], dest
, maxlen
);
827 for (j
= 0; j
< h
->nscount
; j
++) {
828 i
= __encode_answer(ns
[j
], dest
, maxlen
);
835 for (j
= 0; j
< h
->arcount
; j
++) {
836 i
= __encode_answer(ar
[j
], dest
, maxlen
);
846 #endif /* L_encodep */
851 int __decode_packet(unsigned char *data
, struct resolv_header
*h
) attribute_hidden
;
852 int __decode_packet(unsigned char *data
, struct resolv_header
*h
)
854 __decode_header(data
, h
);
857 #endif /* L_decodep */
862 int __form_query(int id
,
865 unsigned char *packet
,
866 int maxlen
) attribute_hidden
;
867 int __form_query(int id
,
870 unsigned char *packet
,
873 struct resolv_header h
;
874 struct resolv_question q
;
877 memset(&h
, 0, sizeof(h
));
881 q
.dotted
= (char *) name
;
883 q
.qclass
= C_IN
; /* CLASS_IN */
885 i
= __encode_header(&h
, packet
, maxlen
);
889 j
= __encode_question(&q
, packet
+ i
, maxlen
- i
);
895 #endif /* L_formquery */
896 #endif /* CURRENTLY_UNUSED */
899 #ifdef L_opennameservers
901 # if __BYTE_ORDER == __LITTLE_ENDIAN
902 #define NAMESERVER_PORT_N (__bswap_constant_16(NAMESERVER_PORT))
904 #define NAMESERVER_PORT_N NAMESERVER_PORT
907 __UCLIBC_MUTEX_INIT(__resolv_lock
, PTHREAD_MUTEX_INITIALIZER
);
909 /* Protected by __resolv_lock */
910 void (*__res_sync
)(void);
911 /*uint32_t __resolv_opts; */
912 uint8_t __resolv_timeout
= RES_TIMEOUT
;
913 uint8_t __resolv_attempts
= RES_DFLRETRY
;
914 unsigned __nameservers
;
915 unsigned __searchdomains
;
916 sockaddr46_t
*__nameserver
;
917 char **__searchdomain
;
918 #ifdef __UCLIBC_HAS_IPV4__
919 const struct sockaddr_in __local_nameserver
= {
920 .sin_family
= AF_INET
,
921 .sin_port
= NAMESERVER_PORT_N
,
924 const struct sockaddr_in6 __local_nameserver
= {
925 .sin6_family
= AF_INET6
,
926 .sin6_port
= NAMESERVER_PORT_N
,
930 /* Helpers. Both stop on EOL, if it's '\n', it is converted to NUL first */
931 static char *skip_nospace(char *p
)
933 while (*p
!= '\0' && !isspace(*p
)) {
942 static char *skip_and_NUL_space(char *p
)
944 /* NB: '\n' is not isspace! */
947 if (c
== '\0' || !isspace(c
))
950 if (c
== '\n' || c
== '#')
957 /* Must be called under __resolv_lock. */
958 void __open_nameservers(void)
960 static uint32_t resolv_conf_mtime
;
962 char szBuffer
[MAXLEN_searchdomain
];
968 /* Reread /etc/resolv.conf if it was modified. */
970 if (stat("/etc/resolv.conf", &sb
) != 0)
972 if (resolv_conf_mtime
!= (uint32_t)sb
.st_mtime
) {
973 resolv_conf_mtime
= sb
.st_mtime
;
974 __close_nameservers(); /* force config reread */
981 __resolv_timeout
= RES_TIMEOUT
;
982 __resolv_attempts
= RES_DFLRETRY
;
984 fp
= fopen("/etc/resolv.conf", "r");
985 #ifdef FALLBACK_TO_CONFIG_RESOLVCONF
987 /* If we do not have a pre-populated /etc/resolv.conf then
988 try to use the one from /etc/config which exists on numerous
989 systems ranging from some uClinux to IRIX installations and
990 may be the only /etc dir that was mounted rw. */
991 fp
= fopen("/etc/config/resolv.conf", "r");
996 while (fgets(szBuffer
, sizeof(szBuffer
), fp
) != NULL
) {
1000 keyword
= p
= skip_and_NUL_space(szBuffer
);
1002 p
= skip_nospace(p
);
1003 /* find next word */
1004 p
= skip_and_NUL_space(p
);
1006 if (strcmp(keyword
, "nameserver") == 0) {
1007 /* terminate IP addr */
1008 *skip_nospace(p
) = '\0';
1009 memset(&sa
, 0, sizeof(sa
));
1010 if (0) /* nothing */;
1011 #ifdef __UCLIBC_HAS_IPV6__
1012 else if (inet_pton(AF_INET6
, p
, &sa
.sa6
.sin6_addr
) > 0) {
1013 sa
.sa6
.sin6_family
= AF_INET6
;
1014 sa
.sa6
.sin6_port
= htons(NAMESERVER_PORT
);
1017 #ifdef __UCLIBC_HAS_IPV4__
1018 else if (inet_pton(AF_INET
, p
, &sa
.sa4
.sin_addr
) > 0) {
1019 sa
.sa4
.sin_family
= AF_INET
;
1020 sa
.sa4
.sin_port
= htons(NAMESERVER_PORT
);
1024 continue; /* garbage on this line */
1025 ptr
= realloc(__nameserver
, (__nameservers
+ 1) * sizeof(__nameserver
[0]));
1029 __nameserver
[__nameservers
++] = sa
; /* struct copy */
1032 if (strcmp(keyword
, "domain") == 0 || strcmp(keyword
, "search") == 0) {
1035 /* free old domains ("last 'domain' or 'search' wins" rule) */
1036 while (__searchdomains
)
1037 free(__searchdomain
[--__searchdomains
]);
1038 /*free(__searchdomain);*/
1039 /*__searchdomain = NULL; - not necessary */
1041 /* terminate current word */
1042 p1
= skip_nospace(p
);
1043 /* find next word (maybe) */
1044 p1
= skip_and_NUL_space(p1
);
1046 ptr
= realloc(__searchdomain
, (__searchdomains
+ 1) * sizeof(__searchdomain
[0]));
1049 __searchdomain
= ptr
;
1050 /* NB: strlen(p) <= MAXLEN_searchdomain) because szBuffer[] is smaller */
1054 DPRINTF("adding search %s\n", (char*)ptr
);
1055 __searchdomain
[__searchdomains
++] = (char*)ptr
;
1061 /* if (strcmp(keyword, "sortlist") == 0)... */
1062 if (strcmp(keyword
, "options") == 0) {
1066 if (p
== NULL
|| (p1
= strchr(p
, ':')) == NULL
)
1069 if (strcmp(p
, "timeout") == 0)
1070 what
= &__resolv_timeout
;
1071 else if (strcmp(p
, "attempts") == 0)
1072 what
= &__resolv_attempts
;
1076 DPRINTF("option %s:%d\n", p
, *what
);
1081 if (__nameservers
== 0) {
1082 /* Have to handle malloc failure! What a mess...
1083 * And it's not only here, we need to be careful
1084 * to never write into __nameserver[0] if it points
1085 * to constant __local_nameserver, or free it. */
1086 __nameserver
= malloc(sizeof(__nameserver
[0]));
1088 memcpy(__nameserver
, &__local_nameserver
, sizeof(__local_nameserver
));
1090 __nameserver
= (void*) &__local_nameserver
;
1093 if (__searchdomains
== 0) {
1096 i
= gethostname(buf
, sizeof(buf
) - 1);
1097 buf
[sizeof(buf
) - 1] = '\0';
1098 if (i
== 0 && (p
= strchr(buf
, '.')) != NULL
&& p
[1]) {
1102 __searchdomain
= malloc(sizeof(__searchdomain
[0]));
1103 if (!__searchdomain
) {
1107 __searchdomain
[0] = p
;
1112 DPRINTF("nameservers = %d\n", __nameservers
);
1118 #endif /* L_opennameservers */
1121 #ifdef L_closenameservers
1123 /* Must be called under __resolv_lock. */
1124 void __close_nameservers(void)
1126 if (__nameserver
!= (void*) &__local_nameserver
)
1128 __nameserver
= NULL
;
1130 while (__searchdomains
)
1131 free(__searchdomain
[--__searchdomains
]);
1132 free(__searchdomain
);
1133 __searchdomain
= NULL
;
1134 /*__searchdomains = 0; - already is */
1136 #endif /* L_closenameservers */
1142 static int __length_question(const unsigned char *data
, int maxlen
)
1144 const unsigned char *start
;
1157 if ((b
& 0xc0) == 0xc0) {
1158 /* It's a "compressed" name. */
1159 data
++; /* skip lsb of redirected offset */
1164 maxlen
-= (b
+ 1); /* account for data++ above */
1166 /* Up to here we were skipping encoded name */
1168 /* Account for QTYPE and QCLASS fields */
1171 return data
- start
+ 2 + 2;
1174 static int __decode_answer(const unsigned char *message
, /* packet */
1176 int len
, /* total packet len */
1177 struct resolv_answer
*a
)
1182 DPRINTF("decode_answer(start): off %d, len %d\n", offset
, len
);
1183 i
= __decode_dotted(message
, offset
, len
, temp
, sizeof(temp
));
1187 message
+= offset
+ i
;
1188 len
-= i
+ RRFIXEDSZ
+ offset
;
1190 DPRINTF("decode_answer: off %d, len %d, i %d\n", offset
, len
, i
);
1194 /* TODO: what if strdup fails? */
1195 a
->dotted
= strdup(temp
);
1196 a
->atype
= (message
[0] << 8) | message
[1];
1198 a
->aclass
= (message
[0] << 8) | message
[1];
1200 a
->ttl
= (message
[0] << 24) |
1201 (message
[1] << 16) | (message
[2] << 8) | (message
[3] << 0);
1203 a
->rdlength
= (message
[0] << 8) | message
[1];
1206 a
->rdoffset
= offset
+ i
+ RRFIXEDSZ
;
1208 DPRINTF("i=%d,rdlength=%d\n", i
, a
->rdlength
);
1210 if (len
< a
->rdlength
)
1212 return i
+ RRFIXEDSZ
+ a
->rdlength
;
1216 * a.buf(len) = auxiliary buffer for IP addresses after first one
1217 * a.add_count = how many additional addresses are there already
1218 * outpacket = where to save ptr to raw packet? can be NULL
1220 * ret < 0: error, all other data is not valid
1221 * ret >= 0: length of reply packet
1222 * a.add_count & a.buf: updated
1223 * a.rdlength: length of addresses (4 bytes for IPv4)
1224 * *outpacket: updated (packet is malloced, you need to free it)
1225 * a.rdata: points into *outpacket to 1st IP addr
1226 * NB: don't pass outpacket == NULL if you need to use a.rdata!
1227 * a.atype: type of query?
1228 * a.dotted: which name we _actually_ used. May contain search domains
1229 * appended. (why the filed is called "dotted" I have no idea)
1230 * This is a malloced string. May be NULL because strdup failed.
1232 int __dns_lookup(const char *name
,
1234 unsigned char **outpacket
,
1235 struct resolv_answer
*a
)
1237 /* Protected by __resolv_lock: */
1238 static int last_ns_num
= 0;
1239 static uint16_t last_id
= 1;
1250 struct resolv_header h
;
1251 struct resolv_question q
;
1252 struct resolv_answer ma
;
1253 bool first_answer
= 1;
1255 unsigned char *packet
= malloc(PACKETSZ
);
1257 int variant
= -1; /* search domain to append, -1: none */
1258 int local_ns_num
= -1; /* Nth server to use */
1259 int local_id
= local_id
; /* for compiler */
1266 name_len
= strlen(name
);
1267 if ((unsigned)name_len
>= MAXDNAME
- MAXLEN_searchdomain
- 2)
1268 goto fail
; /* paranoia */
1269 lookup
= malloc(name_len
+ 1/*for '.'*/ + MAXLEN_searchdomain
+ 1);
1270 if (!packet
|| !lookup
|| !name
[0])
1272 ends_with_dot
= (name
[name_len
- 1] == '.');
1273 /* no strcpy! paranoia, user might change name[] under us */
1274 memcpy(lookup
, name
, name_len
);
1276 DPRINTF("Looking up type %d answer for '%s'\n", type
, name
);
1277 retries_left
= 0; /* for compiler */
1280 unsigned reply_timeout
;
1287 /* Mess with globals while under lock */
1288 /* NB: even data *pointed to* by globals may vanish
1289 * outside the locks. We should assume any and all
1290 * globals can completely change between locked
1291 * code regions. OTOH, this is rare, so we don't need
1292 * to handle it "nicely" (do not skip servers,
1293 * search domains, etc), we only need to ensure
1294 * we do not SEGV, use freed+overwritten data
1295 * or do other Really Bad Things. */
1296 __UCLIBC_MUTEX_LOCK(__resolv_lock
);
1297 __open_nameservers();
1298 sdomains
= __searchdomains
;
1299 lookup
[name_len
] = '\0';
1300 if ((unsigned)variant
< sdomains
) {
1301 /* lookup is name_len + 1 + MAXLEN_searchdomain + 1 long */
1302 /* __searchdomain[] is not bigger than MAXLEN_searchdomain */
1303 lookup
[name_len
] = '.';
1304 strcpy(&lookup
[name_len
+ 1], __searchdomain
[variant
]);
1306 /* first time? pick starting server etc */
1307 if (local_ns_num
< 0) {
1309 /*TODO: implement /etc/resolv.conf's "options rotate"
1310 (a.k.a. RES_ROTATE bit in _res.options)
1312 if (_res.options & RES_ROTATE) */
1313 local_ns_num
= last_ns_num
;
1314 retries_left
= __nameservers
* __resolv_attempts
;
1317 if (local_ns_num
>= __nameservers
)
1321 /* write new values back while still under lock */
1323 last_ns_num
= local_ns_num
;
1325 /* can't just take a pointer, __nameserver[x]
1326 * is not safe to use outside of locks */
1327 sa
= __nameserver
[local_ns_num
];
1328 __UCLIBC_MUTEX_UNLOCK(__resolv_lock
);
1330 memset(packet
, 0, PACKETSZ
);
1331 memset(&h
, 0, sizeof(h
));
1337 DPRINTF("encoding header\n", h
.rd
);
1338 i
= __encode_header(&h
, packet
, PACKETSZ
);
1342 /* encode question */
1343 DPRINTF("lookup name: %s\n", lookup
);
1346 q
.qclass
= C_IN
; /* CLASS_IN */
1347 j
= __encode_question(&q
, packet
+i
, PACKETSZ
-i
);
1355 const socklen_t plen
= sa
.sa
.sa_family
== AF_INET
? INET_ADDRSTRLEN
: INET6_ADDRSTRLEN
;
1356 char *pbuf
= malloc(plen
);
1357 if (pbuf
== NULL
) ;/* nothing */
1358 #ifdef __UCLIBC_HAS_IPV6__
1359 else if (sa
.sa
.sa_family
== AF_INET6
)
1360 pbuf
= (char*)inet_ntop(AF_INET6
, &sa
.sa6
.sin6_addr
, pbuf
, plen
);
1362 #ifdef __UCLIBC_HAS_IPV4__
1363 else if (sa
.sa
.sa_family
== AF_INET
)
1364 pbuf
= (char*)inet_ntop(AF_INET
, &sa
.sa4
.sin_addr
, pbuf
, plen
);
1366 DPRINTF("On try %d, sending query to %s, port %d\n",
1367 retries_left
, pbuf
, NAMESERVER_PORT
);
1371 fd
= socket(sa
.sa
.sa_family
, SOCK_DGRAM
, IPPROTO_UDP
);
1372 if (fd
< 0) /* paranoia */
1373 goto try_next_server
;
1374 rc
= connect(fd
, &sa
.sa
, sizeof(sa
));
1376 /*if (errno == ENETUNREACH) { */
1377 /* routing error, presume not transient */
1378 goto try_next_server
;
1380 /*For example, what transient error this can be? Can't think of any */
1384 DPRINTF("Xmit packet len:%d id:%d qr:%d\n", packet_len
, h
.id
, h
.qr
);
1385 /* no error check - if it fails, we time out on recv */
1386 send(fd
, packet
, packet_len
, 0);
1389 reply_timeout
= __resolv_timeout
;
1393 tv
.tv_sec
= reply_timeout
;
1395 if (select(fd
+ 1, &fds
, NULL
, NULL
, &tv
) <= 0) {
1396 DPRINTF("Timeout\n");
1397 /* timed out, so retry send and receive
1398 * to next nameserver */
1399 goto try_next_server
;
1402 #else /* !USE_SELECT */
1403 reply_timeout
= __resolv_timeout
* 1000;
1406 fds
.events
= POLLIN
;
1407 if (poll(&fds
, 1, reply_timeout
) <= 0) {
1408 DPRINTF("Timeout\n");
1409 /* timed out, so retry send and receive
1410 * to next nameserver */
1411 goto try_next_server
;
1413 /*TODO: better timeout accounting?*/
1414 reply_timeout
-= 1000;
1415 #endif /* USE_SELECT */
1417 /* vda: a bogus response seen in real world (caused SEGV in uclibc):
1418 * "ping www.google.com" sending AAAA query and getting
1419 * response with one answer... with answer part missing!
1420 * Fixed by thorough checks for not going past the packet's end.
1424 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";
1425 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";
1426 pos
= memcmp(packet
+ 2, test_query
+ 2, 30);
1427 packet_len
= recv(fd
, packet
, PACKETSZ
, MSG_DONTWAIT
);
1430 memcpy(packet
+ 2, test_respn
+ 2, 30);
1434 packet_len
= recv(fd
, packet
, PACKETSZ
, MSG_DONTWAIT
);
1437 if (packet_len
< HFIXEDSZ
) {
1439 * If the peer did shutdown then retry later,
1440 * try next peer on error.
1441 * it's just a bogus packet from somewhere */
1443 if (packet_len
>= 0 && reply_timeout
)
1445 goto try_next_server
;
1447 __decode_header(packet
, &h
);
1448 DPRINTF("len:%d id:%d qr:%d\n", packet_len
, h
.id
, h
.qr
);
1449 if (h
.id
!= local_id
|| !h
.qr
) {
1454 DPRINTF("Got response (i think)!\n");
1455 DPRINTF("qrcount=%d,ancount=%d,nscount=%d,arcount=%d\n",
1456 h
.qdcount
, h
.ancount
, h
.nscount
, h
.arcount
);
1457 DPRINTF("opcode=%d,aa=%d,tc=%d,rd=%d,ra=%d,rcode=%d\n",
1458 h
.opcode
, h
.aa
, h
.tc
, h
.rd
, h
.ra
, h
.rcode
);
1460 /* bug 660 says we treat negative response as an error
1461 * and retry, which is, eh, an error. :)
1462 * We were incurring long delays because of this. */
1463 if (h
.rcode
== NXDOMAIN
|| h
.rcode
== SERVFAIL
) {
1464 /* if possible, try next search domain */
1465 if (!ends_with_dot
) {
1466 DPRINTF("variant:%d sdomains:%d\n", variant
, sdomains
);
1467 if (variant
< sdomains
- 1) {
1468 /* next search domain */
1472 /* no more search domains to try */
1474 if (h
.rcode
!= SERVFAIL
) {
1475 /* dont loop, this is "no such host" situation */
1476 h_errno
= HOST_NOT_FOUND
;
1480 /* Insert other non-fatal errors here, which do not warrant
1481 * switching to next nameserver */
1483 /* Strange error, assuming this nameserver is feeling bad */
1485 goto try_next_server
;
1487 /* Code below won't work correctly with h.ancount == 0, so... */
1488 if (h
.ancount
<= 0) {
1489 h_errno
= NO_DATA
; /* [is this correct code to check for?] */
1493 for (j
= 0; j
< h
.qdcount
; j
++) {
1494 DPRINTF("Skipping question %d at %d\n", j
, pos
);
1495 i
= __length_question(packet
+ pos
, packet_len
- pos
);
1497 DPRINTF("Packet'question section "
1498 "is truncated, trying next server\n");
1499 goto try_next_server
;
1502 DPRINTF("Length of question %d is %d\n", j
, i
);
1504 DPRINTF("Decoding answer at pos %d\n", pos
);
1508 for (j
= 0; j
< h
.ancount
; j
++) {
1509 i
= __decode_answer(packet
, pos
, packet_len
, &ma
);
1511 DPRINTF("failed decode %d\n", i
);
1512 /* If the message was truncated but we have
1513 * decoded some answers, pretend it's OK */
1516 goto try_next_server
;
1522 ma
.buflen
= a
->buflen
;
1523 ma
.add_count
= a
->add_count
;
1525 memcpy(a
, &ma
, sizeof(ma
));
1526 if (a
->atype
!= T_SIG
&& (NULL
== a
->buf
|| (type
!= T_A
&& type
!= T_AAAA
)))
1528 if (a
->atype
!= type
)
1530 a
->add_count
= h
.ancount
- j
- 1;
1531 if ((a
->rdlength
+ sizeof(struct in_addr
*)) * a
->add_count
> a
->buflen
)
1537 if (ma
.atype
!= type
)
1539 if (a
->rdlength
!= ma
.rdlength
) {
1541 DPRINTF("Answer address len(%u) differs from original(%u)\n",
1542 ma
.rdlength
, a
->rdlength
);
1543 goto try_next_server
;
1545 memcpy(a
->buf
+ (a
->add_count
* ma
.rdlength
), ma
.rdata
, ma
.rdlength
);
1551 DPRINTF("Answer name = |%s|\n", a
->dotted
);
1552 DPRINTF("Answer type = |%d|\n", a
->atype
);
1556 *outpacket
= packet
;
1563 /* Try next nameserver */
1566 } while (retries_left
> 0);
1569 h_errno
= NETDB_INTERNAL
;
1577 #endif /* L_dnslookup */
1580 #ifdef L_read_etc_hosts_r
1582 parser_t
* __open_etc_hosts(void)
1585 parser
= config_open("/etc/hosts");
1586 #ifdef FALLBACK_TO_CONFIG_RESOLVCONF
1588 parser
= config_open("/etc/config/hosts");
1593 #define MINTOKENS 2 /* ip address + canonical name */
1594 #define MAXTOKENS (MINTOKENS + MAXALIASES)
1595 #define HALISTOFF (sizeof(char*) * MAXTOKENS)
1596 #define INADDROFF (HALISTOFF + 2 * sizeof(char*))
1598 int __read_etc_hosts_r(
1602 enum etc_hosts_action action
,
1603 struct hostent
*result_buf
,
1604 char *buf
, size_t buflen
,
1605 struct hostent
**result
,
1609 struct in_addr
*h_addr0
= NULL
;
1610 const size_t aliaslen
= INADDROFF
+
1611 #ifdef __UCLIBC_HAS_IPV6__
1612 sizeof(struct in6_addr
)
1614 sizeof(struct in_addr
)
1617 int ret
= HOST_NOT_FOUND
;
1618 /* make sure pointer is aligned */
1619 int i
= ALIGN_BUFFER_OFFSET(buf
);
1623 *h_errnop
= NETDB_INTERNAL
;
1624 if (/* (ssize_t)buflen < 0 || */ buflen
< aliaslen
1625 || (buflen
- aliaslen
) < BUFSZ
+ 1)
1628 parser
= __open_etc_hosts();
1629 if (parser
== NULL
) {
1634 * char *alias[MAXTOKENS] = {address, name, aliases...}
1635 * char **h_addr_list[1] = {*in[6]_addr, NULL}
1637 * char line_buffer[BUFSZ+];
1640 parser
->data_len
= aliaslen
;
1641 parser
->line_len
= buflen
- aliaslen
;
1642 *h_errnop
= HOST_NOT_FOUND
;
1643 /* <ip>[[:space:]][<aliases>] */
1644 while (config_read(parser
, &tok
, MAXTOKENS
, MINTOKENS
, "# \t", PARSE_NORMAL
)) {
1645 result_buf
->h_aliases
= tok
+1;
1646 if (action
== GETHOSTENT
) {
1647 /* Return whatever the next entry happens to be. */
1650 if (action
== GET_HOSTS_BYADDR
) {
1651 if (strcmp(name
, *tok
) != 0)
1653 } else { /* GET_HOSTS_BYNAME */
1655 char **alias
= tok
+ 1;
1656 while (aliases
< MAXALIASES
) {
1657 char *tmp
= *(alias
+aliases
++);
1658 if (tmp
&& strcasecmp(name
, tmp
) == 0)
1664 result_buf
->h_name
= *(result_buf
->h_aliases
++);
1665 result_buf
->h_addr_list
= (char**)(buf
+ HALISTOFF
);
1666 *(result_buf
->h_addr_list
+ 1) = '\0';
1667 h_addr0
= (struct in_addr
*)(buf
+ INADDROFF
);
1668 result_buf
->h_addr
= (char*)h_addr0
;
1669 if (0) /* nothing */;
1670 #ifdef __UCLIBC_HAS_IPV4__
1671 else if (type
== AF_INET
1672 && inet_pton(AF_INET
, *tok
, h_addr0
) > 0) {
1673 DPRINTF("Found INET\n");
1674 result_buf
->h_addrtype
= AF_INET
;
1675 result_buf
->h_length
= sizeof(struct in_addr
);
1676 *result
= result_buf
;
1677 ret
= NETDB_SUCCESS
;
1680 #ifdef __UCLIBC_HAS_IPV6__
1681 #define in6 ((struct in6_addr *)buf)
1682 else if (type
== AF_INET6
1683 && inet_pton(AF_INET6
, *tok
, h_addr0
) > 0) {
1684 DPRINTF("Found INET6\n");
1685 result_buf
->h_addrtype
= AF_INET6
;
1686 result_buf
->h_length
= sizeof(struct in6_addr
);
1687 *result
= result_buf
;
1688 ret
= NETDB_SUCCESS
;
1692 /* continue parsing in the hope the user has multiple
1693 * host types listed in the database like so:
1696 * If looking for an IPv6 addr, don't bail when we got the IPv4
1698 DPRINTF("Error: Found host but different address family\n");
1699 /* NB: gethostbyname2_r depends on this feature
1700 * to avoid looking for IPv6 addr of "localhost" etc */
1706 if (action
!= GETHOSTENT
)
1707 config_close(parser
);
1711 #endif /* L_read_etc_hosts_r */
1714 #ifdef L_get_hosts_byname_r
1716 int __get_hosts_byname_r(const char *name
,
1718 struct hostent
*result_buf
,
1721 struct hostent
**result
,
1724 return __read_etc_hosts_r(NULL
, name
, type
, GET_HOSTS_BYNAME
,
1725 result_buf
, buf
, buflen
, result
, h_errnop
);
1727 #endif /* L_get_hosts_byname_r */
1730 #ifdef L_get_hosts_byaddr_r
1732 int __get_hosts_byaddr_r(const char *addr
,
1735 struct hostent
*result_buf
,
1738 struct hostent
**result
,
1741 #ifndef __UCLIBC_HAS_IPV6__
1742 char ipaddr
[INET_ADDRSTRLEN
];
1744 char ipaddr
[INET6_ADDRSTRLEN
];
1748 #ifdef __UCLIBC_HAS_IPV4__
1750 if (len
!= sizeof(struct in_addr
))
1754 #ifdef __UCLIBC_HAS_IPV6__
1756 if (len
!= sizeof(struct in6_addr
))
1764 inet_ntop(type
, addr
, ipaddr
, sizeof(ipaddr
));
1766 return __read_etc_hosts_r(NULL
, ipaddr
, type
, GET_HOSTS_BYADDR
,
1767 result_buf
, buf
, buflen
, result
, h_errnop
);
1769 #endif /* L_get_hosts_byaddr_r */
1772 #ifdef L_getnameinfo
1774 int getnameinfo(const struct sockaddr
*sa
,
1784 struct hostent
*hoste
= NULL
;
1787 if (flags
& ~(NI_NUMERICHOST
|NI_NUMERICSERV
|NI_NOFQDN
|NI_NAMEREQD
|NI_DGRAM
))
1788 return EAI_BADFLAGS
;
1790 if (sa
== NULL
|| addrlen
< sizeof(sa_family_t
))
1793 if (sa
->sa_family
== AF_LOCAL
) /* valid */;
1794 #ifdef __UCLIBC_HAS_IPV4__
1795 else if (sa
->sa_family
== AF_INET
) {
1796 if (addrlen
< sizeof(struct sockaddr_in
))
1800 #ifdef __UCLIBC_HAS_IPV6__
1801 else if (sa
->sa_family
== AF_INET6
) {
1802 if (addrlen
< sizeof(struct sockaddr_in6
))
1809 if (host
!= NULL
&& hostlen
> 0)
1810 switch (sa
->sa_family
) {
1812 #ifdef __UCLIBC_HAS_IPV6__
1815 if (!(flags
& NI_NUMERICHOST
)) {
1816 if (0) /* nothing */;
1817 #ifdef __UCLIBC_HAS_IPV6__
1818 else if (sa
->sa_family
== AF_INET6
)
1819 hoste
= gethostbyaddr((const void *)
1820 &(((const struct sockaddr_in6
*) sa
)->sin6_addr
),
1821 sizeof(struct in6_addr
), AF_INET6
);
1823 #ifdef __UCLIBC_HAS_IPV4__
1825 hoste
= gethostbyaddr((const void *)
1826 &(((const struct sockaddr_in
*)sa
)->sin_addr
),
1827 sizeof(struct in_addr
), AF_INET
);
1832 if ((flags
& NI_NOFQDN
)
1833 && (getdomainname(domain
, sizeof(domain
)) == 0)
1834 && (c
= strstr(hoste
->h_name
, domain
)) != NULL
1835 && (c
!= hoste
->h_name
) && (*(--c
) == '.')
1837 strncpy(host
, hoste
->h_name
,
1838 MIN(hostlen
, (size_t) (c
- hoste
->h_name
)));
1839 host
[MIN(hostlen
- 1, (size_t) (c
- hoste
->h_name
))] = '\0';
1841 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;
3435 /* has to be called under __resolv_lock */
3437 __res_vinit(res_state rp
, int preinit
)
3439 int i
, n
, options
, retrans
, retry
, ndots
;
3440 #ifdef __UCLIBC_HAS_IPV6__
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
;
3541 return 0xffff & getpid();
3544 /* Our res_init never fails (always returns 0) */
3549 * These three fields used to be statically initialized. This made
3550 * it hard to use this code in a shared library. It is necessary,
3551 * now that we're doing dynamic initialization here, that we preserve
3552 * the old semantics: if an application modifies one of these three
3553 * fields of _res before res_init() is called, res_init() will not
3554 * alter them. Of course, if an application is setting them to
3555 * _zero_ before calling res_init(), hoping to override what used
3556 * to be the static default, we can't detect it and unexpected results
3557 * will follow. Zero for any of these fields would make no sense,
3558 * so one can safely assume that the applications were already getting
3559 * unexpected results.
3561 * _res.options is tricky since some apps were known to diddle the bits
3562 * before res_init() was first called. We can't replicate that semantic
3563 * with dynamic initialization (they may have turned bits off that are
3564 * set in RES_DEFAULT). Our solution is to declare such applications
3565 * "broken". They could fool us by setting RES_INIT but none do (yet).
3568 __UCLIBC_MUTEX_LOCK(__resolv_lock
);
3571 _res
.retrans
= RES_TIMEOUT
;
3574 if (!(_res
.options
& RES_INIT
))
3575 _res
.options
= RES_DEFAULT
;
3578 * This one used to initialize implicitly to zero, so unless the app
3579 * has set it to something in particular, we can randomize it now.
3582 _res
.id
= res_randomid();
3585 __res_vinit(&_res
, 1);
3586 __res_sync
= res_sync_func
;
3588 __UCLIBC_MUTEX_UNLOCK(__resolv_lock
);
3592 libc_hidden_def(res_init
)
3595 __res_iclose(res_state statp
)
3597 struct __res_state
* rp
= statp
;
3598 __UCLIBC_MUTEX_LOCK(__resolv_lock
);
3601 __close_nameservers();
3603 #ifdef __UCLIBC_HAS_IPV6__
3605 char *p1
= (char*) &(rp
->nsaddr_list
[0]);
3607 /* free nsaddrs[m] if they do not point to nsaddr_list[x] */
3608 while (m
< ARRAY_SIZE(rp
->_u
._ext
.nsaddrs
)) {
3609 char *p2
= (char*)(rp
->_u
._ext
.nsaddrs
[m
++]);
3610 if (p2
< p1
|| (p2
- p1
) > (signed)sizeof(rp
->nsaddr_list
))
3615 memset(rp
, 0, sizeof(struct __res_state
));
3616 __UCLIBC_MUTEX_UNLOCK(__resolv_lock
);
3620 * This routine is for closing the socket if a virtual circuit is used and
3621 * the program wants to close it. This provides support for endhostent()
3622 * which expects to close the socket.
3624 * This routine is not expected to be user visible.
3628 res_nclose(res_state statp
)
3630 __res_iclose(statp
);
3633 #ifdef __UCLIBC_HAS_BSD_RES_CLOSE__
3634 void res_close(void)
3640 /* This needs to be after the use of _res in res_init, above. */
3643 #ifndef __UCLIBC_HAS_THREADS__
3644 /* The resolver state for use by single-threaded programs.
3645 This differs from plain `struct __res_state _res;' in that it doesn't
3646 create a common definition, but a plain symbol that resides in .bss,
3647 which can have an alias. */
3648 struct __res_state _res
__attribute__((section (".bss")));
3649 struct __res_state
*__resp
= &_res
;
3650 #else /* __UCLIBC_HAS_THREADS__ */
3651 struct __res_state _res
__attribute__((section (".bss"))) attribute_hidden
;
3653 # if defined __UCLIBC_HAS_TLS__
3655 __thread
struct __res_state
*__resp
= &_res
;
3656 extern __thread
struct __res_state
*__libc_resp
3657 __attribute__ ((alias ("__resp"))) attribute_hidden attribute_tls_model_ie
;
3660 struct __res_state
*__resp
= &_res
;
3662 #endif /* !__UCLIBC_HAS_THREADS__ */
3665 * Set up default settings. If the configuration file exist, the values
3666 * there will have precedence. Otherwise, the server address is set to
3667 * INADDR_ANY and the default domain name comes from the gethostname().
3669 * An interrim version of this code (BIND 4.9, pre-4.4BSD) used 127.0.0.1
3670 * rather than INADDR_ANY ("0.0.0.0") as the default name server address
3671 * since it was noted that INADDR_ANY actually meant ``the first interface
3672 * you "ifconfig"'d at boot time'' and if this was a SLIP or PPP interface,
3673 * it had to be "up" in order for you to reach your own name server. It
3674 * was later decided that since the recommended practice is to always
3675 * install local static routes through 127.0.0.1 for all your network
3676 * interfaces, that we could solve this problem without a code change.
3678 * The configuration file should always be used, since it is the only way
3679 * to specify a default domain. If you are running a server on your local
3680 * machine, you should say "nameserver 0.0.0.0" or "nameserver 127.0.0.1"
3681 * in the configuration file.
3683 * Return 0 if completes successfully, -1 on error
3686 res_ninit(res_state statp
)
3689 __UCLIBC_MUTEX_LOCK(__resolv_lock
);
3690 ret
= __res_vinit(statp
, 0);
3691 __UCLIBC_MUTEX_UNLOCK(__resolv_lock
);
3695 #endif /* L_res_init */
3698 # if defined __UCLIBC_HAS_TLS__
3699 struct __res_state
*
3706 extern struct __res_state _res
;
3708 /* When threaded, _res may be a per-thread variable. */
3709 struct __res_state
*
3717 #endif /* L_res_state */
3722 int res_query(const char *dname
, int class, int type
,
3723 unsigned char *answer
, int anslen
)
3726 unsigned char *packet
= NULL
;
3727 struct resolv_answer a
;
3729 if (!dname
|| class != 1 /* CLASS_IN */) {
3730 h_errno
= NO_RECOVERY
;
3734 memset(&a
, '\0', sizeof(a
));
3735 i
= __dns_lookup(dname
, type
, &packet
, &a
);
3738 if (!h_errno
) /* TODO: can this ever happen? */
3739 h_errno
= TRY_AGAIN
;
3747 memcpy(answer
, packet
, i
);
3752 libc_hidden_def(res_query
)
3755 * Formulate a normal query, send, and retrieve answer in supplied buffer.
3756 * Return the size of the response on success, -1 on error.
3757 * If enabled, implement search rules until answer or unrecoverable failure
3758 * is detected. Error code, if any, is left in h_errno.
3760 #define __TRAILING_DOT (1<<0)
3761 #define __GOT_NODATA (1<<1)
3762 #define __GOT_SERVFAIL (1<<2)
3763 #define __TRIED_AS_IS (1<<3)
3764 int res_search(const char *name
, int class, int type
, u_char
*answer
,
3769 HEADER
*hp
= (HEADER
*)(void *)answer
;
3772 int ret
, saved_herrno
;
3773 uint32_t _res_options
;
3774 unsigned _res_ndots
;
3777 if (!name
|| !answer
) {
3778 h_errno
= NETDB_INTERNAL
;
3783 __UCLIBC_MUTEX_LOCK(__resolv_lock
);
3784 _res_options
= _res
.options
;
3785 _res_ndots
= _res
.ndots
;
3786 _res_dnsrch
= _res
.dnsrch
;
3787 __UCLIBC_MUTEX_UNLOCK(__resolv_lock
);
3788 if (!(_res_options
& RES_INIT
)) {
3789 res_init(); /* our res_init never fails */
3795 h_errno
= HOST_NOT_FOUND
; /* default, if we never query */
3797 for (cp
= name
; *cp
; cp
++)
3798 dots
+= (*cp
== '.');
3800 if (cp
> name
&& *--cp
== '.')
3801 state
|= __TRAILING_DOT
;
3804 * If there are dots in the name already, let's just give it a try
3805 * 'as is'. The threshold can be set with the "ndots" option.
3808 if (dots
>= _res_ndots
) {
3809 ret
= res_querydomain(name
, NULL
, class, type
, answer
, anslen
);
3812 saved_herrno
= h_errno
;
3813 state
|= __TRIED_AS_IS
;
3817 * We do at least one level of search if
3818 * - there is no dot and RES_DEFNAME is set, or
3819 * - there is at least one dot, there is no trailing dot,
3820 * and RES_DNSRCH is set.
3822 if ((!dots
&& (_res_options
& RES_DEFNAMES
))
3823 || (dots
&& !(state
& __TRAILING_DOT
) && (_res_options
& RES_DNSRCH
))
3827 for (domain
= _res_dnsrch
; *domain
&& !done
; domain
++) {
3829 ret
= res_querydomain(name
, *domain
, class, type
,
3835 * If no server present, give up.
3836 * If name isn't found in this domain,
3837 * keep trying higher domains in the search list
3838 * (if that's enabled).
3839 * On a NO_DATA error, keep trying, otherwise
3840 * a wildcard entry of another type could keep us
3841 * from finding this entry higher in the domain.
3842 * If we get some other error (negative answer or
3843 * server failure), then stop searching up,
3844 * but try the input name below in case it's
3847 if (errno
== ECONNREFUSED
) {
3848 h_errno
= TRY_AGAIN
;
3854 state
|= __GOT_NODATA
;
3856 case HOST_NOT_FOUND
:
3860 if (hp
->rcode
== SERVFAIL
) {
3861 /* try next search element, if any */
3862 state
|= __GOT_SERVFAIL
;
3867 /* anything else implies that we're done */
3871 * if we got here for some reason other than DNSRCH,
3872 * we only wanted one iteration of the loop, so stop.
3874 if (!(_res_options
& RES_DNSRCH
))
3880 * if we have not already tried the name "as is", do that now.
3881 * note that we do this regardless of how many dots were in the
3882 * name or whether it ends with a dot.
3884 if (!(state
& __TRIED_AS_IS
)) {
3885 ret
= res_querydomain(name
, NULL
, class, type
, answer
, anslen
);
3891 * if we got here, we didn't satisfy the search.
3892 * if we did an initial full query, return that query's h_errno
3893 * (note that we wouldn't be here if that query had succeeded).
3894 * else if we ever got a nodata, send that back as the reason.
3895 * else send back meaningless h_errno, that being the one from
3896 * the last DNSRCH we did.
3898 if (saved_herrno
!= -1)
3899 h_errno
= saved_herrno
;
3900 else if (state
& __GOT_NODATA
)
3902 else if (state
& __GOT_SERVFAIL
)
3903 h_errno
= TRY_AGAIN
;
3906 #undef __TRAILING_DOT
3908 #undef __GOT_SERVFAIL
3909 #undef __TRIED_AS_IS
3911 * Perform a call on res_query on the concatenation of name and domain,
3912 * removing a trailing dot from name if domain is NULL.
3914 int res_querydomain(const char *name
, const char *domain
, int class, int type
,
3915 u_char
*answer
, int anslen
)
3917 char nbuf
[MAXDNAME
];
3918 const char *longname
= nbuf
;
3921 uint32_t _res_options
;
3924 if (!name
|| !answer
) {
3925 h_errno
= NETDB_INTERNAL
;
3931 __UCLIBC_MUTEX_LOCK(__resolv_lock
);
3932 _res_options
= _res
.options
;
3933 __UCLIBC_MUTEX_UNLOCK(__resolv_lock
);
3934 if (!(_res_options
& RES_INIT
)) {
3935 res_init(); /* our res_init never fails */
3938 if (_res_options
& RES_DEBUG
)
3939 printf(";; res_querydomain(%s, %s, %d, %d)\n",
3940 name
, (domain
? domain
: "<Nil>"), class, type
);
3942 if (domain
== NULL
) {
3944 * Check for trailing '.';
3945 * copy without '.' if present.
3948 if (n
+ 1 > sizeof(nbuf
)) {
3949 h_errno
= NO_RECOVERY
;
3952 if (n
> 0 && name
[--n
] == '.') {
3953 strncpy(nbuf
, name
, n
);
3960 if (n
+ 1 + d
+ 1 > sizeof(nbuf
)) {
3961 h_errno
= NO_RECOVERY
;
3964 snprintf(nbuf
, sizeof(nbuf
), "%s.%s", name
, domain
);
3966 return res_query(longname
, class, type
, answer
, anslen
);
3968 libc_hidden_def(res_querydomain
)
3969 #endif /* L_res_query */
3972 unsigned int ns_get16(const unsigned char *src
)
3979 unsigned long ns_get32(const unsigned char *src
)
3986 void ns_put16(unsigned int src
, unsigned char *dst
)
3991 void ns_put32(unsigned long src
, unsigned char *dst
)
3995 #endif /* L_ns_netint */
3998 /* These need to be in the same order as the nres.h:ns_flag enum. */
3999 struct _ns_flagdata
{ unsigned short mask
, shift
; };
4000 static const struct _ns_flagdata _ns_flagdata
[16] = {
4001 { 0x8000, 15 }, /*%< qr. */
4002 { 0x7800, 11 }, /*%< opcode. */
4003 { 0x0400, 10 }, /*%< aa. */
4004 { 0x0200, 9 }, /*%< tc. */
4005 { 0x0100, 8 }, /*%< rd. */
4006 { 0x0080, 7 }, /*%< ra. */
4007 { 0x0040, 6 }, /*%< z. */
4008 { 0x0020, 5 }, /*%< ad. */
4009 { 0x0010, 4 }, /*%< cd. */
4010 { 0x000f, 0 }, /*%< rcode. */
4011 { 0x0000, 0 }, /*%< expansion (1/6). */
4012 { 0x0000, 0 }, /*%< expansion (2/6). */
4013 { 0x0000, 0 }, /*%< expansion (3/6). */
4014 { 0x0000, 0 }, /*%< expansion (4/6). */
4015 { 0x0000, 0 }, /*%< expansion (5/6). */
4016 { 0x0000, 0 }, /*%< expansion (6/6). */
4019 static void setsection(ns_msg
*msg
, ns_sect sect
)
4022 if (sect
== ns_s_max
) {
4027 msg
->_ptr
= msg
->_sections
[(int)sect
];
4031 int ns_skiprr(const unsigned char *ptr
,
4032 const unsigned char *eom
,
4033 ns_sect section
, int count
)
4035 const u_char
*optr
= ptr
;
4037 for (; count
> 0; count
--) {
4040 b
= dn_skipname(ptr
, eom
);
4046 ptr
+= b
/*Name*/ + NS_INT16SZ
/*Type*/ + NS_INT16SZ
/*Class*/;
4047 if (section
!= ns_s_qd
) {
4048 if (ptr
+ NS_INT32SZ
+ NS_INT16SZ
> eom
) {
4053 ptr
+= NS_INT32SZ
/*TTL*/;
4054 NS_GET16(rdlength
, ptr
);
4055 ptr
+= rdlength
/*RData*/;
4066 libc_hidden_def(ns_skiprr
)
4069 ns_initparse(const unsigned char *msg
, int msglen
, ns_msg
*handle
)
4071 const u_char
*eom
= msg
+ msglen
;
4076 if (msg
+ NS_INT16SZ
> eom
) {
4081 NS_GET16(handle
->_id
, msg
);
4082 if (msg
+ NS_INT16SZ
> eom
) {
4087 NS_GET16(handle
->_flags
, msg
);
4088 for (i
= 0; i
< ns_s_max
; i
++) {
4089 if (msg
+ NS_INT16SZ
> eom
) {
4094 NS_GET16(handle
->_counts
[i
], msg
);
4096 for (i
= 0; i
< ns_s_max
; i
++)
4097 if (handle
->_counts
[i
] == 0)
4098 handle
->_sections
[i
] = NULL
;
4100 int b
= ns_skiprr(msg
, eom
, (ns_sect
)i
,
4101 handle
->_counts
[i
]);
4105 handle
->_sections
[i
] = msg
;
4114 setsection(handle
, ns_s_max
);
4119 ns_parserr(ns_msg
*handle
, ns_sect section
, int rrnum
, ns_rr
*rr
)
4124 /* Make section right. */
4126 if (tmp
< 0 || section
>= ns_s_max
) {
4131 if (section
!= handle
->_sect
)
4132 setsection(handle
, section
);
4134 /* Make rrnum right. */
4136 rrnum
= handle
->_rrnum
;
4137 if (rrnum
< 0 || rrnum
>= handle
->_counts
[(int)section
]) {
4141 if (rrnum
< handle
->_rrnum
)
4142 setsection(handle
, section
);
4143 if (rrnum
> handle
->_rrnum
) {
4144 b
= ns_skiprr(handle
->_ptr
, handle
->_eom
, section
,
4145 rrnum
- handle
->_rrnum
);
4150 handle
->_rrnum
= rrnum
;
4154 b
= dn_expand(handle
->_msg
, handle
->_eom
,
4155 handle
->_ptr
, rr
->name
, NS_MAXDNAME
);
4159 if (handle
->_ptr
+ NS_INT16SZ
+ NS_INT16SZ
> handle
->_eom
) {
4163 NS_GET16(rr
->type
, handle
->_ptr
);
4164 NS_GET16(rr
->rr_class
, handle
->_ptr
);
4165 if (section
== ns_s_qd
) {
4170 if (handle
->_ptr
+ NS_INT32SZ
+ NS_INT16SZ
> handle
->_eom
) {
4174 NS_GET32(rr
->ttl
, handle
->_ptr
);
4175 NS_GET16(rr
->rdlength
, handle
->_ptr
);
4176 if (handle
->_ptr
+ rr
->rdlength
> handle
->_eom
) {
4180 rr
->rdata
= handle
->_ptr
;
4181 handle
->_ptr
+= rr
->rdlength
;
4183 if (++handle
->_rrnum
> handle
->_counts
[(int)section
])
4184 setsection(handle
, (ns_sect
)((int)section
+ 1));
4189 int ns_msg_getflag(ns_msg handle
, int flag
)
4191 return ((handle
)._flags
& _ns_flagdata
[flag
].mask
) >> _ns_flagdata
[flag
].shift
;
4193 #endif /* L_ns_parse */
4196 int res_mkquery(int op
, const char *dname
, int class, int type
,
4197 const unsigned char *data
, int datalen
,
4198 const unsigned char *newrr_in
,
4199 unsigned char *buf
, int buflen
)
4202 unsigned char *cp
, *ep
;
4203 unsigned char *dnptrs
[20], **dpp
, **lastdnptr
;
4204 uint32_t _res_options
;
4207 if (!buf
|| buflen
< HFIXEDSZ
) {
4208 h_errno
= NETDB_INTERNAL
;
4213 __UCLIBC_MUTEX_LOCK(__resolv_lock
);
4214 _res_options
= _res
.options
;
4215 __UCLIBC_MUTEX_UNLOCK(__resolv_lock
);
4216 if (!(_res_options
& RES_INIT
)) {
4217 res_init(); /* our res_init never fails */
4222 if (_res_options
& RES_DEBUG
)
4223 printf(";; res_mkquery(%d, %s, %d, %d)\n",
4224 op
, dname
&& *dname
? dname
: "<null>", class, type
);
4227 memset(buf
, 0, HFIXEDSZ
);
4228 hp
= (HEADER
*) buf
;
4229 hp
->id
= getpid() & 0xffff;
4231 hp
->rd
= (_res_options
& RES_RECURSE
) != 0U;
4232 hp
->rcode
= NOERROR
;
4234 cp
= buf
+ HFIXEDSZ
;
4239 lastdnptr
= dnptrs
+ sizeof dnptrs
/ sizeof dnptrs
[0];
4242 * perform opcode specific processing
4247 if (ep
- cp
< QFIXEDSZ
)
4250 n
= dn_comp(dname
, cp
, ep
- cp
- QFIXEDSZ
, dnptrs
, lastdnptr
);
4256 NS_PUT16(class, cp
);
4257 hp
->qdcount
= htons(1);
4259 if (op
== QUERY
|| data
== NULL
)
4263 * Make an additional record for completion domain.
4265 if ((ep
- cp
) < RRFIXEDSZ
)
4268 n
= dn_comp((const char *)data
, cp
, ep
- cp
- RRFIXEDSZ
,
4274 NS_PUT16(T_NULL
, cp
);
4275 NS_PUT16(class, cp
);
4278 hp
->arcount
= htons(1);
4284 * Initialize answer section
4286 if (ep
- cp
< 1 + RRFIXEDSZ
+ datalen
)
4289 *cp
++ = '\0'; /*%< no domain name */
4291 NS_PUT16(class, cp
);
4293 NS_PUT16(datalen
, cp
);
4296 memcpy(cp
, data
, (size_t)datalen
);
4300 hp
->ancount
= htons(1);
4309 #endif /* L_res_data */
4311 /* Unimplemented: */