Skip to content

Commit 61d11d7

Browse files
Added iptools class and the related tests.
1 parent 2909e1f commit 61d11d7

6 files changed

Lines changed: 146 additions & 8 deletions

File tree

ChangeLog

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
8.7.0 2022-03-16
2+
* Added iptools class and the related tests.
3+
14
8.6.4 2021-11-09
25
* Removed debug line.
36

IP2Location.py

Lines changed: 105 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44
import re
55
import json
66
import os
7-
# import ipaddress
7+
import ipaddress
8+
import binascii
89
from re import match
910

1011
MAX_IPV4_RANGE = 4294967295
@@ -95,6 +96,10 @@ def inet_pton(t, addr):
9596
socket.inet_pton = inet_pton
9697

9798
def is_ipv4(hostname):
99+
ip_parts = hostname.split('.')
100+
for i in range(0,len(ip_parts)):
101+
if int(ip_parts[i]) > 255:
102+
return False
98103
pattern = r'^([0-9]{1,3}[.]){3}[0-9]{1,3}$'
99104
if match(pattern, hostname) is not None:
100105
return 4
@@ -650,7 +655,8 @@ def lookup(self,ip,addons=[],language='en'):
650655
response = httprequest(parameters, self.usessl)
651656
if (response == None):
652657
return False
653-
if ('response' in response):
658+
# if ('response' in response):
659+
if (('response' in response) and (response['response'] != 'OK')):
654660
raise IP2LocationAPIError(response['response'])
655661
return response
656662

@@ -665,4 +671,100 @@ def getcredit(self):
665671
return response['response']
666672

667673
class IP2LocationAPIError(Exception):
668-
"""Raise for IP2Location API Error Message"""
674+
"""Raise for IP2Location API Error Message"""
675+
676+
class AddressValueError(ValueError):
677+
"""A Value Error related to the address."""
678+
679+
class IP2LocationIPTools(object):
680+
681+
def is_ipv4(self, ip):
682+
ip_parts = ip.split('.')
683+
for i in range(0,len(ip_parts)):
684+
if int(ip_parts[i]) > 255:
685+
return False
686+
pattern = r'^([0-9]{1,3}[.]){3}[0-9]{1,3}$'
687+
if match(pattern, ip) is not None:
688+
return True
689+
return False
690+
691+
def is_ipv6(self, ip):
692+
try:
693+
socket.inet_pton(socket.AF_INET6, ip)
694+
except socket.error: # not a valid address
695+
return False
696+
return True
697+
698+
def ipv4_to_decimal(self, ip):
699+
try:
700+
ipnum = struct.unpack('!L', socket.inet_pton(socket.AF_INET, ip))[0]
701+
except (socket.error, OSError, ValueError):
702+
# ipnum = -1
703+
return
704+
return ipnum
705+
706+
def decimal_to_ipv4(self, decimal):
707+
if (int(decimal) > 4294967295):
708+
return
709+
else:
710+
return (socket.inet_ntoa(struct.pack('!I', int(decimal))))
711+
712+
def ipv6_to_decimal(self, ip):
713+
return(int(ipaddress.ip_address(u(ip))))
714+
715+
def decimal_to_ipv6(self, decimal):
716+
result = ipaddress.IPv6Address(int(decimal))
717+
if (result.ipv4_mapped != None):
718+
return('::ffff:' + str(result.ipv4_mapped))
719+
else:
720+
return str(result)
721+
722+
def ipv4_to_cidr(self, from_ip, to_ip):
723+
startip = ipaddress.IPv4Address(u(from_ip))
724+
endip = ipaddress.IPv4Address(u(to_ip))
725+
ar = [ipaddr for ipaddr in ipaddress.summarize_address_range(startip, endip)]
726+
ar1 = []
727+
for i in range(len(ar)):
728+
ar1.append(str(ar[i]))
729+
return (ar1)
730+
731+
def ipv6_to_cidr(self, from_ip, to_ip):
732+
startip = ipaddress.IPv6Address(u(from_ip))
733+
endip = ipaddress.IPv6Address(u(to_ip))
734+
ar = [ipaddr for ipaddr in ipaddress.summarize_address_range(startip, endip)]
735+
ar1 = []
736+
for i in range(len(ar)):
737+
ar1.append(str(ar[i]))
738+
return (ar1)
739+
740+
def cidr_to_ipv4(self, cidr):
741+
net=ipaddress.ip_network(u(cidr))
742+
return({"ip_start": str(net[0]), "ip_end": str(net[-1])})
743+
744+
def cidr_to_ipv6(self, cidr):
745+
parts = cidr.split('/')
746+
hexstartaddress = binascii.hexlify(socket.inet_pton(socket.AF_INET6, parts[0]))
747+
if (len(hexstartaddress) < 16):
748+
hexstartaddress = hexstartaddress.zfill(16-hexstartaddress.len())
749+
bits = 128 - int(parts[1])
750+
hexlastaddress = hexstartaddress
751+
pos = 31
752+
while (bits > 0):
753+
int_value = int(hexlastaddress[pos:pos+1], 16)
754+
# new = binascii.hexlify((int_value | (pow(2, min(4, bits)) - 1)).to_bytes(1, 'big'))
755+
new = binascii.hexlify((int_value | (pow(2, min(4, bits)) - 1)).to_bytes(1, 'little'))[1:]
756+
hexlastaddresslist = list(u(hexlastaddress))
757+
hexlastaddresslist[pos] = u(new)
758+
string_hexlastaddresslist = [str(int) for int in hexlastaddresslist]
759+
hexlastaddress = ''.join(string_hexlastaddresslist)
760+
bits = bits - 4
761+
pos = pos - 1
762+
binlastaddress = binascii.unhexlify(b(hexlastaddress))
763+
return({"ip_start": self.expand_ipv6(parts[0]), "ip_end": self.expand_ipv6(socket.inet_ntop(socket.AF_INET6, binlastaddress))})
764+
765+
def compressed_ipv6(self, ip):
766+
return ((ipaddress.IPv6Address(u(ip)).compressed))
767+
768+
def expand_ipv6(self, ip):
769+
return ((ipaddress.IPv6Address(u(ip)).exploded))
770+

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: IP2Location
3-
Version: 8.6.4
3+
Version: 8.7.0
44
Summary: Python API for IP2Location database
55
Home-page: http://www.ip2location.com
66
Author: IP2Location

