]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/dnswriter.cc
implement rfc4255
[thirdparty/pdns.git] / pdns / dnswriter.cc
CommitLineData
a0a276c2
BH
1#include "dnswriter.hh"
2#include "misc.hh"
3#include "dnsparser.hh"
4
a0a276c2
BH
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));
8e97e9a3 12 dnsheader.id=0;
a0a276c2
BH
13 dnsheader.qdcount=htons(1);
14
15 const uint8_t* ptr=(const uint8_t*)&dnsheader;
790e7c1b
BH
16 uint32_t len=d_content.size();
17 d_content.resize(len + sizeof(dnsheader));
18 uint8_t* dptr=(&*d_content.begin()) + len;
19
790e7c1b
BH
20 memcpy(dptr, ptr, sizeof(dnsheader));
21
bca6643b 22 xfrLabel(qname, false);
790e7c1b
BH
23
24 len=d_content.size();
678ce973 25 d_content.resize(len + d_record.size() + 4);
e984b465 26
790e7c1b
BH
27 ptr=&*d_record.begin();
28 dptr=(&*d_content.begin()) + len;
29
30 memcpy(dptr, ptr, d_record.size());
790e7c1b 31
678ce973 32 len+=d_record.size();
bca6643b
BH
33 d_record.clear();
34
a0a276c2 35 qtype=htons(qtype);
a0a276c2 36 qclass=htons(qclass);
e984b465
BH
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);
ea634573
BH
42
43 d_stuff=0xffff;
a0a276c2
BH
44}
45
8e97e9a3
BH
46DNSPacketWriter::dnsheader* DNSPacketWriter::getHeader()
47{
48 return (dnsheader*)&*d_content.begin();
49}
50
878435ce
BH
51
52void DNSPacketWriter::startRecord(const string& name, uint16_t qtype, uint32_t ttl, uint16_t qclass, Place place)
a0a276c2
BH
53{
54 if(!d_record.empty())
55 commit();
878435ce 56
a0a276c2
BH
57 d_recordqname=name;
58 d_recordqtype=qtype;
59 d_recordqclass=qclass;
878435ce 60 d_recordttl=ttl;
10321a98 61 d_recordplace=place;
878435ce 62
bca6643b 63 d_stuff = 0;
10321a98 64 d_rollbackmarker=d_content.size();
bca6643b
BH
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
ea634573 71 d_sor=d_content.size() + d_stuff; // start of real record
878435ce 72}
a0a276c2 73
878435ce
BH
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));
8a63d3ce 89
878435ce
BH
90 ttl=ntohl(ttl); // will be reversed later on
91
92 startRecord("", ns_t_opt, ttl, udpsize, ADDITIONAL);
a0a276c2
BH
93}
94
95void DNSPacketWriter::xfr32BitInt(uint32_t val)
96{
ea634573
BH
97 int rval=htonl(val);
98 uint8_t* ptr=reinterpret_cast<uint8_t*>(&rval);
a0a276c2
BH
99 d_record.insert(d_record.end(), ptr, ptr+4);
100}
101
102void DNSPacketWriter::xfr16BitInt(uint16_t val)
103{
ea634573
BH
104 int rval=htons(val);
105 uint8_t* ptr=reinterpret_cast<uint8_t*>(&rval);
a0a276c2
BH
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
e5bad90b 121// this is the absolute hottest function in the pdns recursor
bca6643b 122void DNSPacketWriter::xfrLabel(const string& label, bool compress)
a0a276c2 123{
8c3149f2 124 typedef vector<pair<unsigned int, unsigned int> > parts_t;
bca6643b 125 parts_t parts;
8c3149f2 126 vstringtok(parts, label, ".");
bca6643b 127
e5bad90b
BH
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;
bca6643b
BH
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;
8c3149f2
BH
134 // see if we've written out this domain before
135 if(compress && (li=d_labelmap.find(chopped))!=d_labelmap.end()) {
bca6643b
BH
136 uint16_t offset=li->second;
137 offset|=0xc000;
8c3149f2
BH
138 d_record.push_back((char)(offset >> 8));
139 d_record.push_back((char)(offset & 0xff));
bca6643b
BH
140 goto out; // skip trailing 0 in case of compression
141 }
142 else if(compress || d_labelmap.count(chopped)) { // if 'compress' is true, li will be equal to d_labelmap.end()
143 d_labelmap[chopped]=pos; // if untrue, we need to count
144 }
8c3149f2
BH
145 d_record.push_back((char)(i->second - i->first));
146 unsigned int len=d_record.size();
147 d_record.resize(len + i->second - i->first);
148 memcpy(((&*d_record.begin()) + len), label.c_str() + i-> first, i->second - i->first);
149
150 pos+=(i->second - i->first)+1;
bca6643b
BH
151 chopOff(chopped); // www.powerdns.com -> powerdns.com -> com
152 }
8c3149f2 153 d_record.push_back(0);
a0a276c2 154
bca6643b 155 out:;
a0a276c2
BH
156}
157
8c1c9170
BH
158void DNSPacketWriter::xfrBlob(const string& blob)
159{
160 const uint8_t* ptr=reinterpret_cast<const uint8_t*>(blob.c_str());
161
162 d_record.insert(d_record.end(), ptr, ptr+blob.size());
163}
164
ea634573
BH
165void DNSPacketWriter::getRecords(string& records)
166{
167 records.assign(d_content.begin() + d_sor, d_content.end());
168}
a0a276c2 169
10321a98
BH
170uint16_t DNSPacketWriter::size()
171{
172 return d_content.size() + d_stuff + d_record.size();
173}
174
175void DNSPacketWriter::rollback()
176{
177 d_content.resize(d_rollbackmarker);
178 d_record.clear();
179 d_stuff=0;
180}
181
a0a276c2
BH
182void DNSPacketWriter::commit()
183{
ea634573
BH
184 if(d_stuff==0xffff && (d_content.size()!=d_sor || !d_record.empty()))
185 throw MOADNSException("DNSPacketWriter::commit() called without startRecord ever having been called, but a record was added");
bca6643b 186 // build dnsrecordheader
a0a276c2
BH
187 struct dnsrecordheader drh;
188 drh.d_type=htons(d_recordqtype);
189 drh.d_class=htons(d_recordqclass);
878435ce 190 drh.d_ttl=htonl(d_recordttl);
a0a276c2 191 drh.d_clen=htons(d_record.size());
10321a98 192
bca6643b
BH
193 // and write out the header
194 const uint8_t* ptr=(const uint8_t*)&drh;
a0a276c2
BH
195 d_content.insert(d_content.end(), ptr, ptr+sizeof(drh));
196
10321a98
BH
197 d_stuff=0;
198
a0a276c2
BH
199 // write out d_record
200 d_content.insert(d_content.end(), d_record.begin(), d_record.end());
201
10321a98
BH
202 dnsheader* dh=reinterpret_cast<dnsheader*>( &*d_content.begin());
203 switch(d_recordplace) {
204 case ANSWER:
205 dh->ancount = htons(ntohs(dh->ancount) + 1);
206 break;
207 case AUTHORITY:
208 dh->nscount = htons(ntohs(dh->nscount) + 1);
209 break;
210 case ADDITIONAL:
211 dh->arcount = htons(ntohs(dh->arcount) + 1);
212 break;
213 }
214
bca6643b 215 d_record.clear(); // clear d_record, ready for next record
a0a276c2
BH
216}
217
218
219
220
221
222