3 Copyright (c) 2007, Arvid Norberg
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions
10 * Redistributions of source code must retain the above copyright
11 notice, this list of conditions and the following disclaimer.
12 * Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions and the following disclaimer in
14 the documentation and/or other materials provided with the distribution.
15 * Neither the name of the author nor the names of its
16 contributors may be used to endorse or promote products derived
17 from this software without specific prior written permission.
19 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
23 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 POSSIBILITY OF SUCH DAMAGE.
33 #include "libtorrent/pch.hpp"
35 #include "libtorrent/socks5_stream.hpp"
40 void socks5_stream::name_lookup(asio::error_code
const& e
, tcp::resolver::iterator i
41 , boost::shared_ptr
<handler_type
> h
)
43 if (e
|| i
== tcp::resolver::iterator())
50 m_sock
.async_connect(i
->endpoint(), boost::bind(
51 &socks5_stream::connected
, this, _1
, h
));
54 void socks5_stream::connected(asio::error_code
const& e
, boost::shared_ptr
<handler_type
> h
)
63 using namespace libtorrent::detail
;
64 // send SOCKS5 authentication methods
65 m_buffer
.resize(m_user
.empty()?3:4);
66 char* p
= &m_buffer
[0];
67 write_uint8(5, p
); // SOCKS VERSION 5
70 write_uint8(1, p
); // 1 authentication method (no auth)
71 write_uint8(0, p
); // no authentication
75 write_uint8(2, p
); // 2 authentication methods
76 write_uint8(0, p
); // no authentication
77 write_uint8(2, p
); // username/password
79 asio::async_write(m_sock
, asio::buffer(m_buffer
)
80 , boost::bind(&socks5_stream::handshake1
, this, _1
, h
));
83 void socks5_stream::handshake1(asio::error_code
const& e
, boost::shared_ptr
<handler_type
> h
)
93 asio::async_read(m_sock
, asio::buffer(m_buffer
)
94 , boost::bind(&socks5_stream::handshake2
, this, _1
, h
));
97 void socks5_stream::handshake2(asio::error_code
const& e
, boost::shared_ptr
<handler_type
> h
)
106 using namespace libtorrent::detail
;
108 char* p
= &m_buffer
[0];
109 int version
= read_uint8(p
);
110 int method
= read_uint8(p
);
114 (*h
)(asio::error::operation_not_supported
);
123 else if (method
== 2)
127 (*h
)(asio::error::operation_not_supported
);
132 // start sub-negotiation
133 m_buffer
.resize(m_user
.size() + m_password
.size() + 3);
134 char* p
= &m_buffer
[0];
136 write_uint8(m_user
.size(), p
);
137 write_string(m_user
, p
);
138 write_uint8(m_password
.size(), p
);
139 write_string(m_password
, p
);
140 asio::async_write(m_sock
, asio::buffer(m_buffer
)
141 , boost::bind(&socks5_stream::handshake3
, this, _1
, h
));
145 (*h
)(asio::error::operation_not_supported
);
151 void socks5_stream::handshake3(asio::error_code
const& e
152 , boost::shared_ptr
<handler_type
> h
)
162 asio::async_read(m_sock
, asio::buffer(m_buffer
)
163 , boost::bind(&socks5_stream::handshake4
, this, _1
, h
));
166 void socks5_stream::handshake4(asio::error_code
const& e
167 , boost::shared_ptr
<handler_type
> h
)
176 using namespace libtorrent::detail
;
178 char* p
= &m_buffer
[0];
179 int version
= read_uint8(p
);
180 int status
= read_uint8(p
);
184 (*h
)(asio::error::operation_not_supported
);
191 (*h
)(asio::error::operation_not_supported
);
196 std::vector
<char>().swap(m_buffer
);
200 void socks5_stream::socks_connect(boost::shared_ptr
<handler_type
> h
)
202 using namespace libtorrent::detail
;
204 // send SOCKS5 connect command
205 m_buffer
.resize(6 + (m_remote_endpoint
.address().is_v4()?4:16));
206 char* p
= &m_buffer
[0];
207 write_uint8(5, p
); // SOCKS VERSION 5
208 write_uint8(1, p
); // CONNECT command
209 write_uint8(0, p
); // reserved
210 write_uint8(m_remote_endpoint
.address().is_v4()?1:4, p
); // address type
211 write_address(m_remote_endpoint
.address(), p
);
212 write_uint16(m_remote_endpoint
.port(), p
);
213 assert(p
- &m_buffer
[0] == int(m_buffer
.size()));
215 asio::async_write(m_sock
, asio::buffer(m_buffer
)
216 , boost::bind(&socks5_stream::connect1
, this, _1
, h
));
219 void socks5_stream::connect1(asio::error_code
const& e
, boost::shared_ptr
<handler_type
> h
)
228 m_buffer
.resize(6 + 4); // assume an IPv4 address
229 asio::async_read(m_sock
, asio::buffer(m_buffer
)
230 , boost::bind(&socks5_stream::connect2
, this, _1
, h
));
233 void socks5_stream::connect2(asio::error_code
const& e
, boost::shared_ptr
<handler_type
> h
)
242 using namespace libtorrent::detail
;
244 // send SOCKS5 connect command
245 char* p
= &m_buffer
[0];
246 int version
= read_uint8(p
);
249 (*h
)(asio::error::operation_not_supported
);
253 int response
= read_uint8(p
);
256 asio::error_code e
= asio::error::fault
;
259 case 1: e
= asio::error::fault
; break;
260 case 2: e
= asio::error::no_permission
; break;
261 case 3: e
= asio::error::network_unreachable
; break;
262 case 4: e
= asio::error::host_unreachable
; break;
263 case 5: e
= asio::error::connection_refused
; break;
264 case 6: e
= asio::error::timed_out
; break;
265 case 7: e
= asio::error::operation_not_supported
; break;
266 case 8: e
= asio::error::address_family_not_supported
; break;
273 int atyp
= read_uint8(p
);
274 // we ignore the proxy IP it was bound to
277 std::vector
<char>().swap(m_buffer
);
288 skip_bytes
= read_uint8(p
) - 3;
292 (*h
)(asio::error::operation_not_supported
);
296 m_buffer
.resize(skip_bytes
);
298 asio::async_read(m_sock
, asio::buffer(m_buffer
)
299 , boost::bind(&socks5_stream::connect3
, this, _1
, h
));
302 void socks5_stream::connect3(asio::error_code
const& e
, boost::shared_ptr
<handler_type
> h
)
311 std::vector
<char>().swap(m_buffer
);