]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/dnsproxy.cc
rest of the big whitespace/tab cleanup
[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
BH
8
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.
13
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
06bd9ccf 16 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
12c86877 17*/
379ab445 18#include "packetcache.hh"
b636533b 19#include "utility.hh"
12c86877
BH
20#include "dnsproxy.hh"
21#include "ahuexception.hh"
22#include <sys/types.h>
23#include <errno.h>
24#include "dns.hh"
25#include "logger.hh"
26#include "statbag.hh"
379ab445 27
12c86877
BH
28
29extern StatBag S;
30extern PacketCache PC;
31
32DNSProxy::DNSProxy(const string &remote)
33{
34 ServiceTuple st;
35 st.port=53;
36 parseService(remote,st);
37
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");
42 if((d_sock=socket(AF_INET, SOCK_DGRAM,0))<0)
43 throw AhuException(string("socket: ")+strerror(errno));
44
45 struct sockaddr_in sin;
46 memset((char *)&sin, 0, sizeof(sin));
47
48 sin.sin_family = AF_INET;
49 sin.sin_addr.s_addr = INADDR_ANY;
50 int n=0;
51 for(;n<10;n++) {
52 sin.sin_port = htons(10000+( Utility::random()%50000));
53
379ab445 54 if(::bind(d_sock, (struct sockaddr *)&sin, sizeof(sin)) >= 0)
12c86877
BH
55 break;
56 }
57 if(n==10) {
58 Utility::closesocket(d_sock);
59 d_sock=-1;
60 throw AhuException(string("binding dnsproxy socket: ")+strerror(errno));
61 }
62
63 struct sockaddr_in toaddr;
64 struct in_addr inp;
65 Utility::inet_aton(st.host.c_str(),&inp);
66 toaddr.sin_addr.s_addr=inp.s_addr;
67
68 toaddr.sin_port=htons(st.port);
69 toaddr.sin_family=AF_INET;
70
71 if(connect(d_sock, (sockaddr *)&toaddr, sizeof(toaddr))<0)
72 throw AhuException("Unable to UDP connect to remote nameserver "+st.host+" ("+itoa(st.port)+"): "+stringerror());
73
74 d_xor=Utility::random()&0xffff;
75 L<<Logger::Error<<"DNS Proxy launched, local port "<<ntohs(sin.sin_port)<<", remote "<<st.host<<":"<<st.port<<endl;
76}
77
78void DNSProxy::go()
79{
80 pthread_t tid;
81 pthread_create(&tid,0,&launchhelper,this);
82}
83
84
85void DNSProxy::onlyFrom(const string &ips)
86{
87 vector<string>parts;
88 stringtok(parts,ips,", \t");
89 for(vector<string>::const_iterator i=parts.begin();
90 i!=parts.end();++i)
91 d_ng.addMask(*i);
92
93}
94
b636533b
BH
95bool DNSProxy::recurseFor(DNSPacket* p)
96{
809fe23f 97 return d_ng.match((ComboAddress *)&p->remote);
b636533b
BH
98}
99
12c86877
BH
100/** returns false if p->remote is not allowed to recurse via us */
101bool DNSProxy::sendPacket(DNSPacket *p)
102{
b636533b 103 if(!recurseFor(p))
12c86877
BH
104 return false;
105
092f210a 106 uint16_t id;
12c86877
BH
107 {
108 Lock l(&d_lock);
109 id=getID_locked();
110
111 ConntrackEntry ce;
112 ce.id = p->d.id;
2a09f6a1
BH
113 memcpy((void *)&ce.remote,(void *)&p->remote, p->remote.getSocklen());
114 ce.addrlen = p->remote.getSocklen();
12c86877
BH
115 ce.outsock = p->getSocket();
116 ce.created = time( NULL );
117
118 d_conntrack[id]=ce;
119 }
bb0bbdc2
BH
120 p->d.id=id^d_xor;
121 p->commitD();
12c86877
BH
122 char *buffer=const_cast<char *>(p->getRaw());
123 int len=p->len;
124 if(send(d_sock,buffer,len,0)<0) { // zoom
125 L<<Logger::Error<<"Unable to send a packet to our recursing backend: "<<stringerror()<<endl;
126 }
127 (*d_resquestions)++;
128 return true;
129
130}
131/** This finds us an unused or stale ID. Does not actually clean the contents */
132int DNSProxy::getID_locked()
133{
134 map_t::iterator i;
135 for(int n=0;;++n) {
136 i=d_conntrack.find(n);
137 if(i==d_conntrack.end()) {
138 return n;
139 }
140 else if(i->second.created<time(0)-60) {
141 if(i->second.created)
142 L<<Logger::Warning<<"Recursive query for remote "<<
37d3f960 143 sockAddrToString((struct sockaddr_in *)&i->second.remote)<<" with internal id "<<n<<
12c86877
BH
144 " was not answered by backend within timeout, reusing id"<<endl;
145
146 return n;
147 }
148 }
149}
150
151void DNSProxy::mainloop(void)
152{
153 try {
154 char buffer[1500];
155 int len;
156
157 for(;;) {
158 len=recv(d_sock, buffer, sizeof(buffer),0); // answer from our backend
159 if(len<12) {
160 if(len<0)
161 L<<Logger::Error<<"Error receiving packet from recursor backend: "<<stringerror()<<endl;
162 else if(len==0)
163 L<<Logger::Error<<"Error receiving packet from recursor backend, EOF"<<endl;
164 else
165 L<<Logger::Error<<"Short packet from recursor backend, "<<len<<" bytes"<<endl;
166
167 continue;
168 }
169 (*d_resanswers)++;
170 (*d_udpanswers)++;
88c1bc50 171 dnsheader d;
caa6eefa 172 memcpy(&d,buffer,sizeof(d));
12c86877
BH
173 {
174 Lock l(&d_lock);
a899e13a
BH
175#ifdef WORDS_BIGENDIAN
176 // this is needed because spoof ID down below does not respect the native byteorder
092f210a 177 d.id = ( 256 * (uint16_t)buffer[1] ) + (uint16_t)buffer[0];
a899e13a 178#endif
caa6eefa 179 map_t::iterator i=d_conntrack.find(d.id^d_xor);
12c86877 180 if(i==d_conntrack.end()) {
caa6eefa 181 L<<Logger::Error<<"Discarding untracked packet from recursor backend with id "<<(d.id^d_xor)<<
12c86877
BH
182 ". Contrack table size="<<d_conntrack.size()<<endl;
183 continue;
184 }
185 else if(i->second.created==0) {
caa6eefa 186 L<<Logger::Error<<"Received packet from recursor backend with id "<<(d.id^d_xor)<<" which is a duplicate"<<endl;
12c86877
BH
187 continue;
188 }
caa6eefa
BH
189 d.id=i->second.id;
190 memcpy(buffer,&d,sizeof(d)); // commit spoofed id
191
12c86877 192 sendto(i->second.outsock,buffer,len,0,(struct sockaddr*)&i->second.remote,i->second.addrlen);
8e50cd4c 193
12c86877
BH
194 DNSPacket p,q;
195 p.parse(buffer,len);
196 q.parse(buffer,len);
8e50cd4c 197
12c86877
BH
198 PC.insert(&q, &p);
199 i->second.created=0;
200 }
201 }
202 }
203 catch(AhuException &ae) {
204 L<<Logger::Error<<"Fatal error in DNS proxy: "<<ae.reason<<endl;
205 }
adc10f99 206 catch(std::exception &e) {
12c86877
BH
207 L<<Logger::Error<<"Communicator thread died because of STL error: "<<e.what()<<endl;
208 }
209 catch( ... )
210 {
211 L << Logger::Error << "Caught unknown exception." << endl;
212 }
213 L<<Logger::Error<<"Exiting because DNS proxy failed"<<endl;
214 exit(1);
215}