libc/inet/resolv.c: add __hnbad to check DNS entries for validity…
[uclibc-ng.git] / libc / inet / resolv.c
blob8bbd7c7cd53d6c7546d831c473432377ddbb0e0c
1 /* resolv.c: DNS Resolver
3 * Copyright (C) 1998 Kenneth Albanowski <kjahds@kjahds.com>,
4 * The Silver Hammer Group, Ltd.
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
12 * Portions Copyright (c) 1985, 1993
13 * The Regents of the University of California. All rights reserved.
14 * Portions Copyright © 2021 mirabilos <m@mirbsd.org>
16 * Redistribution and use in source and binary forms, with or without
17 * modification, are permitted provided that the following conditions
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.
75 /* RFC 1035
76 ...
77 Whenever an octet represents a numeric quantity, the left most bit
78 in the diagram is the high order or most significant bit.
79 That is, the bit labeled 0 is the most significant bit.
80 ...
82 4.1.1. Header section format
83 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
84 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
85 | ID |
86 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
87 |QR| OPCODE |AA|TC|RD|RA| 0 0 0| RCODE |
88 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
89 | QDCOUNT |
90 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
91 | ANCOUNT |
92 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
93 | NSCOUNT |
94 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
95 | ARCOUNT |
96 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
97 ID 16 bit random identifier assigned by querying peer.
98 Used to match query/response.
99 QR message is a query (0), or a response (1).
100 OPCODE 0 standard query (QUERY)
101 1 inverse query (IQUERY)
102 2 server status request (STATUS)
103 AA Authoritative Answer - this bit is valid in responses.
104 Responding name server is an authority for the domain name
105 in question section. Answer section may have multiple owner names
106 because of aliases. The AA bit corresponds to the name which matches
107 the query name, or the first owner name in the answer section.
108 TC TrunCation - this message was truncated.
109 RD Recursion Desired - this bit may be set in a query and
110 is copied into the response. If RD is set, it directs
111 the name server to pursue the query recursively.
112 Recursive query support is optional.
113 RA Recursion Available - this be is set or cleared in a
114 response, and denotes whether recursive query support is
115 available in the name server.
116 RCODE Response code.
117 0 No error condition
118 1 Format error
119 2 Server failure - server was unable to process the query
120 due to a problem with the name server.
121 3 Name Error - meaningful only for responses from
122 an authoritative name server. The referenced domain name
123 does not exist.
124 4 Not Implemented.
125 5 Refused.
126 QDCOUNT number of entries in the question section.
127 ANCOUNT number of records in the answer section.
128 NSCOUNT number of records in the authority records section.
129 ARCOUNT number of records in the additional records section.
131 4.1.2. Question section format
133 The section contains QDCOUNT (usually 1) entries, each of this format:
134 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
135 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
136 / QNAME /
138 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
139 | QTYPE |
140 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
141 | QCLASS |
142 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
143 QNAME a domain name represented as a sequence of labels, where
144 each label consists of a length octet followed by that
145 number of octets. The domain name terminates with the
146 zero length octet for the null label of the root. Note
147 that this field may be an odd number of octets; no
148 padding is used.
149 QTYPE a two octet type of the query.
150 1 a host address [REQ_A const]
151 2 an authoritative name server
152 3 a mail destination (Obsolete - use MX)
153 4 a mail forwarder (Obsolete - use MX)
154 5 the canonical name for an alias
155 6 marks the start of a zone of authority
156 7 a mailbox domain name (EXPERIMENTAL)
157 8 a mail group member (EXPERIMENTAL)
158 9 a mail rename domain name (EXPERIMENTAL)
159 10 a null RR (EXPERIMENTAL)
160 11 a well known service description
161 12 a domain name pointer [REQ_PTR const]
162 13 host information
163 14 mailbox or mail list information
164 15 mail exchange
165 16 text strings
166 0x1c IPv6?
167 252 a request for a transfer of an entire zone
168 253 a request for mailbox-related records (MB, MG or MR)
169 254 a request for mail agent RRs (Obsolete - see MX)
170 255 a request for all records
171 QCLASS a two octet code that specifies the class of the query.
172 1 the Internet
173 (others are historic only)
174 255 any class
176 4.1.3. Resource record format
178 The answer, authority, and additional sections all share the same format:
179 a variable number of resource records, where the number of records
180 is specified in the corresponding count field in the header.
181 Each resource record has this format:
182 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
183 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
185 / NAME /
186 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
187 | TYPE |
188 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
189 | CLASS |
190 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
191 | TTL |
193 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
194 | RDLENGTH |
195 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--|
196 / RDATA /
198 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
199 NAME a domain name to which this resource record pertains.
200 TYPE two octets containing one of the RR type codes. This
201 field specifies the meaning of the data in the RDATA field.
202 CLASS two octets which specify the class of the data in the RDATA field.
203 TTL a 32 bit unsigned integer that specifies the time interval
204 (in seconds) that the record may be cached.
205 RDLENGTH a 16 bit integer, length in octets of the RDATA field.
206 RDATA a variable length string of octets that describes the resource.
207 The format of this information varies according to the TYPE
208 and CLASS of the resource record.
209 If the TYPE is A and the CLASS is IN, it's a 4 octet IP address.
211 4.1.4. Message compression
213 In order to reduce the size of messages, domain names can be compressed.
214 An entire domain name or a list of labels at the end of a domain name
215 is replaced with a pointer to a prior occurance of the same name.
217 The pointer takes the form of a two octet sequence:
218 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
219 | 1 1| OFFSET |
220 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
221 The first two bits are ones. This allows a pointer to be distinguished
222 from a label, since the label must begin with two zero bits because
223 labels are restricted to 63 octets or less. The OFFSET field specifies
224 an offset from the start of the message (i.e., the first octet
225 of the ID field in the domain header).
226 A zero offset specifies the first byte of the ID field, etc.
227 Domain name in a message can be represented as either:
228 - a sequence of labels ending in a zero octet
229 - a pointer
230 - a sequence of labels ending with a pointer
233 #include <string.h>
234 #include <stdio.h>
235 #include <stdio_ext.h>
236 #include <signal.h>
237 #include <malloc.h>
238 #include <errno.h>
239 #include <sys/poll.h>
240 #include <sys/socket.h>
241 #include <sys/types.h>
242 #include <sys/time.h>
243 #include <netinet/in.h>
244 #include <arpa/inet.h>
245 #include <stdlib.h>
246 #include <unistd.h>
247 #include <resolv.h>
248 #include <netdb.h>
249 #include <ctype.h>
250 #include <stdbool.h>
251 #include <time.h>
252 #include <arpa/nameser.h>
253 #include <sys/utsname.h>
254 #include <sys/un.h>
255 #include <sys/stat.h>
256 #include <sys/param.h>
257 #include <bits/uClibc_mutex.h>
258 #include "internal/parse_config.h"
260 /* poll() is not supported in kernel <= 2.0, therefore if __NR_poll is
261 * not available, we assume an old Linux kernel is in use and we will
262 * use select() instead. */
263 #include <sys/syscall.h>
264 #ifndef __NR_poll
265 # define USE_SELECT
266 #endif
268 #if defined __UCLIBC_HAS_IPV4__ && defined __UCLIBC_HAS_IPV6__
269 #define IF_HAS_BOTH(...) __VA_ARGS__
270 #else
271 #define IF_HAS_BOTH(...)
272 #endif
275 #define MAX_RECURSE 5
276 #define MAXALIASES (4)
277 /* 1:ip + 1:full + MAX_ALIASES:aliases + 1:NULL */
278 #define ALIAS_DIM (2 + MAXALIASES + 1)
279 #define BUFSZ (80) /* one line */
281 #define NS_TYPE_ELT 0x40 /*%< EDNS0 extended label type */
282 #define DNS_LABELTYPE_BITSTRING 0x41
284 #undef DEBUG
285 /* #define DEBUG */
287 #ifdef DEBUG
288 #define DPRINTF(X,args...) fprintf(stderr, X, ##args)
289 #else
290 #define DPRINTF(X,args...)
291 #endif
293 /* Make sure the incoming char * buffer is aligned enough to handle our random
294 * structures. This define is the same as we use for malloc alignment (which
295 * has same requirements). The offset is the number of bytes we need to adjust
296 * in order to attain desired alignment.
298 #define ALIGN_ATTR __alignof__(double __attribute_aligned__ (sizeof(size_t)))
299 #define ALIGN_BUFFER_OFFSET(buf) ((ALIGN_ATTR - ((size_t)buf % ALIGN_ATTR)) % ALIGN_ATTR)
302 /* Structs */
303 struct resolv_header {
304 int id;
305 int qr, opcode, aa, tc, rd, ra, rcode;
306 int qdcount;
307 int ancount;
308 int nscount;
309 int arcount;
312 struct resolv_question {
313 char *dotted;
314 int qtype;
315 int qclass;
318 struct resolv_answer {
319 char *dotted;
320 int atype;
321 int aclass;
322 int ttl;
323 int rdlength;
324 const unsigned char *rdata;
325 int rdoffset;
326 char* buf;
327 size_t buflen;
328 size_t add_count;
331 enum etc_hosts_action {
332 GET_HOSTS_BYNAME = 0,
333 GETHOSTENT,
334 GET_HOSTS_BYADDR,
337 typedef union sockaddr46_t {
338 struct sockaddr sa;
339 #ifdef __UCLIBC_HAS_IPV4__
340 struct sockaddr_in sa4;
341 #endif
342 #ifdef __UCLIBC_HAS_IPV6__
343 struct sockaddr_in6 sa6;
344 #endif
345 } sockaddr46_t;
348 __UCLIBC_MUTEX_EXTERN(__resolv_lock) attribute_hidden;
350 /* Protected by __resolv_lock */
351 extern void (*__res_sync)(void) attribute_hidden;
352 /*extern uint32_t __resolv_opts attribute_hidden; */
353 extern uint8_t __resolv_timeout attribute_hidden;
354 extern uint8_t __resolv_attempts attribute_hidden;
355 extern unsigned __nameservers attribute_hidden;
356 extern unsigned __searchdomains attribute_hidden;
357 extern sockaddr46_t *__nameserver attribute_hidden;
358 extern char **__searchdomain attribute_hidden;
359 #ifdef __UCLIBC_HAS_IPV4__
360 extern const struct sockaddr_in __local_nameserver attribute_hidden;
361 #else
362 extern const struct sockaddr_in6 __local_nameserver attribute_hidden;
363 #endif
364 /* Arbitrary */
365 #define MAXLEN_searchdomain 128
368 /* prototypes for internal functions */
369 extern void endhostent_unlocked(void) attribute_hidden;
370 extern int __get_hosts_byname_r(const char *name,
371 int type,
372 struct hostent *result_buf,
373 char *buf,
374 size_t buflen,
375 struct hostent **result,
376 int *h_errnop) attribute_hidden;
377 extern int __get_hosts_byaddr_r(const char *addr,
378 int len,
379 int type,
380 struct hostent *result_buf,
381 char *buf,
382 size_t buflen,
383 struct hostent **result,
384 int *h_errnop) attribute_hidden;
385 extern parser_t *__open_etc_hosts(void) attribute_hidden;
386 extern int __read_etc_hosts_r(parser_t *parser,
387 const char *name,
388 int type,
389 enum etc_hosts_action action,
390 struct hostent *result_buf,
391 char *buf,
392 size_t buflen,
393 struct hostent **result,
394 int *h_errnop) attribute_hidden;
395 extern int __dns_lookup(const char *name,
396 int type,
397 unsigned char **outpacket,
398 struct resolv_answer *a) attribute_hidden;
399 extern int __encode_header(struct resolv_header *h,
400 unsigned char *dest,
401 int maxlen) attribute_hidden;
402 extern void __decode_header(unsigned char *data,
403 struct resolv_header *h) attribute_hidden;
404 extern int __encode_question(const struct resolv_question *q,
405 unsigned char *dest,
406 int maxlen) attribute_hidden;
407 extern int __encode_answer(struct resolv_answer *a,
408 unsigned char *dest,
409 int maxlen) attribute_hidden;
410 extern void __open_nameservers(void) attribute_hidden;
411 extern void __close_nameservers(void) attribute_hidden;
412 extern int __hnbad(const char *dotted) attribute_hidden;
414 #define __encode_dotted(dotted,dest,maxlen) \
415 dn_comp((dotted), (dest), (maxlen), NULL, NULL)
416 #define __decode_dotted(packet,offset,packet_len,dest,dest_len) \
417 dn_expand((packet), (packet) + (packet_len), (packet) + (offset), \
418 (dest), (dest_len))
421 * Theory of operation.
423 * gethostbyname, getaddrinfo and friends end up here, and they sometimes
424 * need to talk to DNS servers. In order to do this, we need to read /etc/resolv.conf
425 * and determine servers' addresses and the like. resolv.conf format:
427 * nameserver <IP[v6]>
428 * Address of DNS server. Cumulative.
429 * If not specified, assumed to be on localhost.
430 * search <domain1>[ <domain2>]...
431 * Append these domains to unqualified names.
432 * See ndots:n option.
433 * $LOCALDOMAIN (space-separated list) overrides this.
434 * domain <domain>
435 * Effectively same as "search" with one domain.
436 * If no "domain" line is present, the domain is determined
437 * from the local host name returned by gethostname();
438 * the domain part is taken to be everything after the first dot.
439 * If there are no dots, there will be no "domain".
440 * The domain and search keywords are mutually exclusive.
441 * If more than one instance of these keywords is present,
442 * the last instance wins.
443 * sortlist 130.155.160.0[/255.255.240.0] 130.155.0.0
444 * Allows addresses returned by gethostbyname to be sorted.
445 * Not supported.
446 * options option[ option]...
447 * (so far we support timeout:n and attempts:n)
448 * $RES_OPTIONS (space-separated list) is to be added to "options"
449 * debug sets RES_DEBUG in _res.options
450 * ndots:n how many dots there should be so that name will be tried
451 * first as an absolute name before any search list elements
452 * are appended to it. Default 1
453 * timeout:n how long to wait for response. Default 5
454 * (sun seems to have retrans:n synonym)
455 * attempts:n number of rounds to do before giving up and returning
456 * an error. Default 2
457 * (sun seems to have retry:n synonym)
458 * rotate sets RES_ROTATE in _res.options, round robin
459 * selection of nameservers. Otherwise try
460 * the first listed server first every time
461 * no-check-names
462 * sets RES_NOCHECKNAME in _res.options, which disables
463 * checking of incoming host names for invalid characters
464 * such as underscore (_), non-ASCII, or control characters
465 * inet6 sets RES_USE_INET6 in _res.options. Try a AAAA query
466 * before an A query inside the gethostbyname(), and map
467 * IPv4 responses in IPv6 "tunnelled form" if no AAAA records
468 * are found but an A record set exists
469 * no_tld_query (FreeBSDism?)
470 * do not attempt to resolve names without dots
472 * We will read and analyze /etc/resolv.conf as needed before
473 * we do a DNS request. This happens in __dns_lookup.
474 * It is reread if its mtime is changed.
476 * BSD has res_init routine which is used to initialize resolver state
477 * which is held in global structure _res.
478 * Generally, programs call res_init, then fiddle with _res.XXX
479 * (_res.options and _res.nscount, _res.nsaddr_list[N]
480 * are popular targets of fiddling) and expect subsequent calls
481 * to gethostbyname, getaddrinfo, etc to use modified information.
483 * However, historical _res structure is quite awkward.
484 * Using it for storing /etc/resolv.conf info is not desirable,
485 * and __dns_lookup does not use it.
487 * We would like to avoid using it unless absolutely necessary.
488 * If user doesn't use res_init, we should arrange it so that
489 * _res structure doesn't even *get linked in* into user's application
490 * (imagine static uclibc build here).
492 * The solution is a __res_sync function pointer, which is normally NULL.
493 * But if res_init is called, it gets set and any subsequent gethostbyname
494 * et al "syncronizes" our internal structures with potentially
495 * modified _res.XXX stuff by calling __res_sync.
496 * The trick here is that if res_init is not used and not linked in,
497 * gethostbyname itself won't reference _res and _res won't be linked in
498 * either. Other possible methods like
499 * if (__res_sync_just_an_int_flag)
500 * __sync_me_with_res()
501 * would pull in __sync_me_with_res, which pulls in _res. Bad.
505 #ifdef L_encodeh
507 int __encode_header(struct resolv_header *h, unsigned char *dest, int maxlen)
509 if (maxlen < HFIXEDSZ)
510 return -1;
512 dest[0] = (h->id & 0xff00) >> 8;
513 dest[1] = (h->id & 0x00ff) >> 0;
514 dest[2] = (h->qr ? 0x80 : 0) |
515 ((h->opcode & 0x0f) << 3) |
516 (h->aa ? 0x04 : 0) |
517 (h->tc ? 0x02 : 0) |
518 (h->rd ? 0x01 : 0);
519 dest[3] = (h->ra ? 0x80 : 0) | (h->rcode & 0x0f);
520 dest[4] = (h->qdcount & 0xff00) >> 8;
521 dest[5] = (h->qdcount & 0x00ff) >> 0;
522 dest[6] = (h->ancount & 0xff00) >> 8;
523 dest[7] = (h->ancount & 0x00ff) >> 0;
524 dest[8] = (h->nscount & 0xff00) >> 8;
525 dest[9] = (h->nscount & 0x00ff) >> 0;
526 dest[10] = (h->arcount & 0xff00) >> 8;
527 dest[11] = (h->arcount & 0x00ff) >> 0;
529 return HFIXEDSZ;
531 #endif /* L_encodeh */
534 #ifdef L_decodeh
536 void __decode_header(unsigned char *data,
537 struct resolv_header *h)
539 h->id = (data[0] << 8) | data[1];
540 h->qr = (data[2] & 0x80) ? 1 : 0;
541 h->opcode = (data[2] >> 3) & 0x0f;
542 h->aa = (data[2] & 0x04) ? 1 : 0;
543 h->tc = (data[2] & 0x02) ? 1 : 0;
544 h->rd = (data[2] & 0x01) ? 1 : 0;
545 h->ra = (data[3] & 0x80) ? 1 : 0;
546 h->rcode = data[3] & 0x0f;
547 h->qdcount = (data[4] << 8) | data[5];
548 h->ancount = (data[6] << 8) | data[7];
549 h->nscount = (data[8] << 8) | data[9];
550 h->arcount = (data[10] << 8) | data[11];
552 #endif /* L_decodeh */
555 #ifdef L_encodeq
557 int __encode_question(const struct resolv_question *q,
558 unsigned char *dest,
559 int maxlen)
561 int i;
563 i = __encode_dotted(q->dotted, dest, maxlen);
564 if (i < 0)
565 return i;
567 dest += i;
568 maxlen -= i;
570 if (maxlen < 4)
571 return -1;
573 dest[0] = (q->qtype & 0xff00) >> 8;
574 dest[1] = (q->qtype & 0x00ff) >> 0;
575 dest[2] = (q->qclass & 0xff00) >> 8;
576 dest[3] = (q->qclass & 0x00ff) >> 0;
578 return i + 4;
580 #endif /* L_encodeq */
583 #ifdef L_encodea
585 int __encode_answer(struct resolv_answer *a, unsigned char *dest, int maxlen)
587 int i;
589 i = __encode_dotted(a->dotted, dest, maxlen);
590 if (i < 0)
591 return i;
593 dest += i;
594 maxlen -= i;
596 if (maxlen < (RRFIXEDSZ + a->rdlength))
597 return -1;
599 *dest++ = (a->atype & 0xff00) >> 8;
600 *dest++ = (a->atype & 0x00ff) >> 0;
601 *dest++ = (a->aclass & 0xff00) >> 8;
602 *dest++ = (a->aclass & 0x00ff) >> 0;
603 *dest++ = (a->ttl & 0xff000000) >> 24;
604 *dest++ = (a->ttl & 0x00ff0000) >> 16;
605 *dest++ = (a->ttl & 0x0000ff00) >> 8;
606 *dest++ = (a->ttl & 0x000000ff) >> 0;
607 *dest++ = (a->rdlength & 0xff00) >> 8;
608 *dest++ = (a->rdlength & 0x00ff) >> 0;
609 memcpy(dest, a->rdata, a->rdlength);
611 return i + RRFIXEDSZ + a->rdlength;
613 #endif /* L_encodea */
616 #ifdef CURRENTLY_UNUSED
617 #ifdef L_encodep
619 int __encode_packet(struct resolv_header *h,
620 struct resolv_question **q,
621 struct resolv_answer **an,
622 struct resolv_answer **ns,
623 struct resolv_answer **ar,
624 unsigned char *dest, int maxlen) attribute_hidden;
625 int __encode_packet(struct resolv_header *h,
626 struct resolv_question **q,
627 struct resolv_answer **an,
628 struct resolv_answer **ns,
629 struct resolv_answer **ar,
630 unsigned char *dest, int maxlen)
632 int i, total = 0;
633 unsigned j;
635 i = __encode_header(h, dest, maxlen);
636 if (i < 0)
637 return i;
639 dest += i;
640 maxlen -= i;
641 total += i;
643 for (j = 0; j < h->qdcount; j++) {
644 i = __encode_question(q[j], dest, maxlen);
645 if (i < 0)
646 return i;
647 dest += i;
648 maxlen -= i;
649 total += i;
652 for (j = 0; j < h->ancount; j++) {
653 i = __encode_answer(an[j], dest, maxlen);
654 if (i < 0)
655 return i;
656 dest += i;
657 maxlen -= i;
658 total += i;
660 for (j = 0; j < h->nscount; j++) {
661 i = __encode_answer(ns[j], dest, maxlen);
662 if (i < 0)
663 return i;
664 dest += i;
665 maxlen -= i;
666 total += i;
668 for (j = 0; j < h->arcount; j++) {
669 i = __encode_answer(ar[j], dest, maxlen);
670 if (i < 0)
671 return i;
672 dest += i;
673 maxlen -= i;
674 total += i;
677 return total;
679 #endif /* L_encodep */
682 #ifdef L_decodep
684 int __decode_packet(unsigned char *data, struct resolv_header *h) attribute_hidden;
685 int __decode_packet(unsigned char *data, struct resolv_header *h)
687 __decode_header(data, h);
688 return HFIXEDSZ;
690 #endif /* L_decodep */
693 #ifdef L_formquery
695 int __form_query(int id,
696 const char *name,
697 int type,
698 unsigned char *packet,
699 int maxlen) attribute_hidden;
700 int __form_query(int id,
701 const char *name,
702 int type,
703 unsigned char *packet,
704 int maxlen)
706 struct resolv_header h;
707 struct resolv_question q;
708 int i, j;
710 memset(&h, 0, sizeof(h));
711 h.id = id;
712 h.qdcount = 1;
714 q.dotted = (char *) name;
715 q.qtype = type;
716 q.qclass = C_IN; /* CLASS_IN */
718 i = __encode_header(&h, packet, maxlen);
719 if (i < 0)
720 return i;
722 j = __encode_question(&q, packet + i, maxlen - i);
723 if (j < 0)
724 return j;
726 return i + j;
728 #endif /* L_formquery */
729 #endif /* CURRENTLY_UNUSED */
732 #ifdef L_opennameservers
734 # if __BYTE_ORDER == __LITTLE_ENDIAN
735 #define NAMESERVER_PORT_N (__bswap_constant_16(NAMESERVER_PORT))
736 #else
737 #define NAMESERVER_PORT_N NAMESERVER_PORT
738 #endif
740 __UCLIBC_MUTEX_INIT(__resolv_lock, PTHREAD_MUTEX_INITIALIZER);
742 /* Protected by __resolv_lock */
743 void (*__res_sync)(void);
744 /*uint32_t __resolv_opts; */
745 uint8_t __resolv_timeout = RES_TIMEOUT;
746 uint8_t __resolv_attempts = RES_DFLRETRY;
747 unsigned __nameservers;
748 unsigned __searchdomains;
749 sockaddr46_t *__nameserver;
750 char **__searchdomain;
751 #ifdef __UCLIBC_HAS_IPV4__
752 const struct sockaddr_in __local_nameserver = {
753 .sin_family = AF_INET,
754 .sin_port = NAMESERVER_PORT_N,
756 #else
757 const struct sockaddr_in6 __local_nameserver = {
758 .sin6_family = AF_INET6,
759 .sin6_port = NAMESERVER_PORT_N,
761 #endif
763 /* Helpers. Both stop on EOL, if it's '\n', it is converted to NUL first */
764 static char *skip_nospace(char *p)
766 while (*p != '\0' && !isspace(*p)) {
767 if (*p == '\n') {
768 *p = '\0';
769 break;
771 p++;
773 return p;
775 static char *skip_and_NUL_space(char *p)
777 /* NB: '\n' is not isspace! */
778 while (1) {
779 char c = *p;
780 if (c == '\0' || !isspace(c))
781 break;
782 *p = '\0';
783 if (c == '\n' || c == '#')
784 break;
785 p++;
787 return p;
790 /* Must be called under __resolv_lock. */
791 void __open_nameservers(void)
793 static uint32_t resolv_conf_mtime;
795 char szBuffer[MAXLEN_searchdomain];
796 FILE *fp;
797 int i;
798 sockaddr46_t sa;
800 if (!__res_sync) {
801 /* Reread /etc/resolv.conf if it was modified. */
802 struct stat sb;
803 if (stat(_PATH_RESCONF, &sb) != 0)
804 sb.st_mtime = 0;
805 if (resolv_conf_mtime != (uint32_t)sb.st_mtime) {
806 resolv_conf_mtime = sb.st_mtime;
807 __close_nameservers(); /* force config reread */
811 if (__nameservers)
812 goto sync;
814 __resolv_timeout = RES_TIMEOUT;
815 __resolv_attempts = RES_DFLRETRY;
817 fp = fopen(_PATH_RESCONF, "r");
818 #ifdef FALLBACK_TO_CONFIG_RESOLVCONF
819 if (!fp) {
820 /* If we do not have a pre-populated /etc/resolv.conf then
821 try to use the one from /etc/config which exists on numerous
822 systems ranging from some uClinux to IRIX installations and
823 may be the only /etc dir that was mounted rw. */
824 fp = fopen("/etc/config/resolv.conf", "r");
826 #endif
828 if (fp) {
829 while (fgets(szBuffer, sizeof(szBuffer), fp) != NULL) {
830 void *ptr;
831 char *keyword, *p;
833 keyword = p = skip_and_NUL_space(szBuffer);
834 /* skip keyword */
835 p = skip_nospace(p);
836 /* find next word */
837 p = skip_and_NUL_space(p);
839 if (strcmp(keyword, "nameserver") == 0) {
840 /* terminate IP addr */
841 *skip_nospace(p) = '\0';
842 memset(&sa, 0, sizeof(sa));
843 if (0) /* nothing */;
844 #ifdef __UCLIBC_HAS_IPV6__
845 else if (inet_pton(AF_INET6, p, &sa.sa6.sin6_addr) > 0) {
846 sa.sa6.sin6_family = AF_INET6;
847 sa.sa6.sin6_port = htons(NAMESERVER_PORT);
849 #endif
850 #ifdef __UCLIBC_HAS_IPV4__
851 else if (inet_pton(AF_INET, p, &sa.sa4.sin_addr) > 0) {
852 sa.sa4.sin_family = AF_INET;
853 sa.sa4.sin_port = htons(NAMESERVER_PORT);
855 #endif
856 else
857 continue; /* garbage on this line */
858 ptr = realloc(__nameserver, (__nameservers + 1) * sizeof(__nameserver[0]));
859 if (!ptr)
860 continue;
861 __nameserver = ptr;
862 __nameserver[__nameservers++] = sa; /* struct copy */
863 continue;
865 if (strcmp(keyword, "domain") == 0 || strcmp(keyword, "search") == 0) {
866 char *p1;
868 /* free old domains ("last 'domain' or 'search' wins" rule) */
869 while (__searchdomains)
870 free(__searchdomain[--__searchdomains]);
871 /*free(__searchdomain);*/
872 /*__searchdomain = NULL; - not necessary */
873 next_word:
874 /* terminate current word */
875 p1 = skip_nospace(p);
876 /* find next word (maybe) */
877 p1 = skip_and_NUL_space(p1);
878 /* add it */
879 ptr = realloc(__searchdomain, (__searchdomains + 1) * sizeof(__searchdomain[0]));
880 if (!ptr)
881 continue;
882 __searchdomain = ptr;
883 /* NB: strlen(p) <= MAXLEN_searchdomain) because szBuffer[] is smaller */
884 ptr = strdup(p);
885 if (!ptr)
886 continue;
887 DPRINTF("adding search %s\n", (char*)ptr);
888 __searchdomain[__searchdomains++] = (char*)ptr;
889 p = p1;
890 if (*p)
891 goto next_word;
892 continue;
894 /* if (strcmp(keyword, "sortlist") == 0)... */
895 if (strcmp(keyword, "options") == 0) {
896 char *p1;
897 uint8_t *what;
899 if (p == NULL || (p1 = strchr(p, ':')) == NULL)
900 continue;
901 *p1++ = '\0';
902 if (strcmp(p, "timeout") == 0)
903 what = &__resolv_timeout;
904 else if (strcmp(p, "attempts") == 0)
905 what = &__resolv_attempts;
906 else
907 continue;
908 *what = atoi(p1);
909 DPRINTF("option %s:%d\n", p, *what);
912 fclose(fp);
914 if (__nameservers == 0) {
915 /* Have to handle malloc failure! What a mess...
916 * And it's not only here, we need to be careful
917 * to never write into __nameserver[0] if it points
918 * to constant __local_nameserver, or free it. */
919 __nameserver = malloc(sizeof(__nameserver[0]));
920 if (__nameserver)
921 memcpy(__nameserver, &__local_nameserver, sizeof(__local_nameserver));
922 else
923 __nameserver = (void*) &__local_nameserver;
924 __nameservers++;
926 if (__searchdomains == 0) {
927 char buf[256];
928 char *p;
929 i = gethostname(buf, sizeof(buf) - 1);
930 buf[sizeof(buf) - 1] = '\0';
931 if (i == 0 && (p = strchr(buf, '.')) != NULL && p[1]) {
932 p = strdup(p + 1);
933 if (!p)
934 goto err;
935 __searchdomain = malloc(sizeof(__searchdomain[0]));
936 if (!__searchdomain) {
937 free(p);
938 goto err;
940 __searchdomain[0] = p;
941 __searchdomains++;
942 err: ;
945 DPRINTF("nameservers = %d\n", __nameservers);
947 sync:
948 if (__res_sync)
949 __res_sync();
951 #endif /* L_opennameservers */
954 #ifdef L_closenameservers
956 /* Must be called under __resolv_lock. */
957 void __close_nameservers(void)
959 if (__nameserver != (void*) &__local_nameserver)
960 free(__nameserver);
961 __nameserver = NULL;
962 __nameservers = 0;
963 while (__searchdomains)
964 free(__searchdomain[--__searchdomains]);
965 free(__searchdomain);
966 __searchdomain = NULL;
967 /*__searchdomains = 0; - already is */
969 #endif /* L_closenameservers */
972 #ifdef L_dnslookup
974 /* Helpers */
975 static int __length_question(const unsigned char *data, int maxlen)
977 const unsigned char *start;
978 unsigned b;
980 if (!data)
981 return -1;
983 start = data;
984 while (1) {
985 if (maxlen <= 0)
986 return -1;
987 b = *data++;
988 if (b == 0)
989 break;
990 if ((b & 0xc0) == 0xc0) {
991 /* It's a "compressed" name. */
992 data++; /* skip lsb of redirected offset */
993 maxlen -= 2;
994 break;
996 data += b;
997 maxlen -= (b + 1); /* account for data++ above */
999 /* Up to here we were skipping encoded name */
1001 /* Account for QTYPE and QCLASS fields */
1002 if (maxlen < 4)
1003 return -1;
1004 return data - start + 2 + 2;
1007 static int __decode_answer(const unsigned char *message, /* packet */
1008 int offset,
1009 int len, /* total packet len */
1010 struct resolv_answer *a)
1012 char temp[256];
1013 int i;
1015 DPRINTF("decode_answer(start): off %d, len %d\n", offset, len);
1016 i = __decode_dotted(message, offset, len, temp, sizeof(temp));
1017 if (i < 0)
1018 return i;
1020 message += offset + i;
1021 len -= i + RRFIXEDSZ + offset;
1022 if (len < 0) {
1023 DPRINTF("decode_answer: off %d, len %d, i %d\n", offset, len, i);
1024 return len;
1027 /* TODO: what if strdup fails? */
1028 a->dotted = strdup(temp);
1029 a->atype = (message[0] << 8) | message[1];
1030 message += 2;
1031 a->aclass = (message[0] << 8) | message[1];
1032 message += 2;
1033 a->ttl = (message[0] << 24) |
1034 (message[1] << 16) | (message[2] << 8) | (message[3] << 0);
1035 message += 4;
1036 a->rdlength = (message[0] << 8) | message[1];
1037 message += 2;
1038 a->rdata = message;
1039 a->rdoffset = offset + i + RRFIXEDSZ;
1041 DPRINTF("i=%d,rdlength=%d\n", i, a->rdlength);
1043 if (len < a->rdlength)
1044 return -1;
1045 return i + RRFIXEDSZ + a->rdlength;
1048 /* On entry:
1049 * a.buf(len) = auxiliary buffer for IP addresses after first one
1050 * a.add_count = how many additional addresses are there already
1051 * outpacket = where to save ptr to raw packet? can be NULL
1052 * On exit:
1053 * ret < 0: error, all other data is not valid
1054 * ret >= 0: length of reply packet
1055 * a.add_count & a.buf: updated
1056 * a.rdlength: length of addresses (4 bytes for IPv4)
1057 * *outpacket: updated (packet is malloced, you need to free it)
1058 * a.rdata: points into *outpacket to 1st IP addr
1059 * NB: don't pass outpacket == NULL if you need to use a.rdata!
1060 * a.atype: type of query?
1061 * a.dotted: which name we _actually_ used. May contain search domains
1062 * appended. (why the filed is called "dotted" I have no idea)
1063 * This is a malloced string. May be NULL because strdup failed.
1065 int __dns_lookup(const char *name,
1066 int type,
1067 unsigned char **outpacket,
1068 struct resolv_answer *a)
1070 /* Protected by __resolv_lock: */
1071 static int last_ns_num = 0;
1072 static uint16_t last_id = 1;
1074 int i, j, fd, rc;
1075 int packet_len;
1076 int name_len;
1077 #ifdef USE_SELECT
1078 struct timeval tv;
1079 fd_set fds;
1080 #else
1081 struct pollfd fds;
1082 #endif
1083 struct resolv_header h;
1084 struct resolv_question q;
1085 struct resolv_answer ma;
1086 bool first_answer = 1;
1087 int retries_left;
1088 unsigned char *packet = malloc(PACKETSZ);
1089 char *lookup;
1090 int variant = -1; /* search domain to append, -1: none */
1091 int local_ns_num = -1; /* Nth server to use */
1092 int local_id = local_id; /* for compiler */
1093 int sdomains = 0;
1094 bool ends_with_dot;
1095 bool contains_dot;
1096 sockaddr46_t sa;
1097 int num_answers;
1099 fd = -1;
1100 lookup = NULL;
1101 name_len = strlen(name);
1102 if ((unsigned)name_len >= MAXDNAME - MAXLEN_searchdomain - 2)
1103 goto fail; /* paranoia */
1104 lookup = malloc(name_len + 1/*for '.'*/ + MAXLEN_searchdomain + 1);
1105 if (!packet || !lookup || !name[0])
1106 goto fail;
1107 ends_with_dot = (name[name_len - 1] == '.');
1108 contains_dot = strchr(name, '.') != NULL;
1109 /* no strcpy! paranoia, user might change name[] under us */
1110 memcpy(lookup, name, name_len);
1112 DPRINTF("Looking up type %d answer for '%s'\n", type, name);
1113 retries_left = 0; /* for compiler */
1114 do {
1115 unsigned act_variant;
1116 int pos;
1117 unsigned reply_timeout;
1119 if (fd != -1) {
1120 close(fd);
1121 fd = -1;
1124 /* Mess with globals while under lock */
1125 /* NB: even data *pointed to* by globals may vanish
1126 * outside the locks. We should assume any and all
1127 * globals can completely change between locked
1128 * code regions. OTOH, this is rare, so we don't need
1129 * to handle it "nicely" (do not skip servers,
1130 * search domains, etc), we only need to ensure
1131 * we do not SEGV, use freed+overwritten data
1132 * or do other Really Bad Things. */
1133 __UCLIBC_MUTEX_LOCK(__resolv_lock);
1134 __open_nameservers();
1135 if (type != T_PTR) {
1136 sdomains = __searchdomains;
1138 lookup[name_len] = '\0';
1139 /* For qualified names, act_variant = MAX_UINT, 0, .., sdomains-1
1140 * => Try original name first, then append search domains
1141 * For names without domain, act_variant = 0, 1, .., sdomains
1142 * => Try search domains first, original name last */
1143 act_variant = contains_dot ? variant : variant + 1;
1144 if (act_variant < sdomains) {
1145 /* lookup is name_len + 1 + MAXLEN_searchdomain + 1 long */
1146 /* __searchdomain[] is not bigger than MAXLEN_searchdomain */
1147 lookup[name_len] = '.';
1148 strcpy(&lookup[name_len + 1], __searchdomain[act_variant]);
1150 /* first time? pick starting server etc */
1151 if (local_ns_num < 0) {
1152 local_id = last_id;
1153 /*TODO: implement /etc/resolv.conf's "options rotate"
1154 (a.k.a. RES_ROTATE bit in _res.options)
1155 local_ns_num = 0;
1156 if (_res.options & RES_ROTATE) */
1157 local_ns_num = last_ns_num;
1158 retries_left = __nameservers * __resolv_attempts;
1160 if (local_ns_num >= __nameservers)
1161 local_ns_num = 0;
1162 local_id++;
1163 local_id &= 0xffff;
1164 /* write new values back while still under lock */
1165 last_id = local_id;
1166 last_ns_num = local_ns_num;
1167 /* struct copy */
1168 /* can't just take a pointer, __nameserver[x]
1169 * is not safe to use outside of locks */
1170 sa = __nameserver[local_ns_num];
1171 __UCLIBC_MUTEX_UNLOCK(__resolv_lock);
1173 memset(packet, 0, PACKETSZ);
1174 memset(&h, 0, sizeof(h));
1176 /* encode header */
1177 h.id = local_id;
1178 h.qdcount = 1;
1179 h.rd = 1;
1180 DPRINTF("encoding header\n", h.rd);
1181 i = __encode_header(&h, packet, PACKETSZ);
1182 if (i < 0)
1183 goto fail;
1185 /* encode question */
1186 DPRINTF("lookup name: %s\n", lookup);
1187 q.dotted = lookup;
1188 q.qtype = type;
1189 q.qclass = C_IN; /* CLASS_IN */
1190 j = __encode_question(&q, packet+i, PACKETSZ-i);
1191 if (j < 0)
1192 goto fail;
1193 packet_len = i + j;
1195 /* send packet */
1196 #ifdef DEBUG
1198 const socklen_t plen = sa.sa.sa_family == AF_INET ? INET_ADDRSTRLEN : INET6_ADDRSTRLEN;
1199 char *pbuf = malloc(plen);
1200 if (pbuf == NULL) ;/* nothing */
1201 #ifdef __UCLIBC_HAS_IPV6__
1202 else if (sa.sa.sa_family == AF_INET6)
1203 pbuf = (char*)inet_ntop(AF_INET6, &sa.sa6.sin6_addr, pbuf, plen);
1204 #endif
1205 #ifdef __UCLIBC_HAS_IPV4__
1206 else if (sa.sa.sa_family == AF_INET)
1207 pbuf = (char*)inet_ntop(AF_INET, &sa.sa4.sin_addr, pbuf, plen);
1208 #endif
1209 DPRINTF("On try %d, sending query to %s, port %d\n",
1210 retries_left, pbuf, NAMESERVER_PORT);
1211 free(pbuf);
1213 #endif
1214 fd = socket(sa.sa.sa_family, SOCK_DGRAM, IPPROTO_UDP);
1215 if (fd < 0) /* paranoia */
1216 goto try_next_server;
1217 rc = connect(fd, &sa.sa, sizeof(sa));
1218 if (rc < 0) {
1219 /*if (errno == ENETUNREACH) { */
1220 /* routing error, presume not transient */
1221 goto try_next_server;
1222 /*} */
1223 /*For example, what transient error this can be? Can't think of any */
1224 /* retry */
1225 /*continue; */
1227 DPRINTF("Xmit packet len:%d id:%d qr:%d\n", packet_len, h.id, h.qr);
1228 /* no error check - if it fails, we time out on recv */
1229 send(fd, packet, packet_len, 0);
1231 #ifdef USE_SELECT
1232 reply_timeout = __resolv_timeout;
1233 wait_again:
1234 FD_ZERO(&fds);
1235 FD_SET(fd, &fds);
1236 tv.tv_sec = reply_timeout;
1237 tv.tv_usec = 0;
1238 if (select(fd + 1, &fds, NULL, NULL, &tv) <= 0) {
1239 DPRINTF("Timeout\n");
1240 /* timed out, so retry send and receive
1241 * to next nameserver */
1242 goto try_next_server;
1244 reply_timeout--;
1245 #else /* !USE_SELECT */
1246 reply_timeout = __resolv_timeout * 1000;
1247 wait_again:
1248 fds.fd = fd;
1249 fds.events = POLLIN;
1250 if (poll(&fds, 1, reply_timeout) <= 0) {
1251 DPRINTF("Timeout\n");
1252 /* timed out, so retry send and receive
1253 * to next nameserver */
1254 goto try_next_server;
1256 if (fds.revents & (POLLERR | POLLHUP | POLLNVAL)) {
1257 DPRINTF("Bad event\n");
1258 goto try_next_server;
1260 /*TODO: better timeout accounting?*/
1261 reply_timeout -= 1000;
1262 #endif /* USE_SELECT */
1264 /* vda: a bogus response seen in real world (caused SEGV in uclibc):
1265 * "ping www.google.com" sending AAAA query and getting
1266 * response with one answer... with answer part missing!
1267 * Fixed by thorough checks for not going past the packet's end.
1269 #ifdef DEBUG
1271 static const char test_query[32] = "\0\2\1\0\0\1\0\0\0\0\0\0\3www\6google\3com\0\0\34\0\1";
1272 static const char test_respn[32] = "\0\2\201\200\0\1\0\1\0\0\0\0\3www\6google\3com\0\0\34\0\1";
1273 pos = memcmp(packet + 2, test_query + 2, 30);
1274 packet_len = recv(fd, packet, PACKETSZ, MSG_DONTWAIT);
1275 if (pos == 0) {
1276 packet_len = 32;
1277 memcpy(packet + 2, test_respn + 2, 30);
1280 #else
1281 packet_len = recv(fd, packet, PACKETSZ, MSG_DONTWAIT);
1282 #endif
1284 if (packet_len < HFIXEDSZ) {
1285 /* too short!
1286 * If the peer did shutdown then retry later,
1287 * try next peer on error.
1288 * it's just a bogus packet from somewhere */
1289 bogus_packet:
1290 if (packet_len >= 0 && reply_timeout)
1291 goto wait_again;
1292 goto try_next_server;
1294 __decode_header(packet, &h);
1295 DPRINTF("len:%d id:%d qr:%d\n", packet_len, h.id, h.qr);
1296 if (h.id != local_id || !h.qr) {
1297 /* unsolicited */
1298 goto bogus_packet;
1301 DPRINTF("Got response (i think)!\n");
1302 DPRINTF("qrcount=%d,ancount=%d,nscount=%d,arcount=%d\n",
1303 h.qdcount, h.ancount, h.nscount, h.arcount);
1304 DPRINTF("opcode=%d,aa=%d,tc=%d,rd=%d,ra=%d,rcode=%d\n",
1305 h.opcode, h.aa, h.tc, h.rd, h.ra, h.rcode);
1307 /* bug 660 says we treat negative response as an error
1308 * and retry, which is, eh, an error. :)
1309 * We were incurring long delays because of this. */
1310 if (h.rcode == NXDOMAIN || h.rcode == SERVFAIL) {
1311 /* if possible, try next search domain */
1312 if (!ends_with_dot) {
1313 DPRINTF("variant:%d sdomains:%d\n", variant, sdomains);
1314 if (variant < sdomains - 1) {
1315 /* next search domain */
1316 variant++;
1317 continue;
1319 /* no more search domains to try */
1321 if (h.rcode != SERVFAIL) {
1322 /* dont loop, this is "no such host" situation */
1323 h_errno = HOST_NOT_FOUND;
1324 goto fail1;
1327 /* Insert other non-fatal errors here, which do not warrant
1328 * switching to next nameserver */
1330 /* Strange error, assuming this nameserver is feeling bad */
1331 if (h.rcode != 0)
1332 goto try_next_server;
1334 /* Code below won't work correctly with h.ancount == 0, so... */
1335 if (h.ancount <= 0) {
1336 h_errno = NO_DATA; /* [is this correct code to check for?] */
1337 goto fail1;
1339 pos = HFIXEDSZ;
1340 /*XXX TODO: check that question matches query (and qdcount==1?) */
1341 for (j = 0; j < h.qdcount; j++) {
1342 DPRINTF("Skipping question %d at %d\n", j, pos);
1343 i = __length_question(packet + pos, packet_len - pos);
1344 if (i < 0) {
1345 DPRINTF("Packet'question section "
1346 "is truncated, trying next server\n");
1347 goto try_next_server;
1349 pos += i;
1350 DPRINTF("Length of question %d is %d\n", j, i);
1352 DPRINTF("Decoding answer at pos %d\n", pos);
1354 first_answer = 1;
1355 num_answers = 0;
1356 a->dotted = NULL;
1357 for (j = 0; j < h.ancount; j++) {
1358 i = __decode_answer(packet, pos, packet_len, &ma);
1359 if (i < 0) {
1360 DPRINTF("failed decode %d\n", i);
1361 /* If the message was truncated but we have
1362 * decoded some answers, pretend it's OK */
1363 if (num_answers && h.tc)
1364 break;
1365 goto try_next_server;
1367 pos += i;
1369 if (__hnbad(ma.dotted))
1370 break;
1371 ++num_answers;
1372 if (first_answer) {
1373 ma.buf = a->buf;
1374 ma.buflen = a->buflen;
1375 ma.add_count = a->add_count;
1376 free(a->dotted);
1377 memcpy(a, &ma, sizeof(ma));
1378 if (a->atype != T_SIG && (NULL == a->buf || (type != T_A && type != T_AAAA)))
1379 break;
1380 if (a->atype != type)
1381 continue;
1382 a->add_count = h.ancount - j - 1;
1383 if ((a->rdlength + sizeof(struct in_addr*)) * a->add_count > a->buflen)
1384 break;
1385 a->add_count = 0;
1386 first_answer = 0;
1387 } else {
1388 free(ma.dotted);
1389 if (ma.atype != type)
1390 continue;
1391 if (a->rdlength != ma.rdlength) {
1392 free(a->dotted);
1393 DPRINTF("Answer address len(%u) differs from original(%u)\n",
1394 ma.rdlength, a->rdlength);
1395 goto try_next_server;
1397 memcpy(a->buf + (a->add_count * ma.rdlength), ma.rdata, ma.rdlength);
1398 ++a->add_count;
1401 if (!num_answers) {
1402 h_errno = NO_RECOVERY;
1403 goto fail1;
1406 /* Success! */
1407 DPRINTF("Answer name = |%s|\n", a->dotted);
1408 DPRINTF("Answer type = |%d|\n", a->atype);
1409 if (fd != -1)
1410 close(fd);
1411 if (outpacket)
1412 *outpacket = packet;
1413 else
1414 free(packet);
1415 free(lookup);
1416 return packet_len;
1418 try_next_server:
1419 /* Try next nameserver */
1420 retries_left--;
1421 local_ns_num++;
1422 variant = -1;
1423 } while (retries_left > 0);
1425 fail:
1426 h_errno = NETDB_INTERNAL;
1427 fail1:
1428 if (fd != -1)
1429 close(fd);
1430 free(lookup);
1431 free(packet);
1432 return -1;
1434 #endif /* L_dnslookup */
1437 #ifdef L_read_etc_hosts_r
1439 parser_t * __open_etc_hosts(void)
1441 parser_t *parser;
1442 parser = config_open("/etc/hosts");
1443 #ifdef FALLBACK_TO_CONFIG_RESOLVCONF
1444 if (parser == NULL)
1445 parser = config_open("/etc/config/hosts");
1446 #endif
1447 return parser;
1450 #define MINTOKENS 2 /* ip address + canonical name */
1451 #define MAXTOKENS (MINTOKENS + MAXALIASES)
1452 #define HALISTOFF (sizeof(char*) * (MAXTOKENS + 1)) /* reserve space for list terminator */
1453 #define INADDROFF (HALISTOFF + 2 * sizeof(char*))
1455 int __read_etc_hosts_r(
1456 parser_t * parser,
1457 const char *name,
1458 int type,
1459 enum etc_hosts_action action,
1460 struct hostent *result_buf,
1461 char *buf, size_t buflen,
1462 struct hostent **result,
1463 int *h_errnop)
1465 char **tok = NULL;
1466 struct in_addr *h_addr0 = NULL;
1467 const size_t aliaslen = INADDROFF +
1468 #ifdef __UCLIBC_HAS_IPV6__
1469 sizeof(struct in6_addr)
1470 #else
1471 sizeof(struct in_addr)
1472 #endif
1474 int ret = HOST_NOT_FOUND;
1475 /* make sure pointer is aligned */
1476 int i = ALIGN_BUFFER_OFFSET(buf);
1477 buf += i;
1478 buflen -= i;
1480 *h_errnop = NETDB_INTERNAL;
1481 if (/* (ssize_t)buflen < 0 || */ buflen < aliaslen
1482 || (buflen - aliaslen) < BUFSZ + 1)
1483 return ERANGE;
1484 if (parser == NULL)
1485 parser = __open_etc_hosts();
1486 if (parser == NULL) {
1487 *result = NULL;
1488 return errno;
1490 /* Layout in buf:
1491 * char *alias[MAXTOKENS] = {address, name, aliases...}
1492 * char **h_addr_list[1] = {*in[6]_addr, NULL}
1493 * struct in[6]_addr
1494 * char line_buffer[BUFSZ+];
1496 parser->data = buf;
1497 parser->data_len = aliaslen;
1498 parser->line_len = buflen - aliaslen;
1499 *h_errnop = HOST_NOT_FOUND;
1500 /* <ip>[[:space:]][<aliases>] */
1501 while (config_read(parser, &tok, MAXTOKENS, MINTOKENS, "# \t", PARSE_NORMAL)) {
1502 result_buf->h_aliases = tok+1;
1503 if (action == GETHOSTENT) {
1504 /* Return whatever the next entry happens to be. */
1506 } else if (action == GET_HOSTS_BYADDR) {
1507 if (strcmp(name, *tok) != 0)
1508 continue;
1509 } else { /* GET_HOSTS_BYNAME */
1510 int aliases = 0;
1511 char **alias = tok + 1;
1512 while (aliases < MAXALIASES) {
1513 char *tmp = *(alias+aliases++);
1514 if (tmp && strcasecmp(name, tmp) == 0)
1515 goto found;
1517 continue;
1519 found:
1520 result_buf->h_name = *(result_buf->h_aliases++);
1521 result_buf->h_addr_list = (char**)(buf + HALISTOFF);
1522 *(result_buf->h_addr_list + 1) = '\0';
1523 h_addr0 = (struct in_addr*)(buf + INADDROFF);
1524 result_buf->h_addr = (char*)h_addr0;
1525 if (0) /* nothing */;
1526 #ifdef __UCLIBC_HAS_IPV4__
1527 else if (type == AF_INET
1528 && inet_pton(AF_INET, *tok, h_addr0) > 0) {
1529 DPRINTF("Found INET\n");
1530 result_buf->h_addrtype = AF_INET;
1531 result_buf->h_length = sizeof(struct in_addr);
1532 *result = result_buf;
1533 ret = NETDB_SUCCESS;
1535 #endif
1536 #ifdef __UCLIBC_HAS_IPV6__
1537 #define in6 ((struct in6_addr *)buf)
1538 else if (type == AF_INET6
1539 && inet_pton(AF_INET6, *tok, h_addr0) > 0) {
1540 DPRINTF("Found INET6\n");
1541 result_buf->h_addrtype = AF_INET6;
1542 result_buf->h_length = sizeof(struct in6_addr);
1543 *result = result_buf;
1544 ret = NETDB_SUCCESS;
1546 #endif
1547 else {
1548 /* continue parsing in the hope the user has multiple
1549 * host types listed in the database like so:
1550 * <ipv4 addr> host
1551 * <ipv6 addr> host
1552 * If looking for an IPv6 addr, don't bail when we got the IPv4
1554 DPRINTF("Error: Found host but different address family\n");
1555 /* NB: gethostbyname2_r depends on this feature
1556 * to avoid looking for IPv6 addr of "localhost" etc */
1557 ret = TRY_AGAIN;
1558 continue;
1560 break;
1562 if (action != GETHOSTENT)
1563 config_close(parser);
1564 return ret;
1565 #undef in6
1567 #endif /* L_read_etc_hosts_r */
1570 #ifdef L_get_hosts_byname_r
1572 int __get_hosts_byname_r(const char *name,
1573 int type,
1574 struct hostent *result_buf,
1575 char *buf,
1576 size_t buflen,
1577 struct hostent **result,
1578 int *h_errnop)
1580 return __read_etc_hosts_r(NULL, name, type, GET_HOSTS_BYNAME,
1581 result_buf, buf, buflen, result, h_errnop);
1583 #endif /* L_get_hosts_byname_r */
1586 #ifdef L_get_hosts_byaddr_r
1588 int __get_hosts_byaddr_r(const char *addr,
1589 int len,
1590 int type,
1591 struct hostent *result_buf,
1592 char *buf,
1593 size_t buflen,
1594 struct hostent **result,
1595 int *h_errnop)
1597 #ifndef __UCLIBC_HAS_IPV6__
1598 char ipaddr[INET_ADDRSTRLEN];
1599 #else
1600 char ipaddr[INET6_ADDRSTRLEN];
1601 #endif
1603 switch (type) {
1604 #ifdef __UCLIBC_HAS_IPV4__
1605 case AF_INET:
1606 if (len != sizeof(struct in_addr))
1607 return 0;
1608 break;
1609 #endif
1610 #ifdef __UCLIBC_HAS_IPV6__
1611 case AF_INET6:
1612 if (len != sizeof(struct in6_addr))
1613 return 0;
1614 break;
1615 #endif
1616 default:
1617 return 0;
1620 inet_ntop(type, addr, ipaddr, sizeof(ipaddr));
1622 return __read_etc_hosts_r(NULL, ipaddr, type, GET_HOSTS_BYADDR,
1623 result_buf, buf, buflen, result, h_errnop);
1625 #endif /* L_get_hosts_byaddr_r */
1628 #ifdef L_getnameinfo
1630 int getnameinfo(const struct sockaddr *sa,
1631 socklen_t addrlen,
1632 char *host,
1633 socklen_t hostlen,
1634 char *serv,
1635 socklen_t servlen,
1636 unsigned flags)
1638 int serrno = errno;
1639 bool ok = 0;
1640 struct hostent *hoste = NULL;
1641 char domain[256];
1643 if (flags & ~(NI_NUMERICHOST|NI_NUMERICSERV|NI_NOFQDN|NI_NAMEREQD|NI_DGRAM))
1644 return EAI_BADFLAGS;
1646 if (sa == NULL || addrlen < sizeof(sa_family_t))
1647 return EAI_FAMILY;
1649 if ((flags & NI_NAMEREQD) && host == NULL && serv == NULL)
1650 return EAI_NONAME;
1652 if (sa->sa_family == AF_LOCAL) /* valid */;
1653 #ifdef __UCLIBC_HAS_IPV4__
1654 else if (sa->sa_family == AF_INET) {
1655 if (addrlen < sizeof(struct sockaddr_in))
1656 return EAI_FAMILY;
1658 #endif
1659 #ifdef __UCLIBC_HAS_IPV6__
1660 else if (sa->sa_family == AF_INET6) {
1661 if (addrlen < sizeof(struct sockaddr_in6))
1662 return EAI_FAMILY;
1664 #endif
1665 else
1666 return EAI_FAMILY;
1668 if (host != NULL && hostlen > 0)
1669 switch (sa->sa_family) {
1670 case AF_INET:
1671 #ifdef __UCLIBC_HAS_IPV6__
1672 case AF_INET6:
1673 #endif
1674 if (!(flags & NI_NUMERICHOST)) {
1675 if (0) /* nothing */;
1676 #ifdef __UCLIBC_HAS_IPV6__
1677 else if (sa->sa_family == AF_INET6)
1678 hoste = gethostbyaddr((const void *)
1679 &(((const struct sockaddr_in6 *) sa)->sin6_addr),
1680 sizeof(struct in6_addr), AF_INET6);
1681 #endif
1682 #ifdef __UCLIBC_HAS_IPV4__
1683 else
1684 hoste = gethostbyaddr((const void *)
1685 &(((const struct sockaddr_in *)sa)->sin_addr),
1686 sizeof(struct in_addr), AF_INET);
1687 #endif
1689 if (hoste) {
1690 char *c;
1691 if ((flags & NI_NOFQDN)
1692 && (getdomainname(domain, sizeof(domain)) == 0)
1693 && (c = strstr(hoste->h_name, domain)) != NULL
1694 && (c != hoste->h_name) && (*(--c) == '.')
1696 strncpy(host, hoste->h_name,
1697 MIN(hostlen, (size_t) (c - hoste->h_name)));
1698 host[MIN(hostlen - 1, (size_t) (c - hoste->h_name))] = '\0';
1699 } else {
1700 strncpy(host, hoste->h_name, hostlen);
1702 ok = 1;
1706 if (!ok) {
1707 const char *c = NULL;
1709 if (flags & NI_NAMEREQD) {
1710 errno = serrno;
1711 return EAI_NONAME;
1713 if (0) /* nothing */;
1714 #ifdef __UCLIBC_HAS_IPV6__
1715 else if (sa->sa_family == AF_INET6) {
1716 const struct sockaddr_in6 *sin6p;
1718 sin6p = (const struct sockaddr_in6 *) sa;
1719 c = inet_ntop(AF_INET6,
1720 (const void *) &sin6p->sin6_addr,
1721 host, hostlen);
1722 #if 0
1723 /* Does scope id need to be supported? */
1724 uint32_t scopeid;
1725 scopeid = sin6p->sin6_scope_id;
1726 if (scopeid != 0) {
1727 /* Buffer is >= IFNAMSIZ+1. */
1728 char scopebuf[IFNAMSIZ + 1];
1729 char *scopeptr;
1730 int ni_numericscope = 0;
1731 size_t real_hostlen = strnlen(host, hostlen);
1732 size_t scopelen = 0;
1734 scopebuf[0] = SCOPE_DELIMITER;
1735 scopebuf[1] = '\0';
1736 scopeptr = &scopebuf[1];
1738 if (IN6_IS_ADDR_LINKLOCAL(&sin6p->sin6_addr)
1739 || IN6_IS_ADDR_MC_LINKLOCAL(&sin6p->sin6_addr)) {
1740 if (if_indextoname(scopeid, scopeptr) == NULL)
1741 ++ni_numericscope;
1742 else
1743 scopelen = strlen(scopebuf);
1744 } else {
1745 ++ni_numericscope;
1748 if (ni_numericscope)
1749 scopelen = 1 + snprintf(scopeptr,
1750 (scopebuf
1751 + sizeof scopebuf
1752 - scopeptr),
1753 "%u", scopeid);
1755 if (real_hostlen + scopelen + 1 > hostlen)
1756 return EAI_SYSTEM;
1757 memcpy(host + real_hostlen, scopebuf, scopelen + 1);
1759 #endif
1761 #endif /* __UCLIBC_HAS_IPV6__ */
1762 #if defined __UCLIBC_HAS_IPV4__
1763 else {
1764 c = inet_ntop(AF_INET, (const void *)
1765 &(((const struct sockaddr_in *) sa)->sin_addr),
1766 host, hostlen);
1768 #endif
1769 if (c == NULL) {
1770 errno = serrno;
1771 return EAI_SYSTEM;
1773 ok = 1;
1775 break;
1777 case AF_LOCAL:
1778 if (!(flags & NI_NUMERICHOST)) {
1779 struct utsname utsname;
1781 if (!uname(&utsname)) {
1782 strncpy(host, utsname.nodename, hostlen);
1783 break;
1787 if (flags & NI_NAMEREQD) {
1788 errno = serrno;
1789 return EAI_NONAME;
1792 strncpy(host, "localhost", hostlen);
1793 break;
1794 /* Already checked above
1795 default:
1796 return EAI_FAMILY;
1800 if (serv && (servlen > 0)) {
1801 if (sa->sa_family == AF_LOCAL) {
1802 strncpy(serv, ((const struct sockaddr_un *) sa)->sun_path, servlen);
1803 } else { /* AF_INET || AF_INET6 */
1804 if (!(flags & NI_NUMERICSERV)) {
1805 struct servent *s;
1806 s = getservbyport(((const struct sockaddr_in *) sa)->sin_port,
1807 ((flags & NI_DGRAM) ? "udp" : "tcp"));
1808 if (s) {
1809 strncpy(serv, s->s_name, servlen);
1810 goto DONE;
1813 snprintf(serv, servlen, "%d",
1814 ntohs(((const struct sockaddr_in *) sa)->sin_port));
1817 DONE:
1818 if (host && (hostlen > 0))
1819 host[hostlen-1] = 0;
1820 if (serv && (servlen > 0))
1821 serv[servlen-1] = 0;
1822 errno = serrno;
1823 return 0;
1825 libc_hidden_def(getnameinfo)
1826 #endif /* L_getnameinfo */
1829 #ifdef L_gethostbyname_r
1831 /* Bug 671 says:
1832 * "uClibc resolver's gethostbyname does not return the requested name
1833 * as an alias, but instead returns the canonical name. glibc's
1834 * gethostbyname has a similar bug where it returns the requested name
1835 * with the search domain name appended (to make a FQDN) as an alias,
1836 * but not the original name itself. Both contradict POSIX, which says
1837 * that the name argument passed to gethostbyname must be in the alias list"
1838 * This is fixed now, and we differ from glibc:
1840 * $ ./gethostbyname_uclibc wer.google.com
1841 * h_name:'c13-ss-2-lb.cnet.com'
1842 * h_length:4
1843 * h_addrtype:2 AF_INET
1844 * alias:'wer.google.com' <===
1845 * addr: 0x4174efd8 '216.239.116.65'
1847 * $ ./gethostbyname_glibc wer.google.com
1848 * h_name:'c13-ss-2-lb.cnet.com'
1849 * h_length:4
1850 * h_addrtype:2 AF_INET
1851 * alias:'wer.google.com.com' <===
1852 * addr:'216.239.116.65'
1854 * When examples were run, /etc/resolv.conf contained "search com" line.
1856 int gethostbyname_r(const char *name,
1857 struct hostent *result_buf,
1858 char *buf,
1859 size_t buflen,
1860 struct hostent **result,
1861 int *h_errnop)
1863 struct in_addr **addr_list;
1864 char **alias;
1865 char *alias0;
1866 unsigned char *packet;
1867 struct resolv_answer a;
1868 int i;
1869 int packet_len;
1870 int wrong_af = 0;
1872 *result = NULL;
1873 if (!name)
1874 return EINVAL;
1876 /* do /etc/hosts first */
1878 int old_errno = errno; /* save the old errno and reset errno */
1879 __set_errno(0); /* to check for missing /etc/hosts. */
1880 i = __get_hosts_byname_r(name, AF_INET, result_buf,
1881 buf, buflen, result, h_errnop);
1882 if (i == NETDB_SUCCESS) {
1883 __set_errno(old_errno);
1884 return i;
1886 switch (*h_errnop) {
1887 case HOST_NOT_FOUND:
1888 wrong_af = (i == TRY_AGAIN);
1889 case NO_ADDRESS:
1890 break;
1891 case NETDB_INTERNAL:
1892 if (errno == ENOENT) {
1893 break;
1895 /* else fall through */
1896 default:
1897 return i;
1899 __set_errno(old_errno);
1902 DPRINTF("Nothing found in /etc/hosts\n");
1904 *h_errnop = NETDB_INTERNAL;
1906 /* prepare future h_aliases[0] */
1907 i = strlen(name) + 1;
1908 if ((ssize_t)buflen <= i)
1909 return ERANGE;
1910 memcpy(buf, name, i); /* paranoia: name might change */
1911 alias0 = buf;
1912 buf += i;
1913 buflen -= i;
1914 /* make sure pointer is aligned */
1915 i = ALIGN_BUFFER_OFFSET(buf);
1916 buf += i;
1917 buflen -= i;
1918 /* Layout in buf:
1919 * char *alias[2];
1920 * struct in_addr* addr_list[NN+1];
1921 * struct in_addr* in[NN];
1923 alias = (char **)buf;
1924 buf += sizeof(alias[0]) * 2;
1925 buflen -= sizeof(alias[0]) * 2;
1926 addr_list = (struct in_addr **)buf;
1927 /* buflen may be < 0, must do signed compare */
1928 if ((ssize_t)buflen < 256)
1929 return ERANGE;
1931 /* we store only one "alias" - the name itself */
1932 alias[0] = alias0;
1933 alias[1] = NULL;
1935 /* maybe it is already an address? */
1937 struct in_addr *in = (struct in_addr *)(buf + sizeof(addr_list[0]) * 2);
1938 if (inet_aton(name, in)) {
1939 addr_list[0] = in;
1940 addr_list[1] = NULL;
1941 result_buf->h_name = alias0;
1942 result_buf->h_aliases = alias;
1943 result_buf->h_addrtype = AF_INET;
1944 result_buf->h_length = sizeof(struct in_addr);
1945 result_buf->h_addr_list = (char **) addr_list;
1946 *result = result_buf;
1947 *h_errnop = NETDB_SUCCESS;
1948 return NETDB_SUCCESS;
1952 /* what if /etc/hosts has it but it's not IPv4?
1953 * F.e. "::1 localhost6". We don't do DNS query for such hosts -
1954 * "ping localhost6" should be fast even if DNS server is down! */
1955 if (wrong_af) {
1956 *h_errnop = HOST_NOT_FOUND;
1957 return TRY_AGAIN;
1960 /* talk to DNS servers */
1961 a.buf = buf;
1962 /* take into account that at least one address will be there,
1963 * we'll need space for one in_addr + two addr_list[] elems */
1964 a.buflen = buflen - ((sizeof(addr_list[0]) * 2 + sizeof(struct in_addr)));
1965 a.add_count = 0;
1966 packet_len = __dns_lookup(name, T_A, &packet, &a);
1967 if (packet_len < 0) {
1968 *h_errnop = HOST_NOT_FOUND;
1969 DPRINTF("__dns_lookup returned < 0\n");
1970 return TRY_AGAIN;
1973 if (a.atype == T_A) { /* ADDRESS */
1974 /* we need space for addr_list[] and one IPv4 address */
1975 /* + 1 accounting for 1st addr (it's in a.rdata),
1976 * another + 1 for NULL in last addr_list[]: */
1977 int need_bytes = sizeof(addr_list[0]) * (a.add_count + 1 + 1)
1978 /* for 1st addr (it's in a.rdata): */
1979 + sizeof(struct in_addr);
1980 /* how many bytes will 2nd and following addresses take? */
1981 int ips_len = a.add_count * a.rdlength;
1983 buflen -= (need_bytes + ips_len);
1984 if ((ssize_t)buflen < 0) {
1985 DPRINTF("buffer too small for all addresses\n");
1986 /* *h_errnop = NETDB_INTERNAL; - already is */
1987 i = ERANGE;
1988 goto free_and_ret;
1991 /* if there are additional addresses in buf,
1992 * move them forward so that they are not destroyed */
1993 DPRINTF("a.add_count:%d a.rdlength:%d a.rdata:%p\n", a.add_count, a.rdlength, a.rdata);
1994 memmove(buf + need_bytes, buf, ips_len);
1996 /* 1st address is in a.rdata, insert it */
1997 buf += need_bytes - sizeof(struct in_addr);
1998 memcpy(buf, a.rdata, sizeof(struct in_addr));
2000 /* fill addr_list[] */
2001 for (i = 0; i <= a.add_count; i++) {
2002 addr_list[i] = (struct in_addr*)buf;
2003 buf += sizeof(struct in_addr);
2005 addr_list[i] = NULL;
2007 /* if we have enough space, we can report "better" name
2008 * (it may contain search domains attached by __dns_lookup,
2009 * or CNAME of the host if it is different from the name
2010 * we used to find it) */
2011 if (a.dotted && buflen > strlen(a.dotted)) {
2012 strcpy(buf, a.dotted);
2013 alias0 = buf;
2016 result_buf->h_name = alias0;
2017 result_buf->h_aliases = alias;
2018 result_buf->h_addrtype = AF_INET;
2019 result_buf->h_length = sizeof(struct in_addr);
2020 result_buf->h_addr_list = (char **) addr_list;
2021 *result = result_buf;
2022 *h_errnop = NETDB_SUCCESS;
2023 i = NETDB_SUCCESS;
2024 goto free_and_ret;
2027 *h_errnop = HOST_NOT_FOUND;
2028 __set_h_errno(HOST_NOT_FOUND);
2029 i = TRY_AGAIN;
2031 free_and_ret:
2032 free(a.dotted);
2033 free(packet);
2034 return i;
2036 libc_hidden_def(gethostbyname_r)
2037 #endif /* L_gethostbyname_r */
2040 #ifdef L_gethostbyname2_r
2042 int gethostbyname2_r(const char *name,
2043 int family,
2044 struct hostent *result_buf,
2045 char *buf,
2046 size_t buflen,
2047 struct hostent **result,
2048 int *h_errnop)
2050 #ifndef __UCLIBC_HAS_IPV6__
2051 return family == (AF_INET)
2052 ? gethostbyname_r(name, result_buf, buf, buflen, result, h_errnop)
2053 : HOST_NOT_FOUND;
2054 #else
2055 struct in6_addr **addr_list;
2056 char **alias;
2057 char *alias0;
2058 unsigned char *packet;
2059 struct resolv_answer a;
2060 int i;
2061 int packet_len;
2062 int wrong_af = 0;
2064 if (family == AF_INET)
2065 return gethostbyname_r(name, result_buf, buf, buflen, result, h_errnop);
2067 *result = NULL;
2068 if (family != AF_INET6)
2069 return EINVAL;
2071 if (!name)
2072 return EINVAL;
2074 /* do /etc/hosts first */
2076 int old_errno = errno; /* save the old errno and reset errno */
2077 __set_errno(0); /* to check for missing /etc/hosts. */
2078 i = __get_hosts_byname_r(name, AF_INET6 /*family*/, result_buf,
2079 buf, buflen, result, h_errnop);
2080 if (i == NETDB_SUCCESS) {
2081 __set_errno(old_errno);
2082 return i;
2084 switch (*h_errnop) {
2085 case HOST_NOT_FOUND:
2086 wrong_af = (i == TRY_AGAIN);
2087 case NO_ADDRESS:
2088 break;
2089 case NETDB_INTERNAL:
2090 if (errno == ENOENT) {
2091 break;
2093 /* else fall through */
2094 default:
2095 return i;
2097 __set_errno(old_errno);
2100 DPRINTF("Nothing found in /etc/hosts\n");
2102 *h_errnop = NETDB_INTERNAL;
2104 /* prepare future h_aliases[0] */
2105 i = strlen(name) + 1;
2106 if ((ssize_t)buflen <= i)
2107 return ERANGE;
2108 memcpy(buf, name, i); /* paranoia: name might change */
2109 alias0 = buf;
2110 buf += i;
2111 buflen -= i;
2112 /* make sure pointer is aligned */
2113 i = ALIGN_BUFFER_OFFSET(buf);
2114 buf += i;
2115 buflen -= i;
2116 /* Layout in buf:
2117 * char *alias[2];
2118 * struct in6_addr* addr_list[NN+1];
2119 * struct in6_addr* in[NN];
2121 alias = (char **)buf;
2122 buf += sizeof(alias[0]) * 2;
2123 buflen -= sizeof(alias[0]) * 2;
2124 addr_list = (struct in6_addr **)buf;
2125 /* buflen may be < 0, must do signed compare */
2126 if ((ssize_t)buflen < 256)
2127 return ERANGE;
2129 /* we store only one "alias" - the name itself */
2130 alias[0] = alias0;
2131 alias[1] = NULL;
2133 /* maybe it is already an address? */
2135 struct in6_addr *in = (struct in6_addr *)(buf + sizeof(addr_list[0]) * 2);
2136 if (inet_pton(AF_INET6, name, in)) {
2137 addr_list[0] = in;
2138 addr_list[1] = NULL;
2139 result_buf->h_name = alias0;
2140 result_buf->h_aliases = alias;
2141 result_buf->h_addrtype = AF_INET6;
2142 result_buf->h_length = sizeof(struct in6_addr);
2143 result_buf->h_addr_list = (char **) addr_list;
2144 *result = result_buf;
2145 *h_errnop = NETDB_SUCCESS;
2146 return NETDB_SUCCESS;
2150 /* what if /etc/hosts has it but it's not IPv6?
2151 * F.e. "127.0.0.1 localhost". We don't do DNS query for such hosts -
2152 * "ping localhost" should be fast even if DNS server is down! */
2153 if (wrong_af) {
2154 *h_errnop = HOST_NOT_FOUND;
2155 return TRY_AGAIN;
2158 /* talk to DNS servers */
2159 a.buf = buf;
2160 /* take into account that at least one address will be there,
2161 * we'll need space of one in6_addr + two addr_list[] elems */
2162 a.buflen = buflen - ((sizeof(addr_list[0]) * 2 + sizeof(struct in6_addr)));
2163 a.add_count = 0;
2164 packet_len = __dns_lookup(name, T_AAAA, &packet, &a);
2165 if (packet_len < 0) {
2166 *h_errnop = HOST_NOT_FOUND;
2167 DPRINTF("__dns_lookup returned < 0\n");
2168 return TRY_AGAIN;
2171 if (a.atype == T_AAAA) { /* ADDRESS */
2172 /* we need space for addr_list[] and one IPv6 address */
2173 /* + 1 accounting for 1st addr (it's in a.rdata),
2174 * another + 1 for NULL in last addr_list[]: */
2175 int need_bytes = sizeof(addr_list[0]) * (a.add_count + 1 + 1)
2176 /* for 1st addr (it's in a.rdata): */
2177 + sizeof(struct in6_addr);
2178 /* how many bytes will 2nd and following addresses take? */
2179 int ips_len = a.add_count * a.rdlength;
2181 buflen -= (need_bytes + ips_len);
2182 if ((ssize_t)buflen < 0) {
2183 DPRINTF("buffer too small for all addresses\n");
2184 /* *h_errnop = NETDB_INTERNAL; - already is */
2185 i = ERANGE;
2186 goto free_and_ret;
2189 /* if there are additional addresses in buf,
2190 * move them forward so that they are not destroyed */
2191 DPRINTF("a.add_count:%d a.rdlength:%d a.rdata:%p\n", a.add_count, a.rdlength, a.rdata);
2192 memmove(buf + need_bytes, buf, ips_len);
2194 /* 1st address is in a.rdata, insert it */
2195 buf += need_bytes - sizeof(struct in6_addr);
2196 memcpy(buf, a.rdata, sizeof(struct in6_addr));
2198 /* fill addr_list[] */
2199 for (i = 0; i <= a.add_count; i++) {
2200 addr_list[i] = (struct in6_addr*)buf;
2201 buf += sizeof(struct in6_addr);
2203 addr_list[i] = NULL;
2205 /* if we have enough space, we can report "better" name
2206 * (it may contain search domains attached by __dns_lookup,
2207 * or CNAME of the host if it is different from the name
2208 * we used to find it) */
2209 if (a.dotted && buflen > strlen(a.dotted)) {
2210 strcpy(buf, a.dotted);
2211 alias0 = buf;
2214 result_buf->h_name = alias0;
2215 result_buf->h_aliases = alias;
2216 result_buf->h_addrtype = AF_INET6;
2217 result_buf->h_length = sizeof(struct in6_addr);
2218 result_buf->h_addr_list = (char **) addr_list;
2219 *result = result_buf;
2220 *h_errnop = NETDB_SUCCESS;
2221 i = NETDB_SUCCESS;
2222 goto free_and_ret;
2225 *h_errnop = HOST_NOT_FOUND;
2226 __set_h_errno(HOST_NOT_FOUND);
2227 i = TRY_AGAIN;
2229 free_and_ret:
2230 free(a.dotted);
2231 free(packet);
2232 return i;
2233 #endif /* __UCLIBC_HAS_IPV6__ */
2235 libc_hidden_def(gethostbyname2_r)
2236 #endif /* L_gethostbyname2_r */
2239 #ifdef L_gethostbyaddr_r
2241 int gethostbyaddr_r(const void *addr, socklen_t addrlen,
2242 int type,
2243 struct hostent *result_buf,
2244 char *buf, size_t buflen,
2245 struct hostent **result,
2246 int *h_errnop)
2249 struct in_addr *in;
2250 struct in_addr **addr_list;
2251 char **alias;
2252 unsigned char *packet;
2253 struct resolv_answer a;
2254 int i;
2255 int packet_len;
2256 int nest = 0;
2258 *result = NULL;
2259 if (!addr)
2260 return EINVAL;
2262 switch (type) {
2263 #ifdef __UCLIBC_HAS_IPV4__
2264 case AF_INET:
2265 if (addrlen != sizeof(struct in_addr))
2266 return EINVAL;
2267 break;
2268 #endif
2269 #ifdef __UCLIBC_HAS_IPV6__
2270 case AF_INET6:
2271 if (addrlen != sizeof(struct in6_addr))
2272 return EINVAL;
2273 break;
2274 #endif
2275 default:
2276 return EINVAL;
2279 /* do /etc/hosts first */
2280 i = __get_hosts_byaddr_r(addr, addrlen, type, result_buf,
2281 buf, buflen, result, h_errnop);
2282 if (i == 0)
2283 return i;
2284 switch (*h_errnop) {
2285 case HOST_NOT_FOUND:
2286 case NO_ADDRESS:
2287 break;
2288 default:
2289 return i;
2292 *h_errnop = NETDB_INTERNAL;
2294 /* make sure pointer is aligned */
2295 i = ALIGN_BUFFER_OFFSET(buf);
2296 buf += i;
2297 buflen -= i;
2298 /* Layout in buf:
2299 * char *alias[ALIAS_DIM];
2300 * struct in[6]_addr* addr_list[2];
2301 * struct in[6]_addr in;
2302 * char scratch_buffer[256+];
2304 #define in6 ((struct in6_addr *)in)
2305 alias = (char **)buf;
2306 addr_list = (struct in_addr**)buf;
2307 buf += sizeof(*addr_list) * 2;
2308 buflen -= sizeof(*addr_list) * 2;
2309 in = (struct in_addr*)buf;
2310 #ifndef __UCLIBC_HAS_IPV6__
2311 buf += sizeof(*in);
2312 buflen -= sizeof(*in);
2313 if (addrlen > sizeof(*in))
2314 return ERANGE;
2315 #else
2316 buf += sizeof(*in6);
2317 buflen -= sizeof(*in6);
2318 if (addrlen > sizeof(*in6))
2319 return ERANGE;
2320 #endif
2321 if ((ssize_t)buflen < 256)
2322 return ERANGE;
2323 alias[0] = buf;
2324 alias[1] = NULL;
2325 addr_list[0] = in;
2326 addr_list[1] = NULL;
2327 memcpy(in, addr, addrlen);
2329 if (0) /* nothing */;
2330 #ifdef __UCLIBC_HAS_IPV4__
2331 else IF_HAS_BOTH(if (type == AF_INET)) {
2332 unsigned char *tp = (unsigned char *)addr;
2333 sprintf(buf, "%u.%u.%u.%u.in-addr.arpa",
2334 tp[3], tp[2], tp[1], tp[0]);
2336 #endif
2337 #ifdef __UCLIBC_HAS_IPV6__
2338 else {
2339 char *dst = buf;
2340 unsigned char *tp = (unsigned char *)addr + addrlen - 1;
2341 do {
2342 dst += sprintf(dst, "%x.%x.", tp[0] & 0xf, tp[0] >> 4);
2343 tp--;
2344 } while (tp >= (unsigned char *)addr);
2345 strcpy(dst, "ip6.arpa");
2347 #endif
2349 memset(&a, '\0', sizeof(a));
2350 for (;;) {
2351 /* Hmm why we memset(a) to zeros only once? */
2352 packet_len = __dns_lookup(buf, T_PTR, &packet, &a);
2353 if (packet_len < 0) {
2354 *h_errnop = HOST_NOT_FOUND;
2355 return TRY_AGAIN;
2358 strncpy(buf, a.dotted, buflen);
2359 free(a.dotted);
2360 if (a.atype != T_CNAME)
2361 break;
2363 DPRINTF("Got a CNAME in gethostbyaddr()\n");
2364 if (++nest > MAX_RECURSE) {
2365 *h_errnop = NO_RECOVERY;
2366 return -1;
2368 /* Decode CNAME into buf, feed it to __dns_lookup() again */
2369 i = __decode_dotted(packet, a.rdoffset, packet_len, buf, buflen);
2370 free(packet);
2371 if (i < 0 || __hnbad(buf)) {
2372 *h_errnop = NO_RECOVERY;
2373 return -1;
2377 if (a.atype == T_PTR) { /* ADDRESS */
2378 i = __decode_dotted(packet, a.rdoffset, packet_len, buf, buflen);
2379 free(packet);
2380 if (__hnbad(buf)) {
2381 *h_errnop = NO_RECOVERY;
2382 return -1;
2384 result_buf->h_name = buf;
2385 result_buf->h_addrtype = type;
2386 result_buf->h_length = addrlen;
2387 result_buf->h_addr_list = (char **) addr_list;
2388 result_buf->h_aliases = alias;
2389 *result = result_buf;
2390 *h_errnop = NETDB_SUCCESS;
2391 return NETDB_SUCCESS;
2394 free(packet);
2395 *h_errnop = NO_ADDRESS;
2396 return TRY_AGAIN;
2397 #undef in6
2399 libc_hidden_def(gethostbyaddr_r)
2400 #endif /* L_gethostbyaddr_r */
2403 #ifdef L_gethostent_r
2405 __UCLIBC_MUTEX_STATIC(mylock, PTHREAD_MUTEX_INITIALIZER);
2407 static parser_t *hostp = NULL;
2408 static smallint host_stayopen;
2410 void endhostent_unlocked(void)
2412 if (hostp) {
2413 config_close(hostp);
2414 hostp = NULL;
2416 host_stayopen = 0;
2418 void endhostent(void)
2420 __UCLIBC_MUTEX_LOCK(mylock);
2421 endhostent_unlocked();
2422 __UCLIBC_MUTEX_UNLOCK(mylock);
2425 void sethostent(int stay_open)
2427 __UCLIBC_MUTEX_LOCK(mylock);
2428 if (stay_open)
2429 host_stayopen = 1;
2430 __UCLIBC_MUTEX_UNLOCK(mylock);
2433 int gethostent_r(struct hostent *result_buf, char *buf, size_t buflen,
2434 struct hostent **result, int *h_errnop)
2436 int ret;
2438 __UCLIBC_MUTEX_LOCK(mylock);
2439 if (hostp == NULL) {
2440 hostp = __open_etc_hosts();
2441 if (hostp == NULL) {
2442 *result = NULL;
2443 ret = TRY_AGAIN;
2444 goto DONE;
2448 ret = __read_etc_hosts_r(hostp, NULL, AF_INET, GETHOSTENT,
2449 result_buf, buf, buflen, result, h_errnop);
2450 if (!host_stayopen)
2451 endhostent_unlocked();
2452 DONE:
2453 __UCLIBC_MUTEX_UNLOCK(mylock);
2454 return ret;
2456 libc_hidden_def(gethostent_r)
2457 #endif /* L_gethostent_r */
2460 #ifndef __UCLIBC_HAS_IPV6__
2461 #define GETXX_BUFSZ (sizeof(struct in_addr) + sizeof(struct in_addr *) * 2 + \
2462 /*sizeof(char *)*ALIAS_DIM */+ 384/*namebuffer*/ + 32/* margin */)
2463 #else
2464 #define GETXX_BUFSZ (sizeof(struct in6_addr) + sizeof(struct in6_addr *) * 2 + \
2465 /*sizeof(char *)*ALIAS_DIM */+ 384/*namebuffer*/ + 32/* margin */)
2466 #endif /* __UCLIBC_HAS_IPV6__ */
2468 #define __INIT_GETXX_BUF(sz) \
2469 if (buf == NULL) \
2470 buf = (char *)__uc_malloc((sz));
2472 #ifdef L_gethostent
2474 struct hostent *gethostent(void)
2476 static struct hostent hoste;
2477 static char *buf = NULL;
2478 struct hostent *host = NULL;
2479 #ifndef __UCLIBC_HAS_IPV6__
2480 #define HOSTENT_BUFSZ (sizeof(struct in_addr) + sizeof(struct in_addr *) * 2 + \
2481 sizeof(char *)*ALIAS_DIM + BUFSZ /*namebuffer*/ + 2 /* margin */)
2482 #else
2483 #define HOSTENT_BUFSZ (sizeof(struct in6_addr) + sizeof(struct in6_addr *) * 2 + \
2484 sizeof(char *)*ALIAS_DIM + BUFSZ /*namebuffer*/ + 2 /* margin */)
2485 #endif /* __UCLIBC_HAS_IPV6__ */
2487 __INIT_GETXX_BUF(HOSTENT_BUFSZ);
2488 gethostent_r(&hoste, buf, HOSTENT_BUFSZ, &host, &h_errno);
2489 return host;
2491 #undef HOSTENT_BUFSZ
2492 #endif /* L_gethostent */
2495 #ifdef L_gethostbyname2
2497 struct hostent *gethostbyname2(const char *name, int family)
2499 static struct hostent hoste;
2500 static char *buf = NULL;
2501 struct hostent *hp;
2503 __INIT_GETXX_BUF(GETXX_BUFSZ);
2504 #ifndef __UCLIBC_HAS_IPV6__
2505 if (family != AF_INET)
2506 return (struct hostent*)NULL;
2507 gethostbyname_r(name, &hoste, buf, GETXX_BUFSZ, &hp, &h_errno);
2508 #else
2509 gethostbyname2_r(name, family, &hoste, buf, GETXX_BUFSZ, &hp, &h_errno);
2510 #endif /* __UCLIBC_HAS_IPV6__ */
2512 return hp;
2514 libc_hidden_def(gethostbyname2)
2515 #endif /* L_gethostbyname2 */
2518 #ifdef L_gethostbyname
2520 struct hostent *gethostbyname(const char *name)
2522 return gethostbyname2(name, AF_INET);
2524 libc_hidden_def(gethostbyname)
2525 #endif /* L_gethostbyname */
2528 #ifdef L_gethostbyaddr
2530 struct hostent *gethostbyaddr(const void *addr, socklen_t len, int type)
2532 static struct hostent hoste;
2533 static char *buf = NULL;
2534 struct hostent *hp;
2536 __INIT_GETXX_BUF(GETXX_BUFSZ);
2537 gethostbyaddr_r(addr, len, type, &hoste, buf, GETXX_BUFSZ, &hp, &h_errno);
2538 return hp;
2540 libc_hidden_def(gethostbyaddr)
2541 #endif /* L_gethostbyaddr */
2544 #ifdef L_res_comp
2547 * Expand compressed domain name 'comp_dn' to full domain name.
2548 * 'msg' is a pointer to the begining of the message,
2549 * 'eomorig' points to the first location after the message,
2550 * 'exp_dn' is a pointer to a buffer of size 'length' for the result.
2551 * Return size of compressed name or -1 if there was an error.
2553 int dn_expand(const u_char *msg, const u_char *eom, const u_char *src,
2554 char *dst, int dstsiz)
2556 int n = ns_name_uncompress(msg, eom, src, dst, (size_t)dstsiz);
2558 if (n > 0 && dst[0] == '.')
2559 dst[0] = '\0';
2560 return n;
2562 libc_hidden_def(dn_expand)
2565 * Pack domain name 'exp_dn' in presentation form into 'comp_dn'.
2566 * Return the size of the compressed name or -1.
2567 * 'length' is the size of the array pointed to by 'comp_dn'.
2570 dn_comp(const char *src, u_char *dst, int dstsiz,
2571 u_char **dnptrs, u_char **lastdnptr)
2573 return ns_name_compress(src, dst, (size_t) dstsiz,
2574 (const u_char **) dnptrs,
2575 (const u_char **) lastdnptr);
2577 libc_hidden_def(dn_comp)
2578 #endif /* L_res_comp */
2581 #ifdef L_ns_name
2583 /* Thinking in noninternationalized USASCII (per the DNS spec),
2584 * is this character visible and not a space when printed ?
2586 static int printable(int ch)
2588 return (ch > 0x20 && ch < 0x7f);
2590 /* Thinking in noninternationalized USASCII (per the DNS spec),
2591 * is this characted special ("in need of quoting") ?
2593 static int special(int ch)
2595 switch (ch) {
2596 case 0x22: /* '"' */
2597 case 0x2E: /* '.' */
2598 case 0x3B: /* ';' */
2599 case 0x5C: /* '\\' */
2600 /* Special modifiers in zone files. */
2601 case 0x40: /* '@' */
2602 case 0x24: /* '$' */
2603 return 1;
2604 default:
2605 return 0;
2610 * ns_name_uncompress(msg, eom, src, dst, dstsiz)
2611 * Expand compressed domain name to presentation format.
2612 * return:
2613 * Number of bytes read out of `src', or -1 (with errno set).
2614 * note:
2615 * Root domain returns as "." not "".
2617 int ns_name_uncompress(const u_char *msg, const u_char *eom,
2618 const u_char *src, char *dst, size_t dstsiz)
2620 u_char tmp[NS_MAXCDNAME];
2621 int n;
2623 n = ns_name_unpack(msg, eom, src, tmp, sizeof tmp);
2624 if (n == -1)
2625 return -1;
2626 if (ns_name_ntop(tmp, dst, dstsiz) == -1)
2627 return -1;
2628 return n;
2630 libc_hidden_def(ns_name_uncompress)
2633 * ns_name_ntop(src, dst, dstsiz)
2634 * Convert an encoded domain name to printable ascii as per RFC1035.
2635 * return:
2636 * Number of bytes written to buffer, or -1 (with errno set)
2637 * notes:
2638 * The root is returned as "."
2639 * All other domains are returned in non absolute form
2641 int ns_name_ntop(const u_char *src, char *dst, size_t dstsiz)
2643 const u_char *cp;
2644 char *dn, *eom;
2645 u_char c;
2646 u_int n;
2648 cp = src;
2649 dn = dst;
2650 eom = dst + dstsiz;
2652 while ((n = *cp++) != 0) {
2653 if ((n & NS_CMPRSFLGS) != 0) {
2654 /* Some kind of compression pointer. */
2655 __set_errno(EMSGSIZE);
2656 return -1;
2658 if (dn != dst) {
2659 if (dn >= eom) {
2660 __set_errno(EMSGSIZE);
2661 return -1;
2663 *dn++ = '.';
2665 if (dn + n >= eom) {
2666 __set_errno(EMSGSIZE);
2667 return -1;
2669 for (; n > 0; n--) {
2670 c = *cp++;
2671 if (special(c)) {
2672 if (dn + 1 >= eom) {
2673 __set_errno(EMSGSIZE);
2674 return -1;
2676 *dn++ = '\\';
2677 *dn++ = (char)c;
2678 } else if (!printable(c)) {
2679 if (dn + 3 >= eom) {
2680 __set_errno(EMSGSIZE);
2681 return -1;
2683 *dn++ = '\\';
2684 *dn++ = "0123456789"[c / 100];
2685 c = c % 100;
2686 *dn++ = "0123456789"[c / 10];
2687 *dn++ = "0123456789"[c % 10];
2688 } else {
2689 if (dn >= eom) {
2690 __set_errno(EMSGSIZE);
2691 return -1;
2693 *dn++ = (char)c;
2697 if (dn == dst) {
2698 if (dn >= eom) {
2699 __set_errno(EMSGSIZE);
2700 return -1;
2702 *dn++ = '.';
2704 if (dn >= eom) {
2705 __set_errno(EMSGSIZE);
2706 return -1;
2708 *dn++ = '\0';
2709 return (dn - dst);
2711 libc_hidden_def(ns_name_ntop)
2713 static int encode_bitstring(const char **bp, const char *end,
2714 unsigned char **labelp,
2715 unsigned char ** dst,
2716 unsigned const char *eom)
2718 int afterslash = 0;
2719 const char *cp = *bp;
2720 unsigned char *tp;
2721 const char *beg_blen;
2722 int value = 0, count = 0, tbcount = 0, blen = 0;
2724 beg_blen = NULL;
2726 /* a bitstring must contain at least 2 characters */
2727 if (end - cp < 2)
2728 return EINVAL;
2730 /* XXX: currently, only hex strings are supported */
2731 if (*cp++ != 'x')
2732 return EINVAL;
2733 if (!isxdigit((unsigned char) *cp)) /*%< reject '\[x/BLEN]' */
2734 return EINVAL;
2736 for (tp = *dst + 1; cp < end && tp < eom; cp++) {
2737 unsigned char c = *cp;
2739 switch (c) {
2740 case ']': /*%< end of the bitstring */
2741 if (afterslash) {
2742 char *end_blen;
2743 if (beg_blen == NULL)
2744 return EINVAL;
2745 blen = (int)strtol(beg_blen, &end_blen, 10);
2746 if (*end_blen != ']')
2747 return EINVAL;
2749 if (count)
2750 *tp++ = ((value << 4) & 0xff);
2751 cp++; /*%< skip ']' */
2752 goto done;
2753 case '/':
2754 afterslash = 1;
2755 break;
2756 default:
2757 if (afterslash) {
2758 if (!__isdigit_char(c))
2759 return EINVAL;
2760 if (beg_blen == NULL) {
2761 if (c == '0') {
2762 /* blen never begings with 0 */
2763 return EINVAL;
2765 beg_blen = cp;
2767 } else {
2768 if (!__isdigit_char(c)) {
2769 c = c | 0x20; /* lowercase */
2770 c = c - 'a';
2771 if (c > 5) /* not a-f? */
2772 return EINVAL;
2773 c += 10 + '0';
2775 value <<= 4;
2776 value += (c - '0');
2777 count += 4;
2778 tbcount += 4;
2779 if (tbcount > 256)
2780 return EINVAL;
2781 if (count == 8) {
2782 *tp++ = value;
2783 count = 0;
2786 break;
2789 done:
2790 if (cp >= end || tp >= eom)
2791 return EMSGSIZE;
2794 * bit length validation:
2795 * If a <length> is present, the number of digits in the <bit-data>
2796 * MUST be just sufficient to contain the number of bits specified
2797 * by the <length>. If there are insignificant bits in a final
2798 * hexadecimal or octal digit, they MUST be zero.
2799 * RFC2673, Section 3.2.
2801 if (blen > 0) {
2802 int traillen;
2804 if (((blen + 3) & ~3) != tbcount)
2805 return EINVAL;
2806 traillen = tbcount - blen; /*%< between 0 and 3 */
2807 if (((value << (8 - traillen)) & 0xff) != 0)
2808 return EINVAL;
2810 else
2811 blen = tbcount;
2812 if (blen == 256)
2813 blen = 0;
2815 /* encode the type and the significant bit fields */
2816 **labelp = DNS_LABELTYPE_BITSTRING;
2817 **dst = blen;
2819 *bp = cp;
2820 *dst = tp;
2822 return 0;
2825 int ns_name_pton(const char *src, u_char *dst, size_t dstsiz)
2827 static const char digits[] = "0123456789";
2828 u_char *label, *bp, *eom;
2829 int c, n, escaped, e = 0;
2830 char *cp;
2832 escaped = 0;
2833 bp = dst;
2834 eom = dst + dstsiz;
2835 label = bp++;
2837 while ((c = *src++) != 0) {
2838 if (escaped) {
2839 if (c == '[') { /*%< start a bit string label */
2840 cp = strchr(src, ']');
2841 if (cp == NULL) {
2842 errno = EINVAL; /*%< ??? */
2843 return -1;
2845 e = encode_bitstring(&src, cp + 2,
2846 &label, &bp, eom);
2847 if (e != 0) {
2848 errno = e;
2849 return -1;
2851 escaped = 0;
2852 label = bp++;
2853 c = *src++;
2854 if (c == '\0')
2855 goto done;
2856 if (c != '.') {
2857 errno = EINVAL;
2858 return -1;
2860 continue;
2862 cp = strchr(digits, c);
2863 if (cp != NULL) {
2864 n = (cp - digits) * 100;
2865 c = *src++;
2866 if (c == '\0')
2867 goto ret_EMSGSIZE;
2868 cp = strchr(digits, c);
2869 if (cp == NULL)
2870 goto ret_EMSGSIZE;
2871 n += (cp - digits) * 10;
2872 c = *src++;
2873 if (c == '\0')
2874 goto ret_EMSGSIZE;
2875 cp = strchr(digits, c);
2876 if (cp == NULL)
2877 goto ret_EMSGSIZE;
2878 n += (cp - digits);
2879 if (n > 255)
2880 goto ret_EMSGSIZE;
2881 c = n;
2883 escaped = 0;
2884 } else if (c == '\\') {
2885 escaped = 1;
2886 continue;
2887 } else if (c == '.') {
2888 c = (bp - label - 1);
2889 if ((c & NS_CMPRSFLGS) != 0) { /*%< Label too big. */
2890 goto ret_EMSGSIZE;
2892 if (label >= eom) {
2893 goto ret_EMSGSIZE;
2895 *label = c;
2896 /* Fully qualified ? */
2897 if (*src == '\0') {
2898 if (c != 0) {
2899 if (bp >= eom) {
2900 goto ret_EMSGSIZE;
2902 *bp++ = '\0';
2904 if ((bp - dst) > MAXCDNAME) {
2905 goto ret_EMSGSIZE;
2908 return 1;
2910 if (c == 0 || *src == '.') {
2911 goto ret_EMSGSIZE;
2913 label = bp++;
2914 continue;
2916 if (bp >= eom) {
2917 goto ret_EMSGSIZE;
2919 *bp++ = (u_char)c;
2921 c = (bp - label - 1);
2922 if ((c & NS_CMPRSFLGS) != 0) { /*%< Label too big. */
2923 goto ret_EMSGSIZE;
2925 done:
2926 if (label >= eom) {
2927 goto ret_EMSGSIZE;
2929 *label = c;
2930 if (c != 0) {
2931 if (bp >= eom) {
2932 goto ret_EMSGSIZE;
2934 *bp++ = 0;
2936 if ((bp - dst) > MAXCDNAME) { /*%< src too big */
2937 goto ret_EMSGSIZE;
2940 return 0;
2942 ret_EMSGSIZE:
2943 errno = EMSGSIZE;
2944 return -1;
2946 libc_hidden_def(ns_name_pton)
2949 * __hnbad(dotted)
2950 * Check whether a name is valid enough for DNS. The rules, as
2951 * laid down by glibc, are:
2952 * - printable input string
2953 * - converts to label notation
2954 * - each label only contains [0-9a-zA-Z_-], up to 63 octets
2955 * - first label doesn’t begin with ‘-’
2956 * This both is weaker than Unix hostnames (e.g. it allows
2957 * underscores and leading/trailing hyphen-minus) and stronger
2958 * than general (e.g. a leading “*.” is valid sometimes), take care.
2959 * return:
2960 * 0 if the name is ok
2962 int __hnbad(const char *dotted)
2964 unsigned char c, n, *cp;
2965 unsigned char buf[NS_MAXCDNAME];
2967 cp = (unsigned char *)dotted;
2968 while ((c = *cp++))
2969 if (c < 0x21 || c > 0x7E)
2970 return (1);
2971 if (ns_name_pton(dotted, buf, sizeof(buf)) < 0)
2972 return (2);
2973 if (buf[0] > 0 && buf[1] == '-')
2974 return (3);
2975 cp = buf;
2976 while ((n = *cp++)) {
2977 if (n > 63)
2978 return (4);
2979 while (n--) {
2980 c = *cp++;
2981 if (c < '-' ||
2982 (c > '-' && c < '0') ||
2983 (c > '9' && c < 'A') ||
2984 (c > 'Z' && c < '_') ||
2985 (c > '_' && c < 'a') ||
2986 c > 'z')
2987 return (5);
2990 return (0);
2994 * ns_name_unpack(msg, eom, src, dst, dstsiz)
2995 * Unpack a domain name from a message, source may be compressed.
2996 * return:
2997 * -1 if it fails, or consumed octets if it succeeds.
2999 int ns_name_unpack(const u_char *msg, const u_char *eom, const u_char *src,
3000 u_char *dst, size_t dstsiz)
3002 const u_char *srcp, *dstlim;
3003 u_char *dstp;
3004 int n, len, checked;
3006 len = -1;
3007 checked = 0;
3008 dstp = dst;
3009 srcp = src;
3010 dstlim = dst + dstsiz;
3011 if (srcp < msg || srcp >= eom) {
3012 __set_errno(EMSGSIZE);
3013 return -1;
3015 /* Fetch next label in domain name. */
3016 while ((n = *srcp++) != 0) {
3017 /* Check for indirection. */
3018 switch (n & NS_CMPRSFLGS) {
3019 case 0:
3020 /* Limit checks. */
3021 if (dstp + n + 1 >= dstlim || srcp + n >= eom) {
3022 __set_errno(EMSGSIZE);
3023 return -1;
3025 checked += n + 1;
3026 *dstp++ = n;
3027 memcpy(dstp, srcp, n);
3028 dstp += n;
3029 srcp += n;
3030 break;
3032 case NS_CMPRSFLGS:
3033 if (srcp >= eom) {
3034 __set_errno(EMSGSIZE);
3035 return -1;
3037 if (len < 0)
3038 len = srcp - src + 1;
3039 srcp = msg + (((n & 0x3f) << 8) | (*srcp & 0xff));
3040 if (srcp < msg || srcp >= eom) { /* Out of range. */
3041 __set_errno(EMSGSIZE);
3042 return -1;
3044 checked += 2;
3046 * Check for loops in the compressed name;
3047 * if we've looked at the whole message,
3048 * there must be a loop.
3050 if (checked >= eom - msg) {
3051 __set_errno(EMSGSIZE);
3052 return -1;
3054 break;
3056 default:
3057 __set_errno(EMSGSIZE);
3058 return -1; /* flag error */
3061 *dstp = '\0';
3062 if (len < 0)
3063 len = srcp - src;
3064 return len;
3066 libc_hidden_def(ns_name_unpack)
3068 static int labellen(const unsigned char *lp)
3070 unsigned bitlen;
3071 unsigned char l = *lp;
3073 if ((l & NS_CMPRSFLGS) == NS_CMPRSFLGS) {
3074 /* should be avoided by the caller */
3075 return -1;
3078 if ((l & NS_CMPRSFLGS) == NS_TYPE_ELT) {
3079 if (l == DNS_LABELTYPE_BITSTRING) {
3080 bitlen = lp[1];
3081 if (bitlen == 0)
3082 bitlen = 256;
3083 return ((bitlen + 7 ) / 8 + 1);
3086 return -1; /*%< unknwon ELT */
3089 return l;
3092 static int mklower(int ch)
3094 if (ch >= 0x41 && ch <= 0x5A)
3095 return (ch + 0x20);
3097 return ch;
3100 static int dn_find(const unsigned char *domain,
3101 const unsigned char *msg,
3102 const unsigned char * const *dnptrs,
3103 const unsigned char * const *lastdnptr)
3105 const unsigned char *dn, *cp, *sp;
3106 const unsigned char * const *cpp;
3107 u_int n;
3109 for (cpp = dnptrs; cpp < lastdnptr; cpp++) {
3110 sp = *cpp;
3112 * terminate search on:
3113 * root label
3114 * compression pointer
3115 * unusable offset
3117 while (*sp != 0 && (*sp & NS_CMPRSFLGS) == 0 &&
3118 (sp - msg) < 0x4000) {
3119 dn = domain;
3120 cp = sp;
3122 while ((n = *cp++) != 0) {
3124 * check for indirection
3126 switch (n & NS_CMPRSFLGS) {
3127 case 0: /*%< normal case, n == len */
3128 n = labellen(cp - 1); /*%< XXX */
3129 if (n != *dn++)
3130 goto next;
3132 for (; n > 0; n--)
3133 if (mklower(*dn++) !=
3134 mklower(*cp++))
3135 goto next;
3136 /* Is next root for both ? */
3137 if (*dn == '\0' && *cp == '\0')
3138 return (sp - msg);
3139 if (*dn)
3140 continue;
3141 goto next;
3142 case NS_CMPRSFLGS: /*%< indirection */
3143 cp = msg + (((n & 0x3f) << 8) | *cp);
3144 break;
3146 default: /*%< illegal type */
3147 errno = EMSGSIZE;
3148 return -1;
3151 next:
3152 sp += *sp + 1;
3156 errno = ENOENT;
3157 return -1;
3160 int ns_name_pack(const unsigned char *src,
3161 unsigned char *dst, int dstsiz,
3162 const unsigned char **dnptrs,
3163 const unsigned char **lastdnptr)
3165 unsigned char *dstp;
3166 const unsigned char **cpp, **lpp, *eob, *msg;
3167 const unsigned char *srcp;
3168 int n, l, first = 1;
3170 srcp = src;
3171 dstp = dst;
3172 eob = dstp + dstsiz;
3173 lpp = cpp = NULL;
3175 if (dnptrs != NULL) {
3176 msg = *dnptrs++;
3177 if (msg != NULL) {
3178 for (cpp = dnptrs; *cpp != NULL; cpp++)
3179 continue;
3181 lpp = cpp; /*%< end of list to search */
3183 } else {
3184 msg = NULL;
3187 /* make sure the domain we are about to add is legal */
3188 l = 0;
3189 do {
3190 int l0;
3192 n = *srcp;
3193 if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) {
3194 errno = EMSGSIZE;
3195 return -1;
3198 l0 = labellen(srcp);
3199 if (l0 < 0) {
3200 errno = EINVAL;
3201 return -1;
3204 l += l0 + 1;
3205 if (l > MAXCDNAME) {
3206 errno = EMSGSIZE;
3207 return -1;
3210 srcp += l0 + 1;
3211 } while (n != 0);
3213 /* from here on we need to reset compression pointer array on error */
3214 srcp = src;
3216 do {
3217 /* Look to see if we can use pointers. */
3218 n = *srcp;
3220 if (n != 0 && msg != NULL) {
3221 l = dn_find(srcp, msg, (const unsigned char * const *) dnptrs,
3222 (const unsigned char * const *) lpp);
3223 if (l >= 0) {
3224 if (dstp + 1 >= eob) {
3225 goto cleanup;
3228 *dstp++ = ((u_int32_t)l >> 8) | NS_CMPRSFLGS;
3229 *dstp++ = l % 256;
3230 return (dstp - dst);
3233 /* Not found, save it. */
3234 if (lastdnptr != NULL && cpp < lastdnptr - 1 &&
3235 (dstp - msg) < 0x4000 && first) {
3236 *cpp++ = dstp;
3237 *cpp = NULL;
3238 first = 0;
3242 /* copy label to buffer */
3243 if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) {
3244 /* Should not happen. */
3245 goto cleanup;
3248 n = labellen(srcp);
3249 if (dstp + 1 + n >= eob) {
3250 goto cleanup;
3253 memcpy(dstp, srcp, (size_t)(n + 1));
3254 srcp += n + 1;
3255 dstp += n + 1;
3256 } while (n != 0);
3258 if (dstp > eob) {
3259 cleanup:
3260 if (msg != NULL)
3261 *lpp = NULL;
3263 errno = EMSGSIZE;
3264 return -1;
3267 return dstp - dst;
3269 libc_hidden_def(ns_name_pack)
3271 int ns_name_compress(const char *src,
3272 unsigned char *dst, size_t dstsiz,
3273 const unsigned char **dnptrs,
3274 const unsigned char **lastdnptr)
3276 unsigned char tmp[NS_MAXCDNAME];
3278 if (ns_name_pton(src, tmp, sizeof(tmp)) == -1)
3279 return -1;
3281 return ns_name_pack(tmp, dst, dstsiz, dnptrs, lastdnptr);
3283 libc_hidden_def(ns_name_compress)
3285 int ns_name_skip(const unsigned char **ptrptr,
3286 const unsigned char *eom)
3288 const unsigned char *cp;
3289 u_int n;
3290 int l;
3292 cp = *ptrptr;
3293 while (cp < eom && (n = *cp++) != 0) {
3294 /* Check for indirection. */
3295 switch (n & NS_CMPRSFLGS) {
3296 case 0: /*%< normal case, n == len */
3297 cp += n;
3298 continue;
3299 case NS_TYPE_ELT: /*%< EDNS0 extended label */
3300 l = labellen(cp - 1);
3301 if (l < 0) {
3302 errno = EMSGSIZE; /*%< XXX */
3303 return -1;
3305 cp += l;
3306 continue;
3307 case NS_CMPRSFLGS: /*%< indirection */
3308 cp++;
3309 break;
3310 default: /*%< illegal type */
3311 errno = EMSGSIZE;
3312 return -1;
3315 break;
3318 if (cp > eom) {
3319 errno = EMSGSIZE;
3320 return -1;
3323 *ptrptr = cp;
3325 return 0;
3327 libc_hidden_def(ns_name_skip)
3329 int dn_skipname(const unsigned char *ptr, const unsigned char *eom)
3331 const unsigned char *saveptr = ptr;
3333 if (ns_name_skip(&ptr, eom) == -1)
3334 return -1;
3336 return ptr - saveptr;
3338 libc_hidden_def(dn_skipname)
3339 #endif /* L_ns_name */
3342 #ifdef L_res_init
3344 /* Will be called under __resolv_lock. */
3345 static void res_sync_func(void)
3347 struct __res_state *rp = &(_res);
3348 int n;
3350 /* If we didn't get malloc failure earlier... */
3351 if (__nameserver != (void*) &__local_nameserver) {
3352 /* TODO:
3353 * if (__nameservers < rp->nscount) - try to grow __nameserver[]?
3355 #ifdef __UCLIBC_HAS_IPV6__
3356 if (__nameservers > rp->_u._ext.nscount)
3357 __nameservers = rp->_u._ext.nscount;
3358 n = __nameservers;
3359 while (--n >= 0)
3360 __nameserver[n].sa6 = *rp->_u._ext.nsaddrs[n]; /* struct copy */
3361 #else /* IPv4 only */
3362 if (__nameservers > rp->nscount)
3363 __nameservers = rp->nscount;
3364 n = __nameservers;
3365 while (--n >= 0)
3366 __nameserver[n].sa4 = rp->nsaddr_list[n]; /* struct copy */
3367 #endif
3369 __resolv_timeout = rp->retrans ? : RES_TIMEOUT;
3370 __resolv_attempts = rp->retry ? : RES_DFLRETRY;
3371 /* Extend and comment what program is known
3372 * to use which _res.XXX member(s).
3374 __resolv_opts = rp->options;
3379 /* has to be called under __resolv_lock */
3380 static int
3381 __res_vinit(res_state rp, int preinit)
3383 int i, n, options, retrans, retry, ndots;
3384 #ifdef __UCLIBC_HAS_IPV6__
3385 int m = 0;
3386 #endif
3388 __close_nameservers();
3389 __open_nameservers();
3391 if (preinit) {
3392 options = rp->options;
3393 retrans = rp->retrans;
3394 retry = rp->retry;
3395 ndots = rp->ndots;
3398 memset(rp, 0, sizeof(*rp));
3400 if (!preinit) {
3401 rp->options = RES_DEFAULT;
3402 rp->retrans = RES_TIMEOUT;
3403 rp->retry = RES_DFLRETRY;
3404 rp->ndots = 1;
3405 } else {
3406 rp->options = options;
3407 rp->retrans = retrans;
3408 rp->retry = retry;
3409 rp->ndots = ndots;
3412 #ifdef __UCLIBC_HAS_COMPAT_RES_STATE__
3413 /* Was: "rp->id = random();" but:
3414 * - random() pulls in largish static buffers
3415 * - isn't actually random unless, say, srandom(time(NULL)) was called
3416 * - is not used by uclibc anyway :)
3418 /* rp->id = 0; - memset did it */
3419 #endif
3420 #ifdef __UCLIBC_HAS_EXTRA_COMPAT_RES_STATE__
3421 rp->_vcsock = -1;
3422 #endif
3424 n = __searchdomains;
3425 if (n > ARRAY_SIZE(rp->dnsrch))
3426 n = ARRAY_SIZE(rp->dnsrch);
3427 for (i = 0; i < n; i++)
3428 rp->dnsrch[i] = __searchdomain[i];
3430 /* copy nameservers' addresses */
3431 i = 0;
3432 #ifdef __UCLIBC_HAS_IPV4__
3433 n = 0;
3434 while (n < ARRAY_SIZE(rp->nsaddr_list) && i < __nameservers) {
3435 if (__nameserver[i].sa.sa_family == AF_INET) {
3436 rp->nsaddr_list[n] = __nameserver[i].sa4; /* struct copy */
3437 #ifdef __UCLIBC_HAS_IPV6__
3438 if (m < ARRAY_SIZE(rp->_u._ext.nsaddrs)) {
3439 rp->_u._ext.nsaddrs[m] = (void*) &rp->nsaddr_list[n];
3440 m++;
3442 #endif
3443 n++;
3445 #ifdef __UCLIBC_HAS_IPV6__
3446 if (__nameserver[i].sa.sa_family == AF_INET6
3447 && m < ARRAY_SIZE(rp->_u._ext.nsaddrs)
3449 struct sockaddr_in6 *sa6 = malloc(sizeof(*sa6));
3450 if (sa6) {
3451 *sa6 = __nameserver[i].sa6; /* struct copy */
3452 rp->_u._ext.nsaddrs[m] = sa6;
3453 m++;
3456 #endif
3457 i++;
3459 rp->nscount = n;
3460 #ifdef __UCLIBC_HAS_IPV6__
3461 rp->_u._ext.nscount = m;
3462 #endif
3464 #else /* IPv6 only */
3465 while (m < ARRAY_SIZE(rp->_u._ext.nsaddrs) && i < __nameservers) {
3466 struct sockaddr_in6 *sa6 = malloc(sizeof(*sa6));
3467 if (sa6) {
3468 *sa6 = __nameserver[i].sa6; /* struct copy */
3469 rp->_u._ext.nsaddrs[m] = sa6;
3470 m++;
3472 i++;
3474 rp->_u._ext.nscount = m;
3475 #endif
3477 rp->options |= RES_INIT;
3479 return 0;
3482 static unsigned int
3483 res_randomid(void)
3485 return 0xffff & getpid();
3488 /* Our res_init never fails (always returns 0) */
3490 res_init(void)
3493 * These three fields used to be statically initialized. This made
3494 * it hard to use this code in a shared library. It is necessary,
3495 * now that we're doing dynamic initialization here, that we preserve
3496 * the old semantics: if an application modifies one of these three
3497 * fields of _res before res_init() is called, res_init() will not
3498 * alter them. Of course, if an application is setting them to
3499 * _zero_ before calling res_init(), hoping to override what used
3500 * to be the static default, we can't detect it and unexpected results
3501 * will follow. Zero for any of these fields would make no sense,
3502 * so one can safely assume that the applications were already getting
3503 * unexpected results.
3505 * _res.options is tricky since some apps were known to diddle the bits
3506 * before res_init() was first called. We can't replicate that semantic
3507 * with dynamic initialization (they may have turned bits off that are
3508 * set in RES_DEFAULT). Our solution is to declare such applications
3509 * "broken". They could fool us by setting RES_INIT but none do (yet).
3512 __UCLIBC_MUTEX_LOCK(__resolv_lock);
3514 if (!_res.retrans)
3515 _res.retrans = RES_TIMEOUT;
3516 if (!_res.retry)
3517 _res.retry = 4;
3518 if (!(_res.options & RES_INIT))
3519 _res.options = RES_DEFAULT;
3522 * This one used to initialize implicitly to zero, so unless the app
3523 * has set it to something in particular, we can randomize it now.
3525 if (!_res.id)
3526 _res.id = res_randomid();
3528 __res_sync = NULL;
3529 __res_vinit(&_res, 1);
3530 __res_sync = res_sync_func;
3532 __UCLIBC_MUTEX_UNLOCK(__resolv_lock);
3534 return 0;
3536 libc_hidden_def(res_init)
3538 static void
3539 __res_iclose(res_state statp)
3541 struct __res_state * rp = statp;
3542 __UCLIBC_MUTEX_LOCK(__resolv_lock);
3543 if (rp == NULL)
3544 rp = __res_state();
3545 __close_nameservers();
3546 __res_sync = NULL;
3547 #ifdef __UCLIBC_HAS_IPV6__
3549 char *p1 = (char*) &(rp->nsaddr_list[0]);
3550 unsigned int m = 0;
3551 /* free nsaddrs[m] if they do not point to nsaddr_list[x] */
3552 while (m < ARRAY_SIZE(rp->_u._ext.nsaddrs)) {
3553 char *p2 = (char*)(rp->_u._ext.nsaddrs[m++]);
3554 if (p2 < p1 || (p2 - p1) > (signed)sizeof(rp->nsaddr_list))
3555 free(p2);
3558 #endif
3559 memset(rp, 0, sizeof(struct __res_state));
3560 __UCLIBC_MUTEX_UNLOCK(__resolv_lock);
3564 * This routine is for closing the socket if a virtual circuit is used and
3565 * the program wants to close it. This provides support for endhostent()
3566 * which expects to close the socket.
3568 * This routine is not expected to be user visible.
3571 void
3572 res_nclose(res_state statp)
3574 __res_iclose(statp);
3577 #ifdef __UCLIBC_HAS_BSD_RES_CLOSE__
3578 void res_close(void)
3580 __res_iclose(NULL);
3582 #endif
3584 #ifdef __UCLIBC_HAS_BSD_B64_NTOP_B64_PTON__
3585 #define Assert(Cond) if (!(Cond)) abort()
3587 static const char Base64[] =
3588 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
3589 static const char Pad64 = '=';
3591 /* (From RFC1521 and draft-ietf-dnssec-secext-03.txt)
3592 The following encoding technique is taken from RFC 1521 by Borenstein
3593 and Freed. It is reproduced here in a slightly edited form for
3594 convenience.
3596 A 65-character subset of US-ASCII is used, enabling 6 bits to be
3597 represented per printable character. (The extra 65th character, "=",
3598 is used to signify a special processing function.)
3600 The encoding process represents 24-bit groups of input bits as output
3601 strings of 4 encoded characters. Proceeding from left to right, a
3602 24-bit input group is formed by concatenating 3 8-bit input groups.
3603 These 24 bits are then treated as 4 concatenated 6-bit groups, each
3604 of which is translated into a single digit in the base64 alphabet.
3606 Each 6-bit group is used as an index into an array of 64 printable
3607 characters. The character referenced by the index is placed in the
3608 output string.
3610 Table 1: The Base64 Alphabet
3612 Value Encoding Value Encoding Value Encoding Value Encoding
3613 0 A 17 R 34 i 51 z
3614 1 B 18 S 35 j 52 0
3615 2 C 19 T 36 k 53 1
3616 3 D 20 U 37 l 54 2
3617 4 E 21 V 38 m 55 3
3618 5 F 22 W 39 n 56 4
3619 6 G 23 X 40 o 57 5
3620 7 H 24 Y 41 p 58 6
3621 8 I 25 Z 42 q 59 7
3622 9 J 26 a 43 r 60 8
3623 10 K 27 b 44 s 61 9
3624 11 L 28 c 45 t 62 +
3625 12 M 29 d 46 u 63 /
3626 13 N 30 e 47 v
3627 14 O 31 f 48 w (pad) =
3628 15 P 32 g 49 x
3629 16 Q 33 h 50 y
3631 Special processing is performed if fewer than 24 bits are available
3632 at the end of the data being encoded. A full encoding quantum is
3633 always completed at the end of a quantity. When fewer than 24 input
3634 bits are available in an input group, zero bits are added (on the
3635 right) to form an integral number of 6-bit groups. Padding at the
3636 end of the data is performed using the '=' character.
3638 Since all base64 input is an integral number of octets, only the
3639 -------------------------------------------------
3640 following cases can arise:
3642 (1) the final quantum of encoding input is an integral
3643 multiple of 24 bits; here, the final unit of encoded
3644 output will be an integral multiple of 4 characters
3645 with no "=" padding,
3646 (2) the final quantum of encoding input is exactly 8 bits;
3647 here, the final unit of encoded output will be two
3648 characters followed by two "=" padding characters, or
3649 (3) the final quantum of encoding input is exactly 16 bits;
3650 here, the final unit of encoded output will be three
3651 characters followed by one "=" padding character.
3655 b64_ntop(u_char const *src, size_t srclength, char *target, size_t targsize) {
3656 size_t datalength = 0;
3657 u_char input[3];
3658 u_char output[4];
3659 size_t i;
3661 while (2 < srclength) {
3662 input[0] = *src++;
3663 input[1] = *src++;
3664 input[2] = *src++;
3665 srclength -= 3;
3667 output[0] = input[0] >> 2;
3668 output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4);
3669 output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6);
3670 output[3] = input[2] & 0x3f;
3671 Assert(output[0] < 64);
3672 Assert(output[1] < 64);
3673 Assert(output[2] < 64);
3674 Assert(output[3] < 64);
3676 if (datalength + 4 > targsize)
3677 return (-1);
3678 target[datalength++] = Base64[output[0]];
3679 target[datalength++] = Base64[output[1]];
3680 target[datalength++] = Base64[output[2]];
3681 target[datalength++] = Base64[output[3]];
3684 /* Now we worry about padding. */
3685 if (0 != srclength) {
3686 /* Get what's left. */
3687 input[0] = input[1] = input[2] = '\0';
3688 for (i = 0; i < srclength; i++)
3689 input[i] = *src++;
3691 output[0] = input[0] >> 2;
3692 output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4);
3693 output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6);
3694 Assert(output[0] < 64);
3695 Assert(output[1] < 64);
3696 Assert(output[2] < 64);
3698 if (datalength + 4 > targsize)
3699 return (-1);
3700 target[datalength++] = Base64[output[0]];
3701 target[datalength++] = Base64[output[1]];
3702 if (srclength == 1)
3703 target[datalength++] = Pad64;
3704 else
3705 target[datalength++] = Base64[output[2]];
3706 target[datalength++] = Pad64;
3708 if (datalength >= targsize)
3709 return (-1);
3710 target[datalength] = '\0'; /* Returned value doesn't count \0. */
3711 return (datalength);
3713 /* libc_hidden_def (b64_ntop) */
3715 /* skips all whitespace anywhere.
3716 converts characters, four at a time, starting at (or after)
3717 src from base - 64 numbers into three 8 bit bytes in the target area.
3718 it returns the number of data bytes stored at the target, or -1 on error.
3722 b64_pton (char const *src, u_char *target, size_t targsize)
3724 int tarindex, state, ch;
3725 char *pos;
3727 state = 0;
3728 tarindex = 0;
3730 while ((ch = *src++) != '\0') {
3731 if (isspace(ch)) /* Skip whitespace anywhere. */
3732 continue;
3734 if (ch == Pad64)
3735 break;
3737 pos = strchr(Base64, ch);
3738 if (pos == 0) /* A non-base64 character. */
3739 return (-1);
3741 switch (state) {
3742 case 0:
3743 if (target) {
3744 if ((size_t)tarindex >= targsize)
3745 return (-1);
3746 target[tarindex] = (pos - Base64) << 2;
3748 state = 1;
3749 break;
3750 case 1:
3751 if (target) {
3752 if ((size_t)tarindex + 1 >= targsize)
3753 return (-1);
3754 target[tarindex] |= (pos - Base64) >> 4;
3755 target[tarindex+1] = ((pos - Base64) & 0x0f)
3756 << 4 ;
3758 tarindex++;
3759 state = 2;
3760 break;
3761 case 2:
3762 if (target) {
3763 if ((size_t)tarindex + 1 >= targsize)
3764 return (-1);
3765 target[tarindex] |= (pos - Base64) >> 2;
3766 target[tarindex+1] = ((pos - Base64) & 0x03)
3767 << 6;
3769 tarindex++;
3770 state = 3;
3771 break;
3772 case 3:
3773 if (target) {
3774 if ((size_t)tarindex >= targsize)
3775 return (-1);
3776 target[tarindex] |= (pos - Base64);
3778 tarindex++;
3779 state = 0;
3780 break;
3781 default:
3782 abort();
3787 * We are done decoding Base-64 chars. Let's see if we ended
3788 * on a byte boundary, and/or with erroneous trailing characters.
3791 if (ch == Pad64) { /* We got a pad char. */
3792 ch = *src++; /* Skip it, get next. */
3793 switch (state) {
3794 case 0: /* Invalid = in first position */
3795 case 1: /* Invalid = in second position */
3796 return (-1);
3798 case 2: /* Valid, means one byte of info */
3799 /* Skip any number of spaces. */
3800 for ((void)NULL; ch != '\0'; ch = *src++)
3801 if (!isspace(ch))
3802 break;
3803 /* Make sure there is another trailing = sign. */
3804 if (ch != Pad64)
3805 return (-1);
3806 ch = *src++; /* Skip the = */
3807 /* Fall through to "single trailing =" case. */
3808 /* FALLTHROUGH */
3810 case 3: /* Valid, means two bytes of info */
3812 * We know this char is an =. Is there anything but
3813 * whitespace after it?
3815 for ((void)NULL; ch != '\0'; ch = *src++)
3816 if (!isspace(ch))
3817 return (-1);
3820 * Now make sure for cases 2 and 3 that the "extra"
3821 * bits that slopped past the last full byte were
3822 * zeros. If we don't check them, they become a
3823 * subliminal channel.
3825 if (target && target[tarindex] != 0)
3826 return (-1);
3828 } else {
3830 * We ended by seeing the end of the string. Make sure we
3831 * have no partial bytes lying around.
3833 if (state != 0)
3834 return (-1);
3837 return (tarindex);
3839 #endif
3841 /* This needs to be after the use of _res in res_init, above. */
3842 #undef _res
3844 #ifndef __UCLIBC_HAS_THREADS__
3845 /* The resolver state for use by single-threaded programs.
3846 This differs from plain `struct __res_state _res;' in that it doesn't
3847 create a common definition, but a plain symbol that resides in .bss,
3848 which can have an alias. */
3849 struct __res_state _res __attribute__((section (".bss")));
3850 struct __res_state *__resp = &_res;
3851 #else /* __UCLIBC_HAS_THREADS__ */
3852 struct __res_state _res __attribute__((section (".bss"))) attribute_hidden;
3854 # if defined __UCLIBC_HAS_TLS__
3855 # undef __resp
3856 __thread struct __res_state *__resp = &_res;
3857 extern __thread struct __res_state *__libc_resp
3858 __attribute__ ((alias ("__resp"))) attribute_hidden attribute_tls_model_ie;
3859 # else
3860 # undef __resp
3861 struct __res_state *__resp = &_res;
3862 # endif
3863 #endif /* !__UCLIBC_HAS_THREADS__ */
3866 * Set up default settings. If the configuration file exist, the values
3867 * there will have precedence. Otherwise, the server address is set to
3868 * INADDR_ANY and the default domain name comes from the gethostname().
3870 * An interrim version of this code (BIND 4.9, pre-4.4BSD) used 127.0.0.1
3871 * rather than INADDR_ANY ("0.0.0.0") as the default name server address
3872 * since it was noted that INADDR_ANY actually meant ``the first interface
3873 * you "ifconfig"'d at boot time'' and if this was a SLIP or PPP interface,
3874 * it had to be "up" in order for you to reach your own name server. It
3875 * was later decided that since the recommended practice is to always
3876 * install local static routes through 127.0.0.1 for all your network
3877 * interfaces, that we could solve this problem without a code change.
3879 * The configuration file should always be used, since it is the only way
3880 * to specify a default domain. If you are running a server on your local
3881 * machine, you should say "nameserver 0.0.0.0" or "nameserver 127.0.0.1"
3882 * in the configuration file.
3884 * Return 0 if completes successfully, -1 on error
3887 res_ninit(res_state statp)
3889 int ret;
3890 __UCLIBC_MUTEX_LOCK(__resolv_lock);
3891 ret = __res_vinit(statp, 0);
3892 __UCLIBC_MUTEX_UNLOCK(__resolv_lock);
3893 return ret;
3896 #endif /* L_res_init */
3898 #ifdef L_res_state
3899 # if defined __UCLIBC_HAS_TLS__
3900 struct __res_state *
3901 __res_state (void)
3903 return __resp;
3905 # else
3906 # undef _res
3907 extern struct __res_state _res;
3909 /* When threaded, _res may be a per-thread variable. */
3910 struct __res_state *
3911 weak_const_function
3912 __res_state (void)
3914 return &_res;
3916 # endif
3918 #endif /* L_res_state */
3921 #ifdef L_res_query
3923 int res_query(const char *dname, int class, int type,
3924 unsigned char *answer, int anslen)
3926 int i;
3927 unsigned char *packet = NULL;
3928 struct resolv_answer a;
3930 if (!dname || class != 1 /* CLASS_IN */) {
3931 h_errno = NO_RECOVERY;
3932 return -1;
3935 memset(&a, '\0', sizeof(a));
3936 i = __dns_lookup(dname, type, &packet, &a);
3938 if (i < 0) {
3939 if (!h_errno) /* TODO: can this ever happen? */
3940 h_errno = TRY_AGAIN;
3941 return -1;
3944 free(a.dotted);
3946 if (i > anslen)
3947 i = anslen;
3948 memcpy(answer, packet, i);
3950 free(packet);
3951 return i;
3953 libc_hidden_def(res_query)
3956 * Formulate a normal query, send, and retrieve answer in supplied buffer.
3957 * Return the size of the response on success, -1 on error.
3958 * If enabled, implement search rules until answer or unrecoverable failure
3959 * is detected. Error code, if any, is left in h_errno.
3961 #define __TRAILING_DOT (1<<0)
3962 #define __GOT_NODATA (1<<1)
3963 #define __GOT_SERVFAIL (1<<2)
3964 #define __TRIED_AS_IS (1<<3)
3965 int res_search(const char *name, int class, int type, u_char *answer,
3966 int anslen)
3968 const char *cp;
3969 char **domain;
3970 HEADER *hp = (HEADER *)(void *)answer;
3971 unsigned dots;
3972 unsigned state;
3973 int ret, saved_herrno;
3974 uint32_t _res_options;
3975 unsigned _res_ndots;
3976 char **_res_dnsrch;
3978 if (!name || !answer) {
3979 h_errno = NETDB_INTERNAL;
3980 return -1;
3983 again:
3984 __UCLIBC_MUTEX_LOCK(__resolv_lock);
3985 _res_options = _res.options;
3986 _res_ndots = _res.ndots;
3987 _res_dnsrch = _res.dnsrch;
3988 __UCLIBC_MUTEX_UNLOCK(__resolv_lock);
3989 if (!(_res_options & RES_INIT)) {
3990 res_init(); /* our res_init never fails */
3991 goto again;
3994 state = 0;
3995 errno = 0;
3996 h_errno = HOST_NOT_FOUND; /* default, if we never query */
3997 dots = 0;
3998 for (cp = name; *cp; cp++)
3999 dots += (*cp == '.');
4001 if (cp > name && *--cp == '.')
4002 state |= __TRAILING_DOT;
4005 * If there are dots in the name already, let's just give it a try
4006 * 'as is'. The threshold can be set with the "ndots" option.
4008 saved_herrno = -1;
4009 if (dots >= _res_ndots) {
4010 ret = res_querydomain(name, NULL, class, type, answer, anslen);
4011 if (ret > 0)
4012 return ret;
4013 saved_herrno = h_errno;
4014 state |= __TRIED_AS_IS;
4018 * We do at least one level of search if
4019 * - there is no dot and RES_DEFNAME is set, or
4020 * - there is at least one dot, there is no trailing dot,
4021 * and RES_DNSRCH is set.
4023 if ((!dots && (_res_options & RES_DEFNAMES))
4024 || (dots && !(state & __TRAILING_DOT) && (_res_options & RES_DNSRCH))
4026 bool done = 0;
4028 for (domain = _res_dnsrch; *domain && !done; domain++) {
4030 ret = res_querydomain(name, *domain, class, type,
4031 answer, anslen);
4032 if (ret > 0)
4033 return ret;
4036 * If no server present, give up.
4037 * If name isn't found in this domain,
4038 * keep trying higher domains in the search list
4039 * (if that's enabled).
4040 * On a NO_DATA error, keep trying, otherwise
4041 * a wildcard entry of another type could keep us
4042 * from finding this entry higher in the domain.
4043 * If we get some other error (negative answer or
4044 * server failure), then stop searching up,
4045 * but try the input name below in case it's
4046 * fully-qualified.
4048 if (errno == ECONNREFUSED) {
4049 h_errno = TRY_AGAIN;
4050 return -1;
4053 switch (h_errno) {
4054 case NO_DATA:
4055 state |= __GOT_NODATA;
4056 /* FALLTHROUGH */
4057 case HOST_NOT_FOUND:
4058 /* keep trying */
4059 break;
4060 case TRY_AGAIN:
4061 if (hp->rcode == SERVFAIL) {
4062 /* try next search element, if any */
4063 state |= __GOT_SERVFAIL;
4064 break;
4066 /* FALLTHROUGH */
4067 default:
4068 /* anything else implies that we're done */
4069 done = 1;
4072 * if we got here for some reason other than DNSRCH,
4073 * we only wanted one iteration of the loop, so stop.
4075 if (!(_res_options & RES_DNSRCH))
4076 done = 1;
4081 * if we have not already tried the name "as is", do that now.
4082 * note that we do this regardless of how many dots were in the
4083 * name or whether it ends with a dot.
4085 if (!(state & __TRIED_AS_IS)) {
4086 ret = res_querydomain(name, NULL, class, type, answer, anslen);
4087 if (ret > 0)
4088 return ret;
4092 * if we got here, we didn't satisfy the search.
4093 * if we did an initial full query, return that query's h_errno
4094 * (note that we wouldn't be here if that query had succeeded).
4095 * else if we ever got a nodata, send that back as the reason.
4096 * else send back meaningless h_errno, that being the one from
4097 * the last DNSRCH we did.
4099 if (saved_herrno != -1)
4100 h_errno = saved_herrno;
4101 else if (state & __GOT_NODATA)
4102 h_errno = NO_DATA;
4103 else if (state & __GOT_SERVFAIL)
4104 h_errno = TRY_AGAIN;
4105 return -1;
4107 #undef __TRAILING_DOT
4108 #undef __GOT_NODATA
4109 #undef __GOT_SERVFAIL
4110 #undef __TRIED_AS_IS
4112 * Perform a call on res_query on the concatenation of name and domain,
4113 * removing a trailing dot from name if domain is NULL.
4115 int res_querydomain(const char *name, const char *domain, int class, int type,
4116 u_char *answer, int anslen)
4118 char nbuf[MAXDNAME];
4119 const char *longname = nbuf;
4120 size_t n, d;
4121 #ifdef DEBUG
4122 uint32_t _res_options;
4123 #endif
4125 if (!name || !answer) {
4126 h_errno = NETDB_INTERNAL;
4127 return -1;
4130 #ifdef DEBUG
4131 again:
4132 __UCLIBC_MUTEX_LOCK(__resolv_lock);
4133 _res_options = _res.options;
4134 __UCLIBC_MUTEX_UNLOCK(__resolv_lock);
4135 if (!(_res_options & RES_INIT)) {
4136 res_init(); /* our res_init never fails */
4137 goto again;
4139 if (_res_options & RES_DEBUG)
4140 printf(";; res_querydomain(%s, %s, %d, %d)\n",
4141 name, (domain ? domain : "<Nil>"), class, type);
4142 #endif
4143 if (domain == NULL) {
4145 * Check for trailing '.';
4146 * copy without '.' if present.
4148 n = strlen(name);
4149 if (n + 1 > sizeof(nbuf)) {
4150 h_errno = NO_RECOVERY;
4151 return -1;
4153 if (n > 0 && name[--n] == '.') {
4154 strncpy(nbuf, name, n);
4155 nbuf[n] = '\0';
4156 } else
4157 longname = name;
4158 } else {
4159 n = strlen(name);
4160 d = strlen(domain);
4161 if (n + 1 + d + 1 > sizeof(nbuf)) {
4162 h_errno = NO_RECOVERY;
4163 return -1;
4165 snprintf(nbuf, sizeof(nbuf), "%s.%s", name, domain);
4167 return res_query(longname, class, type, answer, anslen);
4169 libc_hidden_def(res_querydomain)
4170 #endif /* L_res_query */
4172 #ifdef L_ns_netint
4173 unsigned int ns_get16(const unsigned char *src)
4175 unsigned int dst;
4176 NS_GET16(dst, src);
4177 return dst;
4180 unsigned long ns_get32(const unsigned char *src)
4182 unsigned long dst;
4183 NS_GET32(dst, src);
4184 return dst;
4187 void ns_put16(unsigned int src, unsigned char *dst)
4189 NS_PUT16(src, dst);
4192 void ns_put32(unsigned long src, unsigned char *dst)
4194 NS_PUT32(src, dst);
4196 #endif /* L_ns_netint */
4198 #ifdef L_ns_parse
4199 /* These need to be in the same order as the nres.h:ns_flag enum. */
4200 struct _ns_flagdata { unsigned short mask, shift; };
4201 static const struct _ns_flagdata _ns_flagdata[16] = {
4202 { 0x8000, 15 }, /*%< qr. */
4203 { 0x7800, 11 }, /*%< opcode. */
4204 { 0x0400, 10 }, /*%< aa. */
4205 { 0x0200, 9 }, /*%< tc. */
4206 { 0x0100, 8 }, /*%< rd. */
4207 { 0x0080, 7 }, /*%< ra. */
4208 { 0x0040, 6 }, /*%< z. */
4209 { 0x0020, 5 }, /*%< ad. */
4210 { 0x0010, 4 }, /*%< cd. */
4211 { 0x000f, 0 }, /*%< rcode. */
4212 { 0x0000, 0 }, /*%< expansion (1/6). */
4213 { 0x0000, 0 }, /*%< expansion (2/6). */
4214 { 0x0000, 0 }, /*%< expansion (3/6). */
4215 { 0x0000, 0 }, /*%< expansion (4/6). */
4216 { 0x0000, 0 }, /*%< expansion (5/6). */
4217 { 0x0000, 0 }, /*%< expansion (6/6). */
4220 static void setsection(ns_msg *msg, ns_sect sect)
4222 msg->_sect = sect;
4223 if (sect == ns_s_max) {
4224 msg->_rrnum = -1;
4225 msg->_ptr = NULL;
4226 } else {
4227 msg->_rrnum = 0;
4228 msg->_ptr = msg->_sections[(int)sect];
4232 int ns_skiprr(const unsigned char *ptr,
4233 const unsigned char *eom,
4234 ns_sect section, int count)
4236 const u_char *optr = ptr;
4238 for (; count > 0; count--) {
4239 int b, rdlength;
4241 b = dn_skipname(ptr, eom);
4242 if (b < 0) {
4243 errno = EMSGSIZE;
4244 return -1;
4247 ptr += b/*Name*/ + NS_INT16SZ/*Type*/ + NS_INT16SZ/*Class*/;
4248 if (section != ns_s_qd) {
4249 if (ptr + NS_INT32SZ + NS_INT16SZ > eom) {
4250 errno = EMSGSIZE;
4251 return -1;
4254 ptr += NS_INT32SZ/*TTL*/;
4255 NS_GET16(rdlength, ptr);
4256 ptr += rdlength/*RData*/;
4260 if (ptr > eom) {
4261 errno = EMSGSIZE;
4262 return -1;
4265 return ptr - optr;
4267 libc_hidden_def(ns_skiprr)
4270 ns_initparse(const unsigned char *msg, int msglen, ns_msg *handle)
4272 const u_char *eom = msg + msglen;
4273 int i;
4275 handle->_msg = msg;
4276 handle->_eom = eom;
4277 if (msg + NS_INT16SZ > eom) {
4278 errno = EMSGSIZE;
4279 return -1;
4282 NS_GET16(handle->_id, msg);
4283 if (msg + NS_INT16SZ > eom) {
4284 errno = EMSGSIZE;
4285 return -1;
4288 NS_GET16(handle->_flags, msg);
4289 for (i = 0; i < ns_s_max; i++) {
4290 if (msg + NS_INT16SZ > eom) {
4291 errno = EMSGSIZE;
4292 return -1;
4295 NS_GET16(handle->_counts[i], msg);
4297 for (i = 0; i < ns_s_max; i++)
4298 if (handle->_counts[i] == 0)
4299 handle->_sections[i] = NULL;
4300 else {
4301 int b = ns_skiprr(msg, eom, (ns_sect)i,
4302 handle->_counts[i]);
4304 if (b < 0)
4305 return -1;
4306 handle->_sections[i] = msg;
4307 msg += b;
4310 if (msg != eom) {
4311 errno = EMSGSIZE;
4312 return -1;
4315 setsection(handle, ns_s_max);
4316 return 0;
4320 ns_parserr(ns_msg *handle, ns_sect section, int rrnum, ns_rr *rr)
4322 int b;
4323 int tmp;
4325 /* Make section right. */
4326 tmp = section;
4327 if (tmp < 0 || section >= ns_s_max) {
4328 errno = ENODEV;
4329 return -1;
4332 if (section != handle->_sect)
4333 setsection(handle, section);
4335 /* Make rrnum right. */
4336 if (rrnum == -1)
4337 rrnum = handle->_rrnum;
4338 if (rrnum < 0 || rrnum >= handle->_counts[(int)section]) {
4339 errno = ENODEV;
4340 return -1;
4342 if (rrnum < handle->_rrnum)
4343 setsection(handle, section);
4344 if (rrnum > handle->_rrnum) {
4345 b = ns_skiprr(handle->_ptr, handle->_eom, section,
4346 rrnum - handle->_rrnum);
4348 if (b < 0)
4349 return -1;
4350 handle->_ptr += b;
4351 handle->_rrnum = rrnum;
4354 /* Do the parse. */
4355 b = dn_expand(handle->_msg, handle->_eom,
4356 handle->_ptr, rr->name, NS_MAXDNAME);
4357 if (b < 0)
4358 return -1;
4359 handle->_ptr += b;
4360 if (handle->_ptr + NS_INT16SZ + NS_INT16SZ > handle->_eom) {
4361 errno = EMSGSIZE;
4362 return -1;
4364 NS_GET16(rr->type, handle->_ptr);
4365 NS_GET16(rr->rr_class, handle->_ptr);
4366 if (section == ns_s_qd) {
4367 rr->ttl = 0;
4368 rr->rdlength = 0;
4369 rr->rdata = NULL;
4370 } else {
4371 if (handle->_ptr + NS_INT32SZ + NS_INT16SZ > handle->_eom) {
4372 errno = EMSGSIZE;
4373 return -1;
4375 NS_GET32(rr->ttl, handle->_ptr);
4376 NS_GET16(rr->rdlength, handle->_ptr);
4377 if (handle->_ptr + rr->rdlength > handle->_eom) {
4378 errno = EMSGSIZE;
4379 return -1;
4381 rr->rdata = handle->_ptr;
4382 handle->_ptr += rr->rdlength;
4384 if (++handle->_rrnum > handle->_counts[(int)section])
4385 setsection(handle, (ns_sect)((int)section + 1));
4387 return 0;
4390 int ns_msg_getflag(ns_msg handle, int flag)
4392 return ((handle)._flags & _ns_flagdata[flag].mask) >> _ns_flagdata[flag].shift;
4394 #endif /* L_ns_parse */
4396 #ifdef L_res_data
4397 int res_mkquery(int op, const char *dname, int class, int type,
4398 const unsigned char *data, int datalen,
4399 const unsigned char *newrr_in,
4400 unsigned char *buf, int buflen)
4402 HEADER *hp;
4403 unsigned char *cp, *ep;
4404 unsigned char *dnptrs[20], **dpp, **lastdnptr;
4405 uint32_t _res_options;
4406 int n;
4408 if (!buf || buflen < HFIXEDSZ) {
4409 h_errno = NETDB_INTERNAL;
4410 return -1;
4413 again:
4414 __UCLIBC_MUTEX_LOCK(__resolv_lock);
4415 _res_options = _res.options;
4416 __UCLIBC_MUTEX_UNLOCK(__resolv_lock);
4417 if (!(_res_options & RES_INIT)) {
4418 res_init(); /* our res_init never fails */
4419 goto again;
4422 #ifdef DEBUG
4423 if (_res_options & RES_DEBUG)
4424 printf(";; res_mkquery(%d, %s, %d, %d)\n",
4425 op, dname && *dname ? dname : "<null>", class, type);
4426 #endif
4428 memset(buf, 0, HFIXEDSZ);
4429 hp = (HEADER *) buf;
4430 hp->id = getpid() & 0xffff;
4431 hp->opcode = op;
4432 hp->rd = (_res_options & RES_RECURSE) != 0U;
4433 hp->rcode = NOERROR;
4435 cp = buf + HFIXEDSZ;
4436 ep = buf + buflen;
4437 dpp = dnptrs;
4438 *dpp++ = buf;
4439 *dpp++ = NULL;
4440 lastdnptr = dnptrs + sizeof dnptrs / sizeof dnptrs[0];
4443 * perform opcode specific processing
4445 switch (op) {
4446 case QUERY:
4447 case NS_NOTIFY_OP:
4448 if (ep - cp < QFIXEDSZ)
4449 return -1;
4451 n = dn_comp(dname, cp, ep - cp - QFIXEDSZ, dnptrs, lastdnptr);
4452 if (n < 0)
4453 return -1;
4455 cp += n;
4456 NS_PUT16(type, cp);
4457 NS_PUT16(class, cp);
4458 hp->qdcount = htons(1);
4460 if (op == QUERY || data == NULL)
4461 break;
4464 * Make an additional record for completion domain.
4466 if ((ep - cp) < RRFIXEDSZ)
4467 return -1;
4469 n = dn_comp((const char *)data, cp, ep - cp - RRFIXEDSZ,
4470 dnptrs, lastdnptr);
4471 if (n < 0)
4472 return -1;
4474 cp += n;
4475 NS_PUT16(T_NULL, cp);
4476 NS_PUT16(class, cp);
4477 NS_PUT32(0, cp);
4478 NS_PUT16(0, cp);
4479 hp->arcount = htons(1);
4481 break;
4483 case IQUERY:
4485 * Initialize answer section
4487 if (ep - cp < 1 + RRFIXEDSZ + datalen)
4488 return -1;
4490 *cp++ = '\0'; /*%< no domain name */
4491 NS_PUT16(type, cp);
4492 NS_PUT16(class, cp);
4493 NS_PUT32(0, cp);
4494 NS_PUT16(datalen, cp);
4496 if (datalen) {
4497 memcpy(cp, data, (size_t)datalen);
4498 cp += datalen;
4501 hp->ancount = htons(1);
4502 break;
4504 default:
4505 return -1;
4508 return cp - buf;
4510 #endif /* L_res_data */
4512 /* Unimplemented: */
4513 /* res_send */