README.md

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# IP2Location 8.6.4
1+
# IP2Location 8.7.0
22

33

44
This is a IP2Location Python library that enables the user to find the country, region or state, city, latitude and longitude, ZIP code, time zone, Internet Service Provider (ISP) or company name, domain name, net speed, area code, weather station code, weather station name, mobile country code (MCC), mobile network code (MNC) and carrier brand, elevation, usage type, address type and IAB category by IP address or hostname originates from. The library reads the geo location information from **IP2Location BIN data** file.
@@ -10,7 +10,8 @@ For more details, please visit:
1010

1111
# Requirements
1212

13-
1. Python 2.2 and above
13+
1. Python 2.2 and above for version below than 8.7.0.
14+
2. Python 3.4 and above for version 8.7.0 and above.
1415

1516
# Installation
1617

@@ -72,6 +73,25 @@ Below is the description of the functions available in the **Web Service** looku
7273
| lookup | Return the IP information in array. <ul><li>country_code</li><li>country_name</li><li>region_name</li><li>city_name</li><li>latitude</li><li>longitude</li><li>zip_code</li><li>time_zone</li><li>isp</li><li>domain</li><li>net_speed</li><li>idd_code</li><li>area_code</li><li>weather_station_code</li><li>weather_station_name</li><li>mcc</li><li>mnc</li><li>mobile_brand</li><li>elevation</li><li>usage_type</li><li>address_type</li><li>category</li><li>category_name</li><li>continent<ul><li>name</li><li>code</li><li>hemisphere</li><li>translations</li></ul></li><li>country<ul><li>name</li><li>alpha3_code</li><li>numeric_code</li><li>demonym</li><li>flag</li><li>capital</li><li>total_area</li><li>population</li><li>currency<ul><li>code</li><li>name</li><li>symbol</li></ul></li><li>language<ul><li>code</li><li>name</li></ul></li><li>idd_code</li><li>tld</li><li>translations</li></ul></li><li>region<ul><li>name</li><li>code</li><li>translations</li></ul></li><li>city<ul><li>name</li><li>translations</li></ul></li><li>geotargeting<ul><li>metro</li></ul></li><li>country_groupings</li><li>time_zone_info<ul><li>olson</li><li>current_time</li><li>gmt_offset</li><li>is_dst</li><li>sunrise</li><li>sunset</li></ul></li><ul> |
7374
| get_credit | Return remaining credit of the web service account. |
7475

