]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/lwres.cc
pdns_ilexicographical_compare() and dns_iequals() optimization
[thirdparty/pdns.git] / pdns / lwres.cc
CommitLineData
e14f094b
BH
1/*
2 PowerDNS Versatile Database Driven Nameserver
673c5f31 3 Copyright (C) 2002 - 2010 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
BH
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
06bd9ccf 16 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
e14f094b 17*/
705f31ae
BH
18
19
36c5ee42 20#include "utility.hh"
e14f094b 21#include "lwres.hh"
e14f094b 22#include <iostream>
81883dcc 23#include "dnsrecords.hh"
e14f094b
BH
24#include <errno.h>
25#include "misc.hh"
26#include <algorithm>
27#include <sstream>
28#include <cstring>
29#include <string>
30#include <vector>
e14f094b
BH
31#include "dns.hh"
32#include "qtype.hh"
e14f094b 33#include "ahuexception.hh"
e14f094b 34#include "arguments.hh"
5c633640
BH
35#include "sstuff.hh"
36#include "syncres.hh"
ea634573
BH
37#include "dnswriter.hh"
38#include "dnsparser.hh"
aab4adb0 39#include "logger.hh"
51e2144e 40#include "dns_random.hh"
263f6a5a 41#include <boost/scoped_array.hpp>
51e2144e
BH
42#include <boost/algorithm/string.hpp>
43
44string dns0x20(const std::string& in)
45{
46 string ret(in);
47 string::size_type len=ret.size();
48 for(string::size_type pos = 0 ; pos < len; ++pos) {
49 if(isalpha(in[pos]) && dns_random(2))
50 ret[pos]^=0x20;
51 }
52 // cerr<<"'"<<in<<"' -> '"<<ret<<"'\n";
53 return ret;
54}
e14f094b 55
81883dcc
BH
56//! returns -2 for OS limits error, -1 for permanent error that has to do with remote **transport**, 0 for timeout, 1 for success
57/** lwr is only filled out in case 1 was returned, and even when returning 1 for 'success', lwr might contain DNS errors
58 Never throws!
59 */
6893459d 60int asyncresolve(const ComboAddress& ip, const string& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, LWResult *lwr)
e14f094b 61{
263f6a5a
BH
62 int len;
63 int bufsize=1500;
64 scoped_array<unsigned char> buf(new unsigned char[bufsize]);
ea634573 65 vector<uint8_t> vpacket;
51e2144e 66 // string mapped0x20=dns0x20(domain);
ea634573
BH
67 DNSPacketWriter pw(vpacket, domain, type);
68
c1d73d94 69 pw.getHeader()->rd=sendRDQuery;
51e2144e 70 pw.getHeader()->id=dns_random(0xffff);
81883dcc
BH
71
72 string ping;
73
74 uint32_t nonce=dns_random(0xffffffff);
75 ping.assign((char*) &nonce, 4);
76
77 if(EDNS0Level && !doTCP) {
78 DNSPacketWriter::optvect_t opts;
79 if(EDNS0Level > 1) {
80 opts.push_back(make_pair(5, ping));
81 }
2188dcc3 82
81883dcc 83 pw.addOpt(1200, 0, 0, opts); // 1200 bytes answer size
2188dcc3
BH
84 pw.commit();
85 }
81883dcc
BH
86 lwr->d_rcode = 0;
87 lwr->d_pingCorrect = false;
88 lwr->d_haveEDNS = false;
e14f094b 89
eefd15f9
BH
90 int ret;
91
92 DTime dt;
5e3da48d 93 dt.setTimeval(*now);
263f6a5a 94 errno=0;
5c633640 95 if(!doTCP) {
4ef015cd 96 int queryfd;
996c89cc
BH
97 if(ip.sin4.sin_family==AF_INET6)
98 g_stats.ipv6queries++;
99
787e5eab 100 if((ret=asendto((const char*)&*vpacket.begin(), (int)vpacket.size(), 0, ip, pw.getHeader()->id,
4957a608 101 domain, type, &queryfd)) < 0) {
998a4334 102 return ret; // passes back the -2 EMFILE
5c633640
BH
103 }
104
105 // sleep until we see an answer to this, interface to mtasker
106
263f6a5a 107 ret=arecvfrom(reinterpret_cast<char *>(buf.get()), bufsize-1,0, ip, &len, pw.getHeader()->id,
4957a608 108 domain, type, queryfd, now);
e14f094b 109 }
5c633640 110 else {
998a4334 111 try {
fdf05fd4
BH
112 Socket s((AddressFamily)ip.sin4.sin_family, Stream);
113
998a4334 114 s.setNonBlocking();
1652a63e 115 ComboAddress local = getQueryLocalAddress(ip.sin4.sin_family, 0);
3ac2a2ab 116
5a38281c 117 s.bind(local);
4957a608 118
fdf05fd4
BH
119 ComboAddress remote = ip;
120 remote.sin4.sin_port = htons(53);
121 s.connect(remote);
998a4334 122
263f6a5a
BH
123 uint16_t tlen=htons(vpacket.size());
124 char *lenP=(char*)&tlen;
998a4334
BH
125 const char *msgP=(const char*)&*vpacket.begin();
126 string packet=string(lenP, lenP+2)+string(msgP, msgP+vpacket.size());
127
128 ret=asendtcp(packet, &s);
129 if(!(ret>0))
4957a608 130 return ret;
998a4334
BH
131
132 packet.clear();
133 ret=arecvtcp(packet, 2, &s);
134 if(!(ret > 0))
4957a608 135 return ret;
998a4334 136
263f6a5a
BH
137 memcpy(&tlen, packet.c_str(), 2);
138 len=ntohs(tlen); // switch to the 'len' shared with the rest of the function
998a4334
BH
139
140 ret=arecvtcp(packet, len, &s);
141 if(!(ret > 0))
4957a608 142 return ret;
998a4334 143
263f6a5a 144 if(len > bufsize) {
4957a608
BH
145 bufsize=len;
146 scoped_array<unsigned char> narray(new unsigned char[bufsize]);
147 buf.swap(narray);
998a4334 148 }
263f6a5a
BH
149 memcpy(buf.get(), packet.c_str(), len);
150
998a4334
BH
151 ret=1;
152 }
153 catch(NetworkError& ne) {
154 ret = -2; // OS limits error
66ab6a63 155 }
5c633640 156 }
998a4334 157
81883dcc 158
26de3092
BH
159 lwr->d_usec=dt.udiff();
160 *now=dt.getTimeval();
161
263f6a5a
BH
162 if(ret <= 0) // includes 'timeout'
163 return ret;
e14f094b 164
263f6a5a 165 lwr->d_result.clear();
c836dc19 166 try {
f1f85f12 167 lwr->d_tcbit=0;
263f6a5a
BH
168 MOADNSParser mdp((const char*)buf.get(), len);
169 lwr->d_aabit=mdp.d_header.aa;
170 lwr->d_tcbit=mdp.d_header.tc;
171 lwr->d_rcode=mdp.d_header.rcode;
172
81883dcc
BH
173 if(mdp.d_header.rcode == RCode::FormErr && mdp.d_qname.empty() && mdp.d_qtype == 0 && mdp.d_qclass == 0) {
174 return 1; // this is "success", the error is set in lwr->d_rcode
175 }
176
ec6480f3 177 if(!pdns_iequals(domain, mdp.d_qname)) {
673c5f31 178 if(!mdp.d_qname.empty() && domain.find((char)0) == string::npos) {// embedded nulls are too noisy, plus empty domains are too
4957a608 179 L<<Logger::Notice<<"Packet purporting to come from remote server "<<ip.toString()<<" contained wrong answer: '" << domain << "' != '" << mdp.d_qname << "'" << endl;
01608dca 180 }
284aa5c2 181 // unexpected count has already been done @ pdns_recursor.cc
2353fffa
BH
182 goto out;
183 }
51e2144e 184
ea634573 185 for(MOADNSParser::answers_t::const_iterator i=mdp.d_answers.begin(); i!=mdp.d_answers.end(); ++i) {
ea634573 186 DNSResourceRecord rr;
10d31f4e 187 rr.priority = 0;
ea634573
BH
188 rr.qtype=i->first.d_type;
189 rr.qname=i->first.d_label;
190 rr.ttl=i->first.d_ttl;
191 rr.content=i->first.d_content->getZoneRepresentation(); // this should be the serialised form
ea634573 192 rr.d_place=(DNSResourceRecord::Place) i->first.d_place;
263f6a5a 193 lwr->d_result.push_back(rr);
ea634573 194 }
81883dcc
BH
195
196 EDNSOpts edo;
197 if(EDNS0Level > 1 && getEDNSOpts(mdp, &edo)) {
198 lwr->d_haveEDNS = true;
199 for(vector<pair<uint16_t, string> >::const_iterator iter = edo.d_options.begin();
4957a608
BH
200 iter != edo.d_options.end();
201 ++iter) {
202 if(iter->first == 5 || iter->first == 4) {// 'EDNS PING'
203 if(iter->second == ping) {
204 lwr->d_pingCorrect = true;
205 }
206 }
81883dcc
BH
207 }
208 }
209
263f6a5a 210 return 1;
c836dc19 211 }
fdbf35ac 212 catch(std::exception &mde) {
aab4adb0 213 if(::arg().mustDo("log-common-errors"))
263f6a5a 214 L<<Logger::Notice<<"Unable to parse packet from remote server "<<ip.toString()<<": "<<mde.what()<<endl;
81883dcc
BH
215 lwr->d_rcode = RCode::FormErr;
216 g_stats.serverParseError++;
217 return 1; // success - oddly enough
aab4adb0 218 }
c836dc19 219 catch(...) {
ad1bb608 220 L<<Logger::Notice<<"Unknown error parsing packet from remote server"<<endl;
c836dc19 221 }
263f6a5a 222
aab4adb0 223 g_stats.serverParseError++;
263f6a5a 224
2353fffa 225 out:
81883dcc
BH
226 if(!lwr->d_rcode)
227 lwr->d_rcode=RCode::ServFail;
263f6a5a
BH
228
229 return -1;
e14f094b
BH
230}
231
263f6a5a 232