読者です 読者をやめる 読者になる 読者になる

続 カッコの付け方

AWSを始めとしたクラウドコンピューティング全般と、唯一神emacsにおける()の付け方についてだらだら書きます

大きいCIDRから小さいCIDR以外をくり抜くアプリをつくってみた

CIDR overlapped npm netmask GAS

一体何人の人が使うかわからないが、勉強も兼ねてやってみた。やりたいことは

親 10.0.0.0/8 子 10.120.30.0/24

のような場合、親サブネットの中に、子サブネットがいますが、この親から子を除いた全部のCIDRをくり抜くアプリです。絵にするとこんな感じ。

f:id:iga-ninja:20150119154618p:plain

方法

単純に一言で言うと、バイナリサーチです。ビットマスクが1増える = 半分に割るということなので、

  1. 親のビットマスクを1つ足す。
  2. 2つに割れたCIDRの内、どっちに子CIDRがあるか調べる。
  3. 割った内の子CIDRが存在しない方を保存、もう片方を親CIDRとして1.に戻る
  4. 1-4を 子CIDRのビットマスクまで繰り返す。

イナリサーチと違うのは、最後に子CIDRを返して終わりではなく、子CIDRでない方を保存して終わりということです。

部品集め

やり方がわかったので、部品集めです。なんとなくGASでやりたかったので、javascript でいきました。ほしいものリストは

  • CIDRの文字列表示から、ビットが作れる(計算しやすいように)
  • このCIDRはこのCIDRに属していることを判定
  • 次のCIDRを作るルーチン e.g) 10.8.0.0/16 の場合、 10.9.0.0/16

ビット演算子があれば楽に行けそうですが、激しく車輪の予感。なんかいいライブラリないかなー、他の言語にすればよかったかなー、いや、jsの勉強とか思ってたけど。

ピコーン!node.jsがあるじゃないか!

探しました。我々必死でさがしました。そしたら、、、

ありました。

いや全然余裕で、npm のページで netmaskで調べたら。モロその名前で https://www.npmjs.com/package/netmask

f:id:iga-ninja:20150119003432p:plain

しかもこの機能ですよ!ダンナ!全部そろってますやん!

f:id:iga-ninja:20150119003445p:plain

まあ、node.jsのものなので、そのまんまGASでは動かないだろうけど、多分何とかなるし、実際なったし。先頭の方とケツの方を一部改変すれば行けた。ただ、元コードはcoffee scriptらしいので、npmでインスコすれば.jsもできるので、そいつを使った。このモジュールもperlのNet::Netmaskからインスパイア受けたといっているので、他の言語でもこの手のあるでしょう、多分。

コード

こんな感じになりました。Netmaskモジュールと、spreadsheetの部分は割愛。ほしければGAS公開します。

function GetUnOverlappedCIDR(h_p_cidr, h_c_cidr)
{
  var ret = new Array();
  
  var p_cidr = new Netmask(h_p_cidr);
  var c_cidr = new Netmask(h_c_cidr);
  
  var c_first_ip = c_cidr.first;
  if (!p_cidr.contains(c_first_ip)) {
    ret.push(p_cidr);
    return ret;
  }
  
  var curr_cidr = new Netmask(p_cidr.base, p_cidr.bitmask + 1);
  
  while (curr_cidr.bitmask <= c_cidr.bitmask) {
    
    next_cidr = curr_cidr.next();
    
    if (curr_cidr.contains(c_first_ip)) {
      ret.push(next_cidr);
      curr_cidr = new Netmask(curr_cidr.base, curr_cidr.bitmask + 1);
    } else {
      ret.push(curr_cidr);
      curr_cidr = new Netmask(next_cidr.base, next_cidr.bitmask + 1);
    }
    
  }
  
  return ret;  
}

こんな感じになったよ。

f:id:iga-ninja:20150119005208p:plain