2 * Copyright (c) 2008,2009 by Vinzenz Feenstra
5 * - Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
8 * - Redistributions of source code must retain the above copyright notice, this
9 * list of conditions and the following disclaimer.
10 * - Neither the name of the Vinzenz Feenstra nor the names
11 * of its contributors may be used to endorse or promote products derived from
12 * this software without specific prior written permission.
14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
18 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24 * POSSIBILITY OF SUCH DAMAGE.
26 #ifndef GUARD_NET_CLIENT_PROXY_SOCKS5_HPP_INCLUDED
27 #define GUARD_NET_CLIENT_PROXY_SOCKS5_HPP_INCLUDED
29 #include <net/client/proxy_socket.hpp>
30 #include <net/client/utils/buffer.hpp>
34 template<typename Tag
>
36 : implements_proxy
<Tag
>
38 typedef implements_proxy
<Tag
> base_type
;
39 typedef typename
base_type::error_code error_code
;
40 typedef typename
base_type::service_type service_type
;
41 typedef typename
base_type::endpoint_type endpoint_type
;
42 typedef typename
base_type::connected_handler connected_handler
;
46 session(proxy_socket
<Tag
> & socket
,
47 endpoint_type
const & ep
,
48 connected_handler
const & connected
= connected_handler())
49 : socket_ref(boost::ref(socket
))
55 , auth(boost::asio::buffer(auth_buffer
))
56 , connection(boost::asio::buffer(connection_buffer
))
58 memset(auth_buffer
.data(),0, auth_buffer
.size());
59 memset(connection_buffer
.data(), 0, connection_buffer
.size());
60 memset(response_buffer
.data(), 0, response_buffer
.size());
64 boost::reference_wrapper
< proxy_socket
<Tag
> > socket_ref
;
65 endpoint_type endpoint
;
66 connected_handler handler
;
68 boost::array
<boost::uint8_t, 3> auth_buffer
;
69 boost::array
<boost::uint8_t, 22> connection_buffer
;
70 boost::array
< boost::uint8_t, 22> response_buffer
;
71 boost::asio::mutable_buffer auth
;
72 boost::asio::mutable_buffer connection
;
76 util::adapt_unchecked(auth_buffer
)
80 auth
= boost::asio::buffer(auth_buffer
);
82 util::adapt_unchecked(connection_buffer
)
86 .writeu8(endpoint
.address().is_v4() ? 0x01 : 0x04 )
87 .write(endpoint
.address())
88 .writeu16(endpoint
.port());
89 connection
= boost::asio::buffer(connection_buffer
.data(), endpoint
.address().is_v4() ? 10 : 22);
93 typedef boost::shared_ptr
<session
> session_ptr
;
95 socks5_proxy(service_type
& service
)
99 virtual void on_async_connected(
100 proxy_socket
<Tag
> & socket
,
101 endpoint_type
const & endpoint
,
102 connected_handler connected
105 session_ptr
sess(new session(socket
, endpoint
, connected
));
106 boost::asio::async_write
108 sess
->socket_ref
.get(),
109 boost::asio::buffer(sess
->auth
),
112 &socks5_proxy::on_async_auth_request_sent
,
114 boost::asio::placeholders::error
,
120 void on_async_auth_request_sent(
121 error_code
const & ec
,
127 boost::asio::async_read(
128 sess
->socket_ref
.get(),
129 boost::asio::buffer(sess
->auth_buffer
.data(), 2),
132 &socks5_proxy
<Tag
>::on_async_auth_response_received
,
134 boost::asio::placeholders::error
,
135 boost::asio::placeholders::bytes_transferred
,
146 void on_async_auth_response_received(
147 error_code
const & ec
,
154 if(sess
->auth_buffer
[0] == 0x05 && sess
->auth_buffer
[1] == 0x00)
156 boost::asio::async_write
158 sess
->socket_ref
.get(),
159 boost::asio::buffer(sess
->connection
),
162 &socks5_proxy::on_async_connection_request_sent
,
164 boost::asio::placeholders::error
,
171 sess
->handler(error_code(boost::asio::error::access_denied
));
180 void on_async_connection_request_sent(
181 error_code
const & ec
,
187 boost::asio::async_read
189 sess
->socket_ref
.get(),
190 boost::asio::buffer(sess
->connection
),
191 boost::asio::transfer_at_least(10),
194 &socks5_proxy::on_async_response
,
196 boost::asio::placeholders::error
,
197 boost::asio::placeholders::bytes_transferred
,
208 error_code
translate_socks5_reply(boost::uint8_t reply
)
213 std::cout
<< "Connection via proxy established\n\n";
214 return error_code(); // Success
217 return error_code(boost::asio::error::fault
);
219 // connection not allowed by rule set
220 return error_code(boost::asio::error::access_denied
);
222 // Network unreachable
223 return error_code(boost::asio::error::network_unreachable
);
226 return error_code(boost::asio::error::host_unreachable
);
228 // Connection refused
229 return error_code(boost::asio::error::connection_refused
);
232 return error_code(boost::asio::error::timed_out
);
234 // Command not supported
235 return error_code(boost::asio::error::operation_not_supported
);
237 // Address type not supported
238 return error_code(boost::asio::error::address_family_not_supported
);
242 return error_code(boost::asio::error::service_not_found
);
245 void on_async_response(
246 error_code
const & ec
,
254 res
= check_response(*sess
, bytes_read
);
259 sess
->socket_ref
.get().close();
264 error_code
check_response(session
& sess
, size_t bytes_read
)
269 return translate_socks5_reply(sess
.response_buffer
[3]);
273 return error_code(boost::asio::error::connection_reset
);
278 virtual error_code
on_connected(
279 proxy_socket
<Tag
> & socket
,
280 endpoint_type
const & endpoint
,
286 session
sess(socket
, endpoint
);
291 boost::asio::buffer(sess
.auth
),
292 boost::asio::transfer_all(),
296 size_t read
= boost::asio::read
301 sess
.auth_buffer
.data(),
304 boost::asio::transfer_all(),
310 boost::uint8_t version
= 0;
311 boost::uint8_t method
= 0;
313 util::adapt_unchecked(sess
.auth_buffer
)
317 if(version
== 5 && method
== 0)
323 boost::asio::buffer(sess
.connection
),
324 boost::asio::transfer_all(),
328 size_t cnt
= boost::asio::read
331 boost::asio::buffer(sess
.response_buffer
),
332 boost::asio::transfer_at_least(1),
337 // - We have version 5
338 // - the read size = 10 if addr type = 0x01 (ipv4)
339 // - the read size = 22 if addr type = 0x04 (ipv6)
340 if( sess
.response_buffer
[0] == 5
341 && ( (cnt
== 10 && sess
.response_buffer
[3] == 0x01)
342 ||(cnt
== 22 && sess
.response_buffer
[3] == 0x04)
345 // Translate the repsonse
346 return translate_socks5_reply(sess
.response_buffer
[1]);
349 // Most likely because of invalid protocol
350 ec
= error_code(boost::asio::error::connection_aborted
);
364 #endif //GUARD_NET_CLIENT_PROXY_SOCKS5_HPP_INCLUDED