Show
Ignore:
Timestamp:
12/25/09 23:41:13 (3 years ago)
Author:
ahu
Message:

split up overly large pdns_recursor.cc, parts that deal with auth and forwarding now in 'reczones.cc'
remove multithreading from cache, it did not perform
add infrastructure for 'RPC' calls to other threads, for reloading ACLs, Lua Scripts, manipulating the cache etc
fix up ACL reloading and zone reloading

Files:
1 modified

Legend:

Unmodified
Added
Removed
  • trunk/pdns/pdns/pdns_recursor.cc

    r1472 r1473  
    2626 
    2727#include <boost/foreach.hpp> 
     28#include <pthread.h> 
    2829#include "recpacketcache.hh" 
    2930#include "utility.hh"  
     
    7475bool g_logCommonErrors; 
    7576__thread shared_ptr<PowerDNSLua>* t_pdl; 
    76 unsigned int g_luaReloadCounter; 
    77  
    78 RecursorPacketCache g_packetCache; 
     77 
     78struct ThreadPipeSet 
     79{ 
     80  int writeToThread; 
     81  int readToThread; 
     82  int writeFromThread; 
     83  int readFromThread; 
     84}; 
     85 
     86vector<ThreadPipeSet> g_pipes; 
     87 
     88SyncRes::domainmap_t* g_initialDomainMap; 
    7989 
    8090#include "namespaces.hh" 
    8191 
    82 #ifdef __FreeBSD__           // see cvstrac ticket #26 
    83 #include <pthread.h> 
    84 #include <semaphore.h> 
    85 #endif 
    86  
    87  
    88 MemRecursorCache RC; 
     92 
     93__thread MemRecursorCache* t_RC; 
     94static __thread RecursorPacketCache* t_packetCache; 
    8995RecursorStats g_stats; 
    9096bool g_quiet; 
    91 NetmaskGroup* g_allowFrom; 
     97 
     98static __thread NetmaskGroup* t_allowFrom; 
     99static NetmaskGroup* g_initialAllowFrom; // new thread needs to be setup with this 
     100 
    92101NetmaskGroup* g_dontQuery; 
    93102string s_programname="pdns_recursor"; 
     103 
    94104typedef vector<int> tcpListenSockets_t; 
    95105tcpListenSockets_t g_tcpListenSockets;   // shared across threads, but this is fine, never written to from a thread. All threads listen on all sockets 
    96106int g_tcpTimeout; 
    97 //MemcachedCommunicator* g_mc; 
    98 // DHCPCommunicator* g_dc; 
    99107 
    100108map<int, ComboAddress> g_listenSocketsAddresses; // is shared across all threads right now 
     109 
     110#define LOCAL_NETS "127.0.0.0/8, 10.0.0.0/8, 192.168.0.0/16, 172.16.0.0/12, ::1/128, fe80::/10" 
    101111 
    102112struct DNSComboWriter { 
     
    216226  unsigned int d_numsocks; 
    217227  unsigned int d_maxsocks; 
    218   pthread_mutex_t d_lock; 
    219228public: 
    220229  UDPClientSocks() : d_numsocks(0), d_maxsocks(5000) 
    221230  { 
    222     pthread_mutex_init(&d_lock, 0); 
    223231  } 
    224232 
     
    242250    } 
    243251 
    244     Lock l(&d_lock); 
    245  
    246252    d_socks.insert(*fd); 
    247253    d_numsocks++; 
     
    251257  void returnSocket(int fd) 
    252258  { 
    253     Lock l(&d_lock); 
    254259    socks_t::iterator i=d_socks.find(fd); 
    255260    if(i==d_socks.end()) { 
     
    308313    return ret; 
    309314  } 
    310 } g_udpclientsocks; 
     315}; 
     316 
     317static __thread UDPClientSocks* t_udpclientsocks; 
    311318 
    312319 
     
    338345  } 
    339346 
    340   int ret=g_udpclientsocks.getSocket(toaddr, fd); 
     347  int ret=t_udpclientsocks->getSocket(toaddr, fd); 
    341348  if(ret < 0) 
    342349    return ret; 
     
    351358 
    352359  if(ret < 0) 
    353     g_udpclientsocks.returnSocket(*fd); 
     360    t_udpclientsocks->returnSocket(*fd); 
    354361 
    355362  errno = tmp; // this is for logging purposes only 
     
    389396  else { 
    390397    if(fd >= 0) 
    391       g_udpclientsocks.returnSocket(fd); 
     398      t_udpclientsocks->returnSocket(fd); 
    392399  } 
    393400  return ret; 
    394401} 
    395402 
    396 void setBuffer(int fd, int optname, uint32_t size) 
     403void setSocketBuffer(int fd, int optname, uint32_t size) 
    397404{ 
    398405  uint32_t psize=0; 
     
    409416 
    410417 
    411 static void setReceiveBuffer(int fd, uint32_t size) 
    412 { 
    413   setBuffer(fd, SO_RCVBUF, size); 
    414 } 
    415  
    416 static void setSendBuffer(int fd, uint32_t size) 
    417 { 
    418   setBuffer(fd, SO_SNDBUF, size); 
     418static void setSocketReceiveBuffer(int fd, uint32_t size) 
     419{ 
     420  setSocketBuffer(fd, SO_RCVBUF, size); 
     421} 
     422 
     423static void setSocketSendBuffer(int fd, uint32_t size) 
     424{ 
     425  setSocketBuffer(fd, SO_SNDBUF, size); 
    419426} 
    420427 
     
    429436} 
    430437 
    431 void primeHints(void) 
    432 { 
    433   // prime root cache 
    434   set<DNSResourceRecord>nsset; 
    435 #if 0 
    436   { 
    437     time_t now = time(0); 
    438  
    439     string templ; 
    440     DNSResourceRecord arr; 
    441     
    442     arr.qtype=QType::AAAA; 
    443     arr.ttl=now+3600; 
    444     arr.content="::1"; 
    445      
    446     DTime dt; 
    447     dt.set(); 
    448     for(int n = 0 ; n < 500000; ++n) { 
    449       set<DNSResourceRecord> aset; 
    450       arr.qname=templ="blah"+lexical_cast<string>(n)+".testdomain.com"; 
    451       aset.insert(arr); 
    452       RC.replace(now, templ, QType(QType::AAAA), aset, true); // auth, nuke it all 
    453     } 
    454     cerr<<"fill1 secs: "<<dt.udiff()/1000000.0<<endl; 
    455  
    456     arr.content="::2"; 
    457     dt.set(); 
    458     for(int n = 0 ; n < 500000; ++n) { 
    459       set<DNSResourceRecord> aset; 
    460       arr.qname=templ="blah"+lexical_cast<string>(n)+".testdomain.com"; 
    461       aset.insert(arr); 
    462       RC.replace(now, templ, QType(QType::AAAA), aset, true); // auth, nuke it all 
    463     } 
    464     cerr<<"refill secs: "<<dt.udiff()/1000000.0<<endl; 
    465  
    466  
    467     dt.set(); 
    468     for(int n = 0 ; n < 500000; ++n) { 
    469       set<DNSResourceRecord> aset; 
    470       templ="blah"+lexical_cast<string>(n)+".testdomain.com"; 
    471       RC.get(now, templ, QType(QType::AAAA), &aset); // auth, nuke it all 
    472     } 
    473     cerr<<"get secs: "<<dt.udiff()/1000000.0<<endl; 
    474     vector<string> names; 
    475     for(int n = 0 ; n < 500000; ++n) { 
    476       templ="blah"+lexical_cast<string>(n)+".testdomain.com"; 
    477       names.push_back(templ); 
    478     } 
    479     random_shuffle(names.begin(), names.end()); 
    480     cerr<<"go!"<<endl; 
    481     dt.set(); 
    482     for(int n = 0 ; n < 500000; ++n) { 
    483       vector<DNSResourceRecord> avect; 
    484       RC.get2(now, names[n], QType(QType::AAAA), &avect); // auth, nuke it all 
    485     } 
    486     cerr<<"get2 secs: "<<dt.udiff()/1000000.0<<endl; 
    487  
    488     //    exit(1); 
    489   } 
    490 #endif 
    491  
    492   if(::arg()["hint-file"].empty()) { 
    493     static const char*ips[]={"198.41.0.4", "192.228.79.201", "192.33.4.12", "128.8.10.90", "192.203.230.10", "192.5.5.241",  
    494                              "192.112.36.4", "128.63.2.53", 
    495                              "192.36.148.17","192.58.128.30", "193.0.14.129", "199.7.83.42", "202.12.27.33"}; 
    496     static const char *ip6s[]={ 
    497       "2001:503:ba3e::2:30", NULL, NULL, NULL, NULL, 
    498       "2001:500:2f::f", NULL, "2001:500:1::803f:235", NULL, 
    499       "2001:503:c27::2:30", NULL, NULL, NULL 
    500     }; 
    501     DNSResourceRecord arr, aaaarr, nsrr; 
    502     arr.qtype=QType::A; 
    503     aaaarr.qtype=QType::AAAA; 
    504     nsrr.qtype=QType::NS; 
    505     arr.ttl=aaaarr.ttl=nsrr.ttl=time(0)+3600000; 
    506      
    507     for(char c='a';c<='m';++c) { 
    508       static char templ[40]; 
    509       strncpy(templ,"a.root-servers.net.", sizeof(templ) - 1); 
    510       *templ=c; 
    511       aaaarr.qname=arr.qname=nsrr.content=templ; 
    512       arr.content=ips[c-'a']; 
    513       set<DNSResourceRecord> aset; 
    514       aset.insert(arr); 
    515       RC.replace(time(0), string(templ), QType(QType::A), aset, true); // auth, nuke it all 
    516       if (ip6s[c-'a'] != NULL) { 
    517         aaaarr.content=ip6s[c-'a']; 
    518  
    519         set<DNSResourceRecord> aaaaset; 
    520         aaaaset.insert(aaaarr); 
    521         RC.replace(time(0), string(templ), QType(QType::AAAA), aaaaset, true); 
    522       } 
    523        
    524       nsset.insert(nsrr); 
    525     } 
    526   } 
    527   else { 
    528     ZoneParserTNG zpt(::arg()["hint-file"]); 
    529     DNSResourceRecord rr; 
    530  
    531     while(zpt.get(rr)) { 
    532       rr.ttl+=time(0); 
    533       if(rr.qtype.getCode()==QType::A) { 
    534         set<DNSResourceRecord> aset; 
    535         aset.insert(rr); 
    536         RC.replace(time(0), rr.qname, QType(QType::A), aset, true); // auth, etc see above 
    537       } else if(rr.qtype.getCode()==QType::AAAA) { 
    538         set<DNSResourceRecord> aaaaset; 
    539         aaaaset.insert(rr); 
    540         RC.replace(time(0), rr.qname, QType(QType::AAAA), aaaaset, true); 
    541       } else if(rr.qtype.getCode()==QType::NS) { 
    542         rr.content=toLower(rr.content); 
    543         nsset.insert(rr); 
    544       } 
    545     } 
    546   } 
    547   RC.replace(time(0),".", QType(QType::NS), nsset, true); // and stuff in the cache (auth) 
    548 } 
    549438 
    550439map<ComboAddress, uint32_t> g_tcpClientCounts; 
     
    670559      sendto(dc->d_socket, (const char*)&*packet.begin(), packet.size(), 0, (struct sockaddr *)(&dc->d_remote), dc->d_remote.getSocklen()); 
    671560      if(!SyncRes::s_nopacketcache) { 
    672         g_packetCache.insertResponsePacket(string((const char*)&*packet.begin(), packet.size()), g_now.tv_sec,  
     561        t_packetCache->insertResponsePacket(string((const char*)&*packet.begin(), packet.size()), g_now.tv_sec,  
    673562                                           min(minTTL,  
    674563                                               pw.getHeader()->rcode == RCode::ServFail ? SyncRes::s_packetcacheservfailttl : SyncRes::s_packetcachettl 
     
    723612    } 
    724613 
    725     sr.d_outqueries ? RC.cacheMisses++ : RC.cacheHits++;  
     614    sr.d_outqueries ? t_RC->cacheMisses++ : t_RC->cacheHits++;  
    726615    float spent=makeFloat(sr.d_now-dc->d_now); 
    727616    if(spent < 0.001) 
     
    858747  if(newsock>0) { 
    859748    g_stats.addRemote(addr); 
    860     if(g_allowFrom && !g_allowFrom->match(&addr)) { 
     749    if(t_allowFrom && !t_allowFrom->match(&addr)) { 
    861750      if(!g_quiet)  
    862751        L<<Logger::Error<<"["<<MT->getTid()<<"] dropping TCP query from "<<addr.toString()<<", address not matched by allow-from"<<endl; 
     
    888777} 
    889778  
    890  
    891  
    892779void handleNewUDPQuestion(int fd, FDMultiplexer::funcparam_t& var) 
    893780{ 
    894   //  static HTimer s_timer("udp new question processing"); 
    895   //  HTimerSentinel hts=s_timer.getSentinel(); 
    896781  int len; 
    897782  char data[1500]; 
     
    902787    g_stats.addRemote(fromaddr); 
    903788 
    904     if(g_allowFrom && !g_allowFrom->match(&fromaddr)) { 
     789    if(t_allowFrom && !t_allowFrom->match(&fromaddr)) { 
    905790      if(!g_quiet)  
    906791        L<<Logger::Error<<"["<<MT->getTid()<<"] dropping UDP query from "<<fromaddr.toString()<<", address not matched by allow-from"<<endl; 
     
    920805 
    921806        string response; 
    922         if(!SyncRes::s_nopacketcache && g_packetCache.getResponsePacket(string(data, len), g_now.tv_sec, &response)) { 
     807        if(!SyncRes::s_nopacketcache && t_packetCache->getResponsePacket(string(data, len), g_now.tv_sec, &response)) { 
    923808          if(!g_quiet) 
    924809            L<<Logger::Error<<t_id<< " question answered from packet cache from "<<fromaddr.toString()<<endl; 
     
    997882     
    998883    Utility::setNonBlocking(fd); 
    999     setSendBuffer(fd, 65000); 
     884    setSocketSendBuffer(fd, 65000); 
    1000885    listen(fd, 128); 
    1001886    deferredAdd.push_back(make_pair(fd, handleNewTCPQuestion)); 
     
    1044929    } 
    1045930 
    1046     setReceiveBuffer(fd, 200000); 
     931    setSocketReceiveBuffer(fd, 200000); 
    1047932    sin.sin4.sin_port = htons(st.port); 
    1048933 
     
    1086971bool statsWanted; 
    1087972 
    1088  
    1089973void usr1Handler(int) 
    1090974{ 
    1091975  statsWanted=true; 
    1092976} 
    1093  
    1094  
    1095977 
    1096978void usr2Handler(int) 
     
    1104986void doStats(void) 
    1105987{ 
    1106   if(g_stats.qcounter && (RC.cacheHits + RC.cacheMisses) && SyncRes::s_queries && SyncRes::s_outqueries) { 
    1107     //L<<Logger::Warning<<"stats: "<<g_stats.qcounter<<" questions, "<<RC.size()<<" cache entries, "<<SyncRes::s_negcache.size()<<" negative entries, " 
    1108     L<<Logger::Warning<<"stats: " <<(int)((RC.cacheHits*100.0)/(RC.cacheHits+RC.cacheMisses))<<"% cache hits"<<endl; 
    1109     //    L<<Logger::Warning<<"stats: throttle map: "<<SyncRes::s_throttle.size()<<", ns speeds: " 
    1110     // <<endl; // <<SyncRes::s_nsSpeeds.size()<<endl; // ", bytes: "<<RC.bytes()<<endl; 
     988  if(g_stats.qcounter && (t_RC->cacheHits + t_RC->cacheMisses) && SyncRes::s_queries && SyncRes::s_outqueries) {  // RC  FIXME 
     989    L<<Logger::Warning<<"stats: "<<g_stats.qcounter<<" questions, "<<t_RC->size()<<" cache entries, "<<SyncRes::t_sstorage->negcache.size()<<" negative entries, " << endl;// NEGCACHE MULTI FIXME 
     990    L<<Logger::Warning<<"stats: " <<(int)((t_RC->cacheHits*100.0)/(t_RC->cacheHits+t_RC->cacheMisses))<<"% cache hits"<<endl; // RC MULTI FIXME 
     991    L<<Logger::Warning<<"stats: throttle map: "<<SyncRes::t_sstorage->throttle.size()<<", ns speeds: " 
     992      <<SyncRes::t_sstorage->nsSpeeds.size()<<endl;  // FIXME NSSPEEDS MULTI 
    1111993    L<<Logger::Warning<<"stats: outpacket/query ratio "<<(int)(SyncRes::s_outqueries*100.0/SyncRes::s_queries)<<"%"; 
    1112994    L<<Logger::Warning<<", "<<(int)(SyncRes::s_throttledqueries*100.0/(SyncRes::s_outqueries+SyncRes::s_throttledqueries))<<"% throttled, " 
     
    11211003    L<<Logger::Warning<<"stats: no stats yet!"<<endl; 
    11221004 
    1123   //  HTimer::listAll(); 
    1124  
    11251005  statsWanted=false; 
    11261006} 
     
    11361016    DTime dt; 
    11371017    dt.setTimeval(now); 
    1138     RC.doPrune(); 
    1139      
    1140 #if 0 
     1018    t_RC->doPrune(); // this function is local to a thread, so fine anyhow 
     1019     
    11411020    typedef SyncRes::negcache_t::nth_index<1>::type negcache_by_ttd_index_t; 
    1142     negcache_by_ttd_index_t& ttdindex=boost::multi_index::get<1>(SyncRes::s_negcache); 
     1021    negcache_by_ttd_index_t& ttdindex=boost::multi_index::get<1>(SyncRes::t_sstorage->negcache);  
    11431022 
    11441023    negcache_by_ttd_index_t::iterator i=ttdindex.lower_bound(now.tv_sec); 
     
    11461025 
    11471026    time_t limit=now.tv_sec-300; 
    1148     for(SyncRes::nsspeeds_t::iterator i = SyncRes::s_nsSpeeds.begin() ; i!= SyncRes::s_nsSpeeds.end(); ) 
     1027    for(SyncRes::nsspeeds_t::iterator i = SyncRes::t_sstorage->nsSpeeds.begin() ; i!= SyncRes::t_sstorage->nsSpeeds.end(); ) 
    11491028      if(i->second.stale(limit)) 
    1150         SyncRes::s_nsSpeeds.erase(i++); 
     1029        SyncRes::t_sstorage->nsSpeeds.erase(i++); 
    11511030      else 
    11521031        ++i; 
    1153 #endif 
    1154     //   cerr<<"Pruned "<<pruned<<" records, left "<<SyncRes::s_negcache.size()<<"\n"; 
    1155 //    cout<<"Prune took "<<dt.udiff()<<"usec\n"; 
     1032 
    11561033    last_prune=time(0); 
    11571034  } 
     
    11821059; 
    11831060 
     1061void makeThreadPipes() 
     1062{ 
     1063  int numThreads = ::arg().asNum("threads"); 
     1064  for(int n=0; n < numThreads; ++n) { 
     1065    struct ThreadPipeSet tps; 
     1066    int fd[2]; 
     1067    if(pipe(fd) < 0) 
     1068      unixDie("Creating pipe for inter-thread communications"); 
     1069     
     1070    tps.readToThread = fd[0]; 
     1071    tps.writeToThread = fd[1]; 
     1072     
     1073    if(pipe(fd) < 0) 
     1074      unixDie("Creating pipe for inter-thread communications"); 
     1075    tps.readFromThread = fd[0]; 
     1076    tps.writeFromThread = fd[1]; 
     1077     
     1078    g_pipes.push_back(tps); 
     1079  } 
     1080} 
     1081 
     1082void broadcastFunction(const pipefunc_t& func, bool skipSelf) 
     1083{ 
     1084  typedef pair<int, int> fdss_t; 
     1085   
     1086  unsigned int n = 0; 
     1087  BOOST_FOREACH(ThreadPipeSet& tps, g_pipes)  
     1088  { 
     1089    if(n++ == t_id) { 
     1090      if(!skipSelf) 
     1091        func(); // don't write to ourselves! 
     1092      continue; 
     1093    } 
     1094       
     1095    pipefunc_t *funcptr = new pipefunc_t(func); 
     1096    if(write(tps.writeToThread, &funcptr, sizeof(funcptr)) != sizeof(funcptr)) 
     1097      unixDie("write to thread pipe returned wrong size or error"); 
     1098     
     1099    string* resp; 
     1100    if(read(tps.readFromThread, &resp, sizeof(resp)) != sizeof(resp)) 
     1101      unixDie("read from thread pipe returned wrong size or error"); 
     1102     
     1103    if(resp) { 
     1104//      cerr <<"got response: " << *resp << endl; 
     1105      delete resp; 
     1106    } 
     1107  } 
     1108} 
     1109 
     1110void handlePipeRequest(int fd, FDMultiplexer::funcparam_t& var) 
     1111{ 
     1112  pipefunc_t* func; 
     1113  if(read(fd, &func, sizeof(func)) != sizeof(func)) { // fd == readToThread  
     1114    unixDie("read from thread pipe returned wrong size or error"); 
     1115  } 
     1116  (*func)(); 
     1117  string* ptr = new string("ok"); 
     1118  if(write(g_pipes[t_id].writeFromThread, &ptr, sizeof(ptr)) != sizeof(ptr)) 
     1119    unixDie("write to thread pipe returned wrong size or error"); 
     1120     
     1121  delete func; 
     1122} 
    11841123 
    11851124void handleRCC(int fd, FDMultiplexer::funcparam_t& var) 
     
    12891228    } 
    12901229 
    1291     g_udpclientsocks.returnSocket(fd); 
     1230    t_udpclientsocks->returnSocket(fd); 
    12921231    string empty; 
    12931232 
     
    13541293    } 
    13551294    else if(fd >= 0) { 
    1356       g_udpclientsocks.returnSocket(fd); 
     1295      t_udpclientsocks->returnSocket(fd); 
    13571296    } 
    13581297  } 
     
    13811320} 
    13821321 
    1383 static void makeNameToIPZone(const string& hostname, const string& ip) 
    1384 { 
    1385   SyncRes::AuthDomain ad; 
    1386   DNSResourceRecord rr; 
    1387   rr.qname=toCanonic("", hostname); 
    1388   rr.d_place=DNSResourceRecord::ANSWER; 
    1389   rr.ttl=86400; 
    1390   rr.qtype=QType::SOA; 
    1391   rr.content="localhost. root 1 604800 86400 2419200 604800"; 
    1392    
    1393   ad.d_records.insert(rr); 
    1394  
    1395   rr.qtype=QType::NS; 
    1396   rr.content="localhost."; 
    1397  
    1398   ad.d_records.insert(rr); 
    1399    
    1400   rr.qtype=QType::A; 
    1401   rr.content=ip; 
    1402   ad.d_records.insert(rr); 
    1403    
    1404   if(SyncRes::s_domainmap.count(rr.qname)) { 
    1405     L<<Logger::Warning<<"Hosts file will not overwrite zone '"<<rr.qname<<"' already loaded"<<endl; 
    1406   } 
    1407   else { 
    1408     L<<Logger::Warning<<"Inserting forward zone '"<<rr.qname<<"' based on hosts file"<<endl; 
    1409     SyncRes::s_domainmap[rr.qname]=ad; 
    1410   } 
    1411 } 
    1412  
    1413 //! parts[0] must be an IP address, the rest must be host names 
    1414 static void makeIPToNamesZone(const vector<string>& parts)  
    1415 { 
    1416   string address=parts[0]; 
    1417   vector<string> ipparts; 
    1418   stringtok(ipparts, address,"."); 
    1419    
    1420   SyncRes::AuthDomain ad; 
    1421   DNSResourceRecord rr; 
    1422   for(int n=ipparts.size()-1; n>=0 ; --n) { 
    1423     rr.qname.append(ipparts[n]); 
    1424     rr.qname.append(1,'.'); 
    1425   } 
    1426   rr.qname.append("in-addr.arpa."); 
    1427  
    1428   rr.d_place=DNSResourceRecord::ANSWER; 
    1429   rr.ttl=86400; 
    1430   rr.qtype=QType::SOA; 
    1431   rr.content="localhost. root. 1 604800 86400 2419200 604800"; 
    1432    
    1433   ad.d_records.insert(rr); 
    1434  
    1435   rr.qtype=QType::NS; 
    1436   rr.content="localhost."; 
    1437  
    1438   ad.d_records.insert(rr); 
    1439   rr.qtype=QType::PTR; 
    1440  
    1441   if(ipparts.size()==4)  // otherwise this is a partial zone 
    1442     for(unsigned int n=1; n < parts.size(); ++n) { 
    1443       rr.content=toCanonic("", parts[n]); 
    1444       ad.d_records.insert(rr); 
    1445     } 
    1446  
    1447   if(SyncRes::s_domainmap.count(rr.qname)) { 
    1448     L<<Logger::Warning<<"Will not overwrite zone '"<<rr.qname<<"' already loaded"<<endl; 
    1449   } 
    1450   else { 
    1451     if(ipparts.size()==4) 
    1452       L<<Logger::Warning<<"Inserting reverse zone '"<<rr.qname<<"' based on hosts file"<<endl; 
    1453     SyncRes::s_domainmap[rr.qname]=ad; 
    1454   } 
    1455 } 
    1456  
    1457  
    1458 void parseAuthAndForwards(); 
    1459  
    1460 /* mission in life: parse three cases 
    1461    1) 1.2.3.4 
    1462    2) 1.2.3.4:5300 
    1463    3) 2001::1 
    1464    4) [2002::1]:53 
    1465 */ 
    1466  
    1467 ComboAddress parseIPAndPort(const std::string& input, uint16_t port) 
    1468 { 
    1469   if(input.find(':') == string::npos || input.empty()) // common case 
    1470     return ComboAddress(input, port); 
    1471  
    1472   pair<string,string> both; 
    1473  
    1474   try { // case 2 
    1475     both=splitField(input,':'); 
    1476     uint16_t newport=boost::lexical_cast<uint16_t>(both.second); 
    1477     return ComboAddress(both.first, newport); 
    1478   }  
    1479   catch(...){} 
    1480  
    1481   if(input[0]=='[') { // case 4 
    1482     both=splitField(input.substr(1),']'); 
    1483     return ComboAddress(both.first, both.second.empty() ? port : boost::lexical_cast<uint16_t>(both.second.substr(1))); 
    1484   } 
    1485  
    1486   return ComboAddress(input, port); // case 3 
    1487 } 
    1488  
    1489  
    1490 void convertServersForAD(const std::string& input, SyncRes::AuthDomain& ad, const char* sepa, bool verbose=true) 
    1491 { 
    1492   vector<string> servers; 
    1493   stringtok(servers, input, sepa); 
    1494   ad.d_servers.clear(); 
    1495  
    1496   for(vector<string>::const_iterator iter = servers.begin(); iter != servers.end(); ++iter) { 
    1497     if(verbose && iter != servers.begin())  
    1498       L<<", "; 
    1499  
    1500     ComboAddress addr=parseIPAndPort(*iter, 53); 
    1501     if(verbose) 
    1502       L<<addr.toStringWithPort(); 
    1503     ad.d_servers.push_back(addr); 
    1504   } 
    1505   if(verbose) 
    1506     L<<endl; 
    1507 } 
    1508  
    1509 string reloadAuthAndForwards() 
    1510 { 
    1511   SyncRes::domainmap_t original=SyncRes::s_domainmap; 
    1512    
     1322   
     1323void doReloadLuaScript() 
     1324{ 
     1325  string fname= ::arg()["lua-dns-script"]; 
    15131326  try { 
    1514     L<<Logger::Warning<<"Reloading zones, purging data from cache"<<endl; 
    1515    
    1516     for(SyncRes::domainmap_t::const_iterator i = SyncRes::s_domainmap.begin(); i != SyncRes::s_domainmap.end(); ++i) { 
    1517       for(SyncRes::AuthDomain::records_t::const_iterator j = i->second.d_records.begin(); j != i->second.d_records.end(); ++j)  
    1518         RC.doWipeCache(j->qname); 
    1519     } 
    1520  
     1327    if(fname.empty()) { 
     1328      t_pdl->reset(); 
     1329      L<<Logger::Error<<t_id<<" Unloaded current lua script"<<endl; 
     1330    } 
     1331    else { 
     1332      *t_pdl = shared_ptr<PowerDNSLua>(new PowerDNSLua(fname)); 
     1333    } 
     1334  } 
     1335  catch(std::exception& e) { 
     1336    L<<Logger::Error<<t_id<<" Retaining current script, error from '"<<fname<<"': "<< e.what() <<endl; 
     1337  } 
     1338     
     1339  L<<Logger::Warning<<t_id<<" (Re)loaded lua script from '"<<fname<<"'"<<endl; 
     1340} 
     1341 
     1342   
     1343 
     1344string doQueueReloadLuaScript(vector<string>::const_iterator begin, vector<string>::const_iterator end) 
     1345{ 
     1346  if(begin != end)  
     1347    ::arg().set("lua-dns-script") = *begin; 
     1348   
     1349  broadcastFunction(doReloadLuaScript); 
     1350   
     1351  return "ok, reload/unload queued\n"; 
     1352 
     1353 
     1354void* recursorThread(void*); 
     1355 
     1356void supplantACLs(NetmaskGroup *ng) 
     1357{ 
     1358  t_allowFrom = ng; 
     1359} 
     1360 
     1361void parseACLs() 
     1362{ 
     1363  static bool l_initialized; 
     1364   
     1365  if(l_initialized) { // only reload configuration file on second call 
    15211366    string configname=::arg()["config-dir"]+"/recursor.conf"; 
    15221367    cleanSlashes(configname); 
    15231368     
    1524     if(!::arg().preParseFile(configname.c_str(), "forward-zones"))  
     1369    if(!::arg().preParseFile(configname.c_str(), "allow-from-file"))  
    15251370      L<<Logger::Warning<<"Unable to re-parse configuration file '"<<configname<<"'"<<endl; 
    15261371     
    1527     ::arg().preParseFile(configname.c_str(), "auth-zones"); 
    1528     ::arg().preParseFile(configname.c_str(), "export-etc-hosts", "off"); 
    1529     ::arg().preParseFile(configname.c_str(), "serve-rfc1918"); 
    1530  
    1531     parseAuthAndForwards(); 
    1532      
    1533     // purge again - new zones need to blank out the cache 
    1534     for(SyncRes::domainmap_t::const_iterator i = SyncRes::s_domainmap.begin(); i != SyncRes::s_domainmap.end(); ++i) { 
    1535       for(SyncRes::AuthDomain::records_t::const_iterator j = i->second.d_records.begin(); j != i->second.d_records.end(); ++j)  
    1536         RC.doWipeCache(j->qname); 
    1537     } 
    1538  
    1539     // this is pretty blunt 
    1540     Lock l(&SyncRes::s_negcachelock); 
    1541     SyncRes::s_negcache.clear();   
    1542     return "ok\n"; 
    1543   } 
    1544   catch(std::exception& e) { 
    1545     L<<Logger::Error<<"Had error reloading zones, keeping original data: "<<e.what()<<endl; 
    1546   } 
    1547   catch(AhuException& ae) { 
    1548     L<<Logger::Error<<"Encountered error reloading zones, keeping original data: "<<ae.reason<<endl; 
    1549   } 
    1550   catch(...) { 
    1551     L<<Logger::Error<<"Encountered unknown error reloading zones, keeping original data"<<endl; 
    1552   } 
    1553   SyncRes::s_domainmap.swap(original); 
    1554   return "reloading failed, see log\n"; 
    1555 } 
    1556  
    1557 void parseAuthAndForwards() 
    1558 { 
    1559   SyncRes::s_domainmap.clear(); // this makes us idempotent 
    1560  
    1561   TXTRecordContent::report(); 
    1562   OPTRecordContent::report(); 
    1563  
    1564   typedef vector<string> parts_t; 
    1565   parts_t parts;   
    1566   const char *option_names[3]={"auth-zones", "forward-zones", "forward-zones-recurse"}; 
    1567   for(int n=0; n < 3 ; ++n ) { 
    1568     parts.clear(); 
    1569     stringtok(parts, ::arg()[option_names[n]], ",\t\n\r"); 
    1570     for(parts_t::const_iterator iter = parts.begin(); iter != parts.end(); ++iter) { 
    1571       SyncRes::AuthDomain ad; 
    1572       pair<string,string> headers=splitField(*iter, '='); 
    1573       trim(headers.first); 
    1574       trim(headers.second); 
    1575       headers.first=toCanonic("", headers.first); 
    1576       if(n==0) { 
    1577         L<<Logger::Error<<"Parsing authoritative data for zone '"<<headers.first<<"' from file '"<<headers.second<<"'"<<endl; 
    1578         ZoneParserTNG zpt(headers.second, headers.first); 
    1579         DNSResourceRecord rr; 
    1580         while(zpt.get(rr)) { 
    1581           try { 
    1582             string tmp=DNSRR2String(rr); 
    1583             rr=String2DNSRR(rr.qname, rr.qtype, tmp, rr.ttl); 
    1584           } 
    1585           catch(std::exception &e) { 
    1586             throw AhuException("Error parsing record '"+rr.qname+"' of type "+rr.qtype.getName()+" in zone '"+headers.first+"' from file '"+headers.second+"': "+e.what()); 
    1587           } 
    1588           catch(...) { 
    1589             throw AhuException("Error parsing record '"+rr.qname+"' of type "+rr.qtype.getName()+" in zone '"+headers.first+"' from file '"+headers.second+"'"); 
    1590           } 
    1591  
    1592           ad.d_records.insert(rr); 
    1593         } 
    1594       } 
    1595       else { 
    1596         L<<Logger::Error<<"Redirecting queries for zone '"<<headers.first<<"' "; 
    1597         if(n == 2) { 
    1598           L<<"with recursion "; 
    1599           ad.d_rdForward = 1; 
    1600         } 
    1601         else ad.d_rdForward = 0; 
    1602         L<<"to: "; 
    1603          
    1604         convertServersForAD(headers.second, ad, ";"); 
    1605         if(n == 2) { 
    1606           ad.d_rdForward = 1; 
    1607         } 
    1608       } 
    1609        
    1610       SyncRes::s_domainmap[headers.first]=ad; 
    1611     } 
    1612   } 
    1613    
    1614   if(!::arg()["forward-zones-file"].empty()) { 
    1615     L<<Logger::Warning<<"Reading zone forwarding information from '"<<::arg()["forward-zones-file"]<<"'"<<endl; 
    1616     SyncRes::AuthDomain ad; 
    1617     FILE *rfp=fopen(::arg()["forward-zones-file"].c_str(), "r"); 
    1618  
    1619     if(!rfp) 
    1620       throw AhuException("Error opening forward-zones-file '"+::arg()["forward-zones-file"]+"': "+stringerror()); 
    1621  
    1622     shared_ptr<FILE> fp=shared_ptr<FILE>(rfp, fclose); 
    1623      
    1624     char line[1024]; 
    1625     int linenum=0; 
    1626     uint64_t before = SyncRes::s_domainmap.size(); 
    1627     while(linenum++, fgets(line, sizeof(line)-1, fp.get())) { 
    1628       string domain, instructions; 
    1629       tie(domain, instructions)=splitField(line, '='); 
    1630       trim(domain); 
    1631       trim(instructions); 
    1632       if(boost::starts_with(domain,"+")) { 
    1633         domain=domain.c_str()+1; 
    1634         ad.d_rdForward = true; 
    1635       } 
    1636       else 
    1637         ad.d_rdForward = false; 
    1638       if(domain.empty())  
    1639         throw AhuException("Error parsing line "+lexical_cast<string>(linenum)+" of " +::arg()["forward-zones-file"]); 
    1640  
    1641       try { 
    1642         convertServersForAD(instructions, ad, ",; ", false); 
    1643       } 
    1644       catch(...) { 
    1645         throw AhuException("Conversion error parsing line "+lexical_cast<string>(linenum)+" of " +::arg()["forward-zones-file"]); 
    1646       } 
    1647  
    1648       SyncRes::s_domainmap[toCanonic("", domain)]=ad; 
    1649     } 
    1650     L<<Logger::Warning<<"Done parsing " << SyncRes::s_domainmap.size() - before<<" forwarding instructions from file '"<<::arg()["forward-zones-file"]<<"'"<<endl; 
    1651   } 
    1652  
    1653   if(::arg().mustDo("export-etc-hosts")) { 
     1372    ::arg().preParseFile(configname.c_str(), "allow-from", LOCAL_NETS); 
     1373  } 
     1374 
     1375  NetmaskGroup* oldAllowFrom = t_allowFrom, *allowFrom=new NetmaskGroup; 
     1376   
     1377  if(!::arg()["allow-from-file"].empty()) { 
    16541378    string line; 
    1655     string fname=::arg()["etc-hosts-file"]; 
    1656      
    1657     ifstream ifs(fname.c_str()); 
     1379    ifstream ifs(::arg()["allow-from-file"].c_str()); 
    16581380    if(!ifs) { 
    1659       L<<Logger::Warning<<"Could not open /etc/hosts for reading"<<endl; 
    1660       return; 
    1661     } 
    1662      
     1381      delete allowFrom;  
     1382      throw AhuException("Could not open '"+::arg()["allow-from-file"]+"': "+stringerror()); 
     1383    } 
     1384 
    16631385    string::size_type pos; 
    16641386    while(getline(ifs,line)) { 
     
    16691391      if(line.empty()) 
    16701392        continue; 
    1671       parts.clear(); 
    1672       stringtok(parts, line, "\t\r\n "); 
    1673       if(parts[0].find(':')!=string::npos) 
    1674         continue; 
    1675        
    1676       for(unsigned int n=1; n < parts.size(); ++n) 
    1677         makeNameToIPZone(parts[n], parts[0]); 
    1678       makeIPToNamesZone(parts); 
    1679     } 
    1680   } 
    1681   if(::arg().mustDo("serve-rfc1918")) { 
    1682     L<<Logger::Warning<<"Inserting rfc 1918 private space zones"<<endl; 
    1683     parts.clear(); 
    1684     parts.push_back("127"); 
    1685     makeIPToNamesZone(parts); 
    1686     parts[0]="10"; 
    1687     makeIPToNamesZone(parts); 
    1688  
    1689     parts[0]="192.168"; 
    1690     makeIPToNamesZone(parts); 
    1691     for(int n=16; n < 32; n++) { 
    1692       parts[0]="172."+lexical_cast<string>(n); 
    1693       makeIPToNamesZone(parts); 
    1694     } 
    1695   } 
    1696 } 
    1697  
    1698 string doQueueReloadLuaScript(vector<string>::const_iterator begin, vector<string>::const_iterator end) 
    1699 { 
    1700   if(begin != end)  
    1701     ::arg().set("lua-dns-script") = *begin; 
    1702      
    1703   g_luaReloadCounter = 0; 
    1704   return "ok, reload/unload queued\n"; 
    1705  
    1706    
    1707  
    1708 void doReloadLuaScript() 
    1709 { 
    1710   string fname= ::arg()["lua-dns-script"]; 
    1711   try { 
    1712     if(fname.empty()) { 
    1713       t_pdl->reset(); 
    1714       L<<Logger::Error<<t_id<<" Unloaded current lua script"<<endl; 
    1715     } 
    1716     else { 
    1717       *t_pdl = shared_ptr<PowerDNSLua>(new PowerDNSLua(fname)); 
    1718     } 
    1719   } 
    1720   catch(std::exception& e) { 
    1721     L<<Logger::Error<<t_id<<" Retaining current script, error from '"<<fname<<"': "<< e.what() <<endl; 
    1722   } 
    1723      
    1724   L<<Logger::Warning<<t_id<<" (Re)loaded lua script from '"<<fname<<"'"<<endl; 
    1725 } 
    1726  
    1727 void* recursorThread(void*); 
    1728  
    1729 void parseACLs() 
    1730 { 
    1731   static bool l_initialized; 
    1732   if(l_initialized) { 
    1733     string configname=::arg()["config-dir"]+"/recursor.conf"; 
    1734     cleanSlashes(configname); 
    1735      
    1736     if(!::arg().preParseFile(configname.c_str(), "allow-from-file"))  
    1737       L<<Logger::Warning<<"Unable to re-parse configuration file '"<<configname<<"'"<<endl; 
    1738      
    1739     ::arg().preParseFile(configname.c_str(), "allow-from"); 
    1740   } 
    1741   l_initialized = true; 
    1742   if(!::arg()["allow-from-file"].empty()) { 
    1743     string line; 
    1744     NetmaskGroup* allowFrom=new NetmaskGroup; 
    1745     ifstream ifs(::arg()["allow-from-file"].c_str()); 
    1746     if(!ifs) { 
    1747       throw AhuException("Could not open '"+::arg()["allow-from-file"]+"': "+stringerror()); 
    1748     } 
    1749  
    1750     string::size_type pos; 
    1751     while(getline(ifs,line)) { 
    1752       pos=line.find('#'); 
    1753       if(pos!=string::npos) 
    1754         line.resize(pos); 
    1755       trim(line); 
    1756       if(line.empty()) 
    1757         continue; 
    17581393 
    17591394      allowFrom->addMask(line); 
    17601395    } 
    1761     g_allowFrom = allowFrom; 
    1762     L<<Logger::Warning<<"Done parsing " << g_allowFrom->size() <<" allow-from ranges from file '"<<::arg()["allow-from-file"]<<"' - overriding 'allow-from' setting"<<endl; 
     1396    L<<Logger::Warning<<"Done parsing " << allowFrom->size() <<" allow-from ranges from file '"<<::arg()["allow-from-file"]<<"' - overriding 'allow-from' setting"<<endl; 
    17631397  } 
    17641398  else if(!::arg()["allow-from"].empty()) { 
    1765     NetmaskGroup* allowFrom=new NetmaskGroup; 
    17661399    vector<string> ips; 
    17671400    stringtok(ips, ::arg()["allow-from"], ", "); 
     
    17741407    } 
    17751408    L<<Logger::Warning<<endl; 
    1776     g_allowFrom = allowFrom; 
    1777   } 
    1778   else if(::arg()["local-address"]!="127.0.0.1" && ::arg().asNum("local-port")==53) 
    1779     L<<Logger::Error<<"WARNING: Allowing queries from all IP addresses - this can be a security risk!"<<endl; 
     1409  } 
     1410  else { 
     1411    if(::arg()["local-address"]!="127.0.0.1" && ::arg().asNum("local-port")==53)  
     1412      L<<Logger::Error<<"WARNING: Allowing queries from all IP addresses - this can be a security risk!"<<endl; 
     1413    delete allowFrom; 
     1414    allowFrom = 0; 
     1415  } 
     1416   
     1417  g_initialAllowFrom = allowFrom; 
     1418  broadcastFunction(boost::bind(supplantACLs, allowFrom)); 
     1419  delete oldAllowFrom; 
     1420   
     1421  l_initialized = true; 
    17801422} 
    17811423 
     
    18331475    g_quiet=false; 
    18341476  } 
    1835  
    1836   RC.d_followRFC2181=::arg().mustDo("auth-can-lower-ttl"); 
    18371477   
    18381478  try { 
     
    18761516  g_networkTimeoutMsec = ::arg().asNum("network-timeout"); 
    18771517 
    1878   parseAuthAndForwards(); 
     1518  g_initialDomainMap = parseAuthAndForwards(); 
    18791519  
    1880    
    18811520  g_stats.remotes.resize(::arg().asNum("remotes-ringbuffer-entries")); 
    18821521  if(!g_stats.remotes.empty()) 
     
    18871526  makeTCPServerSockets(); 
    18881527 
    1889 //  g_mc = new MemcachedCommunicator("127.0.0.1"); 
    1890   //  g_dc = new DHCPCommunicator("10.0.0.11"); 
    1891  
    18921528  s_pidfname=::arg()["socket-dir"]+"/"+s_programname+".pid"; 
    18931529  if(!s_pidfname.empty()) 
     
    19011537#endif 
    19021538 
    1903   primeHints();     
    1904   L<<Logger::Warning<<"Done priming cache with root hints"<<endl; 
    19051539#ifndef WIN32 
    19061540  if(::arg().mustDo("daemon")) { 
     
    19161550  makeControlChannelSocket();         
    19171551 
    1918   if(::arg().asNum("threads")==1) { 
     1552  makeThreadPipes(); 
     1553  int numThreads = ::arg().asNum("threads"); 
     1554  if(numThreads == 1) { 
    19191555    L<<Logger::Warning<<"Operating unthreaded"<<endl; 
    1920     g_singleThreaded=true; 
    19211556    recursorThread(0); 
    19221557  } 
    19231558  else { 
    19241559    pthread_t tid; 
    1925     L<<Logger::Warning<<"Launching "<<::arg().asNum("threads")<<" threads"<<endl; 
    1926     for(int n=0; n < ::arg().asNum("threads"); ++n) { 
     1560    L<<Logger::Warning<<"Launching "<< numThreads <<" threads"<<endl; 
     1561    for(int n=0; n < numThreads; ++n) { 
    19271562      pthread_create(&tid, 0, recursorThread, (void*)n); 
    19281563    } 
    19291564    void* res; 
     1565 
     1566     
    19301567    pthread_join(tid, &res); 
    19311568  } 
     
    19361573try 
    19371574{ 
    1938 #if 0 
    1939   DTime dt; 
    1940   time_t now=time(0); 
    1941  
    1942   string templ; 
    1943   vector<string> names; 
    1944   for(int n = 0 ; n < 500000; ++n) { 
    1945     templ="blah"+lexical_cast<string>(n)+".testdomain.com"; 
    1946     names.push_back(templ); 
    1947   } 
    1948   random_shuffle(names.begin(), names.end()); 
    1949   cerr<<"go!"<<endl; 
    1950   dt.set(); 
    1951   for(int n = 0 ; n < 500000; ++n) { 
    1952     vector<DNSResourceRecord> avect; 
    1953     RC.get2(now, names[n], QType(QType::AAAA), &avect); // auth, nuke it all 
    1954   } 
    1955   cerr<<"get2 secs: "<<dt.udiff()/1000000.0<<endl; 
    1956 #endif  
    19571575  t_id=(int) (long) ptr; 
    1958    
     1576  SyncRes tmp(g_now); // make sure it allocates tsstorage before we do anything, like primeHints or so.. 
     1577  SyncRes::t_sstorage->domainmap = g_initialDomainMap; 
     1578  t_allowFrom = g_initialAllowFrom; 
     1579  t_udpclientsocks = new UDPClientSocks(); 
     1580  primeHints(); 
     1581   
     1582  t_packetCache = new RecursorPacketCache(); 
     1583   
     1584  L<<Logger::Warning<<"Done priming cache with root hints"<<endl; 
     1585     
     1586  t_RC->d_followRFC2181=::arg().mustDo("auth-can-lower-ttl"); 
    19591587  t_pdl = new shared_ptr<PowerDNSLua>(); 
    1960   g_luaReloadCounter = t_id + 1; 
     1588   
    19611589  try { 
    19621590    if(!::arg()["lua-dns-script"].empty()) { 
     
    19731601  MT=new MTasker<PacketID,string>(::arg().asNum("stack-size")); 
    19741602   
    1975    
    19761603  PacketID pident; 
    19771604 
     
    19801607    L<<Logger::Error<<"Enabled '"<< t_fdm->getName() << "' multiplexer"<<endl; 
    19811608 
     1609  t_fdm->addReadFD(g_pipes[t_id].readToThread, handlePipeRequest); 
    19821610 
    19831611  for(deferredAdd_t::const_iterator i=deferredAdd.begin(); i!=deferredAdd.end(); ++i)  
     
    20121640  g_maxTCPPerClient=::arg().asNum("max-tcp-per-client"); 
    20131641   
    2014    
    20151642  bool listenOnTCP(true); 
     1643 
     1644   
    20161645   
    20171646  for(;;) { 
     
    20361665       
    20371666    counter++; 
    2038  
    2039     if(g_luaReloadCounter == t_id) { 
    2040       g_luaReloadCounter++; 
    2041       doReloadLuaScript(); 
    2042     } 
    20431667 
    20441668    if(statsWanted) { 
     
    21641788    ::arg().set("remotes-ringbuffer-entries", "maximum number of packets to store statistics for")="0"; 
    21651789    ::arg().set("version-string", "string reported on version.pdns or version.bind")="PowerDNS Recursor "VERSION" $Id$"; 
    2166     ::arg().set("allow-from", "If set, only allow these comma separated netmasks to recurse")="127.0.0.0/8, 10.0.0.0/8, 192.168.0.0/16, 172.16.0.0/12, ::1/128, fe80::/10"; 
     1790    ::arg().set("allow-from", "If set, only allow these comma separated netmasks to recurse")=LOCAL_NETS; 
    21671791    ::arg().set("allow-from-file", "If set, load allowed netmasks from this file")=""; 
    21681792    ::arg().set("entropy-source", "If set, read entropy from this file")="/dev/urandom"; 
    2169     ::arg().set("dont-query", "If set, do not query these netmasks for DNS data")="127.0.0.0/8, 10.0.0.0/8, 192.168.0.0/16, 172.16.0.0/12, ::1/128, fe80::/10"; 
     1793    ::arg().set("dont-query", "If set, do not query these netmasks for DNS data")=LOCAL_NETS;  
    21701794    ::arg().set("max-tcp-per-client", "If set, maximum number of TCP sessions per client (IP address)")="0"; 
    21711795    ::arg().set("fork", "If set, fork the daemon for possible double performance")="no";