76+
### IP Tools
77+
78+
Below is the description of the functions available in the **IP Tools** class.
79+
80+
| Function Name | Description |
81+
| --------------- | ------------------------------------------------------------ |
82+
| is_ipv4 | Return either **true** or **false**. Verify if a string is a valid IPv4 address. |
83+
| is_ipv6 | Return either **true** or **false**. Verify if a string is a valid IPv6 address. |
84+
| ipv4_to_decimal | Translate IPv4 address from dotted-decimal address to decimal format. |
85+
| decimal_to_ipv4 | Translate IPv4 address from decimal number to dotted-decimal address. |
86+
| ipv6_to_decimal | Translate IPv6 address from hexadecimal address to decimal format. |
87+
| decimal_to_ipv6 | Translate IPv6 address from decimal number into hexadecimal address. |
88+
| ipv4_to_cidr | Convert IPv4 range into a list of IPv4 CIDR notation. |
89+
| cidr_to_ipv4 | Convert IPv4 CIDR notation into a list of IPv4 addresses. |
90+
| ipv6_to_cidr | Convert IPv6 range into a list of IPv6 CIDR notation. |
91+
| cidr_to_ipv6 | Convert IPv6 CIDR notation into a list of IPv6 addresses. |
92+
| compressed_ipv6 | Compress a IPv6 to shorten the length. |
93+
| expand_ipv6 | Expand a shorten IPv6 to full length. |
94+
7595
# Testing
7696

7797
python sample.py

sample.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,3 +49,17 @@
4949
print ("\n")
5050
print ("Credit Remaining: {}\n".format(ws.getcredit()))
5151

52+
ipTools = IP2Location.IP2LocationIPTools()
53+
print(str(ipTools.is_ipv4('8.8.8.8')))
54+
print(str(ipTools.is_ipv6('2001:4860:4860::8888')))
55+
print(ipTools.ipv4_to_decimal('8.8.8.8'))
56+
print(ipTools.decimal_to_ipv4(134744072))
57+
print(ipTools.ipv6_to_decimal('2001:4860:4860::8888'))
58+
print(ipTools.decimal_to_ipv6(42541956123769884636017138956568135816))
59+
print(ipTools.ipv4_to_cidr('8.0.0.0', '8.255.255.255'))
60+
print(ipTools.cidr_to_ipv4('8.0.0.0/8'))
61+
print(ipTools.ipv6_to_cidr('2002:0000:0000:1234:abcd:ffff:c0a8:0000', '2002:0000:0000:1234:ffff:ffff:ffff:ffff'))
62+
print(ipTools.cidr_to_ipv6('2002::1234:abcd:ffff:c0a8:101/64'))
63+
print(ipTools.compressed_ipv6('2002:0000:0000:1234:FFFF:FFFF:FFFF:FFFF'))
64+
print(ipTools.expand_ipv6('2002::1234:FFFF:FFFF:FFFF:FFFF'))
65+

setup.py

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

66
setuptools.setup(
77
name="IP2Location",
8-
version="8.6.4",
8+
version="8.7.0",
99
author="IP2Location",
1010
author_email="support@ip2location.com",
1111
description="This is an IP geolocation library that enables the user to find the country, region, city, latitude and longitude, ZIP code, time zone, ISP, domain name, area code, weather info, mobile info, elevation, usage type, address type and IAB category from an IP address. It supports both IPv4 and IPv6 lookup.",
@@ -19,7 +19,6 @@
1919
"Development Status :: 5 - Production/Stable",
2020
"Intended Audience :: Developers",
2121
"Topic :: Software Development :: Libraries :: Python Modules",
22-
"Programming Language :: Python :: 2.7",
2322
"Programming Language :: Python :: 3",
2423
"License :: OSI Approved :: MIT License",
2524
"Operating System :: OS Independent",

0 commit comments

Comments
 (0)