Skip to content

Instantly share code, notes, and snippets.

@theTd
Last active May 11, 2019 08:02
Show Gist options
  • Save theTd/2d9991c219882d9f0a2a413ee6422757 to your computer and use it in GitHub Desktop.
Save theTd/2d9991c219882d9f0a2a413ee6422757 to your computer and use it in GitHub Desktop.
const ip = require("ip");
const fs = require("fs");
const rl = require("readline");
// https://www.regextester.com/93987
var cidrPattern = /^([0-9]{1,3}\.){3}[0-9]{1,3}(\/([0-9]|[1-2][0-9]|3[0-2]))?$/;
function readSourceFromStdin(callbcak) {
let source = {};
let input = rl.createInterface({
input: process.stdin
});
input.on("line", (line) => {
if (cidrPattern.exec(line)) {
source.push(line);
} else {
console.warn("[!] unrecognized route: " + line);
}
});
input.on("close", () => callbcak(source));
}
function readSourceFromFile(filename, callback) {
let source = Array();
let rs = fs.createReadStream(filename);
let input = rl.createInterface({
input: rs
});
input.on("line", (line) => {
if (cidrPattern.exec(line)) {
source.push(line);
} else {
console.warn("[!] unrecognized route: " + line);
}
});
input.on("close", () => callback(source));
}
function ip2int32ip(addr) {
let buffer = ip.toBuffer(addr);
return (buffer[0] << 24) + (buffer[1] << 16) + (buffer[2] << 8) + buffer[3];
}
function int32ip2ip(int32) {
return ((int32 >> 24) & 0xFF) + "." + ((int32 >> 16) & 0xFF) + "."
+ ((int32 >> 8) & 0xFF) + "." + (int32 & 0xFF);
}
function flattenRoutes(source, callback) {
let flatten = Array();
for (route of source) {
let subnet = ip.cidrSubnet(route);
int32ip = ip2int32ip(subnet.networkAddress);
let mask = subnet.subnetMaskLength;
flatten.push({ "int32ip": int32ip, "mask": mask });
}
callback(flatten);
}
function mergeRelative(flatten) {
let result = Array();
let previous;
return new Promise(resolve => {
for (entry of flatten) {
if (!previous) {
previous = entry;
continue;
}
if (previous.mask == entry.mask) {
// mask equal
let mask = previous.mask;
if (((previous.int32ip >> (32 - mask)) & 1) == 0){
// can merge
if (
(previous.int32ip >> (32 - mask)) + 1 ==
(entry.int32ip >> (32 - mask))
) {
// connected, merge
result.push({ "int32ip": previous.int32ip, "mask": mask - 1 });
previous = null;
continue;
}
}
}
// cannot merge or not connected or mask not equal
result.push(previous);
previous = entry;
}
// handle final
if (previous) {
result.push(previous);
}
resolve(result);
});
}
let args = process.argv;
if (args.length < 2 || args.length > 3) {
console.error("[x] Usage: remotemerge.js [file_of_routes]");
process.exit(-1);
}
let sourceReceiver = function (source) {
flattenRoutes(source, async function (flatten) {
let changed = false;
let result = flatten;
let lastResultSize = result.length;
do {
result = await mergeRelative(result);
changed = result.length != lastResultSize;
console.log(`${lastResultSize} -> ${result.length}`);
lastResultSize = result.length;
} while (changed);
// fin
(function (result) {
let finResult = Array();
for (entry of result) {
finResult.push(`${int32ip2ip(entry.int32ip)}/${entry.mask}`);
}
let ws = fs.createWriteStream("merged");
for (line of finResult) {
ws.write(line + "\n");
}
ws.end();
})(result);
});
}
if (args.length == 3) {
try {
source = readSourceFromFile(args[2], sourceReceiver);
} catch (error) {
console.error("[x] error opening file: " + error);
process.exit(-1);
}
} else {
source = readSourceFromStdin(sourceReceiver);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment