Identifying country by IP address
Asked Answered
S

11

77

Is there a way to figure out the country name just by looking at an IP address? I mean, do countries have specific ranges of IP addresses? For example, Australia can have IP addresses only in the range of 123.45.56.89 - 231.54.65.98 (just an example)

Skinner answered 21/3, 2012 at 9:48 Comment(5)
What do you want to do exactly and on which platform ?Biedermeier
@ntidote I want to redirect user to the country-specific site by detecting user's IP address. C# .NETSkinner
The question has been discussed before. #1270591Biedermeier
The four blocks in an IP address are 8 bit numbers, so your examples are kind of strange. If you work on a web site, you should have a look at the GeoLocation API: dev.w3.org/geo/api/spec-source.html.Zebe
possible duplicate of Getting the location from an IP addressInaugurate
T
28

I think what you're looking for is an IP Geolocation database or service provider. There are many out there and some are free (get what you pay for).

Although I haven't used this service before, it claims to be in real-time: https://www.kickfire.com

Here's another IP geo location API from Abstract API - https://www.abstractapi.com/ip-geolocation-api

But just do a google search on IP geo and you'll get more results than you need.

Toneless answered 21/3, 2012 at 10:10 Comment(0)
M
48

No you can't - IP addresses get reallocated and reassigned from time to time, so the mapping of IP to location will also change over time.

If you want to find out the location that an IP address currently maps to you can either download a geolocation database, such as GeoLite from MaxMind, or use an API like http://ipinfo.io (my own service) which will also give you additional details:

$ curl ipinfo.io/8.8.8.8
{
  "ip": "8.8.8.8",
  "hostname": "google-public-dns-a.google.com",
  "loc": "37.385999999999996,-122.0838",
  "org": "AS15169 Google Inc.",
  "city": "Mountain View",
  "region": "California",
  "country": "US",
  "phone": 650
}
Map answered 7/8, 2014 at 6:39 Comment(7)
GeiLite seems legit. I didn't know there are so many geonames. Takes a bit of time to insert into the database parsed.Cthrine
@BenDowling it's interesting that you say it can't be done because "IP addresses get reallocated and reassigned from time to time" and then in the same post say that you've created a service that does it. Can it be done or can't it?Inadmissible
@S.Imp You can't get the country "just by looking at an IP address". Our service, IPinfo.io, infers the geographic location of IPs by pulling in many different data sources, and performing active scans across all IP addresses, and then publishes the results daily.Map
"You can't get the country just by looking at the IP address" Sure about this? I am confused. Because as far as I understand, countries have specific ranges and ip addresses assigned in those ranges simply match with that country name. And your script also does that, no?Nursemaid
@Nursemaid yeah, I mean there's no country information embedded within the IP, or an easy way to infer the country based on IP alone. And there's not a simple mapping of ranges to countries either. Geolocation providers, like us at IPinfo.io, have to do a lot of work to figure out which ranges are located in which cities & countries.Map
Ah ok, I see what you mean. There is not a formula to understand the country from IP number. But yes, there is a specific country assigned to each IP and we can see it by checking range rules (and a few other factors).Nursemaid
good one: curl ipinfo.io/1.1.1.1. Geolite also has an apiCalifornium
T
28

I think what you're looking for is an IP Geolocation database or service provider. There are many out there and some are free (get what you pay for).

Although I haven't used this service before, it claims to be in real-time: https://www.kickfire.com

Here's another IP geo location API from Abstract API - https://www.abstractapi.com/ip-geolocation-api

But just do a google search on IP geo and you'll get more results than you need.

Toneless answered 21/3, 2012 at 10:10 Comment(0)
P
10

I know that it is a very old post but for the sake of the users who are landed here and looking for a solution, if you are using Cloudflare as your DNS then you can activate IP geolocation and get the value from the request header,

Here is the code snippet in C# after you enable IP geolocation in Cloudflare through the network tab

 var countryCode = HttpContext.Request.Headers.Get("cf-ipcountry"); // in older asp.net versions like webform use HttpContext.Current.Request. ...
 var countryName = new RegionInfo(CountryCode)?.EnglishName;

You can simply map it to other programming languages, please take a look at the Cloudflare's documentation here


