]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/stubresolver.cc
rec: ensure correct service user on debian
[thirdparty/pdns.git] / pdns / stubresolver.cc
CommitLineData
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 25static vector<ComboAddress> s_resolversForStub;
9a987ad1
AT
26static pthread_rwlock_t s_resolversForStubLock = PTHREAD_RWLOCK_INITIALIZER;
27static bool s_stubResolvConfigured = false;
9cc98a19
CHB
28
29// /etc/resolv.conf last modification time
bcf07d98 30static time_t s_localResolvConfMtime = 0;
c1e81673 31static 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 */
36bool 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 49static 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
69static 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 88void 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 107int 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}