From: ian Date: Sat, 7 Nov 1998 16:52:17 +0000 (+0000) Subject: Parsing code revamped, not compiled yet. X-Git-Tag: abandon.1999-04-10.multithread~54 X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=adns.git;a=commitdiff_plain;h=31144a72ed24e2d3cd62f5f1239e219737beeff4;hp=f1e474dda132e6d9626bc9930fd9025616de81fb Parsing code revamped, not compiled yet. --- diff --git a/src/adns.h b/src/adns.h index 2ec1f39..f71230a 100644 --- a/src/adns.h +++ b/src/adns.h @@ -265,4 +265,6 @@ void adns_interest(adns_state, int *maxfd_io, fd_set *readfds_io, * } */ +const char *adns_strerror(adns_status st); + #endif diff --git a/src/internal.h b/src/internal.h index c449e7f..1eecc60 100644 --- a/src/internal.h +++ b/src/internal.h @@ -61,11 +61,19 @@ typedef union { typedef struct { adns_rrtype type; int rrsz; - adns_status (*get_fn)(adns_state ads, adns_query qu, int serv, - const byte *dgram, int dglen, - int *cbyte_io, int max, - int nsstart, int arcount, int *arstart_io, - int roff, int *rcount_io); + adns_status (*parse)(adns_state ads, adns_query qu, int serv, vbuf *vb, + const byte *dgram, int dglen, int cbyte, int max, + void *store_r); + /* Parse one RR, in dgram of length dglen, starting at cbyte and + * extending until at most max. + * + * The RR should be stored at *store_r, of length qu->typei->rrsz. + * + * If there is an overrun which might indicate truncation, it should set + * *rdstart to -1; otherwise it may set it to anything else positive. + * + * This function may use vb (which has been initialised) however it likes. + */ } typeinfo; struct adns__query { @@ -76,21 +84,28 @@ struct adns__query { struct { adns_query back, next; } siblings; const typeinfo *typei; + +#error make sure all this is init'd properly +#error make sure all this is freed properly + byte *querymsg; + int querylen; + vbuf ansbuf; /* Used for answer RRs */ - char *cname; + char *cname_str; + byte *cname_dgram; + int cname_dglen, cname_begin; + int id, flags, udpretries; int udpnextserver; unsigned long udpsent, tcpfailed; /* bitmap indexed by server */ struct timeval timeout; - byte *querymsg; - int querylen; qcontext context; char owner[1]; /* After the owner name and nul comes the query message, pointed to by querymsg */ /* Possible states: * - * state Queue child id answer nextudpserver sentudp failedtcp + * state Queue child id ansbuf nextudpserver sentudp failedtcp * * udp NONE null >=0 null 0 zero zero * udp timew null >=0 null any nonzero zero @@ -159,11 +174,16 @@ struct adns__state { void adns__vdiag(adns_state ads, const char *pfx, adns_initflags prevent, int serv, const char *fmt, va_list al); -void adns__debug(adns_state ads, int serv, const char *fmt, ...) PRINTFFORMAT(3,4); -void adns__warn(adns_state ads, int serv, const char *fmt, ...) PRINTFFORMAT(3,4); -void adns__diag(adns_state ads, int serv, const char *fmt, ...) PRINTFFORMAT(3,4); + +void adns__debug(adns_state ads, int serv, adns_query qu, + const char *fmt, ...) PRINTFFORMAT(3,4); +void adns__warn(adns_state ads, int serv, adns_query qu, + const char *fmt, ...) PRINTFFORMAT(3,4); +void adns__diag(adns_state ads, int serv, adns_query qu, + const char *fmt, ...) PRINTFFORMAT(3,4); int adns__vbuf_ensure(vbuf *vb, int want); +int adns__vbuf_appendstr(vbuf *vb, const char *data); int adns__vbuf_append(vbuf *vb, const byte *data, int len); /* 1=>success, 0=>realloc failed */ void adns__vbuf_appendq(vbuf *vb, const byte *data, int len); diff --git a/src/parse.c b/src/parse.c index ad23419..957b572 100644 --- a/src/parse.c +++ b/src/parse.c @@ -85,7 +85,7 @@ adns_status adns__findlabel_next(findlabel_state fls, return adns_s_serverfaulty; } -adns_status adns__parse_domain(adns_state ads, int serv, vbuf *vb, +adns_status adns__parse_domain(adns_state ads, int serv, vbuf *vb, int flags, const byte *dgram, int dglen, int *cbyte_io, int max) { findlabel_state fls; @@ -102,7 +102,7 @@ adns_status adns__parse_domain(adns_state ads, int serv, vbuf *vb, if (!lablen) break; if (vb->used) if (!adns__vbuf_append(&qu->ans,".",1)) return adns_s_nolocalmem; - if (qu->flags & adns_qf_anyquote) { + if (flags & adns_qf_anyquote) { if (!vbuf__append_quoted1035(&qu->ans,dgram+labstart,lablen)) return adns_s_nolocalmem; } else { @@ -119,6 +119,25 @@ adns_status adns__parse_domain(adns_state ads, int serv, vbuf *vb, if (!adns__vbuf_append(&qu->ans,"",1)) return adns_s_nolocalmem; return adns_s_ok; } + +const char *adns__diag_domain(adns_state ads, int serv, vbuf *vb, int flags, + const byte *dgram, int dglen, int cbyte) { + adns_status st; + + st= adns__parse_domain(ads,serv,vb,qu->flags, dgram,dglen, &cbyte,dglen); + if (st) { + vb->used= 0; + adns__vbuf_appendstr(vb,""); + adns__vbuf_append(vb,"",1); + } + if (!vb.used) { + adns__vbuf_appendstr(vb,""); + adns__vbuf_append(vb,"",1); + } + return vb->buf; +} adns_status adns__findrr(adns_state ads, int serv, const byte *dgram, int dglen, int *cbyte_io, diff --git a/src/reply.c b/src/reply.c index 14fc057..0bcc3fa 100644 --- a/src/reply.c +++ b/src/reply.c @@ -9,14 +9,15 @@ static void cname_recurse(adns_state ads, adns_query qu, adns_queryflags xflags) void adns__procdgram(adns_state ads, const byte *dgram, int dglen, int serv, struct timeval now) { int cbyte, rrstart, wantedrrs, rri, foundsoa, foundns; - int id, f1, f2, qdcount, ancount, nscount, arcount, flg_ra, flg_tc; + int id, f1, f2, qdcount, ancount, nscount, arcount, flg_ra, flg_rd, flg_tc, opcode; int rrtype, rrclass, rdlength, rdstart, ownermatched, ownerstart; int anstart, nsstart, arstart; int currentrrs; adns_query qu, nqu; dns_rcode rcode; adns_status st; -= 0; + vbuf vb; +#error init and free vb properly if (dglen>3; flg_tc= f1&0x20; + flg_rd= f1&0x01; flg_ra= f2&0x80; + rcode= (f1&0x0f); - if (f1&0x80) { + if (flg_qr) { adns__diag(ads,serv,"server sent us a query, not a response"); return; } - if (f1&0x70) { - adns__diag(ads,serv,"server sent us unknown opcode %d (wanted 0=QUERY)", - (f1>>4)&0x70); + if (opcode) { + adns__diag(ads,serv,"server sent us unknown opcode %d (wanted 0=QUERY)",opcode); return; } if (!qdcount) { @@ -69,34 +73,27 @@ void adns__procdgram(adns_state ads, const byte *dgram, int dglen, LIST_UNLINK(ads->timew,qu); /* We're definitely going to do something with this query now */ - if (!(f1&0x01)) { - adns__diag(ads,serv,"server thinks we didn't ask for recursive lookup"); - adns__query_fail(ads,qu,adns_s_serverfaulty); - return; - } - - rcode= (f1&0x0f); switch (rcode) { case rcode_noerror: case rcode_nxdomain: break; case rcode_formaterror: - adns__warn(ads,serv,"server cannot understand our query (Format Error)"); + adns__warn(ads,serv,qu,"server cannot understand our query (Format Error)"); adns__query_fail(ads,qu,adns_s_serverfaulty); return; case rcode_servfail: adns__query_fail(ads,qu,adns_s_servfail); return; case rcode_notimp: - adns__warn(ads,serv,"server claims not to implement our query"); + adns__warn(ads,serv,qu,"server claims not to implement our query"); adns__query_fail(ads,qu,adns_s_notimplemented); return; case rcode_refused: - adns__warn(ads,serv,"server refused our query"); + adns__warn(ads,serv,qu,"server refused our query"); adns__query_fail(ads,qu,adns_s_refused); return; default: - adns__warn(ads,serv,"server gave unknown response code %d",rcode); + adns__warn(ads,serv,qu,"server gave unknown response code %d",rcode); adns__query_fail(ads,qu,adns_s_reasonunknown); return; } @@ -107,53 +104,57 @@ void adns__procdgram(adns_state ads, const byte *dgram, int dglen, wantedrrs= 0; for (rri= 0; rricnameoff >= 0) { + if (qu->cname_dgram >= 0) { st= adns__findrr(ads,serv, dgram,dglen,&cbyte, &rrtype,&rrclass,&rdlength,&rdstart, - dgram,dglen,qu->cnameoff, &ownermatched); + qu->cname_dgram,qu->cname_dglen,qu->cname_begin, &ownermatched); } else { - st= adns__get_rr_temp(ads,qu,serv, dgram,dglen,&cbyte, - &rrtype,&rrclass,&rdlength,&rdstart, - qu->querymsg,qu->querylen,DNS_HDRSIZE, &ownermatched); + st= adns__findrr(ads,serv, dgram,dglen,&cbyte, + &rrtype,&rrclass,&rdlength,&rdstart, + qu->querymsg,qu->querylen,DNS_HDRSIZE, &ownermatched); } if (st) adns__query_fail(ads,qu,st); if (rrtype == -1) goto x_truncated; if (rrclass != DNS_CLASS_IN) { - adns__diag(ads,serv,"ignoring answer RR with wrong class %d (expected IN=%d)", + adns__diag(ads,serv,qu,"ignoring answer RR with wrong class %d (expected IN=%d)", rrclass,DNS_CLASS_IN); continue; } if (!ownermatched) { if (ads->iflags & adns_if_debug) { - st= adns__get_domain_temp(ads,qu,serv, dgram,dglen,&rrstart,dglen, &ownerstart); - if (st) - adns__debug(ads,serv, "ignoring RR with an irrelevant owner" - " whose format is bad, code %d",st); - else if (ownerstart>=0) - adns__debug(ads,serv, "ignoring RR with an irrelevant owner" - " \"%s\"", qu->ans.buf+ownerstart); - else - adns__debug(ads,serv,"ignoring RR with an irrelevant truncated owner"); + adns__debug(ads,serv,qu,"ignoring RR with an unexpected owner %s", + adns__diag_domain(ads,serv,&vb,qu->flags, + dgram,dglen,rrstart,dglen)); } continue; } - if (qu->cnameoff<0 && - (qu->typei->type & adns__rrt_typemask) != adns_r_cname && - rrtype == adns_r_cname) { /* Ignore second and subsequent CNAMEs */ - st= adns__get_domain_perm(ads,qu,serv, dgram,dglen, - &rdstart,rdstart+rdlength,&qu->cnameoff); - if (st) { adns__query_fail(ads,qu,st); return; } - if (qu->cnameoff==-1) goto x_truncated; - /* 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 - * it contains the relevant info. - */ + if (rrtype == adns_r_cname && + (qu->typei->type & adns__rrt_typemask) != adns_r_cname) { + if (!qu->cname_str) { /* Ignore second and subsequent CNAMEs */ + qu->cname_begin= rdstart; + qu->cname_dgram= dgram; + qu->cname_dglen= dglen; + st= adns__parse_domain(ads,serv,&vb,qu->flags, + dgram,dglen, &rdstart,rdstart+rdlength); + if (!vb.used) goto x_truncated; + if (st) { adns__query_fail(ads,qu,st); return; } + qu->cname_str= adns__vbuf_extractstring(&vb); + /* 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 + * it contains the relevant info. + */ + } else { + adns__debug(ads,serv,qu,"ignoring duplicate CNAME (%s, as well as %s)", + adns__diag_domain(ads,serv,&vb,qu->flags, + dgram,dglen, rdstart,rdstart+rdlength), + qu->cname_str); + } } else if (rrtype == (qu->typei->type & adns__rrt_typemask)) { wantedrrs++; } else { - adns__debug(ads,serv,"ignoring answer RR with irrelevant type %d",rrtype); + adns__debug(ads,serv,qu,"ignoring answer RR with irrelevant type %d",rrtype); } } @@ -172,12 +173,14 @@ void adns__procdgram(adns_state ads, const byte *dgram, int dglen, foundsoa= 0; foundns= 0; for (rri= 0; rricnameoff != -1) { cname_recurse(ads,qu,0); return; } + if (qu->cname_dgram == dgram) { cname_recurse(ads,qu,0); return; } /* Bloody hell, I thought we asked for recursion ? */ + if (flg_rd) { + adns__diag(ads,serv,qu,"server thinks we didn't ask for recursive lookup"); + } if (!flg_ra) { - adns__diag(ads,serv,"server is not willing to do recursive lookups for us"); + adns__diag(ads,serv,qu,"server is not willing to do recursive lookups for us"); adns__query_fail(ads,qu,adns_s_norecurse); - return; + } else { + adns__diag(ads,serv,qu,"server claims to do recursion, but gave us a referral"); + adns__query_fail(ads,qu,adns_s_serverfaulty); } - adns__diag(ads,serv,"server claims to do recursion, but gave us a referral"); - adns__query_fail(ads,qu,adns_s_serverfaulty); return; } /* Now, we have some RRs which we wanted. */ - qu->rrsoff= adns__vbuf_malloc(&qu->ans,qu->typei->rrsz*wantedrrs); - if (qu->rrsoff == -1) adns__query_fail(ads,qu,adns_s_nolocalmem); + if (!adns__vbuf_ensure(&qu->ansbuf,qu->typei->rrsz*wantedrrs)) { + adns__query_fail(ads,qu,adns_s_nolocalmem); + return; + } cbyte= anstart; currentrrs= 0; arstart= -1; + qu->ansbuf.used= 0; for (rri=0; rricname_dgram >= 0) { + st= adns__findrr(ads,serv, dgram,dglen,&cbyte, + &rrtype,&rrclass,&rdlength,&rdstart, + qu->cname_dgram,qu->cname_dglen,qu->cname_begin, &ownermatched); + } else { + st= adns__findrr(ads,serv, dgram,dglen,&cbyte, + &rrtype,&rrclass,&rdlength,&rdstart, + qu->querymsg,qu->querylen,DNS_HDRSIZE, &ownermatched); + } assert(!st); assert(rrtype != -1); if (rrclass != DNS_CLASS_IN || - rrtype != (qu->typei->type & adns__rrt_typemask)) + rrtype != (qu->typei->type & adns__rrt_typemask) || + !ownermatched) continue; assert(currentrrstypei->get_fn(ads,qu,serv, dgram,dglen, &rdstart,rdstart+rdlength, - nsstart,arcount,&arstart, qu->rrsoff,¤trrs); + qu->ansbuf.used += quj->typei->rrsz; + st= qu->typei->parse(ads,qu,serv,&vb, + dgram,dglen, &rdstart,rdstart+rdlength, + (void*)(qu->ansbuf.buf+qu->ansbuf.used)); if (st) { adns__query_fail(ads,qu,st); return; } - if (currentrrs==-1) goto x_truncated; + if (rdstart==-1) goto x_truncated; } /* This may have generated some child queries ... */ @@ -242,13 +262,11 @@ void adns__procdgram(adns_state ads, const byte *dgram, int dglen, x_truncated: if (!flg_tc) { - adns__diag(ads,serv,"server sent datagram which points outside itself"); + adns__diag(ads,serv,qu,"server sent datagram which points outside itself"); adns__query_fail(ads,qu,adns_s_serverfaulty); return; } - if (qu->cnameoff != -1) { cname_recurse(ads,qu,adns_qf_usevc); return; } - qu->cnameoff= -1; - qu->rrsoff= -1; + if (qu->cname_dgram) { cname_recurse(ads,qu,adns_qf_usevc); return; } ans= (adns_answer*)qu->ans.buf; ans->nrrs= 0; qu->ans.used= sizeof(adns_answer); diff --git a/src/setup.c b/src/setup.c index a83b97a..63469d2 100644 --- a/src/setup.c +++ b/src/setup.c @@ -305,3 +305,9 @@ int adns_init(adns_state *ads_r, adns_initflags flags, FILE *diagfile) { int adns_finish(adns_state ads) { abort(); /* fixme */ } + +const char *adns_strerror(adns_status st) { + static char buf[100]; + snprintf(buf,sizeof(buf),"code %d",st); + return buf; +}