libc/inet: Unbreak gethostent()
[uclibc-ng.git] / libc / inet / resolv.c
blobeb663ac0f8d57889e5d3f6d31e17a1b4da4a7707
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 <malloc.h>
301 #include <errno.h>
302 #include <sys/poll.h>
303 #include <sys/socket.h>
304 #include <sys/types.h>
305 #include <sys/time.h>
306 #include <netinet/in.h>
307 #include <arpa/inet.h>
308 #include <stdlib.h>
309 #include <unistd.h>
310 #include <resolv.h>
311 #include <netdb.h>
312 #include <ctype.h>
313 #include <stdbool.h>
314 #include <time.h>
315 #include <arpa/nameser.h>
316 #include <sys/utsname.h>
317 #include <sys/un.h>
318 #include <sys/stat.h>
319 #include <sys/param.h>
320 #include <bits/uClibc_mutex.h>
321 #include "internal/parse_config.h"
323 /* poll() is not supported in kernel <= 2.0, therefore if __NR_poll is
324 * not available, we assume an old Linux kernel is in use and we will
325 * use select() instead. */
326 #include <sys/syscall.h>
327 #ifndef __NR_poll
328 # define USE_SELECT
329 #endif
331 #if defined __UCLIBC_HAS_IPV4__ && defined __UCLIBC_HAS_IPV6__
332 #define IF_HAS_BOTH(...) __VA_ARGS__
333 #else
334 #define IF_HAS_BOTH(...)
335 #endif
338 #define MAX_RECURSE 5
339 #define MAXALIASES (4)
340 /* 1:ip + 1:full + MAX_ALIASES:aliases + 1:NULL */
341 #define ALIAS_DIM (2 + MAXALIASES + 1)
342 #define BUFSZ (80) /* one line */
344 #define NS_TYPE_ELT 0x40 /*%< EDNS0 extended label type */
345 #define DNS_LABELTYPE_BITSTRING 0x41
347 #undef DEBUG
348 /* #define DEBUG */
350 #ifdef DEBUG
351 #define DPRINTF(X,args...) fprintf(stderr, X, ##args)
352 #else
353 #define DPRINTF(X,args...)
354 #endif
356 /* Make sure the incoming char * buffer is aligned enough to handle our random
357 * structures. This define is the same as we use for malloc alignment (which
358 * has same requirements). The offset is the number of bytes we need to adjust
359 * in order to attain desired alignment.
361 #define ALIGN_ATTR __alignof__(double __attribute_aligned__ (sizeof(size_t)))
362 #define ALIGN_BUFFER_OFFSET(buf) ((ALIGN_ATTR - ((size_t)buf % ALIGN_ATTR)) % ALIGN_ATTR)
365 /* Structs */
366 struct resolv_header {
367 int id;
368 int qr, opcode, aa, tc, rd, ra, rcode;
369 int qdcount;
370 int ancount;
371 int nscount;
372 int arcount;
375 struct resolv_question {
376 char *dotted;
377 int qtype;
378 int qclass;
381 struct resolv_answer {
382 char *dotted;
383 int atype;
384 int aclass;
385 int ttl;
386 int rdlength;
387 const unsigned char *rdata;
388 int rdoffset;
389 char* buf;
390 size_t buflen;
391 size_t add_count;
394 enum etc_hosts_action {
395 GET_HOSTS_BYNAME = 0,
396 GETHOSTENT,
397 GET_HOSTS_BYADDR,
400 typedef union sockaddr46_t {
401 struct sockaddr sa;
402 #ifdef __UCLIBC_HAS_IPV4__
403 struct sockaddr_in sa4;
404 #endif
405 #ifdef __UCLIBC_HAS_IPV6__
406 struct sockaddr_in6 sa6;
407 #endif
408 } sockaddr46_t;
411 __UCLIBC_MUTEX_EXTERN(__resolv_lock) attribute_hidden;
413 /* Protected by __resolv_lock */
414 extern void (*__res_sync)(void) attribute_hidden;
415 /*extern uint32_t __resolv_opts attribute_hidden; */
416 extern uint8_t __resolv_timeout attribute_hidden;
417 extern uint8_t __resolv_attempts attribute_hidden;
418 extern unsigned __nameservers attribute_hidden;
419 extern unsigned __searchdomains attribute_hidden;
420 extern sockaddr46_t *__nameserver attribute_hidden;
421 extern char **__searchdomain attribute_hidden;
422 #ifdef __UCLIBC_HAS_IPV4__
423 extern const struct sockaddr_in __local_nameserver attribute_hidden;
424 #else
425 extern const struct sockaddr_in6 __local_nameserver attribute_hidden;
426 #endif
427 /* Arbitrary */
428 #define MAXLEN_searchdomain 128
431 /* prototypes for internal functions */
432 extern void endhostent_unlocked(void) attribute_hidden;
433 extern int __get_hosts_byname_r(const char *name,
434 int type,
435 struct hostent *result_buf,
436 char *buf,
437 size_t buflen,
438 struct hostent **result,
439 int *h_errnop) attribute_hidden;
440 extern int __get_hosts_byaddr_r(const char *addr,
441 int len,
442 int type,
443 struct hostent *result_buf,
444 char *buf,
445 size_t buflen,
446 struct hostent **result,
447 int *h_errnop) attribute_hidden;
448 extern parser_t *__open_etc_hosts(void) attribute_hidden;
449 extern int __read_etc_hosts_r(parser_t *parser,
450 const char *name,
451 int type,
452 enum etc_hosts_action action,
453 struct hostent *result_buf,
454 char *buf,
455 size_t buflen,
456 struct hostent **result,
457 int *h_errnop) attribute_hidden;
458 extern int __dns_lookup(const char *name,
459 int type,
460 unsigned char **outpacket,
461 struct resolv_answer *a) attribute_hidden;
462 extern int __encode_dotted(const char *dotted,
463 unsigned char *dest,
464 int maxlen) attribute_hidden;
465 extern int __decode_dotted(const unsigned char *packet,
466 int offset,
467 int packet_len,
468 char *dest,
469 int dest_len) attribute_hidden;
470 extern int __encode_header(struct resolv_header *h,
471 unsigned char *dest,
472 int maxlen) attribute_hidden;
473 extern void __decode_header(unsigned char *data,
474 struct resolv_header *h) attribute_hidden;
475 extern int __encode_question(const struct resolv_question *q,
476 unsigned char *dest,
477 int maxlen) attribute_hidden;
478 extern int __encode_answer(struct resolv_answer *a,
479 unsigned char *dest,
480 int maxlen) attribute_hidden;
481 extern void __open_nameservers(void) attribute_hidden;
482 extern void __close_nameservers(void) attribute_hidden;
485 * Theory of operation.
487 * gethostbyname, getaddrinfo and friends end up here, and they sometimes
488 * need to talk to DNS servers. In order to do this, we need to read /etc/resolv.conf
489 * and determine servers' addresses and the like. resolv.conf format:
491 * nameserver <IP[v6]>
492 * Address of DNS server. Cumulative.
493 * If not specified, assumed to be on localhost.
494 * search <domain1>[ <domain2>]...
495 * Append these domains to unqualified names.
496 * See ndots:n option.
497 * $LOCALDOMAIN (space-separated list) overrides this.
498 * domain <domain>
499 * Effectively same as "search" with one domain.
500 * If no "domain" line is present, the domain is determined
501 * from the local host name returned by gethostname();
502 * the domain part is taken to be everything after the first dot.
503 * If there are no dots, there will be no "domain".
504 * The domain and search keywords are mutually exclusive.
505 * If more than one instance of these keywords is present,
506 * the last instance wins.
507 * sortlist 130.155.160.0[/255.255.240.0] 130.155.0.0
508 * Allows addresses returned by gethostbyname to be sorted.
509 * Not supported.
510 * options option[ option]...
511 * (so far we support timeout:n and attempts:n)
512 * $RES_OPTIONS (space-separated list) is to be added to "options"
513 * debug sets RES_DEBUG in _res.options
514 * ndots:n how many dots there should be so that name will be tried
515 * first as an absolute name before any search list elements
516 * are appended to it. Default 1
517 * timeout:n how long to wait for response. Default 5
518 * (sun seems to have retrans:n synonym)
519 * attempts:n number of rounds to do before giving up and returning
520 * an error. Default 2
521 * (sun seems to have retry:n synonym)
522 * rotate sets RES_ROTATE in _res.options, round robin
523 * selection of nameservers. Otherwise try
524 * the first listed server first every time
525 * no-check-names
526 * sets RES_NOCHECKNAME in _res.options, which disables
527 * checking of incoming host names for invalid characters
528 * such as underscore (_), non-ASCII, or control characters
529 * inet6 sets RES_USE_INET6 in _res.options. Try a AAAA query
530 * before an A query inside the gethostbyname(), and map
531 * IPv4 responses in IPv6 "tunnelled form" if no AAAA records
532 * are found but an A record set exists
533 * no_tld_query (FreeBSDism?)
534 * do not attempt to resolve names without dots
536 * We will read and analyze /etc/resolv.conf as needed before
537 * we do a DNS request. This happens in __dns_lookup.
538 * It is reread if its mtime is changed.
540 * BSD has res_init routine which is used to initialize resolver state
541 * which is held in global structure _res.
542 * Generally, programs call res_init, then fiddle with _res.XXX
543 * (_res.options and _res.nscount, _res.nsaddr_list[N]
544 * are popular targets of fiddling) and expect subsequent calls
545 * to gethostbyname, getaddrinfo, etc to use modified information.
547 * However, historical _res structure is quite awkward.
548 * Using it for storing /etc/resolv.conf info is not desirable,
549 * and __dns_lookup does not use it.
551 * We would like to avoid using it unless absolutely necessary.
552 * If user doesn't use res_init, we should arrange it so that
553 * _res structure doesn't even *get linked in* into user's application
554 * (imagine static uclibc build here).
556 * The solution is a __res_sync function pointer, which is normally NULL.
557 * But if res_init is called, it gets set and any subsequent gethostbyname
558 * et al "syncronizes" our internal structures with potentially
559 * modified _res.XXX stuff by calling __res_sync.
560 * The trick here is that if res_init is not used and not linked in,
561 * gethostbyname itself won't reference _res and _res won't be linked in
562 * either. Other possible methods like
563 * if (__res_sync_just_an_int_flag)
564 * __sync_me_with_res()
565 * would pull in __sync_me_with_res, which pulls in _res. Bad.
569 #ifdef L_encodeh
571 int __encode_header(struct resolv_header *h, unsigned char *dest, int maxlen)
573 if (maxlen < HFIXEDSZ)
574 return -1;
576 dest[0] = (h->id & 0xff00) >> 8;
577 dest[1] = (h->id & 0x00ff) >> 0;
578 dest[2] = (h->qr ? 0x80 : 0) |
579 ((h->opcode & 0x0f) << 3) |
580 (h->aa ? 0x04 : 0) |
581 (h->tc ? 0x02 : 0) |
582 (h->rd ? 0x01 : 0);
583 dest[3] = (h->ra ? 0x80 : 0) | (h->rcode & 0x0f);
584 dest[4] = (h->qdcount & 0xff00) >> 8;
585 dest[5] = (h->qdcount & 0x00ff) >> 0;
586 dest[6] = (h->ancount & 0xff00) >> 8;
587 dest[7] = (h->ancount & 0x00ff) >> 0;
588 dest[8] = (h->nscount & 0xff00) >> 8;
589 dest[9] = (h->nscount & 0x00ff) >> 0;
590 dest[10] = (h->arcount & 0xff00) >> 8;
591 dest[11] = (h->arcount & 0x00ff) >> 0;
593 return HFIXEDSZ;
595 #endif /* L_encodeh */
598 #ifdef L_decodeh
600 void __decode_header(unsigned char *data,
601 struct resolv_header *h)
603 h->id = (data[0] << 8) | data[1];
604 h->qr = (data[2] & 0x80) ? 1 : 0;
605 h->opcode = (data[2] >> 3) & 0x0f;
606 h->aa = (data[2] & 0x04) ? 1 : 0;
607 h->tc = (data[2] & 0x02) ? 1 : 0;
608 h->rd = (data[2] & 0x01) ? 1 : 0;
609 h->ra = (data[3] & 0x80) ? 1 : 0;
610 h->rcode = data[3] & 0x0f;
611 h->qdcount = (data[4] << 8) | data[5];
612 h->ancount = (data[6] << 8) | data[7];
613 h->nscount = (data[8] << 8) | data[9];
614 h->arcount = (data[10] << 8) | data[11];
616 #endif /* L_decodeh */
619 #ifdef L_encoded
621 /* Encode a dotted string into nameserver transport-level encoding.
622 This routine is fairly dumb, and doesn't attempt to compress
623 the data */
624 int __encode_dotted(const char *dotted, unsigned char *dest, int maxlen)
626 unsigned used = 0;
628 while (dotted && *dotted) {
629 char *c = strchr(dotted, '.');
630 int l = c ? c - dotted : strlen(dotted);
632 /* two consecutive dots are not valid */
633 if (l == 0)
634 return -1;
636 if (l >= (maxlen - used - 1))
637 return -1;
639 dest[used++] = l;
640 memcpy(dest + used, dotted, l);
641 used += l;
643 if (!c)
644 break;
645 dotted = c + 1;
648 if (maxlen < 1)
649 return -1;
651 dest[used++] = 0;
653 return used;
655 #endif /* L_encoded */
658 #ifdef L_decoded
660 /* Decode a dotted string from nameserver transport-level encoding.
661 This routine understands compressed data. */
662 int __decode_dotted(const unsigned char *packet,
663 int offset,
664 int packet_len,
665 char *dest,
666 int dest_len)
668 unsigned b;
669 bool measure = 1;
670 unsigned total = 0;
671 unsigned used = 0;
673 if (!packet)
674 return -1;
676 while (1) {
677 if (offset >= packet_len)
678 return -1;
679 b = packet[offset++];
680 if (b == 0)
681 break;
683 if (measure)
684 total++;
686 if ((b & 0xc0) == 0xc0) {
687 if (offset >= packet_len)
688 return -1;
689 if (measure)
690 total++;
691 /* compressed item, redirect */
692 offset = ((b & 0x3f) << 8) | packet[offset];
693 measure = 0;
694 continue;
697 if (used + b + 1 >= dest_len)
698 return -1;
699 if (offset + b >= packet_len)
700 return -1;
701 memcpy(dest + used, packet + offset, b);
702 offset += b;
703 used += b;
705 if (measure)
706 total += b;
708 if (packet[offset] != 0)
709 dest[used++] = '.';
710 else
711 dest[used++] = '\0';
714 /* The null byte must be counted too */
715 if (measure)
716 total++;
718 DPRINTF("Total decode len = %d\n", total);
720 return total;
722 #endif /* L_decoded */
725 #ifdef L_encodeq
727 int __encode_question(const struct resolv_question *q,
728 unsigned char *dest,
729 int maxlen)
731 int i;
733 i = __encode_dotted(q->dotted, dest, maxlen);
734 if (i < 0)
735 return i;
737 dest += i;
738 maxlen -= i;
740 if (maxlen < 4)
741 return -1;
743 dest[0] = (q->qtype & 0xff00) >> 8;
744 dest[1] = (q->qtype & 0x00ff) >> 0;
745 dest[2] = (q->qclass & 0xff00) >> 8;
746 dest[3] = (q->qclass & 0x00ff) >> 0;
748 return i + 4;
750 #endif /* L_encodeq */
753 #ifdef L_encodea
755 int __encode_answer(struct resolv_answer *a, unsigned char *dest, int maxlen)
757 int i;
759 i = __encode_dotted(a->dotted, dest, maxlen);
760 if (i < 0)
761 return i;
763 dest += i;
764 maxlen -= i;
766 if (maxlen < (RRFIXEDSZ + a->rdlength))
767 return -1;
769 *dest++ = (a->atype & 0xff00) >> 8;
770 *dest++ = (a->atype & 0x00ff) >> 0;
771 *dest++ = (a->aclass & 0xff00) >> 8;
772 *dest++ = (a->aclass & 0x00ff) >> 0;
773 *dest++ = (a->ttl & 0xff000000) >> 24;
774 *dest++ = (a->ttl & 0x00ff0000) >> 16;
775 *dest++ = (a->ttl & 0x0000ff00) >> 8;
776 *dest++ = (a->ttl & 0x000000ff) >> 0;
777 *dest++ = (a->rdlength & 0xff00) >> 8;
778 *dest++ = (a->rdlength & 0x00ff) >> 0;
779 memcpy(dest, a->rdata, a->rdlength);
781 return i + RRFIXEDSZ + a->rdlength;
783 #endif /* L_encodea */
786 #ifdef CURRENTLY_UNUSED
787 #ifdef L_encodep
789 int __encode_packet(struct resolv_header *h,
790 struct resolv_question **q,
791 struct resolv_answer **an,
792 struct resolv_answer **ns,
793 struct resolv_answer **ar,
794 unsigned char *dest, int maxlen) attribute_hidden;
795 int __encode_packet(struct resolv_header *h,
796 struct resolv_question **q,
797 struct resolv_answer **an,
798 struct resolv_answer **ns,
799 struct resolv_answer **ar,
800 unsigned char *dest, int maxlen)
802 int i, total = 0;
803 unsigned j;
805 i = __encode_header(h, dest, maxlen);
806 if (i < 0)
807 return i;
809 dest += i;
810 maxlen -= i;
811 total += i;
813 for (j = 0; j < h->qdcount; j++) {
814 i = __encode_question(q[j], dest, maxlen);
815 if (i < 0)
816 return i;
817 dest += i;
818 maxlen -= i;
819 total += i;
822 for (j = 0; j < h->ancount; j++) {
823 i = __encode_answer(an[j], dest, maxlen);
824 if (i < 0)
825 return i;
826 dest += i;
827 maxlen -= i;
828 total += i;
830 for (j = 0; j < h->nscount; j++) {
831 i = __encode_answer(ns[j], dest, maxlen);
832 if (i < 0)
833 return i;
834 dest += i;
835 maxlen -= i;
836 total += i;
838 for (j = 0; j < h->arcount; j++) {
839 i = __encode_answer(ar[j], dest, maxlen);
840 if (i < 0)
841 return i;
842 dest += i;
843 maxlen -= i;
844 total += i;
847 return total;
849 #endif /* L_encodep */
852 #ifdef L_decodep
854 int __decode_packet(unsigned char *data, struct resolv_header *h) attribute_hidden;
855 int __decode_packet(unsigned char *data, struct resolv_header *h)
857 __decode_header(data, h);
858 return HFIXEDSZ;
860 #endif /* L_decodep */
863 #ifdef L_formquery
865 int __form_query(int id,
866 const char *name,
867 int type,
868 unsigned char *packet,
869 int maxlen) attribute_hidden;
870 int __form_query(int id,
871 const char *name,
872 int type,
873 unsigned char *packet,
874 int maxlen)
876 struct resolv_header h;
877 struct resolv_question q;
878 int i, j;
880 memset(&h, 0, sizeof(h));
881 h.id = id;
882 h.qdcount = 1;
884 q.dotted = (char *) name;
885 q.qtype = type;
886 q.qclass = C_IN; /* CLASS_IN */
888 i = __encode_header(&h, packet, maxlen);
889 if (i < 0)
890 return i;
892 j = __encode_question(&q, packet + i, maxlen - i);
893 if (j < 0)
894 return j;
896 return i + j;
898 #endif /* L_formquery */
899 #endif /* CURRENTLY_UNUSED */
902 #ifdef L_opennameservers
904 # if __BYTE_ORDER == __LITTLE_ENDIAN
905 #define NAMESERVER_PORT_N (__bswap_constant_16(NAMESERVER_PORT))
906 #else
907 #define NAMESERVER_PORT_N NAMESERVER_PORT
908 #endif
910 __UCLIBC_MUTEX_INIT(__resolv_lock, PTHREAD_MUTEX_INITIALIZER);
912 /* Protected by __resolv_lock */
913 void (*__res_sync)(void);
914 /*uint32_t __resolv_opts; */
915 uint8_t __resolv_timeout = RES_TIMEOUT;
916 uint8_t __resolv_attempts = RES_DFLRETRY;
917 unsigned __nameservers;
918 unsigned __searchdomains;
919 sockaddr46_t *__nameserver;
920 char **__searchdomain;
921 #ifdef __UCLIBC_HAS_IPV4__
922 const struct sockaddr_in __local_nameserver = {
923 .sin_family = AF_INET,
924 .sin_port = NAMESERVER_PORT_N,
926 #else
927 const struct sockaddr_in6 __local_nameserver = {
928 .sin6_family = AF_INET6,
929 .sin6_port = NAMESERVER_PORT_N,
931 #endif
933 /* Helpers. Both stop on EOL, if it's '\n', it is converted to NUL first */
934 static char *skip_nospace(char *p)
936 while (*p != '\0' && !isspace(*p)) {
937 if (*p == '\n') {
938 *p = '\0';
939 break;
941 p++;
943 return p;
945 static char *skip_and_NUL_space(char *p)
947 /* NB: '\n' is not isspace! */
948 while (1) {
949 char c = *p;
950 if (c == '\0' || !isspace(c))
951 break;
952 *p = '\0';
953 if (c == '\n' || c == '#')
954 break;
955 p++;
957 return p;
960 /* Must be called under __resolv_lock. */
961 void __open_nameservers(void)
963 static uint32_t resolv_conf_mtime;
965 char szBuffer[MAXLEN_searchdomain];
966 FILE *fp;
967 int i;
968 sockaddr46_t sa;
970 if (!__res_sync) {
971 /* Reread /etc/resolv.conf if it was modified. */
972 struct stat sb;
973 if (stat("/etc/resolv.conf", &sb) != 0)
974 sb.st_mtime = 0;
975 if (resolv_conf_mtime != (uint32_t)sb.st_mtime) {
976 resolv_conf_mtime = sb.st_mtime;
977 __close_nameservers(); /* force config reread */
981 if (__nameservers)
982 goto sync;
984 __resolv_timeout = RES_TIMEOUT;
985 __resolv_attempts = RES_DFLRETRY;
987 fp = fopen("/etc/resolv.conf", "r");
988 #ifdef FALLBACK_TO_CONFIG_RESOLVCONF
989 if (!fp) {
990 /* If we do not have a pre-populated /etc/resolv.conf then
991 try to use the one from /etc/config which exists on numerous
992 systems ranging from some uClinux to IRIX installations and
993 may be the only /etc dir that was mounted rw. */
994 fp = fopen("/etc/config/resolv.conf", "r");
996 #endif
998 if (fp) {
999 while (fgets(szBuffer, sizeof(szBuffer), fp) != NULL) {
1000 void *ptr;
1001 char *keyword, *p;
1003 keyword = p = skip_and_NUL_space(szBuffer);
1004 /* skip keyword */
1005 p = skip_nospace(p);
1006 /* find next word */
1007 p = skip_and_NUL_space(p);
1009 if (strcmp(keyword, "nameserver") == 0) {
1010 /* terminate IP addr */
1011 *skip_nospace(p) = '\0';
1012 memset(&sa, 0, sizeof(sa));
1013 if (0) /* nothing */;
1014 #ifdef __UCLIBC_HAS_IPV6__
1015 else if (inet_pton(AF_INET6, p, &sa.sa6.sin6_addr) > 0) {
1016 sa.sa6.sin6_family = AF_INET6;
1017 sa.sa6.sin6_port = htons(NAMESERVER_PORT);
1019 #endif
1020 #ifdef __UCLIBC_HAS_IPV4__
1021 else if (inet_pton(AF_INET, p, &sa.sa4.sin_addr) > 0) {
1022 sa.sa4.sin_family = AF_INET;
1023 sa.sa4.sin_port = htons(NAMESERVER_PORT);
1025 #endif
1026 else
1027 continue; /* garbage on this line */
1028 ptr = realloc(__nameserver, (__nameservers + 1) * sizeof(__nameserver[0]));
1029 if (!ptr)
1030 continue;
1031 __nameserver = ptr;
1032 __nameserver[__nameservers++] = sa; /* struct copy */
1033 continue;
1035 if (strcmp(keyword, "domain") == 0 || strcmp(keyword, "search") == 0) {
1036 char *p1;
1038 /* free old domains ("last 'domain' or 'search' wins" rule) */
1039 while (__searchdomains)
1040 free(__searchdomain[--__searchdomains]);
1041 /*free(__searchdomain);*/
1042 /*__searchdomain = NULL; - not necessary */
1043 next_word:
1044 /* terminate current word */
1045 p1 = skip_nospace(p);
1046 /* find next word (maybe) */
1047 p1 = skip_and_NUL_space(p1);
1048 /* add it */
1049 ptr = realloc(__searchdomain, (__searchdomains + 1) * sizeof(__searchdomain[0]));
1050 if (!ptr)
1051 continue;
1052 __searchdomain = ptr;
1053 /* NB: strlen(p) <= MAXLEN_searchdomain) because szBuffer[] is smaller */
1054 ptr = strdup(p);
1055 if (!ptr)
1056 continue;
1057 DPRINTF("adding search %s\n", (char*)ptr);
1058 __searchdomain[__searchdomains++] = (char*)ptr;
1059 p = p1;
1060 if (*p)
1061 goto next_word;
1062 continue;
1064 /* if (strcmp(keyword, "sortlist") == 0)... */
1065 if (strcmp(keyword, "options") == 0) {
1066 char *p1;
1067 uint8_t *what;
1069 if (p == NULL || (p1 = strchr(p, ':')) == NULL)
1070 continue;
1071 *p1++ = '\0';
1072 if (strcmp(p, "timeout") == 0)
1073 what = &__resolv_timeout;
1074 else if (strcmp(p, "attempts") == 0)
1075 what = &__resolv_attempts;
1076 else
1077 continue;
1078 *what = atoi(p1);
1079 DPRINTF("option %s:%d\n", p, *what);
1082 fclose(fp);
1084 if (__nameservers == 0) {
1085 /* Have to handle malloc failure! What a mess...
1086 * And it's not only here, we need to be careful
1087 * to never write into __nameserver[0] if it points
1088 * to constant __local_nameserver, or free it. */
1089 __nameserver = malloc(sizeof(__nameserver[0]));
1090 if (__nameserver)
1091 memcpy(__nameserver, &__local_nameserver, sizeof(__local_nameserver));
1092 else
1093 __nameserver = (void*) &__local_nameserver;
1094 __nameservers++;
1096 if (__searchdomains == 0) {
1097 char buf[256];
1098 char *p;
1099 i = gethostname(buf, sizeof(buf) - 1);
1100 buf[sizeof(buf) - 1] = '\0';
1101 if (i == 0 && (p = strchr(buf, '.')) != NULL && p[1]) {
1102 p = strdup(p + 1);
1103 if (!p)
1104 goto err;
1105 __searchdomain = malloc(sizeof(__searchdomain[0]));
1106 if (!__searchdomain) {
1107 free(p);
1108 goto err;
1110 __searchdomain[0] = p;
1111 __searchdomains++;
1112 err: ;
1115 DPRINTF("nameservers = %d\n", __nameservers);
1117 sync:
1118 if (__res_sync)
1119 __res_sync();
1121 #endif /* L_opennameservers */
1124 #ifdef L_closenameservers
1126 /* Must be called under __resolv_lock. */
1127 void __close_nameservers(void)
1129 if (__nameserver != (void*) &__local_nameserver)
1130 free(__nameserver);
1131 __nameserver = NULL;
1132 __nameservers = 0;
1133 while (__searchdomains)
1134 free(__searchdomain[--__searchdomains]);
1135 free(__searchdomain);
1136 __searchdomain = NULL;
1137 /*__searchdomains = 0; - already is */
1139 #endif /* L_closenameservers */
1142 #ifdef L_dnslookup
1144 /* Helpers */
1145 static int __length_question(const unsigned char *data, int maxlen)
1147 const unsigned char *start;
1148 unsigned b;
1150 if (!data)
1151 return -1;
1153 start = data;
1154 while (1) {
1155 if (maxlen <= 0)
1156 return -1;
1157 b = *data++;
1158 if (b == 0)
1159 break;
1160 if ((b & 0xc0) == 0xc0) {
1161 /* It's a "compressed" name. */
1162 data++; /* skip lsb of redirected offset */
1163 maxlen -= 2;
1164 break;
1166 data += b;
1167 maxlen -= (b + 1); /* account for data++ above */
1169 /* Up to here we were skipping encoded name */
1171 /* Account for QTYPE and QCLASS fields */
1172 if (maxlen < 4)
1173 return -1;
1174 return data - start + 2 + 2;
1177 static int __decode_answer(const unsigned char *message, /* packet */
1178 int offset,
1179 int len, /* total packet len */
1180 struct resolv_answer *a)
1182 char temp[256];
1183 int i;
1185 DPRINTF("decode_answer(start): off %d, len %d\n", offset, len);
1186 i = __decode_dotted(message, offset, len, temp, sizeof(temp));
1187 if (i < 0)
1188 return i;
1190 message += offset + i;
1191 len -= i + RRFIXEDSZ + offset;
1192 if (len < 0) {
1193 DPRINTF("decode_answer: off %d, len %d, i %d\n", offset, len, i);
1194 return len;
1197 /* TODO: what if strdup fails? */
1198 a->dotted = strdup(temp);
1199 a->atype = (message[0] << 8) | message[1];
1200 message += 2;
1201 a->aclass = (message[0] << 8) | message[1];
1202 message += 2;
1203 a->ttl = (message[0] << 24) |
1204 (message[1] << 16) | (message[2] << 8) | (message[3] << 0);
1205 message += 4;
1206 a->rdlength = (message[0] << 8) | message[1];
1207 message += 2;
1208 a->rdata = message;
1209 a->rdoffset = offset + i + RRFIXEDSZ;
1211 DPRINTF("i=%d,rdlength=%d\n", i, a->rdlength);
1213 if (len < a->rdlength)
1214 return -1;
1215 return i + RRFIXEDSZ + a->rdlength;
1218 /* On entry:
1219 * a.buf(len) = auxiliary buffer for IP addresses after first one
1220 * a.add_count = how many additional addresses are there already
1221 * outpacket = where to save ptr to raw packet? can be NULL
1222 * On exit:
1223 * ret < 0: error, all other data is not valid
1224 * ret >= 0: length of reply packet
1225 * a.add_count & a.buf: updated
1226 * a.rdlength: length of addresses (4 bytes for IPv4)
1227 * *outpacket: updated (packet is malloced, you need to free it)
1228 * a.rdata: points into *outpacket to 1st IP addr
1229 * NB: don't pass outpacket == NULL if you need to use a.rdata!
1230 * a.atype: type of query?
1231 * a.dotted: which name we _actually_ used. May contain search domains
1232 * appended. (why the filed is called "dotted" I have no idea)
1233 * This is a malloced string. May be NULL because strdup failed.
1235 int __dns_lookup(const char *name,
1236 int type,
1237 unsigned char **outpacket,
1238 struct resolv_answer *a)
1240 /* Protected by __resolv_lock: */
1241 static int last_ns_num = 0;
1242 static uint16_t last_id = 1;
1244 int i, j, fd, rc;
1245 int packet_len;
1246 int name_len;
1247 #ifdef USE_SELECT
1248 struct timeval tv;
1249 fd_set fds;
1250 #else
1251 struct pollfd fds;
1252 #endif
1253 struct resolv_header h;
1254 struct resolv_question q;
1255 struct resolv_answer ma;
1256 bool first_answer = 1;
1257 int retries_left;
1258 unsigned char *packet = malloc(PACKETSZ);
1259 char *lookup;
1260 int variant = -1; /* search domain to append, -1: none */
1261 int local_ns_num = -1; /* Nth server to use */
1262 int local_id = local_id; /* for compiler */
1263 int sdomains;
1264 bool ends_with_dot;
1265 sockaddr46_t sa;
1267 fd = -1;
1268 lookup = NULL;
1269 name_len = strlen(name);
1270 if ((unsigned)name_len >= MAXDNAME - MAXLEN_searchdomain - 2)
1271 goto fail; /* paranoia */
1272 lookup = malloc(name_len + 1/*for '.'*/ + MAXLEN_searchdomain + 1);
1273 if (!packet || !lookup || !name[0])
1274 goto fail;
1275 ends_with_dot = (name[name_len - 1] == '.');
1276 /* no strcpy! paranoia, user might change name[] under us */
1277 memcpy(lookup, name, name_len);
1279 DPRINTF("Looking up type %d answer for '%s'\n", type, name);
1280 retries_left = 0; /* for compiler */
1281 do {
1282 int pos;
1283 unsigned reply_timeout;
1285 if (fd != -1) {
1286 close(fd);
1287 fd = -1;
1290 /* Mess with globals while under lock */
1291 /* NB: even data *pointed to* by globals may vanish
1292 * outside the locks. We should assume any and all
1293 * globals can completely change between locked
1294 * code regions. OTOH, this is rare, so we don't need
1295 * to handle it "nicely" (do not skip servers,
1296 * search domains, etc), we only need to ensure
1297 * we do not SEGV, use freed+overwritten data
1298 * or do other Really Bad Things. */
1299 __UCLIBC_MUTEX_LOCK(__resolv_lock);
1300 __open_nameservers();
1301 sdomains = __searchdomains;
1302 lookup[name_len] = '\0';
1303 if ((unsigned)variant < sdomains) {
1304 /* lookup is name_len + 1 + MAXLEN_searchdomain + 1 long */
1305 /* __searchdomain[] is not bigger than MAXLEN_searchdomain */
1306 lookup[name_len] = '.';
1307 strcpy(&lookup[name_len + 1], __searchdomain[variant]);
1309 /* first time? pick starting server etc */
1310 if (local_ns_num < 0) {
1311 local_id = last_id;
1312 /*TODO: implement /etc/resolv.conf's "options rotate"
1313 (a.k.a. RES_ROTATE bit in _res.options)
1314 local_ns_num = 0;
1315 if (_res.options & RES_ROTATE) */
1316 local_ns_num = last_ns_num;
1317 retries_left = __nameservers * __resolv_attempts;
1319 retries_left--;
1320 if (local_ns_num >= __nameservers)
1321 local_ns_num = 0;
1322 local_id++;
1323 local_id &= 0xffff;
1324 /* write new values back while still under lock */
1325 last_id = local_id;
1326 last_ns_num = local_ns_num;
1327 /* struct copy */
1328 /* can't just take a pointer, __nameserver[x]
1329 * is not safe to use outside of locks */
1330 sa = __nameserver[local_ns_num];
1331 __UCLIBC_MUTEX_UNLOCK(__resolv_lock);
1333 memset(packet, 0, PACKETSZ);
1334 memset(&h, 0, sizeof(h));
1336 /* encode header */
1337 h.id = local_id;
1338 h.qdcount = 1;
1339 h.rd = 1;
1340 DPRINTF("encoding header\n", h.rd);
1341 i = __encode_header(&h, packet, PACKETSZ);
1342 if (i < 0)
1343 goto fail;
1345 /* encode question */
1346 DPRINTF("lookup name: %s\n", lookup);
1347 q.dotted = lookup;
1348 q.qtype = type;
1349 q.qclass = C_IN; /* CLASS_IN */
1350 j = __encode_question(&q, packet+i, PACKETSZ-i);
1351 if (j < 0)
1352 goto fail;
1353 packet_len = i + j;
1355 /* send packet */
1356 #ifdef DEBUG
1358 const socklen_t plen = sa.sa.sa_family == AF_INET ? INET_ADDRSTRLEN : INET6_ADDRSTRLEN;
1359 char *pbuf = malloc(plen);
1360 if (pbuf == NULL) ;/* nothing */
1361 #ifdef __UCLIBC_HAS_IPV6__
1362 else if (sa.sa.sa_family == AF_INET6)
1363 pbuf = (char*)inet_ntop(AF_INET6, &sa.sa6.sin6_addr, pbuf, plen);
1364 #endif
1365 #ifdef __UCLIBC_HAS_IPV4__
1366 else if (sa.sa.sa_family == AF_INET)
1367 pbuf = (char*)inet_ntop(AF_INET, &sa.sa4.sin_addr, pbuf, plen);
1368 #endif
1369 DPRINTF("On try %d, sending query to %s, port %d\n",
1370 retries_left, pbuf, NAMESERVER_PORT);
1371 free(pbuf);
1373 #endif
1374 fd = socket(sa.sa.sa_family, SOCK_DGRAM, IPPROTO_UDP);
1375 if (fd < 0) /* paranoia */
1376 goto try_next_server;
1377 rc = connect(fd, &sa.sa, sizeof(sa));
1378 if (rc < 0) {
1379 /*if (errno == ENETUNREACH) { */
1380 /* routing error, presume not transient */
1381 goto try_next_server;
1382 /*} */
1383 /*For example, what transient error this can be? Can't think of any */
1384 /* retry */
1385 /*continue; */
1387 DPRINTF("Xmit packet len:%d id:%d qr:%d\n", packet_len, h.id, h.qr);
1388 /* no error check - if it fails, we time out on recv */
1389 send(fd, packet, packet_len, 0);
1391 #ifdef USE_SELECT
1392 reply_timeout = __resolv_timeout;
1393 wait_again:
1394 FD_ZERO(&fds);
1395 FD_SET(fd, &fds);
1396 tv.tv_sec = reply_timeout;
1397 tv.tv_usec = 0;
1398 if (select(fd + 1, &fds, NULL, NULL, &tv) <= 0) {
1399 DPRINTF("Timeout\n");
1400 /* timed out, so retry send and receive
1401 * to next nameserver */
1402 goto try_next_server;
1404 reply_timeout--;
1405 #else /* !USE_SELECT */
1406 reply_timeout = __resolv_timeout * 1000;
1407 wait_again:
1408 fds.fd = fd;
1409 fds.events = POLLIN;
1410 if (poll(&fds, 1, reply_timeout) <= 0) {
1411 DPRINTF("Timeout\n");
1412 /* timed out, so retry send and receive
1413 * to next nameserver */
1414 goto try_next_server;
1416 if (fds.revents & (POLLERR | POLLHUP | POLLNVAL)) {
1417 DPRINTF("Bad event\n");
1418 goto try_next_server;
1420 /*TODO: better timeout accounting?*/
1421 reply_timeout -= 1000;
1422 #endif /* USE_SELECT */
1424 /* vda: a bogus response seen in real world (caused SEGV in uclibc):
1425 * "ping www.google.com" sending AAAA query and getting
1426 * response with one answer... with answer part missing!
1427 * Fixed by thorough checks for not going past the packet's end.
1429 #ifdef DEBUG
1431 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";
1432 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";
1433 pos = memcmp(packet + 2, test_query + 2, 30);
1434 packet_len = recv(fd, packet, PACKETSZ, MSG_DONTWAIT);
1435 if (pos == 0) {
1436 packet_len = 32;
1437 memcpy(packet + 2, test_respn + 2, 30);
1440 #else
1441 packet_len = recv(fd, packet, PACKETSZ, MSG_DONTWAIT);
1442 #endif
1444 if (packet_len < HFIXEDSZ) {
1445 /* too short!
1446 * If the peer did shutdown then retry later,
1447 * try next peer on error.
1448 * it's just a bogus packet from somewhere */
1449 bogus_packet:
1450 if (packet_len >= 0 && reply_timeout)
1451 goto wait_again;
1452 goto try_next_server;
1454 __decode_header(packet, &h);
1455 DPRINTF("len:%d id:%d qr:%d\n", packet_len, h.id, h.qr);
1456 if (h.id != local_id || !h.qr) {
1457 /* unsolicited */
1458 goto bogus_packet;
1461 DPRINTF("Got response (i think)!\n");
1462 DPRINTF("qrcount=%d,ancount=%d,nscount=%d,arcount=%d\n",
1463 h.qdcount, h.ancount, h.nscount, h.arcount);
1464 DPRINTF("opcode=%d,aa=%d,tc=%d,rd=%d,ra=%d,rcode=%d\n",
1465 h.opcode, h.aa, h.tc, h.rd, h.ra, h.rcode);
1467 /* bug 660 says we treat negative response as an error
1468 * and retry, which is, eh, an error. :)
1469 * We were incurring long delays because of this. */
1470 if (h.rcode == NXDOMAIN || h.rcode == SERVFAIL) {
1471 /* if possible, try next search domain */
1472 if (!ends_with_dot) {
1473 DPRINTF("variant:%d sdomains:%d\n", variant, sdomains);
1474 if (variant < sdomains - 1) {
1475 /* next search domain */
1476 variant++;
1477 continue;
1479 /* no more search domains to try */
1481 if (h.rcode != SERVFAIL) {
1482 /* dont loop, this is "no such host" situation */
1483 h_errno = HOST_NOT_FOUND;
1484 goto fail1;
1487 /* Insert other non-fatal errors here, which do not warrant
1488 * switching to next nameserver */
1490 /* Strange error, assuming this nameserver is feeling bad */
1491 if (h.rcode != 0)
1492 goto try_next_server;
1494 /* Code below won't work correctly with h.ancount == 0, so... */
1495 if (h.ancount <= 0) {
1496 h_errno = NO_DATA; /* [is this correct code to check for?] */
1497 goto fail1;
1499 pos = HFIXEDSZ;
1500 for (j = 0; j < h.qdcount; j++) {
1501 DPRINTF("Skipping question %d at %d\n", j, pos);
1502 i = __length_question(packet + pos, packet_len - pos);
1503 if (i < 0) {
1504 DPRINTF("Packet'question section "
1505 "is truncated, trying next server\n");
1506 goto try_next_server;
1508 pos += i;
1509 DPRINTF("Length of question %d is %d\n", j, i);
1511 DPRINTF("Decoding answer at pos %d\n", pos);
1513 first_answer = 1;
1514 a->dotted = NULL;
1515 for (j = 0; j < h.ancount; j++) {
1516 i = __decode_answer(packet, pos, packet_len, &ma);
1517 if (i < 0) {
1518 DPRINTF("failed decode %d\n", i);
1519 /* If the message was truncated but we have
1520 * decoded some answers, pretend it's OK */
1521 if (j && h.tc)
1522 break;
1523 goto try_next_server;
1525 pos += i;
1527 if (first_answer) {
1528 ma.buf = a->buf;
1529 ma.buflen = a->buflen;
1530 ma.add_count = a->add_count;
1531 free(a->dotted);
1532 memcpy(a, &ma, sizeof(ma));
1533 if (a->atype != T_SIG && (NULL == a->buf || (type != T_A && type != T_AAAA)))
1534 break;
1535 if (a->atype != type)
1536 continue;
1537 a->add_count = h.ancount - j - 1;
1538 if ((a->rdlength + sizeof(struct in_addr*)) * a->add_count > a->buflen)
1539 break;
1540 a->add_count = 0;
1541 first_answer = 0;
1542 } else {
1543 free(ma.dotted);
1544 if (ma.atype != type)
1545 continue;
1546 if (a->rdlength != ma.rdlength) {
1547 free(a->dotted);
1548 DPRINTF("Answer address len(%u) differs from original(%u)\n",
1549 ma.rdlength, a->rdlength);
1550 goto try_next_server;
1552 memcpy(a->buf + (a->add_count * ma.rdlength), ma.rdata, ma.rdlength);
1553 ++a->add_count;
1557 /* Success! */
1558 DPRINTF("Answer name = |%s|\n", a->dotted);
1559 DPRINTF("Answer type = |%d|\n", a->atype);
1560 if (fd != -1)
1561 close(fd);
1562 if (outpacket)
1563 *outpacket = packet;
1564 else
1565 free(packet);
1566 free(lookup);
1567 return packet_len;
1569 try_next_server:
1570 /* Try next nameserver */
1571 local_ns_num++;
1572 variant = -1;
1573 } while (retries_left > 0);
1575 fail:
1576 h_errno = NETDB_INTERNAL;
1577 fail1:
1578 if (fd != -1)
1579 close(fd);
1580 free(lookup);
1581 free(packet);
1582 return -1;
1584 #endif /* L_dnslookup */
1587 #ifdef L_read_etc_hosts_r
1589 parser_t * __open_etc_hosts(void)
1591 parser_t *parser;
1592 parser = config_open("/etc/hosts");
1593 #ifdef FALLBACK_TO_CONFIG_RESOLVCONF
1594 if (parser == NULL)
1595 parser = config_open("/etc/config/hosts");
1596 #endif
1597 return parser;
1600 #define MINTOKENS 2 /* ip address + canonical name */
1601 #define MAXTOKENS (MINTOKENS + MAXALIASES)
1602 #define HALISTOFF (sizeof(char*) * (MAXTOKENS + 1)) /* reserve space for list terminator */
1603 #define INADDROFF (HALISTOFF + 2 * sizeof(char*))
1605 int __read_etc_hosts_r(
1606 parser_t * parser,
1607 const char *name,
1608 int type,
1609 enum etc_hosts_action action,
1610 struct hostent *result_buf,
1611 char *buf, size_t buflen,
1612 struct hostent **result,
1613 int *h_errnop)
1615 char **tok = NULL;
1616 struct in_addr *h_addr0 = NULL;
1617 const size_t aliaslen = INADDROFF +
1618 #ifdef __UCLIBC_HAS_IPV6__
1619 sizeof(struct in6_addr)
1620 #else
1621 sizeof(struct in_addr)
1622 #endif
1624 int ret = HOST_NOT_FOUND;
1625 /* make sure pointer is aligned */
1626 int i = ALIGN_BUFFER_OFFSET(buf);
1627 buf += i;
1628 buflen -= i;
1630 *h_errnop = NETDB_INTERNAL;
1631 if (/* (ssize_t)buflen < 0 || */ buflen < aliaslen
1632 || (buflen - aliaslen) < BUFSZ + 1)
1633 return ERANGE;
1634 if (parser == NULL)
1635 parser = __open_etc_hosts();
1636 if (parser == NULL) {
1637 *result = NULL;
1638 return errno;
1640 /* Layout in buf:
1641 * char *alias[MAXTOKENS] = {address, name, aliases...}
1642 * char **h_addr_list[1] = {*in[6]_addr, NULL}
1643 * struct in[6]_addr
1644 * char line_buffer[BUFSZ+];
1646 parser->data = buf;
1647 parser->data_len = aliaslen;
1648 parser->line_len = buflen - aliaslen;
1649 *h_errnop = HOST_NOT_FOUND;
1650 /* <ip>[[:space:]][<aliases>] */
1651 while (config_read(parser, &tok, MAXTOKENS, MINTOKENS, "# \t", PARSE_NORMAL)) {
1652 result_buf->h_aliases = tok+1;
1653 if (action == GETHOSTENT) {
1654 /* Return whatever the next entry happens to be. */
1656 } else if (action == GET_HOSTS_BYADDR) {
1657 if (strcmp(name, *tok) != 0)
1658 continue;
1659 } else { /* GET_HOSTS_BYNAME */
1660 int aliases = 0;
1661 char **alias = tok + 1;
1662 while (aliases < MAXALIASES) {
1663 char *tmp = *(alias+aliases++);
1664 if (tmp && strcasecmp(name, tmp) == 0)
1665 goto found;
1667 continue;
1669 found:
1670 result_buf->h_name = *(result_buf->h_aliases++);
1671 result_buf->h_addr_list = (char**)(buf + HALISTOFF);
1672 *(result_buf->h_addr_list + 1) = '\0';
1673 h_addr0 = (struct in_addr*)(buf + INADDROFF);
1674 result_buf->h_addr = (char*)h_addr0;
1675 if (0) /* nothing */;
1676 #ifdef __UCLIBC_HAS_IPV4__
1677 else if (type == AF_INET
1678 && inet_pton(AF_INET, *tok, h_addr0) > 0) {
1679 DPRINTF("Found INET\n");
1680 result_buf->h_addrtype = AF_INET;
1681 result_buf->h_length = sizeof(struct in_addr);
1682 *result = result_buf;
1683 ret = NETDB_SUCCESS;
1685 #endif
1686 #ifdef __UCLIBC_HAS_IPV6__
1687 #define in6 ((struct in6_addr *)buf)
1688 else if (type == AF_INET6
1689 && inet_pton(AF_INET6, *tok, h_addr0) > 0) {
1690 DPRINTF("Found INET6\n");
1691 result_buf->h_addrtype = AF_INET6;
1692 result_buf->h_length = sizeof(struct in6_addr);
1693 *result = result_buf;
1694 ret = NETDB_SUCCESS;
1696 #endif
1697 else {
1698 /* continue parsing in the hope the user has multiple
1699 * host types listed in the database like so:
1700 * <ipv4 addr> host
1701 * <ipv6 addr> host
1702 * If looking for an IPv6 addr, don't bail when we got the IPv4
1704 DPRINTF("Error: Found host but different address family\n");
1705 /* NB: gethostbyname2_r depends on this feature
1706 * to avoid looking for IPv6 addr of "localhost" etc */
1707 ret = TRY_AGAIN;
1708 continue;
1710 break;
1712 if (action != GETHOSTENT)
1713 config_close(parser);
1714 return ret;
1715 #undef in6
1717 #endif /* L_read_etc_hosts_r */
1720 #ifdef L_get_hosts_byname_r
1722 int __get_hosts_byname_r(const char *name,
1723 int type,
1724 struct hostent *result_buf,
1725 char *buf,
1726 size_t buflen,
1727 struct hostent **result,
1728 int *h_errnop)
1730 return __read_etc_hosts_r(NULL, name, type, GET_HOSTS_BYNAME,
1731 result_buf, buf, buflen, result, h_errnop);
1733 #endif /* L_get_hosts_byname_r */
1736 #ifdef L_get_hosts_byaddr_r
1738 int __get_hosts_byaddr_r(const char *addr,
1739 int len,
1740 int type,
1741 struct hostent *result_buf,
1742 char *buf,
1743 size_t buflen,
1744 struct hostent **result,
1745 int *h_errnop)
1747 #ifndef __UCLIBC_HAS_IPV6__
1748 char ipaddr[INET_ADDRSTRLEN];
1749 #else
1750 char ipaddr[INET6_ADDRSTRLEN];
1751 #endif
1753 switch (type) {
1754 #ifdef __UCLIBC_HAS_IPV4__
1755 case AF_INET:
1756 if (len != sizeof(struct in_addr))
1757 return 0;
1758 break;
1759 #endif
1760 #ifdef __UCLIBC_HAS_IPV6__
1761 case AF_INET6:
1762 if (len != sizeof(struct in6_addr))
1763 return 0;
1764 break;
1765 #endif
1766 default:
1767 return 0;
1770 inet_ntop(type, addr, ipaddr, sizeof(ipaddr));
1772 return __read_etc_hosts_r(NULL, ipaddr, type, GET_HOSTS_BYADDR,
1773 result_buf, buf, buflen, result, h_errnop);
1775 #endif /* L_get_hosts_byaddr_r */
1778 #ifdef L_getnameinfo
1780 int getnameinfo(const struct sockaddr *sa,
1781 socklen_t addrlen,
1782 char *host,
1783 socklen_t hostlen,
1784 char *serv,
1785 socklen_t servlen,
1786 unsigned flags)
1788 int serrno = errno;
1789 bool ok = 0;
1790 struct hostent *hoste = NULL;
1791 char domain[256];
1793 if (flags & ~(NI_NUMERICHOST|NI_NUMERICSERV|NI_NOFQDN|NI_NAMEREQD|NI_DGRAM))
1794 return EAI_BADFLAGS;
1796 if (sa == NULL || addrlen < sizeof(sa_family_t))
1797 return EAI_FAMILY;
1799 if (sa->sa_family == AF_LOCAL) /* valid */;
1800 #ifdef __UCLIBC_HAS_IPV4__
1801 else if (sa->sa_family == AF_INET) {
1802 if (addrlen < sizeof(struct sockaddr_in))
1803 return EAI_FAMILY;
1805 #endif
1806 #ifdef __UCLIBC_HAS_IPV6__
1807 else if (sa->sa_family == AF_INET6) {
1808 if (addrlen < sizeof(struct sockaddr_in6))
1809 return EAI_FAMILY;
1811 #endif
1812 else
1813 return EAI_FAMILY;
1815 if (host != NULL && hostlen > 0)
1816 switch (sa->sa_family) {
1817 case AF_INET:
1818 #ifdef __UCLIBC_HAS_IPV6__
1819 case AF_INET6:
1820 #endif
1821 if (!(flags & NI_NUMERICHOST)) {
1822 if (0) /* nothing */;
1823 #ifdef __UCLIBC_HAS_IPV6__
1824 else if (sa->sa_family == AF_INET6)
1825 hoste = gethostbyaddr((const void *)
1826 &(((const struct sockaddr_in6 *) sa)->sin6_addr),
1827 sizeof(struct in6_addr), AF_INET6);
1828 #endif
1829 #ifdef __UCLIBC_HAS_IPV4__
1830 else
1831 hoste = gethostbyaddr((const void *)
1832 &(((const struct sockaddr_in *)sa)->sin_addr),
1833 sizeof(struct in_addr), AF_INET);
1834 #endif
1836 if (hoste) {
1837 char *c;
1838 if ((flags & NI_NOFQDN)
1839 && (getdomainname(domain, sizeof(domain)) == 0)
1840 && (c = strstr(hoste->h_name, domain)) != NULL
1841 && (c != hoste->h_name) && (*(--c) == '.')
1843 strncpy(host, hoste->h_name,
1844 MIN(hostlen, (size_t) (c - hoste->h_name)));
1845 host[MIN(hostlen - 1, (size_t) (c - hoste->h_name))] = '\0';
1846 } else {
1847 strncpy(host, hoste->h_name, hostlen);
1849 ok = 1;
1853 if (!ok) {
1854 const char *c = NULL;
1856 if (flags & NI_NAMEREQD) {
1857 errno = serrno;
1858 return EAI_NONAME;
1860 if (0) /* nothing */;
1861 #ifdef __UCLIBC_HAS_IPV6__
1862 else if (sa->sa_family == AF_INET6) {
1863 const struct sockaddr_in6 *sin6p;
1865 sin6p = (const struct sockaddr_in6 *) sa;
1866 c = inet_ntop(AF_INET6,
1867 (const void *) &sin6p->sin6_addr,
1868 host, hostlen);
1869 #if 0
1870 /* Does scope id need to be supported? */
1871 uint32_t scopeid;
1872 scopeid = sin6p->sin6_scope_id;
1873 if (scopeid != 0) {
1874 /* Buffer is >= IFNAMSIZ+1. */
1875 char scopebuf[IFNAMSIZ + 1];
1876 char *scopeptr;
1877 int ni_numericscope = 0;
1878 size_t real_hostlen = strnlen(host, hostlen);
1879 size_t scopelen = 0;
1881 scopebuf[0] = SCOPE_DELIMITER;
1882 scopebuf[1] = '\0';
1883 scopeptr = &scopebuf[1];
1885 if (IN6_IS_ADDR_LINKLOCAL(&sin6p->sin6_addr)
1886 || IN6_IS_ADDR_MC_LINKLOCAL(&sin6p->sin6_addr)) {
1887 if (if_indextoname(scopeid, scopeptr) == NULL)
1888 ++ni_numericscope;
1889 else
1890 scopelen = strlen(scopebuf);
1891 } else {
1892 ++ni_numericscope;
1895 if (ni_numericscope)
1896 scopelen = 1 + snprintf(scopeptr,
1897 (scopebuf
1898 + sizeof scopebuf
1899 - scopeptr),
1900 "%u", scopeid);
1902 if (real_hostlen + scopelen + 1 > hostlen)
1903 return EAI_SYSTEM;
1904 memcpy(host + real_hostlen, scopebuf, scopelen + 1);
1906 #endif
1908 #endif /* __UCLIBC_HAS_IPV6__ */
1909 #if defined __UCLIBC_HAS_IPV4__
1910 else {
1911 c = inet_ntop(AF_INET, (const void *)
1912 &(((const struct sockaddr_in *) sa)->sin_addr),
1913 host, hostlen);
1915 #endif
1916 if (c == NULL) {
1917 errno = serrno;
1918 return EAI_SYSTEM;
1920 ok = 1;
1922 break;
1924 case AF_LOCAL:
1925 if (!(flags & NI_NUMERICHOST)) {
1926 struct utsname utsname;
1928 if (!uname(&utsname)) {
1929 strncpy(host, utsname.nodename, hostlen);
1930 break;
1934 if (flags & NI_NAMEREQD) {
1935 errno = serrno;
1936 return EAI_NONAME;
1939 strncpy(host, "localhost", hostlen);
1940 break;
1941 /* Already checked above
1942 default:
1943 return EAI_FAMILY;
1947 if (serv && (servlen > 0)) {
1948 if (sa->sa_family == AF_LOCAL) {
1949 strncpy(serv, ((const struct sockaddr_un *) sa)->sun_path, servlen);
1950 } else { /* AF_INET || AF_INET6 */
1951 if (!(flags & NI_NUMERICSERV)) {
1952 struct servent *s;
1953 s = getservbyport(((const struct sockaddr_in *) sa)->sin_port,
1954 ((flags & NI_DGRAM) ? "udp" : "tcp"));
1955 if (s) {
1956 strncpy(serv, s->s_name, servlen);
1957 goto DONE;
1960 snprintf(serv, servlen, "%d",
1961 ntohs(((const struct sockaddr_in *) sa)->sin_port));
1964 DONE:
1965 if (host && (hostlen > 0))
1966 host[hostlen-1] = 0;
1967 if (serv && (servlen > 0))
1968 serv[servlen-1] = 0;
1969 errno = serrno;
1970 return 0;
1972 libc_hidden_def(getnameinfo)
1973 #endif /* L_getnameinfo */
1976 #ifdef L_gethostbyname_r
1978 /* Bug 671 says:
1979 * "uClibc resolver's gethostbyname does not return the requested name
1980 * as an alias, but instead returns the canonical name. glibc's
1981 * gethostbyname has a similar bug where it returns the requested name
1982 * with the search domain name appended (to make a FQDN) as an alias,
1983 * but not the original name itself. Both contradict POSIX, which says
1984 * that the name argument passed to gethostbyname must be in the alias list"
1985 * This is fixed now, and we differ from glibc:
1987 * $ ./gethostbyname_uclibc wer.google.com
1988 * h_name:'c13-ss-2-lb.cnet.com'
1989 * h_length:4
1990 * h_addrtype:2 AF_INET
1991 * alias:'wer.google.com' <===
1992 * addr: 0x4174efd8 '216.239.116.65'
1994 * $ ./gethostbyname_glibc wer.google.com
1995 * h_name:'c13-ss-2-lb.cnet.com'
1996 * h_length:4
1997 * h_addrtype:2 AF_INET
1998 * alias:'wer.google.com.com' <===
1999 * addr:'216.239.116.65'
2001 * When examples were run, /etc/resolv.conf contained "search com" line.
2003 int gethostbyname_r(const char *name,
2004 struct hostent *result_buf,
2005 char *buf,
2006 size_t buflen,
2007 struct hostent **result,
2008 int *h_errnop)
2010 struct in_addr **addr_list;
2011 char **alias;
2012 char *alias0;
2013 unsigned char *packet;
2014 struct resolv_answer a;
2015 int i;
2016 int packet_len;
2017 int wrong_af = 0;
2019 *result = NULL;
2020 if (!name)
2021 return EINVAL;
2023 /* do /etc/hosts first */
2025 int old_errno = errno; /* save the old errno and reset errno */
2026 __set_errno(0); /* to check for missing /etc/hosts. */
2027 i = __get_hosts_byname_r(name, AF_INET, result_buf,
2028 buf, buflen, result, h_errnop);
2029 if (i == NETDB_SUCCESS) {
2030 __set_errno(old_errno);
2031 return i;
2033 switch (*h_errnop) {
2034 case HOST_NOT_FOUND:
2035 wrong_af = (i == TRY_AGAIN);
2036 case NO_ADDRESS:
2037 break;
2038 case NETDB_INTERNAL:
2039 if (errno == ENOENT) {
2040 break;
2042 /* else fall through */
2043 default:
2044 return i;
2046 __set_errno(old_errno);
2049 DPRINTF("Nothing found in /etc/hosts\n");
2051 *h_errnop = NETDB_INTERNAL;
2053 /* prepare future h_aliases[0] */
2054 i = strlen(name) + 1;
2055 if ((ssize_t)buflen <= i)
2056 return ERANGE;
2057 memcpy(buf, name, i); /* paranoia: name might change */
2058 alias0 = buf;
2059 buf += i;
2060 buflen -= i;
2061 /* make sure pointer is aligned */
2062 i = ALIGN_BUFFER_OFFSET(buf);
2063 buf += i;
2064 buflen -= i;
2065 /* Layout in buf:
2066 * char *alias[2];
2067 * struct in_addr* addr_list[NN+1];
2068 * struct in_addr* in[NN];
2070 alias = (char **)buf;
2071 buf += sizeof(alias[0]) * 2;
2072 buflen -= sizeof(alias[0]) * 2;
2073 addr_list = (struct in_addr **)buf;
2074 /* buflen may be < 0, must do signed compare */
2075 if ((ssize_t)buflen < 256)
2076 return ERANGE;
2078 /* we store only one "alias" - the name itself */
2079 #ifdef __UCLIBC_MJN3_ONLY__
2080 #warning TODO -- generate the full list
2081 #endif
2082 alias[0] = alias0;
2083 alias[1] = NULL;
2085 /* maybe it is already an address? */
2087 struct in_addr *in = (struct in_addr *)(buf + sizeof(addr_list[0]) * 2);
2088 if (inet_aton(name, in)) {
2089 addr_list[0] = in;
2090 addr_list[1] = NULL;
2091 result_buf->h_name = alias0;
2092 result_buf->h_aliases = alias;
2093 result_buf->h_addrtype = AF_INET;
2094 result_buf->h_length = sizeof(struct in_addr);
2095 result_buf->h_addr_list = (char **) addr_list;
2096 *result = result_buf;
2097 *h_errnop = NETDB_SUCCESS;
2098 return NETDB_SUCCESS;
2102 /* what if /etc/hosts has it but it's not IPv4?
2103 * F.e. "::1 localhost6". We don't do DNS query for such hosts -
2104 * "ping localhost6" should be fast even if DNS server is down! */
2105 if (wrong_af) {
2106 *h_errnop = HOST_NOT_FOUND;
2107 return TRY_AGAIN;
2110 /* talk to DNS servers */
2111 a.buf = buf;
2112 /* take into account that at least one address will be there,
2113 * we'll need space for one in_addr + two addr_list[] elems */
2114 a.buflen = buflen - ((sizeof(addr_list[0]) * 2 + sizeof(struct in_addr)));
2115 a.add_count = 0;
2116 packet_len = __dns_lookup(name, T_A, &packet, &a);
2117 if (packet_len < 0) {
2118 *h_errnop = HOST_NOT_FOUND;
2119 DPRINTF("__dns_lookup returned < 0\n");
2120 return TRY_AGAIN;
2123 if (a.atype == T_A) { /* ADDRESS */
2124 /* we need space for addr_list[] and one IPv4 address */
2125 /* + 1 accounting for 1st addr (it's in a.rdata),
2126 * another + 1 for NULL in last addr_list[]: */
2127 int need_bytes = sizeof(addr_list[0]) * (a.add_count + 1 + 1)
2128 /* for 1st addr (it's in a.rdata): */
2129 + sizeof(struct in_addr);
2130 /* how many bytes will 2nd and following addresses take? */
2131 int ips_len = a.add_count * a.rdlength;
2133 buflen -= (need_bytes + ips_len);
2134 if ((ssize_t)buflen < 0) {
2135 DPRINTF("buffer too small for all addresses\n");
2136 /* *h_errnop = NETDB_INTERNAL; - already is */
2137 i = ERANGE;
2138 goto free_and_ret;
2141 /* if there are additional addresses in buf,
2142 * move them forward so that they are not destroyed */
2143 DPRINTF("a.add_count:%d a.rdlength:%d a.rdata:%p\n", a.add_count, a.rdlength, a.rdata);
2144 memmove(buf + need_bytes, buf, ips_len);
2146 /* 1st address is in a.rdata, insert it */
2147 buf += need_bytes - sizeof(struct in_addr);
2148 memcpy(buf, a.rdata, sizeof(struct in_addr));
2150 /* fill addr_list[] */
2151 for (i = 0; i <= a.add_count; i++) {
2152 addr_list[i] = (struct in_addr*)buf;
2153 buf += sizeof(struct in_addr);
2155 addr_list[i] = NULL;
2157 /* if we have enough space, we can report "better" name
2158 * (it may contain search domains attached by __dns_lookup,
2159 * or CNAME of the host if it is different from the name
2160 * we used to find it) */
2161 if (a.dotted && buflen > strlen(a.dotted)) {
2162 strcpy(buf, a.dotted);
2163 alias0 = buf;
2166 result_buf->h_name = alias0;
2167 result_buf->h_aliases = alias;
2168 result_buf->h_addrtype = AF_INET;
2169 result_buf->h_length = sizeof(struct in_addr);
2170 result_buf->h_addr_list = (char **) addr_list;
2171 *result = result_buf;
2172 *h_errnop = NETDB_SUCCESS;
2173 i = NETDB_SUCCESS;
2174 goto free_and_ret;
2177 *h_errnop = HOST_NOT_FOUND;
2178 __set_h_errno(HOST_NOT_FOUND);
2179 i = TRY_AGAIN;
2181 free_and_ret:
2182 free(a.dotted);
2183 free(packet);
2184 return i;
2186 libc_hidden_def(gethostbyname_r)
2187 #endif /* L_gethostbyname_r */
2190 #ifdef L_gethostbyname2_r
2192 int gethostbyname2_r(const char *name,
2193 int family,
2194 struct hostent *result_buf,
2195 char *buf,
2196 size_t buflen,
2197 struct hostent **result,
2198 int *h_errnop)
2200 #ifndef __UCLIBC_HAS_IPV6__
2201 return family == (AF_INET)
2202 ? gethostbyname_r(name, result_buf, buf, buflen, result, h_errnop)
2203 : HOST_NOT_FOUND;
2204 #else
2205 struct in6_addr **addr_list;
2206 char **alias;
2207 char *alias0;
2208 unsigned char *packet;
2209 struct resolv_answer a;
2210 int i;
2211 int packet_len;
2212 int wrong_af = 0;
2214 if (family == AF_INET)
2215 return gethostbyname_r(name, result_buf, buf, buflen, result, h_errnop);
2217 *result = NULL;
2218 if (family != AF_INET6)
2219 return EINVAL;
2221 if (!name)
2222 return EINVAL;
2224 /* do /etc/hosts first */
2226 int old_errno = errno; /* save the old errno and reset errno */
2227 __set_errno(0); /* to check for missing /etc/hosts. */
2228 i = __get_hosts_byname_r(name, AF_INET6 /*family*/, result_buf,
2229 buf, buflen, result, h_errnop);
2230 if (i == NETDB_SUCCESS) {
2231 __set_errno(old_errno);
2232 return i;
2234 switch (*h_errnop) {
2235 case HOST_NOT_FOUND:
2236 wrong_af = (i == TRY_AGAIN);
2237 case NO_ADDRESS:
2238 break;
2239 case NETDB_INTERNAL:
2240 if (errno == ENOENT) {
2241 break;
2243 /* else fall through */
2244 default:
2245 return i;
2247 __set_errno(old_errno);
2250 DPRINTF("Nothing found in /etc/hosts\n");
2252 *h_errnop = NETDB_INTERNAL;
2254 /* prepare future h_aliases[0] */
2255 i = strlen(name) + 1;
2256 if ((ssize_t)buflen <= i)
2257 return ERANGE;
2258 memcpy(buf, name, i); /* paranoia: name might change */
2259 alias0 = buf;
2260 buf += i;
2261 buflen -= i;
2262 /* make sure pointer is aligned */
2263 i = ALIGN_BUFFER_OFFSET(buf);
2264 buf += i;
2265 buflen -= i;
2266 /* Layout in buf:
2267 * char *alias[2];
2268 * struct in6_addr* addr_list[NN+1];
2269 * struct in6_addr* in[NN];
2271 alias = (char **)buf;
2272 buf += sizeof(alias[0]) * 2;
2273 buflen -= sizeof(alias[0]) * 2;
2274 addr_list = (struct in6_addr **)buf;
2275 /* buflen may be < 0, must do signed compare */
2276 if ((ssize_t)buflen < 256)
2277 return ERANGE;
2279 /* we store only one "alias" - the name itself */
2280 #ifdef __UCLIBC_MJN3_ONLY__
2281 #warning TODO -- generate the full list
2282 #endif
2283 alias[0] = alias0;
2284 alias[1] = NULL;
2286 /* maybe it is already an address? */
2288 struct in6_addr *in = (struct in6_addr *)(buf + sizeof(addr_list[0]) * 2);
2289 if (inet_pton(AF_INET6, name, in)) {
2290 addr_list[0] = in;
2291 addr_list[1] = NULL;
2292 result_buf->h_name = alias0;
2293 result_buf->h_aliases = alias;
2294 result_buf->h_addrtype = AF_INET6;
2295 result_buf->h_length = sizeof(struct in6_addr);
2296 result_buf->h_addr_list = (char **) addr_list;
2297 *result = result_buf;
2298 *h_errnop = NETDB_SUCCESS;
2299 return NETDB_SUCCESS;
2303 /* what if /etc/hosts has it but it's not IPv6?
2304 * F.e. "127.0.0.1 localhost". We don't do DNS query for such hosts -
2305 * "ping localhost" should be fast even if DNS server is down! */
2306 if (wrong_af) {
2307 *h_errnop = HOST_NOT_FOUND;
2308 return TRY_AGAIN;
2311 /* talk to DNS servers */
2312 a.buf = buf;
2313 /* take into account that at least one address will be there,
2314 * we'll need space of one in6_addr + two addr_list[] elems */
2315 a.buflen = buflen - ((sizeof(addr_list[0]) * 2 + sizeof(struct in6_addr)));
2316 a.add_count = 0;
2317 packet_len = __dns_lookup(name, T_AAAA, &packet, &a);
2318 if (packet_len < 0) {
2319 *h_errnop = HOST_NOT_FOUND;
2320 DPRINTF("__dns_lookup returned < 0\n");
2321 return TRY_AGAIN;
2324 if (a.atype == T_AAAA) { /* ADDRESS */
2325 /* we need space for addr_list[] and one IPv6 address */
2326 /* + 1 accounting for 1st addr (it's in a.rdata),
2327 * another + 1 for NULL in last addr_list[]: */
2328 int need_bytes = sizeof(addr_list[0]) * (a.add_count + 1 + 1)
2329 /* for 1st addr (it's in a.rdata): */
2330 + sizeof(struct in6_addr);
2331 /* how many bytes will 2nd and following addresses take? */
2332 int ips_len = a.add_count * a.rdlength;
2334 buflen -= (need_bytes + ips_len);
2335 if ((ssize_t)buflen < 0) {
2336 DPRINTF("buffer too small for all addresses\n");
2337 /* *h_errnop = NETDB_INTERNAL; - already is */
2338 i = ERANGE;
2339 goto free_and_ret;
2342 /* if there are additional addresses in buf,
2343 * move them forward so that they are not destroyed */
2344 DPRINTF("a.add_count:%d a.rdlength:%d a.rdata:%p\n", a.add_count, a.rdlength, a.rdata);
2345 memmove(buf + need_bytes, buf, ips_len);
2347 /* 1st address is in a.rdata, insert it */
2348 buf += need_bytes - sizeof(struct in6_addr);
2349 memcpy(buf, a.rdata, sizeof(struct in6_addr));
2351 /* fill addr_list[] */
2352 for (i = 0; i <= a.add_count; i++) {
2353 addr_list[i] = (struct in6_addr*)buf;
2354 buf += sizeof(struct in6_addr);
2356 addr_list[i] = NULL;
2358 /* if we have enough space, we can report "better" name
2359 * (it may contain search domains attached by __dns_lookup,
2360 * or CNAME of the host if it is different from the name
2361 * we used to find it) */
2362 if (a.dotted && buflen > strlen(a.dotted)) {
2363 strcpy(buf, a.dotted);
2364 alias0 = buf;
2367 result_buf->h_name = alias0;
2368 result_buf->h_aliases = alias;
2369 result_buf->h_addrtype = AF_INET6;
2370 result_buf->h_length = sizeof(struct in6_addr);
2371 result_buf->h_addr_list = (char **) addr_list;
2372 *result = result_buf;
2373 *h_errnop = NETDB_SUCCESS;
2374 i = NETDB_SUCCESS;
2375 goto free_and_ret;
2378 *h_errnop = HOST_NOT_FOUND;
2379 __set_h_errno(HOST_NOT_FOUND);
2380 i = TRY_AGAIN;
2382 free_and_ret:
2383 free(a.dotted);
2384 free(packet);
2385 return i;
2386 #endif /* __UCLIBC_HAS_IPV6__ */
2388 libc_hidden_def(gethostbyname2_r)
2389 #endif /* L_gethostbyname2_r */
2392 #ifdef L_gethostbyaddr_r
2394 int gethostbyaddr_r(const void *addr, socklen_t addrlen,
2395 int type,
2396 struct hostent *result_buf,
2397 char *buf, size_t buflen,
2398 struct hostent **result,
2399 int *h_errnop)
2402 struct in_addr *in;
2403 struct in_addr **addr_list;
2404 char **alias;
2405 unsigned char *packet;
2406 struct resolv_answer a;
2407 int i;
2408 int packet_len;
2409 int nest = 0;
2411 *result = NULL;
2412 if (!addr)
2413 return EINVAL;
2415 switch (type) {
2416 #ifdef __UCLIBC_HAS_IPV4__
2417 case AF_INET:
2418 if (addrlen != sizeof(struct in_addr))
2419 return EINVAL;
2420 break;
2421 #endif
2422 #ifdef __UCLIBC_HAS_IPV6__
2423 case AF_INET6:
2424 if (addrlen != sizeof(struct in6_addr))
2425 return EINVAL;
2426 break;
2427 #endif
2428 default:
2429 return EINVAL;
2432 /* do /etc/hosts first */
2433 i = __get_hosts_byaddr_r(addr, addrlen, type, result_buf,
2434 buf, buflen, result, h_errnop);
2435 if (i == 0)
2436 return i;
2437 switch (*h_errnop) {
2438 case HOST_NOT_FOUND:
2439 case NO_ADDRESS:
2440 break;
2441 default:
2442 return i;
2445 *h_errnop = NETDB_INTERNAL;
2447 /* make sure pointer is aligned */
2448 i = ALIGN_BUFFER_OFFSET(buf);
2449 buf += i;
2450 buflen -= i;
2451 /* Layout in buf:
2452 * char *alias[ALIAS_DIM];
2453 * struct in[6]_addr* addr_list[2];
2454 * struct in[6]_addr in;
2455 * char scratch_buffer[256+];
2457 #define in6 ((struct in6_addr *)in)
2458 alias = (char **)buf;
2459 addr_list = (struct in_addr**)buf;
2460 buf += sizeof(*addr_list) * 2;
2461 buflen -= sizeof(*addr_list) * 2;
2462 in = (struct in_addr*)buf;
2463 #ifndef __UCLIBC_HAS_IPV6__
2464 buf += sizeof(*in);
2465 buflen -= sizeof(*in);
2466 if (addrlen > sizeof(*in))
2467 return ERANGE;
2468 #else
2469 buf += sizeof(*in6);
2470 buflen -= sizeof(*in6);
2471 if (addrlen > sizeof(*in6))
2472 return ERANGE;
2473 #endif
2474 if ((ssize_t)buflen < 256)
2475 return ERANGE;
2476 alias[0] = buf;
2477 alias[1] = NULL;
2478 addr_list[0] = in;
2479 addr_list[1] = NULL;
2480 memcpy(in, addr, addrlen);
2482 if (0) /* nothing */;
2483 #ifdef __UCLIBC_HAS_IPV4__
2484 else IF_HAS_BOTH(if (type == AF_INET)) {
2485 unsigned char *tp = (unsigned char *)addr;
2486 sprintf(buf, "%u.%u.%u.%u.in-addr.arpa",
2487 tp[3], tp[2], tp[1], tp[0]);
2489 #endif
2490 #ifdef __UCLIBC_HAS_IPV6__
2491 else {
2492 char *dst = buf;
2493 unsigned char *tp = (unsigned char *)addr + addrlen - 1;
2494 do {
2495 dst += sprintf(dst, "%x.%x.", tp[0] & 0xf, tp[0] >> 4);
2496 tp--;
2497 } while (tp >= (unsigned char *)addr);
2498 strcpy(dst, "ip6.arpa");
2500 #endif
2502 memset(&a, '\0', sizeof(a));
2503 for (;;) {
2504 /* Hmm why we memset(a) to zeros only once? */
2505 packet_len = __dns_lookup(buf, T_PTR, &packet, &a);
2506 if (packet_len < 0) {
2507 *h_errnop = HOST_NOT_FOUND;
2508 return TRY_AGAIN;
2511 strncpy(buf, a.dotted, buflen);
2512 free(a.dotted);
2513 if (a.atype != T_CNAME)
2514 break;
2516 DPRINTF("Got a CNAME in gethostbyaddr()\n");
2517 if (++nest > MAX_RECURSE) {
2518 *h_errnop = NO_RECOVERY;
2519 return -1;
2521 /* Decode CNAME into buf, feed it to __dns_lookup() again */
2522 i = __decode_dotted(packet, a.rdoffset, packet_len, buf, buflen);
2523 free(packet);
2524 if (i < 0) {
2525 *h_errnop = NO_RECOVERY;
2526 return -1;
2530 if (a.atype == T_PTR) { /* ADDRESS */
2531 i = __decode_dotted(packet, a.rdoffset, packet_len, buf, buflen);
2532 free(packet);
2533 result_buf->h_name = buf;
2534 result_buf->h_addrtype = type;
2535 result_buf->h_length = addrlen;
2536 result_buf->h_addr_list = (char **) addr_list;
2537 result_buf->h_aliases = alias;
2538 *result = result_buf;
2539 *h_errnop = NETDB_SUCCESS;
2540 return NETDB_SUCCESS;
2543 free(packet);
2544 *h_errnop = NO_ADDRESS;
2545 return TRY_AGAIN;
2546 #undef in6
2548 libc_hidden_def(gethostbyaddr_r)
2549 #endif /* L_gethostbyaddr_r */
2552 #ifdef L_gethostent_r
2554 __UCLIBC_MUTEX_STATIC(mylock, PTHREAD_MUTEX_INITIALIZER);
2556 static parser_t *hostp = NULL;
2557 static smallint host_stayopen;
2559 void endhostent_unlocked(void)
2561 if (hostp) {
2562 config_close(hostp);
2563 hostp = NULL;
2565 host_stayopen = 0;
2567 void endhostent(void)
2569 __UCLIBC_MUTEX_LOCK(mylock);
2570 endhostent_unlocked();
2571 __UCLIBC_MUTEX_UNLOCK(mylock);
2574 void sethostent(int stay_open)
2576 __UCLIBC_MUTEX_LOCK(mylock);
2577 if (stay_open)
2578 host_stayopen = 1;
2579 __UCLIBC_MUTEX_UNLOCK(mylock);
2582 int gethostent_r(struct hostent *result_buf, char *buf, size_t buflen,
2583 struct hostent **result, int *h_errnop)
2585 int ret;
2587 __UCLIBC_MUTEX_LOCK(mylock);
2588 if (hostp == NULL) {
2589 hostp = __open_etc_hosts();
2590 if (hostp == NULL) {
2591 *result = NULL;
2592 ret = TRY_AGAIN;
2593 goto DONE;
2597 ret = __read_etc_hosts_r(hostp, NULL, AF_INET, GETHOSTENT,
2598 result_buf, buf, buflen, result, h_errnop);
2599 if (!host_stayopen)
2600 endhostent_unlocked();
2601 DONE:
2602 __UCLIBC_MUTEX_UNLOCK(mylock);
2603 return ret;
2605 libc_hidden_def(gethostent_r)
2606 #endif /* L_gethostent_r */
2609 #ifndef __UCLIBC_HAS_IPV6__
2610 #define GETXX_BUFSZ (sizeof(struct in_addr) + sizeof(struct in_addr *) * 2 + \
2611 /*sizeof(char *)*ALIAS_DIM */+ 384/*namebuffer*/ + 32/* margin */)
2612 #else
2613 #define GETXX_BUFSZ (sizeof(struct in6_addr) + sizeof(struct in6_addr *) * 2 + \
2614 /*sizeof(char *)*ALIAS_DIM */+ 384/*namebuffer*/ + 32/* margin */)
2615 #endif /* __UCLIBC_HAS_IPV6__ */
2617 #define __INIT_GETXX_BUF(sz) \
2618 if (buf == NULL) \
2619 buf = (char *)__uc_malloc((sz));
2621 #ifdef L_gethostent
2623 struct hostent *gethostent(void)
2625 static struct hostent hoste;
2626 static char *buf = NULL;
2627 struct hostent *host = NULL;
2628 #ifndef __UCLIBC_HAS_IPV6__
2629 #define HOSTENT_BUFSZ (sizeof(struct in_addr) + sizeof(struct in_addr *) * 2 + \
2630 sizeof(char *)*ALIAS_DIM + BUFSZ /*namebuffer*/ + 2 /* margin */)
2631 #else
2632 #define HOSTENT_BUFSZ (sizeof(struct in6_addr) + sizeof(struct in6_addr *) * 2 + \
2633 sizeof(char *)*ALIAS_DIM + BUFSZ /*namebuffer*/ + 2 /* margin */)
2634 #endif /* __UCLIBC_HAS_IPV6__ */
2636 __INIT_GETXX_BUF(HOSTENT_BUFSZ);
2637 gethostent_r(&hoste, buf, HOSTENT_BUFSZ, &host, &h_errno);
2638 return host;
2640 #undef HOSTENT_BUFSZ
2641 #endif /* L_gethostent */
2644 #ifdef L_gethostbyname2
2646 struct hostent *gethostbyname2(const char *name, int family)
2648 static struct hostent hoste;
2649 static char *buf = NULL;
2650 struct hostent *hp;
2652 __INIT_GETXX_BUF(GETXX_BUFSZ);
2653 #ifndef __UCLIBC_HAS_IPV6__
2654 if (family != AF_INET)
2655 return (struct hostent*)NULL;
2656 gethostbyname_r(name, &hoste, buf, GETXX_BUFSZ, &hp, &h_errno);
2657 #else
2658 gethostbyname2_r(name, family, &hoste, buf, GETXX_BUFSZ, &hp, &h_errno);
2659 #endif /* __UCLIBC_HAS_IPV6__ */
2661 return hp;
2663 libc_hidden_def(gethostbyname2)
2664 #endif /* L_gethostbyname2 */
2667 #ifdef L_gethostbyname
2669 struct hostent *gethostbyname(const char *name)
2671 return gethostbyname2(name, AF_INET);
2673 libc_hidden_def(gethostbyname)
2674 #endif /* L_gethostbyname */
2677 #ifdef L_gethostbyaddr
2679 struct hostent *gethostbyaddr(const void *addr, socklen_t len, int type)
2681 static struct hostent hoste;
2682 static char *buf = NULL;
2683 struct hostent *hp;
2685 __INIT_GETXX_BUF(GETXX_BUFSZ);
2686 gethostbyaddr_r(addr, len, type, &hoste, buf, GETXX_BUFSZ, &hp, &h_errno);
2687 return hp;
2689 libc_hidden_def(gethostbyaddr)
2690 #endif /* L_gethostbyaddr */
2693 #ifdef L_res_comp
2696 * Expand compressed domain name 'comp_dn' to full domain name.
2697 * 'msg' is a pointer to the begining of the message,
2698 * 'eomorig' points to the first location after the message,
2699 * 'exp_dn' is a pointer to a buffer of size 'length' for the result.
2700 * Return size of compressed name or -1 if there was an error.
2702 int dn_expand(const u_char *msg, const u_char *eom, const u_char *src,
2703 char *dst, int dstsiz)
2705 int n = ns_name_uncompress(msg, eom, src, dst, (size_t)dstsiz);
2707 if (n > 0 && dst[0] == '.')
2708 dst[0] = '\0';
2709 return n;
2711 libc_hidden_def(dn_expand)
2714 * Pack domain name 'exp_dn' in presentation form into 'comp_dn'.
2715 * Return the size of the compressed name or -1.
2716 * 'length' is the size of the array pointed to by 'comp_dn'.
2719 dn_comp(const char *src, u_char *dst, int dstsiz,
2720 u_char **dnptrs, u_char **lastdnptr)
2722 return ns_name_compress(src, dst, (size_t) dstsiz,
2723 (const u_char **) dnptrs,
2724 (const u_char **) lastdnptr);
2726 libc_hidden_def(dn_comp)
2727 #endif /* L_res_comp */
2730 #ifdef L_ns_name
2732 /* Thinking in noninternationalized USASCII (per the DNS spec),
2733 * is this character visible and not a space when printed ?
2735 static int printable(int ch)
2737 return (ch > 0x20 && ch < 0x7f);
2739 /* Thinking in noninternationalized USASCII (per the DNS spec),
2740 * is this characted special ("in need of quoting") ?
2742 static int special(int ch)
2744 switch (ch) {
2745 case 0x22: /* '"' */
2746 case 0x2E: /* '.' */
2747 case 0x3B: /* ';' */
2748 case 0x5C: /* '\\' */
2749 /* Special modifiers in zone files. */
2750 case 0x40: /* '@' */
2751 case 0x24: /* '$' */
2752 return 1;
2753 default:
2754 return 0;
2759 * ns_name_uncompress(msg, eom, src, dst, dstsiz)
2760 * Expand compressed domain name to presentation format.
2761 * return:
2762 * Number of bytes read out of `src', or -1 (with errno set).
2763 * note:
2764 * Root domain returns as "." not "".
2766 int ns_name_uncompress(const u_char *msg, const u_char *eom,
2767 const u_char *src, char *dst, size_t dstsiz)
2769 u_char tmp[NS_MAXCDNAME];
2770 int n;
2772 n = ns_name_unpack(msg, eom, src, tmp, sizeof tmp);
2773 if (n == -1)
2774 return -1;
2775 if (ns_name_ntop(tmp, dst, dstsiz) == -1)
2776 return -1;
2777 return n;
2779 libc_hidden_def(ns_name_uncompress)
2782 * ns_name_ntop(src, dst, dstsiz)
2783 * Convert an encoded domain name to printable ascii as per RFC1035.
2784 * return:
2785 * Number of bytes written to buffer, or -1 (with errno set)
2786 * notes:
2787 * The root is returned as "."
2788 * All other domains are returned in non absolute form
2790 int ns_name_ntop(const u_char *src, char *dst, size_t dstsiz)
2792 const u_char *cp;
2793 char *dn, *eom;
2794 u_char c;
2795 u_int n;
2797 cp = src;
2798 dn = dst;
2799 eom = dst + dstsiz;
2801 while ((n = *cp++) != 0) {
2802 if ((n & NS_CMPRSFLGS) != 0) {
2803 /* Some kind of compression pointer. */
2804 __set_errno(EMSGSIZE);
2805 return -1;
2807 if (dn != dst) {
2808 if (dn >= eom) {
2809 __set_errno(EMSGSIZE);
2810 return -1;
2812 *dn++ = '.';
2814 if (dn + n >= eom) {
2815 __set_errno(EMSGSIZE);
2816 return -1;
2818 for (; n > 0; n--) {
2819 c = *cp++;
2820 if (special(c)) {
2821 if (dn + 1 >= eom) {
2822 __set_errno(EMSGSIZE);
2823 return -1;
2825 *dn++ = '\\';
2826 *dn++ = (char)c;
2827 } else if (!printable(c)) {
2828 if (dn + 3 >= eom) {
2829 __set_errno(EMSGSIZE);
2830 return -1;
2832 *dn++ = '\\';
2833 *dn++ = "0123456789"[c / 100];
2834 c = c % 100;
2835 *dn++ = "0123456789"[c / 10];
2836 *dn++ = "0123456789"[c % 10];
2837 } else {
2838 if (dn >= eom) {
2839 __set_errno(EMSGSIZE);
2840 return -1;
2842 *dn++ = (char)c;
2846 if (dn == dst) {
2847 if (dn >= eom) {
2848 __set_errno(EMSGSIZE);
2849 return -1;
2851 *dn++ = '.';
2853 if (dn >= eom) {
2854 __set_errno(EMSGSIZE);
2855 return -1;
2857 *dn++ = '\0';
2858 return (dn - dst);
2860 libc_hidden_def(ns_name_ntop)
2862 static int encode_bitstring(const char **bp, const char *end,
2863 unsigned char **labelp,
2864 unsigned char ** dst,
2865 unsigned const char *eom)
2867 int afterslash = 0;
2868 const char *cp = *bp;
2869 unsigned char *tp;
2870 const char *beg_blen;
2871 int value = 0, count = 0, tbcount = 0, blen = 0;
2873 beg_blen = NULL;
2875 /* a bitstring must contain at least 2 characters */
2876 if (end - cp < 2)
2877 return EINVAL;
2879 /* XXX: currently, only hex strings are supported */
2880 if (*cp++ != 'x')
2881 return EINVAL;
2882 if (!isxdigit((unsigned char) *cp)) /*%< reject '\[x/BLEN]' */
2883 return EINVAL;
2885 for (tp = *dst + 1; cp < end && tp < eom; cp++) {
2886 unsigned char c = *cp;
2888 switch (c) {
2889 case ']': /*%< end of the bitstring */
2890 if (afterslash) {
2891 char *end_blen;
2892 if (beg_blen == NULL)
2893 return EINVAL;
2894 blen = (int)strtol(beg_blen, &end_blen, 10);
2895 if (*end_blen != ']')
2896 return EINVAL;
2898 if (count)
2899 *tp++ = ((value << 4) & 0xff);
2900 cp++; /*%< skip ']' */
2901 goto done;
2902 case '/':
2903 afterslash = 1;
2904 break;
2905 default:
2906 if (afterslash) {
2907 if (!__isdigit_char(c))
2908 return EINVAL;
2909 if (beg_blen == NULL) {
2910 if (c == '0') {
2911 /* blen never begings with 0 */
2912 return EINVAL;
2914 beg_blen = cp;
2916 } else {
2917 if (!__isdigit_char(c)) {
2918 c = c | 0x20; /* lowercase */
2919 c = c - 'a';
2920 if (c > 5) /* not a-f? */
2921 return EINVAL;
2922 c += 10 + '0';
2924 value <<= 4;
2925 value += (c - '0');
2926 count += 4;
2927 tbcount += 4;
2928 if (tbcount > 256)
2929 return EINVAL;
2930 if (count == 8) {
2931 *tp++ = value;
2932 count = 0;
2935 break;
2938 done:
2939 if (cp >= end || tp >= eom)
2940 return EMSGSIZE;
2943 * bit length validation:
2944 * If a <length> is present, the number of digits in the <bit-data>
2945 * MUST be just sufficient to contain the number of bits specified
2946 * by the <length>. If there are insignificant bits in a final
2947 * hexadecimal or octal digit, they MUST be zero.
2948 * RFC2673, Section 3.2.
2950 if (blen > 0) {
2951 int traillen;
2953 if (((blen + 3) & ~3) != tbcount)
2954 return EINVAL;
2955 traillen = tbcount - blen; /*%< between 0 and 3 */
2956 if (((value << (8 - traillen)) & 0xff) != 0)
2957 return EINVAL;
2959 else
2960 blen = tbcount;
2961 if (blen == 256)
2962 blen = 0;
2964 /* encode the type and the significant bit fields */
2965 **labelp = DNS_LABELTYPE_BITSTRING;
2966 **dst = blen;
2968 *bp = cp;
2969 *dst = tp;
2971 return 0;
2974 int ns_name_pton(const char *src, u_char *dst, size_t dstsiz)
2976 static const char digits[] = "0123456789";
2977 u_char *label, *bp, *eom;
2978 int c, n, escaped, e = 0;
2979 char *cp;
2981 escaped = 0;
2982 bp = dst;
2983 eom = dst + dstsiz;
2984 label = bp++;
2986 while ((c = *src++) != 0) {
2987 if (escaped) {
2988 if (c == '[') { /*%< start a bit string label */
2989 cp = strchr(src, ']');
2990 if (cp == NULL) {
2991 errno = EINVAL; /*%< ??? */
2992 return -1;
2994 e = encode_bitstring(&src, cp + 2,
2995 &label, &bp, eom);
2996 if (e != 0) {
2997 errno = e;
2998 return -1;
3000 escaped = 0;
3001 label = bp++;
3002 c = *src++;
3003 if (c == '\0')
3004 goto done;
3005 if (c != '.') {
3006 errno = EINVAL;
3007 return -1;
3009 continue;
3011 cp = strchr(digits, c);
3012 if (cp != NULL) {
3013 n = (cp - digits) * 100;
3014 c = *src++;
3015 if (c == '\0')
3016 goto ret_EMSGSIZE;
3017 cp = strchr(digits, c);
3018 if (cp == NULL)
3019 goto ret_EMSGSIZE;
3020 n += (cp - digits) * 10;
3021 c = *src++;
3022 if (c == '\0')
3023 goto ret_EMSGSIZE;
3024 cp = strchr(digits, c);
3025 if (cp == NULL)
3026 goto ret_EMSGSIZE;
3027 n += (cp - digits);
3028 if (n > 255)
3029 goto ret_EMSGSIZE;
3030 c = n;
3032 escaped = 0;
3033 } else if (c == '\\') {
3034 escaped = 1;
3035 continue;
3036 } else if (c == '.') {
3037 c = (bp - label - 1);
3038 if ((c & NS_CMPRSFLGS) != 0) { /*%< Label too big. */
3039 goto ret_EMSGSIZE;
3041 if (label >= eom) {
3042 goto ret_EMSGSIZE;
3044 *label = c;
3045 /* Fully qualified ? */
3046 if (*src == '\0') {
3047 if (c != 0) {
3048 if (bp >= eom) {
3049 goto ret_EMSGSIZE;
3051 *bp++ = '\0';
3053 if ((bp - dst) > MAXCDNAME) {
3054 goto ret_EMSGSIZE;
3057 return 1;
3059 if (c == 0 || *src == '.') {
3060 goto ret_EMSGSIZE;
3062 label = bp++;
3063 continue;
3065 if (bp >= eom) {
3066 goto ret_EMSGSIZE;
3068 *bp++ = (u_char)c;
3070 c = (bp - label - 1);
3071 if ((c & NS_CMPRSFLGS) != 0) { /*%< Label too big. */
3072 goto ret_EMSGSIZE;
3074 done:
3075 if (label >= eom) {
3076 goto ret_EMSGSIZE;
3078 *label = c;
3079 if (c != 0) {
3080 if (bp >= eom) {
3081 goto ret_EMSGSIZE;
3083 *bp++ = 0;
3085 if ((bp - dst) > MAXCDNAME) { /*%< src too big */
3086 goto ret_EMSGSIZE;
3089 return 0;
3091 ret_EMSGSIZE:
3092 errno = EMSGSIZE;
3093 return -1;
3095 libc_hidden_def(ns_name_pton)
3098 * ns_name_unpack(msg, eom, src, dst, dstsiz)
3099 * Unpack a domain name from a message, source may be compressed.
3100 * return:
3101 * -1 if it fails, or consumed octets if it succeeds.
3103 int ns_name_unpack(const u_char *msg, const u_char *eom, const u_char *src,
3104 u_char *dst, size_t dstsiz)
3106 const u_char *srcp, *dstlim;
3107 u_char *dstp;
3108 int n, len, checked;
3110 len = -1;
3111 checked = 0;
3112 dstp = dst;
3113 srcp = src;
3114 dstlim = dst + dstsiz;
3115 if (srcp < msg || srcp >= eom) {
3116 __set_errno(EMSGSIZE);
3117 return -1;
3119 /* Fetch next label in domain name. */
3120 while ((n = *srcp++) != 0) {
3121 /* Check for indirection. */
3122 switch (n & NS_CMPRSFLGS) {
3123 case 0:
3124 /* Limit checks. */
3125 if (dstp + n + 1 >= dstlim || srcp + n >= eom) {
3126 __set_errno(EMSGSIZE);
3127 return -1;
3129 checked += n + 1;
3130 *dstp++ = n;
3131 memcpy(dstp, srcp, n);
3132 dstp += n;
3133 srcp += n;
3134 break;
3136 case NS_CMPRSFLGS:
3137 if (srcp >= eom) {
3138 __set_errno(EMSGSIZE);
3139 return -1;
3141 if (len < 0)
3142 len = srcp - src + 1;
3143 srcp = msg + (((n & 0x3f) << 8) | (*srcp & 0xff));
3144 if (srcp < msg || srcp >= eom) { /* Out of range. */
3145 __set_errno(EMSGSIZE);
3146 return -1;
3148 checked += 2;
3150 * Check for loops in the compressed name;
3151 * if we've looked at the whole message,
3152 * there must be a loop.
3154 if (checked >= eom - msg) {
3155 __set_errno(EMSGSIZE);
3156 return -1;
3158 break;
3160 default:
3161 __set_errno(EMSGSIZE);
3162 return -1; /* flag error */
3165 *dstp = '\0';
3166 if (len < 0)
3167 len = srcp - src;
3168 return len;
3170 libc_hidden_def(ns_name_unpack)
3172 static int labellen(const unsigned char *lp)
3174 unsigned bitlen;
3175 unsigned char l = *lp;
3177 if ((l & NS_CMPRSFLGS) == NS_CMPRSFLGS) {
3178 /* should be avoided by the caller */
3179 return -1;
3182 if ((l & NS_CMPRSFLGS) == NS_TYPE_ELT) {
3183 if (l == DNS_LABELTYPE_BITSTRING) {
3184 bitlen = lp[1];
3185 if (bitlen == 0)
3186 bitlen = 256;
3187 return ((bitlen + 7 ) / 8 + 1);
3190 return -1; /*%< unknwon ELT */
3193 return l;
3196 static int mklower(int ch)
3198 if (ch >= 0x41 && ch <= 0x5A)
3199 return (ch + 0x20);
3201 return ch;
3204 static int dn_find(const unsigned char *domain,
3205 const unsigned char *msg,
3206 const unsigned char * const *dnptrs,
3207 const unsigned char * const *lastdnptr)
3209 const unsigned char *dn, *cp, *sp;
3210 const unsigned char * const *cpp;
3211 u_int n;
3213 for (cpp = dnptrs; cpp < lastdnptr; cpp++) {
3214 sp = *cpp;
3216 * terminate search on:
3217 * root label
3218 * compression pointer
3219 * unusable offset
3221 while (*sp != 0 && (*sp & NS_CMPRSFLGS) == 0 &&
3222 (sp - msg) < 0x4000) {
3223 dn = domain;
3224 cp = sp;
3226 while ((n = *cp++) != 0) {
3228 * check for indirection
3230 switch (n & NS_CMPRSFLGS) {
3231 case 0: /*%< normal case, n == len */
3232 n = labellen(cp - 1); /*%< XXX */
3233 if (n != *dn++)
3234 goto next;
3236 for (; n > 0; n--)
3237 if (mklower(*dn++) !=
3238 mklower(*cp++))
3239 goto next;
3240 /* Is next root for both ? */
3241 if (*dn == '\0' && *cp == '\0')
3242 return (sp - msg);
3243 if (*dn)
3244 continue;
3245 goto next;
3246 case NS_CMPRSFLGS: /*%< indirection */
3247 cp = msg + (((n & 0x3f) << 8) | *cp);
3248 break;
3250 default: /*%< illegal type */
3251 errno = EMSGSIZE;
3252 return -1;
3255 next:
3256 sp += *sp + 1;
3260 errno = ENOENT;
3261 return -1;
3264 int ns_name_pack(const unsigned char *src,
3265 unsigned char *dst, int dstsiz,
3266 const unsigned char **dnptrs,
3267 const unsigned char **lastdnptr)
3269 unsigned char *dstp;
3270 const unsigned char **cpp, **lpp, *eob, *msg;
3271 const unsigned char *srcp;
3272 int n, l, first = 1;
3274 srcp = src;
3275 dstp = dst;
3276 eob = dstp + dstsiz;
3277 lpp = cpp = NULL;
3279 if (dnptrs != NULL) {
3280 msg = *dnptrs++;
3281 if (msg != NULL) {
3282 for (cpp = dnptrs; *cpp != NULL; cpp++)
3283 continue;
3285 lpp = cpp; /*%< end of list to search */
3287 } else {
3288 msg = NULL;
3291 /* make sure the domain we are about to add is legal */
3292 l = 0;
3293 do {
3294 int l0;
3296 n = *srcp;
3297 if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) {
3298 errno = EMSGSIZE;
3299 return -1;
3302 l0 = labellen(srcp);
3303 if (l0 < 0) {
3304 errno = EINVAL;
3305 return -1;
3308 l += l0 + 1;
3309 if (l > MAXCDNAME) {
3310 errno = EMSGSIZE;
3311 return -1;
3314 srcp += l0 + 1;
3315 } while (n != 0);
3317 /* from here on we need to reset compression pointer array on error */
3318 srcp = src;
3320 do {
3321 /* Look to see if we can use pointers. */
3322 n = *srcp;
3324 if (n != 0 && msg != NULL) {
3325 l = dn_find(srcp, msg, (const unsigned char * const *) dnptrs,
3326 (const unsigned char * const *) lpp);
3327 if (l >= 0) {
3328 if (dstp + 1 >= eob) {
3329 goto cleanup;
3332 *dstp++ = ((u_int32_t)l >> 8) | NS_CMPRSFLGS;
3333 *dstp++ = l % 256;
3334 return (dstp - dst);
3337 /* Not found, save it. */
3338 if (lastdnptr != NULL && cpp < lastdnptr - 1 &&
3339 (dstp - msg) < 0x4000 && first) {
3340 *cpp++ = dstp;
3341 *cpp = NULL;
3342 first = 0;
3346 /* copy label to buffer */
3347 if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) {
3348 /* Should not happen. */
3349 goto cleanup;
3352 n = labellen(srcp);
3353 if (dstp + 1 + n >= eob) {
3354 goto cleanup;
3357 memcpy(dstp, srcp, (size_t)(n + 1));
3358 srcp += n + 1;
3359 dstp += n + 1;
3360 } while (n != 0);
3362 if (dstp > eob) {
3363 cleanup:
3364 if (msg != NULL)
3365 *lpp = NULL;
3367 errno = EMSGSIZE;
3368 return -1;
3371 return dstp - dst;
3373 libc_hidden_def(ns_name_pack)
3375 int ns_name_compress(const char *src,
3376 unsigned char *dst, size_t dstsiz,
3377 const unsigned char **dnptrs,
3378 const unsigned char **lastdnptr)
3380 unsigned char tmp[NS_MAXCDNAME];
3382 if (ns_name_pton(src, tmp, sizeof(tmp)) == -1)
3383 return -1;
3385 return ns_name_pack(tmp, dst, dstsiz, dnptrs, lastdnptr);
3387 libc_hidden_def(ns_name_compress)
3389 int ns_name_skip(const unsigned char **ptrptr,
3390 const unsigned char *eom)
3392 const unsigned char *cp;
3393 u_int n;
3394 int l;
3396 cp = *ptrptr;
3397 while (cp < eom && (n = *cp++) != 0) {
3398 /* Check for indirection. */
3399 switch (n & NS_CMPRSFLGS) {
3400 case 0: /*%< normal case, n == len */
3401 cp += n;
3402 continue;
3403 case NS_TYPE_ELT: /*%< EDNS0 extended label */
3404 l = labellen(cp - 1);
3405 if (l < 0) {
3406 errno = EMSGSIZE; /*%< XXX */
3407 return -1;
3409 cp += l;
3410 continue;
3411 case NS_CMPRSFLGS: /*%< indirection */
3412 cp++;
3413 break;
3414 default: /*%< illegal type */
3415 errno = EMSGSIZE;
3416 return -1;
3419 break;
3422 if (cp > eom) {
3423 errno = EMSGSIZE;
3424 return -1;
3427 *ptrptr = cp;
3429 return 0;
3431 libc_hidden_def(ns_name_skip)
3433 int dn_skipname(const unsigned char *ptr, const unsigned char *eom)
3435 const unsigned char *saveptr = ptr;
3437 if (ns_name_skip(&ptr, eom) == -1)
3438 return -1;
3440 return ptr - saveptr;
3442 libc_hidden_def(dn_skipname)
3443 #endif /* L_ns_name */
3446 #ifdef L_res_init
3448 /* Will be called under __resolv_lock. */
3449 static void res_sync_func(void)
3451 struct __res_state *rp = &(_res);
3452 int n;
3454 /* If we didn't get malloc failure earlier... */
3455 if (__nameserver != (void*) &__local_nameserver) {
3456 /* TODO:
3457 * if (__nameservers < rp->nscount) - try to grow __nameserver[]?
3459 #ifdef __UCLIBC_HAS_IPV6__
3460 if (__nameservers > rp->_u._ext.nscount)
3461 __nameservers = rp->_u._ext.nscount;
3462 n = __nameservers;
3463 while (--n >= 0)
3464 __nameserver[n].sa6 = *rp->_u._ext.nsaddrs[n]; /* struct copy */
3465 #else /* IPv4 only */
3466 if (__nameservers > rp->nscount)
3467 __nameservers = rp->nscount;
3468 n = __nameservers;
3469 while (--n >= 0)
3470 __nameserver[n].sa4 = rp->nsaddr_list[n]; /* struct copy */
3471 #endif
3473 __resolv_timeout = rp->retrans ? : RES_TIMEOUT;
3474 __resolv_attempts = rp->retry ? : RES_DFLRETRY;
3475 /* Extend and comment what program is known
3476 * to use which _res.XXX member(s).
3478 __resolv_opts = rp->options;
3483 /* has to be called under __resolv_lock */
3484 static int
3485 __res_vinit(res_state rp, int preinit)
3487 int i, n, options, retrans, retry, ndots;
3488 #ifdef __UCLIBC_HAS_IPV6__
3489 int m = 0;
3490 #endif
3492 __close_nameservers();
3493 __open_nameservers();
3495 if (preinit) {
3496 options = rp->options;
3497 retrans = rp->retrans;
3498 retry = rp->retry;
3499 ndots = rp->ndots;
3502 memset(rp, 0, sizeof(*rp));
3504 if (!preinit) {
3505 rp->options = RES_DEFAULT;
3506 rp->retrans = RES_TIMEOUT;
3507 rp->retry = RES_DFLRETRY;
3508 rp->ndots = 1;
3509 } else {
3510 rp->options = options;
3511 rp->retrans = retrans;
3512 rp->retry = retry;
3513 rp->ndots = ndots;
3516 #ifdef __UCLIBC_HAS_COMPAT_RES_STATE__
3517 /* Was: "rp->id = random();" but:
3518 * - random() pulls in largish static buffers
3519 * - isn't actually random unless, say, srandom(time(NULL)) was called
3520 * - is not used by uclibc anyway :)
3522 /* rp->id = 0; - memset did it */
3523 #endif
3524 #ifdef __UCLIBC_HAS_EXTRA_COMPAT_RES_STATE__
3525 rp->_vcsock = -1;
3526 #endif
3528 n = __searchdomains;
3529 if (n > ARRAY_SIZE(rp->dnsrch))
3530 n = ARRAY_SIZE(rp->dnsrch);
3531 for (i = 0; i < n; i++)
3532 rp->dnsrch[i] = __searchdomain[i];
3534 /* copy nameservers' addresses */
3535 i = 0;
3536 #ifdef __UCLIBC_HAS_IPV4__
3537 n = 0;
3538 while (n < ARRAY_SIZE(rp->nsaddr_list) && i < __nameservers) {
3539 if (__nameserver[i].sa.sa_family == AF_INET) {
3540 rp->nsaddr_list[n] = __nameserver[i].sa4; /* struct copy */
3541 #ifdef __UCLIBC_HAS_IPV6__
3542 if (m < ARRAY_SIZE(rp->_u._ext.nsaddrs)) {
3543 rp->_u._ext.nsaddrs[m] = (void*) &rp->nsaddr_list[n];
3544 m++;
3546 #endif
3547 n++;
3549 #ifdef __UCLIBC_HAS_IPV6__
3550 if (__nameserver[i].sa.sa_family == AF_INET6
3551 && m < ARRAY_SIZE(rp->_u._ext.nsaddrs)
3553 struct sockaddr_in6 *sa6 = malloc(sizeof(*sa6));
3554 if (sa6) {
3555 *sa6 = __nameserver[i].sa6; /* struct copy */
3556 rp->_u._ext.nsaddrs[m] = sa6;
3557 m++;
3560 #endif
3561 i++;
3563 rp->nscount = n;
3564 #ifdef __UCLIBC_HAS_IPV6__
3565 rp->_u._ext.nscount = m;
3566 #endif
3568 #else /* IPv6 only */
3569 while (m < ARRAY_SIZE(rp->_u._ext.nsaddrs) && i < __nameservers) {
3570 struct sockaddr_in6 *sa6 = malloc(sizeof(*sa6));
3571 if (sa6) {
3572 *sa6 = __nameserver[i].sa6; /* struct copy */
3573 rp->_u._ext.nsaddrs[m] = sa6;
3574 m++;
3576 i++;
3578 rp->_u._ext.nscount = m;
3579 #endif
3581 rp->options |= RES_INIT;
3583 return 0;
3586 static unsigned int
3587 res_randomid(void)
3589 return 0xffff & getpid();
3592 /* Our res_init never fails (always returns 0) */
3594 res_init(void)
3597 * These three fields used to be statically initialized. This made
3598 * it hard to use this code in a shared library. It is necessary,
3599 * now that we're doing dynamic initialization here, that we preserve
3600 * the old semantics: if an application modifies one of these three
3601 * fields of _res before res_init() is called, res_init() will not
3602 * alter them. Of course, if an application is setting them to
3603 * _zero_ before calling res_init(), hoping to override what used
3604 * to be the static default, we can't detect it and unexpected results
3605 * will follow. Zero for any of these fields would make no sense,
3606 * so one can safely assume that the applications were already getting
3607 * unexpected results.
3609 * _res.options is tricky since some apps were known to diddle the bits
3610 * before res_init() was first called. We can't replicate that semantic
3611 * with dynamic initialization (they may have turned bits off that are
3612 * set in RES_DEFAULT). Our solution is to declare such applications
3613 * "broken". They could fool us by setting RES_INIT but none do (yet).
3616 __UCLIBC_MUTEX_LOCK(__resolv_lock);
3618 if (!_res.retrans)
3619 _res.retrans = RES_TIMEOUT;
3620 if (!_res.retry)
3621 _res.retry = 4;
3622 if (!(_res.options & RES_INIT))
3623 _res.options = RES_DEFAULT;
3626 * This one used to initialize implicitly to zero, so unless the app
3627 * has set it to something in particular, we can randomize it now.
3629 if (!_res.id)
3630 _res.id = res_randomid();
3632 __res_sync = NULL;
3633 __res_vinit(&_res, 1);
3634 __res_sync = res_sync_func;
3636 __UCLIBC_MUTEX_UNLOCK(__resolv_lock);
3638 return 0;
3640 libc_hidden_def(res_init)
3642 static void
3643 __res_iclose(res_state statp)
3645 struct __res_state * rp = statp;
3646 __UCLIBC_MUTEX_LOCK(__resolv_lock);
3647 if (rp == NULL)
3648 rp = __res_state();
3649 __close_nameservers();
3650 __res_sync = NULL;
3651 #ifdef __UCLIBC_HAS_IPV6__
3653 char *p1 = (char*) &(rp->nsaddr_list[0]);
3654 unsigned int m = 0;
3655 /* free nsaddrs[m] if they do not point to nsaddr_list[x] */
3656 while (m < ARRAY_SIZE(rp->_u._ext.nsaddrs)) {
3657 char *p2 = (char*)(rp->_u._ext.nsaddrs[m++]);
3658 if (p2 < p1 || (p2 - p1) > (signed)sizeof(rp->nsaddr_list))
3659 free(p2);
3662 #endif
3663 memset(rp, 0, sizeof(struct __res_state));
3664 __UCLIBC_MUTEX_UNLOCK(__resolv_lock);
3668 * This routine is for closing the socket if a virtual circuit is used and
3669 * the program wants to close it. This provides support for endhostent()
3670 * which expects to close the socket.
3672 * This routine is not expected to be user visible.
3675 void
3676 res_nclose(res_state statp)
3678 __res_iclose(statp);
3681 #ifdef __UCLIBC_HAS_BSD_RES_CLOSE__
3682 void res_close(void)
3684 __res_iclose(NULL);
3686 #endif
3688 /* This needs to be after the use of _res in res_init, above. */
3689 #undef _res
3691 #ifndef __UCLIBC_HAS_THREADS__
3692 /* The resolver state for use by single-threaded programs.
3693 This differs from plain `struct __res_state _res;' in that it doesn't
3694 create a common definition, but a plain symbol that resides in .bss,
3695 which can have an alias. */
3696 struct __res_state _res __attribute__((section (".bss")));
3697 struct __res_state *__resp = &_res;
3698 #else /* __UCLIBC_HAS_THREADS__ */
3699 struct __res_state _res __attribute__((section (".bss"))) attribute_hidden;
3701 # if defined __UCLIBC_HAS_TLS__
3702 # undef __resp
3703 __thread struct __res_state *__resp = &_res;
3704 extern __thread struct __res_state *__libc_resp
3705 __attribute__ ((alias ("__resp"))) attribute_hidden attribute_tls_model_ie;
3706 # else
3707 # undef __resp
3708 struct __res_state *__resp = &_res;
3709 # endif
3710 #endif /* !__UCLIBC_HAS_THREADS__ */
3713 * Set up default settings. If the configuration file exist, the values
3714 * there will have precedence. Otherwise, the server address is set to
3715 * INADDR_ANY and the default domain name comes from the gethostname().
3717 * An interrim version of this code (BIND 4.9, pre-4.4BSD) used 127.0.0.1
3718 * rather than INADDR_ANY ("0.0.0.0") as the default name server address
3719 * since it was noted that INADDR_ANY actually meant ``the first interface
3720 * you "ifconfig"'d at boot time'' and if this was a SLIP or PPP interface,
3721 * it had to be "up" in order for you to reach your own name server. It
3722 * was later decided that since the recommended practice is to always
3723 * install local static routes through 127.0.0.1 for all your network
3724 * interfaces, that we could solve this problem without a code change.
3726 * The configuration file should always be used, since it is the only way
3727 * to specify a default domain. If you are running a server on your local
3728 * machine, you should say "nameserver 0.0.0.0" or "nameserver 127.0.0.1"
3729 * in the configuration file.
3731 * Return 0 if completes successfully, -1 on error
3734 res_ninit(res_state statp)
3736 int ret;
3737 __UCLIBC_MUTEX_LOCK(__resolv_lock);
3738 ret = __res_vinit(statp, 0);
3739 __UCLIBC_MUTEX_UNLOCK(__resolv_lock);
3740 return ret;
3743 #endif /* L_res_init */
3745 #ifdef L_res_state
3746 # if defined __UCLIBC_HAS_TLS__
3747 struct __res_state *
3748 __res_state (void)
3750 return __resp;
3752 # else
3753 # undef _res
3754 extern struct __res_state _res;
3756 /* When threaded, _res may be a per-thread variable. */
3757 struct __res_state *
3758 weak_const_function
3759 __res_state (void)
3761 return &_res;
3763 # endif
3765 #endif /* L_res_state */
3768 #ifdef L_res_query
3770 int res_query(const char *dname, int class, int type,
3771 unsigned char *answer, int anslen)
3773 int i;
3774 unsigned char *packet = NULL;
3775 struct resolv_answer a;
3777 if (!dname || class != 1 /* CLASS_IN */) {
3778 h_errno = NO_RECOVERY;
3779 return -1;
3782 memset(&a, '\0', sizeof(a));
3783 i = __dns_lookup(dname, type, &packet, &a);
3785 if (i < 0) {
3786 if (!h_errno) /* TODO: can this ever happen? */
3787 h_errno = TRY_AGAIN;
3788 return -1;
3791 free(a.dotted);
3793 if (i > anslen)
3794 i = anslen;
3795 memcpy(answer, packet, i);
3797 free(packet);
3798 return i;
3800 libc_hidden_def(res_query)
3803 * Formulate a normal query, send, and retrieve answer in supplied buffer.
3804 * Return the size of the response on success, -1 on error.
3805 * If enabled, implement search rules until answer or unrecoverable failure
3806 * is detected. Error code, if any, is left in h_errno.
3808 #define __TRAILING_DOT (1<<0)
3809 #define __GOT_NODATA (1<<1)
3810 #define __GOT_SERVFAIL (1<<2)
3811 #define __TRIED_AS_IS (1<<3)
3812 int res_search(const char *name, int class, int type, u_char *answer,
3813 int anslen)
3815 const char *cp;
3816 char **domain;
3817 HEADER *hp = (HEADER *)(void *)answer;
3818 unsigned dots;
3819 unsigned state;
3820 int ret, saved_herrno;
3821 uint32_t _res_options;
3822 unsigned _res_ndots;
3823 char **_res_dnsrch;
3825 if (!name || !answer) {
3826 h_errno = NETDB_INTERNAL;
3827 return -1;
3830 again:
3831 __UCLIBC_MUTEX_LOCK(__resolv_lock);
3832 _res_options = _res.options;
3833 _res_ndots = _res.ndots;
3834 _res_dnsrch = _res.dnsrch;
3835 __UCLIBC_MUTEX_UNLOCK(__resolv_lock);
3836 if (!(_res_options & RES_INIT)) {
3837 res_init(); /* our res_init never fails */
3838 goto again;
3841 state = 0;
3842 errno = 0;
3843 h_errno = HOST_NOT_FOUND; /* default, if we never query */
3844 dots = 0;
3845 for (cp = name; *cp; cp++)
3846 dots += (*cp == '.');
3848 if (cp > name && *--cp == '.')
3849 state |= __TRAILING_DOT;
3852 * If there are dots in the name already, let's just give it a try
3853 * 'as is'. The threshold can be set with the "ndots" option.
3855 saved_herrno = -1;
3856 if (dots >= _res_ndots) {
3857 ret = res_querydomain(name, NULL, class, type, answer, anslen);
3858 if (ret > 0)
3859 return ret;
3860 saved_herrno = h_errno;
3861 state |= __TRIED_AS_IS;
3865 * We do at least one level of search if
3866 * - there is no dot and RES_DEFNAME is set, or
3867 * - there is at least one dot, there is no trailing dot,
3868 * and RES_DNSRCH is set.
3870 if ((!dots && (_res_options & RES_DEFNAMES))
3871 || (dots && !(state & __TRAILING_DOT) && (_res_options & RES_DNSRCH))
3873 bool done = 0;
3875 for (domain = _res_dnsrch; *domain && !done; domain++) {
3877 ret = res_querydomain(name, *domain, class, type,
3878 answer, anslen);
3879 if (ret > 0)
3880 return ret;
3883 * If no server present, give up.
3884 * If name isn't found in this domain,
3885 * keep trying higher domains in the search list
3886 * (if that's enabled).
3887 * On a NO_DATA error, keep trying, otherwise
3888 * a wildcard entry of another type could keep us
3889 * from finding this entry higher in the domain.
3890 * If we get some other error (negative answer or
3891 * server failure), then stop searching up,
3892 * but try the input name below in case it's
3893 * fully-qualified.
3895 if (errno == ECONNREFUSED) {
3896 h_errno = TRY_AGAIN;
3897 return -1;
3900 switch (h_errno) {
3901 case NO_DATA:
3902 state |= __GOT_NODATA;
3903 /* FALLTHROUGH */
3904 case HOST_NOT_FOUND:
3905 /* keep trying */
3906 break;
3907 case TRY_AGAIN:
3908 if (hp->rcode == SERVFAIL) {
3909 /* try next search element, if any */
3910 state |= __GOT_SERVFAIL;
3911 break;
3913 /* FALLTHROUGH */
3914 default:
3915 /* anything else implies that we're done */
3916 done = 1;
3919 * if we got here for some reason other than DNSRCH,
3920 * we only wanted one iteration of the loop, so stop.
3922 if (!(_res_options & RES_DNSRCH))
3923 done = 1;
3928 * if we have not already tried the name "as is", do that now.
3929 * note that we do this regardless of how many dots were in the
3930 * name or whether it ends with a dot.
3932 if (!(state & __TRIED_AS_IS)) {
3933 ret = res_querydomain(name, NULL, class, type, answer, anslen);
3934 if (ret > 0)
3935 return ret;
3939 * if we got here, we didn't satisfy the search.
3940 * if we did an initial full query, return that query's h_errno
3941 * (note that we wouldn't be here if that query had succeeded).
3942 * else if we ever got a nodata, send that back as the reason.
3943 * else send back meaningless h_errno, that being the one from
3944 * the last DNSRCH we did.
3946 if (saved_herrno != -1)
3947 h_errno = saved_herrno;
3948 else if (state & __GOT_NODATA)
3949 h_errno = NO_DATA;
3950 else if (state & __GOT_SERVFAIL)
3951 h_errno = TRY_AGAIN;
3952 return -1;
3954 #undef __TRAILING_DOT
3955 #undef __GOT_NODATA
3956 #undef __GOT_SERVFAIL
3957 #undef __TRIED_AS_IS
3959 * Perform a call on res_query on the concatenation of name and domain,
3960 * removing a trailing dot from name if domain is NULL.
3962 int res_querydomain(const char *name, const char *domain, int class, int type,
3963 u_char *answer, int anslen)
3965 char nbuf[MAXDNAME];
3966 const char *longname = nbuf;
3967 size_t n, d;
3968 #ifdef DEBUG
3969 uint32_t _res_options;
3970 #endif
3972 if (!name || !answer) {
3973 h_errno = NETDB_INTERNAL;
3974 return -1;
3977 #ifdef DEBUG
3978 again:
3979 __UCLIBC_MUTEX_LOCK(__resolv_lock);
3980 _res_options = _res.options;
3981 __UCLIBC_MUTEX_UNLOCK(__resolv_lock);
3982 if (!(_res_options & RES_INIT)) {
3983 res_init(); /* our res_init never fails */
3984 goto again;
3986 if (_res_options & RES_DEBUG)
3987 printf(";; res_querydomain(%s, %s, %d, %d)\n",
3988 name, (domain ? domain : "<Nil>"), class, type);
3989 #endif
3990 if (domain == NULL) {
3992 * Check for trailing '.';
3993 * copy without '.' if present.
3995 n = strlen(name);
3996 if (n + 1 > sizeof(nbuf)) {
3997 h_errno = NO_RECOVERY;
3998 return -1;
4000 if (n > 0 && name[--n] == '.') {
4001 strncpy(nbuf, name, n);
4002 nbuf[n] = '\0';
4003 } else
4004 longname = name;
4005 } else {
4006 n = strlen(name);
4007 d = strlen(domain);
4008 if (n + 1 + d + 1 > sizeof(nbuf)) {
4009 h_errno = NO_RECOVERY;
4010 return -1;
4012 snprintf(nbuf, sizeof(nbuf), "%s.%s", name, domain);
4014 return res_query(longname, class, type, answer, anslen);
4016 libc_hidden_def(res_querydomain)
4017 #endif /* L_res_query */
4019 #ifdef L_ns_netint
4020 unsigned int ns_get16(const unsigned char *src)
4022 unsigned int dst;
4023 NS_GET16(dst, src);
4024 return dst;
4027 unsigned long ns_get32(const unsigned char *src)
4029 unsigned long dst;
4030 NS_GET32(dst, src);
4031 return dst;
4034 void ns_put16(unsigned int src, unsigned char *dst)
4036 NS_PUT16(src, dst);
4039 void ns_put32(unsigned long src, unsigned char *dst)
4041 NS_PUT32(src, dst);
4043 #endif /* L_ns_netint */
4045 #ifdef L_ns_parse
4046 /* These need to be in the same order as the nres.h:ns_flag enum. */
4047 struct _ns_flagdata { unsigned short mask, shift; };
4048 static const struct _ns_flagdata _ns_flagdata[16] = {
4049 { 0x8000, 15 }, /*%< qr. */
4050 { 0x7800, 11 }, /*%< opcode. */
4051 { 0x0400, 10 }, /*%< aa. */
4052 { 0x0200, 9 }, /*%< tc. */
4053 { 0x0100, 8 }, /*%< rd. */
4054 { 0x0080, 7 }, /*%< ra. */
4055 { 0x0040, 6 }, /*%< z. */
4056 { 0x0020, 5 }, /*%< ad. */
4057 { 0x0010, 4 }, /*%< cd. */
4058 { 0x000f, 0 }, /*%< rcode. */
4059 { 0x0000, 0 }, /*%< expansion (1/6). */
4060 { 0x0000, 0 }, /*%< expansion (2/6). */
4061 { 0x0000, 0 }, /*%< expansion (3/6). */
4062 { 0x0000, 0 }, /*%< expansion (4/6). */
4063 { 0x0000, 0 }, /*%< expansion (5/6). */
4064 { 0x0000, 0 }, /*%< expansion (6/6). */
4067 static void setsection(ns_msg *msg, ns_sect sect)
4069 msg->_sect = sect;
4070 if (sect == ns_s_max) {
4071 msg->_rrnum = -1;
4072 msg->_ptr = NULL;
4073 } else {
4074 msg->_rrnum = 0;
4075 msg->_ptr = msg->_sections[(int)sect];
4079 int ns_skiprr(const unsigned char *ptr,
4080 const unsigned char *eom,
4081 ns_sect section, int count)
4083 const u_char *optr = ptr;
4085 for (; count > 0; count--) {
4086 int b, rdlength;
4088 b = dn_skipname(ptr, eom);
4089 if (b < 0) {
4090 errno = EMSGSIZE;
4091 return -1;
4094 ptr += b/*Name*/ + NS_INT16SZ/*Type*/ + NS_INT16SZ/*Class*/;
4095 if (section != ns_s_qd) {
4096 if (ptr + NS_INT32SZ + NS_INT16SZ > eom) {
4097 errno = EMSGSIZE;
4098 return -1;
4101 ptr += NS_INT32SZ/*TTL*/;
4102 NS_GET16(rdlength, ptr);
4103 ptr += rdlength/*RData*/;
4107 if (ptr > eom) {
4108 errno = EMSGSIZE;
4109 return -1;
4112 return ptr - optr;
4114 libc_hidden_def(ns_skiprr)
4117 ns_initparse(const unsigned char *msg, int msglen, ns_msg *handle)
4119 const u_char *eom = msg + msglen;
4120 int i;
4122 handle->_msg = msg;
4123 handle->_eom = eom;
4124 if (msg + NS_INT16SZ > eom) {
4125 errno = EMSGSIZE;
4126 return -1;
4129 NS_GET16(handle->_id, msg);
4130 if (msg + NS_INT16SZ > eom) {
4131 errno = EMSGSIZE;
4132 return -1;
4135 NS_GET16(handle->_flags, msg);
4136 for (i = 0; i < ns_s_max; i++) {
4137 if (msg + NS_INT16SZ > eom) {
4138 errno = EMSGSIZE;
4139 return -1;
4142 NS_GET16(handle->_counts[i], msg);
4144 for (i = 0; i < ns_s_max; i++)
4145 if (handle->_counts[i] == 0)
4146 handle->_sections[i] = NULL;
4147 else {
4148 int b = ns_skiprr(msg, eom, (ns_sect)i,
4149 handle->_counts[i]);
4151 if (b < 0)
4152 return -1;
4153 handle->_sections[i] = msg;
4154 msg += b;
4157 if (msg != eom) {
4158 errno = EMSGSIZE;
4159 return -1;
4162 setsection(handle, ns_s_max);
4163 return 0;
4167 ns_parserr(ns_msg *handle, ns_sect section, int rrnum, ns_rr *rr)
4169 int b;
4170 int tmp;
4172 /* Make section right. */
4173 tmp = section;
4174 if (tmp < 0 || section >= ns_s_max) {
4175 errno = ENODEV;
4176 return -1;
4179 if (section != handle->_sect)
4180 setsection(handle, section);
4182 /* Make rrnum right. */
4183 if (rrnum == -1)
4184 rrnum = handle->_rrnum;
4185 if (rrnum < 0 || rrnum >= handle->_counts[(int)section]) {
4186 errno = ENODEV;
4187 return -1;
4189 if (rrnum < handle->_rrnum)
4190 setsection(handle, section);
4191 if (rrnum > handle->_rrnum) {
4192 b = ns_skiprr(handle->_ptr, handle->_eom, section,
4193 rrnum - handle->_rrnum);
4195 if (b < 0)
4196 return -1;
4197 handle->_ptr += b;
4198 handle->_rrnum = rrnum;
4201 /* Do the parse. */
4202 b = dn_expand(handle->_msg, handle->_eom,
4203 handle->_ptr, rr->name, NS_MAXDNAME);
4204 if (b < 0)
4205 return -1;
4206 handle->_ptr += b;
4207 if (handle->_ptr + NS_INT16SZ + NS_INT16SZ > handle->_eom) {
4208 errno = EMSGSIZE;
4209 return -1;
4211 NS_GET16(rr->type, handle->_ptr);
4212 NS_GET16(rr->rr_class, handle->_ptr);
4213 if (section == ns_s_qd) {
4214 rr->ttl = 0;
4215 rr->rdlength = 0;
4216 rr->rdata = NULL;
4217 } else {
4218 if (handle->_ptr + NS_INT32SZ + NS_INT16SZ > handle->_eom) {
4219 errno = EMSGSIZE;
4220 return -1;
4222 NS_GET32(rr->ttl, handle->_ptr);
4223 NS_GET16(rr->rdlength, handle->_ptr);
4224 if (handle->_ptr + rr->rdlength > handle->_eom) {
4225 errno = EMSGSIZE;
4226 return -1;
4228 rr->rdata = handle->_ptr;
4229 handle->_ptr += rr->rdlength;
4231 if (++handle->_rrnum > handle->_counts[(int)section])
4232 setsection(handle, (ns_sect)((int)section + 1));
4234 return 0;
4237 int ns_msg_getflag(ns_msg handle, int flag)
4239 return ((handle)._flags & _ns_flagdata[flag].mask) >> _ns_flagdata[flag].shift;
4241 #endif /* L_ns_parse */
4243 #ifdef L_res_data
4244 int res_mkquery(int op, const char *dname, int class, int type,
4245 const unsigned char *data, int datalen,
4246 const unsigned char *newrr_in,
4247 unsigned char *buf, int buflen)
4249 HEADER *hp;
4250 unsigned char *cp, *ep;
4251 unsigned char *dnptrs[20], **dpp, **lastdnptr;
4252 uint32_t _res_options;
4253 int n;
4255 if (!buf || buflen < HFIXEDSZ) {
4256 h_errno = NETDB_INTERNAL;
4257 return -1;
4260 again:
4261 __UCLIBC_MUTEX_LOCK(__resolv_lock);
4262 _res_options = _res.options;
4263 __UCLIBC_MUTEX_UNLOCK(__resolv_lock);
4264 if (!(_res_options & RES_INIT)) {
4265 res_init(); /* our res_init never fails */
4266 goto again;
4269 #ifdef DEBUG
4270 if (_res_options & RES_DEBUG)
4271 printf(";; res_mkquery(%d, %s, %d, %d)\n",
4272 op, dname && *dname ? dname : "<null>", class, type);
4273 #endif
4275 memset(buf, 0, HFIXEDSZ);
4276 hp = (HEADER *) buf;
4277 hp->id = getpid() & 0xffff;
4278 hp->opcode = op;
4279 hp->rd = (_res_options & RES_RECURSE) != 0U;
4280 hp->rcode = NOERROR;
4282 cp = buf + HFIXEDSZ;
4283 ep = buf + buflen;
4284 dpp = dnptrs;
4285 *dpp++ = buf;
4286 *dpp++ = NULL;
4287 lastdnptr = dnptrs + sizeof dnptrs / sizeof dnptrs[0];
4290 * perform opcode specific processing
4292 switch (op) {
4293 case QUERY:
4294 case NS_NOTIFY_OP:
4295 if (ep - cp < QFIXEDSZ)
4296 return -1;
4298 n = dn_comp(dname, cp, ep - cp - QFIXEDSZ, dnptrs, lastdnptr);
4299 if (n < 0)
4300 return -1;
4302 cp += n;
4303 NS_PUT16(type, cp);
4304 NS_PUT16(class, cp);
4305 hp->qdcount = htons(1);
4307 if (op == QUERY || data == NULL)
4308 break;
4311 * Make an additional record for completion domain.
4313 if ((ep - cp) < RRFIXEDSZ)
4314 return -1;
4316 n = dn_comp((const char *)data, cp, ep - cp - RRFIXEDSZ,
4317 dnptrs, lastdnptr);
4318 if (n < 0)
4319 return -1;
4321 cp += n;
4322 NS_PUT16(T_NULL, cp);
4323 NS_PUT16(class, cp);
4324 NS_PUT32(0, cp);
4325 NS_PUT16(0, cp);
4326 hp->arcount = htons(1);
4328 break;
4330 case IQUERY:
4332 * Initialize answer section
4334 if (ep - cp < 1 + RRFIXEDSZ + datalen)
4335 return -1;
4337 *cp++ = '\0'; /*%< no domain name */
4338 NS_PUT16(type, cp);
4339 NS_PUT16(class, cp);
4340 NS_PUT32(0, cp);
4341 NS_PUT16(datalen, cp);
4343 if (datalen) {
4344 memcpy(cp, data, (size_t)datalen);
4345 cp += datalen;
4348 hp->ancount = htons(1);
4349 break;
4351 default:
4352 return -1;
4355 return cp - buf;
4357 #endif /* L_res_data */
4359 /* Unimplemented: */
4360 /* res_send */