]> granicus.if.org Git - pdns/commitdiff
implement multiple forwarders per domain, both from file and from
authorBert Hubert <bert.hubert@netherlabs.nl>
Sat, 22 Mar 2008 18:27:44 +0000 (18:27 +0000)
committerBert Hubert <bert.hubert@netherlabs.nl>
Sat, 22 Mar 2008 18:27:44 +0000 (18:27 +0000)
configuration file, based on patch by Aaron Thompson, with work from Augie
Schwer. Closes ticket 81.

Plus, add support for forwarding to ports != 53, closing ticket 122.

git-svn-id: svn://svn.powerdns.com/pdns/trunk/pdns@1168 d19b8d6e-7fed-0310-83ef-9ca221ded41b

pdns/dnsrecords.cc
pdns/docs/pdns.sgml
pdns/pdns_recursor.cc
pdns/syncres.cc
pdns/syncres.hh

index 44238d9172e000e9e22d167116d6fb36e2a458bb..08a0b95eca7e97c0d4ffd4114984993f0bff408f 100644 (file)
@@ -1,6 +1,6 @@
 /*
     PowerDNS Versatile Database Driven Nameserver
-    Copyright (C) 2005 - 2007  PowerDNS.COM BV
+    Copyright (C) 2005 - 2008  PowerDNS.COM BV
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License version 2 as 
index 840b30ccc09d774f9ab984a697239c86f71e619b..d271a7a757bcc1f1020511b6544e34e6a42f6822 100644 (file)
@@ -7405,6 +7405,10 @@ local0.err                        /var/log/pdns.err
                Comma separated list of 'zonename=IP' pairs. Queries for zones listed here will be forwarded to the IP address listed.
                <command>forward-zones= ds9a.nl=213.244.168.210, powerdns.com=127.0.0.1</command>. Available since 3.1.
              </para>
+             <para>
+               Since version 3.1.5, multiple IP addresses can be specified. Additionally, port numbers other than 53 can be configured.
+               Sample syntax: <command>forward-zones=ds9a.nl=213.244.168.210:5300;127.0.0.1, powerdns.com=127.0.0.1;9.8.7.6:530</command>,
+               or on the command line: <command>--forward-zones="ds9a.nl=213.244.168.210:5300;127.0.0.1, powerdns.com=127.0.0.1;9.8.7.6:530"</command>,
            </listitem>
          </varlistentry>
          <varlistentry>
@@ -7412,7 +7416,7 @@ local0.err                        /var/log/pdns.err
            <listitem>
              <para>
                Same as <command>forward-zones</command>, parsed from a file. Only 1 zone is allowed per line, specified as follows:
-               <command>ds9a.nl=213.244.168.210</command>. Available since 3.1.5.
+               <command>ds9a.nl=213.244.168.210, 1.2.3.4:5300</command>. No comments are allowed. Available since 3.1.5. 
              </para>
            </listitem>
          </varlistentry>
index 6b4dea499d72d8735f579bbd48526eda18e00a12..106b8a435ae0d6506faa87cc6bc59ea1693cbd24 100644 (file)
@@ -1422,6 +1422,24 @@ static void makeIPToNamesZone(const vector<string>& parts)
 
 void parseAuthAndForwards();
 
+void convertServersForAD(const std::string& input, SyncRes::AuthDomain& ad, const char* sepa, bool verbose=true)
+{
+  vector<string> servers;
+  stringtok(servers, input, sepa);
+  ad.d_servers.clear();
+  for(vector<string>::const_iterator iter = servers.begin(); iter != servers.end(); ++iter) {
+    if(verbose && iter != servers.begin()) 
+      L<<", ";
+    pair<string,string> ipport=splitField(*iter, ':');
+    ComboAddress addr(ipport.first, ipport.second.empty() ? 53 : lexical_cast<uint16_t>(ipport.second));
+    if(verbose)
+      L<<addr.toStringWithPort();
+    ad.d_servers.push_back(addr);
+  }
+  if(verbose)
+    L<<endl;
+}
+
 string reloadAuthAndForwards()
 {
   SyncRes::domainmap_t original=SyncRes::s_domainmap;
@@ -1507,8 +1525,8 @@ void parseAuthAndForwards()
        }
       }
       else {
-       L<<Logger::Error<<"Redirecting queries for zone '"<<headers.first<<"' to IP '"<<headers.second<<"'"<<endl;
-       ad.d_server=headers.second;
+       L<<Logger::Error<<"Redirecting queries for zone '"<<headers.first<<"' to: ";
+       convertServersForAD(headers.second, ad, ";");
       }
       
       SyncRes::s_domainmap[headers.first]=ad;
@@ -1526,24 +1544,27 @@ void parseAuthAndForwards()
     shared_ptr<FILE> fp=shared_ptr<FILE>(rfp, fclose);
     
     char line[1024];
-    vector<string> parts;
     int linenum=0;
     uint64_t before = SyncRes::s_domainmap.size();
     while(linenum++, fgets(line, sizeof(line)-1, fp.get())) {
-      parts.clear();
-      stringtok(parts,line,"=, ");
-      if(parts.empty())
-       continue;
-      if(parts.size()<2) 
+      string domain, instructions;
+      tie(domain, instructions)=splitField(line, '=');
+      trim(domain);
+      trim(instructions);
+
+      if(domain.empty()) 
        throw AhuException("Error parsing line "+lexical_cast<string>(linenum)+" of " +::arg()["forward-zones-file"]);
-      trim(parts[0]);
-      trim(parts[1]);
-      parts[0]=toCanonic("", parts[0]);
-      ad.d_server=parts[1];
-      //      cerr<<"Inserting '"<<domain<<"' to '"<<ad.d_server<<"'\n";
-      SyncRes::s_domainmap[parts[0]]=ad;
-    }
-    L<<Logger::Warning<<"Done parsing " << SyncRes::s_domainmap.size() - before<<" forwarding instructions from file '"<<::arg()["forward-zones-files"]<<"'"<<endl;
+
+      try {
+       convertServersForAD(instructions, ad, ",; ", false);
+      }
+      catch(...) {
+       throw AhuException("Conversion error parsing line "+lexical_cast<string>(linenum)+" of " +::arg()["forward-zones-file"]);
+      }
+
+      SyncRes::s_domainmap[toCanonic("", domain)]=ad;
+    }
+    L<<Logger::Warning<<"Done parsing " << SyncRes::s_domainmap.size() - before<<" forwarding instructions from file '"<<::arg()["forward-zones-file"]<<"'"<<endl;
   }
 
   if(::arg().mustDo("export-etc-hosts")) {
index 97a552ed64b45dfe9a93c4f851724536731b2704..3d3d24f4be8e12a77ce315d66ff02cea9b7bc8ab 100644 (file)
@@ -203,15 +203,15 @@ int SyncRes::doResolve(const string &qname, const QType &qtype, vector<DNSResour
       string authname(qname);
       domainmap_t::const_iterator iter=getBestAuthZone(&authname);
       if(iter != s_domainmap.end()) {
-       string server=iter->second.d_server;
-       if(server.empty()) {
+       const vector<ComboAddress>& servers = iter->second.d_servers;
+       if(servers.empty()) {
          ret.clear();
          doOOBResolve(qname, qtype, ret, depth, res);
          return res;
        }
        else {
-         LOG<<prefix<<qname<<": forwarding query to hardcoded nameserver '"<<server<<"' for zone '"<<authname<<"'"<<endl;
-         ComboAddress remoteIP(server, 53);
+         const ComboAddress remoteIP = servers.front();
+         LOG<<prefix<<qname<<": forwarding query to hardcoded nameserver '"<< remoteIP.toStringWithPort()<<"' for zone '"<<authname<<"'"<<endl;
 
          res=asyncresolve(remoteIP, qname, qtype.getCode(), false, false, &d_now, &lwr);    
          // filter out the good stuff from lwr.result()
@@ -372,12 +372,17 @@ SyncRes::domainmap_t::const_iterator SyncRes::getBestAuthZone(string* qname)
 string SyncRes::getBestNSNamesFromCache(const string &qname, set<string, CIStringCompare>& nsset, bool* flawedNSSet, int depth, set<GetBestNSAnswer>&beenthere)
 {
   string subdomain(qname);
-
   string authdomain(qname);
   
   domainmap_t::const_iterator iter=getBestAuthZone(&authdomain);
   if(iter!=s_domainmap.end()) {
-    nsset.insert(iter->second.d_server); // this gets picked up in doResolveAt, if empty it means "we are auth", otherwise it denotes a forward
+    if( iter->second.d_servers.empty() )
+      nsset.insert(string()); // this gets picked up in doResolveAt, if empty it means "we are auth", otherwise it denotes a forward
+    else {
+      for(vector<ComboAddress>::const_iterator server=iter->second.d_servers.begin(); server != iter->second.d_servers.end(); ++server)
+       nsset.insert(server->toStringWithPort());
+    }
+
     return authdomain;
   }
 
@@ -625,8 +630,12 @@ int SyncRes::doResolveAt(set<string, CIStringCompare> nameservers, string auth,
       else {
        LOG<<prefix<<qname<<": Trying to resolve NS '"<<*tns<<"' ("<<1+tns-rnameservers.begin()<<"/"<<(unsigned int)rnameservers.size()<<")"<<endl;
        if(!isCanonical(*tns)) {
-         LOG<<prefix<<qname<<": Domain has hardcoded nameserver"<<endl;
-         remoteIPs.push_back(ComboAddress(*tns, 53));
+         LOG<<prefix<<qname<<": Domain has hardcoded nameserver(s)"<<endl;
+
+         pair<string,string> ipport=splitField(*tns, ':');
+         ComboAddress addr(ipport.first, ipport.second.empty() ? 53 : lexical_cast<uint16_t>(ipport.second));
+
+         remoteIPs.push_back(addr);
        }
        else
          remoteIPs=getAs(*tns, depth+1, beenthere);
@@ -648,7 +657,7 @@ int SyncRes::doResolveAt(set<string, CIStringCompare> nameservers, string auth,
        }
 
        for(remoteIP = remoteIPs.begin(); remoteIP != remoteIPs.end(); ++remoteIP) {
-         LOG<<prefix<<qname<<": Trying IP "<< remoteIP->toString() <<", asking '"<<qname<<"|"<<qtype.getName()<<"'"<<endl;
+         LOG<<prefix<<qname<<": Trying IP "<< remoteIP->toStringWithPort() <<", asking '"<<qname<<"|"<<qtype.getName()<<"'"<<endl;
          extern NetmaskGroup* g_dontQuery;
          
          if(s_throttle.shouldThrottle(d_now.tv_sec, make_tuple(*remoteIP, qname, qtype.getCode()))) {
index 5f032eeb38bff34c3692a298368047702182700f..7d455136dc7fd628d510965165c06fb32b87e42a 100644 (file)
@@ -326,7 +326,7 @@ public:
 
   struct AuthDomain
   {
-    string d_server;
+    vector<ComboAddress> d_servers;
     typedef multi_index_container <
       DNSResourceRecord,
       indexed_by <