1 /* resolv.c: DNS Resolver
4 * The Silver Hammer Group, Ltd.
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
12 * Fix memory leak and memory corruption.
13 * -- Every name resolution resulted in
14 * a new parse of resolv.conf and new
15 * copy of nameservers allocated by
17 * -- Every name resolution resulted in
18 * a new read of resolv.conf without
19 * resetting index from prior read...
20 * resulting in exceeding array bounds.
22 * Limit nameservers read from resolv.conf
24 * Add "search" domains from resolv.conf
26 * Some systems will return a security
27 * signature along with query answer for
28 * dynamic DNS entries.
29 * -- skip/ignore this answer
31 * Include arpa/nameser.h for defines.
36 * partial IPv6 support (i.e. gethostbyname2() and resolve_address2()
37 * functions added), IPv6 nameservers are also supported.
40 * more IPv6 support (IPv6 support for gethostbyaddr();
41 * address family parameter and improved IPv6 support for get_hosts_byname
42 * and read_etc_hosts; getnameinfo() port from glibc; defined
43 * defined ip6addr_any and in6addr_loopback)
52 #include <sys/socket.h>
53 #include <sys/types.h>
54 #include <netinet/in.h>
55 #include <arpa/inet.h>
61 #include <arpa/nameser.h>
62 #include <sys/utsname.h>
66 #define REPLY_TIMEOUT 10
67 #define MAX_RETRIES 15
75 #define DPRINTF(X,args...) fprintf(stderr, X, ##args)
77 #define DPRINTF(X,args...)
81 struct resolv_header {
83 int qr,opcode,aa,tc,rd,ra,rcode;
90 struct resolv_question {
96 struct resolv_answer {
102 unsigned char * rdata;
106 extern int nameservers;
107 extern char * nameserver[MAX_SERVERS];
108 extern int searchdomains;
109 extern char * searchdomain[MAX_SEARCH];
110 extern struct hostent * get_hosts_byname(const char * name, int type);
111 extern struct hostent * get_hosts_byaddr(const char * addr, int len, int type);
112 extern struct hostent * read_etc_hosts(const char * name, int type, int ip);
113 extern int resolve_address(const char * address, int nscount,
114 char ** nsip, struct in_addr * in);
115 extern int resolve_mailbox(const char * address, int nscount,
116 char ** nsip, struct in_addr * in);
117 extern int dns_lookup(const char * name, int type, int nscount,
118 char ** nsip, unsigned char ** outpacket, struct resolv_answer * a);
120 int encode_dotted(const char * dotted, unsigned char * dest, int maxlen);
121 int decode_dotted(const unsigned char * message, int offset,
122 char * dest, int maxlen);
123 int length_dotted(const unsigned char * message, int offset);
124 int encode_header(struct resolv_header * h, unsigned char * dest, int maxlen);
125 int decode_header(unsigned char * data, struct resolv_header * h);
126 int encode_question(struct resolv_question * q,
127 unsigned char * dest, int maxlen);
128 int decode_question(unsigned char * message, int offset,
129 struct resolv_question * q);
130 int encode_answer(struct resolv_answer * a,
131 unsigned char * dest, int maxlen);
132 int decode_answer(unsigned char * message, int offset,
133 struct resolv_answer * a);
134 int length_question(unsigned char * message, int offset);
135 extern int open_nameservers(void);
139 int encode_header(struct resolv_header *h, unsigned char *dest, int maxlen)
141 if (maxlen < HFIXEDSZ)
144 dest[0] = (h->id & 0xff00) >> 8;
145 dest[1] = (h->id & 0x00ff) >> 0;
146 dest[2] = (h->qr ? 0x80 : 0) |
147 ((h->opcode & 0x0f) << 3) |
151 dest[3] = (h->ra ? 0x80 : 0) | (h->rcode & 0x0f);
152 dest[4] = (h->qdcount & 0xff00) >> 8;
153 dest[5] = (h->qdcount & 0x00ff) >> 0;
154 dest[6] = (h->ancount & 0xff00) >> 8;
155 dest[7] = (h->ancount & 0x00ff) >> 0;
156 dest[8] = (h->nscount & 0xff00) >> 8;
157 dest[9] = (h->nscount & 0x00ff) >> 0;
158 dest[10] = (h->arcount & 0xff00) >> 8;
159 dest[11] = (h->arcount & 0x00ff) >> 0;
166 int decode_header(unsigned char *data, struct resolv_header *h)
168 h->id = (data[0] << 8) | data[1];
169 h->qr = (data[2] & 0x80) ? 1 : 0;
170 h->opcode = (data[2] >> 3) & 0x0f;
171 h->aa = (data[2] & 0x04) ? 1 : 0;
172 h->tc = (data[2] & 0x02) ? 1 : 0;
173 h->rd = (data[2] & 0x01) ? 1 : 0;
174 h->ra = (data[3] & 0x80) ? 1 : 0;
175 h->rcode = data[3] & 0x0f;
176 h->qdcount = (data[4] << 8) | data[5];
177 h->ancount = (data[6] << 8) | data[7];
178 h->nscount = (data[8] << 8) | data[9];
179 h->arcount = (data[10] << 8) | data[11];
186 /* Encode a dotted string into nameserver transport-level encoding.
187 This routine is fairly dumb, and doesn't attempt to compress
190 int encode_dotted(const char *dotted, unsigned char *dest, int maxlen)
194 while (dotted && *dotted) {
195 char *c = strchr(dotted, '.');
196 int l = c ? c - dotted : strlen(dotted);
198 if (l >= (maxlen - used - 1))
202 memcpy(dest + used, dotted, l);
221 /* Decode a dotted string from nameserver transport-level encoding.
222 This routine understands compressed data. */
224 int decode_dotted(const unsigned char *data, int offset,
225 char *dest, int maxlen)
235 while ((l=data[offset++])) {
238 if ((l & 0xc0) == (0xc0)) {
241 /* compressed item, redirect */
242 offset = ((l & 0x3f) << 8) | data[offset];
247 if ((used + l + 1) >= maxlen)
250 memcpy(dest + used, data + offset, l);
256 if (data[offset] != 0)
262 DPRINTF("Total decode len = %d\n", total);
270 int length_dotted(const unsigned char *data, int offset)
272 int orig_offset = offset;
278 while ((l = data[offset++])) {
280 if ((l & 0xc0) == (0xc0)) {
288 return offset - orig_offset;
293 int encode_question(struct resolv_question *q,
294 unsigned char *dest, int maxlen)
298 i = encode_dotted(q->dotted, dest, maxlen);
308 dest[0] = (q->qtype & 0xff00) >> 8;
309 dest[1] = (q->qtype & 0x00ff) >> 0;
310 dest[2] = (q->qclass & 0xff00) >> 8;
311 dest[3] = (q->qclass & 0x00ff) >> 0;
318 int decode_question(unsigned char *message, int offset,
319 struct resolv_question *q)
324 i = decode_dotted(message, offset, temp, sizeof(temp));
330 q->dotted = strdup(temp);
331 q->qtype = (message[offset + 0] << 8) | message[offset + 1];
332 q->qclass = (message[offset + 2] << 8) | message[offset + 3];
339 int length_question(unsigned char *message, int offset)
343 i = length_dotted(message, offset);
352 int encode_answer(struct resolv_answer *a, unsigned char *dest, int maxlen)
356 i = encode_dotted(a->dotted, dest, maxlen);
363 if (maxlen < (RRFIXEDSZ+a->rdlength))
366 *dest++ = (a->atype & 0xff00) >> 8;
367 *dest++ = (a->atype & 0x00ff) >> 0;
368 *dest++ = (a->aclass & 0xff00) >> 8;
369 *dest++ = (a->aclass & 0x00ff) >> 0;
370 *dest++ = (a->ttl & 0xff000000) >> 24;
371 *dest++ = (a->ttl & 0x00ff0000) >> 16;
372 *dest++ = (a->ttl & 0x0000ff00) >> 8;
373 *dest++ = (a->ttl & 0x000000ff) >> 0;
374 *dest++ = (a->rdlength & 0xff00) >> 8;
375 *dest++ = (a->rdlength & 0x00ff) >> 0;
376 memcpy(dest, a->rdata, a->rdlength);
378 return i + RRFIXEDSZ + a->rdlength;
383 int decode_answer(unsigned char *message, int offset,
384 struct resolv_answer *a)
389 i = decode_dotted(message, offset, temp, sizeof(temp));
393 message += offset + i;
395 a->dotted = strdup(temp);
396 a->atype = (message[0] << 8) | message[1];
398 a->aclass = (message[0] << 8) | message[1];
400 a->ttl = (message[0] << 24) |
401 (message[1] << 16) | (message[2] << 8) | (message[3] << 0);
403 a->rdlength = (message[0] << 8) | message[1];
406 a->rdoffset = offset + i + RRFIXEDSZ;
408 DPRINTF("i=%d,rdlength=%d\n", i, a->rdlength);
410 return i + RRFIXEDSZ + a->rdlength;
415 int encode_packet(struct resolv_header *h,
416 struct resolv_question **q,
417 struct resolv_answer **an,
418 struct resolv_answer **ns,
419 struct resolv_answer **ar,
420 unsigned char *dest, int maxlen)
425 i = encode_header(h, dest, maxlen);
433 for (j = 0; j < h->qdcount; j++) {
434 i = encode_question(q[j], dest, maxlen);
442 for (j = 0; j < h->ancount; j++) {
443 i = encode_answer(an[j], dest, maxlen);
450 for (j = 0; j < h->nscount; j++) {
451 i = encode_answer(ns[j], dest, maxlen);
458 for (j = 0; j < h->arcount; j++) {
459 i = encode_answer(ar[j], dest, maxlen);
472 int decode_packet(unsigned char *data, struct resolv_header *h)
474 return decode_header(data, h);
479 int form_query(int id, const char *name, int type, unsigned char *packet,
482 struct resolv_header h;
483 struct resolv_question q;
486 memset(&h, 0, sizeof(h));
490 q.dotted = (char *) name;
492 q.qclass = C_IN; /* CLASS_IN */
494 i = encode_header(&h, packet, maxlen);
498 j = encode_question(&q, packet + i, maxlen - i);
508 int dns_caught_signal = 0;
509 void dns_catch_signal(int signo)
511 dns_caught_signal = 1;
514 int dns_lookup(const char *name, int type, int nscount, char **nsip,
515 unsigned char **outpacket, struct resolv_answer *a)
518 int i, j, len, fd, pos;
520 struct sockaddr_in sa;
521 #ifdef __UCLIBC_HAS_IPV6__
522 struct sockaddr_in6 sa6;
523 #endif /* __UCLIBC_HAS_IPV6__ */
525 __sighandler_t oldhandler;
526 struct resolv_header h;
527 struct resolv_question q;
529 unsigned char * packet = malloc(PACKETSZ);
530 unsigned char * lookup = malloc(MAXDNAME);
532 #ifdef __UCLIBC_HAS_IPV6__
534 #endif /* __UCLIBC_HAS_IPV6__ */
538 if (!packet || !lookup || !nscount)
541 DPRINTF("Looking up type %d answer for '%s'\n", type, name);
545 while (retries++ < MAX_RETRIES) {
546 #ifdef __UCLIBC_HAS_IPV6__
547 v6 = (inet_pton(AF_INET6, nsip[ns], &sa6.sin6_addr) > 0);
548 #endif /* __UCLIBC_HAS_IPV6__ */
553 #ifndef __UCLIBC_HAS_IPV6__
554 fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
555 #else /* __UCLIBC_HAS_IPV6__ */
556 fd = socket(v6 ? AF_INET6 : AF_INET, SOCK_DGRAM, IPPROTO_UDP);
557 #endif /* __UCLIBC_HAS_IPV6__ */
562 memset(packet, 0, PACKETSZ);
564 memset(&h, 0, sizeof(h));
569 DPRINTF("encoding header\n", h.rd);
571 i = encode_header(&h, packet, PACKETSZ);
575 strncpy(lookup,name,MAXDNAME);
576 if (variant < searchdomains && strchr(lookup, '.') == NULL)
578 strncat(lookup,".", MAXDNAME);
579 strncat(lookup,searchdomain[variant], MAXDNAME);
581 DPRINTF("lookup name: %s\n", lookup);
582 q.dotted = (char *)lookup;
584 q.qclass = C_IN; /* CLASS_IN */
586 j = encode_question(&q, packet+i, PACKETSZ-i);
592 DPRINTF("On try %d, sending query to port %d of machine %s\n",
593 retries, NAMESERVER_PORT, nsip[ns]);
595 #ifndef __UCLIBC_HAS_IPV6__
596 sa.sin_family = AF_INET;
597 sa.sin_port = htons(NAMESERVER_PORT);
598 sa.sin_addr.s_addr = inet_addr(nsip[ns]);
599 #else /* __UCLIBC_HAS_IPV6__ */
601 sa6.sin6_family = AF_INET6;
602 sa6.sin6_port = htons(NAMESERVER_PORT);
603 /* sa6.sin6_addr is already here */
605 sa.sin_family = AF_INET;
606 sa.sin_port = htons(NAMESERVER_PORT);
607 sa.sin_addr.s_addr = inet_addr(nsip[ns]);
609 #endif /* __UCLIBC_HAS_IPV6__ */
611 #ifndef __UCLIBC_HAS_IPV6__
612 if (connect(fd, (struct sockaddr *) &sa, sizeof(sa)) == -1) {
613 #else /* __UCLIBC_HAS_IPV6__ */
614 if (connect(fd, (struct sockaddr *) (v6 ? &sa6 : &sa),
615 v6 ? sizeof(sa6) : sizeof(sa)) == -1) {
616 #endif /* __UCLIBC_HAS_IPV6__ */
617 if (errno == ENETUNREACH) {
618 /* routing error, presume not transient */
625 DPRINTF("Transmitting packet of length %d, id=%d, qr=%d\n",
628 send(fd, packet, len, 0);
630 dns_caught_signal = 0;
631 oldalarm = alarm(REPLY_TIMEOUT);
632 oldhandler = signal(SIGALRM, dns_catch_signal);
634 i = recv(fd, packet, PACKETSZ, 0);
637 signal(SIGALRM, oldhandler);
640 DPRINTF("Timeout=%d, len=%d\n", dns_caught_signal, i);
642 if (dns_caught_signal)
643 /* timed out, so retry send and receive,
644 to next nameserver on queue */
651 decode_header(packet, &h);
653 DPRINTF("id = %d, qr = %d\n", h.id, h.qr);
655 if ((h.id != id) || (!h.qr))
659 DPRINTF("Got response %s\n", "(i think)!");
660 DPRINTF("qrcount=%d,ancount=%d,nscount=%d,arcount=%d\n",
661 h.qdcount, h.ancount, h.nscount, h.arcount);
662 DPRINTF("opcode=%d,aa=%d,tc=%d,rd=%d,ra=%d,rcode=%d\n",
663 h.opcode, h.aa, h.tc, h.rd, h.ra, h.rcode);
665 if ((h.rcode) || (h.ancount < 1)) {
666 /* negative result, not present */
672 for (j = 0; j < h.qdcount; j++) {
673 DPRINTF("Skipping question %d at %d\n", j, pos);
674 i = length_question(packet, pos);
675 DPRINTF("Length of question %d is %d\n", j, i);
680 DPRINTF("Decoding answer at pos %d\n", pos);
682 for (j=0;j<h.ancount;j++)
684 i = decode_answer(packet, pos, a);
687 DPRINTF("failed decode %d\n", i);
690 /* For all but T_SIG, accept first answer */
691 if (a->atype != T_SIG)
694 DPRINTF("skipping T_SIG %d\n", i);
699 DPRINTF("Answer name = |%s|\n", a->dotted);
700 DPRINTF("Answer type = |%d|\n", a->atype);
709 return (0); /* success! */
712 /* if there are other nameservers, give them a go,
713 otherwise return with error */
715 if (retries >= nscount*(searchdomains+1))
719 /* if there are searchdomains, try them or fallback as passed */
720 if (variant < searchdomains) {
724 /* next server, first search */
725 ns = (ns + 1) % nscount;
741 #ifdef L_resolveaddress
743 int resolve_address(const char *address, int nscount,
744 char **nsip, struct in_addr *in)
746 unsigned char *packet;
747 struct resolv_answer a;
755 strncpy(temp, address, sizeof(temp));
759 i = dns_lookup(temp, T_A, nscount, nsip, &packet, &a);
766 if (a.atype == T_CNAME) { /* CNAME */
767 DPRINTF("Got a CNAME in resolve_address()\n");
768 i = decode_dotted(packet, a.rdoffset, temp, sizeof(temp));
773 if (++nest > MAX_RECURSE)
776 } else if (a.atype == T_A) { /* ADDRESS */
786 memcpy(in, a.rdata, INADDRSZ); /* IPv4 T_A */
792 #ifdef L_resolvemailbox
794 int resolve_mailbox(const char *address, int nscount,
795 char **nsip, struct in_addr *in)
797 struct resolv_answer a;
798 unsigned char *packet;
806 /* look up mail exchange */
807 i = dns_lookup(address, T_MX, nscount, nsip, &packet, &a);
809 strncpy(temp, address, sizeof(temp));
812 i = decode_dotted(packet, a.rdoffset+2, temp, sizeof(temp));
818 i = dns_lookup(temp, T_A, nscount, nsip, &packet, &a);
825 if (a.atype == T_CNAME) { /* CNAME */
826 DPRINTF("Got a CNAME in resolve_mailbox()\n");
827 i = decode_dotted(packet, a.rdoffset, temp, sizeof(temp));
831 if (++nest > MAX_RECURSE)
834 } else if (a.atype == T_A) { /* ADDRESS */
844 memcpy(in, a.rdata, INADDRSZ); /* IPv4 */
851 #ifdef L_opennameservers
854 char * nameserver[MAX_SERVERS];
856 char * searchdomain[MAX_SEARCH];
859 * we currently read formats not quite the same as that on normal
860 * unix systems, we can have a list of nameservers after the keyword.
863 int open_nameservers()
867 #define RESOLV_ARGS 5
868 char szBuffer[128], *p, *argv[RESOLV_ARGS];
874 if ((fp = fopen("/etc/resolv.conf", "r")) ||
875 (fp = fopen("/etc/config/resolv.conf", "r"))) {
877 while (fgets(szBuffer, sizeof(szBuffer), fp) != NULL) {
879 for (p = szBuffer; *p && isspace(*p); p++)
880 /* skip white space */;
881 if (*p == '\0' || *p == '\n' || *p == '#') /* skip comments etc */
884 while (*p && argc < RESOLV_ARGS) {
886 while (*p && !isspace(*p) && *p != '\n')
888 while (*p && (isspace(*p) || *p == '\n')) /* remove spaces */
892 if (strcmp(argv[0], "nameserver") == 0) {
893 for (i = 1; i < argc && nameservers < MAX_SERVERS; i++) {
894 nameserver[nameservers++] = strdup(argv[i]);
895 DPRINTF("adding nameserver %s\n", argv[i]);
899 /* domain and search are mutually exclusive, the last one wins */
900 if (strcmp(argv[0],"domain")==0 || strcmp(argv[0],"search")==0) {
901 while (searchdomains > 0) {
902 free(searchdomain[--searchdomains]);
903 searchdomain[searchdomains] = NULL;
905 for (i=1; i < argc && searchdomains < MAX_SEARCH; i++) {
906 searchdomain[searchdomains++] = strdup(argv[i]);
907 DPRINTF("adding search %s\n", argv[i]);
913 DPRINTF("failed to open %s\n", "resolv.conf");
915 DPRINTF("nameservers = %d\n", nameservers);
921 #ifdef L_closenameservers
923 void close_nameservers(void)
925 while (nameservers > 0) {
926 free(nameserver[--nameservers]);
927 nameserver[nameservers] = NULL;
929 while (searchdomains > 0) {
930 free(searchdomain[--searchdomains]);
931 searchdomain[searchdomains] = NULL;
939 const char *resolve_name(const char *name, int mailbox)
944 /* shortcut: is it a valid IP address to begin with? */
945 if (inet_aton(name, &in))
950 DPRINTF("looking up '%s', mailbox=%d, nameservers=%d\n",
951 name, mailbox, nameservers);
954 i = resolve_mailbox(name, nameservers, nameserver, &in);
956 i = resolve_address(name, nameservers, nameserver, &in);
961 DPRINTF("success = '%s'\n", inet_ntoa(in));
963 return inet_ntoa(in);
968 #ifdef L_gethostbyname
970 struct hostent *gethostbyname(const char *name)
972 static struct hostent h;
973 static char namebuf[256];
974 static struct in_addr in;
975 static struct in_addr *addr_list[2];
977 unsigned char *packet;
978 struct resolv_answer a;
987 if ((hp = get_hosts_byname(name, AF_INET))) /* do /etc/hosts first */
990 memset(&h, 0, sizeof(h));
995 strncpy(namebuf, name, sizeof(namebuf));
997 /* First check if this is already an address */
998 if (inet_aton(name, &in)) {
1000 h.h_addrtype = AF_INET;
1001 h.h_length = sizeof(in);
1002 h.h_addr_list = (char **) addr_list;
1008 i = dns_lookup(namebuf, 1, nameservers, nameserver, &packet, &a);
1013 strncpy(namebuf, a.dotted, sizeof(namebuf));
1017 if (a.atype == T_CNAME) { /* CNAME */
1018 DPRINTF("Got a CNAME in gethostbyname()\n");
1019 i = decode_dotted(packet, a.rdoffset, namebuf, sizeof(namebuf));
1024 if (++nest > MAX_RECURSE)
1027 } else if (a.atype == T_A) { /* ADDRESS */
1028 memcpy(&in, a.rdata, sizeof(in));
1030 h.h_addrtype = AF_INET;
1031 h.h_length = sizeof(in);
1032 h.h_addr_list = (char **) addr_list;
1045 #ifdef L_gethostbyname2
1047 #ifdef __UCLIBC_HAS_IPV6__
1048 /* TBD: Not the right place for defining these, I guess */
1049 const struct in6_addr in6addr_any =
1050 { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } } };
1051 const struct in6_addr in6addr_loopback =
1052 { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 } } };
1053 #endif /* __UCLIBC_HAS_IPV6__ */
1055 struct hostent *gethostbyname2(const char *name, int family)
1057 #ifndef __UCLIBC_HAS_IPV6__
1058 return family == AF_INET ? gethostbyname(name) : (struct hostent*)0;
1059 #else /* __UCLIBC_HAS_IPV6__ */
1060 static struct hostent h;
1061 static char namebuf[256];
1062 static struct in6_addr in;
1063 static struct in6_addr *addr_list[2];
1065 unsigned char *packet;
1066 struct resolv_answer a;
1070 if (family == AF_INET)
1071 return gethostbyname(name);
1073 if (family != AF_INET6)
1081 if ((hp = get_hosts_byname(name, family))) /* do /etc/hosts first */
1084 memset(&h, 0, sizeof(h));
1089 strncpy(namebuf, name, sizeof(namebuf));
1091 /* First check if this is already an address */
1092 if (inet_pton(AF_INET6, name, &in)) {
1094 h.h_addrtype = AF_INET6;
1095 h.h_length = sizeof(in);
1096 h.h_addr_list = (char **) addr_list;
1102 i = dns_lookup(namebuf, T_AAAA, nameservers, nameserver, &packet, &a);
1107 strncpy(namebuf, a.dotted, sizeof(namebuf));
1111 if (a.atype == T_CNAME) { /* CNAME */
1112 DPRINTF("Got a CNAME in gethostbyname()\n");
1113 i = decode_dotted(packet, a.rdoffset, namebuf, sizeof(namebuf));
1118 if (++nest > MAX_RECURSE)
1121 } else if (a.atype == T_AAAA) { /* ADDRESS */
1122 memcpy(&in, a.rdata, sizeof(in));
1124 h.h_addrtype = AF_INET6;
1125 h.h_length = sizeof(in);
1126 h.h_addr_list = (char **) addr_list;
1136 #endif /* __UCLIBC_HAS_IPV6__ */
1140 #ifdef L_getnetbyname
1142 struct netent * getnetbyname(const char * name)
1161 #define MIN(x, y) ((x) < (y) ? (x) : (y))
1164 int res_query(const char *dname, int class, int type,
1165 unsigned char *answer, int anslen)
1167 unsigned char * packet = 0;
1168 struct resolv_answer a;
1173 if (!dname || class != 1 /* CLASS_IN */)
1176 memset((char *) &a, '\0', sizeof(a));
1178 i = dns_lookup(dname, type, nameservers, nameserver, &packet, &a);
1185 if (a.atype == type) { /* CNAME*/
1186 if (anslen && answer)
1187 memcpy(answer, a.rdata, MIN(anslen, a.rdlength));
1190 return(MIN(anslen, a.rdlength));
1199 #ifdef L_gethostbyaddr
1200 struct hostent *gethostbyaddr (const void *addr, socklen_t len, int type)
1202 static struct hostent h;
1203 static char namebuf[256];
1204 static struct in_addr in;
1205 static struct in_addr *addr_list[2];
1206 #ifdef __UCLIBC_HAS_IPV6__
1208 static struct in6_addr in6;
1209 static struct in6_addr *addr_list6[2];
1210 #endif /* __UCLIBC_HAS_IPV6__ */
1212 unsigned char *packet;
1213 struct resolv_answer a;
1222 if (len != sizeof(struct in_addr))
1225 #ifdef __UCLIBC_HAS_IPV6__
1227 if (len != sizeof(struct in6_addr))
1230 #endif /* __UCLIBC_HAS_IPV6__ */
1235 if ((hp = get_hosts_byaddr(addr, len, type))) /* do /etc/hosts first */
1240 memset(&h, 0, sizeof(h));
1242 if(type == AF_INET) {
1243 unsigned char *tmp_addr = (unsigned char *)addr;
1245 memcpy(&in.s_addr, addr, len);
1249 sprintf(namebuf, "%u.%u.%u.%u.in-addr.arpa",
1250 tmp_addr[3], tmp_addr[2], tmp_addr[1], tmp_addr[0]);
1251 #ifdef __UCLIBC_HAS_IPV6__
1253 memcpy(&in6.s6_addr, addr, len);
1255 addr_list6[0] = &in6;
1258 for (i = len - 1; i >= 0; i--) {
1259 qp += sprintf(qp, "%x.%x.", in6.s6_addr[i] & 0xf,
1260 (in6.s6_addr[i] >> 4) & 0xf);
1262 strcpy(qp, "ip6.int");
1263 #endif /* __UCLIBC_HAS_IPV6__ */
1270 i = dns_lookup(namebuf, T_PTR, nameservers, nameserver, &packet, &a);
1275 strncpy(namebuf, a.dotted, sizeof(namebuf));
1278 if (a.atype == T_CNAME) { /* CNAME */
1279 DPRINTF("Got a CNAME in gethostbyaddr()\n");
1280 i = decode_dotted(packet, a.rdoffset, namebuf, sizeof(namebuf));
1285 if (++nest > MAX_RECURSE)
1288 } else if (a.atype == T_PTR) { /* ADDRESS */
1289 i = decode_dotted(packet, a.rdoffset, namebuf, sizeof(namebuf));
1293 h.h_addrtype = type;
1295 if(type == AF_INET) {
1296 h.h_length = sizeof(in);
1297 #ifdef __UCLIBC_HAS_IPV6__
1299 h.h_length = sizeof(in6);
1300 #endif /* __UCLIBC_HAS_IPV6__ */
1303 h.h_addr_list = (char **) addr_list;
1316 #ifdef L_read_etc_hosts
1318 struct hostent * read_etc_hosts(const char * name, int type, int ip)
1320 static struct hostent h;
1321 static struct in_addr in;
1322 static struct in_addr *addr_list[2];
1323 #ifdef __UCLIBC_HAS_IPV6__
1324 static struct in6_addr in6;
1325 static struct in6_addr *addr_list6[2];
1326 #endif /* __UCLIBC_HAS_IPV6__ */
1327 static char line[80];
1331 char *alias[MAX_ALIAS];
1334 if ((fp = fopen("/etc/hosts", "r")) == NULL &&
1335 (fp = fopen("/etc/config/hosts", "r")) == NULL)
1336 return((struct hostent *) NULL);
1338 while (fgets(line, sizeof(line), fp)) {
1339 if ((cp = strchr(line, '#')))
1345 while (*cp && isspace(*cp))
1349 if (aliases < MAX_ALIAS)
1350 alias[aliases++] = cp;
1351 while (*cp && !isspace(*cp))
1356 continue; /* syntax error really */
1359 if (strcmp(name, alias[0]) != 0)
1362 for (i = 1; i < aliases; i++)
1363 if (strcasecmp(name, alias[i]) == 0)
1369 if (type == AF_INET && inet_pton(AF_INET, alias[0], &in) > 0) {
1372 h.h_name = alias[1];
1373 h.h_addrtype = AF_INET;
1374 h.h_length = sizeof(in);
1375 h.h_addr_list = (char**) addr_list;
1376 #ifdef __UCLIBC_HAS_IPV6__
1377 } else if (type == AF_INET6 && inet_pton(AF_INET6, alias[0], &in6) > 0) {
1378 addr_list6[0] = &in6;
1380 h.h_name = alias[1];
1381 h.h_addrtype = AF_INET6;
1382 h.h_length = sizeof(in6);
1383 h.h_addr_list = (char**) addr_list6;
1384 #endif /* __UCLIBC_HAS_IPV6__ */
1386 break; /* bad ip address */
1393 return((struct hostent *) NULL);
1398 #ifdef L_get_hosts_byname
1400 struct hostent * get_hosts_byname(const char * name, int type)
1402 return(read_etc_hosts(name, type, 0));
1407 #ifdef L_get_hosts_byaddr
1409 struct hostent * get_hosts_byaddr(const char * addr, int len, int type)
1411 #ifndef __UCLIBC_HAS_IPV6__
1412 char ipaddr[INET_ADDRSTRLEN];
1414 char ipaddr[INET6_ADDRSTRLEN];
1415 #endif /* __UCLIBC_HAS_IPV6__ */
1419 if (len != sizeof(struct in_addr))
1422 #ifdef __UCLIBC_HAS_IPV6__
1424 if (len != sizeof(struct in6_addr))
1427 #endif /* __UCLIBC_HAS_IPV6__ */
1432 inet_ntop(type, addr, ipaddr, sizeof(ipaddr));
1434 return(read_etc_hosts(ipaddr, type, 1));
1438 #ifdef L_getnameinfo
1441 # define min(x,y) (((x) > (y)) ? (y) : (x))
1444 int getnameinfo (const struct sockaddr *sa, socklen_t addrlen, char *host,
1445 socklen_t hostlen, char *serv, socklen_t servlen,
1450 struct hostent *h = NULL;
1453 if (flags & ~(NI_NUMERICHOST|NI_NUMERICSERV|NI_NOFQDN|NI_NAMEREQD|NI_DGRAM))
1454 return EAI_BADFLAGS;
1456 if (sa == NULL || addrlen < sizeof (sa_family_t))
1459 switch (sa->sa_family) {
1463 if (addrlen < sizeof (struct sockaddr_in))
1466 #ifdef __UCLIBC_HAS_IPV6__
1468 if (addrlen < sizeof (struct sockaddr_in6))
1471 #endif /* __UCLIBC_HAS_IPV6__ */
1476 if (host != NULL && hostlen > 0)
1477 switch (sa->sa_family) {
1479 #ifdef __UCLIBC_HAS_IPV6__
1481 #endif /* __UCLIBC_HAS_IPV6__ */
1482 if (!(flags & NI_NUMERICHOST)) {
1483 #ifdef __UCLIBC_HAS_IPV6__
1484 if (sa->sa_family == AF_INET6)
1485 h = gethostbyaddr ((const void *) &(((const struct sockaddr_in6 *) sa)->sin6_addr),
1486 sizeof(struct in6_addr), AF_INET6);
1488 #endif /* __UCLIBC_HAS_IPV6__ */
1489 h = gethostbyaddr ((const void *) &(((const struct sockaddr_in *)sa)->sin_addr),
1490 sizeof(struct in_addr), AF_INET);
1494 if ((flags & NI_NOFQDN)
1495 && (getdomainname (domain, sizeof(domain)) == 0)
1496 && (c = strstr (h->h_name, domain))
1497 && (c != h->h_name) && (*(--c) == '.')) {
1498 strncpy (host, h->h_name,
1499 min(hostlen, (size_t) (c - h->h_name)));
1500 host[min(hostlen - 1, (size_t) (c - h->h_name))] = '\0';
1503 strncpy (host, h->h_name, hostlen);
1510 if (flags & NI_NAMEREQD) {
1515 #ifdef __UCLIBC_HAS_IPV6__
1516 if (sa->sa_family == AF_INET6) {
1517 const struct sockaddr_in6 *sin6p;
1519 sin6p = (const struct sockaddr_in6 *) sa;
1521 c = inet_ntop (AF_INET6,
1522 (const void *) &sin6p->sin6_addr, host, hostlen);
1524 /* Does scope id need to be supported? */
1526 scopeid = sin6p->sin6_scope_id;
1528 /* Buffer is >= IFNAMSIZ+1. */
1529 char scopebuf[IFNAMSIZ + 1];
1531 int ni_numericscope = 0;
1532 size_t real_hostlen = __strnlen (host, hostlen);
1533 size_t scopelen = 0;
1535 scopebuf[0] = SCOPE_DELIMITER;
1537 scopeptr = &scopebuf[1];
1539 if (IN6_IS_ADDR_LINKLOCAL (&sin6p->sin6_addr)
1540 || IN6_IS_ADDR_MC_LINKLOCAL (&sin6p->sin6_addr)) {
1541 if (if_indextoname (scopeid, scopeptr) == NULL)
1544 scopelen = strlen (scopebuf);
1549 if (ni_numericscope)
1550 scopelen = 1 + snprintf (scopeptr,
1556 if (real_hostlen + scopelen + 1 > hostlen)
1558 memcpy (host + real_hostlen, scopebuf, scopelen + 1);
1562 #endif /* __UCLIBC_HAS_IPV6__ */
1563 c = inet_ntop (AF_INET,
1564 (const void *) &(((const struct sockaddr_in *) sa)->sin_addr),
1577 if (!(flags & NI_NUMERICHOST)) {
1578 struct utsname utsname;
1580 if (!uname (&utsname)) {
1581 strncpy (host, utsname.nodename, hostlen);
1586 if (flags & NI_NAMEREQD) {
1591 strncpy (host, "localhost", hostlen);
1598 if (serv && (servlen > 0)) {
1599 switch (sa->sa_family) {
1601 #ifdef __UCLIBC_HAS_IPV6__
1603 #endif /* __UCLIBC_HAS_IPV6__ */
1604 if (!(flags & NI_NUMERICSERV)) {
1606 s = getservbyport (((const struct sockaddr_in *) sa)->sin_port,
1607 ((flags & NI_DGRAM) ? "udp" : "tcp"));
1609 strncpy (serv, s->s_name, servlen);
1613 snprintf (serv, servlen, "%d",
1614 ntohs (((const struct sockaddr_in *) sa)->sin_port));
1618 strncpy (serv, ((const struct sockaddr_un *) sa)->sun_path, servlen);
1622 if (host && (hostlen > 0))
1623 host[hostlen-1] = 0;
1624 if (serv && (servlen > 0))
1625 serv[servlen-1] = 0;