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