1# Copyright (C) 2005-2016 IP2Location.com
2# All Rights Reserved
3#
4# This library is free software: you can redistribute it and/or
5# modify it under the terms of the GNU Lesser General Public
6# License as published by the Free Software Foundation, either
7# version 3 of the License, or (at your option) any later version.
8#
9# This library is distributed in the hope that it will be useful,
10# but WITHOUT ANY WARRANTY; without even the implied warranty of
11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12# Lesser General Public License for more details.
13#
14# You should have received a copy of the GNU Lesser General Public
15# License along with this library; If not, see <http://www.gnu.org/licenses/>.
16
17package Geo::IP2Location;
18
19use strict;
20use vars qw(@ISA $VERSION @EXPORT);
21use Math::BigInt;
22
23$VERSION = '8.03';
24
25require Exporter;
26@ISA = qw(Exporter);
27
28use constant UNKNOWN => "UNKNOWN IP ADDRESS";
29use constant IPV6_ADDRESS_IN_IPV4_BIN => "IPV6 ADDRESS MISSING IN IPV4 BIN";
30use constant NO_IP => "MISSING IP ADDRESS";
31use constant INVALID_IPV6_ADDRESS => "INVALID IPV6 ADDRESS";
32use constant INVALID_IPV4_ADDRESS => "INVALID IPV4 ADDRESS";
33use constant INVALID_IP_ADDRESS => "INVALID IP ADDRESS";
34use constant NOT_SUPPORTED => "This parameter is unavailable in selected .BIN data file. Please upgrade data file.";
35use constant MAX_IPV4_RANGE => 4294967295;
36use constant MAX_IPV6_RANGE => 340282366920938463463374607431768211455;
37use constant IP_COUNTRY => 1;
38use constant IP_COUNTRY_ISP => 2;
39use constant IP_COUNTRY_REGION_CITY => 3;
40use constant IP_COUNTRY_REGION_CITY_ISP => 4;
41use constant IP_COUNTRY_REGION_CITY_LATITUDE_LONGITUDE => 5;
42use constant IP_COUNTRY_REGION_CITY_LATITUDE_LONGITUDE_ISP => 6;
43use constant IP_COUNTRY_REGION_CITY_ISP_DOMAIN => 7;
44use constant IP_COUNTRY_REGION_CITY_LATITUDE_LONGITUDE_ISP_DOMAIN => 8;
45use constant IP_COUNTRY_REGION_CITY_LATITUDE_LONGITUDE_ZIPCODE => 9;
46use constant IP_COUNTRY_REGION_CITY_LATITUDE_LONGITUDE_ZIPCODE_ISP_DOMAIN => 10;
47use constant IP_COUNTRY_REGION_CITY_LATITUDE_LONGITUDE_ZIPCODE_TIMEZONE => 11;
48use constant IP_COUNTRY_REGION_CITY_LATITUDE_LONGITUDE_ZIPCODE_TIMEZONE_ISP_DOMAIN => 12;
49use constant IP_COUNTRY_REGION_CITY_LATITUDE_LONGITUDE_TIMEZONE_NETSPEED => 13;
50use constant IP_COUNTRY_REGION_CITY_LATITUDE_LONGITUDE_ZIPCODE_TIMEZONE_ISP_DOMAIN_NETSPEED => 14;
51use constant IP_COUNTRY_REGION_CITY_LATITUDE_LONGITUDE_ZIPCODE_TIMEZONE_AREACODE => 15;
52use constant IP_COUNTRY_REGION_CITY_LATITUDE_LONGITUDE_ZIPCODE_TIMEZONE_ISP_DOMAIN_NETSPEED_AREACODE => 16;
53use constant IP_COUNTRY_REGION_CITY_LATITUDE_LONGITUDE_TIMEZONE_NETSPEED_WEATHER => 17;
54use constant IP_COUNTRY_REGION_CITY_LATITUDE_LONGITUDE_ZIPCODE_TIMEZONE_ISP_DOMAIN_NETSPEED_AREACODE_WEATHER => 18;
55use constant IP_COUNTRY_REGION_CITY_LATITUDE_LONGITUDE_ISP_DOMAIN_MOBILE => 19;
56use constant IP_COUNTRY_REGION_CITY_LATITUDE_LONGITUDE_ZIPCODE_TIMEZONE_ISP_DOMAIN_NETSPEED_AREACODE_WEATHER_MOBILE => 20;
57use constant IP_COUNTRY_REGION_CITY_LATITUDE_LONGITUDE_ZIPCODE_TIMEZONE_AREACODE_ELEVATION => 21;
58use constant IP_COUNTRY_REGION_CITY_LATITUDE_LONGITUDE_ZIPCODE_TIMEZONE_ISP_DOMAIN_NETSPEED_AREACODE_WEATHER_MOBILE_ELEVATION => 22;
59use constant IP_COUNTRY_REGION_CITY_LATITUDE_LONGITUDE_ISP_DOMAIN_MOBILE_USAGETYPE => 23;
60use constant IP_COUNTRY_REGION_CITY_LATITUDE_LONGITUDE_ZIPCODE_TIMEZONE_ISP_DOMAIN_NETSPEED_AREACODE_WEATHER_MOBILE_ELEVATION_USAGETYPE => 24;
61
62use constant COUNTRYSHORT => 1;
63use constant COUNTRYLONG => 2;
64use constant REGION => 3;
65use constant CITY => 4;
66use constant ISP => 5;
67use constant LATITUDE => 6;
68use constant LONGITUDE => 7;
69use constant DOMAIN => 8;
70use constant ZIPCODE => 9;
71use constant TIMEZONE => 10;
72use constant NETSPEED => 11;
73use constant IDDCODE => 12;
74use constant AREACODE => 13;
75use constant WEATHERSTATIONCODE => 14;
76use constant WEATHERSTATIONNAME => 15;
77use constant MCC => 16;
78use constant MNC => 17;
79use constant MOBILEBRAND => 18;
80use constant ELEVATION => 19;
81use constant USAGETYPE => 20;
82
83use constant ALL => 100;
84use constant IPV4 => 0;
85use constant IPV6 => 1;
86
87my @COUNTRY_POSITION =             (0,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2);
88my @REGION_POSITION =              (0,  0,  0,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3);
89my @CITY_POSITION =                (0,  0,  0,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4);
90my @LATITUDE_POSITION =            (0,  0,  0,  0,  0,  5,  5,  0,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5);
91my @LONGITUDE_POSITION =           (0,  0,  0,  0,  0,  6,  6,  0,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6);
92my @ZIPCODE_POSITION =             (0,  0,  0,  0,  0,  0,  0,  0,  0,  7,  7,  7,  7,  0,  7,  7,  7,  0,  7,  0,  7,  7,  7,  0,  7);
93my @TIMEZONE_POSITION =            (0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  8,  8,  7,  8,  8,  8,  7,  8,  0,  8,  8,  8,  0,  8);
94my @ISP_POSITION =                 (0,  0,  3,  0,  5,  0,  7,  5,  7,  0,  8,  0,  9,  0,  9,  0,  9,  0,  9,  7,  9,  0,  9,  7,  9);
95my @DOMAIN_POSITION =              (0,  0,  0,  0,  0,  0,  0,  6,  8,  0,  9,  0, 10,  0, 10,  0, 10,  0, 10,  8, 10,  0, 10,  8, 10);
96my @NETSPEED_POSITION =            (0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  8, 11,  0, 11,  8, 11,  0, 11,  0, 11,  0, 11);
97my @IDDCODE_POSITION =             (0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  9, 12,  0, 12,  0, 12,  9, 12,  0, 12);
98my @AREACODE_POSITION =            (0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 10, 13,  0, 13,  0, 13, 10, 13,  0, 13);
99my @WEATHERSTATIONCODE_POSITION =  (0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  9, 14,  0, 14,  0, 14,  0, 14);
100my @WEATHERSTATIONNAME_POSITION =  (0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 10, 15,  0, 15,  0, 15,  0, 15);
101my @MCC_POSITION =                 (0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  9, 16,  0, 16,  9, 16);
102my @MNC_POSITION =                 (0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 10, 17,  0, 17, 10, 17);
103my @MOBILEBRAND_POSITION =         (0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 11, 18,  0, 18, 11, 18);
104my @ELEVATION_POSITION =           (0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 11, 19,  0, 19);
105my @USAGETYPE_POSITION =           (0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 12, 20);
106
107my @IPV6_COUNTRY_POSITION =             (0,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2);
108my @IPV6_REGION_POSITION =              (0,  0,  0,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3);
109my @IPV6_CITY_POSITION =                (0,  0,  0,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4);
110my @IPV6_LATITUDE_POSITION =            (0,  0,  0,  0,  0,  5,  5,  0,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5);
111my @IPV6_LONGITUDE_POSITION =           (0,  0,  0,  0,  0,  6,  6,  0,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6);
112my @IPV6_ZIPCODE_POSITION =             (0,  0,  0,  0,  0,  0,  0,  0,  0,  7,  7,  7,  7,  0,  7,  7,  7,  0,  7,  0,  7,  7,  7,  0,  7);
113my @IPV6_TIMEZONE_POSITION =            (0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  8,  8,  7,  8,  8,  8,  7,  8,  0,  8,  8,  8,  0,  8);
114my @IPV6_ISP_POSITION =                 (0,  0,  3,  0,  5,  0,  7,  5,  7,  0,  8,  0,  9,  0,  9,  0,  9,  0,  9,  7,  9,  0,  9,  7,  9);
115my @IPV6_DOMAIN_POSITION =              (0,  0,  0,  0,  0,  0,  0,  6,  8,  0,  9,  0, 10,  0, 10,  0, 10,  0, 10,  8, 10,  0, 10,  8, 10);
116my @IPV6_NETSPEED_POSITION =            (0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  8, 11,  0, 11,  8, 11,  0, 11,  0, 11,  0, 11);
117my @IPV6_IDDCODE_POSITION =             (0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  9, 12,  0, 12,  0, 12,  9, 12,  0, 12);
118my @IPV6_AREACODE_POSITION =            (0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 10, 13,  0, 13,  0, 13, 10, 13,  0, 13);
119my @IPV6_WEATHERSTATIONCODE_POSITION =  (0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  9, 14,  0, 14,  0, 14,  0, 14);
120my @IPV6_WEATHERSTATIONNAME_POSITION =  (0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 10, 15,  0, 15,  0, 15,  0, 15);
121my @IPV6_MCC_POSITION =                 (0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  9, 16,  0, 16,  9, 16);
122my @IPV6_MNC_POSITION =                 (0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 10, 17,  0, 17, 10, 17);
123my @IPV6_MOBILEBRAND_POSITION =         (0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 11, 18,  0, 18, 11, 18);
124my @IPV6_ELEVATION_POSITION =           (0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 11, 19,  0, 19);
125my @IPV6_USAGETYPE_POSITION =           (0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 12, 20);
126
127my $IPv6_re = qr/:(?::[0-9a-fA-F]{1,4}){0,5}(?:(?::[0-9a-fA-F]{1,4}){1,2}|:(?:(?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})[.](?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})[.](?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})[.](?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})))|[0-9a-fA-F]{1,4}:(?:[0-9a-fA-F]{1,4}:(?:[0-9a-fA-F]{1,4}:(?:[0-9a-fA-F]{1,4}:(?:[0-9a-fA-F]{1,4}:(?:[0-9a-fA-F]{1,4}:(?:[0-9a-fA-F]{1,4}:(?:[0-9a-fA-F]{1,4}|:)|(?::(?:[0-9a-fA-F]{1,4})?|(?:(?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})[.](?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})[.](?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})[.](?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2}))))|:(?:(?:(?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})[.](?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})[.](?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})[.](?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2}))|[0-9a-fA-F]{1,4}(?::[0-9a-fA-F]{1,4})?|))|(?::(?:(?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})[.](?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})[.](?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})[.](?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2}))|:[0-9a-fA-F]{1,4}(?::(?:(?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})[.](?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})[.](?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})[.](?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2}))|(?::[0-9a-fA-F]{1,4}){0,2})|:))|(?:(?::[0-9a-fA-F]{1,4}){0,2}(?::(?:(?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})[.](?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})[.](?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})[.](?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2}))|(?::[0-9a-fA-F]{1,4}){1,2})|:))|(?:(?::[0-9a-fA-F]{1,4}){0,3}(?::(?:(?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})[.](?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})[.](?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})[.](?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2}))|(?::[0-9a-fA-F]{1,4}){1,2})|:))|(?:(?::[0-9a-fA-F]{1,4}){0,4}(?::(?:(?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})[.](?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})[.](?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})[.](?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2}))|(?::[0-9a-fA-F]{1,4}){1,2})|:))/;
128my $IPv4_re = qr/\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/;
129
130sub open {
131  die "Geo::IP2Location::open() requires a database path name" unless( (@_ > 1) && ($_[1]) );
132  my ($class, $db_file) = @_;
133  my $handle;
134  my $obj;
135  CORE::open $handle, "$db_file" or die "Geo::IP2Location::open() error opening $db_file";
136	binmode($handle);
137	$obj = bless {filehandle => $handle}, $class;
138	$obj->initialize();
139	return $obj;
140}
141
142sub initialize {
143	my ($obj) = @_;
144	$obj->{"databasetype"} = $obj->read8($obj->{filehandle}, 1);
145	$obj->{"databasecolumn"} = $obj->read8($obj->{filehandle}, 2);
146	$obj->{"databaseyear"} = $obj->read8($obj->{filehandle}, 3);
147	$obj->{"databasemonth"} = $obj->read8($obj->{filehandle}, 4);
148	$obj->{"databaseday"} = $obj->read8($obj->{filehandle}, 5);
149	$obj->{"ipv4databasecount"} = $obj->read32($obj->{filehandle}, 6);
150	$obj->{"ipv4databaseaddr"} = $obj->read32($obj->{filehandle}, 10);
151	$obj->{"ipv6databasecount"} = $obj->read32($obj->{filehandle}, 14);
152	$obj->{"ipv6databaseaddr"} = $obj->read32($obj->{filehandle}, 18);
153	$obj->{"ipv4indexbaseaddr"} = $obj->read32($obj->{filehandle}, 22);
154	$obj->{"ipv6indexbaseaddr"} = $obj->read32($obj->{filehandle}, 26);
155	return $obj;
156}
157
158sub get_module_version {
159	my $obj = shift(@_);
160	return $VERSION;
161}
162
163sub get_database_version {
164	my $obj = shift(@_);
165	return $obj->{"databaseyear"} . "." . $obj->{"databasemonth"} . "." . $obj->{"databaseday"};
166}
167
168sub get_country_short {
169	my $obj = shift(@_);
170	my $ipaddr = shift(@_);
171	my ($ipv, $ipnum) = $obj->validate_ip($ipaddr);
172	if ($ipv == 4) {
173		return $obj->get_record($ipnum, COUNTRYSHORT);
174	} else {
175		if ($ipv == 6) {
176			return $obj->get_ipv6_record($ipnum, COUNTRYSHORT);
177		} else {
178			return INVALID_IP_ADDRESS;
179		}
180	}
181}
182
183sub get_country_long {
184	my $obj = shift(@_);
185	my $ipaddr = shift(@_);
186	my ($ipv, $ipnum) = $obj->validate_ip($ipaddr);
187	if ($ipv == 4) {
188		return $obj->get_record($ipnum, COUNTRYLONG);
189	} else {
190		if ($ipv == 6) {
191			return $obj->get_ipv6_record($ipnum, COUNTRYLONG);
192		} else {
193			return INVALID_IP_ADDRESS;
194		}
195	}
196}
197
198sub get_region {
199	my $obj = shift(@_);
200	my $ipaddr = shift(@_);
201	my ($ipv, $ipnum) = $obj->validate_ip($ipaddr);
202	if ($ipv == 4) {
203		return $obj->get_record($ipnum, REGION);
204	} else {
205		if ($ipv == 6) {
206			return $obj->get_ipv6_record($ipnum, REGION);
207		} else {
208			return INVALID_IP_ADDRESS;
209		}
210	}
211}
212
213sub get_city {
214	my $obj = shift(@_);
215	my $ipaddr = shift(@_);
216	my ($ipv, $ipnum) = $obj->validate_ip($ipaddr);
217	if ($ipv == 4) {
218		return $obj->get_record($ipnum, CITY);
219	} else {
220		if ($ipv == 6) {
221			return $obj->get_ipv6_record($ipnum, CITY);
222		} else {
223			return INVALID_IP_ADDRESS;
224		}
225	}
226}
227
228sub get_isp {
229	my $obj = shift(@_);
230	my $ipaddr = shift(@_);
231	my ($ipv, $ipnum) = $obj->validate_ip($ipaddr);
232	if ($ipv == 4) {
233		return $obj->get_record($ipnum, ISP);
234	} else {
235		if ($ipv == 6) {
236			return $obj->get_ipv6_record($ipnum, ISP);
237		} else {
238			return INVALID_IP_ADDRESS;
239		}
240	}
241}
242
243sub get_latitude {
244	my $obj = shift(@_);
245	my $ipaddr = shift(@_);
246	my ($ipv, $ipnum) = $obj->validate_ip($ipaddr);
247	if ($ipv == 4) {
248		return $obj->get_record($ipnum, LATITUDE);
249	} else {
250		if ($ipv == 6) {
251			return $obj->get_ipv6_record($ipnum, LATITUDE);
252		} else {
253			return INVALID_IP_ADDRESS;
254		}
255	}
256}
257
258sub get_zipcode {
259	my $obj = shift(@_);
260	my $ipaddr = shift(@_);
261	my ($ipv, $ipnum) = $obj->validate_ip($ipaddr);
262	if ($ipv == 4) {
263		return $obj->get_record($ipnum, ZIPCODE);
264	} else {
265		if ($ipv == 6) {
266			return $obj->get_ipv6_record($ipnum, ZIPCODE);
267		} else {
268			return INVALID_IP_ADDRESS;
269		}
270	}
271}
272
273sub get_longitude {
274	my $obj = shift(@_);
275	my $ipaddr = shift(@_);
276	my ($ipv, $ipnum) = $obj->validate_ip($ipaddr);
277	if ($ipv == 4) {
278		return $obj->get_record($ipnum, LONGITUDE);
279	} else {
280		if ($ipv == 6) {
281			return $obj->get_ipv6_record($ipnum, LONGITUDE);
282		} else {
283			return INVALID_IP_ADDRESS;
284		}
285	}
286}
287
288sub get_domain {
289	my $obj = shift(@_);
290	my $ipaddr = shift(@_);
291	my ($ipv, $ipnum) = $obj->validate_ip($ipaddr);
292	if ($ipv == 4) {
293		return $obj->get_record($ipnum, DOMAIN);
294	} else {
295		if ($ipv == 6) {
296			return $obj->get_ipv6_record($ipnum, DOMAIN);
297		} else {
298			return INVALID_IP_ADDRESS;
299		}
300	}
301}
302
303sub get_timezone {
304	my $obj = shift(@_);
305	my $ipaddr = shift(@_);
306	my ($ipv, $ipnum) = $obj->validate_ip($ipaddr);
307	if ($ipv == 4) {
308		return $obj->get_record($ipnum, TIMEZONE);
309	} else {
310		if ($ipv == 6) {
311			return $obj->get_ipv6_record($ipnum, TIMEZONE);
312		} else {
313			return INVALID_IP_ADDRESS;
314		}
315	}
316}
317
318sub get_netspeed {
319	my $obj = shift(@_);
320	my $ipaddr = shift(@_);
321	my ($ipv, $ipnum) = $obj->validate_ip($ipaddr);
322	if ($ipv == 4) {
323		return $obj->get_record($ipnum, NETSPEED);
324	} else {
325		if ($ipv == 6) {
326			return $obj->get_ipv6_record($ipnum, NETSPEED);
327		} else {
328			return INVALID_IP_ADDRESS;
329		}
330	}
331}
332
333sub get_iddcode {
334	my $obj = shift(@_);
335	my $ipaddr = shift(@_);
336	my ($ipv, $ipnum) = $obj->validate_ip($ipaddr);
337	if ($ipv == 4) {
338		return $obj->get_record($ipnum, IDDCODE);
339	} else {
340		if ($ipv == 6) {
341			return $obj->get_ipv6_record($ipnum, IDDCODE);
342		} else {
343			return INVALID_IP_ADDRESS;
344		}
345	}
346}
347
348sub get_areacode {
349	my $obj = shift(@_);
350	my $ipaddr = shift(@_);
351	my ($ipv, $ipnum) = $obj->validate_ip($ipaddr);
352	if ($ipv == 4) {
353		return $obj->get_record($ipnum, AREACODE);
354	} else {
355		if ($ipv == 6) {
356			return $obj->get_ipv6_record($ipnum, AREACODE);
357		} else {
358			return INVALID_IP_ADDRESS;
359		}
360	}
361}
362
363sub get_weatherstationcode {
364	my $obj = shift(@_);
365	my $ipaddr = shift(@_);
366	my ($ipv, $ipnum) = $obj->validate_ip($ipaddr);
367	if ($ipv == 4) {
368		return $obj->get_record($ipnum, WEATHERSTATIONCODE);
369	} else {
370		if ($ipv == 6) {
371			return $obj->get_ipv6_record($ipnum, WEATHERSTATIONCODE);
372		} else {
373			return INVALID_IP_ADDRESS;
374		}
375	}
376}
377
378sub get_weatherstationname {
379	my $obj = shift(@_);
380	my $ipaddr = shift(@_);
381	my ($ipv, $ipnum) = $obj->validate_ip($ipaddr);
382	if ($ipv == 4) {
383		return $obj->get_record($ipnum, WEATHERSTATIONNAME);
384	} else {
385		if ($ipv == 6) {
386			return $obj->get_ipv6_record($ipnum, WEATHERSTATIONNAME);
387		} else {
388			return INVALID_IP_ADDRESS;
389		}
390	}
391}
392
393sub get_mcc {
394	my $obj = shift(@_);
395	my $ipaddr = shift(@_);
396	my ($ipv, $ipnum) = $obj->validate_ip($ipaddr);
397	if ($ipv == 4) {
398		return $obj->get_record($ipnum, MCC);
399	} else {
400		if ($ipv == 6) {
401			return $obj->get_ipv6_record($ipnum, MCC);
402		} else {
403			return INVALID_IP_ADDRESS;
404		}
405	}
406}
407
408sub get_mnc {
409	my $obj = shift(@_);
410	my $ipaddr = shift(@_);
411	my ($ipv, $ipnum) = $obj->validate_ip($ipaddr);
412	if ($ipv == 4) {
413		return $obj->get_record($ipnum, MNC);
414	} else {
415		if ($ipv == 6) {
416			return $obj->get_ipv6_record($ipnum, MNC);
417		} else {
418			return INVALID_IP_ADDRESS;
419		}
420	}
421}
422
423sub get_mobilebrand {
424	my $obj = shift(@_);
425	my $ipaddr = shift(@_);
426	my ($ipv, $ipnum) = $obj->validate_ip($ipaddr);
427	if ($ipv == 4) {
428		return $obj->get_record($ipnum, MOBILEBRAND);
429	} else {
430		if ($ipv == 6) {
431			return $obj->get_ipv6_record($ipnum, MOBILEBRAND);
432		} else {
433			return INVALID_IP_ADDRESS;
434		}
435	}
436}
437
438sub get_elevation {
439	my $obj = shift(@_);
440	my $ipaddr = shift(@_);
441	my ($ipv, $ipnum) = $obj->validate_ip($ipaddr);
442	if ($ipv == 4) {
443		return $obj->get_record($ipnum, ELEVATION);
444	} else {
445		if ($ipv == 6) {
446			return $obj->get_ipv6_record($ipnum, ELEVATION);
447		} else {
448			return INVALID_IP_ADDRESS;
449		}
450	}
451}
452
453sub get_usagetype {
454	my $obj = shift(@_);
455	my $ipaddr = shift(@_);
456	my ($ipv, $ipnum) = $obj->validate_ip($ipaddr);
457	if ($ipv == 4) {
458		return $obj->get_record($ipnum, USAGETYPE);
459	} else {
460		if ($ipv == 6) {
461			return $obj->get_ipv6_record($ipnum, USAGETYPE);
462		} else {
463			return INVALID_IP_ADDRESS;
464		}
465	}
466}
467
468sub get_all {
469	my $obj = shift(@_);
470	my $ipaddr = shift(@_);
471	my ($ipv, $ipnum) = $obj->validate_ip($ipaddr);
472	if ($ipv == 4) {
473		return $obj->get_record($ipnum, ALL);
474	} else {
475		if ($ipv == 6) {
476			return $obj->get_ipv6_record($ipnum, ALL);
477		} else {
478			return (INVALID_IP_ADDRESS, INVALID_IP_ADDRESS, INVALID_IP_ADDRESS, INVALID_IP_ADDRESS, INVALID_IP_ADDRESS, INVALID_IP_ADDRESS, INVALID_IP_ADDRESS, INVALID_IP_ADDRESS, INVALID_IP_ADDRESS, INVALID_IP_ADDRESS, INVALID_IP_ADDRESS, INVALID_IP_ADDRESS, INVALID_IP_ADDRESS, INVALID_IP_ADDRESS, INVALID_IP_ADDRESS, INVALID_IP_ADDRESS, INVALID_IP_ADDRESS, INVALID_IP_ADDRESS, INVALID_IP_ADDRESS, INVALID_IP_ADDRESS);
479		}
480	}
481}
482
483sub get_ipv6_record {
484	my $obj = shift(@_);
485	my $ipnum = shift(@_);
486	my $mode = shift(@_);
487	my $dbtype = $obj->{"databasetype"};
488
489	if ($ipnum eq "") {
490		if ($mode == ALL) {
491			return (NO_IP, NO_IP, NO_IP, NO_IP, NO_IP, NO_IP, NO_IP, NO_IP, NO_IP, NO_IP, NO_IP, NO_IP, NO_IP, NO_IP, NO_IP, NO_IP, NO_IP, NO_IP, NO_IP, NO_IP);
492		} else {
493			return NO_IP;
494		}
495	}
496
497	if (($mode == COUNTRYSHORT) && ($IPV6_COUNTRY_POSITION[$dbtype] == 0)) {
498		return NOT_SUPPORTED;
499	}
500	if (($mode == COUNTRYLONG) && ($IPV6_COUNTRY_POSITION[$dbtype] == 0)) {
501		return NOT_SUPPORTED;
502	}
503	if (($mode == REGION) && ($IPV6_REGION_POSITION[$dbtype] == 0)) {
504		return NOT_SUPPORTED;
505	}
506	if (($mode == CITY) && ($IPV6_CITY_POSITION[$dbtype] == 0)) {
507		return NOT_SUPPORTED;
508	}
509	if (($mode == ISP) && ($IPV6_ISP_POSITION[$dbtype] == 0)) {
510		return NOT_SUPPORTED;
511	}
512	if (($mode == LATITUDE) && ($IPV6_LATITUDE_POSITION[$dbtype] == 0)) {
513		return NOT_SUPPORTED;
514	}
515	if (($mode == LONGITUDE) && ($IPV6_LONGITUDE_POSITION[$dbtype] == 0)) {
516		return NOT_SUPPORTED;
517	}
518	if (($mode == DOMAIN) && ($IPV6_DOMAIN_POSITION[$dbtype] == 0)) {
519		return NOT_SUPPORTED;
520	}
521	if (($mode == ZIPCODE) && ($IPV6_ZIPCODE_POSITION[$dbtype] == 0)) {
522		return NOT_SUPPORTED;
523	}
524	if (($mode == TIMEZONE) && ($IPV6_TIMEZONE_POSITION[$dbtype] == 0)) {
525		return NOT_SUPPORTED;
526	}
527	if (($mode == NETSPEED) && ($IPV6_NETSPEED_POSITION[$dbtype] == 0)) {
528		return NOT_SUPPORTED;
529	}
530	if (($mode == IDDCODE) && ($IPV6_IDDCODE_POSITION[$dbtype] == 0)) {
531		return NOT_SUPPORTED;
532	}
533	if (($mode == AREACODE) && ($IPV6_AREACODE_POSITION[$dbtype] == 0)) {
534		return NOT_SUPPORTED;
535	}
536	if (($mode == WEATHERSTATIONCODE) && ($IPV6_WEATHERSTATIONCODE_POSITION[$dbtype] == 0)) {
537		return NOT_SUPPORTED;
538	}
539	if (($mode == WEATHERSTATIONNAME) && ($IPV6_WEATHERSTATIONNAME_POSITION[$dbtype] == 0)) {
540		return NOT_SUPPORTED;
541	}
542	if (($mode == MCC) && ($IPV6_MCC_POSITION[$dbtype] == 0)) {
543		return NOT_SUPPORTED;
544	}
545	if (($mode == MNC) && ($IPV6_MNC_POSITION[$dbtype] == 0)) {
546		return NOT_SUPPORTED;
547	}
548	if (($mode == MOBILEBRAND) && ($IPV6_MOBILEBRAND_POSITION[$dbtype] == 0)) {
549		return NOT_SUPPORTED;
550	}
551	if (($mode == ELEVATION) && ($IPV6_ELEVATION_POSITION[$dbtype] == 0)) {
552		return NOT_SUPPORTED;
553	}
554	if (($mode == USAGETYPE) && ($IPV6_USAGETYPE_POSITION[$dbtype] == 0)) {
555		return NOT_SUPPORTED;
556	}
557
558	my $realipno = $ipnum;
559	my $handle = $obj->{"filehandle"};
560	my $baseaddr = $obj->{"ipv6databaseaddr"};
561	my $dbcount = $obj->{"ipv6databasecount"};
562	my $dbcolumn = $obj->{"databasecolumn"};
563	my $indexbaseaddr = $obj->{"ipv6indexbaseaddr"};
564
565	if ($dbcount == 0) {
566		if ($mode == ALL) {
567			return (IPV6_ADDRESS_IN_IPV4_BIN, IPV6_ADDRESS_IN_IPV4_BIN, IPV6_ADDRESS_IN_IPV4_BIN, IPV6_ADDRESS_IN_IPV4_BIN, IPV6_ADDRESS_IN_IPV4_BIN, IPV6_ADDRESS_IN_IPV4_BIN, IPV6_ADDRESS_IN_IPV4_BIN, IPV6_ADDRESS_IN_IPV4_BIN, IPV6_ADDRESS_IN_IPV4_BIN, IPV6_ADDRESS_IN_IPV4_BIN, IPV6_ADDRESS_IN_IPV4_BIN, IPV6_ADDRESS_IN_IPV4_BIN, IPV6_ADDRESS_IN_IPV4_BIN, IPV6_ADDRESS_IN_IPV4_BIN, IPV6_ADDRESS_IN_IPV4_BIN, IPV6_ADDRESS_IN_IPV4_BIN, IPV6_ADDRESS_IN_IPV4_BIN, IPV6_ADDRESS_IN_IPV4_BIN, IPV6_ADDRESS_IN_IPV4_BIN, IPV6_ADDRESS_IN_IPV4_BIN);
568		} else {
569			return IPV6_ADDRESS_IN_IPV4_BIN;
570		}
571	}
572
573	my $ipnum1_2 = new Math::BigInt($ipnum);
574	my $remainder = 0;
575	($ipnum1_2, $remainder) = $ipnum1_2->bdiv(2**112);
576	my $indexaddr = $indexbaseaddr + ($ipnum1_2 << 3);
577
578	my $low = 0;
579	my $high = $dbcount;
580	if ($indexbaseaddr > 0) {
581		$low = $obj->read32($handle, $indexaddr);
582		$high = $obj->read32($handle, $indexaddr + 4);
583	}
584
585	my $mid = 0;
586	my $ipfrom = 0;
587	my $ipto = 0;
588	my $ipno = 0;
589
590	if ($realipno == MAX_IPV6_RANGE) {
591		$ipno = $realipno - 1;
592	} else {
593		$ipno = $realipno;
594	}
595
596	while ($low <= $high) {
597		$mid = int(($low + $high)/2);
598		$ipfrom = $obj->read128($handle, $baseaddr + $mid * (($dbcolumn * 4) + 12));
599		$ipto = $obj->read128($handle, $baseaddr + ($mid + 1) * (($dbcolumn * 4) + 12));
600		if (($ipno >= $ipfrom) && ($ipno < $ipto)) {
601			my $row_pointer = $baseaddr + $mid * (($dbcolumn * 4) + 12);
602			if ($mode == ALL) {
603				my $country_short = NOT_SUPPORTED;
604				my $country_long = NOT_SUPPORTED;
605				my $region = NOT_SUPPORTED;
606				my $city = NOT_SUPPORTED;
607				my $isp = NOT_SUPPORTED;
608				my $latitude = NOT_SUPPORTED;
609				my $longitude = NOT_SUPPORTED;
610				my $domain = NOT_SUPPORTED;
611				my $zipcode = NOT_SUPPORTED;
612				my $timezone = NOT_SUPPORTED;
613				my $netspeed = NOT_SUPPORTED;
614				my $iddcode = NOT_SUPPORTED;
615				my $areacode = NOT_SUPPORTED;
616				my $weatherstationcode = NOT_SUPPORTED;
617				my $weatherstationname = NOT_SUPPORTED;
618				my $mcc = NOT_SUPPORTED;
619				my $mnc = NOT_SUPPORTED;
620				my $mobilebrand = NOT_SUPPORTED;
621				my $elevation = NOT_SUPPORTED;
622				my $usagetype = NOT_SUPPORTED;
623
624				if ($IPV6_COUNTRY_POSITION[$dbtype] != 0) {
625					$country_short = $obj->readStr($handle, $obj->read32($handle, $row_pointer + 8 + 4 * ($IPV6_COUNTRY_POSITION[$dbtype])));
626					$country_long = $obj->readStr($handle, $obj->read32($handle, $row_pointer + 8 + 4 * ($IPV6_COUNTRY_POSITION[$dbtype])) + 3);
627				}
628				if ($IPV6_REGION_POSITION[$dbtype] != 0) {
629					$region = $obj->readStr($handle, $obj->read32($handle, $row_pointer + 8 + 4 * ($IPV6_REGION_POSITION[$dbtype])));
630				}
631				if ($IPV6_CITY_POSITION[$dbtype] != 0) {
632					$city = $obj->readStr($handle, $obj->read32($handle, $row_pointer + 8 + 4 * ($IPV6_CITY_POSITION[$dbtype])));
633				}
634				if ($IPV6_ISP_POSITION[$dbtype] != 0) {
635					$isp = $obj->readStr($handle, $obj->read32($handle, $row_pointer + 8 + 4 * ($IPV6_ISP_POSITION[$dbtype])));
636				}
637				if ($IPV6_LATITUDE_POSITION[$dbtype] != 0) {
638					$latitude = $obj->readFloat($handle, $row_pointer + 8 + 4 * ($IPV6_LATITUDE_POSITION[$dbtype]));
639					$latitude = sprintf("%.6f", $latitude);
640				}
641				if ($IPV6_LONGITUDE_POSITION[$dbtype] != 0) {
642					$longitude = $obj->readFloat($handle, $row_pointer + 8 + 4 * ($IPV6_LONGITUDE_POSITION[$dbtype]));
643					$longitude = sprintf("%.6f", $longitude);
644				}
645				if ($IPV6_DOMAIN_POSITION[$dbtype] != 0) {
646					$domain = $obj->readStr($handle, $obj->read32($handle, $row_pointer + 8 + 4 * ($IPV6_DOMAIN_POSITION[$dbtype])));
647				}
648				if ($IPV6_ZIPCODE_POSITION[$dbtype] != 0) {
649					$zipcode = $obj->readStr($handle, $obj->read32($handle, $row_pointer + 8 + 4 * ($IPV6_ZIPCODE_POSITION[$dbtype])));
650				}
651				if ($IPV6_TIMEZONE_POSITION[$dbtype] != 0) {
652					$timezone = $obj->readStr($handle, $obj->read32($handle, $row_pointer + 8 + 4 * ($IPV6_TIMEZONE_POSITION[$dbtype])));
653				}
654				if ($IPV6_NETSPEED_POSITION[$dbtype] != 0) {
655					$netspeed = $obj->readStr($handle, $obj->read32($handle, $row_pointer + 8 + 4 * ($IPV6_NETSPEED_POSITION[$dbtype])));
656				}
657				if ($IPV6_IDDCODE_POSITION[$dbtype] != 0) {
658					$iddcode = $obj->readStr($handle, $obj->read32($handle, $row_pointer + 8 + 4 * ($IPV6_IDDCODE_POSITION[$dbtype])));
659				}
660				if ($IPV6_AREACODE_POSITION[$dbtype] != 0) {
661					$areacode = $obj->readStr($handle, $obj->read32($handle, $row_pointer + 8 + 4 * ($IPV6_AREACODE_POSITION[$dbtype])));
662				}
663				if ($IPV6_WEATHERSTATIONCODE_POSITION[$dbtype] != 0) {
664					$weatherstationcode = $obj->readStr($handle, $obj->read32($handle, $row_pointer + 8 + 4 * ($IPV6_WEATHERSTATIONCODE_POSITION[$dbtype])));
665				}
666				if ($IPV6_WEATHERSTATIONNAME_POSITION[$dbtype] != 0) {
667					$weatherstationname = $obj->readStr($handle, $obj->read32($handle, $row_pointer + 8 + 4 * ($IPV6_WEATHERSTATIONNAME_POSITION[$dbtype])));
668				}
669				if ($IPV6_MCC_POSITION[$dbtype] != 0) {
670					$mcc = $obj->readStr($handle, $obj->read32($handle, $row_pointer + 8 + 4 * ($IPV6_MCC_POSITION[$dbtype])));
671				}
672				if ($IPV6_MNC_POSITION[$dbtype] != 0) {
673					$mnc = $obj->readStr($handle, $obj->read32($handle, $row_pointer + 8 + 4 * ($IPV6_MNC_POSITION[$dbtype])));
674				}
675				if ($IPV6_MOBILEBRAND_POSITION[$dbtype] != 0) {
676					$mobilebrand = $obj->readStr($handle, $obj->read32($handle, $row_pointer + 8 + 4 * ($IPV6_MOBILEBRAND_POSITION[$dbtype])));
677				}
678				if ($IPV6_ELEVATION_POSITION[$dbtype] != 0) {
679					$elevation = $obj->readStr($handle, $obj->read32($handle, $row_pointer + 8 + 4 * ($IPV6_ELEVATION_POSITION[$dbtype])));
680				}
681				if ($IPV6_USAGETYPE_POSITION[$dbtype] != 0) {
682					$usagetype = $obj->readStr($handle, $obj->read32($handle, $row_pointer + 8 + 4 * ($IPV6_USAGETYPE_POSITION[$dbtype])));
683				}
684				return ($country_short, $country_long, $region, $city, $latitude, $longitude, $zipcode, $timezone, $isp, $domain, $netspeed, $iddcode, $areacode, $weatherstationcode, $weatherstationname, $mcc, $mnc, $mobilebrand, $elevation, $usagetype);
685			}
686			if ($mode == COUNTRYSHORT) {
687				return $obj->readStr($handle, $obj->read32($handle, $row_pointer + 8 + 4 * ($IPV6_COUNTRY_POSITION[$dbtype])));
688			}
689			if ($mode == COUNTRYLONG) {
690				return $obj->readStr($handle, $obj->read32($handle, $row_pointer + 8 + 4 * ($IPV6_COUNTRY_POSITION[$dbtype])) + 3);
691			}
692			if ($mode == REGION) {
693				return $obj->readStr($handle, $obj->read32($handle, $row_pointer + 8 + 4 * ($IPV6_REGION_POSITION[$dbtype])));
694			}
695			if ($mode == CITY) {
696				return $obj->readStr($handle, $obj->read32($handle, $row_pointer + 8 + 4 * ($IPV6_CITY_POSITION[$dbtype])));
697			}
698			if ($mode == ISP) {
699				return $obj->readStr($handle, $obj->read32($handle, $row_pointer + 8 + 4 * ($IPV6_ISP_POSITION[$dbtype])));
700			}
701			if ($mode == LATITUDE) {
702				my $lat = $obj->readFloat($handle, $row_pointer + 8 + 4 * ($IPV6_LATITUDE_POSITION[$dbtype]));
703				$lat = sprintf("%.6f", $lat);
704				return $lat;
705			}
706			if ($mode == LONGITUDE) {
707				my $lon = $obj->readFloat($handle, $row_pointer + 8 + 4 * ($IPV6_LONGITUDE_POSITION[$dbtype]));
708				$lon = sprintf("%.6f", $lon);
709				return $lon;
710			}
711			if ($mode == DOMAIN) {
712				return $obj->readStr($handle, $obj->read32($handle, $row_pointer + 8 + 4 * ($IPV6_DOMAIN_POSITION[$dbtype])));
713			}
714			if ($mode == ZIPCODE) {
715				return $obj->readStr($handle, $obj->read32($handle, $row_pointer + 8 + 4 * ($IPV6_ZIPCODE_POSITION[$dbtype])));
716			}
717			if ($mode == TIMEZONE) {
718				return $obj->readStr($handle, $obj->read32($handle, $row_pointer + 8 + 4 * ($IPV6_TIMEZONE_POSITION[$dbtype])));
719			}
720			if ($mode == NETSPEED) {
721				return $obj->readStr($handle, $obj->read32($handle, $row_pointer + 8 + 4 * ($IPV6_NETSPEED_POSITION[$dbtype])));
722			}
723			if ($mode == IDDCODE) {
724				return $obj->readStr($handle, $obj->read32($handle, $row_pointer + 8 + 4 * ($IPV6_IDDCODE_POSITION[$dbtype])));
725			}
726			if ($mode == AREACODE) {
727				return $obj->readStr($handle, $obj->read32($handle, $row_pointer + 8 + 4 * ($IPV6_AREACODE_POSITION[$dbtype])));
728			}
729			if ($mode == WEATHERSTATIONCODE) {
730				return $obj->readStr($handle, $obj->read32($handle, $row_pointer + 8 + 4 * ($IPV6_WEATHERSTATIONCODE_POSITION[$dbtype])));
731			}
732			if ($mode == WEATHERSTATIONNAME) {
733				return $obj->readStr($handle, $obj->read32($handle, $row_pointer + 8 + 4 * ($IPV6_WEATHERSTATIONNAME_POSITION[$dbtype])));
734			}
735			if ($mode == MCC) {
736				return $obj->readStr($handle, $obj->read32($handle, $row_pointer + 8 + 4 * ($IPV6_MCC_POSITION[$dbtype])));
737			}
738			if ($mode == MNC) {
739				return $obj->readStr($handle, $obj->read32($handle, $row_pointer + 8 + 4 * ($IPV6_MNC_POSITION[$dbtype])));
740			}
741			if ($mode == MOBILEBRAND) {
742				return $obj->readStr($handle, $obj->read32($handle, $row_pointer + 8 + 4 * ($IPV6_MOBILEBRAND_POSITION[$dbtype])));
743			}
744			if ($mode == ELEVATION) {
745				return $obj->readStr($handle, $obj->read32($handle, $row_pointer + 8 + 4 * ($IPV6_ELEVATION_POSITION[$dbtype])));
746			}
747			if ($mode == USAGETYPE) {
748				return $obj->readStr($handle, $obj->read32($handle, $row_pointer + 8 + 4 * ($IPV6_USAGETYPE_POSITION[$dbtype])));
749			}
750		} else {
751			if ($ipno < $ipfrom) {
752				$high = $mid - 1;
753			} else {
754				$low = $mid + 1;
755			}
756		}
757	}
758	if ($mode == ALL) {
759		return (UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN);
760	} else {
761		return UNKNOWN;
762	}
763}
764
765sub get_record {
766	my $obj = shift(@_);
767	my $ipnum = shift(@_);
768	my $mode = shift(@_);
769	my $dbtype= $obj->{"databasetype"};
770
771	if ($ipnum eq "") {
772		if ($mode == ALL) {
773			return (NO_IP, NO_IP, NO_IP, NO_IP, NO_IP, NO_IP, NO_IP, NO_IP, NO_IP, NO_IP, NO_IP, NO_IP, NO_IP, NO_IP, NO_IP, NO_IP, NO_IP, NO_IP, NO_IP, NO_IP);
774		} else {
775			return NO_IP;
776		}
777	}
778
779	if (($mode == COUNTRYSHORT) && ($COUNTRY_POSITION[$dbtype] == 0)) {
780		return NOT_SUPPORTED;
781	}
782	if (($mode == COUNTRYLONG) && ($COUNTRY_POSITION[$dbtype] == 0)) {
783		return NOT_SUPPORTED;
784	}
785	if (($mode == REGION) && ($REGION_POSITION[$dbtype] == 0)) {
786		return NOT_SUPPORTED;
787	}
788	if (($mode == CITY) && ($CITY_POSITION[$dbtype] == 0)) {
789		return NOT_SUPPORTED;
790	}
791	if (($mode == ISP) && ($ISP_POSITION[$dbtype] == 0)) {
792		return NOT_SUPPORTED;
793	}
794	if (($mode == LATITUDE) && ($LATITUDE_POSITION[$dbtype] == 0)) {
795		return NOT_SUPPORTED;
796	}
797	if (($mode == LONGITUDE) && ($LONGITUDE_POSITION[$dbtype] == 0)) {
798		return NOT_SUPPORTED;
799	}
800	if (($mode == DOMAIN) && ($DOMAIN_POSITION[$dbtype] == 0)) {
801		return NOT_SUPPORTED;
802	}
803	if (($mode == ZIPCODE) && ($ZIPCODE_POSITION[$dbtype] == 0)) {
804		return NOT_SUPPORTED;
805	}
806	if (($mode == TIMEZONE) && ($TIMEZONE_POSITION[$dbtype] == 0)) {
807		return NOT_SUPPORTED;
808	}
809	if (($mode == NETSPEED) && ($NETSPEED_POSITION[$dbtype] == 0)) {
810		return NOT_SUPPORTED;
811	}
812	if (($mode == IDDCODE) && ($IDDCODE_POSITION[$dbtype] == 0)) {
813		return NOT_SUPPORTED;
814	}
815	if (($mode == AREACODE) && ($AREACODE_POSITION[$dbtype] == 0)) {
816		return NOT_SUPPORTED;
817	}
818	if (($mode == WEATHERSTATIONCODE) && ($WEATHERSTATIONCODE_POSITION[$dbtype] == 0)) {
819		return NOT_SUPPORTED;
820	}
821	if (($mode == WEATHERSTATIONNAME) && ($WEATHERSTATIONNAME_POSITION[$dbtype] == 0)) {
822		return NOT_SUPPORTED;
823	}
824	if (($mode == MCC) && ($MCC_POSITION[$dbtype] == 0)) {
825		return NOT_SUPPORTED;
826	}
827	if (($mode == MNC) && ($MNC_POSITION[$dbtype] == 0)) {
828		return NOT_SUPPORTED;
829	}
830	if (($mode == MOBILEBRAND) && ($MOBILEBRAND_POSITION[$dbtype] == 0)) {
831		return NOT_SUPPORTED;
832	}
833	if (($mode == ELEVATION) && ($ELEVATION_POSITION[$dbtype] == 0)) {
834		return NOT_SUPPORTED;
835	}
836	if (($mode == USAGETYPE) && ($USAGETYPE_POSITION[$dbtype] == 0)) {
837		return NOT_SUPPORTED;
838	}
839
840	my $realipno = $ipnum;
841	my $handle = $obj->{"filehandle"};
842	my $baseaddr = $obj->{"ipv4databaseaddr"};
843	my $dbcount = $obj->{"ipv4databasecount"};
844	my $dbcolumn = $obj->{"databasecolumn"};
845	my $indexbaseaddr = $obj->{"ipv4indexbaseaddr"};
846
847	my $ipnum1_2 = int($ipnum >> 16);
848	my $indexaddr = $indexbaseaddr + ($ipnum1_2 << 3);
849
850	my $low = 0;
851	my $high = $dbcount;
852	if ($indexbaseaddr > 0) {
853		$low = $obj->read32($handle, $indexaddr);
854		$high = $obj->read32($handle, $indexaddr + 4);
855	}
856	my $mid = 0;
857	my $ipfrom = 0;
858	my $ipto = 0;
859	my $ipno = 0;
860
861	if ($realipno == MAX_IPV4_RANGE) {
862		$ipno = $realipno - 1;
863	} else {
864		$ipno = $realipno;
865	}
866
867	while ($low <= $high) {
868		$mid = int(($low + $high) >> 1);
869		$ipfrom = $obj->read32($handle, $baseaddr + $mid * $dbcolumn * 4);
870		$ipto = $obj->read32($handle, $baseaddr + ($mid + 1) * $dbcolumn * 4);
871		if (($ipno >= $ipfrom) && ($ipno < $ipto)) {
872			if ($mode == ALL) {
873				my $country_short = NOT_SUPPORTED;
874				my $country_long = NOT_SUPPORTED;
875				my $region = NOT_SUPPORTED;
876				my $city = NOT_SUPPORTED;
877				my $isp = NOT_SUPPORTED;
878				my $latitude = NOT_SUPPORTED;
879				my $longitude = NOT_SUPPORTED;
880				my $domain = NOT_SUPPORTED;
881				my $zipcode = NOT_SUPPORTED;
882				my $timezone = NOT_SUPPORTED;
883				my $netspeed = NOT_SUPPORTED;
884				my $iddcode = NOT_SUPPORTED;
885				my $areacode = NOT_SUPPORTED;
886				my $weatherstationcode = NOT_SUPPORTED;
887				my $weatherstationname = NOT_SUPPORTED;
888				my $mcc = NOT_SUPPORTED;
889				my $mnc = NOT_SUPPORTED;
890				my $mobilebrand = NOT_SUPPORTED;
891				my $elevation = NOT_SUPPORTED;
892				my $usagetype = NOT_SUPPORTED;
893
894				if ($COUNTRY_POSITION[$dbtype] != 0) {
895					$country_short = $obj->readStr($handle, $obj->read32($handle, $baseaddr + ($mid * $dbcolumn * 4) + 4 * ($COUNTRY_POSITION[$dbtype]-1)));
896					$country_long = $obj->readStr($handle, $obj->read32($handle, $baseaddr + ($mid * $dbcolumn * 4) + 4 * ($COUNTRY_POSITION[$dbtype]-1))+3);
897				}
898
899				if ($REGION_POSITION[$dbtype] != 0) {
900					$region = $obj->readStr($handle, $obj->read32($handle, $baseaddr + ($mid * $dbcolumn * 4) + 4 * ($REGION_POSITION[$dbtype]-1)));
901				}
902				if ($CITY_POSITION[$dbtype] != 0) {
903					$city = $obj->readStr($handle, $obj->read32($handle, $baseaddr + ($mid * $dbcolumn * 4) + 4 * ($CITY_POSITION[$dbtype]-1)));
904				}
905				if ($ISP_POSITION[$dbtype] != 0) {
906					$isp = $obj->readStr($handle, $obj->read32($handle, $baseaddr + ($mid * $dbcolumn * 4) + 4 * ($ISP_POSITION[$dbtype]-1)));
907				}
908				if ($LATITUDE_POSITION[$dbtype] != 0) {
909					$latitude = $obj->readFloat($handle, $baseaddr + ($mid * $dbcolumn * 4) + 4 * ($LATITUDE_POSITION[$dbtype]-1));
910					$latitude = sprintf("%.6f", $latitude);
911				}
912				if ($LONGITUDE_POSITION[$dbtype] != 0) {
913					$longitude = $obj->readFloat($handle, $baseaddr + ($mid * $dbcolumn * 4) + 4 * ($LONGITUDE_POSITION[$dbtype]-1));
914					$longitude = sprintf("%.6f", $longitude);
915				}
916				if ($DOMAIN_POSITION[$dbtype] != 0) {
917					$domain = $obj->readStr($handle, $obj->read32($handle, $baseaddr + ($mid * $dbcolumn * 4) + 4 * ($DOMAIN_POSITION[$dbtype]-1)));
918				}
919				if ($ZIPCODE_POSITION[$dbtype] != 0) {
920					$zipcode = $obj->readStr($handle, $obj->read32($handle, $baseaddr + ($mid * $dbcolumn * 4) + 4 * ($ZIPCODE_POSITION[$dbtype]-1)));
921				}
922				if ($TIMEZONE_POSITION[$dbtype] != 0) {
923					$timezone = $obj->readStr($handle, $obj->read32($handle, $baseaddr + ($mid * $dbcolumn * 4) + 4 * ($TIMEZONE_POSITION[$dbtype]-1)));
924				}
925				if ($NETSPEED_POSITION[$dbtype] != 0) {
926					$netspeed = $obj->readStr($handle, $obj->read32($handle, $baseaddr + ($mid * $dbcolumn * 4) + 4 * ($NETSPEED_POSITION[$dbtype]-1)));
927				}
928				if ($IDDCODE_POSITION[$dbtype] != 0) {
929					$iddcode = $obj->readStr($handle, $obj->read32($handle, $baseaddr + ($mid * $dbcolumn * 4) + 4 * ($IDDCODE_POSITION[$dbtype]-1)));
930				}
931				if ($AREACODE_POSITION[$dbtype] != 0) {
932					$areacode = $obj->readStr($handle, $obj->read32($handle, $baseaddr + ($mid * $dbcolumn * 4) + 4 * ($AREACODE_POSITION[$dbtype]-1)));
933				}
934				if ($WEATHERSTATIONCODE_POSITION[$dbtype] != 0) {
935					$weatherstationcode = $obj->readStr($handle, $obj->read32($handle, $baseaddr + ($mid * $dbcolumn * 4) + 4 * ($WEATHERSTATIONCODE_POSITION[$dbtype]-1)));
936				}
937				if ($WEATHERSTATIONNAME_POSITION[$dbtype] != 0) {
938					$weatherstationname = $obj->readStr($handle, $obj->read32($handle, $baseaddr + ($mid * $dbcolumn * 4) + 4 * ($WEATHERSTATIONNAME_POSITION[$dbtype]-1)));
939				}
940				if ($MCC_POSITION[$dbtype] != 0) {
941					$mcc = $obj->readStr($handle, $obj->read32($handle, $baseaddr + ($mid * $dbcolumn * 4) + 4 * ($MCC_POSITION[$dbtype]-1)));
942				}
943				if ($MNC_POSITION[$dbtype] != 0) {
944					$mnc = $obj->readStr($handle, $obj->read32($handle, $baseaddr + ($mid * $dbcolumn * 4) + 4 * ($MNC_POSITION[$dbtype]-1)));
945				}
946				if ($MOBILEBRAND_POSITION[$dbtype] != 0) {
947					$mobilebrand = $obj->readStr($handle, $obj->read32($handle, $baseaddr + ($mid * $dbcolumn * 4) + 4 * ($MOBILEBRAND_POSITION[$dbtype]-1)));
948				}
949				if ($ELEVATION_POSITION[$dbtype] != 0) {
950					$elevation = $obj->readStr($handle, $obj->read32($handle, $baseaddr + ($mid * $dbcolumn * 4) + 4 * ($ELEVATION_POSITION[$dbtype]-1)));
951				}
952				if ($USAGETYPE_POSITION[$dbtype] != 0) {
953					$usagetype = $obj->readStr($handle, $obj->read32($handle, $baseaddr + ($mid * $dbcolumn * 4) + 4 * ($USAGETYPE_POSITION[$dbtype]-1)));
954				}
955				return ($country_short, $country_long, $region, $city, $latitude, $longitude, $zipcode, $timezone, $isp, $domain, $netspeed, $iddcode, $areacode, $weatherstationcode, $weatherstationname, $mcc, $mnc, $mobilebrand, $elevation, $usagetype);
956			}
957			if ($mode == COUNTRYSHORT) {
958				return $obj->readStr($handle, $obj->read32($handle, $baseaddr + ($mid * $dbcolumn * 4) + 4 * ($COUNTRY_POSITION[$dbtype]-1)));
959			}
960			if ($mode == COUNTRYLONG) {
961				return $obj->readStr($handle, $obj->read32($handle, $baseaddr + ($mid * $dbcolumn * 4) + 4 * ($COUNTRY_POSITION[$dbtype]-1))+3);
962			}
963			if ($mode == REGION) {
964				return $obj->readStr($handle, $obj->read32($handle, $baseaddr + ($mid * $dbcolumn * 4) + 4 * ($REGION_POSITION[$dbtype]-1)));
965			}
966			if ($mode == CITY) {
967				return $obj->readStr($handle, $obj->read32($handle, $baseaddr + ($mid * $dbcolumn * 4) + 4 * ($CITY_POSITION[$dbtype]-1)));
968			}
969			if ($mode == ISP) {
970				return $obj->readStr($handle, $obj->read32($handle, $baseaddr + ($mid * $dbcolumn * 4) + 4 * ($ISP_POSITION[$dbtype]-1)));
971			}
972			if ($mode == LATITUDE) {
973				my $lat = $obj->readFloat($handle, $baseaddr + ($mid * $dbcolumn * 4) + 4 * ($LATITUDE_POSITION[$dbtype]-1));
974				$lat = sprintf("%.6f", $lat);
975				return $lat;
976			}
977			if ($mode == LONGITUDE) {
978				my $lon = $obj->readFloat($handle, $baseaddr + ($mid * $dbcolumn * 4) + 4 * ($LONGITUDE_POSITION[$dbtype]-1));
979				$lon = sprintf("%.6f", $lon);
980				return $lon;
981			}
982			if ($mode == DOMAIN) {
983				return $obj->readStr($handle, $obj->read32($handle, $baseaddr + ($mid * $dbcolumn * 4) + 4 * ($DOMAIN_POSITION[$dbtype]-1)));
984			}
985			if ($mode == ZIPCODE) {
986				return $obj->readStr($handle, $obj->read32($handle, $baseaddr + ($mid * $dbcolumn * 4) + 4 * ($ZIPCODE_POSITION[$dbtype]-1)));
987			}
988			if ($mode == TIMEZONE) {
989				return $obj->readStr($handle, $obj->read32($handle, $baseaddr + ($mid * $dbcolumn * 4) + 4 * ($TIMEZONE_POSITION[$dbtype]-1)));
990			}
991			if ($mode == NETSPEED) {
992				return $obj->readStr($handle, $obj->read32($handle, $baseaddr + ($mid * $dbcolumn * 4) + 4 * ($NETSPEED_POSITION[$dbtype]-1)));
993			}
994			if ($mode == IDDCODE) {
995				return $obj->readStr($handle, $obj->read32($handle, $baseaddr + ($mid * $dbcolumn * 4) + 4 * ($IDDCODE_POSITION[$dbtype]-1)));
996			}
997			if ($mode == AREACODE) {
998				return $obj->readStr($handle, $obj->read32($handle, $baseaddr + ($mid * $dbcolumn * 4) + 4 * ($AREACODE_POSITION[$dbtype]-1)));
999			}
1000			if ($mode == WEATHERSTATIONCODE) {
1001				return $obj->readStr($handle, $obj->read32($handle, $baseaddr + ($mid * $dbcolumn * 4) + 4 * ($WEATHERSTATIONCODE_POSITION[$dbtype]-1)));
1002			}
1003			if ($mode == WEATHERSTATIONNAME) {
1004				return $obj->readStr($handle, $obj->read32($handle, $baseaddr + ($mid * $dbcolumn * 4) + 4 * ($WEATHERSTATIONNAME_POSITION[$dbtype]-1)));
1005			}
1006			if ($mode == MCC) {
1007				return $obj->readStr($handle, $obj->read32($handle, $baseaddr + ($mid * $dbcolumn * 4) + 4 * ($MCC_POSITION[$dbtype]-1)));
1008			}
1009			if ($mode == MNC) {
1010				return $obj->readStr($handle, $obj->read32($handle, $baseaddr + ($mid * $dbcolumn * 4) + 4 * ($MNC_POSITION[$dbtype]-1)));
1011			}
1012			if ($mode == MOBILEBRAND) {
1013				return $obj->readStr($handle, $obj->read32($handle, $baseaddr + ($mid * $dbcolumn * 4) + 4 * ($MOBILEBRAND_POSITION[$dbtype]-1)));
1014			}
1015			if ($mode == ELEVATION) {
1016				return $obj->readStr($handle, $obj->read32($handle, $baseaddr + ($mid * $dbcolumn * 4) + 4 * ($ELEVATION_POSITION[$dbtype]-1)));
1017			}
1018			if ($mode == USAGETYPE) {
1019				return $obj->readStr($handle, $obj->read32($handle, $baseaddr + ($mid * $dbcolumn * 4) + 4 * ($USAGETYPE_POSITION[$dbtype]-1)));
1020			}
1021		} else {
1022			if ($ipno < $ipfrom) {
1023				$high = $mid - 1;
1024			} else {
1025				$low = $mid + 1;
1026			}
1027		}
1028	}
1029	if ($mode == ALL) {
1030		return (UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN);
1031	} else {
1032		return UNKNOWN;
1033	}
1034}
1035
1036sub read128 {
1037	my ($obj, $handle, $position) = @_;
1038	my $data = "";
1039	seek($handle, $position-1, 0);
1040	read($handle, $data, 16);
1041	return &bytes2int($data);
1042}
1043
1044sub read32 {
1045	my ($obj, $handle, $position) = @_;
1046	my $data = "";
1047	seek($handle, $position-1, 0);
1048	read($handle, $data, 4);
1049	return unpack("V", $data);
1050}
1051
1052sub read8 {
1053	my ($obj, $handle, $position) = @_;
1054	my $data = "";
1055	seek($handle, $position-1, 0);
1056	read($handle, $data, 1);
1057	return unpack("C", $data);
1058}
1059
1060sub readStr {
1061	my ($obj, $handle, $position) = @_;
1062	my $data = "";
1063	my $string = "";
1064	seek($handle, $position, 0);
1065	read($handle, $data, 1);
1066	read($handle, $string, unpack("C", $data));
1067	return $string;
1068}
1069
1070sub readFloat {
1071	my ($obj, $handle, $position) = @_;
1072	my $data = "";
1073	seek($handle, $position-1, 0);
1074	read($handle, $data, 4);
1075
1076	my $is_little_endian = unpack("h*", pack("s", 1));
1077	if ($is_little_endian =~ m/^1/) {
1078		# "LITTLE ENDIAN - x86\n";
1079		return unpack("f", $data);
1080	} else {
1081		# "BIG ENDIAN - MAC\n";
1082		return unpack("f", reverse($data));
1083	}
1084}
1085
1086sub bytes2int {
1087	my $binip = shift(@_);
1088	my @array = split(//, $binip);
1089	return 0 if ($#array != 15);
1090	my $ip96_127 = unpack("V", $array[0] . $array[1] . $array[2] . $array[3]);
1091	my $ip64_95 = unpack("V", $array[4] . $array[5] . $array[6] . $array[7]);
1092	my $ip32_63 = unpack("V", $array[8] . $array[9] . $array[10] . $array[11]);
1093	my $ip1_31 = unpack("V", $array[12] . $array[13] . $array[14] . $array[15]);
1094
1095	my $big1 = Math::BigInt->new("$ip96_127");
1096	my $big2 = Math::BigInt->new("$ip64_95")->blsft(32);
1097	my $big3 = Math::BigInt->new("$ip32_63")->blsft(64);
1098	my $big4 = Math::BigInt->new("$ip1_31")->blsft(96);
1099	$big1 = $big1->badd($big2)->badd($big3)->badd($big4);
1100
1101	return $big1->bstr();
1102}
1103
1104sub validate_ip {
1105	my $obj = shift(@_);
1106	my $ip = shift(@_);
1107	my $ipv = -1;
1108	my $ipnum = -1;
1109	#name server lookup if domain name
1110	$ip = $obj->name2ip($ip);
1111
1112	if ($obj->ip_is_ipv4($ip)) {
1113		#ipv4 address
1114		$ipv = 4;
1115		$ipnum = $obj->ip2no($ip);
1116	} else {
1117		#expand ipv6 address
1118		$ip = $obj->expand_ipv6_address($ip);
1119		if ($obj->ip_is_ipv6($ip)) {
1120			#ipv6 address
1121			$ipv = 6;
1122			$ipnum = $obj->hex2int($ip);
1123
1124			#reformat ipv4 address in ipv6
1125			if (($ipnum >= 281470681743360) && ($ipnum <= 281474976710655)) {
1126				$ipv = 4;
1127				$ipnum = $ipnum - 281470681743360;
1128			}
1129		} else {
1130			#not IPv4 and IPv6
1131		}
1132	}
1133	return ($ipv, $ipnum);
1134}
1135
1136sub expand_ipv6_address {
1137	my $obj = shift(@_);
1138	my $ip = shift(@_);
1139	$ip =~ s/\:\:/\:Z\:/;
1140	my @ip = split(/\:/, $ip);
1141	my $num = scalar(@ip);
1142
1143	my $l = 8;
1144	if ($ip[$#ip] =~ /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/) {
1145		my $a = sprintf("%x", ($1*256 + $2));
1146		my $b = sprintf("%x", ($3*256 + $4));
1147		$ip[$#ip] = $a;
1148		$ip[$#ip+1] = $b;
1149		$l--;
1150	}
1151
1152	if ($#ip == 8) {
1153		shift(@ip);
1154		$l++;
1155	}
1156
1157	foreach (0..(scalar(@ip)-1)) {
1158		$ip[$_] = ('0'x(4-length ($ip[$_]))).$ip[$_];
1159	}
1160
1161	foreach (0..(scalar(@ip)-1)) {
1162		next unless ($ip[$_] eq '000Z');
1163		my @empty = map { $_ = '0'x4 } (0..7);
1164		$ip[$_] = join(':', @empty[0..$l-$num]);
1165		last;
1166	}
1167
1168	return (uc(join ':', @ip));
1169}
1170
1171sub hex2int {
1172	my $obj = shift(@_);
1173	my $hexip = shift(@_);
1174
1175	$hexip =~ s/\://g;
1176
1177	unless (length($hexip) == 32) {
1178		return 0;
1179	};
1180
1181	my $binip = unpack('B128', pack('H32', $hexip));
1182	my ($n, $dec) = (Math::BigInt->new(1), Math::BigInt->new(0));
1183
1184	foreach (reverse (split('', $binip))) {
1185		$_ && ($dec += $n);
1186		$n *= 2;
1187	}
1188
1189	$dec =~ s/^\+//;
1190	return $dec;
1191}
1192
1193sub ip2no {
1194	my $obj = shift(@_);
1195	my $ip = shift(@_);
1196	my @block = split(/\./, $ip);
1197	my $no = 0;
1198	$no = $block[3];
1199	$no = $no + $block[2] * 256;
1200	$no = $no + $block[1] * 256 * 256;
1201	$no = $no + $block[0] * 256 * 256 * 256;
1202	return $no;
1203}
1204
1205sub name2ip {
1206  my $obj = shift(@_);
1207  my $host = shift(@_);
1208  my $ip_address = "";
1209  if (($host =~ m/^$IPv4_re$/) || ($host =~ m/^$IPv6_re$/) || ($host =~ m/^\:\:$/)) {
1210    $ip_address = $host;
1211  } else {
1212  	# TO_DO: Can we return IPv6 address too?
1213    $ip_address = join('.', unpack('C4',(gethostbyname($host))[4]));
1214  }
1215  return $ip_address;
1216}
1217
1218sub ip_is_ipv4 {
1219	my $obj = shift(@_);
1220	my $ip = shift(@_);
1221	if ($ip =~ m/^$IPv4_re$/) {
1222		return 1;
1223	} else {
1224		return 0;
1225	}
1226}
1227
1228sub ip_is_ipv6 {
1229	my $obj = shift(@_);
1230	my $ip = shift(@_);
1231	if (($ip =~ m/^$IPv6_re$/) || ($ip =~ m/^$IPv4_re$/)) {
1232		return 1;
1233	} else {
1234		return 0;
1235	}
1236}
1237
12381;
1239__END__
1240
1241=head1 NAME
1242
1243Geo::IP2Location - Fast lookup of country, region, city, latitude, longitude, ZIP code, time zone, ISP, domain name, connection type, IDD code, area code, weather station code and station, MCC, MNC, mobile carrier brand name, elevation and usage type from IP address by using IP2Location database. It supports both IPv4 and IPv6 addressing. Please visit http://www.ip2location.com for more information.
1244
1245=head1 SYNOPSIS
1246
1247  use Geo::IP2Location;
1248	my $obj = Geo::IP2Location->open("IP-COUNTRY-REGION-CITY-LATITUDE-LONGITUDE-ZIPCODE-TIMEZONE-ISP-DOMAIN-NETSPEED-AREACODE-WEATHER-MOBILE-ELEVATION-USAGETYPE.BIN");
1249
1250	my $dbversion = $obj->get_database_version();
1251	my $moduleversion = $obj->get_module_version();
1252	my $countryshort = $obj->get_country_short("20.11.187.239");
1253	my $countrylong = $obj->get_country_long("20.11.187.239");
1254	my $region = $obj->get_region("20.11.187.239");
1255	my $city = $obj->get_city("20.11.187.239");
1256	my $latitude = $obj->get_latitude("20.11.187.239");
1257	my $longitude = $obj->get_longitude("20.11.187.239");
1258	my $isp = $obj->get_isp("20.11.187.239");
1259	my $domain = $obj->get_domain("20.11.187.239");
1260	my $zipcode = $obj->get_zipcode("20.11.187.239");
1261	my $timezone = $obj->get_timezone("20.11.187.239");
1262	my $netspeed = $obj->get_netspeed("20.11.187.239");
1263	my $iddcode = $obj->get_iddcode("20.11.187.239");
1264	my $areacode = $obj->get_areacode("20.11.187.239");
1265	my $weatherstationcode = $obj->get_weatherstationcode("20.11.187.239");
1266	my $weatherstationname = $obj->get_weatherstationname("20.11.187.239");
1267	my $mcc = $obj->get_mcc("20.11.187.239");
1268	my $mnc = $obj->get_mnc("20.11.187.239");
1269	my $brand = $obj->get_mobilebrand("20.11.187.239");
1270	my $elevation = $obj->get_elevation("20.11.187.239");
1271	my $usagetype = $obj->get_usagetype("20.11.187.239");
1272
1273	($cos, $col, $reg, $cit, $lat, $lon, $zip, $tmz, $isp, $dom, $ns, $idd, $area, $wcode, $wname, $mcc, $mnc, $brand, $elevation, $usagetype) = $obj->get_all("20.11.187.239");
1274	($cos, $col, $reg, $cit, $lat, $lon, $zip, $tmz, $isp, $dom, $ns, $idd, $area, $wcode, $wname, $mcc, $mnc, $brand, $elevation, $usagetype) = $obj->get_all("2001:1000:0000:0000:0000:0000:0000:0000");
1275
1276
1277=head1 DESCRIPTION
1278
1279This Perl module provides fast lookup of country, region, city, latitude, longitude, ZIP code, time zone, ISP, domain name, connection type, IDD code, area code, weather station code and station, MCC, MNC, mobile carrier brand, elevation and usage type from IP address using IP2Location database. This module uses a file based .BIN database available at http://www.ip2location.com upon subscription. This database contains IP blocks as keys and other information as values. It supports IP address in IPv4 or IPv6.
1280
1281This module can be used in many types of project such as:
1282
1283 1) select the geographically closest mirror
1284 2) analyze web server logs to determine the countries of visitors
1285 3) credit card fraud detection
1286 4) software export controls
1287 5) display native language and currency
1288 6) prevent password sharing and abuse of service
1289 7) geotargeting in advertisement
1290
1291=head1 IP2LOCATION DATABASES
1292
1293The complete IPv4 and IPv6 database are available at:
1294
1295http://www.ip2location.com
1296
1297The database will be updated in monthly basis for greater accuracy. Free sample database is available at:
1298
1299http://www.ip2location.com/developers
1300
1301=head1 CLASS METHODS
1302
1303=over 4
1304
1305=item $obj = Geo::IP2Location->open($database_file);
1306
1307Constructs a new Geo::IP2Location object with the database located at $database_file.
1308
1309=back
1310
1311=head1 OBJECT METHODS
1312
1313=over 4
1314
1315=item $countryshort = $obj->get_country_short( $ip );
1316
1317Returns the ISO 3166 country code of IP address or domain name. Returns "-" for unassigned or private IP address.
1318
1319=item $countrylong = $obj->get_country_long( $ip );
1320
1321Returns the full country name of IP address or domain name.  Returns "-" for unassigned or private IP address.
1322
1323=item $region = $obj->get_region( $ip );
1324
1325Returns the region of IP address or domain name.
1326
1327=item $city = $obj->get_city( $ip );
1328
1329Returns the city of IP address or domain name.
1330
1331=item $latitude = $obj->get_latitude( $ip );
1332
1333Returns the latitude of IP address or domain name.
1334
1335=item $longitude = $obj->get_longitude( $ip );
1336
1337Returns the longitude of IP address or domain name.
1338
1339=item $isp = $obj->get_isp( $ip );
1340
1341Returns the ISP name of IP address or domain name.
1342
1343=item $domain = $obj->get_domain( $ip );
1344
1345Returns the domain name of IP address or domain name.
1346
1347=item $zip = $obj->get_zipcode( $ip );
1348
1349Returns the ZIP code of IP address or domain name.
1350
1351=item $tz = $obj->get_timezone( $ip );
1352
1353Returns the time zone of IP address or domain name.
1354
1355=item $ns = $obj->get_netspeed( $ip );
1356
1357Returns the connection type (DIAL, DSL or COMP) of IP address or domain name.
1358
1359=item $idd = $obj->get_iddcode( $ip );
1360
1361Returns the country IDD calling code of IP address or domain name.
1362
1363=item $area = $obj->get_areacode( $ip );
1364
1365Returns the phone area code code of IP address or domain name.
1366
1367=item $wcode = $obj->get_weatherstationcode( $ip );
1368
1369Returns the nearest weather station code of IP address or domain name.
1370
1371=item $wname = $obj->get_weatherstationname( $ip );
1372
1373Returns the nearest weather station name of IP address or domain name.
1374
1375=item $mcc = $obj->get_mcc( $ip );
1376
1377Returns the mobile carrier code (MCC) of IP address or domain name.
1378
1379=item $mnc = $obj->get_mnc( $ip );
1380
1381Returns the mobile network code (MNC) of IP address or domain name.
1382
1383=item $brand = $obj->get_mobilebrand( $ip );
1384
1385Returns the mobile carrier brand of IP address or domain name.
1386
1387=item $elevation = $obj->get_elevation( $ip );
1388
1389Returns the elevation of IP address or domain name.
1390
1391=item $usagetype = $obj->get_usagetype( $ip );
1392
1393Returns the usage type of IP address or domain name.
1394
1395=item ($cos, $col, $reg, $cit, $lat, $lon, $zip, $tmz, $isp, $dom, $ns, $idd, $area, $wcode, $wname, $mcc, $mnc, $brand, $elevation, $usagetype) = $obj->get_all( $ip );
1396
1397Returns an array of country, region, city, latitude, longitude, ZIP code, time zone, ISP, domain name, connection type, IDD code, area code, weather station code and station, MCC, MNC, mobile carrier brand, elevation and usage type of IP address.
1398
1399=item $dbversion = $obj->get_database_version();
1400
1401Returns the version number of database.
1402
1403=item $moduleversion = $obj->get_module_version();
1404
1405Returns the version number of Perl module.
1406
1407=head1 SEE ALSO
1408
1409http://www.ip2location.com
1410
1411=head1 VERSION
1412
14138.01
1414
1415=head1 AUTHOR
1416
1417Copyright (c) 2016 IP2Location.com
1418
1419All rights reserved. This package is free software; It is licensed under the GPL.
1420
1421=cut
1422