6
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

サブネット計算のお供に

Last updated at Posted at 2015-03-17

計算問題が嫌いなので作ってみました。ただこれを使うとあまりサブネット計算の学習にはならないという問題を抱えています。
Ping-tのサブネットの計算問題で試してみて合っていたので、多分問題ないと思います。
  
32bit値のところで参考にさせていただきました。
[@harasou@github シェルスクリプトで IPアドレス計算] (http://qiita.com/harasou@github/items/5c14c335388f70e178f5 "シェルスクリプトで IPアドレス計算")
  
基本的に10進数のIPアドレスを入れて使う用途になっていますが、一応2進数表記から10進数表記に変換することもできます。
  
###色々と問題がありましたので下の方に修正版を追記してあります。

str = ARGV[0]

if str.match(/(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})/) then

  num = str.split(".")

  #入力したIPアドレスの32Bit値を保管
  @hom = (num[0].to_i << 24) + (num[1].to_i << 16) + (num[2].to_i << 8) + (num[3].to_i)

  #2進数表記に変換
  num.each_with_index do |n, count|
    if count == 3
      printf("%08d\n",  "#{n.to_i.to_s(2)}")
      break
    end
    @z = printf("%08d.","#{n.to_i.to_s(2)}")
  end

  puts "ネットワークの計算をしますか?"
  puts "計算する場合はCIDR値を入力してください。"
  print "==> "
  cidr = STDIN.gets.chomp

  #保管している32Bit値から論理和を計算
  exit unless cidr.match(/[1-31]/)
  cidr32 = (( 0xFFFFFFFF ^ ((2 ** (32-cidr.to_i)-1) )))
  nwaddr = cidr32 & @hom
  puts "ネットワークアドレス"
  printf "%d.%d.%d.%d\n", (nwaddr >> 24), ((nwaddr >> 16) & 0xFF), ((nwaddr >> 8) & 0xFF), (nwaddr & 0xFF)
  #ネットワークアドレスの排他的論理和と論理和
  puts "ブロードキャストアドレス"
  broad = ((cidr32 ^ 0xFFFFFFFF) | @hom)
  printf "%d.%d.%d.%d\n", (broad >> 24), ((broad >> 16) & 0xFF), ((broad >> 8) & 0xFF), (broad & 0xFF)

elsif str.match(/([01]{1,8})\.([01]{1,8})\.([01]{1,8})\.([01]{1,8}$)/) then

  num = str.split(".")

  num.each_with_index do |n, count|
    m = n.to_i(2)
    if count == 3
      puts "#{m}"
      break
    end
    print "#{m}."
  end
end

#使い方
引数に10進のIPアドレス。CIDRの確認で止まるので自分で考えてみたりするもよし・・。

$ ruby subnet2.rb 210.150.30.10
11010010.10010110.00011110.00001010
ネットワークの計算をしますか?
計算する場合はCIDR値を入力してください。
==> 28
ネットワークアドレス
210.150.30.0
ブロードキャストアドレス
210.150.30.15

ネットワーク計算が不要なら1〜31以外の数字でも空エンターでも叩くとEXITします。

$ ruby subnet2.rb 192.168.24.133
11000000.10101000.00011000.10000101
ネットワークの計算をしますか?
計算する場合はCIDR値を入力してください。
==>

上の2個を例にして2進数表記からの変換

$ ruby subnet2.rb 11010010.10010110.00011110.00001010
210.150.30.10

$ ruby subnet2.rb 11000000.10101000.00011000.10000101
192.168.24.133

こんな感じです。
  
  
はっ!スクリプトを書きだした前半と後半でprintfの記述の仕方が変わっている!
Σ( ̄ロ ̄lll)がびーん

##2015/03/17 追記

@scivola さん、@riocampos さん
いつもありがとうございます。

指摘いただいた間違い部分と組み込み系のメソッドの利用部分を使って修正してみました。
みましたというかモノマネですが^_^;
長くなりますが比較用のコメントアウトVerと、スッキリVerの2個載せます。

###修正Ver(比較用コメントアウトのみ)

str = ARGV[0]

