]>
Commit | Line | Data |
---|---|---|
9cc98a19 CHB |
1 | #include <sys/stat.h> |
2 | ||
24317c7f PD |
3 | #ifdef HAVE_CONFIG_H |
4 | #include "config.h" | |
5 | #endif | |
6 | ||
7 | #include "logger.hh" | |
8 | #include "arguments.hh" | |
9 | #include "version.hh" | |
10 | #include "misc.hh" | |
11 | ||
12 | #include "sstuff.hh" | |
13 | #include "dnswriter.hh" | |
14 | #include "dns_random.hh" | |
15 | #include "namespaces.hh" | |
16 | #include "statbag.hh" | |
17 | #include "stubresolver.hh" | |
18 | ||
9cc98a19 | 19 | #define LOCAL_RESOLV_CONF_PATH "/etc/resolv.conf" |
c1e81673 CHB |
20 | // don't stat() for local resolv.conf more than once every INTERVAL secs. |
21 | #define LOCAL_RESOLV_CONF_MAX_CHECK_INTERVAL 60 | |
9cc98a19 | 22 | |
2b78726c | 23 | // s_resolversForStub contains the ComboAddresses that are used by |
150e318e | 24 | // stubDoResolve |
2b78726c | 25 | static vector<ComboAddress> s_resolversForStub; |
9a987ad1 AT |
26 | static pthread_rwlock_t s_resolversForStubLock = PTHREAD_RWLOCK_INITIALIZER; |
27 | static bool s_stubResolvConfigured = false; | |
9cc98a19 CHB |
28 | |
29 | // /etc/resolv.conf last modification time | |
bcf07d98 | 30 | static time_t s_localResolvConfMtime = 0; |
c1e81673 | 31 | static time_t s_localResolvConfLastCheck = 0; |
24317c7f | 32 | |
2b78726c PL |
33 | /* |
34 | * Returns false if no resolvers are configured, while emitting a warning about this | |
35 | */ | |
36 | bool resolversDefined() | |
37 | { | |
9a987ad1 | 38 | ReadLock l(&s_resolversForStubLock); |
2b78726c | 39 | if (s_resolversForStub.empty()) { |
e6a9dde5 | 40 | g_log<<Logger::Warning<<"No upstream resolvers configured, stub resolving (including secpoll and ALIAS) impossible."<<endl; |
2b78726c PL |
41 | return false; |
42 | } | |
43 | return true; | |
44 | } | |
45 | ||
9cc98a19 CHB |
46 | /* |
47 | * Parse /etc/resolv.conf and add those nameservers to s_resolversForStub | |
48 | */ | |
9a987ad1 | 49 | static void parseLocalResolvConf_locked(const time_t& now) |
9cc98a19 | 50 | { |
9cc98a19 | 51 | struct stat st; |
c1e81673 CHB |
52 | s_localResolvConfLastCheck = now; |
53 | ||
54 | if (stat(LOCAL_RESOLV_CONF_PATH, &st) != -1) { | |
55 | if (st.st_mtime != s_localResolvConfMtime) { | |
5d4e1ef8 | 56 | std::vector<ComboAddress> resolvers = getResolvers(LOCAL_RESOLV_CONF_PATH); |
c1e81673 CHB |
57 | |
58 | s_localResolvConfMtime = st.st_mtime; | |
c1e81673 | 59 | |
5d4e1ef8 RG |
60 | if (resolvers.empty()) { |
61 | return; | |
9cc98a19 | 62 | } |
5d4e1ef8 RG |
63 | |
64 | s_resolversForStub = std::move(resolvers); | |
9cc98a19 CHB |
65 | } |
66 | } | |
9cc98a19 CHB |
67 | } |
68 | ||
9a987ad1 AT |
69 | static void parseLocalResolvConf() |
70 | { | |
71 | const time_t now = time(nullptr); | |
72 | if ((s_localResolvConfLastCheck + LOCAL_RESOLV_CONF_MAX_CHECK_INTERVAL) > now) | |
73 | return ; | |
74 | ||
75 | WriteLock wl(&s_resolversForStubLock); | |
76 | parseLocalResolvConf_locked(now); | |
77 | } | |
78 | ||
79 | ||
2b78726c PL |
80 | /* |
81 | * Fill the s_resolversForStub vector with addresses for the upstream resolvers. | |
82 | * First, parse the `resolver` configuration option for IP addresses to use. | |
83 | * If that doesn't work, parse /etc/resolv.conf and add those nameservers to | |
84 | * s_resolversForStub. | |
faf7f65b PD |
85 | * |
86 | * mainthread() calls this so you don't have to. | |
24317c7f | 87 | */ |
150e318e | 88 | void stubParseResolveConf() |
24317c7f | 89 | { |
2b78726c | 90 | if(::arg().mustDo("resolver")) { |
9a987ad1 | 91 | WriteLock wl(&s_resolversForStubLock); |
2b78726c PL |
92 | vector<string> parts; |
93 | stringtok(parts, ::arg()["resolver"], " ,\t"); | |
94 | for (const auto& addr : parts) | |
95 | s_resolversForStub.push_back(ComboAddress(addr, 53)); | |
96 | } | |
24317c7f | 97 | |
2b78726c | 98 | if (s_resolversForStub.empty()) { |
9cc98a19 | 99 | parseLocalResolvConf(); |
24317c7f | 100 | } |
2b78726c PL |
101 | // Emit a warning if there are no stubs. |
102 | resolversDefined(); | |
9a987ad1 | 103 | s_stubResolvConfigured = true; |
24317c7f PD |
104 | } |
105 | ||
2b78726c | 106 | // s_resolversForStub contains the ComboAddresses that are used to resolve the |
90ba52e0 | 107 | int stubDoResolve(const DNSName& qname, uint16_t qtype, vector<DNSZoneRecord>& ret) |
24317c7f | 108 | { |
9a987ad1 AT |
109 | // ensure resolver gets always configured |
110 | if (!s_stubResolvConfigured) { | |
111 | stubParseResolveConf(); | |
112 | } | |
3ad680b1 | 113 | // only check if resolvers come from local resolv.conf in the first place |
9cc98a19 | 114 | if (s_localResolvConfMtime != 0) { |
9cc98a19 | 115 | parseLocalResolvConf(); |
9cc98a19 | 116 | } |
2b78726c PL |
117 | if (!resolversDefined()) |
118 | return RCode::ServFail; | |
119 | ||
9a987ad1 | 120 | ReadLock l(&s_resolversForStubLock); |
24317c7f PD |
121 | vector<uint8_t> packet; |
122 | ||
90ba52e0 | 123 | DNSPacketWriter pw(packet, qname, qtype); |
24317c7f PD |
124 | pw.getHeader()->id=dns_random(0xffff); |
125 | pw.getHeader()->rd=1; | |
24317c7f | 126 | |
150e318e | 127 | string msg ="Doing stub resolving, using resolvers: "; |
2b78726c | 128 | for (const auto& server : s_resolversForStub) { |
24317c7f PD |
129 | msg += server.toString() + ", "; |
130 | } | |
e6a9dde5 | 131 | g_log<<Logger::Debug<<msg.substr(0, msg.length() - 2)<<endl; |
24317c7f | 132 | |
2b78726c | 133 | for(const ComboAddress& dest : s_resolversForStub) { |
24317c7f PD |
134 | Socket sock(dest.sin4.sin_family, SOCK_DGRAM); |
135 | sock.setNonBlocking(); | |
90ba52e0 | 136 | sock.connect(dest); |
137 | sock.send(string(packet.begin(), packet.end())); | |
24317c7f PD |
138 | |
139 | string reply; | |
140 | ||
141 | waitForData(sock.getHandle(), 2, 0); | |
142 | try { | |
143 | retry: | |
90ba52e0 | 144 | sock.read(reply); // this calls recv |
24317c7f PD |
145 | if(reply.size() > sizeof(struct dnsheader)) { |
146 | struct dnsheader d; | |
147 | memcpy(&d, reply.c_str(), sizeof(d)); | |
148 | if(d.id != pw.getHeader()->id) | |
149 | goto retry; | |
150 | } | |
151 | } | |
152 | catch(...) { | |
153 | continue; | |
154 | } | |
27c0050c | 155 | MOADNSParser mdp(false, reply); |
24317c7f PD |
156 | if(mdp.d_header.rcode == RCode::ServFail) |
157 | continue; | |
158 | ||
24317c7f PD |
159 | for(MOADNSParser::answers_t::const_iterator i=mdp.d_answers.begin(); i!=mdp.d_answers.end(); ++i) { |
160 | if(i->first.d_place == 1 && i->first.d_type==qtype) { | |
90ba52e0 | 161 | DNSZoneRecord zrr; |
162 | zrr.dr = i->first; | |
163 | zrr.auth=true; | |
164 | ret.push_back(zrr); | |
24317c7f PD |
165 | } |
166 | } | |
e6a9dde5 | 167 | g_log<<Logger::Debug<<"Question got answered by "<<dest.toString()<<endl; |
24317c7f PD |
168 | return mdp.d_header.rcode; |
169 | } | |
170 | return RCode::ServFail; | |
90ba52e0 | 171 | } |