Skip to content

Commit

Permalink
Added provider field and exception handling for incorrect BIN database.
Browse files Browse the repository at this point in the history
  • Loading branch information
ip2location authored Jun 25, 2021
1 parent a7e39fe commit 092febd
Show file tree
Hide file tree
Showing 6 changed files with 83 additions and 22 deletions.
3 changes: 3 additions & 0 deletions ChangeLog
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
3.2.0 2021-06-25
* Added provider field and exception handling for incorrect BIN database.

3.1.2 2019-08-13
* Updated version number to latest.

Expand Down
89 changes: 71 additions & 18 deletions IP2Proxy.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import struct
import socket
import ipaddress
import os

if sys.version < '3':
def u(x):
Expand Down Expand Up @@ -52,7 +53,7 @@ def inet_pton(t, addr):
return out_addr_p.raw
socket.inet_pton = inet_pton

_VERSION = '3.1.2'
_VERSION = '3.2.0'
_NO_IP = 'MISSING IP ADDRESS'
_FIELD_NOT_SUPPORTED = 'NOT SUPPORTED'
_INVALID_IP_ADDRESS = 'INVALID IP ADDRESS'
Expand All @@ -74,30 +75,33 @@ class IP2ProxyRecord:
last_seen = _FIELD_NOT_SUPPORTED
domain = _FIELD_NOT_SUPPORTED
threat = _FIELD_NOT_SUPPORTED
provider = _FIELD_NOT_SUPPORTED

def __str__(self):
return str(self.__dict__)

def __repr__(self):
return repr(self.__dict__)

_COUNTRY_POSITION = (0, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3)
_REGION_POSITION = (0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4)
_CITY_POSITION = (0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5)
_ISP_POSITION = (0, 0, 0, 0, 6, 6, 6, 6, 6, 6, 6)
_PROXYTYPE_POSITION = (0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2)
_DOMAIN_POSITION = (0, 0, 0, 0, 0, 7, 7, 7, 7, 7, 7)
_USAGETYPE_POSITION = (0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8)
_ASN_POSITION = (0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9)
_AS_POSITION = (0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 10)
_LASTSEEN_POSITION = (0, 0, 0, 0, 0, 0, 0, 0, 11, 11, 11)
_THREAT_POSITION = (0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 12)
_COUNTRY_POSITION = (0, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3)
_REGION_POSITION = (0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4)
_CITY_POSITION = (0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5)
_ISP_POSITION = (0, 0, 0, 0, 6, 6, 6, 6, 6, 6, 6, 6)
_PROXYTYPE_POSITION = (0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2)
_DOMAIN_POSITION = (0, 0, 0, 0, 0, 7, 7, 7, 7, 7, 7, 7)
_USAGETYPE_POSITION = (0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8)
_ASN_POSITION = (0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9)
_AS_POSITION = (0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 10, 10)
_LASTSEEN_POSITION = (0, 0, 0, 0, 0, 0, 0, 0, 11, 11, 11, 11)
_THREAT_POSITION = (0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 12, 12)
_PROVIDER_POSITION = (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13)

class IP2Proxy(object):
''' IP2Proxy database '''

def __init__(self, filename=None):
''' Creates a database object and opens a file if filename is given '''

if filename:
self.open(filename)

Expand All @@ -113,6 +117,10 @@ def open(self, filename):
''' Opens a database file '''
# Ensure old file is closed before opening a new one
self.close()

# if filename is not None:
if os.path.isfile(filename) == False:
raise ValueError("The database file does not seem to exist.")

self._f = open(filename, 'rb')
self._dbtype = struct.unpack('B', self._f.read(1))[0]
Expand All @@ -126,6 +134,14 @@ def open(self, filename):
self._ipv6dbaddr = struct.unpack('<I', self._f.read(4))[0]
self._ipv4indexbaseaddr = struct.unpack('<I', self._f.read(4))[0]
self._ipv6indexbaseaddr = struct.unpack('<I', self._f.read(4))[0]
self._productcode = struct.unpack('B', self._f.read(1))[0]
self._licensecode = struct.unpack('B', self._f.read(1))[0]
self._databasesize = struct.unpack('B', self._f.read(1))[0]
if (self._productcode != 2) :
if (self._dbyear > 20 and self._productcode != 0) :
self._f.close()
del self._f
raise ValueError("Incorrect IP2Location BIN file format. Please make sure that you are using the latest IP2Location BIN file.")

