]> git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/stubresolver.cc
rec: Don't account chained queries more than once
[thirdparty/pdns.git] / pdns / stubresolver.cc
1 #ifdef HAVE_CONFIG_H
2 #include "config.h"
3 #endif
4
5 #include "logger.hh"
6 #include "arguments.hh"
7 #include "version.hh"
8 #include "misc.hh"
9
10 #include "sstuff.hh"
11 #include "dnswriter.hh"
12 #include "dns_random.hh"
13 #include "namespaces.hh"
14 #include "statbag.hh"
15 #include "stubresolver.hh"
16
17 // s_resolversForStub contains the ComboAddresses that are used by
18 // stubDoResolve
19 static vector<ComboAddress> s_resolversForStub;
20
21 /*
22 * Returns false if no resolvers are configured, while emitting a warning about this
23 */
24 bool resolversDefined()
25 {
26 if (s_resolversForStub.empty()) {
27 L<<Logger::Warning<<"No upstream resolvers configured, stub resolving (including secpoll and ALIAS) impossible."<<endl;
28 return false;
29 }
30 return true;
31 }
32
33 /*
34 * Fill the s_resolversForStub vector with addresses for the upstream resolvers.
35 * First, parse the `resolver` configuration option for IP addresses to use.
36 * If that doesn't work, parse /etc/resolv.conf and add those nameservers to
37 * s_resolversForStub.
38 */
39 void stubParseResolveConf()
40 {
41 if(::arg().mustDo("resolver")) {
42 vector<string> parts;
43 stringtok(parts, ::arg()["resolver"], " ,\t");
44 for (const auto& addr : parts)
45 s_resolversForStub.push_back(ComboAddress(addr, 53));
46 }
47
48 if (s_resolversForStub.empty()) {
49 ifstream ifs("/etc/resolv.conf");
50 if(!ifs)
51 return;
52
53 string line;
54 while(std::getline(ifs, line)) {
55 boost::trim_right_if(line, is_any_of(" \r\n\x1a"));
56 boost::trim_left(line); // leading spaces, let's be nice
57
58 string::size_type tpos = line.find_first_of(";#");
59 if(tpos != string::npos)
60 line.resize(tpos);
61
62 if(boost::starts_with(line, "nameserver ") || boost::starts_with(line, "nameserver\t")) {
63 vector<string> parts;
64 stringtok(parts, line, " \t,"); // be REALLY nice
65 for(vector<string>::const_iterator iter = parts.begin()+1; iter != parts.end(); ++iter) {
66 try {
67 s_resolversForStub.push_back(ComboAddress(*iter, 53));
68 }
69 catch(...)
70 {
71 }
72 }
73 }
74 }
75 }
76 // Emit a warning if there are no stubs.
77 resolversDefined();
78 }
79
80 // s_resolversForStub contains the ComboAddresses that are used to resolve the
81 int stubDoResolve(const DNSName& qname, uint16_t qtype, vector<DNSZoneRecord>& ret)
82 {
83 if (!resolversDefined())
84 return RCode::ServFail;
85
86 vector<uint8_t> packet;
87
88 DNSPacketWriter pw(packet, qname, qtype);
89 pw.getHeader()->id=dns_random(0xffff);
90 pw.getHeader()->rd=1;
91
92 string msg ="Doing stub resolving, using resolvers: ";
93 for (const auto& server : s_resolversForStub) {
94 msg += server.toString() + ", ";
95 }
96 L<<Logger::Debug<<msg.substr(0, msg.length() - 2)<<endl;
97
98 for(const ComboAddress& dest : s_resolversForStub) {
99 Socket sock(dest.sin4.sin_family, SOCK_DGRAM);
100 sock.setNonBlocking();
101 sock.connect(dest);
102 sock.send(string(packet.begin(), packet.end()));
103
104 string reply;
105
106 waitForData(sock.getHandle(), 2, 0);
107 try {
108 retry:
109 sock.read(reply); // this calls recv
110 if(reply.size() > sizeof(struct dnsheader)) {
111 struct dnsheader d;
112 memcpy(&d, reply.c_str(), sizeof(d));
113 if(d.id != pw.getHeader()->id)
114 goto retry;
115 }
116 }
117 catch(...) {
118 continue;
119 }
120 MOADNSParser mdp(false, reply);
121 if(mdp.d_header.rcode == RCode::ServFail)
122 continue;
123
124 for(MOADNSParser::answers_t::const_iterator i=mdp.d_answers.begin(); i!=mdp.d_answers.end(); ++i) {
125 if(i->first.d_place == 1 && i->first.d_type==qtype) {
126 DNSZoneRecord zrr;
127 zrr.dr = i->first;
128 zrr.auth=true;
129 ret.push_back(zrr);
130 }
131 }
132 L<<Logger::Debug<<"Question got answered by "<<dest.toString()<<endl;
133 return mdp.d_header.rcode;
134 }
135 return RCode::ServFail;
136 }