programing

파이썬에서 ip가 네트워크에 있는지 확인하려면 어떻게 해야 합니까?

goodsources 2023. 9. 8. 21:27
반응형

파이썬에서 ip가 네트워크에 있는지 확인하려면 어떻게 해야 합니까?

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

파이썬에 ip 주소 조작을 위한 일반적인 도구가 있습니까?호스트 룩업, ip address to int, netmask to int 등?바라건대 표준 파이썬 라이브러리에서 2.5용으로.

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

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

python3의 경우

import ipaddress
ipaddress.IPv4Address('192.168.1.1') in ipaddress.IPv4Network('192.168.0.0/24')
ipaddress.IPv4Address('192.168.1.1') in ipaddress.IPv4Network('192.168.0.0/16')

출력 :

False
True

기사는 과한 노력 없이 모듈로 할 수 있음을 보여줍니다.기사에 다음과 같이 조금 덧붙였습니다.

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

Python >= 3.7 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 주소는 가능한 넷마스크가 가장 큰 네트워크라고 생각할 수 있습니다./32 IPv4우의 경우,/128IPv6의 경우)

192.168.0.1에 있습니다192.168.0.0/16을는과로다로r과을sgsseyer 192.168.0.1/32은 의 서브넷입니다.192.168.0.0/16

이 코드는 리눅스 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

가능한 한 내장된 ipaddress 모듈을 추천합니다.Python 3에서만 사용할 수 있지만 사용이 매우 간편하고 IPv6도 지원합니다.근데 왜 아직도 파이썬3를 사용하지 않는 거지?


인정된 대답은 통하지 않습니다...화가 납니다.마스크는 역방향이며 간단한 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]

예:

screen shot of python

저는 모듈이 필요 없을 때 모듈을 사용하는 것을 좋아하지 않습니다.이 직업은 단순한 수학만 필요하므로, 이 직업을 수행하기 위한 간단한 기능은 다음과 같습니다.

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) 

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

2.5용 Standard 라이브러리에는 없지만 ipaddr을 사용하면 이 작업이 매우 쉬워집니다.ip address라는 이름으로 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)

데이브 웹의 해결책을 시도했지만 몇 가지 문제가 생겼습니다.

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

또한 일관성이 당신을 살릴 것이라고 가정하고 엔디안의 행동을 무시하는 것만으로도 옥텟 경계의 마스크에만 효과가 있다는 것을 알게 되었습니다(/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 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로 표시됩니다.저는 이 코드를 작동시키는데 많은 시간을 보냈고 마크에게 정답을 알려주셔서 감사합니다.

"구조" 모듈에 의존하는 것은 엔디안성과 타입 크기에 문제를 일으킬 수 있으므로 불필요합니다.소켓도 아닙니다.inet_aton ().Python은 점선 쿼드 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)

모듈을 가져올 필요가 없고 코드가 일치하는 속도가 매우 빠릅니다.

파이썬 3.7부터는 표준 라이브러리의 일부인 메소드와 헬퍼 메소드를 사용할 수 있습니다.

에 대해 마스크 IP 하려면 를 하면 하면 을 사용하면 됩니다./32으로서 "을 하거나, IP 은 이 을 만 하거나 는 다 할 ", "IP "를 "에게 할 수 .IPv4Nework아니면IPv6Nework생성자가 서브넷 값을 반환합니다.

예를 들어,

from ipaddress import IPv4Network, IPv4Address

# Store IP Address as variable
>>> myip = IPv4Address('192.168.0.1')
>>> myip
IPv4Address('192.168.0.1')

# This treats the IP as a subnet
>>> myip_subnet = IPv4Network(myip)
>>> myip_subnet
IPv4Network('192.168.0.1/32')

# The other subnet to test membership against
>>> other_subnet = IPv4Network('192.168.0.0/24')
>>> other_subnet
IPv4Network('192.168.0.0/24')

# Now we can test
>>> myip_subnet.subnet_of(other_subnet)
True

파이썬에 ip 주소 조작을 위한 일반적인 도구가 있습니까?호스트 룩업, ip address to int, netmask to int 등?바라건대 표준 파이썬 라이브러리에서 2.5용으로.

파이썬 3에는 IPv4와 IPv6 조작을 위한 도구가 있는 모듈이 있습니다.캐스팅을 통해 인트로 변환할 수 있습니다.int(IPv4Address('192.168.0.1')) 은 . . . . . . . . . . . . .ipaddress호스트 등을 위한 모듈

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

