Python의 네트워크에 IP가 있는지 어떻게 확인할 수 있습니까?


100

IP 주소 (예 : 192.168.0.1)가 주어지면 Python에서 네트워크 (예 : 192.168.0.0/24)에 있는지 어떻게 확인합니까?

Python에 IP 주소 조작을위한 일반적인 도구가 있습니까? 호스트 조회, int에 대한 ip 주소, int에 대한 넷 마스크가있는 네트워크 주소 등과 같은 것들? 바라건대 2.5 용 표준 Python 라이브러리에 있습니다.


이 질문은 아주 오래된 2.x 답변에 대해서는 괜찮은 표준처럼 보이지만 3.x에서는 더 이상 사용되지 않습니다. "Python / pandas가 IP 주소 / CIDR을 비교"에 대한 표준을 구성하고 할당하는 방법을
smci

@smci 왜 그런지 모르겠습니다. stackoverflow.com/a/1004527/1709587 에서 phihag의 답변은 Python 3에 대한 완벽한 답변이며 2014 년부터 여기에 있습니다. 해당 답변을 무효화 한 수정 사항을 롤백했습니다.
Mark Amery

@Staale-여기에서 중요한 버그가없는 답변으로 업데이트해야합니다 . 다른 답변은 내장 라이브러리를 사용하여 버그없이 1/10의 코드로 동일한 작업을 수행합니다.
Addison

답변:


30

이 기사 에서는 추가 노력없이 socketstruct모듈로 이를 수행 할 수 있음을 보여줍니다 . 다음과 같이 기사에 약간 추가했습니다.

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

8
또한 struct.unpack ( 'L', socket.inet_aton (ip)) [0]은 엔디안 여부에 관계없이 'L'이 4 바이트가 아닌 다른 것으로 압축 해제되는 아키텍처에서 실패합니다.
Rafał Dowgird

5
계속해서 Rafal의 의견에 따라 64 비트 Python 인터프리터에서 작동하도록하려면 해당 줄을 다음과 같이 바꾸십시오.return struct.unpack('<L',socket.inet_aton(ip))[0]
nitwit

11
나는 당신의 솔루션은 심각한 버그가 생각 : addressInNetwork('172.7.1.1', '172.3.0.0/16') -> True(나는 내 64 비트 운영 체제에서 '<L' 'L'을 변환)
타하 자한 기르

20
주의 :이 솔루션은 심각한 버그가 :addressInNetwork('172.7.1.1', '172.3.0.0/16') -> True
타하 자한 기르에게

6
이 답변에는 버그가 있습니다. 답변보기 : stackoverflow.com/questions/819355/…
Debanshu Kundu 2014

156

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!"

>>> netaddr.all_matching_cidrs ( "192.168.0.1", [ "192.168.0.0/24","212.11.64.0/19"]) [IPNetwork ( '192.168.0.0/24')]

22
또는 새 버전 : from netaddr import IPNetwork, IPAddress IPAddress ( "192.168.0.1") in IPNetwork ( "192.168.0.0/24")
arno_v 2013

140

