]>
Commit | Line | Data |
---|---|---|
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 | |
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 | ||
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 | ||
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 | ||
b636533b BH |
95 | bool 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 */ |
101 | bool 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 */ | |
132 | int 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 | ||
151 | void 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 | } |