~ubuntu-branches/ubuntu/maverick/pdns/maverick-updates

« back to all changes in this revision

Viewing changes to pdns/tcpreceiver.cc

  • Committer: Bazaar Package Importer
  • Author(s): Matthijs Mohlmann, Matthijs Mohlmann, Christoph Haas
  • Date: 2007-04-15 23:23:39 UTC
  • mfrom: (1.1.4 upstream)
  • Revision ID: james.westby@ubuntu.com-20070415232339-5x3scc8gx04e50um
Tags: 2.9.21-1
[ Matthijs Mohlmann ]
* New upstream release. (Closes: #420294)
* Remove meta pdns package.
* Added new sqlite3 backend package.
* Months and minutes where mixed up. (Closes: #406462)
* Case sensitivity in bind backend caused PowerDNS to not serve a certain
  zone. (Closes: #406461)
* Bind backend forgot about zones on a notify. (Closes: #398213)

[ Christoph Haas ]
* Documented incorporated backend bind. (Closes: #415471)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*
2
2
    PowerDNS Versatile Database Driven Nameserver
3
 
    Copyright (C) 2002-2005  PowerDNS.COM BV
 
3
    Copyright (C) 2002-2007  PowerDNS.COM BV
4
4
 
5
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
 
 
 
6
    it under the terms of the GNU General Public License version 2
 
7
    as published by the Free Software Foundation
 
8
    
10
9
    This program is distributed in the hope that it will be useful,
11
10
    but WITHOUT ANY WARRANTY; without even the implied warranty of
12
11
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
13
 
15
14
    You should have received a copy of the GNU General Public License
16
15
    along with this program; if not, write to the Free Software
17
 
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
16
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18
17
*/
19
18
#include "utility.hh"
20
19
#include <cstdio>
40
39
#include "statbag.hh"
41
40
#include "resolver.hh"
42
41
#include "communicator.hh"
 
42
using namespace boost;
43
43
 
44
44
extern PacketCache PC;
45
45
extern StatBag S;
55
55
int TCPNameserver::s_timeout;
56
56
NetmaskGroup TCPNameserver::d_ng;
57
57
 
58
 
int TCPNameserver::sendDelPacket(DNSPacket *p, int outsock)
59
 
{
60
 
  const char *buf=p->getData();
61
 
  int res=sendData(buf, p->len, outsock);
62
 
  delete p;
63
 
  return res;
64
 
}
65
 
 
66
58
void TCPNameserver::go()
67
59
{
68
60
  L<<Logger::Error<<"Creating backend connection for TCP"<<endl;
83
75
  return 0;
84
76
}
85
77
 
86
 
 
87
 
int TCPNameserver::readLength(int fd, struct sockaddr_in *remote)
88
 
{
89
 
  int bytesLeft=2;
90
 
  unsigned char buf[2];
91
 
  
92
 
  Utility::socklen_t remotelen=sizeof(*remote);
93
 
  getpeername(fd, (struct sockaddr *)remote, &remotelen);
94
 
 
95
 
  while(bytesLeft) {
96
 
    int ret=waitForData(fd, s_timeout);
97
 
    if(ret<0)
98
 
      throw AhuException("Waiting on data from remote TCP client "+string(inet_ntoa(remote->sin_addr))+": "+stringerror());
99
 
  
100
 
    ret=recv(fd, reinterpret_cast< char * >( buf ) +2-bytesLeft, bytesLeft,0);
101
 
    if(ret<0)
102
 
      throw AhuException("Trying to read data from remote TCP client "+string(inet_ntoa(remote->sin_addr))+": "+stringerror());
103
 
    if(!ret) {
104
 
      DLOG(L<<"Remote TCP client "+string(inet_ntoa(remote->sin_addr))+" closed connection");
105
 
      return -1;
106
 
    }
107
 
    bytesLeft-=ret;
108
 
  }
109
 
  return buf[0]*256+buf[1];
110
 
}
111
 
 
112
 
void TCPNameserver::getQuestion(int fd, char *mesg, int pktlen, const struct sockaddr_in &remote)
113
 
{
114
 
  int ret=0, bytesread=0;
115
 
  while(bytesread<pktlen) {
116
 
    if((ret=waitForData(fd,s_timeout))<0 || (ret=recv(fd,mesg+bytesread,pktlen-bytesread,0))<=0)
117
 
      goto err;
118
 
 
119
 
    bytesread+=ret;
120
 
  }
 
78
// throws AhuException if things didn't go according to plan, returns 0 if really 0 bytes were read
 
79
int readnWithTimeout(int fd, void* buffer, unsigned int n, bool throwOnEOF=true)
 
80
{
 
81
  unsigned int bytes=n;
 
82
  char *ptr = (char*)buffer;
 
83
  int ret;
 
84
  while(bytes) {
 
85
    ret=read(fd, ptr, bytes);
 
86
    if(ret < 0) {
 
87
      if(errno==EAGAIN) {
 
88
        ret=waitForData(fd, 5);
 
89
        if(ret < 0)
 
90
          throw AhuException("Waiting for data read");
 
91
        if(!ret)
 
92
          throw AhuException("Timeout reading data");
 
93
        continue;
 
94
      }
 
95
      else
 
96
        throw AhuException("Reading data: "+stringerror());
 
97
    }
 
98
    if(!ret) {
 
99
      if(!throwOnEOF && n == bytes)
 
100
        return 0;
 
101
      else
 
102
        throw AhuException("Did not fulfill read from TCP due to EOF");
 
103
    }
 
104
    
 
105
    ptr += ret;
 
106
    bytes -= ret;
 
107
  }
 
108
  return n;
 
109
}
 
110
 
 
111
// ditto
 
112
void writenWithTimeout(int fd, const void *buffer, unsigned int n)
 
113
{
 
114
  unsigned int bytes=n;
 
115
  const char *ptr = (char*)buffer;
 
116
  int ret;
 
117
  while(bytes) {
 
118
    ret=write(fd, ptr, bytes);
 
119
    if(ret < 0) {
 
120
      if(errno==EAGAIN) {
 
121
        ret=waitForRWData(fd, false, 5, 0);
 
122
        if(ret < 0)
 
123
          throw AhuException("Waiting for data write");
 
124
        if(!ret)
 
125
          throw AhuException("Timeout writing data");
 
126
        continue;
 
127
      }
 
128
      else
 
129
        throw AhuException("Writing data: "+stringerror());
 
130
    }
 
131
    if(!ret) {
 
132
      throw AhuException("Did not fulfill TCP write due to EOF");
 
133
    }
 
134
    
 
135
    ptr += ret;
 
136
    bytes -= ret;
 
137
  }
 
138
}
 
139
 
 
140
void connectWithTimeout(int fd, struct sockaddr* remote, size_t socklen)
 
141
{
 
142
  int err;
 
143
  Utility::socklen_t len=sizeof(err);
 
144
 
 
145
#ifndef WIN32
 
146
  if((err=connect(fd, remote, socklen))<0 && errno!=EINPROGRESS) 
 
147
#else
 
148
  if((err=connect(clisock, remote, socklen))<0 && WSAGetLastError() != WSAEWOULDBLOCK ) 
 
149
#endif // WIN32
 
150
    throw AhuException("connect: "+stringerror());
 
151
 
 
152
  if(!err)
 
153
    goto done;
 
154
  
 
155
  err=waitForRWData(fd, false, 5, 0);
 
156
  if(err == 0)
 
157
    throw AhuException("Timeout connecting to remote");
 
158
  if(err < 0)
 
159
    throw AhuException("Error connecting to remote");
 
160
 
 
161
  if(getsockopt(fd, SOL_SOCKET,SO_ERROR,(char *)&err,&len)<0)
 
162
    throw AhuException("Error connecting to remote: "+stringerror()); // Solaris
 
163
 
 
164
  if(err)
 
165
    throw AhuException("Error connecting to remote: "+string(strerror(err)));
 
166
 
 
167
 done:
 
168
  ;
 
169
}
 
170
 
 
171
void TCPNameserver::sendPacket(shared_ptr<DNSPacket> p, int outsock)
 
172
{
 
173
  const char *buf=p->getData();
 
174
  uint16_t len=htons(p->len);
 
175
  writenWithTimeout(outsock, &len, 2);
 
176
  writenWithTimeout(outsock, buf, p->len);
 
177
}
 
178
 
 
179
 
 
180
void TCPNameserver::getQuestion(int fd, char *mesg, int pktlen, const ComboAddress &remote)
 
181
try
 
182
{
 
183
  readnWithTimeout(fd, mesg, pktlen);
 
184
}
 
185
catch(AhuException& ae) {
 
186
    throw AhuException("Error reading DNS data from TCP client "+remote.toString()+": "+ae.reason);
 
187
}
 
188
 
 
189
static void proxyQuestion(shared_ptr<DNSPacket> packet)
 
190
{
 
191
  int sock=socket(AF_INET, SOCK_STREAM, 0);
 
192
  if(sock < 0)
 
193
    throw AhuException("Error making TCP connection socket to recursor: "+stringerror());
 
194
 
 
195
  Utility::setNonBlocking(sock);
 
196
  ServiceTuple st;
 
197
  st.port=53;
 
198
  parseService(arg()["recursor"],st);
 
199
 
 
200
  try {
 
201
    ComboAddress recursor(st.host, st.port);
 
202
    connectWithTimeout(sock, (struct sockaddr*)&recursor, recursor.getSocklen());
 
203
    const string &buffer=packet->getString();
 
204
    
 
205
    uint16_t len=htons(buffer.length()), slen;
 
206
    
 
207
    writenWithTimeout(sock, &len, 2);
 
208
    writenWithTimeout(sock, buffer.c_str(), buffer.length());
 
209
    
 
210
    int ret;
 
211
    
 
212
    ret=readnWithTimeout(sock, &len, 2);
 
213
    len=ntohs(len);
 
214
 
 
215
    char answer[len];
 
216
    ret=readnWithTimeout(sock, answer, len);
 
217
 
 
218
    slen=htons(len);
 
219
    writenWithTimeout(packet->getSocket(), &slen, 2);
 
220
    
 
221
    writenWithTimeout(packet->getSocket(), answer, len);
 
222
  }
 
223
  catch(AhuException& ae) {
 
224
    close(sock);
 
225
    throw AhuException("While proxying a question to recursor "+st.host+": " +ae.reason);
 
226
  }
 
227
  close(sock);
121
228
  return;
122
 
 
123
 
 err:;
124
 
  if(ret<0) 
125
 
    throw AhuException("Error reading DNS data from TCP client "+string(inet_ntoa(remote.sin_addr))+": "+stringerror());
126
 
  else 
127
 
    throw AhuException("Remote TCP client "+string(inet_ntoa(remote.sin_addr))+" closed connection");
128
229
}
129
230
 
130
231
void *TCPNameserver::doConnection(void *data)
131
232
{
 
233
  shared_ptr<DNSPacket> packet;
132
234
  // Fix gcc-4.0 error (on AMD64)
133
235
  int fd=(int)(long)data; // gotta love C (generates a harmless warning on opteron)
134
236
  pthread_detach(pthread_self());
135
 
 
 
237
  Utility::setNonBlocking(fd);
136
238
  try {
137
 
    {
138
 
      Lock l(&s_plock);
139
 
      if(!s_P) {
140
 
        L<<Logger::Error<<"TCP server is without backend connections, launching"<<endl;
141
 
        s_P=new PacketHandler;
142
 
      }
143
 
    }
144
239
    char mesg[512];
145
240
    
146
241
    DLOG(L<<"TCP Connection accepted on fd "<<fd<<endl);
147
242
    
148
243
    for(;;) {
149
 
      struct sockaddr_in remote;
150
 
      
151
 
      int pktlen=readLength(fd, &remote);
152
 
      if(pktlen<0) // EOF
153
 
        break;
 
244
      ComboAddress remote;
 
245
      socklen_t remotelen=sizeof(remote);
 
246
      if(getpeername(fd, (struct sockaddr *)&remote, &remotelen) < 0) {
 
247
        L<<Logger::Error<<"Received question from socket which had no remote address, dropping ("<<stringerror()<<")"<<endl;
 
248
        break;
 
249
      }
 
250
 
 
251
      uint16_t pktlen;
 
252
      if(!readnWithTimeout(fd, &pktlen, 2, false))
 
253
        break;
 
254
      else
 
255
        pktlen=ntohs(pktlen);
154
256
 
155
257
      if(pktlen>511) {
156
 
        L<<Logger::Error<<"Received an overly large question from "<<inet_ntoa(remote.sin_addr)<<", dropping"<<endl;
 
258
        L<<Logger::Error<<"Received an overly large question from "<<remote.toString()<<", dropping"<<endl;
157
259
        break;
158
260
      }
159
261
      
160
262
      getQuestion(fd,mesg,pktlen,remote);
161
263
      S.inc("tcp-queries");      
162
 
      DNSPacket *packet=new DNSPacket;
163
264
 
164
 
      packet->setRemote((struct sockaddr *)&remote,sizeof(remote));
 
265
      packet=shared_ptr<DNSPacket>(new DNSPacket);
 
266
      packet->setRemote(&remote);
165
267
      packet->d_tcp=true;
 
268
      packet->setSocket(fd);
166
269
      if(packet->parse(mesg, pktlen)<0)
167
270
        break;
168
271
      
172
275
        continue;
173
276
      }
174
277
 
175
 
 
176
 
      if(packet->d.rd && arg().mustDo("recursor")) {
177
 
        // now what
178
 
        // this is a pretty rare event all in all, so we can afford to be slow
179
 
 
180
 
        // this code SHOULD attempt to answer from the local cache first!
181
 
        S.inc("recursing-questions");
182
 
        Resolver res;
183
 
        unsigned int len;
184
 
        DLOG(L<<"About to hand query to recursor"<<endl);
185
 
        ServiceTuple st;
186
 
        st.port=53;
187
 
        parseService(arg()["recursor"],st);
188
 
 
189
 
        char *buffer=res.sendReceive(st.host,st.port,packet->getRaw(),packet->len,&len);
190
 
        DLOG(L<<"got an answer from recursor: "<<len<<" bytes, "<<(int)buffer<<endl);
191
 
        if(buffer) {
192
 
          sendData(buffer,len,fd);
193
 
          DLOG(L<<"sent out to customer: "<<len<<" bytes"<<endl);
194
 
          delete buffer;
195
 
          S.inc("recursing-answers");
196
 
          S.inc("tcp-answers");  
197
 
        }
198
 
        continue;
199
 
      }
200
 
 
201
 
      DNSPacket* cached=new DNSPacket;
202
 
      if(!packet->d.rd && (PC.get(packet, cached))) { // short circuit - does the PacketCache recognize this question?
203
 
        cached->setRemote((struct sockaddr *)(packet->remote), sizeof(struct sockaddr_in));
 
278
      shared_ptr<DNSPacket> reply; 
 
279
      shared_ptr<DNSPacket> cached= shared_ptr<DNSPacket>(new DNSPacket);
 
280
 
 
281
      if(!packet->d.rd && (PC.get(packet.get(), cached.get()))) { // short circuit - does the PacketCache recognize this question?
 
282
        cached->setRemote(&packet->remote);
204
283
        cached->spoofID(packet->d.id);
205
 
        if(sendDelPacket(cached, fd)<0) 
206
 
          goto out;
207
 
 
 
284
        sendPacket(cached, fd);
208
285
        S.inc("tcp-answers");
209
286
        continue;
210
287
      }
211
 
      else
212
 
        delete cached;
213
 
      
214
 
      DNSPacket *reply; 
 
288
        
215
289
      {
216
290
        Lock l(&s_plock);
217
 
        reply=s_P->question(packet); // we really need to ask the backend :-)
 
291
        if(!s_P) {
 
292
          L<<Logger::Error<<"TCP server is without backend connections, launching"<<endl;
 
293
          s_P=new PacketHandler;
 
294
        }
 
295
        bool shouldRecurse;
 
296
 
 
297
        reply=shared_ptr<DNSPacket>(s_P->questionOrRecurse(packet.get(), &shouldRecurse)); // we really need to ask the backend :-)
 
298
 
 
299
        if(shouldRecurse) {
 
300
          proxyQuestion(packet);
 
301
          continue;
 
302
        }
218
303
      }
219
304
 
220
 
      delete packet;
221
 
        
222
305
      if(!reply)  // unable to write an answer?
223
306
        break;
224
307
        
225
308
      S.inc("tcp-answers");
226
 
      sendDelPacket(reply, fd);
 
309
      sendPacket(reply, fd);
227
310
    }
228
 
    
229
 
  out:;
230
311
  }
231
312
  catch(DBException &e) {
232
313
    Lock l(&s_plock);
239
320
    Lock l(&s_plock);
240
321
    delete s_P;
241
322
    s_P = 0; // on next call, backend will be recycled
242
 
    L<<Logger::Error<<"TCP nameserver had error, cycling backend:"<<ae.reason<<endl;
 
323
    L<<Logger::Error<<"TCP nameserver had error, cycling backend: "<<ae.reason<<endl;
243
324
  }
244
325
  catch(exception &e) {
245
326
    L<<Logger::Error<<"TCP Connection Thread died because of STL error: "<<e.what()<<endl;
248
329
  {
249
330
    L << Logger::Error << "TCP Connection Thread caught unknown exception." << endl;
250
331
  }
 
332
  d_connectionroom_sem->post();
251
333
  Utility::closesocket(fd);
252
 
  d_connectionroom_sem->post();
253
334
 
254
335
  return 0;
255
336
}
256
337
 
257
 
bool TCPNameserver::canDoAXFR(DNSPacket *q)
 
338
bool TCPNameserver::canDoAXFR(shared_ptr<DNSPacket> q)
258
339
{
259
340
  if(arg().mustDo("disable-axfr"))
260
341
    return false;
261
342
 
262
 
  if( arg()["allow-axfr-ips"].empty() || d_ng.match( (struct sockaddr_in *) &q->remote ) )
 
343
  if( arg()["allow-axfr-ips"].empty() || d_ng.match( (ComboAddress *) &q->remote ) )
263
344
    return true;
264
345
 
265
346
  extern CommunicatorClass Communicator;
273
354
}
274
355
 
275
356
/** do the actual zone transfer. Return 0 in case of error, 1 in case of success */
276
 
int TCPNameserver::doAXFR(const string &target, DNSPacket *q, int outsock)
 
357
int TCPNameserver::doAXFR(const string &target, shared_ptr<DNSPacket> q, int outsock)
277
358
{
278
 
  DNSPacket *outpacket=0;
 
359
  shared_ptr<DNSPacket> outpacket;
279
360
  if(!canDoAXFR(q)) {
280
361
    L<<Logger::Error<<"AXFR of domain '"<<target<<"' denied to "<<q->getRemote()<<endl;
281
362
 
282
 
    outpacket=q->replyPacket();
 
363
    outpacket=shared_ptr<DNSPacket>(q->replyPacket());
283
364
    outpacket->setRcode(RCode::Refused); 
284
365
    // FIXME: should actually figure out if we are auth over a zone, and send out 9 if we aren't
285
 
    sendDelPacket(outpacket,outsock);
 
366
    sendPacket(outpacket,outsock);
286
367
    return 0;
287
368
  }
288
369
  L<<Logger::Error<<"AXFR of domain '"<<target<<"' initiated by "<<q->getRemote()<<endl;
289
 
  outpacket=q->replyPacket();
 
370
  outpacket=shared_ptr<DNSPacket>(q->replyPacket());
290
371
 
291
372
  DNSResourceRecord soa;  
292
373
  DNSResourceRecord rr;
299
380
    // find domain_id via SOA and list complete domain. No SOA, no AXFR
300
381
    
301
382
    DLOG(L<<"Looking for SOA"<<endl);
 
383
    if(!s_P) {
 
384
      L<<Logger::Error<<"TCP server is without backend connections in doAXFR, launching"<<endl;
 
385
      s_P=new PacketHandler;
 
386
    }
302
387
 
303
388
    if(!s_P->getBackend()->getSOA(target,sd)) {
304
389
      L<<Logger::Error<<"AXFR of domain '"<<target<<"' failed: not authoritative"<<endl;
305
390
      outpacket->setRcode(9); // 'NOTAUTH'
306
 
      sendDelPacket(outpacket,outsock);
 
391
      sendPacket(outpacket,outsock);
307
392
      return 0;
308
393
    }
309
394
 
311
396
  PacketHandler P; // now open up a database connection, we'll need it
312
397
 
313
398
  sd.db=(DNSBackend *)-1; // force uncached answer
314
 
  if(!P.getBackend()->getSOA(target,sd)) {
 
399
  if(!P.getBackend()->getSOA(target, sd)) {
315
400
      L<<Logger::Error<<"AXFR of domain '"<<target<<"' failed: not authoritative in second instance"<<endl;
316
401
    outpacket->setRcode(9); // 'NOTAUTH'
317
 
    sendDelPacket(outpacket,outsock);
 
402
    sendPacket(outpacket,outsock);
318
403
    return 0;
319
404
  }
320
405
 
321
406
  soa.qname=target;
322
407
  soa.qtype=QType::SOA;
323
 
  soa.content=DNSPacket::serializeSOAData(sd);
324
 
  soa.ttl=sd.default_ttl;
 
408
  soa.content=serializeSOAData(sd);
 
409
  soa.ttl=sd.ttl;
325
410
  soa.domain_id=sd.domain_id;
326
411
  soa.d_place=DNSResourceRecord::ANSWER;
327
412
    
328
413
  if(!sd.db || sd.db==(DNSBackend *)-1) {
329
414
    L<<Logger::Error<<"Error determining backend for domain '"<<target<<"' trying to serve an AXFR"<<endl;
330
415
    outpacket->setRcode(RCode::ServFail);
331
 
    sendDelPacket(outpacket,outsock);
 
416
    sendPacket(outpacket,outsock);
332
417
    return 0;
333
418
  }
334
419
 
340
425
  if(!(B->list(target, sd.domain_id))) {  
341
426
    L<<Logger::Error<<"Backend signals error condition"<<endl;
342
427
    outpacket->setRcode(2); // 'SERVFAIL'
343
 
    sendDelPacket(outpacket,outsock);
 
428
    sendPacket(outpacket,outsock);
344
429
    return 0;
345
430
  }
346
431
  /* write first part of answer */
347
432
 
348
433
  DLOG(L<<"Sending out SOA"<<endl);
349
434
  outpacket->addRecord(soa); // AXFR format begins and ends with a SOA record, so we add one
350
 
  sendDelPacket(outpacket, outsock);
 
435
  sendPacket(outpacket, outsock);
351
436
 
352
437
  /* now write all other records */
353
438
 
356
441
  if(arg().mustDo("strict-rfc-axfrs"))
357
442
    chunk=1;
358
443
 
359
 
  outpacket=q->replyPacket();
 
444
  outpacket=shared_ptr<DNSPacket>(q->replyPacket());
360
445
  outpacket->setCompress(false);
361
446
 
362
447
  while(B->get(rr)) {
368
453
    if(!((++count)%chunk)) {
369
454
      count=0;
370
455
    
371
 
      if(sendDelPacket(outpacket, outsock)<0)  // FIXME: this leaks memory!
372
 
        return 0;
 
456
      sendPacket(outpacket, outsock);
373
457
 
374
 
      outpacket=q->replyPacket();  
 
458
      outpacket=shared_ptr<DNSPacket>(q->replyPacket());
375
459
      outpacket->setCompress(false);
376
460
      // FIXME: Subsequent messages SHOULD NOT have a question section, though the final message MAY.
377
461
    }
378
462
  }
379
463
  if(count) {
380
 
    sendDelPacket(outpacket, outsock);
 
464
    sendPacket(outpacket, outsock);
381
465
  }
382
466
 
383
467
  DLOG(L<<"Done writing out records"<<endl);
384
468
  /* and terminate with yet again the SOA record */
385
 
  outpacket=q->replyPacket();
 
469
  outpacket=shared_ptr<DNSPacket>(q->replyPacket());
386
470
  outpacket->addRecord(soa);
387
 
  sendDelPacket(outpacket, outsock);
 
471
  sendPacket(outpacket, outsock);
388
472
  DLOG(L<<"last packet - close"<<endl);
389
473
  L<<Logger::Error<<"AXFR of domain '"<<target<<"' to "<<q->getRemote()<<" finished"<<endl;
390
474
 
408
492
  vector<string>locals6;
409
493
  stringtok(locals6,arg()["local-ipv6"]," ,");
410
494
 
411
 
 
412
495
  if(locals.empty() && locals6.empty())
413
496
    throw AhuException("No local address specified");
414
497
 
426
509
  FD_ZERO(&d_rfds);  
427
510
 
428
511
  for(vector<string>::const_iterator laddr=locals.begin();laddr!=locals.end();++laddr) {
429
 
    struct sockaddr_in local;
430
512
    int s=socket(AF_INET,SOCK_STREAM,0); 
431
513
 
432
514
    if(s<0) 
433
515
      throw AhuException("Unable to acquire TCP socket: "+stringerror());
434
 
    
435
 
    memset(&local,0,sizeof(local));
436
 
    local.sin_family=AF_INET;
437
 
 
438
 
    struct hostent *h;
439
 
    
440
 
    if ( *laddr == "0.0.0.0" )
441
 
    {
442
 
      local.sin_addr.s_addr = INADDR_ANY;
443
 
    }
444
 
    else 
445
 
    {
446
 
      h=gethostbyname(laddr->c_str());
447
 
  
448
 
      if(!h)
449
 
        throw AhuException("Unable to resolve local address '"+*laddr+"'");
450
 
 
451
 
      local.sin_addr.s_addr=*(int*)h->h_addr;
452
 
    }
 
516
 
 
517
    ComboAddress local(*laddr, arg().asNum("local-port"));
453
518
      
454
519
    int tmp=1;
455
520
    if(setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char*)&tmp,sizeof tmp)<0) {
457
522
      exit(1);  
458
523
    }
459
524
 
460
 
    local.sin_port=htons(arg().asNum("local-port"));
461
 
    
462
 
    if(bind(s, (sockaddr*)&local,sizeof(local))<0) {
 
525
    if(bind(s, (sockaddr*)&local, local.getSocklen())<0) {
463
526
      L<<Logger::Error<<"binding to TCP socket: "<<strerror(errno)<<endl;
464
527
      throw AhuException("Unable to bind to TCP socket");
465
528
    }
466
529
    
467
530
    listen(s,128);
468
 
    L<<Logger::Error<<"TCP server bound to "<<*laddr<<":"<<arg().asNum("local-port")<<endl;
 
531
    L<<Logger::Error<<"TCP server bound to "<<local.toStringWithPort()<<endl;
469
532
    d_sockets.push_back(s);
470
533
    FD_SET(s, &d_rfds);
471
534
    d_highfd=max(s,d_highfd);
472
535
  }
473
536
 
474
 
  // TODO: Implement ipv6
475
537
#if !WIN32 && HAVE_IPV6
476
538
  for(vector<string>::const_iterator laddr=locals6.begin();laddr!=locals6.end();++laddr) {
477
539
    int s=socket(AF_INET6,SOCK_STREAM,0); 
479
541
    if(s<0) 
480
542
      throw AhuException("Unable to acquire TCPv6 socket: "+stringerror());
481
543
 
482
 
    sockaddr_in6 locala;
483
 
    locala.sin6_port=ntohs(arg().asNum("local-port"));
484
 
    locala.sin6_family=AF_INET6;
485
 
    locala.sin6_flowinfo=0;
486
 
 
487
 
 
488
 
    if(!inet_pton(AF_INET6, laddr->c_str(), (void *)&locala.sin6_addr)) {
489
 
      addrinfo *addrinfos;
490
 
      addrinfo hints;
491
 
      memset(&hints,0,sizeof(hints));
492
 
      hints.ai_socktype=SOCK_STREAM;
493
 
      hints.ai_family=AF_INET6;
494
 
      
495
 
      if(getaddrinfo(laddr->c_str(),arg()["local-port"].c_str(),&hints,&addrinfos)) 
496
 
        throw AhuException("Unable to resolve local IPv6 address '"+*laddr+"'"); 
497
 
 
498
 
      memcpy(&locala,addrinfos->ai_addr,addrinfos->ai_addrlen);
499
 
    }
 
544
    ComboAddress local(*laddr, arg().asNum("local-port"));
500
545
 
501
546
    int tmp=1;
502
547
    if(setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char*)&tmp,sizeof tmp)<0) {
504
549
      exit(1);  
505
550
    }
506
551
 
507
 
 
508
 
    if(bind(s, (const sockaddr*)&locala, sizeof(locala))<0) {
 
552
    if(bind(s, (const sockaddr*)&local, local.getSocklen())<0) {
509
553
      L<<Logger::Error<<"binding to TCP socket: "<<strerror(errno)<<endl;
510
554
      throw AhuException("Unable to bind to TCPv6 socket");
511
555
    }
512
556
    
513
557
    listen(s,128);
514
 
    L<<Logger::Error<<"TCPv6 server bound to ["<<*laddr<<"]:"<<arg()["local-port"]<<endl;
 
558
    L<<Logger::Error<<"TCPv6 server bound to "<<local.toStringWithPort()<<endl;
515
559
    d_sockets.push_back(s);
516
560
    FD_SET(s, &d_rfds);
517
561
    d_highfd=max(s,d_highfd);
520
564
}
521
565
 
522
566
 
523
 
//! Start of TCP operations thread
 
567
//! Start of TCP operations thread, we launch a new thread for each incoming TCP question
524
568
void TCPNameserver::thread()
525
569
{
526
570
  struct timeval tv;
534
578
 
535
579
      fd_set rfds=d_rfds; 
536
580
 
537
 
      int ret=select(d_highfd+1, &rfds, 0, 0,  0); // blocks
 
581
      int ret=select(d_highfd+1, &rfds, 0, 0,  0); // blocks, forever if need be
538
582
      if(ret <= 0)
539
583
        continue;
540
584