/* * axfr ns domain - fetch domain from ns, * print on stdout in ndb format * * Steve Simon and Geoff Collyer */ #include #include #include #include #include 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); }