올바른 코드는 다음과 같습니다.

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)가 더 수 것 같기 에, 가 입니다 할 입니다 가 할 .

from netaddr 가져오기 all_graphics_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 주소를 제공하고 두 번째 인수로 cidrs 목록을 제공합니다.히트 목록이 반환됩니다.

#이상한 바이트 처리 없이도 제대로 작동합니다.def 주소네트워크(ip,net):'''네트워크의 주소'''# 주소를 호스트 순서로 변환하여 이동에 실질적인 도움이 됨ip = struct.unpack('>L', socket.inet_aton(ip)[0]netaddr,비트 = net.tw/)netaddr = struct.unpack('>L', 소켓.inet_aton(netaddr)[0]# 모든 값을 왼쪽으로 시프트해야 합니다. /32 = 0시프트, /0 = 32시프트 왼쪽netmask = (0xffffff< (32비트)) & 0xffffff# 적절한 네트워크 주소만 있으면 네트워크 주소를 숨길 필요가 없습니다.return (ip & netmask) == netaddr

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

가장 긴 접두사 일치를 위해 작성한 클래스는 다음과 같습니다.

#!/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 Class를 사용하는 것은 이진 변환을 사용하는 것보다 10배 느리기 때문에 큰 IP 목록에 사용하려면 netaddr class를 사용하지 않는 것을 고려해야 합니다.
  • 작동하지 !makeMask 하지!//8,/16,/24에 대해서만 합니다.
    예:

    비트 = "21"; 소켓.('=L (<<(비트 (2L << int(비트)-1'), (2L << int(비트))-1)
    '인 반면 '255.255.31.0'이어야 '255.255.248.0'이어야 합니다.

    그래서 저는 http://code.activestate.com/recipes/576483-convert-subnetmask-from-cidr-notation-to-dotdecima/ 의 다른 기능 calcDotedNetmask(마스크)를 사용했습니다.
    예:


#!/usr/bin/python
>>> calcDottedNetmask(21)
>>> '255.255.248.0'
  • 다른 문제는 가 네트워크경우 과정입니다 일치하는 속할 basic ! 과정입니다! Basic & & netmask를 비교해야 .기본 작동은 (ipaddr & netmask) 비교해야 (network & netmask) 합니다 를 와 합니다 비교해야 network ( 기본 작동은 net ipad )
    가 틀립니다 Ex: 은 이 은 이

#!/usr/bin/python
>>> addressInNetwork('188.104.8.64','172.16.0.0/12')
>>>True which is completely WRONG!!

그래서 나의 새 주소는InNetwork 기능 모양:


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

저는 그것이 다른 사람들을 위해 시간을 절약하면서 그들에게 도움이 되기를 바랍니다!

위의 모든 것과 관련하여, 소켓이라고 생각합니다.inet_aton''는 바이트를 네트워크 순서대로 반환하므로 올바른 압축 풀기 방법은 다음과 같습니다.

struct.unpack('!L', ... )
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

진실의

표준 라이브러리에는 아무것도 모르지만, PySubnetTree는 서브넷 매칭을 할 Python 라이브러리입니다.

위의 다양한 출처와 자체 조사를 통해 서브넷과 주소 계산이 이렇게 작동하게 되었습니다.이 조각들은 문제와 관련된 다른 문제들을 풀기에 충분합니다.

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)

파이썬에서 사용 가능한 SubnetTree라는 API가 있으며 이 작업을 매우 잘 수행합니다.다음은 간단한 예입니다.

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

링크입니다.

여기 내 코드가 있습니다.

# -*- 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]

저는 이 답변들에서 제안된 솔루션의 하위 집합을 시도했습니다.결국 저는 제안된 코드를 수정하고 수정하여 제 고정된 기능을 작성하였습니다.

테스트를 해봤는데 적어도 x86과 같은 작은 엔디언 아키텍처에서 작업하고 있습니다. 큰 엔디언 아키텍처를 사용해보고 싶은 사람이 있다면 피드백을 주세요.

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

유용한 희망,

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)

내장 모듈이나 타사 모듈이 시간이 지남에 따라 구문을 변경하는 것을 방지하기 위해 이를 수행하는 자체 모듈을 만들었습니다.저는 이것을 중요한 모듈로 사용하고 있습니다.이것이 누군가에게 도움이 되기를 바랍니다.


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)

이 기능은 IP 주소가 Private IP Subnet 또는 Public Subnet Domain에 속하는지 확인합니다.

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

언급URL : https://stackoverflow.com/questions/819355/how-can-i-check-if-an-ip-is-in-a-network-in-python

반응형