]>
git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/lwres.cc
2 PowerDNS Versatile Database Driven Nameserver
3 Copyright (C) 2002 - 2010 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 "dnsrecords.hh"
33 #include "ahuexception.hh"
34 #include "arguments.hh"
37 #include "dnswriter.hh"
38 #include "dnsparser.hh"
40 #include "dns_random.hh"
41 #include <boost/scoped_array.hpp>
42 #include <boost/algorithm/string.hpp>
44 string
dns0x20 ( const std :: string
& in
)
47 string :: size_type len
= ret
. size ();
48 for ( string :: size_type pos
= 0 ; pos
< len
; ++ pos
) {
49 if ( isalpha ( in
[ pos
]) && dns_random ( 2 ))
52 // cerr<<"'"<<in<<"' -> '"<<ret<<"'\n";
56 //! returns -2 for OS limits error, -1 for permanent error that has to do with remote **transport**, 0 for timeout, 1 for success
57 /** lwr is only filled out in case 1 was returned, and even when returning 1 for 'success', lwr might contain DNS errors
60 int asyncresolve ( const ComboAddress
& ip
, const string
& domain
, int type
, bool doTCP
, bool sendRDQuery
, int EDNS0Level
, struct timeval
* now
, LWResult
* lwr
)
64 scoped_array
< unsigned char > buf ( new unsigned char [ bufsize
]);
65 vector
< uint8_t > vpacket
;
66 // string mapped0x20=dns0x20(domain);
67 DNSPacketWriter
pw ( vpacket
, domain
, type
);
69 pw
. getHeader ()-> rd
= sendRDQuery
;
70 pw
. getHeader ()-> id
= dns_random ( 0xffff );
74 uint32_t nonce
= dns_random ( 0xffffffff );
75 ping
. assign (( char *) & nonce
, 4 );
77 if ( EDNS0Level
&& ! doTCP
) {
78 DNSPacketWriter :: optvect_t opts
;
80 opts
. push_back ( make_pair ( 5 , ping
));
83 pw
. addOpt ( 1200 , 0 , 0 , opts
); // 1200 bytes answer size
87 lwr
-> d_pingCorrect
= false ;
88 lwr
-> d_haveEDNS
= false ;
97 if ( ip
. sin4
. sin_family
== AF_INET6
)
98 g_stats
. ipv6queries
++;
100 if (( ret
= asendto (( const char *)&* vpacket
. begin (), ( int ) vpacket
. size (), 0 , ip
, pw
. getHeader ()-> id
,
101 domain
, type
, & queryfd
)) < 0 ) {
102 return ret
; // passes back the -2 EMFILE
105 // sleep until we see an answer to this, interface to mtasker
107 ret
= arecvfrom ( reinterpret_cast < char *>( buf
. get ()), bufsize
- 1 , 0 , ip
, & len
, pw
. getHeader ()-> id
,
108 domain
, type
, queryfd
, now
);
112 Socket
s (( AddressFamily
) ip
. sin4
. sin_family
, Stream
);
115 ComboAddress local
= getQueryLocalAddress ( ip
. sin4
. sin_family
, 0 );
119 ComboAddress remote
= ip
;
120 remote
. sin4
. sin_port
= htons ( 53 );
123 uint16_t tlen
= htons ( vpacket
. size ());
124 char * lenP
=( char *)& tlen
;
125 const char * msgP
=( const char *)&* vpacket
. begin ();
126 string packet
= string ( lenP
, lenP
+ 2 )+ string ( msgP
, msgP
+ vpacket
. size ());
128 ret
= asendtcp ( packet
, & s
);
133 ret
= arecvtcp ( packet
, 2 , & s
);
137 memcpy (& tlen
, packet
. c_str (), 2 );
138 len
= ntohs ( tlen
); // switch to the 'len' shared with the rest of the function
140 ret
= arecvtcp ( packet
, len
, & s
);
146 scoped_array
< unsigned char > narray ( new unsigned char [ bufsize
]);
149 memcpy ( buf
. get (), packet
. c_str (), len
);
153 catch ( NetworkError
& ne
) {
154 ret
= - 2 ; // OS limits error
159 lwr
-> d_usec
= dt
. udiff ();
160 * now
= dt
. getTimeval ();
162 if ( ret
<= 0 ) // includes 'timeout'
165 lwr
-> d_result
. clear ();
168 MOADNSParser
mdp (( const char *) buf
. get (), len
);
169 lwr
-> d_aabit
= mdp
. d_header
. aa
;
170 lwr
-> d_tcbit
= mdp
. d_header
. tc
;
171 lwr
-> d_rcode
= mdp
. d_header
. rcode
;
173 if ( mdp
. d_header
. rcode
== RCode :: FormErr
&& mdp
. d_qname
. empty () && mdp
. d_qtype
== 0 && mdp
. d_qclass
== 0 ) {
174 return 1 ; // this is "success", the error is set in lwr->d_rcode
177 if (! pdns_iequals ( domain
, mdp
. d_qname
)) {
178 if (! mdp
. d_qname
. empty () && domain
. find (( char ) 0 ) == string :: npos
) { // embedded nulls are too noisy, plus empty domains are too
179 L
<< Logger :: Notice
<< "Packet purporting to come from remote server " << ip
. toString ()<< " contained wrong answer: '" << domain
<< "' != '" << mdp
. d_qname
<< "'" << endl
;
181 // unexpected count has already been done @ pdns_recursor.cc
185 for ( MOADNSParser :: answers_t :: const_iterator i
= mdp
. d_answers
. begin (); i
!= mdp
. d_answers
. end (); ++ i
) {
186 DNSResourceRecord rr
;
188 rr
. qtype
= i
-> first
. d_type
;
189 rr
. qname
= i
-> first
. d_label
;
190 rr
. ttl
= i
-> first
. d_ttl
;
191 rr
. content
= i
-> first
. d_content
-> getZoneRepresentation (); // this should be the serialised form
192 rr
. d_place
=( DNSResourceRecord :: Place
) i
-> first
. d_place
;
193 lwr
-> d_result
. push_back ( rr
);
197 if ( EDNS0Level
> 1 && getEDNSOpts ( mdp
, & edo
)) {
198 lwr
-> d_haveEDNS
= true ;
199 for ( vector
< pair
< uint16_t , string
> >:: const_iterator iter
= edo
. d_options
. begin ();
200 iter
!= edo
. d_options
. end ();
202 if ( iter
-> first
== 5 || iter
-> first
== 4 ) { // 'EDNS PING'
203 if ( iter
-> second
== ping
) {
204 lwr
-> d_pingCorrect
= true ;
212 catch ( std :: exception
& mde
) {
213 if (:: arg (). mustDo ( "log-common-errors" ))
214 L
<< Logger :: Notice
<< "Unable to parse packet from remote server " << ip
. toString ()<< ": " << mde
. what ()<< endl
;
215 lwr
-> d_rcode
= RCode :: FormErr
;
216 g_stats
. serverParseError
++;
217 return 1 ; // success - oddly enough
220 L
<< Logger :: Notice
<< "Unknown error parsing packet from remote server" << endl
;
223 g_stats
. serverParseError
++;
227 lwr
-> d_rcode
= RCode :: ServFail
;