一体何人の人が使うかわからないが、勉強も兼ねてやってみた。やりたいことは
親 10.0.0.0/8 子 10.120.30.0/24
のような場合、親サブネットの中に、子サブネットがいますが、この親から子を除いた全部のCIDRをくり抜くアプリです。絵にするとこんな感じ。
方法
単純に一言で言うと、バイナリサーチです。ビットマスクが1増える = 半分に割るということなので、
- 親のビットマスクを1つ足す。
- 2つに割れたCIDRの内、どっちに子CIDRがあるか調べる。
- 割った内の子CIDRが存在しない方を保存、もう片方を親CIDRとして1.に戻る
- 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
しかもこの機能ですよ!ダンナ!全部そろってますやん!
まあ、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; }
こんな感じになったよ。