사용 IPADDRESS ( 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

이런 식으로 많은 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

2
python-ipaddr은 우리에게 매우 느리게 작동하므로 많은 비교가 자주 필요한 경우에는 적합하지 않을 수 있습니다. YMMV이므로 스스로 벤치마킹하십시오.
drdaeman 2012-06-06

일부 버전에서는 .NET과 같은 Python str 유형 대신 유니 코드 문자열을 제공해야 할 수 있습니다 ipaddress.ip_address(u'192.168.0.1') in ipaddress.ip_network(u'192.168.0.0/24').
Moondoggy

1
이 방법이 네트워크의 주소 목록을 반복하는 것이 걱정되었지만 ipaddress 모듈 __contains__은 네트워크와 브로드 캐스트 주소의 정수 표현을 비교하여 효율적인 방법으로 수행하는 방법을 재정의 하므로 걱정이 되더라도 안심하십시오. .
avatarofhope2


10

이 코드는 Linux x86에서 나를 위해 작동합니다. 엔디 어 니스 문제에 대해서는 전혀 생각하지 않았지만, 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

멋지고 빠릅니다. 몇 가지 간단한 논리 작업을위한 라이브러리가 필요하지 않습니다.
Chris Koston

7

Python3 ipaddress 사용 :

import ipaddress

address = ipaddress.ip_address("192.168.0.1")
network = ipaddress.ip_network("192.168.0.0/16")

print(network.supernet_of(ipaddress.ip_network(f"{address}/{address.max_prefixlen}")))

설명

IP 주소 는 가능한 가장 큰 넷 마스크를 가진 네트워크 로 생각할 수 있습니다 ( /32IPv4의 경우, /128IPv6의 경우)

에 있는지 확인하는 192.168.0.1것은 192.168.0.0/16기본적 192.168.0.1/32으로 서브넷 인지 확인하는 것과 같습니다.192.168.0.0/16


...이 답변이 (아직) 왜 상단에 있는지 확실하지 않습니다.
Filippo Vitale

6

Dave Webb의 솔루션을 시도했지만 몇 가지 문제가 발생했습니다.

가장 근본적으로-일치 여부는 IP 주소를 마스크와 AND로 연결 한 다음 결과가 네트워크 주소와 정확히 일치하는지 확인해야합니다. IP 주소와 네트워크 주소를 AND로 처리하지 않았습니다.

또한 일관성이 절약된다는 가정하에 Endian 동작을 무시하는 것만으로도 옥텟 경계 (/ 24, / 16)의 마스크에 대해서만 작업 할 수 있음을 알았습니다. 다른 마스크 (/ 23, / 21)가 올바르게 작동하도록하기 위해 구조체 명령에 "보다 큼"을 추가하고 바이너리 마스크를 만드는 코드를 모두 "1"로 시작하고 왼쪽으로 (32-mask ).

마지막으로 네트워크 주소가 마스크에 유효한지 확인하고 그렇지 않은 경우 경고 만 인쇄합니다.

결과는 다음과 같습니다.

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

이것은 64 비트에서 안정적으로 작동하는 것으로 보이며 (값이 32 비트이므로 'L'이 실패 함) 합리적인 순서로 값을 반환합니다 (ipaddr은 192.168.0.1의 경우 0xC0A80001이 됨). 또한 "192.168.0.1"에 대한 넷 마스크로 "192.168.0.1/24"에 대응합니다 (표준은 아니지만 가능하고 쉽게
수정할

Python 2.4에서 완벽하게 작동
xlash 2011 년

6

나는 모듈이 필요하지 않을 때 사용하는 것을 좋아하지 않습니다. 이 작업에는 간단한 수학 만 필요하므로 다음은 작업을 수행하는 간단한 기능입니다.

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) 

그것이 포함 된 모듈을 사용하는 위의 솔루션보다 훨씬 빠릅니다.


{TypeError}'map' object is not subscriptable. 당신은 필요 o = list(o)o = map(int, ip.split('.'))
gies0r

5

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)

이것은 여기의 무수한 선택 중에서 내가 가장 좋아하는 것입니다 (댓글 시점, 2017). 감사!
rsaw

5

받아 들여진 대답이 작동하지 않습니다 ... 이로 인해 화가납니다. 마스크는 역방향이며 단순한 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]

예 :

파이썬 스크린 샷


4

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에게 감사드립니다.


시도하고 테스트했습니다. 이 페이지의 모든 소켓 / 구조체 예제에서 이것은 유일한 올바른 것입니다
Zabuzzman 2015-08-07

4

"struct"모듈에 의존하면 엔디안 및 유형 크기에 문제가 발생할 수 있으며 필요하지 않습니다. socket.inet_aton ()도 아닙니다. Python은 점으로 구분 된 쿼드 IP 주소와 매우 잘 작동합니다.

def ip_to_u32(ip):
  return int(''.join('%02x' % int(d) for d in ip.split('.')), 16)

허용 가능한 전체 소스 네트워크 세트에 대해 각 소켓 accept () 호출에서 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)

모듈 가져 오기가 필요하지 않으며 코드는 일치하는 데 매우 빠릅니다.


이 cached_masks는 무엇을 참조합니까 ??
ajin dec

2

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 목록을 두 번째 인수로 제공합니다. 적중 목록이 반환됩니다.


2
# 이것은 바이트 처리에 의한 이상한 바이트없이 제대로 작동합니다.
def addressInNetwork (ip, net) :
    '' '네트워크의 주소입니다' ''
    # 주소를 호스트 순서로 변환하므로 시프트가 실제로 의미가 있습니다.
    ip = struct.unpack ( '> L', socket.inet_aton (ip)) [0]
    netaddr, bits = net.split ( '/')
    netaddr = struct.unpack ( '> L', socket.inet_aton (netaddr)) [0]
    # 모두 1의 값으로 왼쪽으로 이동해야 함, / 32 = 0으로 이동, / 0 = 32로 왼쪽으로 이동
    넷 마스크 = (0xffffffff << (32-int (비트))) & 0xffffffff
    # 적절한 네트워크 주소 만 있으면 네트워크 주소를 마스킹 할 필요가 없습니다.
    return (ip & netmask) == netaddr 

