Генерация случайного IP-адреса из подсети в JS - PullRequest
0 голосов
/ 17 декабря 2018

Я пытаюсь сгенерировать случайный IP-адрес с учетом подсети IP-адреса.Есть много ресурсов, доступных для генерации случайного IP-адреса, но я требую, чтобы он генерировался из определенной подсети.

Я использовал модуль npm с именем netmask - однакореализация абсолютно не элегантна.Кто-нибудь может дать несколько полезных указателей на это?

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 голосов
/ 17 декабря 2018

На основании ответа 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')
0 голосов
/ 18 декабря 2018

(я ждал, чтобы вы опубликовали свою собственную функцию, прежде чем публиковать мою.)

Вот моя собственная версия, основанная на ответе emix.

Я пыталсячтобы сделать его наиболее понятным с помощью циклов и функций массива.

1-й фрагмент

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

⋅ ⋅ ⋅

2-й фрагмент (расширенный, на мой взгляд)

// 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'));
0 голосов
/ 17 декабря 2018

Это довольно легко без каких-либо дополнительных зависимостей, хотя я не даю вам точного ответа, но представляю, как работает 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.Избегайте хоста только с 1 s (1111.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));
}
...