formatting fixes in client test, and made the test build when resolve countries is...
[libtorrent-kjk.git] / src / socks5_stream.cpp
blobb1679c4ac37a65e581e0360e6a0e45abb92f98cc
1 /*
3 Copyright (c) 2007, Arvid Norberg
4 All rights reserved.
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions
8 are met:
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"
37 namespace libtorrent
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())
45 (*h)(e);
46 close();
47 return;
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)
56 if (e)
58 (*h)(e);
59 close();
60 return;
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
68 if (m_user.empty())
70 write_uint8(1, p); // 1 authentication method (no auth)
71 write_uint8(0, p); // no authentication
73 else
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)
85 if (e)
87 (*h)(e);
88 close();
89 return;
92 m_buffer.resize(2);
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)
99 if (e)
101 (*h)(e);
102 close();
103 return;
106 using namespace libtorrent::detail;
108 char* p = &m_buffer[0];
109 int version = read_uint8(p);
110 int method = read_uint8(p);
112 if (version < 5)
114 (*h)(asio::error::operation_not_supported);
115 close();
116 return;
119 if (method == 0)
121 socks_connect(h);
123 else if (method == 2)
125 if (m_user.empty())
127 (*h)(asio::error::operation_not_supported);
128 close();
129 return;
132 // start sub-negotiation
133 m_buffer.resize(m_user.size() + m_password.size() + 3);
134 char* p = &m_buffer[0];
135 write_uint8(1, p);
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));
143 else
145 (*h)(asio::error::operation_not_supported);
146 close();
147 return;
151 void socks5_stream::handshake3(asio::error_code const& e
152 , boost::shared_ptr<handler_type> h)
154 if (e)
156 (*h)(e);
157 close();
158 return;
161 m_buffer.resize(2);
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)
169 if (e)
171 (*h)(e);
172 close();
173 return;
176 using namespace libtorrent::detail;
178 char* p = &m_buffer[0];
179 int version = read_uint8(p);
180 int status = read_uint8(p);
182 if (version != 1)
184 (*h)(asio::error::operation_not_supported);
185 close();
186 return;
189 if (status != 0)
191 (*h)(asio::error::operation_not_supported);
192 close();
193 return;
196 std::vector<char>().swap(m_buffer);
197 (*h)(e);
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)
221 if (e)
223 (*h)(e);
224 close();
225 return;
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)
235 if (e)
237 (*h)(e);
238 close();
239 return;
242 using namespace libtorrent::detail;
244 // send SOCKS5 connect command
245 char* p = &m_buffer[0];
246 int version = read_uint8(p);
247 if (version < 5)
249 (*h)(asio::error::operation_not_supported);
250 close();
251 return;
253 int response = read_uint8(p);
254 if (response != 0)
256 asio::error_code e = asio::error::fault;
257 switch (response)
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;
268 (*h)(e);
269 close();
270 return;
272 p += 1; // reserved
273 int atyp = read_uint8(p);
274 // we ignore the proxy IP it was bound to
275 if (atyp == 1)
277 std::vector<char>().swap(m_buffer);
278 (*h)(e);
279 return;
281 int skip_bytes = 0;
282 if (atyp == 4)
284 skip_bytes = 12;
286 else if (atyp == 3)
288 skip_bytes = read_uint8(p) - 3;
290 else
292 (*h)(asio::error::operation_not_supported);
293 close();
294 return;
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)
304 if (e)
306 (*h)(e);
307 close();
308 return;
311 std::vector<char>().swap(m_buffer);
312 (*h)(e);