山本 健吾です。
最近のサイン本ブームに触発されて(^^;スクリプトを書いてみました。
これでエントリさせて下さい。
IPアドレス用の計算機(199行)です。いろいろと怠ける事ができます。
・ブロードキャストアドレスを求める
ipcalc 192.168.33.43/28 b
192.168.33.47/28
・ネットワークアドレスを求める
ipcalc 172.16.38.32/22 n
172.16.36.0/22
・/27の点区切り10進表記をド忘れしたとき
ipcalc /27
255.255.255.224
・ネットワークを8つに割り、5番目のサブネットのブロードキャストを求める
ipcalc '(172.28.38.17/25 n // 8)[4] b'
172.28.38.79/28
・ネットワークを4つに割り、それぞれのサブネットの先頭と終りのホストア
ドレスを列挙する
ipcalc '(192.168.22.0//4).collect{|sub| [sub + 1, sub b - 1]}'
[192.168.22.1, 192.168.22.62, 192.168.22.65, 192.168.22.126, 192.168.22.129, 192.168.22.190, 192.168.22.193, 192.168.22.254]
↑このあたりで手抜きがバレますね(^^;
他にも演算子(のふりをしたメソッド)があるのですが、あまり使用しないと思
います。
----------------------------------------------------------------------
#!/usr/local/bin/ruby
# ipcalc : An IP address calculator
# Written by Yamamoto Kengo 1998/2/22
class DottedDecimal
def initialize(seed)
@value = 0
if seed.is_a?(String) && seed =~ /^\d+(\.\d+)+$/
seed.split(/\./).each{|octet|
@value <<= 8
@value += octet.to_i
}
else
@value = seed.to_i
end
raise "invalid value #{to_s} for #{type}" unless valid?
end
def valid?
true
end
def to_s
value = @value
string = []
for i in 1..value.size
octet = (value & 0xff).to_s
string.unshift(octet)
value >>= 8
end
string.join('.')
end
def to_i
@value
end
def ==(other)
@value == other.to_i
end
def <=(other)
@value <= other.to_i
end
def >=(other)
@value >= other.to_i
end
def <(other)
@value < other.to_i
end
def >(other)
@value > other.to_i
end
def +(other)
DottedDecimal.new(@value + other.to_i)
end
def -(other)
DottedDecimal.new(@value - other.to_i)
end
def &(other)
DottedDecimal.new(@value & other.to_i)
end
def |(other)
DottedDecimal.new(@value | other.to_i)
end
end
class Netmask < DottedDecimal
def initialize(seed)
seed = 32 if seed.nil?
if seed.is_a?(String) && seed =~ /^\/?\d+$/
seed = seed.sub(/\//, '').to_i
end
if seed.is_a?(Integer) && seed <= 32
seed = (0xffffffff >> seed) ^ 0xffffffff
end
super(seed)
end
def valid?
generated_by_length = (0xffffffff >> length) ^ 0xffffffff
@value == generated_by_length
end
def length
border = 0
while @value[border] == 0 && border <= 31
border += 1
end
32 - border
end
def inv
@value ^ 0xffffffff
end
end
class IPAddress < DottedDecimal
def initialize(address = nil, mask = nil)
if address.is_a?(String) && address =~ /^(\d+(\.\d+){3})(\/(\d+))?$/
address = $1
mask = $4 if $4
end
@mask = Netmask.new(mask) unless mask.nil? || mask == ''
super(address)
end
def valid?
(0..0xffffffff) === @value
end
def to_s
super + '/' + netmask.length
end
def rawaddr
DottedDecimal.new(@value)
end
def /(n)
bits = 0
nth = 0
for i in 0..31
if n[i] == 1
bits += 1
nth = i
end
end
newmask = netmask | (netmask.to_i >> nth)
blocksize = (netmask.inv + 1) / n
if bits == 1 && host(netmask) == 0 && netmask.length + nth <= 32
subnets = []
for i in 0..(n - 1)
topaddr = network(newmask) + blocksize * i
subnet = type.new(topaddr, newmask)
subnets.push(subnet)
end
subnets
else
raise "cannot divide #{self} by #{n}"
end
end
def netmask
if @mask.is_a?(Netmask)
@mask
else
case @value
when 0..0x7fffffff
Netmask.new(8)
when 0x80000000..0xbfffffff
Netmask.new(16)
when 0xc0000000..0xdfffffff
Netmask.new(24)
else
Netmask.new(32)
end
end
end
def network(mask = netmask)
mask = Netmask.new(mask) unless mask.is_a?(Netmask)
type.new(self & mask, mask)
end
def host(mask = netmask)
type.new(self - network(mask), mask)
end
def broadcast(mask = netmask)
mask = Netmask.new(mask) unless mask.is_a?(Netmask)
type.new(network(mask) + mask.inv, mask)
end
end
exp = ARGV.join(' ')
exp.gsub!(/(\d+)([bhnr])/, '\1 \2')
exp.gsub!(/\/\//, ' / ')
exp.gsub!(/((\d+(\.\d+){3})(\/(\d+))?)/, 'IPAddress.new(\'\2\', \'\5\')')
exp.gsub!(/\b(\/\d+)/, 'Netmask.new(\'\1\')')
exp.gsub!(/\.?\bb(roadcast)?[\s\t]*(\d+)?\b/, '.broadcast(\2)')
exp.gsub!(/\.?\bh(ost)?[\s\t]*(\d+)?\b/, '.host(\2)')
exp.gsub!(/\.?\bn(etwork)?[\s\t]*(\d+)?\b/, '.network(\2)')
exp.gsub!(/\.?\br(awaddr)?\b/, '.rawaddr(\2)')
result = eval(exp)
if result.is_a?(Array)
print "[#{result.join(', ')}]\n"
else
print "#{result}\n"
end