首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何从Python中的IP范围列表中生成随机IP地址?

问如何从Python中的IP范围列表中生成随机IP地址?
EN

Stack Overflow用户
提问于 2021-12-17 02:30:57
回答 5查看 1K关注 0票数 0

如何从Python中的IP范围列表中生成随机IP地址?

我尝试使用ipaddress模块创建一个ip地址列表,然后将其随机化。

代码语言:javascript
复制
ipRanges = [
    "103.112.2.0/24"
]
network = ipaddress.IPv4Network(random.choice(ipRanges))
ip= random.choice(list(network))

这是我目前的密码。它工作了,但它使用了很多RAM,因为它需要以更好的方式存储在列表中?

EN

回答 5

Stack Overflow用户

发布于 2021-12-17 04:27:23

与其生成所有可能的IP并选择一个IP,不如将IP威胁为32位整数,使用网络地址作为固定的最重要比特,并生成随机主机部分。

代码语言:javascript
复制
import ipaddress, random, struct

def random_ip(network):
    network = ipaddress.IPv4Network(network)
    network_int, = struct.unpack("!I", network.network_address.packed) # make network address into an integer
    rand_bits = network.max_prefixlen - network.prefixlen # calculate the needed bits for the host part
    rand_host_int = random.randint(0, 2**rand_bits - 1) # generate random host part
    ip_address = ipaddress.IPv4Address(network_int + rand_host_int) # combine the parts 
    return ip_address.exploded

这给了你:

代码语言:javascript
复制
>>> for _ in range(4):
    print(random_ip("103.112.2.0/24"))

103.112.2.143
103.112.2.120
103.112.2.75
103.112.2.59

>>> for _ in range(4):
    print(random_ip("103.112.164.0/22"))

103.112.165.120
103.112.164.219
103.112.165.159
103.112.166.232

>>> for _ in range(4):
    print(random_ip("103.112.164.0/255.255.252.0"))

103.112.165.17
103.112.165.210
103.112.167.184
103.112.166.171

>>> for _ in range(4):
    print(random_ip("0.0.0.0/0"))

115.231.216.55
252.123.19.92
218.198.69.183
179.73.234.254
票数 3
EN

Stack Overflow用户

发布于 2021-12-17 04:15:33

您可以使用网络掩码和来自IPNetwork对象的地址来构造范围内的IP地址:

代码语言:javascript
复制
import ipaddress
import random

# Pick a CIDR block to use
ipRanges = [
    "103.112.2.0/24",
    "1.0.0.0/8",
]
network = ipaddress.IPv4Network(random.choice(ipRanges))

# Get the netmask and address as a list of bytes
netmask = network.netmask.packed
address = network.network_address.packed

# Operate on each byte of the address
picked = b''
for netmask_byte, address_byte in zip(netmask, address):
    # Pick a random value
    val = random.randint(0, 255)
    # Or in the random bits not in the netmask with the bits in the address in the netmask
    picked += bytes([((255 ^ netmask_byte) & random.randint(0, 255)) | address_byte])
# Turn the result into an IP address
picked = ipaddress.IPv4Address(picked)

print(picked)
票数 2
EN

Stack Overflow用户

发布于 2021-12-17 05:50:19

我假设您只对IPv4地址感兴趣,因为这就是您在示例中所显示的。如果您也需要执行IPv6地址,答案就会变得更加复杂。

如果您可以将IP地址的范围转换为整数范围,那么进行随机选择就会容易得多。幸运的是,ipaddress使这个简单,即使它不是简单的。

代码语言:javascript
复制
import ipaddress
import struct

def ip_range(addr_spec):
    ip = ipaddress.ip_network(addr_spec)
    base = struct.unpack('>I', ip.network_address.packed)[0]
    mask = struct.unpack('>I', ip.netmask.packed)[0]
    extent = 0x100000000 - mask
    return range(base, base+extent)

因此,现在您可以将列表转换为更容易处理的内容:

代码语言:javascript
复制
ranges = [ip_range(spec) for spec in ipRanges]

您可能希望选择每个IP地址的可能性相等,因此您需要制作一个与每个范围的大小相对应的权重表。

代码语言:javascript
复制
weights = [len(r) for r in ranges]

从这里开始,这个过程很简单。首先随机选择一个范围,然后在范围内随机选择一个特定的地址。

代码语言:javascript
复制
import random

rng = random.choices(ranges, weights=weights)[0]
ip_int = random.choice(rng)
ip_addr = ipaddress.ip_address(ip_int)

这样做效率更高的原因是,从Python3开始,range返回的是range对象,而不是列表。这个对象是超优化的;它只存储传入的参数,而实现接口所需的只是一点简单的数学--没有必要预先计算所有的值并将它们保存在内存中。例如,len(range)大致是(stop - start) // step。range[i]大致是start + i * step。显然,完整的实现比这要复杂一些,但是内存使用和时间复杂度仍然是O(1)。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/70387792

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档