微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

通过磁力链接的 SSL 种子

如何解决通过磁力链接的 SSL 种子

我正在使用 SSL 种子设置我的系统。如果我的两个客户都拥有 .torrent,那么即使没有跟踪器也能很好地工作,这要归功于本地服务发现。 所以现在我的下一步是为没有 torrent 的客户端使用磁力链接。 我的两个客户端都只监听 SSL 的一个端口(当监听超过 1 个端口时,他们实际上会感到困惑......)。但是在这种设置中,他们似乎无法进行交流。 这是一种预期,因为 ssl 套接字应该只接受来自具有证书的对等方的连接...

但是,我的设置需要什么才能让客户端下载 SSL Torrent 元数据(torrent 文件)?

非常感谢任何帮助。 这是我的实验代码

#include <iostream>
#include <chrono>
#include <fstream>
#include <csignal>
#include <cstring>

#include <libtorrent/session.hpp>
#include <libtorrent/session_params.hpp>
#include <libtorrent/add_torrent_params.hpp>
#include <libtorrent/torrent_handle.hpp>
#include <libtorrent/alert_types.hpp>
#include <libtorrent/bencode.hpp>
#include <libtorrent/torrent_status.hpp>
#include <libtorrent/read_resume_data.hpp>
#include <libtorrent/write_resume_data.hpp>
#include <libtorrent/error_code.hpp>
#include <libtorrent/magnet_uri.hpp>
#include <libtorrent/torrent.hpp>

using namespace std::chrono_literals;

namespace {

// return the name of a torrent status enum
char const* state(lt::torrent_status::state_t s)
{
  switch(s) {
    case lt::torrent_status::checking_files: return "checking";
    case lt::torrent_status::downloading_Metadata: return "dl Metadata";
    case lt::torrent_status::downloading: return "downloading";
    case lt::torrent_status::finished: return "finished";
    case lt::torrent_status::seeding: return "seeding";
    case lt::torrent_status::checking_resume_data: return "checking resume";
    default: return "<>";
    }
}

std::vector<char> load_file(char const* filename) {
    std::ifstream ifs(filename,std::ios_base::binary);
    ifs.unsetf(std::ios_base::skipws);
    return {std::istream_iterator<char>(ifs),std::istream_iterator<char>()};
}

//// set when we're exiting
std::atomic<bool> shut_down{false};

void sighandler(int) { shut_down = true; }

[[noreturn]] void print_usage(const char* msg) {
    if ( msg )
        std::cerr << msg << std::endl << std::endl;
    std::cerr << R"(
usage: torrent_client [OPTIONS]

--magnet magnet_link   Magnet link URI
--cert_path PATH       path where to find client.crt/key and dhparams.pem
--torrent_path PATH    path to torrent file
--data_path PATH       path where the data is or will be stored
--dht_nodes            csv list of host tuples. e.g.,10.1:4444,10.2:5678[,...]
--listen_port port     port the client is listening too
--server               determines if this is a server (and does not require checking the files on disk)
)";
    std::exit(1);
}

} // anonymous namespace


