/*
* axfr ns domain - fetch domain from ns,
* print on stdout in ndb format
*
* Steve Simon and Geoff Collyer
*/
#include <u.h>
#include <libc.h>
#include <bio.h>
#include <ip.h>
#include <ctype.h>
Biobuf *Bo;
enum {
FQDNMAX = 255,
Cin = 1, // internet
Ccs = 2, // csnet
Cch = 3, // CHAOS
Chs = 4, // Hesoid
Call = 255,
Ta = 1, // a host address
Tns = 2, // an authoritative name server
Tmd = 3, // a mail destination (Obsolete - use MX)
Tmf = 4, // a mail forwarder (Obsolete - use MX)
Tcname = 5, // the canonical name for an alias
Tsoa = 6, // marks the start of a zone of authority
Tmb = 7, // a mailbox domain name (EXPERIMENTAL)
Tmg = 8, // a mail group member (EXPERIMENTAL)
Tmr = 9, // a mail rename domain name (EXPERIMENTAL)
Tnull = 10, // a null RR (EXPERIMENTAL)
Twks = 11, // a well known service description
Tptr = 12, // a domain name pointer
Thinfo = 13, // host information
Tminfo = 14, // mailbox or mail list information
Tmx = 15, // mail exchange
Ttxt = 16, // text strings
Trp = 17, // for Responsible Person
Tafsdb = 18, // for AFS Data Base location
Tx25 = 19, // for X.25 PSDN address
Tisdn = 20, // for ISDN address
Trt = 21, // for Route Through
Tnsap = 22, // for NSAP address, NSAP style A record
Tnsap_ptr = 23, // for domain name pointer, NSAP style
Tsig = 24, // for security signature
Tkey = 25, // for security key
Tpx = 26, // X.400 mail mapping information
Tgpos = 27, // Geographical Position
Taaaa = 28, // IP6 Address
Tloc = 29, // Location Information
Tnxt = 30, // Next Domain (obsolete)
Teid = 31, // Endpoint Identifier
Tnimloc = 32, // Nimrod Locator
Tsrv = 33, // Server Selection
Tatma = 34, // ATM Address
Tnaptr = 35, // Naming Authority Pointer
Tkx = 36, // Key Exchanger
Tcert = 37,
Ta6 = 38,
Tdname = 39,
Tsink = 40,
Topt = 41,
Tapl = 42,
Tds = 43, // Delegation Signer
Tsshfp = 44, // SSH Key Fingerprint
Trrsig = 46,
Tnsec = 47,
Tdnskey = 48,
Tuinfo = 100,
Tuid = 101,
Tgid = 102,
Tunspec = 103,
Taddrs = 248,
Ttkey = 249,
Ttsig = 250, // Transaction Signature
Tixfr = 251, // Incremental transfer
Taxfr = 252, // transfer of an entire zone
Tmailb = 253, // mailbox-related RRs (MB, MG or MR)
Tmaila = 254, // mail agent RRs (Obsolete - see MX)
Tall = 255, // A request for all records
Twins = 0xff01, // MS WINS server
Twinsr = 0xff02, // MS wins reverse lookup
};
static char *Typestr[] = {
[Ta] "a",
[Tns] "ns",
[Tmd] "md",
[Tmf] "mf",
[Tcname] "cname",
[Tsoa] "soa",
[Tmb] "mb",
[Tmg] "mg",
[Tmr] "mr",
[Tnull] "null",
[Twks] "wks",
[Tptr] "ptr",
[Thinfo] "hinfo",
[Tminfo] "minfo",
[Tmx] "mx",
[Ttxt] "txt",
[Trp] "rp",
[Tafsdb] "afsdb",
[Tx25] "x25",
[Tisdn] "isdn",
[Trt] "rt",
[Tnsap] "nsap",
[Tnsap_ptr] "nsap_ptr",
[Tsig] "sig",
[Tkey] "key",
[Tpx] "px",
[Tgpos] "gpos",
[Taaaa] "aaaa",
[Tloc] "loc",
[Tnxt] "nxt",
[Teid] "eid",
[Tnimloc] "nimloc",
[Tsrv] "srv",
[Tatma] "atma",
[Tnaptr] "naptr",
[Tkx] "kx",
[Tcert] "cert",
[Ta6] "a6",
[Tdname] "dname",
[Tsink] "sink",
[Topt] "opt",
[Tapl] "apl",
[Tds] "ds",
[Tsshfp] "sshfp",
[Trrsig] "rrsig",
[Tnsec] "nsec",
[Tdnskey] "dnskey",
[Tuinfo] "uinfo",
[Tuid] "uid",
[Tgid] "gid",
[Tunspec] "unspec",
[Taddrs] "addrs",
[Ttkey] "tkey",
[Ttsig] "tsig",
[Tixfr] "ixfr",
[Taxfr] "axfr",
[Tmailb] "mailb",
[Tmaila] "maila",
[Tall] "all",
};
int Debug;
void
usage(void)
{
fprint(2, "usage: %s [-x netmtpt] [-d] nameserver domainname\n", argv0);
exits("usage");
}
void
ding(void *u, char *msg)
{
USED(u);
if(strstr(msg, "alarm"))
noted(NCONT);
noted(NDFLT);
}
int
g8(uchar **p)
{
return *(*p)++;
}
int
g16(uchar **p)
{
int n;
n = *(*p)++ << 8;
n |= *(*p)++;
return n;
}
int
g32(uchar **p)
{
int n;
n = *(*p)++ << 24;
n |= *(*p)++ << 16;
n |= *(*p)++ << 8;
n |= *(*p)++;
return n;
}
void
gname(uchar **p, uchar *buf, char *s)
{
char *last = s;
uchar *q;
int n;
while (n = g8(p)){
if(n & 0xc0){
(*p)--;
n = g16(p);
q = buf + (n & 0x3fff) +2; // +2 to skip packet len
gname(&q, buf, s);
return;
}
while (**p && n--)
*s++ = *(*p)++;
last = s;
*s++ = '.';
}
*last = 0;
}
void
skip(uchar **p, int len)
{
if(Debug)
Bprint(Bo, "skiped %d bytes at end of record\n", len);
*p += len;
}
void *
gmem(uchar **p, int len)
{
char *t, *s;
assert(s = malloc(len));
for (t = s; len; len--)
*t++ = *(*p)++;
return s;
}
void
p8(uchar **p, int n)
{
*(*p)++ = n & 0xff;
}
void
p16(uchar **p, int n)
{
*(*p)++ = (n >> 8) & 0xff;
*(*p)++ = n & 0xff;
}
void
p32(uchar **p, int n)
{
*(*p)++ = (n >> 24) & 0xff;
*(*p)++ = (n >> 16) & 0xff;
*(*p)++ = (n >> 8) & 0xff;
*(*p)++ = n & 0xff;
}
void
pmem(uchar **p, void *v, int len)
{
char *s;
for(s = v; len; len--)
*(*p)++ = *s++;
}
void
pname(uchar **p, char *s)
{
uchar *len;
while (*s){
len = (*p)++;
while(*s && *s != '.')
*(*p)++ = *s++;
*len = (*p - len) -1;
if(*s == '.')
s++;
}
*(*p)++ = 0;
}
void
xd(void *p, int l)
{
int i;
uchar *buf = p;
Bprint(Bo, "\n%-4x ", 0);
for (i = 0; i < l && i < 128; i++){
if(isprint(buf[i]))
Bprint(Bo, " %c ", buf[i]);
else
Bprint(Bo, "%02x ", buf[i]);
if(i != 0 && (i % 16) == 0)
Bprint(Bo, "\n%-4x ", i);
}
Bprint(Bo, "\n");
}
void
pr(uchar **pp, uchar *buf, int vlen, char *name, int type)
{
int n, i, j, k;
uchar *ad = nil;
char *p = nil, *a[128], s[FQDNMAX +1];
switch(type){
case Ta:
ad = gmem(pp, vlen);
Bprint(Bo, "dom=%s ip=%V\n", name, ad);
break;
case Taaaa:
ad = gmem(pp, vlen);
Bprint(Bo, "dom=%s ip=%I\n", name, ad);
break;
case Thinfo:
p = gmem(pp, vlen);
Bprint(Bo, "dom=%s hinfo=\"%s\"\n", name, p);
break;
case Ttxt:
do{
n = g8(pp);
p = gmem(pp, n);
Bprint(Bo, "dom=%s txtrr=\"%.*s\"\n", name, n, p);
free(p);
p = nil;
vlen -= n+1;
}while(vlen > 0);
break;
case Trp:
gname(pp, buf, s);
if((p = strchr(s, '.')) != nil)
*p = '@';
p = nil; // don't free p
Bprint(Bo, "dom=%s contact=%s\n", name, s);
break;
case Tns:
gname(pp, buf, s);
Bprint(Bo, "dom=%s ns=%s\n", name, s);
break;
case Tptr:
gname(pp, buf, s);
Bprint(Bo, "dom=%s ptr=%s\n", s, name);
break;
case Tcname:
gname(pp, buf, s);
Bprint(Bo, "dom=%s cname=%s\n", name, s);
break;
case Tmx:
n = g16(pp);
gname(pp, buf, s);
Bprint(Bo, "dom=%s mx=%s pref=%ud\n", name, s, n);
break;
case Tsoa:
Bprint(Bo, "dom=%s soa= ", name);
gname(pp, buf, s);
Bprint(Bo, "ns=%s ", s);
gname(pp, buf, s);
if((p = strchr(s, '.')) != nil)
*p = '@';
p = nil; // don't free p
Bprint(Bo, "mbox=%s ", s);
Bprint(Bo, "serial=%ud ", g32(pp));
Bprint(Bo, "refresh=%ud ", g32(pp));
Bprint(Bo, "retry=%ud ", g32(pp));
Bprint(Bo, "expire=%ud ", g32(pp));
Bprint(Bo, "min=%ud\n", g32(pp));
break;
case Tsrv:
i = g16(pp);
j = g16(pp);
k = g16(pp);
gname(pp, buf, s);
if((n = gettokens(name, a, 3, "._")) != 3)
sysfatal("%s, %d fields - corrupt srv record\n", name, n);
Bprint(Bo, "srv=%s ", a[2]);
Bprint(Bo, "service=%s ", a[0]);
Bprint(Bo, "port=%ud ", k);
Bprint(Bo, "proto=%s ", a[1]);
Bprint(Bo, "priority=%ud ", i);
Bprint(Bo, "weight=%ud ", j);
Bprint(Bo, "dom=%s\n", s);
break;
case Tgpos:
Bprint(Bo, "# dom=%s ", name);
Bprint(Bo, "longitude=%d ", g16(pp));
Bprint(Bo, "latitude=%d ", g16(pp));
Bprint(Bo, "altitude=%d\n", g16(pp));
break;
case Tx25:
p = gmem(pp, vlen);
Bprint(Bo, "dom=%s x25=%s\n", name, p);
break;
case Tisdn:
p = gmem(pp, vlen);
Bprint(Bo, "dom=%s isdn=%s\n", name, p);
break;
case Twins:
Bprint(Bo, "wins=%s ", name);
Bprint(Bo, "replication=%s ", g32(pp)? "none": "active");
Bprint(Bo, "timeout=%d ", g32(pp));
Bprint(Bo, "cache=%d ", g32(pp));
n = g32(pp);
while(n--){
ad = gmem(pp, 4);
Bprint(Bo, "server=%V ", ad);
free(ad);
ad = nil;
}
Bprint(Bo, "\n");
break;
case Twinsr:
Bprint(Bo, "winsr=%s ", name);
Bprint(Bo, "replication=%s ", g32(pp)? "none": "active");
Bprint(Bo, "timeout=%d ", g32(pp));
Bprint(Bo, "cache=%d ", g32(pp));
gname(pp, buf, s);
Bprint(Bo, "domain=%s\n", s);
break;
default:
if(type > 0 && type < nelem(Typestr) && Typestr[type])
Bprint(Bo, "# %s=%s unsupported\n", Typestr[type], name);
else{
Bprint(Bo, "# %ux=%s unknown\n", type, name);
xd(*pp, vlen);
}
skip(pp, vlen);
break;
}
free(p);
free(ad);
}
/*
* Evade DNS poisioning, detect records that refer
* to domains other than the one we asked about.
*/
int
mydom(char *me, char *dom)
{
int m, d;
m = strlen(me);
d = strlen(dom);
if (m > d)
return 0;
return cistrcmp(me, dom+(d-m)) == 0;
}
void
main(int argc, char *argv[])
{
Biobuf bout;
char net[64], name[FQDNMAX +1];
uchar *p, obuf[0xff], *ibuf;
int nsoa, nans, naut, nadd, vlen, len, id;
int type, class, err, i, fd;
Bo = &bout;
Binit(&bout, 1, OWRITE);
nsoa = 0;
Debug = 0;
setnetmtpt(net, sizeof(net), nil);
ARGBEGIN{
case 'd':
Debug++;
break;
case 'x':
setnetmtpt(net, sizeof(net), EARGF(usage()));
break;
}ARGEND;
if(argc != 2)
usage();
fmtinstall('I', eipfmt);
fmtinstall('V', eipfmt);
if((fd = dial(netmkaddr(argv[0], "tcp", "dns"), 0, 0, 0)) < 0)
sysfatal("%s can't dial - %r", argv[0]);
id = time(nil) + getpid();
p = obuf;
p16(&p, 0); // length, filled in later
p16(&p, id); // ID
p16(&p, 0); // flags
p16(&p, 1); // # questions
p16(&p, 0); // # answers
p16(&p, 0); // # authorities
p16(&p, 0); // # additional
pname(&p, argv[1]); // question name
p16(&p, Taxfr); // question type (AXFR - zone transfer)
p16(&p, Cin); // question class (Internet)
len = p-obuf;
p = obuf;
p16(&p, len -2); // -2 as length is non-inclusive
if(write(fd, obuf, len) != len)
sysfatal("write failed: %r");
notify(ding);
while(1){
assert(ibuf = malloc(2));
alarm(5000);
if(readn(fd, ibuf, 2) != 2)
sysfatal("failed - timeout");
p = ibuf;
len = g16(&p);
assert(ibuf = realloc(ibuf, len +2));
if(readn(fd, ibuf +2, len) != len)
sysfatal("failed - timeout");
alarm(0);
if(g16(&p) != (id & 0xffff))
sysfatal("bad packet ID");
err = g16(&p) & 7; // flags
g16(&p); // # questions
nans = g16(&p); // # answers
naut = g16(&p); // # authorities
nadd = g16(&p); // # additional
gname(&p, ibuf, name); // name requested
type = g16(&p); // type requested
class = g16(&p); // class requested
switch(err){
case 0: break; // success
case 1: sysfatal("bad request");
case 2: sysfatal("internal server failure");
case 3: sysfatal("resource does not exist");
case 4: sysfatal("request not supported");
case 5: sysfatal("permission denied");
default: sysfatal("%d - unknown server error", err);
}
if(Debug){
Bprint(Bo, "got ans=%d auth=%d add=%d type=%d class=%d name=%s\n",
nans, naut, nadd, type, class, name);
xd(ibuf, len);
}
for (i = 0; i < nans; i++){
gname(&p, ibuf, name);
type = g16(&p); // type
g16(&p); // class
g32(&p); // TTL
vlen = g16(&p); // name length
if(type == Tsoa && nsoa++ > 0)
goto done;
if(Debug > 1)
Bprint(Bo, "type=%d len=%d name=%s ", type, len, name);
if (! mydom(argv[1], name))
Bprint(Bo, "#poison: ");
pr(&p, ibuf, vlen, name, type);
}
if(Debug && (p-ibuf > len+2))
fprint(2, "skiped %ld bytes at end of packet\n", (p-ibuf)-(len+2));
free(ibuf);
}
done:
free(ibuf);
close(fd);
exits(0);
}
|