KITA Eng.

北海道でサーバー技術者として歩み出したひとが綴るblog。

グローバルIPアドレス国別割り当てのデータを生成するスクリプトが書き上がるまでの道のりは険しかった…(原因編)

kitaeng.hateblo.jp

RIRsが提供してくれている、RIR statistics exchange formatになっているIPアドレスの割り当て状況のデータを加工するスクリプトを書きました。思考、試行過程をちょっと備忘録的に記録しておきます。

RIR statistics exchange formatについて

このフォーマットの仕様が道のりを険しくする最大の要因です。

普段IPアドレスの一覧を作るときや、iptablesとかの設定に入れるときは、

  • "192.168.2.1" <-- 個別のIPそれぞれ
  • "192.0.2.0/24" <--ブロックでまとめて

と表現することが多いと思います。IPアドレスの国別IPアドレス割り当てなんて話になれば、膨大な数のIPアドレスを扱うことになるので、個別のIPを列挙していくというよりも、ブロックでまとめての表現をつかうのがベターと思うのですが……。

RIR statistics exchange formatでは、割り当て開始のIPアドレスと、そこから何個分を割り当てているかという形で表現されています。そこから何個分を割り当てているかというところが鬼門です。

CIDR表記で扱う時の各CIDRに対応するIPアドレスの個数は、2 ^ (32 - CIDR)で表せて、

CIDR IPアドレス CIDR IPアドレス
/32 1 /16 65,536
/31 2 /15 131,072
/30 4 /14 262,144
/29 8 /13 524,288
/28 16 /12 1,048,576
/27 32 /11 2,097,152
/26 64 /10 4,194,304
/25 128 /9 8,388,608
/24 256 /8 16,777,216
/23 512 /7 33,554,432
/22 1,024 /6 67,108,864
/21 2,048 /5 134,217,728
/20 4,096 /4 268,435,456
/19 8,192 /3 536,870,912
/18 16,384 /2 1,073,741,824
/17 32,768 /1 2,147,483,648
/0 4,294,967,296

という具合になるわけですが、RIR statistics exchange formatでは、この表に出てくるIPアドレス数以外の個数が現れます。

えっ!?」ってなりますよね?

例えばこんなレコードがあります。valueというのがIPアドレスの個数です。

registry cc start value date status
ripencc CH 195.242.163.0 768 20080617 assigned

768個って、上の表では出てきません。768 = 256 * 3なので、なるべくブロックが細かくならないように分けるとすると、/24/23で分割してあげないといけません。

registry cc start value date status
ripencc CH 195.242.163.0 256 20080617 assigned
ripencc CH 195.242.164.0 512 20080617 assigned

こんな具合に書いていてくれればいいんですけど、そうじゃない……。

上のCIDR一覧に出てくるような数字だけが、valueに入っているなら、単純にvalueの部分を対応するCIDRに置換していって、開始IPアドレスstartと結合してあげれば、"192.0.2.0/24"の形になってくれるので、簡単だったんですが…。

手作業で例外部分だけ直すなんてのはちょっと美しくないのでどうしたものかとなったわけです。

皆さんならばどう解決しますか??

つづく...

グローバルIPアドレス国別割り当てのデータを生成するスクリプトを書いた

サーバーの保守をやっていると、接続元IPアドレスで国外からのアクセスかどうかを調べることが多々あります。1、2件調べるだけならwhoisコマンド使って確認すればいいんですけど、whoisの結果って表示書式がバラバラでかなり見にくいですよね。

それに、アクセスログから収集した多数のIPアドレスについて確認するとなると…。なかなか面倒な話です。IPアドレスと割り当て先の国の対応表でもあれば、うまいことマッチングさせられるので楽なんだけどなと思って、Google先生に問い合わせると、いろいろとご回答をいただきました。

これらのページで公開されているリストを使ってしまうというのもいいのですが、RIRsから、日々更新されているデータがもとになっているっぽいので、プログラム書きの練習がてら、RIRs提供データから、国コードとIPアドレスの対応表を作成するスクリプトPythonで書いてみました

RIR statistics exchange formatからIPv4アドレスと国コードの対応表を作るPython3スクリプト

紆余曲折あって出来上がったのが、こちらのスクリプトです。Python3には、IPアドレスを扱うのに便利なipaddressというモジュールがあるということを発見して、これを使って書いてみました。

ちなみに、どうやらipaddressモジュールは、Python 2.x系では標準サポートされていないっぽい?です。