잘못된 netmask값으로 인해 64 비트 OS에서 코드가 올바르게 작동하지 않았습니다 . 나는 그것을 고칠 자유를 얻었습니다.
drdaeman

2

이전 솔루션에는 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");

2

선택한 답변에는 버그가 있습니다.

다음은 올바른 코드입니다.

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)후자가 더 이해할 보인다.


마스크 변환 ((2L<<int(bits)-1) - 1)이 정확 하다고 생각합니다 . 예를 들어 마스크가 16 인 경우 "255.255.0.0"또는 65535L이어야하지만 ((1L << int(bits)) - 1)잘못된 32767L이됩니다.
Chris.Q 2015

@ Chris.Q ((1L << int(bits)) - 1)bits16 으로 설정된 내 시스템에 65535L을 제공합니다 !
Debanshu Kundu 2015

또한, 대한 bits세트 0, ((2L<<int(bits)-1) - 1)오류를 제기된다.
Debanshu Kundu 2015

예, 실제로 / 0, / 8, / 16, / 32 이외의 값은 제대로 작동하지 않습니다.
Debanshu Kundu

2

다음은 가장 긴 접두사 일치를 위해 작성한 클래스입니다.

#!/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

1

스크립트 감사합니다!
나는 모든 것을 작동시키기 위해 꽤 오랫동안 노력했습니다 ... 그래서 여기에서 공유하고 있습니다.

  • netaddr 클래스를 사용하는 것은 바이너리 변환을 사용하는 것보다 10 배 느리므로 큰 IP 목록에서 사용하려면 netaddr 클래스를 사용하지 않는 것이 좋습니다.
  • makeMask 기능이 작동하지 않습니다! / 8, / 16, / 24에서만 작동 함
    예 :

    비트 = "21"; socket.inet_ntoa (struct.pack ( '= L', (2L << int (bits) -1)-1))
    '255.255.31.0'이지만 255.255.248.0이어야합니다.

    그래서 http://code.activestate.com/recipes/576483-convert-subnetmask-from-cidr-notation-to-dotdecima/ 에서 다른 함수 calcDottedNetmask (mask)를 사용했습니다 .
    예 :


#!/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!!

그래서 내 새 addressInNetwork 함수는 다음과 같습니다.


#!/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

다른 사람들에게 도움이되고 시간을 절약 할 수 있기를 바랍니다!


1
위 코드의 현재 버전은 마지막 줄에 "| ="int 및 tuple을 사용할 수있는 트레이스 백을 제공합니다.
Sean Reifschneider 2010

1

위의 모든 것과 관련하여 socket.inet_aton ()은 네트워크 순서로 바이트를 반환한다고 생각하므로 올바른 압축 해제 방법은 아마도

struct.unpack('!L', ... )

1
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
False
True
False


이미 주어진 답변에 무엇을 추가하고 있는지 설명 할 수 있습니까?
David Guyon

주어진 답변에는 CIDR을 처리 할 수없는 문제가 있습니다. 방금 IP 주소의 바이트 순서를 변경했습니다. 다음과 같이 :>>> struct.unpack('!L',socket.inet_aton('10.10.10.110'))[0] 168430190 >>> socket.inet_ntoa(struct.pack('!L', 168430190)) '10.10.10.110'
Johnson

1
답변 해주셔서 감사합니다. 명확히하기 위해 답변에 추가해야 할 것 같습니다. "무엇" "이유"와 마지막으로 "어떻게"를 설명하는 것은 StackOverflow의 정신입니다. 귀하의 답변에는 "어떻게"만 포함되어 있습니다. :(. 편집하여 답변을 완성 할 수 있습니다.).
David Guyon 2013


0

위의 다양한 출처와 내 연구에서 이것이 서브넷 및 주소 계산이 작동하는 방법입니다. 이 조각들은 질문 및 기타 관련 질문을 해결하기에 충분합니다.

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)

0

이 작업을 매우 잘 수행하는 Python에서 사용할 수있는 SubnetTree라는 API가 있습니다. 다음은 간단한 예입니다.

import SubnetTree
t = SubnetTree.SubnetTree()
t.insert("10.0.1.3/32")
print("10.0.1.3" in t)

이것은 링크입니다


0

내 코드는 다음과 같습니다.

# -*- 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')

0

다른 모듈을 가져 오지 않으려면 다음을 사용할 수 있습니다.

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]

0

이 답변에서 제안 된 솔루션 중 하나를 시도했습니다. 성공하지 못한 상태에서 마침내 제안 된 코드를 수정하고 수정 한 후 고정 함수를 작성했습니다.

나는 그것을 테스트하고 적어도 리틀 엔디안 아키텍처 (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

유용한 희망,


0

다음은 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)
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.