OSDN Git Service

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