1. 获取ip/MAC地址等
获取本地ip地址首先想到的命令是ifconfig,然后从结果中提取出ip地址,Python代码如下:
def get_ip():
cmd = "/sbin/ifconfig | grep 'inet addr' | grep -v 127.0.0.1 | awk '{print $2}' | awk -F ':' '{print $2}'"
pip = subprocess.Popen(cmd, shell = True, stdout = subprocess.PIPE)
ip = pip.stdout.read()
return ip
可能大家会觉得这样太山寨或者结果不太可信。而事实上,有一个包可以实现提取ip地址,它就是netifaces。netifaces官网地址是:https://pypi.python.org/pypi/netifaces/,里面有详细的介绍和示例。下面给出使用netifaces取得ip地址的代码:
import netifaces
def get_current_ip():
'''
Using netifaces to fetch the ip address of the current machine.
'''
ips = []
exclude_iface = ['lo']
interfaces = netifaces.interfaces()
for iface in interfaces:
if iface not in exclude_iface:
if netifaces.AF_INET in netifaces.ifaddresses(iface):
addrs = netifaces.ifaddresses(iface)[netifaces.AF_INET] # mac addr: netifaces.AF_LINK
for addr in addrs:
ips.append(info['addr'])
return ips
ips = get_current_ip()
print ips
netifaces.ifaddresses(iface)返回一个字典,其中key为:18,2和30,分别代表协议:AF_LINK、AF_INET(IPV4)和AF_INET6 (IPv6)。上面代码中的addrs为一个列表(因为一台主机可以由多个ip地址),列表中的每个元素是一个字典,包含了广播地址(broadcast)、子网掩码(netmask)和IP地址(addr)。事实上netifaces除了可以查询上述信息,还可以查询物理地址(MAC地址或网卡地址)、网关(使用netifaces.gateways()),网关结果类似于:{'default': {2: ('192.168.1.1', 'eth0')}, 2: [('192.168.1.1', 'eth0', True)]},其中的key 2表示协议AF_INET(IPV4)。
2. 处理ip
取得ip地址后,若要对ip地址进行处理,则要用到subnets包,subnet官网教程,以下是摘取部分:
基本操作
In [1]: from netaddr import *
In [2]: import pprint
In [3]: ip = IPAddress("192.168.2.151")
In [4]: ip.version
Out[4]: 4
In [5]: repr(ip)
Out[5]: "IPAddress('192.168.2.151')"
In [6]: ip
Out[6]: IPAddress('192.168.2.151')
In [7]: str(ip)
Out[7]: '192.168.2.151'
In [8]: '%s' % ip
Out[8]: '192.168.2.151'
In [9]: ip.format()
Out[9]: '192.168.2.151'
可以查看ip地址的其他进制格式:
In [11]: int(ip)
Out[11]: 3232236183L
In [12]: hex(ip)
Out[12]: '0xc0a80297'
In [13]: ip.bin
Out[13]: '0b11000000101010000000001010010111'
In [14]: ip.bits()
Out[14]: '11000000.10101000.00000010.10010111'
In [15]: ip.words == (192,168,2,151)
Out[15]: True
网络/子网
IPNetwork: IPNetwork模块用于处理子网、子网掩码、 CIDR表示的 VLAN或网络In [18]: ip = IPNetwork('192.168.2.151')
In [19]: ip.ip
Out[19]: IPAddress('192.168.2.151')
In [20]: ip.network, ip.broadcast
Out[20]: (IPAddress('192.168.2.151'), IPAddress('192.168.2.151'))
In [21]: ip.size
Out[21]: 1
上述情况下,网络和广播地址是一样的,如果采用CIDR地址块,则:
In [22]: ip = IPNetwork('192.168.2.151/24')
In [23]: ip.ip
Out[23]: IPAddress('192.168.2.151')
In [24]: ip.network, ip.broadcast
Out[24]: (IPAddress('192.168.2.0'), IPAddress('192.168.2.255'))
In [25]: ip.netmask, ip.hostmask
Out[25]: (IPAddress('255.255.255.0'), IPAddress('0.0.0.255'))<pre name="code" class="python">
In [26]: ip.size
Out[26]: 256
上述结果得到了相应的ip地址,子网地址,广播地址,IP掩码和主机号掩码以及该网络容纳ip的数量。对应一个已有的IPNetwork,同样可以更改ip地址和CIDR的前缀:
In [27]: ip = IPNetwork('0.0.0.0/0')
In [28]: ip
Out[28]: IPNetwork('0.0.0.0/0')
In [29]: ip.value = 3221225985
In [30]: ip
Out[30]: IPNetwork('192.0.2.1/0')
In [31]: ip.prefixlen
Out[31]: 0
In [32]: ip.prefixlen=23
In [33]: ip
Out[33]: IPNetwork('192.0.2.1/23')
In [35]: ip.cidr
Out[35]: IPNetwork('192.0.2.0/23')
In [36]: ip.ip.bits()
Out[36]: '11000000.00000000.00000010.00000001'
In [37]: ip.network.bits()
Out[37]: '11000000.00000000.00000010.00000000'
In [38]: ip.netmask.bits()
Out[38]: '11111111.11111111.11111110.00000000'
In [39]: ip.broadcast.bits()
Out[39]: '11000000.00000000.00000011.11111111'
IPv6
netaddr还提供了对IPv6的支持,例如:In [40]: ip = IPAddress(0,6)
In [41]: ip
Out[41]: IPAddress('::')
In [43]: ip = IPNetwork('fe80::dead:beef/64')
In [44]: str(ip), ip.prefixlen, ip.version
Out[44]: ('fe80::dead:beef/64', 64, 6)
In [45]: int(ip.ip)
Out[45]: 338288524927261089654018896845083623151L
In [46]: hex(ip.ip)
Out[46]: '0xfe8000000000000000000000deadbeef'
In [47]: ip.ip.bits()
Out[47]: '1111111010000000:0000000000000000:0000000000000000:0000000000000000:0000000000000000:0000000000000000:1101111010101101:1011111011101111'
In [48]: ip.network, ip.broadcast, ip.netmask, ip.hostmask
Out[48]:
(IPAddress('fe80::'),
IPAddress('fe80::ffff:ffff:ffff:ffff'),
IPAddress('ffff:ffff:ffff:ffff::'),
IPAddress('::ffff:ffff:ffff:ffff'))
IPv6转IPv4
In [50]: IPNetwork('::ffff:192.0.2.1/119').ipv6()
Out[50]: IPNetwork('::ffff:192.0.2.1/119')
In [52]: IPNetwork('::ffff:192.0.2.1/119').ipv6(ipv4_compatible=True)
Out[52]: IPNetwork('::192.0.2.1/119')
In [53]: IPNetwork('::ffff:192.0.2.1/119').ipv4()
Out[53]: IPNetwork('192.0.2.1/23')
In [54]: IPNetwork('::192.0.2.1/119').ipv4()
Out[54]: IPNetwork('192.0.2.1/23')
IP 列表
使用 IPNetwork模块来进行网络操作,事实上,返回的是一个IPNetwork类型,要得到网段内的ip地址列表,需要调用list方法:In [2]: ip = IPNetwork('192.168.2.151/29')
In [3]: type(ip)
Out[3]: netaddr.ip.IPNetwork
In [4]: type(ip[0:-1])
Out[4]: generator
In [5]: ip_list = list(ip)
In [6]: ip_list
Out[6]:
[IPAddress('192.168.2.144'),
IPAddress('192.168.2.145'),
IPAddress('192.168.2.146'),
IPAddress('192.168.2.147'),
IPAddress('192.168.2.148'),
IPAddress('192.168.2.149'),
IPAddress('192.168.2.150'),
IPAddress('192.168.2.151')]
In [7]: ip[-1]
Out[7]: IPAddress('192.168.2.151')
In [8]: ip[0]
Out[8]: IPAddress('192.168.2.144')
In [9]: ip[0:4]
Out[9]: <generator object iter_iprange at 0xb61ec414>
In [10]: list(ip[0::2])
Out[10]:
[IPAddress('192.168.2.144'),
IPAddress('192.168.2.146'),
IPAddress('192.168.2.148'),
IPAddress('192.168.2.150')]
In [11]: list(ip[-1::-1])
Out[11]:
[IPAddress('192.168.2.151'),
IPAddress('192.168.2.150'),
IPAddress('192.168.2.149'),
IPAddress('192.168.2.148'),
IPAddress('192.168.2.147'),
IPAddress('192.168.2.146'),
IPAddress('192.168.2.145'),
IPAddress('192.168.2.144')]
可见,ip[XXX]的形式其实就是一个生成器,生成器的目的是保证在处理拥有大量ip的网络时降低对资源的占用。
In [15]: for ip in IPNetwork('192.0.2.0/23'):
....: print ip
out [15]:
192.0.2.0
192.0.2.1
192.0.2.2
192.0.2.3
...
192.0.3.252
192.0.3.253
192.0.3.254
192.0.3.255
上述结果中:192.0.2.0和192.0.3.255并不是有效的主机地址,而是网络地址和广播地址。为了得到有效的主机地址,则需要使用iter_hosts()
[16]:for ip in IPNetwork('192.0.2.0/23').iter_hosts():
... print '%s' % ip
out [16]:
192.0.2.1
192.0.2.2
192.0.2.3
192.0.2.4
...
192.0.3.251
192.0.3.252
192.0.3.253
192.0.3.254
排序
对IP和网络进行排序的方法是使用sorted函数:
In [16]: ip_list = list(IPNetwork('192.0.2.128/28'))
In [17]: sorted(ip_list)
Out[17]:
[IPAddress('192.0.2.128'),
IPAddress('192.0.2.129'),
IPAddress('192.0.2.130'),
IPAddress('192.0.2.131'),
IPAddress('192.0.2.132'),
IPAddress('192.0.2.133'),
IPAddress('192.0.2.134'),
IPAddress('192.0.2.135'),
IPAddress('192.0.2.136'),
IPAddress('192.0.2.137'),
IPAddress('192.0.2.138'),
IPAddress('192.0.2.139'),
IPAddress('192.0.2.140'),
IPAddress('192.0.2.141'),
IPAddress('192.0.2.142'),
IPAddress('192.0.2.143')]
为了方便起见,也可以对网络进行排序,并且IPv4和IPv6网络可以混排。例如:
In [18]: ip_list = [
....: IPAddress('192.0.2.130'),
....: IPAddress('10.0.0.1'),
....: IPNetwork('192.0.2.128/28'),
....: IPNetwork('192.0.3.0/24'),
....: IPNetwork('192.0.2.0/24'),
....: IPNetwork('fe80::/64'),
....: IPAddress('::'),
....: IPNetwork('172.24/12')]
In [19]: import random
In [20]: random.shuffle(ip_list)
In [21]: ip_list.sort()
In [23]: import pprint
In [24]: pprint.pprint(ip_list)
[IPAddress('10.0.0.1'),
IPNetwork('172.24.0.0/12'),
IPNetwork('192.0.2.0/24'),
IPNetwork('192.0.2.128/28'),
IPAddress('192.0.2.130'),
IPNetwork('192.0.3.0/24'),
IPAddress('::'),
IPNetwork('fe80::/64')]
IP地址分类
IP地址有许多分类,并不是每个ip地址都能够做为主机地址。
单播地址(Unicast)
In [25]: IPAddress('192.0.2.1').is_unicast()
Out[25]: True
In [26]: IPAddress('fe80::1').is_unicast()
Out[26]: True
多播地址(Multicast)
In [27]: IPAddress('239.192.0.1').is_multicast()
Out[27]: True
In [28]: IPAddress('ff00::1').is_multicast()
Out[28]: True
私有地址(Private)
In [29]: IPAddress('172.24.0.1').is_private()
Out[29]: True
In [30]: IPAddress('10.0.0.1').is_private()
Out[30]: True
In [31]: IPAddress('192.168.0.1').is_private()
Out[31]: True
In [32]: IPAddress('fc00::1').is_private()
Out[32]: True
保留地址(Reserved)
In [33]: IPAddress('253.0.0.1').is_reserved()
Out[33]: True
公网地址(Public)
In [34]: ip = IPAddress('62.125.24.5')
In [35]: ip.is_unicast() and not ip.is_private()
Out[35]: True
子网掩码(Netmasks)与主机掩码(Hostmasks)
In [36]: IPAddress('255.255.254.0').is_netmask()
Out[36]: True
In [37]: IPAddress('0.0.1.255').is_hostmask()
Out[37]: True
回环地址(loopback)
In [38]: IPAddress('127.0.0.1').is_loopback()
Out[38]: True
In [39]: IPAddress('::1').is_loopback()
Out[39]: True
IP地址比较
IPAddress对象还可以进行彼此比较。IPAdrees可以代表某个具体的ip地址,也可以代表某个只有单个主机的网络,因此在比较ip地址之前,应转换成同一类型,以避免出现奇怪的结果。
In [42]: IPAddress('192.0.2.1') == IPAddress('192.0.2.1')
Out[42]: True
In [43]: IPAddress('192.0.2.1') < IPAddress('192.0.2.2')
Out[43]: True
In [44]: IPAddress('192.0.2.1') <= IPAddress('192.0.2.1')
Out[44]: True
In [45]: IPAddress('192.0.2.1') <= IPAddress('192.0.2.2')
Out[45]: True
而对于IPNetwork而言,比较的是两个子网而非两个ip地址:
In [46]: IPNetwork('192.0.2.0/24') == IPNetwork('192.0.2.112/24')
Out[46]: True
若要比较其ip,则只需取其ip属性即可:
In [47]: IPNetwork('192.0.2.0/24').ip == IPNetwork('192.0.2.112/24').ip
Out[47]: False
In [48]: IPNetwork('192.0.2.0/24').ip < IPNetwork('192.0.2.112/24').ip
Out[48]: True
或者直接明确比较cidr网络地址:
<pre name="code" class="plain">In [49]: IPNetwork('192.0.2.0/24').cidr == IPNetwork('192.0.2.112/24').cidr
Out[49]: True
注意:IPAddress(标量)和IPNetwork(向量)不能直接比较,如果非要比较的话,则要具体指明IPNetwork的哪个值。比如:
In [50]: IPAddress('192.0.2.0') == IPNetwork('192.0.2.0/32')[0]
Out[50]: True
In [51]: IPAddress('192.0.2.0') == IPNetwork('192.0.2.0/32')[-1]
Out[51]: True
In [52]: IPAddress('192.0.2.0') != IPNetwork('192.0.2.0/32')[0]
Out[52]: False
非标准IP分布
如果要要得到从IP地址A到IP地址B之间的网络,那么需要计算CIDR或子网地址,这无疑是件痛苦的事情。而netaddr提供一种很好的解决方法。
In [55]: r1 = IPRange('192.0.2.1', '192.0.2.15')
In [56]: r1.cidrs()
Out[56]:
[IPNetwork('192.0.2.1/32'),
IPNetwork('192.0.2.2/31'),
IPNetwork('192.0.2.4/30'),
IPNetwork('192.0.2.8/29')]
下面是IPRange和IPNetwork之间的比较:
In [58]: IPRange('192.0.2.0', '192.0.2.255') != IPNetwork('192.0.2.0/24')
Out[58]: False
In [59]: IPRange('192.0.2.0', '192.0.2.255') == IPNetwork('192.0.2.0/24')
Out[59]: True
如果想要得到IPRange中的IP地址,则用list:
In [60]: r1 = IPRange('192.0.2.1', '192.0.2.15')
In [61]: addrs = list(r1)
In [62]: addrs
Out[62]:
[IPAddress('192.0.2.1'),
IPAddress('192.0.2.2'),
IPAddress('192.0.2.3'),
IPAddress('192.0.2.4'),
IPAddress('192.0.2.5'),
IPAddress('192.0.2.6'),
IPAddress('192.0.2.7'),
IPAddress('192.0.2.8'),
IPAddress('192.0.2.9'),
IPAddress('192.0.2.10'),
IPAddress('192.0.2.11'),
IPAddress('192.0.2.12'),
IPAddress('192.0.2.13'),
IPAddress('192.0.2.14'),
IPAddress('192.0.2.15')]
In [63]: r1 == addrs
Out[63]: False
强调一点,若要比较,必须是同类型的才行(才有意义)。但是如果有一个序列包含IPAddress、IPNetwork和string类型的ip地址时该怎么办?IPSet类可以处理IP地址和网络组成的组。
In [64]: ips = [IPAddress('192.0.2.1'), '192.0.2.2/31', IPNetwork('192.0.2.4/31'), IPAddress('192.0.2.6'), IPAddress('192.0.2.7'), '192.0.2.8', '192.0.2.9', IPAddress('192.0.2.10'), IPAddress('192.0.2.11'), IPNetwork('192.0.2.12/30')]
In [67]: s1 = IPSet(r1.cidrs())
In [68]: s2 = IPSet(ips)
In [69]: s1
Out[69]: IPSet(['192.0.2.1/32', '192.0.2.2/31', '192.0.2.4/30', '192.0.2.8/29'])
In [70]: s2
Out[70]: IPSet(['192.0.2.1/32', '192.0.2.2/31', '192.0.2.4/30', '192.0.2.8/29'])
In [71]: s1 == s2
Out[71]: True
那么当从IPSet中移除一个元素,看看会发生什么事情:
In [72]: s2.pop()
Out[72]: IPNetwork('192.0.2.4/30')
In [73]: s1 == s2
Out[73]: False
更多IPSet教程请参看
官网教程。另一种是使用Glob方法表示IP范围,即模式匹配的方法来表示IP地址范围。例如:
In [75]: IPGlob('192.0.2.*') == IPNetwork('192.0.2.0/24')
Out[75]: True
由于IPGlob是IPRange的一个子类,所以IPRange的所有方法都适合于IPGlob,IPGlob暂时只适用于IPv4。