2 * This file is part of PowerDNS or dnsdist.
3 * Copyright -- PowerDNS.COM B.V. and its contributors
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of version 2 of the GNU General Public License as
7 * published by the Free Software Foundation.
9 * In addition, for the avoidance of any doubt, permission is granted to
10 * link this program with OpenSSL and to (re)distribute the binaries
11 * produced as the result of such linking.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
30 #include "ws-recursor.hh"
32 #include "recpacketcache.hh"
34 #include "dns_random.hh"
38 #include "opensslsigners.hh"
41 #include <boost/static_assert.hpp>
44 #include "recursor_cache.hh"
45 #include "cachecleaner.hh"
52 #include "arguments.hh"
56 #include "sortlist.hh"
58 #include <boost/tuple/tuple.hpp>
59 #include <boost/tuple/tuple_comparison.hpp>
60 #include <boost/shared_array.hpp>
61 #include <boost/function.hpp>
62 #include <boost/algorithm/string.hpp>
64 #include "malloctrace.hh"
66 #include <netinet/tcp.h>
67 #include "dnsparser.hh"
68 #include "dnswriter.hh"
69 #include "dnsrecords.hh"
70 #include "zoneparser-tng.hh"
71 #include "rec_channel.hh"
76 #include "lua-recursor4.hh"
78 #include "responsestats.hh"
79 #include "secpoll-recursor.hh"
81 #include "filterpo.hh"
82 #include "rpzloader.hh"
83 #include "validate-recursor.hh"
84 #include "rec-lua-conf.hh"
85 #include "ednsoptions.hh"
88 #include "rec-protobuf.hh"
89 #include "rec-snmp.hh"
92 #include <systemd/sd-daemon.h>
95 #include "namespaces.hh"
97 typedef map
<ComboAddress
, uint32_t, ComboAddress::addressOnlyLessThan
> tcpClientCounts_t
;
99 static thread_local
std::shared_ptr
<RecursorLua4
> t_pdl
;
100 static thread_local
unsigned int t_id
;
101 static thread_local
std::shared_ptr
<Regex
> t_traceRegex
;
102 static thread_local
std::unique_ptr
<tcpClientCounts_t
> t_tcpClientCounts
;
104 thread_local
std::unique_ptr
<MT_t
> MT
; // the big MTasker
105 thread_local
std::unique_ptr
<MemRecursorCache
> t_RC
;
106 thread_local
std::unique_ptr
<RecursorPacketCache
> t_packetCache
;
107 thread_local FDMultiplexer
* t_fdm
{nullptr};
108 thread_local
std::unique_ptr
<addrringbuf_t
> t_remotes
, t_servfailremotes
, t_largeanswerremotes
;
109 thread_local
std::unique_ptr
<boost::circular_buffer
<pair
<DNSName
, uint16_t> > > t_queryring
, t_servfailqueryring
;
110 thread_local
std::shared_ptr
<NetmaskGroup
> t_allowFrom
;
112 thread_local
std::unique_ptr
<boost::uuids::random_generator
> t_uuidGenerator
;
114 __thread
struct timeval g_now
; // timestamp, updated (too) frequently
116 // for communicating with our threads
125 typedef vector
<int> tcpListenSockets_t
;
126 typedef map
<int, ComboAddress
> listenSocketsAddresses_t
; // is shared across all threads right now
127 typedef vector
<pair
<int, function
< void(int, any
&) > > > deferredAdd_t
;
129 static const ComboAddress
g_local4("0.0.0.0"), g_local6("::");
130 static vector
<ThreadPipeSet
> g_pipes
; // effectively readonly after startup
131 static tcpListenSockets_t g_tcpListenSockets
; // shared across threads, but this is fine, never written to from a thread. All threads listen on all sockets
132 static listenSocketsAddresses_t g_listenSocketsAddresses
; // is shared across all threads right now
133 static std::unordered_map
<unsigned int, deferredAdd_t
> deferredAdds
;
134 static set
<int> g_fromtosockets
; // listen sockets that use 'sendfromto()' mechanism
135 static vector
<ComboAddress
> g_localQueryAddresses4
, g_localQueryAddresses6
;
136 static AtomicCounter counter
;
137 static std::shared_ptr
<SyncRes::domainmap_t
> g_initialDomainMap
; // new threads needs this to be setup
138 static std::shared_ptr
<NetmaskGroup
> g_initialAllowFrom
; // new thread needs to be setup with this
139 static size_t g_tcpMaxQueriesPerConn
;
140 static uint64_t g_latencyStatSize
;
141 static uint32_t g_disthashseed
;
142 static unsigned int g_maxTCPPerClient
;
143 static unsigned int g_networkTimeoutMsec
;
144 static unsigned int g_maxMThreads
;
145 static unsigned int g_numWorkerThreads
;
146 static int g_tcpTimeout
;
147 static uint16_t g_udpTruncationThreshold
;
148 static std::atomic
<bool> statsWanted
;
149 static std::atomic
<bool> g_quiet
;
150 static bool g_logCommonErrors
;
151 static bool g_anyToTcp
;
152 static bool g_weDistributeQueries
; // if true, only 1 thread listens on the incoming query sockets
153 static bool g_reusePort
{false};
154 static bool g_useOneSocketPerThread
;
155 static bool g_gettagNeedsEDNSOptions
{false};
156 static time_t g_statisticsInterval
;
157 static bool g_useIncomingECS
;
158 std::atomic
<uint32_t> g_maxCacheEntries
, g_maxPacketCacheEntries
;
160 RecursorControlChannel s_rcc
; // only active in thread 0
161 RecursorStats g_stats
;
162 string s_programname
="pdns_recursor";
164 bool g_lowercaseOutgoing
;
165 unsigned int g_numThreads
;
166 uint16_t g_outgoingEDNSBufsize
;
167 bool g_logRPZChanges
{false};
169 #define LOCAL_NETS "127.0.0.0/8, 10.0.0.0/8, 100.64.0.0/10, 169.254.0.0/16, 192.168.0.0/16, 172.16.0.0/12, ::1/128, fc00::/7, fe80::/10"
170 // Bad Nets taken from both:
171 // http://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml
173 // http://www.iana.org/assignments/iana-ipv6-special-registry/iana-ipv6-special-registry.xhtml
174 // where such a network may not be considered a valid destination
175 #define BAD_NETS "0.0.0.0/8, 192.0.0.0/24, 192.0.2.0/24, 198.51.100.0/24, 203.0.113.0/24, 240.0.0.0/4, ::/96, ::ffff:0:0/96, 100::/64, 2001:db8::/32"
176 #define DONT_QUERY LOCAL_NETS ", " BAD_NETS
178 //! used to send information to a newborn mthread
179 struct DNSComboWriter
{
180 DNSComboWriter(const char* data
, uint16_t len
, const struct timeval
& now
) : d_mdp(true, data
, len
), d_now(now
),
181 d_tcp(false), d_socket(-1)
184 void setRemote(const ComboAddress
* sa
)
189 void setLocal(const ComboAddress
& sa
)
195 void setSocket(int sock
)
200 string
getRemote() const
202 return d_remote
.toString();
205 struct timeval d_now
;
206 ComboAddress d_remote
, d_local
;
208 boost::uuids::uuid d_uuid
;
209 string d_requestorId
;
212 EDNSSubnetOpts d_ednssubnet
;
213 bool d_ecsFound
{false};
214 bool d_ecsParsed
{false};
217 unsigned int d_tag
{0};
220 shared_ptr
<TCPConnection
> d_tcpConnection
;
221 vector
<pair
<uint16_t, string
> > d_ednsOpts
;
222 std::vector
<std::string
> d_policyTags
;
223 LuaContext::LuaObject d_data
;
228 return MT
? MT
.get() : nullptr;
233 static ArgvMap theArg
;
237 unsigned int getRecursorThreadId()
247 static void handleTCPClientWritable(int fd
, FDMultiplexer::funcparam_t
& var
);
249 // -1 is error, 0 is timeout, 1 is success
250 int asendtcp(const string
& data
, Socket
* sock
)
256 t_fdm
->addWriteFD(sock
->getHandle(), handleTCPClientWritable
, pident
);
259 int ret
=MT
->waitEvent(pident
, &packet
, g_networkTimeoutMsec
);
261 if(!ret
|| ret
==-1) { // timeout
262 t_fdm
->removeWriteFD(sock
->getHandle());
264 else if(packet
.size() !=data
.size()) { // main loop tells us what it sent out, or empty in case of an error
270 static void handleTCPClientReadable(int fd
, FDMultiplexer::funcparam_t
& var
);
272 // -1 is error, 0 is timeout, 1 is success
273 int arecvtcp(string
& data
, size_t len
, Socket
* sock
, bool incompleteOkay
)
279 pident
.inIncompleteOkay
=incompleteOkay
;
280 t_fdm
->addReadFD(sock
->getHandle(), handleTCPClientReadable
, pident
);
282 int ret
=MT
->waitEvent(pident
,&data
, g_networkTimeoutMsec
);
283 if(!ret
|| ret
==-1) { // timeout
284 t_fdm
->removeReadFD(sock
->getHandle());
286 else if(data
.empty()) {// error, EOF or other
293 static void handleGenUDPQueryResponse(int fd
, FDMultiplexer::funcparam_t
& var
)
295 PacketID pident
=*any_cast
<PacketID
>(&var
);
297 ssize_t ret
=recv(fd
, resp
, sizeof(resp
), 0);
298 t_fdm
->removeReadFD(fd
);
300 string
data(resp
, (size_t) ret
);
301 MT
->sendEvent(pident
, &data
);
305 MT
->sendEvent(pident
, &empty
);
306 // cerr<<"Had some kind of error: "<<ret<<", "<<strerror(errno)<<endl;
309 string
GenUDPQueryResponse(const ComboAddress
& dest
, const string
& query
)
311 Socket
s(dest
.sin4
.sin_family
, SOCK_DGRAM
);
313 ComboAddress local
= getQueryLocalAddress(dest
.sin4
.sin_family
, 0);
322 t_fdm
->addReadFD(s
.getHandle(), handleGenUDPQueryResponse
, pident
);
326 int ret
=MT
->waitEvent(pident
,&data
, g_networkTimeoutMsec
);
328 if(!ret
|| ret
==-1) { // timeout
329 t_fdm
->removeReadFD(s
.getHandle());
331 else if(data
.empty()) {// error, EOF or other
332 // we could special case this
338 //! pick a random query local address
339 ComboAddress
getQueryLocalAddress(int family
, uint16_t port
)
342 if(family
==AF_INET
) {
343 if(g_localQueryAddresses4
.empty())
346 ret
= g_localQueryAddresses4
[dns_random(g_localQueryAddresses4
.size())];
347 ret
.sin4
.sin_port
= htons(port
);
350 if(g_localQueryAddresses6
.empty())
353 ret
= g_localQueryAddresses6
[dns_random(g_localQueryAddresses6
.size())];
355 ret
.sin6
.sin6_port
= htons(port
);
360 static void handleUDPServerResponse(int fd
, FDMultiplexer::funcparam_t
&);
362 static void setSocketBuffer(int fd
, int optname
, uint32_t size
)
365 socklen_t len
=sizeof(psize
);
367 if(!getsockopt(fd
, SOL_SOCKET
, optname
, (char*)&psize
, &len
) && psize
> size
) {
368 L
<<Logger::Error
<<"Not decreasing socket buffer size from "<<psize
<<" to "<<size
<<endl
;
372 if (setsockopt(fd
, SOL_SOCKET
, optname
, (char*)&size
, sizeof(size
)) < 0 )
373 L
<<Logger::Error
<<"Unable to raise socket buffer size to "<<size
<<": "<<strerror(errno
)<<endl
;
377 static void setSocketReceiveBuffer(int fd
, uint32_t size
)
379 setSocketBuffer(fd
, SO_RCVBUF
, size
);
382 static void setSocketSendBuffer(int fd
, uint32_t size
)
384 setSocketBuffer(fd
, SO_SNDBUF
, size
);
388 // you can ask this class for a UDP socket to send a query from
389 // this socket is not yours, don't even think about deleting it
390 // but after you call 'returnSocket' on it, don't assume anything anymore
393 unsigned int d_numsocks
;
395 UDPClientSocks() : d_numsocks(0)
399 typedef set
<int> socks_t
;
402 // returning -2 means: temporary OS error (ie, out of files), -1 means error related to remote
403 int getSocket(const ComboAddress
& toaddr
, int* fd
)
405 *fd
=makeClientSocket(toaddr
.sin4
.sin_family
);
406 if(*fd
< 0) // temporary error - receive exception otherwise
409 if(connect(*fd
, (struct sockaddr
*)(&toaddr
), toaddr
.getSocklen()) < 0) {
411 // returnSocket(*fd);
415 catch(const PDNSException
& e
) {
416 L
<<Logger::Error
<<"Error closing UDP socket after connect() failed: "<<e
.reason
<<endl
;
419 if(err
==ENETUNREACH
) // Seth "My Interfaces Are Like A Yo Yo" Arnold special
429 void returnSocket(int fd
)
431 socks_t::iterator i
=d_socks
.find(fd
);
432 if(i
==d_socks
.end()) {
433 throw PDNSException("Trying to return a socket (fd="+std::to_string(fd
)+") not in the pool");
435 returnSocketLocked(i
);
438 // return a socket to the pool, or simply erase it
439 void returnSocketLocked(socks_t::iterator
& i
)
441 if(i
==d_socks
.end()) {
442 throw PDNSException("Trying to return a socket not in the pool");
445 t_fdm
->removeReadFD(*i
);
447 catch(FDMultiplexerException
& e
) {
448 // we sometimes return a socket that has not yet been assigned to t_fdm
453 catch(const PDNSException
& e
) {
454 L
<<Logger::Error
<<"Error closing returned UDP socket: "<<e
.reason
<<endl
;
461 // returns -1 for errors which might go away, throws for ones that won't
462 static int makeClientSocket(int family
)
464 int ret
=socket(family
, SOCK_DGRAM
, 0 ); // turns out that setting CLO_EXEC and NONBLOCK from here is not a performance win on Linux (oddly enough)
466 if(ret
< 0 && errno
==EMFILE
) // this is not a catastrophic error
470 throw PDNSException("Making a socket for resolver (family = "+std::to_string(family
)+"): "+stringerror());
472 // setCloseOnExec(ret); // we're not going to exec
479 if(tries
==1) // fall back to kernel 'random'
482 port
= 1025 + dns_random(64510);
484 sin
=getQueryLocalAddress(family
, port
); // does htons for us
486 if (::bind(ret
, (struct sockaddr
*)&sin
, sin
.getSocklen()) >= 0)
490 throw PDNSException("Resolver binding to local query client socket on "+sin
.toString()+": "+stringerror());
497 static thread_local
std::unique_ptr
<UDPClientSocks
> t_udpclientsocks
;
499 /* these two functions are used by LWRes */
500 // -2 is OS error, -1 is error that depends on the remote, > 0 is success
501 int asendto(const char *data
, size_t len
, int flags
,
502 const ComboAddress
& toaddr
, uint16_t id
, const DNSName
& domain
, uint16_t qtype
, int* fd
)
506 pident
.domain
= domain
;
507 pident
.remote
= toaddr
;
510 // see if there is an existing outstanding request we can chain on to, using partial equivalence function
511 pair
<MT_t::waiters_t::iterator
, MT_t::waiters_t::iterator
> chain
=MT
->d_waiters
.equal_range(pident
, PacketIDBirthdayCompare());
513 for(; chain
.first
!= chain
.second
; chain
.first
++) {
514 if(chain
.first
->key
.fd
> -1) { // don't chain onto existing chained waiter!
516 cerr<<"Orig: "<<pident.domain<<", "<<pident.remote.toString()<<", id="<<id<<endl;
517 cerr<<"Had hit: "<< chain.first->key.domain<<", "<<chain.first->key.remote.toString()<<", id="<<chain.first->key.id
518 <<", count="<<chain.first->key.chain.size()<<", origfd: "<<chain.first->key.fd<<endl;
520 chain
.first
->key
.chain
.insert(id
); // we can chain
521 *fd
=-1; // gets used in waitEvent / sendEvent later on
526 int ret
=t_udpclientsocks
->getSocket(toaddr
, fd
);
533 t_fdm
->addReadFD(*fd
, handleUDPServerResponse
, pident
);
534 ret
= send(*fd
, data
, len
, 0);
539 t_udpclientsocks
->returnSocket(*fd
);
541 errno
= tmp
; // this is for logging purposes only
545 // -1 is error, 0 is timeout, 1 is success
546 int arecvfrom(char *data
, size_t len
, int flags
, const ComboAddress
& fromaddr
, size_t *d_len
,
547 uint16_t id
, const DNSName
& domain
, uint16_t qtype
, int fd
, struct timeval
* now
)
549 static optional
<unsigned int> nearMissLimit
;
551 nearMissLimit
=::arg().asNum("spoof-nearmiss-max");
556 pident
.domain
=domain
;
558 pident
.remote
=fromaddr
;
561 int ret
=MT
->waitEvent(pident
, &packet
, g_networkTimeoutMsec
, now
);
564 if(packet
.empty()) // means "error"
567 *d_len
=packet
.size();
568 memcpy(data
,packet
.c_str(),min(len
,*d_len
));
569 if(*nearMissLimit
&& pident
.nearMisses
> *nearMissLimit
) {
570 L
<<Logger::Error
<<"Too many ("<<pident
.nearMisses
<<" > "<<*nearMissLimit
<<") bogus answers for '"<<domain
<<"' from "<<fromaddr
.toString()<<", assuming spoof attempt."<<endl
;
571 g_stats
.spoofCount
++;
577 t_udpclientsocks
->returnSocket(fd
);
582 static void writePid(void)
584 if(!::arg().mustDo("write-pid"))
586 ofstream
of(s_pidfname
.c_str(), std::ios_base::app
);
588 of
<< Utility::getpid() <<endl
;
590 L
<<Logger::Error
<<"Writing pid for "<<Utility::getpid()<<" to "<<s_pidfname
<<" failed: "<<strerror(errno
)<<endl
;
593 TCPConnection::TCPConnection(int fd
, const ComboAddress
& addr
) : d_remote(addr
), d_fd(fd
)
595 ++s_currentConnections
;
596 (*t_tcpClientCounts
)[d_remote
]++;
599 TCPConnection::~TCPConnection()
602 if(closesocket(d_fd
) < 0)
603 L
<<Logger::Error
<<"Error closing socket for TCPConnection"<<endl
;
605 catch(const PDNSException
& e
) {
606 L
<<Logger::Error
<<"Error closing TCPConnection socket: "<<e
.reason
<<endl
;
609 if(t_tcpClientCounts
->count(d_remote
) && !(*t_tcpClientCounts
)[d_remote
]--)
610 t_tcpClientCounts
->erase(d_remote
);
611 --s_currentConnections
;
614 AtomicCounter
TCPConnection::s_currentConnections
;
616 static void handleRunningTCPQuestion(int fd
, FDMultiplexer::funcparam_t
& var
);
618 // the idea is, only do things that depend on the *response* here. Incoming accounting is on incoming.
619 static void updateResponseStats(int res
, const ComboAddress
& remote
, unsigned int packetsize
, const DNSName
* query
, uint16_t qtype
)
621 if(packetsize
> 1000 && t_largeanswerremotes
)
622 t_largeanswerremotes
->push_back(remote
);
624 case RCode::ServFail
:
625 if(t_servfailremotes
) {
626 t_servfailremotes
->push_back(remote
);
627 if(query
&& t_servfailqueryring
) // packet cache
628 t_servfailqueryring
->push_back(make_pair(*query
, qtype
));
632 case RCode::NXDomain
:
641 static string
makeLoginfo(DNSComboWriter
* dc
)
644 return "("+dc
->d_mdp
.d_qname
.toLogString()+"/"+DNSRecordContent::NumberToType(dc
->d_mdp
.d_qtype
)+" from "+(dc
->d_remote
.toString())+")";
648 return "Exception making error message for exception";
652 static void protobufLogQuery(const std::shared_ptr
<RemoteLogger
>& logger
, uint8_t maskV4
, uint8_t maskV6
, const boost::uuids::uuid
& uniqueId
, const ComboAddress
& remote
, const ComboAddress
& local
, const Netmask
& ednssubnet
, bool tcp
, uint16_t id
, size_t len
, const DNSName
& qname
, uint16_t qtype
, uint16_t qclass
, const std::vector
<std::string
>& policyTags
, const std::string
& requestorId
, const std::string
& deviceId
)
654 Netmask
requestorNM(remote
, remote
.sin4
.sin_family
== AF_INET
? maskV4
: maskV6
);
655 const ComboAddress
& requestor
= requestorNM
.getMaskedNetwork();
656 RecProtoBufMessage
message(DNSProtoBufMessage::Query
, uniqueId
, &requestor
, &local
, qname
, qtype
, qclass
, id
, tcp
, len
);
657 message
.setEDNSSubnet(ednssubnet
, ednssubnet
.isIpv4() ? maskV4
: maskV6
);
658 message
.setRequestorId(requestorId
);
659 message
.setDeviceId(deviceId
);
661 if (!policyTags
.empty()) {
662 message
.setPolicyTags(policyTags
);
665 // cerr <<message.toDebugString()<<endl;
667 message
.serialize(str
);
668 logger
->queueData(str
);
671 static void protobufLogResponse(const std::shared_ptr
<RemoteLogger
>& logger
, const RecProtoBufMessage
& message
)
673 // cerr <<message.toDebugString()<<endl;
675 message
.serialize(str
);
676 logger
->queueData(str
);
681 * Chases the CNAME provided by the PolicyCustom RPZ policy.
683 * @param spoofed: The DNSRecord that was created by the policy, should already be added to ret
684 * @param qtype: The QType of the original query
685 * @param sr: A SyncRes
686 * @param res: An integer that will contain the RCODE of the lookup we do
687 * @param ret: A vector of DNSRecords where the result of the CNAME chase should be appended to
689 static void handleRPZCustom(const DNSRecord
& spoofed
, const QType
& qtype
, SyncRes
& sr
, int& res
, vector
<DNSRecord
>& ret
)
691 if (spoofed
.d_type
== QType::CNAME
) {
692 bool oldWantsRPZ
= sr
.getWantsRPZ();
693 sr
.setWantsRPZ(false);
694 vector
<DNSRecord
> ans
;
695 res
= sr
.beginResolve(DNSName(spoofed
.d_content
->getZoneRepresentation()), qtype
, 1, ans
);
696 for (const auto& rec
: ans
) {
697 if(rec
.d_place
== DNSResourceRecord::ANSWER
) {
701 // Reset the RPZ state of the SyncRes
702 sr
.setWantsRPZ(oldWantsRPZ
);
706 static bool addRecordToPacket(DNSPacketWriter
& pw
, const DNSRecord
& rec
, uint32_t& minTTL
, const uint16_t maxAnswerSize
)
708 pw
.startRecord(rec
.d_name
, rec
.d_type
, rec
.d_ttl
, rec
.d_class
, rec
.d_place
);
710 if(rec
.d_type
!= QType::OPT
) // their TTL ain't real
711 minTTL
= min(minTTL
, rec
.d_ttl
);
713 rec
.d_content
->toPacket(pw
);
714 if(pw
.size() > static_cast<size_t>(maxAnswerSize
)) {
716 if(rec
.d_place
!= DNSResourceRecord::ADDITIONAL
) {
717 pw
.getHeader()->tc
=1;
726 static void startDoResolve(void *p
)
728 DNSComboWriter
* dc
=(DNSComboWriter
*)p
;
731 t_queryring
->push_back(make_pair(dc
->d_mdp
.d_qname
, dc
->d_mdp
.d_qtype
));
733 uint16_t maxanswersize
= dc
->d_tcp
? 65535 : min(static_cast<uint16_t>(512), g_udpTruncationThreshold
);
736 if(getEDNSOpts(dc
->d_mdp
, &edo
)) {
739 "Values lower than 512 MUST be treated as equal to 512."
741 maxanswersize
= min(static_cast<uint16_t>(edo
.d_packetsize
>= 512 ? edo
.d_packetsize
: 512), g_udpTruncationThreshold
);
743 dc
->d_ednsOpts
= edo
.d_options
;
746 if (g_useIncomingECS
&& !dc
->d_ecsParsed
) {
747 for (const auto& o
: edo
.d_options
) {
748 if (o
.first
== EDNSOptionCode::ECS
) {
749 dc
->d_ecsFound
= getEDNSSubnetOptsFromString(o
.second
, &dc
->d_ednssubnet
);
755 /* perhaps there was no EDNS or no ECS but by now we looked */
756 dc
->d_ecsParsed
= true;
757 vector
<DNSRecord
> ret
;
758 vector
<uint8_t> packet
;
760 auto luaconfsLocal
= g_luaconfs
.getLocal();
761 // Used to tell syncres later on if we should apply NSDNAME and NSIP RPZ triggers for this query
763 RecProtoBufMessage
pbMessage(RecProtoBufMessage::Response
);
765 if (luaconfsLocal
->protobufServer
) {
766 Netmask
requestorNM(dc
->d_remote
, dc
->d_remote
.sin4
.sin_family
== AF_INET
? luaconfsLocal
->protobufMaskV4
: luaconfsLocal
->protobufMaskV6
);
767 const ComboAddress
& requestor
= requestorNM
.getMaskedNetwork();
768 pbMessage
.update(dc
->d_uuid
, &requestor
, &dc
->d_local
, dc
->d_tcp
, dc
->d_mdp
.d_header
.id
);
769 pbMessage
.setEDNSSubnet(dc
->d_ednssubnet
.source
, dc
->d_ednssubnet
.source
.isIpv4() ? luaconfsLocal
->protobufMaskV4
: luaconfsLocal
->protobufMaskV6
);
770 pbMessage
.setQuestion(dc
->d_mdp
.d_qname
, dc
->d_mdp
.d_qtype
, dc
->d_mdp
.d_qclass
);
772 #endif /* HAVE_PROTOBUF */
774 DNSPacketWriter
pw(packet
, dc
->d_mdp
.d_qname
, dc
->d_mdp
.d_qtype
, dc
->d_mdp
.d_qclass
);
776 pw
.getHeader()->aa
=0;
777 pw
.getHeader()->ra
=1;
778 pw
.getHeader()->qr
=1;
779 pw
.getHeader()->tc
=0;
780 pw
.getHeader()->id
=dc
->d_mdp
.d_header
.id
;
781 pw
.getHeader()->rd
=dc
->d_mdp
.d_header
.rd
;
782 pw
.getHeader()->cd
=dc
->d_mdp
.d_header
.cd
;
784 uint32_t minTTL
=std::numeric_limits
<uint32_t>::max();
786 SyncRes
sr(dc
->d_now
);
790 sr
.setLuaEngine(t_pdl
);
792 sr
.d_requestor
=dc
->d_remote
; // ECS needs this too
793 if(g_dnssecmode
!= DNSSECMode::Off
) {
794 sr
.setDoDNSSEC(true);
796 // Does the requestor want DNSSEC records?
797 if(edo
.d_Z
& EDNSOpts::DNSSECOK
) {
799 g_stats
.dnssecQueries
++;
802 // Ignore the client-set CD flag
803 pw
.getHeader()->cd
=0;
805 sr
.setDNSSECValidationRequested(g_dnssecmode
== DNSSECMode::ValidateAll
|| g_dnssecmode
==DNSSECMode::ValidateForLog
|| ((dc
->d_mdp
.d_header
.ad
|| DNSSECOK
) && g_dnssecmode
==DNSSECMode::Process
));
808 sr
.setInitialRequestId(dc
->d_uuid
);
811 if (g_useIncomingECS
) {
812 sr
.setIncomingECSFound(dc
->d_ecsFound
);
813 if (dc
->d_ecsFound
) {
814 sr
.setIncomingECS(dc
->d_ednssubnet
);
818 bool tracedQuery
=false; // we could consider letting Lua know about this too
819 bool variableAnswer
= false;
820 bool shouldNotValidate
= false;
822 /* preresolve expects res (dq.rcode) to be set to RCode::NoError by default */
823 int res
= RCode::NoError
;
824 DNSFilterEngine::Policy appliedPolicy
;
826 RecursorLua4::DNSQuestion
dq(dc
->d_remote
, dc
->d_local
, dc
->d_mdp
.d_qname
, dc
->d_mdp
.d_qtype
, dc
->d_tcp
, variableAnswer
, wantsRPZ
);
827 dq
.ednsFlags
= &edo
.d_Z
;
828 dq
.ednsOptions
= &dc
->d_ednsOpts
;
830 dq
.discardedPolicies
= &sr
.d_discardedPolicies
;
831 dq
.policyTags
= &dc
->d_policyTags
;
832 dq
.appliedPolicy
= &appliedPolicy
;
833 dq
.currentRecords
= &ret
;
834 dq
.dh
= &dc
->d_mdp
.d_header
;
835 dq
.data
= dc
->d_data
;
837 dq
.requestorId
= dc
->d_requestorId
;
838 dq
.deviceId
= dc
->d_deviceId
;
841 if(dc
->d_mdp
.d_qtype
==QType::ANY
&& !dc
->d_tcp
&& g_anyToTcp
) {
842 pw
.getHeader()->tc
= 1;
844 variableAnswer
= true;
848 if(t_traceRegex
&& t_traceRegex
->match(dc
->d_mdp
.d_qname
.toString())) {
849 sr
.setLogMode(SyncRes::Store
);
854 if(!g_quiet
|| tracedQuery
) {
855 L
<<Logger::Warning
<<t_id
<<" ["<<MT
->getTid()<<"/"<<MT
->numProcesses()<<"] " << (dc
->d_tcp
? "TCP " : "") << "question for '"<<dc
->d_mdp
.d_qname
<<"|"
856 <<DNSRecordContent::NumberToType(dc
->d_mdp
.d_qtype
)<<"' from "<<dc
->getRemote();
857 if(!dc
->d_ednssubnet
.source
.empty()) {
858 L
<<" (ecs "<<dc
->d_ednssubnet
.source
.toString()<<")";
863 sr
.setId(MT
->getTid());
864 if(!dc
->d_mdp
.d_header
.rd
)
868 t_pdl
->prerpz(dq
, res
);
871 // Check if the query has a policy attached to it
873 appliedPolicy
= luaconfsLocal
->dfe
.getQueryPolicy(dc
->d_mdp
.d_qname
, dc
->d_remote
, sr
.d_discardedPolicies
);
876 // if there is a RecursorLua active, and it 'took' the query in preResolve, we don't launch beginResolve
877 if(!t_pdl
|| !t_pdl
->preresolve(dq
, res
)) {
879 sr
.setWantsRPZ(wantsRPZ
);
881 switch(appliedPolicy
.d_kind
) {
882 case DNSFilterEngine::PolicyKind::NoAction
:
884 case DNSFilterEngine::PolicyKind::Drop
:
885 g_stats
.policyDrops
++;
886 g_stats
.policyResults
[appliedPolicy
.d_kind
]++;
890 case DNSFilterEngine::PolicyKind::NXDOMAIN
:
891 g_stats
.policyResults
[appliedPolicy
.d_kind
]++;
894 case DNSFilterEngine::PolicyKind::NODATA
:
895 g_stats
.policyResults
[appliedPolicy
.d_kind
]++;
898 case DNSFilterEngine::PolicyKind::Custom
:
899 g_stats
.policyResults
[appliedPolicy
.d_kind
]++;
901 spoofed
=appliedPolicy
.getCustomRecord(dc
->d_mdp
.d_qname
);
902 ret
.push_back(spoofed
);
903 handleRPZCustom(spoofed
, QType(dc
->d_mdp
.d_qtype
), sr
, res
, ret
);
905 case DNSFilterEngine::PolicyKind::Truncate
:
907 g_stats
.policyResults
[appliedPolicy
.d_kind
]++;
909 pw
.getHeader()->tc
=1;
916 // Query got not handled for QNAME Policy reasons, now actually go out to find an answer
918 res
= sr
.beginResolve(dc
->d_mdp
.d_qname
, QType(dc
->d_mdp
.d_qtype
), dc
->d_mdp
.d_qclass
, ret
);
919 shouldNotValidate
= sr
.wasOutOfBand();
921 catch(ImmediateServFailException
&e
) {
922 if(g_logCommonErrors
)
923 L
<<Logger::Notice
<<"Sending SERVFAIL to "<<dc
->getRemote()<<" during resolve of '"<<dc
->d_mdp
.d_qname
<<"' because: "<<e
.reason
<<endl
;
924 res
= RCode::ServFail
;
927 dq
.validationState
= sr
.getValidationState();
929 // During lookup, an NSDNAME or NSIP trigger was hit in RPZ
930 if (res
== -2) { // XXX This block should be macro'd, it is repeated post-resolve.
931 appliedPolicy
= sr
.d_appliedPolicy
;
932 g_stats
.policyResults
[appliedPolicy
.d_kind
]++;
933 switch(appliedPolicy
.d_kind
) {
934 case DNSFilterEngine::PolicyKind::NoAction
: // This can never happen
935 throw PDNSException("NoAction policy returned while a NSDNAME or NSIP trigger was hit");
936 case DNSFilterEngine::PolicyKind::Drop
:
937 g_stats
.policyDrops
++;
941 case DNSFilterEngine::PolicyKind::NXDOMAIN
:
946 case DNSFilterEngine::PolicyKind::NODATA
:
951 case DNSFilterEngine::PolicyKind::Truncate
:
955 pw
.getHeader()->tc
=1;
960 case DNSFilterEngine::PolicyKind::Custom
:
963 spoofed
=appliedPolicy
.getCustomRecord(dc
->d_mdp
.d_qname
);
964 ret
.push_back(spoofed
);
965 handleRPZCustom(spoofed
, QType(dc
->d_mdp
.d_qtype
), sr
, res
, ret
);
971 appliedPolicy
= luaconfsLocal
->dfe
.getPostPolicy(ret
, sr
.d_discardedPolicies
);
975 if(res
== RCode::NoError
) {
977 for(; i
!= ret
.cend(); ++i
)
978 if(i
->d_type
== dc
->d_mdp
.d_qtype
&& i
->d_place
== DNSResourceRecord::ANSWER
)
980 if(i
== ret
.cend() && t_pdl
->nodata(dq
, res
))
981 shouldNotValidate
= true;
984 else if(res
== RCode::NXDomain
&& t_pdl
->nxdomain(dq
, res
))
985 shouldNotValidate
= true;
987 if(t_pdl
->postresolve(dq
, res
))
988 shouldNotValidate
= true;
991 if (wantsRPZ
) { //XXX This block is repeated, see above
992 g_stats
.policyResults
[appliedPolicy
.d_kind
]++;
993 switch(appliedPolicy
.d_kind
) {
994 case DNSFilterEngine::PolicyKind::NoAction
:
996 case DNSFilterEngine::PolicyKind::Drop
:
997 g_stats
.policyDrops
++;
1001 case DNSFilterEngine::PolicyKind::NXDOMAIN
:
1003 res
=RCode::NXDomain
;
1006 case DNSFilterEngine::PolicyKind::NODATA
:
1011 case DNSFilterEngine::PolicyKind::Truncate
:
1015 pw
.getHeader()->tc
=1;
1020 case DNSFilterEngine::PolicyKind::Custom
:
1023 spoofed
=appliedPolicy
.getCustomRecord(dc
->d_mdp
.d_qname
);
1024 ret
.push_back(spoofed
);
1025 handleRPZCustom(spoofed
, QType(dc
->d_mdp
.d_qtype
), sr
, res
, ret
);
1031 if(res
== PolicyDecision::DROP
) {
1032 g_stats
.policyDrops
++;
1037 if(tracedQuery
|| res
== -1 || res
== RCode::ServFail
|| pw
.getHeader()->rcode
== RCode::ServFail
)
1039 string
trace(sr
.getTrace());
1040 if(!trace
.empty()) {
1041 vector
<string
> lines
;
1042 boost::split(lines
, trace
, boost::is_any_of("\n"));
1043 for(const string
& line
: lines
) {
1045 L
<<Logger::Warning
<< line
<< endl
;
1051 pw
.getHeader()->rcode
=RCode::ServFail
;
1052 // no commit here, because no record
1053 g_stats
.servFails
++;
1056 pw
.getHeader()->rcode
=res
;
1058 // Does the validation mode or query demand validation?
1059 if(!shouldNotValidate
&& sr
.isDNSSECValidationRequested()) {
1062 L
<<Logger::Warning
<<"Starting validation of answer to "<<dc
->d_mdp
.d_qname
<<"|"<<QType(dc
->d_mdp
.d_qtype
).getName()<<" for "<<dc
->d_remote
.toStringWithPort()<<endl
;
1065 auto state
= sr
.getValidationState();
1067 if(state
== Secure
) {
1069 L
<<Logger::Warning
<<"Answer to "<<dc
->d_mdp
.d_qname
<<"|"<<QType(dc
->d_mdp
.d_qtype
).getName()<<" for "<<dc
->d_remote
.toStringWithPort()<<" validates correctly"<<endl
;
1072 // Is the query source interested in the value of the ad-bit?
1073 if (dc
->d_mdp
.d_header
.ad
|| DNSSECOK
)
1074 pw
.getHeader()->ad
=1;
1076 else if(state
== Insecure
) {
1078 L
<<Logger::Warning
<<"Answer to "<<dc
->d_mdp
.d_qname
<<"|"<<QType(dc
->d_mdp
.d_qtype
).getName()<<" for "<<dc
->d_remote
.toStringWithPort()<<" validates as Insecure"<<endl
;
1081 pw
.getHeader()->ad
=0;
1083 else if(state
== Bogus
) {
1084 if(g_dnssecLogBogus
|| sr
.doLog() || g_dnssecmode
== DNSSECMode::ValidateForLog
) {
1085 L
<<Logger::Warning
<<"Answer to "<<dc
->d_mdp
.d_qname
<<"|"<<QType(dc
->d_mdp
.d_qtype
).getName()<<" for "<<dc
->d_remote
.toStringWithPort()<<" validates as Bogus"<<endl
;
1088 // Does the query or validation mode sending out a SERVFAIL on validation errors?
1089 if(!pw
.getHeader()->cd
&& (g_dnssecmode
== DNSSECMode::ValidateAll
|| dc
->d_mdp
.d_header
.ad
|| DNSSECOK
)) {
1091 L
<<Logger::Warning
<<"Sending out SERVFAIL for "<<dc
->d_mdp
.d_qname
<<"|"<<QType(dc
->d_mdp
.d_qtype
).getName()<<" because recursor or query demands it for Bogus results"<<endl
;
1094 pw
.getHeader()->rcode
=RCode::ServFail
;
1098 L
<<Logger::Warning
<<"Not sending out SERVFAIL for "<<dc
->d_mdp
.d_qname
<<"|"<<QType(dc
->d_mdp
.d_qtype
).getName()<<" Bogus validation since neither config nor query demands this"<<endl
;
1103 catch(ImmediateServFailException
&e
) {
1104 if(g_logCommonErrors
)
1105 L
<<Logger::Notice
<<"Sending SERVFAIL to "<<dc
->getRemote()<<" during validation of '"<<dc
->d_mdp
.d_qname
<<"|"<<QType(dc
->d_mdp
.d_qtype
).getName()<<"' because: "<<e
.reason
<<endl
;
1106 pw
.getHeader()->rcode
=RCode::ServFail
;
1112 orderAndShuffle(ret
);
1113 if(auto sl
= luaconfsLocal
->sortlist
.getOrderCmp(dc
->d_remote
)) {
1114 stable_sort(ret
.begin(), ret
.end(), *sl
);
1115 variableAnswer
=true;
1119 bool needCommit
= false;
1120 for(auto i
=ret
.cbegin(); i
!=ret
.cend(); ++i
) {
1122 ( i
->d_type
== QType::NSEC3
||
1124 ( i
->d_type
== QType::RRSIG
|| i
->d_type
==QType::NSEC
) &&
1126 ( dc
->d_mdp
.d_qtype
!= i
->d_type
&& dc
->d_mdp
.d_qtype
!= QType::ANY
) ||
1127 i
->d_place
!= DNSResourceRecord::ANSWER
1135 if (!addRecordToPacket(pw
, *i
, minTTL
, maxanswersize
)) {
1141 #ifdef HAVE_PROTOBUF
1142 if(luaconfsLocal
->protobufServer
&& (i
->d_type
== QType::A
|| i
->d_type
== QType::AAAA
|| i
->d_type
== QType::CNAME
)) {
1143 pbMessage
.addRR(*i
);
1153 /* we try to add the EDNS OPT RR even for truncated answers,
1155 "The minimal response MUST be the DNS header, question section, and an
1156 OPT record. This MUST also occur when a truncated response (using
1157 the DNS header's TC bit) is returned."
1159 if (addRecordToPacket(pw
, makeOpt(edo
.d_packetsize
, 0, edo
.d_Z
), minTTL
, maxanswersize
)) {
1164 g_rs
.submitResponse(dc
->d_mdp
.d_qtype
, packet
.size(), !dc
->d_tcp
);
1165 updateResponseStats(res
, dc
->d_remote
, packet
.size(), &dc
->d_mdp
.d_qname
, dc
->d_mdp
.d_qtype
);
1166 #ifdef HAVE_PROTOBUF
1167 if (luaconfsLocal
->protobufServer
&& (!luaconfsLocal
->protobufTaggedOnly
|| (appliedPolicy
.d_name
&& !appliedPolicy
.d_name
->empty()) || !dc
->d_policyTags
.empty())) {
1168 pbMessage
.setBytes(packet
.size());
1169 pbMessage
.setResponseCode(pw
.getHeader()->rcode
);
1170 if (appliedPolicy
.d_name
) {
1171 pbMessage
.setAppliedPolicy(*appliedPolicy
.d_name
);
1172 pbMessage
.setAppliedPolicyType(appliedPolicy
.d_type
);
1174 pbMessage
.setPolicyTags(dc
->d_policyTags
);
1175 pbMessage
.setQueryTime(dc
->d_now
.tv_sec
, dc
->d_now
.tv_usec
);
1176 pbMessage
.setRequestorId(dq
.requestorId
);
1177 pbMessage
.setDeviceId(dq
.deviceId
);
1178 protobufLogResponse(luaconfsLocal
->protobufServer
, pbMessage
);
1185 fillMSGHdr(&msgh
, &iov
, cbuf
, 0, (char*)&*packet
.begin(), packet
.size(), &dc
->d_remote
);
1186 msgh
.msg_control
=NULL
;
1188 if(g_fromtosockets
.count(dc
->d_socket
)) {
1189 addCMsgSrcAddr(&msgh
, cbuf
, &dc
->d_local
, 0);
1191 if(sendmsg(dc
->d_socket
, &msgh
, 0) < 0 && g_logCommonErrors
)
1192 L
<<Logger::Warning
<<"Sending UDP reply to client "<<dc
->d_remote
.toStringWithPort()<<" failed with: "<<strerror(errno
)<<endl
;
1193 if(!SyncRes::s_nopacketcache
&& !variableAnswer
&& !sr
.wasVariable() ) {
1194 t_packetCache
->insertResponsePacket(dc
->d_tag
, dc
->d_qhash
, dc
->d_mdp
.d_qname
, dc
->d_mdp
.d_qtype
, dc
->d_mdp
.d_qclass
,
1195 string((const char*)&*packet
.begin(), packet
.size()),
1197 pw
.getHeader()->rcode
== RCode::ServFail
? SyncRes::s_packetcacheservfailttl
:
1198 min(minTTL
,SyncRes::s_packetcachettl
),
1201 // else cerr<<"Not putting in packet cache: "<<sr.wasVariable()<<endl;
1205 buf
[0]=packet
.size()/256;
1206 buf
[1]=packet
.size()%256;
1208 Utility::iovec iov
[2];
1210 iov
[0].iov_base
=(void*)buf
; iov
[0].iov_len
=2;
1211 iov
[1].iov_base
=(void*)&*packet
.begin(); iov
[1].iov_len
= packet
.size();
1213 int wret
=Utility::writev(dc
->d_socket
, iov
, 2);
1217 L
<<Logger::Error
<<"EOF writing TCP answer to "<<dc
->getRemote()<<endl
;
1219 L
<<Logger::Error
<<"Error writing TCP answer to "<<dc
->getRemote()<<": "<< strerror(errno
) <<endl
;
1220 else if((unsigned int)wret
!= 2 + packet
.size())
1221 L
<<Logger::Error
<<"Oops, partial answer sent to "<<dc
->getRemote()<<" for "<<dc
->d_mdp
.d_qname
<<" (size="<< (2 + packet
.size()) <<", sent "<<wret
<<")"<<endl
;
1225 // update tcp connection status, either by closing or moving to 'BYTE0'
1228 // no need to remove us from FDM, we weren't there
1232 dc
->d_tcpConnection
->queriesCount
++;
1233 if (g_tcpMaxQueriesPerConn
&& dc
->d_tcpConnection
->queriesCount
>= g_tcpMaxQueriesPerConn
) {
1237 dc
->d_tcpConnection
->state
=TCPConnection::BYTE0
;
1238 Utility::gettimeofday(&g_now
, 0); // needs to be updated
1239 t_fdm
->addReadFD(dc
->d_socket
, handleRunningTCPQuestion
, dc
->d_tcpConnection
);
1240 t_fdm
->setReadTTD(dc
->d_socket
, g_now
, g_tcpTimeout
);
1244 float spent
=makeFloat(sr
.getNow()-dc
->d_now
);
1246 L
<<Logger::Error
<<t_id
<<" ["<<MT
->getTid()<<"/"<<MT
->numProcesses()<<"] answer to "<<(dc
->d_mdp
.d_header
.rd
?"":"non-rd ")<<"question '"<<dc
->d_mdp
.d_qname
<<"|"<<DNSRecordContent::NumberToType(dc
->d_mdp
.d_qtype
);
1247 L
<<"': "<<ntohs(pw
.getHeader()->ancount
)<<" answers, "<<ntohs(pw
.getHeader()->arcount
)<<" additional, took "<<sr
.d_outqueries
<<" packets, "<<
1248 sr
.d_totUsec
/1000.0<<" netw ms, "<< spent
*1000.0<<" tot ms, "<<
1249 sr
.d_throttledqueries
<<" throttled, "<<sr
.d_timeouts
<<" timeouts, "<<sr
.d_tcpoutqueries
<<" tcp connections, rcode="<< res
;
1251 if(!shouldNotValidate
&& sr
.isDNSSECValidationRequested()) {
1252 L
<< ", dnssec="<<vStates
[sr
.getValidationState()];
1259 sr
.d_outqueries
? t_RC
->cacheMisses
++ : t_RC
->cacheHits
++;
1262 g_stats
.answers0_1
++;
1263 else if(spent
< 0.010)
1264 g_stats
.answers1_10
++;
1265 else if(spent
< 0.1)
1266 g_stats
.answers10_100
++;
1267 else if(spent
< 1.0)
1268 g_stats
.answers100_1000
++;
1270 g_stats
.answersSlow
++;
1272 uint64_t newLat
=(uint64_t)(spent
*1000000);
1273 newLat
= min(newLat
,(uint64_t)(((uint64_t) g_networkTimeoutMsec
)*1000)); // outliers of several minutes exist..
1274 g_stats
.avgLatencyUsec
=(1-1.0/g_latencyStatSize
)*g_stats
.avgLatencyUsec
+ (float)newLat
/g_latencyStatSize
;
1275 // no worries, we do this for packet cache hits elsewhere
1277 auto ourtime
= 1000.0*spent
-sr
.d_totUsec
/1000.0; // in msec
1279 g_stats
.ourtime0_1
++;
1280 else if(ourtime
< 2)
1281 g_stats
.ourtime1_2
++;
1282 else if(ourtime
< 4)
1283 g_stats
.ourtime2_4
++;
1284 else if(ourtime
< 8)
1285 g_stats
.ourtime4_8
++;
1286 else if(ourtime
< 16)
1287 g_stats
.ourtime8_16
++;
1288 else if(ourtime
< 32)
1289 g_stats
.ourtime16_32
++;
1291 // cerr<<"SLOW: "<<ourtime<<"ms -> "<<dc->d_mdp.d_qname<<"|"<<DNSRecordContent::NumberToType(dc->d_mdp.d_qtype)<<endl;
1292 g_stats
.ourtimeSlow
++;
1294 if(ourtime
>= 0.0) {
1295 newLat
=ourtime
*1000; // usec
1296 g_stats
.avgLatencyOursUsec
=(1-1.0/g_latencyStatSize
)*g_stats
.avgLatencyOursUsec
+ (float)newLat
/g_latencyStatSize
;
1298 // cout<<dc->d_mdp.d_qname<<"\t"<<MT->getUsec()<<"\t"<<sr.d_outqueries<<endl;
1302 catch(PDNSException
&ae
) {
1303 L
<<Logger::Error
<<"startDoResolve problem "<<makeLoginfo(dc
)<<": "<<ae
.reason
<<endl
;
1306 catch(MOADNSException
& e
) {
1307 L
<<Logger::Error
<<"DNS parser error "<<makeLoginfo(dc
) <<": "<<dc
->d_mdp
.d_qname
<<", "<<e
.what()<<endl
;
1310 catch(std::exception
& e
) {
1311 L
<<Logger::Error
<<"STL error "<< makeLoginfo(dc
)<<": "<<e
.what();
1313 // Luawrapper nests the exception from Lua, so we unnest it here
1315 std::rethrow_if_nested(e
);
1316 } catch(const std::exception
& ne
) {
1317 L
<<". Extra info: "<<ne
.what();
1324 L
<<Logger::Error
<<"Any other exception in a resolver context "<< makeLoginfo(dc
) <<endl
;
1327 g_stats
.maxMThreadStackUsage
= max(MT
->getMaxStackUsage(), g_stats
.maxMThreadStackUsage
);
1330 static void makeControlChannelSocket(int processNum
=-1)
1332 string sockname
=::arg()["socket-dir"]+"/"+s_programname
;
1334 sockname
+= "."+std::to_string(processNum
);
1335 sockname
+=".controlsocket";
1336 s_rcc
.listen(sockname
);
1341 if (!::arg().isEmpty("socket-group"))
1342 sockgroup
=::arg().asGid("socket-group");
1343 if (!::arg().isEmpty("socket-owner"))
1344 sockowner
=::arg().asUid("socket-owner");
1346 if (sockgroup
> -1 || sockowner
> -1) {
1347 if(chown(sockname
.c_str(), sockowner
, sockgroup
) < 0) {
1348 unixDie("Failed to chown control socket");
1352 // do mode change if socket-mode is given
1353 if(!::arg().isEmpty("socket-mode")) {
1354 mode_t sockmode
=::arg().asMode("socket-mode");
1355 if(chmod(sockname
.c_str(), sockmode
) < 0) {
1356 unixDie("Failed to chmod control socket");
1361 static bool getQNameAndSubnet(const std::string
& question
, DNSName
* dnsname
, uint16_t* qtype
, uint16_t* qclass
, EDNSSubnetOpts
* ednssubnet
, std::map
<uint16_t, EDNSOptionView
>* options
)
1364 const struct dnsheader
* dh
= (struct dnsheader
*)question
.c_str();
1365 size_t questionLen
= question
.length();
1366 unsigned int consumed
=0;
1367 *dnsname
=DNSName(question
.c_str(), questionLen
, sizeof(dnsheader
), false, qtype
, qclass
, &consumed
);
1369 size_t pos
= sizeof(dnsheader
)+consumed
+4;
1370 /* at least OPT root label (1), type (2), class (2) and ttl (4) + OPT RR rdlen (2)
1372 if(ntohs(dh
->arcount
) == 1 && questionLen
> pos
+ 11) { // this code can extract one (1) EDNS Subnet option
1373 /* OPT root label (1) followed by type (2) */
1374 if(question
.at(pos
)==0 && question
.at(pos
+1)==0 && question
.at(pos
+2)==QType::OPT
) {
1376 char* ecsStart
= nullptr;
1378 int res
= getEDNSOption((char*)question
.c_str()+pos
+9, questionLen
- pos
- 9, EDNSOptionCode::ECS
, &ecsStart
, &ecsLen
);
1379 if (res
== 0 && ecsLen
> 4) {
1381 if(getEDNSSubnetOptsFromString(ecsStart
+ 4, ecsLen
- 4, &eso
)) {
1388 int res
= getEDNSOptions((char*)question
.c_str()+pos
+9, questionLen
- pos
- 9, *options
);
1390 const auto& it
= options
->find(EDNSOptionCode::ECS
);
1391 if (it
!= options
->end() && it
->second
.content
!= nullptr && it
->second
.size
> 0) {
1393 if(getEDNSSubnetOptsFromString(it
->second
.content
, it
->second
.size
, &eso
)) {
1405 static void handleRunningTCPQuestion(int fd
, FDMultiplexer::funcparam_t
& var
)
1407 shared_ptr
<TCPConnection
> conn
=any_cast
<shared_ptr
<TCPConnection
> >(var
);
1409 if(conn
->state
==TCPConnection::BYTE0
) {
1410 ssize_t bytes
=recv(conn
->getFD(), conn
->data
, 2, 0);
1412 conn
->state
=TCPConnection::BYTE1
;
1414 conn
->qlen
=(((unsigned char)conn
->data
[0]) << 8)+ (unsigned char)conn
->data
[1];
1416 conn
->state
=TCPConnection::GETQUESTION
;
1418 if(!bytes
|| bytes
< 0) {
1419 t_fdm
->removeReadFD(fd
);
1423 else if(conn
->state
==TCPConnection::BYTE1
) {
1424 ssize_t bytes
=recv(conn
->getFD(), conn
->data
+1, 1, 0);
1426 conn
->state
=TCPConnection::GETQUESTION
;
1427 conn
->qlen
=(((unsigned char)conn
->data
[0]) << 8)+ (unsigned char)conn
->data
[1];
1430 if(!bytes
|| bytes
< 0) {
1431 if(g_logCommonErrors
)
1432 L
<<Logger::Error
<<"TCP client "<< conn
->d_remote
.toString() <<" disconnected after first byte"<<endl
;
1433 t_fdm
->removeReadFD(fd
);
1437 else if(conn
->state
==TCPConnection::GETQUESTION
) {
1438 ssize_t bytes
=recv(conn
->getFD(), conn
->data
+ conn
->bytesread
, conn
->qlen
- conn
->bytesread
, 0);
1439 if(!bytes
|| bytes
< 0 || bytes
> std::numeric_limits
<std::uint16_t>::max()) {
1440 L
<<Logger::Error
<<"TCP client "<< conn
->d_remote
.toString() <<" disconnected while reading question body"<<endl
;
1441 t_fdm
->removeReadFD(fd
);
1444 conn
->bytesread
+=(uint16_t)bytes
;
1445 if(conn
->bytesread
==conn
->qlen
) {
1446 t_fdm
->removeReadFD(fd
); // should no longer awake ourselves when there is data to read
1448 DNSComboWriter
* dc
=nullptr;
1450 dc
=new DNSComboWriter(conn
->data
, conn
->qlen
, g_now
);
1452 catch(MOADNSException
&mde
) {
1453 g_stats
.clientParseError
++;
1454 if(g_logCommonErrors
)
1455 L
<<Logger::Error
<<"Unable to parse packet from TCP client "<< conn
->d_remote
.toString() <<endl
;
1458 dc
->d_tcpConnection
= conn
; // carry the torch
1459 dc
->setSocket(conn
->getFD()); // this is the only time a copy is made of the actual fd
1461 dc
->setRemote(&conn
->d_remote
);
1463 memset(&dest
, 0, sizeof(dest
));
1464 dest
.sin4
.sin_family
= conn
->d_remote
.sin4
.sin_family
;
1465 socklen_t len
= dest
.getSocklen();
1466 getsockname(conn
->getFD(), (sockaddr
*)&dest
, &len
); // if this fails, we're ok with it
1471 bool needECS
= false;
1474 #ifdef HAVE_PROTOBUF
1475 auto luaconfsLocal
= g_luaconfs
.getLocal();
1476 if (luaconfsLocal
->protobufServer
) {
1481 if(needECS
|| (t_pdl
&& t_pdl
->d_gettag
)) {
1484 std::map
<uint16_t, EDNSOptionView
> ednsOptions
;
1485 dc
->d_ecsParsed
= true;
1486 dc
->d_ecsFound
= getQNameAndSubnet(std::string(conn
->data
, conn
->qlen
), &qname
, &qtype
, &qclass
, &dc
->d_ednssubnet
, g_gettagNeedsEDNSOptions
? &ednsOptions
: nullptr);
1488 if(t_pdl
&& t_pdl
->d_gettag
) {
1490 dc
->d_tag
= t_pdl
->gettag(conn
->d_remote
, dc
->d_ednssubnet
.source
, dest
, qname
, qtype
, &dc
->d_policyTags
, dc
->d_data
, ednsOptions
, true, requestorId
, deviceId
);
1492 catch(std::exception
& e
) {
1493 if(g_logCommonErrors
)
1494 L
<<Logger::Warning
<<"Error parsing a query packet qname='"<<qname
<<"' for tag determination, setting tag=0: "<<e
.what()<<endl
;
1498 catch(std::exception
& e
)
1500 if(g_logCommonErrors
)
1501 L
<<Logger::Warning
<<"Error parsing a query packet for tag determination, setting tag=0: "<<e
.what()<<endl
;
1504 #ifdef HAVE_PROTOBUF
1505 if(luaconfsLocal
->protobufServer
|| luaconfsLocal
->outgoingProtobufServer
) {
1506 dc
->d_requestorId
= requestorId
;
1507 dc
->d_deviceId
= deviceId
;
1508 dc
->d_uuid
= (*t_uuidGenerator
)();
1511 if(luaconfsLocal
->protobufServer
) {
1513 const struct dnsheader
* dh
= (const struct dnsheader
*) conn
->data
;
1515 if (!luaconfsLocal
->protobufTaggedOnly
) {
1516 protobufLogQuery(luaconfsLocal
->protobufServer
, luaconfsLocal
->protobufMaskV4
, luaconfsLocal
->protobufMaskV6
, dc
->d_uuid
, conn
->d_remote
, dest
, dc
->d_ednssubnet
.source
, true, dh
->id
, conn
->qlen
, qname
, qtype
, qclass
, dc
->d_policyTags
, dc
->d_requestorId
, dc
->d_deviceId
);
1519 catch(std::exception
& e
) {
1520 if(g_logCommonErrors
)
1521 L
<<Logger::Warning
<<"Error parsing a TCP query packet for edns subnet: "<<e
.what()<<endl
;
1525 if(dc
->d_mdp
.d_header
.qr
) {
1527 g_stats
.ignoredCount
++;
1528 L
<<Logger::Error
<<"Ignoring answer from TCP client "<< conn
->d_remote
.toString() <<" on server socket!"<<endl
;
1531 if(dc
->d_mdp
.d_header
.opcode
) {
1533 g_stats
.ignoredCount
++;
1534 L
<<Logger::Error
<<"Ignoring non-query opcode from TCP client "<< conn
->d_remote
.toString() <<" on server socket!"<<endl
;
1539 ++g_stats
.tcpqcounter
;
1540 MT
->makeThread(startDoResolve
, dc
); // deletes dc, will set state to BYTE0 again
1547 //! Handle new incoming TCP connection
1548 static void handleNewTCPQuestion(int fd
, FDMultiplexer::funcparam_t
& )
1551 socklen_t addrlen
=sizeof(addr
);
1552 int newsock
=accept(fd
, (struct sockaddr
*)&addr
, &addrlen
);
1554 if(MT
->numProcesses() > g_maxMThreads
) {
1555 g_stats
.overCapacityDrops
++;
1557 closesocket(newsock
);
1559 catch(const PDNSException
& e
) {
1560 L
<<Logger::Error
<<"Error closing TCP socket after an over capacity drop: "<<e
.reason
<<endl
;
1566 t_remotes
->push_back(addr
);
1567 if(t_allowFrom
&& !t_allowFrom
->match(&addr
)) {
1569 L
<<Logger::Error
<<"["<<MT
->getTid()<<"] dropping TCP query from "<<addr
.toString()<<", address not matched by allow-from"<<endl
;
1571 g_stats
.unauthorizedTCP
++;
1573 closesocket(newsock
);
1575 catch(const PDNSException
& e
) {
1576 L
<<Logger::Error
<<"Error closing TCP socket after an ACL drop: "<<e
.reason
<<endl
;
1580 if(g_maxTCPPerClient
&& t_tcpClientCounts
->count(addr
) && (*t_tcpClientCounts
)[addr
] >= g_maxTCPPerClient
) {
1581 g_stats
.tcpClientOverflow
++;
1583 closesocket(newsock
); // don't call TCPConnection::closeAndCleanup here - did not enter it in the counts yet!
1585 catch(const PDNSException
& e
) {
1586 L
<<Logger::Error
<<"Error closing TCP socket after an overflow drop: "<<e
.reason
<<endl
;
1591 setNonBlocking(newsock
);
1592 std::shared_ptr
<TCPConnection
> tc
= std::make_shared
<TCPConnection
>(newsock
, addr
);
1593 tc
->state
=TCPConnection::BYTE0
;
1595 t_fdm
->addReadFD(tc
->getFD(), handleRunningTCPQuestion
, tc
);
1598 Utility::gettimeofday(&now
, 0);
1599 t_fdm
->setReadTTD(tc
->getFD(), now
, g_tcpTimeout
);
1603 static string
* doProcessUDPQuestion(const std::string
& question
, const ComboAddress
& fromaddr
, const ComboAddress
& destaddr
, struct timeval tv
, int fd
)
1605 gettimeofday(&g_now
, 0);
1606 struct timeval diff
= g_now
- tv
;
1607 double delta
=(diff
.tv_sec
*1000 + diff
.tv_usec
/1000.0);
1609 if(tv
.tv_sec
&& delta
> 1000.0) {
1610 g_stats
.tooOldDrops
++;
1615 if(fromaddr
.sin4
.sin_family
==AF_INET6
)
1616 g_stats
.ipv6qcounter
++;
1619 const struct dnsheader
* dh
= (struct dnsheader
*)question
.c_str();
1620 unsigned int ctag
=0;
1622 bool needECS
= false;
1623 std::vector
<std::string
> policyTags
;
1624 LuaContext::LuaObject data
;
1627 #ifdef HAVE_PROTOBUF
1628 boost::uuids::uuid uniqueId
;
1629 auto luaconfsLocal
= g_luaconfs
.getLocal();
1630 if (luaconfsLocal
->protobufServer
) {
1631 uniqueId
= (*t_uuidGenerator
)();
1633 } else if (luaconfsLocal
->outgoingProtobufServer
) {
1634 uniqueId
= (*t_uuidGenerator
)();
1637 EDNSSubnetOpts ednssubnet
;
1638 bool ecsFound
= false;
1639 bool ecsParsed
= false;
1645 bool qnameParsed
=false;
1648 static uint64_t last=0;
1650 g_mtracer->clearAllocators();
1651 cout<<g_mtracer->getAllocs()-last<<" "<<g_mtracer->getNumOut()<<" -- BEGIN TRACE"<<endl;
1652 last=g_mtracer->getAllocs();
1653 cout<<g_mtracer->topAllocatorsString()<<endl;
1654 g_mtracer->clearAllocators();
1658 if(needECS
|| (t_pdl
&& t_pdl
->d_gettag
)) {
1660 std::map
<uint16_t, EDNSOptionView
> ednsOptions
;
1661 ecsFound
= getQNameAndSubnet(question
, &qname
, &qtype
, &qclass
, &ednssubnet
, g_gettagNeedsEDNSOptions
? &ednsOptions
: nullptr);
1665 if(t_pdl
&& t_pdl
->d_gettag
) {
1667 ctag
=t_pdl
->gettag(fromaddr
, ednssubnet
.source
, destaddr
, qname
, qtype
, &policyTags
, data
, ednsOptions
, false, requestorId
, deviceId
);
1669 catch(std::exception
& e
) {
1670 if(g_logCommonErrors
)
1671 L
<<Logger::Warning
<<"Error parsing a query packet qname='"<<qname
<<"' for tag determination, setting tag=0: "<<e
.what()<<endl
;
1675 catch(std::exception
& e
)
1677 if(g_logCommonErrors
)
1678 L
<<Logger::Warning
<<"Error parsing a query packet for tag determination, setting tag=0: "<<e
.what()<<endl
;
1682 bool cacheHit
= false;
1683 RecProtoBufMessage
pbMessage(DNSProtoBufMessage::DNSProtoBufMessageType::Response
);
1684 #ifdef HAVE_PROTOBUF
1685 if(luaconfsLocal
->protobufServer
) {
1686 if (!luaconfsLocal
->protobufTaggedOnly
|| !policyTags
.empty()) {
1687 protobufLogQuery(luaconfsLocal
->protobufServer
, luaconfsLocal
->protobufMaskV4
, luaconfsLocal
->protobufMaskV6
, uniqueId
, fromaddr
, destaddr
, ednssubnet
.source
, false, dh
->id
, question
.size(), qname
, qtype
, qclass
, policyTags
, requestorId
, deviceId
);
1690 #endif /* HAVE_PROTOBUF */
1693 cacheHit
= (!SyncRes::s_nopacketcache
&& t_packetCache
->getResponsePacket(ctag
, question
, qname
, qtype
, qclass
, g_now
.tv_sec
, &response
, &age
, &qhash
, &pbMessage
));
1696 cacheHit
= (!SyncRes::s_nopacketcache
&& t_packetCache
->getResponsePacket(ctag
, question
, g_now
.tv_sec
, &response
, &age
, &qhash
, &pbMessage
));
1700 #ifdef HAVE_PROTOBUF
1701 if(luaconfsLocal
->protobufServer
&& (!luaconfsLocal
->protobufTaggedOnly
|| !pbMessage
.getAppliedPolicy().empty() || !pbMessage
.getPolicyTags().empty())) {
1702 Netmask
requestorNM(fromaddr
, fromaddr
.sin4
.sin_family
== AF_INET
? luaconfsLocal
->protobufMaskV4
: luaconfsLocal
->protobufMaskV6
);
1703 const ComboAddress
& requestor
= requestorNM
.getMaskedNetwork();
1704 pbMessage
.update(uniqueId
, &requestor
, &destaddr
, false, dh
->id
);
1705 pbMessage
.setEDNSSubnet(ednssubnet
.source
, ednssubnet
.source
.isIpv4() ? luaconfsLocal
->protobufMaskV4
: luaconfsLocal
->protobufMaskV6
);
1706 pbMessage
.setQueryTime(g_now
.tv_sec
, g_now
.tv_usec
);
1707 pbMessage
.setRequestorId(requestorId
);
1708 pbMessage
.setDeviceId(deviceId
);
1709 protobufLogResponse(luaconfsLocal
->protobufServer
, pbMessage
);
1711 #endif /* HAVE_PROTOBUF */
1713 L
<<Logger::Notice
<<t_id
<< " question answered from packet cache tag="<<ctag
<<" from "<<fromaddr
.toString()<<endl
;
1715 g_stats
.packetCacheHits
++;
1716 SyncRes::s_queries
++;
1717 ageDNSPacket(response
, age
);
1721 fillMSGHdr(&msgh
, &iov
, cbuf
, 0, (char*)response
.c_str(), response
.length(), const_cast<ComboAddress
*>(&fromaddr
));
1722 msgh
.msg_control
=NULL
;
1724 if(g_fromtosockets
.count(fd
)) {
1725 addCMsgSrcAddr(&msgh
, cbuf
, &destaddr
, 0);
1727 if(sendmsg(fd
, &msgh
, 0) < 0 && g_logCommonErrors
)
1728 L
<<Logger::Warning
<<"Sending UDP reply to client "<<fromaddr
.toStringWithPort()<<" failed with: "<<strerror(errno
)<<endl
;
1730 if(response
.length() >= sizeof(struct dnsheader
)) {
1731 struct dnsheader tmpdh
;
1732 memcpy(&tmpdh
, response
.c_str(), sizeof(tmpdh
));
1733 updateResponseStats(tmpdh
.rcode
, fromaddr
, response
.length(), 0, 0);
1735 g_stats
.avgLatencyUsec
=(1-1.0/g_latencyStatSize
)*g_stats
.avgLatencyUsec
+ 0.0; // we assume 0 usec
1736 g_stats
.avgLatencyOursUsec
=(1-1.0/g_latencyStatSize
)*g_stats
.avgLatencyOursUsec
+ 0.0; // we assume 0 usec
1740 catch(std::exception
& e
) {
1741 L
<<Logger::Error
<<"Error processing or aging answer packet: "<<e
.what()<<endl
;
1746 if(t_pdl
->ipfilter(fromaddr
, destaddr
, *dh
)) {
1748 L
<<Logger::Notice
<<t_id
<<" ["<<MT
->getTid()<<"/"<<MT
->numProcesses()<<"] DROPPED question from "<<fromaddr
.toStringWithPort()<<" based on policy"<<endl
;
1749 g_stats
.policyDrops
++;
1754 if(MT
->numProcesses() > g_maxMThreads
) {
1756 L
<<Logger::Notice
<<t_id
<<" ["<<MT
->getTid()<<"/"<<MT
->numProcesses()<<"] DROPPED question from "<<fromaddr
.toStringWithPort()<<", over capacity"<<endl
;
1758 g_stats
.overCapacityDrops
++;
1762 DNSComboWriter
* dc
= new DNSComboWriter(question
.c_str(), question
.size(), g_now
);
1766 dc
->d_query
= question
;
1767 dc
->setRemote(&fromaddr
);
1768 dc
->setLocal(destaddr
);
1770 dc
->d_policyTags
= policyTags
;
1772 dc
->d_ecsFound
= ecsFound
;
1773 dc
->d_ecsParsed
= ecsParsed
;
1774 dc
->d_ednssubnet
= ednssubnet
;
1775 #ifdef HAVE_PROTOBUF
1776 if (luaconfsLocal
->protobufServer
|| luaconfsLocal
->outgoingProtobufServer
) {
1777 dc
->d_uuid
= uniqueId
;
1779 dc
->d_requestorId
= requestorId
;
1780 dc
->d_deviceId
= deviceId
;
1783 MT
->makeThread(startDoResolve
, (void*) dc
); // deletes dc
1788 static void handleNewUDPQuestion(int fd
, FDMultiplexer::funcparam_t
& var
)
1792 ComboAddress fromaddr
;
1796 bool firstQuery
= true;
1798 fromaddr
.sin6
.sin6_family
=AF_INET6
; // this makes sure fromaddr is big enough
1799 fillMSGHdr(&msgh
, &iov
, cbuf
, sizeof(cbuf
), data
, sizeof(data
), &fromaddr
);
1802 if((len
=recvmsg(fd
, &msgh
, 0)) >= 0) {
1807 t_remotes
->push_back(fromaddr
);
1809 if(t_allowFrom
&& !t_allowFrom
->match(&fromaddr
)) {
1811 L
<<Logger::Error
<<"["<<MT
->getTid()<<"] dropping UDP query from "<<fromaddr
.toString()<<", address not matched by allow-from"<<endl
;
1813 g_stats
.unauthorizedUDP
++;
1816 BOOST_STATIC_ASSERT(offsetof(sockaddr_in
, sin_port
) == offsetof(sockaddr_in6
, sin6_port
));
1817 if(!fromaddr
.sin4
.sin_port
) { // also works for IPv6
1819 L
<<Logger::Error
<<"["<<MT
->getTid()<<"] dropping UDP query from "<<fromaddr
.toStringWithPort()<<", can't deal with port 0"<<endl
;
1821 g_stats
.clientParseError
++; // not quite the best place to put it, but needs to go somewhere
1825 dnsheader
* dh
=(dnsheader
*)data
;
1828 g_stats
.ignoredCount
++;
1829 if(g_logCommonErrors
)
1830 L
<<Logger::Error
<<"Ignoring answer from "<<fromaddr
.toString()<<" on server socket!"<<endl
;
1832 else if(dh
->opcode
) {
1833 g_stats
.ignoredCount
++;
1834 if(g_logCommonErrors
)
1835 L
<<Logger::Error
<<"Ignoring non-query opcode "<<dh
->opcode
<<" from "<<fromaddr
.toString()<<" on server socket!"<<endl
;
1838 string
question(data
, (size_t)len
);
1839 struct timeval tv
={0,0};
1840 HarvestTimestamp(&msgh
, &tv
);
1842 memset(&dest
, 0, sizeof(dest
)); // this makes sure we ignore this address if not returned by recvmsg above
1843 auto loc
= rplookup(g_listenSocketsAddresses
, fd
);
1844 if(HarvestDestinationAddress(&msgh
, &dest
)) {
1845 // but.. need to get port too
1847 dest
.sin4
.sin_port
= loc
->sin4
.sin_port
;
1854 dest
.sin4
.sin_family
= fromaddr
.sin4
.sin_family
;
1855 socklen_t slen
= dest
.getSocklen();
1856 getsockname(fd
, (sockaddr
*)&dest
, &slen
); // if this fails, we're ok with it
1859 if(g_weDistributeQueries
)
1860 distributeAsyncFunction(question
, boost::bind(doProcessUDPQuestion
, question
, fromaddr
, dest
, tv
, fd
));
1862 doProcessUDPQuestion(question
, fromaddr
, dest
, tv
, fd
);
1865 catch(MOADNSException
& mde
) {
1866 g_stats
.clientParseError
++;
1867 if(g_logCommonErrors
)
1868 L
<<Logger::Error
<<"Unable to parse packet from remote UDP client "<<fromaddr
.toString() <<": "<<mde
.what()<<endl
;
1870 catch(std::runtime_error
& e
) {
1871 g_stats
.clientParseError
++;
1872 if(g_logCommonErrors
)
1873 L
<<Logger::Error
<<"Unable to parse packet from remote UDP client "<<fromaddr
.toString() <<": "<<e
.what()<<endl
;
1877 // cerr<<t_id<<" had error: "<<stringerror()<<endl;
1878 if(firstQuery
&& errno
== EAGAIN
)
1879 g_stats
.noPacketError
++;
1885 static void makeTCPServerSockets(unsigned int threadId
)
1888 vector
<string
>locals
;
1889 stringtok(locals
,::arg()["local-address"]," ,");
1892 throw PDNSException("No local address specified");
1894 for(vector
<string
>::const_iterator i
=locals
.begin();i
!=locals
.end();++i
) {
1896 st
.port
=::arg().asNum("local-port");
1897 parseService(*i
, st
);
1901 memset((char *)&sin
,0, sizeof(sin
));
1902 sin
.sin4
.sin_family
= AF_INET
;
1903 if(!IpToU32(st
.host
, (uint32_t*)&sin
.sin4
.sin_addr
.s_addr
)) {
1904 sin
.sin6
.sin6_family
= AF_INET6
;
1905 if(makeIPv6sockaddr(st
.host
, &sin
.sin6
) < 0)
1906 throw PDNSException("Unable to resolve local address for TCP server on '"+ st
.host
+"'");
1909 fd
=socket(sin
.sin6
.sin6_family
, SOCK_STREAM
, 0);
1911 throw PDNSException("Making a TCP server socket for resolver: "+stringerror());
1916 if(setsockopt(fd
, SOL_SOCKET
, SO_REUSEADDR
, &tmp
, sizeof tmp
)<0) {
1917 L
<<Logger::Error
<<"Setsockopt failed for TCP listening socket"<<endl
;
1920 if(sin
.sin6
.sin6_family
== AF_INET6
&& setsockopt(fd
, IPPROTO_IPV6
, IPV6_V6ONLY
, &tmp
, sizeof(tmp
)) < 0) {
1921 L
<<Logger::Error
<<"Failed to set IPv6 socket to IPv6 only, continuing anyhow: "<<strerror(errno
)<<endl
;
1924 #ifdef TCP_DEFER_ACCEPT
1925 if(setsockopt(fd
, SOL_TCP
, TCP_DEFER_ACCEPT
, &tmp
, sizeof tmp
) >= 0) {
1926 if(i
==locals
.begin())
1927 L
<<Logger::Error
<<"Enabled TCP data-ready filter for (slight) DoS protection"<<endl
;
1931 if( ::arg().mustDo("non-local-bind") )
1932 Utility::setBindAny(AF_INET
, fd
);
1936 if(setsockopt(fd
, SOL_SOCKET
, SO_REUSEPORT
, &tmp
, sizeof(tmp
)) < 0)
1937 throw PDNSException("SO_REUSEPORT: "+stringerror());
1941 if (::arg().asNum("tcp-fast-open") > 0) {
1943 int fastOpenQueueSize
= ::arg().asNum("tcp-fast-open");
1944 if (setsockopt(fd
, IPPROTO_TCP
, TCP_FASTOPEN
, &fastOpenQueueSize
, sizeof fastOpenQueueSize
) < 0) {
1945 L
<<Logger::Error
<<"Failed to enable TCP Fast Open for listening socket: "<<strerror(errno
)<<endl
;
1948 L
<<Logger::Warning
<<"TCP Fast Open configured but not supported for listening socket"<<endl
;
1952 sin
.sin4
.sin_port
= htons(st
.port
);
1953 socklen_t socklen
=sin
.sin4
.sin_family
==AF_INET
? sizeof(sin
.sin4
) : sizeof(sin
.sin6
);
1954 if (::bind(fd
, (struct sockaddr
*)&sin
, socklen
)<0)
1955 throw PDNSException("Binding TCP server socket for "+ st
.host
+": "+stringerror());
1958 setSocketSendBuffer(fd
, 65000);
1960 deferredAdds
[threadId
].push_back(make_pair(fd
, handleNewTCPQuestion
));
1961 g_tcpListenSockets
.push_back(fd
);
1962 // we don't need to update g_listenSocketsAddresses since it doesn't work for TCP/IP:
1963 // - fd is not that which we know here, but returned from accept()
1964 if(sin
.sin4
.sin_family
== AF_INET
)
1965 L
<<Logger::Error
<<"Listening for TCP queries on "<< sin
.toString() <<":"<<st
.port
<<endl
;
1967 L
<<Logger::Error
<<"Listening for TCP queries on ["<< sin
.toString() <<"]:"<<st
.port
<<endl
;
1971 static void makeUDPServerSockets(unsigned int threadId
)
1974 vector
<string
>locals
;
1975 stringtok(locals
,::arg()["local-address"]," ,");
1978 throw PDNSException("No local address specified");
1980 for(vector
<string
>::const_iterator i
=locals
.begin();i
!=locals
.end();++i
) {
1982 st
.port
=::arg().asNum("local-port");
1983 parseService(*i
, st
);
1987 memset(&sin
, 0, sizeof(sin
));
1988 sin
.sin4
.sin_family
= AF_INET
;
1989 if(!IpToU32(st
.host
.c_str() , (uint32_t*)&sin
.sin4
.sin_addr
.s_addr
)) {
1990 sin
.sin6
.sin6_family
= AF_INET6
;
1991 if(makeIPv6sockaddr(st
.host
, &sin
.sin6
) < 0)
1992 throw PDNSException("Unable to resolve local address for UDP server on '"+ st
.host
+"'");
1995 int fd
=socket(sin
.sin4
.sin_family
, SOCK_DGRAM
, 0);
1997 throw PDNSException("Making a UDP server socket for resolver: "+netstringerror());
1999 if (!setSocketTimestamps(fd
))
2000 L
<<Logger::Warning
<<"Unable to enable timestamp reporting for socket"<<endl
;
2002 if(IsAnyAddress(sin
)) {
2003 if(sin
.sin4
.sin_family
== AF_INET
)
2004 if(!setsockopt(fd
, IPPROTO_IP
, GEN_IP_PKTINFO
, &one
, sizeof(one
))) // linux supports this, so why not - might fail on other systems
2005 g_fromtosockets
.insert(fd
);
2006 #ifdef IPV6_RECVPKTINFO
2007 if(sin
.sin4
.sin_family
== AF_INET6
)
2008 if(!setsockopt(fd
, IPPROTO_IPV6
, IPV6_RECVPKTINFO
, &one
, sizeof(one
)))
2009 g_fromtosockets
.insert(fd
);
2011 if(sin
.sin6
.sin6_family
== AF_INET6
&& setsockopt(fd
, IPPROTO_IPV6
, IPV6_V6ONLY
, &one
, sizeof(one
)) < 0) {
2012 L
<<Logger::Error
<<"Failed to set IPv6 socket to IPv6 only, continuing anyhow: "<<strerror(errno
)<<endl
;
2015 if( ::arg().mustDo("non-local-bind") )
2016 Utility::setBindAny(AF_INET6
, fd
);
2020 setSocketReceiveBuffer(fd
, 250000);
2021 sin
.sin4
.sin_port
= htons(st
.port
);
2026 if(setsockopt(fd
, SOL_SOCKET
, SO_REUSEPORT
, &one
, sizeof(one
)) < 0)
2027 throw PDNSException("SO_REUSEPORT: "+stringerror());
2030 socklen_t socklen
=sin
.getSocklen();
2031 if (::bind(fd
, (struct sockaddr
*)&sin
, socklen
)<0)
2032 throw PDNSException("Resolver binding to server socket on port "+ std::to_string(st
.port
) +" for "+ st
.host
+": "+stringerror());
2036 deferredAdds
[threadId
].push_back(make_pair(fd
, handleNewUDPQuestion
));
2037 g_listenSocketsAddresses
[fd
]=sin
; // this is written to only from the startup thread, not from the workers
2038 if(sin
.sin4
.sin_family
== AF_INET
)
2039 L
<<Logger::Error
<<"Listening for UDP queries on "<< sin
.toString() <<":"<<st
.port
<<endl
;
2041 L
<<Logger::Error
<<"Listening for UDP queries on ["<< sin
.toString() <<"]:"<<st
.port
<<endl
;
2045 static void daemonize(void)
2052 int i
=open("/dev/null",O_RDWR
); /* open stdin */
2054 L
<<Logger::Critical
<<"Unable to open /dev/null: "<<stringerror()<<endl
;
2056 dup2(i
,0); /* stdin */
2057 dup2(i
,1); /* stderr */
2058 dup2(i
,2); /* stderr */
2063 static void usr1Handler(int)
2068 static void usr2Handler(int)
2071 SyncRes::setDefaultLogMode(g_quiet
? SyncRes::LogNone
: SyncRes::Log
);
2072 ::arg().set("quiet")=g_quiet
? "" : "no";
2075 static void doStats(void)
2077 static time_t lastOutputTime
;
2078 static uint64_t lastQueryCount
;
2080 uint64_t cacheHits
= broadcastAccFunction
<uint64_t>(pleaseGetCacheHits
);
2081 uint64_t cacheMisses
= broadcastAccFunction
<uint64_t>(pleaseGetCacheMisses
);
2083 if(g_stats
.qcounter
&& (cacheHits
+ cacheMisses
) && SyncRes::s_queries
&& SyncRes::s_outqueries
) {
2084 L
<<Logger::Notice
<<"stats: "<<g_stats
.qcounter
<<" questions, "<<
2085 broadcastAccFunction
<uint64_t>(pleaseGetCacheSize
)<< " cache entries, "<<
2086 broadcastAccFunction
<uint64_t>(pleaseGetNegCacheSize
)<<" negative entries, "<<
2087 (int)((cacheHits
*100.0)/(cacheHits
+cacheMisses
))<<"% cache hits"<<endl
;
2089 L
<<Logger::Notice
<<"stats: throttle map: "
2090 << broadcastAccFunction
<uint64_t>(pleaseGetThrottleSize
) <<", ns speeds: "
2091 << broadcastAccFunction
<uint64_t>(pleaseGetNsSpeedsSize
)<<endl
;
2092 L
<<Logger::Notice
<<"stats: outpacket/query ratio "<<(int)(SyncRes::s_outqueries
*100.0/SyncRes::s_queries
)<<"%";
2093 L
<<Logger::Notice
<<", "<<(int)(SyncRes::s_throttledqueries
*100.0/(SyncRes::s_outqueries
+SyncRes::s_throttledqueries
))<<"% throttled, "
2094 <<SyncRes::s_nodelegated
<<" no-delegation drops"<<endl
;
2095 L
<<Logger::Notice
<<"stats: "<<SyncRes::s_tcpoutqueries
<<" outgoing tcp connections, "<<
2096 broadcastAccFunction
<uint64_t>(pleaseGetConcurrentQueries
)<<" queries running, "<<SyncRes::s_outgoingtimeouts
<<" outgoing timeouts"<<endl
;
2098 //L<<Logger::Notice<<"stats: "<<g_stats.ednsPingMatches<<" ping matches, "<<g_stats.ednsPingMismatches<<" mismatches, "<<
2099 //g_stats.noPingOutQueries<<" outqueries w/o ping, "<< g_stats.noEdnsOutQueries<<" w/o EDNS"<<endl;
2101 L
<<Logger::Notice
<<"stats: " << broadcastAccFunction
<uint64_t>(pleaseGetPacketCacheSize
) <<
2102 " packet cache entries, "<<(int)(100.0*broadcastAccFunction
<uint64_t>(pleaseGetPacketCacheHits
)/SyncRes::s_queries
) << "% packet cache hits"<<endl
;
2104 time_t now
= time(0);
2105 if(lastOutputTime
&& lastQueryCount
&& now
!= lastOutputTime
) {
2106 L
<<Logger::Notice
<<"stats: "<< (SyncRes::s_queries
- lastQueryCount
) / (now
- lastOutputTime
) <<" qps (average over "<< (now
- lastOutputTime
) << " seconds)"<<endl
;
2108 lastOutputTime
= now
;
2109 lastQueryCount
= SyncRes::s_queries
;
2111 else if(statsWanted
)
2112 L
<<Logger::Notice
<<"stats: no stats yet!"<<endl
;
2117 static void houseKeeping(void *)
2119 static thread_local
time_t last_stat
, last_rootupdate
, last_prune
, last_secpoll
;
2120 static thread_local
int cleanCounter
=0;
2121 static thread_local
bool s_running
; // houseKeeping can get suspended in secpoll, and be restarted, which makes us do duplicate work
2128 Utility::gettimeofday(&now
, 0);
2130 if(now
.tv_sec
- last_prune
> (time_t)(5 + t_id
)) {
2133 t_RC
->doPrune(g_maxCacheEntries
/ g_numThreads
); // this function is local to a thread, so fine anyhow
2134 t_packetCache
->doPruneTo(g_maxPacketCacheEntries
/ g_numWorkerThreads
);
2136 SyncRes::pruneNegCache(g_maxCacheEntries
/ (g_numWorkerThreads
* 10));
2138 if(!((cleanCounter
++)%40)) { // this is a full scan!
2139 time_t limit
=now
.tv_sec
-300;
2140 SyncRes::pruneNSSpeeds(limit
);
2145 if(now
.tv_sec
- last_rootupdate
> 7200) {
2146 int res
= SyncRes::getRootNS(g_now
, nullptr);
2148 last_rootupdate
=now
.tv_sec
;
2152 if(g_statisticsInterval
> 0 && now
.tv_sec
- last_stat
>= g_statisticsInterval
) {
2157 if(now
.tv_sec
- last_secpoll
>= 3600) {
2159 doSecPoll(&last_secpoll
);
2166 catch(PDNSException
& ae
)
2169 L
<<Logger::Error
<<"Fatal error in housekeeping thread: "<<ae
.reason
<<endl
;
2174 static void makeThreadPipes()
2176 for(unsigned int n
=0; n
< g_numThreads
; ++n
) {
2177 struct ThreadPipeSet tps
;
2180 unixDie("Creating pipe for inter-thread communications");
2182 tps
.readToThread
= fd
[0];
2183 tps
.writeToThread
= fd
[1];
2186 unixDie("Creating pipe for inter-thread communications");
2187 tps
.readFromThread
= fd
[0];
2188 tps
.writeFromThread
= fd
[1];
2190 g_pipes
.push_back(tps
);
2200 void broadcastFunction(const pipefunc_t
& func
, bool skipSelf
)
2203 for(ThreadPipeSet
& tps
: g_pipes
)
2207 func(); // don't write to ourselves!
2211 ThreadMSG
* tmsg
= new ThreadMSG();
2213 tmsg
->wantAnswer
= true;
2214 if(write(tps
.writeToThread
, &tmsg
, sizeof(tmsg
)) != sizeof(tmsg
)) {
2216 unixDie("write to thread pipe returned wrong size or error");
2220 if(read(tps
.readFromThread
, &resp
, sizeof(resp
)) != sizeof(resp
))
2221 unixDie("read from thread pipe returned wrong size or error");
2224 // cerr <<"got response: " << *resp << endl;
2230 void distributeAsyncFunction(const string
& packet
, const pipefunc_t
& func
)
2232 unsigned int hash
= hashQuestion(packet
.c_str(), packet
.length(), g_disthashseed
);
2233 unsigned int target
= 1 + (hash
% (g_pipes
.size()-1));
2235 if(target
== t_id
) {
2239 ThreadPipeSet
& tps
= g_pipes
[target
];
2240 ThreadMSG
* tmsg
= new ThreadMSG();
2242 tmsg
->wantAnswer
= false;
2244 if(write(tps
.writeToThread
, &tmsg
, sizeof(tmsg
)) != sizeof(tmsg
)) {
2246 unixDie("write to thread pipe returned wrong size or error");
2250 static void handlePipeRequest(int fd
, FDMultiplexer::funcparam_t
& var
)
2252 ThreadMSG
* tmsg
= nullptr;
2254 if(read(fd
, &tmsg
, sizeof(tmsg
)) != sizeof(tmsg
)) { // fd == readToThread
2255 unixDie("read from thread pipe returned wrong size or error");
2260 resp
= tmsg
->func();
2262 catch(std::exception
& e
) {
2263 if(g_logCommonErrors
)
2264 L
<<Logger::Error
<<"PIPE function we executed created exception: "<<e
.what()<<endl
; // but what if they wanted an answer.. we send 0
2266 catch(PDNSException
& e
) {
2267 if(g_logCommonErrors
)
2268 L
<<Logger::Error
<<"PIPE function we executed created PDNS exception: "<<e
.reason
<<endl
; // but what if they wanted an answer.. we send 0
2270 if(tmsg
->wantAnswer
) {
2271 if(write(g_pipes
[t_id
].writeFromThread
, &resp
, sizeof(resp
)) != sizeof(resp
)) {
2273 unixDie("write to thread pipe returned wrong size or error");
2280 template<class T
> void *voider(const boost::function
<T
*()>& func
)
2285 vector
<ComboAddress
>& operator+=(vector
<ComboAddress
>&a
, const vector
<ComboAddress
>& b
)
2287 a
.insert(a
.end(), b
.begin(), b
.end());
2291 vector
<pair
<string
, uint16_t> >& operator+=(vector
<pair
<string
, uint16_t> >&a
, const vector
<pair
<string
, uint16_t> >& b
)
2293 a
.insert(a
.end(), b
.begin(), b
.end());
2297 vector
<pair
<DNSName
, uint16_t> >& operator+=(vector
<pair
<DNSName
, uint16_t> >&a
, const vector
<pair
<DNSName
, uint16_t> >& b
)
2299 a
.insert(a
.end(), b
.begin(), b
.end());
2304 template<class T
> T
broadcastAccFunction(const boost::function
<T
*()>& func
, bool skipSelf
)
2308 for(ThreadPipeSet
& tps
: g_pipes
)
2312 T
* resp
= (T
*)func(); // don't write to ourselves!
2314 //~ cerr <<"got direct: " << *resp << endl;
2322 ThreadMSG
* tmsg
= new ThreadMSG();
2323 tmsg
->func
= boost::bind(voider
<T
>, func
);
2324 tmsg
->wantAnswer
= true;
2326 if(write(tps
.writeToThread
, &tmsg
, sizeof(tmsg
)) != sizeof(tmsg
)) {
2328 unixDie("write to thread pipe returned wrong size or error");
2332 if(read(tps
.readFromThread
, &resp
, sizeof(resp
)) != sizeof(resp
))
2333 unixDie("read from thread pipe returned wrong size or error");
2336 //~ cerr <<"got response: " << *resp << endl;
2344 template string
broadcastAccFunction(const boost::function
<string
*()>& fun
, bool skipSelf
); // explicit instantiation
2345 template uint64_t broadcastAccFunction(const boost::function
<uint64_t*()>& fun
, bool skipSelf
); // explicit instantiation
2346 template vector
<ComboAddress
> broadcastAccFunction(const boost::function
<vector
<ComboAddress
> *()>& fun
, bool skipSelf
); // explicit instantiation
2347 template vector
<pair
<DNSName
,uint16_t> > broadcastAccFunction(const boost::function
<vector
<pair
<DNSName
, uint16_t> > *()>& fun
, bool skipSelf
); // explicit instantiation
2349 static void handleRCC(int fd
, FDMultiplexer::funcparam_t
& var
)
2352 string msg
=s_rcc
.recv(&remote
);
2353 RecursorControlParser rcp
;
2354 RecursorControlParser::func_t
* command
;
2356 string answer
=rcp
.getAnswer(msg
, &command
);
2358 // If we are inside a chroot, we need to strip
2359 if (!arg()["chroot"].empty()) {
2360 size_t len
= arg()["chroot"].length();
2361 remote
= remote
.substr(len
);
2365 s_rcc
.send(answer
, &remote
);
2368 catch(std::exception
& e
) {
2369 L
<<Logger::Error
<<"Error dealing with control socket request: "<<e
.what()<<endl
;
2371 catch(PDNSException
& ae
) {
2372 L
<<Logger::Error
<<"Error dealing with control socket request: "<<ae
.reason
<<endl
;
2376 static void handleTCPClientReadable(int fd
, FDMultiplexer::funcparam_t
& var
)
2378 PacketID
* pident
=any_cast
<PacketID
>(&var
);
2379 // cerr<<"handleTCPClientReadable called for fd "<<fd<<", pident->inNeeded: "<<pident->inNeeded<<", "<<pident->sock->getHandle()<<endl;
2381 shared_array
<char> buffer(new char[pident
->inNeeded
]);
2383 ssize_t ret
=recv(fd
, buffer
.get(), pident
->inNeeded
,0);
2385 pident
->inMSG
.append(&buffer
[0], &buffer
[ret
]);
2386 pident
->inNeeded
-=(size_t)ret
;
2387 if(!pident
->inNeeded
|| pident
->inIncompleteOkay
) {
2388 // cerr<<"Got entire load of "<<pident->inMSG.size()<<" bytes"<<endl;
2389 PacketID pid
=*pident
;
2390 string msg
=pident
->inMSG
;
2392 t_fdm
->removeReadFD(fd
);
2393 MT
->sendEvent(pid
, &msg
);
2396 // cerr<<"Still have "<<pident->inNeeded<<" left to go"<<endl;
2400 PacketID tmp
=*pident
;
2401 t_fdm
->removeReadFD(fd
); // pident might now be invalid (it isn't, but still)
2403 MT
->sendEvent(tmp
, &empty
); // this conveys error status
2407 static void handleTCPClientWritable(int fd
, FDMultiplexer::funcparam_t
& var
)
2409 PacketID
* pid
=any_cast
<PacketID
>(&var
);
2410 ssize_t ret
=send(fd
, pid
->outMSG
.c_str() + pid
->outPos
, pid
->outMSG
.size() - pid
->outPos
,0);
2412 pid
->outPos
+=(ssize_t
)ret
;
2413 if(pid
->outPos
==pid
->outMSG
.size()) {
2415 t_fdm
->removeWriteFD(fd
);
2416 MT
->sendEvent(tmp
, &tmp
.outMSG
); // send back what we sent to convey everything is ok
2419 else { // error or EOF
2421 t_fdm
->removeWriteFD(fd
);
2423 MT
->sendEvent(tmp
, &sent
); // we convey error status by sending empty string
2427 // resend event to everybody chained onto it
2428 static void doResends(MT_t::waiters_t::iterator
& iter
, PacketID resend
, const string
& content
)
2430 if(iter
->key
.chain
.empty())
2432 // cerr<<"doResends called!\n";
2433 for(PacketID::chain_t::iterator i
=iter
->key
.chain
.begin(); i
!= iter
->key
.chain
.end() ; ++i
) {
2436 // cerr<<"\tResending "<<content.size()<<" bytes for fd="<<resend.fd<<" and id="<<resend.id<<endl;
2438 MT
->sendEvent(resend
, &content
);
2439 g_stats
.chainResends
++;
2443 static void handleUDPServerResponse(int fd
, FDMultiplexer::funcparam_t
& var
)
2445 PacketID pid
=any_cast
<PacketID
>(var
);
2447 char data
[g_outgoingEDNSBufsize
];
2448 ComboAddress fromaddr
;
2449 socklen_t addrlen
=sizeof(fromaddr
);
2451 len
=recvfrom(fd
, data
, sizeof(data
), 0, (sockaddr
*)&fromaddr
, &addrlen
);
2453 if(len
< (ssize_t
) sizeof(dnsheader
)) {
2455 ; // cerr<<"Error on fd "<<fd<<": "<<stringerror()<<"\n";
2457 g_stats
.serverParseError
++;
2458 if(g_logCommonErrors
)
2459 L
<<Logger::Error
<<"Unable to parse packet from remote UDP server "<< fromaddr
.toString() <<
2460 ": packet smaller than DNS header"<<endl
;
2463 t_udpclientsocks
->returnSocket(fd
);
2466 MT_t::waiters_t::iterator iter
=MT
->d_waiters
.find(pid
);
2467 if(iter
!= MT
->d_waiters
.end())
2468 doResends(iter
, pid
, empty
);
2470 MT
->sendEvent(pid
, &empty
); // this denotes error (does lookup again.. at least L1 will be hot)
2475 memcpy(&dh
, data
, sizeof(dh
));
2478 pident
.remote
=fromaddr
;
2482 if(!dh
.qr
&& g_logCommonErrors
) {
2483 L
<<Logger::Notice
<<"Not taking data from question on outgoing socket from "<< fromaddr
.toStringWithPort() <<endl
;
2486 if(!dh
.qdcount
|| // UPC, Nominum, very old BIND on FormErr, NSD
2487 !dh
.qr
) { // one weird server
2488 pident
.domain
.clear();
2494 pident
.domain
=DNSName(data
, len
, 12, false, &pident
.type
); // don't copy this from above - we need to do the actual read
2496 catch(std::exception
& e
) {
2497 g_stats
.serverParseError
++; // won't be fed to lwres.cc, so we have to increment
2498 L
<<Logger::Warning
<<"Error in packet from remote nameserver "<< fromaddr
.toStringWithPort() << ": "<<e
.what() << endl
;
2503 packet
.assign(data
, len
);
2505 MT_t::waiters_t::iterator iter
=MT
->d_waiters
.find(pident
);
2506 if(iter
!= MT
->d_waiters
.end()) {
2507 doResends(iter
, pident
, packet
);
2512 if(!MT
->sendEvent(pident
, &packet
)) {
2513 // we do a full scan for outstanding queries on unexpected answers. not too bad since we only accept them on the right port number, which is hard enough to guess
2514 for(MT_t::waiters_t::iterator mthread
=MT
->d_waiters
.begin(); mthread
!=MT
->d_waiters
.end(); ++mthread
) {
2515 if(pident
.fd
==mthread
->key
.fd
&& mthread
->key
.remote
==pident
.remote
&& mthread
->key
.type
== pident
.type
&&
2516 pident
.domain
== mthread
->key
.domain
) {
2517 mthread
->key
.nearMisses
++;
2520 // be a bit paranoid here since we're weakening our matching
2521 if(pident
.domain
.empty() && !mthread
->key
.domain
.empty() && !pident
.type
&& mthread
->key
.type
&&
2522 pident
.id
== mthread
->key
.id
&& mthread
->key
.remote
== pident
.remote
) {
2523 // cerr<<"Empty response, rest matches though, sending to a waiter"<<endl;
2524 pident
.domain
= mthread
->key
.domain
;
2525 pident
.type
= mthread
->key
.type
;
2526 goto retryWithName
; // note that this only passes on an error, lwres will still reject the packet
2529 g_stats
.unexpectedCount
++; // if we made it here, it really is an unexpected answer
2530 if(g_logCommonErrors
) {
2531 L
<<Logger::Warning
<<"Discarding unexpected packet from "<<fromaddr
.toStringWithPort()<<": "<< (pident
.domain
.empty() ? "<empty>" : pident
.domain
.toString())<<", "<<pident
.type
<<", "<<MT
->d_waiters
.size()<<" waiters"<<endl
;
2535 t_udpclientsocks
->returnSocket(fd
);
2539 FDMultiplexer
* getMultiplexer()
2542 for(const auto& i
: FDMultiplexer::getMultiplexerMap()) {
2547 catch(FDMultiplexerException
&fe
) {
2548 L
<<Logger::Error
<<"Non-fatal error initializing possible multiplexer ("<<fe
.what()<<"), falling back"<<endl
;
2551 L
<<Logger::Error
<<"Non-fatal error initializing possible multiplexer"<<endl
;
2554 L
<<Logger::Error
<<"No working multiplexer found!"<<endl
;
2559 static string
* doReloadLuaScript()
2561 string fname
= ::arg()["lua-dns-script"];
2565 L
<<Logger::Error
<<t_id
<<" Unloaded current lua script"<<endl
;
2566 return new string("unloaded\n");
2569 t_pdl
= std::make_shared
<RecursorLua4
>(fname
);
2572 catch(std::exception
& e
) {
2573 L
<<Logger::Error
<<t_id
<<" Retaining current script, error from '"<<fname
<<"': "<< e
.what() <<endl
;
2574 return new string("retaining current script, error from '"+fname
+"': "+e
.what()+"\n");
2577 L
<<Logger::Warning
<<t_id
<<" (Re)loaded lua script from '"<<fname
<<"'"<<endl
;
2578 return new string("(re)loaded '"+fname
+"'\n");
2581 string
doQueueReloadLuaScript(vector
<string
>::const_iterator begin
, vector
<string
>::const_iterator end
)
2584 ::arg().set("lua-dns-script") = *begin
;
2586 return broadcastAccFunction
<string
>(doReloadLuaScript
);
2589 static string
* pleaseUseNewTraceRegex(const std::string
& newRegex
)
2592 if(newRegex
.empty()) {
2593 t_traceRegex
.reset();
2594 return new string("unset\n");
2597 t_traceRegex
= std::make_shared
<Regex
>(newRegex
);
2598 return new string("ok\n");
2601 catch(PDNSException
& ae
)
2603 return new string(ae
.reason
+"\n");
2606 string
doTraceRegex(vector
<string
>::const_iterator begin
, vector
<string
>::const_iterator end
)
2608 return broadcastAccFunction
<string
>(boost::bind(pleaseUseNewTraceRegex
, begin
!=end
? *begin
: ""));
2611 static void checkLinuxIPv6Limits()
2615 if(readFileIfThere("/proc/sys/net/ipv6/route/max_size", &line
)) {
2616 int lim
=std::stoi(line
);
2618 L
<<Logger::Error
<<"If using IPv6, please raise sysctl net.ipv6.route.max_size, currently set to "<<lim
<<" which is < 16384"<<endl
;
2623 static void checkOrFixFDS()
2625 unsigned int availFDs
=getFilenumLimit();
2626 unsigned int wantFDs
= g_maxMThreads
* g_numWorkerThreads
+25; // even healthier margin then before
2628 if(wantFDs
> availFDs
) {
2629 unsigned int hardlimit
= getFilenumLimit(true);
2630 if(hardlimit
>= wantFDs
) {
2631 setFilenumLimit(wantFDs
);
2632 L
<<Logger::Warning
<<"Raised soft limit on number of filedescriptors to "<<wantFDs
<<" to match max-mthreads and threads settings"<<endl
;
2635 int newval
= (hardlimit
- 25) / g_numWorkerThreads
;
2636 L
<<Logger::Warning
<<"Insufficient number of filedescriptors available for max-mthreads*threads setting! ("<<hardlimit
<<" < "<<wantFDs
<<"), reducing max-mthreads to "<<newval
<<endl
;
2637 g_maxMThreads
= newval
;
2638 setFilenumLimit(hardlimit
);
2643 static void* recursorThread(void*);
2645 static void* pleaseSupplantACLs(std::shared_ptr
<NetmaskGroup
> ng
)
2656 static bool l_initialized
;
2658 if(l_initialized
) { // only reload configuration file on second call
2659 string configname
=::arg()["config-dir"]+"/recursor.conf";
2660 cleanSlashes(configname
);
2662 if(!::arg().preParseFile(configname
.c_str(), "allow-from-file"))
2663 throw runtime_error("Unable to re-parse configuration file '"+configname
+"'");
2664 ::arg().preParseFile(configname
.c_str(), "allow-from", LOCAL_NETS
);
2665 ::arg().preParseFile(configname
.c_str(), "include-dir");
2666 ::arg().preParse(g_argc
, g_argv
, "include-dir");
2668 // then process includes
2669 std::vector
<std::string
> extraConfigs
;
2670 ::arg().gatherIncludes(extraConfigs
);
2672 for(const std::string
& fn
: extraConfigs
) {
2673 if(!::arg().preParseFile(fn
.c_str(), "allow-from-file", ::arg()["allow-from-file"]))
2674 throw runtime_error("Unable to re-parse configuration file include '"+fn
+"'");
2675 if(!::arg().preParseFile(fn
.c_str(), "allow-from", ::arg()["allow-from"]))
2676 throw runtime_error("Unable to re-parse configuration file include '"+fn
+"'");
2679 ::arg().preParse(g_argc
, g_argv
, "allow-from-file");
2680 ::arg().preParse(g_argc
, g_argv
, "allow-from");
2683 std::shared_ptr
<NetmaskGroup
> oldAllowFrom
= t_allowFrom
;
2684 std::shared_ptr
<NetmaskGroup
> allowFrom
= std::make_shared
<NetmaskGroup
>();
2686 if(!::arg()["allow-from-file"].empty()) {
2688 ifstream
ifs(::arg()["allow-from-file"].c_str());
2690 throw runtime_error("Could not open '"+::arg()["allow-from-file"]+"': "+stringerror());
2693 string::size_type pos
;
2694 while(getline(ifs
,line
)) {
2696 if(pos
!=string::npos
)
2702 allowFrom
->addMask(line
);
2704 L
<<Logger::Warning
<<"Done parsing " << allowFrom
->size() <<" allow-from ranges from file '"<<::arg()["allow-from-file"]<<"' - overriding 'allow-from' setting"<<endl
;
2706 else if(!::arg()["allow-from"].empty()) {
2708 stringtok(ips
, ::arg()["allow-from"], ", ");
2710 L
<<Logger::Warning
<<"Only allowing queries from: ";
2711 for(vector
<string
>::const_iterator i
= ips
.begin(); i
!= ips
.end(); ++i
) {
2712 allowFrom
->addMask(*i
);
2714 L
<<Logger::Warning
<<", ";
2715 L
<<Logger::Warning
<<*i
;
2717 L
<<Logger::Warning
<<endl
;
2720 if(::arg()["local-address"]!="127.0.0.1" && ::arg().asNum("local-port")==53)
2721 L
<<Logger::Error
<<"WARNING: Allowing queries from all IP addresses - this can be a security risk!"<<endl
;
2722 allowFrom
= nullptr;
2725 g_initialAllowFrom
= allowFrom
;
2726 broadcastFunction(boost::bind(pleaseSupplantACLs
, allowFrom
));
2727 oldAllowFrom
= nullptr;
2729 l_initialized
= true;
2733 static void setupDelegationOnly()
2735 vector
<string
> parts
;
2736 stringtok(parts
, ::arg()["delegation-only"], ", \t");
2737 for(const auto& p
: parts
) {
2738 SyncRes::addDelegationOnly(DNSName(p
));
2742 static std::map
<unsigned int, std::set
<int> > parseCPUMap()
2744 std::map
<unsigned int, std::set
<int> > result
;
2746 const std::string value
= ::arg()["cpu-map"];
2748 if (!value
.empty() && !isSettingThreadCPUAffinitySupported()) {
2749 L
<<Logger::Warning
<<"CPU mapping requested but not supported, skipping"<<endl
;
2753 std::vector
<std::string
> parts
;
2755 stringtok(parts
, value
, " \t");
2757 for(const auto& part
: parts
) {
2758 if (part
.find('=') == string::npos
)
2762 auto headers
= splitField(part
, '=');
2763 trim(headers
.first
);
2764 trim(headers
.second
);
2766 unsigned int threadId
= pdns_stou(headers
.first
);
2767 std::vector
<std::string
> cpus
;
2769 stringtok(cpus
, headers
.second
, ",");
2771 for(const auto& cpu
: cpus
) {
2772 int cpuId
= std::stoi(cpu
);
2774 result
[threadId
].insert(cpuId
);
2777 catch(const std::exception
& e
) {
2778 L
<<Logger::Error
<<"Error parsing cpu-map entry '"<<part
<<"': "<<e
.what()<<endl
;
2785 static void setCPUMap(const std::map
<unsigned int, std::set
<int> >& cpusMap
, unsigned int n
, pthread_t tid
)
2787 const auto& cpuMapping
= cpusMap
.find(n
);
2788 if (cpuMapping
!= cpusMap
.cend()) {
2789 int rc
= mapThreadToCPUList(tid
, cpuMapping
->second
);
2791 L
<<Logger::Info
<<"CPU affinity for worker "<<n
<<" has been set to CPU map:";
2792 for (const auto cpu
: cpuMapping
->second
) {
2793 L
<<Logger::Info
<<" "<<cpu
;
2795 L
<<Logger::Info
<<endl
;
2798 L
<<Logger::Warning
<<"Error setting CPU affinity for worker "<<n
<<" to CPU map:";
2799 for (const auto cpu
: cpuMapping
->second
) {
2800 L
<<Logger::Info
<<" "<<cpu
;
2802 L
<<Logger::Info
<<strerror(rc
)<<endl
;
2807 static int serviceMain(int argc
, char*argv
[])
2809 L
.setName(s_programname
);
2810 L
.disableSyslog(::arg().mustDo("disable-syslog"));
2811 L
.setTimestamps(::arg().mustDo("log-timestamp"));
2813 if(!::arg()["logging-facility"].empty()) {
2814 int val
=logFacilityToLOG(::arg().asNum("logging-facility") );
2816 theL().setFacility(val
);
2818 L
<<Logger::Error
<<"Unknown logging facility "<<::arg().asNum("logging-facility") <<endl
;
2821 showProductVersion();
2822 seedRandom(::arg()["entropy-source"]);
2824 g_disthashseed
=dns_random(0xffffffff);
2826 checkLinuxIPv6Limits();
2828 vector
<string
> addrs
;
2829 if(!::arg()["query-local-address6"].empty()) {
2830 SyncRes::s_doIPv6
=true;
2831 L
<<Logger::Warning
<<"Enabling IPv6 transport for outgoing queries"<<endl
;
2833 stringtok(addrs
, ::arg()["query-local-address6"], ", ;");
2834 for(const string
& addr
: addrs
) {
2835 g_localQueryAddresses6
.push_back(ComboAddress(addr
));
2839 L
<<Logger::Warning
<<"NOT using IPv6 for outgoing queries - set 'query-local-address6=::' to enable"<<endl
;
2842 stringtok(addrs
, ::arg()["query-local-address"], ", ;");
2843 for(const string
& addr
: addrs
) {
2844 g_localQueryAddresses4
.push_back(ComboAddress(addr
));
2847 catch(std::exception
& e
) {
2848 L
<<Logger::Error
<<"Assigning local query addresses: "<<e
.what();
2852 // keep this ABOVE loadRecursorLuaConfig!
2853 if(::arg()["dnssec"]=="off")
2854 g_dnssecmode
=DNSSECMode::Off
;
2855 else if(::arg()["dnssec"]=="process-no-validate")
2856 g_dnssecmode
=DNSSECMode::ProcessNoValidate
;
2857 else if(::arg()["dnssec"]=="process")
2858 g_dnssecmode
=DNSSECMode::Process
;
2859 else if(::arg()["dnssec"]=="validate")
2860 g_dnssecmode
=DNSSECMode::ValidateAll
;
2861 else if(::arg()["dnssec"]=="log-fail")
2862 g_dnssecmode
=DNSSECMode::ValidateForLog
;
2864 L
<<Logger::Error
<<"Unknown DNSSEC mode "<<::arg()["dnssec"]<<endl
;
2868 g_dnssecLogBogus
= ::arg().mustDo("dnssec-log-bogus");
2869 g_maxNSEC3Iterations
= ::arg().asNum("nsec3-max-iterations");
2871 g_maxCacheEntries
= ::arg().asNum("max-cache-entries");
2872 g_maxPacketCacheEntries
= ::arg().asNum("max-packetcache-entries");
2875 loadRecursorLuaConfig(::arg()["lua-config-file"], ::arg().mustDo("daemon"));
2877 catch (PDNSException
&e
) {
2878 L
<<Logger::Error
<<"Cannot load Lua configuration: "<<e
.reason
<<endl
;
2883 sortPublicSuffixList();
2885 if(!::arg()["dont-query"].empty()) {
2887 stringtok(ips
, ::arg()["dont-query"], ", ");
2888 ips
.push_back("0.0.0.0");
2889 ips
.push_back("::");
2891 L
<<Logger::Warning
<<"Will not send queries to: ";
2892 for(vector
<string
>::const_iterator i
= ips
.begin(); i
!= ips
.end(); ++i
) {
2893 SyncRes::addDontQuery(*i
);
2895 L
<<Logger::Warning
<<", ";
2896 L
<<Logger::Warning
<<*i
;
2898 L
<<Logger::Warning
<<endl
;
2901 g_quiet
=::arg().mustDo("quiet");
2903 g_weDistributeQueries
= ::arg().mustDo("pdns-distributes-queries");
2904 if(g_weDistributeQueries
) {
2905 L
<<Logger::Warning
<<"PowerDNS Recursor itself will distribute queries over threads"<<endl
;
2908 setupDelegationOnly();
2909 g_outgoingEDNSBufsize
=::arg().asNum("edns-outgoing-bufsize");
2911 if(::arg()["trace"]=="fail") {
2912 SyncRes::setDefaultLogMode(SyncRes::Store
);
2914 else if(::arg().mustDo("trace")) {
2915 SyncRes::setDefaultLogMode(SyncRes::Log
);
2916 ::arg().set("quiet")="no";
2921 SyncRes::s_minimumTTL
= ::arg().asNum("minimum-ttl-override");
2923 SyncRes::s_nopacketcache
= ::arg().mustDo("disable-packetcache");
2925 SyncRes::s_maxnegttl
=::arg().asNum("max-negative-ttl");
2926 SyncRes::s_maxcachettl
=max(::arg().asNum("max-cache-ttl"), 15);
2927 SyncRes::s_packetcachettl
=::arg().asNum("packetcache-ttl");
2928 // Cap the packetcache-servfail-ttl to the packetcache-ttl
2929 uint32_t packetCacheServFailTTL
= ::arg().asNum("packetcache-servfail-ttl");
2930 SyncRes::s_packetcacheservfailttl
=(packetCacheServFailTTL
> SyncRes::s_packetcachettl
) ? SyncRes::s_packetcachettl
: packetCacheServFailTTL
;
2931 SyncRes::s_serverdownmaxfails
=::arg().asNum("server-down-max-fails");
2932 SyncRes::s_serverdownthrottletime
=::arg().asNum("server-down-throttle-time");
2933 SyncRes::s_serverID
=::arg()["server-id"];
2934 SyncRes::s_maxqperq
=::arg().asNum("max-qperq");
2935 SyncRes::s_maxtotusec
=1000*::arg().asNum("max-total-msec");
2936 SyncRes::s_maxdepth
=::arg().asNum("max-recursion-depth");
2937 SyncRes::s_rootNXTrust
= ::arg().mustDo( "root-nx-trust");
2938 if(SyncRes::s_serverID
.empty()) {
2940 gethostname(tmp
, sizeof(tmp
)-1);
2941 SyncRes::s_serverID
=tmp
;
2944 SyncRes::s_ecsipv4limit
= ::arg().asNum("ecs-ipv4-bits");
2945 SyncRes::s_ecsipv6limit
= ::arg().asNum("ecs-ipv6-bits");
2947 if (!::arg().isEmpty("ecs-scope-zero-address")) {
2948 ComboAddress
scopeZero(::arg()["ecs-scope-zero-address"]);
2949 SyncRes::setECSScopeZeroAddress(Netmask(scopeZero
, scopeZero
.isIPv4() ? 32 : 128));
2953 for (const auto& addr
: g_localQueryAddresses4
) {
2954 if (!IsAnyAddress(addr
)) {
2955 SyncRes::setECSScopeZeroAddress(Netmask(addr
, 32));
2961 for (const auto& addr
: g_localQueryAddresses6
) {
2962 if (!IsAnyAddress(addr
)) {
2963 SyncRes::setECSScopeZeroAddress(Netmask(addr
, 128));
2969 SyncRes::setECSScopeZeroAddress(Netmask("127.0.0.1/32"));
2974 g_networkTimeoutMsec
= ::arg().asNum("network-timeout");
2976 g_initialDomainMap
= parseAuthAndForwards();
2978 g_latencyStatSize
=::arg().asNum("latency-statistic-size");
2980 g_logCommonErrors
=::arg().mustDo("log-common-errors");
2981 g_logRPZChanges
= ::arg().mustDo("log-rpz-changes");
2983 g_anyToTcp
= ::arg().mustDo("any-to-tcp");
2984 g_udpTruncationThreshold
= ::arg().asNum("udp-truncation-threshold");
2986 g_lowercaseOutgoing
= ::arg().mustDo("lowercase-outgoing");
2988 g_numWorkerThreads
= ::arg().asNum("threads");
2989 g_numThreads
= g_numWorkerThreads
+ g_weDistributeQueries
;
2990 g_maxMThreads
= ::arg().asNum("max-mthreads");
2992 g_gettagNeedsEDNSOptions
= ::arg().mustDo("gettag-needs-edns-options");
2994 g_statisticsInterval
= ::arg().asNum("statistics-interval");
2997 g_reusePort
= ::arg().mustDo("reuseport");
3000 g_useOneSocketPerThread
= (!g_weDistributeQueries
&& g_reusePort
);
3002 if (g_useOneSocketPerThread
) {
3003 for (unsigned int threadId
= 0; threadId
< g_numWorkerThreads
; threadId
++) {
3004 makeUDPServerSockets(threadId
);
3005 makeTCPServerSockets(threadId
);
3009 makeUDPServerSockets(0);
3010 makeTCPServerSockets(0);
3013 SyncRes::parseEDNSSubnetWhitelist(::arg()["edns-subnet-whitelist"]);
3014 g_useIncomingECS
= ::arg().mustDo("use-incoming-edns-subnet");
3017 for(forks
= 0; forks
< ::arg().asNum("processes") - 1; ++forks
) {
3018 if(!fork()) // we are child
3022 if(::arg().mustDo("daemon")) {
3023 L
<<Logger::Warning
<<"Calling daemonize, going to background"<<endl
;
3024 L
.toConsole(Logger::Critical
);
3026 loadRecursorLuaConfig(::arg()["lua-config-file"], false);
3028 signal(SIGUSR1
,usr1Handler
);
3029 signal(SIGUSR2
,usr2Handler
);
3030 signal(SIGPIPE
,SIG_IGN
);
3034 #ifdef HAVE_LIBSODIUM
3035 if (sodium_init() == -1) {
3036 L
<<Logger::Error
<<"Unable to initialize sodium crypto library"<<endl
;
3041 openssl_thread_setup();
3045 if(!::arg()["setgid"].empty())
3046 newgid
=Utility::makeGidNumeric(::arg()["setgid"]);
3048 if(!::arg()["setuid"].empty())
3049 newuid
=Utility::makeUidNumeric(::arg()["setuid"]);
3051 Utility::dropGroupPrivs(newuid
, newgid
);
3053 if (!::arg()["chroot"].empty()) {
3056 ns
= getenv("NOTIFY_SOCKET");
3057 if (ns
!= nullptr) {
3058 L
<<Logger::Error
<<"Unable to chroot when running from systemd. Please disable chroot= or set the 'Type' for this service to 'simple'"<<endl
;
3062 if (chroot(::arg()["chroot"].c_str())<0 || chdir("/") < 0) {
3063 L
<<Logger::Error
<<"Unable to chroot to '"+::arg()["chroot"]+"': "<<strerror (errno
)<<", exiting"<<endl
;
3067 L
<<Logger::Error
<<"Chrooted to '"<<::arg()["chroot"]<<"'"<<endl
;
3070 s_pidfname
=::arg()["socket-dir"]+"/"+s_programname
+".pid";
3071 if(!s_pidfname
.empty())
3072 unlink(s_pidfname
.c_str()); // remove possible old pid file
3075 makeControlChannelSocket( ::arg().asNum("processes") > 1 ? forks
: -1);
3077 Utility::dropUserPrivs(newuid
);
3081 g_tcpTimeout
=::arg().asNum("client-tcp-timeout");
3082 g_maxTCPPerClient
=::arg().asNum("max-tcp-per-client");
3083 g_tcpMaxQueriesPerConn
=::arg().asNum("max-tcp-queries-per-connection");
3085 if (::arg().mustDo("snmp-agent")) {
3086 g_snmpAgent
= std::make_shared
<RecursorSNMPAgent
>("recursor", ::arg()["snmp-master-socket"]);
3090 const auto cpusMap
= parseCPUMap();
3091 if(g_numThreads
== 1) {
3092 L
<<Logger::Warning
<<"Operating unthreaded"<<endl
;
3094 sd_notify(0, "READY=1");
3096 setCPUMap(cpusMap
, 0, pthread_self());
3101 L
<<Logger::Warning
<<"Launching "<< g_numThreads
<<" threads"<<endl
;
3102 for(unsigned int n
=0; n
< g_numThreads
; ++n
) {
3103 pthread_create(&tid
, 0, recursorThread
, (void*)(long)n
);
3105 setCPUMap(cpusMap
, n
, tid
);
3109 sd_notify(0, "READY=1");
3111 pthread_join(tid
, &res
);
3116 static void* recursorThread(void* ptr
)
3119 t_id
=(int) (long) ptr
;
3120 SyncRes
tmp(g_now
); // make sure it allocates tsstorage before we do anything, like primeHints or so..
3121 SyncRes::setDomainMap(g_initialDomainMap
);
3122 t_allowFrom
= g_initialAllowFrom
;
3123 t_udpclientsocks
= std::unique_ptr
<UDPClientSocks
>(new UDPClientSocks());
3124 t_tcpClientCounts
= std::unique_ptr
<tcpClientCounts_t
>(new tcpClientCounts_t());
3127 t_packetCache
= std::unique_ptr
<RecursorPacketCache
>(new RecursorPacketCache());
3129 #ifdef HAVE_PROTOBUF
3130 t_uuidGenerator
= std::unique_ptr
<boost::uuids::random_generator
>(new boost::uuids::random_generator());
3132 L
<<Logger::Warning
<<"Done priming cache with root hints"<<endl
;
3135 if(!::arg()["lua-dns-script"].empty()) {
3136 t_pdl
= std::make_shared
<RecursorLua4
>(::arg()["lua-dns-script"]);
3137 L
<<Logger::Warning
<<"Loaded 'lua' script from '"<<::arg()["lua-dns-script"]<<"'"<<endl
;
3140 catch(std::exception
&e
) {
3141 L
<<Logger::Error
<<"Failed to load 'lua' script from '"<<::arg()["lua-dns-script"]<<"': "<<e
.what()<<endl
;
3145 unsigned int ringsize
=::arg().asNum("stats-ringbuffer-entries") / g_numWorkerThreads
;
3147 t_remotes
= std::unique_ptr
<addrringbuf_t
>(new addrringbuf_t());
3148 if(g_weDistributeQueries
) // if so, only 1 thread does recvfrom
3149 t_remotes
->set_capacity(::arg().asNum("stats-ringbuffer-entries"));
3151 t_remotes
->set_capacity(ringsize
);
3152 t_servfailremotes
= std::unique_ptr
<addrringbuf_t
>(new addrringbuf_t());
3153 t_servfailremotes
->set_capacity(ringsize
);
3154 t_largeanswerremotes
= std::unique_ptr
<addrringbuf_t
>(new addrringbuf_t());
3155 t_largeanswerremotes
->set_capacity(ringsize
);
3157 t_queryring
= std::unique_ptr
<boost::circular_buffer
<pair
<DNSName
, uint16_t> > >(new boost::circular_buffer
<pair
<DNSName
, uint16_t> >());
3158 t_queryring
->set_capacity(ringsize
);
3159 t_servfailqueryring
= std::unique_ptr
<boost::circular_buffer
<pair
<DNSName
, uint16_t> > >(new boost::circular_buffer
<pair
<DNSName
, uint16_t> >());
3160 t_servfailqueryring
->set_capacity(ringsize
);
3163 MT
=std::unique_ptr
<MTasker
<PacketID
,string
> >(new MTasker
<PacketID
,string
>(::arg().asNum("stack-size")));
3167 t_fdm
=getMultiplexer();
3169 if(::arg().mustDo("webserver")) {
3170 L
<<Logger::Warning
<< "Enabling web server" << endl
;
3172 new RecursorWebServer(t_fdm
);
3174 catch(PDNSException
&e
) {
3175 L
<<Logger::Error
<<"Exception: "<<e
.reason
<<endl
;
3179 L
<<Logger::Error
<<"Enabled '"<< t_fdm
->getName() << "' multiplexer"<<endl
;
3182 t_fdm
->addReadFD(g_pipes
[t_id
].readToThread
, handlePipeRequest
);
3184 if(g_useOneSocketPerThread
) {
3185 for(deferredAdd_t::const_iterator i
= deferredAdds
[t_id
].cbegin(); i
!= deferredAdds
[t_id
].cend(); ++i
) {
3186 t_fdm
->addReadFD(i
->first
, i
->second
);
3190 if(!g_weDistributeQueries
|| !t_id
) { // if we distribute queries, only t_id = 0 listens
3191 for(deferredAdd_t::const_iterator i
= deferredAdds
[0].cbegin(); i
!= deferredAdds
[0].cend(); ++i
) {
3192 t_fdm
->addReadFD(i
->first
, i
->second
);
3199 t_fdm
->addReadFD(s_rcc
.d_fd
, handleRCC
); // control channel
3202 unsigned int maxTcpClients
=::arg().asNum("max-tcp-clients");
3204 bool listenOnTCP(true);
3206 time_t last_carbon
=0;
3207 time_t carbonInterval
=::arg().asNum("carbon-interval");
3208 counter
.store(0); // used to periodically execute certain tasks
3210 while(MT
->schedule(&g_now
)); // MTasker letting the mthreads do their thing
3212 if(!(counter
%500)) {
3213 MT
->makeThread(houseKeeping
, 0);
3217 typedef vector
<pair
<int, FDMultiplexer::funcparam_t
> > expired_t
;
3218 expired_t expired
=t_fdm
->getTimeouts(g_now
);
3220 for(expired_t::iterator i
=expired
.begin() ; i
!= expired
.end(); ++i
) {
3221 shared_ptr
<TCPConnection
> conn
=any_cast
<shared_ptr
<TCPConnection
> >(i
->second
);
3222 if(g_logCommonErrors
)
3223 L
<<Logger::Warning
<<"Timeout from remote TCP client "<< conn
->d_remote
.toString() <<endl
;
3224 t_fdm
->removeReadFD(i
->first
);
3230 if(!t_id
&& statsWanted
) {
3234 Utility::gettimeofday(&g_now
, 0);
3236 if(!t_id
&& (g_now
.tv_sec
- last_carbon
>= carbonInterval
)) {
3237 MT
->makeThread(doCarbonDump
, 0);
3238 last_carbon
= g_now
.tv_sec
;
3242 // 'run' updates g_now for us
3244 if(!g_weDistributeQueries
|| !t_id
) { // if pdns distributes queries, only tid 0 should do this
3246 if(TCPConnection::getCurrentConnections() > maxTcpClients
) { // shutdown, too many connections
3247 for(tcpListenSockets_t::iterator i
=g_tcpListenSockets
.begin(); i
!= g_tcpListenSockets
.end(); ++i
)
3248 t_fdm
->removeReadFD(*i
);
3253 if(TCPConnection::getCurrentConnections() <= maxTcpClients
) { // reenable
3254 for(tcpListenSockets_t::iterator i
=g_tcpListenSockets
.begin(); i
!= g_tcpListenSockets
.end(); ++i
)
3255 t_fdm
->addReadFD(*i
, handleNewTCPQuestion
);
3262 catch(PDNSException
&ae
) {
3263 L
<<Logger::Error
<<"Exception: "<<ae
.reason
<<endl
;
3266 catch(std::exception
&e
) {
3267 L
<<Logger::Error
<<"STL Exception: "<<e
.what()<<endl
;
3271 L
<<Logger::Error
<<"any other exception in main: "<<endl
;
3276 int main(int argc
, char **argv
)
3280 g_stats
.startupTime
=time(0);
3281 versionSetProduct(ProductRecursor
);
3285 int ret
= EXIT_SUCCESS
;
3288 ::arg().set("stack-size","stack size per mthread")="200000";
3289 ::arg().set("soa-minimum-ttl","Don't change")="0";
3290 ::arg().set("no-shuffle","Don't change")="off";
3291 ::arg().set("local-port","port to listen on")="53";
3292 ::arg().set("local-address","IP addresses to listen on, separated by spaces or commas. Also accepts ports.")="127.0.0.1";
3293 ::arg().setSwitch("non-local-bind", "Enable binding to non-local addresses by using FREEBIND / BINDANY socket options")="no";
3294 ::arg().set("trace","if we should output heaps of logging. set to 'fail' to only log failing domains")="off";
3295 ::arg().set("dnssec", "DNSSEC mode: off/process-no-validate (default)/process/log-fail/validate")="process-no-validate";
3296 ::arg().set("dnssec-log-bogus", "Log DNSSEC bogus validations")="no";
3297 ::arg().set("daemon","Operate as a daemon")="no";
3298 ::arg().setSwitch("write-pid","Write a PID file")="yes";
3299 ::arg().set("loglevel","Amount of logging. Higher is more. Do not set below 3")="6";
3300 ::arg().set("disable-syslog","Disable logging to syslog, useful when running inside a supervisor that logs stdout")="no";
3301 ::arg().set("log-timestamp","Print timestamps in log lines, useful to disable when running with a tool that timestamps stdout already")="yes";
3302 ::arg().set("log-common-errors","If we should log rather common errors")="no";
3303 ::arg().set("chroot","switch to chroot jail")="";
3304 ::arg().set("setgid","If set, change group id to this gid for more security")="";
3305 ::arg().set("setuid","If set, change user id to this uid for more security")="";
3306 ::arg().set("network-timeout", "Wait this number of milliseconds for network i/o")="1500";
3307 ::arg().set("threads", "Launch this number of threads")="2";
3308 ::arg().set("processes", "Launch this number of processes (EXPERIMENTAL, DO NOT CHANGE)")="1"; // if we un-experimental this, need to fix openssl rand seeding for multiple PIDs!
3309 ::arg().set("config-name","Name of this virtual configuration - will rename the binary image")="";
3310 ::arg().set("api-config-dir", "Directory where REST API stores config and zones") = "";
3311 ::arg().set("api-key", "Static pre-shared authentication key for access to the REST API") = "";
3312 ::arg().set("api-logfile", "Location of the server logfile (used by the REST API)") = "/var/log/pdns.log";
3313 ::arg().set("api-readonly", "Disallow data modification through the REST API when set") = "no";
3314 ::arg().setSwitch("webserver", "Start a webserver (for REST API)") = "no";
3315 ::arg().set("webserver-address", "IP Address of webserver to listen on") = "127.0.0.1";
3316 ::arg().set("webserver-port", "Port of webserver to listen on") = "8082";
3317 ::arg().set("webserver-password", "Password required for accessing the webserver") = "";
3318 ::arg().set("webserver-allow-from","Webserver access is only allowed from these subnets")="127.0.0.1,::1";
3319 ::arg().set("carbon-ourname", "If set, overrides our reported hostname for carbon stats")="";
3320 ::arg().set("carbon-server", "If set, send metrics in carbon (graphite) format to this server IP address")="";
3321 ::arg().set("carbon-interval", "Number of seconds between carbon (graphite) updates")="30";
3322 ::arg().set("statistics-interval", "Number of seconds between printing of recursor statistics, 0 to disable")="1800";
3323 ::arg().set("quiet","Suppress logging of questions and answers")="";
3324 ::arg().set("logging-facility","Facility to log messages as. 0 corresponds to local0")="";
3325 ::arg().set("config-dir","Location of configuration directory (recursor.conf)")=SYSCONFDIR
;
3326 ::arg().set("socket-owner","Owner of socket")="";
3327 ::arg().set("socket-group","Group of socket")="";
3328 ::arg().set("socket-mode", "Permissions for socket")="";
3330 ::arg().set("socket-dir",string("Where the controlsocket will live, ")+LOCALSTATEDIR
+" when unset and not chrooted" )="";
3331 ::arg().set("delegation-only","Which domains we only accept delegations from")="";
3332 ::arg().set("query-local-address","Source IP address for sending queries")="0.0.0.0";
3333 ::arg().set("query-local-address6","Source IPv6 address for sending queries. IF UNSET, IPv6 WILL NOT BE USED FOR OUTGOING QUERIES")="";
3334 ::arg().set("client-tcp-timeout","Timeout in seconds when talking to TCP clients")="2";
3335 ::arg().set("max-mthreads", "Maximum number of simultaneous Mtasker threads")="2048";
3336 ::arg().set("max-tcp-clients","Maximum number of simultaneous TCP clients")="128";
3337 ::arg().set("server-down-max-fails","Maximum number of consecutive timeouts (and unreachables) to mark a server as down ( 0 => disabled )")="64";
3338 ::arg().set("server-down-throttle-time","Number of seconds to throttle all queries to a server after being marked as down")="60";
3339 ::arg().set("hint-file", "If set, load root hints from this file")="";
3340 ::arg().set("max-cache-entries", "If set, maximum number of entries in the main cache")="1000000";
3341 ::arg().set("max-negative-ttl", "maximum number of seconds to keep a negative cached entry in memory")="3600";
3342 ::arg().set("max-cache-ttl", "maximum number of seconds to keep a cached entry in memory")="86400";
3343 ::arg().set("packetcache-ttl", "maximum number of seconds to keep a cached entry in packetcache")="3600";
3344 ::arg().set("max-packetcache-entries", "maximum number of entries to keep in the packetcache")="500000";
3345 ::arg().set("packetcache-servfail-ttl", "maximum number of seconds to keep a cached servfail entry in packetcache")="60";
3346 ::arg().set("server-id", "Returned when queried for 'server.id' TXT or NSID, defaults to hostname")="";
3347 ::arg().set("stats-ringbuffer-entries", "maximum number of packets to store statistics for")="10000";
3348 ::arg().set("version-string", "string reported on version.pdns or version.bind")=fullVersionString();
3349 ::arg().set("allow-from", "If set, only allow these comma separated netmasks to recurse")=LOCAL_NETS
;
3350 ::arg().set("allow-from-file", "If set, load allowed netmasks from this file")="";
3351 ::arg().set("entropy-source", "If set, read entropy from this file")="/dev/urandom";
3352 ::arg().set("dont-query", "If set, do not query these netmasks for DNS data")=DONT_QUERY
;
3353 ::arg().set("max-tcp-per-client", "If set, maximum number of TCP sessions per client (IP address)")="0";
3354 ::arg().set("max-tcp-queries-per-connection", "If set, maximum number of TCP queries in a TCP connection")="0";
3355 ::arg().set("spoof-nearmiss-max", "If non-zero, assume spoofing after this many near misses")="20";
3356 ::arg().set("single-socket", "If set, only use a single socket for outgoing queries")="off";
3357 ::arg().set("auth-zones", "Zones for which we have authoritative data, comma separated domain=file pairs ")="";
3358 ::arg().set("lua-config-file", "More powerful configuration options")="";
3360 ::arg().set("forward-zones", "Zones for which we forward queries, comma separated domain=ip pairs")="";
3361 ::arg().set("forward-zones-recurse", "Zones for which we forward queries with recursion bit, comma separated domain=ip pairs")="";
3362 ::arg().set("forward-zones-file", "File with (+)domain=ip pairs for forwarding")="";
3363 ::arg().set("export-etc-hosts", "If we should serve up contents from /etc/hosts")="off";
3364 ::arg().set("export-etc-hosts-search-suffix", "Also serve up the contents of /etc/hosts with this suffix")="";
3365 ::arg().set("etc-hosts-file", "Path to 'hosts' file")="/etc/hosts";
3366 ::arg().set("serve-rfc1918", "If we should be authoritative for RFC 1918 private IP space")="yes";
3367 ::arg().set("lua-dns-script", "Filename containing an optional 'lua' script that will be used to modify dns answers")="";
3368 ::arg().set("latency-statistic-size","Number of latency values to calculate the qa-latency average")="10000";
3369 ::arg().setSwitch( "disable-packetcache", "Disable packetcache" )= "no";
3370 ::arg().set("ecs-ipv4-bits", "Number of bits of IPv4 address to pass for EDNS Client Subnet")="24";
3371 ::arg().set("ecs-ipv6-bits", "Number of bits of IPv6 address to pass for EDNS Client Subnet")="56";
3372 ::arg().set("edns-subnet-whitelist", "List of netmasks and domains that we should enable EDNS subnet for")="";
3373 ::arg().set("ecs-scope-zero-address", "Address to send to whitelisted authoritative servers for incoming queries with ECS prefix-length source of 0")="";
3374 ::arg().setSwitch( "use-incoming-edns-subnet", "Pass along received EDNS Client Subnet information")="no";
3375 ::arg().setSwitch( "pdns-distributes-queries", "If PowerDNS itself should distribute queries over threads")="yes";
3376 ::arg().setSwitch( "root-nx-trust", "If set, believe that an NXDOMAIN from the root means the TLD does not exist")="yes";
3377 ::arg().setSwitch( "any-to-tcp","Answer ANY queries with tc=1, shunting to TCP" )="no";
3378 ::arg().setSwitch( "lowercase-outgoing","Force outgoing questions to lowercase")="no";
3379 ::arg().setSwitch("gettag-needs-edns-options", "If EDNS Options should be extracted before calling the gettag() hook")="no";
3380 ::arg().set("udp-truncation-threshold", "Maximum UDP response size before we truncate")="1680";
3381 ::arg().set("edns-outgoing-bufsize", "Outgoing EDNS buffer size")="1680";
3382 ::arg().set("minimum-ttl-override", "Set under adverse conditions, a minimum TTL")="0";
3383 ::arg().set("max-qperq", "Maximum outgoing queries per query")="50";
3384 ::arg().set("max-total-msec", "Maximum total wall-clock time per query in milliseconds, 0 for unlimited")="7000";
3385 ::arg().set("max-recursion-depth", "Maximum number of internal recursion calls per query, 0 for unlimited")="40";
3387 ::arg().set("include-dir","Include *.conf files from this directory")="";
3388 ::arg().set("security-poll-suffix","Domain name from which to query security update notifications")="secpoll.powerdns.com.";
3390 ::arg().setSwitch("reuseport","Enable SO_REUSEPORT allowing multiple recursors processes to listen to 1 address")="no";
3392 ::arg().setSwitch("snmp-agent", "If set, register as an SNMP agent")="no";
3393 ::arg().set("snmp-master-socket", "If set and snmp-agent is set, the socket to use to register to the SNMP master")="";
3395 ::arg().set("tcp-fast-open", "Enable TCP Fast Open support on the listening sockets, using the supplied numerical value as the queue size")="0";
3396 ::arg().set("nsec3-max-iterations", "Maximum number of iterations allowed for an NSEC3 record")="2500";
3398 ::arg().set("cpu-map", "Thread to CPU mapping, space separated thread-id=cpu1,cpu2..cpuN pairs")="";
3400 ::arg().setSwitch("log-rpz-changes", "Log additions and removals to RPZ zones at Info level")="no";
3402 ::arg().setCmd("help","Provide a helpful message");
3403 ::arg().setCmd("version","Print version string");
3404 ::arg().setCmd("config","Output blank configuration");
3405 L
.toConsole(Logger::Info
);
3406 ::arg().laxParse(argc
,argv
); // do a lax parse
3408 string configname
=::arg()["config-dir"]+"/recursor.conf";
3409 if(::arg()["config-name"]!="") {
3410 configname
=::arg()["config-dir"]+"/recursor-"+::arg()["config-name"]+".conf";
3411 s_programname
+="-"+::arg()["config-name"];
3413 cleanSlashes(configname
);
3415 if(::arg().mustDo("config")) {
3416 cout
<<::arg().configstring()<<endl
;
3420 if(!::arg().file(configname
.c_str()))
3421 L
<<Logger::Warning
<<"Unable to parse configuration file '"<<configname
<<"'"<<endl
;
3423 ::arg().parse(argc
,argv
);
3425 if( !::arg()["chroot"].empty() && !::arg()["api-config-dir"].empty() && !::arg().mustDo("api-readonly") ) {
3426 L
<<Logger::Error
<<"Using chroot and a writable API is not possible"<<endl
;
3430 if (::arg()["socket-dir"].empty()) {
3431 if (::arg()["chroot"].empty())
3432 ::arg().set("socket-dir") = LOCALSTATEDIR
;
3434 ::arg().set("socket-dir") = "/";
3437 ::arg().set("delegation-only")=toLower(::arg()["delegation-only"]);
3439 if(::arg().asNum("threads")==1)
3440 ::arg().set("pdns-distributes-queries")="no";
3442 if(::arg().mustDo("help")) {
3443 cout
<<"syntax:"<<endl
<<endl
;
3444 cout
<<::arg().helpstring(::arg()["help"])<<endl
;
3447 if(::arg().mustDo("version")) {
3448 showProductVersion();
3449 showBuildConfiguration();
3453 Logger::Urgency logUrgency
= (Logger::Urgency
)::arg().asNum("loglevel");
3455 if (logUrgency
< Logger::Error
)
3456 logUrgency
= Logger::Error
;
3457 if(!g_quiet
&& logUrgency
< Logger::Info
) { // Logger::Info=6, Logger::Debug=7
3458 logUrgency
= Logger::Info
; // if you do --quiet=no, you need Info to also see the query log
3460 L
.setLoglevel(logUrgency
);
3461 L
.toConsole(logUrgency
);
3463 serviceMain(argc
, argv
);
3465 catch(PDNSException
&ae
) {
3466 L
<<Logger::Error
<<"Exception: "<<ae
.reason
<<endl
;
3469 catch(std::exception
&e
) {
3470 L
<<Logger::Error
<<"STL Exception: "<<e
.what()<<endl
;
3474 L
<<Logger::Error
<<"any other exception in main: "<<endl
;