ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

reply.c
Go to the documentation of this file.
00001 /*
00002  * reply.c
00003  * - main handling and parsing routine for received datagrams
00004  */
00005 /*
00006  *  This file is
00007  *    Copyright (C) 1997-2000 Ian Jackson <ian@davenant.greenend.org.uk>
00008  *
00009  *  It is part of adns, which is
00010  *    Copyright (C) 1997-2000 Ian Jackson <ian@davenant.greenend.org.uk>
00011  *    Copyright (C) 1999-2000 Tony Finch <dot@dotat.at>
00012  *
00013  *  This program is free software; you can redistribute it and/or modify
00014  *  it under the terms of the GNU General Public License as published by
00015  *  the Free Software Foundation; either version 2, or (at your option)
00016  *  any later version.
00017  *
00018  *  This program is distributed in the hope that it will be useful,
00019  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00020  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00021  *  GNU General Public License for more details.
00022  *
00023  *  You should have received a copy of the GNU General Public License
00024  *  along with this program; if not, write to the Free Software Foundation,
00025  *  Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00026  */
00027 
00028 #ifdef ADNS_JGAA_WIN32
00029 # include "adns_win32.h"
00030 #endif
00031 
00032 #include <stdlib.h>
00033 
00034 #include "internal.h"
00035 
00036 void adns__procdgram(adns_state ads, const byte *dgram, int dglen,
00037              int serv, int viatcp, struct timeval now) {
00038   int cbyte, rrstart, wantedrrs, rri, foundsoa, foundns, cname_here;
00039   int id, f1, f2, qdcount, ancount, nscount, arcount;
00040   int flg_ra, flg_rd, flg_tc, flg_qr, opcode;
00041   int rrtype, rrclass, rdlength, rdstart;
00042   int anstart, nsstart, arstart;
00043   int ownermatched, l, nrrs;
00044   unsigned long ttl, soattl;
00045   const typeinfo *typei;
00046   adns_query qu, nqu;
00047   dns_rcode rcode;
00048   adns_status st;
00049   vbuf tempvb;
00050   byte *newquery, *rrsdata;
00051   parseinfo pai;
00052 
00053   if (dglen<DNS_HDRSIZE) {
00054     adns__diag(ads,serv,0,"received datagram too short for message header (%d)",dglen);
00055     return;
00056   }
00057   cbyte= 0;
00058   GET_W(cbyte,id);
00059   GET_B(cbyte,f1);
00060   GET_B(cbyte,f2);
00061   GET_W(cbyte,qdcount);
00062   GET_W(cbyte,ancount);
00063   GET_W(cbyte,nscount);
00064   GET_W(cbyte,arcount);
00065   assert(cbyte == DNS_HDRSIZE);
00066 
00067   flg_qr= f1&0x80;
00068   opcode= (f1&0x78)>>3;
00069   flg_tc= f1&0x02;
00070   flg_rd= f1&0x01;
00071   flg_ra= f2&0x80;
00072   rcode= (f2&0x0f);
00073 
00074   cname_here= 0;
00075 
00076   if (!flg_qr) {
00077     adns__diag(ads,serv,0,"server sent us a query, not a response");
00078     return;
00079   }
00080   if (opcode) {
00081     adns__diag(ads,serv,0,"server sent us unknown opcode %d (wanted 0=QUERY)",opcode);
00082     return;
00083   }
00084 
00085   qu= 0;
00086   /* See if we can find the relevant query, or leave qu=0 otherwise ... */
00087 
00088   if (qdcount == 1) {
00089     for (qu= viatcp ? ads->tcpw.head : ads->udpw.head; qu; qu= nqu) {
00090       nqu= qu->next;
00091       if (qu->id != id) continue;
00092       if (dglen < qu->query_dglen) continue;
00093       if (memcmp(qu->query_dgram+DNS_HDRSIZE,
00094          dgram+DNS_HDRSIZE,
00095          (size_t) qu->query_dglen-DNS_HDRSIZE))
00096     continue;
00097       if (viatcp) {
00098     assert(qu->state == query_tcpw);
00099       } else {
00100     assert(qu->state == query_tosend);
00101     if (!(qu->udpsent & (1<<serv))) continue;
00102       }
00103       break;
00104     }
00105     if (qu) {
00106       /* We're definitely going to do something with this query now */
00107       if (viatcp) LIST_UNLINK(ads->tcpw,qu);
00108       else LIST_UNLINK(ads->udpw,qu);
00109     }
00110   }
00111 
00112   /* If we're going to ignore the packet, we return as soon as we have
00113    * failed the query (if any) and printed the warning message (if
00114    * any).
00115    */
00116   switch (rcode) {
00117   case rcode_noerror:
00118   case rcode_nxdomain:
00119     break;
00120   case rcode_formaterror:
00121     adns__warn(ads,serv,qu,"server cannot understand our query (Format Error)");
00122     if (qu) adns__query_fail(qu,adns_s_rcodeformaterror);
00123     return;
00124   case rcode_servfail:
00125     if (qu) adns__query_fail(qu,adns_s_rcodeservfail);
00126     else adns__debug(ads,serv,qu,"server failure on unidentifiable query");
00127     return;
00128   case rcode_notimp:
00129     adns__warn(ads,serv,qu,"server claims not to implement our query");
00130     if (qu) adns__query_fail(qu,adns_s_rcodenotimplemented);
00131     return;
00132   case rcode_refused:
00133     adns__debug(ads,serv,qu,"server refused our query");
00134     if (qu) adns__query_fail(qu,adns_s_rcoderefused);
00135     return;
00136   default:
00137     adns__warn(ads,serv,qu,"server gave unknown response code %d",rcode);
00138     if (qu) adns__query_fail(qu,adns_s_rcodeunknown);
00139     return;
00140   }
00141 
00142   if (!qu) {
00143     if (!qdcount) {
00144       adns__diag(ads,serv,0,"server sent reply without quoting our question");
00145     } else if (qdcount>1) {
00146       adns__diag(ads,serv,0,"server claimed to answer %d questions with one message",
00147          qdcount);
00148     } else if (ads->iflags & adns_if_debug) {
00149       adns__vbuf_init(&tempvb);
00150       adns__debug(ads,serv,0,"reply not found, id %02x, query owner %s",
00151           id, adns__diag_domain(ads,serv,0,&tempvb,dgram,dglen,DNS_HDRSIZE));
00152       adns__vbuf_free(&tempvb);
00153     }
00154     return;
00155   }
00156 
00157   /* We're definitely going to do something with this packet and this query now. */
00158 
00159   anstart= qu->query_dglen;
00160   arstart= -1;
00161 
00162   /* Now, take a look at the answer section, and see if it is complete.
00163    * If it has any CNAMEs we stuff them in the answer.
00164    */
00165   wantedrrs= 0;
00166   cbyte= anstart;
00167   for (rri= 0; rri<ancount; rri++) {
00168     rrstart= cbyte;
00169     st= adns__findrr(qu,serv, dgram,dglen,&cbyte,
00170              &rrtype,&rrclass,&ttl, &rdlength,&rdstart,
00171              &ownermatched);
00172     if (st) { adns__query_fail(qu,st); return; }
00173     if (rrtype == -1) goto x_truncated;
00174 
00175     if (rrclass != DNS_CLASS_IN) {
00176       adns__diag(ads,serv,qu,"ignoring answer RR with wrong class %d (expected IN=%d)",
00177          rrclass,DNS_CLASS_IN);
00178       continue;
00179     }
00180     if (!ownermatched) {
00181       if (ads->iflags & adns_if_debug) {
00182     adns__debug(ads,serv,qu,"ignoring RR with an unexpected owner %s",
00183             adns__diag_domain(ads,serv,qu, &qu->vb, dgram,dglen,rrstart));
00184       }
00185       continue;
00186     }
00187     if (rrtype == adns_r_cname &&
00188     (qu->typei->type & adns__rrt_typemask) != adns_r_cname) {
00189       if (qu->flags & adns_qf_cname_forbid) {
00190     adns__query_fail(qu,adns_s_prohibitedcname);
00191     return;
00192       } else if (qu->cname_dgram) { /* Ignore second and subsequent CNAME(s) */
00193     adns__debug(ads,serv,qu,"allegedly canonical name %s is actually alias for %s",
00194             qu->answer->cname,
00195             adns__diag_domain(ads,serv,qu, &qu->vb, dgram,dglen,rdstart));
00196     adns__query_fail(qu,adns_s_prohibitedcname);
00197     return;
00198       } else if (wantedrrs) { /* Ignore CNAME(s) after RR(s). */
00199     adns__debug(ads,serv,qu,"ignoring CNAME (to %s) coexisting with RR",
00200             adns__diag_domain(ads,serv,qu, &qu->vb, dgram,dglen,rdstart));
00201       } else {
00202     qu->cname_begin= rdstart;
00203     qu->cname_dglen= dglen;
00204     st= adns__parse_domain(ads,serv,qu, &qu->vb,
00205                    qu->flags & adns_qf_quotefail_cname ? 0 : pdf_quoteok,
00206                    dgram,dglen, &rdstart,rdstart+rdlength);
00207     if (!qu->vb.used) goto x_truncated;
00208     if (st) { adns__query_fail(qu,st); return; }
00209     l= strlen((char*)qu->vb.buf)+1;
00210     qu->answer->cname= adns__alloc_preserved(qu,(size_t) l);
00211     if (!qu->answer->cname) { adns__query_fail(qu,adns_s_nomemory); return; }
00212 
00213     qu->cname_dgram= adns__alloc_mine(qu, (size_t) dglen);
00214     memcpy(qu->cname_dgram,dgram,(size_t) dglen);
00215 
00216     memcpy(qu->answer->cname,qu->vb.buf, (size_t) l);
00217     cname_here= 1;
00218     adns__update_expires(qu,ttl,now);
00219     /* If we find the answer section truncated after this point we restart
00220      * the query at the CNAME; if beforehand then we obviously have to use
00221      * TCP.  If there is no truncation we can use the whole answer if
00222      * it contains the relevant info.
00223      */
00224       }
00225     } else if (rrtype == ((INT)qu->typei->type & (INT)adns__rrt_typemask)) {
00226       wantedrrs++;
00227     } else {
00228       adns__debug(ads,serv,qu,"ignoring answer RR with irrelevant type %d",rrtype);
00229     }
00230   }
00231 
00232   /* We defer handling truncated responses here, in case there was a CNAME
00233    * which we could use.
00234    */
00235   if (flg_tc) goto x_truncated;
00236 
00237   nsstart= cbyte;
00238 
00239   if (!wantedrrs) {
00240     /* Oops, NODATA or NXDOMAIN or perhaps a referral (which would be a problem) */
00241 
00242     /* RFC2308: NODATA has _either_ a SOA _or_ _no_ NS records in authority section */
00243     foundsoa= 0; soattl= 0; foundns= 0;
00244     for (rri= 0; rri<nscount; rri++) {
00245       rrstart= cbyte;
00246       st= adns__findrr(qu,serv, dgram,dglen,&cbyte,
00247                &rrtype,&rrclass,&ttl, &rdlength,&rdstart, 0);
00248       if (st) { adns__query_fail(qu,st); return; }
00249       if (rrtype==-1) goto x_truncated;
00250       if (rrclass != DNS_CLASS_IN) {
00251     adns__diag(ads,serv,qu,
00252            "ignoring authority RR with wrong class %d (expected IN=%d)",
00253            rrclass,DNS_CLASS_IN);
00254     continue;
00255       }
00256       if (rrtype == adns_r_soa_raw) { foundsoa= 1; soattl= ttl; break; }
00257       else if (rrtype == adns_r_ns_raw) { foundns= 1; }
00258     }
00259 
00260     if (rcode == rcode_nxdomain) {
00261       /* We still wanted to look for the SOA so we could find the TTL. */
00262       adns__update_expires(qu,soattl,now);
00263 
00264       if (qu->flags & adns_qf_search) {
00265     adns__search_next(ads,qu,now);
00266       } else {
00267     adns__query_fail(qu,adns_s_nxdomain);
00268       }
00269       return;
00270     }
00271 
00272     if (foundsoa || !foundns) {
00273       /* Aha !  A NODATA response, good. */
00274       adns__update_expires(qu,soattl,now);
00275       adns__query_fail(qu,adns_s_nodata);
00276       return;
00277     }
00278 
00279     /* Now what ?  No relevant answers, no SOA, and at least some NS's.
00280      * Looks like a referral.  Just one last chance ... if we came across
00281      * a CNAME in this datagram then we should probably do our own CNAME
00282      * lookup now in the hope that we won't get a referral again.
00283      */
00284     if (cname_here) goto x_restartquery;
00285 
00286     /* Bloody hell, I thought we asked for recursion ? */
00287     if (!flg_ra) {
00288       adns__diag(ads,serv,qu,"server is not willing to do recursive lookups for us");
00289       adns__query_fail(qu,adns_s_norecurse);
00290     } else {
00291       if (!flg_rd)
00292     adns__diag(ads,serv,qu,"server thinks we didn't ask for recursive lookup");
00293       else
00294     adns__debug(ads,serv,qu,"server claims to do recursion, but gave us a referral");
00295       adns__query_fail(qu,adns_s_invalidresponse);
00296     }
00297     return;
00298   }
00299 
00300   /* Now, we have some RRs which we wanted. */
00301 
00302   qu->answer->rrs.untyped= adns__alloc_interim(qu,(size_t) qu->typei->rrsz*wantedrrs);
00303   if (!qu->answer->rrs.untyped) { adns__query_fail(qu,adns_s_nomemory); return; }
00304 
00305   typei= qu->typei;
00306   cbyte= anstart;
00307   rrsdata= qu->answer->rrs.bytes;
00308 
00309   pai.ads= qu->ads;
00310   pai.qu= qu;
00311   pai.serv= serv;
00312   pai.dgram= dgram;
00313   pai.dglen= dglen;
00314   pai.nsstart= nsstart;
00315   pai.nscount= nscount;
00316   pai.arcount= arcount;
00317   pai.now= now;
00318 
00319   for (rri=0, nrrs=0; rri<ancount; rri++) {
00320     st= adns__findrr(qu,serv, dgram,dglen,&cbyte,
00321              &rrtype,&rrclass,&ttl, &rdlength,&rdstart,
00322              &ownermatched);
00323     assert(!st); assert(rrtype != -1);
00324     if (rrclass != DNS_CLASS_IN ||
00325     rrtype != ((INT)qu->typei->type & (INT)adns__rrt_typemask) ||
00326     !ownermatched)
00327       continue;
00328     adns__update_expires(qu,ttl,now);
00329     st= typei->parse(&pai, rdstart,rdstart+rdlength, rrsdata+nrrs*typei->rrsz);
00330     if (st) { adns__query_fail(qu,st); return; }
00331     if (rdstart==-1) goto x_truncated;
00332     nrrs++;
00333   }
00334   assert(nrrs==wantedrrs);
00335   qu->answer->nrrs= nrrs;
00336 
00337   /* This may have generated some child queries ... */
00338   if (qu->children.head) {
00339     qu->state= query_childw;
00340     LIST_LINK_TAIL(ads->childw,qu);
00341     return;
00342   }
00343   adns__query_done(qu);
00344   return;
00345 
00346  x_truncated:
00347 
00348   if (!flg_tc) {
00349     adns__diag(ads,serv,qu,"server sent datagram which points outside itself");
00350     adns__query_fail(qu,adns_s_invalidresponse);
00351     return;
00352   }
00353   qu->flags |= adns_qf_usevc;
00354 
00355  x_restartquery:
00356   if (qu->cname_dgram) {
00357     st= adns__mkquery_frdgram(qu->ads,&qu->vb,&qu->id,
00358                   qu->cname_dgram, qu->cname_dglen, qu->cname_begin,
00359                   qu->typei->type, qu->flags);
00360     if (st) { adns__query_fail(qu,st); return; }
00361 
00362     newquery= realloc(qu->query_dgram, (size_t) qu->vb.used);
00363     if (!newquery) { adns__query_fail(qu,adns_s_nomemory); return; }
00364 
00365     qu->query_dgram= newquery;
00366     qu->query_dglen= qu->vb.used;
00367     memcpy(newquery,qu->vb.buf, (size_t) qu->vb.used);
00368   }
00369 
00370   if (qu->state == query_tcpw) qu->state= query_tosend;
00371   qu->retries= 0;
00372   adns__reset_preserved(qu);
00373   adns__query_send(qu,now);
00374 }

Generated on Mon May 28 2012 04:33:20 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.