87
int TCPNameserver::readLength(int fd, struct sockaddr_in *remote)
92
Utility::socklen_t remotelen=sizeof(*remote);
93
getpeername(fd, (struct sockaddr *)remote, &remotelen);
96
int ret=waitForData(fd, s_timeout);
98
throw AhuException("Waiting on data from remote TCP client "+string(inet_ntoa(remote->sin_addr))+": "+stringerror());
100
ret=recv(fd, reinterpret_cast< char * >( buf ) +2-bytesLeft, bytesLeft,0);
102
throw AhuException("Trying to read data from remote TCP client "+string(inet_ntoa(remote->sin_addr))+": "+stringerror());
104
DLOG(L<<"Remote TCP client "+string(inet_ntoa(remote->sin_addr))+" closed connection");
109
return buf[0]*256+buf[1];
112
void TCPNameserver::getQuestion(int fd, char *mesg, int pktlen, const struct sockaddr_in &remote)
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)
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)
82
char *ptr = (char*)buffer;
85
ret=read(fd, ptr, bytes);
88
ret=waitForData(fd, 5);
90
throw AhuException("Waiting for data read");
92
throw AhuException("Timeout reading data");
96
throw AhuException("Reading data: "+stringerror());
99
if(!throwOnEOF && n == bytes)
102
throw AhuException("Did not fulfill read from TCP due to EOF");
112
void writenWithTimeout(int fd, const void *buffer, unsigned int n)
114
unsigned int bytes=n;
115
const char *ptr = (char*)buffer;
118
ret=write(fd, ptr, bytes);
121
ret=waitForRWData(fd, false, 5, 0);
123
throw AhuException("Waiting for data write");
125
throw AhuException("Timeout writing data");
129
throw AhuException("Writing data: "+stringerror());
132
throw AhuException("Did not fulfill TCP write due to EOF");
140
void connectWithTimeout(int fd, struct sockaddr* remote, size_t socklen)
143
Utility::socklen_t len=sizeof(err);
146
if((err=connect(fd, remote, socklen))<0 && errno!=EINPROGRESS)
148
if((err=connect(clisock, remote, socklen))<0 && WSAGetLastError() != WSAEWOULDBLOCK )
150
throw AhuException("connect: "+stringerror());
155
err=waitForRWData(fd, false, 5, 0);
157
throw AhuException("Timeout connecting to remote");
159
throw AhuException("Error connecting to remote");
161
if(getsockopt(fd, SOL_SOCKET,SO_ERROR,(char *)&err,&len)<0)
162
throw AhuException("Error connecting to remote: "+stringerror()); // Solaris
165
throw AhuException("Error connecting to remote: "+string(strerror(err)));
171
void TCPNameserver::sendPacket(shared_ptr<DNSPacket> p, int outsock)
173
const char *buf=p->getData();
174
uint16_t len=htons(p->len);
175
writenWithTimeout(outsock, &len, 2);
176
writenWithTimeout(outsock, buf, p->len);
180
void TCPNameserver::getQuestion(int fd, char *mesg, int pktlen, const ComboAddress &remote)
183
readnWithTimeout(fd, mesg, pktlen);
185
catch(AhuException& ae) {
186
throw AhuException("Error reading DNS data from TCP client "+remote.toString()+": "+ae.reason);
189
static void proxyQuestion(shared_ptr<DNSPacket> packet)
191
int sock=socket(AF_INET, SOCK_STREAM, 0);
193
throw AhuException("Error making TCP connection socket to recursor: "+stringerror());
195
Utility::setNonBlocking(sock);
198
parseService(arg()["recursor"],st);
201
ComboAddress recursor(st.host, st.port);
202
connectWithTimeout(sock, (struct sockaddr*)&recursor, recursor.getSocklen());
203
const string &buffer=packet->getString();
205
uint16_t len=htons(buffer.length()), slen;
207
writenWithTimeout(sock, &len, 2);
208
writenWithTimeout(sock, buffer.c_str(), buffer.length());
212
ret=readnWithTimeout(sock, &len, 2);
216
ret=readnWithTimeout(sock, answer, len);
219
writenWithTimeout(packet->getSocket(), &slen, 2);
221
writenWithTimeout(packet->getSocket(), answer, len);
223
catch(AhuException& ae) {
225
throw AhuException("While proxying a question to recursor "+st.host+": " +ae.reason);
125
throw AhuException("Error reading DNS data from TCP client "+string(inet_ntoa(remote.sin_addr))+": "+stringerror());
127
throw AhuException("Remote TCP client "+string(inet_ntoa(remote.sin_addr))+" closed connection");
130
231
void *TCPNameserver::doConnection(void *data)
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());
237
Utility::setNonBlocking(fd);
140
L<<Logger::Error<<"TCP server is without backend connections, launching"<<endl;
141
s_P=new PacketHandler;
146
241
DLOG(L<<"TCP Connection accepted on fd "<<fd<<endl);
149
struct sockaddr_in remote;
151
int pktlen=readLength(fd, &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;
252
if(!readnWithTimeout(fd, &pktlen, 2, false))
255
pktlen=ntohs(pktlen);
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;
160
262
getQuestion(fd,mesg,pktlen,remote);
161
263
S.inc("tcp-queries");
162
DNSPacket *packet=new DNSPacket;
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)
176
if(packet->d.rd && arg().mustDo("recursor")) {
178
// this is a pretty rare event all in all, so we can afford to be slow
180
// this code SHOULD attempt to answer from the local cache first!
181
S.inc("recursing-questions");
184
DLOG(L<<"About to hand query to recursor"<<endl);
187
parseService(arg()["recursor"],st);
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);
192
sendData(buffer,len,fd);
193
DLOG(L<<"sent out to customer: "<<len<<" bytes"<<endl);
195
S.inc("recursing-answers");
196
S.inc("tcp-answers");
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);
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)
284
sendPacket(cached, fd);
208
285
S.inc("tcp-answers");
216
290
Lock l(&s_plock);
217
reply=s_P->question(packet); // we really need to ask the backend :-)
292
L<<Logger::Error<<"TCP server is without backend connections, launching"<<endl;
293
s_P=new PacketHandler;
297
reply=shared_ptr<DNSPacket>(s_P->questionOrRecurse(packet.get(), &shouldRecurse)); // we really need to ask the backend :-)
300
proxyQuestion(packet);
222
305
if(!reply) // unable to write an answer?
225
308
S.inc("tcp-answers");
226
sendDelPacket(reply, fd);
309
sendPacket(reply, fd);
231
312
catch(DBException &e) {
232
313
Lock l(&s_plock);