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