Aggregator.rb
This content was produced by an LLM and could include errors.
このスクリプトはIPアドレスリストの集約ツールです。summarize_ips は重複排除・整数ソート後、連続するアドレスを chunk_while で1つの範囲にまとめ、largest_block が可能な限り大きい整列ブロックを貪欲に選んでCIDR列へ展開します。例では 192.168.1.0 と .1 が /31 の1ブロックに要約されます。cidrs_to_acl は /32 を host xxx 表記へ、それ以外をネットマスク表記へ変換します。
def summarize_ips(ip_list, min_mask: 0)
ips = ip_list.uniq.map { IPAddr.new(_1) }.sort_by(&:to_i)
ips.chunk_while { |a, b| b.to_i == a.to_i + 1 }
.flat_map { |c| range_to_cidrs(c.first, c.last, min_mask: min_mask) }
end
#=> :summarize_ips
def cidrs_to_acl(entries)
entries.map { |e| cidr_to_acl(e) }
end
#=> :cidrs_to_acl
def mask_to_netmask(mask)
[(0xffffffff << (32 - mask)) & 0xffffffff]
.pack('N').unpack('C4').join('.')
end
#=> :mask_to_netmask
def cidr_to_acl(entry)
ip, mask = entry
return "host #{ip}" if mask == 32
"#{ip} #{mask_to_netmask(mask)}"
end
#=> :cidr_to_acl
def largest_block(start_ip, end_ip, min_mask)
mask = 32
best = [start_ip.to_s, 32]
while mask >= min_mask
block = IPAddr.new("#{start_ip}/#{mask}")
break unless block.to_range.first == start_ip
break if block.to_range.last > end_ip
best = [start_ip.to_s, mask]
mask -= 1
end
best
end
#=> :largest_block
def range_to_cidrs(start_ip, end_ip, min_mask:)
res = []
cur = start_ip
while cur <= end_ip
ip_str, mask = largest_block(cur, end_ip, min_mask)
res << [ip_str, mask]
block = IPAddr.new("#{cur}/#{mask}")
cur = IPAddr.new(block.to_range.last.to_i + 1, Socket::AF_INET)
end
res
end
#=> :range_to_cidrs
ips = ['192.168.1.0', '192.168.1.1']
#=> ["192.168.1.0", "192.168.1.1"]
raw = summarize_ips(ips)
#=> [["192.168.1.0", 31]]
cidrs_to_acl(raw)
#=> ["192.168.1.0 255.255.255.254"]
Ruby 4.0.6