::arg().set("negquery-cache-ttl","Seconds to store packets in the PacketCache")="60";
::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";
::arg().set("soa-expire-default","Default SOA expire")="604800";
::arg().set("max-cache-entries", "Maximum number of cache entries")="1000000";
}
-
-
void declareStats(void)
{
S.declare("udp-queries","Number of UDP queries received");
S.ringAccount("queries", P->qdomain+"/"+P->qtype.getName());
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
cached.spoofID(P->d.id); // inlined
#include "arguments.hh"
#include "dnswriter.hh"
#include "dnsparser.hh"
+#include "dnsrecords.hh"
DNSPacket::DNSPacket()
{
d_wrapped=false;
d_compress=true;
d_tcp=false;
+ d_wantsnsid=false;
}
string DNSPacket::getString()
qclass=orig.qclass;
qdomain=orig.qdomain;
d_maxreplylen = orig.d_maxreplylen;
+ d_ednsping = orig.d_ednsping;
+ d_wantsnsid = orig.d_wantsnsid;
rrs=orig.rrs;
d_wrapped=orig.d_wrapped;
rrs.reserve(200);
}
+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.
*/
pw.getHeader()->id=d.id;
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) {
// this needs to deal with the 'prio' mismatch!
shared_ptr<DNSRecordContent> drc(DNSRecordContent::mastermake(pos->qtype.getCode(), 1, pos->content));
drc->toPacket(pw);
}
+ if(!opts.empty())
+ pw.addOpt(2800, 0, 0, opts);
+
pw.commit();
}
catch(exception& e) {
r->qdomain = qdomain;
r->qtype = qtype;
r->d_maxreplylen = d_maxreplylen;
+ r->d_ednsping = d_ednsping;
+ r->d_wantsnsid = d_wantsnsid;
return r;
}
try
{
stringbuffer.assign(mesg,length);
-
+
len=length;
if(length < 12) {
L << Logger::Warning << "Ignoring packet: too short from "
<< getRemote() << endl;
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;
+
+ 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
+ else {
d_maxreplylen=512;
+ }
memcpy((void *)&d,(const void *)stringbuffer.c_str(),12);
qdomain=mdp.d_qname;
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 !
ComboAddress remote;
string stringbuffer; // this is where everything lives 4
int d_maxreplylen;
+ string d_ednsping;
+ bool d_wantsnsid;
vector<DNSResourceRecord> rrs; // 4
};
DNSRecordContent* DNSRecordContent::mastermake(const DNSRecord &dr,
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);
}
}
}
-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)
{
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;
}
return pr;
}
- 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);
void init(const char *packet, unsigned int len);
);
-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,
conv.xfrLabel(d_algoName);
conv.xfrBlob(d_key);
)
+
+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()
{
ARecordContent::report();
{
public:
includeboilerplate(OPT)
-
+ void getData(vector<pair<uint16_t, string> > &opts);
private:
string d_data;
};
CONV; \
} \
+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();
void reportAllTypes();
d_sor=d_content.size() + d_stuff; // start of real record
}
-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;
stuff.extRCode=extRCode;
stuff.version=0;
stuff.Z=htons(Z);
-
+
memcpy(&ttl, &stuff, sizeof(stuff));
ttl=ntohl(ttl); // will be reversed later on
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);
+ }
}
void DNSPacketWriter::xfr48BitInt(uint64_t val)
void startRecord(const string& name, uint16_t qtype, uint32_t ttl=3600, uint16_t qclass=1, Place place=ANSWER);
/** 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.
The content of the vector<> passed to the constructor is inconsistent until commit is called.
else noCache=true;
}
+ if(!noCache)
+ noCache = !p->couldBeCached();
+
string::size_type pos;
DLOG(L<<"Nothing found so far for '"<<target<<"', do we even have authority over this domain?"<<endl);
return 0;
r->wrapup(); // needed for inserting in cache
- if(!noCache)
+ if(!noCache) {
PC.insert(p,r); // in the packet cache
+ }
}
catch(DBException &e) {
L<<Logger::Error<<"Database module reported condition which prevented lookup ("+e.reason+") sending out servfail"<<endl;
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;
}
::arg().set("hint-file", "If set, load root hints from this file")="";
::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$";
::arg().set("allow-from", "If set, only allow these comma separated netmasks to recurse")="127.0.0.0/8, 10.0.0.0/8, 192.168.0.0/16, 172.16.0.0/12, ::1/128, fe80::/10";
cerr<<"Fatal: non-option on the command line, perhaps a '--setting=123' statement missed the '='?"<<endl;
exit(99);
}
-
-
if(::arg().mustDo("help")) {
cerr<<"syntax:"<<endl<<endl;
daemonize();
}
+ if(::arg()["server-id"].empty()) {
+ char tmp[128];
+ gethostname(tmp, sizeof(tmp)-1);
+ ::arg().set("server-id")=tmp;
+ }
+
if(isGuarded(argv)) {
L<<Logger::Warning<<"This is a guarded instance of pdns"<<endl;
dl=new DynListener; // listens on stdin