main.cpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594
  1. /*
  2. * Address miner for Yggdrsail Network 0.4.x and higher.
  3. *
  4. * developers: Vort, acetone, R4SAS, lialh4, filarius, orignal
  5. * developers team, 2021 (c) GPLv3
  6. *
  7. */
  8. #include "main.h"
  9. std::time_t sygstartedin = std::time(NULL); // для вывода времени работы
  10. int countsize = 0; // определяет периодичность вывода счетчика
  11. uint64_t totalcount = 0; // общий счетчик
  12. uint64_t countfortune = 0; // счетчик нахождений
  13. bool newline = false; // форматирует вывод после нахождения адреса
  14. std::chrono::steady_clock::duration blocks_duration(0);
  15. std::mutex mtx;
  16. static option conf;
  17. void intro()
  18. {
  19. std::cout << std::endl << "\
  20. +--------------------------------------------------------------------------+ \n\
  21. | [ SimpleYggGen C++ 5.1-flow ] | \n\
  22. | EdDSA public key -> IPv6 -> Meshname | \n\
  23. | notabug.org/acetone/SimpleYggGen-CPP | \n\
  24. | | \n\
  25. | GPLv3 (c) 2021 | \n\
  26. +--------------------------------------------------------------------------+ "
  27. << std::endl;
  28. }
  29. void displayConfig()
  30. {
  31. // из-за регулирования количества потоков и countsize вызов функции обязателен
  32. unsigned int processor_count = std::thread::hardware_concurrency(); // кол-во процессоров
  33. if (conf.proc == 0 || conf.proc > static_cast<unsigned int>(processor_count))
  34. conf.proc = static_cast<unsigned int>(processor_count);
  35. countsize = 80000 * conf.proc;
  36. std::cout << " Threads: " << conf.proc << ", ";
  37. if(conf.mode == 0)
  38. std::cout << "IPv6 pattern (" << conf.str << "), ";
  39. else if(conf.mode == 1)
  40. {
  41. std::cout << "high addresses (2" << std::setw(2) << std::setfill('0') <<
  42. std::hex << conf.high << std::dec;
  43. (conf.letsup != 0) ? std::cout << "++), " : std::cout << "+), ";
  44. }
  45. else if(conf.mode == 2)
  46. {
  47. std::cout << "by pattern (" << conf.str << ") & high (2" <<
  48. std::setw(2) << std::setfill('0') << std::hex << conf.high << std::dec;
  49. (conf.letsup != 0) ? std::cout << "++), " : std::cout << "+), ";
  50. }
  51. else if(conf.mode == 3)
  52. std::cout << "IPv6 regexp (" << conf.str << "), ";
  53. else if(conf.mode == 4)
  54. {
  55. std::cout << "IPv6 regexp (" << conf.str << ") & high (2" <<
  56. std::setw(2) << std::setfill('0') << std::hex << conf.high << std::dec;
  57. (conf.letsup != 0) ? std::cout << "++), " : std::cout << "+), ";
  58. }
  59. else if(conf.mode == 5)
  60. std::cout << "meshname pattern (" << conf.str << "), ";
  61. else if(conf.mode == 6)
  62. std::cout << "meshname regexp (" << conf.str << "), ";
  63. else if(conf.mode == 7)
  64. std::cout << "subnet brute force (" << conf.str << "/" << (conf.sbt_size+1) * 8 << "), ";
  65. if(conf.log)
  66. std::cout << "logging to text file.";
  67. else
  68. std::cout << "console log only.";
  69. if((conf.mode == 5 || conf.mode == 6) && conf.mesh == 0)
  70. conf.mesh = 1; // принудительно включаем отображение мешнейм-доменов при их майнинге
  71. std::cout << std::endl << std::endl;
  72. }
  73. void testOutput()
  74. {
  75. if(conf.log)
  76. {
  77. if(conf.mode == 0)
  78. conf.outputfile = "syg-ipv6-pattern.txt";
  79. else if(conf.mode == 1)
  80. conf.outputfile = "syg-ipv6-high.txt";
  81. else if(conf.mode == 2)
  82. conf.outputfile = "syg-ipv6-pattern-high.txt";
  83. else if(conf.mode == 3)
  84. conf.outputfile = "syg-ipv6-regexp.txt";
  85. else if(conf.mode == 4)
  86. conf.outputfile = "syg-ipv6-regexp-high.txt";
  87. else if(conf.mode == 5)
  88. conf.outputfile = "syg-meshname-pattern.txt";
  89. else if(conf.mode == 6)
  90. conf.outputfile = "syg-meshname-regexp.txt";
  91. else if(conf.mode == 7)
  92. conf.outputfile = "syg-subnet-brute-force.txt";
  93. std::ifstream test(conf.outputfile);
  94. if(!test)
  95. {
  96. test.close();
  97. std::ofstream output(conf.outputfile);
  98. output << "******************************************************\n"
  99. << "Change PublicKey and PrivateKey to your yggdrasil.conf\n"
  100. << "Windows: C:\\ProgramData\\Yggdrasil\\yggdrasil.conf\n"
  101. << "Debian: /etc/yggdrasil.conf\n"
  102. << "******************************************************\n";
  103. output.close();
  104. } else test.close();
  105. }
  106. }
  107. void logStatistics()
  108. {
  109. if (totalcount % countsize == 0)
  110. {
  111. mtx.lock();
  112. auto timedays = (std::time(NULL) - sygstartedin) / 86400;
  113. auto timehours = ((std::time(NULL) - sygstartedin) - (timedays * 86400)) / 3600;
  114. auto timeminutes = ((std::time(NULL) - sygstartedin) - (timedays * 86400) - (timehours * 3600)) / 60;
  115. auto timeseconds = (std::time(NULL) - sygstartedin) - (timedays * 86400) - (timehours * 3600) - (timeminutes * 60);
  116. std::chrono::duration<double, std::milli> df = blocks_duration;
  117. blocks_duration = std::chrono::steady_clock::duration::zero();
  118. uint64_t khs = conf.proc * countsize / df.count();
  119. std::cout <<
  120. " kH/s: [" << std::setw(7) << std::setfill('_') << khs <<
  121. "] Total: [" << std::setw(19) << totalcount <<
  122. "] Found: [" << std::setw(3) << countfortune <<
  123. "] Time: [" << timedays << ":" << std::setw(2) << std::setfill('0') <<
  124. timehours << ":" << std::setw(2) << timeminutes << ":" << std::setw(2) << timeseconds << "]" << std::endl;
  125. newline = true;
  126. mtx.unlock();
  127. }
  128. }
  129. void logKeys(const Address& raw, const KeysBox& keys)
  130. {
  131. mtx.lock();
  132. if(newline) // добавляем пустую строку на экране между счетчиком и новым адресом
  133. {
  134. std::cout << std::endl;
  135. newline = false;
  136. }
  137. if (conf.mesh) {
  138. std::string base32 = getBase32(raw);
  139. std::cout << " Domain: " << pickupMeshnameForOutput(base32) << std::endl;
  140. }
  141. std::cout << " Address: " << getAddress(raw) << std::endl;
  142. std::cout << " PublicKey: " << keyToString(keys.PublicKey) << std::endl;
  143. std::cout << " PrivateKey: " << keyToString(keys.PrivateKey);
  144. // Можем выводить приватный ключ в консоль в полном формате
  145. if (!conf.log || conf.fullkeys) std::cout << keyToString(keys.PublicKey);
  146. std::cout << std::endl << std::endl;
  147. if (conf.log) // запись в файл
  148. {
  149. std::ofstream output(conf.outputfile, std::ios::app);
  150. output << std::endl;
  151. if (conf.mesh) {
  152. std::string base32 = getBase32(raw);
  153. output << "Domain: " << pickupMeshnameForOutput(base32) << std::endl;
  154. }
  155. output << "Address: " << getAddress(raw) << std::endl;
  156. output << "PublicKey: " << keyToString(keys.PublicKey) << std::endl;
  157. output << "PrivateKey: " << keyToString(keys.PrivateKey) << keyToString(keys.PublicKey) << std::endl;
  158. output.close();
  159. }
  160. mtx.unlock();
  161. }
  162. std::string getBase32(const Address& rawAddr)
  163. {
  164. return static_cast<std::string>(cppcodec::base32_rfc4648::encode(rawAddr.data(), 16));
  165. }
  166. /**
  167. * pickupStringForMeshname получает человекочитаемую строку
  168. * типа fsdasdaklasdgdas.meship и возвращает значение, пригодное
  169. * для поиска по meshname-строке: удаляет возможную доменную зону
  170. * (всё после точки и саму точку), а также делает все буквы
  171. * заглавными.
  172. */
  173. std::string pickupStringForMeshname(std::string str)
  174. {
  175. bool dot = false;
  176. std::string::iterator delend;
  177. for (auto it = str.begin(); it != str.end(); it++)
  178. {
  179. *it = toupper(*it); // делаем все буквы заглавными для обработки
  180. if(*it == '.') {
  181. delend = it;
  182. dot = true;
  183. }
  184. }
  185. if (dot)
  186. for (auto it = str.end(); it != delend; it--)
  187. str.pop_back(); // удаляем доменную зону
  188. return str;
  189. }
  190. /**
  191. * pickupMeshnameForOutput получает сырое base32 значение
  192. * типа KLASJFHASSA7979====== и возвращает meshname-домен:
  193. * делает все символы строчными и удаляет паддинги ('='),
  194. * а также добавляет доменную зону ".meship".
  195. */
  196. std::string pickupMeshnameForOutput(std::string str)
  197. {
  198. for (auto it = str.begin(); it != str.end(); it++) // делаем все буквы строчными для вывода
  199. *it = tolower(*it);
  200. for (auto it = str.end(); *(it-1) == '='; it--)
  201. str.pop_back(); // удаляем символы '=' в конце адреса
  202. return str + ".meship";
  203. }
  204. /**
  205. * decodeMeshToIP получает строковое значение сырого base32
  206. * кода типа KLASJFHASSA7979====== и возвращает IPv6-стринг.
  207. */
  208. std::string decodeMeshToIP(const std::string& str)
  209. {
  210. std::string mesh = pickupStringForMeshname(str) + "======"; // 6 паддингов - норма для IPv6 адреса
  211. std::vector<uint8_t> raw = cppcodec::base32_rfc4648::decode(mesh);
  212. Address rawAddr;
  213. for(int i = 0; i < 16; ++i)
  214. rawAddr[i] = raw[i];
  215. return std::string(getAddress(rawAddr));
  216. }
  217. bool subnetCheck() // замена 300::/64 на целевой 200::/7
  218. {
  219. if(conf.str[0] == '3')
  220. {
  221. conf.str[0] = '2';
  222. return true;
  223. }
  224. return false;
  225. }
  226. bool convertStrToRaw(const std::string& str, Address& array)
  227. {
  228. return inet_pton(AF_INET6, str.c_str(), (void*)array.data());
  229. }
  230. KeysBox getKeyPair()
  231. {
  232. KeysBox keys;
  233. uint8_t sk[64];
  234. crypto_sign_ed25519_keypair(keys.PublicKey.data(), sk);
  235. memcpy(keys.PrivateKey.data(), sk, 32);
  236. return keys;
  237. }
  238. void getRawAddress(int lErase, Key InvertedPublicKey, Address& rawAddr)
  239. {
  240. ++lErase; // лидирующие единицы + первый ноль
  241. int bitsToShift = lErase % 8;
  242. int start = lErase / 8;
  243. for(int i = start; i < start + 15; ++i)
  244. {
  245. InvertedPublicKey[i] <<= bitsToShift;
  246. InvertedPublicKey[i] |= (InvertedPublicKey[i + 1] >> (8 - bitsToShift));
  247. }
  248. rawAddr[0] = 0x02;
  249. rawAddr[1] = lErase - 1;
  250. for (int i = 0; i < 14; ++i)
  251. rawAddr[i + 2] = InvertedPublicKey[i+start];
  252. }
  253. Key bitwiseInverse(const Key& key)
  254. {
  255. Key inverted;
  256. for(size_t i = 0; i < key.size(); ++i)
  257. inverted[i] = ~key[i];
  258. return inverted;
  259. }
  260. int getOnes(const Key& value)
  261. {
  262. const int zeroBytesMap[8] = {0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01};
  263. int leadOnes = 0; // кол-во лидирующих единиц
  264. for (int i = 0; i < 17; ++i) // 32B(ключ) - 15B(IPv6 без 0x02) = 17B(возможных лидирующих единиц)
  265. {
  266. for (int j = 0; j < 8; ++j)
  267. {
  268. if (value[i] & zeroBytesMap[j]) ++leadOnes;
  269. else return leadOnes;
  270. }
  271. }
  272. return 0; // никогда не случится
  273. }
  274. std::string getAddress(const Address& rawAddr)
  275. {
  276. char ipStrBuf[46];
  277. inet_ntop(AF_INET6, rawAddr.data(), ipStrBuf, 46);
  278. return std::string(ipStrBuf);
  279. }
  280. std::string hexArrayToString(const uint8_t* bytes, int length)
  281. {
  282. std::stringstream ss;
  283. for (int i = 0; i < length; i++)
  284. ss << std::setw(2) << std::setfill('0') << std::hex << static_cast<int>(bytes[i]);
  285. return ss.str();
  286. }
  287. std::string keyToString(const Key& key)
  288. {
  289. return hexArrayToString(key.data(), KEYSIZE);
  290. }
  291. void process_fortune_key(const KeysBox& keys)
  292. {
  293. Key invKey = bitwiseInverse(keys.PublicKey);
  294. int ones = getOnes(invKey);
  295. Address rawAddr;
  296. getRawAddress(ones, invKey, rawAddr);
  297. logKeys(rawAddr, keys);
  298. ++countfortune;
  299. }
  300. template <int T>
  301. void miner_thread()
  302. {
  303. if (T == 5) // meshname pattern
  304. {
  305. conf.str = pickupStringForMeshname(conf.str);
  306. }
  307. Address rawForBrute;
  308. if (T == 7) // subnet brute force
  309. {
  310. mtx.lock();
  311. std::string oldString = conf.str;
  312. bool edited = subnetCheck();
  313. bool result = convertStrToRaw(conf.str, rawForBrute);
  314. if (!result || edited || conf.str != getAddress(rawForBrute))
  315. {
  316. if (!conf.sbt_alarm) // однократный вывод ошибки
  317. {
  318. std::cerr << " WARNING: Your string [" << oldString << "] converted to IP [" <<
  319. getAddress(rawForBrute) << "]" << std::endl << std::endl;
  320. }
  321. conf.sbt_alarm = true;
  322. }
  323. mtx.unlock();
  324. }
  325. Address rawAddr;
  326. std::regex regx(conf.str, std::regex_constants::egrep | std::regex_constants::icase);
  327. int ones = 0;
  328. for (;;) // основной цикл майнинга
  329. {
  330. auto start_time = std::chrono::steady_clock::now();
  331. KeysBox keys = getKeyPair();
  332. Key invKey = bitwiseInverse(keys.PublicKey);
  333. ones = getOnes(invKey);
  334. if (T == 0) // IPv6 pattern mining
  335. {
  336. getRawAddress(ones, invKey, rawAddr);
  337. if (getAddress(rawAddr).find(conf.str.c_str()) != std::string::npos)
  338. {
  339. process_fortune_key(keys);
  340. }
  341. }
  342. if (T == 1) // high mining
  343. {
  344. if (ones > conf.high)
  345. {
  346. if (conf.letsup != 0) conf.high = ones;
  347. process_fortune_key(keys);
  348. }
  349. }
  350. if (T == 2) // pattern & high mining
  351. {
  352. getRawAddress(ones, invKey, rawAddr);
  353. if (ones > conf.high && getAddress(rawAddr).find(conf.str.c_str()) != std::string::npos)
  354. {
  355. if (conf.letsup != 0) conf.high = ones;
  356. process_fortune_key(keys);
  357. }
  358. }
  359. if (T == 3) // IPv6 regexp mining
  360. {
  361. getRawAddress(ones, invKey, rawAddr);
  362. if (std::regex_search((getAddress(rawAddr)), regx))
  363. {
  364. process_fortune_key(keys);
  365. }
  366. }
  367. if (T == 4) // IPv6 regexp & high mining
  368. {
  369. getRawAddress(ones, invKey, rawAddr);
  370. if (ones > conf.high)
  371. {
  372. if (std::regex_search((getAddress(rawAddr)), regx))
  373. {
  374. if (conf.letsup != 0) conf.high = ones;
  375. process_fortune_key(keys);
  376. }
  377. }
  378. }
  379. if (T == 5) // meshname pattern mining
  380. {
  381. getRawAddress(ones, invKey, rawAddr);
  382. if (getBase32(rawAddr).find(conf.str.c_str()) != std::string::npos)
  383. {
  384. process_fortune_key(keys);
  385. }
  386. }
  387. if (T == 6) // meshname regexp mining
  388. {
  389. getRawAddress(ones, invKey, rawAddr);
  390. if (std::regex_search((getBase32(rawAddr)), regx))
  391. {
  392. process_fortune_key(keys);
  393. }
  394. }
  395. if (T == 7) // subnet brute force
  396. {
  397. getRawAddress(ones, invKey, rawAddr);
  398. for(int z = 0; rawForBrute[z] == rawAddr[z]; ++z)
  399. {
  400. if (z > 4)
  401. {
  402. if (z == conf.sbt_size) process_fortune_key(keys);
  403. else
  404. {
  405. mtx.lock();
  406. std::cout << " So close! Bruted bytes: " << z+1
  407. << "/" << conf.sbt_size+1 << std::endl;
  408. mtx.unlock();
  409. }
  410. }
  411. }
  412. }
  413. auto stop_time = std::chrono::steady_clock::now();
  414. ++totalcount;
  415. blocks_duration += stop_time - start_time;
  416. logStatistics();
  417. }
  418. }
  419. void startThreads()
  420. {
  421. for (unsigned int i = 0; i < conf.proc; ++i)
  422. {
  423. std::thread * thread = new std::thread(
  424. conf.mode == 0 ? miner_thread<0> :
  425. conf.mode == 1 ? miner_thread<1> :
  426. conf.mode == 2 ? miner_thread<2> :
  427. conf.mode == 3 ? miner_thread<3> :
  428. conf.mode == 4 ? miner_thread<4> :
  429. conf.mode == 5 ? miner_thread<5> :
  430. conf.mode == 6 ? miner_thread<6> :
  431. miner_thread<7>
  432. );
  433. if (i+1 < conf.proc) thread->detach();
  434. else thread->join();
  435. }
  436. }
  437. void error(int code)
  438. {
  439. std::cerr << std::endl << "\
  440. +--------------------------------------------------------------------------+\n\
  441. | Incorrect input, my dear friend. Use --help for usage information. |\n\
  442. +--------------------------------------------------------------------------+\n\
  443. Error code: " << code << std::endl;
  444. }
  445. void help()
  446. {
  447. std::cout << std::endl << "\
  448. +--------------------------------------------------------------------------+\n\
  449. | Simple Yggdrasil address miner usage: --help or -h |\n\
  450. +--------------------------------------------------------------------------+\n\
  451. [Mining modes] \n\
  452. High addresses BY DEFAULT | \n\
  453. IPv6 by pattern --ip | -i \n\
  454. IPv6 by pattern + height --ip-high | -ih \n\
  455. IPv6 by regular expression --regexp | -r \n\
  456. IPv6 by regular expression + height --regexp-high | -rh \n\
  457. Meshname by pattern --mesh | -m \n\
  458. Meshname by regular expression --mesh-regexp | -mr \n\
  459. Subnet brute force (300::/64) --brute-force | -b \n\
  460. [Main parameters] \n\
  461. Threads count (maximum by default) --threads | -t <value>\n\
  462. String for pattern or regular expression --pattern | -p <value>\n\
  463. Start position for high addresses (14 by default) --altitude | -a <value>\n\
  464. [Extra options] \n\
  465. Disable auto-increase in high mode --increase-none | -in \n\
  466. Disable logging to text file, stdout only --logging-none | -ln \n\
  467. Force display meshname domains --display-mesh | -dm \n\
  468. Show PrivateKeys in full format in console --full-pk | -fp \n\
  469. Show the version of the miner --version | -v \n\
  470. [Meshname convertation] \n\
  471. Convert IP to Meshname --tomesh | -tm <value>\n\
  472. Convert Meshname to IP --toip | -ti <value>\n\
  473. [Notes] \n\
  474. Meshname domains use base32 (RFC4648) alphabet symbols. \n\
  475. In meshname domain mining should use \"=\" instead \".meship\" or \".meshname\".\n\
  476. Subnet brute force mode understand \"3xx:\" and \"2xx:\" patterns. \n\
  477. +--------------------------------------------------------------------------+\n";
  478. }
  479. void without()
  480. {
  481. std::cout << "\
  482. SimpleYggGen was started without parameters.\n\
  483. The mining mode for high addresses will be launched automatically.\n\
  484. Use --help for usage information."
  485. << std::flush;
  486. }
  487. int main(int argc, char *argv[])
  488. {
  489. if(argc >= 2)
  490. {
  491. std::string p1;
  492. ///////////////////////////////// Вспомогательные функции
  493. p1 = argv[1];
  494. if (p1 == "--help" || p1 == "-help" || p1 == "-h") {
  495. help();
  496. return 0;
  497. } else if (p1 == "--version" || p1 == "-v") {
  498. intro();
  499. return 0;
  500. } else if (p1 == "--tomesh" || p1 == "-tm") { // преобразование IP -> Meshname
  501. if (argc >= 3) {
  502. Address rawAddr;
  503. convertStrToRaw(argv[2], rawAddr);
  504. std::string base32 = getBase32(rawAddr);
  505. std::cout << std::endl << pickupMeshnameForOutput(base32) << std::endl;
  506. return 0;
  507. } else { error(-501); return -501; }
  508. } else if (p1 == "--toip" || p1 == "-ti") { // преобразование Meshname -> IP
  509. if (argc >= 3) {
  510. std::cout << std::endl << decodeMeshToIP(argv[2]) << std::endl;
  511. return 0;
  512. } else { error(-502); return -502; }
  513. ///////////////////////////////// Основные функции
  514. } else {
  515. int res = -1;
  516. for(int i = 1;; ++i) {
  517. if (argv[i] == nullptr) break;
  518. res = parameters(conf, std::string(argv[i]));
  519. if (res == 777) { // Нужно передать параметр
  520. ++i;
  521. if (argv[i] == nullptr) { // Значение параметра не передано
  522. error(776);
  523. std::cerr << " Empty value for parameter \"" << argv[i-1] << "\"" << std::endl;
  524. return 776;
  525. }
  526. int res2 = parameters(conf, std::string( std::string(argv[i-1]) + " " + std::string(argv[i])) );
  527. if (res2 != 0) { // Значение передано, но является некорректным
  528. error(res);
  529. std::cerr << " Wrong value \"" << argv[i] <<"\" for parameter \"" << argv[i-1] << "\"" << std::endl;
  530. return res;
  531. }
  532. }
  533. }
  534. }
  535. }
  536. else { without(); std::this_thread::sleep_for(std::chrono::seconds(1)); }
  537. intro();
  538. displayConfig();
  539. testOutput();
  540. startThreads();
  541. }