- UltraSparc alignment issues Chris Andrews
- compression (Mark Bergsma)
- SRV records (Ueli Heuer)
+ - updated J root-server IP address in the recursor
Changes since 2.9.3a:
feat - make *all* sql in gsqlbackends available for configuration (Martin Klebermass/bert hubert)
dnl intro
AC_INIT(pdns/receiver.cc)
-AM_INIT_AUTOMAKE(pdns, 2.9.4)
+AM_INIT_AUTOMAKE(pdns, 2.9.5)
AC_CANONICAL_HOST
AM_CONFIG_HEADER(config.h)
AC_C_BIGENDIAN
-// $Id: gsqlbackend.cc,v 1.5 2003/01/02 20:15:26 ahu Exp $
+// $Id: gsqlbackend.cc,v 1.6 2003/01/23 15:34:53 ahu Exp $
#include <string>
#include <map>
else
r.qname=row[5];
r.qtype=row[3];
+ r.last_modified=0;
r.domain_id=atoi(row[4].c_str());
return true;
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-// $Id: dnspacket.cc,v 1.15 2003/01/21 15:04:02 ahu Exp $
+// $Id: dnspacket.cc,v 1.16 2003/01/23 15:34:53 ahu Exp $
#include "utility.hh"
#include <cstdio>
toqname(domain,&piece1);
char piece2[12];
-
- piece2[0]=0;
-
- piece2[1]=15; // MX
- piece2[2]=0;
- piece2[3]=1; // IN
-
- putLong(piece2+4,ttl);
- piece2[8]=0;
- piece2[9]=0; // need to fill this in
+ makeHeader(piece2,QType::MX,ttl);
// start of payload for which we need to specify the length in 8 & 9
toqname(domain, &piece1);
char p[10];
-
- p[0]=0;
- p[1]=6; // SOA
- p[2]=0;
- p[3]=1; // IN
-
- putLong(p+4,ttl);
- p[8]=0;
- p[9]=0; // need to fill this in (length)
+ makeHeader(p,QType::SOA,ttl);
string piece3;
toqname(soadata.nameserver,&piece3, false);
toqname(domain.c_str(),&piece1);
char p[10];
-
- p[0]=0;
- p[1]=17; // RP
- p[2]=0;
- p[3]=1; // IN
-
- putLong(p+4,ttl);
-
- p[8]=0;
- p[9]=0; // need to fill this in
+ makeHeader(p,17,ttl);
// content contains: mailbox-name more-info-domain (Separated by a space)
unsigned int pos;
char p[10];
makeHeader(p,QType::HINFO,ttl);
- p[8]=0;
- p[9]=0; // need to fill this in
-
unsigned int offset=content.find(" ");
string cpu, host;
if(offset==string::npos) {
toqname(domain, &piece1);
char p[10];
-
- p[0]=0;
- p[1]=2; // NS
- p[2]=0;
- p[3]=1; // IN
- putLong(p+4,ttl);
-
- p[8]=0;
- p[9]=0; // need to fill this in
+ makeHeader(p,QType::NS,ttl);
string piece3;
string::size_type pos=server.find('@'); // chop off @
</affiliation>
</author>
- <PubDate>v2.1 $Date: 2003/01/21 15:04:02 $</PubDate>
+ <PubDate>v2.1 $Date: 2003/01/23 15:34:53 $</PubDate>
<Abstract>
<para>
for example. Cooperation between the both halves of PDNS is also almost seamless. As a result, 'non-lazy recursion' has been dropped. See
<xref linkend="recursion"> for more details.
</para>
+ <para>
+ Furthermore, the recursor only works on Linux and Solaris (probably, untested). FreeBSD does not support the required functions.
+ If you know any important FreeBSD people, plea with them to support set/get/swapcontext!
+ </para>
<para>
The 'Contributor of the Month' award goes to Mark Bergsma who has responded to our plea for help with the label compressor and contributed
a wonderfully simple and right fix that allows PDNS to compress just as well as Other namerervers out there. An honorary mention goes to
Yet more UltraSPARC alignment issues fixed (Chris Andrews).
</para>
</listitem>
+ <listitem>
+ <para>
+ Dropped non-lazy recursion, nobody was using it.
+ </para>
+ </listitem>
<listitem>
<para>
Label compression was improved so we can now fit all . records in 436 bytes, this used to be 460! (Code & formal
SRV support (incoming and outgoing), submitted by Ueli Heuer.
</para>
</listitem>
+ <listitem>
+ <para>
+ Generic backends do not support SOA serial autocalculation, it appears. Could lead to random SOA serials in case
+ of a serial of 0 in the database. Fixed so that 0 stays zero in that case. Don't set the SOA serial to 0 when using
+ Generic MySQL or Generic PostgreSQL!
+ </para>
+ </listitem>
</itemizedlist>
</para>
</sect2>
mysql> CREATE TABLE records (
id int(11) NOT NULL auto_increment,
- domain_id int(11) default NULL,
- name varchar(255) default NULL,
- type varchar(6) default NULL,
+ domain_id int(11) NOT NULL,
+ name varchar(255) NOT NULL,
+ type varchar(6) NOT NULL,
content varchar(255) default NULL,
- ttl int(11) default NULL,
+ ttl int(11) NOT NULL,
prio int(11) default NULL,
change_date int(11) default NULL,
PRIMARY KEY (id),
not proceed from the authoritative database.
</para>
</sect1>
- <sect1 id="built-in-recursor"><title>PowerDNS resolver/recursing nameserver</title>
+ </chapter>
+ <chapter id="built-in-recursor"><title>PowerDNS resolver/recursing nameserver</title>
+ <para>
+ As of 2.9.4, a small recursor comes with PowerDNS. The algorithm is influenced by the works of Dan J. Bernstein although
+ all mistakes are ours. Here are the current faults, so nobody can accuse us of false advertising:
+ <itemizedlist>
+ <listitem><para>
+ Only ignores stale cache entries, does not actually clean them up. May replace them with newer data, however.
+ </para></listitem>
+ <listitem><para>
+ Only compiles on Linux and possibly Solaris. FreeBSD 4.x decided not to support the
+ POSIX get/set/swapcontext functions. Bug your favorite FreeBSD kernel or libc maintainer for a fix,
+ or ask him to port MTasker (see below) to your operating system.
+ </para></listitem>
+ <listitem<para>
+ It does not do TCP yet, and may have big problems with truncated packets.
+ </para></listitem>
+ </itemizedlist>
+ </para>
+ <para>
+ To compile, add <command>--enable-recursor</command> to configure and the file <filename>pdns_recursor</filename> will be
+ compiled. To run on a different port, use <command>./syncres --local-port=53</command>.
+ To bind to another address, use the <command>local-address</command> setting.
+ </para>
+ <para>
+ <note>
+ <para>
+ PowerDNS author bert hubert has the pdns recursor in production and browsing with it works for him. Furthermore, the LARTC
+ mailinglist (2000 subscribers) is using the pdns recursing nameserver.
+ </para>
+ </note>
+ </para>
+ <para>
+ Good points:
+ <itemizedlist>
+ <listitem><para>
+ Uses MTasker (<ulink url="http://ds9a.nl/mtasker">homepage</ulink>)
+ </para></listitem>
+ <listitem><para>
+ Can handle thousands of concurrent questions
+ </para></listitem>
+ <listitem><para>
+ Code is written linearly, sequentially, which means that there are no problems with 'query restart' or anything.
+ </para></listitem>
+ <listitem><para>
+ Relies heavily on Standard C++ Library infrastructure, which makes for little code (406 core lines).
+ </para></listitem>
+ <listitem><para>
+ Is very verbose in showing how recursion actually works.
+ </para></listitem>
+ <listitem><para>
+ The algorithm is simple and quite nifty.
+ </para></listitem>
+ </itemizedlist>
+ </para>
+ <sect1><title>pdns_recursor settings</title>
<para>
- As of 2.9.4, a small recursor comes with PowerDNS. The algorithm is influenced by the works of Dan J. Bernstein although
- all mistakes are ours. Here are the current faults, so nobody can accuse us of false advertising:
- <itemizedlist>
- <listitem><para>
- Only ignores stale cache entries, does not actually clean them up. May replace them with newer data, however.
- </para></listitem>
- <listitem><para>
- Only compiles on Linux and possibly Solaris. FreeBSD 4.x decided not to support the
- POSIX get/set/swapcontext functions. Bug your favorite FreeBSD kernel or libc maintainer for a fix,
- or ask him to port MTasker (see below) to your operating system.
- </para></listitem>
- <listitem<para>
- It does not do TCP yet, and may have big problems with truncated packets.
- </para></listitem>
- </itemizedlist>
+ At startup, the recursing nameserver reads the file <filename>recursor.conf</filename> from the configuration directory,
+ often <filename>/etc/powerdns</filename> or <filename>/usr/local/etc</filename>.
</para>
<para>
- To compile, add <command>--enable-recursor</command> to configure and the file <filename>pdns_recursor</filename> will be
- compiled. To run on a different port, use <command>./syncres --local-port=53</command>.
- To bind to another address, use the <command>local-address</command> setting.
- </para>
+ The following settings can be configured:
+ <variablelist>
+ <varlistentry>
+ <term>aaaa-additional-processing</term>
+ <listitem>
+ <para>
+ If turned on, the recursor will attempt to add AAAA IPv6 records to questions for MX records and NS records.
+ Can be quite slow as absence of these records in earlier answers does not guarantee their non-existance. Can double
+ the amount of queries needed. Off by default.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>daemon</term>
+ <listitem>
+ <para>
+ Operate in the background, which is the default.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>local-address</term>
+ <listitem>
+ <para>
+ Local IP address (singular) to bind to. Defaults to all addresses.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>local-port</term>
+ <listitem>
+ <para>
+ Local port (singular) to bind to. Defaults to 53.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>trace</term>
+ <listitem>
+ <para>
+ If turned on, output impressive heaps of logging. May destroy performance under load.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
<para>
- <note>
- <para>
- PowerDNS author bert hubert has the pdns recursor in production and browsing with it works for him. Furthermore, the LARTC
- mailinglist (2000 subscribers) is using the pdns recursing nameserver.
- </para>
- </note>
- </para>
+ </sect1>
+ <sect1><title>Statistics</title>
<para>
- Good points:
- <itemizedlist>
- <listitem><para>
- Uses MTasker (<ulink url="http://ds9a.nl/mtasker">homepage</ulink>)
- </para></listitem>
- <listitem><para>
- Can handle thousands of concurrent questions
- </para></listitem>
- <listitem><para>
- Code is written linearly, sequentially, which means that there are no problems with 'query restart' or anything.
- </para></listitem>
- <listitem><para>
- Relies heavily on Standard C++ Library infrastructure, which makes for little code (406 core lines).
- </para></listitem>
- <listitem><para>
- Is very verbose in showing how recursion actually works.
- </para></listitem>
- <listitem><para>
- The algorithm is simple and quite nifty.
- </para></listitem>
- </itemizedlist>
+ Every half our or so, the recursor outputs a line with statistics. More infrastructure is planned so as to allow
+ for Cricket or MRTG graphs.
</para>
- <sect2><title>pdns_recursor settings</title>
- <para>
- <variablelist>
- <varlistentry>
- <term>aaaa-additional-processing</term>
- <listitem>
- <para>
- If turned on, the recursor will attempt to add AAAA IPv6 records to questions for MX records and NS records.
- Can be quite slow as absence of these records in earlier answers does not guarantee their non-existance. Can double
- the amount of queries needed.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>daemon</term>
- <listitem>
- <para>
- Operate in the background.
- </para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>local-address</term>
- <listitem>
- <para>
- Local IP address (singular) to bind to.
- </para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>local-port</term>
- <listitem>
- <para>
- Local port (singular) to bind to. Defaults to 5300!
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>local-port</term>
- <listitem>
- <para>
- Local port (singular) to bind to. Defaults to 5300!
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>trace</term>
- <listitem>
- <para>
- If turned on, output impressive heaps of logging. May destroy performance under load.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- </sect2>
</sect1>
</chapter>
<chapter id="replication"><title>Master/Slave operation & replication</title>
</para>
</listitem>
</varlistentry>
+ <varlistentry>
+ <term>Q: Can I use a MySQL database with the Windows version of PowerDNS?</term>
+ <listitem>
+ <para>
+ A: You can. MySQL support is supplied through the ODBC backend, which is compiled into the main binary.
+ So if you want to use MySQL you can change the pdns.conf file, which is located in the PowerDNS for Windows directory, to use the
+ correct ODBC data sources.
+
+ If you don't know how to use ODBC with MySQL:
+ <itemizedlist>
+ <listitem><para>
+ Download MyODBC from <ulink url="http://www.mysql.com/">http://www.mysql.com/</ulink>
+ </para></listitem>
+ <listitem><para>
+ Install the MySQL ODBC driver.
+ </para></listitem>
+ </itemizedlist>
+ Then you can follow the instructions located in <xref linkend="windows">.
+ But instead of selecting the Microsoft Access Driver you select the MySQL ODBC Driver and configure it to use your MySQL database.
+
+ <note><para>For other databases for which an ODBC driver is available, the procedure is the same as this example.</para></note>
+ </para>
+ </listitem>
+ </varlistentry>
</variablelist>
</para>
<sect1 id="pdns-devel-faq"><title>Backend developer HOWTO</title>
<screen>
CREATE TABLE records (
id int(11) NOT NULL auto_increment,
- domain_id int(11) default NULL,
- name varchar(255) default NULL,
- type varchar(6) default NULL,
- content varchar(255) default NULL,
- ttl int(11) default NULL,
+ domain_id int(11) NOT NULL,
+ name varchar(255) NOT NULL,
+ type varchar(6) NOT NULL,
+ content varchar(255) NOT NULL,
+ ttl int(11) NOT NULL,
prio int(11) default NULL,
change_date int(11) default NULL,
PRIMARY KEY (id),
<row><entry>Master</entry><entry>Yes</entry></row>
<row><entry>Slave</entry><entry>Yes</entry></row>
<row><entry>Superslave</entry><entry>Yes</entry></row>
- <row><entry>Autoserial</entry><entry>Yes</entry></row>
+ <row><entry>Autoserial</entry><entry>NO</entry></row>
<row><entry>Case</entry><entry>All lower</entry></row>
<row><entry>Module name < 2.9.3</entry><entry>pgmysql</entry></row>
<row><entry>Module name > 2.9.2</entry><entry>gmysql and gpgsql</entry></row>
#include "resolver.hh"
#include "communicator.hh"
#include "dnsproxy.hh"
-#include "recbcomm.hh"
extern StatBag S;
extern PacketCache PC;
DNSResourceRecord rr;
if (p->qclass == 3 && p->qtype.getName() == "HINFO") {
- rr.content = "PowerDNS $Id: packethandler.cc,v 1.7 2003/01/21 10:42:34 ahu Exp $";
+ rr.content = "PowerDNS $Id: packethandler.cc,v 1.8 2003/01/23 15:34:53 ahu Exp $";
rr.ttl = 5;
rr.qname=target;
rr.qtype=13; // hinfo
{
DNSResourceRecord rr;
if(p->qtype.getCode()==QType::TXT && target=="version.bind") {// TXT
- rr.content="Served by POWERDNS "VERSION" $Id: packethandler.cc,v 1.7 2003/01/21 10:42:34 ahu Exp $";
+ rr.content="Served by POWERDNS "VERSION" $Id: packethandler.cc,v 1.8 2003/01/23 15:34:53 ahu Exp $";
rr.ttl=5;
rr.qname=target;
rr.qtype=QType::TXT; // TXT
#include <set>
#include <netdb.h>
#include <stdio.h>
+#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
#include "mtasker.hh"
int d_clientsock;
int d_serversock;
-
-/*
-Jan 20 00:21:40 [48570] new question arrived for 'idealx.com|MX' from 127.0.0.1
-Jan 20 00:21:40 [48571] new question arrived for 'idealx.com|MX' from 127.0.0.1
-Jan 20 00:21:40 [48572] new question arrived for 'idealx.com|MX' from 127.0.0.1
-Jan 20 00:21:40 [48573] new question arrived for 'idealx.com|MX' from 127.0.0.1
-Jan 20 00:21:44 [48573] sent answer to question for 'idealx.com|MX' to 127.0.0.1, 0 answers, 0 additional, sent 2 packets, rcode=2
-Jan 20 00:21:44 [48573] sent answer to question for 'idealx.com|MX' to 127.0.0.1, 0 answers, 0 additional, sent 2 packets, rcode=2
-Jan 20 00:21:44 [48573] sent answer to question for 'idealx.com|MX' to 127.0.0.1, 0 answers, 0 additional, sent 2 packets, rcode=2
-Jan 20 00:21:44 [48573] sent answer to question for 'idealx.com|MX' to 127.0.0.1, 0 answers, 0 additional, sent 2 packets, rcode=2
-*/
-
struct PacketID
{
u_int16_t id;
return false;
}
-MTasker<PacketID,string> MT(200000);
+MTasker<PacketID,string> MT(100000); // could probably be way lower
/* these two functions are used by LWRes */
int asendto(const char *data, int len, int flags, struct sockaddr *toaddr, int addrlen, int id)
return 1;
}
-
typedef map<string,set<DNSResourceRecord> > cache_t;
cache_t cache;
int cacheHits, cacheMisses;
if(j!=cache.end() && j->first==toLower(qname)+"|"+qt.getName() && j->second.begin()->ttl>(unsigned int)time(0)) {
if(res)
*res=j->second;
- cacheHits++;
+
return (unsigned int)j->second.begin()->ttl-time(0);
}
- cacheMisses++;
+
return -1;
}
// prime root cache
static char*ips[]={"198.41.0.4", "128.9.0.107", "192.33.4.12", "128.8.10.90", "192.203.230.10", "192.5.5.241", "192.112.36.4", "128.63.2.53",
- "192.36.148.17","198.41.0.10", "193.0.14.129", "198.32.64.12", "202.12.27.33"};
+ "192.36.148.17","192.58.128.30", "193.0.14.129", "198.32.64.12", "202.12.27.33"};
DNSResourceRecord arr, nsrr;
arr.qtype=QType::A;
arr.ttl=time(0)+3600000;
void startDoResolve(void *p)
{
try {
+ bool quiet=arg().mustDo("quiet");
DNSPacket P=*(DNSPacket *)p;
delete (DNSPacket *)p;
R->setRA(true);
SyncRes sr;
- L<<Logger::Error<<"["<<MT.getTid()<<"] question for '"<<P.qdomain<<"|"<<P.qtype.getName()<<"' from "<<P.getRemote()<<endl;
+ if(!quiet)
+ L<<Logger::Error<<"["<<MT.getTid()<<"] question for '"<<P.qdomain<<"|"<<P.qtype.getName()<<"' from "<<P.getRemote()<<endl;
+
sr.setId(MT.getTid());
if(!P.d.rd)
sr.setCacheOnly();
const char *buffer=R->getData();
sendto(d_serversock,buffer,R->len,0,(struct sockaddr *)(R->remote),R->d_socklen);
- L<<Logger::Error<<"["<<MT.getTid()<<"] answer to "<<(P.d.rd?"":"non-rd ")<<"question '"<<P.qdomain<<"|"<<P.qtype.getName();
- L<<"': "<<ntohs(R->d.ancount)<<" answers, "<<ntohs(R->d.arcount)<<" additional, took "<<sr.d_outqueries<<" packets, rcode="<<res<<endl;
+ if(!quiet) {
+ L<<Logger::Error<<"["<<MT.getTid()<<"] answer to "<<(P.d.rd?"":"non-rd ")<<"question '"<<P.qdomain<<"|"<<P.qtype.getName();
+ L<<"': "<<ntohs(R->d.ancount)<<" answers, "<<ntohs(R->d.arcount)<<" additional, took "<<sr.d_outqueries<<" packets, rcode="<<res<<endl;
+ }
+
+ sr.d_outqueries ? cacheMisses++ : cacheHits++;
delete R;
}
}
int counter, qcounter;
+bool statsWanted;
+
+void usr1Handler(int)
+{
+ statsWanted=true;
+}
+void doStats(void)
+{
+ if(qcounter) {
+ L<<Logger::Error<<"stats: "<<qcounter<<" questions, "<<cache.size()<<" cache entries, "<<SyncRes::s_negcache.size()<<" negative entries, "
+ <<(int)((cacheHits*100.0)/(cacheHits+cacheMisses))<<"% cache hits";
+ L<<Logger::Error<<", outpacket/query ratio "<<(int)(SyncRes::s_outqueries*100.0/SyncRes::s_queries)<<"%"<<endl;
+ }
+ statsWanted=false;
+}
void houseKeeping(void *)
{
static time_t last_stat, last_rootupdate;
- if(time(0)-last_stat>1800) {
- if(qcounter) {
- L<<Logger::Error<<"stats: "<<qcounter<<" questions, "<<cache.size()<<" cache entries, "
- <<(int)((cacheHits*100.0)/(cacheHits+cacheMisses))<<"% cache hits";
- L<<Logger::Error<<", outpacket/query ratio "<<(int)(SyncRes::s_outqueries*100.0/SyncRes::s_queries)<<"%"<<endl;
- }
+ if(time(0)-last_stat>1800) {
+ doStats();
last_stat=time(0);
}
if(time(0)-last_rootupdate>7200) {
arg().set("soa-minimum-ttl","Don't change")="0";
arg().set("soa-serial-offset","Don't change")="0";
arg().set("aaaa-additional-processing","turn on to do AAAA additional processing (slow)")="off";
- arg().set("local-port","port to listen on")="5300";
+ arg().set("local-port","port to listen on")="53";
arg().set("local-address","port to listen on")="0.0.0.0";
arg().set("trace","if we should output heaps of logging")="off";
- arg().set("daemon","Operate as a daemon")="no";
+ arg().set("daemon","Operate as a daemon")="yes";
+ arg().set("quiet","Suppress logging of questions and answers")="off";
+ arg().set("config-dir","Location of configuration directory (recursor.conf)")=SYSCONFDIR;
arg().setCmd("help","Provide a helpful message");
+ L.toConsole(Logger::Warning);
+ arg().laxParse(argc,argv); // do a lax parse
+
+ string configname=arg()["config-dir"]+"/recursor.conf";
+ cleanSlashes(configname);
+
+ if(!arg().file(configname.c_str()))
+ L<<Logger::Warning<<"Unable to parse configuration file '"<<configname<<"'"<<endl;
+
+ arg().parse(argc,argv);
- arg().parse(argc, argv);
if(arg().mustDo("help")) {
cerr<<"syntax:"<<endl<<endl;
exit(99);
}
-
L.setName("pdns_recursor");
- L.toConsole(Logger::Warning);
if(arg().mustDo("trace"))
SyncRes::setLog(true);
L.toConsole(Logger::Critical);
daemonize();
}
+ signal(SIGUSR1,usr1Handler);
+
for(;;) {
while(MT.schedule()); // housekeeping, let threads do their thing
- if(!((counter++)%1000))
+ if(!((counter++)%100))
MT.makeThread(houseKeeping,0);
+ if(statsWanted)
+ doStats();
socklen_t addrlen=sizeof(fromaddr);
int d_len;
FD_SET( d_clientsock, &readfds );
FD_SET( d_serversock, &readfds );
int selret = select( max(d_clientsock,d_serversock) + 1, &readfds, NULL, NULL, &tv );
- if (selret == -1)
+ if(selret<=0)
+ if (selret == -1 && errno!=EINTR)
throw AhuException("Select returned: "+stringerror());
- if(!selret) // nothing happened
- continue;
+ else
+ continue;
+
if(FD_ISSET(d_clientsock,&readfds)) { // do we have a question response?
d_len=recvfrom(d_clientsock, data, sizeof(data), 0, (sockaddr *)&fromaddr, &addrlen);
static unsigned int s_queries;
static unsigned int s_outqueries;
unsigned int d_outqueries;
-
+ static map<string,string> s_negcache;
private:
struct GetBestNSAnswer;
int doResolveAt(set<string> nameservers, string auth, const string &qname, const QType &qtype, vector<DNSResourceRecord>&ret,
vector<string> shuffle(set<string> &nameservers);
bool moreSpecificThan(const string& a, const string &b);
string getA(const string &qname, int depth, set<GetBestNSAnswer>& beenthere);
-
+
private:
string d_prefix;
static bool s_log;
bool d_cacheonly;
bool d_nocache;
LWRes d_lwr;
- static map<string,string> s_negcache;
+
struct GetBestNSAnswer
{
string qname;