如何从一个IPrange/subnet获取随机IP?

How to get a random IP from an IP range/subnet?

假设我的 IP 范围是:“52.93.50.128/32” 我如何获得该范围内的随机 IP 地址?

Ruby 更可取。

我认为 this snippet using this gem 应该可行,简单的方法是计算 IP 范围,然后 select 一个新的

#!/usr/bin/env ruby

require 'ipaddr'

family = Socket::AF_INET

subnet_range = IPAddr.new("52.93.50.128/32", family).to_range
from = subnet_range.first(2).last
to = IPAddr.new(subnet_range.last.to_i - 2, family)

puts "From: #{from}"
puts "To: #{to}"

random_ip = IPAddr.new(rand(from.to_i..to.to_i), family)

puts "Random IP: #{random_ip}"

Let's suppose, I have the IP Range: "52.93.50.128/32" How can I get a random IP address that in that range?

这很简单。这是一个主机地址,换句话说,它根本不是一个范围,它只是一个地址。所以,你只需 return 再次输入:

def random_ip_address_from_subnet(subnet) = subnet

但是,我们可以通过考虑主机地址和 RFC 3021 点对点链接的具体情况来做一些更智能的事情。

我将在这里假设您只需要主机地址,而不需要网络或广播地址。

require 'ipaddr'

def random_ip_from_subnet(subnet)
  ipaddr = IPAddr.new(subnet)
  range = host_address_range(ipaddr)
  range.to_a.sample
end

def host_address_range(subnet)
  range = subnet.to_range

  return range if rfc3021?(subnet) || host?(subnet)

  Range.new(range.begin.succ, IPAddr.new(range.end.to_i - 1, subnet.family))
end

def host?(subnet) = subnet.ipv4? && subnet.prefix == 32 || subnet.ipv6? && subnet.prefix == 128
def rfc3021?(subnet) = subnet.ipv4? && subnet.prefix == 31

require 'minitest/autorun'

class TestRandomIp < Minitest::Test
  def setup
    @subnet_address1 = '52.93.50.129/30'
    @subnet_address2 = '52.93.50.130/30'
    @subnet_address_network = '52.93.50.128/30'
    @subnet_address_broadcast = '52.93.50.131/30'
    @subnet_address1_ip = IPAddr.new(@subnet_address1).succ
    @subnet_address2_ip = @subnet_address1_ip.succ
    @subnet_address_network_ip = IPAddr.new(@subnet_address_network)
    @subnet_address_broadcast_ip = @subnet_address2_ip.succ

    @host_address = '52.93.50.128/32'
    @host_address_ip = IPAddr.new(@host_address)

    @rfc3021_address1 = '52.93.50.128/31'
    @rfc3021_address2 = '52.93.50.129/31'
    @rfc3021_address1_ip = IPAddr.new(@rfc3021_address1)
    @rfc3021_address2_ip = IPAddr.new(@rfc3021_address2).succ
  end

  def test_that_host_address_range_works_with_normal_subnet_addresses
    range1 = host_address_range(@subnet_address1_ip)
    assert_equal @subnet_address1_ip, range1.begin
    assert_equal @subnet_address2_ip, range1.end
    assert_equal @subnet_address1_ip..@subnet_address2_ip, range1
    assert_equal 2, range1.count

    range2 = host_address_range(@subnet_address2_ip)
    assert_equal @subnet_address1_ip, range2.begin
    assert_equal @subnet_address2_ip, range2.end
    assert_equal @subnet_address1_ip..@subnet_address2_ip, range2
    assert_equal 2, range2.count

    range3 = host_address_range(@subnet_address_network_ip)
    assert_equal @subnet_address1_ip, range3.begin
    assert_equal @subnet_address2_ip, range3.end
    assert_equal @subnet_address1_ip..@subnet_address2_ip, range3
    assert_equal 2, range3.count

    range4 = host_address_range(@subnet_address_broadcast_ip)
    assert_equal @subnet_address1_ip, range4.begin
    assert_equal @subnet_address2_ip, range4.end
    assert_equal @subnet_address1_ip..@subnet_address2_ip, range4
    assert_equal 2, range4.count

    assert_equal range1, range2
    assert_equal range1, range3
    assert_equal range1, range4
    assert_equal range2, range3
    assert_equal range2, range4
    assert_equal range3, range4
  end

  def test_that_host_address_range_works_with_host_addresses
    range = host_address_range(@host_address_ip)
    assert_equal @host_address_ip, range.begin
    assert_equal @host_address_ip, range.end
    assert_equal @host_address_ip..@host_address_ip, range
    assert_equal 1, range.count
  end

  def test_that_host_address_range_works_with_rfc3021_addresses
    range1 = host_address_range(@rfc3021_address1_ip)
    assert_equal @rfc3021_address1_ip, range1.begin
    assert_equal @rfc3021_address2_ip, range1.end
    assert_equal @rfc3021_address1_ip..@rfc3021_address2_ip, range1
    assert_equal 2, range1.count

    range2 = host_address_range(@rfc3021_address2_ip)
    assert_equal @rfc3021_address1_ip, range2.begin
    assert_equal @rfc3021_address2_ip, range2.end
    assert_equal @rfc3021_address1_ip..@rfc3021_address2_ip, range2
    assert_equal 2, range2.count

    assert_equal range1, range2
  end

  def test_that_random_ip_from_subnet_works_with_normal_subnet_addresses
    100.times do
      random_ip = random_ip_from_subnet(@subnet_address1)
      assert [@subnet_address1_ip, @subnet_address2_ip].include?(random_ip)
    end

    100.times do
      random_ip = random_ip_from_subnet(@subnet_address2)
      assert [@subnet_address1_ip, @subnet_address2_ip].include?(random_ip)
    end

    100.times do
      random_ip = random_ip_from_subnet(@subnet_address_network)
      assert [@subnet_address1_ip, @subnet_address2_ip].include?(random_ip)
    end

    100.times do
      random_ip = random_ip_from_subnet(@subnet_address_broadcast)
      assert [@subnet_address1_ip, @subnet_address2_ip].include?(random_ip)
    end
  end

  def test_that_random_ip_from_subnet_works_with_rfc3021_addresses
    100.times do
      random_ip = random_ip_from_subnet(@rfc3021_address1)
      assert [@rfc3021_address1_ip, @rfc3021_address2_ip].include?(random_ip)
    end

    100.times do
      random_ip = random_ip_from_subnet(@rfc3021_address2)
      assert [@rfc3021_address1_ip, @rfc3021_address2_ip].include?(random_ip)
    end
  end

  def test_that_random_ip_from_subnet_works_with_host_addresses
    100.times do
      random_ip = random_ip_from_subnet(@host_address)
      assert_equal @host_address_ip, random_ip
    end
  end
end