Ztsig.com:ns1.example.com.:ahu.example.com.:2000081501:28800:7200:604800:86400:120
&tsig.com::ns1.example.com.:120
&tsig.com::ns2.example.com.:120
+#2000081501 auto axfr-get
+Zstest.com:ns1.example.com.:ahu.example.com.:2000081501:28800:7200:604800:86400:120
+&stest.com::ns1.example.com.:120
+&stest.com::ns2.example.com.:120
Resolver::Resolver()
try
{
- d_sock4 = d_sock6 = 0;
- d_sock4 = makeQuerySocket(ComboAddress(::arg()["query-local-address"]), true);
+ locals["default4"] = makeQuerySocket(ComboAddress(::arg()["query-local-address"]), true);
if(!::arg()["query-local-address6"].empty())
- d_sock6 = makeQuerySocket(ComboAddress(::arg()["query-local-address6"]), true);
+ locals["default6"] = makeQuerySocket(ComboAddress(::arg()["query-local-address6"]), true);
else
- d_sock6 = -1;
+ locals["default6"] = -1;
}
catch(...) {
- if(d_sock4>=0)
- close(d_sock4);
+ if(locals["default4"]>=0)
+ close(locals["default4"]);
throw;
}
Resolver::~Resolver()
{
- if(d_sock4>=0)
- Utility::closesocket(d_sock4);
- if(d_sock6>=0)
- Utility::closesocket(d_sock6);
+ for(std::map<std::string,int>::iterator iter = locals.begin(); iter != locals.end(); iter++) {
+ close(iter->second);
+ }
}
-uint16_t Resolver::sendResolve(const ComboAddress& remote, const char *domain, int type, bool dnssecOK,
+uint16_t Resolver::sendResolve(const ComboAddress& remote, const ComboAddress& local,
+ const char *domain, int type, bool dnssecOK,
const string& tsigkeyname, const string& tsigalgorithm,
const string& tsigsecret)
{
trc.d_eRcode=0;
addTSIG(pw, &trc, tsigkeyname, tsigsecret, "", false);
}
-
- int sock = remote.sin4.sin_family == AF_INET ? d_sock4 : d_sock6;
+
+ int sock;
+
+ // choose socket based on local
+ if (local.sin4.sin_family == 0) {
+ // up to us.
+ sock = remote.sin4.sin_family == AF_INET ? locals["default4"] : locals["default6"];
+ } else {
+ std::string lstr = local.toString();
+ std::map<std::string, int>::iterator lptr;
+ // see if there is a local
+
+ if ((lptr = locals.find(lstr)) != locals.end()) {
+ sock = lptr->second;
+ } else {
+ // try to make socket
+ sock = makeQuerySocket(local, true);
+ locals[lstr] = sock;
+ }
+ }
if(sendto(sock, &packet[0], packet.size(), 0, (struct sockaddr*)(&remote), remote.getSocklen()) < 0) {
throw ResolverException("Unable to ask query of "+remote.toStringWithPort()+": "+stringerror());
return randomid;
}
+uint16_t Resolver::sendResolve(const ComboAddress& remote, const char *domain,
+ int type, bool dnssecOK,
+ const string& tsigkeyname, const string& tsigalgorithm,
+ const string& tsigsecret)
+{
+ ComboAddress local;
+ local.sin4.sin_family = 0;
+ return this->sendResolve(remote, local, domain, type, dnssecOK, tsigkeyname, tsigalgorithm, tsigsecret);
+}
+
static int parseResult(MOADNSParser& mdp, const std::string& origQname, uint16_t origQtype, uint16_t id, Resolver::res_t* result)
{
result->clear();
bool Resolver::tryGetSOASerial(string* domain, uint32_t *theirSerial, uint32_t *theirInception, uint32_t *theirExpire, uint16_t* id)
{
- Utility::setNonBlocking( d_sock4 );
- Utility::setNonBlocking( d_sock6 );
-
+ struct pollfd *fds = new struct pollfd[locals.size()];
+ size_t i = 0, k;
int sock;
- if(!waitFor2Data(d_sock4, d_sock6, 0, 250000, &sock)) // lame function, I know..
- return false;
-
+
+ for(std::map<string,int>::iterator iter=locals.begin(); iter != locals.end(); iter++, i++) {
+ fds[i].fd = iter->second;
+ fds[i].events = POLLIN;
+ }
+
+ if (poll(fds, i, 250) < 1) { // wait for 0.25s
+ delete [] fds;
+ return false;
+ }
+
+ sock = -1;
+
+ // determine who
+ for(k=0;k<i;k++) {
+ if ((fds[k].revents & POLLIN) == POLLIN) {
+ sock = fds[k].fd;
+ break;
+ }
+ }
+
+ delete [] fds;
+
+ if (sock < 0) return false; // false alarm
+
int err;
ComboAddress fromaddr;
socklen_t addrlen=fromaddr.getSocklen();
if(err < 0) {
if(errno == EAGAIN)
return false;
-
+
throw ResolverException("recvfrom error waiting for answer: "+stringerror());
}
-
+
MOADNSParser mdp((char*)buf, err);
*id=mdp.d_header.id;
*domain = stripDot(mdp.d_qname);
return true;
}
-int Resolver::resolve(const string &ipport, const char *domain, int type, Resolver::res_t* res)
+int Resolver::resolve(const string &ipport, const char *domain, int type, Resolver::res_t* res, const ComboAddress &local)
{
try {
ComboAddress to(ipport, 53);
- int id = sendResolve(to, domain, type);
- int sock = to.sin4.sin_family == AF_INET ? d_sock4 : d_sock6;
+ int id = sendResolve(to, local, domain, type);
+ int sock;
+
+ // choose socket based on local
+ if (local.sin4.sin_family == 0) {
+ // up to us.
+ sock = to.sin4.sin_family == AF_INET ? locals["default4"] : locals["default6"];
+ } else {
+ std::string lstr = local.toString();
+ std::map<std::string, int>::iterator lptr;
+ // see if there is a local
+
+ if ((lptr = locals.find(lstr)) != locals.end()) sock = lptr->second;
+ else throw ResolverException("sendResolve did not create socket for " + lstr);
+ }
+
int err=waitForData(sock, 0, 3000000);
if(!err) {
return -1;
}
-
+int Resolver::resolve(const string &ipport, const char *domain, int type, Resolver::res_t* res) {
+ ComboAddress local;
+ local.sin4.sin_family = 0;
+ return resolve(ipport, domain, type, res, local);
+}
void Resolver::getSoaSerial(const string &ipport, const string &domain, uint32_t *serial)
{
typedef vector<DNSResourceRecord> res_t;
//! synchronously resolve domain|type at IP, store result in result, rcode in ret
+ int resolve(const string &ip, const char *domain, int type, res_t* result, const ComboAddress& local);
+
int resolve(const string &ip, const char *domain, int type, res_t* result);
-
+
//! only send out a resolution request
+ uint16_t sendResolve(const ComboAddress& remote, const ComboAddress& local, const char *domain, int type, bool dnssecOk=false,
+ const string& tsigkeyname="", const string& tsigalgorithm="", const string& tsigsecret="");
+
uint16_t sendResolve(const ComboAddress& remote, const char *domain, int type, bool dnssecOk=false,
const string& tsigkeyname="", const string& tsigalgorithm="", const string& tsigsecret="");
-
+
//! see if we got a SOA response from our sendResolve
bool tryGetSOASerial(string* theirDomain, uint32_t* theirSerial, uint32_t* theirInception, uint32_t* theirExpire, uint16_t* id);
void getSoaSerial(const string &, const string &, uint32_t *);
private:
- int d_sock4, d_sock6;
-
+ std::map<std::string, int> locals;
+
uint16_t d_randomid;
};
{
DomainInfo di;
bool dnssecOk;
+ ComboAddress localaddr;
string tsigkeyname, tsigalgname, tsigsecret;
};
}
random_shuffle(dni.di.masters.begin(), dni.di.masters.end());
try {
ComboAddress remote(*dni.di.masters.begin());
- return make_pair(dni.di.zone,
- d_resolver.sendResolve(ComboAddress(*dni.di.masters.begin(), 53),
- dni.di.zone.c_str(),
- QType::SOA,
- dni.dnssecOk, dni.tsigkeyname, dni.tsigalgname, dni.tsigsecret)
- );
+ if (dni.localaddr.sin4.sin_family == 0) {
+ return make_pair(dni.di.zone,
+ d_resolver.sendResolve(ComboAddress(*dni.di.masters.begin(), 53),
+ dni.di.zone.c_str(),
+ QType::SOA,
+ dni.dnssecOk, dni.tsigkeyname, dni.tsigalgname, dni.tsigsecret)
+ );
+ } else {
+ return make_pair(dni.di.zone,
+ d_resolver.sendResolve(ComboAddress(*dni.di.masters.begin(), 53), dni.localaddr,
+ dni.di.zone.c_str(),
+ QType::SOA,
+ dni.dnssecOk, dni.tsigkeyname, dni.tsigalgname, dni.tsigsecret)
+ );
+ }
}
catch(PDNSException& e) {
throw runtime_error("While attempting to query freshness of '"+dni.di.zone+"': "+e.reason);
domains_by_name_t& nameindex=boost::multi_index::get<IDTag>(d_suckdomains);
BOOST_FOREACH(DomainInfo& di, rdomains) {
+ std::vector<std::string> localaddr;
SuckRequest sr;
sr.domain=di.zone;
if(di.masters.empty()) // slave domains w/o masters are ignored
B->getTSIGKey(dni.tsigkeyname, &dni.tsigalgname, &secret64);
B64Decode(secret64, dni.tsigsecret);
}
+
+ localaddr.clear();
+ // check for AXFR-SOURCE
+ if(B->getDomainMetadata(di.zone, "AXFR-SOURCE", localaddr) && !localaddr.empty()) {
+ try {
+ dni.localaddr = ComboAddress(localaddr[0]);
+ L<<Logger::Info<<"Freshness check source (AXFR-SOURCE) for domain '"<<di.zone<<"' set to "<<localaddr[0]<<endl;
+ }
+ catch(std::exception& e) {
+ L<<Logger::Error<<"Failed to load freshness check source '"<<localaddr[0]<<"' for '"<<di.zone<<"': "<<e.what()<<endl;
+ return;
+ }
+ } else {
+ dni.localaddr.sin4.sin_family = 0;
+ }
+
sdomains.push_back(dni);
}
}
a63dc120391d9df0003f2ec4f461a6af ../regression-tests/secure-delegated.dnssec-parent.com
24514dc104b22206daeb973ff9303545 ../regression-tests/minimal.com
0b20d7a0250576451135483b863750bf ../regression-tests/tsig.com
-113e496cbfb8528775697bdc44deea9d ../modules/tinydnsbackend/data.cdb
+b1f775045fa2cf0a3b91aa834af06e49 ../regression-tests/stest.com
+4d3d89309ee74b0b7c44042de92eb9e1 ../modules/tinydnsbackend/data.cdb
--- /dev/null
+function prequery ( dnspacket )
+ qname, qtype = dnspacket:getQuestion()
+ remote = dnspacket:getRemote()
+ if qname == "stest.com" and remote != "127.0.0.2":
+ return false
+ return true
+end
type master;
file "./tsig.com";
};
+
+zone "stest.com"{
+ type master;
+ file "./stest.com";
+};
fi
+# check for lua
+if grep -q "^#define HAVE_LUA 1" ../config.h
+then
+ lua_prequery="--lua-prequery-script=./check_stest_source"
+ skiplua=0
+else
+ lua_prequery=""
+ skiplua=1
+fi
+
case $context in
ext-nsd | ext-nsd-nsec | ext-nsd-nsec3 | ext-nsd-nsec3-optout)
case $context in
--send-root-referral \
--allow-2136-from=127.0.0.0/8 --experimental-rfc2136=yes --experimental-direct-dnskey=yes \
--cache-ttl=$cachettl --no-config \
- --bind-ignore-broken-records=yes &
+ --bind-ignore-broken-records=yes $lua_prequery &
bindwait
;;
--gmysql-dbname="$GMYSQLDB" \
--gmysql-user="$GMYSQLUSER" \
--gmysql-host="$GMYSQLHOST" \
- --gmysql-password="$GMYSQLPASSWD" &
+ --gmysql-password="$GMYSQLPASSWD" $lua_prequery &
if [ $context = gmysql-nsec3 ]
then
extracontexts="dnssec nsec3"
--allow-2136-from=127.0.0.0/8 --experimental-rfc2136=yes \
--cache-ttl=$cachettl --no-config \
--gpgsql-dbname="$GPGSQLDB" \
- --gpgsql-user="$GPGSQLUSER" &
+ --gpgsql-user="$GPGSQLUSER" $lua_prequery &
if [ $context = gpgsql-nsec3 ]
then
extracontexts="dnssec nsec3"
--send-root-referral \
--allow-2136-from=127.0.0.0/8 --experimental-rfc2136=yes \
--cache-ttl=$cachettl --no-config \
- --gsqlite3-database=pdns.sqlite3 &
+ --gsqlite3-database=pdns.sqlite3 $lua_prequery &
if [ $context = gsqlite3-nsec3 ]
then
extracontexts="dnssec nsec3"
exit 1
esac
+if [ "$skiplua" == "1" ]; then
+ skipreasons="$skipreaasons nolua"
+fi
+
check_process
startslave ()
-e "INSERT INTO tsigkeys (name, algorithm,secret) VALUES('test', '$ALGORITHM', '$KEY')"
mysql --user="$GMYSQL2USER" --password="$GMYSQL2PASSWD" --host="$GMYSQL2HOST" "$GMYSQL2DB" \
-e "INSERT INTO domainmetadata (domain_id, kind, content) SELECT id, 'AXFR-MASTER-TSIG', 'test' FROM domains WHERE name = 'tsig.com'"
+ echo $skipreasons | grep -q nolua
+ if [ $? -ne 0 ]; then
+ mysql --user="$GMYSQL2USER" --password="$GMYSQL2PASSWD" --host="$GMYSQL2HOST" "$GMYSQL2DB" \
+ -e "INSERT INTO domainmetadata (domain_id,kind,content) SELECT id,'AXFR-SOURCE','127.0.0.2' FROM domains WHERE name = 'stest.com'"
+ fi
fi
set -e
if [ $? -ne 0 ]; then
sqlite3 pdns.sqlite31 "INSERT INTO tsigkeys (name,algorithm,secret) VALUES('test','$ALGORITHM', '$KEY')"
sqlite3 pdns.sqlite31 "INSERT INTO domainmetadata (domain_id, kind, content) SELECT id, 'AXFR-MASTER-TSIG', 'test' FROM domains WHERE name = 'tsig.com'"
+ echo $skipreasons | grep -q nolua
+ if [ $? -ne 0 ]; then
+ sqlite3 pdns.sqlite31 "INSERT INTO domainmetadata (domain_id,kind,content) SELECT id,'AXFR-SOURCE','127.0.0.2' FROM domains WHERE name = 'stest.com'"
+ fi
fi
set -e
if [ $? -ne 0 ]; then
sqlite3 dnssec-slave.sqlite3 "INSERT INTO tsigkeys (name, algorithm,secret) VALUES('test', '$ALGORITHM', '$KEY')"
sqlite3 dnssec-slave.sqlite3 "INSERT INTO domainmetadata (domain, kind, content) SELECT 'tsig.com', 'AXFR-MASTER-TSIG', 'test'"
+ echo $skipreasons | grep -q nolua
+ if [ $? -ne 0 ]; then
+ sqlite3 dnssec-slave.sqlite3 "INSERT INTO domainmetadata (domain,kind,content) SELECT 'stest.com','AXFR-SOURCE','127.0.0.2'"
+ fi
fi
set -e
--- /dev/null
+$TTL 120
+$ORIGIN stest.com.
+@ IN SOA ns1.example.com. ahu.example.com. (
+ 2000081501
+ 8H ; refresh
+ 2H ; retry
+ 1W ; expire
+ 1D ; default_ttl
+ )
+
+@ IN NS ns1.example.com.
+@ IN NS ns2.example.com.
OK
RETVAL: 0
+--- ldns-verify-zone -V2 stest.com
+RETVAL: 0
+
+--- validns stest.com
+RETVAL: 0
+
+--- jdnssec-verifyzone stest.com
+zone verified.
+RETVAL: 0
+
+--- named-checkzone stest.com
+zone stest.com/IN: loaded serial 2000081501 (DNSSEC signed)
+OK
+RETVAL: 0
+