Da ozivim malo ovu temu ... nedavno sam naleteo na musteriju koji u svojoj Cisco konfiguraciji ima bas ovakve nezgodne netmaske ... i to ogromne liste pune takvi stvari - npr.:
Code:
ip access-list standard ACL-CUST-RANGES
permit 10.192.64.0 0.15.63.255
...
Posto vecina modernih (non-Cisco) rutera podrzava uglavnom samo lepe CIDR blokove ovo zahteva bas mukotrpan rad - recimo ova gore lista postaje:
Code:
10.192.64.0/18, 10.193.64.0/18, 10.194.64.0/18, 10.195.64.0/18, 10.196.64.0/18, 10.197.64.0/18,
10.198.64.0/18, 10.199.64.0/18, 10.200.64.0/18, 10.201.64.0/18, 10.202.64.0/18, 10.203.64.0/18,
10.204.64.0/18, 10.205.64.0/18, 10.206.64.0/18, 10.207.64.0/18
Posto sam pretrazio sve po netu da nadjem neku skriptu/modul da mi ovo resi - najpre Python modul netaddr, pa ipaddr, pa jos 2-3 slicna ... nijedan nije imao resenje za ovakve probleme. Zavrnuo sam rukave i napravio nesto "domace". I koliko vidim lepo radi, za vecinu normalnih slucajeva (ipak niko danas nece koristiti sulude netmaske poput 0.254.254.254 koje bi - priznajem - razbile ovu skriptu dole, jer je algoritam O(2**N)). Otkud znam, verovatno moze da se napravi i bolje ako se koriste neke naprednije strukture podataka, ali posto ja nisam developer po struci meni ovo dole lepo radi. Koristi se vrlo retko, jednokratno ... pa i ako naleti neka nezgodna netmaska nije problem sacekati da komp ovo sazvace.
Ako nekome ikada zatreba nesto ovako - evo koda:
Code (python):
#!/usr/bin/python
import sys
from netaddr import *
from itertools import combinations
#
# non_cidr() - Convert non-CIDR Cisco ACL (e.g. 172.0.0.0/0.15.63.255) into a CIDR range.
# Can easily be modified to handle "classic" netmasks (e.g. 255.240.192.0).
#
def non_cidr(ip, mask):
ip_range = IPSet()
ip_range_hosts = set()
bin_ip = int(IPAddress(ip)) # int() of the IP address (e.g. 10.0.0.1 == 167772161)
bin_mask = int(IPAddress(mask)) # int() of the Cisco ACL mask (e.g 0.0.15.255 == 4095)
if (not bin_mask):
ip_range.add(IPNetwork(ip + '/32'))
return ip_range
if (bin_ip & bin_mask):
sys.stderr.write ('non_cidr(): Error - netmask bits overlap with the network address\n')
return -1
try:
# - Have we got a nice CIDR-like range alraedy? Then waste no more time ...
ip_range.add(IPNetwork(ip + '/' + mask))
except:
# - Not CIDR-able? Well, we'll have some tough time then ...
bit = 1 # Bit-iterator, used to shift left ...
pos = [] # Keeps track of bit positions where bit value is 1
# A bit of background story here: the cisco ACL netmask is a string of bits.
# Bit value of 1 indicates a bit position in the IP network which changes.
# For instance - acl '10.0.0.0 0.0.0.3' means last 2 bits (11) change,
# so IP addresses matching the acl are: 10.0.0.0, 10.0.0.1, 10.0.0.2, 10.0.0.3
# The last 2 bits are all possible permutations of two bits (00, 01, 10, 11).
#
# If the ACL is '10.0.0.22 0.0.192.0', then the first two bits of byte 3 change,
# giving the adddresses: 10.0.0.22, 10.0.64.22, 10.0.128.22, 10.0.192.22.
#
# So, we first determine all bit positions (bp) in the netmask being 1 and
# we put the 2**bp values into the list ones. For instance:
#
# Subnet mask: 0.1.1.255 => ones = [1, 2, 4, 8, 16, 32, 64, 128, 256, 65536]
# We need to iterate bits on those positions between 0 and 1.
# Mathematically, this gives all combinations of numbers in this list.
#
# However, we're getting an O(2**N) algorithm, where N is the number of ones
# in the bit string ... which is slow like a snail!
# OTOH, most engineers won't ever use netmasks like 170.170.170.170, but rather
# things like: 0.0.252.255, 0.252.255.255 ... so the idea is: split this mask
# to a CIDR-able part and non-CIDR-able part and remember the border position
# of those partitions with the variable 'gap'. Then, iterate only the part of
# the netmask left to the gap, while everything right from the gap will use
# the standard 'netaddr' module functions to generate the CIDR range.
# That mehtod speeds up the process dramatically for most use cases!
#
# That mehtod speeds up the process dramatically for most realistic use cases,
# since we reduce N to the amount of "ones" left to the gap position only.
gap = -1
for i in range (0,32):
if (bit & bin_mask):
pos.append(bit)
elif (gap < 0):
gap = i
bit <<= 1
pos=pos[gap:]
# - pos = e.g. [1, 256, 65536] <=> 0.1.1.1
for i in range(0,len(pos)+1):
for j in combinations(pos, i):
bitmask = sum(j)
ip_range.add(IPNetwork(str(IPAddress(int(IPAddress(ip))|bitmask))+'/'+str(32-gap)))
# - Always return ip_range as IPSet()
return ip_range
### - MAIN
all_addrs = IPSet()
for line in sys.stdin.readlines():
ip,mask = line.strip().replace('permit','').replace('deny','').split()
all_addrs |= non_cidr(ip,mask)
for i in all_addrs.iter_cidrs():
print str(i)
Primer:
$ ./acl2ip.py
10.224.64.0 0.7.63.255
<Ctrl-D>
10.224.64.0/18
10.225.64.0/18
10.226.64.0/18
10.227.64.0/18
10.228.64.0/18
10.229.64.0/18
10.230.64.0/18
10.231.64.0/18
$
[Ovu poruku je menjao B3R1 dana 08.05.2021. u 12:10 GMT+1]