af-wall/external/dist/busybox-patches/050-dietlibc_resolver-nslookup.patch
2025-11-20 14:05:38 +01:00

1243 lines
37 KiB
Diff

From: Tias Guns <tias@ulyssis.org>
Date: Tue, 20 Mar 2012 23:10:18 +0000
Subject: [PATCH] fix nslookup, add libres, a dietlibc resolver
patches from 'dietlibc-resolver' by Dan Drown
"""
use the bionic's resolver functions do not allow changing the dns
server. Use
dietlibc's resolver code instead (see package libres-devel)
"""
http://dan.drown.org/android/src/busybox/
libres from 'libres-0.32-1' also by Dan Drown:
http://dan.drown.org/android/src/libres/
---
Makefile | 1 +
libres/Kbuild.src | 11 +++
libres/Makefile | 32 ++++++++
libres/README | 5 ++
libres/dietdns.h | 189 +++++++++++++++++++++++++++++++++++++++++++++
libres/dn_expand.c | 12 +++
libres/dnscruft.c | 119 ++++++++++++++++++++++++++++
libres/dnscruft2.c | 132 +++++++++++++++++++++++++++++++
libres/dnscruft3.c | 6 ++
libres/freeaddrinfo.c | 14 ++++
libres/gai_strerror.c | 14 ++++
libres/getaddrinfo.c | 137 ++++++++++++++++++++++++++++++++
libres/gethostbyname2_r.c | 35 +++++++++
libres/h_errno.c | 1 +
libres/res_init.c | 12 +++
libres/res_mkquery.c | 85 ++++++++++++++++++++
libres/res_query.c | 81 +++++++++++++++++++
libres/test.c | 105 +++++++++++++++++++++++++
networking/nslookup.c | 25 +++---
19 files changed, 1005 insertions(+), 11 deletions(-)
create mode 100644 libres/Kbuild.src
create mode 100644 libres/Makefile
create mode 100644 libres/README
create mode 100644 libres/dietdns.h
create mode 100644 libres/dn_expand.c
create mode 100644 libres/dnscruft.c
create mode 100644 libres/dnscruft2.c
create mode 100644 libres/dnscruft3.c
create mode 100644 libres/freeaddrinfo.c
create mode 100644 libres/gai_strerror.c
create mode 100644 libres/getaddrinfo.c
create mode 100644 libres/gethostbyname2_r.c
create mode 100644 libres/h_errno.c
create mode 100644 libres/res_init.c
create mode 100644 libres/res_mkquery.c
create mode 100644 libres/res_query.c
create mode 100644 libres/test.c
diff --git a/Makefile b/Makefile
index c31ca89..8e0226a 100644
--- a/Makefile
+++ b/Makefile
@@ -476,6 +476,7 @@ libs-y := \
init/ \
libbb/ \
libpwdgrp/ \
+ libres/ \
loginutils/ \
mailutils/ \
miscutils/ \
diff --git a/libres/Kbuild.src b/libres/Kbuild.src
new file mode 100644
index 0000000..abd4194
--- /dev/null
+++ b/libres/Kbuild.src
@@ -0,0 +1,11 @@
+# Makefile for busybox
+#
+# Copyright (C) 2012-2012 by Tias Guns <tias@ulyssis.org>
+#
+# Licensed under GPLv2, see file LICENSE in this source tree.
+
+lib-$(CONFIG_NSLOOKUP) += getaddrinfo.o gethostbyname2_r.o freeaddrinfo.o
+lib-$(CONFIG_NSLOOKUP) += dnscruft.o dnscruft2.o dnscruft3.o
+lib-$(CONFIG_NSLOOKUP) += res_init.o res_query.o res_mkquery.o
+lib-$(CONFIG_NSLOOKUP) += h_errno.o gai_strerror.o
+lib-$(CONFIG_NSLOOKUP) += dn_expand.o
diff --git a/libres/Makefile b/libres/Makefile
new file mode 100644
index 0000000..4a56888
--- /dev/null
+++ b/libres/Makefile
@@ -0,0 +1,32 @@
+CC=agcc
+
+OBJECTS=getaddrinfo.o
+OBJECTS+=gethostbyname2_r.o
+OBJECTS+=dnscruft.o
+OBJECTS+=dnscruft2.o
+OBJECTS+=dnscruft3.o
+OBJECTS+=h_errno.o
+OBJECTS+=res_query.o
+OBJECTS+=res_mkquery.o
+OBJECTS+=gai_strerror.o
+OBJECTS+=freeaddrinfo.o
+OBJECTS+=res_init.o
+OBJECTS+=dn_expand.o
+
+CFLAGS+=-Wall
+
+all: libres.a test
+clean:
+ rm -f $(OBJECTS) libres.a test.o test
+
+test: libres.a test.o
+ $(CC) $(CFLAGS) -o test test.o libres.a
+
+libres.a: $(OBJECTS)
+ ar r libres.a $(OBJECTS)
+ ranlib libres.a
+
+.PHONY: all clean
+
+%.o: %.c dietdns.h
+ $(CC) $(CFLAGS) -c $<
diff --git a/libres/README b/libres/README
new file mode 100644
index 0000000..cab8e47
--- /dev/null
+++ b/libres/README
@@ -0,0 +1,5 @@
+all these files are from dietlibc, modified to fit as a plug-in resolver
+
+Work by Dan Drown, called libres-0.32-1
+available at:
+http://dan.drown.org/android/src/libres/
diff --git a/libres/dietdns.h b/libres/dietdns.h
new file mode 100644
index 0000000..9ae0b4d
--- /dev/null
+++ b/libres/dietdns.h
@@ -0,0 +1,189 @@
+#ifndef __DIETDNS_H_
+#define __DIETDNS_H_
+
+#define DIET_MAXDNAME 1025 /* maximum domain name */
+#define DIET_PACKETSZ 512
+
+#define DIET_MAXNS 8 /* max # name servers we'll track */
+#define DIET_MAXDNSRCH 6 /* max # domains in search path */
+#define DIET_MAXRESOLVSORT 10 /* number of net to sort on */
+
+struct diet_res_state {
+ int retrans; /* retransmission time interval */
+ int retry; /* number of times to retransmit */
+ unsigned long options; /* option flags - see below. */
+ int nscount; /* number of name servers */
+ struct sockaddr_in
+ nsaddr_list[DIET_MAXNS]; /* address of name server */
+#define nsaddr nsaddr_list[0] /* for backward compatibility */
+ unsigned short id; /* current message id */
+ char *dnsrch[DIET_MAXDNSRCH+1]; /* components of domain to search */
+ char defdname[256]; /* default domain (deprecated) */
+ unsigned long pfcode; /* RES_PRF_ flags - see below. */
+ unsigned ndots:4; /* threshold for initial abs. query */
+ unsigned nsort:4; /* number of elements in sort_list[] */
+ char unused[3];
+ struct {
+ struct in_addr addr;
+ uint32_t mask;
+ } sort_list[DIET_MAXRESOLVSORT];
+ char pad[72];
+};
+
+/*
+ * Values for class field
+ */
+enum diet_ns_class {
+ diet_ns_c_invalid = 0, /* Cookie. */
+ diet_ns_c_in = 1, /* Internet. */
+ diet_ns_c_2 = 2, /* unallocated/unsupported. */
+ diet_ns_c_chaos = 3, /* MIT Chaos-net. */
+ diet_ns_c_hs = 4, /* MIT Hesiod. */
+ /* Query class values which do not appear in resource records */
+ diet_ns_c_none = 254, /* for prereq. sections in update requests */
+ diet_ns_c_any = 255, /* Wildcard match. */
+ diet_ns_c_max = 65536
+};
+
+#define DIET_C_IN diet_ns_c_in
+
+/*
+ * Currently defined opcodes.
+ */
+enum diet_ns_opcode {
+ diet_ns_o_query = 0, /* Standard query. */
+ diet_ns_o_iquery = 1, /* Inverse query (deprecated/unsupported). */
+ diet_ns_o_status = 2, /* Name server status query (unsupported). */
+ /* Opcode 3 is undefined/reserved. */
+ diet_ns_o_notify = 4, /* Zone change notification. */
+ diet_ns_o_update = 5, /* Zone update message. */
+ diet_ns_o_max = 6
+};
+
+#define DIET_QUERY diet_ns_o_query
+
+/*
+ * Currently defined type values for resources and queries.
+ */
+enum diet_ns_type {
+ diet_ns_t_invalid = 0, /* Cookie. */
+ diet_ns_t_a = 1, /* Host address. */
+ diet_ns_t_ns = 2, /* Authoritative server. */
+ diet_ns_t_md = 3, /* Mail destination. */
+ diet_ns_t_mf = 4, /* Mail forwarder. */
+ diet_ns_t_cname = 5, /* Canonical name. */
+ diet_ns_t_soa = 6, /* Start of authority zone. */
+ diet_ns_t_mb = 7, /* Mailbox domain name. */
+ diet_ns_t_mg = 8, /* Mail group member. */
+ diet_ns_t_mr = 9, /* Mail rename name. */
+ diet_ns_t_null = 10, /* Null resource record. */
+ diet_ns_t_wks = 11, /* Well known service. */
+ diet_ns_t_ptr = 12, /* Domain name pointer. */
+ diet_ns_t_hinfo = 13, /* Host information. */
+ diet_ns_t_minfo = 14, /* Mailbox information. */
+ diet_ns_t_mx = 15, /* Mail routing information. */
+ diet_ns_t_txt = 16, /* Text strings. */
+ diet_ns_t_rp = 17, /* Responsible person. */
+ diet_ns_t_afsdb = 18, /* AFS cell database. */
+ diet_ns_t_x25 = 19, /* X_25 calling address. */
+ diet_ns_t_isdn = 20, /* ISDN calling address. */
+ diet_ns_t_rt = 21, /* Router. */
+ diet_ns_t_nsap = 22, /* NSAP address. */
+ diet_ns_t_nsap_ptr = 23, /* Reverse NSAP lookup (deprecated). */
+ diet_ns_t_sig = 24, /* Security signature. */
+ diet_ns_t_key = 25, /* Security key. */
+ diet_ns_t_px = 26, /* X.400 mail mapping. */
+ diet_ns_t_gpos = 27, /* Geographical position (withdrawn). */
+ diet_ns_t_aaaa = 28, /* Ip6 Address. */
+ diet_ns_t_loc = 29, /* Location Information. */
+ diet_ns_t_nxt = 30, /* Next domain (security). */
+ diet_ns_t_eid = 31, /* Endpoint identifier. */
+ diet_ns_t_nimloc = 32, /* Nimrod Locator. */
+ diet_ns_t_srv = 33, /* Server Selection. */
+ diet_ns_t_atma = 34, /* ATM Address */
+ diet_ns_t_naptr = 35, /* Naming Authority PoinTeR */
+ diet_ns_t_kx = 36, /* Key Exchange */
+ diet_ns_t_cert = 37, /* Certification record */
+ diet_ns_t_a6 = 38, /* IPv6 address (deprecates AAAA) */
+ diet_ns_t_dname = 39, /* Non-terminal DNAME (for IPv6) */
+ diet_ns_t_sink = 40, /* Kitchen sink (experimentatl) */
+ diet_ns_t_opt = 41, /* EDNS0 option (meta-RR) */
+ diet_ns_t_tsig = 250, /* Transaction signature. */
+ diet_ns_t_ixfr = 251, /* Incremental zone transfer. */
+ diet_ns_t_axfr = 252, /* Transfer zone of authority. */
+ diet_ns_t_mailb = 253, /* Transfer mailbox records. */
+ diet_ns_t_maila = 254, /* Transfer mail agent records. */
+ diet_ns_t_any = 255, /* Wildcard match. */
+ diet_ns_t_zxfr = 256, /* BIND-specific, nonstandard. */
+ diet_ns_t_max = 65536
+};
+
+#define DIET_T_A diet_ns_t_a
+#define DIET_T_NS diet_ns_t_ns
+#define DIET_T_CNAME diet_ns_t_cname
+#define DIET_T_SOA diet_ns_t_soa
+#define DIET_T_PTR diet_ns_t_ptr
+#define DIET_T_MX diet_ns_t_mx
+#define DIET_T_TXT diet_ns_t_txt
+#define DIET_T_AAAA diet_ns_t_aaaa
+#define DIET_T_ANY diet_ns_t_any
+
+/*
+ * Currently defined response codes.
+ */
+enum diet_ns_rcode {
+ diet_ns_r_noerror = 0, /* No error occurred. */
+ diet_ns_r_formerr = 1, /* Format error. */
+ diet_ns_r_servfail = 2, /* Server failure. */
+ diet_ns_r_nxdomain = 3, /* Name error. */
+ diet_ns_r_notimpl = 4, /* Unimplemented. */
+ diet_ns_r_refused = 5, /* Operation refused. */
+ /* these are for BIND_UPDATE */
+ diet_ns_r_yxdomain = 6, /* Name exists */
+ diet_ns_r_yxrrset = 7, /* RRset exists */
+ diet_ns_r_nxrrset = 8, /* RRset does not exist */
+ diet_ns_r_notauth = 9, /* Not authoritative for zone */
+ diet_ns_r_notzone = 10, /* Zone of record different from zone section */
+ diet_ns_r_max = 11,
+ /* The following are TSIG extended errors */
+ diet_ns_r_badsig = 16,
+ diet_ns_r_badkey = 17,
+ diet_ns_r_badtime = 18
+};
+
+
+
+#define DIET_NOERROR diet_ns_r_noerror
+#define DIET_FORMERR diet_ns_r_formerr
+#define DIET_SERVFAIL diet_ns_r_servfail
+#define DIET_NXDOMAIN diet_ns_r_nxdomain
+#define DIET_NOTIMP diet_ns_r_notimpl
+#define DIET_REFUSED diet_ns_r_refused
+#define DIET_YXDOMAIN diet_ns_r_yxdomain
+#define DIET_YXRRSET diet_ns_r_yxrrset
+#define DIET_NXRRSET diet_ns_r_nxrrset
+#define DIET_NOTAUTH diet_ns_r_notauth
+#define DIET_NOTZONE diet_ns_r_notzone
+
+
+#define DIET_RES_RECURSE 0x00000040 /* recursion desired */
+
+extern struct diet_res_state _diet_res;
+extern int diet_h_errno;
+
+int __dns_gethostbyx_r(const char* name, struct hostent* result,
+ char *buf, size_t buflen,
+ struct hostent **RESULT, int *h_errnop, int lookfor);
+int diet_gethostbyname2_r(const char* name, int AF, struct hostent* result,
+ char *buf, size_t buflen,
+ struct hostent **RESULT, int *h_errnop);
+int diet_res_query(const char *dname, int class, int type, unsigned char *answer, int anslen);
+int diet_res_mkquery(int op, const char *dname, int class, int type, char* data,
+ int datalen, const unsigned char* newrr, char* buf, int buflen);
+const char* diet_gai_strerror(int error);
+int diet_getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res);
+void diet_freeaddrinfo(struct addrinfo *res);
+int diet_res_init(void);
+int diet_dn_expand(const unsigned char *msg, const unsigned char *eomorig, const unsigned char *comp_dn, unsigned char *exp_dn, int length);
+
+#endif
diff --git a/libres/dn_expand.c b/libres/dn_expand.c
new file mode 100644
index 0000000..9eb4587
--- /dev/null
+++ b/libres/dn_expand.c
@@ -0,0 +1,12 @@
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+#include <netdb.h>
+#include "dietdns.h"
+
+extern int __dns_decodename(const unsigned char *packet,unsigned int ofs,unsigned char *dest,
+ unsigned int maxlen,const unsigned char* behindpacket);
+
+int diet_dn_expand(const unsigned char *msg, const unsigned char *eomorig, const unsigned char *comp_dn, unsigned char *exp_dn, int length) {
+ return __dns_decodename(msg,comp_dn-msg,exp_dn,length,eomorig)-(comp_dn-msg);
+}
diff --git a/libres/dnscruft.c b/libres/dnscruft.c
new file mode 100644
index 0000000..142ffec
--- /dev/null
+++ b/libres/dnscruft.c
@@ -0,0 +1,119 @@
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <arpa/inet.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <resolv.h>
+#include <net/if.h>
+#include <netdb.h>
+#include "dietdns.h"
+
+#ifdef __BIONIC__
+#include <sys/system_properties.h>
+#endif
+
+
+/* needs:
+ * _res
+ */
+
+int __dns_fd=-1;
+
+/* the ad-hoc internal API from hell ;-) */
+void __dns_make_fd(void);
+void __dns_make_fd6(void);
+void __dns_readstartfiles(void);
+int __dns_decodename(const unsigned char *packet,unsigned int offset,unsigned char *dest,
+ unsigned int maxlen,const unsigned char* behindpacket);
+
+void __dns_make_fd(void) {
+ int tmp;
+ struct sockaddr_in si;
+ if (__dns_fd>=0) return;
+ tmp=socket(PF_INET,SOCK_DGRAM,IPPROTO_UDP);
+ if (tmp<0) return;
+ fcntl(tmp,F_SETFD,FD_CLOEXEC);
+ si.sin_family=AF_INET;
+ si.sin_port=0;
+ si.sin_addr.s_addr=INADDR_ANY;
+ if (bind(tmp,(struct sockaddr*)&si,sizeof(si))) return;
+ __dns_fd=tmp;
+}
+
+static int parsesockaddr(const char* c,void* x) {
+ struct sockaddr_in to;
+ if (inet_aton(c,&to.sin_addr)) {
+ to.sin_port=htons(53);
+ to.sin_family=AF_INET;
+ memmove(x,&to,sizeof(struct sockaddr_in));
+ return 1;
+ }
+ return 0;
+}
+
+#define MAX_DNS_PROPERTIES 8
+#define DNS_PROP_NAME_PREFIX "net.dns"
+void __dns_readstartfiles(void) {
+#ifdef __BIONIC__
+ char propvalue[PROP_VALUE_MAX];
+ char propname[PROP_NAME_MAX];
+ int i;
+#endif
+
+ if (_diet_res.nscount>0)
+ return;
+
+ _diet_res.options=DIET_RES_RECURSE;
+
+#ifdef __BIONIC__
+ for(i = 1; i <= MAX_DNS_PROPERTIES; i++) {
+ snprintf(propname, sizeof(propname), "%s%d", DNS_PROP_NAME_PREFIX, i);
+ if(__system_property_get(propname, propvalue) < 1) {
+ break;
+ }
+
+ if (parsesockaddr(propvalue,&_diet_res.nsaddr_list[_diet_res.nscount]))
+ if (_diet_res.nscount<DIET_MAXNS)
+ ++_diet_res.nscount;
+ }
+#else
+ /* testing */
+ parsesockaddr("127.0.0.1",&_diet_res.nsaddr_list[_diet_res.nscount]);
+ ++_diet_res.nscount;
+#endif
+}
+
+/* return length of decoded data or -1 */
+int __dns_decodename(const unsigned char *packet,unsigned int offset,unsigned char *dest,
+ unsigned int maxlen,const unsigned char* behindpacket) {
+ const unsigned char *tmp;
+ const unsigned char *max=dest+maxlen;
+ const unsigned char *after=packet+offset;
+ int ok=0;
+ for (tmp=after; maxlen>0&&*tmp; ) {
+ if (tmp>=behindpacket) return -1;
+ if ((*tmp>>6)==3) { /* goofy DNS decompression */
+ unsigned int ofs=((unsigned int)(*tmp&0x3f)<<8)|*(tmp+1);
+ if (ofs>=(unsigned int)offset) return -1; /* RFC1035: "pointer to a _prior_ occurrance" */
+ if (after<tmp+2) after=tmp+2;
+ tmp=packet+ofs;
+ ok=0;
+ } else {
+ unsigned int duh;
+ if (dest+*tmp+1>max) return -1;
+ if (tmp+*tmp+1>=behindpacket) return -1;
+ for (duh=*tmp; duh>0; --duh)
+ *dest++=*++tmp;
+ *dest++='.'; ok=1;
+ ++tmp;
+ if (tmp>after) { after=tmp; if (!*tmp) ++after; }
+ }
+ }
+ if (ok) --dest;
+ *dest=0;
+ return after-packet;
+}
diff --git a/libres/dnscruft2.c b/libres/dnscruft2.c
new file mode 100644
index 0000000..db9782f
--- /dev/null
+++ b/libres/dnscruft2.c
@@ -0,0 +1,132 @@
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <stdlib.h>
+#include <arpa/inet.h>
+#include <unistd.h>
+#include <errno.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+#include "dietdns.h"
+
+/* needs:
+ * __dns_decodename
+ * res_query
+ */
+
+extern int __dns_decodename(unsigned char *packet,unsigned int offset,unsigned char *dest,
+ unsigned int maxlen,unsigned char* behindpacket);
+
+/* Oh boy, this interface sucks so badly, there are no words for it.
+ * Not one, not two, but _three_ error signalling methods! (*h_errnop
+ * nonzero? return value nonzero? *RESULT zero?) The glibc goons
+ * really outdid themselves with this one. */
+int __dns_gethostbyx_r(const char* name, struct hostent* result,
+ char *buf, size_t buflen,
+ struct hostent **RESULT, int *h_errnop, int lookfor) {
+ int names,ips;
+ char *cur;
+ char *max;
+ char inpkg[1500];
+ char* tmp;
+ int size;
+
+ if (lookfor==1) {
+ result->h_addrtype=AF_INET;
+ result->h_length=4;
+ } else {
+ result->h_addrtype=AF_INET6;
+ result->h_length=16;
+ }
+ result->h_aliases=(char**)(buf+8*sizeof(char*));
+ result->h_addr_list=(char**)buf;
+ result->h_aliases[0]=0;
+
+ cur=buf+16*sizeof(char*);
+ max=buf+buflen;
+ names=ips=0;
+
+ if ((size=diet_res_query(name,DIET_C_IN,lookfor,(unsigned char*)inpkg,512))<0) {
+invalidpacket:
+ *h_errnop=HOST_NOT_FOUND;
+ return -1;
+ }
+ {
+ tmp=inpkg+12;
+ {
+ unsigned char Name[257];
+ unsigned short q=((unsigned short)inpkg[4]<<8)+inpkg[5];
+ while (q>0) {
+ if (tmp>(char*)inpkg+size) goto invalidpacket;
+ while (*tmp) { tmp+=*tmp+1; if (tmp>(char*)inpkg+size) goto invalidpacket; }
+ tmp+=5;
+ --q;
+ }
+ if (tmp>inpkg+size) goto invalidpacket;
+ q=((unsigned short)inpkg[6]<<8)+inpkg[7];
+ if (q<1) goto nodata;
+ while (q>0) {
+ int decofs=__dns_decodename((unsigned char*)inpkg,(size_t)(tmp-(char*)inpkg),Name,256,(unsigned char*)inpkg+size);
+ if (decofs<0) break;
+ tmp=inpkg+decofs;
+ --q;
+ if (tmp[0]!=0 || tmp[1]!=lookfor || /* TYPE != A */
+ tmp[2]!=0 || tmp[3]!=1) { /* CLASS != IN */
+ if (tmp[1]==5) { /* CNAME */
+ tmp+=10;
+ decofs=__dns_decodename((unsigned char*)inpkg,(size_t)(tmp-(char*)inpkg),Name,256,(unsigned char*)inpkg+size);
+ if (decofs<0) break;
+ tmp=inpkg+decofs;
+ } else
+ break;
+ continue;
+ }
+ tmp+=10; /* skip type, class, TTL and length */
+ {
+ int slen;
+ if (lookfor==1 || lookfor==28) /* A or AAAA*/ {
+ slen=strlen((char*)Name);
+ if (cur+slen+8+(lookfor==28?12:0)>=max) { *h_errnop=NO_RECOVERY; return -1; }
+ } else {
+ if (lookfor==12) /* PTR */ {
+ decofs=__dns_decodename((unsigned char*)inpkg,(size_t)(tmp-(char*)inpkg),Name,256,(unsigned char*)inpkg+size);
+ if (decofs<0) break;
+ tmp=inpkg+decofs;
+ }
+ slen=strlen((char*)Name);
+ }
+ strcpy(cur,(char*)Name);
+ if (names==0)
+ result->h_name=cur;
+ else
+ result->h_aliases[names-1]=cur;
+ result->h_aliases[names]=0;
+ if (names<8) ++names;
+/* cur+=slen+1; */
+ cur+=(slen|3)+1;
+ result->h_addr_list[ips++] = cur;
+ if (lookfor==1) /* A */ {
+ memcpy(cur,tmp,4);
+ cur+=4; tmp+=4;
+ result->h_addr_list[ips]=0;
+ } else if (lookfor==28) /* AAAA */ {
+ memcpy(cur,tmp,16);
+ cur+=16; tmp+=16;
+ result->h_addr_list[ips]=0;
+ }
+ }
+/* puts(Name); */
+ }
+ }
+ }
+ if (!names) {
+nodata:
+ *h_errnop=NO_DATA;
+ return -1;
+ }
+ *h_errnop=0;
+ *RESULT=result;
+ return 0;
+}
diff --git a/libres/dnscruft3.c b/libres/dnscruft3.c
new file mode 100644
index 0000000..379dc8b
--- /dev/null
+++ b/libres/dnscruft3.c
@@ -0,0 +1,6 @@
+#include <netinet/in.h>
+#include <resolv.h>
+#include <netdb.h>
+#include "dietdns.h"
+
+struct diet_res_state _diet_res; /* don't ask. */
diff --git a/libres/freeaddrinfo.c b/libres/freeaddrinfo.c
new file mode 100644
index 0000000..f525d2c
--- /dev/null
+++ b/libres/freeaddrinfo.c
@@ -0,0 +1,14 @@
+#include <sys/socket.h>
+#include <stdlib.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include "dietdns.h"
+
+void diet_freeaddrinfo(struct addrinfo *res) {
+ while (res) {
+ struct addrinfo *duh;
+ duh=res;
+ res=res->ai_next;
+ free(duh);
+ }
+}
diff --git a/libres/gai_strerror.c b/libres/gai_strerror.c
new file mode 100644
index 0000000..311777e
--- /dev/null
+++ b/libres/gai_strerror.c
@@ -0,0 +1,14 @@
+#include <sys/socket.h>
+#include <netdb.h>
+
+const char* diet_gai_strerror(int error) {
+ switch (error) {
+ case EAI_FAMILY: return "family not supported";
+ case EAI_SOCKTYPE: return "socket type not supported";
+ case EAI_NONAME: return "unknown host";
+ case EAI_SERVICE: return "unknown service";
+ case EAI_MEMORY: return "memory allocation failure";
+ case EAI_AGAIN: return "temporary failure";
+ }
+ return "DNS error. Sorry.";
+}
diff --git a/libres/getaddrinfo.c b/libres/getaddrinfo.c
new file mode 100644
index 0000000..3c6f7ee
--- /dev/null
+++ b/libres/getaddrinfo.c
@@ -0,0 +1,137 @@
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <stdlib.h>
+#include <string.h>
+#include <netdb.h>
+#include <net/if.h>
+#include <arpa/inet.h>
+#include "dietdns.h"
+
+/* XXX TODO FIXME */
+
+/* needs:
+ * gethostbyname2_r
+ */
+
+int diet_getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res) {
+ struct addrinfo **tmp;
+ int family;
+ tmp=res; *res=0;
+ if (hints) {
+ if (hints->ai_family && hints->ai_family != PF_INET6 && hints->ai_family != PF_INET) return EAI_FAMILY;
+ if (hints->ai_socktype && hints->ai_socktype != SOCK_STREAM && hints->ai_socktype != SOCK_DGRAM) return EAI_SOCKTYPE;
+ }
+ for (family=PF_INET6; ; family=PF_INET) {
+ if (!hints || hints->ai_family==family || hints->ai_family==AF_UNSPEC) { /* IPv6 addresses are OK */
+ struct hostent h;
+ struct hostent *H;
+ int herrno=0;
+ char buf[4096];
+ int lookupok=0, i;
+ char* interface;
+ h.h_addr_list=(char**)buf+16;
+ h.h_addr_list[1]=0;
+ if (node) {
+ if ((interface=strchr(node,'%'))) ++interface;
+ if (family==PF_INET6 && inet_pton(AF_INET,node,buf)) continue;
+ if (inet_pton(family,node,buf)>0) {
+ h.h_name=(char*)node;
+ h.h_addr_list[0]=buf;
+ lookupok=1;
+ } else if ((!hints || !(hints->ai_flags&AI_NUMERICHOST)) &&
+ !diet_gethostbyname2_r(node,family,&h,buf,4096,&H,&herrno)) {
+ lookupok=1;
+ } else {
+ if (herrno==TRY_AGAIN) { diet_freeaddrinfo(*res); return EAI_AGAIN; }
+ }
+ } else {
+ h.h_name=0;
+ h.h_addr_list[0]=buf;
+ interface=0;
+ memset(buf,0,16);
+ if (!hints || !(hints->ai_flags&AI_PASSIVE)) {
+ if (family==AF_INET) {
+ buf[0]=127; buf[3]=1;
+ } else
+ buf[15]=1;
+ }
+ lookupok=1;
+ }
+ if (lookupok) {
+
+ for (i=0; h.h_addr_list[i]; ++i) {
+ struct ai_v6 {
+ struct addrinfo ai;
+ union {
+ struct sockaddr_in6 ip6;
+ struct sockaddr_in ip4;
+ } ip;
+ char name[1];
+ } *foo;
+ unsigned short port;
+ int len;
+
+ len=sizeof(struct ai_v6)+(h.h_name?strlen(h.h_name):0);
+
+ if (!(foo=malloc(len))) goto error;
+ foo->ai.ai_next=0;
+ foo->ai.ai_addrlen=family==PF_INET6?sizeof(struct sockaddr_in6):sizeof(struct sockaddr_in);
+ foo->ai.ai_addr=(struct sockaddr*)&foo->ip;
+ if (family==PF_INET6) {
+ memset(&foo->ip,0,sizeof(foo->ip));
+ memmove(&foo->ip.ip6.sin6_addr,h.h_addr_list[i],16);
+ if (interface) foo->ip.ip6.sin6_scope_id=if_nametoindex(interface);
+ } else {
+ memmove(&foo->ip.ip4.sin_addr,h.h_addr_list[i],4);
+ }
+ foo->ip.ip6.sin6_family=foo->ai.ai_family=family;
+ if (h.h_name) {
+ foo->ai.ai_canonname=foo->name;
+ memmove(foo->name,h.h_name,strlen(h.h_name)+1);
+ } else
+ foo->ai.ai_canonname=0;
+
+ for (foo->ai.ai_socktype=SOCK_STREAM; ; foo->ai.ai_socktype=SOCK_DGRAM) {
+ char* type,* x;
+ if (foo->ai.ai_socktype==SOCK_STREAM) { /* TCP */
+ if (hints && hints->ai_socktype==SOCK_DGRAM) continue;
+ foo->ai.ai_protocol=IPPROTO_TCP;
+ type="tcp";
+ } else { /* UDP */
+ if (hints && hints->ai_socktype==SOCK_STREAM) break;
+ foo->ai.ai_protocol=IPPROTO_UDP;
+ type="udp";
+ }
+ port=htons(strtol(service?service:"0",&x,0));
+ if (*x) { /* service is not numeric :-( */
+ free(foo);
+ /* no getservbyname on android */
+ diet_freeaddrinfo(*res);
+ return EAI_SERVICE;
+ }
+ if (family==PF_INET6)
+ foo->ip.ip6.sin6_port=port;
+ else
+ foo->ip.ip4.sin_port=port;
+ if (!*tmp) *tmp=&(foo->ai); else (*tmp)->ai_next=&(foo->ai);
+ if (!(foo=malloc(len))) goto error;
+ memmove(foo,*tmp,len);
+ tmp=&(*tmp)->ai_next;
+ foo->ai.ai_addr=(struct sockaddr*)&foo->ip;
+ if (foo->ai.ai_canonname)
+ foo->ai.ai_canonname=foo->name;
+ if (foo->ai.ai_socktype==SOCK_DGRAM) break;
+ }
+ free(foo);
+ }
+ }
+ }
+ if (family==PF_INET) break;
+ }
+ if (*res==0) return EAI_NONAME; /* kludge kludge... */
+ return 0;
+error:
+ diet_freeaddrinfo(*res);
+ return EAI_MEMORY;
+}
diff --git a/libres/gethostbyname2_r.c b/libres/gethostbyname2_r.c
new file mode 100644
index 0000000..2558e5d
--- /dev/null
+++ b/libres/gethostbyname2_r.c
@@ -0,0 +1,35 @@
+#include <string.h>
+#include <strings.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <stdlib.h>
+#include <arpa/inet.h>
+#include <unistd.h>
+#include <errno.h>
+#include "dietdns.h"
+
+/* needs:
+ * __dns_gethostbyx_r
+ */
+
+/* Oh boy, this interface sucks so badly, there are no words for it.
+ * Not one, not two, but _three_ error signalling methods! (*h_errnop
+ * nonzero? return value nonzero? *RESULT zero?) The glibc goons
+ * really outdid themselves with this one. */
+int diet_gethostbyname2_r(const char* name, int AF, struct hostent* result,
+ char *buf, size_t buflen,
+ struct hostent **RESULT, int *h_errnop) {
+ size_t L=strlen(name);
+ int lookfor=0;
+ switch (AF) {
+ case AF_INET: lookfor=1; break;
+ case AF_INET6: lookfor=28; break;
+ default: *h_errnop=EINVAL; return 1;
+ }
+ result->h_name=buf;
+ if (buflen<L) { *h_errnop=ERANGE; return 1; }
+ strcpy(buf,name);
+ return __dns_gethostbyx_r(name,result,buf+L,buflen-L,RESULT,h_errnop,lookfor);
+}
diff --git a/libres/h_errno.c b/libres/h_errno.c
new file mode 100644
index 0000000..fbdfd23
--- /dev/null
+++ b/libres/h_errno.c
@@ -0,0 +1 @@
+int diet_h_errno;
diff --git a/libres/res_init.c b/libres/res_init.c
new file mode 100644
index 0000000..c3a7e6d
--- /dev/null
+++ b/libres/res_init.c
@@ -0,0 +1,12 @@
+#include <resolv.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include "dietdns.h"
+
+extern void __dns_readstartfiles(void);
+
+int diet_res_init(void) {
+ _diet_res.nscount=0;
+ __dns_readstartfiles();
+ return 0;
+}
diff --git a/libres/res_mkquery.c b/libres/res_mkquery.c
new file mode 100644
index 0000000..a8cece6
--- /dev/null
+++ b/libres/res_mkquery.c
@@ -0,0 +1,85 @@
+#include <resolv.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <stdlib.h>
+#include <arpa/inet.h>
+#include <unistd.h>
+#include <errno.h>
+#include <arpa/nameser.h>
+#include "dietdns.h"
+
+/* needs:
+ * _res
+ */
+
+static char dnspacket[]="\xfe\xfe\001\000\000\001\000\000\000\000\000\000";
+
+/*
+ 1 1 1 1 1 1
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | ID |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ |QR| Opcode |AA|TC|RD|RA| Z | RCODE |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | QDCOUNT |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | ANCOUNT |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | NSCOUNT |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | ARCOUNT |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+*/
+
+extern void __dns_make_fd(void);
+extern int __dns_fd;
+
+extern int __dns_servers;
+extern struct sockaddr __dns_server_ips[];
+
+extern void __dns_readstartfiles(void);
+
+int diet_res_mkquery(int op, const char *dname, int class, int type, char* data,
+ int datalen, const unsigned char* newrr, char* buf, int buflen) {
+ unsigned char packet[512];
+ unsigned long len;
+
+ memcpy(packet,dnspacket,12);
+ len=rand();
+ packet[0]=len;
+ packet[1]=len>>8;
+ len=0;
+ if ((_diet_res.options&DIET_RES_RECURSE)==0) packet[2]=0;
+ {
+ unsigned char* x;
+ const char* y,* tmp;
+ x=packet+12; y=dname;
+ while (*y) {
+ while (*y=='.') ++y;
+ for (tmp=y; *tmp && *tmp!='.'; ++tmp) ;
+ if (tmp-y > 63) return -1;
+ *x=tmp-y;
+ if (!(tmp-y)) break;
+ if ((len+=*x+1) > 254) return -1;
+ ++x;
+// if (x>=packet+510-(tmp-y)) { return -1; }
+ memmove(x,y,tmp-y);
+ x+=tmp-y;
+ if (!*tmp) {
+ *x=0;
+ break;
+ }
+ y=tmp;
+ }
+ *++x= 0; *++x= type; /* A */
+ *++x= 0; *++x= class; /* IN */
+ ++x;
+ if (x-packet>buflen) return -1;
+ memmove(buf,packet,x-packet);
+ return x-packet;
+ }
+}
diff --git a/libres/res_query.c b/libres/res_query.c
new file mode 100644
index 0000000..19898b7
--- /dev/null
+++ b/libres/res_query.c
@@ -0,0 +1,81 @@
+#include <resolv.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <stdlib.h>
+#include <arpa/inet.h>
+#include <poll.h>
+#include <unistd.h>
+#include <errno.h>
+#include <arpa/nameser.h>
+#include <fcntl.h>
+#include <sys/time.h>
+#include "dietdns.h"
+
+/* needs:
+ * __dns_fd
+ * __dns_make_fd
+ * __dns_readstartfiles
+ * h_errno
+ * diet_res_mkquery
+ * _res
+ */
+
+extern void __dns_make_fd(void);
+extern int __dns_fd;
+
+extern void __dns_readstartfiles(void);
+
+int diet_res_query(const char *dname, int class, int type, unsigned char *answer, int anslen) {
+ unsigned char packet[512];
+ int size;
+ struct pollfd duh[2];
+ __dns_make_fd();
+
+ __dns_readstartfiles();
+ if ((size=diet_res_mkquery(DIET_QUERY,dname,class,type,0,0,0,(char*)packet,512))<0) { diet_h_errno=NO_RECOVERY; return -1; }
+ {
+ {
+ int i; /* current server */
+ int j; /* timeout count down */
+ struct timeval last,now;
+
+ i=0;
+ duh[0].events=POLLIN;
+ duh[0].fd=0;
+ last.tv_sec=0;
+ for (j=20; j>0; --j) {
+ gettimeofday(&now,0);
+ if (now.tv_sec-last.tv_sec>10) {
+ duh[0].fd=__dns_fd;
+ sendto(__dns_fd,packet,size,0,(struct sockaddr*)&(_diet_res.nsaddr_list[i]),sizeof(struct sockaddr));
+ last=now;
+ }
+ if (++i >= _diet_res.nscount) i=0;
+ if (poll(duh,1,1000) == 1) {
+ /* read and parse answer */
+ unsigned char inpkg[1500];
+ int len=read(duh[0].fd,inpkg,sizeof(inpkg));
+ /* header, question, answer, authority, additional */
+ if (inpkg[0]!=packet[0] || inpkg[1]!=packet[1]) continue; /* wrong ID */
+ if ((inpkg[2]&0xf9) != (_diet_res.options&DIET_RES_RECURSE?0x81:0x80)) continue; /* not answer */
+ if ((inpkg[3]&0x0f) != 0) {
+ diet_h_errno=HOST_NOT_FOUND;
+ return -1;
+ } /* error */
+ if (len>anslen) {
+ diet_h_errno=NO_RECOVERY;
+ return -1;
+ }
+ memcpy(answer,inpkg,len);
+ return len;
+ }
+/*kaputt:*/
+ }
+ }
+ }
+ diet_h_errno=TRY_AGAIN;
+ return -1;
+}
diff --git a/libres/test.c b/libres/test.c
new file mode 100644
index 0000000..45095d8
--- /dev/null
+++ b/libres/test.c
@@ -0,0 +1,105 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <sys/poll.h>
+#include <netinet/icmp6.h>
+#include <netinet/ip_icmp.h>
+#include <netinet/in.h>
+#include <netinet/ip6.h>
+#include <netdb.h>
+#include <arpa/inet.h>
+#include "dietdns.h"
+
+union common_sockaddr {
+ struct sockaddr sa;
+ struct sockaddr_in sin;
+ struct sockaddr_in6 sin6;
+};
+typedef union common_sockaddr sockaddr_any;
+
+static int getaddr (const char *name, sockaddr_any *addr, int af) {
+ int ret;
+ struct addrinfo hints, *ai, *res = NULL;
+
+ memset (&hints, 0, sizeof (hints));
+ hints.ai_family = af;
+ hints.ai_socktype = SOCK_DGRAM;
+ hints.ai_flags = AI_ADDRCONFIG;
+
+ ret = diet_getaddrinfo (name, NULL, &hints, &res);
+ if (ret) {
+ fprintf (stderr, "%s: %s\n", name, diet_gai_strerror (ret));
+ return -1;
+ }
+
+ for (ai = res; ai; ai = ai->ai_next) {
+ if (ai->ai_family == af) break;
+ }
+ if (!ai) ai = res; /* anything... */
+
+ if (ai->ai_addrlen > sizeof (*addr))
+ return -1; /* paranoia */
+ memcpy (addr, ai->ai_addr, ai->ai_addrlen);
+
+ if(res != NULL)
+ diet_freeaddrinfo (res);
+
+ return 0;
+}
+
+static void printaddr(sockaddr_any *addr) {
+ char addr_str[INET6_ADDRSTRLEN];
+
+ if(addr->sa.sa_family == AF_INET) {
+ printf("family = AF_INET\n");
+ if(inet_ntop(addr->sin.sin_family, &addr->sin.sin_addr, (char *)&addr_str, sizeof(addr_str)) == NULL) {
+ perror("inet_ntop failed");
+ return;
+ }
+ printf("addr = %s\n", addr_str);
+ } else if(addr->sa.sa_family == AF_INET6) {
+ printf("family = AF_INET6\n");
+ if(inet_ntop(addr->sin6.sin6_family, &addr->sin6.sin6_addr, (char *)&addr_str, sizeof(addr_str)) == NULL) {
+ perror("inet_ntop failed");
+ return;
+ }
+ printf("addr = %s\n", addr_str);
+ } else {
+ printf("unknown family = %d\n",addr->sa.sa_family);
+ }
+}
+
+int main() {
+ sockaddr_any dst_addr = {{ 0, }, };
+ struct sockaddr_in lsa_u;
+
+ if (getaddr("www.datapipe.net", &dst_addr, AF_INET) < 0) {
+ fprintf(stderr, "getaddr failed\n");
+ } else {
+ printaddr(&dst_addr);
+ }
+
+ if (getaddr("www.datapipe.net", &dst_addr, AF_INET6) < 0) {
+ fprintf(stderr, "getaddr failed\n");
+ } else {
+ printaddr(&dst_addr);
+ }
+
+ inet_aton("127.0.0.1",&lsa_u.sin_addr);
+ lsa_u.sin_port=htons(53);
+ lsa_u.sin_family=AF_INET;
+
+ _diet_res.nscount = 1;
+ _diet_res.nsaddr_list[0] = lsa_u;
+
+ if (getaddr("www.datapipe.net", &dst_addr, AF_INET6) < 0) {
+ fprintf(stderr, "getaddr failed\n");
+ } else {
+ printaddr(&dst_addr);
+ }
+
+ return 0;
+}
diff --git a/networking/nslookup.c b/networking/nslookup.c
index f4fd407..465f4b4 100644
--- a/networking/nslookup.c
+++ b/networking/nslookup.c
@@ -26,6 +26,9 @@
//usage: "Address: 127.0.0.1\n"
#include <resolv.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include "../libres/dietdns.h"
#include "libbb.h"
/*
@@ -78,7 +81,7 @@ static int print_host(const char *hostname, const char *header)
* for each possible socket type (tcp,udp,raw...): */
hint.ai_socktype = SOCK_STREAM;
// hint.ai_flags = AI_CANONNAME;
- rc = getaddrinfo(hostname, NULL /*service*/, &hint, &result);
+ rc = diet_getaddrinfo(hostname, NULL /*service*/, &hint, &result);
if (rc == 0) {
struct addrinfo *cur = result;
@@ -109,7 +112,7 @@ static int print_host(const char *hostname, const char *header)
#endif
}
if (ENABLE_FEATURE_CLEAN_UP && result)
- freeaddrinfo(result);
+ diet_freeaddrinfo(result);
return (rc != 0);
}
@@ -119,11 +122,11 @@ static void server_print(void)
char *server;
struct sockaddr *sa;
-#if ENABLE_FEATURE_IPV6
- sa = (struct sockaddr*)_res._u._ext.nsaddrs[0];
+#if 0
+ sa = (struct sockaddr*)_diet_res._u._ext.nsaddrs[0];
if (!sa)
#endif
- sa = (struct sockaddr*)&_res.nsaddr_list[0];
+ sa = (struct sockaddr*)&_diet_res.nsaddr_list[0];
server = xmalloc_sockaddr2dotted_noport(sa);
print_host(server, "Server:");
@@ -142,11 +145,11 @@ static void set_default_dns(const char *server)
lsa = xhost2sockaddr(server, 53);
if (lsa->u.sa.sa_family == AF_INET) {
- _res.nscount = 1;
+ _diet_res.nscount = 1;
/* struct copy */
- _res.nsaddr_list[0] = lsa->u.sin;
+ _diet_res.nsaddr_list[0] = lsa->u.sin;
}
-#if ENABLE_FEATURE_IPV6
+#if 0
/* Hoped libc can cope with IPv4 address there too.
* No such luck, glibc 2.4 segfaults even with IPv6,
* maybe I misunderstand how to make glibc use IPv6 addr?
@@ -155,9 +158,9 @@ static void set_default_dns(const char *server)
// glibc neither SEGVs nor sends any dgrams with this
// (strace shows no socket ops):
//_res.nscount = 0;
- _res._u._ext.nscount = 1;
+ _diet_res._u._ext.nscount = 1;
/* store a pointer to part of malloc'ed lsa */
- _res._u._ext.nsaddrs[0] = &lsa->u.sin6;
+ _diet_res._u._ext.nsaddrs[0] = &lsa->u.sin6;
/* must not free(lsa)! */
}
#endif
@@ -176,7 +179,7 @@ int nslookup_main(int argc, char **argv)
/* initialize DNS structure _res used in printing the default
* name server and in the explicit name server option feature. */
- res_init();
+ diet_res_init();
/* rfc2133 says this enables IPv6 lookups */
/* (but it also says "may be enabled in /etc/resolv.conf") */
/*_res.options |= RES_USE_INET6;*/
--
1.7.10.4