Alecriar Studioの中の人の技術メモ

横浜の個人事業主が日々の技術的な情報をつづります

GeoIPでIPアドレスから国や都市を判別

f:id:alecriarstudio:20191123182433j:plain
GeoIP

筆者は Apache を使用して自宅でWebサーバーを立ち上げており、以前から GeoIP によりアクセス元の国を判別し、望ましくない国からのアクセスは遮断していました。つい最近アクセスログを覗くと GeoIP 関連のエラーが大量に残っており、どうやら今までのデータベースはレガシーとなり、GeoIP は GeoIP2 として新しく生まれ変わったようで、そのためにエラーとなっていたのでした。

そこで新たな GeoIP2 を設定し Apache (2.2以降)で使用するまでの手順を書き記します。

GeoIP2

MaxMind 社が提供する特定のIPアドレスに関する情報を提供するサービス。さまざまなデータベースという形でユーザーに提供されています。有料版と無料版があり、無料版はフリーで利用できます。最近 GeoIP は収束し、これからは GeoIP2 になる模様です。

GeoLite2 データベース

GeoLite2 Free Downloadable Databases « MaxMind Developer Site

MaxMind 社がフリーで提供する GeoIP2 データベース。旧来の GeoLite データベースはレガシーとなり、GeoLite2 に生まれ変わりました。内部形式も MaxMind DB という新しい形式に変わったらしく、それを取り扱うためのライブラリが必要です。

Arch Linux では、GeoLite2 データベースがパッケージという形で配布されています。これをインストールしておきます。

$ pikaur -S geoip2-database

インストールされた場所を確認。

$ pikaur -Ql geoip2-database

geoip2-database /usr/
geoip2-database /usr/share/
geoip2-database /usr/share/GeoIP/
geoip2-database /usr/share/GeoIP/GeoLite2-ASN.mmdb
geoip2-database /usr/share/GeoIP/GeoLite2-City.mmdb
geoip2-database /usr/share/GeoIP/GeoLite2-Country.mmdb
geoip2-database /usr/share/licenses/
geoip2-database /usr/share/licenses/geoip2-database/
geoip2-database /usr/share/licenses/geoip2-database/COPYRIGHT.txt
geoip2-database /usr/share/licenses/geoip2-database/LICENSE.txt

libmaxminddb

maxmind.github.io

MaxMind DB ファイルを読み込むための C ライブラリ。GeoIP2 を使用するためにインストールする必要があります。

以下は Arch Linux でのインストール例です。

$ pikaur -Ss libmaxminddb

community/libmaxminddb 1.3.2-1 
    MaxMindDB GeoIP2 database library
aur/libmaxminddb-git r959.00316fe-1 (2, 0.00)
    C library for the MaxMind DB file format

$ pikaur -S libmaxminddb

pikaur はAURヘルパーです。環境によって yay や yaourt などで代用してください。

mod_maxminddb

github.com

libmaxminddb を介して MaxMind DB を Apache で取り扱うためのモジュールです。Apache は 2.2 以降が必須です。

現時点では公式やAURリポジトリにパッケージが登録されていないようですので、自前でインストールする必要があります。tarball からコンパイルしインストールすることもできますが、ここでは Arch らしくパッケージ作成しインストールする方法を紹介します。

自前パッケージの作成方法はここでは詳しくふれません。以下の Wiki が詳しいです。

パッケージの作成 - ArchWiki

パッケージを作成する準備を整えた後、PKGBUILD ファイルを作成します。以下にサンプルをのせます。

# Maintainer: Hoge <hoge@sample.com>

pkgname=mod_maxminddb-git
pkgver=1.1.0
pkgrel=1
pkgdesc="MaxMindDB Apache Module using the libmaxminddb library"
arch=('any')
url="https://github.com/maxmind/mod_maxminddb"
license=('Apache')
depends=('pacman')
makedepends=('git' 'apache>=2.2' 'gcc-libs')
optdepends=('libmaxminddb: MaxMindDB GeoIP2 database library')

__gitroot="git://github.com/maxmind/mod_maxminddb.git"

prepare() {
  cd "$srcdir"
  if [ -d $pkgname ] ; then
    rm -rf $pkgname
  fi
  git clone $__gitroot $pkgname
}

pkgver() {
  cd "$srcdir/$pkgname"
  git describe --long | sed -E 's/([^-]*-g)/r\1/;s/-/./g'
}

build() {
  cd "$srcdir/$pkgname"
  ./bootstrap
  ./configure --prefix=/usr
  make
}

check() {
  cd "$srcdir/$pkgname"
  make check
}

package() {
  cd "$srcdir/$pkgname/src"
  install -d "$pkgdir/usr/lib/httpd/modules"
  install -Dm755 ".libs/mod_maxminddb.so" "$pkgdir/usr/lib/httpd/modules"
}

その後パッケージを作成しインストールします。

$ makepkg

$ pikaur -U [作成されたパッケージのファイル名]

インストールされた Apache モジュールを確認します。

$ pikaur -Ql mod_maxminddb-git

mod_maxminddb-git /usr/
mod_maxminddb-git /usr/lib/
mod_maxminddb-git /usr/lib/httpd/
mod_maxminddb-git /usr/lib/httpd/modules/
mod_maxminddb-git /usr/lib/httpd/modules/mod_maxminddb.so

