IPアドレスから地域を特定する - MaxMind DB Reader, GeoIP2 Java API

MaxMind が提供している無償の IP Geolocation DB である GeoLite と Java 用ライブラリを使って IP アドレスから国や都市を特定してみました。

今回は Java 用ライブラリの下記 2種類を試してみる事にします。

どちらも Maven のセントラルリポジトリから入手でき、MaxMind DB Reader は low-level API、GeoIP2 は high-level API な印象となっています。

また、GeoLite には下記 2種類があり、上記ライブラリで使えるのは GeoLite2 の方です。

今回のソースは http://github.com/fits/try_samples/tree/master/blog/20141004/

MaxMind DB Reader

MaxMind DB Reader を使って IP アドレスから地域を取得するコードを Groovy で実装しました。

GeoLite2 の DB ファイルを引数にして com.maxmind.db.Readerインスタンス化し、get メソッドへ IP アドレスから作成した InetAddress を渡すだけです。

Reader の get メソッドで取得する地域情報は JSONデータ (com.fasterxml.jackson.databind.JsonNode) となります。

get_location_dbreader.groovy
@Grab('com.maxmind.db:maxmind-db:1.0.0')
import com.maxmind.db.Reader

if (args.length < 2) {
    println '<maxmind db file> <ip>'
    return
}

def reader = new Reader(new File(args[0]))

println reader.get(InetAddress.getByName(args[1]))

reader.close()

実行には、GeoLite2 Free Downloadable Databases から GeoLite2 City と GeoLite2 Country のどちらかの MaxMind DB をダウンロード・解凍し .mmdb ファイルを取得しておきます。

今回は GeoLite2 City の MaxMind DB GeoLite2-City.mmdb を使って、IP アドレス 1.21.127.254 の地域判定を行ってみました。 (下記の出力結果は加工しています)

実行結果1
> groovy get_location_dbreader.groovy GeoLite2-City.mmdb 1.21.127.254

{
 "city":{"geoname_id":1850147,"names":{・・・,"en":"Tokyo",・・・,"ja":"東京",・・・}},
 "continent":{"code":"AS","geoname_id":6255147,"names":{・・・,"en":"Asia",・・・,"ja":"アジア",・・・}},
 "country":{"geoname_id":1861060,"iso_code":"JP","names":{・・・,"en":"Japan",・・・"ja":"日本",・・・}},
 "location":{"latitude":35.685,"longitude":139.7514,"time_zone":"Asia/Tokyo"},
 "registered_country":{"geoname_id":1861060,"iso_code":"JP","names":{"de":"Japan","en":"Japan",・・・,"ja":"日本",・・・}},
 "subdivisions":[{"geoname_id":1850144,"iso_code":"13","names":{・・・,"ja":"東京都"}}]
}

結果は、東京だと判定されました。

なお、上記では省略してますが、言語毎の名称は en と ja だけではなく de・es・fr・pt-BR・ru・zh-CN なども設定されています。

次に、別の IP アドレス 223.255.254.1 を試してみます。

実行結果2
> groovy get_location_dbreader.groovy GeoLite2-City.mmdb 223.255.254.1

{
 "continent":{"code":"AS","geoname_id":6255147,"names":{・・・,"en":"Asia",・・・}},
 "country":{"geoname_id":1880251,"iso_code":"SG","names":{・・・,"en":"Singapore",・・・,"ja":"シンガポール",・・・}},
 "location":{"latitude":1.3667,"longitude":103.8,"time_zone":"Asia/Singapore"},
 "registered_country":{"geoname_id":1880251,"iso_code":"SG","names":{・・・,"en":"Singapore",・・・,"ja":"シンガポール",・・・}}
}

今度の結果には city 情報を含んでおらず、特定できなかったようです。

ちなみに、地域が全く特定できなかった場合の get メソッドの結果は null となるようです。 (プライベート IP などを使えば確認できます)

GeoIP2 Java API

次に GeoIP2 の方を使った場合の Groovy スクリプトは下記のようになります。

使用する .mmdb によって DatabaseReader の使用可能なメソッドが異なるようなので注意が必要です。

今回のように GeoLite2-City.mmdb ファイルを使う場合、city メソッドが使えますが、country メソッドは使えないようです。 (UnsupportedOperationException が発生しました)

get_location_geoip2.groovy
@Grab('com.maxmind.geoip2:geoip2:2.0.0')
import com.maxmind.geoip2.DatabaseReader

if (args.length < 2) {
    println '<maxmind db file> <ip>'
    return
}

def reader = new DatabaseReader.Builder(new File(args[0])).build()

def res = reader.city(InetAddress.getByName(args[1]))

println res.country
println res.city

reader.close()

実行結果は下記の通りです。

実行結果1
> groovy get_location_geoip2.groovy GeoLite2-City.mmdb 1.21.127.254

Japan
Tokyo
実行結果2
> groovy get_location_geoip2.groovy GeoLite2-City.mmdb 223.255.254.1

Singapore