1 #define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN
2 #include <doctest/doctest.h>
3
4 #include <arataga/acl_handler/buffers.hpp>
5
6 #include <tests/connection_handler_simulator/pub.hpp>
7
8 #include <asio.hpp>
9
10 using namespace std::string_view_literals;
11 using namespace std::chrono_literals;
12
13 namespace chs = connection_handler_simulator;
14
15 void
write_auth_pdu(asio::ip::tcp::socket & connection,std::string username="user",std::string password="1234")16 write_auth_pdu(
17 asio::ip::tcp::socket & connection,
18 std::string username = "user",
19 std::string password = "1234" )
20 {
21 {
22 std::array< std::uint8_t, 3 > first_pdu{ 0x5u, 0x1u, 0x2u };
23 REQUIRE_NOTHROW( asio::write( connection, asio::buffer(first_pdu) ) );
24 }
25
26 {
27 std::array< std::uint8_t, 20 > response;
28 std::size_t read;
29 REQUIRE_NOTHROW( read = connection.read_some( asio::buffer(response) ) );
30 REQUIRE( 2u == read );
31 REQUIRE( 0x5u == response[ 0 ] );
32 REQUIRE( 0x2u == response[ 1 ] );
33 }
34
35 {
36 arataga::acl_handler::out_buffer_fixed_t< 1u + 1u + 255u + 1u + 255u >
37 data;
38
39 data.write_byte( std::byte{0x1u} );
40 data.write_byte( std::byte{ static_cast<std::uint8_t>(username.size()) } );
41 data.write_string( username );
42 data.write_byte( std::byte{ static_cast<std::uint8_t>(password.size()) } );
43 data.write_string( password );
44
45 REQUIRE_NOTHROW( asio::write( connection, data.asio_buffer() ) );
46 }
47
48 {
49 std::array< std::uint8_t, 20 > response;
50 std::size_t read;
51 REQUIRE_NOTHROW( read = connection.read_some( asio::buffer(response) ) );
52 REQUIRE( 2u == read );
53 REQUIRE( 0x1u == response[ 0 ] );
54 REQUIRE( 0x0u == response[ 1 ] );
55 }
56 }
57
58 void
write_bind_pdu(asio::ip::tcp::socket & connection,std::string_view host_name,std::uint16_t port)59 write_bind_pdu(
60 asio::ip::tcp::socket & connection,
61 std::string_view host_name,
62 std::uint16_t port )
63 {
64 {
65 arataga::acl_handler::out_buffer_fixed_t<
66 1 // VER
67 + 1 // CMD
68 + 1 // RESERVED
69 + 1 // ATYP
70 + 256 // DST.ADDR (it's the max possible length).
71 + 2 // DST.PORT
72 > data;
73
74 data.write_byte( std::byte{0x5u} );
75 data.write_byte( std::byte{0x2u} );
76 data.write_byte( std::byte{0u} );
77 data.write_byte( std::byte{0x3u} ); // ATYP
78
79 // domain name length.
80 data.write_byte( std::byte{ static_cast<std::uint8_t>(host_name.size()) } );
81 // domain name.
82 data.write_string( host_name );
83
84 // DST.PORT
85 data.write_byte(
86 std::byte{ static_cast<std::uint8_t>(port >> 8) } );
87 data.write_byte(
88 std::byte{ static_cast<std::uint8_t>(port & 0xff) } );
89
90 REQUIRE_NOTHROW( asio::write( connection, data.asio_buffer() ) );
91 }
92 }
93
94 TEST_CASE("no connection from target-end") {
95 asio::ip::tcp::endpoint proxy_endpoint{
96 asio::ip::make_address_v4( "127.0.0.1" ),
97 2444
98 };
99
100 chs::simulator_t simulator{
101 proxy_endpoint,
102 chs::handler_config_values_t{}
103 };
104
105 asio::io_context ctx;
106
107 asio::ip::tcp::socket connection{ ctx };
108 REQUIRE_NOTHROW( connection.connect( proxy_endpoint ) );
109
110 write_auth_pdu( connection, "user", "12345" );
111 write_bind_pdu( connection, "localhost", 3333 );
112
113 // A positive response is expected.
114 {
115 std::array< std::uint8_t,
116 1 // VER
117 + 1 // REP
118 + 1 // RESERVED
119 + 1 // ATYP
120 + 4 // DST.ADDR (IPv4).
121 + 2 // DST.PORT
122 > data;
123
124 std::size_t read;
125 REQUIRE_NOTHROW( read = connection.read_some( asio::buffer(data) ) );
126 REQUIRE( 10u == read );
127 REQUIRE( 0x5u == data[ 0 ] );
128 REQUIRE( 0x0u == data[ 1 ] );
129 REQUIRE( 0x0u == data[ 2 ] );
130 REQUIRE( 0x1u == data[ 3 ] );
131 REQUIRE( 0x7fu == data[ 4 ] );
132 REQUIRE( 0x0u == data[ 5 ] );
133 REQUIRE( 0x0u == data[ 6 ] );
134 REQUIRE( 0x1u == data[ 7 ] );
135 }
136
137 chs::dump_trace( (std::cout << "***\n"), simulator.get_trace() );
138
139 // A negative response is expected.
140 {
141 std::array< std::uint8_t,
142 1 // VER
143 + 1 // REP
144 + 1 // RESERVED
145 + 1 // ATYP
146 + 4 // DST.ADDR (IPv4).
147 + 2 // DST.PORT
148 > data;
149
150 std::size_t read;
151 REQUIRE_NOTHROW( read = connection.read_some( asio::buffer(data) ) );
152 REQUIRE( 4u == read );
153 REQUIRE( 0x5u == data[ 0 ] );
154 REQUIRE( 0x4u == data[ 1 ] );
155 REQUIRE( 0x0u == data[ 2 ] );
156 }
157
158 chs::dump_trace( (std::cout << "-----\n"), simulator.get_trace() );
159 }
160
161 TEST_CASE("connection from target-end") {
162 asio::ip::tcp::endpoint proxy_endpoint{
163 asio::ip::make_address_v4( "127.0.0.1" ),
164 2444
165 };
166
167 chs::simulator_t simulator{
168 proxy_endpoint,
169 chs::handler_config_values_t{}
170 };
171
172 asio::io_context ctx;
173
174 asio::ip::tcp::socket connection{ ctx };
175 REQUIRE_NOTHROW( connection.connect( proxy_endpoint ) );
176
177 write_auth_pdu( connection, "user", "12345" );
178 write_bind_pdu( connection, "localhost", 3333 );
179
180 chs::dump_trace( (std::cout << "***\n"), simulator.get_trace() );
181
182 // A positive response is expected.
183 std::uint16_t listening_port{ 0u };
184 {
185 std::array< std::uint8_t,
186 1 // VER
187 + 1 // REP
188 + 1 // RESERVED
189 + 1 // ATYP
190 + 4 // DST.ADDR (IPv4).
191 + 2 // DST.PORT
192 > data;
193
194 std::size_t read;
195 REQUIRE_NOTHROW( read = connection.read_some( asio::buffer(data) ) );
196 REQUIRE( 10u == read );
197 REQUIRE( 0x5u == data[ 0 ] );
198 REQUIRE( 0x0u == data[ 1 ] );
199 REQUIRE( 0x0u == data[ 2 ] );
200 REQUIRE( 0x1u == data[ 3 ] );
201 REQUIRE( 0x7fu == data[ 4 ] );
202 REQUIRE( 0x0u == data[ 5 ] );
203 REQUIRE( 0x0u == data[ 6 ] );
204 REQUIRE( 0x1u == data[ 7 ] );
205
206 listening_port = (static_cast<std::uint16_t>(data[8]) << 8) |
207 static_cast<std::uint16_t>(data[9]);
208
209 std::cout << "=====\n => listening port: " << listening_port << std::endl;
210 }
211
212 chs::dump_trace( (std::cout << "***\n"), simulator.get_trace() );
213
214 asio::ip::tcp::socket incoming{ ctx };
215
216 REQUIRE_NOTHROW( incoming.connect(
217 asio::ip::tcp::endpoint{
218 asio::ip::make_address( "127.0.0.1" ),
219 listening_port
220 } )
221 );
222
223 // A negative response is expected.
224 {
225 std::array< std::uint8_t,
226 1 // VER
227 + 1 // REP
228 + 1 // RESERVED
229 + 1 // ATYP
230 + 4 // DST.ADDR (IPv4).
231 + 2 // DST.PORT
232 > data;
233
234 std::size_t read;
235 REQUIRE_NOTHROW( read = connection.read_some( asio::buffer(data) ) );
236 REQUIRE( 10u == read );
237 REQUIRE( 0x5u == data[ 0 ] );
238 REQUIRE( 0x0u == data[ 1 ] );
239 REQUIRE( 0x0u == data[ 2 ] );
240 }
241
242 chs::dump_trace( (std::cout << "***\n"), simulator.get_trace() );
243
244 {
245 std::array< char, 6 > data{ 'H', 'e', 'l', 'l', 'o', '?' };
246 REQUIRE_NOTHROW( asio::write( connection, asio::buffer(data) ) );
247 }
248
249 {
250 std::array< char, 6 > data;
251 const std::array< char, 6 > expected{ 'H', 'e', 'l', 'l', 'o', '?' };
252 REQUIRE_NOTHROW( asio::read( incoming, asio::buffer(data) ) );
253 REQUIRE( data == expected );
254 }
255
256 {
257 std::array< char, 6 > data{ 'W', 'o', 'r', 'l', 'd', '!' };
258 REQUIRE_NOTHROW( asio::write( incoming, asio::buffer(data) ) );
259 }
260
261 {
262 std::array< char, 6 > data;
263 const std::array< char, 6 > expected{ 'W', 'o', 'r', 'l', 'd', '!' };
264 REQUIRE_NOTHROW( asio::read( connection, asio::buffer(data) ) );
265 REQUIRE( data == expected );
266 }
267
268 chs::dump_trace( (std::cout << "-----\n"), simulator.get_trace() );
269 }
270
271