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

Revision 803, 6.0 KB (checked in by ahu, 7 years ago)

centralise and fix 'packed' ugliness for EDNS0 and dnsrecordheader
fix compilarion on FreeBSD

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  d_stuff=0;
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
46dnsheader* 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
78  EDNS0Record stuff;
79
80  stuff.extRCode=extRCode;
81  stuff.version=0;
82  stuff.Z=htons(Z);
83 
84  memcpy(&ttl, &stuff, sizeof(stuff));
85
86  ttl=ntohl(ttl); // will be reversed later on
87 
88  startRecord("", ns_t_opt, ttl, udpsize, ADDITIONAL);
89}
90
91void DNSPacketWriter::xfr32BitInt(uint32_t val)
92{
93  int rval=htonl(val);
94  uint8_t* ptr=reinterpret_cast<uint8_t*>(&rval);
95  d_record.insert(d_record.end(), ptr, ptr+4);
96}
97
98void DNSPacketWriter::xfr16BitInt(uint16_t val)
99{
100  uint16_t rval=htons(val);
101  uint8_t* ptr=reinterpret_cast<uint8_t*>(&rval);
102  d_record.insert(d_record.end(), ptr, ptr+2);
103}
104
105void DNSPacketWriter::xfr8BitInt(uint8_t val)
106{
107  d_record.push_back(val);
108}
109
110void DNSPacketWriter::xfrText(const string& text)
111{
112  d_record.push_back(text.length());
113  const uint8_t* ptr=(uint8_t*)(text.c_str());
114  d_record.insert(d_record.end(), ptr, ptr+text.size());
115}
116
117// this is the absolute hottest function in the pdns recursor
118void DNSPacketWriter::xfrLabel(const string& label, bool compress)
119{
120  typedef vector<pair<unsigned int, unsigned int> > parts_t;
121  parts_t parts;
122  vstringtok(parts, label, "."); // XXX FIXME this should deal with escaped .
123 
124  // d_stuff is amount of stuff that is yet to be written out - the dnsrecordheader for example
125  unsigned int pos=d_content.size() + d_record.size() + d_stuff; 
126  string chopped(label);
127
128  for(parts_t::const_iterator i=parts.begin(); i!=parts.end(); ++i) {
129    //    cerr<<"chopped: '"<<chopped<<"'\n";
130    map<string, uint16_t>::iterator li=d_labelmap.end();
131    // see if we've written out this domain before
132    if(compress && (li=d_labelmap.find(chopped))!=d_labelmap.end()) {   
133      uint16_t offset=li->second;
134      offset|=0xc000;
135      d_record.push_back((char)(offset >> 8));
136      d_record.push_back((char)(offset & 0xff));
137      goto out;                                 // skip trailing 0 in case of compression
138    }
139
140    if(li==d_labelmap.end() && pos< 16384)
141      d_labelmap[chopped]=pos;                       //  if untrue, we need to count - also, don't store offsets > 16384, won't work
142   
143    d_record.push_back((char)(i->second - i->first));
144    unsigned int len=d_record.size();
145    d_record.resize(len + i->second - i->first);
146    memcpy(((&*d_record.begin()) + len), label.c_str() + i-> first, i->second - i->first);
147    //    cerr<<"Added: '"<<string(label.c_str() + i->first, i->second - i->first) <<"'\n";
148    pos+=(i->second - i->first)+1;
149    chopOff(chopped);                   // www.powerdns.com. -> powerdns.com. -> com. -> .
150  }
151  d_record.push_back(0);
152
153 out:;
154}
155
156void DNSPacketWriter::xfrBlob(const string& blob)
157{
158  const uint8_t* ptr=reinterpret_cast<const uint8_t*>(blob.c_str());
159
160  d_record.insert(d_record.end(), ptr, ptr+blob.size());
161}
162
163void DNSPacketWriter::xfrHexBlob(const string& blob)
164{
165  xfrBlob(blob);
166}
167
168
169void DNSPacketWriter::getRecords(string& records)
170{
171  records.assign(d_content.begin() + d_sor, d_content.end());
172}
173
174uint16_t DNSPacketWriter::size()
175{
176  return d_content.size() + d_stuff + d_record.size();
177}
178
179void DNSPacketWriter::rollback()
180{
181  d_content.resize(d_rollbackmarker);
182  d_record.clear();
183  d_stuff=0;
184}
185
186void DNSPacketWriter::commit()
187{
188  if(d_stuff==0xffff && (d_content.size()!=d_sor || !d_record.empty()))
189    throw MOADNSException("DNSPacketWriter::commit() called without startRecord ever having been called, but a record was added");
190  // build dnsrecordheader
191  struct dnsrecordheader drh;
192  drh.d_type=htons(d_recordqtype);
193  drh.d_class=htons(d_recordqclass);
194  drh.d_ttl=htonl(d_recordttl);
195  drh.d_clen=htons(d_record.size());
196 
197  // and write out the header
198  const uint8_t* ptr=(const uint8_t*)&drh;
199  d_content.insert(d_content.end(), ptr, ptr+sizeof(drh));
200
201  d_stuff=0;
202
203  // write out d_record
204  d_content.insert(d_content.end(), d_record.begin(), d_record.end());
205
206  dnsheader* dh=reinterpret_cast<dnsheader*>( &*d_content.begin());
207  switch(d_recordplace) {
208  case ANSWER:
209    dh->ancount = htons(ntohs(dh->ancount) + 1);
210    break;
211  case AUTHORITY:
212    dh->nscount = htons(ntohs(dh->nscount) + 1);
213    break;
214  case ADDITIONAL:
215    dh->arcount = htons(ntohs(dh->arcount) + 1);
216    break;
217  }
218
219  d_record.clear();   // clear d_record, ready for next record
220}
221
222
223
224
225
226
Note: See TracBrowser for help on using the browser.