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.
14 * Portions Copyright © 2021 mirabilos <m@mirbsd.org>
16 * Redistribution and use in source and binary forms, with or without
17 * modification, are permitted provided that the following conditions
19 * 1. Redistributions of source code must retain the above copyright
20 * notice, this list of conditions and the following disclaimer.
21 * 2. Redistributions in binary form must reproduce the above copyright
22 * notice, this list of conditions and the following disclaimer in the
23 * documentation and/or other materials provided with the distribution.
24 * 4. Neither the name of the University nor the names of its contributors
25 * may be used to endorse or promote products derived from this software
26 * without specific prior written permission.
28 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
29 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
32 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
41 * Portions Copyright (c) 1993 by Digital Equipment Corporation.
43 * Permission to use, copy, modify, and distribute this software for any
44 * purpose with or without fee is hereby granted, provided that the above
45 * copyright notice and this permission notice appear in all copies, and that
46 * the name of Digital Equipment Corporation not be used in advertising or
47 * publicity pertaining to distribution of the document or software without
48 * specific, written prior permission.
50 * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
51 * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
52 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
53 * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
54 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
55 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
56 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
60 * Portions Copyright (c) 1996-1999 by Internet Software Consortium.
62 * Permission to use, copy, modify, and distribute this software for any
63 * purpose with or without fee is hereby granted, provided that the above
64 * copyright notice and this permission notice appear in all copies.
66 * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
67 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
68 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
69 * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
70 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
71 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
72 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
77 Whenever an octet represents a numeric quantity, the left most bit
78 in the diagram is the high order or most significant bit.
79 That is, the bit labeled 0 is the most significant bit.
82 4.1.1. Header section format
83 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
84 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
86 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
87 |QR| OPCODE |AA|TC|RD|RA| 0 0 0| RCODE |
88 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
90 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
92 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
94 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
96 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
97 ID 16 bit random identifier assigned by querying peer.
98 Used to match query/response.
99 QR message is a query (0), or a response (1).
100 OPCODE 0 standard query (QUERY)
101 1 inverse query (IQUERY)
102 2 server status request (STATUS)
103 AA Authoritative Answer - this bit is valid in responses.
104 Responding name server is an authority for the domain name
105 in question section. Answer section may have multiple owner names
106 because of aliases. The AA bit corresponds to the name which matches
107 the query name, or the first owner name in the answer section.
108 TC TrunCation - this message was truncated.
109 RD Recursion Desired - this bit may be set in a query and
110 is copied into the response. If RD is set, it directs
111 the name server to pursue the query recursively.
112 Recursive query support is optional.
113 RA Recursion Available - this be is set or cleared in a
114 response, and denotes whether recursive query support is
115 available in the name server.
119 2 Server failure - server was unable to process the query
120 due to a problem with the name server.
121 3 Name Error - meaningful only for responses from
122 an authoritative name server. The referenced domain name
126 QDCOUNT number of entries in the question section.
127 ANCOUNT number of records in the answer section.
128 NSCOUNT number of records in the authority records section.
129 ARCOUNT number of records in the additional records section.
131 4.1.2. Question section format
133 The section contains QDCOUNT (usually 1) entries, each of this format:
134 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
135 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
138 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
140 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
142 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
143 QNAME a domain name represented as a sequence of labels, where
144 each label consists of a length octet followed by that
145 number of octets. The domain name terminates with the
146 zero length octet for the null label of the root. Note
147 that this field may be an odd number of octets; no
149 QTYPE a two octet type of the query.
150 1 a host address [REQ_A const]
151 2 an authoritative name server
152 3 a mail destination (Obsolete - use MX)
153 4 a mail forwarder (Obsolete - use MX)
154 5 the canonical name for an alias
155 6 marks the start of a zone of authority
156 7 a mailbox domain name (EXPERIMENTAL)
157 8 a mail group member (EXPERIMENTAL)
158 9 a mail rename domain name (EXPERIMENTAL)
159 10 a null RR (EXPERIMENTAL)
160 11 a well known service description
161 12 a domain name pointer [REQ_PTR const]
163 14 mailbox or mail list information
167 252 a request for a transfer of an entire zone
168 253 a request for mailbox-related records (MB, MG or MR)
169 254 a request for mail agent RRs (Obsolete - see MX)
170 255 a request for all records
171 QCLASS a two octet code that specifies the class of the query.
173 (others are historic only)
176 4.1.3. Resource record format
178 The answer, authority, and additional sections all share the same format:
179 a variable number of resource records, where the number of records
180 is specified in the corresponding count field in the header.
181 Each resource record has this format:
182 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
183 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
186 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
188 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
190 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
193 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
195 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--|
198 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
199 NAME a domain name to which this resource record pertains.
200 TYPE two octets containing one of the RR type codes. This
201 field specifies the meaning of the data in the RDATA field.
202 CLASS two octets which specify the class of the data in the RDATA field.
203 TTL a 32 bit unsigned integer that specifies the time interval
204 (in seconds) that the record may be cached.
205 RDLENGTH a 16 bit integer, length in octets of the RDATA field.
206 RDATA a variable length string of octets that describes the resource.
207 The format of this information varies according to the TYPE
208 and CLASS of the resource record.
209 If the TYPE is A and the CLASS is IN, it's a 4 octet IP address.
211 4.1.4. Message compression
213 In order to reduce the size of messages, domain names can be compressed.
214 An entire domain name or a list of labels at the end of a domain name
215 is replaced with a pointer to a prior occurance of the same name.
217 The pointer takes the form of a two octet sequence:
218 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
220 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
221 The first two bits are ones. This allows a pointer to be distinguished
222 from a label, since the label must begin with two zero bits because
223 labels are restricted to 63 octets or less. The OFFSET field specifies
224 an offset from the start of the message (i.e., the first octet
225 of the ID field in the domain header).
226 A zero offset specifies the first byte of the ID field, etc.
227 Domain name in a message can be represented as either:
228 - a sequence of labels ending in a zero octet
230 - a sequence of labels ending with a pointer
235 #include <stdio_ext.h>
239 #include <sys/poll.h>
240 #include <sys/socket.h>
241 #include <sys/types.h>
242 #include <sys/time.h>
243 #include <netinet/in.h>
244 #include <arpa/inet.h>
252 #include <arpa/nameser.h>
253 #include <sys/utsname.h>
255 #include <sys/stat.h>
256 #include <sys/param.h>
257 #include <bits/uClibc_mutex.h>
258 #include "internal/parse_config.h"
260 /* poll() is not supported in kernel <= 2.0, therefore if __NR_poll is
261 * not available, we assume an old Linux kernel is in use and we will
262 * use select() instead. */
263 #include <sys/syscall.h>
268 #if defined __UCLIBC_HAS_IPV4__ && defined __UCLIBC_HAS_IPV6__
269 #define IF_HAS_BOTH(...) __VA_ARGS__
271 #define IF_HAS_BOTH(...)
275 #define MAX_RECURSE 5
276 #define MAXALIASES (4)
277 /* 1:ip + 1:full + MAX_ALIASES:aliases + 1:NULL */
278 #define ALIAS_DIM (2 + MAXALIASES + 1)
279 #define BUFSZ (80) /* one line */
281 #define NS_TYPE_ELT 0x40 /*%< EDNS0 extended label type */
282 #define DNS_LABELTYPE_BITSTRING 0x41
288 #define DPRINTF(X,args...) fprintf(stderr, X, ##args)
290 #define DPRINTF(X,args...)
293 /* Make sure the incoming char * buffer is aligned enough to handle our random
294 * structures. This define is the same as we use for malloc alignment (which
295 * has same requirements). The offset is the number of bytes we need to adjust
296 * in order to attain desired alignment.
298 #define ALIGN_ATTR __alignof__(double __attribute_aligned__ (sizeof(size_t)))
299 #define ALIGN_BUFFER_OFFSET(buf) ((ALIGN_ATTR - ((size_t)buf % ALIGN_ATTR)) % ALIGN_ATTR)
303 struct resolv_header
{
305 int qr
, opcode
, aa
, tc
, rd
, ra
, rcode
;
312 struct resolv_question
{
318 struct resolv_answer
{
324 const unsigned char *rdata
;
331 enum etc_hosts_action
{
332 GET_HOSTS_BYNAME
= 0,
337 typedef union sockaddr46_t
{
339 #ifdef __UCLIBC_HAS_IPV4__
340 struct sockaddr_in sa4
;
342 #ifdef __UCLIBC_HAS_IPV6__
343 struct sockaddr_in6 sa6
;
348 __UCLIBC_MUTEX_EXTERN(__resolv_lock
) attribute_hidden
;
350 /* Protected by __resolv_lock */
351 extern void (*__res_sync
)(void) attribute_hidden
;
352 /*extern uint32_t __resolv_opts attribute_hidden; */
353 extern uint8_t __resolv_timeout attribute_hidden
;
354 extern uint8_t __resolv_attempts attribute_hidden
;
355 extern unsigned __nameservers attribute_hidden
;
356 extern unsigned __searchdomains attribute_hidden
;
357 extern sockaddr46_t
*__nameserver attribute_hidden
;
358 extern char **__searchdomain attribute_hidden
;
359 #ifdef __UCLIBC_HAS_IPV4__
360 extern const struct sockaddr_in __local_nameserver attribute_hidden
;
362 extern const struct sockaddr_in6 __local_nameserver attribute_hidden
;
365 #define MAXLEN_searchdomain 128
368 /* prototypes for internal functions */
369 extern void endhostent_unlocked(void) attribute_hidden
;
370 extern int __get_hosts_byname_r(const char *name
,
372 struct hostent
*result_buf
,
375 struct hostent
**result
,
376 int *h_errnop
) attribute_hidden
;
377 extern int __get_hosts_byaddr_r(const char *addr
,
380 struct hostent
*result_buf
,
383 struct hostent
**result
,
384 int *h_errnop
) attribute_hidden
;
385 extern parser_t
*__open_etc_hosts(void) attribute_hidden
;
386 extern int __read_etc_hosts_r(parser_t
*parser
,
389 enum etc_hosts_action action
,
390 struct hostent
*result_buf
,
393 struct hostent
**result
,
394 int *h_errnop
) attribute_hidden
;
395 extern int __dns_lookup(const char *name
,
397 unsigned char **outpacket
,
398 struct resolv_answer
*a
) attribute_hidden
;
399 extern int __encode_header(struct resolv_header
*h
,
401 int maxlen
) attribute_hidden
;
402 extern void __decode_header(unsigned char *data
,
403 struct resolv_header
*h
) attribute_hidden
;
404 extern int __encode_question(const struct resolv_question
*q
,
406 int maxlen
) attribute_hidden
;
407 extern int __encode_answer(struct resolv_answer
*a
,
409 int maxlen
) attribute_hidden
;
410 extern void __open_nameservers(void) attribute_hidden
;
411 extern void __close_nameservers(void) attribute_hidden
;
412 extern int __hnbad(const char *dotted
) attribute_hidden
;
414 #define __encode_dotted(dotted,dest,maxlen) \
415 dn_comp((dotted), (dest), (maxlen), NULL, NULL)
416 #define __decode_dotted(packet,offset,packet_len,dest,dest_len) \
417 dn_expand((packet), (packet) + (packet_len), (packet) + (offset), \
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 int __encode_question(const struct resolv_question
*q
,
563 i
= __encode_dotted(q
->dotted
, dest
, maxlen
);
573 dest
[0] = (q
->qtype
& 0xff00) >> 8;
574 dest
[1] = (q
->qtype
& 0x00ff) >> 0;
575 dest
[2] = (q
->qclass
& 0xff00) >> 8;
576 dest
[3] = (q
->qclass
& 0x00ff) >> 0;
580 #endif /* L_encodeq */
585 int __encode_answer(struct resolv_answer
*a
, unsigned char *dest
, int maxlen
)
589 i
= __encode_dotted(a
->dotted
, dest
, maxlen
);
596 if (maxlen
< (RRFIXEDSZ
+ a
->rdlength
))
599 *dest
++ = (a
->atype
& 0xff00) >> 8;
600 *dest
++ = (a
->atype
& 0x00ff) >> 0;
601 *dest
++ = (a
->aclass
& 0xff00) >> 8;
602 *dest
++ = (a
->aclass
& 0x00ff) >> 0;
603 *dest
++ = (a
->ttl
& 0xff000000) >> 24;
604 *dest
++ = (a
->ttl
& 0x00ff0000) >> 16;
605 *dest
++ = (a
->ttl
& 0x0000ff00) >> 8;
606 *dest
++ = (a
->ttl
& 0x000000ff) >> 0;
607 *dest
++ = (a
->rdlength
& 0xff00) >> 8;
608 *dest
++ = (a
->rdlength
& 0x00ff) >> 0;
609 memcpy(dest
, a
->rdata
, a
->rdlength
);
611 return i
+ RRFIXEDSZ
+ a
->rdlength
;
613 #endif /* L_encodea */
616 #ifdef CURRENTLY_UNUSED
619 int __encode_packet(struct resolv_header
*h
,
620 struct resolv_question
**q
,
621 struct resolv_answer
**an
,
622 struct resolv_answer
**ns
,
623 struct resolv_answer
**ar
,
624 unsigned char *dest
, int maxlen
) attribute_hidden
;
625 int __encode_packet(struct resolv_header
*h
,
626 struct resolv_question
**q
,
627 struct resolv_answer
**an
,
628 struct resolv_answer
**ns
,
629 struct resolv_answer
**ar
,
630 unsigned char *dest
, int maxlen
)
635 i
= __encode_header(h
, dest
, maxlen
);
643 for (j
= 0; j
< h
->qdcount
; j
++) {
644 i
= __encode_question(q
[j
], dest
, maxlen
);
652 for (j
= 0; j
< h
->ancount
; j
++) {
653 i
= __encode_answer(an
[j
], dest
, maxlen
);
660 for (j
= 0; j
< h
->nscount
; j
++) {
661 i
= __encode_answer(ns
[j
], dest
, maxlen
);
668 for (j
= 0; j
< h
->arcount
; j
++) {
669 i
= __encode_answer(ar
[j
], dest
, maxlen
);
679 #endif /* L_encodep */
684 int __decode_packet(unsigned char *data
, struct resolv_header
*h
) attribute_hidden
;
685 int __decode_packet(unsigned char *data
, struct resolv_header
*h
)
687 __decode_header(data
, h
);
690 #endif /* L_decodep */
695 int __form_query(int id
,
698 unsigned char *packet
,
699 int maxlen
) attribute_hidden
;
700 int __form_query(int id
,
703 unsigned char *packet
,
706 struct resolv_header h
;
707 struct resolv_question q
;
710 memset(&h
, 0, sizeof(h
));
714 q
.dotted
= (char *) name
;
716 q
.qclass
= C_IN
; /* CLASS_IN */
718 i
= __encode_header(&h
, packet
, maxlen
);
722 j
= __encode_question(&q
, packet
+ i
, maxlen
- i
);
728 #endif /* L_formquery */
729 #endif /* CURRENTLY_UNUSED */
732 #ifdef L_opennameservers
734 # if __BYTE_ORDER == __LITTLE_ENDIAN
735 #define NAMESERVER_PORT_N (__bswap_constant_16(NAMESERVER_PORT))
737 #define NAMESERVER_PORT_N NAMESERVER_PORT
740 __UCLIBC_MUTEX_INIT(__resolv_lock
, PTHREAD_MUTEX_INITIALIZER
);
742 /* Protected by __resolv_lock */
743 void (*__res_sync
)(void);
744 /*uint32_t __resolv_opts; */
745 uint8_t __resolv_timeout
= RES_TIMEOUT
;
746 uint8_t __resolv_attempts
= RES_DFLRETRY
;
747 unsigned __nameservers
;
748 unsigned __searchdomains
;
749 sockaddr46_t
*__nameserver
;
750 char **__searchdomain
;
751 #ifdef __UCLIBC_HAS_IPV4__
752 const struct sockaddr_in __local_nameserver
= {
753 .sin_family
= AF_INET
,
754 .sin_port
= NAMESERVER_PORT_N
,
757 const struct sockaddr_in6 __local_nameserver
= {
758 .sin6_family
= AF_INET6
,
759 .sin6_port
= NAMESERVER_PORT_N
,
763 /* Helpers. Both stop on EOL, if it's '\n', it is converted to NUL first */
764 static char *skip_nospace(char *p
)
766 while (*p
!= '\0' && !isspace(*p
)) {
775 static char *skip_and_NUL_space(char *p
)
777 /* NB: '\n' is not isspace! */
780 if (c
== '\0' || !isspace(c
))
783 if (c
== '\n' || c
== '#')
790 /* Must be called under __resolv_lock. */
791 void __open_nameservers(void)
793 static uint32_t resolv_conf_mtime
;
795 char szBuffer
[MAXLEN_searchdomain
];
801 /* Reread /etc/resolv.conf if it was modified. */
803 if (stat(_PATH_RESCONF
, &sb
) != 0)
805 if (resolv_conf_mtime
!= (uint32_t)sb
.st_mtime
) {
806 resolv_conf_mtime
= sb
.st_mtime
;
807 __close_nameservers(); /* force config reread */
814 __resolv_timeout
= RES_TIMEOUT
;
815 __resolv_attempts
= RES_DFLRETRY
;
817 fp
= fopen(_PATH_RESCONF
, "r");
818 #ifdef FALLBACK_TO_CONFIG_RESOLVCONF
820 /* If we do not have a pre-populated /etc/resolv.conf then
821 try to use the one from /etc/config which exists on numerous
822 systems ranging from some uClinux to IRIX installations and
823 may be the only /etc dir that was mounted rw. */
824 fp
= fopen("/etc/config/resolv.conf", "r");
829 while (fgets(szBuffer
, sizeof(szBuffer
), fp
) != NULL
) {
833 keyword
= p
= skip_and_NUL_space(szBuffer
);
837 p
= skip_and_NUL_space(p
);
839 if (strcmp(keyword
, "nameserver") == 0) {
840 /* terminate IP addr */
841 *skip_nospace(p
) = '\0';
842 memset(&sa
, 0, sizeof(sa
));
843 if (0) /* nothing */;
844 #ifdef __UCLIBC_HAS_IPV6__
845 else if (inet_pton(AF_INET6
, p
, &sa
.sa6
.sin6_addr
) > 0) {
846 sa
.sa6
.sin6_family
= AF_INET6
;
847 sa
.sa6
.sin6_port
= htons(NAMESERVER_PORT
);
850 #ifdef __UCLIBC_HAS_IPV4__
851 else if (inet_pton(AF_INET
, p
, &sa
.sa4
.sin_addr
) > 0) {
852 sa
.sa4
.sin_family
= AF_INET
;
853 sa
.sa4
.sin_port
= htons(NAMESERVER_PORT
);
857 continue; /* garbage on this line */
858 ptr
= realloc(__nameserver
, (__nameservers
+ 1) * sizeof(__nameserver
[0]));
862 __nameserver
[__nameservers
++] = sa
; /* struct copy */
865 if (strcmp(keyword
, "domain") == 0 || strcmp(keyword
, "search") == 0) {
868 /* free old domains ("last 'domain' or 'search' wins" rule) */
869 while (__searchdomains
)
870 free(__searchdomain
[--__searchdomains
]);
871 /*free(__searchdomain);*/
872 /*__searchdomain = NULL; - not necessary */
874 /* terminate current word */
875 p1
= skip_nospace(p
);
876 /* find next word (maybe) */
877 p1
= skip_and_NUL_space(p1
);
879 ptr
= realloc(__searchdomain
, (__searchdomains
+ 1) * sizeof(__searchdomain
[0]));
882 __searchdomain
= ptr
;
883 /* NB: strlen(p) <= MAXLEN_searchdomain) because szBuffer[] is smaller */
887 DPRINTF("adding search %s\n", (char*)ptr
);
888 __searchdomain
[__searchdomains
++] = (char*)ptr
;
894 /* if (strcmp(keyword, "sortlist") == 0)... */
895 if (strcmp(keyword
, "options") == 0) {
899 if (p
== NULL
|| (p1
= strchr(p
, ':')) == NULL
)
902 if (strcmp(p
, "timeout") == 0)
903 what
= &__resolv_timeout
;
904 else if (strcmp(p
, "attempts") == 0)
905 what
= &__resolv_attempts
;
909 DPRINTF("option %s:%d\n", p
, *what
);
914 if (__nameservers
== 0) {
915 /* Have to handle malloc failure! What a mess...
916 * And it's not only here, we need to be careful
917 * to never write into __nameserver[0] if it points
918 * to constant __local_nameserver, or free it. */
919 __nameserver
= malloc(sizeof(__nameserver
[0]));
921 memcpy(__nameserver
, &__local_nameserver
, sizeof(__local_nameserver
));
923 __nameserver
= (void*) &__local_nameserver
;
926 if (__searchdomains
== 0) {
929 i
= gethostname(buf
, sizeof(buf
) - 1);
930 buf
[sizeof(buf
) - 1] = '\0';
931 if (i
== 0 && (p
= strchr(buf
, '.')) != NULL
&& p
[1]) {
935 __searchdomain
= malloc(sizeof(__searchdomain
[0]));
936 if (!__searchdomain
) {
940 __searchdomain
[0] = p
;
945 DPRINTF("nameservers = %d\n", __nameservers
);
951 #endif /* L_opennameservers */
954 #ifdef L_closenameservers
956 /* Must be called under __resolv_lock. */
957 void __close_nameservers(void)
959 if (__nameserver
!= (void*) &__local_nameserver
)
963 while (__searchdomains
)
964 free(__searchdomain
[--__searchdomains
]);
965 free(__searchdomain
);
966 __searchdomain
= NULL
;
967 /*__searchdomains = 0; - already is */
969 #endif /* L_closenameservers */
975 static int __length_question(const unsigned char *data
, int maxlen
)
977 const unsigned char *start
;
990 if ((b
& 0xc0) == 0xc0) {
991 /* It's a "compressed" name. */
992 data
++; /* skip lsb of redirected offset */
997 maxlen
-= (b
+ 1); /* account for data++ above */
999 /* Up to here we were skipping encoded name */
1001 /* Account for QTYPE and QCLASS fields */
1004 return data
- start
+ 2 + 2;
1007 static int __decode_answer(const unsigned char *message
, /* packet */
1009 int len
, /* total packet len */
1010 struct resolv_answer
*a
)
1015 DPRINTF("decode_answer(start): off %d, len %d\n", offset
, len
);
1016 i
= __decode_dotted(message
, offset
, len
, temp
, sizeof(temp
));
1020 message
+= offset
+ i
;
1021 len
-= i
+ RRFIXEDSZ
+ offset
;
1023 DPRINTF("decode_answer: off %d, len %d, i %d\n", offset
, len
, i
);
1027 /* TODO: what if strdup fails? */
1028 a
->dotted
= strdup(temp
);
1029 a
->atype
= (message
[0] << 8) | message
[1];
1031 a
->aclass
= (message
[0] << 8) | message
[1];
1033 a
->ttl
= (message
[0] << 24) |
1034 (message
[1] << 16) | (message
[2] << 8) | (message
[3] << 0);
1036 a
->rdlength
= (message
[0] << 8) | message
[1];
1039 a
->rdoffset
= offset
+ i
+ RRFIXEDSZ
;
1041 DPRINTF("i=%d,rdlength=%d\n", i
, a
->rdlength
);
1043 if (len
< a
->rdlength
)
1045 return i
+ RRFIXEDSZ
+ a
->rdlength
;
1049 * a.buf(len) = auxiliary buffer for IP addresses after first one
1050 * a.add_count = how many additional addresses are there already
1051 * outpacket = where to save ptr to raw packet? can be NULL
1053 * ret < 0: error, all other data is not valid
1054 * ret >= 0: length of reply packet
1055 * a.add_count & a.buf: updated
1056 * a.rdlength: length of addresses (4 bytes for IPv4)
1057 * *outpacket: updated (packet is malloced, you need to free it)
1058 * a.rdata: points into *outpacket to 1st IP addr
1059 * NB: don't pass outpacket == NULL if you need to use a.rdata!
1060 * a.atype: type of query?
1061 * a.dotted: which name we _actually_ used. May contain search domains
1062 * appended. (why the filed is called "dotted" I have no idea)
1063 * This is a malloced string. May be NULL because strdup failed.
1065 int __dns_lookup(const char *name
,
1067 unsigned char **outpacket
,
1068 struct resolv_answer
*a
)
1070 /* Protected by __resolv_lock: */
1071 static int last_ns_num
= 0;
1072 static uint16_t last_id
= 1;
1083 struct resolv_header h
;
1084 struct resolv_question q
;
1085 struct resolv_answer ma
;
1086 bool first_answer
= 1;
1088 unsigned char *packet
= malloc(PACKETSZ
);
1090 int variant
= -1; /* search domain to append, -1: none */
1091 int local_ns_num
= -1; /* Nth server to use */
1092 int local_id
= local_id
; /* for compiler */
1101 name_len
= strlen(name
);
1102 if ((unsigned)name_len
>= MAXDNAME
- MAXLEN_searchdomain
- 2)
1103 goto fail
; /* paranoia */
1104 lookup
= malloc(name_len
+ 1/*for '.'*/ + MAXLEN_searchdomain
+ 1);
1105 if (!packet
|| !lookup
|| !name
[0])
1107 ends_with_dot
= (name
[name_len
- 1] == '.');
1108 contains_dot
= strchr(name
, '.') != NULL
;
1109 /* no strcpy! paranoia, user might change name[] under us */
1110 memcpy(lookup
, name
, name_len
);
1112 DPRINTF("Looking up type %d answer for '%s'\n", type
, name
);
1113 retries_left
= 0; /* for compiler */
1115 unsigned act_variant
;
1117 unsigned reply_timeout
;
1124 /* Mess with globals while under lock */
1125 /* NB: even data *pointed to* by globals may vanish
1126 * outside the locks. We should assume any and all
1127 * globals can completely change between locked
1128 * code regions. OTOH, this is rare, so we don't need
1129 * to handle it "nicely" (do not skip servers,
1130 * search domains, etc), we only need to ensure
1131 * we do not SEGV, use freed+overwritten data
1132 * or do other Really Bad Things. */
1133 __UCLIBC_MUTEX_LOCK(__resolv_lock
);
1134 __open_nameservers();
1135 if (type
!= T_PTR
) {
1136 sdomains
= __searchdomains
;
1138 lookup
[name_len
] = '\0';
1139 /* For qualified names, act_variant = MAX_UINT, 0, .., sdomains-1
1140 * => Try original name first, then append search domains
1141 * For names without domain, act_variant = 0, 1, .., sdomains
1142 * => Try search domains first, original name last */
1143 act_variant
= contains_dot
? variant
: variant
+ 1;
1144 if (act_variant
< sdomains
) {
1145 /* lookup is name_len + 1 + MAXLEN_searchdomain + 1 long */
1146 /* __searchdomain[] is not bigger than MAXLEN_searchdomain */
1147 lookup
[name_len
] = '.';
1148 strcpy(&lookup
[name_len
+ 1], __searchdomain
[act_variant
]);
1150 /* first time? pick starting server etc */
1151 if (local_ns_num
< 0) {
1153 /*TODO: implement /etc/resolv.conf's "options rotate"
1154 (a.k.a. RES_ROTATE bit in _res.options)
1156 if (_res.options & RES_ROTATE) */
1157 local_ns_num
= last_ns_num
;
1158 retries_left
= __nameservers
* __resolv_attempts
;
1160 if (local_ns_num
>= __nameservers
)
1164 /* write new values back while still under lock */
1166 last_ns_num
= local_ns_num
;
1168 /* can't just take a pointer, __nameserver[x]
1169 * is not safe to use outside of locks */
1170 sa
= __nameserver
[local_ns_num
];
1171 __UCLIBC_MUTEX_UNLOCK(__resolv_lock
);
1173 memset(packet
, 0, PACKETSZ
);
1174 memset(&h
, 0, sizeof(h
));
1180 DPRINTF("encoding header\n", h
.rd
);
1181 i
= __encode_header(&h
, packet
, PACKETSZ
);
1185 /* encode question */
1186 DPRINTF("lookup name: %s\n", lookup
);
1189 q
.qclass
= C_IN
; /* CLASS_IN */
1190 j
= __encode_question(&q
, packet
+i
, PACKETSZ
-i
);
1198 const socklen_t plen
= sa
.sa
.sa_family
== AF_INET
? INET_ADDRSTRLEN
: INET6_ADDRSTRLEN
;
1199 char *pbuf
= malloc(plen
);
1200 if (pbuf
== NULL
) ;/* nothing */
1201 #ifdef __UCLIBC_HAS_IPV6__
1202 else if (sa
.sa
.sa_family
== AF_INET6
)
1203 pbuf
= (char*)inet_ntop(AF_INET6
, &sa
.sa6
.sin6_addr
, pbuf
, plen
);
1205 #ifdef __UCLIBC_HAS_IPV4__
1206 else if (sa
.sa
.sa_family
== AF_INET
)
1207 pbuf
= (char*)inet_ntop(AF_INET
, &sa
.sa4
.sin_addr
, pbuf
, plen
);
1209 DPRINTF("On try %d, sending query to %s, port %d\n",
1210 retries_left
, pbuf
, NAMESERVER_PORT
);
1214 fd
= socket(sa
.sa
.sa_family
, SOCK_DGRAM
, IPPROTO_UDP
);
1215 if (fd
< 0) /* paranoia */
1216 goto try_next_server
;
1217 rc
= connect(fd
, &sa
.sa
, sizeof(sa
));
1219 /*if (errno == ENETUNREACH) { */
1220 /* routing error, presume not transient */
1221 goto try_next_server
;
1223 /*For example, what transient error this can be? Can't think of any */
1227 DPRINTF("Xmit packet len:%d id:%d qr:%d\n", packet_len
, h
.id
, h
.qr
);
1228 /* no error check - if it fails, we time out on recv */
1229 send(fd
, packet
, packet_len
, 0);
1232 reply_timeout
= __resolv_timeout
;
1236 tv
.tv_sec
= reply_timeout
;
1238 if (select(fd
+ 1, &fds
, NULL
, NULL
, &tv
) <= 0) {
1239 DPRINTF("Timeout\n");
1240 /* timed out, so retry send and receive
1241 * to next nameserver */
1242 goto try_next_server
;
1245 #else /* !USE_SELECT */
1246 reply_timeout
= __resolv_timeout
* 1000;
1249 fds
.events
= POLLIN
;
1250 if (poll(&fds
, 1, reply_timeout
) <= 0) {
1251 DPRINTF("Timeout\n");
1252 /* timed out, so retry send and receive
1253 * to next nameserver */
1254 goto try_next_server
;
1256 if (fds
.revents
& (POLLERR
| POLLHUP
| POLLNVAL
)) {
1257 DPRINTF("Bad event\n");
1258 goto try_next_server
;
1260 /*TODO: better timeout accounting?*/
1261 reply_timeout
-= 1000;
1262 #endif /* USE_SELECT */
1264 /* vda: a bogus response seen in real world (caused SEGV in uclibc):
1265 * "ping www.google.com" sending AAAA query and getting
1266 * response with one answer... with answer part missing!
1267 * Fixed by thorough checks for not going past the packet's end.
1271 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";
1272 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";
1273 pos
= memcmp(packet
+ 2, test_query
+ 2, 30);
1274 packet_len
= recv(fd
, packet
, PACKETSZ
, MSG_DONTWAIT
);
1277 memcpy(packet
+ 2, test_respn
+ 2, 30);
1281 packet_len
= recv(fd
, packet
, PACKETSZ
, MSG_DONTWAIT
);
1284 if (packet_len
< HFIXEDSZ
) {
1286 * If the peer did shutdown then retry later,
1287 * try next peer on error.
1288 * it's just a bogus packet from somewhere */
1290 if (packet_len
>= 0 && reply_timeout
)
1292 goto try_next_server
;
1294 __decode_header(packet
, &h
);
1295 DPRINTF("len:%d id:%d qr:%d\n", packet_len
, h
.id
, h
.qr
);
1296 if (h
.id
!= local_id
|| !h
.qr
) {
1301 DPRINTF("Got response (i think)!\n");
1302 DPRINTF("qrcount=%d,ancount=%d,nscount=%d,arcount=%d\n",
1303 h
.qdcount
, h
.ancount
, h
.nscount
, h
.arcount
);
1304 DPRINTF("opcode=%d,aa=%d,tc=%d,rd=%d,ra=%d,rcode=%d\n",
1305 h
.opcode
, h
.aa
, h
.tc
, h
.rd
, h
.ra
, h
.rcode
);
1307 /* bug 660 says we treat negative response as an error
1308 * and retry, which is, eh, an error. :)
1309 * We were incurring long delays because of this. */
1310 if (h
.rcode
== NXDOMAIN
|| h
.rcode
== SERVFAIL
) {
1311 /* if possible, try next search domain */
1312 if (!ends_with_dot
) {
1313 DPRINTF("variant:%d sdomains:%d\n", variant
, sdomains
);
1314 if (variant
< sdomains
- 1) {
1315 /* next search domain */
1319 /* no more search domains to try */
1321 if (h
.rcode
!= SERVFAIL
) {
1322 /* dont loop, this is "no such host" situation */
1323 h_errno
= HOST_NOT_FOUND
;
1327 /* Insert other non-fatal errors here, which do not warrant
1328 * switching to next nameserver */
1330 /* Strange error, assuming this nameserver is feeling bad */
1332 goto try_next_server
;
1334 /* Code below won't work correctly with h.ancount == 0, so... */
1335 if (h
.ancount
<= 0) {
1336 h_errno
= NO_DATA
; /* [is this correct code to check for?] */
1340 /*XXX TODO: check that question matches query (and qdcount==1?) */
1341 for (j
= 0; j
< h
.qdcount
; j
++) {
1342 DPRINTF("Skipping question %d at %d\n", j
, pos
);
1343 i
= __length_question(packet
+ pos
, packet_len
- pos
);
1345 DPRINTF("Packet'question section "
1346 "is truncated, trying next server\n");
1347 goto try_next_server
;
1350 DPRINTF("Length of question %d is %d\n", j
, i
);
1352 DPRINTF("Decoding answer at pos %d\n", pos
);
1357 for (j
= 0; j
< h
.ancount
; j
++) {
1358 i
= __decode_answer(packet
, pos
, packet_len
, &ma
);
1360 DPRINTF("failed decode %d\n", i
);
1361 /* If the message was truncated but we have
1362 * decoded some answers, pretend it's OK */
1363 if (num_answers
&& h
.tc
)
1365 goto try_next_server
;
1369 if (__hnbad(ma
.dotted
))
1374 ma
.buflen
= a
->buflen
;
1375 ma
.add_count
= a
->add_count
;
1377 memcpy(a
, &ma
, sizeof(ma
));
1378 if (a
->atype
!= T_SIG
&& (NULL
== a
->buf
|| (type
!= T_A
&& type
!= T_AAAA
)))
1380 if (a
->atype
!= type
)
1382 a
->add_count
= h
.ancount
- j
- 1;
1383 if ((a
->rdlength
+ sizeof(struct in_addr
*)) * a
->add_count
> a
->buflen
)
1389 if (ma
.atype
!= type
)
1391 if (a
->rdlength
!= ma
.rdlength
) {
1393 DPRINTF("Answer address len(%u) differs from original(%u)\n",
1394 ma
.rdlength
, a
->rdlength
);
1395 goto try_next_server
;
1397 memcpy(a
->buf
+ (a
->add_count
* ma
.rdlength
), ma
.rdata
, ma
.rdlength
);
1402 h_errno
= NO_RECOVERY
;
1407 DPRINTF("Answer name = |%s|\n", a
->dotted
);
1408 DPRINTF("Answer type = |%d|\n", a
->atype
);
1412 *outpacket
= packet
;
1419 /* Try next nameserver */
1423 } while (retries_left
> 0);
1426 h_errno
= NETDB_INTERNAL
;
1434 #endif /* L_dnslookup */
1437 #ifdef L_read_etc_hosts_r
1439 parser_t
* __open_etc_hosts(void)
1442 parser
= config_open("/etc/hosts");
1443 #ifdef FALLBACK_TO_CONFIG_RESOLVCONF
1445 parser
= config_open("/etc/config/hosts");
1450 #define MINTOKENS 2 /* ip address + canonical name */
1451 #define MAXTOKENS (MINTOKENS + MAXALIASES)
1452 #define HALISTOFF (sizeof(char*) * (MAXTOKENS + 1)) /* reserve space for list terminator */
1453 #define INADDROFF (HALISTOFF + 2 * sizeof(char*))
1455 int __read_etc_hosts_r(
1459 enum etc_hosts_action action
,
1460 struct hostent
*result_buf
,
1461 char *buf
, size_t buflen
,
1462 struct hostent
**result
,
1466 struct in_addr
*h_addr0
= NULL
;
1467 const size_t aliaslen
= INADDROFF
+
1468 #ifdef __UCLIBC_HAS_IPV6__
1469 sizeof(struct in6_addr
)
1471 sizeof(struct in_addr
)
1474 int ret
= HOST_NOT_FOUND
;
1475 /* make sure pointer is aligned */
1476 int i
= ALIGN_BUFFER_OFFSET(buf
);
1480 *h_errnop
= NETDB_INTERNAL
;
1481 if (/* (ssize_t)buflen < 0 || */ buflen
< aliaslen
1482 || (buflen
- aliaslen
) < BUFSZ
+ 1)
1485 parser
= __open_etc_hosts();
1486 if (parser
== NULL
) {
1491 * char *alias[MAXTOKENS] = {address, name, aliases...}
1492 * char **h_addr_list[1] = {*in[6]_addr, NULL}
1494 * char line_buffer[BUFSZ+];
1497 parser
->data_len
= aliaslen
;
1498 parser
->line_len
= buflen
- aliaslen
;
1499 *h_errnop
= HOST_NOT_FOUND
;
1500 /* <ip>[[:space:]][<aliases>] */
1501 while (config_read(parser
, &tok
, MAXTOKENS
, MINTOKENS
, "# \t", PARSE_NORMAL
)) {
1502 result_buf
->h_aliases
= tok
+1;
1503 if (action
== GETHOSTENT
) {
1504 /* Return whatever the next entry happens to be. */
1506 } else if (action
== GET_HOSTS_BYADDR
) {
1507 if (strcmp(name
, *tok
) != 0)
1509 } else { /* GET_HOSTS_BYNAME */
1511 char **alias
= tok
+ 1;
1512 while (aliases
< MAXALIASES
) {
1513 char *tmp
= *(alias
+aliases
++);
1514 if (tmp
&& strcasecmp(name
, tmp
) == 0)
1520 result_buf
->h_name
= *(result_buf
->h_aliases
++);
1521 result_buf
->h_addr_list
= (char**)(buf
+ HALISTOFF
);
1522 *(result_buf
->h_addr_list
+ 1) = '\0';
1523 h_addr0
= (struct in_addr
*)(buf
+ INADDROFF
);
1524 result_buf
->h_addr
= (char*)h_addr0
;
1525 if (0) /* nothing */;
1526 #ifdef __UCLIBC_HAS_IPV4__
1527 else if (type
== AF_INET
1528 && inet_pton(AF_INET
, *tok
, h_addr0
) > 0) {
1529 DPRINTF("Found INET\n");
1530 result_buf
->h_addrtype
= AF_INET
;
1531 result_buf
->h_length
= sizeof(struct in_addr
);
1532 *result
= result_buf
;
1533 ret
= NETDB_SUCCESS
;
1536 #ifdef __UCLIBC_HAS_IPV6__
1537 #define in6 ((struct in6_addr *)buf)
1538 else if (type
== AF_INET6
1539 && inet_pton(AF_INET6
, *tok
, h_addr0
) > 0) {
1540 DPRINTF("Found INET6\n");
1541 result_buf
->h_addrtype
= AF_INET6
;
1542 result_buf
->h_length
= sizeof(struct in6_addr
);
1543 *result
= result_buf
;
1544 ret
= NETDB_SUCCESS
;
1548 /* continue parsing in the hope the user has multiple
1549 * host types listed in the database like so:
1552 * If looking for an IPv6 addr, don't bail when we got the IPv4
1554 DPRINTF("Error: Found host but different address family\n");
1555 /* NB: gethostbyname2_r depends on this feature
1556 * to avoid looking for IPv6 addr of "localhost" etc */
1562 if (action
!= GETHOSTENT
)
1563 config_close(parser
);
1567 #endif /* L_read_etc_hosts_r */
1570 #ifdef L_get_hosts_byname_r
1572 int __get_hosts_byname_r(const char *name
,
1574 struct hostent
*result_buf
,
1577 struct hostent
**result
,
1580 return __read_etc_hosts_r(NULL
, name
, type
, GET_HOSTS_BYNAME
,
1581 result_buf
, buf
, buflen
, result
, h_errnop
);
1583 #endif /* L_get_hosts_byname_r */
1586 #ifdef L_get_hosts_byaddr_r
1588 int __get_hosts_byaddr_r(const char *addr
,
1591 struct hostent
*result_buf
,
1594 struct hostent
**result
,
1597 #ifndef __UCLIBC_HAS_IPV6__
1598 char ipaddr
[INET_ADDRSTRLEN
];
1600 char ipaddr
[INET6_ADDRSTRLEN
];
1604 #ifdef __UCLIBC_HAS_IPV4__
1606 if (len
!= sizeof(struct in_addr
))
1610 #ifdef __UCLIBC_HAS_IPV6__
1612 if (len
!= sizeof(struct in6_addr
))
1620 inet_ntop(type
, addr
, ipaddr
, sizeof(ipaddr
));
1622 return __read_etc_hosts_r(NULL
, ipaddr
, type
, GET_HOSTS_BYADDR
,
1623 result_buf
, buf
, buflen
, result
, h_errnop
);
1625 #endif /* L_get_hosts_byaddr_r */
1628 #ifdef L_getnameinfo
1630 int getnameinfo(const struct sockaddr
*sa
,
1640 struct hostent
*hoste
= NULL
;
1643 if (flags
& ~(NI_NUMERICHOST
|NI_NUMERICSERV
|NI_NOFQDN
|NI_NAMEREQD
|NI_DGRAM
))
1644 return EAI_BADFLAGS
;
1646 if (sa
== NULL
|| addrlen
< sizeof(sa_family_t
))
1649 if ((flags
& NI_NAMEREQD
) && host
== NULL
&& serv
== NULL
)
1652 if (sa
->sa_family
== AF_LOCAL
) /* valid */;
1653 #ifdef __UCLIBC_HAS_IPV4__
1654 else if (sa
->sa_family
== AF_INET
) {
1655 if (addrlen
< sizeof(struct sockaddr_in
))
1659 #ifdef __UCLIBC_HAS_IPV6__
1660 else if (sa
->sa_family
== AF_INET6
) {
1661 if (addrlen
< sizeof(struct sockaddr_in6
))
1668 if (host
!= NULL
&& hostlen
> 0)
1669 switch (sa
->sa_family
) {
1671 #ifdef __UCLIBC_HAS_IPV6__
1674 if (!(flags
& NI_NUMERICHOST
)) {
1675 if (0) /* nothing */;
1676 #ifdef __UCLIBC_HAS_IPV6__
1677 else if (sa
->sa_family
== AF_INET6
)
1678 hoste
= gethostbyaddr((const void *)
1679 &(((const struct sockaddr_in6
*) sa
)->sin6_addr
),
1680 sizeof(struct in6_addr
), AF_INET6
);
1682 #ifdef __UCLIBC_HAS_IPV4__
1684 hoste
= gethostbyaddr((const void *)
1685 &(((const struct sockaddr_in
*)sa
)->sin_addr
),
1686 sizeof(struct in_addr
), AF_INET
);
1691 if ((flags
& NI_NOFQDN
)
1692 && (getdomainname(domain
, sizeof(domain
)) == 0)
1693 && (c
= strstr(hoste
->h_name
, domain
)) != NULL
1694 && (c
!= hoste
->h_name
) && (*(--c
) == '.')
1696 strncpy(host
, hoste
->h_name
,
1697 MIN(hostlen
, (size_t) (c
- hoste
->h_name
)));
1698 host
[MIN(hostlen
- 1, (size_t) (c
- hoste
->h_name
))] = '\0';
1700 strncpy(host
, hoste
->h_name
, hostlen
);
1707 const char *c
= NULL
;
1709 if (flags
& NI_NAMEREQD
) {
1713 if (0) /* nothing */;
1714 #ifdef __UCLIBC_HAS_IPV6__
1715 else if (sa
->sa_family
== AF_INET6
) {
1716 const struct sockaddr_in6
*sin6p
;
1718 sin6p
= (const struct sockaddr_in6
*) sa
;
1719 c
= inet_ntop(AF_INET6
,
1720 (const void *) &sin6p
->sin6_addr
,
1723 /* Does scope id need to be supported? */
1725 scopeid
= sin6p
->sin6_scope_id
;
1727 /* Buffer is >= IFNAMSIZ+1. */
1728 char scopebuf
[IFNAMSIZ
+ 1];
1730 int ni_numericscope
= 0;
1731 size_t real_hostlen
= strnlen(host
, hostlen
);
1732 size_t scopelen
= 0;
1734 scopebuf
[0] = SCOPE_DELIMITER
;
1736 scopeptr
= &scopebuf
[1];
1738 if (IN6_IS_ADDR_LINKLOCAL(&sin6p
->sin6_addr
)
1739 || IN6_IS_ADDR_MC_LINKLOCAL(&sin6p
->sin6_addr
)) {
1740 if (if_indextoname(scopeid
, scopeptr
) == NULL
)
1743 scopelen
= strlen(scopebuf
);
1748 if (ni_numericscope
)
1749 scopelen
= 1 + snprintf(scopeptr
,
1755 if (real_hostlen
+ scopelen
+ 1 > hostlen
)
1757 memcpy(host
+ real_hostlen
, scopebuf
, scopelen
+ 1);
1761 #endif /* __UCLIBC_HAS_IPV6__ */
1762 #if defined __UCLIBC_HAS_IPV4__
1764 c
= inet_ntop(AF_INET
, (const void *)
1765 &(((const struct sockaddr_in
*) sa
)->sin_addr
),
1778 if (!(flags
& NI_NUMERICHOST
)) {
1779 struct utsname utsname
;
1781 if (!uname(&utsname
)) {
1782 strncpy(host
, utsname
.nodename
, hostlen
);
1787 if (flags
& NI_NAMEREQD
) {
1792 strncpy(host
, "localhost", hostlen
);
1794 /* Already checked above
1800 if (serv
&& (servlen
> 0)) {
1801 if (sa
->sa_family
== AF_LOCAL
) {
1802 strncpy(serv
, ((const struct sockaddr_un
*) sa
)->sun_path
, servlen
);
1803 } else { /* AF_INET || AF_INET6 */
1804 if (!(flags
& NI_NUMERICSERV
)) {
1806 s
= getservbyport(((const struct sockaddr_in
*) sa
)->sin_port
,
1807 ((flags
& NI_DGRAM
) ? "udp" : "tcp"));
1809 strncpy(serv
, s
->s_name
, servlen
);
1813 snprintf(serv
, servlen
, "%d",
1814 ntohs(((const struct sockaddr_in
*) sa
)->sin_port
));
1818 if (host
&& (hostlen
> 0))
1819 host
[hostlen
-1] = 0;
1820 if (serv
&& (servlen
> 0))
1821 serv
[servlen
-1] = 0;
1825 libc_hidden_def(getnameinfo
)
1826 #endif /* L_getnameinfo */
1829 #ifdef L_gethostbyname_r
1832 * "uClibc resolver's gethostbyname does not return the requested name
1833 * as an alias, but instead returns the canonical name. glibc's
1834 * gethostbyname has a similar bug where it returns the requested name
1835 * with the search domain name appended (to make a FQDN) as an alias,
1836 * but not the original name itself. Both contradict POSIX, which says
1837 * that the name argument passed to gethostbyname must be in the alias list"
1838 * This is fixed now, and we differ from glibc:
1840 * $ ./gethostbyname_uclibc wer.google.com
1841 * h_name:'c13-ss-2-lb.cnet.com'
1843 * h_addrtype:2 AF_INET
1844 * alias:'wer.google.com' <===
1845 * addr: 0x4174efd8 '216.239.116.65'
1847 * $ ./gethostbyname_glibc wer.google.com
1848 * h_name:'c13-ss-2-lb.cnet.com'
1850 * h_addrtype:2 AF_INET
1851 * alias:'wer.google.com.com' <===
1852 * addr:'216.239.116.65'
1854 * When examples were run, /etc/resolv.conf contained "search com" line.
1856 int gethostbyname_r(const char *name
,
1857 struct hostent
*result_buf
,
1860 struct hostent
**result
,
1863 struct in_addr
**addr_list
;
1866 unsigned char *packet
;
1867 struct resolv_answer a
;
1876 /* do /etc/hosts first */
1878 int old_errno
= errno
; /* save the old errno and reset errno */
1879 __set_errno(0); /* to check for missing /etc/hosts. */
1880 i
= __get_hosts_byname_r(name
, AF_INET
, result_buf
,
1881 buf
, buflen
, result
, h_errnop
);
1882 if (i
== NETDB_SUCCESS
) {
1883 __set_errno(old_errno
);
1886 switch (*h_errnop
) {
1887 case HOST_NOT_FOUND
:
1888 wrong_af
= (i
== TRY_AGAIN
);
1891 case NETDB_INTERNAL
:
1892 if (errno
== ENOENT
) {
1895 /* else fall through */
1899 __set_errno(old_errno
);
1902 DPRINTF("Nothing found in /etc/hosts\n");
1904 *h_errnop
= NETDB_INTERNAL
;
1906 /* prepare future h_aliases[0] */
1907 i
= strlen(name
) + 1;
1908 if ((ssize_t
)buflen
<= i
)
1910 memcpy(buf
, name
, i
); /* paranoia: name might change */
1914 /* make sure pointer is aligned */
1915 i
= ALIGN_BUFFER_OFFSET(buf
);
1920 * struct in_addr* addr_list[NN+1];
1921 * struct in_addr* in[NN];
1923 alias
= (char **)buf
;
1924 buf
+= sizeof(alias
[0]) * 2;
1925 buflen
-= sizeof(alias
[0]) * 2;
1926 addr_list
= (struct in_addr
**)buf
;
1927 /* buflen may be < 0, must do signed compare */
1928 if ((ssize_t
)buflen
< 256)
1931 /* we store only one "alias" - the name itself */
1935 /* maybe it is already an address? */
1937 struct in_addr
*in
= (struct in_addr
*)(buf
+ sizeof(addr_list
[0]) * 2);
1938 if (inet_aton(name
, in
)) {
1940 addr_list
[1] = NULL
;
1941 result_buf
->h_name
= alias0
;
1942 result_buf
->h_aliases
= alias
;
1943 result_buf
->h_addrtype
= AF_INET
;
1944 result_buf
->h_length
= sizeof(struct in_addr
);
1945 result_buf
->h_addr_list
= (char **) addr_list
;
1946 *result
= result_buf
;
1947 *h_errnop
= NETDB_SUCCESS
;
1948 return NETDB_SUCCESS
;
1952 /* what if /etc/hosts has it but it's not IPv4?
1953 * F.e. "::1 localhost6". We don't do DNS query for such hosts -
1954 * "ping localhost6" should be fast even if DNS server is down! */
1956 *h_errnop
= HOST_NOT_FOUND
;
1960 /* talk to DNS servers */
1962 /* take into account that at least one address will be there,
1963 * we'll need space for one in_addr + two addr_list[] elems */
1964 a
.buflen
= buflen
- ((sizeof(addr_list
[0]) * 2 + sizeof(struct in_addr
)));
1966 packet_len
= __dns_lookup(name
, T_A
, &packet
, &a
);
1967 if (packet_len
< 0) {
1968 *h_errnop
= HOST_NOT_FOUND
;
1969 DPRINTF("__dns_lookup returned < 0\n");
1973 if (a
.atype
== T_A
) { /* ADDRESS */
1974 /* we need space for addr_list[] and one IPv4 address */
1975 /* + 1 accounting for 1st addr (it's in a.rdata),
1976 * another + 1 for NULL in last addr_list[]: */
1977 int need_bytes
= sizeof(addr_list
[0]) * (a
.add_count
+ 1 + 1)
1978 /* for 1st addr (it's in a.rdata): */
1979 + sizeof(struct in_addr
);
1980 /* how many bytes will 2nd and following addresses take? */
1981 int ips_len
= a
.add_count
* a
.rdlength
;
1983 buflen
-= (need_bytes
+ ips_len
);
1984 if ((ssize_t
)buflen
< 0) {
1985 DPRINTF("buffer too small for all addresses\n");
1986 /* *h_errnop = NETDB_INTERNAL; - already is */
1991 /* if there are additional addresses in buf,
1992 * move them forward so that they are not destroyed */
1993 DPRINTF("a.add_count:%d a.rdlength:%d a.rdata:%p\n", a
.add_count
, a
.rdlength
, a
.rdata
);
1994 memmove(buf
+ need_bytes
, buf
, ips_len
);
1996 /* 1st address is in a.rdata, insert it */
1997 buf
+= need_bytes
- sizeof(struct in_addr
);
1998 memcpy(buf
, a
.rdata
, sizeof(struct in_addr
));
2000 /* fill addr_list[] */
2001 for (i
= 0; i
<= a
.add_count
; i
++) {
2002 addr_list
[i
] = (struct in_addr
*)buf
;
2003 buf
+= sizeof(struct in_addr
);
2005 addr_list
[i
] = NULL
;
2007 /* if we have enough space, we can report "better" name
2008 * (it may contain search domains attached by __dns_lookup,
2009 * or CNAME of the host if it is different from the name
2010 * we used to find it) */
2011 if (a
.dotted
&& buflen
> strlen(a
.dotted
)) {
2012 strcpy(buf
, a
.dotted
);
2016 result_buf
->h_name
= alias0
;
2017 result_buf
->h_aliases
= alias
;
2018 result_buf
->h_addrtype
= AF_INET
;
2019 result_buf
->h_length
= sizeof(struct in_addr
);
2020 result_buf
->h_addr_list
= (char **) addr_list
;
2021 *result
= result_buf
;
2022 *h_errnop
= NETDB_SUCCESS
;
2027 *h_errnop
= HOST_NOT_FOUND
;
2028 __set_h_errno(HOST_NOT_FOUND
);
2036 libc_hidden_def(gethostbyname_r
)
2037 #endif /* L_gethostbyname_r */
2040 #ifdef L_gethostbyname2_r
2042 int gethostbyname2_r(const char *name
,
2044 struct hostent
*result_buf
,
2047 struct hostent
**result
,
2050 #ifndef __UCLIBC_HAS_IPV6__
2051 return family
== (AF_INET
)
2052 ? gethostbyname_r(name
, result_buf
, buf
, buflen
, result
, h_errnop
)
2055 struct in6_addr
**addr_list
;
2058 unsigned char *packet
;
2059 struct resolv_answer a
;
2064 if (family
== AF_INET
)
2065 return gethostbyname_r(name
, result_buf
, buf
, buflen
, result
, h_errnop
);
2068 if (family
!= AF_INET6
)
2074 /* do /etc/hosts first */
2076 int old_errno
= errno
; /* save the old errno and reset errno */
2077 __set_errno(0); /* to check for missing /etc/hosts. */
2078 i
= __get_hosts_byname_r(name
, AF_INET6
/*family*/, result_buf
,
2079 buf
, buflen
, result
, h_errnop
);
2080 if (i
== NETDB_SUCCESS
) {
2081 __set_errno(old_errno
);
2084 switch (*h_errnop
) {
2085 case HOST_NOT_FOUND
:
2086 wrong_af
= (i
== TRY_AGAIN
);
2089 case NETDB_INTERNAL
:
2090 if (errno
== ENOENT
) {
2093 /* else fall through */
2097 __set_errno(old_errno
);
2100 DPRINTF("Nothing found in /etc/hosts\n");
2102 *h_errnop
= NETDB_INTERNAL
;
2104 /* prepare future h_aliases[0] */
2105 i
= strlen(name
) + 1;
2106 if ((ssize_t
)buflen
<= i
)
2108 memcpy(buf
, name
, i
); /* paranoia: name might change */
2112 /* make sure pointer is aligned */
2113 i
= ALIGN_BUFFER_OFFSET(buf
);
2118 * struct in6_addr* addr_list[NN+1];
2119 * struct in6_addr* in[NN];
2121 alias
= (char **)buf
;
2122 buf
+= sizeof(alias
[0]) * 2;
2123 buflen
-= sizeof(alias
[0]) * 2;
2124 addr_list
= (struct in6_addr
**)buf
;
2125 /* buflen may be < 0, must do signed compare */
2126 if ((ssize_t
)buflen
< 256)
2129 /* we store only one "alias" - the name itself */
2133 /* maybe it is already an address? */
2135 struct in6_addr
*in
= (struct in6_addr
*)(buf
+ sizeof(addr_list
[0]) * 2);
2136 if (inet_pton(AF_INET6
, name
, in
)) {
2138 addr_list
[1] = NULL
;
2139 result_buf
->h_name
= alias0
;
2140 result_buf
->h_aliases
= alias
;
2141 result_buf
->h_addrtype
= AF_INET6
;
2142 result_buf
->h_length
= sizeof(struct in6_addr
);
2143 result_buf
->h_addr_list
= (char **) addr_list
;
2144 *result
= result_buf
;
2145 *h_errnop
= NETDB_SUCCESS
;
2146 return NETDB_SUCCESS
;
2150 /* what if /etc/hosts has it but it's not IPv6?
2151 * F.e. "127.0.0.1 localhost". We don't do DNS query for such hosts -
2152 * "ping localhost" should be fast even if DNS server is down! */
2154 *h_errnop
= HOST_NOT_FOUND
;
2158 /* talk to DNS servers */
2160 /* take into account that at least one address will be there,
2161 * we'll need space of one in6_addr + two addr_list[] elems */
2162 a
.buflen
= buflen
- ((sizeof(addr_list
[0]) * 2 + sizeof(struct in6_addr
)));
2164 packet_len
= __dns_lookup(name
, T_AAAA
, &packet
, &a
);
2165 if (packet_len
< 0) {
2166 *h_errnop
= HOST_NOT_FOUND
;
2167 DPRINTF("__dns_lookup returned < 0\n");
2171 if (a
.atype
== T_AAAA
) { /* ADDRESS */
2172 /* we need space for addr_list[] and one IPv6 address */
2173 /* + 1 accounting for 1st addr (it's in a.rdata),
2174 * another + 1 for NULL in last addr_list[]: */
2175 int need_bytes
= sizeof(addr_list
[0]) * (a
.add_count
+ 1 + 1)
2176 /* for 1st addr (it's in a.rdata): */
2177 + sizeof(struct in6_addr
);
2178 /* how many bytes will 2nd and following addresses take? */
2179 int ips_len
= a
.add_count
* a
.rdlength
;
2181 buflen
-= (need_bytes
+ ips_len
);
2182 if ((ssize_t
)buflen
< 0) {
2183 DPRINTF("buffer too small for all addresses\n");
2184 /* *h_errnop = NETDB_INTERNAL; - already is */
2189 /* if there are additional addresses in buf,
2190 * move them forward so that they are not destroyed */
2191 DPRINTF("a.add_count:%d a.rdlength:%d a.rdata:%p\n", a
.add_count
, a
.rdlength
, a
.rdata
);
2192 memmove(buf
+ need_bytes
, buf
, ips_len
);
2194 /* 1st address is in a.rdata, insert it */
2195 buf
+= need_bytes
- sizeof(struct in6_addr
);
2196 memcpy(buf
, a
.rdata
, sizeof(struct in6_addr
));
2198 /* fill addr_list[] */
2199 for (i
= 0; i
<= a
.add_count
; i
++) {
2200 addr_list
[i
] = (struct in6_addr
*)buf
;
2201 buf
+= sizeof(struct in6_addr
);
2203 addr_list
[i
] = NULL
;
2205 /* if we have enough space, we can report "better" name
2206 * (it may contain search domains attached by __dns_lookup,
2207 * or CNAME of the host if it is different from the name
2208 * we used to find it) */
2209 if (a
.dotted
&& buflen
> strlen(a
.dotted
)) {
2210 strcpy(buf
, a
.dotted
);
2214 result_buf
->h_name
= alias0
;
2215 result_buf
->h_aliases
= alias
;
2216 result_buf
->h_addrtype
= AF_INET6
;
2217 result_buf
->h_length
= sizeof(struct in6_addr
);
2218 result_buf
->h_addr_list
= (char **) addr_list
;
2219 *result
= result_buf
;
2220 *h_errnop
= NETDB_SUCCESS
;
2225 *h_errnop
= HOST_NOT_FOUND
;
2226 __set_h_errno(HOST_NOT_FOUND
);
2233 #endif /* __UCLIBC_HAS_IPV6__ */
2235 libc_hidden_def(gethostbyname2_r
)
2236 #endif /* L_gethostbyname2_r */
2239 #ifdef L_gethostbyaddr_r
2241 int gethostbyaddr_r(const void *addr
, socklen_t addrlen
,
2243 struct hostent
*result_buf
,
2244 char *buf
, size_t buflen
,
2245 struct hostent
**result
,
2250 struct in_addr
**addr_list
;
2252 unsigned char *packet
;
2253 struct resolv_answer a
;
2263 #ifdef __UCLIBC_HAS_IPV4__
2265 if (addrlen
!= sizeof(struct in_addr
))
2269 #ifdef __UCLIBC_HAS_IPV6__
2271 if (addrlen
!= sizeof(struct in6_addr
))
2279 /* do /etc/hosts first */
2280 i
= __get_hosts_byaddr_r(addr
, addrlen
, type
, result_buf
,
2281 buf
, buflen
, result
, h_errnop
);
2284 switch (*h_errnop
) {
2285 case HOST_NOT_FOUND
:
2292 *h_errnop
= NETDB_INTERNAL
;
2294 /* make sure pointer is aligned */
2295 i
= ALIGN_BUFFER_OFFSET(buf
);
2299 * char *alias[ALIAS_DIM];
2300 * struct in[6]_addr* addr_list[2];
2301 * struct in[6]_addr in;
2302 * char scratch_buffer[256+];
2304 #define in6 ((struct in6_addr *)in)
2305 alias
= (char **)buf
;
2306 addr_list
= (struct in_addr
**)buf
;
2307 buf
+= sizeof(*addr_list
) * 2;
2308 buflen
-= sizeof(*addr_list
) * 2;
2309 in
= (struct in_addr
*)buf
;
2310 #ifndef __UCLIBC_HAS_IPV6__
2312 buflen
-= sizeof(*in
);
2313 if (addrlen
> sizeof(*in
))
2316 buf
+= sizeof(*in6
);
2317 buflen
-= sizeof(*in6
);
2318 if (addrlen
> sizeof(*in6
))
2321 if ((ssize_t
)buflen
< 256)
2326 addr_list
[1] = NULL
;
2327 memcpy(in
, addr
, addrlen
);
2329 if (0) /* nothing */;
2330 #ifdef __UCLIBC_HAS_IPV4__
2331 else IF_HAS_BOTH(if (type
== AF_INET
)) {
2332 unsigned char *tp
= (unsigned char *)addr
;
2333 sprintf(buf
, "%u.%u.%u.%u.in-addr.arpa",
2334 tp
[3], tp
[2], tp
[1], tp
[0]);
2337 #ifdef __UCLIBC_HAS_IPV6__
2340 unsigned char *tp
= (unsigned char *)addr
+ addrlen
- 1;
2342 dst
+= sprintf(dst
, "%x.%x.", tp
[0] & 0xf, tp
[0] >> 4);
2344 } while (tp
>= (unsigned char *)addr
);
2345 strcpy(dst
, "ip6.arpa");
2349 memset(&a
, '\0', sizeof(a
));
2351 /* Hmm why we memset(a) to zeros only once? */
2352 packet_len
= __dns_lookup(buf
, T_PTR
, &packet
, &a
);
2353 if (packet_len
< 0) {
2354 *h_errnop
= HOST_NOT_FOUND
;
2358 strncpy(buf
, a
.dotted
, buflen
);
2360 if (a
.atype
!= T_CNAME
)
2363 DPRINTF("Got a CNAME in gethostbyaddr()\n");
2364 if (++nest
> MAX_RECURSE
) {
2365 *h_errnop
= NO_RECOVERY
;
2368 /* Decode CNAME into buf, feed it to __dns_lookup() again */
2369 i
= __decode_dotted(packet
, a
.rdoffset
, packet_len
, buf
, buflen
);
2371 if (i
< 0 || __hnbad(buf
)) {
2372 *h_errnop
= NO_RECOVERY
;
2377 if (a
.atype
== T_PTR
) { /* ADDRESS */
2378 i
= __decode_dotted(packet
, a
.rdoffset
, packet_len
, buf
, buflen
);
2381 *h_errnop
= NO_RECOVERY
;
2384 result_buf
->h_name
= buf
;
2385 result_buf
->h_addrtype
= type
;
2386 result_buf
->h_length
= addrlen
;
2387 result_buf
->h_addr_list
= (char **) addr_list
;
2388 result_buf
->h_aliases
= alias
;
2389 *result
= result_buf
;
2390 *h_errnop
= NETDB_SUCCESS
;
2391 return NETDB_SUCCESS
;
2395 *h_errnop
= NO_ADDRESS
;
2399 libc_hidden_def(gethostbyaddr_r
)
2400 #endif /* L_gethostbyaddr_r */
2403 #ifdef L_gethostent_r
2405 __UCLIBC_MUTEX_STATIC(mylock
, PTHREAD_MUTEX_INITIALIZER
);
2407 static parser_t
*hostp
= NULL
;
2408 static smallint host_stayopen
;
2410 void endhostent_unlocked(void)
2413 config_close(hostp
);
2418 void endhostent(void)
2420 __UCLIBC_MUTEX_LOCK(mylock
);
2421 endhostent_unlocked();
2422 __UCLIBC_MUTEX_UNLOCK(mylock
);
2425 void sethostent(int stay_open
)
2427 __UCLIBC_MUTEX_LOCK(mylock
);
2430 __UCLIBC_MUTEX_UNLOCK(mylock
);
2433 int gethostent_r(struct hostent
*result_buf
, char *buf
, size_t buflen
,
2434 struct hostent
**result
, int *h_errnop
)
2438 __UCLIBC_MUTEX_LOCK(mylock
);
2439 if (hostp
== NULL
) {
2440 hostp
= __open_etc_hosts();
2441 if (hostp
== NULL
) {
2448 ret
= __read_etc_hosts_r(hostp
, NULL
, AF_INET
, GETHOSTENT
,
2449 result_buf
, buf
, buflen
, result
, h_errnop
);
2451 endhostent_unlocked();
2453 __UCLIBC_MUTEX_UNLOCK(mylock
);
2456 libc_hidden_def(gethostent_r
)
2457 #endif /* L_gethostent_r */
2460 #ifndef __UCLIBC_HAS_IPV6__
2461 #define GETXX_BUFSZ (sizeof(struct in_addr) + sizeof(struct in_addr *) * 2 + \
2462 /*sizeof(char *)*ALIAS_DIM */+ 384/*namebuffer*/ + 32/* margin */)
2464 #define GETXX_BUFSZ (sizeof(struct in6_addr) + sizeof(struct in6_addr *) * 2 + \
2465 /*sizeof(char *)*ALIAS_DIM */+ 384/*namebuffer*/ + 32/* margin */)
2466 #endif /* __UCLIBC_HAS_IPV6__ */
2468 #define __INIT_GETXX_BUF(sz) \
2470 buf = (char *)__uc_malloc((sz));
2474 struct hostent
*gethostent(void)
2476 static struct hostent hoste
;
2477 static char *buf
= NULL
;
2478 struct hostent
*host
= NULL
;
2479 #ifndef __UCLIBC_HAS_IPV6__
2480 #define HOSTENT_BUFSZ (sizeof(struct in_addr) + sizeof(struct in_addr *) * 2 + \
2481 sizeof(char *)*ALIAS_DIM + BUFSZ /*namebuffer*/ + 2 /* margin */)
2483 #define HOSTENT_BUFSZ (sizeof(struct in6_addr) + sizeof(struct in6_addr *) * 2 + \
2484 sizeof(char *)*ALIAS_DIM + BUFSZ /*namebuffer*/ + 2 /* margin */)
2485 #endif /* __UCLIBC_HAS_IPV6__ */
2487 __INIT_GETXX_BUF(HOSTENT_BUFSZ
);
2488 gethostent_r(&hoste
, buf
, HOSTENT_BUFSZ
, &host
, &h_errno
);
2491 #undef HOSTENT_BUFSZ
2492 #endif /* L_gethostent */
2495 #ifdef L_gethostbyname2
2497 struct hostent
*gethostbyname2(const char *name
, int family
)
2499 static struct hostent hoste
;
2500 static char *buf
= NULL
;
2503 __INIT_GETXX_BUF(GETXX_BUFSZ
);
2504 #ifndef __UCLIBC_HAS_IPV6__
2505 if (family
!= AF_INET
)
2506 return (struct hostent
*)NULL
;
2507 gethostbyname_r(name
, &hoste
, buf
, GETXX_BUFSZ
, &hp
, &h_errno
);
2509 gethostbyname2_r(name
, family
, &hoste
, buf
, GETXX_BUFSZ
, &hp
, &h_errno
);
2510 #endif /* __UCLIBC_HAS_IPV6__ */
2514 libc_hidden_def(gethostbyname2
)
2515 #endif /* L_gethostbyname2 */
2518 #ifdef L_gethostbyname
2520 struct hostent
*gethostbyname(const char *name
)
2522 return gethostbyname2(name
, AF_INET
);
2524 libc_hidden_def(gethostbyname
)
2525 #endif /* L_gethostbyname */
2528 #ifdef L_gethostbyaddr
2530 struct hostent
*gethostbyaddr(const void *addr
, socklen_t len
, int type
)
2532 static struct hostent hoste
;
2533 static char *buf
= NULL
;
2536 __INIT_GETXX_BUF(GETXX_BUFSZ
);
2537 gethostbyaddr_r(addr
, len
, type
, &hoste
, buf
, GETXX_BUFSZ
, &hp
, &h_errno
);
2540 libc_hidden_def(gethostbyaddr
)
2541 #endif /* L_gethostbyaddr */
2547 * Expand compressed domain name 'comp_dn' to full domain name.
2548 * 'msg' is a pointer to the begining of the message,
2549 * 'eomorig' points to the first location after the message,
2550 * 'exp_dn' is a pointer to a buffer of size 'length' for the result.
2551 * Return size of compressed name or -1 if there was an error.
2553 int dn_expand(const u_char
*msg
, const u_char
*eom
, const u_char
*src
,
2554 char *dst
, int dstsiz
)
2556 int n
= ns_name_uncompress(msg
, eom
, src
, dst
, (size_t)dstsiz
);
2558 if (n
> 0 && dst
[0] == '.')
2562 libc_hidden_def(dn_expand
)
2565 * Pack domain name 'exp_dn' in presentation form into 'comp_dn'.
2566 * Return the size of the compressed name or -1.
2567 * 'length' is the size of the array pointed to by 'comp_dn'.
2570 dn_comp(const char *src
, u_char
*dst
, int dstsiz
,
2571 u_char
**dnptrs
, u_char
**lastdnptr
)
2573 return ns_name_compress(src
, dst
, (size_t) dstsiz
,
2574 (const u_char
**) dnptrs
,
2575 (const u_char
**) lastdnptr
);
2577 libc_hidden_def(dn_comp
)
2578 #endif /* L_res_comp */
2583 /* Thinking in noninternationalized USASCII (per the DNS spec),
2584 * is this character visible and not a space when printed ?
2586 static int printable(int ch
)
2588 return (ch
> 0x20 && ch
< 0x7f);
2590 /* Thinking in noninternationalized USASCII (per the DNS spec),
2591 * is this characted special ("in need of quoting") ?
2593 static int special(int ch
)
2596 case 0x22: /* '"' */
2597 case 0x2E: /* '.' */
2598 case 0x3B: /* ';' */
2599 case 0x5C: /* '\\' */
2600 /* Special modifiers in zone files. */
2601 case 0x40: /* '@' */
2602 case 0x24: /* '$' */
2610 * ns_name_uncompress(msg, eom, src, dst, dstsiz)
2611 * Expand compressed domain name to presentation format.
2613 * Number of bytes read out of `src', or -1 (with errno set).
2615 * Root domain returns as "." not "".
2617 int ns_name_uncompress(const u_char
*msg
, const u_char
*eom
,
2618 const u_char
*src
, char *dst
, size_t dstsiz
)
2620 u_char tmp
[NS_MAXCDNAME
];
2623 n
= ns_name_unpack(msg
, eom
, src
, tmp
, sizeof tmp
);
2626 if (ns_name_ntop(tmp
, dst
, dstsiz
) == -1)
2630 libc_hidden_def(ns_name_uncompress
)
2633 * ns_name_ntop(src, dst, dstsiz)
2634 * Convert an encoded domain name to printable ascii as per RFC1035.
2636 * Number of bytes written to buffer, or -1 (with errno set)
2638 * The root is returned as "."
2639 * All other domains are returned in non absolute form
2641 int ns_name_ntop(const u_char
*src
, char *dst
, size_t dstsiz
)
2652 while ((n
= *cp
++) != 0) {
2653 if ((n
& NS_CMPRSFLGS
) != 0) {
2654 /* Some kind of compression pointer. */
2655 __set_errno(EMSGSIZE
);
2660 __set_errno(EMSGSIZE
);
2665 if (dn
+ n
>= eom
) {
2666 __set_errno(EMSGSIZE
);
2669 for (; n
> 0; n
--) {
2672 if (dn
+ 1 >= eom
) {
2673 __set_errno(EMSGSIZE
);
2678 } else if (!printable(c
)) {
2679 if (dn
+ 3 >= eom
) {
2680 __set_errno(EMSGSIZE
);
2684 *dn
++ = "0123456789"[c
/ 100];
2686 *dn
++ = "0123456789"[c
/ 10];
2687 *dn
++ = "0123456789"[c
% 10];
2690 __set_errno(EMSGSIZE
);
2699 __set_errno(EMSGSIZE
);
2705 __set_errno(EMSGSIZE
);
2711 libc_hidden_def(ns_name_ntop
)
2713 static int encode_bitstring(const char **bp
, const char *end
,
2714 unsigned char **labelp
,
2715 unsigned char ** dst
,
2716 unsigned const char *eom
)
2719 const char *cp
= *bp
;
2721 const char *beg_blen
;
2722 int value
= 0, count
= 0, tbcount
= 0, blen
= 0;
2726 /* a bitstring must contain at least 2 characters */
2730 /* XXX: currently, only hex strings are supported */
2733 if (!isxdigit((unsigned char) *cp
)) /*%< reject '\[x/BLEN]' */
2736 for (tp
= *dst
+ 1; cp
< end
&& tp
< eom
; cp
++) {
2737 unsigned char c
= *cp
;
2740 case ']': /*%< end of the bitstring */
2743 if (beg_blen
== NULL
)
2745 blen
= (int)strtol(beg_blen
, &end_blen
, 10);
2746 if (*end_blen
!= ']')
2750 *tp
++ = ((value
<< 4) & 0xff);
2751 cp
++; /*%< skip ']' */
2758 if (!__isdigit_char(c
))
2760 if (beg_blen
== NULL
) {
2762 /* blen never begings with 0 */
2768 if (!__isdigit_char(c
)) {
2769 c
= c
| 0x20; /* lowercase */
2771 if (c
> 5) /* not a-f? */
2790 if (cp
>= end
|| tp
>= eom
)
2794 * bit length validation:
2795 * If a <length> is present, the number of digits in the <bit-data>
2796 * MUST be just sufficient to contain the number of bits specified
2797 * by the <length>. If there are insignificant bits in a final
2798 * hexadecimal or octal digit, they MUST be zero.
2799 * RFC2673, Section 3.2.
2804 if (((blen
+ 3) & ~3) != tbcount
)
2806 traillen
= tbcount
- blen
; /*%< between 0 and 3 */
2807 if (((value
<< (8 - traillen
)) & 0xff) != 0)
2815 /* encode the type and the significant bit fields */
2816 **labelp
= DNS_LABELTYPE_BITSTRING
;
2825 int ns_name_pton(const char *src
, u_char
*dst
, size_t dstsiz
)
2827 static const char digits
[] = "0123456789";
2828 u_char
*label
, *bp
, *eom
;
2829 int c
, n
, escaped
, e
= 0;
2837 while ((c
= *src
++) != 0) {
2839 if (c
== '[') { /*%< start a bit string label */
2840 cp
= strchr(src
, ']');
2842 errno
= EINVAL
; /*%< ??? */
2845 e
= encode_bitstring(&src
, cp
+ 2,
2862 cp
= strchr(digits
, c
);
2864 n
= (cp
- digits
) * 100;
2868 cp
= strchr(digits
, c
);
2871 n
+= (cp
- digits
) * 10;
2875 cp
= strchr(digits
, c
);
2884 } else if (c
== '\\') {
2887 } else if (c
== '.') {
2888 c
= (bp
- label
- 1);
2889 if ((c
& NS_CMPRSFLGS
) != 0) { /*%< Label too big. */
2896 /* Fully qualified ? */
2904 if ((bp
- dst
) > MAXCDNAME
) {
2910 if (c
== 0 || *src
== '.') {
2921 c
= (bp
- label
- 1);
2922 if ((c
& NS_CMPRSFLGS
) != 0) { /*%< Label too big. */
2936 if ((bp
- dst
) > MAXCDNAME
) { /*%< src too big */
2946 libc_hidden_def(ns_name_pton
)
2950 * Check whether a name is valid enough for DNS. The rules, as
2951 * laid down by glibc, are:
2952 * - printable input string
2953 * - converts to label notation
2954 * - each label only contains [0-9a-zA-Z_-], up to 63 octets
2955 * - first label doesn’t begin with ‘-’
2956 * This both is weaker than Unix hostnames (e.g. it allows
2957 * underscores and leading/trailing hyphen-minus) and stronger
2958 * than general (e.g. a leading “*.” is valid sometimes), take care.
2960 * 0 if the name is ok
2962 int __hnbad(const char *dotted
)
2964 unsigned char c
, n
, *cp
;
2965 unsigned char buf
[NS_MAXCDNAME
];
2967 cp
= (unsigned char *)dotted
;
2969 if (c
< 0x21 || c
> 0x7E)
2971 if (ns_name_pton(dotted
, buf
, sizeof(buf
)) < 0)
2973 if (buf
[0] > 0 && buf
[1] == '-')
2976 while ((n
= *cp
++)) {
2982 (c
> '-' && c
< '0') ||
2983 (c
> '9' && c
< 'A') ||
2984 (c
> 'Z' && c
< '_') ||
2985 (c
> '_' && c
< 'a') ||
2994 * ns_name_unpack(msg, eom, src, dst, dstsiz)
2995 * Unpack a domain name from a message, source may be compressed.
2997 * -1 if it fails, or consumed octets if it succeeds.
2999 int ns_name_unpack(const u_char
*msg
, const u_char
*eom
, const u_char
*src
,
3000 u_char
*dst
, size_t dstsiz
)
3002 const u_char
*srcp
, *dstlim
;
3004 int n
, len
, checked
;
3010 dstlim
= dst
+ dstsiz
;
3011 if (srcp
< msg
|| srcp
>= eom
) {
3012 __set_errno(EMSGSIZE
);
3015 /* Fetch next label in domain name. */
3016 while ((n
= *srcp
++) != 0) {
3017 /* Check for indirection. */
3018 switch (n
& NS_CMPRSFLGS
) {
3021 if (dstp
+ n
+ 1 >= dstlim
|| srcp
+ n
>= eom
) {
3022 __set_errno(EMSGSIZE
);
3027 memcpy(dstp
, srcp
, n
);
3034 __set_errno(EMSGSIZE
);
3038 len
= srcp
- src
+ 1;
3039 srcp
= msg
+ (((n
& 0x3f) << 8) | (*srcp
& 0xff));
3040 if (srcp
< msg
|| srcp
>= eom
) { /* Out of range. */
3041 __set_errno(EMSGSIZE
);
3046 * Check for loops in the compressed name;
3047 * if we've looked at the whole message,
3048 * there must be a loop.
3050 if (checked
>= eom
- msg
) {
3051 __set_errno(EMSGSIZE
);
3057 __set_errno(EMSGSIZE
);
3058 return -1; /* flag error */
3066 libc_hidden_def(ns_name_unpack
)
3068 static int labellen(const unsigned char *lp
)
3071 unsigned char l
= *lp
;
3073 if ((l
& NS_CMPRSFLGS
) == NS_CMPRSFLGS
) {
3074 /* should be avoided by the caller */
3078 if ((l
& NS_CMPRSFLGS
) == NS_TYPE_ELT
) {
3079 if (l
== DNS_LABELTYPE_BITSTRING
) {
3083 return ((bitlen
+ 7 ) / 8 + 1);
3086 return -1; /*%< unknwon ELT */
3092 static int mklower(int ch
)
3094 if (ch
>= 0x41 && ch
<= 0x5A)
3100 static int dn_find(const unsigned char *domain
,
3101 const unsigned char *msg
,
3102 const unsigned char * const *dnptrs
,
3103 const unsigned char * const *lastdnptr
)
3105 const unsigned char *dn
, *cp
, *sp
;
3106 const unsigned char * const *cpp
;
3109 for (cpp
= dnptrs
; cpp
< lastdnptr
; cpp
++) {
3112 * terminate search on:
3114 * compression pointer
3117 while (*sp
!= 0 && (*sp
& NS_CMPRSFLGS
) == 0 &&
3118 (sp
- msg
) < 0x4000) {
3122 while ((n
= *cp
++) != 0) {
3124 * check for indirection
3126 switch (n
& NS_CMPRSFLGS
) {
3127 case 0: /*%< normal case, n == len */
3128 n
= labellen(cp
- 1); /*%< XXX */
3133 if (mklower(*dn
++) !=
3136 /* Is next root for both ? */
3137 if (*dn
== '\0' && *cp
== '\0')
3142 case NS_CMPRSFLGS
: /*%< indirection */
3143 cp
= msg
+ (((n
& 0x3f) << 8) | *cp
);
3146 default: /*%< illegal type */
3160 int ns_name_pack(const unsigned char *src
,
3161 unsigned char *dst
, int dstsiz
,
3162 const unsigned char **dnptrs
,
3163 const unsigned char **lastdnptr
)
3165 unsigned char *dstp
;
3166 const unsigned char **cpp
, **lpp
, *eob
, *msg
;
3167 const unsigned char *srcp
;
3168 int n
, l
, first
= 1;
3172 eob
= dstp
+ dstsiz
;
3175 if (dnptrs
!= NULL
) {
3178 for (cpp
= dnptrs
; *cpp
!= NULL
; cpp
++)
3181 lpp
= cpp
; /*%< end of list to search */
3187 /* make sure the domain we are about to add is legal */
3193 if ((n
& NS_CMPRSFLGS
) == NS_CMPRSFLGS
) {
3198 l0
= labellen(srcp
);
3205 if (l
> MAXCDNAME
) {
3213 /* from here on we need to reset compression pointer array on error */
3217 /* Look to see if we can use pointers. */
3220 if (n
!= 0 && msg
!= NULL
) {
3221 l
= dn_find(srcp
, msg
, (const unsigned char * const *) dnptrs
,
3222 (const unsigned char * const *) lpp
);
3224 if (dstp
+ 1 >= eob
) {
3228 *dstp
++ = ((u_int32_t
)l
>> 8) | NS_CMPRSFLGS
;
3230 return (dstp
- dst
);
3233 /* Not found, save it. */
3234 if (lastdnptr
!= NULL
&& cpp
< lastdnptr
- 1 &&
3235 (dstp
- msg
) < 0x4000 && first
) {
3242 /* copy label to buffer */
3243 if ((n
& NS_CMPRSFLGS
) == NS_CMPRSFLGS
) {
3244 /* Should not happen. */
3249 if (dstp
+ 1 + n
>= eob
) {
3253 memcpy(dstp
, srcp
, (size_t)(n
+ 1));
3269 libc_hidden_def(ns_name_pack
)
3271 int ns_name_compress(const char *src
,
3272 unsigned char *dst
, size_t dstsiz
,
3273 const unsigned char **dnptrs
,
3274 const unsigned char **lastdnptr
)
3276 unsigned char tmp
[NS_MAXCDNAME
];
3278 if (ns_name_pton(src
, tmp
, sizeof(tmp
)) == -1)
3281 return ns_name_pack(tmp
, dst
, dstsiz
, dnptrs
, lastdnptr
);
3283 libc_hidden_def(ns_name_compress
)
3285 int ns_name_skip(const unsigned char **ptrptr
,
3286 const unsigned char *eom
)
3288 const unsigned char *cp
;
3293 while (cp
< eom
&& (n
= *cp
++) != 0) {
3294 /* Check for indirection. */
3295 switch (n
& NS_CMPRSFLGS
) {
3296 case 0: /*%< normal case, n == len */
3299 case NS_TYPE_ELT
: /*%< EDNS0 extended label */
3300 l
= labellen(cp
- 1);
3302 errno
= EMSGSIZE
; /*%< XXX */
3307 case NS_CMPRSFLGS
: /*%< indirection */
3310 default: /*%< illegal type */
3327 libc_hidden_def(ns_name_skip
)
3329 int dn_skipname(const unsigned char *ptr
, const unsigned char *eom
)
3331 const unsigned char *saveptr
= ptr
;
3333 if (ns_name_skip(&ptr
, eom
) == -1)
3336 return ptr
- saveptr
;
3338 libc_hidden_def(dn_skipname
)
3339 #endif /* L_ns_name */
3344 /* Will be called under __resolv_lock. */
3345 static void res_sync_func(void)
3347 struct __res_state
*rp
= &(_res
);
3350 /* If we didn't get malloc failure earlier... */
3351 if (__nameserver
!= (void*) &__local_nameserver
) {
3353 * if (__nameservers < rp->nscount) - try to grow __nameserver[]?
3355 #ifdef __UCLIBC_HAS_IPV6__
3356 if (__nameservers
> rp
->_u
._ext
.nscount
)
3357 __nameservers
= rp
->_u
._ext
.nscount
;
3360 __nameserver
[n
].sa6
= *rp
->_u
._ext
.nsaddrs
[n
]; /* struct copy */
3361 #else /* IPv4 only */
3362 if (__nameservers
> rp
->nscount
)
3363 __nameservers
= rp
->nscount
;
3366 __nameserver
[n
].sa4
= rp
->nsaddr_list
[n
]; /* struct copy */
3369 __resolv_timeout
= rp
->retrans
? : RES_TIMEOUT
;
3370 __resolv_attempts
= rp
->retry
? : RES_DFLRETRY
;
3371 /* Extend and comment what program is known
3372 * to use which _res.XXX member(s).
3374 __resolv_opts = rp->options;
3379 /* has to be called under __resolv_lock */
3381 __res_vinit(res_state rp
, int preinit
)
3383 int i
, n
, options
, retrans
, retry
, ndots
;
3384 #ifdef __UCLIBC_HAS_IPV6__
3388 __close_nameservers();
3389 __open_nameservers();
3392 options
= rp
->options
;
3393 retrans
= rp
->retrans
;
3398 memset(rp
, 0, sizeof(*rp
));
3401 rp
->options
= RES_DEFAULT
;
3402 rp
->retrans
= RES_TIMEOUT
;
3403 rp
->retry
= RES_DFLRETRY
;
3406 rp
->options
= options
;
3407 rp
->retrans
= retrans
;
3412 #ifdef __UCLIBC_HAS_COMPAT_RES_STATE__
3413 /* Was: "rp->id = random();" but:
3414 * - random() pulls in largish static buffers
3415 * - isn't actually random unless, say, srandom(time(NULL)) was called
3416 * - is not used by uclibc anyway :)
3418 /* rp->id = 0; - memset did it */
3420 #ifdef __UCLIBC_HAS_EXTRA_COMPAT_RES_STATE__
3424 n
= __searchdomains
;
3425 if (n
> ARRAY_SIZE(rp
->dnsrch
))
3426 n
= ARRAY_SIZE(rp
->dnsrch
);
3427 for (i
= 0; i
< n
; i
++)
3428 rp
->dnsrch
[i
] = __searchdomain
[i
];
3430 /* copy nameservers' addresses */
3432 #ifdef __UCLIBC_HAS_IPV4__
3434 while (n
< ARRAY_SIZE(rp
->nsaddr_list
) && i
< __nameservers
) {
3435 if (__nameserver
[i
].sa
.sa_family
== AF_INET
) {
3436 rp
->nsaddr_list
[n
] = __nameserver
[i
].sa4
; /* struct copy */
3437 #ifdef __UCLIBC_HAS_IPV6__
3438 if (m
< ARRAY_SIZE(rp
->_u
._ext
.nsaddrs
)) {
3439 rp
->_u
._ext
.nsaddrs
[m
] = (void*) &rp
->nsaddr_list
[n
];
3445 #ifdef __UCLIBC_HAS_IPV6__
3446 if (__nameserver
[i
].sa
.sa_family
== AF_INET6
3447 && m
< ARRAY_SIZE(rp
->_u
._ext
.nsaddrs
)
3449 struct sockaddr_in6
*sa6
= malloc(sizeof(*sa6
));
3451 *sa6
= __nameserver
[i
].sa6
; /* struct copy */
3452 rp
->_u
._ext
.nsaddrs
[m
] = sa6
;
3460 #ifdef __UCLIBC_HAS_IPV6__
3461 rp
->_u
._ext
.nscount
= m
;
3464 #else /* IPv6 only */
3465 while (m
< ARRAY_SIZE(rp
->_u
._ext
.nsaddrs
) && i
< __nameservers
) {
3466 struct sockaddr_in6
*sa6
= malloc(sizeof(*sa6
));
3468 *sa6
= __nameserver
[i
].sa6
; /* struct copy */
3469 rp
->_u
._ext
.nsaddrs
[m
] = sa6
;
3474 rp
->_u
._ext
.nscount
= m
;
3477 rp
->options
|= RES_INIT
;
3485 return 0xffff & getpid();
3488 /* Our res_init never fails (always returns 0) */
3493 * These three fields used to be statically initialized. This made
3494 * it hard to use this code in a shared library. It is necessary,
3495 * now that we're doing dynamic initialization here, that we preserve
3496 * the old semantics: if an application modifies one of these three
3497 * fields of _res before res_init() is called, res_init() will not
3498 * alter them. Of course, if an application is setting them to
3499 * _zero_ before calling res_init(), hoping to override what used
3500 * to be the static default, we can't detect it and unexpected results
3501 * will follow. Zero for any of these fields would make no sense,
3502 * so one can safely assume that the applications were already getting
3503 * unexpected results.
3505 * _res.options is tricky since some apps were known to diddle the bits
3506 * before res_init() was first called. We can't replicate that semantic
3507 * with dynamic initialization (they may have turned bits off that are
3508 * set in RES_DEFAULT). Our solution is to declare such applications
3509 * "broken". They could fool us by setting RES_INIT but none do (yet).
3512 __UCLIBC_MUTEX_LOCK(__resolv_lock
);
3515 _res
.retrans
= RES_TIMEOUT
;
3518 if (!(_res
.options
& RES_INIT
))
3519 _res
.options
= RES_DEFAULT
;
3522 * This one used to initialize implicitly to zero, so unless the app
3523 * has set it to something in particular, we can randomize it now.
3526 _res
.id
= res_randomid();
3529 __res_vinit(&_res
, 1);
3530 __res_sync
= res_sync_func
;
3532 __UCLIBC_MUTEX_UNLOCK(__resolv_lock
);
3536 libc_hidden_def(res_init
)
3539 __res_iclose(res_state statp
)
3541 struct __res_state
* rp
= statp
;
3542 __UCLIBC_MUTEX_LOCK(__resolv_lock
);
3545 __close_nameservers();
3547 #ifdef __UCLIBC_HAS_IPV6__
3549 char *p1
= (char*) &(rp
->nsaddr_list
[0]);
3551 /* free nsaddrs[m] if they do not point to nsaddr_list[x] */
3552 while (m
< ARRAY_SIZE(rp
->_u
._ext
.nsaddrs
)) {
3553 char *p2
= (char*)(rp
->_u
._ext
.nsaddrs
[m
++]);
3554 if (p2
< p1
|| (p2
- p1
) > (signed)sizeof(rp
->nsaddr_list
))
3559 memset(rp
, 0, sizeof(struct __res_state
));
3560 __UCLIBC_MUTEX_UNLOCK(__resolv_lock
);
3564 * This routine is for closing the socket if a virtual circuit is used and
3565 * the program wants to close it. This provides support for endhostent()
3566 * which expects to close the socket.
3568 * This routine is not expected to be user visible.
3572 res_nclose(res_state statp
)
3574 __res_iclose(statp
);
3577 #ifdef __UCLIBC_HAS_BSD_RES_CLOSE__
3578 void res_close(void)
3584 #ifdef __UCLIBC_HAS_BSD_B64_NTOP_B64_PTON__
3585 #define Assert(Cond) if (!(Cond)) abort()
3587 static const char Base64
[] =
3588 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
3589 static const char Pad64
= '=';
3591 /* (From RFC1521 and draft-ietf-dnssec-secext-03.txt)
3592 The following encoding technique is taken from RFC 1521 by Borenstein
3593 and Freed. It is reproduced here in a slightly edited form for
3596 A 65-character subset of US-ASCII is used, enabling 6 bits to be
3597 represented per printable character. (The extra 65th character, "=",
3598 is used to signify a special processing function.)
3600 The encoding process represents 24-bit groups of input bits as output
3601 strings of 4 encoded characters. Proceeding from left to right, a
3602 24-bit input group is formed by concatenating 3 8-bit input groups.
3603 These 24 bits are then treated as 4 concatenated 6-bit groups, each
3604 of which is translated into a single digit in the base64 alphabet.
3606 Each 6-bit group is used as an index into an array of 64 printable
3607 characters. The character referenced by the index is placed in the
3610 Table 1: The Base64 Alphabet
3612 Value Encoding Value Encoding Value Encoding Value Encoding
3627 14 O 31 f 48 w (pad) =
3631 Special processing is performed if fewer than 24 bits are available
3632 at the end of the data being encoded. A full encoding quantum is
3633 always completed at the end of a quantity. When fewer than 24 input
3634 bits are available in an input group, zero bits are added (on the
3635 right) to form an integral number of 6-bit groups. Padding at the
3636 end of the data is performed using the '=' character.
3638 Since all base64 input is an integral number of octets, only the
3639 -------------------------------------------------
3640 following cases can arise:
3642 (1) the final quantum of encoding input is an integral
3643 multiple of 24 bits; here, the final unit of encoded
3644 output will be an integral multiple of 4 characters
3645 with no "=" padding,
3646 (2) the final quantum of encoding input is exactly 8 bits;
3647 here, the final unit of encoded output will be two
3648 characters followed by two "=" padding characters, or
3649 (3) the final quantum of encoding input is exactly 16 bits;
3650 here, the final unit of encoded output will be three
3651 characters followed by one "=" padding character.
3655 b64_ntop(u_char
const *src
, size_t srclength
, char *target
, size_t targsize
) {
3656 size_t datalength
= 0;
3661 while (2 < srclength
) {
3667 output
[0] = input
[0] >> 2;
3668 output
[1] = ((input
[0] & 0x03) << 4) + (input
[1] >> 4);
3669 output
[2] = ((input
[1] & 0x0f) << 2) + (input
[2] >> 6);
3670 output
[3] = input
[2] & 0x3f;
3671 Assert(output
[0] < 64);
3672 Assert(output
[1] < 64);
3673 Assert(output
[2] < 64);
3674 Assert(output
[3] < 64);
3676 if (datalength
+ 4 > targsize
)
3678 target
[datalength
++] = Base64
[output
[0]];
3679 target
[datalength
++] = Base64
[output
[1]];
3680 target
[datalength
++] = Base64
[output
[2]];
3681 target
[datalength
++] = Base64
[output
[3]];
3684 /* Now we worry about padding. */
3685 if (0 != srclength
) {
3686 /* Get what's left. */
3687 input
[0] = input
[1] = input
[2] = '\0';
3688 for (i
= 0; i
< srclength
; i
++)
3691 output
[0] = input
[0] >> 2;
3692 output
[1] = ((input
[0] & 0x03) << 4) + (input
[1] >> 4);
3693 output
[2] = ((input
[1] & 0x0f) << 2) + (input
[2] >> 6);
3694 Assert(output
[0] < 64);
3695 Assert(output
[1] < 64);
3696 Assert(output
[2] < 64);
3698 if (datalength
+ 4 > targsize
)
3700 target
[datalength
++] = Base64
[output
[0]];
3701 target
[datalength
++] = Base64
[output
[1]];
3703 target
[datalength
++] = Pad64
;
3705 target
[datalength
++] = Base64
[output
[2]];
3706 target
[datalength
++] = Pad64
;
3708 if (datalength
>= targsize
)
3710 target
[datalength
] = '\0'; /* Returned value doesn't count \0. */
3711 return (datalength
);
3713 /* libc_hidden_def (b64_ntop) */
3715 /* skips all whitespace anywhere.
3716 converts characters, four at a time, starting at (or after)
3717 src from base - 64 numbers into three 8 bit bytes in the target area.
3718 it returns the number of data bytes stored at the target, or -1 on error.
3722 b64_pton (char const *src
, u_char
*target
, size_t targsize
)
3724 int tarindex
, state
, ch
;
3730 while ((ch
= *src
++) != '\0') {
3731 if (isspace(ch
)) /* Skip whitespace anywhere. */
3737 pos
= strchr(Base64
, ch
);
3738 if (pos
== 0) /* A non-base64 character. */
3744 if ((size_t)tarindex
>= targsize
)
3746 target
[tarindex
] = (pos
- Base64
) << 2;
3752 if ((size_t)tarindex
+ 1 >= targsize
)
3754 target
[tarindex
] |= (pos
- Base64
) >> 4;
3755 target
[tarindex
+1] = ((pos
- Base64
) & 0x0f)
3763 if ((size_t)tarindex
+ 1 >= targsize
)
3765 target
[tarindex
] |= (pos
- Base64
) >> 2;
3766 target
[tarindex
+1] = ((pos
- Base64
) & 0x03)
3774 if ((size_t)tarindex
>= targsize
)
3776 target
[tarindex
] |= (pos
- Base64
);
3787 * We are done decoding Base-64 chars. Let's see if we ended
3788 * on a byte boundary, and/or with erroneous trailing characters.
3791 if (ch
== Pad64
) { /* We got a pad char. */
3792 ch
= *src
++; /* Skip it, get next. */
3794 case 0: /* Invalid = in first position */
3795 case 1: /* Invalid = in second position */
3798 case 2: /* Valid, means one byte of info */
3799 /* Skip any number of spaces. */
3800 for ((void)NULL
; ch
!= '\0'; ch
= *src
++)
3803 /* Make sure there is another trailing = sign. */
3806 ch
= *src
++; /* Skip the = */
3807 /* Fall through to "single trailing =" case. */
3810 case 3: /* Valid, means two bytes of info */
3812 * We know this char is an =. Is there anything but
3813 * whitespace after it?
3815 for ((void)NULL
; ch
!= '\0'; ch
= *src
++)
3820 * Now make sure for cases 2 and 3 that the "extra"
3821 * bits that slopped past the last full byte were
3822 * zeros. If we don't check them, they become a
3823 * subliminal channel.
3825 if (target
&& target
[tarindex
] != 0)
3830 * We ended by seeing the end of the string. Make sure we
3831 * have no partial bytes lying around.
3841 /* This needs to be after the use of _res in res_init, above. */
3844 #ifndef __UCLIBC_HAS_THREADS__
3845 /* The resolver state for use by single-threaded programs.
3846 This differs from plain `struct __res_state _res;' in that it doesn't
3847 create a common definition, but a plain symbol that resides in .bss,
3848 which can have an alias. */
3849 struct __res_state _res
__attribute__((section (".bss")));
3850 struct __res_state
*__resp
= &_res
;
3851 #else /* __UCLIBC_HAS_THREADS__ */
3852 struct __res_state _res
__attribute__((section (".bss"))) attribute_hidden
;
3854 # if defined __UCLIBC_HAS_TLS__
3856 __thread
struct __res_state
*__resp
= &_res
;
3857 extern __thread
struct __res_state
*__libc_resp
3858 __attribute__ ((alias ("__resp"))) attribute_hidden attribute_tls_model_ie
;
3861 struct __res_state
*__resp
= &_res
;
3863 #endif /* !__UCLIBC_HAS_THREADS__ */
3866 * Set up default settings. If the configuration file exist, the values
3867 * there will have precedence. Otherwise, the server address is set to
3868 * INADDR_ANY and the default domain name comes from the gethostname().
3870 * An interrim version of this code (BIND 4.9, pre-4.4BSD) used 127.0.0.1
3871 * rather than INADDR_ANY ("0.0.0.0") as the default name server address
3872 * since it was noted that INADDR_ANY actually meant ``the first interface
3873 * you "ifconfig"'d at boot time'' and if this was a SLIP or PPP interface,
3874 * it had to be "up" in order for you to reach your own name server. It
3875 * was later decided that since the recommended practice is to always
3876 * install local static routes through 127.0.0.1 for all your network
3877 * interfaces, that we could solve this problem without a code change.
3879 * The configuration file should always be used, since it is the only way
3880 * to specify a default domain. If you are running a server on your local
3881 * machine, you should say "nameserver 0.0.0.0" or "nameserver 127.0.0.1"
3882 * in the configuration file.
3884 * Return 0 if completes successfully, -1 on error
3887 res_ninit(res_state statp
)
3890 __UCLIBC_MUTEX_LOCK(__resolv_lock
);
3891 ret
= __res_vinit(statp
, 0);
3892 __UCLIBC_MUTEX_UNLOCK(__resolv_lock
);
3896 #endif /* L_res_init */
3899 # if defined __UCLIBC_HAS_TLS__
3900 struct __res_state
*
3907 extern struct __res_state _res
;
3909 /* When threaded, _res may be a per-thread variable. */
3910 struct __res_state
*
3918 #endif /* L_res_state */
3923 int res_query(const char *dname
, int class, int type
,
3924 unsigned char *answer
, int anslen
)
3927 unsigned char *packet
= NULL
;
3928 struct resolv_answer a
;
3930 if (!dname
|| class != 1 /* CLASS_IN */) {
3931 h_errno
= NO_RECOVERY
;
3935 memset(&a
, '\0', sizeof(a
));
3936 i
= __dns_lookup(dname
, type
, &packet
, &a
);
3939 if (!h_errno
) /* TODO: can this ever happen? */
3940 h_errno
= TRY_AGAIN
;
3948 memcpy(answer
, packet
, i
);
3953 libc_hidden_def(res_query
)
3956 * Formulate a normal query, send, and retrieve answer in supplied buffer.
3957 * Return the size of the response on success, -1 on error.
3958 * If enabled, implement search rules until answer or unrecoverable failure
3959 * is detected. Error code, if any, is left in h_errno.
3961 #define __TRAILING_DOT (1<<0)
3962 #define __GOT_NODATA (1<<1)
3963 #define __GOT_SERVFAIL (1<<2)
3964 #define __TRIED_AS_IS (1<<3)
3965 int res_search(const char *name
, int class, int type
, u_char
*answer
,
3970 HEADER
*hp
= (HEADER
*)(void *)answer
;
3973 int ret
, saved_herrno
;
3974 uint32_t _res_options
;
3975 unsigned _res_ndots
;
3978 if (!name
|| !answer
) {
3979 h_errno
= NETDB_INTERNAL
;
3984 __UCLIBC_MUTEX_LOCK(__resolv_lock
);
3985 _res_options
= _res
.options
;
3986 _res_ndots
= _res
.ndots
;
3987 _res_dnsrch
= _res
.dnsrch
;
3988 __UCLIBC_MUTEX_UNLOCK(__resolv_lock
);
3989 if (!(_res_options
& RES_INIT
)) {
3990 res_init(); /* our res_init never fails */
3996 h_errno
= HOST_NOT_FOUND
; /* default, if we never query */
3998 for (cp
= name
; *cp
; cp
++)
3999 dots
+= (*cp
== '.');
4001 if (cp
> name
&& *--cp
== '.')
4002 state
|= __TRAILING_DOT
;
4005 * If there are dots in the name already, let's just give it a try
4006 * 'as is'. The threshold can be set with the "ndots" option.
4009 if (dots
>= _res_ndots
) {
4010 ret
= res_querydomain(name
, NULL
, class, type
, answer
, anslen
);
4013 saved_herrno
= h_errno
;
4014 state
|= __TRIED_AS_IS
;
4018 * We do at least one level of search if
4019 * - there is no dot and RES_DEFNAME is set, or
4020 * - there is at least one dot, there is no trailing dot,
4021 * and RES_DNSRCH is set.
4023 if ((!dots
&& (_res_options
& RES_DEFNAMES
))
4024 || (dots
&& !(state
& __TRAILING_DOT
) && (_res_options
& RES_DNSRCH
))
4028 for (domain
= _res_dnsrch
; *domain
&& !done
; domain
++) {
4030 ret
= res_querydomain(name
, *domain
, class, type
,
4036 * If no server present, give up.
4037 * If name isn't found in this domain,
4038 * keep trying higher domains in the search list
4039 * (if that's enabled).
4040 * On a NO_DATA error, keep trying, otherwise
4041 * a wildcard entry of another type could keep us
4042 * from finding this entry higher in the domain.
4043 * If we get some other error (negative answer or
4044 * server failure), then stop searching up,
4045 * but try the input name below in case it's
4048 if (errno
== ECONNREFUSED
) {
4049 h_errno
= TRY_AGAIN
;
4055 state
|= __GOT_NODATA
;
4057 case HOST_NOT_FOUND
:
4061 if (hp
->rcode
== SERVFAIL
) {
4062 /* try next search element, if any */
4063 state
|= __GOT_SERVFAIL
;
4068 /* anything else implies that we're done */
4072 * if we got here for some reason other than DNSRCH,
4073 * we only wanted one iteration of the loop, so stop.
4075 if (!(_res_options
& RES_DNSRCH
))
4081 * if we have not already tried the name "as is", do that now.
4082 * note that we do this regardless of how many dots were in the
4083 * name or whether it ends with a dot.
4085 if (!(state
& __TRIED_AS_IS
)) {
4086 ret
= res_querydomain(name
, NULL
, class, type
, answer
, anslen
);
4092 * if we got here, we didn't satisfy the search.
4093 * if we did an initial full query, return that query's h_errno
4094 * (note that we wouldn't be here if that query had succeeded).
4095 * else if we ever got a nodata, send that back as the reason.
4096 * else send back meaningless h_errno, that being the one from
4097 * the last DNSRCH we did.
4099 if (saved_herrno
!= -1)
4100 h_errno
= saved_herrno
;
4101 else if (state
& __GOT_NODATA
)
4103 else if (state
& __GOT_SERVFAIL
)
4104 h_errno
= TRY_AGAIN
;
4107 #undef __TRAILING_DOT
4109 #undef __GOT_SERVFAIL
4110 #undef __TRIED_AS_IS
4112 * Perform a call on res_query on the concatenation of name and domain,
4113 * removing a trailing dot from name if domain is NULL.
4115 int res_querydomain(const char *name
, const char *domain
, int class, int type
,
4116 u_char
*answer
, int anslen
)
4118 char nbuf
[MAXDNAME
];
4119 const char *longname
= nbuf
;
4122 uint32_t _res_options
;
4125 if (!name
|| !answer
) {
4126 h_errno
= NETDB_INTERNAL
;
4132 __UCLIBC_MUTEX_LOCK(__resolv_lock
);
4133 _res_options
= _res
.options
;
4134 __UCLIBC_MUTEX_UNLOCK(__resolv_lock
);
4135 if (!(_res_options
& RES_INIT
)) {
4136 res_init(); /* our res_init never fails */
4139 if (_res_options
& RES_DEBUG
)
4140 printf(";; res_querydomain(%s, %s, %d, %d)\n",
4141 name
, (domain
? domain
: "<Nil>"), class, type
);
4143 if (domain
== NULL
) {
4145 * Check for trailing '.';
4146 * copy without '.' if present.
4149 if (n
+ 1 > sizeof(nbuf
)) {
4150 h_errno
= NO_RECOVERY
;
4153 if (n
> 0 && name
[--n
] == '.') {
4154 strncpy(nbuf
, name
, n
);
4161 if (n
+ 1 + d
+ 1 > sizeof(nbuf
)) {
4162 h_errno
= NO_RECOVERY
;
4165 snprintf(nbuf
, sizeof(nbuf
), "%s.%s", name
, domain
);
4167 return res_query(longname
, class, type
, answer
, anslen
);
4169 libc_hidden_def(res_querydomain
)
4170 #endif /* L_res_query */
4173 unsigned int ns_get16(const unsigned char *src
)
4180 unsigned long ns_get32(const unsigned char *src
)
4187 void ns_put16(unsigned int src
, unsigned char *dst
)
4192 void ns_put32(unsigned long src
, unsigned char *dst
)
4196 #endif /* L_ns_netint */
4199 /* These need to be in the same order as the nres.h:ns_flag enum. */
4200 struct _ns_flagdata
{ unsigned short mask
, shift
; };
4201 static const struct _ns_flagdata _ns_flagdata
[16] = {
4202 { 0x8000, 15 }, /*%< qr. */
4203 { 0x7800, 11 }, /*%< opcode. */
4204 { 0x0400, 10 }, /*%< aa. */
4205 { 0x0200, 9 }, /*%< tc. */
4206 { 0x0100, 8 }, /*%< rd. */
4207 { 0x0080, 7 }, /*%< ra. */
4208 { 0x0040, 6 }, /*%< z. */
4209 { 0x0020, 5 }, /*%< ad. */
4210 { 0x0010, 4 }, /*%< cd. */
4211 { 0x000f, 0 }, /*%< rcode. */
4212 { 0x0000, 0 }, /*%< expansion (1/6). */
4213 { 0x0000, 0 }, /*%< expansion (2/6). */
4214 { 0x0000, 0 }, /*%< expansion (3/6). */
4215 { 0x0000, 0 }, /*%< expansion (4/6). */
4216 { 0x0000, 0 }, /*%< expansion (5/6). */
4217 { 0x0000, 0 }, /*%< expansion (6/6). */
4220 static void setsection(ns_msg
*msg
, ns_sect sect
)
4223 if (sect
== ns_s_max
) {
4228 msg
->_ptr
= msg
->_sections
[(int)sect
];
4232 int ns_skiprr(const unsigned char *ptr
,
4233 const unsigned char *eom
,
4234 ns_sect section
, int count
)
4236 const u_char
*optr
= ptr
;
4238 for (; count
> 0; count
--) {
4241 b
= dn_skipname(ptr
, eom
);
4247 ptr
+= b
/*Name*/ + NS_INT16SZ
/*Type*/ + NS_INT16SZ
/*Class*/;
4248 if (section
!= ns_s_qd
) {
4249 if (ptr
+ NS_INT32SZ
+ NS_INT16SZ
> eom
) {
4254 ptr
+= NS_INT32SZ
/*TTL*/;
4255 NS_GET16(rdlength
, ptr
);
4256 ptr
+= rdlength
/*RData*/;
4267 libc_hidden_def(ns_skiprr
)
4270 ns_initparse(const unsigned char *msg
, int msglen
, ns_msg
*handle
)
4272 const u_char
*eom
= msg
+ msglen
;
4277 if (msg
+ NS_INT16SZ
> eom
) {
4282 NS_GET16(handle
->_id
, msg
);
4283 if (msg
+ NS_INT16SZ
> eom
) {
4288 NS_GET16(handle
->_flags
, msg
);
4289 for (i
= 0; i
< ns_s_max
; i
++) {
4290 if (msg
+ NS_INT16SZ
> eom
) {
4295 NS_GET16(handle
->_counts
[i
], msg
);
4297 for (i
= 0; i
< ns_s_max
; i
++)
4298 if (handle
->_counts
[i
] == 0)
4299 handle
->_sections
[i
] = NULL
;
4301 int b
= ns_skiprr(msg
, eom
, (ns_sect
)i
,
4302 handle
->_counts
[i
]);
4306 handle
->_sections
[i
] = msg
;
4315 setsection(handle
, ns_s_max
);
4320 ns_parserr(ns_msg
*handle
, ns_sect section
, int rrnum
, ns_rr
*rr
)
4325 /* Make section right. */
4327 if (tmp
< 0 || section
>= ns_s_max
) {
4332 if (section
!= handle
->_sect
)
4333 setsection(handle
, section
);
4335 /* Make rrnum right. */
4337 rrnum
= handle
->_rrnum
;
4338 if (rrnum
< 0 || rrnum
>= handle
->_counts
[(int)section
]) {
4342 if (rrnum
< handle
->_rrnum
)
4343 setsection(handle
, section
);
4344 if (rrnum
> handle
->_rrnum
) {
4345 b
= ns_skiprr(handle
->_ptr
, handle
->_eom
, section
,
4346 rrnum
- handle
->_rrnum
);
4351 handle
->_rrnum
= rrnum
;
4355 b
= dn_expand(handle
->_msg
, handle
->_eom
,
4356 handle
->_ptr
, rr
->name
, NS_MAXDNAME
);
4360 if (handle
->_ptr
+ NS_INT16SZ
+ NS_INT16SZ
> handle
->_eom
) {
4364 NS_GET16(rr
->type
, handle
->_ptr
);
4365 NS_GET16(rr
->rr_class
, handle
->_ptr
);
4366 if (section
== ns_s_qd
) {
4371 if (handle
->_ptr
+ NS_INT32SZ
+ NS_INT16SZ
> handle
->_eom
) {
4375 NS_GET32(rr
->ttl
, handle
->_ptr
);
4376 NS_GET16(rr
->rdlength
, handle
->_ptr
);
4377 if (handle
->_ptr
+ rr
->rdlength
> handle
->_eom
) {
4381 rr
->rdata
= handle
->_ptr
;
4382 handle
->_ptr
+= rr
->rdlength
;
4384 if (++handle
->_rrnum
> handle
->_counts
[(int)section
])
4385 setsection(handle
, (ns_sect
)((int)section
+ 1));
4390 int ns_msg_getflag(ns_msg handle
, int flag
)
4392 return ((handle
)._flags
& _ns_flagdata
[flag
].mask
) >> _ns_flagdata
[flag
].shift
;
4394 #endif /* L_ns_parse */
4397 int res_mkquery(int op
, const char *dname
, int class, int type
,
4398 const unsigned char *data
, int datalen
,
4399 const unsigned char *newrr_in
,
4400 unsigned char *buf
, int buflen
)
4403 unsigned char *cp
, *ep
;
4404 unsigned char *dnptrs
[20], **dpp
, **lastdnptr
;
4405 uint32_t _res_options
;
4408 if (!buf
|| buflen
< HFIXEDSZ
) {
4409 h_errno
= NETDB_INTERNAL
;
4414 __UCLIBC_MUTEX_LOCK(__resolv_lock
);
4415 _res_options
= _res
.options
;
4416 __UCLIBC_MUTEX_UNLOCK(__resolv_lock
);
4417 if (!(_res_options
& RES_INIT
)) {
4418 res_init(); /* our res_init never fails */
4423 if (_res_options
& RES_DEBUG
)
4424 printf(";; res_mkquery(%d, %s, %d, %d)\n",
4425 op
, dname
&& *dname
? dname
: "<null>", class, type
);
4428 memset(buf
, 0, HFIXEDSZ
);
4429 hp
= (HEADER
*) buf
;
4430 hp
->id
= getpid() & 0xffff;
4432 hp
->rd
= (_res_options
& RES_RECURSE
) != 0U;
4433 hp
->rcode
= NOERROR
;
4435 cp
= buf
+ HFIXEDSZ
;
4440 lastdnptr
= dnptrs
+ sizeof dnptrs
/ sizeof dnptrs
[0];
4443 * perform opcode specific processing
4448 if (ep
- cp
< QFIXEDSZ
)
4451 n
= dn_comp(dname
, cp
, ep
- cp
- QFIXEDSZ
, dnptrs
, lastdnptr
);
4457 NS_PUT16(class, cp
);
4458 hp
->qdcount
= htons(1);
4460 if (op
== QUERY
|| data
== NULL
)
4464 * Make an additional record for completion domain.
4466 if ((ep
- cp
) < RRFIXEDSZ
)
4469 n
= dn_comp((const char *)data
, cp
, ep
- cp
- RRFIXEDSZ
,
4475 NS_PUT16(T_NULL
, cp
);
4476 NS_PUT16(class, cp
);
4479 hp
->arcount
= htons(1);
4485 * Initialize answer section
4487 if (ep
- cp
< 1 + RRFIXEDSZ
+ datalen
)
4490 *cp
++ = '\0'; /*%< no domain name */
4492 NS_PUT16(class, cp
);
4494 NS_PUT16(datalen
, cp
);
4497 memcpy(cp
, data
, (size_t)datalen
);
4501 hp
->ancount
= htons(1);
4510 #endif /* L_res_data */
4512 /* Unimplemented: */