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

Revision 773, 6.1 KB (checked in by ahu, 7 years ago)

this fixes prio in MX and in SRV records from being zero on sun-endian platforms

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
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  uint16_t 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, "."); // XXX FIXME this should deal with escaped .
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    //    cerr<<"chopped: '"<<chopped<<"'\n";
134    map<string, uint16_t>::iterator li=d_labelmap.end();
135    // see if we've written out this domain before
136    if(compress && (li=d_labelmap.find(chopped))!=d_labelmap.end()) {   
137      uint16_t offset=li->second;
138      offset|=0xc000;
139      d_record.push_back((char)(offset >> 8));
140      d_record.push_back((char)(offset & 0xff));
141      goto out;                                 // skip trailing 0 in case of compression
142    }
143
144    if(li==d_labelmap.end() && pos< 16384)
145      d_labelmap[chopped]=pos;                       //  if untrue, we need to count - also, don't store offsets > 16384, won't work
146   
147    d_record.push_back((char)(i->second - i->first));
148    unsigned int len=d_record.size();
149    d_record.resize(len + i->second - i->first);
150    memcpy(((&*d_record.begin()) + len), label.c_str() + i-> first, i->second - i->first);
151    //    cerr<<"Added: '"<<string(label.c_str() + i->first, i->second - i->first) <<"'\n";
152    pos+=(i->second - i->first)+1;
153    chopOff(chopped);                   // www.powerdns.com. -> powerdns.com. -> com. -> .
154  }
155  d_record.push_back(0);
156
157 out:;
158}
159
160void DNSPacketWriter::xfrBlob(const string& blob)
161{
162  const uint8_t* ptr=reinterpret_cast<const uint8_t*>(blob.c_str());
163
164  d_record.insert(d_record.end(), ptr, ptr+blob.size());
165}
166
167void DNSPacketWriter::xfrHexBlob(const string& blob)
168{
169  xfrBlob(blob);
170}
171
172
173void DNSPacketWriter::getRecords(string& records)
174{
175  records.assign(d_content.begin() + d_sor, d_content.end());
176}
177
178uint16_t DNSPacketWriter::size()
179{
180  return d_content.size() + d_stuff + d_record.size();
181}
182
183void DNSPacketWriter::rollback()
184{
185  d_content.resize(d_rollbackmarker);
186  d_record.clear();
187  d_stuff=0;
188}
189
190void DNSPacketWriter::commit()
191{
192  if(d_stuff==0xffff && (d_content.size()!=d_sor || !d_record.empty()))
193    throw MOADNSException("DNSPacketWriter::commit() called without startRecord ever having been called, but a record was added");
194  // build dnsrecordheader
195  struct dnsrecordheader drh;
196  drh.d_type=htons(d_recordqtype);
197  drh.d_class=htons(d_recordqclass);
198  drh.d_ttl=htonl(d_recordttl);
199  drh.d_clen=htons(d_record.size());
200 
201  // and write out the header
202  const uint8_t* ptr=(const uint8_t*)&drh;
203  d_content.insert(d_content.end(), ptr, ptr+sizeof(drh));
204
205  d_stuff=0;
206
207  // write out d_record
208  d_content.insert(d_content.end(), d_record.begin(), d_record.end());
209
210  dnsheader* dh=reinterpret_cast<dnsheader*>( &*d_content.begin());
211  switch(d_recordplace) {
212  case ANSWER:
213    dh->ancount = htons(ntohs(dh->ancount) + 1);
214    break;
215  case AUTHORITY:
216    dh->nscount = htons(ntohs(dh->nscount) + 1);
217    break;
218  case ADDITIONAL:
219    dh->arcount = htons(ntohs(dh->arcount) + 1);
220    break;
221  }
222
223  d_record.clear();   // clear d_record, ready for next record
224}
225
226
227
228
229
230
Note: See TracBrowser for help on using the browser.