From: ian Date: Sun, 4 Oct 1998 23:58:27 +0000 (+0000) Subject: All except rrtype-specific stuff complete but largely untest. That is X-Git-Tag: abandon.1999-04-10.multithread~58 X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=adns.git;a=commitdiff_plain;h=98a3f706175de88b2c9f0729b405330457ae680b All except rrtype-specific stuff complete but largely untest. That is missing so does not link, otherwise compilez. --- diff --git a/client/adnstest.c b/client/adnstest.c index 95f89b7..2f9e525 100644 --- a/client/adnstest.c +++ b/client/adnstest.c @@ -20,7 +20,6 @@ int main(void) { r= adns_wait(ads,&qu,&ans,0); if (r) { perror("wait"); exit(2); } - if (!ans) { fputs("no answer\n",stderr); exit(2); } fprintf(stderr,"answer status %d type %d rrs %d cname %s\n", ans->status,ans->type,ans->nrrs, ans->cname ? ans->cname : "-"); diff --git a/src/Makefile b/src/Makefile index 46b6be9..2719f33 100644 --- a/src/Makefile +++ b/src/Makefile @@ -7,10 +7,12 @@ WERROR=-Werror all: dtest -dtest: dtest.o event.o query.o setup.o submit.o reply.o +dtest: dtest.o event.o query.o setup.o submit.o reply.o parse.o clean: rm -f dtest *.o -dtest.o event.o query.o setup.o submit.o reply.o: internal.h adns.h +dtest.o: adns.h + +event.o query.o setup.o submit.o reply.o parse.o: internal.h adns.h diff --git a/src/Makefile.in b/src/Makefile.in index 46b6be9..2719f33 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -7,10 +7,12 @@ WERROR=-Werror all: dtest -dtest: dtest.o event.o query.o setup.o submit.o reply.o +dtest: dtest.o event.o query.o setup.o submit.o reply.o parse.o clean: rm -f dtest *.o -dtest.o event.o query.o setup.o submit.o reply.o: internal.h adns.h +dtest.o: adns.h + +event.o query.o setup.o submit.o reply.o parse.o: internal.h adns.h diff --git a/src/adns.h b/src/adns.h index 18c21df..b110a94 100644 --- a/src/adns.h +++ b/src/adns.h @@ -143,8 +143,8 @@ typedef struct { adns_rrtype type; int nrrs; union { - struct in_addr *inaddr; /* a */ char *(*str); /* ns_raw, cname, ptr, ptr_raw, txt, _mf */ + struct in_addr *inaddr; /* a */ adns_rr_dmaddr *dmaddr; /* ns */ adns_rr_strpair *strpair; /* hinfo, rp, rp_raw */ adns_rr_intdmaddr *intdmaddr; /* mx */ @@ -173,8 +173,6 @@ typedef struct { * type will always be the type requested; * If no (appropriate) requests are done adns_check returns EWOULDBLOCK; * If no (appropriate) requests are outstanding adns_query and adns_wait return ESRCH; - * If malloc failure occurs during internal allocation or processing - * ands_check and _wait set *answer to 0. */ int adns_init(adns_state *newstate_r, adns_initflags flags, FILE *diagfile/*0=>stderr*/); diff --git a/src/event.c b/src/event.c index 7ed12f6..9ddf4c7 100644 --- a/src/event.c +++ b/src/event.c @@ -77,7 +77,7 @@ void adns__tcp_tryconnect(adns_state ads, struct timeval now) { } memset(&addr,0,sizeof(addr)); addr.sin_family= AF_INET; - addr.sin_port= htons(NSPORT); + addr.sin_port= htons(DNS_PORT); addr.sin_addr= ads->servers[ads->tcpserver].addr; r= connect(fd,&addr,sizeof(addr)); ads->tcpsocket= fd; @@ -195,7 +195,7 @@ static int internal_callback(adns_state ads, int maxfd, const fd_set *exceptfds, struct timeval now) { int skip, want, dgramlen, count, udpaddrlen, r, serv; - byte udpbuf[MAXUDPDGRAM]; + byte udpbuf[DNS_MAXUDP]; struct sockaddr_in udpaddr; count= 0; @@ -234,7 +234,7 @@ static int internal_callback(adns_state ads, int maxfd, if (ads->tcprecv.usedtcprecv.buf+skip+2,dgramlen,ads->tcpserver); + adns__procdgram(ads,ads->tcprecv.buf+skip+2,dgramlen,ads->tcpserver,now); skip+= 2+dgramlen; continue; } } @@ -294,9 +294,9 @@ static int internal_callback(adns_state ads, int maxfd, " %u (expected %u)",udpaddr.sin_family,AF_INET); continue; } - if (ntohs(udpaddr.sin_port) != NSPORT) { + if (ntohs(udpaddr.sin_port) != DNS_PORT) { adns__diag(ads,-1,"datagram received from wrong port %u (expected %u)", - ntohs(udpaddr.sin_port),NSPORT); + ntohs(udpaddr.sin_port),DNS_PORT); continue; } for (serv= 0; @@ -308,7 +308,7 @@ static int internal_callback(adns_state ads, int maxfd, inet_ntoa(udpaddr.sin_addr)); continue; } - adns__procdgram(ads,udpbuf,r,serv); + adns__procdgram(ads,udpbuf,r,serv,now); } } return count; @@ -346,7 +346,7 @@ static int internal_check(adns_state ads, if (qu->id>=0) return EWOULDBLOCK; } LIST_UNLINK(ads->output,qu); - *answer= (adns_answer*)qu->answer.buf; + *answer= (adns_answer*)qu->ans.buf; if (context_r) *context_r= qu->context.ext; free(qu); return 0; diff --git a/src/internal.h b/src/internal.h index cd58d7a..ab68ead 100644 --- a/src/internal.h +++ b/src/internal.h @@ -22,12 +22,21 @@ typedef unsigned char byte; #define TCPMS 30000 #define LOCALRESOURCEMS 20 -#define DNS_UDPPORT 53 +#define DNS_PORT 53 #define DNS_MAXUDP 512 #define DNS_MAXDOMAIN 255 #define DNS_HDRSIZE 12 #define DNS_CLASS_IN 1 +typedef enum { + rcode_noerror, + rcode_formaterror, + rcode_servfail, + rcode_nxdomain, + rcode_notimp, + rcode_refused +} dns_rcode; + /* Shared data structures */ typedef union { @@ -50,8 +59,13 @@ typedef union { } qcontext; typedef struct { - unsigned long searchkey; /* flags and typecode swapped */ 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); } typeinfo; struct adns__query { @@ -68,7 +82,7 @@ struct adns__query { unsigned long udpsent, tcpfailed; /* bitmap indexed by server */ struct timeval timeout; byte *querymsg; - int querylen; + int querylen, cnameoff, rrsoff; qcontext context; char owner[1]; /* After the owner name and nul comes the query message, pointed to by querymsg */ @@ -150,6 +164,7 @@ void adns__diag(adns_state ads, int serv, const char *fmt, ...) PRINTFFORMAT(3,4 int adns__vbuf_ensure(vbuf *vb, int want); int adns__vbuf_append(vbuf *vb, const byte *data, int len); +int adns__vbuf_malloc(vbuf *vb, size_t len); /* 1=>success, 0=>realloc failed */ void adns__vbuf_appendq(vbuf *vb, const byte *data, int len); void adns__vbuf_init(vbuf *vb); @@ -159,6 +174,7 @@ int adns__setnonblock(adns_state ads, int fd); /* => errno value */ /* From submit.c: */ void adns__query_nomem(adns_state ads, adns_query qu); +void adns__query_finish(adns_state ads, adns_query qu, adns_status stat); void adns__query_fail(adns_state ads, adns_query qu, adns_status stat); /* From query.c: */ @@ -166,11 +182,35 @@ void adns__query_fail(adns_state ads, adns_query qu, adns_status stat); void adns__query_udp(adns_state ads, adns_query qu, struct timeval now); void adns__query_tcp(adns_state ads, adns_query qu, struct timeval now); adns_status adns__mkquery(adns_state ads, const char *owner, int ol, int id, - adns_rrtype type, adns_queryflags flags); + const typeinfo *typei, adns_queryflags flags); /* From reply.c: */ -void adns__procdgram(adns_state ads, const byte *dgram, int len, int serv); +void adns__procdgram(adns_state ads, const byte *dgram, int len, + int serv, struct timeval now); + +/* From types.c: */ + +const typeinfo *adns__findtype(adns_rrtype type); + +/* From parse.c: */ + +int vbuf__append_quoted1035(vbuf *vb, const byte *buf, int len); + +adns_status adns__get_label(const byte *dgram, int dglen, int *max_io, + int *cbyte_io, int *lablen_r, int *labstart_r, + int *namelen_io); +adns_status adns__get_domain_perm(adns_state ads, adns_query qu, int serv, + const byte *dgram, int dglen, + int *cbyte_io, int max, int *domainstart_r); +adns_status adns__get_domain_temp(adns_state ads, adns_query qu, int serv, + const byte *dgram, int dglen, + int *cbyte_io, int max, int *domainstart_r); +adns_status adns__get_rr_temp(adns_state ads, adns_query qu, int serv, + const byte *dgram, int dglen, int *cbyte_io, + int *type_r, int *class_r, int *rdlen_r, int *rdstart_r, + const byte *eo_dgram, int eo_dglen, int eo_cbyte, + int *eo_matched_r); /* From event.c: */ @@ -192,6 +232,9 @@ static inline void timevaladd(struct timeval *tv_io, long ms) { static inline int ctype_whitespace(int c) { return c==' ' || c=='\n' || c=='\t'; } static inline int ctype_digit(int c) { return c>='0' && c<='9'; } +static inline int ctype_alpha(int c) { + return (c >= 'a' && c <= 'z') || (c >= 'A' || c <= 'Z'); +} /* Useful macros */ @@ -216,4 +259,8 @@ static inline int ctype_digit(int c) { return c>='0' && c<='9'; } #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 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)) + #endif diff --git a/src/parse.c b/src/parse.c new file mode 100644 index 0000000..2a9dd94 --- /dev/null +++ b/src/parse.c @@ -0,0 +1,179 @@ +/**/ + +#include "internal.h" + +int vbuf__append_quoted1035(vbuf *vb, const byte *buf, int len) { + char qbuf[10]; + int i, ch; + + while (len) { + qbuf[0]= 0; + for (i=0; i= 127) { + sprintf(qbuf,"\\%03o",ch); + break; + } + } + if (!adns__vbuf_append(vb,buf,i) || !adns__vbuf_append(vb,qbuf,strlen(qbuf))) + return 0; + buf+= i; len-= i; + } + return 1; +} + +adns_status adns__get_label(const byte *dgram, int dglen, int *max_io, + int *cbyte_io, int *lablen_r, int *labstart_r, + int *namelen_io) { + /* If succeeds, *lablen_r may be set to -1 to indicate truncation/overrun */ + int max, cbyte, lablen, namelen; + + max= *max_io; + cbyte= *cbyte_io; + + for (;;) { + if (cbyte+2 > max) goto x_truncated; + GET_W(cbyte,lablen); + if (!(lablen & 0x0c000)) break; + if ((lablen & 0x0c000) != 0x0c000) return adns_s_unknownreply; + if (cbyte_io) { *cbyte_io= cbyte; cbyte_io= 0; } + cbyte= DNS_HDRSIZE+(lablen&0x3fff); + *max_io= max= dglen; + } + if (labstart_r) *labstart_r= cbyte; + if (lablen) { + namelen= *namelen_io; + if (namelen) namelen++; + namelen+= lablen; + if (namelen > DNS_MAXDOMAIN) return adns_s_domaintoolong; + *namelen_io= namelen; + cbyte+= lablen; + if (cbyte > max) goto x_truncated; + } + if (cbyte_io) *cbyte_io= cbyte; + *lablen_r= lablen; + return adns_s_ok; + + x_truncated: + *lablen_r= -1; + return adns_s_ok; +} + +adns_status adns__get_domain_perm(adns_state ads, adns_query qu, int serv, + const byte *dgram, int dglen, + int *cbyte_io, int max, int *domainstart_r) { + /* Returns 0 for OK (*domainstart_r >=0) or truncated (*domainstart_r == -1) + * or any other adns_s_* value. + */ + int cbyte, sused, lablen, labstart, namelen, i, ch; + adns_status st; + + /* If we follow a pointer we set cbyte_io to 0 to indicate that + * we've lost our original starting and ending points; we don't + * put the end of the pointed-to thing into the original *cbyte_io. + */ + cbyte= *cbyte_io; + sused= qu->ans.used; + namelen= 0; + for (;;) { + st= adns__get_label(dgram,dglen,&max, &cbyte,&lablen,&labstart,&namelen); + if (st) return st; + if (lablen<0) goto x_truncated; + if (!lablen) break; + if (qu->ans.used != sused) + if (!adns__vbuf_append(&qu->ans,".",1)) return adns_s_nolocalmem; + if (qu->flags & adns_qf_anyquote) { + if (!vbuf__append_quoted1035(&qu->ans,dgram+labstart,lablen)) + return adns_s_nolocalmem; + } else { + if (!ctype_alpha(dgram[labstart])) return adns_s_invaliddomain; + for (i= cbyte+1; ians,dgram+labstart,lablen)) + return adns_s_nolocalmem; + } + } + if (cbyte_io) *cbyte_io= cbyte; + if (!adns__vbuf_append(&qu->ans,"",1)) return adns_s_nolocalmem; + *domainstart_r= sused; + return adns_s_ok; + + x_truncated: + *domainstart_r= -1; + return cbyte_io ? -1 : adns_s_serverfaulty; +} + +adns_status adns__get_domain_temp(adns_state ads, adns_query qu, int serv, + const byte *dgram, int dglen, + int *cbyte_io, int max, int *domainstart_r) { + int sused; + adns_status st; + + sused= qu->ans.used; + st= adns__get_domain_perm(ads,qu,serv,dgram,dglen,cbyte_io,max,domainstart_r); + qu->ans.used= sused; + return st; +} + +adns_status adns__get_rr_temp(adns_state ads, adns_query qu, int serv, + const byte *dgram, int dglen, int *cbyte_io, + int *type_r, int *class_r, int *rdlen_r, int *rdstart_r, + const byte *eo_dgram, int eo_dglen, int eo_cbyte, + int *eo_matched_r) { + /* _s_ok can have *type_r == -1 and other output invalid, for truncation + * type_r and class_r must be !0, other _r may be 0. + * eo_dgram==0 for no comparison, otherwise all eo_ must be valid. + */ + int cbyte, tmp, rdlen, mismatch; + int max, lablen, labstart, namelen, ch; + int eo_max, eo_lablen, eo_labstart, eo_namelen, eo_ch; + adns_status st; + + cbyte= *cbyte_io; + mismatch= eo_dgram ? 1 : 0; + + namelen= 0; eo_namelen= 0; + max= dglen; eo_max= eo_dglen; + for (;;) { + st= adns__get_label(dgram,dglen,&max, + &cbyte,&lablen,&labstart,&namelen); + if (st) return st; + if (lablen<0) goto x_truncated; + + if (!mismatch) { + st= adns__get_label(eo_dgram,eo_dglen,&eo_max, + &eo_cbyte,&eo_lablen,&eo_labstart,&eo_namelen); + if (st) return st; + assert(eo_lablen>=0); + if (lablen != eo_lablen) mismatch= 1; + while (!mismatch && 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 (eo_matched_r) *eo_matched_r= !mismatch; + + if (cbyte+10>dglen) goto x_truncated; + 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; + if (rdstart_r) *rdstart_r= cbyte; + cbyte+= rdlen; + if (cbyte>dglen) goto x_truncated; + *cbyte_io= cbyte; + return adns_s_ok; + + x_truncated: + *type_r= -1; + return 0;; +} diff --git a/src/query.c b/src/query.c index 2b21da4..d3139dd 100644 --- a/src/query.c +++ b/src/query.c @@ -2,13 +2,14 @@ #include #include +#include #include #include "internal.h" adns_status adns__mkquery(adns_state ads, const char *owner, int ol, int id, - adns_rrtype type, adns_queryflags flags) { + const typeinfo *typei, adns_queryflags flags) { /* Assembles a query packet in ads->rqbuf. */ int ll, c, nlabs; byte label[255], *rqp; @@ -17,7 +18,7 @@ adns_status adns__mkquery(adns_state ads, const char *owner, int ol, int id, #define MKQUERY_ADDB(b) *rqp++= (b) #define MKQUERY_ADDW(w) (MKQUERY_ADDB(((w)>>8)&0x0ff), MKQUERY_ADDB((w)&0x0ff)) - if (!adns__vbuf_ensure(&ads->rqbuf,DNSHDRSIZE+strlen(owner)+1+5)) + if (!adns__vbuf_ensure(&ads->rqbuf,DNS_HDRSIZE+strlen(owner)+1+5)) return adns_s_nolocalmem; rqp= ads->rqbuf.buf; @@ -50,7 +51,7 @@ adns_status adns__mkquery(adns_state ads, const char *owner, int ol, int id, if (!(flags & adns_qf_anyquote)) { if (ctype_digit(c) || c == '-') { if (!ll) return adns_s_invaliddomain; - } else if ((c < 'a' || c > 'z') && (c < 'A' && c > 'Z')) { + } else if (!ctype_alpha(c)) { return adns_s_invaliddomain; } } @@ -64,7 +65,7 @@ adns_status adns__mkquery(adns_state ads, const char *owner, int ol, int id, } while (p!=pe); MKQUERY_ADDB(0); - MKQUERY_ADDW(type & adns__rrt_typemask); /* QTYPE */ + MKQUERY_ADDW(typei->type & adns__rrt_typemask); /* QTYPE */ MKQUERY_ADDW(DNS_CLASS_IN); /* QCLASS=IN */ ads->rqbuf.used= rqp - ads->rqbuf.buf; @@ -148,12 +149,12 @@ void adns__query_udp(adns_state ads, adns_query qu, struct timeval now) { int serv, r; assert(qu->state == query_udp); - if ((qu->flags & adns_qf_usevc) || (qu->querylen > MAXUDPDGRAM)) { + if ((qu->flags & adns_qf_usevc) || (qu->querylen > DNS_MAXUDP)) { query_usetcp(ads,qu,now); return; } - if (qu->udpretries >= MAXUDPRETRIES) { + if (qu->udpretries >= UDPMAXRETRIES) { adns__query_fail(ads,qu,adns_s_timeout); return; } @@ -162,7 +163,7 @@ void adns__query_udp(adns_state ads, adns_query qu, struct timeval now) { memset(&servaddr,0,sizeof(servaddr)); servaddr.sin_family= AF_INET; servaddr.sin_addr= ads->servers[serv].addr; - servaddr.sin_port= htons(NSPORT); + servaddr.sin_port= htons(DNS_PORT); r= sendto(ads->udpsocket,qu->querymsg,qu->querylen,0,&servaddr,sizeof(servaddr)); if (r<0 && errno == EMSGSIZE) { query_usetcp(ads,qu,now); return; } @@ -176,8 +177,16 @@ void adns__query_udp(adns_state ads, adns_query qu, struct timeval now) { LIST_LINK_TAIL(ads->timew,qu); } -void adns__query_nomem(adns_state ads, adns_query qu) { - qu->answer.used= 0; +void adns__query_finish(adns_state ads, adns_query qu, adns_status stat) { + adns_answer *ans; + byte *newbuf; + + newbuf= realloc(qu->ans.buf,qu->ans.used); + if (newbuf) qu->ans.buf= newbuf; + ans= (adns_answer*)qu->ans.buf; + ans->status= stat; + ans->cname= qu->cnameoff<0 ? 0 : qu->ans.buf + qu->cnameoff; + ans->rrs.str= qu->rrsoff<0 ? 0 : (char **)(qu->ans.buf + qu->rrsoff); qu->id= -1; LIST_LINK_TAIL(ads->output,qu); } @@ -185,16 +194,11 @@ void adns__query_nomem(adns_state ads, adns_query qu) { void adns__query_fail(adns_state ads, adns_query qu, adns_status stat) { adns_answer *ans; - if (!adns__vbuf_ensure(&qu->answer,sizeof(adns_answer))) { - adns__query_nomem(ads,qu); - return; - } - ans= (adns_answer*)qu->answer.buf; - ans->status= stat; - ans->cname= 0; - ans->type= qu->type; + qu->ans.used= sizeof(adns_answer); + qu->cnameoff= -1; + qu->rrsoff= -1; + ans= (adns_answer*)qu->ans.buf; ans->nrrs= 0; - qu->answer.used= sizeof(adns_answer); - qu->id= -1; - LIST_LINK_TAIL(ads->output,qu); + + adns__query_finish(ads,qu,stat); } diff --git a/src/reply.c b/src/reply.c index 7158668..39337e8 100644 --- a/src/reply.c +++ b/src/reply.c @@ -2,199 +2,26 @@ #include "internal.h" -typedef enum { - rcode_noerror, - rcode_formaterror, - rcode_servfail, - rcode_nxdomain, - rcode_notimp, - rcode_refused -} dns_rcode; - -#define GETIL_B(cb) (dgram[*(cb)++]) -#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)) - -static void vbuf__append_quoted1035(vbuf *vb, const byte *buf, int len) { - char qbuf[10]; - int i; - - while (len) { - qbuf[0]= 0; - for (i=0; i= 127) { - sprintf(qbuf,"\\%03o",ch); - break; - } - } - if (!adns__vbuf_append(vb,buf,i) || !adns__vbuf_append(vb,qbuf,strlen(qbuf))) - return adns_s_nolocalmem; - buf+= i; len-= i; - } -} - -static adns_status get_label(const byte *dgram, int dglen, int *max_io, - int *cbyte_io, int *lablen_r, int *labstart_r, - int *namelen_io) { - /* If succeeds, *lablen_r may be set to -1 to indicate truncation/overrun */ - int max, cbyte, lablen, namelen; - - max= *max_io; - cbyte= *cbyte_io; - - for (;;) { - if (cbyte+2 > max) goto x_truncated; - GET_W(cbyte,lablen); - if (!(lablen & 0x0c000)) break; - if ((lablen & 0x0c000) != 0x0c000) return adns_s_unknownreply; - if (cbyte_io) { *cbyte_io= cbyte; cbyte_io= 0; } - cbyte= dgram+DNS_HDR_SIZE+(lablen&0x3fff); - *max_io= max= dglen; - } - if (labstart_r) *labstart_r= cbyte; - if (lablen) { - namelen= *namelen_io; - if (namelen) namelen++; - namelen+= lablen; - if (namelen > DNS_MAXDOMAIN) return adns_s_domaintoolong; - *namelen_io= namelen; - cbyte+= lablen; - if (cbyte > max) goto x_truncated; - } - if (cbyte_io) *cbyte_io= cbyte; - *lablen_r= lablen; - return adns_s_ok; - - x_truncated: - *lablen_r= -1; - return adns_s_ok; -} - -static adns_status get_domain_perm(adns_state ads, adns_query qu, int serv, - const byte *dgram, int dglen, - int *cbyte_io, int max, char **domain_r) { - /* Returns 0 for OK (*domain_r set) or truncated (*domain_r null) - * or any other adns_s_* value. - */ - int cbyte, sused, lablen, namelen; - - /* If we follow a pointer we set cbyte_io to 0 to indicate that - * we've lost our original starting and ending points; we don't - * put the end of the pointed-to thing into the original *cbyte_io. - */ - cbyte= *cbyte_io; - sused= qu->ans.used; - *domain_r= 0; - namelen= 0; - for (;;) { - st= get_label(dgram,dglen,&max, &cbyte,&lablen,&labstart,&namelen); - if (st) return st; - if (lablen<0) goto x_truncated; - if (!lablen) break; - if (qu->ans.used != sused) - if (!adns__vbuf_append(&qu->ans,".",1)) return adns_s_nolocalmem; - if (qu->flags & adns_qf_anyquote) { - if (!vbuf__append_quoted1035(&qu->ans,dgram+labstart,lablen)) - return adns_s_nolocalmem; - } else { - if (!ctype_isalpha(dgram[labstart])) return adns_s_invaliddomain; - for (i= cbyte+1; ians,dgram+labstart,lablen)) - return adns_s_nolocalmem; - } - } - if (cbyte_io) *cbyte_io= cbyte; - if (!adns__vbuf_append(&qu->ans,"",1)) return adns_s_nolocalmem; - *domain_r= qu->ans.buf+sused; - return adns_s_ok; - - x_truncated: - return cbyte_io ? -1 : adns_s_serverfaulty; +static void cname_recurse(adns_state ads, adns_query qu, adns_queryflags xflags) { + abort(); /* FIXME */ } -static adns_status get_domain_temp(adns_state ads, adns_query qu, int serv, - const byte *dgram, int dglen, - int *cbyte_io, int max, char **domain_r) { - int sused; +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 rrtype, rrclass, rdlength, rdstart, ownermatched, ownerstart; + int anstart, nsstart, arstart; + int currentrrs; + adns_query qu, nqu; + dns_rcode rcode; adns_status st; - - sused= qu->ans.used; - st= get_domain_perm(ads,qu,serv,dgram,dglen,cbyte_io,max,domain_r); - qu->ans.used= sused; - return st; -} - -static adns_status get_rr_temp(adns_state ads, adns_query qu, int serv, - const byte *dgram, int dglen, int *cbyte_io, - int *type_r, int *class_r, int *rdlen_r, int *rdstart_r, - const byte *eo_dgram, int eo_dglen, int eo_cbyte, - int *eo_matched_r) { - /* _s_ok can have *type_r == -1 and other output invalid, for truncation - * type_r and class_r must be !0, other _r may be 0. - * eo_dgram==0 for no comparison, otherwise all eo_ must be valid. - */ - int cbyte, tmp, rdlen, mismatch; - int max, lablen, labstart, namelen; - int eo_max, eo_lablen, eo_labstart, eo_namelen; - - cbyte= *cbyte_io; - mismatch= eo_dgram ? 1 : 0; - - namelen= 0; eo_namelen= 0; - max= dglen; eo_max= eo_dglen; - for (;;) { - st= get_label(dgram,dglen,&max, - &cbyte,&lablen,&labstart,&namelen); - if (st) return st; - if (lablen<0) goto x_truncated; - - if (!mismatch) { - st= get_label(eo_dgram,eo_dglen,&eo_max, - &eo_cbyte,&eo_lablen,&eo_labstart,&eo_namelen); - if (st) return st; - assert(eo_lablen>=0); - if (lablen != eo_lablen) mismatch= 1; - while (!mismatch && lablen-- > 0) { - ch= dgram[labstart++]; if (ctype_isalpha(ch)) ch &= ~32; - eo_ch= eo_dgram[eo_labstart++]; if (ctype_isalpha(eo_ch)) eo_ch &= ~32; - if (ch != eo_ch) mismatch= 1 - } - } - } - if (eo_matched_r) *eo_matched_r= !mismatch; - - if (cbyte+10>len) goto x_truncated; - 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; - if (rdstart_r) *rdstart_r= cbyte; - cbyte+= rdlen; - if (cbyte>dglen) goto x_truncated; - *cbyte_io= cbyte; - return adns_s_ok; - - x_truncated: - *type_r= -1; - return 0;; -} - -void adns__procdgram(adns_state ads, const byte *dgram, int dglen, int serv) { - int cbyte, anstart, rrstart, lablen, wantedrrs, get_t, cnamestart; + adns_answer *ans; cbyte= 0; - if (dglentimew; qu= nqu; qu++) { + for (qu= ads->timew.head; qu; qu= nqu) { nqu= qu->next; if (qu->id != id) continue; - if (len < qu->querylen) continue; - if (memcmp(qu->querymsg+DNSHDRSIZE,dgram+DNSHDRSIZE,qu->querylen-DNSHDRSIZE)) + if (dglen < qu->querylen) continue; + if (memcmp(qu->querymsg+DNS_HDRSIZE,dgram+DNS_HDRSIZE,qu->querylen-DNS_HDRSIZE)) continue; break; } + assert(qu->cnameoff == -1); anstart= qu->querylen; if (!qu) { adns__debug(ads,serv,"reply not found (id=%02x)",id); return; } + + 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); @@ -253,8 +86,8 @@ void adns__procdgram(adns_state ads, const byte *dgram, int dglen, int serv) { adns__warn(ads,serv,"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_serverfailure); + 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"); @@ -276,14 +109,14 @@ void adns__procdgram(adns_state ads, const byte *dgram, int dglen, int serv) { wantedrrs= 0; for (rri= 0; rricname) { - st= get_rr_temp(ads,qu,serv, dgram,dglen,&cbyte, - &rrtype,&rrclass,&rdlength,&rdstart, - dgram,dglen,cnamestart, &ownermatched); + if (qu->cnameoff >= 0) { + st= adns__get_rr_temp(ads,qu,serv, dgram,dglen,&cbyte, + &rrtype,&rrclass,&rdlength,&rdstart, + dgram,dglen,qu->cnameoff, &ownermatched); } else { - st= get_rr_temp(ads,qu,serv, dgram,dglen,&cbyte, - &rrtype,&rrclass,&rdlength,&rdstart, - qu->querymsg,qu->querylen,DNS_HDR_SIZE, &ownermatched); + st= adns__get_rr_temp(ads,qu,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; @@ -294,26 +127,32 @@ void adns__procdgram(adns_state ads, const byte *dgram, int dglen, int serv) { continue; } if (!ownermatched) { - if (ads->iflag & adns_if_debug) { - st= get_domain_temp(ads,qu,serv, dgram,dglen,&rrstart,dglen, &cowner); - if (st) adns__debug(ads,serv,"ignoring RR with an irrelevant owner, code %d",st); - else adns__debug(ads,serv,"ignoring RR with an irrelevant owner \"%s\"",cowner); + 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"); } continue; } - if (!qu->cname && - (qu->type & adns__rrt_typemask) != adns_cname && - rrtype == adns_cname) { /* Ignore second and subsequent CNAMEs */ - st= get_domain_perm(ads,qu,serv, dgram,dglen, - &rdstart,rdstart+rdlength,&qu->cname); - if (st) return st; - if (!qu->cname) goto x_truncated; + 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. */ - } else if (rrtype == (qu->type & adns__rrt_typemask)) { + } else if (rrtype == (qu->typei->type & adns__rrt_typemask)) { wantedrrs++; } else { adns__debug(ads,serv,"ignoring answer RR with irrelevant type %d",rrtype); @@ -335,9 +174,9 @@ void adns__procdgram(adns_state ads, const byte *dgram, int dglen, int serv) { foundsoa= 0; foundns= 0; for (rri= 0; rricname) { - cname_recurse(ads,qu); - return; - } + if (qu->cnameoff != -1) { cname_recurse(ads,qu,0); return; } /* Bloody hell, I thought we asked for recursion ? */ if (!flg_ra) { @@ -370,81 +206,54 @@ void adns__procdgram(adns_state ads, const byte *dgram, int dglen, int serv) { return; } adns__diag(ads,serv,"server claims to do recursion, but gave us a referral"); - adns__query_fail(ads,qu,adns_s_serverfault); + adns__query_fail(ads,qu,adns_s_serverfaulty); return; } /* Now, we have some RRs which we wanted. */ - rrs= - - } - } else { - -{ truncated(ads,qu,flg_ra); return; } - - ) { - if (type - if (cbyte+lab - if (anstart > dgend) { truncated(ads,qu,f1); return; } - } - for - /* Look for CNAMEs in the answer section */ + qu->rrsoff= adns__vbuf_malloc(&qu->ans,qu->typei->rrsz*wantedrrs); + if (qu->rrsoff == -1) adns__query_fail(ads,qu,adns_s_nolocalmem); + + cbyte= anstart; + currentrrs= 0; + arstart= -1; + for (rri=0; rritypei->type & adns__rrt_typemask)) + continue; + assert(currentrrstypei->get_fn(ads,qu,serv, dgram,dglen, &rdstart,rdstart+rdlength, + nsstart,arcount,&arstart, qu->rrsoff,¤trrs); + if (st) { adns__query_fail(ads,qu,st); return; } + if (currentrrs==-1) goto x_truncated; + } + /* This may have generated some child queries ... */ + if (qu->children.head) { + qu->state= query_child; + LIST_LINK_TAIL(ads->childw,qu); + return; } - - - adns__diag(ads,serv,"server refused our query"); - - case rcode_ - - case 0: /* NOERROR - break; - case 1: /* Format error */ - case 3: /* Name Error */ - - qr= f1&0x80; - - - adns__diag(ads,serv,"received datagram size %d",len); -} + adns__query_finish(ads,qu,adns_s_ok); + return; - while ( - switch (type) { - case adns_r_a: - adns_r_a_mf= adns_r_a|adns__qtf_masterfmt, - - adns_r_ns_raw= 2, - adns_r_ns= adns_r_ns_raw|adns__qtf_deref, - adns_r_ns_mf= adns_r_ns_raw|adns__qtf_masterfmt, - - adns_r_cname= 5, - adns_r_cname_mf= adns_r_cname|adns__qtf_masterfmt, - - adns_r_soa_raw= 6, - adns_r_soa= adns_r_soa_raw|adns__qtf_mail822, - adns_r_soa_mf= adns_r_soa_raw|adns__qtf_masterfmt, - - adns_r_null= 10, - adns_r_null_mf= adns_r_null|adns__qtf_masterfmt, - - adns_r_ptr_raw= 12, - adns_r_ptr= adns_r_ptr_raw|adns__qtf_deref, - adns_r_ptr_mf= adns_r_ptr_raw|adns__qtf_masterfmt, - - adns_r_hinfo= 13, - adns_r_hinfo_mf= adns_r_hinfo|adns__qtf_masterfmt, - - adns_r_mx_raw= 15, - adns_r_mx= adns_r_mx_raw|adns__qtf_deref, - adns_r_mx_mf= adns_r_mx_raw|adns__qtf_masterfmt, - - adns_r_txt= 16, - adns_r_txt_mf= adns_r_txt|adns__qtf_masterfmt, - - adns_r_rp_raw= 17, - adns_r_rp= adns_r_rp_raw|adns__qtf_mail822, - adns_r_rp_mf= adns_r_rp_raw|adns__qtf_masterfmt - - +x_truncated: + if (!flg_tc) { + adns__diag(ads,serv,"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; + ans= (adns_answer*)qu->ans.buf; + ans->nrrs= 0; + qu->ans.used= sizeof(adns_answer); + qu->flags |= adns_qf_usevc; + adns__query_udp(ads,qu,now); +} diff --git a/src/submit.c b/src/submit.c index d29a140..a6d0e63 100644 --- a/src/submit.c +++ b/src/submit.c @@ -13,14 +13,23 @@ static adns_query allocquery(adns_state ads, const char *owner, int ol, adns_queryflags flags, const qcontext *ctx) { /* Query message used is the one assembled in ads->rqbuf */ adns_query qu; + adns_answer *ans; qu= malloc(sizeof(*qu)+ol+1+ads->rqbuf.used); if (!qu) return 0; + + adns__vbuf_init(&qu->ans); + if (!adns__vbuf_ensure(&qu->ans,sizeof(adns_answer))) { free(qu); return 0; } + ans= (adns_answer*)qu->ans.buf; + ans->status= adns_s_ok; + ans->type= qu->typei->type; + ans->nrrs= 0; + ans->rrs.str= 0; + qu->state= query_udp; qu->next= qu->back= qu->parent= 0; LIST_INIT(qu->children); qu->siblings.next= qu->siblings.back= 0; qu->typei= typei; - adns__vbuf_init(&qu->answer); qu->id= id; qu->flags= flags; qu->udpretries= 0; @@ -32,16 +41,16 @@ static adns_query allocquery(adns_state ads, const char *owner, int ol, qu->querymsg= qu->owner+ol+1; memcpy(qu->owner+ol+1,ads->rqbuf.buf,ads->rqbuf.used); qu->querylen= ads->rqbuf.used; + return qu; } static int failsubmit(adns_state ads, const qcontext *ctx, adns_query *query_r, - adns_rrtype type, adns_queryflags flags, - int id, adns_status stat) { + adns_queryflags flags, int id, adns_status stat) { adns_query qu; ads->rqbuf.used= 0; - qu= allocquery(ads,0,0,id,type,flags,ctx); if (!qu) return errno; + qu= allocquery(ads,0,0,id,0,flags,ctx); if (!qu) return errno; adns__query_fail(ads,qu,stat); *query_r= qu; return 0; @@ -58,23 +67,23 @@ int adns_submit(adns_state ads, int ol, id, r; qcontext ctx; struct timeval now; - const typeinfo typei; + const typeinfo *typei; ctx.ext= context; id= ads->nextid++; r= gettimeofday(&now,0); if (r) return errno; - typei= findtype(type); - if (!typei) return failsubmit(ads,context,query_r,0,flags,id,adns_s_notimplemented); + typei= adns__findtype(type); + if (!typei) return failsubmit(ads,context,query_r,flags,id,adns_s_notimplemented); ol= strlen(owner); - if (ol<=1 || ol>MAXDNAME+1) - return failsubmit(ads,context,query_r,0,flags,id,adns_s_invaliddomain); + if (ol<=1 || ol>DNS_MAXDOMAIN+1) + return failsubmit(ads,context,query_r,flags,id,adns_s_invaliddomain); if (owner[ol-1]=='.' && owner[ol-2]!='\\') { flags &= ~adns_qf_search; ol--; } - stat= adns__mkquery(ads,owner,ol,id,type,flags); - if (stat) return failsubmit(ads,context,query_r,type,flags,id,stat); + stat= adns__mkquery(ads,owner,ol,id,typei,flags); + if (stat) return failsubmit(ads,context,query_r,flags,id,stat); qu= allocquery(ads,owner,ol,id,typei,flags,&ctx); if (!qu) return errno; adns__query_udp(ads,qu,now); diff --git a/src/types.c b/src/types.c new file mode 100644 index 0000000..f427dcd --- /dev/null +++ b/src/types.c @@ -0,0 +1,43 @@ +/**/ + +#include "internal.h" + +#define TYRRSZ(rrtype,size,func) { (rrtype), (size), (func) } + +#define TYRRSZ(sizememb) (sizeof(((adns_answer*)0)->rrs.sizememb)) + +static const typeinfo typeinfos[] = { + /* Must be in ascending order of rrtype ! */ + + { adns_r_a, TYRR(inaddr), rpf_inaddr }, + { adns_r_ns_raw, TYRR(str), rpf_domain_raw }, + { adns_r_cname, TYRR(str), rpf_domain_raw }, + { adns_r_soa_raw, TYRR(soa), rpf_soa }, + { adns_r_null, 0, rpf_null }, + { adns_r_ptr_raw, TYRR(str), rpf_domain_raw }, + { adns_r_hinfo, TYRR(strpair), rpf_hinfo }, + { adns_r_mx_raw, TYRR(intstr), rpf_mx_raw }, + { adns_r_txt, TYRR(str), rpf_txt }, + { adns_r_rp_raw, TYRR(strpair), rpf_rp }, + + { adns_r_ns, TYRR(dmaddr), rpf_dmaddr }, + { adns_r_ptr, TYRR(str), rpf_ptr }, + { adns_r_mx, TYRR(intdmaddr), rpf_mx }, + + { adns_r_soa, TYRR(soa), rpf_soa }, + { adns_r_rp, TYRR(strpair), rpf_rp }, +}; + +const typeinfo adns__findtype(adns_rrtype type) { + const typeinfo *begin, *end; + + begin= typeinfos; end= typeinfos+(sizeof(typeinfos)/sizeof(typeinfo)); + + while (begin < end) { + mid= begin + ((end-begin)>>1); + if (mid->type == type) return mid; + if (type > mid->type) begin= mid+1; + else end= mid; + } + return 0; +}