]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/dnsproxy.cc
dnsproxy.cc and nameserver.cc use addCMsgSrcAddr() to add a source address control...
[thirdparty/pdns.git] / pdns / dnsproxy.cc
CommitLineData
12c86877
BH
1/*
2 PowerDNS Versatile Database Driven Nameserver
379ab445 3 Copyright (C) 2004 - 2008 PowerDNS.COM BV
12c86877
BH
4
5 This program is free software; you can redistribute it and/or modify
a899e13a
BH
6 it under the terms of the GNU General Public License version 2 as
7 published by the Free Software Foundation;
12c86877 8
f782fe38
MH
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.
12
12c86877
BH
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.
17
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
06bd9ccf 20 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
12c86877 21*/
379ab445 22#include "packetcache.hh"
b636533b 23#include "utility.hh"
12c86877 24#include "dnsproxy.hh"
5c409fa2 25#include "pdnsexception.hh"
12c86877
BH
26#include <sys/types.h>
27#include <errno.h>
28#include "dns.hh"
29#include "logger.hh"
30#include "statbag.hh"
379ab445 31
12c86877
BH
32
33extern StatBag S;
34extern PacketCache PC;
35
36DNSProxy::DNSProxy(const string &remote)
37{
12c86877
BH
38 pthread_mutex_init(&d_lock,0);
39 d_resanswers=S.getPointer("recursing-answers");
40 d_resquestions=S.getPointer("recursing-questions");
41 d_udpanswers=S.getPointer("udp-answers");
c0cc6559
BH
42 ComboAddress remaddr(remote, 53);
43
44 if((d_sock=socket(remaddr.sin4.sin_family, SOCK_DGRAM,0))<0)
3f81d239 45 throw PDNSException(string("socket: ")+strerror(errno));
12c86877 46
c0cc6559
BH
47 ComboAddress local;
48 if(remaddr.sin4.sin_family==AF_INET)
49 local = ComboAddress("0.0.0.0");
50 else
51 local = ComboAddress("::");
52
12c86877
BH
53 int n=0;
54 for(;n<10;n++) {
c0cc6559 55 local.sin4.sin_port = htons(10000+( Utility::random()%50000));
12c86877 56
c0cc6559 57 if(::bind(d_sock, (struct sockaddr *)&local, local.getSocklen()) >= 0)
12c86877
BH
58 break;
59 }
60 if(n==10) {
61 Utility::closesocket(d_sock);
62 d_sock=-1;
3f81d239 63 throw PDNSException(string("binding dnsproxy socket: ")+strerror(errno));
12c86877
BH
64 }
65
c0cc6559 66 if(connect(d_sock, (sockaddr *)&remaddr, remaddr.getSocklen())<0)
3f81d239 67 throw PDNSException("Unable to UDP connect to remote nameserver "+remaddr.toStringWithPort()+": "+stringerror());
12c86877
BH
68
69 d_xor=Utility::random()&0xffff;
c0cc6559 70 L<<Logger::Error<<"DNS Proxy launched, local port "<<ntohs(local.sin4.sin_port)<<", remote "<<remaddr.toStringWithPort()<<endl;
12c86877
BH
71}
72
73void DNSProxy::go()
74{
75 pthread_t tid;
76 pthread_create(&tid,0,&launchhelper,this);
77}
78
79
80void DNSProxy::onlyFrom(const string &ips)
81{
82 vector<string>parts;
83 stringtok(parts,ips,", \t");
84 for(vector<string>::const_iterator i=parts.begin();
85 i!=parts.end();++i)
86 d_ng.addMask(*i);
87
88}
89
b636533b
BH
90bool DNSProxy::recurseFor(DNSPacket* p)
91{
d06799d4 92 return d_ng.match((ComboAddress *)&p->d_remote);
b636533b
BH
93}
94
12c86877
BH
95/** returns false if p->remote is not allowed to recurse via us */
96bool DNSProxy::sendPacket(DNSPacket *p)
97{
b636533b 98 if(!recurseFor(p))
12c86877
BH
99 return false;
100
092f210a 101 uint16_t id;
12c86877
BH
102 {
103 Lock l(&d_lock);
104 id=getID_locked();
105
106 ConntrackEntry ce;
107 ce.id = p->d.id;
d06799d4 108 ce.remote = p->d_remote;
12c86877
BH
109 ce.outsock = p->getSocket();
110 ce.created = time( NULL );
7de6b0d5
BH
111 ce.qtype = p->qtype.getCode();
112 ce.qname = p->qdomain;
f5310162 113 ce.anyLocal = p->d_anyLocal;
12c86877
BH
114 d_conntrack[id]=ce;
115 }
bb0bbdc2
BH
116 p->d.id=id^d_xor;
117 p->commitD();
3f45f34d
BH
118
119 const string& buffer = p->getString();
120
121 if(send(d_sock,buffer.c_str(), buffer.length() , 0)<0) { // zoom
12c86877
BH
122 L<<Logger::Error<<"Unable to send a packet to our recursing backend: "<<stringerror()<<endl;
123 }
124 (*d_resquestions)++;
125 return true;
126
127}
128/** This finds us an unused or stale ID. Does not actually clean the contents */
129int DNSProxy::getID_locked()
130{
131 map_t::iterator i;
132 for(int n=0;;++n) {
133 i=d_conntrack.find(n);
134 if(i==d_conntrack.end()) {
135 return n;
136 }
137 else if(i->second.created<time(0)-60) {
138 if(i->second.created)
4957a608 139 L<<Logger::Warning<<"Recursive query for remote "<<
85db02c5 140 i->second.remote.toStringWithPort()<<" with internal id "<<n<<
4957a608 141 " was not answered by backend within timeout, reusing id"<<endl;
12c86877
BH
142
143 return n;
144 }
145 }
146}
147
148void DNSProxy::mainloop(void)
149{
150 try {
151 char buffer[1500];
152 int len;
153
65d8e171
KN
154 struct msghdr msgh;
155 struct iovec iov;
156 char cbuf[256];
157
12c86877
BH
158 for(;;) {
159 len=recv(d_sock, buffer, sizeof(buffer),0); // answer from our backend
160 if(len<12) {
4957a608
BH
161 if(len<0)
162 L<<Logger::Error<<"Error receiving packet from recursor backend: "<<stringerror()<<endl;
163 else if(len==0)
164 L<<Logger::Error<<"Error receiving packet from recursor backend, EOF"<<endl;
165 else
166 L<<Logger::Error<<"Short packet from recursor backend, "<<len<<" bytes"<<endl;
167
168 continue;
12c86877
BH
169 }
170 (*d_resanswers)++;
171 (*d_udpanswers)++;
88c1bc50 172 dnsheader d;
caa6eefa 173 memcpy(&d,buffer,sizeof(d));
12c86877 174 {
4957a608 175 Lock l(&d_lock);
a899e13a 176#ifdef WORDS_BIGENDIAN
4957a608
BH
177 // this is needed because spoof ID down below does not respect the native byteorder
178 d.id = ( 256 * (uint16_t)buffer[1] ) + (uint16_t)buffer[0];
a899e13a 179#endif
4957a608
BH
180 map_t::iterator i=d_conntrack.find(d.id^d_xor);
181 if(i==d_conntrack.end()) {
182 L<<Logger::Error<<"Discarding untracked packet from recursor backend with id "<<(d.id^d_xor)<<
abc1d928 183 ". Conntrack table size="<<d_conntrack.size()<<endl;
4957a608
BH
184 continue;
185 }
186 else if(i->second.created==0) {
187 L<<Logger::Error<<"Received packet from recursor backend with id "<<(d.id^d_xor)<<" which is a duplicate"<<endl;
188 continue;
189 }
190 d.id=i->second.id;
191 memcpy(buffer,&d,sizeof(d)); // commit spoofed id
192
4957a608
BH
193 DNSPacket p,q;
194 p.parse(buffer,len);
195 q.parse(buffer,len);
7de6b0d5
BH
196
197 if(p.qtype.getCode() != i->second.qtype || p.qdomain != i->second.qname) {
198 L<<Logger::Error<<"Discarding packet from recursor backend with id "<<(d.id^d_xor)<<
199 ", qname or qtype mismatch"<<endl;
200 continue;
201 }
f5310162 202
65d8e171
KN
203 /* Set up iov and msgh structures. */
204 memset(&msgh, 0, sizeof(struct msghdr));
205 iov.iov_base = buffer;
206 iov.iov_len = len;
207 msgh.msg_iov = &iov;
208 msgh.msg_iovlen = 1;
209 msgh.msg_name = (struct sockaddr*)&i->second.remote;
210 msgh.msg_namelen = i->second.remote.getSocklen();
211
212 if(i->second.anyLocal) {
213 addCMsgSrcAddr(&msgh, cbuf, i->second.anyLocal.get_ptr());
f5310162 214 }
65d8e171 215 sendmsg(i->second.outsock, &msgh, 0);
4957a608
BH
216
217 PC.insert(&q, &p);
218 i->second.created=0;
12c86877
BH
219 }
220 }
221 }
3f81d239 222 catch(PDNSException &ae) {
12c86877
BH
223 L<<Logger::Error<<"Fatal error in DNS proxy: "<<ae.reason<<endl;
224 }
adc10f99 225 catch(std::exception &e) {
12c86877
BH
226 L<<Logger::Error<<"Communicator thread died because of STL error: "<<e.what()<<endl;
227 }
228 catch( ... )
229 {
230 L << Logger::Error << "Caught unknown exception." << endl;
231 }
232 L<<Logger::Error<<"Exiting because DNS proxy failed"<<endl;
233 exit(1);
234}