网络工程师学Python——处理IP地址的利器 IPy
考过思科和华为认证的朋友们,想必对IP编址和计算烂熟于心。IP地址的规划,不仅是网络设计中的重中之重,还会直接影响网络的转发效率和扩展性。
很多从事网络工作多年的朋友,免不了要在工作中重复计算诸如网段、子网掩码、广播地址、子网数。还要判断IP网段的包含关系和对多个IP地址段进行汇总等等。
如果计算数据量特别大,不仅费时费力,还容易出错。
正好Python有一个非常强大的第三方库IPy,可以帮助我们完成此类计算任务。大家可以参见IPy的项目地址: https:// github.com/haypo/python -ipy/
下面我就把自己对IPy使用的一些小技巧分享给各位网络爱好者。
IPy是python的第三方库,需要手动安装。
安装方法如下:
我的系统环境是MacOS,直接打开终端就能安装。
步骤是:1、打开终端;2、输入:pip list查看自己安装的库,如果有,就不需要安装了。3、如果没有IPy,则输入pip install IPy即可(Windows类似:直接打开命令提示符输入)
pip list
若有IPy,则不需要安装,若没有安装IPy则输入:pip install IPy
一、使用IPy中的IP方法迅速格式化
(1)查看地址是IPv4还是IPv6
>>> from IPy import IP
>>> IP('10.0.0.0/8').version()
>>> IP('::1').version()
>>>
(2)格式化输出IPv4和IPv6的地址
>>> from IPy import IP
>>> print(IP('127.0.0.1'))
127.0.0.1
>>> print(IP('10'))
10.0.0.0
>>> print(IP('0x7f000001'))
127.0.0.1
>>> print(IP(0x7f000001))
127.0.0.1
>>> print(IP('1080:0:0:0:8:800:200C:417A'))
1080::8:800:200c:417a
>>> print(IP('1080::8:800:200C:417A'))
1080::8:800:200c:417a
>>> print(IP('::1'))
>>> print(IP('::13.1.68.3'))
::d01:4403
(3)子网掩码及网段前缀转换
>>> from IPy import IP
>>> print(IP('1.0.0.0/8'))
1.0.0.0/8
>>> print(IP('1.0.0.0/255.0.0.0'))
1.0.0.0/8
>>> print(IP('1.0.0.0-1.255.255.255'))
1.0.0.0/8
(4)已知IP地址的子网掩码,快速求出该地址所在的网段
>>> from IPy import IP
>>> print(IP('127.0.0.1/255.0.0.0', make_net=True))
127.0.0.0/8
>>> print(IP('12.1.0.1').make_net('255.255.255.224'))
12.1.0.0/27
二、IPy中的IP方法格式化的高级用法
(1)IPy中IP地址格式转换的高级用法
>>> from IPy import IP
>>> ip_address = IP('192.168.100.3')
>>> ip.reverseNames()
>>> ip_address.reverseNames() #反向解析地址格式
['3.100.168.192.in-addr.arpa.']
>>> ip_address.iptype() #解析地址的“公网、私网属性” 192.168.100.0为私有网段
'PRIVATE'
>>> ip_address.int() #把192.168.100.3转换成整数
3232261123
>>> ip_address.strHex() #把192.168.100.3转换成十六进制数
'0xc0a86403'
>>> ip_address.strBin() #把192.168.100.3转换成二进制数
'11000000101010000110010000000011'
>>> print(IP(0xc0a86403)) #把十六进制数0xc0a86403转换成点分十进制192.168.100.3
192.168.100.3
(2)IPy将IP地址转换成字符串的方法:
可以通过strNomal方法指定不同的wantprefixlen参数定制不同输出类型的网段输出为字符串。
wantprefixlen = 0 ,无返回的意思
wantprefixlen = 1 ,返回前缀的类型
wantprefixlen = 2 ,返回网段/子网掩码的类型
wantprefixlen = 3 ,返回IP地址范围的类型
>>> from IPy import IP
>>> IP('10.0.0.0/24').strNormal()
'10.0.0.0/24'
>>> IP('10.0.0.0/24').strNormal(0)
'10.0.0.0'
>>> IP('10.0.0.0/24').strNormal(1)
'10.0.0.0/24'
>>> IP('10.0.0.0/24').strNormal(2)
'10.0.0.0/255.255.255.0'
>>> IP('10.0.0.0/24').strNormal(3)
'10.0.0.0-10.0.0.255'
三、 使用IPy中的IP方法处理IP地址段的包含关系
涉及处理两个网段是否包含的关系,IPy中的IP方法也提供了这个功能,他会返回一个布尔值告诉我们是否包含:
(1)判断两个IP网段的大小:
>>> from IPy import IP
>>> IP('1.1.1.0/24') < IP('2.2.2.0/24')
True
(2)判断一个IP地址是否包含于另一个IP网段
>>> from IPy import IP
>>> '192.168.100.1' in IP('192.168.100.0/27')
True
(3)判断一个IP网段是否被另一个IP网段包含
>>> from IPy import IP
>>> IP('192.168.2.0/24') in IP('192.168.0.0/23')
False
>>> from IPy import IP
>>> IP('192.168.1.0/24') in IP('192.168.0.0/23')
True
四、使用IPy中的IPSet方法汇总不连续的IP网段
IPy中还提供了IPSet这个神奇的方法来达成汇总网段的目的。非常灵活。下面来看看方法:
>>> from IPy import IP, IPSet
>>> IPSet([IP('192.168.0.0/30'), IP('192.168.0.4/30'),IP('192.168.0.8/30'), IP('192.168.0.12/30')])
IPSet([IP('192.168.0.0/28')])
#! /usr/bin/env python3
#! _*_ coding: utf-8 _*_
from IPy import IP, IPSet
a = IP('192.168.0.0/17')
a1 = IP('192.168.0.64/27')
a2 = IP('192.168.0.96/27')
a3 = IP('192.168.0.128/27')
a4 = IP('192.168.0.160/27')
a5 = IP('192.168.0.192/27')
a6 = IP('192.168.0.224/27')
b = IP('192.168.1.0/27')
c = IP('192.168.2.0/27')
d = IP('192.168.4.0/27')
d1 = IP('192.168.4.32/27')
d2 = IP('192.168.4.128/25')
e = IP('192.168.5.0/27')
e1 = IP('192.168.5.32/27')
summary = IPSet([a1, a2, a3, a4, a5, a6, b, c, d, d1, d2, e, e1])
print(summary)
注意IPSet的数据类型是集合Set中的列表。
这样我们就能用IPSet这个方法来快速的计算IP地址汇总的问题。
最后,为坚持看完这篇文章的小伙伴,分享一个我自己做的IP地址处理小程序的源码:
#! /usr/bin/env python3
#! _*_ coding: utf-8 _*_
本程序是一个用于处理IP地址的程序
from IPy import IP, IPSet
def ip_belongs_prefix(ip_address, ip_prefix):
#定义了一个判断IP地址是否从属于另外一个IP网段的方法
ip_net_b = IP(ip_prefix)
return print(ip_address in ip_net_b)
#返回一个布尔值,如果IP地址从属于另一个网段就返回 True,如果不属于,就返回 False
def prefix_belongs_prefix(ip_prefix_1, ip_prefix_2):
#定义了一个判断IP网段是否从属于另外一个IP网段的方法
ip_prefix_a = IP(ip_prefix_1)
ip_prefix_b = IP(ip_prefix_2)
return print(ip_prefix_a in ip_prefix_b)
#返回一个布尔值,如果IP地址从属于另一个网段就返回 True,如果不属于,就返回 False
def summary_ip(ip_prefix_times):
#定一个使用IPSet汇总网段的方法
ip_prefix_times = int(ip_prefix_times)
#接收选择d后的输入的数字,并且把input中str的类型转换为int类型
ip_list = [None] * ip_prefix_times
#利用接收到的次数来定义列表元素的个数,用于存放输入的IP网段
code = 0
while code < ip_prefix_times:
print('您第:%d 次输入的 ip 前缀,比如 192.168.1.0/24 。 您的输入是: ' % (code + 1))
ip = input(': ')
ip_list[code] = IP(ip)
code = code + 1
#使用while循环,创建列表中元素的索引,用来存放接收的IP网段
return print(IPSet(ip_list))
#使用IPSet求出汇总的网段
key = input('按键盘的字母 y 开始本程序,您的选择是: ')
while key == 'y' or key == 'Y':
print('***************** 欢迎使用 IP Prefix 处理程序 ***************')
print('* 按 a 开始 IP Prefix 前缀网段处理功能,列出网段详细信息 *')
print('* 按 b 开始判断 IP 地址是否属于一个 IP 地址段 *')
print('* 按 c 开始判断 一个 IP 地址段,是否从属于另外一个 IP 地址段*')
print('* 按 d 启动 IP 网段地址汇总功能 *')
print('*********************************************** @ by惰惰猴 **')
choose_key = input('请输入您的选择, a/b/c/d : ')
if choose_key == 'a' or choose_key == 'A':
print('***** 您选择了a, Prefix 前缀网段处理功能,列出网段详细信息 *****\n')
ip_name = input('请输入IP前缀,比如 192.168.1.0/24 。您的输入是: ')
ip_addr = IP(ip_name)
if len(ip_addr) > 1:
print('ip 前缀的网段为: %s' % ip_addr.net())
print('ip 前缀子网掩码为 : %s' % ip_addr.netmask())
print('ip 前缀广播地址为 : %s' % ip_addr.broadcast())
print('ip 前缀的reverse : %s' % ip_addr.reverseNames()[0])
print('ip 前缀地址个数为: %s' % len(ip_addr))
else:
print('hex_addr is : %s' % ip_addr.strHex)
print('bin_addr is : %s' % ip_addr.strBin)
elif choose_key == 'b' or choose_key == 'B':
print('***** 您选择了b, 判断 IP 地址是否属于一个 IP 地址段 *****\n')
ipaddress = input('请输入一个ip地址,比如 192.168.1.1 。您的输入为 : ')
ipprefix = input('请输入一个ip网段前缀,比如 192.168.1.0/24 。您的输入为 : ')
ip_belongs_prefix(ipaddress, ipprefix)
elif choose_key == 'c' or choose_key == 'C':
print('***** 您选择了c, 判断 一个 IP 地址段 是否 从属于另外一个 IP 地址段 *****\n')
ipprefix_1 = input('请输入一个ip网段前缀,比如 192.168.1.0/24 。您的输入为 : ')
ipprefix_2 = input('请输入另外一个ip网段前缀,比如 192.168.0.0/16 。您的输入为 : ')
prefix_belongs_prefix(ipprefix_1, ipprefix_2)
elif choose_key == 'd' or choose_key == 'D':
print('***** 您选择了d, 启动 IP 网段地址汇总功能 *****\n')
summary_prefix = input('请输入您要汇总网段的数量,比如您要汇总5个网段,就输入5. 您的选择是 : ')
summary_ip(summary_prefix)
else:
print('没有这个选项 , 请在 a,b,c,d 的四个选项中选择')
print('***** 继续使用本程序,青按字母 y 退出本程序,请按字母 n 或者其他键 *****')
key = input('继续本程序 或 退出本程序 Y/N : ')
运行起来是这个样子的:
再来一段基于面向对象的:
#! /usr/bin/env python3
#! _*_ coding: utf-8 _*_
from IPy import IP, IPSet
class IpProgram(object):
this ip address or ip prefix compute program
def __init__(self, ip_prefix_1, ip_prefix_2):
self.ip_prefix_1 = ip_prefix_1
self.ip_prefix_2 = ip_prefix_2
def ip_list(self):
self.ip_prefix_1 = IP(self.ip_prefix_1)
print('子网掩码是: %s' % self.ip_prefix_1.strNormal(2))
print('可用地址段: %s' % self.ip_prefix_1.strNormal(3))
print('ip地址的版本是 : IPv%s' % self.ip_prefix_1.version())
print('ip前缀的反向解析 : %s' % self.ip_prefix_1.reverseNames()[0])
print('ip前缀地址个数为: %s' % len(self.ip_prefix_1))
def ip_mask_to_ip_prefix(self):
self.ip_prefix_1 = self.ip_prefix_1
self.ip_prefix_2 = self.ip_prefix_2
print('ip地址转换成前缀是: %s' % IP(self.ip_prefix_1).make_net(self.ip_prefix_2))
def ip_belongs_prefix(self):
self.ip_prefix_1 = self.ip_prefix_1
self.ip_prefix_2 = IP(self.ip_prefix_1)
print('ip地址:{0} 属于 ip网段:{1} 为:{2}'.format(self.ip_prefix_1, self.ip_prefix_2, self.ip_prefix_1 in self.ip_prefix_2))
def ip_prefix_belongs_other_prefix(self):
self.ip_prefix_1 = IP(self.ip_prefix_1)
self.ip_prefix_2 = IP(self.ip_prefix_1)
print('ip网段:{0} 属于 ip网段:{1} 为:{2}'.format(self.ip_prefix_1, self.ip_prefix_2, self.ip_prefix_1 in self.ip_prefix_2))
class IpSummary(object):
this IP address summary compute
def __init__(self, codes):
self.codes = codes
def summary(self):
self.codes = int(self.codes)
ip_list = [None] * self.codes
code = 0
while code < self.codes:
print('您第:%d 次输入的 ip 前缀,比如 192.168.1.0/24 。 您的输入是: ' % (code + 1))
ip = input(': ')
ip_list[code] = IP(ip)
code = code + 1
print(IPSet(ip_list))
key = input('按键盘的字母 y 开始本程序,您的选择是: ')
while key == 'y' or key == 'Y':
print('***************** 欢迎使用 IP Prefix 处理程序 ***************')
print('* 按 a 开始 IP Prefix 前缀网段处理功能,列出网段详细信息 *')
print('* 按 b 开始判断 IP 地址是否属于一个 IP 地址段 *')
print('* 按 c 开始判断 一个 IP 地址段,是否从属于另外一个 IP 地址段*')
print('* 按 d 输入一个 IP 地址、IP 地址的子网掩码 换算该地址前缀 *')
print('* 按 e 启动 IP 网段地址汇总功能 *')
print('*********************************************** @ by惰惰猴 **')
choose_key = input('请输入您的选择, a/b/c/d/e : ')
if choose_key == 'a' or choose_key == 'A':
ipaddress_1 = input('请输入您要处理的网段,例如 192.168.1.0/24: ')
ip1 = IpProgram(ipaddress_1 , None)
ip1.ip_list()
elif choose_key == 'b' or choose_key == 'B':
print('***** 您选择了b, 判断 IP 地址是否属于一个 IP 地址段 *****\n')
ipaddress_2 = input('请输入一个ip地址,比如 192.168.1.1 。您的输入为 : ')
ipprefix_2 = input('请输入一个ip网段前缀,比如 192.168.1.0/24 。您的输入为 : ')
ip2 = IpProgram(ipaddress_2, ipprefix_2)
ip2.ip_belongs_prefix()
elif choose_key == 'c' or choose_key == 'C':
print('***** 您选择了c, 判断 一个 IP 地址段 是否 从属于另外一个 IP 地址段 *****\n')
ipprefix_3 = input('请输入一个ip网段前缀,比如 192.168.1.0/24 。您的输入为 : ')
ipprefix_3 = input('请输入另外一个ip网段前缀,比如 192.168.0.0/16 。您的输入为 : ')
ip3 = IpProgram(ipprefix_3, ipprefix_3)
ip3.ip_prefix_belongs_other_prefix()
elif choose_key == 'd' or choose_key == 'D':
print('***** 您选择了d, 输入一个地址的 ip地址和子网掩码,换算该地址前缀 *****\n')
ipprefix_4 = input('请输入一个ip地址,比如 192.168.1.1 。您的输入为 : ')
ipmask_4 = input('请输入这个ip地址的子网掩码,比如 255.255.255.0 您的输入为 : ')
ip4 = IpProgram(ipprefix_4, ipmask_4)
ip4.ip_mask_to_ip_prefix()
elif choose_key == 'e' or choose_key == 'e':
print('***** 您选择了d, 启动 IP 网段地址汇总功能 *****\n')
times = input('请输入您要汇总网段的数量,比如您要汇总5个网段,就输入5. 您的选择是 : ')