2009-12-01 8 views
7

に私は、IPアドレスの宝石を使用してきたし、CIDR形式ネットマスクはCIDRにルビー

にフォーム

255.255.255.0 

のネットマスクから変換する能力を持っていないようです

/24 

誰もが前者を後者にすばやく変換する方法を知っていますか?ここで

+0

一つの解決策は、より完全に見えている代わりにipadminの宝石を使用することが考えられます。 私はまだコードの観点からこれに対する解決策が何であるか見ることに興味があります。 –

答えて

11

があり、私はそれを見つけることができなかった、そのための適切な関数であるので、あなたはするつもりなら、私はちょうど「1」

をカウントする必要があり、迅速かつ汚い方法

require 'ipaddr' 
puts IPAddr.new("255.255.255.0").to_i.to_s(2).count("1") 

です多くの場所で関数を使用しているとmonkeypatchingを気にしない、これは助けることができる:

IPAddr.class_eval 
    def to_cidr 
    "/" + self.to_i.to_s(2).count("1") 
    end 
end 

を次にあなたが得る

ただ、FYIとして3210
IPAddr.new('255.255.255.0').to_cidr 
# => "/24" 
+0

カウント( "1")を使うよりも何かが適切であるかどうかはわかりません。おそらくこのような何か? '32 - (2 ** 32 - 1 - IPAddr.new(" 255.255.255.0 ")。to_i).to_s(2)。長さ ' –

+0

Cで、私はおそらく右へのシフトを行い、&1で到達可能性があるまで、例えば 'bits = 32; unsigned int ipaddr = 0xFFFFFF00; while(ipaddr&1 == 0){ipaddr = ipaddr> > 1; bits - ;} '上記の場合、8回右にシフトする必要があると思います。 – YOU

9

、そして...検索している人のために簡単にアクセス

を情報を維持するためには、ここではCIDRからネットマスク形式に変換するための簡単な方法です。例えば

def cidr_to_netmask(cidr) 
    IPAddr.new('255.255.255.255').mask(cidr).to_s 
end 

cidr_to_netmask(24) #=> "255.255.255.0" 
cidr_to_netmask(32) #=> "255.255.255.255" 
cidr_to_netmask(16) #=> "255.255.0.0" 
cidr_to_netmask(22) #=> "255.255.252.0" 
2

あなたは、IPアドレスの宝石を使用する必要がない場合、あなたはnetaddr宝石

でこれを行うことができます
require 'netaddr' 

def to_cidr_mask(dotted_mask) 
    NetAddr::CIDR.create('0.0.0.0/'+dotted_mask).netmask 
end 

to_cidr_mask("255.224.0.0") # => "/11" 
4

は、ここですべてのコストでの文字列を避け、より数学的なアプローチだ:「マスク」255.255.255.0のような文字列であることと

def cidr_mask 
    Integer(32-Math.log2((IPAddr.new(mask,Socket::AF_INET).to_i^0xffffffff)+1)) 
end 

。 "mask"がすでにIPアドレスの整数表現であれば、それを修正し、最初の引数を単に "mask"に変更することができます。

ので、マスクが "255.255.255.0"、IPAddr.new(マスク、ソケット:: AF_INET)だった場合、たとえば、.to_iは255

に等しく、その後は0xffffffffとのXORをとる0xffffff00、なります

これを1に加えて、256のホストの完全な範囲にしてから、ログベース2を256(ホストアドレスに使用されるビット)に等しい8を求め、その32を32から減算します。ネットワークアドレスに使用されるビット)。

Math.log2がfloatを返すため、整数にキャストします。

4

間に合わせ変換:

"255.255.255.0".split(".").map { |e| e.to_i.to_s(2).rjust(8, "0") }.join.count("1").split(".")

=> Iは、アレイ内の各要素の配列

.map { |e| e.to_i.to_s(2).rjust(8, "0") }

=>マスクを分割:

.to_i

=>整数に変換し

.to_s(2)

=>

.rjust(8, "0")

=>パディングを追加

=>地図

同じカーディナリティ持つ配列を返す二

に整数に変換

.join

=>完全な文字列に配列を変換し

.count("1")

=> "1" の文字をカウント=> CIDRは

def mask_2_ciddr mask 
     "/" + mask.split(".").map { |e| e.to_i.to_s(2).rjust(8, "0") }.join.count("1").to_s 
    end 

    mask_2_ciddr "255.255.255.0" 
    => "/24" 
    mask_2_ciddr "255.255.255.128" 
    => "/25" 
1
require 'ipaddr' 

def serialize_ipaddr(address) 
    mask = address.instance_variable_get(:@mask_addr).to_s(2).count('1') 
    "#{address}/#{mask}" 
end 

serialize_ipaddr(IPAddr.new('192.168.0.1/24')) # => "192.168.0.0/24" 

をマスク付けコードは、プライベートアクセスすることにより、マスキングを実現しますIPAddrインスタンス(アドレス、serialize_ipaddrに渡される)のインスタンス変数* @ mask_addr)。インスタンス変数は、クラスのパブリックAPIの一部ではありませんが、ここで、それは私の意見で#inspectから文字列を解析よりはましだとこれは(方法は推奨されません

を次のようにプロセスは次のとおりです。

  1. ネットマスク
  2. を表すインスタンス変数@mask_addrそのバイナリ表現をゲット例えば255.255.255.0 -> 4294967040 -> 11111111111111111111111100000000
  3. CIDRマスク(24)
  4. 01を取得するために、ベース2数1-Sカウント
  5. アドレス&からなる文字列をメイク

をマスクEDIT:追加されましたNathanOliver

によって要求された実装への説明
+0

このコードスニペットは問題を解決するかもしれませんが、[説明を含む](http://meta.stackexchange.com/questions/114762/explaining-entirely-code-based-answers)は、あなたの質を改善するのに本当に役立ちます役職。将来読者の質問に答えていることを覚えていて、コード提案の理由を知らない人もいるかもしれません。 – NathanOliver