But if you are really insisting on using a 3rd party solution to have more precise information about the visitors using their IP here is a complete, ready to use implementation using C#:

The 3rd party I have used is https://ipstack.com, you can simply register for a free plan and get an access token to use for 100 API requests each month, I am using the JSON model to retrieve and like to convert all the info the API gives me, here we go:

The DTO:

    using System;
    using Newtonsoft.Json;

     public partial class GeoLocationModel
     {
        [JsonProperty("ip")]
        public string Ip { get; set; }

        [JsonProperty("hostname")]
        public string Hostname { get; set; }

        [JsonProperty("type")]
        public string Type { get; set; }

        [JsonProperty("continent_code")]
        public string ContinentCode { get; set; }

        [JsonProperty("continent_name")]
        public string ContinentName { get; set; }

        [JsonProperty("country_code")]
        public string CountryCode { get; set; }

        [JsonProperty("country_name")]
        public string CountryName { get; set; }

        [JsonProperty("region_code")]
        public string RegionCode { get; set; }

        [JsonProperty("region_name")]
        public string RegionName { get; set; }

        [JsonProperty("city")]
        public string City { get; set; }

        [JsonProperty("zip")]
        public long Zip { get; set; }

        [JsonProperty("latitude")]
        public double Latitude { get; set; }

        [JsonProperty("longitude")]
        public double Longitude { get; set; }

        [JsonProperty("location")]
        public Location Location { get; set; }

        [JsonProperty("time_zone")]
        public TimeZone TimeZone { get; set; }

        [JsonProperty("currency")]
        public Currency Currency { get; set; }

        [JsonProperty("connection")]
        public Connection Connection { get; set; }

        [JsonProperty("security")]
        public Security Security { get; set; }
     }

    public partial class Connection
    {
        [JsonProperty("asn")]
        public long Asn { get; set; }

        [JsonProperty("isp")]
        public string Isp { get; set; }
    }

    public partial class Currency
    {
        [JsonProperty("code")]
        public string Code { get; set; }

        [JsonProperty("name")]
        public string Name { get; set; }

        [JsonProperty("plural")]
        public string Plural { get; set; }

        [JsonProperty("symbol")]
        public string Symbol { get; set; }

        [JsonProperty("symbol_native")]
        public string SymbolNative { get; set; }
    }

    public partial class Location
    {
        [JsonProperty("geoname_id")]
        public long GeonameId { get; set; }

        [JsonProperty("capital")]
        public string Capital { get; set; }

        [JsonProperty("languages")]
        public Language[] Languages { get; set; }

        [JsonProperty("country_flag")]
        public Uri CountryFlag { get; set; }

        [JsonProperty("country_flag_emoji")]
        public string CountryFlagEmoji { get; set; }

        [JsonProperty("country_flag_emoji_unicode")]
        public string CountryFlagEmojiUnicode { get; set; }

        [JsonProperty("calling_code")]
        public long CallingCode { get; set; }

        [JsonProperty("is_eu")]
        public bool IsEu { get; set; }
    }

    public partial class Language
    {
        [JsonProperty("code")]
        public string Code { get; set; }

        [JsonProperty("name")]
        public string Name { get; set; }

        [JsonProperty("native")]
        public string Native { get; set; }
    }

    public partial class Security
    {
        [JsonProperty("is_proxy")]
        public bool IsProxy { get; set; }

        [JsonProperty("proxy_type")]
        public object ProxyType { get; set; }

        [JsonProperty("is_crawler")]
        public bool IsCrawler { get; set; }

        [JsonProperty("crawler_name")]
        public object CrawlerName { get; set; }

        [JsonProperty("crawler_type")]
        public object CrawlerType { get; set; }

        [JsonProperty("is_tor")]
        public bool IsTor { get; set; }

        [JsonProperty("threat_level")]
        public string ThreatLevel { get; set; }

        [JsonProperty("threat_types")]
        public object ThreatTypes { get; set; }
    }

    public partial class TimeZone
    {
        [JsonProperty("id")]
        public string Id { get; set; }

        [JsonProperty("current_time")]
        public DateTimeOffset CurrentTime { get; set; }

        [JsonProperty("gmt_offset")]
        public long GmtOffset { get; set; }

        [JsonProperty("code")]
        public string Code { get; set; }

        [JsonProperty("is_daylight_saving")]
        public bool IsDaylightSaving { get; set; }
    }

