]>
Commit | Line | Data |
---|---|---|
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 | ||
43 | string 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 | 57 | int 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 BH |
101 | s.setNonBlocking(); |
102 | s.connect(ie); | |
103 | ||
263f6a5a BH |
104 | uint16_t tlen=htons(vpacket.size()); |
105 | char *lenP=(char*)&tlen; | |
998a4334 BH |
106 | const char *msgP=(const char*)&*vpacket.begin(); |
107 | string packet=string(lenP, lenP+2)+string(msgP, msgP+vpacket.size()); | |
108 | ||
109 | ret=asendtcp(packet, &s); | |
110 | if(!(ret>0)) | |
111 | return ret; | |
112 | ||
113 | packet.clear(); | |
114 | ret=arecvtcp(packet, 2, &s); | |
115 | if(!(ret > 0)) | |
116 | return ret; | |
117 | ||
263f6a5a BH |
118 | memcpy(&tlen, packet.c_str(), 2); |
119 | len=ntohs(tlen); // switch to the 'len' shared with the rest of the function | |
998a4334 BH |
120 | |
121 | ret=arecvtcp(packet, len, &s); | |
122 | if(!(ret > 0)) | |
123 | return ret; | |
124 | ||
263f6a5a BH |
125 | if(len > bufsize) { |
126 | bufsize=len; | |
127 | scoped_array<unsigned char> narray(new unsigned char[bufsize]); | |
128 | buf.swap(narray); | |
998a4334 | 129 | } |
263f6a5a BH |
130 | memcpy(buf.get(), packet.c_str(), len); |
131 | ||
998a4334 BH |
132 | ret=1; |
133 | } | |
134 | catch(NetworkError& ne) { | |
135 | ret = -2; // OS limits error | |
66ab6a63 | 136 | } |
5c633640 | 137 | } |
998a4334 | 138 | |
26de3092 BH |
139 | lwr->d_usec=dt.udiff(); |
140 | *now=dt.getTimeval(); | |
141 | ||
263f6a5a BH |
142 | if(ret <= 0) // includes 'timeout' |
143 | return ret; | |
e14f094b | 144 | |
263f6a5a | 145 | lwr->d_result.clear(); |
c836dc19 | 146 | try { |
263f6a5a BH |
147 | MOADNSParser mdp((const char*)buf.get(), len); |
148 | lwr->d_aabit=mdp.d_header.aa; | |
149 | lwr->d_tcbit=mdp.d_header.tc; | |
150 | lwr->d_rcode=mdp.d_header.rcode; | |
151 | ||
152 | if(Utility::strcasecmp(domain.c_str(), mdp.d_qname.c_str())) { | |
153 | if(domain.find((char)0)==string::npos) {// embedded nulls are too noisy | |
154 | L<<Logger::Notice<<"Packet purporting to come from remote server "<<ip.toString()<<" contained wrong answer: '" << domain << "' != '" << mdp.d_qname << "'" << endl; | |
01ed3112 | 155 | g_stats.unexpectedCount++; |
01608dca | 156 | } |
2353fffa BH |
157 | goto out; |
158 | } | |
51e2144e | 159 | |
ea634573 | 160 | for(MOADNSParser::answers_t::const_iterator i=mdp.d_answers.begin(); i!=mdp.d_answers.end(); ++i) { |
ea634573 BH |
161 | DNSResourceRecord rr; |
162 | rr.qtype=i->first.d_type; | |
163 | rr.qname=i->first.d_label; | |
51e2144e BH |
164 | /* |
165 | if(i->first.d_label == mapped0x20) | |
166 | rr.qname=domain; | |
167 | else | |
168 | rr.qname=i->first.d_label; | |
169 | */ | |
ea634573 BH |
170 | rr.ttl=i->first.d_ttl; |
171 | rr.content=i->first.d_content->getZoneRepresentation(); // this should be the serialised form | |
ea634573 | 172 | rr.d_place=(DNSResourceRecord::Place) i->first.d_place; |
263f6a5a | 173 | lwr->d_result.push_back(rr); |
ea634573 | 174 | } |
263f6a5a BH |
175 | |
176 | return 1; | |
c836dc19 | 177 | } |
aab4adb0 BH |
178 | catch(exception &mde) { |
179 | if(::arg().mustDo("log-common-errors")) | |
263f6a5a | 180 | L<<Logger::Notice<<"Unable to parse packet from remote server "<<ip.toString()<<": "<<mde.what()<<endl; |
aab4adb0 | 181 | } |
c836dc19 | 182 | catch(...) { |
ad1bb608 | 183 | L<<Logger::Notice<<"Unknown error parsing packet from remote server"<<endl; |
c836dc19 | 184 | } |
263f6a5a | 185 | |
aab4adb0 | 186 | g_stats.serverParseError++; |
263f6a5a | 187 | |
2353fffa | 188 | out: |
263f6a5a BH |
189 | lwr->d_rcode=RCode::ServFail; |
190 | ||
191 | return -1; | |
e14f094b BH |
192 | } |
193 | ||
263f6a5a | 194 |