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