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.
29 #ifdef HAVE_BOOST_CONTAINER_FLAT_SET_HPP
30 #include <boost/container/flat_set.hpp>
32 #include "ws-recursor.hh"
34 #include "threadname.hh"
35 #include "recpacketcache.hh"
37 #include "dns_random.hh"
41 #include "opensslsigners.hh"
44 #include <boost/static_assert.hpp>
47 #include "recursor_cache.hh"
48 #include "cachecleaner.hh"
55 #include "arguments.hh"
59 #include "sortlist.hh"
61 #include <boost/tuple/tuple.hpp>
62 #include <boost/tuple/tuple_comparison.hpp>
63 #include <boost/shared_array.hpp>
64 #include <boost/function.hpp>
65 #include <boost/algorithm/string.hpp>
67 #include "malloctrace.hh"
69 #include <netinet/tcp.h>
70 #include "capabilities.hh"
71 #include "dnsparser.hh"
72 #include "dnswriter.hh"
73 #include "dnsrecords.hh"
74 #include "zoneparser-tng.hh"
75 #include "rec_channel.hh"
80 #include "lua-recursor4.hh"
82 #include "responsestats.hh"
83 #include "secpoll-recursor.hh"
85 #include "filterpo.hh"
86 #include "rpzloader.hh"
87 #include "validate-recursor.hh"
88 #include "rec-lua-conf.hh"
89 #include "ednsoptions.hh"
91 #include "pubsuffix.hh"
94 #endif /* NOD_ENABLED */
96 #include "rec-protobuf.hh"
97 #include "rec-snmp.hh"
100 #include <systemd/sd-daemon.h>
103 #include "namespaces.hh"
106 #include "uuid-utils.hh"
111 typedef map
<ComboAddress
, uint32_t, ComboAddress::addressOnlyLessThan
> tcpClientCounts_t
;
113 static thread_local
std::shared_ptr
<RecursorLua4
> t_pdl
;
114 static thread_local
unsigned int t_id
= 0;
115 static thread_local
std::shared_ptr
<Regex
> t_traceRegex
;
116 static thread_local
std::unique_ptr
<tcpClientCounts_t
> t_tcpClientCounts
;
118 static thread_local
std::shared_ptr
<std::vector
<std::unique_ptr
<RemoteLogger
>>> t_protobufServers
{nullptr};
119 static thread_local
uint64_t t_protobufServersGeneration
;
120 static thread_local
std::shared_ptr
<std::vector
<std::unique_ptr
<RemoteLogger
>>> t_outgoingProtobufServers
{nullptr};
121 static thread_local
uint64_t t_outgoingProtobufServersGeneration
;
122 #endif /* HAVE_PROTOBUF */
124 thread_local
std::unique_ptr
<MT_t
> MT
; // the big MTasker
125 thread_local
std::unique_ptr
<MemRecursorCache
> t_RC
;
126 thread_local
std::unique_ptr
<RecursorPacketCache
> t_packetCache
;
127 thread_local FDMultiplexer
* t_fdm
{nullptr};
128 thread_local
std::unique_ptr
<addrringbuf_t
> t_remotes
, t_servfailremotes
, t_largeanswerremotes
, t_bogusremotes
;
129 thread_local
std::unique_ptr
<boost::circular_buffer
<pair
<DNSName
, uint16_t> > > t_queryring
, t_servfailqueryring
, t_bogusqueryring
;
130 thread_local
std::shared_ptr
<NetmaskGroup
> t_allowFrom
;
132 thread_local
std::shared_ptr
<nod::NODDB
> t_nodDBp
;
133 thread_local
std::shared_ptr
<nod::UniqueResponseDB
> t_udrDBp
;
134 #endif /* NOD_ENABLED */
135 __thread
struct timeval g_now
; // timestamp, updated (too) frequently
137 typedef vector
<pair
<int, function
< void(int, any
&) > > > deferredAdd_t
;
139 // for communicating with our threads
140 // effectively readonly after startup
145 int writeToThread
{-1};
146 int readToThread
{-1};
147 int writeFromThread
{-1};
148 int readFromThread
{-1};
149 int writeQueriesToThread
{-1}; // this one is non-blocking
150 int readQueriesToThread
{-1};
153 /* FD corresponding to TCP sockets this thread is listening
155 These FDs are also in deferredAdds when we have one
156 socket per listener, and in g_deferredAdds instead. */
157 std::set
<int> tcpSockets
;
158 /* FD corresponding to listening sockets if we have one socket per
159 listener (with reuseport), otherwise all listeners share the
160 same FD and g_deferredAdds is then used instead */
161 deferredAdd_t deferredAdds
;
162 struct ThreadPipeSet pipes
;
165 uint64_t numberOfDistributedQueries
{0};
166 /* handle the web server, carbon, statistics and the control channel */
167 bool isHandler
{false};
168 /* accept incoming queries (and distributes them to the workers if pdns-distributes-queries is set) */
169 bool isListener
{false};
170 /* process queries */
171 bool isWorker
{false};
174 /* first we have the handler thread, t_id == 0 (some other
175 helper threads like SNMP might have t_id == 0 as well)
176 then the distributor threads if any
177 and finally the workers */
178 static std::vector
<RecThreadInfo
> s_threadInfos
;
179 /* without reuseport, all listeners share the same sockets */
180 static deferredAdd_t g_deferredAdds
;
182 typedef vector
<int> tcpListenSockets_t
;
183 typedef map
<int, ComboAddress
> listenSocketsAddresses_t
; // is shared across all threads right now
185 static const ComboAddress
g_local4("0.0.0.0"), g_local6("::");
186 static listenSocketsAddresses_t g_listenSocketsAddresses
; // is shared across all threads right now
187 static set
<int> g_fromtosockets
; // listen sockets that use 'sendfromto()' mechanism
188 static vector
<ComboAddress
> g_localQueryAddresses4
, g_localQueryAddresses6
;
189 static AtomicCounter counter
;
190 static std::shared_ptr
<SyncRes::domainmap_t
> g_initialDomainMap
; // new threads needs this to be setup
191 static std::shared_ptr
<NetmaskGroup
> g_initialAllowFrom
; // new thread needs to be setup with this
192 static NetmaskGroup g_XPFAcl
;
193 static size_t g_tcpMaxQueriesPerConn
;
194 static size_t s_maxUDPQueriesPerRound
;
195 static uint64_t g_latencyStatSize
;
196 static uint32_t g_disthashseed
;
197 static unsigned int g_maxTCPPerClient
;
198 static unsigned int g_maxMThreads
;
199 static unsigned int g_numDistributorThreads
;
200 static unsigned int g_numWorkerThreads
;
201 static int g_tcpTimeout
;
202 static uint16_t g_udpTruncationThreshold
;
203 static uint16_t g_xpfRRCode
{0};
204 static std::atomic
<bool> statsWanted
;
205 static std::atomic
<bool> g_quiet
;
206 static bool g_logCommonErrors
;
207 static bool g_anyToTcp
;
208 static bool g_weDistributeQueries
; // if true, 1 or more threads listen on the incoming query sockets and distribute them to workers
209 static bool g_reusePort
{false};
210 static bool g_gettagNeedsEDNSOptions
{false};
211 static time_t g_statisticsInterval
;
212 static bool g_useIncomingECS
;
213 std::atomic
<uint32_t> g_maxCacheEntries
, g_maxPacketCacheEntries
;
215 static bool g_nodEnabled
;
216 static DNSName g_nodLookupDomain
;
217 static bool g_nodLog
;
218 static SuffixMatchNode g_nodDomainWL
;
219 static std::string g_nod_pbtag
;
220 static bool g_udrEnabled
;
221 static bool g_udrLog
;
222 static std::string g_udr_pbtag
;
223 #endif /* NOD_ENABLED */
224 #ifdef HAVE_BOOST_CONTAINER_FLAT_SET_HPP
225 static boost::container::flat_set
<uint16_t> s_avoidUdpSourcePorts
;
227 static std::set
<uint16_t> s_avoidUdpSourcePorts
;
229 static uint16_t s_minUdpSourcePort
;
230 static uint16_t s_maxUdpSourcePort
;
231 static double s_balancingFactor
;
233 RecursorControlChannel s_rcc
; // only active in the handler thread
234 RecursorStats g_stats
;
235 string s_programname
="pdns_recursor";
237 bool g_lowercaseOutgoing
;
238 unsigned int g_networkTimeoutMsec
;
239 unsigned int g_numThreads
;
240 uint16_t g_outgoingEDNSBufsize
;
241 bool g_logRPZChanges
{false};
243 #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"
244 #define LOCAL_NETS_INVERSE "!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"
245 // Bad Nets taken from both:
246 // http://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml
248 // http://www.iana.org/assignments/iana-ipv6-special-registry/iana-ipv6-special-registry.xhtml
249 // where such a network may not be considered a valid destination
250 #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"
251 #define DONT_QUERY LOCAL_NETS ", " BAD_NETS
253 //! used to send information to a newborn mthread
254 struct DNSComboWriter
{
255 DNSComboWriter(const std::string
& query
, const struct timeval
& now
): d_mdp(true, query
), d_now(now
), d_query(query
)
259 DNSComboWriter(const std::string
& query
, const struct timeval
& now
, std::vector
<std::string
>&& policyTags
, LuaContext::LuaObject
&& data
): d_mdp(true, query
), d_now(now
), d_query(query
), d_policyTags(std::move(policyTags
)), d_data(std::move(data
))
263 void setRemote(const ComboAddress
& sa
)
268 void setSource(const ComboAddress
& sa
)
273 void setLocal(const ComboAddress
& sa
)
278 void setDestination(const ComboAddress
& sa
)
283 void setSocket(int sock
)
288 string
getRemote() const
290 if (d_source
== d_remote
) {
291 return d_source
.toStringWithPort();
293 return d_source
.toStringWithPort() + " (proxied by " + d_remote
.toStringWithPort() + ")";
297 struct timeval d_now
;
298 /* Remote client, might differ from d_source
299 in case of XPF, in which case d_source holds
300 the IP of the client and d_remote of the proxy
302 ComboAddress d_remote
;
303 ComboAddress d_source
;
304 /* Destination address, might differ from
305 d_destination in case of XPF, in which case
306 d_destination holds the IP of the proxy and
307 d_local holds our own. */
308 ComboAddress d_local
;
309 ComboAddress d_destination
;
311 boost::uuids::uuid d_uuid
;
312 string d_requestorId
;
316 std::vector
<std::string
> d_policyTags
;
317 LuaContext::LuaObject d_data
;
318 EDNSSubnetOpts d_ednssubnet
;
319 shared_ptr
<TCPConnection
> d_tcpConnection
;
321 unsigned int d_tag
{0};
323 uint32_t d_ttlCap
{std::numeric_limits
<uint32_t>::max()};
324 uint16_t d_ecsBegin
{0};
325 uint16_t d_ecsEnd
{0};
326 bool d_variable
{false};
327 bool d_ecsFound
{false};
328 bool d_ecsParsed
{false};
334 return MT
? MT
.get() : nullptr;
339 static ArgvMap theArg
;
343 unsigned int getRecursorThreadId()
353 static bool isDistributorThread()
359 return g_weDistributeQueries
&& s_threadInfos
.at(t_id
).isListener
;
362 static bool isHandlerThread()
368 return s_threadInfos
.at(t_id
).isHandler
;
371 static void handleTCPClientWritable(int fd
, FDMultiplexer::funcparam_t
& var
);
373 // -1 is error, 0 is timeout, 1 is success
374 int asendtcp(const string
& data
, Socket
* sock
)
380 t_fdm
->addWriteFD(sock
->getHandle(), handleTCPClientWritable
, pident
);
383 int ret
=MT
->waitEvent(pident
, &packet
, g_networkTimeoutMsec
);
385 if(!ret
|| ret
==-1) { // timeout
386 t_fdm
->removeWriteFD(sock
->getHandle());
388 else if(packet
.size() !=data
.size()) { // main loop tells us what it sent out, or empty in case of an error
394 static void handleTCPClientReadable(int fd
, FDMultiplexer::funcparam_t
& var
);
396 // -1 is error, 0 is timeout, 1 is success
397 int arecvtcp(string
& data
, size_t len
, Socket
* sock
, bool incompleteOkay
)
403 pident
.inIncompleteOkay
=incompleteOkay
;
404 t_fdm
->addReadFD(sock
->getHandle(), handleTCPClientReadable
, pident
);
406 int ret
=MT
->waitEvent(pident
,&data
, g_networkTimeoutMsec
);
407 if(!ret
|| ret
==-1) { // timeout
408 t_fdm
->removeReadFD(sock
->getHandle());
410 else if(data
.empty()) {// error, EOF or other
417 static void handleGenUDPQueryResponse(int fd
, FDMultiplexer::funcparam_t
& var
)
419 PacketID pident
=*any_cast
<PacketID
>(&var
);
421 ComboAddress fromaddr
;
422 socklen_t addrlen
=sizeof(fromaddr
);
424 ssize_t ret
=recvfrom(fd
, resp
, sizeof(resp
), 0, (sockaddr
*)&fromaddr
, &addrlen
);
425 if (fromaddr
!= pident
.remote
) {
426 g_log
<<Logger::Notice
<<"Response received from the wrong remote host ("<<fromaddr
.toStringWithPort()<<" instead of "<<pident
.remote
.toStringWithPort()<<"), discarding"<<endl
;
430 t_fdm
->removeReadFD(fd
);
432 string
data(resp
, (size_t) ret
);
433 MT
->sendEvent(pident
, &data
);
437 MT
->sendEvent(pident
, &empty
);
438 // cerr<<"Had some kind of error: "<<ret<<", "<<strerror(errno)<<endl;
441 string
GenUDPQueryResponse(const ComboAddress
& dest
, const string
& query
)
443 Socket
s(dest
.sin4
.sin_family
, SOCK_DGRAM
);
445 ComboAddress local
= getQueryLocalAddress(dest
.sin4
.sin_family
, 0);
455 t_fdm
->addReadFD(s
.getHandle(), handleGenUDPQueryResponse
, pident
);
459 int ret
=MT
->waitEvent(pident
,&data
, g_networkTimeoutMsec
);
461 if(!ret
|| ret
==-1) { // timeout
462 t_fdm
->removeReadFD(s
.getHandle());
464 else if(data
.empty()) {// error, EOF or other
465 // we could special case this
471 //! pick a random query local address
472 ComboAddress
getQueryLocalAddress(int family
, uint16_t port
)
475 if(family
==AF_INET
) {
476 if(g_localQueryAddresses4
.empty())
479 ret
= g_localQueryAddresses4
[dns_random(g_localQueryAddresses4
.size())];
480 ret
.sin4
.sin_port
= htons(port
);
483 if(g_localQueryAddresses6
.empty())
486 ret
= g_localQueryAddresses6
[dns_random(g_localQueryAddresses6
.size())];
488 ret
.sin6
.sin6_port
= htons(port
);
493 static void handleUDPServerResponse(int fd
, FDMultiplexer::funcparam_t
&);
495 static void setSocketBuffer(int fd
, int optname
, uint32_t size
)
498 socklen_t len
=sizeof(psize
);
500 if(!getsockopt(fd
, SOL_SOCKET
, optname
, (char*)&psize
, &len
) && psize
> size
) {
501 g_log
<<Logger::Error
<<"Not decreasing socket buffer size from "<<psize
<<" to "<<size
<<endl
;
505 if (setsockopt(fd
, SOL_SOCKET
, optname
, (char*)&size
, sizeof(size
)) < 0 )
506 g_log
<<Logger::Error
<<"Unable to raise socket buffer size to "<<size
<<": "<<strerror(errno
)<<endl
;
510 static void setSocketReceiveBuffer(int fd
, uint32_t size
)
512 setSocketBuffer(fd
, SO_RCVBUF
, size
);
515 static void setSocketSendBuffer(int fd
, uint32_t size
)
517 setSocketBuffer(fd
, SO_SNDBUF
, size
);
521 // you can ask this class for a UDP socket to send a query from
522 // this socket is not yours, don't even think about deleting it
523 // but after you call 'returnSocket' on it, don't assume anything anymore
526 unsigned int d_numsocks
;
528 UDPClientSocks() : d_numsocks(0)
532 typedef set
<int> socks_t
;
535 // returning -2 means: temporary OS error (ie, out of files), -1 means error related to remote
536 int getSocket(const ComboAddress
& toaddr
, int* fd
)
538 *fd
=makeClientSocket(toaddr
.sin4
.sin_family
);
539 if(*fd
< 0) // temporary error - receive exception otherwise
542 if(connect(*fd
, (struct sockaddr
*)(&toaddr
), toaddr
.getSocklen()) < 0) {
544 // returnSocket(*fd);
548 catch(const PDNSException
& e
) {
549 g_log
<<Logger::Error
<<"Error closing UDP socket after connect() failed: "<<e
.reason
<<endl
;
552 if(err
==ENETUNREACH
) // Seth "My Interfaces Are Like A Yo Yo" Arnold special
562 void returnSocket(int fd
)
564 socks_t::iterator i
=d_socks
.find(fd
);
565 if(i
==d_socks
.end()) {
566 throw PDNSException("Trying to return a socket (fd="+std::to_string(fd
)+") not in the pool");
568 returnSocketLocked(i
);
571 // return a socket to the pool, or simply erase it
572 void returnSocketLocked(socks_t::iterator
& i
)
574 if(i
==d_socks
.end()) {
575 throw PDNSException("Trying to return a socket not in the pool");
578 t_fdm
->removeReadFD(*i
);
580 catch(FDMultiplexerException
& e
) {
581 // we sometimes return a socket that has not yet been assigned to t_fdm
586 catch(const PDNSException
& e
) {
587 g_log
<<Logger::Error
<<"Error closing returned UDP socket: "<<e
.reason
<<endl
;
594 // returns -1 for errors which might go away, throws for ones that won't
595 static int makeClientSocket(int family
)
597 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)
599 if(ret
< 0 && errno
==EMFILE
) // this is not a catastrophic error
603 throw PDNSException("Making a socket for resolver (family = "+std::to_string(family
)+"): "+stringerror());
605 // setCloseOnExec(ret); // we're not going to exec
612 if(tries
==1) // fall back to kernel 'random'
616 port
= s_minUdpSourcePort
+ dns_random(s_maxUdpSourcePort
- s_minUdpSourcePort
+ 1);
618 while (s_avoidUdpSourcePorts
.count(port
));
621 sin
=getQueryLocalAddress(family
, port
); // does htons for us
623 if (::bind(ret
, (struct sockaddr
*)&sin
, sin
.getSocklen()) >= 0)
627 throw PDNSException("Resolver binding to local query client socket on "+sin
.toString()+": "+stringerror());
629 setReceiveSocketErrors(ret
, family
);
635 static thread_local
std::unique_ptr
<UDPClientSocks
> t_udpclientsocks
;
637 /* these two functions are used by LWRes */
638 // -2 is OS error, -1 is error that depends on the remote, > 0 is success
639 int asendto(const char *data
, size_t len
, int flags
,
640 const ComboAddress
& toaddr
, uint16_t id
, const DNSName
& domain
, uint16_t qtype
, int* fd
)
644 pident
.domain
= domain
;
645 pident
.remote
= toaddr
;
648 // see if there is an existing outstanding request we can chain on to, using partial equivalence function
649 pair
<MT_t::waiters_t::iterator
, MT_t::waiters_t::iterator
> chain
=MT
->d_waiters
.equal_range(pident
, PacketIDBirthdayCompare());
651 for(; chain
.first
!= chain
.second
; chain
.first
++) {
652 if(chain
.first
->key
.fd
> -1) { // don't chain onto existing chained waiter!
654 cerr<<"Orig: "<<pident.domain<<", "<<pident.remote.toString()<<", id="<<id<<endl;
655 cerr<<"Had hit: "<< chain.first->key.domain<<", "<<chain.first->key.remote.toString()<<", id="<<chain.first->key.id
656 <<", count="<<chain.first->key.chain.size()<<", origfd: "<<chain.first->key.fd<<endl;
658 chain
.first
->key
.chain
.insert(id
); // we can chain
659 *fd
=-1; // gets used in waitEvent / sendEvent later on
664 int ret
=t_udpclientsocks
->getSocket(toaddr
, fd
);
671 t_fdm
->addReadFD(*fd
, handleUDPServerResponse
, pident
);
672 ret
= send(*fd
, data
, len
, 0);
677 t_udpclientsocks
->returnSocket(*fd
);
679 errno
= tmp
; // this is for logging purposes only
683 // -1 is error, 0 is timeout, 1 is success
684 int arecvfrom(std::string
& packet
, int flags
, const ComboAddress
& fromaddr
, size_t *d_len
,
685 uint16_t id
, const DNSName
& domain
, uint16_t qtype
, int fd
, struct timeval
* now
)
687 static optional
<unsigned int> nearMissLimit
;
689 nearMissLimit
=::arg().asNum("spoof-nearmiss-max");
694 pident
.domain
=domain
;
696 pident
.remote
=fromaddr
;
698 int ret
=MT
->waitEvent(pident
, &packet
, g_networkTimeoutMsec
, now
);
701 if(packet
.empty()) // means "error"
704 *d_len
=packet
.size();
706 if(*nearMissLimit
&& pident
.nearMisses
> *nearMissLimit
) {
707 g_log
<<Logger::Error
<<"Too many ("<<pident
.nearMisses
<<" > "<<*nearMissLimit
<<") bogus answers for '"<<domain
<<"' from "<<fromaddr
.toString()<<", assuming spoof attempt."<<endl
;
708 g_stats
.spoofCount
++;
714 t_udpclientsocks
->returnSocket(fd
);
719 static void writePid(void)
721 if(!::arg().mustDo("write-pid"))
723 ofstream
of(s_pidfname
.c_str(), std::ios_base::app
);
725 of
<< Utility::getpid() <<endl
;
727 g_log
<<Logger::Error
<<"Writing pid for "<<Utility::getpid()<<" to "<<s_pidfname
<<" failed: "<<strerror(errno
)<<endl
;
730 TCPConnection::TCPConnection(int fd
, const ComboAddress
& addr
) : data(2, 0), d_remote(addr
), d_fd(fd
)
732 ++s_currentConnections
;
733 (*t_tcpClientCounts
)[d_remote
]++;
736 TCPConnection::~TCPConnection()
739 if(closesocket(d_fd
) < 0)
740 g_log
<<Logger::Error
<<"Error closing socket for TCPConnection"<<endl
;
742 catch(const PDNSException
& e
) {
743 g_log
<<Logger::Error
<<"Error closing TCPConnection socket: "<<e
.reason
<<endl
;
746 if(t_tcpClientCounts
->count(d_remote
) && !(*t_tcpClientCounts
)[d_remote
]--)
747 t_tcpClientCounts
->erase(d_remote
);
748 --s_currentConnections
;
751 AtomicCounter
TCPConnection::s_currentConnections
;
753 static void handleRunningTCPQuestion(int fd
, FDMultiplexer::funcparam_t
& var
);
755 // the idea is, only do things that depend on the *response* here. Incoming accounting is on incoming.
756 static void updateResponseStats(int res
, const ComboAddress
& remote
, unsigned int packetsize
, const DNSName
* query
, uint16_t qtype
)
758 if(packetsize
> 1000 && t_largeanswerremotes
)
759 t_largeanswerremotes
->push_back(remote
);
761 case RCode::ServFail
:
762 if(t_servfailremotes
) {
763 t_servfailremotes
->push_back(remote
);
764 if(query
&& t_servfailqueryring
) // packet cache
765 t_servfailqueryring
->push_back(make_pair(*query
, qtype
));
769 case RCode::NXDomain
:
778 static string
makeLoginfo(const std::unique_ptr
<DNSComboWriter
>& dc
)
781 return "("+dc
->d_mdp
.d_qname
.toLogString()+"/"+DNSRecordContent::NumberToType(dc
->d_mdp
.d_qtype
)+" from "+(dc
->getRemote())+")";
785 return "Exception making error message for exception";
789 static void protobufLogQuery(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
)
791 if (!t_protobufServers
) {
795 Netmask
requestorNM(remote
, remote
.sin4
.sin_family
== AF_INET
? maskV4
: maskV6
);
796 const ComboAddress
& requestor
= requestorNM
.getMaskedNetwork();
797 RecProtoBufMessage
message(DNSProtoBufMessage::Query
, uniqueId
, &requestor
, &local
, qname
, qtype
, qclass
, id
, tcp
, len
);
798 message
.setServerIdentity(SyncRes::s_serverID
);
799 message
.setEDNSSubnet(ednssubnet
, ednssubnet
.isIpv4() ? maskV4
: maskV6
);
800 message
.setRequestorId(requestorId
);
801 message
.setDeviceId(deviceId
);
803 if (!policyTags
.empty()) {
804 message
.setPolicyTags(policyTags
);
807 // cerr <<message.toDebugString()<<endl;
809 message
.serialize(str
);
811 for (auto& server
: *t_protobufServers
) {
812 server
->queueData(str
);
816 static void protobufLogResponse(const RecProtoBufMessage
& message
)
818 if (!t_protobufServers
) {
822 // cerr <<message.toDebugString()<<endl;
824 message
.serialize(str
);
826 for (auto& server
: *t_protobufServers
) {
827 server
->queueData(str
);
833 * Chases the CNAME provided by the PolicyCustom RPZ policy.
835 * @param spoofed: The DNSRecord that was created by the policy, should already be added to ret
836 * @param qtype: The QType of the original query
837 * @param sr: A SyncRes
838 * @param res: An integer that will contain the RCODE of the lookup we do
839 * @param ret: A vector of DNSRecords where the result of the CNAME chase should be appended to
841 static void handleRPZCustom(const DNSRecord
& spoofed
, const QType
& qtype
, SyncRes
& sr
, int& res
, vector
<DNSRecord
>& ret
)
843 if (spoofed
.d_type
== QType::CNAME
) {
844 bool oldWantsRPZ
= sr
.getWantsRPZ();
845 sr
.setWantsRPZ(false);
846 vector
<DNSRecord
> ans
;
847 res
= sr
.beginResolve(DNSName(spoofed
.d_content
->getZoneRepresentation()), qtype
, QClass::IN
, ans
);
848 for (const auto& rec
: ans
) {
849 if(rec
.d_place
== DNSResourceRecord::ANSWER
) {
853 // Reset the RPZ state of the SyncRes
854 sr
.setWantsRPZ(oldWantsRPZ
);
858 static bool addRecordToPacket(DNSPacketWriter
& pw
, const DNSRecord
& rec
, uint32_t& minTTL
, uint32_t ttlCap
, const uint16_t maxAnswerSize
)
860 pw
.startRecord(rec
.d_name
, rec
.d_type
, (rec
.d_ttl
> ttlCap
? ttlCap
: rec
.d_ttl
), rec
.d_class
, rec
.d_place
);
862 if(rec
.d_type
!= QType::OPT
) // their TTL ain't real
863 minTTL
= min(minTTL
, rec
.d_ttl
);
865 rec
.d_content
->toPacket(pw
);
866 if(pw
.size() > static_cast<size_t>(maxAnswerSize
)) {
868 if(rec
.d_place
!= DNSResourceRecord::ADDITIONAL
) {
869 pw
.getHeader()->tc
=1;
879 static std::shared_ptr
<std::vector
<std::unique_ptr
<RemoteLogger
>>> startProtobufServers(const ProtobufExportConfig
& config
)
881 auto result
= std::make_shared
<std::vector
<std::unique_ptr
<RemoteLogger
>>>();
883 for (const auto& server
: config
.servers
) {
885 result
->emplace_back(new RemoteLogger(server
, config
.timeout
, 100*config
.maxQueuedEntries
, config
.reconnectWaitTime
, config
.asyncConnect
));
887 catch(const std::exception
& e
) {
888 g_log
<<Logger::Error
<<"Error while starting protobuf logger to '"<<server
<<": "<<e
.what()<<endl
;
890 catch(const PDNSException
& e
) {
891 g_log
<<Logger::Error
<<"Error while starting protobuf logger to '"<<server
<<": "<<e
.reason
<<endl
;
898 static bool checkProtobufExport(LocalStateHolder
<LuaConfigItems
>& luaconfsLocal
)
900 if (!luaconfsLocal
->protobufExportConfig
.enabled
) {
901 if (t_protobufServers
) {
902 for (auto& server
: *t_protobufServers
) {
905 t_protobufServers
.reset();
911 /* if the server was not running, or if it was running according to a
912 previous configuration */
913 if (!t_protobufServers
||
914 t_protobufServersGeneration
< luaconfsLocal
->generation
) {
916 if (t_protobufServers
) {
917 for (auto& server
: *t_protobufServers
) {
921 t_protobufServers
.reset();
923 t_protobufServers
= startProtobufServers(luaconfsLocal
->protobufExportConfig
);
924 t_protobufServersGeneration
= luaconfsLocal
->generation
;
930 static bool checkOutgoingProtobufExport(LocalStateHolder
<LuaConfigItems
>& luaconfsLocal
)
932 if (!luaconfsLocal
->outgoingProtobufExportConfig
.enabled
) {
933 if (t_outgoingProtobufServers
) {
934 for (auto& server
: *t_outgoingProtobufServers
) {
938 t_outgoingProtobufServers
.reset();
943 /* if the server was not running, or if it was running according to a
944 previous configuration */
945 if (!t_outgoingProtobufServers
||
946 t_outgoingProtobufServersGeneration
< luaconfsLocal
->generation
) {
948 if (t_outgoingProtobufServers
) {
949 for (auto& server
: *t_outgoingProtobufServers
) {
953 t_outgoingProtobufServers
.reset();
955 t_outgoingProtobufServers
= startProtobufServers(luaconfsLocal
->outgoingProtobufExportConfig
);
956 t_outgoingProtobufServersGeneration
= luaconfsLocal
->generation
;
961 #endif /* HAVE_PROTOBUF */
964 static bool nodCheckNewDomain(const DNSName
& dname
)
966 static const QType
qt(QType::A
);
967 static const uint16_t qc(QClass::IN
);
969 // First check the (sub)domain isn't whitelisted for NOD purposes
970 if (!g_nodDomainWL
.check(dname
)) {
971 // Now check the NODDB (note this is probablistic so can have FNs/FPs)
972 if (t_nodDBp
&& t_nodDBp
->isNewDomain(dname
)) {
974 // This should probably log to a dedicated log file
975 g_log
<<Logger::Notice
<<"Newly observed domain nod="<<dname
.toLogString()<<endl
;
977 if (!(g_nodLookupDomain
.isRoot())) {
978 // Send a DNS A query to <domain>.g_nodLookupDomain
979 DNSName qname
= dname
;
980 vector
<DNSRecord
> dummy
;
981 qname
+= g_nodLookupDomain
;
982 directResolve(qname
, qt
, qc
, dummy
);
990 static void nodAddDomain(const DNSName
& dname
)
992 // Don't bother adding domains on the nod whitelist
993 if (!g_nodDomainWL
.check(dname
)) {
995 // This keeps the nod info up to date
996 t_nodDBp
->addDomain(dname
);
1001 static bool udrCheckUniqueDNSRecord(const DNSName
& dname
, uint16_t qtype
, const DNSRecord
& record
)
1004 if (record
.d_place
== DNSResourceRecord::ANSWER
||
1005 record
.d_place
== DNSResourceRecord::ADDITIONAL
) {
1006 // Create a string that represent a triplet of (qname, qtype and RR[type, name, content])
1007 std::stringstream ss
;
1008 ss
<< dname
.toDNSStringLC() << ":" << qtype
<< ":" << qtype
<< ":" << record
.d_type
<< ":" << record
.d_name
.toDNSStringLC() << ":" << record
.d_content
->getZoneRepresentation();
1009 if (t_udrDBp
&& t_udrDBp
->isUniqueResponse(ss
.str())) {
1011 // This should also probably log to a dedicated file.
1012 g_log
<<Logger::Notice
<<"Unique response observed: qname="<<dname
.toLogString()<<" qtype="<<QType(qtype
).getName()<< " rrtype=" << QType(record
.d_type
).getName() << " rrname=" << record
.d_name
.toLogString() << " rrcontent=" << record
.d_content
->getZoneRepresentation() << endl
;
1019 #endif /* NOD_ENABLED */
1021 static void startDoResolve(void *p
)
1023 auto dc
=std::unique_ptr
<DNSComboWriter
>(reinterpret_cast<DNSComboWriter
*>(p
));
1026 t_queryring
->push_back(make_pair(dc
->d_mdp
.d_qname
, dc
->d_mdp
.d_qtype
));
1028 uint16_t maxanswersize
= dc
->d_tcp
? 65535 : min(static_cast<uint16_t>(512), g_udpTruncationThreshold
);
1030 std::vector
<pair
<uint16_t, string
> > ednsOpts
;
1031 bool variableAnswer
= dc
->d_variable
;
1032 bool haveEDNS
=false;
1034 bool hasUDR
= false;
1035 #endif /* NOD_ENABLED */
1036 DNSPacketWriter::optvect_t returnedEdnsOptions
; // Here we stuff all the options for the return packet
1037 uint8_t ednsExtRCode
= 0;
1038 if(getEDNSOpts(dc
->d_mdp
, &edo
)) {
1040 if (edo
.d_version
!= 0) {
1041 ednsExtRCode
= ERCode::BADVERS
;
1046 "Values lower than 512 MUST be treated as equal to 512."
1048 maxanswersize
= min(static_cast<uint16_t>(edo
.d_packetsize
>= 512 ? edo
.d_packetsize
: 512), g_udpTruncationThreshold
);
1050 ednsOpts
= edo
.d_options
;
1051 maxanswersize
-= 11; // EDNS header size
1053 for (const auto& o
: edo
.d_options
) {
1054 if (o
.first
== EDNSOptionCode::ECS
&& g_useIncomingECS
&& !dc
->d_ecsParsed
) {
1055 dc
->d_ecsFound
= getEDNSSubnetOptsFromString(o
.second
, &dc
->d_ednssubnet
);
1056 } else if (o
.first
== EDNSOptionCode::NSID
) {
1057 const static string mode_server_id
= ::arg()["server-id"];
1058 if(mode_server_id
!= "disabled" && !mode_server_id
.empty() &&
1059 maxanswersize
> (2 + 2 + mode_server_id
.size())) {
1060 returnedEdnsOptions
.push_back(make_pair(EDNSOptionCode::NSID
, mode_server_id
));
1061 variableAnswer
= true; // Can't packetcache an answer with NSID
1062 // Option Code and Option Length are both 2
1063 maxanswersize
-= 2 + 2 + mode_server_id
.size();
1068 /* perhaps there was no EDNS or no ECS but by now we looked */
1069 dc
->d_ecsParsed
= true;
1070 vector
<DNSRecord
> ret
;
1071 vector
<uint8_t> packet
;
1073 auto luaconfsLocal
= g_luaconfs
.getLocal();
1074 // Used to tell syncres later on if we should apply NSDNAME and NSIP RPZ triggers for this query
1075 bool wantsRPZ(true);
1076 boost::optional
<RecProtoBufMessage
> pbMessage(boost::none
);
1077 bool logResponse
= false;
1078 #ifdef HAVE_PROTOBUF
1079 if (checkProtobufExport(luaconfsLocal
)) {
1080 logResponse
= t_protobufServers
&& luaconfsLocal
->protobufExportConfig
.logResponses
;
1081 Netmask
requestorNM(dc
->d_source
, dc
->d_source
.sin4
.sin_family
== AF_INET
? luaconfsLocal
->protobufMaskV4
: luaconfsLocal
->protobufMaskV6
);
1082 const ComboAddress
& requestor
= requestorNM
.getMaskedNetwork();
1083 pbMessage
= RecProtoBufMessage(RecProtoBufMessage::Response
, dc
->d_uuid
, &requestor
, &dc
->d_destination
, dc
->d_mdp
.d_qname
, dc
->d_mdp
.d_qtype
, dc
->d_mdp
.d_qclass
, dc
->d_mdp
.d_header
.id
, dc
->d_tcp
, 0);
1084 pbMessage
->setServerIdentity(SyncRes::s_serverID
);
1085 pbMessage
->setEDNSSubnet(dc
->d_ednssubnet
.source
, dc
->d_ednssubnet
.source
.isIpv4() ? luaconfsLocal
->protobufMaskV4
: luaconfsLocal
->protobufMaskV6
);
1087 #endif /* HAVE_PROTOBUF */
1089 DNSPacketWriter
pw(packet
, dc
->d_mdp
.d_qname
, dc
->d_mdp
.d_qtype
, dc
->d_mdp
.d_qclass
);
1091 pw
.getHeader()->aa
=0;
1092 pw
.getHeader()->ra
=1;
1093 pw
.getHeader()->qr
=1;
1094 pw
.getHeader()->tc
=0;
1095 pw
.getHeader()->id
=dc
->d_mdp
.d_header
.id
;
1096 pw
.getHeader()->rd
=dc
->d_mdp
.d_header
.rd
;
1097 pw
.getHeader()->cd
=dc
->d_mdp
.d_header
.cd
;
1099 /* This is the lowest TTL seen in the records of the response,
1100 so we can't cache it for longer than this value.
1101 If we have a TTL cap, this value can't be larger than the
1102 cap no matter what. */
1103 uint32_t minTTL
= dc
->d_ttlCap
;
1105 SyncRes
sr(dc
->d_now
);
1107 bool DNSSECOK
=false;
1109 sr
.setLuaEngine(t_pdl
);
1111 if(g_dnssecmode
!= DNSSECMode::Off
) {
1112 sr
.setDoDNSSEC(true);
1114 // Does the requestor want DNSSEC records?
1115 if(edo
.d_extFlags
& EDNSOpts::DNSSECOK
) {
1117 g_stats
.dnssecQueries
++;
1119 if (dc
->d_mdp
.d_header
.cd
) {
1120 /* Per rfc6840 section 5.9, "When processing a request with
1121 the Checking Disabled (CD) bit set, a resolver SHOULD attempt
1122 to return all response data, even data that has failed DNSSEC
1124 ++g_stats
.dnssecCheckDisabledQueries
;
1126 if (dc
->d_mdp
.d_header
.ad
) {
1127 /* Per rfc6840 section 5.7, "the AD bit in a query as a signal
1128 indicating that the requester understands and is interested in the
1129 value of the AD bit in the response. This allows a requester to
1130 indicate that it understands the AD bit without also requesting
1131 DNSSEC data via the DO bit. */
1132 ++g_stats
.dnssecAuthenticDataQueries
;
1135 // Ignore the client-set CD flag
1136 pw
.getHeader()->cd
=0;
1138 sr
.setDNSSECValidationRequested(g_dnssecmode
== DNSSECMode::ValidateAll
|| g_dnssecmode
==DNSSECMode::ValidateForLog
|| ((dc
->d_mdp
.d_header
.ad
|| DNSSECOK
) && g_dnssecmode
==DNSSECMode::Process
));
1140 #ifdef HAVE_PROTOBUF
1141 sr
.setInitialRequestId(dc
->d_uuid
);
1142 sr
.setOutgoingProtobufServers(t_outgoingProtobufServers
);
1145 sr
.setQuerySource(dc
->d_remote
, g_useIncomingECS
&& !dc
->d_ednssubnet
.source
.empty() ? boost::optional
<const EDNSSubnetOpts
&>(dc
->d_ednssubnet
) : boost::none
);
1147 bool tracedQuery
=false; // we could consider letting Lua know about this too
1148 bool shouldNotValidate
= false;
1150 /* preresolve expects res (dq.rcode) to be set to RCode::NoError by default */
1151 int res
= RCode::NoError
;
1152 DNSFilterEngine::Policy appliedPolicy
;
1153 std::vector
<DNSRecord
> spoofed
;
1154 RecursorLua4::DNSQuestion
dq(dc
->d_source
, dc
->d_destination
, dc
->d_mdp
.d_qname
, dc
->d_mdp
.d_qtype
, dc
->d_tcp
, variableAnswer
, wantsRPZ
, logResponse
);
1155 dq
.ednsFlags
= &edo
.d_extFlags
;
1156 dq
.ednsOptions
= &ednsOpts
;
1158 dq
.discardedPolicies
= &sr
.d_discardedPolicies
;
1159 dq
.policyTags
= &dc
->d_policyTags
;
1160 dq
.appliedPolicy
= &appliedPolicy
;
1161 dq
.currentRecords
= &ret
;
1162 dq
.dh
= &dc
->d_mdp
.d_header
;
1163 dq
.data
= dc
->d_data
;
1164 #ifdef HAVE_PROTOBUF
1165 dq
.requestorId
= dc
->d_requestorId
;
1166 dq
.deviceId
= dc
->d_deviceId
;
1169 if(ednsExtRCode
!= 0) {
1173 if(dc
->d_mdp
.d_qtype
==QType::ANY
&& !dc
->d_tcp
&& g_anyToTcp
) {
1174 pw
.getHeader()->tc
= 1;
1176 variableAnswer
= true;
1180 if(t_traceRegex
&& t_traceRegex
->match(dc
->d_mdp
.d_qname
.toString())) {
1181 sr
.setLogMode(SyncRes::Store
);
1186 if(!g_quiet
|| tracedQuery
) {
1187 g_log
<<Logger::Warning
<<t_id
<<" ["<<MT
->getTid()<<"/"<<MT
->numProcesses()<<"] " << (dc
->d_tcp
? "TCP " : "") << "question for '"<<dc
->d_mdp
.d_qname
<<"|"
1188 <<DNSRecordContent::NumberToType(dc
->d_mdp
.d_qtype
)<<"' from "<<dc
->getRemote();
1189 if(!dc
->d_ednssubnet
.source
.empty()) {
1190 g_log
<<" (ecs "<<dc
->d_ednssubnet
.source
.toString()<<")";
1195 sr
.setId(MT
->getTid());
1196 if(!dc
->d_mdp
.d_header
.rd
)
1200 t_pdl
->prerpz(dq
, res
);
1203 // Check if the query has a policy attached to it
1205 appliedPolicy
= luaconfsLocal
->dfe
.getQueryPolicy(dc
->d_mdp
.d_qname
, dc
->d_source
, sr
.d_discardedPolicies
);
1208 // if there is a RecursorLua active, and it 'took' the query in preResolve, we don't launch beginResolve
1209 if(!t_pdl
|| !t_pdl
->preresolve(dq
, res
)) {
1211 sr
.setWantsRPZ(wantsRPZ
);
1213 switch(appliedPolicy
.d_kind
) {
1214 case DNSFilterEngine::PolicyKind::NoAction
:
1216 case DNSFilterEngine::PolicyKind::Drop
:
1217 g_stats
.policyDrops
++;
1218 g_stats
.policyResults
[appliedPolicy
.d_kind
]++;
1220 case DNSFilterEngine::PolicyKind::NXDOMAIN
:
1221 g_stats
.policyResults
[appliedPolicy
.d_kind
]++;
1222 res
=RCode::NXDomain
;
1224 case DNSFilterEngine::PolicyKind::NODATA
:
1225 g_stats
.policyResults
[appliedPolicy
.d_kind
]++;
1228 case DNSFilterEngine::PolicyKind::Custom
:
1229 g_stats
.policyResults
[appliedPolicy
.d_kind
]++;
1231 spoofed
=appliedPolicy
.getCustomRecords(dc
->d_mdp
.d_qname
, dc
->d_mdp
.d_qtype
);
1232 for (const auto& dr
: spoofed
) {
1234 handleRPZCustom(dr
, QType(dc
->d_mdp
.d_qtype
), sr
, res
, ret
);
1237 case DNSFilterEngine::PolicyKind::Truncate
:
1239 g_stats
.policyResults
[appliedPolicy
.d_kind
]++;
1241 pw
.getHeader()->tc
=1;
1248 // Query got not handled for QNAME Policy reasons, now actually go out to find an answer
1250 res
= sr
.beginResolve(dc
->d_mdp
.d_qname
, QType(dc
->d_mdp
.d_qtype
), dc
->d_mdp
.d_qclass
, ret
);
1251 shouldNotValidate
= sr
.wasOutOfBand();
1253 catch(ImmediateServFailException
&e
) {
1254 if(g_logCommonErrors
)
1255 g_log
<<Logger::Notice
<<"Sending SERVFAIL to "<<dc
->getRemote()<<" during resolve of '"<<dc
->d_mdp
.d_qname
<<"' because: "<<e
.reason
<<endl
;
1256 res
= RCode::ServFail
;
1259 dq
.validationState
= sr
.getValidationState();
1261 // During lookup, an NSDNAME or NSIP trigger was hit in RPZ
1262 if (res
== -2) { // XXX This block should be macro'd, it is repeated post-resolve.
1263 appliedPolicy
= sr
.d_appliedPolicy
;
1264 g_stats
.policyResults
[appliedPolicy
.d_kind
]++;
1265 switch(appliedPolicy
.d_kind
) {
1266 case DNSFilterEngine::PolicyKind::NoAction
: // This can never happen
1267 throw PDNSException("NoAction policy returned while a NSDNAME or NSIP trigger was hit");
1268 case DNSFilterEngine::PolicyKind::Drop
:
1269 g_stats
.policyDrops
++;
1271 case DNSFilterEngine::PolicyKind::NXDOMAIN
:
1273 res
=RCode::NXDomain
;
1276 case DNSFilterEngine::PolicyKind::NODATA
:
1281 case DNSFilterEngine::PolicyKind::Truncate
:
1285 pw
.getHeader()->tc
=1;
1290 case DNSFilterEngine::PolicyKind::Custom
:
1293 spoofed
=appliedPolicy
.getCustomRecords(dc
->d_mdp
.d_qname
, dc
->d_mdp
.d_qtype
);
1294 for (const auto& dr
: spoofed
) {
1296 handleRPZCustom(dr
, QType(dc
->d_mdp
.d_qtype
), sr
, res
, ret
);
1303 appliedPolicy
= luaconfsLocal
->dfe
.getPostPolicy(ret
, sr
.d_discardedPolicies
);
1307 if(res
== RCode::NoError
) {
1308 auto i
=ret
.cbegin();
1309 for(; i
!= ret
.cend(); ++i
)
1310 if(i
->d_type
== dc
->d_mdp
.d_qtype
&& i
->d_place
== DNSResourceRecord::ANSWER
)
1312 if(i
== ret
.cend() && t_pdl
->nodata(dq
, res
))
1313 shouldNotValidate
= true;
1316 else if(res
== RCode::NXDomain
&& t_pdl
->nxdomain(dq
, res
))
1317 shouldNotValidate
= true;
1319 if(t_pdl
->postresolve(dq
, res
))
1320 shouldNotValidate
= true;
1323 if (wantsRPZ
) { //XXX This block is repeated, see above
1324 g_stats
.policyResults
[appliedPolicy
.d_kind
]++;
1325 switch(appliedPolicy
.d_kind
) {
1326 case DNSFilterEngine::PolicyKind::NoAction
:
1328 case DNSFilterEngine::PolicyKind::Drop
:
1329 g_stats
.policyDrops
++;
1331 case DNSFilterEngine::PolicyKind::NXDOMAIN
:
1333 res
=RCode::NXDomain
;
1336 case DNSFilterEngine::PolicyKind::NODATA
:
1341 case DNSFilterEngine::PolicyKind::Truncate
:
1345 pw
.getHeader()->tc
=1;
1350 case DNSFilterEngine::PolicyKind::Custom
:
1353 spoofed
=appliedPolicy
.getCustomRecords(dc
->d_mdp
.d_qname
, dc
->d_mdp
.d_qtype
);
1354 for (const auto& dr
: spoofed
) {
1356 handleRPZCustom(dr
, QType(dc
->d_mdp
.d_qtype
), sr
, res
, ret
);
1363 if(res
== PolicyDecision::DROP
) {
1364 g_stats
.policyDrops
++;
1367 if(tracedQuery
|| res
== -1 || res
== RCode::ServFail
|| pw
.getHeader()->rcode
== RCode::ServFail
)
1369 string
trace(sr
.getTrace());
1370 if(!trace
.empty()) {
1371 vector
<string
> lines
;
1372 boost::split(lines
, trace
, boost::is_any_of("\n"));
1373 for(const string
& line
: lines
) {
1375 g_log
<<Logger::Warning
<< line
<< endl
;
1381 pw
.getHeader()->rcode
=RCode::ServFail
;
1382 // no commit here, because no record
1383 g_stats
.servFails
++;
1386 pw
.getHeader()->rcode
=res
;
1388 // Does the validation mode or query demand validation?
1389 if(!shouldNotValidate
&& sr
.isDNSSECValidationRequested()) {
1392 g_log
<<Logger::Warning
<<"Starting validation of answer to "<<dc
->d_mdp
.d_qname
<<"|"<<QType(dc
->d_mdp
.d_qtype
).getName()<<" for "<<dc
->getRemote()<<endl
;
1395 auto state
= sr
.getValidationState();
1397 if(state
== Secure
) {
1399 g_log
<<Logger::Warning
<<"Answer to "<<dc
->d_mdp
.d_qname
<<"|"<<QType(dc
->d_mdp
.d_qtype
).getName()<<" for "<<dc
->getRemote()<<" validates correctly"<<endl
;
1402 // Is the query source interested in the value of the ad-bit?
1403 if (dc
->d_mdp
.d_header
.ad
|| DNSSECOK
)
1404 pw
.getHeader()->ad
=1;
1406 else if(state
== Insecure
) {
1408 g_log
<<Logger::Warning
<<"Answer to "<<dc
->d_mdp
.d_qname
<<"|"<<QType(dc
->d_mdp
.d_qtype
).getName()<<" for "<<dc
->getRemote()<<" validates as Insecure"<<endl
;
1411 pw
.getHeader()->ad
=0;
1413 else if(state
== Bogus
) {
1415 t_bogusremotes
->push_back(dc
->d_source
);
1416 if(t_bogusqueryring
)
1417 t_bogusqueryring
->push_back(make_pair(dc
->d_mdp
.d_qname
, dc
->d_mdp
.d_qtype
));
1418 if(g_dnssecLogBogus
|| sr
.doLog() || g_dnssecmode
== DNSSECMode::ValidateForLog
) {
1419 g_log
<<Logger::Warning
<<"Answer to "<<dc
->d_mdp
.d_qname
<<"|"<<QType(dc
->d_mdp
.d_qtype
).getName()<<" for "<<dc
->getRemote()<<" validates as Bogus"<<endl
;
1422 // Does the query or validation mode sending out a SERVFAIL on validation errors?
1423 if(!pw
.getHeader()->cd
&& (g_dnssecmode
== DNSSECMode::ValidateAll
|| dc
->d_mdp
.d_header
.ad
|| DNSSECOK
)) {
1425 g_log
<<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
;
1428 pw
.getHeader()->rcode
=RCode::ServFail
;
1432 g_log
<<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
;
1437 catch(ImmediateServFailException
&e
) {
1438 if(g_logCommonErrors
)
1439 g_log
<<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
;
1440 pw
.getHeader()->rcode
=RCode::ServFail
;
1446 orderAndShuffle(ret
);
1447 if(auto sl
= luaconfsLocal
->sortlist
.getOrderCmp(dc
->d_source
)) {
1448 stable_sort(ret
.begin(), ret
.end(), *sl
);
1449 variableAnswer
=true;
1453 bool needCommit
= false;
1454 for(auto i
=ret
.cbegin(); i
!=ret
.cend(); ++i
) {
1456 ( i
->d_type
== QType::NSEC3
||
1458 ( i
->d_type
== QType::RRSIG
|| i
->d_type
==QType::NSEC
) &&
1460 ( dc
->d_mdp
.d_qtype
!= i
->d_type
&& dc
->d_mdp
.d_qtype
!= QType::ANY
) ||
1461 i
->d_place
!= DNSResourceRecord::ANSWER
1469 if (!addRecordToPacket(pw
, *i
, minTTL
, dc
->d_ttlCap
, maxanswersize
)) {
1478 udr
= udrCheckUniqueDNSRecord(dc
->d_mdp
.d_qname
, dc
->d_mdp
.d_qtype
, *i
);
1482 #endif /* NOD ENABLED */
1484 #ifdef HAVE_PROTOBUF
1485 if (t_protobufServers
) {
1487 pbMessage
->addRR(*i
, luaconfsLocal
->protobufExportConfig
.exportTypes
, udr
);
1489 pbMessage
->addRR(*i
, luaconfsLocal
->protobufExportConfig
.exportTypes
);
1490 #endif /* NOD_ENABLED */
1499 if(g_useIncomingECS
&& dc
->d_ecsFound
&& !sr
.wasVariable() && !variableAnswer
) {
1500 // cerr<<"Stuffing in a 0 scope because answer is static"<<endl;
1502 eo
.source
= dc
->d_ednssubnet
.source
;
1505 sa
.sin4
.sin_family
= eo
.source
.getNetwork().sin4
.sin_family
;
1506 eo
.scope
= Netmask(sa
, 0);
1508 returnedEdnsOptions
.push_back(make_pair(EDNSOptionCode::ECS
, makeEDNSSubnetOptsString(eo
)));
1512 /* we try to add the EDNS OPT RR even for truncated answers,
1514 "The minimal response MUST be the DNS header, question section, and an
1515 OPT record. This MUST also occur when a truncated response (using
1516 the DNS header's TC bit) is returned."
1518 pw
.addOpt(512, ednsExtRCode
, DNSSECOK
? EDNSOpts::DNSSECOK
: 0, returnedEdnsOptions
);
1522 g_rs
.submitResponse(dc
->d_mdp
.d_qtype
, packet
.size(), !dc
->d_tcp
);
1523 updateResponseStats(res
, dc
->d_source
, packet
.size(), &dc
->d_mdp
.d_qname
, dc
->d_mdp
.d_qtype
);
1527 if (nodCheckNewDomain(dc
->d_mdp
.d_qname
))
1530 #endif /* NOD_ENABLED */
1531 #ifdef HAVE_PROTOBUF
1532 if (t_protobufServers
&& logResponse
&& !(luaconfsLocal
->protobufExportConfig
.taggedOnly
&& (!appliedPolicy
.d_name
|| appliedPolicy
.d_name
->empty()) && dc
->d_policyTags
.empty())) {
1533 pbMessage
->setBytes(packet
.size());
1534 pbMessage
->setResponseCode(pw
.getHeader()->rcode
);
1535 if (appliedPolicy
.d_name
) {
1536 pbMessage
->setAppliedPolicy(*appliedPolicy
.d_name
);
1537 pbMessage
->setAppliedPolicyType(appliedPolicy
.d_type
);
1539 pbMessage
->setPolicyTags(dc
->d_policyTags
);
1540 pbMessage
->setQueryTime(dc
->d_now
.tv_sec
, dc
->d_now
.tv_usec
);
1541 pbMessage
->setRequestorId(dq
.requestorId
);
1542 pbMessage
->setDeviceId(dq
.deviceId
);
1546 pbMessage
->setNOD(true);
1547 pbMessage
->addPolicyTag(g_nod_pbtag
);
1550 pbMessage
->addPolicyTag(g_udr_pbtag
);
1553 #endif /* NOD_ENABLED */
1554 protobufLogResponse(*pbMessage
);
1557 pbMessage
->setNOD(false);
1558 pbMessage
->clearUDR();
1560 pbMessage
->removePolicyTag(g_nod_pbtag
);
1562 pbMessage
->removePolicyTag(g_udr_pbtag
);
1564 #endif /* NOD_ENABLED */
1571 fillMSGHdr(&msgh
, &iov
, cbuf
, 0, (char*)&*packet
.begin(), packet
.size(), &dc
->d_remote
);
1572 msgh
.msg_control
=NULL
;
1574 if(g_fromtosockets
.count(dc
->d_socket
)) {
1575 addCMsgSrcAddr(&msgh
, cbuf
, &dc
->d_local
, 0);
1577 if(sendmsg(dc
->d_socket
, &msgh
, 0) < 0 && g_logCommonErrors
)
1578 g_log
<<Logger::Warning
<<"Sending UDP reply to client "<<dc
->getRemote()<<" failed with: "<<strerror(errno
)<<endl
;
1580 if(variableAnswer
|| sr
.wasVariable()) {
1581 g_stats
.variableResponses
++;
1583 if(!SyncRes::s_nopacketcache
&& !variableAnswer
&& !sr
.wasVariable() ) {
1584 t_packetCache
->insertResponsePacket(dc
->d_tag
, dc
->d_qhash
, std::move(dc
->d_query
), dc
->d_mdp
.d_qname
, dc
->d_mdp
.d_qtype
, dc
->d_mdp
.d_qclass
,
1585 string((const char*)&*packet
.begin(), packet
.size()),
1587 pw
.getHeader()->rcode
== RCode::ServFail
? SyncRes::s_packetcacheservfailttl
:
1588 min(minTTL
,SyncRes::s_packetcachettl
),
1592 std::move(pbMessage
));
1594 // else cerr<<"Not putting in packet cache: "<<sr.wasVariable()<<endl;
1598 buf
[0]=packet
.size()/256;
1599 buf
[1]=packet
.size()%256;
1601 Utility::iovec iov
[2];
1603 iov
[0].iov_base
=(void*)buf
; iov
[0].iov_len
=2;
1604 iov
[1].iov_base
=(void*)&*packet
.begin(); iov
[1].iov_len
= packet
.size();
1606 int wret
=Utility::writev(dc
->d_socket
, iov
, 2);
1610 g_log
<<Logger::Error
<<"EOF writing TCP answer to "<<dc
->getRemote()<<endl
;
1612 g_log
<<Logger::Error
<<"Error writing TCP answer to "<<dc
->getRemote()<<": "<< strerror(errno
) <<endl
;
1613 else if((unsigned int)wret
!= 2 + packet
.size())
1614 g_log
<<Logger::Error
<<"Oops, partial answer sent to "<<dc
->getRemote()<<" for "<<dc
->d_mdp
.d_qname
<<" (size="<< (2 + packet
.size()) <<", sent "<<wret
<<")"<<endl
;
1618 // update tcp connection status, either by closing or moving to 'BYTE0'
1621 // no need to remove us from FDM, we weren't there
1625 dc
->d_tcpConnection
->queriesCount
++;
1626 if (g_tcpMaxQueriesPerConn
&& dc
->d_tcpConnection
->queriesCount
>= g_tcpMaxQueriesPerConn
) {
1630 dc
->d_tcpConnection
->state
=TCPConnection::BYTE0
;
1631 Utility::gettimeofday(&g_now
, 0); // needs to be updated
1632 t_fdm
->addReadFD(dc
->d_socket
, handleRunningTCPQuestion
, dc
->d_tcpConnection
);
1633 t_fdm
->setReadTTD(dc
->d_socket
, g_now
, g_tcpTimeout
);
1637 float spent
=makeFloat(sr
.getNow()-dc
->d_now
);
1639 g_log
<<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
);
1640 g_log
<<"': "<<ntohs(pw
.getHeader()->ancount
)<<" answers, "<<ntohs(pw
.getHeader()->arcount
)<<" additional, took "<<sr
.d_outqueries
<<" packets, "<<
1641 sr
.d_totUsec
/1000.0<<" netw ms, "<< spent
*1000.0<<" tot ms, "<<
1642 sr
.d_throttledqueries
<<" throttled, "<<sr
.d_timeouts
<<" timeouts, "<<sr
.d_tcpoutqueries
<<" tcp connections, rcode="<< res
;
1644 if(!shouldNotValidate
&& sr
.isDNSSECValidationRequested()) {
1645 g_log
<< ", dnssec="<<vStates
[sr
.getValidationState()];
1652 if (sr
.d_outqueries
|| sr
.d_authzonequeries
) {
1653 t_RC
->cacheMisses
++;
1660 g_stats
.answers0_1
++;
1661 else if(spent
< 0.010)
1662 g_stats
.answers1_10
++;
1663 else if(spent
< 0.1)
1664 g_stats
.answers10_100
++;
1665 else if(spent
< 1.0)
1666 g_stats
.answers100_1000
++;
1668 g_stats
.answersSlow
++;
1670 uint64_t newLat
=(uint64_t)(spent
*1000000);
1671 newLat
= min(newLat
,(uint64_t)(((uint64_t) g_networkTimeoutMsec
)*1000)); // outliers of several minutes exist..
1672 g_stats
.avgLatencyUsec
=(1-1.0/g_latencyStatSize
)*g_stats
.avgLatencyUsec
+ (float)newLat
/g_latencyStatSize
;
1673 // no worries, we do this for packet cache hits elsewhere
1675 auto ourtime
= 1000.0*spent
-sr
.d_totUsec
/1000.0; // in msec
1677 g_stats
.ourtime0_1
++;
1678 else if(ourtime
< 2)
1679 g_stats
.ourtime1_2
++;
1680 else if(ourtime
< 4)
1681 g_stats
.ourtime2_4
++;
1682 else if(ourtime
< 8)
1683 g_stats
.ourtime4_8
++;
1684 else if(ourtime
< 16)
1685 g_stats
.ourtime8_16
++;
1686 else if(ourtime
< 32)
1687 g_stats
.ourtime16_32
++;
1689 // cerr<<"SLOW: "<<ourtime<<"ms -> "<<dc->d_mdp.d_qname<<"|"<<DNSRecordContent::NumberToType(dc->d_mdp.d_qtype)<<endl;
1690 g_stats
.ourtimeSlow
++;
1692 if(ourtime
>= 0.0) {
1693 newLat
=ourtime
*1000; // usec
1694 g_stats
.avgLatencyOursUsec
=(1-1.0/g_latencyStatSize
)*g_stats
.avgLatencyOursUsec
+ (float)newLat
/g_latencyStatSize
;
1696 // cout<<dc->d_mdp.d_qname<<"\t"<<MT->getUsec()<<"\t"<<sr.d_outqueries<<endl;
1698 catch(PDNSException
&ae
) {
1699 g_log
<<Logger::Error
<<"startDoResolve problem "<<makeLoginfo(dc
)<<": "<<ae
.reason
<<endl
;
1701 catch(const MOADNSException
&mde
) {
1702 g_log
<<Logger::Error
<<"DNS parser error "<<makeLoginfo(dc
) <<": "<<dc
->d_mdp
.d_qname
<<", "<<mde
.what()<<endl
;
1704 catch(std::exception
& e
) {
1705 g_log
<<Logger::Error
<<"STL error "<< makeLoginfo(dc
)<<": "<<e
.what();
1707 // Luawrapper nests the exception from Lua, so we unnest it here
1709 std::rethrow_if_nested(e
);
1710 } catch(const std::exception
& ne
) {
1711 g_log
<<". Extra info: "<<ne
.what();
1717 g_log
<<Logger::Error
<<"Any other exception in a resolver context "<< makeLoginfo(dc
) <<endl
;
1720 g_stats
.maxMThreadStackUsage
= max(MT
->getMaxStackUsage(), g_stats
.maxMThreadStackUsage
);
1723 static void makeControlChannelSocket(int processNum
=-1)
1725 string sockname
=::arg()["socket-dir"]+"/"+s_programname
;
1727 sockname
+= "."+std::to_string(processNum
);
1728 sockname
+=".controlsocket";
1729 s_rcc
.listen(sockname
);
1734 if (!::arg().isEmpty("socket-group"))
1735 sockgroup
=::arg().asGid("socket-group");
1736 if (!::arg().isEmpty("socket-owner"))
1737 sockowner
=::arg().asUid("socket-owner");
1739 if (sockgroup
> -1 || sockowner
> -1) {
1740 if(chown(sockname
.c_str(), sockowner
, sockgroup
) < 0) {
1741 unixDie("Failed to chown control socket");
1745 // do mode change if socket-mode is given
1746 if(!::arg().isEmpty("socket-mode")) {
1747 mode_t sockmode
=::arg().asMode("socket-mode");
1748 if(chmod(sockname
.c_str(), sockmode
) < 0) {
1749 unixDie("Failed to chmod control socket");
1754 static void getQNameAndSubnet(const std::string
& question
, DNSName
* dnsname
, uint16_t* qtype
, uint16_t* qclass
,
1755 bool& foundECS
, EDNSSubnetOpts
* ednssubnet
, EDNSOptionViewMap
* options
,
1756 bool& foundXPF
, ComboAddress
* xpfSource
, ComboAddress
* xpfDest
)
1758 const bool lookForXPF
= xpfSource
!= nullptr && g_xpfRRCode
!= 0;
1759 const bool lookForECS
= ednssubnet
!= nullptr;
1760 const struct dnsheader
* dh
= reinterpret_cast<const struct dnsheader
*>(question
.c_str());
1761 size_t questionLen
= question
.length();
1762 unsigned int consumed
=0;
1763 *dnsname
=DNSName(question
.c_str(), questionLen
, sizeof(dnsheader
), false, qtype
, qclass
, &consumed
);
1765 size_t pos
= sizeof(dnsheader
)+consumed
+4;
1766 const size_t headerSize
= /* root */ 1 + sizeof(dnsrecordheader
);
1767 const uint16_t arcount
= ntohs(dh
->arcount
);
1769 for (uint16_t arpos
= 0; arpos
< arcount
&& questionLen
> (pos
+ headerSize
) && ((lookForECS
&& !foundECS
) || (lookForXPF
&& !foundXPF
)); arpos
++) {
1770 if (question
.at(pos
) != 0) {
1771 /* not an OPT or a XPF, bye. */
1776 const dnsrecordheader
* drh
= reinterpret_cast<const dnsrecordheader
*>(&question
.at(pos
));
1777 pos
+= sizeof(dnsrecordheader
);
1779 if (pos
>= questionLen
) {
1783 /* OPT root label (1) followed by type (2) */
1784 if(lookForECS
&& ntohs(drh
->d_type
) == QType::OPT
) {
1786 char* ecsStart
= nullptr;
1788 /* we need to pass the record len */
1789 int res
= getEDNSOption(const_cast<char*>(reinterpret_cast<const char*>(&question
.at(pos
- sizeof(drh
->d_clen
)))), questionLen
- pos
+ sizeof(drh
->d_clen
), EDNSOptionCode::ECS
, &ecsStart
, &ecsLen
);
1790 if (res
== 0 && ecsLen
> 4) {
1792 if(getEDNSSubnetOptsFromString(ecsStart
+ 4, ecsLen
- 4, &eso
)) {
1799 /* we need to pass the record len */
1800 int res
= getEDNSOptions(reinterpret_cast<const char*>(&question
.at(pos
-sizeof(drh
->d_clen
))), questionLen
- pos
+ (sizeof(drh
->d_clen
)), *options
);
1802 const auto& it
= options
->find(EDNSOptionCode::ECS
);
1803 if (it
!= options
->end() && !it
->second
.values
.empty() && it
->second
.values
.at(0).content
!= nullptr && it
->second
.values
.at(0).size
> 0) {
1805 if(getEDNSSubnetOptsFromString(it
->second
.values
.at(0).content
, it
->second
.values
.at(0).size
, &eso
)) {
1813 else if (lookForXPF
&& ntohs(drh
->d_type
) == g_xpfRRCode
&& ntohs(drh
->d_class
) == QClass::IN
&& drh
->d_ttl
== 0) {
1814 if ((questionLen
- pos
) < ntohs(drh
->d_clen
)) {
1818 foundXPF
= parseXPFPayload(reinterpret_cast<const char*>(&question
.at(pos
)), ntohs(drh
->d_clen
), *xpfSource
, xpfDest
);
1821 pos
+= ntohs(drh
->d_clen
);
1825 static void handleRunningTCPQuestion(int fd
, FDMultiplexer::funcparam_t
& var
)
1827 shared_ptr
<TCPConnection
> conn
=any_cast
<shared_ptr
<TCPConnection
> >(var
);
1829 if(conn
->state
==TCPConnection::BYTE0
) {
1830 ssize_t bytes
=recv(conn
->getFD(), &conn
->data
[0], 2, 0);
1832 conn
->state
=TCPConnection::BYTE1
;
1834 conn
->qlen
=(((unsigned char)conn
->data
[0]) << 8)+ (unsigned char)conn
->data
[1];
1835 conn
->data
.resize(conn
->qlen
);
1837 conn
->state
=TCPConnection::GETQUESTION
;
1839 if(!bytes
|| bytes
< 0) {
1840 t_fdm
->removeReadFD(fd
);
1844 else if(conn
->state
==TCPConnection::BYTE1
) {
1845 ssize_t bytes
=recv(conn
->getFD(), &conn
->data
[1], 1, 0);
1847 conn
->state
=TCPConnection::GETQUESTION
;
1848 conn
->qlen
=(((unsigned char)conn
->data
[0]) << 8)+ (unsigned char)conn
->data
[1];
1849 conn
->data
.resize(conn
->qlen
);
1852 if(!bytes
|| bytes
< 0) {
1853 if(g_logCommonErrors
)
1854 g_log
<<Logger::Error
<<"TCP client "<< conn
->d_remote
.toStringWithPort() <<" disconnected after first byte"<<endl
;
1855 t_fdm
->removeReadFD(fd
);
1859 else if(conn
->state
==TCPConnection::GETQUESTION
) {
1860 ssize_t bytes
=recv(conn
->getFD(), &conn
->data
[conn
->bytesread
], conn
->qlen
- conn
->bytesread
, 0);
1861 if(!bytes
|| bytes
< 0 || bytes
> std::numeric_limits
<std::uint16_t>::max()) {
1862 if(g_logCommonErrors
) {
1863 g_log
<<Logger::Error
<<"TCP client "<< conn
->d_remote
.toStringWithPort() <<" disconnected while reading question body"<<endl
;
1865 t_fdm
->removeReadFD(fd
);
1868 conn
->bytesread
+=(uint16_t)bytes
;
1869 if(conn
->bytesread
==conn
->qlen
) {
1870 t_fdm
->removeReadFD(fd
); // should no longer awake ourselves when there is data to read
1872 std::unique_ptr
<DNSComboWriter
> dc
;
1874 dc
=std::unique_ptr
<DNSComboWriter
>(new DNSComboWriter(conn
->data
, g_now
));
1876 catch(const MOADNSException
&mde
) {
1877 g_stats
.clientParseError
++;
1878 if(g_logCommonErrors
)
1879 g_log
<<Logger::Error
<<"Unable to parse packet from TCP client "<< conn
->d_remote
.toStringWithPort() <<endl
;
1882 dc
->d_tcpConnection
= conn
; // carry the torch
1883 dc
->setSocket(conn
->getFD()); // this is the only time a copy is made of the actual fd
1885 dc
->setRemote(conn
->d_remote
);
1886 dc
->setSource(conn
->d_remote
);
1889 dest
.sin4
.sin_family
= conn
->d_remote
.sin4
.sin_family
;
1890 socklen_t len
= dest
.getSocklen();
1891 getsockname(conn
->getFD(), (sockaddr
*)&dest
, &len
); // if this fails, we're ok with it
1893 dc
->setDestination(dest
);
1897 bool needECS
= false;
1898 bool needXPF
= g_XPFAcl
.match(conn
->d_remote
);
1901 bool logQuery
= false;
1902 #ifdef HAVE_PROTOBUF
1903 auto luaconfsLocal
= g_luaconfs
.getLocal();
1904 if (checkProtobufExport(luaconfsLocal
)) {
1907 logQuery
= t_protobufServers
&& luaconfsLocal
->protobufExportConfig
.logQueries
;
1910 if(needECS
|| needXPF
|| (t_pdl
&& (t_pdl
->d_gettag_ffi
|| t_pdl
->d_gettag
))) {
1913 EDNSOptionViewMap ednsOptions
;
1914 bool xpfFound
= false;
1915 dc
->d_ecsParsed
= true;
1916 dc
->d_ecsFound
= false;
1917 getQNameAndSubnet(conn
->data
, &qname
, &qtype
, &qclass
,
1918 dc
->d_ecsFound
, &dc
->d_ednssubnet
, g_gettagNeedsEDNSOptions
? &ednsOptions
: nullptr,
1919 xpfFound
, needXPF
? &dc
->d_source
: nullptr, needXPF
? &dc
->d_destination
: nullptr);
1923 if (t_pdl
->d_gettag_ffi
) {
1924 dc
->d_tag
= t_pdl
->gettag_ffi(dc
->d_source
, dc
->d_ednssubnet
.source
, dc
->d_destination
, qname
, qtype
, &dc
->d_policyTags
, dc
->d_data
, ednsOptions
, true, requestorId
, deviceId
, dc
->d_ttlCap
, dc
->d_variable
, logQuery
);
1926 else if (t_pdl
->d_gettag
) {
1927 dc
->d_tag
= t_pdl
->gettag(dc
->d_source
, dc
->d_ednssubnet
.source
, dc
->d_destination
, qname
, qtype
, &dc
->d_policyTags
, dc
->d_data
, ednsOptions
, true, requestorId
, deviceId
);
1930 catch(const std::exception
& e
) {
1931 if(g_logCommonErrors
)
1932 g_log
<<Logger::Warning
<<"Error parsing a query packet qname='"<<qname
<<"' for tag determination, setting tag=0: "<<e
.what()<<endl
;
1936 catch(const std::exception
& e
)
1938 if(g_logCommonErrors
)
1939 g_log
<<Logger::Warning
<<"Error parsing a query packet for tag determination, setting tag=0: "<<e
.what()<<endl
;
1943 const struct dnsheader
* dh
= reinterpret_cast<const struct dnsheader
*>(&conn
->data
[0]);
1945 #ifdef HAVE_PROTOBUF
1946 if(t_protobufServers
|| t_outgoingProtobufServers
) {
1947 dc
->d_requestorId
= requestorId
;
1948 dc
->d_deviceId
= deviceId
;
1949 dc
->d_uuid
= getUniqueID();
1952 if(t_protobufServers
) {
1955 if (logQuery
&& !(luaconfsLocal
->protobufExportConfig
.taggedOnly
&& dc
->d_policyTags
.empty())) {
1956 protobufLogQuery(luaconfsLocal
->protobufMaskV4
, luaconfsLocal
->protobufMaskV6
, dc
->d_uuid
, dc
->d_source
, dc
->d_destination
, dc
->d_ednssubnet
.source
, true, dh
->id
, conn
->qlen
, qname
, qtype
, qclass
, dc
->d_policyTags
, dc
->d_requestorId
, dc
->d_deviceId
);
1959 catch(std::exception
& e
) {
1960 if(g_logCommonErrors
)
1961 g_log
<<Logger::Warning
<<"Error parsing a TCP query packet for edns subnet: "<<e
.what()<<endl
;
1966 if(t_pdl
->ipfilter(dc
->d_source
, dc
->d_destination
, *dh
)) {
1968 g_log
<<Logger::Notice
<<t_id
<<" ["<<MT
->getTid()<<"/"<<MT
->numProcesses()<<"] DROPPED TCP question from "<<dc
->d_source
.toStringWithPort()<<(dc
->d_source
!= dc
->d_remote
? " (via "+dc
->d_remote
.toStringWithPort()+")" : "")<<" based on policy"<<endl
;
1969 g_stats
.policyDrops
++;
1974 if(dc
->d_mdp
.d_header
.qr
) {
1975 g_stats
.ignoredCount
++;
1976 if(g_logCommonErrors
) {
1977 g_log
<<Logger::Error
<<"Ignoring answer from TCP client "<< dc
->getRemote() <<" on server socket!"<<endl
;
1981 if(dc
->d_mdp
.d_header
.opcode
) {
1982 g_stats
.ignoredCount
++;
1983 if(g_logCommonErrors
) {
1984 g_log
<<Logger::Error
<<"Ignoring non-query opcode from TCP client "<< dc
->getRemote() <<" on server socket!"<<endl
;
1988 else if (dh
->qdcount
== 0) {
1989 g_stats
.emptyQueriesCount
++;
1990 if(g_logCommonErrors
) {
1991 g_log
<<Logger::Error
<<"Ignoring empty (qdcount == 0) query from "<< dc
->getRemote() <<" on server socket!"<<endl
;
1997 ++g_stats
.tcpqcounter
;
1998 MT
->makeThread(startDoResolve
, dc
.release()); // deletes dc, will set state to BYTE0 again
2005 //! Handle new incoming TCP connection
2006 static void handleNewTCPQuestion(int fd
, FDMultiplexer::funcparam_t
& )
2009 socklen_t addrlen
=sizeof(addr
);
2010 int newsock
=accept(fd
, (struct sockaddr
*)&addr
, &addrlen
);
2012 if(MT
->numProcesses() > g_maxMThreads
) {
2013 g_stats
.overCapacityDrops
++;
2015 closesocket(newsock
);
2017 catch(const PDNSException
& e
) {
2018 g_log
<<Logger::Error
<<"Error closing TCP socket after an over capacity drop: "<<e
.reason
<<endl
;
2024 t_remotes
->push_back(addr
);
2025 if(t_allowFrom
&& !t_allowFrom
->match(&addr
)) {
2027 g_log
<<Logger::Error
<<"["<<MT
->getTid()<<"] dropping TCP query from "<<addr
.toString()<<", address not matched by allow-from"<<endl
;
2029 g_stats
.unauthorizedTCP
++;
2031 closesocket(newsock
);
2033 catch(const PDNSException
& e
) {
2034 g_log
<<Logger::Error
<<"Error closing TCP socket after an ACL drop: "<<e
.reason
<<endl
;
2038 if(g_maxTCPPerClient
&& t_tcpClientCounts
->count(addr
) && (*t_tcpClientCounts
)[addr
] >= g_maxTCPPerClient
) {
2039 g_stats
.tcpClientOverflow
++;
2041 closesocket(newsock
); // don't call TCPConnection::closeAndCleanup here - did not enter it in the counts yet!
2043 catch(const PDNSException
& e
) {
2044 g_log
<<Logger::Error
<<"Error closing TCP socket after an overflow drop: "<<e
.reason
<<endl
;
2049 setNonBlocking(newsock
);
2050 std::shared_ptr
<TCPConnection
> tc
= std::make_shared
<TCPConnection
>(newsock
, addr
);
2051 tc
->state
=TCPConnection::BYTE0
;
2053 t_fdm
->addReadFD(tc
->getFD(), handleRunningTCPQuestion
, tc
);
2056 Utility::gettimeofday(&now
, 0);
2057 t_fdm
->setReadTTD(tc
->getFD(), now
, g_tcpTimeout
);
2061 static string
* doProcessUDPQuestion(const std::string
& question
, const ComboAddress
& fromaddr
, const ComboAddress
& destaddr
, struct timeval tv
, int fd
)
2063 gettimeofday(&g_now
, 0);
2064 struct timeval diff
= g_now
- tv
;
2065 double delta
=(diff
.tv_sec
*1000 + diff
.tv_usec
/1000.0);
2067 if(tv
.tv_sec
&& delta
> 1000.0) {
2068 g_stats
.tooOldDrops
++;
2073 if(fromaddr
.sin4
.sin_family
==AF_INET6
)
2074 g_stats
.ipv6qcounter
++;
2077 const struct dnsheader
* dh
= (struct dnsheader
*)question
.c_str();
2078 unsigned int ctag
=0;
2080 bool needECS
= false;
2081 bool needXPF
= g_XPFAcl
.match(fromaddr
);
2082 std::vector
<std::string
> policyTags
;
2083 LuaContext::LuaObject data
;
2084 ComboAddress source
= fromaddr
;
2085 ComboAddress destination
= destaddr
;
2088 bool logQuery
= false;
2089 #ifdef HAVE_PROTOBUF
2090 boost::uuids::uuid uniqueId
;
2091 auto luaconfsLocal
= g_luaconfs
.getLocal();
2092 if (checkProtobufExport(luaconfsLocal
)) {
2093 uniqueId
= getUniqueID();
2095 } else if (checkOutgoingProtobufExport(luaconfsLocal
)) {
2096 uniqueId
= getUniqueID();
2098 logQuery
= t_protobufServers
&& luaconfsLocal
->protobufExportConfig
.logQueries
;
2099 bool logResponse
= t_protobufServers
&& luaconfsLocal
->protobufExportConfig
.logResponses
;
2101 EDNSSubnetOpts ednssubnet
;
2102 bool ecsFound
= false;
2103 bool ecsParsed
= false;
2104 uint16_t ecsBegin
= 0;
2105 uint16_t ecsEnd
= 0;
2106 uint32_t ttlCap
= std::numeric_limits
<uint32_t>::max();
2107 bool variable
= false;
2113 bool qnameParsed
=false;
2116 static uint64_t last=0;
2118 g_mtracer->clearAllocators();
2119 cout<<g_mtracer->getAllocs()-last<<" "<<g_mtracer->getNumOut()<<" -- BEGIN TRACE"<<endl;
2120 last=g_mtracer->getAllocs();
2121 cout<<g_mtracer->topAllocatorsString()<<endl;
2122 g_mtracer->clearAllocators();
2126 if(needECS
|| needXPF
|| (t_pdl
&& (t_pdl
->d_gettag
|| t_pdl
->d_gettag_ffi
))) {
2128 EDNSOptionViewMap ednsOptions
;
2129 bool xpfFound
= false;
2133 getQNameAndSubnet(question
, &qname
, &qtype
, &qclass
,
2134 ecsFound
, &ednssubnet
, g_gettagNeedsEDNSOptions
? &ednsOptions
: nullptr,
2135 xpfFound
, needXPF
? &source
: nullptr, needXPF
? &destination
: nullptr);
2142 if (t_pdl
->d_gettag_ffi
) {
2143 ctag
= t_pdl
->gettag_ffi(source
, ednssubnet
.source
, destination
, qname
, qtype
, &policyTags
, data
, ednsOptions
, false, requestorId
, deviceId
, ttlCap
, variable
, logQuery
);
2145 else if (t_pdl
->d_gettag
) {
2146 ctag
= t_pdl
->gettag(source
, ednssubnet
.source
, destination
, qname
, qtype
, &policyTags
, data
, ednsOptions
, false, requestorId
, deviceId
);
2149 catch(const std::exception
& e
) {
2150 if(g_logCommonErrors
)
2151 g_log
<<Logger::Warning
<<"Error parsing a query packet qname='"<<qname
<<"' for tag determination, setting tag=0: "<<e
.what()<<endl
;
2155 catch(const std::exception
& e
)
2157 if(g_logCommonErrors
)
2158 g_log
<<Logger::Warning
<<"Error parsing a query packet for tag determination, setting tag=0: "<<e
.what()<<endl
;
2162 bool cacheHit
= false;
2163 boost::optional
<RecProtoBufMessage
> pbMessage(boost::none
);
2164 #ifdef HAVE_PROTOBUF
2165 if (t_protobufServers
) {
2166 pbMessage
= RecProtoBufMessage(DNSProtoBufMessage::DNSProtoBufMessageType::Response
);
2167 pbMessage
->setServerIdentity(SyncRes::s_serverID
);
2168 if (logQuery
&& !(luaconfsLocal
->protobufExportConfig
.taggedOnly
&& policyTags
.empty())) {
2169 protobufLogQuery(luaconfsLocal
->protobufMaskV4
, luaconfsLocal
->protobufMaskV6
, uniqueId
, source
, destination
, ednssubnet
.source
, false, dh
->id
, question
.size(), qname
, qtype
, qclass
, policyTags
, requestorId
, deviceId
);
2172 #endif /* HAVE_PROTOBUF */
2174 /* It might seem like a good idea to skip the packet cache lookup if we know that the answer is not cacheable,
2175 but it means that the hash would not be computed. If some script decides at a later time to mark back the answer
2176 as cacheable we would cache it with a wrong tag, so better safe than sorry. */
2179 cacheHit
= (!SyncRes::s_nopacketcache
&& t_packetCache
->getResponsePacket(ctag
, question
, qname
, qtype
, qclass
, g_now
.tv_sec
, &response
, &age
, &valState
, &qhash
, &ecsBegin
, &ecsEnd
, pbMessage
? &(*pbMessage
) : nullptr));
2182 cacheHit
= (!SyncRes::s_nopacketcache
&& t_packetCache
->getResponsePacket(ctag
, question
, qname
, &qtype
, &qclass
, g_now
.tv_sec
, &response
, &age
, &valState
, &qhash
, &ecsBegin
, &ecsEnd
, pbMessage
? &(*pbMessage
) : nullptr));
2186 if(valState
== Bogus
) {
2188 t_bogusremotes
->push_back(source
);
2189 if(t_bogusqueryring
)
2190 t_bogusqueryring
->push_back(make_pair(qname
, qtype
));
2193 #ifdef HAVE_PROTOBUF
2194 if(t_protobufServers
&& logResponse
&& !(luaconfsLocal
->protobufExportConfig
.taggedOnly
&& pbMessage
->getAppliedPolicy().empty() && pbMessage
->getPolicyTags().empty())) {
2195 Netmask
requestorNM(source
, source
.sin4
.sin_family
== AF_INET
? luaconfsLocal
->protobufMaskV4
: luaconfsLocal
->protobufMaskV6
);
2196 const ComboAddress
& requestor
= requestorNM
.getMaskedNetwork();
2197 pbMessage
->update(uniqueId
, &requestor
, &destination
, false, dh
->id
);
2198 pbMessage
->setEDNSSubnet(ednssubnet
.source
, ednssubnet
.source
.isIpv4() ? luaconfsLocal
->protobufMaskV4
: luaconfsLocal
->protobufMaskV6
);
2199 pbMessage
->setQueryTime(g_now
.tv_sec
, g_now
.tv_usec
);
2200 pbMessage
->setRequestorId(requestorId
);
2201 pbMessage
->setDeviceId(deviceId
);
2202 protobufLogResponse(*pbMessage
);
2204 #endif /* HAVE_PROTOBUF */
2206 g_log
<<Logger::Notice
<<t_id
<< " question answered from packet cache tag="<<ctag
<<" from "<<source
.toStringWithPort()<<(source
!= fromaddr
? " (via "+fromaddr
.toStringWithPort()+")" : "")<<endl
;
2208 g_stats
.packetCacheHits
++;
2209 SyncRes::s_queries
++;
2210 ageDNSPacket(response
, age
);
2214 fillMSGHdr(&msgh
, &iov
, cbuf
, 0, (char*)response
.c_str(), response
.length(), const_cast<ComboAddress
*>(&fromaddr
));
2215 msgh
.msg_control
=NULL
;
2217 if(g_fromtosockets
.count(fd
)) {
2218 addCMsgSrcAddr(&msgh
, cbuf
, &destaddr
, 0);
2220 if(sendmsg(fd
, &msgh
, 0) < 0 && g_logCommonErrors
)
2221 g_log
<<Logger::Warning
<<"Sending UDP reply to client "<<source
.toStringWithPort()<<(source
!= fromaddr
? " (via "+fromaddr
.toStringWithPort()+")" : "")<<" failed with: "<<strerror(errno
)<<endl
;
2223 if(response
.length() >= sizeof(struct dnsheader
)) {
2224 struct dnsheader tmpdh
;
2225 memcpy(&tmpdh
, response
.c_str(), sizeof(tmpdh
));
2226 updateResponseStats(tmpdh
.rcode
, source
, response
.length(), 0, 0);
2228 g_stats
.avgLatencyUsec
=(1-1.0/g_latencyStatSize
)*g_stats
.avgLatencyUsec
+ 0.0; // we assume 0 usec
2229 g_stats
.avgLatencyOursUsec
=(1-1.0/g_latencyStatSize
)*g_stats
.avgLatencyOursUsec
+ 0.0; // we assume 0 usec
2233 catch(std::exception
& e
) {
2234 g_log
<<Logger::Error
<<"Error processing or aging answer packet: "<<e
.what()<<endl
;
2239 if(t_pdl
->ipfilter(source
, destination
, *dh
)) {
2241 g_log
<<Logger::Notice
<<t_id
<<" ["<<MT
->getTid()<<"/"<<MT
->numProcesses()<<"] DROPPED question from "<<source
.toStringWithPort()<<(source
!= fromaddr
? " (via "+fromaddr
.toStringWithPort()+")" : "")<<" based on policy"<<endl
;
2242 g_stats
.policyDrops
++;
2247 if(MT
->numProcesses() > g_maxMThreads
) {
2249 g_log
<<Logger::Notice
<<t_id
<<" ["<<MT
->getTid()<<"/"<<MT
->numProcesses()<<"] DROPPED question from "<<source
.toStringWithPort()<<(source
!= fromaddr
? " (via "+fromaddr
.toStringWithPort()+")" : "")<<", over capacity"<<endl
;
2251 g_stats
.overCapacityDrops
++;
2255 auto dc
= std::unique_ptr
<DNSComboWriter
>(new DNSComboWriter(question
, g_now
, std::move(policyTags
), std::move(data
)));
2259 dc
->setRemote(fromaddr
);
2260 dc
->setSource(source
);
2261 dc
->setLocal(destaddr
);
2262 dc
->setDestination(destination
);
2264 dc
->d_ecsFound
= ecsFound
;
2265 dc
->d_ecsParsed
= ecsParsed
;
2266 dc
->d_ecsBegin
= ecsBegin
;
2267 dc
->d_ecsEnd
= ecsEnd
;
2268 dc
->d_ednssubnet
= ednssubnet
;
2269 dc
->d_ttlCap
= ttlCap
;
2270 dc
->d_variable
= variable
;
2271 #ifdef HAVE_PROTOBUF
2272 if (t_protobufServers
|| t_outgoingProtobufServers
) {
2273 dc
->d_uuid
= std::move(uniqueId
);
2275 dc
->d_requestorId
= requestorId
;
2276 dc
->d_deviceId
= deviceId
;
2279 MT
->makeThread(startDoResolve
, (void*) dc
.release()); // deletes dc
2284 static void handleNewUDPQuestion(int fd
, FDMultiplexer::funcparam_t
& var
)
2287 static const size_t maxIncomingQuerySize
= 512;
2288 static thread_local
std::string data
;
2289 ComboAddress fromaddr
;
2293 bool firstQuery
= true;
2295 for(size_t queriesCounter
= 0; queriesCounter
< s_maxUDPQueriesPerRound
; queriesCounter
++) {
2296 data
.resize(maxIncomingQuerySize
);
2297 fromaddr
.sin6
.sin6_family
=AF_INET6
; // this makes sure fromaddr is big enough
2298 fillMSGHdr(&msgh
, &iov
, cbuf
, sizeof(cbuf
), &data
[0], data
.size(), &fromaddr
);
2300 if((len
=recvmsg(fd
, &msgh
, 0)) >= 0) {
2304 if (static_cast<size_t>(len
) < sizeof(dnsheader
)) {
2305 g_stats
.ignoredCount
++;
2307 g_log
<<Logger::Error
<<"Ignoring too-short ("<<std::to_string(len
)<<") query from "<<fromaddr
.toString()<<endl
;
2312 if (msgh
.msg_flags
& MSG_TRUNC
) {
2313 g_stats
.truncatedDrops
++;
2315 g_log
<<Logger::Error
<<"Ignoring truncated query from "<<fromaddr
.toString()<<endl
;
2321 t_remotes
->push_back(fromaddr
);
2324 if(t_allowFrom
&& !t_allowFrom
->match(&fromaddr
)) {
2326 g_log
<<Logger::Error
<<"["<<MT
->getTid()<<"] dropping UDP query from "<<fromaddr
.toString()<<", address not matched by allow-from"<<endl
;
2329 g_stats
.unauthorizedUDP
++;
2332 BOOST_STATIC_ASSERT(offsetof(sockaddr_in
, sin_port
) == offsetof(sockaddr_in6
, sin6_port
));
2333 if(!fromaddr
.sin4
.sin_port
) { // also works for IPv6
2335 g_log
<<Logger::Error
<<"["<<MT
->getTid()<<"] dropping UDP query from "<<fromaddr
.toStringWithPort()<<", can't deal with port 0"<<endl
;
2338 g_stats
.clientParseError
++; // not quite the best place to put it, but needs to go somewhere
2343 data
.resize(static_cast<size_t>(len
));
2344 dnsheader
* dh
=(dnsheader
*)&data
[0];
2347 g_stats
.ignoredCount
++;
2348 if(g_logCommonErrors
) {
2349 g_log
<<Logger::Error
<<"Ignoring answer from "<<fromaddr
.toString()<<" on server socket!"<<endl
;
2352 else if(dh
->opcode
) {
2353 g_stats
.ignoredCount
++;
2354 if(g_logCommonErrors
) {
2355 g_log
<<Logger::Error
<<"Ignoring non-query opcode "<<dh
->opcode
<<" from "<<fromaddr
.toString()<<" on server socket!"<<endl
;
2358 else if (dh
->qdcount
== 0) {
2359 g_stats
.emptyQueriesCount
++;
2360 if(g_logCommonErrors
) {
2361 g_log
<<Logger::Error
<<"Ignoring empty (qdcount == 0) query from "<<fromaddr
.toString()<<" on server socket!"<<endl
;
2365 struct timeval tv
={0,0};
2366 HarvestTimestamp(&msgh
, &tv
);
2368 dest
.reset(); // this makes sure we ignore this address if not returned by recvmsg above
2369 auto loc
= rplookup(g_listenSocketsAddresses
, fd
);
2370 if(HarvestDestinationAddress(&msgh
, &dest
)) {
2371 // but.. need to get port too
2373 dest
.sin4
.sin_port
= loc
->sin4
.sin_port
;
2381 dest
.sin4
.sin_family
= fromaddr
.sin4
.sin_family
;
2382 socklen_t slen
= dest
.getSocklen();
2383 getsockname(fd
, (sockaddr
*)&dest
, &slen
); // if this fails, we're ok with it
2387 if(g_weDistributeQueries
) {
2388 distributeAsyncFunction(data
, boost::bind(doProcessUDPQuestion
, data
, fromaddr
, dest
, tv
, fd
));
2391 ++s_threadInfos
[t_id
].numberOfDistributedQueries
;
2392 doProcessUDPQuestion(data
, fromaddr
, dest
, tv
, fd
);
2396 catch(const MOADNSException
&mde
) {
2397 g_stats
.clientParseError
++;
2398 if(g_logCommonErrors
) {
2399 g_log
<<Logger::Error
<<"Unable to parse packet from remote UDP client "<<fromaddr
.toString() <<": "<<mde
.what()<<endl
;
2402 catch(const std::runtime_error
& e
) {
2403 g_stats
.clientParseError
++;
2404 if(g_logCommonErrors
) {
2405 g_log
<<Logger::Error
<<"Unable to parse packet from remote UDP client "<<fromaddr
.toString() <<": "<<e
.what()<<endl
;
2410 // cerr<<t_id<<" had error: "<<stringerror()<<endl;
2411 if(firstQuery
&& errno
== EAGAIN
) {
2412 g_stats
.noPacketError
++;
2420 static void makeTCPServerSockets(deferredAdd_t
& deferredAdds
, std::set
<int>& tcpSockets
)
2423 vector
<string
>locals
;
2424 stringtok(locals
,::arg()["local-address"]," ,");
2427 throw PDNSException("No local address specified");
2429 for(vector
<string
>::const_iterator i
=locals
.begin();i
!=locals
.end();++i
) {
2431 st
.port
=::arg().asNum("local-port");
2432 parseService(*i
, st
);
2437 sin
.sin4
.sin_family
= AF_INET
;
2438 if(!IpToU32(st
.host
, (uint32_t*)&sin
.sin4
.sin_addr
.s_addr
)) {
2439 sin
.sin6
.sin6_family
= AF_INET6
;
2440 if(makeIPv6sockaddr(st
.host
, &sin
.sin6
) < 0)
2441 throw PDNSException("Unable to resolve local address for TCP server on '"+ st
.host
+"'");
2444 fd
=socket(sin
.sin6
.sin6_family
, SOCK_STREAM
, 0);
2446 throw PDNSException("Making a TCP server socket for resolver: "+stringerror());
2451 if(setsockopt(fd
, SOL_SOCKET
, SO_REUSEADDR
, &tmp
, sizeof tmp
)<0) {
2452 g_log
<<Logger::Error
<<"Setsockopt failed for TCP listening socket"<<endl
;
2455 if(sin
.sin6
.sin6_family
== AF_INET6
&& setsockopt(fd
, IPPROTO_IPV6
, IPV6_V6ONLY
, &tmp
, sizeof(tmp
)) < 0) {
2456 g_log
<<Logger::Error
<<"Failed to set IPv6 socket to IPv6 only, continuing anyhow: "<<strerror(errno
)<<endl
;
2459 #ifdef TCP_DEFER_ACCEPT
2460 if(setsockopt(fd
, IPPROTO_TCP
, TCP_DEFER_ACCEPT
, &tmp
, sizeof tmp
) >= 0) {
2461 if(i
==locals
.begin())
2462 g_log
<<Logger::Info
<<"Enabled TCP data-ready filter for (slight) DoS protection"<<endl
;
2466 if( ::arg().mustDo("non-local-bind") )
2467 Utility::setBindAny(AF_INET
, fd
);
2471 if(setsockopt(fd
, SOL_SOCKET
, SO_REUSEPORT
, &tmp
, sizeof(tmp
)) < 0)
2472 throw PDNSException("SO_REUSEPORT: "+stringerror());
2476 if (::arg().asNum("tcp-fast-open") > 0) {
2478 int fastOpenQueueSize
= ::arg().asNum("tcp-fast-open");
2479 if (setsockopt(fd
, IPPROTO_TCP
, TCP_FASTOPEN
, &fastOpenQueueSize
, sizeof fastOpenQueueSize
) < 0) {
2480 g_log
<<Logger::Error
<<"Failed to enable TCP Fast Open for listening socket: "<<strerror(errno
)<<endl
;
2483 g_log
<<Logger::Warning
<<"TCP Fast Open configured but not supported for listening socket"<<endl
;
2487 sin
.sin4
.sin_port
= htons(st
.port
);
2488 socklen_t socklen
=sin
.sin4
.sin_family
==AF_INET
? sizeof(sin
.sin4
) : sizeof(sin
.sin6
);
2489 if (::bind(fd
, (struct sockaddr
*)&sin
, socklen
)<0)
2490 throw PDNSException("Binding TCP server socket for "+ st
.host
+": "+stringerror());
2493 setSocketSendBuffer(fd
, 65000);
2495 deferredAdds
.push_back(make_pair(fd
, handleNewTCPQuestion
));
2496 tcpSockets
.insert(fd
);
2498 // we don't need to update g_listenSocketsAddresses since it doesn't work for TCP/IP:
2499 // - fd is not that which we know here, but returned from accept()
2500 if(sin
.sin4
.sin_family
== AF_INET
)
2501 g_log
<<Logger::Info
<<"Listening for TCP queries on "<< sin
.toString() <<":"<<st
.port
<<endl
;
2503 g_log
<<Logger::Info
<<"Listening for TCP queries on ["<< sin
.toString() <<"]:"<<st
.port
<<endl
;
2507 static void makeUDPServerSockets(deferredAdd_t
& deferredAdds
)
2510 vector
<string
>locals
;
2511 stringtok(locals
,::arg()["local-address"]," ,");
2514 throw PDNSException("No local address specified");
2516 for(vector
<string
>::const_iterator i
=locals
.begin();i
!=locals
.end();++i
) {
2518 st
.port
=::arg().asNum("local-port");
2519 parseService(*i
, st
);
2524 sin
.sin4
.sin_family
= AF_INET
;
2525 if(!IpToU32(st
.host
.c_str() , (uint32_t*)&sin
.sin4
.sin_addr
.s_addr
)) {
2526 sin
.sin6
.sin6_family
= AF_INET6
;
2527 if(makeIPv6sockaddr(st
.host
, &sin
.sin6
) < 0)
2528 throw PDNSException("Unable to resolve local address for UDP server on '"+ st
.host
+"'");
2531 int fd
=socket(sin
.sin4
.sin_family
, SOCK_DGRAM
, 0);
2533 throw PDNSException("Making a UDP server socket for resolver: "+netstringerror());
2535 if (!setSocketTimestamps(fd
))
2536 g_log
<<Logger::Warning
<<"Unable to enable timestamp reporting for socket"<<endl
;
2538 if(IsAnyAddress(sin
)) {
2539 if(sin
.sin4
.sin_family
== AF_INET
)
2540 if(!setsockopt(fd
, IPPROTO_IP
, GEN_IP_PKTINFO
, &one
, sizeof(one
))) // linux supports this, so why not - might fail on other systems
2541 g_fromtosockets
.insert(fd
);
2542 #ifdef IPV6_RECVPKTINFO
2543 if(sin
.sin4
.sin_family
== AF_INET6
)
2544 if(!setsockopt(fd
, IPPROTO_IPV6
, IPV6_RECVPKTINFO
, &one
, sizeof(one
)))
2545 g_fromtosockets
.insert(fd
);
2547 if(sin
.sin6
.sin6_family
== AF_INET6
&& setsockopt(fd
, IPPROTO_IPV6
, IPV6_V6ONLY
, &one
, sizeof(one
)) < 0) {
2548 g_log
<<Logger::Error
<<"Failed to set IPv6 socket to IPv6 only, continuing anyhow: "<<strerror(errno
)<<endl
;
2551 if( ::arg().mustDo("non-local-bind") )
2552 Utility::setBindAny(AF_INET6
, fd
);
2556 setSocketReceiveBuffer(fd
, 250000);
2557 sin
.sin4
.sin_port
= htons(st
.port
);
2562 if(setsockopt(fd
, SOL_SOCKET
, SO_REUSEPORT
, &one
, sizeof(one
)) < 0)
2563 throw PDNSException("SO_REUSEPORT: "+stringerror());
2566 socklen_t socklen
=sin
.getSocklen();
2567 if (::bind(fd
, (struct sockaddr
*)&sin
, socklen
)<0)
2568 throw PDNSException("Resolver binding to server socket on port "+ std::to_string(st
.port
) +" for "+ st
.host
+": "+stringerror());
2572 deferredAdds
.push_back(make_pair(fd
, handleNewUDPQuestion
));
2573 g_listenSocketsAddresses
[fd
]=sin
; // this is written to only from the startup thread, not from the workers
2574 if(sin
.sin4
.sin_family
== AF_INET
)
2575 g_log
<<Logger::Info
<<"Listening for UDP queries on "<< sin
.toString() <<":"<<st
.port
<<endl
;
2577 g_log
<<Logger::Info
<<"Listening for UDP queries on ["<< sin
.toString() <<"]:"<<st
.port
<<endl
;
2581 static void daemonize(void)
2588 int i
=open("/dev/null",O_RDWR
); /* open stdin */
2590 g_log
<<Logger::Critical
<<"Unable to open /dev/null: "<<stringerror()<<endl
;
2592 dup2(i
,0); /* stdin */
2593 dup2(i
,1); /* stderr */
2594 dup2(i
,2); /* stderr */
2599 static void usr1Handler(int)
2604 static void usr2Handler(int)
2607 SyncRes::setDefaultLogMode(g_quiet
? SyncRes::LogNone
: SyncRes::Log
);
2608 ::arg().set("quiet")=g_quiet
? "" : "no";
2611 static void doStats(void)
2613 static time_t lastOutputTime
;
2614 static uint64_t lastQueryCount
;
2616 uint64_t cacheHits
= broadcastAccFunction
<uint64_t>(pleaseGetCacheHits
);
2617 uint64_t cacheMisses
= broadcastAccFunction
<uint64_t>(pleaseGetCacheMisses
);
2619 if(g_stats
.qcounter
&& (cacheHits
+ cacheMisses
) && SyncRes::s_queries
&& SyncRes::s_outqueries
) {
2620 g_log
<<Logger::Notice
<<"stats: "<<g_stats
.qcounter
<<" questions, "<<
2621 broadcastAccFunction
<uint64_t>(pleaseGetCacheSize
)<< " cache entries, "<<
2622 broadcastAccFunction
<uint64_t>(pleaseGetNegCacheSize
)<<" negative entries, "<<
2623 (int)((cacheHits
*100.0)/(cacheHits
+cacheMisses
))<<"% cache hits"<<endl
;
2625 g_log
<<Logger::Notice
<<"stats: throttle map: "
2626 << broadcastAccFunction
<uint64_t>(pleaseGetThrottleSize
) <<", ns speeds: "
2627 << broadcastAccFunction
<uint64_t>(pleaseGetNsSpeedsSize
)<<endl
;
2628 g_log
<<Logger::Notice
<<"stats: outpacket/query ratio "<<(int)(SyncRes::s_outqueries
*100.0/SyncRes::s_queries
)<<"%";
2629 g_log
<<Logger::Notice
<<", "<<(int)(SyncRes::s_throttledqueries
*100.0/(SyncRes::s_outqueries
+SyncRes::s_throttledqueries
))<<"% throttled, "
2630 <<SyncRes::s_nodelegated
<<" no-delegation drops"<<endl
;
2631 g_log
<<Logger::Notice
<<"stats: "<<SyncRes::s_tcpoutqueries
<<" outgoing tcp connections, "<<
2632 broadcastAccFunction
<uint64_t>(pleaseGetConcurrentQueries
)<<" queries running, "<<SyncRes::s_outgoingtimeouts
<<" outgoing timeouts"<<endl
;
2634 //g_log<<Logger::Notice<<"stats: "<<g_stats.ednsPingMatches<<" ping matches, "<<g_stats.ednsPingMismatches<<" mismatches, "<<
2635 //g_stats.noPingOutQueries<<" outqueries w/o ping, "<< g_stats.noEdnsOutQueries<<" w/o EDNS"<<endl;
2637 g_log
<<Logger::Notice
<<"stats: " << broadcastAccFunction
<uint64_t>(pleaseGetPacketCacheSize
) <<
2638 " packet cache entries, "<<(int)(100.0*broadcastAccFunction
<uint64_t>(pleaseGetPacketCacheHits
)/SyncRes::s_queries
) << "% packet cache hits"<<endl
;
2641 for (const auto& threadInfo
: s_threadInfos
) {
2642 if(threadInfo
.isWorker
) {
2643 g_log
<<Logger::Notice
<<"Thread "<<idx
<<" has been distributed "<<threadInfo
.numberOfDistributedQueries
<<" queries"<<endl
;
2648 time_t now
= time(0);
2649 if(lastOutputTime
&& lastQueryCount
&& now
!= lastOutputTime
) {
2650 g_log
<<Logger::Notice
<<"stats: "<< (SyncRes::s_queries
- lastQueryCount
) / (now
- lastOutputTime
) <<" qps (average over "<< (now
- lastOutputTime
) << " seconds)"<<endl
;
2652 lastOutputTime
= now
;
2653 lastQueryCount
= SyncRes::s_queries
;
2655 else if(statsWanted
)
2656 g_log
<<Logger::Notice
<<"stats: no stats yet!"<<endl
;
2661 static void houseKeeping(void *)
2663 static thread_local
time_t last_rootupdate
, last_prune
, last_secpoll
, last_trustAnchorUpdate
{0};
2664 static thread_local
int cleanCounter
=0;
2665 static thread_local
bool s_running
; // houseKeeping can get suspended in secpoll, and be restarted, which makes us do duplicate work
2666 auto luaconfsLocal
= g_luaconfs
.getLocal();
2668 if (last_trustAnchorUpdate
== 0 && !luaconfsLocal
->trustAnchorFileInfo
.fname
.empty() && luaconfsLocal
->trustAnchorFileInfo
.interval
!= 0) {
2669 // Loading the Lua config file already "refreshed" the TAs
2670 last_trustAnchorUpdate
= g_now
.tv_sec
+ luaconfsLocal
->trustAnchorFileInfo
.interval
* 3600;
2679 Utility::gettimeofday(&now
, 0);
2681 if(now
.tv_sec
- last_prune
> (time_t)(5 + t_id
)) {
2684 t_RC
->doPrune(g_maxCacheEntries
/ g_numThreads
); // this function is local to a thread, so fine anyhow
2685 t_packetCache
->doPruneTo(g_maxPacketCacheEntries
/ g_numWorkerThreads
);
2687 SyncRes::pruneNegCache(g_maxCacheEntries
/ (g_numWorkerThreads
* 10));
2689 if(!((cleanCounter
++)%40)) { // this is a full scan!
2690 time_t limit
=now
.tv_sec
-300;
2691 SyncRes::pruneNSSpeeds(limit
);
2696 if(now
.tv_sec
- last_rootupdate
> 7200) {
2697 int res
= SyncRes::getRootNS(g_now
, nullptr);
2699 last_rootupdate
=now
.tv_sec
;
2702 if(isHandlerThread()) {
2704 if(now
.tv_sec
- last_secpoll
>= 3600) {
2706 doSecPoll(&last_secpoll
);
2708 catch(std::exception
& e
)
2710 g_log
<<Logger::Error
<<"Exception while performing security poll: "<<e
.what()<<endl
;
2712 catch(PDNSException
& e
)
2714 g_log
<<Logger::Error
<<"Exception while performing security poll: "<<e
.reason
<<endl
;
2716 catch(ImmediateServFailException
&e
)
2718 g_log
<<Logger::Error
<<"Exception while performing security poll: "<<e
.reason
<<endl
;
2722 g_log
<<Logger::Error
<<"Exception while performing security poll"<<endl
;
2726 if (!luaconfsLocal
->trustAnchorFileInfo
.fname
.empty() && luaconfsLocal
->trustAnchorFileInfo
.interval
!= 0 &&
2727 g_now
.tv_sec
- last_trustAnchorUpdate
>= (luaconfsLocal
->trustAnchorFileInfo
.interval
* 3600)) {
2728 g_log
<<Logger::Debug
<<"Refreshing Trust Anchors from file"<<endl
;
2730 map
<DNSName
, dsmap_t
> dsAnchors
;
2731 if (updateTrustAnchorsFromFile(luaconfsLocal
->trustAnchorFileInfo
.fname
, dsAnchors
)) {
2732 g_luaconfs
.modify([&dsAnchors
](LuaConfigItems
& lci
) {
2733 lci
.dsAnchors
= dsAnchors
;
2736 last_trustAnchorUpdate
= now
.tv_sec
;
2737 } catch (const PDNSException
&pe
) {
2738 g_log
<<Logger::Error
<<"Unable to update Trust Anchors: "<<pe
.reason
<<endl
;
2744 catch(PDNSException
& ae
)
2747 g_log
<<Logger::Error
<<"Fatal error in housekeeping thread: "<<ae
.reason
<<endl
;
2752 static void makeThreadPipes()
2754 /* thread 0 is the handler / SNMP, we start at 1 */
2755 for(unsigned int n
= 1; n
<= (g_numWorkerThreads
+ g_numDistributorThreads
); ++n
) {
2756 auto& threadInfos
= s_threadInfos
.at(n
);
2760 unixDie("Creating pipe for inter-thread communications");
2762 threadInfos
.pipes
.readToThread
= fd
[0];
2763 threadInfos
.pipes
.writeToThread
= fd
[1];
2766 unixDie("Creating pipe for inter-thread communications");
2768 threadInfos
.pipes
.readFromThread
= fd
[0];
2769 threadInfos
.pipes
.writeFromThread
= fd
[1];
2772 unixDie("Creating pipe for inter-thread communications");
2774 threadInfos
.pipes
.readQueriesToThread
= fd
[0];
2775 threadInfos
.pipes
.writeQueriesToThread
= fd
[1];
2777 if (!setNonBlocking(threadInfos
.pipes
.writeQueriesToThread
)) {
2778 unixDie("Making pipe for inter-thread communications non-blocking");
2789 void broadcastFunction(const pipefunc_t
& func
)
2791 /* This function might be called by the worker with t_id 0 during startup
2792 for the initialization of ACLs and domain maps. After that it should only
2793 be called by the handler. */
2795 if (s_threadInfos
.empty() && isHandlerThread()) {
2796 /* the handler and distributors will call themselves below, but
2797 during startup we get called while s_threadInfos has not been
2798 populated yet to update the ACL or domain maps, so we need to
2805 for (const auto& threadInfo
: s_threadInfos
) {
2807 func(); // don't write to ourselves!
2811 ThreadMSG
* tmsg
= new ThreadMSG();
2813 tmsg
->wantAnswer
= true;
2814 if(write(threadInfo
.pipes
.writeToThread
, &tmsg
, sizeof(tmsg
)) != sizeof(tmsg
)) {
2817 unixDie("write to thread pipe returned wrong size or error");
2820 string
* resp
= nullptr;
2821 if(read(threadInfo
.pipes
.readFromThread
, &resp
, sizeof(resp
)) != sizeof(resp
))
2822 unixDie("read from thread pipe returned wrong size or error");
2831 static bool trySendingQueryToWorker(unsigned int target
, ThreadMSG
* tmsg
)
2833 auto& targetInfo
= s_threadInfos
[target
];
2834 if(!targetInfo
.isWorker
) {
2835 g_log
<<Logger::Error
<<"distributeAsyncFunction() tried to assign a query to a non-worker thread"<<endl
;
2839 const auto& tps
= targetInfo
.pipes
;
2841 ssize_t written
= write(tps
.writeQueriesToThread
, &tmsg
, sizeof(tmsg
));
2843 if (static_cast<size_t>(written
) != sizeof(tmsg
)) {
2845 unixDie("write to thread pipe returned wrong size or error");
2850 if (error
== EAGAIN
|| error
== EWOULDBLOCK
) {
2854 unixDie("write to thread pipe returned wrong size or error:" + std::to_string(error
));
2858 ++targetInfo
.numberOfDistributedQueries
;
2863 static unsigned int getWorkerLoad(size_t workerIdx
)
2865 const auto mt
= s_threadInfos
[/* skip handler */ 1 + g_numDistributorThreads
+ workerIdx
].mt
;
2866 if (mt
!= nullptr) {
2867 return mt
->numProcesses();
2872 static unsigned int selectWorker(unsigned int hash
)
2874 if (s_balancingFactor
== 0) {
2875 return /* skip handler */ 1 + g_numDistributorThreads
+ (hash
% g_numWorkerThreads
);
2878 /* we start with one, representing the query we are currently handling */
2879 double currentLoad
= 1;
2880 std::vector
<unsigned int> load(g_numWorkerThreads
);
2881 for (size_t idx
= 0; idx
< g_numWorkerThreads
; idx
++) {
2882 load
[idx
] = getWorkerLoad(idx
);
2883 currentLoad
+= load
[idx
];
2884 // cerr<<"load for worker "<<idx<<" is "<<load[idx]<<endl;
2887 double targetLoad
= (currentLoad
/ g_numWorkerThreads
) * s_balancingFactor
;
2888 // cerr<<"total load is "<<currentLoad<<", number of workers is "<<g_numWorkerThreads<<", target load is "<<targetLoad<<endl;
2890 unsigned int worker
= hash
% g_numWorkerThreads
;
2891 /* at least one server has to be below the average load */
2892 while(load
[worker
] > targetLoad
) {
2893 // cerr<<"worker "<<worker<<" is above the target load, selecting another one"<<endl;
2894 worker
= (worker
+ 1) % g_numWorkerThreads
;
2897 return /* skip handler */ 1 + g_numDistributorThreads
+ worker
;
2900 // This function is only called by the distributor threads, when pdns-distributes-queries is set
2901 void distributeAsyncFunction(const string
& packet
, const pipefunc_t
& func
)
2903 if (!isDistributorThread()) {
2904 g_log
<<Logger::Error
<<"distributeAsyncFunction() has been called by a worker ("<<t_id
<<")"<<endl
;
2908 unsigned int hash
= hashQuestion(packet
.c_str(), packet
.length(), g_disthashseed
);
2909 unsigned int target
= selectWorker(hash
);
2911 ThreadMSG
* tmsg
= new ThreadMSG();
2913 tmsg
->wantAnswer
= false;
2915 if (!trySendingQueryToWorker(target
, tmsg
)) {
2916 /* if this function failed but did not raise an exception, it means that the pipe
2917 was full, let's try another one */
2918 unsigned int newTarget
= 0;
2920 newTarget
= /* skip handler */ 1 + g_numDistributorThreads
+ dns_random(g_numWorkerThreads
);
2921 } while (newTarget
== target
);
2923 if (!trySendingQueryToWorker(newTarget
, tmsg
)) {
2924 g_stats
.queryPipeFullDrops
++;
2930 static void handlePipeRequest(int fd
, FDMultiplexer::funcparam_t
& var
)
2932 ThreadMSG
* tmsg
= nullptr;
2934 if(read(fd
, &tmsg
, sizeof(tmsg
)) != sizeof(tmsg
)) { // fd == readToThread || fd == readQueriesToThread
2935 unixDie("read from thread pipe returned wrong size or error");
2940 resp
= tmsg
->func();
2942 catch(std::exception
& e
) {
2943 if(g_logCommonErrors
)
2944 g_log
<<Logger::Error
<<"PIPE function we executed created exception: "<<e
.what()<<endl
; // but what if they wanted an answer.. we send 0
2946 catch(PDNSException
& e
) {
2947 if(g_logCommonErrors
)
2948 g_log
<<Logger::Error
<<"PIPE function we executed created PDNS exception: "<<e
.reason
<<endl
; // but what if they wanted an answer.. we send 0
2950 if(tmsg
->wantAnswer
) {
2951 const auto& threadInfo
= s_threadInfos
.at(t_id
);
2952 if(write(threadInfo
.pipes
.writeFromThread
, &resp
, sizeof(resp
)) != sizeof(resp
)) {
2954 unixDie("write to thread pipe returned wrong size or error");
2961 template<class T
> void *voider(const boost::function
<T
*()>& func
)
2966 vector
<ComboAddress
>& operator+=(vector
<ComboAddress
>&a
, const vector
<ComboAddress
>& b
)
2968 a
.insert(a
.end(), b
.begin(), b
.end());
2972 vector
<pair
<string
, uint16_t> >& operator+=(vector
<pair
<string
, uint16_t> >&a
, const vector
<pair
<string
, uint16_t> >& b
)
2974 a
.insert(a
.end(), b
.begin(), b
.end());
2978 vector
<pair
<DNSName
, uint16_t> >& operator+=(vector
<pair
<DNSName
, uint16_t> >&a
, const vector
<pair
<DNSName
, uint16_t> >& b
)
2980 a
.insert(a
.end(), b
.begin(), b
.end());
2986 This function should only be called by the handler to gather metrics, wipe the cache,
2987 reload the Lua script (not the Lua config) or change the current trace regex,
2988 and by the SNMP thread to gather metrics. */
2989 template<class T
> T
broadcastAccFunction(const boost::function
<T
*()>& func
)
2991 if (!isHandlerThread()) {
2992 g_log
<<Logger::Error
<<"broadcastAccFunction has been called by a worker ("<<t_id
<<")"<<endl
;
2998 for (const auto& threadInfo
: s_threadInfos
) {
3003 const auto& tps
= threadInfo
.pipes
;
3004 ThreadMSG
* tmsg
= new ThreadMSG();
3005 tmsg
->func
= boost::bind(voider
<T
>, func
);
3006 tmsg
->wantAnswer
= true;
3008 if(write(tps
.writeToThread
, &tmsg
, sizeof(tmsg
)) != sizeof(tmsg
)) {
3010 unixDie("write to thread pipe returned wrong size or error");
3014 if(read(tps
.readFromThread
, &resp
, sizeof(resp
)) != sizeof(resp
))
3015 unixDie("read from thread pipe returned wrong size or error");
3026 template string
broadcastAccFunction(const boost::function
<string
*()>& fun
); // explicit instantiation
3027 template uint64_t broadcastAccFunction(const boost::function
<uint64_t*()>& fun
); // explicit instantiation
3028 template vector
<ComboAddress
> broadcastAccFunction(const boost::function
<vector
<ComboAddress
> *()>& fun
); // explicit instantiation
3029 template vector
<pair
<DNSName
,uint16_t> > broadcastAccFunction(const boost::function
<vector
<pair
<DNSName
, uint16_t> > *()>& fun
); // explicit instantiation
3031 static void handleRCC(int fd
, FDMultiplexer::funcparam_t
& var
)
3035 string msg
=s_rcc
.recv(&remote
);
3036 RecursorControlParser rcp
;
3037 RecursorControlParser::func_t
* command
;
3039 string answer
=rcp
.getAnswer(msg
, &command
);
3041 // If we are inside a chroot, we need to strip
3042 if (!arg()["chroot"].empty()) {
3043 size_t len
= arg()["chroot"].length();
3044 remote
= remote
.substr(len
);
3047 s_rcc
.send(answer
, &remote
);
3050 catch(const std::exception
& e
) {
3051 g_log
<<Logger::Error
<<"Error dealing with control socket request: "<<e
.what()<<endl
;
3053 catch(const PDNSException
& ae
) {
3054 g_log
<<Logger::Error
<<"Error dealing with control socket request: "<<ae
.reason
<<endl
;
3058 static void handleTCPClientReadable(int fd
, FDMultiplexer::funcparam_t
& var
)
3060 PacketID
* pident
=any_cast
<PacketID
>(&var
);
3061 // cerr<<"handleTCPClientReadable called for fd "<<fd<<", pident->inNeeded: "<<pident->inNeeded<<", "<<pident->sock->getHandle()<<endl;
3063 shared_array
<char> buffer(new char[pident
->inNeeded
]);
3065 ssize_t ret
=recv(fd
, buffer
.get(), pident
->inNeeded
,0);
3067 pident
->inMSG
.append(&buffer
[0], &buffer
[ret
]);
3068 pident
->inNeeded
-=(size_t)ret
;
3069 if(!pident
->inNeeded
|| pident
->inIncompleteOkay
) {
3070 // cerr<<"Got entire load of "<<pident->inMSG.size()<<" bytes"<<endl;
3071 PacketID pid
=*pident
;
3072 string msg
=pident
->inMSG
;
3074 t_fdm
->removeReadFD(fd
);
3075 MT
->sendEvent(pid
, &msg
);
3078 // cerr<<"Still have "<<pident->inNeeded<<" left to go"<<endl;
3082 PacketID tmp
=*pident
;
3083 t_fdm
->removeReadFD(fd
); // pident might now be invalid (it isn't, but still)
3085 MT
->sendEvent(tmp
, &empty
); // this conveys error status
3089 static void handleTCPClientWritable(int fd
, FDMultiplexer::funcparam_t
& var
)
3091 PacketID
* pid
=any_cast
<PacketID
>(&var
);
3092 ssize_t ret
=send(fd
, pid
->outMSG
.c_str() + pid
->outPos
, pid
->outMSG
.size() - pid
->outPos
,0);
3094 pid
->outPos
+=(ssize_t
)ret
;
3095 if(pid
->outPos
==pid
->outMSG
.size()) {
3097 t_fdm
->removeWriteFD(fd
);
3098 MT
->sendEvent(tmp
, &tmp
.outMSG
); // send back what we sent to convey everything is ok
3101 else { // error or EOF
3103 t_fdm
->removeWriteFD(fd
);
3105 MT
->sendEvent(tmp
, &sent
); // we convey error status by sending empty string
3109 // resend event to everybody chained onto it
3110 static void doResends(MT_t::waiters_t::iterator
& iter
, PacketID resend
, const string
& content
)
3112 if(iter
->key
.chain
.empty())
3114 // cerr<<"doResends called!\n";
3115 for(PacketID::chain_t::iterator i
=iter
->key
.chain
.begin(); i
!= iter
->key
.chain
.end() ; ++i
) {
3118 // cerr<<"\tResending "<<content.size()<<" bytes for fd="<<resend.fd<<" and id="<<resend.id<<endl;
3120 MT
->sendEvent(resend
, &content
);
3121 g_stats
.chainResends
++;
3125 static void handleUDPServerResponse(int fd
, FDMultiplexer::funcparam_t
& var
)
3127 PacketID pid
=any_cast
<PacketID
>(var
);
3130 packet
.resize(g_outgoingEDNSBufsize
);
3131 ComboAddress fromaddr
;
3132 socklen_t addrlen
=sizeof(fromaddr
);
3134 len
=recvfrom(fd
, &packet
.at(0), packet
.size(), 0, (sockaddr
*)&fromaddr
, &addrlen
);
3136 if(len
< (ssize_t
) sizeof(dnsheader
)) {
3138 ; // cerr<<"Error on fd "<<fd<<": "<<stringerror()<<"\n";
3140 g_stats
.serverParseError
++;
3141 if(g_logCommonErrors
)
3142 g_log
<<Logger::Error
<<"Unable to parse packet from remote UDP server "<< fromaddr
.toString() <<
3143 ": packet smaller than DNS header"<<endl
;
3146 t_udpclientsocks
->returnSocket(fd
);
3149 MT_t::waiters_t::iterator iter
=MT
->d_waiters
.find(pid
);
3150 if(iter
!= MT
->d_waiters
.end())
3151 doResends(iter
, pid
, empty
);
3153 MT
->sendEvent(pid
, &empty
); // this denotes error (does lookup again.. at least L1 will be hot)
3159 memcpy(&dh
, &packet
.at(0), sizeof(dh
));
3162 pident
.remote
=fromaddr
;
3166 if(!dh
.qr
&& g_logCommonErrors
) {
3167 g_log
<<Logger::Notice
<<"Not taking data from question on outgoing socket from "<< fromaddr
.toStringWithPort() <<endl
;
3170 if(!dh
.qdcount
|| // UPC, Nominum, very old BIND on FormErr, NSD
3171 !dh
.qr
) { // one weird server
3172 pident
.domain
.clear();
3178 pident
.domain
=DNSName(&packet
.at(0), len
, 12, false, &pident
.type
); // don't copy this from above - we need to do the actual read
3180 catch(std::exception
& e
) {
3181 g_stats
.serverParseError
++; // won't be fed to lwres.cc, so we have to increment
3182 g_log
<<Logger::Warning
<<"Error in packet from remote nameserver "<< fromaddr
.toStringWithPort() << ": "<<e
.what() << endl
;
3187 MT_t::waiters_t::iterator iter
=MT
->d_waiters
.find(pident
);
3188 if(iter
!= MT
->d_waiters
.end()) {
3189 doResends(iter
, pident
, packet
);
3194 if(!MT
->sendEvent(pident
, &packet
)) {
3195 // 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
3196 for(MT_t::waiters_t::iterator mthread
=MT
->d_waiters
.begin(); mthread
!=MT
->d_waiters
.end(); ++mthread
) {
3197 if(pident
.fd
==mthread
->key
.fd
&& mthread
->key
.remote
==pident
.remote
&& mthread
->key
.type
== pident
.type
&&
3198 pident
.domain
== mthread
->key
.domain
) {
3199 mthread
->key
.nearMisses
++;
3202 // be a bit paranoid here since we're weakening our matching
3203 if(pident
.domain
.empty() && !mthread
->key
.domain
.empty() && !pident
.type
&& mthread
->key
.type
&&
3204 pident
.id
== mthread
->key
.id
&& mthread
->key
.remote
== pident
.remote
) {
3205 // cerr<<"Empty response, rest matches though, sending to a waiter"<<endl;
3206 pident
.domain
= mthread
->key
.domain
;
3207 pident
.type
= mthread
->key
.type
;
3208 goto retryWithName
; // note that this only passes on an error, lwres will still reject the packet
3211 g_stats
.unexpectedCount
++; // if we made it here, it really is an unexpected answer
3212 if(g_logCommonErrors
) {
3213 g_log
<<Logger::Warning
<<"Discarding unexpected packet from "<<fromaddr
.toStringWithPort()<<": "<< (pident
.domain
.empty() ? "<empty>" : pident
.domain
.toString())<<", "<<pident
.type
<<", "<<MT
->d_waiters
.size()<<" waiters"<<endl
;
3217 t_udpclientsocks
->returnSocket(fd
);
3221 FDMultiplexer
* getMultiplexer()
3224 for(const auto& i
: FDMultiplexer::getMultiplexerMap()) {
3229 catch(FDMultiplexerException
&fe
) {
3230 g_log
<<Logger::Error
<<"Non-fatal error initializing possible multiplexer ("<<fe
.what()<<"), falling back"<<endl
;
3233 g_log
<<Logger::Error
<<"Non-fatal error initializing possible multiplexer"<<endl
;
3236 g_log
<<Logger::Error
<<"No working multiplexer found!"<<endl
;
3241 static string
* doReloadLuaScript()
3243 string fname
= ::arg()["lua-dns-script"];
3247 g_log
<<Logger::Info
<<t_id
<<" Unloaded current lua script"<<endl
;
3248 return new string("unloaded\n");
3251 t_pdl
= std::make_shared
<RecursorLua4
>();
3252 t_pdl
->loadFile(fname
);
3255 catch(std::exception
& e
) {
3256 g_log
<<Logger::Error
<<t_id
<<" Retaining current script, error from '"<<fname
<<"': "<< e
.what() <<endl
;
3257 return new string("retaining current script, error from '"+fname
+"': "+e
.what()+"\n");
3260 g_log
<<Logger::Warning
<<t_id
<<" (Re)loaded lua script from '"<<fname
<<"'"<<endl
;
3261 return new string("(re)loaded '"+fname
+"'\n");
3264 string
doQueueReloadLuaScript(vector
<string
>::const_iterator begin
, vector
<string
>::const_iterator end
)
3267 ::arg().set("lua-dns-script") = *begin
;
3269 return broadcastAccFunction
<string
>(doReloadLuaScript
);
3272 static string
* pleaseUseNewTraceRegex(const std::string
& newRegex
)
3275 if(newRegex
.empty()) {
3276 t_traceRegex
.reset();
3277 return new string("unset\n");
3280 t_traceRegex
= std::make_shared
<Regex
>(newRegex
);
3281 return new string("ok\n");
3284 catch(PDNSException
& ae
)
3286 return new string(ae
.reason
+"\n");
3289 string
doTraceRegex(vector
<string
>::const_iterator begin
, vector
<string
>::const_iterator end
)
3291 return broadcastAccFunction
<string
>(boost::bind(pleaseUseNewTraceRegex
, begin
!=end
? *begin
: ""));
3294 static void checkLinuxIPv6Limits()
3298 if(readFileIfThere("/proc/sys/net/ipv6/route/max_size", &line
)) {
3299 int lim
=std::stoi(line
);
3301 g_log
<<Logger::Error
<<"If using IPv6, please raise sysctl net.ipv6.route.max_size, currently set to "<<lim
<<" which is < 16384"<<endl
;
3306 static void checkOrFixFDS()
3308 unsigned int availFDs
=getFilenumLimit();
3309 unsigned int wantFDs
= g_maxMThreads
* g_numWorkerThreads
+25; // even healthier margin then before
3311 if(wantFDs
> availFDs
) {
3312 unsigned int hardlimit
= getFilenumLimit(true);
3313 if(hardlimit
>= wantFDs
) {
3314 setFilenumLimit(wantFDs
);
3315 g_log
<<Logger::Warning
<<"Raised soft limit on number of filedescriptors to "<<wantFDs
<<" to match max-mthreads and threads settings"<<endl
;
3318 int newval
= (hardlimit
- 25) / g_numWorkerThreads
;
3319 g_log
<<Logger::Warning
<<"Insufficient number of filedescriptors available for max-mthreads*threads setting! ("<<hardlimit
<<" < "<<wantFDs
<<"), reducing max-mthreads to "<<newval
<<endl
;
3320 g_maxMThreads
= newval
;
3321 setFilenumLimit(hardlimit
);
3326 static void* recursorThread(unsigned int tid
, const string
& threadName
);
3328 static void* pleaseSupplantACLs(std::shared_ptr
<NetmaskGroup
> ng
)
3339 static bool l_initialized
;
3341 if(l_initialized
) { // only reload configuration file on second call
3342 string configname
=::arg()["config-dir"]+"/recursor.conf";
3343 if(::arg()["config-name"]!="") {
3344 configname
=::arg()["config-dir"]+"/recursor-"+::arg()["config-name"]+".conf";
3346 cleanSlashes(configname
);
3348 if(!::arg().preParseFile(configname
.c_str(), "allow-from-file"))
3349 throw runtime_error("Unable to re-parse configuration file '"+configname
+"'");
3350 ::arg().preParseFile(configname
.c_str(), "allow-from", LOCAL_NETS
);
3351 ::arg().preParseFile(configname
.c_str(), "include-dir");
3352 ::arg().preParse(g_argc
, g_argv
, "include-dir");
3354 // then process includes
3355 std::vector
<std::string
> extraConfigs
;
3356 ::arg().gatherIncludes(extraConfigs
);
3358 for(const std::string
& fn
: extraConfigs
) {
3359 if(!::arg().preParseFile(fn
.c_str(), "allow-from-file", ::arg()["allow-from-file"]))
3360 throw runtime_error("Unable to re-parse configuration file include '"+fn
+"'");
3361 if(!::arg().preParseFile(fn
.c_str(), "allow-from", ::arg()["allow-from"]))
3362 throw runtime_error("Unable to re-parse configuration file include '"+fn
+"'");
3365 ::arg().preParse(g_argc
, g_argv
, "allow-from-file");
3366 ::arg().preParse(g_argc
, g_argv
, "allow-from");
3369 std::shared_ptr
<NetmaskGroup
> oldAllowFrom
= t_allowFrom
;
3370 std::shared_ptr
<NetmaskGroup
> allowFrom
= std::make_shared
<NetmaskGroup
>();
3372 if(!::arg()["allow-from-file"].empty()) {
3374 ifstream
ifs(::arg()["allow-from-file"].c_str());
3376 throw runtime_error("Could not open '"+::arg()["allow-from-file"]+"': "+stringerror());
3379 string::size_type pos
;
3380 while(getline(ifs
,line
)) {
3382 if(pos
!=string::npos
)
3388 allowFrom
->addMask(line
);
3390 g_log
<<Logger::Warning
<<"Done parsing " << allowFrom
->size() <<" allow-from ranges from file '"<<::arg()["allow-from-file"]<<"' - overriding 'allow-from' setting"<<endl
;
3392 else if(!::arg()["allow-from"].empty()) {
3394 stringtok(ips
, ::arg()["allow-from"], ", ");
3396 g_log
<<Logger::Warning
<<"Only allowing queries from: ";
3397 for(vector
<string
>::const_iterator i
= ips
.begin(); i
!= ips
.end(); ++i
) {
3398 allowFrom
->addMask(*i
);
3400 g_log
<<Logger::Warning
<<", ";
3401 g_log
<<Logger::Warning
<<*i
;
3403 g_log
<<Logger::Warning
<<endl
;
3406 if(::arg()["local-address"]!="127.0.0.1" && ::arg().asNum("local-port")==53)
3407 g_log
<<Logger::Warning
<<"WARNING: Allowing queries from all IP addresses - this can be a security risk!"<<endl
;
3408 allowFrom
= nullptr;
3411 g_initialAllowFrom
= allowFrom
;
3412 broadcastFunction(boost::bind(pleaseSupplantACLs
, allowFrom
));
3413 oldAllowFrom
= nullptr;
3415 l_initialized
= true;
3419 static void setupDelegationOnly()
3421 vector
<string
> parts
;
3422 stringtok(parts
, ::arg()["delegation-only"], ", \t");
3423 for(const auto& p
: parts
) {
3424 SyncRes::addDelegationOnly(DNSName(p
));
3428 static std::map
<unsigned int, std::set
<int> > parseCPUMap()
3430 std::map
<unsigned int, std::set
<int> > result
;
3432 const std::string value
= ::arg()["cpu-map"];
3434 if (!value
.empty() && !isSettingThreadCPUAffinitySupported()) {
3435 g_log
<<Logger::Warning
<<"CPU mapping requested but not supported, skipping"<<endl
;
3439 std::vector
<std::string
> parts
;
3441 stringtok(parts
, value
, " \t");
3443 for(const auto& part
: parts
) {
3444 if (part
.find('=') == string::npos
)
3448 auto headers
= splitField(part
, '=');
3449 trim(headers
.first
);
3450 trim(headers
.second
);
3452 unsigned int threadId
= pdns_stou(headers
.first
);
3453 std::vector
<std::string
> cpus
;
3455 stringtok(cpus
, headers
.second
, ",");
3457 for(const auto& cpu
: cpus
) {
3458 int cpuId
= std::stoi(cpu
);
3460 result
[threadId
].insert(cpuId
);
3463 catch(const std::exception
& e
) {
3464 g_log
<<Logger::Error
<<"Error parsing cpu-map entry '"<<part
<<"': "<<e
.what()<<endl
;
3471 static void setCPUMap(const std::map
<unsigned int, std::set
<int> >& cpusMap
, unsigned int n
, pthread_t tid
)
3473 const auto& cpuMapping
= cpusMap
.find(n
);
3474 if (cpuMapping
!= cpusMap
.cend()) {
3475 int rc
= mapThreadToCPUList(tid
, cpuMapping
->second
);
3477 g_log
<<Logger::Info
<<"CPU affinity for worker "<<n
<<" has been set to CPU map:";
3478 for (const auto cpu
: cpuMapping
->second
) {
3479 g_log
<<Logger::Info
<<" "<<cpu
;
3481 g_log
<<Logger::Info
<<endl
;
3484 g_log
<<Logger::Warning
<<"Error setting CPU affinity for worker "<<n
<<" to CPU map:";
3485 for (const auto cpu
: cpuMapping
->second
) {
3486 g_log
<<Logger::Info
<<" "<<cpu
;
3488 g_log
<<Logger::Info
<<strerror(rc
)<<endl
;
3494 static void setupNODThread()
3497 uint32_t num_cells
= ::arg().asNum("new-domain-db-size");
3498 t_nodDBp
= std::make_shared
<nod::NODDB
>(num_cells
);
3500 t_nodDBp
->setCacheDir(::arg()["new-domain-history-dir"]);
3502 catch (const PDNSException
& e
) {
3503 g_log
<<Logger::Error
<<"new-domain-history-dir (" << ::arg()["new-domain-history-dir"] << ") is not readable or does not exist"<<endl
;
3506 if (!t_nodDBp
->init()) {
3507 g_log
<<Logger::Error
<<"Could not initialize domain tracking"<<endl
;
3510 std::thread
t(nod::NODDB::startHousekeepingThread
, t_nodDBp
, std::this_thread::get_id());
3512 g_nod_pbtag
= ::arg()["new-domain-pb-tag"];
3515 uint32_t num_cells
= ::arg().asNum("unique-response-db-size");
3516 t_udrDBp
= std::make_shared
<nod::UniqueResponseDB
>(num_cells
);
3518 t_udrDBp
->setCacheDir(::arg()["unique-response-history-dir"]);
3520 catch (const PDNSException
& e
) {
3521 g_log
<<Logger::Error
<<"unique-response-history-dir (" << ::arg()["unique-response-history-dir"] << ") is not readable or does not exist"<<endl
;
3524 if (!t_udrDBp
->init()) {
3525 g_log
<<Logger::Error
<<"Could not initialize unique response tracking"<<endl
;
3528 std::thread
t(nod::UniqueResponseDB::startHousekeepingThread
, t_udrDBp
, std::this_thread::get_id());
3530 g_udr_pbtag
= ::arg()["unique-response-pb-tag"];
3534 void parseNODWhitelist(const std::string
& wlist
)
3536 vector
<string
> parts
;
3537 stringtok(parts
, wlist
, ",; ");
3538 for(const auto& a
: parts
) {
3539 g_nodDomainWL
.add(DNSName(a
));
3543 static void setupNODGlobal()
3545 // Setup NOD subsystem
3546 g_nodEnabled
= ::arg().mustDo("new-domain-tracking");
3547 g_nodLookupDomain
= DNSName(::arg()["new-domain-lookup"]);
3548 g_nodLog
= ::arg().mustDo("new-domain-log");
3549 parseNODWhitelist(::arg()["new-domain-whitelist"]);
3551 // Setup Unique DNS Response subsystem
3552 g_udrEnabled
= ::arg().mustDo("unique-response-tracking");
3553 g_udrLog
= ::arg().mustDo("unique-response-log");
3555 #endif /* NOD_ENABLED */
3557 static int serviceMain(int argc
, char*argv
[])
3559 g_log
.setName(s_programname
);
3560 g_log
.disableSyslog(::arg().mustDo("disable-syslog"));
3561 g_log
.setTimestamps(::arg().mustDo("log-timestamp"));
3563 if(!::arg()["logging-facility"].empty()) {
3564 int val
=logFacilityToLOG(::arg().asNum("logging-facility") );
3566 g_log
.setFacility(val
);
3568 g_log
<<Logger::Error
<<"Unknown logging facility "<<::arg().asNum("logging-facility") <<endl
;
3571 showProductVersion();
3573 g_disthashseed
=dns_random(0xffffffff);
3575 checkLinuxIPv6Limits();
3577 vector
<string
> addrs
;
3578 if(!::arg()["query-local-address6"].empty()) {
3579 SyncRes::s_doIPv6
=true;
3580 g_log
<<Logger::Warning
<<"Enabling IPv6 transport for outgoing queries"<<endl
;
3582 stringtok(addrs
, ::arg()["query-local-address6"], ", ;");
3583 for(const string
& addr
: addrs
) {
3584 g_localQueryAddresses6
.push_back(ComboAddress(addr
));
3588 g_log
<<Logger::Warning
<<"NOT using IPv6 for outgoing queries - set 'query-local-address6=::' to enable"<<endl
;
3591 stringtok(addrs
, ::arg()["query-local-address"], ", ;");
3592 for(const string
& addr
: addrs
) {
3593 g_localQueryAddresses4
.push_back(ComboAddress(addr
));
3596 catch(std::exception
& e
) {
3597 g_log
<<Logger::Error
<<"Assigning local query addresses: "<<e
.what();
3601 // keep this ABOVE loadRecursorLuaConfig!
3602 if(::arg()["dnssec"]=="off")
3603 g_dnssecmode
=DNSSECMode::Off
;
3604 else if(::arg()["dnssec"]=="process-no-validate")
3605 g_dnssecmode
=DNSSECMode::ProcessNoValidate
;
3606 else if(::arg()["dnssec"]=="process")
3607 g_dnssecmode
=DNSSECMode::Process
;
3608 else if(::arg()["dnssec"]=="validate")
3609 g_dnssecmode
=DNSSECMode::ValidateAll
;
3610 else if(::arg()["dnssec"]=="log-fail")
3611 g_dnssecmode
=DNSSECMode::ValidateForLog
;
3613 g_log
<<Logger::Error
<<"Unknown DNSSEC mode "<<::arg()["dnssec"]<<endl
;
3617 g_signatureInceptionSkew
= ::arg().asNum("signature-inception-skew");
3618 if (g_signatureInceptionSkew
< 0) {
3619 g_log
<<Logger::Error
<<"A negative value for 'signature-inception-skew' is not allowed"<<endl
;
3623 g_dnssecLogBogus
= ::arg().mustDo("dnssec-log-bogus");
3624 g_maxNSEC3Iterations
= ::arg().asNum("nsec3-max-iterations");
3626 g_maxCacheEntries
= ::arg().asNum("max-cache-entries");
3627 g_maxPacketCacheEntries
= ::arg().asNum("max-packetcache-entries");
3629 luaConfigDelayedThreads delayedLuaThreads
;
3631 loadRecursorLuaConfig(::arg()["lua-config-file"], delayedLuaThreads
);
3633 catch (PDNSException
&e
) {
3634 g_log
<<Logger::Error
<<"Cannot load Lua configuration: "<<e
.reason
<<endl
;
3639 initPublicSuffixList(::arg()["public-suffix-list-file"]);
3641 if(!::arg()["dont-query"].empty()) {
3643 stringtok(ips
, ::arg()["dont-query"], ", ");
3644 ips
.push_back("0.0.0.0");
3645 ips
.push_back("::");
3647 g_log
<<Logger::Warning
<<"Will not send queries to: ";
3648 for(vector
<string
>::const_iterator i
= ips
.begin(); i
!= ips
.end(); ++i
) {
3649 SyncRes::addDontQuery(*i
);
3651 g_log
<<Logger::Warning
<<", ";
3652 g_log
<<Logger::Warning
<<*i
;
3654 g_log
<<Logger::Warning
<<endl
;
3657 g_quiet
=::arg().mustDo("quiet");
3659 /* this needs to be done before parseACLs(), which call broadcastFunction() */
3660 g_weDistributeQueries
= ::arg().mustDo("pdns-distributes-queries");
3661 if(g_weDistributeQueries
) {
3662 g_log
<<Logger::Warning
<<"PowerDNS Recursor itself will distribute queries over threads"<<endl
;
3665 setupDelegationOnly();
3666 g_outgoingEDNSBufsize
=::arg().asNum("edns-outgoing-bufsize");
3668 if(::arg()["trace"]=="fail") {
3669 SyncRes::setDefaultLogMode(SyncRes::Store
);
3671 else if(::arg().mustDo("trace")) {
3672 SyncRes::setDefaultLogMode(SyncRes::Log
);
3673 ::arg().set("quiet")="no";
3677 string myHostname
= getHostname();
3678 if (myHostname
== "UNKNOWN"){
3679 g_log
<<Logger::Warning
<<"Unable to get the hostname, NSID and id.server values will be empty"<<endl
;
3683 SyncRes::s_minimumTTL
= ::arg().asNum("minimum-ttl-override");
3684 SyncRes::s_minimumECSTTL
= ::arg().asNum("ecs-minimum-ttl-override");
3686 SyncRes::s_nopacketcache
= ::arg().mustDo("disable-packetcache");
3688 SyncRes::s_maxnegttl
=::arg().asNum("max-negative-ttl");
3689 SyncRes::s_maxbogusttl
=::arg().asNum("max-cache-bogus-ttl");
3690 SyncRes::s_maxcachettl
=max(::arg().asNum("max-cache-ttl"), 15);
3691 SyncRes::s_packetcachettl
=::arg().asNum("packetcache-ttl");
3692 // Cap the packetcache-servfail-ttl to the packetcache-ttl
3693 uint32_t packetCacheServFailTTL
= ::arg().asNum("packetcache-servfail-ttl");
3694 SyncRes::s_packetcacheservfailttl
=(packetCacheServFailTTL
> SyncRes::s_packetcachettl
) ? SyncRes::s_packetcachettl
: packetCacheServFailTTL
;
3695 SyncRes::s_serverdownmaxfails
=::arg().asNum("server-down-max-fails");
3696 SyncRes::s_serverdownthrottletime
=::arg().asNum("server-down-throttle-time");
3697 SyncRes::s_serverID
=::arg()["server-id"];
3698 SyncRes::s_maxqperq
=::arg().asNum("max-qperq");
3699 SyncRes::s_maxtotusec
=1000*::arg().asNum("max-total-msec");
3700 SyncRes::s_maxdepth
=::arg().asNum("max-recursion-depth");
3701 SyncRes::s_rootNXTrust
= ::arg().mustDo( "root-nx-trust");
3702 if(SyncRes::s_serverID
.empty()) {
3703 SyncRes::s_serverID
= myHostname
;
3706 SyncRes::s_ecsipv4limit
= ::arg().asNum("ecs-ipv4-bits");
3707 SyncRes::s_ecsipv6limit
= ::arg().asNum("ecs-ipv6-bits");
3708 SyncRes::clearECSStats();
3710 if (!::arg().isEmpty("ecs-scope-zero-address")) {
3711 ComboAddress
scopeZero(::arg()["ecs-scope-zero-address"]);
3712 SyncRes::setECSScopeZeroAddress(Netmask(scopeZero
, scopeZero
.isIPv4() ? 32 : 128));
3716 for (const auto& addr
: g_localQueryAddresses4
) {
3717 if (!IsAnyAddress(addr
)) {
3718 SyncRes::setECSScopeZeroAddress(Netmask(addr
, 32));
3724 for (const auto& addr
: g_localQueryAddresses6
) {
3725 if (!IsAnyAddress(addr
)) {
3726 SyncRes::setECSScopeZeroAddress(Netmask(addr
, 128));
3732 SyncRes::setECSScopeZeroAddress(Netmask("127.0.0.1/32"));
3737 SyncRes::parseEDNSSubnetWhitelist(::arg()["edns-subnet-whitelist"]);
3738 SyncRes::parseEDNSSubnetAddFor(::arg()["ecs-add-for"]);
3739 g_useIncomingECS
= ::arg().mustDo("use-incoming-edns-subnet");
3741 g_XPFAcl
.toMasks(::arg()["xpf-allow-from"]);
3742 g_xpfRRCode
= ::arg().asNum("xpf-rr-code");
3744 g_networkTimeoutMsec
= ::arg().asNum("network-timeout");
3746 g_initialDomainMap
= parseAuthAndForwards();
3748 g_latencyStatSize
=::arg().asNum("latency-statistic-size");
3750 g_logCommonErrors
=::arg().mustDo("log-common-errors");
3751 g_logRPZChanges
= ::arg().mustDo("log-rpz-changes");
3753 g_anyToTcp
= ::arg().mustDo("any-to-tcp");
3754 g_udpTruncationThreshold
= ::arg().asNum("udp-truncation-threshold");
3756 g_lowercaseOutgoing
= ::arg().mustDo("lowercase-outgoing");
3758 g_numDistributorThreads
= ::arg().asNum("distributor-threads");
3759 g_numWorkerThreads
= ::arg().asNum("threads");
3760 if (g_numWorkerThreads
< 1) {
3761 g_log
<<Logger::Warning
<<"Asked to run with 0 threads, raising to 1 instead"<<endl
;
3762 g_numWorkerThreads
= 1;
3765 g_numThreads
= g_numDistributorThreads
+ g_numWorkerThreads
;
3766 g_maxMThreads
= ::arg().asNum("max-mthreads");
3768 g_gettagNeedsEDNSOptions
= ::arg().mustDo("gettag-needs-edns-options");
3770 g_statisticsInterval
= ::arg().asNum("statistics-interval");
3772 s_balancingFactor
= ::arg().asDouble("distribution-load-factor");
3775 g_reusePort
= ::arg().mustDo("reuseport");
3778 s_threadInfos
.resize(g_numDistributorThreads
+ g_numWorkerThreads
+ /* handler */ 1);
3781 if (g_weDistributeQueries
) {
3782 /* first thread is the handler, then distributors */
3783 for (unsigned int threadId
= 1; threadId
<= g_numDistributorThreads
; threadId
++) {
3784 auto& deferredAdds
= s_threadInfos
.at(threadId
).deferredAdds
;
3785 auto& tcpSockets
= s_threadInfos
.at(threadId
).tcpSockets
;
3786 makeUDPServerSockets(deferredAdds
);
3787 makeTCPServerSockets(deferredAdds
, tcpSockets
);
3791 /* first thread is the handler, there is no distributor here and workers are accepting queries */
3792 for (unsigned int threadId
= 1; threadId
<= g_numWorkerThreads
; threadId
++) {
3793 auto& deferredAdds
= s_threadInfos
.at(threadId
).deferredAdds
;
3794 auto& tcpSockets
= s_threadInfos
.at(threadId
).tcpSockets
;
3795 makeUDPServerSockets(deferredAdds
);
3796 makeTCPServerSockets(deferredAdds
, tcpSockets
);
3801 std::set
<int> tcpSockets
;
3802 /* we don't have reuseport so we can only open one socket per
3803 listening addr:port and everyone will listen on it */
3804 makeUDPServerSockets(g_deferredAdds
);
3805 makeTCPServerSockets(g_deferredAdds
, tcpSockets
);
3807 /* every listener (so distributor if g_weDistributeQueries, workers otherwise)
3808 needs to listen to the shared sockets */
3809 if (g_weDistributeQueries
) {
3810 /* first thread is the handler, then distributors */
3811 for (unsigned int threadId
= 1; threadId
<= g_numDistributorThreads
; threadId
++) {
3812 s_threadInfos
.at(threadId
).tcpSockets
= tcpSockets
;
3816 /* first thread is the handler, there is no distributor here and workers are accepting queries */
3817 for (unsigned int threadId
= 1; threadId
<= g_numWorkerThreads
; threadId
++) {
3818 s_threadInfos
.at(threadId
).tcpSockets
= tcpSockets
;
3824 // Setup newly observed domain globals
3826 #endif /* NOD_ENABLED */
3829 for(forks
= 0; forks
< ::arg().asNum("processes") - 1; ++forks
) {
3830 if(!fork()) // we are child
3834 if(::arg().mustDo("daemon")) {
3835 g_log
<<Logger::Warning
<<"Calling daemonize, going to background"<<endl
;
3836 g_log
.toConsole(Logger::Critical
);
3839 signal(SIGUSR1
,usr1Handler
);
3840 signal(SIGUSR2
,usr2Handler
);
3841 signal(SIGPIPE
,SIG_IGN
);
3845 #ifdef HAVE_LIBSODIUM
3846 if (sodium_init() == -1) {
3847 g_log
<<Logger::Error
<<"Unable to initialize sodium crypto library"<<endl
;
3852 openssl_thread_setup();
3854 /* setup rng before chroot */
3857 if(::arg()["server-id"].empty()) {
3858 ::arg().set("server-id") = myHostname
;
3862 if(!::arg()["setgid"].empty())
3863 newgid
=Utility::makeGidNumeric(::arg()["setgid"]);
3865 if(!::arg()["setuid"].empty())
3866 newuid
=Utility::makeUidNumeric(::arg()["setuid"]);
3868 Utility::dropGroupPrivs(newuid
, newgid
);
3870 if (!::arg()["chroot"].empty()) {
3873 ns
= getenv("NOTIFY_SOCKET");
3874 if (ns
!= nullptr) {
3875 g_log
<<Logger::Error
<<"Unable to chroot when running from systemd. Please disable chroot= or set the 'Type' for this service to 'simple'"<<endl
;
3879 if (chroot(::arg()["chroot"].c_str())<0 || chdir("/") < 0) {
3880 g_log
<<Logger::Error
<<"Unable to chroot to '"+::arg()["chroot"]+"': "<<strerror (errno
)<<", exiting"<<endl
;
3884 g_log
<<Logger::Info
<<"Chrooted to '"<<::arg()["chroot"]<<"'"<<endl
;
3887 s_pidfname
=::arg()["socket-dir"]+"/"+s_programname
+".pid";
3888 if(!s_pidfname
.empty())
3889 unlink(s_pidfname
.c_str()); // remove possible old pid file
3892 makeControlChannelSocket( ::arg().asNum("processes") > 1 ? forks
: -1);
3894 Utility::dropUserPrivs(newuid
);
3896 /* we might still have capabilities remaining, for example if we have been started as root
3897 without --setuid (please don't do that) or as an unprivileged user with ambient capabilities
3898 like CAP_NET_BIND_SERVICE.
3902 catch(const std::exception
& e
) {
3903 g_log
<<Logger::Warning
<<e
.what()<<endl
;
3906 startLuaConfigDelayedThreads(delayedLuaThreads
, g_luaconfs
.getCopy().generation
);
3910 g_tcpTimeout
=::arg().asNum("client-tcp-timeout");
3911 g_maxTCPPerClient
=::arg().asNum("max-tcp-per-client");
3912 g_tcpMaxQueriesPerConn
=::arg().asNum("max-tcp-queries-per-connection");
3913 s_maxUDPQueriesPerRound
=::arg().asNum("max-udp-queries-per-round");
3915 blacklistStats(StatComponent::API
, ::arg()["stats-api-blacklist"]);
3916 blacklistStats(StatComponent::Carbon
, ::arg()["stats-carbon-blacklist"]);
3917 blacklistStats(StatComponent::RecControl
, ::arg()["stats-rec-control-blacklist"]);
3918 blacklistStats(StatComponent::SNMP
, ::arg()["stats-snmp-blacklist"]);
3920 if (::arg().mustDo("snmp-agent")) {
3921 g_snmpAgent
= std::make_shared
<RecursorSNMPAgent
>("recursor", ::arg()["snmp-master-socket"]);
3925 int port
= ::arg().asNum("udp-source-port-min");
3926 if(port
< 1024 || port
> 65535){
3927 g_log
<<Logger::Error
<<"Unable to launch, udp-source-port-min is not a valid port number"<<endl
;
3928 exit(99); // this isn't going to fix itself either
3930 s_minUdpSourcePort
= port
;
3931 port
= ::arg().asNum("udp-source-port-max");
3932 if(port
< 1024 || port
> 65535 || port
< s_minUdpSourcePort
){
3933 g_log
<<Logger::Error
<<"Unable to launch, udp-source-port-max is not a valid port number or is smaller than udp-source-port-min"<<endl
;
3934 exit(99); // this isn't going to fix itself either
3936 s_maxUdpSourcePort
= port
;
3937 std::vector
<string
> parts
{};
3938 stringtok(parts
, ::arg()["udp-source-port-avoid"], ", ");
3939 for (const auto &part
: parts
)
3941 port
= std::stoi(part
);
3942 if(port
< 1024 || port
> 65535){
3943 g_log
<<Logger::Error
<<"Unable to launch, udp-source-port-avoid contains an invalid port number: "<<part
<<endl
;
3944 exit(99); // this isn't going to fix itself either
3946 s_avoidUdpSourcePorts
.insert(port
);
3949 unsigned int currentThreadId
= 1;
3950 const auto cpusMap
= parseCPUMap();
3952 if(g_numThreads
== 1) {
3953 g_log
<<Logger::Warning
<<"Operating unthreaded"<<endl
;
3955 sd_notify(0, "READY=1");
3958 /* This thread handles the web server, carbon, statistics and the control channel */
3959 auto& handlerInfos
= s_threadInfos
.at(0);
3960 handlerInfos
.isHandler
= true;
3961 handlerInfos
.thread
= std::thread(recursorThread
, 0, "main");
3963 setCPUMap(cpusMap
, currentThreadId
, pthread_self());
3965 auto& infos
= s_threadInfos
.at(currentThreadId
);
3966 infos
.isListener
= true;
3967 infos
.isWorker
= true;
3968 recursorThread(currentThreadId
++, "worker");
3972 if (g_weDistributeQueries
) {
3973 g_log
<<Logger::Warning
<<"Launching "<< g_numDistributorThreads
<<" distributor threads"<<endl
;
3974 for(unsigned int n
=0; n
< g_numDistributorThreads
; ++n
) {
3975 auto& infos
= s_threadInfos
.at(currentThreadId
);
3976 infos
.isListener
= true;
3977 infos
.thread
= std::thread(recursorThread
, currentThreadId
++, "distr");
3979 setCPUMap(cpusMap
, currentThreadId
, infos
.thread
.native_handle());
3983 g_log
<<Logger::Warning
<<"Launching "<< g_numWorkerThreads
<<" worker threads"<<endl
;
3985 for(unsigned int n
=0; n
< g_numWorkerThreads
; ++n
) {
3986 auto& infos
= s_threadInfos
.at(currentThreadId
);
3987 infos
.isListener
= g_weDistributeQueries
? false : true;
3988 infos
.isWorker
= true;
3989 infos
.thread
= std::thread(recursorThread
, currentThreadId
++, "worker");
3991 setCPUMap(cpusMap
, currentThreadId
, infos
.thread
.native_handle());
3995 sd_notify(0, "READY=1");
3998 /* This thread handles the web server, carbon, statistics and the control channel */
3999 auto& infos
= s_threadInfos
.at(0);
4000 infos
.isHandler
= true;
4001 infos
.thread
= std::thread(recursorThread
, 0, "web+stat");
4003 s_threadInfos
.at(0).thread
.join();
4008 static void* recursorThread(unsigned int n
, const string
& threadName
)
4012 auto& threadInfo
= s_threadInfos
.at(t_id
);
4014 static string threadPrefix
= "pdns-r/";
4015 setThreadName(threadPrefix
+ threadName
);
4017 SyncRes
tmp(g_now
); // make sure it allocates tsstorage before we do anything, like primeHints or so..
4018 SyncRes::setDomainMap(g_initialDomainMap
);
4019 t_allowFrom
= g_initialAllowFrom
;
4020 t_udpclientsocks
= std::unique_ptr
<UDPClientSocks
>(new UDPClientSocks());
4021 t_tcpClientCounts
= std::unique_ptr
<tcpClientCounts_t
>(new tcpClientCounts_t());
4024 t_packetCache
= std::unique_ptr
<RecursorPacketCache
>(new RecursorPacketCache());
4026 g_log
<<Logger::Warning
<<"Done priming cache with root hints"<<endl
;
4029 if (threadInfo
.isWorker
)
4031 #endif /* NOD_ENABLED */
4033 /* the listener threads handle TCP queries */
4034 if(threadInfo
.isWorker
|| threadInfo
.isListener
) {
4036 if(!::arg()["lua-dns-script"].empty()) {
4037 t_pdl
= std::make_shared
<RecursorLua4
>();
4038 t_pdl
->loadFile(::arg()["lua-dns-script"]);
4039 g_log
<<Logger::Warning
<<"Loaded 'lua' script from '"<<::arg()["lua-dns-script"]<<"'"<<endl
;
4042 catch(std::exception
&e
) {
4043 g_log
<<Logger::Error
<<"Failed to load 'lua' script from '"<<::arg()["lua-dns-script"]<<"': "<<e
.what()<<endl
;
4048 unsigned int ringsize
=::arg().asNum("stats-ringbuffer-entries") / g_numWorkerThreads
;
4050 t_remotes
= std::unique_ptr
<addrringbuf_t
>(new addrringbuf_t());
4051 if(g_weDistributeQueries
)
4052 t_remotes
->set_capacity(::arg().asNum("stats-ringbuffer-entries") / g_numDistributorThreads
);
4054 t_remotes
->set_capacity(ringsize
);
4055 t_servfailremotes
= std::unique_ptr
<addrringbuf_t
>(new addrringbuf_t());
4056 t_servfailremotes
->set_capacity(ringsize
);
4057 t_bogusremotes
= std::unique_ptr
<addrringbuf_t
>(new addrringbuf_t());
4058 t_bogusremotes
->set_capacity(ringsize
);
4059 t_largeanswerremotes
= std::unique_ptr
<addrringbuf_t
>(new addrringbuf_t());
4060 t_largeanswerremotes
->set_capacity(ringsize
);
4061 t_timeouts
= std::unique_ptr
<addrringbuf_t
>(new addrringbuf_t());
4062 t_timeouts
->set_capacity(ringsize
);
4064 t_queryring
= std::unique_ptr
<boost::circular_buffer
<pair
<DNSName
, uint16_t> > >(new boost::circular_buffer
<pair
<DNSName
, uint16_t> >());
4065 t_queryring
->set_capacity(ringsize
);
4066 t_servfailqueryring
= std::unique_ptr
<boost::circular_buffer
<pair
<DNSName
, uint16_t> > >(new boost::circular_buffer
<pair
<DNSName
, uint16_t> >());
4067 t_servfailqueryring
->set_capacity(ringsize
);
4068 t_bogusqueryring
= std::unique_ptr
<boost::circular_buffer
<pair
<DNSName
, uint16_t> > >(new boost::circular_buffer
<pair
<DNSName
, uint16_t> >());
4069 t_bogusqueryring
->set_capacity(ringsize
);
4072 MT
=std::unique_ptr
<MTasker
<PacketID
,string
> >(new MTasker
<PacketID
,string
>(::arg().asNum("stack-size")));
4073 threadInfo
.mt
= MT
.get();
4075 #ifdef HAVE_PROTOBUF
4076 /* start protobuf export threads if needed */
4077 auto luaconfsLocal
= g_luaconfs
.getLocal();
4078 checkProtobufExport(luaconfsLocal
);
4079 checkOutgoingProtobufExport(luaconfsLocal
);
4080 #endif /* HAVE_PROTOBUF */
4084 t_fdm
=getMultiplexer();
4086 if(threadInfo
.isHandler
) {
4087 if(::arg().mustDo("webserver")) {
4088 g_log
<<Logger::Warning
<< "Enabling web server" << endl
;
4090 new RecursorWebServer(t_fdm
);
4092 catch(PDNSException
&e
) {
4093 g_log
<<Logger::Error
<<"Exception: "<<e
.reason
<<endl
;
4097 g_log
<<Logger::Info
<<"Enabled '"<< t_fdm
->getName() << "' multiplexer"<<endl
;
4101 t_fdm
->addReadFD(threadInfo
.pipes
.readToThread
, handlePipeRequest
);
4102 t_fdm
->addReadFD(threadInfo
.pipes
.readQueriesToThread
, handlePipeRequest
);
4104 if (threadInfo
.isListener
) {
4106 /* then every listener has its own FDs */
4107 for(const auto deferred
: threadInfo
.deferredAdds
) {
4108 t_fdm
->addReadFD(deferred
.first
, deferred
.second
);
4112 /* otherwise all listeners are listening on the same ones */
4113 for(const auto deferred
: g_deferredAdds
) {
4114 t_fdm
->addReadFD(deferred
.first
, deferred
.second
);
4122 if(threadInfo
.isHandler
) {
4123 t_fdm
->addReadFD(s_rcc
.d_fd
, handleRCC
); // control channel
4126 unsigned int maxTcpClients
=::arg().asNum("max-tcp-clients");
4128 bool listenOnTCP(true);
4130 time_t last_stat
= 0;
4131 time_t last_carbon
=0, last_lua_maintenance
=0;
4132 time_t carbonInterval
=::arg().asNum("carbon-interval");
4133 time_t luaMaintenanceInterval
=::arg().asNum("lua-maintenance-interval");
4134 counter
.store(0); // used to periodically execute certain tasks
4136 while(MT
->schedule(&g_now
)); // MTasker letting the mthreads do their thing
4138 if(!(counter
%500)) {
4139 MT
->makeThread(houseKeeping
, 0);
4143 typedef vector
<pair
<int, FDMultiplexer::funcparam_t
> > expired_t
;
4144 expired_t expired
=t_fdm
->getTimeouts(g_now
);
4146 for(expired_t::iterator i
=expired
.begin() ; i
!= expired
.end(); ++i
) {
4147 shared_ptr
<TCPConnection
> conn
=any_cast
<shared_ptr
<TCPConnection
> >(i
->second
);
4148 if(g_logCommonErrors
)
4149 g_log
<<Logger::Warning
<<"Timeout from remote TCP client "<< conn
->d_remote
.toStringWithPort() <<endl
;
4150 t_fdm
->removeReadFD(i
->first
);
4156 if(threadInfo
.isHandler
) {
4157 if(statsWanted
|| (g_statisticsInterval
> 0 && (g_now
.tv_sec
- last_stat
) >= g_statisticsInterval
)) {
4159 last_stat
= g_now
.tv_sec
;
4162 Utility::gettimeofday(&g_now
, 0);
4164 if((g_now
.tv_sec
- last_carbon
) >= carbonInterval
) {
4165 MT
->makeThread(doCarbonDump
, 0);
4166 last_carbon
= g_now
.tv_sec
;
4169 if (t_pdl
!= nullptr) {
4170 // lua-dns-script directive is present, call the maintenance callback if needed
4171 /* remember that the listener threads handle TCP queries */
4172 if (threadInfo
.isWorker
|| threadInfo
.isListener
) {
4173 // Only on threads processing queries
4174 if(g_now
.tv_sec
- last_lua_maintenance
>= luaMaintenanceInterval
) {
4175 t_pdl
->maintenance();
4176 last_lua_maintenance
= g_now
.tv_sec
;
4182 // 'run' updates g_now for us
4184 if(threadInfo
.isListener
) {
4186 if(TCPConnection::getCurrentConnections() > maxTcpClients
) { // shutdown, too many connections
4187 for(const auto fd
: threadInfo
.tcpSockets
) {
4188 t_fdm
->removeReadFD(fd
);
4194 if(TCPConnection::getCurrentConnections() <= maxTcpClients
) { // reenable
4195 for(const auto fd
: threadInfo
.tcpSockets
) {
4196 t_fdm
->addReadFD(fd
, handleNewTCPQuestion
);
4204 catch(PDNSException
&ae
) {
4205 g_log
<<Logger::Error
<<"Exception: "<<ae
.reason
<<endl
;
4208 catch(std::exception
&e
) {
4209 g_log
<<Logger::Error
<<"STL Exception: "<<e
.what()<<endl
;
4213 g_log
<<Logger::Error
<<"any other exception in main: "<<endl
;
4218 int main(int argc
, char **argv
)
4222 g_stats
.startupTime
=time(0);
4224 versionSetProduct(ProductRecursor
);
4228 int ret
= EXIT_SUCCESS
;
4231 ::arg().set("stack-size","stack size per mthread")="200000";
4232 ::arg().set("soa-minimum-ttl","Don't change")="0";
4233 ::arg().set("no-shuffle","Don't change")="off";
4234 ::arg().set("local-port","port to listen on")="53";
4235 ::arg().set("local-address","IP addresses to listen on, separated by spaces or commas. Also accepts ports.")="127.0.0.1";
4236 ::arg().setSwitch("non-local-bind", "Enable binding to non-local addresses by using FREEBIND / BINDANY socket options")="no";
4237 ::arg().set("trace","if we should output heaps of logging. set to 'fail' to only log failing domains")="off";
4238 ::arg().set("dnssec", "DNSSEC mode: off/process-no-validate (default)/process/log-fail/validate")="process-no-validate";
4239 ::arg().set("dnssec-log-bogus", "Log DNSSEC bogus validations")="no";
4240 ::arg().set("signature-inception-skew", "Allow the signature inception to be off by this number of seconds")="60";
4241 ::arg().set("daemon","Operate as a daemon")="no";
4242 ::arg().setSwitch("write-pid","Write a PID file")="yes";
4243 ::arg().set("loglevel","Amount of logging. Higher is more. Do not set below 3")="6";
4244 ::arg().set("disable-syslog","Disable logging to syslog, useful when running inside a supervisor that logs stdout")="no";
4245 ::arg().set("log-timestamp","Print timestamps in log lines, useful to disable when running with a tool that timestamps stdout already")="yes";
4246 ::arg().set("log-common-errors","If we should log rather common errors")="no";
4247 ::arg().set("chroot","switch to chroot jail")="";
4248 ::arg().set("setgid","If set, change group id to this gid for more security")="";
4249 ::arg().set("setuid","If set, change user id to this uid for more security")="";
4250 ::arg().set("network-timeout", "Wait this number of milliseconds for network i/o")="1500";
4251 ::arg().set("threads", "Launch this number of threads")="2";
4252 ::arg().set("distributor-threads", "Launch this number of distributor threads, distributing queries to other threads")="0";
4253 ::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!
4254 ::arg().set("config-name","Name of this virtual configuration - will rename the binary image")="";
4255 ::arg().set("api-config-dir", "Directory where REST API stores config and zones") = "";
4256 ::arg().set("api-key", "Static pre-shared authentication key for access to the REST API") = "";
4257 ::arg().setSwitch("webserver", "Start a webserver (for REST API)") = "no";
4258 ::arg().set("webserver-address", "IP Address of webserver to listen on") = "127.0.0.1";
4259 ::arg().set("webserver-port", "Port of webserver to listen on") = "8082";
4260 ::arg().set("webserver-password", "Password required for accessing the webserver") = "";
4261 ::arg().set("webserver-allow-from","Webserver access is only allowed from these subnets")="127.0.0.1,::1";
4262 ::arg().set("carbon-ourname", "If set, overrides our reported hostname for carbon stats")="";
4263 ::arg().set("carbon-server", "If set, send metrics in carbon (graphite) format to this server IP address")="";
4264 ::arg().set("carbon-interval", "Number of seconds between carbon (graphite) updates")="30";
4265 ::arg().set("carbon-namespace", "If set overwrites the first part of the carbon string")="pdns";
4266 ::arg().set("carbon-instance", "If set overwrites the the instance name default")="recursor";
4268 ::arg().set("statistics-interval", "Number of seconds between printing of recursor statistics, 0 to disable")="1800";
4269 ::arg().set("quiet","Suppress logging of questions and answers")="";
4270 ::arg().set("logging-facility","Facility to log messages as. 0 corresponds to local0")="";
4271 ::arg().set("config-dir","Location of configuration directory (recursor.conf)")=SYSCONFDIR
;
4272 ::arg().set("socket-owner","Owner of socket")="";
4273 ::arg().set("socket-group","Group of socket")="";
4274 ::arg().set("socket-mode", "Permissions for socket")="";
4276 ::arg().set("socket-dir",string("Where the controlsocket will live, ")+LOCALSTATEDIR
+" when unset and not chrooted" )="";
4277 ::arg().set("delegation-only","Which domains we only accept delegations from")="";
4278 ::arg().set("query-local-address","Source IP address for sending queries")="0.0.0.0";
4279 ::arg().set("query-local-address6","Source IPv6 address for sending queries. IF UNSET, IPv6 WILL NOT BE USED FOR OUTGOING QUERIES")="";
4280 ::arg().set("client-tcp-timeout","Timeout in seconds when talking to TCP clients")="2";
4281 ::arg().set("max-mthreads", "Maximum number of simultaneous Mtasker threads")="2048";
4282 ::arg().set("max-tcp-clients","Maximum number of simultaneous TCP clients")="128";
4283 ::arg().set("server-down-max-fails","Maximum number of consecutive timeouts (and unreachables) to mark a server as down ( 0 => disabled )")="64";
4284 ::arg().set("server-down-throttle-time","Number of seconds to throttle all queries to a server after being marked as down")="60";
4285 ::arg().set("hint-file", "If set, load root hints from this file")="";
4286 ::arg().set("max-cache-entries", "If set, maximum number of entries in the main cache")="1000000";
4287 ::arg().set("max-negative-ttl", "maximum number of seconds to keep a negative cached entry in memory")="3600";
4288 ::arg().set("max-cache-bogus-ttl", "maximum number of seconds to keep a Bogus (positive or negative) cached entry in memory")="3600";
4289 ::arg().set("max-cache-ttl", "maximum number of seconds to keep a cached entry in memory")="86400";
4290 ::arg().set("packetcache-ttl", "maximum number of seconds to keep a cached entry in packetcache")="3600";
4291 ::arg().set("max-packetcache-entries", "maximum number of entries to keep in the packetcache")="500000";
4292 ::arg().set("packetcache-servfail-ttl", "maximum number of seconds to keep a cached servfail entry in packetcache")="60";
4293 ::arg().set("server-id", "Returned when queried for 'id.server' TXT or NSID, defaults to hostname, set custom or 'disabled'")="";
4294 ::arg().set("stats-ringbuffer-entries", "maximum number of packets to store statistics for")="10000";
4295 ::arg().set("version-string", "string reported on version.pdns or version.bind")=fullVersionString();
4296 ::arg().set("allow-from", "If set, only allow these comma separated netmasks to recurse")=LOCAL_NETS
;
4297 ::arg().set("allow-from-file", "If set, load allowed netmasks from this file")="";
4298 ::arg().set("entropy-source", "If set, read entropy from this file")="/dev/urandom";
4299 ::arg().set("dont-query", "If set, do not query these netmasks for DNS data")=DONT_QUERY
;
4300 ::arg().set("max-tcp-per-client", "If set, maximum number of TCP sessions per client (IP address)")="0";
4301 ::arg().set("max-tcp-queries-per-connection", "If set, maximum number of TCP queries in a TCP connection")="0";
4302 ::arg().set("spoof-nearmiss-max", "If non-zero, assume spoofing after this many near misses")="20";
4303 ::arg().set("single-socket", "If set, only use a single socket for outgoing queries")="off";
4304 ::arg().set("auth-zones", "Zones for which we have authoritative data, comma separated domain=file pairs ")="";
4305 ::arg().set("lua-config-file", "More powerful configuration options")="";
4307 ::arg().set("forward-zones", "Zones for which we forward queries, comma separated domain=ip pairs")="";
4308 ::arg().set("forward-zones-recurse", "Zones for which we forward queries with recursion bit, comma separated domain=ip pairs")="";
4309 ::arg().set("forward-zones-file", "File with (+)domain=ip pairs for forwarding")="";
4310 ::arg().set("export-etc-hosts", "If we should serve up contents from /etc/hosts")="off";
4311 ::arg().set("export-etc-hosts-search-suffix", "Also serve up the contents of /etc/hosts with this suffix")="";
4312 ::arg().set("etc-hosts-file", "Path to 'hosts' file")="/etc/hosts";
4313 ::arg().set("serve-rfc1918", "If we should be authoritative for RFC 1918 private IP space")="yes";
4314 ::arg().set("lua-dns-script", "Filename containing an optional 'lua' script that will be used to modify dns answers")="";
4315 ::arg().set("lua-maintenance-interval", "Number of seconds between calls to the lua user defined maintenance() function")="1";
4316 ::arg().set("latency-statistic-size","Number of latency values to calculate the qa-latency average")="10000";
4317 ::arg().setSwitch( "disable-packetcache", "Disable packetcache" )= "no";
4318 ::arg().set("ecs-ipv4-bits", "Number of bits of IPv4 address to pass for EDNS Client Subnet")="24";
4319 ::arg().set("ecs-ipv6-bits", "Number of bits of IPv6 address to pass for EDNS Client Subnet")="56";
4320 ::arg().set("ecs-minimum-ttl-override", "Set under adverse conditions, a minimum TTL for records in ECS-specific answers")="0";
4321 ::arg().set("edns-subnet-whitelist", "List of netmasks and domains that we should enable EDNS subnet for")="";
4322 ::arg().set("ecs-add-for", "List of client netmasks for which EDNS Client Subnet will be added")="0.0.0.0/0, ::/0, " LOCAL_NETS_INVERSE
;
4323 ::arg().set("ecs-scope-zero-address", "Address to send to whitelisted authoritative servers for incoming queries with ECS prefix-length source of 0")="";
4324 ::arg().setSwitch( "use-incoming-edns-subnet", "Pass along received EDNS Client Subnet information")="no";
4325 ::arg().setSwitch( "pdns-distributes-queries", "If PowerDNS itself should distribute queries over threads")="yes";
4326 ::arg().setSwitch( "root-nx-trust", "If set, believe that an NXDOMAIN from the root means the TLD does not exist")="yes";
4327 ::arg().setSwitch( "any-to-tcp","Answer ANY queries with tc=1, shunting to TCP" )="no";
4328 ::arg().setSwitch( "lowercase-outgoing","Force outgoing questions to lowercase")="no";
4329 ::arg().setSwitch("gettag-needs-edns-options", "If EDNS Options should be extracted before calling the gettag() hook")="no";
4330 ::arg().set("udp-truncation-threshold", "Maximum UDP response size before we truncate")="1232";
4331 ::arg().set("edns-outgoing-bufsize", "Outgoing EDNS buffer size")="1232";
4332 ::arg().set("minimum-ttl-override", "Set under adverse conditions, a minimum TTL")="0";
4333 ::arg().set("max-qperq", "Maximum outgoing queries per query")="50";
4334 ::arg().set("max-total-msec", "Maximum total wall-clock time per query in milliseconds, 0 for unlimited")="7000";
4335 ::arg().set("max-recursion-depth", "Maximum number of internal recursion calls per query, 0 for unlimited")="40";
4336 ::arg().set("max-udp-queries-per-round", "Maximum number of UDP queries processed per recvmsg() round, before returning back to normal processing")="10000";
4338 ::arg().set("include-dir","Include *.conf files from this directory")="";
4339 ::arg().set("security-poll-suffix","Domain name from which to query security update notifications")="secpoll.powerdns.com.";
4341 ::arg().setSwitch("reuseport","Enable SO_REUSEPORT allowing multiple recursors processes to listen to 1 address")="no";
4343 ::arg().setSwitch("snmp-agent", "If set, register as an SNMP agent")="no";
4344 ::arg().set("snmp-master-socket", "If set and snmp-agent is set, the socket to use to register to the SNMP master")="";
4346 std::string defaultBlacklistedStats
= "cache-bytes, packetcache-bytes, special-memory-usage";
4347 for (size_t idx
= 0; idx
< 32; idx
++) {
4348 defaultBlacklistedStats
+= ", ecs-v4-response-bits-" + std::to_string(idx
+ 1);
4350 for (size_t idx
= 0; idx
< 128; idx
++) {
4351 defaultBlacklistedStats
+= ", ecs-v6-response-bits-" + std::to_string(idx
+ 1);
4353 ::arg().set("stats-api-blacklist", "List of statistics that are disabled when retrieving the complete list of statistics via the API")=defaultBlacklistedStats
;
4354 ::arg().set("stats-carbon-blacklist", "List of statistics that are prevented from being exported via Carbon")=defaultBlacklistedStats
;
4355 ::arg().set("stats-rec-control-blacklist", "List of statistics that are prevented from being exported via rec_control get-all")=defaultBlacklistedStats
;
4356 ::arg().set("stats-snmp-blacklist", "List of statistics that are prevented from being exported via SNMP")=defaultBlacklistedStats
;
4358 ::arg().set("tcp-fast-open", "Enable TCP Fast Open support on the listening sockets, using the supplied numerical value as the queue size")="0";
4359 ::arg().set("nsec3-max-iterations", "Maximum number of iterations allowed for an NSEC3 record")="2500";
4361 ::arg().set("cpu-map", "Thread to CPU mapping, space separated thread-id=cpu1,cpu2..cpuN pairs")="";
4363 ::arg().setSwitch("log-rpz-changes", "Log additions and removals to RPZ zones at Info level")="no";
4365 ::arg().set("xpf-allow-from","XPF information is only processed from these subnets")="";
4366 ::arg().set("xpf-rr-code","XPF option code to use")="0";
4368 ::arg().set("udp-source-port-min", "Minimum UDP port to bind on")="1024";
4369 ::arg().set("udp-source-port-max", "Maximum UDP port to bind on")="65535";
4370 ::arg().set("udp-source-port-avoid", "List of comma separated UDP port number to avoid")="11211";
4371 ::arg().set("rng", "Specify random number generator to use. Valid values are auto,sodium,openssl,getrandom,arc4random,urandom.")="auto";
4372 ::arg().set("public-suffix-list-file", "Path to the Public Suffix List file, if any")="";
4373 ::arg().set("distribution-load-factor", "The load factor used when PowerDNS is distributing queries to worker threads")="0.0";
4375 ::arg().set("new-domain-tracking", "Track newly observed domains (i.e. never seen before).")="no";
4376 ::arg().set("new-domain-log", "Log newly observed domains.")="yes";
4377 ::arg().set("new-domain-lookup", "Perform a DNS lookup newly observed domains as a subdomain of the configured domain")="";
4378 ::arg().set("new-domain-history-dir", "Persist new domain tracking data here to persist between restarts")=string(NODCACHEDIR
)+"/nod";
4379 ::arg().set("new-domain-whitelist", "List of domains (and implicitly all subdomains) which will never be considered a new domain")="";
4380 ::arg().set("new-domain-db-size", "Size of the DB used to track new domains in terms of number of cells. Defaults to 67108864")="67108864";
4381 ::arg().set("new-domain-pb-tag", "If protobuf is configured, the tag to use for messages containing newly observed domains. Defaults to 'pdns-nod'")="pdns-nod";
4382 ::arg().set("unique-response-tracking", "Track unique responses (tuple of query name, type and RR).")="no";
4383 ::arg().set("unique-response-log", "Log unique responses")="yes";
4384 ::arg().set("unique-response-history-dir", "Persist unique response tracking data here to persist between restarts")=string(NODCACHEDIR
)+"/udr";
4385 ::arg().set("unique-response-db-size", "Size of the DB used to track unique responses in terms of number of cells. Defaults to 67108864")="67108864";
4386 ::arg().set("unique-response-pb-tag", "If protobuf is configured, the tag to use for messages containing unique DNS responses. Defaults to 'pdns-udr'")="pdns-udr";
4387 #endif /* NOD_ENABLED */
4388 ::arg().setCmd("help","Provide a helpful message");
4389 ::arg().setCmd("version","Print version string");
4390 ::arg().setCmd("config","Output blank configuration");
4391 g_log
.toConsole(Logger::Info
);
4392 ::arg().laxParse(argc
,argv
); // do a lax parse
4394 string configname
=::arg()["config-dir"]+"/recursor.conf";
4395 if(::arg()["config-name"]!="") {
4396 configname
=::arg()["config-dir"]+"/recursor-"+::arg()["config-name"]+".conf";
4397 s_programname
+="-"+::arg()["config-name"];
4399 cleanSlashes(configname
);
4401 if(!::arg().getCommands().empty()) {
4402 cerr
<<"Fatal: non-option on the command line, perhaps a '--setting=123' statement missed the '='?"<<endl
;
4406 if(::arg().mustDo("config")) {
4407 cout
<<::arg().configstring()<<endl
;
4411 if(!::arg().file(configname
.c_str()))
4412 g_log
<<Logger::Warning
<<"Unable to parse configuration file '"<<configname
<<"'"<<endl
;
4414 ::arg().parse(argc
,argv
);
4416 if( !::arg()["chroot"].empty() && !::arg()["api-config-dir"].empty() ) {
4417 g_log
<<Logger::Error
<<"Using chroot and enabling the API is not possible"<<endl
;
4421 if (::arg()["socket-dir"].empty()) {
4422 if (::arg()["chroot"].empty())
4423 ::arg().set("socket-dir") = LOCALSTATEDIR
;
4425 ::arg().set("socket-dir") = "/";
4428 ::arg().set("delegation-only")=toLower(::arg()["delegation-only"]);
4430 if(::arg().asNum("threads")==1) {
4431 if (::arg().mustDo("pdns-distributes-queries")) {
4432 g_log
<<Logger::Warning
<<"Only one thread, no need to distribute queries ourselves"<<endl
;
4433 ::arg().set("pdns-distributes-queries")="no";
4437 if(::arg().mustDo("pdns-distributes-queries") && ::arg().asNum("distributor-threads") <= 0) {
4438 g_log
<<Logger::Warning
<<"Asked to run with pdns-distributes-queries set but no distributor threads, raising to 1"<<endl
;
4439 ::arg().set("distributor-threads")="1";
4442 if (!::arg().mustDo("pdns-distributes-queries")) {
4443 ::arg().set("distributor-threads")="0";
4446 if(::arg().mustDo("help")) {
4447 cout
<<"syntax:"<<endl
<<endl
;
4448 cout
<<::arg().helpstring(::arg()["help"])<<endl
;
4451 if(::arg().mustDo("version")) {
4452 showProductVersion();
4453 showBuildConfiguration();
4457 Logger::Urgency logUrgency
= (Logger::Urgency
)::arg().asNum("loglevel");
4459 if (logUrgency
< Logger::Error
)
4460 logUrgency
= Logger::Error
;
4461 if(!g_quiet
&& logUrgency
< Logger::Info
) { // Logger::Info=6, Logger::Debug=7
4462 logUrgency
= Logger::Info
; // if you do --quiet=no, you need Info to also see the query log
4464 g_log
.setLoglevel(logUrgency
);
4465 g_log
.toConsole(logUrgency
);
4467 serviceMain(argc
, argv
);
4469 catch(PDNSException
&ae
) {
4470 g_log
<<Logger::Error
<<"Exception: "<<ae
.reason
<<endl
;
4473 catch(std::exception
&e
) {
4474 g_log
<<Logger::Error
<<"STL Exception: "<<e
.what()<<endl
;
4478 g_log
<<Logger::Error
<<"any other exception in main: "<<endl
;