]>
git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/dnsproxy.cc
2 * This file is part of PowerDNS or dnsdist.
3 * Copyright -- PowerDNS.COM B.V. and its contributors
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.
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.
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.
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.
25 #include "packetcache.hh"
27 #include "dnsproxy.hh"
28 #include "pdnsexception.hh"
29 #include <sys/types.h>
34 #include "dns_random.hh"
38 DNSProxy::DNSProxy(const string
&remote
)
40 pthread_mutex_init(&d_lock
,0);
41 d_resanswers
=S
.getPointer("recursing-answers");
42 d_resquestions
=S
.getPointer("recursing-questions");
43 d_udpanswers
=S
.getPointer("udp-answers");
45 vector
<string
> addresses
;
46 stringtok(addresses
, remote
, " ,\t");
47 d_remote
= ComboAddress(addresses
[0], 53);
49 if((d_sock
=socket(d_remote
.sin4
.sin_family
, SOCK_DGRAM
,0))<0) {
50 throw PDNSException(string("socket: ")+strerror(errno
));
54 if(d_remote
.sin4
.sin_family
==AF_INET
) {
55 local
= ComboAddress("0.0.0.0");
58 local
= ComboAddress("::");
63 local
.sin4
.sin_port
= htons(10000+dns_random(50000));
65 if(::bind(d_sock
, (struct sockaddr
*)&local
, local
.getSocklen()) >= 0)
71 throw PDNSException(string("binding dnsproxy socket: ")+strerror(errno
));
74 if(connect(d_sock
, (sockaddr
*)&d_remote
, d_remote
.getSocklen())<0) {
75 throw PDNSException("Unable to UDP connect to remote nameserver "+d_remote
.toStringWithPort()+": "+stringerror());
78 d_xor
=dns_random(0xffff);
79 L
<<Logger::Error
<<"DNS Proxy launched, local port "<<ntohs(local
.sin4
.sin_port
)<<", remote "<<d_remote
.toStringWithPort()<<endl
;
85 pthread_create(&tid
,0,&launchhelper
,this);
88 /** returns false if p->remote is not allowed to recurse via us */
89 bool DNSProxy::sendPacket(DNSPacket
*p
)
98 ce
.remote
= p
->d_remote
;
99 ce
.outsock
= p
->getSocket();
100 ce
.created
= time( NULL
);
101 ce
.qtype
= p
->qtype
.getCode();
102 ce
.qname
= p
->qdomain
;
103 ce
.anyLocal
= p
->d_anyLocal
;
110 const string
& buffer
= p
->getString();
112 if(send(d_sock
,buffer
.c_str(), buffer
.length() , 0)<0) { // zoom
113 L
<<Logger::Error
<<"Unable to send a packet to our recursing backend: "<<stringerror()<<endl
;
120 //! look up qname aname with r->qtype, plonk it in the answer section of 'r' with name target
121 bool DNSProxy::completePacket(DNSPacket
*r
, const DNSName
& target
,const DNSName
& aname
)
130 ce
.remote
= r
->d_remote
;
131 ce
.outsock
= r
->getSocket();
132 ce
.created
= time( NULL
);
133 ce
.qtype
= r
->qtype
.getCode();
135 ce
.anyLocal
= r
->d_anyLocal
;
141 vector
<uint8_t> packet
;
142 DNSPacketWriter
pw(packet
, target
, r
->qtype
.getCode());
143 pw
.getHeader()->rd
=true;
144 pw
.getHeader()->id
=id
^ d_xor
;
146 if(send(d_sock
,&packet
[0], packet
.size() , 0)<0) { // zoom
147 L
<<Logger::Error
<<"Unable to send a packet to our recursing backend: "<<stringerror()<<endl
;
155 /** This finds us an unused or stale ID. Does not actually clean the contents */
156 int DNSProxy::getID_locked()
160 i
=d_conntrack
.find(n
);
161 if(i
==d_conntrack
.end()) {
164 else if(i
->second
.created
<time(0)-60) {
165 if(i
->second
.created
) {
166 L
<<Logger::Warning
<<"Recursive query for remote "<<
167 i
->second
.remote
.toStringWithPort()<<" with internal id "<<n
<<
168 " was not answered by backend within timeout, reusing id"<<endl
;
169 delete i
->second
.complete
;
170 S
.inc("recursion-unanswered");
177 void DNSProxy::mainloop(void)
186 ComboAddress fromaddr
;
189 socklen_t fromaddrSize
= sizeof(fromaddr
);
190 len
=recvfrom(d_sock
, buffer
, sizeof(buffer
),0, (struct sockaddr
*) &fromaddr
, &fromaddrSize
); // answer from our backend
191 if(len
<(ssize_t
)sizeof(dnsheader
)) {
193 L
<<Logger::Error
<<"Error receiving packet from recursor backend: "<<stringerror()<<endl
;
195 L
<<Logger::Error
<<"Error receiving packet from recursor backend, EOF"<<endl
;
197 L
<<Logger::Error
<<"Short packet from recursor backend, "<<len
<<" bytes"<<endl
;
201 if (fromaddr
!= d_remote
) {
202 L
<<Logger::Error
<<"Got answer from unexpected host "<<fromaddr
.toStringWithPort()<<" instead of our recursor backend "<<d_remote
.toStringWithPort()<<endl
;
208 memcpy(&d
,buffer
,sizeof(d
));
211 #if BYTE_ORDER == BIG_ENDIAN
212 // this is needed because spoof ID down below does not respect the native byteorder
213 d
.id
= ( 256 * (uint16_t)buffer
[1] ) + (uint16_t)buffer
[0];
215 map_t::iterator i
=d_conntrack
.find(d
.id
^d_xor
);
216 if(i
==d_conntrack
.end()) {
217 L
<<Logger::Error
<<"Discarding untracked packet from recursor backend with id "<<(d
.id
^d_xor
)<<
218 ". Conntrack table size="<<d_conntrack
.size()<<endl
;
221 else if(i
->second
.created
==0) {
222 L
<<Logger::Error
<<"Received packet from recursor backend with id "<<(d
.id
^d_xor
)<<" which is a duplicate"<<endl
;
227 memcpy(buffer
,&d
,sizeof(d
)); // commit spoofed id
229 DNSPacket
p(false),q(false);
230 p
.parse(buffer
,(size_t)len
);
231 q
.parse(buffer
,(size_t)len
);
233 if(p
.qtype
.getCode() != i
->second
.qtype
|| p
.qdomain
!= i
->second
.qname
) {
234 L
<<Logger::Error
<<"Discarding packet from recursor backend with id "<<(d
.id
^d_xor
)<<
235 ", qname or qtype mismatch ("<<p
.qtype
.getCode()<<" v " <<i
->second
.qtype
<<", "<<p
.qdomain
<<" v "<<i
->second
.qname
<<")"<<endl
;
239 /* Set up iov and msgh structures. */
240 memset(&msgh
, 0, sizeof(struct msghdr
));
241 string reply
; // needs to be alive at time of sendmsg!
242 if(i
->second
.complete
) {
244 MOADNSParser
mdp(false, p
.getString());
245 // cerr<<"Got completion, "<<mdp.d_answers.size()<<" answers, rcode: "<<mdp.d_header.rcode<<endl;
246 for(MOADNSParser::answers_t::const_iterator j
=mdp
.d_answers
.begin(); j
!=mdp
.d_answers
.end(); ++j
) {
247 // cerr<<"comp: "<<(int)j->first.d_place-1<<" "<<j->first.d_label<<" " << DNSRecordContent::NumberToType(j->first.d_type)<<" "<<j->first.d_content->getZoneRepresentation()<<endl;
248 if(j
->first
.d_place
== DNSResourceRecord::ANSWER
|| (j
->first
.d_place
== DNSResourceRecord::AUTHORITY
&& j
->first
.d_type
== QType::SOA
)) {
250 if(j
->first
.d_type
== i
->second
.qtype
|| (i
->second
.qtype
== QType::ANY
&& (j
->first
.d_type
== QType::A
|| j
->first
.d_type
== QType::AAAA
))) {
252 dzr
.dr
.d_name
=i
->second
.aname
;
253 dzr
.dr
.d_type
= j
->first
.d_type
;
254 dzr
.dr
.d_ttl
=j
->first
.d_ttl
;
255 dzr
.dr
.d_place
= j
->first
.d_place
;
256 dzr
.dr
.d_content
=j
->first
.d_content
;
257 i
->second
.complete
->addRecord(dzr
);
261 i
->second
.complete
->setRcode(mdp
.d_header
.rcode
);
262 reply
=i
->second
.complete
->getString();
263 iov
.iov_base
= (void*)reply
.c_str();
264 iov
.iov_len
= reply
.length();
265 delete i
->second
.complete
;
266 i
->second
.complete
=0;
269 iov
.iov_base
= buffer
;
274 msgh
.msg_name
= (struct sockaddr
*)&i
->second
.remote
;
275 msgh
.msg_namelen
= i
->second
.remote
.getSocklen();
276 msgh
.msg_control
=NULL
;
278 if(i
->second
.anyLocal
) {
279 addCMsgSrcAddr(&msgh
, cbuf
, i
->second
.anyLocal
.get_ptr(), 0);
281 if(sendmsg(i
->second
.outsock
, &msgh
, 0) < 0)
282 L
<<Logger::Warning
<<"dnsproxy.cc: Error sending reply with sendmsg (socket="<<i
->second
.outsock
<<"): "<<strerror(errno
)<<endl
;
288 catch(PDNSException
&ae
) {
289 L
<<Logger::Error
<<"Fatal error in DNS proxy: "<<ae
.reason
<<endl
;
291 catch(std::exception
&e
) {
292 L
<<Logger::Error
<<"Communicator thread died because of STL error: "<<e
.what()<<endl
;
296 L
<< Logger::Error
<< "Caught unknown exception." << endl
;
298 L
<<Logger::Error
<<"Exiting because DNS proxy failed"<<endl
;
302 DNSProxy::~DNSProxy() {
307 catch(const PDNSException
& e
) {