case str
when /(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})/

  #nums = str.split(".")
  nums = [$1, $2, $3, $4].map(&:to_i)

  #IPアドレスの最終確認
  #nums.each do |x|
  #  if x.to_i > 255
  #    puts "不正な入力です。"
  #    exit
  #  end
  #end
  if nums.any? { |x| x.to_i > 255 }
      puts "不正な入力です。"
        exit
  end

  #入力したIPアドレスの32Bit値を保管
  #p @hom = (nums[0].to_i << 24) + (nums[1].to_i << 16) + (nums[2].to_i << 8) + (nums[3].to_i)
  @hom = nums.inject{|r, x| r * 256 + x}

  #2進数表記に変換
  puts nums.map{|x| format('%08b', x)}.join('.')

  #2進数表記に変換
  #nums.each_with_index do |n, count|
  #  if count == 3
  #    printf("%08d\n",  "#{n.to_i.to_s(2)}")
  #    break
  #  end
  #  printf("%08d.","#{n.to_i.to_s(2)}")
  #end

  puts "ネットワークの計算をしますか?"
  puts "計算する場合はCIDR値を入力してください。"
  print "==> "
  cidr = STDIN.gets.chomp

  #保管している32Bit値から論理和を計算
  exit unless cidr.match(/\A\d+\z/) && (1..31).include?(cidr.to_i)
  cidr32 = (( 0xFFFFFFFF ^ ((2 ** (32-cidr.to_i)-1) )))
  nwaddr = cidr32 & @hom
  puts "ネットワークアドレス"
  #printf "%d.%d.%d.%d\n", (nwaddr >> 24), ((nwaddr >> 16) & 0xFF), ((nwaddr >> 8) & 0xFF), (nwaddr & 0xFF)
  puts [24, 16, 8, 0].map{|n| (nwaddr >> n) & 0xFF}.join('.')
  #ネットワークアドレスの排他的論理和と論理和
  puts "ブロードキャストアドレス"
  broad = ((cidr32 ^ 0xFFFFFFFF) | @hom)
  #printf "%d.%d.%d.%d\n", (broad >> 24), ((broad >> 16) & 0xFF), ((broad >> 8) & 0xFF), (broad & 0xFF)
  puts [24, 16, 8, 0].map{|n| (broad >> n) &0xFF}.join('.')

when /([01]{1,8})\.([01]{1,8})\.([01]{1,8})\.([01]{1,8}$)/

  #2進数表記から10進数表記に変換
  puts nums = [$1, $2, $3, $4].map{|s| s.to_i(2)}.join('.')

  #2進数表記から10進数表記に変換
  #nums = str.split(".")
  #nums.each_with_index do |n, count|
  #  m = n.to_i(2)
  #  if count == 3
  #    puts "#{m}"
  #    break
  #  end
  #  print "#{m}."
  #end
end

###スッキリVer

str = ARGV[0]

case str
when /(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})/

  nums = [$1, $2, $3, $4].map(&:to_i)

  #IPアドレスの最終確認
  if nums.any? { |x| x.to_i > 255 }
      puts "不正な入力です。"
        exit
  end

  #入力したIPアドレスの32Bit値を保管
  @hom = nums.inject{|r, x| r * 256 + x}

  #2進数表記に変換
  puts nums.map{|x| format('%08b', x)}.join('.')
  puts "ネットワークの計算をしますか?"
  puts "計算する場合はCIDR値を入力してください。"
  print "==> "
  cidr = STDIN.gets.chomp

  #保管している32Bit値から論理和を計算
  exit unless cidr.match(/\A\d+\z/) && (1..31).include?(cidr.to_i)
  cidr32 = (( 0xFFFFFFFF ^ ((2 ** (32-cidr.to_i)-1) )))
  nwaddr = cidr32 & @hom
  puts "ネットワークアドレス"
  puts [24, 16, 8, 0].map{|n| (nwaddr >> n) & 0xFF}.join('.')

  #ネットワークアドレスの排他的論理和と論理和
  puts "ブロードキャストアドレス"
  broad = ((cidr32 ^ 0xFFFFFFFF) | @hom)
  puts [24, 16, 8, 0].map{|n| (broad >> n) &0xFF}.join('.')

when /([01]{1,8})\.([01]{1,8})\.([01]{1,8})\.([01]{1,8}$)/

  puts nums = [$1, $2, $3, $4].map{|s| s.to_i(2)}.join('.')

end

###不具合の例
正規表現が間違っており、おかしなものが入った場合はEXITと思って書いていましたがこんなのが通ってしまっていました。

計算する場合はCIDR値を入力してください。
==> 2222
subnet2.rb:29:in `^': Rational can't be coerced into Rational (TypeError)
	from subnet2.rb:29:in `<main>'

もういっちょは何も入れずでエラーが。

$ ruby subnet2.rb
subnet2.rb:6:in `<main>': undefined method `match' for nil:NilClass (NoMethodError)

などなど。

6
6
9

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?