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