Skip to content
This repository was archived by the owner on Jan 2, 2025. It is now read-only.

Commit eccd5e7

Browse files
authored
Allow to run NDT over Tor (#15)
* Start adding support for NDT over Tor * curlx_test.cpp: fix test I have broken Now init() is idempotent in the proper sense, while before the behavior was consistent but possibly not idempotent. * Revert small, unnecessary change * libndt.cpp: fix MSVC 32 bit build * Repair build * revamp socks5 code * libndt.cpp: attempt to fix windows build * Write tests to cover more curlx methods * Add one more simple test * libndt_test: use connect_tcp_maybe_socks5() Of course, where it makes sense. * Start adding more tests for socks5h * Repair build error * More tests for socks5 code * Fix previous * Add some more tests * More socks5 tests * more tests * improve tests * add two more tests * Remove unused methods * Final changes before merging
1 parent b8540dd commit eccd5e7

File tree

7 files changed

+880
-53
lines changed

7 files changed

+880
-53
lines changed

curlx.cpp

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,25 @@ void CurlDeleter::operator()(CURL *handle) noexcept {
4242

4343
Curl::Curl() noexcept {}
4444

45+
bool Curl::method_get_maybe_socks5(const std::string &proxy_port,
46+
const std::string &url, long timeout,
47+
std::string *body,
48+
std::string *err) noexcept {
49+
if (!init()) {
50+
*err = "cannot initialize cURL";
51+
return false;
52+
}
53+
if (!proxy_port.empty()) {
54+
std::stringstream ss;
55+
ss << "socks5h://127.0.0.1:" << proxy_port;
56+
if (setopt_proxy(ss.str()) != CURLE_OK) {
57+
*err = "cannot set proxy";
58+
return false;
59+
}
60+
}
61+
return method_get(url, timeout, body, err);
62+
}
63+
4564
bool Curl::method_get(const std::string &url, long timeout, std::string *body,
4665
std::string *err) noexcept {
4766
if (body == nullptr || err == nullptr) {
@@ -80,7 +99,7 @@ bool Curl::method_get(const std::string &url, long timeout, std::string *body,
8099

81100
bool Curl::init() noexcept {
82101
if (!!handle_) {
83-
return false;
102+
return true; // make the method idempotent
84103
}
85104
auto handle = this->easy_init();
86105
if (!handle) {
@@ -95,6 +114,11 @@ CURLcode Curl::setopt_url(const std::string &url) noexcept {
95114
return ::curl_easy_setopt(handle_.get(), CURLOPT_URL, url.c_str());
96115
}
97116

117+
CURLcode Curl::setopt_proxy(const std::string &url) noexcept {
118+
assert(handle_);
119+
return ::curl_easy_setopt(handle_.get(), CURLOPT_PROXY, url.c_str());
120+
}
121+
98122
CURLcode Curl::setopt_writefunction(size_t (*callback)(
99123
char *ptr, size_t size, size_t nmemb, void *userdata)) noexcept {
100124
assert(handle_);

curlx.hpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,10 @@ class Curl {
2626

2727
Curl() noexcept;
2828

29+
bool method_get_maybe_socks5(const std::string &proxy_port,
30+
const std::string &url, long timeout,
31+
std::string *body, std::string *err) noexcept;
32+
2933
bool method_get(const std::string &url, long timeout, std::string *body,
3034
std::string *err) noexcept;
3135

@@ -35,6 +39,8 @@ class Curl {
3539

3640
virtual CURLcode setopt_url(const std::string &url) noexcept;
3741

42+
virtual CURLcode setopt_proxy(const std::string &url) noexcept;
43+
3844
virtual CURLcode setopt_writefunction(size_t (*callback)(
3945
char *ptr, size_t size, size_t nmemb, void *userdata)) noexcept;
4046

curlx_test.cpp

Lines changed: 44 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,40 @@
99

1010
using namespace measurement_kit;
1111

12+
// Curl::method_get_maybe_socks5() tests
13+
// -------------------------------------
14+
15+
class FailInit : public libndt::Curl {
16+
public:
17+
using libndt::Curl::Curl;
18+
virtual bool init() noexcept override { return false; }
19+
};
20+
21+
TEST_CASE("Curl::method_get_maybe_socks5() deals with Curl::init() failure") {
22+
FailInit curl;
23+
std::string body;
24+
std::string err;
25+
REQUIRE(!curl.method_get_maybe_socks5("", "http://x.org", 1, &body, &err));
26+
}
27+
28+
class FailSetoptProxy : public libndt::Curl {
29+
public:
30+
using libndt::Curl::Curl;
31+
virtual CURLcode setopt_proxy(const std::string &) noexcept override {
32+
return CURLE_UNSUPPORTED_PROTOCOL; // any error is okay here
33+
}
34+
};
35+
36+
TEST_CASE(
37+
"Curl::method_get_maybe_socks5() deals with Curl::setopt_proxy() failure") {
38+
FailSetoptProxy curl;
39+
std::string body;
40+
std::string err;
41+
REQUIRE(
42+
!curl.method_get_maybe_socks5("9050", "http://x.org", 1, &body, &err));
43+
REQUIRE(err == "cannot set proxy");
44+
}
45+
1246
// Curl::method_get() tests
1347
// ------------------------
1448

@@ -24,12 +58,6 @@ TEST_CASE("Curl::method_get() deals with null err") {
2458
REQUIRE(curl.method_get("http://x.org", 1, &body, nullptr) == false);
2559
}
2660

27-
class FailInit : public libndt::Curl {
28-
public:
29-
using libndt::Curl::Curl;
30-
virtual bool init() noexcept override { return false; }
31-
};
32-
3361
TEST_CASE("Curl::method_get() deals with Curl::init() failure") {
3462
FailInit curl;
3563
std::string body;
@@ -129,7 +157,16 @@ TEST_CASE("Curl::init() deals with curl_easy_init() failure") {
129157
TEST_CASE("Curl::init() is idempotent") {
130158
libndt::Curl curl;
131159
REQUIRE(curl.init() == true);
132-
REQUIRE(curl.init() == false);
160+
REQUIRE(curl.init() == true);
161+
}
162+
163+
// Curl::setopt_proxy() tests
164+
// --------------------------
165+
166+
TEST_CASE("Curl::setopt_proxy() works") {
167+
libndt::Curl curl;
168+
REQUIRE(curl.init() == true);
169+
REQUIRE(curl.setopt_proxy("socks5h://127.0.0.1:9050") == CURLE_OK);
133170
}
134171

135172
#endif // HAVE_CURL

libndt-client.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ static void usage() {
2020
std::clog << " --download-ext : run multi-stream download test\n";
2121
std::clog << " --json : use the JSON protocol\n";
2222
std::clog << " --port <port> : use the specified port\n";
23+
std::clog
24+
<< " --socks5h <port> : use socks5h proxy at 127.0.0.1:<port>\n";
2325
std::clog << " --upload : run upload test\n";
2426
std::clog << " --verbose : be verbose\n";
2527
std::clog << "\n";
@@ -31,11 +33,12 @@ int main(int, char **argv) {
3133
using namespace measurement_kit;
3234
libndt::Settings settings;
3335
settings.verbosity = libndt::verbosity::quiet;
34-
settings.test_suite = 0; // you need to enable tests explicitly
36+
settings.test_suite = 0; // you need to enable tests explicitly
3537

3638
{
3739
argh::parser cmdline;
3840
cmdline.add_param("port");
41+
cmdline.add_param("socks5h");
3942
cmdline.parse(argv);
4043
for (auto &flag : cmdline.flags()) {
4144
if (flag == "download") {
@@ -63,6 +66,10 @@ int main(int, char **argv) {
6366
if (param.first == "port") {
6467
settings.port = param.second;
6568
std::clog << "will use port: " << param.second << std::endl;
69+
} else if (param.first == "socks5h") {
70+
settings.socks5h_port = param.second;
71+
std::clog << "will use socks5h proxy at: 127.0.0.1:" << param.second
72+
<< std::endl;
6673
} else {
6774
std::clog << "fatal: unrecognized param: " << param.first << std::endl;
6875
usage();

0 commit comments

Comments
 (0)