17行目の、rirsFile = 'rirsfiles'で元となるRIR statisticsのデータファイルを指定してあげます。
18行目の、outFile = 'ipdata.csv'で出力するcsvデータの保存先ファイルを指定してあげます。

各RIRが提供しているRIR statisticsのデータは、

からそれぞれ最新版がダウンロードできます。各RIRのローカル時刻で23:59時点の情報から生成されるデータのようです。毎日更新されているらしいです。IPv4以外の情報も混じっていますが、IPv4についての部分のみ抽出するようにしてあるので、前処理不要です。しいて言えば、5つのRIRからダウンロードしてきたデータを単純に結合しておくと、全部分をいっぺんにできます。

RIR statistics exchange formatについては、APNICのページに見やすく成型されたドキュメントがあります。→RIR statistics exchange format | APNIC

出力されるCSVファイル

上記スクリプトで生成されるcsvファイルは、以下から出力ファイルがダウンロードできるようにしてみました。データの正確性については保証できませんが、ご自由にごりようください。データは、毎日午前3時30分ごろに更新されます。上記スクリプトから生成されるのは、改行コードがLFのものだけですが、事後処理でCR+LF版も生成してあります。

自動化のしくみとか
  1. 最新版ファイルのダウンロード
  2. ダウンロードデータからcsvファイル作成
  3. Postgresqlへの読み込み

を自動化させようと思ってごにょごにょしてます。おおむね完成というところです。一応、Githubレポジトリを作ってみたのでどうぞ。Pythonとshのコラボ仕様となっています。

github.com

Postgresに取り込んでいるのは、最初にやりたかった「アクセスログから収集した多数のIPアドレスについて確認」をするために、検索ならば、DBにデータ入れといたほうがいろいろとよかろうという、思い込みによるものです。

DBがPostgresqlなのは、データ型にipaddressに関する型があって、なんだか便利そうだったのでpostgresqlです。

記事書きながら一応調べなおしたら、mysqlには型はないけど、一応簡単に扱えるらしいですね...。→ SQLにおけるIPアドレスの比較 | Yakst

あれ・・・

マッチングに使うデータの生成まではできましたが、まだ当初目的「アクセスログから収集した多数のIPアドレスについて確認」を達成していません。もう一息。

Let's EncryptのSSL証明書を自動更新して、結果をメール通知するスクリプトを書いてみた(WEBROOT、NGINX用)

2015/12/03にパブリックベータ版になったLet's Encrypt。以下のように掲げられているような理念だそうですね。

Let's Encrypt は、認証局(CA)として「SSL/TLSサーバ証明書」を無料で発行するとともに、証明書の発行・インストール・更新のプロセスを自動化することにより、TLSHTTPSTLSプロトコルによって提供されるセキュアな接続の上でのHTTP通信)を普及させることを目的としているプロジェクトです。( Let's Encrypt 総合ポータル )

内部的に使うシステムとかだと、自己証明書(オレオレ証明書とかいう)でもいいんでしょうけど、それなりに大きな組織が使うのにオレオレ証明書なのってどうなんだってのがあったりなかったりした記憶があります。

最近使い始めたSoft Ether VPN Serverとかだと、Soft Ether VPN Clientをいれればオレオレ証明書でも怒られませんが、Windows10とかiPhoneの標準装備VPNクライアントでつなごうとすると、オレオレ証明書だとつなげませんでした。なんか回避策はあるのかもしれませんが…。

そんなときには、結構便利なサービスになるんだろうなと思いますが、証明書の有効期限が90日間というのがネックです。といっても、ほんの1行のコマンドで取得、更新、廃止ができるようにするのが到達点のようなので、更新の自動化さえしてしまえば、有効期限が短いのは大した問題ではないのですが、パブリックベータがスタートした段階では、自動化をどうするかのHow toは公式さんにはありませんでした。が、今日のぞいてみたらシンプルなスクリプトが紹介されていました

前置きが長くなりましたが、証明書を更新し、更新結果をメール通知までしてくれるようにちょとスクリプトを書いてみましたよって話です。

前提として…

そもそも、Let's Encryptってなんだよとか、どうやって導入するんだよということは、以下のページにわかりやすくまとまっているので、こちらを参考にしましょう。

blog.apar.jp

初回取得後以降の自動更新スクリプト

公式さんのスクリプトを大改造!?して、証明書の更新処理、WEBサーバーの再起動(更新した証明書を読み込ませる)、結果をメール通知してくれるスクリプトを書きました。

29~33行目の設定部分を環境に合わせて修正してください。

