From c2c4de7267db9835e36132364f422ba7d93f25d6 Mon Sep 17 00:00:00 2001 From: Peter Powell Date: Thu, 7 Feb 2019 15:34:41 +0000 Subject: [PATCH] Fix linking servers with UNIX sockets. - Remove the address/port overloads of BeginConnect. - Change DoConnect to take a sockaddrs instead of an address/port. --- include/inspsocket.h | 8 ++---- src/inspsocket.cpp | 25 ++--------------- src/modules/m_spanningtree/main.cpp | 32 ++++++++++------------ src/modules/m_spanningtree/resolvers.cpp | 10 ++++++- src/modules/m_spanningtree/treesocket.h | 2 +- src/modules/m_spanningtree/treesocket1.cpp | 14 ++++++++-- src/modules/m_spanningtree/utils.cpp | 2 +- 7 files changed, 43 insertions(+), 50 deletions(-) diff --git a/include/inspsocket.h b/include/inspsocket.h index 69fdaac8b..a41c3ebc7 100644 --- a/include/inspsocket.h +++ b/include/inspsocket.h @@ -380,12 +380,11 @@ class CoreExport BufferedSocket : public StreamSocket * This will create a socket, register with socket engine, and start the asynchronous * connection process. If an error is detected at this point (such as out of file descriptors), * OnError will be called; otherwise, the state will become CONNECTING. - * @param ipaddr Address to connect to - * @param aport Port to connect on + * @param dest Remote endpoint to connect to. + * @param bind Local endpoint to connect from. * @param maxtime Time to wait for connection - * @param connectbindip Address to bind to (if NULL, no bind will be done) */ - void DoConnect(const std::string& ipaddr, int aport, unsigned int maxtime, const std::string& connectbindip); + void DoConnect(const irc::sockets::sockaddrs& dest, const irc::sockets::sockaddrs& bind, unsigned int maxtime); /** This method is called when an outbound connection on your socket is * completed. @@ -412,7 +411,6 @@ class CoreExport BufferedSocket : public StreamSocket protected: void OnEventHandlerWrite() CXX11_OVERRIDE; BufferedSocketError BeginConnect(const irc::sockets::sockaddrs& dest, const irc::sockets::sockaddrs& bind, unsigned int timeout); - BufferedSocketError BeginConnect(const std::string& ipaddr, int aport, unsigned int maxtime, const std::string& connectbindip); }; inline IOHook* StreamSocket::GetIOHook() const { return iohook; } diff --git a/src/inspsocket.cpp b/src/inspsocket.cpp index ebbff448e..59d9558a4 100644 --- a/src/inspsocket.cpp +++ b/src/inspsocket.cpp @@ -48,9 +48,9 @@ BufferedSocket::BufferedSocket(int newfd) SocketEngine::AddFd(this, FD_WANT_FAST_READ | FD_WANT_EDGE_WRITE); } -void BufferedSocket::DoConnect(const std::string& ipaddr, int aport, unsigned int maxtime, const std::string& connectbindip) +void BufferedSocket::DoConnect(const irc::sockets::sockaddrs& dest, const irc::sockets::sockaddrs& bind, unsigned int maxtime) { - BufferedSocketError err = BeginConnect(ipaddr, aport, maxtime, connectbindip); + BufferedSocketError err = BeginConnect(dest, bind, maxtime); if (err != I_ERR_NONE) { state = I_ERROR; @@ -59,27 +59,6 @@ void BufferedSocket::DoConnect(const std::string& ipaddr, int aport, unsigned in } } -BufferedSocketError BufferedSocket::BeginConnect(const std::string& ipaddr, int aport, unsigned int maxtime, const std::string& connectbindip) -{ - irc::sockets::sockaddrs addr, bind; - if (!irc::sockets::aptosa(ipaddr, aport, addr)) - { - ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "BUG: Hostname passed to BufferedSocket, rather than an IP address!"); - return I_ERR_CONNECT; - } - - bind.sa.sa_family = 0; - if (!connectbindip.empty()) - { - if (!irc::sockets::aptosa(connectbindip, 0, bind)) - { - return I_ERR_BIND; - } - } - - return BeginConnect(addr, bind, maxtime); -} - BufferedSocketError BufferedSocket::BeginConnect(const irc::sockets::sockaddrs& dest, const irc::sockets::sockaddrs& bind, unsigned int timeout) { if (fd < 0) diff --git a/src/modules/m_spanningtree/main.cpp b/src/modules/m_spanningtree/main.cpp index 920840f9b..8b24b1e22 100644 --- a/src/modules/m_spanningtree/main.cpp +++ b/src/modules/m_spanningtree/main.cpp @@ -198,40 +198,38 @@ void ModuleSpanningTree::ConnectServer(Autoconnect* a, bool on_timer) void ModuleSpanningTree::ConnectServer(Link* x, Autoconnect* y) { - bool ipvalid = true; - if (InspIRCd::Match(ServerInstance->Config->ServerName, x->Name, ascii_case_insensitive_map)) { ServerInstance->SNO->WriteToSnoMask('l', "CONNECT: Not connecting to myself."); return; } + irc::sockets::sockaddrs sa; #ifndef _WIN32 if (x->IPAddr.find('/') != std::string::npos) { struct stat sb; - if (stat(x->IPAddr.c_str(), &sb) == -1 || !S_ISSOCK(sb.st_mode)) - ipvalid = false; - } -#endif - if (x->IPAddr.find(':') != std::string::npos) - { - in6_addr n; - if (inet_pton(AF_INET6, x->IPAddr.c_str(), &n) < 1) - ipvalid = false; + if (stat(x->IPAddr.c_str(), &sb) == -1 || !S_ISSOCK(sb.st_mode) || !irc::sockets::untosa(x->IPAddr, sa)) + { + // We don't use the family() != AF_UNSPEC check below for UNIX sockets as + // that results in a DNS lookup. + ServerInstance->SNO->WriteToSnoMask('l', "CONNECT: Error connecting \002%s\002: %s is not a UNIX socket!", + x->Name.c_str(), x->IPAddr.c_str()); + return; + } } else +#endif { - in_addr n; - if (inet_pton(AF_INET, x->IPAddr.c_str(),&n) < 1) - ipvalid = false; + // If this fails then the IP sa will be AF_UNSPEC. + irc::sockets::aptosa(x->IPAddr, x->Port, sa); } - + /* Do we already have an IP? If so, no need to resolve it. */ - if (ipvalid) + if (sa.family() != AF_UNSPEC) { // Create a TreeServer object that will start connecting immediately in the background - TreeSocket* newsocket = new TreeSocket(x, y, x->IPAddr); + TreeSocket* newsocket = new TreeSocket(x, y, sa); if (newsocket->GetFd() > -1) { /* Handled automatically on success */ diff --git a/src/modules/m_spanningtree/resolvers.cpp b/src/modules/m_spanningtree/resolvers.cpp index ded0573af..b20b100dd 100644 --- a/src/modules/m_spanningtree/resolvers.cpp +++ b/src/modules/m_spanningtree/resolvers.cpp @@ -49,6 +49,14 @@ void ServernameResolver::OnLookupComplete(const DNS::Query *r) return; } + irc::sockets::sockaddrs sa; + if (!irc::sockets::aptosa(ans_record->rdata, MyLink->Port, sa)) + { + // We had a result but it wasn't a valid IPv4/IPv6. + OnError(r); + return; + } + /* Initiate the connection, now that we have an IP to use. * Passing a hostname directly to BufferedSocket causes it to * just bail and set its FD to -1. @@ -56,7 +64,7 @@ void ServernameResolver::OnLookupComplete(const DNS::Query *r) TreeServer* CheckDupe = Utils->FindServer(MyLink->Name); if (!CheckDupe) /* Check that nobody tried to connect it successfully while we were resolving */ { - TreeSocket* newsocket = new TreeSocket(MyLink, myautoconnect, ans_record->rdata); + TreeSocket* newsocket = new TreeSocket(MyLink, myautoconnect, sa); if (newsocket->GetFd() > -1) { /* We're all OK */ diff --git a/src/modules/m_spanningtree/treesocket.h b/src/modules/m_spanningtree/treesocket.h index 6206448c1..547c87195 100644 --- a/src/modules/m_spanningtree/treesocket.h +++ b/src/modules/m_spanningtree/treesocket.h @@ -164,7 +164,7 @@ class TreeSocket : public BufferedSocket * most of the action, and append a few of our own values * to it. */ - TreeSocket(Link* link, Autoconnect* myac, const std::string& ipaddr); + TreeSocket(Link* link, Autoconnect* myac, const irc::sockets::sockaddrs& sa); /** When a listening socket gives us a new file descriptor, * we must associate it with a socket without creating a new diff --git a/src/modules/m_spanningtree/treesocket1.cpp b/src/modules/m_spanningtree/treesocket1.cpp index 062d04222..fd20d04c4 100644 --- a/src/modules/m_spanningtree/treesocket1.cpp +++ b/src/modules/m_spanningtree/treesocket1.cpp @@ -36,7 +36,7 @@ * BufferedSocket, we just call DoConnect() for most of the action, * and only do minor initialization tasks ourselves. */ -TreeSocket::TreeSocket(Link* link, Autoconnect* myac, const std::string& ipaddr) +TreeSocket::TreeSocket(Link* link, Autoconnect* myac, const irc::sockets::sockaddrs& dest) : linkID(link->Name), LinkState(CONNECTING), MyRoot(NULL), proto_version(0) , burstsent(false), age(ServerInstance->Time()) { @@ -45,7 +45,17 @@ TreeSocket::TreeSocket(Link* link, Autoconnect* myac, const std::string& ipaddr) capab->ac = myac; capab->capab_phase = 0; - DoConnect(ipaddr, link->Port, link->Timeout, link->Bind); + irc::sockets::sockaddrs bind; + memset(&bind, 0, sizeof(bind)); + if ((dest.family() == AF_INET || dest.family() == AF_INET6) && !irc::sockets::aptosa(link->Bind, 0, bind)) + { + state = I_ERROR; + SetError("Bind address '" + link->Bind + "' is not an valid IPv4 or IPv6 address"); + TreeSocket::OnError(I_ERR_BIND); + return; + } + + DoConnect(dest, bind, link->Timeout); Utils->timeoutlist[this] = std::pair(linkID, link->Timeout); SendCapabilities(1); } diff --git a/src/modules/m_spanningtree/utils.cpp b/src/modules/m_spanningtree/utils.cpp index 1f2ed9c90..f78b8d4c0 100644 --- a/src/modules/m_spanningtree/utils.cpp +++ b/src/modules/m_spanningtree/utils.cpp @@ -303,7 +303,7 @@ void SpanningTreeUtilities::ReadConfiguration() ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Configuration warning: Link block '" + L->Name + "' has no IP defined! This will allow any IP to connect as this server, and MAY not be what you want."); } - if (!L->Port) + if (!L->Port && L->IPAddr.find('/') == std::string::npos) ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Configuration warning: Link block '" + L->Name + "' has no port defined, you will not be able to /connect it."); L->Fingerprint.erase(std::remove(L->Fingerprint.begin(), L->Fingerprint.end(), ':'), L->Fingerprint.end()); -- 2.39.2