+4003. [security] When geoip-directory was reconfigured during
+ named run-time, the previously loaded GeoIP
+ data could remain, potentially causing wrong
+ ACLs to be used or wrong results to be served
+ based on geolocation. [RT #37720]
+
+4002. [security] Lookups in GeoIP databases that were not
+ loaded could cause an assertion failure.
+ [RT #37679]
+
+4001. [security] The caching of GeoIP lookups did not always
+ handle address families correctly, potentially
+ resulting in an assertion failure. [RT #37672]
+
--- 9.10.1 released ---
3950. [port] Changed the bin/python Makefile to work around a
#ifndef HAVE_GEOIP
return;
#else
+ GeoIP_cleanup();
if (ns_g_geoip == NULL)
ns_g_geoip = &geoip_table;
#endif
# PERFORMANCE OF THIS SOFTWARE.
rm -f ns2/named.conf
-rm -f ns2/example[1234567].db
+rm -f ns2/example*.db
rm -f dig.out.* rndc.out.*
+rm -f data2/*dat
+[ -d data2 ] && rmdir data2
+rm -f ns?/named.run
+rm -f ns?/named.memstats
--- /dev/null
+/*
+ * Copyright (C) 2014 Internet Systems Consortium, Inc. ("ISC")
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+// NS2
+
+controls { /* empty */ };
+
+options {
+ query-source address 10.53.0.2;
+ notify-source 10.53.0.2;
+ transfer-source 10.53.0.2;
+ port 5300;
+ pid-file "named.pid";
+ listen-on { 10.53.0.2; };
+ listen-on-v6 { fd92:7065:b8e:ffff::2; };
+ recursion no;
+ geoip-directory "../data2";
+};
+
+key rndc_key {
+ secret "1234abcd8765";
+ algorithm hmac-sha256;
+};
+
+controls {
+ inet 10.53.0.2 port 9953 allow { any; } keys { rndc_key; };
+};
+
+view two {
+ match-clients { geoip country US; };
+ zone "example" {
+ type master;
+ file "../ns2/example2.db";
+ };
+};
+
+view none {
+ zone "example" {
+ type master;
+ file "examplebogus.db";
+ };
+};
port 5300;
pid-file "named.pid";
listen-on { 10.53.0.2; };
- listen-on-v6 { none; };
+ listen-on-v6 { fd92:7065:b8e:ffff::1; };
recursion no;
geoip-directory "../data";
};
cp ns2/named1.conf ns2/named.conf
-for i in 1 2 3 4 5 6 7; do
+for i in 1 2 3 4 5 6 7 other bogus; do
cp ns2/example.db.in ns2/example${i}.db
echo "@ IN TXT \"$i\"" >> ns2/example$i.db
done
+
+mkdir -p data2
+cp data/GeoIPv6.dat data2/
rm -f dig.out.*
DIGOPTS="+tcp +short -p 5300 @10.53.0.2"
+DIGOPTS6="+tcp +short -p 5300 @fd92:7065:b8e:ffff::2"
n=`expr $n + 1`
echo "I:checking GeoIP country database by code ($n)"
$RNDC -c ../common/rndc.conf -s 10.53.0.2 -p 9953 reload 2>&1 | sed 's/^/I:ns2 /'
sleep 3
+if $TESTSOCK6 fd92:7065:b8e:ffff::3
+then
+ n=`expr $n + 1`
+ echo "I:checking GeoIP city database by city name using IPv6 ($n)"
+ ret=0
+ $DIG +tcp +short -p 5300 @fd92:7065:b8e:ffff::1 -6 txt example -b fd92:7065:b8e:ffff::2 > dig.out.ns2.test$n || ret=1
+ [ $ret -eq 0 ] || echo "I:failed"
+ status=`expr $status + $ret`
+else
+ echo "I:IPv6 unavailable; skipping"
+fi
+
n=`expr $n + 1`
echo "I:checking GeoIP city database by city name ($n)"
ret=0
[ $ret -eq 0 ] || echo "I:failed"
status=`expr $status + $ret`
+n=`expr $n + 1`
+echo "I:reloading server with different geoip-directory ($n)"
+ret=0
+cp -f ns2/named15.conf ns2/named.conf
+$RNDC -c ../common/rndc.conf -s 10.53.0.2 -p 9953 reload 2>&1 | sed 's/^/I:ns2 /'
+sleep 3
+awk '/using "..\/data2" as GeoIP directory/ {m=1} ; { if (m>0) { print } }' ns2/named.run | grep "GeoIP City .* DB not available" > /dev/null || ret=1
+[ $ret -eq 0 ] || echo "I:failed"
+status=`expr $status + $ret`
+
+n=`expr $n + 1`
+echo "I:checking GeoIP v4/v6 when only IPv6 database is available ($n)"
+ret=0
+$DIG $DIGOPTS -4 txt example -b 10.53.0.2 > dig.out.ns2.test$n.1 || ret=1
+j=`cat dig.out.ns2.test$n.1 | tr -d '"'`
+[ "$j" = "bogus" ] || ret=1
+if $TESTSOCK6 fd92:7065:b8e:ffff::2; then
+ $DIG $DIGOPTS6 txt example -b fd92:7065:b8e:ffff::2 > dig.out.ns2.test$n.2 || ret=1
+ j=`cat dig.out.ns2.test$n.2 | tr -d '"'`
+ [ "$j" = "2" ] || ret=1
+fi
+[ $ret -eq 0 ] || echo "I:failed"
+status=`expr $status + $ret`
+
echo "I:exit status: $status"
exit $status
* so that successive lookups for the same data from the same IP
* address will not require repeated calls into the GeoIP library
* to look up data in the database. This should improve performance
- * somwhat.
+ * somewhat.
*
* For lookups in the City and Region databases, we preserve pointers
* to the GeoIPRecord and GeoIPregion structures; these will need to be
if (state == NULL)
return;
- if (state->record != NULL)
+ if (state->record != NULL) {
GeoIPRecord_delete(state->record);
- if (state->region != NULL)
+ state->record = NULL;
+ }
+ if (state->region != NULL) {
GeoIPRegion_delete(state->region);
- if (state->name != NULL)
+ state->region = NULL;
+ }
+ if (state->name != NULL) {
free (state->name);
+ state->name = NULL;
+ }
state->ipnum = 0;
state->text = NULL;
state->id = 0;
clean_state(state);
#else
state = &prev_state;
- if (state->ipnum != ipnum)
- clean_state(state);
+ clean_state(state);
#endif
if (family == AF_INET)
}
static geoip_state_t *
-get_state(void) {
+get_state_for(unsigned int family, isc_uint32_t ipnum,
+ const geoipv6_t *ipnum6)
+{
+ geoip_state_t *state;
+
#ifdef ISC_PLATFORM_USETHREADS
isc_result_t result;
- geoip_state_t *state;
result = state_key_init();
if (result != ISC_R_SUCCESS)
return (NULL);
state = (geoip_state_t *) isc_thread_key_getspecific(state_key);
- return (state);
+ if (state == NULL)
+ return (NULL);
#else
- return (&prev_state);
+ state = &prev_state;
#endif
+
+ if (state->family == family &&
+ ((state->family == AF_INET && state->ipnum == ipnum) ||
+ (state->family == AF_INET6 && ipnum6 != NULL &&
+ memcmp(state->ipnum6.s6_addr, ipnum6->s6_addr, 16) == 0)))
+ return (state);
+
+ return (NULL);
}
/*
return (NULL);
#endif
- prev_state = get_state();
-
- if (prev_state != NULL &&
- prev_state->subtype == subtype &&
- prev_state->family == family &&
- ((prev_state->family == AF_INET && prev_state->ipnum == ipnum) ||
- (prev_state->family == AF_INET6 && ipnum6 != NULL &&
- memcmp(prev_state->ipnum6.s6_addr, ipnum6->s6_addr, 16) == 0)))
+ prev_state = get_state_for(family, ipnum, ipnum6);
+ if (prev_state != NULL && prev_state->subtype == subtype)
text = prev_state->text;
if (text == NULL) {
return (NULL);
#endif
- prev_state = get_state();
-
- if (prev_state != NULL &&
- is_city(prev_state->subtype) &&
- ((prev_state->family == AF_INET && prev_state->ipnum == ipnum) ||
- (prev_state->family == AF_INET6 &&
- memcmp(prev_state->ipnum6.s6_addr, ipnum6->s6_addr, 16) == 0)))
+ prev_state = get_state_for(family, ipnum, ipnum6);
+ if (prev_state != NULL && is_city(prev_state->subtype))
record = prev_state->record;
if (record == NULL) {
REQUIRE(db != NULL);
- prev_state = get_state();
-
- if (prev_state != NULL && prev_state->ipnum == ipnum &&
- is_region(prev_state->subtype))
+ prev_state = get_state_for(AF_INET, ipnum, NULL);
+ if (prev_state != NULL && is_region(prev_state->subtype))
region = prev_state->region;
if (region == NULL) {
REQUIRE(db != NULL);
- prev_state = get_state();
-
- if (prev_state != NULL && prev_state->ipnum == ipnum &&
- prev_state->subtype == subtype)
+ prev_state = get_state_for(AF_INET, ipnum, NULL);
+ if (prev_state != NULL && prev_state->subtype == subtype)
name = prev_state->name;
if (name == NULL) {
REQUIRE(db != NULL);
- prev_state = get_state();
-
- if (prev_state != NULL && prev_state->ipnum == ipnum &&
- prev_state->subtype == subtype) {
+ prev_state = get_state_for(AF_INET, ipnum, NULL);
+ if (prev_state != NULL && prev_state->subtype == subtype) {
id = prev_state->id;
found = ISC_TRUE;
}
return (ISC_TRUE);
break;
+ case dns_geoip_countrycode:
+ case dns_geoip_countrycode3:
+ case dns_geoip_countryname:
+ case dns_geoip_regionname:
+ /*
+ * If these were not remapped by fix_subtype(),
+ * the database was unavailable. Always return false.
+ */
+ break;
+
default:
INSIST(0);
}
void
dns_geoip_shutdown(void) {
-#if defined(HAVE_GEOIP) && defined(ISC_PLATFORM_USETHREADS)
+#ifdef HAVE_GEOIP
+ GeoIP_cleanup();
+#ifdef ISC_PLATFORM_USETHREADS
if (state_mctx != NULL)
isc_mem_detach(&state_mctx);
+#endif
#else
return;
#endif