raw
genesis                 1 // Copyright (c) 2009-2010 Satoshi Nakamoto
genesis 2 // Copyright (c) 2009-2012 The Bitcoin developers
genesis 3 // Distributed under the MIT/X11 software license, see the accompanying
genesis 4 // file license.txt or http://www.opensource.org/licenses/mit-license.php.
genesis 5
genesis 6 #include "headers.h"
genesis 7 #include "irc.h"
genesis 8 #include "net.h"
genesis 9 #include "strlcpy.h"
genesis 10
genesis 11 using namespace std;
genesis 12 using namespace boost;
genesis 13
genesis 14 int nGotIRCAddresses = 0;
genesis 15 bool fGotExternalIP = false;
genesis 16
genesis 17 void ThreadIRCSeed2(void* parg);
genesis 18
genesis 19
genesis 20
genesis 21
genesis 22 #pragma pack(push, 1)
genesis 23 struct ircaddr
genesis 24 {
genesis 25 int ip;
genesis 26 short port;
genesis 27 };
genesis 28 #pragma pack(pop)
genesis 29
genesis 30 string EncodeAddress(const CAddress& addr)
genesis 31 {
genesis 32 struct ircaddr tmp;
genesis 33 tmp.ip = addr.ip;
genesis 34 tmp.port = addr.port;
genesis 35
genesis 36 vector<unsigned char> vch(UBEGIN(tmp), UEND(tmp));
genesis 37 return string("u") + EncodeBase58Check(vch);
genesis 38 }
genesis 39
genesis 40 bool DecodeAddress(string str, CAddress& addr)
genesis 41 {
genesis 42 vector<unsigned char> vch;
genesis 43 if (!DecodeBase58Check(str.substr(1), vch))
genesis 44 return false;
genesis 45
genesis 46 struct ircaddr tmp;
genesis 47 if (vch.size() != sizeof(tmp))
genesis 48 return false;
genesis 49 memcpy(&tmp, &vch[0], sizeof(tmp));
genesis 50
genesis 51 addr = CAddress(tmp.ip, ntohs(tmp.port), NODE_NETWORK);
genesis 52 return true;
genesis 53 }
genesis 54
genesis 55
genesis 56
genesis 57
genesis 58
genesis 59
genesis 60 static bool Send(SOCKET hSocket, const char* pszSend)
genesis 61 {
genesis 62 if (strstr(pszSend, "PONG") != pszSend)
genesis 63 printf("IRC SENDING: %s\n", pszSend);
genesis 64 const char* psz = pszSend;
genesis 65 const char* pszEnd = psz + strlen(psz);
genesis 66 while (psz < pszEnd)
genesis 67 {
genesis 68 int ret = send(hSocket, psz, pszEnd - psz, MSG_NOSIGNAL);
genesis 69 if (ret < 0)
genesis 70 return false;
genesis 71 psz += ret;
genesis 72 }
genesis 73 return true;
genesis 74 }
genesis 75
genesis 76 bool RecvLine(SOCKET hSocket, string& strLine)
genesis 77 {
genesis 78 strLine = "";
genesis 79 loop
genesis 80 {
genesis 81 char c;
genesis 82 int nBytes = recv(hSocket, &c, 1, 0);
genesis 83 if (nBytes > 0)
genesis 84 {
genesis 85 if (c == '\n')
genesis 86 continue;
genesis 87 if (c == '\r')
genesis 88 return true;
genesis 89 strLine += c;
genesis 90 if (strLine.size() >= 9000)
genesis 91 return true;
genesis 92 }
genesis 93 else if (nBytes <= 0)
genesis 94 {
genesis 95 if (fShutdown)
genesis 96 return false;
genesis 97 if (nBytes < 0)
genesis 98 {
genesis 99 int nErr = WSAGetLastError();
genesis 100 if (nErr == WSAEMSGSIZE)
genesis 101 continue;
genesis 102 if (nErr == WSAEWOULDBLOCK || nErr == WSAEINTR || nErr == WSAEINPROGRESS)
genesis 103 {
genesis 104 Sleep(10);
genesis 105 continue;
genesis 106 }
genesis 107 }
genesis 108 if (!strLine.empty())
genesis 109 return true;
genesis 110 if (nBytes == 0)
genesis 111 {
genesis 112 // socket closed
genesis 113 printf("socket closed\n");
genesis 114 return false;
genesis 115 }
genesis 116 else
genesis 117 {
genesis 118 // socket error
genesis 119 int nErr = WSAGetLastError();
genesis 120 printf("recv failed: %d\n", nErr);
genesis 121 return false;
genesis 122 }
genesis 123 }
genesis 124 }
genesis 125 }
genesis 126
genesis 127 bool RecvLineIRC(SOCKET hSocket, string& strLine)
genesis 128 {
genesis 129 loop
genesis 130 {
genesis 131 bool fRet = RecvLine(hSocket, strLine);
genesis 132 if (fRet)
genesis 133 {
genesis 134 if (fShutdown)
genesis 135 return false;
genesis 136 vector<string> vWords;
genesis 137 ParseString(strLine, ' ', vWords);
genesis 138 if (vWords.size() >= 1 && vWords[0] == "PING")
genesis 139 {
genesis 140 strLine[1] = 'O';
genesis 141 strLine += '\r';
genesis 142 Send(hSocket, strLine.c_str());
genesis 143 continue;
genesis 144 }
genesis 145 }
genesis 146 return fRet;
genesis 147 }
genesis 148 }
genesis 149
genesis 150 int RecvUntil(SOCKET hSocket, const char* psz1, const char* psz2=NULL, const char* psz3=NULL, const char* psz4=NULL)
genesis 151 {
genesis 152 loop
genesis 153 {
genesis 154 string strLine;
genesis 155 strLine.reserve(10000);
genesis 156 if (!RecvLineIRC(hSocket, strLine))
genesis 157 return 0;
genesis 158 printf("IRC %s\n", strLine.c_str());
genesis 159 if (psz1 && strLine.find(psz1) != -1)
genesis 160 return 1;
genesis 161 if (psz2 && strLine.find(psz2) != -1)
genesis 162 return 2;
genesis 163 if (psz3 && strLine.find(psz3) != -1)
genesis 164 return 3;
genesis 165 if (psz4 && strLine.find(psz4) != -1)
genesis 166 return 4;
genesis 167 }
genesis 168 }
genesis 169
genesis 170 bool Wait(int nSeconds)
genesis 171 {
genesis 172 if (fShutdown)
genesis 173 return false;
genesis 174 printf("IRC waiting %d seconds to reconnect\n", nSeconds);
genesis 175 for (int i = 0; i < nSeconds; i++)
genesis 176 {
genesis 177 if (fShutdown)
genesis 178 return false;
genesis 179 Sleep(1000);
genesis 180 }
genesis 181 return true;
genesis 182 }
genesis 183
genesis 184 bool RecvCodeLine(SOCKET hSocket, const char* psz1, string& strRet)
genesis 185 {
genesis 186 strRet.clear();
genesis 187 loop
genesis 188 {
genesis 189 string strLine;
genesis 190 if (!RecvLineIRC(hSocket, strLine))
genesis 191 return false;
genesis 192
genesis 193 vector<string> vWords;
genesis 194 ParseString(strLine, ' ', vWords);
genesis 195 if (vWords.size() < 2)
genesis 196 continue;
genesis 197
genesis 198 if (vWords[1] == psz1)
genesis 199 {
genesis 200 printf("IRC %s\n", strLine.c_str());
genesis 201 strRet = strLine;
genesis 202 return true;
genesis 203 }
genesis 204 }
genesis 205 }
genesis 206
genesis 207 bool GetIPFromIRC(SOCKET hSocket, string strMyName, unsigned int& ipRet)
genesis 208 {
genesis 209 Send(hSocket, strprintf("USERHOST %s\r", strMyName.c_str()).c_str());
genesis 210
genesis 211 string strLine;
genesis 212 if (!RecvCodeLine(hSocket, "302", strLine))
genesis 213 return false;
genesis 214
genesis 215 vector<string> vWords;
genesis 216 ParseString(strLine, ' ', vWords);
genesis 217 if (vWords.size() < 4)
genesis 218 return false;
genesis 219
genesis 220 string str = vWords[3];
genesis 221 if (str.rfind("@") == string::npos)
genesis 222 return false;
genesis 223 string strHost = str.substr(str.rfind("@")+1);
genesis 224
genesis 225 // Hybrid IRC used by lfnet always returns IP when you userhost yourself,
genesis 226 // but in case another IRC is ever used this should work.
genesis 227 printf("GetIPFromIRC() got userhost %s\n", strHost.c_str());
genesis 228 if (fUseProxy)
genesis 229 return false;
genesis 230 CAddress addr(strHost, 0, true);
genesis 231 if (!addr.IsValid())
genesis 232 return false;
genesis 233 ipRet = addr.ip;
genesis 234
genesis 235 return true;
genesis 236 }
genesis 237
genesis 238
genesis 239
genesis 240 void ThreadIRCSeed(void* parg)
genesis 241 {
genesis 242 IMPLEMENT_RANDOMIZE_STACK(ThreadIRCSeed(parg));
genesis 243 try
genesis 244 {
genesis 245 ThreadIRCSeed2(parg);
genesis 246 }
genesis 247 catch (std::exception& e) {
genesis 248 PrintExceptionContinue(&e, "ThreadIRCSeed()");
genesis 249 } catch (...) {
genesis 250 PrintExceptionContinue(NULL, "ThreadIRCSeed()");
genesis 251 }
genesis 252 printf("ThreadIRCSeed exiting\n");
genesis 253 }
genesis 254
genesis 255 void ThreadIRCSeed2(void* parg)
genesis 256 {
genesis 257 /* Dont advertise on IRC if we don't allow incoming connections */
genesis 258 if (mapArgs.count("-connect") || fNoListen)
genesis 259 return;
genesis 260
genesis 261 if (GetBoolArg("-noirc"))
genesis 262 return;
genesis 263 printf("ThreadIRCSeed started\n");
genesis 264 int nErrorWait = 10;
genesis 265 int nRetryWait = 10;
genesis 266 bool fNameInUse = false;
genesis 267
genesis 268 while (!fShutdown)
genesis 269 {
genesis 270 CAddress addrConnect("92.243.23.21", 6667); // irc.lfnet.org
genesis 271
genesis 272 CAddress addrIRC("irc.lfnet.org", 6667, true);
genesis 273 if (addrIRC.IsValid())
genesis 274 addrConnect = addrIRC;
genesis 275
genesis 276 SOCKET hSocket;
genesis 277 if (!ConnectSocket(addrConnect, hSocket))
genesis 278 {
genesis 279 printf("IRC connect failed\n");
genesis 280 nErrorWait = nErrorWait * 11 / 10;
genesis 281 if (Wait(nErrorWait += 60))
genesis 282 continue;
genesis 283 else
genesis 284 return;
genesis 285 }
genesis 286
genesis 287 if (!RecvUntil(hSocket, "Found your hostname", "using your IP address instead", "Couldn't look up your hostname", "ignoring hostname"))
genesis 288 {
genesis 289 closesocket(hSocket);
genesis 290 hSocket = INVALID_SOCKET;
genesis 291 nErrorWait = nErrorWait * 11 / 10;
genesis 292 if (Wait(nErrorWait += 60))
genesis 293 continue;
genesis 294 else
genesis 295 return;
genesis 296 }
genesis 297
genesis 298 string strMyName;
genesis 299 if (addrLocalHost.IsRoutable() && !fUseProxy && !fNameInUse)
genesis 300 strMyName = EncodeAddress(addrLocalHost);
genesis 301 else
genesis 302 strMyName = strprintf("x%u", GetRand(1000000000));
genesis 303
genesis 304 Send(hSocket, strprintf("NICK %s\r", strMyName.c_str()).c_str());
genesis 305 Send(hSocket, strprintf("USER %s 8 * : %s\r", strMyName.c_str(), strMyName.c_str()).c_str());
genesis 306
genesis 307 int nRet = RecvUntil(hSocket, " 004 ", " 433 ");
genesis 308 if (nRet != 1)
genesis 309 {
genesis 310 closesocket(hSocket);
genesis 311 hSocket = INVALID_SOCKET;
genesis 312 if (nRet == 2)
genesis 313 {
genesis 314 printf("IRC name already in use\n");
genesis 315 fNameInUse = true;
genesis 316 Wait(10);
genesis 317 continue;
genesis 318 }
genesis 319 nErrorWait = nErrorWait * 11 / 10;
genesis 320 if (Wait(nErrorWait += 60))
genesis 321 continue;
genesis 322 else
genesis 323 return;
genesis 324 }
genesis 325 Sleep(500);
genesis 326
genesis 327 // Get our external IP from the IRC server and re-nick before joining the channel
genesis 328 CAddress addrFromIRC;
genesis 329 if (GetIPFromIRC(hSocket, strMyName, addrFromIRC.ip))
genesis 330 {
genesis 331 printf("GetIPFromIRC() returned %s\n", addrFromIRC.ToStringIP().c_str());
genesis 332 if (!fUseProxy && addrFromIRC.IsRoutable())
genesis 333 {
genesis 334 // IRC lets you to re-nick
genesis 335 fGotExternalIP = true;
genesis 336 addrLocalHost.ip = addrFromIRC.ip;
genesis 337 strMyName = EncodeAddress(addrLocalHost);
genesis 338 Send(hSocket, strprintf("NICK %s\r", strMyName.c_str()).c_str());
genesis 339 }
genesis 340 }
genesis 341
genesis 342 if (fTestNet) {
genesis 343 Send(hSocket, "JOIN #bitcoinTEST\r");
genesis 344 Send(hSocket, "WHO #bitcoinTEST\r");
genesis 345 } else {
genesis 346 // randomly join #bitcoin00-#bitcoin99
genesis 347 int channel_number = GetRandInt(100);
genesis 348 Send(hSocket, strprintf("JOIN #bitcoin%02d\r", channel_number).c_str());
genesis 349 Send(hSocket, strprintf("WHO #bitcoin%02d\r", channel_number).c_str());
genesis 350 }
genesis 351
genesis 352 int64 nStart = GetTime();
genesis 353 string strLine;
genesis 354 strLine.reserve(10000);
genesis 355 while (!fShutdown && RecvLineIRC(hSocket, strLine))
genesis 356 {
genesis 357 if (strLine.empty() || strLine.size() > 900 || strLine[0] != ':')
genesis 358 continue;
genesis 359
genesis 360 vector<string> vWords;
genesis 361 ParseString(strLine, ' ', vWords);
genesis 362 if (vWords.size() < 2)
genesis 363 continue;
genesis 364
genesis 365 char pszName[10000];
genesis 366 pszName[0] = '\0';
genesis 367
genesis 368 if (vWords[1] == "352" && vWords.size() >= 8)
genesis 369 {
genesis 370 // index 7 is limited to 16 characters
genesis 371 // could get full length name at index 10, but would be different from join messages
genesis 372 strlcpy(pszName, vWords[7].c_str(), sizeof(pszName));
genesis 373 printf("IRC got who\n");
genesis 374 }
genesis 375
genesis 376 if (vWords[1] == "JOIN" && vWords[0].size() > 1)
genesis 377 {
genesis 378 // :username!username@50000007.F000000B.90000002.IP JOIN :#channelname
genesis 379 strlcpy(pszName, vWords[0].c_str() + 1, sizeof(pszName));
genesis 380 if (strchr(pszName, '!'))
genesis 381 *strchr(pszName, '!') = '\0';
genesis 382 printf("IRC got join\n");
genesis 383 }
genesis 384
genesis 385 if (pszName[0] == 'u')
genesis 386 {
genesis 387 CAddress addr;
genesis 388 if (DecodeAddress(pszName, addr))
genesis 389 {
genesis 390 addr.nTime = GetAdjustedTime();
genesis 391 if (AddAddress(addr, 51 * 60))
genesis 392 printf("IRC got new address: %s\n", addr.ToString().c_str());
genesis 393 nGotIRCAddresses++;
genesis 394 }
genesis 395 else
genesis 396 {
genesis 397 printf("IRC decode failed\n");
genesis 398 }
genesis 399 }
genesis 400 }
genesis 401 closesocket(hSocket);
genesis 402 hSocket = INVALID_SOCKET;
genesis 403
genesis 404 if (GetTime() - nStart > 20 * 60)
genesis 405 {
genesis 406 nErrorWait /= 3;
genesis 407 nRetryWait /= 3;
genesis 408 }
genesis 409
genesis 410 nRetryWait = nRetryWait * 11 / 10;
genesis 411 if (!Wait(nRetryWait += 60))
genesis 412 return;
genesis 413 }
genesis 414 }
genesis 415
genesis 416
genesis 417
genesis 418
genesis 419
genesis 420
genesis 421
genesis 422
genesis 423
genesis 424
genesis 425 #ifdef TEST
genesis 426 int main(int argc, char *argv[])
genesis 427 {
genesis 428 WSADATA wsadata;
genesis 429 if (WSAStartup(MAKEWORD(2,2), &wsadata) != NO_ERROR)
genesis 430 {
genesis 431 printf("Error at WSAStartup()\n");
genesis 432 return false;
genesis 433 }
genesis 434
genesis 435 ThreadIRCSeed(NULL);
genesis 436
genesis 437 WSACleanup();
genesis 438 return 0;
genesis 439 }
genesis 440 #endif