Separate IPv4 and IPv6 geoip file loading.

Also add IPv6 geoip file digest to extra info.

Also also, add support for IPv6 addresses in control command
"ip-to-country".
This commit is contained in:
Linus Nordberg 2012-10-20 18:48:58 +02:00
parent e2313d8622
commit 817ff962f8
5 changed files with 59 additions and 46 deletions

View File

@ -1512,10 +1512,10 @@ options_act(const or_options_t *old_options)
connection_or_update_token_buckets(get_connection_array(), options); connection_or_update_token_buckets(get_connection_array(), options);
} }
/* Maybe load geoip file */ /* Maybe load IPv4 geoip file */
if (options->GeoIPFile && if (options->GeoIPFile &&
((!old_options || !opt_streq(old_options->GeoIPFile, options->GeoIPFile)) ((!old_options || !opt_streq(old_options->GeoIPFile, options->GeoIPFile))
|| !geoip_is_loaded())) { || !geoip_is_loaded(AF_INET))) {
/* XXXX Don't use this "<default>" junk; make our filename options /* XXXX Don't use this "<default>" junk; make our filename options
* understand prefixes somehow. -NM */ * understand prefixes somehow. -NM */
/* XXXX024 Reload GeoIPFile on SIGHUP. -NM */ /* XXXX024 Reload GeoIPFile on SIGHUP. -NM */
@ -1530,11 +1530,11 @@ options_act(const or_options_t *old_options)
geoip_load_file(AF_INET, actual_fname, options); geoip_load_file(AF_INET, actual_fname, options);
tor_free(actual_fname); tor_free(actual_fname);
} }
/* And maybe load geoip ipv6 file */ /* And maybe load IPv6 geoip file */
if (options->GeoIPv6File && if (options->GeoIPv6File &&
((!old_options || !opt_streq(old_options->GeoIPv6File, ((!old_options || !opt_streq(old_options->GeoIPv6File,
options->GeoIPv6File)) options->GeoIPv6File))
|| !geoip_is_loaded())) { || !geoip_is_loaded(AF_INET6))) {
/* XXXX Don't use this "<default>" junk; make our filename options /* XXXX Don't use this "<default>" junk; make our filename options
* understand prefixes somehow. See also comment for GeoIPFile. */ * understand prefixes somehow. See also comment for GeoIPFile. */
/* XXXX024 Reload GeoIPV6File on SIGHUP. See also comment for /* XXXX024 Reload GeoIPV6File on SIGHUP. See also comment for
@ -1573,7 +1573,7 @@ options_act(const or_options_t *old_options)
} }
if ((!old_options || !old_options->DirReqStatistics) && if ((!old_options || !old_options->DirReqStatistics) &&
options->DirReqStatistics) { options->DirReqStatistics) {
if (geoip_is_loaded()) { if (geoip_is_loaded(AF_INET)) {
geoip_dirreq_stats_init(now); geoip_dirreq_stats_init(now);
print_notice = 1; print_notice = 1;
} else { } else {
@ -1588,7 +1588,7 @@ options_act(const or_options_t *old_options)
} }
if ((!old_options || !old_options->EntryStatistics) && if ((!old_options || !old_options->EntryStatistics) &&
options->EntryStatistics && !should_record_bridge_info(options)) { options->EntryStatistics && !should_record_bridge_info(options)) {
if (geoip_is_loaded()) { if (geoip_is_loaded(AF_INET) || geoip_is_loaded(AF_INET6)) {
geoip_entry_stats_init(now); geoip_entry_stats_init(now);
print_notice = 1; print_notice = 1;
} else { } else {

View File

@ -52,8 +52,9 @@ static strmap_t *country_idxplus1_by_lc_code = NULL;
* by their respective ip_low. */ * by their respective ip_low. */
static smartlist_t *geoip_ipv4_entries = NULL, *geoip_ipv6_entries = NULL; static smartlist_t *geoip_ipv4_entries = NULL, *geoip_ipv6_entries = NULL;
/** SHA1 digest of the GeoIP file to include in extra-info descriptors. */ /** SHA1 digest of the GeoIP files to include in extra-info descriptors. */
static char geoip_digest[DIGEST_LEN]; static char geoip_digest[DIGEST_LEN];
static char geoip6_digest[DIGEST_LEN];
/** Return the index of the <b>country</b>'s entry in the GeoIP DB /** Return the index of the <b>country</b>'s entry in the GeoIP DB
* if it is a valid 2-letter country code, otherwise return -1. * if it is a valid 2-letter country code, otherwise return -1.
@ -376,22 +377,20 @@ geoip_load_file(sa_family_t family, const char *filename,
/*XXXX abort and return -1 if no entries/illformed?*/ /*XXXX abort and return -1 if no entries/illformed?*/
fclose(f); fclose(f);
if (family == AF_INET) /* Sort list and remember file digests so that we can include it in
* our extra-info descriptors. */
if (family == AF_INET) {
smartlist_sort(geoip_ipv4_entries, geoip_ipv4_compare_entries_); smartlist_sort(geoip_ipv4_entries, geoip_ipv4_compare_entries_);
else /* AF_INET6 */ /* Okay, now we need to maybe change our mind about what is in
smartlist_sort(geoip_ipv6_entries, geoip_ipv6_compare_entries_); * which country. We do this for IPv4 only since that's what we
* store in node->country. */
/* Okay, now we need to maybe change our mind about what is in which
* country. */
refresh_all_country_info(); refresh_all_country_info();
/* Remember file digest so that we can include it in our extra-info
* descriptors. */
/* XXX5053 This is a bug! We overwrite geoip_digest with whichever file
* we parse last. We'll want to add a separate geoip6_digest and write
* a geoip6-db-digest line to our extra-info descriptor. Needs a
* dir-spec.txt patch, too. -KL */
crypto_digest_get_digest(geoip_digest_env, geoip_digest, DIGEST_LEN); crypto_digest_get_digest(geoip_digest_env, geoip_digest, DIGEST_LEN);
}
else { /* AF_INET6 */
smartlist_sort(geoip_ipv6_entries, geoip_ipv6_compare_entries_);
crypto_digest_get_digest(geoip_digest_env, geoip6_digest, DIGEST_LEN);
}
crypto_digest_free(geoip_digest_env); crypto_digest_free(geoip_digest_env);
return 0; return 0;
@ -471,22 +470,28 @@ geoip_get_country_name(country_t num)
/** Return true iff we have loaded a GeoIP database.*/ /** Return true iff we have loaded a GeoIP database.*/
int int
geoip_is_loaded(void) geoip_is_loaded(sa_family_t family)
{ {
/* XXX5053 Saying that we have loaded a GeoIP database if have _either_ tor_assert(family == AF_INET || family == AF_INET6);
* a v4 or v6 database might be problematic. Maybe we need to add an if (geoip_countries == NULL)
* address parameter to this function? -KL */ return 0;
return geoip_countries != NULL && if (family == AF_INET)
(geoip_ipv4_entries != NULL || geoip_ipv6_entries != NULL); return geoip_ipv4_entries != NULL;
else /* AF_INET6 */
return geoip_ipv6_entries != NULL;
} }
/** Return the hex-encoded SHA1 digest of the loaded GeoIP file. The /** Return the hex-encoded SHA1 digest of the loaded GeoIP file. The
* result does not need to be deallocated, but will be overwritten by the * result does not need to be deallocated, but will be overwritten by the
* next call of hex_str(). */ * next call of hex_str(). */
const char * const char *
geoip_db_digest(void) geoip_db_digest(sa_family_t family)
{ {
tor_assert(family == AF_INET || family == AF_INET6);
if (family == AF_INET)
return hex_str(geoip_digest, DIGEST_LEN); return hex_str(geoip_digest, DIGEST_LEN);
else /* AF_INET6 */
return hex_str(geoip6_digest, DIGEST_LEN);
} }
/** Entry in a map from IP address to the last time we've seen an incoming /** Entry in a map from IP address to the last time we've seen an incoming
@ -1011,7 +1016,7 @@ geoip_get_client_history(geoip_client_action_t action, int *total_ipv4,
unsigned total = 0; unsigned total = 0;
unsigned ipv4_count = 0, ipv6_count = 0; unsigned ipv4_count = 0, ipv6_count = 0;
if (!geoip_is_loaded()) if (!geoip_is_loaded(AF_INET) && !geoip_is_loaded(AF_INET6))
return NULL; return NULL;
counts = tor_malloc_zero(sizeof(unsigned)*n_countries); counts = tor_malloc_zero(sizeof(unsigned)*n_countries);
@ -1639,21 +1644,26 @@ getinfo_helper_geoip(control_connection_t *control_conn,
const char **errmsg) const char **errmsg)
{ {
(void)control_conn; (void)control_conn;
if (!geoip_is_loaded()) { if (!strcmpstart(question, "ip-to-country/")) {
int c;
sa_family_t family;
tor_addr_t addr;
question += strlen("ip-to-country/");
family = tor_addr_parse(&addr, question);
if (family != AF_INET && family != AF_INET6) {
*errmsg = "Invalid address family";
return -1;
}
if (!geoip_is_loaded(family)) {
*errmsg = "GeoIP data not loaded"; *errmsg = "GeoIP data not loaded";
return -1; return -1;
} }
if (!strcmpstart(question, "ip-to-country/")) { if (family == AF_INET)
int c; c = geoip_get_country_by_ipv4(tor_addr_to_ipv4h(&addr));
uint32_t ip; else /* AF_INET6 */
struct in_addr in; c = geoip_get_country_by_ipv6(tor_addr_to_in6(&addr));
question += strlen("ip-to-country/");
if (tor_inet_aton(question, &in) != 0) {
ip = ntohl(in.s_addr);
c = geoip_get_country_by_ipv4(ip);
*answer = tor_strdup(geoip_get_country_name(c)); *answer = tor_strdup(geoip_get_country_name(c));
} }
}
return 0; return 0;
} }