Apache の設定

Apache の設定ファイル本体に以下の行を追加します。

/etc/httpd/conf/httpd.conf

LoadModule maxminddb_module /usr/lib/httpd/modules/mod_maxminddb.so

Include conf/extra/mod_maxminddb.conf

さらにMaxMind DBの設定ファイルを新規に編集します。以下はそのサンプルです。

/etc/httpd/conf/extra/mod_maxminddb.conf

<IfModule mod_maxminddb.c>
    MaxMindDBEnable On

    # ASN Database
    #MaxMindDBFile ASN_DB /usr/share/GeoIP/GeoLite2-ASN.mmdb
    #MaxMindDBEnv MM_ASN ASN_DB/autonomous_system_number
    #MaxMindDBEnv MM_ASORG ASN_DB/autonomous_system_organization
    #MaxMindDBNetworkEnv ASN_DB ASN_DB_NETWORK

    # City Database
    #MaxMindDBFile CITY_DB /usr/share/GeoIP/GeoLite2-City.mmdb
    #MaxMindDBEnv MM_CONTINENT_CODE         CITY_DB/continent/code
    #MaxMindDBEnv MM_CONTINENT_GEONAME_ID   CITY_DB/continent/geoname_id
    #MaxMindDBEnv MM_CONTINENT_NAME         CITY_DB/continent/names/en
    #MaxMindDBEnv MM_CONTINENT_NAME_JA      CITY_DB/continent/names/ja
    #MaxMindDBEnv MM_COUNTRY_CODE           CITY_DB/country/iso_code
    #MaxMindDBEnv MM_COUNTRY_GEONAME_ID     CITY_DB/country/geoname_id
    #MaxMindDBEnv MM_COUNTRY_NAME           CITY_DB/country/names/en
    #MaxMindDBEnv MM_COUNTRY_NAME_JA        CITY_DB/country/names/ja
    #MaxMindDBEnv MM_CITY_NAME              CITY_DB/city/names/en
    #MaxMindDBEnv MM_CITY_NAME_JA           CITY_DB/city/names/ja
    #MaxMindDBEnv MM_LONGITUDE              CITY_DB/location/longitude
    #MaxMindDBEnv MM_LATITUDE               CITY_DB/location/latitude
    #MaxMindDBEnv MM_TIME_ZONE              CITY_DB/location/time_zone
    #MaxMindDBEnv MM_POSTAL_CODE            CITY_DB/postal/code
    #MaxMindDBNetworkEnv CITY_DB CITY_DB_NETWORK

    # Country Database
    MaxMindDBFile COUNTRY_DB /usr/share/GeoIP/GeoLite2-Country.mmdb
    MaxMindDBEnv MM_CONTINENT_CODE          COUNTRY_DB/continent/code
    #MaxMindDBEnv MM_CONTINENT_GEONAME_ID   COUNTRY_DB/continent/geoname_id
    MaxMindDBEnv MM_CONTINENT_NAME          COUNTRY_DB/continent/names/en
    #MaxMindDBEnv MM_CONTINENT_NAME_JA      COUNTRY_DB/continent/names/ja
    MaxMindDBEnv MM_COUNTRY_CODE            COUNTRY_DB/country/iso_code
    #MaxMindDBEnv MM_COUNTRY_GEONAME_ID     COUNTRY_DB/country/geoname_id
    MaxMindDBEnv MM_COUNTRY_NAME            COUNTRY_DB/country/names/en
    #MaxMindDBEnv MM_COUNTRY_NAME_JA        COUNTRY_DB/country/names/ja

    # Log entry
    LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" Country_Code=\"%{MM_COUNTRY_CODE}e\" Country_Name=\"%{MM_COUNTRY_NAME}e\"" combined
    <IfModule logio_module>
      # You need to enable mod_logio.c to use %I and %O
      LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %I %O Country_Code=\"%{MM_COUNTRY_CODE}e\" Country_Name=\"%{MM_COUNTRY_NAME}e\"" combinedio
    </IfModule>
    
    # Blocking by Country
    SetEnvIf MM_COUNTRY_CODE JP AllowCountry
    <Location />
        <RequireAny>
            Require all denied
            Require env AllowCountry
        </RequireAny>
    </Location>
</IfModule>

この設定ファイルではIPアドレスから国の情報を引き出し、それを元にログファイルに記録したりアクセス制限に使用したりしています。使用目的によって適宜改変してください。

設定ファイルの編集が終わった後、Apache の再起動をします。

# sudo systemctl restart httpd

正常であればアクセスログに国についての情報が記録されるようになるはずです。

geoipupdate

本手順では GeoIP2 データベースのファイルはパッケージをアップデートしない限りは固定されたままですが、cron などを使用し定期的にアップデートしたい方は geoipupdate ツールが用意されています。以下のようにパッケージをインストールすればすぐに使用できます。

$ pikaur -S geoipupdate

コマンドを実行すればデータベースファイルを即時更新します。

/usr/bin/geoipupdate

正常に動作することを確認後、cron などに登録し定期的に動かすことで、最新のデータベースに保つことができます。