*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
#include "internal.h"
void adns__procdgram(adns_state ads, const byte *dgram, int dglen,
#include "internal.h"
void adns__procdgram(adns_state ads, const byte *dgram, int dglen,
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;
int anstart, nsstart, arstart;
int ownermatched, l, nrrs;
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;
int anstart, nsstart, arstart;
int ownermatched, l, nrrs;
if (dglen<DNS_HDRSIZE) {
adns__diag(ads,serv,0,"received datagram too short for message header (%d)",dglen);
if (dglen<DNS_HDRSIZE) {
adns__diag(ads,serv,0,"received datagram too short for message header (%d)",dglen);
break;
case rcode_formaterror:
adns__warn(ads,serv,qu,"server cannot understand our query (Format Error)");
break;
case rcode_formaterror:
adns__warn(ads,serv,qu,"server cannot understand our query (Format Error)");
return;
case rcode_notimp:
adns__warn(ads,serv,qu,"server claims not to implement our query");
return;
case rcode_notimp:
adns__warn(ads,serv,qu,"server claims not to implement our query");
return;
case rcode_refused:
adns__warn(ads,serv,qu,"server refused our query");
return;
case rcode_refused:
adns__warn(ads,serv,qu,"server refused our query");
return;
default:
adns__warn(ads,serv,qu,"server gave unknown response code %d",rcode);
return;
default:
adns__warn(ads,serv,qu,"server gave unknown response code %d",rcode);
for (rri= 0; rri<ancount; rri++) {
rrstart= cbyte;
st= adns__findrr(qu,serv, dgram,dglen,&cbyte,
for (rri= 0; rri<ancount; rri++) {
rrstart= cbyte;
st= adns__findrr(qu,serv, dgram,dglen,&cbyte,
- &rrtype,&rrclass,&rdlength,&rdstart,
+ &rrtype,&rrclass,&ttl, &rdlength,&rdstart,
&ownermatched);
if (st) { adns__query_fail(qu,st); return; }
if (rrtype == -1) goto x_truncated;
&ownermatched);
if (st) { adns__query_fail(qu,st); return; }
if (rrtype == -1) goto x_truncated;
- if (!qu->cname_dgram) { /* Ignore second and subsequent CNAMEs */
+ if (qu->flags & adns_qf_cname_forbid) {
+ adns__query_fail(qu,adns_s_prohibitedcname);
+ return;
+ } else if (!qu->cname_dgram) { /* Ignore second and subsequent CNAMEs */
qu->cname_begin= rdstart;
qu->cname_dglen= dglen;
st= adns__parse_domain(ads,serv,qu, &qu->vb,
qu->cname_begin= rdstart;
qu->cname_dglen= dglen;
st= adns__parse_domain(ads,serv,qu, &qu->vb,
if (!qu->vb.used) goto x_truncated;
if (st) { adns__query_fail(qu,st); return; }
l= strlen(qu->vb.buf)+1;
if (!qu->vb.used) goto x_truncated;
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) { adns__query_fail(qu,adns_s_nolocalmem); return; }
+ qu->answer->cname= adns__alloc_preserved(qu,l);
+ if (!qu->answer->cname) { adns__query_fail(qu,adns_s_nomemory); 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;
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
* 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
/* 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
for (rri= 0; rri<nscount; rri++) {
rrstart= cbyte;
st= adns__findrr(qu,serv, dgram,dglen,&cbyte,
for (rri= 0; rri<nscount; rri++) {
rrstart= cbyte;
st= adns__findrr(qu,serv, dgram,dglen,&cbyte,
- &rrtype,&rrclass,&rdlength,&rdstart, 0);
+ &rrtype,&rrclass,&ttl, &rdlength,&rdstart, 0);
if (st) { adns__query_fail(qu,st); return; }
if (rrtype==-1) goto x_truncated;
if (rrclass != DNS_CLASS_IN) {
if (st) { adns__query_fail(qu,st); return; }
if (rrtype==-1) goto x_truncated;
if (rrclass != DNS_CLASS_IN) {
+
+ if (rcode == rcode_nxdomain) {
+ /* We still wanted to look for the SOA so we could find the TTL. */
+ adns__update_expires(qu,soattl,now);
+
+ if (qu->flags & adns_qf_search) {
+ adns__search_next(ads,qu,now);
+ } else {
+ adns__query_fail(qu,adns_s_nxdomain);
+ }
+ return;
+ }
if (foundsoa || !foundns) {
/* Aha ! A NODATA response, good. */
if (foundsoa || !foundns) {
/* Aha ! A NODATA response, good. */
adns__query_fail(qu,adns_s_norecurse);
} else {
adns__diag(ads,serv,qu,"server claims to do recursion, but gave us a referral");
adns__query_fail(qu,adns_s_norecurse);
} else {
adns__diag(ads,serv,qu,"server claims to do recursion, but gave us a referral");
/* Now, we have some RRs which we wanted. */
qu->answer->rrs.untyped= adns__alloc_interim(qu,qu->typei->rrsz*wantedrrs);
/* Now, we have some RRs which we wanted. */
qu->answer->rrs.untyped= adns__alloc_interim(qu,qu->typei->rrsz*wantedrrs);
st= adns__findrr(qu,serv, dgram,dglen,&cbyte,
st= adns__findrr(qu,serv, dgram,dglen,&cbyte,
- &rrtype,&rrclass,&rdlength,&rdstart,
+ &rrtype,&rrclass,&ttl, &rdlength,&rdstart,
&ownermatched);
assert(!st); assert(rrtype != -1);
if (rrclass != DNS_CLASS_IN ||
rrtype != (qu->typei->type & adns__rrt_typemask) ||
!ownermatched)
continue;
&ownermatched);
assert(!st); assert(rrtype != -1);
if (rrclass != DNS_CLASS_IN ||
rrtype != (qu->typei->type & adns__rrt_typemask) ||
!ownermatched)
continue;
- st= typei->parse(qu,serv, dgram,dglen, rdstart,rdstart+rdlength,
- nsstart,&arstart, rrsdata+nrrs*typei->rrsz);
+ adns__update_expires(qu,ttl,now);
+ st= typei->parse(&pai, rdstart,rdstart+rdlength, rrsdata+nrrs*typei->rrsz);
if (st) { adns__query_fail(qu,st); return; }
if (rdstart==-1) goto x_truncated;
nrrs++;
if (st) { adns__query_fail(qu,st); return; }
if (rdstart==-1) goto x_truncated;
nrrs++;
if (!flg_tc) {
adns__diag(ads,serv,qu,"server sent datagram which points outside itself");
if (!flg_tc) {
adns__diag(ads,serv,qu,"server sent datagram which points outside itself");
if (qu->cname_dgram) {
st= adns__mkquery_frdgram(qu->ads,&qu->vb,&qu->id,
qu->cname_dgram, qu->cname_dglen, qu->cname_begin,
if (qu->cname_dgram) {
st= adns__mkquery_frdgram(qu->ads,&qu->vb,&qu->id,
qu->cname_dgram, qu->cname_dglen, qu->cname_begin,
if (st) { adns__query_fail(qu,st); return; }
newquery= realloc(qu->query_dgram,qu->vb.used);
if (st) { adns__query_fail(qu,st); return; }
newquery= realloc(qu->query_dgram,qu->vb.used);
qu->query_dgram= newquery;
qu->query_dglen= qu->vb.used;
memcpy(newquery,qu->vb.buf,qu->vb.used);
}
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);
+ if (qu->state == query_tcpsent) qu->state= query_tosend;
+ adns__reset_preserved(qu);
+ adns__query_send(qu,now);