1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

IP2LocationLITE を利用して IP から 国名を判定する方法

Last updated at Posted at 2021-02-07

IP アドレスから いくつかありますが、このドキュメントでは、
IP2Location LITE の Free で 公開されているデータを利用する
方法について紹介します。

CVS を取得

IP2LocationLITE にて、 IPと国名のペアが公開されています。
https://lite.ip2location.com/database/ip-country

IPから国名を判定してみる

コードに落とすと以下のような感じ

  1. CVSデータを読む
  2. 読んだデータをもとに探す

という感じで書いてます。

# include <iostream>
# include <fstream>
# include <iterator>
# include <sstream>
# include <vector>

//
// data format ref https://lite.ip2location.com/database/ip-country
// "0","281470681743359","-","-"
// "281470681743360","281470698520575","-","-"
// "281470698520576","281470698520831","US","United States of America"
//  
//
void printUsage()
{
    std::cerr << "./a.out <file path> <ip>" << std::endl;
}

struct IpAndCountryInfo
{
    long begin;
    long end;
    std::string country_name;
    IpAndCountryInfo(std::string line)
    {
        std::stringstream ss;
        ss << line;
        std::string begin_src;
        std::string end_src;

        std::getline(ss, begin_src, ',');
        std::getline(ss, end_src, ',');
        std::getline(ss, country_name, ',');

        if (begin_src.length() > 0 && begin_src[0] == '"')
        {
            begin = std::stol(begin_src.substr(1, begin_src.length() - 2));
        }
        else
        {
            begin = std::stol(begin_src);
        }

        if (end_src.length() > 0 && end_src[0] == '"')
        {
            end = std::stol(end_src.substr(1, end_src.length() - 2));
        }
        else
        {
            end = std::stol(end_src);
        }
    }

    static IpAndCountryInfo find(std::vector<IpAndCountryInfo> ips, long ip)
    {
        int min = 0;
        int max = ips.size() - 1;

        if (ips[min].begin <= ip && ip <= ips[min].end)
        {
            return ips[min];
        }
        if (ips[max].begin <= ip && ip <= ips[max].end)
        {
            return ips[max];
        }
        int index = -1;
        int prev_index = -1;
        do
        {
            prev_index = index;
            index = (max - min) / 2 + min;
            IpAndCountryInfo i = ips[index];
            if (i.begin <= ip && ip <= i.end)
            {
                return i;
            }
            if (ip < i.begin)
            {
                max = index;
            }
            else if (i.end < ip)
            {
                min = index;
            }
            //std::cout << "::" << index<< "::"  << std::endl;
        } while (prev_index != index);

        //for(ipinfo i : ips) {
        //    if(i.begin <= ip && ip<=i.end) {
        //        return i;
        //    }
        //}
        throw std::invalid_argument("ipinfo::find");
    }

    static void createIpAndCountryInfoList(std::string filepath, std::vector<IpAndCountryInfo> &output)
    {
        std::fstream f(filepath);
        std::string l;

        while (std::getline(f, l))
        {
            output.push_back(IpAndCountryInfo(l));
        }
    }
};

int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        printUsage();
    }

    std::vector<IpAndCountryInfo> context;
    IpAndCountryInfo::createIpAndCountryInfoList(std::string(argv[1]), context);

    std::cout << IpAndCountryInfo::find(context, 16781311).country_name << std::endl;

    return 0;
}

終わり

Source Code

https://github.com/kyorohiro/hello_libtorrent
app/main_get_contryname_from_ip_at_ip2location_data.cpp
※ Ipv6 の コードも同リポジトリ内にあります。

REF

以下でも公開しています。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?