require 'whatmask/version' class Whatmask def initialize(mask, address=nil) @mask = get_mask(mask) if /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/.match(address) @address = octets_to_bin(address) end @allones = "11111111111111111111111111111111".to_i(2) validate(@mask) end def address return bin_to_octets(@address) if @address end def network return bin_to_octets(get_network) if @address end def broadcast return bin_to_octets(get_broadcast) if @address end def first if @mask != @allones return bin_to_octets(get_network+1) if @address end return address if @address end def last if @mask != @allones return bin_to_octets(get_broadcast-1) if @address end return address if @address end def inverse return bin_to_octets(get_inverse) end def mask return bin_to_octets(@mask) end def hex return bin_to_hex(@mask) end def cidr return @mask.to_s(2).count('1') end def avail return ((2**(32-cidr))-2) if cidr <= 30 return 1 end private def get_network return (@address & @mask) end def get_inverse return (@mask ^ @allones) end def get_broadcast return (get_network | get_inverse) end def validate(mask) mask = bin_to_32bit(mask) if mask[0] == '1' if /1/.match(mask.sub(/1+/, '0')) == nil return 1 else abort 'whatmask: "'+mask+'" is not a valid subnet mask or wildcard bit mask!' end elsif mask == '0'*32 return 1 elsif mask[0] == '0' if /0/.match(mask.sub(/0+/, '1')) == nil @mask = get_inverse return 1 else abort 'whatmask: "'+mask+'" is not a valid subnet mask or wildcard bit mask!' end else abort 'whatmask: error encountered in validation' end end def get_mask(mask) if (/\h\h\h\h\h\h\h\h/ =~ mask) == 2 return mask.hex elsif mask.length <= 2 return cidr_to_bin(mask) elsif /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/.match(mask) return octets_to_bin(mask) else abort 'whatmask: "'+mask+'" is not a valid subnet mask or wildcard bit mask!' end end def bin_to_32bit(bin) bits = bin.to_s(2) while bits.length < 32 bits = '0'+bits end return bits if (bits.length <= 32) abort 'whatmask: "'+bin+'" is greater than 32 bits!' end def bin_to_octets(bin) bin = bin.to_s(2) while bin.length < 32 bin = '0'+bin end return bin.scan(/.{8}/).map { |b| b.to_i(2) }.join('.') end def bin_to_hex(bin) bin = bin.to_s(2) while bin.length < 32 bin = '0'+bin end return '0x'+bin.scan(/.{8}/).map { |b| ('0'+b.to_i(2).to_s(16))[-2,2] }.join end def octets_to_bin(octets) bin = octets.split('.').map { |octet| octet = octet.to_i.to_s(2) if octet.length > 8 abort 'whatmask: "'+octets+'" is not a valid subnet mask or wildcard bit mask, or ip address!' end while octet.length < 8 octet = '0'+octet end octet }.join.to_i(2) return bin end def cidr_to_bin(cidr) bin = '' if (0..32) === cidr.to_i for i in 0..(cidr.to_i-1) bin = '1'+bin end while bin.length < 32 bin = bin+'0' end return bin.to_i(2) else abort 'whatmask: '+cidr+' is an invalid CIDR mask!' end end end