From df4f0dc888a2a24e7f8b42a1c21670679e633506 Mon Sep 17 00:00:00 2001 From: brain Date: Sun, 19 Aug 2007 16:00:57 +0000 Subject: [PATCH] Allow support for multiple dns results per request. This is a significant change and should probably not be backported to stable. This will allow for a fix to feature request bug #384 git-svn-id: http://svn.inspircd.org/repository/trunk/inspircd@7753 e03df62e-2008-0410-955e-edbf42e46eb7 --- include/dns.h | 7 +- include/users.h | 3 +- src/dns.cpp | 93 ++++++++++++++---------- src/modules/extra/m_pgsql.cpp | 13 ++-- src/modules/m_cgiirc.cpp | 5 +- src/modules/m_dnsbl.cpp | 2 +- src/modules/m_http_client.cpp | 5 +- src/modules/m_spanningtree/resolvers.cpp | 5 +- src/modules/m_spanningtree/resolvers.h | 4 +- src/users.cpp | 6 +- 10 files changed, 88 insertions(+), 55 deletions(-) diff --git a/include/dns.h b/include/dns.h index b00c57201..adb9fdab8 100644 --- a/include/dns.h +++ b/include/dns.h @@ -286,8 +286,10 @@ class CoreExport Resolver : public Extensible * result, this is the number of seconds remaining before refresh/expiry. * @param cached True if the result is a cached result, false if it was requested * from the DNS server. + * @param resultnum Result number, for records with multiple matching results. + * Normally, you will only want to act on this when the result is 0. */ - virtual void OnLookupComplete(const std::string &result, unsigned int ttl, bool cached) = 0; + virtual void OnLookupComplete(const std::string &result, unsigned int ttl, bool cached, int resultnum = 0) = 0; /** * If an error occurs (such as NXDOMAIN, no domain name found) then this method * will be called. @@ -439,8 +441,9 @@ class CoreExport DNS : public EventHandler /** * Fetch the result string (an ip or host) * and/or an error message to go with it. + * @param resultnum Result number to fetch */ - DNSResult GetResult(); + DNSResult GetResult(int resultnum); /** * Handle a SocketEngine read event diff --git a/include/users.h b/include/users.h index 0443b24d2..a2d89b0a7 100644 --- a/include/users.h +++ b/include/users.h @@ -106,8 +106,9 @@ class CoreExport UserResolver : public Resolver * @param result Result string * @param ttl Time to live for result * @param cached True if the result was found in the cache + * @param resultnum Result number, we are only interested in result 0 */ - void OnLookupComplete(const std::string &result, unsigned int ttl, bool cached); + void OnLookupComplete(const std::string &result, unsigned int ttl, bool cached, int resultnum = 0); /** Called on failed lookup * @param e Error code diff --git a/src/dns.cpp b/src/dns.cpp index 292ca00ac..a714794bf 100644 --- a/src/dns.cpp +++ b/src/dns.cpp @@ -104,7 +104,7 @@ class DNSRequest DNSRequest(InspIRCd* Instance, DNS* dns, int id, const std::string &original); ~DNSRequest(); - DNSInfo ResultIsReady(DNSHeader &h, int length); + DNSInfo ResultIsReady(DNSHeader &h, int length, int result_we_want); int SendRequests(const DNSHeader *header, const int length, QueryType qt); }; @@ -612,7 +612,7 @@ void DNS::MakeIP6Int(char* query, const in6_addr *ip) } /** Return the next id which is ready, and the result attached to it */ -DNSResult DNS::GetResult() +DNSResult DNS::GetResult(int resultnum) { /* Fetch dns query response and decide where it belongs */ DNSHeader header; @@ -702,7 +702,7 @@ DNSResult DNS::GetResult() * When its finished it will return a DNSInfo which is a pair of * unsigned char* resource record data, and an error message. */ - DNSInfo data = req->ResultIsReady(header, length); + DNSInfo data = req->ResultIsReady(header, length, resultnum); std::string resultstr; /* Check if we got a result, if we didnt, its an error */ @@ -787,7 +787,7 @@ DNSResult DNS::GetResult() } /** A result is ready, process it */ -DNSInfo DNSRequest::ResultIsReady(DNSHeader &header, int length) +DNSInfo DNSRequest::ResultIsReady(DNSHeader &header, int length, int result_we_want) { int i = 0; int q = 0; @@ -857,7 +857,9 @@ DNSInfo DNSRequest::ResultIsReady(DNSHeader &header, int length) return std::make_pair((unsigned char*)NULL,"Incorrectly sized DNS reply"); /* XXX: We actually initialise 'rr' here including its ttl field */ - DNS::FillResourceRecord(&rr,&header.payload[i]); + if (curanswer == result_we_want) + DNS::FillResourceRecord(&rr,&header.payload[i]); + i += 10; if (rr.type != this->type) { @@ -874,7 +876,7 @@ DNSInfo DNSRequest::ResultIsReady(DNSHeader &header, int length) break; } if ((unsigned int)curanswer == header.ancount) - return std::make_pair((unsigned char*)NULL,"No valid answers"); + return std::make_pair((unsigned char*)NULL,"No more records"); if (i + rr.rdlength > (unsigned int)length) return std::make_pair((unsigned char*)NULL,"Resource record larger than stated"); @@ -930,7 +932,7 @@ DNSInfo DNSRequest::ResultIsReady(DNSHeader &header, int length) res[rr.rdlength] = 0; break; } - return std::make_pair(res,"No error");; + return std::make_pair(res,"No error"); } /** Close the master socket */ @@ -959,7 +961,7 @@ void DNS::DelCache(const std::string &source) void Resolver::TriggerCachedResult() { if (CQ) - OnLookupComplete(CQ->data, time_left, true); + OnLookupComplete(CQ->data, time_left, true, 0); } /** High level abstraction of dns used by application at large */ @@ -1062,47 +1064,60 @@ Module* Resolver::GetCreator() void DNS::HandleEvent(EventType et, int errornum) { /* Fetch the id and result of the next available packet */ - DNSResult res = this->GetResult(); - /* Is there a usable request id? */ - if (res.id != -1) + int resultnum = 0; + DNSResult res(0,"",0,""); + res.id = 0; + ServerInstance->Log(DEBUG,"Handle DNS event"); + while ((res.id & ERROR_MASK) == 0) { - /* Its an error reply */ - if (res.id & ERROR_MASK) + res = this->GetResult(resultnum); + + ServerInstance->Log(DEBUG,"Result %d id %d", resultnum, res.id); + + /* Is there a usable request id? */ + if (res.id != -1) { - /* Mask off the error bit */ - res.id -= ERROR_MASK; - /* Marshall the error to the correct class */ - if (Classes[res.id]) + /* Its an error reply */ + if (res.id & ERROR_MASK) { - if (ServerInstance && ServerInstance->stats) - ServerInstance->stats->statsDnsBad++; - Classes[res.id]->OnError(RESOLVER_NXDOMAIN, res.result); - delete Classes[res.id]; - Classes[res.id] = NULL; + /* Mask off the error bit */ + res.id -= ERROR_MASK; + /* Marshall the error to the correct class */ + if (Classes[res.id]) + { + if (ServerInstance && ServerInstance->stats) + ServerInstance->stats->statsDnsBad++; + Classes[res.id]->OnError(RESOLVER_NXDOMAIN, res.result); + delete Classes[res.id]; + Classes[res.id] = NULL; + } + break; } - } - else - { - /* It is a non-error result, marshall the result to the correct class */ - if (Classes[res.id]) + else { - if (ServerInstance && ServerInstance->stats) - ServerInstance->stats->statsDnsGood++; - - if (!this->GetCache(res.original.c_str())) - this->cache->insert(std::make_pair(res.original.c_str(), CachedQuery(res.result, res.ttl))); - - Classes[res.id]->OnLookupComplete(res.result, res.ttl, false); - delete Classes[res.id]; - Classes[res.id] = NULL; + /* It is a non-error result, marshall the result to the correct class */ + if (Classes[res.id]) + { + if (ServerInstance && ServerInstance->stats) + ServerInstance->stats->statsDnsGood++; + + if (!this->GetCache(res.original.c_str())) + this->cache->insert(std::make_pair(res.original.c_str(), CachedQuery(res.result, res.ttl))); + + Classes[res.id]->OnLookupComplete(res.result, res.ttl, false, resultnum); + delete Classes[res.id]; + Classes[res.id] = NULL; + } } + + if (ServerInstance && ServerInstance->stats) + ServerInstance->stats->statsDns++; } - if (ServerInstance && ServerInstance->stats) - ServerInstance->stats->statsDns++; + resultnum++; } } - + /** Add a derived Resolver to the working set */ bool DNS::AddResolverClass(Resolver* r) { diff --git a/src/modules/extra/m_pgsql.cpp b/src/modules/extra/m_pgsql.cpp index 5d267fc1a..393cbd1d7 100644 --- a/src/modules/extra/m_pgsql.cpp +++ b/src/modules/extra/m_pgsql.cpp @@ -107,7 +107,7 @@ class SQLresolver : public Resolver { } - virtual void OnLookupComplete(const std::string &result, unsigned int ttl, bool cached); + virtual void OnLookupComplete(const std::string &result, unsigned int ttl, bool cached, int resultnum = 0); virtual void OnError(ResolverError e, const std::string &errormessage) { @@ -963,11 +963,14 @@ class ModulePgSQL : public Module /* move this here to use AddConn, rather that than having the whole * module above SQLConn, since this is buggin me right now :/ */ -void SQLresolver::OnLookupComplete(const std::string &result, unsigned int ttl, bool cached) +void SQLresolver::OnLookupComplete(const std::string &result, unsigned int ttl, bool cached, int resultnum) { - host.ip = result; - ((ModulePgSQL*)mod)->AddConn(host); - ((ModulePgSQL*)mod)->ClearOldConnections(); + if (!resultnum) + { + host.ip = result; + ((ModulePgSQL*)mod)->AddConn(host); + ((ModulePgSQL*)mod)->ClearOldConnections(); + } } void ReconnectTimer::Tick(time_t time) diff --git a/src/modules/m_cgiirc.cpp b/src/modules/m_cgiirc.cpp index d82705d81..c99d6b5eb 100644 --- a/src/modules/m_cgiirc.cpp +++ b/src/modules/m_cgiirc.cpp @@ -91,8 +91,11 @@ class CGIResolver : public Resolver CGIResolver(Module* me, InspIRCd* ServerInstance, bool NotifyOpers, const std::string &source, bool forward, userrec* u, int userfd, const std::string &type, bool &cached) : Resolver(ServerInstance, source, forward ? DNS_QUERY_A : DNS_QUERY_PTR4, cached, me), typ(type), theirfd(userfd), them(u), notify(NotifyOpers) { } - virtual void OnLookupComplete(const std::string &result, unsigned int ttl, bool cached) + virtual void OnLookupComplete(const std::string &result, unsigned int ttl, bool cached, int resultnum = 0) { + if (resultnum) + return; + /* Check the user still exists */ if ((them) && (them == ServerInstance->SE->GetRef(theirfd))) { diff --git a/src/modules/m_dnsbl.cpp b/src/modules/m_dnsbl.cpp index d07b268f7..aaf4de05c 100644 --- a/src/modules/m_dnsbl.cpp +++ b/src/modules/m_dnsbl.cpp @@ -60,7 +60,7 @@ class DNSBLResolver : public Resolver ConfEntry = conf; } - virtual void OnLookupComplete(const std::string &result, unsigned int ttl, bool cached) + virtual void OnLookupComplete(const std::string &result, unsigned int ttl, bool cached, int resultnum = 0) { /* Check the user still exists */ if ((them) && (them == ServerInstance->SE->GetRef(theirfd))) diff --git a/src/modules/m_http_client.cpp b/src/modules/m_http_client.cpp index 35b93b581..7e1b94f11 100644 --- a/src/modules/m_http_client.cpp +++ b/src/modules/m_http_client.cpp @@ -56,9 +56,10 @@ class HTTPResolver : public Resolver { } - void OnLookupComplete(const string &result, unsigned int ttl, bool cached) + void OnLookupComplete(const string &result, unsigned int ttl, bool cached, int resultnum = 0) { - socket->Connect(result); + if (!resultnum) + socket->Connect(result); } void OnError(ResolverError e, const string &errmsg) diff --git a/src/modules/m_spanningtree/resolvers.cpp b/src/modules/m_spanningtree/resolvers.cpp index 0d94da99f..ac14833a5 100644 --- a/src/modules/m_spanningtree/resolvers.cpp +++ b/src/modules/m_spanningtree/resolvers.cpp @@ -43,8 +43,11 @@ ServernameResolver::ServernameResolver(Module* me, SpanningTreeUtilities* Util, /* Nothing in here, folks */ } -void ServernameResolver::OnLookupComplete(const std::string &result, unsigned int ttl, bool cached) +void ServernameResolver::OnLookupComplete(const std::string &result, unsigned int ttl, bool cached, int resultnum) { + if (resultnum) + return; + /* Initiate the connection, now that we have an IP to use. * Passing a hostname directly to InspSocket causes it to * just bail and set its FD to -1. diff --git a/src/modules/m_spanningtree/resolvers.h b/src/modules/m_spanningtree/resolvers.h index 06fd05bad..53adaa50f 100644 --- a/src/modules/m_spanningtree/resolvers.h +++ b/src/modules/m_spanningtree/resolvers.h @@ -45,7 +45,7 @@ class SecurityIPResolver : public Resolver { } - void OnLookupComplete(const std::string &result, unsigned int ttl, bool cached) + void OnLookupComplete(const std::string &result, unsigned int ttl, bool cached, int resultnum = 0) { Utils->ValidIPs.push_back(result); } @@ -83,7 +83,7 @@ class ServernameResolver : public Resolver Module* mine; public: ServernameResolver(Module* me, SpanningTreeUtilities* Util, InspIRCd* Instance, const std::string &hostname, Link x, bool &cached, QueryType qt); - void OnLookupComplete(const std::string &result, unsigned int ttl, bool cached); + void OnLookupComplete(const std::string &result, unsigned int ttl, bool cached, int resultnum = 0); void OnError(ResolverError e, const std::string &errormessage); }; diff --git a/src/users.cpp b/src/users.cpp index cbf9de0cd..bc8dc51e4 100644 --- a/src/users.cpp +++ b/src/users.cpp @@ -164,8 +164,12 @@ UserResolver::UserResolver(InspIRCd* Instance, userrec* user, std::string to_res this->bound_fd = user->GetFd(); } -void UserResolver::OnLookupComplete(const std::string &result, unsigned int ttl, bool cached) +void UserResolver::OnLookupComplete(const std::string &result, unsigned int ttl, bool cached, int resultnum) { + /* We are only interested in the first matching result */ + if (resultnum) + return; + if ((!this->fwd) && (ServerInstance->SE->GetRef(this->bound_fd) == this->bound_user)) { this->bound_user->stored_host = result; -- 2.39.5