Python의 네트워크에 IP가 있는지 확인하려면 어떻게해야합니까?
-
03-07-2019 - |
문제
IP 주소 (192.168.0.1)가 주어지면 Python의 네트워크 (192.168.0.0/24)에 있는지 어떻게 확인합니까?
IP 주소 조작을위한 Python에 일반 도구가 있습니까? 호스트 조회, IP Adddress에서 int, 넷 마스크에서 int 등을 가진 네트워크 주소와 같은 것들? 2.5의 표준 파이썬 라이브러리에서.
해결책
이 기사 당신이 할 수 있다는 것을 보여줍니다 socket
그리고 struct
너무 많은 노력이없는 모듈. 다음과 같이 기사에 조금 추가했습니다.
import socket,struct
def makeMask(n):
"return a mask of n bits as a long integer"
return (2L<<n-1) - 1
def dottedQuadToNum(ip):
"convert decimal dotted quad string to long integer"
return struct.unpack('L',socket.inet_aton(ip))[0]
def networkMask(ip,bits):
"Convert a network address to a long integer"
return dottedQuadToNum(ip) & makeMask(bits)
def addressInNetwork(ip,net):
"Is an address in a network"
return ip & net == net
address = dottedQuadToNum("192.168.1.1")
networka = networkMask("10.0.0.0",24)
networkb = networkMask("192.168.0.0",24)
print (address,networka,networkb)
print addressInNetwork(address,networka)
print addressInNetwork(address,networkb)
이 출력 :
False
True
문자열을 취하는 단일 함수 만 원한다면 다음과 같이 보입니다.
import socket,struct
def addressInNetwork(ip,net):
"Is an address in a network"
ipaddr = struct.unpack('L',socket.inet_aton(ip))[0]
netaddr,bits = net.split('/')
netmask = struct.unpack('L',socket.inet_aton(netaddr))[0] & ((2L<<int(bits)-1) - 1)
return ipaddr & netmask == netmask
다른 팁
나는 사용하는 것을 좋아한다 netaddr 그에 대한:
from netaddr import CIDR, IP
if IP("192.168.0.1") in CIDR("192.168.0.0/24"):
print "Yay!"
Arno_v가 주석에서 지적했듯이 NetAddr의 새로운 버전은 다음과 같습니다.
from netaddr import IPNetwork, IPAddress
if IPAddress("192.168.0.1") in IPNetwork("192.168.0.0/24"):
print "Yay!"
사용 IP 주소 (3.3 이후 stdlib에서, 2.6/2.7의 PYPI에서):
>>> import ipaddress
>>> ipaddress.ip_address('192.168.0.1') in ipaddress.ip_network('192.168.0.0/24')
True
평가하려면 a 많은 이런 방식으로 IP 주소의 경우, 아마도 넷 마스크를 선불로 계산하고 싶을 것입니다.
n = ipaddress.ip_network('192.0.0.0/16')
netw = int(n.network_address)
mask = int(n.netmask)
그런 다음 각 주소에 대해 하나의 이진 표현을 계산하십시오.
a = int(ipaddress.ip_address('192.0.43.10'))
a = struct.unpack('!I', socket.inet_pton(socket.AF_INET, '192.0.43.10'))[0]
a = struct.unpack('!I', socket.inet_aton('192.0.43.10'))[0] # IPv4 only
마지막으로 간단히 확인할 수 있습니다.
in_network = (a & mask) == netw
이 코드는 Linux X86에서 저를 위해 작동합니다. 나는 Endianess 문제에 대해 실제로 생각하지 않았지만 8 개의 다른 네트워크 문자열에 대해 테스트 된 200k 이상의 IP 주소를 사용하여 "iPaddr"모듈에 대해 테스트했으며 iPaddr의 결과는이 코드와 동일합니다.
def addressInNetwork(ip, net):
import socket,struct
ipaddr = int(''.join([ '%02x' % int(x) for x in ip.split('.') ]), 16)
netstr, bits = net.split('/')
netaddr = int(''.join([ '%02x' % int(x) for x in netstr.split('.') ]), 16)
mask = (0xffffffff << (32 - int(bits))) & 0xffffffff
return (ipaddr & mask) == (netaddr & mask)
예시:
>>> print addressInNetwork('10.9.8.7', '10.9.1.0/16')
True
>>> print addressInNetwork('10.9.8.7', '10.9.1.0/24')
False
python3의 경우
In [64]: ipaddress.IPv4Address('192.168.1.1') in ipaddress.IPv4Network('192.168.0.0/24')
Out[64]: False
Dave Webb의 솔루션을 시도했지만 몇 가지 문제를 겪었습니다.
가장 근본적으로 - 마스크와 함께 IP 주소를 및 IP 주소를 확인한 다음 결과를 확인하면 네트워크 주소와 정확히 일치했습니다. 완료된대로 네트워크 주소로 IP 주소를 사용하지 않습니다.
또한 일관성이 절약 될 것이라고 가정 할 때 엔디 언 동작을 무시하는 것만으로 도문 경계 ( /24, /16)의 마스크에만 작동합니다. 다른 마스크 ( /23, /21)를 올바르게 작동시키기 위해 구조물 명령에 "더 큰"을 추가하고 바이너리 마스크를 만들기위한 코드를 변경하여 모든 "1"로 시작하고 (32 마스크로 왼쪽으로 이동합니다. ).
마지막으로, 네트워크 주소가 마스크에 유효한 간단한 점검을 추가하고 경고가 아닌 경우 경고를 인쇄합니다.
결과는 다음과 같습니다.
def addressInNetwork(ip,net):
"Is an address in a network"
ipaddr = struct.unpack('>L',socket.inet_aton(ip))[0]
netaddr,bits = net.split('/')
netmask = struct.unpack('>L',socket.inet_aton(netaddr))[0]
ipaddr_masked = ipaddr & (4294967295<<(32-int(bits))) # Logical AND of IP address and mask will equal the network address if it matches
if netmask == netmask & (4294967295<<(32-int(bits))): # Validate network address is valid for mask
return ipaddr_masked == netmask
else:
print "***WARNING*** Network",netaddr,"not valid with mask /"+bits
return ipaddr_masked == netmask
나는 모듈이 필요하지 않을 때 사용하는 팬이 아닙니다. 이 직업은 간단한 수학 만 필요하므로 여기에 작업을 수행하는 간단한 기능이 있습니다.
def ipToInt(ip):
o = map(int, ip.split('.'))
res = (16777216 * o[0]) + (65536 * o[1]) + (256 * o[2]) + o[3]
return res
def isIpInSubnet(ip, ipNetwork, maskLength):
ipInt = ipToInt(ip)#my test ip, in int form
maskLengthFromRight = 32 - maskLength
ipNetworkInt = ipToInt(ipNetwork) #convert the ip network into integer form
binString = "{0:b}".format(ipNetworkInt) #convert that into into binary (string format)
chopAmount = 0 #find out how much of that int I need to cut off
for i in range(maskLengthFromRight):
if i < len(binString):
chopAmount += int(binString[len(binString)-1-i]) * 2**i
minVal = ipNetworkInt-chopAmount
maxVal = minVal+2**maskLengthFromRight -1
return minVal <= ipInt and ipInt <= maxVal
그런 다음 사용하십시오 :
>>> print isIpInSubnet('66.151.97.0', '66.151.97.192',24)
True
>>> print isIpInSubnet('66.151.97.193', '66.151.97.192',29)
True
>>> print isIpInSubnet('66.151.96.0', '66.151.97.192',24)
False
>>> print isIpInSubnet('66.151.97.0', '66.151.97.192',29)
그게 다야, 이것은 포함 된 모듈의 솔루션보다 훨씬 빠릅니다.
받아 들여진 대답은 작동하지 않습니다 ... 나를 화나게합니다. 마스크는 뒤로이며 간단한 8 비트 블록 (예 : /24)이 아닌 비트에서는 작동하지 않습니다. 나는 답을 조정했고 잘 작동합니다.
import socket,struct
def addressInNetwork(ip, net_n_bits):
ipaddr = struct.unpack('!L', socket.inet_aton(ip))[0]
net, bits = net_n_bits.split('/')
netaddr = struct.unpack('!L', socket.inet_aton(net))[0]
netmask = (0xFFFFFFFF >> int(bits)) ^ 0xFFFFFFFF
return ipaddr & netmask == netaddr
다음은 마스킹을 시각화하는 데 도움이되는 점선 바이너리 스트링을 반환하는 함수입니다. ipcalc
산출.
def bb(i):
def s = '{:032b}'.format(i)
def return s[0:8]+"."+s[8:16]+"."+s[16:24]+"."+s[24:32]
예 :
2.5의 표준 라이브러리는 아니지만 iPaddr는이를 매우 쉽게 만듭니다. 나는 그것이 iPaddress라는 이름으로 3.3이라고 생각합니다.
import ipaddr
a = ipaddr.IPAddress('192.168.0.1')
n = ipaddr.IPNetwork('192.168.0.0/24')
#This will return True
n.Contains(a)
Marc의 코드는 거의 정확합니다. 코드의 전체 버전은 -
def addressInNetwork3(ip,net):
'''This function allows you to check if on IP belogs to a Network'''
ipaddr = struct.unpack('=L',socket.inet_aton(ip))[0]
netaddr,bits = net.split('/')
netmask = struct.unpack('=L',socket.inet_aton(calcDottedNetmask(int(bits))))[0]
network = struct.unpack('=L',socket.inet_aton(netaddr))[0] & netmask
return (ipaddr & netmask) == (network & netmask)
def calcDottedNetmask(mask):
bits = 0
for i in xrange(32-mask,32):
bits |= (1 << i)
return "%d.%d.%d.%d" % ((bits & 0xff000000) >> 24, (bits & 0xff0000) >> 16, (bits & 0xff00) >> 8 , (bits & 0xff))
분명히 위와 같은 소스에서 ...
매우 중요한 참고 사항은 첫 번째 코드에 작은 글리치가 있다는 것입니다. IP 주소 255.255.255.255도 모든 서브넷의 유효한 IP로 표시됩니다. 이 코드가 작동하는 데 시간이 걸렸으며 정답에 대한 Marc에게 감사드립니다.
"struct"모듈에 의존하면 Endian-Inness 및 유형 크기에 문제가 발생할 수 있으며 필요하지 않습니다. Socket.inet_aton ()도 아닙니다. 파이썬은 점선 쿼드 IP 주소와 매우 잘 작동합니다.
def ip_to_u32(ip):
return int(''.join('%02x' % int(d) for d in ip.split('.')), 16)
허용 가능한 소스 네트워크 세트에 대해 각 소켓 수락 () 호출에 IP 일치를 수행해야하므로 마스크와 네트워크를 정수로 전달해야합니다.
SNS_SOURCES = [
# US-EAST-1
'207.171.167.101',
'207.171.167.25',
'207.171.167.26',
'207.171.172.6',
'54.239.98.0/24',
'54.240.217.16/29',
'54.240.217.8/29',
'54.240.217.64/28',
'54.240.217.80/29',
'72.21.196.64/29',
'72.21.198.64/29',
'72.21.198.72',
'72.21.217.0/24',
]
def build_masks():
masks = [ ]
for cidr in SNS_SOURCES:
if '/' in cidr:
netstr, bits = cidr.split('/')
mask = (0xffffffff << (32 - int(bits))) & 0xffffffff
net = ip_to_u32(netstr) & mask
else:
mask = 0xffffffff
net = ip_to_u32(cidr)
masks.append((mask, net))
return masks
그런 다음 주어진 IP가 해당 네트워크 중 하나 내에 있는지 신속하게 확인할 수 있습니다.
ip = ip_to_u32(ipstr)
for mask, net in cached_masks:
if ip & mask == net:
# matched!
break
else:
raise BadClientIP(ipstr)
모듈 가져 오기가 필요하지 않으며 코드가 있습니다 매우 일치합니다.
netAddr에서 all_matching_cidrs를 가져옵니다
>>> from netaddr import all_matching_cidrs
>>> all_matching_cidrs("212.11.70.34", ["192.168.0.0/24","212.11.64.0/19"] )
[IPNetwork('212.11.64.0/19')]
이 방법의 사용법은 다음과 같습니다.
>>> help(all_matching_cidrs)
Help on function all_matching_cidrs in module netaddr.ip:
all_matching_cidrs(ip, cidrs)
Matches an IP address or subnet against a given sequence of IP addresses and subnets.
@param ip: a single IP address or subnet.
@param cidrs: a sequence of IP addresses and/or subnets.
@return: all matching IPAddress and/or IPNetwork objects from the provided
sequence, an empty list if there was no match.
기본적으로 귀하는 IP 주소를 첫 번째 인수로 제공하고 CIDR 목록을 두 번째 인수로 제공합니다. 적중 목록이 반환됩니다.
#This works properly without the weird byte by byte handling def addressInNetwork(ip,net): '''Is an address in a network''' # Convert addresses to host order, so shifts actually make sense ip = struct.unpack('>L',socket.inet_aton(ip))[0] netaddr,bits = net.split('/') netaddr = struct.unpack('>L',socket.inet_aton(netaddr))[0] # Must shift left an all ones value, /32 = zero shift, /0 = 32 shift left netmask = (0xffffffff << (32-int(bits))) & 0xffffffff # There's no need to mask the network address, as long as its a proper network address return (ip & netmask) == netaddr
선택 답변에는 버그가 있습니다.
다음은 올바른 코드입니다.
def addressInNetwork(ip, net_n_bits):
ipaddr = struct.unpack('<L', socket.inet_aton(ip))[0]
net, bits = net_n_bits.split('/')
netaddr = struct.unpack('<L', socket.inet_aton(net))[0]
netmask = ((1L << int(bits)) - 1)
return ipaddr & netmask == netaddr & netmask
메모: ipaddr & netmask == netaddr & netmask
대신에 ipaddr & netmask == netmask
.
나도 교체합니다 ((2L<<int(bits)-1) - 1)
~와 함께 ((1L << int(bits)) - 1)
, 후자는 더 이해하기 쉬운 것처럼 보입니다.
다음은 가장 긴 접두사 일치에 대해 쓴 수업입니다.
#!/usr/bin/env python
class Node:
def __init__(self):
self.left_child = None
self.right_child = None
self.data = "-"
def setData(self, data): self.data = data
def setLeft(self, pointer): self.left_child = pointer
def setRight(self, pointer): self.right_child = pointer
def getData(self): return self.data
def getLeft(self): return self.left_child
def getRight(self): return self.right_child
def __str__(self):
return "LC: %s RC: %s data: %s" % (self.left_child, self.right_child, self.data)
class LPMTrie:
def __init__(self):
self.nodes = [Node()]
self.curr_node_ind = 0
def addPrefix(self, prefix):
self.curr_node_ind = 0
prefix_bits = ''.join([bin(int(x)+256)[3:] for x in prefix.split('/')[0].split('.')])
prefix_length = int(prefix.split('/')[1])
for i in xrange(0, prefix_length):
if (prefix_bits[i] == '1'):
if (self.nodes[self.curr_node_ind].getRight()):
self.curr_node_ind = self.nodes[self.curr_node_ind].getRight()
else:
tmp = Node()
self.nodes[self.curr_node_ind].setRight(len(self.nodes))
tmp.setData(self.nodes[self.curr_node_ind].getData());
self.curr_node_ind = len(self.nodes)
self.nodes.append(tmp)
else:
if (self.nodes[self.curr_node_ind].getLeft()):
self.curr_node_ind = self.nodes[self.curr_node_ind].getLeft()
else:
tmp = Node()
self.nodes[self.curr_node_ind].setLeft(len(self.nodes))
tmp.setData(self.nodes[self.curr_node_ind].getData());
self.curr_node_ind = len(self.nodes)
self.nodes.append(tmp)
if i == prefix_length - 1 :
self.nodes[self.curr_node_ind].setData(prefix)
def searchPrefix(self, ip):
self.curr_node_ind = 0
ip_bits = ''.join([bin(int(x)+256)[3:] for x in ip.split('.')])
for i in xrange(0, 32):
if (ip_bits[i] == '1'):
if (self.nodes[self.curr_node_ind].getRight()):
self.curr_node_ind = self.nodes[self.curr_node_ind].getRight()
else:
return self.nodes[self.curr_node_ind].getData()
else:
if (self.nodes[self.curr_node_ind].getLeft()):
self.curr_node_ind = self.nodes[self.curr_node_ind].getLeft()
else:
return self.nodes[self.curr_node_ind].getData()
return None
def triePrint(self):
n = 1
for i in self.nodes:
print n, ':'
print i
n += 1
그리고 여기 테스트 프로그램이 있습니다.
n=LPMTrie()
n.addPrefix('10.25.63.0/24')
n.addPrefix('10.25.63.0/16')
n.addPrefix('100.25.63.2/8')
n.addPrefix('100.25.0.3/16')
print n.searchPrefix('10.25.63.152')
print n.searchPrefix('100.25.63.200')
#10.25.63.0/24
#100.25.0.3/16
대본에 감사드립니다!
나는 모든 것을 작동시키기 위해 꽤 오랫동안 일하고 있습니다 ... 그래서 나는 그것을 여기에서 공유하고 있습니다.
- NetAddr 클래스 사용은 이진 변환을 사용하는 것보다 10 배 느리므로 큰 IP 목록에서 사용하려면 NetADDR 클래스를 사용하지 않는 것이 좋습니다.
Makemask 기능이 작동하지 않습니다! /8,/16,/24에서만 작업
전:비트 = "21"; socket.inet_ntoa (struct.pack ( '= l', (2l << int (비트) -1) -1))))
'255.255.31.0'반면 255.255.248.0이어야합니다그래서 나는 다른 함수 calcdottednetmask (마스크)를 사용했습니다. http://code.activestate.com/recipes/576483-convert-subnetmask-from-cidr-notation-to-dotdecima/
전:
#!/usr/bin/python
>>> calcDottedNetmask(21)
>>> '255.255.248.0'
- 또 다른 문제는 IP가 네트워크에 속하는 경우 일치하는 프로세스입니다! 기본 작동은 (iPaddr & netmask) 및 (Network & Netmask)를 비교해야합니다.
예 : 당분간 기능이 잘못되었습니다.
#!/usr/bin/python
>>> addressInNetwork('188.104.8.64','172.16.0.0/12')
>>>True which is completely WRONG!!
따라서 새 주소 인 네트워크 기능이 보입니다.
#!/usr/bin/python
import socket,struct
def addressInNetwork(ip,net):
'''This function allows you to check if on IP belogs to a Network'''
ipaddr = struct.unpack('=L',socket.inet_aton(ip))[0]
netaddr,bits = net.split('/')
netmask = struct.unpack('=L',socket.inet_aton(calcDottedNetmask(bits)))[0]
network = struct.unpack('=L',socket.inet_aton(netaddr))[0] & netmask
return (ipaddr & netmask) == (network & netmask)
def calcDottedNetmask(mask):
bits = 0
for i in xrange(32-int(mask),32):
bits |= (1 > 24, (bits & 0xff0000) >> 16, (bits & 0xff00) >> 8 , (bits & 0xff))
그리고 이제 대답이 맞습니다 !!
#!/usr/bin/python
>>> addressInNetwork('188.104.8.64','172.16.0.0/12')
False
나는 그것이 다른 사람들에게 도움이되기를 바랍니다.
위의 모든 것과 관련하여 Socket.inet_aton ()이 네트워크 순서로 바이트를 반환한다고 생각하므로 포장을 풀리는 올바른 방법은 아마도
struct.unpack('!L', ... )
이전 솔루션에는 IP & NET == NET에 버그가 있습니다. 올바른 IP 조회는 IP & Netmask = NET입니다
버그 픽스 코드 :
import socket
import struct
def makeMask(n):
"return a mask of n bits as a long integer"
return (2L<<n-1) - 1
def dottedQuadToNum(ip):
"convert decimal dotted quad string to long integer"
return struct.unpack('L',socket.inet_aton(ip))[0]
def addressInNetwork(ip,net,netmask):
"Is an address in a network"
print "IP "+str(ip) + " NET "+str(net) + " MASK "+str(netmask)+" AND "+str(ip & netmask)
return ip & netmask == net
def humannetcheck(ip,net):
address=dottedQuadToNum(ip)
netaddr=dottedQuadToNum(net.split("/")[0])
netmask=makeMask(long(net.split("/")[1]))
return addressInNetwork(address,netaddr,netmask)
print humannetcheck("192.168.0.1","192.168.0.0/24");
print humannetcheck("192.169.0.1","192.168.0.0/24");
이 작업을 잘 수행하는 파이썬으로 사용 가능한 서브넷 트리라고하는 API가 있습니다. 이것은 간단한 예입니다.
import SubnetTree
t = SubnetTree.SubnetTree()
t.insert("10.0.1.3/32")
print("10.0.1.3" in t)
import socket,struct
def addressInNetwork(ip,net):
"Is an address in a network"
ipaddr = struct.unpack('!L',socket.inet_aton(ip))[0]
netaddr,bits = net.split('/')
netaddr = struct.unpack('!L',socket.inet_aton(netaddr))[0]
netmask = ((1<<(32-int(bits))) - 1)^0xffffffff
return ipaddr & netmask == netaddr & netmask
print addressInNetwork('10.10.10.110','10.10.10.128/25')
print addressInNetwork('10.10.10.110','10.10.10.0/25')
print addressInNetwork('10.10.10.110','10.20.10.128/25')
$ python check-subnet.py
거짓
진실
거짓
표준 라이브러리에서 아무것도 모르지만 pysubnettree 서브넷 매칭을 수행하는 파이썬 라이브러리입니다.
위의 다양한 출처에서 내 자신의 연구에서 이것은 서브넷과 주소 계산이 작동하는 방법입니다. 이 부분은 질문 및 기타 관련 질문을 해결하기에 충분합니다.
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)
여기 내 코드가 있습니다
# -*- 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 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]
이 답변에서 제안 된 솔루션 중 하나를 시도했습니다. 성공하지 못한 상태에서 제안 된 코드를 조정하고 수정하고 고정 기능을 작성했습니다.
나는 그것을 테스트하고 적어도 Little Endian Architectures (EGX86)에서 일합니다. 누군가가 큰 엔디 언 아키텍처를 시도하는 사람이라면 피드백을주십시오.
IP2Int
코드는 이 게시물, 다른 방법은이 질문에서 이전 제안서의 완전한 (테스트 사례) 작업 수정입니다.
코드:
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
유용한 희망,