| 1 | /* |
|---|
| 2 | PowerDNS Versatile Database Driven Nameserver |
|---|
| 3 | Copyright (C) 2001 - 2010 PowerDNS.COM BV |
|---|
| 4 | |
|---|
| 5 | This program is free software; you can redistribute it and/or modify |
|---|
| 6 | it under the terms of the GNU General Public License version 2 as |
|---|
| 7 | published by the Free Software Foundation |
|---|
| 8 | |
|---|
| 9 | This program is distributed in the hope that it will be useful, |
|---|
| 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|---|
| 12 | GNU General Public License for more details. |
|---|
| 13 | |
|---|
| 14 | You should have received a copy of the GNU General Public License |
|---|
| 15 | along with this program; if not, write to the Free Software |
|---|
| 16 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
|---|
| 17 | */ |
|---|
| 18 | |
|---|
| 19 | #include "utility.hh" |
|---|
| 20 | #include <cstdio> |
|---|
| 21 | |
|---|
| 22 | #include <cstdlib> |
|---|
| 23 | #include <sys/types.h> |
|---|
| 24 | |
|---|
| 25 | #include <iostream> |
|---|
| 26 | |
|---|
| 27 | #include <string> |
|---|
| 28 | #include <errno.h> |
|---|
| 29 | #include <boost/tokenizer.hpp> |
|---|
| 30 | #include <boost/algorithm/string.hpp> |
|---|
| 31 | #include <polarssl/havege.h> |
|---|
| 32 | #include <algorithm> |
|---|
| 33 | #include <boost/foreach.hpp> |
|---|
| 34 | #include "dnsseckeeper.hh" |
|---|
| 35 | #include "dns.hh" |
|---|
| 36 | #include "dnsbackend.hh" |
|---|
| 37 | #include "ahuexception.hh" |
|---|
| 38 | #include "dnspacket.hh" |
|---|
| 39 | #include "logger.hh" |
|---|
| 40 | #include "arguments.hh" |
|---|
| 41 | #include "dnswriter.hh" |
|---|
| 42 | #include "dnsparser.hh" |
|---|
| 43 | #include "dnsrecords.hh" |
|---|
| 44 | #include <polarssl/rsa.h> |
|---|
| 45 | #include "dnssecinfra.hh" |
|---|
| 46 | |
|---|
| 47 | DNSPacket::DNSPacket() |
|---|
| 48 | { |
|---|
| 49 | d_wrapped=false; |
|---|
| 50 | d_compress=true; |
|---|
| 51 | d_tcp=false; |
|---|
| 52 | d_wantsnsid=false; |
|---|
| 53 | d_dnssecOk=false; |
|---|
| 54 | } |
|---|
| 55 | |
|---|
| 56 | string DNSPacket::getString() |
|---|
| 57 | { |
|---|
| 58 | return stringbuffer; |
|---|
| 59 | } |
|---|
| 60 | |
|---|
| 61 | const char *DNSPacket::getData(void) |
|---|
| 62 | { |
|---|
| 63 | if(!d_wrapped) |
|---|
| 64 | wrapup(); |
|---|
| 65 | |
|---|
| 66 | return stringbuffer.data(); |
|---|
| 67 | } |
|---|
| 68 | |
|---|
| 69 | const char *DNSPacket::getRaw(void) |
|---|
| 70 | { |
|---|
| 71 | return stringbuffer.data(); |
|---|
| 72 | } |
|---|
| 73 | |
|---|
| 74 | string DNSPacket::getRemote() const |
|---|
| 75 | { |
|---|
| 76 | return remote.toString(); |
|---|
| 77 | } |
|---|
| 78 | |
|---|
| 79 | uint16_t DNSPacket::getRemotePort() const |
|---|
| 80 | { |
|---|
| 81 | return remote.sin4.sin_port; |
|---|
| 82 | } |
|---|
| 83 | |
|---|
| 84 | DNSPacket::DNSPacket(const DNSPacket &orig) |
|---|
| 85 | { |
|---|
| 86 | DLOG(L<<"DNSPacket copy constructor called!"<<endl); |
|---|
| 87 | d_socket=orig.d_socket; |
|---|
| 88 | remote=orig.remote; |
|---|
| 89 | len=orig.len; |
|---|
| 90 | d_qlen=orig.d_qlen; |
|---|
| 91 | d_dt=orig.d_dt; |
|---|
| 92 | d_compress=orig.d_compress; |
|---|
| 93 | d_tcp=orig.d_tcp; |
|---|
| 94 | qtype=orig.qtype; |
|---|
| 95 | qclass=orig.qclass; |
|---|
| 96 | qdomain=orig.qdomain; |
|---|
| 97 | d_maxreplylen = orig.d_maxreplylen; |
|---|
| 98 | d_ednsping = orig.d_ednsping; |
|---|
| 99 | d_wantsnsid = orig.d_wantsnsid; |
|---|
| 100 | d_dnssecOk = orig.d_dnssecOk; |
|---|
| 101 | d_rrs=orig.d_rrs; |
|---|
| 102 | |
|---|
| 103 | d_wrapped=orig.d_wrapped; |
|---|
| 104 | |
|---|
| 105 | stringbuffer=orig.stringbuffer; |
|---|
| 106 | d=orig.d; |
|---|
| 107 | } |
|---|
| 108 | |
|---|
| 109 | void DNSPacket::setRcode(int v) |
|---|
| 110 | { |
|---|
| 111 | d.rcode=v; |
|---|
| 112 | } |
|---|
| 113 | |
|---|
| 114 | void DNSPacket::setAnswer(bool b) |
|---|
| 115 | { |
|---|
| 116 | if(b) { |
|---|
| 117 | stringbuffer.assign(12,(char)0); |
|---|
| 118 | memset((void *)&d,0,sizeof(d)); |
|---|
| 119 | |
|---|
| 120 | d.qr=b; |
|---|
| 121 | } |
|---|
| 122 | } |
|---|
| 123 | |
|---|
| 124 | void DNSPacket::setA(bool b) |
|---|
| 125 | { |
|---|
| 126 | d.aa=b; |
|---|
| 127 | } |
|---|
| 128 | |
|---|
| 129 | void DNSPacket::setID(uint16_t id) |
|---|
| 130 | { |
|---|
| 131 | d.id=id; |
|---|
| 132 | } |
|---|
| 133 | |
|---|
| 134 | void DNSPacket::setRA(bool b) |
|---|
| 135 | { |
|---|
| 136 | d.ra=b; |
|---|
| 137 | } |
|---|
| 138 | |
|---|
| 139 | void DNSPacket::setRD(bool b) |
|---|
| 140 | { |
|---|
| 141 | d.rd=b; |
|---|
| 142 | } |
|---|
| 143 | |
|---|
| 144 | void DNSPacket::setOpcode(uint16_t opcode) |
|---|
| 145 | { |
|---|
| 146 | d.opcode=opcode; |
|---|
| 147 | } |
|---|
| 148 | |
|---|
| 149 | |
|---|
| 150 | void DNSPacket::clearRecords() |
|---|
| 151 | { |
|---|
| 152 | d_rrs.clear(); |
|---|
| 153 | } |
|---|
| 154 | |
|---|
| 155 | void DNSPacket::addRecord(const DNSResourceRecord &rr) |
|---|
| 156 | { |
|---|
| 157 | if(d_compress) |
|---|
| 158 | for(vector<DNSResourceRecord>::const_iterator i=d_rrs.begin();i!=d_rrs.end();++i) |
|---|
| 159 | if(rr.qname==i->qname && rr.qtype==i->qtype && rr.content==i->content) { |
|---|
| 160 | if(rr.qtype.getCode()!=QType::MX && rr.qtype.getCode()!=QType::SRV) |
|---|
| 161 | return; |
|---|
| 162 | if(rr.priority==i->priority) |
|---|
| 163 | return; |
|---|
| 164 | } |
|---|
| 165 | |
|---|
| 166 | d_rrs.push_back(rr); |
|---|
| 167 | } |
|---|
| 168 | |
|---|
| 169 | // the functions below update the 'arcount' and 'ancount', plus they serialize themselves to the stringbuffer |
|---|
| 170 | |
|---|
| 171 | string& attodot(string &str) |
|---|
| 172 | { |
|---|
| 173 | if(str.find_first_of("@")==string::npos) |
|---|
| 174 | return str; |
|---|
| 175 | |
|---|
| 176 | for (unsigned int i = 0; i < str.length(); i++) |
|---|
| 177 | { |
|---|
| 178 | if (str[i] == '@') { |
|---|
| 179 | str[i] = '.'; |
|---|
| 180 | break; |
|---|
| 181 | } else if (str[i] == '.') { |
|---|
| 182 | str.insert(i++, "\\"); |
|---|
| 183 | } |
|---|
| 184 | } |
|---|
| 185 | |
|---|
| 186 | return str; |
|---|
| 187 | } |
|---|
| 188 | |
|---|
| 189 | void fillSOAData(const string &content, SOAData &data) |
|---|
| 190 | { |
|---|
| 191 | // content consists of fields separated by spaces: |
|---|
| 192 | // nameservername hostmaster serial-number [refresh [retry [expire [ minimum] ] ] ] |
|---|
| 193 | |
|---|
| 194 | // fill out data with some plausible defaults: |
|---|
| 195 | // 10800 3600 604800 3600 |
|---|
| 196 | data.serial=0; |
|---|
| 197 | data.refresh=::arg().asNum("soa-refresh-default"); |
|---|
| 198 | data.retry=::arg().asNum("soa-retry-default"); |
|---|
| 199 | data.expire=::arg().asNum("soa-expire-default"); |
|---|
| 200 | data.default_ttl=::arg().asNum("soa-minimum-ttl"); |
|---|
| 201 | |
|---|
| 202 | vector<string>parts; |
|---|
| 203 | stringtok(parts,content); |
|---|
| 204 | int pleft=parts.size(); |
|---|
| 205 | |
|---|
| 206 | // cout<<"'"<<content<<"'"<<endl; |
|---|
| 207 | |
|---|
| 208 | if(pleft) |
|---|
| 209 | data.nameserver=parts[0]; |
|---|
| 210 | |
|---|
| 211 | if(pleft>1) |
|---|
| 212 | data.hostmaster=attodot(parts[1]); // ahu@ds9a.nl -> ahu.ds9a.nl, piet.puk@ds9a.nl -> piet\.puk.ds9a.nl |
|---|
| 213 | |
|---|
| 214 | if(pleft>2) |
|---|
| 215 | data.serial=strtoul(parts[2].c_str(), NULL, 10); |
|---|
| 216 | |
|---|
| 217 | if(pleft>3) |
|---|
| 218 | data.refresh=atoi(parts[3].c_str()); |
|---|
| 219 | |
|---|
| 220 | if(pleft>4) |
|---|
| 221 | data.retry=atoi(parts[4].c_str()); |
|---|
| 222 | |
|---|
| 223 | if(pleft>5) |
|---|
| 224 | data.expire=atoi(parts[5].c_str()); |
|---|
| 225 | |
|---|
| 226 | if(pleft>6) |
|---|
| 227 | data.default_ttl=atoi(parts[6].c_str()); |
|---|
| 228 | |
|---|
| 229 | } |
|---|
| 230 | |
|---|
| 231 | string serializeSOAData(const SOAData &d) |
|---|
| 232 | { |
|---|
| 233 | ostringstream o; |
|---|
| 234 | // nameservername hostmaster serial-number [refresh [retry [expire [ minimum] ] ] ] |
|---|
| 235 | o<<d.nameserver<<" "<< d.hostmaster <<" "<< d.serial <<" "<< d.refresh << " "<< d.retry << " "<< d.expire << " "<< d.default_ttl; |
|---|
| 236 | |
|---|
| 237 | return o.str(); |
|---|
| 238 | } |
|---|
| 239 | |
|---|
| 240 | |
|---|
| 241 | static int rrcomp(const DNSResourceRecord &A, const DNSResourceRecord &B) |
|---|
| 242 | { |
|---|
| 243 | if(A.d_place<B.d_place) |
|---|
| 244 | return 1; |
|---|
| 245 | |
|---|
| 246 | return 0; |
|---|
| 247 | } |
|---|
| 248 | |
|---|
| 249 | vector<DNSResourceRecord*> DNSPacket::getAPRecords() |
|---|
| 250 | { |
|---|
| 251 | vector<DNSResourceRecord*> arrs; |
|---|
| 252 | |
|---|
| 253 | for(vector<DNSResourceRecord>::iterator i=d_rrs.begin(); |
|---|
| 254 | i!=d_rrs.end(); |
|---|
| 255 | ++i) |
|---|
| 256 | { |
|---|
| 257 | if(i->d_place!=DNSResourceRecord::ADDITIONAL && |
|---|
| 258 | (i->qtype.getCode()==15 || |
|---|
| 259 | i->qtype.getCode()==2 )) // CNAME or MX or NS |
|---|
| 260 | { |
|---|
| 261 | arrs.push_back(&*i); |
|---|
| 262 | } |
|---|
| 263 | } |
|---|
| 264 | |
|---|
| 265 | return arrs; |
|---|
| 266 | |
|---|
| 267 | } |
|---|
| 268 | |
|---|
| 269 | vector<DNSResourceRecord*> DNSPacket::getAnswerRecords() |
|---|
| 270 | { |
|---|
| 271 | vector<DNSResourceRecord*> arrs; |
|---|
| 272 | |
|---|
| 273 | for(vector<DNSResourceRecord>::iterator i=d_rrs.begin(); |
|---|
| 274 | i!=d_rrs.end(); |
|---|
| 275 | ++i) |
|---|
| 276 | { |
|---|
| 277 | if(i->d_place!=DNSResourceRecord::ADDITIONAL) |
|---|
| 278 | arrs.push_back(&*i); |
|---|
| 279 | } |
|---|
| 280 | return arrs; |
|---|
| 281 | } |
|---|
| 282 | |
|---|
| 283 | |
|---|
| 284 | void DNSPacket::setCompress(bool compress) |
|---|
| 285 | { |
|---|
| 286 | d_compress=compress; |
|---|
| 287 | stringbuffer.reserve(65000); |
|---|
| 288 | d_rrs.reserve(200); |
|---|
| 289 | } |
|---|
| 290 | |
|---|
| 291 | bool DNSPacket::couldBeCached() |
|---|
| 292 | { |
|---|
| 293 | return d_ednsping.empty() && !d_wantsnsid && qclass==QClass::IN; |
|---|
| 294 | } |
|---|
| 295 | |
|---|
| 296 | /** Must be called before attempting to access getData(). This function stuffs all resource |
|---|
| 297 | * records found in rrs into the data buffer. It also frees resource records queued for us. |
|---|
| 298 | */ |
|---|
| 299 | void DNSPacket::wrapup(void) |
|---|
| 300 | { |
|---|
| 301 | if(d_wrapped) { |
|---|
| 302 | return; |
|---|
| 303 | } |
|---|
| 304 | |
|---|
| 305 | // do embedded-additional processing decapsulation |
|---|
| 306 | DNSResourceRecord rr; |
|---|
| 307 | vector<DNSResourceRecord>::iterator pos; |
|---|
| 308 | |
|---|
| 309 | vector<DNSResourceRecord> additional; |
|---|
| 310 | |
|---|
| 311 | int ipos=d_rrs.size(); |
|---|
| 312 | d_rrs.resize(d_rrs.size()+additional.size()); |
|---|
| 313 | copy(additional.begin(), additional.end(), d_rrs.begin()+ipos); |
|---|
| 314 | |
|---|
| 315 | // we now need to order rrs so that the different sections come at the right place |
|---|
| 316 | // we want a stable sort, based on the d_place field |
|---|
| 317 | |
|---|
| 318 | stable_sort(d_rrs.begin(),d_rrs.end(),rrcomp); |
|---|
| 319 | |
|---|
| 320 | static bool mustShuffle =::arg().mustDo("no-shuffle"); |
|---|
| 321 | |
|---|
| 322 | if(!d_tcp && !mustShuffle) { |
|---|
| 323 | shuffle(d_rrs); |
|---|
| 324 | } |
|---|
| 325 | d_wrapped=true; |
|---|
| 326 | |
|---|
| 327 | vector<uint8_t> packet; |
|---|
| 328 | DNSPacketWriter pw(packet, qdomain, qtype.getCode(), qclass); |
|---|
| 329 | |
|---|
| 330 | pw.getHeader()->rcode=d.rcode; |
|---|
| 331 | pw.getHeader()->aa=d.aa; |
|---|
| 332 | pw.getHeader()->ra=d.ra; |
|---|
| 333 | pw.getHeader()->qr=d.qr; |
|---|
| 334 | pw.getHeader()->id=d.id; |
|---|
| 335 | pw.getHeader()->rd=d.rd; |
|---|
| 336 | |
|---|
| 337 | DNSPacketWriter::optvect_t opts; |
|---|
| 338 | if(d_wantsnsid) { |
|---|
| 339 | opts.push_back(make_pair(3, ::arg()["server-id"])); |
|---|
| 340 | } |
|---|
| 341 | |
|---|
| 342 | if(!d_ednsping.empty()) { |
|---|
| 343 | opts.push_back(make_pair(4, d_ednsping)); |
|---|
| 344 | } |
|---|
| 345 | |
|---|
| 346 | if(!d_rrs.empty() || !opts.empty()) { |
|---|
| 347 | try { |
|---|
| 348 | string signQName, wildcardQName; |
|---|
| 349 | uint16_t signQType=0; |
|---|
| 350 | uint32_t signTTL=0; |
|---|
| 351 | DNSPacketWriter::Place signPlace=DNSPacketWriter::ANSWER; |
|---|
| 352 | vector<shared_ptr<DNSRecordContent> > toSign; |
|---|
| 353 | |
|---|
| 354 | for(pos=d_rrs.begin(); pos < d_rrs.end(); ++pos) { |
|---|
| 355 | // this needs to deal with the 'prio' mismatch! |
|---|
| 356 | if(pos->qtype.getCode()==QType::MX || pos->qtype.getCode() == QType::SRV) { |
|---|
| 357 | pos->content = lexical_cast<string>(pos->priority) + " " + pos->content; |
|---|
| 358 | } |
|---|
| 359 | |
|---|
| 360 | if(!pos->content.empty() && pos->qtype.getCode()==QType::TXT && pos->content[0]!='"') { |
|---|
| 361 | pos->content="\""+pos->content+"\""; |
|---|
| 362 | } |
|---|
| 363 | if(pos->content.empty()) // empty contents confuse the MOADNS setup |
|---|
| 364 | pos->content="."; |
|---|
| 365 | shared_ptr<DNSRecordContent> drc(DNSRecordContent::mastermake(pos->qtype.getCode(), 1, pos->content)); |
|---|
| 366 | |
|---|
| 367 | if(d_dnssecOk) { |
|---|
| 368 | if(pos != d_rrs.begin() && (signQType != pos->qtype.getCode() || signQName != pos->qname)) { |
|---|
| 369 | addSignature(::arg()["key-repository"], signQName, wildcardQName, signQType, signTTL, signPlace, toSign, pw); |
|---|
| 370 | } |
|---|
| 371 | signQName= pos->qname; |
|---|
| 372 | wildcardQName = pos->wildcardname; |
|---|
| 373 | signQType = pos ->qtype.getCode(); |
|---|
| 374 | signTTL = pos->ttl; |
|---|
| 375 | signPlace = (DNSPacketWriter::Place) pos->d_place; |
|---|
| 376 | if(pos->auth) |
|---|
| 377 | toSign.push_back(drc); |
|---|
| 378 | } |
|---|
| 379 | |
|---|
| 380 | pw.startRecord(pos->qname, pos->qtype.getCode(), pos->ttl, pos->qclass, (DNSPacketWriter::Place)pos->d_place); |
|---|
| 381 | |
|---|
| 382 | drc->toPacket(pw); |
|---|
| 383 | |
|---|
| 384 | if(!d_tcp && pw.size() + 20 > getMaxReplyLen()) { |
|---|
| 385 | cerr<<"Truncating!"<<endl; |
|---|
| 386 | pw.rollback(); |
|---|
| 387 | if(pos->d_place == DNSResourceRecord::ANSWER) { |
|---|
| 388 | cerr<<"Set TC bit"<<endl; |
|---|
| 389 | pw.getHeader()->tc=1; |
|---|
| 390 | } |
|---|
| 391 | goto noCommit; |
|---|
| 392 | |
|---|
| 393 | break; |
|---|
| 394 | } |
|---|
| 395 | } |
|---|
| 396 | if(d_dnssecOk && !(d_tcp && d_rrs.rbegin()->qtype.getCode() == QType::SOA && d_rrs.rbegin()->priority == 1234)) { |
|---|
| 397 | // cerr<<"Last signature.. "<<d_tcp<<", "<<d_rrs.rbegin()->priority<<", "<<d_rrs.rbegin()->qtype.getCode()<<", "<< d_rrs.size()<<endl; |
|---|
| 398 | addSignature(::arg()["key-repository"], signQName, wildcardQName, signQType, signTTL, signPlace, toSign, pw); |
|---|
| 399 | } |
|---|
| 400 | |
|---|
| 401 | if(!opts.empty() || d_dnssecOk) |
|---|
| 402 | pw.addOpt(2800, 0, d_dnssecOk ? EDNSOpts::DNSSECOK : 0, opts); |
|---|
| 403 | |
|---|
| 404 | pw.commit(); |
|---|
| 405 | noCommit:; |
|---|
| 406 | } |
|---|
| 407 | catch(std::exception& e) { |
|---|
| 408 | L<<Logger::Warning<<"Exception: "<<e.what()<<endl; |
|---|
| 409 | throw; |
|---|
| 410 | } |
|---|
| 411 | } |
|---|
| 412 | stringbuffer.assign((char*)&packet[0], packet.size()); |
|---|
| 413 | len=packet.size(); |
|---|
| 414 | } |
|---|
| 415 | |
|---|
| 416 | |
|---|
| 417 | /** Truncates a packet that has already been wrapup()-ed, possibly via a call to getData(). Do not call this function |
|---|
| 418 | before having done this - it will possibly break your packet, or crash your program. |
|---|
| 419 | |
|---|
| 420 | This method sets the 'TC' bit in the stringbuffer, and caps the len attributed to new_length. |
|---|
| 421 | */ |
|---|
| 422 | |
|---|
| 423 | void DNSPacket::truncate(int new_length) |
|---|
| 424 | { |
|---|
| 425 | if(new_length>len || !d_wrapped) |
|---|
| 426 | return; |
|---|
| 427 | |
|---|
| 428 | DLOG(L<<Logger::Warning<<"Truncating a packet to "<< remote.toString() <<endl); |
|---|
| 429 | |
|---|
| 430 | len=new_length; |
|---|
| 431 | stringbuffer[2]|=2; // set TC |
|---|
| 432 | } |
|---|
| 433 | |
|---|
| 434 | |
|---|
| 435 | void DNSPacket::setQuestion(int op, const string &qd, int newqtype) |
|---|
| 436 | { |
|---|
| 437 | memset(&d,0,sizeof(d)); |
|---|
| 438 | d.id=Utility::random(); |
|---|
| 439 | d.rd=d.tc=d.aa=false; |
|---|
| 440 | d.qr=false; |
|---|
| 441 | d.qdcount=1; // is htons'ed later on |
|---|
| 442 | d.ancount=d.arcount=d.nscount=0; |
|---|
| 443 | d.opcode=op; |
|---|
| 444 | qdomain=qd; |
|---|
| 445 | qtype=newqtype; |
|---|
| 446 | } |
|---|
| 447 | |
|---|
| 448 | /** convenience function for creating a reply packet from a question packet. Do not forget to delete it after use! */ |
|---|
| 449 | DNSPacket *DNSPacket::replyPacket() const |
|---|
| 450 | { |
|---|
| 451 | DNSPacket *r=new DNSPacket; |
|---|
| 452 | r->setSocket(d_socket); |
|---|
| 453 | |
|---|
| 454 | r->setRemote(&remote); |
|---|
| 455 | r->setAnswer(true); // this implies the allocation of the header |
|---|
| 456 | r->setA(true); // and we are authoritative |
|---|
| 457 | r->setRA(0); // no recursion available |
|---|
| 458 | r->setRD(d.rd); // if you wanted to recurse, answer will say you wanted it (we don't do it) |
|---|
| 459 | r->setID(d.id); |
|---|
| 460 | r->setOpcode(d.opcode); |
|---|
| 461 | |
|---|
| 462 | r->d_dt=d_dt; |
|---|
| 463 | r->d.qdcount=1; |
|---|
| 464 | r->d_tcp = d_tcp; |
|---|
| 465 | r->qdomain = qdomain; |
|---|
| 466 | r->qtype = qtype; |
|---|
| 467 | r->qclass = qclass; |
|---|
| 468 | r->d_maxreplylen = d_maxreplylen; |
|---|
| 469 | r->d_ednsping = d_ednsping; |
|---|
| 470 | r->d_wantsnsid = d_wantsnsid; |
|---|
| 471 | r->d_dnssecOk = d_dnssecOk; |
|---|
| 472 | return r; |
|---|
| 473 | } |
|---|
| 474 | |
|---|
| 475 | void DNSPacket::spoofQuestion(const string &qd) |
|---|
| 476 | { |
|---|
| 477 | string label=simpleCompress(qd); |
|---|
| 478 | for(string::size_type i=0;i<label.size();++i) |
|---|
| 479 | stringbuffer[i+sizeof(d)]=label[i]; |
|---|
| 480 | d_wrapped=true; // if we do this, don't later on wrapup |
|---|
| 481 | } |
|---|
| 482 | |
|---|
| 483 | int DNSPacket::noparse(const char *mesg, int length) |
|---|
| 484 | { |
|---|
| 485 | stringbuffer.assign(mesg,length); |
|---|
| 486 | |
|---|
| 487 | len=length; |
|---|
| 488 | if(length < 12) { |
|---|
| 489 | L << Logger::Warning << "Ignoring packet: too short from " |
|---|
| 490 | << getRemote() << endl; |
|---|
| 491 | return -1; |
|---|
| 492 | } |
|---|
| 493 | d_wantsnsid=false; |
|---|
| 494 | d_ednsping.clear(); |
|---|
| 495 | d_maxreplylen=512; |
|---|
| 496 | memcpy((void *)&d,(const void *)stringbuffer.c_str(),12); |
|---|
| 497 | return 0; |
|---|
| 498 | } |
|---|
| 499 | |
|---|
| 500 | /** This function takes data from the network, possibly received with recvfrom, and parses |
|---|
| 501 | it into our class. Results of calling this function multiple times on one packet are |
|---|
| 502 | unknown. Returns -1 if the packet cannot be parsed. |
|---|
| 503 | */ |
|---|
| 504 | int DNSPacket::parse(const char *mesg, int length) |
|---|
| 505 | try |
|---|
| 506 | { |
|---|
| 507 | stringbuffer.assign(mesg,length); |
|---|
| 508 | |
|---|
| 509 | len=length; |
|---|
| 510 | if(length < 12) { |
|---|
| 511 | L << Logger::Warning << "Ignoring packet: too short from " |
|---|
| 512 | << getRemote() << endl; |
|---|
| 513 | return -1; |
|---|
| 514 | } |
|---|
| 515 | |
|---|
| 516 | MOADNSParser mdp(stringbuffer); |
|---|
| 517 | EDNSOpts edo; |
|---|
| 518 | |
|---|
| 519 | // ANY OPTION WHICH *MIGHT* BE SET DOWN BELOW SHOULD BE CLEARED FIRST! |
|---|
| 520 | |
|---|
| 521 | d_wantsnsid=false; |
|---|
| 522 | d_dnssecOk=false; |
|---|
| 523 | d_ednsping.clear(); |
|---|
| 524 | |
|---|
| 525 | |
|---|
| 526 | if(getEDNSOpts(mdp, &edo)) { |
|---|
| 527 | d_maxreplylen=max(edo.d_packetsize, (uint16_t)1280); |
|---|
| 528 | // cerr<<edo.d_Z<<endl; |
|---|
| 529 | if(edo.d_Z & EDNSOpts::DNSSECOK) |
|---|
| 530 | d_dnssecOk=true; |
|---|
| 531 | |
|---|
| 532 | for(vector<pair<uint16_t, string> >::const_iterator iter = edo.d_options.begin(); |
|---|
| 533 | iter != edo.d_options.end(); |
|---|
| 534 | ++iter) { |
|---|
| 535 | if(iter->first == 3) {// 'EDNS NSID' |
|---|
| 536 | d_wantsnsid=1; |
|---|
| 537 | } |
|---|
| 538 | else if(iter->first == 5) {// 'EDNS PING' |
|---|
| 539 | d_ednsping = iter->second; |
|---|
| 540 | } |
|---|
| 541 | else |
|---|
| 542 | ; // cerr<<"Have an option #"<<iter->first<<endl; |
|---|
| 543 | } |
|---|
| 544 | } |
|---|
| 545 | else { |
|---|
| 546 | d_maxreplylen=512; |
|---|
| 547 | } |
|---|
| 548 | |
|---|
| 549 | memcpy((void *)&d,(const void *)stringbuffer.c_str(),12); |
|---|
| 550 | qdomain=mdp.d_qname; |
|---|
| 551 | if(!qdomain.empty()) // strip dot |
|---|
| 552 | boost::erase_tail(qdomain, 1); |
|---|
| 553 | |
|---|
| 554 | if(!ntohs(d.qdcount)) { |
|---|
| 555 | if(!d_tcp) { |
|---|
| 556 | L << Logger::Warning << "No question section in packet from " << getRemote() <<", rcode="<<(int)d.rcode<<endl; |
|---|
| 557 | return -1; |
|---|
| 558 | } |
|---|
| 559 | } |
|---|
| 560 | |
|---|
| 561 | qtype=mdp.d_qtype; |
|---|
| 562 | qclass=mdp.d_qclass; |
|---|
| 563 | return 0; |
|---|
| 564 | } |
|---|
| 565 | catch(std::exception& e) { |
|---|
| 566 | return -1; |
|---|
| 567 | } |
|---|
| 568 | |
|---|
| 569 | int DNSPacket::getMaxReplyLen() |
|---|
| 570 | { |
|---|
| 571 | return d_maxreplylen; |
|---|
| 572 | } |
|---|
| 573 | |
|---|
| 574 | void DNSPacket::setMaxReplyLen(int bytes) |
|---|
| 575 | { |
|---|
| 576 | d_maxreplylen=bytes; |
|---|
| 577 | } |
|---|
| 578 | |
|---|
| 579 | //! Use this to set where this packet was received from or should be sent to |
|---|
| 580 | void DNSPacket::setRemote(const ComboAddress *s) |
|---|
| 581 | { |
|---|
| 582 | remote=*s; |
|---|
| 583 | } |
|---|
| 584 | |
|---|
| 585 | void DNSPacket::setSocket(Utility::sock_t sock) |
|---|
| 586 | { |
|---|
| 587 | d_socket=sock; |
|---|
| 588 | } |
|---|
| 589 | |
|---|
| 590 | void DNSPacket::commitD() |
|---|
| 591 | { |
|---|
| 592 | stringbuffer.replace(0,12,(char *)&d,12); // copy in d |
|---|
| 593 | } |
|---|
| 594 | |
|---|