如何在Python中从IP范围列表生成所有可能的IP地址?

7

假设我有一个文本文件,其中包含一堆IP范围,如下所示:

x.x.x.x-y.y.y.y
x.x.x.x-y.y.y.y
x.x.x.x-y.y.y.y
x.x.x.x-y.y.y.y
x.x.x.x-y.y.y.y

x.x.x.x是起始值,y.y.y.y是结束值。

如何在Python中将这些IP范围转换为新文本文件中的所有可能IP地址?

注:这个问题不同于我的任何先前的问题。我在先前的问题中问了“如何从CIDR表示法生成所有可能的IP地址”,但在这里我问的是“如何从IP范围列表生成”。这些是不同的事情。


这只是一个 IPv4 地址文件吗?还是里面也有 IPv6 的地址? - will
4个回答

15

此函数返回从开始到结束的所有IP地址:

def ips(start, end):
    import socket, struct
    start = struct.unpack('>I', socket.inet_aton(start))[0]
    end = struct.unpack('>I', socket.inet_aton(end))[0]
    return [socket.inet_ntoa(struct.pack('>I', i)) for i in range(start, end)]

这些都是自己构建它的基石:

>>> import socket, struct
>>> ip = '0.0.0.5'
>>> i = struct.unpack('>I', socket.inet_aton(ip))[0]
>>> i
5
>>> i += 1
>>> socket.inet_ntoa(struct.pack('>I', i))
'0.0.0.6'

例子:

ips('1.2.3.4', '1.2.4.5')
['1.2.3.4', '1.2.3.5', '1.2.3.6', '1.2.3.7', ..., '1.2.3.253', '1.2.3.254', '1.2.3.255', '1.2.4.0', '1.2.4.1', '1.2.4.2', '1.2.4.3', '1.2.4.4']

读取文件

在您的情况下,您可以按照以下方式从文件中读取:

with open('file') as f:
    for line in f:
        start, end = line.strip().split('-')
        # ....

为什么这个答案没有被标记为已接受的答案?@Leadri在Python中从文件中读取文本是一项基本任务,你可以找到数百篇其他帖子来展示如何完成这个任务。原始问题在这里得到了明确的回答,至于其余部分,你需要通过Google/DuckDuckGo自己努力去解决。 - Zahra
这很棒-谢谢。建议开始和结束的输入可能会被认为是包含在内的,如果是这样,最后一行将是range(start, end + 1)] - lost

10

只适用于Python 3,针对IPv4,与@User提供的方法类似,但使用新的Python3标准库:ipaddress

IPv4由4个字节表示。因此,下一个IP实际上是下一个数字,一系列IP地址可以表示为一系列整数。

0.0.0.1相当于1

0.0.0.2相当于2

...

0.0.0.255相当于255

0.0.1.0相当于256

0.0.1.1相当于257

代码如下(忽略In []:和Out []:)

In [68]: from ipaddress import ip_address

In [69]: ip_address('0.0.0.1')
Out[69]: IPv4Address('0.0.0.1')

In [70]: ip_address('0.0.0.1').packed
Out[70]: b'\x00\x00\x00\x01'

In [71]: int(ip_address('0.0.0.1').packed.hex(), 16)
Out[71]: 1

In [72]: int(ip_address('0.0.1.0').packed.hex(), 16)
Out[72]: 256

In [73]: int(ip_address('0.0.1.1').packed.hex(), 16)
Out[73]: 257

ip.packed.hex() 返回4字节的十六进制格式,由于它是十六进制的,所以更短(例如:0xff十六进制==255十进制==0b11111111二进制),因此常用于表示字节。int(hex, 16) 返回对应的整数值,因为它更符合人类习惯,可以作为ip_address的输入。

from ipaddress import ip_address

def ips(start, end):
    '''Return IPs in IPv4 range, inclusive.'''
    start_int = int(ip_address(start).packed.hex(), 16)
    end_int = int(ip_address(end).packed.hex(), 16)
    return [ip_address(ip).exploded for ip in range(start_int, end_int)]


ips('192.168.1.240', '192.168.2.5')

返回:

['192.168.1.240',
 '192.168.1.241',
 '192.168.1.242',
 '192.168.1.243',
 '192.168.1.244',
 '192.168.1.245',
 '192.168.1.246',
 '192.168.1.247',
 '192.168.1.248',
 '192.168.1.249',
 '192.168.1.250',
 '192.168.1.251',
 '192.168.1.252',
 '192.168.1.253',
 '192.168.1.254',
 '192.168.1.255',
 '192.168.2.0',
 '192.168.2.1',
 '192.168.2.2',
 '192.168.2.3',
 '192.168.2.4']

1
请注意,此方法不包括IP范围的末尾。例如,对于范围为“1.1.1.1 - 1.1.1.1”的情况,将返回[]而不是可能预期的['1.1.1.1']。要包括末尾,请将列表推导式中的范围更改为range(start_int, end_int + 1) - asgaines

3

试一下这个:

def ip_range(start_ip,end_ip):
start = list(map(int,start_ip.split('.')))
end = list(map(int,end_ip.split('.')))
iprange=[]
while start!=list(map(int,end_ip.split('.'))):
    for i in range(len(start)-1,-1,-1):
        if start[i]<255:
            start[i]+=1
            break
        else:
            start[i]=0
    iprange.append('.'.join(map(str,start)))
return iprange

2
使用ipaddress和range()函数
import ipaddress

print([ipaddress.ip_address(i).exploded for i in range(int(ipaddress.ip_address(first_ip)), int(ipaddress.ip_address(last_ip)))])

1
虽然这段代码可能解决了问题,但是包括解释它如何以及为什么解决了问题将有助于提高您的帖子质量,并可能导致更多的赞。请记住,您正在回答未来读者的问题,而不仅仅是现在提问的人。请[编辑]您的答案以添加解释并指出适用的限制和假设。 - Yunnosch
这并没有回答问题。一旦您拥有足够的声望,您将能够评论任何帖子;相反,提供不需要询问者澄清的答案。- 来自审核 - Naeem Khan
1
你的回答是最好的,也是最容易理解的,与其他人相比。不需要再写一句话了。这个网站应该为开发人员/工程师提供服务。如果一个人连这么简单的一行代码都看不懂,请关掉电脑去做别的事情吧。(然而,你的回答也没有包含结尾,需要在结尾加1,像这样 int(ipaddress.ip_address(last_ip)) + 1。) - Bruce

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接