Changeset 1232

Show
Ignore:
Timestamp:
07/13/08 22:21:54 (20 months ago)
Author:
ahu
Message:

implement EDNS NSID call (RFC 5001), plus an experimental EDNS option ('ping')

Location:
trunk/pdns/pdns
Files:
12 modified

Legend:

Unmodified
Added
Removed
  • trunk/pdns/pdns/common_startup.cc

    r1217 r1232  
    105105  ::arg().set("query-cache-ttl","Seconds to store packets in the PacketCache")="20"; 
    106106  ::arg().set("soa-minimum-ttl","Default SOA mininum ttl")="3600"; 
    107  
     107  ::arg().set("server-id", "Returned when queried for 'server.id' TXT or NSID, defaults to hostname")=""; 
    108108  ::arg().set("soa-refresh-default","Default SOA refresh")="10800"; 
    109109  ::arg().set("soa-retry-default","Default SOA retry")="3600"; 
     
    123123  ::arg().set("max-cache-entries", "Maximum number of cache entries")="1000000"; 
    124124} 
    125  
    126  
    127125 
    128126void declareStats(void) 
     
    242240    S.ringAccount("remotes",P->getRemote()); 
    243241 
    244     if((P->d.opcode != Opcode::Notify) && PC.get(P,&cached)) { // short circuit - does the PacketCache recognize this question? 
     242    if((P->d.opcode != Opcode::Notify) && P->couldBeCached() && PC.get(P,&cached)) { // short circuit - does the PacketCache recognize this question? 
    245243      cached.setRemote(&P->remote);  // inlined 
    246244      cached.setSocket(P->getSocket());                               // inlined 
  • trunk/pdns/pdns/dnspacket.cc

    r1138 r1232  
    3939#include "dnswriter.hh" 
    4040#include "dnsparser.hh" 
     41#include "dnsrecords.hh" 
    4142 
    4243DNSPacket::DNSPacket()  
     
    4546  d_compress=true; 
    4647  d_tcp=false; 
     48  d_wantsnsid=false; 
    4749} 
    4850 
     
    8991  qdomain=orig.qdomain; 
    9092  d_maxreplylen = orig.d_maxreplylen; 
     93  d_ednsping = orig.d_ednsping; 
     94  d_wantsnsid = orig.d_wantsnsid; 
    9195  rrs=orig.rrs; 
    9296 
     
    264268} 
    265269 
     270bool DNSPacket::couldBeCached() 
     271{ 
     272  return d_ednsping.empty() && !d_wantsnsid; 
     273} 
     274 
    266275/** Must be called before attempting to access getData(). This function stuffs all resource 
    267276 *  records found in rrs into the data buffer. It also frees resource records queued for us. 
     
    305314  pw.getHeader()->rd=d.rd; 
    306315 
    307   if(!rrs.empty()) { 
     316  DNSPacketWriter::optvect_t opts; 
     317  if(d_wantsnsid) { 
     318    opts.push_back(make_pair(3, ::arg()["server-id"])); 
     319  } 
     320 
     321  if(!d_ednsping.empty()) { 
     322    opts.push_back(make_pair(4, d_ednsping)); 
     323  } 
     324 
     325  if(!rrs.empty() || !opts.empty()) { 
    308326    try { 
    309327      for(pos=rrs.begin(); pos < rrs.end(); ++pos) { 
     
    321339        drc->toPacket(pw); 
    322340      } 
     341      if(!opts.empty()) 
     342        pw.addOpt(2800, 0, 0, opts); 
     343 
    323344      pw.commit(); 
    324345    } 
     
    384405  r->qtype = qtype; 
    385406  r->d_maxreplylen = d_maxreplylen; 
     407  r->d_ednsping = d_ednsping; 
     408  r->d_wantsnsid = d_wantsnsid; 
    386409  return r; 
    387410} 
     
    403426{ 
    404427  stringbuffer.assign(mesg,length);  
    405  
     428   
    406429  len=length; 
    407430  if(length < 12) {  
     
    410433    return -1; 
    411434  } 
     435 
    412436  MOADNSParser mdp(stringbuffer); 
    413   MOADNSParser::EDNSOpts edo; 
    414   if(mdp.getEDNSOpts(&edo)) { 
     437  EDNSOpts edo; 
     438 
     439  // ANY OPTION WHICH *MIGHT* BE SET DOWN BELOW SHOULD BE CLEARED FIRST! 
     440 
     441  d_wantsnsid=false; 
     442  d_ednsping.clear(); 
     443 
     444  if(getEDNSOpts(mdp, &edo)) { 
    415445    d_maxreplylen=edo.d_packetsize; 
    416   } 
    417   else 
     446 
     447    for(vector<pair<uint16_t, string> >::const_iterator iter = edo.d_options.begin(); 
     448        iter != edo.d_options.end();  
     449        ++iter) { 
     450      if(iter->first == 3) {// 'EDNS NSID' 
     451        d_wantsnsid=1; 
     452      } 
     453      else if(iter->first == 4) {// 'EDNS PING' 
     454        d_ednsping = iter->second; 
     455      } 
     456      else 
     457        ; // cerr<<"Have an option #"<<iter->first<<endl; 
     458    } 
     459  } 
     460  else  { 
    418461    d_maxreplylen=512; 
     462  } 
    419463 
    420464  memcpy((void *)&d,(const void *)stringbuffer.c_str(),12); 
  • trunk/pdns/pdns/dnspacket.hh

    r1123 r1232  
    140140  void commitD(); //!< copies 'd' into the stringbuffer 
    141141  int getMaxReplyLen(); //!< retrieve the maximum length of the packet we should send in response 
     142 
     143  bool couldBeCached(); //!< returns 0 if this query should bypass the packet cache 
     144 
    142145  //////// DATA ! 
    143146 
     
    163166  string stringbuffer; // this is where everything lives 4 
    164167  int d_maxreplylen; 
     168  string d_ednsping; 
     169  bool d_wantsnsid; 
    165170  vector<DNSResourceRecord> rrs; // 4 
    166171}; 
  • trunk/pdns/pdns/dnsparser.cc

    r1166 r1232  
    133133                                               PacketReader& pr) 
    134134{ 
    135   typemap_t::const_iterator i=getTypemap().find(make_pair(dr.d_class, dr.d_type)); 
     135  uint16_t searchclass = (dr.d_type == QType::OPT) ? 1 : dr.d_class; // class is invalid for OPT 
     136 
     137  typemap_t::const_iterator i=getTypemap().find(make_pair(searchclass, dr.d_type)); 
    136138  if(i==getTypemap().end() || !i->second) { 
    137139    return new UnknownRecordContent(dr, pr); 
     
    258260} 
    259261 
    260 bool MOADNSParser::getEDNSOpts(EDNSOpts* eo) 
    261 { 
    262   if(d_header.arcount && !d_answers.empty() && d_answers.back().first.d_type == QType::OPT) { 
    263     eo->d_packetsize=d_answers.back().first.d_class; 
    264  
    265     EDNS0Record stuff; 
    266     uint32_t ttl=ntohl(d_answers.back().first.d_ttl); 
    267     memcpy(&stuff, &ttl, sizeof(stuff)); 
    268  
    269     eo->d_extRCode=stuff.extRCode; 
    270     eo->d_version=stuff.version; 
    271     eo->d_Z=stuff.Z; 
    272  
    273     return true; 
    274   } 
    275   else 
    276     return false; 
    277 } 
    278262 
    279263void PacketReader::getDnsrecordheader(struct dnsrecordheader &ah) 
     
    448432void PacketReader::xfrBlob(string& blob) 
    449433{ 
    450   blob.assign(&d_content.at(d_pos), &d_content.at(d_startrecordpos + d_recordlen - 1 ) + 1); 
     434  if(d_recordlen) 
     435    blob.assign(&d_content.at(d_pos), &d_content.at(d_startrecordpos + d_recordlen - 1 ) + 1); 
     436  else 
     437    blob.clear(); 
    451438 
    452439  d_pos = d_startrecordpos + d_recordlen; 
  • trunk/pdns/pdns/dnsparser.hh

    r1100 r1232  
    299299  } 
    300300 
    301   struct EDNSOpts 
    302   { 
    303     uint16_t d_packetsize; 
    304     uint8_t d_extRCode, d_version; 
    305     uint16_t d_Z; 
    306   }; 
    307  
    308   //! Convenience function that fills out EDNS0 options, and returns true if there are any 
    309   bool getEDNSOpts(EDNSOpts* eo); 
    310  
     301   
    311302private: 
    312303  void getDnsrecordheader(struct dnsrecordheader &ah); 
  • trunk/pdns/pdns/dnsrecords.cc

    r1168 r1232  
    188188 
    189189 
    190 boilerplate_conv(OPT, ns_t_opt, 
    191                  conv.xfrText(d_data) 
     190boilerplate_conv(OPT, ns_t_opt,  
     191                   conv.xfrBlob(d_data) 
    192192                 ); 
    193193 
     194void OPTRecordContent::getData(vector<pair<uint16_t, string> >& options) 
     195{ 
     196  string::size_type pos=0; 
     197  uint16_t code, len; 
     198  while(d_data.size() >= 4 + pos) { 
     199    code = 0xff * d_data[pos] + d_data[pos+1]; 
     200    len = 0xff * d_data[pos+2] + d_data[pos+3]; 
     201    pos+=4; 
     202 
     203    if(pos + len > d_data.size()) 
     204      break; 
     205 
     206    string field(d_data.c_str() + pos, len); 
     207    pos+=len; 
     208 
     209    options.push_back(make_pair(code, field)); 
     210  } 
     211} 
    194212 
    195213boilerplate_conv(TSIG, ns_t_tsig,  
     
    321339                 ) 
    322340 
     341 
     342bool getEDNSOpts(const MOADNSParser& mdp, EDNSOpts* eo) 
     343{ 
     344  if(mdp.d_header.arcount && !mdp.d_answers.empty() &&  
     345     mdp.d_answers.back().first.d_type == QType::OPT) { 
     346    eo->d_packetsize=mdp.d_answers.back().first.d_class; 
     347     
     348    EDNS0Record stuff; 
     349    uint32_t ttl=ntohl(mdp.d_answers.back().first.d_ttl); 
     350    memcpy(&stuff, &ttl, sizeof(stuff)); 
     351 
     352    eo->d_extRCode=stuff.extRCode; 
     353    eo->d_version=stuff.version; 
     354    eo->d_Z=stuff.Z; 
     355     
     356    OPTRecordContent* orc =  
     357      dynamic_cast<OPTRecordContent*>(mdp.d_answers.back().first.d_content.get()); 
     358 
     359    orc->getData(eo->d_options); 
     360 
     361    return true; 
     362  } 
     363  else 
     364    return false; 
     365} 
     366 
     367 
    323368void reportBasicTypes() 
    324369{ 
  • trunk/pdns/pdns/dnsrecords.hh

    r1144 r1232  
    198198public: 
    199199  includeboilerplate(OPT) 
    200  
     200  void getData(vector<pair<uint16_t, string> > &opts); 
    201201private: 
    202202  string d_data; 
     
    423423}                                                                 \ 
    424424 
     425struct EDNSOpts 
     426{ 
     427  uint16_t d_packetsize; 
     428  uint8_t d_extRCode, d_version; 
     429  uint16_t d_Z; 
     430  vector<pair<uint16_t, string> > d_options; 
     431}; 
     432//! Convenience function that fills out EDNS0 options, and returns true if there are any 
     433 
     434class MOADNSParser; 
     435bool getEDNSOpts(const MOADNSParser& mdp, EDNSOpts* eo); 
     436 
    425437void reportBasicTypes(); 
    426438void reportOtherTypes(); 
  • trunk/pdns/pdns/dnswriter.cc

    r1156 r1232  
    8282} 
    8383 
    84 void DNSPacketWriter::addOpt(int udpsize, int extRCode, int Z) 
     84void DNSPacketWriter::addOpt(int udpsize, int extRCode, int Z, const vector<pair<uint16_t,string> >& options) 
    8585{ 
    8686  uint32_t ttl=0; 
     
    9191  stuff.version=0; 
    9292  stuff.Z=htons(Z); 
    93    
     93 
    9494  memcpy(&ttl, &stuff, sizeof(stuff)); 
    9595 
     
    9797   
    9898  startRecord("", ns_t_opt, ttl, udpsize, ADDITIONAL); 
     99  for(optvect_t::const_iterator iter = options.begin(); iter != options.end(); ++iter) { 
     100    xfr16BitInt(iter->first); 
     101    xfr16BitInt(iter->second.length()); 
     102    xfrBlob(iter->second); 
     103  }  
    99104} 
    100105 
  • trunk/pdns/pdns/dnswriter.hh

    r1100 r1232  
    5454 
    5555  /** Shorthand way to add an Opt-record, for example for EDNS0 purposes */ 
    56   void addOpt(int udpsize, int extRCode, int Z); 
     56  typedef vector<pair<uint16_t,std::string> > optvect_t; 
     57  void addOpt(int udpsize, int extRCode, int Z, const optvect_t& options=optvect_t()); 
    5758 
    5859  /** needs to be called after the last record is added, but can be called again and again later on. Is called internally by startRecord too. 
  • trunk/pdns/pdns/packethandler.cc

    r1216 r1232  
    797797    } 
    798798     
     799    if(!noCache) 
     800      noCache = !p->couldBeCached(); 
     801 
    799802    string::size_type pos; 
    800803     
     
    925928 
    926929    r->wrapup(); // needed for inserting in cache 
    927     if(!noCache) 
     930    if(!noCache) { 
    928931      PC.insert(p,r); // in the packet cache 
     932    } 
    929933  } 
    930934  catch(DBException &e) { 
  • trunk/pdns/pdns/pdns_recursor.cc

    r1200 r1232  
    512512  try { 
    513513    uint16_t maxudpsize=512; 
    514     MOADNSParser::EDNSOpts edo; 
    515     if(dc->d_mdp.getEDNSOpts(&edo)) { 
     514    EDNSOpts edo; 
     515    if(getEDNSOpts(dc->d_mdp, &edo)) { 
    516516      maxudpsize=edo.d_packetsize; 
    517517    } 
     
    19961996    ::arg().set("max-cache-entries", "If set, maximum number of entries in the main cache")="0"; 
    19971997    ::arg().set("max-negative-ttl", "maximum number of seconds to keep a negative cached entry in memory")="3600"; 
    1998     ::arg().set("server-id", "Returned when queried for 'server.id' TXT, defaults to hostname")=""; 
     1998    ::arg().set("server-id", "Returned when queried for 'server.id' TXT or NSID, defaults to hostname")=""; 
    19991999    ::arg().set("remotes-ringbuffer-entries", "maximum number of packets to store statistics for")="0"; 
    20002000    ::arg().set("version-string", "string reported on version.pdns or version.bind")="PowerDNS Recursor "VERSION" $Id$"; 
  • trunk/pdns/pdns/receiver.cc

    r1216 r1232  
    464464      exit(99); 
    465465    } 
    466  
    467  
    468466     
    469467    if(::arg().mustDo("help")) { 
     
    499497      if(!isGuarded(argv)) 
    500498        daemonize(); 
     499    } 
     500 
     501    if(::arg()["server-id"].empty()) { 
     502      char tmp[128]; 
     503      gethostname(tmp, sizeof(tmp)-1); 
     504      ::arg().set("server-id")=tmp; 
    501505    } 
    502506