aboutsummaryrefslogtreecommitdiff
path: root/src/libndb
diff options
context:
space:
mode:
authorrsc <devnull@localhost>2006-01-27 05:32:04 +0000
committerrsc <devnull@localhost>2006-01-27 05:32:04 +0000
commitbc5d57712754818a2320a385afbf1c0c9558a4b3 (patch)
treec2e1bc094bea133442bcca3912fbfd1068ada3cd /src/libndb
parentee51985f90394959068f41aa42f898c9bb972f08 (diff)
downloadplan9port-bc5d57712754818a2320a385afbf1c0c9558a4b3.tar.gz
plan9port-bc5d57712754818a2320a385afbf1c0c9558a4b3.tar.bz2
plan9port-bc5d57712754818a2320a385afbf1c0c9558a4b3.zip
dns
Diffstat (limited to 'src/libndb')
-rw-r--r--src/libndb/mkfile6
-rw-r--r--src/libndb/sysdnsquery.c409
-rw-r--r--src/libndb/testdns.c35
3 files changed, 448 insertions, 2 deletions
diff --git a/src/libndb/mkfile b/src/libndb/mkfile
index a49cd5e0..b7c9ee96 100644
--- a/src/libndb/mkfile
+++ b/src/libndb/mkfile
@@ -21,6 +21,7 @@ OFILES=\
ndbparse.$O\
ndbreorder.$O\
ndbsubstitute.$O\
+ sysdnsquery.$O\
HFILES=\
$PLAN9/include/ndb.h\
@@ -28,5 +29,6 @@ HFILES=\
<$PLAN9/src/mksyslib
-$O.out: testipinfo.$O
- $LD $prereq
+testdns: testdns.$O $LIBDIR/$LIB
+ $LD -o $target $prereq
+
diff --git a/src/libndb/sysdnsquery.c b/src/libndb/sysdnsquery.c
new file mode 100644
index 00000000..1561c4dd
--- /dev/null
+++ b/src/libndb/sysdnsquery.c
@@ -0,0 +1,409 @@
+#include <u.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+#include <netdb.h>
+#include <libc.h>
+#include <ip.h>
+#include <bio.h>
+#include <ndb.h>
+#include "ndbhf.h"
+
+static void nstrcpy(char*, char*, int);
+static void mkptrname(char*, char*, int);
+static Ndbtuple *doquery(char*, char*);
+
+/*
+ * Run a DNS lookup for val/type on net.
+ */
+Ndbtuple*
+dnsquery(char *net, char *val, char *type)
+{
+ static int init;
+ char rip[128];
+ Ndbtuple *t;
+
+ USED(net);
+
+ if(!init){
+ init = 1;
+ fmtinstall('I', eipfmt);
+ }
+ /* give up early on stupid questions - vwhois */
+ if(strcmp(val, "::") == 0 || strcmp(val, "0.0.0.0") == 0)
+ return nil;
+
+ /* zero out the error string */
+ werrstr("");
+
+ /* if this is a reverse lookup, first look up the domain name */
+ if(strcmp(type, "ptr") == 0){
+ mkptrname(val, rip, sizeof rip);
+ t = doquery(rip, "ptr");
+ }else
+ t = doquery(val, type);
+
+ return t;
+}
+
+/*
+ * convert address into a reverse lookup address
+ */
+static void
+mkptrname(char *ip, char *rip, int rlen)
+{
+ char buf[128];
+ char *p, *np;
+ int len;
+
+ if(strstr(ip, "in-addr.arpa") || strstr(ip, "IN-ADDR.ARPA")){
+ nstrcpy(rip, ip, rlen);
+ return;
+ }
+
+ nstrcpy(buf, ip, sizeof buf);
+ for(p = buf; *p; p++)
+ ;
+ *p = '.';
+ np = rip;
+ len = 0;
+ while(p >= buf){
+ len++;
+ p--;
+ if(*p == '.'){
+ memmove(np, p+1, len);
+ np += len;
+ len = 0;
+ }
+ }
+ memmove(np, p+1, len);
+ np += len;
+ strcpy(np, "in-addr.arpa");
+}
+
+static void
+nstrcpy(char *to, char *from, int len)
+{
+ strncpy(to, from, len);
+ to[len-1] = 0;
+}
+
+/*
+ * Disgusting, ugly interface to libresolv,
+ * which everyone seems to have.
+ */
+enum
+{
+ MAXRR = 100,
+ MAXDNS = 4096,
+};
+
+static int name2type(char*);
+static uchar *skipquestion(uchar*, uchar*, uchar*, int);
+static uchar *unpack(uchar*, uchar*, uchar*, Ndbtuple**, int);
+static uchar *rrnext(uchar*, uchar*, uchar*, Ndbtuple**);
+static Ndbtuple *rrunpack(uchar*, uchar*, uchar**, char*, ...);
+
+static Ndbtuple*
+doquery(char *name, char *type)
+{
+ int n, nstype;
+ uchar *buf, *p;
+ HEADER *h;
+ Ndbtuple *t;
+
+ if((nstype = name2type(type)) < 0){
+ werrstr("unknown dns type %s", type);
+ return nil;
+ }
+
+ buf = malloc(MAXDNS);
+ if(buf == nil)
+ return nil;
+
+ if((n = res_search(name, ns_c_in, nstype, buf, MAXDNS)) < 0){
+ free(buf);
+ return nil;
+ }
+ if(n >= MAXDNS){
+ free(buf);
+ werrstr("too much dns information");
+ return nil;
+ }
+
+ h = (HEADER*)buf;
+ h->qdcount = ntohs(h->qdcount);
+ h->ancount = ntohs(h->ancount);
+ h->nscount = ntohs(h->nscount);
+ h->arcount = ntohs(h->arcount);
+
+ p = buf+sizeof(HEADER);
+ p = skipquestion(buf, buf+n, p, h->qdcount);
+ p = unpack(buf, buf+n, p, &t, h->ancount);
+ USED(p);
+ return t;
+}
+
+static struct {
+ char *s;
+ int t;
+} dnsnames[] =
+{
+ "ip", ns_t_a,
+ "ns", ns_t_ns,
+ "md", ns_t_md,
+ "mf", ns_t_mf,
+ "cname", ns_t_cname,
+ "soa", ns_t_soa,
+ "mb", ns_t_mb,
+ "mg", ns_t_mg,
+ "mr", ns_t_mr,
+ "null", ns_t_null,
+ "ptr", ns_t_ptr,
+ "hinfo", ns_t_hinfo,
+ "minfo", ns_t_minfo,
+ "mx", ns_t_mx,
+ "txt", ns_t_txt,
+ "rp", ns_t_rp,
+ "key", ns_t_key,
+ "cert", ns_t_cert,
+ "sig", ns_t_sig,
+ "aaaa", ns_t_aaaa,
+ "ixfr", ns_t_ixfr,
+ "axfr", ns_t_axfr,
+ "all", ns_t_any,
+};
+
+static char*
+type2name(int t)
+{
+ int i;
+
+ for(i=0; i<nelem(dnsnames); i++)
+ if(dnsnames[i].t == t)
+ return dnsnames[i].s;
+ return nil;
+}
+
+static int
+name2type(char *name)
+{
+ int i;
+
+ for(i=0; i<nelem(dnsnames); i++)
+ if(strcmp(name, dnsnames[i].s) == 0)
+ return dnsnames[i].t;
+ return -1;
+}
+
+static uchar*
+skipquestion(uchar *buf, uchar *ebuf, uchar *p, int n)
+{
+ int i, len;
+ char tmp[100];
+
+ for(i=0; i<n; i++){
+ if((len = dn_expand(buf, ebuf, p, tmp, sizeof tmp)) <= 0)
+ return nil;
+ p += NS_QFIXEDSZ+len;
+ }
+ return p;
+}
+
+static uchar*
+unpack(uchar *buf, uchar *ebuf, uchar *p, Ndbtuple **tt, int n)
+{
+ int i;
+ Ndbtuple *first, *last, *t;
+
+ *tt = nil;
+ first = nil;
+ last = nil;
+ for(i=0; i<n; i++){
+ if((p = rrnext(buf, ebuf, p, &t)) == nil){
+ if(first)
+ ndbfree(first);
+ return nil;
+ }
+ if(t == nil) /* unimplemented rr type */
+ continue;
+ if(last)
+ last->entry = t;
+ else
+ first = t;
+ for(last=t; last->entry; last=last->entry)
+ last->line = last->entry;
+ last->line = t;
+ }
+ *tt = first;
+ return p;
+}
+
+#define G2(p) nhgets(p)
+#define G4(p) nhgetl(p)
+
+static uchar*
+rrnext(uchar *buf, uchar *ebuf, uchar *p, Ndbtuple **tt)
+{
+ char tmp[Ndbvlen];
+ char b[MAXRR];
+ uchar ip[IPaddrlen];
+ int len;
+ Ndbtuple *first, *t;
+ int rrtype;
+ int rrlen;
+
+ first = nil;
+ t = nil;
+ *tt = nil;
+ if(p == nil)
+ return nil;
+
+ if((len = dn_expand(buf, ebuf, p, b, sizeof b)) < 0){
+ corrupt:
+ werrstr("corrupt dns packet");
+ if(first)
+ ndbfree(first);
+ return nil;
+ }
+ p += len;
+
+ rrtype = G2(p);
+ rrlen = G2(p+8);
+ p += 10;
+
+ if(rrtype == ns_t_ptr)
+ first = ndbnew("ptr", b);
+ else
+ first = ndbnew("dom", b);
+
+ switch(rrtype){
+ default:
+ goto end;
+ case ns_t_hinfo:
+ t = rrunpack(buf, ebuf, &p, "YY", "cpu", "os");
+ break;
+ case ns_t_minfo:
+ t = rrunpack(buf, ebuf, &p, "NN", "mbox", "mbox");
+ break;
+ case ns_t_mx:
+ t = rrunpack(buf, ebuf, &p, "SN", "pref", "mx");
+ break;
+ case ns_t_cname:
+ case ns_t_md:
+ case ns_t_mf:
+ case ns_t_mg:
+ case ns_t_mr:
+ case ns_t_mb:
+ case ns_t_ns:
+ case ns_t_ptr:
+ case ns_t_rp:
+ t = rrunpack(buf, ebuf, &p, "N", type2name(rrtype));
+ break;
+ case ns_t_a:
+ if(rrlen != IPv4addrlen)
+ goto corrupt;
+ memmove(ip, v4prefix, IPaddrlen);
+ memmove(ip+IPv4off, p, IPv4addrlen);
+ snprint(tmp, sizeof tmp, "%I", ip);
+ t = ndbnew("ip", tmp);
+ p += rrlen;
+ break;
+ case ns_t_aaaa:
+ if(rrlen != IPaddrlen)
+ goto corrupt;
+ snprint(tmp, sizeof tmp, "%I", ip);
+ t = ndbnew("ip", tmp);
+ p += rrlen;
+ break;
+ case ns_t_null:
+ snprint(tmp, sizeof tmp, "%.*H", rrlen, p);
+ t = ndbnew("null", tmp);
+ p += rrlen;
+ break;
+ case ns_t_txt:
+ t = rrunpack(buf, ebuf, &p, "Y", "txt");
+ break;
+
+ case ns_t_soa:
+ t = rrunpack(buf, ebuf, &p, "NNLLLLL", "ns", "mbox",
+ "serial", "refresh", "retry", "expire", "ttl");
+ break;
+
+ case ns_t_key:
+ t = rrunpack(buf, ebuf, &p, "SCCY", "flags", "proto", "alg", "key");
+ break;
+
+ case ns_t_sig:
+ t = rrunpack(buf, ebuf, &p, "SCCLLLSNY", "type", "alg", "labels",
+ "ttl", "exp", "incep", "tag", "signer", "sig");
+ break;
+
+ case ns_t_cert:
+ t = rrunpack(buf, ebuf, &p, "SSCY", "type", "tag", "alg", "cert");
+ break;
+ }
+ if(t == nil)
+ goto corrupt;
+
+end:
+ first->entry = t;
+ *tt = first;
+ return p;
+}
+
+static Ndbtuple*
+rrunpack(uchar *buf, uchar *ebuf, uchar **pp, char *fmt, ...)
+{
+ char *name;
+ int len, n;
+ uchar *p;
+ va_list arg;
+ Ndbtuple *t, *first, *last;
+ char tmp[Ndbvlen];
+
+ p = *pp;
+ va_start(arg, fmt);
+ first = nil;
+ last = nil;
+ for(; *fmt; fmt++){
+ name = va_arg(arg, char*);
+ switch(*fmt){
+ default:
+ return nil;
+ case 'C':
+ snprint(tmp, sizeof tmp, "%d", *p++);
+ break;
+ case 'S':
+ snprint(tmp, sizeof tmp, "%d", G2(p));
+ p += 2;
+ break;
+ case 'L':
+ snprint(tmp, sizeof tmp, "%d", G4(p));
+ p += 4;
+ break;
+ case 'N':
+ if((len = dn_expand(buf, ebuf, p, tmp, sizeof tmp)) < 0)
+ return nil;
+ p += len;
+ break;
+ case 'Y':
+ len = *p++;
+ n = len;
+ if(n >= sizeof tmp)
+ n = sizeof tmp-1;
+ memmove(tmp, p, n);
+ p += len;
+ tmp[n] = 0;
+ break;
+ }
+ t = ndbnew(name, tmp);
+ if(last)
+ last->entry = t;
+ else
+ first = t;
+ last = t;
+ }
+ *pp = p;
+ return first;
+}
diff --git a/src/libndb/testdns.c b/src/libndb/testdns.c
new file mode 100644
index 00000000..6c72c5d8
--- /dev/null
+++ b/src/libndb/testdns.c
@@ -0,0 +1,35 @@
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <ndb.h>
+
+void
+main(int argc, char **argv)
+{
+ Ndbtuple *t, *t0;
+
+ ARGBEGIN{
+ default:
+ goto usage;
+ }ARGEND
+
+ if(argc != 2){
+ usage:
+ fprint(2, "usage: testdns name val\n");
+ exits("usage");
+ }
+
+ quotefmtinstall();
+ if((t = dnsquery(nil, argv[0], argv[1])) == nil)
+ sysfatal("dnsquery: %r");
+
+ for(t0=t; t; t=t->entry){
+ print("%s=%q ", t->attr, t->val);
+ if(t->line == t0){
+ print("\n");
+ t0 = t->entry;
+ }
+ }
+ exits(0);
+}
+