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_rwlock_t s_resolversForStubLock
= PTHREAD_RWLOCK_INITIALIZER
;
27 static bool s_stubResolvConfigured
= false;
29 // /etc/resolv.conf last modification time
30 static time_t s_localResolvConfMtime
= 0;
31 static time_t s_localResolvConfLastCheck
= 0;
34 * Returns false if no resolvers are configured, while emitting a warning about this
36 bool resolversDefined()
38 ReadLock
l(&s_resolversForStubLock
);
39 if (s_resolversForStub
.empty()) {
40 g_log
<<Logger::Warning
<<"No upstream resolvers configured, stub resolving (including secpoll and ALIAS) impossible."<<endl
;
47 * Parse /etc/resolv.conf and add those nameservers to s_resolversForStub
49 static void parseLocalResolvConf_locked(const time_t& now
)
52 s_localResolvConfLastCheck
= now
;
54 if (stat(LOCAL_RESOLV_CONF_PATH
, &st
) != -1) {
55 if (st
.st_mtime
!= s_localResolvConfMtime
) {
56 ifstream
ifs(LOCAL_RESOLV_CONF_PATH
);
59 s_localResolvConfMtime
= st
.st_mtime
;
63 s_resolversForStub
.clear();
64 while(std::getline(ifs
, line
)) {
65 boost::trim_right_if(line
, is_any_of(" \r\n\x1a"));
66 boost::trim_left(line
); // leading spaces, let's be nice
68 string::size_type tpos
= line
.find_first_of(";#");
69 if(tpos
!= string::npos
)
72 if(boost::starts_with(line
, "nameserver ") || boost::starts_with(line
, "nameserver\t")) {
74 stringtok(parts
, line
, " \t,"); // be REALLY nice
75 for(vector
<string
>::const_iterator iter
= parts
.begin()+1; iter
!= parts
.end(); ++iter
) {
77 s_resolversForStub
.push_back(ComboAddress(*iter
, 53));
89 static void parseLocalResolvConf()
91 const time_t now
= time(nullptr);
92 if ((s_localResolvConfLastCheck
+ LOCAL_RESOLV_CONF_MAX_CHECK_INTERVAL
) > now
)
95 WriteLock
wl(&s_resolversForStubLock
);
96 parseLocalResolvConf_locked(now
);
101 * Fill the s_resolversForStub vector with addresses for the upstream resolvers.
102 * First, parse the `resolver` configuration option for IP addresses to use.
103 * If that doesn't work, parse /etc/resolv.conf and add those nameservers to
104 * s_resolversForStub.
106 * mainthread() calls this so you don't have to.
108 void stubParseResolveConf()
110 if(::arg().mustDo("resolver")) {
111 WriteLock
wl(&s_resolversForStubLock
);
112 vector
<string
> parts
;
113 stringtok(parts
, ::arg()["resolver"], " ,\t");
114 for (const auto& addr
: parts
)
115 s_resolversForStub
.push_back(ComboAddress(addr
, 53));
118 if (s_resolversForStub
.empty()) {
119 parseLocalResolvConf();
121 // Emit a warning if there are no stubs.
123 s_stubResolvConfigured
= true;
126 // s_resolversForStub contains the ComboAddresses that are used to resolve the
127 int stubDoResolve(const DNSName
& qname
, uint16_t qtype
, vector
<DNSZoneRecord
>& ret
)
129 // ensure resolver gets always configured
130 if (!s_stubResolvConfigured
) {
131 stubParseResolveConf();
133 // only check if resolvers come from local resolv.conf in the first place
134 if (s_localResolvConfMtime
!= 0) {
135 parseLocalResolvConf();
137 if (!resolversDefined())
138 return RCode::ServFail
;
140 ReadLock
l(&s_resolversForStubLock
);
141 vector
<uint8_t> packet
;
143 DNSPacketWriter
pw(packet
, qname
, qtype
);
144 pw
.getHeader()->id
=dns_random(0xffff);
145 pw
.getHeader()->rd
=1;
147 string msg
="Doing stub resolving, using resolvers: ";
148 for (const auto& server
: s_resolversForStub
) {
149 msg
+= server
.toString() + ", ";
151 g_log
<<Logger::Debug
<<msg
.substr(0, msg
.length() - 2)<<endl
;
153 for(const ComboAddress
& dest
: s_resolversForStub
) {
154 Socket
sock(dest
.sin4
.sin_family
, SOCK_DGRAM
);
155 sock
.setNonBlocking();
157 sock
.send(string(packet
.begin(), packet
.end()));
161 waitForData(sock
.getHandle(), 2, 0);
164 sock
.read(reply
); // this calls recv
165 if(reply
.size() > sizeof(struct dnsheader
)) {
167 memcpy(&d
, reply
.c_str(), sizeof(d
));
168 if(d
.id
!= pw
.getHeader()->id
)
175 MOADNSParser
mdp(false, reply
);
176 if(mdp
.d_header
.rcode
== RCode::ServFail
)
179 for(MOADNSParser::answers_t::const_iterator i
=mdp
.d_answers
.begin(); i
!=mdp
.d_answers
.end(); ++i
) {
180 if(i
->first
.d_place
== 1 && i
->first
.d_type
==qtype
) {
187 g_log
<<Logger::Debug
<<"Question got answered by "<<dest
.toString()<<endl
;
188 return mdp
.d_header
.rcode
;
190 return RCode::ServFail
;