From a6a5bb7c204130dd4f3ced74446798eb67ea6472 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Mon, 2 May 2011 15:34:42 +0200 Subject: [PATCH] Support for name lookups in -connect and -addnode * A new option -dns is introduced that enables name lookups in -connect and -addnode, which is not enabled by default, as it may be considered a security issue. * A Lookup function is added that supports retrieving one or more addresses based on a host name * CAddress constructors (optionally) support name lookups. * The different places in the source code that did name lookups are refactored to use NameLookup or CAddress instead (dns seeding, irc server lookup, getexternalip, ...). * Removed ToStringLog() from CAddress, and switched to ToString(), since it was empty. --- src/init.cpp | 4 +- src/irc.cpp | 38 +++++-------- src/net.cpp | 158 +++++++++++++++++++++++++++++++++++---------------- src/net.h | 62 +++++++------------- 4 files changed, 148 insertions(+), 114 deletions(-) diff --git a/src/init.cpp b/src/init.cpp index a8e93140b..7e8467534 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -158,6 +158,7 @@ bool AppInit2(int argc, char* argv[]) " -min \t\t " + _("Start minimized\n") + " -datadir= \t\t " + _("Specify data directory\n") + " -proxy= \t " + _("Connect through socks4 proxy\n") + + " -dns \t " + _("Allow DNS lookups for addnode and connect\n") + " -addnode= \t " + _("Add a node to connect to\n") + " -connect= \t\t " + _("Connect only to the specified node\n") + " -nolisten \t " + _("Don't accept connections from outside\n") + @@ -208,6 +209,7 @@ bool AppInit2(int argc, char* argv[]) } fDebug = GetBoolArg("-debug"); + fAllowDNS = GetBoolArg("-dns"); #ifndef __WXMSW__ fDaemon = GetBoolArg("-daemon"); @@ -458,7 +460,7 @@ bool AppInit2(int argc, char* argv[]) { foreach(string strAddr, mapMultiArgs["-addnode"]) { - CAddress addr(strAddr, NODE_NETWORK); + CAddress addr(strAddr, fAllowDNS); addr.nTime = 0; // so it won't relay unless successfully connected if (addr.IsValid()) AddAddress(addr); diff --git a/src/irc.cpp b/src/irc.cpp index 5adaf1165..4e3988924 100644 --- a/src/irc.cpp +++ b/src/irc.cpp @@ -41,7 +41,7 @@ bool DecodeAddress(string str, CAddress& addr) return false; memcpy(&tmp, &vch[0], sizeof(tmp)); - addr = CAddress(tmp.ip, tmp.port, NODE_NETWORK); + addr = CAddress(tmp.ip, ntohs(tmp.port), NODE_NETWORK); return true; } @@ -215,25 +215,15 @@ bool GetIPFromIRC(SOCKET hSocket, string strMyName, unsigned int& ipRet) return false; string strHost = str.substr(str.rfind("@")+1); - unsigned int a=0, b=0, c=0, d=0; - if (sscanf(strHost.c_str(), "%u.%u.%u.%u", &a, &b, &c, &d) == 4 && - inet_addr(strHost.c_str()) != INADDR_NONE) - { - printf("GetIPFromIRC() userhost is IP %s\n", strHost.c_str()); - ipRet = CAddress(strHost).ip; - } - else - { - // Hybrid IRC used by lfnet always returns IP when you userhost yourself, - // but in case another IRC is ever used this should work. - printf("GetIPFromIRC() got userhost %s\n", strHost.c_str()); - if (fUseProxy) - return false; - struct hostent* phostent = gethostbyname(strHost.c_str()); - if (!phostent || !phostent->h_addr_list || !phostent->h_addr_list[0]) - return false; - ipRet = *(u_long*)phostent->h_addr_list[0]; - } + // Hybrid IRC used by lfnet always returns IP when you userhost yourself, + // but in case another IRC is ever used this should work. + printf("GetIPFromIRC() got userhost %s\n", strHost.c_str()); + if (fUseProxy) + return false; + CAddress addr(strHost, 0, true); + if (!addr.IsValid()) + return false; + ipRet = addr.ip; return true; } @@ -276,9 +266,9 @@ void ThreadIRCSeed2(void* parg) if (!fTOR) { //struct hostent* phostent = gethostbyname("chat.freenode.net"); - struct hostent* phostent = gethostbyname("irc.lfnet.org"); - if (phostent && phostent->h_addr_list && phostent->h_addr_list[0]) - addrConnect = CAddress(*(u_long*)phostent->h_addr_list[0], htons(6667)); + CAddress addrIRC("irc.lfnet.org:6667", 0, true); + if (addrIRC.IsValid()) + addrConnect = addrIRC; } SOCKET hSocket; @@ -390,7 +380,7 @@ void ThreadIRCSeed2(void* parg) { addr.nTime = GetAdjustedTime(); if (AddAddress(addr, 51 * 60)) - printf("IRC got new address\n"); + printf("IRC got new address: %s\n", addr.ToString().c_str()); nGotIRCAddresses++; } else diff --git a/src/net.cpp b/src/net.cpp index a40365566..b7cf973d4 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -29,8 +29,9 @@ bool OpenNetworkConnection(const CAddress& addrConnect); // Global state variables // bool fClient = false; +bool fAllowDNS = false; uint64 nLocalServices = (fClient ? 0 : NODE_NETWORK); -CAddress addrLocalHost(0, 0, nLocalServices); +CAddress addrLocalHost("0.0.0.0", 0, false, nLocalServices); CNode* pnodeLocalHost = NULL; uint64 nLocalHostNonce = 0; array vnThreadsRunning; @@ -47,7 +48,7 @@ map mapAlreadyAskedFor; // Settings int fUseProxy = false; -CAddress addrProxy("127.0.0.1:9050"); +CAddress addrProxy("127.0.0.1",9050); @@ -92,7 +93,7 @@ bool ConnectSocket(const CAddress& addrConnect, SOCKET& hSocketRet) if (fProxy) { - printf("proxy connecting %s\n", addrConnect.ToStringLog().c_str()); + printf("proxy connecting %s\n", addrConnect.ToString().c_str()); char pszSocks4IP[] = "\4\1\0\0\0\0\0\0user"; memcpy(pszSocks4IP + 2, &addrConnect.port, 2); memcpy(pszSocks4IP + 4, &addrConnect.ip, 4); @@ -118,14 +119,81 @@ bool ConnectSocket(const CAddress& addrConnect, SOCKET& hSocketRet) printf("ERROR: Proxy returned error %d\n", pchRet[1]); return false; } - printf("proxy connected %s\n", addrConnect.ToStringLog().c_str()); + printf("proxy connected %s\n", addrConnect.ToString().c_str()); } hSocketRet = hSocket; return true; } +// portDefault is in host order +bool Lookup(const char *pszName, vector& vaddr, int nServices, int nMaxSolutions, bool fAllowLookup, int portDefault, bool fAllowPort) +{ + vaddr.clear(); + int port = portDefault; + char psz[256]; + char *pszHost = psz; + strlcpy(psz, pszName, sizeof(psz)); + if (fAllowPort) + { + char* pszColon = strrchr(psz+1,':'); + char *pszPortEnd = NULL; + int portParsed = pszColon ? strtoul(pszColon+1, &pszPortEnd, 10) : 0; + if (pszColon && pszPortEnd && pszPortEnd[0] == 0) + { + if (psz[0] == '[' && pszColon[-1] == ']') + { + // Future: enable IPv6 colon-notation inside [] + pszHost = psz+1; + pszColon[-1] = 0; + } + else + pszColon[0] = 0; + port = portParsed; + if (port < 0 || port > USHRT_MAX) + port = USHRT_MAX; + } + } + + struct in_addr addrIP; + if (inet_aton(pszHost, &addrIP)) + { + // valid IP address passed + vaddr.push_back(CAddress(addrIP.s_addr, port, nServices)); + return true; + } + + if (!fAllowLookup) + return false; + + struct hostent* phostent = gethostbyname(pszHost); + if (!phostent) + return false; + + if (phostent->h_addrtype != AF_INET) + return false; + char** ppAddr = phostent->h_addr_list; + while (*ppAddr != NULL && vaddr.size() != nMaxSolutions) + { + CAddress addr(((struct in_addr*)ppAddr[0])->s_addr, port, nServices); + if (addr.IsValid()) + vaddr.push_back(addr); + ppAddr++; + } + + return (vaddr.size() > 0); +} + +// portDefault is in host order +bool Lookup(const char *pszName, CAddress& addr, int nServices, bool fAllowLookup, int portDefault, bool fAllowPort) +{ + vector vaddr; + bool fRet = Lookup(pszName, vaddr, nServices, 1, fAllowLookup, portDefault, fAllowPort); + if (fRet) + addr = vaddr[0]; + return fRet; +} bool GetMyExternalIP2(const CAddress& addrConnect, const char* pszGet, const char* pszKeyword, unsigned int& ipRet) { @@ -161,7 +229,7 @@ bool GetMyExternalIP2(const CAddress& addrConnect, const char* pszGet, const cha strLine = strLine.substr(strspn(strLine.c_str(), " \t\n\r")); while (strLine.size() > 0 && isspace(strLine[strLine.size()-1])) strLine.resize(strLine.size()-1); - CAddress addr(strLine.c_str()); + CAddress addr(strLine,0,true); printf("GetMyExternalIP() received [%s] %s\n", strLine.c_str(), addr.ToString().c_str()); if (addr.ip == 0 || addr.ip == INADDR_NONE || !addr.IsRoutable()) return false; @@ -192,13 +260,13 @@ bool GetMyExternalIP(unsigned int& ipRet) // if (nHost == 1) { - addrConnect = CAddress("91.198.22.70:80"); // checkip.dyndns.org + addrConnect = CAddress("91.198.22.70",80); // checkip.dyndns.org if (nLookup == 1) { - struct hostent* phostent = gethostbyname("checkip.dyndns.org"); - if (phostent && phostent->h_addr_list && phostent->h_addr_list[0]) - addrConnect = CAddress(*(u_long*)phostent->h_addr_list[0], htons(80)); + CAddress addrIP("checkip.dyndns.org", 80, true); + if (addrIP.IsValid()) + addrConnect = addrIP; } pszGet = "GET / HTTP/1.1\r\n" @@ -211,13 +279,13 @@ bool GetMyExternalIP(unsigned int& ipRet) } else if (nHost == 2) { - addrConnect = CAddress("74.208.43.192:80"); // www.showmyip.com + addrConnect = CAddress("74.208.43.192", 80); // www.showmyip.com if (nLookup == 1) { - struct hostent* phostent = gethostbyname("www.showmyip.com"); - if (phostent && phostent->h_addr_list && phostent->h_addr_list[0]) - addrConnect = CAddress(*(u_long*)phostent->h_addr_list[0], htons(80)); + CAddress addrIP("www.showmyip.com", 80, true); + if (addrIP.IsValid()) + addrConnect = addrIP; } pszGet = "GET /simple/ HTTP/1.1\r\n" @@ -283,7 +351,7 @@ bool AddAddress(CAddress addr, int64 nTimePenalty) if (it == mapAddresses.end()) { // New address - printf("AddAddress(%s)\n", addr.ToStringLog().c_str()); + printf("AddAddress(%s)\n", addr.ToString().c_str()); mapAddresses.insert(make_pair(addr.GetKey(), addr)); CAddrDB().WriteAddress(addr); return true; @@ -479,7 +547,7 @@ CNode* ConnectNode(CAddress addrConnect, int64 nTimeout) /// debug print printf("trying connection %s lastseen=%.1fhrs lasttry=%.1fhrs\n", - addrConnect.ToStringLog().c_str(), + addrConnect.ToString().c_str(), (double)(addrConnect.nTime - GetAdjustedTime())/3600.0, (double)(addrConnect.nLastTry - GetAdjustedTime())/3600.0); @@ -491,7 +559,7 @@ CNode* ConnectNode(CAddress addrConnect, int64 nTimeout) if (ConnectSocket(addrConnect, hSocket)) { /// debug print - printf("connected %s\n", addrConnect.ToStringLog().c_str()); + printf("connected %s\n", addrConnect.ToString().c_str()); // Set to nonblocking #ifdef __WXMSW__ @@ -528,7 +596,7 @@ void CNode::CloseSocketDisconnect() { if (fDebug) printf("%s ", DateTimeStrFormat("%x %H:%M:%S", GetTime()).c_str()); - printf("disconnecting node %s\n", addr.ToStringLog().c_str()); + printf("disconnecting node %s\n", addr.ToString().c_str()); closesocket(hSocket); hSocket = INVALID_SOCKET; } @@ -715,7 +783,7 @@ void ThreadSocketHandler2(void* parg) } else { - printf("accepted connection %s\n", addr.ToStringLog().c_str()); + printf("accepted connection %s\n", addr.ToString().c_str()); CNode* pnode = new CNode(hSocket, addr, true); pnode->AddRef(); CRITICAL_BLOCK(cs_vNodes) @@ -892,7 +960,7 @@ void ThreadMapPort2(void* parg) printf("ThreadMapPort started\n"); char port[6]; - sprintf(port, "%d", ntohs(GetDefaultPort())); + sprintf(port, "%d", GetDefaultPort()); const char * rootdescurl = 0; const char * multicastif = 0; @@ -984,17 +1052,17 @@ void DNSAddressSeed() printf("Loading addresses from DNS seeds (could take a while)\n"); for (int seed_idx = 0; seed_idx < ARRAYLEN(strDNSSeed); seed_idx++) { - struct hostent* phostent = gethostbyname(strDNSSeed[seed_idx]); - if (!phostent) - continue; - - for (int host = 0; phostent->h_addr_list[host] != NULL; host++) { - CAddress addr(*(unsigned int*)phostent->h_addr_list[host], - GetDefaultPort(), NODE_NETWORK); - addr.nTime = 0; - if (addr.IsValid() && addr.GetByte(3) != 127) { - AddAddress(addr); - found++; + vector vaddr; + if (Lookup(strDNSSeed[seed_idx], vaddr, NODE_NETWORK, true)) + { + foreach (CAddress& addr, vaddr) + { + if (addr.GetByte(3) != 127) + { + addr.nTime = 0; + AddAddress(addr); + found++; + } } } } @@ -1080,7 +1148,7 @@ void ThreadOpenConnections2(void* parg) { foreach(string strAddr, mapMultiArgs["-connect"]) { - CAddress addr(strAddr, NODE_NETWORK); + CAddress addr(strAddr, fAllowDNS); if (addr.IsValid()) OpenNetworkConnection(addr); for (int i = 0; i < 10 && i < nLoop; i++) @@ -1098,7 +1166,7 @@ void ThreadOpenConnections2(void* parg) { foreach(string strAddr, mapMultiArgs["-addnode"]) { - CAddress addr(strAddr, NODE_NETWORK); + CAddress addr(strAddr, fAllowDNS); if (addr.IsValid()) { OpenNetworkConnection(addr); @@ -1209,7 +1277,7 @@ void ThreadOpenConnections2(void* parg) // Randomize the order in a deterministic way, putting the standard port first int64 nRandomizer = (uint64)(nStart * 4951 + addr.nLastTry * 9567851 + addr.ip * 7789) % (2 * 60 * 60); - if (addr.port != GetDefaultPort()) + if (addr.port != htons(GetDefaultPort())) nRandomizer += 2 * 60 * 60; // Last seen Base retry frequency @@ -1369,7 +1437,7 @@ bool BindListenPort(string& strError) { strError = ""; int nOne = 1; - addrLocalHost.port = GetDefaultPort(); + addrLocalHost.port = htons(GetDefaultPort()); #ifdef __WXMSW__ // Initialize Windows Sockets @@ -1421,7 +1489,7 @@ bool BindListenPort(string& strError) memset(&sockaddr, 0, sizeof(sockaddr)); sockaddr.sin_family = AF_INET; sockaddr.sin_addr.s_addr = INADDR_ANY; // bind to all IPs on this computer - sockaddr.sin_port = GetDefaultPort(); + sockaddr.sin_port = htons(GetDefaultPort()); if (::bind(hListenSocket, (struct sockaddr*)&sockaddr, sizeof(sockaddr)) == SOCKET_ERROR) { int nErr = WSAGetLastError(); @@ -1448,29 +1516,21 @@ bool BindListenPort(string& strError) void StartNode(void* parg) { if (pnodeLocalHost == NULL) - pnodeLocalHost = new CNode(INVALID_SOCKET, CAddress("127.0.0.1", nLocalServices)); + pnodeLocalHost = new CNode(INVALID_SOCKET, CAddress("127.0.0.1", 0, false, nLocalServices)); #ifdef __WXMSW__ // Get local host ip char pszHostName[1000] = ""; if (gethostname(pszHostName, sizeof(pszHostName)) != SOCKET_ERROR) { - struct hostent* phostent = gethostbyname(pszHostName); - if (phostent) - { - // Take the first IP that isn't loopback 127.x.x.x - for (int i = 0; phostent->h_addr_list[i] != NULL; i++) - printf("host ip %d: %s\n", i, CAddress(*(unsigned int*)phostent->h_addr_list[i]).ToStringIP().c_str()); - for (int i = 0; phostent->h_addr_list[i] != NULL; i++) - { - CAddress addr(*(unsigned int*)phostent->h_addr_list[i], GetDefaultPort(), nLocalServices); - if (addr.IsValid() && addr.GetByte(3) != 127) + vector vaddr; + if (NameLookup(pszHostName, vaddr, nLocalServices)) + foreach (const CAddress &addr, vaddr) + if (addr.GetByte(3) != 127) { addrLocalHost = addr; break; } - } - } } #else // Get local host ip @@ -1491,7 +1551,7 @@ void StartNode(void* parg) printf("ipv4 %s: %s\n", ifa->ifa_name, pszIP); // Take the first IP that isn't loopback 127.x.x.x - CAddress addr(*(unsigned int*)&s4->sin_addr, GetDefaultPort(), nLocalServices); + CAddress addr(*(unsigned int*)&s4->sin_addr, 0, nLocalServices); if (addr.IsValid() && addr.GetByte(3) != 127) { addrLocalHost = addr; diff --git a/src/net.h b/src/net.h index b3bd74da4..ea12b983e 100644 --- a/src/net.h +++ b/src/net.h @@ -12,7 +12,7 @@ extern int nBestHeight; -inline unsigned short GetDefaultPort() { return fTestNet ? htons(18333) : htons(8333); } +inline unsigned short GetDefaultPort() { return fTestNet ? 18333 : 8333; } static const unsigned int PUBLISH_HOPS = 5; enum { @@ -23,6 +23,8 @@ enum bool ConnectSocket(const CAddress& addrConnect, SOCKET& hSocketRet); +bool Lookup(const char *pszName, vector& vaddr, int nServices, int nMaxSolutions, bool fAllowLookup = false, int portDefault = 0, bool fAllowPort = false); +bool Lookup(const char *pszName, CAddress& addr, int nServices, bool fAllowLookup = false, int portDefault = 0, bool fAllowPort = false); bool GetMyExternalIP(unsigned int& ipRet); bool AddAddress(CAddress addr, int64 nTimePenalty=0); void AddressCurrentlyConnected(const CAddress& addr); @@ -156,7 +158,7 @@ public: { Init(); ip = ipIn; - port = (portIn == 0 ? GetDefaultPort() : portIn); + port = htons(portIn == 0 ? GetDefaultPort() : portIn); nServices = nServicesIn; } @@ -168,54 +170,38 @@ public: nServices = nServicesIn; } - explicit CAddress(const char* pszIn, uint64 nServicesIn=NODE_NETWORK) + explicit CAddress(const char* pszIn, int portIn, bool fNameLookup = false, uint64 nServicesIn=NODE_NETWORK) { Init(); - SetAddress(pszIn); - nServices = nServicesIn; + Lookup(pszIn, *this, nServicesIn, fNameLookup, portIn); } - explicit CAddress(string strIn, uint64 nServicesIn=NODE_NETWORK) + explicit CAddress(const char* pszIn, bool fNameLookup = false, uint64 nServicesIn=NODE_NETWORK) { Init(); - SetAddress(strIn.c_str()); - nServices = nServicesIn; + Lookup(pszIn, *this, nServicesIn, fNameLookup, 0, true); } - void Init() + explicit CAddress(string strIn, int portIn, bool fNameLookup = false, uint64 nServicesIn=NODE_NETWORK) { - nServices = NODE_NETWORK; - memcpy(pchReserved, pchIPv4, sizeof(pchReserved)); - ip = INADDR_NONE; - port = GetDefaultPort(); - nTime = 100000000; - nLastTry = 0; + Init(); + Lookup(strIn.c_str(), *this, nServicesIn, fNameLookup, portIn); } - bool SetAddress(const char* pszIn) + explicit CAddress(string strIn, bool fNameLookup = false, uint64 nServicesIn=NODE_NETWORK) { - ip = INADDR_NONE; - port = GetDefaultPort(); - char psz[100]; - strlcpy(psz, pszIn, sizeof(psz)); - unsigned int a=0, b=0, c=0, d=0, e=0; - if (sscanf(psz, "%u.%u.%u.%u:%u", &a, &b, &c, &d, &e) < 4) - return false; - char* pszPort = strchr(psz, ':'); - if (pszPort) - { - *pszPort++ = '\0'; - port = htons(atoi(pszPort)); - if (atoi(pszPort) < 0 || atoi(pszPort) > USHRT_MAX) - port = htons(USHRT_MAX); - } - ip = inet_addr(psz); - return IsValid(); + Init(); + Lookup(strIn.c_str(), *this, nServicesIn, fNameLookup, 0, true); } - bool SetAddress(string strIn) + void Init() { - return SetAddress(strIn.c_str()); + nServices = NODE_NETWORK; + memcpy(pchReserved, pchIPv4, sizeof(pchReserved)); + ip = INADDR_NONE; + port = htons(GetDefaultPort()); + nTime = 100000000; + nLastTry = 0; } IMPLEMENT_SERIALIZE @@ -330,11 +316,6 @@ public: return strprintf("%u", ntohs(port)); } - string ToStringLog() const - { - return ""; - } - string ToString() const { return strprintf("%u.%u.%u.%u:%u", GetByte(3), GetByte(2), GetByte(1), GetByte(0), ntohs(port)); @@ -460,6 +441,7 @@ public: extern bool fClient; +extern bool fAllowDNS; extern uint64 nLocalServices; extern CAddress addrLocalHost; extern CNode* pnodeLocalHost;