]>
Commit | Line | Data |
---|---|---|
e14f094b BH |
1 | /* |
2 | PowerDNS Versatile Database Driven Nameserver | |
a5c1b943 | 3 | Copyright (C) 2002 - 2015 PowerDNS.COM BV |
e14f094b BH |
4 | |
5 | This program is free software; you can redistribute it and/or modify | |
d0166f4a BH |
6 | it under the terms of the GNU General Public License version 2 as |
7 | published by the Free Software Foundation | |
e14f094b | 8 | |
f782fe38 MH |
9 | Additionally, the license of this program contains a special |
10 | exception which allows to distribute the program in binary form when | |
11 | it is linked against OpenSSL. | |
12 | ||
e14f094b BH |
13 | This program is distributed in the hope that it will be useful, |
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | GNU General Public License for more details. | |
17 | ||
18 | You should have received a copy of the GNU General Public License | |
19 | along with this program; if not, write to the Free Software | |
06bd9ccf | 20 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
e14f094b | 21 | */ |
705f31ae BH |
22 | |
23 | ||
870a0fe4 AT |
24 | #ifdef HAVE_CONFIG_H |
25 | #include "config.h" | |
26 | #endif | |
36c5ee42 | 27 | #include "utility.hh" |
e14f094b | 28 | #include "lwres.hh" |
e14f094b | 29 | #include <iostream> |
81883dcc | 30 | #include "dnsrecords.hh" |
e14f094b BH |
31 | #include <errno.h> |
32 | #include "misc.hh" | |
33 | #include <algorithm> | |
34 | #include <sstream> | |
35 | #include <cstring> | |
36 | #include <string> | |
37 | #include <vector> | |
e14f094b BH |
38 | #include "dns.hh" |
39 | #include "qtype.hh" | |
5c409fa2 | 40 | #include "pdnsexception.hh" |
e14f094b | 41 | #include "arguments.hh" |
5c633640 BH |
42 | #include "sstuff.hh" |
43 | #include "syncres.hh" | |
ea634573 BH |
44 | #include "dnswriter.hh" |
45 | #include "dnsparser.hh" | |
aab4adb0 | 46 | #include "logger.hh" |
51e2144e | 47 | #include "dns_random.hh" |
263f6a5a | 48 | #include <boost/scoped_array.hpp> |
51e2144e | 49 | #include <boost/algorithm/string.hpp> |
12ce523e | 50 | #include "validate-recursor.hh" |
c4443ccb | 51 | #include "ednssubnet.hh" |
51e2144e | 52 | |
81883dcc BH |
53 | //! returns -2 for OS limits error, -1 for permanent error that has to do with remote **transport**, 0 for timeout, 1 for success |
54 | /** lwr is only filled out in case 1 was returned, and even when returning 1 for 'success', lwr might contain DNS errors | |
55 | Never throws! | |
56 | */ | |
376effcf | 57 | int asyncresolve(const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, LWResult *lwr) |
e14f094b | 58 | { |
263f6a5a | 59 | int len; |
b33c2462 | 60 | int bufsize=g_outgoingEDNSBufsize; |
263f6a5a | 61 | scoped_array<unsigned char> buf(new unsigned char[bufsize]); |
ea634573 | 62 | vector<uint8_t> vpacket; |
51e2144e | 63 | // string mapped0x20=dns0x20(domain); |
ea634573 BH |
64 | DNSPacketWriter pw(vpacket, domain, type); |
65 | ||
c1d73d94 | 66 | pw.getHeader()->rd=sendRDQuery; |
51e2144e | 67 | pw.getHeader()->id=dns_random(0xffff); |
81883dcc BH |
68 | |
69 | string ping; | |
70 | ||
81883dcc BH |
71 | if(EDNS0Level && !doTCP) { |
72 | DNSPacketWriter::optvect_t opts; | |
376effcf | 73 | if(srcmask) { |
74 | EDNSSubnetOpts eo; | |
75 | eo.source = *srcmask; | |
bf4ab707 | 76 | // cout<<"Adding request mask: "<<eo.source.toString()<<endl; |
376effcf | 77 | opts.push_back(make_pair(8, makeEDNSSubnetOptsString(eo))); |
78 | srcmask=boost::optional<Netmask>(); // this is also our return value | |
79 | } | |
93d4a890 | 80 | |
12ce523e | 81 | pw.addOpt(g_outgoingEDNSBufsize, 0, g_dnssecmode == DNSSECMode::Off ? 0 : EDNSOpts::DNSSECOK, opts); |
2188dcc3 BH |
82 | pw.commit(); |
83 | } | |
81883dcc | 84 | lwr->d_rcode = 0; |
81883dcc | 85 | lwr->d_haveEDNS = false; |
eefd15f9 BH |
86 | int ret; |
87 | ||
88 | DTime dt; | |
4c4765c1 | 89 | dt.set(); |
90 | *now=dt.getTimeval(); | |
263f6a5a | 91 | errno=0; |
5c633640 | 92 | if(!doTCP) { |
4ef015cd | 93 | int queryfd; |
996c89cc BH |
94 | if(ip.sin4.sin_family==AF_INET6) |
95 | g_stats.ipv6queries++; | |
96 | ||
787e5eab | 97 | if((ret=asendto((const char*)&*vpacket.begin(), (int)vpacket.size(), 0, ip, pw.getHeader()->id, |
232f0877 | 98 | domain, type, &queryfd)) < 0) { |
998a4334 | 99 | return ret; // passes back the -2 EMFILE |
5c633640 BH |
100 | } |
101 | ||
102 | // sleep until we see an answer to this, interface to mtasker | |
103 | ||
263f6a5a | 104 | ret=arecvfrom(reinterpret_cast<char *>(buf.get()), bufsize-1,0, ip, &len, pw.getHeader()->id, |
232f0877 | 105 | domain, type, queryfd, now); |
e14f094b | 106 | } |
5c633640 | 107 | else { |
998a4334 | 108 | try { |
93f4e5ce | 109 | Socket s(ip.sin4.sin_family, SOCK_STREAM); |
fdf05fd4 | 110 | |
998a4334 | 111 | s.setNonBlocking(); |
1652a63e | 112 | ComboAddress local = getQueryLocalAddress(ip.sin4.sin_family, 0); |
3ac2a2ab | 113 | |
5a38281c | 114 | s.bind(local); |
4957a608 | 115 | |
fdf05fd4 BH |
116 | ComboAddress remote = ip; |
117 | remote.sin4.sin_port = htons(53); | |
118 | s.connect(remote); | |
998a4334 | 119 | |
263f6a5a BH |
120 | uint16_t tlen=htons(vpacket.size()); |
121 | char *lenP=(char*)&tlen; | |
998a4334 BH |
122 | const char *msgP=(const char*)&*vpacket.begin(); |
123 | string packet=string(lenP, lenP+2)+string(msgP, msgP+vpacket.size()); | |
124 | ||
125 | ret=asendtcp(packet, &s); | |
126 | if(!(ret>0)) | |
4957a608 | 127 | return ret; |
998a4334 BH |
128 | |
129 | packet.clear(); | |
825fa717 | 130 | ret=arecvtcp(packet, 2, &s, false); |
998a4334 | 131 | if(!(ret > 0)) |
4957a608 | 132 | return ret; |
998a4334 | 133 | |
263f6a5a BH |
134 | memcpy(&tlen, packet.c_str(), 2); |
135 | len=ntohs(tlen); // switch to the 'len' shared with the rest of the function | |
998a4334 | 136 | |
825fa717 | 137 | ret=arecvtcp(packet, len, &s, false); |
998a4334 | 138 | if(!(ret > 0)) |
4957a608 | 139 | return ret; |
998a4334 | 140 | |
263f6a5a | 141 | if(len > bufsize) { |
4957a608 BH |
142 | bufsize=len; |
143 | scoped_array<unsigned char> narray(new unsigned char[bufsize]); | |
144 | buf.swap(narray); | |
998a4334 | 145 | } |
263f6a5a BH |
146 | memcpy(buf.get(), packet.c_str(), len); |
147 | ||
998a4334 BH |
148 | ret=1; |
149 | } | |
150 | catch(NetworkError& ne) { | |
151 | ret = -2; // OS limits error | |
66ab6a63 | 152 | } |
5c633640 | 153 | } |
998a4334 | 154 | |
81883dcc | 155 | |
26de3092 BH |
156 | lwr->d_usec=dt.udiff(); |
157 | *now=dt.getTimeval(); | |
158 | ||
263f6a5a BH |
159 | if(ret <= 0) // includes 'timeout' |
160 | return ret; | |
e14f094b | 161 | |
e325f20c | 162 | lwr->d_records.clear(); |
c836dc19 | 163 | try { |
f1f85f12 | 164 | lwr->d_tcbit=0; |
263f6a5a BH |
165 | MOADNSParser mdp((const char*)buf.get(), len); |
166 | lwr->d_aabit=mdp.d_header.aa; | |
167 | lwr->d_tcbit=mdp.d_header.tc; | |
168 | lwr->d_rcode=mdp.d_header.rcode; | |
169 | ||
81883dcc BH |
170 | if(mdp.d_header.rcode == RCode::FormErr && mdp.d_qname.empty() && mdp.d_qtype == 0 && mdp.d_qclass == 0) { |
171 | return 1; // this is "success", the error is set in lwr->d_rcode | |
172 | } | |
173 | ||
e325f20c | 174 | if(domain != mdp.d_qname) { |
c5c066bf | 175 | if(!mdp.d_qname.empty() && domain.toString().find((char)0) == string::npos /* ugly */) {// embedded nulls are too noisy, plus empty domains are too |
4957a608 | 176 | L<<Logger::Notice<<"Packet purporting to come from remote server "<<ip.toString()<<" contained wrong answer: '" << domain << "' != '" << mdp.d_qname << "'" << endl; |
01608dca | 177 | } |
284aa5c2 | 178 | // unexpected count has already been done @ pdns_recursor.cc |
2353fffa BH |
179 | goto out; |
180 | } | |
e325f20c | 181 | |
182 | for(const auto& a : mdp.d_answers) | |
183 | lwr->d_records.push_back(a.first); | |
81883dcc BH |
184 | |
185 | EDNSOpts edo; | |
57769f13 | 186 | if(EDNS0Level > 0 && getEDNSOpts(mdp, &edo)) { |
81883dcc | 187 | lwr->d_haveEDNS = true; |
376effcf | 188 | |
189 | for(const auto& opt : edo.d_options) { | |
190 | if(opt.first==8) { | |
191 | EDNSSubnetOpts reso; | |
192 | if(getEDNSSubnetOptsFromString(opt.second, &reso)) { | |
bf4ab707 | 193 | // cerr<<"EDNS Subnet response: "<<reso.source.toString()<<", scope: "<<reso.scope.toString()<<", family = "<<reso.scope.getNetwork().sin4.sin_family<<endl; |
6dd7e60c | 194 | if(reso.scope.getBits()) |
376effcf | 195 | srcmask = reso.scope; |
196 | } | |
197 | } | |
198 | ||
199 | } | |
81883dcc BH |
200 | } |
201 | ||
263f6a5a | 202 | return 1; |
c836dc19 | 203 | } |
fdbf35ac | 204 | catch(std::exception &mde) { |
aab4adb0 | 205 | if(::arg().mustDo("log-common-errors")) |
263f6a5a | 206 | L<<Logger::Notice<<"Unable to parse packet from remote server "<<ip.toString()<<": "<<mde.what()<<endl; |
81883dcc BH |
207 | lwr->d_rcode = RCode::FormErr; |
208 | g_stats.serverParseError++; | |
209 | return 1; // success - oddly enough | |
aab4adb0 | 210 | } |
c836dc19 | 211 | catch(...) { |
ad1bb608 | 212 | L<<Logger::Notice<<"Unknown error parsing packet from remote server"<<endl; |
c836dc19 | 213 | } |
263f6a5a | 214 | |
aab4adb0 | 215 | g_stats.serverParseError++; |
263f6a5a | 216 | |
2353fffa | 217 | out: |
81883dcc BH |
218 | if(!lwr->d_rcode) |
219 | lwr->d_rcode=RCode::ServFail; | |
263f6a5a BH |
220 | |
221 | return -1; | |
e14f094b BH |
222 | } |
223 |