]>
Commit | Line | Data |
---|---|---|
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 | ||
29 | extern StatBag S; | |
30 | extern PacketCache PC; | |
31 | ||
32 | DNSProxy::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 | ||
78 | void DNSProxy::go() | |
79 | { | |
80 | pthread_t tid; | |
81 | pthread_create(&tid,0,&launchhelper,this); | |
82 | } | |
83 | ||
84 | ||
85 | void 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 */ | |
96 | bool 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 */ | |
127 | int 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 | ||
146 | void 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 | } |