]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/lwres.cc
define EDNSStatus struct & map, plus define the EDNS and EDNS-ping statistics, plus...
[thirdparty/pdns.git] / pdns / lwres.cc
CommitLineData
e14f094b
BH
1/*
2 PowerDNS Versatile Database Driven Nameserver
51e2144e 3 Copyright (C) 2002 - 2008 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
BH
22#include <iostream>
23#include <errno.h>
24#include "misc.hh"
25#include <algorithm>
26#include <sstream>
27#include <cstring>
28#include <string>
29#include <vector>
e14f094b
BH
30#include "dns.hh"
31#include "qtype.hh"
e14f094b 32#include "ahuexception.hh"
e14f094b 33#include "arguments.hh"
5c633640
BH
34#include "sstuff.hh"
35#include "syncres.hh"
ea634573
BH
36#include "dnswriter.hh"
37#include "dnsparser.hh"
aab4adb0 38#include "logger.hh"
51e2144e 39#include "dns_random.hh"
263f6a5a 40#include <boost/scoped_array.hpp>
51e2144e
BH
41#include <boost/algorithm/string.hpp>
42
43string dns0x20(const std::string& in)
44{
45 string ret(in);
46 string::size_type len=ret.size();
47 for(string::size_type pos = 0 ; pos < len; ++pos) {
48 if(isalpha(in[pos]) && dns_random(2))
49 ret[pos]^=0x20;
50 }
51 // cerr<<"'"<<in<<"' -> '"<<ret<<"'\n";
52 return ret;
53}
e14f094b 54
998a4334 55//! returns -2 for OS limits error, -1 for permanent error that has to do with remote, 0 for timeout, 1 for success
e14f094b 56/** Never throws! */
2188dcc3 57int asyncresolve(const ComboAddress& ip, const string& domain, int type, bool doTCP, bool doEDNS0, struct timeval* now, LWResult *lwr)
e14f094b 58{
263f6a5a
BH
59 int len;
60 int bufsize=1500;
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
66 pw.getHeader()->rd=0;
51e2144e 67 pw.getHeader()->id=dns_random(0xffff);
2188dcc3
BH
68
69 if(doEDNS0 && !doTCP) {
70 pw.addOpt(1200, 0, 0); // 1200 bytes answer size
71 pw.commit();
72 }
263f6a5a 73 lwr->d_rcode=0;
e14f094b 74
eefd15f9
BH
75 int ret;
76
77 DTime dt;
5e3da48d 78 dt.setTimeval(*now);
263f6a5a 79 errno=0;
5c633640 80 if(!doTCP) {
4ef015cd 81 int queryfd;
996c89cc
BH
82 if(ip.sin4.sin_family==AF_INET6)
83 g_stats.ipv6queries++;
84
787e5eab
BH
85 if((ret=asendto((const char*)&*vpacket.begin(), (int)vpacket.size(), 0, ip, pw.getHeader()->id,
86 domain, type, &queryfd)) < 0) {
998a4334 87 return ret; // passes back the -2 EMFILE
5c633640
BH
88 }
89
90 // sleep until we see an answer to this, interface to mtasker
91
263f6a5a 92 ret=arecvfrom(reinterpret_cast<char *>(buf.get()), bufsize-1,0, ip, &len, pw.getHeader()->id,
f6c254c1 93 domain, type, queryfd, now->tv_sec);
e14f094b 94 }
5c633640 95 else {
998a4334 96 try {
ccd3ed60 97 if(ip.sin4.sin_family != AF_INET) // sstuff isn't yet ready for IPv6
996c89cc 98 return -1;
998a4334 99 Socket s(InterNetwork, Stream);
ccd3ed60 100 IPEndpoint ie(U32ToIP(ntohl(ip.sin4.sin_addr.s_addr)), 53); // WRONG WRONG WRONG XXX FIXME
998a4334 101 s.setNonBlocking();
3ac2a2ab
BH
102 string bindIP=::arg()["query-local-address"];
103 if(!bindIP.empty()) {
104 ComboAddress local(bindIP);
105 s.bind(local.sin4);
106 }
107
998a4334
BH
108 s.connect(ie);
109
263f6a5a
BH
110 uint16_t tlen=htons(vpacket.size());
111 char *lenP=(char*)&tlen;
998a4334
BH
112 const char *msgP=(const char*)&*vpacket.begin();
113 string packet=string(lenP, lenP+2)+string(msgP, msgP+vpacket.size());
114
115 ret=asendtcp(packet, &s);
116 if(!(ret>0))
117 return ret;
118
119 packet.clear();
120 ret=arecvtcp(packet, 2, &s);
121 if(!(ret > 0))
122 return ret;
123
263f6a5a
BH
124 memcpy(&tlen, packet.c_str(), 2);
125 len=ntohs(tlen); // switch to the 'len' shared with the rest of the function
998a4334
BH
126
127 ret=arecvtcp(packet, len, &s);
128 if(!(ret > 0))
129 return ret;
130
263f6a5a
BH
131 if(len > bufsize) {
132 bufsize=len;
133 scoped_array<unsigned char> narray(new unsigned char[bufsize]);
134 buf.swap(narray);
998a4334 135 }
263f6a5a
BH
136 memcpy(buf.get(), packet.c_str(), len);
137
998a4334
BH
138 ret=1;
139 }
140 catch(NetworkError& ne) {
141 ret = -2; // OS limits error
66ab6a63 142 }
5c633640 143 }
998a4334 144
26de3092
BH
145 lwr->d_usec=dt.udiff();
146 *now=dt.getTimeval();
147
263f6a5a
BH
148 if(ret <= 0) // includes 'timeout'
149 return ret;
e14f094b 150
263f6a5a 151 lwr->d_result.clear();
c836dc19 152 try {
263f6a5a
BH
153 MOADNSParser mdp((const char*)buf.get(), len);
154 lwr->d_aabit=mdp.d_header.aa;
155 lwr->d_tcbit=mdp.d_header.tc;
156 lwr->d_rcode=mdp.d_header.rcode;
157
158 if(Utility::strcasecmp(domain.c_str(), mdp.d_qname.c_str())) {
159 if(domain.find((char)0)==string::npos) {// embedded nulls are too noisy
160 L<<Logger::Notice<<"Packet purporting to come from remote server "<<ip.toString()<<" contained wrong answer: '" << domain << "' != '" << mdp.d_qname << "'" << endl;
01ed3112 161 g_stats.unexpectedCount++;
01608dca 162 }
2353fffa
BH
163 goto out;
164 }
51e2144e 165
ea634573 166 for(MOADNSParser::answers_t::const_iterator i=mdp.d_answers.begin(); i!=mdp.d_answers.end(); ++i) {
ea634573
BH
167 DNSResourceRecord rr;
168 rr.qtype=i->first.d_type;
169 rr.qname=i->first.d_label;
51e2144e
BH
170 /*
171 if(i->first.d_label == mapped0x20)
172 rr.qname=domain;
173 else
174 rr.qname=i->first.d_label;
175 */
ea634573
BH
176 rr.ttl=i->first.d_ttl;
177 rr.content=i->first.d_content->getZoneRepresentation(); // this should be the serialised form
ea634573 178 rr.d_place=(DNSResourceRecord::Place) i->first.d_place;
263f6a5a 179 lwr->d_result.push_back(rr);
ea634573 180 }
263f6a5a
BH
181
182 return 1;
c836dc19 183 }
fdbf35ac 184 catch(std::exception &mde) {
aab4adb0 185 if(::arg().mustDo("log-common-errors"))
263f6a5a 186 L<<Logger::Notice<<"Unable to parse packet from remote server "<<ip.toString()<<": "<<mde.what()<<endl;
aab4adb0 187 }
c836dc19 188 catch(...) {
ad1bb608 189 L<<Logger::Notice<<"Unknown error parsing packet from remote server"<<endl;
c836dc19 190 }
263f6a5a 191
aab4adb0 192 g_stats.serverParseError++;
263f6a5a 193
2353fffa 194 out:
263f6a5a
BH
195 lwr->d_rcode=RCode::ServFail;
196
197 return -1;
e14f094b
BH
198}
199
263f6a5a 200