/* XMRig * Copyright 2010 Jeff Garzik * Copyright 2012-2014 pooler * Copyright 2014 Lucas Jones * Copyright 2014-2016 Wolf9466 * Copyright 2016 Jay D Dee * Copyright 2017-2019 XMR-Stak , * Copyright 2018-2019 SChernykh * Copyright 2016-2019 XMRig , * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include #include "base/io/Json.h" #include "base/net/Pool.h" #include "rapidjson/document.h" #ifdef APP_DEBUG # include "common/log/Log.h" #endif #ifdef _MSC_VER # define strncasecmp _strnicmp # define strcasecmp _stricmp #endif static const char *kTls = "tls"; static const char *kUrl = "url"; static const char *kUser = "user"; static const char *kPass = "pass"; static const char *kRigId = "rig-id"; static const char *kNicehash = "nicehash"; static const char *kKeepalive = "keepalive"; static const char *kVariant = "variant"; static const char *kFingerprint = "tls-fingerprint"; xmrig::Pool::Pool() : m_nicehash(false), m_tls(false), m_keepAlive(0), m_port(kDefaultPort) { } /** * @brief Parse url. * * Valid urls: * example.com * example.com:3333 * stratum+tcp://example.com * stratum+tcp://example.com:3333 * * @param url */ xmrig::Pool::Pool(const char *url) : m_nicehash(false), m_tls(false), m_keepAlive(0), m_port(kDefaultPort) { parse(url); } xmrig::Pool::Pool(const rapidjson::Value &object) : m_nicehash(false), m_tls(false), m_keepAlive(0), m_port(kDefaultPort) { if (!parse(Json::getString(object, kUrl))) { return; } setUser(Json::getString(object, kUser)); setPassword(Json::getString(object, kPass)); setRigId(Json::getString(object, kRigId)); setNicehash(Json::getBool(object, kNicehash)); const rapidjson::Value &keepalive = object[kKeepalive]; if (keepalive.IsInt()) { setKeepAlive(keepalive.GetInt()); } else if (keepalive.IsBool()) { setKeepAlive(keepalive.GetBool()); } const rapidjson::Value &variant = object[kVariant]; if (variant.IsString()) { algorithm().parseVariant(variant.GetString()); } else if (variant.IsInt()) { algorithm().parseVariant(variant.GetInt()); } m_tls = Json::getBool(object, kTls); m_fingerprint = Json::getString(object, kFingerprint); } xmrig::Pool::Pool(const char *host, uint16_t port, const char *user, const char *password, int keepAlive, bool nicehash, bool tls) : m_nicehash(nicehash), m_tls(tls), m_keepAlive(keepAlive), m_host(host), m_password(password), m_user(user), m_port(port) { const size_t size = m_host.size() + 8; assert(size > 8); char *url = new char[size](); snprintf(url, size - 1, "%s:%d", m_host.data(), m_port); m_url = url; } bool xmrig::Pool::isCompatible(const Algorithm &algorithm) const { if (m_algorithms.empty()) { return true; } for (const auto &a : m_algorithms) { if (algorithm == a) { return true; } } # ifdef XMRIG_PROXY_PROJECT if (m_algorithm.algo() == xmrig::CRYPTONIGHT && algorithm.algo() == xmrig::CRYPTONIGHT) { return m_algorithm.variant() == xmrig::VARIANT_XTL || m_algorithm.variant() == xmrig::VARIANT_MSR; } # endif return false; } bool xmrig::Pool::isEnabled() const { # ifdef XMRIG_NO_TLS if (isTLS()) { return false; } # endif return isValid() && algorithm().isValid(); } bool xmrig::Pool::isEqual(const Pool &other) const { return (m_nicehash == other.m_nicehash && m_tls == other.m_tls && m_keepAlive == other.m_keepAlive && m_port == other.m_port && m_algorithm == other.m_algorithm && m_fingerprint == other.m_fingerprint && m_host == other.m_host && m_password == other.m_password && m_rigId == other.m_rigId && m_url == other.m_url && m_user == other.m_user); } bool xmrig::Pool::parse(const char *url) { assert(url != nullptr); const char *p = strstr(url, "://"); const char *base = url; if (p) { if (strncasecmp(url, "stratum+tcp://", 14) == 0) { m_tls = false; } else if (strncasecmp(url, "stratum+ssl://", 14) == 0) { m_tls = true; } else { return false; } base = url + 14; } if (!strlen(base) || *base == '/') { return false; } m_url = url; if (base[0] == '[') { return parseIPv6(base); } const char *port = strchr(base, ':'); if (!port) { m_host = base; return true; } const size_t size = static_cast(port++ - base + 1); char *host = new char[size](); memcpy(host, base, size - 1); m_host = host; m_port = static_cast(strtol(port, nullptr, 10)); return true; } bool xmrig::Pool::setUserpass(const char *userpass) { const char *p = strchr(userpass, ':'); if (!p) { return false; } char *user = new char[p - userpass + 1](); strncpy(user, userpass, static_cast(p - userpass)); m_user = user; m_password = p + 1; return true; } rapidjson::Value xmrig::Pool::toJSON(rapidjson::Document &doc) const { using namespace rapidjson; auto &allocator = doc.GetAllocator(); Value obj(kObjectType); obj.AddMember(StringRef(kUrl), m_url.toJSON(), allocator); obj.AddMember(StringRef(kUser), m_user.toJSON(), allocator); obj.AddMember(StringRef(kPass), m_password.toJSON(), allocator); obj.AddMember(StringRef(kRigId), m_rigId.toJSON(), allocator); # ifndef XMRIG_PROXY_PROJECT obj.AddMember(StringRef(kNicehash), isNicehash(), allocator); # endif if (m_keepAlive == 0 || m_keepAlive == kKeepAliveTimeout) { obj.AddMember(StringRef(kKeepalive), m_keepAlive > 0, allocator); } else { obj.AddMember(StringRef(kKeepalive), m_keepAlive, allocator); } switch (m_algorithm.variant()) { case VARIANT_AUTO: case VARIANT_0: case VARIANT_1: obj.AddMember(StringRef(kVariant), m_algorithm.variant(), allocator); break; case VARIANT_2: obj.AddMember(StringRef(kVariant), 2, allocator); break; default: obj.AddMember(StringRef(kVariant), StringRef(m_algorithm.variantName()), allocator); break; } obj.AddMember(StringRef(kTls), isTLS(), allocator); obj.AddMember(StringRef(kFingerprint), m_fingerprint.toJSON(), allocator); return obj; } void xmrig::Pool::adjust(const Algorithm &algorithm) { if (!isValid()) { return; } if (!m_algorithm.isValid()) { m_algorithm.setAlgo(algorithm.algo()); adjustVariant(algorithm.variant()); } rebuild(); } void xmrig::Pool::setAlgo(const xmrig::Algorithm &algorithm) { m_algorithm = algorithm; rebuild(); } #ifdef APP_DEBUG void xmrig::Pool::print() const { LOG_NOTICE("url: %s", m_url.data()); LOG_DEBUG ("host: %s", m_host.data()); LOG_DEBUG ("port: %d", static_cast(m_port)); LOG_DEBUG ("user: %s", m_user.data()); LOG_DEBUG ("pass: %s", m_password.data()); LOG_DEBUG ("rig-id %s", m_rigId.data()); LOG_DEBUG ("algo: %s", m_algorithm.name()); LOG_DEBUG ("nicehash: %d", static_cast(m_nicehash)); LOG_DEBUG ("keepAlive: %d", m_keepAlive); } #endif bool xmrig::Pool::parseIPv6(const char *addr) { const char *end = strchr(addr, ']'); if (!end) { return false; } const char *port = strchr(end, ':'); if (!port) { return false; } const size_t size = static_cast(end - addr); char *host = new char[size](); memcpy(host, addr + 1, size - 1); m_host = host; m_port = static_cast(strtol(port + 1, nullptr, 10)); return true; } void xmrig::Pool::addVariant(xmrig::Variant variant) { const xmrig::Algorithm algorithm(m_algorithm.algo(), variant); if (!algorithm.isValid() || m_algorithm == algorithm) { return; } m_algorithms.push_back(algorithm); } void xmrig::Pool::adjustVariant(const xmrig::Variant variantHint) { # ifndef XMRIG_PROXY_PROJECT using namespace xmrig; if (m_host.contains(".nicehash.com")) { m_keepAlive = false; m_nicehash = true; bool valid = true; switch (m_port) { case 3355: case 33355: valid = m_algorithm.algo() == CRYPTONIGHT && m_host.contains("cryptonight."); m_algorithm.setVariant(VARIANT_0); break; case 3363: case 33363: valid = m_algorithm.algo() == CRYPTONIGHT && m_host.contains("cryptonightv7."); m_algorithm.setVariant(VARIANT_1); break; case 3364: valid = m_algorithm.algo() == CRYPTONIGHT_HEAVY && m_host.contains("cryptonightheavy."); m_algorithm.setVariant(VARIANT_0); break; case 3367: case 33367: valid = m_algorithm.algo() == CRYPTONIGHT && m_host.contains("cryptonightv8."); m_algorithm.setVariant(VARIANT_2); break; default: break; } if (!valid) { m_algorithm.setAlgo(INVALID_ALGO); } m_tls = m_port > 33000; return; } if (m_host.contains(".minergate.com")) { m_keepAlive = false; bool valid = true; m_algorithm.setVariant(VARIANT_1); if (m_host.contains("xmr.pool.")) { valid = m_algorithm.algo() == CRYPTONIGHT; m_algorithm.setVariant(m_port == 45700 ? VARIANT_AUTO : VARIANT_0); } else if (m_host.contains("aeon.pool.") && m_port == 45690) { valid = m_algorithm.algo() == CRYPTONIGHT_LITE; m_algorithm.setVariant(VARIANT_1); } if (!valid) { m_algorithm.setAlgo(INVALID_ALGO); } return; } if (variantHint != VARIANT_AUTO) { m_algorithm.setVariant(variantHint); return; } if (m_algorithm.variant() != VARIANT_AUTO) { return; } if (m_algorithm.algo() == CRYPTONIGHT_HEAVY) { m_algorithm.setVariant(VARIANT_0); } else if (m_algorithm.algo() == CRYPTONIGHT_LITE) { m_algorithm.setVariant(VARIANT_1); } # endif } void xmrig::Pool::rebuild() { m_algorithms.clear(); if (!m_algorithm.isValid()) { return; } m_algorithms.push_back(m_algorithm); # ifndef XMRIG_PROXY_PROJECT addVariant(VARIANT_WOW); addVariant(VARIANT_2); addVariant(VARIANT_1); addVariant(VARIANT_0); addVariant(VARIANT_HALF); addVariant(VARIANT_XTL); addVariant(VARIANT_TUBE); addVariant(VARIANT_MSR); addVariant(VARIANT_XHV); addVariant(VARIANT_XAO); addVariant(VARIANT_RTO); addVariant(VARIANT_GPU); addVariant(VARIANT_AUTO); # endif }