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
);
2161 catch(std::exception
& e
)
2163 L
<<Logger::Error
<<"Exception while performing security poll: "<<e
.what()<<endl
;
2169 catch(PDNSException
& ae
)
2172 L
<<Logger::Error
<<"Fatal error in housekeeping thread: "<<ae
.reason
<<endl
;
2177 static void makeThreadPipes()
2179 for(unsigned int n
=0; n
< g_numThreads
; ++n
) {
2180 struct ThreadPipeSet tps
;
2183 unixDie("Creating pipe for inter-thread communications");
2185 tps
.readToThread
= fd
[0];
2186 tps
.writeToThread
= fd
[1];
2189 unixDie("Creating pipe for inter-thread communications");
2190 tps
.readFromThread
= fd
[0];
2191 tps
.writeFromThread
= fd
[1];
2193 g_pipes
.push_back(tps
);
2203 void broadcastFunction(const pipefunc_t
& func
, bool skipSelf
)
2206 for(ThreadPipeSet
& tps
: g_pipes
)
2210 func(); // don't write to ourselves!
2214 ThreadMSG
* tmsg
= new ThreadMSG();
2216 tmsg
->wantAnswer
= true;
2217 if(write(tps
.writeToThread
, &tmsg
, sizeof(tmsg
)) != sizeof(tmsg
)) {
2219 unixDie("write to thread pipe returned wrong size or error");
2223 if(read(tps
.readFromThread
, &resp
, sizeof(resp
)) != sizeof(resp
))
2224 unixDie("read from thread pipe returned wrong size or error");
2227 // cerr <<"got response: " << *resp << endl;
2233 void distributeAsyncFunction(const string
& packet
, const pipefunc_t
& func
)
2235 unsigned int hash
= hashQuestion(packet
.c_str(), packet
.length(), g_disthashseed
);
2236 unsigned int target
= 1 + (hash
% (g_pipes
.size()-1));
2238 if(target
== t_id
) {
2242 ThreadPipeSet
& tps
= g_pipes
[target
];
2243 ThreadMSG
* tmsg
= new ThreadMSG();
2245 tmsg
->wantAnswer
= false;
2247 if(write(tps
.writeToThread
, &tmsg
, sizeof(tmsg
)) != sizeof(tmsg
)) {
2249 unixDie("write to thread pipe returned wrong size or error");
2253 static void handlePipeRequest(int fd
, FDMultiplexer::funcparam_t
& var
)
2255 ThreadMSG
* tmsg
= nullptr;
2257 if(read(fd
, &tmsg
, sizeof(tmsg
)) != sizeof(tmsg
)) { // fd == readToThread
2258 unixDie("read from thread pipe returned wrong size or error");
2263 resp
= tmsg
->func();
2265 catch(std::exception
& e
) {
2266 if(g_logCommonErrors
)
2267 L
<<Logger::Error
<<"PIPE function we executed created exception: "<<e
.what()<<endl
; // but what if they wanted an answer.. we send 0
2269 catch(PDNSException
& e
) {
2270 if(g_logCommonErrors
)
2271 L
<<Logger::Error
<<"PIPE function we executed created PDNS exception: "<<e
.reason
<<endl
; // but what if they wanted an answer.. we send 0
2273 if(tmsg
->wantAnswer
) {
2274 if(write(g_pipes
[t_id
].writeFromThread
, &resp
, sizeof(resp
)) != sizeof(resp
)) {
2276 unixDie("write to thread pipe returned wrong size or error");
2283 template<class T
> void *voider(const boost::function
<T
*()>& func
)
2288 vector
<ComboAddress
>& operator+=(vector
<ComboAddress
>&a
, const vector
<ComboAddress
>& b
)
2290 a
.insert(a
.end(), b
.begin(), b
.end());
2294 vector
<pair
<string
, uint16_t> >& operator+=(vector
<pair
<string
, uint16_t> >&a
, const vector
<pair
<string
, uint16_t> >& b
)
2296 a
.insert(a
.end(), b
.begin(), b
.end());
2300 vector
<pair
<DNSName
, uint16_t> >& operator+=(vector
<pair
<DNSName
, uint16_t> >&a
, const vector
<pair
<DNSName
, uint16_t> >& b
)
2302 a
.insert(a
.end(), b
.begin(), b
.end());
2307 template<class T
> T
broadcastAccFunction(const boost::function
<T
*()>& func
, bool skipSelf
)
2311 for(ThreadPipeSet
& tps
: g_pipes
)
2315 T
* resp
= (T
*)func(); // don't write to ourselves!
2317 //~ cerr <<"got direct: " << *resp << endl;
2325 ThreadMSG
* tmsg
= new ThreadMSG();
2326 tmsg
->func
= boost::bind(voider
<T
>, func
);
2327 tmsg
->wantAnswer
= true;
2329 if(write(tps
.writeToThread
, &tmsg
, sizeof(tmsg
)) != sizeof(tmsg
)) {
2331 unixDie("write to thread pipe returned wrong size or error");
2335 if(read(tps
.readFromThread
, &resp
, sizeof(resp
)) != sizeof(resp
))
2336 unixDie("read from thread pipe returned wrong size or error");
2339 //~ cerr <<"got response: " << *resp << endl;
2347 template string
broadcastAccFunction(const boost::function
<string
*()>& fun
, bool skipSelf
); // explicit instantiation
2348 template uint64_t broadcastAccFunction(const boost::function
<uint64_t*()>& fun
, bool skipSelf
); // explicit instantiation
2349 template vector
<ComboAddress
> broadcastAccFunction(const boost::function
<vector
<ComboAddress
> *()>& fun
, bool skipSelf
); // explicit instantiation
2350 template vector
<pair
<DNSName
,uint16_t> > broadcastAccFunction(const boost::function
<vector
<pair
<DNSName
, uint16_t> > *()>& fun
, bool skipSelf
); // explicit instantiation
2352 static void handleRCC(int fd
, FDMultiplexer::funcparam_t
& var
)
2355 string msg
=s_rcc
.recv(&remote
);
2356 RecursorControlParser rcp
;
2357 RecursorControlParser::func_t
* command
;
2359 string answer
=rcp
.getAnswer(msg
, &command
);
2361 // If we are inside a chroot, we need to strip
2362 if (!arg()["chroot"].empty()) {
2363 size_t len
= arg()["chroot"].length();
2364 remote
= remote
.substr(len
);
2368 s_rcc
.send(answer
, &remote
);
2371 catch(std::exception
& e
) {
2372 L
<<Logger::Error
<<"Error dealing with control socket request: "<<e
.what()<<endl
;
2374 catch(PDNSException
& ae
) {
2375 L
<<Logger::Error
<<"Error dealing with control socket request: "<<ae
.reason
<<endl
;
2379 static void handleTCPClientReadable(int fd
, FDMultiplexer::funcparam_t
& var
)
2381 PacketID
* pident
=any_cast
<PacketID
>(&var
);
2382 // cerr<<"handleTCPClientReadable called for fd "<<fd<<", pident->inNeeded: "<<pident->inNeeded<<", "<<pident->sock->getHandle()<<endl;
2384 shared_array
<char> buffer(new char[pident
->inNeeded
]);
2386 ssize_t ret
=recv(fd
, buffer
.get(), pident
->inNeeded
,0);
2388 pident
->inMSG
.append(&buffer
[0], &buffer
[ret
]);
2389 pident
->inNeeded
-=(size_t)ret
;
2390 if(!pident
->inNeeded
|| pident
->inIncompleteOkay
) {
2391 // cerr<<"Got entire load of "<<pident->inMSG.size()<<" bytes"<<endl;
2392 PacketID pid
=*pident
;
2393 string msg
=pident
->inMSG
;
2395 t_fdm
->removeReadFD(fd
);
2396 MT
->sendEvent(pid
, &msg
);
2399 // cerr<<"Still have "<<pident->inNeeded<<" left to go"<<endl;
2403 PacketID tmp
=*pident
;
2404 t_fdm
->removeReadFD(fd
); // pident might now be invalid (it isn't, but still)
2406 MT
->sendEvent(tmp
, &empty
); // this conveys error status
2410 static void handleTCPClientWritable(int fd
, FDMultiplexer::funcparam_t
& var
)
2412 PacketID
* pid
=any_cast
<PacketID
>(&var
);
2413 ssize_t ret
=send(fd
, pid
->outMSG
.c_str() + pid
->outPos
, pid
->outMSG
.size() - pid
->outPos
,0);
2415 pid
->outPos
+=(ssize_t
)ret
;
2416 if(pid
->outPos
==pid
->outMSG
.size()) {
2418 t_fdm
->removeWriteFD(fd
);
2419 MT
->sendEvent(tmp
, &tmp
.outMSG
); // send back what we sent to convey everything is ok
2422 else { // error or EOF
2424 t_fdm
->removeWriteFD(fd
);
2426 MT
->sendEvent(tmp
, &sent
); // we convey error status by sending empty string
2430 // resend event to everybody chained onto it
2431 static void doResends(MT_t::waiters_t::iterator
& iter
, PacketID resend
, const string
& content
)
2433 if(iter
->key
.chain
.empty())
2435 // cerr<<"doResends called!\n";
2436 for(PacketID::chain_t::iterator i
=iter
->key
.chain
.begin(); i
!= iter
->key
.chain
.end() ; ++i
) {
2439 // cerr<<"\tResending "<<content.size()<<" bytes for fd="<<resend.fd<<" and id="<<resend.id<<endl;
2441 MT
->sendEvent(resend
, &content
);
2442 g_stats
.chainResends
++;
2446 static void handleUDPServerResponse(int fd
, FDMultiplexer::funcparam_t
& var
)
2448 PacketID pid
=any_cast
<PacketID
>(var
);
2450 char data
[g_outgoingEDNSBufsize
];
2451 ComboAddress fromaddr
;
2452 socklen_t addrlen
=sizeof(fromaddr
);
2454 len
=recvfrom(fd
, data
, sizeof(data
), 0, (sockaddr
*)&fromaddr
, &addrlen
);
2456 if(len
< (ssize_t
) sizeof(dnsheader
)) {
2458 ; // cerr<<"Error on fd "<<fd<<": "<<stringerror()<<"\n";
2460 g_stats
.serverParseError
++;
2461 if(g_logCommonErrors
)
2462 L
<<Logger::Error
<<"Unable to parse packet from remote UDP server "<< fromaddr
.toString() <<
2463 ": packet smaller than DNS header"<<endl
;
2466 t_udpclientsocks
->returnSocket(fd
);
2469 MT_t::waiters_t::iterator iter
=MT
->d_waiters
.find(pid
);
2470 if(iter
!= MT
->d_waiters
.end())
2471 doResends(iter
, pid
, empty
);
2473 MT
->sendEvent(pid
, &empty
); // this denotes error (does lookup again.. at least L1 will be hot)
2478 memcpy(&dh
, data
, sizeof(dh
));
2481 pident
.remote
=fromaddr
;
2485 if(!dh
.qr
&& g_logCommonErrors
) {
2486 L
<<Logger::Notice
<<"Not taking data from question on outgoing socket from "<< fromaddr
.toStringWithPort() <<endl
;
2489 if(!dh
.qdcount
|| // UPC, Nominum, very old BIND on FormErr, NSD
2490 !dh
.qr
) { // one weird server
2491 pident
.domain
.clear();
2497 pident
.domain
=DNSName(data
, len
, 12, false, &pident
.type
); // don't copy this from above - we need to do the actual read
2499 catch(std::exception
& e
) {
2500 g_stats
.serverParseError
++; // won't be fed to lwres.cc, so we have to increment
2501 L
<<Logger::Warning
<<"Error in packet from remote nameserver "<< fromaddr
.toStringWithPort() << ": "<<e
.what() << endl
;
2506 packet
.assign(data
, len
);
2508 MT_t::waiters_t::iterator iter
=MT
->d_waiters
.find(pident
);
2509 if(iter
!= MT
->d_waiters
.end()) {
2510 doResends(iter
, pident
, packet
);
2515 if(!MT
->sendEvent(pident
, &packet
)) {
2516 // 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
2517 for(MT_t::waiters_t::iterator mthread
=MT
->d_waiters
.begin(); mthread
!=MT
->d_waiters
.end(); ++mthread
) {
2518 if(pident
.fd
==mthread
->key
.fd
&& mthread
->key
.remote
==pident
.remote
&& mthread
->key
.type
== pident
.type
&&
2519 pident
.domain
== mthread
->key
.domain
) {
2520 mthread
->key
.nearMisses
++;
2523 // be a bit paranoid here since we're weakening our matching
2524 if(pident
.domain
.empty() && !mthread
->key
.domain
.empty() && !pident
.type
&& mthread
->key
.type
&&
2525 pident
.id
== mthread
->key
.id
&& mthread
->key
.remote
== pident
.remote
) {
2526 // cerr<<"Empty response, rest matches though, sending to a waiter"<<endl;
2527 pident
.domain
= mthread
->key
.domain
;
2528 pident
.type
= mthread
->key
.type
;
2529 goto retryWithName
; // note that this only passes on an error, lwres will still reject the packet
2532 g_stats
.unexpectedCount
++; // if we made it here, it really is an unexpected answer
2533 if(g_logCommonErrors
) {
2534 L
<<Logger::Warning
<<"Discarding unexpected packet from "<<fromaddr
.toStringWithPort()<<": "<< (pident
.domain
.empty() ? "<empty>" : pident
.domain
.toString())<<", "<<pident
.type
<<", "<<MT
->d_waiters
.size()<<" waiters"<<endl
;
2538 t_udpclientsocks
->returnSocket(fd
);
2542 FDMultiplexer
* getMultiplexer()
2545 for(const auto& i
: FDMultiplexer::getMultiplexerMap()) {
2550 catch(FDMultiplexerException
&fe
) {
2551 L
<<Logger::Error
<<"Non-fatal error initializing possible multiplexer ("<<fe
.what()<<"), falling back"<<endl
;
2554 L
<<Logger::Error
<<"Non-fatal error initializing possible multiplexer"<<endl
;
2557 L
<<Logger::Error
<<"No working multiplexer found!"<<endl
;
2562 static string
* doReloadLuaScript()
2564 string fname
= ::arg()["lua-dns-script"];
2568 L
<<Logger::Error
<<t_id
<<" Unloaded current lua script"<<endl
;
2569 return new string("unloaded\n");
2572 t_pdl
= std::make_shared
<RecursorLua4
>(fname
);
2575 catch(std::exception
& e
) {
2576 L
<<Logger::Error
<<t_id
<<" Retaining current script, error from '"<<fname
<<"': "<< e
.what() <<endl
;
2577 return new string("retaining current script, error from '"+fname
+"': "+e
.what()+"\n");
2580 L
<<Logger::Warning
<<t_id
<<" (Re)loaded lua script from '"<<fname
<<"'"<<endl
;
2581 return new string("(re)loaded '"+fname
+"'\n");
2584 string
doQueueReloadLuaScript(vector
<string
>::const_iterator begin
, vector
<string
>::const_iterator end
)
2587 ::arg().set("lua-dns-script") = *begin
;
2589 return broadcastAccFunction
<string
>(doReloadLuaScript
);
2592 static string
* pleaseUseNewTraceRegex(const std::string
& newRegex
)
2595 if(newRegex
.empty()) {
2596 t_traceRegex
.reset();
2597 return new string("unset\n");
2600 t_traceRegex
= std::make_shared
<Regex
>(newRegex
);
2601 return new string("ok\n");
2604 catch(PDNSException
& ae
)
2606 return new string(ae
.reason
+"\n");
2609 string
doTraceRegex(vector
<string
>::const_iterator begin
, vector
<string
>::const_iterator end
)
2611 return broadcastAccFunction
<string
>(boost::bind(pleaseUseNewTraceRegex
, begin
!=end
? *begin
: ""));
2614 static void checkLinuxIPv6Limits()
2618 if(readFileIfThere("/proc/sys/net/ipv6/route/max_size", &line
)) {
2619 int lim
=std::stoi(line
);
2621 L
<<Logger::Error
<<"If using IPv6, please raise sysctl net.ipv6.route.max_size, currently set to "<<lim
<<" which is < 16384"<<endl
;
2626 static void checkOrFixFDS()
2628 unsigned int availFDs
=getFilenumLimit();
2629 unsigned int wantFDs
= g_maxMThreads
* g_numWorkerThreads
+25; // even healthier margin then before
2631 if(wantFDs
> availFDs
) {
2632 unsigned int hardlimit
= getFilenumLimit(true);
2633 if(hardlimit
>= wantFDs
) {
2634 setFilenumLimit(wantFDs
);
2635 L
<<Logger::Warning
<<"Raised soft limit on number of filedescriptors to "<<wantFDs
<<" to match max-mthreads and threads settings"<<endl
;
2638 int newval
= (hardlimit
- 25) / g_numWorkerThreads
;
2639 L
<<Logger::Warning
<<"Insufficient number of filedescriptors available for max-mthreads*threads setting! ("<<hardlimit
<<" < "<<wantFDs
<<"), reducing max-mthreads to "<<newval
<<endl
;
2640 g_maxMThreads
= newval
;
2641 setFilenumLimit(hardlimit
);
2646 static void* recursorThread(void*);
2648 static void* pleaseSupplantACLs(std::shared_ptr
<NetmaskGroup
> ng
)
2659 static bool l_initialized
;
2661 if(l_initialized
) { // only reload configuration file on second call
2662 string configname
=::arg()["config-dir"]+"/recursor.conf";
2663 cleanSlashes(configname
);
2665 if(!::arg().preParseFile(configname
.c_str(), "allow-from-file"))
2666 throw runtime_error("Unable to re-parse configuration file '"+configname
+"'");
2667 ::arg().preParseFile(configname
.c_str(), "allow-from", LOCAL_NETS
);
2668 ::arg().preParseFile(configname
.c_str(), "include-dir");
2669 ::arg().preParse(g_argc
, g_argv
, "include-dir");
2671 // then process includes
2672 std::vector
<std::string
> extraConfigs
;
2673 ::arg().gatherIncludes(extraConfigs
);
2675 for(const std::string
& fn
: extraConfigs
) {
2676 if(!::arg().preParseFile(fn
.c_str(), "allow-from-file", ::arg()["allow-from-file"]))
2677 throw runtime_error("Unable to re-parse configuration file include '"+fn
+"'");
2678 if(!::arg().preParseFile(fn
.c_str(), "allow-from", ::arg()["allow-from"]))
2679 throw runtime_error("Unable to re-parse configuration file include '"+fn
+"'");
2682 ::arg().preParse(g_argc
, g_argv
, "allow-from-file");
2683 ::arg().preParse(g_argc
, g_argv
, "allow-from");
2686 std::shared_ptr
<NetmaskGroup
> oldAllowFrom
= t_allowFrom
;
2687 std::shared_ptr
<NetmaskGroup
> allowFrom
= std::make_shared
<NetmaskGroup
>();
2689 if(!::arg()["allow-from-file"].empty()) {
2691 ifstream
ifs(::arg()["allow-from-file"].c_str());
2693 throw runtime_error("Could not open '"+::arg()["allow-from-file"]+"': "+stringerror());
2696 string::size_type pos
;
2697 while(getline(ifs
,line
)) {
2699 if(pos
!=string::npos
)
2705 allowFrom
->addMask(line
);
2707 L
<<Logger::Warning
<<"Done parsing " << allowFrom
->size() <<" allow-from ranges from file '"<<::arg()["allow-from-file"]<<"' - overriding 'allow-from' setting"<<endl
;
2709 else if(!::arg()["allow-from"].empty()) {
2711 stringtok(ips
, ::arg()["allow-from"], ", ");
2713 L
<<Logger::Warning
<<"Only allowing queries from: ";
2714 for(vector
<string
>::const_iterator i
= ips
.begin(); i
!= ips
.end(); ++i
) {
2715 allowFrom
->addMask(*i
);
2717 L
<<Logger::Warning
<<", ";
2718 L
<<Logger::Warning
<<*i
;
2720 L
<<Logger::Warning
<<endl
;
2723 if(::arg()["local-address"]!="127.0.0.1" && ::arg().asNum("local-port")==53)
2724 L
<<Logger::Error
<<"WARNING: Allowing queries from all IP addresses - this can be a security risk!"<<endl
;
2725 allowFrom
= nullptr;
2728 g_initialAllowFrom
= allowFrom
;
2729 broadcastFunction(boost::bind(pleaseSupplantACLs
, allowFrom
));
2730 oldAllowFrom
= nullptr;
2732 l_initialized
= true;
2736 static void setupDelegationOnly()
2738 vector
<string
> parts
;
2739 stringtok(parts
, ::arg()["delegation-only"], ", \t");
2740 for(const auto& p
: parts
) {
2741 SyncRes::addDelegationOnly(DNSName(p
));
2745 static std::map
<unsigned int, std::set
<int> > parseCPUMap()
2747 std::map
<unsigned int, std::set
<int> > result
;
2749 const std::string value
= ::arg()["cpu-map"];
2751 if (!value
.empty() && !isSettingThreadCPUAffinitySupported()) {
2752 L
<<Logger::Warning
<<"CPU mapping requested but not supported, skipping"<<endl
;
2756 std::vector
<std::string
> parts
;
2758 stringtok(parts
, value
, " \t");
2760 for(const auto& part
: parts
) {
2761 if (part
.find('=') == string::npos
)
2765 auto headers
= splitField(part
, '=');
2766 trim(headers
.first
);
2767 trim(headers
.second
);
2769 unsigned int threadId
= pdns_stou(headers
.first
);
2770 std::vector
<std::string
> cpus
;
2772 stringtok(cpus
, headers
.second
, ",");
2774 for(const auto& cpu
: cpus
) {
2775 int cpuId
= std::stoi(cpu
);
2777 result
[threadId
].insert(cpuId
);
2780 catch(const std::exception
& e
) {
2781 L
<<Logger::Error
<<"Error parsing cpu-map entry '"<<part
<<"': "<<e
.what()<<endl
;
2788 static void setCPUMap(const std::map
<unsigned int, std::set
<int> >& cpusMap
, unsigned int n
, pthread_t tid
)
2790 const auto& cpuMapping
= cpusMap
.find(n
);
2791 if (cpuMapping
!= cpusMap
.cend()) {
2792 int rc
= mapThreadToCPUList(tid
, cpuMapping
->second
);
2794 L
<<Logger::Info
<<"CPU affinity for worker "<<n
<<" has been set to CPU map:";
2795 for (const auto cpu
: cpuMapping
->second
) {
2796 L
<<Logger::Info
<<" "<<cpu
;
2798 L
<<Logger::Info
<<endl
;
2801 L
<<Logger::Warning
<<"Error setting CPU affinity for worker "<<n
<<" to CPU map:";
2802 for (const auto cpu
: cpuMapping
->second
) {
2803 L
<<Logger::Info
<<" "<<cpu
;
2805 L
<<Logger::Info
<<strerror(rc
)<<endl
;
2810 static int serviceMain(int argc
, char*argv
[])
2812 L
.setName(s_programname
);
2813 L
.disableSyslog(::arg().mustDo("disable-syslog"));
2814 L
.setTimestamps(::arg().mustDo("log-timestamp"));
2816 if(!::arg()["logging-facility"].empty()) {
2817 int val
=logFacilityToLOG(::arg().asNum("logging-facility") );
2819 theL().setFacility(val
);
2821 L
<<Logger::Error
<<"Unknown logging facility "<<::arg().asNum("logging-facility") <<endl
;
2824 showProductVersion();
2825 seedRandom(::arg()["entropy-source"]);
2827 g_disthashseed
=dns_random(0xffffffff);
2829 checkLinuxIPv6Limits();
2831 vector
<string
> addrs
;
2832 if(!::arg()["query-local-address6"].empty()) {
2833 SyncRes::s_doIPv6
=true;
2834 L
<<Logger::Warning
<<"Enabling IPv6 transport for outgoing queries"<<endl
;
2836 stringtok(addrs
, ::arg()["query-local-address6"], ", ;");
2837 for(const string
& addr
: addrs
) {
2838 g_localQueryAddresses6
.push_back(ComboAddress(addr
));
2842 L
<<Logger::Warning
<<"NOT using IPv6 for outgoing queries - set 'query-local-address6=::' to enable"<<endl
;
2845 stringtok(addrs
, ::arg()["query-local-address"], ", ;");
2846 for(const string
& addr
: addrs
) {
2847 g_localQueryAddresses4
.push_back(ComboAddress(addr
));
2850 catch(std::exception
& e
) {
2851 L
<<Logger::Error
<<"Assigning local query addresses: "<<e
.what();
2855 // keep this ABOVE loadRecursorLuaConfig!
2856 if(::arg()["dnssec"]=="off")
2857 g_dnssecmode
=DNSSECMode::Off
;
2858 else if(::arg()["dnssec"]=="process-no-validate")
2859 g_dnssecmode
=DNSSECMode::ProcessNoValidate
;
2860 else if(::arg()["dnssec"]=="process")
2861 g_dnssecmode
=DNSSECMode::Process
;
2862 else if(::arg()["dnssec"]=="validate")
2863 g_dnssecmode
=DNSSECMode::ValidateAll
;
2864 else if(::arg()["dnssec"]=="log-fail")
2865 g_dnssecmode
=DNSSECMode::ValidateForLog
;
2867 L
<<Logger::Error
<<"Unknown DNSSEC mode "<<::arg()["dnssec"]<<endl
;
2871 g_dnssecLogBogus
= ::arg().mustDo("dnssec-log-bogus");
2872 g_maxNSEC3Iterations
= ::arg().asNum("nsec3-max-iterations");
2874 g_maxCacheEntries
= ::arg().asNum("max-cache-entries");
2875 g_maxPacketCacheEntries
= ::arg().asNum("max-packetcache-entries");
2878 loadRecursorLuaConfig(::arg()["lua-config-file"], ::arg().mustDo("daemon"));
2880 catch (PDNSException
&e
) {
2881 L
<<Logger::Error
<<"Cannot load Lua configuration: "<<e
.reason
<<endl
;
2886 sortPublicSuffixList();
2888 if(!::arg()["dont-query"].empty()) {
2890 stringtok(ips
, ::arg()["dont-query"], ", ");
2891 ips
.push_back("0.0.0.0");
2892 ips
.push_back("::");
2894 L
<<Logger::Warning
<<"Will not send queries to: ";
2895 for(vector
<string
>::const_iterator i
= ips
.begin(); i
!= ips
.end(); ++i
) {
2896 SyncRes::addDontQuery(*i
);
2898 L
<<Logger::Warning
<<", ";
2899 L
<<Logger::Warning
<<*i
;
2901 L
<<Logger::Warning
<<endl
;
2904 g_quiet
=::arg().mustDo("quiet");
2906 g_weDistributeQueries
= ::arg().mustDo("pdns-distributes-queries");
2907 if(g_weDistributeQueries
) {
2908 L
<<Logger::Warning
<<"PowerDNS Recursor itself will distribute queries over threads"<<endl
;
2911 setupDelegationOnly();
2912 g_outgoingEDNSBufsize
=::arg().asNum("edns-outgoing-bufsize");
2914 if(::arg()["trace"]=="fail") {
2915 SyncRes::setDefaultLogMode(SyncRes::Store
);
2917 else if(::arg().mustDo("trace")) {
2918 SyncRes::setDefaultLogMode(SyncRes::Log
);
2919 ::arg().set("quiet")="no";
2924 SyncRes::s_minimumTTL
= ::arg().asNum("minimum-ttl-override");
2926 SyncRes::s_nopacketcache
= ::arg().mustDo("disable-packetcache");
2928 SyncRes::s_maxnegttl
=::arg().asNum("max-negative-ttl");
2929 SyncRes::s_maxcachettl
=max(::arg().asNum("max-cache-ttl"), 15);
2930 SyncRes::s_packetcachettl
=::arg().asNum("packetcache-ttl");
2931 // Cap the packetcache-servfail-ttl to the packetcache-ttl
2932 uint32_t packetCacheServFailTTL
= ::arg().asNum("packetcache-servfail-ttl");
2933 SyncRes::s_packetcacheservfailttl
=(packetCacheServFailTTL
> SyncRes::s_packetcachettl
) ? SyncRes::s_packetcachettl
: packetCacheServFailTTL
;
2934 SyncRes::s_serverdownmaxfails
=::arg().asNum("server-down-max-fails");
2935 SyncRes::s_serverdownthrottletime
=::arg().asNum("server-down-throttle-time");
2936 SyncRes::s_serverID
=::arg()["server-id"];
2937 SyncRes::s_maxqperq
=::arg().asNum("max-qperq");
2938 SyncRes::s_maxtotusec
=1000*::arg().asNum("max-total-msec");
2939 SyncRes::s_maxdepth
=::arg().asNum("max-recursion-depth");
2940 SyncRes::s_rootNXTrust
= ::arg().mustDo( "root-nx-trust");
2941 if(SyncRes::s_serverID
.empty()) {
2943 gethostname(tmp
, sizeof(tmp
)-1);
2944 SyncRes::s_serverID
=tmp
;
2947 SyncRes::s_ecsipv4limit
= ::arg().asNum("ecs-ipv4-bits");
2948 SyncRes::s_ecsipv6limit
= ::arg().asNum("ecs-ipv6-bits");
2950 if (!::arg().isEmpty("ecs-scope-zero-address")) {
2951 ComboAddress
scopeZero(::arg()["ecs-scope-zero-address"]);
2952 SyncRes::setECSScopeZeroAddress(Netmask(scopeZero
, scopeZero
.isIPv4() ? 32 : 128));
2956 for (const auto& addr
: g_localQueryAddresses4
) {
2957 if (!IsAnyAddress(addr
)) {
2958 SyncRes::setECSScopeZeroAddress(Netmask(addr
, 32));
2964 for (const auto& addr
: g_localQueryAddresses6
) {
2965 if (!IsAnyAddress(addr
)) {
2966 SyncRes::setECSScopeZeroAddress(Netmask(addr
, 128));
2972 SyncRes::setECSScopeZeroAddress(Netmask("127.0.0.1/32"));
2977 g_networkTimeoutMsec
= ::arg().asNum("network-timeout");
2979 g_initialDomainMap
= parseAuthAndForwards();
2981 g_latencyStatSize
=::arg().asNum("latency-statistic-size");
2983 g_logCommonErrors
=::arg().mustDo("log-common-errors");
2984 g_logRPZChanges
= ::arg().mustDo("log-rpz-changes");
2986 g_anyToTcp
= ::arg().mustDo("any-to-tcp");
2987 g_udpTruncationThreshold
= ::arg().asNum("udp-truncation-threshold");
2989 g_lowercaseOutgoing
= ::arg().mustDo("lowercase-outgoing");
2991 g_numWorkerThreads
= ::arg().asNum("threads");
2992 g_numThreads
= g_numWorkerThreads
+ g_weDistributeQueries
;
2993 g_maxMThreads
= ::arg().asNum("max-mthreads");
2995 g_gettagNeedsEDNSOptions
= ::arg().mustDo("gettag-needs-edns-options");
2997 g_statisticsInterval
= ::arg().asNum("statistics-interval");
3000 g_reusePort
= ::arg().mustDo("reuseport");
3003 g_useOneSocketPerThread
= (!g_weDistributeQueries
&& g_reusePort
);
3005 if (g_useOneSocketPerThread
) {
3006 for (unsigned int threadId
= 0; threadId
< g_numWorkerThreads
; threadId
++) {
3007 makeUDPServerSockets(threadId
);
3008 makeTCPServerSockets(threadId
);
3012 makeUDPServerSockets(0);
3013 makeTCPServerSockets(0);
3016 SyncRes::parseEDNSSubnetWhitelist(::arg()["edns-subnet-whitelist"]);
3017 g_useIncomingECS
= ::arg().mustDo("use-incoming-edns-subnet");
3020 for(forks
= 0; forks
< ::arg().asNum("processes") - 1; ++forks
) {
3021 if(!fork()) // we are child
3025 if(::arg().mustDo("daemon")) {
3026 L
<<Logger::Warning
<<"Calling daemonize, going to background"<<endl
;
3027 L
.toConsole(Logger::Critical
);
3029 loadRecursorLuaConfig(::arg()["lua-config-file"], false);
3031 signal(SIGUSR1
,usr1Handler
);
3032 signal(SIGUSR2
,usr2Handler
);
3033 signal(SIGPIPE
,SIG_IGN
);
3037 #ifdef HAVE_LIBSODIUM
3038 if (sodium_init() == -1) {
3039 L
<<Logger::Error
<<"Unable to initialize sodium crypto library"<<endl
;
3044 openssl_thread_setup();
3048 if(!::arg()["setgid"].empty())
3049 newgid
=Utility::makeGidNumeric(::arg()["setgid"]);
3051 if(!::arg()["setuid"].empty())
3052 newuid
=Utility::makeUidNumeric(::arg()["setuid"]);
3054 Utility::dropGroupPrivs(newuid
, newgid
);
3056 if (!::arg()["chroot"].empty()) {
3059 ns
= getenv("NOTIFY_SOCKET");
3060 if (ns
!= nullptr) {
3061 L
<<Logger::Error
<<"Unable to chroot when running from systemd. Please disable chroot= or set the 'Type' for this service to 'simple'"<<endl
;
3065 if (chroot(::arg()["chroot"].c_str())<0 || chdir("/") < 0) {
3066 L
<<Logger::Error
<<"Unable to chroot to '"+::arg()["chroot"]+"': "<<strerror (errno
)<<", exiting"<<endl
;
3070 L
<<Logger::Error
<<"Chrooted to '"<<::arg()["chroot"]<<"'"<<endl
;
3073 s_pidfname
=::arg()["socket-dir"]+"/"+s_programname
+".pid";
3074 if(!s_pidfname
.empty())
3075 unlink(s_pidfname
.c_str()); // remove possible old pid file
3078 makeControlChannelSocket( ::arg().asNum("processes") > 1 ? forks
: -1);
3080 Utility::dropUserPrivs(newuid
);
3084 g_tcpTimeout
=::arg().asNum("client-tcp-timeout");
3085 g_maxTCPPerClient
=::arg().asNum("max-tcp-per-client");
3086 g_tcpMaxQueriesPerConn
=::arg().asNum("max-tcp-queries-per-connection");
3088 if (::arg().mustDo("snmp-agent")) {
3089 g_snmpAgent
= std::make_shared
<RecursorSNMPAgent
>("recursor", ::arg()["snmp-master-socket"]);
3093 const auto cpusMap
= parseCPUMap();
3094 if(g_numThreads
== 1) {
3095 L
<<Logger::Warning
<<"Operating unthreaded"<<endl
;
3097 sd_notify(0, "READY=1");
3099 setCPUMap(cpusMap
, 0, pthread_self());
3104 L
<<Logger::Warning
<<"Launching "<< g_numThreads
<<" threads"<<endl
;
3105 for(unsigned int n
=0; n
< g_numThreads
; ++n
) {
3106 pthread_create(&tid
, 0, recursorThread
, (void*)(long)n
);
3108 setCPUMap(cpusMap
, n
, tid
);
3112 sd_notify(0, "READY=1");
3114 pthread_join(tid
, &res
);
3119 static void* recursorThread(void* ptr
)
3122 t_id
=(int) (long) ptr
;
3123 SyncRes
tmp(g_now
); // make sure it allocates tsstorage before we do anything, like primeHints or so..
3124 SyncRes::setDomainMap(g_initialDomainMap
);
3125 t_allowFrom
= g_initialAllowFrom
;
3126 t_udpclientsocks
= std::unique_ptr
<UDPClientSocks
>(new UDPClientSocks());
3127 t_tcpClientCounts
= std::unique_ptr
<tcpClientCounts_t
>(new tcpClientCounts_t());
3130 t_packetCache
= std::unique_ptr
<RecursorPacketCache
>(new RecursorPacketCache());
3132 #ifdef HAVE_PROTOBUF
3133 t_uuidGenerator
= std::unique_ptr
<boost::uuids::random_generator
>(new boost::uuids::random_generator());
3135 L
<<Logger::Warning
<<"Done priming cache with root hints"<<endl
;
3138 if(!::arg()["lua-dns-script"].empty()) {
3139 t_pdl
= std::make_shared
<RecursorLua4
>(::arg()["lua-dns-script"]);
3140 L
<<Logger::Warning
<<"Loaded 'lua' script from '"<<::arg()["lua-dns-script"]<<"'"<<endl
;
3143 catch(std::exception
&e
) {
3144 L
<<Logger::Error
<<"Failed to load 'lua' script from '"<<::arg()["lua-dns-script"]<<"': "<<e
.what()<<endl
;
3148 unsigned int ringsize
=::arg().asNum("stats-ringbuffer-entries") / g_numWorkerThreads
;
3150 t_remotes
= std::unique_ptr
<addrringbuf_t
>(new addrringbuf_t());
3151 if(g_weDistributeQueries
) // if so, only 1 thread does recvfrom
3152 t_remotes
->set_capacity(::arg().asNum("stats-ringbuffer-entries"));
3154 t_remotes
->set_capacity(ringsize
);
3155 t_servfailremotes
= std::unique_ptr
<addrringbuf_t
>(new addrringbuf_t());
3156 t_servfailremotes
->set_capacity(ringsize
);
3157 t_largeanswerremotes
= std::unique_ptr
<addrringbuf_t
>(new addrringbuf_t());
3158 t_largeanswerremotes
->set_capacity(ringsize
);
3160 t_queryring
= std::unique_ptr
<boost::circular_buffer
<pair
<DNSName
, uint16_t> > >(new boost::circular_buffer
<pair
<DNSName
, uint16_t> >());
3161 t_queryring
->set_capacity(ringsize
);
3162 t_servfailqueryring
= std::unique_ptr
<boost::circular_buffer
<pair
<DNSName
, uint16_t> > >(new boost::circular_buffer
<pair
<DNSName
, uint16_t> >());
3163 t_servfailqueryring
->set_capacity(ringsize
);
3166 MT
=std::unique_ptr
<MTasker
<PacketID
,string
> >(new MTasker
<PacketID
,string
>(::arg().asNum("stack-size")));
3170 t_fdm
=getMultiplexer();
3172 if(::arg().mustDo("webserver")) {
3173 L
<<Logger::Warning
<< "Enabling web server" << endl
;
3175 new RecursorWebServer(t_fdm
);
3177 catch(PDNSException
&e
) {
3178 L
<<Logger::Error
<<"Exception: "<<e
.reason
<<endl
;
3182 L
<<Logger::Error
<<"Enabled '"<< t_fdm
->getName() << "' multiplexer"<<endl
;
3185 t_fdm
->addReadFD(g_pipes
[t_id
].readToThread
, handlePipeRequest
);
3187 if(g_useOneSocketPerThread
) {
3188 for(deferredAdd_t::const_iterator i
= deferredAdds
[t_id
].cbegin(); i
!= deferredAdds
[t_id
].cend(); ++i
) {
3189 t_fdm
->addReadFD(i
->first
, i
->second
);
3193 if(!g_weDistributeQueries
|| !t_id
) { // if we distribute queries, only t_id = 0 listens
3194 for(deferredAdd_t::const_iterator i
= deferredAdds
[0].cbegin(); i
!= deferredAdds
[0].cend(); ++i
) {
3195 t_fdm
->addReadFD(i
->first
, i
->second
);
3202 t_fdm
->addReadFD(s_rcc
.d_fd
, handleRCC
); // control channel
3205 unsigned int maxTcpClients
=::arg().asNum("max-tcp-clients");
3207 bool listenOnTCP(true);
3209 time_t last_carbon
=0;
3210 time_t carbonInterval
=::arg().asNum("carbon-interval");
3211 counter
.store(0); // used to periodically execute certain tasks
3213 while(MT
->schedule(&g_now
)); // MTasker letting the mthreads do their thing
3215 if(!(counter
%500)) {
3216 MT
->makeThread(houseKeeping
, 0);
3220 typedef vector
<pair
<int, FDMultiplexer::funcparam_t
> > expired_t
;
3221 expired_t expired
=t_fdm
->getTimeouts(g_now
);
3223 for(expired_t::iterator i
=expired
.begin() ; i
!= expired
.end(); ++i
) {
3224 shared_ptr
<TCPConnection
> conn
=any_cast
<shared_ptr
<TCPConnection
> >(i
->second
);
3225 if(g_logCommonErrors
)
3226 L
<<Logger::Warning
<<"Timeout from remote TCP client "<< conn
->d_remote
.toString() <<endl
;
3227 t_fdm
->removeReadFD(i
->first
);
3233 if(!t_id
&& statsWanted
) {
3237 Utility::gettimeofday(&g_now
, 0);
3239 if(!t_id
&& (g_now
.tv_sec
- last_carbon
>= carbonInterval
)) {
3240 MT
->makeThread(doCarbonDump
, 0);
3241 last_carbon
= g_now
.tv_sec
;
3245 // 'run' updates g_now for us
3247 if(!g_weDistributeQueries
|| !t_id
) { // if pdns distributes queries, only tid 0 should do this
3249 if(TCPConnection::getCurrentConnections() > maxTcpClients
) { // shutdown, too many connections
3250 for(tcpListenSockets_t::iterator i
=g_tcpListenSockets
.begin(); i
!= g_tcpListenSockets
.end(); ++i
)
3251 t_fdm
->removeReadFD(*i
);
3256 if(TCPConnection::getCurrentConnections() <= maxTcpClients
) { // reenable
3257 for(tcpListenSockets_t::iterator i
=g_tcpListenSockets
.begin(); i
!= g_tcpListenSockets
.end(); ++i
)
3258 t_fdm
->addReadFD(*i
, handleNewTCPQuestion
);
3265 catch(PDNSException
&ae
) {
3266 L
<<Logger::Error
<<"Exception: "<<ae
.reason
<<endl
;
3269 catch(std::exception
&e
) {
3270 L
<<Logger::Error
<<"STL Exception: "<<e
.what()<<endl
;
3274 L
<<Logger::Error
<<"any other exception in main: "<<endl
;
3279 int main(int argc
, char **argv
)
3283 g_stats
.startupTime
=time(0);
3284 versionSetProduct(ProductRecursor
);
3288 int ret
= EXIT_SUCCESS
;
3291 ::arg().set("stack-size","stack size per mthread")="200000";
3292 ::arg().set("soa-minimum-ttl","Don't change")="0";
3293 ::arg().set("no-shuffle","Don't change")="off";
3294 ::arg().set("local-port","port to listen on")="53";
3295 ::arg().set("local-address","IP addresses to listen on, separated by spaces or commas. Also accepts ports.")="127.0.0.1";
3296 ::arg().setSwitch("non-local-bind", "Enable binding to non-local addresses by using FREEBIND / BINDANY socket options")="no";
3297 ::arg().set("trace","if we should output heaps of logging. set to 'fail' to only log failing domains")="off";
3298 ::arg().set("dnssec", "DNSSEC mode: off/process-no-validate (default)/process/log-fail/validate")="process-no-validate";
3299 ::arg().set("dnssec-log-bogus", "Log DNSSEC bogus validations")="no";
3300 ::arg().set("daemon","Operate as a daemon")="no";
3301 ::arg().setSwitch("write-pid","Write a PID file")="yes";
3302 ::arg().set("loglevel","Amount of logging. Higher is more. Do not set below 3")="6";
3303 ::arg().set("disable-syslog","Disable logging to syslog, useful when running inside a supervisor that logs stdout")="no";
3304 ::arg().set("log-timestamp","Print timestamps in log lines, useful to disable when running with a tool that timestamps stdout already")="yes";
3305 ::arg().set("log-common-errors","If we should log rather common errors")="no";
3306 ::arg().set("chroot","switch to chroot jail")="";
3307 ::arg().set("setgid","If set, change group id to this gid for more security")="";
3308 ::arg().set("setuid","If set, change user id to this uid for more security")="";
3309 ::arg().set("network-timeout", "Wait this number of milliseconds for network i/o")="1500";
3310 ::arg().set("threads", "Launch this number of threads")="2";
3311 ::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!
3312 ::arg().set("config-name","Name of this virtual configuration - will rename the binary image")="";
3313 ::arg().set("api-config-dir", "Directory where REST API stores config and zones") = "";
3314 ::arg().set("api-key", "Static pre-shared authentication key for access to the REST API") = "";
3315 ::arg().set("api-logfile", "Location of the server logfile (used by the REST API)") = "/var/log/pdns.log";
3316 ::arg().set("api-readonly", "Disallow data modification through the REST API when set") = "no";
3317 ::arg().setSwitch("webserver", "Start a webserver (for REST API)") = "no";
3318 ::arg().set("webserver-address", "IP Address of webserver to listen on") = "127.0.0.1";
3319 ::arg().set("webserver-port", "Port of webserver to listen on") = "8082";
3320 ::arg().set("webserver-password", "Password required for accessing the webserver") = "";
3321 ::arg().set("webserver-allow-from","Webserver access is only allowed from these subnets")="127.0.0.1,::1";
3322 ::arg().set("carbon-ourname", "If set, overrides our reported hostname for carbon stats")="";
3323 ::arg().set("carbon-server", "If set, send metrics in carbon (graphite) format to this server IP address")="";
3324 ::arg().set("carbon-interval", "Number of seconds between carbon (graphite) updates")="30";
3325 ::arg().set("statistics-interval", "Number of seconds between printing of recursor statistics, 0 to disable")="1800";
3326 ::arg().set("quiet","Suppress logging of questions and answers")="";
3327 ::arg().set("logging-facility","Facility to log messages as. 0 corresponds to local0")="";
3328 ::arg().set("config-dir","Location of configuration directory (recursor.conf)")=SYSCONFDIR
;
3329 ::arg().set("socket-owner","Owner of socket")="";
3330 ::arg().set("socket-group","Group of socket")="";
3331 ::arg().set("socket-mode", "Permissions for socket")="";
3333 ::arg().set("socket-dir",string("Where the controlsocket will live, ")+LOCALSTATEDIR
+" when unset and not chrooted" )="";
3334 ::arg().set("delegation-only","Which domains we only accept delegations from")="";
3335 ::arg().set("query-local-address","Source IP address for sending queries")="0.0.0.0";
3336 ::arg().set("query-local-address6","Source IPv6 address for sending queries. IF UNSET, IPv6 WILL NOT BE USED FOR OUTGOING QUERIES")="";
3337 ::arg().set("client-tcp-timeout","Timeout in seconds when talking to TCP clients")="2";
3338 ::arg().set("max-mthreads", "Maximum number of simultaneous Mtasker threads")="2048";
3339 ::arg().set("max-tcp-clients","Maximum number of simultaneous TCP clients")="128";
3340 ::arg().set("server-down-max-fails","Maximum number of consecutive timeouts (and unreachables) to mark a server as down ( 0 => disabled )")="64";
3341 ::arg().set("server-down-throttle-time","Number of seconds to throttle all queries to a server after being marked as down")="60";
3342 ::arg().set("hint-file", "If set, load root hints from this file")="";
3343 ::arg().set("max-cache-entries", "If set, maximum number of entries in the main cache")="1000000";
3344 ::arg().set("max-negative-ttl", "maximum number of seconds to keep a negative cached entry in memory")="3600";
3345 ::arg().set("max-cache-ttl", "maximum number of seconds to keep a cached entry in memory")="86400";
3346 ::arg().set("packetcache-ttl", "maximum number of seconds to keep a cached entry in packetcache")="3600";
3347 ::arg().set("max-packetcache-entries", "maximum number of entries to keep in the packetcache")="500000";
3348 ::arg().set("packetcache-servfail-ttl", "maximum number of seconds to keep a cached servfail entry in packetcache")="60";
3349 ::arg().set("server-id", "Returned when queried for 'server.id' TXT or NSID, defaults to hostname")="";
3350 ::arg().set("stats-ringbuffer-entries", "maximum number of packets to store statistics for")="10000";
3351 ::arg().set("version-string", "string reported on version.pdns or version.bind")=fullVersionString();
3352 ::arg().set("allow-from", "If set, only allow these comma separated netmasks to recurse")=LOCAL_NETS
;
3353 ::arg().set("allow-from-file", "If set, load allowed netmasks from this file")="";
3354 ::arg().set("entropy-source", "If set, read entropy from this file")="/dev/urandom";
3355 ::arg().set("dont-query", "If set, do not query these netmasks for DNS data")=DONT_QUERY
;
3356 ::arg().set("max-tcp-per-client", "If set, maximum number of TCP sessions per client (IP address)")="0";
3357 ::arg().set("max-tcp-queries-per-connection", "If set, maximum number of TCP queries in a TCP connection")="0";
3358 ::arg().set("spoof-nearmiss-max", "If non-zero, assume spoofing after this many near misses")="20";
3359 ::arg().set("single-socket", "If set, only use a single socket for outgoing queries")="off";
3360 ::arg().set("auth-zones", "Zones for which we have authoritative data, comma separated domain=file pairs ")="";
3361 ::arg().set("lua-config-file", "More powerful configuration options")="";
3363 ::arg().set("forward-zones", "Zones for which we forward queries, comma separated domain=ip pairs")="";
3364 ::arg().set("forward-zones-recurse", "Zones for which we forward queries with recursion bit, comma separated domain=ip pairs")="";
3365 ::arg().set("forward-zones-file", "File with (+)domain=ip pairs for forwarding")="";
3366 ::arg().set("export-etc-hosts", "If we should serve up contents from /etc/hosts")="off";
3367 ::arg().set("export-etc-hosts-search-suffix", "Also serve up the contents of /etc/hosts with this suffix")="";
3368 ::arg().set("etc-hosts-file", "Path to 'hosts' file")="/etc/hosts";
3369 ::arg().set("serve-rfc1918", "If we should be authoritative for RFC 1918 private IP space")="yes";
3370 ::arg().set("lua-dns-script", "Filename containing an optional 'lua' script that will be used to modify dns answers")="";
3371 ::arg().set("latency-statistic-size","Number of latency values to calculate the qa-latency average")="10000";
3372 ::arg().setSwitch( "disable-packetcache", "Disable packetcache" )= "no";
3373 ::arg().set("ecs-ipv4-bits", "Number of bits of IPv4 address to pass for EDNS Client Subnet")="24";
3374 ::arg().set("ecs-ipv6-bits", "Number of bits of IPv6 address to pass for EDNS Client Subnet")="56";
3375 ::arg().set("edns-subnet-whitelist", "List of netmasks and domains that we should enable EDNS subnet for")="";
3376 ::arg().set("ecs-scope-zero-address", "Address to send to whitelisted authoritative servers for incoming queries with ECS prefix-length source of 0")="";
3377 ::arg().setSwitch( "use-incoming-edns-subnet", "Pass along received EDNS Client Subnet information")="no";
3378 ::arg().setSwitch( "pdns-distributes-queries", "If PowerDNS itself should distribute queries over threads")="yes";
3379 ::arg().setSwitch( "root-nx-trust", "If set, believe that an NXDOMAIN from the root means the TLD does not exist")="yes";
3380 ::arg().setSwitch( "any-to-tcp","Answer ANY queries with tc=1, shunting to TCP" )="no";
3381 ::arg().setSwitch( "lowercase-outgoing","Force outgoing questions to lowercase")="no";
3382 ::arg().setSwitch("gettag-needs-edns-options", "If EDNS Options should be extracted before calling the gettag() hook")="no";
3383 ::arg().set("udp-truncation-threshold", "Maximum UDP response size before we truncate")="1680";
3384 ::arg().set("edns-outgoing-bufsize", "Outgoing EDNS buffer size")="1680";
3385 ::arg().set("minimum-ttl-override", "Set under adverse conditions, a minimum TTL")="0";
3386 ::arg().set("max-qperq", "Maximum outgoing queries per query")="50";
3387 ::arg().set("max-total-msec", "Maximum total wall-clock time per query in milliseconds, 0 for unlimited")="7000";
3388 ::arg().set("max-recursion-depth", "Maximum number of internal recursion calls per query, 0 for unlimited")="40";
3390 ::arg().set("include-dir","Include *.conf files from this directory")="";
3391 ::arg().set("security-poll-suffix","Domain name from which to query security update notifications")="secpoll.powerdns.com.";
3393 ::arg().setSwitch("reuseport","Enable SO_REUSEPORT allowing multiple recursors processes to listen to 1 address")="no";
3395 ::arg().setSwitch("snmp-agent", "If set, register as an SNMP agent")="no";
3396 ::arg().set("snmp-master-socket", "If set and snmp-agent is set, the socket to use to register to the SNMP master")="";
3398 ::arg().set("tcp-fast-open", "Enable TCP Fast Open support on the listening sockets, using the supplied numerical value as the queue size")="0";
3399 ::arg().set("nsec3-max-iterations", "Maximum number of iterations allowed for an NSEC3 record")="2500";
3401 ::arg().set("cpu-map", "Thread to CPU mapping, space separated thread-id=cpu1,cpu2..cpuN pairs")="";
3403 ::arg().setSwitch("log-rpz-changes", "Log additions and removals to RPZ zones at Info level")="no";
3405 ::arg().setCmd("help","Provide a helpful message");
3406 ::arg().setCmd("version","Print version string");
3407 ::arg().setCmd("config","Output blank configuration");
3408 L
.toConsole(Logger::Info
);
3409 ::arg().laxParse(argc
,argv
); // do a lax parse
3411 string configname
=::arg()["config-dir"]+"/recursor.conf";
3412 if(::arg()["config-name"]!="") {
3413 configname
=::arg()["config-dir"]+"/recursor-"+::arg()["config-name"]+".conf";
3414 s_programname
+="-"+::arg()["config-name"];
3416 cleanSlashes(configname
);
3418 if(::arg().mustDo("config")) {
3419 cout
<<::arg().configstring()<<endl
;
3423 if(!::arg().file(configname
.c_str()))
3424 L
<<Logger::Warning
<<"Unable to parse configuration file '"<<configname
<<"'"<<endl
;
3426 ::arg().parse(argc
,argv
);
3428 if( !::arg()["chroot"].empty() && !::arg()["api-config-dir"].empty() && !::arg().mustDo("api-readonly") ) {
3429 L
<<Logger::Error
<<"Using chroot and a writable API is not possible"<<endl
;
3433 if (::arg()["socket-dir"].empty()) {
3434 if (::arg()["chroot"].empty())
3435 ::arg().set("socket-dir") = LOCALSTATEDIR
;
3437 ::arg().set("socket-dir") = "/";
3440 ::arg().set("delegation-only")=toLower(::arg()["delegation-only"]);
3442 if(::arg().asNum("threads")==1)
3443 ::arg().set("pdns-distributes-queries")="no";
3445 if(::arg().mustDo("help")) {
3446 cout
<<"syntax:"<<endl
<<endl
;
3447 cout
<<::arg().helpstring(::arg()["help"])<<endl
;
3450 if(::arg().mustDo("version")) {
3451 showProductVersion();
3452 showBuildConfiguration();
3456 Logger::Urgency logUrgency
= (Logger::Urgency
)::arg().asNum("loglevel");
3458 if (logUrgency
< Logger::Error
)
3459 logUrgency
= Logger::Error
;
3460 if(!g_quiet
&& logUrgency
< Logger::Info
) { // Logger::Info=6, Logger::Debug=7
3461 logUrgency
= Logger::Info
; // if you do --quiet=no, you need Info to also see the query log
3463 L
.setLoglevel(logUrgency
);
3464 L
.toConsole(logUrgency
);
3466 serviceMain(argc
, argv
);
3468 catch(PDNSException
&ae
) {
3469 L
<<Logger::Error
<<"Exception: "<<ae
.reason
<<endl
;
3472 catch(std::exception
&e
) {
3473 L
<<Logger::Error
<<"STL Exception: "<<e
.what()<<endl
;
3477 L
<<Logger::Error
<<"any other exception in main: "<<endl
;