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

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

make pipe backend clean up after itself, fixing the problem reported in
 http://mailman.powerdns.com/pipermail/pdns-dev/2005-October/000360.html

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
216bool MOADNSParser::getEDNSOpts(EDNSOpts* eo)
217{
218  if(d_header.arcount) {
219    eo->d_packetsize=d_answers.back().first.d_class;
220    struct Stuff {
221      uint8_t extRCode, version;
222      uint16_t Z;
223    } __attribute__((packed));
224   
225    Stuff stuff;
226    uint32_t ttl=ntohl(d_answers.back().first.d_ttl);
227    memcpy(&stuff, &ttl, sizeof(stuff));
228
229    eo->d_extRCode=stuff.extRCode;
230    eo->d_version=stuff.version;
231    eo->d_Z=stuff.Z;
232
233    return true;
234  }
235  else
236    return false;
237}
238
239void PacketReader::getDnsrecordheader(struct dnsrecordheader &ah)
240{
241  unsigned int n;
242  unsigned char *p=reinterpret_cast<unsigned char*>(&ah);
243 
244  for(n=0; n < sizeof(dnsrecordheader); ++n) 
245    p[n]=d_content.at(d_pos++);
246 
247  ah.d_type=ntohs(ah.d_type);
248  ah.d_class=ntohs(ah.d_class);
249  ah.d_clen=ntohs(ah.d_clen);
250  ah.d_ttl=ntohl(ah.d_ttl);
251
252  d_startrecordpos=d_pos; // needed for getBlob later on
253  d_recordlen=ah.d_clen;
254}
255
256
257void PacketReader::copyRecord(vector<unsigned char>& dest, uint16_t len)
258{
259  dest.resize(len);
260  if(!len)
261    return;
262
263  for(uint16_t n=0;n<len;++n) {
264    dest.at(n)=d_content.at(d_pos++);
265  }
266}
267
268void PacketReader::copyRecord(unsigned char* dest, uint16_t len)
269{
270  if(d_pos + len > d_content.size())
271    throw MOADNSException("Attempt to copy outside of packet");
272
273  memcpy(dest, &d_content.at(d_pos), len);
274  d_pos+=len;
275}
276
277
278uint32_t PacketReader::get32BitInt()
279{
280  uint32_t ret=0;
281  ret+=d_content.at(d_pos++);
282  ret<<=8;
283  ret+=d_content.at(d_pos++);
284  ret<<=8;
285  ret+=d_content.at(d_pos++);
286  ret<<=8;
287  ret+=d_content.at(d_pos++);
288 
289  return ret;
290}
291
292
293uint16_t PacketReader::get16BitInt()
294{
295  return get16BitInt(d_content, d_pos);
296}
297
298uint16_t PacketReader::get16BitInt(const vector<unsigned char>&content, uint16_t& pos)
299{
300  uint16_t ret=0;
301  ret+=content.at(pos++);
302  ret<<=8;
303  ret+=content.at(pos++);
304 
305  return ret;
306}
307
308u_int8_t PacketReader::get8BitInt()
309{
310  return d_content.at(d_pos++);
311}
312
313
314string PacketReader::getLabel(unsigned int recurs)
315{
316  string ret;
317  ret.reserve(40);
318  getLabelFromContent(d_content, d_pos, ret, recurs++);
319  return ret;
320}
321
322string PacketReader::getText()
323{
324  string ret;
325  ret.reserve(40);
326
327  unsigned char labellen=d_content.at(d_pos++);
328  ret.append(&d_content.at(d_pos), &d_content.at(d_pos+labellen-1)+1); // the end is one beyond the packet
329  d_pos+=labellen;
330  return ret;
331}
332
333void PacketReader::getLabelFromContent(const vector<u_int8_t>& content, uint16_t& frompos, string& ret, int recurs) 
334{
335  if(recurs > 10)
336    throw MOADNSException("Loop");
337
338  for(;;) {
339    unsigned char labellen=content.at(frompos++);
340
341    // cout<<"Labellen: "<<(int)labellen<<endl;
342    if(!labellen) {
343      //      if(ret.empty())
344      //        ret.append(1,'.');
345      break;
346    }
347    if((labellen & 0xc0) == 0xc0) {
348      uint16_t offset=256*(labellen & ~0xc0) + (unsigned int)content.at(frompos++) - sizeof(dnsheader);
349      //        cout<<"This is an offset, need to go to: "<<offset<<endl;
350      return getLabelFromContent(content, offset, ret, ++recurs);
351    }
352    else {
353      if(!ret.empty())
354        ret.append(1,'.');
355      ret.append(&content.at(frompos), &content.at(frompos+labellen));
356      frompos+=labellen;
357    }
358  }
359}
360
361void PacketReader::xfrBlob(string& blob)
362{
363  blob.assign(&d_content.at(d_pos), &d_content.at(d_startrecordpos + d_recordlen - 1 ) + 1);
364
365  d_pos = d_startrecordpos + d_recordlen;
366}
Note: See TracBrowser for help on using the browser.