从JS中的子网生成一个随机IP地址

时间:2018-12-17 12:56:15

标签: javascript npm ip-address ipv4 subnet

我正在尝试在给定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 :(
    }
});

3 个答案:

答案 0 :(得分:4)

这很容易,没有任何其他依赖关系,尽管我没有给您确切的答案,但可以了解IP的总体工作方式以及如何解决您的问题。如果您自己这样做,那么本课将更有价值。

让我们以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。避免只使用11111.11111111)的主机,因为它是广播IP,它仍然是有效的IP,尽管对于主机而言却不是。将子网部分与主机部分连接在一起。我们得到:

// S=Subnet, H=Host
SSSSSSSS.SSSSSSSS.SSSSHHHH.HHHHHHHH
00001010.00000000.00000101.10001010

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));
}

答案 1 :(得分:1)

(我在等您发布我的函数,然后再发布我的函数。)

这是我自己的版本,基于emix的答案。

我试图使用循环和数组函数使其最容易理解。

第一个代码段

// 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'));

⋅ ⋅ ⋅

第二个片段 (我认为已增强)

// 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'));

答案 2 :(得分:0)

基于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')