New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

cidr-tools

Package Overview
Dependencies
Maintainers
1
Versions
93
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

cidr-tools - npm Package Compare versions

Comparing version 1.2.2 to 2.0.0

355

index.js
"use strict";
const execa = require("execa");
const fs = require("mz/fs");
const path = require("path");
const tempfile = require("tempfile");
const cidrTools = module.exports = {};
const IPCIDR = require("ip-cidr");
const isCidr = require("is-cidr");
const ipv6Normalize = require("ipv6-normalize");
const naturalCompare = require("string-natural-compare");
const Address4 = require("ip-address").Address4;
const Address6 = require("ip-address").Address6;
const BigInteger = require("jsbn").BigInteger;
const net = require("net");
const merge = path.join(__dirname, "cidr-merge.py");
const exclude = path.join(__dirname, "cidr-exclude.py");
const expand = path.join(__dirname, "cidr-expand.py");
const bits = {
"v4": 32,
"v6": 128,
};
function parseNets(nets) {
if (typeof nets === "string") {
return nets;
} else if (Array.isArray(nets)) {
return nets.join("\n");
function bigint(numberstring) {
return new BigInteger(numberstring);
}
function parse(str) {
if (isCidr(str)) {
return new IPCIDR(cidrTools.normalize(str));
} else {
const version = net.isIP(str);
if (version) {
return new IPCIDR(cidrTools.normalize(`${str}/${bits[`v${version}`]}`));
} else {
throw new Error(`Network is not a CIDR or IP: ${str}`);
}
}
}
module.exports.merge = function(nets) {
return new Promise(function(resolve, reject) {
if (!Array.isArray(nets) && typeof nets !== "string") {
return reject(new Error("Expected an array or string, not " + nets));
function format(number, v) {
const cls = v === "v6" ? Address6 : Address4;
if (number.constructor.name !== "BigInteger") number = bigint(number);
return cidrTools.normalize(cls.fromBigInteger(number).address);
}
function prefix(size, v) {
return bits[v] - (bigint(String(size)).toString(2).match(/0/g) || []).length;
}
function overlap(a, b) {
const aStart = a.start({type: "bigInteger"});
const bStart = b.start({type: "bigInteger"});
const aEnd = a.end({type: "bigInteger"});
const bEnd = b.end({type: "bigInteger"});
// aaa
// bbb
if (aStart.compareTo(bEnd) > 0) return false; // a starts after b
// aaa
// bbb
if (bStart.compareTo(aEnd) > 0) return false; // b starts after a
return true;
}
// exclude b from a end return remainder numbers
function exclude(a, b, v) {
const aStart = a.start({type: "bigInteger"});
const bStart = b.start({type: "bigInteger"});
const aEnd = a.end({type: "bigInteger"});
const bEnd = b.end({type: "bigInteger"});
// compareTo returns negative if left is less than right
const parts = [];
// aaa
// bbb
// aaa
// bbb
if (aEnd.compareTo(bStart) < 0 || aStart.compareTo(bEnd) > 0) {
return [a.cidr];
}
// aaa
// bbb
if (aStart.compareTo(bStart) === 0 && aEnd.compareTo(bEnd) === 0) {
return [];
}
// aa
// bbbb
if (aStart.compareTo(bStart) > 0 && aEnd.compareTo(bEnd) < 0) {
return [];
}
// aaaa
// bbbb
// aaaa
// bb
if (aStart.compareTo(bStart) < 0 && aEnd.compareTo(bEnd) <= 0) {
parts.push({
start: aStart,
end: bStart.subtract(bigint("1")),
});
}
// aaa
// bbb
// aaaa
// bbb
if (aStart.compareTo(bStart) >= 0 && aEnd.compareTo(bEnd) > 0) {
parts.push({
start: bEnd.add(bigint("1")),
end: aEnd,
});
}
// aaaa
// bb
if (aStart.compareTo(bStart) < 0 && aEnd.compareTo(bEnd) > 0) {
parts.push({
start: aStart,
end: bStart.subtract(bigint("1")),
});
parts.push({
start: bEnd.add(bigint("1")),
end: aEnd,
});
}
const remaining = [];
for (const part of parts) {
for (const subpart of subparts(part, v)) {
remaining.push(formatPart(subpart, v));
}
}
const netfile = tempfile(".net");
// return remaining;
return cidrTools.merge(remaining);
}
fs.writeFile(netfile, parseNets(nets)).then(function() {
execa.stdout(merge, [netfile]).then(function(stdout) {
resolve(stdout.split("\n").filter(net => Boolean(net)));
fs.unlink(netfile);
}).catch(function(err) {
resolve(err);
fs.unlink(netfile);
});
}).catch(reject);
});
function biggestPowerOfTwo(num) {
if (num === 0) return 0;
return Math.pow(2, num.toString(2).length - 1);
}
function subparts(part) {
const size = bigint(String(diff(part.end, part.start)));
const biggest = bigint(String(biggestPowerOfTwo(Number(size.toString()))));
if (size.equals(biggest)) return [part];
const start = part.start.add(biggest).divide(biggest).multiply(biggest);
const end = start.add(biggest).subtract(bigint("1"));
let parts = [{start, end}];
// // additional subnets on left side
if (!start.equals(part.start)) {
parts = parts.concat(subparts({start: part.start, end: start.subtract(bigint("1"))}));
}
// additional subnets on right side
if (!end.equals(part.end)) {
parts = parts.concat(subparts({start: part.start, end: start.subtract(bigint("1"))}));
}
return parts;
}
function diff(a, b) {
if (a.constructor.name !== "BigInteger") a = bigint(a);
if (b.constructor.name !== "BigInteger") b = bigint(b);
return Number((a.add(bigint("1"))).subtract(b).toString());
}
function formatPart(part, v) {
const d = diff(part.end, part.start);
return format(part.start, v) + "/" + prefix(d, v);
}
cidrTools.normalize = (cidr) => {
const cidrVersion = isCidr(cidr);
if (cidrVersion === 4) {
return cidr;
} else if (cidrVersion === 6) {
const [ip, prefix] = cidr.split("/");
return `${ipv6Normalize(ip)}/${prefix}`;
}
const ipVersion = net.isIP(cidr);
if (ipVersion === 4) {
return cidr;
} else if (ipVersion === 6) {
return ipv6Normalize(cidr);
}
throw new Error(`Invalid network: ${cidr}`);
};
module.exports.exclude = function(basenets, excludenets) {
return new Promise(function(resolve, reject) {
if (!Array.isArray(basenets) && typeof basenets !== "string") {
return reject(new Error("Expected an array or string, not " + basenets));
function mapNets(nets) {
const maps = {v4: {}, v6: {}};
for (const net of nets) {
const start = net.start({type: "bigInteger"}).toString();
const end = net.end({type: "bigInteger"}).toString();
const v = `v${isCidr(net)}`;
if (!maps[v][start]) maps[v][start] = {};
if (!maps[v][end]) maps[v][end] = {};
if (maps[v][start].start) {
maps[v][start].start += 1;
} else {
maps[v][start].start = 1;
}
if (!Array.isArray(excludenets) && typeof excludenets !== "string") {
return reject(new Error("Expected an array or string, not " + excludenets));
if (maps[v][end].end) {
maps[v][end].end += 1;
} else {
maps[v][end].end = 1;
}
}
return maps;
}
const basefile = tempfile(".net");
const excludefile = tempfile(".net");
cidrTools.merge = function(nets) {
nets = (Array.isArray(nets) ? nets : [nets]).map(parse);
const maps = mapNets(nets);
fs.writeFile(basefile, parseNets(basenets)).then(function() {
fs.writeFile(excludefile, parseNets(excludenets)).then(function() {
execa.stdout(exclude, [basefile, excludefile]).then(function(stdout) {
resolve(stdout.split("\n").filter(net => Boolean(net)));
fs.unlink(basefile);
fs.unlink(excludefile);
}).catch(function(err) {
resolve(err);
fs.unlink(basefile);
fs.unlink(excludefile);
});
}).catch(reject);
}).catch(reject);
});
const merged = {v4: [], v6: []};
const start = {v4: null, v6: null};
const end = {v4: null, v6: null};
for (const v of ["v4", "v6"]) {
const numbers = Object.keys(maps[v]).sort(naturalCompare);
let depth = 0;
for (const [index, number] of numbers.entries()) {
const marker = maps[v][number];
if (!start[v] && marker.start) {
start[v] = bigint(number);
}
if (marker.end) {
end[v] = bigint(number);
}
if (marker.start) depth += marker.start;
if (marker.end) depth -= marker.end;
if (marker.end && depth === 0 && ((numbers[index + 1] - numbers[index]) > 1)) {
for (const sub of subparts({start: start[v], end: end[v]})) {
merged[v].push(formatPart(sub, v));
}
start[v] = null;
end[v] = null;
} else if (index === (numbers.length - 1)) {
for (const sub of subparts({start: start[v], end: end[v]})) {
merged[v].push(formatPart(sub, v));
}
}
}
}
merged.v4 = merged.v4.sort(naturalCompare);
merged.v6 = merged.v6.sort(naturalCompare);
return merged.v4.concat(merged.v6);
};
module.exports.expand = function(nets) {
return new Promise(function(resolve, reject) {
if (!Array.isArray(nets) && typeof nets !== "string") {
return reject(new Error("Expected an array or string, not " + nets));
cidrTools.exclude = function(basenets, exclnets) {
basenets = Array.isArray(basenets) ? basenets : [basenets];
exclnets = Array.isArray(exclnets) ? exclnets : [exclnets];
basenets = cidrTools.merge(basenets);
exclnets = cidrTools.merge(exclnets);
const bases = {v4: [], v6: []};
const excls = {v4: [], v6: []};
for (const basenet of basenets) {
bases[`v${isCidr(basenet)}`].push(basenet);
}
for (const exclnet of exclnets) {
excls[`v${isCidr(exclnet)}`].push(exclnet);
}
for (const v of ["v4", "v6"]) {
for (const exclcidr of excls[v]) {
const excl = parse(exclcidr);
for (const [index, basecidr] of bases[v].entries()) {
const base = parse(basecidr);
const remainders = exclude(base, excl, v);
bases[v] = bases[v].concat(remainders);
bases[v].splice(index, 1);
}
}
}
const netfile = tempfile(".net");
return bases.v4.concat(bases.v6);
};
fs.writeFile(netfile, parseNets(nets)).then(function() {
execa.stdout(expand, [netfile]).then(function(stdout) {
resolve(stdout.split("\n").filter(net => Boolean(net)));
fs.unlink(netfile);
}).catch(function(err) {
resolve(err);
fs.unlink(netfile);
});
}).catch(reject);
});
cidrTools.expand = function(nets) {
nets = Array.isArray(nets) ? nets : [nets];
let ips = [];
for (const net of cidrTools.merge(nets)) {
ips = ips.concat((new IPCIDR(net)).toArray());
}
return ips.map(cidrTools.normalize);
};
cidrTools.overlap = (a, b) => {
a = parse(a);
b = parse(b);
if (a.address.v4 !== b.address.v4) return false;
return overlap(a, b);
};

33

package.json
{
"name": "cidr-tools",
"version": "1.2.2",
"version": "2.0.0",
"author": "silverwind <me@silverwind.io>",

@@ -18,26 +18,27 @@ "description": "Tools to work with IPv4 and IPv6 CIDR network lists",

"ipv4",
"ipv6"
"ipv6",
"merge",
"exclude",
"expand"
],
"engines": {
"node": ">=4"
"node": ">=8"
},
"files": [
"index.js",
"cidr-merge.py",
"cidr-exclude.py",
"cidr-expand.py",
"install.sh"
"index.js"
],
"dependencies": {
"execa": "^0.9.0",
"ipaddr.js": "^1.6.0",
"mz": "^2.7.0",
"tempfile": "^2.0.0"
"ip-address": "^5.8.9",
"ip-cidr": "^2.0.0",
"ipv6-normalize": "^1.0.1",
"is-cidr": "^3.0.0",
"jsbn": "^1.1.0",
"string-natural-compare": "^2.0.2"
},
"devDependencies": {
"ava": "^0.25.0",
"eslint": "^4.18.2",
"eslint-config-silverwind": "^1.0.37",
"updates": "^2.3.1"
"eslint": "^5.7.0",
"eslint-config-silverwind": "^2.0.9",
"updates": "^4.5.2",
"ver": "^3.0.0"
}
}

@@ -7,6 +7,6 @@ # cidr-tools

With `python3`, `node` and `npm` available:
## Install
```bash
$ npm i --save cidr-tools
$ npm i cidr-tools
```

@@ -18,16 +18,7 @@ ## Example

cidrTools.merge(['1.0.0.0/24', '1.0.1.0/24']).then(r => {
console.log(r);
//=> ['1.0.0.0/23']
});
cidrTools.exclude(['::1/127'], ['::1/128']).then(r => {
console.log(r);
//=> ['::/128']
});
cidrTools.expand(['2001:db8::/126']).then(r => {
console.log(r);
//=> ['2001:db8::', '2001:db8::1', '2001:db8::2', '2001:db8::3']
});
cidrTools.merge(['1.0.0.0/24', '1.0.1.0/24']); //=> ['1.0.0.0/23']
cidrTools.exclude(['::1/127'], ['::1/128']) //=> ['::/128']
cidrTools.expand(['2001:db8::/126']) //=> ['2001:db8::', '2001:db8::1', '2001:db8::2', '2001:db8::3']
cidrTools.overlap('1.0.0.0/24', '1.0.0.128/25') //=> true
cidrTools.normalize('0:0:0:0:0:0:0:0/0') //=> '::/0'
```

@@ -37,19 +28,36 @@

All functions take CIDR addresses or single IP addresses. On single addresses, a prefix of `/32` or `/128` is assumed. Function that return networks will return a merged and properly sorted set of networks with IPv4 sorted before IPv6.
### cidrTools.merge(networks)
- `networks` *String* or *Array*: A list of IPv4 and IPv6 networks.
- Returns: A promise that resolves to an array of merged networks.
- `networks` *String* or *Array*: One or more CIDR or IP addresses.
Returns an array of merged networks.
### cidrTools.exclude(baseNetworks, excludeNetworks)
- `baseNetworks` *String* or *Array*: A list of IPv4 and IPv6 networks.
- `excludeNetworks` *Array*: A list of IPv4 and IPv6 networks to exclude from `baseNetworks`.
- Returns: A promise that resolves to an array of merged remaining networks.
- `baseNetworks` *String* or *Array*: One or more CIDR or IP addresses.
- `excludeNetworks` *String* or *Array*: One or more CIDR or IP addresses to exclude from `baseNetworks`.
Returns an array of merged remaining networks.
### cidrTools.expand(networks)
- `networks` *String* or *Array*: A list of IPv4 and IPv6 networks.
- Returns: A promise that resolves to an array of individual IPs contained in the networks.
- `networks` *String* or *Array*: One or more CIDR or IP addresses.
Returns an array of individual IPs contained in the networks.
### cidrTools.overlap(networkA, networkB)
- `networkA` *String*: A CIDR or IP addresses.
- `networkB` *String*: A CIDR or IP addresses.
Returns a boolean that indicates if the networks overlap (intersect) each other.
### cidrTools.normalize(network)
- `network` *String*: A CIDR or IP addresses.
Returns a normalized representation of a IP or CIDR. Will not include a prefix on IPs.
© [silverwind](https://github.com/silverwind), distributed under BSD licence.
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc