2 * InspIRCd -- Internet Relay Chat Daemon
4 * Copyright (C) 2013, 2019 Sadie Powell <sadie@witchery.services>
5 * Copyright (C) 2013, 2016 Adam <Adam@anope.org>
6 * Copyright (C) 2012-2014, 2016 Attila Molnar <attilamolnar@hush.com>
7 * Copyright (C) 2012 Robby <robby@chatbelgie.be>
8 * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org>
9 * Copyright (C) 2007, 2010 Craig Edwards <brain@inspircd.org>
10 * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net>
11 * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org>
13 * This file is part of InspIRCd. InspIRCd is free software: you can
14 * redistribute it and/or modify it under the terms of the GNU General Public
15 * License as published by the Free Software Foundation, version 2.
17 * This program is distributed in the hope that it will be useful, but WITHOUT
18 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
19 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
22 * You should have received a copy of the GNU General Public License
23 * along with this program. If not, see <http://www.gnu.org/licenses/>.
29 #include "cachetimer.h"
30 #include "resolvers.h"
33 #include "treeserver.h"
35 #include "treesocket.h"
37 /** This class is used to resolve server hostnames during /connect and autoconnect.
38 * As of 1.1, the resolver system is seperated out from BufferedSocket, so we must do this
39 * resolver step first ourselves if we need it. This is totally nonblocking, and will
40 * callback to OnLookupComplete or OnError when completed. Once it has completed we
41 * will have an IP address which we can then use to continue our connection.
43 ServernameResolver::ServernameResolver(DNS::Manager* mgr, const std::string& hostname, Link* x, DNS::QueryType qt, Autoconnect* myac)
44 : DNS::Request(mgr, Utils->Creator, hostname, qt)
45 , query(qt), host(hostname), MyLink(x), myautoconnect(myac)
49 void ServernameResolver::OnLookupComplete(const DNS::Query *r)
51 const DNS::ResourceRecord* const ans_record = r->FindAnswerOfType(this->question.type);
58 irc::sockets::sockaddrs sa;
59 if (!irc::sockets::aptosa(ans_record->rdata, MyLink->Port, sa))
61 // We had a result but it wasn't a valid IPv4/IPv6.
66 /* Initiate the connection, now that we have an IP to use.
67 * Passing a hostname directly to BufferedSocket causes it to
68 * just bail and set its FD to -1.
70 TreeServer* CheckDupe = Utils->FindServer(MyLink->Name);
71 if (!CheckDupe) /* Check that nobody tried to connect it successfully while we were resolving */
73 TreeSocket* newsocket = new TreeSocket(MyLink, myautoconnect, sa);
74 if (newsocket->GetFd() > -1)
80 /* Something barfed, show the opers */
81 ServerInstance->SNO->WriteToSnoMask('l', "CONNECT: Error connecting \002%s\002: %s.",
82 MyLink->Name.c_str(), newsocket->getError().c_str());
83 ServerInstance->GlobalCulls.AddItem(newsocket);
88 void ServernameResolver::OnError(const DNS::Query *r)
90 if (r->error == DNS::ERROR_UNLOADED)
92 // We're being unloaded, skip the snotice and ConnectServer() below to prevent autoconnect creating new sockets
96 if (query == DNS::QUERY_AAAA)
98 ServernameResolver* snr = new ServernameResolver(this->manager, host, MyLink, DNS::QUERY_A, myautoconnect);
101 this->manager->Process(snr);
104 catch (DNS::Exception &)
110 ServerInstance->SNO->WriteToSnoMask('l', "CONNECT: Error connecting \002%s\002: Unable to resolve hostname - %s", MyLink->Name.c_str(), this->manager->GetErrorStr(r->error).c_str());
111 Utils->Creator->ConnectServer(myautoconnect, false);
114 SecurityIPResolver::SecurityIPResolver(Module* me, DNS::Manager* mgr, const std::string& hostname, Link* x, DNS::QueryType qt)
115 : DNS::Request(mgr, me, hostname, qt)
116 , MyLink(x), mine(me), host(hostname), query(qt)
120 void SecurityIPResolver::OnLookupComplete(const DNS::Query *r)
122 for (std::vector<reference<Link> >::iterator i = Utils->LinkBlocks.begin(); i != Utils->LinkBlocks.end(); ++i)
125 if (L->IPAddr == host)
127 for (std::vector<DNS::ResourceRecord>::const_iterator j = r->answers.begin(); j != r->answers.end(); ++j)
129 const DNS::ResourceRecord& ans_record = *j;
130 if (ans_record.type == this->question.type)
131 Utils->ValidIPs.push_back(ans_record.rdata);
138 void SecurityIPResolver::OnError(const DNS::Query *r)
140 // This can be called because of us being unloaded but we don't have to do anything differently
141 if (query == DNS::QUERY_AAAA)
143 SecurityIPResolver* res = new SecurityIPResolver(mine, this->manager, host, MyLink, DNS::QUERY_A);
146 this->manager->Process(res);
149 catch (DNS::Exception &)
154 ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Could not resolve IP associated with Link '%s': %s",
155 MyLink->Name.c_str(), this->manager->GetErrorStr(r->error).c_str());
158 CacheRefreshTimer::CacheRefreshTimer()
163 bool CacheRefreshTimer::Tick(time_t TIME)
165 Utils->RefreshIPCache();