从 JS 中的子网生成随机 IP 地址
Posted
技术标签:
【中文标题】从 JS 中的子网生成随机 IP 地址【英文标题】:Generate a random IP address from a subnet in JS 【发布时间】:2019-05-17 20:23:25 【问题描述】:我正在尝试在给定 IP 地址子网的情况下生成一个随机 IP 地址。有大量资源可用于生成随机 IP,但我要求它从特定子网中生成。
我使用了一个名为 netmask 的 npm 模块 - 但是实现绝对不优雅。任何人都可以请给出一些巧妙的指针吗?
var netmask = require("netmask").Netmask
var block = new netmask('10.0.0.0/24')
console.log(block) // gives block details
var blockSize = block.size - 1 ;
var randomIndex = Math.floor(Math.random() * blockSize ) +1; // generate a random number less than the size of the block
console.log("randomIndex is: " + randomIndex);
block.forEach(function(ip, long, index)
if(index == randomIndex)
console.log('IP: ' + ip)
console.log('INDEX: ' + index)
// cannot break! this is a forEach :(
);
【问题讨论】:
【参考方案1】:这很容易,无需任何额外的依赖,尽管我没有给你一个确切的答案,但我知道IP's work in general 是如何解决你的问题的。如果你自己做这件事,这一课会更有价值。
我们以10.0.0.0/20
CIDR 为例。让我们将10.0.0.0
转换为位:
00001010.00000000.00000000.00000000
我们去掉 20 位,因为这是从左边开始的网络,所以我们留下了 0000.00000000
用于主机(.
点仅用于可读性):
00001010.00000000.00000000.00000000 Network
XXXXXXXX.XXXXXXXX.XXXX0000.00000000 Strip 20 bits of the subnet
随心所欲地用剩余的位随机排列每个八位字节,例如我们可以得到0101.10001010
。避免使用仅带有1
s (1111.11111111
) 的主机,因为它是broadcast IP,它仍然是有效的 IP,但不适用于主机。将子网部分与主机部分连接起来。我们得到:
// S=Subnet, H=Host
SSSSSSSS.SSSSSSSS.SSSSHHHH.HHHHHHHH
00001010.00000000.00000101.10001010
这是1010 = 10
和0
和101 = 5
和10001010=138
所以最终地址是10.0.5.138
因为写起来很有趣,我可以给你我自己的实现,它不涉及任何字符串操作。如您所见,IPv4 地址是一个2^32
无符号整数。因此我们可以应用基础数学:
let ipv4 =
random: function (subnet, mask)
// generate random address (integer)
// if the mask is 20, then it's an integer between
// 1 and 2^(32-20)
let randomIp = Math.floor(Math.random() * Math.pow(2, 32 - mask)) + 1;
return this.lon2ip(this.ip2lon(subnet) | randomIp);
,
ip2lon: function (address)
let result = 0;
address.split('.').forEach(function(octet)
result <<= 8;
result += parseInt(octet, 10);
);
return result >>> 0;
,
lon2ip: function (lon)
return [lon >>> 24, lon >> 16 & 255, lon >> 8 & 255, lon & 255].join('.');
;
// unit test
console.log(
"192.168.0.35" === ipv4.lon2ip(ipv4.ip2lon('192.168.0.35')) ?
'Test passed' :
'Test failed'
);
for (let i = 0; i < 5; i++)
console.log(ipv4.random('10.0.0.0', 8));
【讨论】:
谢谢你。它有很大帮助!我正在根据您的方法进行模拟。 :) 当然,如果我有帮助,请考虑支持和标记作为解决方案。 谢谢@emix。我根据你解释的方法给出了一个粗略的答案 完美解决方案! 谢谢。二元运算效率更高。路由器和交换机以这种方式运行。【参考方案2】:(我在等你发布自己的函数,然后再发布我的函数。)
这是我自己的版本,基于 emix 的回答。
我尝试使用循环和数组函数使其最容易理解。
1st sn-p
// Function to convert string of numbers to 01010101 with leading zeros
function StrToBlock(str)
return ("00000000" + (+str).toString(2)).slice(-8);
// Function to convert 01010101 to string of numbers
function BlockToStr(block)
return parseInt(block, 2);
// Main function
function GetRandomIP(netmask)
// Split netmask
var netmasks = netmask.split("/");
var maskBlocks = netmasks[0].split(".");
var maskLength = netmasks[1];
// Loop for each address part
var blockBits = '';
maskBlocks.forEach(function(block)
// Convert to bits
blockBits = blockBits + StrToBlock(block);
);
// Here, blockBits is something like 00110101001101010011010100110101
// Loop for each bit
var ipBits = [];
var ipBlocks = [];
for (var i = 0; i < 32; i++)
// If in mask, take the mask bit, else, a random 0 or 1
var bit = (i < maskLength) ? blockBits[i] : Math.round(Math.random());
ipBits.push(bit);
// If block is full, convert back to a decimal string
if (ipBits.length == 8)
ipBlocks.push(BlockToStr(ipBits.join('')));
ipBits = []; // Erase to start a new block
// Return address as string
return ipBlocks.join('.');
// Different tests
console.log(GetRandomIP('255.255.255.0/8'));
console.log(GetRandomIP('255.255.255.0/24'));
console.log(GetRandomIP('10.0.0.0/24'));
⋅ ⋅ ⋅
2nd sn-p (在我看来增强了)
// Function to convert string of numbers to 01010101 with leading zeros
function StrToBlock(str)
return ("00000000" + (+str).toString(2)).slice(-8);
// Function to convert 01010101 to string of numbers
function BlockToStr(block)
return parseInt(block, 2);
// Main function
function GetRandomIP(netmask)
// Split netmask
var netmasks = netmask.split("/");
var maskBlocks = netmasks[0].split(".");
var maskLength = netmasks[1];
// Loop for each of the 4 address parts
var blockBits = '';
maskBlocks.forEach(function(block)
blockBits = blockBits + StrToBlock(block);
);
// Copy mask and then add some random bits
var ipBits = blockBits.substring(0, maskLength);
for (var i = maskLength; i < 32; i++)
ipBits = ipBits + Math.round(Math.random());
// Split and convert back to decimal strings
var ipBlocks = ipBits.match(/.8/g);
ipBlocks.forEach(function(block, i)
ipBlocks[i] = BlockToStr(block);
);
// Return address as string
return ipBlocks.join('.');
// Different tests
console.log(GetRandomIP('255.255.255.0/8'));
console.log(GetRandomIP('255.255.255.0/24'));
console.log(GetRandomIP('10.0.0.0/24'));
【讨论】:
谢谢,感谢您的帮助! @blueren 很高兴它有帮助。在发布我的功能之前,我一直在等待您发布自己的功能。 :) 我添加了另一个版本(因为我更喜欢这个新版本。:p) 我会以不同的方式做这件事。将网络地址转换为一个数字(它是一个 2^32 无符号整数),生成介于 1 和 2 的 11 次方(32 - 掩码 (20))之间的随机数,并对它和子网进行逻辑或。然后再次将号码转换为IP。这是纯粹的数学运算,在这种情况下操作字符串对我来说感觉不自然。 @emix 好吧,也许你可以分享你自己的功能。 :)【参考方案3】:基于 emix 的回答 -
function getIPFromSubnet(subnetRange)
// subnetRange = "10.0.0.0/24"
const subnet = subnetRange.split('/')[0]; // 10.0.0.0
const mask = subnetRange.split('/')[1]; // 24
const ipArray = subnet.split('.'); //["10", "0", "0", "0"]
var ipInBinary = ""; // will contain the binary equivalent of the iP
// for each element in the array, convert from decimal to binary
for (let quad of ipArray)
let octet = parseInt(quad, 10).toString(2)
// we need each octet to be 8 bits. So provide padding for those which are less than 8 bits
// 0101 becomes 00000101
let octetLength = octet.length
if (octetLength < 8)
let octDiff = 8 - octetLength;
octet = "0".repeat(octDiff) + octet
// concat all the octets into a 32 bit binary
ipInBinary = ipInBinary.concat(octet) // 00001010000000000000000000000000
// console.log("ipInBinary: ", ipInBinary);
// strip the subnet from the entire address:
let subnetBinary = ipInBinary.slice(0, mask) // 000010100000000000000000
let hostsBinary = ipInBinary.slice(mask, ipInBinary.length) // 00000000
var randomBinarySubstitute = "";
const randomPool = "10101010101010101010101010101010" //fix this nonsense later.
for (let i = 0; i < 32 - mask; i++)
randomBinarySubstitute += randomPool[Math.floor(Math.random() * ipInBinary.length)]
let newIPBinary = subnetBinary + randomBinarySubstitute;
let finalIP = "";
// split the 32 bit binary IP into an array of 8 bits, each representing an octate
let finalIPArray_binary = newIPBinary.match(/.8/g) // ["00001010", "00000000", "00000000", "10001010"]
// convert the binary quad array to decimal dotted quad
for (let element of finalIPArray_binary)
finalIP = finalIP + "." + parseInt(element, 2);
finalIP = finalIP.replace(/^\./, ""); // remnove the leading .
console.log("FinalIP", finalIP)
return finalIP
getIPFromSubnet('10.0.0.0/16')
【讨论】:
以上是关于从 JS 中的子网生成随机 IP 地址的主要内容,如果未能解决你的问题,请参考以下文章