int main(int argc_,char* argv_[]) try {
    lt::span<char *> args(argv_,argc_);
    args = args.subspan(1);
    if ( args.size() < 2 )
        print_usage("");

    std::vector<std::pair<std::string,int>> dht_nodes;
    auto session_params = load_file(".session");
    lt::session_params params = (session_params.empty()
      ? lt::session_params()
      : lt::read_session_params(session_params)
    );

    params.settings.set_int(lt::settings_pack::alert_mask,lt::alert_category_t::all()
//        lt::alert_category::error
//      | lt::alert_category::storage
//      | lt::alert_category::status
//      | lt::alert_category::connect
//     // | lt::alert_category::dht
    );

    //trying with tracker+lsd only...
    params.settings.set_bool(lt::settings_pack::enable_dht,false);
    params.settings.set_bool(lt::settings_pack::enable_lsd,true);
    params.settings.set_bool(lt::settings_pack::enable_upnp,false);
    params.settings.set_bool(lt::settings_pack::enable_natpmp,false);

    //params.settings.set_str(params.settings.dht_bootstrap_nodes,""); //do not default to libtorrent's own dht nodes...


    lt::add_torrent_params atp;
    bool has_torrent_info = false;
    bool has_magnet_link = false;
    bool is_server = false;
    std::string certPath;
    atp.save_path = ".";
    int port = 0;

    bool param_has_value = true;
    for (; !args.empty(); args = args.subspan(1 + param_has_value)) {
        if ( 0 == strcmp(args[0],"--server") ) {
            is_server = true;
            param_has_value = false;
        } else  {
            param_has_value = true;
            if ( args.size() < 2 )
                print_usage("Missing value.");

            if ( 0 == strcmp(args[0],"--torrent_path") ) {
                printf("Torrent path: %s\n",args[1]);
                atp.ti = std::make_shared<lt::torrent_info>(std::string(args[1]));
                has_torrent_info = true;
            }
            else if ( 0 == strcmp(args[0],"--data_path") ) {
                printf("Data path: %s\n",args[1]);
                atp.save_path = std::string(args[1]);
            }
            else if ( 0 == strcmp(args[0],"--dht_nodes") ) {
                printf("Settings DHT node: %s\n",args[1]);
                params.settings.set_str(params.settings.dht_bootstrap_nodes,args[1]);
            }
            else if ( 0 == strcmp(args[0],"--magnet") ) {
                lt::error_code ec;
                lt::parse_magnet_uri(args[1],atp,ec);
                has_magnet_link = true;
            }
            else if ( 0 == strcmp(args[0],"--cert_path") ) {
                printf("Torrent certpath: %s\n",args[1]);
                certPath = std::string(args[1]);
            }
            else if ( 0 == strcmp(args[0],"--listen_port") ) {
                printf("Torrent listen port: %s\n",args[1]);
                port = atoi(args[1]);
            }
            else {
                print_usage(args[0]);
            }
        }
    }

    if (port) { //setting the listening interface
        std::ostringstream stringStream;
        stringStream << "0.0.0.0:" << port;
        if (!certPath.empty()) {
            stringStream << "s"; //,127.0.0.1:" << port+1 << "s";
        }

        std::string copyOfStr = stringStream.str();
        params.settings.set_str(params.settings.listen_interfaces,copyOfStr);
        std::cout << "LISTENING INTERFACES " << copyOfStr << std::endl;
    } else {
        std::cout << "no port was specified,that client will not be listening" << std::endl;
    }

    lt::session ses(std::move(params));

    if ( has_magnet_link && has_torrent_info ) {
        printf("Stupid PoC code.  For Now,--magnet and --torrent_path are mutually exclusive.\n");
        std::exit(1);
    }

    // load resume data from disk and pass it in as we add the magnet link
    auto buf = load_file(".resume_file");

    if ( buf.size() ) {
        lt::add_torrent_params resume = lt::read_resume_data(buf);
        if (atp.info_hashes == resume.info_hashes) {
            atp = std::move(resume);
        }
    }

    if (is_server) {
        printf("seeding mode,No need to check pieces.\n");
        atp.flags |= lt::torrent_flags::seed_mode; //seeding only (no check at startup);
    }

    ses.async_add_torrent(std::move(atp));

    std::signal(SIGINT,&sighandler);

    // set when we're exiting
    bool done = false;
    for (;ses.wait_for_alert(1s);) {
        std::vector<lt::alert*> alerts;
        ses.pop_alerts(&alerts);

        if (shut_down) {
            shut_down = false;
            auto const handles = ses.get_torrents();
            if (handles.size() == 1) {
                handles[0].save_resume_data(lt::torrent_handle::save_info_dict);
                done = true;
            }
        }

        for (lt::alert * a : alerts) {
            if (auto at = lt::alert_cast<lt::add_torrent_alert>(a)) {
                std::cout << "add_torrent_alert,torrent file " << at->handle.torrent_file() << std::endl;
            }
            // if we receive the finished alert or an error,we're done
            else if (auto fal = lt::alert_cast<lt::torrent_finished_alert>(a)) {
                if (!is_server) {
                    fal->handle.save_resume_data(lt::torrent_handle::save_info_dict);
                }
            }
            else if (auto error_alert = lt::alert_cast<lt::torrent_error_alert>(a)) {
                std::cout << "\n\n\n\n ERROR\n\n\n\n";
                std::cout << a->message() << std::endl;
                done = true;
                error_alert->handle.save_resume_data(lt::torrent_handle::save_info_dict);
            } else if (auto rd = lt::alert_cast<lt::save_resume_data_alert>(a)) {
                std::ofstream of(".resume_file",std::ios_base::binary);
                of.unsetf(std::ios_base::skipws);
                auto const b = write_resume_data_buf(rd->params);
                of.write(b.data(),int(b.size()));
                if (done)
                    goto done;
            } else if (lt::alert_cast<lt::save_resume_data_Failed_alert>(a)) {
                if (done)
                    goto done;
            } else if (auto st = lt::alert_cast<lt::state_update_alert>(a)) {
                if (st->status.empty())
                    continue;

                // we only have a single torrent,so we kNow which one
                // the status is for
                lt::torrent_status const& s = st->status[0];
                std::cout << '\r' << state(s.state) << ' '
                          << (s.download_payload_rate / 1000) << " kB/s "
                          << (s.total_done / 1000) << " kB ("
                          << (s.progress_ppm / 10000) << "%) downloaded ("
                          << s.num_peers << " peers)\x1b[K";
                std::cout.flush();
            } else if (auto ssl_alert = lt::alert_cast<lt::torrent_need_cert_alert>(a)) {
                std::cout << a->message() << std::endl;
                if (!certPath.empty()) {
                    std::string clientCert = certPath + "/client.crt";
                    std::string clientPKey = certPath + "/client.key";
                    std::string dhparams = certPath + "/dhparams.pem";
                    std::cout << "ADDING TORRENT,setting client certificate " << clientCert << std::endl;
                    lt::torrent_handle t = ssl_alert->handle;
                    t.set_ssl_certificate(clientCert,clientPKey,dhparams);
                }
            }else {
                std::cout << "unhandled alert " << a->message() << std::endl;
            }
        }

        // ask the session to post a state_update_alert,to update our
        // state output for the torrent
        ses.post_torrent_updates();
    }

done:
    std::cout << "\nsaving session state" << std::endl;
    {
        std::ofstream of(".session",std::ios_base::binary);
        of.unsetf(std::ios_base::skipws);
        auto const b = write_session_params_buf(ses.session_state(),lt::save_state_flags_t::all());
        of.write(b.data(),int(b.size()));
    }

    std::cout << "\ndone,shutting down" << std::endl;
}
catch (std::exception& e) {
  std::cerr << "Error: " << e.what() << std::endl;
}

