Advertisement
Brainsucker

Untitled

Oct 9th, 2011
88
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 9.50 KB | None | 0 0
  1. # IPToCountry by David Bowland
  2. # ./addons/eventscripts/_libs/python/iptocountry.py
  3. # Database provided by: http://Software77.net
  4.  
  5. """
  6.   * To use this library, you must first import it:
  7.  
  8.   import iptocountry
  9.  
  10.  
  11.   * IPToCountry exposes the following functions:
  12.  
  13.   get_country(ip)
  14.      - Returns full the country name, three-letter country abbreviation corresponding to IP
  15.      ip = IP address to resolve to country name
  16.  
  17.   get_location_data(ip)
  18.      - Returns a dictionary of location data corresponding to IP
  19.         * Dictionary keys:
  20.            ip_from      = Bottom long IP of location range
  21.            ip_to        = Upper long IP of location range
  22.            registry     = International registry agency through which the IP is registered
  23.            assigned     = Unix time the IP was assigned
  24.            country_2    = Two-character international country code
  25.            country_3    = Three-character international country code (preferred because more unique)
  26.            country_long = Country name
  27.      ip = IP address to resolve to location data
  28.  
  29.   update_data(url=None)
  30.      - Syncs server database with internet data--VERY SLOW
  31.      - Returns True if update was sucessful otherwise returns False
  32.      url = URL to download IPToCountry database
  33.  
  34.   get_last_update()
  35.      - Returns the time of the last database update (in Unix time)
  36.  
  37.   update_from_file(path=None)
  38.      - Updates the database from IpToCountry.csv that has been extracted, see the library link below to download the database
  39.      - Returns True if data was successfully updated otherwise return False
  40.      path = Absolute path to file (including IpToCountry.csv)
  41.  
  42.  
  43.   * The following instance of CountryResolve is publicly exposed:
  44.  
  45.   service
  46.  
  47.  
  48.   * The database for this library is provided by http://Software77.net. For more information, please see:
  49.  
  50.   http://software77.net/geo-ip/
  51.  
  52.   * NO CLAIMS ARE MADE REGARDING THE ACCURACY OF THIS DATABASE. Please use this library with that in mind.
  53. """
  54.  
  55. from __future__ import with_statement
  56.  
  57. __all__ = ['get_country', 'get_location_data', 'update_data', 'get_last_update', 'update_from_file', 'service']
  58.  
  59. import os
  60. import sys
  61. import traceback
  62. import urllib
  63. import zipfile
  64.  
  65. from contextlib import closing
  66. from StringIO import StringIO
  67.  
  68.  
  69. try:
  70.    import psyco
  71.    psyco.full()
  72.  
  73.    # Source server running EventScripts
  74.    import es
  75.    dbgmsg   = es.dbgmsg
  76.    lib_path = es.getAddonPath('_libs') + '/python/'
  77.  
  78.    import installlib
  79.    # Designate the database file for cleanup by installlib
  80.    if installlib.infomanager.hasInstallInfo('iptocountry'):
  81.       installinfo = installlib.infomanager.getInstallInfo('iptocountry')
  82.       installinfo.addFile(lib_path + 'iptocountry.db')
  83.       installlib.infomanager.saveInstallInfo('iptocountry', installinfo)
  84.  
  85. except ImportError:
  86.    # IDLE
  87.    def dbgmsg(x, msg): print msg
  88.    lib_path = os.getcwd() + '/'
  89.  
  90.  
  91. class CountryResolve(object):
  92.    base_path  = lib_path
  93.    default_db = 'http://software77.net/geo-ip?DL=2'
  94.  
  95.    def __init__(self, url=None):
  96.       """ Loads database for later query """
  97.       self.ip_data = []
  98.  
  99.       # Loads database
  100.       if self.get_last_update():
  101.          self._load_data()
  102.  
  103.       else:
  104.          dbgmsg(0, 'No IPToCountry database found! Downloading database.')
  105.          if not self.update_data(url):
  106.             raise IOError, 'Could not download IPToCountry database!'
  107.          self._load_data()
  108.  
  109.    def get_location_data(self, ip):
  110.       """
  111.      Returns a dictionary of location data corresponding to IP
  112.      Dictionary keys:
  113.         ip_from      = Bottom long IP of location range
  114.         ip_to        = Upper long IP of location range
  115.         registry     = International registry agency through which the IP is registered
  116.         assigned     = Unix time the IP was assigned
  117.         country_2    = Two-character international country code
  118.         country_3    = Three-character international country code (preferred because more unique)
  119.         country_long = Country name
  120.      More information can be found here: http://software77.net/geo-ip/
  121.      """
  122.       if not self.ip_data:
  123.          # No database to query
  124.          return {}
  125.  
  126.       # Formats the IP, without port, to a list
  127.       ip = ip.split(':', 1)[0]
  128.       ip_list = map(int, ip.split('.'))
  129.  
  130.       # Validates the address for conversion to long format
  131.       if len(ip_list) != 4:
  132.          raise ValueError, 'Invalid IP address "%s"' % ip
  133.  
  134.       # Converts the IP to long IP format
  135.       long_ip = ip_list[3] + (ip_list[2] << 8) + (ip_list[1] << 16) + (ip_list[0] << 24)
  136.  
  137.       # Finds the IP in the database
  138.       for data in self.ip_data:
  139.          if long_ip <= data['ip_to']:
  140.             return data
  141.  
  142.       # No data found
  143.       return {}
  144.  
  145.    def get_country(self, ip):
  146.       """ Returns full country name and three-letter country abbreviation corresponding to IP """
  147.       data = self.get_location_data(ip)
  148.  
  149.       if data:
  150.          # Country data found
  151.          return data['country_long'], data['country_3']
  152.  
  153.       else:
  154.          # Country unknown
  155.          return 'Unknown', 'Unknown'
  156.  
  157.    def update_data(self, url=None):
  158.       """
  159.      Syncs server database with internet data--VERY SLOW
  160.      Returns True if update is sucessful, otherwise returns False
  161.      """
  162.       if not url:
  163.          url = self.default_db
  164.  
  165.       # The database is not yet updated
  166.       return_val = False
  167.  
  168.       # Download database
  169.       raw_zip = self._download_database(url)
  170.  
  171.       # If download was sucessful, parse the databse
  172.       if raw_zip:
  173.          return_val = self._parse_zip(raw_zip)
  174.  
  175.          # Close the downloaded zip file
  176.          raw_zip.close()
  177.  
  178.       # Update complete
  179.       return return_val
  180.  
  181.    def get_last_update(self):
  182.       """ Returns the time of the last database update (in Unix time) """
  183.       path = self.base_path + 'iptocountry.db'
  184.       return os.stat(path).st_mtime if os.path.isfile(path) else 0
  185.  
  186.    def update_from_file(path=None):
  187.       """ Updates the database from an existing file (without download) """
  188.       if path is None:
  189.          path = self.base_path + 'IpToCountry.csv'
  190.       return_val = False
  191.  
  192.       try:
  193.          with open(path) as f:
  194.             if self.__parse_database(f):
  195.                self._load_data()
  196.                return_val = True
  197.  
  198.       except:
  199.          self.__show_exception(sys.exc_info())
  200.  
  201.       return return_val
  202.  
  203.    def _load_data(self):
  204.       """
  205.      Internal use recommended: This function is SLOW
  206.      Loads the IP data into memory
  207.      """
  208.       self.ip_data = []
  209.       dbpath = self.base_path + 'iptocountry.db'
  210.  
  211.       with open(dbpath) as data_db:
  212.          # Reads the contents of the database to a dictionary
  213.          for line in data_db.readlines():
  214.             data = line.strip().split(',')
  215.             self.ip_data.append({
  216.              'ip_from': float(data[0]),
  217.              'ip_to': float(data[1]),
  218.              'registry': data[2],
  219.              'assigned': float(data[3]),
  220.              'country_2': data[4],
  221.              'country_3': data[5].strip(),
  222.              'country_long': data[6]})
  223.  
  224.    def _download_database(self, url):
  225.       try:
  226.          with closing(urllib.urlopen(url)) as u:
  227.             return StringIO(u.read())
  228.       except IOError:
  229.          self.__show_exception(sys.exc_info())
  230.       return None
  231.  
  232.    def _parse_zip(self, raw_zip):
  233.       try:
  234.          zip = zipfile.ZipFile(raw_zip)
  235.  
  236.          filelist = map(lambda x: x.filename, zip.filelist)
  237.          db_file  = 'IpToCountry.csv' if 'IpToCountry.csv' in filelist else filelist[0]
  238.  
  239.          with closing(StringIO(zip.read(db_file))) as raw_database:
  240.             return_val = self.___parse_database(raw_database)
  241.  
  242.          if return_val:
  243.             self._load_data()
  244.  
  245.       except:
  246.          self.__show_exception(sys.exc_info())
  247.          return_val = False
  248.  
  249.       return return_val
  250.  
  251.    def ___parse_database(self, raw_database):
  252.       """
  253.      Internal use highly recommended
  254.      Converts raw internet data into plain-text format
  255.      """
  256.       database = []
  257.  
  258.       for line in raw_database.readlines():
  259.          if line.startswith('#'): continue
  260.  
  261.          if line.count(',') >= 6:
  262.             database.append(line.strip().replace(r'"', '') + '\n')
  263.  
  264.       if not database: return False
  265.  
  266.       # Saves the parsed database
  267.       with open(self.base_path + 'iptocountry.db', 'w') as new_db:
  268.          # Sorts the database for quicker reference
  269.          new_db.writelines(sorted(database, key=lambda x: float(x.split(',', 1)[0])))
  270.          new_db.close()
  271.  
  272.       return True
  273.  
  274.    def __show_exception(self, exc_info):
  275.       dbgmsg(1, 'IPToCountry update exception:')
  276.       sys.excepthook(*exc_info)
  277.  
  278.  
  279. # Public instance of CountryResolve
  280. service = CountryResolve()
  281.  
  282.  
  283. # Easy-reference functions to the public instance of CountryResolve
  284. def get_country(*a, **kw):
  285.    """ Returns full country name and three-letter country abbreviation of IP """
  286.    return service.get_country(*a, **kw)
  287.  
  288.  
  289. def get_location_data(*a, **kw):
  290.    """ Returns a dictionary of location data of IP """
  291.    return service.get_location_data(*a, **kw)
  292.  
  293.  
  294. def get_last_update(*a, **kw):
  295.    """ Returns the time of the last database update (in Unix time) """
  296.    return service.get_last_update(*a, **kw)
  297.  
  298.  
  299. def update_data(*a, **kw):
  300.    """ Syncs server database with internet data--VERY SLOW """
  301.    return service.update_data(*a, **kw)
  302.  
  303.  
  304. def update_from_file(*a, **kw):
  305.    """ Updates the database from an existing file (without download) """
  306.    return service.update_from_file(*a, **kw)
  307.  
  308.  
  309. """ Python program functionality """
  310.  
  311. if __name__ == '__main__':
  312.    text = 'start'
  313.    print 'Enter a blank line to exit\n'
  314.    while text:
  315.       text = raw_input('Enter IP address: ')
  316.       if text:
  317.          print 'Country: ', get_country(text), '\n'
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement