#include #include #include #include #include #include extern const char *__progname; typedef struct name NAME; struct name { char *name; int naddr; int goodaddr; } ; static struct in_addr addr; static int nnames; static NAME *names; static int nganames; static int nnanames; static void usage(void) __attribute__((__noreturn__)); static void usage(void) { fprintf(stderr,"Usage: %s dotted-quad\n",__progname); exit(1); } static int dns_skip(const void *dbuf, int len, int off) { const unsigned char *d; int i; d = dbuf; while (1) { if (off >= len) return(-1); i = d[off]; switch (i & 0xc0) { case 0: if (i) off += i + 1; else return(off+1); break; case 0xc0: if (off+1 >= len) return(-1); return(off+2); break; default: return(-1); break; } } } static int query_it(const char *name, int wanttype, const char *what, void (*fn)(const void *, const void *, const void *, int)) { unsigned char respbuf[8192]; unsigned char compbuf[1024]; unsigned char nbuf[1024]; int rdl; int rl; int n; int i; int x; int nl; int type; int class; static int exp(int inx) { return(dn_expand((const void *)&respbuf[0],(const void *)&respbuf[rl],(const void *)&respbuf[inx],(void *)&compbuf[0],sizeof(compbuf))); } bzero(&respbuf[0],12); /* res_query doesn't check response length (!!) */ printf("[doing %s query for %s]\n",what,name); rl = res_query(name,C_IN,wanttype,(void *)&respbuf[0],sizeof(respbuf)); if (rl <= 0) { printf("res_query failed for `%s'\n",name); return(0); } if (rl < 12) { printf("`%s' lookup response is too short (%d)\n",name,rl); return(0); } if (respbuf[3] & 2) { printf("`%s' lookup response is truncated\n",name); return(0); } n = (respbuf[6] * 256) + respbuf[7]; printf("[response, ancount=%d]\n",n); if (n == 0) return(1); i = (respbuf[4] * 256) + respbuf[5]; x = 12; for (;i>0;i--) { x = dns_skip(&respbuf[0],rl,x); if (x < 0) { printf("`%s' lookup response includes invalid compressed name\n",name); return(0); } x += 4; if (x >= rl) { printf("`%s' lookup response queries overflow packet\n",name); return(0); } } for (i=0;i= rl) { printf("`%s' lookup response answers overflow packet\n",name); return(0); } rdl = (respbuf[x-2] * 256) + respbuf[x-1]; class = (respbuf[x-8] * 256) + respbuf[x-7]; if (class == C_IN) { type = (respbuf[x-10] * 256) + respbuf[x-9]; if (type == T_CNAME) { if (! strcasecmp(&compbuf[0],name)) { nl = exp(x); if (nl < 0) { printf("`%s' lookup response includes invalid compressed name\n",name); return(0); } if (nl != rdl) { printf("`%s' lookup response CNAME data length wrong\n",name); return(0); } printf("[CNAME mapping %s -> %s]\n",name,&compbuf[0]); strcpy(&nbuf[0],&compbuf[0]); name = &nbuf[0]; } } else if (type == wanttype) { if (! strcasecmp(&compbuf[0],name)) { printf("[found %s for %s]\n",what,name); (*fn)((const void *)&respbuf[0],(const void *)&respbuf[rl],(const void *)&respbuf[x],rdl); } } } x += rdl; } return(1); } static void crosscheck(void) { unsigned long int a; char inaddr_name[3+1+3+1+3+1+3+13+1]; int i; static void save_ptr(const void *pktbase, const void *pktend, const void *rrn, int rdl) { unsigned char xbuf[1024]; int xl; xl = dn_expand(pktbase,pktend,rrn,(void *)&xbuf[0],sizeof(xbuf)); if (xl < 0) { printf("in-addr.arpa lookup response includes invalid compressed name\n"); exit(1); } if (xl != rdl) { printf("in-addr.arpa lookup response PTR name length wrong\n"); exit(1); } printf("[got PTR: %s]\n",&xbuf[0]); names = realloc(names,(nnames+1)*sizeof(*names)); names[nnames].name = strdup(&xbuf[0]); nnames ++; } static void check_address(const void *pktbase __attribute__((__unused__)), const void *pktend __attribute__((__unused__)), const void *rrn, int rdl) { unsigned long int v; if (rdl != 4) { printf("%s lookup response A length wrong\n",names[i].name); exit(1); } v = (((const unsigned char *)rrn)[0] << 24) | (((const unsigned char *)rrn)[1] << 16) | (((const unsigned char *)rrn)[2] << 8) | ((const unsigned char *)rrn)[3]; printf("[got A for %s: %d.%d.%d.%d]\n",names[i].name,((const unsigned char *)rrn)[0],((const unsigned char *)rrn)[1],((const unsigned char *)rrn)[2],((const unsigned char *)rrn)[3]); names[i].naddr ++; if (v == a) { names[i].goodaddr = 1; printf("[match for %s]\n",names[i].name); } } nnames = 0; names = 0; a = ntohl(addr.s_addr); printf("[checking %08lx]\n",a); sprintf(&inaddr_name[0],"%lu.%lu.%lu.%lu.in-addr.arpa",a&255,(a>>8)&255,(a>>16)&255,(a>>24)&255); query_it(&inaddr_name[0],T_PTR,"PTR",save_ptr); nganames = 0; for (i=0;igoodaddr); } static int testname_nogood(NAME *n) { return(!n->goodaddr); } static int testname_noaddr(NAME *n) { return(n->naddr==0); } static int testname_ngaddr(NAME *n) { return((n->naddr>0)&&(n->goodaddr==0)); } static const char *dont(int n) { return((n==1)?"doesn't":"don't"); } static const char *havenoaddr(int n) { return((n==1)?"has no address":"have no addresses"); } static const char *nonehave(int n) { return((n==2)?"neither of those has":"none of those have"); } int main(int, char **); int main(int ac, char **av) { if (ac != 2) usage(); if (! inet_aton(av[1],&addr)) usage(); printf("[Checking %s]\n",inet_ntoa(addr)); crosscheck(); printf("host %s",inet_ntoa(addr)); if (nnames == 0) { printf(". This address has no name.\n"); } else if (nnames == 1) { if (names[0].goodaddr) { printf(", %s.\n",names[0].name); } else { switch (names[0].naddr) { case 0: printf(". This address has the name %s, but that name has no address.\n",names[0].name); break; case 1: printf(". This address has the name %s, but that name has a different address.\n",names[0].name); break; default: printf(". This address has the name %s, but that name does not have that address.\n",names[0].name); break; } } } else if (nganames == nnames) { printf(", "); listnames(testname_always); printf(".\n"); } else if (nganames == 0) { printf(". This address has names "); listnames(testname_always); printf(", but %s that address.\n",nonehave(nnames)); } else if ((nganames == 1) && (nnames == 2)) { NAME *g; NAME *ng; g = names[0].goodaddr ? &names[0] : &names[1]; ng = names[0].goodaddr ? &names[1] : &names[0]; printf(", %s; this address also has the name %s, but that name ",g->name,ng->name); switch (ng->naddr) { case 0: printf("has no address.\n"); break; case 1: printf("has a different address.\n"); break; default: printf("does not have that address.\n"); break; } } else if (nganames == 1) { printf(", "); listnames(testname_good); printf("; this address also has names "); listnames(testname_nogood); if (nnanames == 0) { printf(", but %s that address.\n",nonehave(nnames-nganames)); } else if (nnanames == nnames-nganames) { printf(", but %s an address.\n",nonehave(nnames-nganames)); } else { printf(", of which "); listnames(testname_noaddr); printf("%s and ",havenoaddr(nnanames)); listnames(testname_ngaddr); printf("%s have that address.\n",dont(nnames-nganames-nnanames)); } } else { printf("\nnnames %d: ",nnames); listnames(testname_always); printf("\nnganames %d: ",nganames); listnames(testname_good); printf("\nnnanames %d: ",nnanames); listnames(testname_noaddr); printf("\n"); } exit(0); }