]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/dnswriter.cc
fix up padding errors in base64 decoding
[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];
110 bytes[5] = val % 0xff; val /= 0xff; // untested code! XXX FIXME
111 bytes[4] = val % 0xff; val /= 0xff;
112 bytes[3] = val % 0xff; val /= 0xff;
113 bytes[2] = val % 0xff; val /= 0xff;
114 bytes[1] = val % 0xff; val /= 0xff;
115 bytes[0] = val % 0xff; val /= 0xff;
116
117 d_record.insert(d_record.end(), bytes, bytes + 6);
118}
119
120
a0a276c2
BH
121void DNSPacketWriter::xfr32BitInt(uint32_t val)
122{
ea634573
BH
123 int rval=htonl(val);
124 uint8_t* ptr=reinterpret_cast<uint8_t*>(&rval);
a0a276c2
BH
125 d_record.insert(d_record.end(), ptr, ptr+4);
126}
127
128void DNSPacketWriter::xfr16BitInt(uint16_t val)
129{
96aed220 130 uint16_t rval=htons(val);
ea634573 131 uint8_t* ptr=reinterpret_cast<uint8_t*>(&rval);
a0a276c2
BH
132 d_record.insert(d_record.end(), ptr, ptr+2);
133}
134
135void DNSPacketWriter::xfr8BitInt(uint8_t val)
136{
137 d_record.push_back(val);
138}
139
ef6a78d5 140void DNSPacketWriter::xfrText(const string& text, bool)
a0a276c2 141{
ef6a78d5
BH
142 escaped_list_separator<char> sep('\\', ' ' , '"');
143 tokenizer<escaped_list_separator<char> > tok(text, sep);
144
145 tokenizer<escaped_list_separator<char> >::iterator beg=tok.begin();
146
147 if(beg==tok.end()) {
148 d_record.push_back(0);
149 }
150 else
151 for(; beg!=tok.end(); ++beg){
a6c51664
BH
152 if(beg->empty())
153 d_record.push_back(0);
154 else
155 for (unsigned int i = 0; i < beg->length(); i += 0xff){
156 d_record.push_back(min(0xffU, beg->length()-i));
157 const uint8_t* ptr=(uint8_t*)(beg->c_str()) + i;
158 d_record.insert(d_record.end(), ptr, ptr+min(0xffU, beg->length()-i));
159 }
ef6a78d5 160 }
a0a276c2
BH
161}
162
a2ce25e4
BH
163DNSPacketWriter::lmap_t::iterator find(DNSPacketWriter::lmap_t& lmap, const string& label)
164{
165 DNSPacketWriter::lmap_t::iterator ret;
166 for(ret=lmap.begin(); ret != lmap.end(); ++ret)
16989b4c 167 if(!strcasecmp(ret->first.c_str() ,label.c_str()))
a2ce25e4
BH
168 break;
169 return ret;
170}
171
38e655b6
BH
172typedef vector<pair<string::size_type, string::size_type> > parts_t;
173
174bool labeltokUnescape(parts_t& parts, const string& label)
175{
176 string::size_type epos = label.size(), lpos(0), pos;
177 bool unescapedSomething = false;
178 const char* ptr=label.c_str();
179
180 parts.clear();
181
182 for(pos = 0 ; pos < epos; ++pos) {
183 if(ptr[pos]=='\\') {
184 pos++;
185 unescapedSomething = true;
186 continue;
187 }
188 if(ptr[pos]=='.') {
189 parts.push_back(make_pair(lpos, pos));
190 lpos=pos+1;
191 }
192 }
193
194 if(lpos < pos)
195 parts.push_back(make_pair(lpos, pos));
196 return unescapedSomething;
197}
198
a2ce25e4 199// this is the absolute hottest function in the pdns recursor
bca6643b 200void DNSPacketWriter::xfrLabel(const string& label, bool compress)
a0a276c2 201{
bca6643b 202 parts_t parts;
c1d02c0d
BH
203
204 if(label.size()==1 && label[0]=='.') { // otherwise we encode '..'
205 d_record.push_back(0);
206 return;
207 }
208
38e655b6 209 bool unescaped=labeltokUnescape(parts, label);
bca6643b 210
e5bad90b
BH
211 // d_stuff is amount of stuff that is yet to be written out - the dnsrecordheader for example
212 unsigned int pos=d_content.size() + d_record.size() + d_stuff;
38e655b6 213 string chopped;
bca6643b 214 for(parts_t::const_iterator i=parts.begin(); i!=parts.end(); ++i) {
38e655b6 215 chopped.assign(label.c_str() + i->first);
a2ce25e4 216 lmap_t::iterator li=d_labelmap.end();
8c3149f2 217 // see if we've written out this domain before
a2ce25e4 218 if(compress && (li=find(d_labelmap, chopped))!=d_labelmap.end()) {
bca6643b
BH
219 uint16_t offset=li->second;
220 offset|=0xc000;
8c3149f2
BH
221 d_record.push_back((char)(offset >> 8));
222 d_record.push_back((char)(offset & 0xff));
bca6643b
BH
223 goto out; // skip trailing 0 in case of compression
224 }
2f4c3abb
BH
225
226 if(li==d_labelmap.end() && pos< 16384)
a2ce25e4
BH
227 d_labelmap.push_back(make_pair(chopped, pos)); // if untrue, we need to count - also, don't store offsets > 16384, won't work
228
38e655b6
BH
229 if(unescaped) {
230 string part(label.c_str() + i -> first, i->second - i->first);
231 replace_all(part, "\\.", ".");
232 d_record.push_back(part.size());
233 unsigned int len=d_record.size();
234 d_record.resize(len + part.size());
235
236 memcpy(((&*d_record.begin()) + len), part.c_str(), part.size());
237 pos+=(part.size())+1;
238 }
239 else {
240 d_record.push_back((char)(i->second - i->first));
241 unsigned int len=d_record.size();
242 d_record.resize(len + i->second - i->first);
243 memcpy(((&*d_record.begin()) + len), label.c_str() + i-> first, i->second - i->first);
244 pos+=(i->second - i->first)+1;
245 }
bca6643b 246 }
8c3149f2 247 d_record.push_back(0);
a0a276c2 248
bca6643b 249 out:;
a0a276c2
BH
250}
251
06ffdc52 252void DNSPacketWriter::xfrBlob(const string& blob, int )
8c1c9170
BH
253{
254 const uint8_t* ptr=reinterpret_cast<const uint8_t*>(blob.c_str());
255
256 d_record.insert(d_record.end(), ptr, ptr+blob.size());
257}
258
59a0f653
BH
259void DNSPacketWriter::xfrHexBlob(const string& blob)
260{
261 xfrBlob(blob);
262}
263
264
ea634573
BH
265void DNSPacketWriter::getRecords(string& records)
266{
267 records.assign(d_content.begin() + d_sor, d_content.end());
268}
a0a276c2 269
10321a98
BH
270uint16_t DNSPacketWriter::size()
271{
272 return d_content.size() + d_stuff + d_record.size();
273}
274
275void DNSPacketWriter::rollback()
276{
277 d_content.resize(d_rollbackmarker);
278 d_record.clear();
279 d_stuff=0;
280}
281
a0a276c2
BH
282void DNSPacketWriter::commit()
283{
ea634573
BH
284 if(d_stuff==0xffff && (d_content.size()!=d_sor || !d_record.empty()))
285 throw MOADNSException("DNSPacketWriter::commit() called without startRecord ever having been called, but a record was added");
bca6643b 286 // build dnsrecordheader
a0a276c2
BH
287 struct dnsrecordheader drh;
288 drh.d_type=htons(d_recordqtype);
289 drh.d_class=htons(d_recordqclass);
878435ce 290 drh.d_ttl=htonl(d_recordttl);
a0a276c2 291 drh.d_clen=htons(d_record.size());
10321a98 292
bca6643b
BH
293 // and write out the header
294 const uint8_t* ptr=(const uint8_t*)&drh;
a0a276c2
BH
295 d_content.insert(d_content.end(), ptr, ptr+sizeof(drh));
296
10321a98
BH
297 d_stuff=0;
298
6f8b3628 299 // write out pending d_record
a0a276c2
BH
300 d_content.insert(d_content.end(), d_record.begin(), d_record.end());
301
10321a98
BH
302 dnsheader* dh=reinterpret_cast<dnsheader*>( &*d_content.begin());
303 switch(d_recordplace) {
304 case ANSWER:
305 dh->ancount = htons(ntohs(dh->ancount) + 1);
306 break;
307 case AUTHORITY:
308 dh->nscount = htons(ntohs(dh->nscount) + 1);
309 break;
310 case ADDITIONAL:
311 dh->arcount = htons(ntohs(dh->arcount) + 1);
312 break;
313 }
314
bca6643b 315 d_record.clear(); // clear d_record, ready for next record
a0a276c2
BH
316}
317
318
319
320
321
322