]>
git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/dnsproxy.cc
3c6fcf8b9b41f902912b844f351fd8454094c4e4
2 PowerDNS Versatile Database Driven Nameserver
3 Copyright (C) 2004 - 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 Additionally, the license of this program contains a special
10 exception which allows to distribute the program in binary form when
11 it is linked against OpenSSL.
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 St, Fifth Floor, Boston, MA 02110-1301 USA
25 #include "packetcache.hh"
27 #include "dnsproxy.hh"
28 #include "pdnsexception.hh"
29 #include <sys/types.h>
37 extern PacketCache PC
;
39 DNSProxy::DNSProxy(const string
&remote
)
41 pthread_mutex_init(&d_lock
,0);
42 d_resanswers
=S
.getPointer("recursing-answers");
43 d_resquestions
=S
.getPointer("recursing-questions");
44 d_udpanswers
=S
.getPointer("udp-answers");
45 ComboAddress
remaddr(remote
, 53);
47 if((d_sock
=socket(remaddr
.sin4
.sin_family
, SOCK_DGRAM
,0))<0)
48 throw PDNSException(string("socket: ")+strerror(errno
));
51 if(remaddr
.sin4
.sin_family
==AF_INET
)
52 local
= ComboAddress("0.0.0.0");
54 local
= ComboAddress("::");
58 local
.sin4
.sin_port
= htons(10000+( Utility::random()%50000));
60 if(::bind(d_sock
, (struct sockaddr
*)&local
, local
.getSocklen()) >= 0)
66 throw PDNSException(string("binding dnsproxy socket: ")+strerror(errno
));
69 if(connect(d_sock
, (sockaddr
*)&remaddr
, remaddr
.getSocklen())<0)
70 throw PDNSException("Unable to UDP connect to remote nameserver "+remaddr
.toStringWithPort()+": "+stringerror());
72 d_xor
=Utility::random()&0xffff;
73 L
<<Logger::Error
<<"DNS Proxy launched, local port "<<ntohs(local
.sin4
.sin_port
)<<", remote "<<remaddr
.toStringWithPort()<<endl
;
79 pthread_create(&tid
,0,&launchhelper
,this);
83 void DNSProxy::onlyFrom(const string
&ips
)
88 bool DNSProxy::recurseFor(DNSPacket
* p
)
90 return d_ng
.match((ComboAddress
*)&p
->d_remote
);
93 /** returns false if p->remote is not allowed to recurse via us */
94 bool DNSProxy::sendPacket(DNSPacket
*p
)
106 ce
.remote
= p
->d_remote
;
107 ce
.outsock
= p
->getSocket();
108 ce
.created
= time( NULL
);
109 ce
.qtype
= p
->qtype
.getCode();
110 ce
.qname
= p
->qdomain
;
111 ce
.anyLocal
= p
->d_anyLocal
;
118 const string
& buffer
= p
->getString();
120 if(send(d_sock
,buffer
.c_str(), buffer
.length() , 0)<0) { // zoom
121 L
<<Logger::Error
<<"Unable to send a packet to our recursing backend: "<<stringerror()<<endl
;
128 //! look up qname aname with r->qtype, plonk it in the answer section of 'r' with name target
129 bool DNSProxy::completePacket(DNSPacket
*r
, const DNSName
& target
,const DNSName
& aname
)
138 ce
.remote
= r
->d_remote
;
139 ce
.outsock
= r
->getSocket();
140 ce
.created
= time( NULL
);
141 ce
.qtype
= r
->qtype
.getCode();
143 ce
.anyLocal
= r
->d_anyLocal
;
149 vector
<uint8_t> packet
;
150 DNSPacketWriter
pw(packet
, target
, r
->qtype
.getCode());
151 pw
.getHeader()->rd
=true;
152 pw
.getHeader()->id
=id
^ d_xor
;
154 if(send(d_sock
,&packet
[0], packet
.size() , 0)<0) { // zoom
155 L
<<Logger::Error
<<"Unable to send a packet to our recursing backend: "<<stringerror()<<endl
;
163 /** This finds us an unused or stale ID. Does not actually clean the contents */
164 int DNSProxy::getID_locked()
168 i
=d_conntrack
.find(n
);
169 if(i
==d_conntrack
.end()) {
172 else if(i
->second
.created
<time(0)-60) {
173 if(i
->second
.created
) {
174 L
<<Logger::Warning
<<"Recursive query for remote "<<
175 i
->second
.remote
.toStringWithPort()<<" with internal id "<<n
<<
176 " was not answered by backend within timeout, reusing id"<<endl
;
177 delete i
->second
.complete
;
178 S
.inc("recursion-unanswered");
185 void DNSProxy::mainloop(void)
196 len
=recv(d_sock
, buffer
, sizeof(buffer
),0); // answer from our backend
197 if(len
<(ssize_t
)sizeof(dnsheader
)) {
199 L
<<Logger::Error
<<"Error receiving packet from recursor backend: "<<stringerror()<<endl
;
201 L
<<Logger::Error
<<"Error receiving packet from recursor backend, EOF"<<endl
;
203 L
<<Logger::Error
<<"Short packet from recursor backend, "<<len
<<" bytes"<<endl
;
210 memcpy(&d
,buffer
,sizeof(d
));
213 #if BYTE_ORDER == BIG_ENDIAN
214 // this is needed because spoof ID down below does not respect the native byteorder
215 d
.id
= ( 256 * (uint16_t)buffer
[1] ) + (uint16_t)buffer
[0];
217 map_t::iterator i
=d_conntrack
.find(d
.id
^d_xor
);
218 if(i
==d_conntrack
.end()) {
219 L
<<Logger::Error
<<"Discarding untracked packet from recursor backend with id "<<(d
.id
^d_xor
)<<
220 ". Conntrack table size="<<d_conntrack
.size()<<endl
;
223 else if(i
->second
.created
==0) {
224 L
<<Logger::Error
<<"Received packet from recursor backend with id "<<(d
.id
^d_xor
)<<" which is a duplicate"<<endl
;
229 memcpy(buffer
,&d
,sizeof(d
)); // commit spoofed id
232 p
.parse(buffer
,(size_t)len
);
233 q
.parse(buffer
,(size_t)len
);
235 if(p
.qtype
.getCode() != i
->second
.qtype
|| p
.qdomain
!= i
->second
.qname
) {
236 L
<<Logger::Error
<<"Discarding packet from recursor backend with id "<<(d
.id
^d_xor
)<<
237 ", qname or qtype mismatch ("<<p
.qtype
.getCode()<<" v " <<i
->second
.qtype
<<", "<<p
.qdomain
<<" v "<<i
->second
.qname
<<")"<<endl
;
241 /* Set up iov and msgh structures. */
242 memset(&msgh
, 0, sizeof(struct msghdr
));
243 string reply
; // needs to be alive at time of sendmsg!
244 if(i
->second
.complete
) {
246 MOADNSParser
mdp(p
.getString());
247 // cerr<<"Got completion, "<<mdp.d_answers.size()<<" answers, rcode: "<<mdp.d_header.rcode<<endl;
248 for(MOADNSParser::answers_t::const_iterator j
=mdp
.d_answers
.begin(); j
!=mdp
.d_answers
.end(); ++j
) {
249 // cerr<<"comp: "<<(int)j->first.d_place-1<<" "<<j->first.d_label<<" " << DNSRecordContent::NumberToType(j->first.d_type)<<" "<<j->first.d_content->getZoneRepresentation()<<endl;
250 if(j
->first
.d_place
== DNSResourceRecord::ANSWER
|| (j
->first
.d_place
== DNSResourceRecord::AUTHORITY
&& j
->first
.d_type
== QType::SOA
)) {
252 DNSResourceRecord rr
;
254 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
))) {
255 rr
.qname
=i
->second
.aname
;
256 rr
.qtype
= j
->first
.d_type
;
257 rr
.ttl
=j
->first
.d_ttl
;
258 rr
.d_place
= j
->first
.d_place
;
259 rr
.content
=j
->first
.d_content
->getZoneRepresentation();
260 i
->second
.complete
->addRecord(rr
);
264 i
->second
.complete
->setRcode(mdp
.d_header
.rcode
);
265 reply
=i
->second
.complete
->getString();
266 iov
.iov_base
= (void*)reply
.c_str();
267 iov
.iov_len
= reply
.length();
268 delete i
->second
.complete
;
269 i
->second
.complete
=0;
272 iov
.iov_base
= buffer
;
277 msgh
.msg_name
= (struct sockaddr
*)&i
->second
.remote
;
278 msgh
.msg_namelen
= i
->second
.remote
.getSocklen();
279 msgh
.msg_control
=NULL
;
281 if(i
->second
.anyLocal
) {
282 addCMsgSrcAddr(&msgh
, cbuf
, i
->second
.anyLocal
.get_ptr(), 0);
284 if(sendmsg(i
->second
.outsock
, &msgh
, 0) < 0)
285 L
<<Logger::Warning
<<"dnsproxy.cc: Error sending reply with sendmsg (socket="<<i
->second
.outsock
<<"): "<<strerror(errno
)<<endl
;
287 PC
.insert(&q
, &p
, true);
292 catch(PDNSException
&ae
) {
293 L
<<Logger::Error
<<"Fatal error in DNS proxy: "<<ae
.reason
<<endl
;
295 catch(std::exception
&e
) {
296 L
<<Logger::Error
<<"Communicator thread died because of STL error: "<<e
.what()<<endl
;
300 L
<< Logger::Error
<< "Caught unknown exception." << endl
;
302 L
<<Logger::Error
<<"Exiting because DNS proxy failed"<<endl
;
306 DNSProxy::~DNSProxy() {
307 if (d_sock
>-1) closesocket(d_sock
);