Ruby版
# coding: utf-8 def ip_to_b(addr) addr.split(".").map{|x| sprintf("%08d", x.to_i.to_s(2).to_i)}.join("") end def in_subnet?(addr, subnet) addr_b = ip_to_b(addr) subnet_addr, mask = subnet.split("/") subnet_addr_b = ip_to_b(subnet_addr) mask = mask.to_i addr_b.slice(0...mask) == subnet_addr_b.slice(0...mask) end addr = "192.168.1.5" subnet = "192.168.1.0/24" puts in_subnet?(addr, subnet) addr2 = "127.0.0.1" puts in_subnet?(addr2, subnet)
takatoh@nightschool $ ruby is_in_subnet.rb true false
ちょっとトリッキーなのは、ip_to_b メソッドの sprintf のところ。頭に 0 をつけて8桁にするために、2進数(の文字列)にしたものを1と0だけからなる10進数だとみなして、%08d というフォーマットに変換している。これで IPアドレスの . で区切られた4つの部分のそれぞれが8桁(言い換えると8ビット)になる。
結果は上に示したとおり。192.18.1.5 はサブネット 192.168.1.0/24 に含まれるけど、127.0.0.1 は含まれない。
Python版
やってることは Ruby 版と同じ。
# coding: utf-8 def ip_to_b(addr): return "".join(map(lambda x: "%08d" % int(bin(int(x))[2:]), addr.split("."))) def is_in_subnet(addr, subnet): addr_b = ip_to_b(addr) subnet_addr, mask = subnet.split("/") subnet_addr_b = ip_to_b(subnet_addr) mask = int(mask) return addr_b[:mask] == subnet_addr_b[:mask] addr = "192.168.1.5" subnet = "192.168.1.0/25" print is_in_subnet(addr, subnet) addr2 = "127.0.0.1" print is_in_subnet(addr2, subnet)
当然結果も同じ。
takatoh@nightschool $ python is_in_subnet.py True False