簡體   English   中英

給定兩個文件(IP和子網信息),創建將每個IP與子網關聯的文件

[英]Given two files (IP's and Subnet Info), create file that associates each IP to a subnet

我一直在努力尋找解決此問題的正確方法幾天,我正在尋求幫助。

我有兩個文件,需要創建第三個文件來顯示關系。

  1. IP地址文件-ip.csv
  2. 子網文件-subnet.csv

我需要指定每個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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM