resolv: fix unaligned tmp buffer corner-case
[uclibc-ng.git] / libc / inet / resolv.c
blob31e63810becae5173cbd2e492a1df25be31ecd2e
1 /* vi: set sw=4 ts=4: */
2 /* resolv.c: DNS Resolver
4 * Copyright (C) 1998 Kenneth Albanowski <kjahds@kjahds.com>,
5 * The Silver Hammer Group, Ltd.
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
13 * Portions Copyright (c) 1985, 1993
14 * The Regents of the University of California. All rights reserved.
16 * Redistribution and use in source and binary forms, with or without
17 * modification, are permitted provided that the following conditions
18 * are met:
19 * 1. Redistributions of source code must retain the above copyright
20 * notice, this list of conditions and the following disclaimer.
21 * 2. Redistributions in binary form must reproduce the above copyright
22 * notice, this list of conditions and the following disclaimer in the
23 * documentation and/or other materials provided with the distribution.
24 * 4. Neither the name of the University nor the names of its contributors
25 * may be used to endorse or promote products derived from this software
26 * without specific prior written permission.
28 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
29 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
32 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38 * SUCH DAMAGE.
41 * Portions Copyright (c) 1993 by Digital Equipment Corporation.
43 * Permission to use, copy, modify, and distribute this software for any
44 * purpose with or without fee is hereby granted, provided that the above
45 * copyright notice and this permission notice appear in all copies, and that
46 * the name of Digital Equipment Corporation not be used in advertising or
47 * publicity pertaining to distribution of the document or software without
48 * specific, written prior permission.
50 * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
51 * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
52 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
53 * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
54 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
55 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
56 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
57 * SOFTWARE.
60 * Portions Copyright (c) 1996-1999 by Internet Software Consortium.
62 * Permission to use, copy, modify, and distribute this software for any
63 * purpose with or without fee is hereby granted, provided that the above
64 * copyright notice and this permission notice appear in all copies.
66 * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
67 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
68 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
69 * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
70 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
71 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
72 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
73 * SOFTWARE.
76 * 5-Oct-2000 W. Greathouse wgreathouse@smva.com
77 * Fix memory leak and memory corruption.
78 * -- Every name resolution resulted in
79 * a new parse of resolv.conf and new
80 * copy of nameservers allocated by
81 * strdup.
82 * -- Every name resolution resulted in
83 * a new read of resolv.conf without
84 * resetting index from prior read...
85 * resulting in exceeding array bounds.
87 * Limit nameservers read from resolv.conf.
88 * Add "search" domains from resolv.conf.
89 * Some systems will return a security
90 * signature along with query answer for
91 * dynamic DNS entries -- skip/ignore this answer.
92 * Include arpa/nameser.h for defines.
93 * General cleanup.
95 * 20-Jun-2001 Michal Moskal <malekith@pld.org.pl>
96 * partial IPv6 support (i.e. gethostbyname2() and resolve_address2()
97 * functions added), IPv6 nameservers are also supported.
99 * 6-Oct-2001 Jari Korva <jari.korva@iki.fi>
100 * more IPv6 support (IPv6 support for gethostbyaddr();
101 * address family parameter and improved IPv6 support for get_hosts_byname
102 * and read_etc_hosts; getnameinfo() port from glibc; defined
103 * defined ip6addr_any and in6addr_loopback)
105 * 2-Feb-2002 Erik Andersen <andersen@codepoet.org>
106 * Added gethostent(), sethostent(), and endhostent()
108 * 17-Aug-2002 Manuel Novoa III <mjn3@codepoet.org>
109 * Fixed __read_etc_hosts_r to return alias list, and modified buffer
110 * allocation accordingly. See MAX_ALIASES and ALIAS_DIM below.
111 * This fixes the segfault in the Python 2.2.1 socket test.
113 * 04-Jan-2003 Jay Kulpinski <jskulpin@berkshire.rr.com>
114 * Fixed __decode_dotted to count the terminating null character
115 * in a host name.
117 * 02-Oct-2003 Tony J. White <tjw@tjw.org>
118 * Lifted dn_expand() and dependent ns_name_uncompress(), ns_name_unpack(),
119 * and ns_name_ntop() from glibc 2.3.2 for compatibility with ipsec-tools
120 * and openldap.
122 * 7-Sep-2004 Erik Andersen <andersen@codepoet.org>
123 * Added gethostent_r()
125 * 2008, 2009 Denys Vlasenko <vda.linux@googlemail.com>
126 * Cleanups, fixes, readability, more cleanups and more fixes.
128 * March 2010 Bernhard Reutner-Fischer
129 * Switch to common config parser
131 /* Nota bene:
132 * The whole resolver code has several (severe) problems:
133 * - it doesn't even build without IPv4, i.e. !UCLIBC_HAS_IPV4 but only IPv6
134 * - it is way too big
136 * Both points above are considered bugs, patches/reimplementations welcome.
138 /* RFC 1035
140 Whenever an octet represents a numeric quantity, the left most bit
141 in the diagram is the high order or most significant bit.
142 That is, the bit labeled 0 is the most significant bit.
145 4.1.1. Header section format
146 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
147 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
148 | ID |
149 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
150 |QR| OPCODE |AA|TC|RD|RA| 0 0 0| RCODE |
151 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
152 | QDCOUNT |
153 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
154 | ANCOUNT |
155 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
156 | NSCOUNT |
157 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
158 | ARCOUNT |
159 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
160 ID 16 bit random identifier assigned by querying peer.
161 Used to match query/response.
162 QR message is a query (0), or a response (1).
163 OPCODE 0 standard query (QUERY)
164 1 inverse query (IQUERY)
165 2 server status request (STATUS)
166 AA Authoritative Answer - this bit is valid in responses.
167 Responding name server is an authority for the domain name
168 in question section. Answer section may have multiple owner names
169 because of aliases. The AA bit corresponds to the name which matches
170 the query name, or the first owner name in the answer section.
171 TC TrunCation - this message was truncated.
172 RD Recursion Desired - this bit may be set in a query and
173 is copied into the response. If RD is set, it directs
174 the name server to pursue the query recursively.
175 Recursive query support is optional.
176 RA Recursion Available - this be is set or cleared in a
177 response, and denotes whether recursive query support is
178 available in the name server.
179 RCODE Response code.
180 0 No error condition
181 1 Format error
182 2 Server failure - server was unable to process the query
183 due to a problem with the name server.
184 3 Name Error - meaningful only for responses from
185 an authoritative name server. The referenced domain name
186 does not exist.
187 4 Not Implemented.
188 5 Refused.
189 QDCOUNT number of entries in the question section.
190 ANCOUNT number of records in the answer section.
191 NSCOUNT number of records in the authority records section.
192 ARCOUNT number of records in the additional records section.
194 4.1.2. Question section format
196 The section contains QDCOUNT (usually 1) entries, each of this format:
197 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
198 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
199 / QNAME /
201 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
202 | QTYPE |
203 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
204 | QCLASS |
205 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
206 QNAME a domain name represented as a sequence of labels, where
207 each label consists of a length octet followed by that
208 number of octets. The domain name terminates with the
209 zero length octet for the null label of the root. Note
210 that this field may be an odd number of octets; no
211 padding is used.
212 QTYPE a two octet type of the query.
213 1 a host address [REQ_A const]
214 2 an authoritative name server
215 3 a mail destination (Obsolete - use MX)
216 4 a mail forwarder (Obsolete - use MX)
217 5 the canonical name for an alias
218 6 marks the start of a zone of authority
219 7 a mailbox domain name (EXPERIMENTAL)
220 8 a mail group member (EXPERIMENTAL)
221 9 a mail rename domain name (EXPERIMENTAL)
222 10 a null RR (EXPERIMENTAL)
223 11 a well known service description
224 12 a domain name pointer [REQ_PTR const]
225 13 host information
226 14 mailbox or mail list information
227 15 mail exchange
228 16 text strings
229 0x1c IPv6?
230 252 a request for a transfer of an entire zone
231 253 a request for mailbox-related records (MB, MG or MR)
232 254 a request for mail agent RRs (Obsolete - see MX)
233 255 a request for all records
234 QCLASS a two octet code that specifies the class of the query.
235 1 the Internet
236 (others are historic only)
237 255 any class
239 4.1.3. Resource record format
241 The answer, authority, and additional sections all share the same format:
242 a variable number of resource records, where the number of records
243 is specified in the corresponding count field in the header.
244 Each resource record has this format:
245 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
246 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
248 / NAME /
249 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
250 | TYPE |
251 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
252 | CLASS |
253 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
254 | TTL |
256 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
257 | RDLENGTH |
258 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--|
259 / RDATA /
261 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
262 NAME a domain name to which this resource record pertains.
263 TYPE two octets containing one of the RR type codes. This
264 field specifies the meaning of the data in the RDATA field.
265 CLASS two octets which specify the class of the data in the RDATA field.
266 TTL a 32 bit unsigned integer that specifies the time interval
267 (in seconds) that the record may be cached.
268 RDLENGTH a 16 bit integer, length in octets of the RDATA field.
269 RDATA a variable length string of octets that describes the resource.
270 The format of this information varies according to the TYPE
271 and CLASS of the resource record.
272 If the TYPE is A and the CLASS is IN, it's a 4 octet IP address.
274 4.1.4. Message compression
276 In order to reduce the size of messages, domain names can be compressed.
277 An entire domain name or a list of labels at the end of a domain name
278 is replaced with a pointer to a prior occurance of the same name.
280 The pointer takes the form of a two octet sequence:
281 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
282 | 1 1| OFFSET |
283 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
284 The first two bits are ones. This allows a pointer to be distinguished
285 from a label, since the label must begin with two zero bits because
286 labels are restricted to 63 octets or less. The OFFSET field specifies
287 an offset from the start of the message (i.e., the first octet
288 of the ID field in the domain header).
289 A zero offset specifies the first byte of the ID field, etc.
290 Domain name in a message can be represented as either:
291 - a sequence of labels ending in a zero octet
292 - a pointer
293 - a sequence of labels ending with a pointer
296 #include <string.h>
297 #include <stdio.h>
298 #include <stdio_ext.h>
299 #include <signal.h>
300 #include <errno.h>
301 #include <sys/poll.h>
302 #include <sys/socket.h>
303 #include <sys/types.h>
304 #include <sys/time.h>
305 #include <netinet/in.h>
306 #include <arpa/inet.h>
307 #include <stdlib.h>
308 #include <unistd.h>
309 #include <resolv.h>
310 #include <netdb.h>
311 #include <ctype.h>
312 #include <stdbool.h>
313 #include <time.h>
314 #include <arpa/nameser.h>
315 #include <sys/utsname.h>
316 #include <sys/un.h>
317 #include <sys/stat.h>
318 #include <sys/param.h>
319 #include <bits/uClibc_mutex.h>
320 #include "internal/parse_config.h"
322 /* poll() is not supported in kernel <= 2.0, therefore if __NR_poll is
323 * not available, we assume an old Linux kernel is in use and we will
324 * use select() instead. */
325 #include <sys/syscall.h>
326 #ifndef __NR_poll
327 # define USE_SELECT
328 #endif
330 #if defined __UCLIBC_HAS_IPV4__ && defined __UCLIBC_HAS_IPV6__
331 #define IF_HAS_BOTH(...) __VA_ARGS__
332 #else
333 #define IF_HAS_BOTH(...)
334 #endif
337 #define MAX_RECURSE 5
338 #define MAXALIASES (4)
339 #define BUFSZ (80) /* one line */
341 #define NS_TYPE_ELT 0x40 /*%< EDNS0 extended label type */
342 #define DNS_LABELTYPE_BITSTRING 0x41
344 #undef DEBUG
345 /* #define DEBUG */
347 #ifdef DEBUG
348 #define DPRINTF(X,args...) fprintf(stderr, X, ##args)
349 #else
350 #define DPRINTF(X,args...)
351 #endif
353 /* Make sure the incoming char * buffer is aligned enough to handle our random
354 * structures. This define is the same as we use for malloc alignment (which
355 * has same requirements). The offset is the number of bytes we need to adjust
356 * in order to attain desired alignment.
358 #define ALIGN_ATTR __alignof__(double __attribute_aligned__ (sizeof(size_t)))
359 #define ALIGN_BUFFER_OFFSET(buf) ((ALIGN_ATTR - ((size_t)buf % ALIGN_ATTR)) % ALIGN_ATTR)
362 /* Structs */
363 struct resolv_header {
364 int id;
365 int qr, opcode, aa, tc, rd, ra, rcode;
366 int qdcount;
367 int ancount;
368 int nscount;
369 int arcount;
372 struct resolv_question {
373 char *dotted;
374 int qtype;
375 int qclass;
378 struct resolv_answer {
379 char *dotted;
380 int atype;
381 int aclass;
382 int ttl;
383 int rdlength;
384 const unsigned char *rdata;
385 int rdoffset;
386 char* buf;
387 size_t buflen;
388 size_t add_count;
391 enum etc_hosts_action {
392 GET_HOSTS_BYNAME = 0,
393 GETHOSTENT,
394 GET_HOSTS_BYADDR,
397 typedef union sockaddr46_t {
398 struct sockaddr sa;
399 #ifdef __UCLIBC_HAS_IPV4__
400 struct sockaddr_in sa4;
401 #endif
402 #ifdef __UCLIBC_HAS_IPV6__
403 struct sockaddr_in6 sa6;
404 #endif
405 } sockaddr46_t;
408 __UCLIBC_MUTEX_EXTERN(__resolv_lock) attribute_hidden;
410 /* Protected by __resolv_lock */
411 extern void (*__res_sync)(void) attribute_hidden;
412 /*extern uint32_t __resolv_opts attribute_hidden; */
413 extern uint8_t __resolv_timeout attribute_hidden;
414 extern uint8_t __resolv_attempts attribute_hidden;
415 extern unsigned __nameservers attribute_hidden;
416 extern unsigned __searchdomains attribute_hidden;
417 extern sockaddr46_t *__nameserver attribute_hidden;
418 extern char **__searchdomain attribute_hidden;
419 #ifdef __UCLIBC_HAS_IPV4__
420 extern const struct sockaddr_in __local_nameserver attribute_hidden;
421 #else
422 extern const struct sockaddr_in6 __local_nameserver attribute_hidden;
423 #endif
424 /* Arbitrary */
425 #define MAXLEN_searchdomain 128
428 /* prototypes for internal functions */
429 extern void endhostent_unlocked(void) attribute_hidden;
430 extern int __get_hosts_byname_r(const char *name,
431 int type,
432 struct hostent *result_buf,
433 char *buf,
434 size_t buflen,
435 struct hostent **result,
436 int *h_errnop) attribute_hidden;
437 extern int __get_hosts_byaddr_r(const char *addr,
438 int len,
439 int type,
440 struct hostent *result_buf,
441 char *buf,
442 size_t buflen,
443 struct hostent **result,
444 int *h_errnop) attribute_hidden;
445 extern parser_t *__open_etc_hosts(void) attribute_hidden;
446 extern int __read_etc_hosts_r(parser_t *parser,
447 const char *name,
448 int type,
449 enum etc_hosts_action action,
450 struct hostent *result_buf,
451 char *buf,
452 size_t buflen,
453 struct hostent **result,
454 int *h_errnop) attribute_hidden;
455 extern int __dns_lookup(const char *name,
456 int type,
457 unsigned char **outpacket,
458 struct resolv_answer *a) attribute_hidden;
459 extern int __encode_dotted(const char *dotted,
460 unsigned char *dest,
461 int maxlen) attribute_hidden;
462 extern int __decode_dotted(const unsigned char *packet,
463 int offset,
464 int packet_len,
465 char *dest,
466 int dest_len) attribute_hidden;
467 extern int __encode_header(struct resolv_header *h,
468 unsigned char *dest,
469 int maxlen) attribute_hidden;
470 extern void __decode_header(unsigned char *data,
471 struct resolv_header *h) attribute_hidden;
472 extern int __encode_question(const struct resolv_question *q,
473 unsigned char *dest,
474 int maxlen) attribute_hidden;
475 extern int __encode_answer(struct resolv_answer *a,
476 unsigned char *dest,
477 int maxlen) attribute_hidden;
478 extern void __open_nameservers(void) attribute_hidden;
479 extern void __close_nameservers(void) attribute_hidden;
482 * Theory of operation.
484 * gethostbyname, getaddrinfo and friends end up here, and they sometimes
485 * need to talk to DNS servers. In order to do this, we need to read /etc/resolv.conf
486 * and determine servers' addresses and the like. resolv.conf format:
488 * nameserver <IP[v6]>
489 * Address of DNS server. Cumulative.
490 * If not specified, assumed to be on localhost.
491 * search <domain1>[ <domain2>]...
492 * Append these domains to unqualified names.
493 * See ndots:n option.
494 * $LOCALDOMAIN (space-separated list) overrides this.
495 * domain <domain>
496 * Effectively same as "search" with one domain.
497 * If no "domain" line is present, the domain is determined
498 * from the local host name returned by gethostname();
499 * the domain part is taken to be everything after the first dot.
500 * If there are no dots, there will be no "domain".
501 * The domain and search keywords are mutually exclusive.
502 * If more than one instance of these keywords is present,
503 * the last instance wins.
504 * sortlist 130.155.160.0[/255.255.240.0] 130.155.0.0
505 * Allows addresses returned by gethostbyname to be sorted.
506 * Not supported.
507 * options option[ option]...
508 * (so far we support timeout:n and attempts:n)
509 * $RES_OPTIONS (space-separated list) is to be added to "options"
510 * debug sets RES_DEBUG in _res.options
511 * ndots:n how many dots there should be so that name will be tried
512 * first as an absolute name before any search list elements
513 * are appended to it. Default 1
514 * timeout:n how long to wait for response. Default 5
515 * (sun seems to have retrans:n synonym)
516 * attempts:n number of rounds to do before giving up and returning
517 * an error. Default 2
518 * (sun seems to have retry:n synonym)
519 * rotate sets RES_ROTATE in _res.options, round robin
520 * selection of nameservers. Otherwise try
521 * the first listed server first every time
522 * no-check-names
523 * sets RES_NOCHECKNAME in _res.options, which disables
524 * checking of incoming host names for invalid characters
525 * such as underscore (_), non-ASCII, or control characters
526 * inet6 sets RES_USE_INET6 in _res.options. Try a AAAA query
527 * before an A query inside the gethostbyname(), and map
528 * IPv4 responses in IPv6 "tunnelled form" if no AAAA records
529 * are found but an A record set exists
530 * no_tld_query (FreeBSDism?)
531 * do not attempt to resolve names without dots
533 * We will read and analyze /etc/resolv.conf as needed before
534 * we do a DNS request. This happens in __dns_lookup.
535 * It is reread if its mtime is changed.
537 * BSD has res_init routine which is used to initialize resolver state
538 * which is held in global structure _res.
539 * Generally, programs call res_init, then fiddle with _res.XXX
540 * (_res.options and _res.nscount, _res.nsaddr_list[N]
541 * are popular targets of fiddling) and expect subsequent calls
542 * to gethostbyname, getaddrinfo, etc to use modified information.
544 * However, historical _res structure is quite awkward.
545 * Using it for storing /etc/resolv.conf info is not desirable,
546 * and __dns_lookup does not use it.
548 * We would like to avoid using it unless absolutely necessary.
549 * If user doesn't use res_init, we should arrange it so that
550 * _res structure doesn't even *get linked in* into user's application
551 * (imagine static uclibc build here).
553 * The solution is a __res_sync function pointer, which is normally NULL.
554 * But if res_init is called, it gets set and any subsequent gethostbyname
555 * et al "syncronizes" our internal structures with potentially
556 * modified _res.XXX stuff by calling __res_sync.
557 * The trick here is that if res_init is not used and not linked in,
558 * gethostbyname itself won't reference _res and _res won't be linked in
559 * either. Other possible methods like
560 * if (__res_sync_just_an_int_flag)
561 * __sync_me_with_res()
562 * would pull in __sync_me_with_res, which pulls in _res. Bad.
566 #ifdef L_encodeh
568 int __encode_header(struct resolv_header *h, unsigned char *dest, int maxlen)
570 if (maxlen < HFIXEDSZ)
571 return -1;
573 dest[0] = (h->id & 0xff00) >> 8;
574 dest[1] = (h->id & 0x00ff) >> 0;
575 dest[2] = (h->qr ? 0x80 : 0) |
576 ((h->opcode & 0x0f) << 3) |
577 (h->aa ? 0x04 : 0) |
578 (h->tc ? 0x02 : 0) |
579 (h->rd ? 0x01 : 0);
580 dest[3] = (h->ra ? 0x80 : 0) | (h->rcode & 0x0f);
581 dest[4] = (h->qdcount & 0xff00) >> 8;
582 dest[5] = (h->qdcount & 0x00ff) >> 0;
583 dest[6] = (h->ancount & 0xff00) >> 8;
584 dest[7] = (h->ancount & 0x00ff) >> 0;
585 dest[8] = (h->nscount & 0xff00) >> 8;
586 dest[9] = (h->nscount & 0x00ff) >> 0;
587 dest[10] = (h->arcount & 0xff00) >> 8;
588 dest[11] = (h->arcount & 0x00ff) >> 0;
590 return HFIXEDSZ;
592 #endif /* L_encodeh */
595 #ifdef L_decodeh
597 void __decode_header(unsigned char *data,
598 struct resolv_header *h)
600 h->id = (data[0] << 8) | data[1];
601 h->qr = (data[2] & 0x80) ? 1 : 0;
602 h->opcode = (data[2] >> 3) & 0x0f;
603 h->aa = (data[2] & 0x04) ? 1 : 0;
604 h->tc = (data[2] & 0x02) ? 1 : 0;
605 h->rd = (data[2] & 0x01) ? 1 : 0;
606 h->ra = (data[3] & 0x80) ? 1 : 0;
607 h->rcode = data[3] & 0x0f;
608 h->qdcount = (data[4] << 8) | data[5];
609 h->ancount = (data[6] << 8) | data[7];
610 h->nscount = (data[8] << 8) | data[9];
611 h->arcount = (data[10] << 8) | data[11];
613 #endif /* L_decodeh */
616 #ifdef L_encoded
618 /* Encode a dotted string into nameserver transport-level encoding.
619 This routine is fairly dumb, and doesn't attempt to compress
620 the data */
621 int __encode_dotted(const char *dotted, unsigned char *dest, int maxlen)
623 unsigned used = 0;
625 while (dotted && *dotted) {
626 char *c = strchr(dotted, '.');
627 int l = c ? c - dotted : strlen(dotted);
629 /* two consecutive dots are not valid */
630 if (l == 0)
631 return -1;
633 if (l >= (maxlen - used - 1))
634 return -1;
636 dest[used++] = l;
637 memcpy(dest + used, dotted, l);
638 used += l;
640 if (!c)
641 break;
642 dotted = c + 1;
645 if (maxlen < 1)
646 return -1;
648 dest[used++] = 0;
650 return used;
652 #endif /* L_encoded */
655 #ifdef L_decoded
657 /* Decode a dotted string from nameserver transport-level encoding.
658 This routine understands compressed data. */
659 int __decode_dotted(const unsigned char *packet,
660 int offset,
661 int packet_len,
662 char *dest,
663 int dest_len)
665 unsigned b;
666 bool measure = 1;
667 unsigned total = 0;
668 unsigned used = 0;
670 if (!packet)
671 return -1;
673 while (1) {
674 if (offset >= packet_len)
675 return -1;
676 b = packet[offset++];
677 if (b == 0)
678 break;
680 if (measure)
681 total++;
683 if ((b & 0xc0) == 0xc0) {
684 if (offset >= packet_len)
685 return -1;
686 if (measure)
687 total++;
688 /* compressed item, redirect */
689 offset = ((b & 0x3f) << 8) | packet[offset];
690 measure = 0;
691 continue;
694 if (used + b + 1 >= dest_len)
695 return -1;
696 if (offset + b >= packet_len)
697 return -1;
698 memcpy(dest + used, packet + offset, b);
699 offset += b;
700 used += b;
702 if (measure)
703 total += b;
705 if (packet[offset] != 0)
706 dest[used++] = '.';
707 else
708 dest[used++] = '\0';
711 /* The null byte must be counted too */
712 if (measure)
713 total++;
715 DPRINTF("Total decode len = %d\n", total);
717 return total;
719 #endif /* L_decoded */
722 #ifdef L_encodeq
724 int __encode_question(const struct resolv_question *q,
725 unsigned char *dest,
726 int maxlen)
728 int i;
730 i = __encode_dotted(q->dotted, dest, maxlen);
731 if (i < 0)
732 return i;
734 dest += i;
735 maxlen -= i;
737 if (maxlen < 4)
738 return -1;
740 dest[0] = (q->qtype & 0xff00) >> 8;
741 dest[1] = (q->qtype & 0x00ff) >> 0;
742 dest[2] = (q->qclass & 0xff00) >> 8;
743 dest[3] = (q->qclass & 0x00ff) >> 0;
745 return i + 4;
747 #endif /* L_encodeq */
750 #ifdef L_encodea
752 int __encode_answer(struct resolv_answer *a, unsigned char *dest, int maxlen)
754 int i;
756 i = __encode_dotted(a->dotted, dest, maxlen);
757 if (i < 0)
758 return i;
760 dest += i;
761 maxlen -= i;
763 if (maxlen < (RRFIXEDSZ + a->rdlength))
764 return -1;
766 *dest++ = (a->atype & 0xff00) >> 8;
767 *dest++ = (a->atype & 0x00ff) >> 0;
768 *dest++ = (a->aclass & 0xff00) >> 8;
769 *dest++ = (a->aclass & 0x00ff) >> 0;
770 *dest++ = (a->ttl & 0xff000000) >> 24;
771 *dest++ = (a->ttl & 0x00ff0000) >> 16;
772 *dest++ = (a->ttl & 0x0000ff00) >> 8;
773 *dest++ = (a->ttl & 0x000000ff) >> 0;
774 *dest++ = (a->rdlength & 0xff00) >> 8;
775 *dest++ = (a->rdlength & 0x00ff) >> 0;
776 memcpy(dest, a->rdata, a->rdlength);
778 return i + RRFIXEDSZ + a->rdlength;
780 #endif /* L_encodea */
783 #ifdef CURRENTLY_UNUSED
784 #ifdef L_encodep
786 int __encode_packet(struct resolv_header *h,
787 struct resolv_question **q,
788 struct resolv_answer **an,
789 struct resolv_answer **ns,
790 struct resolv_answer **ar,
791 unsigned char *dest, int maxlen) attribute_hidden;
792 int __encode_packet(struct resolv_header *h,
793 struct resolv_question **q,
794 struct resolv_answer **an,
795 struct resolv_answer **ns,
796 struct resolv_answer **ar,
797 unsigned char *dest, int maxlen)
799 int i, total = 0;
800 unsigned j;
802 i = __encode_header(h, dest, maxlen);
803 if (i < 0)
804 return i;
806 dest += i;
807 maxlen -= i;
808 total += i;
810 for (j = 0; j < h->qdcount; j++) {
811 i = __encode_question(q[j], dest, maxlen);
812 if (i < 0)
813 return i;
814 dest += i;
815 maxlen -= i;
816 total += i;
819 for (j = 0; j < h->ancount; j++) {
820 i = __encode_answer(an[j], dest, maxlen);
821 if (i < 0)
822 return i;
823 dest += i;
824 maxlen -= i;
825 total += i;
827 for (j = 0; j < h->nscount; j++) {
828 i = __encode_answer(ns[j], dest, maxlen);
829 if (i < 0)
830 return i;
831 dest += i;
832 maxlen -= i;
833 total += i;
835 for (j = 0; j < h->arcount; j++) {
836 i = __encode_answer(ar[j], dest, maxlen);
837 if (i < 0)
838 return i;
839 dest += i;
840 maxlen -= i;
841 total += i;
844 return total;
846 #endif /* L_encodep */
849 #ifdef L_decodep
851 int __decode_packet(unsigned char *data, struct resolv_header *h) attribute_hidden;
852 int __decode_packet(unsigned char *data, struct resolv_header *h)
854 __decode_header(data, h);
855 return HFIXEDSZ;
857 #endif /* L_decodep */
860 #ifdef L_formquery
862 int __form_query(int id,
863 const char *name,
864 int type,
865 unsigned char *packet,
866 int maxlen) attribute_hidden;
867 int __form_query(int id,
868 const char *name,
869 int type,
870 unsigned char *packet,
871 int maxlen)
873 struct resolv_header h;
874 struct resolv_question q;
875 int i, j;
877 memset(&h, 0, sizeof(h));
878 h.id = id;
879 h.qdcount = 1;
881 q.dotted = (char *) name;
882 q.qtype = type;
883 q.qclass = C_IN; /* CLASS_IN */
885 i = __encode_header(&h, packet, maxlen);
886 if (i < 0)
887 return i;
889 j = __encode_question(&q, packet + i, maxlen - i);
890 if (j < 0)
891 return j;
893 return i + j;
895 #endif /* L_formquery */
896 #endif /* CURRENTLY_UNUSED */
899 #ifdef L_opennameservers
901 # if __BYTE_ORDER == __LITTLE_ENDIAN
902 #define NAMESERVER_PORT_N (__bswap_constant_16(NAMESERVER_PORT))
903 #else
904 #define NAMESERVER_PORT_N NAMESERVER_PORT
905 #endif
907 __UCLIBC_MUTEX_INIT(__resolv_lock, PTHREAD_MUTEX_INITIALIZER);
909 /* Protected by __resolv_lock */
910 void (*__res_sync)(void);
911 /*uint32_t __resolv_opts; */
912 uint8_t __resolv_timeout = RES_TIMEOUT;
913 uint8_t __resolv_attempts = RES_DFLRETRY;
914 unsigned __nameservers;
915 unsigned __searchdomains;
916 sockaddr46_t *__nameserver;
917 char **__searchdomain;
918 #ifdef __UCLIBC_HAS_IPV4__
919 const struct sockaddr_in __local_nameserver = {
920 .sin_family = AF_INET,
921 .sin_port = NAMESERVER_PORT_N,
923 #else
924 const struct sockaddr_in6 __local_nameserver = {
925 .sin6_family = AF_INET6,
926 .sin6_port = NAMESERVER_PORT_N,
928 #endif
930 /* Helpers. Both stop on EOL, if it's '\n', it is converted to NUL first */
931 static char *skip_nospace(char *p)
933 while (*p != '\0' && !isspace(*p)) {
934 if (*p == '\n') {
935 *p = '\0';
936 break;
938 p++;
940 return p;
942 static char *skip_and_NUL_space(char *p)
944 /* NB: '\n' is not isspace! */
945 while (1) {
946 char c = *p;
947 if (c == '\0' || !isspace(c))
948 break;
949 *p = '\0';
950 if (c == '\n' || c == '#')
951 break;
952 p++;
954 return p;
957 /* Must be called under __resolv_lock. */
958 void __open_nameservers(void)
960 static uint32_t resolv_conf_mtime;
962 char szBuffer[MAXLEN_searchdomain];
963 FILE *fp;
964 int i;
965 sockaddr46_t sa;
967 if (!__res_sync) {
968 /* Reread /etc/resolv.conf if it was modified. */
969 struct stat sb;
970 if (stat("/etc/resolv.conf", &sb) != 0)
971 sb.st_mtime = 0;
972 if (resolv_conf_mtime != (uint32_t)sb.st_mtime) {
973 resolv_conf_mtime = sb.st_mtime;
974 __close_nameservers(); /* force config reread */
978 if (__nameservers)
979 goto sync;
981 __resolv_timeout = RES_TIMEOUT;
982 __resolv_attempts = RES_DFLRETRY;
984 fp = fopen("/etc/resolv.conf", "r");
985 #ifdef FALLBACK_TO_CONFIG_RESOLVCONF
986 if (!fp) {
987 /* If we do not have a pre-populated /etc/resolv.conf then
988 try to use the one from /etc/config which exists on numerous
989 systems ranging from some uClinux to IRIX installations and
990 may be the only /etc dir that was mounted rw. */
991 fp = fopen("/etc/config/resolv.conf", "r");
993 #endif
995 if (fp) {
996 while (fgets(szBuffer, sizeof(szBuffer), fp) != NULL) {
997 void *ptr;
998 char *keyword, *p;
1000 keyword = p = skip_and_NUL_space(szBuffer);
1001 /* skip keyword */
1002 p = skip_nospace(p);
1003 /* find next word */
1004 p = skip_and_NUL_space(p);
1006 if (strcmp(keyword, "nameserver") == 0) {
1007 /* terminate IP addr */
1008 *skip_nospace(p) = '\0';
1009 memset(&sa, 0, sizeof(sa));
1010 if (0) /* nothing */;
1011 #ifdef __UCLIBC_HAS_IPV6__
1012 else if (inet_pton(AF_INET6, p, &sa.sa6.sin6_addr) > 0) {
1013 sa.sa6.sin6_family = AF_INET6;
1014 sa.sa6.sin6_port = htons(NAMESERVER_PORT);
1016 #endif
1017 #ifdef __UCLIBC_HAS_IPV4__
1018 else if (inet_pton(AF_INET, p, &sa.sa4.sin_addr) > 0) {
1019 sa.sa4.sin_family = AF_INET;
1020 sa.sa4.sin_port = htons(NAMESERVER_PORT);
1022 #endif
1023 else
1024 continue; /* garbage on this line */
1025 ptr = realloc(__nameserver, (__nameservers + 1) * sizeof(__nameserver[0]));
1026 if (!ptr)
1027 continue;
1028 __nameserver = ptr;
1029 __nameserver[__nameservers++] = sa; /* struct copy */
1030 continue;
1032 if (strcmp(keyword, "domain") == 0 || strcmp(keyword, "search") == 0) {
1033 char *p1;
1035 /* free old domains ("last 'domain' or 'search' wins" rule) */
1036 while (__searchdomains)
1037 free(__searchdomain[--__searchdomains]);
1038 /*free(__searchdomain);*/
1039 /*__searchdomain = NULL; - not necessary */
1040 next_word:
1041 /* terminate current word */
1042 p1 = skip_nospace(p);
1043 /* find next word (maybe) */
1044 p1 = skip_and_NUL_space(p1);
1045 /* add it */
1046 ptr = realloc(__searchdomain, (__searchdomains + 1) * sizeof(__searchdomain[0]));
1047 if (!ptr)
1048 continue;
1049 __searchdomain = ptr;
1050 /* NB: strlen(p) <= MAXLEN_searchdomain) because szBuffer[] is smaller */
1051 ptr = strdup(p);
1052 if (!ptr)
1053 continue;
1054 DPRINTF("adding search %s\n", (char*)ptr);
1055 __searchdomain[__searchdomains++] = (char*)ptr;
1056 p = p1;
1057 if (*p)
1058 goto next_word;
1059 continue;
1061 /* if (strcmp(keyword, "sortlist") == 0)... */
1062 if (strcmp(keyword, "options") == 0) {
1063 char *p1;
1064 uint8_t *what;
1066 if (p == NULL || (p1 = strchr(p, ':')) == NULL)
1067 continue;
1068 *p1++ = '\0';
1069 if (strcmp(p, "timeout") == 0)
1070 what = &__resolv_timeout;
1071 else if (strcmp(p, "attempts") == 0)
1072 what = &__resolv_attempts;
1073 else
1074 continue;
1075 *what = atoi(p1);
1076 DPRINTF("option %s:%d\n", p, *what);
1079 fclose(fp);
1081 if (__nameservers == 0) {
1082 /* Have to handle malloc failure! What a mess...
1083 * And it's not only here, we need to be careful
1084 * to never write into __nameserver[0] if it points
1085 * to constant __local_nameserver, or free it. */
1086 __nameserver = malloc(sizeof(__nameserver[0]));
1087 if (__nameserver)
1088 memcpy(__nameserver, &__local_nameserver, sizeof(__local_nameserver));
1089 else
1090 __nameserver = (void*) &__local_nameserver;
1091 __nameservers++;
1093 if (__searchdomains == 0) {
1094 char buf[256];
1095 char *p;
1096 i = gethostname(buf, sizeof(buf) - 1);
1097 buf[sizeof(buf) - 1] = '\0';
1098 if (i == 0 && (p = strchr(buf, '.')) != NULL && p[1]) {
1099 p = strdup(p + 1);
1100 if (!p)
1101 goto err;
1102 __searchdomain = malloc(sizeof(__searchdomain[0]));
1103 if (!__searchdomain) {
1104 free(p);
1105 goto err;
1107 __searchdomain[0] = p;
1108 __searchdomains++;
1109 err: ;
1112 DPRINTF("nameservers = %d\n", __nameservers);
1114 sync:
1115 if (__res_sync)
1116 __res_sync();
1118 #endif /* L_opennameservers */
1121 #ifdef L_closenameservers
1123 /* Must be called under __resolv_lock. */
1124 void __close_nameservers(void)
1126 if (__nameserver != (void*) &__local_nameserver)
1127 free(__nameserver);
1128 __nameserver = NULL;
1129 __nameservers = 0;
1130 while (__searchdomains)
1131 free(__searchdomain[--__searchdomains]);
1132 free(__searchdomain);
1133 __searchdomain = NULL;
1134 /*__searchdomains = 0; - already is */
1136 #endif /* L_closenameservers */
1139 #ifdef L_dnslookup
1141 /* Helpers */
1142 static int __length_question(const unsigned char *data, int maxlen)
1144 const unsigned char *start;
1145 unsigned b;
1147 if (!data)
1148 return -1;
1150 start = data;
1151 while (1) {
1152 if (maxlen <= 0)
1153 return -1;
1154 b = *data++;
1155 if (b == 0)
1156 break;
1157 if ((b & 0xc0) == 0xc0) {
1158 /* It's a "compressed" name. */
1159 data++; /* skip lsb of redirected offset */
1160 maxlen -= 2;
1161 break;
1163 data += b;
1164 maxlen -= (b + 1); /* account for data++ above */
1166 /* Up to here we were skipping encoded name */
1168 /* Account for QTYPE and QCLASS fields */
1169 if (maxlen < 4)
1170 return -1;
1171 return data - start + 2 + 2;
1174 static int __decode_answer(const unsigned char *message, /* packet */
1175 int offset,
1176 int len, /* total packet len */
1177 struct resolv_answer *a)
1179 char temp[256];
1180 int i;
1182 DPRINTF("decode_answer(start): off %d, len %d\n", offset, len);
1183 i = __decode_dotted(message, offset, len, temp, sizeof(temp));
1184 if (i < 0)
1185 return i;
1187 message += offset + i;
1188 len -= i + RRFIXEDSZ + offset;
1189 if (len < 0) {
1190 DPRINTF("decode_answer: off %d, len %d, i %d\n", offset, len, i);
1191 return len;
1194 /* TODO: what if strdup fails? */
1195 a->dotted = strdup(temp);
1196 a->atype = (message[0] << 8) | message[1];
1197 message += 2;
1198 a->aclass = (message[0] << 8) | message[1];
1199 message += 2;
1200 a->ttl = (message[0] << 24) |
1201 (message[1] << 16) | (message[2] << 8) | (message[3] << 0);
1202 message += 4;
1203 a->rdlength = (message[0] << 8) | message[1];
1204 message += 2;
1205 a->rdata = message;
1206 a->rdoffset = offset + i + RRFIXEDSZ;
1208 DPRINTF("i=%d,rdlength=%d\n", i, a->rdlength);
1210 if (len < a->rdlength)
1211 return -1;
1212 return i + RRFIXEDSZ + a->rdlength;
1215 /* On entry:
1216 * a.buf(len) = auxiliary buffer for IP addresses after first one
1217 * a.add_count = how many additional addresses are there already
1218 * outpacket = where to save ptr to raw packet? can be NULL
1219 * On exit:
1220 * ret < 0: error, all other data is not valid
1221 * ret >= 0: length of reply packet
1222 * a.add_count & a.buf: updated
1223 * a.rdlength: length of addresses (4 bytes for IPv4)
1224 * *outpacket: updated (packet is malloced, you need to free it)
1225 * a.rdata: points into *outpacket to 1st IP addr
1226 * NB: don't pass outpacket == NULL if you need to use a.rdata!
1227 * a.atype: type of query?
1228 * a.dotted: which name we _actually_ used. May contain search domains
1229 * appended. (why the filed is called "dotted" I have no idea)
1230 * This is a malloced string. May be NULL because strdup failed.
1232 int __dns_lookup(const char *name,
1233 int type,
1234 unsigned char **outpacket,
1235 struct resolv_answer *a)
1237 /* Protected by __resolv_lock: */
1238 static int last_ns_num = 0;
1239 static uint16_t last_id = 1;
1241 int i, j, fd, rc;
1242 int packet_len;
1243 int name_len;
1244 #ifdef USE_SELECT
1245 struct timeval tv;
1246 fd_set fds;
1247 #else
1248 struct pollfd fds;
1249 #endif
1250 struct resolv_header h;
1251 struct resolv_question q;
1252 struct resolv_answer ma;
1253 bool first_answer = 1;
1254 int retries_left;
1255 unsigned char *packet = malloc(PACKETSZ);
1256 char *lookup;
1257 int variant = -1; /* search domain to append, -1: none */
1258 int local_ns_num = -1; /* Nth server to use */
1259 int local_id = local_id; /* for compiler */
1260 int sdomains;
1261 bool ends_with_dot;
1262 sockaddr46_t sa;
1264 fd = -1;
1265 lookup = NULL;
1266 name_len = strlen(name);
1267 if ((unsigned)name_len >= MAXDNAME - MAXLEN_searchdomain - 2)
1268 goto fail; /* paranoia */
1269 lookup = malloc(name_len + 1/*for '.'*/ + MAXLEN_searchdomain + 1);
1270 if (!packet || !lookup || !name[0])
1271 goto fail;
1272 ends_with_dot = (name[name_len - 1] == '.');
1273 /* no strcpy! paranoia, user might change name[] under us */
1274 memcpy(lookup, name, name_len);
1276 DPRINTF("Looking up type %d answer for '%s'\n", type, name);
1277 retries_left = 0; /* for compiler */
1278 do {
1279 int pos;
1280 unsigned reply_timeout;
1282 if (fd != -1) {
1283 close(fd);
1284 fd = -1;
1287 /* Mess with globals while under lock */
1288 /* NB: even data *pointed to* by globals may vanish
1289 * outside the locks. We should assume any and all
1290 * globals can completely change between locked
1291 * code regions. OTOH, this is rare, so we don't need
1292 * to handle it "nicely" (do not skip servers,
1293 * search domains, etc), we only need to ensure
1294 * we do not SEGV, use freed+overwritten data
1295 * or do other Really Bad Things. */
1296 __UCLIBC_MUTEX_LOCK(__resolv_lock);
1297 __open_nameservers();
1298 sdomains = __searchdomains;
1299 lookup[name_len] = '\0';
1300 if ((unsigned)variant < sdomains) {
1301 /* lookup is name_len + 1 + MAXLEN_searchdomain + 1 long */
1302 /* __searchdomain[] is not bigger than MAXLEN_searchdomain */
1303 lookup[name_len] = '.';
1304 strcpy(&lookup[name_len + 1], __searchdomain[variant]);
1306 /* first time? pick starting server etc */
1307 if (local_ns_num < 0) {
1308 local_id = last_id;
1309 /*TODO: implement /etc/resolv.conf's "options rotate"
1310 (a.k.a. RES_ROTATE bit in _res.options)
1311 local_ns_num = 0;
1312 if (_res.options & RES_ROTATE) */
1313 local_ns_num = last_ns_num;
1314 retries_left = __nameservers * __resolv_attempts;
1316 retries_left--;
1317 if (local_ns_num >= __nameservers)
1318 local_ns_num = 0;
1319 local_id++;
1320 local_id &= 0xffff;
1321 /* write new values back while still under lock */
1322 last_id = local_id;
1323 last_ns_num = local_ns_num;
1324 /* struct copy */
1325 /* can't just take a pointer, __nameserver[x]
1326 * is not safe to use outside of locks */
1327 sa = __nameserver[local_ns_num];
1328 __UCLIBC_MUTEX_UNLOCK(__resolv_lock);
1330 memset(packet, 0, PACKETSZ);
1331 memset(&h, 0, sizeof(h));
1333 /* encode header */
1334 h.id = local_id;
1335 h.qdcount = 1;
1336 h.rd = 1;
1337 DPRINTF("encoding header\n", h.rd);
1338 i = __encode_header(&h, packet, PACKETSZ);
1339 if (i < 0)
1340 goto fail;
1342 /* encode question */
1343 DPRINTF("lookup name: %s\n", lookup);
1344 q.dotted = lookup;
1345 q.qtype = type;
1346 q.qclass = C_IN; /* CLASS_IN */
1347 j = __encode_question(&q, packet+i, PACKETSZ-i);
1348 if (j < 0)
1349 goto fail;
1350 packet_len = i + j;
1352 /* send packet */
1353 #ifdef DEBUG
1355 const socklen_t plen = sa.sa.sa_family == AF_INET ? INET_ADDRSTRLEN : INET6_ADDRSTRLEN;
1356 char *pbuf = malloc(plen);
1357 if (pbuf == NULL) ;/* nothing */
1358 #ifdef __UCLIBC_HAS_IPV6__
1359 else if (sa.sa.sa_family == AF_INET6)
1360 pbuf = (char*)inet_ntop(AF_INET6, &sa.sa6.sin6_addr, pbuf, plen);
1361 #endif
1362 #ifdef __UCLIBC_HAS_IPV4__
1363 else if (sa.sa.sa_family == AF_INET)
1364 pbuf = (char*)inet_ntop(AF_INET, &sa.sa4.sin_addr, pbuf, plen);
1365 #endif
1366 DPRINTF("On try %d, sending query to %s, port %d\n",
1367 retries_left, pbuf, NAMESERVER_PORT);
1368 free(pbuf);
1370 #endif
1371 fd = socket(sa.sa.sa_family, SOCK_DGRAM, IPPROTO_UDP);
1372 if (fd < 0) /* paranoia */
1373 goto try_next_server;
1374 rc = connect(fd, &sa.sa, sizeof(sa));
1375 if (rc < 0) {
1376 /*if (errno == ENETUNREACH) { */
1377 /* routing error, presume not transient */
1378 goto try_next_server;
1379 /*} */
1380 /*For example, what transient error this can be? Can't think of any */
1381 /* retry */
1382 /*continue; */
1384 DPRINTF("Xmit packet len:%d id:%d qr:%d\n", packet_len, h.id, h.qr);
1385 /* no error check - if it fails, we time out on recv */
1386 send(fd, packet, packet_len, 0);
1388 #ifdef USE_SELECT
1389 reply_timeout = __resolv_timeout;
1390 wait_again:
1391 FD_ZERO(&fds);
1392 FD_SET(fd, &fds);
1393 tv.tv_sec = reply_timeout;
1394 tv.tv_usec = 0;
1395 if (select(fd + 1, &fds, NULL, NULL, &tv) <= 0) {
1396 DPRINTF("Timeout\n");
1397 /* timed out, so retry send and receive
1398 * to next nameserver */
1399 goto try_next_server;
1401 reply_timeout--;
1402 #else /* !USE_SELECT */
1403 reply_timeout = __resolv_timeout * 1000;
1404 wait_again:
1405 fds.fd = fd;
1406 fds.events = POLLIN;
1407 if (poll(&fds, 1, reply_timeout) <= 0) {
1408 DPRINTF("Timeout\n");
1409 /* timed out, so retry send and receive
1410 * to next nameserver */
1411 goto try_next_server;
1413 /*TODO: better timeout accounting?*/
1414 reply_timeout -= 1000;
1415 #endif /* USE_SELECT */
1417 /* vda: a bogus response seen in real world (caused SEGV in uclibc):
1418 * "ping www.google.com" sending AAAA query and getting
1419 * response with one answer... with answer part missing!
1420 * Fixed by thorough checks for not going past the packet's end.
1422 #ifdef DEBUG
1424 static const char test_query[32] = "\0\2\1\0\0\1\0\0\0\0\0\0\3www\6google\3com\0\0\34\0\1";
1425 static const char test_respn[32] = "\0\2\201\200\0\1\0\1\0\0\0\0\3www\6google\3com\0\0\34\0\1";
1426 pos = memcmp(packet + 2, test_query + 2, 30);
1427 packet_len = recv(fd, packet, PACKETSZ, MSG_DONTWAIT);
1428 if (pos == 0) {
1429 packet_len = 32;
1430 memcpy(packet + 2, test_respn + 2, 30);
1433 #else
1434 packet_len = recv(fd, packet, PACKETSZ, MSG_DONTWAIT);
1435 #endif
1437 if (packet_len < HFIXEDSZ) {
1438 /* too short!
1439 * If the peer did shutdown then retry later,
1440 * try next peer on error.
1441 * it's just a bogus packet from somewhere */
1442 bogus_packet:
1443 if (packet_len >= 0 && reply_timeout)
1444 goto wait_again;
1445 goto try_next_server;
1447 __decode_header(packet, &h);
1448 DPRINTF("len:%d id:%d qr:%d\n", packet_len, h.id, h.qr);
1449 if (h.id != local_id || !h.qr) {
1450 /* unsolicited */
1451 goto bogus_packet;
1454 DPRINTF("Got response (i think)!\n");
1455 DPRINTF("qrcount=%d,ancount=%d,nscount=%d,arcount=%d\n",
1456 h.qdcount, h.ancount, h.nscount, h.arcount);
1457 DPRINTF("opcode=%d,aa=%d,tc=%d,rd=%d,ra=%d,rcode=%d\n",
1458 h.opcode, h.aa, h.tc, h.rd, h.ra, h.rcode);
1460 /* bug 660 says we treat negative response as an error
1461 * and retry, which is, eh, an error. :)
1462 * We were incurring long delays because of this. */
1463 if (h.rcode == NXDOMAIN || h.rcode == SERVFAIL) {
1464 /* if possible, try next search domain */
1465 if (!ends_with_dot) {
1466 DPRINTF("variant:%d sdomains:%d\n", variant, sdomains);
1467 if (variant < sdomains - 1) {
1468 /* next search domain */
1469 variant++;
1470 continue;
1472 /* no more search domains to try */
1474 if (h.rcode != SERVFAIL) {
1475 /* dont loop, this is "no such host" situation */
1476 h_errno = HOST_NOT_FOUND;
1477 goto fail1;
1480 /* Insert other non-fatal errors here, which do not warrant
1481 * switching to next nameserver */
1483 /* Strange error, assuming this nameserver is feeling bad */
1484 if (h.rcode != 0)
1485 goto try_next_server;
1487 /* Code below won't work correctly with h.ancount == 0, so... */
1488 if (h.ancount <= 0) {
1489 h_errno = NO_DATA; /* [is this correct code to check for?] */
1490 goto fail1;
1492 pos = HFIXEDSZ;
1493 for (j = 0; j < h.qdcount; j++) {
1494 DPRINTF("Skipping question %d at %d\n", j, pos);
1495 i = __length_question(packet + pos, packet_len - pos);
1496 if (i < 0) {
1497 DPRINTF("Packet'question section "
1498 "is truncated, trying next server\n");
1499 goto try_next_server;
1501 pos += i;
1502 DPRINTF("Length of question %d is %d\n", j, i);
1504 DPRINTF("Decoding answer at pos %d\n", pos);
1506 first_answer = 1;
1507 a->dotted = NULL;
1508 for (j = 0; j < h.ancount; j++) {
1509 i = __decode_answer(packet, pos, packet_len, &ma);
1510 if (i < 0) {
1511 DPRINTF("failed decode %d\n", i);
1512 /* If the message was truncated but we have
1513 * decoded some answers, pretend it's OK */
1514 if (j && h.tc)
1515 break;
1516 goto try_next_server;
1518 pos += i;
1520 if (first_answer) {
1521 ma.buf = a->buf;
1522 ma.buflen = a->buflen;
1523 ma.add_count = a->add_count;
1524 free(a->dotted);
1525 memcpy(a, &ma, sizeof(ma));
1526 if (a->atype != T_SIG && (NULL == a->buf || (type != T_A && type != T_AAAA)))
1527 break;
1528 if (a->atype != type)
1529 continue;
1530 a->add_count = h.ancount - j - 1;
1531 if ((a->rdlength + sizeof(struct in_addr*)) * a->add_count > a->buflen)
1532 break;
1533 a->add_count = 0;
1534 first_answer = 0;
1535 } else {
1536 free(ma.dotted);
1537 if (ma.atype != type)
1538 continue;
1539 if (a->rdlength != ma.rdlength) {
1540 free(a->dotted);
1541 DPRINTF("Answer address len(%u) differs from original(%u)\n",
1542 ma.rdlength, a->rdlength);
1543 goto try_next_server;
1545 memcpy(a->buf + (a->add_count * ma.rdlength), ma.rdata, ma.rdlength);
1546 ++a->add_count;
1550 /* Success! */
1551 DPRINTF("Answer name = |%s|\n", a->dotted);
1552 DPRINTF("Answer type = |%d|\n", a->atype);
1553 if (fd != -1)
1554 close(fd);
1555 if (outpacket)
1556 *outpacket = packet;
1557 else
1558 free(packet);
1559 free(lookup);
1560 return packet_len;
1562 try_next_server:
1563 /* Try next nameserver */
1564 local_ns_num++;
1565 variant = -1;
1566 } while (retries_left > 0);
1568 fail:
1569 h_errno = NETDB_INTERNAL;
1570 fail1:
1571 if (fd != -1)
1572 close(fd);
1573 free(lookup);
1574 free(packet);
1575 return -1;
1577 #endif /* L_dnslookup */
1580 #ifdef L_read_etc_hosts_r
1582 parser_t * __open_etc_hosts(void)
1584 parser_t *parser;
1585 parser = config_open("/etc/hosts");
1586 #ifdef FALLBACK_TO_CONFIG_RESOLVCONF
1587 if (parser == NULL)
1588 parser = config_open("/etc/config/hosts");
1589 #endif
1590 return parser;
1593 #define MINTOKENS 2 /* ip address + canonical name */
1594 #define MAXTOKENS (MINTOKENS + MAXALIASES)
1595 #define HALISTOFF (sizeof(char*) * MAXTOKENS)
1596 #define INADDROFF (HALISTOFF + 2 * sizeof(char*))
1598 int __read_etc_hosts_r(
1599 parser_t * parser,
1600 const char *name,
1601 int type,
1602 enum etc_hosts_action action,
1603 struct hostent *result_buf,
1604 char *buf, size_t buflen,
1605 struct hostent **result,
1606 int *h_errnop)
1608 char **tok = NULL;
1609 struct in_addr *h_addr0 = NULL;
1610 const size_t aliaslen = INADDROFF +
1611 #ifdef __UCLIBC_HAS_IPV6__
1612 sizeof(struct in6_addr)
1613 #else
1614 sizeof(struct in_addr)
1615 #endif
1617 int ret = HOST_NOT_FOUND;
1618 /* make sure pointer is aligned */
1619 int i = ALIGN_BUFFER_OFFSET(buf);
1620 buf += i;
1621 buflen -= i;
1623 *h_errnop = NETDB_INTERNAL;
1624 if (/* (ssize_t)buflen < 0 || */ buflen < aliaslen
1625 || (buflen - aliaslen) < BUFSZ + 1)
1626 return ERANGE;
1627 if (parser == NULL)
1628 parser = __open_etc_hosts();
1629 if (parser == NULL) {
1630 *result = NULL;
1631 return errno;
1633 /* Layout in buf:
1634 * char *alias[MAXTOKENS] = {address, name, aliases...}
1635 * char **h_addr_list[1] = {*in[6]_addr, NULL}
1636 * struct in[6]_addr
1637 * char line_buffer[BUFSZ+];
1639 parser->data = buf;
1640 parser->data_len = aliaslen;
1641 parser->line_len = buflen - aliaslen;
1642 *h_errnop = HOST_NOT_FOUND;
1643 /* <ip>[[:space:]][<aliases>] */
1644 while (config_read(parser, &tok, MAXTOKENS, MINTOKENS, "# \t", PARSE_NORMAL)) {
1645 result_buf->h_aliases = tok+1;
1646 if (action == GETHOSTENT) {
1647 /* Return whatever the next entry happens to be. */
1648 break;
1650 if (action == GET_HOSTS_BYADDR) {
1651 if (strcmp(name, *tok) != 0)
1652 continue;
1653 } else { /* GET_HOSTS_BYNAME */
1654 int aliases = 0;
1655 char **alias = tok + 1;
1656 while (aliases < MAXALIASES) {
1657 char *tmp = *(alias+aliases++);
1658 if (tmp && strcasecmp(name, tmp) == 0)
1659 goto found;
1661 continue;
1663 found:
1664 result_buf->h_name = *(result_buf->h_aliases++);
1665 result_buf->h_addr_list = (char**)(buf + HALISTOFF);
1666 *(result_buf->h_addr_list + 1) = '\0';
1667 h_addr0 = (struct in_addr*)(buf + INADDROFF);
1668 result_buf->h_addr = (char*)h_addr0;
1669 if (0) /* nothing */;
1670 #ifdef __UCLIBC_HAS_IPV4__
1671 else if (type == AF_INET
1672 && inet_pton(AF_INET, *tok, h_addr0) > 0) {
1673 DPRINTF("Found INET\n");
1674 result_buf->h_addrtype = AF_INET;
1675 result_buf->h_length = sizeof(struct in_addr);
1676 *result = result_buf;
1677 ret = NETDB_SUCCESS;
1679 #endif
1680 #ifdef __UCLIBC_HAS_IPV6__
1681 #define in6 ((struct in6_addr *)buf)
1682 else if (type == AF_INET6
1683 && inet_pton(AF_INET6, *tok, h_addr0) > 0) {
1684 DPRINTF("Found INET6\n");
1685 result_buf->h_addrtype = AF_INET6;
1686 result_buf->h_length = sizeof(struct in6_addr);
1687 *result = result_buf;
1688 ret = NETDB_SUCCESS;
1690 #endif
1691 else {
1692 /* continue parsing in the hope the user has multiple
1693 * host types listed in the database like so:
1694 * <ipv4 addr> host
1695 * <ipv6 addr> host
1696 * If looking for an IPv6 addr, don't bail when we got the IPv4
1698 DPRINTF("Error: Found host but different address family\n");
1699 /* NB: gethostbyname2_r depends on this feature
1700 * to avoid looking for IPv6 addr of "localhost" etc */
1701 ret = TRY_AGAIN;
1702 continue;
1704 break;
1706 if (action != GETHOSTENT)
1707 config_close(parser);
1708 return ret;
1709 #undef in6
1711 #endif /* L_read_etc_hosts_r */
1714 #ifdef L_get_hosts_byname_r
1716 int __get_hosts_byname_r(const char *name,
1717 int type,
1718 struct hostent *result_buf,
1719 char *buf,
1720 size_t buflen,
1721 struct hostent **result,
1722 int *h_errnop)
1724 return __read_etc_hosts_r(NULL, name, type, GET_HOSTS_BYNAME,
1725 result_buf, buf, buflen, result, h_errnop);
1727 #endif /* L_get_hosts_byname_r */
1730 #ifdef L_get_hosts_byaddr_r
1732 int __get_hosts_byaddr_r(const char *addr,
1733 int len,
1734 int type,
1735 struct hostent *result_buf,
1736 char *buf,
1737 size_t buflen,
1738 struct hostent **result,
1739 int *h_errnop)
1741 #ifndef __UCLIBC_HAS_IPV6__
1742 char ipaddr[INET_ADDRSTRLEN];
1743 #else
1744 char ipaddr[INET6_ADDRSTRLEN];
1745 #endif
1747 switch (type) {
1748 #ifdef __UCLIBC_HAS_IPV4__
1749 case AF_INET:
1750 if (len != sizeof(struct in_addr))
1751 return 0;
1752 break;
1753 #endif
1754 #ifdef __UCLIBC_HAS_IPV6__
1755 case AF_INET6:
1756 if (len != sizeof(struct in6_addr))
1757 return 0;
1758 break;
1759 #endif
1760 default:
1761 return 0;
1764 inet_ntop(type, addr, ipaddr, sizeof(ipaddr));
1766 return __read_etc_hosts_r(NULL, ipaddr, type, GET_HOSTS_BYADDR,
1767 result_buf, buf, buflen, result, h_errnop);
1769 #endif /* L_get_hosts_byaddr_r */
1772 #ifdef L_getnameinfo
1774 int getnameinfo(const struct sockaddr *sa,
1775 socklen_t addrlen,
1776 char *host,
1777 socklen_t hostlen,
1778 char *serv,
1779 socklen_t servlen,
1780 unsigned flags)
1782 int serrno = errno;
1783 bool ok = 0;
1784 struct hostent *hoste = NULL;
1785 char domain[256];
1787 if (flags & ~(NI_NUMERICHOST|NI_NUMERICSERV|NI_NOFQDN|NI_NAMEREQD|NI_DGRAM))
1788 return EAI_BADFLAGS;
1790 if (sa == NULL || addrlen < sizeof(sa_family_t))
1791 return EAI_FAMILY;
1793 if (sa->sa_family == AF_LOCAL) /* valid */;
1794 #ifdef __UCLIBC_HAS_IPV4__
1795 else if (sa->sa_family == AF_INET) {
1796 if (addrlen < sizeof(struct sockaddr_in))
1797 return EAI_FAMILY;
1799 #endif
1800 #ifdef __UCLIBC_HAS_IPV6__
1801 else if (sa->sa_family == AF_INET6) {
1802 if (addrlen < sizeof(struct sockaddr_in6))
1803 return EAI_FAMILY;
1805 #endif
1806 else
1807 return EAI_FAMILY;
1809 if (host != NULL && hostlen > 0)
1810 switch (sa->sa_family) {
1811 case AF_INET:
1812 #ifdef __UCLIBC_HAS_IPV6__
1813 case AF_INET6:
1814 #endif
1815 if (!(flags & NI_NUMERICHOST)) {
1816 if (0) /* nothing */;
1817 #ifdef __UCLIBC_HAS_IPV6__
1818 else if (sa->sa_family == AF_INET6)
1819 hoste = gethostbyaddr((const void *)
1820 &(((const struct sockaddr_in6 *) sa)->sin6_addr),
1821 sizeof(struct in6_addr), AF_INET6);
1822 #endif
1823 #ifdef __UCLIBC_HAS_IPV4__
1824 else
1825 hoste = gethostbyaddr((const void *)
1826 &(((const struct sockaddr_in *)sa)->sin_addr),
1827 sizeof(struct in_addr), AF_INET);
1828 #endif
1830 if (hoste) {
1831 char *c;
1832 if ((flags & NI_NOFQDN)
1833 && (getdomainname(domain, sizeof(domain)) == 0)
1834 && (c = strstr(hoste->h_name, domain)) != NULL
1835 && (c != hoste->h_name) && (*(--c) == '.')
1837 strncpy(host, hoste->h_name,
1838 MIN(hostlen, (size_t) (c - hoste->h_name)));
1839 host[MIN(hostlen - 1, (size_t) (c - hoste->h_name))] = '\0';
1840 } else {
1841 strncpy(host, hoste->h_name, hostlen);
1843 ok = 1;
1847 if (!ok) {
1848 const char *c = NULL;
1850 if (flags & NI_NAMEREQD) {
1851 errno = serrno;
1852 return EAI_NONAME;
1854 if (0) /* nothing */;
1855 #ifdef __UCLIBC_HAS_IPV6__
1856 else if (sa->sa_family == AF_INET6) {
1857 const struct sockaddr_in6 *sin6p;
1859 sin6p = (const struct sockaddr_in6 *) sa;
1860 c = inet_ntop(AF_INET6,
1861 (const void *) &sin6p->sin6_addr,
1862 host, hostlen);
1863 #if 0
1864 /* Does scope id need to be supported? */
1865 uint32_t scopeid;
1866 scopeid = sin6p->sin6_scope_id;
1867 if (scopeid != 0) {
1868 /* Buffer is >= IFNAMSIZ+1. */
1869 char scopebuf[IFNAMSIZ + 1];
1870 char *scopeptr;
1871 int ni_numericscope = 0;
1872 size_t real_hostlen = strnlen(host, hostlen);
1873 size_t scopelen = 0;
1875 scopebuf[0] = SCOPE_DELIMITER;
1876 scopebuf[1] = '\0';
1877 scopeptr = &scopebuf[1];
1879 if (IN6_IS_ADDR_LINKLOCAL(&sin6p->sin6_addr)
1880 || IN6_IS_ADDR_MC_LINKLOCAL(&sin6p->sin6_addr)) {
1881 if (if_indextoname(scopeid, scopeptr) == NULL)
1882 ++ni_numericscope;
1883 else
1884 scopelen = strlen(scopebuf);
1885 } else {
1886 ++ni_numericscope;
1889 if (ni_numericscope)
1890 scopelen = 1 + snprintf(scopeptr,
1891 (scopebuf
1892 + sizeof scopebuf
1893 - scopeptr),
1894 "%u", scopeid);
1896 if (real_hostlen + scopelen + 1 > hostlen)
1897 return EAI_SYSTEM;
1898 memcpy(host + real_hostlen, scopebuf, scopelen + 1);
1900 #endif
1902 #endif /* __UCLIBC_HAS_IPV6__ */
1903 #if defined __UCLIBC_HAS_IPV4__
1904 else {
1905 c = inet_ntop(AF_INET, (const void *)
1906 &(((const struct sockaddr_in *) sa)->sin_addr),
1907 host, hostlen);
1909 #endif
1910 if (c == NULL) {
1911 errno = serrno;
1912 return EAI_SYSTEM;
1914 ok = 1;
1916 break;
1918 case AF_LOCAL:
1919 if (!(flags & NI_NUMERICHOST)) {
1920 struct utsname utsname;
1922 if (!uname(&utsname)) {
1923 strncpy(host, utsname.nodename, hostlen);
1924 break;
1928 if (flags & NI_NAMEREQD) {
1929 errno = serrno;
1930 return EAI_NONAME;
1933 strncpy(host, "localhost", hostlen);
1934 break;
1935 /* Already checked above
1936 default:
1937 return EAI_FAMILY;
1941 if (serv && (servlen > 0)) {
1942 if (sa->sa_family == AF_LOCAL) {
1943 strncpy(serv, ((const struct sockaddr_un *) sa)->sun_path, servlen);
1944 } else { /* AF_INET || AF_INET6 */
1945 if (!(flags & NI_NUMERICSERV)) {
1946 struct servent *s;
1947 s = getservbyport(((const struct sockaddr_in *) sa)->sin_port,
1948 ((flags & NI_DGRAM) ? "udp" : "tcp"));
1949 if (s) {
1950 strncpy(serv, s->s_name, servlen);
1951 goto DONE;
1954 snprintf(serv, servlen, "%d",
1955 ntohs(((const struct sockaddr_in *) sa)->sin_port));
1958 DONE:
1959 if (host && (hostlen > 0))
1960 host[hostlen-1] = 0;
1961 if (serv && (servlen > 0))
1962 serv[servlen-1] = 0;
1963 errno = serrno;
1964 return 0;
1966 libc_hidden_def(getnameinfo)
1967 #endif /* L_getnameinfo */
1970 #ifdef L_gethostbyname_r
1972 /* Bug 671 says:
1973 * "uClibc resolver's gethostbyname does not return the requested name
1974 * as an alias, but instead returns the canonical name. glibc's
1975 * gethostbyname has a similar bug where it returns the requested name
1976 * with the search domain name appended (to make a FQDN) as an alias,
1977 * but not the original name itself. Both contradict POSIX, which says
1978 * that the name argument passed to gethostbyname must be in the alias list"
1979 * This is fixed now, and we differ from glibc:
1981 * $ ./gethostbyname_uclibc wer.google.com
1982 * h_name:'c13-ss-2-lb.cnet.com'
1983 * h_length:4
1984 * h_addrtype:2 AF_INET
1985 * alias:'wer.google.com' <===
1986 * addr: 0x4174efd8 '216.239.116.65'
1988 * $ ./gethostbyname_glibc wer.google.com
1989 * h_name:'c13-ss-2-lb.cnet.com'
1990 * h_length:4
1991 * h_addrtype:2 AF_INET
1992 * alias:'wer.google.com.com' <===
1993 * addr:'216.239.116.65'
1995 * When examples were run, /etc/resolv.conf contained "search com" line.
1997 int gethostbyname_r(const char *name,
1998 struct hostent *result_buf,
1999 char *buf,
2000 size_t buflen,
2001 struct hostent **result,
2002 int *h_errnop)
2004 struct in_addr **addr_list;
2005 char **alias;
2006 char *alias0;
2007 unsigned char *packet;
2008 struct resolv_answer a;
2009 int i;
2010 int packet_len;
2011 int wrong_af = 0;
2013 *result = NULL;
2014 if (!name)
2015 return EINVAL;
2017 /* do /etc/hosts first */
2019 int old_errno = errno; /* save the old errno and reset errno */
2020 __set_errno(0); /* to check for missing /etc/hosts. */
2021 i = __get_hosts_byname_r(name, AF_INET, result_buf,
2022 buf, buflen, result, h_errnop);
2023 if (i == NETDB_SUCCESS) {
2024 __set_errno(old_errno);
2025 return i;
2027 switch (*h_errnop) {
2028 case HOST_NOT_FOUND:
2029 wrong_af = (i == TRY_AGAIN);
2030 case NO_ADDRESS:
2031 break;
2032 case NETDB_INTERNAL:
2033 if (errno == ENOENT) {
2034 break;
2036 /* else fall through */
2037 default:
2038 return i;
2040 __set_errno(old_errno);
2043 DPRINTF("Nothing found in /etc/hosts\n");
2045 *h_errnop = NETDB_INTERNAL;
2047 /* prepare future h_aliases[0] */
2048 i = strlen(name) + 1;
2049 if ((ssize_t)buflen <= i)
2050 return ERANGE;
2051 memcpy(buf, name, i); /* paranoia: name might change */
2052 alias0 = buf;
2053 buf += i;
2054 buflen -= i;
2055 /* make sure pointer is aligned */
2056 i = ALIGN_BUFFER_OFFSET(buf);
2057 buf += i;
2058 buflen -= i;
2059 /* Layout in buf:
2060 * char *alias[2];
2061 * struct in_addr* addr_list[NN+1];
2062 * struct in_addr* in[NN];
2064 alias = (char **)buf;
2065 buf += sizeof(alias[0]) * 2;
2066 buflen -= sizeof(alias[0]) * 2;
2067 addr_list = (struct in_addr **)buf;
2068 /* buflen may be < 0, must do signed compare */
2069 if ((ssize_t)buflen < 256)
2070 return ERANGE;
2072 /* we store only one "alias" - the name itself */
2073 #ifdef __UCLIBC_MJN3_ONLY__
2074 #warning TODO -- generate the full list
2075 #endif
2076 alias[0] = alias0;
2077 alias[1] = NULL;
2079 /* maybe it is already an address? */
2081 struct in_addr *in = (struct in_addr *)(buf + sizeof(addr_list[0]) * 2);
2082 if (inet_aton(name, in)) {
2083 addr_list[0] = in;
2084 addr_list[1] = NULL;
2085 result_buf->h_name = alias0;
2086 result_buf->h_aliases = alias;
2087 result_buf->h_addrtype = AF_INET;
2088 result_buf->h_length = sizeof(struct in_addr);
2089 result_buf->h_addr_list = (char **) addr_list;
2090 *result = result_buf;
2091 *h_errnop = NETDB_SUCCESS;
2092 return NETDB_SUCCESS;
2096 /* what if /etc/hosts has it but it's not IPv4?
2097 * F.e. "::1 localhost6". We don't do DNS query for such hosts -
2098 * "ping localhost6" should be fast even if DNS server is down! */
2099 if (wrong_af) {
2100 *h_errnop = HOST_NOT_FOUND;
2101 return TRY_AGAIN;
2104 /* talk to DNS servers */
2105 a.buf = buf;
2106 /* take into account that at least one address will be there,
2107 * we'll need space for one in_addr + two addr_list[] elems */
2108 a.buflen = buflen - ((sizeof(addr_list[0]) * 2 + sizeof(struct in_addr)));
2109 a.add_count = 0;
2110 packet_len = __dns_lookup(name, T_A, &packet, &a);
2111 if (packet_len < 0) {
2112 *h_errnop = HOST_NOT_FOUND;
2113 DPRINTF("__dns_lookup returned < 0\n");
2114 return TRY_AGAIN;
2117 if (a.atype == T_A) { /* ADDRESS */
2118 /* we need space for addr_list[] and one IPv4 address */
2119 /* + 1 accounting for 1st addr (it's in a.rdata),
2120 * another + 1 for NULL in last addr_list[]: */
2121 int need_bytes = sizeof(addr_list[0]) * (a.add_count + 1 + 1)
2122 /* for 1st addr (it's in a.rdata): */
2123 + sizeof(struct in_addr);
2124 /* how many bytes will 2nd and following addresses take? */
2125 int ips_len = a.add_count * a.rdlength;
2127 buflen -= (need_bytes + ips_len);
2128 if ((ssize_t)buflen < 0) {
2129 DPRINTF("buffer too small for all addresses\n");
2130 /* *h_errnop = NETDB_INTERNAL; - already is */
2131 i = ERANGE;
2132 goto free_and_ret;
2135 /* if there are additional addresses in buf,
2136 * move them forward so that they are not destroyed */
2137 DPRINTF("a.add_count:%d a.rdlength:%d a.rdata:%p\n", a.add_count, a.rdlength, a.rdata);
2138 memmove(buf + need_bytes, buf, ips_len);
2140 /* 1st address is in a.rdata, insert it */
2141 buf += need_bytes - sizeof(struct in_addr);
2142 memcpy(buf, a.rdata, sizeof(struct in_addr));
2144 /* fill addr_list[] */
2145 for (i = 0; i <= a.add_count; i++) {
2146 addr_list[i] = (struct in_addr*)buf;
2147 buf += sizeof(struct in_addr);
2149 addr_list[i] = NULL;
2151 /* if we have enough space, we can report "better" name
2152 * (it may contain search domains attached by __dns_lookup,
2153 * or CNAME of the host if it is different from the name
2154 * we used to find it) */
2155 if (a.dotted && buflen > strlen(a.dotted)) {
2156 strcpy(buf, a.dotted);
2157 alias0 = buf;
2160 result_buf->h_name = alias0;
2161 result_buf->h_aliases = alias;
2162 result_buf->h_addrtype = AF_INET;
2163 result_buf->h_length = sizeof(struct in_addr);
2164 result_buf->h_addr_list = (char **) addr_list;
2165 *result = result_buf;
2166 *h_errnop = NETDB_SUCCESS;
2167 i = NETDB_SUCCESS;
2168 goto free_and_ret;
2171 *h_errnop = HOST_NOT_FOUND;
2172 __set_h_errno(HOST_NOT_FOUND);
2173 i = TRY_AGAIN;
2175 free_and_ret:
2176 free(a.dotted);
2177 free(packet);
2178 return i;
2180 libc_hidden_def(gethostbyname_r)
2181 link_warning(gethostbyname_r, "gethostbyname_r is obsolescent, use getnameinfo() instead.");
2182 #endif /* L_gethostbyname_r */
2185 #ifdef L_gethostbyname2_r
2187 int gethostbyname2_r(const char *name,
2188 int family,
2189 struct hostent *result_buf,
2190 char *buf,
2191 size_t buflen,
2192 struct hostent **result,
2193 int *h_errnop)
2195 #ifndef __UCLIBC_HAS_IPV6__
2196 return family == (AF_INET)
2197 ? gethostbyname_r(name, result_buf, buf, buflen, result, h_errnop)
2198 : HOST_NOT_FOUND;
2199 #else
2200 struct in6_addr *in;
2201 struct in6_addr **addr_list;
2202 unsigned char *packet;
2203 struct resolv_answer a;
2204 int i;
2205 int nest = 0;
2206 int wrong_af = 0;
2208 if (family == AF_INET)
2209 return gethostbyname_r(name, result_buf, buf, buflen, result, h_errnop);
2211 *result = NULL;
2212 if (family != AF_INET6)
2213 return EINVAL;
2215 if (!name)
2216 return EINVAL;
2218 /* do /etc/hosts first */
2220 int old_errno = errno; /* Save the old errno and reset errno */
2221 __set_errno(0); /* to check for missing /etc/hosts. */
2223 i = __get_hosts_byname_r(name, AF_INET6 /*family*/, result_buf,
2224 buf, buflen, result, h_errnop);
2225 if (i == NETDB_SUCCESS) {
2226 __set_errno(old_errno);
2227 return i;
2229 switch (*h_errnop) {
2230 case HOST_NOT_FOUND:
2231 wrong_af = (i == TRY_AGAIN);
2232 case NO_ADDRESS:
2233 break;
2234 case NETDB_INTERNAL:
2235 if (errno == ENOENT) {
2236 break;
2238 /* else fall through */
2239 default:
2240 return i;
2242 __set_errno(old_errno);
2244 DPRINTF("Nothing found in /etc/hosts\n");
2246 *h_errnop = NETDB_INTERNAL;
2248 /* make sure pointer is aligned */
2249 i = ALIGN_BUFFER_OFFSET(buf);
2250 buf += i;
2251 buflen -= i;
2252 /* Layout in buf:
2253 * struct in6_addr* in;
2254 * struct in6_addr* addr_list[2];
2255 * char scratch_buf[256];
2257 in = (struct in6_addr*)buf;
2258 buf += sizeof(*in);
2259 buflen -= sizeof(*in);
2260 addr_list = (struct in6_addr**)buf;
2261 buf += sizeof(*addr_list) * 2;
2262 buflen -= sizeof(*addr_list) * 2;
2263 if ((ssize_t)buflen < 256)
2264 return ERANGE;
2265 addr_list[0] = in;
2266 addr_list[1] = NULL;
2267 strncpy(buf, name, buflen);
2268 buf[buflen] = '\0';
2270 /* maybe it is already an address? */
2271 if (inet_pton(AF_INET6, name, in)) {
2272 result_buf->h_name = buf;
2273 result_buf->h_addrtype = AF_INET6;
2274 result_buf->h_length = sizeof(*in);
2275 result_buf->h_addr_list = (char **) addr_list;
2276 /* result_buf->h_aliases = ??? */
2277 *result = result_buf;
2278 *h_errnop = NETDB_SUCCESS;
2279 return NETDB_SUCCESS;
2282 /* what if /etc/hosts has it but it's not IPv6?
2283 * F.e. "127.0.0.1 localhost". We don't do DNS query for such hosts -
2284 * "ping localhost" should be fast even if DNS server is down! */
2285 if (wrong_af) {
2286 *h_errnop = HOST_NOT_FOUND;
2287 return TRY_AGAIN;
2290 /* talk to DNS servers */
2291 /* TODO: why it's so different from gethostbyname_r (IPv4 case)? */
2292 memset(&a, '\0', sizeof(a));
2293 for (;;) {
2294 int packet_len;
2296 /* Hmm why we memset(a) to zeros only once? */
2297 packet_len = __dns_lookup(buf, T_AAAA, &packet, &a);
2298 if (packet_len < 0) {
2299 *h_errnop = HOST_NOT_FOUND;
2300 return TRY_AGAIN;
2302 strncpy(buf, a.dotted, buflen);
2303 free(a.dotted);
2305 if (a.atype != T_CNAME)
2306 break;
2308 DPRINTF("Got a CNAME in gethostbyname()\n");
2309 if (++nest > MAX_RECURSE) {
2310 *h_errnop = NO_RECOVERY;
2311 return -1;
2313 i = __decode_dotted(packet, a.rdoffset, packet_len, buf, buflen);
2314 free(packet);
2315 if (i < 0) {
2316 *h_errnop = NO_RECOVERY;
2317 return -1;
2320 if (a.atype == T_AAAA) { /* ADDRESS */
2321 memcpy(in, a.rdata, sizeof(*in));
2322 result_buf->h_name = buf;
2323 result_buf->h_addrtype = AF_INET6;
2324 result_buf->h_length = sizeof(*in);
2325 result_buf->h_addr_list = (char **) addr_list;
2326 /* result_buf->h_aliases = ??? */
2327 free(packet);
2328 *result = result_buf;
2329 *h_errnop = NETDB_SUCCESS;
2330 return NETDB_SUCCESS;
2332 free(packet);
2333 *h_errnop = HOST_NOT_FOUND;
2334 return TRY_AGAIN;
2336 #endif /* __UCLIBC_HAS_IPV6__ */
2338 libc_hidden_def(gethostbyname2_r)
2339 #endif /* L_gethostbyname2_r */
2342 #ifdef L_gethostbyaddr_r
2344 int gethostbyaddr_r(const void *addr, socklen_t addrlen,
2345 int type,
2346 struct hostent *result_buf,
2347 char *buf, size_t buflen,
2348 struct hostent **result,
2349 int *h_errnop)
2352 struct in_addr *in;
2353 struct in_addr **addr_list;
2354 char **alias;
2355 unsigned char *packet;
2356 struct resolv_answer a;
2357 int i;
2358 int packet_len;
2359 int nest = 0;
2361 *result = NULL;
2362 if (!addr)
2363 return EINVAL;
2365 switch (type) {
2366 #ifdef __UCLIBC_HAS_IPV4__
2367 case AF_INET:
2368 if (addrlen != sizeof(struct in_addr))
2369 return EINVAL;
2370 break;
2371 #endif
2372 #ifdef __UCLIBC_HAS_IPV6__
2373 case AF_INET6:
2374 if (addrlen != sizeof(struct in6_addr))
2375 return EINVAL;
2376 break;
2377 #endif
2378 default:
2379 return EINVAL;
2382 /* do /etc/hosts first */
2383 i = __get_hosts_byaddr_r(addr, addrlen, type, result_buf,
2384 buf, buflen, result, h_errnop);
2385 if (i == 0)
2386 return i;
2387 switch (*h_errnop) {
2388 case HOST_NOT_FOUND:
2389 case NO_ADDRESS:
2390 break;
2391 default:
2392 return i;
2395 *h_errnop = NETDB_INTERNAL;
2397 /* make sure pointer is aligned */
2398 i = ALIGN_BUFFER_OFFSET(buf);
2399 buf += i;
2400 buflen -= i;
2401 /* Layout in buf:
2402 * char *alias[ALIAS_DIM];
2403 * struct in[6]_addr* addr_list[2];
2404 * struct in[6]_addr in;
2405 * char scratch_buffer[256+];
2407 #define in6 ((struct in6_addr *)in)
2408 alias = (char **)buf;
2409 addr_list = (struct in_addr**)buf;
2410 buf += sizeof(*addr_list) * 2;
2411 buflen -= sizeof(*addr_list) * 2;
2412 in = (struct in_addr*)buf;
2413 #ifndef __UCLIBC_HAS_IPV6__
2414 buf += sizeof(*in);
2415 buflen -= sizeof(*in);
2416 if (addrlen > sizeof(*in))
2417 return ERANGE;
2418 #else
2419 buf += sizeof(*in6);
2420 buflen -= sizeof(*in6);
2421 if (addrlen > sizeof(*in6))
2422 return ERANGE;
2423 #endif
2424 if ((ssize_t)buflen < 256)
2425 return ERANGE;
2426 alias[0] = buf;
2427 alias[1] = NULL;
2428 addr_list[0] = in;
2429 addr_list[1] = NULL;
2430 memcpy(in, addr, addrlen);
2432 if (0) /* nothing */;
2433 #ifdef __UCLIBC_HAS_IPV4__
2434 else IF_HAS_BOTH(if (type == AF_INET)) {
2435 unsigned char *tp = (unsigned char *)addr;
2436 sprintf(buf, "%u.%u.%u.%u.in-addr.arpa",
2437 tp[3], tp[2], tp[1], tp[0]);
2439 #endif
2440 #ifdef __UCLIBC_HAS_IPV6__
2441 else {
2442 char *dst = buf;
2443 unsigned char *tp = (unsigned char *)addr + addrlen - 1;
2444 do {
2445 dst += sprintf(dst, "%x.%x.", tp[0] & 0xf, tp[0] >> 4);
2446 tp--;
2447 } while (tp >= (unsigned char *)addr);
2448 strcpy(dst, "ip6.arpa");
2450 #endif
2452 memset(&a, '\0', sizeof(a));
2453 for (;;) {
2454 /* Hmm why we memset(a) to zeros only once? */
2455 packet_len = __dns_lookup(buf, T_PTR, &packet, &a);
2456 if (packet_len < 0) {
2457 *h_errnop = HOST_NOT_FOUND;
2458 return TRY_AGAIN;
2461 strncpy(buf, a.dotted, buflen);
2462 free(a.dotted);
2463 if (a.atype != T_CNAME)
2464 break;
2466 DPRINTF("Got a CNAME in gethostbyaddr()\n");
2467 if (++nest > MAX_RECURSE) {
2468 *h_errnop = NO_RECOVERY;
2469 return -1;
2471 /* Decode CNAME into buf, feed it to __dns_lookup() again */
2472 i = __decode_dotted(packet, a.rdoffset, packet_len, buf, buflen);
2473 free(packet);
2474 if (i < 0) {
2475 *h_errnop = NO_RECOVERY;
2476 return -1;
2480 if (a.atype == T_PTR) { /* ADDRESS */
2481 i = __decode_dotted(packet, a.rdoffset, packet_len, buf, buflen);
2482 free(packet);
2483 result_buf->h_name = buf;
2484 result_buf->h_addrtype = type;
2485 result_buf->h_length = addrlen;
2486 result_buf->h_addr_list = (char **) addr_list;
2487 result_buf->h_aliases = alias;
2488 *result = result_buf;
2489 *h_errnop = NETDB_SUCCESS;
2490 return NETDB_SUCCESS;
2493 free(packet);
2494 *h_errnop = NO_ADDRESS;
2495 return TRY_AGAIN;
2496 #undef in6
2498 libc_hidden_def(gethostbyaddr_r)
2499 link_warning(gethostbyaddr_r, "gethostbyaddr_r is obsolescent, use getaddrinfo() instead.");
2500 #endif /* L_gethostbyaddr_r */
2503 #ifdef L_gethostent_r
2505 __UCLIBC_MUTEX_STATIC(mylock, PTHREAD_MUTEX_INITIALIZER);
2507 static parser_t *hostp = NULL;
2508 static smallint host_stayopen;
2510 void endhostent_unlocked(void)
2512 if (hostp) {
2513 config_close(hostp);
2514 hostp = NULL;
2516 host_stayopen = 0;
2518 void endhostent(void)
2520 __UCLIBC_MUTEX_LOCK(mylock);
2521 endhostent_unlocked();
2522 __UCLIBC_MUTEX_UNLOCK(mylock);
2525 void sethostent(int stay_open)
2527 __UCLIBC_MUTEX_LOCK(mylock);
2528 if (stay_open)
2529 host_stayopen = 1;
2530 __UCLIBC_MUTEX_UNLOCK(mylock);
2533 int gethostent_r(struct hostent *result_buf, char *buf, size_t buflen,
2534 struct hostent **result, int *h_errnop)
2536 int ret;
2538 __UCLIBC_MUTEX_LOCK(mylock);
2539 if (hostp == NULL) {
2540 hostp = __open_etc_hosts();
2541 if (hostp == NULL) {
2542 *result = NULL;
2543 ret = TRY_AGAIN;
2544 goto DONE;
2548 ret = __read_etc_hosts_r(hostp, NULL, AF_INET, GETHOSTENT,
2549 result_buf, buf, buflen, result, h_errnop);
2550 if (!host_stayopen)
2551 endhostent_unlocked();
2552 DONE:
2553 __UCLIBC_MUTEX_UNLOCK(mylock);
2554 return ret;
2556 libc_hidden_def(gethostent_r)
2557 #endif /* L_gethostent_r */
2560 #ifdef L_gethostent
2562 struct hostent *gethostent(void)
2564 static struct hostent hoste;
2565 static char buf[
2566 #ifndef __UCLIBC_HAS_IPV6__
2567 sizeof(struct in_addr) + sizeof(struct in_addr *) * 2 +
2568 #else
2569 sizeof(struct in6_addr) + sizeof(struct in6_addr *) * 2 +
2570 #endif /* __UCLIBC_HAS_IPV6__ */
2571 BUFSZ /*namebuffer*/ + 2 /* margin */];
2572 struct hostent *host;
2574 gethostent_r(&hoste, buf, sizeof(buf), &host, &h_errno);
2575 return host;
2577 #endif /* L_gethostent */
2580 #ifdef L_gethostbyname2
2582 struct hostent *gethostbyname2(const char *name, int family)
2584 #ifndef __UCLIBC_HAS_IPV6__
2585 return family == AF_INET ? gethostbyname(name) : (struct hostent*)NULL;
2586 #else
2587 static struct hostent hoste;
2588 static char buf[sizeof(struct in6_addr) +
2589 sizeof(struct in6_addr *) * 2 +
2590 /*sizeof(char *)*ALIAS_DIM +*/ 384/*namebuffer*/ + 32/* margin */];
2591 struct hostent *hp;
2593 gethostbyname2_r(name, family, &hoste, buf, sizeof(buf), &hp, &h_errno);
2594 return hp;
2595 #endif
2597 libc_hidden_def(gethostbyname2)
2598 #endif /* L_gethostbyname2 */
2601 #ifdef L_gethostbyname
2603 struct hostent *gethostbyname(const char *name)
2605 #ifndef __UCLIBC_HAS_IPV6__
2606 static struct hostent hoste;
2607 static char buf[sizeof(struct in_addr) +
2608 sizeof(struct in_addr *) * 2 +
2609 /*sizeof(char *)*ALIAS_DIM +*/ 384/*namebuffer*/ + 32/* margin */];
2610 struct hostent *hp;
2612 gethostbyname_r(name, &hoste, buf, sizeof(buf), &hp, &h_errno);
2613 return hp;
2614 #else
2615 return gethostbyname2(name, AF_INET);
2616 #endif
2618 libc_hidden_def(gethostbyname)
2619 link_warning(gethostbyname, "gethostbyname is obsolescent, use getnameinfo() instead.");
2620 #endif /* L_gethostbyname */
2623 #ifdef L_gethostbyaddr
2625 struct hostent *gethostbyaddr(const void *addr, socklen_t len, int type)
2627 static struct hostent hoste;
2628 static char buf[
2629 #ifndef __UCLIBC_HAS_IPV6__
2630 sizeof(struct in_addr) + sizeof(struct in_addr *)*2 +
2631 #else
2632 sizeof(struct in6_addr) + sizeof(struct in6_addr *)*2 +
2633 #endif /* __UCLIBC_HAS_IPV6__ */
2634 /*sizeof(char *)*ALIAS_DIM +*/ 384 /*namebuffer*/ + 32 /* margin */];
2635 struct hostent *hp;
2637 gethostbyaddr_r(addr, len, type, &hoste, buf, sizeof(buf), &hp, &h_errno);
2638 return hp;
2640 libc_hidden_def(gethostbyaddr)
2641 link_warning(gethostbyaddr, "gethostbyaddr is obsolescent, use getaddrinfo() instead.");
2642 #endif /* L_gethostbyaddr */
2645 #ifdef L_res_comp
2648 * Expand compressed domain name 'comp_dn' to full domain name.
2649 * 'msg' is a pointer to the begining of the message,
2650 * 'eomorig' points to the first location after the message,
2651 * 'exp_dn' is a pointer to a buffer of size 'length' for the result.
2652 * Return size of compressed name or -1 if there was an error.
2654 int dn_expand(const u_char *msg, const u_char *eom, const u_char *src,
2655 char *dst, int dstsiz)
2657 int n = ns_name_uncompress(msg, eom, src, dst, (size_t)dstsiz);
2659 if (n > 0 && dst[0] == '.')
2660 dst[0] = '\0';
2661 return n;
2663 libc_hidden_def(dn_expand)
2666 * Pack domain name 'exp_dn' in presentation form into 'comp_dn'.
2667 * Return the size of the compressed name or -1.
2668 * 'length' is the size of the array pointed to by 'comp_dn'.
2671 dn_comp(const char *src, u_char *dst, int dstsiz,
2672 u_char **dnptrs, u_char **lastdnptr)
2674 return ns_name_compress(src, dst, (size_t) dstsiz,
2675 (const u_char **) dnptrs,
2676 (const u_char **) lastdnptr);
2678 libc_hidden_def(dn_comp)
2679 #endif /* L_res_comp */
2682 #ifdef L_ns_name
2684 /* Thinking in noninternationalized USASCII (per the DNS spec),
2685 * is this character visible and not a space when printed ?
2687 static int printable(int ch)
2689 return (ch > 0x20 && ch < 0x7f);
2691 /* Thinking in noninternationalized USASCII (per the DNS spec),
2692 * is this characted special ("in need of quoting") ?
2694 static int special(int ch)
2696 switch (ch) {
2697 case 0x22: /* '"' */
2698 case 0x2E: /* '.' */
2699 case 0x3B: /* ';' */
2700 case 0x5C: /* '\\' */
2701 /* Special modifiers in zone files. */
2702 case 0x40: /* '@' */
2703 case 0x24: /* '$' */
2704 return 1;
2705 default:
2706 return 0;
2711 * ns_name_uncompress(msg, eom, src, dst, dstsiz)
2712 * Expand compressed domain name to presentation format.
2713 * return:
2714 * Number of bytes read out of `src', or -1 (with errno set).
2715 * note:
2716 * Root domain returns as "." not "".
2718 int ns_name_uncompress(const u_char *msg, const u_char *eom,
2719 const u_char *src, char *dst, size_t dstsiz)
2721 u_char tmp[NS_MAXCDNAME];
2722 int n;
2724 n = ns_name_unpack(msg, eom, src, tmp, sizeof tmp);
2725 if (n == -1)
2726 return -1;
2727 if (ns_name_ntop(tmp, dst, dstsiz) == -1)
2728 return -1;
2729 return n;
2731 libc_hidden_def(ns_name_uncompress)
2734 * ns_name_ntop(src, dst, dstsiz)
2735 * Convert an encoded domain name to printable ascii as per RFC1035.
2736 * return:
2737 * Number of bytes written to buffer, or -1 (with errno set)
2738 * notes:
2739 * The root is returned as "."
2740 * All other domains are returned in non absolute form
2742 int ns_name_ntop(const u_char *src, char *dst, size_t dstsiz)
2744 const u_char *cp;
2745 char *dn, *eom;
2746 u_char c;
2747 u_int n;
2749 cp = src;
2750 dn = dst;
2751 eom = dst + dstsiz;
2753 while ((n = *cp++) != 0) {
2754 if ((n & NS_CMPRSFLGS) != 0) {
2755 /* Some kind of compression pointer. */
2756 __set_errno(EMSGSIZE);
2757 return -1;
2759 if (dn != dst) {
2760 if (dn >= eom) {
2761 __set_errno(EMSGSIZE);
2762 return -1;
2764 *dn++ = '.';
2766 if (dn + n >= eom) {
2767 __set_errno(EMSGSIZE);
2768 return -1;
2770 for (; n > 0; n--) {
2771 c = *cp++;
2772 if (special(c)) {
2773 if (dn + 1 >= eom) {
2774 __set_errno(EMSGSIZE);
2775 return -1;
2777 *dn++ = '\\';
2778 *dn++ = (char)c;
2779 } else if (!printable(c)) {
2780 if (dn + 3 >= eom) {
2781 __set_errno(EMSGSIZE);
2782 return -1;
2784 *dn++ = '\\';
2785 *dn++ = "0123456789"[c / 100];
2786 c = c % 100;
2787 *dn++ = "0123456789"[c / 10];
2788 *dn++ = "0123456789"[c % 10];
2789 } else {
2790 if (dn >= eom) {
2791 __set_errno(EMSGSIZE);
2792 return -1;
2794 *dn++ = (char)c;
2798 if (dn == dst) {
2799 if (dn >= eom) {
2800 __set_errno(EMSGSIZE);
2801 return -1;
2803 *dn++ = '.';
2805 if (dn >= eom) {
2806 __set_errno(EMSGSIZE);
2807 return -1;
2809 *dn++ = '\0';
2810 return (dn - dst);
2812 libc_hidden_def(ns_name_ntop)
2814 static int encode_bitstring(const char **bp, const char *end,
2815 unsigned char **labelp,
2816 unsigned char ** dst,
2817 unsigned const char *eom)
2819 int afterslash = 0;
2820 const char *cp = *bp;
2821 unsigned char *tp;
2822 const char *beg_blen;
2823 int value = 0, count = 0, tbcount = 0, blen = 0;
2825 beg_blen = NULL;
2827 /* a bitstring must contain at least 2 characters */
2828 if (end - cp < 2)
2829 return EINVAL;
2831 /* XXX: currently, only hex strings are supported */
2832 if (*cp++ != 'x')
2833 return EINVAL;
2834 if (!isxdigit((unsigned char) *cp)) /*%< reject '\[x/BLEN]' */
2835 return EINVAL;
2837 for (tp = *dst + 1; cp < end && tp < eom; cp++) {
2838 unsigned char c = *cp;
2840 switch (c) {
2841 case ']': /*%< end of the bitstring */
2842 if (afterslash) {
2843 char *end_blen;
2844 if (beg_blen == NULL)
2845 return EINVAL;
2846 blen = (int)strtol(beg_blen, &end_blen, 10);
2847 if (*end_blen != ']')
2848 return EINVAL;
2850 if (count)
2851 *tp++ = ((value << 4) & 0xff);
2852 cp++; /*%< skip ']' */
2853 goto done;
2854 case '/':
2855 afterslash = 1;
2856 break;
2857 default:
2858 if (afterslash) {
2859 if (!__isdigit_char(c))
2860 return EINVAL;
2861 if (beg_blen == NULL) {
2862 if (c == '0') {
2863 /* blen never begings with 0 */
2864 return EINVAL;
2866 beg_blen = cp;
2868 } else {
2869 if (!__isdigit_char(c)) {
2870 c = c | 0x20; /* lowercase */
2871 c = c - 'a';
2872 if (c > 5) /* not a-f? */
2873 return EINVAL;
2874 c += 10 + '0';
2876 value <<= 4;
2877 value += (c - '0');
2878 count += 4;
2879 tbcount += 4;
2880 if (tbcount > 256)
2881 return EINVAL;
2882 if (count == 8) {
2883 *tp++ = value;
2884 count = 0;
2887 break;
2890 done:
2891 if (cp >= end || tp >= eom)
2892 return EMSGSIZE;
2895 * bit length validation:
2896 * If a <length> is present, the number of digits in the <bit-data>
2897 * MUST be just sufficient to contain the number of bits specified
2898 * by the <length>. If there are insignificant bits in a final
2899 * hexadecimal or octal digit, they MUST be zero.
2900 * RFC2673, Section 3.2.
2902 if (blen > 0) {
2903 int traillen;
2905 if (((blen + 3) & ~3) != tbcount)
2906 return EINVAL;
2907 traillen = tbcount - blen; /*%< between 0 and 3 */
2908 if (((value << (8 - traillen)) & 0xff) != 0)
2909 return EINVAL;
2911 else
2912 blen = tbcount;
2913 if (blen == 256)
2914 blen = 0;
2916 /* encode the type and the significant bit fields */
2917 **labelp = DNS_LABELTYPE_BITSTRING;
2918 **dst = blen;
2920 *bp = cp;
2921 *dst = tp;
2923 return 0;
2926 int ns_name_pton(const char *src, u_char *dst, size_t dstsiz)
2928 static const char digits[] = "0123456789";
2929 u_char *label, *bp, *eom;
2930 int c, n, escaped, e = 0;
2931 char *cp;
2933 escaped = 0;
2934 bp = dst;
2935 eom = dst + dstsiz;
2936 label = bp++;
2938 while ((c = *src++) != 0) {
2939 if (escaped) {
2940 if (c == '[') { /*%< start a bit string label */
2941 cp = strchr(src, ']');
2942 if (cp == NULL) {
2943 errno = EINVAL; /*%< ??? */
2944 return -1;
2946 e = encode_bitstring(&src, cp + 2,
2947 &label, &bp, eom);
2948 if (e != 0) {
2949 errno = e;
2950 return -1;
2952 escaped = 0;
2953 label = bp++;
2954 c = *src++;
2955 if (c == '\0')
2956 goto done;
2957 if (c != '.') {
2958 errno = EINVAL;
2959 return -1;
2961 continue;
2963 cp = strchr(digits, c);
2964 if (cp != NULL) {
2965 n = (cp - digits) * 100;
2966 c = *src++;
2967 if (c == '\0')
2968 goto ret_EMSGSIZE;
2969 cp = strchr(digits, c);
2970 if (cp == NULL)
2971 goto ret_EMSGSIZE;
2972 n += (cp - digits) * 10;
2973 c = *src++;
2974 if (c == '\0')
2975 goto ret_EMSGSIZE;
2976 cp = strchr(digits, c);
2977 if (cp == NULL)
2978 goto ret_EMSGSIZE;
2979 n += (cp - digits);
2980 if (n > 255)
2981 goto ret_EMSGSIZE;
2982 c = n;
2984 escaped = 0;
2985 } else if (c == '\\') {
2986 escaped = 1;
2987 continue;
2988 } else if (c == '.') {
2989 c = (bp - label - 1);
2990 if ((c & NS_CMPRSFLGS) != 0) { /*%< Label too big. */
2991 goto ret_EMSGSIZE;
2993 if (label >= eom) {
2994 goto ret_EMSGSIZE;
2996 *label = c;
2997 /* Fully qualified ? */
2998 if (*src == '\0') {
2999 if (c != 0) {
3000 if (bp >= eom) {
3001 goto ret_EMSGSIZE;
3003 *bp++ = '\0';
3005 if ((bp - dst) > MAXCDNAME) {
3006 goto ret_EMSGSIZE;
3009 return 1;
3011 if (c == 0 || *src == '.') {
3012 goto ret_EMSGSIZE;
3014 label = bp++;
3015 continue;
3017 if (bp >= eom) {
3018 goto ret_EMSGSIZE;
3020 *bp++ = (u_char)c;
3022 c = (bp - label - 1);
3023 if ((c & NS_CMPRSFLGS) != 0) { /*%< Label too big. */
3024 goto ret_EMSGSIZE;
3026 done:
3027 if (label >= eom) {
3028 goto ret_EMSGSIZE;
3030 *label = c;
3031 if (c != 0) {
3032 if (bp >= eom) {
3033 goto ret_EMSGSIZE;
3035 *bp++ = 0;
3037 if ((bp - dst) > MAXCDNAME) { /*%< src too big */
3038 goto ret_EMSGSIZE;
3041 return 0;
3043 ret_EMSGSIZE:
3044 errno = EMSGSIZE;
3045 return -1;
3047 libc_hidden_def(ns_name_pton)
3050 * ns_name_unpack(msg, eom, src, dst, dstsiz)
3051 * Unpack a domain name from a message, source may be compressed.
3052 * return:
3053 * -1 if it fails, or consumed octets if it succeeds.
3055 int ns_name_unpack(const u_char *msg, const u_char *eom, const u_char *src,
3056 u_char *dst, size_t dstsiz)
3058 const u_char *srcp, *dstlim;
3059 u_char *dstp;
3060 int n, len, checked;
3062 len = -1;
3063 checked = 0;
3064 dstp = dst;
3065 srcp = src;
3066 dstlim = dst + dstsiz;
3067 if (srcp < msg || srcp >= eom) {
3068 __set_errno(EMSGSIZE);
3069 return -1;
3071 /* Fetch next label in domain name. */
3072 while ((n = *srcp++) != 0) {
3073 /* Check for indirection. */
3074 switch (n & NS_CMPRSFLGS) {
3075 case 0:
3076 /* Limit checks. */
3077 if (dstp + n + 1 >= dstlim || srcp + n >= eom) {
3078 __set_errno(EMSGSIZE);
3079 return -1;
3081 checked += n + 1;
3082 *dstp++ = n;
3083 memcpy(dstp, srcp, n);
3084 dstp += n;
3085 srcp += n;
3086 break;
3088 case NS_CMPRSFLGS:
3089 if (srcp >= eom) {
3090 __set_errno(EMSGSIZE);
3091 return -1;
3093 if (len < 0)
3094 len = srcp - src + 1;
3095 srcp = msg + (((n & 0x3f) << 8) | (*srcp & 0xff));
3096 if (srcp < msg || srcp >= eom) { /* Out of range. */
3097 __set_errno(EMSGSIZE);
3098 return -1;
3100 checked += 2;
3102 * Check for loops in the compressed name;
3103 * if we've looked at the whole message,
3104 * there must be a loop.
3106 if (checked >= eom - msg) {
3107 __set_errno(EMSGSIZE);
3108 return -1;
3110 break;
3112 default:
3113 __set_errno(EMSGSIZE);
3114 return -1; /* flag error */
3117 *dstp = '\0';
3118 if (len < 0)
3119 len = srcp - src;
3120 return len;
3122 libc_hidden_def(ns_name_unpack)
3124 static int labellen(const unsigned char *lp)
3126 unsigned bitlen;
3127 unsigned char l = *lp;
3129 if ((l & NS_CMPRSFLGS) == NS_CMPRSFLGS) {
3130 /* should be avoided by the caller */
3131 return -1;
3134 if ((l & NS_CMPRSFLGS) == NS_TYPE_ELT) {
3135 if (l == DNS_LABELTYPE_BITSTRING) {
3136 bitlen = lp[1];
3137 if (bitlen == 0)
3138 bitlen = 256;
3139 return ((bitlen + 7 ) / 8 + 1);
3142 return -1; /*%< unknwon ELT */
3145 return l;
3148 static int mklower(int ch)
3150 if (ch >= 0x41 && ch <= 0x5A)
3151 return (ch + 0x20);
3153 return ch;
3156 static int dn_find(const unsigned char *domain,
3157 const unsigned char *msg,
3158 const unsigned char * const *dnptrs,
3159 const unsigned char * const *lastdnptr)
3161 const unsigned char *dn, *cp, *sp;
3162 const unsigned char * const *cpp;
3163 u_int n;
3165 for (cpp = dnptrs; cpp < lastdnptr; cpp++) {
3166 sp = *cpp;
3168 * terminate search on:
3169 * root label
3170 * compression pointer
3171 * unusable offset
3173 while (*sp != 0 && (*sp & NS_CMPRSFLGS) == 0 &&
3174 (sp - msg) < 0x4000) {
3175 dn = domain;
3176 cp = sp;
3178 while ((n = *cp++) != 0) {
3180 * check for indirection
3182 switch (n & NS_CMPRSFLGS) {
3183 case 0: /*%< normal case, n == len */
3184 n = labellen(cp - 1); /*%< XXX */
3185 if (n != *dn++)
3186 goto next;
3188 for (; n > 0; n--)
3189 if (mklower(*dn++) !=
3190 mklower(*cp++))
3191 goto next;
3192 /* Is next root for both ? */
3193 if (*dn == '\0' && *cp == '\0')
3194 return (sp - msg);
3195 if (*dn)
3196 continue;
3197 goto next;
3198 case NS_CMPRSFLGS: /*%< indirection */
3199 cp = msg + (((n & 0x3f) << 8) | *cp);
3200 break;
3202 default: /*%< illegal type */
3203 errno = EMSGSIZE;
3204 return -1;
3207 next:
3208 sp += *sp + 1;
3212 errno = ENOENT;
3213 return -1;
3216 int ns_name_pack(const unsigned char *src,
3217 unsigned char *dst, int dstsiz,
3218 const unsigned char **dnptrs,
3219 const unsigned char **lastdnptr)
3221 unsigned char *dstp;
3222 const unsigned char **cpp, **lpp, *eob, *msg;
3223 const unsigned char *srcp;
3224 int n, l, first = 1;
3226 srcp = src;
3227 dstp = dst;
3228 eob = dstp + dstsiz;
3229 lpp = cpp = NULL;
3231 if (dnptrs != NULL) {
3232 msg = *dnptrs++;
3233 if (msg != NULL) {
3234 for (cpp = dnptrs; *cpp != NULL; cpp++)
3235 continue;
3237 lpp = cpp; /*%< end of list to search */
3239 } else {
3240 msg = NULL;
3243 /* make sure the domain we are about to add is legal */
3244 l = 0;
3245 do {
3246 int l0;
3248 n = *srcp;
3249 if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) {
3250 errno = EMSGSIZE;
3251 return -1;
3254 l0 = labellen(srcp);
3255 if (l0 < 0) {
3256 errno = EINVAL;
3257 return -1;
3260 l += l0 + 1;
3261 if (l > MAXCDNAME) {
3262 errno = EMSGSIZE;
3263 return -1;
3266 srcp += l0 + 1;
3267 } while (n != 0);
3269 /* from here on we need to reset compression pointer array on error */
3270 srcp = src;
3272 do {
3273 /* Look to see if we can use pointers. */
3274 n = *srcp;
3276 if (n != 0 && msg != NULL) {
3277 l = dn_find(srcp, msg, (const unsigned char * const *) dnptrs,
3278 (const unsigned char * const *) lpp);
3279 if (l >= 0) {
3280 if (dstp + 1 >= eob) {
3281 goto cleanup;
3284 *dstp++ = ((u_int32_t)l >> 8) | NS_CMPRSFLGS;
3285 *dstp++ = l % 256;
3286 return (dstp - dst);
3289 /* Not found, save it. */
3290 if (lastdnptr != NULL && cpp < lastdnptr - 1 &&
3291 (dstp - msg) < 0x4000 && first) {
3292 *cpp++ = dstp;
3293 *cpp = NULL;
3294 first = 0;
3298 /* copy label to buffer */
3299 if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) {
3300 /* Should not happen. */
3301 goto cleanup;
3304 n = labellen(srcp);
3305 if (dstp + 1 + n >= eob) {
3306 goto cleanup;
3309 memcpy(dstp, srcp, (size_t)(n + 1));
3310 srcp += n + 1;
3311 dstp += n + 1;
3312 } while (n != 0);
3314 if (dstp > eob) {
3315 cleanup:
3316 if (msg != NULL)
3317 *lpp = NULL;
3319 errno = EMSGSIZE;
3320 return -1;
3323 return dstp - dst;
3325 libc_hidden_def(ns_name_pack)
3327 int ns_name_compress(const char *src,
3328 unsigned char *dst, size_t dstsiz,
3329 const unsigned char **dnptrs,
3330 const unsigned char **lastdnptr)
3332 unsigned char tmp[NS_MAXCDNAME];
3334 if (ns_name_pton(src, tmp, sizeof(tmp)) == -1)
3335 return -1;
3337 return ns_name_pack(tmp, dst, dstsiz, dnptrs, lastdnptr);
3339 libc_hidden_def(ns_name_compress)
3341 int ns_name_skip(const unsigned char **ptrptr,
3342 const unsigned char *eom)
3344 const unsigned char *cp;
3345 u_int n;
3346 int l;
3348 cp = *ptrptr;
3349 while (cp < eom && (n = *cp++) != 0) {
3350 /* Check for indirection. */
3351 switch (n & NS_CMPRSFLGS) {
3352 case 0: /*%< normal case, n == len */
3353 cp += n;
3354 continue;
3355 case NS_TYPE_ELT: /*%< EDNS0 extended label */
3356 l = labellen(cp - 1);
3357 if (l < 0) {
3358 errno = EMSGSIZE; /*%< XXX */
3359 return -1;
3361 cp += l;
3362 continue;
3363 case NS_CMPRSFLGS: /*%< indirection */
3364 cp++;
3365 break;
3366 default: /*%< illegal type */
3367 errno = EMSGSIZE;
3368 return -1;
3371 break;
3374 if (cp > eom) {
3375 errno = EMSGSIZE;
3376 return -1;
3379 *ptrptr = cp;
3381 return 0;
3383 libc_hidden_def(ns_name_skip)
3385 int dn_skipname(const unsigned char *ptr, const unsigned char *eom)
3387 const unsigned char *saveptr = ptr;
3389 if (ns_name_skip(&ptr, eom) == -1)
3390 return -1;
3392 return ptr - saveptr;
3394 libc_hidden_def(dn_skipname)
3395 #endif /* L_ns_name */
3398 #ifdef L_res_init
3400 /* Will be called under __resolv_lock. */
3401 static void res_sync_func(void)
3403 struct __res_state *rp = &(_res);
3404 int n;
3406 /* If we didn't get malloc failure earlier... */
3407 if (__nameserver != (void*) &__local_nameserver) {
3408 /* TODO:
3409 * if (__nameservers < rp->nscount) - try to grow __nameserver[]?
3411 #ifdef __UCLIBC_HAS_IPV6__
3412 if (__nameservers > rp->_u._ext.nscount)
3413 __nameservers = rp->_u._ext.nscount;
3414 n = __nameservers;
3415 while (--n >= 0)
3416 __nameserver[n].sa6 = *rp->_u._ext.nsaddrs[n]; /* struct copy */
3417 #else /* IPv4 only */
3418 if (__nameservers > rp->nscount)
3419 __nameservers = rp->nscount;
3420 n = __nameservers;
3421 while (--n >= 0)
3422 __nameserver[n].sa4 = rp->nsaddr_list[n]; /* struct copy */
3423 #endif
3425 __resolv_timeout = rp->retrans ? : RES_TIMEOUT;
3426 __resolv_attempts = rp->retry ? : RES_DFLRETRY;
3427 /* Extend and comment what program is known
3428 * to use which _res.XXX member(s).
3430 __resolv_opts = rp->options;
3435 /* has to be called under __resolv_lock */
3436 static int
3437 __res_vinit(res_state rp, int preinit)
3439 int i, n, options, retrans, retry, ndots;
3440 #ifdef __UCLIBC_HAS_IPV6__
3441 int m = 0;
3442 #endif
3444 __close_nameservers();
3445 __open_nameservers();
3447 if (preinit) {
3448 options = rp->options;
3449 retrans = rp->retrans;
3450 retry = rp->retry;
3451 ndots = rp->ndots;
3454 memset(rp, 0, sizeof(*rp));
3456 if (!preinit) {
3457 rp->options = RES_DEFAULT;
3458 rp->retrans = RES_TIMEOUT;
3459 rp->retry = RES_DFLRETRY;
3460 rp->ndots = 1;
3461 } else {
3462 rp->options = options;
3463 rp->retrans = retrans;
3464 rp->retry = retry;
3465 rp->ndots = ndots;
3468 #ifdef __UCLIBC_HAS_COMPAT_RES_STATE__
3469 /* Was: "rp->id = random();" but:
3470 * - random() pulls in largish static buffers
3471 * - isn't actually random unless, say, srandom(time(NULL)) was called
3472 * - is not used by uclibc anyway :)
3474 /* rp->id = 0; - memset did it */
3475 #endif
3476 #ifdef __UCLIBC_HAS_EXTRA_COMPAT_RES_STATE__
3477 rp->_vcsock = -1;
3478 #endif
3480 n = __searchdomains;
3481 if (n > ARRAY_SIZE(rp->dnsrch))
3482 n = ARRAY_SIZE(rp->dnsrch);
3483 for (i = 0; i < n; i++)
3484 rp->dnsrch[i] = __searchdomain[i];
3486 /* copy nameservers' addresses */
3487 i = 0;
3488 #ifdef __UCLIBC_HAS_IPV4__
3489 n = 0;
3490 while (n < ARRAY_SIZE(rp->nsaddr_list) && i < __nameservers) {
3491 if (__nameserver[i].sa.sa_family == AF_INET) {
3492 rp->nsaddr_list[n] = __nameserver[i].sa4; /* struct copy */
3493 #ifdef __UCLIBC_HAS_IPV6__
3494 if (m < ARRAY_SIZE(rp->_u._ext.nsaddrs)) {
3495 rp->_u._ext.nsaddrs[m] = (void*) &rp->nsaddr_list[n];
3496 m++;
3498 #endif
3499 n++;
3501 #ifdef __UCLIBC_HAS_IPV6__
3502 if (__nameserver[i].sa.sa_family == AF_INET6
3503 && m < ARRAY_SIZE(rp->_u._ext.nsaddrs)
3505 struct sockaddr_in6 *sa6 = malloc(sizeof(*sa6));
3506 if (sa6) {
3507 *sa6 = __nameserver[i].sa6; /* struct copy */
3508 rp->_u._ext.nsaddrs[m] = sa6;
3509 m++;
3512 #endif
3513 i++;
3515 rp->nscount = n;
3516 #ifdef __UCLIBC_HAS_IPV6__
3517 rp->_u._ext.nscount = m;
3518 #endif
3520 #else /* IPv6 only */
3521 while (m < ARRAY_SIZE(rp->_u._ext.nsaddrs) && i < __nameservers) {
3522 struct sockaddr_in6 *sa6 = malloc(sizeof(*sa6));
3523 if (sa6) {
3524 *sa6 = __nameserver[i].sa6; /* struct copy */
3525 rp->_u._ext.nsaddrs[m] = sa6;
3526 m++;
3528 i++;
3530 rp->_u._ext.nscount = m;
3531 #endif
3533 rp->options |= RES_INIT;
3535 return 0;
3538 static unsigned int
3539 res_randomid(void)
3541 return 0xffff & getpid();
3544 /* Our res_init never fails (always returns 0) */
3546 res_init(void)
3549 * These three fields used to be statically initialized. This made
3550 * it hard to use this code in a shared library. It is necessary,
3551 * now that we're doing dynamic initialization here, that we preserve
3552 * the old semantics: if an application modifies one of these three
3553 * fields of _res before res_init() is called, res_init() will not
3554 * alter them. Of course, if an application is setting them to
3555 * _zero_ before calling res_init(), hoping to override what used
3556 * to be the static default, we can't detect it and unexpected results
3557 * will follow. Zero for any of these fields would make no sense,
3558 * so one can safely assume that the applications were already getting
3559 * unexpected results.
3561 * _res.options is tricky since some apps were known to diddle the bits
3562 * before res_init() was first called. We can't replicate that semantic
3563 * with dynamic initialization (they may have turned bits off that are
3564 * set in RES_DEFAULT). Our solution is to declare such applications
3565 * "broken". They could fool us by setting RES_INIT but none do (yet).
3568 __UCLIBC_MUTEX_LOCK(__resolv_lock);
3570 if (!_res.retrans)
3571 _res.retrans = RES_TIMEOUT;
3572 if (!_res.retry)
3573 _res.retry = 4;
3574 if (!(_res.options & RES_INIT))
3575 _res.options = RES_DEFAULT;
3578 * This one used to initialize implicitly to zero, so unless the app
3579 * has set it to something in particular, we can randomize it now.
3581 if (!_res.id)
3582 _res.id = res_randomid();
3584 __res_sync = NULL;
3585 __res_vinit(&_res, 1);
3586 __res_sync = res_sync_func;
3588 __UCLIBC_MUTEX_UNLOCK(__resolv_lock);
3590 return 0;
3592 libc_hidden_def(res_init)
3594 static void
3595 __res_iclose(res_state statp)
3597 struct __res_state * rp = statp;
3598 __UCLIBC_MUTEX_LOCK(__resolv_lock);
3599 if (rp == NULL)
3600 rp = __res_state();
3601 __close_nameservers();
3602 __res_sync = NULL;
3603 #ifdef __UCLIBC_HAS_IPV6__
3605 char *p1 = (char*) &(rp->nsaddr_list[0]);
3606 unsigned int m = 0;
3607 /* free nsaddrs[m] if they do not point to nsaddr_list[x] */
3608 while (m < ARRAY_SIZE(rp->_u._ext.nsaddrs)) {
3609 char *p2 = (char*)(rp->_u._ext.nsaddrs[m++]);
3610 if (p2 < p1 || (p2 - p1) > (signed)sizeof(rp->nsaddr_list))
3611 free(p2);
3614 #endif
3615 memset(rp, 0, sizeof(struct __res_state));
3616 __UCLIBC_MUTEX_UNLOCK(__resolv_lock);
3620 * This routine is for closing the socket if a virtual circuit is used and
3621 * the program wants to close it. This provides support for endhostent()
3622 * which expects to close the socket.
3624 * This routine is not expected to be user visible.
3627 void
3628 res_nclose(res_state statp)
3630 __res_iclose(statp);
3633 #ifdef __UCLIBC_HAS_BSD_RES_CLOSE__
3634 void res_close(void)
3636 __res_iclose(NULL);
3638 #endif
3640 /* This needs to be after the use of _res in res_init, above. */
3641 #undef _res
3643 #ifndef __UCLIBC_HAS_THREADS__
3644 /* The resolver state for use by single-threaded programs.
3645 This differs from plain `struct __res_state _res;' in that it doesn't
3646 create a common definition, but a plain symbol that resides in .bss,
3647 which can have an alias. */
3648 struct __res_state _res __attribute__((section (".bss")));
3649 struct __res_state *__resp = &_res;
3650 #else /* __UCLIBC_HAS_THREADS__ */
3651 struct __res_state _res __attribute__((section (".bss"))) attribute_hidden;
3653 # if defined __UCLIBC_HAS_TLS__
3654 # undef __resp
3655 __thread struct __res_state *__resp = &_res;
3656 extern __thread struct __res_state *__libc_resp
3657 __attribute__ ((alias ("__resp"))) attribute_hidden attribute_tls_model_ie;
3658 # else
3659 # undef __resp
3660 struct __res_state *__resp = &_res;
3661 # endif
3662 #endif /* !__UCLIBC_HAS_THREADS__ */
3665 * Set up default settings. If the configuration file exist, the values
3666 * there will have precedence. Otherwise, the server address is set to
3667 * INADDR_ANY and the default domain name comes from the gethostname().
3669 * An interrim version of this code (BIND 4.9, pre-4.4BSD) used 127.0.0.1
3670 * rather than INADDR_ANY ("0.0.0.0") as the default name server address
3671 * since it was noted that INADDR_ANY actually meant ``the first interface
3672 * you "ifconfig"'d at boot time'' and if this was a SLIP or PPP interface,
3673 * it had to be "up" in order for you to reach your own name server. It
3674 * was later decided that since the recommended practice is to always
3675 * install local static routes through 127.0.0.1 for all your network
3676 * interfaces, that we could solve this problem without a code change.
3678 * The configuration file should always be used, since it is the only way
3679 * to specify a default domain. If you are running a server on your local
3680 * machine, you should say "nameserver 0.0.0.0" or "nameserver 127.0.0.1"
3681 * in the configuration file.
3683 * Return 0 if completes successfully, -1 on error
3686 res_ninit(res_state statp)
3688 int ret;
3689 __UCLIBC_MUTEX_LOCK(__resolv_lock);
3690 ret = __res_vinit(statp, 0);
3691 __UCLIBC_MUTEX_UNLOCK(__resolv_lock);
3692 return ret;
3695 #endif /* L_res_init */
3697 #ifdef L_res_state
3698 # if defined __UCLIBC_HAS_TLS__
3699 struct __res_state *
3700 __res_state (void)
3702 return __resp;
3704 # else
3705 # undef _res
3706 extern struct __res_state _res;
3708 /* When threaded, _res may be a per-thread variable. */
3709 struct __res_state *
3710 weak_const_function
3711 __res_state (void)
3713 return &_res;
3715 # endif
3717 #endif /* L_res_state */
3720 #ifdef L_res_query
3722 int res_query(const char *dname, int class, int type,
3723 unsigned char *answer, int anslen)
3725 int i;
3726 unsigned char *packet = NULL;
3727 struct resolv_answer a;
3729 if (!dname || class != 1 /* CLASS_IN */) {
3730 h_errno = NO_RECOVERY;
3731 return -1;
3734 memset(&a, '\0', sizeof(a));
3735 i = __dns_lookup(dname, type, &packet, &a);
3737 if (i < 0) {
3738 if (!h_errno) /* TODO: can this ever happen? */
3739 h_errno = TRY_AGAIN;
3740 return -1;
3743 free(a.dotted);
3745 if (i > anslen)
3746 i = anslen;
3747 memcpy(answer, packet, i);
3749 free(packet);
3750 return i;
3752 libc_hidden_def(res_query)
3755 * Formulate a normal query, send, and retrieve answer in supplied buffer.
3756 * Return the size of the response on success, -1 on error.
3757 * If enabled, implement search rules until answer or unrecoverable failure
3758 * is detected. Error code, if any, is left in h_errno.
3760 #define __TRAILING_DOT (1<<0)
3761 #define __GOT_NODATA (1<<1)
3762 #define __GOT_SERVFAIL (1<<2)
3763 #define __TRIED_AS_IS (1<<3)
3764 int res_search(const char *name, int class, int type, u_char *answer,
3765 int anslen)
3767 const char *cp;
3768 char **domain;
3769 HEADER *hp = (HEADER *)(void *)answer;
3770 unsigned dots;
3771 unsigned state;
3772 int ret, saved_herrno;
3773 uint32_t _res_options;
3774 unsigned _res_ndots;
3775 char **_res_dnsrch;
3777 if (!name || !answer) {
3778 h_errno = NETDB_INTERNAL;
3779 return -1;
3782 again:
3783 __UCLIBC_MUTEX_LOCK(__resolv_lock);
3784 _res_options = _res.options;
3785 _res_ndots = _res.ndots;
3786 _res_dnsrch = _res.dnsrch;
3787 __UCLIBC_MUTEX_UNLOCK(__resolv_lock);
3788 if (!(_res_options & RES_INIT)) {
3789 res_init(); /* our res_init never fails */
3790 goto again;
3793 state = 0;
3794 errno = 0;
3795 h_errno = HOST_NOT_FOUND; /* default, if we never query */
3796 dots = 0;
3797 for (cp = name; *cp; cp++)
3798 dots += (*cp == '.');
3800 if (cp > name && *--cp == '.')
3801 state |= __TRAILING_DOT;
3804 * If there are dots in the name already, let's just give it a try
3805 * 'as is'. The threshold can be set with the "ndots" option.
3807 saved_herrno = -1;
3808 if (dots >= _res_ndots) {
3809 ret = res_querydomain(name, NULL, class, type, answer, anslen);
3810 if (ret > 0)
3811 return ret;
3812 saved_herrno = h_errno;
3813 state |= __TRIED_AS_IS;
3817 * We do at least one level of search if
3818 * - there is no dot and RES_DEFNAME is set, or
3819 * - there is at least one dot, there is no trailing dot,
3820 * and RES_DNSRCH is set.
3822 if ((!dots && (_res_options & RES_DEFNAMES))
3823 || (dots && !(state & __TRAILING_DOT) && (_res_options & RES_DNSRCH))
3825 bool done = 0;
3827 for (domain = _res_dnsrch; *domain && !done; domain++) {
3829 ret = res_querydomain(name, *domain, class, type,
3830 answer, anslen);
3831 if (ret > 0)
3832 return ret;
3835 * If no server present, give up.
3836 * If name isn't found in this domain,
3837 * keep trying higher domains in the search list
3838 * (if that's enabled).
3839 * On a NO_DATA error, keep trying, otherwise
3840 * a wildcard entry of another type could keep us
3841 * from finding this entry higher in the domain.
3842 * If we get some other error (negative answer or
3843 * server failure), then stop searching up,
3844 * but try the input name below in case it's
3845 * fully-qualified.
3847 if (errno == ECONNREFUSED) {
3848 h_errno = TRY_AGAIN;
3849 return -1;
3852 switch (h_errno) {
3853 case NO_DATA:
3854 state |= __GOT_NODATA;
3855 /* FALLTHROUGH */
3856 case HOST_NOT_FOUND:
3857 /* keep trying */
3858 break;
3859 case TRY_AGAIN:
3860 if (hp->rcode == SERVFAIL) {
3861 /* try next search element, if any */
3862 state |= __GOT_SERVFAIL;
3863 break;
3865 /* FALLTHROUGH */
3866 default:
3867 /* anything else implies that we're done */
3868 done = 1;
3871 * if we got here for some reason other than DNSRCH,
3872 * we only wanted one iteration of the loop, so stop.
3874 if (!(_res_options & RES_DNSRCH))
3875 done = 1;
3880 * if we have not already tried the name "as is", do that now.
3881 * note that we do this regardless of how many dots were in the
3882 * name or whether it ends with a dot.
3884 if (!(state & __TRIED_AS_IS)) {
3885 ret = res_querydomain(name, NULL, class, type, answer, anslen);
3886 if (ret > 0)
3887 return ret;
3891 * if we got here, we didn't satisfy the search.
3892 * if we did an initial full query, return that query's h_errno
3893 * (note that we wouldn't be here if that query had succeeded).
3894 * else if we ever got a nodata, send that back as the reason.
3895 * else send back meaningless h_errno, that being the one from
3896 * the last DNSRCH we did.
3898 if (saved_herrno != -1)
3899 h_errno = saved_herrno;
3900 else if (state & __GOT_NODATA)
3901 h_errno = NO_DATA;
3902 else if (state & __GOT_SERVFAIL)
3903 h_errno = TRY_AGAIN;
3904 return -1;
3906 #undef __TRAILING_DOT
3907 #undef __GOT_NODATA
3908 #undef __GOT_SERVFAIL
3909 #undef __TRIED_AS_IS
3911 * Perform a call on res_query on the concatenation of name and domain,
3912 * removing a trailing dot from name if domain is NULL.
3914 int res_querydomain(const char *name, const char *domain, int class, int type,
3915 u_char *answer, int anslen)
3917 char nbuf[MAXDNAME];
3918 const char *longname = nbuf;
3919 size_t n, d;
3920 #ifdef DEBUG
3921 uint32_t _res_options;
3922 #endif
3924 if (!name || !answer) {
3925 h_errno = NETDB_INTERNAL;
3926 return -1;
3929 #ifdef DEBUG
3930 again:
3931 __UCLIBC_MUTEX_LOCK(__resolv_lock);
3932 _res_options = _res.options;
3933 __UCLIBC_MUTEX_UNLOCK(__resolv_lock);
3934 if (!(_res_options & RES_INIT)) {
3935 res_init(); /* our res_init never fails */
3936 goto again;
3938 if (_res_options & RES_DEBUG)
3939 printf(";; res_querydomain(%s, %s, %d, %d)\n",
3940 name, (domain ? domain : "<Nil>"), class, type);
3941 #endif
3942 if (domain == NULL) {
3944 * Check for trailing '.';
3945 * copy without '.' if present.
3947 n = strlen(name);
3948 if (n + 1 > sizeof(nbuf)) {
3949 h_errno = NO_RECOVERY;
3950 return -1;
3952 if (n > 0 && name[--n] == '.') {
3953 strncpy(nbuf, name, n);
3954 nbuf[n] = '\0';
3955 } else
3956 longname = name;
3957 } else {
3958 n = strlen(name);
3959 d = strlen(domain);
3960 if (n + 1 + d + 1 > sizeof(nbuf)) {
3961 h_errno = NO_RECOVERY;
3962 return -1;
3964 snprintf(nbuf, sizeof(nbuf), "%s.%s", name, domain);
3966 return res_query(longname, class, type, answer, anslen);
3968 libc_hidden_def(res_querydomain)
3969 #endif /* L_res_query */
3971 #ifdef L_ns_netint
3972 unsigned int ns_get16(const unsigned char *src)
3974 unsigned int dst;
3975 NS_GET16(dst, src);
3976 return dst;
3979 unsigned long ns_get32(const unsigned char *src)
3981 unsigned long dst;
3982 NS_GET32(dst, src);
3983 return dst;
3986 void ns_put16(unsigned int src, unsigned char *dst)
3988 NS_PUT16(src, dst);
3991 void ns_put32(unsigned long src, unsigned char *dst)
3993 NS_PUT32(src, dst);
3995 #endif /* L_ns_netint */
3997 #ifdef L_ns_parse
3998 /* These need to be in the same order as the nres.h:ns_flag enum. */
3999 struct _ns_flagdata { unsigned short mask, shift; };
4000 static const struct _ns_flagdata _ns_flagdata[16] = {
4001 { 0x8000, 15 }, /*%< qr. */
4002 { 0x7800, 11 }, /*%< opcode. */
4003 { 0x0400, 10 }, /*%< aa. */
4004 { 0x0200, 9 }, /*%< tc. */
4005 { 0x0100, 8 }, /*%< rd. */
4006 { 0x0080, 7 }, /*%< ra. */
4007 { 0x0040, 6 }, /*%< z. */
4008 { 0x0020, 5 }, /*%< ad. */
4009 { 0x0010, 4 }, /*%< cd. */
4010 { 0x000f, 0 }, /*%< rcode. */
4011 { 0x0000, 0 }, /*%< expansion (1/6). */
4012 { 0x0000, 0 }, /*%< expansion (2/6). */
4013 { 0x0000, 0 }, /*%< expansion (3/6). */
4014 { 0x0000, 0 }, /*%< expansion (4/6). */
4015 { 0x0000, 0 }, /*%< expansion (5/6). */
4016 { 0x0000, 0 }, /*%< expansion (6/6). */
4019 static void setsection(ns_msg *msg, ns_sect sect)
4021 msg->_sect = sect;
4022 if (sect == ns_s_max) {
4023 msg->_rrnum = -1;
4024 msg->_ptr = NULL;
4025 } else {
4026 msg->_rrnum = 0;
4027 msg->_ptr = msg->_sections[(int)sect];
4031 int ns_skiprr(const unsigned char *ptr,
4032 const unsigned char *eom,
4033 ns_sect section, int count)
4035 const u_char *optr = ptr;
4037 for (; count > 0; count--) {
4038 int b, rdlength;
4040 b = dn_skipname(ptr, eom);
4041 if (b < 0) {
4042 errno = EMSGSIZE;
4043 return -1;
4046 ptr += b/*Name*/ + NS_INT16SZ/*Type*/ + NS_INT16SZ/*Class*/;
4047 if (section != ns_s_qd) {
4048 if (ptr + NS_INT32SZ + NS_INT16SZ > eom) {
4049 errno = EMSGSIZE;
4050 return -1;
4053 ptr += NS_INT32SZ/*TTL*/;
4054 NS_GET16(rdlength, ptr);
4055 ptr += rdlength/*RData*/;
4059 if (ptr > eom) {
4060 errno = EMSGSIZE;
4061 return -1;
4064 return ptr - optr;
4066 libc_hidden_def(ns_skiprr)
4069 ns_initparse(const unsigned char *msg, int msglen, ns_msg *handle)
4071 const u_char *eom = msg + msglen;
4072 int i;
4074 handle->_msg = msg;
4075 handle->_eom = eom;
4076 if (msg + NS_INT16SZ > eom) {
4077 errno = EMSGSIZE;
4078 return -1;
4081 NS_GET16(handle->_id, msg);
4082 if (msg + NS_INT16SZ > eom) {
4083 errno = EMSGSIZE;
4084 return -1;
4087 NS_GET16(handle->_flags, msg);
4088 for (i = 0; i < ns_s_max; i++) {
4089 if (msg + NS_INT16SZ > eom) {
4090 errno = EMSGSIZE;
4091 return -1;
4094 NS_GET16(handle->_counts[i], msg);
4096 for (i = 0; i < ns_s_max; i++)
4097 if (handle->_counts[i] == 0)
4098 handle->_sections[i] = NULL;
4099 else {
4100 int b = ns_skiprr(msg, eom, (ns_sect)i,
4101 handle->_counts[i]);
4103 if (b < 0)
4104 return -1;
4105 handle->_sections[i] = msg;
4106 msg += b;
4109 if (msg != eom) {
4110 errno = EMSGSIZE;
4111 return -1;
4114 setsection(handle, ns_s_max);
4115 return 0;
4119 ns_parserr(ns_msg *handle, ns_sect section, int rrnum, ns_rr *rr)
4121 int b;
4122 int tmp;
4124 /* Make section right. */
4125 tmp = section;
4126 if (tmp < 0 || section >= ns_s_max) {
4127 errno = ENODEV;
4128 return -1;
4131 if (section != handle->_sect)
4132 setsection(handle, section);
4134 /* Make rrnum right. */
4135 if (rrnum == -1)
4136 rrnum = handle->_rrnum;
4137 if (rrnum < 0 || rrnum >= handle->_counts[(int)section]) {
4138 errno = ENODEV;
4139 return -1;
4141 if (rrnum < handle->_rrnum)
4142 setsection(handle, section);
4143 if (rrnum > handle->_rrnum) {
4144 b = ns_skiprr(handle->_ptr, handle->_eom, section,
4145 rrnum - handle->_rrnum);
4147 if (b < 0)
4148 return -1;
4149 handle->_ptr += b;
4150 handle->_rrnum = rrnum;
4153 /* Do the parse. */
4154 b = dn_expand(handle->_msg, handle->_eom,
4155 handle->_ptr, rr->name, NS_MAXDNAME);
4156 if (b < 0)
4157 return -1;
4158 handle->_ptr += b;
4159 if (handle->_ptr + NS_INT16SZ + NS_INT16SZ > handle->_eom) {
4160 errno = EMSGSIZE;
4161 return -1;
4163 NS_GET16(rr->type, handle->_ptr);
4164 NS_GET16(rr->rr_class, handle->_ptr);
4165 if (section == ns_s_qd) {
4166 rr->ttl = 0;
4167 rr->rdlength = 0;
4168 rr->rdata = NULL;
4169 } else {
4170 if (handle->_ptr + NS_INT32SZ + NS_INT16SZ > handle->_eom) {
4171 errno = EMSGSIZE;
4172 return -1;
4174 NS_GET32(rr->ttl, handle->_ptr);
4175 NS_GET16(rr->rdlength, handle->_ptr);
4176 if (handle->_ptr + rr->rdlength > handle->_eom) {
4177 errno = EMSGSIZE;
4178 return -1;
4180 rr->rdata = handle->_ptr;
4181 handle->_ptr += rr->rdlength;
4183 if (++handle->_rrnum > handle->_counts[(int)section])
4184 setsection(handle, (ns_sect)((int)section + 1));
4186 return 0;
4189 int ns_msg_getflag(ns_msg handle, int flag)
4191 return ((handle)._flags & _ns_flagdata[flag].mask) >> _ns_flagdata[flag].shift;
4193 #endif /* L_ns_parse */
4195 #ifdef L_res_data
4196 int res_mkquery(int op, const char *dname, int class, int type,
4197 const unsigned char *data, int datalen,
4198 const unsigned char *newrr_in,
4199 unsigned char *buf, int buflen)
4201 HEADER *hp;
4202 unsigned char *cp, *ep;
4203 unsigned char *dnptrs[20], **dpp, **lastdnptr;
4204 uint32_t _res_options;
4205 int n;
4207 if (!buf || buflen < HFIXEDSZ) {
4208 h_errno = NETDB_INTERNAL;
4209 return -1;
4212 again:
4213 __UCLIBC_MUTEX_LOCK(__resolv_lock);
4214 _res_options = _res.options;
4215 __UCLIBC_MUTEX_UNLOCK(__resolv_lock);
4216 if (!(_res_options & RES_INIT)) {
4217 res_init(); /* our res_init never fails */
4218 goto again;
4221 #ifdef DEBUG
4222 if (_res_options & RES_DEBUG)
4223 printf(";; res_mkquery(%d, %s, %d, %d)\n",
4224 op, dname && *dname ? dname : "<null>", class, type);
4225 #endif
4227 memset(buf, 0, HFIXEDSZ);
4228 hp = (HEADER *) buf;
4229 hp->id = getpid() & 0xffff;
4230 hp->opcode = op;
4231 hp->rd = (_res_options & RES_RECURSE) != 0U;
4232 hp->rcode = NOERROR;
4234 cp = buf + HFIXEDSZ;
4235 ep = buf + buflen;
4236 dpp = dnptrs;
4237 *dpp++ = buf;
4238 *dpp++ = NULL;
4239 lastdnptr = dnptrs + sizeof dnptrs / sizeof dnptrs[0];
4242 * perform opcode specific processing
4244 switch (op) {
4245 case QUERY:
4246 case NS_NOTIFY_OP:
4247 if (ep - cp < QFIXEDSZ)
4248 return -1;
4250 n = dn_comp(dname, cp, ep - cp - QFIXEDSZ, dnptrs, lastdnptr);
4251 if (n < 0)
4252 return -1;
4254 cp += n;
4255 NS_PUT16(type, cp);
4256 NS_PUT16(class, cp);
4257 hp->qdcount = htons(1);
4259 if (op == QUERY || data == NULL)
4260 break;
4263 * Make an additional record for completion domain.
4265 if ((ep - cp) < RRFIXEDSZ)
4266 return -1;
4268 n = dn_comp((const char *)data, cp, ep - cp - RRFIXEDSZ,
4269 dnptrs, lastdnptr);
4270 if (n < 0)
4271 return -1;
4273 cp += n;
4274 NS_PUT16(T_NULL, cp);
4275 NS_PUT16(class, cp);
4276 NS_PUT32(0, cp);
4277 NS_PUT16(0, cp);
4278 hp->arcount = htons(1);
4280 break;
4282 case IQUERY:
4284 * Initialize answer section
4286 if (ep - cp < 1 + RRFIXEDSZ + datalen)
4287 return -1;
4289 *cp++ = '\0'; /*%< no domain name */
4290 NS_PUT16(type, cp);
4291 NS_PUT16(class, cp);
4292 NS_PUT32(0, cp);
4293 NS_PUT16(datalen, cp);
4295 if (datalen) {
4296 memcpy(cp, data, (size_t)datalen);
4297 cp += datalen;
4300 hp->ancount = htons(1);
4301 break;
4303 default:
4304 return -1;
4307 return cp - buf;
4309 #endif /* L_res_data */
4311 /* Unimplemented: */
4312 /* res_send */