Skip to content

Commit 092febd

Browse files
authored
Added provider field and exception handling for incorrect BIN database.
1 parent a7e39fe commit 092febd

File tree

6 files changed

+83
-22
lines changed

6 files changed

+83
-22
lines changed

ChangeLog

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
3.2.0 2021-06-25
2+
* Added provider field and exception handling for incorrect BIN database.
3+
14
3.1.2 2019-08-13
25
* Updated version number to latest.
36

IP2Proxy.py

Lines changed: 71 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import struct
1919
import socket
2020
import ipaddress
21+
import os
2122

2223
if sys.version < '3':
2324
def u(x):
@@ -52,7 +53,7 @@ def inet_pton(t, addr):
5253
return out_addr_p.raw
5354
socket.inet_pton = inet_pton
5455

55-
_VERSION = '3.1.2'
56+
_VERSION = '3.2.0'
5657
_NO_IP = 'MISSING IP ADDRESS'
5758
_FIELD_NOT_SUPPORTED = 'NOT SUPPORTED'
5859
_INVALID_IP_ADDRESS = 'INVALID IP ADDRESS'
@@ -74,30 +75,33 @@ class IP2ProxyRecord:
7475
last_seen = _FIELD_NOT_SUPPORTED
7576
domain = _FIELD_NOT_SUPPORTED
7677
threat = _FIELD_NOT_SUPPORTED
78+
provider = _FIELD_NOT_SUPPORTED
7779

7880
def __str__(self):
7981
return str(self.__dict__)
8082

8183
def __repr__(self):
8284
return repr(self.__dict__)
8385

84-
_COUNTRY_POSITION = (0, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3)
85-
_REGION_POSITION = (0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4)
86-
_CITY_POSITION = (0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5)
87-
_ISP_POSITION = (0, 0, 0, 0, 6, 6, 6, 6, 6, 6, 6)
88-
_PROXYTYPE_POSITION = (0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2)
89-
_DOMAIN_POSITION = (0, 0, 0, 0, 0, 7, 7, 7, 7, 7, 7)
90-
_USAGETYPE_POSITION = (0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8)
91-
_ASN_POSITION = (0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9)
92-
_AS_POSITION = (0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 10)
93-
_LASTSEEN_POSITION = (0, 0, 0, 0, 0, 0, 0, 0, 11, 11, 11)
94-
_THREAT_POSITION = (0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 12)
86+
_COUNTRY_POSITION = (0, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3)
87+
_REGION_POSITION = (0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4)
88+
_CITY_POSITION = (0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5)
89+
_ISP_POSITION = (0, 0, 0, 0, 6, 6, 6, 6, 6, 6, 6, 6)
90+
_PROXYTYPE_POSITION = (0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2)
91+
_DOMAIN_POSITION = (0, 0, 0, 0, 0, 7, 7, 7, 7, 7, 7, 7)
92+
_USAGETYPE_POSITION = (0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8)
93+
_ASN_POSITION = (0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9)
94+
_AS_POSITION = (0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 10, 10)
95+
_LASTSEEN_POSITION = (0, 0, 0, 0, 0, 0, 0, 0, 11, 11, 11, 11)
96+
_THREAT_POSITION = (0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 12, 12)
97+
_PROVIDER_POSITION = (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13)
9598

9699
class IP2Proxy(object):
97100
''' IP2Proxy database '''
98101

99102
def __init__(self, filename=None):
100103
''' Creates a database object and opens a file if filename is given '''
104+
101105
if filename:
102106
self.open(filename)
103107

@@ -113,6 +117,10 @@ def open(self, filename):
113117
''' Opens a database file '''
114118
# Ensure old file is closed before opening a new one
115119
self.close()
120+
121+
# if filename is not None:
122+
if os.path.isfile(filename) == False:
123+
raise ValueError("The database file does not seem to exist.")
116124

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

130146
def close(self):
131147
if hasattr(self, '_f'):
@@ -269,10 +285,17 @@ def get_threat(self, ip):
269285
threat = _INVALID_IP_ADDRESS
270286
return threat
271287

288+
def get_provider(self, ip):
289+
''' Get provider'''
290+
try:
291+
rec = self._get_record(ip)
292+
provider = rec.provider
293+
except:
294+
provider = _INVALID_IP_ADDRESS
295+
return provider
296+
272297
def get_all(self, ip):
273298
''' Get the whole record with all fields read from the file '''
274-
# if self._validate_addr(ip) == False:
275-
# return ipv, ipnum
276299
try:
277300
rec = self._get_record(ip)
278301
country_short = rec.country_short
@@ -287,6 +310,7 @@ def get_all(self, ip):
287310
as_name = rec.as_name
288311
last_seen = rec.last_seen
289312
threat = rec.threat
313+
provider = rec.provider
290314

291315
# if self._dbtype == 1:
292316
# is_proxy = 0 if (rec.country_short == '-') else ( 2 if ((rec.proxy_type == 'DCH') | (rec.proxy_type == 'SES')) else 1)
@@ -301,7 +325,7 @@ def get_all(self, ip):
301325
is_proxy = -1
302326
except:
303327
# except Exception as ex:
304-
print(ex)
328+
# print(ex)
305329
country_short = _INVALID_IP_ADDRESS
306330
country_long = _INVALID_IP_ADDRESS
307331
region = _INVALID_IP_ADDRESS
@@ -315,6 +339,7 @@ def get_all(self, ip):
315339
as_name = _INVALID_IP_ADDRESS
316340
last_seen = _INVALID_IP_ADDRESS
317341
threat = _INVALID_IP_ADDRESS
342+
provider = _INVALID_IP_ADDRESS
318343

