root/trunk/pdns/pdns/dnsparser.cc @ 524

Revision 524, 9.6 KB (checked in by ahu, 8 years ago)

update TODO list
some cosmetic changes in pdns_recursor
make dnsreplay_mindex compile again
improve 'trailing garbage' error
teach zone content input/output code about spaces in labels

Line 
1/*
2    PowerDNS Versatile Database Driven Nameserver
3    Copyright (C) 2005  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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17*/
18
19#include "dnsparser.hh"
20#include "dnswriter.hh"
21#include <boost/lexical_cast.hpp>
22
23using namespace boost;
24
25class UnknownRecordContent : public DNSRecordContent
26{
27public:
28  UnknownRecordContent(const DNSRecord& dr, PacketReader& pr) 
29    : DNSRecordContent(dr.d_type), d_dr(dr)
30  {
31    pr.copyRecord(d_record, dr.d_clen);
32  }
33
34  UnknownRecordContent(const string& zone) : DNSRecordContent(0)
35  {
36    d_record.insert(d_record.end(), zone.begin(), zone.end());
37  }
38 
39  string getZoneRepresentation() const
40  {
41    ostringstream str;
42 
43    str<<"\\# "<<d_record.size()<<" ";
44    char hex[4];
45    for(size_t n=0; n<d_record.size(); ++n) {
46      snprintf(hex,sizeof(hex)-1, "%02x", d_record.at(n));
47      str << hex;
48    }
49    return str.str();
50  }
51 
52  void toPacket(DNSPacketWriter& pw)
53  {
54    string tmp((char*)&*d_record.begin(), (char*)&*d_record.end());
55    vector<string> parts;
56    stringtok(parts, tmp);
57    const string& relevant=parts[2];
58    unsigned int total=atoi(parts[1].c_str());
59    if(relevant.size()!=2*total)
60      throw runtime_error("invalid unknown record");
61    string out;
62    for(unsigned int n=0; n < total; ++n) {
63      int c;
64      sscanf(relevant.c_str()+2*n, "%02x", &c);
65      out.append(1, (char)c);
66    }
67    pw.xfrBlob(out);
68  }
69private:
70  DNSRecord d_dr;
71  vector<uint8_t> d_record;
72};
73
74static const string EncodeDNSLabel(const string& input) 
75{ 
76  typedef vector<string> parts_t; 
77  parts_t parts; 
78  stringtok(parts,input,".");                   
79  string ret; 
80  for(parts_t::const_iterator i=parts.begin(); i!=parts.end(); ++i) { 
81    ret.append(1,(char)i->length()); 
82    ret.append(*i); 
83  } 
84  ret.append(1,(char)0); 
85  return ret; 
86} 
87
88shared_ptr<DNSRecordContent> DNSRecordContent::unserialize(const string& qname, uint16_t qtype, const string& serialized)
89{
90  dnsheader dnsheader;
91  memset(&dnsheader, 0, sizeof(dnsheader));
92  dnsheader.qdcount=htons(1);
93  dnsheader.ancount=htons(1);
94
95  vector<uint8_t> packet; // build pseudo packet
96  const uint8_t* ptr=(const uint8_t*)&dnsheader;
97  packet.insert(packet.end(), ptr, ptr + sizeof(dnsheader));   
98  char tmp[6]="\x0" "\x0\x1" "\x0\x1"; // root question for ns_t_a
99  packet.insert(packet.end(), tmp, tmp+5);
100
101  string encoded=EncodeDNSLabel(qname);
102  packet.insert(packet.end(), encoded.c_str(), encoded.c_str() + encoded.size()); // append the label
103
104  struct dnsrecordheader drh;
105  drh.d_type=htons(qtype);
106  drh.d_class=htons(1);
107  drh.d_ttl=0;
108  drh.d_clen=htons(serialized.size());
109
110  ptr=(const uint8_t*)&drh;
111  packet.insert(packet.end(), ptr, ptr + sizeof(drh));
112
113  packet.insert(packet.end(), serialized.c_str(), serialized.c_str() + serialized.size()); // this is our actual data
114 
115  MOADNSParser mdp((char*)&*packet.begin(), packet.size());
116  shared_ptr<DNSRecordContent> ret= mdp.d_answers.begin()->first.d_content;
117  ret->header.d_type=ret->d_qtype;
118  ret->label=mdp.d_answers.begin()->first.d_label;
119  ret->header.d_ttl=mdp.d_answers.begin()->first.d_ttl;
120  return ret;
121}
122
123DNSRecordContent* DNSRecordContent::mastermake(const DNSRecord &dr, 
124                                               PacketReader& pr)
125{
126  typemap_t::const_iterator i=typemap.find(make_pair(dr.d_class, dr.d_type));
127  if(i==typemap.end() || !i->second) {
128    return new UnknownRecordContent(dr, pr);
129  }
130
131  return i->second(dr, pr);
132}
133
134DNSRecordContent* DNSRecordContent::mastermake(uint16_t qtype, uint16_t qclass,
135                                               const string& content)
136{
137  zmakermap_t::const_iterator i=zmakermap.find(make_pair(qclass, qtype));
138  if(i==zmakermap.end()) {
139    return new UnknownRecordContent(content);
140  }
141
142  return i->second(content);
143}
144
145
146DNSRecordContent::typemap_t DNSRecordContent::typemap __attribute__((init_priority(1000)));
147DNSRecordContent::namemap_t DNSRecordContent::namemap __attribute__((init_priority(1000)));
148DNSRecordContent::zmakermap_t DNSRecordContent::zmakermap __attribute__((init_priority(1000)));
149
150void MOADNSParser::init(const char *packet, unsigned int len)
151{
152  if(len < sizeof(dnsheader))
153    throw MOADNSException("Packet shorter than minimal header");
154 
155  memcpy(&d_header, packet, sizeof(dnsheader));
156
157  d_header.qdcount=ntohs(d_header.qdcount);
158  d_header.ancount=ntohs(d_header.ancount);
159  d_header.nscount=ntohs(d_header.nscount);
160  d_header.arcount=ntohs(d_header.arcount);
161 
162  uint16_t contentlen=len-sizeof(dnsheader);
163
164  d_content.resize(contentlen);
165  copy(packet+sizeof(dnsheader), packet+len, d_content.begin());
166 
167  unsigned int n;
168
169  PacketReader pr(d_content);
170
171  for(n=0;n < d_header.qdcount; ++n) {
172    d_qname=pr.getLabel();
173    d_qtype=pr.get16BitInt();
174    d_qclass=pr.get16BitInt();
175  }
176
177  try {
178    struct dnsrecordheader ah;
179    vector<unsigned char> record;
180   
181    for(n=0;n < d_header.ancount + d_header.nscount + d_header.arcount; ++n) {
182     
183      DNSRecord dr;
184     
185      if(n < d_header.ancount)
186        dr.d_place=DNSRecord::Answer;
187      else if(n < d_header.ancount + d_header.nscount)
188        dr.d_place=DNSRecord::Nameserver;
189      else 
190        dr.d_place=DNSRecord::Additional;
191     
192      string label=pr.getLabel();
193     
194      pr.getDnsrecordheader(ah);
195      dr.d_ttl=ah.d_ttl;
196      dr.d_type=ah.d_type;
197      dr.d_class=ah.d_class;
198     
199      dr.d_label=label;
200      dr.d_clen=ah.d_clen;
201     
202      dr.d_content=boost::shared_ptr<DNSRecordContent>(DNSRecordContent::mastermake(dr, pr));
203      d_answers.push_back(make_pair(dr, pr.d_pos));
204    }
205   
206    if(pr.d_pos!=contentlen) {
207      throw MOADNSException("Packet ("+d_qname+"|#"+lexical_cast<string>(d_qtype)+") has trailing garbage ("+ lexical_cast<string>(pr.d_pos) + " < " + 
208                            lexical_cast<string>(contentlen) + ")");
209    }
210  }
211  catch(out_of_range &re) {
212    throw MOADNSException("Packet parsing error, out of bounds: "+string(re.what()));
213  }
214 
215}
216
217bool MOADNSParser::getEDNSOpts(EDNSOpts* eo)
218{
219  if(d_header.arcount) {
220    eo->d_packetsize=d_answers.back().first.d_class;
221    struct Stuff {
222      uint8_t extRCode, version;
223      uint16_t Z;
224    } __attribute__((packed));
225   
226    Stuff stuff;
227    uint32_t ttl=ntohl(d_answers.back().first.d_ttl);
228    memcpy(&stuff, &ttl, sizeof(stuff));
229
230    eo->d_extRCode=stuff.extRCode;
231    eo->d_version=stuff.version;
232    eo->d_Z=stuff.Z;
233
234    return true;
235  }
236  else
237    return false;
238}
239
240void PacketReader::getDnsrecordheader(struct dnsrecordheader &ah)
241{
242  unsigned int n;
243  unsigned char *p=reinterpret_cast<unsigned char*>(&ah);
244 
245  for(n=0; n < sizeof(dnsrecordheader); ++n) 
246    p[n]=d_content.at(d_pos++);
247 
248  ah.d_type=ntohs(ah.d_type);
249  ah.d_class=ntohs(ah.d_class);
250  ah.d_clen=ntohs(ah.d_clen);
251  ah.d_ttl=ntohl(ah.d_ttl);
252
253  d_startrecordpos=d_pos; // needed for getBlob later on
254  d_recordlen=ah.d_clen;
255}
256
257
258void PacketReader::copyRecord(vector<unsigned char>& dest, uint16_t len)
259{
260  dest.resize(len);
261  if(!len)
262    return;
263
264  for(uint16_t n=0;n<len;++n) {
265    dest.at(n)=d_content.at(d_pos++);
266  }
267}
268
269void PacketReader::copyRecord(unsigned char* dest, uint16_t len)
270{
271  if(d_pos + len > d_content.size())
272    throw MOADNSException("Attempt to copy outside of packet");
273
274  memcpy(dest, &d_content.at(d_pos), len);
275  d_pos+=len;
276}
277
278
279uint32_t PacketReader::get32BitInt()
280{
281  uint32_t ret=0;
282  ret+=d_content.at(d_pos++);
283  ret<<=8;
284  ret+=d_content.at(d_pos++);
285  ret<<=8;
286  ret+=d_content.at(d_pos++);
287  ret<<=8;
288  ret+=d_content.at(d_pos++);
289 
290  return ret;
291}
292
293
294uint16_t PacketReader::get16BitInt()
295{
296  return get16BitInt(d_content, d_pos);
297}
298
299uint16_t PacketReader::get16BitInt(const vector<unsigned char>&content, uint16_t& pos)
300{
301  uint16_t ret=0;
302  ret+=content.at(pos++);
303  ret<<=8;
304  ret+=content.at(pos++);
305 
306  return ret;
307}
308
309u_int8_t PacketReader::get8BitInt()
310{
311  return d_content.at(d_pos++);
312}
313
314
315string PacketReader::getLabel(unsigned int recurs)
316{
317  string ret;
318  ret.reserve(40);
319  getLabelFromContent(d_content, d_pos, ret, recurs++);
320  return ret;
321}
322
323string PacketReader::getText()
324{
325  string ret;
326  ret.reserve(40);
327
328  unsigned char labellen=d_content.at(d_pos++);
329  ret.append(&d_content.at(d_pos), &d_content.at(d_pos+labellen-1)+1); // the end is one beyond the packet
330  d_pos+=labellen;
331  return ret;
332}
333
334void PacketReader::getLabelFromContent(const vector<u_int8_t>& content, uint16_t& frompos, string& ret, int recurs) 
335{
336  if(recurs > 10)
337    throw MOADNSException("Loop");
338
339  for(;;) {
340    unsigned char labellen=content.at(frompos++);
341
342    // cout<<"Labellen: "<<(int)labellen<<endl;
343    if(!labellen) {
344      //      if(ret.empty())
345      //        ret.append(1,'.');
346      break;
347    }
348    if((labellen & 0xc0) == 0xc0) {
349      uint16_t offset=256*(labellen & ~0xc0) + (unsigned int)content.at(frompos++) - sizeof(dnsheader);
350      //        cout<<"This is an offset, need to go to: "<<offset<<endl;
351      return getLabelFromContent(content, offset, ret, ++recurs);
352    }
353    else {
354      if(!ret.empty())
355        ret.append(1,'.');
356      ret.append(&content.at(frompos), &content.at(frompos+labellen));
357      frompos+=labellen;
358    }
359  }
360}
361
362void PacketReader::xfrBlob(string& blob)
363{
364  blob.assign(&d_content.at(d_pos), &d_content.at(d_startrecordpos + d_recordlen - 1 ) + 1);
365
366  d_pos = d_startrecordpos + d_recordlen;
367}
Note: See TracBrowser for help on using the browser.