]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/dnsproxy.cc
recursor work, alignment issues
[thirdparty/pdns.git] / pdns / dnsproxy.cc
CommitLineData
12c86877
BH
1/*
2 PowerDNS Versatile Database Driven Nameserver
3 Copyright (C) 2002 PowerDNS.COM BV
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18*/
19#include "utility.hh"\r
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"
27#include "packetcache.hh"
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
54 if(bind(d_sock, (struct sockaddr *)&sin, sizeof(sin)) >= 0)
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
95/** returns false if p->remote is not allowed to recurse via us */
96bool DNSProxy::sendPacket(DNSPacket *p)
97{
98 if(!d_ng.empty() && !d_ng.match((struct sockaddr_in *)&p->remote))
99 return false;
100
101 int id;
102 {
103 Lock l(&d_lock);
104 id=getID_locked();
105
106 ConntrackEntry ce;
107 ce.id = p->d.id;
108 memcpy((void *)&ce.remote,(void *)&p->remote, p->d_socklen);
109 ce.addrlen = p->d_socklen;
110 ce.outsock = p->getSocket();
111 ce.created = time( NULL );
112
113 d_conntrack[id]=ce;
114 }
115 p->spoofID(id^d_xor);
116
117 char *buffer=const_cast<char *>(p->getRaw());
118 int len=p->len;
119 if(send(d_sock,buffer,len,0)<0) { // zoom
120 L<<Logger::Error<<"Unable to send a packet to our recursing backend: "<<stringerror()<<endl;
121 }
122 (*d_resquestions)++;
123 return true;
124
125}
126/** This finds us an unused or stale ID. Does not actually clean the contents */
127int DNSProxy::getID_locked()
128{
129 map_t::iterator i;
130 for(int n=0;;++n) {
131 i=d_conntrack.find(n);
132 if(i==d_conntrack.end()) {
133 return n;
134 }
135 else if(i->second.created<time(0)-60) {
136 if(i->second.created)
137 L<<Logger::Warning<<"Recursive query for remote "<<
138 sockAddrToString((struct sockaddr_in *)&i->second.remote, i->second.addrlen)<<" with internal id "<<n<<
139 " was not answered by backend within timeout, reusing id"<<endl;
140
141 return n;
142 }
143 }
144}
145
146void DNSProxy::mainloop(void)
147{
148 try {
149 char buffer[1500];
150 int len;
151
152 for(;;) {
153 len=recv(d_sock, buffer, sizeof(buffer),0); // answer from our backend
154 if(len<12) {
155 if(len<0)
156 L<<Logger::Error<<"Error receiving packet from recursor backend: "<<stringerror()<<endl;
157 else if(len==0)
158 L<<Logger::Error<<"Error receiving packet from recursor backend, EOF"<<endl;
159 else
160 L<<Logger::Error<<"Short packet from recursor backend, "<<len<<" bytes"<<endl;
161
162 continue;
163 }
164 (*d_resanswers)++;
165 (*d_udpanswers)++;
166 DNSPacket::dnsheader *d=reinterpret_cast<DNSPacket::dnsheader *>(buffer);
167 {
168 Lock l(&d_lock);
169 map_t::iterator i=d_conntrack.find(d->id^d_xor);
170 if(i==d_conntrack.end()) {
171 L<<Logger::Error<<"Discarding untracked packet from recursor backend with id "<<(d->id^d_xor)<<
172 ". Contrack table size="<<d_conntrack.size()<<endl;
173 continue;
174 }
175 else if(i->second.created==0) {
176 L<<Logger::Error<<"Received packet from recursor backend with id "<<(d->id^d_xor)<<" which is a duplicate"<<endl;
177 continue;
178 }
179 d->id=i->second.id;
180 sendto(i->second.outsock,buffer,len,0,(struct sockaddr*)&i->second.remote,i->second.addrlen);
181
182 DNSPacket p,q;
183 p.parse(buffer,len);
184 q.parse(buffer,len);
185
186 PC.insert(&q, &p);
187 i->second.created=0;
188 }
189 }
190 }
191 catch(AhuException &ae) {
192 L<<Logger::Error<<"Fatal error in DNS proxy: "<<ae.reason<<endl;
193 }
194 catch(exception &e) {
195 L<<Logger::Error<<"Communicator thread died because of STL error: "<<e.what()<<endl;
196 }
197 catch( ... )
198 {
199 L << Logger::Error << "Caught unknown exception." << endl;
200 }
201 L<<Logger::Error<<"Exiting because DNS proxy failed"<<endl;
202 exit(1);
203}