/*
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
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>
<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>
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;
}
}
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;
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")) {
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()
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;
}
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);
}
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()))) {
struct AuthDomain
{
- string d_server;
+ vector<ComboAddress> d_servers;
typedef multi_index_container <
DNSResourceRecord,
indexed_by <