README.md
  1  # socks  [![Build Status](https://travis-ci.org/JoshGlazebrook/socks.svg?branch=master)](https://travis-ci.org/JoshGlazebrook/socks)  [![Coverage Status](https://coveralls.io/repos/github/JoshGlazebrook/socks/badge.svg?branch=master)](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).