def close(self):
if hasattr(self, '_f'):
Expand Down Expand Up @@ -269,10 +285,17 @@ def get_threat(self, ip):
threat = _INVALID_IP_ADDRESS
return threat

def get_provider(self, ip):
''' Get provider'''
try:
rec = self._get_record(ip)
provider = rec.provider
except:
provider = _INVALID_IP_ADDRESS
return provider

def get_all(self, ip):
''' Get the whole record with all fields read from the file '''
# if self._validate_addr(ip) == False:
# return ipv, ipnum
try:
rec = self._get_record(ip)
country_short = rec.country_short
Expand All @@ -287,6 +310,7 @@ def get_all(self, ip):
as_name = rec.as_name
last_seen = rec.last_seen
threat = rec.threat
provider = rec.provider

# if self._dbtype == 1:
# is_proxy = 0 if (rec.country_short == '-') else ( 2 if ((rec.proxy_type == 'DCH') | (rec.proxy_type == 'SES')) else 1)
Expand All @@ -301,7 +325,7 @@ def get_all(self, ip):
is_proxy = -1
except:
# except Exception as ex:
print(ex)
# print(ex)
country_short = _INVALID_IP_ADDRESS
country_long = _INVALID_IP_ADDRESS
region = _INVALID_IP_ADDRESS
Expand All @@ -315,6 +339,7 @@ def get_all(self, ip):
as_name = _INVALID_IP_ADDRESS
last_seen = _INVALID_IP_ADDRESS
threat = _INVALID_IP_ADDRESS
provider = _INVALID_IP_ADDRESS

results = {}
results['is_proxy'] = is_proxy
Expand All @@ -330,6 +355,7 @@ def get_all(self, ip):
results['as_name'] = as_name
results['last_seen'] = last_seen
results['threat'] = threat
results['provider'] = provider
return results

def _reads(self, offset):
Expand Down Expand Up @@ -428,6 +454,11 @@ def calc_off(what, mid):
elif _THREAT_POSITION[self._dbtype] == 0:
rec.threat = _FIELD_NOT_SUPPORTED

if _PROVIDER_POSITION[self._dbtype] != 0:
rec.provider = self._reads(self._readi(calc_off(_PROVIDER_POSITION, mid)) + 1)
elif _PROVIDER_POSITION[self._dbtype] == 0:
rec.provider = _FIELD_NOT_SUPPORTED

return rec

def __iter__(self):
Expand Down Expand Up @@ -493,12 +524,30 @@ def _parse_addr(self, addr):
# socket.inet_pton(socket.AF_INET, addr)
ipv = 4
return ipv, ipnum

def _get_record(self, ip):
low = 0
ipv = self._parse_addr(ip)[0]
ipnum = self._parse_addr(ip)[1]
if ipv == 4:
ipnum = self._parse_addr(ip)[1]
print (ipv)
print (ipnum)
if (ipv == 0):
rec = IP2ProxyRecord()
rec.country_short = _INVALID_IP_ADDRESS
rec.country_long = _INVALID_IP_ADDRESS
rec.region = _INVALID_IP_ADDRESS
rec.city = _INVALID_IP_ADDRESS
rec.isp = _INVALID_IP_ADDRESS
rec.proxy_type = _INVALID_IP_ADDRESS
rec.domain = _INVALID_IP_ADDRESS
rec.usage_type = _INVALID_IP_ADDRESS
rec.asn = _INVALID_IP_ADDRESS
rec.as_name = _INVALID_IP_ADDRESS
rec.last_seen = _INVALID_IP_ADDRESS
rec.threat = _INVALID_IP_ADDRESS
rec.provider = _INVALID_IP_ADDRESS
return rec
elif ipv == 4:
# ipnum = struct.unpack('!L', socket.inet_pton(socket.AF_INET, ip))[0]
if (ipnum == MAX_IPV4_RANGE):
ipno = ipnum - 1
Expand Down Expand Up @@ -541,6 +590,8 @@ def _get_record(self, ip):
rec.asn = _NO_IP
rec.as_name = _NO_IP
rec.last_seen = _NO_IP
rec.threat = _NO_IP
rec.provider = _NO_IP
return rec
else:
rec = IP2ProxyRecord()
Expand All @@ -555,6 +606,8 @@ def _get_record(self, ip):
rec.asn = _INVALID_IP_ADDRESS
rec.as_name = _INVALID_IP_ADDRESS
rec.last_seen = _INVALID_IP_ADDRESS
rec.threat = _INVALID_IP_ADDRESS
rec.provider = _INVALID_IP_ADDRESS
return rec