319344
results = {}
320345
results['is_proxy'] = is_proxy
@@ -330,6 +355,7 @@ def get_all(self, ip):
330355
results['as_name'] = as_name
331356
results['last_seen'] = last_seen
332357
results['threat'] = threat
358+
results['provider'] = provider
333359
return results
334360

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

457+
if _PROVIDER_POSITION[self._dbtype] != 0:
458+
rec.provider = self._reads(self._readi(calc_off(_PROVIDER_POSITION, mid)) + 1)
459+
elif _PROVIDER_POSITION[self._dbtype] == 0:
460+
rec.provider = _FIELD_NOT_SUPPORTED
461+
431462
return rec
432463

433464
def __iter__(self):
@@ -493,12 +524,30 @@ def _parse_addr(self, addr):
493524
# socket.inet_pton(socket.AF_INET, addr)
494525
ipv = 4
495526
return ipv, ipnum
496-
527+
497528
def _get_record(self, ip):
498529
low = 0
499530
ipv = self._parse_addr(ip)[0]
500-
ipnum = self._parse_addr(ip)[1]
501-
if ipv == 4:
531+
ipnum = self._parse_addr(ip)[1]
532+
print (ipv)
533+
print (ipnum)
534+
if (ipv == 0):
535+
rec = IP2ProxyRecord()
536+
rec.country_short = _INVALID_IP_ADDRESS
537+
rec.country_long = _INVALID_IP_ADDRESS
538+
rec.region = _INVALID_IP_ADDRESS
539+
rec.city = _INVALID_IP_ADDRESS
540+
rec.isp = _INVALID_IP_ADDRESS
541+
rec.proxy_type = _INVALID_IP_ADDRESS
542+
rec.domain = _INVALID_IP_ADDRESS
543+
rec.usage_type = _INVALID_IP_ADDRESS
544+
rec.asn = _INVALID_IP_ADDRESS
545+
rec.as_name = _INVALID_IP_ADDRESS
546+
rec.last_seen = _INVALID_IP_ADDRESS
547+
rec.threat = _INVALID_IP_ADDRESS
548+
rec.provider = _INVALID_IP_ADDRESS
549+
return rec
550+
elif ipv == 4:
502551
# ipnum = struct.unpack('!L', socket.inet_pton(socket.AF_INET, ip))[0]
503552
if (ipnum == MAX_IPV4_RANGE):
504553
ipno = ipnum - 1
@@ -541,6 +590,8 @@ def _get_record(self, ip):
541590
rec.asn = _NO_IP
542591
rec.as_name = _NO_IP
543592
rec.last_seen = _NO_IP
593+
rec.threat = _NO_IP
594+
rec.provider = _NO_IP
544595
return rec
545596
else:
546597
rec = IP2ProxyRecord()
@@ -555,6 +606,8 @@ def _get_record(self, ip):
555606
rec.asn = _INVALID_IP_ADDRESS
556607
rec.as_name = _INVALID_IP_ADDRESS
557608
rec.last_seen = _INVALID_IP_ADDRESS
609+
rec.threat = _INVALID_IP_ADDRESS
610+
rec.provider = _INVALID_IP_ADDRESS
558611
return rec
559612

560613
while low <= high:

PKG-INFO

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
Metadata-Version: 1.0
22
Name: IP2Proxy
3-
Version: 3.1.2
3+
Version: 3.2.0
44
Summary: Python API for IP2Proxy database
55
Home-page: http://www.ip2location.com
66
Author: IP2Location

README.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ Below are the methods supported in this library.
1616
|---|---|
1717
|open|Open the IP2Proxy BIN data with **File I/O** mode for lookup.|
1818
|close|Close and clean up the file pointer.|
19-
|get_package_version|Get the package version (1 to 10 for PX1 to PX10 respectively).|
19+
|get_package_version|Get the package version (1 to 11 for PX1 to PX11 respectively).|
2020
|get_module_version|Get the module version.|
2121
|get_database_version|Get the database version.|
2222
|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>|
@@ -33,6 +33,7 @@ Below are the methods supported in this library.
3333
|get_as_name|Return the autonomous system (AS) name of proxy's IP address or domain name.|
3434
|get_last_seen|Return the last seen days ago value of proxy's IP address or domain name.|
3535
|get_threat|Return the threat types reported to proxy's IP address or domain name.|
36+
|get_provider|Returns the VPN service provider name if available.|
3637

3738
## Requirements
3839
1. Python 2.2 and above
@@ -77,6 +78,7 @@ print ('ASN: ' + db.get_asn("4.0.0.47"))
7778
print ('AS Name: ' + db.get_as_name("4.0.0.47"))
7879
print ('Last Seen: ' + db.get_last_seen("4.0.0.47"))
7980
print ('Threat: ' + db.get_threat("4.0.0.47"))
81+
print ('Provider: ' + db.get_provider("4.0.0.47"))
8082

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

98101
# close IP2Proxy BIN database
99102
db.close()

example.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import IP2Proxy
1+
import IP2Proxy, os
22

33
db = IP2Proxy.IP2Proxy()
44

@@ -24,6 +24,7 @@
2424
print ('AS Name: ' + db.get_as_name("4.0.0.47"))
2525
print ('Last Seen: ' + db.get_last_seen("4.0.0.47"))
2626
print ('Threat: ' + db.get_threat("4.0.0.47"))
27+
print ('Provider: ' + db.get_provider("4.0.0.47"))
2728

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

4547
# close IP2Proxy BIN database
4648
db.close()

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
setuptools.setup(
77
name="IP2Proxy",
8-
version="3.1.2",
8+
version="3.2.0",
99
author="IP2Location",
1010
author_email="support@ip2location.com",
1111
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.",

0 commit comments

Comments
 (0)