root/trunk/pdns/pdns/dnswriter.cc @ 661

Revision 661, 5.9 KB (checked in by ahu, 7 years ago)

ok - this is a scary commit. It fixes TCP packets with >16384 size offsets, which is nice, but it also removes some logic
that looks remarkably well thought out but also appeared to serve no purpose. But perhaps it was magic..

Line 
1#include "dnswriter.hh"
2#include "misc.hh"
3#include "dnsparser.hh"
4
5DNSPacketWriter::DNSPacketWriter(vector<uint8_t>& content, const string& qname, uint16_t  qtype, uint16_t qclass)
6  : d_pos(0), d_content(content), d_qname(qname), d_qtype(qtype), d_qclass(qclass)
7{
8  d_content.clear();
9  dnsheader dnsheader;
10 
11  memset(&dnsheader, 0, sizeof(dnsheader));
12  dnsheader.id=0;
13  dnsheader.qdcount=htons(1);
14 
15  const uint8_t* ptr=(const uint8_t*)&dnsheader;
16  uint32_t len=d_content.size();
17  d_content.resize(len + sizeof(dnsheader));
18  uint8_t* dptr=(&*d_content.begin()) + len;
19
20  memcpy(dptr, ptr, sizeof(dnsheader));
21
22  xfrLabel(qname, false);
23 
24  len=d_content.size();
25  d_content.resize(len + d_record.size() + 4);
26
27  ptr=&*d_record.begin();
28  dptr=(&*d_content.begin()) + len;
29 
30  memcpy(dptr, ptr, d_record.size());
31
32  len+=d_record.size();
33  d_record.clear();
34
35  qtype=htons(qtype);
36  qclass=htons(qclass);
37
38  vector<uint8_t>::iterator i=d_content.begin()+len; // this works around a gcc 3.4 bug
39  memcpy(&*i, &qtype, 2);
40  i+=2;
41  memcpy(&*i, &qclass, 2);
42
43  d_stuff=0xffff;
44}
45
46DNSPacketWriter::dnsheader* DNSPacketWriter::getHeader()
47{
48  return (dnsheader*)&*d_content.begin();
49}
50
51
52void DNSPacketWriter::startRecord(const string& name, uint16_t qtype, uint32_t ttl, uint16_t qclass, Place place)
53{
54  if(!d_record.empty()) 
55    commit();
56
57  d_recordqname=name;
58  d_recordqtype=qtype;
59  d_recordqclass=qclass;
60  d_recordttl=ttl;
61  d_recordplace=place;
62
63  d_stuff = 0; 
64  d_rollbackmarker=d_content.size();
65
66  xfrLabel(d_recordqname, true);
67  d_content.insert(d_content.end(), d_record.begin(), d_record.end());
68  d_record.clear();
69
70  d_stuff = sizeof(dnsrecordheader); // this is needed to get compressed label offsets right, the dnsrecordheader will be interspersed
71  d_sor=d_content.size() + d_stuff; // start of real record
72}
73
74void DNSPacketWriter::addOpt(int udpsize, int extRCode, int Z)
75{
76  uint32_t ttl=0;
77  struct Stuff {
78    uint8_t extRCode, version;
79    uint16_t Z;
80  } __attribute__((packed));
81
82  Stuff stuff;
83
84  stuff.extRCode=extRCode;
85  stuff.version=0;
86  stuff.Z=htons(Z);
87 
88  memcpy(&ttl, &stuff, sizeof(stuff));
89
90  ttl=ntohl(ttl); // will be reversed later on
91 
92  startRecord("", ns_t_opt, ttl, udpsize, ADDITIONAL);
93}
94
95void DNSPacketWriter::xfr32BitInt(uint32_t val)
96{
97  int rval=htonl(val);
98  uint8_t* ptr=reinterpret_cast<uint8_t*>(&rval);
99  d_record.insert(d_record.end(), ptr, ptr+4);
100}
101
102void DNSPacketWriter::xfr16BitInt(uint16_t val)
103{
104  int rval=htons(val);
105  uint8_t* ptr=reinterpret_cast<uint8_t*>(&rval);
106  d_record.insert(d_record.end(), ptr, ptr+2);
107}
108
109void DNSPacketWriter::xfr8BitInt(uint8_t val)
110{
111  d_record.push_back(val);
112}
113
114void DNSPacketWriter::xfrText(const string& text)
115{
116  d_record.push_back(text.length());
117  const uint8_t* ptr=(uint8_t*)(text.c_str());
118  d_record.insert(d_record.end(), ptr, ptr+text.size());
119}
120
121// this is the absolute hottest function in the pdns recursor
122void DNSPacketWriter::xfrLabel(const string& label, bool compress)
123{
124  typedef vector<pair<unsigned int, unsigned int> > parts_t;
125  parts_t parts;
126  vstringtok(parts, label, ".");
127 
128  // d_stuff is amount of stuff that is yet to be written out - the dnsrecordheader for example
129  unsigned int pos=d_content.size() + d_record.size() + d_stuff; 
130  string chopped(label);
131 
132  for(parts_t::const_iterator i=parts.begin(); i!=parts.end(); ++i) {
133    map<string, uint16_t>::iterator li;
134    // see if we've written out this domain before
135    if(compress && (li=d_labelmap.find(chopped))!=d_labelmap.end()) {   
136      uint16_t offset=li->second;
137      offset|=0xc000;
138      d_record.push_back((char)(offset >> 8));
139      d_record.push_back((char)(offset & 0xff));
140      goto out;                                 // skip trailing 0 in case of compression
141    }
142   
143    if(compress && pos < 16384) { 
144      d_labelmap[chopped]=pos;                       //  if untrue, we need to count - also, don't store offsets > 16384, won't work
145    }
146    d_record.push_back((char)(i->second - i->first));
147    unsigned int len=d_record.size();
148    d_record.resize(len + i->second - i->first);
149    memcpy(((&*d_record.begin()) + len), label.c_str() + i-> first, i->second - i->first);
150
151    pos+=(i->second - i->first)+1;
152    chopOff(chopped);                   // www.powerdns.com -> powerdns.com -> com
153  }
154  d_record.push_back(0);
155
156 out:;
157}
158
159void DNSPacketWriter::xfrBlob(const string& blob)
160{
161  const uint8_t* ptr=reinterpret_cast<const uint8_t*>(blob.c_str());
162
163  d_record.insert(d_record.end(), ptr, ptr+blob.size());
164}
165
166void DNSPacketWriter::xfrHexBlob(const string& blob)
167{
168  xfrBlob(blob);
169}
170
171
172void DNSPacketWriter::getRecords(string& records)
173{
174  records.assign(d_content.begin() + d_sor, d_content.end());
175}
176
177uint16_t DNSPacketWriter::size()
178{
179  return d_content.size() + d_stuff + d_record.size();
180}
181
182void DNSPacketWriter::rollback()
183{
184  d_content.resize(d_rollbackmarker);
185  d_record.clear();
186  d_stuff=0;
187}
188
189void DNSPacketWriter::commit()
190{
191  if(d_stuff==0xffff && (d_content.size()!=d_sor || !d_record.empty()))
192    throw MOADNSException("DNSPacketWriter::commit() called without startRecord ever having been called, but a record was added");
193  // build dnsrecordheader
194  struct dnsrecordheader drh;
195  drh.d_type=htons(d_recordqtype);
196  drh.d_class=htons(d_recordqclass);
197  drh.d_ttl=htonl(d_recordttl);
198  drh.d_clen=htons(d_record.size());
199 
200  // and write out the header
201  const uint8_t* ptr=(const uint8_t*)&drh;
202  d_content.insert(d_content.end(), ptr, ptr+sizeof(drh));
203
204  d_stuff=0;
205
206  // write out d_record
207  d_content.insert(d_content.end(), d_record.begin(), d_record.end());
208
209  dnsheader* dh=reinterpret_cast<dnsheader*>( &*d_content.begin());
210  switch(d_recordplace) {
211  case ANSWER:
212    dh->ancount = htons(ntohs(dh->ancount) + 1);
213    break;
214  case AUTHORITY:
215    dh->nscount = htons(ntohs(dh->nscount) + 1);
216    break;
217  case ADDITIONAL:
218    dh->arcount = htons(ntohs(dh->arcount) + 1);
219    break;
220  }
221
222  d_record.clear();   // clear d_record, ready for next record
223}
224
225
226
227
228
229
Note: See TracBrowser for help on using the browser.