2021-06-08 22:45:25 +02:00
#!/usr/bin/python
2020-08-04 03:11:35 +02:00
2020-11-24 23:07:38 +01:00
import argparse
2020-08-04 03:11:35 +02:00
import sys
try :
import geoip2 . database
2020-11-24 23:07:38 +01:00
import geoip2 . errors
2020-08-04 03:11:35 +02:00
except ImportError :
print (
2020-11-24 23:07:38 +01:00
" Required modules geoip2.database and geoip2.errors not found. On Gentoo Linux, please install dev-python/geoip2 from the ' fritteli ' overlay. " ,
2020-08-04 03:11:35 +02:00
file = sys . stderr )
exit ( 1 )
2020-11-24 23:07:38 +01:00
try :
import maxminddb . errors
except ImportError :
print (
" Required module maxminddb.errors not found. On Gentoo Linux, please install dev-python/maxminddb from the ' fritteli ' overlay. " ,
file = sys . stderr )
exit ( 1 )
2020-08-04 03:11:35 +02:00
class LookupException ( Exception ) :
"""
General Exception class that is raised if anything goes wrong .
"""
pass
def get_county_code ( ipaddress , dbfile ) :
"""
Determine the country code that the given ipaddress comes from .
: param ipaddress : The IP address to look up
: param dbfile : The path to the GeoIP2 / GeoLite2 database file ( Country or City database )
: return : The ISO country code ( 2 letters )
"""
if not ipaddress :
raise LookupException ( " No address given " )
if not dbfile :
raise LookupException ( " No db file given " )
2021-07-15 21:51:14 +02:00
2020-08-04 03:11:35 +02:00
reader = None
try :
reader = geoip2 . database . Reader ( dbfile )
dbtype = reader . metadata ( ) . database_type
country = None
if dbtype == ' GeoLite2-City ' or dbtype == ' GeoIP2-City ' :
country = reader . city ( ipaddress ) . country
2021-07-15 21:55:10 +02:00
elif dbtype == ' GeoLite2-Country ' or dbtype == ' GeoIP2-Country ' :
2020-08-04 03:11:35 +02:00
country = reader . country ( ipaddress ) . country
# ASN is not supported
# elif dbfile == 'GeoLite2-ASN' or dbtype == 'GeoIP2-ASN':
2021-07-15 21:51:14 +02:00
else :
2020-08-04 03:11:35 +02:00
raise LookupException ( " Unsupported DB type: " + dbtype )
2021-07-15 21:51:14 +02:00
2020-08-04 03:11:35 +02:00
return country . iso_code
2020-11-24 23:07:38 +01:00
except FileNotFoundError as e :
raise LookupException ( e . args )
except maxminddb . errors . InvalidDatabaseError as e :
raise LookupException ( e . args )
except geoip2 . errors . AddressNotFoundError as e :
raise LookupException ( e . args )
except ValueError as e :
raise LookupException ( e . args )
2020-08-04 03:11:35 +02:00
finally :
if reader :
reader . close ( )
2021-07-14 03:37:50 +02:00
def get_details ( ipaddress , dbfile ) :
2021-07-15 21:51:14 +02:00
"""
Determine the country code , continent code and the network that the given ipaddress comes from .
: param ipaddress : The IP address to look up
: param dbfile : The path to the GeoIP2 / GeoLite2 database file ( Country or City database )
: return : A string consisting of the ISO country code ( 2 letters ) , ISO continent code ( 2 letters ) and network ( CIDR notation ) , concatenated by " , "
"""
if not ipaddress :
raise LookupException ( " No address given " )
if not dbfile :
raise LookupException ( " No db file given " )
2021-07-14 03:37:50 +02:00
reader = None
try :
reader = geoip2 . database . Reader ( dbfile )
2021-07-15 21:51:14 +02:00
dbtype = reader . metadata ( ) . database_type
result = None
country = None
continent = None
network = None
if dbtype == ' GeoLite2-City ' or dbtype == ' GeoIP2-City ' :
result = reader . city ( ipaddress )
2021-07-15 21:55:10 +02:00
elif dbtype == ' GeoLite2-Country ' or dbtype == ' GeoIP2-Country ' :
2021-07-15 21:51:14 +02:00
result = reader . country ( ipaddress )
# ASN is not supported
# elif dbfile == 'GeoLite2-ASN' or dbtype == 'GeoIP2-ASN':
else :
raise LookupException ( " Unsupported DB type: " + dbtype )
country = result . country . iso_code
continent = result . continent . code
network = result . traits . network
return " %s , %s , %s " % ( country , continent , network )
2021-07-14 03:37:50 +02:00
finally :
if reader :
reader . close ( )
2020-08-04 03:11:35 +02:00
def parse_command_line ( argv ) :
"""
Parse the command line . First , the database file must be specified ( " -f /path/to/db/file.mmdb " ) , then the IP address
to look up
: param argv :
: return :
"""
dbfile = None
2020-11-24 23:07:38 +01:00
parser = argparse . ArgumentParser ( description = ' Get the country code from an IP address ' )
parser . add_argument ( ' -f ' , dest = ' dbfile ' , required = True , help = " Path to the GeoIP2 database file " )
2021-07-15 21:51:14 +02:00
parser . add_argument ( ' -d ' , dest = ' detail ' , action = ' store_const ' , const = True , default = False , help = " Verbose output: Print continent code and network along with country code " )
parser . add_argument ( ' --detail ' , dest = ' detail ' , action = ' store_const ' , const = True , default = False , help = " Verbose output: Print continent code and network along with country code " )
2020-11-24 23:07:38 +01:00
parser . add_argument ( ' address ' , help = " The IP address to check " )
args = parser . parse_args ( )
2021-07-15 21:51:14 +02:00
2021-07-14 03:37:50 +02:00
return args . dbfile , args . address , args . detail
2020-08-04 03:11:35 +02:00
def main ( argv ) :
"""
Read the database file and the IP address from the command line and print the corresponding ISO country code on
stdout .
2021-07-15 21:51:14 +02:00
: param argv : Format : " -f /path/to/database.mmdb [--detail|-d] ip.v4.add.ress "
2020-08-04 03:11:35 +02:00
: return :
"""
2020-11-24 23:07:38 +01:00
try :
2021-07-14 03:37:50 +02:00
( dbfile , ipaddress , detail ) = parse_command_line ( argv )
if detail :
code = get_details ( ipaddress , dbfile )
else :
code = get_county_code ( ipaddress , dbfile )
2021-07-15 21:51:14 +02:00
2020-11-24 22:04:38 +01:00
print ( code )
except LookupException as e :
2020-11-24 23:07:38 +01:00
print ( e . args , file = sys . stderr )
2020-11-24 22:04:38 +01:00
print ( " Unknown " )
2020-08-04 03:11:35 +02:00
if __name__ == ' __main__ ' :
try :
main ( sys . argv [ 1 : ] )
except BaseException as e :
2020-11-24 23:07:38 +01:00
print ( " Unknown " )
2020-08-04 03:11:35 +02:00
raise e