From: bert hubert Date: Thu, 8 Jan 2015 15:40:13 +0000 (+0100) Subject: recursor timestamps, recursor any address, auth consolidation: teach recursor about... X-Git-Tag: rec-3.7.0-rc1~46 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=b71b60ee73ef3c86f80a2179981eda2e61c4363f;p=pdns recursor timestamps, recursor any address, auth consolidation: teach recursor about how to properly reply from 0.0.0.0, :: teach recursor to measure 'received' timestamps, teach it to drop queries that have been sitting in a queue for a second already, add too-old-drops metric for this unify some code with the auth server --- diff --git a/pdns/iputils.cc b/pdns/iputils.cc index 11f8181af..2f09d5192 100644 --- a/pdns/iputils.cc +++ b/pdns/iputils.cc @@ -133,3 +133,21 @@ int sendfromto(int sock, const char* data, int len, int flags, const ComboAddres } return sendmsg(sock, &msgh, flags); } + +// be careful: when using this for receive purposes, make sure addr->sin4.sin_family is set appropriately so getSocklen works! +// be careful: when using this function for *send* purposes, be sure to set cbufsize to 0! +void fillMSGHdr(struct msghdr* msgh, struct iovec* iov, char* cbuf, size_t cbufsize, char* data, size_t datalen, ComboAddress* addr) +{ + iov->iov_base = data; + iov->iov_len = datalen; + + memset(msgh, 0, sizeof(struct msghdr)); + + msgh->msg_control = cbuf; + msgh->msg_controllen = cbufsize; + msgh->msg_name = addr; + msgh->msg_namelen = addr->getSocklen(); + msgh->msg_iov = iov; + msgh->msg_iovlen = 1; + msgh->msg_flags = 0; +} diff --git a/pdns/iputils.hh b/pdns/iputils.hh index 99abd3384..8ac7fb215 100644 --- a/pdns/iputils.hh +++ b/pdns/iputils.hh @@ -441,6 +441,5 @@ int SSetsockopt(int sockfd, int level, int opname, int value); bool IsAnyAddress(const ComboAddress& addr); bool HarvestDestinationAddress(struct msghdr* msgh, ComboAddress* destination); bool HarvestTimestamp(struct msghdr* msgh, struct timeval* tv); - - +void fillMSGHdr(struct msghdr* msgh, struct iovec* iov, char* cbuf, size_t cbufsize, char* data, size_t datalen, ComboAddress* addr); #endif diff --git a/pdns/nameserver.cc b/pdns/nameserver.cc index fca614170..99be86b99 100644 --- a/pdns/nameserver.cc +++ b/pdns/nameserver.cc @@ -295,14 +295,7 @@ void UDPNameserver::send(DNSPacket *p) else numanswered6++; - /* Set up iov and msgh structures. */ - memset(&msgh, 0, sizeof(struct msghdr)); - iov.iov_base = (void*)buffer.c_str(); - iov.iov_len = buffer.length(); - msgh.msg_iov = &iov; - msgh.msg_iovlen = 1; - msgh.msg_name = (struct sockaddr*)&p->d_remote; - msgh.msg_namelen = p->d_remote.getSocklen(); + fillMSGHdr(&msgh, &iov, cbuf, 0, (char*)buffer.c_str(), buffer.length(), &p->d_remote); if(p->d_anyLocal) { addCMsgSrcAddr(&msgh, cbuf, p->d_anyLocal.get_ptr()); @@ -327,18 +320,8 @@ DNSPacket *UDPNameserver::receive(DNSPacket *prefilled) struct iovec iov; char cbuf[256]; - iov.iov_base = mesg; - iov.iov_len = sizeof(mesg); - - memset(&msgh, 0, sizeof(struct msghdr)); - - msgh.msg_control = cbuf; - msgh.msg_controllen = sizeof(cbuf); - msgh.msg_name = &remote; - msgh.msg_namelen = sizeof(remote); - msgh.msg_iov = &iov; - msgh.msg_iovlen = 1; - msgh.msg_flags = 0; + remote.sin6.sin6_family=AF_INET6; // make sure it is big enough + fillMSGHdr(&msgh, &iov, cbuf, sizeof(cbuf), mesg, sizeof(mesg), &remote); int err; vector rfds= d_rfds; diff --git a/pdns/pdns_recursor.cc b/pdns/pdns_recursor.cc index 56568eb54..22811e0fe 100644 --- a/pdns/pdns_recursor.cc +++ b/pdns/pdns_recursor.cc @@ -149,6 +149,12 @@ struct DNSComboWriter { d_remote=*sa; } + void setLocal(const ComboAddress& sa) + { + d_local=sa; + } + + void setSocket(int sock) { d_socket=sock; @@ -160,7 +166,7 @@ struct DNSComboWriter { } struct timeval d_now; - ComboAddress d_remote; + ComboAddress d_remote, d_local; bool d_tcp; int d_socket; shared_ptr d_tcpConnection; @@ -596,7 +602,6 @@ void startDoResolve(void *p) } catch(ImmediateServFailException &e) { L<getRemote()<<" during resolve of '"<d_mdp.d_qname<<"' because: "<d_mdp.d_qtype, packet.size(), !dc->d_tcp); updateResponseStats(res, dc->d_remote, packet.size(), &dc->d_mdp.d_qname, dc->d_mdp.d_qtype); if(!dc->d_tcp) { - sendto(dc->d_socket, (const char*)&*packet.begin(), packet.size(), 0, (struct sockaddr *)(&dc->d_remote), dc->d_remote.getSocklen()); + struct msghdr msgh; + struct iovec iov; + char cbuf[256]; + fillMSGHdr(&msgh, &iov, cbuf, 0, (char*)&*packet.begin(), packet.size(), &dc->d_remote); + if(dc->d_local.sin4.sin_family) + addCMsgSrcAddr(&msgh, cbuf, &dc->d_local); + sendmsg(dc->d_socket, &msgh, 0); if(!SyncRes::s_nopacketcache && !variableAnswer ) { t_packetCache->insertResponsePacket(string((const char*)&*packet.begin(), packet.size()), g_now.tv_sec, @@ -913,8 +924,16 @@ void handleNewTCPQuestion(int fd, FDMultiplexer::funcparam_t& ) } } -string* doProcessUDPQuestion(const std::string& question, const ComboAddress& fromaddr, int fd) +string* doProcessUDPQuestion(const std::string& question, const ComboAddress& fromaddr, const ComboAddress& destaddr, struct timeval tv, int fd) { + struct timeval diff = g_now - tv; + double delta=(diff.tv_sec*1000 + diff.tv_usec/1000.0); + + if(delta > 1000.0) { + g_stats.tooOldDrops++; + return 0; + } + ++g_stats.qcounter; if(fromaddr.sin4.sin_family==AF_INET6) g_stats.ipv6qcounter++; @@ -930,7 +949,16 @@ string* doProcessUDPQuestion(const std::string& question, const ComboAddress& fr g_stats.packetCacheHits++; SyncRes::s_queries++; ageDNSPacket(response, age); - sendto(fd, response.c_str(), response.length(), 0, (struct sockaddr*) &fromaddr, fromaddr.getSocklen()); + struct msghdr msgh; + struct iovec iov; + char cbuf[256]; + fillMSGHdr(&msgh, &iov, cbuf, 0, (char*)response.c_str(), response.length(), const_cast(&fromaddr)); + if(destaddr.sin4.sin_family) { + cerr<<"Add!"<= sizeof(struct dnsheader)) { struct dnsheader dh; memcpy(&dh, response.c_str(), sizeof(dh)); @@ -956,21 +984,28 @@ string* doProcessUDPQuestion(const std::string& question, const ComboAddress& fr DNSComboWriter* dc = new DNSComboWriter(question.c_str(), question.size(), g_now); dc->setSocket(fd); dc->setRemote(&fromaddr); + dc->setLocal(destaddr); dc->d_tcp=false; MT->makeThread(startDoResolve, (void*) dc); // deletes dc return 0; } + void handleNewUDPQuestion(int fd, FDMultiplexer::funcparam_t& var) { int len; char data[1500]; ComboAddress fromaddr; - socklen_t addrlen=sizeof(fromaddr); - + struct msghdr msgh; + struct iovec iov; + char cbuf[256]; + + fromaddr.sin6.sin6_family=AF_INET6; // this makes sure fromaddr is big enough + fillMSGHdr(&msgh, &iov, cbuf, sizeof(cbuf), data, sizeof(data), &fromaddr); + for(;;) - if((len=recvfrom(fd, data, sizeof(data), 0, (sockaddr *)&fromaddr, &addrlen)) >= 0) { + if((len=recvmsg(fd, &msgh, 0)) >= 0) { if(t_remotes) t_remotes->push_back(fromaddr); @@ -1002,10 +1037,15 @@ void handleNewUDPQuestion(int fd, FDMultiplexer::funcparam_t& var) } else { string question(data, len); + struct timeval tv={0,0}; + HarvestTimestamp(&msgh, &tv); + ComboAddress dest; + memset(&dest, 0, sizeof(dest)); // this makes sure we igore this address if not returned by recvmsg above + HarvestDestinationAddress(&msgh, &dest); if(g_weDistributeQueries) - distributeAsyncFunction(question, boost::bind(doProcessUDPQuestion, question, fromaddr, fd)); + distributeAsyncFunction(question, boost::bind(doProcessUDPQuestion, question, fromaddr, dest, tv, fd)); else - doProcessUDPQuestion(question, fromaddr, fd); + doProcessUDPQuestion(question, fromaddr, dest, tv, fd); } } catch(MOADNSException& mde) { @@ -1096,10 +1136,6 @@ void makeUDPServerSockets() if(locals.empty()) throw PDNSException("No local address specified"); - if(::arg()["local-address"]=="0.0.0.0") { - L<::const_iterator i=locals.begin();i!=locals.end();++i) { ServiceTuple st; st.port=::arg().asNum("local-port"); @@ -1119,6 +1155,12 @@ void makeUDPServerSockets() if(fd < 0) { throw PDNSException("Making a UDP server socket for resolver: "+netstringerror()); } + setSocketTimestamps(fd); + int one; + if(IsAnyAddress(sin)) { + setsockopt(fd, IPPROTO_IP, GEN_IP_PKTINFO, &one, sizeof(one)); // linux supports this, so why not - might fail on other systems + setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &one, sizeof(one)); + } Utility::setCloseOnExec(fd); diff --git a/pdns/rec_channel_rec.cc b/pdns/rec_channel_rec.cc index 73ded636e..0c5600e6d 100644 --- a/pdns/rec_channel_rec.cc +++ b/pdns/rec_channel_rec.cc @@ -511,6 +511,7 @@ RecursorControlParser::RecursorControlParser() addGetStat("client-parse-errors", &g_stats.clientParseError); addGetStat("server-parse-errors", &g_stats.serverParseError); + addGetStat("too-old-drops", &g_stats.tooOldDrops); addGetStat("answers0-1", &g_stats.answers0_1); addGetStat("answers1-10", &g_stats.answers1_10); diff --git a/pdns/syncres.hh b/pdns/syncres.hh index d345dd91c..f92a4d44a 100644 --- a/pdns/syncres.hh +++ b/pdns/syncres.hh @@ -558,6 +558,7 @@ struct RecursorStats uint64_t tcpClientOverflow; uint64_t clientParseError; uint64_t serverParseError; + uint64_t tooOldDrops; uint64_t unexpectedCount; uint64_t caseMismatchCount; uint64_t spoofCount; diff --git a/pdns/toysdig.cc b/pdns/toysdig.cc index ed5323be5..707007c05 100644 --- a/pdns/toysdig.cc +++ b/pdns/toysdig.cc @@ -20,7 +20,7 @@ try Socket sock(AF_INET, SOCK_DGRAM); ComboAddress dest(argv[1] + (*argv[1]=='@'), atoi(argv[2])); - for(unsigned int n=0; n < 100; ++n) { + for(unsigned int n=0; n < 20000; ++n) { vector packet; string qname;