X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=adns.git;a=blobdiff_plain;f=src%2Freply.c;h=0379ca441ff52f90feefdce6cf3dc333c7b808a7;hp=fbafb82e646a3c3d502a07cd064e4096c631faa0;hb=fcf2b4e1faf22accb6184cca595aaee602839868;hpb=3d5cde09d167be1609d27d0d93de2096250a310c diff --git a/src/reply.c b/src/reply.c index fbafb82..0379ca4 100644 --- a/src/reply.c +++ b/src/reply.c @@ -3,16 +3,16 @@ * - main handling and parsing routine for received datagrams */ /* - * This file is - * Copyright (C) 1997-2000 Ian Jackson - * - * It is part of adns, which is - * Copyright (C) 1997-2000 Ian Jackson - * Copyright (C) 1999 Tony Finch + * This file is part of adns, which is + * Copyright (C) 1997-2000,2003,2006,2014-2016 Ian Jackson + * Copyright (C) 2014 Mark Wooding + * Copyright (C) 1999-2000,2003,2006 Tony Finch + * Copyright (C) 1991 Massachusetts Institute of Technology + * (See the file INSTALL for full details.) * * 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 - * the Free Software Foundation; either version 2, or (at your option) + * the Free Software Foundation; either version 3, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, @@ -21,8 +21,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * along with this program; if not, write to the Free Software Foundation. */ #include @@ -35,8 +34,8 @@ void adns__procdgram(adns_state ads, const byte *dgram, int dglen, 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 anstart, nsstart; + int ownermatched, l, nrrs, restartfrom; unsigned long ttl, soattl; const typeinfo *typei; adns_query qu, nqu; @@ -47,7 +46,8 @@ void adns__procdgram(adns_state ads, const byte *dgram, int dglen, parseinfo pai; if (dglen1) { - adns__diag(ads,serv,0,"server claimed to answer %d questions with one message", - qdcount); + adns__diag(ads,serv,0,"server claimed to answer %d" + " questions with one message", qdcount); } else if (ads->iflags & adns_if_debug) { adns__vbuf_init(&tempvb); adns__debug(ads,serv,0,"reply not found, id %02x, query owner %s", - id, adns__diag_domain(ads,serv,0,&tempvb,dgram,dglen,DNS_HDRSIZE)); + id, adns__diag_domain(ads,serv,0,&tempvb, + dgram,dglen,DNS_HDRSIZE)); adns__vbuf_free(&tempvb); } return; } - /* We're definitely going to do something with this packet and this query now. */ + /* We're definitely going to do something with this packet and this + * query now. */ anstart= qu->query_dglen; - arstart= -1; /* Now, take a look at the answer section, and see if it is complete. * If it has any CNAMEs we stuff them in the answer. */ wantedrrs= 0; + restartfrom= -1; cbyte= anstart; for (rri= 0; rriiflags & adns_if_debug) { adns__debug(ads,serv,qu,"ignoring RR with an unexpected owner %s", - adns__diag_domain(ads,serv,qu, &qu->vb, dgram,dglen,rrstart)); + adns__diag_domain(ads,serv,qu, &qu->vb, + dgram,dglen,rrstart)); } continue; } if (rrtype == adns_r_cname && - (qu->typei->type & adns__rrt_typemask) != adns_r_cname) { + (qu->answer->type & adns_rrt_typemask) != adns_r_cname) { if (qu->flags & adns_qf_cname_forbid) { adns__query_fail(qu,adns_s_prohibitedcname); return; } else if (qu->cname_dgram) { /* Ignore second and subsequent CNAME(s) */ - adns__debug(ads,serv,qu,"allegedly canonical name %s is actually alias for %s", - qu->answer->cname, - adns__diag_domain(ads,serv,qu, &qu->vb, dgram,dglen,rdstart)); + adns__debug(ads,serv,qu,"allegedly canonical name %s" + " is actually alias for %s", qu->answer->cname, + adns__diag_domain(ads,serv,qu, &qu->vb, + dgram,dglen,rdstart)); adns__query_fail(qu,adns_s_prohibitedcname); return; } else if (wantedrrs) { /* Ignore CNAME(s) after RR(s). */ adns__debug(ads,serv,qu,"ignoring CNAME (to %s) coexisting with RR", - adns__diag_domain(ads,serv,qu, &qu->vb, dgram,dglen,rdstart)); + adns__diag_domain(ads,serv,qu, &qu->vb, + dgram,dglen,rdstart)); } else { qu->cname_begin= rdstart; qu->cname_dglen= dglen; st= adns__parse_domain(ads,serv,qu, &qu->vb, - qu->flags & adns_qf_quotefail_cname ? 0 : pdf_quoteok, + qu->flags & adns_qf_quotefail_cname + ? 0 : pdf_quoteok, dgram,dglen, &rdstart,rdstart+rdlength); 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_preserved(qu,l); - if (!qu->answer->cname) { adns__query_fail(qu,adns_s_nomemory); return; } + 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); @@ -218,10 +229,12 @@ void adns__procdgram(adns_state ads, const byte *dgram, int dglen, * it contains the relevant info. */ } - } else if (rrtype == (qu->typei->type & adns__rrt_typemask)) { + } else if (rrtype == (qu->answer->type & adns_rrt_typemask)) { + if (restartfrom==-1) restartfrom= rri; wantedrrs++; } else { - adns__debug(ads,serv,qu,"ignoring answer RR with irrelevant type %d",rrtype); + adns__debug(ads,serv,qu,"ignoring answer RR" + " with irrelevant type %d",rrtype); } } @@ -233,9 +246,11 @@ void adns__procdgram(adns_state ads, const byte *dgram, int dglen, nsstart= cbyte; if (!wantedrrs) { - /* Oops, NODATA or NXDOMAIN or perhaps a referral (which would be a problem) */ + /* Oops, NODATA or NXDOMAIN or perhaps a referral + * (which would be a problem) */ - /* RFC2308: NODATA has _either_ a SOA _or_ _no_ NS records in authority section */ + /* RFC2308: NODATA has _either_ a SOA _or_ _no_ NS records + * in authority section */ foundsoa= 0; soattl= 0; foundns= 0; for (rri= 0; rriflags & adns_qf_search) { + if (qu->flags & adns_qf_search && !qu->cname_dgram) { adns__search_next(ads,qu,now); } else { adns__query_fail(qu,adns_s_nxdomain); @@ -281,13 +296,16 @@ void adns__procdgram(adns_state ads, const byte *dgram, int dglen, /* Bloody hell, I thought we asked for recursion ? */ if (!flg_ra) { - adns__diag(ads,serv,qu,"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(qu,adns_s_norecurse); } else { if (!flg_rd) - adns__diag(ads,serv,qu,"server thinks we didn't ask for recursive lookup"); + adns__diag(ads,serv,qu,"server thinks" + " we didn't ask for recursive lookup"); else - adns__diag(ads,serv,qu,"server claims to do recursion, but gave us a referral"); + adns__debug(ads,serv,qu,"server claims to do recursion," + " but gave us a referral"); adns__query_fail(qu,adns_s_invalidresponse); } return; @@ -295,8 +313,11 @@ void adns__procdgram(adns_state ads, const byte *dgram, int dglen, /* 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) { adns__query_fail(qu,adns_s_nomemory); return; } + qu->answer->rrs.untyped= adns__alloc_interim(qu,qu->answer->rrsz*wantedrrs); + if (!qu->answer->rrs.untyped) { + adns__query_fail(qu,adns_s_nomemory); + return; + } typei= qu->typei; cbyte= anstart; @@ -312,17 +333,20 @@ void adns__procdgram(adns_state ads, const byte *dgram, int dglen, pai.arcount= arcount; pai.now= now; + assert(restartfrom>=0); for (rri=0, nrrs=0; rritypei->type & adns__rrt_typemask) || + if (rri < restartfrom || + rrclass != DNS_CLASS_IN || + rrtype != (qu->answer->type & adns_rrt_typemask) || !ownermatched) continue; adns__update_expires(qu,ttl,now); - st= typei->parse(&pai, rdstart,rdstart+rdlength, rrsdata+nrrs*typei->rrsz); + st= typei->parse(&pai, rdstart,rdstart+rdlength, + rrsdata+nrrs*qu->answer->rrsz); if (st) { adns__query_fail(qu,st); return; } if (rdstart==-1) goto x_truncated; nrrs++; @@ -351,8 +375,8 @@ void adns__procdgram(adns_state ads, const byte *dgram, int dglen, 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); + qu->cname_dgram,qu->cname_dglen,qu->cname_begin, + qu->answer->type, qu->flags); if (st) { adns__query_fail(qu,st); return; } newquery= realloc(qu->query_dgram,qu->vb.used);