]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/dnswriter.cc
we had some htonls in a twist for xfrIP.. hopefully this is the right fix
[thirdparty/pdns.git] / pdns / dnswriter.cc
CommitLineData
a0a276c2
BH
1#include "dnswriter.hh"
2#include "misc.hh"
3#include "dnsparser.hh"
ef6a78d5 4#include <boost/tokenizer.hpp>
38e655b6 5#include <boost/algorithm/string.hpp>
a6c51664 6#include <limits.h>
a0a276c2 7
88c1bc50 8DNSPacketWriter::DNSPacketWriter(vector<uint8_t>& content, const string& qname, uint16_t qtype, uint16_t qclass, uint8_t opcode)
a0a276c2
BH
9 : d_pos(0), d_content(content), d_qname(qname), d_qtype(qtype), d_qclass(qclass)
10{
11 d_content.clear();
12 dnsheader dnsheader;
13
14 memset(&dnsheader, 0, sizeof(dnsheader));
8e97e9a3 15 dnsheader.id=0;
a0a276c2 16 dnsheader.qdcount=htons(1);
88c1bc50 17 dnsheader.opcode=opcode;
a0a276c2
BH
18
19 const uint8_t* ptr=(const uint8_t*)&dnsheader;
790e7c1b
BH
20 uint32_t len=d_content.size();
21 d_content.resize(len + sizeof(dnsheader));
22 uint8_t* dptr=(&*d_content.begin()) + len;
2f4c3abb 23
790e7c1b 24 memcpy(dptr, ptr, sizeof(dnsheader));
2f4c3abb 25 d_stuff=0;
b59d34f7 26
bca6643b 27 xfrLabel(qname, false);
790e7c1b
BH
28
29 len=d_content.size();
678ce973 30 d_content.resize(len + d_record.size() + 4);
e984b465 31
790e7c1b
BH
32 ptr=&*d_record.begin();
33 dptr=(&*d_content.begin()) + len;
34
35 memcpy(dptr, ptr, d_record.size());
790e7c1b 36
678ce973 37 len+=d_record.size();
bca6643b
BH
38 d_record.clear();
39
a0a276c2 40 qtype=htons(qtype);
a0a276c2 41 qclass=htons(qclass);
e984b465
BH
42
43 vector<uint8_t>::iterator i=d_content.begin()+len; // this works around a gcc 3.4 bug
44 memcpy(&*i, &qtype, 2);
45 i+=2;
46 memcpy(&*i, &qclass, 2);
ea634573
BH
47
48 d_stuff=0xffff;
a2ce25e4 49 d_labelmap.reserve(16);
a0a276c2
BH
50}
51
5a57d2ea 52dnsheader* DNSPacketWriter::getHeader()
8e97e9a3
BH
53{
54 return (dnsheader*)&*d_content.begin();
55}
56
878435ce 57void DNSPacketWriter::startRecord(const string& name, uint16_t qtype, uint32_t ttl, uint16_t qclass, Place place)
a0a276c2
BH
58{
59 if(!d_record.empty())
60 commit();
878435ce 61
a0a276c2
BH
62 d_recordqname=name;
63 d_recordqtype=qtype;
64 d_recordqclass=qclass;
878435ce 65 d_recordttl=ttl;
10321a98 66 d_recordplace=place;
878435ce 67
bca6643b 68 d_stuff = 0;
10321a98 69 d_rollbackmarker=d_content.size();
bca6643b 70
16989b4c 71 if(!strcasecmp(d_qname.c_str(), d_recordqname.c_str())) { // don't do the whole label compression thing if we *know* we can get away with "see question"
a2ce25e4
BH
72 static char marker[2]={0xc0, 0x0c};
73 d_content.insert(d_content.end(), &marker[0], &marker[2]);
74 }
75 else {
76 xfrLabel(d_recordqname, true);
77 d_content.insert(d_content.end(), d_record.begin(), d_record.end());
78 d_record.clear();
79 }
80
bca6643b 81 d_stuff = sizeof(dnsrecordheader); // this is needed to get compressed label offsets right, the dnsrecordheader will be interspersed
ea634573 82 d_sor=d_content.size() + d_stuff; // start of real record
878435ce 83}
a0a276c2 84
7f7b8d55 85void DNSPacketWriter::addOpt(int udpsize, int extRCode, int Z, const vector<pair<uint16_t,string> >& options)
878435ce
BH
86{
87 uint32_t ttl=0;
705f31ae 88
009f9f55 89 EDNS0Record stuff;
878435ce
BH
90
91 stuff.extRCode=extRCode;
92 stuff.version=0;
93 stuff.Z=htons(Z);
7f7b8d55 94
878435ce 95 memcpy(&ttl, &stuff, sizeof(stuff));
8a63d3ce 96
878435ce
BH
97 ttl=ntohl(ttl); // will be reversed later on
98
99 startRecord("", ns_t_opt, ttl, udpsize, ADDITIONAL);
7f7b8d55
BH
100 for(optvect_t::const_iterator iter = options.begin(); iter != options.end(); ++iter) {
101 xfr16BitInt(iter->first);
102 xfr16BitInt(iter->second.length());
103 xfrBlob(iter->second);
104 }
a0a276c2
BH
105}
106
341930bb
BH
107void DNSPacketWriter::xfr48BitInt(uint64_t val)
108{
109 unsigned char bytes[6];
0407751c
BH
110 uint16_t theLeft = htons(val >> 32);
111 uint32_t theRight = htonl(val & 0xffffffffU);
112 memcpy(bytes, (void*)&theLeft, 2);
113 memcpy(bytes+2, (void*)&theRight, 4);
341930bb
BH
114
115 d_record.insert(d_record.end(), bytes, bytes + 6);
116}
117
118
a0a276c2
BH
119void DNSPacketWriter::xfr32BitInt(uint32_t val)
120{
ea634573
BH
121 int rval=htonl(val);
122 uint8_t* ptr=reinterpret_cast<uint8_t*>(&rval);
a0a276c2
BH
123 d_record.insert(d_record.end(), ptr, ptr+4);
124}
125
126void DNSPacketWriter::xfr16BitInt(uint16_t val)
127{
96aed220 128 uint16_t rval=htons(val);
ea634573 129 uint8_t* ptr=reinterpret_cast<uint8_t*>(&rval);
a0a276c2
BH
130 d_record.insert(d_record.end(), ptr, ptr+2);
131}
132
133void DNSPacketWriter::xfr8BitInt(uint8_t val)
134{
135 d_record.push_back(val);
136}
137
ef6a78d5 138void DNSPacketWriter::xfrText(const string& text, bool)
a0a276c2 139{
ef6a78d5
BH
140 escaped_list_separator<char> sep('\\', ' ' , '"');
141 tokenizer<escaped_list_separator<char> > tok(text, sep);
142
143 tokenizer<escaped_list_separator<char> >::iterator beg=tok.begin();
144
145 if(beg==tok.end()) {
146 d_record.push_back(0);
147 }
148 else
149 for(; beg!=tok.end(); ++beg){
a6c51664
BH
150 if(beg->empty())
151 d_record.push_back(0);
152 else
153 for (unsigned int i = 0; i < beg->length(); i += 0xff){
154 d_record.push_back(min(0xffU, beg->length()-i));
155 const uint8_t* ptr=(uint8_t*)(beg->c_str()) + i;
156 d_record.insert(d_record.end(), ptr, ptr+min(0xffU, beg->length()-i));
157 }
ef6a78d5 158 }
a0a276c2
BH
159}
160
a2ce25e4
BH
161DNSPacketWriter::lmap_t::iterator find(DNSPacketWriter::lmap_t& lmap, const string& label)
162{
163 DNSPacketWriter::lmap_t::iterator ret;
164 for(ret=lmap.begin(); ret != lmap.end(); ++ret)
16989b4c 165 if(!strcasecmp(ret->first.c_str() ,label.c_str()))
a2ce25e4
BH
166 break;
167 return ret;
168}
169
38e655b6
BH
170typedef vector<pair<string::size_type, string::size_type> > parts_t;
171
172bool labeltokUnescape(parts_t& parts, const string& label)
173{
174 string::size_type epos = label.size(), lpos(0), pos;
175 bool unescapedSomething = false;
176 const char* ptr=label.c_str();
177
178 parts.clear();
179
180 for(pos = 0 ; pos < epos; ++pos) {
181 if(ptr[pos]=='\\') {
182 pos++;
183 unescapedSomething = true;
184 continue;
185 }
186 if(ptr[pos]=='.') {
187 parts.push_back(make_pair(lpos, pos));
188 lpos=pos+1;
189 }
190 }
191
192 if(lpos < pos)
193 parts.push_back(make_pair(lpos, pos));
194 return unescapedSomething;
195}
196
a2ce25e4 197// this is the absolute hottest function in the pdns recursor
bca6643b 198void DNSPacketWriter::xfrLabel(const string& label, bool compress)
a0a276c2 199{
bca6643b 200 parts_t parts;
c1d02c0d
BH
201
202 if(label.size()==1 && label[0]=='.') { // otherwise we encode '..'
203 d_record.push_back(0);
204 return;
205 }
206
38e655b6 207 bool unescaped=labeltokUnescape(parts, label);
bca6643b 208
e5bad90b
BH
209 // d_stuff is amount of stuff that is yet to be written out - the dnsrecordheader for example
210 unsigned int pos=d_content.size() + d_record.size() + d_stuff;
38e655b6 211 string chopped;
bca6643b 212 for(parts_t::const_iterator i=parts.begin(); i!=parts.end(); ++i) {
38e655b6 213 chopped.assign(label.c_str() + i->first);
a2ce25e4 214 lmap_t::iterator li=d_labelmap.end();
8c3149f2 215 // see if we've written out this domain before
a2ce25e4 216 if(compress && (li=find(d_labelmap, chopped))!=d_labelmap.end()) {
bca6643b
BH
217 uint16_t offset=li->second;
218 offset|=0xc000;
8c3149f2
BH
219 d_record.push_back((char)(offset >> 8));
220 d_record.push_back((char)(offset & 0xff));
bca6643b
BH
221 goto out; // skip trailing 0 in case of compression
222 }
2f4c3abb
BH
223
224 if(li==d_labelmap.end() && pos< 16384)
a2ce25e4
BH
225 d_labelmap.push_back(make_pair(chopped, pos)); // if untrue, we need to count - also, don't store offsets > 16384, won't work
226
38e655b6
BH
227 if(unescaped) {
228 string part(label.c_str() + i -> first, i->second - i->first);
229 replace_all(part, "\\.", ".");
230 d_record.push_back(part.size());
231 unsigned int len=d_record.size();
232 d_record.resize(len + part.size());
233
234 memcpy(((&*d_record.begin()) + len), part.c_str(), part.size());
235 pos+=(part.size())+1;
236 }
237 else {
238 d_record.push_back((char)(i->second - i->first));
239 unsigned int len=d_record.size();
240 d_record.resize(len + i->second - i->first);
241 memcpy(((&*d_record.begin()) + len), label.c_str() + i-> first, i->second - i->first);
242 pos+=(i->second - i->first)+1;
243 }
bca6643b 244 }
8c3149f2 245 d_record.push_back(0);
a0a276c2 246
bca6643b 247 out:;
a0a276c2
BH
248}
249
06ffdc52 250void DNSPacketWriter::xfrBlob(const string& blob, int )
8c1c9170
BH
251{
252 const uint8_t* ptr=reinterpret_cast<const uint8_t*>(blob.c_str());
253
254 d_record.insert(d_record.end(), ptr, ptr+blob.size());
255}
256
59a0f653
BH
257void DNSPacketWriter::xfrHexBlob(const string& blob)
258{
259 xfrBlob(blob);
260}
261
262
ea634573
BH
263void DNSPacketWriter::getRecords(string& records)
264{
265 records.assign(d_content.begin() + d_sor, d_content.end());
266}
a0a276c2 267
10321a98
BH
268uint16_t DNSPacketWriter::size()
269{
270 return d_content.size() + d_stuff + d_record.size();
271}
272
273void DNSPacketWriter::rollback()
274{
275 d_content.resize(d_rollbackmarker);
276 d_record.clear();
277 d_stuff=0;
278}
279
a0a276c2
BH
280void DNSPacketWriter::commit()
281{
ea634573
BH
282 if(d_stuff==0xffff && (d_content.size()!=d_sor || !d_record.empty()))
283 throw MOADNSException("DNSPacketWriter::commit() called without startRecord ever having been called, but a record was added");
bca6643b 284 // build dnsrecordheader
a0a276c2
BH
285 struct dnsrecordheader drh;
286 drh.d_type=htons(d_recordqtype);
287 drh.d_class=htons(d_recordqclass);
878435ce 288 drh.d_ttl=htonl(d_recordttl);
a0a276c2 289 drh.d_clen=htons(d_record.size());
10321a98 290
bca6643b
BH
291 // and write out the header
292 const uint8_t* ptr=(const uint8_t*)&drh;
a0a276c2
BH
293 d_content.insert(d_content.end(), ptr, ptr+sizeof(drh));
294
10321a98
BH
295 d_stuff=0;
296
6f8b3628 297 // write out pending d_record
a0a276c2
BH
298 d_content.insert(d_content.end(), d_record.begin(), d_record.end());
299
10321a98
BH
300 dnsheader* dh=reinterpret_cast<dnsheader*>( &*d_content.begin());
301 switch(d_recordplace) {
302 case ANSWER:
303 dh->ancount = htons(ntohs(dh->ancount) + 1);
304 break;
305 case AUTHORITY:
306 dh->nscount = htons(ntohs(dh->nscount) + 1);
307 break;
308 case ADDITIONAL:
309 dh->arcount = htons(ntohs(dh->arcount) + 1);
310 break;
311 }
312
bca6643b 313 d_record.clear(); // clear d_record, ready for next record
a0a276c2
BH
314}
315
316
317
318
319
320