Index: trunk/pdns/pdns/dnswriter.hh
===================================================================
--- trunk/pdns/pdns/dnswriter.hh (revision 1100)
+++ trunk/pdns/pdns/dnswriter.hh (revision 1232)
@@ -54,5 +54,6 @@
 
   /** Shorthand way to add an Opt-record, for example for EDNS0 purposes */
-  void addOpt(int udpsize, int extRCode, int Z);
+  typedef vector<pair<uint16_t,std::string> > optvect_t;
+  void addOpt(int udpsize, int extRCode, int Z, const optvect_t& options=optvect_t());
 
   /** 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.
Index: trunk/pdns/pdns/common_startup.cc
===================================================================
--- trunk/pdns/pdns/common_startup.cc (revision 1217)
+++ trunk/pdns/pdns/common_startup.cc (revision 1232)
@@ -105,5 +105,5 @@
   ::arg().set("query-cache-ttl","Seconds to store packets in the PacketCache")="20";
   ::arg().set("soa-minimum-ttl","Default SOA mininum ttl")="3600";
-
+  ::arg().set("server-id", "Returned when queried for 'server.id' TXT or NSID, defaults to hostname")="";
   ::arg().set("soa-refresh-default","Default SOA refresh")="10800";
   ::arg().set("soa-retry-default","Default SOA retry")="3600";
@@ -123,6 +123,4 @@
   ::arg().set("max-cache-entries", "Maximum number of cache entries")="1000000";
 }
-
-
 
 void declareStats(void)
@@ -242,5 +240,5 @@
     S.ringAccount("remotes",P->getRemote());
 
-    if((P->d.opcode != Opcode::Notify) && PC.get(P,&cached)) { // short circuit - does the PacketCache recognize this question?
+    if((P->d.opcode != Opcode::Notify) && P->couldBeCached() && PC.get(P,&cached)) { // short circuit - does the PacketCache recognize this question?
       cached.setRemote(&P->remote);  // inlined
       cached.setSocket(P->getSocket());                               // inlined
Index: trunk/pdns/pdns/packethandler.cc
===================================================================
--- trunk/pdns/pdns/packethandler.cc (revision 1216)
+++ trunk/pdns/pdns/packethandler.cc (revision 1232)
@@ -797,4 +797,7 @@
     }
     
+    if(!noCache)
+      noCache = !p->couldBeCached();
+
     string::size_type pos;
     
@@ -925,6 +928,7 @@
 
     r->wrapup(); // needed for inserting in cache
-    if(!noCache)
+    if(!noCache) {
       PC.insert(p,r); // in the packet cache
+    }
   }
   catch(DBException &e) {
Index: trunk/pdns/pdns/dnsparser.hh
===================================================================
--- trunk/pdns/pdns/dnsparser.hh (revision 1100)
+++ trunk/pdns/pdns/dnsparser.hh (revision 1232)
@@ -299,14 +299,5 @@
   }
 
-  struct EDNSOpts
-  {
-    uint16_t d_packetsize;
-    uint8_t d_extRCode, d_version;
-    uint16_t d_Z;
-  };
-
-  //! Convenience function that fills out EDNS0 options, and returns true if there are any
-  bool getEDNSOpts(EDNSOpts* eo);
-
+  
 private:
   void getDnsrecordheader(struct dnsrecordheader &ah);
Index: trunk/pdns/pdns/dnsrecords.hh
===================================================================
--- trunk/pdns/pdns/dnsrecords.hh (revision 1144)
+++ trunk/pdns/pdns/dnsrecords.hh (revision 1232)
@@ -198,5 +198,5 @@
 public:
   includeboilerplate(OPT)
-
+  void getData(vector<pair<uint16_t, string> > &opts);
 private:
   string d_data;
@@ -423,4 +423,16 @@
 }                                                                 \
 
+struct EDNSOpts
+{
+  uint16_t d_packetsize;
+  uint8_t d_extRCode, d_version;
+  uint16_t d_Z;
+  vector<pair<uint16_t, string> > d_options;
+};
+//! Convenience function that fills out EDNS0 options, and returns true if there are any
+
+class MOADNSParser;
+bool getEDNSOpts(const MOADNSParser& mdp, EDNSOpts* eo);
+
 void reportBasicTypes();
 void reportOtherTypes();
Index: trunk/pdns/pdns/dnswriter.cc
===================================================================
--- trunk/pdns/pdns/dnswriter.cc (revision 1156)
+++ trunk/pdns/pdns/dnswriter.cc (revision 1232)
@@ -82,5 +82,5 @@
 }
 
-void DNSPacketWriter::addOpt(int udpsize, int extRCode, int Z)
+void DNSPacketWriter::addOpt(int udpsize, int extRCode, int Z, const vector<pair<uint16_t,string> >& options)
 {
   uint32_t ttl=0;
@@ -91,5 +91,5 @@
   stuff.version=0;
   stuff.Z=htons(Z);
-  
+
   memcpy(&ttl, &stuff, sizeof(stuff));
 
@@ -97,4 +97,9 @@
   
   startRecord("", ns_t_opt, ttl, udpsize, ADDITIONAL);
+  for(optvect_t::const_iterator iter = options.begin(); iter != options.end(); ++iter) {
+    xfr16BitInt(iter->first);
+    xfr16BitInt(iter->second.length());
+    xfrBlob(iter->second);
+  } 
 }
 
Index: trunk/pdns/pdns/pdns_recursor.cc
===================================================================
--- trunk/pdns/pdns/pdns_recursor.cc (revision 1200)
+++ trunk/pdns/pdns/pdns_recursor.cc (revision 1232)
@@ -512,6 +512,6 @@
   try {
     uint16_t maxudpsize=512;
-    MOADNSParser::EDNSOpts edo;
-    if(dc->d_mdp.getEDNSOpts(&edo)) {
+    EDNSOpts edo;
+    if(getEDNSOpts(dc->d_mdp, &edo)) {
       maxudpsize=edo.d_packetsize;
     }
@@ -1996,5 +1996,5 @@
     ::arg().set("max-cache-entries", "If set, maximum number of entries in the main cache")="0";
     ::arg().set("max-negative-ttl", "maximum number of seconds to keep a negative cached entry in memory")="3600";
-    ::arg().set("server-id", "Returned when queried for 'server.id' TXT, defaults to hostname")="";
+    ::arg().set("server-id", "Returned when queried for 'server.id' TXT or NSID, defaults to hostname")="";
     ::arg().set("remotes-ringbuffer-entries", "maximum number of packets to store statistics for")="0";
     ::arg().set("version-string", "string reported on version.pdns or version.bind")="PowerDNS Recursor "VERSION" $Id$";
Index: trunk/pdns/pdns/receiver.cc
===================================================================
--- trunk/pdns/pdns/receiver.cc (revision 1216)
+++ trunk/pdns/pdns/receiver.cc (revision 1232)
@@ -464,6 +464,4 @@
       exit(99);
     }
-
-
     
     if(::arg().mustDo("help")) {
@@ -499,4 +497,10 @@
       if(!isGuarded(argv))
 	daemonize();
+    }
+
+    if(::arg()["server-id"].empty()) {
+      char tmp[128];
+      gethostname(tmp, sizeof(tmp)-1);
+      ::arg().set("server-id")=tmp;
     }
 
Index: trunk/pdns/pdns/dnsparser.cc
===================================================================
--- trunk/pdns/pdns/dnsparser.cc (revision 1166)
+++ trunk/pdns/pdns/dnsparser.cc (revision 1232)
@@ -133,5 +133,7 @@
 					       PacketReader& pr)
 {
-  typemap_t::const_iterator i=getTypemap().find(make_pair(dr.d_class, dr.d_type));
+  uint16_t searchclass = (dr.d_type == QType::OPT) ? 1 : dr.d_class; // class is invalid for OPT
+
+  typemap_t::const_iterator i=getTypemap().find(make_pair(searchclass, dr.d_type));
   if(i==getTypemap().end() || !i->second) {
     return new UnknownRecordContent(dr, pr);
@@ -258,22 +260,4 @@
 }
 
-bool MOADNSParser::getEDNSOpts(EDNSOpts* eo)
-{
-  if(d_header.arcount && !d_answers.empty() && d_answers.back().first.d_type == QType::OPT) {
-    eo->d_packetsize=d_answers.back().first.d_class;
-
-    EDNS0Record stuff;
-    uint32_t ttl=ntohl(d_answers.back().first.d_ttl);
-    memcpy(&stuff, &ttl, sizeof(stuff));
-
-    eo->d_extRCode=stuff.extRCode;
-    eo->d_version=stuff.version;
-    eo->d_Z=stuff.Z;
-
-    return true;
-  }
-  else
-    return false;
-}
 
 void PacketReader::getDnsrecordheader(struct dnsrecordheader &ah)
@@ -448,5 +432,8 @@
 void PacketReader::xfrBlob(string& blob)
 {
-  blob.assign(&d_content.at(d_pos), &d_content.at(d_startrecordpos + d_recordlen - 1 ) + 1);
+  if(d_recordlen)
+    blob.assign(&d_content.at(d_pos), &d_content.at(d_startrecordpos + d_recordlen - 1 ) + 1);
+  else
+    blob.clear();
 
   d_pos = d_startrecordpos + d_recordlen;
Index: trunk/pdns/pdns/dnsrecords.cc
===================================================================
--- trunk/pdns/pdns/dnsrecords.cc (revision 1168)
+++ trunk/pdns/pdns/dnsrecords.cc (revision 1232)
@@ -188,8 +188,26 @@
 
 
-boilerplate_conv(OPT, ns_t_opt,
-		 conv.xfrText(d_data)
+boilerplate_conv(OPT, ns_t_opt, 
+		   conv.xfrBlob(d_data)
 		 );
 
+void OPTRecordContent::getData(vector<pair<uint16_t, string> >& options)
+{
+  string::size_type pos=0;
+  uint16_t code, len;
+  while(d_data.size() >= 4 + pos) {
+    code = 0xff * d_data[pos] + d_data[pos+1];
+    len = 0xff * d_data[pos+2] + d_data[pos+3];
+    pos+=4;
+
+    if(pos + len > d_data.size())
+      break;
+
+    string field(d_data.c_str() + pos, len);
+    pos+=len;
+
+    options.push_back(make_pair(code, field));
+  }
+}
 
 boilerplate_conv(TSIG, ns_t_tsig, 
@@ -321,4 +339,31 @@
 		 )
 
+
+bool getEDNSOpts(const MOADNSParser& mdp, EDNSOpts* eo)
+{
+  if(mdp.d_header.arcount && !mdp.d_answers.empty() && 
+     mdp.d_answers.back().first.d_type == QType::OPT) {
+    eo->d_packetsize=mdp.d_answers.back().first.d_class;
+    
+    EDNS0Record stuff;
+    uint32_t ttl=ntohl(mdp.d_answers.back().first.d_ttl);
+    memcpy(&stuff, &ttl, sizeof(stuff));
+
+    eo->d_extRCode=stuff.extRCode;
+    eo->d_version=stuff.version;
+    eo->d_Z=stuff.Z;
+    
+    OPTRecordContent* orc = 
+      dynamic_cast<OPTRecordContent*>(mdp.d_answers.back().first.d_content.get());
+
+    orc->getData(eo->d_options);
+
+    return true;
+  }
+  else
+    return false;
+}
+
+
 void reportBasicTypes()
 {
Index: trunk/pdns/pdns/dnspacket.hh
===================================================================
--- trunk/pdns/pdns/dnspacket.hh (revision 1123)
+++ trunk/pdns/pdns/dnspacket.hh (revision 1232)
@@ -140,4 +140,7 @@
   void commitD(); //!< copies 'd' into the stringbuffer
   int getMaxReplyLen(); //!< retrieve the maximum length of the packet we should send in response
+
+  bool couldBeCached(); //!< returns 0 if this query should bypass the packet cache
+
   //////// DATA !
 
@@ -163,4 +166,6 @@
   string stringbuffer; // this is where everything lives 4
   int d_maxreplylen;
+  string d_ednsping;
+  bool d_wantsnsid;
   vector<DNSResourceRecord> rrs; // 4
 };
Index: trunk/pdns/pdns/dnspacket.cc
===================================================================
--- trunk/pdns/pdns/dnspacket.cc (revision 1138)
+++ trunk/pdns/pdns/dnspacket.cc (revision 1232)
@@ -39,4 +39,5 @@
 #include "dnswriter.hh"
 #include "dnsparser.hh"
+#include "dnsrecords.hh"
 
 DNSPacket::DNSPacket() 
@@ -45,4 +46,5 @@
   d_compress=true;
   d_tcp=false;
+  d_wantsnsid=false;
 }
 
@@ -89,4 +91,6 @@
   qdomain=orig.qdomain;
   d_maxreplylen = orig.d_maxreplylen;
+  d_ednsping = orig.d_ednsping;
+  d_wantsnsid = orig.d_wantsnsid;
   rrs=orig.rrs;
 
@@ -264,4 +268,9 @@
 }
 
+bool DNSPacket::couldBeCached()
+{
+  return d_ednsping.empty() && !d_wantsnsid;
+}
+
 /** Must be called before attempting to access getData(). This function stuffs all resource
  *  records found in rrs into the data buffer. It also frees resource records queued for us.
@@ -305,5 +314,14 @@
   pw.getHeader()->rd=d.rd;
 
-  if(!rrs.empty()) {
+  DNSPacketWriter::optvect_t opts;
+  if(d_wantsnsid) {
+    opts.push_back(make_pair(3, ::arg()["server-id"]));
+  }
+
+  if(!d_ednsping.empty()) {
+    opts.push_back(make_pair(4, d_ednsping));
+  }
+
+  if(!rrs.empty() || !opts.empty()) {
     try {
       for(pos=rrs.begin(); pos < rrs.end(); ++pos) {
@@ -321,4 +339,7 @@
 	drc->toPacket(pw);
       }
+      if(!opts.empty())
+	pw.addOpt(2800, 0, 0, opts);
+
       pw.commit();
     }
@@ -384,4 +405,6 @@
   r->qtype = qtype;
   r->d_maxreplylen = d_maxreplylen;
+  r->d_ednsping = d_ednsping;
+  r->d_wantsnsid = d_wantsnsid;
   return r;
 }
@@ -403,5 +426,5 @@
 {
   stringbuffer.assign(mesg,length); 
-
+  
   len=length;
   if(length < 12) { 
@@ -410,11 +433,32 @@
     return -1;
   }
+
   MOADNSParser mdp(stringbuffer);
-  MOADNSParser::EDNSOpts edo;
-  if(mdp.getEDNSOpts(&edo)) {
+  EDNSOpts edo;
+
+  // ANY OPTION WHICH *MIGHT* BE SET DOWN BELOW SHOULD BE CLEARED FIRST!
+
+  d_wantsnsid=false;
+  d_ednsping.clear();
+
+  if(getEDNSOpts(mdp, &edo)) {
     d_maxreplylen=edo.d_packetsize;
-  }
-  else
+
+    for(vector<pair<uint16_t, string> >::const_iterator iter = edo.d_options.begin();
+	iter != edo.d_options.end(); 
+	++iter) {
+      if(iter->first == 3) {// 'EDNS NSID'
+	d_wantsnsid=1;
+      }
+      else if(iter->first == 4) {// 'EDNS PING'
+	d_ednsping = iter->second;
+      }
+      else
+	; // cerr<<"Have an option #"<<iter->first<<endl;
+    }
+  }
+  else  {
     d_maxreplylen=512;
+  }
 
   memcpy((void *)&d,(const void *)stringbuffer.c_str(),12);