The Helper:

    using System.Configuration;
    using System.IO;
    using System.Net;
    using System.Threading.Tasks;

    public class GeoLocationHelper
    {
        public static async Task<GeoLocationModel> GetGeoLocationByIp(string ipAddress)
        {
            var request = WebRequest.Create(string.Format("http://api.ipstack.com/{0}?access_key={1}", ipAddress, ConfigurationManager.AppSettings["ipStackAccessKey"]));
            var response = await request.GetResponseAsync();
            using (var stream = new StreamReader(response.GetResponseStream()))
            {
                var jsonGeoData = await stream.ReadToEndAsync();
                return Newtonsoft.Json.JsonConvert.DeserializeObject<GeoLocationModel>(jsonGeoData);
            }
        }
    }
Provide answered 3/6, 2020 at 10:42 Comment(1)
That's a great hint. AWS CloudFront seems to have something like that too if you're already in the AWS Ecosystem (docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/…).Heroworship
M
6

You could use ipdata.co to perform the lookup

This answer uses a 'test' API Key that is very limited and only meant for testing a few calls. Signup for your own Free API Key and get up to 1500 requests daily for development.

curl https://api.ipdata.co/23.221.76.66?api-key=test

Ipdata has 10 endpoints globally each able to handle >10,000 requests per second!

Gives

{
    "ip": "23.221.76.66",
    "city": "Cambridge",
    "region": "Massachusetts",
    "region_code": "MA",
    "country_name": "United States",
    "country_code": "US",
    "continent_name": "North America",
    "continent_code": "NA",
    "latitude": 42.3626,
    "longitude": -71.0843,
    "asn": "AS20940",
    "organisation": "Akamai International B.V.",
    "postal": "02142",
    "calling_code": "1",
    "flag": "https://ipdata.co/flags/us.png",
    "emoji_flag": "\ud83c\uddfa\ud83c\uddf8",
    "emoji_unicode": "U+1F1FA U+1F1F8",
    "is_eu": false,
    "languages": [
        {
            "name": "English",
            "native": "English"
        }
    ],
    "currency": {
        "name": "US Dollar",
        "code": "USD",
        "symbol": "$",
        "native": "$",
        "plural": "US dollars"
    },
    "time_zone": {
        "name": "America/New_York",
        "abbr": "EDT",
        "offset": "-0400",
        "is_dst": true,
        "current_time": "2018-04-19T06:32:30.690963-04:00"
    },
    "threat": {
        "is_tor": false,
        "is_proxy": false,
        "is_anonymous": false,
        "is_known_attacker": false,
        "is_known_abuser": false,
        "is_threat": false,
        "is_bogon": false
    }
}⏎ 
Mcgovern answered 6/11, 2017 at 17:34 Comment(0)
N
6

Yes, countries have specific IP address ranges as you mentioned.

For example, Australia is between 16777216 - 16777471. China is between 16777472 - 16778239. But one country may have multiple ranges. For example, Australia also has this range between 16778240 - 16779263

(These are numerical conversions of IP addresses. It depends whether you use IPv4 or IPv6)

More information about these ranges can be seen here: https://lite.ip2location.com/ip-address-ranges-by-country

We get the ip addresses of our website visitors and sometimes want to make relevant campaign for a specific country. We were using bulk conversion tools but later on decided to define the rules in an Excel file and convert it in the tool. And we have built this Excel template: https://www.someka.net/excel-template/ip-to-country-converter/

Now we use this for our own needs and also sell it. I don't want it to be a sales pitch but for those who are looking for an easy solution can benefit from this.

Nursemaid answered 22/11, 2018 at 12:53 Comment(1)
The first link is not working.Californium
E
5

