README.md
1 # socks [](https://travis-ci.org/JoshGlazebrook/socks) [](https://coveralls.io/github/JoshGlazebrook/socks?branch=v2) 2 3 Fully featured SOCKS proxy client supporting SOCKSv4, SOCKSv4a, and SOCKSv5. Includes Bind and Associate functionality. 4 5 ### Features 6 7 * Supports SOCKS v4, v4a, v5, and v5h protocols. 8 * Supports the CONNECT, BIND, and ASSOCIATE commands. 9 * Supports callbacks, promises, and events for proxy connection creation async flow control. 10 * Supports proxy chaining (CONNECT only). 11 * Supports user/password authentication. 12 * Supports custom authentication. 13 * Built in UDP frame creation & parse functions. 14 * Created with TypeScript, type definitions are provided. 15 16 ### Requirements 17 18 * Node.js v10.0+ (Please use [v1](https://github.com/JoshGlazebrook/socks/tree/82d83923ad960693d8b774cafe17443ded7ed584) for older versions of Node.js) 19 20 ### Looking for v1? 21 * Docs for v1 are available [here](https://github.com/JoshGlazebrook/socks/tree/82d83923ad960693d8b774cafe17443ded7ed584) 22 23 ## Installation 24 25 `yarn add socks` 26 27 or 28 29 `npm install --save socks` 30 31 ## Usage 32 33 ```typescript 34 // TypeScript 35 import { SocksClient, SocksClientOptions, SocksClientChainOptions } from 'socks'; 36 37 // ES6 JavaScript 38 import { SocksClient } from 'socks'; 39 40 // Legacy JavaScript 41 const SocksClient = require('socks').SocksClient; 42 ``` 43 44 ## Quick Start Example 45 46 Connect to github.com (192.30.253.113) on port 80, using a SOCKS proxy. 47 48 ```javascript 49 const options = { 50 proxy: { 51 host: '159.203.75.200', // ipv4 or ipv6 or hostname 52 port: 1080, 53 type: 5 // Proxy version (4 or 5) 54 }, 55 56 command: 'connect', // SOCKS command (createConnection factory function only supports the connect command) 57 58 destination: { 59 host: '192.30.253.113', // github.com (hostname lookups are supported with SOCKS v4a and 5) 60 port: 80 61 } 62 }; 63 64 // Async/Await 65 try { 66 const info = await SocksClient.createConnection(options); 67 68 console.log(info.socket); 69 // <Socket ...> (this is a raw net.Socket that is established to the destination host through the given proxy server) 70 } catch (err) { 71 // Handle errors 72 } 73 74 // Promises 75 SocksClient.createConnection(options) 76 .then(info => { 77 console.log(info.socket); 78 // <Socket ...> (this is a raw net.Socket that is established to the destination host through the given proxy server) 79 }) 80 .catch(err => { 81 // Handle errors 82 }); 83 84 // Callbacks 85 SocksClient.createConnection(options, (err, info) => { 86 if (!err) { 87 console.log(info.socket); 88 // <Socket ...> (this is a raw net.Socket that is established to the destination host through the given proxy server) 89 } else { 90 // Handle errors 91 } 92 }); 93 ``` 94 95 ## Chaining Proxies 96 97 **Note:** Chaining is only supported when using the SOCKS connect command, and chaining can only be done through the special factory chaining function. 98 99 This example makes a proxy chain through two SOCKS proxies to ip-api.com. Once the connection to the destination is established it sends an HTTP request to get a JSON response that returns ip info for the requesting ip. 100 101 ```javascript 102 const options = { 103 destination: { 104 host: 'ip-api.com', // host names are supported with SOCKS v4a and SOCKS v5. 105 port: 80 106 }, 107 command: 'connect', // Only the connect command is supported when chaining proxies. 108 proxies: [ // The chain order is the order in the proxies array, meaning the last proxy will establish a connection to the destination. 109 { 110 host: '159.203.75.235', // ipv4, ipv6, or hostname 111 port: 1081, 112 type: 5 113 }, 114 { 115 host: '104.131.124.203', // ipv4, ipv6, or hostname 116 port: 1081, 117 type: 5 118 } 119 ] 120 } 121 122 // Async/Await 123 try { 124 const info = await SocksClient.createConnectionChain(options); 125 126 console.log(info.socket); 127 // <Socket ...> (this is a raw net.Socket that is established to the destination host through the given proxy servers) 128 129 console.log(info.socket.remoteAddress) // The remote address of the returned socket is the first proxy in the chain. 130 // 159.203.75.235 131 132 info.socket.write('GET /json HTTP/1.1\nHost: ip-api.com\n\n'); 133 info.socket.on('data', (data) => { 134 console.log(data.toString()); // ip-api.com sees that the last proxy in the chain (104.131.124.203) is connected to it. 135 /* 136 HTTP/1.1 200 OK 137 Access-Control-Allow-Origin: * 138 Content-Type: application/json; charset=utf-8 139 Date: Sun, 24 Dec 2017 03:47:51 GMT 140 Content-Length: 300 141 142 { 143 "as":"AS14061 Digital Ocean, Inc.", 144 "city":"Clifton", 145 "country":"United States", 146 "countryCode":"US", 147 "isp":"Digital Ocean", 148 "lat":40.8326, 149 "lon":-74.1307, 150 "org":"Digital Ocean", 151 "query":"104.131.124.203", 152 "region":"NJ", 153 "regionName":"New Jersey", 154 "status":"success", 155 "timezone":"America/New_York", 156 "zip":"07014" 157 } 158 */ 159 }); 160 } catch (err) { 161 // Handle errors 162 } 163 164 // Promises 165 SocksClient.createConnectionChain(options) 166 .then(info => { 167 console.log(info.socket); 168 // <Socket ...> (this is a raw net.Socket that is established to the destination host through the given proxy server) 169 170 console.log(info.socket.remoteAddress) // The remote address of the returned socket is the first proxy in the chain. 171 // 159.203.75.235 172 173 info.socket.write('GET /json HTTP/1.1\nHost: ip-api.com\n\n'); 174 info.socket.on('data', (data) => { 175 console.log(data.toString()); // ip-api.com sees that the last proxy in the chain (104.131.124.203) is connected to it. 176 /* 177 HTTP/1.1 200 OK 178 Access-Control-Allow-Origin: * 179 Content-Type: application/json; charset=utf-8 180 Date: Sun, 24 Dec 2017 03:47:51 GMT 181 Content-Length: 300 182 183 { 184 "as":"AS14061 Digital Ocean, Inc.", 185 "city":"Clifton", 186 "country":"United States", 187 "countryCode":"US", 188 "isp":"Digital Ocean", 189 "lat":40.8326, 190 "lon":-74.1307, 191 "org":"Digital Ocean", 192 "query":"104.131.124.203", 193 "region":"NJ", 194 "regionName":"New Jersey", 195 "status":"success", 196 "timezone":"America/New_York", 197 "zip":"07014" 198 } 199 */ 200 }); 201 }) 202 .catch(err => { 203 // Handle errors 204 }); 205 206 // Callbacks 207 SocksClient.createConnectionChain(options, (err, info) => { 208 if (!err) { 209 console.log(info.socket); 210 // <Socket ...> (this is a raw net.Socket that is established to the destination host through the given proxy server) 211 212 console.log(info.socket.remoteAddress) // The remote address of the returned socket is the first proxy in the chain. 213 // 159.203.75.235 214 215 info.socket.write('GET /json HTTP/1.1\nHost: ip-api.com\n\n'); 216 info.socket.on('data', (data) => { 217 console.log(data.toString()); // ip-api.com sees that the last proxy in the chain (104.131.124.203) is connected to it. 218 /* 219 HTTP/1.1 200 OK 220 Access-Control-Allow-Origin: * 221 Content-Type: application/json; charset=utf-8 222 Date: Sun, 24 Dec 2017 03:47:51 GMT 223 Content-Length: 300 224 225 { 226 "as":"AS14061 Digital Ocean, Inc.", 227 "city":"Clifton", 228 "country":"United States", 229 "countryCode":"US", 230 "isp":"Digital Ocean", 231 "lat":40.8326, 232 "lon":-74.1307, 233 "org":"Digital Ocean", 234 "query":"104.131.124.203", 235 "region":"NJ", 236 "regionName":"New Jersey", 237 "status":"success", 238 "timezone":"America/New_York", 239 "zip":"07014" 240 } 241 */ 242 }); 243 } else { 244 // Handle errors 245 } 246 }); 247 ``` 248 249 ## Bind Example (TCP Relay) 250 251 When the bind command is sent to a SOCKS v4/v5 proxy server, the proxy server starts listening on a new TCP port and the proxy relays then remote host information back to the client. When another remote client connects to the proxy server on this port the SOCKS proxy sends a notification that an incoming connection has been accepted to the initial client and a full duplex stream is now established to the initial client and the client that connected to that special port. 252 253 ```javascript 254 const options = { 255 proxy: { 256 host: '159.203.75.235', // ipv4, ipv6, or hostname 257 port: 1081, 258 type: 5 259 }, 260 261 command: 'bind', 262 263 // When using BIND, the destination should be the remote client that is expected to connect to the SOCKS proxy. Using 0.0.0.0 makes the Proxy accept any incoming connection on that port. 264 destination: { 265 host: '0.0.0.0', 266 port: 0 267 } 268 }; 269 270 // Creates a new SocksClient instance. 271 const client = new SocksClient(options); 272 273 // When the SOCKS proxy has bound a new port and started listening, this event is fired. 274 client.on('bound', info => { 275 console.log(info.remoteHost); 276 /* 277 { 278 host: "159.203.75.235", 279 port: 57362 280 } 281 */ 282 }); 283 284 // When a client connects to the newly bound port on the SOCKS proxy, this event is fired. 285 client.on('established', info => { 286 // info.remoteHost is the remote address of the client that connected to the SOCKS proxy. 287 console.log(info.remoteHost); 288 /* 289 host: 67.171.34.23, 290 port: 49823 291 */ 292 293 console.log(info.socket); 294 // <Socket ...> (This is a raw net.Socket that is a connection between the initial client and the remote client that connected to the proxy) 295 296 // Handle received data... 297 info.socket.on('data', data => { 298 console.log('recv', data); 299 }); 300 }); 301 302 // An error occurred trying to establish this SOCKS connection. 303 client.on('error', err => { 304 console.error(err); 305 }); 306 307 // Start connection to proxy 308 client.connect(); 309 ``` 310 311 ## Associate Example (UDP Relay) 312 313 When the associate command is sent to a SOCKS v5 proxy server, it sets up a UDP relay that allows the client to send UDP packets to a remote host through the proxy server, and also receive UDP packet responses back through the proxy server. 314 315 ```javascript 316 const options = { 317 proxy: { 318 host: '159.203.75.235', // ipv4, ipv6, or hostname 319 port: 1081, 320 type: 5 321 }, 322 323 command: 'associate', 324 325 // When using associate, the destination should be the remote client that is expected to send UDP packets to the proxy server to be forwarded. This should be your local ip, or optionally the wildcard address (0.0.0.0) UDP Client <-> Proxy <-> UDP Client 326 destination: { 327 host: '0.0.0.0', 328 port: 0 329 } 330 }; 331 332 // Create a local UDP socket for sending packets to the proxy. 333 const udpSocket = dgram.createSocket('udp4'); 334 udpSocket.bind(); 335 336 // Listen for incoming UDP packets from the proxy server. 337 udpSocket.on('message', (message, rinfo) => { 338 console.log(SocksClient.parseUDPFrame(message)); 339 /* 340 { frameNumber: 0, 341 remoteHost: { host: '165.227.108.231', port: 4444 }, // The remote host that replied with a UDP packet 342 data: <Buffer 74 65 73 74 0a> // The data 343 } 344 */ 345 }); 346 347 let client = new SocksClient(associateOptions); 348 349 // When the UDP relay is established, this event is fired and includes the UDP relay port to send data to on the proxy server. 350 client.on('established', info => { 351 console.log(info.remoteHost); 352 /* 353 { 354 host: '159.203.75.235', 355 port: 44711 356 } 357 */ 358 359 // Send 'hello' to 165.227.108.231:4444 360 const packet = SocksClient.createUDPFrame({ 361 remoteHost: { host: '165.227.108.231', port: 4444 }, 362 data: Buffer.from(line) 363 }); 364 udpSocket.send(packet, info.remoteHost.port, info.remoteHost.host); 365 }); 366 367 // Start connection 368 client.connect(); 369 ``` 370 371 **Note:** The associate TCP connection to the proxy must remain open for the UDP relay to work. 372 373 ## Additional Examples 374 375 [Documentation](docs/index.md) 376 377 378 ## Migrating from v1 379 380 Looking for a guide to migrate from v1? Look [here](docs/migratingFromV1.md) 381 382 ## Api Reference: 383 384 **Note:** socks includes full TypeScript definitions. These can even be used without using TypeScript as most IDEs (such as VS Code) will use these type definition files for auto completion intellisense even in JavaScript files. 385 386 * Class: SocksClient 387 * [new SocksClient(options[, callback])](#new-socksclientoptions) 388 * [Class Method: SocksClient.createConnection(options[, callback])](#class-method-socksclientcreateconnectionoptions-callback) 389 * [Class Method: SocksClient.createConnectionChain(options[, callback])](#class-method-socksclientcreateconnectionchainoptions-callback) 390 * [Class Method: SocksClient.createUDPFrame(options)](#class-method-socksclientcreateudpframedetails) 391 * [Class Method: SocksClient.parseUDPFrame(data)](#class-method-socksclientparseudpframedata) 392 * [Event: 'error'](#event-error) 393 * [Event: 'bound'](#event-bound) 394 * [Event: 'established'](#event-established) 395 * [client.connect()](#clientconnect) 396 * [client.socksClientOptions](#clientconnect) 397 398 ### SocksClient 399 400 SocksClient establishes SOCKS proxy connections to remote destination hosts. These proxy connections are fully transparent to the server and once established act as full duplex streams. SOCKS v4, v4a, v5, and v5h are supported, as well as the connect, bind, and associate commands. 401 402 SocksClient supports creating connections using callbacks, promises, and async/await flow control using two static factory functions createConnection and createConnectionChain. It also internally extends EventEmitter which results in allowing event handling based async flow control. 403 404 **SOCKS Compatibility Table** 405 406 Note: When using 4a please specify type: 4, and when using 5h please specify type 5. 407 408 | Socks Version | TCP | UDP | IPv4 | IPv6 | Hostname | 409 | --- | :---: | :---: | :---: | :---: | :---: | 410 | SOCKS v4 | ✅ | ❌ | ✅ | ❌ | ❌ | 411 | SOCKS v4a | ✅ | ❌ | ✅ | ❌ | ✅ | 412 | SOCKS v5 (includes v5h) | ✅ | ✅ | ✅ | ✅ | ✅ | 413 414 ### new SocksClient(options) 415 416 * ```options``` {SocksClientOptions} - An object describing the SOCKS proxy to use, the command to send and establish, and the destination host to connect to. 417 418 ### SocksClientOptions 419 420 ```typescript 421 { 422 proxy: { 423 host: '159.203.75.200', // ipv4, ipv6, or hostname 424 port: 1080, 425 type: 5 // Proxy version (4 or 5). For v4a use 4, for v5h use 5. 426 427 // Optional fields 428 userId: 'some username', // Used for SOCKS4 userId auth, and SOCKS5 user/pass auth in conjunction with password. 429 password: 'some password', // Used in conjunction with userId for user/pass auth for SOCKS5 proxies. 430 custom_auth_method: 0x80, // If using a custom auth method, specify the type here. If this is set, ALL other custom_auth_*** options must be set as well. 431 custom_auth_request_handler: async () =>. { 432 // This will be called when it's time to send the custom auth handshake. You must return a Buffer containing the data to send as your authentication. 433 return Buffer.from([0x01,0x02,0x03]); 434 }, 435 // This is the expected size (bytes) of the custom auth response from the proxy server. 436 custom_auth_response_size: 2, 437 // This is called when the auth response is received. The received packet is passed in as a Buffer, and you must return a boolean indicating the response from the server said your custom auth was successful or failed. 438 custom_auth_response_handler: async (data) => { 439 return data[1] === 0x00; 440 } 441 }, 442 443 command: 'connect', // connect, bind, associate 444 445 destination: { 446 host: '192.30.253.113', // ipv4, ipv6, hostname. Hostnames work with v4a and v5. 447 port: 80 448 }, 449 450 // Optional fields 451 timeout: 30000, // How long to wait to establish a proxy connection. (defaults to 30 seconds) 452 453 set_tcp_nodelay: true // If true, will turn on the underlying sockets TCP_NODELAY option. 454 } 455 ``` 456 457 ### Class Method: SocksClient.createConnection(options[, callback]) 458 * ```options``` { SocksClientOptions } - An object describing the SOCKS proxy to use, the command to send and establish, and the destination host to connect to. 459 * ```callback``` { Function } - Optional callback function that is called when the proxy connection is established, or an error occurs. 460 * ```returns``` { Promise } - A Promise is returned that is resolved when the proxy connection is established, or rejected when an error occurs. 461 462 Creates a new proxy connection through the given proxy to the given destination host. This factory function supports callbacks and promises for async flow control. 463 464 **Note:** If a callback function is provided, the promise will always resolve regardless of an error occurring. Please be sure to exclusively use either promises or callbacks when using this factory function. 465 466 ```typescript 467 const options = { 468 proxy: { 469 host: '159.203.75.200', // ipv4, ipv6, or hostname 470 port: 1080, 471 type: 5 // Proxy version (4 or 5) 472 }, 473 474 command: 'connect', // connect, bind, associate 475 476 destination: { 477 host: '192.30.253.113', // ipv4, ipv6, or hostname 478 port: 80 479 } 480 } 481 482 // Await/Async (uses a Promise) 483 try { 484 const info = await SocksClient.createConnection(options); 485 console.log(info); 486 /* 487 { 488 socket: <Socket ...>, // Raw net.Socket 489 } 490 */ 491 / <Socket ...> (this is a raw net.Socket that is established to the destination host through the given proxy server) 492 493 } catch (err) { 494 // Handle error... 495 } 496 497 // Promise 498 SocksClient.createConnection(options) 499 .then(info => { 500 console.log(info); 501 /* 502 { 503 socket: <Socket ...>, // Raw net.Socket 504 } 505 */ 506 }) 507 .catch(err => { 508 // Handle error... 509 }); 510 511 // Callback 512 SocksClient.createConnection(options, (err, info) => { 513 if (!err) { 514 console.log(info); 515 /* 516 { 517 socket: <Socket ...>, // Raw net.Socket 518 } 519 */ 520 } else { 521 // Handle error... 522 } 523 }); 524 ``` 525 526 ### Class Method: SocksClient.createConnectionChain(options[, callback]) 527 * ```options``` { SocksClientChainOptions } - An object describing a list of SOCKS proxies to use, the command to send and establish, and the destination host to connect to. 528 * ```callback``` { Function } - Optional callback function that is called when the proxy connection chain is established, or an error occurs. 529 * ```returns``` { Promise } - A Promise is returned that is resolved when the proxy connection chain is established, or rejected when an error occurs. 530 531 Creates a new proxy connection chain through a list of at least two SOCKS proxies to the given destination host. This factory method supports callbacks and promises for async flow control. 532 533 **Note:** If a callback function is provided, the promise will always resolve regardless of an error occurring. Please be sure to exclusively use either promises or callbacks when using this factory function. 534 535 **Note:** At least two proxies must be provided for the chain to be established. 536 537 ```typescript 538 const options = { 539 proxies: [ // The chain order is the order in the proxies array, meaning the last proxy will establish a connection to the destination. 540 { 541 host: '159.203.75.235', // ipv4, ipv6, or hostname 542 port: 1081, 543 type: 5 544 }, 545 { 546 host: '104.131.124.203', // ipv4, ipv6, or hostname 547 port: 1081, 548 type: 5 549 } 550 ] 551 552 command: 'connect', // Only connect is supported in chaining mode. 553 554 destination: { 555 host: '192.30.253.113', // ipv4, ipv6, hostname 556 port: 80 557 } 558 } 559 ``` 560 561 ### Class Method: SocksClient.createUDPFrame(details) 562 * ```details``` { SocksUDPFrameDetails } - An object containing the remote host, frame number, and frame data to use when creating a SOCKS UDP frame packet. 563 * ```returns``` { Buffer } - A Buffer containing all of the UDP frame data. 564 565 Creates a SOCKS UDP frame relay packet that is sent and received via a SOCKS proxy when using the associate command for UDP packet forwarding. 566 567 **SocksUDPFrameDetails** 568 569 ```typescript 570 { 571 frameNumber: 0, // The frame number (used for breaking up larger packets) 572 573 remoteHost: { // The remote host to have the proxy send data to, or the remote host that send this data. 574 host: '1.2.3.4', 575 port: 1234 576 }, 577 578 data: <Buffer 01 02 03 04...> // A Buffer instance of data to include in the packet (actual data sent to the remote host) 579 } 580 interface SocksUDPFrameDetails { 581 // The frame number of the packet. 582 frameNumber?: number; 583 584 // The remote host. 585 remoteHost: SocksRemoteHost; 586 587 // The packet data. 588 data: Buffer; 589 } 590 ``` 591 592 ### Class Method: SocksClient.parseUDPFrame(data) 593 * ```data``` { Buffer } - A Buffer instance containing SOCKS UDP frame data to parse. 594 * ```returns``` { SocksUDPFrameDetails } - An object containing the remote host, frame number, and frame data of the SOCKS UDP frame. 595 596 ```typescript 597 const frame = SocksClient.parseUDPFrame(data); 598 console.log(frame); 599 /* 600 { 601 frameNumber: 0, 602 remoteHost: { 603 host: '1.2.3.4', 604 port: 1234 605 }, 606 data: <Buffer 01 02 03 04 ...> 607 } 608 */ 609 ``` 610 611 Parses a Buffer instance and returns the parsed SocksUDPFrameDetails object. 612 613 ## Event: 'error' 614 * ```err``` { SocksClientError } - An Error object containing an error message and the original SocksClientOptions. 615 616 This event is emitted if an error occurs when trying to establish the proxy connection. 617 618 ## Event: 'bound' 619 * ```info``` { SocksClientBoundEvent } An object containing a Socket and SocksRemoteHost info. 620 621 This event is emitted when using the BIND command on a remote SOCKS proxy server. This event indicates the proxy server is now listening for incoming connections on a specified port. 622 623 **SocksClientBoundEvent** 624 ```typescript 625 { 626 socket: net.Socket, // The underlying raw Socket 627 remoteHost: { 628 host: '1.2.3.4', // The remote host that is listening (usually the proxy itself) 629 port: 4444 // The remote port the proxy is listening on for incoming connections (when using BIND). 630 } 631 } 632 ``` 633 634 ## Event: 'established' 635 * ```info``` { SocksClientEstablishedEvent } An object containing a Socket and SocksRemoteHost info. 636 637 This event is emitted when the following conditions are met: 638 1. When using the CONNECT command, and a proxy connection has been established to the remote host. 639 2. When using the BIND command, and an incoming connection has been accepted by the proxy and a TCP relay has been established. 640 3. When using the ASSOCIATE command, and a UDP relay has been established. 641 642 When using BIND, 'bound' is first emitted to indicate the SOCKS server is waiting for an incoming connection, and provides the remote port the SOCKS server is listening on. 643 644 When using ASSOCIATE, 'established' is emitted with the remote UDP port the SOCKS server is accepting UDP frame packets on. 645 646 **SocksClientEstablishedEvent** 647 ```typescript 648 { 649 socket: net.Socket, // The underlying raw Socket 650 remoteHost: { 651 host: '1.2.3.4', // The remote host that is listening (usually the proxy itself) 652 port: 52738 // The remote port the proxy is listening on for incoming connections (when using BIND). 653 } 654 } 655 ``` 656 657 ## client.connect() 658 659 Starts connecting to the remote SOCKS proxy server to establish a proxy connection to the destination host. 660 661 ## client.socksClientOptions 662 * ```returns``` { SocksClientOptions } The options that were passed to the SocksClient. 663 664 Gets the options that were passed to the SocksClient when it was created. 665 666 667 **SocksClientError** 668 ```typescript 669 { // Subclassed from Error. 670 message: 'An error has occurred', 671 options: { 672 // SocksClientOptions 673 } 674 } 675 ``` 676 677 # Further Reading: 678 679 Please read the SOCKS 5 specifications for more information on how to use BIND and Associate. 680 http://www.ietf.org/rfc/rfc1928.txt 681 682 # License 683 684 This work is licensed under the [MIT license](http://en.wikipedia.org/wiki/MIT_License).