8 #include "arguments.hh"
13 #include "dnswriter.hh"
14 #include "dns_random.hh"
15 #include "namespaces.hh"
17 #include "stubresolver.hh"
19 #define LOCAL_RESOLV_CONF_PATH "/etc/resolv.conf"
20 // don't stat() for local resolv.conf more than once every INTERVAL secs.
21 #define LOCAL_RESOLV_CONF_MAX_CHECK_INTERVAL 60
23 // s_resolversForStub contains the ComboAddresses that are used by
25 static vector
<ComboAddress
> s_resolversForStub
;
26 static pthread_mutex_t s_resolversForStubLock
= PTHREAD_MUTEX_INITIALIZER
;
28 // /etc/resolv.conf last modification time
29 static time_t s_localResolvConfMtime
= 0;
30 static time_t s_localResolvConfLastCheck
= 0;
33 * Returns false if no resolvers are configured, while emitting a warning about this
35 bool resolversDefined()
37 if (s_resolversForStub
.empty()) {
38 g_log
<<Logger::Warning
<<"No upstream resolvers configured, stub resolving (including secpoll and ALIAS) impossible."<<endl
;
45 * Parse /etc/resolv.conf and add those nameservers to s_resolversForStub
47 static void parseLocalResolvConf()
49 const time_t now
= time(nullptr);
52 if ((s_localResolvConfLastCheck
+ LOCAL_RESOLV_CONF_MAX_CHECK_INTERVAL
) > now
)
54 s_localResolvConfLastCheck
= now
;
56 if (stat(LOCAL_RESOLV_CONF_PATH
, &st
) != -1) {
57 if (st
.st_mtime
!= s_localResolvConfMtime
) {
58 ifstream
ifs(LOCAL_RESOLV_CONF_PATH
);
60 Lock
l(&s_resolversForStubLock
);
62 s_localResolvConfMtime
= st
.st_mtime
;
66 s_resolversForStub
.clear();
67 while(std::getline(ifs
, line
)) {
68 boost::trim_right_if(line
, is_any_of(" \r\n\x1a"));
69 boost::trim_left(line
); // leading spaces, let's be nice
71 string::size_type tpos
= line
.find_first_of(";#");
72 if(tpos
!= string::npos
)
75 if(boost::starts_with(line
, "nameserver ") || boost::starts_with(line
, "nameserver\t")) {
77 stringtok(parts
, line
, " \t,"); // be REALLY nice
78 for(vector
<string
>::const_iterator iter
= parts
.begin()+1; iter
!= parts
.end(); ++iter
) {
80 s_resolversForStub
.push_back(ComboAddress(*iter
, 53));
93 * Fill the s_resolversForStub vector with addresses for the upstream resolvers.
94 * First, parse the `resolver` configuration option for IP addresses to use.
95 * If that doesn't work, parse /etc/resolv.conf and add those nameservers to
98 void stubParseResolveConf()
100 if(::arg().mustDo("resolver")) {
101 vector
<string
> parts
;
102 stringtok(parts
, ::arg()["resolver"], " ,\t");
103 for (const auto& addr
: parts
)
104 s_resolversForStub
.push_back(ComboAddress(addr
, 53));
107 if (s_resolversForStub
.empty()) {
108 parseLocalResolvConf();
110 // Emit a warning if there are no stubs.
114 // s_resolversForStub contains the ComboAddresses that are used to resolve the
115 int stubDoResolve(const DNSName
& qname
, uint16_t qtype
, vector
<DNSZoneRecord
>& ret
)
117 // only check if resolvers come from local resolv.conf in the first place
118 if (s_localResolvConfMtime
!= 0) {
119 parseLocalResolvConf();
121 if (!resolversDefined())
122 return RCode::ServFail
;
124 vector
<uint8_t> packet
;
126 DNSPacketWriter
pw(packet
, qname
, qtype
);
127 pw
.getHeader()->id
=dns_random(0xffff);
128 pw
.getHeader()->rd
=1;
130 string msg
="Doing stub resolving, using resolvers: ";
131 for (const auto& server
: s_resolversForStub
) {
132 msg
+= server
.toString() + ", ";
134 g_log
<<Logger::Debug
<<msg
.substr(0, msg
.length() - 2)<<endl
;
136 for(const ComboAddress
& dest
: s_resolversForStub
) {
137 Socket
sock(dest
.sin4
.sin_family
, SOCK_DGRAM
);
138 sock
.setNonBlocking();
140 sock
.send(string(packet
.begin(), packet
.end()));
144 waitForData(sock
.getHandle(), 2, 0);
147 sock
.read(reply
); // this calls recv
148 if(reply
.size() > sizeof(struct dnsheader
)) {
150 memcpy(&d
, reply
.c_str(), sizeof(d
));
151 if(d
.id
!= pw
.getHeader()->id
)
158 MOADNSParser
mdp(false, reply
);
159 if(mdp
.d_header
.rcode
== RCode::ServFail
)
162 for(MOADNSParser::answers_t::const_iterator i
=mdp
.d_answers
.begin(); i
!=mdp
.d_answers
.end(); ++i
) {
163 if(i
->first
.d_place
== 1 && i
->first
.d_type
==qtype
) {
170 g_log
<<Logger::Debug
<<"Question got answered by "<<dest
.toString()<<endl
;
171 return mdp
.d_header
.rcode
;
173 return RCode::ServFail
;