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_SOCKS4_HPP_INCLUDED
27 #define GUARD_NET_CLIENT_PROXY_SOCKS4_HPP_INCLUDED
29 #if defined(WIN32) || defined(WIN64)
35 #include <net/client/proxy_socket.hpp>
40 template<typename Tag
>
42 : implements_proxy
<Tag
>
44 typedef implements_proxy
<Tag
> base_type
;
45 typedef typename
base_type::service_type service_type
;
46 typedef typename
base_type::endpoint_type endpoint_type
;
47 typedef typename
base_type::connected_handler connected_handler
;
48 typedef typename
base_type::error_code error_code
;
54 boost::uint8_t version
;
55 boost::uint8_t command
;
56 boost::uint16_t destination_port
;
57 boost::array
<boost::uint8_t, 4> destination_address
;
58 boost::uint8_t end_marker
;
61 boost::array
<boost::uint8_t, 9> bytes
;
66 session(proxy_socket
<Tag
> & socket
)
68 , request(reinterpret_cast<request_t
*>(&data_buffer
[0]))
71 , socket(boost::ref(socket
))
75 boost::array
<boost::uint8_t, 0x1000> data_buffer
;
77 connected_handler handler
;
78 endpoint_type endpoint
;
79 boost::reference_wrapper
<proxy_socket
<Tag
> > socket
;
81 void dump_buffer(size_t size
)
83 static char const hex_chars
[17] = "0123456789ABCDEF";
84 for(size_t i
= 0; i
< std::min(size
, data_buffer
.size()); ++i
)
86 boost::uint8_t b
= data_buffer
[i
];
87 std::cout
<< " " << hex_chars
[(b
&0xF0)>>4] << hex_chars
[b
&0x0F];
92 typedef boost::shared_ptr
<session
> session_ptr
;
95 socks4_proxy(service_type
& service
)
101 virtual void on_async_connected(
102 proxy_socket
<Tag
> & socket
,
103 endpoint_type
const & endpoint
,
104 connected_handler connected
107 std::cout
<< "Connected to proxy..." << std::endl
;
108 boost::system::error_code ec
;
109 session_ptr
sess(new session(socket
));
111 *(sess
->request
) = build_request(endpoint
, ec
);
112 if(ec
) // Something went wrong with build_request
114 std::cout
<< "Something went wrong with build_request: " << ec
<< " Message: " << ec
.message() << std::endl
;
118 sess
->handler
= connected
;
119 sess
->endpoint
= endpoint
;
121 std::cout
<< "Attempt to write: " << sess
->request
->bytes
.size() << " bytes: ";
122 sess
->dump_buffer(sess
->request
->bytes
.size());
123 std::cout
<< std::endl
;
125 boost::asio::async_write(
127 boost::asio::buffer(sess
->request
->bytes
),
129 &socks4_proxy::on_async_request_sent
,
131 boost::asio::placeholders::error
,
137 virtual void on_async_request_sent(
138 error_code
const & ec
,
144 boost::asio::async_read(
146 boost::asio::buffer(sess
->data_buffer
),
147 boost::asio::transfer_at_least(8),
149 &socks4_proxy::on_async_response_received
,
151 boost::asio::placeholders::error
,
152 boost::asio::placeholders::bytes_transferred
,
164 virtual void on_async_response_received(
165 error_code
const & ec
,
166 size_t bytes_transferred
,
170 static char const hex_chars
[17] = "0123456789ABCDEF";
171 std::cout
<< ec
<< " Response received: (" << bytes_transferred
<< ") ";
172 sess
->dump_buffer(bytes_transferred
);
173 std::cout
<< std::endl
;
177 if(sess
->data_buffer
[1] == 0x5a)
179 sess
->handler(error_code());
183 sess
->handler(error_code(boost::asio::error::connection_refused
));
192 virtual error_code
on_connected(
193 proxy_socket
<Tag
> & socket
,
194 endpoint_type
const & endpoint
,
198 std::cout
<< "Connected to proxy..." << std::endl
;
200 request_t request
= build_request(endpoint
, ec
);
203 std::cout
<< "Sending connection request to proxy..." << std::endl
;
204 size_t bytes_sent
= socket
.send( boost::asio::buffer(request
.bytes
), 0, ec
);
207 std::cout
<< "Reading response from proxy..." << std::endl
;
208 boost::array
<boost::uint8_t, 8> buffer
;
209 size_t bytes_read
= socket
.read_some(boost::asio::buffer(buffer
), ec
);
214 if(buffer
[1] == 0x5a)
216 std::cout
<< "Connection to remote endpoint granted and established" << std::endl
;
217 return (ec
= error_code());
220 std::cout
<< "Connection to remote endpoint denied or invalid response" << std::endl
;
221 return (ec
= error_code(boost::asio::error::connection_refused
));
228 virtual request_t
build_request(endpoint_type ep
, error_code
& ec
)
230 request_t rc
= request_t();
231 if(!ep
.address().is_v4())
233 ec
= error_code(boost::asio::error::address_family_not_supported
);
236 rc
.detail
.version
= 4;
237 rc
.detail
.command
= 1;
238 rc
.detail
.destination_port
= ::htons(ep
.port());
239 rc
.detail
.destination_address
= ep
.address().to_v4().to_bytes();
240 rc
.detail
.end_marker
= 0;
247 #endif //GUARD_NET_CLIENT_PROXY_SOCKS4_HPP_INCLUDED