Amazon's CloudFront content delivery network can now be configured to pass this information through as a header. Given Amazon's size (they're big and stable, not going anywhere) and this is configuration over code (no third-party API to learn or code to maintain), all around believe this to be the best option.

If you do not use AWS CloudFront, I'd look into seeing if your CDN has a similar header option that can be turned on. Usually the large providers are quick to push for feature parity. And if you are not using a CDN, you could put CloudFront in front of your infrastructure and simply set the origin to resolve to whatever you are currently using.

Additionally, it also makes sense to resolve this at the CDN level. Your CDN is already having to figure out geo location to route the user to the nearest content node, might as well pass this information along and not figure it out twice through a third party API (this becomes chokepoint for your app, waiting for a geo location lookup to resolve). No need to do this work twice (and the second time, arguably less resilient [e.g., 3rd party geo lookup]).

https://aws.amazon.com/blogs/aws/enhanced-cloudfront-customization/

Geo-Targeting – CloudFront will detect the user’s country of origin and pass along the county code to you in the CloudFront-Viewer-Country header. You can use this information to customize your responses without having to use URLs that are specific to each country.

Eggplant answered 20/12, 2017 at 21:40 Comment(0)
P
3

It's not that easy. IP adresses are not assigned to countries as such, but to companies and organizations.

But maybe this can help you out: http://www.maxmind.com/app/geolitecountry

Pronoun answered 21/3, 2012 at 9:50 Comment(0)
F
2

May be these two links can help you Associate IP addresses with countries

http://en.wikipedia.org/wiki/Regional_Internet_Registry

Fountain answered 21/3, 2012 at 10:2 Comment(0)
K
2

Here is my solution in Python 3.x to return geo-location info given a dataframe containing IP Address(s); efficient parallelized application of function on vectorized pd.series/dataframe is the way to go.

Will contrast performance of two popular libraries to return location.

TLDR: use geolite2 method.

1. geolite2 package from geolite2 library

Input

# !pip install maxminddb-geolite2
import time
from geolite2 import geolite2
geo = geolite2.reader()
df_1 = train_data.loc[:50,['IP_Address']]

def IP_info_1(ip):
    try:
        x = geo.get(ip)
    except ValueError:   #Faulty IP value
        return np.nan
    try:
        return x['country']['names']['en'] if x is not None else np.nan
    except KeyError:   #Faulty Key value
        return np.nan

s_time = time.time()
# map IP --> country
#apply(fn) applies fn. on all pd.series elements
df_1['country'] = df_1.loc[:,'IP_Address'].apply(IP_info_1)
print(df_1.head(), '\n')
print('Time:',str(time.time()-s_time)+'s \n')

print(type(geo.get('48.151.136.76')))

Output

       IP_Address         country
0   48.151.136.76   United States
1    94.9.145.169  United Kingdom
2   58.94.157.121           Japan
3  193.187.41.186         Austria
4   125.96.20.172           China 

Time: 0.09906983375549316s 

<class 'dict'>

2. DbIpCity package from ip2geotools library

Input

# !pip install ip2geotools
import time
s_time = time.time()
from ip2geotools.databases.noncommercial import DbIpCity
df_2 = train_data.loc[:50,['IP_Address']]
def IP_info_2(ip):
    try:
        return DbIpCity.get(ip, api_key = 'free').country
    except:
        return np.nan
df_2['country'] = df_2.loc[:, 'IP_Address'].apply(IP_info_2)
print(df_2.head())
print('Time:',str(time.time()-s_time)+'s')

print(type(DbIpCity.get('48.151.136.76',api_key = 'free')))

Output

       IP_Address country
0   48.151.136.76      US
1    94.9.145.169      GB
2   58.94.157.121      JP
3  193.187.41.186      AT
4   125.96.20.172      CN

Time: 80.53318452835083s 

<class 'ip2geotools.models.IpLocation'>

A reason why the huge time difference could be due to the Data structure of the output, i.e direct subsetting from dictionaries seems way more efficient than indexing from the specicialized ip2geotools.models.IpLocation object.

Also, the output of the 1st method is dictionary containing geo-location data, subset respecitively to obtain needed info:

x = geolite2.reader().get('48.151.136.76')
print(x)

>>>
    {'city': {'geoname_id': 5101798, 'names': {'de': 'Newark', 'en': 'Newark', 'es': 'Newark', 'fr': 'Newark', 'ja': 'ニューアーク', 'pt-BR': 'Newark', 'ru': 'Ньюарк'}},

 'continent': {'code': 'NA', 'geoname_id': 6255149, 'names': {'de': 'Nordamerika', 'en': 'North America', 'es': 'Norteamérica', 'fr': 'Amérique du Nord', 'ja': '北アメリカ', 'pt-BR': 'América do Norte', 'ru': 'Северная Америка', 'zh-CN': '北美洲'}}, 

'country': {'geoname_id': 6252001, 'iso_code': 'US', 'names': {'de': 'USA', 'en': 'United States', 'es': 'Estados Unidos', 'fr': 'États-Unis', 'ja': 'アメリカ合衆国', 'pt-BR': 'Estados Unidos', 'ru': 'США', 'zh-CN': '美国'}}, 

'location': {'accuracy_radius': 1000, 'latitude': 40.7355, 'longitude': -74.1741, 'metro_code': 501, 'time_zone': 'America/New_York'}, 

'postal': {'code': '07102'}, 

'registered_country': {'geoname_id': 6252001, 'iso_code': 'US', 'names': {'de': 'USA', 'en': 'United States', 'es': 'Estados Unidos', 'fr': 'États-Unis', 'ja': 'アメリカ合衆国', 'pt-BR': 'Estados Unidos', 'ru': 'США', 'zh-CN': '美国'}}, 

'subdivisions': [{'geoname_id': 5101760, 'iso_code': 'NJ', 'names': {'en': 'New Jersey', 'es': 'Nueva Jersey', 'fr': 'New Jersey', 'ja': 'ニュージャージー州', 'pt-BR': 'Nova Jérsia', 'ru': 'Нью-Джерси', 'zh-CN': '新泽西州'}}]}
Kopaz answered 12/7, 2019 at 12:13 Comment(0)
B
1

I agree with above answers, the best way to get country from ip address is Maxmind.

If you want to write code in java, you might want to use i.e. geoip-api-1.2.10.jar and geoIP dat files (GeoIPCity.dat), which can be found via google.

Following code may be useful for you to get almost all information related to location, I am also using the same code.

public static String getGeoDetailsUsingMaxmind(String ipAddress, String desiredValue) 
    {
        Location getLocation;
        String returnString = "";
        try
        {
            String geoIPCity_datFile = System.getenv("AUTOMATION_HOME").concat("/tpt/GeoIP/GeoIPCity.dat");
            LookupService isp = new LookupService(geoIPCity_datFile);
            getLocation = isp.getLocation(ipAddress);
            isp.close();

            //Getting all location details 
            if(desiredValue.equalsIgnoreCase("latitude") || desiredValue.equalsIgnoreCase("lat"))
            {
                returnString = String.valueOf(getLocation.latitude);
            }
            else if(desiredValue.equalsIgnoreCase("longitude") || desiredValue.equalsIgnoreCase("lon"))
            {
                returnString = String.valueOf(getLocation.longitude);
            }
            else if(desiredValue.equalsIgnoreCase("countrycode") || desiredValue.equalsIgnoreCase("country"))
            {
                returnString = getLocation.countryCode;
            }
            else if(desiredValue.equalsIgnoreCase("countryname"))
            {
                returnString = getLocation.countryName;
            }
            else if(desiredValue.equalsIgnoreCase("region"))
            {
                returnString = getLocation.region;
            }
            else if(desiredValue.equalsIgnoreCase("metro"))
            {
                returnString = String.valueOf(getLocation.metro_code);
            }
            else if(desiredValue.equalsIgnoreCase("city"))
            {
                returnString = getLocation.city;
            }
            else if(desiredValue.equalsIgnoreCase("zip") || desiredValue.equalsIgnoreCase("postalcode"))
            {
                returnString = getLocation.postalCode;
            }
            else
            {
                returnString = "";
                System.out.println("There is no value found for parameter: "+desiredValue);
            }

            System.out.println("Value of: "+desiredValue + " is: "+returnString + " for ip address: "+ipAddress);
        }
        catch (Exception e) 
        {
            System.out.println("Exception occured while getting details from max mind. " + e);
        }
        finally
        {
            return returnString;
        }
    }
Backhanded answered 7/11, 2014 at 9:15 Comment(1)
You have to pay for MaxMind -- either for an API key or for the databases.Inadmissible
T
1

Yes, you can download the IP address ranges by country from https://lite.ip2location.com/ip-address-ranges-by-country

You can see that each country has multiple ranges and changes frequently.

Tena answered 28/2, 2018 at 2:12 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.