socks 2.3.1 → 2.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.prettierrc.yaml +3 -1
- package/.travis.yml +3 -2
- package/README.md +1 -1
- package/build/client/socksclient.js +163 -161
- package/build/client/socksclient.js.map +1 -1
- package/build/common/constants.js +2 -1
- package/build/common/constants.js.map +1 -1
- package/build/common/helpers.js +1 -0
- package/build/common/helpers.js.map +1 -1
- package/build/common/receivebuffer.js +17 -16
- package/build/common/receivebuffer.js.map +1 -1
- package/build/common/util.js +3 -1
- package/build/common/util.js.map +1 -1
- package/build/index.js +11 -4
- package/build/index.js.map +1 -1
- package/package.json +18 -16
- package/typings/client/socksclient.d.ts +34 -36
- package/typings/common/constants.d.ts +9 -8
- package/typings/common/receiveBuffer.d.ts +4 -4
- package/yarn-error.log +0 -2416
- package/yarn.lock +0 -2300
@@ -1,13 +1,15 @@
|
|
1
1
|
"use strict";
|
2
2
|
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
3
4
|
return new (P || (P = Promise))(function (resolve, reject) {
|
4
5
|
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
5
6
|
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
6
|
-
function step(result) { result.done ? resolve(result.value) :
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
7
8
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
8
9
|
});
|
9
10
|
};
|
10
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
12
|
+
exports.SocksClientError = exports.SocksClient = void 0;
|
11
13
|
const events_1 = require("events");
|
12
14
|
const net = require("net");
|
13
15
|
const ip = require("ip");
|
@@ -16,14 +18,15 @@ const constants_1 = require("../common/constants");
|
|
16
18
|
const helpers_1 = require("../common/helpers");
|
17
19
|
const receivebuffer_1 = require("../common/receivebuffer");
|
18
20
|
const util_1 = require("../common/util");
|
21
|
+
Object.defineProperty(exports, "SocksClientError", { enumerable: true, get: function () { return util_1.SocksClientError; } });
|
19
22
|
class SocksClient extends events_1.EventEmitter {
|
20
23
|
constructor(options) {
|
21
24
|
super();
|
22
|
-
this.
|
25
|
+
this.options = Object.assign({}, options);
|
23
26
|
// Validate SocksClientOptions
|
24
27
|
helpers_1.validateSocksClientOptions(options);
|
25
28
|
// Default state
|
26
|
-
this.
|
29
|
+
this.setState(constants_1.SocksClientState.Created);
|
27
30
|
}
|
28
31
|
/**
|
29
32
|
* Creates a new SOCKS connection.
|
@@ -81,6 +84,7 @@ class SocksClient extends events_1.EventEmitter {
|
|
81
84
|
return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
|
82
85
|
let sock;
|
83
86
|
try {
|
87
|
+
// tslint:disable-next-line:no-increment-decrement
|
84
88
|
for (let i = 0; i < options.proxies.length; i++) {
|
85
89
|
const nextProxy = options.proxies[i];
|
86
90
|
// If we've reached the last proxy in the chain, the destination is the actual destination, otherwise it's the next proxy.
|
@@ -88,14 +92,13 @@ class SocksClient extends events_1.EventEmitter {
|
|
88
92
|
? options.destination
|
89
93
|
: {
|
90
94
|
host: options.proxies[i + 1].ipaddress,
|
91
|
-
port: options.proxies[i + 1].port
|
95
|
+
port: options.proxies[i + 1].port,
|
92
96
|
};
|
93
97
|
// Creates the next connection in the chain.
|
94
98
|
const result = yield SocksClient.createConnection({
|
95
99
|
command: 'connect',
|
96
100
|
proxy: nextProxy,
|
97
|
-
destination: nextDestination
|
98
|
-
// Initial connection ignores this as sock is undefined. Subsequent connections re-use the first proxy socket to form a chain.
|
101
|
+
destination: nextDestination,
|
99
102
|
});
|
100
103
|
// If sock is undefined, assign it here.
|
101
104
|
if (!sock) {
|
@@ -173,75 +176,73 @@ class SocksClient extends events_1.EventEmitter {
|
|
173
176
|
frameNumber,
|
174
177
|
remoteHost: {
|
175
178
|
host: remoteHost,
|
176
|
-
port: remotePort
|
179
|
+
port: remotePort,
|
177
180
|
},
|
178
|
-
data: buff.readBuffer()
|
181
|
+
data: buff.readBuffer(),
|
179
182
|
};
|
180
183
|
}
|
181
|
-
/**
|
182
|
-
* Gets the SocksClient internal state.
|
183
|
-
*/
|
184
|
-
get state() {
|
185
|
-
return this._state;
|
186
|
-
}
|
187
184
|
/**
|
188
185
|
* Internal state setter. If the SocksClient is in an error state, it cannot be changed to a non error state.
|
189
186
|
*/
|
190
|
-
|
191
|
-
if (this.
|
192
|
-
this.
|
187
|
+
setState(newState) {
|
188
|
+
if (this.state !== constants_1.SocksClientState.Error) {
|
189
|
+
this.state = newState;
|
193
190
|
}
|
194
191
|
}
|
195
192
|
/**
|
196
193
|
* Starts the connection establishment to the proxy and destination.
|
197
|
-
* @param
|
194
|
+
* @param existingSocket Connected socket to use instead of creating a new one (internal use).
|
198
195
|
*/
|
199
|
-
connect(
|
200
|
-
this.
|
201
|
-
this.
|
202
|
-
this.
|
203
|
-
this.
|
196
|
+
connect(existingSocket) {
|
197
|
+
this.onDataReceived = (data) => this.onDataReceivedHandler(data);
|
198
|
+
this.onClose = () => this.onCloseHandler();
|
199
|
+
this.onError = (err) => this.onErrorHandler(err);
|
200
|
+
this.onConnect = () => this.onConnectHandler();
|
204
201
|
// Start timeout timer (defaults to 30 seconds)
|
205
|
-
const timer = setTimeout(() => this.onEstablishedTimeout(), this.
|
202
|
+
const timer = setTimeout(() => this.onEstablishedTimeout(), this.options.timeout || constants_1.DEFAULT_TIMEOUT);
|
206
203
|
// check whether unref is available as it differs from browser to NodeJS (#33)
|
207
204
|
if (timer.unref && typeof timer.unref === 'function') {
|
208
205
|
timer.unref();
|
209
206
|
}
|
210
207
|
// If an existing socket is provided, use it to negotiate SOCKS handshake. Otherwise create a new Socket.
|
211
|
-
if (
|
212
|
-
this.
|
208
|
+
if (existingSocket) {
|
209
|
+
this.socket = existingSocket;
|
213
210
|
}
|
214
211
|
else {
|
215
|
-
this.
|
212
|
+
this.socket = new net.Socket();
|
216
213
|
}
|
217
214
|
// Attach Socket error handlers.
|
218
|
-
this.
|
219
|
-
this.
|
220
|
-
this.
|
221
|
-
this.
|
222
|
-
this.
|
223
|
-
this.
|
224
|
-
if (
|
225
|
-
this.
|
215
|
+
this.socket.once('close', this.onClose);
|
216
|
+
this.socket.once('error', this.onError);
|
217
|
+
this.socket.once('connect', this.onConnect);
|
218
|
+
this.socket.on('data', this.onDataReceived);
|
219
|
+
this.setState(constants_1.SocksClientState.Connecting);
|
220
|
+
this.receiveBuffer = new receivebuffer_1.ReceiveBuffer();
|
221
|
+
if (existingSocket) {
|
222
|
+
this.socket.emit('connect');
|
226
223
|
}
|
227
224
|
else {
|
228
|
-
this.
|
229
|
-
if (this.
|
230
|
-
this.
|
231
|
-
this.
|
225
|
+
this.socket.connect(this.getSocketOptions());
|
226
|
+
if (this.options.set_tcp_nodelay !== undefined &&
|
227
|
+
this.options.set_tcp_nodelay !== null) {
|
228
|
+
this.socket.setNoDelay(!!this.options.set_tcp_nodelay);
|
232
229
|
}
|
233
230
|
}
|
234
231
|
// Listen for established event so we can re-emit any excess data received during handshakes.
|
235
|
-
this.prependOnceListener('established', info => {
|
232
|
+
this.prependOnceListener('established', (info) => {
|
236
233
|
setImmediate(() => {
|
237
|
-
if (this.
|
238
|
-
const excessData = this.
|
234
|
+
if (this.receiveBuffer.length > 0) {
|
235
|
+
const excessData = this.receiveBuffer.get(this.receiveBuffer.length);
|
239
236
|
info.socket.emit('data', excessData);
|
240
237
|
}
|
241
238
|
info.socket.resume();
|
242
239
|
});
|
243
240
|
});
|
244
241
|
}
|
242
|
+
// Socket options (defaults host/port to options.proxy.host/options.proxy.port)
|
243
|
+
getSocketOptions() {
|
244
|
+
return Object.assign(Object.assign({}, this.options.socket_options), { host: this.options.proxy.host || this.options.proxy.ipaddress, port: this.options.proxy.port });
|
245
|
+
}
|
245
246
|
/**
|
246
247
|
* Handles internal Socks timeout callback.
|
247
248
|
* Note: If the Socks client is not BoundWaitingForConnection or Established, the connection will be closed.
|
@@ -249,33 +250,33 @@ class SocksClient extends events_1.EventEmitter {
|
|
249
250
|
onEstablishedTimeout() {
|
250
251
|
if (this.state !== constants_1.SocksClientState.Established &&
|
251
252
|
this.state !== constants_1.SocksClientState.BoundWaitingForConnection) {
|
252
|
-
this.
|
253
|
+
this.closeSocket(constants_1.ERRORS.ProxyConnectionTimedOut);
|
253
254
|
}
|
254
255
|
}
|
255
256
|
/**
|
256
257
|
* Handles Socket connect event.
|
257
258
|
*/
|
258
|
-
|
259
|
-
this.
|
259
|
+
onConnectHandler() {
|
260
|
+
this.setState(constants_1.SocksClientState.Connected);
|
260
261
|
// Send initial handshake.
|
261
|
-
if (this.
|
262
|
+
if (this.options.proxy.type === 4) {
|
262
263
|
this.sendSocks4InitialHandshake();
|
263
264
|
}
|
264
265
|
else {
|
265
266
|
this.sendSocks5InitialHandshake();
|
266
267
|
}
|
267
|
-
this.
|
268
|
+
this.setState(constants_1.SocksClientState.SentInitialHandshake);
|
268
269
|
}
|
269
270
|
/**
|
270
271
|
* Handles Socket data event.
|
271
272
|
* @param data
|
272
273
|
*/
|
273
|
-
|
274
|
+
onDataReceivedHandler(data) {
|
274
275
|
/*
|
275
276
|
All received data is appended to a ReceiveBuffer.
|
276
277
|
This makes sure that all the data we need is received before we attempt to process it.
|
277
278
|
*/
|
278
|
-
this.
|
279
|
+
this.receiveBuffer.append(data);
|
279
280
|
// Process data that we have.
|
280
281
|
this.processData();
|
281
282
|
}
|
@@ -284,10 +285,10 @@ class SocksClient extends events_1.EventEmitter {
|
|
284
285
|
*/
|
285
286
|
processData() {
|
286
287
|
// If we have enough data to process the next step in the SOCKS handshake, proceed.
|
287
|
-
if (this.
|
288
|
+
if (this.receiveBuffer.length >= this.nextRequiredPacketBufferSize) {
|
288
289
|
// Sent initial handshake, waiting for response.
|
289
290
|
if (this.state === constants_1.SocksClientState.SentInitialHandshake) {
|
290
|
-
if (this.
|
291
|
+
if (this.options.proxy.type === 4) {
|
291
292
|
// Socks v4 only has one handshake response.
|
292
293
|
this.handleSocks4FinalHandshakeResponse();
|
293
294
|
}
|
@@ -306,7 +307,7 @@ class SocksClient extends events_1.EventEmitter {
|
|
306
307
|
// Socks BIND established. Waiting for remote connection via proxy.
|
307
308
|
}
|
308
309
|
else if (this.state === constants_1.SocksClientState.BoundWaitingForConnection) {
|
309
|
-
if (this.
|
310
|
+
if (this.options.proxy.type === 4) {
|
310
311
|
this.handleSocks4IncomingConnectionResponse();
|
311
312
|
}
|
312
313
|
else {
|
@@ -317,7 +318,7 @@ class SocksClient extends events_1.EventEmitter {
|
|
317
318
|
// do nothing (prevents closing of the socket)
|
318
319
|
}
|
319
320
|
else {
|
320
|
-
this.
|
321
|
+
this.closeSocket(constants_1.ERRORS.InternalError);
|
321
322
|
}
|
322
323
|
}
|
323
324
|
}
|
@@ -325,56 +326,56 @@ class SocksClient extends events_1.EventEmitter {
|
|
325
326
|
* Handles Socket close event.
|
326
327
|
* @param had_error
|
327
328
|
*/
|
328
|
-
|
329
|
-
this.
|
329
|
+
onCloseHandler() {
|
330
|
+
this.closeSocket(constants_1.ERRORS.SocketClosed);
|
330
331
|
}
|
331
332
|
/**
|
332
333
|
* Handles Socket error event.
|
333
334
|
* @param err
|
334
335
|
*/
|
335
|
-
|
336
|
-
this.
|
336
|
+
onErrorHandler(err) {
|
337
|
+
this.closeSocket(err.message);
|
337
338
|
}
|
338
339
|
/**
|
339
340
|
* Removes internal event listeners on the underlying Socket.
|
340
341
|
*/
|
341
342
|
removeInternalSocketHandlers() {
|
342
343
|
// Pauses data flow of the socket (this is internally resumed after 'established' is emitted)
|
343
|
-
this.
|
344
|
-
this.
|
345
|
-
this.
|
346
|
-
this.
|
347
|
-
this.
|
344
|
+
this.socket.pause();
|
345
|
+
this.socket.removeListener('data', this.onDataReceived);
|
346
|
+
this.socket.removeListener('close', this.onClose);
|
347
|
+
this.socket.removeListener('error', this.onError);
|
348
|
+
this.socket.removeListener('connect', this.onConnect);
|
348
349
|
}
|
349
350
|
/**
|
350
351
|
* Closes and destroys the underlying Socket. Emits an error event.
|
351
352
|
* @param err { String } An error string to include in error event.
|
352
353
|
*/
|
353
|
-
|
354
|
+
closeSocket(err) {
|
354
355
|
// Make sure only one 'error' event is fired for the lifetime of this SocksClient instance.
|
355
356
|
if (this.state !== constants_1.SocksClientState.Error) {
|
356
357
|
// Set internal state to Error.
|
357
|
-
this.
|
358
|
+
this.setState(constants_1.SocksClientState.Error);
|
358
359
|
// Destroy Socket
|
359
|
-
this.
|
360
|
+
this.socket.destroy();
|
360
361
|
// Remove internal listeners
|
361
362
|
this.removeInternalSocketHandlers();
|
362
363
|
// Fire 'error' event.
|
363
|
-
this.emit('error', new util_1.SocksClientError(err, this.
|
364
|
+
this.emit('error', new util_1.SocksClientError(err, this.options));
|
364
365
|
}
|
365
366
|
}
|
366
367
|
/**
|
367
368
|
* Sends initial Socks v4 handshake request.
|
368
369
|
*/
|
369
370
|
sendSocks4InitialHandshake() {
|
370
|
-
const userId = this.
|
371
|
+
const userId = this.options.proxy.userId || '';
|
371
372
|
const buff = new smart_buffer_1.SmartBuffer();
|
372
373
|
buff.writeUInt8(0x04);
|
373
|
-
buff.writeUInt8(constants_1.SocksCommand[this.
|
374
|
-
buff.writeUInt16BE(this.
|
374
|
+
buff.writeUInt8(constants_1.SocksCommand[this.options.command]);
|
375
|
+
buff.writeUInt16BE(this.options.destination.port);
|
375
376
|
// Socks 4 (IPv4)
|
376
|
-
if (net.isIPv4(this.
|
377
|
-
buff.writeBuffer(ip.toBuffer(this.
|
377
|
+
if (net.isIPv4(this.options.destination.host)) {
|
378
|
+
buff.writeBuffer(ip.toBuffer(this.options.destination.host));
|
378
379
|
buff.writeStringNT(userId);
|
379
380
|
// Socks 4a (hostname)
|
380
381
|
}
|
@@ -384,42 +385,42 @@ class SocksClient extends events_1.EventEmitter {
|
|
384
385
|
buff.writeUInt8(0x00);
|
385
386
|
buff.writeUInt8(0x01);
|
386
387
|
buff.writeStringNT(userId);
|
387
|
-
buff.writeStringNT(this.
|
388
|
+
buff.writeStringNT(this.options.destination.host);
|
388
389
|
}
|
389
|
-
this.
|
390
|
+
this.nextRequiredPacketBufferSize =
|
390
391
|
constants_1.SOCKS_INCOMING_PACKET_SIZES.Socks4Response;
|
391
|
-
this.
|
392
|
+
this.socket.write(buff.toBuffer());
|
392
393
|
}
|
393
394
|
/**
|
394
395
|
* Handles Socks v4 handshake response.
|
395
396
|
* @param data
|
396
397
|
*/
|
397
398
|
handleSocks4FinalHandshakeResponse() {
|
398
|
-
const data = this.
|
399
|
+
const data = this.receiveBuffer.get(8);
|
399
400
|
if (data[1] !== constants_1.Socks4Response.Granted) {
|
400
|
-
this.
|
401
|
+
this.closeSocket(`${constants_1.ERRORS.Socks4ProxyRejectedConnection} - (${constants_1.Socks4Response[data[1]]})`);
|
401
402
|
}
|
402
403
|
else {
|
403
404
|
// Bind response
|
404
|
-
if (constants_1.SocksCommand[this.
|
405
|
+
if (constants_1.SocksCommand[this.options.command] === constants_1.SocksCommand.bind) {
|
405
406
|
const buff = smart_buffer_1.SmartBuffer.fromBuffer(data);
|
406
407
|
buff.readOffset = 2;
|
407
408
|
const remoteHost = {
|
408
409
|
port: buff.readUInt16BE(),
|
409
|
-
host: ip.fromLong(buff.readUInt32BE())
|
410
|
+
host: ip.fromLong(buff.readUInt32BE()),
|
410
411
|
};
|
411
412
|
// If host is 0.0.0.0, set to proxy host.
|
412
413
|
if (remoteHost.host === '0.0.0.0') {
|
413
|
-
remoteHost.host = this.
|
414
|
+
remoteHost.host = this.options.proxy.ipaddress;
|
414
415
|
}
|
415
|
-
this.
|
416
|
-
this.emit('bound', { socket: this.
|
416
|
+
this.setState(constants_1.SocksClientState.BoundWaitingForConnection);
|
417
|
+
this.emit('bound', { remoteHost, socket: this.socket });
|
417
418
|
// Connect response
|
418
419
|
}
|
419
420
|
else {
|
420
|
-
this.
|
421
|
+
this.setState(constants_1.SocksClientState.Established);
|
421
422
|
this.removeInternalSocketHandlers();
|
422
|
-
this.emit('established', { socket: this.
|
423
|
+
this.emit('established', { socket: this.socket });
|
423
424
|
}
|
424
425
|
}
|
425
426
|
}
|
@@ -428,20 +429,20 @@ class SocksClient extends events_1.EventEmitter {
|
|
428
429
|
* @param data
|
429
430
|
*/
|
430
431
|
handleSocks4IncomingConnectionResponse() {
|
431
|
-
const data = this.
|
432
|
+
const data = this.receiveBuffer.get(8);
|
432
433
|
if (data[1] !== constants_1.Socks4Response.Granted) {
|
433
|
-
this.
|
434
|
+
this.closeSocket(`${constants_1.ERRORS.Socks4ProxyRejectedIncomingBoundConnection} - (${constants_1.Socks4Response[data[1]]})`);
|
434
435
|
}
|
435
436
|
else {
|
436
437
|
const buff = smart_buffer_1.SmartBuffer.fromBuffer(data);
|
437
438
|
buff.readOffset = 2;
|
438
439
|
const remoteHost = {
|
439
440
|
port: buff.readUInt16BE(),
|
440
|
-
host: ip.fromLong(buff.readUInt32BE())
|
441
|
+
host: ip.fromLong(buff.readUInt32BE()),
|
441
442
|
};
|
442
|
-
this.
|
443
|
+
this.setState(constants_1.SocksClientState.Established);
|
443
444
|
this.removeInternalSocketHandlers();
|
444
|
-
this.emit('established', { socket: this.
|
445
|
+
this.emit('established', { remoteHost, socket: this.socket });
|
445
446
|
}
|
446
447
|
}
|
447
448
|
/**
|
@@ -452,7 +453,7 @@ class SocksClient extends events_1.EventEmitter {
|
|
452
453
|
buff.writeUInt8(0x05);
|
453
454
|
// We should only tell the proxy we support user/pass auth if auth info is actually provided.
|
454
455
|
// Note: As of Tor v0.3.5.7+, if user/pass auth is an option from the client, by default it will always take priority.
|
455
|
-
if (this.
|
456
|
+
if (this.options.proxy.userId || this.options.proxy.password) {
|
456
457
|
buff.writeUInt8(2);
|
457
458
|
buff.writeUInt8(constants_1.Socks5Auth.NoAuth);
|
458
459
|
buff.writeUInt8(constants_1.Socks5Auth.UserPass);
|
@@ -461,22 +462,22 @@ class SocksClient extends events_1.EventEmitter {
|
|
461
462
|
buff.writeUInt8(1);
|
462
463
|
buff.writeUInt8(constants_1.Socks5Auth.NoAuth);
|
463
464
|
}
|
464
|
-
this.
|
465
|
+
this.nextRequiredPacketBufferSize =
|
465
466
|
constants_1.SOCKS_INCOMING_PACKET_SIZES.Socks5InitialHandshakeResponse;
|
466
|
-
this.
|
467
|
-
this.
|
467
|
+
this.socket.write(buff.toBuffer());
|
468
|
+
this.setState(constants_1.SocksClientState.SentInitialHandshake);
|
468
469
|
}
|
469
470
|
/**
|
470
471
|
* Handles initial Socks v5 handshake response.
|
471
472
|
* @param data
|
472
473
|
*/
|
473
474
|
handleInitialSocks5HandshakeResponse() {
|
474
|
-
const data = this.
|
475
|
+
const data = this.receiveBuffer.get(2);
|
475
476
|
if (data[0] !== 0x05) {
|
476
|
-
this.
|
477
|
+
this.closeSocket(constants_1.ERRORS.InvalidSocks5IntiailHandshakeSocksVersion);
|
477
478
|
}
|
478
479
|
else if (data[1] === 0xff) {
|
479
|
-
this.
|
480
|
+
this.closeSocket(constants_1.ERRORS.InvalidSocks5InitialHandshakeNoAcceptedAuthType);
|
480
481
|
}
|
481
482
|
else {
|
482
483
|
// If selected Socks v5 auth method is no auth, send final handshake request.
|
@@ -488,7 +489,7 @@ class SocksClient extends events_1.EventEmitter {
|
|
488
489
|
this.sendSocks5UserPassAuthentication();
|
489
490
|
}
|
490
491
|
else {
|
491
|
-
this.
|
492
|
+
this.closeSocket(constants_1.ERRORS.InvalidSocks5InitialHandshakeUnknownAuthType);
|
492
493
|
}
|
493
494
|
}
|
494
495
|
}
|
@@ -498,28 +499,28 @@ class SocksClient extends events_1.EventEmitter {
|
|
498
499
|
* Note: No auth and user/pass are currently supported.
|
499
500
|
*/
|
500
501
|
sendSocks5UserPassAuthentication() {
|
501
|
-
const userId = this.
|
502
|
-
const password = this.
|
502
|
+
const userId = this.options.proxy.userId || '';
|
503
|
+
const password = this.options.proxy.password || '';
|
503
504
|
const buff = new smart_buffer_1.SmartBuffer();
|
504
505
|
buff.writeUInt8(0x01);
|
505
506
|
buff.writeUInt8(Buffer.byteLength(userId));
|
506
507
|
buff.writeString(userId);
|
507
508
|
buff.writeUInt8(Buffer.byteLength(password));
|
508
509
|
buff.writeString(password);
|
509
|
-
this.
|
510
|
+
this.nextRequiredPacketBufferSize =
|
510
511
|
constants_1.SOCKS_INCOMING_PACKET_SIZES.Socks5UserPassAuthenticationResponse;
|
511
|
-
this.
|
512
|
-
this.
|
512
|
+
this.socket.write(buff.toBuffer());
|
513
|
+
this.setState(constants_1.SocksClientState.SentAuthentication);
|
513
514
|
}
|
514
515
|
/**
|
515
516
|
* Handles Socks v5 auth handshake response.
|
516
517
|
* @param data
|
517
518
|
*/
|
518
519
|
handleInitialSocks5AuthenticationHandshakeResponse() {
|
519
|
-
this.
|
520
|
-
const data = this.
|
520
|
+
this.setState(constants_1.SocksClientState.ReceivedAuthenticationResponse);
|
521
|
+
const data = this.receiveBuffer.get(2);
|
521
522
|
if (data[1] !== 0x00) {
|
522
|
-
this.
|
523
|
+
this.closeSocket(constants_1.ERRORS.Socks5AuthenticationFailed);
|
523
524
|
}
|
524
525
|
else {
|
525
526
|
this.sendSocks5CommandRequest();
|
@@ -531,27 +532,27 @@ class SocksClient extends events_1.EventEmitter {
|
|
531
532
|
sendSocks5CommandRequest() {
|
532
533
|
const buff = new smart_buffer_1.SmartBuffer();
|
533
534
|
buff.writeUInt8(0x05);
|
534
|
-
buff.writeUInt8(constants_1.SocksCommand[this.
|
535
|
+
buff.writeUInt8(constants_1.SocksCommand[this.options.command]);
|
535
536
|
buff.writeUInt8(0x00);
|
536
537
|
// ipv4, ipv6, domain?
|
537
|
-
if (net.isIPv4(this.
|
538
|
+
if (net.isIPv4(this.options.destination.host)) {
|
538
539
|
buff.writeUInt8(constants_1.Socks5HostType.IPv4);
|
539
|
-
buff.writeBuffer(ip.toBuffer(this.
|
540
|
+
buff.writeBuffer(ip.toBuffer(this.options.destination.host));
|
540
541
|
}
|
541
|
-
else if (net.isIPv6(this.
|
542
|
+
else if (net.isIPv6(this.options.destination.host)) {
|
542
543
|
buff.writeUInt8(constants_1.Socks5HostType.IPv6);
|
543
|
-
buff.writeBuffer(ip.toBuffer(this.
|
544
|
+
buff.writeBuffer(ip.toBuffer(this.options.destination.host));
|
544
545
|
}
|
545
546
|
else {
|
546
547
|
buff.writeUInt8(constants_1.Socks5HostType.Hostname);
|
547
|
-
buff.writeUInt8(this.
|
548
|
-
buff.writeString(this.
|
548
|
+
buff.writeUInt8(this.options.destination.host.length);
|
549
|
+
buff.writeString(this.options.destination.host);
|
549
550
|
}
|
550
|
-
buff.writeUInt16BE(this.
|
551
|
-
this.
|
551
|
+
buff.writeUInt16BE(this.options.destination.port);
|
552
|
+
this.nextRequiredPacketBufferSize =
|
552
553
|
constants_1.SOCKS_INCOMING_PACKET_SIZES.Socks5ResponseHeader;
|
553
|
-
this.
|
554
|
-
this.
|
554
|
+
this.socket.write(buff.toBuffer());
|
555
|
+
this.setState(constants_1.SocksClientState.SentFinalHandshake);
|
555
556
|
}
|
556
557
|
/**
|
557
558
|
* Handles Socks v5 final handshake response.
|
@@ -559,9 +560,9 @@ class SocksClient extends events_1.EventEmitter {
|
|
559
560
|
*/
|
560
561
|
handleSocks5FinalHandshakeResponse() {
|
561
562
|
// Peek at available data (we need at least 5 bytes to get the hostname length)
|
562
|
-
const header = this.
|
563
|
+
const header = this.receiveBuffer.peek(5);
|
563
564
|
if (header[0] !== 0x05 || header[1] !== constants_1.Socks5Response.Granted) {
|
564
|
-
this.
|
565
|
+
this.closeSocket(`${constants_1.ERRORS.InvalidSocks5FinalHandshakeRejected} - ${constants_1.Socks5Response[header[1]]}`);
|
565
566
|
}
|
566
567
|
else {
|
567
568
|
// Read address type
|
@@ -572,18 +573,18 @@ class SocksClient extends events_1.EventEmitter {
|
|
572
573
|
if (addressType === constants_1.Socks5HostType.IPv4) {
|
573
574
|
// Check if data is available.
|
574
575
|
const dataNeeded = constants_1.SOCKS_INCOMING_PACKET_SIZES.Socks5ResponseIPv4;
|
575
|
-
if (this.
|
576
|
-
this.
|
576
|
+
if (this.receiveBuffer.length < dataNeeded) {
|
577
|
+
this.nextRequiredPacketBufferSize = dataNeeded;
|
577
578
|
return;
|
578
579
|
}
|
579
|
-
buff = smart_buffer_1.SmartBuffer.fromBuffer(this.
|
580
|
+
buff = smart_buffer_1.SmartBuffer.fromBuffer(this.receiveBuffer.get(dataNeeded).slice(4));
|
580
581
|
remoteHost = {
|
581
582
|
host: ip.fromLong(buff.readUInt32BE()),
|
582
|
-
port: buff.readUInt16BE()
|
583
|
+
port: buff.readUInt16BE(),
|
583
584
|
};
|
584
585
|
// If given host is 0.0.0.0, assume remote proxy ip instead.
|
585
586
|
if (remoteHost.host === '0.0.0.0') {
|
586
|
-
remoteHost.host = this.
|
587
|
+
remoteHost.host = this.options.proxy.ipaddress;
|
587
588
|
}
|
588
589
|
// Hostname
|
589
590
|
}
|
@@ -591,55 +592,57 @@ class SocksClient extends events_1.EventEmitter {
|
|
591
592
|
const hostLength = header[4];
|
592
593
|
const dataNeeded = constants_1.SOCKS_INCOMING_PACKET_SIZES.Socks5ResponseHostname(hostLength); // header + host length + host + port
|
593
594
|
// Check if data is available.
|
594
|
-
if (this.
|
595
|
-
this.
|
595
|
+
if (this.receiveBuffer.length < dataNeeded) {
|
596
|
+
this.nextRequiredPacketBufferSize = dataNeeded;
|
596
597
|
return;
|
597
598
|
}
|
598
|
-
buff = smart_buffer_1.SmartBuffer.fromBuffer(this.
|
599
|
-
);
|
599
|
+
buff = smart_buffer_1.SmartBuffer.fromBuffer(this.receiveBuffer.get(dataNeeded).slice(5));
|
600
600
|
remoteHost = {
|
601
601
|
host: buff.readString(hostLength),
|
602
|
-
port: buff.readUInt16BE()
|
602
|
+
port: buff.readUInt16BE(),
|
603
603
|
};
|
604
604
|
// IPv6
|
605
605
|
}
|
606
606
|
else if (addressType === constants_1.Socks5HostType.IPv6) {
|
607
607
|
// Check if data is available.
|
608
608
|
const dataNeeded = constants_1.SOCKS_INCOMING_PACKET_SIZES.Socks5ResponseIPv6;
|
609
|
-
if (this.
|
610
|
-
this.
|
609
|
+
if (this.receiveBuffer.length < dataNeeded) {
|
610
|
+
this.nextRequiredPacketBufferSize = dataNeeded;
|
611
611
|
return;
|
612
612
|
}
|
613
|
-
buff = smart_buffer_1.SmartBuffer.fromBuffer(this.
|
613
|
+
buff = smart_buffer_1.SmartBuffer.fromBuffer(this.receiveBuffer.get(dataNeeded).slice(4));
|
614
614
|
remoteHost = {
|
615
615
|
host: ip.toString(buff.readBuffer(16)),
|
616
|
-
port: buff.readUInt16BE()
|
616
|
+
port: buff.readUInt16BE(),
|
617
617
|
};
|
618
618
|
}
|
619
619
|
// We have everything we need
|
620
|
-
this.
|
620
|
+
this.setState(constants_1.SocksClientState.ReceivedFinalResponse);
|
621
621
|
// If using CONNECT, the client is now in the established state.
|
622
|
-
if (constants_1.SocksCommand[this.
|
623
|
-
this.
|
622
|
+
if (constants_1.SocksCommand[this.options.command] === constants_1.SocksCommand.connect) {
|
623
|
+
this.setState(constants_1.SocksClientState.Established);
|
624
624
|
this.removeInternalSocketHandlers();
|
625
|
-
this.emit('established', { socket: this.
|
625
|
+
this.emit('established', { socket: this.socket });
|
626
626
|
}
|
627
|
-
else if (constants_1.SocksCommand[this.
|
627
|
+
else if (constants_1.SocksCommand[this.options.command] === constants_1.SocksCommand.bind) {
|
628
628
|
/* If using BIND, the Socks client is now in BoundWaitingForConnection state.
|
629
629
|
This means that the remote proxy server is waiting for a remote connection to the bound port. */
|
630
|
-
this.
|
631
|
-
this.
|
630
|
+
this.setState(constants_1.SocksClientState.BoundWaitingForConnection);
|
631
|
+
this.nextRequiredPacketBufferSize =
|
632
632
|
constants_1.SOCKS_INCOMING_PACKET_SIZES.Socks5ResponseHeader;
|
633
|
-
this.emit('bound', { socket: this.
|
633
|
+
this.emit('bound', { remoteHost, socket: this.socket });
|
634
634
|
/*
|
635
635
|
If using Associate, the Socks client is now Established. And the proxy server is now accepting UDP packets at the
|
636
636
|
given bound port. This initial Socks TCP connection must remain open for the UDP relay to continue to work.
|
637
637
|
*/
|
638
638
|
}
|
639
|
-
else if (constants_1.SocksCommand[this.
|
640
|
-
this.
|
639
|
+
else if (constants_1.SocksCommand[this.options.command] === constants_1.SocksCommand.associate) {
|
640
|
+
this.setState(constants_1.SocksClientState.Established);
|
641
641
|
this.removeInternalSocketHandlers();
|
642
|
-
this.emit('established', {
|
642
|
+
this.emit('established', {
|
643
|
+
remoteHost,
|
644
|
+
socket: this.socket,
|
645
|
+
});
|
643
646
|
}
|
644
647
|
}
|
645
648
|
}
|
@@ -648,9 +651,9 @@ class SocksClient extends events_1.EventEmitter {
|
|
648
651
|
*/
|
649
652
|
handleSocks5IncomingConnectionResponse() {
|
650
653
|
// Peek at available data (we need at least 5 bytes to get the hostname length)
|
651
|
-
const header = this.
|
654
|
+
const header = this.receiveBuffer.peek(5);
|
652
655
|
if (header[0] !== 0x05 || header[1] !== constants_1.Socks5Response.Granted) {
|
653
|
-
this.
|
656
|
+
this.closeSocket(`${constants_1.ERRORS.Socks5ProxyRejectedIncomingBoundConnection} - ${constants_1.Socks5Response[header[1]]}`);
|
654
657
|
}
|
655
658
|
else {
|
656
659
|
// Read address type
|
@@ -661,18 +664,18 @@ class SocksClient extends events_1.EventEmitter {
|
|
661
664
|
if (addressType === constants_1.Socks5HostType.IPv4) {
|
662
665
|
// Check if data is available.
|
663
666
|
const dataNeeded = constants_1.SOCKS_INCOMING_PACKET_SIZES.Socks5ResponseIPv4;
|
664
|
-
if (this.
|
665
|
-
this.
|
667
|
+
if (this.receiveBuffer.length < dataNeeded) {
|
668
|
+
this.nextRequiredPacketBufferSize = dataNeeded;
|
666
669
|
return;
|
667
670
|
}
|
668
|
-
buff = smart_buffer_1.SmartBuffer.fromBuffer(this.
|
671
|
+
buff = smart_buffer_1.SmartBuffer.fromBuffer(this.receiveBuffer.get(dataNeeded).slice(4));
|
669
672
|
remoteHost = {
|
670
673
|
host: ip.fromLong(buff.readUInt32BE()),
|
671
|
-
port: buff.readUInt16BE()
|
674
|
+
port: buff.readUInt16BE(),
|
672
675
|
};
|
673
676
|
// If given host is 0.0.0.0, assume remote proxy ip instead.
|
674
677
|
if (remoteHost.host === '0.0.0.0') {
|
675
|
-
remoteHost.host = this.
|
678
|
+
remoteHost.host = this.options.proxy.ipaddress;
|
676
679
|
}
|
677
680
|
// Hostname
|
678
681
|
}
|
@@ -680,38 +683,37 @@ class SocksClient extends events_1.EventEmitter {
|
|
680
683
|
const hostLength = header[4];
|
681
684
|
const dataNeeded = constants_1.SOCKS_INCOMING_PACKET_SIZES.Socks5ResponseHostname(hostLength); // header + host length + port
|
682
685
|
// Check if data is available.
|
683
|
-
if (this.
|
684
|
-
this.
|
686
|
+
if (this.receiveBuffer.length < dataNeeded) {
|
687
|
+
this.nextRequiredPacketBufferSize = dataNeeded;
|
685
688
|
return;
|
686
689
|
}
|
687
|
-
buff = smart_buffer_1.SmartBuffer.fromBuffer(this.
|
688
|
-
);
|
690
|
+
buff = smart_buffer_1.SmartBuffer.fromBuffer(this.receiveBuffer.get(dataNeeded).slice(5));
|
689
691
|
remoteHost = {
|
690
692
|
host: buff.readString(hostLength),
|
691
|
-
port: buff.readUInt16BE()
|
693
|
+
port: buff.readUInt16BE(),
|
692
694
|
};
|
693
695
|
// IPv6
|
694
696
|
}
|
695
697
|
else if (addressType === constants_1.Socks5HostType.IPv6) {
|
696
698
|
// Check if data is available.
|
697
699
|
const dataNeeded = constants_1.SOCKS_INCOMING_PACKET_SIZES.Socks5ResponseIPv6;
|
698
|
-
if (this.
|
699
|
-
this.
|
700
|
+
if (this.receiveBuffer.length < dataNeeded) {
|
701
|
+
this.nextRequiredPacketBufferSize = dataNeeded;
|
700
702
|
return;
|
701
703
|
}
|
702
|
-
buff = smart_buffer_1.SmartBuffer.fromBuffer(this.
|
704
|
+
buff = smart_buffer_1.SmartBuffer.fromBuffer(this.receiveBuffer.get(dataNeeded).slice(4));
|
703
705
|
remoteHost = {
|
704
706
|
host: ip.toString(buff.readBuffer(16)),
|
705
|
-
port: buff.readUInt16BE()
|
707
|
+
port: buff.readUInt16BE(),
|
706
708
|
};
|
707
709
|
}
|
708
|
-
this.
|
710
|
+
this.setState(constants_1.SocksClientState.Established);
|
709
711
|
this.removeInternalSocketHandlers();
|
710
|
-
this.emit('established', { socket: this.
|
712
|
+
this.emit('established', { remoteHost, socket: this.socket });
|
711
713
|
}
|
712
714
|
}
|
713
715
|
get socksClientOptions() {
|
714
|
-
return Object.assign({}, this.
|
716
|
+
return Object.assign({}, this.options);
|
715
717
|
}
|
716
718
|
}
|
717
719
|
exports.SocksClient = SocksClient;
|