所以我开始我的播种客户端

torrent_client --cert_path <cert_path> --torrent_path foo.ssltorrent --listen_port 27400 --server

...还有我需要的客户

torrent_client --cert_path {cert_path} --torrent_path toto.ssltorrent --listen_port 27300

这就像一个魅力。并不是说 cert_path 是我的客户端证书的路径,其中主题备用名称设置为 * 以及我使用 openssl 生成的 sh params 文件

但是如果我这样做:

torrent_client --cert_path {cert_path} --magnet "{magnet link}" --listen_port 27300

这会卡在“dl 元数据”上。

当然,用非 SSL Torrent 尝试同样的事情就像一个魅力。

-----经过深思熟虑后编辑------

因为这很有意义:能够加入群意味着一个人需要使用适当的证书并知道底层的 torrent 是 SSL 的,所以我继续更改了我的代码管理1 个提醒

           if (auto at = lt::alert_cast<lt::add_torrent_alert>(a)) {
                std::cout << "add_torrent_alert,torrent file " << at->handle.torrent_file() << std::endl;
                if (!at->handle.torrent_file() && !certPath.empty()) {
                   auto contents = load_file(certPath + "/ca.crt");

                   lt::string_view c{contents.data(),contents.size()};

                   //Todo: find a better way
                   at->handle.native_handle()->m_ssl_torrent = 1;
                   at->handle.native_handle()->init_ssl(c);
                   std::cout << "setting the certificate of the magnet torrent" << std::endl;
                }

            }

这完全是丑陋的(使用私有 api),但它似乎确实有效。我会努力寻找更好的解决方案。

所以如果我错过了什么,请告诉我。 谢谢。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。