2 * This file is part of PowerDNS or dnsdist.
3 * Copyright -- PowerDNS.COM B.V. and its contributors
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of version 2 of the GNU General Public License as
7 * published by the Free Software Foundation.
9 * In addition, for the avoidance of any doubt, permission is granted to
10 * link this program with OpenSSL and to (re)distribute the binaries
11 * produced as the result of such linking.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
30 #include "ws-recursor.hh"
32 #include "recpacketcache.hh"
34 #include "dns_random.hh"
38 #include "opensslsigners.hh"
41 #include <boost/static_assert.hpp>
44 #include "recursor_cache.hh"
45 #include "cachecleaner.hh"
52 #include "arguments.hh"
56 #include "sortlist.hh"
57 extern SortList g_sortlist
;
59 #include <boost/tuple/tuple.hpp>
60 #include <boost/tuple/tuple_comparison.hpp>
61 #include <boost/shared_array.hpp>
62 #include <boost/function.hpp>
63 #include <boost/algorithm/string.hpp>
65 #include "malloctrace.hh"
67 #include <netinet/tcp.h>
68 #include "dnsparser.hh"
69 #include "dnswriter.hh"
70 #include "dnsrecords.hh"
71 #include "zoneparser-tng.hh"
72 #include "rec_channel.hh"
77 #include "lua-recursor4.hh"
79 #include "responsestats.hh"
80 #include "secpoll-recursor.hh"
82 #include "filterpo.hh"
83 #include "rpzloader.hh"
84 #include "validate-recursor.hh"
85 #include "rec-lua-conf.hh"
86 #include "ednsoptions.hh"
89 #include "rec-protobuf.hh"
90 #include "rec-snmp.hh"
93 #include <systemd/sd-daemon.h>
96 #include "namespaces.hh"
98 typedef map
<ComboAddress
, uint32_t, ComboAddress::addressOnlyLessThan
> tcpClientCounts_t
;
100 static thread_local
std::shared_ptr
<RecursorLua4
> t_pdl
;
101 static thread_local
unsigned int t_id
;
102 static thread_local
std::shared_ptr
<Regex
> t_traceRegex
;
103 static thread_local
std::unique_ptr
<tcpClientCounts_t
> t_tcpClientCounts
;
105 thread_local
std::unique_ptr
<MT_t
> MT
; // the big MTasker
106 thread_local
std::unique_ptr
<MemRecursorCache
> t_RC
;
107 thread_local
std::unique_ptr
<RecursorPacketCache
> t_packetCache
;
108 thread_local FDMultiplexer
* t_fdm
{nullptr};
109 thread_local
std::unique_ptr
<addrringbuf_t
> t_remotes
, t_servfailremotes
, t_largeanswerremotes
;
110 thread_local
std::unique_ptr
<boost::circular_buffer
<pair
<DNSName
, uint16_t> > > t_queryring
, t_servfailqueryring
;
111 thread_local
std::shared_ptr
<NetmaskGroup
> t_allowFrom
;
113 thread_local
std::unique_ptr
<boost::uuids::random_generator
> t_uuidGenerator
;
115 __thread
struct timeval g_now
; // timestamp, updated (too) frequently
117 // for communicating with our threads
126 typedef vector
<int> tcpListenSockets_t
;
127 typedef map
<int, ComboAddress
> listenSocketsAddresses_t
; // is shared across all threads right now
128 typedef vector
<pair
<int, function
< void(int, any
&) > > > deferredAdd_t
;
130 static const ComboAddress
g_local4("0.0.0.0"), g_local6("::");
131 static vector
<ThreadPipeSet
> g_pipes
; // effectively readonly after startup
132 static tcpListenSockets_t g_tcpListenSockets
; // shared across threads, but this is fine, never written to from a thread. All threads listen on all sockets
133 static listenSocketsAddresses_t g_listenSocketsAddresses
; // is shared across all threads right now
134 static std::unordered_map
<unsigned int, deferredAdd_t
> deferredAdds
;
135 static set
<int> g_fromtosockets
; // listen sockets that use 'sendfromto()' mechanism
136 static vector
<ComboAddress
> g_localQueryAddresses4
, g_localQueryAddresses6
;
137 static AtomicCounter counter
;
138 static std::shared_ptr
<SyncRes::domainmap_t
> g_initialDomainMap
; // new threads needs this to be setup
139 static std::shared_ptr
<NetmaskGroup
> g_initialAllowFrom
; // new thread needs to be setup with this
140 static size_t g_tcpMaxQueriesPerConn
;
141 static uint64_t g_latencyStatSize
;
142 static uint32_t g_disthashseed
;
143 static unsigned int g_maxTCPPerClient
;
144 static unsigned int g_networkTimeoutMsec
;
145 static unsigned int g_maxMThreads
;
146 static unsigned int g_numWorkerThreads
;
147 static int g_tcpTimeout
;
148 static uint16_t g_udpTruncationThreshold
;
149 static std::atomic
<bool> statsWanted
;
150 static std::atomic
<bool> g_quiet
;
151 static bool g_logCommonErrors
;
152 static bool g_anyToTcp
;
153 static bool g_lowercaseOutgoing
;
154 static bool g_weDistributeQueries
; // if true, only 1 thread listens on the incoming query sockets
155 static bool g_reusePort
{false};
156 static bool g_useOneSocketPerThread
;
157 static bool g_gettagNeedsEDNSOptions
{false};
158 static time_t g_statisticsInterval
;
159 static bool g_useIncomingECS
;
161 RecursorControlChannel s_rcc
; // only active in thread 0
162 RecursorStats g_stats
;
163 string s_programname
="pdns_recursor";
165 unsigned int g_numThreads
;
166 uint16_t g_outgoingEDNSBufsize
;
168 #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"
169 // Bad Nets taken from both:
170 // http://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml
172 // http://www.iana.org/assignments/iana-ipv6-special-registry/iana-ipv6-special-registry.xhtml
173 // where such a network may not be considered a valid destination
174 #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"
175 #define DONT_QUERY LOCAL_NETS ", " BAD_NETS
177 //! used to send information to a newborn mthread
178 struct DNSComboWriter
{
179 DNSComboWriter(const char* data
, uint16_t len
, const struct timeval
& now
) : d_mdp(true, data
, len
), d_now(now
),
180 d_tcp(false), d_socket(-1)
183 void setRemote(const ComboAddress
* sa
)
188 void setLocal(const ComboAddress
& sa
)
194 void setSocket(int sock
)
199 string
getRemote() const
201 return d_remote
.toString();
204 struct timeval d_now
;
205 ComboAddress d_remote
, d_local
;
207 boost::uuids::uuid d_uuid
;
208 string d_requestorId
;
210 EDNSSubnetOpts d_ednssubnet
;
211 bool d_ecsFound
{false};
212 bool d_ecsParsed
{false};
215 unsigned int d_tag
{0};
218 shared_ptr
<TCPConnection
> d_tcpConnection
;
219 vector
<pair
<uint16_t, string
> > d_ednsOpts
;
220 std::vector
<std::string
> d_policyTags
;
221 LuaContext::LuaObject d_data
;
226 return MT
? MT
.get() : nullptr;
231 static ArgvMap theArg
;
235 unsigned int getRecursorThreadId()
245 static void handleTCPClientWritable(int fd
, FDMultiplexer::funcparam_t
& var
);
247 // -1 is error, 0 is timeout, 1 is success
248 int asendtcp(const string
& data
, Socket
* sock
)
254 t_fdm
->addWriteFD(sock
->getHandle(), handleTCPClientWritable
, pident
);
257 int ret
=MT
->waitEvent(pident
, &packet
, g_networkTimeoutMsec
);
259 if(!ret
|| ret
==-1) { // timeout
260 t_fdm
->removeWriteFD(sock
->getHandle());
262 else if(packet
.size() !=data
.size()) { // main loop tells us what it sent out, or empty in case of an error
268 static void handleTCPClientReadable(int fd
, FDMultiplexer::funcparam_t
& var
);
270 // -1 is error, 0 is timeout, 1 is success
271 int arecvtcp(string
& data
, size_t len
, Socket
* sock
, bool incompleteOkay
)
277 pident
.inIncompleteOkay
=incompleteOkay
;
278 t_fdm
->addReadFD(sock
->getHandle(), handleTCPClientReadable
, pident
);
280 int ret
=MT
->waitEvent(pident
,&data
, g_networkTimeoutMsec
);
281 if(!ret
|| ret
==-1) { // timeout
282 t_fdm
->removeReadFD(sock
->getHandle());
284 else if(data
.empty()) {// error, EOF or other
291 static void handleGenUDPQueryResponse(int fd
, FDMultiplexer::funcparam_t
& var
)
293 PacketID pident
=*any_cast
<PacketID
>(&var
);
295 ssize_t ret
=recv(fd
, resp
, sizeof(resp
), 0);
296 t_fdm
->removeReadFD(fd
);
298 string
data(resp
, (size_t) ret
);
299 MT
->sendEvent(pident
, &data
);
303 MT
->sendEvent(pident
, &empty
);
304 // cerr<<"Had some kind of error: "<<ret<<", "<<strerror(errno)<<endl;
307 string
GenUDPQueryResponse(const ComboAddress
& dest
, const string
& query
)
309 Socket
s(dest
.sin4
.sin_family
, SOCK_DGRAM
);
311 ComboAddress local
= getQueryLocalAddress(dest
.sin4
.sin_family
, 0);
320 t_fdm
->addReadFD(s
.getHandle(), handleGenUDPQueryResponse
, pident
);
324 int ret
=MT
->waitEvent(pident
,&data
, g_networkTimeoutMsec
);
326 if(!ret
|| ret
==-1) { // timeout
327 t_fdm
->removeReadFD(s
.getHandle());
329 else if(data
.empty()) {// error, EOF or other
330 // we could special case this
336 //! pick a random query local address
337 ComboAddress
getQueryLocalAddress(int family
, uint16_t port
)
340 if(family
==AF_INET
) {
341 if(g_localQueryAddresses4
.empty())
344 ret
= g_localQueryAddresses4
[dns_random(g_localQueryAddresses4
.size())];
345 ret
.sin4
.sin_port
= htons(port
);
348 if(g_localQueryAddresses6
.empty())
351 ret
= g_localQueryAddresses6
[dns_random(g_localQueryAddresses6
.size())];
353 ret
.sin6
.sin6_port
= htons(port
);
358 static void handleUDPServerResponse(int fd
, FDMultiplexer::funcparam_t
&);
360 static void setSocketBuffer(int fd
, int optname
, uint32_t size
)
363 socklen_t len
=sizeof(psize
);
365 if(!getsockopt(fd
, SOL_SOCKET
, optname
, (char*)&psize
, &len
) && psize
> size
) {
366 L
<<Logger::Error
<<"Not decreasing socket buffer size from "<<psize
<<" to "<<size
<<endl
;
370 if (setsockopt(fd
, SOL_SOCKET
, optname
, (char*)&size
, sizeof(size
)) < 0 )
371 L
<<Logger::Error
<<"Unable to raise socket buffer size to "<<size
<<": "<<strerror(errno
)<<endl
;
375 static void setSocketReceiveBuffer(int fd
, uint32_t size
)
377 setSocketBuffer(fd
, SO_RCVBUF
, size
);
380 static void setSocketSendBuffer(int fd
, uint32_t size
)
382 setSocketBuffer(fd
, SO_SNDBUF
, size
);
386 // you can ask this class for a UDP socket to send a query from
387 // this socket is not yours, don't even think about deleting it
388 // but after you call 'returnSocket' on it, don't assume anything anymore
391 unsigned int d_numsocks
;
393 UDPClientSocks() : d_numsocks(0)
397 typedef set
<int> socks_t
;
400 // returning -2 means: temporary OS error (ie, out of files), -1 means error related to remote
401 int getSocket(const ComboAddress
& toaddr
, int* fd
)
403 *fd
=makeClientSocket(toaddr
.sin4
.sin_family
);
404 if(*fd
< 0) // temporary error - receive exception otherwise
407 if(connect(*fd
, (struct sockaddr
*)(&toaddr
), toaddr
.getSocklen()) < 0) {
409 // returnSocket(*fd);
413 catch(const PDNSException
& e
) {
414 L
<<Logger::Error
<<"Error closing UDP socket after connect() failed: "<<e
.reason
<<endl
;
417 if(err
==ENETUNREACH
) // Seth "My Interfaces Are Like A Yo Yo" Arnold special
427 void returnSocket(int fd
)
429 socks_t::iterator i
=d_socks
.find(fd
);
430 if(i
==d_socks
.end()) {
431 throw PDNSException("Trying to return a socket (fd="+std::to_string(fd
)+") not in the pool");
433 returnSocketLocked(i
);
436 // return a socket to the pool, or simply erase it
437 void returnSocketLocked(socks_t::iterator
& i
)
439 if(i
==d_socks
.end()) {
440 throw PDNSException("Trying to return a socket not in the pool");
443 t_fdm
->removeReadFD(*i
);
445 catch(FDMultiplexerException
& e
) {
446 // we sometimes return a socket that has not yet been assigned to t_fdm
451 catch(const PDNSException
& e
) {
452 L
<<Logger::Error
<<"Error closing returned UDP socket: "<<e
.reason
<<endl
;
459 // returns -1 for errors which might go away, throws for ones that won't
460 static int makeClientSocket(int family
)
462 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)
464 if(ret
< 0 && errno
==EMFILE
) // this is not a catastrophic error
468 throw PDNSException("Making a socket for resolver (family = "+std::to_string(family
)+"): "+stringerror());
470 // setCloseOnExec(ret); // we're not going to exec
477 if(tries
==1) // fall back to kernel 'random'
480 port
= 1025 + dns_random(64510);
482 sin
=getQueryLocalAddress(family
, port
); // does htons for us
484 if (::bind(ret
, (struct sockaddr
*)&sin
, sin
.getSocklen()) >= 0)
488 throw PDNSException("Resolver binding to local query client socket on "+sin
.toString()+": "+stringerror());
495 static thread_local
std::unique_ptr
<UDPClientSocks
> t_udpclientsocks
;
497 /* these two functions are used by LWRes */
498 // -2 is OS error, -1 is error that depends on the remote, > 0 is success
499 int asendto(const char *data
, size_t len
, int flags
,
500 const ComboAddress
& toaddr
, uint16_t id
, const DNSName
& domain
, uint16_t qtype
, int* fd
)
504 pident
.domain
= domain
;
505 pident
.remote
= toaddr
;
508 // see if there is an existing outstanding request we can chain on to, using partial equivalence function
509 pair
<MT_t::waiters_t::iterator
, MT_t::waiters_t::iterator
> chain
=MT
->d_waiters
.equal_range(pident
, PacketIDBirthdayCompare());
511 for(; chain
.first
!= chain
.second
; chain
.first
++) {
512 if(chain
.first
->key
.fd
> -1) { // don't chain onto existing chained waiter!
514 cerr<<"Orig: "<<pident.domain<<", "<<pident.remote.toString()<<", id="<<id<<endl;
515 cerr<<"Had hit: "<< chain.first->key.domain<<", "<<chain.first->key.remote.toString()<<", id="<<chain.first->key.id
516 <<", count="<<chain.first->key.chain.size()<<", origfd: "<<chain.first->key.fd<<endl;
518 chain
.first
->key
.chain
.insert(id
); // we can chain
519 *fd
=-1; // gets used in waitEvent / sendEvent later on
524 int ret
=t_udpclientsocks
->getSocket(toaddr
, fd
);
531 t_fdm
->addReadFD(*fd
, handleUDPServerResponse
, pident
);
532 ret
= send(*fd
, data
, len
, 0);
537 t_udpclientsocks
->returnSocket(*fd
);
539 errno
= tmp
; // this is for logging purposes only
543 // -1 is error, 0 is timeout, 1 is success
544 int arecvfrom(char *data
, size_t len
, int flags
, const ComboAddress
& fromaddr
, size_t *d_len
,
545 uint16_t id
, const DNSName
& domain
, uint16_t qtype
, int fd
, struct timeval
* now
)
547 static optional
<unsigned int> nearMissLimit
;
549 nearMissLimit
=::arg().asNum("spoof-nearmiss-max");
554 pident
.domain
=domain
;
556 pident
.remote
=fromaddr
;
559 int ret
=MT
->waitEvent(pident
, &packet
, g_networkTimeoutMsec
, now
);
562 if(packet
.empty()) // means "error"
565 *d_len
=packet
.size();
566 memcpy(data
,packet
.c_str(),min(len
,*d_len
));
567 if(*nearMissLimit
&& pident
.nearMisses
> *nearMissLimit
) {
568 L
<<Logger::Error
<<"Too many ("<<pident
.nearMisses
<<" > "<<*nearMissLimit
<<") bogus answers for '"<<domain
<<"' from "<<fromaddr
.toString()<<", assuming spoof attempt."<<endl
;
569 g_stats
.spoofCount
++;
575 t_udpclientsocks
->returnSocket(fd
);
580 static void writePid(void)
582 if(!::arg().mustDo("write-pid"))
584 ofstream
of(s_pidfname
.c_str(), std::ios_base::app
);
586 of
<< Utility::getpid() <<endl
;
588 L
<<Logger::Error
<<"Writing pid for "<<Utility::getpid()<<" to "<<s_pidfname
<<" failed: "<<strerror(errno
)<<endl
;
591 TCPConnection::TCPConnection(int fd
, const ComboAddress
& addr
) : d_remote(addr
), d_fd(fd
)
593 ++s_currentConnections
;
594 (*t_tcpClientCounts
)[d_remote
]++;
597 TCPConnection::~TCPConnection()
600 if(closesocket(d_fd
) < 0)
601 L
<<Logger::Error
<<"Error closing socket for TCPConnection"<<endl
;
603 catch(const PDNSException
& e
) {
604 L
<<Logger::Error
<<"Error closing TCPConnection socket: "<<e
.reason
<<endl
;
607 if(t_tcpClientCounts
->count(d_remote
) && !(*t_tcpClientCounts
)[d_remote
]--)
608 t_tcpClientCounts
->erase(d_remote
);
609 --s_currentConnections
;
612 AtomicCounter
TCPConnection::s_currentConnections
;
614 static void handleRunningTCPQuestion(int fd
, FDMultiplexer::funcparam_t
& var
);
616 // the idea is, only do things that depend on the *response* here. Incoming accounting is on incoming.
617 static void updateResponseStats(int res
, const ComboAddress
& remote
, unsigned int packetsize
, const DNSName
* query
, uint16_t qtype
)
619 if(packetsize
> 1000 && t_largeanswerremotes
)
620 t_largeanswerremotes
->push_back(remote
);
622 case RCode::ServFail
:
623 if(t_servfailremotes
) {
624 t_servfailremotes
->push_back(remote
);
625 if(query
&& t_servfailqueryring
) // packet cache
626 t_servfailqueryring
->push_back(make_pair(*query
, qtype
));
630 case RCode::NXDomain
:
639 static string
makeLoginfo(DNSComboWriter
* dc
)
642 return "("+dc
->d_mdp
.d_qname
.toLogString()+"/"+DNSRecordContent::NumberToType(dc
->d_mdp
.d_qtype
)+" from "+(dc
->d_remote
.toString())+")";
646 return "Exception making error message for exception";
650 static void protobufLogQuery(const std::shared_ptr
<RemoteLogger
>& logger
, uint8_t maskV4
, uint8_t maskV6
, const boost::uuids::uuid
& uniqueId
, const ComboAddress
& remote
, const ComboAddress
& local
, const Netmask
& ednssubnet
, bool tcp
, uint16_t id
, size_t len
, const DNSName
& qname
, uint16_t qtype
, uint16_t qclass
, const std::vector
<std::string
>& policyTags
, const std::string
& requestorId
)
652 Netmask
requestorNM(remote
, remote
.sin4
.sin_family
== AF_INET
? maskV4
: maskV6
);
653 const ComboAddress
& requestor
= requestorNM
.getMaskedNetwork();
654 RecProtoBufMessage
message(DNSProtoBufMessage::Query
, uniqueId
, &requestor
, &local
, qname
, qtype
, qclass
, id
, tcp
, len
);
655 message
.setEDNSSubnet(ednssubnet
, ednssubnet
.isIpv4() ? maskV4
: maskV6
);
656 message
.setRequestorId(requestorId
);
658 if (!policyTags
.empty()) {
659 message
.setPolicyTags(policyTags
);
662 // cerr <<message.toDebugString()<<endl;
664 message
.serialize(str
);
665 logger
->queueData(str
);
668 static void protobufLogResponse(const std::shared_ptr
<RemoteLogger
>& logger
, const RecProtoBufMessage
& message
)
670 // cerr <<message.toDebugString()<<endl;
672 message
.serialize(str
);
673 logger
->queueData(str
);
678 * Chases the CNAME provided by the PolicyCustom RPZ policy.
680 * @param spoofed: The DNSRecord that was created by the policy, should already be added to ret
681 * @param qtype: The QType of the original query
682 * @param sr: A SyncRes
683 * @param res: An integer that will contain the RCODE of the lookup we do
684 * @param ret: A vector of DNSRecords where the result of the CNAME chase should be appended to
686 static void handleRPZCustom(const DNSRecord
& spoofed
, const QType
& qtype
, SyncRes
& sr
, int& res
, vector
<DNSRecord
>& ret
)
688 if (spoofed
.d_type
== QType::CNAME
) {
689 bool oldWantsRPZ
= sr
.getWantsRPZ();
690 sr
.setWantsRPZ(false);
691 vector
<DNSRecord
> ans
;
692 res
= sr
.beginResolve(DNSName(spoofed
.d_content
->getZoneRepresentation()), qtype
, 1, ans
);
693 for (const auto& rec
: ans
) {
694 if(rec
.d_place
== DNSResourceRecord::ANSWER
) {
698 // Reset the RPZ state of the SyncRes
699 sr
.setWantsRPZ(oldWantsRPZ
);
703 static void startDoResolve(void *p
)
705 DNSComboWriter
* dc
=(DNSComboWriter
*)p
;
708 t_queryring
->push_back(make_pair(dc
->d_mdp
.d_qname
, dc
->d_mdp
.d_qtype
));
710 uint16_t maxanswersize
= dc
->d_tcp
? 65535 : min(static_cast<uint16_t>(512), g_udpTruncationThreshold
);
713 if(getEDNSOpts(dc
->d_mdp
, &edo
)) {
716 "Values lower than 512 MUST be treated as equal to 512."
718 maxanswersize
= min(static_cast<uint16_t>(edo
.d_packetsize
>= 512 ? edo
.d_packetsize
: 512), g_udpTruncationThreshold
);
720 dc
->d_ednsOpts
= edo
.d_options
;
723 if (g_useIncomingECS
&& !dc
->d_ecsParsed
) {
724 for (const auto& o
: edo
.d_options
) {
725 if (o
.first
== EDNSOptionCode::ECS
) {
726 dc
->d_ecsFound
= getEDNSSubnetOptsFromString(o
.second
, &dc
->d_ednssubnet
);
732 /* perhaps there was no EDNS or no ECS but by now we looked */
733 dc
->d_ecsParsed
= true;
734 vector
<DNSRecord
> ret
;
735 vector
<uint8_t> packet
;
737 auto luaconfsLocal
= g_luaconfs
.getLocal();
738 // Used to tell syncres later on if we should apply NSDNAME and NSIP RPZ triggers for this query
740 RecProtoBufMessage
pbMessage(RecProtoBufMessage::Response
);
742 if (luaconfsLocal
->protobufServer
) {
743 Netmask
requestorNM(dc
->d_remote
, dc
->d_remote
.sin4
.sin_family
== AF_INET
? luaconfsLocal
->protobufMaskV4
: luaconfsLocal
->protobufMaskV6
);
744 const ComboAddress
& requestor
= requestorNM
.getMaskedNetwork();
745 pbMessage
.update(dc
->d_uuid
, &requestor
, &dc
->d_local
, dc
->d_tcp
, dc
->d_mdp
.d_header
.id
);
746 pbMessage
.setEDNSSubnet(dc
->d_ednssubnet
.source
, dc
->d_ednssubnet
.source
.isIpv4() ? luaconfsLocal
->protobufMaskV4
: luaconfsLocal
->protobufMaskV6
);
747 pbMessage
.setQuestion(dc
->d_mdp
.d_qname
, dc
->d_mdp
.d_qtype
, dc
->d_mdp
.d_qclass
);
749 #endif /* HAVE_PROTOBUF */
751 DNSPacketWriter
pw(packet
, dc
->d_mdp
.d_qname
, dc
->d_mdp
.d_qtype
, dc
->d_mdp
.d_qclass
);
753 pw
.getHeader()->aa
=0;
754 pw
.getHeader()->ra
=1;
755 pw
.getHeader()->qr
=1;
756 pw
.getHeader()->tc
=0;
757 pw
.getHeader()->id
=dc
->d_mdp
.d_header
.id
;
758 pw
.getHeader()->rd
=dc
->d_mdp
.d_header
.rd
;
759 pw
.getHeader()->cd
=dc
->d_mdp
.d_header
.cd
;
761 // DO NOT MOVE THIS CODE UP - DNSPacketWriter needs to get the original-cased version
762 if (g_lowercaseOutgoing
)
763 dc
->d_mdp
.d_qname
= dc
->d_mdp
.d_qname
.makeLowerCase();
765 uint32_t minTTL
=std::numeric_limits
<uint32_t>::max();
767 SyncRes
sr(dc
->d_now
);
770 sr
.setLuaEngine(t_pdl
);
772 sr
.d_requestor
=dc
->d_remote
; // ECS needs this too
773 if(g_dnssecmode
!= DNSSECMode::Off
) {
774 sr
.setDoDNSSEC(true);
776 // Does the requestor want DNSSEC records?
777 if(edo
.d_Z
& EDNSOpts::DNSSECOK
) {
779 g_stats
.dnssecQueries
++;
782 // Ignore the client-set CD flag
783 pw
.getHeader()->cd
=0;
786 sr
.setInitialRequestId(dc
->d_uuid
);
788 if (g_useIncomingECS
) {
789 sr
.setIncomingECSFound(dc
->d_ecsFound
);
790 if (dc
->d_ecsFound
) {
791 sr
.setIncomingECS(dc
->d_ednssubnet
);
795 bool tracedQuery
=false; // we could consider letting Lua know about this too
796 bool variableAnswer
= false;
797 bool shouldNotValidate
= false;
799 /* preresolve expects res (dq.rcode) to be set to RCode::NoError by default */
800 int res
= RCode::NoError
;
801 DNSFilterEngine::Policy appliedPolicy
;
803 RecursorLua4::DNSQuestion
dq(dc
->d_remote
, dc
->d_local
, dc
->d_mdp
.d_qname
, dc
->d_mdp
.d_qtype
, dc
->d_tcp
, variableAnswer
, wantsRPZ
);
804 dq
.ednsFlags
= &edo
.d_Z
;
805 dq
.ednsOptions
= &dc
->d_ednsOpts
;
807 dq
.discardedPolicies
= &sr
.d_discardedPolicies
;
808 dq
.policyTags
= &dc
->d_policyTags
;
809 dq
.appliedPolicy
= &appliedPolicy
;
810 dq
.currentRecords
= &ret
;
811 dq
.dh
= &dc
->d_mdp
.d_header
;
812 dq
.data
= dc
->d_data
;
814 dq
.requestorId
= dc
->d_requestorId
;
817 if(dc
->d_mdp
.d_qtype
==QType::ANY
&& !dc
->d_tcp
&& g_anyToTcp
) {
818 pw
.getHeader()->tc
= 1;
820 variableAnswer
= true;
824 if(t_traceRegex
&& t_traceRegex
->match(dc
->d_mdp
.d_qname
.toString())) {
825 sr
.setLogMode(SyncRes::Store
);
830 if(!g_quiet
|| tracedQuery
) {
831 L
<<Logger::Warning
<<t_id
<<" ["<<MT
->getTid()<<"/"<<MT
->numProcesses()<<"] " << (dc
->d_tcp
? "TCP " : "") << "question for '"<<dc
->d_mdp
.d_qname
<<"|"
832 <<DNSRecordContent::NumberToType(dc
->d_mdp
.d_qtype
)<<"' from "<<dc
->getRemote();
833 if(!dc
->d_ednssubnet
.source
.empty()) {
834 L
<<" (ecs "<<dc
->d_ednssubnet
.source
.toString()<<")";
839 sr
.setId(MT
->getTid());
840 if(!dc
->d_mdp
.d_header
.rd
)
844 t_pdl
->prerpz(dq
, res
);
847 // Check if the query has a policy attached to it
849 appliedPolicy
= luaconfsLocal
->dfe
.getQueryPolicy(dc
->d_mdp
.d_qname
, dc
->d_remote
, sr
.d_discardedPolicies
);
852 // if there is a RecursorLua active, and it 'took' the query in preResolve, we don't launch beginResolve
853 if(!t_pdl
|| !t_pdl
->preresolve(dq
, res
)) {
855 sr
.setWantsRPZ(wantsRPZ
);
857 switch(appliedPolicy
.d_kind
) {
858 case DNSFilterEngine::PolicyKind::NoAction
:
860 case DNSFilterEngine::PolicyKind::Drop
:
861 g_stats
.policyDrops
++;
862 g_stats
.policyResults
[appliedPolicy
.d_kind
]++;
866 case DNSFilterEngine::PolicyKind::NXDOMAIN
:
867 g_stats
.policyResults
[appliedPolicy
.d_kind
]++;
870 case DNSFilterEngine::PolicyKind::NODATA
:
871 g_stats
.policyResults
[appliedPolicy
.d_kind
]++;
874 case DNSFilterEngine::PolicyKind::Custom
:
875 g_stats
.policyResults
[appliedPolicy
.d_kind
]++;
877 spoofed
=appliedPolicy
.getCustomRecord(dc
->d_mdp
.d_qname
);
878 ret
.push_back(spoofed
);
879 handleRPZCustom(spoofed
, QType(dc
->d_mdp
.d_qtype
), sr
, res
, ret
);
881 case DNSFilterEngine::PolicyKind::Truncate
:
883 g_stats
.policyResults
[appliedPolicy
.d_kind
]++;
885 pw
.getHeader()->tc
=1;
892 // Query got not handled for QNAME Policy reasons, now actually go out to find an answer
894 res
= sr
.beginResolve(dc
->d_mdp
.d_qname
, QType(dc
->d_mdp
.d_qtype
), dc
->d_mdp
.d_qclass
, ret
);
895 shouldNotValidate
= sr
.wasOutOfBand();
897 catch(ImmediateServFailException
&e
) {
898 if(g_logCommonErrors
)
899 L
<<Logger::Notice
<<"Sending SERVFAIL to "<<dc
->getRemote()<<" during resolve of '"<<dc
->d_mdp
.d_qname
<<"' because: "<<e
.reason
<<endl
;
900 res
= RCode::ServFail
;
903 // During lookup, an NSDNAME or NSIP trigger was hit in RPZ
904 if (res
== -2) { // XXX This block should be macro'd, it is repeated post-resolve.
905 appliedPolicy
= sr
.d_appliedPolicy
;
906 g_stats
.policyResults
[appliedPolicy
.d_kind
]++;
907 switch(appliedPolicy
.d_kind
) {
908 case DNSFilterEngine::PolicyKind::NoAction
: // This can never happen
909 throw PDNSException("NoAction policy returned while a NSDNAME or NSIP trigger was hit");
910 case DNSFilterEngine::PolicyKind::Drop
:
911 g_stats
.policyDrops
++;
915 case DNSFilterEngine::PolicyKind::NXDOMAIN
:
920 case DNSFilterEngine::PolicyKind::NODATA
:
925 case DNSFilterEngine::PolicyKind::Truncate
:
929 pw
.getHeader()->tc
=1;
934 case DNSFilterEngine::PolicyKind::Custom
:
937 spoofed
=appliedPolicy
.getCustomRecord(dc
->d_mdp
.d_qname
);
938 ret
.push_back(spoofed
);
939 handleRPZCustom(spoofed
, QType(dc
->d_mdp
.d_qtype
), sr
, res
, ret
);
945 appliedPolicy
= luaconfsLocal
->dfe
.getPostPolicy(ret
, sr
.d_discardedPolicies
);
949 if(res
== RCode::NoError
) {
951 for(; i
!= ret
.cend(); ++i
)
952 if(i
->d_type
== dc
->d_mdp
.d_qtype
&& i
->d_place
== DNSResourceRecord::ANSWER
)
954 if(i
== ret
.cend() && t_pdl
->nodata(dq
, res
))
955 shouldNotValidate
= true;
958 else if(res
== RCode::NXDomain
&& t_pdl
->nxdomain(dq
, res
))
959 shouldNotValidate
= true;
961 if(t_pdl
->postresolve(dq
, res
))
962 shouldNotValidate
= true;
965 if (wantsRPZ
) { //XXX This block is repeated, see above
966 g_stats
.policyResults
[appliedPolicy
.d_kind
]++;
967 switch(appliedPolicy
.d_kind
) {
968 case DNSFilterEngine::PolicyKind::NoAction
:
970 case DNSFilterEngine::PolicyKind::Drop
:
971 g_stats
.policyDrops
++;
975 case DNSFilterEngine::PolicyKind::NXDOMAIN
:
980 case DNSFilterEngine::PolicyKind::NODATA
:
985 case DNSFilterEngine::PolicyKind::Truncate
:
989 pw
.getHeader()->tc
=1;
994 case DNSFilterEngine::PolicyKind::Custom
:
997 spoofed
=appliedPolicy
.getCustomRecord(dc
->d_mdp
.d_qname
);
998 ret
.push_back(spoofed
);
999 handleRPZCustom(spoofed
, QType(dc
->d_mdp
.d_qtype
), sr
, res
, ret
);
1005 if(res
== PolicyDecision::DROP
) {
1006 g_stats
.policyDrops
++;
1011 if(tracedQuery
|| res
== PolicyDecision::PASS
|| res
== RCode::ServFail
|| pw
.getHeader()->rcode
== RCode::ServFail
)
1013 string
trace(sr
.getTrace());
1014 if(!trace
.empty()) {
1015 vector
<string
> lines
;
1016 boost::split(lines
, trace
, boost::is_any_of("\n"));
1017 for(const string
& line
: lines
) {
1019 L
<<Logger::Warning
<< line
<< endl
;
1024 if(res
== PolicyDecision::PASS
) { // XXX what does this MEAN? Why servfail on PASS?
1025 pw
.getHeader()->rcode
=RCode::ServFail
;
1026 // no commit here, because no record
1027 g_stats
.servFails
++;
1030 pw
.getHeader()->rcode
=res
;
1032 // Does the validation mode or query demand validation?
1033 if(!shouldNotValidate
&& (g_dnssecmode
== DNSSECMode::ValidateAll
|| g_dnssecmode
==DNSSECMode::ValidateForLog
|| ((dc
->d_mdp
.d_header
.ad
|| DNSSECOK
) && g_dnssecmode
==DNSSECMode::Process
))) {
1036 L
<<Logger::Warning
<<"Starting validation of answer to "<<dc
->d_mdp
.d_qname
<<"|"<<QType(dc
->d_mdp
.d_qtype
).getName()<<" for "<<dc
->d_remote
.toStringWithPort()<<endl
;
1039 auto state
= sr
.getValidationState();
1041 if(state
== Secure
) {
1043 L
<<Logger::Warning
<<"Answer to "<<dc
->d_mdp
.d_qname
<<"|"<<QType(dc
->d_mdp
.d_qtype
).getName()<<" for "<<dc
->d_remote
.toStringWithPort()<<" validates correctly"<<endl
;
1046 // Is the query source interested in the value of the ad-bit?
1047 if (dc
->d_mdp
.d_header
.ad
|| DNSSECOK
)
1048 pw
.getHeader()->ad
=1;
1050 else if(state
== Insecure
) {
1052 L
<<Logger::Warning
<<"Answer to "<<dc
->d_mdp
.d_qname
<<"|"<<QType(dc
->d_mdp
.d_qtype
).getName()<<" for "<<dc
->d_remote
.toStringWithPort()<<" validates as Insecure"<<endl
;
1055 pw
.getHeader()->ad
=0;
1057 else if(state
== Bogus
) {
1058 if(g_dnssecLogBogus
|| sr
.doLog() || g_dnssecmode
== DNSSECMode::ValidateForLog
) {
1059 L
<<Logger::Warning
<<"Answer to "<<dc
->d_mdp
.d_qname
<<"|"<<QType(dc
->d_mdp
.d_qtype
).getName()<<" for "<<dc
->d_remote
.toStringWithPort()<<" validates as Bogus"<<endl
;
1062 // Does the query or validation mode sending out a SERVFAIL on validation errors?
1063 if(!pw
.getHeader()->cd
&& (g_dnssecmode
== DNSSECMode::ValidateAll
|| dc
->d_mdp
.d_header
.ad
|| DNSSECOK
)) {
1065 L
<<Logger::Warning
<<"Sending out SERVFAIL for "<<dc
->d_mdp
.d_qname
<<"|"<<QType(dc
->d_mdp
.d_qtype
).getName()<<" because recursor or query demands it for Bogus results"<<endl
;
1068 pw
.getHeader()->rcode
=RCode::ServFail
;
1072 L
<<Logger::Warning
<<"Not sending out SERVFAIL for "<<dc
->d_mdp
.d_qname
<<"|"<<QType(dc
->d_mdp
.d_qtype
).getName()<<" Bogus validation since neither config nor query demands this"<<endl
;
1077 catch(ImmediateServFailException
&e
) {
1078 if(g_logCommonErrors
)
1079 L
<<Logger::Notice
<<"Sending SERVFAIL to "<<dc
->getRemote()<<" during validation of '"<<dc
->d_mdp
.d_qname
<<"|"<<QType(dc
->d_mdp
.d_qtype
).getName()<<"' because: "<<e
.reason
<<endl
;
1080 pw
.getHeader()->rcode
=RCode::ServFail
;
1086 orderAndShuffle(ret
);
1087 if(auto sl
= luaconfsLocal
->sortlist
.getOrderCmp(dc
->d_remote
)) {
1088 sort(ret
.begin(), ret
.end(), *sl
);
1089 variableAnswer
=true;
1093 ret
.push_back(makeOpt(edo
.d_packetsize
, 0, edo
.d_Z
));
1096 bool needCommit
= false;
1097 for(auto i
=ret
.cbegin(); i
!=ret
.cend(); ++i
) {
1099 ( i
->d_type
== QType::NSEC3
||
1101 ( i
->d_type
== QType::RRSIG
|| i
->d_type
==QType::NSEC
) &&
1103 ( dc
->d_mdp
.d_qtype
!= i
->d_type
&& dc
->d_mdp
.d_qtype
!= QType::ANY
) ||
1104 i
->d_place
!= DNSResourceRecord::ANSWER
1112 pw
.startRecord(i
->d_name
, i
->d_type
, i
->d_ttl
, i
->d_class
, i
->d_place
);
1113 if(i
->d_type
!= QType::OPT
) // their TTL ain't real
1114 minTTL
= min(minTTL
, i
->d_ttl
);
1115 i
->d_content
->toPacket(pw
);
1116 if(pw
.size() > static_cast<size_t>(maxanswersize
)) {
1118 if(i
->d_place
==DNSResourceRecord::ANSWER
) // only truncate if we actually omitted parts of the answer
1120 pw
.getHeader()->tc
=1;
1123 goto sendit
; // need to jump over pw.commit
1126 #ifdef HAVE_PROTOBUF
1127 if(luaconfsLocal
->protobufServer
&& (i
->d_type
== QType::A
|| i
->d_type
== QType::AAAA
|| i
->d_type
== QType::CNAME
)) {
1128 pbMessage
.addRR(*i
);
1137 g_rs
.submitResponse(dc
->d_mdp
.d_qtype
, packet
.size(), !dc
->d_tcp
);
1138 updateResponseStats(res
, dc
->d_remote
, packet
.size(), &dc
->d_mdp
.d_qname
, dc
->d_mdp
.d_qtype
);
1139 #ifdef HAVE_PROTOBUF
1140 if (luaconfsLocal
->protobufServer
&& (!luaconfsLocal
->protobufTaggedOnly
|| (appliedPolicy
.d_name
&& !appliedPolicy
.d_name
->empty()) || !dc
->d_policyTags
.empty())) {
1141 pbMessage
.setBytes(packet
.size());
1142 pbMessage
.setResponseCode(pw
.getHeader()->rcode
);
1143 if (appliedPolicy
.d_name
) {
1144 pbMessage
.setAppliedPolicy(*appliedPolicy
.d_name
);
1146 pbMessage
.setPolicyTags(dc
->d_policyTags
);
1147 pbMessage
.setQueryTime(dc
->d_now
.tv_sec
, dc
->d_now
.tv_usec
);
1148 pbMessage
.setRequestorId(dq
.requestorId
);
1149 protobufLogResponse(luaconfsLocal
->protobufServer
, pbMessage
);
1156 fillMSGHdr(&msgh
, &iov
, cbuf
, 0, (char*)&*packet
.begin(), packet
.size(), &dc
->d_remote
);
1157 msgh
.msg_control
=NULL
;
1159 if(g_fromtosockets
.count(dc
->d_socket
)) {
1160 addCMsgSrcAddr(&msgh
, cbuf
, &dc
->d_local
, 0);
1162 if(sendmsg(dc
->d_socket
, &msgh
, 0) < 0 && g_logCommonErrors
)
1163 L
<<Logger::Warning
<<"Sending UDP reply to client "<<dc
->d_remote
.toStringWithPort()<<" failed with: "<<strerror(errno
)<<endl
;
1164 if(!SyncRes::s_nopacketcache
&& !variableAnswer
&& !sr
.wasVariable() ) {
1165 t_packetCache
->insertResponsePacket(dc
->d_tag
, dc
->d_qhash
, dc
->d_mdp
.d_qname
, dc
->d_mdp
.d_qtype
, dc
->d_mdp
.d_qclass
,
1166 string((const char*)&*packet
.begin(), packet
.size()),
1168 pw
.getHeader()->rcode
== RCode::ServFail
? SyncRes::s_packetcacheservfailttl
:
1169 min(minTTL
,SyncRes::s_packetcachettl
),
1172 // else cerr<<"Not putting in packet cache: "<<sr.wasVariable()<<endl;
1176 buf
[0]=packet
.size()/256;
1177 buf
[1]=packet
.size()%256;
1179 Utility::iovec iov
[2];
1181 iov
[0].iov_base
=(void*)buf
; iov
[0].iov_len
=2;
1182 iov
[1].iov_base
=(void*)&*packet
.begin(); iov
[1].iov_len
= packet
.size();
1184 int wret
=Utility::writev(dc
->d_socket
, iov
, 2);
1188 L
<<Logger::Error
<<"EOF writing TCP answer to "<<dc
->getRemote()<<endl
;
1190 L
<<Logger::Error
<<"Error writing TCP answer to "<<dc
->getRemote()<<": "<< strerror(errno
) <<endl
;
1191 else if((unsigned int)wret
!= 2 + packet
.size())
1192 L
<<Logger::Error
<<"Oops, partial answer sent to "<<dc
->getRemote()<<" for "<<dc
->d_mdp
.d_qname
<<" (size="<< (2 + packet
.size()) <<", sent "<<wret
<<")"<<endl
;
1196 // update tcp connection status, either by closing or moving to 'BYTE0'
1199 // no need to remove us from FDM, we weren't there
1203 dc
->d_tcpConnection
->queriesCount
++;
1204 if (g_tcpMaxQueriesPerConn
&& dc
->d_tcpConnection
->queriesCount
>= g_tcpMaxQueriesPerConn
) {
1208 dc
->d_tcpConnection
->state
=TCPConnection::BYTE0
;
1209 Utility::gettimeofday(&g_now
, 0); // needs to be updated
1210 t_fdm
->addReadFD(dc
->d_socket
, handleRunningTCPQuestion
, dc
->d_tcpConnection
);
1211 t_fdm
->setReadTTD(dc
->d_socket
, g_now
, g_tcpTimeout
);
1217 L
<<Logger::Error
<<t_id
<<" ["<<MT
->getTid()<<"/"<<MT
->numProcesses()<<"] answer to "<<(dc
->d_mdp
.d_header
.rd
?"":"non-rd ")<<"question '"<<dc
->d_mdp
.d_qname
<<"|"<<DNSRecordContent::NumberToType(dc
->d_mdp
.d_qtype
);
1218 L
<<"': "<<ntohs(pw
.getHeader()->ancount
)<<" answers, "<<ntohs(pw
.getHeader()->arcount
)<<" additional, took "<<sr
.d_outqueries
<<" packets, "<<
1219 sr
.d_totUsec
/1000.0<<" ms, "<<
1220 sr
.d_throttledqueries
<<" throttled, "<<sr
.d_timeouts
<<" timeouts, "<<sr
.d_tcpoutqueries
<<" tcp connections, rcode="<<res
<<endl
;
1223 sr
.d_outqueries
? t_RC
->cacheMisses
++ : t_RC
->cacheHits
++;
1224 float spent
=makeFloat(sr
.getNow()-dc
->d_now
);
1226 g_stats
.answers0_1
++;
1227 else if(spent
< 0.010)
1228 g_stats
.answers1_10
++;
1229 else if(spent
< 0.1)
1230 g_stats
.answers10_100
++;
1231 else if(spent
< 1.0)
1232 g_stats
.answers100_1000
++;
1234 g_stats
.answersSlow
++;
1236 uint64_t newLat
=(uint64_t)(spent
*1000000);
1237 newLat
= min(newLat
,(uint64_t)(((uint64_t) g_networkTimeoutMsec
)*1000)); // outliers of several minutes exist..
1238 g_stats
.avgLatencyUsec
=(1-1.0/g_latencyStatSize
)*g_stats
.avgLatencyUsec
+ (float)newLat
/g_latencyStatSize
;
1239 // no worries, we do this for packet cache hits elsewhere
1240 // cout<<dc->d_mdp.d_qname<<"\t"<<MT->getUsec()<<"\t"<<sr.d_outqueries<<endl;
1244 catch(PDNSException
&ae
) {
1245 L
<<Logger::Error
<<"startDoResolve problem "<<makeLoginfo(dc
)<<": "<<ae
.reason
<<endl
;
1248 catch(MOADNSException
& e
) {
1249 L
<<Logger::Error
<<"DNS parser error "<<makeLoginfo(dc
) <<": "<<dc
->d_mdp
.d_qname
<<", "<<e
.what()<<endl
;
1252 catch(std::exception
& e
) {
1253 L
<<Logger::Error
<<"STL error "<< makeLoginfo(dc
)<<": "<<e
.what();
1255 // Luawrapper nests the exception from Lua, so we unnest it here
1257 std::rethrow_if_nested(e
);
1258 } catch(const std::exception
& e
) {
1259 L
<<". Extra info: "<<e
.what();
1266 L
<<Logger::Error
<<"Any other exception in a resolver context "<< makeLoginfo(dc
) <<endl
;
1269 g_stats
.maxMThreadStackUsage
= max(MT
->getMaxStackUsage(), g_stats
.maxMThreadStackUsage
);
1272 static void makeControlChannelSocket(int processNum
=-1)
1274 string sockname
=::arg()["socket-dir"]+"/"+s_programname
;
1276 sockname
+= "."+std::to_string(processNum
);
1277 sockname
+=".controlsocket";
1278 s_rcc
.listen(sockname
);
1283 if (!::arg().isEmpty("socket-group"))
1284 sockgroup
=::arg().asGid("socket-group");
1285 if (!::arg().isEmpty("socket-owner"))
1286 sockowner
=::arg().asUid("socket-owner");
1288 if (sockgroup
> -1 || sockowner
> -1) {
1289 if(chown(sockname
.c_str(), sockowner
, sockgroup
) < 0) {
1290 unixDie("Failed to chown control socket");
1294 // do mode change if socket-mode is given
1295 if(!::arg().isEmpty("socket-mode")) {
1296 mode_t sockmode
=::arg().asMode("socket-mode");
1297 if(chmod(sockname
.c_str(), sockmode
) < 0) {
1298 unixDie("Failed to chmod control socket");
1303 static bool getQNameAndSubnet(const std::string
& question
, DNSName
* dnsname
, uint16_t* qtype
, uint16_t* qclass
, EDNSSubnetOpts
* ednssubnet
, std::map
<uint16_t, EDNSOptionView
>* options
)
1306 const struct dnsheader
* dh
= (struct dnsheader
*)question
.c_str();
1307 size_t questionLen
= question
.length();
1308 unsigned int consumed
=0;
1309 *dnsname
=DNSName(question
.c_str(), questionLen
, sizeof(dnsheader
), false, qtype
, qclass
, &consumed
);
1311 size_t pos
= sizeof(dnsheader
)+consumed
+4;
1312 /* at least OPT root label (1), type (2), class (2) and ttl (4) + OPT RR rdlen (2)
1314 if(ntohs(dh
->arcount
) == 1 && questionLen
> pos
+ 11) { // this code can extract one (1) EDNS Subnet option
1315 /* OPT root label (1) followed by type (2) */
1316 if(question
.at(pos
)==0 && question
.at(pos
+1)==0 && question
.at(pos
+2)==QType::OPT
) {
1318 char* ecsStart
= nullptr;
1320 int res
= getEDNSOption((char*)question
.c_str()+pos
+9, questionLen
- pos
- 9, EDNSOptionCode::ECS
, &ecsStart
, &ecsLen
);
1321 if (res
== 0 && ecsLen
> 4) {
1323 if(getEDNSSubnetOptsFromString(ecsStart
+ 4, ecsLen
- 4, &eso
)) {
1330 int res
= getEDNSOptions((char*)question
.c_str()+pos
+9, questionLen
- pos
- 9, *options
);
1332 const auto& it
= options
->find(EDNSOptionCode::ECS
);
1333 if (it
!= options
->end() && it
->second
.content
!= nullptr && it
->second
.size
> 0) {
1335 if(getEDNSSubnetOptsFromString(it
->second
.content
, it
->second
.size
, &eso
)) {
1347 static void handleRunningTCPQuestion(int fd
, FDMultiplexer::funcparam_t
& var
)
1349 shared_ptr
<TCPConnection
> conn
=any_cast
<shared_ptr
<TCPConnection
> >(var
);
1351 if(conn
->state
==TCPConnection::BYTE0
) {
1352 ssize_t bytes
=recv(conn
->getFD(), conn
->data
, 2, 0);
1354 conn
->state
=TCPConnection::BYTE1
;
1356 conn
->qlen
=(((unsigned char)conn
->data
[0]) << 8)+ (unsigned char)conn
->data
[1];
1358 conn
->state
=TCPConnection::GETQUESTION
;
1360 if(!bytes
|| bytes
< 0) {
1361 t_fdm
->removeReadFD(fd
);
1365 else if(conn
->state
==TCPConnection::BYTE1
) {
1366 ssize_t bytes
=recv(conn
->getFD(), conn
->data
+1, 1, 0);
1368 conn
->state
=TCPConnection::GETQUESTION
;
1369 conn
->qlen
=(((unsigned char)conn
->data
[0]) << 8)+ (unsigned char)conn
->data
[1];
1372 if(!bytes
|| bytes
< 0) {
1373 if(g_logCommonErrors
)
1374 L
<<Logger::Error
<<"TCP client "<< conn
->d_remote
.toString() <<" disconnected after first byte"<<endl
;
1375 t_fdm
->removeReadFD(fd
);
1379 else if(conn
->state
==TCPConnection::GETQUESTION
) {
1380 ssize_t bytes
=recv(conn
->getFD(), conn
->data
+ conn
->bytesread
, conn
->qlen
- conn
->bytesread
, 0);
1381 if(!bytes
|| bytes
< 0 || bytes
> std::numeric_limits
<std::uint16_t>::max()) {
1382 L
<<Logger::Error
<<"TCP client "<< conn
->d_remote
.toString() <<" disconnected while reading question body"<<endl
;
1383 t_fdm
->removeReadFD(fd
);
1386 conn
->bytesread
+=(uint16_t)bytes
;
1387 if(conn
->bytesread
==conn
->qlen
) {
1388 t_fdm
->removeReadFD(fd
); // should no longer awake ourselves when there is data to read
1390 DNSComboWriter
* dc
=nullptr;
1392 dc
=new DNSComboWriter(conn
->data
, conn
->qlen
, g_now
);
1394 catch(MOADNSException
&mde
) {
1395 g_stats
.clientParseError
++;
1396 if(g_logCommonErrors
)
1397 L
<<Logger::Error
<<"Unable to parse packet from TCP client "<< conn
->d_remote
.toString() <<endl
;
1400 dc
->d_tcpConnection
= conn
; // carry the torch
1401 dc
->setSocket(conn
->getFD()); // this is the only time a copy is made of the actual fd
1403 dc
->setRemote(&conn
->d_remote
);
1405 memset(&dest
, 0, sizeof(dest
));
1406 dest
.sin4
.sin_family
= conn
->d_remote
.sin4
.sin_family
;
1407 socklen_t len
= dest
.getSocklen();
1408 getsockname(conn
->getFD(), (sockaddr
*)&dest
, &len
); // if this fails, we're ok with it
1413 bool needECS
= false;
1415 #ifdef HAVE_PROTOBUF
1416 auto luaconfsLocal
= g_luaconfs
.getLocal();
1417 if (luaconfsLocal
->protobufServer
) {
1422 if(needECS
|| (t_pdl
&& t_pdl
->d_gettag
)) {
1425 std::map
<uint16_t, EDNSOptionView
> ednsOptions
;
1426 dc
->d_ecsParsed
= true;
1427 dc
->d_ecsFound
= getQNameAndSubnet(std::string(conn
->data
, conn
->qlen
), &qname
, &qtype
, &qclass
, &dc
->d_ednssubnet
, g_gettagNeedsEDNSOptions
? &ednsOptions
: nullptr);
1429 if(t_pdl
&& t_pdl
->d_gettag
) {
1431 dc
->d_tag
= t_pdl
->gettag(conn
->d_remote
, dc
->d_ednssubnet
.source
, dest
, qname
, qtype
, &dc
->d_policyTags
, dc
->d_data
, ednsOptions
, true, requestorId
);
1433 catch(std::exception
& e
) {
1434 if(g_logCommonErrors
)
1435 L
<<Logger::Warning
<<"Error parsing a query packet qname='"<<qname
<<"' for tag determination, setting tag=0: "<<e
.what()<<endl
;
1439 catch(std::exception
& e
)
1441 if(g_logCommonErrors
)
1442 L
<<Logger::Warning
<<"Error parsing a query packet for tag determination, setting tag=0: "<<e
.what()<<endl
;
1445 #ifdef HAVE_PROTOBUF
1446 if(luaconfsLocal
->protobufServer
|| luaconfsLocal
->outgoingProtobufServer
) {
1447 dc
->d_requestorId
= requestorId
;
1448 dc
->d_uuid
= (*t_uuidGenerator
)();
1451 if(luaconfsLocal
->protobufServer
) {
1453 const struct dnsheader
* dh
= (const struct dnsheader
*) conn
->data
;
1455 if (!luaconfsLocal
->protobufTaggedOnly
) {
1456 protobufLogQuery(luaconfsLocal
->protobufServer
, luaconfsLocal
->protobufMaskV4
, luaconfsLocal
->protobufMaskV6
, dc
->d_uuid
, conn
->d_remote
, dest
, dc
->d_ednssubnet
.source
, true, dh
->id
, conn
->qlen
, qname
, qtype
, qclass
, dc
->d_policyTags
, dc
->d_requestorId
);
1459 catch(std::exception
& e
) {
1460 if(g_logCommonErrors
)
1461 L
<<Logger::Warning
<<"Error parsing a TCP query packet for edns subnet: "<<e
.what()<<endl
;
1465 if(dc
->d_mdp
.d_header
.qr
) {
1467 g_stats
.ignoredCount
++;
1468 L
<<Logger::Error
<<"Ignoring answer from TCP client "<< conn
->d_remote
.toString() <<" on server socket!"<<endl
;
1471 if(dc
->d_mdp
.d_header
.opcode
) {
1473 g_stats
.ignoredCount
++;
1474 L
<<Logger::Error
<<"Ignoring non-query opcode from TCP client "<< conn
->d_remote
.toString() <<" on server socket!"<<endl
;
1479 ++g_stats
.tcpqcounter
;
1480 MT
->makeThread(startDoResolve
, dc
); // deletes dc, will set state to BYTE0 again
1487 //! Handle new incoming TCP connection
1488 static void handleNewTCPQuestion(int fd
, FDMultiplexer::funcparam_t
& )
1491 socklen_t addrlen
=sizeof(addr
);
1492 int newsock
=accept(fd
, (struct sockaddr
*)&addr
, &addrlen
);
1494 if(MT
->numProcesses() > g_maxMThreads
) {
1495 g_stats
.overCapacityDrops
++;
1497 closesocket(newsock
);
1499 catch(const PDNSException
& e
) {
1500 L
<<Logger::Error
<<"Error closing TCP socket after an over capacity drop: "<<e
.reason
<<endl
;
1506 t_remotes
->push_back(addr
);
1507 if(t_allowFrom
&& !t_allowFrom
->match(&addr
)) {
1509 L
<<Logger::Error
<<"["<<MT
->getTid()<<"] dropping TCP query from "<<addr
.toString()<<", address not matched by allow-from"<<endl
;
1511 g_stats
.unauthorizedTCP
++;
1513 closesocket(newsock
);
1515 catch(const PDNSException
& e
) {
1516 L
<<Logger::Error
<<"Error closing TCP socket after an ACL drop: "<<e
.reason
<<endl
;
1520 if(g_maxTCPPerClient
&& t_tcpClientCounts
->count(addr
) && (*t_tcpClientCounts
)[addr
] >= g_maxTCPPerClient
) {
1521 g_stats
.tcpClientOverflow
++;
1523 closesocket(newsock
); // don't call TCPConnection::closeAndCleanup here - did not enter it in the counts yet!
1525 catch(const PDNSException
& e
) {
1526 L
<<Logger::Error
<<"Error closing TCP socket after an overflow drop: "<<e
.reason
<<endl
;
1531 setNonBlocking(newsock
);
1532 std::shared_ptr
<TCPConnection
> tc
= std::make_shared
<TCPConnection
>(newsock
, addr
);
1533 tc
->state
=TCPConnection::BYTE0
;
1535 t_fdm
->addReadFD(tc
->getFD(), handleRunningTCPQuestion
, tc
);
1538 Utility::gettimeofday(&now
, 0);
1539 t_fdm
->setReadTTD(tc
->getFD(), now
, g_tcpTimeout
);
1543 static string
* doProcessUDPQuestion(const std::string
& question
, const ComboAddress
& fromaddr
, const ComboAddress
& destaddr
, struct timeval tv
, int fd
)
1545 gettimeofday(&g_now
, 0);
1546 struct timeval diff
= g_now
- tv
;
1547 double delta
=(diff
.tv_sec
*1000 + diff
.tv_usec
/1000.0);
1549 if(tv
.tv_sec
&& delta
> 1000.0) {
1550 g_stats
.tooOldDrops
++;
1555 if(fromaddr
.sin4
.sin_family
==AF_INET6
)
1556 g_stats
.ipv6qcounter
++;
1559 const struct dnsheader
* dh
= (struct dnsheader
*)question
.c_str();
1560 unsigned int ctag
=0;
1562 bool needECS
= false;
1563 std::vector
<std::string
> policyTags
;
1564 LuaContext::LuaObject data
;
1566 #ifdef HAVE_PROTOBUF
1567 boost::uuids::uuid uniqueId
;
1568 auto luaconfsLocal
= g_luaconfs
.getLocal();
1569 if (luaconfsLocal
->protobufServer
) {
1570 uniqueId
= (*t_uuidGenerator
)();
1572 } else if (luaconfsLocal
->outgoingProtobufServer
) {
1573 uniqueId
= (*t_uuidGenerator
)();
1576 EDNSSubnetOpts ednssubnet
;
1577 bool ecsFound
= false;
1578 bool ecsParsed
= false;
1584 bool qnameParsed
=false;
1587 static uint64_t last=0;
1589 g_mtracer->clearAllocators();
1590 cout<<g_mtracer->getAllocs()-last<<" "<<g_mtracer->getNumOut()<<" -- BEGIN TRACE"<<endl;
1591 last=g_mtracer->getAllocs();
1592 cout<<g_mtracer->topAllocatorsString()<<endl;
1593 g_mtracer->clearAllocators();
1597 if(needECS
|| (t_pdl
&& t_pdl
->d_gettag
)) {
1599 std::map
<uint16_t, EDNSOptionView
> ednsOptions
;
1600 ecsFound
= getQNameAndSubnet(question
, &qname
, &qtype
, &qclass
, &ednssubnet
, g_gettagNeedsEDNSOptions
? &ednsOptions
: nullptr);
1604 if(t_pdl
&& t_pdl
->d_gettag
) {
1606 ctag
=t_pdl
->gettag(fromaddr
, ednssubnet
.source
, destaddr
, qname
, qtype
, &policyTags
, data
, ednsOptions
, false, requestorId
);
1608 catch(std::exception
& e
) {
1609 if(g_logCommonErrors
)
1610 L
<<Logger::Warning
<<"Error parsing a query packet qname='"<<qname
<<"' for tag determination, setting tag=0: "<<e
.what()<<endl
;
1614 catch(std::exception
& e
)
1616 if(g_logCommonErrors
)
1617 L
<<Logger::Warning
<<"Error parsing a query packet for tag determination, setting tag=0: "<<e
.what()<<endl
;
1621 bool cacheHit
= false;
1622 RecProtoBufMessage
pbMessage(DNSProtoBufMessage::DNSProtoBufMessageType::Response
);
1623 #ifdef HAVE_PROTOBUF
1624 if(luaconfsLocal
->protobufServer
) {
1625 if (!luaconfsLocal
->protobufTaggedOnly
|| !policyTags
.empty()) {
1626 protobufLogQuery(luaconfsLocal
->protobufServer
, luaconfsLocal
->protobufMaskV4
, luaconfsLocal
->protobufMaskV6
, uniqueId
, fromaddr
, destaddr
, ednssubnet
.source
, false, dh
->id
, question
.size(), qname
, qtype
, qclass
, policyTags
, requestorId
);
1629 #endif /* HAVE_PROTOBUF */
1632 cacheHit
= (!SyncRes::s_nopacketcache
&& t_packetCache
->getResponsePacket(ctag
, question
, qname
, qtype
, qclass
, g_now
.tv_sec
, &response
, &age
, &qhash
, &pbMessage
));
1635 cacheHit
= (!SyncRes::s_nopacketcache
&& t_packetCache
->getResponsePacket(ctag
, question
, g_now
.tv_sec
, &response
, &age
, &qhash
, &pbMessage
));
1639 #ifdef HAVE_PROTOBUF
1640 if(luaconfsLocal
->protobufServer
&& (!luaconfsLocal
->protobufTaggedOnly
|| !pbMessage
.getAppliedPolicy().empty() || !pbMessage
.getPolicyTags().empty())) {
1641 Netmask
requestorNM(fromaddr
, fromaddr
.sin4
.sin_family
== AF_INET
? luaconfsLocal
->protobufMaskV4
: luaconfsLocal
->protobufMaskV6
);
1642 const ComboAddress
& requestor
= requestorNM
.getMaskedNetwork();
1643 pbMessage
.update(uniqueId
, &requestor
, &destaddr
, false, dh
->id
);
1644 pbMessage
.setEDNSSubnet(ednssubnet
.source
, ednssubnet
.source
.isIpv4() ? luaconfsLocal
->protobufMaskV4
: luaconfsLocal
->protobufMaskV6
);
1645 pbMessage
.setQueryTime(g_now
.tv_sec
, g_now
.tv_usec
);
1646 pbMessage
.setRequestorId(requestorId
);
1647 protobufLogResponse(luaconfsLocal
->protobufServer
, pbMessage
);
1649 #endif /* HAVE_PROTOBUF */
1651 L
<<Logger::Notice
<<t_id
<< " question answered from packet cache tag="<<ctag
<<" from "<<fromaddr
.toString()<<endl
;
1653 g_stats
.packetCacheHits
++;
1654 SyncRes::s_queries
++;
1655 ageDNSPacket(response
, age
);
1659 fillMSGHdr(&msgh
, &iov
, cbuf
, 0, (char*)response
.c_str(), response
.length(), const_cast<ComboAddress
*>(&fromaddr
));
1660 msgh
.msg_control
=NULL
;
1662 if(g_fromtosockets
.count(fd
)) {
1663 addCMsgSrcAddr(&msgh
, cbuf
, &destaddr
, 0);
1665 if(sendmsg(fd
, &msgh
, 0) < 0 && g_logCommonErrors
)
1666 L
<<Logger::Warning
<<"Sending UDP reply to client "<<fromaddr
.toStringWithPort()<<" failed with: "<<strerror(errno
)<<endl
;
1668 if(response
.length() >= sizeof(struct dnsheader
)) {
1669 struct dnsheader tmpdh
;
1670 memcpy(&tmpdh
, response
.c_str(), sizeof(tmpdh
));
1671 updateResponseStats(tmpdh
.rcode
, fromaddr
, response
.length(), 0, 0);
1673 g_stats
.avgLatencyUsec
=(1-1.0/g_latencyStatSize
)*g_stats
.avgLatencyUsec
+ 0.0; // we assume 0 usec
1677 catch(std::exception
& e
) {
1678 L
<<Logger::Error
<<"Error processing or aging answer packet: "<<e
.what()<<endl
;
1683 if(t_pdl
->ipfilter(fromaddr
, destaddr
, *dh
)) {
1685 L
<<Logger::Notice
<<t_id
<<" ["<<MT
->getTid()<<"/"<<MT
->numProcesses()<<"] DROPPED question from "<<fromaddr
.toStringWithPort()<<" based on policy"<<endl
;
1686 g_stats
.policyDrops
++;
1691 if(MT
->numProcesses() > g_maxMThreads
) {
1693 L
<<Logger::Notice
<<t_id
<<" ["<<MT
->getTid()<<"/"<<MT
->numProcesses()<<"] DROPPED question from "<<fromaddr
.toStringWithPort()<<", over capacity"<<endl
;
1695 g_stats
.overCapacityDrops
++;
1699 DNSComboWriter
* dc
= new DNSComboWriter(question
.c_str(), question
.size(), g_now
);
1703 dc
->d_query
= question
;
1704 dc
->setRemote(&fromaddr
);
1705 dc
->setLocal(destaddr
);
1707 dc
->d_policyTags
= policyTags
;
1709 dc
->d_ecsFound
= ecsFound
;
1710 dc
->d_ecsParsed
= ecsParsed
;
1711 dc
->d_ednssubnet
= ednssubnet
;
1712 #ifdef HAVE_PROTOBUF
1713 if (luaconfsLocal
->protobufServer
|| luaconfsLocal
->outgoingProtobufServer
) {
1714 dc
->d_uuid
= uniqueId
;
1716 dc
->d_requestorId
= requestorId
;
1719 MT
->makeThread(startDoResolve
, (void*) dc
); // deletes dc
1724 static void handleNewUDPQuestion(int fd
, FDMultiplexer::funcparam_t
& var
)
1728 ComboAddress fromaddr
;
1733 fromaddr
.sin6
.sin6_family
=AF_INET6
; // this makes sure fromaddr is big enough
1734 fillMSGHdr(&msgh
, &iov
, cbuf
, sizeof(cbuf
), data
, sizeof(data
), &fromaddr
);
1737 if((len
=recvmsg(fd
, &msgh
, 0)) >= 0) {
1739 t_remotes
->push_back(fromaddr
);
1741 if(t_allowFrom
&& !t_allowFrom
->match(&fromaddr
)) {
1743 L
<<Logger::Error
<<"["<<MT
->getTid()<<"] dropping UDP query from "<<fromaddr
.toString()<<", address not matched by allow-from"<<endl
;
1745 g_stats
.unauthorizedUDP
++;
1748 BOOST_STATIC_ASSERT(offsetof(sockaddr_in
, sin_port
) == offsetof(sockaddr_in6
, sin6_port
));
1749 if(!fromaddr
.sin4
.sin_port
) { // also works for IPv6
1751 L
<<Logger::Error
<<"["<<MT
->getTid()<<"] dropping UDP query from "<<fromaddr
.toStringWithPort()<<", can't deal with port 0"<<endl
;
1753 g_stats
.clientParseError
++; // not quite the best place to put it, but needs to go somewhere
1757 dnsheader
* dh
=(dnsheader
*)data
;
1760 g_stats
.ignoredCount
++;
1761 if(g_logCommonErrors
)
1762 L
<<Logger::Error
<<"Ignoring answer from "<<fromaddr
.toString()<<" on server socket!"<<endl
;
1764 else if(dh
->opcode
) {
1765 g_stats
.ignoredCount
++;
1766 if(g_logCommonErrors
)
1767 L
<<Logger::Error
<<"Ignoring non-query opcode "<<dh
->opcode
<<" from "<<fromaddr
.toString()<<" on server socket!"<<endl
;
1770 string
question(data
, (size_t)len
);
1771 struct timeval tv
={0,0};
1772 HarvestTimestamp(&msgh
, &tv
);
1774 memset(&dest
, 0, sizeof(dest
)); // this makes sure we ignore this address if not returned by recvmsg above
1775 auto loc
= rplookup(g_listenSocketsAddresses
, fd
);
1776 if(HarvestDestinationAddress(&msgh
, &dest
)) {
1777 // but.. need to get port too
1779 dest
.sin4
.sin_port
= loc
->sin4
.sin_port
;
1786 dest
.sin4
.sin_family
= fromaddr
.sin4
.sin_family
;
1787 socklen_t slen
= dest
.getSocklen();
1788 getsockname(fd
, (sockaddr
*)&dest
, &slen
); // if this fails, we're ok with it
1791 if(g_weDistributeQueries
)
1792 distributeAsyncFunction(question
, boost::bind(doProcessUDPQuestion
, question
, fromaddr
, dest
, tv
, fd
));
1794 doProcessUDPQuestion(question
, fromaddr
, dest
, tv
, fd
);
1797 catch(MOADNSException
& mde
) {
1798 g_stats
.clientParseError
++;
1799 if(g_logCommonErrors
)
1800 L
<<Logger::Error
<<"Unable to parse packet from remote UDP client "<<fromaddr
.toString() <<": "<<mde
.what()<<endl
;
1802 catch(std::runtime_error
& e
) {
1803 g_stats
.clientParseError
++;
1804 if(g_logCommonErrors
)
1805 L
<<Logger::Error
<<"Unable to parse packet from remote UDP client "<<fromaddr
.toString() <<": "<<e
.what()<<endl
;
1809 // cerr<<t_id<<" had error: "<<stringerror()<<endl;
1811 g_stats
.noPacketError
++;
1816 static void makeTCPServerSockets(unsigned int threadId
)
1819 vector
<string
>locals
;
1820 stringtok(locals
,::arg()["local-address"]," ,");
1823 throw PDNSException("No local address specified");
1825 for(vector
<string
>::const_iterator i
=locals
.begin();i
!=locals
.end();++i
) {
1827 st
.port
=::arg().asNum("local-port");
1828 parseService(*i
, st
);
1832 memset((char *)&sin
,0, sizeof(sin
));
1833 sin
.sin4
.sin_family
= AF_INET
;
1834 if(!IpToU32(st
.host
, (uint32_t*)&sin
.sin4
.sin_addr
.s_addr
)) {
1835 sin
.sin6
.sin6_family
= AF_INET6
;
1836 if(makeIPv6sockaddr(st
.host
, &sin
.sin6
) < 0)
1837 throw PDNSException("Unable to resolve local address for TCP server on '"+ st
.host
+"'");
1840 fd
=socket(sin
.sin6
.sin6_family
, SOCK_STREAM
, 0);
1842 throw PDNSException("Making a TCP server socket for resolver: "+stringerror());
1847 if(setsockopt(fd
, SOL_SOCKET
, SO_REUSEADDR
, &tmp
, sizeof tmp
)<0) {
1848 L
<<Logger::Error
<<"Setsockopt failed for TCP listening socket"<<endl
;
1851 if(sin
.sin6
.sin6_family
== AF_INET6
&& setsockopt(fd
, IPPROTO_IPV6
, IPV6_V6ONLY
, &tmp
, sizeof(tmp
)) < 0) {
1852 L
<<Logger::Error
<<"Failed to set IPv6 socket to IPv6 only, continuing anyhow: "<<strerror(errno
)<<endl
;
1855 #ifdef TCP_DEFER_ACCEPT
1856 if(setsockopt(fd
, SOL_TCP
, TCP_DEFER_ACCEPT
, &tmp
, sizeof tmp
) >= 0) {
1857 if(i
==locals
.begin())
1858 L
<<Logger::Error
<<"Enabled TCP data-ready filter for (slight) DoS protection"<<endl
;
1862 if( ::arg().mustDo("non-local-bind") )
1863 Utility::setBindAny(AF_INET
, fd
);
1867 if(setsockopt(fd
, SOL_SOCKET
, SO_REUSEPORT
, &tmp
, sizeof(tmp
)) < 0)
1868 throw PDNSException("SO_REUSEPORT: "+stringerror());
1872 if (::arg().asNum("tcp-fast-open") > 0) {
1874 int fastOpenQueueSize
= ::arg().asNum("tcp-fast-open");
1875 if (setsockopt(fd
, IPPROTO_TCP
, TCP_FASTOPEN
, &fastOpenQueueSize
, sizeof fastOpenQueueSize
) < 0) {
1876 L
<<Logger::Error
<<"Failed to enable TCP Fast Open for listening socket: "<<strerror(errno
)<<endl
;
1879 L
<<Logger::Warning
<<"TCP Fast Open configured but not supported for listening socket"<<endl
;
1883 sin
.sin4
.sin_port
= htons(st
.port
);
1884 socklen_t socklen
=sin
.sin4
.sin_family
==AF_INET
? sizeof(sin
.sin4
) : sizeof(sin
.sin6
);
1885 if (::bind(fd
, (struct sockaddr
*)&sin
, socklen
)<0)
1886 throw PDNSException("Binding TCP server socket for "+ st
.host
+": "+stringerror());
1889 setSocketSendBuffer(fd
, 65000);
1891 deferredAdds
[threadId
].push_back(make_pair(fd
, handleNewTCPQuestion
));
1892 g_tcpListenSockets
.push_back(fd
);
1893 // we don't need to update g_listenSocketsAddresses since it doesn't work for TCP/IP:
1894 // - fd is not that which we know here, but returned from accept()
1895 if(sin
.sin4
.sin_family
== AF_INET
)
1896 L
<<Logger::Error
<<"Listening for TCP queries on "<< sin
.toString() <<":"<<st
.port
<<endl
;
1898 L
<<Logger::Error
<<"Listening for TCP queries on ["<< sin
.toString() <<"]:"<<st
.port
<<endl
;
1902 static void makeUDPServerSockets(unsigned int threadId
)
1905 vector
<string
>locals
;
1906 stringtok(locals
,::arg()["local-address"]," ,");
1909 throw PDNSException("No local address specified");
1911 for(vector
<string
>::const_iterator i
=locals
.begin();i
!=locals
.end();++i
) {
1913 st
.port
=::arg().asNum("local-port");
1914 parseService(*i
, st
);
1918 memset(&sin
, 0, sizeof(sin
));
1919 sin
.sin4
.sin_family
= AF_INET
;
1920 if(!IpToU32(st
.host
.c_str() , (uint32_t*)&sin
.sin4
.sin_addr
.s_addr
)) {
1921 sin
.sin6
.sin6_family
= AF_INET6
;
1922 if(makeIPv6sockaddr(st
.host
, &sin
.sin6
) < 0)
1923 throw PDNSException("Unable to resolve local address for UDP server on '"+ st
.host
+"'");
1926 int fd
=socket(sin
.sin4
.sin_family
, SOCK_DGRAM
, 0);
1928 throw PDNSException("Making a UDP server socket for resolver: "+netstringerror());
1930 if (!setSocketTimestamps(fd
))
1931 L
<<Logger::Warning
<<"Unable to enable timestamp reporting for socket"<<endl
;
1933 if(IsAnyAddress(sin
)) {
1934 if(sin
.sin4
.sin_family
== AF_INET
)
1935 if(!setsockopt(fd
, IPPROTO_IP
, GEN_IP_PKTINFO
, &one
, sizeof(one
))) // linux supports this, so why not - might fail on other systems
1936 g_fromtosockets
.insert(fd
);
1937 #ifdef IPV6_RECVPKTINFO
1938 if(sin
.sin4
.sin_family
== AF_INET6
)
1939 if(!setsockopt(fd
, IPPROTO_IPV6
, IPV6_RECVPKTINFO
, &one
, sizeof(one
)))
1940 g_fromtosockets
.insert(fd
);
1942 if(sin
.sin6
.sin6_family
== AF_INET6
&& setsockopt(fd
, IPPROTO_IPV6
, IPV6_V6ONLY
, &one
, sizeof(one
)) < 0) {
1943 L
<<Logger::Error
<<"Failed to set IPv6 socket to IPv6 only, continuing anyhow: "<<strerror(errno
)<<endl
;
1946 if( ::arg().mustDo("non-local-bind") )
1947 Utility::setBindAny(AF_INET6
, fd
);
1951 setSocketReceiveBuffer(fd
, 250000);
1952 sin
.sin4
.sin_port
= htons(st
.port
);
1957 if(setsockopt(fd
, SOL_SOCKET
, SO_REUSEPORT
, &one
, sizeof(one
)) < 0)
1958 throw PDNSException("SO_REUSEPORT: "+stringerror());
1961 socklen_t socklen
=sin
.getSocklen();
1962 if (::bind(fd
, (struct sockaddr
*)&sin
, socklen
)<0)
1963 throw PDNSException("Resolver binding to server socket on port "+ std::to_string(st
.port
) +" for "+ st
.host
+": "+stringerror());
1967 deferredAdds
[threadId
].push_back(make_pair(fd
, handleNewUDPQuestion
));
1968 g_listenSocketsAddresses
[fd
]=sin
; // this is written to only from the startup thread, not from the workers
1969 if(sin
.sin4
.sin_family
== AF_INET
)
1970 L
<<Logger::Error
<<"Listening for UDP queries on "<< sin
.toString() <<":"<<st
.port
<<endl
;
1972 L
<<Logger::Error
<<"Listening for UDP queries on ["<< sin
.toString() <<"]:"<<st
.port
<<endl
;
1976 static void daemonize(void)
1983 int i
=open("/dev/null",O_RDWR
); /* open stdin */
1985 L
<<Logger::Critical
<<"Unable to open /dev/null: "<<stringerror()<<endl
;
1987 dup2(i
,0); /* stdin */
1988 dup2(i
,1); /* stderr */
1989 dup2(i
,2); /* stderr */
1994 static void usr1Handler(int)
1999 static void usr2Handler(int)
2002 SyncRes::setDefaultLogMode(g_quiet
? SyncRes::LogNone
: SyncRes::Log
);
2003 ::arg().set("quiet")=g_quiet
? "" : "no";
2006 static void doStats(void)
2008 static time_t lastOutputTime
;
2009 static uint64_t lastQueryCount
;
2011 uint64_t cacheHits
= broadcastAccFunction
<uint64_t>(pleaseGetCacheHits
);
2012 uint64_t cacheMisses
= broadcastAccFunction
<uint64_t>(pleaseGetCacheMisses
);
2014 if(g_stats
.qcounter
&& (cacheHits
+ cacheMisses
) && SyncRes::s_queries
&& SyncRes::s_outqueries
) {
2015 L
<<Logger::Notice
<<"stats: "<<g_stats
.qcounter
<<" questions, "<<
2016 broadcastAccFunction
<uint64_t>(pleaseGetCacheSize
)<< " cache entries, "<<
2017 broadcastAccFunction
<uint64_t>(pleaseGetNegCacheSize
)<<" negative entries, "<<
2018 (int)((cacheHits
*100.0)/(cacheHits
+cacheMisses
))<<"% cache hits"<<endl
;
2020 L
<<Logger::Notice
<<"stats: throttle map: "
2021 << broadcastAccFunction
<uint64_t>(pleaseGetThrottleSize
) <<", ns speeds: "
2022 << broadcastAccFunction
<uint64_t>(pleaseGetNsSpeedsSize
)<<endl
;
2023 L
<<Logger::Notice
<<"stats: outpacket/query ratio "<<(int)(SyncRes::s_outqueries
*100.0/SyncRes::s_queries
)<<"%";
2024 L
<<Logger::Notice
<<", "<<(int)(SyncRes::s_throttledqueries
*100.0/(SyncRes::s_outqueries
+SyncRes::s_throttledqueries
))<<"% throttled, "
2025 <<SyncRes::s_nodelegated
<<" no-delegation drops"<<endl
;
2026 L
<<Logger::Notice
<<"stats: "<<SyncRes::s_tcpoutqueries
<<" outgoing tcp connections, "<<
2027 broadcastAccFunction
<uint64_t>(pleaseGetConcurrentQueries
)<<" queries running, "<<SyncRes::s_outgoingtimeouts
<<" outgoing timeouts"<<endl
;
2029 //L<<Logger::Notice<<"stats: "<<g_stats.ednsPingMatches<<" ping matches, "<<g_stats.ednsPingMismatches<<" mismatches, "<<
2030 //g_stats.noPingOutQueries<<" outqueries w/o ping, "<< g_stats.noEdnsOutQueries<<" w/o EDNS"<<endl;
2032 L
<<Logger::Notice
<<"stats: " << broadcastAccFunction
<uint64_t>(pleaseGetPacketCacheSize
) <<
2033 " packet cache entries, "<<(int)(100.0*broadcastAccFunction
<uint64_t>(pleaseGetPacketCacheHits
)/SyncRes::s_queries
) << "% packet cache hits"<<endl
;
2035 time_t now
= time(0);
2036 if(lastOutputTime
&& lastQueryCount
&& now
!= lastOutputTime
) {
2037 L
<<Logger::Notice
<<"stats: "<< (SyncRes::s_queries
- lastQueryCount
) / (now
- lastOutputTime
) <<" qps (average over "<< (now
- lastOutputTime
) << " seconds)"<<endl
;
2039 lastOutputTime
= now
;
2040 lastQueryCount
= SyncRes::s_queries
;
2042 else if(statsWanted
)
2043 L
<<Logger::Notice
<<"stats: no stats yet!"<<endl
;
2048 static void houseKeeping(void *)
2050 static thread_local
time_t last_stat
, last_rootupdate
, last_prune
, last_secpoll
;
2051 static thread_local
int cleanCounter
=0;
2052 static thread_local
bool s_running
; // houseKeeping can get suspended in secpoll, and be restarted, which makes us do duplicate work
2059 Utility::gettimeofday(&now
, 0);
2061 if(now
.tv_sec
- last_prune
> (time_t)(5 + t_id
)) {
2064 t_RC
->doPrune(); // this function is local to a thread, so fine anyhow
2065 t_packetCache
->doPruneTo(::arg().asNum("max-packetcache-entries") / g_numWorkerThreads
);
2067 SyncRes::pruneNegCache(::arg().asNum("max-cache-entries") / (g_numWorkerThreads
* 10));
2069 if(!((cleanCounter
++)%40)) { // this is a full scan!
2070 time_t limit
=now
.tv_sec
-300;
2071 SyncRes::pruneNSSpeeds(limit
);
2076 if(now
.tv_sec
- last_rootupdate
> 7200) {
2077 int res
= SyncRes::getRootNS(g_now
, nullptr);
2079 last_rootupdate
=now
.tv_sec
;
2083 if(g_statisticsInterval
> 0 && now
.tv_sec
- last_stat
>= g_statisticsInterval
) {
2088 if(now
.tv_sec
- last_secpoll
>= 3600) {
2090 doSecPoll(&last_secpoll
);
2097 catch(PDNSException
& ae
)
2100 L
<<Logger::Error
<<"Fatal error in housekeeping thread: "<<ae
.reason
<<endl
;
2105 static void makeThreadPipes()
2107 for(unsigned int n
=0; n
< g_numThreads
; ++n
) {
2108 struct ThreadPipeSet tps
;
2111 unixDie("Creating pipe for inter-thread communications");
2113 tps
.readToThread
= fd
[0];
2114 tps
.writeToThread
= fd
[1];
2117 unixDie("Creating pipe for inter-thread communications");
2118 tps
.readFromThread
= fd
[0];
2119 tps
.writeFromThread
= fd
[1];
2121 g_pipes
.push_back(tps
);
2131 void broadcastFunction(const pipefunc_t
& func
, bool skipSelf
)
2134 for(ThreadPipeSet
& tps
: g_pipes
)
2138 func(); // don't write to ourselves!
2142 ThreadMSG
* tmsg
= new ThreadMSG();
2144 tmsg
->wantAnswer
= true;
2145 if(write(tps
.writeToThread
, &tmsg
, sizeof(tmsg
)) != sizeof(tmsg
)) {
2147 unixDie("write to thread pipe returned wrong size or error");
2151 if(read(tps
.readFromThread
, &resp
, sizeof(resp
)) != sizeof(resp
))
2152 unixDie("read from thread pipe returned wrong size or error");
2155 // cerr <<"got response: " << *resp << endl;
2161 void distributeAsyncFunction(const string
& packet
, const pipefunc_t
& func
)
2163 unsigned int hash
= hashQuestion(packet
.c_str(), packet
.length(), g_disthashseed
);
2164 unsigned int target
= 1 + (hash
% (g_pipes
.size()-1));
2166 if(target
== t_id
) {
2170 ThreadPipeSet
& tps
= g_pipes
[target
];
2171 ThreadMSG
* tmsg
= new ThreadMSG();
2173 tmsg
->wantAnswer
= false;
2175 if(write(tps
.writeToThread
, &tmsg
, sizeof(tmsg
)) != sizeof(tmsg
)) {
2177 unixDie("write to thread pipe returned wrong size or error");
2181 static void handlePipeRequest(int fd
, FDMultiplexer::funcparam_t
& var
)
2183 ThreadMSG
* tmsg
= nullptr;
2185 if(read(fd
, &tmsg
, sizeof(tmsg
)) != sizeof(tmsg
)) { // fd == readToThread
2186 unixDie("read from thread pipe returned wrong size or error");
2191 resp
= tmsg
->func();
2193 catch(std::exception
& e
) {
2194 if(g_logCommonErrors
)
2195 L
<<Logger::Error
<<"PIPE function we executed created exception: "<<e
.what()<<endl
; // but what if they wanted an answer.. we send 0
2197 catch(PDNSException
& e
) {
2198 if(g_logCommonErrors
)
2199 L
<<Logger::Error
<<"PIPE function we executed created PDNS exception: "<<e
.reason
<<endl
; // but what if they wanted an answer.. we send 0
2201 if(tmsg
->wantAnswer
) {
2202 if(write(g_pipes
[t_id
].writeFromThread
, &resp
, sizeof(resp
)) != sizeof(resp
)) {
2204 unixDie("write to thread pipe returned wrong size or error");
2211 template<class T
> void *voider(const boost::function
<T
*()>& func
)
2216 vector
<ComboAddress
>& operator+=(vector
<ComboAddress
>&a
, const vector
<ComboAddress
>& b
)
2218 a
.insert(a
.end(), b
.begin(), b
.end());
2222 vector
<pair
<string
, uint16_t> >& operator+=(vector
<pair
<string
, uint16_t> >&a
, const vector
<pair
<string
, uint16_t> >& b
)
2224 a
.insert(a
.end(), b
.begin(), b
.end());
2228 vector
<pair
<DNSName
, uint16_t> >& operator+=(vector
<pair
<DNSName
, uint16_t> >&a
, const vector
<pair
<DNSName
, uint16_t> >& b
)
2230 a
.insert(a
.end(), b
.begin(), b
.end());
2235 template<class T
> T
broadcastAccFunction(const boost::function
<T
*()>& func
, bool skipSelf
)
2239 for(ThreadPipeSet
& tps
: g_pipes
)
2243 T
* resp
= (T
*)func(); // don't write to ourselves!
2245 //~ cerr <<"got direct: " << *resp << endl;
2253 ThreadMSG
* tmsg
= new ThreadMSG();
2254 tmsg
->func
= boost::bind(voider
<T
>, func
);
2255 tmsg
->wantAnswer
= true;
2257 if(write(tps
.writeToThread
, &tmsg
, sizeof(tmsg
)) != sizeof(tmsg
)) {
2259 unixDie("write to thread pipe returned wrong size or error");
2263 if(read(tps
.readFromThread
, &resp
, sizeof(resp
)) != sizeof(resp
))
2264 unixDie("read from thread pipe returned wrong size or error");
2267 //~ cerr <<"got response: " << *resp << endl;
2275 template string
broadcastAccFunction(const boost::function
<string
*()>& fun
, bool skipSelf
); // explicit instantiation
2276 template uint64_t broadcastAccFunction(const boost::function
<uint64_t*()>& fun
, bool skipSelf
); // explicit instantiation
2277 template vector
<ComboAddress
> broadcastAccFunction(const boost::function
<vector
<ComboAddress
> *()>& fun
, bool skipSelf
); // explicit instantiation
2278 template vector
<pair
<DNSName
,uint16_t> > broadcastAccFunction(const boost::function
<vector
<pair
<DNSName
, uint16_t> > *()>& fun
, bool skipSelf
); // explicit instantiation
2280 static void handleRCC(int fd
, FDMultiplexer::funcparam_t
& var
)
2283 string msg
=s_rcc
.recv(&remote
);
2284 RecursorControlParser rcp
;
2285 RecursorControlParser::func_t
* command
;
2287 string answer
=rcp
.getAnswer(msg
, &command
);
2289 // If we are inside a chroot, we need to strip
2290 if (!arg()["chroot"].empty()) {
2291 size_t len
= arg()["chroot"].length();
2292 remote
= remote
.substr(len
);
2296 s_rcc
.send(answer
, &remote
);
2299 catch(std::exception
& e
) {
2300 L
<<Logger::Error
<<"Error dealing with control socket request: "<<e
.what()<<endl
;
2302 catch(PDNSException
& ae
) {
2303 L
<<Logger::Error
<<"Error dealing with control socket request: "<<ae
.reason
<<endl
;
2307 static void handleTCPClientReadable(int fd
, FDMultiplexer::funcparam_t
& var
)
2309 PacketID
* pident
=any_cast
<PacketID
>(&var
);
2310 // cerr<<"handleTCPClientReadable called for fd "<<fd<<", pident->inNeeded: "<<pident->inNeeded<<", "<<pident->sock->getHandle()<<endl;
2312 shared_array
<char> buffer(new char[pident
->inNeeded
]);
2314 ssize_t ret
=recv(fd
, buffer
.get(), pident
->inNeeded
,0);
2316 pident
->inMSG
.append(&buffer
[0], &buffer
[ret
]);
2317 pident
->inNeeded
-=(size_t)ret
;
2318 if(!pident
->inNeeded
|| pident
->inIncompleteOkay
) {
2319 // cerr<<"Got entire load of "<<pident->inMSG.size()<<" bytes"<<endl;
2320 PacketID pid
=*pident
;
2321 string msg
=pident
->inMSG
;
2323 t_fdm
->removeReadFD(fd
);
2324 MT
->sendEvent(pid
, &msg
);
2327 // cerr<<"Still have "<<pident->inNeeded<<" left to go"<<endl;
2331 PacketID tmp
=*pident
;
2332 t_fdm
->removeReadFD(fd
); // pident might now be invalid (it isn't, but still)
2334 MT
->sendEvent(tmp
, &empty
); // this conveys error status
2338 static void handleTCPClientWritable(int fd
, FDMultiplexer::funcparam_t
& var
)
2340 PacketID
* pid
=any_cast
<PacketID
>(&var
);
2341 ssize_t ret
=send(fd
, pid
->outMSG
.c_str() + pid
->outPos
, pid
->outMSG
.size() - pid
->outPos
,0);
2343 pid
->outPos
+=(ssize_t
)ret
;
2344 if(pid
->outPos
==pid
->outMSG
.size()) {
2346 t_fdm
->removeWriteFD(fd
);
2347 MT
->sendEvent(tmp
, &tmp
.outMSG
); // send back what we sent to convey everything is ok
2350 else { // error or EOF
2352 t_fdm
->removeWriteFD(fd
);
2354 MT
->sendEvent(tmp
, &sent
); // we convey error status by sending empty string
2358 // resend event to everybody chained onto it
2359 static void doResends(MT_t::waiters_t::iterator
& iter
, PacketID resend
, const string
& content
)
2361 if(iter
->key
.chain
.empty())
2363 // cerr<<"doResends called!\n";
2364 for(PacketID::chain_t::iterator i
=iter
->key
.chain
.begin(); i
!= iter
->key
.chain
.end() ; ++i
) {
2367 // cerr<<"\tResending "<<content.size()<<" bytes for fd="<<resend.fd<<" and id="<<resend.id<<endl;
2369 MT
->sendEvent(resend
, &content
);
2370 g_stats
.chainResends
++;
2374 static void handleUDPServerResponse(int fd
, FDMultiplexer::funcparam_t
& var
)
2376 PacketID pid
=any_cast
<PacketID
>(var
);
2378 char data
[g_outgoingEDNSBufsize
];
2379 ComboAddress fromaddr
;
2380 socklen_t addrlen
=sizeof(fromaddr
);
2382 len
=recvfrom(fd
, data
, sizeof(data
), 0, (sockaddr
*)&fromaddr
, &addrlen
);
2384 if(len
< (ssize_t
) sizeof(dnsheader
)) {
2386 ; // cerr<<"Error on fd "<<fd<<": "<<stringerror()<<"\n";
2388 g_stats
.serverParseError
++;
2389 if(g_logCommonErrors
)
2390 L
<<Logger::Error
<<"Unable to parse packet from remote UDP server "<< fromaddr
.toString() <<
2391 ": packet smaller than DNS header"<<endl
;
2394 t_udpclientsocks
->returnSocket(fd
);
2397 MT_t::waiters_t::iterator iter
=MT
->d_waiters
.find(pid
);
2398 if(iter
!= MT
->d_waiters
.end())
2399 doResends(iter
, pid
, empty
);
2401 MT
->sendEvent(pid
, &empty
); // this denotes error (does lookup again.. at least L1 will be hot)
2406 memcpy(&dh
, data
, sizeof(dh
));
2409 pident
.remote
=fromaddr
;
2413 if(!dh
.qr
&& g_logCommonErrors
) {
2414 L
<<Logger::Notice
<<"Not taking data from question on outgoing socket from "<< fromaddr
.toStringWithPort() <<endl
;
2417 if(!dh
.qdcount
|| // UPC, Nominum, very old BIND on FormErr, NSD
2418 !dh
.qr
) { // one weird server
2419 pident
.domain
.clear();
2425 pident
.domain
=DNSName(data
, len
, 12, false, &pident
.type
); // don't copy this from above - we need to do the actual read
2427 catch(std::exception
& e
) {
2428 g_stats
.serverParseError
++; // won't be fed to lwres.cc, so we have to increment
2429 L
<<Logger::Warning
<<"Error in packet from remote nameserver "<< fromaddr
.toStringWithPort() << ": "<<e
.what() << endl
;
2434 packet
.assign(data
, len
);
2436 MT_t::waiters_t::iterator iter
=MT
->d_waiters
.find(pident
);
2437 if(iter
!= MT
->d_waiters
.end()) {
2438 doResends(iter
, pident
, packet
);
2443 if(!MT
->sendEvent(pident
, &packet
)) {
2444 // 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
2445 for(MT_t::waiters_t::iterator mthread
=MT
->d_waiters
.begin(); mthread
!=MT
->d_waiters
.end(); ++mthread
) {
2446 if(pident
.fd
==mthread
->key
.fd
&& mthread
->key
.remote
==pident
.remote
&& mthread
->key
.type
== pident
.type
&&
2447 pident
.domain
== mthread
->key
.domain
) {
2448 mthread
->key
.nearMisses
++;
2451 // be a bit paranoid here since we're weakening our matching
2452 if(pident
.domain
.empty() && !mthread
->key
.domain
.empty() && !pident
.type
&& mthread
->key
.type
&&
2453 pident
.id
== mthread
->key
.id
&& mthread
->key
.remote
== pident
.remote
) {
2454 // cerr<<"Empty response, rest matches though, sending to a waiter"<<endl;
2455 pident
.domain
= mthread
->key
.domain
;
2456 pident
.type
= mthread
->key
.type
;
2457 goto retryWithName
; // note that this only passes on an error, lwres will still reject the packet
2460 g_stats
.unexpectedCount
++; // if we made it here, it really is an unexpected answer
2461 if(g_logCommonErrors
) {
2462 L
<<Logger::Warning
<<"Discarding unexpected packet from "<<fromaddr
.toStringWithPort()<<": "<< (pident
.domain
.empty() ? "<empty>" : pident
.domain
.toString())<<", "<<pident
.type
<<", "<<MT
->d_waiters
.size()<<" waiters"<<endl
;
2466 t_udpclientsocks
->returnSocket(fd
);
2470 FDMultiplexer
* getMultiplexer()
2473 for(const auto& i
: FDMultiplexer::getMultiplexerMap()) {
2478 catch(FDMultiplexerException
&fe
) {
2479 L
<<Logger::Error
<<"Non-fatal error initializing possible multiplexer ("<<fe
.what()<<"), falling back"<<endl
;
2482 L
<<Logger::Error
<<"Non-fatal error initializing possible multiplexer"<<endl
;
2485 L
<<Logger::Error
<<"No working multiplexer found!"<<endl
;
2490 static string
* doReloadLuaScript()
2492 string fname
= ::arg()["lua-dns-script"];
2496 L
<<Logger::Error
<<t_id
<<" Unloaded current lua script"<<endl
;
2497 return new string("unloaded\n");
2500 t_pdl
= std::make_shared
<RecursorLua4
>(fname
);
2503 catch(std::exception
& e
) {
2504 L
<<Logger::Error
<<t_id
<<" Retaining current script, error from '"<<fname
<<"': "<< e
.what() <<endl
;
2505 return new string("retaining current script, error from '"+fname
+"': "+e
.what()+"\n");
2508 L
<<Logger::Warning
<<t_id
<<" (Re)loaded lua script from '"<<fname
<<"'"<<endl
;
2509 return new string("(re)loaded '"+fname
+"'\n");
2512 string
doQueueReloadLuaScript(vector
<string
>::const_iterator begin
, vector
<string
>::const_iterator end
)
2515 ::arg().set("lua-dns-script") = *begin
;
2517 return broadcastAccFunction
<string
>(doReloadLuaScript
);
2520 static string
* pleaseUseNewTraceRegex(const std::string
& newRegex
)
2523 if(newRegex
.empty()) {
2524 t_traceRegex
.reset();
2525 return new string("unset\n");
2528 t_traceRegex
= std::make_shared
<Regex
>(newRegex
);
2529 return new string("ok\n");
2532 catch(PDNSException
& ae
)
2534 return new string(ae
.reason
+"\n");
2537 string
doTraceRegex(vector
<string
>::const_iterator begin
, vector
<string
>::const_iterator end
)
2539 return broadcastAccFunction
<string
>(boost::bind(pleaseUseNewTraceRegex
, begin
!=end
? *begin
: ""));
2542 static void checkLinuxIPv6Limits()
2546 if(readFileIfThere("/proc/sys/net/ipv6/route/max_size", &line
)) {
2547 int lim
=std::stoi(line
);
2549 L
<<Logger::Error
<<"If using IPv6, please raise sysctl net.ipv6.route.max_size, currently set to "<<lim
<<" which is < 16384"<<endl
;
2554 static void checkOrFixFDS()
2556 unsigned int availFDs
=getFilenumLimit();
2557 unsigned int wantFDs
= g_maxMThreads
* g_numWorkerThreads
+25; // even healthier margin then before
2559 if(wantFDs
> availFDs
) {
2560 unsigned int hardlimit
= getFilenumLimit(true);
2561 if(hardlimit
>= wantFDs
) {
2562 setFilenumLimit(wantFDs
);
2563 L
<<Logger::Warning
<<"Raised soft limit on number of filedescriptors to "<<wantFDs
<<" to match max-mthreads and threads settings"<<endl
;
2566 int newval
= (hardlimit
- 25) / g_numWorkerThreads
;
2567 L
<<Logger::Warning
<<"Insufficient number of filedescriptors available for max-mthreads*threads setting! ("<<hardlimit
<<" < "<<wantFDs
<<"), reducing max-mthreads to "<<newval
<<endl
;
2568 g_maxMThreads
= newval
;
2569 setFilenumLimit(hardlimit
);
2574 static void* recursorThread(void*);
2576 static void* pleaseSupplantACLs(std::shared_ptr
<NetmaskGroup
> ng
)
2587 static bool l_initialized
;
2589 if(l_initialized
) { // only reload configuration file on second call
2590 string configname
=::arg()["config-dir"]+"/recursor.conf";
2591 cleanSlashes(configname
);
2593 if(!::arg().preParseFile(configname
.c_str(), "allow-from-file"))
2594 throw runtime_error("Unable to re-parse configuration file '"+configname
+"'");
2595 ::arg().preParseFile(configname
.c_str(), "allow-from", LOCAL_NETS
);
2596 ::arg().preParseFile(configname
.c_str(), "include-dir");
2597 ::arg().preParse(g_argc
, g_argv
, "include-dir");
2599 // then process includes
2600 std::vector
<std::string
> extraConfigs
;
2601 ::arg().gatherIncludes(extraConfigs
);
2603 for(const std::string
& fn
: extraConfigs
) {
2604 if(!::arg().preParseFile(fn
.c_str(), "allow-from-file", ::arg()["allow-from-file"]))
2605 throw runtime_error("Unable to re-parse configuration file include '"+fn
+"'");
2606 if(!::arg().preParseFile(fn
.c_str(), "allow-from", ::arg()["allow-from"]))
2607 throw runtime_error("Unable to re-parse configuration file include '"+fn
+"'");
2610 ::arg().preParse(g_argc
, g_argv
, "allow-from-file");
2611 ::arg().preParse(g_argc
, g_argv
, "allow-from");
2614 std::shared_ptr
<NetmaskGroup
> oldAllowFrom
= t_allowFrom
;
2615 std::shared_ptr
<NetmaskGroup
> allowFrom
= std::make_shared
<NetmaskGroup
>();
2617 if(!::arg()["allow-from-file"].empty()) {
2619 ifstream
ifs(::arg()["allow-from-file"].c_str());
2621 throw runtime_error("Could not open '"+::arg()["allow-from-file"]+"': "+stringerror());
2624 string::size_type pos
;
2625 while(getline(ifs
,line
)) {
2627 if(pos
!=string::npos
)
2633 allowFrom
->addMask(line
);
2635 L
<<Logger::Warning
<<"Done parsing " << allowFrom
->size() <<" allow-from ranges from file '"<<::arg()["allow-from-file"]<<"' - overriding 'allow-from' setting"<<endl
;
2637 else if(!::arg()["allow-from"].empty()) {
2639 stringtok(ips
, ::arg()["allow-from"], ", ");
2641 L
<<Logger::Warning
<<"Only allowing queries from: ";
2642 for(vector
<string
>::const_iterator i
= ips
.begin(); i
!= ips
.end(); ++i
) {
2643 allowFrom
->addMask(*i
);
2645 L
<<Logger::Warning
<<", ";
2646 L
<<Logger::Warning
<<*i
;
2648 L
<<Logger::Warning
<<endl
;
2651 if(::arg()["local-address"]!="127.0.0.1" && ::arg().asNum("local-port")==53)
2652 L
<<Logger::Error
<<"WARNING: Allowing queries from all IP addresses - this can be a security risk!"<<endl
;
2653 allowFrom
= nullptr;
2656 g_initialAllowFrom
= allowFrom
;
2657 broadcastFunction(boost::bind(pleaseSupplantACLs
, allowFrom
));
2658 oldAllowFrom
= nullptr;
2660 l_initialized
= true;
2664 static void setupDelegationOnly()
2666 vector
<string
> parts
;
2667 stringtok(parts
, ::arg()["delegation-only"], ", \t");
2668 for(const auto& p
: parts
) {
2669 SyncRes::addDelegationOnly(DNSName(p
));
2673 static int serviceMain(int argc
, char*argv
[])
2675 L
.setName(s_programname
);
2676 L
.setLoglevel((Logger::Urgency
)(6)); // info and up
2677 L
.disableSyslog(::arg().mustDo("disable-syslog"));
2679 if(!::arg()["logging-facility"].empty()) {
2680 int val
=logFacilityToLOG(::arg().asNum("logging-facility") );
2682 theL().setFacility(val
);
2684 L
<<Logger::Error
<<"Unknown logging facility "<<::arg().asNum("logging-facility") <<endl
;
2687 showProductVersion();
2688 seedRandom(::arg()["entropy-source"]);
2690 g_disthashseed
=dns_random(0xffffffff);
2692 checkLinuxIPv6Limits();
2694 vector
<string
> addrs
;
2695 if(!::arg()["query-local-address6"].empty()) {
2696 SyncRes::s_doIPv6
=true;
2697 L
<<Logger::Warning
<<"Enabling IPv6 transport for outgoing queries"<<endl
;
2699 stringtok(addrs
, ::arg()["query-local-address6"], ", ;");
2700 for(const string
& addr
: addrs
) {
2701 g_localQueryAddresses6
.push_back(ComboAddress(addr
));
2705 L
<<Logger::Warning
<<"NOT using IPv6 for outgoing queries - set 'query-local-address6=::' to enable"<<endl
;
2708 stringtok(addrs
, ::arg()["query-local-address"], ", ;");
2709 for(const string
& addr
: addrs
) {
2710 g_localQueryAddresses4
.push_back(ComboAddress(addr
));
2713 catch(std::exception
& e
) {
2714 L
<<Logger::Error
<<"Assigning local query addresses: "<<e
.what();
2718 // keep this ABOVE loadRecursorLuaConfig!
2719 if(::arg()["dnssec"]=="off")
2720 g_dnssecmode
=DNSSECMode::Off
;
2721 else if(::arg()["dnssec"]=="process-no-validate")
2722 g_dnssecmode
=DNSSECMode::ProcessNoValidate
;
2723 else if(::arg()["dnssec"]=="process")
2724 g_dnssecmode
=DNSSECMode::Process
;
2725 else if(::arg()["dnssec"]=="validate")
2726 g_dnssecmode
=DNSSECMode::ValidateAll
;
2727 else if(::arg()["dnssec"]=="log-fail")
2728 g_dnssecmode
=DNSSECMode::ValidateForLog
;
2730 L
<<Logger::Error
<<"Unknown DNSSEC mode "<<::arg()["dnssec"]<<endl
;
2734 g_dnssecLogBogus
= ::arg().mustDo("dnssec-log-bogus");
2735 g_maxNSEC3Iterations
= ::arg().asNum("nsec3-max-iterations");
2738 loadRecursorLuaConfig(::arg()["lua-config-file"], ::arg().mustDo("daemon"));
2740 catch (PDNSException
&e
) {
2741 L
<<Logger::Error
<<"Cannot load Lua configuration: "<<e
.reason
<<endl
;
2746 sortPublicSuffixList();
2748 if(!::arg()["dont-query"].empty()) {
2750 stringtok(ips
, ::arg()["dont-query"], ", ");
2751 ips
.push_back("0.0.0.0");
2752 ips
.push_back("::");
2754 L
<<Logger::Warning
<<"Will not send queries to: ";
2755 for(vector
<string
>::const_iterator i
= ips
.begin(); i
!= ips
.end(); ++i
) {
2756 SyncRes::addDontQuery(*i
);
2758 L
<<Logger::Warning
<<", ";
2759 L
<<Logger::Warning
<<*i
;
2761 L
<<Logger::Warning
<<endl
;
2764 g_quiet
=::arg().mustDo("quiet");
2766 g_weDistributeQueries
= ::arg().mustDo("pdns-distributes-queries");
2767 if(g_weDistributeQueries
) {
2768 L
<<Logger::Warning
<<"PowerDNS Recursor itself will distribute queries over threads"<<endl
;
2771 setupDelegationOnly();
2772 g_outgoingEDNSBufsize
=::arg().asNum("edns-outgoing-bufsize");
2774 if(::arg()["trace"]=="fail") {
2775 SyncRes::setDefaultLogMode(SyncRes::Store
);
2777 else if(::arg().mustDo("trace")) {
2778 SyncRes::setDefaultLogMode(SyncRes::Log
);
2779 ::arg().set("quiet")="no";
2784 SyncRes::s_minimumTTL
= ::arg().asNum("minimum-ttl-override");
2786 SyncRes::s_nopacketcache
= ::arg().mustDo("disable-packetcache");
2788 SyncRes::s_maxnegttl
=::arg().asNum("max-negative-ttl");
2789 SyncRes::s_maxcachettl
=max(::arg().asNum("max-cache-ttl"), 15);
2790 SyncRes::s_packetcachettl
=::arg().asNum("packetcache-ttl");
2791 // Cap the packetcache-servfail-ttl to the packetcache-ttl
2792 uint32_t packetCacheServFailTTL
= ::arg().asNum("packetcache-servfail-ttl");
2793 SyncRes::s_packetcacheservfailttl
=(packetCacheServFailTTL
> SyncRes::s_packetcachettl
) ? SyncRes::s_packetcachettl
: packetCacheServFailTTL
;
2794 SyncRes::s_serverdownmaxfails
=::arg().asNum("server-down-max-fails");
2795 SyncRes::s_serverdownthrottletime
=::arg().asNum("server-down-throttle-time");
2796 SyncRes::s_serverID
=::arg()["server-id"];
2797 SyncRes::s_maxqperq
=::arg().asNum("max-qperq");
2798 SyncRes::s_maxtotusec
=1000*::arg().asNum("max-total-msec");
2799 SyncRes::s_maxdepth
=::arg().asNum("max-recursion-depth");
2800 SyncRes::s_rootNXTrust
= ::arg().mustDo( "root-nx-trust");
2801 if(SyncRes::s_serverID
.empty()) {
2803 gethostname(tmp
, sizeof(tmp
)-1);
2804 SyncRes::s_serverID
=tmp
;
2807 SyncRes::s_ecsipv4limit
= ::arg().asNum("ecs-ipv4-bits");
2808 SyncRes::s_ecsipv6limit
= ::arg().asNum("ecs-ipv6-bits");
2810 g_networkTimeoutMsec
= ::arg().asNum("network-timeout");
2812 g_initialDomainMap
= parseAuthAndForwards();
2814 g_latencyStatSize
=::arg().asNum("latency-statistic-size");
2816 g_logCommonErrors
=::arg().mustDo("log-common-errors");
2818 g_anyToTcp
= ::arg().mustDo("any-to-tcp");
2819 g_udpTruncationThreshold
= ::arg().asNum("udp-truncation-threshold");
2821 g_lowercaseOutgoing
= ::arg().mustDo("lowercase-outgoing");
2823 g_numWorkerThreads
= ::arg().asNum("threads");
2824 g_numThreads
= g_numWorkerThreads
+ g_weDistributeQueries
;
2825 g_maxMThreads
= ::arg().asNum("max-mthreads");
2827 g_gettagNeedsEDNSOptions
= ::arg().mustDo("gettag-needs-edns-options");
2829 g_statisticsInterval
= ::arg().asNum("statistics-interval");
2832 g_reusePort
= ::arg().mustDo("reuseport");
2835 g_useOneSocketPerThread
= (!g_weDistributeQueries
&& g_reusePort
);
2837 if (g_useOneSocketPerThread
) {
2838 for (unsigned int threadId
= 0; threadId
< g_numWorkerThreads
; threadId
++) {
2839 makeUDPServerSockets(threadId
);
2840 makeTCPServerSockets(threadId
);
2844 makeUDPServerSockets(0);
2845 makeTCPServerSockets(0);
2848 SyncRes::parseEDNSSubnetWhitelist(::arg()["edns-subnet-whitelist"]);
2849 g_useIncomingECS
= ::arg().mustDo("use-incoming-edns-subnet");
2852 for(forks
= 0; forks
< ::arg().asNum("processes") - 1; ++forks
) {
2853 if(!fork()) // we are child
2857 if(::arg().mustDo("daemon")) {
2858 L
<<Logger::Warning
<<"Calling daemonize, going to background"<<endl
;
2859 L
.toConsole(Logger::Critical
);
2861 loadRecursorLuaConfig(::arg()["lua-config-file"], false);
2863 signal(SIGUSR1
,usr1Handler
);
2864 signal(SIGUSR2
,usr2Handler
);
2865 signal(SIGPIPE
,SIG_IGN
);
2869 #ifdef HAVE_LIBSODIUM
2870 if (sodium_init() == -1) {
2871 L
<<Logger::Error
<<"Unable to initialize sodium crypto library"<<endl
;
2876 openssl_thread_setup();
2880 if(!::arg()["setgid"].empty())
2881 newgid
=Utility::makeGidNumeric(::arg()["setgid"]);
2883 if(!::arg()["setuid"].empty())
2884 newuid
=Utility::makeUidNumeric(::arg()["setuid"]);
2886 Utility::dropGroupPrivs(newuid
, newgid
);
2888 if (!::arg()["chroot"].empty()) {
2891 ns
= getenv("NOTIFY_SOCKET");
2892 if (ns
!= nullptr) {
2893 L
<<Logger::Error
<<"Unable to chroot when running from systemd. Please disable chroot= or set the 'Type' for this service to 'simple'"<<endl
;
2897 if (chroot(::arg()["chroot"].c_str())<0 || chdir("/") < 0) {
2898 L
<<Logger::Error
<<"Unable to chroot to '"+::arg()["chroot"]+"': "<<strerror (errno
)<<", exiting"<<endl
;
2902 L
<<Logger::Error
<<"Chrooted to '"<<::arg()["chroot"]<<"'"<<endl
;
2905 s_pidfname
=::arg()["socket-dir"]+"/"+s_programname
+".pid";
2906 if(!s_pidfname
.empty())
2907 unlink(s_pidfname
.c_str()); // remove possible old pid file
2910 makeControlChannelSocket( ::arg().asNum("processes") > 1 ? forks
: -1);
2912 Utility::dropUserPrivs(newuid
);
2916 g_tcpTimeout
=::arg().asNum("client-tcp-timeout");
2917 g_maxTCPPerClient
=::arg().asNum("max-tcp-per-client");
2918 g_tcpMaxQueriesPerConn
=::arg().asNum("max-tcp-queries-per-connection");
2920 if (::arg().mustDo("snmp-agent")) {
2921 g_snmpAgent
= std::make_shared
<RecursorSNMPAgent
>("recursor", ::arg()["snmp-master-socket"]);
2925 if(g_numThreads
== 1) {
2926 L
<<Logger::Warning
<<"Operating unthreaded"<<endl
;
2928 sd_notify(0, "READY=1");
2934 L
<<Logger::Warning
<<"Launching "<< g_numThreads
<<" threads"<<endl
;
2935 for(unsigned int n
=0; n
< g_numThreads
; ++n
) {
2936 pthread_create(&tid
, 0, recursorThread
, (void*)(long)n
);
2940 sd_notify(0, "READY=1");
2942 pthread_join(tid
, &res
);
2947 static void* recursorThread(void* ptr
)
2950 t_id
=(int) (long) ptr
;
2951 SyncRes
tmp(g_now
); // make sure it allocates tsstorage before we do anything, like primeHints or so..
2952 SyncRes::setDomainMap(g_initialDomainMap
);
2953 t_allowFrom
= g_initialAllowFrom
;
2954 t_udpclientsocks
= std::unique_ptr
<UDPClientSocks
>(new UDPClientSocks());
2955 t_tcpClientCounts
= std::unique_ptr
<tcpClientCounts_t
>(new tcpClientCounts_t());
2958 t_packetCache
= std::unique_ptr
<RecursorPacketCache
>(new RecursorPacketCache());
2960 #ifdef HAVE_PROTOBUF
2961 t_uuidGenerator
= std::unique_ptr
<boost::uuids::random_generator
>(new boost::uuids::random_generator());
2963 L
<<Logger::Warning
<<"Done priming cache with root hints"<<endl
;
2966 if(!::arg()["lua-dns-script"].empty()) {
2967 t_pdl
= std::make_shared
<RecursorLua4
>(::arg()["lua-dns-script"]);
2968 L
<<Logger::Warning
<<"Loaded 'lua' script from '"<<::arg()["lua-dns-script"]<<"'"<<endl
;
2971 catch(std::exception
&e
) {
2972 L
<<Logger::Error
<<"Failed to load 'lua' script from '"<<::arg()["lua-dns-script"]<<"': "<<e
.what()<<endl
;
2976 unsigned int ringsize
=::arg().asNum("stats-ringbuffer-entries") / g_numWorkerThreads
;
2978 t_remotes
= std::unique_ptr
<addrringbuf_t
>(new addrringbuf_t());
2979 if(g_weDistributeQueries
) // if so, only 1 thread does recvfrom
2980 t_remotes
->set_capacity(::arg().asNum("stats-ringbuffer-entries"));
2982 t_remotes
->set_capacity(ringsize
);
2983 t_servfailremotes
= std::unique_ptr
<addrringbuf_t
>(new addrringbuf_t());
2984 t_servfailremotes
->set_capacity(ringsize
);
2985 t_largeanswerremotes
= std::unique_ptr
<addrringbuf_t
>(new addrringbuf_t());
2986 t_largeanswerremotes
->set_capacity(ringsize
);
2988 t_queryring
= std::unique_ptr
<boost::circular_buffer
<pair
<DNSName
, uint16_t> > >(new boost::circular_buffer
<pair
<DNSName
, uint16_t> >());
2989 t_queryring
->set_capacity(ringsize
);
2990 t_servfailqueryring
= std::unique_ptr
<boost::circular_buffer
<pair
<DNSName
, uint16_t> > >(new boost::circular_buffer
<pair
<DNSName
, uint16_t> >());
2991 t_servfailqueryring
->set_capacity(ringsize
);
2994 MT
=std::unique_ptr
<MTasker
<PacketID
,string
> >(new MTasker
<PacketID
,string
>(::arg().asNum("stack-size")));
2998 t_fdm
=getMultiplexer();
3000 if(::arg().mustDo("webserver")) {
3001 L
<<Logger::Warning
<< "Enabling web server" << endl
;
3003 new RecursorWebServer(t_fdm
);
3005 catch(PDNSException
&e
) {
3006 L
<<Logger::Error
<<"Exception: "<<e
.reason
<<endl
;
3010 L
<<Logger::Error
<<"Enabled '"<< t_fdm
->getName() << "' multiplexer"<<endl
;
3013 t_fdm
->addReadFD(g_pipes
[t_id
].readToThread
, handlePipeRequest
);
3015 if(g_useOneSocketPerThread
) {
3016 for (unsigned int threadId
= 0; threadId
< g_numWorkerThreads
; threadId
++) {
3017 for(deferredAdd_t::const_iterator i
= deferredAdds
[threadId
].cbegin(); i
!= deferredAdds
[threadId
].cend(); ++i
) {
3018 t_fdm
->addReadFD(i
->first
, i
->second
);
3023 if(!g_weDistributeQueries
|| !t_id
) { // if we distribute queries, only t_id = 0 listens
3024 for(deferredAdd_t::const_iterator i
= deferredAdds
[0].cbegin(); i
!= deferredAdds
[0].cend(); ++i
) {
3025 t_fdm
->addReadFD(i
->first
, i
->second
);
3032 t_fdm
->addReadFD(s_rcc
.d_fd
, handleRCC
); // control channel
3035 unsigned int maxTcpClients
=::arg().asNum("max-tcp-clients");
3037 bool listenOnTCP(true);
3039 time_t last_carbon
=0;
3040 time_t carbonInterval
=::arg().asNum("carbon-interval");
3041 counter
.store(0); // used to periodically execute certain tasks
3043 while(MT
->schedule(&g_now
)); // MTasker letting the mthreads do their thing
3045 if(!(counter
%500)) {
3046 MT
->makeThread(houseKeeping
, 0);
3050 typedef vector
<pair
<int, FDMultiplexer::funcparam_t
> > expired_t
;
3051 expired_t expired
=t_fdm
->getTimeouts(g_now
);
3053 for(expired_t::iterator i
=expired
.begin() ; i
!= expired
.end(); ++i
) {
3054 shared_ptr
<TCPConnection
> conn
=any_cast
<shared_ptr
<TCPConnection
> >(i
->second
);
3055 if(g_logCommonErrors
)
3056 L
<<Logger::Warning
<<"Timeout from remote TCP client "<< conn
->d_remote
.toString() <<endl
;
3057 t_fdm
->removeReadFD(i
->first
);
3063 if(!t_id
&& statsWanted
) {
3067 Utility::gettimeofday(&g_now
, 0);
3069 if(!t_id
&& (g_now
.tv_sec
- last_carbon
>= carbonInterval
)) {
3070 MT
->makeThread(doCarbonDump
, 0);
3071 last_carbon
= g_now
.tv_sec
;
3075 // 'run' updates g_now for us
3077 if(!g_weDistributeQueries
|| !t_id
) { // if pdns distributes queries, only tid 0 should do this
3079 if(TCPConnection::getCurrentConnections() > maxTcpClients
) { // shutdown, too many connections
3080 for(tcpListenSockets_t::iterator i
=g_tcpListenSockets
.begin(); i
!= g_tcpListenSockets
.end(); ++i
)
3081 t_fdm
->removeReadFD(*i
);
3086 if(TCPConnection::getCurrentConnections() <= maxTcpClients
) { // reenable
3087 for(tcpListenSockets_t::iterator i
=g_tcpListenSockets
.begin(); i
!= g_tcpListenSockets
.end(); ++i
)
3088 t_fdm
->addReadFD(*i
, handleNewTCPQuestion
);
3095 catch(PDNSException
&ae
) {
3096 L
<<Logger::Error
<<"Exception: "<<ae
.reason
<<endl
;
3099 catch(std::exception
&e
) {
3100 L
<<Logger::Error
<<"STL Exception: "<<e
.what()<<endl
;
3104 L
<<Logger::Error
<<"any other exception in main: "<<endl
;
3109 int main(int argc
, char **argv
)
3113 g_stats
.startupTime
=time(0);
3114 versionSetProduct(ProductRecursor
);
3118 int ret
= EXIT_SUCCESS
;
3121 ::arg().set("stack-size","stack size per mthread")="200000";
3122 ::arg().set("soa-minimum-ttl","Don't change")="0";
3123 ::arg().set("no-shuffle","Don't change")="off";
3124 ::arg().set("local-port","port to listen on")="53";
3125 ::arg().set("local-address","IP addresses to listen on, separated by spaces or commas. Also accepts ports.")="127.0.0.1";
3126 ::arg().setSwitch("non-local-bind", "Enable binding to non-local addresses by using FREEBIND / BINDANY socket options")="no";
3127 ::arg().set("trace","if we should output heaps of logging. set to 'fail' to only log failing domains")="off";
3128 ::arg().set("dnssec", "DNSSEC mode: off/process-no-validate (default)/process/log-fail/validate")="process-no-validate";
3129 ::arg().set("dnssec-log-bogus", "Log DNSSEC bogus validations")="no";
3130 ::arg().set("daemon","Operate as a daemon")="no";
3131 ::arg().setSwitch("write-pid","Write a PID file")="yes";
3132 ::arg().set("loglevel","Amount of logging. Higher is more. Do not set below 3")="4";
3133 ::arg().set("disable-syslog","Disable logging to syslog, useful when running inside a supervisor that logs stdout")="no";
3134 ::arg().set("log-common-errors","If we should log rather common errors")="no";
3135 ::arg().set("chroot","switch to chroot jail")="";
3136 ::arg().set("setgid","If set, change group id to this gid for more security")="";
3137 ::arg().set("setuid","If set, change user id to this uid for more security")="";
3138 ::arg().set("network-timeout", "Wait this number of milliseconds for network i/o")="1500";
3139 ::arg().set("threads", "Launch this number of threads")="2";
3140 ::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!
3141 ::arg().set("config-name","Name of this virtual configuration - will rename the binary image")="";
3142 ::arg().set("api-config-dir", "Directory where REST API stores config and zones") = "";
3143 ::arg().set("api-key", "Static pre-shared authentication key for access to the REST API") = "";
3144 ::arg().set("api-logfile", "Location of the server logfile (used by the REST API)") = "/var/log/pdns.log";
3145 ::arg().set("api-readonly", "Disallow data modification through the REST API when set") = "no";
3146 ::arg().setSwitch("webserver", "Start a webserver (for REST API)") = "no";
3147 ::arg().set("webserver-address", "IP Address of webserver to listen on") = "127.0.0.1";
3148 ::arg().set("webserver-port", "Port of webserver to listen on") = "8082";
3149 ::arg().set("webserver-password", "Password required for accessing the webserver") = "";
3150 ::arg().set("webserver-allow-from","Webserver access is only allowed from these subnets")="0.0.0.0/0,::/0";
3151 ::arg().set("carbon-ourname", "If set, overrides our reported hostname for carbon stats")="";
3152 ::arg().set("carbon-server", "If set, send metrics in carbon (graphite) format to this server IP address")="";
3153 ::arg().set("carbon-interval", "Number of seconds between carbon (graphite) updates")="30";
3154 ::arg().set("statistics-interval", "Number of seconds between printing of recursor statistics, 0 to disable")="1800";
3155 ::arg().set("quiet","Suppress logging of questions and answers")="";
3156 ::arg().set("logging-facility","Facility to log messages as. 0 corresponds to local0")="";
3157 ::arg().set("config-dir","Location of configuration directory (recursor.conf)")=SYSCONFDIR
;
3158 ::arg().set("socket-owner","Owner of socket")="";
3159 ::arg().set("socket-group","Group of socket")="";
3160 ::arg().set("socket-mode", "Permissions for socket")="";
3162 ::arg().set("socket-dir",string("Where the controlsocket will live, ")+LOCALSTATEDIR
+" when unset and not chrooted" )="";
3163 ::arg().set("delegation-only","Which domains we only accept delegations from")="";
3164 ::arg().set("query-local-address","Source IP address for sending queries")="0.0.0.0";
3165 ::arg().set("query-local-address6","Source IPv6 address for sending queries. IF UNSET, IPv6 WILL NOT BE USED FOR OUTGOING QUERIES")="";
3166 ::arg().set("client-tcp-timeout","Timeout in seconds when talking to TCP clients")="2";
3167 ::arg().set("max-mthreads", "Maximum number of simultaneous Mtasker threads")="2048";
3168 ::arg().set("max-tcp-clients","Maximum number of simultaneous TCP clients")="128";
3169 ::arg().set("server-down-max-fails","Maximum number of consecutive timeouts (and unreachables) to mark a server as down ( 0 => disabled )")="64";
3170 ::arg().set("server-down-throttle-time","Number of seconds to throttle all queries to a server after being marked as down")="60";
3171 ::arg().set("hint-file", "If set, load root hints from this file")="";
3172 ::arg().set("max-cache-entries", "If set, maximum number of entries in the main cache")="1000000";
3173 ::arg().set("max-negative-ttl", "maximum number of seconds to keep a negative cached entry in memory")="3600";
3174 ::arg().set("max-cache-ttl", "maximum number of seconds to keep a cached entry in memory")="86400";
3175 ::arg().set("packetcache-ttl", "maximum number of seconds to keep a cached entry in packetcache")="3600";
3176 ::arg().set("max-packetcache-entries", "maximum number of entries to keep in the packetcache")="500000";
3177 ::arg().set("packetcache-servfail-ttl", "maximum number of seconds to keep a cached servfail entry in packetcache")="60";
3178 ::arg().set("server-id", "Returned when queried for 'server.id' TXT or NSID, defaults to hostname")="";
3179 ::arg().set("stats-ringbuffer-entries", "maximum number of packets to store statistics for")="10000";
3180 ::arg().set("version-string", "string reported on version.pdns or version.bind")=fullVersionString();
3181 ::arg().set("allow-from", "If set, only allow these comma separated netmasks to recurse")=LOCAL_NETS
;
3182 ::arg().set("allow-from-file", "If set, load allowed netmasks from this file")="";
3183 ::arg().set("entropy-source", "If set, read entropy from this file")="/dev/urandom";
3184 ::arg().set("dont-query", "If set, do not query these netmasks for DNS data")=DONT_QUERY
;
3185 ::arg().set("max-tcp-per-client", "If set, maximum number of TCP sessions per client (IP address)")="0";
3186 ::arg().set("max-tcp-queries-per-connection", "If set, maximum number of TCP queries in a TCP connection")="0";
3187 ::arg().set("spoof-nearmiss-max", "If non-zero, assume spoofing after this many near misses")="20";
3188 ::arg().set("single-socket", "If set, only use a single socket for outgoing queries")="off";
3189 ::arg().set("auth-zones", "Zones for which we have authoritative data, comma separated domain=file pairs ")="";
3190 ::arg().set("lua-config-file", "More powerful configuration options")="";
3192 ::arg().set("forward-zones", "Zones for which we forward queries, comma separated domain=ip pairs")="";
3193 ::arg().set("forward-zones-recurse", "Zones for which we forward queries with recursion bit, comma separated domain=ip pairs")="";
3194 ::arg().set("forward-zones-file", "File with (+)domain=ip pairs for forwarding")="";
3195 ::arg().set("export-etc-hosts", "If we should serve up contents from /etc/hosts")="off";
3196 ::arg().set("export-etc-hosts-search-suffix", "Also serve up the contents of /etc/hosts with this suffix")="";
3197 ::arg().set("etc-hosts-file", "Path to 'hosts' file")="/etc/hosts";
3198 ::arg().set("serve-rfc1918", "If we should be authoritative for RFC 1918 private IP space")="yes";
3199 ::arg().set("lua-dns-script", "Filename containing an optional 'lua' script that will be used to modify dns answers")="";
3200 ::arg().set("latency-statistic-size","Number of latency values to calculate the qa-latency average")="10000";
3201 ::arg().setSwitch( "disable-packetcache", "Disable packetcache" )= "no";
3202 ::arg().set("ecs-ipv4-bits", "Number of bits of IPv4 address to pass for EDNS Client Subnet")="24";
3203 ::arg().set("ecs-ipv6-bits", "Number of bits of IPv6 address to pass for EDNS Client Subnet")="56";
3204 ::arg().set("edns-subnet-whitelist", "List of netmasks and domains that we should enable EDNS subnet for")="";
3205 ::arg().setSwitch( "use-incoming-edns-subnet", "Pass along received EDNS Client Subnet information")="no";
3206 ::arg().setSwitch( "pdns-distributes-queries", "If PowerDNS itself should distribute queries over threads")="yes";
3207 ::arg().setSwitch( "root-nx-trust", "If set, believe that an NXDOMAIN from the root means the TLD does not exist")="yes";
3208 ::arg().setSwitch( "any-to-tcp","Answer ANY queries with tc=1, shunting to TCP" )="no";
3209 ::arg().setSwitch( "lowercase-outgoing","Force outgoing questions to lowercase")="no";
3210 ::arg().setSwitch("gettag-needs-edns-options", "If EDNS Options should be extracted before calling the gettag() hook")="no";
3211 ::arg().set("udp-truncation-threshold", "Maximum UDP response size before we truncate")="1680";
3212 ::arg().set("edns-outgoing-bufsize", "Outgoing EDNS buffer size")="1680";
3213 ::arg().set("minimum-ttl-override", "Set under adverse conditions, a minimum TTL")="0";
3214 ::arg().set("max-qperq", "Maximum outgoing queries per query")="50";
3215 ::arg().set("max-total-msec", "Maximum total wall-clock time per query in milliseconds, 0 for unlimited")="7000";
3216 ::arg().set("max-recursion-depth", "Maximum number of internal recursion calls per query, 0 for unlimited")="40";
3218 ::arg().set("include-dir","Include *.conf files from this directory")="";
3219 ::arg().set("security-poll-suffix","Domain name from which to query security update notifications")="secpoll.powerdns.com.";
3221 ::arg().setSwitch("reuseport","Enable SO_REUSEPORT allowing multiple recursors processes to listen to 1 address")="no";
3223 ::arg().setSwitch("snmp-agent", "If set, register as an SNMP agent")="no";
3224 ::arg().set("snmp-master-socket", "If set and snmp-agent is set, the socket to use to register to the SNMP master")="";
3226 ::arg().set("tcp-fast-open", "Enable TCP Fast Open support on the listening sockets, using the supplied numerical value as the queue size")="0";
3227 ::arg().set("nsec3-max-iterations", "Maximum number of iterations allowed for an NSEC3 record")="2500";
3229 ::arg().setCmd("help","Provide a helpful message");
3230 ::arg().setCmd("version","Print version string");
3231 ::arg().setCmd("config","Output blank configuration");
3232 L
.toConsole(Logger::Info
);
3233 ::arg().laxParse(argc
,argv
); // do a lax parse
3235 string configname
=::arg()["config-dir"]+"/recursor.conf";
3236 if(::arg()["config-name"]!="") {
3237 configname
=::arg()["config-dir"]+"/recursor-"+::arg()["config-name"]+".conf";
3238 s_programname
+="-"+::arg()["config-name"];
3240 cleanSlashes(configname
);
3242 if(::arg().mustDo("config")) {
3243 cout
<<::arg().configstring()<<endl
;
3247 if(!::arg().file(configname
.c_str()))
3248 L
<<Logger::Warning
<<"Unable to parse configuration file '"<<configname
<<"'"<<endl
;
3250 ::arg().parse(argc
,argv
);
3252 if( !::arg()["chroot"].empty() && !::arg()["api-config-dir"].empty() && !::arg().mustDo("api-readonly") ) {
3253 L
<<Logger::Error
<<"Using chroot and a writable API is not possible"<<endl
;
3257 if (::arg()["socket-dir"].empty()) {
3258 if (::arg()["chroot"].empty())
3259 ::arg().set("socket-dir") = LOCALSTATEDIR
;
3261 ::arg().set("socket-dir") = "/";
3264 ::arg().set("delegation-only")=toLower(::arg()["delegation-only"]);
3266 if(::arg().asNum("threads")==1)
3267 ::arg().set("pdns-distributes-queries")="no";
3269 if(::arg().mustDo("help")) {
3270 cout
<<"syntax:"<<endl
<<endl
;
3271 cout
<<::arg().helpstring(::arg()["help"])<<endl
;
3274 if(::arg().mustDo("version")) {
3275 showProductVersion();
3276 showBuildConfiguration();
3280 Logger::Urgency logUrgency
= (Logger::Urgency
)::arg().asNum("loglevel");
3282 if (logUrgency
< Logger::Error
)
3283 logUrgency
= Logger::Error
;
3284 if(!g_quiet
&& logUrgency
< Logger::Info
) { // Logger::Info=6, Logger::Debug=7
3285 logUrgency
= Logger::Info
; // if you do --quiet=no, you need Info to also see the query log
3287 L
.setLoglevel(logUrgency
);
3288 L
.toConsole(logUrgency
);
3290 serviceMain(argc
, argv
);
3292 catch(PDNSException
&ae
) {
3293 L
<<Logger::Error
<<"Exception: "<<ae
.reason
<<endl
;
3296 catch(std::exception
&e
) {
3297 L
<<Logger::Error
<<"STL Exception: "<<e
.what()<<endl
;
3301 L
<<Logger::Error
<<"any other exception in main: "<<endl
;