Skip to content

Commit 66b7f73

Browse files
remove ip package (#94)
* remove ip package
1 parent 76d013e commit 66b7f73

12 files changed

+1666
-1100
lines changed

.github/workflows/nodejs.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ jobs:
99
runs-on: ubuntu-latest
1010
strategy:
1111
matrix:
12-
node-version: [14.x, 16.x, 18.x]
12+
node-version: [16.x, 18.x, 20.x]
1313
# See supported Node.js release schedule at https://nodejs.org/en/about/releases/
1414
steps:
1515
- uses: actions/checkout@v3

package-lock.json

+1,534-1,019
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+11-11
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "socks",
33
"private": false,
4-
"version": "2.7.1",
4+
"version": "2.7.3",
55
"description": "Fully featured SOCKS proxy client supporting SOCKSv4, SOCKSv4a, and SOCKSv5. Includes Bind and Associate functionality.",
66
"main": "build/index.js",
77
"typings": "typings/index.d.ts",
@@ -23,7 +23,7 @@
2323
"socks5"
2424
],
2525
"engines": {
26-
"node": ">= 10.13.0",
26+
"node": ">= 10.0.0",
2727
"npm": ">= 3.0.0"
2828
},
2929
"author": "Josh Glazebrook",
@@ -33,26 +33,26 @@
3333
"license": "MIT",
3434
"readmeFilename": "README.md",
3535
"devDependencies": {
36-
"@types/ip": "1.1.0",
37-
"@types/mocha": "^9.1.1",
38-
"@types/node": "^18.0.6",
39-
"@typescript-eslint/eslint-plugin": "^5.30.6",
40-
"@typescript-eslint/parser": "^5.30.6",
36+
"@types/mocha": "^10.0.6",
37+
"@types/node": "^20.11.17",
38+
"@typescript-eslint/eslint-plugin": "^6.21.0",
39+
"@typescript-eslint/parser": "^6.21.0",
4140
"eslint": "^8.20.0",
4241
"mocha": "^10.0.0",
43-
"prettier": "^2.7.1",
42+
"prettier": "^3.2.5",
4443
"ts-node": "^10.9.1",
45-
"typescript": "^4.7.4"
44+
"typescript": "^5.3.3"
4645
},
4746
"dependencies": {
48-
"ip": "^2.0.0",
47+
"ip-address": "^9.0.5",
4948
"smart-buffer": "^4.2.0"
5049
},
5150
"scripts": {
5251
"prepublish": "npm install -g typescript && npm run build",
5352
"test": "NODE_ENV=test mocha --recursive --require ts-node/register test/**/*.ts",
5453
"prettier": "prettier --write ./src/**/*.ts --config .prettierrc.yaml",
5554
"lint": "eslint 'src/**/*.ts'",
56-
"build": "rm -rf build typings && prettier --write ./src/**/*.ts --config .prettierrc.yaml && tsc -p ."
55+
"build": "rm -rf build typings && prettier --write ./src/**/*.ts --config .prettierrc.yaml && tsc -p .",
56+
"build-raw": "rm -rf build typings && tsc -p ."
5757
}
5858
}

src/client/socksclient.ts

