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