]>
Commit | Line | Data |
---|---|---|
4192ca66 | 1 | /* |
12471842 PL |
2 | * This file is part of PowerDNS or dnsdist. |
3 | * Copyright -- PowerDNS.COM B.V. and its contributors | |
4 | * | |
5 | * This program is free software; you can redistribute it and/or modify | |
6 | * it under the terms of version 2 of the GNU General Public License as | |
7 | * published by the Free Software Foundation. | |
8 | * | |
9 | * In addition, for the avoidance of any doubt, permission is granted to | |
10 | * link this program with OpenSSL and to (re)distribute the binaries | |
11 | * produced as the result of such linking. | |
12 | * | |
13 | * This program is distributed in the hope that it will be useful, | |
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | * GNU General Public License for more details. | |
17 | * | |
18 | * You should have received a copy of the GNU General Public License | |
19 | * along with this program; if not, write to the Free Software | |
20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |
21 | */ | |
ff6a1e7b | 22 | #include "dnsparser.hh" |
6c0670c3 | 23 | #include "dnswriter.hh" |
4cf74e6f | 24 | #include <boost/algorithm/string.hpp> |
5dba9d25 | 25 | #include <boost/format.hpp> |
ff6a1e7b | 26 | |
61b26744 | 27 | #include "namespaces.hh" |
ff6a1e7b BH |
28 | |
29 | class UnknownRecordContent : public DNSRecordContent | |
30 | { | |
31 | public: | |
7fc69fd0 | 32 | UnknownRecordContent(const DNSRecord& dr, PacketReader& pr) |
5a1f298f | 33 | : d_dr(dr) |
ff6a1e7b | 34 | { |
7fc69fd0 | 35 | pr.copyRecord(d_record, dr.d_clen); |
ff6a1e7b BH |
36 | } |
37 | ||
5a1f298f | 38 | UnknownRecordContent(const string& zone) |
6c0670c3 | 39 | { |
95a61c6f AT |
40 | // parse the input |
41 | vector<string> parts; | |
42 | stringtok(parts, zone); | |
43 | if(parts.size()!=3 && !(parts.size()==2 && equals(parts[1],"0")) ) | |
335da0ba | 44 | throw MOADNSException("Unknown record was stored incorrectly, need 3 fields, got "+std::to_string(parts.size())+": "+zone ); |
95a61c6f | 45 | const string& relevant=(parts.size() > 2) ? parts[2] : ""; |
335da0ba | 46 | unsigned int total=pdns_stou(parts[1]); |
e007fb02 RG |
47 | if(relevant.size() % 2 || relevant.size() / 2 != total) |
48 | throw MOADNSException((boost::format("invalid unknown record length: size not equal to length field (%d != 2 * %d)") % relevant.size() % total).str()); | |
95a61c6f AT |
49 | string out; |
50 | out.reserve(total+1); | |
51 | for(unsigned int n=0; n < total; ++n) { | |
52 | int c; | |
53 | sscanf(relevant.c_str()+2*n, "%02x", &c); | |
54 | out.append(1, (char)c); | |
55 | } | |
56 | ||
57 | d_record.insert(d_record.end(), out.begin(), out.end()); | |
6c0670c3 | 58 | } |
cff3e04d | 59 | |
f21fc0aa | 60 | string getZoneRepresentation(bool noDot) const override |
ff6a1e7b BH |
61 | { |
62 | ostringstream str; | |
705f31ae | 63 | str<<"\\# "<<(unsigned int)d_record.size()<<" "; |
ff6a1e7b BH |
64 | char hex[4]; |
65 | for(size_t n=0; n<d_record.size(); ++n) { | |
9b2244e1 | 66 | snprintf(hex, sizeof(hex), "%02x", d_record.at(n)); |
ff6a1e7b BH |
67 | str << hex; |
68 | } | |
ff6a1e7b BH |
69 | return str.str(); |
70 | } | |
cff3e04d CH |
71 | |
72 | void toPacket(DNSPacketWriter& pw) override | |
6c0670c3 | 73 | { |
95a61c6f | 74 | pw.xfrBlob(string(d_record.begin(),d_record.end())); |
6c0670c3 | 75 | } |
5a1f298f | 76 | |
cff3e04d | 77 | uint16_t getType() const override |
5a1f298f | 78 | { |
79 | return d_dr.d_type; | |
80 | } | |
ff6a1e7b | 81 | private: |
6c0670c3 BH |
82 | DNSRecord d_dr; |
83 | vector<uint8_t> d_record; | |
ff6a1e7b BH |
84 | }; |
85 | ||
561434a6 | 86 | shared_ptr<DNSRecordContent> DNSRecordContent::unserialize(const DNSName& qname, uint16_t qtype, const string& serialized) |
ea634573 BH |
87 | { |
88 | dnsheader dnsheader; | |
89 | memset(&dnsheader, 0, sizeof(dnsheader)); | |
90 | dnsheader.qdcount=htons(1); | |
91 | dnsheader.ancount=htons(1); | |
92 | ||
93 | vector<uint8_t> packet; // build pseudo packet | |
678ce973 BH |
94 | |
95 | /* will look like: dnsheader, 5 bytes, encoded qname, dns record header, serialized data */ | |
ea634573 | 96 | |
98584698 | 97 | string encoded=qname.toDNSString(); |
678ce973 BH |
98 | |
99 | packet.resize(sizeof(dnsheader) + 5 + encoded.size() + sizeof(struct dnsrecordheader) + serialized.size()); | |
100 | ||
101 | uint16_t pos=0; | |
102 | ||
103 | memcpy(&packet[0], &dnsheader, sizeof(dnsheader)); pos+=sizeof(dnsheader); | |
104 | ||
105 | char tmp[6]="\x0" "\x0\x1" "\x0\x1"; // root question for ns_t_a | |
106 | memcpy(&packet[pos], &tmp, 5); pos+=5; | |
107 | ||
705f31ae | 108 | memcpy(&packet[pos], encoded.c_str(), encoded.size()); pos+=(uint16_t)encoded.size(); |
ea634573 BH |
109 | |
110 | struct dnsrecordheader drh; | |
111 | drh.d_type=htons(qtype); | |
78f56b38 | 112 | drh.d_class=htons(QClass::IN); |
ea634573 BH |
113 | drh.d_ttl=0; |
114 | drh.d_clen=htons(serialized.size()); | |
115 | ||
678ce973 | 116 | memcpy(&packet[pos], &drh, sizeof(drh)); pos+=sizeof(drh); |
705f31ae | 117 | memcpy(&packet[pos], serialized.c_str(), serialized.size()); pos+=(uint16_t)serialized.size(); |
ea634573 | 118 | |
27c0050c | 119 | MOADNSParser mdp(false, (char*)&*packet.begin(), (unsigned int)packet.size()); |
ea634573 | 120 | shared_ptr<DNSRecordContent> ret= mdp.d_answers.begin()->first.d_content; |
ea634573 BH |
121 | return ret; |
122 | } | |
ff6a1e7b | 123 | |
6177a176 | 124 | std::shared_ptr<DNSRecordContent> DNSRecordContent::mastermake(const DNSRecord &dr, |
232f0877 | 125 | PacketReader& pr) |
ff6a1e7b | 126 | { |
7f7b8d55 BH |
127 | uint16_t searchclass = (dr.d_type == QType::OPT) ? 1 : dr.d_class; // class is invalid for OPT |
128 | ||
129 | typemap_t::const_iterator i=getTypemap().find(make_pair(searchclass, dr.d_type)); | |
49a06471 | 130 | if(i==getTypemap().end() || !i->second) { |
6177a176 | 131 | return std::make_shared<UnknownRecordContent>(dr, pr); |
ff6a1e7b | 132 | } |
945a9ad4 | 133 | |
32122aab | 134 | return i->second(dr, pr); |
ff6a1e7b BH |
135 | } |
136 | ||
6177a176 | 137 | std::shared_ptr<DNSRecordContent> DNSRecordContent::mastermake(uint16_t qtype, uint16_t qclass, |
232f0877 | 138 | const string& content) |
6c0670c3 | 139 | { |
49a06471 BH |
140 | zmakermap_t::const_iterator i=getZmakermap().find(make_pair(qclass, qtype)); |
141 | if(i==getZmakermap().end()) { | |
6177a176 | 142 | return std::make_shared<UnknownRecordContent>(content); |
6c0670c3 BH |
143 | } |
144 | ||
32122aab | 145 | return i->second(content); |
6c0670c3 BH |
146 | } |
147 | ||
6177a176 | 148 | std::shared_ptr<DNSRecordContent> DNSRecordContent::mastermake(const DNSRecord &dr, PacketReader& pr, uint16_t oc) { |
7945d472 RA |
149 | // For opcode UPDATE and where the DNSRecord is an answer record, we don't care about content, because this is |
150 | // not used within the prerequisite section of RFC2136, so - we can simply use unknownrecordcontent. | |
89c46d18 | 151 | // For section 3.2.3, we do need content so we need to get it properly. But only for the correct QClasses. |
e693ff5a | 152 | if (oc == Opcode::Update && dr.d_place == DNSResourceRecord::ANSWER && dr.d_class != 1) |
6177a176 | 153 | return std::make_shared<UnknownRecordContent>(dr, pr); |
914353ca | 154 | |
7945d472 RA |
155 | uint16_t searchclass = (dr.d_type == QType::OPT) ? 1 : dr.d_class; // class is invalid for OPT |
156 | ||
157 | typemap_t::const_iterator i=getTypemap().find(make_pair(searchclass, dr.d_type)); | |
158 | if(i==getTypemap().end() || !i->second) { | |
6177a176 | 159 | return std::make_shared<UnknownRecordContent>(dr, pr); |
7945d472 RA |
160 | } |
161 | ||
32122aab | 162 | return i->second(dr, pr); |
7945d472 RA |
163 | } |
164 | ||
165 | ||
49a06471 BH |
166 | DNSRecordContent::typemap_t& DNSRecordContent::getTypemap() |
167 | { | |
168 | static DNSRecordContent::typemap_t typemap; | |
169 | return typemap; | |
170 | } | |
171 | ||
108c321e | 172 | DNSRecordContent::n2typemap_t& DNSRecordContent::getN2Typemap() |
49a06471 | 173 | { |
93e4cb97 BH |
174 | static DNSRecordContent::n2typemap_t n2typemap; |
175 | return n2typemap; | |
49a06471 BH |
176 | } |
177 | ||
108c321e BH |
178 | DNSRecordContent::t2namemap_t& DNSRecordContent::getT2Namemap() |
179 | { | |
93e4cb97 BH |
180 | static DNSRecordContent::t2namemap_t t2namemap; |
181 | return t2namemap; | |
108c321e BH |
182 | } |
183 | ||
49a06471 BH |
184 | DNSRecordContent::zmakermap_t& DNSRecordContent::getZmakermap() |
185 | { | |
186 | static DNSRecordContent::zmakermap_t zmakermap; | |
187 | return zmakermap; | |
188 | } | |
189 | ||
5708a729 | 190 | DNSRecord::DNSRecord(const DNSResourceRecord& rr): d_name(rr.qname) |
fbe23591 | 191 | { |
fbe23591 | 192 | d_type = rr.qtype.getCode(); |
193 | d_ttl = rr.ttl; | |
194 | d_class = rr.qclass; | |
4950b140 | 195 | d_place = DNSResourceRecord::ANSWER; |
e24c18b0 | 196 | d_clen = 0; |
6177a176 | 197 | d_content = DNSRecordContent::mastermake(d_type, rr.qclass, rr.content); |
fbe23591 | 198 | } |
199 | ||
4950b140 CH |
200 | // If you call this and you are not parsing a packet coming from a socket, you are doing it wrong. |
201 | DNSResourceRecord DNSResourceRecord::fromWire(const DNSRecord& d) { | |
202 | DNSResourceRecord rr; | |
203 | rr.qname = d.d_name; | |
204 | rr.qtype = QType(d.d_type); | |
205 | rr.ttl = d.d_ttl; | |
bb7123d3 | 206 | rr.content = d.d_content->getZoneRepresentation(true); |
4950b140 CH |
207 | rr.auth = false; |
208 | rr.qclass = d.d_class; | |
209 | return rr; | |
210 | } | |
211 | ||
78f56b38 | 212 | void MOADNSParser::init(bool query, const std::string& packet) |
ff6a1e7b | 213 | { |
78f56b38 | 214 | if (packet.size() < sizeof(dnsheader)) |
ff6a1e7b BH |
215 | throw MOADNSException("Packet shorter than minimal header"); |
216 | ||
78f56b38 | 217 | memcpy(&d_header, packet.data(), sizeof(dnsheader)); |
ff6a1e7b | 218 | |
7945d472 | 219 | if(d_header.opcode != Opcode::Query && d_header.opcode != Opcode::Notify && d_header.opcode != Opcode::Update) |
335da0ba | 220 | throw MOADNSException("Can't parse non-query packet with opcode="+ std::to_string(d_header.opcode)); |
f27e6356 | 221 | |
ff6a1e7b BH |
222 | d_header.qdcount=ntohs(d_header.qdcount); |
223 | d_header.ancount=ntohs(d_header.ancount); | |
224 | d_header.nscount=ntohs(d_header.nscount); | |
225 | d_header.arcount=ntohs(d_header.arcount); | |
27c0050c RG |
226 | |
227 | if (query && (d_header.qdcount > 1)) | |
228 | throw MOADNSException("Query with QD > 1 ("+std::to_string(d_header.qdcount)+")"); | |
ff6a1e7b | 229 | |
629eaf49 | 230 | unsigned int n=0; |
ff6a1e7b | 231 | |
78f56b38 | 232 | PacketReader pr(packet); |
7b1469bb | 233 | bool validPacket=false; |
512c8492 | 234 | try { |
00bf10d3 BH |
235 | d_qtype = d_qclass = 0; // sometimes replies come in with no question, don't present garbage then |
236 | ||
40207e64 | 237 | for(n=0;n < d_header.qdcount; ++n) { |
8ad443ea | 238 | d_qname=pr.getName(); |
40207e64 BH |
239 | d_qtype=pr.get16BitInt(); |
240 | d_qclass=pr.get16BitInt(); | |
241 | } | |
242 | ||
512c8492 BH |
243 | struct dnsrecordheader ah; |
244 | vector<unsigned char> record; | |
04151caa | 245 | bool seenTSIG = false; |
7b1469bb | 246 | validPacket=true; |
756e82cf | 247 | d_answers.reserve((unsigned int)(d_header.ancount + d_header.nscount + d_header.arcount)); |
c4ac5865 | 248 | for(n=0;n < (unsigned int)(d_header.ancount + d_header.nscount + d_header.arcount); ++n) { |
512c8492 BH |
249 | DNSRecord dr; |
250 | ||
251 | if(n < d_header.ancount) | |
e693ff5a | 252 | dr.d_place=DNSResourceRecord::ANSWER; |
512c8492 | 253 | else if(n < d_header.ancount + d_header.nscount) |
e693ff5a | 254 | dr.d_place=DNSResourceRecord::AUTHORITY; |
512c8492 | 255 | else |
e693ff5a | 256 | dr.d_place=DNSResourceRecord::ADDITIONAL; |
04151caa | 257 | |
78f56b38 | 258 | unsigned int recordStartPos=pr.getPosition(); |
57e5f5f7 | 259 | |
f809c028 | 260 | DNSName name=pr.getName(); |
04151caa | 261 | |
512c8492 BH |
262 | pr.getDnsrecordheader(ah); |
263 | dr.d_ttl=ah.d_ttl; | |
264 | dr.d_type=ah.d_type; | |
265 | dr.d_class=ah.d_class; | |
04151caa | 266 | |
f809c028 | 267 | dr.d_name=name; |
512c8492 | 268 | dr.d_clen=ah.d_clen; |
7b1469bb | 269 | |
c2a1b24d PL |
270 | if (query && |
271 | !(d_qtype == QType::IXFR && dr.d_place == DNSResourceRecord::AUTHORITY && dr.d_type == QType::SOA) && // IXFR queries have a SOA in their AUTHORITY section | |
272 | (dr.d_place == DNSResourceRecord::ANSWER || dr.d_place == DNSResourceRecord::AUTHORITY || (dr.d_type != QType::OPT && dr.d_type != QType::TSIG && dr.d_type != QType::SIG && dr.d_type != QType::TKEY) || ((dr.d_type == QType::TSIG || dr.d_type == QType::SIG || dr.d_type == QType::TKEY) && dr.d_class != QClass::ANY))) { | |
27c0050c | 273 | // cerr<<"discarding RR, query is "<<query<<", place is "<<dr.d_place<<", type is "<<dr.d_type<<", class is "<<dr.d_class<<endl; |
63fc7705 | 274 | dr.d_content=std::make_shared<UnknownRecordContent>(dr, pr); |
27c0050c RG |
275 | } |
276 | else { | |
277 | // cerr<<"parsing RR, query is "<<query<<", place is "<<dr.d_place<<", type is "<<dr.d_type<<", class is "<<dr.d_class<<endl; | |
6177a176 | 278 | dr.d_content=DNSRecordContent::mastermake(dr, pr, d_header.opcode); |
27c0050c RG |
279 | } |
280 | ||
78f56b38 | 281 | d_answers.push_back(make_pair(dr, pr.getPosition() - sizeof(dnsheader))); |
57e5f5f7 | 282 | |
18f707fa RG |
283 | /* XXX: XPF records should be allowed after TSIG as soon as the actual XPF option code has been assigned: |
284 | if (dr.d_place == DNSResourceRecord::ADDITIONAL && seenTSIG && dr.d_type != QType::XPF) | |
285 | */ | |
286 | if (dr.d_place == DNSResourceRecord::ADDITIONAL && seenTSIG) { | |
04151caa RG |
287 | /* only XPF records are allowed after a TSIG */ |
288 | throw MOADNSException("Packet ("+d_qname.toString()+"|#"+std::to_string(d_qtype)+") has an unexpected record ("+std::to_string(dr.d_type)+") after a TSIG one."); | |
289 | } | |
290 | ||
60a1c204 | 291 | if(dr.d_type == QType::TSIG && dr.d_class == QClass::ANY) { |
18f707fa | 292 | if(seenTSIG || dr.d_place != DNSResourceRecord::ADDITIONAL) { |
86f1af1c | 293 | throw MOADNSException("Packet ("+d_qname.toLogString()+"|#"+std::to_string(d_qtype)+") has a TSIG record in an invalid position."); |
60a1c204 | 294 | } |
04151caa | 295 | seenTSIG = true; |
78f56b38 | 296 | d_tsigPos = recordStartPos; |
60a1c204 | 297 | } |
512c8492 | 298 | } |
e5986c84 | 299 | |
04151caa | 300 | #if 0 |
78f56b38 RG |
301 | if(pr.getPosition()!=packet.size()) { |
302 | throw MOADNSException("Packet ("+d_qname+"|#"+std::to_string(d_qtype)+") has trailing garbage ("+ std::to_string(pr.getPosition()) + " < " + | |
303 | std::to_string(packet.size()) + ")"); | |
ff6a1e7b | 304 | } |
04151caa | 305 | #endif |
512c8492 | 306 | } |
78f56b38 | 307 | catch(const std::out_of_range &re) { |
629eaf49 BH |
308 | if(validPacket && d_header.tc) { // don't sweat it over truncated packets, but do adjust an, ns and arcount |
309 | if(n < d_header.ancount) { | |
4957a608 | 310 | d_header.ancount=n; d_header.nscount = d_header.arcount = 0; |
629eaf49 BH |
311 | } |
312 | else if(n < d_header.ancount + d_header.nscount) { | |
4957a608 | 313 | d_header.nscount = n - d_header.ancount; d_header.arcount=0; |
629eaf49 BH |
314 | } |
315 | else { | |
4957a608 | 316 | d_header.arcount = n - d_header.ancount - d_header.nscount; |
629eaf49 BH |
317 | } |
318 | } | |
319 | else { | |
78f56b38 | 320 | throw MOADNSException("Error parsing packet of "+std::to_string(packet.size())+" bytes (rd="+ |
335da0ba | 321 | std::to_string(d_header.rd)+ |
232f0877 | 322 | "), out of bounds: "+string(re.what())); |
629eaf49 | 323 | } |
ff6a1e7b | 324 | } |
ff6a1e7b BH |
325 | } |
326 | ||
10321a98 | 327 | |
ff6a1e7b BH |
328 | void PacketReader::getDnsrecordheader(struct dnsrecordheader &ah) |
329 | { | |
330 | unsigned int n; | |
331 | unsigned char *p=reinterpret_cast<unsigned char*>(&ah); | |
332 | ||
333 | for(n=0; n < sizeof(dnsrecordheader); ++n) | |
334 | p[n]=d_content.at(d_pos++); | |
335 | ||
336 | ah.d_type=ntohs(ah.d_type); | |
337 | ah.d_class=ntohs(ah.d_class); | |
338 | ah.d_clen=ntohs(ah.d_clen); | |
339 | ah.d_ttl=ntohl(ah.d_ttl); | |
8c1c9170 BH |
340 | |
341 | d_startrecordpos=d_pos; // needed for getBlob later on | |
342 | d_recordlen=ah.d_clen; | |
ff6a1e7b BH |
343 | } |
344 | ||
345 | ||
092f210a | 346 | void PacketReader::copyRecord(vector<unsigned char>& dest, uint16_t len) |
ff6a1e7b BH |
347 | { |
348 | dest.resize(len); | |
bff744a8 BH |
349 | if(!len) |
350 | return; | |
351 | ||
092f210a | 352 | for(uint16_t n=0;n<len;++n) { |
ff6a1e7b BH |
353 | dest.at(n)=d_content.at(d_pos++); |
354 | } | |
355 | } | |
356 | ||
092f210a | 357 | void PacketReader::copyRecord(unsigned char* dest, uint16_t len) |
ff6a1e7b BH |
358 | { |
359 | if(d_pos + len > d_content.size()) | |
10f4eea8 | 360 | throw std::out_of_range("Attempt to copy outside of packet"); |
ff6a1e7b | 361 | |
bff744a8 | 362 | memcpy(dest, &d_content.at(d_pos), len); |
ff6a1e7b BH |
363 | d_pos+=len; |
364 | } | |
365 | ||
341930bb BH |
366 | void PacketReader::xfr48BitInt(uint64_t& ret) |
367 | { | |
368 | ret=0; | |
78f56b38 | 369 | ret+=static_cast<uint8_t>(d_content.at(d_pos++)); |
341930bb | 370 | ret<<=8; |
78f56b38 | 371 | ret+=static_cast<uint8_t>(d_content.at(d_pos++)); |
341930bb | 372 | ret<<=8; |
78f56b38 | 373 | ret+=static_cast<uint8_t>(d_content.at(d_pos++)); |
341930bb | 374 | ret<<=8; |
78f56b38 | 375 | ret+=static_cast<uint8_t>(d_content.at(d_pos++)); |
341930bb | 376 | ret<<=8; |
78f56b38 | 377 | ret+=static_cast<uint8_t>(d_content.at(d_pos++)); |
341930bb | 378 | ret<<=8; |
78f56b38 | 379 | ret+=static_cast<uint8_t>(d_content.at(d_pos++)); |
341930bb | 380 | } |
ff6a1e7b | 381 | |
092f210a | 382 | uint32_t PacketReader::get32BitInt() |
ff6a1e7b | 383 | { |
092f210a | 384 | uint32_t ret=0; |
78f56b38 | 385 | ret+=static_cast<uint8_t>(d_content.at(d_pos++)); |
ff6a1e7b | 386 | ret<<=8; |
78f56b38 | 387 | ret+=static_cast<uint8_t>(d_content.at(d_pos++)); |
ff6a1e7b | 388 | ret<<=8; |
78f56b38 | 389 | ret+=static_cast<uint8_t>(d_content.at(d_pos++)); |
ff6a1e7b | 390 | ret<<=8; |
78f56b38 | 391 | ret+=static_cast<uint8_t>(d_content.at(d_pos++)); |
ff6a1e7b BH |
392 | |
393 | return ret; | |
394 | } | |
395 | ||
396 | ||
092f210a | 397 | uint16_t PacketReader::get16BitInt() |
ff6a1e7b | 398 | { |
092f210a | 399 | uint16_t ret=0; |
78f56b38 | 400 | ret+=static_cast<uint8_t>(d_content.at(d_pos++)); |
ff6a1e7b | 401 | ret<<=8; |
78f56b38 | 402 | ret+=static_cast<uint8_t>(d_content.at(d_pos++)); |
ff6a1e7b BH |
403 | |
404 | return ret; | |
405 | } | |
406 | ||
49a06471 | 407 | uint8_t PacketReader::get8BitInt() |
ff6a1e7b BH |
408 | { |
409 | return d_content.at(d_pos++); | |
410 | } | |
411 | ||
8171ab83 | 412 | DNSName PacketReader::getName() |
ff6a1e7b | 413 | { |
d926c0da | 414 | unsigned int consumed; |
c1229531 | 415 | try { |
78f56b38 | 416 | DNSName dn((const char*) d_content.data(), d_content.size(), d_pos, true /* uncompress */, 0 /* qtype */, 0 /* qclass */, &consumed, sizeof(dnsheader)); |
c1229531 | 417 | |
418 | d_pos+=consumed; | |
8171ab83 | 419 | return dn; |
c1229531 | 420 | } |
6177a176 RG |
421 | catch(const std::range_error& re) { |
422 | throw std::out_of_range(string("dnsname issue: ")+re.what()); | |
423 | } | |
424 | catch(...) { | |
425 | throw std::out_of_range("dnsname issue"); | |
426 | } | |
fb38d90b | 427 | throw PDNSException("PacketReader::getName(): name is empty"); |
ff6a1e7b BH |
428 | } |
429 | ||
ef6a78d5 BH |
430 | static string txtEscape(const string &name) |
431 | { | |
432 | string ret; | |
5dba9d25 | 433 | char ebuf[5]; |
ef6a78d5 | 434 | |
5dba9d25 | 435 | for(string::const_iterator i=name.begin();i!=name.end();++i) { |
fa1dc694 | 436 | if((unsigned char) *i >= 127 || (unsigned char) *i < 32) { |
5dba9d25 PD |
437 | snprintf(ebuf, sizeof(ebuf), "\\%03u", (unsigned char)*i); |
438 | ret += ebuf; | |
439 | } | |
66b40966 | 440 | else if(*i=='"' || *i=='\\'){ |
ef6a78d5 BH |
441 | ret += '\\'; |
442 | ret += *i; | |
443 | } | |
444 | else | |
445 | ret += *i; | |
5dba9d25 | 446 | } |
ef6a78d5 BH |
447 | return ret; |
448 | } | |
449 | ||
450 | // exceptions thrown here do not result in logging in the main pdns auth server - just so you know! | |
84e1142d | 451 | string PacketReader::getText(bool multi, bool lenField) |
9d9c52ef BH |
452 | { |
453 | string ret; | |
454 | ret.reserve(40); | |
ef6a78d5 BH |
455 | while(d_pos < d_startrecordpos + d_recordlen ) { |
456 | if(!ret.empty()) { | |
457 | ret.append(1,' '); | |
458 | } | |
84e1142d PL |
459 | uint16_t labellen; |
460 | if(lenField) | |
78f56b38 | 461 | labellen=static_cast<uint8_t>(d_content.at(d_pos++)); |
84e1142d PL |
462 | else |
463 | labellen=d_recordlen - (d_pos - d_startrecordpos); | |
ef6a78d5 BH |
464 | |
465 | ret.append(1,'"'); | |
950f78df BH |
466 | if(labellen) { // no need to do anything for an empty string |
467 | string val(&d_content.at(d_pos), &d_content.at(d_pos+labellen-1)+1); | |
468 | ret.append(txtEscape(val)); // the end is one beyond the packet | |
469 | } | |
ef6a78d5 BH |
470 | ret.append(1,'"'); |
471 | d_pos+=labellen; | |
472 | if(!multi) | |
473 | break; | |
474 | } | |
9d9c52ef | 475 | |
9d9c52ef BH |
476 | return ret; |
477 | } | |
ff6a1e7b | 478 | |
948a927f PL |
479 | string PacketReader::getUnquotedText(bool lenField) |
480 | { | |
a94e5580 | 481 | uint16_t stop_at; |
948a927f | 482 | if(lenField) |
78f56b38 | 483 | stop_at = static_cast<uint8_t>(d_content.at(d_pos)) + d_pos + 1; |
948a927f PL |
484 | else |
485 | stop_at = d_recordlen; | |
486 | ||
d7bbbcf4 RG |
487 | /* think unsigned overflow */ |
488 | if (stop_at < d_pos) { | |
489 | throw std::out_of_range("getUnquotedText out of record range"); | |
490 | } | |
491 | ||
948a927f PL |
492 | if(stop_at == d_pos) |
493 | return ""; | |
494 | ||
495 | d_pos++; | |
496 | string ret(&d_content.at(d_pos), &d_content.at(stop_at)); | |
497 | d_pos = stop_at; | |
498 | return ret; | |
499 | } | |
ef6a78d5 | 500 | |
8c1c9170 | 501 | void PacketReader::xfrBlob(string& blob) |
2bc83940 | 502 | try |
8c1c9170 | 503 | { |
b4d358e7 RG |
504 | if(d_recordlen && !(d_pos == (d_startrecordpos + d_recordlen))) { |
505 | if (d_pos > (d_startrecordpos + d_recordlen)) { | |
506 | throw std::out_of_range("xfrBlob out of record range"); | |
507 | } | |
7f7b8d55 | 508 | blob.assign(&d_content.at(d_pos), &d_content.at(d_startrecordpos + d_recordlen - 1 ) + 1); |
b4d358e7 RG |
509 | } |
510 | else { | |
7f7b8d55 | 511 | blob.clear(); |
b4d358e7 | 512 | } |
8c1c9170 BH |
513 | |
514 | d_pos = d_startrecordpos + d_recordlen; | |
515 | } | |
2bc83940 | 516 | catch(...) |
517 | { | |
518 | throw std::out_of_range("xfrBlob out of range"); | |
519 | } | |
59a0f653 | 520 | |
2fe9d6f7 AT |
521 | void PacketReader::xfrBlobNoSpaces(string& blob, int length) { |
522 | xfrBlob(blob, length); | |
523 | } | |
524 | ||
06ffdc52 BH |
525 | void PacketReader::xfrBlob(string& blob, int length) |
526 | { | |
2617464d | 527 | if(length) { |
b4d358e7 RG |
528 | if (length < 0) { |
529 | throw std::out_of_range("xfrBlob out of range (negative length)"); | |
530 | } | |
531 | ||
0407751c | 532 | blob.assign(&d_content.at(d_pos), &d_content.at(d_pos + length - 1 ) + 1 ); |
b4d358e7 | 533 | |
2617464d BH |
534 | d_pos += length; |
535 | } | |
b4d358e7 | 536 | else { |
2617464d | 537 | blob.clear(); |
b4d358e7 | 538 | } |
06ffdc52 BH |
539 | } |
540 | ||
541 | ||
e4090157 | 542 | void PacketReader::xfrHexBlob(string& blob, bool keepReading) |
59a0f653 BH |
543 | { |
544 | xfrBlob(blob); | |
545 | } | |
b8e0f341 | 546 | |
3343ad1f | 547 | //FIXME400 remove this method completely |
27ff60a3 | 548 | string simpleCompress(const string& elabel, const string& root) |
b8e0f341 | 549 | { |
27ff60a3 | 550 | string label=elabel; |
3343ad1f | 551 | // FIXME400: this relies on the semi-canonical escaped output from getName |
83b746fd | 552 | if(strchr(label.c_str(), '\\')) { |
553 | boost::replace_all(label, "\\.", "."); | |
554 | boost::replace_all(label, "\\032", " "); | |
555 | boost::replace_all(label, "\\\\", "\\"); | |
556 | } | |
b8e0f341 BH |
557 | typedef vector<pair<unsigned int, unsigned int> > parts_t; |
558 | parts_t parts; | |
559 | vstringtok(parts, label, "."); | |
560 | string ret; | |
561 | ret.reserve(label.size()+4); | |
562 | for(parts_t::const_iterator i=parts.begin(); i!=parts.end(); ++i) { | |
05a38bfa | 563 | if(!root.empty() && !strncasecmp(root.c_str(), label.c_str() + i->first, 1 + label.length() - i->first)) { // also match trailing 0, hence '1 +' |
015db425 PD |
564 | const unsigned char rootptr[2]={0xc0,0x11}; |
565 | ret.append((const char *) rootptr, 2); | |
7127879f BH |
566 | return ret; |
567 | } | |
b8e0f341 BH |
568 | ret.append(1, (char)(i->second - i->first)); |
569 | ret.append(label.c_str() + i->first, i->second - i->first); | |
570 | } | |
571 | ret.append(1, (char)0); | |
572 | return ret; | |
573 | } | |
574 | ||
7127879f | 575 | |
2c73e580 BH |
576 | /** Simple DNSPacketMangler. Ritual is: get a pointer into the packet and moveOffset() to beyond your needs |
577 | * If you survive that, feel free to read from the pointer */ | |
578 | class DNSPacketMangler | |
579 | { | |
580 | public: | |
581 | explicit DNSPacketMangler(std::string& packet) | |
886e2cf2 RG |
582 | : d_packet((char*) packet.c_str()), d_length(packet.length()), d_notyouroffset(12), d_offset(d_notyouroffset) |
583 | {} | |
584 | DNSPacketMangler(char* packet, size_t length) | |
585 | : d_packet(packet), d_length(length), d_notyouroffset(12), d_offset(d_notyouroffset) | |
2c73e580 BH |
586 | {} |
587 | ||
4f9597f5 RG |
588 | /*! Advances past a wire-format domain name |
589 | * The name is not checked for adherence to length restrictions. | |
590 | * Compression pointers are not followed. | |
591 | */ | |
c1780c41 | 592 | void skipDomainName() |
2c73e580 BH |
593 | { |
594 | uint8_t len; | |
595 | while((len=get8BitInt())) { | |
596 | if(len >= 0xc0) { // extended label | |
232f0877 CH |
597 | get8BitInt(); |
598 | return; | |
2c73e580 BH |
599 | } |
600 | skipBytes(len); | |
601 | } | |
602 | } | |
4f9597f5 | 603 | |
2c73e580 BH |
604 | void skipBytes(uint16_t bytes) |
605 | { | |
153d5065 RG |
606 | moveOffset(bytes); |
607 | } | |
608 | void rewindBytes(uint16_t by) | |
609 | { | |
610 | rewindOffset(by); | |
2c73e580 | 611 | } |
0766890a RG |
612 | uint32_t get32BitInt() |
613 | { | |
614 | const char* p = d_packet + d_offset; | |
615 | moveOffset(4); | |
616 | uint32_t ret; | |
a683e8bd | 617 | memcpy(&ret, (void*)p, sizeof(ret)); |
0766890a RG |
618 | return ntohl(ret); |
619 | } | |
2c73e580 BH |
620 | uint16_t get16BitInt() |
621 | { | |
886e2cf2 | 622 | const char* p = d_packet + d_offset; |
2c73e580 BH |
623 | moveOffset(2); |
624 | uint16_t ret; | |
a683e8bd | 625 | memcpy(&ret, (void*)p, sizeof(ret)); |
2c73e580 BH |
626 | return ntohs(ret); |
627 | } | |
628 | ||
629 | uint8_t get8BitInt() | |
630 | { | |
886e2cf2 | 631 | const char* p = d_packet + d_offset; |
2c73e580 BH |
632 | moveOffset(1); |
633 | return *p; | |
634 | } | |
635 | ||
636 | void skipRData() | |
637 | { | |
638 | int toskip = get16BitInt(); | |
639 | moveOffset(toskip); | |
640 | } | |
153d5065 | 641 | |
2c73e580 BH |
642 | void decreaseAndSkip32BitInt(uint32_t decrease) |
643 | { | |
886e2cf2 | 644 | const char *p = d_packet + d_offset; |
2c73e580 | 645 | moveOffset(4); |
153d5065 | 646 | |
2c73e580 BH |
647 | uint32_t tmp; |
648 | memcpy(&tmp, (void*) p, sizeof(tmp)); | |
649 | tmp = ntohl(tmp); | |
650 | tmp-=decrease; | |
651 | tmp = htonl(tmp); | |
886e2cf2 | 652 | memcpy(d_packet + d_offset-4, (const char*)&tmp, sizeof(tmp)); |
2c73e580 | 653 | } |
153d5065 RG |
654 | void setAndSkip32BitInt(uint32_t value) |
655 | { | |
656 | moveOffset(4); | |
657 | ||
658 | value = htonl(value); | |
659 | memcpy(d_packet + d_offset-4, (const char*)&value, sizeof(value)); | |
660 | } | |
55baa1f2 RG |
661 | uint32_t getOffset() const |
662 | { | |
663 | return d_offset; | |
664 | } | |
2c73e580 BH |
665 | private: |
666 | void moveOffset(uint16_t by) | |
667 | { | |
668 | d_notyouroffset += by; | |
886e2cf2 | 669 | if(d_notyouroffset > d_length) |
335da0ba | 670 | throw std::out_of_range("dns packet out of range: "+std::to_string(d_notyouroffset) +" > " |
886e2cf2 | 671 | + std::to_string(d_length) ); |
2c73e580 | 672 | } |
153d5065 RG |
673 | void rewindOffset(uint16_t by) |
674 | { | |
675 | if(d_notyouroffset < by) | |
676 | throw std::out_of_range("Rewinding dns packet out of range: "+std::to_string(d_notyouroffset) +" < " | |
677 | + std::to_string(by)); | |
678 | d_notyouroffset -= by; | |
679 | if(d_notyouroffset < 12) | |
680 | throw std::out_of_range("Rewinding dns packet out of range: "+std::to_string(d_notyouroffset) +" < " | |
681 | + std::to_string(12)); | |
682 | } | |
886e2cf2 RG |
683 | char* d_packet; |
684 | size_t d_length; | |
2c73e580 BH |
685 | |
686 | uint32_t d_notyouroffset; // only 'moveOffset' can touch this | |
687 | const uint32_t& d_offset; // look.. but don't touch | |
688 | ||
689 | }; | |
690 | ||
153d5065 RG |
691 | // method of operation: silently fail if it doesn't work - we're only trying to be nice, don't fall over on it |
692 | void editDNSPacketTTL(char* packet, size_t length, std::function<uint32_t(uint8_t, uint16_t, uint16_t, uint32_t)> visitor) | |
693 | { | |
694 | if(length < sizeof(dnsheader)) | |
695 | return; | |
696 | try | |
697 | { | |
698 | dnsheader dh; | |
699 | memcpy((void*)&dh, (const dnsheader*)packet, sizeof(dh)); | |
700 | uint64_t numrecords = ntohs(dh.ancount) + ntohs(dh.nscount) + ntohs(dh.arcount); | |
701 | DNSPacketMangler dpm(packet, length); | |
702 | ||
703 | uint64_t n; | |
704 | for(n=0; n < ntohs(dh.qdcount) ; ++n) { | |
c1780c41 | 705 | dpm.skipDomainName(); |
153d5065 RG |
706 | /* type and class */ |
707 | dpm.skipBytes(4); | |
708 | } | |
709 | ||
710 | for(n=0; n < numrecords; ++n) { | |
c1780c41 | 711 | dpm.skipDomainName(); |
153d5065 | 712 | |
d7ce446c | 713 | uint8_t section = n < ntohs(dh.ancount) ? 1 : (n < (ntohs(dh.ancount) + ntohs(dh.nscount)) ? 2 : 3); |
153d5065 RG |
714 | uint16_t dnstype = dpm.get16BitInt(); |
715 | uint16_t dnsclass = dpm.get16BitInt(); | |
716 | ||
717 | if(dnstype == QType::OPT) // not getting near that one with a stick | |
718 | break; | |
719 | ||
720 | uint32_t dnsttl = dpm.get32BitInt(); | |
721 | uint32_t newttl = visitor(section, dnsclass, dnstype, dnsttl); | |
722 | if (newttl) { | |
723 | dpm.rewindBytes(sizeof(newttl)); | |
724 | dpm.setAndSkip32BitInt(newttl); | |
725 | } | |
726 | dpm.skipRData(); | |
727 | } | |
728 | } | |
729 | catch(...) | |
730 | { | |
731 | return; | |
732 | } | |
733 | } | |
734 | ||
2c73e580 | 735 | // method of operation: silently fail if it doesn't work - we're only trying to be nice, don't fall over on it |
886e2cf2 | 736 | void ageDNSPacket(char* packet, size_t length, uint32_t seconds) |
2c73e580 | 737 | { |
886e2cf2 | 738 | if(length < sizeof(dnsheader)) |
2c73e580 BH |
739 | return; |
740 | try | |
741 | { | |
7def3a4b RG |
742 | const dnsheader* dh = reinterpret_cast<const dnsheader*>(packet); |
743 | const uint64_t dqcount = ntohs(dh->qdcount); | |
744 | const uint64_t numrecords = ntohs(dh->ancount) + ntohs(dh->nscount) + ntohs(dh->arcount); | |
886e2cf2 | 745 | DNSPacketMangler dpm(packet, length); |
a683e8bd RG |
746 | |
747 | uint64_t n; | |
7def3a4b | 748 | for(n=0; n < dqcount; ++n) { |
c1780c41 | 749 | dpm.skipDomainName(); |
1819b930 RG |
750 | /* type and class */ |
751 | dpm.skipBytes(4); | |
2c73e580 BH |
752 | } |
753 | // cerr<<"Skipped "<<n<<" questions, now parsing "<<numrecords<<" records"<<endl; | |
754 | for(n=0; n < numrecords; ++n) { | |
c1780c41 | 755 | dpm.skipDomainName(); |
2c73e580 BH |
756 | |
757 | uint16_t dnstype = dpm.get16BitInt(); | |
1819b930 RG |
758 | /* class */ |
759 | dpm.skipBytes(2); | |
2c73e580 BH |
760 | |
761 | if(dnstype == QType::OPT) // not aging that one with a stick | |
232f0877 | 762 | break; |
2c73e580 BH |
763 | |
764 | dpm.decreaseAndSkip32BitInt(seconds); | |
765 | dpm.skipRData(); | |
766 | } | |
767 | } | |
768 | catch(...) | |
769 | { | |
770 | return; | |
771 | } | |
772 | } | |
886e2cf2 RG |
773 | |
774 | void ageDNSPacket(std::string& packet, uint32_t seconds) | |
775 | { | |
776 | ageDNSPacket((char*)packet.c_str(), packet.length(), seconds); | |
777 | } | |
0766890a | 778 | |
47698274 | 779 | uint32_t getDNSPacketMinTTL(const char* packet, size_t length, bool* seenAuthSOA) |
0766890a RG |
780 | { |
781 | uint32_t result = std::numeric_limits<uint32_t>::max(); | |
782 | if(length < sizeof(dnsheader)) { | |
783 | return result; | |
784 | } | |
785 | try | |
786 | { | |
787 | const dnsheader* dh = (const dnsheader*) packet; | |
788 | DNSPacketMangler dpm(const_cast<char*>(packet), length); | |
789 | ||
790 | const uint16_t qdcount = ntohs(dh->qdcount); | |
791 | for(size_t n = 0; n < qdcount; ++n) { | |
c1780c41 | 792 | dpm.skipDomainName(); |
1819b930 RG |
793 | /* type and class */ |
794 | dpm.skipBytes(4); | |
0766890a RG |
795 | } |
796 | const size_t numrecords = ntohs(dh->ancount) + ntohs(dh->nscount) + ntohs(dh->arcount); | |
797 | for(size_t n = 0; n < numrecords; ++n) { | |
c1780c41 | 798 | dpm.skipDomainName(); |
0766890a | 799 | const uint16_t dnstype = dpm.get16BitInt(); |
1819b930 | 800 | /* class */ |
47698274 | 801 | const uint16_t dnsclass = dpm.get16BitInt(); |
0766890a | 802 | |
d7ce446c | 803 | if(dnstype == QType::OPT) { |
0766890a | 804 | break; |
d7ce446c RG |
805 | } |
806 | ||
807 | /* report it if we see a SOA record in the AUTHORITY section */ | |
cfd669b4 | 808 | if(dnstype == QType::SOA && dnsclass == QClass::IN && seenAuthSOA != nullptr && n >= ntohs(dh->ancount) && n < (ntohs(dh->ancount) + ntohs(dh->nscount))) { |
d7ce446c RG |
809 | *seenAuthSOA = true; |
810 | } | |
0766890a RG |
811 | |
812 | const uint32_t ttl = dpm.get32BitInt(); | |
47698274 | 813 | if (result > ttl) { |
0766890a | 814 | result = ttl; |
47698274 | 815 | } |
0766890a RG |
816 | |
817 | dpm.skipRData(); | |
818 | } | |
819 | } | |
820 | catch(...) | |
821 | { | |
822 | } | |
823 | return result; | |
824 | } | |
55baa1f2 RG |
825 | |
826 | uint32_t getDNSPacketLength(const char* packet, size_t length) | |
827 | { | |
828 | uint32_t result = length; | |
829 | if(length < sizeof(dnsheader)) { | |
830 | return result; | |
831 | } | |
832 | try | |
833 | { | |
53c57da7 | 834 | const dnsheader* dh = reinterpret_cast<const dnsheader*>(packet); |
55baa1f2 RG |
835 | DNSPacketMangler dpm(const_cast<char*>(packet), length); |
836 | ||
837 | const uint16_t qdcount = ntohs(dh->qdcount); | |
838 | for(size_t n = 0; n < qdcount; ++n) { | |
c1780c41 | 839 | dpm.skipDomainName(); |
1819b930 RG |
840 | /* type and class */ |
841 | dpm.skipBytes(4); | |
55baa1f2 RG |
842 | } |
843 | const size_t numrecords = ntohs(dh->ancount) + ntohs(dh->nscount) + ntohs(dh->arcount); | |
844 | for(size_t n = 0; n < numrecords; ++n) { | |
c1780c41 | 845 | dpm.skipDomainName(); |
1819b930 RG |
846 | /* type (2), class (2) and ttl (4) */ |
847 | dpm.skipBytes(8); | |
55baa1f2 RG |
848 | dpm.skipRData(); |
849 | } | |
850 | result = dpm.getOffset(); | |
851 | } | |
852 | catch(...) | |
853 | { | |
854 | } | |
855 | return result; | |
856 | } | |
857 | ||
858 | uint16_t getRecordsOfTypeCount(const char* packet, size_t length, uint8_t section, uint16_t type) | |
859 | { | |
860 | uint16_t result = 0; | |
861 | if(length < sizeof(dnsheader)) { | |
862 | return result; | |
863 | } | |
864 | try | |
865 | { | |
866 | const dnsheader* dh = (const dnsheader*) packet; | |
867 | DNSPacketMangler dpm(const_cast<char*>(packet), length); | |
868 | ||
869 | const uint16_t qdcount = ntohs(dh->qdcount); | |
870 | for(size_t n = 0; n < qdcount; ++n) { | |
c1780c41 | 871 | dpm.skipDomainName(); |
55baa1f2 RG |
872 | if (section == 0) { |
873 | uint16_t dnstype = dpm.get16BitInt(); | |
874 | if (dnstype == type) { | |
875 | result++; | |
876 | } | |
1819b930 RG |
877 | /* class */ |
878 | dpm.skipBytes(2); | |
55baa1f2 | 879 | } else { |
1819b930 RG |
880 | /* type and class */ |
881 | dpm.skipBytes(4); | |
55baa1f2 RG |
882 | } |
883 | } | |
884 | const uint16_t ancount = ntohs(dh->ancount); | |
885 | for(size_t n = 0; n < ancount; ++n) { | |
c1780c41 | 886 | dpm.skipDomainName(); |
55baa1f2 RG |
887 | if (section == 1) { |
888 | uint16_t dnstype = dpm.get16BitInt(); | |
889 | if (dnstype == type) { | |
890 | result++; | |
891 | } | |
1819b930 RG |
892 | /* class */ |
893 | dpm.skipBytes(2); | |
55baa1f2 | 894 | } else { |
1819b930 RG |
895 | /* type and class */ |
896 | dpm.skipBytes(4); | |
55baa1f2 | 897 | } |
1819b930 RG |
898 | /* ttl */ |
899 | dpm.skipBytes(4); | |
55baa1f2 RG |
900 | dpm.skipRData(); |
901 | } | |
902 | const uint16_t nscount = ntohs(dh->nscount); | |
903 | for(size_t n = 0; n < nscount; ++n) { | |
c1780c41 | 904 | dpm.skipDomainName(); |
55baa1f2 RG |
905 | if (section == 2) { |
906 | uint16_t dnstype = dpm.get16BitInt(); | |
907 | if (dnstype == type) { | |
908 | result++; | |
909 | } | |
1819b930 RG |
910 | /* class */ |
911 | dpm.skipBytes(2); | |
55baa1f2 | 912 | } else { |
1819b930 RG |
913 | /* type and class */ |
914 | dpm.skipBytes(4); | |
55baa1f2 | 915 | } |
1819b930 RG |
916 | /* ttl */ |
917 | dpm.skipBytes(4); | |
55baa1f2 RG |
918 | dpm.skipRData(); |
919 | } | |
920 | const uint16_t arcount = ntohs(dh->arcount); | |
921 | for(size_t n = 0; n < arcount; ++n) { | |
c1780c41 | 922 | dpm.skipDomainName(); |
55baa1f2 RG |
923 | if (section == 3) { |
924 | uint16_t dnstype = dpm.get16BitInt(); | |
925 | if (dnstype == type) { | |
926 | result++; | |
927 | } | |
1819b930 RG |
928 | /* class */ |
929 | dpm.skipBytes(2); | |
55baa1f2 | 930 | } else { |
1819b930 RG |
931 | /* type and class */ |
932 | dpm.skipBytes(4); | |
55baa1f2 | 933 | } |
1819b930 RG |
934 | /* ttl */ |
935 | dpm.skipBytes(4); | |
55baa1f2 RG |
936 | dpm.skipRData(); |
937 | } | |
938 | } | |
939 | catch(...) | |
940 | { | |
941 | } | |
942 | return result; | |
943 | } | |
e7c732b8 | 944 | |
e0fd37ec | 945 | bool getEDNSUDPPayloadSizeAndZ(const char* packet, size_t length, uint16_t* payloadSize, uint16_t* z) |
e7c732b8 RG |
946 | { |
947 | if (length < sizeof(dnsheader)) { | |
e0fd37ec | 948 | return false; |
e7c732b8 RG |
949 | } |
950 | ||
e0fd37ec RG |
951 | *payloadSize = 0; |
952 | *z = 0; | |
953 | ||
e7c732b8 RG |
954 | try |
955 | { | |
956 | const dnsheader* dh = (const dnsheader*) packet; | |
957 | DNSPacketMangler dpm(const_cast<char*>(packet), length); | |
958 | ||
959 | const uint16_t qdcount = ntohs(dh->qdcount); | |
960 | for(size_t n = 0; n < qdcount; ++n) { | |
c1780c41 | 961 | dpm.skipDomainName(); |
e7c732b8 RG |
962 | /* type and class */ |
963 | dpm.skipBytes(4); | |
964 | } | |
965 | const size_t numrecords = ntohs(dh->ancount) + ntohs(dh->nscount) + ntohs(dh->arcount); | |
966 | for(size_t n = 0; n < numrecords; ++n) { | |
c1780c41 | 967 | dpm.skipDomainName(); |
e7c732b8 RG |
968 | const uint16_t dnstype = dpm.get16BitInt(); |
969 | const uint16_t dnsclass = dpm.get16BitInt(); | |
970 | ||
971 | if(dnstype == QType::OPT) { | |
e0fd37ec RG |
972 | /* skip extended rcode and version */ |
973 | dpm.skipBytes(2); | |
974 | *z = dpm.get16BitInt(); | |
975 | *payloadSize = dnsclass; | |
976 | return true; | |
e7c732b8 RG |
977 | } |
978 | ||
979 | /* TTL */ | |
980 | dpm.skipBytes(4); | |
981 | dpm.skipRData(); | |
982 | } | |
983 | } | |
984 | catch(...) | |
985 | { | |
986 | } | |
e0fd37ec RG |
987 | |
988 | return false; | |
e7c732b8 | 989 | } |