IPy-IPv4和IPv6地址处理模块学习笔记

在日常网络规划中,会有很多关于IP地址的分配规划问题,如果是手动分配,在量很大的情况下,容易出错。而利用IPy这个python模块,可以很容易实现对iP地址的分配等操作。

以下是对IPy模块学习的一个记录。

IPy模块简介

主要用处:

IPy-用于处理IPv4和IPv6地址和网络的类和工具。

IPy相关:

IPy源码: https://github.com/autocracy/python-ipy/

IPy类和方法

IPy主要有如下类和方法:

dir(IPy)
Out[8]: 
['INT_TYPES',  
 'IP',
 'IPSet',
 'IPV6_MAP_MASK',
 'IPV6_TEST_MAP',
 'IPint',
 'IPv4ranges',
 'IPv6ranges',
 'MAX_IPV4_ADDRESS',
 'MAX_IPV6_ADDRESS',
 'STR_TYPES',
 '_BitTable',
 '__builtins__',
 '__cached__',
 '__doc__',
 '__file__',
 '__loader__',
 '__name__',
 '__package__',
 '__spec__',
 '__version__',
 '_checkNetaddrWorksWithPrefixlen',
 '_checkNetmask',
 '_checkPrefix',
 '_count0Bits',
 '_count1Bits',
 '_countFollowingZeros',
 '_intToBin',
 '_ipVersionToLen',
 '_netmaskToPrefixlen',
 '_parseAddressIPv6',
 '_prefixlenToNetmask',
 '_remove_subprefix',
 'bisect',
 'collections',
 'intToIp',
 'parseAddress',
 'sys',
 'types',
 'xrange']

其中有IPint,IP,IPSet是三个类。

一般都使用IP类,IP类是IPint的代替,IP类继承IPint类。

INT_TYPES,IPV6_MAP_MASK,IPV6_TEST_MAP,IPv4ranges, IPv6ranges,MAX_IPV4_ADDRESS,MAX_IPV6_ADDRESS,STR_TYPES这都是定义的常量。

IPint类 class IPint(object):

处理返回整数的IP地址。

因为IP类继承自IPint,所以IPint类中的方法在IP类中同样适用。

下面会记录常用方法。

__init__(self, data, ipversion=0, make_net=0)

  • data可以是常见的IPv4和IPv6地址的各种表现形式。支持前缀表示,IP段表示,小数点掩码表示,单个IP等。

    也可以输入10进制的进制,2进制的地址等。

  • ipversion可以制定地址的版本,版本为4或者6,输入其他会报错。

  • mask_net如果是为Ture,则可以通过指定掩码来分配IP地址。

测试如下:

>>> print(IP('127.0.0.0/8'))
127.0.0.0/8
>>> print(IP('127.0.0.0/255.0.0.0'))
127.0.0.0/8
>>> print(IP('127.0.0.0-127.255.255.255'))
127.0.0.0/8
>>> print(IP('127.0.0.1/255.0.0.0', make_net=True))
127.0.0.0/8
[39]: from IPy import IPint
ip = IPint('192.168.1.0/24',make_net=True)
ip
Out[41]: IPint('192.168.1.0/24')
for x in ip:
    print(x)
    
3232235776
3232235777  #返回的是整数类型的IP地址。
3232235778
3232235779
3232235780
...

常用方法:

#实例化一个IP地址
ip = IPint('192.168.1.0/24')
ip.int() #返回第一个长整型的IP地址
Out[52]: 3232235776
ip.version() #返回ip的版本号
Out[53]: 4
ip.prefixlen() #返回掩码长度
Out[54]: 24
ip.net()  #返回第一个长整型的IP地址
Out[55]: 3232235776
ip.broadcast() #返回长整型的广播地址
Out[56]: 3232236031
-----------------------------------------

_printPrefix(self, want): #按输入的want打印掩码
ip._printPrefix(0) #want == 0,None,什么也不返回
Out[58]: ''
ip._printPrefix(1) #want == 1, 返回前缀形式的掩码
Out[59]: '/24'
ip._printPrefix(2) #want == 2,返回小数点的掩码
Out[60]: '/255.255.255.0'
ip._printPrefix(3) #want == 3,返回网络号的最后一个地址
Out[61]: '-192.168.1.255'
    
