adns_r_ns_raw,
adns_r_cname,
adns_r_ptr_raw,
+ adns_r_mx_raw,
+ adns_r_rp_raw,
adns_r_txt,
adns_r_none
};
-int main(int argc, const char *const *argv) {
+static void dumptype(adns_status ri, const char *rrtn, const char *fmtn) {
+ fprintf(stdout, "%s(%s)%s%s",
+ ri ? "?" : rrtn, ri ? "?" : fmtn ? fmtn : "-",
+ ri ? " " : "", ri ? adns_strerror(ri) : "");
+}
+
+int main(int argc, char *const *argv) {
adns_state ads;
adns_query *qus, qu;
adns_answer *ans;
- const char *rrtn, *fmtn;
- char *show;
- int len, i, qc, qi, tc, ti;
+ const char *rrtn, *fmtn, *const *domlist;
+ char *show, *cp;
+ int len, i, qc, qi, tc, ti, ch;
adns_status r, ri;
const adns_rrtype *types;
+ adns_rrtype *types_a;
- if (argv[0] && argv[1]) argv++;
- else argv= defaultargv;
-
- types= defaulttypes;
+ if (argv[0] && argv[1] && argv[1][0] == ':') {
+ for (cp= argv[1]+1, tc=1; (ch= *cp); cp++)
+ if (ch==',') tc++;
+ types_a= malloc(sizeof(*types_a)*tc);
+ if (!types_a) { perror("malloc types"); exit(3); }
+ for (cp= argv[1]+1, ti=0; ti<tc; ti++) {
+ types_a[ti]= strtoul(cp,&cp,10);
+ if ((ch= *cp)) {
+ if (ch != ':') {
+ fputs("usage: dtest [:<typenum>,...] [<domain> ...]",stderr);
+ exit(4);
+ }
+ cp++;
+ }
+ }
+ types= types_a;
+ argv++;
+ } else {
+ types= defaulttypes;
+ }
+
+ if (argv[0] && argv[1]) domlist= (const char *const*)argv+1;
+ else domlist= defaultargv;
- for (qc=0; qc[argv]; qc++);
+ for (qc=0; qc[domlist]; qc++);
for (tc=0; types[tc] != adns_r_none; tc++);
qus= malloc(sizeof(qus)*qc*tc);
if (!qus) { perror("malloc qus"); exit(3); }
for (qi=0; qi<qc; qi++) {
for (ti=0; ti<tc; ti++) {
- fprintf(stdout,"%s type %d",argv[qi],types[ti]);
- r= adns_submit(ads,argv[qi],types[ti],0,0,&qus[qi*tc+ti]);
+ fprintf(stdout,"%s type %d",domlist[qi],types[ti]);
+ r= adns_submit(ads,domlist[qi],types[ti],0,0,&qus[qi*tc+ti]);
if (r == adns_s_notimplemented) {
fprintf(stdout," not implemented\n");
qus[qi*tc+ti]= 0;
} else if (r) {
failure("submit",r);
} else {
+ ri= adns_rr_info(types[ti], &rrtn,&fmtn,0, 0,0);
+ putchar(' ');
+ dumptype(ri,rrtn,fmtn);
fprintf(stdout," submitted\n");
}
}
if (r) failure("wait",r);
ri= adns_rr_info(ans->type, &rrtn,&fmtn,&len, 0,0);
- fprintf(stdout, "%s type %s(%s)%s%s: ",
- argv[qi],
- ri ? "?" : rrtn, ri ? "?" : fmtn ? fmtn : "-",
- ri ? " " : "", ri ? adns_strerror(ri) : "");
- fprintf(stdout, "%s; nrrs=%d; cname=%s\n",
+ fprintf(stdout, "%s type ", domlist[qi]);
+ dumptype(ri,rrtn,fmtn);
+ fprintf(stdout, ": %s; nrrs=%d; cname=%s\n",
adns_strerror(ans->status),
ans->nrrs, ans->cname ? ans->cname : "$");
if (ans->nrrs) {
*/
typedef enum {
+ /* fixme: think about error codes */
adns_s_ok,
adns_s_timeout,
adns_s_nolocalmem,
} adns_rr_intdmaddr;
typedef struct {
+ /* Used both for mx_raw, in which case i is the preference and str the domain,
+ * and for txt, in which case each entry has i for the `text' length,
+ * and str for the data (which will have had an extra nul appended
+ * so that if it was plain text it is now a null-terminated string).
+ */
int i;
char *str;
} adns_rr_intstr;
void *untyped;
unsigned char *bytes;
char *(*str); /* ns_raw, cname, ptr, ptr_raw */
- char *(**manystr); /* txt (list is null-terminated) */
+ adns_rr_intstr *(*manyistr); /* txt (list of strings ends with i=-1, str=0) */
struct in_addr *inaddr; /* a */
adns_rr_dmaddr *dmaddr; /* ns */
- adns_rr_strpair *strpair; /* hinfo, rp, rp_raw */
+ adns_rr_strpair *strpair; /* hinfo ??fixme, rp, rp_raw */
adns_rr_intdmaddr *intdmaddr; /* mx */
adns_rr_intstr *intstr; /* mx_raw */
adns_rr_soa *soa; /* soa, soa_raw */
inter_addfd(maxfd,readfds,ads->tcpsocket);
inter_addfd(maxfd,exceptfds,ads->tcpsocket);
if (ads->tcpsend.used) inter_addfd(maxfd,writefds,ads->tcpsocket);
+ break;
default:
abort();
}
if (callb_checkfd(maxfd,writefds,ads->tcpsocket)) {
count++;
assert(ads->tcprecv.used==0);
- adns__vbuf_ensure(&ads->tcprecv,1);
+ if (!adns__vbuf_ensure(&ads->tcprecv,1)) return -1;
if (ads->tcprecv.buf) {
r= read(ads->tcpsocket,&ads->tcprecv.buf,1);
if (r==0 || (r<0 && (errno==EAGAIN || errno==EWOULDBLOCK))) {
}
ads->tcprecv.used -= skip;
memmove(ads->tcprecv.buf,ads->tcprecv.buf+skip,ads->tcprecv.used);
- adns__vbuf_ensure(&ads->tcprecv,want);
- if (ads->tcprecv.used >= ads->tcprecv.avail) break;
+ skip= 0;
+ if (!adns__vbuf_ensure(&ads->tcprecv,want)) return -1;
+ assert(ads->tcprecv.used <= ads->tcprecv.avail);
+ if (ads->tcprecv.used == ads->tcprecv.avail) continue;
r= read(ads->tcpsocket,
ads->tcprecv.buf+ads->tcprecv.used,
ads->tcprecv.avail-ads->tcprecv.used);
memmove(ads->tcpsend.buf,ads->tcpsend.buf+r,ads->tcpsend.used);
}
}
+ break;
default:
abort();
}
* If there is an overrun which might indicate truncation, it should set
* *rdstart to -1; otherwise it may set it to anything else positive.
*/
+
+ int (*diff_needswap)(const void *datap_a, const void *datap_b);
+ /* Returns >0 if RR a should be strictly after RR b in the sort order,
+ * 0 otherwise. Must not fail.
+ */
} typeinfo;
typedef struct allocnode {
void *final_allocspace;
const typeinfo *typei;
- char *query_dgram;
+ byte *query_dgram;
int query_dglen;
vbuf vb;
const typeinfo *typei, adns_queryflags flags);
/* Assembles a query packet in vb, and returns id at *id_r. */
+adns_status adns__mkquery_frdgram(adns_state ads, vbuf *vb, int *id_r,
+ const byte *qd_dgram, int qd_dglen, int qd_begin,
+ adns_rrtype type, adns_queryflags flags);
+/* Same as adns__mkquery, but takes the owner domain from an existing datagram.
+ * That domain must be correct and untruncated.
+ */
+
void adns__query_tcp(adns_query qu, struct timeval now);
/* Query must be in state tcpwait/timew; it will be moved to a new state
* if possible and no further processing can be done on it for now.
* big enough for all these allocations, and then adns__alloc_final
* will get memory from this buffer.
*
- * _alloc_interim can fail, in which case it will fail the query too,
- * so nothing more need be done with it.
+ * _alloc_interim can fail (and return 0).
+ * The caller must ensure that the query is failed.
*
- * adns__alloc_interim(qu,0) will not return 0, but it will not
- * necessarily return a distinct pointer each time.
+ * adns__alloc_interim_{only,fail}(qu,0) will not return 0,
+ * but it will not necessarily return a distinct pointer each time.
*/
void *adns__alloc_mine(adns_query qu, size_t sz);
if (!sz) return qu; /* Any old pointer will do */
assert(!qu->final_allocspace);
an= malloc(MEM_ROUND(MEM_ROUND(sizeof(*an)) + sz));
- if (!an) {
- adns__query_fail(qu,adns_s_nolocalmem);
- return 0;
- }
+ if (!an) return 0;
an->next= qu->allocations;
qu->allocations= an;
return (byte*)an + MEM_ROUND(sizeof(*an));
allocnode *an, *ann;
int i;
- qu->answer= ans= realloc(qu->answer,
- MEM_ROUND(MEM_ROUND(sizeof(*ans)) +
- qu->interim_allocd));
- qu->final_allocspace= (byte*)qu->answer + MEM_ROUND(sizeof(*ans));
+ if (qu->answer->status == adns_s_nolocalmem && !qu->interim_allocd) {
+ ans= qu->answer;
+ } else {
+ ans= realloc(qu->answer,
+ MEM_ROUND(MEM_ROUND(sizeof(*ans)) + qu->interim_allocd));
+ if (!ans) {
+ qu->answer->cname= 0;
+ adns__query_fail(qu, adns_s_nolocalmem);
+ return;
+ }
+ qu->answer= ans;
+ }
+ qu->final_allocspace= (byte*)ans + MEM_ROUND(sizeof(*ans));
adns__makefinal_str(qu,&ans->cname);
if (ans->nrrs) {
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
-#include "internal.h"
+#include <stdlib.h>
+#include <string.h>
-static void cname_recurse(adns_query qu, adns_queryflags xflags) {
- adns__diag(qu->ads,-1,qu,"cname following not implemented fixme");
- adns__query_fail(qu,adns_s_notimplemented);
-}
+#include "internal.h"
void adns__procdgram(adns_state ads, const byte *dgram, int dglen,
int serv, struct timeval now) {
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;
+ int rrtype, rrclass, rdlength, rdstart;
int anstart, nsstart, arstart;
+ int ownermatched, l, nrrs, place;
+ const typeinfo *typei;
adns_query qu, nqu;
dns_rcode rcode;
adns_status st;
vbuf tempvb;
+ byte *newquery, *rrsdata;
if (dglen<DNS_HDRSIZE) {
adns__diag(ads,serv,0,"received datagram too short for message header (%d)",dglen);
flg_qr= f1&0x80;
opcode= (f1&0x78)>>3;
- flg_tc= f1&0x20;
+ flg_tc= f1&0x02;
flg_rd= f1&0x01;
flg_ra= f2&0x80;
rcode= (f2&0x0f);
}
continue;
}
- if (rrtype == adns_r_cname &&
+ if (rrtype == adns_r_cname && /* fixme - implement adns_qf_nocname */
(qu->typei->type & adns__rrt_typemask) != adns_r_cname) {
if (!qu->cname_dgram) { /* Ignore second and subsequent CNAMEs */
- qu->cname_dgram= adns__alloc_mine(qu,dglen);
- if (!qu->cname_dgram) return;
qu->cname_begin= rdstart;
qu->cname_dglen= dglen;
st= adns__parse_domain(ads,serv,qu, &qu->vb,qu->flags,
if (st) { adns__query_fail(qu,st); return; }
l= strlen(qu->vb.buf)+1;
qu->answer->cname= adns__alloc_interim(qu,l);
- if (!qu->answer->cname) return;
+ if (!qu->answer->cname) { adns__query_fail(qu,adns_s_nolocalmem); return; }
+
+ qu->cname_dgram= adns__alloc_mine(qu,dglen);
+ memcpy(qu->cname_dgram,dgram,dglen);
+
memcpy(qu->answer->cname,qu->vb.buf,l);
cname_here= 1;
/* If we find the answer section truncated after this point we restart
}
}
- /* If we got here then the answer section is intact. */
+ /* We defer handling truncated responses here, in case there was a CNAME
+ * which we could use.
+ */
+ if (flg_tc) goto x_truncated;
+
nsstart= cbyte;
if (!wantedrrs) {
* 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 (cname_here) { cname_recurse(qu,0); return; }
+ if (cname_here) goto x_restartquery;
/* Bloody hell, I thought we asked for recursion ? */
if (flg_rd) {
/* Now, we have some RRs which we wanted. */
qu->answer->rrs.untyped= adns__alloc_interim(qu,qu->typei->rrsz*wantedrrs);
- if (!qu->answer->rrs.untyped) return;
+ if (!qu->answer->rrs.untyped) { adns__query_fail(qu,adns_s_nolocalmem); return; }
+ typei= qu->typei;
cbyte= anstart;
arstart= -1;
+ rrsdata= qu->answer->rrs.bytes;
+
+ if (typei->diff_needswap) {
+ if (!adns__vbuf_ensure(&qu->vb,typei->rrsz)) {
+ adns__query_fail(qu,adns_s_nolocalmem);
+ return;
+ }
+ }
+ nrrs= 0;
+
for (rri=0; rri<ancount; rri++) {
st= adns__findrr(qu,serv, dgram,dglen,&cbyte,
&rrtype,&rrclass,&rdlength,&rdstart,
rrtype != (qu->typei->type & adns__rrt_typemask) ||
!ownermatched)
continue;
- assert(qu->answer->nrrs<wantedrrs);
- st= qu->typei->parse(qu,serv,
- dgram,dglen, rdstart,rdstart+rdlength,
- qu->answer->rrs.bytes+qu->answer->nrrs*qu->typei->rrsz);
+ st= typei->parse(qu,serv, dgram,dglen, rdstart,rdstart+rdlength,
+ rrsdata+nrrs*typei->rrsz);
if (st) { adns__query_fail(qu,st); return; }
if (rdstart==-1) goto x_truncated;
- qu->answer->nrrs++;
+
+ if (typei->diff_needswap) {
+ for (place= nrrs;
+ place>0 && typei->diff_needswap(rrsdata+(place-1)*typei->rrsz,
+ rrsdata+nrrs*typei->rrsz);
+ place--);
+ if (place != nrrs) {
+ memcpy(qu->vb.buf,rrsdata+nrrs*typei->rrsz,typei->rrsz);
+ memmove(rrsdata+(place+1)*typei->rrsz,
+ rrsdata+place*typei->rrsz,
+ (nrrs-place)*typei->rrsz);
+ memcpy(rrsdata+place*typei->rrsz,qu->vb.buf,typei->rrsz);
+ }
+ }
+ nrrs++;
}
+ assert(nrrs==wantedrrs);
+ qu->answer->nrrs= nrrs;
/* This may have generated some child queries ... */
if (qu->children.head) {
return;
x_truncated:
+
if (!flg_tc) {
adns__diag(ads,serv,qu,"server sent datagram which points outside itself");
adns__query_fail(qu,adns_s_serverfaulty);
return;
}
- if (qu->cname_dgram) { cname_recurse(qu,adns_qf_usevc); return; }
- adns__reset_cnameonly(qu);
qu->flags |= adns_qf_usevc;
+
+ x_restartquery:
+
+ if (qu->cname_dgram) {
+ st= adns__mkquery_frdgram(qu->ads,&qu->vb,&qu->id,
+ qu->cname_dgram, qu->cname_dglen, qu->cname_begin,
+ qu->typei->type, qu->flags);
+ if (st) { adns__query_fail(qu,st); return; }
+
+ newquery= realloc(qu->query_dgram,qu->vb.used);
+ if (!newquery) { adns__query_fail(qu,adns_s_nolocalmem); return; }
+
+ qu->query_dgram= newquery;
+ qu->query_dglen= qu->vb.used;
+ memcpy(newquery,qu->vb.buf,qu->vb.used);
+ }
+
+ adns__reset_cnameonly(qu);
adns__query_udp(qu,now);
}
#include "internal.h"
-adns_status adns__mkquery(adns_state ads, vbuf *vb, int *id_r,
- const char *owner, int ol,
- const typeinfo *typei, adns_queryflags flags) {
- int ll, c, nlabs, id;
- byte label[255], *rqp;
- const char *p, *pe;
-
+#define MKQUERY_START(vb) (rqp= (vb)->buf+(vb)->used)
#define MKQUERY_ADDB(b) *rqp++= (b)
#define MKQUERY_ADDW(w) (MKQUERY_ADDB(((w)>>8)&0x0ff), MKQUERY_ADDB((w)&0x0ff))
+#define MKQUERY_STOP(vb) ((vb)->used= rqp-(vb)->buf)
- vb->used= 0;
- if (!adns__vbuf_ensure(vb,DNS_HDRSIZE+strlen(owner)+1+5))
- return adns_s_nolocalmem;
- rqp= vb->buf;
+static adns_status mkquery_header(adns_state ads, vbuf *vb, int *id_r, int qdlen) {
+ int id;
+ byte *rqp;
+
+ if (!adns__vbuf_ensure(vb,DNS_HDRSIZE+qdlen+4)) return adns_s_nolocalmem;
*id_r= id= (ads->nextid++) & 0x0ffff;
-
+
+ vb->used= 0;
+ MKQUERY_START(vb);
+
MKQUERY_ADDW(id);
MKQUERY_ADDB(0x01); /* QR=Q(0), OPCODE=QUERY(0000), !AA, !TC, RD */
MKQUERY_ADDB(0x00); /* !RA, Z=000, RCODE=NOERROR(0000) */
MKQUERY_ADDW(0); /* ANCOUNT=0 */
MKQUERY_ADDW(0); /* NSCOUNT=0 */
MKQUERY_ADDW(0); /* ARCOUNT=0 */
+
+ MKQUERY_STOP(vb);
+
+ return adns_s_ok;
+}
+
+static adns_status mkquery_footer(vbuf *vb, adns_rrtype type) {
+ byte *rqp;
+
+ MKQUERY_START(vb);
+ MKQUERY_ADDW(type & adns__rrt_typemask); /* QTYPE */
+ MKQUERY_ADDW(DNS_CLASS_IN); /* QCLASS=IN */
+ MKQUERY_STOP(vb);
+ assert(vb->used <= vb->avail);
+
+ return adns_s_ok;
+}
+
+adns_status adns__mkquery(adns_state ads, vbuf *vb, int *id_r,
+ const char *owner, int ol,
+ const typeinfo *typei, adns_queryflags flags) {
+ int ll, c, nlabs;
+ byte label[255], *rqp;
+ const char *p, *pe;
+ adns_status st;
+
+ st= mkquery_header(ads,vb,id_r,strlen(owner)+2); if (st) return st;
+
+ MKQUERY_START(vb);
+
p= owner; pe= owner+ol;
nlabs= 0;
if (!*p) return adns_s_invalidquerydomain;
MKQUERY_ADDB(ll);
memcpy(rqp,label,ll); rqp+= ll;
} while (p!=pe);
+ MKQUERY_ADDB(0);
+ MKQUERY_STOP(vb);
+
+ st= mkquery_footer(vb,typei->type);
+
+ return adns_s_ok;
+}
+
+adns_status adns__mkquery_frdgram(adns_state ads, vbuf *vb, int *id_r,
+ const byte *qd_dgram, int qd_dglen, int qd_begin,
+ adns_rrtype type, adns_queryflags flags) {
+ byte *rqp;
+ findlabel_state fls;
+ int lablen, labstart;
+ adns_status st;
+
+ st= mkquery_header(ads,vb,id_r,qd_dglen); if (st) return st;
+
+ MKQUERY_START(vb);
+
+ adns__findlabel_start(&fls,ads,-1,0,qd_dgram,qd_dglen,qd_dglen,qd_begin,0);
+ for (;;) {
+ st= adns__findlabel_next(&fls,&lablen,&labstart); assert(!st);
+ if (!lablen) break;
+ assert(lablen<255);
+ MKQUERY_ADDB(lablen);
+ memcpy(rqp,qd_dgram+labstart,lablen);
+ rqp+= lablen;
+ }
MKQUERY_ADDB(0);
- MKQUERY_ADDW(typei->type & adns__rrt_typemask); /* QTYPE */
- MKQUERY_ADDW(DNS_CLASS_IN); /* QCLASS=IN */
- vb->used= rqp - vb->buf;
- assert(vb->used <= vb->avail);
+ MKQUERY_STOP(vb);
+
+ st= mkquery_footer(vb,type);
return adns_s_ok;
}
timevaladd(&now,TCPMS);
qu->timeout= now;
qu->state= query_tcpsent;
- LIST_LINK_TAIL(ads->timew,qu);
if (ads->tcpsend.used) {
wr= 0;
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;
+ void *datap) {
+ struct in_addr *storeto= datap;
if (max-cbyte != 4) return adns_s_invaliddata;
- memcpy(dr,dgram+cbyte,4);
+ memcpy(storeto,dgram+cbyte,4);
return adns_s_ok;
}
-static adns_status cs_inaddr(vbuf *vb, const void *data) {
- const struct in_addr *dp= data;
+static int dip_inaddr(struct in_addr a, struct in_addr b) {
+ /* fixme implement sortlist */
+ return 0;
+}
+
+static int di_inaddr(const void *datap_a, const void *datap_b) {
+ const struct in_addr *ap= datap_a, *bp= datap_b;
+
+ return dip_inaddr(*ap,*bp);
+}
+
+static adns_status cs_inaddr(vbuf *vb, const void *datap) {
+ const struct in_addr *rrp= datap, rr= *rrp;
const char *ia;
- ia= inet_ntoa(*dp); assert(ia);
+ ia= inet_ntoa(rr); assert(ia);
return adns__vbuf_appendstr(vb,ia) ? adns_s_ok : adns_s_nolocalmem;
}
+static adns_status pap_domain(adns_query qu, int serv,
+ const byte *dgram, int dglen, int *cbyte_io, int max,
+ char **domain_r) {
+ adns_status st;
+ char *dm;
+
+ st= adns__parse_domain(qu->ads,serv,qu,&qu->vb,qu->flags,
+ dgram,dglen, cbyte_io,max);
+ if (st) return st;
+ if (!qu->vb.used) return adns_s_invaliddata;
+
+ dm= adns__alloc_interim(qu,qu->vb.used+1);
+ if (!dm) return adns_s_nolocalmem;
+
+ dm[qu->vb.used]= 0;
+ memcpy(dm,qu->vb.buf,qu->vb.used);
+
+ *domain_r= dm;
+ return adns_s_ok;
+}
+
static adns_status pa_domain_raw(adns_query qu, int serv,
const byte *dgram, int dglen, int cbyte, int max,
- void *store_r) {
- char **dpp= store_r;
+ void *datap) {
+ char **rrp= datap;
adns_status st;
- vbuf vb;
- char *dp;
- adns__vbuf_init(&vb);
- st= adns__parse_domain(qu->ads,serv,qu,&vb,qu->flags,
- dgram,dglen, &cbyte,max);
- if (st) goto x_error;
-
- dp= adns__alloc_interim(qu,vb.used+1);
- if (!dp) { st= adns_s_nolocalmem; goto x_error; }
+ st= pap_domain(qu,serv,dgram,dglen,&cbyte,max,rrp);
+ if (st) return st;
+
+ if (cbyte != max) return adns_s_invaliddata;
+ return adns_s_ok;
+}
- dp[vb.used]= 0;
- memcpy(dp,vb.buf,vb.used);
+static adns_status pa_mx_raw(adns_query qu, int serv,
+ const byte *dgram, int dglen, int cbyte, int max,
+ void *datap) {
+ adns_rr_intstr *rrp= datap;
+ adns_status st;
+ int pref;
- if (cbyte != max) { st= adns_s_invaliddata; goto x_error; }
+ if (cbyte+2 > max) return adns_s_invaliddata;
+ GET_W(cbyte,pref);
+ rrp->i= pref;
+ st= pap_domain(qu,serv,dgram,dglen,&cbyte,max,&rrp->str);
+ if (st) return st;
+
+ if (cbyte != max) return adns_s_invaliddata;
+ return adns_s_ok;
+}
- st= adns_s_ok;
- *dpp= dp;
+static int di_mx_raw(const void *datap_a, const void *datap_b) {
+ const adns_rr_intstr *ap= datap_a, *bp= datap_b;
- x_error:
- adns__vbuf_free(&vb);
- return st;
+ if (ap->i < bp->i) return 0;
+ if (ap->i > bp->i) return 1;
+ return 0;
}
-static void mf_str(adns_query qu, void *data) {
- char **ddp= data;
+static adns_status pa_txt(adns_query qu, int serv,
+ const byte *dgram, int dglen, int startbyte, int max,
+ void *datap) {
+ adns_rr_intstr **rrp= datap, *table, *te;
+ int ti, tc, cbyte, l;
- adns__makefinal_str(qu,ddp);
+ cbyte= startbyte;
+ if (cbyte >= max) return adns_s_invaliddata;
+ tc= 0;
+ while (cbyte < max) {
+ GET_B(cbyte,l);
+ cbyte+= l;
+ }
+ if (cbyte != max) return adns_s_invaliddata;
+
+ table= adns__alloc_interim(qu,sizeof(*table)*(tc+1));
+ if (!table) return adns_s_nolocalmem;
+
+ for (cbyte=startbyte, ti=0, te=table; ti<tc; ti++, te++) {
+ GET_B(cbyte,l);
+ te->str= adns__alloc_interim(qu,l+1);
+ if (!te->str) return adns_s_nolocalmem;
+ te->str[l]= 0;
+ memcpy(te->str,dgram+cbyte,l);
+ te->i= l;
+ }
+ assert(cbyte == max);
+
+ te->i= -1;
+ te->str= 0;
+
+ *rrp= table;
+ return adns_s_ok;
}
-static int csp_qstring(vbuf *vb, const char *dp) {
+static int csp_textdata(vbuf *vb, const char *dp, int len) {
unsigned char ch;
char buf[10];
+ int cn;
if (!adns__vbuf_append(vb,"\"",1)) return 0;
- while ((ch= *dp++)) {
+ for (cn=0; cn<len; cn++) {
+ ch= *dp++;
if (ch >= 32 && ch <= 126 && ch != '"' && ch != '\\') {
if (!adns__vbuf_append(vb,&ch,1)) return 0;
} else {
return 1;
}
-static adns_status cs_str(vbuf *vb, const void *data) {
- const char *const *dpp= data;
+static int csp_qstring(vbuf *vb, const char *dp) {
+ return csp_textdata(vb, dp, strlen(dp));
+}
+
+static adns_status cs_str(vbuf *vb, const void *datap) {
+ const char *const *rrp= datap;
+
+ return csp_qstring(vb,*rrp) ? adns_s_ok : adns_s_nolocalmem;
+}
+
+static adns_status cs_intstr(vbuf *vb, const void *datap) {
+ const adns_rr_intstr *rrp= datap;
+ char buf[10];
+
+ sprintf(buf,"%u ",rrp->i);
+ return (adns__vbuf_appendstr(vb,buf) &&
+ csp_qstring(vb,rrp->str)) ? adns_s_ok : adns_s_nolocalmem;
+}
+
+static adns_status cs_manyistr(vbuf *vb, const void *datap) {
+ const adns_rr_intstr *const *rrp= datap;
+ const adns_rr_intstr *current;
+ int spc;
+
+ for (spc=0, current= *rrp; current->i >= 0; current++) {
+ if (spc)
+ if (!adns__vbuf_append(vb," ",1)) goto x_nomem;
+ if (!csp_textdata(vb,current->str,current->i)) goto x_nomem;
+ }
+ return adns_s_ok;
- return csp_qstring(vb,*dpp) ? adns_s_ok : adns_s_nolocalmem;
+ x_nomem:
+ return adns_s_nolocalmem;
+}
+
+static void mf_str(adns_query qu, void *datap) {
+ char **rrp= datap;
+
+ adns__makefinal_str(qu,rrp);
+}
+
+static void mf_intstr(adns_query qu, void *datap) {
+ adns_rr_intstr *rrp= datap;
+
+ adns__makefinal_str(qu,&rrp->str);
+}
+
+static void mf_manyistr(adns_query qu, void *datap) {
+ adns_rr_intstr **rrp= datap;
+ adns_rr_intstr *te, *table;
+ void *tablev;
+ int tc;
+
+ for (tc=0, te= *rrp; te->i >= 0; te++, tc++);
+ tablev= *rrp;
+ adns__makefinal_block(qu,&tablev,sizeof(*te)*(tc+1));
+ *rrp= table= tablev;
+ for (te= *rrp; te->i >= 0; te++)
+ adns__makefinal_str(qu,&te->str);
}
static void mf_flat(adns_query qu, void *data) { }
#define TYPE_SF(size,func,cp,free) size, pa_##func, mf_##free, cs_##cp
#define TYPE_SN(size,func,cp) size, pa_##func, mf_flat, cs_##cp
-#define TYPESZ_M(member) (sizeof(((adns_answer*)0)->rrs.member))
+#define TYPESZ_M(member) (sizeof(*((adns_answer*)0)->rrs.member))
#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)
static const typeinfo typeinfos[] = {
/* Must be in ascending order of rrtype ! */
- /* rr type code rrt fmt mem.mgmt member parser */
+ /* rr type code rrt fmt mem.mgmt member parser comparer */
- { adns_r_a, "A", 0, FLAT_MEMB(inaddr), pa_inaddr },
- { 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_a, "A", 0, FLAT_MEMB(inaddr), pa_inaddr, di_inaddr },
+ { adns_r_ns_raw, "NS", "raw", DEEP_MEMB(str), pa_domain_raw, 0 },
+ { adns_r_cname, "CNAME", 0, DEEP_MEMB(str), pa_domain_raw, 0 },
#if 0 /*fixme*/
- { adns_r_soa_raw, "SOA", "raw", DEEP_MEMB(soa), pa_soa },
+ { adns_r_soa_raw, "SOA", "raw", DEEP_MEMB(soa), pa_soa, 0 },
#endif
- { adns_r_ptr_raw, "PTR", "raw", DEEP_MEMB(str), pa_domain_raw },
-#if 0 /*fixme*/
- { 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(manystr), pa_txt },
- { adns_r_rp_raw, "RP", "raw", DEEP_MEMB(strpair), pa_rp },
+ { adns_r_ptr_raw, "PTR", "raw", DEEP_MEMB(str), pa_domain_raw, 0 },
+#if 0 /*fixme*/
+ { adns_r_hinfo, "HINFO", 0, DEEP_MEMB(strpair), pa_hinfo, 0 },
+#endif
+ { adns_r_mx_raw, "MX", "raw", DEEP_MEMB(intstr), pa_mx_raw, di_mx_raw },
+ { adns_r_txt, "TXT", 0, DEEP_MEMB(manyistr), pa_txt, 0 },
+#if 0 /*fixme*/
+ { adns_r_rp_raw, "RP", "raw", DEEP_MEMB(strpair), pa_rp, 0 },
+#endif
+#if 0 /*fixme*/
- { 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_ns, "NS", "+addr", DEEP_MEMB(dmaddr), pa_dmaddr, di_dmaddr },
+ { adns_r_ptr, "PTR","checked", DEEP_MEMB(str), pa_ptr, 0 },
+ { adns_r_mx, "MX", "+addr", DEEP_MEMB(intdmaddr), pa_mx, di_mx },
- { adns_r_soa, "SOA", "822", DEEP_MEMB(soa), pa_soa },
- { adns_r_rp, "RP", "822", DEEP_MEMB(strpair), pa_rp },
+#endif
+#if 0 /*fixme*/
+ { adns_r_soa, "SOA", "822", DEEP_MEMB(soa), pa_soa, 0 },
+ { adns_r_rp, "RP", "822", DEEP_MEMB(strpair), pa_rp, 0 },
#endif
};