sonickun.log

備忘録

任意のIPv4アドレスRangeをPrefix表記に変換する[はじめてのRuby]

 "192.168.192.48 - 192.168.192.79"といった始点と終点によって定義されるIPアドレス空間を,"192.168.192.48/27"というPrefix表記に変換するスクリプトです.

 サブネットマスクの計算方法は下のリンクを参照してください.
 基礎から学ぶWindowsネットワーク:第7回 IPアドレスとネットマスク (3/3) - @IT

Input Data

 IPアドレスのリストをI-Blocklistというサイトから入手しました.このサイトは,世界中の政府機関,教育機関,研究機関などが公開しているIPアドレスのリストを提供しています.
 今回は教育機関のIPアドレスのリストを使いました.

bt_edu.txt

China Education and Research Network - Nanjing:1.51.0.0-1.51.255.255
Jinan University:1.184.0.0-1.184.127.255
China Education and Research Network - Guangzhou:1.184.0.0-1.185.255.255
Istituto Statale Secondario Superiore Pacifici de Magistris Priverno:2.119.234.168-2.119.234.175
s0-1.championsschoolofrea.bbnplanet.net:4.0.32.62-4.0.33.4
Education Management Corporation:4.2.144.0-4.2.144.31
Concordia University:4.2.160.32-4.2.160.63
American Education Centers:4.2.161.32-4.2.161.39
United Schools District:4.2.161.96-4.2.161.127
Education Management Corporation:4.2.170.0-4.2.170.31
American Education Centers, Inc:4.2.173.16-4.2.173.23
United Schools District:4.2.173.96-4.2.173.127
Sewickley Academy:4.2.174.0-4.2.175.255
City of Pittsfield Schools:4.2.176.192-4.2.176.223
Taft School:4.2.176.240-4.2.176.255
Taft School:4.2.179.128-4.2.179.191
Alice Lloyd College:4.2.224.160-4.2.224.175
Learning Tree:4.2.225.0-4.2.225.63
Kennedy Krieger Institute:4.17.69.128-4.17.69.159
New Bedford Public Schools:4.17.112.0-4.17.112.255
...

このように,1行ごとに「"組織名":"IPレンジ"」という形式で書かれています.

Script

 はじめてRuby書きました.

def inet_aton ip
  ip.split(/\./).map{|c| c.to_i}.pack("C*").unpack("N").first
end

def inet_ntoa n
  [n].pack("N").unpack("C4").join(".")
end

def get_forward_prefixes(s,e)
  prefixes = []
  while s <= e
    len = 32 - ((Math.log(e - s + 1) / Math.log(2)).to_i).floor
    prefixes << "#{inet_ntoa(s)}/#{len}"
    s = s + 2 ** (32 - len)
  end
  return prefixes
end

def get_backward_prefixes(s,e)
  prefixes = []
  while s <= e
    len = 32 - ((Math.log(e - s + 1) / Math.log(2)).to_i).floor
    prefix = inet_ntoa(e - 2 ** (32 - len) + 1)
    prefixes << "#{prefix}/#{len}"
    e = e - 2 ** (32 - len) 
  end
  return prefixes.reverse
end

def get_prefixes(s, e)
  return [] if e < s
  prefixes = []
  if (s & 0x000000ff == 0) 
    prefixes = get_forward_prefixes(s,e)
  else
    if (e & 0xffffff00) > (s & 0xffffff00) 
      prefixes = 
        get_backward_prefixes(s, (e & 0xffffff00) - 1) +
        get_forward_prefixes(e & 0xffffff00, e)
    else
      l = e - s + 1
      base = s & 0xffffff00
      width = 2 ** ((Math.log(l) / Math.log(2)).to_i.floor - 1)
      i = 0
      while i < (s & 0x000000ff)
        i += width
      end
      prefixes = 
        get_backward_prefixes(s, base + i - 1) + 
        get_forward_prefixes(base + i, e)
    end
  end
  return prefixes
end

File.open("out.txt","w") do |out|
  open ("bt_edu.txt"){|file|
    puts "start"
    while l = file.gets
      a = l.split(/:/)
      b = a[1].split(/-/)
      for p in get_prefixes(inet_aton(b[0]),inet_aton(b[1])) do
        out.write(a[0] + ":" + p + "\n")
      end
    end
  }
end
puts "finished"


Output Data

 実行結果は次のようになります.

out.txt

China Education and Research Network - Nanjing:1.51.0.0/16
Jinan University:1.184.0.0/17
China Education and Research Network - Guangzhou:1.184.0.0/15
Istituto Statale Secondario Superiore Pacifici de Magistris Priverno:2.119.234.168/29
s0-1.championsschoolofrea.bbnplanet.net:4.0.32.62/31
s0-1.championsschoolofrea.bbnplanet.net:4.0.32.64/26
s0-1.championsschoolofrea.bbnplanet.net:4.0.32.128/25
s0-1.championsschoolofrea.bbnplanet.net:4.0.33.0/30
s0-1.championsschoolofrea.bbnplanet.net:4.0.33.4/32
Education Management Corporation:4.2.144.0/27
Concordia University:4.2.160.32/27
American Education Centers:4.2.161.32/29
United Schools District:4.2.161.96/27
Education Management Corporation:4.2.170.0/27
American Education Centers, Inc:4.2.173.16/29
United Schools District:4.2.173.96/27
Sewickley Academy:4.2.174.0/23
City of Pittsfield Schools:4.2.176.192/27
Taft School:4.2.176.240/28
Taft School:4.2.179.128/26
Alice Lloyd College:4.2.224.160/28
Learning Tree:4.2.225.0/26
Kennedy Krieger Institute:4.17.69.128/27
New Bedford Public Schools:4.17.112.0/24
...

 このように,IPアドレスがPrefix表記に変換されています.
 
 "s0-1.championsschoolofrea.bbnplanet.net"の行を見ると分かりますが,1通りのPrefix表記では表せない場合でも無理やり変換してくれます.

 個人的にこれで何をしたいかというと,IPアドレスの探索やマッチングに使えたらいいなと思っています.そのプログラムは現在Pythonで書いているので後ほど...

補足

 ちなみにPythonで書くと、こんなかんじになります。

>>> from ipaddress import ip_address, summarize_address_range
>>> first = ip_address(u'192.168.1.0')
>>> last = ip_address(u'192.168.1.200')
>>> pre = list(summarize_address_range(first,last))
>>> for h in pre:
...  print str(h)
...
192.168.1.0/25
192.168.1.128/26
192.168.1.192/29
192.168.1.200/32