libdl: first execute all destructors, then munmap library
[uclibc-ng.git] / libc / inet / resolv.c
blobc05f18980cc1ec4a2604bbd4d2cce303719f9f6a
1 /* resolv.c: DNS Resolver
3 * Copyright (C) 1998 Kenneth Albanowski <kjahds@kjahds.com>,
4 * The Silver Hammer Group, Ltd.
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
12 * Portions Copyright (c) 1985, 1993
13 * The Regents of the University of California. All rights reserved.
15 * Redistribution and use in source and binary forms, with or without
16 * modification, are permitted provided that the following conditions
17 * are met:
18 * 1. Redistributions of source code must retain the above copyright
19 * notice, this list of conditions and the following disclaimer.
20 * 2. Redistributions in binary form must reproduce the above copyright
21 * notice, this list of conditions and the following disclaimer in the
22 * documentation and/or other materials provided with the distribution.
23 * 4. Neither the name of the University nor the names of its contributors
24 * may be used to endorse or promote products derived from this software
25 * without specific prior written permission.
27 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 * SUCH DAMAGE.
40 * Portions Copyright (c) 1993 by Digital Equipment Corporation.
42 * Permission to use, copy, modify, and distribute this software for any
43 * purpose with or without fee is hereby granted, provided that the above
44 * copyright notice and this permission notice appear in all copies, and that
45 * the name of Digital Equipment Corporation not be used in advertising or
46 * publicity pertaining to distribution of the document or software without
47 * specific, written prior permission.
49 * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
50 * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
51 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
52 * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
53 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
54 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
55 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
56 * SOFTWARE.
59 * Portions Copyright (c) 1996-1999 by Internet Software Consortium.
61 * Permission to use, copy, modify, and distribute this software for any
62 * purpose with or without fee is hereby granted, provided that the above
63 * copyright notice and this permission notice appear in all copies.
65 * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
66 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
67 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
68 * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
69 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
70 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
71 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
72 * SOFTWARE.
74 /* RFC 1035
75 ...
76 Whenever an octet represents a numeric quantity, the left most bit
77 in the diagram is the high order or most significant bit.
78 That is, the bit labeled 0 is the most significant bit.
79 ...
81 4.1.1. Header section format
82 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
83 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
84 | ID |
85 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
86 |QR| OPCODE |AA|TC|RD|RA| 0 0 0| RCODE |
87 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
88 | QDCOUNT |
89 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
90 | ANCOUNT |
91 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
92 | NSCOUNT |
93 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
94 | ARCOUNT |
95 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
96 ID 16 bit random identifier assigned by querying peer.
97 Used to match query/response.
98 QR message is a query (0), or a response (1).
99 OPCODE 0 standard query (QUERY)
100 1 inverse query (IQUERY)
101 2 server status request (STATUS)
102 AA Authoritative Answer - this bit is valid in responses.
103 Responding name server is an authority for the domain name
104 in question section. Answer section may have multiple owner names
105 because of aliases. The AA bit corresponds to the name which matches
106 the query name, or the first owner name in the answer section.
107 TC TrunCation - this message was truncated.
108 RD Recursion Desired - this bit may be set in a query and
109 is copied into the response. If RD is set, it directs
110 the name server to pursue the query recursively.
111 Recursive query support is optional.
112 RA Recursion Available - this be is set or cleared in a
113 response, and denotes whether recursive query support is
114 available in the name server.
115 RCODE Response code.
116 0 No error condition
117 1 Format error
118 2 Server failure - server was unable to process the query
119 due to a problem with the name server.
120 3 Name Error - meaningful only for responses from
121 an authoritative name server. The referenced domain name
122 does not exist.
123 4 Not Implemented.
124 5 Refused.
125 QDCOUNT number of entries in the question section.
126 ANCOUNT number of records in the answer section.
127 NSCOUNT number of records in the authority records section.
128 ARCOUNT number of records in the additional records section.
130 4.1.2. Question section format
132 The section contains QDCOUNT (usually 1) entries, each of this format:
133 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
134 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
135 / QNAME /
137 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
138 | QTYPE |
139 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
140 | QCLASS |
141 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
142 QNAME a domain name represented as a sequence of labels, where
143 each label consists of a length octet followed by that
144 number of octets. The domain name terminates with the
145 zero length octet for the null label of the root. Note
146 that this field may be an odd number of octets; no
147 padding is used.
148 QTYPE a two octet type of the query.
149 1 a host address [REQ_A const]
150 2 an authoritative name server
151 3 a mail destination (Obsolete - use MX)
152 4 a mail forwarder (Obsolete - use MX)
153 5 the canonical name for an alias
154 6 marks the start of a zone of authority
155 7 a mailbox domain name (EXPERIMENTAL)
156 8 a mail group member (EXPERIMENTAL)
157 9 a mail rename domain name (EXPERIMENTAL)
158 10 a null RR (EXPERIMENTAL)
159 11 a well known service description
160 12 a domain name pointer [REQ_PTR const]
161 13 host information
162 14 mailbox or mail list information
163 15 mail exchange
164 16 text strings
165 0x1c IPv6?
166 252 a request for a transfer of an entire zone
167 253 a request for mailbox-related records (MB, MG or MR)
168 254 a request for mail agent RRs (Obsolete - see MX)
169 255 a request for all records
170 QCLASS a two octet code that specifies the class of the query.
171 1 the Internet
172 (others are historic only)
173 255 any class
175 4.1.3. Resource record format
177 The answer, authority, and additional sections all share the same format:
178 a variable number of resource records, where the number of records
179 is specified in the corresponding count field in the header.
180 Each resource record has this format:
181 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
182 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
184 / NAME /
185 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
186 | TYPE |
187 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
188 | CLASS |
189 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
190 | TTL |
192 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
193 | RDLENGTH |
194 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--|
195 / RDATA /
197 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
198 NAME a domain name to which this resource record pertains.
199 TYPE two octets containing one of the RR type codes. This
200 field specifies the meaning of the data in the RDATA field.
201 CLASS two octets which specify the class of the data in the RDATA field.
202 TTL a 32 bit unsigned integer that specifies the time interval
203 (in seconds) that the record may be cached.
204 RDLENGTH a 16 bit integer, length in octets of the RDATA field.
205 RDATA a variable length string of octets that describes the resource.
206 The format of this information varies according to the TYPE
207 and CLASS of the resource record.
208 If the TYPE is A and the CLASS is IN, it's a 4 octet IP address.
210 4.1.4. Message compression
212 In order to reduce the size of messages, domain names can be compressed.
213 An entire domain name or a list of labels at the end of a domain name
214 is replaced with a pointer to a prior occurance of the same name.
216 The pointer takes the form of a two octet sequence:
217 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
218 | 1 1| OFFSET |
219 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
220 The first two bits are ones. This allows a pointer to be distinguished
221 from a label, since the label must begin with two zero bits because
222 labels are restricted to 63 octets or less. The OFFSET field specifies
223 an offset from the start of the message (i.e., the first octet
224 of the ID field in the domain header).
225 A zero offset specifies the first byte of the ID field, etc.
226 Domain name in a message can be represented as either:
227 - a sequence of labels ending in a zero octet
228 - a pointer
229 - a sequence of labels ending with a pointer
232 #include <string.h>
233 #include <stdio.h>
234 #include <stdio_ext.h>
235 #include <signal.h>
236 #include <malloc.h>
237 #include <errno.h>
238 #include <sys/poll.h>
239 #include <sys/socket.h>
240 #include <sys/types.h>
241 #include <sys/time.h>
242 #include <netinet/in.h>
243 #include <arpa/inet.h>
244 #include <stdlib.h>
245 #include <unistd.h>
246 #include <resolv.h>
247 #include <netdb.h>
248 #include <ctype.h>
249 #include <stdbool.h>
250 #include <time.h>
251 #include <arpa/nameser.h>
252 #include <sys/utsname.h>
253 #include <sys/un.h>
254 #include <sys/stat.h>
255 #include <sys/param.h>
256 #include <bits/uClibc_mutex.h>
257 #include "internal/parse_config.h"
259 /* poll() is not supported in kernel <= 2.0, therefore if __NR_poll is
260 * not available, we assume an old Linux kernel is in use and we will
261 * use select() instead. */
262 #include <sys/syscall.h>
263 #ifndef __NR_poll
264 # define USE_SELECT
265 #endif
267 #if defined __UCLIBC_HAS_IPV4__ && defined __UCLIBC_HAS_IPV6__
268 #define IF_HAS_BOTH(...) __VA_ARGS__
269 #else
270 #define IF_HAS_BOTH(...)
271 #endif
274 #define MAX_RECURSE 5
275 #define MAXALIASES (4)
276 /* 1:ip + 1:full + MAX_ALIASES:aliases + 1:NULL */
277 #define ALIAS_DIM (2 + MAXALIASES + 1)
278 #define BUFSZ (80) /* one line */
280 #define NS_TYPE_ELT 0x40 /*%< EDNS0 extended label type */
281 #define DNS_LABELTYPE_BITSTRING 0x41
283 #undef DEBUG
284 /* #define DEBUG */
286 #ifdef DEBUG
287 #define DPRINTF(X,args...) fprintf(stderr, X, ##args)
288 #else
289 #define DPRINTF(X,args...)
290 #endif
292 /* Make sure the incoming char * buffer is aligned enough to handle our random
293 * structures. This define is the same as we use for malloc alignment (which
294 * has same requirements). The offset is the number of bytes we need to adjust
295 * in order to attain desired alignment.
297 #define ALIGN_ATTR __alignof__(double __attribute_aligned__ (sizeof(size_t)))
298 #define ALIGN_BUFFER_OFFSET(buf) ((ALIGN_ATTR - ((size_t)buf % ALIGN_ATTR)) % ALIGN_ATTR)
301 /* Structs */
302 struct resolv_header {
303 int id;
304 int qr, opcode, aa, tc, rd, ra, rcode;
305 int qdcount;
306 int ancount;
307 int nscount;
308 int arcount;
311 struct resolv_question {
312 char *dotted;
313 int qtype;
314 int qclass;
317 struct resolv_answer {
318 char *dotted;
319 int atype;
320 int aclass;
321 int ttl;
322 int rdlength;
323 const unsigned char *rdata;
324 int rdoffset;
325 char* buf;
326 size_t buflen;
327 size_t add_count;
330 enum etc_hosts_action {
331 GET_HOSTS_BYNAME = 0,
332 GETHOSTENT,
333 GET_HOSTS_BYADDR,
336 typedef union sockaddr46_t {
337 struct sockaddr sa;
338 #ifdef __UCLIBC_HAS_IPV4__
339 struct sockaddr_in sa4;
340 #endif
341 #ifdef __UCLIBC_HAS_IPV6__
342 struct sockaddr_in6 sa6;
343 #endif
344 } sockaddr46_t;
347 __UCLIBC_MUTEX_EXTERN(__resolv_lock) attribute_hidden;
349 /* Protected by __resolv_lock */
350 extern void (*__res_sync)(void) attribute_hidden;
351 /*extern uint32_t __resolv_opts attribute_hidden; */
352 extern uint8_t __resolv_timeout attribute_hidden;
353 extern uint8_t __resolv_attempts attribute_hidden;
354 extern unsigned __nameservers attribute_hidden;
355 extern unsigned __searchdomains attribute_hidden;
356 extern sockaddr46_t *__nameserver attribute_hidden;
357 extern char **__searchdomain attribute_hidden;
358 #ifdef __UCLIBC_HAS_IPV4__
359 extern const struct sockaddr_in __local_nameserver attribute_hidden;
360 #else
361 extern const struct sockaddr_in6 __local_nameserver attribute_hidden;
362 #endif
363 /* Arbitrary */
364 #define MAXLEN_searchdomain 128
367 /* prototypes for internal functions */
368 extern void endhostent_unlocked(void) attribute_hidden;
369 extern int __get_hosts_byname_r(const char *name,
370 int type,
371 struct hostent *result_buf,
372 char *buf,
373 size_t buflen,
374 struct hostent **result,
375 int *h_errnop) attribute_hidden;
376 extern int __get_hosts_byaddr_r(const char *addr,
377 int len,
378 int type,
379 struct hostent *result_buf,
380 char *buf,
381 size_t buflen,
382 struct hostent **result,
383 int *h_errnop) attribute_hidden;
384 extern parser_t *__open_etc_hosts(void) attribute_hidden;
385 extern int __read_etc_hosts_r(parser_t *parser,
386 const char *name,
387 int type,
388 enum etc_hosts_action action,
389 struct hostent *result_buf,
390 char *buf,
391 size_t buflen,
392 struct hostent **result,
393 int *h_errnop) attribute_hidden;
394 extern int __dns_lookup(const char *name,
395 int type,
396 unsigned char **outpacket,
397 struct resolv_answer *a) attribute_hidden;
398 extern int __encode_dotted(const char *dotted,
399 unsigned char *dest,
400 int maxlen) attribute_hidden;
401 extern int __decode_dotted(const unsigned char *packet,
402 int offset,
403 int packet_len,
404 char *dest,
405 int dest_len) attribute_hidden;
406 extern int __encode_header(struct resolv_header *h,
407 unsigned char *dest,
408 int maxlen) attribute_hidden;
409 extern void __decode_header(unsigned char *data,
410 struct resolv_header *h) attribute_hidden;
411 extern int __encode_question(const struct resolv_question *q,
412 unsigned char *dest,
413 int maxlen) attribute_hidden;
414 extern int __encode_answer(struct resolv_answer *a,
415 unsigned char *dest,
416 int maxlen) attribute_hidden;
417 extern void __open_nameservers(void) attribute_hidden;
418 extern void __close_nameservers(void) attribute_hidden;
421 * Theory of operation.
423 * gethostbyname, getaddrinfo and friends end up here, and they sometimes
424 * need to talk to DNS servers. In order to do this, we need to read /etc/resolv.conf
425 * and determine servers' addresses and the like. resolv.conf format:
427 * nameserver <IP[v6]>
428 * Address of DNS server. Cumulative.
429 * If not specified, assumed to be on localhost.
430 * search <domain1>[ <domain2>]...
431 * Append these domains to unqualified names.
432 * See ndots:n option.
433 * $LOCALDOMAIN (space-separated list) overrides this.
434 * domain <domain>
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.
445 * Not supported.
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
461 * no-check-names
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.
505 #ifdef L_encodeh
507 int __encode_header(struct resolv_header *h, unsigned char *dest, int maxlen)
509 if (maxlen < HFIXEDSZ)
510 return -1;
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) |
516 (h->aa ? 0x04 : 0) |
517 (h->tc ? 0x02 : 0) |
518 (h->rd ? 0x01 : 0);
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;
529 return HFIXEDSZ;
531 #endif /* L_encodeh */
534 #ifdef L_decodeh
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 */
555 #ifdef L_encoded
557 /* Encode a dotted string into nameserver transport-level encoding.
558 This routine is fairly dumb, and doesn't attempt to compress
559 the data */
560 int __encode_dotted(const char *dotted, unsigned char *dest, int maxlen)
562 unsigned used = 0;
564 while (dotted && *dotted) {
565 char *c = strchr(dotted, '.');
566 int l = c ? c - dotted : strlen(dotted);
568 /* two consecutive dots are not valid */
569 if (l == 0)
570 return -1;
572 if (l >= (maxlen - used - 1))
573 return -1;
575 dest[used++] = l;
576 memcpy(dest + used, dotted, l);
577 used += l;
579 if (!c)
580 break;
581 dotted = c + 1;
584 if (maxlen < 1)
585 return -1;
587 dest[used++] = 0;
589 return used;
591 #endif /* L_encoded */
594 #ifdef L_decoded
596 /* Decode a dotted string from nameserver transport-level encoding.
597 This routine understands compressed data. */
598 int __decode_dotted(const unsigned char *packet,
599 int offset,
600 int packet_len,
601 char *dest,
602 int dest_len)
604 unsigned b;
605 bool measure = 1;
606 unsigned total = 0;
607 unsigned used = 0;
608 unsigned maxiter = 256;
610 if (!packet)
611 return -1;
613 dest[0] = '\0';
614 while (--maxiter) {
615 if (offset >= packet_len)
616 return -1;
617 b = packet[offset++];
618 if (b == 0)
619 break;
621 if (measure)
622 total++;
624 if ((b & 0xc0) == 0xc0) {
625 if (offset >= packet_len)
626 return -1;
627 if (measure)
628 total++;
629 /* compressed item, redirect */
630 offset = ((b & 0x3f) << 8) | packet[offset];
631 measure = 0;
632 continue;
635 if (used + b + 1 >= dest_len)
636 return -1;
637 if (offset + b >= packet_len)
638 return -1;
639 memcpy(dest + used, packet + offset, b);
640 offset += b;
641 used += b;
643 if (measure)
644 total += b;
646 if (packet[offset] != 0)
647 dest[used++] = '.';
648 else
649 dest[used++] = '\0';
651 if (!maxiter)
652 return -1;
654 /* The null byte must be counted too */
655 if (measure)
656 total++;
658 DPRINTF("Total decode len = %d\n", total);
660 return total;
662 #endif /* L_decoded */
665 #ifdef L_encodeq
667 int __encode_question(const struct resolv_question *q,
668 unsigned char *dest,
669 int maxlen)
671 int i;
673 i = __encode_dotted(q->dotted, dest, maxlen);
674 if (i < 0)
675 return i;
677 dest += i;
678 maxlen -= i;
680 if (maxlen < 4)
681 return -1;
683 dest[0] = (q->qtype & 0xff00) >> 8;
684 dest[1] = (q->qtype & 0x00ff) >> 0;
685 dest[2] = (q->qclass & 0xff00) >> 8;
686 dest[3] = (q->qclass & 0x00ff) >> 0;
688 return i + 4;
690 #endif /* L_encodeq */
693 #ifdef L_encodea
695 int __encode_answer(struct resolv_answer *a, unsigned char *dest, int maxlen)
697 int i;
699 i = __encode_dotted(a->dotted, dest, maxlen);
700 if (i < 0)
701 return i;
703 dest += i;
704 maxlen -= i;
706 if (maxlen < (RRFIXEDSZ + a->rdlength))
707 return -1;
709 *dest++ = (a->atype & 0xff00) >> 8;
710 *dest++ = (a->atype & 0x00ff) >> 0;
711 *dest++ = (a->aclass & 0xff00) >> 8;
712 *dest++ = (a->aclass & 0x00ff) >> 0;
713 *dest++ = (a->ttl & 0xff000000) >> 24;
714 *dest++ = (a->ttl & 0x00ff0000) >> 16;
715 *dest++ = (a->ttl & 0x0000ff00) >> 8;
716 *dest++ = (a->ttl & 0x000000ff) >> 0;
717 *dest++ = (a->rdlength & 0xff00) >> 8;
718 *dest++ = (a->rdlength & 0x00ff) >> 0;
719 memcpy(dest, a->rdata, a->rdlength);
721 return i + RRFIXEDSZ + a->rdlength;
723 #endif /* L_encodea */
726 #ifdef CURRENTLY_UNUSED
727 #ifdef L_encodep
729 int __encode_packet(struct resolv_header *h,
730 struct resolv_question **q,
731 struct resolv_answer **an,
732 struct resolv_answer **ns,
733 struct resolv_answer **ar,
734 unsigned char *dest, int maxlen) attribute_hidden;
735 int __encode_packet(struct resolv_header *h,
736 struct resolv_question **q,
737 struct resolv_answer **an,
738 struct resolv_answer **ns,
739 struct resolv_answer **ar,
740 unsigned char *dest, int maxlen)
742 int i, total = 0;
743 unsigned j;
745 i = __encode_header(h, dest, maxlen);
746 if (i < 0)
747 return i;
749 dest += i;
750 maxlen -= i;
751 total += i;
753 for (j = 0; j < h->qdcount; j++) {
754 i = __encode_question(q[j], dest, maxlen);
755 if (i < 0)
756 return i;
757 dest += i;
758 maxlen -= i;
759 total += i;
762 for (j = 0; j < h->ancount; j++) {
763 i = __encode_answer(an[j], dest, maxlen);
764 if (i < 0)
765 return i;
766 dest += i;
767 maxlen -= i;
768 total += i;
770 for (j = 0; j < h->nscount; j++) {
771 i = __encode_answer(ns[j], dest, maxlen);
772 if (i < 0)
773 return i;
774 dest += i;
775 maxlen -= i;
776 total += i;
778 for (j = 0; j < h->arcount; j++) {
779 i = __encode_answer(ar[j], dest, maxlen);
780 if (i < 0)
781 return i;
782 dest += i;
783 maxlen -= i;
784 total += i;
787 return total;
789 #endif /* L_encodep */
792 #ifdef L_decodep
794 int __decode_packet(unsigned char *data, struct resolv_header *h) attribute_hidden;
795 int __decode_packet(unsigned char *data, struct resolv_header *h)
797 __decode_header(data, h);
798 return HFIXEDSZ;
800 #endif /* L_decodep */
803 #ifdef L_formquery
805 int __form_query(int id,
806 const char *name,
807 int type,
808 unsigned char *packet,
809 int maxlen) attribute_hidden;
810 int __form_query(int id,
811 const char *name,
812 int type,
813 unsigned char *packet,
814 int maxlen)
816 struct resolv_header h;
817 struct resolv_question q;
818 int i, j;
820 memset(&h, 0, sizeof(h));
821 h.id = id;
822 h.qdcount = 1;
824 q.dotted = (char *) name;
825 q.qtype = type;
826 q.qclass = C_IN; /* CLASS_IN */
828 i = __encode_header(&h, packet, maxlen);
829 if (i < 0)
830 return i;
832 j = __encode_question(&q, packet + i, maxlen - i);
833 if (j < 0)
834 return j;
836 return i + j;
838 #endif /* L_formquery */
839 #endif /* CURRENTLY_UNUSED */
842 #ifdef L_opennameservers
844 # if __BYTE_ORDER == __LITTLE_ENDIAN
845 #define NAMESERVER_PORT_N (__bswap_constant_16(NAMESERVER_PORT))
846 #else
847 #define NAMESERVER_PORT_N NAMESERVER_PORT
848 #endif
850 __UCLIBC_MUTEX_INIT(__resolv_lock, PTHREAD_MUTEX_INITIALIZER);
852 /* Protected by __resolv_lock */
853 void (*__res_sync)(void);
854 /*uint32_t __resolv_opts; */
855 uint8_t __resolv_timeout = RES_TIMEOUT;
856 uint8_t __resolv_attempts = RES_DFLRETRY;
857 unsigned __nameservers;
858 unsigned __searchdomains;
859 sockaddr46_t *__nameserver;
860 char **__searchdomain;
861 #ifdef __UCLIBC_HAS_IPV4__
862 const struct sockaddr_in __local_nameserver = {
863 .sin_family = AF_INET,
864 .sin_port = NAMESERVER_PORT_N,
866 #else
867 const struct sockaddr_in6 __local_nameserver = {
868 .sin6_family = AF_INET6,
869 .sin6_port = NAMESERVER_PORT_N,
871 #endif
873 /* Helpers. Both stop on EOL, if it's '\n', it is converted to NUL first */
874 static char *skip_nospace(char *p)
876 while (*p != '\0' && !isspace(*p)) {
877 if (*p == '\n') {
878 *p = '\0';
879 break;
881 p++;
883 return p;
885 static char *skip_and_NUL_space(char *p)
887 /* NB: '\n' is not isspace! */
888 while (1) {
889 char c = *p;
890 if (c == '\0' || !isspace(c))
891 break;
892 *p = '\0';
893 if (c == '\n' || c == '#')
894 break;
895 p++;
897 return p;
900 /* Must be called under __resolv_lock. */
901 void __open_nameservers(void)
903 static uint32_t resolv_conf_mtime;
905 char szBuffer[MAXLEN_searchdomain];
906 FILE *fp;
907 int i;
908 sockaddr46_t sa;
910 if (!__res_sync) {
911 /* Reread /etc/resolv.conf if it was modified. */
912 struct stat sb;
913 if (stat(_PATH_RESCONF, &sb) != 0)
914 sb.st_mtime = 0;
915 if (resolv_conf_mtime != (uint32_t)sb.st_mtime) {
916 resolv_conf_mtime = sb.st_mtime;
917 __close_nameservers(); /* force config reread */
921 if (__nameservers)
922 goto sync;
924 __resolv_timeout = RES_TIMEOUT;
925 __resolv_attempts = RES_DFLRETRY;
927 fp = fopen(_PATH_RESCONF, "r");
928 #ifdef FALLBACK_TO_CONFIG_RESOLVCONF
929 if (!fp) {
930 /* If we do not have a pre-populated /etc/resolv.conf then
931 try to use the one from /etc/config which exists on numerous
932 systems ranging from some uClinux to IRIX installations and
933 may be the only /etc dir that was mounted rw. */
934 fp = fopen("/etc/config/resolv.conf", "r");
936 #endif
938 if (fp) {
939 while (fgets(szBuffer, sizeof(szBuffer), fp) != NULL) {
940 void *ptr;
941 char *keyword, *p;
943 keyword = p = skip_and_NUL_space(szBuffer);
944 /* skip keyword */
945 p = skip_nospace(p);
946 /* find next word */
947 p = skip_and_NUL_space(p);
949 if (strcmp(keyword, "nameserver") == 0) {
950 /* terminate IP addr */
951 *skip_nospace(p) = '\0';
952 memset(&sa, 0, sizeof(sa));
953 if (0) /* nothing */;
954 #ifdef __UCLIBC_HAS_IPV6__
955 else if (inet_pton(AF_INET6, p, &sa.sa6.sin6_addr) > 0) {
956 sa.sa6.sin6_family = AF_INET6;
957 sa.sa6.sin6_port = htons(NAMESERVER_PORT);
959 #endif
960 #ifdef __UCLIBC_HAS_IPV4__
961 else if (inet_pton(AF_INET, p, &sa.sa4.sin_addr) > 0) {
962 sa.sa4.sin_family = AF_INET;
963 sa.sa4.sin_port = htons(NAMESERVER_PORT);
965 #endif
966 else
967 continue; /* garbage on this line */
968 ptr = realloc(__nameserver, (__nameservers + 1) * sizeof(__nameserver[0]));
969 if (!ptr)
970 continue;
971 __nameserver = ptr;
972 __nameserver[__nameservers++] = sa; /* struct copy */
973 continue;
975 if (strcmp(keyword, "domain") == 0 || strcmp(keyword, "search") == 0) {
976 char *p1;
978 /* free old domains ("last 'domain' or 'search' wins" rule) */
979 while (__searchdomains)
980 free(__searchdomain[--__searchdomains]);
981 /*free(__searchdomain);*/
982 /*__searchdomain = NULL; - not necessary */
983 next_word:
984 /* terminate current word */
985 p1 = skip_nospace(p);
986 /* find next word (maybe) */
987 p1 = skip_and_NUL_space(p1);
988 /* add it */
989 ptr = realloc(__searchdomain, (__searchdomains + 1) * sizeof(__searchdomain[0]));
990 if (!ptr)
991 continue;
992 __searchdomain = ptr;
993 /* NB: strlen(p) <= MAXLEN_searchdomain) because szBuffer[] is smaller */
994 ptr = strdup(p);
995 if (!ptr)
996 continue;
997 DPRINTF("adding search %s\n", (char*)ptr);
998 __searchdomain[__searchdomains++] = (char*)ptr;
999 p = p1;
1000 if (*p)
1001 goto next_word;
1002 continue;
1004 /* if (strcmp(keyword, "sortlist") == 0)... */
1005 if (strcmp(keyword, "options") == 0) {
1006 char *p1;
1007 uint8_t *what;
1009 if (p == NULL || (p1 = strchr(p, ':')) == NULL)
1010 continue;
1011 *p1++ = '\0';
1012 if (strcmp(p, "timeout") == 0)
1013 what = &__resolv_timeout;
1014 else if (strcmp(p, "attempts") == 0)
1015 what = &__resolv_attempts;
1016 else
1017 continue;
1018 *what = atoi(p1);
1019 DPRINTF("option %s:%d\n", p, *what);
1022 fclose(fp);
1024 if (__nameservers == 0) {
1025 /* Have to handle malloc failure! What a mess...
1026 * And it's not only here, we need to be careful
1027 * to never write into __nameserver[0] if it points
1028 * to constant __local_nameserver, or free it. */
1029 __nameserver = malloc(sizeof(__nameserver[0]));
1030 if (__nameserver)
1031 memcpy(__nameserver, &__local_nameserver, sizeof(__local_nameserver));
1032 else
1033 __nameserver = (void*) &__local_nameserver;
1034 __nameservers++;
1036 if (__searchdomains == 0) {
1037 char buf[256];
1038 char *p;
1039 i = gethostname(buf, sizeof(buf) - 1);
1040 buf[sizeof(buf) - 1] = '\0';
1041 if (i == 0 && (p = strchr(buf, '.')) != NULL && p[1]) {
1042 p = strdup(p + 1);
1043 if (!p)
1044 goto err;
1045 __searchdomain = malloc(sizeof(__searchdomain[0]));
1046 if (!__searchdomain) {
1047 free(p);
1048 goto err;
1050 __searchdomain[0] = p;
1051 __searchdomains++;
1052 err: ;
1055 DPRINTF("nameservers = %d\n", __nameservers);
1057 sync:
1058 if (__res_sync)
1059 __res_sync();
1061 #endif /* L_opennameservers */
1064 #ifdef L_closenameservers
1066 /* Must be called under __resolv_lock. */
1067 void __close_nameservers(void)
1069 if (__nameserver != (void*) &__local_nameserver)
1070 free(__nameserver);
1071 __nameserver = NULL;
1072 __nameservers = 0;
1073 while (__searchdomains)
1074 free(__searchdomain[--__searchdomains]);
1075 free(__searchdomain);
1076 __searchdomain = NULL;
1077 /*__searchdomains = 0; - already is */
1079 #endif /* L_closenameservers */
1082 #ifdef L_dnslookup
1084 /* Helpers */
1085 static int __length_question(const unsigned char *data, int maxlen)
1087 const unsigned char *start;
1088 unsigned b;
1090 if (!data)
1091 return -1;
1093 start = data;
1094 while (1) {
1095 if (maxlen <= 0)
1096 return -1;
1097 b = *data++;
1098 if (b == 0)
1099 break;
1100 if ((b & 0xc0) == 0xc0) {
1101 /* It's a "compressed" name. */
1102 data++; /* skip lsb of redirected offset */
1103 maxlen -= 2;
1104 break;
1106 data += b;
1107 maxlen -= (b + 1); /* account for data++ above */
1109 /* Up to here we were skipping encoded name */
1111 /* Account for QTYPE and QCLASS fields */
1112 if (maxlen < 4)
1113 return -1;
1114 return data - start + 2 + 2;
1117 static int __decode_answer(const unsigned char *message, /* packet */
1118 int offset,
1119 int len, /* total packet len */
1120 struct resolv_answer *a)
1122 char temp[256];
1123 int i;
1125 DPRINTF("decode_answer(start): off %d, len %d\n", offset, len);
1126 i = __decode_dotted(message, offset, len, temp, sizeof(temp));
1127 if (i < 0)
1128 return i;
1130 message += offset + i;
1131 len -= i + RRFIXEDSZ + offset;
1132 if (len < 0) {
1133 DPRINTF("decode_answer: off %d, len %d, i %d\n", offset, len, i);
1134 return len;
1137 /* TODO: what if strdup fails? */
1138 a->dotted = strdup(temp);
1139 a->atype = (message[0] << 8) | message[1];
1140 message += 2;
1141 a->aclass = (message[0] << 8) | message[1];
1142 message += 2;
1143 a->ttl = (message[0] << 24) |
1144 (message[1] << 16) | (message[2] << 8) | (message[3] << 0);
1145 message += 4;
1146 a->rdlength = (message[0] << 8) | message[1];
1147 message += 2;
1148 a->rdata = message;
1149 a->rdoffset = offset + i + RRFIXEDSZ;
1151 DPRINTF("i=%d,rdlength=%d\n", i, a->rdlength);
1153 if (len < a->rdlength)
1154 return -1;
1155 return i + RRFIXEDSZ + a->rdlength;
1158 /* On entry:
1159 * a.buf(len) = auxiliary buffer for IP addresses after first one
1160 * a.add_count = how many additional addresses are there already
1161 * outpacket = where to save ptr to raw packet? can be NULL
1162 * On exit:
1163 * ret < 0: error, all other data is not valid
1164 * ret >= 0: length of reply packet
1165 * a.add_count & a.buf: updated
1166 * a.rdlength: length of addresses (4 bytes for IPv4)
1167 * *outpacket: updated (packet is malloced, you need to free it)
1168 * a.rdata: points into *outpacket to 1st IP addr
1169 * NB: don't pass outpacket == NULL if you need to use a.rdata!
1170 * a.atype: type of query?
1171 * a.dotted: which name we _actually_ used. May contain search domains
1172 * appended. (why the filed is called "dotted" I have no idea)
1173 * This is a malloced string. May be NULL because strdup failed.
1175 int __dns_lookup(const char *name,
1176 int type,
1177 unsigned char **outpacket,
1178 struct resolv_answer *a)
1180 /* Protected by __resolv_lock: */
1181 static int last_ns_num = 0;
1182 static uint16_t last_id = 1;
1184 int i, j, fd, rc;
1185 int packet_len;
1186 int name_len;
1187 #ifdef USE_SELECT
1188 struct timeval tv;
1189 fd_set fds;
1190 #else
1191 struct pollfd fds;
1192 #endif
1193 struct resolv_header h;
1194 struct resolv_question q;
1195 struct resolv_answer ma;
1196 bool first_answer = 1;
1197 int retries_left;
1198 unsigned char *packet = malloc(PACKETSZ);
1199 char *lookup;
1200 int variant = -1; /* search domain to append, -1: none */
1201 int local_ns_num = -1; /* Nth server to use */
1202 int local_id = local_id; /* for compiler */
1203 int sdomains = 0;
1204 bool ends_with_dot;
1205 bool contains_dot;
1206 sockaddr46_t sa;
1208 fd = -1;
1209 lookup = NULL;
1210 name_len = strlen(name);
1211 if ((unsigned)name_len >= MAXDNAME - MAXLEN_searchdomain - 2)
1212 goto fail; /* paranoia */
1213 lookup = malloc(name_len + 1/*for '.'*/ + MAXLEN_searchdomain + 1);
1214 if (!packet || !lookup || !name[0])
1215 goto fail;
1216 ends_with_dot = (name[name_len - 1] == '.');
1217 contains_dot = strchr(name, '.') != NULL;
1218 /* no strcpy! paranoia, user might change name[] under us */
1219 memcpy(lookup, name, name_len);
1221 DPRINTF("Looking up type %d answer for '%s'\n", type, name);
1222 retries_left = 0; /* for compiler */
1223 do {
1224 unsigned act_variant;
1225 int pos;
1226 unsigned reply_timeout;
1228 if (fd != -1) {
1229 close(fd);
1230 fd = -1;
1233 /* Mess with globals while under lock */
1234 /* NB: even data *pointed to* by globals may vanish
1235 * outside the locks. We should assume any and all
1236 * globals can completely change between locked
1237 * code regions. OTOH, this is rare, so we don't need
1238 * to handle it "nicely" (do not skip servers,
1239 * search domains, etc), we only need to ensure
1240 * we do not SEGV, use freed+overwritten data
1241 * or do other Really Bad Things. */
1242 __UCLIBC_MUTEX_LOCK(__resolv_lock);
1243 __open_nameservers();
1244 if (type != T_PTR) {
1245 sdomains = __searchdomains;
1247 lookup[name_len] = '\0';
1248 /* For qualified names, act_variant = MAX_UINT, 0, .., sdomains-1
1249 * => Try original name first, then append search domains
1250 * For names without domain, act_variant = 0, 1, .., sdomains
1251 * => Try search domains first, original name last */
1252 act_variant = contains_dot ? variant : variant + 1;
1253 if (act_variant < sdomains) {
1254 /* lookup is name_len + 1 + MAXLEN_searchdomain + 1 long */
1255 /* __searchdomain[] is not bigger than MAXLEN_searchdomain */
1256 lookup[name_len] = '.';
1257 strcpy(&lookup[name_len + 1], __searchdomain[act_variant]);
1259 /* first time? pick starting server etc */
1260 if (local_ns_num < 0) {
1261 local_id = last_id;
1262 /*TODO: implement /etc/resolv.conf's "options rotate"
1263 (a.k.a. RES_ROTATE bit in _res.options)
1264 local_ns_num = 0;
1265 if (_res.options & RES_ROTATE) */
1266 local_ns_num = last_ns_num;
1267 retries_left = __nameservers * __resolv_attempts;
1269 if (local_ns_num >= __nameservers)
1270 local_ns_num = 0;
1271 local_id++;
1272 local_id &= 0xffff;
1273 /* write new values back while still under lock */
1274 last_id = local_id;
1275 last_ns_num = local_ns_num;
1276 /* struct copy */
1277 /* can't just take a pointer, __nameserver[x]
1278 * is not safe to use outside of locks */
1279 sa = __nameserver[local_ns_num];
1280 __UCLIBC_MUTEX_UNLOCK(__resolv_lock);
1282 memset(packet, 0, PACKETSZ);
1283 memset(&h, 0, sizeof(h));
1285 /* encode header */
1286 h.id = local_id;
1287 h.qdcount = 1;
1288 h.rd = 1;
1289 DPRINTF("encoding header\n", h.rd);
1290 i = __encode_header(&h, packet, PACKETSZ);
1291 if (i < 0)
1292 goto fail;
1294 /* encode question */
1295 DPRINTF("lookup name: %s\n", lookup);
1296 q.dotted = lookup;
1297 q.qtype = type;
1298 q.qclass = C_IN; /* CLASS_IN */
1299 j = __encode_question(&q, packet+i, PACKETSZ-i);
1300 if (j < 0)
1301 goto fail;
1302 packet_len = i + j;
1304 /* send packet */
1305 #ifdef DEBUG
1307 const socklen_t plen = sa.sa.sa_family == AF_INET ? INET_ADDRSTRLEN : INET6_ADDRSTRLEN;
1308 char *pbuf = malloc(plen);
1309 if (pbuf == NULL) ;/* nothing */
1310 #ifdef __UCLIBC_HAS_IPV6__
1311 else if (sa.sa.sa_family == AF_INET6)
1312 pbuf = (char*)inet_ntop(AF_INET6, &sa.sa6.sin6_addr, pbuf, plen);
1313 #endif
1314 #ifdef __UCLIBC_HAS_IPV4__
1315 else if (sa.sa.sa_family == AF_INET)
1316 pbuf = (char*)inet_ntop(AF_INET, &sa.sa4.sin_addr, pbuf, plen);
1317 #endif
1318 DPRINTF("On try %d, sending query to %s, port %d\n",
1319 retries_left, pbuf, NAMESERVER_PORT);
1320 free(pbuf);
1322 #endif
1323 fd = socket(sa.sa.sa_family, SOCK_DGRAM, IPPROTO_UDP);
1324 if (fd < 0) /* paranoia */
1325 goto try_next_server;
1326 rc = connect(fd, &sa.sa, sizeof(sa));
1327 if (rc < 0) {
1328 /*if (errno == ENETUNREACH) { */
1329 /* routing error, presume not transient */
1330 goto try_next_server;
1331 /*} */
1332 /*For example, what transient error this can be? Can't think of any */
1333 /* retry */
1334 /*continue; */
1336 DPRINTF("Xmit packet len:%d id:%d qr:%d\n", packet_len, h.id, h.qr);
1337 /* no error check - if it fails, we time out on recv */
1338 send(fd, packet, packet_len, 0);
1340 #ifdef USE_SELECT
1341 reply_timeout = __resolv_timeout;
1342 wait_again:
1343 FD_ZERO(&fds);
1344 FD_SET(fd, &fds);
1345 tv.tv_sec = reply_timeout;
1346 tv.tv_usec = 0;
1347 if (select(fd + 1, &fds, NULL, NULL, &tv) <= 0) {
1348 DPRINTF("Timeout\n");
1349 /* timed out, so retry send and receive
1350 * to next nameserver */
1351 goto try_next_server;
1353 reply_timeout--;
1354 #else /* !USE_SELECT */
1355 reply_timeout = __resolv_timeout * 1000;
1356 wait_again:
1357 fds.fd = fd;
1358 fds.events = POLLIN;
1359 if (poll(&fds, 1, reply_timeout) <= 0) {
1360 DPRINTF("Timeout\n");
1361 /* timed out, so retry send and receive
1362 * to next nameserver */
1363 goto try_next_server;
1365 if (fds.revents & (POLLERR | POLLHUP | POLLNVAL)) {
1366 DPRINTF("Bad event\n");
1367 goto try_next_server;
1369 /*TODO: better timeout accounting?*/
1370 reply_timeout -= 1000;
1371 #endif /* USE_SELECT */
1373 /* vda: a bogus response seen in real world (caused SEGV in uclibc):
1374 * "ping www.google.com" sending AAAA query and getting
1375 * response with one answer... with answer part missing!
1376 * Fixed by thorough checks for not going past the packet's end.
1378 #ifdef DEBUG
1380 static const char test_query[32] = "\0\2\1\0\0\1\0\0\0\0\0\0\3www\6google\3com\0\0\34\0\1";
1381 static const char test_respn[32] = "\0\2\201\200\0\1\0\1\0\0\0\0\3www\6google\3com\0\0\34\0\1";
1382 pos = memcmp(packet + 2, test_query + 2, 30);
1383 packet_len = recv(fd, packet, PACKETSZ, MSG_DONTWAIT);
1384 if (pos == 0) {
1385 packet_len = 32;
1386 memcpy(packet + 2, test_respn + 2, 30);
1389 #else
1390 packet_len = recv(fd, packet, PACKETSZ, MSG_DONTWAIT);
1391 #endif
1393 if (packet_len < HFIXEDSZ) {
1394 /* too short!
1395 * If the peer did shutdown then retry later,
1396 * try next peer on error.
1397 * it's just a bogus packet from somewhere */
1398 bogus_packet:
1399 if (packet_len >= 0 && reply_timeout)
1400 goto wait_again;
1401 goto try_next_server;
1403 __decode_header(packet, &h);
1404 DPRINTF("len:%d id:%d qr:%d\n", packet_len, h.id, h.qr);
1405 if (h.id != local_id || !h.qr) {
1406 /* unsolicited */
1407 goto bogus_packet;
1410 DPRINTF("Got response (i think)!\n");
1411 DPRINTF("qrcount=%d,ancount=%d,nscount=%d,arcount=%d\n",
1412 h.qdcount, h.ancount, h.nscount, h.arcount);
1413 DPRINTF("opcode=%d,aa=%d,tc=%d,rd=%d,ra=%d,rcode=%d\n",
1414 h.opcode, h.aa, h.tc, h.rd, h.ra, h.rcode);
1416 /* bug 660 says we treat negative response as an error
1417 * and retry, which is, eh, an error. :)
1418 * We were incurring long delays because of this. */
1419 if (h.rcode == NXDOMAIN || h.rcode == SERVFAIL) {
1420 /* if possible, try next search domain */
1421 if (!ends_with_dot) {
1422 DPRINTF("variant:%d sdomains:%d\n", variant, sdomains);
1423 if (variant < sdomains - 1) {
1424 /* next search domain */
1425 variant++;
1426 continue;
1428 /* no more search domains to try */
1430 if (h.rcode != SERVFAIL) {
1431 /* dont loop, this is "no such host" situation */
1432 h_errno = HOST_NOT_FOUND;
1433 goto fail1;
1436 /* Insert other non-fatal errors here, which do not warrant
1437 * switching to next nameserver */
1439 /* Strange error, assuming this nameserver is feeling bad */
1440 if (h.rcode != 0)
1441 goto try_next_server;
1443 /* Code below won't work correctly with h.ancount == 0, so... */
1444 if (h.ancount <= 0) {
1445 h_errno = NO_DATA; /* [is this correct code to check for?] */
1446 goto fail1;
1448 pos = HFIXEDSZ;
1449 for (j = 0; j < h.qdcount; j++) {
1450 DPRINTF("Skipping question %d at %d\n", j, pos);
1451 i = __length_question(packet + pos, packet_len - pos);
1452 if (i < 0) {
1453 DPRINTF("Packet'question section "
1454 "is truncated, trying next server\n");
1455 goto try_next_server;
1457 pos += i;
1458 DPRINTF("Length of question %d is %d\n", j, i);
1460 DPRINTF("Decoding answer at pos %d\n", pos);
1462 first_answer = 1;
1463 a->dotted = NULL;
1464 for (j = 0; j < h.ancount; j++) {
1465 i = __decode_answer(packet, pos, packet_len, &ma);
1466 if (i < 0) {
1467 DPRINTF("failed decode %d\n", i);
1468 /* If the message was truncated but we have
1469 * decoded some answers, pretend it's OK */
1470 if (j && h.tc)
1471 break;
1472 goto try_next_server;
1474 pos += i;
1476 if (first_answer) {
1477 ma.buf = a->buf;
1478 ma.buflen = a->buflen;
1479 ma.add_count = a->add_count;
1480 free(a->dotted);
1481 memcpy(a, &ma, sizeof(ma));
1482 if (a->atype != T_SIG && (NULL == a->buf || (type != T_A && type != T_AAAA)))
1483 break;
1484 if (a->atype != type)
1485 continue;
1486 a->add_count = h.ancount - j - 1;
1487 if ((a->rdlength + sizeof(struct in_addr*)) * a->add_count > a->buflen)
1488 break;
1489 a->add_count = 0;
1490 first_answer = 0;
1491 } else {
1492 free(ma.dotted);
1493 if (ma.atype != type)
1494 continue;
1495 if (a->rdlength != ma.rdlength) {
1496 free(a->dotted);
1497 DPRINTF("Answer address len(%u) differs from original(%u)\n",
1498 ma.rdlength, a->rdlength);
1499 goto try_next_server;
1501 memcpy(a->buf + (a->add_count * ma.rdlength), ma.rdata, ma.rdlength);
1502 ++a->add_count;
1506 /* Success! */
1507 DPRINTF("Answer name = |%s|\n", a->dotted);
1508 DPRINTF("Answer type = |%d|\n", a->atype);
1509 if (fd != -1)
1510 close(fd);
1511 if (outpacket)
1512 *outpacket = packet;
1513 else
1514 free(packet);
1515 free(lookup);
1516 return packet_len;
1518 try_next_server:
1519 /* Try next nameserver */
1520 retries_left--;
1521 local_ns_num++;
1522 variant = -1;
1523 } while (retries_left > 0);
1525 fail:
1526 h_errno = NETDB_INTERNAL;
1527 fail1:
1528 if (fd != -1)
1529 close(fd);
1530 free(lookup);
1531 free(packet);
1532 return -1;
1534 #endif /* L_dnslookup */
1537 #ifdef L_read_etc_hosts_r
1539 parser_t * __open_etc_hosts(void)
1541 parser_t *parser;
1542 parser = config_open("/etc/hosts");
1543 #ifdef FALLBACK_TO_CONFIG_RESOLVCONF
1544 if (parser == NULL)
1545 parser = config_open("/etc/config/hosts");
1546 #endif
1547 return parser;
1550 #define MINTOKENS 2 /* ip address + canonical name */
1551 #define MAXTOKENS (MINTOKENS + MAXALIASES)
1552 #define HALISTOFF (sizeof(char*) * (MAXTOKENS + 1)) /* reserve space for list terminator */
1553 #define INADDROFF (HALISTOFF + 2 * sizeof(char*))
1555 int __read_etc_hosts_r(
1556 parser_t * parser,
1557 const char *name,
1558 int type,
1559 enum etc_hosts_action action,
1560 struct hostent *result_buf,
1561 char *buf, size_t buflen,
1562 struct hostent **result,
1563 int *h_errnop)
1565 char **tok = NULL;
1566 struct in_addr *h_addr0 = NULL;
1567 const size_t aliaslen = INADDROFF +
1568 #ifdef __UCLIBC_HAS_IPV6__
1569 sizeof(struct in6_addr)
1570 #else
1571 sizeof(struct in_addr)
1572 #endif
1574 int ret = HOST_NOT_FOUND;
1575 /* make sure pointer is aligned */
1576 int i = ALIGN_BUFFER_OFFSET(buf);
1577 buf += i;
1578 buflen -= i;
1580 *h_errnop = NETDB_INTERNAL;
1581 if (/* (ssize_t)buflen < 0 || */ buflen < aliaslen
1582 || (buflen - aliaslen) < BUFSZ + 1)
1583 return ERANGE;
1584 if (parser == NULL)
1585 parser = __open_etc_hosts();
1586 if (parser == NULL) {
1587 *result = NULL;
1588 return errno;
1590 /* Layout in buf:
1591 * char *alias[MAXTOKENS] = {address, name, aliases...}
1592 * char **h_addr_list[1] = {*in[6]_addr, NULL}
1593 * struct in[6]_addr
1594 * char line_buffer[BUFSZ+];
1596 parser->data = buf;
1597 parser->data_len = aliaslen;
1598 parser->line_len = buflen - aliaslen;
1599 *h_errnop = HOST_NOT_FOUND;
1600 /* <ip>[[:space:]][<aliases>] */
1601 while (config_read(parser, &tok, MAXTOKENS, MINTOKENS, "# \t", PARSE_NORMAL)) {
1602 result_buf->h_aliases = tok+1;
1603 if (action == GETHOSTENT) {
1604 /* Return whatever the next entry happens to be. */
1606 } else if (action == GET_HOSTS_BYADDR) {
1607 if (strcmp(name, *tok) != 0)
1608 continue;
1609 } else { /* GET_HOSTS_BYNAME */
1610 int aliases = 0;
1611 char **alias = tok + 1;
1612 while (aliases < MAXALIASES) {
1613 char *tmp = *(alias+aliases++);
1614 if (tmp && strcasecmp(name, tmp) == 0)
1615 goto found;
1617 continue;
1619 found:
1620 result_buf->h_name = *(result_buf->h_aliases++);
1621 result_buf->h_addr_list = (char**)(buf + HALISTOFF);
1622 *(result_buf->h_addr_list + 1) = '\0';
1623 h_addr0 = (struct in_addr*)(buf + INADDROFF);
1624 result_buf->h_addr = (char*)h_addr0;
1625 if (0) /* nothing */;
1626 #ifdef __UCLIBC_HAS_IPV4__
1627 else if (type == AF_INET
1628 && inet_pton(AF_INET, *tok, h_addr0) > 0) {
1629 DPRINTF("Found INET\n");
1630 result_buf->h_addrtype = AF_INET;
1631 result_buf->h_length = sizeof(struct in_addr);
1632 *result = result_buf;
1633 ret = NETDB_SUCCESS;
1635 #endif
1636 #ifdef __UCLIBC_HAS_IPV6__
1637 #define in6 ((struct in6_addr *)buf)
1638 else if (type == AF_INET6
1639 && inet_pton(AF_INET6, *tok, h_addr0) > 0) {
1640 DPRINTF("Found INET6\n");
1641 result_buf->h_addrtype = AF_INET6;
1642 result_buf->h_length = sizeof(struct in6_addr);
1643 *result = result_buf;
1644 ret = NETDB_SUCCESS;
1646 #endif
1647 else {
1648 /* continue parsing in the hope the user has multiple
1649 * host types listed in the database like so:
1650 * <ipv4 addr> host
1651 * <ipv6 addr> host
1652 * If looking for an IPv6 addr, don't bail when we got the IPv4
1654 DPRINTF("Error: Found host but different address family\n");
1655 /* NB: gethostbyname2_r depends on this feature
1656 * to avoid looking for IPv6 addr of "localhost" etc */
1657 ret = TRY_AGAIN;
1658 continue;
1660 break;
1662 if (action != GETHOSTENT)
1663 config_close(parser);
1664 return ret;
1665 #undef in6
1667 #endif /* L_read_etc_hosts_r */
1670 #ifdef L_get_hosts_byname_r
1672 int __get_hosts_byname_r(const char *name,
1673 int type,
1674 struct hostent *result_buf,
1675 char *buf,
1676 size_t buflen,
1677 struct hostent **result,
1678 int *h_errnop)
1680 return __read_etc_hosts_r(NULL, name, type, GET_HOSTS_BYNAME,
1681 result_buf, buf, buflen, result, h_errnop);
1683 #endif /* L_get_hosts_byname_r */
1686 #ifdef L_get_hosts_byaddr_r
1688 int __get_hosts_byaddr_r(const char *addr,
1689 int len,
1690 int type,
1691 struct hostent *result_buf,
1692 char *buf,
1693 size_t buflen,
1694 struct hostent **result,
1695 int *h_errnop)
1697 #ifndef __UCLIBC_HAS_IPV6__
1698 char ipaddr[INET_ADDRSTRLEN];
1699 #else
1700 char ipaddr[INET6_ADDRSTRLEN];
1701 #endif
1703 switch (type) {
1704 #ifdef __UCLIBC_HAS_IPV4__
1705 case AF_INET:
1706 if (len != sizeof(struct in_addr))
1707 return 0;
1708 break;
1709 #endif
1710 #ifdef __UCLIBC_HAS_IPV6__
1711 case AF_INET6:
1712 if (len != sizeof(struct in6_addr))
1713 return 0;
1714 break;
1715 #endif
1716 default:
1717 return 0;
1720 inet_ntop(type, addr, ipaddr, sizeof(ipaddr));
1722 return __read_etc_hosts_r(NULL, ipaddr, type, GET_HOSTS_BYADDR,
1723 result_buf, buf, buflen, result, h_errnop);
1725 #endif /* L_get_hosts_byaddr_r */
1728 #ifdef L_getnameinfo
1730 int getnameinfo(const struct sockaddr *sa,
1731 socklen_t addrlen,
1732 char *host,
1733 socklen_t hostlen,
1734 char *serv,
1735 socklen_t servlen,
1736 unsigned flags)
1738 int serrno = errno;
1739 bool ok = 0;
1740 struct hostent *hoste = NULL;
1741 char domain[256];
1743 if (flags & ~(NI_NUMERICHOST|NI_NUMERICSERV|NI_NOFQDN|NI_NAMEREQD|NI_DGRAM))
1744 return EAI_BADFLAGS;
1746 if (sa == NULL || addrlen < sizeof(sa_family_t))
1747 return EAI_FAMILY;
1749 if ((flags & NI_NAMEREQD) && host == NULL && serv == NULL)
1750 return EAI_NONAME;
1752 if (sa->sa_family == AF_LOCAL) /* valid */;
1753 #ifdef __UCLIBC_HAS_IPV4__
1754 else if (sa->sa_family == AF_INET) {
1755 if (addrlen < sizeof(struct sockaddr_in))
1756 return EAI_FAMILY;
1758 #endif
1759 #ifdef __UCLIBC_HAS_IPV6__
1760 else if (sa->sa_family == AF_INET6) {
1761 if (addrlen < sizeof(struct sockaddr_in6))
1762 return EAI_FAMILY;
1764 #endif
1765 else
1766 return EAI_FAMILY;
1768 if (host != NULL && hostlen > 0)
1769 switch (sa->sa_family) {
1770 case AF_INET:
1771 #ifdef __UCLIBC_HAS_IPV6__
1772 case AF_INET6:
1773 #endif
1774 if (!(flags & NI_NUMERICHOST)) {
1775 if (0) /* nothing */;
1776 #ifdef __UCLIBC_HAS_IPV6__
1777 else if (sa->sa_family == AF_INET6)
1778 hoste = gethostbyaddr((const void *)
1779 &(((const struct sockaddr_in6 *) sa)->sin6_addr),
1780 sizeof(struct in6_addr), AF_INET6);
1781 #endif
1782 #ifdef __UCLIBC_HAS_IPV4__
1783 else
1784 hoste = gethostbyaddr((const void *)
1785 &(((const struct sockaddr_in *)sa)->sin_addr),
1786 sizeof(struct in_addr), AF_INET);
1787 #endif
1789 if (hoste) {
1790 char *c;
1791 if ((flags & NI_NOFQDN)
1792 && (getdomainname(domain, sizeof(domain)) == 0)
1793 && (c = strstr(hoste->h_name, domain)) != NULL
1794 && (c != hoste->h_name) && (*(--c) == '.')
1796 strncpy(host, hoste->h_name,
1797 MIN(hostlen, (size_t) (c - hoste->h_name)));
1798 host[MIN(hostlen - 1, (size_t) (c - hoste->h_name))] = '\0';
1799 } else {
1800 strncpy(host, hoste->h_name, hostlen);
1802 ok = 1;
1806 if (!ok) {
1807 const char *c = NULL;
1809 if (flags & NI_NAMEREQD) {
1810 errno = serrno;
1811 return EAI_NONAME;
1813 if (0) /* nothing */;
1814 #ifdef __UCLIBC_HAS_IPV6__
1815 else if (sa->sa_family == AF_INET6) {
1816 const struct sockaddr_in6 *sin6p;
1818 sin6p = (const struct sockaddr_in6 *) sa;
1819 c = inet_ntop(AF_INET6,
1820 (const void *) &sin6p->sin6_addr,
1821 host, hostlen);
1822 #if 0
1823 /* Does scope id need to be supported? */
1824 uint32_t scopeid;
1825 scopeid = sin6p->sin6_scope_id;
1826 if (scopeid != 0) {
1827 /* Buffer is >= IFNAMSIZ+1. */
1828 char scopebuf[IFNAMSIZ + 1];
1829 char *scopeptr;
1830 int ni_numericscope = 0;
1831 size_t real_hostlen = strnlen(host, hostlen);
1832 size_t scopelen = 0;
1834 scopebuf[0] = SCOPE_DELIMITER;
1835 scopebuf[1] = '\0';
1836 scopeptr = &scopebuf[1];
1838 if (IN6_IS_ADDR_LINKLOCAL(&sin6p->sin6_addr)
1839 || IN6_IS_ADDR_MC_LINKLOCAL(&sin6p->sin6_addr)) {
1840 if (if_indextoname(scopeid, scopeptr) == NULL)
1841 ++ni_numericscope;
1842 else
1843 scopelen = strlen(scopebuf);
1844 } else {
1845 ++ni_numericscope;
1848 if (ni_numericscope)
1849 scopelen = 1 + snprintf(scopeptr,
1850 (scopebuf
1851 + sizeof scopebuf
1852 - scopeptr),
1853 "%u", scopeid);
1855 if (real_hostlen + scopelen + 1 > hostlen)
1856 return EAI_SYSTEM;
1857 memcpy(host + real_hostlen, scopebuf, scopelen + 1);
1859 #endif
1861 #endif /* __UCLIBC_HAS_IPV6__ */
1862 #if defined __UCLIBC_HAS_IPV4__
1863 else {
1864 c = inet_ntop(AF_INET, (const void *)
1865 &(((const struct sockaddr_in *) sa)->sin_addr),
1866 host, hostlen);
1868 #endif
1869 if (c == NULL) {
1870 errno = serrno;
1871 return EAI_SYSTEM;
1873 ok = 1;
1875 break;
1877 case AF_LOCAL:
1878 if (!(flags & NI_NUMERICHOST)) {
1879 struct utsname utsname;
1881 if (!uname(&utsname)) {
1882 strncpy(host, utsname.nodename, hostlen);
1883 break;
1887 if (flags & NI_NAMEREQD) {
1888 errno = serrno;
1889 return EAI_NONAME;
1892 strncpy(host, "localhost", hostlen);
1893 break;
1894 /* Already checked above
1895 default:
1896 return EAI_FAMILY;
1900 if (serv && (servlen > 0)) {
1901 if (sa->sa_family == AF_LOCAL) {
1902 strncpy(serv, ((const struct sockaddr_un *) sa)->sun_path, servlen);
1903 } else { /* AF_INET || AF_INET6 */
1904 if (!(flags & NI_NUMERICSERV)) {
1905 struct servent *s;
1906 s = getservbyport(((const struct sockaddr_in *) sa)->sin_port,
1907 ((flags & NI_DGRAM) ? "udp" : "tcp"));
1908 if (s) {
1909 strncpy(serv, s->s_name, servlen);
1910 goto DONE;
1913 snprintf(serv, servlen, "%d",
1914 ntohs(((const struct sockaddr_in *) sa)->sin_port));
1917 DONE:
1918 if (host && (hostlen > 0))
1919 host[hostlen-1] = 0;
1920 if (serv && (servlen > 0))
1921 serv[servlen-1] = 0;
1922 errno = serrno;
1923 return 0;
1925 libc_hidden_def(getnameinfo)
1926 #endif /* L_getnameinfo */
1929 #ifdef L_gethostbyname_r
1931 /* Bug 671 says:
1932 * "uClibc resolver's gethostbyname does not return the requested name
1933 * as an alias, but instead returns the canonical name. glibc's
1934 * gethostbyname has a similar bug where it returns the requested name
1935 * with the search domain name appended (to make a FQDN) as an alias,
1936 * but not the original name itself. Both contradict POSIX, which says
1937 * that the name argument passed to gethostbyname must be in the alias list"
1938 * This is fixed now, and we differ from glibc:
1940 * $ ./gethostbyname_uclibc wer.google.com
1941 * h_name:'c13-ss-2-lb.cnet.com'
1942 * h_length:4
1943 * h_addrtype:2 AF_INET
1944 * alias:'wer.google.com' <===
1945 * addr: 0x4174efd8 '216.239.116.65'
1947 * $ ./gethostbyname_glibc wer.google.com
1948 * h_name:'c13-ss-2-lb.cnet.com'
1949 * h_length:4
1950 * h_addrtype:2 AF_INET
1951 * alias:'wer.google.com.com' <===
1952 * addr:'216.239.116.65'
1954 * When examples were run, /etc/resolv.conf contained "search com" line.
1956 int gethostbyname_r(const char *name,
1957 struct hostent *result_buf,
1958 char *buf,
1959 size_t buflen,
1960 struct hostent **result,
1961 int *h_errnop)
1963 struct in_addr **addr_list;
1964 char **alias;
1965 char *alias0;
1966 unsigned char *packet;
1967 struct resolv_answer a;
1968 int i;
1969 int packet_len;
1970 int wrong_af = 0;
1972 *result = NULL;
1973 if (!name)
1974 return EINVAL;
1976 /* do /etc/hosts first */
1978 int old_errno = errno; /* save the old errno and reset errno */
1979 __set_errno(0); /* to check for missing /etc/hosts. */
1980 i = __get_hosts_byname_r(name, AF_INET, result_buf,
1981 buf, buflen, result, h_errnop);
1982 if (i == NETDB_SUCCESS) {
1983 __set_errno(old_errno);
1984 return i;
1986 switch (*h_errnop) {
1987 case HOST_NOT_FOUND:
1988 wrong_af = (i == TRY_AGAIN);
1989 case NO_ADDRESS:
1990 break;
1991 case NETDB_INTERNAL:
1992 if (errno == ENOENT) {
1993 break;
1995 /* else fall through */
1996 default:
1997 return i;
1999 __set_errno(old_errno);
2002 DPRINTF("Nothing found in /etc/hosts\n");
2004 *h_errnop = NETDB_INTERNAL;
2006 /* prepare future h_aliases[0] */
2007 i = strlen(name) + 1;
2008 if ((ssize_t)buflen <= i)
2009 return ERANGE;
2010 memcpy(buf, name, i); /* paranoia: name might change */
2011 alias0 = buf;
2012 buf += i;
2013 buflen -= i;
2014 /* make sure pointer is aligned */
2015 i = ALIGN_BUFFER_OFFSET(buf);
2016 buf += i;
2017 buflen -= i;
2018 /* Layout in buf:
2019 * char *alias[2];
2020 * struct in_addr* addr_list[NN+1];
2021 * struct in_addr* in[NN];
2023 alias = (char **)buf;
2024 buf += sizeof(alias[0]) * 2;
2025 buflen -= sizeof(alias[0]) * 2;
2026 addr_list = (struct in_addr **)buf;
2027 /* buflen may be < 0, must do signed compare */
2028 if ((ssize_t)buflen < 256)
2029 return ERANGE;
2031 /* we store only one "alias" - the name itself */
2032 alias[0] = alias0;
2033 alias[1] = NULL;
2035 /* maybe it is already an address? */
2037 struct in_addr *in = (struct in_addr *)(buf + sizeof(addr_list[0]) * 2);
2038 if (inet_aton(name, in)) {
2039 addr_list[0] = in;
2040 addr_list[1] = NULL;
2041 result_buf->h_name = alias0;
2042 result_buf->h_aliases = alias;
2043 result_buf->h_addrtype = AF_INET;
2044 result_buf->h_length = sizeof(struct in_addr);
2045 result_buf->h_addr_list = (char **) addr_list;
2046 *result = result_buf;
2047 *h_errnop = NETDB_SUCCESS;
2048 return NETDB_SUCCESS;
2052 /* what if /etc/hosts has it but it's not IPv4?
2053 * F.e. "::1 localhost6". We don't do DNS query for such hosts -
2054 * "ping localhost6" should be fast even if DNS server is down! */
2055 if (wrong_af) {
2056 *h_errnop = HOST_NOT_FOUND;
2057 return TRY_AGAIN;
2060 /* talk to DNS servers */
2061 a.buf = buf;
2062 /* take into account that at least one address will be there,
2063 * we'll need space for one in_addr + two addr_list[] elems */
2064 a.buflen = buflen - ((sizeof(addr_list[0]) * 2 + sizeof(struct in_addr)));
2065 a.add_count = 0;
2066 packet_len = __dns_lookup(name, T_A, &packet, &a);
2067 if (packet_len < 0) {
2068 *h_errnop = HOST_NOT_FOUND;
2069 DPRINTF("__dns_lookup returned < 0\n");
2070 return TRY_AGAIN;
2073 if (a.atype == T_A) { /* ADDRESS */
2074 /* we need space for addr_list[] and one IPv4 address */
2075 /* + 1 accounting for 1st addr (it's in a.rdata),
2076 * another + 1 for NULL in last addr_list[]: */
2077 int need_bytes = sizeof(addr_list[0]) * (a.add_count + 1 + 1)
2078 /* for 1st addr (it's in a.rdata): */
2079 + sizeof(struct in_addr);
2080 /* how many bytes will 2nd and following addresses take? */
2081 int ips_len = a.add_count * a.rdlength;
2083 buflen -= (need_bytes + ips_len);
2084 if ((ssize_t)buflen < 0) {
2085 DPRINTF("buffer too small for all addresses\n");
2086 /* *h_errnop = NETDB_INTERNAL; - already is */
2087 i = ERANGE;
2088 goto free_and_ret;
2091 /* if there are additional addresses in buf,
2092 * move them forward so that they are not destroyed */
2093 DPRINTF("a.add_count:%d a.rdlength:%d a.rdata:%p\n", a.add_count, a.rdlength, a.rdata);
2094 memmove(buf + need_bytes, buf, ips_len);
2096 /* 1st address is in a.rdata, insert it */
2097 buf += need_bytes - sizeof(struct in_addr);
2098 memcpy(buf, a.rdata, sizeof(struct in_addr));
2100 /* fill addr_list[] */
2101 for (i = 0; i <= a.add_count; i++) {
2102 addr_list[i] = (struct in_addr*)buf;
2103 buf += sizeof(struct in_addr);
2105 addr_list[i] = NULL;
2107 /* if we have enough space, we can report "better" name
2108 * (it may contain search domains attached by __dns_lookup,
2109 * or CNAME of the host if it is different from the name
2110 * we used to find it) */
2111 if (a.dotted && buflen > strlen(a.dotted)) {
2112 strcpy(buf, a.dotted);
2113 alias0 = buf;
2116 result_buf->h_name = alias0;
2117 result_buf->h_aliases = alias;
2118 result_buf->h_addrtype = AF_INET;
2119 result_buf->h_length = sizeof(struct in_addr);
2120 result_buf->h_addr_list = (char **) addr_list;
2121 *result = result_buf;
2122 *h_errnop = NETDB_SUCCESS;
2123 i = NETDB_SUCCESS;
2124 goto free_and_ret;
2127 *h_errnop = HOST_NOT_FOUND;
2128 __set_h_errno(HOST_NOT_FOUND);
2129 i = TRY_AGAIN;
2131 free_and_ret:
2132 free(a.dotted);
2133 free(packet);
2134 return i;
2136 libc_hidden_def(gethostbyname_r)
2137 #endif /* L_gethostbyname_r */
2140 #ifdef L_gethostbyname2_r
2142 int gethostbyname2_r(const char *name,
2143 int family,
2144 struct hostent *result_buf,
2145 char *buf,
2146 size_t buflen,
2147 struct hostent **result,
2148 int *h_errnop)
2150 #ifndef __UCLIBC_HAS_IPV6__
2151 return family == (AF_INET)
2152 ? gethostbyname_r(name, result_buf, buf, buflen, result, h_errnop)
2153 : HOST_NOT_FOUND;
2154 #else
2155 struct in6_addr **addr_list;
2156 char **alias;
2157 char *alias0;
2158 unsigned char *packet;
2159 struct resolv_answer a;
2160 int i;
2161 int packet_len;
2162 int wrong_af = 0;
2164 if (family == AF_INET)
2165 return gethostbyname_r(name, result_buf, buf, buflen, result, h_errnop);
2167 *result = NULL;
2168 if (family != AF_INET6)
2169 return EINVAL;
2171 if (!name)
2172 return EINVAL;
2174 /* do /etc/hosts first */
2176 int old_errno = errno; /* save the old errno and reset errno */
2177 __set_errno(0); /* to check for missing /etc/hosts. */
2178 i = __get_hosts_byname_r(name, AF_INET6 /*family*/, result_buf,
2179 buf, buflen, result, h_errnop);
2180 if (i == NETDB_SUCCESS) {
2181 __set_errno(old_errno);
2182 return i;
2184 switch (*h_errnop) {
2185 case HOST_NOT_FOUND:
2186 wrong_af = (i == TRY_AGAIN);
2187 case NO_ADDRESS:
2188 break;
2189 case NETDB_INTERNAL:
2190 if (errno == ENOENT) {
2191 break;
2193 /* else fall through */
2194 default:
2195 return i;
2197 __set_errno(old_errno);
2200 DPRINTF("Nothing found in /etc/hosts\n");
2202 *h_errnop = NETDB_INTERNAL;
2204 /* prepare future h_aliases[0] */
2205 i = strlen(name) + 1;
2206 if ((ssize_t)buflen <= i)
2207 return ERANGE;
2208 memcpy(buf, name, i); /* paranoia: name might change */
2209 alias0 = buf;
2210 buf += i;
2211 buflen -= i;
2212 /* make sure pointer is aligned */
2213 i = ALIGN_BUFFER_OFFSET(buf);
2214 buf += i;
2215 buflen -= i;
2216 /* Layout in buf:
2217 * char *alias[2];
2218 * struct in6_addr* addr_list[NN+1];
2219 * struct in6_addr* in[NN];
2221 alias = (char **)buf;
2222 buf += sizeof(alias[0]) * 2;
2223 buflen -= sizeof(alias[0]) * 2;
2224 addr_list = (struct in6_addr **)buf;
2225 /* buflen may be < 0, must do signed compare */
2226 if ((ssize_t)buflen < 256)
2227 return ERANGE;
2229 /* we store only one "alias" - the name itself */
2230 alias[0] = alias0;
2231 alias[1] = NULL;
2233 /* maybe it is already an address? */
2235 struct in6_addr *in = (struct in6_addr *)(buf + sizeof(addr_list[0]) * 2);
2236 if (inet_pton(AF_INET6, name, in)) {
2237 addr_list[0] = in;
2238 addr_list[1] = NULL;
2239 result_buf->h_name = alias0;
2240 result_buf->h_aliases = alias;
2241 result_buf->h_addrtype = AF_INET6;
2242 result_buf->h_length = sizeof(struct in6_addr);
2243 result_buf->h_addr_list = (char **) addr_list;
2244 *result = result_buf;
2245 *h_errnop = NETDB_SUCCESS;
2246 return NETDB_SUCCESS;
2250 /* what if /etc/hosts has it but it's not IPv6?
2251 * F.e. "127.0.0.1 localhost". We don't do DNS query for such hosts -
2252 * "ping localhost" should be fast even if DNS server is down! */
2253 if (wrong_af) {
2254 *h_errnop = HOST_NOT_FOUND;
2255 return TRY_AGAIN;
2258 /* talk to DNS servers */
2259 a.buf = buf;
2260 /* take into account that at least one address will be there,
2261 * we'll need space of one in6_addr + two addr_list[] elems */
2262 a.buflen = buflen - ((sizeof(addr_list[0]) * 2 + sizeof(struct in6_addr)));
2263 a.add_count = 0;
2264 packet_len = __dns_lookup(name, T_AAAA, &packet, &a);
2265 if (packet_len < 0) {
2266 *h_errnop = HOST_NOT_FOUND;
2267 DPRINTF("__dns_lookup returned < 0\n");
2268 return TRY_AGAIN;
2271 if (a.atype == T_AAAA) { /* ADDRESS */
2272 /* we need space for addr_list[] and one IPv6 address */
2273 /* + 1 accounting for 1st addr (it's in a.rdata),
2274 * another + 1 for NULL in last addr_list[]: */
2275 int need_bytes = sizeof(addr_list[0]) * (a.add_count + 1 + 1)
2276 /* for 1st addr (it's in a.rdata): */
2277 + sizeof(struct in6_addr);
2278 /* how many bytes will 2nd and following addresses take? */
2279 int ips_len = a.add_count * a.rdlength;
2281 buflen -= (need_bytes + ips_len);
2282 if ((ssize_t)buflen < 0) {
2283 DPRINTF("buffer too small for all addresses\n");
2284 /* *h_errnop = NETDB_INTERNAL; - already is */
2285 i = ERANGE;
2286 goto free_and_ret;
2289 /* if there are additional addresses in buf,
2290 * move them forward so that they are not destroyed */
2291 DPRINTF("a.add_count:%d a.rdlength:%d a.rdata:%p\n", a.add_count, a.rdlength, a.rdata);
2292 memmove(buf + need_bytes, buf, ips_len);
2294 /* 1st address is in a.rdata, insert it */
2295 buf += need_bytes - sizeof(struct in6_addr);
2296 memcpy(buf, a.rdata, sizeof(struct in6_addr));
2298 /* fill addr_list[] */
2299 for (i = 0; i <= a.add_count; i++) {
2300 addr_list[i] = (struct in6_addr*)buf;
2301 buf += sizeof(struct in6_addr);
2303 addr_list[i] = NULL;
2305 /* if we have enough space, we can report "better" name
2306 * (it may contain search domains attached by __dns_lookup,
2307 * or CNAME of the host if it is different from the name
2308 * we used to find it) */
2309 if (a.dotted && buflen > strlen(a.dotted)) {
2310 strcpy(buf, a.dotted);
2311 alias0 = buf;
2314 result_buf->h_name = alias0;
2315 result_buf->h_aliases = alias;
2316 result_buf->h_addrtype = AF_INET6;
2317 result_buf->h_length = sizeof(struct in6_addr);
2318 result_buf->h_addr_list = (char **) addr_list;
2319 *result = result_buf;
2320 *h_errnop = NETDB_SUCCESS;
2321 i = NETDB_SUCCESS;
2322 goto free_and_ret;
2325 *h_errnop = HOST_NOT_FOUND;
2326 __set_h_errno(HOST_NOT_FOUND);
2327 i = TRY_AGAIN;
2329 free_and_ret:
2330 free(a.dotted);
2331 free(packet);
2332 return i;
2333 #endif /* __UCLIBC_HAS_IPV6__ */
2335 libc_hidden_def(gethostbyname2_r)
2336 #endif /* L_gethostbyname2_r */
2339 #ifdef L_gethostbyaddr_r
2341 int gethostbyaddr_r(const void *addr, socklen_t addrlen,
2342 int type,
2343 struct hostent *result_buf,
2344 char *buf, size_t buflen,
2345 struct hostent **result,
2346 int *h_errnop)
2349 struct in_addr *in;
2350 struct in_addr **addr_list;
2351 char **alias;
2352 unsigned char *packet;
2353 struct resolv_answer a;
2354 int i;
2355 int packet_len;
2356 int nest = 0;
2358 *result = NULL;
2359 if (!addr)
2360 return EINVAL;
2362 switch (type) {
2363 #ifdef __UCLIBC_HAS_IPV4__
2364 case AF_INET:
2365 if (addrlen != sizeof(struct in_addr))
2366 return EINVAL;
2367 break;
2368 #endif
2369 #ifdef __UCLIBC_HAS_IPV6__
2370 case AF_INET6:
2371 if (addrlen != sizeof(struct in6_addr))
2372 return EINVAL;
2373 break;
2374 #endif
2375 default:
2376 return EINVAL;
2379 /* do /etc/hosts first */
2380 i = __get_hosts_byaddr_r(addr, addrlen, type, result_buf,
2381 buf, buflen, result, h_errnop);
2382 if (i == 0)
2383 return i;
2384 switch (*h_errnop) {
2385 case HOST_NOT_FOUND:
2386 case NO_ADDRESS:
2387 break;
2388 default:
2389 return i;
2392 *h_errnop = NETDB_INTERNAL;
2394 /* make sure pointer is aligned */
2395 i = ALIGN_BUFFER_OFFSET(buf);
2396 buf += i;
2397 buflen -= i;
2398 /* Layout in buf:
2399 * char *alias[ALIAS_DIM];
2400 * struct in[6]_addr* addr_list[2];
2401 * struct in[6]_addr in;
2402 * char scratch_buffer[256+];
2404 #define in6 ((struct in6_addr *)in)
2405 alias = (char **)buf;
2406 addr_list = (struct in_addr**)buf;
2407 buf += sizeof(*addr_list) * 2;
2408 buflen -= sizeof(*addr_list) * 2;
2409 in = (struct in_addr*)buf;
2410 #ifndef __UCLIBC_HAS_IPV6__
2411 buf += sizeof(*in);
2412 buflen -= sizeof(*in);
2413 if (addrlen > sizeof(*in))
2414 return ERANGE;
2415 #else
2416 buf += sizeof(*in6);
2417 buflen -= sizeof(*in6);
2418 if (addrlen > sizeof(*in6))
2419 return ERANGE;
2420 #endif
2421 if ((ssize_t)buflen < 256)
2422 return ERANGE;
2423 alias[0] = buf;
2424 alias[1] = NULL;
2425 addr_list[0] = in;
2426 addr_list[1] = NULL;
2427 memcpy(in, addr, addrlen);
2429 if (0) /* nothing */;
2430 #ifdef __UCLIBC_HAS_IPV4__
2431 else IF_HAS_BOTH(if (type == AF_INET)) {
2432 unsigned char *tp = (unsigned char *)addr;
2433 sprintf(buf, "%u.%u.%u.%u.in-addr.arpa",
2434 tp[3], tp[2], tp[1], tp[0]);
2436 #endif
2437 #ifdef __UCLIBC_HAS_IPV6__
2438 else {
2439 char *dst = buf;
2440 unsigned char *tp = (unsigned char *)addr + addrlen - 1;
2441 do {
2442 dst += sprintf(dst, "%x.%x.", tp[0] & 0xf, tp[0] >> 4);
2443 tp--;
2444 } while (tp >= (unsigned char *)addr);
2445 strcpy(dst, "ip6.arpa");
2447 #endif
2449 memset(&a, '\0', sizeof(a));
2450 for (;;) {
2451 /* Hmm why we memset(a) to zeros only once? */
2452 packet_len = __dns_lookup(buf, T_PTR, &packet, &a);
2453 if (packet_len < 0) {
2454 *h_errnop = HOST_NOT_FOUND;
2455 return TRY_AGAIN;
2458 strncpy(buf, a.dotted, buflen);
2459 free(a.dotted);
2460 if (a.atype != T_CNAME)
2461 break;
2463 DPRINTF("Got a CNAME in gethostbyaddr()\n");
2464 if (++nest > MAX_RECURSE) {
2465 *h_errnop = NO_RECOVERY;
2466 return -1;
2468 /* Decode CNAME into buf, feed it to __dns_lookup() again */
2469 i = __decode_dotted(packet, a.rdoffset, packet_len, buf, buflen);
2470 free(packet);
2471 if (i < 0) {
2472 *h_errnop = NO_RECOVERY;
2473 return -1;
2477 if (a.atype == T_PTR) { /* ADDRESS */
2478 i = __decode_dotted(packet, a.rdoffset, packet_len, buf, buflen);
2479 free(packet);
2480 result_buf->h_name = buf;
2481 result_buf->h_addrtype = type;
2482 result_buf->h_length = addrlen;
2483 result_buf->h_addr_list = (char **) addr_list;
2484 result_buf->h_aliases = alias;
2485 *result = result_buf;
2486 *h_errnop = NETDB_SUCCESS;
2487 return NETDB_SUCCESS;
2490 free(packet);
2491 *h_errnop = NO_ADDRESS;
2492 return TRY_AGAIN;
2493 #undef in6
2495 libc_hidden_def(gethostbyaddr_r)
2496 #endif /* L_gethostbyaddr_r */
2499 #ifdef L_gethostent_r
2501 __UCLIBC_MUTEX_STATIC(mylock, PTHREAD_MUTEX_INITIALIZER);
2503 static parser_t *hostp = NULL;
2504 static smallint host_stayopen;
2506 void endhostent_unlocked(void)
2508 if (hostp) {
2509 config_close(hostp);
2510 hostp = NULL;
2512 host_stayopen = 0;
2514 void endhostent(void)
2516 __UCLIBC_MUTEX_LOCK(mylock);
2517 endhostent_unlocked();
2518 __UCLIBC_MUTEX_UNLOCK(mylock);
2521 void sethostent(int stay_open)
2523 __UCLIBC_MUTEX_LOCK(mylock);
2524 if (stay_open)
2525 host_stayopen = 1;
2526 __UCLIBC_MUTEX_UNLOCK(mylock);
2529 int gethostent_r(struct hostent *result_buf, char *buf, size_t buflen,
2530 struct hostent **result, int *h_errnop)
2532 int ret;
2534 __UCLIBC_MUTEX_LOCK(mylock);
2535 if (hostp == NULL) {
2536 hostp = __open_etc_hosts();
2537 if (hostp == NULL) {
2538 *result = NULL;
2539 ret = TRY_AGAIN;
2540 goto DONE;
2544 ret = __read_etc_hosts_r(hostp, NULL, AF_INET, GETHOSTENT,
2545 result_buf, buf, buflen, result, h_errnop);
2546 if (!host_stayopen)
2547 endhostent_unlocked();
2548 DONE:
2549 __UCLIBC_MUTEX_UNLOCK(mylock);
2550 return ret;
2552 libc_hidden_def(gethostent_r)
2553 #endif /* L_gethostent_r */
2556 #ifndef __UCLIBC_HAS_IPV6__
2557 #define GETXX_BUFSZ (sizeof(struct in_addr) + sizeof(struct in_addr *) * 2 + \
2558 /*sizeof(char *)*ALIAS_DIM */+ 384/*namebuffer*/ + 32/* margin */)
2559 #else
2560 #define GETXX_BUFSZ (sizeof(struct in6_addr) + sizeof(struct in6_addr *) * 2 + \
2561 /*sizeof(char *)*ALIAS_DIM */+ 384/*namebuffer*/ + 32/* margin */)
2562 #endif /* __UCLIBC_HAS_IPV6__ */
2564 #define __INIT_GETXX_BUF(sz) \
2565 if (buf == NULL) \
2566 buf = (char *)__uc_malloc((sz));
2568 #ifdef L_gethostent
2570 struct hostent *gethostent(void)
2572 static struct hostent hoste;
2573 static char *buf = NULL;
2574 struct hostent *host = NULL;
2575 #ifndef __UCLIBC_HAS_IPV6__
2576 #define HOSTENT_BUFSZ (sizeof(struct in_addr) + sizeof(struct in_addr *) * 2 + \
2577 sizeof(char *)*ALIAS_DIM + BUFSZ /*namebuffer*/ + 2 /* margin */)
2578 #else
2579 #define HOSTENT_BUFSZ (sizeof(struct in6_addr) + sizeof(struct in6_addr *) * 2 + \
2580 sizeof(char *)*ALIAS_DIM + BUFSZ /*namebuffer*/ + 2 /* margin */)
2581 #endif /* __UCLIBC_HAS_IPV6__ */
2583 __INIT_GETXX_BUF(HOSTENT_BUFSZ);
2584 gethostent_r(&hoste, buf, HOSTENT_BUFSZ, &host, &h_errno);
2585 return host;
2587 #undef HOSTENT_BUFSZ
2588 #endif /* L_gethostent */
2591 #ifdef L_gethostbyname2
2593 struct hostent *gethostbyname2(const char *name, int family)
2595 static struct hostent hoste;
2596 static char *buf = NULL;
2597 struct hostent *hp;
2599 __INIT_GETXX_BUF(GETXX_BUFSZ);
2600 #ifndef __UCLIBC_HAS_IPV6__
2601 if (family != AF_INET)
2602 return (struct hostent*)NULL;
2603 gethostbyname_r(name, &hoste, buf, GETXX_BUFSZ, &hp, &h_errno);
2604 #else
2605 gethostbyname2_r(name, family, &hoste, buf, GETXX_BUFSZ, &hp, &h_errno);
2606 #endif /* __UCLIBC_HAS_IPV6__ */
2608 return hp;
2610 libc_hidden_def(gethostbyname2)
2611 #endif /* L_gethostbyname2 */
2614 #ifdef L_gethostbyname
2616 struct hostent *gethostbyname(const char *name)
2618 return gethostbyname2(name, AF_INET);
2620 libc_hidden_def(gethostbyname)
2621 #endif /* L_gethostbyname */
2624 #ifdef L_gethostbyaddr
2626 struct hostent *gethostbyaddr(const void *addr, socklen_t len, int type)
2628 static struct hostent hoste;
2629 static char *buf = NULL;
2630 struct hostent *hp;
2632 __INIT_GETXX_BUF(GETXX_BUFSZ);
2633 gethostbyaddr_r(addr, len, type, &hoste, buf, GETXX_BUFSZ, &hp, &h_errno);
2634 return hp;
2636 libc_hidden_def(gethostbyaddr)
2637 #endif /* L_gethostbyaddr */
2640 #ifdef L_res_comp
2643 * Expand compressed domain name 'comp_dn' to full domain name.
2644 * 'msg' is a pointer to the begining of the message,
2645 * 'eomorig' points to the first location after the message,
2646 * 'exp_dn' is a pointer to a buffer of size 'length' for the result.
2647 * Return size of compressed name or -1 if there was an error.
2649 int dn_expand(const u_char *msg, const u_char *eom, const u_char *src,
2650 char *dst, int dstsiz)
2652 int n = ns_name_uncompress(msg, eom, src, dst, (size_t)dstsiz);
2654 if (n > 0 && dst[0] == '.')
2655 dst[0] = '\0';
2656 return n;
2658 libc_hidden_def(dn_expand)
2661 * Pack domain name 'exp_dn' in presentation form into 'comp_dn'.
2662 * Return the size of the compressed name or -1.
2663 * 'length' is the size of the array pointed to by 'comp_dn'.
2666 dn_comp(const char *src, u_char *dst, int dstsiz,
2667 u_char **dnptrs, u_char **lastdnptr)
2669 return ns_name_compress(src, dst, (size_t) dstsiz,
2670 (const u_char **) dnptrs,
2671 (const u_char **) lastdnptr);
2673 libc_hidden_def(dn_comp)
2674 #endif /* L_res_comp */
2677 #ifdef L_ns_name
2679 /* Thinking in noninternationalized USASCII (per the DNS spec),
2680 * is this character visible and not a space when printed ?
2682 static int printable(int ch)
2684 return (ch > 0x20 && ch < 0x7f);
2686 /* Thinking in noninternationalized USASCII (per the DNS spec),
2687 * is this characted special ("in need of quoting") ?
2689 static int special(int ch)
2691 switch (ch) {
2692 case 0x22: /* '"' */
2693 case 0x2E: /* '.' */
2694 case 0x3B: /* ';' */
2695 case 0x5C: /* '\\' */
2696 /* Special modifiers in zone files. */
2697 case 0x40: /* '@' */
2698 case 0x24: /* '$' */
2699 return 1;
2700 default:
2701 return 0;
2706 * ns_name_uncompress(msg, eom, src, dst, dstsiz)
2707 * Expand compressed domain name to presentation format.
2708 * return:
2709 * Number of bytes read out of `src', or -1 (with errno set).
2710 * note:
2711 * Root domain returns as "." not "".
2713 int ns_name_uncompress(const u_char *msg, const u_char *eom,
2714 const u_char *src, char *dst, size_t dstsiz)
2716 u_char tmp[NS_MAXCDNAME];
2717 int n;
2719 n = ns_name_unpack(msg, eom, src, tmp, sizeof tmp);
2720 if (n == -1)
2721 return -1;
2722 if (ns_name_ntop(tmp, dst, dstsiz) == -1)
2723 return -1;
2724 return n;
2726 libc_hidden_def(ns_name_uncompress)
2729 * ns_name_ntop(src, dst, dstsiz)
2730 * Convert an encoded domain name to printable ascii as per RFC1035.
2731 * return:
2732 * Number of bytes written to buffer, or -1 (with errno set)
2733 * notes:
2734 * The root is returned as "."
2735 * All other domains are returned in non absolute form
2737 int ns_name_ntop(const u_char *src, char *dst, size_t dstsiz)
2739 const u_char *cp;
2740 char *dn, *eom;
2741 u_char c;
2742 u_int n;
2744 cp = src;
2745 dn = dst;
2746 eom = dst + dstsiz;
2748 while ((n = *cp++) != 0) {
2749 if ((n & NS_CMPRSFLGS) != 0) {
2750 /* Some kind of compression pointer. */
2751 __set_errno(EMSGSIZE);
2752 return -1;
2754 if (dn != dst) {
2755 if (dn >= eom) {
2756 __set_errno(EMSGSIZE);
2757 return -1;
2759 *dn++ = '.';
2761 if (dn + n >= eom) {
2762 __set_errno(EMSGSIZE);
2763 return -1;
2765 for (; n > 0; n--) {
2766 c = *cp++;
2767 if (special(c)) {
2768 if (dn + 1 >= eom) {
2769 __set_errno(EMSGSIZE);
2770 return -1;
2772 *dn++ = '\\';
2773 *dn++ = (char)c;
2774 } else if (!printable(c)) {
2775 if (dn + 3 >= eom) {
2776 __set_errno(EMSGSIZE);
2777 return -1;
2779 *dn++ = '\\';
2780 *dn++ = "0123456789"[c / 100];
2781 c = c % 100;
2782 *dn++ = "0123456789"[c / 10];
2783 *dn++ = "0123456789"[c % 10];
2784 } else {
2785 if (dn >= eom) {
2786 __set_errno(EMSGSIZE);
2787 return -1;
2789 *dn++ = (char)c;
2793 if (dn == dst) {
2794 if (dn >= eom) {
2795 __set_errno(EMSGSIZE);
2796 return -1;
2798 *dn++ = '.';
2800 if (dn >= eom) {
2801 __set_errno(EMSGSIZE);
2802 return -1;
2804 *dn++ = '\0';
2805 return (dn - dst);
2807 libc_hidden_def(ns_name_ntop)
2809 static int encode_bitstring(const char **bp, const char *end,
2810 unsigned char **labelp,
2811 unsigned char ** dst,
2812 unsigned const char *eom)
2814 int afterslash = 0;
2815 const char *cp = *bp;
2816 unsigned char *tp;
2817 const char *beg_blen;
2818 int value = 0, count = 0, tbcount = 0, blen = 0;
2820 beg_blen = NULL;
2822 /* a bitstring must contain at least 2 characters */
2823 if (end - cp < 2)
2824 return EINVAL;
2826 /* XXX: currently, only hex strings are supported */
2827 if (*cp++ != 'x')
2828 return EINVAL;
2829 if (!isxdigit((unsigned char) *cp)) /*%< reject '\[x/BLEN]' */
2830 return EINVAL;
2832 for (tp = *dst + 1; cp < end && tp < eom; cp++) {
2833 unsigned char c = *cp;
2835 switch (c) {
2836 case ']': /*%< end of the bitstring */
2837 if (afterslash) {
2838 char *end_blen;
2839 if (beg_blen == NULL)
2840 return EINVAL;
2841 blen = (int)strtol(beg_blen, &end_blen, 10);
2842 if (*end_blen != ']')
2843 return EINVAL;
2845 if (count)
2846 *tp++ = ((value << 4) & 0xff);
2847 cp++; /*%< skip ']' */
2848 goto done;
2849 case '/':
2850 afterslash = 1;
2851 break;
2852 default:
2853 if (afterslash) {
2854 if (!__isdigit_char(c))
2855 return EINVAL;
2856 if (beg_blen == NULL) {
2857 if (c == '0') {
2858 /* blen never begings with 0 */
2859 return EINVAL;
2861 beg_blen = cp;
2863 } else {
2864 if (!__isdigit_char(c)) {
2865 c = c | 0x20; /* lowercase */
2866 c = c - 'a';
2867 if (c > 5) /* not a-f? */
2868 return EINVAL;
2869 c += 10 + '0';
2871 value <<= 4;
2872 value += (c - '0');
2873 count += 4;
2874 tbcount += 4;
2875 if (tbcount > 256)
2876 return EINVAL;
2877 if (count == 8) {
2878 *tp++ = value;
2879 count = 0;
2882 break;
2885 done:
2886 if (cp >= end || tp >= eom)
2887 return EMSGSIZE;
2890 * bit length validation:
2891 * If a <length> is present, the number of digits in the <bit-data>
2892 * MUST be just sufficient to contain the number of bits specified
2893 * by the <length>. If there are insignificant bits in a final
2894 * hexadecimal or octal digit, they MUST be zero.
2895 * RFC2673, Section 3.2.
2897 if (blen > 0) {
2898 int traillen;
2900 if (((blen + 3) & ~3) != tbcount)
2901 return EINVAL;
2902 traillen = tbcount - blen; /*%< between 0 and 3 */
2903 if (((value << (8 - traillen)) & 0xff) != 0)
2904 return EINVAL;
2906 else
2907 blen = tbcount;
2908 if (blen == 256)
2909 blen = 0;
2911 /* encode the type and the significant bit fields */
2912 **labelp = DNS_LABELTYPE_BITSTRING;
2913 **dst = blen;
2915 *bp = cp;
2916 *dst = tp;
2918 return 0;
2921 int ns_name_pton(const char *src, u_char *dst, size_t dstsiz)
2923 static const char digits[] = "0123456789";
2924 u_char *label, *bp, *eom;
2925 int c, n, escaped, e = 0;
2926 char *cp;
2928 escaped = 0;
2929 bp = dst;
2930 eom = dst + dstsiz;
2931 label = bp++;
2933 while ((c = *src++) != 0) {
2934 if (escaped) {
2935 if (c == '[') { /*%< start a bit string label */
2936 cp = strchr(src, ']');
2937 if (cp == NULL) {
2938 errno = EINVAL; /*%< ??? */
2939 return -1;
2941 e = encode_bitstring(&src, cp + 2,
2942 &label, &bp, eom);
2943 if (e != 0) {
2944 errno = e;
2945 return -1;
2947 escaped = 0;
2948 label = bp++;
2949 c = *src++;
2950 if (c == '\0')
2951 goto done;
2952 if (c != '.') {
2953 errno = EINVAL;
2954 return -1;
2956 continue;
2958 cp = strchr(digits, c);
2959 if (cp != NULL) {
2960 n = (cp - digits) * 100;
2961 c = *src++;
2962 if (c == '\0')
2963 goto ret_EMSGSIZE;
2964 cp = strchr(digits, c);
2965 if (cp == NULL)
2966 goto ret_EMSGSIZE;
2967 n += (cp - digits) * 10;
2968 c = *src++;
2969 if (c == '\0')
2970 goto ret_EMSGSIZE;
2971 cp = strchr(digits, c);
2972 if (cp == NULL)
2973 goto ret_EMSGSIZE;
2974 n += (cp - digits);
2975 if (n > 255)
2976 goto ret_EMSGSIZE;
2977 c = n;
2979 escaped = 0;
2980 } else if (c == '\\') {
2981 escaped = 1;
2982 continue;
2983 } else if (c == '.') {
2984 c = (bp - label - 1);
2985 if ((c & NS_CMPRSFLGS) != 0) { /*%< Label too big. */
2986 goto ret_EMSGSIZE;
2988 if (label >= eom) {
2989 goto ret_EMSGSIZE;
2991 *label = c;
2992 /* Fully qualified ? */
2993 if (*src == '\0') {
2994 if (c != 0) {
2995 if (bp >= eom) {
2996 goto ret_EMSGSIZE;
2998 *bp++ = '\0';
3000 if ((bp - dst) > MAXCDNAME) {
3001 goto ret_EMSGSIZE;
3004 return 1;
3006 if (c == 0 || *src == '.') {
3007 goto ret_EMSGSIZE;
3009 label = bp++;
3010 continue;
3012 if (bp >= eom) {
3013 goto ret_EMSGSIZE;
3015 *bp++ = (u_char)c;
3017 c = (bp - label - 1);
3018 if ((c & NS_CMPRSFLGS) != 0) { /*%< Label too big. */
3019 goto ret_EMSGSIZE;
3021 done:
3022 if (label >= eom) {
3023 goto ret_EMSGSIZE;
3025 *label = c;
3026 if (c != 0) {
3027 if (bp >= eom) {
3028 goto ret_EMSGSIZE;
3030 *bp++ = 0;
3032 if ((bp - dst) > MAXCDNAME) { /*%< src too big */
3033 goto ret_EMSGSIZE;
3036 return 0;
3038 ret_EMSGSIZE:
3039 errno = EMSGSIZE;
3040 return -1;
3042 libc_hidden_def(ns_name_pton)
3045 * ns_name_unpack(msg, eom, src, dst, dstsiz)
3046 * Unpack a domain name from a message, source may be compressed.
3047 * return:
3048 * -1 if it fails, or consumed octets if it succeeds.
3050 int ns_name_unpack(const u_char *msg, const u_char *eom, const u_char *src,
3051 u_char *dst, size_t dstsiz)
3053 const u_char *srcp, *dstlim;
3054 u_char *dstp;
3055 int n, len, checked;
3057 len = -1;
3058 checked = 0;
3059 dstp = dst;
3060 srcp = src;
3061 dstlim = dst + dstsiz;
3062 if (srcp < msg || srcp >= eom) {
3063 __set_errno(EMSGSIZE);
3064 return -1;
3066 /* Fetch next label in domain name. */
3067 while ((n = *srcp++) != 0) {
3068 /* Check for indirection. */
3069 switch (n & NS_CMPRSFLGS) {
3070 case 0:
3071 /* Limit checks. */
3072 if (dstp + n + 1 >= dstlim || srcp + n >= eom) {
3073 __set_errno(EMSGSIZE);
3074 return -1;
3076 checked += n + 1;
3077 *dstp++ = n;
3078 memcpy(dstp, srcp, n);
3079 dstp += n;
3080 srcp += n;
3081 break;
3083 case NS_CMPRSFLGS:
3084 if (srcp >= eom) {
3085 __set_errno(EMSGSIZE);
3086 return -1;
3088 if (len < 0)
3089 len = srcp - src + 1;
3090 srcp = msg + (((n & 0x3f) << 8) | (*srcp & 0xff));
3091 if (srcp < msg || srcp >= eom) { /* Out of range. */
3092 __set_errno(EMSGSIZE);
3093 return -1;
3095 checked += 2;
3097 * Check for loops in the compressed name;
3098 * if we've looked at the whole message,
3099 * there must be a loop.
3101 if (checked >= eom - msg) {
3102 __set_errno(EMSGSIZE);
3103 return -1;
3105 break;
3107 default:
3108 __set_errno(EMSGSIZE);
3109 return -1; /* flag error */
3112 *dstp = '\0';
3113 if (len < 0)
3114 len = srcp - src;
3115 return len;
3117 libc_hidden_def(ns_name_unpack)
3119 static int labellen(const unsigned char *lp)
3121 unsigned bitlen;
3122 unsigned char l = *lp;
3124 if ((l & NS_CMPRSFLGS) == NS_CMPRSFLGS) {
3125 /* should be avoided by the caller */
3126 return -1;
3129 if ((l & NS_CMPRSFLGS) == NS_TYPE_ELT) {
3130 if (l == DNS_LABELTYPE_BITSTRING) {
3131 bitlen = lp[1];
3132 if (bitlen == 0)
3133 bitlen = 256;
3134 return ((bitlen + 7 ) / 8 + 1);
3137 return -1; /*%< unknwon ELT */
3140 return l;
3143 static int mklower(int ch)
3145 if (ch >= 0x41 && ch <= 0x5A)
3146 return (ch + 0x20);
3148 return ch;
3151 static int dn_find(const unsigned char *domain,
3152 const unsigned char *msg,
3153 const unsigned char * const *dnptrs,
3154 const unsigned char * const *lastdnptr)
3156 const unsigned char *dn, *cp, *sp;
3157 const unsigned char * const *cpp;
3158 u_int n;
3160 for (cpp = dnptrs; cpp < lastdnptr; cpp++) {
3161 sp = *cpp;
3163 * terminate search on:
3164 * root label
3165 * compression pointer
3166 * unusable offset
3168 while (*sp != 0 && (*sp & NS_CMPRSFLGS) == 0 &&
3169 (sp - msg) < 0x4000) {
3170 dn = domain;
3171 cp = sp;
3173 while ((n = *cp++) != 0) {
3175 * check for indirection
3177 switch (n & NS_CMPRSFLGS) {
3178 case 0: /*%< normal case, n == len */
3179 n = labellen(cp - 1); /*%< XXX */
3180 if (n != *dn++)
3181 goto next;
3183 for (; n > 0; n--)
3184 if (mklower(*dn++) !=
3185 mklower(*cp++))
3186 goto next;
3187 /* Is next root for both ? */
3188 if (*dn == '\0' && *cp == '\0')
3189 return (sp - msg);
3190 if (*dn)
3191 continue;
3192 goto next;
3193 case NS_CMPRSFLGS: /*%< indirection */
3194 cp = msg + (((n & 0x3f) << 8) | *cp);
3195 break;
3197 default: /*%< illegal type */
3198 errno = EMSGSIZE;
3199 return -1;
3202 next:
3203 sp += *sp + 1;
3207 errno = ENOENT;
3208 return -1;
3211 int ns_name_pack(const unsigned char *src,
3212 unsigned char *dst, int dstsiz,
3213 const unsigned char **dnptrs,
3214 const unsigned char **lastdnptr)
3216 unsigned char *dstp;
3217 const unsigned char **cpp, **lpp, *eob, *msg;
3218 const unsigned char *srcp;
3219 int n, l, first = 1;
3221 srcp = src;
3222 dstp = dst;
3223 eob = dstp + dstsiz;
3224 lpp = cpp = NULL;
3226 if (dnptrs != NULL) {
3227 msg = *dnptrs++;
3228 if (msg != NULL) {
3229 for (cpp = dnptrs; *cpp != NULL; cpp++)
3230 continue;
3232 lpp = cpp; /*%< end of list to search */
3234 } else {
3235 msg = NULL;
3238 /* make sure the domain we are about to add is legal */
3239 l = 0;
3240 do {
3241 int l0;
3243 n = *srcp;
3244 if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) {
3245 errno = EMSGSIZE;
3246 return -1;
3249 l0 = labellen(srcp);
3250 if (l0 < 0) {
3251 errno = EINVAL;
3252 return -1;
3255 l += l0 + 1;
3256 if (l > MAXCDNAME) {
3257 errno = EMSGSIZE;
3258 return -1;
3261 srcp += l0 + 1;
3262 } while (n != 0);
3264 /* from here on we need to reset compression pointer array on error */
3265 srcp = src;
3267 do {
3268 /* Look to see if we can use pointers. */
3269 n = *srcp;
3271 if (n != 0 && msg != NULL) {
3272 l = dn_find(srcp, msg, (const unsigned char * const *) dnptrs,
3273 (const unsigned char * const *) lpp);
3274 if (l >= 0) {
3275 if (dstp + 1 >= eob) {
3276 goto cleanup;
3279 *dstp++ = ((u_int32_t)l >> 8) | NS_CMPRSFLGS;
3280 *dstp++ = l % 256;
3281 return (dstp - dst);
3284 /* Not found, save it. */
3285 if (lastdnptr != NULL && cpp < lastdnptr - 1 &&
3286 (dstp - msg) < 0x4000 && first) {
3287 *cpp++ = dstp;
3288 *cpp = NULL;
3289 first = 0;
3293 /* copy label to buffer */
3294 if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) {
3295 /* Should not happen. */
3296 goto cleanup;
3299 n = labellen(srcp);
3300 if (dstp + 1 + n >= eob) {
3301 goto cleanup;
3304 memcpy(dstp, srcp, (size_t)(n + 1));
3305 srcp += n + 1;
3306 dstp += n + 1;
3307 } while (n != 0);
3309 if (dstp > eob) {
3310 cleanup:
3311 if (msg != NULL)
3312 *lpp = NULL;
3314 errno = EMSGSIZE;
3315 return -1;
3318 return dstp - dst;
3320 libc_hidden_def(ns_name_pack)
3322 int ns_name_compress(const char *src,
3323 unsigned char *dst, size_t dstsiz,
3324 const unsigned char **dnptrs,
3325 const unsigned char **lastdnptr)
3327 unsigned char tmp[NS_MAXCDNAME];
3329 if (ns_name_pton(src, tmp, sizeof(tmp)) == -1)
3330 return -1;
3332 return ns_name_pack(tmp, dst, dstsiz, dnptrs, lastdnptr);
3334 libc_hidden_def(ns_name_compress)
3336 int ns_name_skip(const unsigned char **ptrptr,
3337 const unsigned char *eom)
3339 const unsigned char *cp;
3340 u_int n;
3341 int l;
3343 cp = *ptrptr;
3344 while (cp < eom && (n = *cp++) != 0) {
3345 /* Check for indirection. */
3346 switch (n & NS_CMPRSFLGS) {
3347 case 0: /*%< normal case, n == len */
3348 cp += n;
3349 continue;
3350 case NS_TYPE_ELT: /*%< EDNS0 extended label */
3351 l = labellen(cp - 1);
3352 if (l < 0) {
3353 errno = EMSGSIZE; /*%< XXX */
3354 return -1;
3356 cp += l;
3357 continue;
3358 case NS_CMPRSFLGS: /*%< indirection */
3359 cp++;
3360 break;
3361 default: /*%< illegal type */
3362 errno = EMSGSIZE;
3363 return -1;
3366 break;
3369 if (cp > eom) {
3370 errno = EMSGSIZE;
3371 return -1;
3374 *ptrptr = cp;
3376 return 0;
3378 libc_hidden_def(ns_name_skip)
3380 int dn_skipname(const unsigned char *ptr, const unsigned char *eom)
3382 const unsigned char *saveptr = ptr;
3384 if (ns_name_skip(&ptr, eom) == -1)
3385 return -1;
3387 return ptr - saveptr;
3389 libc_hidden_def(dn_skipname)
3390 #endif /* L_ns_name */
3393 #ifdef L_res_init
3395 /* Will be called under __resolv_lock. */
3396 static void res_sync_func(void)
3398 struct __res_state *rp = &(_res);
3399 int n;
3401 /* If we didn't get malloc failure earlier... */
3402 if (__nameserver != (void*) &__local_nameserver) {
3403 /* TODO:
3404 * if (__nameservers < rp->nscount) - try to grow __nameserver[]?
3406 #ifdef __UCLIBC_HAS_IPV6__
3407 if (__nameservers > rp->_u._ext.nscount)
3408 __nameservers = rp->_u._ext.nscount;
3409 n = __nameservers;
3410 while (--n >= 0)
3411 __nameserver[n].sa6 = *rp->_u._ext.nsaddrs[n]; /* struct copy */
3412 #else /* IPv4 only */
3413 if (__nameservers > rp->nscount)
3414 __nameservers = rp->nscount;
3415 n = __nameservers;
3416 while (--n >= 0)
3417 __nameserver[n].sa4 = rp->nsaddr_list[n]; /* struct copy */
3418 #endif
3420 __resolv_timeout = rp->retrans ? : RES_TIMEOUT;
3421 __resolv_attempts = rp->retry ? : RES_DFLRETRY;
3422 /* Extend and comment what program is known
3423 * to use which _res.XXX member(s).
3425 __resolv_opts = rp->options;
3430 /* has to be called under __resolv_lock */
3431 static int
3432 __res_vinit(res_state rp, int preinit)
3434 int i, n, options, retrans, retry, ndots;
3435 #ifdef __UCLIBC_HAS_IPV6__
3436 int m = 0;
3437 #endif
3439 __close_nameservers();
3440 __open_nameservers();
3442 if (preinit) {
3443 options = rp->options;
3444 retrans = rp->retrans;
3445 retry = rp->retry;
3446 ndots = rp->ndots;
3449 memset(rp, 0, sizeof(*rp));
3451 if (!preinit) {
3452 rp->options = RES_DEFAULT;
3453 rp->retrans = RES_TIMEOUT;
3454 rp->retry = RES_DFLRETRY;
3455 rp->ndots = 1;
3456 } else {
3457 rp->options = options;
3458 rp->retrans = retrans;
3459 rp->retry = retry;
3460 rp->ndots = ndots;
3463 #ifdef __UCLIBC_HAS_COMPAT_RES_STATE__
3464 /* Was: "rp->id = random();" but:
3465 * - random() pulls in largish static buffers
3466 * - isn't actually random unless, say, srandom(time(NULL)) was called
3467 * - is not used by uclibc anyway :)
3469 /* rp->id = 0; - memset did it */
3470 #endif
3471 #ifdef __UCLIBC_HAS_EXTRA_COMPAT_RES_STATE__
3472 rp->_vcsock = -1;
3473 #endif
3475 n = __searchdomains;
3476 if (n > ARRAY_SIZE(rp->dnsrch))
3477 n = ARRAY_SIZE(rp->dnsrch);
3478 for (i = 0; i < n; i++)
3479 rp->dnsrch[i] = __searchdomain[i];
3481 /* copy nameservers' addresses */
3482 i = 0;
3483 #ifdef __UCLIBC_HAS_IPV4__
3484 n = 0;
3485 while (n < ARRAY_SIZE(rp->nsaddr_list) && i < __nameservers) {
3486 if (__nameserver[i].sa.sa_family == AF_INET) {
3487 rp->nsaddr_list[n] = __nameserver[i].sa4; /* struct copy */
3488 #ifdef __UCLIBC_HAS_IPV6__
3489 if (m < ARRAY_SIZE(rp->_u._ext.nsaddrs)) {
3490 rp->_u._ext.nsaddrs[m] = (void*) &rp->nsaddr_list[n];
3491 m++;
3493 #endif
3494 n++;
3496 #ifdef __UCLIBC_HAS_IPV6__
3497 if (__nameserver[i].sa.sa_family == AF_INET6
3498 && m < ARRAY_SIZE(rp->_u._ext.nsaddrs)
3500 struct sockaddr_in6 *sa6 = malloc(sizeof(*sa6));
3501 if (sa6) {
3502 *sa6 = __nameserver[i].sa6; /* struct copy */
3503 rp->_u._ext.nsaddrs[m] = sa6;
3504 m++;
3507 #endif
3508 i++;
3510 rp->nscount = n;
3511 #ifdef __UCLIBC_HAS_IPV6__
3512 rp->_u._ext.nscount = m;
3513 #endif
3515 #else /* IPv6 only */
3516 while (m < ARRAY_SIZE(rp->_u._ext.nsaddrs) && i < __nameservers) {
3517 struct sockaddr_in6 *sa6 = malloc(sizeof(*sa6));
3518 if (sa6) {
3519 *sa6 = __nameserver[i].sa6; /* struct copy */
3520 rp->_u._ext.nsaddrs[m] = sa6;
3521 m++;
3523 i++;
3525 rp->_u._ext.nscount = m;
3526 #endif
3528 rp->options |= RES_INIT;
3530 return 0;
3533 static unsigned int
3534 res_randomid(void)
3536 return 0xffff & getpid();
3539 /* Our res_init never fails (always returns 0) */
3541 res_init(void)
3544 * These three fields used to be statically initialized. This made
3545 * it hard to use this code in a shared library. It is necessary,
3546 * now that we're doing dynamic initialization here, that we preserve
3547 * the old semantics: if an application modifies one of these three
3548 * fields of _res before res_init() is called, res_init() will not
3549 * alter them. Of course, if an application is setting them to
3550 * _zero_ before calling res_init(), hoping to override what used
3551 * to be the static default, we can't detect it and unexpected results
3552 * will follow. Zero for any of these fields would make no sense,
3553 * so one can safely assume that the applications were already getting
3554 * unexpected results.
3556 * _res.options is tricky since some apps were known to diddle the bits
3557 * before res_init() was first called. We can't replicate that semantic
3558 * with dynamic initialization (they may have turned bits off that are
3559 * set in RES_DEFAULT). Our solution is to declare such applications
3560 * "broken". They could fool us by setting RES_INIT but none do (yet).
3563 __UCLIBC_MUTEX_LOCK(__resolv_lock);
3565 if (!_res.retrans)
3566 _res.retrans = RES_TIMEOUT;
3567 if (!_res.retry)
3568 _res.retry = 4;
3569 if (!(_res.options & RES_INIT))
3570 _res.options = RES_DEFAULT;
3573 * This one used to initialize implicitly to zero, so unless the app
3574 * has set it to something in particular, we can randomize it now.
3576 if (!_res.id)
3577 _res.id = res_randomid();
3579 __res_sync = NULL;
3580 __res_vinit(&_res, 1);
3581 __res_sync = res_sync_func;
3583 __UCLIBC_MUTEX_UNLOCK(__resolv_lock);
3585 return 0;
3587 libc_hidden_def(res_init)
3589 static void
3590 __res_iclose(res_state statp)
3592 struct __res_state * rp = statp;
3593 __UCLIBC_MUTEX_LOCK(__resolv_lock);
3594 if (rp == NULL)
3595 rp = __res_state();
3596 __close_nameservers();
3597 __res_sync = NULL;
3598 #ifdef __UCLIBC_HAS_IPV6__
3600 char *p1 = (char*) &(rp->nsaddr_list[0]);
3601 unsigned int m = 0;
3602 /* free nsaddrs[m] if they do not point to nsaddr_list[x] */
3603 while (m < ARRAY_SIZE(rp->_u._ext.nsaddrs)) {
3604 char *p2 = (char*)(rp->_u._ext.nsaddrs[m++]);
3605 if (p2 < p1 || (p2 - p1) > (signed)sizeof(rp->nsaddr_list))
3606 free(p2);
3609 #endif
3610 memset(rp, 0, sizeof(struct __res_state));
3611 __UCLIBC_MUTEX_UNLOCK(__resolv_lock);
3615 * This routine is for closing the socket if a virtual circuit is used and
3616 * the program wants to close it. This provides support for endhostent()
3617 * which expects to close the socket.
3619 * This routine is not expected to be user visible.
3622 void
3623 res_nclose(res_state statp)
3625 __res_iclose(statp);
3628 #ifdef __UCLIBC_HAS_BSD_RES_CLOSE__
3629 void res_close(void)
3631 __res_iclose(NULL);
3633 #endif
3635 /* This needs to be after the use of _res in res_init, above. */
3636 #undef _res
3638 #ifndef __UCLIBC_HAS_THREADS__
3639 /* The resolver state for use by single-threaded programs.
3640 This differs from plain `struct __res_state _res;' in that it doesn't
3641 create a common definition, but a plain symbol that resides in .bss,
3642 which can have an alias. */
3643 struct __res_state _res __attribute__((section (".bss")));
3644 struct __res_state *__resp = &_res;
3645 #else /* __UCLIBC_HAS_THREADS__ */
3646 struct __res_state _res __attribute__((section (".bss"))) attribute_hidden;
3648 # if defined __UCLIBC_HAS_TLS__
3649 # undef __resp
3650 __thread struct __res_state *__resp = &_res;
3651 extern __thread struct __res_state *__libc_resp
3652 __attribute__ ((alias ("__resp"))) attribute_hidden attribute_tls_model_ie;
3653 # else
3654 # undef __resp
3655 struct __res_state *__resp = &_res;
3656 # endif
3657 #endif /* !__UCLIBC_HAS_THREADS__ */
3660 * Set up default settings. If the configuration file exist, the values
3661 * there will have precedence. Otherwise, the server address is set to
3662 * INADDR_ANY and the default domain name comes from the gethostname().
3664 * An interrim version of this code (BIND 4.9, pre-4.4BSD) used 127.0.0.1
3665 * rather than INADDR_ANY ("0.0.0.0") as the default name server address
3666 * since it was noted that INADDR_ANY actually meant ``the first interface
3667 * you "ifconfig"'d at boot time'' and if this was a SLIP or PPP interface,
3668 * it had to be "up" in order for you to reach your own name server. It
3669 * was later decided that since the recommended practice is to always
3670 * install local static routes through 127.0.0.1 for all your network
3671 * interfaces, that we could solve this problem without a code change.
3673 * The configuration file should always be used, since it is the only way
3674 * to specify a default domain. If you are running a server on your local
3675 * machine, you should say "nameserver 0.0.0.0" or "nameserver 127.0.0.1"
3676 * in the configuration file.
3678 * Return 0 if completes successfully, -1 on error
3681 res_ninit(res_state statp)
3683 int ret;
3684 __UCLIBC_MUTEX_LOCK(__resolv_lock);
3685 ret = __res_vinit(statp, 0);
3686 __UCLIBC_MUTEX_UNLOCK(__resolv_lock);
3687 return ret;
3690 #endif /* L_res_init */
3692 #ifdef L_res_state
3693 # if defined __UCLIBC_HAS_TLS__
3694 struct __res_state *
3695 __res_state (void)
3697 return __resp;
3699 # else
3700 # undef _res
3701 extern struct __res_state _res;
3703 /* When threaded, _res may be a per-thread variable. */
3704 struct __res_state *
3705 weak_const_function
3706 __res_state (void)
3708 return &_res;
3710 # endif
3712 #endif /* L_res_state */
3715 #ifdef L_res_query
3717 int res_query(const char *dname, int class, int type,
3718 unsigned char *answer, int anslen)
3720 int i;
3721 unsigned char *packet = NULL;
3722 struct resolv_answer a;
3724 if (!dname || class != 1 /* CLASS_IN */) {
3725 h_errno = NO_RECOVERY;
3726 return -1;
3729 memset(&a, '\0', sizeof(a));
3730 i = __dns_lookup(dname, type, &packet, &a);
3732 if (i < 0) {
3733 if (!h_errno) /* TODO: can this ever happen? */
3734 h_errno = TRY_AGAIN;
3735 return -1;
3738 free(a.dotted);
3740 if (i > anslen)
3741 i = anslen;
3742 memcpy(answer, packet, i);
3744 free(packet);
3745 return i;
3747 libc_hidden_def(res_query)
3750 * Formulate a normal query, send, and retrieve answer in supplied buffer.
3751 * Return the size of the response on success, -1 on error.
3752 * If enabled, implement search rules until answer or unrecoverable failure
3753 * is detected. Error code, if any, is left in h_errno.
3755 #define __TRAILING_DOT (1<<0)
3756 #define __GOT_NODATA (1<<1)
3757 #define __GOT_SERVFAIL (1<<2)
3758 #define __TRIED_AS_IS (1<<3)
3759 int res_search(const char *name, int class, int type, u_char *answer,
3760 int anslen)
3762 const char *cp;
3763 char **domain;
3764 HEADER *hp = (HEADER *)(void *)answer;
3765 unsigned dots;
3766 unsigned state;
3767 int ret, saved_herrno;
3768 uint32_t _res_options;
3769 unsigned _res_ndots;
3770 char **_res_dnsrch;
3772 if (!name || !answer) {
3773 h_errno = NETDB_INTERNAL;
3774 return -1;
3777 again:
3778 __UCLIBC_MUTEX_LOCK(__resolv_lock);
3779 _res_options = _res.options;
3780 _res_ndots = _res.ndots;
3781 _res_dnsrch = _res.dnsrch;
3782 __UCLIBC_MUTEX_UNLOCK(__resolv_lock);
3783 if (!(_res_options & RES_INIT)) {
3784 res_init(); /* our res_init never fails */
3785 goto again;
3788 state = 0;
3789 errno = 0;
3790 h_errno = HOST_NOT_FOUND; /* default, if we never query */
3791 dots = 0;
3792 for (cp = name; *cp; cp++)
3793 dots += (*cp == '.');
3795 if (cp > name && *--cp == '.')
3796 state |= __TRAILING_DOT;
3799 * If there are dots in the name already, let's just give it a try
3800 * 'as is'. The threshold can be set with the "ndots" option.
3802 saved_herrno = -1;
3803 if (dots >= _res_ndots) {
3804 ret = res_querydomain(name, NULL, class, type, answer, anslen);
3805 if (ret > 0)
3806 return ret;
3807 saved_herrno = h_errno;
3808 state |= __TRIED_AS_IS;
3812 * We do at least one level of search if
3813 * - there is no dot and RES_DEFNAME is set, or
3814 * - there is at least one dot, there is no trailing dot,
3815 * and RES_DNSRCH is set.
3817 if ((!dots && (_res_options & RES_DEFNAMES))
3818 || (dots && !(state & __TRAILING_DOT) && (_res_options & RES_DNSRCH))
3820 bool done = 0;
3822 for (domain = _res_dnsrch; *domain && !done; domain++) {
3824 ret = res_querydomain(name, *domain, class, type,
3825 answer, anslen);
3826 if (ret > 0)
3827 return ret;
3830 * If no server present, give up.
3831 * If name isn't found in this domain,
3832 * keep trying higher domains in the search list
3833 * (if that's enabled).
3834 * On a NO_DATA error, keep trying, otherwise
3835 * a wildcard entry of another type could keep us
3836 * from finding this entry higher in the domain.
3837 * If we get some other error (negative answer or
3838 * server failure), then stop searching up,
3839 * but try the input name below in case it's
3840 * fully-qualified.
3842 if (errno == ECONNREFUSED) {
3843 h_errno = TRY_AGAIN;
3844 return -1;
3847 switch (h_errno) {
3848 case NO_DATA:
3849 state |= __GOT_NODATA;
3850 /* FALLTHROUGH */
3851 case HOST_NOT_FOUND:
3852 /* keep trying */
3853 break;
3854 case TRY_AGAIN:
3855 if (hp->rcode == SERVFAIL) {
3856 /* try next search element, if any */
3857 state |= __GOT_SERVFAIL;
3858 break;
3860 /* FALLTHROUGH */
3861 default:
3862 /* anything else implies that we're done */
3863 done = 1;
3866 * if we got here for some reason other than DNSRCH,
3867 * we only wanted one iteration of the loop, so stop.
3869 if (!(_res_options & RES_DNSRCH))
3870 done = 1;
3875 * if we have not already tried the name "as is", do that now.
3876 * note that we do this regardless of how many dots were in the
3877 * name or whether it ends with a dot.
3879 if (!(state & __TRIED_AS_IS)) {
3880 ret = res_querydomain(name, NULL, class, type, answer, anslen);
3881 if (ret > 0)
3882 return ret;
3886 * if we got here, we didn't satisfy the search.
3887 * if we did an initial full query, return that query's h_errno
3888 * (note that we wouldn't be here if that query had succeeded).
3889 * else if we ever got a nodata, send that back as the reason.
3890 * else send back meaningless h_errno, that being the one from
3891 * the last DNSRCH we did.
3893 if (saved_herrno != -1)
3894 h_errno = saved_herrno;
3895 else if (state & __GOT_NODATA)
3896 h_errno = NO_DATA;
3897 else if (state & __GOT_SERVFAIL)
3898 h_errno = TRY_AGAIN;
3899 return -1;
3901 #undef __TRAILING_DOT
3902 #undef __GOT_NODATA
3903 #undef __GOT_SERVFAIL
3904 #undef __TRIED_AS_IS
3906 * Perform a call on res_query on the concatenation of name and domain,
3907 * removing a trailing dot from name if domain is NULL.
3909 int res_querydomain(const char *name, const char *domain, int class, int type,
3910 u_char *answer, int anslen)
3912 char nbuf[MAXDNAME];
3913 const char *longname = nbuf;
3914 size_t n, d;
3915 #ifdef DEBUG
3916 uint32_t _res_options;
3917 #endif
3919 if (!name || !answer) {
3920 h_errno = NETDB_INTERNAL;
3921 return -1;
3924 #ifdef DEBUG
3925 again:
3926 __UCLIBC_MUTEX_LOCK(__resolv_lock);
3927 _res_options = _res.options;
3928 __UCLIBC_MUTEX_UNLOCK(__resolv_lock);
3929 if (!(_res_options & RES_INIT)) {
3930 res_init(); /* our res_init never fails */
3931 goto again;
3933 if (_res_options & RES_DEBUG)
3934 printf(";; res_querydomain(%s, %s, %d, %d)\n",
3935 name, (domain ? domain : "<Nil>"), class, type);
3936 #endif
3937 if (domain == NULL) {
3939 * Check for trailing '.';
3940 * copy without '.' if present.
3942 n = strlen(name);
3943 if (n + 1 > sizeof(nbuf)) {
3944 h_errno = NO_RECOVERY;
3945 return -1;
3947 if (n > 0 && name[--n] == '.') {
3948 strncpy(nbuf, name, n);
3949 nbuf[n] = '\0';
3950 } else
3951 longname = name;
3952 } else {
3953 n = strlen(name);
3954 d = strlen(domain);
3955 if (n + 1 + d + 1 > sizeof(nbuf)) {
3956 h_errno = NO_RECOVERY;
3957 return -1;
3959 snprintf(nbuf, sizeof(nbuf), "%s.%s", name, domain);
3961 return res_query(longname, class, type, answer, anslen);
3963 libc_hidden_def(res_querydomain)
3964 #endif /* L_res_query */
3966 #ifdef L_ns_netint
3967 unsigned int ns_get16(const unsigned char *src)
3969 unsigned int dst;
3970 NS_GET16(dst, src);
3971 return dst;
3974 unsigned long ns_get32(const unsigned char *src)
3976 unsigned long dst;
3977 NS_GET32(dst, src);
3978 return dst;
3981 void ns_put16(unsigned int src, unsigned char *dst)
3983 NS_PUT16(src, dst);
3986 void ns_put32(unsigned long src, unsigned char *dst)
3988 NS_PUT32(src, dst);
3990 #endif /* L_ns_netint */
3992 #ifdef L_ns_parse
3993 /* These need to be in the same order as the nres.h:ns_flag enum. */
3994 struct _ns_flagdata { unsigned short mask, shift; };
3995 static const struct _ns_flagdata _ns_flagdata[16] = {
3996 { 0x8000, 15 }, /*%< qr. */
3997 { 0x7800, 11 }, /*%< opcode. */
3998 { 0x0400, 10 }, /*%< aa. */
3999 { 0x0200, 9 }, /*%< tc. */
4000 { 0x0100, 8 }, /*%< rd. */
4001 { 0x0080, 7 }, /*%< ra. */
4002 { 0x0040, 6 }, /*%< z. */
4003 { 0x0020, 5 }, /*%< ad. */
4004 { 0x0010, 4 }, /*%< cd. */
4005 { 0x000f, 0 }, /*%< rcode. */
4006 { 0x0000, 0 }, /*%< expansion (1/6). */
4007 { 0x0000, 0 }, /*%< expansion (2/6). */
4008 { 0x0000, 0 }, /*%< expansion (3/6). */
4009 { 0x0000, 0 }, /*%< expansion (4/6). */
4010 { 0x0000, 0 }, /*%< expansion (5/6). */
4011 { 0x0000, 0 }, /*%< expansion (6/6). */
4014 static void setsection(ns_msg *msg, ns_sect sect)
4016 msg->_sect = sect;
4017 if (sect == ns_s_max) {
4018 msg->_rrnum = -1;
4019 msg->_ptr = NULL;
4020 } else {
4021 msg->_rrnum = 0;
4022 msg->_ptr = msg->_sections[(int)sect];
4026 int ns_skiprr(const unsigned char *ptr,
4027 const unsigned char *eom,
4028 ns_sect section, int count)
4030 const u_char *optr = ptr;
4032 for (; count > 0; count--) {
4033 int b, rdlength;
4035 b = dn_skipname(ptr, eom);
4036 if (b < 0) {
4037 errno = EMSGSIZE;
4038 return -1;
4041 ptr += b/*Name*/ + NS_INT16SZ/*Type*/ + NS_INT16SZ/*Class*/;
4042 if (section != ns_s_qd) {
4043 if (ptr + NS_INT32SZ + NS_INT16SZ > eom) {
4044 errno = EMSGSIZE;
4045 return -1;
4048 ptr += NS_INT32SZ/*TTL*/;
4049 NS_GET16(rdlength, ptr);
4050 ptr += rdlength/*RData*/;
4054 if (ptr > eom) {
4055 errno = EMSGSIZE;
4056 return -1;
4059 return ptr - optr;
4061 libc_hidden_def(ns_skiprr)
4064 ns_initparse(const unsigned char *msg, int msglen, ns_msg *handle)
4066 const u_char *eom = msg + msglen;
4067 int i;
4069 handle->_msg = msg;
4070 handle->_eom = eom;
4071 if (msg + NS_INT16SZ > eom) {
4072 errno = EMSGSIZE;
4073 return -1;
4076 NS_GET16(handle->_id, msg);
4077 if (msg + NS_INT16SZ > eom) {
4078 errno = EMSGSIZE;
4079 return -1;
4082 NS_GET16(handle->_flags, msg);
4083 for (i = 0; i < ns_s_max; i++) {
4084 if (msg + NS_INT16SZ > eom) {
4085 errno = EMSGSIZE;
4086 return -1;
4089 NS_GET16(handle->_counts[i], msg);
4091 for (i = 0; i < ns_s_max; i++)
4092 if (handle->_counts[i] == 0)
4093 handle->_sections[i] = NULL;
4094 else {
4095 int b = ns_skiprr(msg, eom, (ns_sect)i,
4096 handle->_counts[i]);
4098 if (b < 0)
4099 return -1;
4100 handle->_sections[i] = msg;
4101 msg += b;
4104 if (msg != eom) {
4105 errno = EMSGSIZE;
4106 return -1;
4109 setsection(handle, ns_s_max);
4110 return 0;
4114 ns_parserr(ns_msg *handle, ns_sect section, int rrnum, ns_rr *rr)
4116 int b;
4117 int tmp;
4119 /* Make section right. */
4120 tmp = section;
4121 if (tmp < 0 || section >= ns_s_max) {
4122 errno = ENODEV;
4123 return -1;
4126 if (section != handle->_sect)
4127 setsection(handle, section);
4129 /* Make rrnum right. */
4130 if (rrnum == -1)
4131 rrnum = handle->_rrnum;
4132 if (rrnum < 0 || rrnum >= handle->_counts[(int)section]) {
4133 errno = ENODEV;
4134 return -1;
4136 if (rrnum < handle->_rrnum)
4137 setsection(handle, section);
4138 if (rrnum > handle->_rrnum) {
4139 b = ns_skiprr(handle->_ptr, handle->_eom, section,
4140 rrnum - handle->_rrnum);
4142 if (b < 0)
4143 return -1;
4144 handle->_ptr += b;
4145 handle->_rrnum = rrnum;
4148 /* Do the parse. */
4149 b = dn_expand(handle->_msg, handle->_eom,
4150 handle->_ptr, rr->name, NS_MAXDNAME);
4151 if (b < 0)
4152 return -1;
4153 handle->_ptr += b;
4154 if (handle->_ptr + NS_INT16SZ + NS_INT16SZ > handle->_eom) {
4155 errno = EMSGSIZE;
4156 return -1;
4158 NS_GET16(rr->type, handle->_ptr);
4159 NS_GET16(rr->rr_class, handle->_ptr);
4160 if (section == ns_s_qd) {
4161 rr->ttl = 0;
4162 rr->rdlength = 0;
4163 rr->rdata = NULL;
4164 } else {
4165 if (handle->_ptr + NS_INT32SZ + NS_INT16SZ > handle->_eom) {
4166 errno = EMSGSIZE;
4167 return -1;
4169 NS_GET32(rr->ttl, handle->_ptr);
4170 NS_GET16(rr->rdlength, handle->_ptr);
4171 if (handle->_ptr + rr->rdlength > handle->_eom) {
4172 errno = EMSGSIZE;
4173 return -1;
4175 rr->rdata = handle->_ptr;
4176 handle->_ptr += rr->rdlength;
4178 if (++handle->_rrnum > handle->_counts[(int)section])
4179 setsection(handle, (ns_sect)((int)section + 1));
4181 return 0;
4184 int ns_msg_getflag(ns_msg handle, int flag)
4186 return ((handle)._flags & _ns_flagdata[flag].mask) >> _ns_flagdata[flag].shift;
4188 #endif /* L_ns_parse */
4190 #ifdef L_res_data
4191 int res_mkquery(int op, const char *dname, int class, int type,
4192 const unsigned char *data, int datalen,
4193 const unsigned char *newrr_in,
4194 unsigned char *buf, int buflen)
4196 HEADER *hp;
4197 unsigned char *cp, *ep;
4198 unsigned char *dnptrs[20], **dpp, **lastdnptr;
4199 uint32_t _res_options;
4200 int n;
4202 if (!buf || buflen < HFIXEDSZ) {
4203 h_errno = NETDB_INTERNAL;
4204 return -1;
4207 again:
4208 __UCLIBC_MUTEX_LOCK(__resolv_lock);
4209 _res_options = _res.options;
4210 __UCLIBC_MUTEX_UNLOCK(__resolv_lock);
4211 if (!(_res_options & RES_INIT)) {
4212 res_init(); /* our res_init never fails */
4213 goto again;
4216 #ifdef DEBUG
4217 if (_res_options & RES_DEBUG)
4218 printf(";; res_mkquery(%d, %s, %d, %d)\n",
4219 op, dname && *dname ? dname : "<null>", class, type);
4220 #endif
4222 memset(buf, 0, HFIXEDSZ);
4223 hp = (HEADER *) buf;
4224 hp->id = getpid() & 0xffff;
4225 hp->opcode = op;
4226 hp->rd = (_res_options & RES_RECURSE) != 0U;
4227 hp->rcode = NOERROR;
4229 cp = buf + HFIXEDSZ;
4230 ep = buf + buflen;
4231 dpp = dnptrs;
4232 *dpp++ = buf;
4233 *dpp++ = NULL;
4234 lastdnptr = dnptrs + sizeof dnptrs / sizeof dnptrs[0];
4237 * perform opcode specific processing
4239 switch (op) {
4240 case QUERY:
4241 case NS_NOTIFY_OP:
4242 if (ep - cp < QFIXEDSZ)
4243 return -1;
4245 n = dn_comp(dname, cp, ep - cp - QFIXEDSZ, dnptrs, lastdnptr);
4246 if (n < 0)
4247 return -1;
4249 cp += n;
4250 NS_PUT16(type, cp);
4251 NS_PUT16(class, cp);
4252 hp->qdcount = htons(1);
4254 if (op == QUERY || data == NULL)
4255 break;
4258 * Make an additional record for completion domain.
4260 if ((ep - cp) < RRFIXEDSZ)
4261 return -1;
4263 n = dn_comp((const char *)data, cp, ep - cp - RRFIXEDSZ,
4264 dnptrs, lastdnptr);
4265 if (n < 0)
4266 return -1;
4268 cp += n;
4269 NS_PUT16(T_NULL, cp);
4270 NS_PUT16(class, cp);
4271 NS_PUT32(0, cp);
4272 NS_PUT16(0, cp);
4273 hp->arcount = htons(1);
4275 break;
4277 case IQUERY:
4279 * Initialize answer section
4281 if (ep - cp < 1 + RRFIXEDSZ + datalen)
4282 return -1;
4284 *cp++ = '\0'; /*%< no domain name */
4285 NS_PUT16(type, cp);
4286 NS_PUT16(class, cp);
4287 NS_PUT32(0, cp);
4288 NS_PUT16(datalen, cp);
4290 if (datalen) {
4291 memcpy(cp, data, (size_t)datalen);
4292 cp += datalen;
4295 hp->ancount = htons(1);
4296 break;
4298 default:
4299 return -1;
4302 return cp - buf;
4304 #endif /* L_res_data */
4306 /* Unimplemented: */
4307 /* res_send */