OSDN Git Service

Implement hidden poll, switch user to hidden *printf/*scanf/poll
[uclinux-h8/uClibc.git] / libc / inet / resolv.c
1 /* resolv.c: DNS Resolver
2  *
3  * Copyright (C) 1998  Kenneth Albanowski <kjahds@kjahds.com>,
4  *                     The Silver Hammer Group, Ltd.
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10 */
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 /*
42  * Portions Copyright (c) 1993 by Digital Equipment Corporation.
43  *
44  * Permission to use, copy, modify, and distribute this software for any
45  * purpose with or without fee is hereby granted, provided that the above
46  * copyright notice and this permission notice appear in all copies, and that
47  * the name of Digital Equipment Corporation not be used in advertising or
48  * publicity pertaining to distribution of the document or software without
49  * specific, written prior permission.
50  *
51  * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
52  * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
53  * OF MERCHANTABILITY AND FITNESS.   IN NO EVENT SHALL DIGITAL EQUIPMENT
54  * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
55  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
56  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
57  * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
58  * SOFTWARE.
59  */
60
61 /*
62  * Portions Copyright (c) 1996-1999 by Internet Software Consortium.
63  *
64  * Permission to use, copy, modify, and distribute this software for any
65  * purpose with or without fee is hereby granted, provided that the above
66  * copyright notice and this permission notice appear in all copies.
67  *
68  * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
69  * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
70  * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
71  * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
72  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
73  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
74  * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
75  * SOFTWARE.
76  */
77
78 /*
79  *
80  *  5-Oct-2000 W. Greathouse  wgreathouse@smva.com
81  *                              Fix memory leak and memory corruption.
82  *                              -- Every name resolution resulted in
83  *                                 a new parse of resolv.conf and new
84  *                                 copy of nameservers allocated by
85  *                                 strdup.
86  *                              -- Every name resolution resulted in
87  *                                 a new read of resolv.conf without
88  *                                 resetting index from prior read...
89  *                                 resulting in exceeding array bounds.
90  *
91  *                              Limit nameservers read from resolv.conf
92  *
93  *                              Add "search" domains from resolv.conf
94  *
95  *                              Some systems will return a security
96  *                              signature along with query answer for
97  *                              dynamic DNS entries.
98  *                              -- skip/ignore this answer
99  *
100  *                              Include arpa/nameser.h for defines.
101  *
102  *                              General cleanup
103  *
104  * 20-Jun-2001 Michal Moskal <malekith@pld.org.pl>
105  *   partial IPv6 support (i.e. gethostbyname2() and resolve_address2()
106  *   functions added), IPv6 nameservers are also supported.
107  *
108  * 6-Oct-2001 Jari Korva <jari.korva@iki.fi>
109  *   more IPv6 support (IPv6 support for gethostbyaddr();
110  *   address family parameter and improved IPv6 support for get_hosts_byname
111  *   and read_etc_hosts; getnameinfo() port from glibc; defined
112  *   defined ip6addr_any and in6addr_loopback)
113  *
114  * 2-Feb-2002 Erik Andersen <andersen@codepoet.org>
115  *   Added gethostent(), sethostent(), and endhostent()
116  *
117  * 17-Aug-2002 Manuel Novoa III <mjn3@codepoet.org>
118  *   Fixed __read_etc_hosts_r to return alias list, and modified buffer
119  *   allocation accordingly.  See MAX_ALIASES and ALIAS_DIM below.
120  *   This fixes the segfault in the Python 2.2.1 socket test.
121  *
122  * 04-Jan-2003 Jay Kulpinski <jskulpin@berkshire.rr.com>
123  *   Fixed __decode_dotted to count the terminating null character
124  *   in a host name.
125  *
126  * 02-Oct-2003 Tony J. White <tjw@tjw.org>
127  *   Lifted dn_expand() and dependent ns_name_uncompress(), ns_name_unpack(),
128  *   and ns_name_ntop() from glibc 2.3.2 for compatibility with ipsec-tools
129  *   and openldap.
130  *
131  * 7-Sep-2004 Erik Andersen <andersen@codepoet.org>
132  *   Added gethostent_r()
133  *
134  */
135
136 #define strnlen __strnlen
137 #define strncat __strncat
138 #define strstr __strstr
139 #define random __random
140 #define getservbyport __getservbyport
141 #define getdomainname __getdomainname
142 #define uname __uname
143 #define inet_addr __inet_addr
144 #define inet_aton __inet_aton
145 #define inet_pton __inet_pton
146 #define inet_ntop __inet_ntop
147 #define connect __connect
148 #define select __select
149 #define recv __recv
150 #define send __send
151 #define snprintf __snprintf
152
153 #define __FORCE_GLIBC
154 #include <features.h>
155 #include <string.h>
156 #include <stdio.h>
157 #include <signal.h>
158 #include <errno.h>
159 #include <sys/socket.h>
160 #include <sys/types.h>
161 #include <sys/time.h>
162 #include <netinet/in.h>
163 #include <arpa/inet.h>
164 #include <stdlib.h>
165 #include <unistd.h>
166 #include <resolv.h>
167 #include <netdb.h>
168 #include <ctype.h>
169 #include <arpa/nameser.h>
170 #include <sys/utsname.h>
171 #include <sys/un.h>
172
173 extern int __gethostbyname_r (__const char *__restrict __name,
174                             struct hostent *__restrict __result_buf,
175                             char *__restrict __buf, size_t __buflen,
176                             struct hostent **__restrict __result,
177                             int *__restrict __h_errnop) attribute_hidden;
178
179 extern struct hostent *__gethostbyaddr (__const void *__addr, __socklen_t __len,
180                                       int __type) attribute_hidden;
181 #define MAX_RECURSE 5
182 #define REPLY_TIMEOUT 10
183 #define MAX_RETRIES 3
184 #define MAX_SERVERS 3
185 #define MAX_SEARCH 4
186
187 #define MAX_ALIASES     5
188
189 /* 1:ip + 1:full + MAX_ALIASES:aliases + 1:NULL */
190 #define         ALIAS_DIM               (2 + MAX_ALIASES + 1)
191
192 #undef DEBUG
193 /* #define DEBUG */
194
195 #ifdef DEBUG
196 #define DPRINTF(X,args...) fprintf(stderr, X, ##args)
197 #else
198 #define DPRINTF(X,args...)
199 #endif /* DEBUG */
200
201
202 /* Global stuff (stuff needing to be locked to be thread safe)... */
203 extern int __nameservers;
204 extern char * __nameserver[MAX_SERVERS];
205 extern int __searchdomains;
206 extern char * __searchdomain[MAX_SEARCH];
207
208
209 #ifdef __UCLIBC_HAS_THREADS__
210 # include <pthread.h>
211 extern pthread_mutex_t __resolv_lock;
212 #endif
213 #define BIGLOCK __pthread_mutex_lock(&__resolv_lock)
214 #define BIGUNLOCK       __pthread_mutex_unlock(&__resolv_lock)
215
216
217
218 /* Structs */
219 struct resolv_header {
220         int id;
221         int qr,opcode,aa,tc,rd,ra,rcode;
222         int qdcount;
223         int ancount;
224         int nscount;
225         int arcount;
226 };
227
228 struct resolv_question {
229         char * dotted;
230         int qtype;
231         int qclass;
232 };
233
234 struct resolv_answer {
235         char * dotted;
236         int atype;
237         int aclass;
238         int ttl;
239         int rdlength;
240         unsigned char * rdata;
241         int rdoffset;
242         char* buf;
243         size_t buflen;
244         size_t add_count;
245 };
246
247 enum etc_hosts_action {
248     GET_HOSTS_BYNAME = 0,
249     GETHOSTENT,
250     GET_HOSTS_BYADDR,
251 };
252
253 /* function prototypes */
254 extern int __get_hosts_byname_r(const char * name, int type,
255                               struct hostent * result_buf,
256                               char * buf, size_t buflen,
257                               struct hostent ** result,
258                               int * h_errnop) attribute_hidden;
259 extern int __get_hosts_byaddr_r(const char * addr, int len, int type,
260                               struct hostent * result_buf,
261                               char * buf, size_t buflen,
262                               struct hostent ** result,
263                               int * h_errnop) attribute_hidden;
264 extern void __open_etc_hosts(FILE **fp) attribute_hidden;
265 extern int __read_etc_hosts_r(FILE *fp, const char * name, int type,
266                             enum etc_hosts_action action,
267                             struct hostent * result_buf,
268                             char * buf, size_t buflen,
269                             struct hostent ** result,
270                             int * h_errnop) attribute_hidden;
271 extern int __dns_lookup(const char * name, int type, int nscount,
272         char ** nsip, unsigned char ** outpacket, struct resolv_answer * a) attribute_hidden;
273
274 extern int __encode_dotted(const char * dotted, unsigned char * dest, int maxlen) attribute_hidden;
275 extern int __decode_dotted(const unsigned char * message, int offset,
276         char * dest, int maxlen) attribute_hidden;
277 extern int __length_dotted(const unsigned char * message, int offset) attribute_hidden;
278 extern int __encode_header(struct resolv_header * h, unsigned char * dest, int maxlen) attribute_hidden;
279 extern int __decode_header(unsigned char * data, struct resolv_header * h) attribute_hidden;
280 extern int __encode_question(struct resolv_question * q,
281         unsigned char * dest, int maxlen) attribute_hidden;
282 extern int __decode_question(unsigned char * message, int offset,
283         struct resolv_question * q);
284 extern int __encode_answer(struct resolv_answer * a,
285         unsigned char * dest, int maxlen) attribute_hidden;
286 extern int __decode_answer(unsigned char * message, int offset,
287         struct resolv_answer * a) attribute_hidden;
288 extern int __length_question(unsigned char * message, int offset) attribute_hidden;
289 extern int __open_nameservers(void) attribute_hidden;
290 extern void __close_nameservers(void) attribute_hidden;
291 extern int __dn_expand(const u_char *, const u_char *, const u_char *,
292         char *, int);
293 extern int __ns_name_uncompress_internal(const u_char *, const u_char *,
294                 const u_char *, char *, size_t) attribute_hidden;
295 extern int __ns_name_ntop_internal(const u_char *, char *, size_t) attribute_hidden;
296 extern int __ns_name_unpack_internal(const u_char *, const u_char *, const u_char *,
297                u_char *, size_t) attribute_hidden;
298
299
300 extern int __gethostent_r (struct hostent *__restrict __result_buf,
301                          char *__restrict __buf, size_t __buflen,
302                          struct hostent **__restrict __result,
303                          int *__restrict __h_errnop) attribute_hidden;
304
305 #ifdef L_encodeh
306 int attribute_hidden __encode_header(struct resolv_header *h, unsigned char *dest, int maxlen)
307 {
308         if (maxlen < HFIXEDSZ)
309                 return -1;
310
311         dest[0] = (h->id & 0xff00) >> 8;
312         dest[1] = (h->id & 0x00ff) >> 0;
313         dest[2] = (h->qr ? 0x80 : 0) |
314                 ((h->opcode & 0x0f) << 3) |
315                 (h->aa ? 0x04 : 0) |
316                 (h->tc ? 0x02 : 0) |
317                 (h->rd ? 0x01 : 0);
318         dest[3] = (h->ra ? 0x80 : 0) | (h->rcode & 0x0f);
319         dest[4] = (h->qdcount & 0xff00) >> 8;
320         dest[5] = (h->qdcount & 0x00ff) >> 0;
321         dest[6] = (h->ancount & 0xff00) >> 8;
322         dest[7] = (h->ancount & 0x00ff) >> 0;
323         dest[8] = (h->nscount & 0xff00) >> 8;
324         dest[9] = (h->nscount & 0x00ff) >> 0;
325         dest[10] = (h->arcount & 0xff00) >> 8;
326         dest[11] = (h->arcount & 0x00ff) >> 0;
327
328         return HFIXEDSZ;
329 }
330 #endif
331
332 #ifdef L_decodeh
333 int attribute_hidden __decode_header(unsigned char *data, struct resolv_header *h)
334 {
335         h->id = (data[0] << 8) | data[1];
336         h->qr = (data[2] & 0x80) ? 1 : 0;
337         h->opcode = (data[2] >> 3) & 0x0f;
338         h->aa = (data[2] & 0x04) ? 1 : 0;
339         h->tc = (data[2] & 0x02) ? 1 : 0;
340         h->rd = (data[2] & 0x01) ? 1 : 0;
341         h->ra = (data[3] & 0x80) ? 1 : 0;
342         h->rcode = data[3] & 0x0f;
343         h->qdcount = (data[4] << 8) | data[5];
344         h->ancount = (data[6] << 8) | data[7];
345         h->nscount = (data[8] << 8) | data[9];
346         h->arcount = (data[10] << 8) | data[11];
347
348         return HFIXEDSZ;
349 }
350 #endif
351
352 #ifdef L_encoded
353 /* Encode a dotted string into nameserver transport-level encoding.
354    This routine is fairly dumb, and doesn't attempt to compress
355    the data */
356
357 int attribute_hidden __encode_dotted(const char *dotted, unsigned char *dest, int maxlen)
358 {
359         int used = 0;
360
361         while (dotted && *dotted) {
362                 char *c = __strchr(dotted, '.');
363                 int l = c ? c - dotted : __strlen(dotted);
364
365                 if (l >= (maxlen - used - 1))
366                         return -1;
367
368                 dest[used++] = l;
369                 __memcpy(dest + used, dotted, l);
370                 used += l;
371
372                 if (c)
373                         dotted = c + 1;
374                 else
375                         break;
376         }
377
378         if (maxlen < 1)
379                 return -1;
380
381         dest[used++] = 0;
382
383         return used;
384 }
385 #endif
386
387 #ifdef L_decoded
388 /* Decode a dotted string from nameserver transport-level encoding.
389    This routine understands compressed data. */
390
391 int attribute_hidden __decode_dotted(const unsigned char *data, int offset,
392                                   char *dest, int maxlen)
393 {
394         int l;
395         int measure = 1;
396         int total = 0;
397         int used = 0;
398
399         if (!data)
400                 return -1;
401
402         while ((l=data[offset++])) {
403                 if (measure)
404                     total++;
405                 if ((l & 0xc0) == (0xc0)) {
406                         if (measure)
407                                 total++;
408                         /* compressed item, redirect */
409                         offset = ((l & 0x3f) << 8) | data[offset];
410                         measure = 0;
411                         continue;
412                 }
413
414                 if ((used + l + 1) >= maxlen)
415                         return -1;
416
417                 __memcpy(dest + used, data + offset, l);
418                 offset += l;
419                 used += l;
420                 if (measure)
421                         total += l;
422
423                 if (data[offset] != 0)
424                         dest[used++] = '.';
425                 else
426                         dest[used++] = '\0';
427         }
428
429         /* The null byte must be counted too */
430         if (measure) {
431             total++;
432         }
433
434         DPRINTF("Total decode len = %d\n", total);
435
436         return total;
437 }
438 #endif
439
440 #ifdef L_lengthd
441
442 int attribute_hidden __length_dotted(const unsigned char *data, int offset)
443 {
444         int orig_offset = offset;
445         int l;
446
447         if (!data)
448                 return -1;
449
450         while ((l = data[offset++])) {
451
452                 if ((l & 0xc0) == (0xc0)) {
453                         offset++;
454                         break;
455                 }
456
457                 offset += l;
458         }
459
460         return offset - orig_offset;
461 }
462 #endif
463
464 #ifdef L_encodeq
465 int attribute_hidden __encode_question(struct resolv_question *q,
466                                         unsigned char *dest, int maxlen)
467 {
468         int i;
469
470         i = __encode_dotted(q->dotted, dest, maxlen);
471         if (i < 0)
472                 return i;
473
474         dest += i;
475         maxlen -= i;
476
477         if (maxlen < 4)
478                 return -1;
479
480         dest[0] = (q->qtype & 0xff00) >> 8;
481         dest[1] = (q->qtype & 0x00ff) >> 0;
482         dest[2] = (q->qclass & 0xff00) >> 8;
483         dest[3] = (q->qclass & 0x00ff) >> 0;
484
485         return i + 4;
486 }
487 #endif
488
489 #ifdef L_decodeq
490 int __decode_question(unsigned char *message, int offset,
491                                         struct resolv_question *q)
492 {
493         char temp[256];
494         int i;
495
496         i = __decode_dotted(message, offset, temp, sizeof(temp));
497         if (i < 0)
498                 return i;
499
500         offset += i;
501
502         q->dotted = __strdup(temp);
503         q->qtype = (message[offset + 0] << 8) | message[offset + 1];
504         q->qclass = (message[offset + 2] << 8) | message[offset + 3];
505
506         return i + 4;
507 }
508 #endif
509
510 #ifdef L_lengthq
511 int attribute_hidden __length_question(unsigned char *message, int offset)
512 {
513         int i;
514
515         i = __length_dotted(message, offset);
516         if (i < 0)
517                 return i;
518
519         return i + 4;
520 }
521 #endif
522
523 #ifdef L_encodea
524 int attribute_hidden __encode_answer(struct resolv_answer *a, unsigned char *dest, int maxlen)
525 {
526         int i;
527
528         i = __encode_dotted(a->dotted, dest, maxlen);
529         if (i < 0)
530                 return i;
531
532         dest += i;
533         maxlen -= i;
534
535         if (maxlen < (RRFIXEDSZ+a->rdlength))
536                 return -1;
537
538         *dest++ = (a->atype & 0xff00) >> 8;
539         *dest++ = (a->atype & 0x00ff) >> 0;
540         *dest++ = (a->aclass & 0xff00) >> 8;
541         *dest++ = (a->aclass & 0x00ff) >> 0;
542         *dest++ = (a->ttl & 0xff000000) >> 24;
543         *dest++ = (a->ttl & 0x00ff0000) >> 16;
544         *dest++ = (a->ttl & 0x0000ff00) >> 8;
545         *dest++ = (a->ttl & 0x000000ff) >> 0;
546         *dest++ = (a->rdlength & 0xff00) >> 8;
547         *dest++ = (a->rdlength & 0x00ff) >> 0;
548         __memcpy(dest, a->rdata, a->rdlength);
549
550         return i + RRFIXEDSZ + a->rdlength;
551 }
552 #endif
553
554 #ifdef L_decodea
555 int attribute_hidden __decode_answer(unsigned char *message, int offset,
556                                   struct resolv_answer *a)
557 {
558         char temp[256];
559         int i;
560
561         i = __decode_dotted(message, offset, temp, sizeof(temp));
562         if (i < 0)
563                 return i;
564
565         message += offset + i;
566
567         a->dotted = __strdup(temp);
568         a->atype = (message[0] << 8) | message[1];
569         message += 2;
570         a->aclass = (message[0] << 8) | message[1];
571         message += 2;
572         a->ttl = (message[0] << 24) |
573                 (message[1] << 16) | (message[2] << 8) | (message[3] << 0);
574         message += 4;
575         a->rdlength = (message[0] << 8) | message[1];
576         message += 2;
577         a->rdata = message;
578         a->rdoffset = offset + i + RRFIXEDSZ;
579
580         DPRINTF("i=%d,rdlength=%d\n", i, a->rdlength);
581
582         return i + RRFIXEDSZ + a->rdlength;
583 }
584 #endif
585
586 #ifdef L_encodep
587 int __encode_packet(struct resolv_header *h,
588         struct resolv_question **q,
589         struct resolv_answer **an,
590         struct resolv_answer **ns,
591         struct resolv_answer **ar,
592         unsigned char *dest, int maxlen)
593 {
594         int i, total = 0;
595         int j;
596
597         i = __encode_header(h, dest, maxlen);
598         if (i < 0)
599                 return i;
600
601         dest += i;
602         maxlen -= i;
603         total += i;
604
605         for (j = 0; j < h->qdcount; j++) {
606                 i = __encode_question(q[j], dest, maxlen);
607                 if (i < 0)
608                         return i;
609                 dest += i;
610                 maxlen -= i;
611                 total += i;
612         }
613
614         for (j = 0; j < h->ancount; j++) {
615                 i = __encode_answer(an[j], dest, maxlen);
616                 if (i < 0)
617                         return i;
618                 dest += i;
619                 maxlen -= i;
620                 total += i;
621         }
622         for (j = 0; j < h->nscount; j++) {
623                 i = __encode_answer(ns[j], dest, maxlen);
624                 if (i < 0)
625                         return i;
626                 dest += i;
627                 maxlen -= i;
628                 total += i;
629         }
630         for (j = 0; j < h->arcount; j++) {
631                 i = __encode_answer(ar[j], dest, maxlen);
632                 if (i < 0)
633                         return i;
634                 dest += i;
635                 maxlen -= i;
636                 total += i;
637         }
638
639         return total;
640 }
641 #endif
642
643 #ifdef L_decodep
644 int __decode_packet(unsigned char *data, struct resolv_header *h)
645 {
646         return __decode_header(data, h);
647 }
648 #endif
649
650 #ifdef L_formquery
651 int __form_query(int id, const char *name, int type, unsigned char *packet,
652                            int maxlen)
653 {
654         struct resolv_header h;
655         struct resolv_question q;
656         int i, j;
657
658         __memset(&h, 0, sizeof(h));
659         h.id = id;
660         h.qdcount = 1;
661
662         q.dotted = (char *) name;
663         q.qtype = type;
664         q.qclass = C_IN; /* CLASS_IN */
665
666         i = __encode_header(&h, packet, maxlen);
667         if (i < 0)
668                 return i;
669
670         j = __encode_question(&q, packet + i, maxlen - i);
671         if (j < 0)
672                 return j;
673
674         return i + j;
675 }
676 #endif
677
678 #if defined(L_dnslookup) || defined(L_gethostent)
679 #ifdef __UCLIBC_HAS_THREADS__
680 # include <pthread.h>
681 static pthread_mutex_t mylock = PTHREAD_MUTEX_INITIALIZER;
682 #endif
683 #define LOCK    __pthread_mutex_lock(&mylock)
684 #define UNLOCK  __pthread_mutex_unlock(&mylock)
685 #endif
686
687 #ifdef L_dnslookup
688
689 /* Just for the record, having to lock __dns_lookup() just for these two globals
690  * is pretty lame.  I think these two variables can probably be de-global-ized,
691  * which should eliminate the need for doing locking here...  Needs a closer
692  * look anyways. */
693 static int ns=0, id=1;
694
695 int attribute_hidden __dns_lookup(const char *name, int type, int nscount, char **nsip,
696                            unsigned char **outpacket, struct resolv_answer *a)
697 {
698         int i, j, len, fd, pos, rc;
699         struct timeval tv;
700         fd_set fds;
701         struct resolv_header h;
702         struct resolv_question q;
703         struct resolv_answer ma;
704         int first_answer = 1;
705         int retries = 0;
706         unsigned char * packet = malloc(PACKETSZ);
707         char *dns, *lookup = malloc(MAXDNAME);
708         int variant = -1;
709         struct sockaddr_in sa;
710         int local_ns = -1, local_id = -1;
711 #ifdef __UCLIBC_HAS_IPV6__
712         int v6;
713         struct sockaddr_in6 sa6;
714 #endif
715
716         fd = -1;
717
718         if (!packet || !lookup || !nscount)
719             goto fail;
720
721         DPRINTF("Looking up type %d answer for '%s'\n", type, name);
722
723         /* Mess with globals while under lock */
724         LOCK;
725         local_ns = ns % nscount;
726         local_id = id;
727         UNLOCK;
728
729         while (retries < MAX_RETRIES) {
730                 if (fd != -1)
731                         __close(fd);
732
733                 __memset(packet, 0, PACKETSZ);
734
735                 __memset(&h, 0, sizeof(h));
736
737                 ++local_id;
738                 local_id &= 0xffff;
739                 h.id = local_id;
740                 dns = nsip[local_ns];
741
742                 h.qdcount = 1;
743                 h.rd = 1;
744
745                 DPRINTF("encoding header\n", h.rd);
746
747                 i = __encode_header(&h, packet, PACKETSZ);
748                 if (i < 0)
749                         goto fail;
750
751                 __strncpy(lookup,name,MAXDNAME);
752                 if (variant >= 0) {
753                         BIGLOCK;
754                         if (variant < __searchdomains) {
755                                 strncat(lookup,".", MAXDNAME);
756                                 strncat(lookup,__searchdomain[variant], MAXDNAME);
757                         }
758                         BIGUNLOCK;
759                 }
760                 DPRINTF("lookup name: %s\n", lookup);
761                 q.dotted = (char *)lookup;
762                 q.qtype = type;
763                 q.qclass = C_IN; /* CLASS_IN */
764
765                 j = __encode_question(&q, packet+i, PACKETSZ-i);
766                 if (j < 0)
767                         goto fail;
768
769                 len = i + j;
770
771                 DPRINTF("On try %d, sending query to port %d of machine %s\n",
772                                 retries+1, NAMESERVER_PORT, dns);
773
774 #ifdef __UCLIBC_HAS_IPV6__
775                 v6 = inet_pton(AF_INET6, dns, &sa6.sin6_addr) > 0;
776                 fd = __socket(v6 ? AF_INET6 : AF_INET, SOCK_DGRAM, IPPROTO_UDP);
777 #else
778                 fd = __socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
779 #endif
780                 if (fd < 0) {
781                     retries++;
782                     continue;
783                 }
784
785                 /* Connect to the UDP socket so that asyncronous errors are returned */
786 #ifdef __UCLIBC_HAS_IPV6__
787                 if (v6) {
788                     sa6.sin6_family = AF_INET6;
789                     sa6.sin6_port = htons(NAMESERVER_PORT);
790                     /* sa6.sin6_addr is already here */
791                     rc = connect(fd, (struct sockaddr *) &sa6, sizeof(sa6));
792                 } else {
793 #endif
794                     sa.sin_family = AF_INET;
795                     sa.sin_port = htons(NAMESERVER_PORT);
796                     sa.sin_addr.s_addr = inet_addr(dns);
797                     rc = connect(fd, (struct sockaddr *) &sa, sizeof(sa));
798 #ifdef __UCLIBC_HAS_IPV6__
799                 }
800 #endif
801                 if (rc < 0) {
802                     if (errno == ENETUNREACH) {
803                         /* routing error, presume not transient */
804                         goto tryall;
805                     } else
806                         /* retry */
807                         retries++;
808                         continue;
809                 }
810
811                 DPRINTF("Transmitting packet of length %d, id=%d, qr=%d\n",
812                                 len, h.id, h.qr);
813
814                 send(fd, packet, len, 0);
815
816                 FD_ZERO(&fds);
817                 FD_SET(fd, &fds);
818                 tv.tv_sec = REPLY_TIMEOUT;
819                 tv.tv_usec = 0;
820                 if (select(fd + 1, &fds, NULL, NULL, &tv) <= 0) {
821                     DPRINTF("Timeout\n");
822
823                         /* timed out, so retry send and receive,
824                          * to next nameserver on queue */
825                         goto tryall;
826                 }
827
828                 len = recv(fd, packet, 512, 0);
829                 if (len < HFIXEDSZ) {
830                         /* too short ! */
831                         goto again;
832                 }
833
834                 __decode_header(packet, &h);
835
836                 DPRINTF("id = %d, qr = %d\n", h.id, h.qr);
837
838                 if ((h.id != local_id) || (!h.qr)) {
839                         /* unsolicited */
840                         goto again;
841                 }
842
843
844                 DPRINTF("Got response %s\n", "(i think)!");
845                 DPRINTF("qrcount=%d,ancount=%d,nscount=%d,arcount=%d\n",
846                                 h.qdcount, h.ancount, h.nscount, h.arcount);
847                 DPRINTF("opcode=%d,aa=%d,tc=%d,rd=%d,ra=%d,rcode=%d\n",
848                                 h.opcode, h.aa, h.tc, h.rd, h.ra, h.rcode);
849
850                 if ((h.rcode) || (h.ancount < 1)) {
851                         /* negative result, not present */
852                         goto again;
853                 }
854
855                 pos = HFIXEDSZ;
856
857                 for (j = 0; j < h.qdcount; j++) {
858                         DPRINTF("Skipping question %d at %d\n", j, pos);
859                         i = __length_question(packet, pos);
860                         DPRINTF("Length of question %d is %d\n", j, i);
861                         if (i < 0)
862                                 goto again;
863                         pos += i;
864                 }
865                 DPRINTF("Decoding answer at pos %d\n", pos);
866
867                 first_answer = 1;
868                 for (j=0;j<h.ancount;j++,pos += i)
869                 {
870                     i = __decode_answer(packet, pos, &ma);
871
872                     if (i<0) {
873                         DPRINTF("failed decode %d\n", i);
874                         goto again;
875                     }
876
877                     if ( first_answer )
878                     {
879                         ma.buf = a->buf;
880                         ma.buflen = a->buflen;
881                         ma.add_count = a->add_count;
882                         __memcpy(a, &ma, sizeof(ma));
883                         if (a->atype != T_SIG && (0 == a->buf || (type != T_A && type != T_AAAA)))
884                         {
885                             break;
886                         }
887                         if (a->atype != type)
888                         {
889                             free(a->dotted);
890                             continue;
891                         }
892                         a->add_count = h.ancount - j - 1;
893                         if ((a->rdlength + sizeof(struct in_addr*)) * a->add_count > a->buflen)
894                         {
895                             break;
896                         }
897                         a->add_count = 0;
898                         first_answer = 0;
899                     }
900                     else
901                     {
902                         free(ma.dotted);
903                         if (ma.atype != type)
904                         {
905                             continue;
906                         }
907                         if (a->rdlength != ma.rdlength)
908                         {
909                             free(a->dotted);
910                             DPRINTF("Answer address len(%u) differs from original(%u)\n",
911                                     ma.rdlength, a->rdlength);
912                             goto again;
913                         }
914                         __memcpy(a->buf + (a->add_count * ma.rdlength), ma.rdata, ma.rdlength);
915                         ++a->add_count;
916                     }
917                 }
918
919                 DPRINTF("Answer name = |%s|\n", a->dotted);
920                 DPRINTF("Answer type = |%d|\n", a->atype);
921
922                 __close(fd);
923
924                 if (outpacket)
925                         *outpacket = packet;
926                 else
927                         free(packet);
928                 free(lookup);
929
930                 /* Mess with globals while under lock */
931                 LOCK;
932                 ns = local_ns;
933                 id = local_id;
934                 UNLOCK;
935
936                 return (len);                           /* success! */
937
938           tryall:
939                 /* if there are other nameservers, give them a go,
940                    otherwise return with error */
941                 {
942                     variant = -1;
943                     local_ns = (local_ns + 1) % nscount;
944                     if (local_ns == 0)
945                       retries++;
946
947                     continue;
948                 }
949
950           again:
951                 /* if there are searchdomains, try them or fallback as passed */
952                 {
953                     int sdomains;
954                     BIGLOCK;
955                     sdomains=__searchdomains;
956                     BIGUNLOCK;
957
958                     if (variant < sdomains - 1) {
959                         /* next search */
960                         variant++;
961                     } else {
962                         /* next server, first search */
963                         local_ns = (local_ns + 1) % nscount;
964                         if (local_ns == 0)
965                           retries++;
966
967                         variant = -1;
968                     }
969                 }
970         }
971
972 fail:
973         if (fd != -1)
974             __close(fd);
975         if (lookup)
976             free(lookup);
977         if (packet)
978             free(packet);
979         h_errno = NETDB_INTERNAL;
980         /* Mess with globals while under lock */
981         if (local_ns != -1) {
982             LOCK;
983             ns = local_ns;
984             id = local_id;
985             UNLOCK;
986         }
987         return -1;
988 }
989 #endif
990
991 #ifdef L_opennameservers
992
993 int __nameservers;
994 char * __nameserver[MAX_SERVERS];
995 int __searchdomains;
996 char * __searchdomain[MAX_SEARCH];
997 #ifdef __UCLIBC_HAS_THREADS__
998 # include <pthread.h>
999 pthread_mutex_t __resolv_lock = PTHREAD_MUTEX_INITIALIZER;
1000 #endif
1001
1002 /*
1003  *      we currently read formats not quite the same as that on normal
1004  *      unix systems, we can have a list of nameservers after the keyword.
1005  */
1006
1007 int attribute_hidden __open_nameservers()
1008 {
1009         FILE *fp;
1010         int i;
1011 #define RESOLV_ARGS 5
1012         char szBuffer[128], *p, *argv[RESOLV_ARGS];
1013         int argc;
1014
1015         BIGLOCK;
1016         if (__nameservers > 0) {
1017             BIGUNLOCK;
1018             return 0;
1019         }
1020
1021         if ((fp = fopen("/etc/resolv.conf", "r")) ||
1022                         (fp = fopen("/etc/config/resolv.conf", "r")))
1023         {
1024
1025                 while (fgets(szBuffer, sizeof(szBuffer), fp) != NULL) {
1026
1027                         for (p = szBuffer; *p && isspace(*p); p++)
1028                                 /* skip white space */;
1029                         if (*p == '\0' || *p == '\n' || *p == '#') /* skip comments etc */
1030                                 continue;
1031                         argc = 0;
1032                         while (*p && argc < RESOLV_ARGS) {
1033                                 argv[argc++] = p;
1034                                 while (*p && !isspace(*p) && *p != '\n')
1035                                         p++;
1036                                 while (*p && (isspace(*p) || *p == '\n')) /* remove spaces */
1037                                         *p++ = '\0';
1038                         }
1039
1040                         if (__strcmp(argv[0], "nameserver") == 0) {
1041                                 for (i = 1; i < argc && __nameservers < MAX_SERVERS; i++) {
1042                                         __nameserver[__nameservers++] = __strdup(argv[i]);
1043                                         DPRINTF("adding nameserver %s\n", argv[i]);
1044                                 }
1045                         }
1046
1047                         /* domain and search are mutually exclusive, the last one wins */
1048                         if (__strcmp(argv[0],"domain")==0 || __strcmp(argv[0],"search")==0) {
1049                                 while (__searchdomains > 0) {
1050                                         free(__searchdomain[--__searchdomains]);
1051                                         __searchdomain[__searchdomains] = NULL;
1052                                 }
1053                                 for (i=1; i < argc && __searchdomains < MAX_SEARCH; i++) {
1054                                         __searchdomain[__searchdomains++] = __strdup(argv[i]);
1055                                         DPRINTF("adding search %s\n", argv[i]);
1056                                 }
1057                         }
1058                 }
1059                 fclose(fp);
1060                 DPRINTF("nameservers = %d\n", __nameservers);
1061                 BIGUNLOCK;
1062                 return 0;
1063         }
1064         DPRINTF("failed to open %s\n", "resolv.conf");
1065         h_errno = NO_RECOVERY;
1066         BIGUNLOCK;
1067         return -1;
1068 }
1069 #endif
1070
1071
1072 #ifdef L_closenameservers
1073
1074 void attribute_hidden __close_nameservers(void)
1075 {
1076         BIGLOCK;
1077         while (__nameservers > 0) {
1078                 free(__nameserver[--__nameservers]);
1079                 __nameserver[__nameservers] = NULL;
1080         }
1081         while (__searchdomains > 0) {
1082                 free(__searchdomain[--__searchdomains]);
1083                 __searchdomain[__searchdomains] = NULL;
1084         }
1085         BIGUNLOCK;
1086 }
1087 #endif
1088
1089 #ifdef L_gethostbyname
1090
1091 struct hostent attribute_hidden *__gethostbyname(const char *name)
1092 {
1093         static struct hostent h;
1094         static char buf[sizeof(struct in_addr) +
1095                         sizeof(struct in_addr *)*2 +
1096                         sizeof(char *)*(ALIAS_DIM) + 384/*namebuffer*/ + 32/* margin */];
1097         struct hostent *hp;
1098
1099         __gethostbyname_r(name, &h, buf, sizeof(buf), &hp, &h_errno);
1100
1101         return hp;
1102 }
1103 strong_alias(__gethostbyname,gethostbyname)
1104 #endif
1105
1106 #ifdef L_gethostbyname2
1107
1108 #ifndef __UCLIBC_HAS_IPV6__
1109 extern struct hostent *__gethostbyname (__const char *__name) attribute_hidden;
1110 #else
1111 extern int __gethostbyname2_r (__const char *__restrict __name, int __af,
1112                              struct hostent *__restrict __result_buf,
1113                              char *__restrict __buf, size_t __buflen,
1114                              struct hostent **__restrict __result,
1115                              int *__restrict __h_errnop) attribute_hidden;
1116 #endif
1117
1118 struct hostent *gethostbyname2(const char *name, int family)
1119 {
1120 #ifndef __UCLIBC_HAS_IPV6__
1121         return family == AF_INET ? __gethostbyname(name) : (struct hostent*)0;
1122 #else /* __UCLIBC_HAS_IPV6__ */
1123         static struct hostent h;
1124         static char buf[sizeof(struct in6_addr) +
1125                         sizeof(struct in6_addr *)*2 +
1126                         sizeof(char *)*(ALIAS_DIM) + 384/*namebuffer*/ + 32/* margin */];
1127         struct hostent *hp;
1128
1129         __gethostbyname2_r(name, family, &h, buf, sizeof(buf), &hp, &h_errno);
1130
1131         return hp;
1132 #endif /* __UCLIBC_HAS_IPV6__ */
1133 }
1134 #endif
1135
1136
1137
1138 #ifdef L_res_init
1139 struct __res_state _res;
1140
1141 int res_init(void)
1142 {
1143         struct __res_state *rp = &(_res);
1144
1145         __close_nameservers();
1146         __open_nameservers();
1147         rp->retrans = RES_TIMEOUT;
1148         rp->retry = 4;
1149         rp->options = RES_INIT;
1150         rp->id = (u_int) random();
1151         rp->nsaddr.sin_addr.s_addr = INADDR_ANY;
1152         rp->nsaddr.sin_family = AF_INET;
1153         rp->nsaddr.sin_port = htons(NAMESERVER_PORT);
1154         rp->ndots = 1;
1155         /** rp->pfcode = 0; **/
1156         rp->_vcsock = -1;
1157         /** rp->_flags = 0; **/
1158         /** rp->qhook = NULL; **/
1159         /** rp->rhook = NULL; **/
1160         /** rp->_u._ext.nsinit = 0; **/
1161
1162         BIGLOCK;
1163         if(__searchdomains) {
1164                 int i;
1165                 for(i=0; i<__searchdomains; i++) {
1166                         rp->dnsrch[i] = __searchdomain[i];
1167                 }
1168         }
1169
1170         if(__nameservers) {
1171                 int i;
1172                 struct in_addr a;
1173                 for(i=0; i<__nameservers; i++) {
1174                         if (inet_aton(__nameserver[i], &a)) {
1175                                 rp->nsaddr_list[i].sin_addr = a;
1176                                 rp->nsaddr_list[i].sin_family = AF_INET;
1177                                 rp->nsaddr_list[i].sin_port = htons(NAMESERVER_PORT);
1178                         }
1179                 }
1180         }
1181         rp->nscount = __nameservers;
1182         BIGUNLOCK;
1183
1184         return(0);
1185 }
1186
1187 void res_close( void )
1188 {
1189         return;
1190 }
1191
1192 #endif
1193
1194
1195 #ifdef L_res_query
1196
1197 #ifndef MIN
1198 #define MIN(x, y)       ((x) < (y) ? (x) : (y))
1199 #endif
1200
1201 int res_query(const char *dname, int class, int type,
1202               unsigned char *answer, int anslen)
1203 {
1204         int i;
1205         unsigned char * packet = 0;
1206         struct resolv_answer a;
1207         int __nameserversXX;
1208         char ** __nameserverXX;
1209
1210         __open_nameservers();
1211         if (!dname || class != 1 /* CLASS_IN */) {
1212                 h_errno = NO_RECOVERY;
1213                 return(-1);
1214         }
1215
1216         __memset((char *) &a, '\0', sizeof(a));
1217
1218         BIGLOCK;
1219         __nameserversXX=__nameservers;
1220         __nameserverXX=__nameserver;
1221         BIGUNLOCK;
1222         i = __dns_lookup(dname, type, __nameserversXX, __nameserverXX, &packet, &a);
1223
1224         if (i < 0) {
1225                 h_errno = TRY_AGAIN;
1226                 return(-1);
1227         }
1228
1229         free(a.dotted);
1230
1231         if (a.atype == type) { /* CNAME*/
1232                 int len = MIN(anslen, i);
1233                 __memcpy(answer, packet, len);
1234                 if (packet)
1235                         free(packet);
1236                 return(len);
1237         }
1238         if (packet)
1239                 free(packet);
1240         return i;
1241 }
1242
1243 /*
1244  * Formulate a normal query, send, and retrieve answer in supplied buffer.
1245  * Return the size of the response on success, -1 on error.
1246  * If enabled, implement search rules until answer or unrecoverable failure
1247  * is detected.  Error code, if any, is left in h_errno.
1248  */
1249 int res_search(name, class, type, answer, anslen)
1250         const char *name;       /* domain name */
1251         int class, type;        /* class and type of query */
1252         u_char *answer;         /* buffer to put answer */
1253         int anslen;             /* size of answer */
1254 {
1255         const char *cp, * const *domain;
1256         HEADER *hp = (HEADER *)(void *)answer;
1257         u_int dots;
1258         int trailing_dot, ret, saved_herrno;
1259         int got_nodata = 0, got_servfail = 0, tried_as_is = 0;
1260
1261         if ((!name || !answer) || ((_res.options & RES_INIT) == 0 && res_init() == -1)) {
1262                 h_errno = NETDB_INTERNAL;
1263                 return (-1);
1264         }
1265
1266         errno = 0;
1267         h_errno = HOST_NOT_FOUND;       /* default, if we never query */
1268         dots = 0;
1269         for (cp = name; *cp; cp++)
1270                 dots += (*cp == '.');
1271         trailing_dot = 0;
1272         if (cp > name && *--cp == '.')
1273                 trailing_dot++;
1274
1275         /*
1276          * If there are dots in the name already, let's just give it a try
1277          * 'as is'.  The threshold can be set with the "ndots" option.
1278          */
1279         saved_herrno = -1;
1280         if (dots >= _res.ndots) {
1281                 ret = res_querydomain(name, NULL, class, type, answer, anslen);
1282                 if (ret > 0)
1283                         return (ret);
1284                 saved_herrno = h_errno;
1285                 tried_as_is++;
1286         }
1287
1288         /*
1289          * We do at least one level of search if
1290          *      - there is no dot and RES_DEFNAME is set, or
1291          *      - there is at least one dot, there is no trailing dot,
1292          *        and RES_DNSRCH is set.
1293          */
1294         if ((!dots && (_res.options & RES_DEFNAMES)) ||
1295             (dots && !trailing_dot && (_res.options & RES_DNSRCH))) {
1296                 int done = 0;
1297
1298                 for (domain = (const char * const *)_res.dnsrch;
1299                    *domain && !done;
1300                    domain++) {
1301
1302                         ret = res_querydomain(name, *domain, class, type,
1303                             answer, anslen);
1304                         if (ret > 0)
1305                                 return (ret);
1306
1307                         /*
1308                          * If no server present, give up.
1309                          * If name isn't found in this domain,
1310                          * keep trying higher domains in the search list
1311                          * (if that's enabled).
1312                          * On a NO_DATA error, keep trying, otherwise
1313                          * a wildcard entry of another type could keep us
1314                          * from finding this entry higher in the domain.
1315                          * If we get some other error (negative answer or
1316                          * server failure), then stop searching up,
1317                          * but try the input name below in case it's
1318                          * fully-qualified.
1319                          */
1320                         if (errno == ECONNREFUSED) {
1321                                 h_errno = TRY_AGAIN;
1322                                 return (-1);
1323                         }
1324
1325                         switch (h_errno) {
1326                         case NO_DATA:
1327                                 got_nodata++;
1328                                 /* FALLTHROUGH */
1329                         case HOST_NOT_FOUND:
1330                                 /* keep trying */
1331                                 break;
1332                         case TRY_AGAIN:
1333                                 if (hp->rcode == SERVFAIL) {
1334                                         /* try next search element, if any */
1335                                         got_servfail++;
1336                                         break;
1337                                 }
1338                                 /* FALLTHROUGH */
1339                         default:
1340                                 /* anything else implies that we're done */
1341                                 done++;
1342                         }
1343                         /*
1344                          * if we got here for some reason other than DNSRCH,
1345                          * we only wanted one iteration of the loop, so stop.
1346                          */
1347                         if (!(_res.options & RES_DNSRCH))
1348                                 done++;
1349                 }
1350         }
1351
1352         /*
1353          * if we have not already tried the name "as is", do that now.
1354          * note that we do this regardless of how many dots were in the
1355          * name or whether it ends with a dot.
1356          */
1357         if (!tried_as_is) {
1358                 ret = res_querydomain(name, NULL, class, type, answer, anslen);
1359                 if (ret > 0)
1360                         return (ret);
1361         }
1362
1363         /*
1364          * if we got here, we didn't satisfy the search.
1365          * if we did an initial full query, return that query's h_errno
1366          * (note that we wouldn't be here if that query had succeeded).
1367          * else if we ever got a nodata, send that back as the reason.
1368          * else send back meaningless h_errno, that being the one from
1369          * the last DNSRCH we did.
1370          */
1371         if (saved_herrno != -1)
1372                 h_errno = saved_herrno;
1373         else if (got_nodata)
1374                 h_errno = NO_DATA;
1375         else if (got_servfail)
1376                 h_errno = TRY_AGAIN;
1377         return (-1);
1378 }
1379
1380 /*
1381  * Perform a call on res_query on the concatenation of name and domain,
1382  * removing a trailing dot from name if domain is NULL.
1383  */
1384 int res_querydomain(name, domain, class, type, answer, anslen)
1385         const char *name, *domain;
1386         int class, type;        /* class and type of query */
1387         u_char *answer;         /* buffer to put answer */
1388         int anslen;             /* size of answer */
1389 {
1390         char nbuf[MAXDNAME];
1391         const char *longname = nbuf;
1392         size_t n, d;
1393
1394         if ((!name || !answer) || ((_res.options & RES_INIT) == 0 && res_init() == -1)) {
1395                 h_errno = NETDB_INTERNAL;
1396                 return (-1);
1397         }
1398
1399 #ifdef DEBUG
1400         if (_res.options & RES_DEBUG)
1401                 __printf(";; res_querydomain(%s, %s, %d, %d)\n",
1402                         name, domain?domain:"<Nil>", class, type);
1403 #endif
1404         if (domain == NULL) {
1405                 /*
1406                  * Check for trailing '.';
1407                  * copy without '.' if present.
1408                  */
1409                 n = __strlen(name);
1410                 if (n + 1 > sizeof(nbuf)) {
1411                         h_errno = NO_RECOVERY;
1412                         return (-1);
1413                 }
1414                 if (n > 0 && name[--n] == '.') {
1415                         __strncpy(nbuf, name, n);
1416                         nbuf[n] = '\0';
1417                 } else
1418                         longname = name;
1419         } else {
1420                 n = __strlen(name);
1421                 d = __strlen(domain);
1422                 if (n + 1 + d + 1 > sizeof(nbuf)) {
1423                         h_errno = NO_RECOVERY;
1424                         return (-1);
1425                 }
1426                 snprintf(nbuf, sizeof(nbuf), "%s.%s", name, domain);
1427         }
1428         return (res_query(longname, class, type, answer, anslen));
1429 }
1430
1431 /* res_mkquery */
1432 /* res_send */
1433 /* dn_comp */
1434 /* dn_expand */
1435 #endif
1436
1437 #ifdef L_gethostbyaddr
1438 extern int __gethostbyaddr_r (__const void *__restrict __addr, __socklen_t __len,
1439                             int __type,
1440                             struct hostent *__restrict __result_buf,
1441                             char *__restrict __buf, size_t __buflen,
1442                             struct hostent **__restrict __result,
1443                             int *__restrict __h_errnop) attribute_hidden;
1444
1445 struct hostent attribute_hidden *__gethostbyaddr (const void *addr, socklen_t len, int type)
1446 {
1447         static struct hostent h;
1448         static char buf[
1449 #ifndef __UCLIBC_HAS_IPV6__
1450                 sizeof(struct in_addr) + sizeof(struct in_addr *)*2 +
1451 #else
1452                 sizeof(struct in6_addr) + sizeof(struct in6_addr *)*2 +
1453 #endif /* __UCLIBC_HAS_IPV6__ */
1454                 sizeof(char *)*(ALIAS_DIM) + 384/*namebuffer*/ + 32/* margin */];
1455         struct hostent *hp;
1456
1457         __gethostbyaddr_r(addr, len, type, &h, buf, sizeof(buf), &hp, &h_errno);
1458
1459         return hp;
1460 }
1461 strong_alias(__gethostbyaddr,gethostbyaddr)
1462 #endif
1463
1464
1465 #ifdef L_read_etc_hosts_r
1466
1467 void attribute_hidden __open_etc_hosts(FILE **fp)
1468 {
1469         if ((*fp = fopen("/etc/hosts", "r")) == NULL) {
1470                 *fp = fopen("/etc/config/hosts", "r");
1471         }
1472         return;
1473 }
1474
1475 int attribute_hidden __read_etc_hosts_r(FILE * fp, const char * name, int type,
1476                      enum etc_hosts_action action,
1477                      struct hostent * result_buf,
1478                      char * buf, size_t buflen,
1479                      struct hostent ** result,
1480                      int * h_errnop)
1481 {
1482         struct in_addr  *in=NULL;
1483         struct in_addr  **addr_list=NULL;
1484 #ifdef __UCLIBC_HAS_IPV6__
1485         struct in6_addr *in6=NULL;
1486         struct in6_addr **addr_list6=NULL;
1487 #endif /* __UCLIBC_HAS_IPV6__ */
1488         char *cp, **alias;
1489         int aliases, i, ret=HOST_NOT_FOUND;
1490
1491         if (buflen < sizeof(char *)*(ALIAS_DIM))
1492                 return ERANGE;
1493         alias=(char **)buf;
1494         buf+=sizeof(char **)*(ALIAS_DIM);
1495         buflen-=sizeof(char **)*(ALIAS_DIM);
1496
1497         if (action!=GETHOSTENT) {
1498 #ifdef __UCLIBC_HAS_IPV6__
1499                 char *p=buf;
1500                 size_t len=buflen;
1501 #endif /* __UCLIBC_HAS_IPV6__ */
1502                 *h_errnop=NETDB_INTERNAL;
1503                 if (buflen < sizeof(*in))
1504                         return ERANGE;
1505                 in=(struct in_addr*)buf;
1506                 buf+=sizeof(*in);
1507                 buflen-=sizeof(*in);
1508
1509                 if (buflen < sizeof(*addr_list)*2)
1510                         return ERANGE;
1511                 addr_list=(struct in_addr **)buf;
1512                 buf+=sizeof(*addr_list)*2;
1513                 buflen-=sizeof(*addr_list)*2;
1514
1515 #ifdef __UCLIBC_HAS_IPV6__
1516                 if (len < sizeof(*in6))
1517                         return ERANGE;
1518                 in6=(struct in6_addr*)p;
1519                 p+=sizeof(*in6);
1520                 len-=sizeof(*in6);
1521
1522                 if (len < sizeof(*addr_list6)*2)
1523                         return ERANGE;
1524                 addr_list6=(struct in6_addr**)p;
1525                 p+=sizeof(*addr_list6)*2;
1526                 len-=sizeof(*addr_list6)*2;
1527
1528                 if (len < buflen) {
1529                         buflen=len;
1530                         buf=p;
1531                 }
1532 #endif /* __UCLIBC_HAS_IPV6__ */
1533
1534                 if (buflen < 80)
1535                         return ERANGE;
1536
1537                 __open_etc_hosts(&fp);
1538                 if (fp == NULL) {
1539                         result=NULL;
1540                         return errno;
1541                 }
1542         }
1543
1544         *h_errnop=HOST_NOT_FOUND;
1545         while (fgets(buf, buflen, fp)) {
1546                 if ((cp = __strchr(buf, '#')))
1547                         *cp = '\0';
1548                 DPRINTF("Looking at: %s\n", buf);
1549                 aliases = 0;
1550
1551                 cp = buf;
1552                 while (*cp) {
1553                         while (*cp && isspace(*cp))
1554                                 *cp++ = '\0';
1555                         if (!*cp)
1556                                 continue;
1557                         if (aliases < (2+MAX_ALIASES))
1558                                 alias[aliases++] = cp;
1559                         while (*cp && !isspace(*cp))
1560                                 cp++;
1561                 }
1562                 alias[aliases] = 0;
1563
1564                 if (aliases < 2)
1565                         continue; /* syntax error really */
1566
1567                 if (action==GETHOSTENT) {
1568                         /* Return whatever the next entry happens to be. */
1569                         break;
1570                 } else if (action==GET_HOSTS_BYADDR) {
1571                         if (__strcmp(name, alias[0]) != 0)
1572                                 continue;
1573                 } else {
1574                         /* GET_HOSTS_BYNAME */
1575                         for (i = 1; i < aliases; i++)
1576                                 if (__strcasecmp(name, alias[i]) == 0)
1577                                         break;
1578                         if (i >= aliases)
1579                                 continue;
1580                 }
1581
1582                 if (type == AF_INET && inet_pton(AF_INET, alias[0], in) > 0) {
1583                         DPRINTF("Found INET\n");
1584                         addr_list[0] = in;
1585                         addr_list[1] = 0;
1586                         result_buf->h_name = alias[1];
1587                         result_buf->h_addrtype = AF_INET;
1588                         result_buf->h_length = sizeof(*in);
1589                         result_buf->h_addr_list = (char**) addr_list;
1590                         result_buf->h_aliases = alias + 2;
1591                         *result=result_buf;
1592                         ret=NETDB_SUCCESS;
1593 #ifdef __UCLIBC_HAS_IPV6__
1594         } else if (type == AF_INET6 && inet_pton(AF_INET6, alias[0], in6) > 0) {
1595                         DPRINTF("Found INET6\n");
1596                         addr_list6[0] = in6;
1597                         addr_list6[1] = 0;
1598                         result_buf->h_name = alias[1];
1599                         result_buf->h_addrtype = AF_INET6;
1600                         result_buf->h_length = sizeof(*in6);
1601                         result_buf->h_addr_list = (char**) addr_list6;
1602                         result_buf->h_aliases = alias + 2;
1603                         *result=result_buf;
1604                         ret=NETDB_SUCCESS;
1605 #endif /* __UCLIBC_HAS_IPV6__ */
1606                 } else {
1607                         DPRINTF("Error\n");
1608                         ret=TRY_AGAIN;
1609                         break; /* bad ip address */
1610         }
1611
1612                 if (action!=GETHOSTENT) {
1613                         fclose(fp);
1614                 }
1615                 return ret;
1616         }
1617         if (action!=GETHOSTENT) {
1618                 fclose(fp);
1619         }
1620         return ret;
1621 }
1622 #endif
1623
1624
1625 #ifdef L_gethostent
1626
1627 static int __stay_open;
1628 static FILE * __gethostent_fp;
1629
1630 void endhostent (void)
1631 {
1632     LOCK;
1633     __stay_open = 0;
1634     if (__gethostent_fp) {
1635         fclose(__gethostent_fp);
1636     }
1637     UNLOCK;
1638 }
1639
1640 void sethostent (int stay_open)
1641 {
1642     LOCK;
1643     __stay_open = stay_open;
1644     UNLOCK;
1645 }
1646
1647 int attribute_hidden __gethostent_r(struct hostent *result_buf, char *buf, size_t buflen,
1648         struct hostent **result, int *h_errnop)
1649 {
1650     int ret;
1651
1652     LOCK;
1653     if (__gethostent_fp == NULL) {
1654         __open_etc_hosts(&__gethostent_fp);
1655         if (__gethostent_fp == NULL) {
1656             UNLOCK;
1657             *result=NULL;
1658             return 0;
1659         }
1660     }
1661
1662     ret = __read_etc_hosts_r(__gethostent_fp, NULL, AF_INET, GETHOSTENT,
1663                    result_buf, buf, buflen, result, h_errnop);
1664     if (__stay_open==0) {
1665         fclose(__gethostent_fp);
1666     }
1667     UNLOCK;
1668     return(ret);
1669 }
1670 strong_alias(__gethostent_r,gethostent_r)
1671
1672 struct hostent *gethostent (void)
1673 {
1674     static struct hostent h;
1675     static char buf[
1676 #ifndef __UCLIBC_HAS_IPV6__
1677             sizeof(struct in_addr) + sizeof(struct in_addr *)*2 +
1678 #else
1679             sizeof(struct in6_addr) + sizeof(struct in6_addr *)*2 +
1680 #endif /* __UCLIBC_HAS_IPV6__ */
1681                 sizeof(char *)*(ALIAS_DIM) +
1682             80/*namebuffer*/ + 2/* margin */];
1683     struct hostent *host;
1684
1685     LOCK;
1686     __gethostent_r(&h, buf, sizeof(buf), &host, &h_errno);
1687     UNLOCK;
1688     return(host);
1689 }
1690 #endif
1691
1692 #ifdef L_get_hosts_byname_r
1693
1694 int attribute_hidden __get_hosts_byname_r(const char * name, int type,
1695                             struct hostent * result_buf,
1696                             char * buf, size_t buflen,
1697                             struct hostent ** result,
1698                             int * h_errnop)
1699 {
1700         return(__read_etc_hosts_r(NULL, name, type, GET_HOSTS_BYNAME,
1701                     result_buf, buf, buflen, result, h_errnop));
1702 }
1703 #endif
1704
1705 #ifdef L_get_hosts_byaddr_r
1706
1707 int attribute_hidden __get_hosts_byaddr_r(const char * addr, int len, int type,
1708                             struct hostent * result_buf,
1709                             char * buf, size_t buflen,
1710                             struct hostent ** result,
1711                             int * h_errnop)
1712 {
1713 #ifndef __UCLIBC_HAS_IPV6__
1714         char    ipaddr[INET_ADDRSTRLEN];
1715 #else
1716         char    ipaddr[INET6_ADDRSTRLEN];
1717 #endif /* __UCLIBC_HAS_IPV6__ */
1718
1719     switch (type) {
1720         case AF_INET:
1721                 if (len != sizeof(struct in_addr))
1722                         return 0;
1723                 break;
1724 #ifdef __UCLIBC_HAS_IPV6__
1725         case AF_INET6:
1726                 if (len != sizeof(struct in6_addr))
1727                         return 0;
1728                 break;
1729 #endif /* __UCLIBC_HAS_IPV6__ */
1730         default:
1731                 return 0;
1732         }
1733
1734         inet_ntop(type, addr, ipaddr, sizeof(ipaddr));
1735
1736         return(__read_etc_hosts_r(NULL, ipaddr, type, GET_HOSTS_BYADDR,
1737                     result_buf, buf, buflen, result, h_errnop));
1738 }
1739 #endif
1740
1741 #ifdef L_getnameinfo
1742
1743 #ifndef min
1744 # define min(x,y) (((x) > (y)) ? (y) : (x))
1745 #endif /* min */
1746
1747 int attribute_hidden __getnameinfo (const struct sockaddr *sa, socklen_t addrlen, char *host,
1748              socklen_t hostlen, char *serv, socklen_t servlen,
1749              unsigned int flags)
1750 {
1751         int serrno = errno;
1752         int ok = 0;
1753         struct hostent *h = NULL;
1754         char domain[256];
1755
1756         if (flags & ~(NI_NUMERICHOST|NI_NUMERICSERV|NI_NOFQDN|NI_NAMEREQD|NI_DGRAM))
1757                 return EAI_BADFLAGS;
1758
1759         if (sa == NULL || addrlen < sizeof (sa_family_t))
1760                 return EAI_FAMILY;
1761
1762         switch (sa->sa_family) {
1763         case AF_LOCAL:
1764                 break;
1765         case AF_INET:
1766                 if (addrlen < sizeof (struct sockaddr_in))
1767                         return EAI_FAMILY;
1768                 break;
1769 #ifdef __UCLIBC_HAS_IPV6__
1770         case AF_INET6:
1771                 if (addrlen < sizeof (struct sockaddr_in6))
1772                         return EAI_FAMILY;
1773                 break;
1774 #endif /* __UCLIBC_HAS_IPV6__ */
1775         default:
1776                 return EAI_FAMILY;
1777         }
1778
1779         if (host != NULL && hostlen > 0)
1780                 switch (sa->sa_family) {
1781                 case AF_INET:
1782 #ifdef __UCLIBC_HAS_IPV6__
1783                 case AF_INET6:
1784 #endif /* __UCLIBC_HAS_IPV6__ */
1785                         if (!(flags & NI_NUMERICHOST)) {
1786 #ifdef __UCLIBC_HAS_IPV6__
1787                                 if (sa->sa_family == AF_INET6)
1788                                         h = __gethostbyaddr ((const void *)
1789                                                 &(((const struct sockaddr_in6 *) sa)->sin6_addr),
1790                                                 sizeof(struct in6_addr), AF_INET6);
1791                                 else
1792 #endif /* __UCLIBC_HAS_IPV6__ */
1793                     h = __gethostbyaddr ((const void *) &(((const struct sockaddr_in *)sa)->sin_addr),
1794                                           sizeof(struct in_addr), AF_INET);
1795
1796                                 if (h) {
1797                                         char *c;
1798                                         if ((flags & NI_NOFQDN)
1799                                             && (getdomainname (domain, sizeof(domain)) == 0)
1800                                             && (c = strstr (h->h_name, domain))
1801                                             && (c != h->h_name) && (*(--c) == '.')) {
1802                                                 __strncpy (host, h->h_name,
1803                                                         min(hostlen, (size_t) (c - h->h_name)));
1804                                                 host[min(hostlen - 1, (size_t) (c - h->h_name))] = '\0';
1805                                                 ok = 1;
1806                                         } else {
1807                                                 __strncpy (host, h->h_name, hostlen);
1808                                                 ok = 1;
1809                                         }
1810                                  }
1811                         }
1812
1813                         if (!ok) {
1814                                 if (flags & NI_NAMEREQD) {
1815                                         errno = serrno;
1816                                         return EAI_NONAME;
1817                                 } else {
1818                                         const char *c;
1819 #ifdef __UCLIBC_HAS_IPV6__
1820                                         if (sa->sa_family == AF_INET6) {
1821                                                 const struct sockaddr_in6 *sin6p;
1822
1823                                                 sin6p = (const struct sockaddr_in6 *) sa;
1824
1825                                                 c = inet_ntop (AF_INET6,
1826                                                         (const void *) &sin6p->sin6_addr, host, hostlen);
1827 #if 0
1828                                                 /* Does scope id need to be supported? */
1829                                                 uint32_t scopeid;
1830                                                 scopeid = sin6p->sin6_scope_id;
1831                                                 if (scopeid != 0) {
1832                                                         /* Buffer is >= IFNAMSIZ+1.  */
1833                                                         char scopebuf[IFNAMSIZ + 1];
1834                                                         char *scopeptr;
1835                                                         int ni_numericscope = 0;
1836                                                         size_t real_hostlen = __strnlen (host, hostlen);
1837                                                         size_t scopelen = 0;
1838
1839                                                         scopebuf[0] = SCOPE_DELIMITER;
1840                                                         scopebuf[1] = '\0';
1841                                                         scopeptr = &scopebuf[1];
1842
1843                                                         if (IN6_IS_ADDR_LINKLOCAL (&sin6p->sin6_addr)
1844                                                             || IN6_IS_ADDR_MC_LINKLOCAL (&sin6p->sin6_addr)) {
1845                                                                 if (if_indextoname (scopeid, scopeptr) == NULL)
1846                                                                         ++ni_numericscope;
1847                                                                 else
1848                                                                         scopelen = __strlen (scopebuf);
1849                                                         } else {
1850                                                                 ++ni_numericscope;
1851                                                         }
1852
1853                                                         if (ni_numericscope)
1854                                                                 scopelen = 1 + snprintf (scopeptr,
1855                                                                         (scopebuf
1856                                                                         + sizeof scopebuf
1857                                                                         - scopeptr),
1858                                                                         "%u", scopeid);
1859
1860                                                         if (real_hostlen + scopelen + 1 > hostlen)
1861                                                                 return EAI_SYSTEM;
1862                                                         __memcpy (host + real_hostlen, scopebuf, scopelen + 1);
1863                                                 }
1864 #endif
1865                                         } else
1866 #endif /* __UCLIBC_HAS_IPV6__ */
1867                                                 c = inet_ntop (AF_INET, (const void *)
1868                                                         &(((const struct sockaddr_in *) sa)->sin_addr),
1869                                                         host, hostlen);
1870
1871                                         if (c == NULL) {
1872                                                 errno = serrno;
1873                                                 return EAI_SYSTEM;
1874                                         }
1875                                 }
1876                                 ok = 1;
1877                         }
1878                         break;
1879
1880                 case AF_LOCAL:
1881                         if (!(flags & NI_NUMERICHOST)) {
1882                                 struct utsname utsname;
1883
1884                                 if (!uname (&utsname)) {
1885                                         __strncpy (host, utsname.nodename, hostlen);
1886                                         break;
1887                                 };
1888                         };
1889
1890                         if (flags & NI_NAMEREQD) {
1891                                 errno = serrno;
1892                                 return EAI_NONAME;
1893                         }
1894
1895                         __strncpy (host, "localhost", hostlen);
1896                         break;
1897
1898                 default:
1899                         return EAI_FAMILY;
1900         }
1901
1902         if (serv && (servlen > 0)) {
1903                 switch (sa->sa_family) {
1904                 case AF_INET:
1905 #ifdef __UCLIBC_HAS_IPV6__
1906                 case AF_INET6:
1907 #endif /* __UCLIBC_HAS_IPV6__ */
1908                         if (!(flags & NI_NUMERICSERV)) {
1909                                 struct servent *s;
1910                                 s = getservbyport (((const struct sockaddr_in *) sa)->sin_port,
1911                                       ((flags & NI_DGRAM) ? "udp" : "tcp"));
1912                                 if (s) {
1913                                         __strncpy (serv, s->s_name, servlen);
1914                                         break;
1915                                 }
1916                         }
1917                         snprintf (serv, servlen, "%d",
1918                                 ntohs (((const struct sockaddr_in *) sa)->sin_port));
1919                         break;
1920
1921                 case AF_LOCAL:
1922                         __strncpy (serv, ((const struct sockaddr_un *) sa)->sun_path, servlen);
1923                         break;
1924                 }
1925         }
1926         if (host && (hostlen > 0))
1927                 host[hostlen-1] = 0;
1928         if (serv && (servlen > 0))
1929                 serv[servlen-1] = 0;
1930         errno = serrno;
1931         return 0;
1932 }
1933 strong_alias(__getnameinfo,getnameinfo)
1934 #endif
1935
1936
1937 #ifdef L_gethostbyname_r
1938
1939 int attribute_hidden __gethostbyname_r(const char * name,
1940                             struct hostent * result_buf,
1941                             char * buf, size_t buflen,
1942                             struct hostent ** result,
1943                             int * h_errnop)
1944 {
1945         struct in_addr *in;
1946         struct in_addr **addr_list;
1947         char **alias;
1948         unsigned char *packet;
1949         struct resolv_answer a;
1950         int i;
1951         int __nameserversXX;
1952         char ** __nameserverXX;
1953
1954         __open_nameservers();
1955         *result=NULL;
1956         if (!name)
1957                 return EINVAL;
1958
1959         /* do /etc/hosts first */
1960         {
1961                 int old_errno = errno;  /* Save the old errno and reset errno */
1962                 __set_errno(0);                 /* to check for missing /etc/hosts. */
1963
1964                 if ((i=__get_hosts_byname_r(name, AF_INET, result_buf,
1965                                 buf, buflen, result, h_errnop))==0)
1966                         return i;
1967                 switch (*h_errnop) {
1968                         case HOST_NOT_FOUND:
1969                         case NO_ADDRESS:
1970                                 break;
1971                         case NETDB_INTERNAL:
1972                                 if (errno == ENOENT) {
1973                                         break;
1974                                 }
1975                                 /* else fall through */
1976                         default:
1977                                 return i;
1978                 }
1979                 __set_errno(old_errno);
1980         }
1981
1982         DPRINTF("Nothing found in /etc/hosts\n");
1983
1984         *h_errnop = NETDB_INTERNAL;
1985         if (buflen < sizeof(*in))
1986                 return ERANGE;
1987         in=(struct in_addr*)buf;
1988         buf+=sizeof(*in);
1989         buflen-=sizeof(*in);
1990
1991         if (buflen < sizeof(*addr_list)*2)
1992                 return ERANGE;
1993         addr_list=(struct in_addr**)buf;
1994         buf+=sizeof(*addr_list)*2;
1995         buflen-=sizeof(*addr_list)*2;
1996
1997         addr_list[0] = in;
1998         addr_list[1] = 0;
1999
2000         if (buflen < sizeof(char *)*(ALIAS_DIM))
2001                 return ERANGE;
2002         alias=(char **)buf;
2003         buf+=sizeof(char **)*(ALIAS_DIM);
2004         buflen-=sizeof(char **)*(ALIAS_DIM);
2005
2006         if (buflen<256)
2007                 return ERANGE;
2008         __strncpy(buf, name, buflen);
2009
2010         alias[0] = buf;
2011         alias[1] = NULL;
2012
2013         /* First check if this is already an address */
2014         if (inet_aton(name, in)) {
2015             result_buf->h_name = buf;
2016             result_buf->h_addrtype = AF_INET;
2017             result_buf->h_length = sizeof(*in);
2018             result_buf->h_addr_list = (char **) addr_list;
2019             result_buf->h_aliases = alias;
2020             *result=result_buf;
2021             *h_errnop = NETDB_SUCCESS;
2022             return NETDB_SUCCESS;
2023         }
2024
2025         for (;;) {
2026
2027             BIGLOCK;
2028             __nameserversXX=__nameservers;
2029             __nameserverXX=__nameserver;
2030             BIGUNLOCK;
2031             a.buf = buf;
2032             a.buflen = buflen;
2033             a.add_count = 0;
2034             i = __dns_lookup(name, T_A, __nameserversXX, __nameserverXX, &packet, &a);
2035
2036             if (i < 0) {
2037                 *h_errnop = HOST_NOT_FOUND;
2038                 DPRINTF("__dns_lookup\n");
2039                 return TRY_AGAIN;
2040             }
2041
2042             if ((a.rdlength + sizeof(struct in_addr*)) * a.add_count + 256 > buflen)
2043             {
2044                 free(a.dotted);
2045                 free(packet);
2046                 *h_errnop = NETDB_INTERNAL;
2047                 DPRINTF("buffer too small for all addresses\n");
2048                 return ERANGE;
2049             }
2050             else if(a.add_count > 0)
2051             {
2052                 __memmove(buf - sizeof(struct in_addr*)*2, buf, a.add_count * a.rdlength);
2053                 addr_list = (struct in_addr**)(buf + a.add_count * a.rdlength);
2054                 addr_list[0] = in;
2055                 for (i = a.add_count-1; i>=0; --i)
2056                     addr_list[i+1] = (struct in_addr*)(buf - sizeof(struct in_addr*)*2 + a.rdlength * i);
2057                 addr_list[a.add_count + 1] = 0;
2058                 buflen -= (((char*)&(addr_list[a.add_count + 2])) - buf);
2059                 buf = (char*)&addr_list[a.add_count + 2];
2060             }
2061
2062             __strncpy(buf, a.dotted, buflen);
2063             free(a.dotted);
2064
2065             if (a.atype == T_A) { /* ADDRESS */
2066                 __memcpy(in, a.rdata, sizeof(*in));
2067                 result_buf->h_name = buf;
2068                 result_buf->h_addrtype = AF_INET;
2069                 result_buf->h_length = sizeof(*in);
2070                 result_buf->h_addr_list = (char **) addr_list;
2071 #ifdef __UCLIBC_MJN3_ONLY__
2072 #warning TODO -- generate the full list
2073 #endif
2074                 result_buf->h_aliases = alias; /* TODO: generate the full list */
2075                 free(packet);
2076                 break;
2077             } else {
2078                 free(packet);
2079                 *h_errnop=HOST_NOT_FOUND;
2080                 return TRY_AGAIN;
2081             }
2082         }
2083
2084         *result=result_buf;
2085         *h_errnop = NETDB_SUCCESS;
2086         return NETDB_SUCCESS;
2087 }
2088 strong_alias(__gethostbyname_r,gethostbyname_r)
2089 #endif
2090
2091 #ifdef L_gethostbyname2_r
2092
2093 int attribute_hidden __gethostbyname2_r(const char *name, int family,
2094                             struct hostent * result_buf,
2095                             char * buf, size_t buflen,
2096                             struct hostent ** result,
2097                             int * h_errnop)
2098 {
2099 #ifndef __UCLIBC_HAS_IPV6__
2100         return family == (AF_INET)? __gethostbyname_r(name, result_buf,
2101                 buf, buflen, result, h_errnop) : HOST_NOT_FOUND;
2102 #else /* __UCLIBC_HAS_IPV6__ */
2103         struct in6_addr *in;
2104         struct in6_addr **addr_list;
2105         unsigned char *packet;
2106         struct resolv_answer a;
2107         int i;
2108         int nest = 0;
2109         int __nameserversXX;
2110         char ** __nameserverXX;
2111
2112         if (family == AF_INET)
2113                 return __gethostbyname_r(name, result_buf, buf, buflen, result, h_errnop);
2114
2115         if (family != AF_INET6)
2116                 return EINVAL;
2117
2118         __open_nameservers();
2119         *result=NULL;
2120         if (!name)
2121                 return EINVAL;
2122
2123         /* do /etc/hosts first */
2124         {
2125                 int old_errno = errno;  /* Save the old errno and reset errno */
2126                 __set_errno(0);                 /* to check for missing /etc/hosts. */
2127
2128                 if ((i=__get_hosts_byname_r(name, AF_INET, result_buf,
2129                                 buf, buflen, result, h_errnop))==0)
2130                         return i;
2131                 switch (*h_errnop) {
2132                         case HOST_NOT_FOUND:
2133                         case NO_ADDRESS:
2134                                 break;
2135                         case NETDB_INTERNAL:
2136                                 if (errno == ENOENT) {
2137                                         break;
2138                                 }
2139                                 /* else fall through */
2140                         default:
2141                                 return i;
2142                 }
2143                 __set_errno(old_errno);
2144         }
2145
2146         DPRINTF("Nothing found in /etc/hosts\n");
2147
2148         *h_errnop = NETDB_INTERNAL;
2149         if (buflen < sizeof(*in))
2150                 return ERANGE;
2151         in=(struct in6_addr*)buf;
2152         buf+=sizeof(*in);
2153         buflen-=sizeof(*in);
2154
2155         if (buflen < sizeof(*addr_list)*2)
2156                 return ERANGE;
2157         addr_list=(struct in6_addr**)buf;
2158         buf+=sizeof(*addr_list)*2;
2159         buflen-=sizeof(*addr_list)*2;
2160
2161         addr_list[0] = in;
2162         addr_list[1] = 0;
2163
2164         if (buflen<256)
2165                 return ERANGE;
2166         __strncpy(buf, name, buflen);
2167
2168         /* First check if this is already an address */
2169         if (inet_pton(AF_INET6, name, in)) {
2170             result_buf->h_name = buf;
2171             result_buf->h_addrtype = AF_INET6;
2172             result_buf->h_length = sizeof(*in);
2173             result_buf->h_addr_list = (char **) addr_list;
2174             *result=result_buf;
2175             *h_errnop = NETDB_SUCCESS;
2176             return NETDB_SUCCESS;
2177         }
2178
2179         __memset((char *) &a, '\0', sizeof(a));
2180
2181         for (;;) {
2182         BIGLOCK;
2183         __nameserversXX=__nameservers;
2184         __nameserverXX=__nameserver;
2185         BIGUNLOCK;
2186
2187                 i = __dns_lookup(buf, T_AAAA, __nameserversXX, __nameserverXX, &packet, &a);
2188
2189                 if (i < 0) {
2190                         *h_errnop = HOST_NOT_FOUND;
2191                         return TRY_AGAIN;
2192                 }
2193
2194                 __strncpy(buf, a.dotted, buflen);
2195                 free(a.dotted);
2196
2197                 if (a.atype == T_CNAME) {               /* CNAME */
2198                         DPRINTF("Got a CNAME in gethostbyname()\n");
2199                         i = __decode_dotted(packet, a.rdoffset, buf, buflen);
2200                         free(packet);
2201
2202                         if (i < 0) {
2203                                 *h_errnop = NO_RECOVERY;
2204                                 return -1;
2205                         }
2206                         if (++nest > MAX_RECURSE) {
2207                                 *h_errnop = NO_RECOVERY;
2208                                 return -1;
2209                         }
2210                         continue;
2211                 } else if (a.atype == T_AAAA) { /* ADDRESS */
2212                         __memcpy(in, a.rdata, sizeof(*in));
2213                         result_buf->h_name = buf;
2214                         result_buf->h_addrtype = AF_INET6;
2215                         result_buf->h_length = sizeof(*in);
2216                         result_buf->h_addr_list = (char **) addr_list;
2217                         free(packet);
2218                         break;
2219                 } else {
2220                         free(packet);
2221                         *h_errnop=HOST_NOT_FOUND;
2222                         return TRY_AGAIN;
2223                 }
2224         }
2225
2226         *result=result_buf;
2227         *h_errnop = NETDB_SUCCESS;
2228         return NETDB_SUCCESS;
2229 #endif /* __UCLIBC_HAS_IPV6__ */
2230 }
2231 strong_alias(__gethostbyname2_r,gethostbyname2_r)
2232 #endif
2233
2234 #ifdef L_gethostbyaddr_r
2235 int attribute_hidden __gethostbyaddr_r (const void *addr, socklen_t len, int type,
2236                             struct hostent * result_buf,
2237                             char * buf, size_t buflen,
2238                             struct hostent ** result,
2239                             int * h_errnop)
2240
2241 {
2242         struct in_addr *in;
2243         struct in_addr **addr_list;
2244 #ifdef __UCLIBC_HAS_IPV6__
2245         char *qp;
2246         size_t plen;
2247         struct in6_addr *in6;
2248         struct in6_addr **addr_list6;
2249 #endif /* __UCLIBC_HAS_IPV6__ */
2250         unsigned char *packet;
2251         struct resolv_answer a;
2252         int i;
2253         int nest = 0;
2254         int __nameserversXX;
2255         char ** __nameserverXX;
2256
2257         *result=NULL;
2258         if (!addr)
2259                 return EINVAL;
2260
2261         __memset((char *) &a, '\0', sizeof(a));
2262
2263         switch (type) {
2264                 case AF_INET:
2265                         if (len != sizeof(struct in_addr))
2266                                 return EINVAL;
2267                         break;
2268 #ifdef __UCLIBC_HAS_IPV6__
2269                 case AF_INET6:
2270                         if (len != sizeof(struct in6_addr))
2271                                 return EINVAL;
2272                         break;
2273 #endif /* __UCLIBC_HAS_IPV6__ */
2274                 default:
2275                         return EINVAL;
2276         }
2277
2278         /* do /etc/hosts first */
2279         if ((i=__get_hosts_byaddr_r(addr, len, type, result_buf,
2280                                   buf, buflen, result, h_errnop))==0)
2281                 return i;
2282         switch (*h_errnop) {
2283                 case HOST_NOT_FOUND:
2284                 case NO_ADDRESS:
2285                         break;
2286                 default:
2287                         return i;
2288         }
2289
2290         __open_nameservers();
2291
2292 #ifdef __UCLIBC_HAS_IPV6__
2293         qp=buf;
2294         plen=buflen;
2295 #endif /* __UCLIBC_HAS_IPV6__ */
2296
2297         *h_errnop = NETDB_INTERNAL;
2298         if (buflen < sizeof(*in))
2299                 return ERANGE;
2300         in=(struct in_addr*)buf;
2301         buf+=sizeof(*in);
2302         buflen-=sizeof(*in);
2303
2304         if (buflen < sizeof(*addr_list)*2)
2305                 return ERANGE;
2306         addr_list=(struct in_addr**)buf;
2307         buf+=sizeof(*addr_list)*2;
2308         buflen-=sizeof(*addr_list)*2;
2309
2310 #ifdef __UCLIBC_HAS_IPV6__
2311         if (plen < sizeof(*in6))
2312                 return ERANGE;
2313         in6=(struct in6_addr*)qp;
2314         qp+=sizeof(*in6);
2315         plen-=sizeof(*in6);
2316
2317         if (plen < sizeof(*addr_list6)*2)
2318                 return ERANGE;
2319         addr_list6=(struct in6_addr**)qp;
2320         qp+=sizeof(*addr_list6)*2;
2321         plen-=sizeof(*addr_list6)*2;
2322
2323         if (plen < buflen) {
2324                 buflen=plen;
2325                 buf=qp;
2326         }
2327 #endif /* __UCLIBC_HAS_IPV6__ */
2328
2329         if (buflen<256)
2330                 return ERANGE;
2331
2332         if(type == AF_INET) {
2333                 unsigned char *tmp_addr = (unsigned char *)addr;
2334
2335                 __memcpy(&in->s_addr, addr, len);
2336
2337                 addr_list[0] = in;
2338
2339                 __sprintf(buf, "%u.%u.%u.%u.in-addr.arpa",
2340                         tmp_addr[3], tmp_addr[2], tmp_addr[1], tmp_addr[0]);
2341 #ifdef __UCLIBC_HAS_IPV6__
2342         } else {
2343                 __memcpy(in6->s6_addr, addr, len);
2344
2345                 addr_list6[0] = in6;
2346                 qp = buf;
2347
2348                 for (i = len - 1; i >= 0; i--) {
2349                         qp += __sprintf(qp, "%x.%x.", in6->s6_addr[i] & 0xf,
2350                                 (in6->s6_addr[i] >> 4) & 0xf);
2351         }
2352         __strcpy(qp, "ip6.int");
2353 #endif /* __UCLIBC_HAS_IPV6__ */
2354         }
2355
2356         addr_list[1] = 0;
2357
2358         for (;;) {
2359
2360         BIGLOCK;
2361         __nameserversXX=__nameservers;
2362         __nameserverXX=__nameserver;
2363         BIGUNLOCK;
2364                 i = __dns_lookup(buf, T_PTR, __nameserversXX, __nameserverXX, &packet, &a);
2365
2366                 if (i < 0) {
2367                         *h_errnop = HOST_NOT_FOUND;
2368                         return TRY_AGAIN;
2369                 }
2370
2371                 __strncpy(buf, a.dotted, buflen);
2372                 free(a.dotted);
2373
2374                 if (a.atype == T_CNAME) {               /* CNAME */
2375                         DPRINTF("Got a CNAME in gethostbyaddr()\n");
2376                         i = __decode_dotted(packet, a.rdoffset, buf, buflen);
2377                         free(packet);
2378
2379                         if (i < 0) {
2380                                 *h_errnop = NO_RECOVERY;
2381                                 return -1;
2382                         }
2383                         if (++nest > MAX_RECURSE) {
2384                                 *h_errnop = NO_RECOVERY;
2385                                 return -1;
2386                         }
2387                         continue;
2388                 } else if (a.atype == T_PTR) {  /* ADDRESS */
2389                         i = __decode_dotted(packet, a.rdoffset, buf, buflen);
2390                         free(packet);
2391
2392                         result_buf->h_name = buf;
2393                         result_buf->h_addrtype = type;
2394
2395                         if(type == AF_INET) {
2396                                 result_buf->h_length = sizeof(*in);
2397 #ifdef __UCLIBC_HAS_IPV6__
2398                         } else {
2399                                 result_buf->h_length = sizeof(*in6);
2400 #endif /* __UCLIBC_HAS_IPV6__ */
2401                 }
2402
2403                         result_buf->h_addr_list = (char **) addr_list;
2404                         break;
2405                 } else {
2406                         free(packet);
2407                         *h_errnop = NO_ADDRESS;
2408                         return TRY_AGAIN;
2409                 }
2410         }
2411
2412         *result=result_buf;
2413         *h_errnop = NETDB_SUCCESS;
2414         return NETDB_SUCCESS;
2415 }
2416 strong_alias(__gethostbyaddr_r,gethostbyaddr_r)
2417 #endif
2418
2419 #ifdef L_res_comp
2420 /*
2421  * Expand compressed domain name 'comp_dn' to full domain name.
2422  * 'msg' is a pointer to the begining of the message,
2423  * 'eomorig' points to the first location after the message,
2424  * 'exp_dn' is a pointer to a buffer of size 'length' for the result.
2425  * Return size of compressed name or -1 if there was an error.
2426  */
2427 int __dn_expand(const u_char *msg, const u_char *eom, const u_char *src,
2428           char *dst, int dstsiz)
2429 {
2430         int n = __ns_name_uncompress_internal(msg, eom, src, dst, (size_t)dstsiz);
2431
2432         if (n > 0 && dst[0] == '.')
2433                 dst[0] = '\0';
2434         return (n);
2435 }
2436 #endif /* L_res_comp */
2437
2438 #ifdef L_ns_name
2439 /*
2440  * printable(ch)
2441  *      Thinking in noninternationalized USASCII (per the DNS spec),
2442  *      is this character visible and not a space when printed ?
2443  * return:
2444  *      boolean.
2445  */
2446 static int printable(int ch)
2447 {
2448         return (ch > 0x20 && ch < 0x7f);
2449 }
2450
2451 /*
2452  * special(ch)
2453  *      Thinking in noninternationalized USASCII (per the DNS spec),
2454  *      is this characted special ("in need of quoting") ?
2455  * return:
2456  *      boolean.
2457  */
2458 static int special(int ch)
2459 {
2460         switch (ch) {
2461         case 0x22: /* '"' */
2462         case 0x2E: /* '.' */
2463         case 0x3B: /* ';' */
2464         case 0x5C: /* '\\' */
2465         /* Special modifiers in zone files. */
2466         case 0x40: /* '@' */
2467         case 0x24: /* '$' */
2468                 return (1);
2469         default:
2470                 return (0);
2471         }
2472 }
2473
2474 /*
2475  * ns_name_uncompress(msg, eom, src, dst, dstsiz)
2476  *      Expand compressed domain name to presentation format.
2477  * return:
2478  *      Number of bytes read out of `src', or -1 (with errno set).
2479  * note:
2480  *      Root domain returns as "." not "".
2481  */
2482 int attribute_hidden __ns_name_uncompress_internal(const u_char *msg, const u_char *eom,
2483                 const u_char *src, char *dst, size_t dstsiz)
2484 {
2485         u_char tmp[NS_MAXCDNAME];
2486         int n;
2487
2488         if ((n = __ns_name_unpack_internal(msg, eom, src, tmp, sizeof tmp)) == -1)
2489                 return (-1);
2490         if (__ns_name_ntop_internal(tmp, dst, dstsiz) == -1)
2491                 return (-1);
2492         return (n);
2493 }
2494 strong_alias(__ns_name_uncompress_internal,__ns_name_uncompress)
2495
2496
2497 /*
2498  * ns_name_ntop(src, dst, dstsiz)
2499  *      Convert an encoded domain name to printable ascii as per RFC1035.
2500  * return:
2501  *      Number of bytes written to buffer, or -1 (with errno set)
2502  * notes:
2503  *      The root is returned as "."
2504  *      All other domains are returned in non absolute form
2505  */
2506 int attribute_hidden __ns_name_ntop_internal(const u_char *src, char *dst, size_t dstsiz) {
2507         const u_char *cp;
2508         char *dn, *eom;
2509         u_char c;
2510         u_int n;
2511         const char digits[] = "0123456789";
2512
2513         cp = src;
2514         dn = dst;
2515         eom = dst + dstsiz;
2516
2517         while ((n = *cp++) != 0) {
2518                 if ((n & NS_CMPRSFLGS) != 0) {
2519                         /* Some kind of compression pointer. */
2520                         __set_errno (EMSGSIZE);
2521                         return (-1);
2522                 }
2523                 if (dn != dst) {
2524                         if (dn >= eom) {
2525                                 __set_errno (EMSGSIZE);
2526                                 return (-1);
2527                         }
2528                         *dn++ = '.';
2529                 }
2530                 if (dn + n >= eom) {
2531                         __set_errno (EMSGSIZE);
2532                         return (-1);
2533                 }
2534                 for ((void)NULL; n > 0; n--) {
2535                         c = *cp++;
2536                         if (special(c)) {
2537                                 if (dn + 1 >= eom) {
2538                                         __set_errno (EMSGSIZE);
2539                                         return (-1);
2540                                 }
2541                                 *dn++ = '\\';
2542                                 *dn++ = (char)c;
2543                         } else if (!printable(c)) {
2544                                 if (dn + 3 >= eom) {
2545                                         __set_errno (EMSGSIZE);
2546                                         return (-1);
2547                                 }
2548                                 *dn++ = '\\';
2549                                 *dn++ = digits[c / 100];
2550                                 *dn++ = digits[(c % 100) / 10];
2551                                 *dn++ = digits[c % 10];
2552                         } else {
2553                                 if (dn >= eom) {
2554                                         __set_errno (EMSGSIZE);
2555                                         return (-1);
2556                                 }
2557                                 *dn++ = (char)c;
2558                         }
2559                 }
2560         }
2561         if (dn == dst) {
2562                 if (dn >= eom) {
2563                         __set_errno (EMSGSIZE);
2564                         return (-1);
2565                 }
2566                 *dn++ = '.';
2567         }
2568         if (dn >= eom) {
2569                 __set_errno (EMSGSIZE);
2570                 return (-1);
2571         }
2572         *dn++ = '\0';
2573         return (dn - dst);
2574 }
2575 strong_alias(__ns_name_ntop_internal,__ns_name_ntop)
2576
2577 /*
2578  * ns_name_unpack(msg, eom, src, dst, dstsiz)
2579  *      Unpack a domain name from a message, source may be compressed.
2580  * return:
2581  *      -1 if it fails, or consumed octets if it succeeds.
2582  */
2583 int attribute_hidden __ns_name_unpack_internal(const u_char *msg, const u_char *eom, const u_char *src,
2584                u_char *dst, size_t dstsiz)
2585 {
2586         const u_char *srcp, *dstlim;
2587         u_char *dstp;
2588         int n, len, checked;
2589
2590         len = -1;
2591         checked = 0;
2592         dstp = dst;
2593         srcp = src;
2594         dstlim = dst + dstsiz;
2595         if (srcp < msg || srcp >= eom) {
2596                 __set_errno (EMSGSIZE);
2597                 return (-1);
2598         }
2599         /* Fetch next label in domain name. */
2600         while ((n = *srcp++) != 0) {
2601                 /* Check for indirection. */
2602                 switch (n & NS_CMPRSFLGS) {
2603                 case 0:
2604                         /* Limit checks. */
2605                         if (dstp + n + 1 >= dstlim || srcp + n >= eom) {
2606                                 __set_errno (EMSGSIZE);
2607                                 return (-1);
2608                         }
2609                         checked += n + 1;
2610                         *dstp++ = n;
2611                         __memcpy(dstp, srcp, n);
2612                         dstp += n;
2613                         srcp += n;
2614                         break;
2615
2616                 case NS_CMPRSFLGS:
2617                         if (srcp >= eom) {
2618                                 __set_errno (EMSGSIZE);
2619                                 return (-1);
2620                         }
2621                         if (len < 0)
2622                                 len = srcp - src + 1;
2623                         srcp = msg + (((n & 0x3f) << 8) | (*srcp & 0xff));
2624                         if (srcp < msg || srcp >= eom) {  /* Out of range. */
2625                                 __set_errno (EMSGSIZE);
2626                                 return (-1);
2627                         }
2628                         checked += 2;
2629                         /*
2630                          * Check for loops in the compressed name;
2631                          * if we've looked at the whole message,
2632                          * there must be a loop.
2633                          */
2634                         if (checked >= eom - msg) {
2635                                 __set_errno (EMSGSIZE);
2636                                 return (-1);
2637                         }
2638                         break;
2639
2640                 default:
2641                         __set_errno (EMSGSIZE);
2642                         return (-1);                    /* flag error */
2643                 }
2644         }
2645         *dstp = '\0';
2646         if (len < 0)
2647                 len = srcp - src;
2648         return (len);
2649 }
2650 strong_alias(__ns_name_unpack_internal,__ns_name_unpack)
2651 #endif /* L_ns_name */