assert(ads->tcpstate == server_connecting || ads->tcpstate == server_ok);
serv= ads->tcpserver;
- adns__warn(ads,serv,"TCP connection lost: %s: %s",what,why);
+ adns__warn(ads,serv,0,"TCP connection lost: %s: %s",what,why);
close(ads->tcpsocket);
ads->tcpstate= server_disconnected;
static void tcp_connected(adns_state ads, struct timeval now) {
adns_query qu, nqu;
- adns__debug(ads,ads->tcpserver,"TCP connected");
+ adns__debug(ads,ads->tcpserver,0,"TCP connected");
ads->tcpstate= server_ok;
for (qu= ads->timew.head; qu; qu= nqu) {
nqu= qu->next;
assert(!ads->tcprecv.used);
proto= getprotobyname("tcp");
- if (!proto) { adns__diag(ads,-1,"unable to find protocol no. for TCP !"); return; }
+ if (!proto) { adns__diag(ads,-1,0,"unable to find protocol no. for TCP !"); return; }
fd= socket(AF_INET,SOCK_STREAM,proto->p_proto);
if (fd<0) {
- adns__diag(ads,-1,"cannot create TCP socket: %s",strerror(errno));
+ adns__diag(ads,-1,0,"cannot create TCP socket: %s",strerror(errno));
return;
}
r= adns__setnonblock(ads,fd);
if (r) {
- adns__diag(ads,-1,"cannot make TCP socket nonblocking: %s",strerror(r));
+ adns__diag(ads,-1,0,"cannot make TCP socket nonblocking: %s",strerror(r));
close(fd);
return;
}
r= gettimeofday(&now,0);
if (r) {
- adns__warn(ads,-1,"gettimeofday failed - will sleep for a bit: %s",strerror(errno));
+ adns__warn(ads,-1,0,"gettimeofday failed - will sleep for a bit: %s",
+ strerror(errno));
timerclear(&tvto_lr); timevaladd(&tvto_lr,LOCALRESOURCEMS);
inter_maxto(tv_io, tvbuf, tvto_lr);
} else {
if (r<0) {
if (!(errno == EAGAIN || errno == EWOULDBLOCK ||
errno == EINTR || errno == ENOMEM || errno == ENOBUFS))
- adns__warn(ads,-1,"datagram receive error: %s",strerror(errno));
+ adns__warn(ads,-1,0,"datagram receive error: %s",strerror(errno));
break;
}
if (udpaddrlen != sizeof(udpaddr)) {
- adns__diag(ads,-1,"datagram received with wrong address length %d (expected %d)",
- udpaddrlen,sizeof(udpaddr));
+ adns__diag(ads,-1,0,"datagram received with wrong address length %d"
+ " (expected %d)", udpaddrlen,sizeof(udpaddr));
continue;
}
if (udpaddr.sin_family != AF_INET) {
- adns__diag(ads,-1,"datagram received with wrong protocol family"
+ adns__diag(ads,-1,0,"datagram received with wrong protocol family"
" %u (expected %u)",udpaddr.sin_family,AF_INET);
continue;
}
if (ntohs(udpaddr.sin_port) != DNS_PORT) {
- adns__diag(ads,-1,"datagram received from wrong port %u (expected %u)",
+ adns__diag(ads,-1,0,"datagram received from wrong port %u (expected %u)",
ntohs(udpaddr.sin_port),DNS_PORT);
continue;
}
ads->servers[serv].addr.s_addr != udpaddr.sin_addr.s_addr;
serv++);
if (serv >= ads->nservers) {
- adns__warn(ads,-1,"datagram received from unknown nameserver %s",
+ adns__warn(ads,-1,0,"datagram received from unknown nameserver %s",
inet_ntoa(udpaddr.sin_addr));
continue;
}
typedef struct {
adns_rrtype type;
+ const char *name;
int rrsz;
adns_status (*parse)(adns_state ads, adns_query qu, int serv,
struct { adns_query head, tail; } children;
struct { adns_query back, next; } siblings;
struct allocnode *allocations;
- int interim_alloced, final_used;
+ int interim_allocd;
+ void *final_allocspace;
const typeinfo *typei;
char *query_dgram;
/* From setup.c: */
void adns__vdiag(adns_state ads, const char *pfx, adns_initflags prevent,
- int serv, const char *fmt, va_list al);
+ int serv, adns_query qu, const char *fmt, va_list al);
void adns__debug(adns_state ads, int serv, adns_query qu,
- const char *fmt, ...) PRINTFFORMAT(3,4);
+ const char *fmt, ...) PRINTFFORMAT(4,5);
void adns__warn(adns_state ads, int serv, adns_query qu,
- const char *fmt, ...) PRINTFFORMAT(3,4);
+ const char *fmt, ...) PRINTFFORMAT(4,5);
void adns__diag(adns_state ads, int serv, adns_query qu,
- const char *fmt, ...) PRINTFFORMAT(3,4);
+ const char *fmt, ...) PRINTFFORMAT(4,5);
int adns__vbuf_ensure(vbuf *vb, int want);
int adns__vbuf_appendstr(vbuf *vb, const char *data);
/* From submit.c: */
int adns__internal_submit(adns_state ads, adns_query *query_r,
- adns_rrtype type, char *query_dgram, int query_len,
+ adns_rrtype type, vbuf *qumsg_vb, int id,
adns_queryflags flags, struct timeval now,
adns_status failstat, const qcontext *ctx);
/* Submits a query (for internal use, called during external submits).
*
* The new query is returned in *query_r, or we return adns_s_nomemory.
*
- * The query datagram should already have been assembled; memory for it
- * is taken over by this routine whether it succeeds or fails.
+ * The query datagram should already have been assembled in qumsg_vb;
+ * the memory for it is _taken over_ by this routine whether it
+ * succeeds or fails (if it succeeds, the vbuf is reused for qu->vb).
*
* If failstat is nonzero then if we are successful in creating the query
* it is immediately failed with code failstat (but _submit still succeds).
/* Cannot fail.
*/
+void adns__makefinal_block(adns_query qu, void **blpp, size_t sz);
+void adns__makefinal_str(adns_query qu, char **strp);
+
/* From query.c: */
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_status adns__mkquery(adns_state ads, vbuf *vb,
+ const char *owner, int ol, int *id_r,
const typeinfo *typei, adns_queryflags flags);
+/* Assembles a query packet in vb, and returns id at *id_r. */
void adns__query_ok(adns_state ads, adns_query qu);
void adns__query_fail(adns_state ads, adns_query qu, adns_status stat);
+void adns__reset_cnameonly(adns_state ads, adns_query qu);
+/* Resets all of the memory management stuff etc. to
+ * take account of only the CNAME. Used when we find an error somewhere
+ * and want to just report the error (with perhaps CNAME info), and also
+ * when we're halfway through RRs in a datagram and discover that we
+ * need to retry the query.
+ */
+
/* From reply.c: */
void adns__procdgram(adns_state ads, const byte *dgram, int len,
/* From parse.c: */
typedef struct {
- adns_state ads, int serv;
+ adns_state ads;
+ int serv;
const byte *dgram;
int dglen, max, cbyte, namelen;
int *dmend_rlater, *namelen_rlater;
if (!(lablen & 0x0c000)) break;
if ((lablen & 0x0c000) != 0x0c000) return adns_s_unknownreply;
if (jumped++) {
- adns__diag(ads,serv,"compressed datagram contains loop");
+ adns__diag(ads,fls->serv,fls->qu,"compressed datagram contains loop");
return adns_s_serverfaulty;
}
if (fls->dmend_r) *(fls->dmend_r)= fls->cbyte;
return adns_s_ok;
x_serverfaulty:
- adns__diag(ads,serv,"label in domain runs beyond end of domain");
+ adns__diag(ads,fls->serv,fls->qu,"label in domain runs beyond end of domain");
return adns_s_serverfaulty;
}
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) {
+const char *adns__diag_domain(adns_state ads, int serv, adns_query qu, 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 == adns_s_nomemory) {
+ return "<cannot report domain... out of memory>";
+ }
if (st) {
vb->used= 0;
- adns__vbuf_appendstr(vb,"<bad format... ");
- adns__vbuf_appendstr(vb,adns_strerror(st));
- adns__vbuf_appendstr(vb,">");
- adns__vbuf_append(vb,"",1);
+ if (!(adns__vbuf_appendstr(vb,"<bad format... ") &&
+ adns__vbuf_appendstr(vb,adns_strerror(st)) &&
+ adns__vbuf_appendstr(vb,">") &&
+ adns__vbuf_append(vb,"",1))) {
+ return "<cannot report bad format... out of memory>";
+ }
}
if (!vb.used) {
adns__vbuf_appendstr(vb,"<truncated ...>");
#include "internal.h"
-adns_status adns__mkquery(adns_state ads, const char *owner, int ol, int id,
+adns_status adns__mkquery(adns_state ads, vbuf *vb,
+ const char *owner, int ol, int *id_r,
const typeinfo *typei, adns_queryflags flags) {
- /* Assembles a query packet in ads->rqbuf. */
- int ll, c, nlabs;
+ int ll, c, nlabs, id;
byte label[255], *rqp;
const char *p, *pe;
#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,DNS_HDRSIZE+strlen(owner)+1+5))
+ vb->used= 0;
+ if (!adns__vbuf_ensure(vb,DNS_HDRSIZE+strlen(owner)+1+5))
return adns_s_nolocalmem;
- rqp= ads->rqbuf.buf;
+ rqp= vb->buf;
+
+ *id_r= id= (ads->nextid++) & 0x0ffff;
MKQUERY_ADDW(id);
MKQUERY_ADDB(0x01); /* QR=Q(0), OPCODE=QUERY(0000), !AA, !TC, RD */
MKQUERY_ADDW(typei->type & adns__rrt_typemask); /* QTYPE */
MKQUERY_ADDW(DNS_CLASS_IN); /* QCLASS=IN */
- ads->rqbuf.used= rqp - ads->rqbuf.buf;
- assert(ads->rqbuf.used <= ads->rqbuf.avail);
+ vb->used= rqp - vb->buf;
+ assert(vb->used <= vb->avail);
return adns_s_ok;
}
if (ads->tcpstate != server_ok) return;
- length[0]= (qu->querylen&0x0ff00U) >>8;
- length[1]= (qu->querylen&0x0ff);
+ length[0]= (qu->query_dglen&0x0ff00U) >>8;
+ length[1]= (qu->query_dglen&0x0ff);
- if (!adns__vbuf_ensure(&ads->tcpsend,ads->tcpsend.used+qu->querylen+2)) return;
+ if (!adns__vbuf_ensure(&ads->tcpsend,ads->tcpsend.used+qu->query_dglen+2)) return;
timevaladd(&now,TCPMS);
qu->timeout= now;
} else {
iov[0].iov_base= length;
iov[0].iov_len= 2;
- iov[1].iov_base= qu->querymsg;
- iov[1].iov_len= qu->querylen;
+ iov[1].iov_base= qu->query_dgram;
+ iov[1].iov_len= qu->query_dglen;
wr= writev(ads->tcpsocket,iov,2);
if (wr < 0) {
if (!(errno == EAGAIN || errno == EINTR || errno == ENOSPC ||
} else {
wr-= 2;
}
- if (wr<qu->querylen) {
- r= adns__vbuf_append(&ads->tcpsend,qu->querymsg+wr,qu->querylen-wr); assert(r);
+ if (wr<qu->query_dglen) {
+ r= adns__vbuf_append(&ads->tcpsend,qu->query_dgram+wr,qu->query_dglen-wr); assert(r);
}
}
int serv, r;
assert(qu->state == query_udp);
- if ((qu->flags & adns_qf_usevc) || (qu->querylen > DNS_MAXUDP)) {
+ if ((qu->flags & adns_qf_usevc) || (qu->query_dglen > DNS_MAXUDP)) {
query_usetcp(ads,qu,now);
return;
}
servaddr.sin_addr= ads->servers[serv].addr;
servaddr.sin_port= htons(DNS_PORT);
- r= sendto(ads->udpsocket,qu->querymsg,qu->querylen,0,&servaddr,sizeof(servaddr));
+ r= sendto(ads->udpsocket,qu->query_dgram,qu->query_dglen,0,&servaddr,sizeof(servaddr));
if (r<0 && errno == EMSGSIZE) { query_usetcp(ads,qu,now); return; }
- if (r<0) adns__warn(ads,serv,"sendto failed: %s",strerror(errno));
+ if (r<0) adns__warn(ads,serv,0,"sendto failed: %s",strerror(errno));
timevaladd(&now,UDPRETRYMS);
qu->timeout= now;
static void adns__query_done(adns_state ads, adns_query qu) {
adns_answer *ans;
allocnode *an, *ann;
+ int i;
qu->answer= ans= realloc(qu->answer,
MEM_ROUND(MEM_ROUND(sizeof(*ans)) +
qu->interim_allocd));
- qu->final_used= MEM_ROUND(sizeof(*ans));
+ qu->final_allocspace= (byte*)qu->answer + MEM_ROUND(sizeof(*ans));
adns__makefinal_str(qu,&ans->cname);
if (ans->nrrs) {
}
void adns__reset_cnameonly(adns_state ads, adns_query qu) {
+ assert(qu->final_allocspace);
qu->answer->nrrs= 0;
qu->answer->rrs= 0;
- qu->permalloclen= qu->answer->cname ? MEM_ROUND(strlen(qu->answer->cname)+1) : 0;
+ qu->interim_allocd= qu->answer->cname ? MEM_ROUND(strlen(qu->answer->cname)+1) : 0;
}
void adns__query_fail(adns_state ads, adns_query qu, adns_status stat) {
adns__reset_cnameonly(ads,qu);
qu->answer->status= stat;
- qu->answer->type= qu->type;
- adns__query_done(ads,qu,stat);
+ adns__query_done(ads,qu);
}
#include "internal.h"
void adns__vdiag(adns_state ads, const char *pfx, adns_initflags prevent,
- int serv, const char *fmt, va_list al) {
+ int serv, const char *fmt, adns_query qu, va_list al) {
+ const char *bef, *aft;
+ vbuf vb;
if (!(ads->iflags & adns_if_debug) && (!prevent || (ads->iflags & prevent))) return;
+
+ fprintf(stderr,"adns%s: ",pfx);
+
+ vfprintf(stderr,fmt,al);
+
+ bef= " (";
+ aft= "\n";
+
+ if (qu && qu->query_dgram) {
+ adns__vbuf_init(&vb);
+ fprintf(stderr,"%sQNAME=%s, QTYPE=%s",
+ bef,
+ adns__diag_domain(ads,-1,0,&vb,qu->query_dgram,qu->query_dglen,DNS_HDRSIZE),
+ qu->typei ? qu->typei->name : "<unknown>");
+ bef=", "; aft=")\n";
+ }
+
if (serv>=0) {
- fprintf(stderr,"adns%s: nameserver %s: ",pfx,inet_ntoa(ads->servers[serv].addr));
- } else {
- fprintf(stderr,"adns%s: ",pfx);
+ fprintf(stderr,"%sNS=%s",bef,inet_ntoa(ads->servers[serv].addr));
+ bef=", "; aft=")\n";
}
- vfprintf(stderr,fmt,al);
- fputc('\n',stderr);
+
+ fputs(aft,stderr);
}
-void adns__debug(adns_state ads, int serv, const char *fmt, ...) {
+void adns__debug(adns_state ads, int serv, adns_query qu, const char *fmt, ...) {
va_list al;
va_start(al,fmt);
- adns__vdiag(ads," debug",0,serv,fmt,al);
+ adns__vdiag(ads," debug",0,serv,qu,fmt,al);
va_end(al);
}
-void adns__warn(adns_state ads, int serv, const char *fmt, ...) {
+void adns__warn(adns_state ads, int serv, adns_query qu, const char *fmt, ...) {
va_list al;
va_start(al,fmt);
- adns__vdiag(ads," warning",adns_if_noerrprint|adns_if_noserverwarn,serv,fmt,al);
+ adns__vdiag(ads," warning",adns_if_noerrprint|adns_if_noserverwarn,serv,qu,fmt,al);
va_end(al);
}
-void adns__diag(adns_state ads, int serv, const char *fmt, ...) {
+void adns__diag(adns_state ads, int serv, adns_query qu, const char *fmt, ...) {
va_list al;
va_start(al,fmt);
- adns__vdiag(ads,"",adns_if_noerrprint,serv,fmt,al);
+ adns__vdiag(ads,"",adns_if_noerrprint,serv,qu,fmt,al);
va_end(al);
}
#include "internal.h"
int adns__internal_submit(adns_state ads, adns_query *query_r,
- adns_rrtype type, char *query_dgram, int query_len,
+ adns_rrtype type, vbuf *qumsg_vb, int id,
adns_queryflags flags, struct timeval now,
adns_status failstat, const qcontext *ctx) {
- /* Submits a query (for internal use, called during external submits).
- *
- * The new query is returned in *query_r, or we return adns_s_nomemory.
- *
- * The query datagram should already have been assembled; memory for it
- * is taken over by this routine whether it succeeds or fails.
- *
- * If failstat is nonzero then if we are successful in creating the query
- * it is immediately failed with code failstat (but _submit still succeds).
- *
- * ctx is copied byte-for-byte into the query.
- */
adns_query qu;
adns_status stat;
int ol, id, r;
const typeinfo *typei;
adns_query qu;
- id= ads->nextid++;
-
qu= malloc(sizeof(*qu)); if (!qu) goto x_nomemory;
qu->answer= malloc(sizeof(*qu->answer)); if (!qu->answer) goto x_freequ_nomemory;
qu->perm_used= 0;
qu->typei= adns__findtype(type);
- qu->query_dgram= query_dgram;
- qu->query_dglen= query_dglen;
adns__vbuf_init(&qu->vb);
qu->cname_dgram= 0;
qu->answer->nrrs= 0;
qu->answer->rrs= 0;
- *query_r= qu;
-
if (qu->typei) {
qu->answer->rrsz= qu->rrsz;
} else {
qu->answer->rrsz= -1;
failstat= adns_s_notimplemented;
}
+
+ *query_r= qu;
+
+ qu->query_dgram= malloc(qumsg_vb->used);
+ if (!qu->query_dgram) {
+ adns__query_fail(ads,qu,adns_s_nomemory);
+ return;
+ }
+ memcpy(qu->query_dgram,qumsg_vb->buf,qumsg_vb->used);
+ qu->vb= *qumsg_vb;
+ adns__vbuf_init(qumsg_vb);
+
if (failstat) {
adns__query_fail(ads,qu,failstat);
return;
}
-
adns__query_udp(ads,qu,now);
adns__autosys(ads,now);
void *context,
adns_query *query_r) {
qcontext ctx;
+ int id;
+ vbuf vb;
ctx.ext= context;
r= gettimeofday(&now,0); if (r) return errno;
+ id= 0;
+
+ adns__vbuf_init(&vb);
ol= strlen(owner);
- if (ol<=1 || ol>DNS_MAXDOMAIN+1)
- return failsubmit(ads,context,query_r,flags,id,adns_s_invaliddomain);
+ if (ol<=1 || ol>DNS_MAXDOMAIN+1) { stat= adns_s_invaliddomain; goto xit; }
+
if (owner[ol-1]=='.' && owner[ol-2]!='\\') { flags &= ~adns_qf_search; ol--; }
- stat= adns__mkquery(ads,owner,ol,id,typei,flags);
- if (stat) return failsubmit(ads,context,query_r,flags,id,stat);
-
- adns__internal_submit(ads,type,flags,now,query_r
+ stat= adns__mkquery(ads,&vb, &id, owner,ol, typei,flags);
+
+ xit:
+ return adns__internal_submit(ads,query_r, type,&vb,id, flags,now, stat,&ctx);
}
int adns_synchronous(adns_state ads,
abort(); /* fixme */
}
+void adns__makefinal_str(adns_query qu, char **strp) {
+ int l;
+ char *before, *after;
+
+ before= *strp;
+ l= strlen(before)+1;
+ after= adns__alloc_final(qu,l);
+ memcpy(after,before,l);
+ *strp= after;
+}
+
+void adns__makefinal_block(adns__query qu, void **blpp, size_t sz) {
+ void *after;
+
+ after= adns__alloc_final(qu,sz);
+ memcpy(after,*blpp,sz);
+ *blpp= after;
+}
+
void *adns__alloc_interim(adns_state ads, adns_query qu, size_t sz) {
allocnode *an;
+ assert(!qu->final_allocspace);
sz= MEM_ROUND(sz);
an= malloc(MEM_ROUND(MEM_ROUND(sizeof(*an)) + sz));
if (!an) {
qu->allocations= an;
return (byte*)an + MEM_ROUND(sizeof(*an));
}
+
+void *adns__alloc_final(adns_query qu, size_t sz) {
+ /* When we're in the _final stage, we _subtract_ from interim_alloc'd
+ * each allocation, and use final_allocspace to point to the next free
+ * bit.
+ */
+ void *rp;
+
+ sz= MEM_ROUND(sz);
+ rp= qu->final_allocspace;
+ assert(rp);
+ qu->interim_allocd -= sz;
+ assert(qu->interim_allocd>=0);
+ qu->final_allocspace= (byte*)rp + sz;
+ return rp;
+}
static const typeinfo typeinfos[] = {
/* Must be in ascending order of rrtype ! */
- /* rr type code style member size parser */
+ /* rr type code name style member size parser */
- { adns_r_a, TYPE_MN( inaddr, inaddr ) },
-#if 0 /*fixme*/
- { adns_r_ns_raw, TYPE_MF( str, domain_raw ) },
- { adns_r_cname, TYPE_MF( str, domain_raw ) },
- { adns_r_soa_raw, TYPE_MF( soa, soa ) },
- { adns_r_null, TYPE_SN( 0, null ) },
- { adns_r_ptr_raw, TYPE_MF( str, domain_raw ) },
- { adns_r_hinfo, TYPE_MF( strpair, hinfo ) },
- { adns_r_mx_raw, TYPE_MF( intstr, mx_raw ) },
- { adns_r_txt, TYPE_MF( str, txt ) },
- { adns_r_rp_raw, TYPE_MF( strpair, rp ) },
-
- { adns_r_ns, TYPE_MF( dmaddr, dmaddr ) },
- { adns_r_ptr, TYPE_MF( str, ptr ) },
- { adns_r_mx, TYPE_MF( intdmaddr, mx ) },
-
- { adns_r_soa, TYPE_MF( soa, soa ) },
- { adns_r_rp, TYPE_MF( strpair, rp ) },
+ { 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 ) },
#endif
};