#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# date: 2019/6/6
# author: he.zhiming
#
from __future__ import (absolute_import, unicode_literals)
import ipaddress
from ipaddress import ip_interface, ip_network
import six
def _is_ip_address(ipobj):
return isinstance(ipobj, (ipaddress.IPv4Address, ipaddress.IPv6Address))
def _is_ip_network(ipobj):
return isinstance(ipobj, (ipaddress.IPv4Network, ipaddress.IPv6Network))
[docs]class IPException(Exception):
"""异常类"""
pass
[docs]class IPUtils:
[docs] @classmethod
def is_special_ip(cls, ip,
check_link_local=True,
check_multicast=True,
check_loopback=True,
check_reserved=True,
check_site_local=True,
check_unspecified=True):
"""是否为特殊IP
:param ip:
:return:
"""
cls.check_ips_valid(ip)
obj = ip_interface(ip)
is_special = True
if check_loopback:
is_special = is_special or obj.is_loopback
if check_link_local:
is_special = is_special or obj.is_link_local
if check_multicast:
is_special = is_special or obj.is_multicast
if check_reserved:
is_special = is_special or obj.is_reserved
if check_site_local:
is_special = is_special or obj.is_site_local
if check_unspecified:
is_special = is_special or obj.is_unspecified
return is_special
[docs] @classmethod
def is_useable_ip(cls, ip, check_reserved=True):
return cls.is_valid(ip) and (not cls.is_special_ip(ip, check_reserved=check_reserved))
[docs] @classmethod
def get_ip_amount(cls, network, strict=False):
"""获取一个网络内的IP数目
:param network: 网段地址
:param strict: 是否严格模式
:return: IP数量
:rtype: int
"""
net = ip_network(network, strict=strict)
return net.num_addresses
[docs] @classmethod
def is_valid(cls, ip):
"""IP是否合法
:param ip: IP地址(4/6)
:return:
"""
try:
ip_interface(ip)
return True
except ValueError:
return False
[docs] @classmethod
def is_ipv4(cls, ip):
"""是否为IPv4地址
:param ip:
:return:
"""
return ip_interface(ip).version == 4
[docs] @classmethod
def is_ipv6(cls, ip):
"""是否为IPv6地址
:param ip:
:return:
"""
return ip_interface(ip).version == 6
[docs] @classmethod
def is_network(cls, ip, strict=True):
"""是否是一个网段
:param ip:
:param strict: 是否为严格模式. 建议使用True
:return:
"""
try:
ip_network(ip, strict=strict)
return True
except ValueError:
return False
[docs] @classmethod
def get_network_addr(cls, ip):
"""获取网段地址
:param ip: 某IP地址
:return:
"""
return str(ip_interface(ip).network)
[docs] @classmethod
def get_broadcast_addr(cls, ip):
"""获取广播地址
:param ip: 某IP地址
:return:
"""
n = ip_interface(ip).network
return str(n.broadcast_address)
[docs] @classmethod
def with_prefix(cls, ip):
"""转化成前缀格式的IP
:param ip: 子网掩码格式的IP
:return:
"""
return ip_interface(ip).with_prefixlen
[docs] @classmethod
def with_netmask(cls, ip):
"""转化成子网掩码格式的IP
:param ip: 前缀形式的IP
:return:
"""
return ip_interface(ip).with_netmask
[docs] @classmethod
def ip_to_int(cls, ip):
return int(ip_interface(ip))
[docs] @classmethod
def int_to_ip(cls, number, version=4):
if version == 4:
return str(ipaddress.IPv4Interface(number).ip)
if version == 6:
return str(ipaddress.IPv6Interface(number).ip)
raise IPException('not support version: {}'.format(version))
[docs] @classmethod
def is_in_network(cls, ip, network, strict=True):
"""某IP是否在某网络内
:param ip:
:param network:
:param strict: 严格的网络地址
:return:
"""
return cls._is_in_network(ip, ipaddress.ip_network(network, strict=strict))
[docs] @classmethod
def is_ips_equal(cls, *ips):
"""多个IP是否相等
:param ips:
:return:
"""
return len({cls.ip_to_int(ip) for ip in ips}) == 1
@classmethod
def _is_in_network(cls, ip, network_obj):
ipint = cls.ip_to_int(ip)
if _is_ip_address(network_obj):
return ipint == int(network_obj)
return int(network_obj[0]) <= ipint <= int(network_obj[-1])
[docs] @classmethod
def is_same_ip_version(cls, ip1, ip2):
if not (cls.is_valid(ip1) and cls.is_valid(ip2)):
raise IPException('invalid ip input {} {}'.format(ip1, ip2))
return ip_interface(ip1).version == ip_interface(ip2).version
[docs] @classmethod
def is_ip_in_network(cls, ip1, network_ip, strict=False):
if not (cls.is_valid(ip1) and cls.is_valid(network_ip)):
raise IPException('invalid ip input {ip1} {network_ip}'.format(ip1=ip1, network_ip=network_ip))
net = ip_network(network_ip, strict=strict)
return cls._is_in_network(ip1, net)
[docs] @classmethod
def is_subnet(cls, ip1, ip2, exchange=True):
cls.check_ips_valid(ip1, ip2)
net1 = ip_network(ip1, strict=False)
net2 = ip_network(ip2, strict=False)
is_subnet = net1.subnet_of(net2)
if exchange:
is_subnet = is_subnet or net2.subnet_of(net1)
return is_subnet
[docs] @classmethod
def check_ip_valid(cls, ip):
if not cls.is_valid(ip):
raise IPException('invalid ip input {ip}'.format(ip=ip))
[docs] @classmethod
def check_ips_valid(cls, *ips):
for ip in ips:
cls.check_ip_valid(ip)