From: Bert Hubert Date: Tue, 5 Jul 2005 22:33:29 +0000 (+0000) Subject: first shot at working TCP resolving code on receipt of packet with TC bit (f.e.,... X-Git-Tag: pdns-2.9.18~16 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=5c63364010df662292e9eebfb4c86a32ad78a8f2;p=pdns first shot at working TCP resolving code on receipt of packet with TC bit (f.e., www.kde-look.org) only use if desperate, very fresh code git-svn-id: svn://svn.powerdns.com/pdns/trunk/pdns@433 d19b8d6e-7fed-0310-83ef-9ca221ded41b --- diff --git a/pdns/lwres.cc b/pdns/lwres.cc index a50415cb2..cf77c93f7 100644 --- a/pdns/lwres.cc +++ b/pdns/lwres.cc @@ -35,7 +35,8 @@ #include "ahuexception.hh" #include "statbag.hh" #include "arguments.hh" - +#include "sstuff.hh" +#include "syncres.hh" LWRes::LWRes() { @@ -55,7 +56,7 @@ LWRes::~LWRes() //! returns -1 for permanent error, 0 for timeout, 1 for success /** Never throws! */ -int LWRes::asyncresolve(const string &ip, const char *domain, int type) +int LWRes::asyncresolve(const string &ip, const char *domain, int type, bool doTCP) { DNSPacket p; p.setQuestion(Opcode::Query,domain,type); @@ -69,6 +70,7 @@ int LWRes::asyncresolve(const string &ip, const char *domain, int type) struct sockaddr_in toaddr; struct in_addr inp; + Utility::socklen_t addrlen=sizeof(toaddr); Utility::inet_aton(ip.c_str(),&inp); toaddr.sin_addr.s_addr=inp.s_addr; @@ -79,16 +81,53 @@ int LWRes::asyncresolve(const string &ip, const char *domain, int type) DTime dt; dt.set(); - if(asendto(p.getData(), p.len, 0, (struct sockaddr*)(&toaddr), sizeof(toaddr),p.d.id)<0) { - return -1; + + if(!doTCP) { + if(asendto(p.getData(), p.len, 0, (struct sockaddr*)(&toaddr), sizeof(toaddr),p.d.id)<0) { + return -1; + } + + // sleep until we see an answer to this, interface to mtasker + + ret=arecvfrom(reinterpret_cast(d_buf), d_bufsize-1,0,(struct sockaddr*)(&toaddr), &addrlen, &d_len, p.d.id); } + else { + Socket s(InterNetwork, Stream); + IPEndpoint ie(ip, 53); + s.setNonBlocking(); + s.connect(ie); + + int len=htons(p.len); + char *lenP=(char*)&len; + const char *msgP=p.getData(); + string packet=string(lenP, lenP+2)+string(msgP, msgP+p.len); + + if(asendtcp(packet, &s) == 0) { + cerr<<"asendtcp: timeout"<(d_buf), d_bufsize-1,0,(struct sockaddr*)(&toaddr), &addrlen, &d_len, p.d.id); - d_usec=dt.udiff(); + packet.clear(); + if(arecvtcp(packet,2, &s)==0) { + cerr<<"arecvtcp: timeout"< res_t; - int asyncresolve(const string &ip, const char *domain, int type); + int asyncresolve(const string &ip, const char *domain, int type, bool doTCP); vector result(); int d_rcode; - bool d_aabit; + bool d_aabit, d_tcbit; u_int32_t d_usec; private: int d_sock; @@ -78,8 +78,6 @@ private: u_int32_t d_ip; bool d_inaxfr; int d_bufsize; - - }; #endif // PDNS_LWRES_HH diff --git a/pdns/pdns_recursor.cc b/pdns/pdns_recursor.cc index 5bfe6293a..7c89a86d0 100644 --- a/pdns/pdns_recursor.cc +++ b/pdns/pdns_recursor.cc @@ -36,6 +36,12 @@ #include "syncres.hh" #include #include +#include "sstuff.hh" +#include +#include + +using namespace boost; + #include "recursor_cache.hh" #ifdef __FreeBSD__ // see cvstrac ticket #26 @@ -74,29 +80,74 @@ static int d_clientsock; static vector d_udpserversocks; static vector d_tcpserversocks; + struct PacketID { - u_int16_t id; - struct sockaddr_in remote; + PacketID() : sock(0), inNeeded(0), outPos(0) + {} + + u_int16_t id; // wait for a specific id/remote paie + struct sockaddr_in remote; // this is the remote + + Socket* sock; // or wait for an event on a TCP fd + int inNeeded; // if this is set, we'll read until inNeeded bytes are read + string inMSG; // they'll go here + + string outMSG; // the outgoing message that needs to be sent + int outPos; // how far we are along in the outMSG + + bool operator<(const PacketID& b) const + { + int ourSock= sock ? sock->getHandle() : 0; + int bSock = b.sock ? b.sock->getHandle() : 0; + return + tie(id, remote.sin_addr.s_addr, remote.sin_port, ourSock) < + tie(b.id, b.remote.sin_addr.s_addr, b.remote.sin_port, bSock); + } }; -bool operator<(const PacketID& a, const PacketID& b) +static map d_tcpclientreadsocks, d_tcpclientwritesocks; + +MTasker* MT; + +int asendtcp(const string& data, Socket* sock) +{ + PacketID pident; + pident.sock=sock; + pident.outMSG=data; + string packet; + + // cerr<<"asendtcp called for "<getHandle()]=pident; + + if(!MT->waitEvent(pident,&packet,1)) { // timeout + d_tcpclientwritesocks.erase(sock->getHandle()); + return 0; + } + // cerr<<"asendtcp happy"<getHandle()]=pident; + + if(!MT->waitEvent(pident,&data,1)) { // timeout + d_tcpclientreadsocks.erase(sock->getHandle()); + return 0; } - return false; + // cerr<<"arecvtcp happy, data.size(): "<* MT; /* these two functions are used by LWRes */ int asendto(const char *data, int len, int flags, struct sockaddr *toaddr, int addrlen, int id) @@ -205,7 +256,7 @@ void startDoResolve(void *p) if(!quiet) { L<getTid()<<"] answer to "<<(P.d.rd?"":"non-rd ")<<"question '"<d.ancount)<<" answers, "<d.arcount)<<" additional, took "<numProcesses()<<" queries running, "<numProcesses()<<" queries running, "<::const_iterator i=d_tcpclientreadsocks.begin(); i!=d_tcpclientreadsocks.end(); ++i) { + // cerr<<"Adding TCP socket "<first<<" to read select set"<first, &readfds ); + fdmax=max(fdmax,i->first); + } + + for(map::const_iterator i=d_tcpclientwritesocks.begin(); i!=d_tcpclientwritesocks.end(); ++i) { + // cerr<<"Adding TCP socket "<first<<" to write select set"<first, &writefds ); + fdmax=max(fdmax,i->first); + } - int selret = select( fdmax + 1, &readfds, NULL, NULL, &tv ); + int selret = select( fdmax + 1, &readfds, &writefds, NULL, &tv ); if(selret<=0) if (selret == -1 && errno!=EINTR) throw AhuException("Select returned: "+stringerror()); @@ -562,7 +625,6 @@ int main(int argc, char **argv) } else { if(P.d.qr) { - pident.remote=fromaddr; pident.id=P.d.id; string packet; @@ -614,6 +676,65 @@ int main(int argc, char **argv) } } + for(map::iterator i=d_tcpclientreadsocks.begin(); i!=d_tcpclientreadsocks.end();) { + if(FD_ISSET(i->first, &readfds)) { // can we receive + // cerr<<"Something happened on our socket when we wanted to read "<first<second.inMSG.size()<second.inNeeded]; + int ret=read(i->first, buffer, min(i->second.inNeeded,200)); + // cerr<<"Read returned "< 0) { + i->second.inMSG.append(buffer, buffer+ret); + i->second.inNeeded-=ret; + if(!i->second.inNeeded) { + // cerr<<"Got entire load of "<second.inMSG.size()<<" bytes"<second; + string msg=i->second.inMSG; + + d_tcpclientreadsocks.erase((i++)); + MT->sendEvent(pid, &msg); // XXX DODGY + } + else { + // cerr<<"Still have "<second.inNeeded<<" left to go"<first<<" available for writing"<first, i->second.outMSG.c_str(), i->second.outMSG.size() - i->second.outPos); + if(ret > 0) { + i->second.outPos+=ret; + if(i->second.outPos==i->second.outMSG.size()) { + // cerr<<"Sent out entire load of "<second.outMSG.size()<<" bytes"<second; + d_tcpclientwritesocks.erase((i++)); + MT->sendEvent(pid, 0); + // cerr<<"Sent event too"<::iterator i=tcpconnections.begin();i!=tcpconnections.end();++i) { if(FD_ISSET(i->fd, &readfds)) { if(i->state==TCPConnection::BYTE0) { diff --git a/pdns/sstuff.hh b/pdns/sstuff.hh index eb75e91ad..35546d84d 100755 --- a/pdns/sstuff.hh +++ b/pdns/sstuff.hh @@ -162,7 +162,7 @@ public: remote.sin_addr.s_addr=ep.address.byte; remote.sin_port=htons(ep.port); - if(::connect(d_socket,(struct sockaddr *)&remote,sizeof(remote))<0) + if(::connect(d_socket,(struct sockaddr *)&remote,sizeof(remote)) < 0 && errno != EINPROGRESS) throw NetworkError(strerror(errno)); } diff --git a/pdns/syncres.cc b/pdns/syncres.cc index 769beaedc..d7384a1dd 100644 --- a/pdns/syncres.cc +++ b/pdns/syncres.cc @@ -39,6 +39,7 @@ map SyncRes::s_negcache; unsigned int SyncRes::s_queries; unsigned int SyncRes::s_outgoingtimeouts; unsigned int SyncRes::s_outqueries; +unsigned int SyncRes::s_tcpoutqueries; unsigned int SyncRes::s_throttledqueries; unsigned int SyncRes::s_nodelegated; bool SyncRes::s_log; @@ -89,7 +90,6 @@ int SyncRes::doResolve(const string &qname, const QType &qtype, vector SyncRes::shuffle(set &nameservers, const string &p } L< nameservers, string auth, const string &qna } LOG< nameservers, string auth, const string &qna else { s_outqueries++; d_outqueries++; - int ret=d_lwr.asyncresolve(remoteIP,qname.c_str(),qtype.getCode()); - if(ret != 1) { // <- we go out on the wire! + TryTCP: + if(doTCP) { + s_tcpoutqueries++; + d_tcpoutqueries++; + } + + int ret=d_lwr.asyncresolve(remoteIP, qname.c_str(), qtype.getCode(), doTCP); // <- we go out on the wire! + if(ret != 1) { if(ret==0) { LOG< nameservers, string auth, const string &qna // for ANY answers we *must* have an authoritive answer else if(i->d_place==DNSResourceRecord::ANSWER && toLower(i->qname)==toLower(qname) && (((i->qtype==qtype) || (i->qtype.getCode()>1024 && i->qtype.getCode()-1024==qtype.getCode())) || ( qtype==QType(QType::ANY) && - d_lwr.d_aabit))) { if(i->qtype.getCode() < 1024) { LOG<content<<"|"<qtype.getName()<<"'"< nameservers, string auth, const string &qna return doResolve(newtarget, qtype, ret,0,beenthere2); } if(nsset.empty() && !d_lwr.d_rcode) { + if(!negindic && d_lwr.d_tcbit) { + if(!doTCP) { + doTCP=true; + LOG<&ret); void setId(int id) { @@ -138,8 +138,10 @@ public: static unsigned int s_outgoingtimeouts; static unsigned int s_throttledqueries; static unsigned int s_outqueries; + static unsigned int s_tcpoutqueries; static unsigned int s_nodelegated; unsigned int d_outqueries; + unsigned int d_tcpoutqueries; unsigned int d_throttledqueries; unsigned int d_timeouts; static map s_negcache; @@ -185,4 +187,7 @@ private: }; }; +class Socket; +int asendtcp(const string& data, Socket* sock); +int arecvtcp(string& data, int len, Socket* sock); #endif