123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365 |
- // ECOin - Copyright (c) - 2014/2021 - GPLv3 - epsylon@riseup.net (https://03c8.net)
- #include "irc.h"
- #include "net.h"
- #include "strlcpy.h"
- #include "base58.h"
- using namespace std;
- using namespace boost;
- int nGotIRCAddresses = 0;
- void ThreadIRCSeed2(void* parg);
- #pragma pack(push, 1)
- struct ircaddr
- {
- struct in_addr ip;
- short port;
- };
- #pragma pack(pop)
- string EncodeAddress(const CService& addr)
- {
- struct ircaddr tmp;
- if (addr.GetInAddr(&tmp.ip))
- {
- tmp.port = htons(addr.GetPort());
- vector<unsigned char> vch(UBEGIN(tmp), UEND(tmp));
- return string("u") + EncodeBase58Check(vch);
- }
- return "";
- }
- bool DecodeAddress(string str, CService& addr)
- {
- vector<unsigned char> vch;
- if (!DecodeBase58Check(str.substr(1), vch))
- return false;
- struct ircaddr tmp;
- if (vch.size() != sizeof(tmp))
- return false;
- memcpy(&tmp, &vch[0], sizeof(tmp));
- addr = CService(tmp.ip, ntohs(tmp.port));
- return true;
- }
- static bool Send(SOCKET hSocket, const char* pszSend)
- {
- if (strstr(pszSend, "PONG") != pszSend)
- printf("IRC SENDING: %s\n", pszSend);
- const char* psz = pszSend;
- const char* pszEnd = psz + strlen(psz);
- while (psz < pszEnd)
- {
- int ret = send(hSocket, psz, pszEnd - psz, MSG_NOSIGNAL);
- if (ret < 0)
- return false;
- psz += ret;
- }
- return true;
- }
- bool RecvLineIRC(SOCKET hSocket, string& strLine)
- {
- while (true)
- {
- bool fRet = RecvLine(hSocket, strLine);
- if (fRet)
- {
- if (fShutdown)
- return false;
- vector<string> vWords;
- ParseString(strLine, ' ', vWords);
- if (vWords.size() >= 1 && vWords[0] == "PING")
- {
- strLine[1] = 'O';
- strLine += '\r';
- Send(hSocket, strLine.c_str());
- continue;
- }
- }
- return fRet;
- }
- }
- int RecvUntil(SOCKET hSocket, const char* psz1, const char* psz2=NULL, const char* psz3=NULL, const char* psz4=NULL)
- {
- while (true)
- {
- string strLine;
- strLine.reserve(10000);
- if (!RecvLineIRC(hSocket, strLine))
- return 0;
- printf("IRC %s\n", strLine.c_str());
- if (psz1 && strLine.find(psz1) != string::npos)
- return 1;
- if (psz2 && strLine.find(psz2) != string::npos)
- return 2;
- if (psz3 && strLine.find(psz3) != string::npos)
- return 3;
- if (psz4 && strLine.find(psz4) != string::npos)
- return 4;
- }
- }
- bool Wait(int nSeconds)
- {
- if (fShutdown)
- return false;
- printf("IRC waiting %d seconds to reconnect\n", nSeconds);
- for (int i = 0; i < nSeconds; i++)
- {
- if (fShutdown)
- return false;
- Sleep(1000);
- }
- return true;
- }
- bool RecvCodeLine(SOCKET hSocket, const char* psz1, string& strRet)
- {
- strRet.clear();
- while (true)
- {
- string strLine;
- if (!RecvLineIRC(hSocket, strLine))
- return false;
- vector<string> vWords;
- ParseString(strLine, ' ', vWords);
- if (vWords.size() < 2)
- continue;
- if (vWords[1] == psz1)
- {
- printf("IRC %s\n", strLine.c_str());
- strRet = strLine;
- return true;
- }
- }
- }
- bool GetIPFromIRC(SOCKET hSocket, string strMyName, CNetAddr& ipRet)
- {
- Send(hSocket, strprintf("USERHOST %s\r", strMyName.c_str()).c_str());
- string strLine;
- if (!RecvCodeLine(hSocket, "302", strLine))
- return false;
- vector<string> vWords;
- ParseString(strLine, ' ', vWords);
- if (vWords.size() < 4)
- return false;
- string str = vWords[3];
- if (str.rfind("@") == string::npos)
- return false;
- string strHost = str.substr(str.rfind("@")+1);
- printf("GetIPFromIRC() got userhost %s\n", strHost.c_str());
- CNetAddr addr(strHost, true);
- if (!addr.IsValid())
- return false;
- ipRet = addr;
- return true;
- }
- void ThreadIRCSeed(void* parg)
- {
- RenameThread("ecoin-ircseed");
- try
- {
- ThreadIRCSeed2(parg);
- }
- catch (std::exception& e) {
- PrintExceptionContinue(&e, "ThreadIRCSeed()");
- } catch (...) {
- PrintExceptionContinue(NULL, "ThreadIRCSeed()");
- }
- printf("ThreadIRCSeed exited\n");
- }
- void ThreadIRCSeed2(void* parg)
- {
- if (IsLimited(NET_IPV4))
- return;
- if (mapArgs.count("-connect") && fNoListen)
- return;
- if (!GetBoolArg("-irc", true))
- return;
- printf("ThreadIRCSeed started\n");
- int nErrorWait = 10;
- int nRetryWait = 10;
- int nNameRetry = 0;
- while (!fShutdown)
- {
- CService addrConnect("162.213.39.42", 6697); // irc.freenode.net (10/01/2021)
- CService addrIRC("irc.freenode.net", 6697, true);
- if (addrIRC.IsValid())
- addrConnect = addrIRC;
- SOCKET hSocket;
- if (!ConnectSocket(addrConnect, hSocket))
- {
- printf("IRC connect failed\n");
- nErrorWait = nErrorWait * 11 / 10;
- if (Wait(nErrorWait += 60))
- continue;
- else
- return;
- }
- if (!RecvUntil(hSocket, "Found your hostname", "using your IP address instead", "Couldn't look up your hostname", "ignoring hostname"))
- {
- closesocket(hSocket);
- hSocket = INVALID_SOCKET;
- nErrorWait = nErrorWait * 11 / 10;
- if (Wait(nErrorWait += 60))
- continue;
- else
- return;
- }
- CNetAddr addrIPv4("1.2.3.4"); // arbitrary IPv4 address to make GetLocal prefer IPv4 addresses
- CService addrLocal;
- string strMyName;
- if (!fNoListen && GetLocal(addrLocal, &addrIPv4) && nNameRetry<3)
- strMyName = EncodeAddress(GetLocalAddress(&addrConnect));
- if (strMyName == "")
- strMyName = strprintf("x%" PRI64u"", GetRand(1000000000));
- Send(hSocket, strprintf("NICK %s\r", strMyName.c_str()).c_str());
- Send(hSocket, strprintf("USER %s 8 * : %s\r", strMyName.c_str(), strMyName.c_str()).c_str());
- int nRet = RecvUntil(hSocket, " 004 ", " 433 ");
- if (nRet != 1)
- {
- closesocket(hSocket);
- hSocket = INVALID_SOCKET;
- if (nRet == 2)
- {
- printf("IRC name already in use\n");
- nNameRetry++;
- Wait(10);
- continue;
- }
- nErrorWait = nErrorWait * 11 / 10;
- if (Wait(nErrorWait += 60))
- continue;
- else
- return;
- }
- nNameRetry = 0;
- Sleep(500);
- CNetAddr addrFromIRC;
- if (GetIPFromIRC(hSocket, strMyName, addrFromIRC))
- {
- printf("GetIPFromIRC() returned %s\n", addrFromIRC.ToString().c_str());
- // Don't use our IP as our nick if we're not listening
- if (!fNoListen && addrFromIRC.IsRoutable())
- {
- // IRC lets you to re-nick
- AddLocal(addrFromIRC, LOCAL_IRC);
- strMyName = EncodeAddress(GetLocalAddress(&addrConnect));
- Send(hSocket, strprintf("NICK %s\r", strMyName.c_str()).c_str());
- }
- }
- if (fTestNet) {
- Send(hSocket, "JOIN #ecoinTEST2\r");
- Send(hSocket, "WHO #ecoinTEST2\r");
- } else {
- // Channel number is always 0 for initial release
- int channel_number = 0;
- Send(hSocket, strprintf("JOIN #ecoin%02d\r", channel_number).c_str());
- Send(hSocket, strprintf("WHO #ecoin%02d\r", channel_number).c_str());
- }
- int64 nStart = GetTime();
- string strLine;
- strLine.reserve(10000);
- while (!fShutdown && RecvLineIRC(hSocket, strLine))
- {
- if (strLine.empty() || strLine.size() > 900 || strLine[0] != ':')
- continue;
- vector<string> vWords;
- ParseString(strLine, ' ', vWords);
- if (vWords.size() < 2)
- continue;
- char pszName[10000];
- pszName[0] = '\0';
- if (vWords[1] == "352" && vWords.size() >= 8)
- {
- strlcpy(pszName, vWords[7].c_str(), sizeof(pszName));
- printf("IRC got who\n");
- }
- if (vWords[1] == "JOIN" && vWords[0].size() > 1)
- {
- strlcpy(pszName, vWords[0].c_str() + 1, sizeof(pszName));
- if (strchr(pszName, '!'))
- *strchr(pszName, '!') = '\0';
- printf("IRC got join\n");
- }
- if (pszName[0] == 'u')
- {
- CAddress addr;
- if (DecodeAddress(pszName, addr))
- {
- addr.nTime = GetAdjustedTime();
- if (addrman.Add(addr, addrConnect, 51 * 60))
- printf("IRC got new address: %s\n", addr.ToString().c_str());
- nGotIRCAddresses++;
- }
- else
- {
- printf("IRC decode failed\n");
- }
- }
- }
- closesocket(hSocket);
- hSocket = INVALID_SOCKET;
- if (GetTime() - nStart > 20 * 60)
- {
- nErrorWait /= 3;
- nRetryWait /= 3;
- }
- nRetryWait = nRetryWait * 11 / 10;
- if (!Wait(nRetryWait += 60))
- return;
- }
- }
- #ifdef TEST
- int main(int argc, char *argv[])
- {
- WSADATA wsadata;
- if (WSAStartup(MAKEWORD(2,2), &wsadata) != NO_ERROR)
- {
- printf("Error at WSAStartup()\n");
- return false;
- }
- ThreadIRCSeed(NULL);
- WSACleanup();
- return 0;
- }
- #endif
|