\brief This file implements the tcpreceiver that receives and answers questions over TCP/IP
*/
-std::mutex TCPNameserver::s_plock;
std::unique_ptr<Semaphore> TCPNameserver::d_connectionroom_sem{nullptr};
-std::unique_ptr<PacketHandler> TCPNameserver::s_P{nullptr};
+LockGuarded<std::unique_ptr<PacketHandler>> TCPNameserver::s_P{nullptr};
unsigned int TCPNameserver::d_maxTCPConnections = 0;
NetmaskGroup TCPNameserver::d_ng;
size_t TCPNameserver::d_maxTransactionsPerConn;
size_t TCPNameserver::d_maxConnectionsPerClient;
unsigned int TCPNameserver::d_idleTimeout;
unsigned int TCPNameserver::d_maxConnectionDuration;
-std::mutex TCPNameserver::s_clientsCountMutex;
-std::map<ComboAddress,size_t,ComboAddress::addressOnlyLessThan> TCPNameserver::s_clientsCount;
+LockGuarded<std::map<ComboAddress,size_t,ComboAddress::addressOnlyLessThan>> TCPNameserver::s_clientsCount;
void TCPNameserver::go()
{
g_log<<Logger::Error<<"Creating backend connection for TCP"<<endl;
- s_P.reset();
+ s_P.lock()->reset();
try {
- s_P=make_unique<PacketHandler>();
+ *(s_P.lock()) = make_unique<PacketHandler>();
}
catch(PDNSException &ae) {
g_log<<Logger::Error<<"TCP server is unable to launch backends - will try again when questions come in: "<<ae.reason<<endl;
void TCPNameserver::decrementClientCount(const ComboAddress& remote)
{
if (d_maxConnectionsPerClient) {
- std::lock_guard<std::mutex> lock(s_clientsCountMutex);
- s_clientsCount[remote]--;
- if (s_clientsCount[remote] == 0) {
- s_clientsCount.erase(remote);
+ auto count = s_clientsCount.lock();
+ auto it = count->find(remote);
+ if (it == count->end()) {
+ // this is worrying, but nothing we can do at this point
+ return;
+ }
+ --it->second;
+ if (it->second == 0) {
+ count->erase(it);
}
}
}
}
}
{
- std::lock_guard<std::mutex> l(s_plock);
- if(!s_P) {
+ auto packetHandler = s_P.lock();
+ if (!*packetHandler) {
g_log<<Logger::Warning<<"TCP server is without backend connections, launching"<<endl;
- s_P=make_unique<PacketHandler>();
+ *packetHandler = make_unique<PacketHandler>();
}
- reply= s_P->doQuestion(*packet); // we really need to ask the backend :-)
+ reply = (*packetHandler)->doQuestion(*packet); // we really need to ask the backend :-)
}
if(!reply) // unable to write an answer?
}
}
catch(PDNSException &ae) {
- std::lock_guard<std::mutex> l(s_plock);
- s_P.reset(); // on next call, backend will be recycled
+ s_P.lock()->reset(); // on next call, backend will be recycled
g_log<<Logger::Error<<"TCP nameserver had error, cycling backend: "<<ae.reason<<endl;
}
catch(NetworkError &e) {
}
-// call this method with s_plock held!
-bool TCPNameserver::canDoAXFR(std::unique_ptr<DNSPacket>& q, bool isAXFR)
+bool TCPNameserver::canDoAXFR(std::unique_ptr<DNSPacket>& q, bool isAXFR, std::unique_ptr<PacketHandler>& packetHandler)
{
if(::arg().mustDo("disable-axfr"))
return false;
TSIGRecordContent trc;
DNSName keyname;
string secret;
- if(!q->checkForCorrectTSIG(s_P->getBackend(), &keyname, &secret, &trc)) {
+ if(!q->checkForCorrectTSIG(packetHandler->getBackend(), &keyname, &secret, &trc)) {
return false;
} else {
getTSIGHashEnum(trc.d_algoName, q->d_tsig_algo);
}
- DNSSECKeeper dk(s_P->getBackend());
+ DNSSECKeeper dk(packetHandler->getBackend());
if(!dk.TSIGGrantsAccess(q->qdomain, keyname)) {
g_log<<Logger::Warning<<logPrefix<<"denied: key with name '"<<keyname<<"' and algorithm '"<<getTSIGAlgoName(q->d_tsig_algo)<<"' does not grant access"<<endl;
return false;
// cerr<<"doing per-zone-axfr-acls"<<endl;
SOAData sd;
- if(s_P->getBackend()->getSOAUncached(q->qdomain,sd)) {
+ if(packetHandler->getBackend()->getSOAUncached(q->qdomain,sd)) {
// cerr<<"got backend and SOA"<<endl;
vector<string> acl;
- s_P->getBackend()->getDomainMetadata(q->qdomain, "ALLOW-AXFR-FROM", acl);
+ packetHandler->getBackend()->getDomainMetadata(q->qdomain, "ALLOW-AXFR-FROM", acl);
for (const auto & i : acl) {
// cerr<<"matching against "<<*i<<endl;
if(pdns_iequals(i, "AUTO-NS")) {
nsset.insert(DNSName(rr.content));
}
for(const auto & j: nsset) {
- vector<string> nsips=fns.lookup(j, s_P->getBackend());
+ vector<string> nsips=fns.lookup(j, packetHandler->getBackend());
for(const auto & nsip : nsips) {
// cerr<<"got "<<*k<<" from AUTO-NS"<<endl;
if(nsip == q->getRemote().toString())
// determine if zone exists and AXFR is allowed using existing backend before spawning a new backend.
SOAData sd;
{
- std::lock_guard<std::mutex> l(s_plock);
+ auto packetHandler = s_P.lock();
DLOG(g_log<<logPrefix<<"looking for SOA"<<endl); // find domain_id via SOA and list complete domain. No SOA, no AXFR
- if(!s_P) {
+ if(!*packetHandler) {
g_log<<Logger::Warning<<"TCP server is without backend connections in doAXFR, launching"<<endl;
- s_P=make_unique<PacketHandler>();
+ *packetHandler = make_unique<PacketHandler>();
}
// canDoAXFR does all the ACL checks, and has the if(disable-axfr) shortcut, call it first.
- if (!canDoAXFR(q, true)) {
+ if (!canDoAXFR(q, true, *packetHandler)) {
g_log<<Logger::Warning<<logPrefix<<"failed: client may not request AXFR"<<endl;
outpacket->setRcode(RCode::NotAuth);
sendPacket(outpacket,outsock);
return 0;
}
- if(!s_P->getBackend()->getSOAUncached(target, sd)) {
+ if(!(*packetHandler)->getBackend()->getSOAUncached(target, sd)) {
g_log<<Logger::Warning<<logPrefix<<"failed: not authoritative"<<endl;
outpacket->setRcode(RCode::NotAuth);
sendPacket(outpacket,outsock);
bool securedZone;
bool serialPermitsIXFR;
{
- std::lock_guard<std::mutex> l(s_plock);
+ auto packetHandler = s_P.lock();
DLOG(g_log<<logPrefix<<"Looking for SOA"<<endl); // find domain_id via SOA and list complete domain. No SOA, no IXFR
- if(!s_P) {
+ if(!*packetHandler) {
g_log<<Logger::Warning<<"TCP server is without backend connections in doIXFR, launching"<<endl;
- s_P=make_unique<PacketHandler>();
+ *packetHandler = make_unique<PacketHandler>();
}
// canDoAXFR does all the ACL checks, and has the if(disable-axfr) shortcut, call it first.
- if(!canDoAXFR(q, false) || !s_P->getBackend()->getSOAUncached(q->qdomain, sd)) {
+ if(!canDoAXFR(q, false, *packetHandler) || !(*packetHandler)->getBackend()->getSOAUncached(q->qdomain, sd)) {
g_log<<Logger::Warning<<logPrefix<<"failed: not authoritative"<<endl;
outpacket->setRcode(RCode::NotAuth);
sendPacket(outpacket,outsock);
return 0;
}
- DNSSECKeeper dk(s_P->getBackend());
+ DNSSECKeeper dk((*packetHandler)->getBackend());
DNSSECKeeper::clearCaches(q->qdomain);
bool narrow;
securedZone = dk.isSecuredZone(q->qdomain);
}
else {
if (d_maxConnectionsPerClient) {
- std::lock_guard<std::mutex> lock(s_clientsCountMutex);
- if (s_clientsCount[remote] >= d_maxConnectionsPerClient) {
+ auto clientsCount = s_clientsCount.lock();
+ if ((*clientsCount)[remote] >= d_maxConnectionsPerClient) {
g_log<<Logger::Notice<<"Limit of simultaneous TCP connections per client reached for "<< remote<<", dropping"<<endl;
close(fd);
continue;
}
- s_clientsCount[remote]++;
+ (*clientsCount)[remote]++;
}
d_connectionroom_sem->wait(); // blocks if no connections are available