Skip to content

Commit

Permalink
remove ip package (#94)
Browse files Browse the repository at this point in the history
* remove ip package
  • Loading branch information
JoshGlazebrook committed Feb 12, 2024
1 parent 76d013e commit 66b7f73
Show file tree
Hide file tree
Showing 12 changed files with 1,666 additions and 1,100 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/nodejs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [14.x, 16.x, 18.x]
node-version: [16.x, 18.x, 20.x]
# See supported Node.js release schedule at https://nodejs.org/en/about/releases/
steps:
- uses: actions/checkout@v3
Expand Down
2,553 changes: 1,534 additions & 1,019 deletions package-lock.json

Large diffs are not rendered by default.

22 changes: 11 additions & 11 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "socks",
"private": false,
"version": "2.7.1",
"version": "2.7.3",
"description": "Fully featured SOCKS proxy client supporting SOCKSv4, SOCKSv4a, and SOCKSv5. Includes Bind and Associate functionality.",
"main": "build/index.js",
"typings": "typings/index.d.ts",
Expand All @@ -23,7 +23,7 @@
"socks5"
],
"engines": {
"node": ">= 10.13.0",
"node": ">= 10.0.0",
"npm": ">= 3.0.0"
},
"author": "Josh Glazebrook",
Expand All @@ -33,26 +33,26 @@
"license": "MIT",
"readmeFilename": "README.md",
"devDependencies": {
"@types/ip": "1.1.0",
"@types/mocha": "^9.1.1",
"@types/node": "^18.0.6",
"@typescript-eslint/eslint-plugin": "^5.30.6",
"@typescript-eslint/parser": "^5.30.6",
"@types/mocha": "^10.0.6",
"@types/node": "^20.11.17",
"@typescript-eslint/eslint-plugin": "^6.21.0",
"@typescript-eslint/parser": "^6.21.0",
"eslint": "^8.20.0",
"mocha": "^10.0.0",
"prettier": "^2.7.1",
"prettier": "^3.2.5",
"ts-node": "^10.9.1",
"typescript": "^4.7.4"
"typescript": "^5.3.3"
},
"dependencies": {
"ip": "^2.0.0",
"ip-address": "^9.0.5",
"smart-buffer": "^4.2.0"
},
"scripts": {
"prepublish": "npm install -g typescript && npm run build",
"test": "NODE_ENV=test mocha --recursive --require ts-node/register test/**/*.ts",
"prettier": "prettier --write ./src/**/*.ts --config .prettierrc.yaml",
"lint": "eslint 'src/**/*.ts'",
"build": "rm -rf build typings && prettier --write ./src/**/*.ts --config .prettierrc.yaml && tsc -p ."
"build": "rm -rf build typings && prettier --write ./src/**/*.ts --config .prettierrc.yaml && tsc -p .",
"build-raw": "rm -rf build typings && tsc -p ."
}
}
37 changes: 23 additions & 14 deletions src/client/socksclient.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import {EventEmitter} from 'events';
import * as net from 'net';
import * as ip from 'ip';
import {SmartBuffer} from 'smart-buffer';
import {
DEFAULT_TIMEOUT,
Expand All @@ -24,10 +23,14 @@ import {
import {
validateSocksClientOptions,
validateSocksClientChainOptions,
ipv4ToInt32,
ipToBuffer,
int32ToIpv4,
} from '../common/helpers';
import {ReceiveBuffer} from '../common/receivebuffer';
import {SocksClientError, shuffleArray} from '../common/util';
import {Duplex} from 'stream';
import {Address6} from 'ip-address';

// Exposes SocksClient event types
declare interface SocksClient {
Expand Down Expand Up @@ -231,10 +234,10 @@ class SocksClient extends EventEmitter implements SocksClient {
// IPv4/IPv6/Hostname
if (net.isIPv4(options.remoteHost.host)) {
buff.writeUInt8(Socks5HostType.IPv4);
buff.writeUInt32BE(ip.toLong(options.remoteHost.host));
buff.writeUInt32BE(ipv4ToInt32(options.remoteHost.host));
} else if (net.isIPv6(options.remoteHost.host)) {
buff.writeUInt8(Socks5HostType.IPv6);
buff.writeBuffer(ip.toBuffer(options.remoteHost.host));
buff.writeBuffer(ipToBuffer(options.remoteHost.host));
} else {
buff.writeUInt8(Socks5HostType.Hostname);
buff.writeUInt8(Buffer.byteLength(options.remoteHost.host));
Expand Down Expand Up @@ -263,9 +266,11 @@ class SocksClient extends EventEmitter implements SocksClient {
let remoteHost;

if (hostType === Socks5HostType.IPv4) {
remoteHost = ip.fromLong(buff.readUInt32BE());
remoteHost = int32ToIpv4(buff.readUInt32BE());
} else if (hostType === Socks5HostType.IPv6) {
remoteHost = ip.toString(buff.readBuffer(16));
remoteHost = Address6.fromByteArray(
Array.from(buff.readBuffer(16)),
).canonicalForm();
} else {
remoteHost = buff.readString(buff.readUInt8());
}
Expand Down Expand Up @@ -508,7 +513,7 @@ class SocksClient extends EventEmitter implements SocksClient {

// Socks 4 (IPv4)
if (net.isIPv4(this.options.destination.host)) {
buff.writeBuffer(ip.toBuffer(this.options.destination.host));
buff.writeBuffer(ipToBuffer(this.options.destination.host));
buff.writeStringNT(userId);
// Socks 4a (hostname)
} else {
Expand Down Expand Up @@ -546,7 +551,7 @@ class SocksClient extends EventEmitter implements SocksClient {

const remoteHost: SocksRemoteHost = {
port: buff.readUInt16BE(),
host: ip.fromLong(buff.readUInt32BE()),
host: int32ToIpv4(buff.readUInt32BE()),
};

// If host is 0.0.0.0, set to proxy host.
Expand Down Expand Up @@ -584,7 +589,7 @@ class SocksClient extends EventEmitter implements SocksClient {

const remoteHost: SocksRemoteHost = {
port: buff.readUInt16BE(),
host: ip.fromLong(buff.readUInt32BE()),
host: int32ToIpv4(buff.readUInt32BE()),
};

this.setState(SocksClientState.Established);
Expand Down Expand Up @@ -747,10 +752,10 @@ class SocksClient extends EventEmitter implements SocksClient {
// ipv4, ipv6, domain?
if (net.isIPv4(this.options.destination.host)) {
buff.writeUInt8(Socks5HostType.IPv4);
buff.writeBuffer(ip.toBuffer(this.options.destination.host));
buff.writeBuffer(ipToBuffer(this.options.destination.host));
} else if (net.isIPv6(this.options.destination.host)) {
buff.writeUInt8(Socks5HostType.IPv6);
buff.writeBuffer(ip.toBuffer(this.options.destination.host));
buff.writeBuffer(ipToBuffer(this.options.destination.host));
} else {
buff.writeUInt8(Socks5HostType.Hostname);
buff.writeUInt8(this.options.destination.host.length);
Expand Down Expand Up @@ -799,7 +804,7 @@ class SocksClient extends EventEmitter implements SocksClient {
);

remoteHost = {
host: ip.fromLong(buff.readUInt32BE()),
host: int32ToIpv4(buff.readUInt32BE()),
port: buff.readUInt16BE(),
};

Expand Down Expand Up @@ -842,7 +847,9 @@ class SocksClient extends EventEmitter implements SocksClient {
);

remoteHost = {
host: ip.toString(buff.readBuffer(16)),
host: Address6.fromByteArray(
Array.from(buff.readBuffer(16)),
).canonicalForm(),
port: buff.readUInt16BE(),
};
}
Expand Down Expand Up @@ -913,7 +920,7 @@ class SocksClient extends EventEmitter implements SocksClient {
);

remoteHost = {
host: ip.fromLong(buff.readUInt32BE()),
host: int32ToIpv4(buff.readUInt32BE()),
port: buff.readUInt16BE(),
};

Expand Down Expand Up @@ -956,7 +963,9 @@ class SocksClient extends EventEmitter implements SocksClient {
);

remoteHost = {
host: ip.toString(buff.readBuffer(16)),
host: Address6.fromByteArray(
Array.from(buff.readBuffer(16)),
).canonicalForm(),
port: buff.readUInt16BE(),
};
}
Expand Down
48 changes: 22 additions & 26 deletions src/common/constants.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import {Duplex} from 'stream';
import {Socket, SocketConnectOpts} from 'net';
import {RequireOnlyOne} from './util';

const DEFAULT_TIMEOUT = 30000;

Expand Down Expand Up @@ -112,32 +111,29 @@ enum SocksClientState {
/**
* Represents a SocksProxy
*/
type SocksProxy = RequireOnlyOne<
{
// The ip address (or hostname) of the proxy. (this is equivalent to the host option)
ipaddress?: string;
// The ip address (or hostname) of the proxy. (this is equivalent to the ipaddress option)
host?: string;
// Numeric port number of the proxy.
port: number;
// 4 or 5 (4 is also used for 4a).
type: SocksProxyType;
/* For SOCKS v4, the userId can be used for authentication.
interface SocksProxy {
// The ip address (or hostname) of the proxy. (this is equivalent to the host option)
ipaddress?: string;
// The ip address (or hostname) of the proxy. (this is equivalent to the ipaddress option)
host?: string;
// Numeric port number of the proxy.
port: number;
// 4 or 5 (4 is also used for 4a).
type: SocksProxyType;
/* For SOCKS v4, the userId can be used for authentication.
For SOCKS v5, userId is used as the username for username/password authentication. */
userId?: string;
// For SOCKS v5, this password is used in username/password authentication.
password?: string;
// If present, this auth method will be sent to the proxy server during the initial handshake.
custom_auth_method?: number;
// If present with custom_auth_method, the payload of the returned Buffer of the provided function is sent during the auth handshake.
custom_auth_request_handler?: () => Promise<Buffer>;
// If present with custom_auth_method, this is the expected total response size of the data returned from the server during custom auth handshake.
custom_auth_response_size?: number;
// If present with custom_auth_method, the response from the server is passed to this function. If true is returned from this function, socks client will continue the handshake process, if false it will disconnect.
custom_auth_response_handler?: (data: Buffer) => Promise<boolean>;
},
'host' | 'ipaddress'
>;
userId?: string;
// For SOCKS v5, this password is used in username/password authentication.
password?: string;
// If present, this auth method will be sent to the proxy server during the initial handshake.
custom_auth_method?: number;
// If present with custom_auth_method, the payload of the returned Buffer of the provided function is sent during the auth handshake.
custom_auth_request_handler?: () => Promise<Buffer>;
// If present with custom_auth_method, this is the expected total response size of the data returned from the server during custom auth handshake.
custom_auth_response_size?: number;
// If present with custom_auth_method, the response from the server is passed to this function. If true is returned from this function, socks client will continue the handshake process, if false it will disconnect.
custom_auth_response_handler?: (data: Buffer) => Promise<boolean>;
}

/**
* Represents a remote host
Expand Down
33 changes: 33 additions & 0 deletions src/common/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import {
SocksProxy,
} from './constants';
import * as stream from 'stream';
import {Address4, Address6} from 'ip-address';
import * as net from 'net';

/**
* Validates the provided SocksClientOptions
Expand Down Expand Up @@ -208,3 +210,34 @@ function isValidTimeoutValue(value: number) {
}

export {validateSocksClientOptions, validateSocksClientChainOptions};

export function ipv4ToInt32(ip: string): number {
const address = new Address4(ip);
// Convert the IPv4 address parts to an integer
return address.toArray().reduce((acc, part) => (acc << 8) + part, 0);
}

export function int32ToIpv4(int32: number): string {
// Extract each byte (octet) from the 32-bit integer
const octet1 = (int32 >>> 24) & 0xff;
const octet2 = (int32 >>> 16) & 0xff;
const octet3 = (int32 >>> 8) & 0xff;
const octet4 = int32 & 0xff;

// Combine the octets into a string in IPv4 format
return [octet1, octet2, octet3, octet4].join('.');
}

export function ipToBuffer(ip: string): Buffer {
if (net.isIPv4(ip)) {
// Handle IPv4 addresses
const address = new Address4(ip);
return Buffer.from(address.toArray());
} else if (net.isIPv6(ip)) {
// Handle IPv6 addresses
const address = new Address6(ip);
return Buffer.from(address.toByteArray());
} else {
throw new Error('Invalid IP address format');
}
}
12 changes: 1 addition & 11 deletions src/common/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,4 @@ function shuffleArray(array: unknown[]) {
}
}

// Helper type to require one of N keys.
type RequireOnlyOne<T, Keys extends keyof T = keyof T> = Pick<
T,
Exclude<keyof T, Keys>
> &
{
[K in Keys]?: Required<Pick<T, K>> &
Partial<Record<Exclude<Keys, K>, undefined>>;
}[Keys];

export {RequireOnlyOne, SocksClientError, shuffleArray};
export {SocksClientError, shuffleArray};

0 comments on commit 66b7f73

Please sign in to comment.