Skip to content

Instantly share code, notes, and snippets.

@markusl
Created July 16, 2011 15:32
Show Gist options
  • Save markusl/1086449 to your computer and use it in GitHub Desktop.
Save markusl/1086449 to your computer and use it in GitHub Desktop.
C++ class to map IP addresses to countries using database from http://software77.net/geo-ip/
#include <string>
#include <fstream>
#include <vector>
#include <sstream>
#include <algorithm>
#include <stdexcept>
std::vector<std::string> &split(const std::string &s, char delim, std::vector<std::string> &elems) {
std::stringstream ss(s);
std::string item;
while(std::getline(ss, item, delim)) {
elems.push_back(item);
}
return elems;
}
std::vector<std::string> split(const std::string &s, char delim) {
std::vector<std::string> elems;
return split(s, delim, elems);
}
template <class T>
T stringTo(const std::string &str)
{
T result;
std::stringstream ss(str);
ss >> result;
return result;
}
template <class Ty, class Container>
std::vector<Ty> convertContainerTo(const Container &source)
{
std::vector<Ty> result;
std::for_each(source.begin(), source.end(),
[&result](const std::string &it){ result.push_back(stringTo<Ty>(it)); });
return result;
}
typedef unsigned int uint32_t;
typedef uint32_t IpAddress_t;
/** IP address mapping entry */
class IpAddressMapping {
public:
std::string country;
IpAddress_t startAddress;
};
/** Class for mapping IP addresses to countries using database
* from http://software77.net/geo-ip/ */
class IpToCountrySlow
{
std::vector<IpAddressMapping> m_countryIpList;
public:
/** Construct new IP-to-country mapper from the specified file. */
IpToCountrySlow(const std::string &FileName = "IpToCountry.csv")
{
std::ifstream file(FileName);
while(file.good() && !file.eof())
{
std::string line;
std::getline(file, line);
if(line.find_first_of('#') == std::string::npos && line.length() > 0)
m_countryIpList.push_back(ParseSingleLine(line));
}
}
/** Find the country for given IP address or throw std::exception. */
IpAddressMapping GetCountry(const std::string &address) const
{
IpAddress_t integerIp = IntegerFromIp(address);
auto it = std::find_if(m_countryIpList.rbegin(), m_countryIpList.rend(),
[integerIp](IpAddressMapping it) { return it.startAddress <= integerIp; });
if(it == m_countryIpList.rend())
throw std::runtime_error("Address not found");
return *it;
}
/** Convert a human-readable ipv4 address to integer */
static IpAddress_t IntegerFromIp(const std::string &ip)
{
auto tokens = split(ip, '.');
auto integers = convertContainerTo<uint32_t>(tokens);
return (integers[0] << (3*8)) +
(integers[1] << (2*8)) +
(integers[2] << (1*8)) +
integers[3];
}
private:
// File format:
// "1464729600","1464860671","ripencc","1117497600","DE","DEU","Germany"
static IpAddressMapping ParseSingleLine(const std::string &line)
{
IpAddressMapping mapping;
auto tokens = split(line, ',');
mapping.country = tokens[6].substr(1, tokens[6].length()-2);
mapping.startAddress = stringTo<uint32_t>(tokens[0].substr(1, tokens[0].length()-2));
return mapping;
}
};
// Example usage
int main()
{
IpToCountrySlow iptc;
IpAddressMapping country = iptc.GetCountry("158.127.18.60");
}
@huangyudan
Copy link

I have try it but nothing happened,what is the expected result??

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment