如何在Python中检查IP地址(比如192.168.0.1)是否属于某个网络(比如192.168.0.0/24)?
在Python中是否有一些常规工具用于IP地址的操作,例如主机查找、将IP地址转换为整数、将带有子网掩码的网络地址转换成整数等等?希望这些工具能够在Python 2.5标准库中找到。
如何在Python中检查IP地址(比如192.168.0.1)是否属于某个网络(比如192.168.0.0/24)?
在Python中是否有一些常规工具用于IP地址的操作,例如主机查找、将IP地址转换为整数、将带有子网掩码的网络地址转换成整数等等?希望这些工具能够在Python 2.5标准库中找到。
struct.unpack('!L', ... )
有一个名为SubnetTree的API可用于Python,非常适合完成此任务。 这是一个简单的示例:
import SubnetTree
t = SubnetTree.SubnetTree()
t.insert("10.0.1.3/32")
print("10.0.1.3" in t)
如果您不想导入其他模块,可以选择:
def ip_matches_network(self, network, ip):
"""
'{:08b}'.format(254): Converts 254 in a string of its binary representation
ip_bits[:net_mask] == net_ip_bits[:net_mask]: compare the ip bit streams
:param network: string like '192.168.33.0/24'
:param ip: string like '192.168.33.1'
:return: if ip matches network
"""
net_ip, net_mask = network.split('/')
net_mask = int(net_mask)
ip_bits = ''.join('{:08b}'.format(int(x)) for x in ip.split('.'))
net_ip_bits = ''.join('{:08b}'.format(int(x)) for x in net_ip.split('.'))
# example: net_mask=24 -> compare strings at position 0 to 23
return ip_bits[:net_mask] == net_ip_bits[:net_mask]
def subnet_lookup(subnet: str, netmask: str, ip_address: str):
"""
:param subnet: subnet to test against (as string)
:param netmask: mask of subnet
:param ip_address: ip to test against subnet and mask
:return True if a match; False if not a match
Steps:
1) convert entire subnet into one binary word
2) convert entire mask into one binary word
3) determine bcast from comparing subnet and mask
4) convert entire ip_address into one binary word
5) convert entire subnet into decimal
6) convert entire bcast into decimal
7) convert entire ip_address into decimal
8) determine if ip_address falls between subnet and bcast using range(); returns True if yes, False if no
"""
def convert_whole_to_bin(whole):
ip_dec_list = whole.split(".")
ip_bin_str = ""
for ip in ip_dec_list:
binary = dec_to_bin(int(ip))
ip_bin_str += binary
return ip_bin_str
def dec_to_bin(decimal_octet: int):
binary = bin(decimal_octet).replace("0b", "")
return binary.rjust(8, '0')
def split_binary_into_list(binary_octet: str):
bin_list = []
for s in binary_octet:
bin_list.append(s)
return bin_list
def determine_bcast(subnet, netmask):
subnet_split = split_binary_into_list(subnet)
netmask_split = split_binary_into_list(netmask)
bcast_list = []
for subnet, mask in zip(subnet_split, netmask_split):
if mask != '0':
bcast_list.append(subnet)
else:
bcast_list.append('1')
bcast_bin = "".join(bcast_list)
return bcast_bin
def bin_to_dec(binary_single_word: str):
decimal = int(binary_single_word, 2)
return decimal
def subnet_lookup(ip_address, subnet, bcast):
return ip_address in range(subnet, bcast + 1)
# 1) convert entire subnet into one binary word
subnet_single_bin = convert_whole_to_bin(whole=subnet)
# 2) convert entire mask into one binary word
mask_single_bin = convert_whole_to_bin(whole=netmask)
# 3) determine bcast from comparing subnet and mask
bcast_single_bin = determine_bcast(subnet=subnet_single_bin, netmask=mask_single_bin)
# 4) convert entire ip_address into one binary word
ip_address_single_bin = convert_whole_to_bin(whole=ip_address)
# 5) convert entire subnet into decimal
subnet_single_dec = bin_to_dec(binary_single_word=subnet_single_bin)
# 6) convert entire bcast into decimal
bcast_single_dec = bin_to_dec(binary_single_word=bcast_single_bin)
# 7) convert entire ip_address into decimal
ip_address_single_dec = bin_to_dec(binary_single_word=ip_address_single_bin)
# 8) determine if ip_address falls between subnet and bcast; returns True if yes, False if no
lookup_result = subnet_lookup(ip_address=ip_address_single_dec, subnet=subnet_single_dec, bcast=bcast_single_dec)
return lookup_result
# Testing:
subnet = "172.16.0.0"
netmask = "255.255.0.0"
ip_address = "172.16.255.255"
result = subnet_lookup(subnet=subnet, netmask=netmask, ip_address=ip_address)
print(result)
我尝试了这些答案中的一个子集...但没有成功,最终我改编并修复了提出的代码,并编写了我的修复函数。
我测试过它,在小端架构上至少可以工作--例如x86--如果有人想在大端架构上尝试,请给我反馈。
IP2Int
代码来自this post,另一种方法是对此问题先前提出的建议进行完全(对于我的测试用例)的修复。
代码如下:
def IP2Int(ip):
o = map(int, ip.split('.'))
res = (16777216 * o[0]) + (65536 * o[1]) + (256 * o[2]) + o[3]
return res
def addressInNetwork(ip, net_n_bits):
ipaddr = IP2Int(ip)
net, bits = net_n_bits.split('/')
netaddr = IP2Int(net)
bits_num = int(bits)
netmask = ((1L << bits_num) - 1) << (32 - bits_num)
return ipaddr & netmask == netaddr & netmask
希望有用,
从上述各种来源以及我自己的研究中,这就是我得出子网和地址计算的方法。这些要素足以解决问题和其他相关问题。
class iptools:
@staticmethod
def dottedQuadToNum(ip):
"convert decimal dotted quad string to long integer"
return struct.unpack('>L', socket.inet_aton(ip))[0]
@staticmethod
def numToDottedQuad(n):
"convert long int to dotted quad string"
return socket.inet_ntoa(struct.pack('>L', n))
@staticmethod
def makeNetmask(mask):
bits = 0
for i in xrange(32-int(mask), 32):
bits |= (1 << i)
return bits
@staticmethod
def ipToNetAndHost(ip, maskbits):
"returns tuple (network, host) dotted-quad addresses given"
" IP and mask size"
# (by Greg Jorgensen)
n = iptools.dottedQuadToNum(ip)
m = iptools.makeMask(maskbits)
net = n & m
host = n - mask
return iptools.numToDottedQuad(net), iptools.numToDottedQuad(host)
这里是使用netaddr包的解决方案
from netaddr import IPNetwork, IPAddress
def network_has_ip(network, ip):
if not isinstance(network, IPNetwork):
raise Exception("network parameter must be {0} instance".format(IPNetwork.__name__))
if not isinstance(ip, IPAddress):
raise Exception("ip parameter must be {0} instance".format(IPAddress.__name__))
return (network.cidr.ip.value & network.netmask.value) == (ip.value & network.netmask.value)
这是我的代码
# -*- coding: utf-8 -*-
import socket
class SubnetTest(object):
def __init__(self, network):
self.network, self.netmask = network.split('/')
self._network_int = int(socket.inet_aton(self.network).encode('hex'), 16)
self._mask = ((1L << int(self.netmask)) - 1) << (32 - int(self.netmask))
self._net_prefix = self._network_int & self._mask
def match(self, ip):
'''
判断传入的 IP 是不是本 Network 内的 IP
'''
ip_int = int(socket.inet_aton(ip).encode('hex'), 16)
return (ip_int & self._mask) == self._net_prefix
st = SubnetTest('100.98.21.0/24')
print st.match('100.98.23.32')
def is_private_ip(ip_address_as_str):
'''Takes String IP Address without Cider as input
Returns True if the IP Address falls in Private subnet
Returns False if IP Address is public
'''
class_a=ipaddress.ip_address(ip_address_as_str) in ipaddress.ip_network('10.0.0.0/8')
class_b=ipaddress.ip_address(ip_address_as_str) in ipaddress.ip_network('172.16.0.0/12')
class_c=ipaddress.ip_address(ip_address_as_str) in ipaddress.ip_network('192.168.0.0/16')
class_local_loop=ipaddress.ip_address(ip_address_as_str) in ipaddress.ip_network('127.0.0.0/8')
class_apipa=ipaddress.ip_address(ip_address_as_str) in ipaddress.ip_network('169.254.0.0/16')
return class_a|class_b|class_c|class_local_loop|class_apipa