Last active
May 11, 2019 08:02
-
-
Save theTd/2d9991c219882d9f0a2a413ee6422757 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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