root/trunk/pdns/pdns/pdns_recursor.cc @ 129

Revision 129, 10.2 KB (checked in by ahu, 10 years ago)

more work

  • Property svn:eol-style set to native
  • Property svn:keywords set to author date id revision
Line 
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 
20#include <iostream>
21#include <errno.h>
22#include <map>
23#include <set>
24#include <netdb.h>
25#include <stdio.h>
26#include <stdlib.h>
27#include <unistd.h>
28#include "mtasker.hh"
29#include <utility>
30#include "dnspacket.hh"
31#include "statbag.hh"
32#include "arguments.hh"
33#include "syncres.hh"
34
35extern "C" {
36  int sem_init(sem_t*, int, unsigned int){return 0;}
37  int sem_wait(sem_t*){return 0;}
38  int sem_trywait(sem_t*){return 0;}
39  int sem_post(sem_t*){return 0;}
40  int sem_getvalue(sem_t*, int*){return 0;}
41}
42
43StatBag S;
44ArgvMap &arg()
45{
46  static ArgvMap theArg;
47  return theArg;
48}
49int d_clientsock;
50int d_serversock;
51
52struct PacketID
53{
54  u_int16_t id;
55  struct sockaddr_in remote;
56};
57
58bool operator<(const PacketID& a, const PacketID& b)
59{
60  if(a.id<b.id)
61    return true;
62
63  if(a.id==b.id) {
64    if(a.remote.sin_addr.s_addr < b.remote.sin_addr.s_addr)
65      return true;
66    if(a.remote.sin_addr.s_addr == b.remote.sin_addr.s_addr)
67      if(a.remote.sin_port < b.remote.sin_port)
68        return true;
69  }
70
71  return false;
72}
73
74MTasker<PacketID,string> MT(200000);
75
76/* these two functions are used by LWRes */
77int asendto(const char *data, int len, int flags, struct sockaddr *toaddr, int addrlen, int id) 
78{
79  return sendto(d_clientsock, data, len, flags, toaddr, addrlen);
80}
81
82int arecvfrom(char *data, int len, int flags, struct sockaddr *toaddr, socklen_t *addrlen, int *d_len, int id)
83{
84  PacketID pident;
85  pident.id=id;
86  memcpy(&pident.remote,toaddr,sizeof(pident.remote));
87 
88  string packet;
89  if(!MT.waitEvent(pident,&packet,1)) { // timeout
90    return 0; 
91  }
92
93  *d_len=packet.size();
94  memcpy(data,packet.c_str(),min(len,*d_len));
95
96  return 1;
97}
98
99
100typedef map<string,set<DNSResourceRecord> > cache_t;
101cache_t cache;
102int cacheHits, cacheMisses;
103int getCache(const string &qname, const QType& qt, set<DNSResourceRecord>* res)
104{
105  cache_t::const_iterator j=cache.find(toLower(qname)+"|"+qt.getName());
106  if(j!=cache.end() && j->first==toLower(qname)+"|"+qt.getName() && j->second.begin()->ttl>(unsigned int)time(0)) {
107    if(res)
108      *res=j->second;
109    cacheHits++;
110    return (unsigned int)j->second.begin()->ttl-time(0);
111  }
112  cacheMisses++;
113  return -1;
114}
115
116void replaceCache(const string &qname, const QType& qt,  const set<DNSResourceRecord>& content)
117{
118  cache[toLower(qname)+"|"+qt.getName()]=content;
119}
120
121void init(void)
122{
123  // prime root cache
124  static char*ips[]={"198.41.0.4", "128.9.0.107", "192.33.4.12", "128.8.10.90", "192.203.230.10", "192.5.5.241", "192.112.36.4", "128.63.2.53", 
125                     "192.36.148.17","198.41.0.10", "193.0.14.129", "198.32.64.12", "202.12.27.33"};
126  DNSResourceRecord arr, nsrr;
127  arr.qtype=QType::A;
128  arr.ttl=time(0)+3600000;
129  nsrr.qtype=QType::NS;
130  nsrr.ttl=time(0)+3600000;
131 
132  set<DNSResourceRecord>nsset;
133  for(char c='a';c<='m';++c) {
134    static char templ[40];
135    strncpy(templ,"a.root-servers.net", sizeof(templ) - 1);
136    *templ=c;
137    arr.qname=nsrr.content=templ;
138    arr.content=ips[c-'a'];
139    set<DNSResourceRecord>aset;
140    aset.insert(arr);
141    replaceCache(string(templ),QType(QType::A),aset);
142
143    nsset.insert(nsrr);
144  }
145  replaceCache("",QType(QType::NS),nsset);
146}
147
148void startDoResolve(void *p)
149{
150  try {
151    DNSPacket P=*(DNSPacket *)p;
152    delete (DNSPacket *)p;
153   
154    vector<DNSResourceRecord>ret;
155    DNSPacket *R=P.replyPacket();
156    R->setA(false);
157    R->setRA(true);
158
159    SyncRes<LWRes> sr;
160    int res=sr.beginResolve(P.qdomain, P.qtype, ret);
161    if(res<0)
162      R->setRcode(RCode::ServFail);
163    else {
164      R->setRcode(res);
165      for(vector<DNSResourceRecord>::const_iterator i=ret.begin();i!=ret.end();++i)
166        R->addRecord(*i);
167    }
168
169    const char *buffer=R->getData();
170    sendto(d_serversock,buffer,R->len,0,(struct sockaddr *)(R->remote),R->d_socklen);
171    delete R;
172  }
173  catch(AhuException &ae) {
174    cerr<<"startDoResolve problem: "<<ae.reason<<endl;
175  }
176  catch(...) {
177    cerr<<"Any other exception"<<endl;
178  }
179}
180
181void startDoResolveEmbed(void *p)
182{
183  try {
184    DNSPacket P=*(DNSPacket *)p;
185    delete (DNSPacket *)p;
186   
187    vector<DNSResourceRecord>ret;
188    SyncRes<LWRes> sr;
189    int res=sr.beginResolve(P.qdomain, P.qtype, ret);
190    P.setRA(true);
191    P.commitD();
192    string line="P: "+P.qdomain+" "+itoa(P.qtype.getCode())+" "+itoa(P.getSocket())+" "+itoa(P.d.id)+" ";
193    line+=itoa(*(((char*)&P.d)+2))+" "+P.getRemote()+" "+itoa(P.getRemotePort())+" ";
194    if(res<0)
195      line+=itoa(RCode::ServFail)+"\n\n";
196    else {
197      line+=itoa(res)+"\n";
198
199      for(vector<DNSResourceRecord>::const_iterator i=ret.begin();i!=ret.end();++i) {
200        line.append(1,(char)(i->d_place+'0'));
201        line+=i->serialize()+"\n";
202      }
203      line+="\n";
204    }
205    write(d_serversock,line.c_str(),line.size());
206  }
207  catch(AhuException &ae) {
208    cerr<<"startDoResolve problem: "<<ae.reason<<endl;
209  }
210  catch(...) {
211    cerr<<"Any other exception"<<endl;
212  }
213}
214
215void makeClientSocket()
216{
217  d_clientsock=socket(AF_INET, SOCK_DGRAM,0);
218  if(d_clientsock<0) 
219    throw AhuException("Making a socket for resolver: "+stringerror());
220 
221  struct sockaddr_in sin;
222  memset((char *)&sin,0, sizeof(sin));
223 
224  sin.sin_family = AF_INET;
225  sin.sin_addr.s_addr = INADDR_ANY;
226 
227  int tries=10;
228  while(--tries) {
229    u_int16_t port=10000+random()%10000;
230    sin.sin_port = htons(port); 
231   
232    if (bind(d_clientsock, (struct sockaddr *)&sin, sizeof(sin)) >= 0) {
233      cout<<"Outging query source port: "<<port<<endl;
234      break;
235    }
236   
237  }
238  if(!tries)
239    throw AhuException("Resolver binding to local socket: "+stringerror());
240}
241
242void makeServerSocket()
243{
244  d_serversock=socket(AF_INET, SOCK_DGRAM,0);
245  if(d_serversock<0) 
246    throw AhuException("Making a server socket for resolver: "+stringerror());
247 
248  struct sockaddr_in sin;
249  memset((char *)&sin,0, sizeof(sin));
250 
251  sin.sin_family = AF_INET;
252
253  if(arg()["local-address"]=="0.0.0.0") {
254    cerr<<"It is advised to bind to explicit addresses with the --local-address option"<<endl;
255    sin.sin_addr.s_addr = INADDR_ANY;
256  }
257  else {
258    struct hostent *h=0;
259    h=gethostbyname(arg()["local-address"].c_str());
260    if(!h)
261      throw AhuException("Unable to resolve local address"); 
262   
263    sin.sin_addr.s_addr=*(int*)h->h_addr;
264  }
265
266  sin.sin_port = htons(arg().asNum("local-port")); 
267   
268  if (bind(d_serversock, (struct sockaddr *)&sin, sizeof(sin))<0) 
269    throw AhuException("Resolver binding to server socket: "+stringerror());
270  cout<<"Incoming query source port: "<<arg().asNum("local-port")<<endl;
271}
272
273
274int main(int argc, char **argv) 
275{
276#if __GNUC__ >= 3
277    ios_base::sync_with_stdio(false);
278#endif
279
280  try {
281    cout<<"argc="<<argc<<endl;
282    srandom(time(0));
283    arg().set("soa-minimum-ttl","0")="0";
284    arg().set("soa-serial-offset","0")="0";
285    arg().set("local-port","port to listen on")="5300";
286    arg().set("local-address","port to listen on")="0.0.0.0";
287    arg().parse(argc, argv);
288
289    cerr<<"Done priming cache with root hints"<<endl;
290
291   
292    makeClientSocket();
293    makeServerSocket();
294       
295    char data[1500];
296    struct sockaddr_in fromaddr;
297   
298    PacketID pident;
299    init();   
300    int counter=0;
301    for(;;) {
302      while(MT.schedule()); // housekeeping, let threads do their thing
303     
304      socklen_t addrlen=sizeof(fromaddr);
305      int d_len;
306      DNSPacket P;
307     
308      struct timeval tv;
309      tv.tv_sec=0;
310      tv.tv_usec=500000;
311     
312      fd_set readfds;
313      FD_ZERO( &readfds );
314      FD_SET( d_clientsock, &readfds );
315      FD_SET( d_serversock, &readfds );
316      int selret = select( max(d_clientsock,d_serversock) + 1, &readfds, NULL, NULL, &tv );
317      if (selret == -1) 
318          throw AhuException("Select returned: "+stringerror());
319      if(!selret) // nothing happened
320        continue;
321     
322      if(FD_ISSET(d_clientsock,&readfds)) { // do we have a question response?
323        d_len=recvfrom(d_clientsock, data, sizeof(data), 0, (sockaddr *)&fromaddr, &addrlen);   
324        if(d_len<0) {
325          cerr<<"Recvfrom returned error, retrying: "<<strerror(errno)<<endl;
326          continue;
327        }
328       
329        P.setRemote((struct sockaddr *)&fromaddr, addrlen);
330        if(P.parse(data,d_len)<0) {
331          cerr<<"Unparseable packet from "<<P.getRemote()<<endl;
332        }
333        else { 
334          if(P.d.qr) {
335            //      cout<<"answer to a question received"<<endl;
336            //      cout<<"Packet from "<<P.getRemote()<<" with id "<<P.d.id<<": "; cout.flush();
337            pident.remote=fromaddr;
338            pident.id=P.d.id;
339            string *packet=new string;
340            packet->assign(data,d_len);
341            MT.sendEvent(pident,packet);
342          }
343          else 
344            cout<<"Ignoring question on outgoing socket!"<<endl;
345        }
346      }
347     
348      if(FD_ISSET(d_serversock,&readfds)) { // do we have a new question?
349        cout<<"question on the serversock"<<endl;
350
351        d_len=recvfrom(d_serversock, data, sizeof(data), 0, (sockaddr *)&fromaddr, &addrlen);   
352        if(d_len<0) {
353          cerr<<"Recvfrom returned error, retrying: "<<strerror(errno)<<endl;
354          continue;
355        }
356        P.setRemote((struct sockaddr *)&fromaddr, addrlen);
357        if(P.parse(data,d_len)<0) {
358          cerr<<"Unparseable packet from "<<P.getRemote()<<endl;
359        }
360        else { 
361          if(P.d.qr)
362            cout<<"Ignoring answer on server socket!"<<endl;
363          else {
364            cout<<"new question arrived for '"<<P.qdomain<<"|"<<P.qtype.getName()<<"' from "<<P.getRemote()<<endl;
365            MT.makeThread(startDoResolve,(void*)new DNSPacket(P));
366            if(!((counter++)%100)) {
367              cout<<"stats: "<<counter<<" questions, "<<cache.size()<<" cache entries, "<<(cacheHits*100.0)/(cacheHits+cacheMisses)<<"% cache hits"<<endl;
368            }
369          }
370        }
371      }
372    }
373  }
374  catch(AhuException &ae) {
375    cerr<<"Exception: "<<ae.reason<<endl;
376  }
377  catch(exception &e) {
378    cerr<<"STL Exception: "<<e.what()<<endl;
379  }
380  catch(...) {
381    cerr<<"any other exception in main: "<<endl;
382  }
383}
Note: See TracBrowser for help on using the browser.