+23-14
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import {EventEmitter} from 'events';
22
import * as net from 'net';
3-
import * as ip from 'ip';
43
import {SmartBuffer} from 'smart-buffer';
54
import {
65
DEFAULT_TIMEOUT,
@@ -24,10 +23,14 @@ import {
2423
import {
2524
validateSocksClientOptions,
2625
validateSocksClientChainOptions,
26+
ipv4ToInt32,
27+
ipToBuffer,
28+
int32ToIpv4,
2729
} from '../common/helpers';
2830
import {ReceiveBuffer} from '../common/receivebuffer';
2931
import {SocksClientError, shuffleArray} from '../common/util';
3032
import {Duplex} from 'stream';
33+
import {Address6} from 'ip-address';
3134

3235
// Exposes SocksClient event types
3336
declare interface SocksClient {
@@ -231,10 +234,10 @@ class SocksClient extends EventEmitter implements SocksClient {
231234
// IPv4/IPv6/Hostname
232235
if (net.isIPv4(options.remoteHost.host)) {
233236
buff.writeUInt8(Socks5HostType.IPv4);
234-
buff.writeUInt32BE(ip.toLong(options.remoteHost.host));
237+
buff.writeUInt32BE(ipv4ToInt32(options.remoteHost.host));
235238
} else if (net.isIPv6(options.remoteHost.host)) {
236239
buff.writeUInt8(Socks5HostType.IPv6);
237-
buff.writeBuffer(ip.toBuffer(options.remoteHost.host));
240+
buff.writeBuffer(ipToBuffer(options.remoteHost.host));
238241
} else {
239242
buff.writeUInt8(Socks5HostType.Hostname);
240243
buff.writeUInt8(Buffer.byteLength(options.remoteHost.host));
@@ -263,9 +266,11 @@ class SocksClient extends EventEmitter implements SocksClient {
263266
let remoteHost;
264267

265268
if (hostType === Socks5HostType.IPv4) {
266-
remoteHost = ip.fromLong(buff.readUInt32BE());
269+
remoteHost = int32ToIpv4(buff.readUInt32BE());
267270
} else if (hostType === Socks5HostType.IPv6) {
268-
remoteHost = ip.toString(buff.readBuffer(16));
271+
remoteHost = Address6.fromByteArray(
272+
Array.from(buff.readBuffer(16)),
273+
).canonicalForm();
269274
} else {
270275
remoteHost = buff.readString(buff.readUInt8());
271276
}
@@ -508,7 +513,7 @@ class SocksClient extends EventEmitter implements SocksClient {
508513

509514
// Socks 4 (IPv4)
510515
if (net.isIPv4(this.options.destination.host)) {
511-
buff.writeBuffer(ip.toBuffer(this.options.destination.host));
516+
buff.writeBuffer(ipToBuffer(this.options.destination.host));
512517
buff.writeStringNT(userId);
513518
// Socks 4a (hostname)
514519
} else {
@@ -546,7 +551,7 @@ class SocksClient extends EventEmitter implements SocksClient {
546551

547552
const remoteHost: SocksRemoteHost = {
548553
port: buff.readUInt16BE(),
549-
host: ip.fromLong(buff.readUInt32BE()),
554+
host: int32ToIpv4(buff.readUInt32BE()),
550555
};
551556

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

585590
const remoteHost: SocksRemoteHost = {
586591
port: buff.readUInt16BE(),
587-
host: ip.fromLong(buff.readUInt32BE()),
592+
host: int32ToIpv4(buff.readUInt32BE()),
588593
};
589594

590595
this.setState(SocksClientState.Established);
@@ -747,10 +752,10 @@ class SocksClient extends EventEmitter implements SocksClient {
747752
// ipv4, ipv6, domain?
748753
if (net.isIPv4(this.options.destination.host)) {
749754
buff.writeUInt8(Socks5HostType.IPv4);
750-
buff.writeBuffer(ip.toBuffer(this.options.destination.host));
755+
buff.writeBuffer(ipToBuffer(this.options.destination.host));
751756
} else if (net.isIPv6(this.options.destination.host)) {
752757
buff.writeUInt8(Socks5HostType.IPv6);
753-
buff.writeBuffer(ip.toBuffer(this.options.destination.host));
758+
buff.writeBuffer(ipToBuffer(this.options.destination.host));
754759
} else {
755760
buff.writeUInt8(Socks5HostType.Hostname);
756761
buff.writeUInt8(this.options.destination.host.length);
@@ -799,7 +804,7 @@ class SocksClient extends EventEmitter implements SocksClient {
799804
);
800805

801806
remoteHost = {
802-
host: ip.fromLong(buff.readUInt32BE()),
807+
host: int32ToIpv4(buff.readUInt32BE()),
803808
port: buff.readUInt16BE(),
804809
};
805810

@@ -842,7 +847,9 @@ class SocksClient extends EventEmitter implements SocksClient {
842847
);
843848

844849
remoteHost = {
845-
host: ip.toString(buff.readBuffer(16)),
850+
host: Address6.fromByteArray(
851+
Array.from(buff.readBuffer(16)),
852+
).canonicalForm(),
846853
port: buff.readUInt16BE(),
847854
};
848855
}
@@ -913,7 +920,7 @@ class SocksClient extends EventEmitter implements SocksClient {
913920
);
914921

915922
remoteHost = {
916-
host: ip.fromLong(buff.readUInt32BE()),
923+
host: int32ToIpv4(buff.readUInt32BE()),
917924
port: buff.readUInt16BE(),
918925
};
919926

@@ -956,7 +963,9 @@ class SocksClient extends EventEmitter implements SocksClient {
956963
);
957964

958965
remoteHost = {
959-
host: ip.toString(buff.readBuffer(16)),
966+
host: Address6.fromByteArray(
967+
Array.from(buff.readBuffer(16)),
968+
).canonicalForm(),
960969
port: buff.readUInt16BE(),
961970
};
962971
}

src/common/constants.ts

+22-26
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import {Duplex} from 'stream';
22
import {Socket, SocketConnectOpts} from 'net';
3-
import {RequireOnlyOne} from './util';
43

54
const DEFAULT_TIMEOUT = 30000;
65

@@ -112,32 +111,29 @@ enum SocksClientState {
112111
/**
113112
* Represents a SocksProxy
114113
*/
115-
type SocksProxy = RequireOnlyOne<
116-
{
117-
// The ip address (or hostname) of the proxy. (this is equivalent to the host option)
118-
ipaddress?: string;
119-
// The ip address (or hostname) of the proxy. (this is equivalent to the ipaddress option)
120-
host?: string;
121-
// Numeric port number of the proxy.
122-
port: number;
123-
// 4 or 5 (4 is also used for 4a).
124-
type: SocksProxyType;
125-
/* For SOCKS v4, the userId can be used for authentication.
114+
interface SocksProxy {
115+
// The ip address (or hostname) of the proxy. (this is equivalent to the host option)
116+
ipaddress?: string;
117+
// The ip address (or hostname) of the proxy. (this is equivalent to the ipaddress option)
118+
host?: string;
119+
// Numeric port number of the proxy.
120+
port: number;
121+
// 4 or 5 (4 is also used for 4a).
122+
type: SocksProxyType;
123+
/* For SOCKS v4, the userId can be used for authentication.
126124
For SOCKS v5, userId is used as the username for username/password authentication. */
127-
userId?: string;
128-
// For SOCKS v5, this password is used in username/password authentication.
129-
password?: string;
130-
// If present, this auth method will be sent to the proxy server during the initial handshake.
131-
custom_auth_method?: number;
132-
// If present with custom_auth_method, the payload of the returned Buffer of the provided function is sent during the auth handshake.
133-
custom_auth_request_handler?: () => Promise<Buffer>;
134-
// If present with custom_auth_method, this is the expected total response size of the data returned from the server during custom auth handshake.
135-
custom_auth_response_size?: number;
136-
// 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.
137-
custom_auth_response_handler?: (data: Buffer) => Promise<boolean>;
138-
},
139-
'host' | 'ipaddress'
140-
>;
125+
userId?: string;
126+
// For SOCKS v5, this password is used in username/password authentication.
127+
password?: string;
128+
// If present, this auth method will be sent to the proxy server during the initial handshake.
129+
custom_auth_method?: number;
130+
// If present with custom_auth_method, the payload of the returned Buffer of the provided function is sent during the auth handshake.
131+
custom_auth_request_handler?: () => Promise<Buffer>;
132+
// If present with custom_auth_method, this is the expected total response size of the data returned from the server during custom auth handshake.
133+
custom_auth_response_size?: number;
134+
// 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.
135+
custom_auth_response_handler?: (data: Buffer) => Promise<boolean>;
136+
}
141137

142138
/**
143139
* Represents a remote host

src/common/helpers.ts

+33
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ import {
1212
SocksProxy,
1313
} from './constants';
1414
import * as stream from 'stream';
15+
import {Address4, Address6} from 'ip-address';
16+
import * as net from 'net';
1517

1618
/**
1719
* Validates the provided SocksClientOptions
@@ -208,3 +210,34 @@ function isValidTimeoutValue(value: number) {
208210
}
209211

210212
export {validateSocksClientOptions, validateSocksClientChainOptions};
213+
214+
export function ipv4ToInt32(ip: string): number {
215+
const address = new Address4(ip);
216+
// Convert the IPv4 address parts to an integer
217+
return address.toArray().reduce((acc, part) => (acc << 8) + part, 0);
218+
}
219+
220+
export function int32ToIpv4(int32: number): string {
221+
// Extract each byte (octet) from the 32-bit integer
222+
const octet1 = (int32 >>> 24) & 0xff;
223+
const octet2 = (int32 >>> 16) & 0xff;
224+
const octet3 = (int32 >>> 8) & 0xff;
225+
const octet4 = int32 & 0xff;
226+
227+
// Combine the octets into a string in IPv4 format
228+
return [octet1, octet2, octet3, octet4].join('.');
229+
}
230+
231+
export function ipToBuffer(ip: string): Buffer {
232+
if (net.isIPv4(ip)) {
233+
// Handle IPv4 addresses
234+
const address = new Address4(ip);
235+
return Buffer.from(address.toArray());
236+
} else if (net.isIPv6(ip)) {
237+
// Handle IPv6 addresses
238+
const address = new Address6(ip);
239+
return Buffer.from(address.toByteArray());
240+
} else {
241+
throw new Error('Invalid IP address format');
242+
}
243+
}

src/common/util.ts

+1-11
Original file line numberDiff line numberDiff line change
@@ -23,14 +23,4 @@ function shuffleArray(array: unknown[]) {
2323
}
2424
}
2525

26-
// Helper type to require one of N keys.
27-
type RequireOnlyOne<T, Keys extends keyof T = keyof T> = Pick<
28-
T,
29-
Exclude<keyof T, Keys>
30-
> &
31-
{
32-
[K in Keys]?: Required<Pick<T, K>> &
33-
Partial<Record<Exclude<Keys, K>, undefined>>;
34-
}[Keys];
35-
36-
export {RequireOnlyOne, SocksClientError, shuffleArray};
26+
export {SocksClientError, shuffleArray};

0 commit comments

Comments
 (0)