* Fixed g++ warnings
[libnetpp.git] / net / client / proxy / socks5.hpp
blobab1b649673d5c7fccabb5e31a72fbbc1936a0411
1 /*
2 * Copyright (c) 2008,2009 by Vinzenz Feenstra
3 * All rights reserved.
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>
32 namespace net
34 template<typename Tag>
35 struct socks5_proxy
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;
44 struct session
46 session(proxy_socket<Tag> & socket,
47 endpoint_type const & ep,
48 connected_handler const & connected = connected_handler())
49 : socket_ref(boost::ref(socket))
50 , endpoint(ep)
51 , handler(connected)
52 , auth_buffer()
53 , connection_buffer()
54 , response_buffer()
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());
61 build_requests();
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;
74 void build_requests()
76 util::adapt_unchecked(auth_buffer)
77 .writeu8(0x05)
78 .writeu8(0x01)
79 .writeu8(0x00);
80 auth = boost::asio::buffer(auth_buffer);
82 util::adapt_unchecked(connection_buffer)
83 .writeu8(0x05)
84 .writeu8(0x01)
85 .writeu8(0x00)
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)
96 : base_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),
110 boost::bind
112 &socks5_proxy::on_async_auth_request_sent,
113 this,
114 boost::asio::placeholders::error,
115 sess
120 void on_async_auth_request_sent(
121 error_code const & ec,
122 session_ptr sess
125 if(!ec)
127 boost::asio::async_read(
128 sess->socket_ref.get(),
129 boost::asio::buffer(sess->auth_buffer.data(), 2),
130 boost::bind
132 &socks5_proxy<Tag>::on_async_auth_response_received,
133 this,
134 boost::asio::placeholders::error,
135 boost::asio::placeholders::bytes_transferred,
136 sess
140 else
142 sess->handler(ec);
146 void on_async_auth_response_received(
147 error_code const & ec,
148 size_t,
149 session_ptr sess
152 if(!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),
160 boost::bind
162 &socks5_proxy::on_async_connection_request_sent,
163 this,
164 boost::asio::placeholders::error,
165 sess
169 else
171 sess->handler(error_code(boost::asio::error::access_denied));
174 else
176 sess->handler(ec);
180 void on_async_connection_request_sent(
181 error_code const & ec,
182 session_ptr sess
185 if(!ec)
187 boost::asio::async_read
189 sess->socket_ref.get(),
190 boost::asio::buffer(sess->connection),
191 boost::asio::transfer_at_least(10),
192 boost::bind
194 &socks5_proxy::on_async_response,
195 this,
196 boost::asio::placeholders::error,
197 boost::asio::placeholders::bytes_transferred,
198 sess
202 else
204 sess->handler(ec);
208 error_code translate_socks5_reply(boost::uint8_t reply)
210 switch(reply)
212 case 0:
213 std::cout << "Connection via proxy established\n\n";
214 return error_code(); // Success
215 case 1:
216 // SOCKS failure
217 return error_code(boost::asio::error::fault);
218 case 2:
219 // connection not allowed by rule set
220 return error_code(boost::asio::error::access_denied);
221 case 3:
222 // Network unreachable
223 return error_code(boost::asio::error::network_unreachable);
224 case 4:
225 // Host unreachable
226 return error_code(boost::asio::error::host_unreachable);
227 case 5:
228 // Connection refused
229 return error_code(boost::asio::error::connection_refused);
230 case 6:
231 // TTL expired
232 return error_code(boost::asio::error::timed_out);
233 case 7:
234 // Command not supported
235 return error_code(boost::asio::error::operation_not_supported);
236 case 8:
237 // Address type not supported
238 return error_code(boost::asio::error::address_family_not_supported);
239 default:
240 break;
242 return error_code(boost::asio::error::service_not_found);
245 void on_async_response(
246 error_code const & ec,
247 size_t bytes_read,
248 session_ptr sess
251 error_code res = ec;
252 if(!res)
254 res = check_response(*sess, bytes_read);
257 if(res)
259 sess->socket_ref.get().close();
261 sess->handler(res);
264 error_code check_response(session & sess, size_t bytes_read)
266 error_code ec;
267 if(bytes_read > 1)
269 return translate_socks5_reply(sess.response_buffer[3]);
271 else
273 return error_code(boost::asio::error::connection_reset);
275 return ec;
278 virtual error_code on_connected(
279 proxy_socket<Tag> & socket,
280 endpoint_type const & endpoint,
281 error_code & ec
284 if(!ec)
286 session sess(socket, endpoint);
288 boost::asio::write
290 socket,
291 boost::asio::buffer(sess.auth),
292 boost::asio::transfer_all(),
296 size_t read = boost::asio::read
298 socket,
299 boost::asio::buffer
301 sess.auth_buffer.data(),
304 boost::asio::transfer_all(),
308 if(read == 2)
310 boost::uint8_t version = 0;
311 boost::uint8_t method = 0;
313 util::adapt_unchecked(sess.auth_buffer)
314 .readu8(version)
315 .readu8(method);
317 if(version == 5 && method == 0)
320 boost::asio::write
322 socket,
323 boost::asio::buffer(sess.connection),
324 boost::asio::transfer_all(),
328 size_t cnt = boost::asio::read
330 socket,
331 boost::asio::buffer(sess.response_buffer),
332 boost::asio::transfer_at_least(1),
336 // Check:
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);
355 if(!ec)
357 socket.close();
359 return ec;
364 #endif //GUARD_NET_CLIENT_PROXY_SOCKS5_HPP_INCLUDED