source: trip-planner-front/node_modules/socks/build/client/socksclient.js@ 571e0df

Last change on this file since 571e0df was 6a3a178, checked in by Ema <ema_spirova@…>, 3 years ago

initial commit

  • Property mode set to 100644
File size: 34.2 KB
RevLine 
[6a3a178]1"use strict";
2var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3 function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4 return new (P || (P = Promise))(function (resolve, reject) {
5 function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6 function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7 function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8 step((generator = generator.apply(thisArg, _arguments || [])).next());
9 });
10};
11Object.defineProperty(exports, "__esModule", { value: true });
12exports.SocksClientError = exports.SocksClient = void 0;
13const events_1 = require("events");
14const net = require("net");
15const ip = require("ip");
16const smart_buffer_1 = require("smart-buffer");
17const constants_1 = require("../common/constants");
18const helpers_1 = require("../common/helpers");
19const receivebuffer_1 = require("../common/receivebuffer");
20const util_1 = require("../common/util");
21Object.defineProperty(exports, "SocksClientError", { enumerable: true, get: function () { return util_1.SocksClientError; } });
22class SocksClient extends events_1.EventEmitter {
23 constructor(options) {
24 super();
25 this.options = Object.assign({}, options);
26 // Validate SocksClientOptions
27 helpers_1.validateSocksClientOptions(options);
28 // Default state
29 this.setState(constants_1.SocksClientState.Created);
30 }
31 /**
32 * Creates a new SOCKS connection.
33 *
34 * Note: Supports callbacks and promises. Only supports the connect command.
35 * @param options { SocksClientOptions } Options.
36 * @param callback { Function } An optional callback function.
37 * @returns { Promise }
38 */
39 static createConnection(options, callback) {
40 return new Promise((resolve, reject) => {
41 // Validate SocksClientOptions
42 try {
43 helpers_1.validateSocksClientOptions(options, ['connect']);
44 }
45 catch (err) {
46 if (typeof callback === 'function') {
47 callback(err);
48 return resolve(err); // Resolves pending promise (prevents memory leaks).
49 }
50 else {
51 return reject(err);
52 }
53 }
54 const client = new SocksClient(options);
55 client.connect(options.existing_socket);
56 client.once('established', (info) => {
57 client.removeAllListeners();
58 if (typeof callback === 'function') {
59 callback(null, info);
60 resolve(info); // Resolves pending promise (prevents memory leaks).
61 }
62 else {
63 resolve(info);
64 }
65 });
66 // Error occurred, failed to establish connection.
67 client.once('error', (err) => {
68 client.removeAllListeners();
69 if (typeof callback === 'function') {
70 callback(err);
71 resolve(err); // Resolves pending promise (prevents memory leaks).
72 }
73 else {
74 reject(err);
75 }
76 });
77 });
78 }
79 /**
80 * Creates a new SOCKS connection chain to a destination host through 2 or more SOCKS proxies.
81 *
82 * Note: Supports callbacks and promises. Only supports the connect method.
83 * Note: Implemented via createConnection() factory function.
84 * @param options { SocksClientChainOptions } Options
85 * @param callback { Function } An optional callback function.
86 * @returns { Promise }
87 */
88 static createConnectionChain(options, callback) {
89 return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
90 // Validate SocksClientChainOptions
91 try {
92 helpers_1.validateSocksClientChainOptions(options);
93 }
94 catch (err) {
95 if (typeof callback === 'function') {
96 callback(err);
97 return resolve(err); // Resolves pending promise (prevents memory leaks).
98 }
99 else {
100 return reject(err);
101 }
102 }
103 let sock;
104 // Shuffle proxies
105 if (options.randomizeChain) {
106 util_1.shuffleArray(options.proxies);
107 }
108 try {
109 // tslint:disable-next-line:no-increment-decrement
110 for (let i = 0; i < options.proxies.length; i++) {
111 const nextProxy = options.proxies[i];
112 // If we've reached the last proxy in the chain, the destination is the actual destination, otherwise it's the next proxy.
113 const nextDestination = i === options.proxies.length - 1
114 ? options.destination
115 : {
116 host: options.proxies[i + 1].ipaddress,
117 port: options.proxies[i + 1].port,
118 };
119 // Creates the next connection in the chain.
120 const result = yield SocksClient.createConnection({
121 command: 'connect',
122 proxy: nextProxy,
123 destination: nextDestination,
124 // Initial connection ignores this as sock is undefined. Subsequent connections re-use the first proxy socket to form a chain.
125 });
126 // If sock is undefined, assign it here.
127 if (!sock) {
128 sock = result.socket;
129 }
130 }
131 if (typeof callback === 'function') {
132 callback(null, { socket: sock });
133 resolve({ socket: sock }); // Resolves pending promise (prevents memory leaks).
134 }
135 else {
136 resolve({ socket: sock });
137 }
138 }
139 catch (err) {
140 if (typeof callback === 'function') {
141 callback(err);
142 resolve(err); // Resolves pending promise (prevents memory leaks).
143 }
144 else {
145 reject(err);
146 }
147 }
148 }));
149 }
150 /**
151 * Creates a SOCKS UDP Frame.
152 * @param options
153 */
154 static createUDPFrame(options) {
155 const buff = new smart_buffer_1.SmartBuffer();
156 buff.writeUInt16BE(0);
157 buff.writeUInt8(options.frameNumber || 0);
158 // IPv4/IPv6/Hostname
159 if (net.isIPv4(options.remoteHost.host)) {
160 buff.writeUInt8(constants_1.Socks5HostType.IPv4);
161 buff.writeUInt32BE(ip.toLong(options.remoteHost.host));
162 }
163 else if (net.isIPv6(options.remoteHost.host)) {
164 buff.writeUInt8(constants_1.Socks5HostType.IPv6);
165 buff.writeBuffer(ip.toBuffer(options.remoteHost.host));
166 }
167 else {
168 buff.writeUInt8(constants_1.Socks5HostType.Hostname);
169 buff.writeUInt8(Buffer.byteLength(options.remoteHost.host));
170 buff.writeString(options.remoteHost.host);
171 }
172 // Port
173 buff.writeUInt16BE(options.remoteHost.port);
174 // Data
175 buff.writeBuffer(options.data);
176 return buff.toBuffer();
177 }
178 /**
179 * Parses a SOCKS UDP frame.
180 * @param data
181 */
182 static parseUDPFrame(data) {
183 const buff = smart_buffer_1.SmartBuffer.fromBuffer(data);
184 buff.readOffset = 2;
185 const frameNumber = buff.readUInt8();
186 const hostType = buff.readUInt8();
187 let remoteHost;
188 if (hostType === constants_1.Socks5HostType.IPv4) {
189 remoteHost = ip.fromLong(buff.readUInt32BE());
190 }
191 else if (hostType === constants_1.Socks5HostType.IPv6) {
192 remoteHost = ip.toString(buff.readBuffer(16));
193 }
194 else {
195 remoteHost = buff.readString(buff.readUInt8());
196 }
197 const remotePort = buff.readUInt16BE();
198 return {
199 frameNumber,
200 remoteHost: {
201 host: remoteHost,
202 port: remotePort,
203 },
204 data: buff.readBuffer(),
205 };
206 }
207 /**
208 * Internal state setter. If the SocksClient is in an error state, it cannot be changed to a non error state.
209 */
210 setState(newState) {
211 if (this.state !== constants_1.SocksClientState.Error) {
212 this.state = newState;
213 }
214 }
215 /**
216 * Starts the connection establishment to the proxy and destination.
217 * @param existingSocket Connected socket to use instead of creating a new one (internal use).
218 */
219 connect(existingSocket) {
220 this.onDataReceived = (data) => this.onDataReceivedHandler(data);
221 this.onClose = () => this.onCloseHandler();
222 this.onError = (err) => this.onErrorHandler(err);
223 this.onConnect = () => this.onConnectHandler();
224 // Start timeout timer (defaults to 30 seconds)
225 const timer = setTimeout(() => this.onEstablishedTimeout(), this.options.timeout || constants_1.DEFAULT_TIMEOUT);
226 // check whether unref is available as it differs from browser to NodeJS (#33)
227 if (timer.unref && typeof timer.unref === 'function') {
228 timer.unref();
229 }
230 // If an existing socket is provided, use it to negotiate SOCKS handshake. Otherwise create a new Socket.
231 if (existingSocket) {
232 this.socket = existingSocket;
233 }
234 else {
235 this.socket = new net.Socket();
236 }
237 // Attach Socket error handlers.
238 this.socket.once('close', this.onClose);
239 this.socket.once('error', this.onError);
240 this.socket.once('connect', this.onConnect);
241 this.socket.on('data', this.onDataReceived);
242 this.setState(constants_1.SocksClientState.Connecting);
243 this.receiveBuffer = new receivebuffer_1.ReceiveBuffer();
244 if (existingSocket) {
245 this.socket.emit('connect');
246 }
247 else {
248 this.socket.connect(this.getSocketOptions());
249 if (this.options.set_tcp_nodelay !== undefined &&
250 this.options.set_tcp_nodelay !== null) {
251 this.socket.setNoDelay(!!this.options.set_tcp_nodelay);
252 }
253 }
254 // Listen for established event so we can re-emit any excess data received during handshakes.
255 this.prependOnceListener('established', (info) => {
256 setImmediate(() => {
257 if (this.receiveBuffer.length > 0) {
258 const excessData = this.receiveBuffer.get(this.receiveBuffer.length);
259 info.socket.emit('data', excessData);
260 }
261 info.socket.resume();
262 });
263 });
264 }
265 // Socket options (defaults host/port to options.proxy.host/options.proxy.port)
266 getSocketOptions() {
267 return Object.assign(Object.assign({}, this.options.socket_options), { host: this.options.proxy.host || this.options.proxy.ipaddress, port: this.options.proxy.port });
268 }
269 /**
270 * Handles internal Socks timeout callback.
271 * Note: If the Socks client is not BoundWaitingForConnection or Established, the connection will be closed.
272 */
273 onEstablishedTimeout() {
274 if (this.state !== constants_1.SocksClientState.Established &&
275 this.state !== constants_1.SocksClientState.BoundWaitingForConnection) {
276 this.closeSocket(constants_1.ERRORS.ProxyConnectionTimedOut);
277 }
278 }
279 /**
280 * Handles Socket connect event.
281 */
282 onConnectHandler() {
283 this.setState(constants_1.SocksClientState.Connected);
284 // Send initial handshake.
285 if (this.options.proxy.type === 4) {
286 this.sendSocks4InitialHandshake();
287 }
288 else {
289 this.sendSocks5InitialHandshake();
290 }
291 this.setState(constants_1.SocksClientState.SentInitialHandshake);
292 }
293 /**
294 * Handles Socket data event.
295 * @param data
296 */
297 onDataReceivedHandler(data) {
298 /*
299 All received data is appended to a ReceiveBuffer.
300 This makes sure that all the data we need is received before we attempt to process it.
301 */
302 this.receiveBuffer.append(data);
303 // Process data that we have.
304 this.processData();
305 }
306 /**
307 * Handles processing of the data we have received.
308 */
309 processData() {
310 // If we have enough data to process the next step in the SOCKS handshake, proceed.
311 while (this.state !== constants_1.SocksClientState.Established &&
312 this.state !== constants_1.SocksClientState.Error &&
313 this.receiveBuffer.length >= this.nextRequiredPacketBufferSize) {
314 // Sent initial handshake, waiting for response.
315 if (this.state === constants_1.SocksClientState.SentInitialHandshake) {
316 if (this.options.proxy.type === 4) {
317 // Socks v4 only has one handshake response.
318 this.handleSocks4FinalHandshakeResponse();
319 }
320 else {
321 // Socks v5 has two handshakes, handle initial one here.
322 this.handleInitialSocks5HandshakeResponse();
323 }
324 // Sent auth request for Socks v5, waiting for response.
325 }
326 else if (this.state === constants_1.SocksClientState.SentAuthentication) {
327 this.handleInitialSocks5AuthenticationHandshakeResponse();
328 // Sent final Socks v5 handshake, waiting for final response.
329 }
330 else if (this.state === constants_1.SocksClientState.SentFinalHandshake) {
331 this.handleSocks5FinalHandshakeResponse();
332 // Socks BIND established. Waiting for remote connection via proxy.
333 }
334 else if (this.state === constants_1.SocksClientState.BoundWaitingForConnection) {
335 if (this.options.proxy.type === 4) {
336 this.handleSocks4IncomingConnectionResponse();
337 }
338 else {
339 this.handleSocks5IncomingConnectionResponse();
340 }
341 }
342 else {
343 this.closeSocket(constants_1.ERRORS.InternalError);
344 break;
345 }
346 }
347 }
348 /**
349 * Handles Socket close event.
350 * @param had_error
351 */
352 onCloseHandler() {
353 this.closeSocket(constants_1.ERRORS.SocketClosed);
354 }
355 /**
356 * Handles Socket error event.
357 * @param err
358 */
359 onErrorHandler(err) {
360 this.closeSocket(err.message);
361 }
362 /**
363 * Removes internal event listeners on the underlying Socket.
364 */
365 removeInternalSocketHandlers() {
366 // Pauses data flow of the socket (this is internally resumed after 'established' is emitted)
367 this.socket.pause();
368 this.socket.removeListener('data', this.onDataReceived);
369 this.socket.removeListener('close', this.onClose);
370 this.socket.removeListener('error', this.onError);
371 this.socket.removeListener('connect', this.onConnect);
372 }
373 /**
374 * Closes and destroys the underlying Socket. Emits an error event.
375 * @param err { String } An error string to include in error event.
376 */
377 closeSocket(err) {
378 // Make sure only one 'error' event is fired for the lifetime of this SocksClient instance.
379 if (this.state !== constants_1.SocksClientState.Error) {
380 // Set internal state to Error.
381 this.setState(constants_1.SocksClientState.Error);
382 // Destroy Socket
383 this.socket.destroy();
384 // Remove internal listeners
385 this.removeInternalSocketHandlers();
386 // Fire 'error' event.
387 this.emit('error', new util_1.SocksClientError(err, this.options));
388 }
389 }
390 /**
391 * Sends initial Socks v4 handshake request.
392 */
393 sendSocks4InitialHandshake() {
394 const userId = this.options.proxy.userId || '';
395 const buff = new smart_buffer_1.SmartBuffer();
396 buff.writeUInt8(0x04);
397 buff.writeUInt8(constants_1.SocksCommand[this.options.command]);
398 buff.writeUInt16BE(this.options.destination.port);
399 // Socks 4 (IPv4)
400 if (net.isIPv4(this.options.destination.host)) {
401 buff.writeBuffer(ip.toBuffer(this.options.destination.host));
402 buff.writeStringNT(userId);
403 // Socks 4a (hostname)
404 }
405 else {
406 buff.writeUInt8(0x00);
407 buff.writeUInt8(0x00);
408 buff.writeUInt8(0x00);
409 buff.writeUInt8(0x01);
410 buff.writeStringNT(userId);
411 buff.writeStringNT(this.options.destination.host);
412 }
413 this.nextRequiredPacketBufferSize =
414 constants_1.SOCKS_INCOMING_PACKET_SIZES.Socks4Response;
415 this.socket.write(buff.toBuffer());
416 }
417 /**
418 * Handles Socks v4 handshake response.
419 * @param data
420 */
421 handleSocks4FinalHandshakeResponse() {
422 const data = this.receiveBuffer.get(8);
423 if (data[1] !== constants_1.Socks4Response.Granted) {
424 this.closeSocket(`${constants_1.ERRORS.Socks4ProxyRejectedConnection} - (${constants_1.Socks4Response[data[1]]})`);
425 }
426 else {
427 // Bind response
428 if (constants_1.SocksCommand[this.options.command] === constants_1.SocksCommand.bind) {
429 const buff = smart_buffer_1.SmartBuffer.fromBuffer(data);
430 buff.readOffset = 2;
431 const remoteHost = {
432 port: buff.readUInt16BE(),
433 host: ip.fromLong(buff.readUInt32BE()),
434 };
435 // If host is 0.0.0.0, set to proxy host.
436 if (remoteHost.host === '0.0.0.0') {
437 remoteHost.host = this.options.proxy.ipaddress;
438 }
439 this.setState(constants_1.SocksClientState.BoundWaitingForConnection);
440 this.emit('bound', { remoteHost, socket: this.socket });
441 // Connect response
442 }
443 else {
444 this.setState(constants_1.SocksClientState.Established);
445 this.removeInternalSocketHandlers();
446 this.emit('established', { socket: this.socket });
447 }
448 }
449 }
450 /**
451 * Handles Socks v4 incoming connection request (BIND)
452 * @param data
453 */
454 handleSocks4IncomingConnectionResponse() {
455 const data = this.receiveBuffer.get(8);
456 if (data[1] !== constants_1.Socks4Response.Granted) {
457 this.closeSocket(`${constants_1.ERRORS.Socks4ProxyRejectedIncomingBoundConnection} - (${constants_1.Socks4Response[data[1]]})`);
458 }
459 else {
460 const buff = smart_buffer_1.SmartBuffer.fromBuffer(data);
461 buff.readOffset = 2;
462 const remoteHost = {
463 port: buff.readUInt16BE(),
464 host: ip.fromLong(buff.readUInt32BE()),
465 };
466 this.setState(constants_1.SocksClientState.Established);
467 this.removeInternalSocketHandlers();
468 this.emit('established', { remoteHost, socket: this.socket });
469 }
470 }
471 /**
472 * Sends initial Socks v5 handshake request.
473 */
474 sendSocks5InitialHandshake() {
475 const buff = new smart_buffer_1.SmartBuffer();
476 // By default we always support no auth.
477 const supportedAuthMethods = [constants_1.Socks5Auth.NoAuth];
478 // We should only tell the proxy we support user/pass auth if auth info is actually provided.
479 // 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.
480 if (this.options.proxy.userId || this.options.proxy.password) {
481 supportedAuthMethods.push(constants_1.Socks5Auth.UserPass);
482 }
483 // Custom auth method?
484 if (this.options.proxy.custom_auth_method !== undefined) {
485 supportedAuthMethods.push(this.options.proxy.custom_auth_method);
486 }
487 // Build handshake packet
488 buff.writeUInt8(0x05);
489 buff.writeUInt8(supportedAuthMethods.length);
490 for (const authMethod of supportedAuthMethods) {
491 buff.writeUInt8(authMethod);
492 }
493 this.nextRequiredPacketBufferSize =
494 constants_1.SOCKS_INCOMING_PACKET_SIZES.Socks5InitialHandshakeResponse;
495 this.socket.write(buff.toBuffer());
496 this.setState(constants_1.SocksClientState.SentInitialHandshake);
497 }
498 /**
499 * Handles initial Socks v5 handshake response.
500 * @param data
501 */
502 handleInitialSocks5HandshakeResponse() {
503 const data = this.receiveBuffer.get(2);
504 if (data[0] !== 0x05) {
505 this.closeSocket(constants_1.ERRORS.InvalidSocks5IntiailHandshakeSocksVersion);
506 }
507 else if (data[1] === constants_1.SOCKS5_NO_ACCEPTABLE_AUTH) {
508 this.closeSocket(constants_1.ERRORS.InvalidSocks5InitialHandshakeNoAcceptedAuthType);
509 }
510 else {
511 // If selected Socks v5 auth method is no auth, send final handshake request.
512 if (data[1] === constants_1.Socks5Auth.NoAuth) {
513 this.socks5ChosenAuthType = constants_1.Socks5Auth.NoAuth;
514 this.sendSocks5CommandRequest();
515 // If selected Socks v5 auth method is user/password, send auth handshake.
516 }
517 else if (data[1] === constants_1.Socks5Auth.UserPass) {
518 this.socks5ChosenAuthType = constants_1.Socks5Auth.UserPass;
519 this.sendSocks5UserPassAuthentication();
520 // If selected Socks v5 auth method is the custom_auth_method, send custom handshake.
521 }
522 else if (data[1] === this.options.proxy.custom_auth_method) {
523 this.socks5ChosenAuthType = this.options.proxy.custom_auth_method;
524 this.sendSocks5CustomAuthentication();
525 }
526 else {
527 this.closeSocket(constants_1.ERRORS.InvalidSocks5InitialHandshakeUnknownAuthType);
528 }
529 }
530 }
531 /**
532 * Sends Socks v5 user & password auth handshake.
533 *
534 * Note: No auth and user/pass are currently supported.
535 */
536 sendSocks5UserPassAuthentication() {
537 const userId = this.options.proxy.userId || '';
538 const password = this.options.proxy.password || '';
539 const buff = new smart_buffer_1.SmartBuffer();
540 buff.writeUInt8(0x01);
541 buff.writeUInt8(Buffer.byteLength(userId));
542 buff.writeString(userId);
543 buff.writeUInt8(Buffer.byteLength(password));
544 buff.writeString(password);
545 this.nextRequiredPacketBufferSize =
546 constants_1.SOCKS_INCOMING_PACKET_SIZES.Socks5UserPassAuthenticationResponse;
547 this.socket.write(buff.toBuffer());
548 this.setState(constants_1.SocksClientState.SentAuthentication);
549 }
550 sendSocks5CustomAuthentication() {
551 return __awaiter(this, void 0, void 0, function* () {
552 this.nextRequiredPacketBufferSize = this.options.proxy.custom_auth_response_size;
553 this.socket.write(yield this.options.proxy.custom_auth_request_handler());
554 this.setState(constants_1.SocksClientState.SentAuthentication);
555 });
556 }
557 handleSocks5CustomAuthHandshakeResponse(data) {
558 return __awaiter(this, void 0, void 0, function* () {
559 return yield this.options.proxy.custom_auth_response_handler(data);
560 });
561 }
562 handleSocks5AuthenticationNoAuthHandshakeResponse(data) {
563 return __awaiter(this, void 0, void 0, function* () {
564 return data[1] === 0x00;
565 });
566 }
567 handleSocks5AuthenticationUserPassHandshakeResponse(data) {
568 return __awaiter(this, void 0, void 0, function* () {
569 return data[1] === 0x00;
570 });
571 }
572 /**
573 * Handles Socks v5 auth handshake response.
574 * @param data
575 */
576 handleInitialSocks5AuthenticationHandshakeResponse() {
577 return __awaiter(this, void 0, void 0, function* () {
578 this.setState(constants_1.SocksClientState.ReceivedAuthenticationResponse);
579 let authResult = false;
580 if (this.socks5ChosenAuthType === constants_1.Socks5Auth.NoAuth) {
581 authResult = yield this.handleSocks5AuthenticationNoAuthHandshakeResponse(this.receiveBuffer.get(2));
582 }
583 else if (this.socks5ChosenAuthType === constants_1.Socks5Auth.UserPass) {
584 authResult = yield this.handleSocks5AuthenticationUserPassHandshakeResponse(this.receiveBuffer.get(2));
585 }
586 else if (this.socks5ChosenAuthType === this.options.proxy.custom_auth_method) {
587 authResult = yield this.handleSocks5CustomAuthHandshakeResponse(this.receiveBuffer.get(this.options.proxy.custom_auth_response_size));
588 }
589 if (!authResult) {
590 this.closeSocket(constants_1.ERRORS.Socks5AuthenticationFailed);
591 }
592 else {
593 this.sendSocks5CommandRequest();
594 }
595 });
596 }
597 /**
598 * Sends Socks v5 final handshake request.
599 */
600 sendSocks5CommandRequest() {
601 const buff = new smart_buffer_1.SmartBuffer();
602 buff.writeUInt8(0x05);
603 buff.writeUInt8(constants_1.SocksCommand[this.options.command]);
604 buff.writeUInt8(0x00);
605 // ipv4, ipv6, domain?
606 if (net.isIPv4(this.options.destination.host)) {
607 buff.writeUInt8(constants_1.Socks5HostType.IPv4);
608 buff.writeBuffer(ip.toBuffer(this.options.destination.host));
609 }
610 else if (net.isIPv6(this.options.destination.host)) {
611 buff.writeUInt8(constants_1.Socks5HostType.IPv6);
612 buff.writeBuffer(ip.toBuffer(this.options.destination.host));
613 }
614 else {
615 buff.writeUInt8(constants_1.Socks5HostType.Hostname);
616 buff.writeUInt8(this.options.destination.host.length);
617 buff.writeString(this.options.destination.host);
618 }
619 buff.writeUInt16BE(this.options.destination.port);
620 this.nextRequiredPacketBufferSize =
621 constants_1.SOCKS_INCOMING_PACKET_SIZES.Socks5ResponseHeader;
622 this.socket.write(buff.toBuffer());
623 this.setState(constants_1.SocksClientState.SentFinalHandshake);
624 }
625 /**
626 * Handles Socks v5 final handshake response.
627 * @param data
628 */
629 handleSocks5FinalHandshakeResponse() {
630 // Peek at available data (we need at least 5 bytes to get the hostname length)
631 const header = this.receiveBuffer.peek(5);
632 if (header[0] !== 0x05 || header[1] !== constants_1.Socks5Response.Granted) {
633 this.closeSocket(`${constants_1.ERRORS.InvalidSocks5FinalHandshakeRejected} - ${constants_1.Socks5Response[header[1]]}`);
634 }
635 else {
636 // Read address type
637 const addressType = header[3];
638 let remoteHost;
639 let buff;
640 // IPv4
641 if (addressType === constants_1.Socks5HostType.IPv4) {
642 // Check if data is available.
643 const dataNeeded = constants_1.SOCKS_INCOMING_PACKET_SIZES.Socks5ResponseIPv4;
644 if (this.receiveBuffer.length < dataNeeded) {
645 this.nextRequiredPacketBufferSize = dataNeeded;
646 return;
647 }
648 buff = smart_buffer_1.SmartBuffer.fromBuffer(this.receiveBuffer.get(dataNeeded).slice(4));
649 remoteHost = {
650 host: ip.fromLong(buff.readUInt32BE()),
651 port: buff.readUInt16BE(),
652 };
653 // If given host is 0.0.0.0, assume remote proxy ip instead.
654 if (remoteHost.host === '0.0.0.0') {
655 remoteHost.host = this.options.proxy.ipaddress;
656 }
657 // Hostname
658 }
659 else if (addressType === constants_1.Socks5HostType.Hostname) {
660 const hostLength = header[4];
661 const dataNeeded = constants_1.SOCKS_INCOMING_PACKET_SIZES.Socks5ResponseHostname(hostLength); // header + host length + host + port
662 // Check if data is available.
663 if (this.receiveBuffer.length < dataNeeded) {
664 this.nextRequiredPacketBufferSize = dataNeeded;
665 return;
666 }
667 buff = smart_buffer_1.SmartBuffer.fromBuffer(this.receiveBuffer.get(dataNeeded).slice(5));
668 remoteHost = {
669 host: buff.readString(hostLength),
670 port: buff.readUInt16BE(),
671 };
672 // IPv6
673 }
674 else if (addressType === constants_1.Socks5HostType.IPv6) {
675 // Check if data is available.
676 const dataNeeded = constants_1.SOCKS_INCOMING_PACKET_SIZES.Socks5ResponseIPv6;
677 if (this.receiveBuffer.length < dataNeeded) {
678 this.nextRequiredPacketBufferSize = dataNeeded;
679 return;
680 }
681 buff = smart_buffer_1.SmartBuffer.fromBuffer(this.receiveBuffer.get(dataNeeded).slice(4));
682 remoteHost = {
683 host: ip.toString(buff.readBuffer(16)),
684 port: buff.readUInt16BE(),
685 };
686 }
687 // We have everything we need
688 this.setState(constants_1.SocksClientState.ReceivedFinalResponse);
689 // If using CONNECT, the client is now in the established state.
690 if (constants_1.SocksCommand[this.options.command] === constants_1.SocksCommand.connect) {
691 this.setState(constants_1.SocksClientState.Established);
692 this.removeInternalSocketHandlers();
693 this.emit('established', { remoteHost, socket: this.socket });
694 }
695 else if (constants_1.SocksCommand[this.options.command] === constants_1.SocksCommand.bind) {
696 /* If using BIND, the Socks client is now in BoundWaitingForConnection state.
697 This means that the remote proxy server is waiting for a remote connection to the bound port. */
698 this.setState(constants_1.SocksClientState.BoundWaitingForConnection);
699 this.nextRequiredPacketBufferSize =
700 constants_1.SOCKS_INCOMING_PACKET_SIZES.Socks5ResponseHeader;
701 this.emit('bound', { remoteHost, socket: this.socket });
702 /*
703 If using Associate, the Socks client is now Established. And the proxy server is now accepting UDP packets at the
704 given bound port. This initial Socks TCP connection must remain open for the UDP relay to continue to work.
705 */
706 }
707 else if (constants_1.SocksCommand[this.options.command] === constants_1.SocksCommand.associate) {
708 this.setState(constants_1.SocksClientState.Established);
709 this.removeInternalSocketHandlers();
710 this.emit('established', {
711 remoteHost,
712 socket: this.socket,
713 });
714 }
715 }
716 }
717 /**
718 * Handles Socks v5 incoming connection request (BIND).
719 */
720 handleSocks5IncomingConnectionResponse() {
721 // Peek at available data (we need at least 5 bytes to get the hostname length)
722 const header = this.receiveBuffer.peek(5);
723 if (header[0] !== 0x05 || header[1] !== constants_1.Socks5Response.Granted) {
724 this.closeSocket(`${constants_1.ERRORS.Socks5ProxyRejectedIncomingBoundConnection} - ${constants_1.Socks5Response[header[1]]}`);
725 }
726 else {
727 // Read address type
728 const addressType = header[3];
729 let remoteHost;
730 let buff;
731 // IPv4
732 if (addressType === constants_1.Socks5HostType.IPv4) {
733 // Check if data is available.
734 const dataNeeded = constants_1.SOCKS_INCOMING_PACKET_SIZES.Socks5ResponseIPv4;
735 if (this.receiveBuffer.length < dataNeeded) {
736 this.nextRequiredPacketBufferSize = dataNeeded;
737 return;
738 }
739 buff = smart_buffer_1.SmartBuffer.fromBuffer(this.receiveBuffer.get(dataNeeded).slice(4));
740 remoteHost = {
741 host: ip.fromLong(buff.readUInt32BE()),
742 port: buff.readUInt16BE(),
743 };
744 // If given host is 0.0.0.0, assume remote proxy ip instead.
745 if (remoteHost.host === '0.0.0.0') {
746 remoteHost.host = this.options.proxy.ipaddress;
747 }
748 // Hostname
749 }
750 else if (addressType === constants_1.Socks5HostType.Hostname) {
751 const hostLength = header[4];
752 const dataNeeded = constants_1.SOCKS_INCOMING_PACKET_SIZES.Socks5ResponseHostname(hostLength); // header + host length + port
753 // Check if data is available.
754 if (this.receiveBuffer.length < dataNeeded) {
755 this.nextRequiredPacketBufferSize = dataNeeded;
756 return;
757 }
758 buff = smart_buffer_1.SmartBuffer.fromBuffer(this.receiveBuffer.get(dataNeeded).slice(5));
759 remoteHost = {
760 host: buff.readString(hostLength),
761 port: buff.readUInt16BE(),
762 };
763 // IPv6
764 }
765 else if (addressType === constants_1.Socks5HostType.IPv6) {
766 // Check if data is available.
767 const dataNeeded = constants_1.SOCKS_INCOMING_PACKET_SIZES.Socks5ResponseIPv6;
768 if (this.receiveBuffer.length < dataNeeded) {
769 this.nextRequiredPacketBufferSize = dataNeeded;
770 return;
771 }
772 buff = smart_buffer_1.SmartBuffer.fromBuffer(this.receiveBuffer.get(dataNeeded).slice(4));
773 remoteHost = {
774 host: ip.toString(buff.readBuffer(16)),
775 port: buff.readUInt16BE(),
776 };
777 }
778 this.setState(constants_1.SocksClientState.Established);
779 this.removeInternalSocketHandlers();
780 this.emit('established', { remoteHost, socket: this.socket });
781 }
782 }
783 get socksClientOptions() {
784 return Object.assign({}, this.options);
785 }
786}
787exports.SocksClient = SocksClient;
788//# sourceMappingURL=socksclient.js.map
Note: See TracBrowser for help on using the repository browser.