xref: /minix/external/bsd/bind/dist/lib/dns/geoip.c (revision 00b67f09)
1 /*	$NetBSD: geoip.c,v 1.1.1.6 2015/07/08 15:38:01 christos Exp $	*/
2 
3 /*
4  * Copyright (C) 2013-2015  Internet Systems Consortium, Inc. ("ISC")
5  *
6  * Permission to use, copy, modify, and/or distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
11  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
12  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
13  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
14  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
15  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
16  * PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 /*! \file */
20 
21 #include <config.h>
22 
23 #include <isc/util.h>
24 
25 #include <isc/mem.h>
26 #include <isc/once.h>
27 #include <isc/string.h>
28 
29 #include <dns/acl.h>
30 #include <dns/geoip.h>
31 
32 #include <isc/thread.h>
33 #include <math.h>
34 #ifndef WIN32
35 #include <netinet/in.h>
36 #else
37 #ifndef _WINSOCKAPI_
38 #define _WINSOCKAPI_   /* Prevent inclusion of winsock.h in windows.h */
39 #endif
40 #include <winsock2.h>
41 #endif	/* WIN32 */
42 #include <dns/log.h>
43 
44 #ifdef HAVE_GEOIP
45 #include <GeoIP.h>
46 #include <GeoIPCity.h>
47 
48 /*
49  * This structure preserves state from the previous GeoIP lookup,
50  * so that successive lookups for the same data from the same IP
51  * address will not require repeated calls into the GeoIP library
52  * to look up data in the database. This should improve performance
53  * somewhat.
54  *
55  * For lookups in the City and Region databases, we preserve pointers
56  * to the GeoIPRecord and GeoIPregion structures; these will need to be
57  * freed by GeoIPRecord_delete() and GeoIPRegion_delete().
58  *
59  * for lookups in ISP, AS, Org and Domain we prserve a pointer to
60  * the returned name; these must be freed by free().
61  *
62  * For lookups in Country we preserve a pointer to the text of
63  * the country code, name, etc (we use a different pointer for this
64  * than for the names returned by Org, ISP, etc, because those need
65  * to be freed but country lookups do not).
66  *
67  * For lookups in Netspeed we preserve the returned ID.
68  *
69  * XXX: Currently this mechanism is only used for IPv4 lookups; the
70  * family and addr6 fields are to be used IPv6 is added.
71  */
72 typedef struct geoip_state {
73 	isc_uint16_t subtype;
74 	unsigned int family;
75 	isc_uint32_t ipnum;
76 	geoipv6_t ipnum6;
77 	GeoIPRecord *record;
78 	GeoIPRegion *region;
79 	const char *text;
80 	char *name;
81 	int id;
82 	isc_mem_t *mctx;
83 } geoip_state_t;
84 
85 #ifdef ISC_PLATFORM_USETHREADS
86 static isc_mutex_t key_mutex;
87 static isc_boolean_t state_key_initialized = ISC_FALSE;
88 static isc_thread_key_t state_key;
89 static isc_once_t mutex_once = ISC_ONCE_INIT;
90 static isc_mem_t *state_mctx = NULL;
91 
92 static void
key_mutex_init(void)93 key_mutex_init(void) {
94 	RUNTIME_CHECK(isc_mutex_init(&key_mutex) == ISC_R_SUCCESS);
95 }
96 
97 static void
free_state(void * arg)98 free_state(void *arg) {
99 	geoip_state_t *state = arg;
100 	if (state != NULL && state->record != NULL)
101 		GeoIPRecord_delete(state->record);
102 	if (state != NULL)
103 		isc_mem_putanddetach(&state->mctx,
104 				     state, sizeof(geoip_state_t));
105 	isc_thread_key_setspecific(state_key, NULL);
106 }
107 
108 static isc_result_t
state_key_init(void)109 state_key_init(void) {
110 	isc_result_t result;
111 
112 	result = isc_once_do(&mutex_once, key_mutex_init);
113 	if (result != ISC_R_SUCCESS)
114 		return (result);
115 
116 	if (!state_key_initialized) {
117 		LOCK(&key_mutex);
118 		if (!state_key_initialized) {
119 			int ret;
120 
121 			if (state_mctx == NULL)
122 				result = isc_mem_create2(0, 0, &state_mctx, 0);
123 			if (result != ISC_R_SUCCESS)
124 				goto unlock;
125 			isc_mem_setname(state_mctx, "geoip_state", NULL);
126 			isc_mem_setdestroycheck(state_mctx, ISC_FALSE);
127 
128 			ret = isc_thread_key_create(&state_key, free_state);
129 			if (ret == 0)
130 				state_key_initialized = ISC_TRUE;
131 			else
132 				result = ISC_R_FAILURE;
133 		}
134  unlock:
135 		UNLOCK(&key_mutex);
136 	}
137 
138 	return (result);
139 }
140 #else
141 geoip_state_t prev_state;
142 #endif
143 
144 static void
clean_state(geoip_state_t * state)145 clean_state(geoip_state_t *state) {
146 	if (state == NULL)
147 		return;
148 
149 	if (state->record != NULL) {
150 		GeoIPRecord_delete(state->record);
151 		state->record = NULL;
152 	}
153 	if (state->region != NULL) {
154 		GeoIPRegion_delete(state->region);
155 		state->region = NULL;
156 	}
157 	if (state->name != NULL) {
158 		free (state->name);
159 		state->name = NULL;
160 	}
161 	state->ipnum = 0;
162 	state->text = NULL;
163 	state->id = 0;
164 }
165 
166 static isc_result_t
set_state(unsigned int family,isc_uint32_t ipnum,const geoipv6_t * ipnum6,dns_geoip_subtype_t subtype,GeoIPRecord * record,GeoIPRegion * region,char * name,const char * text,int id)167 set_state(unsigned int family, isc_uint32_t ipnum, const geoipv6_t *ipnum6,
168 	  dns_geoip_subtype_t subtype, GeoIPRecord *record,
169 	  GeoIPRegion *region, char *name, const char *text, int id)
170 {
171 	geoip_state_t *state = NULL;
172 
173 #ifdef ISC_PLATFORM_USETHREADS
174 	isc_result_t result;
175 
176 	result = state_key_init();
177 	if (result != ISC_R_SUCCESS)
178 		return (result);
179 
180 	state = (geoip_state_t *) isc_thread_key_getspecific(state_key);
181 	if (state == NULL) {
182 		state = (geoip_state_t *) isc_mem_get(state_mctx,
183 						      sizeof(geoip_state_t));
184 		if (state == NULL)
185 			return (ISC_R_NOMEMORY);
186 		memset(state, 0, sizeof(*state));
187 
188 		result = isc_thread_key_setspecific(state_key, state);
189 		if (result != ISC_R_SUCCESS) {
190 			isc_mem_put(state_mctx, state, sizeof(geoip_state_t));
191 			return (result);
192 		}
193 
194 		isc_mem_attach(state_mctx, &state->mctx);
195 	} else
196 		clean_state(state);
197 #else
198 	state = &prev_state;
199 	clean_state(state);
200 #endif
201 
202 	if (family == AF_INET)
203 		state->ipnum = ipnum;
204 	else
205 		state->ipnum6 = *ipnum6;
206 
207 	state->family = family;
208 	state->subtype = subtype;
209 	state->record = record;
210 	state->region = region;
211 	state->name = name;
212 	state->text = text;
213 	state->id = id;
214 
215 	return (ISC_R_SUCCESS);
216 }
217 
218 static geoip_state_t *
get_state_for(unsigned int family,isc_uint32_t ipnum,const geoipv6_t * ipnum6)219 get_state_for(unsigned int family, isc_uint32_t ipnum,
220 	      const geoipv6_t *ipnum6)
221 {
222 	geoip_state_t *state;
223 
224 #ifdef ISC_PLATFORM_USETHREADS
225 	isc_result_t result;
226 
227 	result = state_key_init();
228 	if (result != ISC_R_SUCCESS)
229 		return (NULL);
230 
231 	state = (geoip_state_t *) isc_thread_key_getspecific(state_key);
232 	if (state == NULL)
233 		return (NULL);
234 #else
235 	state = &prev_state;
236 #endif
237 
238 	if (state->family == family &&
239 	    ((state->family == AF_INET && state->ipnum == ipnum) ||
240 	     (state->family == AF_INET6 && ipnum6 != NULL &&
241 	      memcmp(state->ipnum6.s6_addr, ipnum6->s6_addr, 16) == 0)))
242 		return (state);
243 
244 	return (NULL);
245 }
246 
247 /*
248  * Country lookups are performed if the previous lookup was from a
249  * different IP address than the current, or was for a search of a
250  * different subtype.
251  */
252 static const char *
country_lookup(GeoIP * db,dns_geoip_subtype_t subtype,unsigned int family,isc_uint32_t ipnum,const geoipv6_t * ipnum6)253 country_lookup(GeoIP *db, dns_geoip_subtype_t subtype,
254 	       unsigned int family,
255 	       isc_uint32_t ipnum, const geoipv6_t *ipnum6)
256 {
257 	geoip_state_t *prev_state = NULL;
258 	const char *text = NULL;
259 
260 	REQUIRE(db != NULL);
261 
262 #ifndef HAVE_GEOIP_V6
263 	/* no IPv6 support? give up now */
264 	if (family == AF_INET6)
265 		return (NULL);
266 #endif
267 
268 	prev_state = get_state_for(family, ipnum, ipnum6);
269 	if (prev_state != NULL && prev_state->subtype == subtype)
270 		text = prev_state->text;
271 
272 	if (text == NULL) {
273 		switch (subtype) {
274 		case dns_geoip_country_code:
275 			if (family == AF_INET)
276 				text = GeoIP_country_code_by_ipnum(db, ipnum);
277 #ifdef HAVE_GEOIP_V6
278 			else
279 				text = GeoIP_country_code_by_ipnum_v6(db,
280 								      *ipnum6);
281 #endif
282 			break;
283 		case dns_geoip_country_code3:
284 			if (family == AF_INET)
285 				text = GeoIP_country_code3_by_ipnum(db, ipnum);
286 #ifdef HAVE_GEOIP_V6
287 			else
288 				text = GeoIP_country_code3_by_ipnum_v6(db,
289 								       *ipnum6);
290 #endif
291 			break;
292 		case dns_geoip_country_name:
293 			if (family == AF_INET)
294 				text = GeoIP_country_name_by_ipnum(db, ipnum);
295 #ifdef HAVE_GEOIP_V6
296 			else
297 				text = GeoIP_country_name_by_ipnum_v6(db,
298 								      *ipnum6);
299 #endif
300 			break;
301 		default:
302 			INSIST(0);
303 		}
304 
305 		set_state(family, ipnum, ipnum6, subtype,
306 			  NULL, NULL, NULL, text, 0);
307 	}
308 
309 	return (text);
310 }
311 
312 static char *
city_string(GeoIPRecord * record,dns_geoip_subtype_t subtype,int * maxlen)313 city_string(GeoIPRecord *record, dns_geoip_subtype_t subtype, int *maxlen) {
314 	const char *s;
315 	char *deconst;
316 
317 	REQUIRE(record != NULL);
318 	REQUIRE(maxlen != NULL);
319 
320 	/* Set '*maxlen' to the maximum length of this subtype, if any */
321 	switch (subtype) {
322 	case dns_geoip_city_countrycode:
323 	case dns_geoip_city_region:
324 	case dns_geoip_city_continentcode:
325 		*maxlen = 2;
326 		break;
327 
328 	case dns_geoip_city_countrycode3:
329 		*maxlen = 3;
330 		break;
331 
332 	default:
333 		/* No fixed length; just use strcasecmp() for comparison */
334 		*maxlen = 255;
335 	}
336 
337 	switch (subtype) {
338 	case dns_geoip_city_countrycode:
339 		return (record->country_code);
340 	case dns_geoip_city_countrycode3:
341 		return (record->country_code3);
342 	case dns_geoip_city_countryname:
343 		return (record->country_name);
344 	case dns_geoip_city_region:
345 		return (record->region);
346 	case dns_geoip_city_regionname:
347 		s = GeoIP_region_name_by_code(record->country_code,
348 					      record->region);
349 		DE_CONST(s, deconst);
350 		return (deconst);
351 	case dns_geoip_city_name:
352 		return (record->city);
353 	case dns_geoip_city_postalcode:
354 		return (record->postal_code);
355 	case dns_geoip_city_continentcode:
356 		return (record->continent_code);
357 	case dns_geoip_city_timezonecode:
358 		s = GeoIP_time_zone_by_country_and_region(record->country_code,
359 							  record->region);
360 		DE_CONST(s, deconst);
361 		return (deconst);
362 	default:
363 		INSIST(0);
364 	}
365 }
366 
367 static isc_boolean_t
is_city(dns_geoip_subtype_t subtype)368 is_city(dns_geoip_subtype_t subtype) {
369 	switch (subtype) {
370 	case dns_geoip_city_countrycode:
371 	case dns_geoip_city_countrycode3:
372 	case dns_geoip_city_countryname:
373 	case dns_geoip_city_region:
374 	case dns_geoip_city_regionname:
375 	case dns_geoip_city_name:
376 	case dns_geoip_city_postalcode:
377 	case dns_geoip_city_continentcode:
378 	case dns_geoip_city_timezonecode:
379 	case dns_geoip_city_metrocode:
380 	case dns_geoip_city_areacode:
381 		return (ISC_TRUE);
382 	default:
383 		return (ISC_FALSE);
384 	}
385 }
386 
387 /*
388  * GeoIPRecord lookups are performed if the previous lookup was
389  * from a different IP address than the current, or was for a search
390  * outside the City database.
391  */
392 static GeoIPRecord *
city_lookup(GeoIP * db,dns_geoip_subtype_t subtype,unsigned int family,isc_uint32_t ipnum,const geoipv6_t * ipnum6)393 city_lookup(GeoIP *db, dns_geoip_subtype_t subtype,
394 	    unsigned int family, isc_uint32_t ipnum, const geoipv6_t *ipnum6)
395 {
396 	GeoIPRecord *record = NULL;
397 	geoip_state_t *prev_state = NULL;
398 
399 	REQUIRE(db != NULL);
400 
401 #ifndef HAVE_GEOIP_V6
402 	/* no IPv6 support? give up now */
403 	if (family == AF_INET6)
404 		return (NULL);
405 #endif
406 
407 	prev_state = get_state_for(family, ipnum, ipnum6);
408 	if (prev_state != NULL && is_city(prev_state->subtype))
409 		record = prev_state->record;
410 
411 	if (record == NULL) {
412 		if (family == AF_INET)
413 			record = GeoIP_record_by_ipnum(db, ipnum);
414 #ifdef HAVE_GEOIP_V6
415 		else
416 			record = GeoIP_record_by_ipnum_v6(db, *ipnum6);
417 #endif
418 		if (record == NULL)
419 			return (NULL);
420 
421 		set_state(family, ipnum, ipnum6, subtype,
422 			  record, NULL, NULL, NULL, 0);
423 	}
424 
425 	return (record);
426 }
427 
428 static char *
region_string(GeoIPRegion * region,dns_geoip_subtype_t subtype,int * maxlen)429 region_string(GeoIPRegion *region, dns_geoip_subtype_t subtype, int *maxlen) {
430 	const char *s;
431 	char *deconst;
432 
433 	REQUIRE(region != NULL);
434 	REQUIRE(maxlen != NULL);
435 
436 	switch (subtype) {
437 	case dns_geoip_region_countrycode:
438 		*maxlen = 2;
439 		return (region->country_code);
440 	case dns_geoip_region_code:
441 		*maxlen = 2;
442 		return (region->region);
443 	case dns_geoip_region_name:
444 		*maxlen = 255;
445 		s = GeoIP_region_name_by_code(region->country_code,
446 					      region->region);
447 		DE_CONST(s, deconst);
448 		return (deconst);
449 	default:
450 		INSIST(0);
451 	}
452 }
453 
454 static isc_boolean_t
is_region(dns_geoip_subtype_t subtype)455 is_region(dns_geoip_subtype_t subtype) {
456 	switch (subtype) {
457 	case dns_geoip_region_countrycode:
458 	case dns_geoip_region_code:
459 		return (ISC_TRUE);
460 	default:
461 		return (ISC_FALSE);
462 	}
463 }
464 
465 /*
466  * GeoIPRegion lookups are performed if the previous lookup was
467  * from a different IP address than the current, or was for a search
468  * outside the Region database.
469  */
470 static GeoIPRegion *
region_lookup(GeoIP * db,dns_geoip_subtype_t subtype,isc_uint32_t ipnum)471 region_lookup(GeoIP *db, dns_geoip_subtype_t subtype, isc_uint32_t ipnum) {
472 	GeoIPRegion *region = NULL;
473 	geoip_state_t *prev_state = NULL;
474 
475 	REQUIRE(db != NULL);
476 
477 	prev_state = get_state_for(AF_INET, ipnum, NULL);
478 	if (prev_state != NULL && is_region(prev_state->subtype))
479 		region = prev_state->region;
480 
481 	if (region == NULL) {
482 		region = GeoIP_region_by_ipnum(db, ipnum);
483 		if (region == NULL)
484 			return (NULL);
485 
486 		set_state(AF_INET, ipnum, NULL,
487 			  subtype, NULL, region, NULL, NULL, 0);
488 	}
489 
490 	return (region);
491 }
492 
493 /*
494  * ISP, Organization, AS Number and Domain lookups are performed if
495  * the previous lookup was from a different IP address than the current,
496  * or was for a search of a different subtype.
497  */
498 static char *
name_lookup(GeoIP * db,dns_geoip_subtype_t subtype,isc_uint32_t ipnum)499 name_lookup(GeoIP *db, dns_geoip_subtype_t subtype, isc_uint32_t ipnum) {
500 	char *name = NULL;
501 	geoip_state_t *prev_state = NULL;
502 
503 	REQUIRE(db != NULL);
504 
505 	prev_state = get_state_for(AF_INET, ipnum, NULL);
506 	if (prev_state != NULL && prev_state->subtype == subtype)
507 		name = prev_state->name;
508 
509 	if (name == NULL) {
510 		name = GeoIP_name_by_ipnum(db, ipnum);
511 		if (name == NULL)
512 			return (NULL);
513 
514 		set_state(AF_INET, ipnum, NULL,
515 			  subtype, NULL, NULL, name, NULL, 0);
516 	}
517 
518 	return (name);
519 }
520 
521 /*
522  * Netspeed lookups are performed if the previous lookup was from a
523  * different IP address than the current, or was for a search of a
524  * different subtype.
525  */
526 static int
netspeed_lookup(GeoIP * db,dns_geoip_subtype_t subtype,isc_uint32_t ipnum)527 netspeed_lookup(GeoIP *db, dns_geoip_subtype_t subtype, isc_uint32_t ipnum) {
528 	geoip_state_t *prev_state = NULL;
529 	isc_boolean_t found = ISC_FALSE;
530 	int id = -1;
531 
532 	REQUIRE(db != NULL);
533 
534 	prev_state = get_state_for(AF_INET, ipnum, NULL);
535 	if (prev_state != NULL && prev_state->subtype == subtype) {
536 		id = prev_state->id;
537 		found = ISC_TRUE;
538 	}
539 
540 	if (!found) {
541 		id = GeoIP_id_by_ipnum(db, ipnum);
542 		set_state(AF_INET, ipnum, NULL,
543 			  subtype, NULL, NULL, NULL, NULL, id);
544 	}
545 
546 	return (id);
547 }
548 #endif /* HAVE_GEOIP */
549 
550 #define DB46(addr, geoip, name) \
551 	((addr->family == AF_INET) ? (geoip->name##_v4) : (geoip->name##_v6))
552 
553 #ifdef HAVE_GEOIP
554 /*
555  * Find the best database to answer a generic subtype
556  */
557 static dns_geoip_subtype_t
fix_subtype(const isc_netaddr_t * reqaddr,const dns_geoip_databases_t * geoip,dns_geoip_subtype_t subtype)558 fix_subtype(const isc_netaddr_t *reqaddr, const dns_geoip_databases_t *geoip,
559 	    dns_geoip_subtype_t subtype)
560 {
561 	dns_geoip_subtype_t ret = subtype;
562 
563 	switch (subtype) {
564 	case dns_geoip_countrycode:
565 		if (DB46(reqaddr, geoip, city) != NULL)
566 			ret = dns_geoip_city_countrycode;
567 		else if (reqaddr->family == AF_INET && geoip->region != NULL)
568 			ret = dns_geoip_region_countrycode;
569 		else if (DB46(reqaddr, geoip, country) != NULL)
570 			ret = dns_geoip_country_code;
571 		break;
572 	case dns_geoip_countrycode3:
573 		if (DB46(reqaddr, geoip, city) != NULL)
574 			ret = dns_geoip_city_countrycode3;
575 		else if (DB46(reqaddr, geoip, country) != NULL)
576 			ret = dns_geoip_country_code3;
577 		break;
578 	case dns_geoip_countryname:
579 		if (DB46(reqaddr, geoip, city) != NULL)
580 			ret = dns_geoip_city_countryname;
581 		else if (DB46(reqaddr, geoip, country) != NULL)
582 			ret = dns_geoip_country_name;
583 		break;
584 	case dns_geoip_region:
585 		if (DB46(reqaddr, geoip, city) != NULL)
586 			ret = dns_geoip_city_region;
587 		else if (reqaddr->family == AF_INET && geoip->region != NULL)
588 			ret = dns_geoip_region_code;
589 		break;
590 	case dns_geoip_regionname:
591 		if (DB46(reqaddr, geoip, city) != NULL)
592 			ret = dns_geoip_city_regionname;
593 		else if (reqaddr->family == AF_INET && geoip->region != NULL)
594 			ret = dns_geoip_region_name;
595 		break;
596 	default:
597 		break;
598 	}
599 
600 	return (ret);
601 }
602 #endif /* HAVE_GEOIP */
603 
604 isc_boolean_t
dns_geoip_match(const isc_netaddr_t * reqaddr,const dns_geoip_databases_t * geoip,const dns_geoip_elem_t * elt)605 dns_geoip_match(const isc_netaddr_t *reqaddr,
606 		const dns_geoip_databases_t *geoip,
607 		const dns_geoip_elem_t *elt)
608 {
609 #ifndef HAVE_GEOIP
610 	UNUSED(reqaddr);
611 	UNUSED(geoip);
612 	UNUSED(elt);
613 
614 	return (ISC_FALSE);
615 #else
616 	GeoIP *db;
617 	GeoIPRecord *record;
618 	GeoIPRegion *region;
619 	dns_geoip_subtype_t subtype;
620 	isc_uint32_t ipnum = 0;
621 	int maxlen = 0, id, family;
622 	const char *cs;
623 	char *s;
624 #ifdef HAVE_GEOIP_V6
625 	const geoipv6_t *ipnum6 = NULL;
626 #else
627 	const void *ipnum6 = NULL;
628 #endif
629 
630 	INSIST(geoip != NULL);
631 
632 	family = reqaddr->family;
633 	switch (family) {
634 	case AF_INET:
635 		ipnum = ntohl(reqaddr->type.in.s_addr);
636 		break;
637 	case AF_INET6:
638 #ifdef HAVE_GEOIP_V6
639 		ipnum6 = &reqaddr->type.in6;
640 		break;
641 #else
642 		return (ISC_FALSE);
643 #endif
644 	default:
645 		return (ISC_FALSE);
646 	}
647 
648 	subtype = fix_subtype(reqaddr, geoip, elt->subtype);
649 
650 	switch (subtype) {
651 	case dns_geoip_country_code:
652 		maxlen = 2;
653 		goto getcountry;
654 
655 	case dns_geoip_country_code3:
656 		maxlen = 3;
657 		goto getcountry;
658 
659 	case dns_geoip_country_name:
660 		maxlen = 255;
661  getcountry:
662 		db = DB46(reqaddr, geoip, country);
663 		if (db == NULL)
664 			return (ISC_FALSE);
665 
666 		INSIST(elt->as_string != NULL);
667 
668 		cs = country_lookup(db, subtype, family, ipnum, ipnum6);
669 		if (cs != NULL && strncasecmp(elt->as_string, cs, maxlen) == 0)
670 			return (ISC_TRUE);
671 		break;
672 
673 	case dns_geoip_city_countrycode:
674 	case dns_geoip_city_countrycode3:
675 	case dns_geoip_city_countryname:
676 	case dns_geoip_city_region:
677 	case dns_geoip_city_regionname:
678 	case dns_geoip_city_name:
679 	case dns_geoip_city_postalcode:
680 	case dns_geoip_city_continentcode:
681 	case dns_geoip_city_timezonecode:
682 		INSIST(elt->as_string != NULL);
683 
684 		db = DB46(reqaddr, geoip, city);
685 		if (db == NULL)
686 			return (ISC_FALSE);
687 
688 		record = city_lookup(db, subtype, family, ipnum, ipnum6);
689 		if (record == NULL)
690 			break;
691 
692 		s = city_string(record, subtype, &maxlen);
693 		INSIST(maxlen != 0);
694 		if (s != NULL && strncasecmp(elt->as_string, s, maxlen) == 0)
695 			return (ISC_TRUE);
696 		break;
697 
698 	case dns_geoip_city_metrocode:
699 		db = DB46(reqaddr, geoip, city);
700 		if (db == NULL)
701 			return (ISC_FALSE);
702 
703 		record = city_lookup(db, subtype, family, ipnum, ipnum6);
704 		if (record == NULL)
705 			break;
706 
707 		if (elt->as_int == record->metro_code)
708 			return (ISC_TRUE);
709 		break;
710 
711 	case dns_geoip_city_areacode:
712 		db = DB46(reqaddr, geoip, city);
713 		if (db == NULL)
714 			return (ISC_FALSE);
715 
716 		record = city_lookup(db, subtype, family, ipnum, ipnum6);
717 		if (record == NULL)
718 			break;
719 
720 		if (elt->as_int == record->area_code)
721 			return (ISC_TRUE);
722 		break;
723 
724 	case dns_geoip_region_countrycode:
725 	case dns_geoip_region_code:
726 	case dns_geoip_region_name:
727 	case dns_geoip_region:
728 		if (geoip->region == NULL)
729 			return (ISC_FALSE);
730 
731 		INSIST(elt->as_string != NULL);
732 
733 		/* Region DB is not supported for IPv6 */
734 		if (family == AF_INET6)
735 			return (ISC_FALSE);
736 
737 		region = region_lookup(geoip->region, subtype, ipnum);
738 		if (region == NULL)
739 			break;
740 
741 		s = region_string(region, subtype, &maxlen);
742 		INSIST(maxlen != 0);
743 		if (s != NULL && strncasecmp(elt->as_string, s, maxlen) == 0)
744 			return (ISC_TRUE);
745 		break;
746 
747 	case dns_geoip_isp_name:
748 		db = geoip->isp;
749 		goto getname;
750 
751 	case dns_geoip_org_name:
752 		db = geoip->org;
753 		goto getname;
754 
755 	case dns_geoip_as_asnum:
756 		db = geoip->as;
757 		goto getname;
758 
759 	case dns_geoip_domain_name:
760 		db = geoip->domain;
761 
762  getname:
763 		if (db == NULL)
764 			return (ISC_FALSE);
765 
766 		INSIST(elt->as_string != NULL);
767 		/* ISP, Org, AS, and Domain are not supported for IPv6 */
768 		if (family == AF_INET6)
769 			return (ISC_FALSE);
770 
771 		s = name_lookup(db, subtype, ipnum);
772 		if (s != NULL) {
773 			size_t l;
774 			if (strcasecmp(elt->as_string, s) == 0)
775 				return (ISC_TRUE);
776 			if (subtype != dns_geoip_as_asnum)
777 				break;
778 			/*
779 			 * Just check if the ASNNNN value matches.
780 			 */
781 			l = strlen(elt->as_string);
782 			if (l > 0U && strchr(elt->as_string, ' ') == NULL &&
783 			    strncasecmp(elt->as_string, s, l) == 0 &&
784 			    s[l] == ' ')
785 				return (ISC_TRUE);
786 		}
787 		break;
788 
789 	case dns_geoip_netspeed_id:
790 		INSIST(geoip->netspeed != NULL);
791 
792 		/* Netspeed DB is not supported for IPv6 */
793 		if (family == AF_INET6)
794 			return (ISC_FALSE);
795 
796 		id = netspeed_lookup(geoip->netspeed, subtype, ipnum);
797 		if (id == elt->as_int)
798 			return (ISC_TRUE);
799 		break;
800 
801 	case dns_geoip_countrycode:
802 	case dns_geoip_countrycode3:
803 	case dns_geoip_countryname:
804 	case dns_geoip_regionname:
805 		/*
806 		 * If these were not remapped by fix_subtype(),
807 		 * the database was unavailable. Always return false.
808 		 */
809 		break;
810 
811 	default:
812 		INSIST(0);
813 	}
814 
815 	return (ISC_FALSE);
816 #endif
817 }
818 
819 void
dns_geoip_shutdown(void)820 dns_geoip_shutdown(void) {
821 #ifdef HAVE_GEOIP
822 	GeoIP_cleanup();
823 #ifdef ISC_PLATFORM_USETHREADS
824 	if (state_mctx != NULL)
825 		isc_mem_detach(&state_mctx);
826 #endif
827 #else
828 	return;
829 #endif
830 }
831