1 /* resolv.c: DNS Resolver
3 * Copyright (C) 1998 Kenneth Albanowski <kjahds@kjahds.com>,
4 * The Silver Hammer Group, Ltd.
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
12 * Portions Copyright (c) 1985, 1993
13 * The Regents of the University of California. All rights reserved.
15 * Redistribution and use in source and binary forms, with or without
16 * modification, are permitted provided that the following conditions
18 * 1. Redistributions of source code must retain the above copyright
19 * notice, this list of conditions and the following disclaimer.
20 * 2. Redistributions in binary form must reproduce the above copyright
21 * notice, this list of conditions and the following disclaimer in the
22 * documentation and/or other materials provided with the distribution.
23 * 4. Neither the name of the University nor the names of its contributors
24 * may be used to endorse or promote products derived from this software
25 * without specific prior written permission.
27 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
40 * Portions Copyright (c) 1993 by Digital Equipment Corporation.
42 * Permission to use, copy, modify, and distribute this software for any
43 * purpose with or without fee is hereby granted, provided that the above
44 * copyright notice and this permission notice appear in all copies, and that
45 * the name of Digital Equipment Corporation not be used in advertising or
46 * publicity pertaining to distribution of the document or software without
47 * specific, written prior permission.
49 * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
50 * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
51 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
52 * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
53 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
54 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
55 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
59 * Portions Copyright (c) 1996-1999 by Internet Software Consortium.
61 * Permission to use, copy, modify, and distribute this software for any
62 * purpose with or without fee is hereby granted, provided that the above
63 * copyright notice and this permission notice appear in all copies.
65 * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
66 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
67 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
68 * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
69 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
70 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
71 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
76 Whenever an octet represents a numeric quantity, the left most bit
77 in the diagram is the high order or most significant bit.
78 That is, the bit labeled 0 is the most significant bit.
81 4.1.1. Header section format
82 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
83 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
85 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
86 |QR| OPCODE |AA|TC|RD|RA| 0 0 0| RCODE |
87 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
89 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
91 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
93 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
95 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
96 ID 16 bit random identifier assigned by querying peer.
97 Used to match query/response.
98 QR message is a query (0), or a response (1).
99 OPCODE 0 standard query (QUERY)
100 1 inverse query (IQUERY)
101 2 server status request (STATUS)
102 AA Authoritative Answer - this bit is valid in responses.
103 Responding name server is an authority for the domain name
104 in question section. Answer section may have multiple owner names
105 because of aliases. The AA bit corresponds to the name which matches
106 the query name, or the first owner name in the answer section.
107 TC TrunCation - this message was truncated.
108 RD Recursion Desired - this bit may be set in a query and
109 is copied into the response. If RD is set, it directs
110 the name server to pursue the query recursively.
111 Recursive query support is optional.
112 RA Recursion Available - this be is set or cleared in a
113 response, and denotes whether recursive query support is
114 available in the name server.
118 2 Server failure - server was unable to process the query
119 due to a problem with the name server.
120 3 Name Error - meaningful only for responses from
121 an authoritative name server. The referenced domain name
125 QDCOUNT number of entries in the question section.
126 ANCOUNT number of records in the answer section.
127 NSCOUNT number of records in the authority records section.
128 ARCOUNT number of records in the additional records section.
130 4.1.2. Question section format
132 The section contains QDCOUNT (usually 1) entries, each of this format:
133 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
134 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
137 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
139 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
141 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
142 QNAME a domain name represented as a sequence of labels, where
143 each label consists of a length octet followed by that
144 number of octets. The domain name terminates with the
145 zero length octet for the null label of the root. Note
146 that this field may be an odd number of octets; no
148 QTYPE a two octet type of the query.
149 1 a host address [REQ_A const]
150 2 an authoritative name server
151 3 a mail destination (Obsolete - use MX)
152 4 a mail forwarder (Obsolete - use MX)
153 5 the canonical name for an alias
154 6 marks the start of a zone of authority
155 7 a mailbox domain name (EXPERIMENTAL)
156 8 a mail group member (EXPERIMENTAL)
157 9 a mail rename domain name (EXPERIMENTAL)
158 10 a null RR (EXPERIMENTAL)
159 11 a well known service description
160 12 a domain name pointer [REQ_PTR const]
162 14 mailbox or mail list information
166 252 a request for a transfer of an entire zone
167 253 a request for mailbox-related records (MB, MG or MR)
168 254 a request for mail agent RRs (Obsolete - see MX)
169 255 a request for all records
170 QCLASS a two octet code that specifies the class of the query.
172 (others are historic only)
175 4.1.3. Resource record format
177 The answer, authority, and additional sections all share the same format:
178 a variable number of resource records, where the number of records
179 is specified in the corresponding count field in the header.
180 Each resource record has this format:
181 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
182 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
185 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
187 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
189 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
192 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
194 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--|
197 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
198 NAME a domain name to which this resource record pertains.
199 TYPE two octets containing one of the RR type codes. This
200 field specifies the meaning of the data in the RDATA field.
201 CLASS two octets which specify the class of the data in the RDATA field.
202 TTL a 32 bit unsigned integer that specifies the time interval
203 (in seconds) that the record may be cached.
204 RDLENGTH a 16 bit integer, length in octets of the RDATA field.
205 RDATA a variable length string of octets that describes the resource.
206 The format of this information varies according to the TYPE
207 and CLASS of the resource record.
208 If the TYPE is A and the CLASS is IN, it's a 4 octet IP address.
210 4.1.4. Message compression
212 In order to reduce the size of messages, domain names can be compressed.
213 An entire domain name or a list of labels at the end of a domain name
214 is replaced with a pointer to a prior occurance of the same name.
216 The pointer takes the form of a two octet sequence:
217 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
219 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
220 The first two bits are ones. This allows a pointer to be distinguished
221 from a label, since the label must begin with two zero bits because
222 labels are restricted to 63 octets or less. The OFFSET field specifies
223 an offset from the start of the message (i.e., the first octet
224 of the ID field in the domain header).
225 A zero offset specifies the first byte of the ID field, etc.
226 Domain name in a message can be represented as either:
227 - a sequence of labels ending in a zero octet
229 - a sequence of labels ending with a pointer
234 #include <stdio_ext.h>
238 #include <sys/poll.h>
239 #include <sys/socket.h>
240 #include <sys/types.h>
241 #include <sys/time.h>
242 #include <netinet/in.h>
243 #include <arpa/inet.h>
251 #include <arpa/nameser.h>
252 #include <sys/utsname.h>
254 #include <sys/stat.h>
255 #include <sys/param.h>
256 #include <bits/uClibc_mutex.h>
257 #include "internal/parse_config.h"
259 /* poll() is not supported in kernel <= 2.0, therefore if __NR_poll is
260 * not available, we assume an old Linux kernel is in use and we will
261 * use select() instead. */
262 #include <sys/syscall.h>
267 #if defined __UCLIBC_HAS_IPV4__ && defined __UCLIBC_HAS_IPV6__
268 #define IF_HAS_BOTH(...) __VA_ARGS__
270 #define IF_HAS_BOTH(...)
274 #define MAX_RECURSE 5
275 #define MAXALIASES (4)
276 /* 1:ip + 1:full + MAX_ALIASES:aliases + 1:NULL */
277 #define ALIAS_DIM (2 + MAXALIASES + 1)
278 #define BUFSZ (80) /* one line */
280 #define NS_TYPE_ELT 0x40 /*%< EDNS0 extended label type */
281 #define DNS_LABELTYPE_BITSTRING 0x41
287 #define DPRINTF(X,args...) fprintf(stderr, X, ##args)
289 #define DPRINTF(X,args...)
292 /* Make sure the incoming char * buffer is aligned enough to handle our random
293 * structures. This define is the same as we use for malloc alignment (which
294 * has same requirements). The offset is the number of bytes we need to adjust
295 * in order to attain desired alignment.
297 #define ALIGN_ATTR __alignof__(double __attribute_aligned__ (sizeof(size_t)))
298 #define ALIGN_BUFFER_OFFSET(buf) ((ALIGN_ATTR - ((size_t)buf % ALIGN_ATTR)) % ALIGN_ATTR)
302 struct resolv_header
{
304 int qr
, opcode
, aa
, tc
, rd
, ra
, rcode
;
311 struct resolv_question
{
317 struct resolv_answer
{
323 const unsigned char *rdata
;
330 enum etc_hosts_action
{
331 GET_HOSTS_BYNAME
= 0,
336 typedef union sockaddr46_t
{
338 #ifdef __UCLIBC_HAS_IPV4__
339 struct sockaddr_in sa4
;
341 #ifdef __UCLIBC_HAS_IPV6__
342 struct sockaddr_in6 sa6
;
347 __UCLIBC_MUTEX_EXTERN(__resolv_lock
) attribute_hidden
;
349 /* Protected by __resolv_lock */
350 extern void (*__res_sync
)(void) attribute_hidden
;
351 /*extern uint32_t __resolv_opts attribute_hidden; */
352 extern uint8_t __resolv_timeout attribute_hidden
;
353 extern uint8_t __resolv_attempts attribute_hidden
;
354 extern unsigned __nameservers attribute_hidden
;
355 extern unsigned __searchdomains attribute_hidden
;
356 extern sockaddr46_t
*__nameserver attribute_hidden
;
357 extern char **__searchdomain attribute_hidden
;
358 #ifdef __UCLIBC_HAS_IPV4__
359 extern const struct sockaddr_in __local_nameserver attribute_hidden
;
361 extern const struct sockaddr_in6 __local_nameserver attribute_hidden
;
364 #define MAXLEN_searchdomain 128
367 /* prototypes for internal functions */
368 extern void endhostent_unlocked(void) attribute_hidden
;
369 extern int __get_hosts_byname_r(const char *name
,
371 struct hostent
*result_buf
,
374 struct hostent
**result
,
375 int *h_errnop
) attribute_hidden
;
376 extern int __get_hosts_byaddr_r(const char *addr
,
379 struct hostent
*result_buf
,
382 struct hostent
**result
,
383 int *h_errnop
) attribute_hidden
;
384 extern parser_t
*__open_etc_hosts(void) attribute_hidden
;
385 extern int __read_etc_hosts_r(parser_t
*parser
,
388 enum etc_hosts_action action
,
389 struct hostent
*result_buf
,
392 struct hostent
**result
,
393 int *h_errnop
) attribute_hidden
;
394 extern int __dns_lookup(const char *name
,
396 unsigned char **outpacket
,
397 struct resolv_answer
*a
) attribute_hidden
;
398 extern int __encode_dotted(const char *dotted
,
400 int maxlen
) attribute_hidden
;
401 extern int __decode_dotted(const unsigned char *packet
,
405 int dest_len
) attribute_hidden
;
406 extern int __encode_header(struct resolv_header
*h
,
408 int maxlen
) attribute_hidden
;
409 extern void __decode_header(unsigned char *data
,
410 struct resolv_header
*h
) attribute_hidden
;
411 extern int __encode_question(const struct resolv_question
*q
,
413 int maxlen
) attribute_hidden
;
414 extern int __encode_answer(struct resolv_answer
*a
,
416 int maxlen
) attribute_hidden
;
417 extern void __open_nameservers(void) attribute_hidden
;
418 extern void __close_nameservers(void) attribute_hidden
;
421 * Theory of operation.
423 * gethostbyname, getaddrinfo and friends end up here, and they sometimes
424 * need to talk to DNS servers. In order to do this, we need to read /etc/resolv.conf
425 * and determine servers' addresses and the like. resolv.conf format:
427 * nameserver <IP[v6]>
428 * Address of DNS server. Cumulative.
429 * If not specified, assumed to be on localhost.
430 * search <domain1>[ <domain2>]...
431 * Append these domains to unqualified names.
432 * See ndots:n option.
433 * $LOCALDOMAIN (space-separated list) overrides this.
435 * Effectively same as "search" with one domain.
436 * If no "domain" line is present, the domain is determined
437 * from the local host name returned by gethostname();
438 * the domain part is taken to be everything after the first dot.
439 * If there are no dots, there will be no "domain".
440 * The domain and search keywords are mutually exclusive.
441 * If more than one instance of these keywords is present,
442 * the last instance wins.
443 * sortlist 130.155.160.0[/255.255.240.0] 130.155.0.0
444 * Allows addresses returned by gethostbyname to be sorted.
446 * options option[ option]...
447 * (so far we support timeout:n and attempts:n)
448 * $RES_OPTIONS (space-separated list) is to be added to "options"
449 * debug sets RES_DEBUG in _res.options
450 * ndots:n how many dots there should be so that name will be tried
451 * first as an absolute name before any search list elements
452 * are appended to it. Default 1
453 * timeout:n how long to wait for response. Default 5
454 * (sun seems to have retrans:n synonym)
455 * attempts:n number of rounds to do before giving up and returning
456 * an error. Default 2
457 * (sun seems to have retry:n synonym)
458 * rotate sets RES_ROTATE in _res.options, round robin
459 * selection of nameservers. Otherwise try
460 * the first listed server first every time
462 * sets RES_NOCHECKNAME in _res.options, which disables
463 * checking of incoming host names for invalid characters
464 * such as underscore (_), non-ASCII, or control characters
465 * inet6 sets RES_USE_INET6 in _res.options. Try a AAAA query
466 * before an A query inside the gethostbyname(), and map
467 * IPv4 responses in IPv6 "tunnelled form" if no AAAA records
468 * are found but an A record set exists
469 * no_tld_query (FreeBSDism?)
470 * do not attempt to resolve names without dots
472 * We will read and analyze /etc/resolv.conf as needed before
473 * we do a DNS request. This happens in __dns_lookup.
474 * It is reread if its mtime is changed.
476 * BSD has res_init routine which is used to initialize resolver state
477 * which is held in global structure _res.
478 * Generally, programs call res_init, then fiddle with _res.XXX
479 * (_res.options and _res.nscount, _res.nsaddr_list[N]
480 * are popular targets of fiddling) and expect subsequent calls
481 * to gethostbyname, getaddrinfo, etc to use modified information.
483 * However, historical _res structure is quite awkward.
484 * Using it for storing /etc/resolv.conf info is not desirable,
485 * and __dns_lookup does not use it.
487 * We would like to avoid using it unless absolutely necessary.
488 * If user doesn't use res_init, we should arrange it so that
489 * _res structure doesn't even *get linked in* into user's application
490 * (imagine static uclibc build here).
492 * The solution is a __res_sync function pointer, which is normally NULL.
493 * But if res_init is called, it gets set and any subsequent gethostbyname
494 * et al "syncronizes" our internal structures with potentially
495 * modified _res.XXX stuff by calling __res_sync.
496 * The trick here is that if res_init is not used and not linked in,
497 * gethostbyname itself won't reference _res and _res won't be linked in
498 * either. Other possible methods like
499 * if (__res_sync_just_an_int_flag)
500 * __sync_me_with_res()
501 * would pull in __sync_me_with_res, which pulls in _res. Bad.
507 int __encode_header(struct resolv_header
*h
, unsigned char *dest
, int maxlen
)
509 if (maxlen
< HFIXEDSZ
)
512 dest
[0] = (h
->id
& 0xff00) >> 8;
513 dest
[1] = (h
->id
& 0x00ff) >> 0;
514 dest
[2] = (h
->qr
? 0x80 : 0) |
515 ((h
->opcode
& 0x0f) << 3) |
519 dest
[3] = (h
->ra
? 0x80 : 0) | (h
->rcode
& 0x0f);
520 dest
[4] = (h
->qdcount
& 0xff00) >> 8;
521 dest
[5] = (h
->qdcount
& 0x00ff) >> 0;
522 dest
[6] = (h
->ancount
& 0xff00) >> 8;
523 dest
[7] = (h
->ancount
& 0x00ff) >> 0;
524 dest
[8] = (h
->nscount
& 0xff00) >> 8;
525 dest
[9] = (h
->nscount
& 0x00ff) >> 0;
526 dest
[10] = (h
->arcount
& 0xff00) >> 8;
527 dest
[11] = (h
->arcount
& 0x00ff) >> 0;
531 #endif /* L_encodeh */
536 void __decode_header(unsigned char *data
,
537 struct resolv_header
*h
)
539 h
->id
= (data
[0] << 8) | data
[1];
540 h
->qr
= (data
[2] & 0x80) ? 1 : 0;
541 h
->opcode
= (data
[2] >> 3) & 0x0f;
542 h
->aa
= (data
[2] & 0x04) ? 1 : 0;
543 h
->tc
= (data
[2] & 0x02) ? 1 : 0;
544 h
->rd
= (data
[2] & 0x01) ? 1 : 0;
545 h
->ra
= (data
[3] & 0x80) ? 1 : 0;
546 h
->rcode
= data
[3] & 0x0f;
547 h
->qdcount
= (data
[4] << 8) | data
[5];
548 h
->ancount
= (data
[6] << 8) | data
[7];
549 h
->nscount
= (data
[8] << 8) | data
[9];
550 h
->arcount
= (data
[10] << 8) | data
[11];
552 #endif /* L_decodeh */
557 /* Encode a dotted string into nameserver transport-level encoding.
558 This routine is fairly dumb, and doesn't attempt to compress
560 int __encode_dotted(const char *dotted
, unsigned char *dest
, int maxlen
)
564 while (dotted
&& *dotted
) {
565 char *c
= strchr(dotted
, '.');
566 int l
= c
? c
- dotted
: strlen(dotted
);
568 /* two consecutive dots are not valid */
572 if (l
>= (maxlen
- used
- 1))
576 memcpy(dest
+ used
, dotted
, l
);
591 #endif /* L_encoded */
596 /* Decode a dotted string from nameserver transport-level encoding.
597 This routine understands compressed data. */
598 int __decode_dotted(const unsigned char *packet
,
608 unsigned maxiter
= 256;
615 if (offset
>= packet_len
)
617 b
= packet
[offset
++];
624 if ((b
& 0xc0) == 0xc0) {
625 if (offset
>= packet_len
)
629 /* compressed item, redirect */
630 offset
= ((b
& 0x3f) << 8) | packet
[offset
];
635 if (used
+ b
+ 1 >= dest_len
)
637 if (offset
+ b
>= packet_len
)
639 memcpy(dest
+ used
, packet
+ offset
, b
);
646 if (packet
[offset
] != 0)
654 /* The null byte must be counted too */
658 DPRINTF("Total decode len = %d\n", total
);
662 #endif /* L_decoded */
667 int __encode_question(const struct resolv_question
*q
,
673 i
= __encode_dotted(q
->dotted
, dest
, maxlen
);
683 dest
[0] = (q
->qtype
& 0xff00) >> 8;
684 dest
[1] = (q
->qtype
& 0x00ff) >> 0;
685 dest
[2] = (q
->qclass
& 0xff00) >> 8;
686 dest
[3] = (q
->qclass
& 0x00ff) >> 0;
690 #endif /* L_encodeq */
695 int __encode_answer(struct resolv_answer
*a
, unsigned char *dest
, int maxlen
)
699 i
= __encode_dotted(a
->dotted
, dest
, maxlen
);
706 if (maxlen
< (RRFIXEDSZ
+ a
->rdlength
))
709 *dest
++ = (a
->atype
& 0xff00) >> 8;
710 *dest
++ = (a
->atype
& 0x00ff) >> 0;
711 *dest
++ = (a
->aclass
& 0xff00) >> 8;
712 *dest
++ = (a
->aclass
& 0x00ff) >> 0;
713 *dest
++ = (a
->ttl
& 0xff000000) >> 24;
714 *dest
++ = (a
->ttl
& 0x00ff0000) >> 16;
715 *dest
++ = (a
->ttl
& 0x0000ff00) >> 8;
716 *dest
++ = (a
->ttl
& 0x000000ff) >> 0;
717 *dest
++ = (a
->rdlength
& 0xff00) >> 8;
718 *dest
++ = (a
->rdlength
& 0x00ff) >> 0;
719 memcpy(dest
, a
->rdata
, a
->rdlength
);
721 return i
+ RRFIXEDSZ
+ a
->rdlength
;
723 #endif /* L_encodea */
726 #ifdef CURRENTLY_UNUSED
729 int __encode_packet(struct resolv_header
*h
,
730 struct resolv_question
**q
,
731 struct resolv_answer
**an
,
732 struct resolv_answer
**ns
,
733 struct resolv_answer
**ar
,
734 unsigned char *dest
, int maxlen
) attribute_hidden
;
735 int __encode_packet(struct resolv_header
*h
,
736 struct resolv_question
**q
,
737 struct resolv_answer
**an
,
738 struct resolv_answer
**ns
,
739 struct resolv_answer
**ar
,
740 unsigned char *dest
, int maxlen
)
745 i
= __encode_header(h
, dest
, maxlen
);
753 for (j
= 0; j
< h
->qdcount
; j
++) {
754 i
= __encode_question(q
[j
], dest
, maxlen
);
762 for (j
= 0; j
< h
->ancount
; j
++) {
763 i
= __encode_answer(an
[j
], dest
, maxlen
);
770 for (j
= 0; j
< h
->nscount
; j
++) {
771 i
= __encode_answer(ns
[j
], dest
, maxlen
);
778 for (j
= 0; j
< h
->arcount
; j
++) {
779 i
= __encode_answer(ar
[j
], dest
, maxlen
);
789 #endif /* L_encodep */
794 int __decode_packet(unsigned char *data
, struct resolv_header
*h
) attribute_hidden
;
795 int __decode_packet(unsigned char *data
, struct resolv_header
*h
)
797 __decode_header(data
, h
);
800 #endif /* L_decodep */
805 int __form_query(int id
,
808 unsigned char *packet
,
809 int maxlen
) attribute_hidden
;
810 int __form_query(int id
,
813 unsigned char *packet
,
816 struct resolv_header h
;
817 struct resolv_question q
;
820 memset(&h
, 0, sizeof(h
));
824 q
.dotted
= (char *) name
;
826 q
.qclass
= C_IN
; /* CLASS_IN */
828 i
= __encode_header(&h
, packet
, maxlen
);
832 j
= __encode_question(&q
, packet
+ i
, maxlen
- i
);
838 #endif /* L_formquery */
839 #endif /* CURRENTLY_UNUSED */
842 #ifdef L_opennameservers
844 # if __BYTE_ORDER == __LITTLE_ENDIAN
845 #define NAMESERVER_PORT_N (__bswap_constant_16(NAMESERVER_PORT))
847 #define NAMESERVER_PORT_N NAMESERVER_PORT
850 __UCLIBC_MUTEX_INIT(__resolv_lock
, PTHREAD_MUTEX_INITIALIZER
);
852 /* Protected by __resolv_lock */
853 void (*__res_sync
)(void);
854 /*uint32_t __resolv_opts; */
855 uint8_t __resolv_timeout
= RES_TIMEOUT
;
856 uint8_t __resolv_attempts
= RES_DFLRETRY
;
857 unsigned __nameservers
;
858 unsigned __searchdomains
;
859 sockaddr46_t
*__nameserver
;
860 char **__searchdomain
;
861 #ifdef __UCLIBC_HAS_IPV4__
862 const struct sockaddr_in __local_nameserver
= {
863 .sin_family
= AF_INET
,
864 .sin_port
= NAMESERVER_PORT_N
,
867 const struct sockaddr_in6 __local_nameserver
= {
868 .sin6_family
= AF_INET6
,
869 .sin6_port
= NAMESERVER_PORT_N
,
873 /* Helpers. Both stop on EOL, if it's '\n', it is converted to NUL first */
874 static char *skip_nospace(char *p
)
876 while (*p
!= '\0' && !isspace(*p
)) {
885 static char *skip_and_NUL_space(char *p
)
887 /* NB: '\n' is not isspace! */
890 if (c
== '\0' || !isspace(c
))
893 if (c
== '\n' || c
== '#')
900 /* Must be called under __resolv_lock. */
901 void __open_nameservers(void)
903 static uint32_t resolv_conf_mtime
;
905 char szBuffer
[MAXLEN_searchdomain
];
911 /* Reread /etc/resolv.conf if it was modified. */
913 if (stat(_PATH_RESCONF
, &sb
) != 0)
915 if (resolv_conf_mtime
!= (uint32_t)sb
.st_mtime
) {
916 resolv_conf_mtime
= sb
.st_mtime
;
917 __close_nameservers(); /* force config reread */
924 __resolv_timeout
= RES_TIMEOUT
;
925 __resolv_attempts
= RES_DFLRETRY
;
927 fp
= fopen(_PATH_RESCONF
, "r");
928 #ifdef FALLBACK_TO_CONFIG_RESOLVCONF
930 /* If we do not have a pre-populated /etc/resolv.conf then
931 try to use the one from /etc/config which exists on numerous
932 systems ranging from some uClinux to IRIX installations and
933 may be the only /etc dir that was mounted rw. */
934 fp
= fopen("/etc/config/resolv.conf", "r");
939 while (fgets(szBuffer
, sizeof(szBuffer
), fp
) != NULL
) {
943 keyword
= p
= skip_and_NUL_space(szBuffer
);
947 p
= skip_and_NUL_space(p
);
949 if (strcmp(keyword
, "nameserver") == 0) {
950 /* terminate IP addr */
951 *skip_nospace(p
) = '\0';
952 memset(&sa
, 0, sizeof(sa
));
953 if (0) /* nothing */;
954 #ifdef __UCLIBC_HAS_IPV6__
955 else if (inet_pton(AF_INET6
, p
, &sa
.sa6
.sin6_addr
) > 0) {
956 sa
.sa6
.sin6_family
= AF_INET6
;
957 sa
.sa6
.sin6_port
= htons(NAMESERVER_PORT
);
960 #ifdef __UCLIBC_HAS_IPV4__
961 else if (inet_pton(AF_INET
, p
, &sa
.sa4
.sin_addr
) > 0) {
962 sa
.sa4
.sin_family
= AF_INET
;
963 sa
.sa4
.sin_port
= htons(NAMESERVER_PORT
);
967 continue; /* garbage on this line */
968 ptr
= realloc(__nameserver
, (__nameservers
+ 1) * sizeof(__nameserver
[0]));
972 __nameserver
[__nameservers
++] = sa
; /* struct copy */
975 if (strcmp(keyword
, "domain") == 0 || strcmp(keyword
, "search") == 0) {
978 /* free old domains ("last 'domain' or 'search' wins" rule) */
979 while (__searchdomains
)
980 free(__searchdomain
[--__searchdomains
]);
981 /*free(__searchdomain);*/
982 /*__searchdomain = NULL; - not necessary */
984 /* terminate current word */
985 p1
= skip_nospace(p
);
986 /* find next word (maybe) */
987 p1
= skip_and_NUL_space(p1
);
989 ptr
= realloc(__searchdomain
, (__searchdomains
+ 1) * sizeof(__searchdomain
[0]));
992 __searchdomain
= ptr
;
993 /* NB: strlen(p) <= MAXLEN_searchdomain) because szBuffer[] is smaller */
997 DPRINTF("adding search %s\n", (char*)ptr
);
998 __searchdomain
[__searchdomains
++] = (char*)ptr
;
1004 /* if (strcmp(keyword, "sortlist") == 0)... */
1005 if (strcmp(keyword
, "options") == 0) {
1009 if (p
== NULL
|| (p1
= strchr(p
, ':')) == NULL
)
1012 if (strcmp(p
, "timeout") == 0)
1013 what
= &__resolv_timeout
;
1014 else if (strcmp(p
, "attempts") == 0)
1015 what
= &__resolv_attempts
;
1019 DPRINTF("option %s:%d\n", p
, *what
);
1024 if (__nameservers
== 0) {
1025 /* Have to handle malloc failure! What a mess...
1026 * And it's not only here, we need to be careful
1027 * to never write into __nameserver[0] if it points
1028 * to constant __local_nameserver, or free it. */
1029 __nameserver
= malloc(sizeof(__nameserver
[0]));
1031 memcpy(__nameserver
, &__local_nameserver
, sizeof(__local_nameserver
));
1033 __nameserver
= (void*) &__local_nameserver
;
1036 if (__searchdomains
== 0) {
1039 i
= gethostname(buf
, sizeof(buf
) - 1);
1040 buf
[sizeof(buf
) - 1] = '\0';
1041 if (i
== 0 && (p
= strchr(buf
, '.')) != NULL
&& p
[1]) {
1045 __searchdomain
= malloc(sizeof(__searchdomain
[0]));
1046 if (!__searchdomain
) {
1050 __searchdomain
[0] = p
;
1055 DPRINTF("nameservers = %d\n", __nameservers
);
1061 #endif /* L_opennameservers */
1064 #ifdef L_closenameservers
1066 /* Must be called under __resolv_lock. */
1067 void __close_nameservers(void)
1069 if (__nameserver
!= (void*) &__local_nameserver
)
1071 __nameserver
= NULL
;
1073 while (__searchdomains
)
1074 free(__searchdomain
[--__searchdomains
]);
1075 free(__searchdomain
);
1076 __searchdomain
= NULL
;
1077 /*__searchdomains = 0; - already is */
1079 #endif /* L_closenameservers */
1085 static int __length_question(const unsigned char *data
, int maxlen
)
1087 const unsigned char *start
;
1100 if ((b
& 0xc0) == 0xc0) {
1101 /* It's a "compressed" name. */
1102 data
++; /* skip lsb of redirected offset */
1107 maxlen
-= (b
+ 1); /* account for data++ above */
1109 /* Up to here we were skipping encoded name */
1111 /* Account for QTYPE and QCLASS fields */
1114 return data
- start
+ 2 + 2;
1117 static int __decode_answer(const unsigned char *message
, /* packet */
1119 int len
, /* total packet len */
1120 struct resolv_answer
*a
)
1125 DPRINTF("decode_answer(start): off %d, len %d\n", offset
, len
);
1126 i
= __decode_dotted(message
, offset
, len
, temp
, sizeof(temp
));
1130 message
+= offset
+ i
;
1131 len
-= i
+ RRFIXEDSZ
+ offset
;
1133 DPRINTF("decode_answer: off %d, len %d, i %d\n", offset
, len
, i
);
1137 /* TODO: what if strdup fails? */
1138 a
->dotted
= strdup(temp
);
1139 a
->atype
= (message
[0] << 8) | message
[1];
1141 a
->aclass
= (message
[0] << 8) | message
[1];
1143 a
->ttl
= (message
[0] << 24) |
1144 (message
[1] << 16) | (message
[2] << 8) | (message
[3] << 0);
1146 a
->rdlength
= (message
[0] << 8) | message
[1];
1149 a
->rdoffset
= offset
+ i
+ RRFIXEDSZ
;
1151 DPRINTF("i=%d,rdlength=%d\n", i
, a
->rdlength
);
1153 if (len
< a
->rdlength
)
1155 return i
+ RRFIXEDSZ
+ a
->rdlength
;
1159 * a.buf(len) = auxiliary buffer for IP addresses after first one
1160 * a.add_count = how many additional addresses are there already
1161 * outpacket = where to save ptr to raw packet? can be NULL
1163 * ret < 0: error, all other data is not valid
1164 * ret >= 0: length of reply packet
1165 * a.add_count & a.buf: updated
1166 * a.rdlength: length of addresses (4 bytes for IPv4)
1167 * *outpacket: updated (packet is malloced, you need to free it)
1168 * a.rdata: points into *outpacket to 1st IP addr
1169 * NB: don't pass outpacket == NULL if you need to use a.rdata!
1170 * a.atype: type of query?
1171 * a.dotted: which name we _actually_ used. May contain search domains
1172 * appended. (why the filed is called "dotted" I have no idea)
1173 * This is a malloced string. May be NULL because strdup failed.
1175 int __dns_lookup(const char *name
,
1177 unsigned char **outpacket
,
1178 struct resolv_answer
*a
)
1180 /* Protected by __resolv_lock: */
1181 static int last_ns_num
= 0;
1182 static uint16_t last_id
= 1;
1193 struct resolv_header h
;
1194 struct resolv_question q
;
1195 struct resolv_answer ma
;
1196 bool first_answer
= 1;
1198 unsigned char *packet
= malloc(PACKETSZ
);
1200 int variant
= -1; /* search domain to append, -1: none */
1201 int local_ns_num
= -1; /* Nth server to use */
1202 int local_id
= local_id
; /* for compiler */
1210 name_len
= strlen(name
);
1211 if ((unsigned)name_len
>= MAXDNAME
- MAXLEN_searchdomain
- 2)
1212 goto fail
; /* paranoia */
1213 lookup
= malloc(name_len
+ 1/*for '.'*/ + MAXLEN_searchdomain
+ 1);
1214 if (!packet
|| !lookup
|| !name
[0])
1216 ends_with_dot
= (name
[name_len
- 1] == '.');
1217 contains_dot
= strchr(name
, '.') != NULL
;
1218 /* no strcpy! paranoia, user might change name[] under us */
1219 memcpy(lookup
, name
, name_len
);
1221 DPRINTF("Looking up type %d answer for '%s'\n", type
, name
);
1222 retries_left
= 0; /* for compiler */
1224 unsigned act_variant
;
1226 unsigned reply_timeout
;
1233 /* Mess with globals while under lock */
1234 /* NB: even data *pointed to* by globals may vanish
1235 * outside the locks. We should assume any and all
1236 * globals can completely change between locked
1237 * code regions. OTOH, this is rare, so we don't need
1238 * to handle it "nicely" (do not skip servers,
1239 * search domains, etc), we only need to ensure
1240 * we do not SEGV, use freed+overwritten data
1241 * or do other Really Bad Things. */
1242 __UCLIBC_MUTEX_LOCK(__resolv_lock
);
1243 __open_nameservers();
1244 if (type
!= T_PTR
) {
1245 sdomains
= __searchdomains
;
1247 lookup
[name_len
] = '\0';
1248 /* For qualified names, act_variant = MAX_UINT, 0, .., sdomains-1
1249 * => Try original name first, then append search domains
1250 * For names without domain, act_variant = 0, 1, .., sdomains
1251 * => Try search domains first, original name last */
1252 act_variant
= contains_dot
? variant
: variant
+ 1;
1253 if (act_variant
< sdomains
) {
1254 /* lookup is name_len + 1 + MAXLEN_searchdomain + 1 long */
1255 /* __searchdomain[] is not bigger than MAXLEN_searchdomain */
1256 lookup
[name_len
] = '.';
1257 strcpy(&lookup
[name_len
+ 1], __searchdomain
[act_variant
]);
1259 /* first time? pick starting server etc */
1260 if (local_ns_num
< 0) {
1262 /*TODO: implement /etc/resolv.conf's "options rotate"
1263 (a.k.a. RES_ROTATE bit in _res.options)
1265 if (_res.options & RES_ROTATE) */
1266 local_ns_num
= last_ns_num
;
1267 retries_left
= __nameservers
* __resolv_attempts
;
1269 if (local_ns_num
>= __nameservers
)
1273 /* write new values back while still under lock */
1275 last_ns_num
= local_ns_num
;
1277 /* can't just take a pointer, __nameserver[x]
1278 * is not safe to use outside of locks */
1279 sa
= __nameserver
[local_ns_num
];
1280 __UCLIBC_MUTEX_UNLOCK(__resolv_lock
);
1282 memset(packet
, 0, PACKETSZ
);
1283 memset(&h
, 0, sizeof(h
));
1289 DPRINTF("encoding header\n", h
.rd
);
1290 i
= __encode_header(&h
, packet
, PACKETSZ
);
1294 /* encode question */
1295 DPRINTF("lookup name: %s\n", lookup
);
1298 q
.qclass
= C_IN
; /* CLASS_IN */
1299 j
= __encode_question(&q
, packet
+i
, PACKETSZ
-i
);
1307 const socklen_t plen
= sa
.sa
.sa_family
== AF_INET
? INET_ADDRSTRLEN
: INET6_ADDRSTRLEN
;
1308 char *pbuf
= malloc(plen
);
1309 if (pbuf
== NULL
) ;/* nothing */
1310 #ifdef __UCLIBC_HAS_IPV6__
1311 else if (sa
.sa
.sa_family
== AF_INET6
)
1312 pbuf
= (char*)inet_ntop(AF_INET6
, &sa
.sa6
.sin6_addr
, pbuf
, plen
);
1314 #ifdef __UCLIBC_HAS_IPV4__
1315 else if (sa
.sa
.sa_family
== AF_INET
)
1316 pbuf
= (char*)inet_ntop(AF_INET
, &sa
.sa4
.sin_addr
, pbuf
, plen
);
1318 DPRINTF("On try %d, sending query to %s, port %d\n",
1319 retries_left
, pbuf
, NAMESERVER_PORT
);
1323 fd
= socket(sa
.sa
.sa_family
, SOCK_DGRAM
, IPPROTO_UDP
);
1324 if (fd
< 0) /* paranoia */
1325 goto try_next_server
;
1326 rc
= connect(fd
, &sa
.sa
, sizeof(sa
));
1328 /*if (errno == ENETUNREACH) { */
1329 /* routing error, presume not transient */
1330 goto try_next_server
;
1332 /*For example, what transient error this can be? Can't think of any */
1336 DPRINTF("Xmit packet len:%d id:%d qr:%d\n", packet_len
, h
.id
, h
.qr
);
1337 /* no error check - if it fails, we time out on recv */
1338 send(fd
, packet
, packet_len
, 0);
1341 reply_timeout
= __resolv_timeout
;
1345 tv
.tv_sec
= reply_timeout
;
1347 if (select(fd
+ 1, &fds
, NULL
, NULL
, &tv
) <= 0) {
1348 DPRINTF("Timeout\n");
1349 /* timed out, so retry send and receive
1350 * to next nameserver */
1351 goto try_next_server
;
1354 #else /* !USE_SELECT */
1355 reply_timeout
= __resolv_timeout
* 1000;
1358 fds
.events
= POLLIN
;
1359 if (poll(&fds
, 1, reply_timeout
) <= 0) {
1360 DPRINTF("Timeout\n");
1361 /* timed out, so retry send and receive
1362 * to next nameserver */
1363 goto try_next_server
;
1365 if (fds
.revents
& (POLLERR
| POLLHUP
| POLLNVAL
)) {
1366 DPRINTF("Bad event\n");
1367 goto try_next_server
;
1369 /*TODO: better timeout accounting?*/
1370 reply_timeout
-= 1000;
1371 #endif /* USE_SELECT */
1373 /* vda: a bogus response seen in real world (caused SEGV in uclibc):
1374 * "ping www.google.com" sending AAAA query and getting
1375 * response with one answer... with answer part missing!
1376 * Fixed by thorough checks for not going past the packet's end.
1380 static const char test_query
[32] = "\0\2\1\0\0\1\0\0\0\0\0\0\3www\6google\3com\0\0\34\0\1";
1381 static const char test_respn
[32] = "\0\2\201\200\0\1\0\1\0\0\0\0\3www\6google\3com\0\0\34\0\1";
1382 pos
= memcmp(packet
+ 2, test_query
+ 2, 30);
1383 packet_len
= recv(fd
, packet
, PACKETSZ
, MSG_DONTWAIT
);
1386 memcpy(packet
+ 2, test_respn
+ 2, 30);
1390 packet_len
= recv(fd
, packet
, PACKETSZ
, MSG_DONTWAIT
);
1393 if (packet_len
< HFIXEDSZ
) {
1395 * If the peer did shutdown then retry later,
1396 * try next peer on error.
1397 * it's just a bogus packet from somewhere */
1399 if (packet_len
>= 0 && reply_timeout
)
1401 goto try_next_server
;
1403 __decode_header(packet
, &h
);
1404 DPRINTF("len:%d id:%d qr:%d\n", packet_len
, h
.id
, h
.qr
);
1405 if (h
.id
!= local_id
|| !h
.qr
) {
1410 DPRINTF("Got response (i think)!\n");
1411 DPRINTF("qrcount=%d,ancount=%d,nscount=%d,arcount=%d\n",
1412 h
.qdcount
, h
.ancount
, h
.nscount
, h
.arcount
);
1413 DPRINTF("opcode=%d,aa=%d,tc=%d,rd=%d,ra=%d,rcode=%d\n",
1414 h
.opcode
, h
.aa
, h
.tc
, h
.rd
, h
.ra
, h
.rcode
);
1416 /* bug 660 says we treat negative response as an error
1417 * and retry, which is, eh, an error. :)
1418 * We were incurring long delays because of this. */
1419 if (h
.rcode
== NXDOMAIN
|| h
.rcode
== SERVFAIL
) {
1420 /* if possible, try next search domain */
1421 if (!ends_with_dot
) {
1422 DPRINTF("variant:%d sdomains:%d\n", variant
, sdomains
);
1423 if (variant
< sdomains
- 1) {
1424 /* next search domain */
1428 /* no more search domains to try */
1430 if (h
.rcode
!= SERVFAIL
) {
1431 /* dont loop, this is "no such host" situation */
1432 h_errno
= HOST_NOT_FOUND
;
1436 /* Insert other non-fatal errors here, which do not warrant
1437 * switching to next nameserver */
1439 /* Strange error, assuming this nameserver is feeling bad */
1441 goto try_next_server
;
1443 /* Code below won't work correctly with h.ancount == 0, so... */
1444 if (h
.ancount
<= 0) {
1445 h_errno
= NO_DATA
; /* [is this correct code to check for?] */
1449 for (j
= 0; j
< h
.qdcount
; j
++) {
1450 DPRINTF("Skipping question %d at %d\n", j
, pos
);
1451 i
= __length_question(packet
+ pos
, packet_len
- pos
);
1453 DPRINTF("Packet'question section "
1454 "is truncated, trying next server\n");
1455 goto try_next_server
;
1458 DPRINTF("Length of question %d is %d\n", j
, i
);
1460 DPRINTF("Decoding answer at pos %d\n", pos
);
1464 for (j
= 0; j
< h
.ancount
; j
++) {
1465 i
= __decode_answer(packet
, pos
, packet_len
, &ma
);
1467 DPRINTF("failed decode %d\n", i
);
1468 /* If the message was truncated but we have
1469 * decoded some answers, pretend it's OK */
1472 goto try_next_server
;
1478 ma
.buflen
= a
->buflen
;
1479 ma
.add_count
= a
->add_count
;
1481 memcpy(a
, &ma
, sizeof(ma
));
1482 if (a
->atype
!= T_SIG
&& (NULL
== a
->buf
|| (type
!= T_A
&& type
!= T_AAAA
)))
1484 if (a
->atype
!= type
)
1486 a
->add_count
= h
.ancount
- j
- 1;
1487 if ((a
->rdlength
+ sizeof(struct in_addr
*)) * a
->add_count
> a
->buflen
)
1493 if (ma
.atype
!= type
)
1495 if (a
->rdlength
!= ma
.rdlength
) {
1497 DPRINTF("Answer address len(%u) differs from original(%u)\n",
1498 ma
.rdlength
, a
->rdlength
);
1499 goto try_next_server
;
1501 memcpy(a
->buf
+ (a
->add_count
* ma
.rdlength
), ma
.rdata
, ma
.rdlength
);
1507 DPRINTF("Answer name = |%s|\n", a
->dotted
);
1508 DPRINTF("Answer type = |%d|\n", a
->atype
);
1512 *outpacket
= packet
;
1519 /* Try next nameserver */
1523 } while (retries_left
> 0);
1526 h_errno
= NETDB_INTERNAL
;
1534 #endif /* L_dnslookup */
1537 #ifdef L_read_etc_hosts_r
1539 parser_t
* __open_etc_hosts(void)
1542 parser
= config_open("/etc/hosts");
1543 #ifdef FALLBACK_TO_CONFIG_RESOLVCONF
1545 parser
= config_open("/etc/config/hosts");
1550 #define MINTOKENS 2 /* ip address + canonical name */
1551 #define MAXTOKENS (MINTOKENS + MAXALIASES)
1552 #define HALISTOFF (sizeof(char*) * (MAXTOKENS + 1)) /* reserve space for list terminator */
1553 #define INADDROFF (HALISTOFF + 2 * sizeof(char*))
1555 int __read_etc_hosts_r(
1559 enum etc_hosts_action action
,
1560 struct hostent
*result_buf
,
1561 char *buf
, size_t buflen
,
1562 struct hostent
**result
,
1566 struct in_addr
*h_addr0
= NULL
;
1567 const size_t aliaslen
= INADDROFF
+
1568 #ifdef __UCLIBC_HAS_IPV6__
1569 sizeof(struct in6_addr
)
1571 sizeof(struct in_addr
)
1574 int ret
= HOST_NOT_FOUND
;
1575 /* make sure pointer is aligned */
1576 int i
= ALIGN_BUFFER_OFFSET(buf
);
1580 *h_errnop
= NETDB_INTERNAL
;
1581 if (/* (ssize_t)buflen < 0 || */ buflen
< aliaslen
1582 || (buflen
- aliaslen
) < BUFSZ
+ 1)
1585 parser
= __open_etc_hosts();
1586 if (parser
== NULL
) {
1591 * char *alias[MAXTOKENS] = {address, name, aliases...}
1592 * char **h_addr_list[1] = {*in[6]_addr, NULL}
1594 * char line_buffer[BUFSZ+];
1597 parser
->data_len
= aliaslen
;
1598 parser
->line_len
= buflen
- aliaslen
;
1599 *h_errnop
= HOST_NOT_FOUND
;
1600 /* <ip>[[:space:]][<aliases>] */
1601 while (config_read(parser
, &tok
, MAXTOKENS
, MINTOKENS
, "# \t", PARSE_NORMAL
)) {
1602 result_buf
->h_aliases
= tok
+1;
1603 if (action
== GETHOSTENT
) {
1604 /* Return whatever the next entry happens to be. */
1606 } else if (action
== GET_HOSTS_BYADDR
) {
1607 if (strcmp(name
, *tok
) != 0)
1609 } else { /* GET_HOSTS_BYNAME */
1611 char **alias
= tok
+ 1;
1612 while (aliases
< MAXALIASES
) {
1613 char *tmp
= *(alias
+aliases
++);
1614 if (tmp
&& strcasecmp(name
, tmp
) == 0)
1620 result_buf
->h_name
= *(result_buf
->h_aliases
++);
1621 result_buf
->h_addr_list
= (char**)(buf
+ HALISTOFF
);
1622 *(result_buf
->h_addr_list
+ 1) = '\0';
1623 h_addr0
= (struct in_addr
*)(buf
+ INADDROFF
);
1624 result_buf
->h_addr
= (char*)h_addr0
;
1625 if (0) /* nothing */;
1626 #ifdef __UCLIBC_HAS_IPV4__
1627 else if (type
== AF_INET
1628 && inet_pton(AF_INET
, *tok
, h_addr0
) > 0) {
1629 DPRINTF("Found INET\n");
1630 result_buf
->h_addrtype
= AF_INET
;
1631 result_buf
->h_length
= sizeof(struct in_addr
);
1632 *result
= result_buf
;
1633 ret
= NETDB_SUCCESS
;
1636 #ifdef __UCLIBC_HAS_IPV6__
1637 #define in6 ((struct in6_addr *)buf)
1638 else if (type
== AF_INET6
1639 && inet_pton(AF_INET6
, *tok
, h_addr0
) > 0) {
1640 DPRINTF("Found INET6\n");
1641 result_buf
->h_addrtype
= AF_INET6
;
1642 result_buf
->h_length
= sizeof(struct in6_addr
);
1643 *result
= result_buf
;
1644 ret
= NETDB_SUCCESS
;
1648 /* continue parsing in the hope the user has multiple
1649 * host types listed in the database like so:
1652 * If looking for an IPv6 addr, don't bail when we got the IPv4
1654 DPRINTF("Error: Found host but different address family\n");
1655 /* NB: gethostbyname2_r depends on this feature
1656 * to avoid looking for IPv6 addr of "localhost" etc */
1662 if (action
!= GETHOSTENT
)
1663 config_close(parser
);
1667 #endif /* L_read_etc_hosts_r */
1670 #ifdef L_get_hosts_byname_r
1672 int __get_hosts_byname_r(const char *name
,
1674 struct hostent
*result_buf
,
1677 struct hostent
**result
,
1680 return __read_etc_hosts_r(NULL
, name
, type
, GET_HOSTS_BYNAME
,
1681 result_buf
, buf
, buflen
, result
, h_errnop
);
1683 #endif /* L_get_hosts_byname_r */
1686 #ifdef L_get_hosts_byaddr_r
1688 int __get_hosts_byaddr_r(const char *addr
,
1691 struct hostent
*result_buf
,
1694 struct hostent
**result
,
1697 #ifndef __UCLIBC_HAS_IPV6__
1698 char ipaddr
[INET_ADDRSTRLEN
];
1700 char ipaddr
[INET6_ADDRSTRLEN
];
1704 #ifdef __UCLIBC_HAS_IPV4__
1706 if (len
!= sizeof(struct in_addr
))
1710 #ifdef __UCLIBC_HAS_IPV6__
1712 if (len
!= sizeof(struct in6_addr
))
1720 inet_ntop(type
, addr
, ipaddr
, sizeof(ipaddr
));
1722 return __read_etc_hosts_r(NULL
, ipaddr
, type
, GET_HOSTS_BYADDR
,
1723 result_buf
, buf
, buflen
, result
, h_errnop
);
1725 #endif /* L_get_hosts_byaddr_r */
1728 #ifdef L_getnameinfo
1730 int getnameinfo(const struct sockaddr
*sa
,
1740 struct hostent
*hoste
= NULL
;
1743 if (flags
& ~(NI_NUMERICHOST
|NI_NUMERICSERV
|NI_NOFQDN
|NI_NAMEREQD
|NI_DGRAM
))
1744 return EAI_BADFLAGS
;
1746 if (sa
== NULL
|| addrlen
< sizeof(sa_family_t
))
1749 if ((flags
& NI_NAMEREQD
) && host
== NULL
&& serv
== NULL
)
1752 if (sa
->sa_family
== AF_LOCAL
) /* valid */;
1753 #ifdef __UCLIBC_HAS_IPV4__
1754 else if (sa
->sa_family
== AF_INET
) {
1755 if (addrlen
< sizeof(struct sockaddr_in
))
1759 #ifdef __UCLIBC_HAS_IPV6__
1760 else if (sa
->sa_family
== AF_INET6
) {
1761 if (addrlen
< sizeof(struct sockaddr_in6
))
1768 if (host
!= NULL
&& hostlen
> 0)
1769 switch (sa
->sa_family
) {
1771 #ifdef __UCLIBC_HAS_IPV6__
1774 if (!(flags
& NI_NUMERICHOST
)) {
1775 if (0) /* nothing */;
1776 #ifdef __UCLIBC_HAS_IPV6__
1777 else if (sa
->sa_family
== AF_INET6
)
1778 hoste
= gethostbyaddr((const void *)
1779 &(((const struct sockaddr_in6
*) sa
)->sin6_addr
),
1780 sizeof(struct in6_addr
), AF_INET6
);
1782 #ifdef __UCLIBC_HAS_IPV4__
1784 hoste
= gethostbyaddr((const void *)
1785 &(((const struct sockaddr_in
*)sa
)->sin_addr
),
1786 sizeof(struct in_addr
), AF_INET
);
1791 if ((flags
& NI_NOFQDN
)
1792 && (getdomainname(domain
, sizeof(domain
)) == 0)
1793 && (c
= strstr(hoste
->h_name
, domain
)) != NULL
1794 && (c
!= hoste
->h_name
) && (*(--c
) == '.')
1796 strncpy(host
, hoste
->h_name
,
1797 MIN(hostlen
, (size_t) (c
- hoste
->h_name
)));
1798 host
[MIN(hostlen
- 1, (size_t) (c
- hoste
->h_name
))] = '\0';
1800 strncpy(host
, hoste
->h_name
, hostlen
);
1807 const char *c
= NULL
;
1809 if (flags
& NI_NAMEREQD
) {
1813 if (0) /* nothing */;
1814 #ifdef __UCLIBC_HAS_IPV6__
1815 else if (sa
->sa_family
== AF_INET6
) {
1816 const struct sockaddr_in6
*sin6p
;
1818 sin6p
= (const struct sockaddr_in6
*) sa
;
1819 c
= inet_ntop(AF_INET6
,
1820 (const void *) &sin6p
->sin6_addr
,
1823 /* Does scope id need to be supported? */
1825 scopeid
= sin6p
->sin6_scope_id
;
1827 /* Buffer is >= IFNAMSIZ+1. */
1828 char scopebuf
[IFNAMSIZ
+ 1];
1830 int ni_numericscope
= 0;
1831 size_t real_hostlen
= strnlen(host
, hostlen
);
1832 size_t scopelen
= 0;
1834 scopebuf
[0] = SCOPE_DELIMITER
;
1836 scopeptr
= &scopebuf
[1];
1838 if (IN6_IS_ADDR_LINKLOCAL(&sin6p
->sin6_addr
)
1839 || IN6_IS_ADDR_MC_LINKLOCAL(&sin6p
->sin6_addr
)) {
1840 if (if_indextoname(scopeid
, scopeptr
) == NULL
)
1843 scopelen
= strlen(scopebuf
);
1848 if (ni_numericscope
)
1849 scopelen
= 1 + snprintf(scopeptr
,
1855 if (real_hostlen
+ scopelen
+ 1 > hostlen
)
1857 memcpy(host
+ real_hostlen
, scopebuf
, scopelen
+ 1);
1861 #endif /* __UCLIBC_HAS_IPV6__ */
1862 #if defined __UCLIBC_HAS_IPV4__
1864 c
= inet_ntop(AF_INET
, (const void *)
1865 &(((const struct sockaddr_in
*) sa
)->sin_addr
),
1878 if (!(flags
& NI_NUMERICHOST
)) {
1879 struct utsname utsname
;
1881 if (!uname(&utsname
)) {
1882 strncpy(host
, utsname
.nodename
, hostlen
);
1887 if (flags
& NI_NAMEREQD
) {
1892 strncpy(host
, "localhost", hostlen
);
1894 /* Already checked above
1900 if (serv
&& (servlen
> 0)) {
1901 if (sa
->sa_family
== AF_LOCAL
) {
1902 strncpy(serv
, ((const struct sockaddr_un
*) sa
)->sun_path
, servlen
);
1903 } else { /* AF_INET || AF_INET6 */
1904 if (!(flags
& NI_NUMERICSERV
)) {
1906 s
= getservbyport(((const struct sockaddr_in
*) sa
)->sin_port
,
1907 ((flags
& NI_DGRAM
) ? "udp" : "tcp"));
1909 strncpy(serv
, s
->s_name
, servlen
);
1913 snprintf(serv
, servlen
, "%d",
1914 ntohs(((const struct sockaddr_in
*) sa
)->sin_port
));
1918 if (host
&& (hostlen
> 0))
1919 host
[hostlen
-1] = 0;
1920 if (serv
&& (servlen
> 0))
1921 serv
[servlen
-1] = 0;
1925 libc_hidden_def(getnameinfo
)
1926 #endif /* L_getnameinfo */
1929 #ifdef L_gethostbyname_r
1932 * "uClibc resolver's gethostbyname does not return the requested name
1933 * as an alias, but instead returns the canonical name. glibc's
1934 * gethostbyname has a similar bug where it returns the requested name
1935 * with the search domain name appended (to make a FQDN) as an alias,
1936 * but not the original name itself. Both contradict POSIX, which says
1937 * that the name argument passed to gethostbyname must be in the alias list"
1938 * This is fixed now, and we differ from glibc:
1940 * $ ./gethostbyname_uclibc wer.google.com
1941 * h_name:'c13-ss-2-lb.cnet.com'
1943 * h_addrtype:2 AF_INET
1944 * alias:'wer.google.com' <===
1945 * addr: 0x4174efd8 '216.239.116.65'
1947 * $ ./gethostbyname_glibc wer.google.com
1948 * h_name:'c13-ss-2-lb.cnet.com'
1950 * h_addrtype:2 AF_INET
1951 * alias:'wer.google.com.com' <===
1952 * addr:'216.239.116.65'
1954 * When examples were run, /etc/resolv.conf contained "search com" line.
1956 int gethostbyname_r(const char *name
,
1957 struct hostent
*result_buf
,
1960 struct hostent
**result
,
1963 struct in_addr
**addr_list
;
1966 unsigned char *packet
;
1967 struct resolv_answer a
;
1976 /* do /etc/hosts first */
1978 int old_errno
= errno
; /* save the old errno and reset errno */
1979 __set_errno(0); /* to check for missing /etc/hosts. */
1980 i
= __get_hosts_byname_r(name
, AF_INET
, result_buf
,
1981 buf
, buflen
, result
, h_errnop
);
1982 if (i
== NETDB_SUCCESS
) {
1983 __set_errno(old_errno
);
1986 switch (*h_errnop
) {
1987 case HOST_NOT_FOUND
:
1988 wrong_af
= (i
== TRY_AGAIN
);
1991 case NETDB_INTERNAL
:
1992 if (errno
== ENOENT
) {
1995 /* else fall through */
1999 __set_errno(old_errno
);
2002 DPRINTF("Nothing found in /etc/hosts\n");
2004 *h_errnop
= NETDB_INTERNAL
;
2006 /* prepare future h_aliases[0] */
2007 i
= strlen(name
) + 1;
2008 if ((ssize_t
)buflen
<= i
)
2010 memcpy(buf
, name
, i
); /* paranoia: name might change */
2014 /* make sure pointer is aligned */
2015 i
= ALIGN_BUFFER_OFFSET(buf
);
2020 * struct in_addr* addr_list[NN+1];
2021 * struct in_addr* in[NN];
2023 alias
= (char **)buf
;
2024 buf
+= sizeof(alias
[0]) * 2;
2025 buflen
-= sizeof(alias
[0]) * 2;
2026 addr_list
= (struct in_addr
**)buf
;
2027 /* buflen may be < 0, must do signed compare */
2028 if ((ssize_t
)buflen
< 256)
2031 /* we store only one "alias" - the name itself */
2035 /* maybe it is already an address? */
2037 struct in_addr
*in
= (struct in_addr
*)(buf
+ sizeof(addr_list
[0]) * 2);
2038 if (inet_aton(name
, in
)) {
2040 addr_list
[1] = NULL
;
2041 result_buf
->h_name
= alias0
;
2042 result_buf
->h_aliases
= alias
;
2043 result_buf
->h_addrtype
= AF_INET
;
2044 result_buf
->h_length
= sizeof(struct in_addr
);
2045 result_buf
->h_addr_list
= (char **) addr_list
;
2046 *result
= result_buf
;
2047 *h_errnop
= NETDB_SUCCESS
;
2048 return NETDB_SUCCESS
;
2052 /* what if /etc/hosts has it but it's not IPv4?
2053 * F.e. "::1 localhost6". We don't do DNS query for such hosts -
2054 * "ping localhost6" should be fast even if DNS server is down! */
2056 *h_errnop
= HOST_NOT_FOUND
;
2060 /* talk to DNS servers */
2062 /* take into account that at least one address will be there,
2063 * we'll need space for one in_addr + two addr_list[] elems */
2064 a
.buflen
= buflen
- ((sizeof(addr_list
[0]) * 2 + sizeof(struct in_addr
)));
2066 packet_len
= __dns_lookup(name
, T_A
, &packet
, &a
);
2067 if (packet_len
< 0) {
2068 *h_errnop
= HOST_NOT_FOUND
;
2069 DPRINTF("__dns_lookup returned < 0\n");
2073 if (a
.atype
== T_A
) { /* ADDRESS */
2074 /* we need space for addr_list[] and one IPv4 address */
2075 /* + 1 accounting for 1st addr (it's in a.rdata),
2076 * another + 1 for NULL in last addr_list[]: */
2077 int need_bytes
= sizeof(addr_list
[0]) * (a
.add_count
+ 1 + 1)
2078 /* for 1st addr (it's in a.rdata): */
2079 + sizeof(struct in_addr
);
2080 /* how many bytes will 2nd and following addresses take? */
2081 int ips_len
= a
.add_count
* a
.rdlength
;
2083 buflen
-= (need_bytes
+ ips_len
);
2084 if ((ssize_t
)buflen
< 0) {
2085 DPRINTF("buffer too small for all addresses\n");
2086 /* *h_errnop = NETDB_INTERNAL; - already is */
2091 /* if there are additional addresses in buf,
2092 * move them forward so that they are not destroyed */
2093 DPRINTF("a.add_count:%d a.rdlength:%d a.rdata:%p\n", a
.add_count
, a
.rdlength
, a
.rdata
);
2094 memmove(buf
+ need_bytes
, buf
, ips_len
);
2096 /* 1st address is in a.rdata, insert it */
2097 buf
+= need_bytes
- sizeof(struct in_addr
);
2098 memcpy(buf
, a
.rdata
, sizeof(struct in_addr
));
2100 /* fill addr_list[] */
2101 for (i
= 0; i
<= a
.add_count
; i
++) {
2102 addr_list
[i
] = (struct in_addr
*)buf
;
2103 buf
+= sizeof(struct in_addr
);
2105 addr_list
[i
] = NULL
;
2107 /* if we have enough space, we can report "better" name
2108 * (it may contain search domains attached by __dns_lookup,
2109 * or CNAME of the host if it is different from the name
2110 * we used to find it) */
2111 if (a
.dotted
&& buflen
> strlen(a
.dotted
)) {
2112 strcpy(buf
, a
.dotted
);
2116 result_buf
->h_name
= alias0
;
2117 result_buf
->h_aliases
= alias
;
2118 result_buf
->h_addrtype
= AF_INET
;
2119 result_buf
->h_length
= sizeof(struct in_addr
);
2120 result_buf
->h_addr_list
= (char **) addr_list
;
2121 *result
= result_buf
;
2122 *h_errnop
= NETDB_SUCCESS
;
2127 *h_errnop
= HOST_NOT_FOUND
;
2128 __set_h_errno(HOST_NOT_FOUND
);
2136 libc_hidden_def(gethostbyname_r
)
2137 #endif /* L_gethostbyname_r */
2140 #ifdef L_gethostbyname2_r
2142 int gethostbyname2_r(const char *name
,
2144 struct hostent
*result_buf
,
2147 struct hostent
**result
,
2150 #ifndef __UCLIBC_HAS_IPV6__
2151 return family
== (AF_INET
)
2152 ? gethostbyname_r(name
, result_buf
, buf
, buflen
, result
, h_errnop
)
2155 struct in6_addr
**addr_list
;
2158 unsigned char *packet
;
2159 struct resolv_answer a
;
2164 if (family
== AF_INET
)
2165 return gethostbyname_r(name
, result_buf
, buf
, buflen
, result
, h_errnop
);
2168 if (family
!= AF_INET6
)
2174 /* do /etc/hosts first */
2176 int old_errno
= errno
; /* save the old errno and reset errno */
2177 __set_errno(0); /* to check for missing /etc/hosts. */
2178 i
= __get_hosts_byname_r(name
, AF_INET6
/*family*/, result_buf
,
2179 buf
, buflen
, result
, h_errnop
);
2180 if (i
== NETDB_SUCCESS
) {
2181 __set_errno(old_errno
);
2184 switch (*h_errnop
) {
2185 case HOST_NOT_FOUND
:
2186 wrong_af
= (i
== TRY_AGAIN
);
2189 case NETDB_INTERNAL
:
2190 if (errno
== ENOENT
) {
2193 /* else fall through */
2197 __set_errno(old_errno
);
2200 DPRINTF("Nothing found in /etc/hosts\n");
2202 *h_errnop
= NETDB_INTERNAL
;
2204 /* prepare future h_aliases[0] */
2205 i
= strlen(name
) + 1;
2206 if ((ssize_t
)buflen
<= i
)
2208 memcpy(buf
, name
, i
); /* paranoia: name might change */
2212 /* make sure pointer is aligned */
2213 i
= ALIGN_BUFFER_OFFSET(buf
);
2218 * struct in6_addr* addr_list[NN+1];
2219 * struct in6_addr* in[NN];
2221 alias
= (char **)buf
;
2222 buf
+= sizeof(alias
[0]) * 2;
2223 buflen
-= sizeof(alias
[0]) * 2;
2224 addr_list
= (struct in6_addr
**)buf
;
2225 /* buflen may be < 0, must do signed compare */
2226 if ((ssize_t
)buflen
< 256)
2229 /* we store only one "alias" - the name itself */
2233 /* maybe it is already an address? */
2235 struct in6_addr
*in
= (struct in6_addr
*)(buf
+ sizeof(addr_list
[0]) * 2);
2236 if (inet_pton(AF_INET6
, name
, in
)) {
2238 addr_list
[1] = NULL
;
2239 result_buf
->h_name
= alias0
;
2240 result_buf
->h_aliases
= alias
;
2241 result_buf
->h_addrtype
= AF_INET6
;
2242 result_buf
->h_length
= sizeof(struct in6_addr
);
2243 result_buf
->h_addr_list
= (char **) addr_list
;
2244 *result
= result_buf
;
2245 *h_errnop
= NETDB_SUCCESS
;
2246 return NETDB_SUCCESS
;
2250 /* what if /etc/hosts has it but it's not IPv6?
2251 * F.e. "127.0.0.1 localhost". We don't do DNS query for such hosts -
2252 * "ping localhost" should be fast even if DNS server is down! */
2254 *h_errnop
= HOST_NOT_FOUND
;
2258 /* talk to DNS servers */
2260 /* take into account that at least one address will be there,
2261 * we'll need space of one in6_addr + two addr_list[] elems */
2262 a
.buflen
= buflen
- ((sizeof(addr_list
[0]) * 2 + sizeof(struct in6_addr
)));
2264 packet_len
= __dns_lookup(name
, T_AAAA
, &packet
, &a
);
2265 if (packet_len
< 0) {
2266 *h_errnop
= HOST_NOT_FOUND
;
2267 DPRINTF("__dns_lookup returned < 0\n");
2271 if (a
.atype
== T_AAAA
) { /* ADDRESS */
2272 /* we need space for addr_list[] and one IPv6 address */
2273 /* + 1 accounting for 1st addr (it's in a.rdata),
2274 * another + 1 for NULL in last addr_list[]: */
2275 int need_bytes
= sizeof(addr_list
[0]) * (a
.add_count
+ 1 + 1)
2276 /* for 1st addr (it's in a.rdata): */
2277 + sizeof(struct in6_addr
);
2278 /* how many bytes will 2nd and following addresses take? */
2279 int ips_len
= a
.add_count
* a
.rdlength
;
2281 buflen
-= (need_bytes
+ ips_len
);
2282 if ((ssize_t
)buflen
< 0) {
2283 DPRINTF("buffer too small for all addresses\n");
2284 /* *h_errnop = NETDB_INTERNAL; - already is */
2289 /* if there are additional addresses in buf,
2290 * move them forward so that they are not destroyed */
2291 DPRINTF("a.add_count:%d a.rdlength:%d a.rdata:%p\n", a
.add_count
, a
.rdlength
, a
.rdata
);
2292 memmove(buf
+ need_bytes
, buf
, ips_len
);
2294 /* 1st address is in a.rdata, insert it */
2295 buf
+= need_bytes
- sizeof(struct in6_addr
);
2296 memcpy(buf
, a
.rdata
, sizeof(struct in6_addr
));
2298 /* fill addr_list[] */
2299 for (i
= 0; i
<= a
.add_count
; i
++) {
2300 addr_list
[i
] = (struct in6_addr
*)buf
;
2301 buf
+= sizeof(struct in6_addr
);
2303 addr_list
[i
] = NULL
;
2305 /* if we have enough space, we can report "better" name
2306 * (it may contain search domains attached by __dns_lookup,
2307 * or CNAME of the host if it is different from the name
2308 * we used to find it) */
2309 if (a
.dotted
&& buflen
> strlen(a
.dotted
)) {
2310 strcpy(buf
, a
.dotted
);
2314 result_buf
->h_name
= alias0
;
2315 result_buf
->h_aliases
= alias
;
2316 result_buf
->h_addrtype
= AF_INET6
;
2317 result_buf
->h_length
= sizeof(struct in6_addr
);
2318 result_buf
->h_addr_list
= (char **) addr_list
;
2319 *result
= result_buf
;
2320 *h_errnop
= NETDB_SUCCESS
;
2325 *h_errnop
= HOST_NOT_FOUND
;
2326 __set_h_errno(HOST_NOT_FOUND
);
2333 #endif /* __UCLIBC_HAS_IPV6__ */
2335 libc_hidden_def(gethostbyname2_r
)
2336 #endif /* L_gethostbyname2_r */
2339 #ifdef L_gethostbyaddr_r
2341 int gethostbyaddr_r(const void *addr
, socklen_t addrlen
,
2343 struct hostent
*result_buf
,
2344 char *buf
, size_t buflen
,
2345 struct hostent
**result
,
2350 struct in_addr
**addr_list
;
2352 unsigned char *packet
;
2353 struct resolv_answer a
;
2363 #ifdef __UCLIBC_HAS_IPV4__
2365 if (addrlen
!= sizeof(struct in_addr
))
2369 #ifdef __UCLIBC_HAS_IPV6__
2371 if (addrlen
!= sizeof(struct in6_addr
))
2379 /* do /etc/hosts first */
2380 i
= __get_hosts_byaddr_r(addr
, addrlen
, type
, result_buf
,
2381 buf
, buflen
, result
, h_errnop
);
2384 switch (*h_errnop
) {
2385 case HOST_NOT_FOUND
:
2392 *h_errnop
= NETDB_INTERNAL
;
2394 /* make sure pointer is aligned */
2395 i
= ALIGN_BUFFER_OFFSET(buf
);
2399 * char *alias[ALIAS_DIM];
2400 * struct in[6]_addr* addr_list[2];
2401 * struct in[6]_addr in;
2402 * char scratch_buffer[256+];
2404 #define in6 ((struct in6_addr *)in)
2405 alias
= (char **)buf
;
2406 addr_list
= (struct in_addr
**)buf
;
2407 buf
+= sizeof(*addr_list
) * 2;
2408 buflen
-= sizeof(*addr_list
) * 2;
2409 in
= (struct in_addr
*)buf
;
2410 #ifndef __UCLIBC_HAS_IPV6__
2412 buflen
-= sizeof(*in
);
2413 if (addrlen
> sizeof(*in
))
2416 buf
+= sizeof(*in6
);
2417 buflen
-= sizeof(*in6
);
2418 if (addrlen
> sizeof(*in6
))
2421 if ((ssize_t
)buflen
< 256)
2426 addr_list
[1] = NULL
;
2427 memcpy(in
, addr
, addrlen
);
2429 if (0) /* nothing */;
2430 #ifdef __UCLIBC_HAS_IPV4__
2431 else IF_HAS_BOTH(if (type
== AF_INET
)) {
2432 unsigned char *tp
= (unsigned char *)addr
;
2433 sprintf(buf
, "%u.%u.%u.%u.in-addr.arpa",
2434 tp
[3], tp
[2], tp
[1], tp
[0]);
2437 #ifdef __UCLIBC_HAS_IPV6__
2440 unsigned char *tp
= (unsigned char *)addr
+ addrlen
- 1;
2442 dst
+= sprintf(dst
, "%x.%x.", tp
[0] & 0xf, tp
[0] >> 4);
2444 } while (tp
>= (unsigned char *)addr
);
2445 strcpy(dst
, "ip6.arpa");
2449 memset(&a
, '\0', sizeof(a
));
2451 /* Hmm why we memset(a) to zeros only once? */
2452 packet_len
= __dns_lookup(buf
, T_PTR
, &packet
, &a
);
2453 if (packet_len
< 0) {
2454 *h_errnop
= HOST_NOT_FOUND
;
2458 strncpy(buf
, a
.dotted
, buflen
);
2460 if (a
.atype
!= T_CNAME
)
2463 DPRINTF("Got a CNAME in gethostbyaddr()\n");
2464 if (++nest
> MAX_RECURSE
) {
2465 *h_errnop
= NO_RECOVERY
;
2468 /* Decode CNAME into buf, feed it to __dns_lookup() again */
2469 i
= __decode_dotted(packet
, a
.rdoffset
, packet_len
, buf
, buflen
);
2472 *h_errnop
= NO_RECOVERY
;
2477 if (a
.atype
== T_PTR
) { /* ADDRESS */
2478 i
= __decode_dotted(packet
, a
.rdoffset
, packet_len
, buf
, buflen
);
2480 result_buf
->h_name
= buf
;
2481 result_buf
->h_addrtype
= type
;
2482 result_buf
->h_length
= addrlen
;
2483 result_buf
->h_addr_list
= (char **) addr_list
;
2484 result_buf
->h_aliases
= alias
;
2485 *result
= result_buf
;
2486 *h_errnop
= NETDB_SUCCESS
;
2487 return NETDB_SUCCESS
;
2491 *h_errnop
= NO_ADDRESS
;
2495 libc_hidden_def(gethostbyaddr_r
)
2496 #endif /* L_gethostbyaddr_r */
2499 #ifdef L_gethostent_r
2501 __UCLIBC_MUTEX_STATIC(mylock
, PTHREAD_MUTEX_INITIALIZER
);
2503 static parser_t
*hostp
= NULL
;
2504 static smallint host_stayopen
;
2506 void endhostent_unlocked(void)
2509 config_close(hostp
);
2514 void endhostent(void)
2516 __UCLIBC_MUTEX_LOCK(mylock
);
2517 endhostent_unlocked();
2518 __UCLIBC_MUTEX_UNLOCK(mylock
);
2521 void sethostent(int stay_open
)
2523 __UCLIBC_MUTEX_LOCK(mylock
);
2526 __UCLIBC_MUTEX_UNLOCK(mylock
);
2529 int gethostent_r(struct hostent
*result_buf
, char *buf
, size_t buflen
,
2530 struct hostent
**result
, int *h_errnop
)
2534 __UCLIBC_MUTEX_LOCK(mylock
);
2535 if (hostp
== NULL
) {
2536 hostp
= __open_etc_hosts();
2537 if (hostp
== NULL
) {
2544 ret
= __read_etc_hosts_r(hostp
, NULL
, AF_INET
, GETHOSTENT
,
2545 result_buf
, buf
, buflen
, result
, h_errnop
);
2547 endhostent_unlocked();
2549 __UCLIBC_MUTEX_UNLOCK(mylock
);
2552 libc_hidden_def(gethostent_r
)
2553 #endif /* L_gethostent_r */
2556 #ifndef __UCLIBC_HAS_IPV6__
2557 #define GETXX_BUFSZ (sizeof(struct in_addr) + sizeof(struct in_addr *) * 2 + \
2558 /*sizeof(char *)*ALIAS_DIM */+ 384/*namebuffer*/ + 32/* margin */)
2560 #define GETXX_BUFSZ (sizeof(struct in6_addr) + sizeof(struct in6_addr *) * 2 + \
2561 /*sizeof(char *)*ALIAS_DIM */+ 384/*namebuffer*/ + 32/* margin */)
2562 #endif /* __UCLIBC_HAS_IPV6__ */
2564 #define __INIT_GETXX_BUF(sz) \
2566 buf = (char *)__uc_malloc((sz));
2570 struct hostent
*gethostent(void)
2572 static struct hostent hoste
;
2573 static char *buf
= NULL
;
2574 struct hostent
*host
= NULL
;
2575 #ifndef __UCLIBC_HAS_IPV6__
2576 #define HOSTENT_BUFSZ (sizeof(struct in_addr) + sizeof(struct in_addr *) * 2 + \
2577 sizeof(char *)*ALIAS_DIM + BUFSZ /*namebuffer*/ + 2 /* margin */)
2579 #define HOSTENT_BUFSZ (sizeof(struct in6_addr) + sizeof(struct in6_addr *) * 2 + \
2580 sizeof(char *)*ALIAS_DIM + BUFSZ /*namebuffer*/ + 2 /* margin */)
2581 #endif /* __UCLIBC_HAS_IPV6__ */
2583 __INIT_GETXX_BUF(HOSTENT_BUFSZ
);
2584 gethostent_r(&hoste
, buf
, HOSTENT_BUFSZ
, &host
, &h_errno
);
2587 #undef HOSTENT_BUFSZ
2588 #endif /* L_gethostent */
2591 #ifdef L_gethostbyname2
2593 struct hostent
*gethostbyname2(const char *name
, int family
)
2595 static struct hostent hoste
;
2596 static char *buf
= NULL
;
2599 __INIT_GETXX_BUF(GETXX_BUFSZ
);
2600 #ifndef __UCLIBC_HAS_IPV6__
2601 if (family
!= AF_INET
)
2602 return (struct hostent
*)NULL
;
2603 gethostbyname_r(name
, &hoste
, buf
, GETXX_BUFSZ
, &hp
, &h_errno
);
2605 gethostbyname2_r(name
, family
, &hoste
, buf
, GETXX_BUFSZ
, &hp
, &h_errno
);
2606 #endif /* __UCLIBC_HAS_IPV6__ */
2610 libc_hidden_def(gethostbyname2
)
2611 #endif /* L_gethostbyname2 */
2614 #ifdef L_gethostbyname
2616 struct hostent
*gethostbyname(const char *name
)
2618 return gethostbyname2(name
, AF_INET
);
2620 libc_hidden_def(gethostbyname
)
2621 #endif /* L_gethostbyname */
2624 #ifdef L_gethostbyaddr
2626 struct hostent
*gethostbyaddr(const void *addr
, socklen_t len
, int type
)
2628 static struct hostent hoste
;
2629 static char *buf
= NULL
;
2632 __INIT_GETXX_BUF(GETXX_BUFSZ
);
2633 gethostbyaddr_r(addr
, len
, type
, &hoste
, buf
, GETXX_BUFSZ
, &hp
, &h_errno
);
2636 libc_hidden_def(gethostbyaddr
)
2637 #endif /* L_gethostbyaddr */
2643 * Expand compressed domain name 'comp_dn' to full domain name.
2644 * 'msg' is a pointer to the begining of the message,
2645 * 'eomorig' points to the first location after the message,
2646 * 'exp_dn' is a pointer to a buffer of size 'length' for the result.
2647 * Return size of compressed name or -1 if there was an error.
2649 int dn_expand(const u_char
*msg
, const u_char
*eom
, const u_char
*src
,
2650 char *dst
, int dstsiz
)
2652 int n
= ns_name_uncompress(msg
, eom
, src
, dst
, (size_t)dstsiz
);
2654 if (n
> 0 && dst
[0] == '.')
2658 libc_hidden_def(dn_expand
)
2661 * Pack domain name 'exp_dn' in presentation form into 'comp_dn'.
2662 * Return the size of the compressed name or -1.
2663 * 'length' is the size of the array pointed to by 'comp_dn'.
2666 dn_comp(const char *src
, u_char
*dst
, int dstsiz
,
2667 u_char
**dnptrs
, u_char
**lastdnptr
)
2669 return ns_name_compress(src
, dst
, (size_t) dstsiz
,
2670 (const u_char
**) dnptrs
,
2671 (const u_char
**) lastdnptr
);
2673 libc_hidden_def(dn_comp
)
2674 #endif /* L_res_comp */
2679 /* Thinking in noninternationalized USASCII (per the DNS spec),
2680 * is this character visible and not a space when printed ?
2682 static int printable(int ch
)
2684 return (ch
> 0x20 && ch
< 0x7f);
2686 /* Thinking in noninternationalized USASCII (per the DNS spec),
2687 * is this characted special ("in need of quoting") ?
2689 static int special(int ch
)
2692 case 0x22: /* '"' */
2693 case 0x2E: /* '.' */
2694 case 0x3B: /* ';' */
2695 case 0x5C: /* '\\' */
2696 /* Special modifiers in zone files. */
2697 case 0x40: /* '@' */
2698 case 0x24: /* '$' */
2706 * ns_name_uncompress(msg, eom, src, dst, dstsiz)
2707 * Expand compressed domain name to presentation format.
2709 * Number of bytes read out of `src', or -1 (with errno set).
2711 * Root domain returns as "." not "".
2713 int ns_name_uncompress(const u_char
*msg
, const u_char
*eom
,
2714 const u_char
*src
, char *dst
, size_t dstsiz
)
2716 u_char tmp
[NS_MAXCDNAME
];
2719 n
= ns_name_unpack(msg
, eom
, src
, tmp
, sizeof tmp
);
2722 if (ns_name_ntop(tmp
, dst
, dstsiz
) == -1)
2726 libc_hidden_def(ns_name_uncompress
)
2729 * ns_name_ntop(src, dst, dstsiz)
2730 * Convert an encoded domain name to printable ascii as per RFC1035.
2732 * Number of bytes written to buffer, or -1 (with errno set)
2734 * The root is returned as "."
2735 * All other domains are returned in non absolute form
2737 int ns_name_ntop(const u_char
*src
, char *dst
, size_t dstsiz
)
2748 while ((n
= *cp
++) != 0) {
2749 if ((n
& NS_CMPRSFLGS
) != 0) {
2750 /* Some kind of compression pointer. */
2751 __set_errno(EMSGSIZE
);
2756 __set_errno(EMSGSIZE
);
2761 if (dn
+ n
>= eom
) {
2762 __set_errno(EMSGSIZE
);
2765 for (; n
> 0; n
--) {
2768 if (dn
+ 1 >= eom
) {
2769 __set_errno(EMSGSIZE
);
2774 } else if (!printable(c
)) {
2775 if (dn
+ 3 >= eom
) {
2776 __set_errno(EMSGSIZE
);
2780 *dn
++ = "0123456789"[c
/ 100];
2782 *dn
++ = "0123456789"[c
/ 10];
2783 *dn
++ = "0123456789"[c
% 10];
2786 __set_errno(EMSGSIZE
);
2795 __set_errno(EMSGSIZE
);
2801 __set_errno(EMSGSIZE
);
2807 libc_hidden_def(ns_name_ntop
)
2809 static int encode_bitstring(const char **bp
, const char *end
,
2810 unsigned char **labelp
,
2811 unsigned char ** dst
,
2812 unsigned const char *eom
)
2815 const char *cp
= *bp
;
2817 const char *beg_blen
;
2818 int value
= 0, count
= 0, tbcount
= 0, blen
= 0;
2822 /* a bitstring must contain at least 2 characters */
2826 /* XXX: currently, only hex strings are supported */
2829 if (!isxdigit((unsigned char) *cp
)) /*%< reject '\[x/BLEN]' */
2832 for (tp
= *dst
+ 1; cp
< end
&& tp
< eom
; cp
++) {
2833 unsigned char c
= *cp
;
2836 case ']': /*%< end of the bitstring */
2839 if (beg_blen
== NULL
)
2841 blen
= (int)strtol(beg_blen
, &end_blen
, 10);
2842 if (*end_blen
!= ']')
2846 *tp
++ = ((value
<< 4) & 0xff);
2847 cp
++; /*%< skip ']' */
2854 if (!__isdigit_char(c
))
2856 if (beg_blen
== NULL
) {
2858 /* blen never begings with 0 */
2864 if (!__isdigit_char(c
)) {
2865 c
= c
| 0x20; /* lowercase */
2867 if (c
> 5) /* not a-f? */
2886 if (cp
>= end
|| tp
>= eom
)
2890 * bit length validation:
2891 * If a <length> is present, the number of digits in the <bit-data>
2892 * MUST be just sufficient to contain the number of bits specified
2893 * by the <length>. If there are insignificant bits in a final
2894 * hexadecimal or octal digit, they MUST be zero.
2895 * RFC2673, Section 3.2.
2900 if (((blen
+ 3) & ~3) != tbcount
)
2902 traillen
= tbcount
- blen
; /*%< between 0 and 3 */
2903 if (((value
<< (8 - traillen
)) & 0xff) != 0)
2911 /* encode the type and the significant bit fields */
2912 **labelp
= DNS_LABELTYPE_BITSTRING
;
2921 int ns_name_pton(const char *src
, u_char
*dst
, size_t dstsiz
)
2923 static const char digits
[] = "0123456789";
2924 u_char
*label
, *bp
, *eom
;
2925 int c
, n
, escaped
, e
= 0;
2933 while ((c
= *src
++) != 0) {
2935 if (c
== '[') { /*%< start a bit string label */
2936 cp
= strchr(src
, ']');
2938 errno
= EINVAL
; /*%< ??? */
2941 e
= encode_bitstring(&src
, cp
+ 2,
2958 cp
= strchr(digits
, c
);
2960 n
= (cp
- digits
) * 100;
2964 cp
= strchr(digits
, c
);
2967 n
+= (cp
- digits
) * 10;
2971 cp
= strchr(digits
, c
);
2980 } else if (c
== '\\') {
2983 } else if (c
== '.') {
2984 c
= (bp
- label
- 1);
2985 if ((c
& NS_CMPRSFLGS
) != 0) { /*%< Label too big. */
2992 /* Fully qualified ? */
3000 if ((bp
- dst
) > MAXCDNAME
) {
3006 if (c
== 0 || *src
== '.') {
3017 c
= (bp
- label
- 1);
3018 if ((c
& NS_CMPRSFLGS
) != 0) { /*%< Label too big. */
3032 if ((bp
- dst
) > MAXCDNAME
) { /*%< src too big */
3042 libc_hidden_def(ns_name_pton
)
3045 * ns_name_unpack(msg, eom, src, dst, dstsiz)
3046 * Unpack a domain name from a message, source may be compressed.
3048 * -1 if it fails, or consumed octets if it succeeds.
3050 int ns_name_unpack(const u_char
*msg
, const u_char
*eom
, const u_char
*src
,
3051 u_char
*dst
, size_t dstsiz
)
3053 const u_char
*srcp
, *dstlim
;
3055 int n
, len
, checked
;
3061 dstlim
= dst
+ dstsiz
;
3062 if (srcp
< msg
|| srcp
>= eom
) {
3063 __set_errno(EMSGSIZE
);
3066 /* Fetch next label in domain name. */
3067 while ((n
= *srcp
++) != 0) {
3068 /* Check for indirection. */
3069 switch (n
& NS_CMPRSFLGS
) {
3072 if (dstp
+ n
+ 1 >= dstlim
|| srcp
+ n
>= eom
) {
3073 __set_errno(EMSGSIZE
);
3078 memcpy(dstp
, srcp
, n
);
3085 __set_errno(EMSGSIZE
);
3089 len
= srcp
- src
+ 1;
3090 srcp
= msg
+ (((n
& 0x3f) << 8) | (*srcp
& 0xff));
3091 if (srcp
< msg
|| srcp
>= eom
) { /* Out of range. */
3092 __set_errno(EMSGSIZE
);
3097 * Check for loops in the compressed name;
3098 * if we've looked at the whole message,
3099 * there must be a loop.
3101 if (checked
>= eom
- msg
) {
3102 __set_errno(EMSGSIZE
);
3108 __set_errno(EMSGSIZE
);
3109 return -1; /* flag error */
3117 libc_hidden_def(ns_name_unpack
)
3119 static int labellen(const unsigned char *lp
)
3122 unsigned char l
= *lp
;
3124 if ((l
& NS_CMPRSFLGS
) == NS_CMPRSFLGS
) {
3125 /* should be avoided by the caller */
3129 if ((l
& NS_CMPRSFLGS
) == NS_TYPE_ELT
) {
3130 if (l
== DNS_LABELTYPE_BITSTRING
) {
3134 return ((bitlen
+ 7 ) / 8 + 1);
3137 return -1; /*%< unknwon ELT */
3143 static int mklower(int ch
)
3145 if (ch
>= 0x41 && ch
<= 0x5A)
3151 static int dn_find(const unsigned char *domain
,
3152 const unsigned char *msg
,
3153 const unsigned char * const *dnptrs
,
3154 const unsigned char * const *lastdnptr
)
3156 const unsigned char *dn
, *cp
, *sp
;
3157 const unsigned char * const *cpp
;
3160 for (cpp
= dnptrs
; cpp
< lastdnptr
; cpp
++) {
3163 * terminate search on:
3165 * compression pointer
3168 while (*sp
!= 0 && (*sp
& NS_CMPRSFLGS
) == 0 &&
3169 (sp
- msg
) < 0x4000) {
3173 while ((n
= *cp
++) != 0) {
3175 * check for indirection
3177 switch (n
& NS_CMPRSFLGS
) {
3178 case 0: /*%< normal case, n == len */
3179 n
= labellen(cp
- 1); /*%< XXX */
3184 if (mklower(*dn
++) !=
3187 /* Is next root for both ? */
3188 if (*dn
== '\0' && *cp
== '\0')
3193 case NS_CMPRSFLGS
: /*%< indirection */
3194 cp
= msg
+ (((n
& 0x3f) << 8) | *cp
);
3197 default: /*%< illegal type */
3211 int ns_name_pack(const unsigned char *src
,
3212 unsigned char *dst
, int dstsiz
,
3213 const unsigned char **dnptrs
,
3214 const unsigned char **lastdnptr
)
3216 unsigned char *dstp
;
3217 const unsigned char **cpp
, **lpp
, *eob
, *msg
;
3218 const unsigned char *srcp
;
3219 int n
, l
, first
= 1;
3223 eob
= dstp
+ dstsiz
;
3226 if (dnptrs
!= NULL
) {
3229 for (cpp
= dnptrs
; *cpp
!= NULL
; cpp
++)
3232 lpp
= cpp
; /*%< end of list to search */
3238 /* make sure the domain we are about to add is legal */
3244 if ((n
& NS_CMPRSFLGS
) == NS_CMPRSFLGS
) {
3249 l0
= labellen(srcp
);
3256 if (l
> MAXCDNAME
) {
3264 /* from here on we need to reset compression pointer array on error */
3268 /* Look to see if we can use pointers. */
3271 if (n
!= 0 && msg
!= NULL
) {
3272 l
= dn_find(srcp
, msg
, (const unsigned char * const *) dnptrs
,
3273 (const unsigned char * const *) lpp
);
3275 if (dstp
+ 1 >= eob
) {
3279 *dstp
++ = ((u_int32_t
)l
>> 8) | NS_CMPRSFLGS
;
3281 return (dstp
- dst
);
3284 /* Not found, save it. */
3285 if (lastdnptr
!= NULL
&& cpp
< lastdnptr
- 1 &&
3286 (dstp
- msg
) < 0x4000 && first
) {
3293 /* copy label to buffer */
3294 if ((n
& NS_CMPRSFLGS
) == NS_CMPRSFLGS
) {
3295 /* Should not happen. */
3300 if (dstp
+ 1 + n
>= eob
) {
3304 memcpy(dstp
, srcp
, (size_t)(n
+ 1));
3320 libc_hidden_def(ns_name_pack
)
3322 int ns_name_compress(const char *src
,
3323 unsigned char *dst
, size_t dstsiz
,
3324 const unsigned char **dnptrs
,
3325 const unsigned char **lastdnptr
)
3327 unsigned char tmp
[NS_MAXCDNAME
];
3329 if (ns_name_pton(src
, tmp
, sizeof(tmp
)) == -1)
3332 return ns_name_pack(tmp
, dst
, dstsiz
, dnptrs
, lastdnptr
);
3334 libc_hidden_def(ns_name_compress
)
3336 int ns_name_skip(const unsigned char **ptrptr
,
3337 const unsigned char *eom
)
3339 const unsigned char *cp
;
3344 while (cp
< eom
&& (n
= *cp
++) != 0) {
3345 /* Check for indirection. */
3346 switch (n
& NS_CMPRSFLGS
) {
3347 case 0: /*%< normal case, n == len */
3350 case NS_TYPE_ELT
: /*%< EDNS0 extended label */
3351 l
= labellen(cp
- 1);
3353 errno
= EMSGSIZE
; /*%< XXX */
3358 case NS_CMPRSFLGS
: /*%< indirection */
3361 default: /*%< illegal type */
3378 libc_hidden_def(ns_name_skip
)
3380 int dn_skipname(const unsigned char *ptr
, const unsigned char *eom
)
3382 const unsigned char *saveptr
= ptr
;
3384 if (ns_name_skip(&ptr
, eom
) == -1)
3387 return ptr
- saveptr
;
3389 libc_hidden_def(dn_skipname
)
3390 #endif /* L_ns_name */
3395 /* Will be called under __resolv_lock. */
3396 static void res_sync_func(void)
3398 struct __res_state
*rp
= &(_res
);
3401 /* If we didn't get malloc failure earlier... */
3402 if (__nameserver
!= (void*) &__local_nameserver
) {
3404 * if (__nameservers < rp->nscount) - try to grow __nameserver[]?
3406 #ifdef __UCLIBC_HAS_IPV6__
3407 if (__nameservers
> rp
->_u
._ext
.nscount
)
3408 __nameservers
= rp
->_u
._ext
.nscount
;
3411 __nameserver
[n
].sa6
= *rp
->_u
._ext
.nsaddrs
[n
]; /* struct copy */
3412 #else /* IPv4 only */
3413 if (__nameservers
> rp
->nscount
)
3414 __nameservers
= rp
->nscount
;
3417 __nameserver
[n
].sa4
= rp
->nsaddr_list
[n
]; /* struct copy */
3420 __resolv_timeout
= rp
->retrans
? : RES_TIMEOUT
;
3421 __resolv_attempts
= rp
->retry
? : RES_DFLRETRY
;
3422 /* Extend and comment what program is known
3423 * to use which _res.XXX member(s).
3425 __resolv_opts = rp->options;
3430 /* has to be called under __resolv_lock */
3432 __res_vinit(res_state rp
, int preinit
)
3434 int i
, n
, options
, retrans
, retry
, ndots
;
3435 #ifdef __UCLIBC_HAS_IPV6__
3439 __close_nameservers();
3440 __open_nameservers();
3443 options
= rp
->options
;
3444 retrans
= rp
->retrans
;
3449 memset(rp
, 0, sizeof(*rp
));
3452 rp
->options
= RES_DEFAULT
;
3453 rp
->retrans
= RES_TIMEOUT
;
3454 rp
->retry
= RES_DFLRETRY
;
3457 rp
->options
= options
;
3458 rp
->retrans
= retrans
;
3463 #ifdef __UCLIBC_HAS_COMPAT_RES_STATE__
3464 /* Was: "rp->id = random();" but:
3465 * - random() pulls in largish static buffers
3466 * - isn't actually random unless, say, srandom(time(NULL)) was called
3467 * - is not used by uclibc anyway :)
3469 /* rp->id = 0; - memset did it */
3471 #ifdef __UCLIBC_HAS_EXTRA_COMPAT_RES_STATE__
3475 n
= __searchdomains
;
3476 if (n
> ARRAY_SIZE(rp
->dnsrch
))
3477 n
= ARRAY_SIZE(rp
->dnsrch
);
3478 for (i
= 0; i
< n
; i
++)
3479 rp
->dnsrch
[i
] = __searchdomain
[i
];
3481 /* copy nameservers' addresses */
3483 #ifdef __UCLIBC_HAS_IPV4__
3485 while (n
< ARRAY_SIZE(rp
->nsaddr_list
) && i
< __nameservers
) {
3486 if (__nameserver
[i
].sa
.sa_family
== AF_INET
) {
3487 rp
->nsaddr_list
[n
] = __nameserver
[i
].sa4
; /* struct copy */
3488 #ifdef __UCLIBC_HAS_IPV6__
3489 if (m
< ARRAY_SIZE(rp
->_u
._ext
.nsaddrs
)) {
3490 rp
->_u
._ext
.nsaddrs
[m
] = (void*) &rp
->nsaddr_list
[n
];
3496 #ifdef __UCLIBC_HAS_IPV6__
3497 if (__nameserver
[i
].sa
.sa_family
== AF_INET6
3498 && m
< ARRAY_SIZE(rp
->_u
._ext
.nsaddrs
)
3500 struct sockaddr_in6
*sa6
= malloc(sizeof(*sa6
));
3502 *sa6
= __nameserver
[i
].sa6
; /* struct copy */
3503 rp
->_u
._ext
.nsaddrs
[m
] = sa6
;
3511 #ifdef __UCLIBC_HAS_IPV6__
3512 rp
->_u
._ext
.nscount
= m
;
3515 #else /* IPv6 only */
3516 while (m
< ARRAY_SIZE(rp
->_u
._ext
.nsaddrs
) && i
< __nameservers
) {
3517 struct sockaddr_in6
*sa6
= malloc(sizeof(*sa6
));
3519 *sa6
= __nameserver
[i
].sa6
; /* struct copy */
3520 rp
->_u
._ext
.nsaddrs
[m
] = sa6
;
3525 rp
->_u
._ext
.nscount
= m
;
3528 rp
->options
|= RES_INIT
;
3536 return 0xffff & getpid();
3539 /* Our res_init never fails (always returns 0) */
3544 * These three fields used to be statically initialized. This made
3545 * it hard to use this code in a shared library. It is necessary,
3546 * now that we're doing dynamic initialization here, that we preserve
3547 * the old semantics: if an application modifies one of these three
3548 * fields of _res before res_init() is called, res_init() will not
3549 * alter them. Of course, if an application is setting them to
3550 * _zero_ before calling res_init(), hoping to override what used
3551 * to be the static default, we can't detect it and unexpected results
3552 * will follow. Zero for any of these fields would make no sense,
3553 * so one can safely assume that the applications were already getting
3554 * unexpected results.
3556 * _res.options is tricky since some apps were known to diddle the bits
3557 * before res_init() was first called. We can't replicate that semantic
3558 * with dynamic initialization (they may have turned bits off that are
3559 * set in RES_DEFAULT). Our solution is to declare such applications
3560 * "broken". They could fool us by setting RES_INIT but none do (yet).
3563 __UCLIBC_MUTEX_LOCK(__resolv_lock
);
3566 _res
.retrans
= RES_TIMEOUT
;
3569 if (!(_res
.options
& RES_INIT
))
3570 _res
.options
= RES_DEFAULT
;
3573 * This one used to initialize implicitly to zero, so unless the app
3574 * has set it to something in particular, we can randomize it now.
3577 _res
.id
= res_randomid();
3580 __res_vinit(&_res
, 1);
3581 __res_sync
= res_sync_func
;
3583 __UCLIBC_MUTEX_UNLOCK(__resolv_lock
);
3587 libc_hidden_def(res_init
)
3590 __res_iclose(res_state statp
)
3592 struct __res_state
* rp
= statp
;
3593 __UCLIBC_MUTEX_LOCK(__resolv_lock
);
3596 __close_nameservers();
3598 #ifdef __UCLIBC_HAS_IPV6__
3600 char *p1
= (char*) &(rp
->nsaddr_list
[0]);
3602 /* free nsaddrs[m] if they do not point to nsaddr_list[x] */
3603 while (m
< ARRAY_SIZE(rp
->_u
._ext
.nsaddrs
)) {
3604 char *p2
= (char*)(rp
->_u
._ext
.nsaddrs
[m
++]);
3605 if (p2
< p1
|| (p2
- p1
) > (signed)sizeof(rp
->nsaddr_list
))
3610 memset(rp
, 0, sizeof(struct __res_state
));
3611 __UCLIBC_MUTEX_UNLOCK(__resolv_lock
);
3615 * This routine is for closing the socket if a virtual circuit is used and
3616 * the program wants to close it. This provides support for endhostent()
3617 * which expects to close the socket.
3619 * This routine is not expected to be user visible.
3623 res_nclose(res_state statp
)
3625 __res_iclose(statp
);
3628 #ifdef __UCLIBC_HAS_BSD_RES_CLOSE__
3629 void res_close(void)
3635 /* This needs to be after the use of _res in res_init, above. */
3638 #ifndef __UCLIBC_HAS_THREADS__
3639 /* The resolver state for use by single-threaded programs.
3640 This differs from plain `struct __res_state _res;' in that it doesn't
3641 create a common definition, but a plain symbol that resides in .bss,
3642 which can have an alias. */
3643 struct __res_state _res
__attribute__((section (".bss")));
3644 struct __res_state
*__resp
= &_res
;
3645 #else /* __UCLIBC_HAS_THREADS__ */
3646 struct __res_state _res
__attribute__((section (".bss"))) attribute_hidden
;
3648 # if defined __UCLIBC_HAS_TLS__
3650 __thread
struct __res_state
*__resp
= &_res
;
3651 extern __thread
struct __res_state
*__libc_resp
3652 __attribute__ ((alias ("__resp"))) attribute_hidden attribute_tls_model_ie
;
3655 struct __res_state
*__resp
= &_res
;
3657 #endif /* !__UCLIBC_HAS_THREADS__ */
3660 * Set up default settings. If the configuration file exist, the values
3661 * there will have precedence. Otherwise, the server address is set to
3662 * INADDR_ANY and the default domain name comes from the gethostname().
3664 * An interrim version of this code (BIND 4.9, pre-4.4BSD) used 127.0.0.1
3665 * rather than INADDR_ANY ("0.0.0.0") as the default name server address
3666 * since it was noted that INADDR_ANY actually meant ``the first interface
3667 * you "ifconfig"'d at boot time'' and if this was a SLIP or PPP interface,
3668 * it had to be "up" in order for you to reach your own name server. It
3669 * was later decided that since the recommended practice is to always
3670 * install local static routes through 127.0.0.1 for all your network
3671 * interfaces, that we could solve this problem without a code change.
3673 * The configuration file should always be used, since it is the only way
3674 * to specify a default domain. If you are running a server on your local
3675 * machine, you should say "nameserver 0.0.0.0" or "nameserver 127.0.0.1"
3676 * in the configuration file.
3678 * Return 0 if completes successfully, -1 on error
3681 res_ninit(res_state statp
)
3684 __UCLIBC_MUTEX_LOCK(__resolv_lock
);
3685 ret
= __res_vinit(statp
, 0);
3686 __UCLIBC_MUTEX_UNLOCK(__resolv_lock
);
3690 #endif /* L_res_init */
3693 # if defined __UCLIBC_HAS_TLS__
3694 struct __res_state
*
3701 extern struct __res_state _res
;
3703 /* When threaded, _res may be a per-thread variable. */
3704 struct __res_state
*
3712 #endif /* L_res_state */
3717 int res_query(const char *dname
, int class, int type
,
3718 unsigned char *answer
, int anslen
)
3721 unsigned char *packet
= NULL
;
3722 struct resolv_answer a
;
3724 if (!dname
|| class != 1 /* CLASS_IN */) {
3725 h_errno
= NO_RECOVERY
;
3729 memset(&a
, '\0', sizeof(a
));
3730 i
= __dns_lookup(dname
, type
, &packet
, &a
);
3733 if (!h_errno
) /* TODO: can this ever happen? */
3734 h_errno
= TRY_AGAIN
;
3742 memcpy(answer
, packet
, i
);
3747 libc_hidden_def(res_query
)
3750 * Formulate a normal query, send, and retrieve answer in supplied buffer.
3751 * Return the size of the response on success, -1 on error.
3752 * If enabled, implement search rules until answer or unrecoverable failure
3753 * is detected. Error code, if any, is left in h_errno.
3755 #define __TRAILING_DOT (1<<0)
3756 #define __GOT_NODATA (1<<1)
3757 #define __GOT_SERVFAIL (1<<2)
3758 #define __TRIED_AS_IS (1<<3)
3759 int res_search(const char *name
, int class, int type
, u_char
*answer
,
3764 HEADER
*hp
= (HEADER
*)(void *)answer
;
3767 int ret
, saved_herrno
;
3768 uint32_t _res_options
;
3769 unsigned _res_ndots
;
3772 if (!name
|| !answer
) {
3773 h_errno
= NETDB_INTERNAL
;
3778 __UCLIBC_MUTEX_LOCK(__resolv_lock
);
3779 _res_options
= _res
.options
;
3780 _res_ndots
= _res
.ndots
;
3781 _res_dnsrch
= _res
.dnsrch
;
3782 __UCLIBC_MUTEX_UNLOCK(__resolv_lock
);
3783 if (!(_res_options
& RES_INIT
)) {
3784 res_init(); /* our res_init never fails */
3790 h_errno
= HOST_NOT_FOUND
; /* default, if we never query */
3792 for (cp
= name
; *cp
; cp
++)
3793 dots
+= (*cp
== '.');
3795 if (cp
> name
&& *--cp
== '.')
3796 state
|= __TRAILING_DOT
;
3799 * If there are dots in the name already, let's just give it a try
3800 * 'as is'. The threshold can be set with the "ndots" option.
3803 if (dots
>= _res_ndots
) {
3804 ret
= res_querydomain(name
, NULL
, class, type
, answer
, anslen
);
3807 saved_herrno
= h_errno
;
3808 state
|= __TRIED_AS_IS
;
3812 * We do at least one level of search if
3813 * - there is no dot and RES_DEFNAME is set, or
3814 * - there is at least one dot, there is no trailing dot,
3815 * and RES_DNSRCH is set.
3817 if ((!dots
&& (_res_options
& RES_DEFNAMES
))
3818 || (dots
&& !(state
& __TRAILING_DOT
) && (_res_options
& RES_DNSRCH
))
3822 for (domain
= _res_dnsrch
; *domain
&& !done
; domain
++) {
3824 ret
= res_querydomain(name
, *domain
, class, type
,
3830 * If no server present, give up.
3831 * If name isn't found in this domain,
3832 * keep trying higher domains in the search list
3833 * (if that's enabled).
3834 * On a NO_DATA error, keep trying, otherwise
3835 * a wildcard entry of another type could keep us
3836 * from finding this entry higher in the domain.
3837 * If we get some other error (negative answer or
3838 * server failure), then stop searching up,
3839 * but try the input name below in case it's
3842 if (errno
== ECONNREFUSED
) {
3843 h_errno
= TRY_AGAIN
;
3849 state
|= __GOT_NODATA
;
3851 case HOST_NOT_FOUND
:
3855 if (hp
->rcode
== SERVFAIL
) {
3856 /* try next search element, if any */
3857 state
|= __GOT_SERVFAIL
;
3862 /* anything else implies that we're done */
3866 * if we got here for some reason other than DNSRCH,
3867 * we only wanted one iteration of the loop, so stop.
3869 if (!(_res_options
& RES_DNSRCH
))
3875 * if we have not already tried the name "as is", do that now.
3876 * note that we do this regardless of how many dots were in the
3877 * name or whether it ends with a dot.
3879 if (!(state
& __TRIED_AS_IS
)) {
3880 ret
= res_querydomain(name
, NULL
, class, type
, answer
, anslen
);
3886 * if we got here, we didn't satisfy the search.
3887 * if we did an initial full query, return that query's h_errno
3888 * (note that we wouldn't be here if that query had succeeded).
3889 * else if we ever got a nodata, send that back as the reason.
3890 * else send back meaningless h_errno, that being the one from
3891 * the last DNSRCH we did.
3893 if (saved_herrno
!= -1)
3894 h_errno
= saved_herrno
;
3895 else if (state
& __GOT_NODATA
)
3897 else if (state
& __GOT_SERVFAIL
)
3898 h_errno
= TRY_AGAIN
;
3901 #undef __TRAILING_DOT
3903 #undef __GOT_SERVFAIL
3904 #undef __TRIED_AS_IS
3906 * Perform a call on res_query on the concatenation of name and domain,
3907 * removing a trailing dot from name if domain is NULL.
3909 int res_querydomain(const char *name
, const char *domain
, int class, int type
,
3910 u_char
*answer
, int anslen
)
3912 char nbuf
[MAXDNAME
];
3913 const char *longname
= nbuf
;
3916 uint32_t _res_options
;
3919 if (!name
|| !answer
) {
3920 h_errno
= NETDB_INTERNAL
;
3926 __UCLIBC_MUTEX_LOCK(__resolv_lock
);
3927 _res_options
= _res
.options
;
3928 __UCLIBC_MUTEX_UNLOCK(__resolv_lock
);
3929 if (!(_res_options
& RES_INIT
)) {
3930 res_init(); /* our res_init never fails */
3933 if (_res_options
& RES_DEBUG
)
3934 printf(";; res_querydomain(%s, %s, %d, %d)\n",
3935 name
, (domain
? domain
: "<Nil>"), class, type
);
3937 if (domain
== NULL
) {
3939 * Check for trailing '.';
3940 * copy without '.' if present.
3943 if (n
+ 1 > sizeof(nbuf
)) {
3944 h_errno
= NO_RECOVERY
;
3947 if (n
> 0 && name
[--n
] == '.') {
3948 strncpy(nbuf
, name
, n
);
3955 if (n
+ 1 + d
+ 1 > sizeof(nbuf
)) {
3956 h_errno
= NO_RECOVERY
;
3959 snprintf(nbuf
, sizeof(nbuf
), "%s.%s", name
, domain
);
3961 return res_query(longname
, class, type
, answer
, anslen
);
3963 libc_hidden_def(res_querydomain
)
3964 #endif /* L_res_query */
3967 unsigned int ns_get16(const unsigned char *src
)
3974 unsigned long ns_get32(const unsigned char *src
)
3981 void ns_put16(unsigned int src
, unsigned char *dst
)
3986 void ns_put32(unsigned long src
, unsigned char *dst
)
3990 #endif /* L_ns_netint */
3993 /* These need to be in the same order as the nres.h:ns_flag enum. */
3994 struct _ns_flagdata
{ unsigned short mask
, shift
; };
3995 static const struct _ns_flagdata _ns_flagdata
[16] = {
3996 { 0x8000, 15 }, /*%< qr. */
3997 { 0x7800, 11 }, /*%< opcode. */
3998 { 0x0400, 10 }, /*%< aa. */
3999 { 0x0200, 9 }, /*%< tc. */
4000 { 0x0100, 8 }, /*%< rd. */
4001 { 0x0080, 7 }, /*%< ra. */
4002 { 0x0040, 6 }, /*%< z. */
4003 { 0x0020, 5 }, /*%< ad. */
4004 { 0x0010, 4 }, /*%< cd. */
4005 { 0x000f, 0 }, /*%< rcode. */
4006 { 0x0000, 0 }, /*%< expansion (1/6). */
4007 { 0x0000, 0 }, /*%< expansion (2/6). */
4008 { 0x0000, 0 }, /*%< expansion (3/6). */
4009 { 0x0000, 0 }, /*%< expansion (4/6). */
4010 { 0x0000, 0 }, /*%< expansion (5/6). */
4011 { 0x0000, 0 }, /*%< expansion (6/6). */
4014 static void setsection(ns_msg
*msg
, ns_sect sect
)
4017 if (sect
== ns_s_max
) {
4022 msg
->_ptr
= msg
->_sections
[(int)sect
];
4026 int ns_skiprr(const unsigned char *ptr
,
4027 const unsigned char *eom
,
4028 ns_sect section
, int count
)
4030 const u_char
*optr
= ptr
;
4032 for (; count
> 0; count
--) {
4035 b
= dn_skipname(ptr
, eom
);
4041 ptr
+= b
/*Name*/ + NS_INT16SZ
/*Type*/ + NS_INT16SZ
/*Class*/;
4042 if (section
!= ns_s_qd
) {
4043 if (ptr
+ NS_INT32SZ
+ NS_INT16SZ
> eom
) {
4048 ptr
+= NS_INT32SZ
/*TTL*/;
4049 NS_GET16(rdlength
, ptr
);
4050 ptr
+= rdlength
/*RData*/;
4061 libc_hidden_def(ns_skiprr
)
4064 ns_initparse(const unsigned char *msg
, int msglen
, ns_msg
*handle
)
4066 const u_char
*eom
= msg
+ msglen
;
4071 if (msg
+ NS_INT16SZ
> eom
) {
4076 NS_GET16(handle
->_id
, msg
);
4077 if (msg
+ NS_INT16SZ
> eom
) {
4082 NS_GET16(handle
->_flags
, msg
);
4083 for (i
= 0; i
< ns_s_max
; i
++) {
4084 if (msg
+ NS_INT16SZ
> eom
) {
4089 NS_GET16(handle
->_counts
[i
], msg
);
4091 for (i
= 0; i
< ns_s_max
; i
++)
4092 if (handle
->_counts
[i
] == 0)
4093 handle
->_sections
[i
] = NULL
;
4095 int b
= ns_skiprr(msg
, eom
, (ns_sect
)i
,
4096 handle
->_counts
[i
]);
4100 handle
->_sections
[i
] = msg
;
4109 setsection(handle
, ns_s_max
);
4114 ns_parserr(ns_msg
*handle
, ns_sect section
, int rrnum
, ns_rr
*rr
)
4119 /* Make section right. */
4121 if (tmp
< 0 || section
>= ns_s_max
) {
4126 if (section
!= handle
->_sect
)
4127 setsection(handle
, section
);
4129 /* Make rrnum right. */
4131 rrnum
= handle
->_rrnum
;
4132 if (rrnum
< 0 || rrnum
>= handle
->_counts
[(int)section
]) {
4136 if (rrnum
< handle
->_rrnum
)
4137 setsection(handle
, section
);
4138 if (rrnum
> handle
->_rrnum
) {
4139 b
= ns_skiprr(handle
->_ptr
, handle
->_eom
, section
,
4140 rrnum
- handle
->_rrnum
);
4145 handle
->_rrnum
= rrnum
;
4149 b
= dn_expand(handle
->_msg
, handle
->_eom
,
4150 handle
->_ptr
, rr
->name
, NS_MAXDNAME
);
4154 if (handle
->_ptr
+ NS_INT16SZ
+ NS_INT16SZ
> handle
->_eom
) {
4158 NS_GET16(rr
->type
, handle
->_ptr
);
4159 NS_GET16(rr
->rr_class
, handle
->_ptr
);
4160 if (section
== ns_s_qd
) {
4165 if (handle
->_ptr
+ NS_INT32SZ
+ NS_INT16SZ
> handle
->_eom
) {
4169 NS_GET32(rr
->ttl
, handle
->_ptr
);
4170 NS_GET16(rr
->rdlength
, handle
->_ptr
);
4171 if (handle
->_ptr
+ rr
->rdlength
> handle
->_eom
) {
4175 rr
->rdata
= handle
->_ptr
;
4176 handle
->_ptr
+= rr
->rdlength
;
4178 if (++handle
->_rrnum
> handle
->_counts
[(int)section
])
4179 setsection(handle
, (ns_sect
)((int)section
+ 1));
4184 int ns_msg_getflag(ns_msg handle
, int flag
)
4186 return ((handle
)._flags
& _ns_flagdata
[flag
].mask
) >> _ns_flagdata
[flag
].shift
;
4188 #endif /* L_ns_parse */
4191 int res_mkquery(int op
, const char *dname
, int class, int type
,
4192 const unsigned char *data
, int datalen
,
4193 const unsigned char *newrr_in
,
4194 unsigned char *buf
, int buflen
)
4197 unsigned char *cp
, *ep
;
4198 unsigned char *dnptrs
[20], **dpp
, **lastdnptr
;
4199 uint32_t _res_options
;
4202 if (!buf
|| buflen
< HFIXEDSZ
) {
4203 h_errno
= NETDB_INTERNAL
;
4208 __UCLIBC_MUTEX_LOCK(__resolv_lock
);
4209 _res_options
= _res
.options
;
4210 __UCLIBC_MUTEX_UNLOCK(__resolv_lock
);
4211 if (!(_res_options
& RES_INIT
)) {
4212 res_init(); /* our res_init never fails */
4217 if (_res_options
& RES_DEBUG
)
4218 printf(";; res_mkquery(%d, %s, %d, %d)\n",
4219 op
, dname
&& *dname
? dname
: "<null>", class, type
);
4222 memset(buf
, 0, HFIXEDSZ
);
4223 hp
= (HEADER
*) buf
;
4224 hp
->id
= getpid() & 0xffff;
4226 hp
->rd
= (_res_options
& RES_RECURSE
) != 0U;
4227 hp
->rcode
= NOERROR
;
4229 cp
= buf
+ HFIXEDSZ
;
4234 lastdnptr
= dnptrs
+ sizeof dnptrs
/ sizeof dnptrs
[0];
4237 * perform opcode specific processing
4242 if (ep
- cp
< QFIXEDSZ
)
4245 n
= dn_comp(dname
, cp
, ep
- cp
- QFIXEDSZ
, dnptrs
, lastdnptr
);
4251 NS_PUT16(class, cp
);
4252 hp
->qdcount
= htons(1);
4254 if (op
== QUERY
|| data
== NULL
)
4258 * Make an additional record for completion domain.
4260 if ((ep
- cp
) < RRFIXEDSZ
)
4263 n
= dn_comp((const char *)data
, cp
, ep
- cp
- RRFIXEDSZ
,
4269 NS_PUT16(T_NULL
, cp
);
4270 NS_PUT16(class, cp
);
4273 hp
->arcount
= htons(1);
4279 * Initialize answer section
4281 if (ep
- cp
< 1 + RRFIXEDSZ
+ datalen
)
4284 *cp
++ = '\0'; /*%< no domain name */
4286 NS_PUT16(class, cp
);
4288 NS_PUT16(datalen
, cp
);
4291 memcpy(cp
, data
, (size_t)datalen
);
4295 hp
->ancount
= htons(1);
4304 #endif /* L_res_data */
4306 /* Unimplemented: */