mybase 1.1.29 → 1.1.31
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +9 -9
- package/ts/funcs/isLANIp.js +12 -12
- package/ts/funcs/isLANIp.ts +15 -16
- package/ts/funcs/isLoopbackIP.js +14 -12
- package/ts/funcs/isLoopbackIP.ts +12 -12
- package/ts/index.test.ts +1 -1
- package/ts/models/IPAddress.js +101 -8
- package/ts/models/IPAddress.test.ts +220 -15
- package/ts/models/IPAddress.ts +109 -10
- package/tsconfig.json +2 -1
- package/types/ip6addr.d.ts +52 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mybase",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.31",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "mybase.js",
|
|
6
6
|
"scripts": {
|
|
@@ -10,25 +10,25 @@
|
|
|
10
10
|
"license": "ISC",
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"@7c/validurl": "0.0.3",
|
|
13
|
+
"@types/debug": "^4.1.12",
|
|
14
|
+
"@types/ip6addr": "^0.2.6",
|
|
15
|
+
"@types/mysql": "^2.15.25",
|
|
16
|
+
"@types/node": "^20.11.5",
|
|
17
|
+
"@types/request": "^2.48.12",
|
|
18
|
+
"@types/validator": "^13.11.8",
|
|
13
19
|
"aes-js": "^3.1.2",
|
|
14
20
|
"chalk": "^3.0.0",
|
|
15
21
|
"debug": "^4.3.4",
|
|
16
22
|
"ip-range-check": "^0.2.0",
|
|
17
23
|
"ip6": "=0.2.7",
|
|
18
|
-
"ip6addr": "
|
|
24
|
+
"ip6addr": "github:7c/node-ip6addr#db6d558af1f314bcb0a733fd61611fa85e1a3eff",
|
|
19
25
|
"js-sha512": "^0.8.0",
|
|
20
26
|
"mysql": "^2.18.1",
|
|
21
27
|
"mysql2": "^3.9.1",
|
|
22
28
|
"node-vault": "^0.10.2",
|
|
23
29
|
"psl": "^1.9.0",
|
|
24
30
|
"punycode": "^2.1.1",
|
|
25
|
-
"validator": "^13.7.0"
|
|
26
|
-
"@types/debug": "^4.1.12",
|
|
27
|
-
"@types/ip6addr": "^0.2.6",
|
|
28
|
-
"@types/mysql": "^2.15.25",
|
|
29
|
-
"@types/node": "^20.11.5",
|
|
30
|
-
"@types/validator": "^13.11.8",
|
|
31
|
-
"@types/request": "^2.48.12"
|
|
31
|
+
"validator": "^13.7.0"
|
|
32
32
|
},
|
|
33
33
|
"devDependencies": {
|
|
34
34
|
"@jest/globals": "^29.7.0",
|
package/ts/funcs/isLANIp.js
CHANGED
|
@@ -3,24 +3,16 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.isLANIp = void 0;
|
|
6
|
+
exports.isLANIp = exports.private_network_cidrs = void 0;
|
|
7
7
|
const ip6addr_1 = __importDefault(require("ip6addr"));
|
|
8
8
|
const net_1 = __importDefault(require("net"));
|
|
9
|
-
|
|
9
|
+
exports.private_network_cidrs = [
|
|
10
|
+
ip6addr_1.default.createCIDR('10.0.0.0/8'),
|
|
10
11
|
ip6addr_1.default.createCIDR('172.16.0.0/12'),
|
|
11
12
|
ip6addr_1.default.createCIDR('192.168.0.0/16'),
|
|
12
13
|
ip6addr_1.default.createCIDR('fd00::/8'), // Reserved by IETF for future use, but not currently in active use.
|
|
13
|
-
,
|
|
14
14
|
ip6addr_1.default.createCIDR('fc00::/8'), // The range currently in use for local communications within a site or organization.
|
|
15
15
|
];
|
|
16
|
-
function normalizeIp(ip) {
|
|
17
|
-
// also support ipv6
|
|
18
|
-
if (net_1.default.isIP(ip) === 0)
|
|
19
|
-
return '';
|
|
20
|
-
if (net_1.default.isIPv6(ip))
|
|
21
|
-
return ip.toLowerCase().replace(/^::ffff:/, '');
|
|
22
|
-
return ip;
|
|
23
|
-
}
|
|
24
16
|
function isLANIp(ip) {
|
|
25
17
|
ip = normalizeIp(ip);
|
|
26
18
|
if (net_1.default.isIP(ip) === 0)
|
|
@@ -28,7 +20,7 @@ function isLANIp(ip) {
|
|
|
28
20
|
try {
|
|
29
21
|
// speed optimized
|
|
30
22
|
let ipVersion = net_1.default.isIPv4(ip) ? 'ipv4' : 'ipv6';
|
|
31
|
-
for (let cidr of private_network_cidrs) {
|
|
23
|
+
for (let cidr of exports.private_network_cidrs) {
|
|
32
24
|
if (!cidr)
|
|
33
25
|
continue;
|
|
34
26
|
let first = cidr.first();
|
|
@@ -44,4 +36,12 @@ function isLANIp(ip) {
|
|
|
44
36
|
return false;
|
|
45
37
|
}
|
|
46
38
|
exports.isLANIp = isLANIp;
|
|
39
|
+
function normalizeIp(ip) {
|
|
40
|
+
// also support ipv6
|
|
41
|
+
if (net_1.default.isIP(ip) === 0)
|
|
42
|
+
return '';
|
|
43
|
+
if (net_1.default.isIPv6(ip))
|
|
44
|
+
return ip.toLowerCase().replace(/^::ffff:/, '');
|
|
45
|
+
return ip;
|
|
46
|
+
}
|
|
47
47
|
//# sourceMappingURL=isLANIp.js.map
|
package/ts/funcs/isLANIp.ts
CHANGED
|
@@ -1,25 +1,17 @@
|
|
|
1
1
|
import ip6addr from 'ip6addr'
|
|
2
2
|
import net from 'net'
|
|
3
3
|
|
|
4
|
-
const private_network_cidrs = [
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
function normalizeIp(ip:string):string {
|
|
13
|
-
// also support ipv6
|
|
14
|
-
if (net.isIP(ip) === 0) return ''
|
|
15
|
-
if (net.isIPv6(ip)) return ip.toLowerCase().replace(/^::ffff:/, '')
|
|
16
|
-
return ip
|
|
17
|
-
}
|
|
18
|
-
|
|
4
|
+
export const private_network_cidrs = [
|
|
5
|
+
ip6addr.createCIDR('10.0.0.0/8'),
|
|
6
|
+
ip6addr.createCIDR('172.16.0.0/12'),
|
|
7
|
+
ip6addr.createCIDR('192.168.0.0/16'),
|
|
8
|
+
ip6addr.createCIDR('fd00::/8'), // Reserved by IETF for future use, but not currently in active use.
|
|
9
|
+
ip6addr.createCIDR('fc00::/8'), // The range currently in use for local communications within a site or organization.
|
|
10
|
+
]
|
|
19
11
|
|
|
20
12
|
export function isLANIp(ip:string) : boolean {
|
|
21
13
|
ip=normalizeIp(ip)
|
|
22
|
-
if (net.isIP(ip)
|
|
14
|
+
if (net.isIP(ip)===0) return false
|
|
23
15
|
try {
|
|
24
16
|
// speed optimized
|
|
25
17
|
let ipVersion = net.isIPv4(ip) ? 'ipv4' : 'ipv6'
|
|
@@ -36,3 +28,10 @@ export function isLANIp(ip:string) : boolean {
|
|
|
36
28
|
}
|
|
37
29
|
return false
|
|
38
30
|
}
|
|
31
|
+
|
|
32
|
+
function normalizeIp(ip:string):string {
|
|
33
|
+
// also support ipv6
|
|
34
|
+
if (net.isIP(ip) === 0) return ''
|
|
35
|
+
if (net.isIPv6(ip)) return ip.toLowerCase().replace(/^::ffff:/, '')
|
|
36
|
+
return ip
|
|
37
|
+
}
|
package/ts/funcs/isLoopbackIP.js
CHANGED
|
@@ -3,19 +3,13 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.isLoopbackIP = void 0;
|
|
6
|
+
exports.isLoopbackIP = exports.local_network_cidrs = void 0;
|
|
7
7
|
const ip6addr_1 = __importDefault(require("ip6addr"));
|
|
8
8
|
const net_1 = __importDefault(require("net"));
|
|
9
|
-
|
|
10
|
-
ip6addr_1.default.createCIDR('
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
if (net_1.default.isIP(ip) === 0)
|
|
14
|
-
return '';
|
|
15
|
-
if (net_1.default.isIPv6(ip))
|
|
16
|
-
return ip.toLowerCase().replace(/^::ffff:/, '');
|
|
17
|
-
return ip;
|
|
18
|
-
}
|
|
9
|
+
exports.local_network_cidrs = [
|
|
10
|
+
ip6addr_1.default.createCIDR('127.0.0.0/8'),
|
|
11
|
+
ip6addr_1.default.createCIDR('::1/128')
|
|
12
|
+
];
|
|
19
13
|
function isLoopbackIP(ip) {
|
|
20
14
|
ip = normalizeIp(ip);
|
|
21
15
|
if (net_1.default.isIP(ip) === 0)
|
|
@@ -23,7 +17,7 @@ function isLoopbackIP(ip) {
|
|
|
23
17
|
try {
|
|
24
18
|
// speed optimized
|
|
25
19
|
let ipVersion = net_1.default.isIPv4(ip) ? 'ipv4' : 'ipv6';
|
|
26
|
-
for (let cidr of local_network_cidrs) {
|
|
20
|
+
for (let cidr of exports.local_network_cidrs) {
|
|
27
21
|
let first = cidr.first();
|
|
28
22
|
if (first.kind() !== ipVersion)
|
|
29
23
|
continue;
|
|
@@ -37,4 +31,12 @@ function isLoopbackIP(ip) {
|
|
|
37
31
|
return false;
|
|
38
32
|
}
|
|
39
33
|
exports.isLoopbackIP = isLoopbackIP;
|
|
34
|
+
function normalizeIp(ip) {
|
|
35
|
+
// also support ipv6
|
|
36
|
+
if (net_1.default.isIP(ip) === 0)
|
|
37
|
+
return '';
|
|
38
|
+
if (net_1.default.isIPv6(ip))
|
|
39
|
+
return ip.toLowerCase().replace(/^::ffff:/, '');
|
|
40
|
+
return ip;
|
|
41
|
+
}
|
|
40
42
|
//# sourceMappingURL=isLoopbackIP.js.map
|
package/ts/funcs/isLoopbackIP.ts
CHANGED
|
@@ -1,21 +1,14 @@
|
|
|
1
1
|
import ip6addr from 'ip6addr'
|
|
2
2
|
import net from 'net'
|
|
3
3
|
|
|
4
|
-
const local_network_cidrs = [
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
function normalizeIp(ip:string):string {
|
|
9
|
-
// also support ipv6
|
|
10
|
-
if (net.isIP(ip) === 0) return ''
|
|
11
|
-
if (net.isIPv6(ip)) return ip.toLowerCase().replace(/^::ffff:/, '')
|
|
12
|
-
return ip
|
|
13
|
-
}
|
|
14
|
-
|
|
4
|
+
export const local_network_cidrs = [
|
|
5
|
+
ip6addr.createCIDR('127.0.0.0/8'),
|
|
6
|
+
ip6addr.createCIDR('::1/128')
|
|
7
|
+
]
|
|
15
8
|
|
|
16
9
|
export function isLoopbackIP(ip:string) : boolean {
|
|
17
10
|
ip=normalizeIp(ip)
|
|
18
|
-
if (net.isIP(ip)
|
|
11
|
+
if (net.isIP(ip)===0) return false
|
|
19
12
|
try {
|
|
20
13
|
// speed optimized
|
|
21
14
|
let ipVersion = net.isIPv4(ip) ? 'ipv4' : 'ipv6'
|
|
@@ -30,3 +23,10 @@ export function isLoopbackIP(ip:string) : boolean {
|
|
|
30
23
|
}
|
|
31
24
|
return false
|
|
32
25
|
}
|
|
26
|
+
|
|
27
|
+
function normalizeIp(ip:string):string {
|
|
28
|
+
// also support ipv6
|
|
29
|
+
if (net.isIP(ip) === 0) return ''
|
|
30
|
+
if (net.isIPv6(ip)) return ip.toLowerCase().replace(/^::ffff:/, '')
|
|
31
|
+
return ip
|
|
32
|
+
}
|
package/ts/index.test.ts
CHANGED
package/ts/models/IPAddress.js
CHANGED
|
@@ -4,16 +4,24 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.IPAddress = void 0;
|
|
7
|
+
const debug_1 = __importDefault(require("debug"));
|
|
7
8
|
const __1 = require("./../");
|
|
8
9
|
const ip6addr_1 = __importDefault(require("ip6addr"));
|
|
10
|
+
const net_1 = __importDefault(require("net"));
|
|
9
11
|
const ip6 = require('ip6'); // "url": "https://github.com/elgs/ip6"
|
|
12
|
+
const dbg = (0, debug_1.default)('_IPAddress');
|
|
13
|
+
dbg.enabled = true;
|
|
10
14
|
// need version "ip6": "0.2.7",!!
|
|
11
15
|
class IPAddress {
|
|
12
16
|
constructor(ip) {
|
|
13
17
|
if (ip === '-')
|
|
14
|
-
ip = '0.0.0.0';
|
|
18
|
+
ip = '0.0.0.0'; // is this really required?
|
|
15
19
|
try {
|
|
16
20
|
this._ip = ip6addr_1.default.parse(ip);
|
|
21
|
+
if (this._ip._attrs.ipv4Mapped) {
|
|
22
|
+
// we wany to convert it to ipv4
|
|
23
|
+
this._ip = ip6addr_1.default.parse(this._ip.toString({ format: 'v4' }));
|
|
24
|
+
}
|
|
17
25
|
}
|
|
18
26
|
catch (err) {
|
|
19
27
|
if (err instanceof Error)
|
|
@@ -21,6 +29,9 @@ class IPAddress {
|
|
|
21
29
|
throw err;
|
|
22
30
|
}
|
|
23
31
|
}
|
|
32
|
+
abbreviated() {
|
|
33
|
+
return this.toString(); // default behaviour of ip6addr
|
|
34
|
+
}
|
|
24
35
|
toString(opts = { format: 'auto', zeroElide: false, zeroPad: false }) {
|
|
25
36
|
return this._ip.toString();
|
|
26
37
|
}
|
|
@@ -51,10 +62,33 @@ class IPAddress {
|
|
|
51
62
|
return new IPAddress('0.0.0.0');
|
|
52
63
|
}
|
|
53
64
|
isLoopbackIP() {
|
|
54
|
-
return
|
|
65
|
+
return this.partOfCIDR(IPAddress.loopback_cidrs);
|
|
55
66
|
}
|
|
56
67
|
isLANIP() {
|
|
57
|
-
return
|
|
68
|
+
return this.partOfCIDR(IPAddress.lan_cidrs);
|
|
69
|
+
}
|
|
70
|
+
isLocalIP() {
|
|
71
|
+
return this.partOfCIDR(IPAddress.local_cidrs);
|
|
72
|
+
}
|
|
73
|
+
partOfCIDR(cidr_networks) {
|
|
74
|
+
const ipNormalized = this.toString();
|
|
75
|
+
let ipVersion = net_1.default.isIPv4(ipNormalized) ? 'ipv4' : 'ipv6';
|
|
76
|
+
for (let cidr of cidr_networks) {
|
|
77
|
+
if (!cidr)
|
|
78
|
+
continue;
|
|
79
|
+
let first = cidr.first();
|
|
80
|
+
if (first.kind() !== ipVersion)
|
|
81
|
+
continue;
|
|
82
|
+
if (cidr.contains(ipNormalized))
|
|
83
|
+
return true;
|
|
84
|
+
}
|
|
85
|
+
return false;
|
|
86
|
+
}
|
|
87
|
+
static partOfCIDR(_ip, cidr_networks) {
|
|
88
|
+
const ip = IPAddress.try(_ip);
|
|
89
|
+
if (ip === undefined)
|
|
90
|
+
return false;
|
|
91
|
+
return ip.partOfCIDR(cidr_networks);
|
|
58
92
|
}
|
|
59
93
|
isPublicIP() {
|
|
60
94
|
return this.toString() !== '0.0.0.0' && !this.isLoopbackIP() && !this.isLANIP();
|
|
@@ -82,6 +116,50 @@ class IPAddress {
|
|
|
82
116
|
static randomIP6() {
|
|
83
117
|
return new IPAddress((0, __1.randomIP6)());
|
|
84
118
|
}
|
|
119
|
+
static randomCIDRIp(cidr) {
|
|
120
|
+
if (cidr === 'loopback')
|
|
121
|
+
cidr = IPAddress.loopback_cidrs;
|
|
122
|
+
if (cidr === 'loopback4')
|
|
123
|
+
cidr = IPAddress.loopback_cidrs4;
|
|
124
|
+
if (cidr === 'loopback6')
|
|
125
|
+
cidr = IPAddress.loopback_cidrs6;
|
|
126
|
+
if (cidr === 'lan')
|
|
127
|
+
cidr = IPAddress.lan_cidrs;
|
|
128
|
+
if (cidr === 'lan4')
|
|
129
|
+
cidr = IPAddress.lan_cidrs4;
|
|
130
|
+
if (cidr === 'lan6')
|
|
131
|
+
cidr = IPAddress.lan_cidrs6;
|
|
132
|
+
if (cidr === 'local')
|
|
133
|
+
cidr = IPAddress.local_cidrs;
|
|
134
|
+
if (cidr === 'local4')
|
|
135
|
+
cidr = IPAddress.local_cidrs4;
|
|
136
|
+
if (cidr === 'local6')
|
|
137
|
+
cidr = IPAddress.local_cidrs6;
|
|
138
|
+
// dbg('randomCIDRIp', cidr)
|
|
139
|
+
if (cidr.length === 0)
|
|
140
|
+
throw new Error('CIDR array is empty');
|
|
141
|
+
// Pick a random CIDR network
|
|
142
|
+
const network = cidr[Math.floor(Math.random() * cidr.length)];
|
|
143
|
+
// dbg('randomCIDRIp:network', network)
|
|
144
|
+
// Get the range of IPs in this CIDR
|
|
145
|
+
const start = network.first().toBigInt();
|
|
146
|
+
// dbg('randomCIDRIp:first', network.first().toString(),start)
|
|
147
|
+
const end = network.last().toBigInt();
|
|
148
|
+
// dbg('randomCIDRIp:last', network.last().toString(),end)
|
|
149
|
+
let range = end - start;
|
|
150
|
+
// dbg('randomCIDRIp:first:last', start, end)
|
|
151
|
+
// Generate a random Long between the start and end
|
|
152
|
+
// if start-end > Maximum integer number
|
|
153
|
+
// we need to use BigInt
|
|
154
|
+
if (range > BigInt(Number.MAX_SAFE_INTEGER))
|
|
155
|
+
range = (Number.MAX_SAFE_INTEGER);
|
|
156
|
+
const randomBigInt = BigInt(Math.floor(Math.random() * (Number(range) + 1))) + start;
|
|
157
|
+
// dbg('randomBigInt', randomBigInt)
|
|
158
|
+
// Convert the BigInt back to an IP address
|
|
159
|
+
const randomIp = ip6addr_1.default.parse(randomBigInt);
|
|
160
|
+
// dbg('randomCIDRIp', randomIp.toString())
|
|
161
|
+
return new IPAddress(randomIp.toString());
|
|
162
|
+
}
|
|
85
163
|
serialize() {
|
|
86
164
|
if (this.kind() === 4) {
|
|
87
165
|
// zero pad ipv4
|
|
@@ -110,11 +188,6 @@ class IPAddress {
|
|
|
110
188
|
return this._ip.toString();
|
|
111
189
|
return ip6.normalize(this._ip.toString());
|
|
112
190
|
}
|
|
113
|
-
abbreviated() {
|
|
114
|
-
if (this.kind() === 4)
|
|
115
|
-
return this._ip.toString();
|
|
116
|
-
return ip6.abbreviate(this._ip.toString());
|
|
117
|
-
}
|
|
118
191
|
padIp6() {
|
|
119
192
|
const hextets = this.normalized().split(':'); // we need to have the full form
|
|
120
193
|
const paddedHextets = hextets.map(hextet => {
|
|
@@ -158,4 +231,24 @@ class IPAddress {
|
|
|
158
231
|
}
|
|
159
232
|
}
|
|
160
233
|
exports.IPAddress = IPAddress;
|
|
234
|
+
IPAddress.loopback_cidrs4 = [
|
|
235
|
+
ip6addr_1.default.createCIDR('127.0.0.0/8'),
|
|
236
|
+
];
|
|
237
|
+
IPAddress.loopback_cidrs6 = [
|
|
238
|
+
ip6addr_1.default.createCIDR('::1/128') // yes ipv6 has single address
|
|
239
|
+
];
|
|
240
|
+
IPAddress.loopback_cidrs = IPAddress.loopback_cidrs4.concat(IPAddress.loopback_cidrs6);
|
|
241
|
+
IPAddress.lan_cidrs4 = [
|
|
242
|
+
ip6addr_1.default.createCIDR('10.0.0.0/8'),
|
|
243
|
+
ip6addr_1.default.createCIDR('172.16.0.0/12'),
|
|
244
|
+
ip6addr_1.default.createCIDR('192.168.0.0/16'),
|
|
245
|
+
];
|
|
246
|
+
IPAddress.lan_cidrs6 = [
|
|
247
|
+
ip6addr_1.default.createCIDR('fd00::/8'), // Reserved by IETF for future use, but not currently in active use.
|
|
248
|
+
ip6addr_1.default.createCIDR('fc00::/8'), // The range currently in use for local communications within a site or organization.
|
|
249
|
+
];
|
|
250
|
+
IPAddress.lan_cidrs = IPAddress.lan_cidrs4.concat(IPAddress.lan_cidrs6);
|
|
251
|
+
IPAddress.local_cidrs = IPAddress.loopback_cidrs.concat(IPAddress.lan_cidrs);
|
|
252
|
+
IPAddress.local_cidrs4 = IPAddress.loopback_cidrs4.concat(IPAddress.lan_cidrs4);
|
|
253
|
+
IPAddress.local_cidrs6 = IPAddress.loopback_cidrs6.concat(IPAddress.lan_cidrs6);
|
|
161
254
|
//# sourceMappingURL=IPAddress.js.map
|
|
@@ -63,22 +63,22 @@ describe('IPAddress', () => {
|
|
|
63
63
|
})
|
|
64
64
|
|
|
65
65
|
it('randomly generated ipv4 serialization', () => {
|
|
66
|
-
for(let i = 0; i < 100; i++) {
|
|
66
|
+
for (let i = 0; i < 100; i++) {
|
|
67
67
|
const ip = randomIP()
|
|
68
68
|
expect(IPAddress.unserialize(IPAddress.fromString(ip).serialize()).toString()).toBe(ip)
|
|
69
69
|
}
|
|
70
70
|
})
|
|
71
71
|
|
|
72
72
|
it('randomly generated ipv6 serialization and unserialization', () => {
|
|
73
|
-
for(let i = 0; i < 100; i++) {
|
|
73
|
+
for (let i = 0; i < 100; i++) {
|
|
74
74
|
const ip = randomIP6()
|
|
75
75
|
let ip2 = IPAddress.unserialize(IPAddress.fromString(ip).serialize()).toString()
|
|
76
|
-
expect(ip6addr.compare(ip, ip2)).toEqual(0)
|
|
76
|
+
expect(ip6addr.compare(ip, ip2)).toEqual(0)
|
|
77
77
|
}
|
|
78
78
|
})
|
|
79
79
|
|
|
80
80
|
it('it should detect the kind of ip4', () => {
|
|
81
|
-
for(let i = 0; i < 100; i++)
|
|
81
|
+
for (let i = 0; i < 100; i++)
|
|
82
82
|
expect(IPAddress.randomIP4().kind()).toBe(4)
|
|
83
83
|
})
|
|
84
84
|
|
|
@@ -88,10 +88,10 @@ describe('IPAddress', () => {
|
|
|
88
88
|
|
|
89
89
|
it('randomPad return valid ipv4 results', () => {
|
|
90
90
|
let compared = 0
|
|
91
|
-
while(compared<100) {
|
|
91
|
+
while (compared < 100) {
|
|
92
92
|
const ip1 = IPAddress.randomIP4()
|
|
93
93
|
const ip2 = ip1.randomPad()
|
|
94
|
-
if (ip1.toString()!==ip2) { // find ips they are padded from the original
|
|
94
|
+
if (ip1.toString() !== ip2) { // find ips they are padded from the original
|
|
95
95
|
compared++
|
|
96
96
|
}
|
|
97
97
|
expect(IPAddress.validate(ip2)).toBe(true)
|
|
@@ -100,16 +100,102 @@ describe('IPAddress', () => {
|
|
|
100
100
|
|
|
101
101
|
it('compare ipv4 should detect equality even if they are padded', () => {
|
|
102
102
|
let compared = 0
|
|
103
|
-
while(compared<100) {
|
|
103
|
+
while (compared < 100) {
|
|
104
104
|
const ip1 = IPAddress.randomIP4()
|
|
105
105
|
const ip2 = ip1.randomPad()
|
|
106
|
-
if (ip1.toString()!==ip2) { // find ips they are padded from the original
|
|
106
|
+
if (ip1.toString() !== ip2) { // find ips they are padded from the original
|
|
107
107
|
compared++
|
|
108
108
|
}
|
|
109
109
|
expect(ip1.equals(IPAddress.fromString(ip2))).toBe(true)
|
|
110
110
|
}
|
|
111
111
|
})
|
|
112
112
|
|
|
113
|
+
it('normalized should normalize ipv4 ips properly', () => {
|
|
114
|
+
expect(new IPAddress('127.0.0.1').normalized()).toBe('127.0.0.1')
|
|
115
|
+
expect(new IPAddress('127.00.0.1').normalized()).toBe('127.0.0.1')
|
|
116
|
+
expect(new IPAddress('127.000.00.1').normalized()).toBe('127.0.0.1')
|
|
117
|
+
expect(new IPAddress('127.0.00.00001').normalized()).toBe('127.0.0.1')
|
|
118
|
+
})
|
|
119
|
+
|
|
120
|
+
it('normalized should normalize ipv6 ips properly', () => {
|
|
121
|
+
expect(new IPAddress('::1').normalized()).toBe('0000:0000:0000:0000:0000:0000:0000:0001')
|
|
122
|
+
expect(new IPAddress('::01').normalized()).toBe('0000:0000:0000:0000:0000:0000:0000:0001')
|
|
123
|
+
expect(new IPAddress('::001').normalized()).toBe('0000:0000:0000:0000:0000:0000:0000:0001')
|
|
124
|
+
expect(new IPAddress('::0001').normalized()).toBe('0000:0000:0000:0000:0000:0000:0000:0001')
|
|
125
|
+
expect(new IPAddress('::000001').normalized()).toBe('0000:0000:0000:0000:0000:0000:0000:0001')
|
|
126
|
+
expect(new IPAddress('::1:1').normalized()).toBe('0000:0000:0000:0000:0000:0000:0001:0001')
|
|
127
|
+
expect(new IPAddress('::2:1').normalized()).toBe('0000:0000:0000:0000:0000:0000:0002:0001')
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
expect(new IPAddress('1::1').normalized()).toBe('0001:0000:0000:0000:0000:0000:0000:0001')
|
|
131
|
+
expect(new IPAddress('2::01').normalized()).toBe('0002:0000:0000:0000:0000:0000:0000:0001')
|
|
132
|
+
expect(new IPAddress('3::001').normalized()).toBe('0003:0000:0000:0000:0000:0000:0000:0001')
|
|
133
|
+
expect(new IPAddress('4::0001').normalized()).toBe('0004:0000:0000:0000:0000:0000:0000:0001')
|
|
134
|
+
expect(new IPAddress('5::000001').normalized()).toBe('0005:0000:0000:0000:0000:0000:0000:0001')
|
|
135
|
+
expect(new IPAddress('6::1:1').normalized()).toBe('0006:0000:0000:0000:0000:0000:0001:0001')
|
|
136
|
+
expect(new IPAddress('7::2:1').normalized()).toBe('0007:0000:0000:0000:0000:0000:0002:0001')
|
|
137
|
+
})
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
it('abbreviated should abbreviate ipv6 ips properly', () => {
|
|
141
|
+
expect(new IPAddress('::1').abbreviated()).toBe('::1')
|
|
142
|
+
expect(new IPAddress('::01').abbreviated()).toBe('::1')
|
|
143
|
+
expect(new IPAddress('::001').abbreviated()).toBe('::1')
|
|
144
|
+
expect(new IPAddress('::0001').abbreviated()).toBe('::1')
|
|
145
|
+
expect(new IPAddress('::000001').abbreviated()).toBe('::1')
|
|
146
|
+
expect(new IPAddress('0000:0000:0000:0000:0000:0000:0001:0001').abbreviated()).toBe('::1:1')
|
|
147
|
+
expect(new IPAddress('0000:0000:0000:0000:0000:0000:0002:0001').abbreviated()).toBe('::2:1')
|
|
148
|
+
|
|
149
|
+
expect(new IPAddress('2001:0db8:0001:0002:0003:0004:0005:0006').abbreviated()).toBe('2001:db8:1:2:3:4:5:6')
|
|
150
|
+
expect(new IPAddress('1:0000:0000::0000:0000:0000:0001').abbreviated()).toBe('1::1')
|
|
151
|
+
expect(new IPAddress('0001:0000:0000:0000:0000:0000:0000:0001').abbreviated()).toBe('1::1')
|
|
152
|
+
expect(new IPAddress('0002:0000:0000:0000:0000::0000:0001').abbreviated()).toBe('2::1')
|
|
153
|
+
expect(new IPAddress('0003:0000:0000:0000:0000:0000:0000:0001').abbreviated()).toBe('3::1')
|
|
154
|
+
expect(new IPAddress('0004::0000:0000:0000:0000:0000:0001').abbreviated()).toBe('4::1')
|
|
155
|
+
expect(new IPAddress('0005:0000:0000:0000:0000:0000:0000:0001').abbreviated()).toBe('5::1')
|
|
156
|
+
expect(new IPAddress('0006:0000:0000::0000:0000:0001:0001').abbreviated()).toBe('6::1:1')
|
|
157
|
+
expect(new IPAddress('0007:0000:0000:0000:0000::0002:0001').abbreviated()).toBe('7::2:1')
|
|
158
|
+
})
|
|
159
|
+
|
|
160
|
+
it('abbreviated should abbreviate ipv4 ips properly', () => {
|
|
161
|
+
expect(new IPAddress('127.00.000.1').abbreviated()).toBe('127.0.0.1')
|
|
162
|
+
expect(new IPAddress('127.0.00.00001').abbreviated()).toBe('127.0.0.1')
|
|
163
|
+
expect(new IPAddress('127.0000.0.00001').abbreviated()).toBe('127.0.0.1')
|
|
164
|
+
expect(new IPAddress('0.0000.0.00000').abbreviated()).toBe('0.0.0.0')
|
|
165
|
+
})
|
|
166
|
+
it('abbreviated should abbreviate ipv4-mapped ips properly', () => {
|
|
167
|
+
expect(new IPAddress('::ffff:127.00.000.1').abbreviated()).toBe('127.0.0.1')
|
|
168
|
+
expect(new IPAddress('::ffff:127.0.00.00001').abbreviated()).toBe('127.0.0.1')
|
|
169
|
+
expect(new IPAddress('::ffff:127.0000.0.00001').abbreviated()).toBe('127.0.0.1')
|
|
170
|
+
expect(new IPAddress('0::ffff:127.0000.0.00001').abbreviated()).toBe('127.0.0.1')
|
|
171
|
+
expect(new IPAddress('0:0:0::ffff:127.0000.0.00001').abbreviated()).toBe('127.0.0.1')
|
|
172
|
+
expect(new IPAddress('::ffff:0.0000.0.00000').abbreviated()).toBe('0.0.0.0')
|
|
173
|
+
})
|
|
174
|
+
|
|
175
|
+
it('toString() IPv4-mapped IPv6 address should be returned as ipv4', () => {
|
|
176
|
+
expect(new IPAddress('::ffff:127.0.00.00001').toString()).toBe('127.0.0.1')
|
|
177
|
+
expect(new IPAddress('0::ffff:127.0.00.00001').toString()).toBe('127.0.0.1')
|
|
178
|
+
expect(new IPAddress('00::ffff:127.0.00.00001').toString()).toBe('127.0.0.1')
|
|
179
|
+
expect(new IPAddress('0:00::ffff:127.0.00.00001').toString()).toBe('127.0.0.1')
|
|
180
|
+
expect(new IPAddress('0:0:0::ffff:127.0.00.00001').toString()).toBe('127.0.0.1')
|
|
181
|
+
})
|
|
182
|
+
|
|
183
|
+
it('kind() IPv4-mapped IPv6 address should be returned as ipv4', () => {
|
|
184
|
+
expect(new IPAddress('::ffff:127.0.00.00001').kind()).toBe(4)
|
|
185
|
+
expect(new IPAddress('0::ffff:127.0.00.00001').kind()).toBe(4)
|
|
186
|
+
expect(new IPAddress('00::ffff:127.0.00.00001').kind()).toBe(4)
|
|
187
|
+
expect(new IPAddress('0:00::ffff:127.0.00.00001').kind()).toBe(4)
|
|
188
|
+
expect(new IPAddress('0:0:0::ffff:127.0.00.00001').kind()).toBe(4)
|
|
189
|
+
})
|
|
190
|
+
|
|
191
|
+
it('IPv4-mapps Addresses should be converted to Ipv4 at constructor', () => {
|
|
192
|
+
expect(new IPAddress('::ffff:127.0.00.00001').toString()).toBe('127.0.0.1')
|
|
193
|
+
expect(new IPAddress('0::ffff:127.0.00.00001').toString()).toBe('127.0.0.1')
|
|
194
|
+
expect(new IPAddress('00::ffff:127.0.00.00001').toString()).toBe('127.0.0.1')
|
|
195
|
+
expect(new IPAddress('0:00::ffff:127.0.00.00001').toString()).toBe('127.0.0.1')
|
|
196
|
+
expect(new IPAddress('0:0:0::ffff:127.0.00.00001').toString()).toBe('127.0.0.1')
|
|
197
|
+
})
|
|
198
|
+
|
|
113
199
|
});
|
|
114
200
|
|
|
115
201
|
describe('IPAddress IPv6', () => {
|
|
@@ -137,20 +223,20 @@ describe('IPAddress IPv6', () => {
|
|
|
137
223
|
|
|
138
224
|
it('it should detect the kind of ip6', () => {
|
|
139
225
|
expect(new IPAddress('2605:2700:0000:0003:a800:00ff:fe10:f0d3').kind()).toBe(6);
|
|
140
|
-
for(let i = 0; i < 100; i++)
|
|
226
|
+
for (let i = 0; i < 100; i++)
|
|
141
227
|
expect(IPAddress.randomIP6().kind()).toBe(6)
|
|
142
228
|
})
|
|
143
229
|
|
|
144
230
|
it('randomPad return valid ipv6 results be compareable with equals', () => {
|
|
145
231
|
let compared = 0
|
|
146
|
-
while(compared<500) {
|
|
232
|
+
while (compared < 500) {
|
|
147
233
|
const ip1 = IPAddress.randomIP6()
|
|
148
234
|
const ip2 = ip1.randomPad()
|
|
149
235
|
expect(ip1.kind()).toBe(6)
|
|
150
|
-
if (ip1.toString()!==ip2) { // find ips they are padded from the original
|
|
236
|
+
if (ip1.toString() !== ip2) { // find ips they are padded from the original
|
|
151
237
|
compared++
|
|
152
238
|
}
|
|
153
|
-
|
|
239
|
+
|
|
154
240
|
expect(IPAddress.validate(ip2)).toBe(true)
|
|
155
241
|
expect(ip1.equals(IPAddress.fromString(ip2))).toBe(true)
|
|
156
242
|
}
|
|
@@ -173,16 +259,135 @@ describe('IPAddress asciiChecksum', () => {
|
|
|
173
259
|
})
|
|
174
260
|
|
|
175
261
|
it('it should always return a single character ipv4/v6', () => {
|
|
176
|
-
for(let i=0;i<10000;i++) {
|
|
262
|
+
for (let i = 0; i < 10000; i++) {
|
|
177
263
|
expect(new IPAddress(randomIP()).asciiChecksum().length).toBe(1)
|
|
178
264
|
expect(new IPAddress(randomIP6()).asciiChecksum().length).toBe(1)
|
|
179
265
|
}
|
|
180
266
|
})
|
|
181
267
|
|
|
182
|
-
it('it should return a-z0-9 ascii only',()=>{
|
|
183
|
-
for(let i=0;i<10000;i++) {
|
|
268
|
+
it('it should return a-z0-9 ascii only', () => {
|
|
269
|
+
for (let i = 0; i < 10000; i++) {
|
|
184
270
|
expect('abcdefghijklmnopqrstuvwxyz0123456789').toContain(new IPAddress(randomIP()).asciiChecksum())
|
|
185
271
|
expect('abcdefghijklmnopqrstuvwxyz0123456789').toContain(new IPAddress(randomIP6()).asciiChecksum())
|
|
186
272
|
}
|
|
187
273
|
})
|
|
274
|
+
})
|
|
275
|
+
|
|
276
|
+
describe('IPAddress partOfCIDR', () => {
|
|
277
|
+
it('should detect cidrs in ipv4', () => {
|
|
278
|
+
expect(IPAddress.partOfCIDR('127.0.0.1', [ip6addr.createCIDR('127.0.0.0/8')])).toBe(true)
|
|
279
|
+
expect(IPAddress.partOfCIDR('127.0.0.1', [ip6addr.createCIDR('128.0.0.0/8')])).toBe(false)
|
|
280
|
+
expect(IPAddress.partOfCIDR('127.0.0.1', [ip6addr.createCIDR('126.0.0.0/8')])).toBe(false)
|
|
281
|
+
})
|
|
282
|
+
it('should detect cidrs in ipv6', () => {
|
|
283
|
+
expect(IPAddress.partOfCIDR('::1', [ip6addr.createCIDR('::/8')])).toBe(true)
|
|
284
|
+
expect(IPAddress.partOfCIDR('::1', [ip6addr.createCIDR('2ff0::1:0/8')])).toBe(false)
|
|
285
|
+
expect(IPAddress.partOfCIDR('::1', [ip6addr.createCIDR('3ff0::2:0/8')])).toBe(false)
|
|
286
|
+
})
|
|
287
|
+
|
|
288
|
+
it('should also work non-static', () => {
|
|
289
|
+
expect(new IPAddress('::1').partOfCIDR([ip6addr.createCIDR('::/8')])).toBe(true)
|
|
290
|
+
})
|
|
291
|
+
})
|
|
292
|
+
|
|
293
|
+
describe('IPAddress randomCIDRIp', () => {
|
|
294
|
+
const testCount = 25000
|
|
295
|
+
|
|
296
|
+
it('"loopback" should return random loopback ip4/6', () => {
|
|
297
|
+
const stats:any={
|
|
298
|
+
'4':0,
|
|
299
|
+
'6':0
|
|
300
|
+
}
|
|
301
|
+
for(var i=0;i<testCount;i++) {
|
|
302
|
+
const rip = IPAddress.randomCIDRIp('loopback')
|
|
303
|
+
stats[rip.kind().toString()]++
|
|
304
|
+
expect(rip.isLoopbackIP()).toBe(true)
|
|
305
|
+
}
|
|
306
|
+
// we need to have at least 30% of ipv4 and ipv6
|
|
307
|
+
expect(stats['4']).toBeGreaterThan(testCount*0.3)
|
|
308
|
+
expect(stats['6']).toBeGreaterThan(testCount*0.3)
|
|
309
|
+
})
|
|
310
|
+
|
|
311
|
+
it('"loopback4" should return random loopback ip4', () => {
|
|
312
|
+
for(var i=0;i<testCount;i++) {
|
|
313
|
+
const rip = IPAddress.randomCIDRIp('loopback4')
|
|
314
|
+
expect(rip.kind()).toBe(4)
|
|
315
|
+
expect(rip.isLoopbackIP()).toBe(true)
|
|
316
|
+
}
|
|
317
|
+
})
|
|
318
|
+
|
|
319
|
+
|
|
320
|
+
it('"loopback6" should return random loopback ip6', () => {
|
|
321
|
+
for(var i=0;i<testCount;i++) {
|
|
322
|
+
const rip = IPAddress.randomCIDRIp('loopback6')
|
|
323
|
+
expect(rip.kind()).toBe(6)
|
|
324
|
+
expect(rip.isLoopbackIP()).toBe(true)
|
|
325
|
+
// ipv6 has single loopback address
|
|
326
|
+
expect(rip.toString()).toBe('::1')
|
|
327
|
+
}
|
|
328
|
+
})
|
|
329
|
+
|
|
330
|
+
it('"lan" should return random LAN ip4/6', () => {
|
|
331
|
+
const stats:any={
|
|
332
|
+
'4':0,
|
|
333
|
+
'6':0
|
|
334
|
+
}
|
|
335
|
+
for(var i=0;i<testCount;i++) {
|
|
336
|
+
const rip = IPAddress.randomCIDRIp('lan')
|
|
337
|
+
stats[rip.kind().toString()]++
|
|
338
|
+
// if (!rip.isLANIP()) console.log(rip.toString(),`must be lan but it is not`)
|
|
339
|
+
expect(rip.isLANIP()).toBe(true)
|
|
340
|
+
}
|
|
341
|
+
// we need to have at least 30% of ipv4 and ipv6
|
|
342
|
+
expect(stats['4']).toBeGreaterThan(testCount*0.3)
|
|
343
|
+
expect(stats['6']).toBeGreaterThan(testCount*0.3)
|
|
344
|
+
})
|
|
345
|
+
|
|
346
|
+
|
|
347
|
+
it('"lan6" should return random lan ip6', () => {
|
|
348
|
+
for(var i=0;i<testCount;i++) {
|
|
349
|
+
const rip = IPAddress.randomCIDRIp('lan6')
|
|
350
|
+
expect(rip.kind()).toBe(6)
|
|
351
|
+
expect(rip.isLANIP()).toBe(true)
|
|
352
|
+
}
|
|
353
|
+
})
|
|
354
|
+
|
|
355
|
+
it('"lan4" should return random lan ip4', () => {
|
|
356
|
+
for(var i=0;i<testCount;i++) {
|
|
357
|
+
const rip = IPAddress.randomCIDRIp('lan4')
|
|
358
|
+
expect(rip.kind()).toBe(4)
|
|
359
|
+
expect(rip.isLANIP()).toBe(true)
|
|
360
|
+
}
|
|
361
|
+
})
|
|
362
|
+
|
|
363
|
+
it('"local" should return random local ip4/6', () => {
|
|
364
|
+
const stats:any={
|
|
365
|
+
'4':0,
|
|
366
|
+
'6':0
|
|
367
|
+
}
|
|
368
|
+
for(var i=0;i<testCount;i++) {
|
|
369
|
+
const rip = IPAddress.randomCIDRIp('local')
|
|
370
|
+
stats[rip.kind().toString()]++
|
|
371
|
+
expect(rip.isLocalIP()).toBe(true)
|
|
372
|
+
}
|
|
373
|
+
// we need to have at least 30% of ipv4 and ipv6
|
|
374
|
+
expect(stats['4']).toBeGreaterThan(testCount*0.3)
|
|
375
|
+
expect(stats['6']).toBeGreaterThan(testCount*0.3)
|
|
376
|
+
})
|
|
377
|
+
|
|
378
|
+
it('"local4" should return random local ip4', () => {
|
|
379
|
+
for(var i=0;i<testCount;i++) {
|
|
380
|
+
const rip = IPAddress.randomCIDRIp('local4')
|
|
381
|
+
expect(rip.kind()).toBe(4)
|
|
382
|
+
expect(rip.isLocalIP()).toBe(true)
|
|
383
|
+
}
|
|
384
|
+
})
|
|
385
|
+
|
|
386
|
+
it('"local6" should return random local ip6', () => {
|
|
387
|
+
for(var i=0;i<testCount;i++) {
|
|
388
|
+
const rip = IPAddress.randomCIDRIp('local6')
|
|
389
|
+
expect(rip.kind()).toBe(6)
|
|
390
|
+
expect(rip.isLocalIP()).toBe(true)
|
|
391
|
+
}
|
|
392
|
+
})
|
|
188
393
|
})
|
package/ts/models/IPAddress.ts
CHANGED
|
@@ -1,16 +1,51 @@
|
|
|
1
|
-
import
|
|
1
|
+
import debug from 'debug'
|
|
2
|
+
import { randomIP, randomIP6, } from "./../"
|
|
2
3
|
import ip6addr, { Addr, ToStringOpts } from 'ip6addr'
|
|
4
|
+
import net from 'net'
|
|
3
5
|
const ip6 = require('ip6') // "url": "https://github.com/elgs/ip6"
|
|
6
|
+
const dbg = debug('_IPAddress')
|
|
7
|
+
dbg.enabled = true
|
|
4
8
|
// need version "ip6": "0.2.7",!!
|
|
5
9
|
|
|
6
10
|
export class IPAddress {
|
|
7
11
|
private _ip: Addr
|
|
8
12
|
|
|
9
|
-
|
|
10
|
-
|
|
13
|
+
public static loopback_cidrs4 = [
|
|
14
|
+
ip6addr.createCIDR('127.0.0.0/8'),
|
|
15
|
+
]
|
|
16
|
+
|
|
17
|
+
public static loopback_cidrs6 = [
|
|
18
|
+
ip6addr.createCIDR('::1/128') // yes ipv6 has single address
|
|
19
|
+
]
|
|
20
|
+
|
|
21
|
+
public static loopback_cidrs = IPAddress.loopback_cidrs4.concat(IPAddress.loopback_cidrs6)
|
|
22
|
+
|
|
23
|
+
public static lan_cidrs4 = [
|
|
24
|
+
ip6addr.createCIDR('10.0.0.0/8'),
|
|
25
|
+
ip6addr.createCIDR('172.16.0.0/12'),
|
|
26
|
+
ip6addr.createCIDR('192.168.0.0/16'),
|
|
27
|
+
]
|
|
28
|
+
|
|
29
|
+
public static lan_cidrs6 = [
|
|
30
|
+
ip6addr.createCIDR('fd00::/8'), // Reserved by IETF for future use, but not currently in active use.
|
|
31
|
+
ip6addr.createCIDR('fc00::/8'), // The range currently in use for local communications within a site or organization.
|
|
32
|
+
]
|
|
33
|
+
|
|
34
|
+
public static lan_cidrs = IPAddress.lan_cidrs4.concat(IPAddress.lan_cidrs6)
|
|
35
|
+
|
|
36
|
+
public static local_cidrs = IPAddress.loopback_cidrs.concat(IPAddress.lan_cidrs)
|
|
37
|
+
public static local_cidrs4 = IPAddress.loopback_cidrs4.concat(IPAddress.lan_cidrs4)
|
|
38
|
+
public static local_cidrs6 = IPAddress.loopback_cidrs6.concat(IPAddress.lan_cidrs6)
|
|
39
|
+
|
|
11
40
|
|
|
41
|
+
constructor(ip: string) { // may throw
|
|
42
|
+
if (ip === '-') ip = '0.0.0.0' // is this really required?
|
|
12
43
|
try {
|
|
13
44
|
this._ip = ip6addr.parse(ip)
|
|
45
|
+
if (this._ip._attrs.ipv4Mapped) {
|
|
46
|
+
// we wany to convert it to ipv4
|
|
47
|
+
this._ip = ip6addr.parse(this._ip.toString({ format: 'v4' }))
|
|
48
|
+
}
|
|
14
49
|
} catch (err) {
|
|
15
50
|
if (err instanceof Error)
|
|
16
51
|
throw new Error(`IPAddress: '${ip}' Error: ${err.message}`)
|
|
@@ -18,7 +53,12 @@ export class IPAddress {
|
|
|
18
53
|
}
|
|
19
54
|
}
|
|
20
55
|
|
|
21
|
-
|
|
56
|
+
|
|
57
|
+
public abbreviated(): string {
|
|
58
|
+
return this.toString() // default behaviour of ip6addr
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
public toString(opts: ToStringOpts = { format: 'auto', zeroElide: false, zeroPad: false }): string {
|
|
22
62
|
return this._ip.toString()
|
|
23
63
|
}
|
|
24
64
|
|
|
@@ -51,11 +91,34 @@ export class IPAddress {
|
|
|
51
91
|
}
|
|
52
92
|
|
|
53
93
|
public isLoopbackIP(): boolean {
|
|
54
|
-
return
|
|
94
|
+
return this.partOfCIDR(IPAddress.loopback_cidrs)
|
|
55
95
|
}
|
|
56
96
|
|
|
57
97
|
public isLANIP(): boolean {
|
|
58
|
-
return
|
|
98
|
+
return this.partOfCIDR(IPAddress.lan_cidrs)
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
public isLocalIP(): boolean {
|
|
102
|
+
return this.partOfCIDR(IPAddress.local_cidrs)
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
partOfCIDR(cidr_networks: ip6addr.CIDR[]): boolean {
|
|
106
|
+
const ipNormalized = this.toString()
|
|
107
|
+
let ipVersion = net.isIPv4(ipNormalized) ? 'ipv4' : 'ipv6'
|
|
108
|
+
for (let cidr of cidr_networks) {
|
|
109
|
+
if (!cidr) continue
|
|
110
|
+
let first = cidr.first()
|
|
111
|
+
if (first.kind() !== ipVersion) continue
|
|
112
|
+
if (cidr.contains(ipNormalized))
|
|
113
|
+
return true
|
|
114
|
+
}
|
|
115
|
+
return false
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
static partOfCIDR(_ip: string, cidr_networks: ip6addr.CIDR[]): boolean {
|
|
119
|
+
const ip = IPAddress.try(_ip)
|
|
120
|
+
if (ip === undefined) return false
|
|
121
|
+
return ip.partOfCIDR(cidr_networks)
|
|
59
122
|
}
|
|
60
123
|
|
|
61
124
|
public isPublicIP(): boolean {
|
|
@@ -86,6 +149,46 @@ export class IPAddress {
|
|
|
86
149
|
return new IPAddress(randomIP6())
|
|
87
150
|
}
|
|
88
151
|
|
|
152
|
+
|
|
153
|
+
public static randomCIDRIp(cidr: ip6addr.CIDR[] | 'loopback' | 'lan' | 'local' | 'loopback4' | 'loopback6' | 'lan4' | 'lan6' | 'local4' | 'local6'): IPAddress {
|
|
154
|
+
if (cidr === 'loopback') cidr = IPAddress.loopback_cidrs
|
|
155
|
+
if (cidr === 'loopback4') cidr = IPAddress.loopback_cidrs4
|
|
156
|
+
if (cidr === 'loopback6') cidr = IPAddress.loopback_cidrs6
|
|
157
|
+
if (cidr === 'lan') cidr = IPAddress.lan_cidrs
|
|
158
|
+
if (cidr === 'lan4') cidr = IPAddress.lan_cidrs4
|
|
159
|
+
if (cidr === 'lan6') cidr = IPAddress.lan_cidrs6
|
|
160
|
+
if (cidr === 'local') cidr = IPAddress.local_cidrs
|
|
161
|
+
if (cidr === 'local4') cidr = IPAddress.local_cidrs4
|
|
162
|
+
if (cidr === 'local6') cidr = IPAddress.local_cidrs6
|
|
163
|
+
// dbg('randomCIDRIp', cidr)
|
|
164
|
+
if (cidr.length === 0) throw new Error('CIDR array is empty')
|
|
165
|
+
// Pick a random CIDR network
|
|
166
|
+
const network = cidr[Math.floor(Math.random() * cidr.length)];
|
|
167
|
+
// dbg('randomCIDRIp:network', network)
|
|
168
|
+
// Get the range of IPs in this CIDR
|
|
169
|
+
const start = network.first().toBigInt()
|
|
170
|
+
// dbg('randomCIDRIp:first', network.first().toString(),start)
|
|
171
|
+
const end = network.last().toBigInt();
|
|
172
|
+
// dbg('randomCIDRIp:last', network.last().toString(),end)
|
|
173
|
+
let range : any = end-start
|
|
174
|
+
// dbg('randomCIDRIp:first:last', start, end)
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
// Generate a random Long between the start and end
|
|
178
|
+
// if start-end > Maximum integer number
|
|
179
|
+
// we need to use BigInt
|
|
180
|
+
if (range > BigInt(Number.MAX_SAFE_INTEGER)) range=(Number.MAX_SAFE_INTEGER)
|
|
181
|
+
|
|
182
|
+
const randomBigInt = BigInt(Math.floor(Math.random() * (Number(range) + 1))) + start;
|
|
183
|
+
// dbg('randomBigInt', randomBigInt)
|
|
184
|
+
|
|
185
|
+
// Convert the BigInt back to an IP address
|
|
186
|
+
const randomIp = ip6addr.parse(randomBigInt)
|
|
187
|
+
// dbg('randomCIDRIp', randomIp.toString())
|
|
188
|
+
|
|
189
|
+
return new IPAddress(randomIp.toString())
|
|
190
|
+
}
|
|
191
|
+
|
|
89
192
|
public serialize(): string {
|
|
90
193
|
if (this.kind() === 4) {
|
|
91
194
|
// zero pad ipv4
|
|
@@ -118,10 +221,6 @@ export class IPAddress {
|
|
|
118
221
|
return ip6.normalize(this._ip.toString())
|
|
119
222
|
}
|
|
120
223
|
|
|
121
|
-
public abbreviated(): string {
|
|
122
|
-
if (this.kind() === 4) return this._ip.toString()
|
|
123
|
-
return ip6.abbreviate(this._ip.toString())
|
|
124
|
-
}
|
|
125
224
|
|
|
126
225
|
private padIp6(): string {
|
|
127
226
|
const hextets = this.normalized().split(':') // we need to have the full form
|
package/tsconfig.json
CHANGED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
declare module 'ip6addr' {
|
|
2
|
+
export interface ToStringOpts {
|
|
3
|
+
format?: "auto" | "v4" | "v4-mapped" | "v6" | undefined;
|
|
4
|
+
zeroElide?: boolean | undefined;
|
|
5
|
+
zeroPad?: boolean | undefined;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export interface AddrAttributes {
|
|
9
|
+
ipv4Bare:boolean;
|
|
10
|
+
ipv4Mapped: boolean;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface Addr {
|
|
14
|
+
_attrs: AddrAttributes;
|
|
15
|
+
kind: () => "ipv4" | "ipv6";
|
|
16
|
+
toString: (opts?: ToStringOpts) => string;
|
|
17
|
+
toBuffer: (buff?: Uint8Array) => Uint8Array;
|
|
18
|
+
toLong: () => number;
|
|
19
|
+
toBigInt: () => bigint;
|
|
20
|
+
offset: (num: number) => Addr | null;
|
|
21
|
+
compare: (other: string | Addr) => number;
|
|
22
|
+
clone: () => Addr;
|
|
23
|
+
and: (input: string | Addr) => Addr;
|
|
24
|
+
or: (input: string | Addr) => Addr;
|
|
25
|
+
not: () => Addr;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface AddrRange {
|
|
29
|
+
contains: (input: string | Addr) => boolean;
|
|
30
|
+
first: () => Addr;
|
|
31
|
+
last: () => Addr;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export interface CIDR extends AddrRange {
|
|
35
|
+
broadcast: () => Addr;
|
|
36
|
+
compare: (other: string | CIDR) => number;
|
|
37
|
+
prefixLength: (format?: "auto" | "v4" | "v6") => number;
|
|
38
|
+
address: () => Addr;
|
|
39
|
+
toString: (opts?: ToStringOpts) => string;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function compare(addr1: string | Addr, addr2: string | Addr): number;
|
|
43
|
+
|
|
44
|
+
export function compareCIDR(cidr1: string | CIDR, cidr2: string | CIDR): number;
|
|
45
|
+
|
|
46
|
+
export function createAddrRange(begin: string | Addr, end: string | Addr): AddrRange;
|
|
47
|
+
|
|
48
|
+
export function createCIDR(addr: string | Addr, len?: number): CIDR;
|
|
49
|
+
|
|
50
|
+
export function parse(input: string | number | Addr | BigInt): Addr;
|
|
51
|
+
|
|
52
|
+
}
|