From 86e7b8d96483d2f55561aa76ac96e7663840b796 Mon Sep 17 00:00:00 2001 From: ian Date: Tue, 10 Nov 1998 01:03:54 +0000 Subject: [PATCH] Import changes from chiark: cvs rdiff -u -r tochiark-1998-11-08 -r fromchiark-1998-11-09 >~/private/t dnslib --- client/adnstest.c | 63 +++++++++++++++++++++++++++++++-------- src/adns.h | 30 ++++++++++++++++++- src/general.c | 76 +++++++++++++++++++++++++++++++++++++++++++++-- src/internal.h | 27 ++++++++++------- src/parse.c | 28 ++++++++++------- src/reply.c | 29 +++++++++++------- src/types.c | 64 +++++++++++++++++++++++---------------- 7 files changed, 246 insertions(+), 71 deletions(-) diff --git a/client/adnstest.c b/client/adnstest.c index 1752072..46a0258 100644 --- a/client/adnstest.c +++ b/client/adnstest.c @@ -22,27 +22,66 @@ #include #include +#include +#include #include "adns.h" -int main(void) { +static void failure(const char *what, adns_status st) { + fprintf(stderr,"adns failure: %s: %s\n",what,adns_strerror(st)); + exit(2); +} + +static const char *defaultargv[]= { "ns.chiark.greenend.org.uk", 0 }; + +int main(int argc, const char *const *argv) { adns_state ads; - adns_query qu; + adns_query *qus, qu; adns_answer *ans; - int r; + const char *rrtn, *fmtn; + char *show; + int len, i, qc, qi; + adns_status r, ri; + + if (argv[0] && argv[1]) argv++; + else argv= defaultargv; + + for (qc=0; qc[argv]; qc++); + qus= malloc(sizeof(qus)*qc); + if (!qus) { perror("malloc qus"); exit(3); } r= adns_init(&ads,adns_if_debug|adns_if_noautosys,0); - if (r) { perror("init"); exit(2); } + if (r) failure("init",r); + + for (qi=0; qitype, &rrtn,&fmtn,&len, 0,0); + fprintf(stdout, "%s: %s; nrrs=%d; cname=%s; ", + argv[qi], adns_strerror(ans->status), + ans->nrrs, ans->cname ? ans->cname : "$"); + fprintf(stdout, "type %s(%s) %s\n", + ri ? "?" : rrtn, ri ? "?" : fmtn ? fmtn : "-", + adns_strerror(ri)); + if (ans->nrrs) { + assert(!ri); + for (i=0; inrrs; i++) { + r= adns_rr_info(ans->type, 0,0,0, ans->rrs.bytes+i*len,&show); + if (r) failure("info",r); + printf(" %s\n",show); + free(show); + } + } + free(ans); + } - fprintf(stderr,"answer status %d type %d rrs %d cname %s\n", - ans->status,ans->type,ans->nrrs, - ans->cname ? ans->cname : "-"); - + free(qus); exit(0); } diff --git a/src/adns.h b/src/adns.h index 9f9cb12..a800813 100644 --- a/src/adns.h +++ b/src/adns.h @@ -163,7 +163,7 @@ typedef struct { typedef struct { adns_status status; char *cname; /* always NULL if query was for CNAME records */ - adns_rrtype type; + adns_rrtype type; /* guaranteed to be same as in query */ int nrrs, rrsz; union { void *untyped; @@ -288,6 +288,34 @@ void adns_interest(adns_state, int *maxfd_io, fd_set *readfds_io, * } */ +adns_status adns_rr_info(adns_rrtype type, + const char **rrtname_r, const char **fmtname_r, + int *len_r, + const void *datap, char **data_r); +/* Gets information in human-readable (but non-i18n) form + * for eg debugging purposes. type must be specified, + * and the official name of the corresponding RR type will + * be returned in *rrtname_r, and information about the processing + * style in *fmtname_r. The length of the table entry in an answer + * for that type will be returned in in *len_r. + * Any or all of rrtname_r, fmtname_r and len_r may be 0. + * If fmtname_r is non-null then *fmtname_r may be + * null on return, indicating that no special processing is + * involved. + * + * data_r be must be non-null iff datap is. In this case + * *data_r will be set to point to a human-readable text + * string representing the RR data. The text will have + * been obtained from malloc() and must be freed by the caller. + * + * Usually this routine will succeed. Possible errors include: + * adns_s_nomemory + * adns_s_notimplemented (RR type not known) + * adns_s_invaliddata (*datap contained garbage) + * If an error occurs then no memory has been allocated, + * and *rrtname_r, *fmtname_r, *len_r and *data_r are undefined. + */ + const char *adns_strerror(adns_status st); #endif diff --git a/src/general.c b/src/general.c index efad813..37edfa3 100644 --- a/src/general.c +++ b/src/general.c @@ -48,7 +48,9 @@ void adns__vdiag(adns_state ads, const char *pfx, adns_initflags prevent, bef, adns__diag_domain(qu->ads,-1,0, &vb,qu->flags, qu->query_dgram,qu->query_dglen,DNS_HDRSIZE), - qu->typei ? qu->typei->name : ""); + qu->typei ? qu->typei->rrtname : ""); + if (qu->typei && qu->typei->fmtname) + fprintf(stderr,"(%s)",qu->typei->fmtname); bef=", "; aft=")\n"; } @@ -159,9 +161,79 @@ const char *adns__diag_domain(adns_state ads, int serv, adns_query qu, vbuf *vb, } return vb->buf; } - + +adns_status adns_rr_info(adns_rrtype type, + const char **rrtname_r, const char **fmtname_r, + int *len_r, + const void *datap, char **data_r) { + const typeinfo *typei; + vbuf vb; + adns_status st; + + typei= adns__findtype(type); + if (!typei) return adns_s_notimplemented; + + if (rrtname_r) *rrtname_r= typei->rrtname; + if (fmtname_r) *fmtname_r= typei->fmtname; + if (len_r) *len_r= typei->rrsz; + + if (!datap) return adns_s_ok; + + adns__vbuf_init(&vb); + st= typei->convstring(&vb,datap); + if (st) goto x_freevb; + if (!adns__vbuf_append(&vb,"",1)) { st= adns_s_nolocalmem; goto x_freevb; } + assert(strlen(vb.buf) == vb.used-1); + *data_r= realloc(vb.buf,vb.used); + if (!*data_r) *data_r= vb.buf; + return adns_s_ok; + + x_freevb: + adns__vbuf_free(&vb); + return st; +} + +#define SINFO(n,s) { adns_s_##n, s } + +static const struct sinfo { + adns_status st; + const char *string; +} sinfos[]= { + SINFO( ok, "OK" ), + SINFO( timeout, "Timed out" ), + SINFO( nolocalmem, "Out of memory" ), + SINFO( allservfail, "No working nameservers" ), + SINFO( servfail, "Nameserver failure" ), + SINFO( notimplemented, "Query not implemented" ), + SINFO( refused, "Refused by nameserver" ), + SINFO( reasonunknown, "Reason unknown" ), + SINFO( norecurse, "Recursion denied by nameserver" ), + SINFO( serverfaulty, "Nameserver sent bad data" ), + SINFO( unknownreply, "Reply from nameserver not understood" ), + SINFO( invaliddata, "Invalid data" ), + SINFO( inconsistent, "Inconsistent data" ), + SINFO( cname, "RR refers to an alias" ), + SINFO( nxdomain, "No such domain" ), + SINFO( nodata, "No such data" ), + SINFO( invaliddomain, "Domain syntactically invalid" ), + SINFO( domaintoolong, "Domain name too long" ) +}; + +static int si_compar(const void *key, const void *elem) { + const adns_status *st= key; + const struct sinfo *si= elem; + + return *st < si->st ? -1 : *st > si->st ? 1 : 0; +} + const char *adns_strerror(adns_status st) { static char buf[100]; + + const struct sinfo *si; + + si= bsearch(&st,sinfos,sizeof(sinfos)/sizeof(*si),sizeof(*si),si_compar); + if (si) return si->string; + snprintf(buf,sizeof(buf),"code %d",st); return buf; } diff --git a/src/internal.h b/src/internal.h index 257953f..852c05c 100644 --- a/src/internal.h +++ b/src/internal.h @@ -82,9 +82,21 @@ typedef union { typedef struct { adns_rrtype type; - const char *name; + const char *rrtname; + const char *fmtname; int rrsz; + void (*makefinal)(adns_query qu, void *data); + /* Change memory management of *data. + * Previously, used alloc_interim, now use alloc_final. + */ + + adns_status (*convstring)(vbuf *vb, const void *data); + /* Converts the RR data to a string representation in vbuf. + * vbuf will be appended to (it must have been initialised), + * and will not be null-terminated by convstring. + */ + adns_status (*parse)(adns_query qu, int serv, const byte *dgram, int dglen, int cbyte, int max, void *store_r); @@ -96,11 +108,6 @@ typedef struct { * If there is an overrun which might indicate truncation, it should set * *rdstart to -1; otherwise it may set it to anything else positive. */ - - void (*makefinal)(adns_query qu, void *data); - /* Change memory management of *data. - * Previously, used alloc_interim, now use alloc_final. - */ } typeinfo; typedef struct allocnode { @@ -487,16 +494,16 @@ static inline int ctype_alpha(int c) { #define LIST_LINK_TAIL_PART(list,node,part) \ do { \ - (node)->part back= 0; \ - (node)->part next= (list).tail; \ - if ((list).tail) (list).tail->part back= (node); else (list).part head= (node); \ + (node)->part next= 0; \ + (node)->part back= (list).tail; \ + if ((list).tail) (list).tail->part next= (node); else (list).part head= (node); \ (list).tail= (node); \ } while(0) #define LIST_UNLINK(list,node) LIST_UNLINK_PART(list,node,) #define LIST_LINK_TAIL(list,node) LIST_LINK_TAIL_PART(list,node,) -#define GETIL_B(cb) (dgram[(cb)++]) +#define GETIL_B(cb) (((dgram)[(cb)++]) & 0x0ff) #define GET_B(cb,tv) ((tv)= GETIL_B((cb))) #define GET_W(cb,tv) ((tv)=0, (tv)|=(GETIL_B((cb))<<8), (tv)|=GETIL_B(cb), (tv)) diff --git a/src/parse.c b/src/parse.c index 099deb7..46d76fa 100644 --- a/src/parse.c +++ b/src/parse.c @@ -63,25 +63,30 @@ void adns__findlabel_start(findlabel_state *fls, adns_state ads, adns_status adns__findlabel_next(findlabel_state *fls, int *lablen_r, int *labstart_r) { - int lablen, jumped; + int lablen, jumped, jumpto; const char *dgram; jumped= 0; dgram= fls->dgram; for (;;) { - if (fls->cbyte+2 > fls->dglen) goto x_truncated; - if (fls->cbyte+2 > fls->max) goto x_serverfaulty; - GET_W(fls->cbyte,lablen); - if (!(lablen & 0x0c000)) break; - if ((lablen & 0x0c000) != 0x0c000) return adns_s_unknownreply; + if (fls->cbyte >= fls->dglen) goto x_truncated; + if (fls->cbyte >= fls->max) goto x_serverfaulty; + GET_B(fls->cbyte,lablen); + if (!(lablen & 0x0c0)) break; + if ((lablen & 0x0c0) != 0x0c0) return adns_s_unknownreply; if (jumped++) { adns__diag(fls->ads,fls->serv,fls->qu,"compressed datagram contains loop"); return adns_s_serverfaulty; } + if (fls->cbyte >= fls->dglen) goto x_truncated; + if (fls->cbyte >= fls->max) goto x_serverfaulty; + GET_B(fls->cbyte,jumpto); + jumpto |= (lablen&0x3f)<<8; if (fls->dmend_r) *(fls->dmend_r)= fls->cbyte; - fls->cbyte= DNS_HDRSIZE+(lablen&0x3fff); + fls->cbyte= jumpto; fls->dmend_r= 0; fls->max= fls->dglen+1; } + if (labstart_r) *labstart_r= fls->cbyte; if (lablen) { if (fls->namelen) fls->namelen++; fls->namelen+= lablen; @@ -92,8 +97,8 @@ adns_status adns__findlabel_next(findlabel_state *fls, } else { if (fls->dmend_r) *(fls->dmend_r)= fls->cbyte; } - if (labstart_r) *labstart_r= fls->cbyte; *lablen_r= lablen; +/*if (labstart_r) fprintf(stderr,"label %d >%.*s<\n",lablen,lablen,fls->dgram+*labstart_r);*/ return adns_s_ok; x_truncated: @@ -185,12 +190,13 @@ static adns_status findrr_intern(adns_query qu, int serv, st= adns__findlabel_next(&eo_fls,&eo_lablen,&eo_labstart); assert(!st); assert(eo_lablen>=0); if (lablen != eo_lablen) mismatch= 1; - while (!mismatch && lablen-- > 0) { + while (!mismatch && eo_lablen-- > 0) { ch= dgram[labstart++]; if (ctype_alpha(ch)) ch &= ~32; eo_ch= eo_dgram[eo_labstart++]; if (ctype_alpha(eo_ch)) eo_ch &= ~32; if (ch != eo_ch) mismatch= 1; } } + if (!lablen) break; } if (eo_matched_r) *eo_matched_r= !mismatch; @@ -198,7 +204,7 @@ static adns_status findrr_intern(adns_query qu, int serv, GET_W(cbyte,tmp); *type_r= tmp; GET_W(cbyte,tmp); *class_r= tmp; cbyte+= 4; /* we skip the TTL */ - GET_W(cbyte,rdlen); if (rdlen_r) *rdlen_r= tmp; + GET_W(cbyte,rdlen); if (rdlen_r) *rdlen_r= rdlen; if (rdstart_r) *rdstart_r= cbyte; cbyte+= rdlen; if (cbyte>dglen) goto x_truncated; @@ -207,7 +213,7 @@ static adns_status findrr_intern(adns_query qu, int serv, x_truncated: *type_r= -1; - return 0;; + return 0; } adns_status adns__findrr(adns_query qu, int serv, diff --git a/src/reply.c b/src/reply.c index f98540c..5ed6581 100644 --- a/src/reply.c +++ b/src/reply.c @@ -23,12 +23,12 @@ #include "internal.h" static void cname_recurse(adns_query qu, adns_queryflags xflags) { - abort(); /* FIXME */ + assert(!"cname not implemented"); /* FIXME */ } void adns__procdgram(adns_state ads, const byte *dgram, int dglen, int serv, struct timeval now) { - int cbyte, rrstart, wantedrrs, rri, foundsoa, foundns; + int cbyte, rrstart, wantedrrs, rri, foundsoa, foundns, cname_here; int id, f1, f2, qdcount, ancount, nscount, arcount; int flg_ra, flg_rd, flg_tc, flg_qr, opcode; int rrtype, rrclass, rdlength, rdstart, ownermatched, l; @@ -36,6 +36,7 @@ void adns__procdgram(adns_state ads, const byte *dgram, int dglen, adns_query qu, nqu; dns_rcode rcode; adns_status st; + vbuf tempvb; if (dglenquery_dglen; if (!qu) { - adns__debug(ads,serv,0,"reply not found (id=%02x)",id); + if (ads->iflags & adns_if_debug) { + adns__vbuf_init(&tempvb); + adns__debug(ads,serv,0,"reply not found, id %02x, query owner %s", + id, adns__diag_domain(ads,serv,0,&tempvb,adns_qf_anyquote, + dgram,dglen,DNS_HDRSIZE)); + adns__vbuf_free(&tempvb); + } return; } + anstart= qu->query_dglen; LIST_UNLINK(ads->timew,qu); /* We're definitely going to do something with this query now */ @@ -125,12 +131,13 @@ void adns__procdgram(adns_state ads, const byte *dgram, int dglen, * If it has any CNAMEs we stuff them in the answer. */ wantedrrs= 0; + cbyte= anstart; for (rri= 0; rrianswer->cname= adns__alloc_interim(qu,l); if (!qu->answer->cname) return; memcpy(qu->answer->cname,qu->vb.buf,l); + cname_here= 1; /* If we find the answer section truncated after this point we restart * the query at the CNAME; if beforehand then we obviously have to use * TCP. If there is no truncation we can use the whole answer if @@ -219,7 +227,7 @@ void adns__procdgram(adns_state ads, const byte *dgram, int dglen, * a CNAME in this datagram then we should probably do our own CNAME * lookup now in the hope that we won't get a referral again. */ - if (qu->cname_dgram == dgram) { cname_recurse(qu,0); return; } + if (cname_here) { cname_recurse(qu,0); return; } /* Bloody hell, I thought we asked for recursion ? */ if (flg_rd) { @@ -257,6 +265,7 @@ void adns__procdgram(adns_state ads, const byte *dgram, int dglen, qu->answer->rrs.bytes+qu->answer->nrrs*qu->typei->rrsz); if (st) { adns__query_fail(qu,st); return; } if (rdstart==-1) goto x_truncated; + qu->answer->nrrs++; } /* This may have generated some child queries ... */ diff --git a/src/types.c b/src/types.c index 5219ff5..436cc87 100644 --- a/src/types.c +++ b/src/types.c @@ -20,9 +20,11 @@ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +#include + #include "internal.h" -static adns_status rp_inaddr(adns_query qu, int serv, +static adns_status pa_inaddr(adns_query qu, int serv, const byte *dgram, int dglen, int cbyte, int max, void *store_r) { struct in_addr *dr= store_r; @@ -32,13 +34,25 @@ static adns_status rp_inaddr(adns_query qu, int serv, return adns_s_ok; } -static void rmf_null(adns_query qu, void *data) { } +static adns_status cs_inaddr(vbuf *vb, const void *data) { + const struct in_addr *dp= data; + const char *ia; + + ia= inet_ntoa(*dp); assert(ia); + return adns__vbuf_appendstr(vb,ia) ? adns_s_ok : adns_s_nolocalmem; +} -#define TYPE_SF(size,func,free) size, rp_##func, rmf_##free -#define TYPE_SN(size,func) size, rp_##func, rmf_null +static void fr_null(adns_query qu, void *data) { } + +#define TYPE_SF(size,func,cp,free) size, pa_##func, fr_##free, cs_##cp +#define TYPE_SN(size,func,cp) size, pa_##func, fr_null, cs_##cp #define TYPESZ_M(member) (sizeof(((adns_answer*)0)->rrs.member)) -#define TYPE_MF(member,parse) TYPE_SF(TYPESZ_M(member),parse,member) -#define TYPE_MN(member,parse) TYPE_SN(TYPESZ_M(member),parse) +#define TYPE_MF(memb,parse) TYPE_SF(TYPESZ_M(memb),parse,memb,memb) +#define TYPE_MN(memb,parse) TYPE_SN(TYPESZ_M(memb),parse,memb) + +#define DEEP_MEMB(memb) TYPESZ_M(memb), fr_##memb, cs_##memb +#define FLAT_MEMB(memb) TYPESZ_M(memb), fr_null, cs_##memb +#define NULL_MEMB 0, fr_null, cs_null /* TYPE_ * ms is M specify member name @@ -49,26 +63,26 @@ static void rmf_null(adns_query qu, void *data) { } static const typeinfo typeinfos[] = { /* Must be in ascending order of rrtype ! */ - /* rr type code name style member size parser */ + /* rr type code rrt fmt mem.mgmt member parser */ - { adns_r_a, "A", TYPE_MN( inaddr, inaddr ) }, -#if 0 /*fixme*/ - { adns_r_ns_raw, "NS(raw)", TYPE_MF( str, domain_raw ) }, - { adns_r_cname, "CNAME", TYPE_MF( str, domain_raw ) }, - { adns_r_soa_raw, "SOA(raw)", TYPE_MF( soa, soa ) }, - { adns_r_null, "NULL", TYPE_SN( 0, null ) }, - { adns_r_ptr_raw, "PTR(raw)", TYPE_MF( str, domain_raw ) }, - { adns_r_hinfo, "HINFO", TYPE_MF( strpair, hinfo ) }, - { adns_r_mx_raw, "MX(raw)", TYPE_MF( intstr, mx_raw ) }, - { adns_r_txt, "TXT", TYPE_MF( str, txt ) }, - { adns_r_rp_raw, "RP(raw)", TYPE_MF( strpair, rp ) }, - - { adns_r_ns, "NS(+addr)", TYPE_MF( dmaddr, dmaddr ) }, - { adns_r_ptr, "PTR(checked)", TYPE_MF( str, ptr ) }, - { adns_r_mx, "MX(+addr)", TYPE_MF( intdmaddr, mx ) }, - - { adns_r_soa, "SOA(822)", TYPE_MF( soa, soa ) }, - { adns_r_rp, "RP(822)", TYPE_MF( strpair, rp ) }, + { adns_r_a, "A", 0, FLAT_MEMB(inaddr), pa_inaddr }, +#if 0 /*fixme*/ + { adns_r_ns_raw, "NS", "raw", DEEP_MEMB(str), pa_domain_raw }, + { adns_r_cname, "CNAME", 0, DEEP_MEMB(str), pa_domain_raw }, + { adns_r_soa_raw, "SOA", "raw", DEEP_MEMB(soa), pa_soa }, + { adns_r_null, "NULL", 0, NULL_MEMB, pa_null }, + { adns_r_ptr_raw, "PTR", "raw", DEEP_MEMB(str), pa_domain_raw }, + { adns_r_hinfo, "HINFO", 0, DEEP_MEMB(strpair), pa_hinfo }, + { adns_r_mx_raw, "MX", "raw", DEEP_MEMB(intstr), pa_mx_raw }, + { adns_r_txt, "TXT", 0, DEEP_MEMB(str), pa_txt }, + { adns_r_rp_raw, "RP", "raw", DEEP_MEMB(strpair), pa_rp }, + + { adns_r_ns, "NS", "+addr", DEEP_MEMB(dmaddr), pa_dmaddr }, + { adns_r_ptr, "PTR", "checked", DEEP_MEMB(str), pa_ptr }, + { adns_r_mx, "MX", "+addr", DEEP_MEMB(intdmaddr), pa_mx }, + + { adns_r_soa, "SOA", "822", DEEP_MEMB(soa), pa_soa }, + { adns_r_rp, "RP", "822", DEEP_MEMB(strpair), pa_rp }, #endif }; -- 2.30.2