1 #define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN 2 #include <doctest/doctest.h> 3 4 #include <tests/connection_handler_simulator/pub.hpp> 5 6 #include <asio.hpp> 7 8 using namespace std::string_view_literals; 9 using namespace std::chrono_literals; 10 11 namespace chs = connection_handler_simulator; 12 13 TEST_CASE("no auth PDU") { 14 asio::ip::tcp::endpoint proxy_endpoint{ 15 asio::ip::make_address_v4( "127.0.0.1" ), 16 2444 17 }; 18 19 chs::simulator_t simulator{ 20 proxy_endpoint, 21 chs::handler_config_values_t{} 22 }; 23 24 asio::io_context ctx; 25 26 asio::ip::tcp::socket connection{ ctx }; 27 REQUIRE_NOTHROW( connection.connect( proxy_endpoint ) ); 28 29 { 30 std::array< std::uint8_t, 3 > first_pdu{ 0x5u, 0x1u, 0x2u }; 31 std::size_t written; 32 REQUIRE_NOTHROW( written = connection.write_some( asio::buffer(first_pdu) ) ); 33 REQUIRE( first_pdu.size() == written ); 34 } 35 36 { 37 std::array< std::uint8_t, 20 > response; 38 std::size_t read; 39 REQUIRE_NOTHROW( read = connection.read_some( asio::buffer(response) ) ); 40 REQUIRE( 2u == read ); 41 REQUIRE( 0x5u == response[ 0 ] ); 42 REQUIRE( 0x2u == response[ 1 ] ); 43 } 44 45 // The connection has to be closed on the other side. 46 { 47 std::array< std::uint8_t, 20 > data; 48 asio::error_code ec; 49 REQUIRE_NOTHROW( connection.read_some( asio::buffer(data), ec ) ); 50 REQUIRE( asio::error::eof == ec ); 51 } 52 53 chs::dump_trace( (std::cout << "-----\n"), simulator.get_trace() ); 54 } 55 56 TEST_CASE("no auth PDU (one byte per second)") { 57 asio::ip::tcp::endpoint proxy_endpoint{ 58 asio::ip::make_address_v4( "127.0.0.1" ), 59 2444 60 }; 61 62 chs::handler_config_values_t config_values; 63 config_values.m_socks_handshake_phase_timeout = 3s; 64 chs::simulator_t simulator{ 65 proxy_endpoint, 66 config_values 67 }; 68 69 asio::io_context ctx; 70 71 asio::ip::tcp::socket connection{ ctx }; 72 REQUIRE_NOTHROW( connection.connect( proxy_endpoint ) ); 73 74 { 75 std::array< std::uint8_t, 1 > first_pdu{ 0x5u }; 76 std::size_t written; 77 REQUIRE_NOTHROW( written = connection.write_some( asio::buffer(first_pdu) ) ); 78 REQUIRE( first_pdu.size() == written ); 79 80 std::this_thread::sleep_for( 1s ); 81 } 82 83 { 84 std::array< std::uint8_t, 1 > first_pdu{ 0x1u }; 85 std::size_t written; 86 REQUIRE_NOTHROW( written = connection.write_some( asio::buffer(first_pdu) ) ); 87 REQUIRE( first_pdu.size() == written ); 88 89 std::this_thread::sleep_for( 1s ); 90 } 91 92 { 93 std::array< std::uint8_t, 1 > first_pdu{ 0x2u }; 94 std::size_t written; 95 REQUIRE_NOTHROW( written = connection.write_some( asio::buffer(first_pdu) ) ); 96 REQUIRE( first_pdu.size() == written ); 97 } 98 99 { 100 std::array< std::uint8_t, 20 > response; 101 std::size_t read; 102 REQUIRE_NOTHROW( read = connection.read_some( asio::buffer(response) ) ); 103 REQUIRE( 2u == read ); 104 REQUIRE( 0x5u == response[ 0 ] ); 105 REQUIRE( 0x2u == response[ 1 ] ); 106 } 107 108 // The connection has to be closed on the other side. 109 { 110 std::array< std::uint8_t, 20 > data; 111 asio::error_code ec; 112 REQUIRE_NOTHROW( connection.read_some( asio::buffer(data), ec ) ); 113 REQUIRE( asio::error::eof == ec ); 114 } 115 116 chs::dump_trace( (std::cout << "-----\n"), simulator.get_trace() ); 117 } 118 119 TEST_CASE("wrong auth PDU version") { 120 asio::ip::tcp::endpoint proxy_endpoint{ 121 asio::ip::make_address_v4( "127.0.0.1" ), 122 2444 123 }; 124 125 chs::simulator_t simulator{ 126 proxy_endpoint, 127 chs::handler_config_values_t{} 128 }; 129 130 asio::io_context ctx; 131 132 asio::ip::tcp::socket connection{ ctx }; 133 REQUIRE_NOTHROW( connection.connect( proxy_endpoint ) ); 134 135 { 136 std::array< std::uint8_t, 3 > first_pdu{ 0x5u, 0x1u, 0x2u }; 137 std::size_t written; 138 REQUIRE_NOTHROW( written = connection.write_some( asio::buffer(first_pdu) ) ); 139 REQUIRE( first_pdu.size() == written ); 140 } 141 142 { 143 std::array< std::uint8_t, 20 > response; 144 std::size_t read; 145 REQUIRE_NOTHROW( read = connection.read_some( asio::buffer(response) ) ); 146 REQUIRE( 2u == read ); 147 REQUIRE( 0x5u == response[ 0 ] ); 148 REQUIRE( 0x2u == response[ 1 ] ); 149 } 150 151 { 152 std::array< std::uint8_t, 12 > data{ 153 0x2, 154 0x4, 'u', 's', 'e', 'r', 155 0x5, '1', '2', '3', '4', '5' 156 }; 157 std::size_t written; 158 REQUIRE_NOTHROW( written = connection.write_some( asio::buffer(data) ) ); 159 REQUIRE( data.size() == written ); 160 } 161 162 // The connection has to be closed on the other side. 163 { 164 std::array< std::uint8_t, 20 > data; 165 asio::error_code ec; 166 REQUIRE_NOTHROW( connection.read_some( asio::buffer(data), ec ) ); 167 REQUIRE( asio::error::eof == ec ); 168 } 169 170 chs::dump_trace( (std::cout << "-----\n"), simulator.get_trace() ); 171 } 172 173 TEST_CASE("partial auth PDU then close connection") { 174 asio::ip::tcp::endpoint proxy_endpoint{ 175 asio::ip::make_address_v4( "127.0.0.1" ), 176 2444 177 }; 178 179 chs::simulator_t simulator{ 180 proxy_endpoint, 181 chs::handler_config_values_t{} 182 }; 183 184 asio::io_context ctx; 185 186 asio::ip::tcp::socket connection{ ctx }; 187 REQUIRE_NOTHROW( connection.connect( proxy_endpoint ) ); 188 189 { 190 std::array< std::uint8_t, 3 > first_pdu{ 0x5u, 0x1u, 0x2u }; 191 std::size_t written; 192 REQUIRE_NOTHROW( written = connection.write_some( asio::buffer(first_pdu) ) ); 193 REQUIRE( first_pdu.size() == written ); 194 } 195 196 { 197 std::array< std::uint8_t, 20 > response; 198 std::size_t read; 199 REQUIRE_NOTHROW( read = connection.read_some( asio::buffer(response) ) ); 200 REQUIRE( 2u == read ); 201 REQUIRE( 0x5u == response[ 0 ] ); 202 REQUIRE( 0x2u == response[ 1 ] ); 203 } 204 205 { 206 std::array< std::uint8_t, 5 > data{ 207 0x1, 208 0x4, 'u', 's', 'e' 209 }; 210 std::size_t written; 211 REQUIRE_NOTHROW( written = connection.write_some( asio::buffer(data) ) ); 212 REQUIRE( data.size() == written ); 213 } 214 215 connection.close(); 216 217 std::this_thread::sleep_for( 1s ); 218 219 chs::dump_trace( (std::cout << "-----\n"), simulator.get_trace() ); 220 } 221 222 TEST_CASE("partial auth PDU") { 223 asio::ip::tcp::endpoint proxy_endpoint{ 224 asio::ip::make_address_v4( "127.0.0.1" ), 225 2444 226 }; 227 228 chs::simulator_t simulator{ 229 proxy_endpoint, 230 chs::handler_config_values_t{} 231 }; 232 233 asio::io_context ctx; 234 235 asio::ip::tcp::socket connection{ ctx }; 236 REQUIRE_NOTHROW( connection.connect( proxy_endpoint ) ); 237 238 { 239 std::array< std::uint8_t, 3 > first_pdu{ 0x5u, 0x1u, 0x2u }; 240 std::size_t written; 241 REQUIRE_NOTHROW( written = connection.write_some( asio::buffer(first_pdu) ) ); 242 REQUIRE( first_pdu.size() == written ); 243 } 244 245 { 246 std::array< std::uint8_t, 20 > response; 247 std::size_t read; 248 REQUIRE_NOTHROW( read = connection.read_some( asio::buffer(response) ) ); 249 REQUIRE( 2u == read ); 250 REQUIRE( 0x5u == response[ 0 ] ); 251 REQUIRE( 0x2u == response[ 1 ] ); 252 } 253 254 { 255 std::array< std::uint8_t, 5 > data{ 256 0x1, 257 0x4, 'u', 's', 'e' 258 }; 259 std::size_t written; 260 REQUIRE_NOTHROW( written = connection.write_some( asio::buffer(data) ) ); 261 REQUIRE( data.size() == written ); 262 } 263 264 // The connection has to be closed on the other side. 265 { 266 std::array< std::uint8_t, 20 > data; 267 asio::error_code ec; 268 REQUIRE_NOTHROW( connection.read_some( asio::buffer(data), ec ) ); 269 REQUIRE( asio::error::eof == ec ); 270 } 271 272 chs::dump_trace( (std::cout << "-----\n"), simulator.get_trace() ); 273 } 274 275 TEST_CASE("garbage after auth PDU") { 276 asio::ip::tcp::endpoint proxy_endpoint{ 277 asio::ip::make_address_v4( "127.0.0.1" ), 278 2444 279 }; 280 281 chs::simulator_t simulator{ 282 proxy_endpoint, 283 chs::handler_config_values_t{} 284 }; 285 286 asio::io_context ctx; 287 288 asio::ip::tcp::socket connection{ ctx }; 289 REQUIRE_NOTHROW( connection.connect( proxy_endpoint ) ); 290 291 { 292 std::array< std::uint8_t, 3 > first_pdu{ 0x5u, 0x1u, 0x2u }; 293 std::size_t written; 294 REQUIRE_NOTHROW( written = connection.write_some( asio::buffer(first_pdu) ) ); 295 REQUIRE( first_pdu.size() == written ); 296 } 297 298 { 299 std::array< std::uint8_t, 20 > response; 300 std::size_t read; 301 REQUIRE_NOTHROW( read = connection.read_some( asio::buffer(response) ) ); 302 REQUIRE( 2u == read ); 303 REQUIRE( 0x5u == response[ 0 ] ); 304 REQUIRE( 0x2u == response[ 1 ] ); 305 } 306 307 { 308 std::array< std::uint8_t, 28 > data{ 309 0x1, 310 0x4, 'u', 's', 'e', 'r', 311 0x5, '1', '2', '3', '4', '5', 'a', 'b', 'c', 312 0x5, 0x1, 0x0, 313 0x3, 0x6, 'y', 'a', '.', 'c', 'o', 'm', 314 0x01, 0x00 315 }; 316 std::size_t written; 317 REQUIRE_NOTHROW( written = connection.write_some( asio::buffer(data) ) ); 318 REQUIRE( data.size() == written ); 319 } 320 321 // Since v.0.5.0 the size of auth PDU isn't checked. 322 { 323 std::array< std::uint8_t, 20 > data; 324 std::size_t bytes_read{}; 325 REQUIRE_NOTHROW( bytes_read = connection.read_some( asio::buffer(data) ) ); 326 REQUIRE( 2u == bytes_read ); 327 } 328 329 chs::dump_trace( (std::cout << "-----\n"), simulator.get_trace() ); 330 } 331 332 TEST_CASE("zero-length username/password") { 333 asio::ip::tcp::endpoint proxy_endpoint{ 334 asio::ip::make_address_v4( "127.0.0.1" ), 335 2444 336 }; 337 338 chs::simulator_t simulator{ 339 proxy_endpoint, 340 chs::handler_config_values_t{} 341 }; 342 343 asio::io_context ctx; 344 345 asio::ip::tcp::socket connection{ ctx }; 346 REQUIRE_NOTHROW( connection.connect( proxy_endpoint ) ); 347 348 { 349 std::array< std::uint8_t, 3 > first_pdu{ 0x5u, 0x1u, 0x2u }; 350 std::size_t written; 351 REQUIRE_NOTHROW( written = connection.write_some( asio::buffer(first_pdu) ) ); 352 REQUIRE( first_pdu.size() == written ); 353 } 354 355 { 356 std::array< std::uint8_t, 20 > response; 357 std::size_t read; 358 REQUIRE_NOTHROW( read = connection.read_some( asio::buffer(response) ) ); 359 REQUIRE( 2u == read ); 360 REQUIRE( 0x5u == response[ 0 ] ); 361 REQUIRE( 0x2u == response[ 1 ] ); 362 } 363 364 { 365 std::array< std::uint8_t, 3 > data{ 366 0x1, 367 0x0, 368 0x0 369 }; 370 std::size_t written; 371 REQUIRE_NOTHROW( written = connection.write_some( asio::buffer(data) ) ); 372 REQUIRE( data.size() == written ); 373 } 374 375 { 376 std::array< std::uint8_t, 20 > response; 377 std::size_t read; 378 REQUIRE_NOTHROW( read = connection.read_some( asio::buffer(response) ) ); 379 REQUIRE( 2u == read ); 380 REQUIRE( 0x1u == response[ 0 ] ); 381 REQUIRE( 0x0u == response[ 1 ] ); 382 } 383 384 chs::dump_trace( (std::cout << "-----\n"), simulator.get_trace() ); 385 } 386 387 TEST_CASE("valid auth PDU") { 388 asio::ip::tcp::endpoint proxy_endpoint{ 389 asio::ip::make_address_v4( "127.0.0.1" ), 390 2444 391 }; 392 393 chs::simulator_t simulator{ 394 proxy_endpoint, 395 chs::handler_config_values_t{} 396 }; 397 398 asio::io_context ctx; 399 400 asio::ip::tcp::socket connection{ ctx }; 401 REQUIRE_NOTHROW( connection.connect( proxy_endpoint ) ); 402 403 { 404 std::array< std::uint8_t, 3 > first_pdu{ 0x5u, 0x1u, 0x2u }; 405 std::size_t written; 406 REQUIRE_NOTHROW( written = connection.write_some( asio::buffer(first_pdu) ) ); 407 REQUIRE( first_pdu.size() == written ); 408 } 409 410 { 411 std::array< std::uint8_t, 20 > response; 412 std::size_t read; 413 REQUIRE_NOTHROW( read = connection.read_some( asio::buffer(response) ) ); 414 REQUIRE( 2u == read ); 415 REQUIRE( 0x5u == response[ 0 ] ); 416 REQUIRE( 0x2u == response[ 1 ] ); 417 } 418 419 { 420 std::array< std::uint8_t, 12 > data{ 421 0x1, 422 0x4, 'u', 's', 'e', 'r', 423 0x5, '1', '2', '3', '4', '5' 424 }; 425 std::size_t written; 426 REQUIRE_NOTHROW( written = connection.write_some( asio::buffer(data) ) ); 427 REQUIRE( data.size() == written ); 428 } 429 430 { 431 std::array< std::uint8_t, 20 > response; 432 std::size_t read; 433 REQUIRE_NOTHROW( read = connection.read_some( asio::buffer(response) ) ); 434 REQUIRE( 2u == read ); 435 REQUIRE( 0x1u == response[ 0 ] ); 436 REQUIRE( 0x0u == response[ 1 ] ); 437 } 438 439 chs::dump_trace( (std::cout << "-----\n"), simulator.get_trace() ); 440 } 441 442 TEST_CASE("auth method with auth PDU as one package") { 443 asio::ip::tcp::endpoint proxy_endpoint{ 444 asio::ip::make_address_v4( "127.0.0.1" ), 445 2444 446 }; 447 448 chs::simulator_t simulator{ 449 proxy_endpoint, 450 chs::handler_config_values_t{} 451 }; 452 453 asio::io_context ctx; 454 455 asio::ip::tcp::socket connection{ ctx }; 456 REQUIRE_NOTHROW( connection.connect( proxy_endpoint ) ); 457 458 { 459 std::array< std::uint8_t, 15 > first_pdu{ 460 0x5u, 0x1u, 0x2u, // Auth method selection. 461 0x1, // Auth PDU. 462 0x4, 'u', 's', 'e', 'r', 463 0x5, '1', '2', '3', '4', '5' 464 }; 465 std::size_t written; 466 REQUIRE_NOTHROW( written = connection.write_some( asio::buffer(first_pdu) ) ); 467 REQUIRE( first_pdu.size() == written ); 468 } 469 470 { 471 std::array< std::uint8_t, 2 > response; 472 std::size_t read; 473 REQUIRE_NOTHROW( read = connection.read_some( asio::buffer(response) ) ); 474 REQUIRE( 2u == read ); 475 REQUIRE( 0x5u == response[ 0 ] ); 476 REQUIRE( 0x2u == response[ 1 ] ); 477 } 478 479 { 480 std::array< std::uint8_t, 20 > response; 481 std::size_t read; 482 REQUIRE_NOTHROW( read = connection.read_some( asio::buffer(response) ) ); 483 REQUIRE( 2u == read ); 484 REQUIRE( 0x1u == response[ 0 ] ); 485 REQUIRE( 0x0u == response[ 1 ] ); 486 } 487 488 chs::dump_trace( (std::cout << "-----\n"), simulator.get_trace() ); 489 } 490 491