# CONFIGER SECTION #----------------------------------------------------------#

readonly CMD_PATH=/usr/local/letsencrypt
readonly LOG_FILE=/var/log/letsencrypt/renew.log

readonly SERVER_RESTART_CMD='/etc/init.d/nginx restart'   # After update CA, How to restart WEB Server?
                                                          # Default set is for NGINX

readonly CN="exsample.com"                   # Your Common Name for CA
readonly WEB_ROOT_PATH=/var/www/html   # WEB ROOT Path 
readonly MAIL_TO="root"                      # Mail to update result.
                                             # Default set is Local USER ROOT!

#-----------------------------------------------------------------------------#

こいつを、cronで毎月とか2か月に1回動かしてやればOKです。

cronの設定例(2か月に1回、15日の午前3:05に実行する)

5 3 15 */2 *    root    if [ -x /root/bin/ letsencrypt_cert_autoupdate_webroot.sh ]; then /root/bin/ letsencrypt_cert_autoupdate_webroot.sh; fi 

うまく更新できたときには、こんなメールが届きます。

    Subject: [Let's Encrypt Auto Update] Update Report for exsample.com
    Date: Sun, 31 Jan 2016 12:54:22 +0900 (JST)
    From: root <root@mx.exsample.com>
    To: root@mx.exsample.com

    # Let's Encrypt Cert autopudate Start: 2016-01-31-Sun-12:54:02
    # Update Log START --------------------------------------------------------------#
    Updating letsencrypt and virtual environment dependencies......
    Requesting root privileges to run with virtualenv: /root/.local/share/letsencrypt/bin/letsencrypt certonly --renew-by-default --webroot -w /var/www/html -d exsample.com
    IMPORTANT NOTES:
    - Congratulations! Your certificate and chain have been saved at
    /etc/letsencrypt/live/exsample.com/fullchain.pem. Your cert will
    expire on 2016-04-30. To obtain a new version of the certificate in
    the future, simply run Let's Encrypt again.
    - If you like Let's Encrypt, please consider supporting our work by:

    Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate
    Donating to EFF: https://eff.org/donate-le


    # WEB SERVER RESTART LOG START ------------------------------#
    * Restarting nginx nginx
    ...done.
    #---------------------------- WEB SERVER RESTART LOG END ---#
    #------------------------------------------------------------- Update Log END ---#
    # Let's Encrypt Cert autopudate End: 2016-01-31-Sun-12:54:22

数千件のIPアドレスを逆引きしまくるミッション用スクリプト完成!?

転職したての頃にこんな記事を書いていました。

kitaeng.hateblo.jp

この記事の中で、

本当はしたかったこと
実は逆引き対象のIPアドレスのリストには、かなりの数のダブりがあったりしたので、 重複している分は一回だけ、digして、すでにdigで結果を得ている部分は、 もう一度DNSに問い合わせをしないで、問い合わせ済みのデータを使う とかできたら、少しはネットワークリソースを使わずに済んだのな。 あと、処理も少しは早くなったろうに…
きっと条件分岐とかうまく使えばできるんだろうけど。 今後の課題です。

ということをぼやいていました。

ここ数日いろいろとシェルスクリプトを書き始めて、条件分岐とかループとかの扱いがなんとなく見えてきたので、3カ月ほど前の自分がしたかったことを実装してみました。

IPアドレスのリストを与えると、逆引きしまくってくれるスクリプト

一行ごとにIPアドレスが一つだけ列挙されている状態のファイルを引数として与えてあげることで、ひたすら逆引きをして、与えたIPアドレスFQDNのペアをカンマ区切りで出力してくれます。 一行に1一つのIPアドレスを想定して作りましたが、「for ~ in ~」で読み込んでいるので、スペース区切りやタブ区切りが混じっていても問題ないような気がします。

リダイレクトしてファイルに書き出せばcsvファイルとしてExcelとかで読み込めるはずです。

一度逆引きをしたIPアドレスFQDNについては、tmpファイルに記憶しておいて、そっちから引っ張ってくる(grep)ようにしています。ネットワークトラフィックをこれで減少させられるはずです。

これからしたいこと

IPアドレスの逆引きをするときって、メールログの解析のときとかだったりするので、その辺のログを読み込ませるだけでいいようになればよいなと。ついでにもうちょいいろいろ集計できたらなと。

IPアドレスの国別割り当ては公開リストがあるようなので、その辺の判別結果も出るようにしたり…。

いつ使うのやらですが、いつか使いそうなので、ちょこちょこバージョンあげましょう…。

/etc/resolv.conf についての取り扱いUbuntu12.04以降から

Ubuntuにおいては、12.04LTSから/etc/resolv.confのしくみが変わったようです。 確かに、12.04LTSのリリースノートにもさりげなく書かれています。

"PrecisePangolin/ReleaseNotes/UbuntuServer - Ubuntu Wiki"

Common Infrastructure
resolvconf is now used to manage /etc/resolv.conf on all Ubuntu systems. You can learn more here

resolvconfってのが/etc/resolv.confを管理するようになったそうです。詳しいことはリンク先を読めよっていうので、クリックしてみると...

リンク先の"DNS in Ubuntu 12.04 | Stéphane Graber's website"には、次のようにあります。

resolvconf is a set of script and hooks managing DNS resolution. The most notable difference for the user is that any change manually done to /etc/resolv.conf will be lost as it gets overwritten next time something triggers resolvconf. Instead, resolvconf uses DHCP client hooks, a Network Manager plugin and /etc/network/interfaces to generate a list of nameservers and domain to put in /etc/resolv.conf.

resolvconfっていうので、/etc/resolv.confは管理するようになったから、/etc/resolv.confに手動で変更を加えても、resolvconfが何らかによって動かされたときにすべて上書きされてしまうということだそうです。

詳しいことは、man resolvconfmanページに書かれているのですが、要点については、リンク先でも言及されていて、以下の通りです。

I use static IP configuration, where should I put my DNS configuration?
The DNS configuration for a static interface should go as “dns-nameservers”, “dns-search” and “dns-domain” entries added to the interface in /etc/network/interfaces
How can I override resolvconf’s configuration or append some entries to it?
Resolvconf has a /etc/resolvconf/resolv.conf.d/ directory that can contain “base”, “head”, “original” and “tail” files. All in resolv.conf format.
base: Used when no other data can be found
head: Used for the header of resolv.conf, can be used to ensure a DNS server is always the first one in the list
original: Just a backup of your resolv.conf at the time of resolvconf installation
tail: Any entry in tail is appended at the end of the resulting resolv.conf. In some cases, upgrading from a previous Ubuntu release, will make tail a symlink to original (when we think you manually modified resolv.conf in the past)
I really don’t want resolvconf, how can I disable it?
I certainly wouldn’t recommend disabling resolvconf but you can do it by making /etc/resolv.conf a regular file instead of a symlink.
Though please note that you may then be getting inconsistent /etc/resolv.conf when multiple software are fighting to change it.

巷では、baseに書いてあげればOKみたいなことが書かれているものもありますが、この説明を読む限り、/etc/resolvconf/resolv.conf.d/baseDNS解決について、他に参照すべきものがなかった時に使われるファイルのようです。baseに書いてsudo resolvconf -uしたけど駄目だったみたいなことが起こるのは、baseを読むまでもなく、他にDNS解決について参照すべきものがあったから読み込まれなかったということなのでしょう。自分の最初はbaseに書いても反映されないじゃん現象で悩みました。

headは、とにかくresolv.confの先頭に挿入されるものを記述するファイルのようです。/etc/resolv.confの先頭にあるコメントの部分もここから拾われているようです。

/etc/resolvconf/resolv.conf.d/head

# Dynamic resolv.conf(5) file for glibc resolver(3) generated by resolvconf(8)
#     DO NOT EDIT THIS FILE BY HAND -- YOUR CHANGES WILL BE OVERWRITTEN

最初何も知らずにheadを見たときには、ここに書いたやつは更新されて消えてしまうんだって本気で思いましたが、そういうことではなかったようです。なんと紛らわしい...
どうしても上のほうに入れたいDNSサーバーとかがあれば/etc/resolvconf/resolv.conf.d/headに書けばよさそうです。

originalは途中からresolvconfがインストールされたのでなければ関係なさそう。resolvconfがインストールされたときにあった、/etc/resolv.confを保持するファイルっぽい。うちのUbuntu 14.04 LTSにはoriginのファイルはなかった。

tailは、とにかく/etc/resolv.confの最後尾につけられる部分とのことです。他のDNSの設定がうまくないときの最終奥義的なものでしょうか。一般的な環境ならGoogleのパブリックDNSとかのIPを入れといたらいんじゃないかと個人的には思ったりします。というか、先日のVPN Clientを起動させてVPNをつなぐと名前解決がうまくいかない問題は、これで解決しました。

/etc/resolv.confにかかわる設定ファイル群はまだあるようですが、今日はここまでです。