]>
git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/dnspacket.cc
2 PowerDNS Versatile Database Driven Nameserver
3 Copyright (C) 2001 - 2008 PowerDNS.COM BV
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
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.
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
23 #include <sys/types.h>
29 #include <boost/tokenizer.hpp>
30 #include <boost/algorithm/string.hpp>
34 #include "dnsbackend.hh"
35 #include "ahuexception.hh"
36 #include "dnspacket.hh"
38 #include "arguments.hh"
39 #include "dnswriter.hh"
40 #include "dnsparser.hh"
41 #include "dnsrecords.hh"
43 DNSPacket::DNSPacket()
51 string
DNSPacket::getString()
56 const char *DNSPacket::getData(void)
61 return stringbuffer
.data();
64 const char *DNSPacket::getRaw(void)
66 return stringbuffer
.data();
69 string
DNSPacket::getRemote() const
71 return remote
.toString();
74 uint16_t DNSPacket::getRemotePort() const
76 return remote
.sin4
.sin_port
;
79 DNSPacket::DNSPacket(const DNSPacket
&orig
)
81 DLOG(L
<<"DNSPacket copy constructor called!"<<endl
);
82 d_socket
=orig
.d_socket
;
87 d_compress
=orig
.d_compress
;
92 d_maxreplylen
= orig
.d_maxreplylen
;
93 d_ednsping
= orig
.d_ednsping
;
94 d_wantsnsid
= orig
.d_wantsnsid
;
97 d_wrapped
=orig
.d_wrapped
;
99 stringbuffer
=orig
.stringbuffer
;
103 void DNSPacket::setRcode(int v
)
108 void DNSPacket::setAnswer(bool b
)
111 stringbuffer
.assign(12,(char)0);
112 memset((void *)&d
,0,sizeof(d
));
118 void DNSPacket::setA(bool b
)
123 void DNSPacket::setID(uint16_t id
)
128 void DNSPacket::setRA(bool b
)
133 void DNSPacket::setRD(bool b
)
138 void DNSPacket::setOpcode(uint16_t opcode
)
144 void DNSPacket::clearRecords()
149 void DNSPacket::addRecord(const DNSResourceRecord
&rr
)
152 for(vector
<DNSResourceRecord
>::const_iterator i
=rrs
.begin();i
!=rrs
.end();++i
)
153 if(rr
.qname
==i
->qname
&& rr
.qtype
==i
->qtype
&& rr
.content
==i
->content
) {
154 if(rr
.qtype
.getCode()!=QType::MX
&& rr
.qtype
.getCode()!=QType::SRV
)
156 if(rr
.priority
==i
->priority
)
163 // the functions below update the 'arcount' and 'ancount', plus they serialize themselves to the stringbuffer
165 string
& attodot(string
&str
)
167 if(str
.find_first_of("@")==string::npos
)
170 for (unsigned int i
= 0; i
< str
.length(); i
++)
175 } else if (str
[i
] == '.') {
176 str
.insert(i
++, "\\");
183 void fillSOAData(const string
&content
, SOAData
&data
)
185 // content consists of fields separated by spaces:
186 // nameservername hostmaster serial-number [refresh [retry [expire [ minimum] ] ] ]
188 // fill out data with some plausible defaults:
189 // 10800 3600 604800 3600
191 data
.refresh
=::arg().asNum("soa-refresh-default");
192 data
.retry
=::arg().asNum("soa-retry-default");
193 data
.expire
=::arg().asNum("soa-expire-default");
194 data
.default_ttl
=::arg().asNum("soa-minimum-ttl");
197 stringtok(parts
,content
);
198 int pleft
=parts
.size();
200 // cout<<"'"<<content<<"'"<<endl;
203 data
.nameserver
=parts
[0];
206 data
.hostmaster
=attodot(parts
[1]); // ahu@ds9a.nl -> ahu.ds9a.nl, piet.puk@ds9a.nl -> piet\.puk.ds9a.nl
209 data
.serial
=strtoul(parts
[2].c_str(), NULL
, 10);
212 data
.refresh
=atoi(parts
[3].c_str());
215 data
.retry
=atoi(parts
[4].c_str());
218 data
.expire
=atoi(parts
[5].c_str());
221 data
.default_ttl
=atoi(parts
[6].c_str());
225 string
serializeSOAData(const SOAData
&d
)
228 // nameservername hostmaster serial-number [refresh [retry [expire [ minimum] ] ] ]
229 o
<<d
.nameserver
<<" "<< d
.hostmaster
<<" "<< d
.serial
<<" "<< d
.refresh
<< " "<< d
.retry
<< " "<< d
.expire
<< " "<< d
.default_ttl
;
235 static int rrcomp(const DNSResourceRecord
&A
, const DNSResourceRecord
&B
)
237 if(A
.d_place
<B
.d_place
)
243 vector
<DNSResourceRecord
*> DNSPacket::getAPRecords()
245 vector
<DNSResourceRecord
*> arrs
;
247 for(vector
<DNSResourceRecord
>::iterator i
=rrs
.begin();
251 if(i
->d_place
!=DNSResourceRecord::ADDITIONAL
&&
252 (i
->qtype
.getCode()==15 ||
253 i
->qtype
.getCode()==2 )) // CNAME or MX or NS
263 void DNSPacket::setCompress(bool compress
)
266 stringbuffer
.reserve(65000);
270 bool DNSPacket::couldBeCached()
272 return d_ednsping
.empty() && !d_wantsnsid
;
275 /** Must be called before attempting to access getData(). This function stuffs all resource
276 * records found in rrs into the data buffer. It also frees resource records queued for us.
278 void DNSPacket::wrapup(void)
284 // do embedded-additional processing decapsulation
285 DNSResourceRecord rr
;
286 vector
<DNSResourceRecord
>::iterator pos
;
288 vector
<DNSResourceRecord
> additional
;
291 rrs
.resize(rrs
.size()+additional
.size());
292 copy(additional
.begin(), additional
.end(), rrs
.begin()+ipos
);
294 // we now need to order rrs so that the different sections come at the right place
295 // we want a stable sort, based on the d_place field
297 stable_sort(rrs
.begin(),rrs
.end(),rrcomp
);
299 static bool mustShuffle
=::arg().mustDo("no-shuffle");
301 if(!d_tcp
&& !mustShuffle
) {
306 vector
<uint8_t> packet
;
307 DNSPacketWriter
pw(packet
, qdomain
, qtype
.getCode(), 1);
309 pw
.getHeader()->rcode
=d
.rcode
;
310 pw
.getHeader()->aa
=d
.aa
;
311 pw
.getHeader()->ra
=d
.ra
;
312 pw
.getHeader()->qr
=d
.qr
;
313 pw
.getHeader()->id
=d
.id
;
314 pw
.getHeader()->rd
=d
.rd
;
316 DNSPacketWriter::optvect_t opts
;
318 opts
.push_back(make_pair(3, ::arg()["server-id"]));
321 if(!d_ednsping
.empty()) {
322 opts
.push_back(make_pair(4, d_ednsping
));
325 if(!rrs
.empty() || !opts
.empty()) {
327 for(pos
=rrs
.begin(); pos
< rrs
.end(); ++pos
) {
328 // this needs to deal with the 'prio' mismatch!
329 if(pos
->qtype
.getCode()==QType::MX
|| pos
->qtype
.getCode() == QType::SRV
) {
330 pos
->content
= lexical_cast
<string
>(pos
->priority
) + " " + pos
->content
;
332 pw
.startRecord(pos
->qname
, pos
->qtype
.getCode(), pos
->ttl
, 1, (DNSPacketWriter::Place
)pos
->d_place
);
333 if(!pos
->content
.empty() && pos
->qtype
.getCode()==QType::TXT
&& pos
->content
[0]!='"') {
334 pos
->content
="\""+pos
->content
+"\"";
336 if(pos
->content
.empty()) // empty contents confuse the MOADNS setup
338 shared_ptr
<DNSRecordContent
> drc(DNSRecordContent::mastermake(pos
->qtype
.getCode(), 1, pos
->content
));
342 pw
.addOpt(2800, 0, 0, opts
);
346 catch(std::exception
& e
) {
347 L
<<Logger::Warning
<<"Exception: "<<e
.what()<<endl
;
351 stringbuffer
.assign((char*)&packet
[0], packet
.size());
356 /** Truncates a packet that has already been wrapup()-ed, possibly via a call to getData(). Do not call this function
357 before having done this - it will possibly break your packet, or crash your program.
359 This method sets the 'TC' bit in the stringbuffer, and caps the len attributed to new_length.
362 void DNSPacket::truncate(int new_length
)
364 if(new_length
>len
|| !d_wrapped
)
367 DLOG(L
<<Logger::Warning
<<"Truncating a packet to "<< remote
.toString() <<endl
);
370 stringbuffer
[2]|=2; // set TC
374 void DNSPacket::setQuestion(int op
, const string
&qd
, int newqtype
)
376 memset(&d
,0,sizeof(d
));
377 d
.id
=Utility::random();
378 d
.rd
=d
.tc
=d
.aa
=false;
380 d
.qdcount
=1; // is htons'ed later on
381 d
.ancount
=d
.arcount
=d
.nscount
=0;
387 /** convenience function for creating a reply packet from a question packet. Do not forget to delete it after use! */
388 DNSPacket
*DNSPacket::replyPacket() const
390 DNSPacket
*r
=new DNSPacket
;
391 r
->setSocket(d_socket
);
393 r
->setRemote(&remote
);
394 r
->setAnswer(true); // this implies the allocation of the header
395 r
->setA(true); // and we are authoritative
396 r
->setRA(0); // no recursion available
397 r
->setRD(d
.rd
); // if you wanted to recurse, answer will say you wanted it (we don't do it)
399 r
->setOpcode(d
.opcode
);
404 r
->qdomain
= qdomain
;
406 r
->d_maxreplylen
= d_maxreplylen
;
407 r
->d_ednsping
= d_ednsping
;
408 r
->d_wantsnsid
= d_wantsnsid
;
412 void DNSPacket::spoofQuestion(const string
&qd
)
414 string label
=simpleCompress(qd
);
415 for(string::size_type i
=0;i
<label
.size();++i
)
416 stringbuffer
[i
+sizeof(d
)]=label
[i
];
417 d_wrapped
=true; // if we do this, don't later on wrapup
420 int DNSPacket::noparse(const char *mesg
, int length
)
422 stringbuffer
.assign(mesg
,length
);
426 L
<< Logger::Warning
<< "Ignoring packet: too short from "
427 << getRemote() << endl
;
433 memcpy((void *)&d
,(const void *)stringbuffer
.c_str(),12);
437 /** This function takes data from the network, possibly received with recvfrom, and parses
438 it into our class. Results of calling this function multiple times on one packet are
439 unknown. Returns -1 if the packet cannot be parsed.
441 int DNSPacket::parse(const char *mesg
, int length
)
444 stringbuffer
.assign(mesg
,length
);
448 L
<< Logger::Warning
<< "Ignoring packet: too short from "
449 << getRemote() << endl
;
453 MOADNSParser
mdp(stringbuffer
);
456 // ANY OPTION WHICH *MIGHT* BE SET DOWN BELOW SHOULD BE CLEARED FIRST!
461 if(getEDNSOpts(mdp
, &edo
)) {
462 d_maxreplylen
=max(edo
.d_packetsize
, (uint16_t)1280);
464 for(vector
<pair
<uint16_t, string
> >::const_iterator iter
= edo
.d_options
.begin();
465 iter
!= edo
.d_options
.end();
467 if(iter
->first
== 3) {// 'EDNS NSID'
470 else if(iter
->first
== 5) {// 'EDNS PING'
471 d_ednsping
= iter
->second
;
474 ; // cerr<<"Have an option #"<<iter->first<<endl;
481 memcpy((void *)&d
,(const void *)stringbuffer
.c_str(),12);
483 if(!qdomain
.empty()) // strip dot
484 erase_tail(qdomain
, 1);
486 if(!ntohs(d
.qdcount
)) {
488 L
<< Logger::Warning
<< "No question section in packet from " << getRemote() <<", rcode="<<(int)d
.rcode
<<endl
;
497 catch(std::exception
& e
) {
501 int DNSPacket::getMaxReplyLen()
503 return d_maxreplylen
;
506 void DNSPacket::setMaxReplyLen(int bytes
)
511 //! Use this to set where this packet was received from or should be sent to
512 void DNSPacket::setRemote(const ComboAddress
*s
)
517 void DNSPacket::setSocket(Utility::sock_t sock
)
522 void DNSPacket::commitD()
524 stringbuffer
.replace(0,12,(char *)&d
,12); // copy in d