[英]Given two files (IP's and Subnet Info), create file that associates each IP to a subnet
我一直在努力尋找解決此問題的正確方法幾天,我正在尋求幫助。
我有兩個文件,需要創建第三個文件來顯示關系。
我需要指定每個IP所在的子網,並創建第三個文件
ip.csv文件將包含大約150萬個IP,subnet.csv文件將包含大約140,000個子網。
ip.csv文件示例:
IP,Type
10.78.175.167,IPv4
10.20.3.56,IPv4
subnet.csv文件樣本:
Subnet,Netmask
10.176.122.136/30,255.255.255.252
10.20.3.0/24,255.255.254.0
我需要創建的文件格式:
Subnet,IP
10.20.3.0/24,10.20.3.56
我試圖利用這些頁面中的內容:
這是我嘗試過的代碼。 它適用於小型集合,但是我無法在完整文件集上運行它。
#!/usr/local/bin/python2.7
import csv
import ipaddress
import iptools
import re
import SubnetTree
import sys
from socket import inet_aton
testdir = '/home/test/testdir/'
iprelfile = testdir + 'relationship.csv'
testipsub = testdir + 'subnet.csv'
testipaddr = testdir + 'ip.csv'
o1 = open (iprelfile, "a")
# Subnet file
IPR = set()
o1.write('Subnet,IP\n')
with open(testipsub, 'rb') as master:
reader = csv.reader(master)
for row in reader:
if 'Subnet' not in row[0]:
# Convert string to unicode to be parsed with ipaddress module
b = unicode(row[1])
# Using ipaddress module to create list containing every IP in subnet
n2 = ipaddress.ip_network(b)
b1 = (list(n2.hosts()))
# IP address file
with open(testipaddr, 'rb') as ipaddy:
readera = csv.reader(ipaddy)
for rowa in readera:
if 'IP' not in rowa[0]:
bb = rowa[0]
for ij in b1:
# Convert to string for comparison
f = str(ij)
# If the IP address is in subnet range
if f == bb:
IPR.update([row[0] + ',' + bb + '\n'])
for ip in IPR:
o1.write(ip + '\n')
# Closing the file
o1.close()
您可以將所有子網讀取到內存中,然后按網絡地址對其進行排序。 這將允許您使用bisect
進行二進制搜索,以便找到每個IP的子網。 這僅在子網彼此不重疊時才有效,如果子網重疊,則可能需要使用線段樹 。
import bisect
import csv
import ipaddress
def sanitize(ip):
parts = ip.split('/', 1)
parts[0] = '.'.join(str(int(x)) for x in parts[0].split('.'))
return '/'.join(parts)
with open('subnet.csv') as subnet_f:
reader = csv.reader(subnet_f)
next(reader) # Skip column names
# Create list of subnets sorted by network address and
# list of network addresses in the same order
subnets = sorted((ipaddress.IPv4Network(sanitize(row[0])) for row in reader),
key=lambda x: x.network_address)
network_addrs = [subnet.network_address for subnet in subnets]
with open('ip.csv') as ip_f, open('output.csv', 'w', newline='') as out_f:
reader = csv.reader(ip_f)
next(reader)
writer = csv.writer(out_f)
writer.writerow(['Subnet', 'IP'])
for row in reader:
ip = ipaddress.IPv4Address(sanitize(row[0]))
index = bisect.bisect(network_addrs, ip) - 1
if index < 0 or subnets[index].broadcast_address < ip:
continue # IP not in range of any networks
writer.writerow([subnets[index], ip])
輸出:
Subnet,IP
10.20.3.0/24,10.20.3.56
上面的時間復雜度為O(n log m) ,其中n是IP數量,m是網絡數量。 請注意,由於ipaddress
不包含在Python 2.7中,因此它僅與Python 3一起運行。 如果您需要使用Python 2.7,則可以使用反向移植 。
更新高效解決方案的首要目標是找到一種以高效方式處理每個IP的方法。 遍歷所有子網非常昂貴,因此不會這樣做。 在每個子網中創建第一個IP的排序列表要好得多。 對於給定的數據,它看起來像這樣:
[IPv4Address('10.20.3.0'), IPv4Address('10.176.122.136')]
這將使我們能夠執行二進制搜索,以查找等於或低於單個IP的IP地址索引。 例如,當我們搜索IP 10.20.3.56時,我們使用bisect.bisect
為我們提供大於IP的第一個索引,並將其減一:
>>> l = [IPv4Address('10.20.3.0'), IPv4Address('10.176.122.136')]
>>> index = bisect.bisect(l, IPv4Address('10.20.3.56'))
>>> index
1
>>> l[index - 1]
IPv4Address('10.20.3.0')
由於我們已將網絡存儲到另一個列表中,並且順序相同,因此可以使用索引來檢索給定的子網。 擁有子網后,我們仍然需要檢查單個IP是否等於或小於子網中的最后一個IP。 如果單個IP在子網內,則寫一行以得出結果,如果不移到下一個IP。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.