2006-01-27 05:32:04 +00:00
|
|
|
#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,
|
2006-01-27 08:56:16 +00:00
|
|
|
|
|
|
|
/* RR types */
|
|
|
|
Ta= 1,
|
|
|
|
Tns= 2,
|
|
|
|
Tmd= 3,
|
|
|
|
Tmf= 4,
|
|
|
|
Tcname= 5,
|
|
|
|
Tsoa= 6,
|
|
|
|
Tmb= 7,
|
|
|
|
Tmg= 8,
|
|
|
|
Tmr= 9,
|
|
|
|
Tnull= 10,
|
|
|
|
Twks= 11,
|
|
|
|
Tptr= 12,
|
|
|
|
Thinfo= 13,
|
|
|
|
Tminfo= 14,
|
|
|
|
Tmx= 15,
|
|
|
|
Ttxt= 16,
|
|
|
|
Trp= 17,
|
|
|
|
Tsig= 24,
|
|
|
|
Tkey= 25,
|
|
|
|
Taaaa= 28,
|
|
|
|
Tcert= 37,
|
|
|
|
|
|
|
|
/* query types (all RR types are also queries) */
|
|
|
|
Tixfr= 251, /* incremental zone transfer */
|
|
|
|
Taxfr= 252, /* zone transfer */
|
|
|
|
Tmailb= 253, /* { Tmb, Tmg, Tmr } */
|
|
|
|
Tall= 255, /* all records */
|
|
|
|
|
|
|
|
/* classes */
|
|
|
|
Csym= 0, /* internal symbols */
|
|
|
|
Cin= 1, /* internet */
|
|
|
|
Ccs, /* CSNET (obsolete) */
|
|
|
|
Cch, /* Chaos net */
|
|
|
|
Chs, /* Hesiod (?) */
|
|
|
|
|
|
|
|
/* class queries (all class types are also queries) */
|
|
|
|
Call= 255, /* all classes */
|
|
|
|
|
2006-01-27 05:32:04 +00:00
|
|
|
};
|
|
|
|
|
2006-01-27 08:56:16 +00:00
|
|
|
|
2006-01-27 05:32:04 +00:00
|
|
|
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;
|
|
|
|
|
2006-01-27 08:56:16 +00:00
|
|
|
if((n = res_search(name, Cin, nstype, buf, MAXDNS)) < 0){
|
2006-01-27 05:32:04 +00:00
|
|
|
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[] =
|
|
|
|
{
|
2006-01-27 08:54:27 +00:00
|
|
|
"ip", Ta,
|
|
|
|
"ns", Tns,
|
|
|
|
"md", Tmd,
|
|
|
|
"mf", Tmf,
|
|
|
|
"cname", Tcname,
|
|
|
|
"soa", Tsoa,
|
|
|
|
"mb", Tmb,
|
|
|
|
"mg", Tmg,
|
|
|
|
"mr", Tmr,
|
|
|
|
"null", Tnull,
|
|
|
|
"ptr", Tptr,
|
|
|
|
"hinfo", Thinfo,
|
|
|
|
"minfo", Tminfo,
|
|
|
|
"mx", Tmx,
|
|
|
|
"txt", Ttxt,
|
|
|
|
"rp", Trp,
|
|
|
|
"key", Tkey,
|
|
|
|
"cert", Tcert,
|
|
|
|
"sig", Tsig,
|
|
|
|
"aaaa", Taaaa,
|
|
|
|
"ixfr", Tixfr,
|
|
|
|
"axfr", Taxfr,
|
|
|
|
"all", Call,
|
2006-01-27 05:32:04 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
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;
|
2006-01-27 17:50:46 +00:00
|
|
|
p += 4+len;
|
2006-01-27 05:32:04 +00:00
|
|
|
}
|
|
|
|
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;
|
|
|
|
|
2006-01-27 08:56:16 +00:00
|
|
|
if(rrtype == Tptr)
|
2006-01-27 05:32:04 +00:00
|
|
|
first = ndbnew("ptr", b);
|
|
|
|
else
|
|
|
|
first = ndbnew("dom", b);
|
|
|
|
|
|
|
|
switch(rrtype){
|
|
|
|
default:
|
|
|
|
goto end;
|
2006-01-27 08:56:16 +00:00
|
|
|
case Thinfo:
|
2006-01-27 05:32:04 +00:00
|
|
|
t = rrunpack(buf, ebuf, &p, "YY", "cpu", "os");
|
|
|
|
break;
|
2006-01-27 08:56:16 +00:00
|
|
|
case Tminfo:
|
2006-01-27 05:32:04 +00:00
|
|
|
t = rrunpack(buf, ebuf, &p, "NN", "mbox", "mbox");
|
|
|
|
break;
|
2006-01-27 08:56:16 +00:00
|
|
|
case Tmx:
|
2006-01-27 05:32:04 +00:00
|
|
|
t = rrunpack(buf, ebuf, &p, "SN", "pref", "mx");
|
|
|
|
break;
|
2006-01-27 08:56:16 +00:00
|
|
|
case Tcname:
|
|
|
|
case Tmd:
|
|
|
|
case Tmf:
|
|
|
|
case Tmg:
|
|
|
|
case Tmr:
|
|
|
|
case Tmb:
|
|
|
|
case Tns:
|
|
|
|
case Tptr:
|
|
|
|
case Trp:
|
2006-01-27 05:32:04 +00:00
|
|
|
t = rrunpack(buf, ebuf, &p, "N", type2name(rrtype));
|
|
|
|
break;
|
2006-01-27 08:56:16 +00:00
|
|
|
case Ta:
|
2006-01-27 05:32:04 +00:00
|
|
|
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;
|
2006-01-27 08:56:16 +00:00
|
|
|
case Taaaa:
|
2006-01-27 05:32:04 +00:00
|
|
|
if(rrlen != IPaddrlen)
|
|
|
|
goto corrupt;
|
|
|
|
snprint(tmp, sizeof tmp, "%I", ip);
|
|
|
|
t = ndbnew("ip", tmp);
|
|
|
|
p += rrlen;
|
|
|
|
break;
|
2006-01-27 08:56:16 +00:00
|
|
|
case Tnull:
|
2006-01-27 05:32:04 +00:00
|
|
|
snprint(tmp, sizeof tmp, "%.*H", rrlen, p);
|
|
|
|
t = ndbnew("null", tmp);
|
|
|
|
p += rrlen;
|
|
|
|
break;
|
2006-01-27 08:56:16 +00:00
|
|
|
case Ttxt:
|
2006-01-27 05:32:04 +00:00
|
|
|
t = rrunpack(buf, ebuf, &p, "Y", "txt");
|
|
|
|
break;
|
|
|
|
|
2006-01-27 08:56:16 +00:00
|
|
|
case Tsoa:
|
2006-01-27 05:32:04 +00:00
|
|
|
t = rrunpack(buf, ebuf, &p, "NNLLLLL", "ns", "mbox",
|
|
|
|
"serial", "refresh", "retry", "expire", "ttl");
|
|
|
|
break;
|
|
|
|
|
2006-01-27 08:56:16 +00:00
|
|
|
case Tkey:
|
2006-01-27 05:32:04 +00:00
|
|
|
t = rrunpack(buf, ebuf, &p, "SCCY", "flags", "proto", "alg", "key");
|
|
|
|
break;
|
|
|
|
|
2006-01-27 08:56:16 +00:00
|
|
|
case Tsig:
|
2006-01-27 05:32:04 +00:00
|
|
|
t = rrunpack(buf, ebuf, &p, "SCCLLLSNY", "type", "alg", "labels",
|
|
|
|
"ttl", "exp", "incep", "tag", "signer", "sig");
|
|
|
|
break;
|
|
|
|
|
2006-01-27 08:56:16 +00:00
|
|
|
case Tcert:
|
2006-01-27 05:32:04 +00:00
|
|
|
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;
|
|
|
|
}
|