1 /*
2  * IP2Location C library is distributed under MIT license
3  * Copyright (c) 2013-2015 IP2Location.com. support at ip2location dot com
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the MIT license
7  */
8 
9 #ifdef WIN32
10 #include <winsock2.h>
11 #include <ws2tcpip.h>
12 #else
13 #include <stdint.h>
14 #include <strings.h>
15 #include <sys/socket.h>
16 #include <netinet/in.h>
17 #include <arpa/inet.h>
18 #endif
19 
20 #include <string.h>
21 #include <stdio.h>
22 
23 #include "IP2Location.h"
24 #include "IP2Loc_DBInterface.h"
25 
26 #ifdef _WIN32
27   #define _STR2(x)  #x
28   #define _STR(x)  _STR2(x)
29   #define PACKAGE_VERSION  _STR(API_VERSION)
30 #else
31   #include "../config.h"
32 #endif
33 
34 typedef struct ipv_t
35 {
36     uint32_t ipversion;
37     uint32_t ipv4;
38     struct in6_addr_local ipv6;
39 } ipv_t;
40 
41 uint8_t COUNTRY_POSITION[25]             = {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};
42 uint8_t REGION_POSITION[25]              = {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};
43 uint8_t CITY_POSITION[25]                = {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};
44 uint8_t ISP_POSITION[25]                 = {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};
45 uint8_t LATITUDE_POSITION[25]            = {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};
46 uint8_t LONGITUDE_POSITION[25]           = {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};
47 uint8_t DOMAIN_POSITION[25]              = {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};
48 uint8_t ZIPCODE_POSITION[25]             = {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};
49 uint8_t TIMEZONE_POSITION[25]            = {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};
50 uint8_t NETSPEED_POSITION[25]            = {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};
51 uint8_t IDDCODE_POSITION[25]             = {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};
52 uint8_t AREACODE_POSITION[25]            = {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};
53 uint8_t WEATHERSTATIONCODE_POSITION[25]  = {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};
54 uint8_t WEATHERSTATIONNAME_POSITION[25]  = {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};
55 uint8_t MCC_POSITION[25]                 = {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};
56 uint8_t MNC_POSITION[25]                 = {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};
57 uint8_t MOBILEBRAND_POSITION[25]         = {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};
58 uint8_t ELEVATION_POSITION[25]           = {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};
59 uint8_t USAGETYPE_POSITION[25]           = {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};
60 
61 static int IP2Location_initialize(IP2Location *loc);
62 static IP2LocationRecord *IP2Location_new_record();
63 static uint32_t IP2Location_ip2no(char* ip);
64 static struct in6_addr_local  IP2Location_ipv6_to_no(char* ipaddr);
65 static int IP2Location_ip_is_ipv4 (char* ipaddr);
66 static int IP2Location_ip_is_ipv6 (char* ipaddr);
67 static IP2LocationRecord *IP2Location_get_record(IP2Location *loc, char *ip, uint32_t mode);
68 static IP2LocationRecord *IP2Location_get_ipv6_record(IP2Location *loc, char *ipstring, uint32_t mode, ipv_t parsed_ipv);
69 static int32_t openMemFlag = 0;
70 
71 // Description: Open the IP2Location database file
IP2Location_open(char * db)72 IP2Location *IP2Location_open(char *db)
73 {
74     FILE *f;
75     IP2Location *loc;
76 
77     if ((f = fopen( db, "rb")) == NULL)
78     {
79         printf("IP2Location library error in opening database %s.\n", db);
80         return NULL;
81     }
82 
83     loc = (IP2Location *) calloc(1, sizeof(IP2Location));
84     loc->filehandle = f;
85 
86     IP2Location_initialize(loc);
87     return loc;
88 }
89 
90 // Description: This function to set the DB access type.
IP2Location_open_mem(IP2Location * loc,enum IP2Location_mem_type mtype)91 int32_t IP2Location_open_mem(IP2Location *loc, enum IP2Location_mem_type mtype)
92 {
93     if( loc == NULL)
94         return -1;
95 
96     // Once IP2Location_open_mem is called, it can not be called again till IP2Location_close is called
97     if(openMemFlag != 0)
98         return -1;
99     openMemFlag = 1;
100 
101     if(mtype == IP2LOCATION_FILE_IO)
102     {
103         return 0; //Just return, by default its IP2LOCATION_FILE_IO
104     }
105     else if(mtype == IP2LOCATION_CACHE_MEMORY)
106     {
107         return IP2Location_DB_set_memory_cache(loc->filehandle);
108     }
109     else if (mtype == IP2LOCATION_SHARED_MEMORY)
110     {
111         return IP2Location_DB_set_shared_memory(loc->filehandle);
112     }
113     else
114         return -1;
115 }
116 
117 // Description: Close the IP2Location database file
IP2Location_close(IP2Location * loc)118 uint32_t IP2Location_close(IP2Location *loc)
119 {
120     openMemFlag = 0;
121     if (loc != NULL)
122     {
123         IP2Location_DB_close(loc->filehandle);
124         free(loc);
125     }
126 
127     return 0;
128 }
129 
130 // Description: Delete IP2Location shared memory if its present.
IP2Location_delete_shm()131 void IP2Location_delete_shm()
132 {
133     IP2Location_DB_del_shm();
134 }
135 
136 // Description: Startup
IP2Location_initialize(IP2Location * loc)137 static int IP2Location_initialize(IP2Location *loc)
138 {
139     loc->databasetype   = IP2Location_read8(loc->filehandle, 1);
140     loc->databasecolumn = IP2Location_read8(loc->filehandle, 2);
141     loc->databaseyear    = IP2Location_read8(loc->filehandle, 3);
142     loc->databasemonth  = IP2Location_read8(loc->filehandle, 4);
143     loc->databaseday   = IP2Location_read8(loc->filehandle, 5);
144 
145     loc->databasecount  = IP2Location_read32(loc->filehandle, 6);
146     loc->databaseaddr   = IP2Location_read32(loc->filehandle, 10);
147     loc->ipversion      = IP2Location_read32(loc->filehandle, 14);
148 
149     loc->ipv4databasecount  = IP2Location_read32(loc->filehandle, 6);
150     loc->ipv4databaseaddr   = IP2Location_read32(loc->filehandle, 10);
151     loc->ipv6databasecount  = IP2Location_read32(loc->filehandle, 14);
152     loc->ipv6databaseaddr   = IP2Location_read32(loc->filehandle, 18);
153 
154     loc->ipv4indexbaseaddr     = IP2Location_read32(loc->filehandle, 22);
155     loc->ipv6indexbaseaddr    = IP2Location_read32(loc->filehandle, 26);
156 
157     return 0;
158 }
159 
160 // Description: Compare to ipv6 address
ipv6_compare(struct in6_addr_local * addr1,struct in6_addr_local * addr2)161 int ipv6_compare(struct in6_addr_local *addr1, struct in6_addr_local *addr2)
162 {
163     int i, ret = 0;
164     for(i = 0 ; i < 16 ; i++ )
165     {
166         if(addr1->u.addr8[i] > addr2->u.addr8[i])
167         {
168             ret = 1;
169             break;
170         }
171         else if(addr1->u.addr8[i] < addr2->u.addr8[i])
172         {
173             ret = -1;
174             break;
175         }
176     }
177 
178     return ret;
179 }
180 
181 
182 // Parses IPv[46] addresses and returns both the version of address
183 // and binary address used for searching
184 // You can implement domain name lookup here as well
185 // ipversion will be -1 on error (or something other than 4 or 6)
IP2Location_parse_addr(const char * addr)186 static ipv_t IP2Location_parse_addr(const char *addr)
187 {
188     ipv_t parsed;
189     if (IP2Location_ip_is_ipv4((char *)addr))
190     {
191         parsed.ipversion = 4;
192         parsed.ipv4 = IP2Location_ip2no((char *)addr);
193     }
194     else if (IP2Location_ip_is_ipv6((char *)addr))
195     {
196         // Parse the v6 address
197         inet_pton(AF_INET6, addr, &parsed.ipv6);
198         if (parsed.ipv6.u.addr8[0] == 0 && parsed.ipv6.u.addr8[1] == 0 && parsed.ipv6.u.addr8[2] == 0 &&
199                 parsed.ipv6.u.addr8[3] == 0 && parsed.ipv6.u.addr8[4] == 0 && parsed.ipv6.u.addr8[5] == 0 &&
200                 parsed.ipv6.u.addr8[6] == 0 && parsed.ipv6.u.addr8[7] == 0 && parsed.ipv6.u.addr8[8] == 0 &&
201                 parsed.ipv6.u.addr8[9] == 0 && parsed.ipv6.u.addr8[10] == 255 && parsed.ipv6.u.addr8[11] == 255)
202         {
203             // IPv4 address in IPv6 format (::ffff:0.0.0.0 or ::ffff:00:00)
204             parsed.ipversion = 4;
205             parsed.ipv4 = (parsed.ipv6.u.addr8[12] << 24) + (parsed.ipv6.u.addr8[13] << 16) + (parsed.ipv6.u.addr8[14] << 8) + parsed.ipv6.u.addr8[15];
206         }
207         else
208         {
209             // pure IPv6 format
210             parsed.ipversion = 6;
211         }
212     }
213     else
214     {
215         parsed.ipversion = -1;
216     }
217 
218     return parsed;
219 }
220 
221 // Description: Get country code
IP2Location_get_country_short(IP2Location * loc,char * ip)222 IP2LocationRecord *IP2Location_get_country_short(IP2Location *loc, char *ip)
223 {
224     return IP2Location_get_record(loc, ip, COUNTRYSHORT);
225 }
226 
227 // Description: Get country name
IP2Location_get_country_long(IP2Location * loc,char * ip)228 IP2LocationRecord *IP2Location_get_country_long(IP2Location *loc, char *ip)
229 {
230     return IP2Location_get_record(loc, ip, COUNTRYLONG);
231 }
232 
233 // Description: Get the name of state/region
IP2Location_get_region(IP2Location * loc,char * ip)234 IP2LocationRecord *IP2Location_get_region(IP2Location *loc, char *ip)
235 {
236     return IP2Location_get_record(loc, ip, REGION);
237 }
238 
239 // Description: Get city name
IP2Location_get_city(IP2Location * loc,char * ip)240 IP2LocationRecord *IP2Location_get_city (IP2Location *loc, char *ip)
241 {
242     return IP2Location_get_record(loc, ip, CITY);
243 }
244 
245 // Description: Get ISP name
IP2Location_get_isp(IP2Location * loc,char * ip)246 IP2LocationRecord *IP2Location_get_isp(IP2Location *loc, char *ip)
247 {
248     return IP2Location_get_record(loc, ip, ISP);
249 }
250 
251 // Description: Get latitude
IP2Location_get_latitude(IP2Location * loc,char * ip)252 IP2LocationRecord *IP2Location_get_latitude(IP2Location *loc, char *ip)
253 {
254     return IP2Location_get_record(loc, ip, LATITUDE);
255 }
256 
257 // Description: Get longitude
IP2Location_get_longitude(IP2Location * loc,char * ip)258 IP2LocationRecord *IP2Location_get_longitude(IP2Location *loc, char *ip)
259 {
260     return IP2Location_get_record(loc, ip, LONGITUDE);
261 }
262 
263 // Description: Get domain name
IP2Location_get_domain(IP2Location * loc,char * ip)264 IP2LocationRecord *IP2Location_get_domain(IP2Location *loc, char *ip)
265 {
266     return IP2Location_get_record(loc, ip, DOMAIN_);
267 }
268 
269 // Description: Get ZIP code
IP2Location_get_zipcode(IP2Location * loc,char * ip)270 IP2LocationRecord *IP2Location_get_zipcode(IP2Location *loc, char *ip)
271 {
272     return IP2Location_get_record(loc, ip, ZIPCODE);
273 }
274 
275 // Description: Get time zone
IP2Location_get_timezone(IP2Location * loc,char * ip)276 IP2LocationRecord *IP2Location_get_timezone(IP2Location *loc, char *ip)
277 {
278     return IP2Location_get_record(loc, ip, TIMEZONE);
279 }
280 
281 // Description: Get net speed
IP2Location_get_netspeed(IP2Location * loc,char * ip)282 IP2LocationRecord *IP2Location_get_netspeed(IP2Location *loc, char *ip)
283 {
284     return IP2Location_get_record(loc, ip, NETSPEED);
285 }
286 
287 // Description: Get IDD code
IP2Location_get_iddcode(IP2Location * loc,char * ip)288 IP2LocationRecord *IP2Location_get_iddcode(IP2Location *loc, char *ip)
289 {
290     return IP2Location_get_record(loc, ip, IDDCODE);
291 }
292 
293 // Description: Get area code
IP2Location_get_areacode(IP2Location * loc,char * ip)294 IP2LocationRecord *IP2Location_get_areacode(IP2Location *loc, char *ip)
295 {
296     return IP2Location_get_record(loc, ip, AREACODE);
297 }
298 
299 // Description: Get weather station code
IP2Location_get_weatherstationcode(IP2Location * loc,char * ip)300 IP2LocationRecord *IP2Location_get_weatherstationcode(IP2Location *loc, char *ip)
301 {
302     return IP2Location_get_record(loc, ip, WEATHERSTATIONCODE);
303 }
304 
305 // Description: Get weather station name
IP2Location_get_weatherstationname(IP2Location * loc,char * ip)306 IP2LocationRecord *IP2Location_get_weatherstationname(IP2Location *loc, char *ip)
307 {
308     return IP2Location_get_record(loc, ip, WEATHERSTATIONNAME);
309 }
310 
311 // Description: Get mobile country code
IP2Location_get_mcc(IP2Location * loc,char * ip)312 IP2LocationRecord *IP2Location_get_mcc(IP2Location *loc, char *ip)
313 {
314     return IP2Location_get_record(loc, ip, MCC);
315 }
316 
317 // Description: Get mobile national code
IP2Location_get_mnc(IP2Location * loc,char * ip)318 IP2LocationRecord *IP2Location_get_mnc(IP2Location *loc, char *ip)
319 {
320     return IP2Location_get_record(loc, ip, MNC);
321 }
322 
323 // Description: Get mobile carrier brand
IP2Location_get_mobilebrand(IP2Location * loc,char * ip)324 IP2LocationRecord *IP2Location_get_mobilebrand(IP2Location *loc, char *ip)
325 {
326     return IP2Location_get_record(loc, ip, MOBILEBRAND);
327 }
328 
329 // Description: Get elevation
IP2Location_get_elevation(IP2Location * loc,char * ip)330 IP2LocationRecord *IP2Location_get_elevation(IP2Location *loc, char *ip)
331 {
332     return IP2Location_get_record(loc, ip, ELEVATION);
333 }
334 
335 // Description: Get usage type
IP2Location_get_usagetype(IP2Location * loc,char * ip)336 IP2LocationRecord *IP2Location_get_usagetype(IP2Location *loc, char *ip)
337 {
338     return IP2Location_get_record(loc, ip, USAGETYPE);
339 }
340 
341 // Description: Get all records of an IP address
IP2Location_get_all(IP2Location * loc,char * ip)342 IP2LocationRecord *IP2Location_get_all(IP2Location *loc, char *ip)
343 {
344     return IP2Location_get_record(loc, ip, ALL);
345 }
346 
347 // Description: fill the record fields with error message
IP2Location_bad_record(const char * message)348 static IP2LocationRecord *IP2Location_bad_record(const char *message)
349 {
350     IP2LocationRecord *record = IP2Location_new_record();
351     record->country_short = strdup(message);
352     record->country_long = strdup(message);
353     record->region = strdup(message);
354     record->city = strdup(message);
355     record->isp = strdup(message);
356     record->latitude = 0;
357     record->longitude = 0;
358     record->domain = strdup(message);
359     record->zipcode = strdup(message);
360     record->timezone = strdup(message);
361     record->netspeed = strdup(message);
362     record->iddcode = strdup(message);
363     record->areacode = strdup(message);
364     record->weatherstationcode = strdup(message);
365     record->weatherstationname = strdup(message);
366     record->mcc = strdup(message);
367     record->mnc = strdup(message);
368     record->mobilebrand = strdup(message);
369     record->elevation = 0;
370     record->usagetype = strdup(message);
371 
372     return record;
373 }
374 
375 // Description: read the record data
IP2Location_read_record(IP2Location * loc,uint32_t rowaddr,uint32_t mode)376 static IP2LocationRecord *IP2Location_read_record(IP2Location *loc, uint32_t rowaddr, uint32_t mode)
377 {
378     uint8_t dbtype = loc->databasetype;
379     FILE *handle = loc->filehandle;
380     IP2LocationRecord *record = IP2Location_new_record();
381 
382     if ((mode & COUNTRYSHORT) && (COUNTRY_POSITION[dbtype] != 0))
383     {
384         if (!record->country_short)
385         {
386             record->country_short = IP2Location_readStr(handle, IP2Location_read32(handle, rowaddr + 4 * (COUNTRY_POSITION[dbtype]-1)));
387         }
388     }
389     else
390     {
391         if (!record->country_short)
392         {
393             record->country_short = strdup(NOT_SUPPORTED);
394         }
395     }
396 
397     if ((mode & COUNTRYLONG) && (COUNTRY_POSITION[dbtype] != 0))
398     {
399         if (!record->country_long)
400         {
401             record->country_long = IP2Location_readStr(handle, IP2Location_read32(handle, rowaddr + 4 * (COUNTRY_POSITION[dbtype]-1))+3);
402         }
403     }
404     else
405     {
406         if (!record->country_long)
407         {
408             record->country_long = strdup(NOT_SUPPORTED);
409         }
410     }
411 
412     if ((mode & REGION) && (REGION_POSITION[dbtype] != 0))
413     {
414         if (!record->region)
415         {
416             record->region = IP2Location_readStr(handle, IP2Location_read32(handle, rowaddr + 4 * (REGION_POSITION[dbtype]-1)));
417         }
418     }
419     else
420     {
421         if (!record->region)
422         {
423             record->region = strdup(NOT_SUPPORTED);
424         }
425     }
426 
427     if ((mode & CITY) && (CITY_POSITION[dbtype] != 0))
428     {
429         if (!record->city)
430         {
431             record->city = IP2Location_readStr(handle, IP2Location_read32(handle, rowaddr + 4 * (CITY_POSITION[dbtype]-1)));
432         }
433     }
434     else
435     {
436         if (!record->city)
437         {
438             record->city = strdup(NOT_SUPPORTED);
439         }
440     }
441 
442     if ((mode & ISP) && (ISP_POSITION[dbtype] != 0))
443     {
444         if (!record->isp)
445         {
446             record->isp = IP2Location_readStr(handle, IP2Location_read32(handle, rowaddr + 4 * (ISP_POSITION[dbtype]-1)));
447         }
448     }
449     else
450     {
451         if (!record->isp)
452         {
453             record->isp = strdup(NOT_SUPPORTED);
454         }
455     }
456 
457     if ((mode & LATITUDE) && (LATITUDE_POSITION[dbtype] != 0))
458     {
459         record->latitude = IP2Location_readFloat(handle, rowaddr + 4 * (LATITUDE_POSITION[dbtype]-1));
460     }
461     else
462     {
463         record->latitude = 0.0;
464     }
465 
466     if ((mode & LONGITUDE) && (LONGITUDE_POSITION[dbtype] != 0))
467     {
468         record->longitude = IP2Location_readFloat(handle, rowaddr + 4 * (LONGITUDE_POSITION[dbtype]-1));
469     }
470     else
471     {
472         record->longitude = 0.0;
473     }
474 
475     if ((mode & DOMAIN_) && (DOMAIN_POSITION[dbtype] != 0))
476     {
477         if (!record->domain)
478         {
479             record->domain = IP2Location_readStr(handle, IP2Location_read32(handle, rowaddr + 4 * (DOMAIN_POSITION[dbtype]-1)));
480         }
481     }
482     else
483     {
484         if (!record->domain)
485         {
486             record->domain = strdup(NOT_SUPPORTED);
487         }
488     }
489 
490     if ((mode & ZIPCODE) && (ZIPCODE_POSITION[dbtype] != 0))
491     {
492         if (!record->zipcode)
493         {
494             record->zipcode = IP2Location_readStr(handle, IP2Location_read32(handle, rowaddr + 4 * (ZIPCODE_POSITION[dbtype]-1)));
495         }
496     }
497     else
498     {
499         if (!record->zipcode)
500         {
501             record->zipcode = strdup(NOT_SUPPORTED);
502         }
503     }
504 
505     if ((mode & TIMEZONE) && (TIMEZONE_POSITION[dbtype] != 0))
506     {
507         if (!record->timezone)
508         {
509             record->timezone = IP2Location_readStr(handle, IP2Location_read32(handle, rowaddr + 4 * (TIMEZONE_POSITION[dbtype]-1)));
510         }
511     }
512     else
513     {
514         if (!record->timezone)
515         {
516             record->timezone = strdup(NOT_SUPPORTED);
517         }
518     }
519 
520     if ((mode & NETSPEED) && (NETSPEED_POSITION[dbtype] != 0))
521     {
522         if (!record->netspeed)
523         {
524             record->netspeed = IP2Location_readStr(handle, IP2Location_read32(handle, rowaddr + 4 * (NETSPEED_POSITION[dbtype]-1)));
525         }
526     }
527     else
528     {
529         if (!record->netspeed)
530         {
531             record->netspeed = strdup(NOT_SUPPORTED);
532         }
533     }
534 
535     if ((mode & IDDCODE) && (IDDCODE_POSITION[dbtype] != 0))
536     {
537         if (!record->iddcode)
538         {
539             record->iddcode = IP2Location_readStr(handle, IP2Location_read32(handle, rowaddr + 4 * (IDDCODE_POSITION[dbtype]-1)));
540         }
541     }
542     else
543     {
544         if (!record->iddcode)
545         {
546             record->iddcode = strdup(NOT_SUPPORTED);
547         }
548     }
549 
550     if ((mode & AREACODE) && (AREACODE_POSITION[dbtype] != 0))
551     {
552         if (!record->areacode)
553         {
554             record->areacode = IP2Location_readStr(handle, IP2Location_read32(handle, rowaddr + 4 * (AREACODE_POSITION[dbtype]-1)));
555         }
556     }
557     else
558     {
559         if (!record->areacode)
560         {
561             record->areacode = strdup(NOT_SUPPORTED);
562         }
563     }
564 
565     if ((mode & WEATHERSTATIONCODE) && (WEATHERSTATIONCODE_POSITION[dbtype] != 0))
566     {
567         if (!record->weatherstationcode)
568         {
569             record->weatherstationcode = IP2Location_readStr(handle, IP2Location_read32(handle, rowaddr + 4 * (WEATHERSTATIONCODE_POSITION[dbtype]-1)));
570         }
571     }
572     else
573     {
574         if (!record->weatherstationcode)
575         {
576             record->weatherstationcode = strdup(NOT_SUPPORTED);
577         }
578     }
579 
580     if ((mode & WEATHERSTATIONNAME) && (WEATHERSTATIONNAME_POSITION[dbtype] != 0))
581     {
582         if (!record->weatherstationname)
583         {
584             record->weatherstationname = IP2Location_readStr(handle, IP2Location_read32(handle, rowaddr + 4 * (WEATHERSTATIONNAME_POSITION[dbtype]-1)));
585         }
586     }
587     else
588     {
589         if (!record->weatherstationname)
590         {
591             record->weatherstationname = strdup(NOT_SUPPORTED);
592         }
593     }
594 
595     if ((mode & MCC) && (MCC_POSITION[dbtype] != 0))
596     {
597         if (!record->mcc)
598         {
599             record->mcc = IP2Location_readStr(handle, IP2Location_read32(handle, rowaddr + 4 * (MCC_POSITION[dbtype]-1)));
600         }
601     }
602     else
603     {
604         if (!record->mcc)
605         {
606             record->mcc = strdup(NOT_SUPPORTED);
607         }
608     }
609 
610     if ((mode & MNC) && (MNC_POSITION[dbtype] != 0))
611     {
612         if (!record->mnc)
613         {
614             record->mnc = IP2Location_readStr(handle, IP2Location_read32(handle, rowaddr + 4 * (MNC_POSITION[dbtype]-1)));
615         }
616     }
617     else
618     {
619         if (!record->mnc)
620         {
621             record->mnc = strdup(NOT_SUPPORTED);
622         }
623     }
624 
625     if ((mode & MOBILEBRAND) && (MOBILEBRAND_POSITION[dbtype] != 0))
626     {
627         if (!record->mobilebrand)
628         {
629             record->mobilebrand = IP2Location_readStr(handle, IP2Location_read32(handle, rowaddr + 4 * (MOBILEBRAND_POSITION[dbtype]-1)));
630         }
631     }
632     else
633     {
634         if (!record->mobilebrand)
635         {
636             record->mobilebrand = strdup(NOT_SUPPORTED);
637         }
638     }
639 
640     if ((mode & ELEVATION) && (ELEVATION_POSITION[dbtype] != 0))
641     {
642         char *mem = IP2Location_readStr(handle, IP2Location_read32(handle, rowaddr + 4 * (ELEVATION_POSITION[dbtype]-1)));
643         record->elevation = atof(mem);
644         free(mem);
645     }
646     else
647     {
648         record->elevation = 0.0;
649     }
650 
651     if ((mode & USAGETYPE) && (USAGETYPE_POSITION[dbtype] != 0))
652     {
653         if (!record->usagetype)
654         {
655             record->usagetype = IP2Location_readStr(handle, IP2Location_read32(handle, rowaddr + 4 * (USAGETYPE_POSITION[dbtype]-1)));
656         }
657     }
658     else
659     {
660         if (!record->usagetype)
661         {
662             record->usagetype = strdup(NOT_SUPPORTED);
663         }
664     }
665     return record;
666 }
667 
668 // Description: Get record for a IPv6 from database
IP2Location_get_ipv6_record(IP2Location * loc,char * ipstring,uint32_t mode,ipv_t parsed_ipv)669 static IP2LocationRecord *IP2Location_get_ipv6_record(IP2Location *loc, char *ipstring, uint32_t mode, ipv_t parsed_ipv)
670 {
671     FILE *handle = loc->filehandle;
672     uint32_t baseaddr = loc->ipv6databaseaddr;
673     uint32_t dbcolumn = loc->databasecolumn;
674     uint32_t ipv6indexbaseaddr = loc->ipv6indexbaseaddr;
675 
676     uint32_t low = 0;
677     uint32_t high = loc->ipv6databasecount;
678     uint32_t mid = 0;
679 
680     struct in6_addr_local ipfrom;
681     struct in6_addr_local ipto;
682     struct in6_addr_local ipno;
683 
684     ipno = parsed_ipv.ipv6;
685 
686     if (!high)
687     {
688         return NULL;
689     }
690 
691     if (ipv6indexbaseaddr > 0)
692     {
693         // use the index table
694         uint32_t ipnum1 = (ipno.u.addr8[0] * 256) + ipno.u.addr8[1];
695         uint32_t indexpos = ipv6indexbaseaddr + (ipnum1 << 3);
696 
697         low = IP2Location_read32(handle, indexpos);
698         high = IP2Location_read32(handle, indexpos + 4);
699 
700     }
701 
702     while (low <= high)
703     {
704         mid = (uint32_t)((low + high) >> 1);
705         ipfrom = IP2Location_readIPv6Address(handle, baseaddr + mid * (dbcolumn * 4 + 12));
706         ipto = IP2Location_readIPv6Address(handle, baseaddr + ( mid + 1 ) * (dbcolumn * 4 + 12));
707 
708         if( (ipv6_compare(&ipno, &ipfrom) >= 0) && (ipv6_compare(&ipno, &ipto) < 0))
709         {
710             return IP2Location_read_record(loc, baseaddr + mid * (dbcolumn * 4 + 12) + 12, mode);
711         }
712         else
713         {
714             if ( ipv6_compare(&ipno, &ipfrom) < 0)
715             {
716                 high = mid - 1;
717             }
718             else
719             {
720                 low = mid + 1;
721             }
722         }
723     }
724     return NULL;
725 }
726 
727 // Description: Get record for a IPv4 from database
IP2Location_get_ipv4_record(IP2Location * loc,char * ipstring,uint32_t mode,ipv_t parsed_ipv)728 static IP2LocationRecord *IP2Location_get_ipv4_record(IP2Location *loc, char *ipstring, uint32_t mode, ipv_t parsed_ipv)
729 {
730     FILE *handle = loc->filehandle;
731     uint32_t baseaddr = loc->ipv4databaseaddr;
732     uint32_t dbcolumn = loc->databasecolumn;
733     uint32_t ipv4indexbaseaddr = loc->ipv4indexbaseaddr;
734 
735     uint32_t low = 0;
736     uint32_t high = loc->ipv4databasecount;
737     uint32_t mid = 0;
738 
739     uint32_t ipno;
740     uint32_t ipfrom;
741     uint32_t ipto;
742 
743     ipno = parsed_ipv.ipv4;
744     if (ipno == (uint32_t) MAX_IPV4_RANGE)
745     {
746         ipno = ipno - 1;
747     }
748 
749     if (ipv4indexbaseaddr > 0)
750     {
751         // use the index table
752         uint32_t ipnum1n2 = (uint32_t) ipno >> 16;
753         uint32_t indexpos = ipv4indexbaseaddr + (ipnum1n2 << 3);
754 
755         low = IP2Location_read32(handle, indexpos);
756         high = IP2Location_read32(handle, indexpos + 4);
757     }
758 
759     while (low <= high)
760     {
761         mid = (uint32_t)((low + high) >> 1);
762         ipfrom = IP2Location_read32(handle, baseaddr + mid * dbcolumn * 4);
763         ipto     = IP2Location_read32(handle, baseaddr + (mid + 1) * dbcolumn * 4);
764 
765         if ((ipno >= ipfrom) && (ipno < ipto))
766         {
767             return IP2Location_read_record(loc, baseaddr + (mid * dbcolumn * 4), mode);
768         }
769         else
770         {
771             if ( ipno < ipfrom )
772             {
773                 high = mid - 1;
774             }
775             else
776             {
777                 low = mid + 1;
778             }
779         }
780     }
781     return NULL;
782 }
783 
784 // Description: Get the location data
IP2Location_get_record(IP2Location * loc,char * ipstring,uint32_t mode)785 static IP2LocationRecord *IP2Location_get_record(IP2Location *loc, char *ipstring, uint32_t mode)
786 {
787     ipv_t parsed_ipv = IP2Location_parse_addr(ipstring);
788     if (parsed_ipv.ipversion == 4)
789     {
790         //process IPv4
791         return IP2Location_get_ipv4_record(loc, ipstring, mode, parsed_ipv);
792     }
793     if (parsed_ipv.ipversion == 6)
794     {
795         //process IPv6
796         return IP2Location_get_ipv6_record(loc, ipstring, mode, parsed_ipv);
797     }
798     else
799     {
800         return IP2Location_bad_record(INVALID_IPV4_ADDRESS);
801     }
802 }
803 
804 // Description: Initialize the record object
IP2Location_new_record()805 static IP2LocationRecord *IP2Location_new_record()
806 {
807     IP2LocationRecord *record = (IP2LocationRecord *) calloc(1, sizeof(IP2LocationRecord));
808     return record;
809 }
810 
811 // Description: Free the record object
IP2Location_free_record(IP2LocationRecord * record)812 void IP2Location_free_record(IP2LocationRecord *record)
813 {
814     if (record == NULL)
815     {
816         return;
817     }
818     free(record->city);
819     free(record->country_long);
820     free(record->country_short);
821     free(record->domain);
822     free(record->isp);
823     free(record->region);
824     free(record->zipcode);
825     free(record->timezone);
826     free(record->netspeed);
827     free(record->iddcode);
828     free(record->areacode);
829     free(record->weatherstationcode);
830     free(record->weatherstationname);
831     free(record->mcc);
832     free(record->mnc);
833     free(record->mobilebrand);
834     free(record->usagetype);
835     free(record);
836 }
837 
838 // Description: Convert the IP address (v4) into number
IP2Location_ip2no(char * ipstring)839 static uint32_t IP2Location_ip2no(char* ipstring)
840 {
841     uint32_t ip = inet_addr(ipstring);
842     uint8_t *ptr = (uint8_t *) &ip;
843     uint32_t a = 0;
844 
845     if (ipstring != NULL)
846     {
847         a =  (uint8_t)(ptr[3]);
848         a += (uint8_t)(ptr[2]) * 256;
849         a += (uint8_t)(ptr[1]) * 256 * 256;
850         a += (uint8_t)(ptr[0]) * 256 * 256 * 256;
851     }
852     return a;
853 }
854 
855 
856 // Description: Check if this was an IPv4 address
IP2Location_ip_is_ipv4(char * ipaddr)857 static int IP2Location_ip_is_ipv4 (char* ipaddr)
858 {
859     struct sockaddr_in sa;
860     return inet_pton(AF_INET, ipaddr, &(sa.sin_addr));
861 }
862 
863 // Description: Check if this was an IPv6 address
IP2Location_ip_is_ipv6(char * ipaddr)864 static int IP2Location_ip_is_ipv6 (char* ipaddr)
865 {
866     struct in6_addr_local ipv6;
867     return  inet_pton(AF_INET6, ipaddr, &ipv6);
868 }
869 
870 // Description: Return API version numeric
IP2Location_api_version_num(void)871 unsigned long int IP2Location_api_version_num(void)
872 {
873     return(API_VERSION_NUMERIC);
874 }
875 
876 // Description: Return API version as string
IP2Location_api_version_string(void)877 char *IP2Location_api_version_string(void)
878 {
879     static char version[64];
880     sprintf(version, "%d.%d.%d", API_VERSION_MAJOR, API_VERSION_MINOR, API_VERSION_RELEASE);
881     return(version);
882 }
883 
884 // Description: Return Library version as string
IP2Location_lib_version_string(void)885 char *IP2Location_lib_version_string(void)
886 {
887     return(PACKAGE_VERSION);
888 }
889 
890