]>
Commit | Line | Data |
---|---|---|
a0a276c2 BH |
1 | #include "dnswriter.hh" |
2 | #include "misc.hh" | |
3 | #include "dnsparser.hh" | |
4 | ||
a0a276c2 BH |
5 | DNSPacketWriter::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 |
46 | DNSPacketWriter::dnsheader* DNSPacketWriter::getHeader() |
47 | { | |
48 | return (dnsheader*)&*d_content.begin(); | |
49 | } | |
50 | ||
878435ce BH |
51 | |
52 | void 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 |
74 | void 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 | ||
95 | void 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 | ||
102 | void 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 | ||
109 | void DNSPacketWriter::xfr8BitInt(uint8_t val) | |
110 | { | |
111 | d_record.push_back(val); | |
112 | } | |
113 | ||
114 | void 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 | 122 | void 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 |
158 | void 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 |
165 | void DNSPacketWriter::getRecords(string& records) |
166 | { | |
167 | records.assign(d_content.begin() + d_sor, d_content.end()); | |
168 | } | |
a0a276c2 | 169 | |
10321a98 BH |
170 | uint16_t DNSPacketWriter::size() |
171 | { | |
172 | return d_content.size() + d_stuff + d_record.size(); | |
173 | } | |
174 | ||
175 | void DNSPacketWriter::rollback() | |
176 | { | |
177 | d_content.resize(d_rollbackmarker); | |
178 | d_record.clear(); | |
179 | d_stuff=0; | |
180 | } | |
181 | ||
a0a276c2 BH |
182 | void 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 |