while low <= high:
Expand Down
2 changes: 1 addition & 1 deletion PKG-INFO
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Metadata-Version: 1.0
Name: IP2Proxy
Version: 3.1.2
Version: 3.2.0
Summary: Python API for IP2Proxy database
Home-page: http://www.ip2location.com
Author: IP2Location
Expand Down
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ Below are the methods supported in this library.
|---|---|
|open|Open the IP2Proxy BIN data with **File I/O** mode for lookup.|
|close|Close and clean up the file pointer.|
|get_package_version|Get the package version (1 to 10 for PX1 to PX10 respectively).|
|get_package_version|Get the package version (1 to 11 for PX1 to PX11 respectively).|
|get_module_version|Get the module version.|
|get_database_version|Get the database version.|
|is_proxy|Check whether if an IP address was a proxy. Returned value:<ul><li>-1 : errors</li><li>0 : not a proxy</li><li>1 : a proxy</li><li>2 : a data center IP address</li></ul>|
Expand All @@ -33,6 +33,7 @@ Below are the methods supported in this library.
|get_as_name|Return the autonomous system (AS) name of proxy's IP address or domain name.|
|get_last_seen|Return the last seen days ago value of proxy's IP address or domain name.|
|get_threat|Return the threat types reported to proxy's IP address or domain name.|
|get_provider|Returns the VPN service provider name if available.|

## Requirements
1. Python 2.2 and above
Expand Down Expand Up @@ -77,6 +78,7 @@ print ('ASN: ' + db.get_asn("4.0.0.47"))
print ('AS Name: ' + db.get_as_name("4.0.0.47"))
print ('Last Seen: ' + db.get_last_seen("4.0.0.47"))
print ('Threat: ' + db.get_threat("4.0.0.47"))
print ('Provider: ' + db.get_provider("4.0.0.47"))

# single function to get all proxy data returned in array
record = db.get_all("4.0.0.47")
Expand All @@ -94,6 +96,7 @@ print ('ASN: ' + record['asn'])
print ('AS Name: ' + record['as_name'])
print ('Last Seen: ' + record['last_seen'])
print ('Threat: ' + record['threat'])
print ('Provider: ' + record['provider'])

# close IP2Proxy BIN database
db.close()
Expand Down
4 changes: 3 additions & 1 deletion example.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import IP2Proxy
import IP2Proxy, os

db = IP2Proxy.IP2Proxy()

Expand All @@ -24,6 +24,7 @@
print ('AS Name: ' + db.get_as_name("4.0.0.47"))
print ('Last Seen: ' + db.get_last_seen("4.0.0.47"))
print ('Threat: ' + db.get_threat("4.0.0.47"))
print ('Provider: ' + db.get_provider("4.0.0.47"))

# single function to get all proxy data returned in array
record = db.get_all("4.0.0.47")
Expand All @@ -41,6 +42,7 @@
print ('AS Name: ' + record['as_name'])
print ('Last Seen: ' + record['last_seen'])
print ('Threat: ' + record['threat'])
print ('Provider: ' + record['provider'])

# close IP2Proxy BIN database
db.close()
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

setuptools.setup(
name="IP2Proxy",
version="3.1.2",
version="3.2.0",
author="IP2Location",
author_email="support@ip2location.com",
description="Python API for IP2Proxy database. It can be used to query an IP address if it was being used as open proxy, web proxy, VPN anonymizer and TOR exits.",
Expand Down

0 comments on commit 092febd

Please sign in to comment.