root/trunk/pdns/pdns/lwres.cc @ 1492

Revision 1492, 6.6 KB (checked in by ahu, 3 years ago)

no longer log response packets with an empty domain name - pretty common

  • Property svn:eol-style set to native
  • Property svn:keywords set to author date id revision
Line 
1/*
2    PowerDNS Versatile Database Driven Nameserver
3    Copyright (C) 2002 - 2010 PowerDNS.COM BV
4
5    This program is free software; you can redistribute it and/or modify
6    it under the terms of the GNU General Public License version 2 as
7    published by the Free Software Foundation
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
16    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17*/
18
19
20#include "utility.hh"
21#include "lwres.hh"
22#include <iostream>
23#include "dnsrecords.hh"
24#include <errno.h>
25#include "misc.hh"
26#include <algorithm>
27#include <sstream>
28#include <cstring>
29#include <string>
30#include <vector>
31#include "dns.hh"
32#include "qtype.hh"
33#include "ahuexception.hh"
34#include "arguments.hh"
35#include "sstuff.hh"
36#include "syncres.hh"
37#include "dnswriter.hh"
38#include "dnsparser.hh"
39#include "logger.hh"
40#include "dns_random.hh"
41#include <boost/scoped_array.hpp>
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}
55
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 */
60int asyncresolve(const ComboAddress& ip, const string& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, LWResult *lwr)
61{
62  int len; 
63  int bufsize=1500;
64  scoped_array<unsigned char> buf(new unsigned char[bufsize]);
65  vector<uint8_t> vpacket;
66  //  string mapped0x20=dns0x20(domain);
67  DNSPacketWriter pw(vpacket, domain, type);
68
69  pw.getHeader()->rd=sendRDQuery;
70  pw.getHeader()->id=dns_random(0xffff);
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    }
82
83    pw.addOpt(1200, 0, 0, opts); // 1200 bytes answer size
84    pw.commit();
85  }
86  lwr->d_rcode = 0;
87  lwr->d_pingCorrect = false;
88  lwr->d_haveEDNS = false;
89
90  int ret;
91
92  DTime dt;
93  dt.setTimeval(*now);
94  errno=0;
95  if(!doTCP) {
96    int queryfd;
97    if(ip.sin4.sin_family==AF_INET6)
98      g_stats.ipv6queries++;
99
100    if((ret=asendto((const char*)&*vpacket.begin(), (int)vpacket.size(), 0, ip, pw.getHeader()->id, 
101                    domain, type, &queryfd)) < 0) {
102      return ret; // passes back the -2 EMFILE
103    }
104 
105    // sleep until we see an answer to this, interface to mtasker
106   
107    ret=arecvfrom(reinterpret_cast<char *>(buf.get()), bufsize-1,0, ip, &len, pw.getHeader()->id, 
108                  domain, type, queryfd, now);
109  }
110  else {
111    try {
112      Socket s((AddressFamily)ip.sin4.sin_family, Stream);
113
114      s.setNonBlocking();
115      ComboAddress local = getQueryLocalAddress(ip.sin4.sin_family, 0);
116
117      s.bind(local);
118       
119      ComboAddress remote = ip;
120      remote.sin4.sin_port = htons(53);     
121      s.connect(remote);
122     
123      uint16_t tlen=htons(vpacket.size());
124      char *lenP=(char*)&tlen;
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))           
130        return ret;
131     
132      packet.clear();
133      ret=arecvtcp(packet, 2, &s);
134      if(!(ret > 0))
135        return ret;
136     
137      memcpy(&tlen, packet.c_str(), 2);
138      len=ntohs(tlen); // switch to the 'len' shared with the rest of the function
139     
140      ret=arecvtcp(packet, len, &s);
141      if(!(ret > 0))
142        return ret;
143     
144      if(len > bufsize) {
145        bufsize=len;
146        scoped_array<unsigned char> narray(new unsigned char[bufsize]);
147        buf.swap(narray);
148      }
149      memcpy(buf.get(), packet.c_str(), len);
150
151      ret=1;
152    }
153    catch(NetworkError& ne) {
154      ret = -2; // OS limits error
155    }
156  }
157
158 
159  lwr->d_usec=dt.udiff();
160  *now=dt.getTimeval();
161
162  if(ret <= 0) // includes 'timeout'
163    return ret;
164
165  lwr->d_result.clear();
166  try {
167    MOADNSParser mdp((const char*)buf.get(), len);
168    lwr->d_aabit=mdp.d_header.aa;
169    lwr->d_tcbit=mdp.d_header.tc;
170    lwr->d_rcode=mdp.d_header.rcode;
171   
172    if(mdp.d_header.rcode == RCode::FormErr && mdp.d_qname.empty() && mdp.d_qtype == 0 && mdp.d_qclass == 0) {
173      return 1; // this is "success", the error is set in lwr->d_rcode
174    }
175
176    if(!pdns_iequals(domain, mdp.d_qname)) { 
177      if(!mdp.d_qname.empty() && domain.find((char)0) == string::npos) {// embedded nulls are too noisy, plus empty domains are too
178        L<<Logger::Notice<<"Packet purporting to come from remote server "<<ip.toString()<<" contained wrong answer: '" << domain << "' != '" << mdp.d_qname << "'" << endl;
179      }
180      g_stats.unexpectedCount++;
181      goto out;
182    }
183
184    for(MOADNSParser::answers_t::const_iterator i=mdp.d_answers.begin(); i!=mdp.d_answers.end(); ++i) {         
185      DNSResourceRecord rr;
186      rr.priority = 0;
187      rr.qtype=i->first.d_type;
188      rr.qname=i->first.d_label;
189   
190      rr.ttl=i->first.d_ttl;
191      rr.content=i->first.d_content->getZoneRepresentation();  // this should be the serialised form
192      rr.d_place=(DNSResourceRecord::Place) i->first.d_place;
193      lwr->d_result.push_back(rr);
194    }
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();
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        }
207      }
208    }
209       
210    return 1;
211  }
212  catch(std::exception &mde) {
213    if(::arg().mustDo("log-common-errors"))
214      L<<Logger::Notice<<"Unable to parse packet from remote server "<<ip.toString()<<": "<<mde.what()<<endl;
215    lwr->d_rcode = RCode::FormErr;
216    g_stats.serverParseError++; 
217    return 1; // success - oddly enough
218  }
219  catch(...) {
220    L<<Logger::Notice<<"Unknown error parsing packet from remote server"<<endl;
221  }
222 
223  g_stats.serverParseError++; 
224 
225 out:
226  if(!lwr->d_rcode)
227    lwr->d_rcode=RCode::ServFail;
228
229  return -1;
230}
231
232
Note: See TracBrowser for help on using the browser.