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