View File

@ -24,8 +24,8 @@ int geoip_load_file(sa_family_t family, const char *filename,
int geoip_get_country_by_addr(const tor_addr_t *addr); int geoip_get_country_by_addr(const tor_addr_t *addr);
int geoip_get_n_countries(void); int geoip_get_n_countries(void);
const char *geoip_get_country_name(country_t num); const char *geoip_get_country_name(country_t num);
int geoip_is_loaded(void); int geoip_is_loaded(sa_family_t family);
const char *geoip_db_digest(void); const char *geoip_db_digest(sa_family_t family);
country_t geoip_get_country(const char *countrycode); country_t geoip_get_country(const char *countrycode);
void geoip_note_client_seen(geoip_client_action_t action, void geoip_note_client_seen(geoip_client_action_t action,

View File

@ -2313,9 +2313,12 @@ extrainfo_dump_to_string(char **s_out, extrainfo_t *extrainfo,
tor_free(bandwidth_usage); tor_free(bandwidth_usage);
smartlist_add(chunks, pre); smartlist_add(chunks, pre);
if (geoip_is_loaded()) { if (geoip_is_loaded(AF_INET))
smartlist_add_asprintf(chunks, "geoip-db-digest %s\n", geoip_db_digest()); smartlist_add_asprintf(chunks, "geoip-db-digest %s\n",
} geoip_db_digest(AF_INET));
if (geoip_is_loaded(AF_INET6))
smartlist_add_asprintf(chunks, "geoip6-db-digest %s\n",
geoip_db_digest(AF_INET6));
if (options->ExtraInfoStatistics && write_stats_to_extrainfo) { if (options->ExtraInfoStatistics && write_stats_to_extrainfo) {
log_info(LD_GENERAL, "Adding stats to extra-info descriptor."); log_info(LD_GENERAL, "Adding stats to extra-info descriptor.");

View File

@ -82,7 +82,7 @@ routerset_refresh_countries(routerset_t *target)
int cc; int cc;
bitarray_free(target->countries); bitarray_free(target->countries);
if (!geoip_is_loaded()) { if (!geoip_is_loaded(AF_INET)) {
target->countries = NULL; target->countries = NULL;
target->n_countries = 0; target->n_countries = 0;
return; return;