root/trunk/pdns/pdns/tcpreceiver.cc @ 2140

Revision 2140, 26.3 KB (checked in by ahu, 2 years ago)

silence further debugging, move 'every query output' behind 'log-dns-queries' (which defaults to off), plus add some more documentation on 3.0

  • 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-2011  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 version 2
7    as published by the Free Software Foundation
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
16    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17*/
18#include "packetcache.hh"
19#include "utility.hh"
20#include "dnssecinfra.hh"
21#include "dnsseckeeper.hh"
22#include <cstdio>
23#include "base32.hh"
24#include <cstring>
25#include <cstdlib>
26#include <sys/types.h>
27#include <iostream>
28#include <string>
29#include "tcpreceiver.hh"
30#include "sstuff.hh"
31#include <boost/foreach.hpp>
32#include <errno.h>
33#include <signal.h>
34#include "base64.hh"
35#include "ueberbackend.hh"
36#include "dnspacket.hh"
37#include "nameserver.hh"
38#include "distributor.hh"
39#include "lock.hh"
40#include "logger.hh"
41#include "arguments.hh"
42
43#include "packethandler.hh"
44#include "statbag.hh"
45#include "resolver.hh"
46#include "communicator.hh"
47#include "namespaces.hh"
48#include "signingpipe.hh"
49extern PacketCache PC;
50extern StatBag S;
51
52/**
53\file tcpreceiver.cc
54\brief This file implements the tcpreceiver that receives and answers questions over TCP/IP
55*/
56
57pthread_mutex_t TCPNameserver::s_plock = PTHREAD_MUTEX_INITIALIZER;
58Semaphore *TCPNameserver::d_connectionroom_sem;
59PacketHandler *TCPNameserver::s_P; 
60int TCPNameserver::s_timeout;
61NetmaskGroup TCPNameserver::d_ng;
62
63void TCPNameserver::go()
64{
65  L<<Logger::Error<<"Creating backend connection for TCP"<<endl;
66  s_P=0;
67  try {
68    s_P=new PacketHandler;
69  }
70  catch(AhuException &ae) {
71    L<<Logger::Error<<Logger::NTLog<<"TCP server is unable to launch backends - will try again when questions come in"<<endl;
72    L<<Logger::Error<<"TCP server is unable to launch backends - will try again when questions come in: "<<ae.reason<<endl;
73  }
74  pthread_create(&d_tid, 0, launcher, static_cast<void *>(this));
75}
76
77void *TCPNameserver::launcher(void *data)
78{
79  static_cast<TCPNameserver *>(data)->thread();
80  return 0;
81}
82
83// throws AhuException if things didn't go according to plan, returns 0 if really 0 bytes were read
84int readnWithTimeout(int fd, void* buffer, unsigned int n, bool throwOnEOF=true)
85{
86  unsigned int bytes=n;
87  char *ptr = (char*)buffer;
88  int ret;
89  while(bytes) {
90    ret=read(fd, ptr, bytes);
91    if(ret < 0) {
92      if(errno==EAGAIN) {
93        ret=waitForData(fd, 5);
94        if(ret < 0)
95          throw NetworkError("Waiting for data read");
96        if(!ret)
97          throw NetworkError("Timeout reading data");
98        continue;
99      }
100      else
101        throw NetworkError("Reading data: "+stringerror());
102    }
103    if(!ret) {
104      if(!throwOnEOF && n == bytes)
105        return 0;
106      else
107        throw NetworkError("Did not fulfill read from TCP due to EOF");
108    }
109   
110    ptr += ret;
111    bytes -= ret;
112  }
113  return n;
114}
115
116// ditto
117void writenWithTimeout(int fd, const void *buffer, unsigned int n)
118{
119  unsigned int bytes=n;
120  const char *ptr = (char*)buffer;
121  int ret;
122  while(bytes) {
123    ret=write(fd, ptr, bytes);
124    if(ret < 0) {
125      if(errno==EAGAIN) {
126        ret=waitForRWData(fd, false, 5, 0);
127        if(ret < 0)
128          throw NetworkError("Waiting for data write");
129        if(!ret)
130          throw NetworkError("Timeout writing data");
131        continue;
132      }
133      else
134        throw NetworkError("Writing data: "+stringerror());
135    }
136    if(!ret) {
137      throw NetworkError("Did not fulfill TCP write due to EOF");
138    }
139   
140    ptr += ret;
141    bytes -= ret;
142  }
143}
144
145void connectWithTimeout(int fd, struct sockaddr* remote, size_t socklen)
146{
147  int err;
148  Utility::socklen_t len=sizeof(err);
149
150#ifndef WIN32
151  if((err=connect(fd, remote, socklen))<0 && errno!=EINPROGRESS) 
152#else
153  if((err=connect(clisock, remote, socklen))<0 && WSAGetLastError() != WSAEWOULDBLOCK ) 
154#endif // WIN32
155    throw NetworkError("connect: "+stringerror());
156
157  if(!err)
158    goto done;
159 
160  err=waitForRWData(fd, false, 5, 0);
161  if(err == 0)
162    throw NetworkError("Timeout connecting to remote");
163  if(err < 0)
164    throw NetworkError("Error connecting to remote");
165
166  if(getsockopt(fd, SOL_SOCKET,SO_ERROR,(char *)&err,&len)<0)
167    throw NetworkError("Error connecting to remote: "+stringerror()); // Solaris
168
169  if(err)
170    throw NetworkError("Error connecting to remote: "+string(strerror(err)));
171
172 done:
173  ;
174}
175
176void TCPNameserver::sendPacket(shared_ptr<DNSPacket> p, int outsock)
177{
178  const string buffer = p->getString();
179  uint16_t len=htons(buffer.length());
180  writenWithTimeout(outsock, &len, 2);
181  writenWithTimeout(outsock, buffer.c_str(), buffer.length());
182}
183
184
185void TCPNameserver::getQuestion(int fd, char *mesg, int pktlen, const ComboAddress &remote)
186try
187{
188  readnWithTimeout(fd, mesg, pktlen);
189}
190catch(NetworkError& ae) {
191  throw NetworkError("Error reading DNS data from TCP client "+remote.toString()+": "+ae.what());
192}
193
194static void proxyQuestion(shared_ptr<DNSPacket> packet)
195{
196  int sock=socket(AF_INET, SOCK_STREAM, 0);
197  if(sock < 0)
198    throw NetworkError("Error making TCP connection socket to recursor: "+stringerror());
199
200  Utility::setNonBlocking(sock);
201  ServiceTuple st;
202  st.port=53;
203  parseService(::arg()["recursor"],st);
204
205  try {
206    ComboAddress recursor(st.host, st.port);
207    connectWithTimeout(sock, (struct sockaddr*)&recursor, recursor.getSocklen());
208    const string &buffer=packet->getString();
209   
210    uint16_t len=htons(buffer.length()), slen;
211   
212    writenWithTimeout(sock, &len, 2);
213    writenWithTimeout(sock, buffer.c_str(), buffer.length());
214   
215    int ret;
216   
217    ret=readnWithTimeout(sock, &len, 2);
218    len=ntohs(len);
219
220    char answer[len];
221    ret=readnWithTimeout(sock, answer, len);
222
223    slen=htons(len);
224    writenWithTimeout(packet->getSocket(), &slen, 2);
225   
226    writenWithTimeout(packet->getSocket(), answer, len);
227  }
228  catch(NetworkError& ae) {
229    close(sock);
230    throw NetworkError("While proxying a question to recursor "+st.host+": " +ae.what());
231  }
232  close(sock);
233  return;
234}
235
236void *TCPNameserver::doConnection(void *data)
237{
238  shared_ptr<DNSPacket> packet;
239  // Fix gcc-4.0 error (on AMD64)
240  int fd=(int)(long)data; // gotta love C (generates a harmless warning on opteron)
241  pthread_detach(pthread_self());
242  Utility::setNonBlocking(fd);
243  try {
244    char mesg[512];
245   
246    DLOG(L<<"TCP Connection accepted on fd "<<fd<<endl);
247    bool logDNSQueries= ::arg().mustDo("log-dns-queries");
248    for(;;) {
249      ComboAddress remote;
250      socklen_t remotelen=sizeof(remote);
251      if(getpeername(fd, (struct sockaddr *)&remote, &remotelen) < 0) {
252        L<<Logger::Error<<"Received question from socket which had no remote address, dropping ("<<stringerror()<<")"<<endl;
253        break;
254      }
255
256      uint16_t pktlen;
257      if(!readnWithTimeout(fd, &pktlen, 2, false))
258        break;
259      else
260        pktlen=ntohs(pktlen);
261
262      if(pktlen>511) {
263        L<<Logger::Error<<"Received an overly large question from "<<remote.toString()<<", dropping"<<endl;
264        break;
265      }
266     
267      getQuestion(fd, mesg, pktlen, remote);
268      S.inc("tcp-queries");     
269
270      packet=shared_ptr<DNSPacket>(new DNSPacket);
271      packet->setRemote(&remote);
272      packet->d_tcp=true;
273      packet->setSocket(fd);
274      if(packet->parse(mesg, pktlen)<0)
275        break;
276     
277      if(packet->qtype.getCode()==QType::AXFR || packet->qtype.getCode()==QType::IXFR ) {
278        if(doAXFR(packet->qdomain, packet, fd)) 
279          S.inc("tcp-answers"); 
280        continue;
281      }
282
283      shared_ptr<DNSPacket> reply; 
284      shared_ptr<DNSPacket> cached= shared_ptr<DNSPacket>(new DNSPacket);
285      if(logDNSQueries) 
286        L << Logger::Notice<<"TCP Remote "<< packet->remote.toString() <<" wants '" << packet->qdomain<<"|"<<packet->qtype.getName() << 
287        "', do = " <<packet->d_dnssecOk <<", bufsize = "<< packet->getMaxReplyLen()<<": ";
288
289
290      if(!packet->d.rd && packet->couldBeCached() && PC.get(packet.get(), cached.get())) { // short circuit - does the PacketCache recognize this question?
291        if(logDNSQueries)
292          L<<"packetcache HIT"<<endl;
293        cached->setRemote(&packet->remote);
294        cached->d.id=packet->d.id;
295        cached->d.rd=packet->d.rd; // copy in recursion desired bit
296        cached->commitD(); // commit d to the packet                        inlined
297
298        sendPacket(cached, fd); // presigned, don't do it again
299        S.inc("tcp-answers");
300        continue;
301      }
302      if(logDNSQueries)
303          L<<"packetcache MISS"<<endl; 
304      {
305        Lock l(&s_plock);
306        if(!s_P) {
307          L<<Logger::Error<<"TCP server is without backend connections, launching"<<endl;
308          s_P=new PacketHandler;
309        }
310        bool shouldRecurse;
311
312        reply=shared_ptr<DNSPacket>(s_P->questionOrRecurse(packet.get(), &shouldRecurse)); // we really need to ask the backend :-)
313
314        if(shouldRecurse) {
315          proxyQuestion(packet);
316          continue;
317        }
318      }
319
320      if(!reply)  // unable to write an answer?
321        break;
322       
323      S.inc("tcp-answers");
324      sendPacket(reply, fd);
325    }
326  }
327  catch(DBException &e) {
328    Lock l(&s_plock);
329    delete s_P;
330    s_P = 0;
331
332    L<<Logger::Error<<"TCP Connection Thread unable to answer a question because of a backend error, cycling"<<endl;
333  }
334  catch(AhuException &ae) {
335    Lock l(&s_plock);
336    delete s_P;
337    s_P = 0; // on next call, backend will be recycled
338    L<<Logger::Error<<"TCP nameserver had error, cycling backend: "<<ae.reason<<endl;
339  }
340  catch(NetworkError &e) {
341    L<<Logger::Info<<"TCP Connection Thread died because of STL error: "<<e.what()<<endl;
342  }
343
344  catch(std::exception &e) {
345    L<<Logger::Error<<"TCP Connection Thread died because of STL error: "<<e.what()<<endl;
346  }
347  catch( ... )
348  {
349    L << Logger::Error << "TCP Connection Thread caught unknown exception." << endl;
350  }
351  d_connectionroom_sem->post();
352  Utility::closesocket(fd);
353
354  return 0;
355}
356
357
358
359bool TCPNameserver::canDoAXFR(shared_ptr<DNSPacket> q)
360{
361  if(::arg().mustDo("disable-axfr"))
362    return false;
363
364  if(q->d_havetsig) { // if you have one, it must be good
365    TSIGRecordContent trc;
366    string keyname, secret;
367    Lock l(&s_plock);
368    if(!checkForCorrectTSIG(q.get(), s_P->getBackend(), &keyname, &secret, &trc))
369      return false;
370   
371    DNSSECKeeper dk;
372   
373    if(!dk.TSIGGrantsAccess(q->qdomain, keyname, trc.d_algoName)) {
374      L<<Logger::Error<<"AXFR '"<<q->qdomain<<"' denied: key with name '"<<keyname<<"' and algorithm '"<<trc.d_algoName<<"' does not grant access to zone"<<endl;
375      return false;
376    }
377    else {
378      L<<Logger::Warning<<"AXFR of domain '"<<q->qdomain<<"' allowed: TSIG signed request with authorized key '"<<keyname<<"' and algorithm '"<<trc.d_algoName<<"'"<<endl;
379      return true;
380    }
381  }
382   
383
384  if(!::arg().mustDo("per-zone-axfr-acls") && (::arg()["allow-axfr-ips"].empty() || d_ng.match( (ComboAddress *) &q->remote )))
385    return true;
386#if 0
387  if(::arg().mustDo("per-zone-axfr-acls")) {
388    SOAData sd;
389    sd.db=(DNSBackend *)-1;
390    if(s_P->getBackend()->getSOA(q->qdomain,sd)) {
391      DNSBackend *B=sd.db;
392      if (B->checkACL(string("allow-axfr"), q->qdomain, q->getRemote())) {
393        return true;
394      }
395    } 
396  }
397#endif
398  extern CommunicatorClass Communicator;
399
400  if(Communicator.justNotified(q->qdomain, q->getRemote())) { // we just notified this ip
401    L<<Logger::Warning<<"Approved AXFR of '"<<q->qdomain<<"' from recently notified slave "<<q->getRemote()<<endl;
402    return true;
403  }
404
405  return false;
406}
407
408namespace {
409struct NSECXEntry
410{
411  set<uint16_t> d_set;
412  unsigned int d_ttl;
413};
414
415DNSResourceRecord makeDNSRRFromSOAData(const SOAData& sd)
416{
417  DNSResourceRecord soa;
418  soa.qname= sd.qname;
419  soa.qtype=QType::SOA;
420  soa.content=serializeSOAData(sd);
421  soa.ttl=sd.ttl;
422  soa.domain_id=sd.domain_id;
423  soa.auth = true;
424  soa.d_place=DNSResourceRecord::ANSWER;
425  return soa;
426}
427
428shared_ptr<DNSPacket> getFreshAXFRPacket(shared_ptr<DNSPacket> q)
429{
430  shared_ptr<DNSPacket> ret = shared_ptr<DNSPacket>(q->replyPacket());
431  ret->setCompress(false);
432  ret->d_dnssecOk=false; // RFC 5936, 2.2.5
433  ret->d_tcp = true;
434  return ret;
435}
436
437}
438/** do the actual zone transfer. Return 0 in case of error, 1 in case of success */
439int TCPNameserver::doAXFR(const string &target, shared_ptr<DNSPacket> q, int outsock)
440{
441  bool noAXFRBecauseOfNSEC3Narrow=false;
442  NSEC3PARAMRecordContent ns3pr;
443  bool narrow;
444  bool NSEC3Zone=false;
445 
446  DNSSECKeeper dk;
447  bool securedZone = dk.isSecuredZone(target);
448  if(dk.getNSEC3PARAM(target, &ns3pr, &narrow)) {
449    NSEC3Zone=true;
450    if(narrow) {
451      L<<Logger::Error<<"Not doing AXFR of an NSEC3 narrow zone.."<<endl;
452      noAXFRBecauseOfNSEC3Narrow=true;
453    }
454  }
455
456  shared_ptr<DNSPacket> outpacket= getFreshAXFRPacket(q);
457  if(q->d_dnssecOk)
458    outpacket->d_dnssecOk=true; // RFC 5936, 2.2.5 'SHOULD'
459 
460  if(!canDoAXFR(q) || noAXFRBecauseOfNSEC3Narrow) {
461    L<<Logger::Error<<"AXFR of domain '"<<target<<"' denied to "<<q->getRemote()<<endl;
462    outpacket->setRcode(RCode::Refused); 
463    // FIXME: should actually figure out if we are auth over a zone, and send out 9 if we aren't
464    sendPacket(outpacket,outsock);
465    return 0;
466  }
467 
468  L<<Logger::Error<<"AXFR of domain '"<<target<<"' initiated by "<<q->getRemote()<<endl;
469
470  SOAData sd;
471  sd.db=(DNSBackend *)-1; // force uncached answer
472  {
473    Lock l(&s_plock);
474    DLOG(L<<"Looking for SOA"<<endl);    // find domain_id via SOA and list complete domain. No SOA, no AXFR
475    if(!s_P) {
476      L<<Logger::Error<<"TCP server is without backend connections in doAXFR, launching"<<endl;
477      s_P=new PacketHandler;
478    }
479
480    if(!s_P->getBackend()->getSOA(target, sd)) {
481      L<<Logger::Error<<"AXFR of domain '"<<target<<"' failed: not authoritative"<<endl;
482      outpacket->setRcode(9); // 'NOTAUTH'
483      sendPacket(outpacket,outsock);
484      return 0;
485    }
486  }
487 
488  UeberBackend db;
489  sd.db=(DNSBackend *)-1; // force uncached answer
490  if(!db.getSOA(target, sd)) {
491    L<<Logger::Error<<"AXFR of domain '"<<target<<"' failed: not authoritative in second instance"<<endl;
492    outpacket->setRcode(9); // 'NOTAUTH'
493    sendPacket(outpacket,outsock);
494    return 0;
495  }
496
497  if(!sd.db || sd.db==(DNSBackend *)-1) {
498    L<<Logger::Error<<"Error determining backend for domain '"<<target<<"' trying to serve an AXFR"<<endl;
499    outpacket->setRcode(RCode::ServFail);
500    sendPacket(outpacket,outsock);
501    return 0;
502  }
503
504  TSIGRecordContent trc;
505  string tsigkeyname, tsigsecret;
506
507  q->getTSIGDetails(&trc, &tsigkeyname, 0);
508
509  if(!tsigkeyname.empty()) {
510    string tsig64, algorithm;
511    Lock l(&s_plock);
512    s_P->getBackend()->getTSIGKey(tsigkeyname, &algorithm, &tsig64);
513    B64Decode(tsig64, tsigsecret);
514  }
515 
516 
517  UeberBackend signatureDB; 
518 
519  // SOA *must* go out first, our signing pipe might reorder
520  DLOG(L<<"Sending out SOA"<<endl);
521  DNSResourceRecord soa = makeDNSRRFromSOAData(sd);
522  outpacket->addRecord(soa);
523  editSOA(dk, sd.qname, outpacket.get());
524  if(securedZone)
525    addRRSigs(dk, signatureDB, target, outpacket->getRRS());
526 
527  if(!tsigkeyname.empty())
528    outpacket->setTSIGDetails(trc, tsigkeyname, tsigsecret, trc.d_mac); // first answer is 'normal'
529 
530  sendPacket(outpacket, outsock);
531 
532  trc.d_mac = outpacket->d_trc.d_mac;
533  outpacket = getFreshAXFRPacket(q);
534 
535  ChunkedSigningPipe csp(target, securedZone, "", ::arg().asNum("signing-threads"));
536 
537  typedef map<string, NSECXEntry> nsecxrepo_t;
538  nsecxrepo_t nsecxrepo;
539 
540  // this is where the DNSKEYs go  in
541 
542  DNSSECKeeper::keyset_t keys = dk.getKeys(target);
543 
544  DNSResourceRecord rr;
545 
546  BOOST_FOREACH(const DNSSECKeeper::keyset_t::value_type& value, keys) {
547    rr.qname = target;
548    rr.qtype = QType(QType::DNSKEY);
549    rr.ttl = sd.default_ttl;
550    rr.auth = 1; // please sign!
551    rr.content = value.first.getDNSKEY().getZoneRepresentation();
552    string keyname = NSEC3Zone ? hashQNameWithSalt(ns3pr.d_iterations, ns3pr.d_salt, rr.qname) : labelReverse(rr.qname);
553    NSECXEntry& ne = nsecxrepo[keyname];
554   
555    ne.d_set.insert(rr.qtype.getCode());
556    ne.d_ttl = rr.ttl;
557    csp.submit(rr);
558  }
559 
560  if(NSEC3Zone) { // now stuff in the NSEC3PARAM
561    rr.qtype = QType(QType::NSEC3PARAM);
562    ns3pr.d_flags = 0;
563    rr.content = ns3pr.getZoneRepresentation();
564    ns3pr.d_flags = 1;
565    string keyname = hashQNameWithSalt(ns3pr.d_iterations, ns3pr.d_salt, rr.qname);
566    NSECXEntry& ne = nsecxrepo[keyname];
567   
568    ne.d_set.insert(rr.qtype.getCode());
569    csp.submit(rr);
570  }
571 
572  // now start list zone
573  if(!(sd.db->list(target, sd.domain_id))) { 
574    L<<Logger::Error<<"Backend signals error condition"<<endl;
575    outpacket->setRcode(2); // 'SERVFAIL'
576    sendPacket(outpacket,outsock);
577    return 0;
578  }
579
580  /* now write all other records */
581 
582  string keyname;
583  DTime dt;
584  dt.set();
585  int records=0;
586  while(sd.db->get(rr)) {
587    records++;
588    if(securedZone && (rr.auth || rr.qtype.getCode() == QType::NS || rr.qtype.getCode() == QType::DS)) { // this is probably NSEC specific, NSEC3 is different
589      keyname = NSEC3Zone ? hashQNameWithSalt(ns3pr.d_iterations, ns3pr.d_salt, rr.qname) : labelReverse(rr.qname);
590      NSECXEntry& ne = nsecxrepo[keyname];
591      ne.d_set.insert(rr.qtype.getCode());
592      ne.d_ttl = rr.ttl;
593    }
594    if(rr.qtype.getCode() == QType::SOA)
595      continue; // skip SOA - would indicate end of AXFR
596
597    if(csp.submit(rr)) {
598      for(;;) {
599        outpacket->getRRS() = csp.getChunk();
600        if(!outpacket->getRRS().empty()) {
601          if(!tsigkeyname.empty())
602            outpacket->setTSIGDetails(trc, tsigkeyname, tsigsecret, trc.d_mac, true); 
603          sendPacket(outpacket, outsock);
604          trc.d_mac=outpacket->d_trc.d_mac;
605          outpacket=getFreshAXFRPacket(q);
606        }
607        else
608          break;
609      }
610    }
611  }
612  unsigned int udiff=dt.udiffNoReset();
613  /*
614  cerr<<"Starting NSEC: "<<csp.d_signed/(udiff/1000000.0)<<" sigs/s, "<<csp.d_signed<<" / "<<udiff/1000000.0<<endl;
615  cerr<<"Outstanding: "<<csp.d_outstanding<<", "<<csp.d_queued - csp.d_signed << endl;
616  cerr<<"Ready for consumption: "<<csp.getReady()<<endl;
617  */
618  if(securedZone) {   
619    if(NSEC3Zone) {
620      for(nsecxrepo_t::const_iterator iter = nsecxrepo.begin(); iter != nsecxrepo.end(); ++iter) {
621        NSEC3RecordContent n3rc;
622        n3rc.d_set = iter->second.d_set;
623        n3rc.d_set.insert(QType::RRSIG);
624        n3rc.d_salt=ns3pr.d_salt;
625        n3rc.d_flags = 0;
626        n3rc.d_iterations = ns3pr.d_iterations;
627        n3rc.d_algorithm = 1; // SHA1, fixed in PowerDNS for now
628        if(boost::next(iter) != nsecxrepo.end()) {
629          n3rc.d_nexthash = boost::next(iter)->first;
630        }
631        else
632          n3rc.d_nexthash=nsecxrepo.begin()->first;
633   
634        rr.qname = dotConcat(toLower(toBase32Hex(iter->first)), sd.qname);
635   
636        rr.ttl = iter->second.d_ttl;
637        rr.content = n3rc.getZoneRepresentation();
638        rr.qtype = QType::NSEC3;
639        rr.d_place = DNSResourceRecord::ANSWER;
640        rr.auth=true;
641        if(csp.submit(rr)) {
642          for(;;) {
643            outpacket->getRRS() = csp.getChunk();
644            if(!outpacket->getRRS().empty()) {
645              if(!tsigkeyname.empty())
646                outpacket->setTSIGDetails(trc, tsigkeyname, tsigsecret, trc.d_mac, true);
647              sendPacket(outpacket, outsock);
648              trc.d_mac=outpacket->d_trc.d_mac;
649              outpacket=getFreshAXFRPacket(q);
650            }
651            else
652              break;
653          }
654        }
655      }
656    }
657    else for(nsecxrepo_t::const_iterator iter = nsecxrepo.begin(); iter != nsecxrepo.end(); ++iter) {
658      NSECRecordContent nrc;
659      nrc.d_set = iter->second.d_set;
660      nrc.d_set.insert(QType::RRSIG);
661      nrc.d_set.insert(QType::NSEC);
662      if(boost::next(iter) != nsecxrepo.end()) {
663        nrc.d_next = labelReverse(boost::next(iter)->first);
664      }
665      else
666        nrc.d_next=labelReverse(nsecxrepo.begin()->first);
667 
668      rr.qname = labelReverse(iter->first);
669 
670      rr.ttl = iter->second.d_ttl;
671      rr.content = nrc.getZoneRepresentation();
672      rr.qtype = QType::NSEC;
673      rr.d_place = DNSResourceRecord::ANSWER;
674      rr.auth=true;
675     
676      if(csp.submit(rr)) {
677        for(;;) {
678          outpacket->getRRS() = csp.getChunk();
679          if(!outpacket->getRRS().empty()) {
680            if(!tsigkeyname.empty())
681              outpacket->setTSIGDetails(trc, tsigkeyname, tsigsecret, trc.d_mac, true); 
682            sendPacket(outpacket, outsock);
683            trc.d_mac=outpacket->d_trc.d_mac;
684            outpacket=getFreshAXFRPacket(q);
685          }
686          else
687            break;
688        }
689      }
690    }
691  }
692  udiff=dt.udiffNoReset();
693  /*
694  cerr<<"Flushing pipe: "<<csp.d_signed/(udiff/1000000.0)<<" sigs/s, "<<csp.d_signed<<" / "<<udiff/1000000.0<<endl;
695  cerr<<"Outstanding: "<<csp.d_outstanding<<", "<<csp.d_queued - csp.d_signed << endl;
696  cerr<<"Ready for consumption: "<<csp.getReady()<<endl;
697  * */
698  for(;;) { 
699    outpacket->getRRS() = csp.getChunk(true); // flush the pipe
700    if(!outpacket->getRRS().empty()) {
701      if(!tsigkeyname.empty())
702        outpacket->setTSIGDetails(trc, tsigkeyname, tsigsecret, trc.d_mac, true); // first answer is 'normal'
703      sendPacket(outpacket, outsock);
704      trc.d_mac=outpacket->d_trc.d_mac;
705      outpacket=getFreshAXFRPacket(q);
706    }
707    else 
708      break;
709  }
710 
711  udiff=dt.udiffNoReset();
712  if(securedZone) 
713    L<<Logger::Info<<"Done signing: "<<csp.d_signed/(udiff/1000000.0)<<" sigs/s, "<<endl;
714 
715  DLOG(L<<"Done writing out records"<<endl);
716  /* and terminate with yet again the SOA record */
717  outpacket=getFreshAXFRPacket(q);
718  outpacket->addRecord(soa);
719  editSOA(dk, sd.qname, outpacket.get());
720  if(!tsigkeyname.empty())
721    outpacket->setTSIGDetails(trc, tsigkeyname, tsigsecret, trc.d_mac, true); 
722 
723  sendPacket(outpacket, outsock);
724 
725  DLOG(L<<"last packet - close"<<endl);
726  L<<Logger::Error<<"AXFR of domain '"<<target<<"' to "<<q->getRemote()<<" finished"<<endl;
727
728  return 1;
729}
730
731TCPNameserver::~TCPNameserver()
732{
733  delete d_connectionroom_sem;
734}
735
736TCPNameserver::TCPNameserver()
737{
738//  sem_init(&d_connectionroom_sem,0,::arg().asNum("max-tcp-connections"));
739  d_connectionroom_sem = new Semaphore( ::arg().asNum( "max-tcp-connections" ));
740
741  s_timeout=10;
742  vector<string>locals;
743  stringtok(locals,::arg()["local-address"]," ,");
744
745  vector<string>locals6;
746  stringtok(locals6,::arg()["local-ipv6"]," ,");
747
748  if(locals.empty() && locals6.empty())
749    throw AhuException("No local address specified");
750
751  d_highfd=0;
752
753  vector<string> parts;
754  stringtok( parts, ::arg()["allow-axfr-ips"], ", \t" ); // is this IP on the guestlist?
755  for( vector<string>::const_iterator i = parts.begin(); i != parts.end(); ++i ) {
756    d_ng.addMask( *i );
757  }
758
759#ifndef WIN32
760  signal(SIGPIPE,SIG_IGN);
761#endif // WIN32
762
763  for(vector<string>::const_iterator laddr=locals.begin();laddr!=locals.end();++laddr) {
764    int s=socket(AF_INET,SOCK_STREAM,0); 
765
766    if(s<0) 
767      throw AhuException("Unable to acquire TCP socket: "+stringerror());
768
769    ComboAddress local(*laddr, ::arg().asNum("local-port"));
770     
771    int tmp=1;
772    if(setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char*)&tmp,sizeof tmp)<0) {
773      L<<Logger::Error<<"Setsockopt failed"<<endl;
774      exit(1); 
775    }
776
777    if(::bind(s, (sockaddr*)&local, local.getSocklen())<0) {
778      L<<Logger::Error<<"binding to TCP socket: "<<strerror(errno)<<endl;
779      throw AhuException("Unable to bind to TCP socket");
780    }
781   
782    listen(s,128);
783    L<<Logger::Error<<"TCP server bound to "<<local.toStringWithPort()<<endl;
784    d_sockets.push_back(s);
785    struct pollfd pfd;
786    memset(&pfd, 0, sizeof(pfd));
787    pfd.fd = s;
788    pfd.events = POLLIN;
789
790    d_prfds.push_back(pfd);
791
792    d_highfd=max(s,d_highfd);
793  }
794
795#if !WIN32 && HAVE_IPV6
796  for(vector<string>::const_iterator laddr=locals6.begin();laddr!=locals6.end();++laddr) {
797    int s=socket(AF_INET6,SOCK_STREAM,0); 
798
799    if(s<0) 
800      throw AhuException("Unable to acquire TCPv6 socket: "+stringerror());
801
802    ComboAddress local(*laddr, ::arg().asNum("local-port"));
803
804    int tmp=1;
805    if(setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char*)&tmp,sizeof tmp)<0) {
806      L<<Logger::Error<<"Setsockopt failed"<<endl;
807      exit(1); 
808    }
809
810    if(bind(s, (const sockaddr*)&local, local.getSocklen())<0) {
811      L<<Logger::Error<<"binding to TCP socket: "<<strerror(errno)<<endl;
812      throw AhuException("Unable to bind to TCPv6 socket");
813    }
814   
815    listen(s,128);
816    L<<Logger::Error<<"TCPv6 server bound to "<<local.toStringWithPort()<<endl; // this gets %eth0 right
817    d_sockets.push_back(s);
818
819    struct pollfd pfd;
820    memset(&pfd, 0, sizeof(pfd));
821    pfd.fd = s;
822    pfd.events = POLLIN;
823
824    d_prfds.push_back(pfd);
825    d_highfd=max(s, d_highfd);
826  }
827#endif // WIN32
828}
829
830
831//! Start of TCP operations thread, we launch a new thread for each incoming TCP question
832void TCPNameserver::thread()
833{
834  struct timeval tv;
835  tv.tv_sec=1;
836  tv.tv_usec=0;
837  try {
838    for(;;) {
839      int fd;
840      struct sockaddr_in remote;
841      Utility::socklen_t addrlen=sizeof(remote);
842
843      int ret=poll(&d_prfds[0], d_prfds.size(), -1); // blocks, forever if need be
844      if(ret <= 0)
845        continue;
846
847      int sock=-1;
848      BOOST_FOREACH(const struct pollfd& pfd, d_prfds) {
849        if(pfd.revents == POLLIN) {
850          sock = pfd.fd;
851          addrlen=sizeof(remote);
852
853          if((fd=accept(sock, (sockaddr*)&remote, &addrlen))<0) {
854            L<<Logger::Error<<"TCP question accept error: "<<strerror(errno)<<endl;
855           
856            if(errno==EMFILE) {
857              L<<Logger::Error<<Logger::NTLog<<"TCP handler out of filedescriptors, exiting, won't recover from this"<<endl;
858              exit(1);
859            }
860          }
861          else {
862            pthread_t tid;
863            d_connectionroom_sem->wait(); // blocks if no connections are available
864
865            int room;
866            d_connectionroom_sem->getValue( &room);
867            if(room<1)
868              L<<Logger::Warning<<Logger::NTLog<<"Limit of simultaneous TCP connections reached - raise max-tcp-connections"<<endl;
869
870            if(pthread_create(&tid, 0, &doConnection, (void *)fd)) {
871              L<<Logger::Error<<"Error creating thread: "<<stringerror()<<endl;
872              d_connectionroom_sem->post();
873            }
874          }
875        }
876      }
877    }
878  }
879  catch(AhuException &AE) {
880    L<<Logger::Error<<"TCP Namerserver thread dying because of fatal error: "<<AE.reason<<endl;
881  }
882  catch(...) {
883    L<<Logger::Error<<"TCPNameserver dying because of an unexpected fatal error"<<endl;
884  }
885  exit(1); // take rest of server with us
886}
887
888
Note: See TracBrowser for help on using the browser.