ipv6 = IPint('2003::/64')

ipv6._printPrefix
Out[70]: <bound method IPint._printPrefix of IPint('2003::/64')>
ipv6._printPrefix(0)
Out[71]: ''
ipv6._printPrefix(1)
Out[72]: '/64'
ipv6._printPrefix(2)
Out[73]: '/ffff:ffff:ffff:ffff:0000:0000:0000:0000'
ipv6._printPrefix(3)
Out[74]: '-2003:0000:0000:0000:ffff:ffff:ffff:ffff'

--------------------------------------
#可以将IP地址转化为多种类型的字符串。
ipv6.strBin() #返会IPv4或者IPv6的2进制形式字符串
Out[79]: '00100000000000110000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
ipv6.strCompressed() #返会简写的形式的地址,主要针对IPv6有效果
Out[80]: '2003::/64'
ipv6.strDec() #返会10进制的地址形式
Out[81]: '42550872755692912415807417417958686720'
ipv6.strFullsize() #返会完整形式的地址格式。
Out[82]: '2003:0000:0000:0000:0000:0000:0000:0000/64'
ipv6.strHex() #返会16进制形式的地址
Out[83]: '0x20030000000000000000000000000000'
ipv6.strNetmask() #返会掩码长度
Out[84]: '/64'
ipv6.strNormal(wantprefixlen = None) #可以按输入的wantprefixlen来转化为字符串
ipv6.strNormal(wantprefixlen = 0) #不输出掩码
Out[92]: '2003:0:0:0:0:0:0:0'
ipv6.strNormal((wantprefixlen = 1) #输出前缀掩码
Out[93]: '2003:0:0:0:0:0:0:0/64'
ipv6.strNormal((wantprefixlen = 2) #输出网络掩码
Out[94]: '2003:0:0:0:0:0:0:0/ffff:ffff:ffff:ffff:0000:0000:0000:0000'
ipv6.strNormal(3) #输出地址段
Out[95]: '2003:0:0:0:0:0:0:0-2003:0000:0000:0000:ffff:ffff:ffff:ff
 ---------------------------------------
               
ip.iptype() #返会IP地址的类型
Out[98]: 'PRIVATE'
ip2 = IPint('1.1.1.1')
ip2.iptype()
Out[100]: 'PUBLIC'
print(IP('127.0.0.1').iptype())
Out[101]: LOOPBACK
print(IP('::1').iptype())
Out[102]: LOOPBACK
print(IP('2001:0658:022a:cafe:0200::1').iptype())
Out[103]: ALLOCATED RIPE NCC
-----------------------------------------
               
ip.netmask() #返会整型形式的掩码
Out[104]: 4294967040
ip.strNetmask() #返会字符串形式的掩码
Out[105]: '255.255.255.0'
ip.len()  #返会子网的长度
Out[106]: 256
IP('10.1.1.0/28').len()
Out[108]: 16
              
----------------------------------------
ip.__getitem__(1) #返会网络号中第i个地址。
Out[120]: 3232235777
ip.__getitem__(2)
Out[121]: 3232235778
ip.__getitem__(3)
Out[122]: 3232235779
              
ip
Out[124]: IPint('192.168.1.0/24')
ip.__contains__('192.168.1.1') #判断一个地址是否在这个网段中
Out[125]: True
ip.__contains__('192.168.2.1')
Out[126]: False   
'192.168.1.1' in ip
Out[127]: True
'192.168.3.1' in ip
Out[128]: False

------------------------------------------
#检查给定IP地址是否在这个实例化的IP地址返回内               
def overlaps(self, item):
#如果不重叠,返会0;
#如果给定地址在这个实例化的IP地址范围内返会1.
#如果给定地址在不这个实例化的IP地址范围内返会-1.                    
IP('192.168.1.0/24').overlaps('192.168.1.254')
Out[131]: 1
IP('192.168.1.0/24').overlaps('192.168.2.254')
Out[132]: 0
IP('192.168.1.0/24').overlaps('192.168.0.0/16')
Out[134]: -1
             
----------------------------------------
#实例化后的两个IP地址可以进行比较,IPv4总是小于IPv6地址,第一个地址总是小的。 掩码短的小于掩码长的
#如果self < other,返会-1, 如果self == other,返会0,如果self > other,返会1.

ip
Out[158]: IPint('192.168.1.0/24')
ip2
Out[159]: IPint('1.1.1.1')
ip3
Out[160]: IP('192.0.0.0/8')
ipv6
Out[161]: IPint('2003::/64')
ip4 = IP('192.168.1.0/24')
ip.__cmp__(ip4)
Out[163]: 0
ip.__cmp__(ip3)
Out[166]: 1
ip.__cmp__(ipv6)
Out[168]: -1
ip > ip2
Out[177]: True
ip < ip2
Out[178]: False
ip == i
              

IP类,class IP(IPint):

IP类继承自IPint,所以IP类具有IPint的所有方法。

IP类主要处理IP地址和网络。IP类与IPint相比,返会的不再是整数型值,而是网络形式的字符串。

ipint = IPint('192.168.1.0/24')
ip = IP('192.168.1.0/24')
ipint.net() 
Out[197]: 3232235776
ip.net()   #返回网络地址
Out[198]: IP('192.168.1.0')
ip.broadcast() #返会广播地址
Out[199]: IP('192.168.1.255')
ipint.broadcast()
Out[200]: 3232236031
ip.netmask()  #返会网络掩码
Out[201]: IP('255.255.255.0')
ip.reverseName()
Out[207]: '1.168.192.in-addr.arpa.'
ip.reverseNames()  #返会用于反向查找的列表值。
Out[208]: ['1.168.192.in-addr.arpa.']
IP('213.221.112.224/30').reverseNames()

Out[209]: 
['224.112.221.213.in-addr.arpa.',
 '225.112.221.213.in-addr.arpa.',
 '226.112.221.213.in-addr.arpa.',
 '227.112.221.213.in-addr.arpa.']
IP('::1:2').reverseNames()
Out[211]: ['2.0.0.0.1.ip6.arpa.']
IP('213.221.112.224/30').reverseName() #返会用于反向查找的一个字符串,而不是列表。
Out[217]: '224-227.112.221.213.in-addr.arpa.'

IP('10.1.1.1').make_net(24) #对于单个IP地址,可以加上掩码,返会新的IP地址实例
Out[231]: IP('10.1.1.0/24')
ip
Out[235]: IP('192.168.1.0/24')
ip.__getitem__(1) #返回网络号中的地i个地址
Out[236]: IP('192.168.1.1')

IPSet类,IPSet(collections.MutableSet):

可以用来对网段进行汇总。

IPSet仅仅接收IP实例的对象。

IPSet的值是存在列表中。

from IPy import IPSet
from IPy import IP
ipset = IPSet() #实例化一个IPSet对象
ipset.add(IP('192.168.1.0/24')) #给IPSet集合中添加一个网段
ipset
Out[301]: IPSet([IP('192.168.1.0/24')])
ipset.add([IP('192.168.2.0/24'),IP('192.168.3.0/24')])
ipset  #以列表形式添加多个网段
Out[303]: IPSet([IP('192.168.1.0/24'), IP('192.168.2.0/23')])
ipset.add(IP('192.168.0.0/16'))
ipset#会对已有的所有网段进行汇总
Out[308]: IPSet([IP('192.168.0.0/16')])  
ipset.discard(IP('192.168.1.0/24')) #移除汇总网段中某个网段
ipset
Out[310]: IPSet([IP('192.168.0.0/24'), IP('192.168.2.0/23'), IP('192.168.4.0/22'), IP('192.168.8.0/21'), IP('192.168.16.0/20'), IP('192.168.32.0/19'), IP('192.168.64.0/18'), IP('192.168.128.0/17')])
n [317]: ipset2 = IPSet()

ipset2.add(IP('192.168.1.0/24'))
ipset2
Out[319]: IPSet([IP('192.168.1.0/24')])
ipset.isdisjoint(ipset2) #判断某个集合中的网段是否在现有集合网段中
Out[320]: True
ipset3 = IPSet()
ipset3.add(IP('192.168.2.0/24'))
ipset.isdisjoint(ipset3)
Out[323]: False
ipset.__contains__(IP('192.168.2.0/24')) #判断某个网段是否在现有汇总网段中
Out[335]: True

IPy中的其他常用方法:

def _parseAddressIPv6(ipstr): #将IPv6字符串解析为十进制的整型数据
ipv6 = IPy._parseAddressIPv6('1080:200C::1')
ipv6
Out[345]: 21932911918296378927538433929194242049
IP(ipv6) 
Out[346]: IP('1080:200c::1')
    
def parseAddress(ipstr, ipversion=0):#解析IP地址
IPy.parseAddress('192.168.1.1')
Out[348]: (3232235777, 4)
IPy.parseAddress('123.132')#不够的后面加0补齐
Out[349]: (2072248320, 4)

IPy.intToIp(3232235777, version=4)
Out[351]: '192.168.1.1'

def intToIp(ip, version): #将整型的IP地址转化为字符串IP地址
IPy.intToIp(3232235777, version=6)
Out[352]: '0000:0000:0000:0000:0000:0000:c0a8:0101'
    
def _intToBin(val): #将int型的地址转化为二进制
IPy._intToBin(13241)
Out[360]: '11001110111001'

利用IPy写的小程序:

批量分配指定掩码和分配个数的IPv4或者IPv6地址:

通过下面的程序,可以指定开始的一个IPv4或者IPv6地址,然后指定掩码,指定需要生成的网段个数,就可以通过程序批量分配地址。

地址输出格式,可以根据需要,灵活定义。

# -*- coding: utf-8 -*-
"""
Created on Sun Dec  1 21:51:11 2019

@author: cao
"""

import IPy

def get_ip_list(begin_ip, count, netmask):
    ip_list = '' #用来存放生成的IP地址
    begin_ip = IPy.IP(begin_ip)
    ip_list += str(begin_ip) + '\n' #将第一个地址放入ip_列表中
    if begin_ip.version() == 4:
        for i in range(count):
            ip = IPy.IP(begin_ip)
            new_ip = IPy.IP(ip.ip + 2 ** (32 - netmask))
            begin_ip =  str(new_ip)
            ip_list += begin_ip + '\n'
    else:
        for i in range(count):
            ipv6 = IPy.IP(begin_ip)
            new_ipv6 = IPy.IP(ipv6.ip + 2 ** (128 - netmask))
            begin_ip =  str(new_ipv6)
            ip_list += begin_ip + '\n'
    return ip_list

if __name__ == "__main__":
    ipv6_list  = get_ip_list(begin_ip = '2002::', count=10, netmask=64)
    print('批量分配业务IPv6地址:')
    print('============================')
    print(ipv6_list)
    
    ipv6_list2  = get_ip_list(begin_ip = 'FD00:0:2e3f::', count=10, netmask=127)
    print('批量分配互联IPv6地址:')
    print('============================')
    print(ipv6_list2)
    
    ip_list = get_ip_list(begin_ip='192.168.1.0', count=10,netmask=24)
    print('批量分配业务IPv4地址:')
    print('============================')
    print(ip_list)
    
    ip_list2 = get_ip_list(begin_ip='192.168.2.0', count = 10, netmask=30)
    print('批量分配互联IPv4地:')
    print('============================')
    print(ip_list2)

程序运行结果:

批量分配业务IPv6地址:
============================
2002::
2002:0:0:1::
2002:0:0:2::
2002:0:0:3::
2002:0:0:4::
2002:0:0:5::
2002:0:0:6::
2002:0:0:7::
2002:0:0:8::
2002:0:0:9::
2002:0:0:a::

批量分配互联IPv6地址:
============================
fd00:0:2e3f::
fd00:0:2e3f::2
fd00:0:2e3f::4
fd00:0:2e3f::6
fd00:0:2e3f::8
fd00:0:2e3f::a
fd00:0:2e3f::c
fd00:0:2e3f::e
fd00:0:2e3f::10
fd00:0:2e3f::12
fd00:0:2e3f::14

批量分配业务IPv4地址:
============================
192.168.1.0
192.168.2.0
192.168.3.0
192.168.4.0
192.168.5.0
192.168.6.0
192.168.7.0
192.168.8.0
192.168.9.0
192.168.10.0
192.168.11.0

批量分配互联IPv4地:
============================
192.168.2.0
192.168.2.4
192.168.2.8
192.168.2.12
192.168.2.16
192.168.2.20
192.168.2.24
192.168.2.28
192.168.2.32
192.168.2.36
192.168.2.40

可将批量生成的IP地址直接复制到Excel表格,或者文件中,用作后续批量生成网络设备配置等。

按固定格式批量分配掩码为64位的IPv6地址:

在网络规划中,需要给业务分配IPv6地址时,假设掩码都是64。同时需要给出IPv6对应的网关地址。

以下程序,给出一个开始的IPv6地址,然后指定count需要分配多少个地址。就会打印出指定数量的IPv6地址,同时给错每个地址对应的指定的网关地址。

# -*- coding: utf-8 -*-
"""
Created on Tue Nov 26 16:04:36 2019

@author: cao
"""

#批量计算业务网段,默认按掩码64位计算

import IPy


#按冒号分割后,判断段是否满足4位,不是前面补零
#这个是为了分下来地址格式比较规整。可以不需要。
def add_0(tmp):
    if len(tmp) == 3:
        tmp = '0' + tmp
    elif len(tmp) == 2:
        tmp = '00' + tmp
    elif len(tmp) == 1:
        tmp = '000' + tmp
    else:
        pass
    return tmp

#传入一个IPv6地址,进项每段0的填充
def ipv6_format(ipv6):
    tmp_ip = ''
    for i in ipv6.split(':'):
        if(len(i) == 0):
            continue
        if(i == '0'): 
            tmp_ip += '0:'
            continue
        tmp_ip += add_0(i) + ':'
    return tmp_ip + ':'

#获取业务网段IPv6对应的网关地址
def ipv6_GW(ipv6_list):
    ip_list_gw = ''
    for ip_net in ipv6_list.split('\n'):
        if(len(ip_net) == 0):
            break
        ip_list_gw += ip_net + 'FFFF\n'
    return ip_list_gw
    

if __name__ == "__main__":
    begin_ip = 'FD00:0:0004:009B::'
    ipv6_count = 10
    ipv6_list = begin_ip + '\n' #业务网段地址
    ipv6_gw = '' #业务网段对应的网关

    for i in range(ipv6_count):
        ipv6 = IPy.IP(begin_ip)
        new_ipv6 = str.upper(str(IPy.IP(ipv6.ip + 2**64)))
        begin_ip = ipv6_format(new_ipv6)
        ipv6_list += begin_ip + '\n'

    print(ipv6_list)

    ipv6_gw = ipv6_GW(ipv6_list)
    print(ipv6_gw)

程序运行结果:

FD00:0:0004:009B::
FD00:0:0004:009C::
FD00:0:0004:009D::
FD00:0:0004:009E::
FD00:0:0004:009F::
FD00:0:0004:00A0::
FD00:0:0004:00A1::
FD00:0:0004:00A2::
FD00:0:0004:00A3::
FD00:0:0004:00A4::
FD00:0:0004:00A5::

FD00:0:0004:009B::FFFF
FD00:0:0004:009C::FFFF
FD00:0:0004:009D::FFFF
FD00:0:0004:009E::FFFF
FD00:0:0004:009F::FFFF
FD00:0:0004:00A0::FFFF
FD00:0:0004:00A1::FFFF
FD00:0:0004:00A2::FFFF
FD00:0:0004:00A3::FFFF
FD00:0:0004:00A4::FFFF
FD00:0:0004:00A5::FFFF

得到想要地址后,可以直接复制到Excel表格中,或者直接写到文件中。用于后续批量生成配置。

至于输出的IPv6地址格式,或者IPv4地址格式,可以根据需要灵活控制。


参考资料:

https://pypi.org/project/IPy/

IPy源码: https://github.com/autocracy/python-ipy/

https://zhuanlan.zhihu.com/p/64791275

你可能感兴趣的:(Python)