web-dev-qa-db-ja.com

Bashの何千ものCIDR /ネットマスク範囲でIPホストアドレスの数をすばやく効率的に取得する方法はありますか?

私はIPSetを使用して、IPTablesルールにリンクされる数万のIPv4 CIDR /ネットマスク範囲を管理しています。この設定はうまく機能していますが、クライアントのレポート作成のためにIPSetが作用するIPホストアドレスの概要を正確に把握したいと思います。

IPSetエントリのフォーマットは、一貫して次のようになります。

123.456.0.0/16 timeout 86400

したがって、timeoutを持つ行をgrepして、エントリに含まれるCIDR /ネットマスク範囲に作用する値を取得できます。

たとえば、IPSet出力を(ipset -L -n > ipset-20181228.txt経由で)ipset-20181228.txtという名前のテキストファイルに保存してから、次のようにgrepwc -lの組み合わせを実行するとします。

grep  "timeout" ipset-20181228.txt  | wc -l

39,000以上のCIDR /ネットマスク範囲に相当する39,000以上のアイテムの数を取得します。ただし、これは(もちろん)CIDR /ネットマスク範囲のみをカウントし、その範囲内のIPホストアドレスの完全なカウントはカウントしません。

prips (CIDR /ネットマスク値をBashの実際のIPアドレスに展開します)をgrepで使用して、次のようなCIDR /ネットマスク範囲のアイテムのみを選別しようとしました。

grep -oE '(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\/([0-9]{1,2})' ipset-20181228.txt | awk 'NF { system( "prips " $0)  }' | wc -l

そして、2018 MacBook Airで(ファンがキックインして)なんと20〜30分(!!!)した後、私が得たカウントは736,000,000+でした。これは、私が目指していることです…しかし、20〜30分は長すぎます。 。これをできるだけスクリプト化可能で邪魔にならないようにし、リソースを消費せずに本番サーバーで実行するようなコマンドを信頼することはできません。私のローカル2018MacBookAir開発セットアップでどのように動作するかを見てください。

単にCIDR /ネットマスク値に基づいてCIDR /ネットマスク範囲カウントを計算する方法はありますか?コマンドラインツール(または使用している既存のツールのオプション)があれば、それが役立つことに気づいていないことを願っています。

4
JakeGould

grepコマンドが_123.456.0.0/16_のような行を出力する場合は、それらをにパイプする必要があります

_awk -F / '{ count[$2]++ } END { for (mask in count) total+=count[mask]*2^(32-mask); print total }'
_

このコマンドは、マスク(つまり、_/_の後にあるもの)のみを抽出し、各マスクの発生をカウントします。最後に、検出されたマスク(2^(32-mask))ごとにホストの数が計算され、発生数が乗算されて合計されます。

ノート:

  • サニティチェックは実行されません。例えば。 _1.2.3.4/40_のような入力が受け入れられ、非整数出力が計算されます。必要に応じて、予備のgrepフィルターを改善します。
  • 各範囲は独立して総数に寄与します。範囲が重なると、結果が膨らみます(pripsでの試行はこれで良くなかったと思います)。
2

元のポスターはtimeoutの行からCIDRを取得するためにgrepを実行しているので、このようなものが機能すると思いました。

awk -F'[ /]' '/timeout/ {hosts+=2^(32-$2)};ENDFILE{print "Hosts number in "FILENAME": "hosts;total+=hosts;hosts=0};END {print "Total: "total}' ipset*.txt

編集-上記のawkプログラムは、GNU awkでのみ正常に実行されます。 ENDFILEはGNU拡張子です。

BSD awkENDFILEを無視し、メインプログラムセクションの一部である場合はそのセクションを実行すると思います。

これはGNUおよびBSDawkと互換性があります。

awk -F'[ /]' '{if (filename != FILENAME) hosts=0};/timeout/ {hosts+=2^(32-$2)};{filename=FILENAME;file_total[filename]=hosts};END{for (i in file_total) {print "Hosts number in "i": "file_total[i];total+=file_total[i]};{print "Total: "total};}' ipset*.txt
0
Paulo