~ubuntu-branches/ubuntu/maverick/libtorrent-rasterbar/maverick

« back to all changes in this revision

Viewing changes to src/socks5_stream.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Cristian Greco
  • Date: 2008-07-02 10:46:21 UTC
  • Revision ID: james.westby@ubuntu.com-20080702104621-jzx3pfke9lkcxfxn
Tags: upstream-0.13.1
ImportĀ upstreamĀ versionĀ 0.13.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 
 
3
Copyright (c) 2007, Arvid Norberg
 
4
All rights reserved.
 
5
 
 
6
Redistribution and use in source and binary forms, with or without
 
7
modification, are permitted provided that the following conditions
 
8
are met:
 
9
 
 
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.
 
18
 
 
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.
 
30
 
 
31
*/
 
32
 
 
33
#include "libtorrent/pch.hpp"
 
34
 
 
35
#include "libtorrent/socks5_stream.hpp"
 
36
#include "libtorrent/assert.hpp"
 
37
 
 
38
namespace libtorrent
 
39
{
 
40
 
 
41
        void socks5_stream::name_lookup(asio::error_code const& e, tcp::resolver::iterator i
 
42
                , boost::shared_ptr<handler_type> h)
 
43
        {
 
44
                if (e || i == tcp::resolver::iterator())
 
45
                {
 
46
                        (*h)(e);
 
47
                        asio::error_code ec;
 
48
                        close(ec);
 
49
                        return;
 
50
                }
 
51
 
 
52
                m_sock.async_connect(i->endpoint(), boost::bind(
 
53
                        &socks5_stream::connected, this, _1, h));
 
54
        }
 
55
 
 
56
        void socks5_stream::connected(asio::error_code const& e, boost::shared_ptr<handler_type> h)
 
57
        {
 
58
                if (e)
 
59
                {
 
60
                        (*h)(e);
 
61
                        asio::error_code ec;
 
62
                        close(ec);
 
63
                        return;
 
64
                }
 
65
 
 
66
                using namespace libtorrent::detail;
 
67
                // send SOCKS5 authentication methods
 
68
                m_buffer.resize(m_user.empty()?3:4);
 
69
                char* p = &m_buffer[0];
 
70
                write_uint8(5, p); // SOCKS VERSION 5
 
71
                if (m_user.empty())
 
72
                {
 
73
                        write_uint8(1, p); // 1 authentication method (no auth)
 
74
                        write_uint8(0, p); // no authentication
 
75
                }
 
76
                else
 
77
                {
 
78
                        write_uint8(2, p); // 2 authentication methods
 
79
                        write_uint8(0, p); // no authentication
 
80
                        write_uint8(2, p); // username/password
 
81
                }
 
82
                asio::async_write(m_sock, asio::buffer(m_buffer)
 
83
                        , boost::bind(&socks5_stream::handshake1, this, _1, h));
 
84
        }
 
85
 
 
86
        void socks5_stream::handshake1(asio::error_code const& e, boost::shared_ptr<handler_type> h)
 
87
        {
 
88
                if (e)
 
89
                {
 
90
                        (*h)(e);
 
91
                        asio::error_code ec;
 
92
                        close(ec);
 
93
                        return;
 
94
                }
 
95
 
 
96
                m_buffer.resize(2);
 
97
                asio::async_read(m_sock, asio::buffer(m_buffer)
 
98
                        , boost::bind(&socks5_stream::handshake2, this, _1, h));
 
99
        }
 
100
 
 
101
        void socks5_stream::handshake2(asio::error_code const& e, boost::shared_ptr<handler_type> h)
 
102
        {
 
103
                if (e)
 
104
                {
 
105
                        (*h)(e);
 
106
                        asio::error_code ec;
 
107
                        close(ec);
 
108
                        return;
 
109
                }
 
110
 
 
111
                using namespace libtorrent::detail;
 
112
 
 
113
                char* p = &m_buffer[0];
 
114
                int version = read_uint8(p);
 
115
                int method = read_uint8(p);
 
116
 
 
117
                if (version < 5)
 
118
                {
 
119
                        (*h)(asio::error::operation_not_supported);
 
120
                        asio::error_code ec;
 
121
                        close(ec);
 
122
                        return;
 
123
                }
 
124
 
 
125
                if (method == 0)
 
126
                {
 
127
                        socks_connect(h);
 
128
                }
 
129
                else if (method == 2)
 
130
                {
 
131
                        if (m_user.empty())
 
132
                        {
 
133
                                (*h)(asio::error::operation_not_supported);
 
134
                                asio::error_code ec;
 
135
                                close(ec);
 
136
                                return;
 
137
                        }
 
138
 
 
139
                        // start sub-negotiation
 
140
                        m_buffer.resize(m_user.size() + m_password.size() + 3);
 
141
                        char* p = &m_buffer[0];
 
142
                        write_uint8(1, p);
 
143
                        write_uint8(m_user.size(), p);
 
144
                        write_string(m_user, p);
 
145
                        write_uint8(m_password.size(), p);
 
146
                        write_string(m_password, p);
 
147
                        asio::async_write(m_sock, asio::buffer(m_buffer)
 
148
                                , boost::bind(&socks5_stream::handshake3, this, _1, h));
 
149
                }
 
150
                else
 
151
                {
 
152
                        (*h)(asio::error::operation_not_supported);
 
153
                        asio::error_code ec;
 
154
                        close(ec);
 
155
                        return;
 
156
                }
 
157
        }
 
158
 
 
159
        void socks5_stream::handshake3(asio::error_code const& e
 
160
                , boost::shared_ptr<handler_type> h)
 
161
        {
 
162
                if (e)
 
163
                {
 
164
                        (*h)(e);
 
165
                        asio::error_code ec;
 
166
                        close(ec);
 
167
                        return;
 
168
                }
 
169
 
 
170
                m_buffer.resize(2);
 
171
                asio::async_read(m_sock, asio::buffer(m_buffer)
 
172
                        , boost::bind(&socks5_stream::handshake4, this, _1, h));
 
173
        }
 
174
 
 
175
        void socks5_stream::handshake4(asio::error_code const& e
 
176
                , boost::shared_ptr<handler_type> h)
 
177
        {
 
178
                if (e)
 
179
                {
 
180
                        (*h)(e);
 
181
                        asio::error_code ec;
 
182
                        close(ec);
 
183
                        return;
 
184
                }
 
185
 
 
186
                using namespace libtorrent::detail;
 
187
 
 
188
                char* p = &m_buffer[0];
 
189
                int version = read_uint8(p);
 
190
                int status = read_uint8(p);
 
191
 
 
192
                if (version != 1)
 
193
                {
 
194
                        (*h)(asio::error::operation_not_supported);
 
195
                        asio::error_code ec;
 
196
                        close(ec);
 
197
                        return;
 
198
                }
 
199
 
 
200
                if (status != 0)
 
201
                {
 
202
                        (*h)(asio::error::operation_not_supported);
 
203
                        asio::error_code ec;
 
204
                        close(ec);
 
205
                        return;
 
206
                }
 
207
 
 
208
                std::vector<char>().swap(m_buffer);
 
209
                socks_connect(h);
 
210
        }
 
211
 
 
212
        void socks5_stream::socks_connect(boost::shared_ptr<handler_type> h)
 
213
        {
 
214
                using namespace libtorrent::detail;
 
215
 
 
216
                // send SOCKS5 connect command
 
217
                m_buffer.resize(6 + (m_remote_endpoint.address().is_v4()?4:16));
 
218
                char* p = &m_buffer[0];
 
219
                write_uint8(5, p); // SOCKS VERSION 5
 
220
                write_uint8(1, p); // CONNECT command
 
221
                write_uint8(0, p); // reserved
 
222
                write_uint8(m_remote_endpoint.address().is_v4()?1:4, p); // address type
 
223
                write_address(m_remote_endpoint.address(), p);
 
224
                write_uint16(m_remote_endpoint.port(), p);
 
225
                TORRENT_ASSERT(p - &m_buffer[0] == int(m_buffer.size()));
 
226
 
 
227
                asio::async_write(m_sock, asio::buffer(m_buffer)
 
228
                        , boost::bind(&socks5_stream::connect1, this, _1, h));
 
229
        }
 
230
 
 
231
        void socks5_stream::connect1(asio::error_code const& e, boost::shared_ptr<handler_type> h)
 
232
        {
 
233
                if (e)
 
234
                {
 
235
                        (*h)(e);
 
236
                        asio::error_code ec;
 
237
                        close(ec);
 
238
                        return;
 
239
                }
 
240
 
 
241
                m_buffer.resize(6 + 4); // assume an IPv4 address
 
242
                asio::async_read(m_sock, asio::buffer(m_buffer)
 
243
                        , boost::bind(&socks5_stream::connect2, this, _1, h));
 
244
        }
 
245
 
 
246
        void socks5_stream::connect2(asio::error_code const& e, boost::shared_ptr<handler_type> h)
 
247
        {
 
248
                if (e)
 
249
                {
 
250
                        (*h)(e);
 
251
                        asio::error_code ec;
 
252
                        close(ec);
 
253
                        return;
 
254
                }
 
255
 
 
256
                using namespace libtorrent::detail;
 
257
 
 
258
                // send SOCKS5 connect command
 
259
                char* p = &m_buffer[0];
 
260
                int version = read_uint8(p);
 
261
                if (version < 5)
 
262
                {
 
263
                        (*h)(asio::error::operation_not_supported);
 
264
                        asio::error_code ec;
 
265
                        close(ec);
 
266
                        return;
 
267
                }
 
268
                int response = read_uint8(p);
 
269
                if (response != 0)
 
270
                {
 
271
                        asio::error_code e = asio::error::fault;
 
272
                        switch (response)
 
273
                        {
 
274
                                case 1: e = asio::error::fault; break;
 
275
                                case 2: e = asio::error::no_permission; break;
 
276
                                case 3: e = asio::error::network_unreachable; break;
 
277
                                case 4: e = asio::error::host_unreachable; break;
 
278
                                case 5: e = asio::error::connection_refused; break;
 
279
                                case 6: e = asio::error::timed_out; break;
 
280
                                case 7: e = asio::error::operation_not_supported; break;
 
281
                                case 8: e = asio::error::address_family_not_supported; break;
 
282
                        }
 
283
                        (*h)(e);
 
284
                        asio::error_code ec;
 
285
                        close(ec);
 
286
                        return;
 
287
                }
 
288
                p += 1; // reserved
 
289
                int atyp = read_uint8(p);
 
290
                // we ignore the proxy IP it was bound to
 
291
                if (atyp == 1)
 
292
                {
 
293
                        std::vector<char>().swap(m_buffer);
 
294
                        (*h)(e);
 
295
                        return;
 
296
                }
 
297
                int skip_bytes = 0;
 
298
                if (atyp == 4)
 
299
                {
 
300
                        skip_bytes = 12;
 
301
                }
 
302
                else if (atyp == 3)
 
303
                {
 
304
                        skip_bytes = read_uint8(p) - 3;
 
305
                }
 
306
                else
 
307
                {
 
308
                        (*h)(asio::error::operation_not_supported);
 
309
                        asio::error_code ec;
 
310
                        close(ec);
 
311
                        return;
 
312
                }
 
313
                m_buffer.resize(skip_bytes);
 
314
 
 
315
                asio::async_read(m_sock, asio::buffer(m_buffer)
 
316
                        , boost::bind(&socks5_stream::connect3, this, _1, h));
 
317
        }
 
318
 
 
319
        void socks5_stream::connect3(asio::error_code const& e, boost::shared_ptr<handler_type> h)
 
320
        {
 
321
                if (e)
 
322
                {
 
323
                        (*h)(e);
 
324
                        asio::error_code ec;
 
325
                        close(ec);
 
326
                        return;
 
327
                }
 
328
 
 
329
                std::vector<char>().swap(m_buffer);
 
330
                (*h)(e);
 
331
        }
 
332
}
 
333