37#include "core/or/dos.h"
46static size_t n_v3_ns_requests_len = 0;
49static uint32_t *n_v3_ns_requests;
53static size_t geoip_client_history_cache_size;
58geoip_increment_client_history_cache_size(
size_t bytes)
61 IF_BUG_ONCE(geoip_client_history_cache_size > (SIZE_MAX - bytes)) {
62 geoip_client_history_cache_size = SIZE_MAX;
65 geoip_client_history_cache_size += bytes;
71geoip_decrement_client_history_cache_size(
size_t bytes)
76 IF_BUG_ONCE(geoip_client_history_cache_size < bytes) {
77 geoip_client_history_cache_size = 0;
80 geoip_client_history_cache_size -= bytes;
90 if ((
size_t)country >= n_v3_ns_requests_len) {
93 if (n_v3_ns_requests_len == 0)
96 new_len = n_v3_ns_requests_len * 2;
97 if (new_len <= (
size_t)country)
98 new_len = ((size_t)country)+1;
99 n_v3_ns_requests = tor_reallocarray(n_v3_ns_requests, new_len,
101 memset(n_v3_ns_requests + n_v3_ns_requests_len, 0,
102 sizeof(uint32_t)*(new_len - n_v3_ns_requests_len));
103 n_v3_ns_requests_len = new_len;
106 n_v3_ns_requests[country] += 1;
120#define MAX_LAST_SEEN_IN_MINUTES 0X3FFFFFFFu
127static inline unsigned
132 if (a->transport_name)
133 h += (unsigned) siphash24g(a->transport_name, strlen(a->transport_name));
141 if (
strcmp_opt(a->transport_name, b->transport_name))
145 a->action == b->action;
149 clientmap_entries_eq);
153#define clientmap_entry_free(ent) \
154 FREE_AND_NULL(clientmap_entry_t, clientmap_entry_free_, ent)
162 (ent->transport_name ? strlen(ent->transport_name) : 0));
174 dos_geoip_entry_about_to_free(ent);
175 geoip_decrement_client_history_cache_size(clientmap_entry_size(ent));
185 const char *transport_name)
194 entry->action = action;
196 if (transport_name) {
197 entry->transport_name = tor_strdup(transport_name);
200 dos_geoip_entry_init(entry);
203 geoip_increment_client_history_cache_size(clientmap_entry_size(entry));
210client_history_clear(
void)
213 for (ent = HT_START(clientmap, &client_history); ent != NULL;
217 next = HT_NEXT_RMV(clientmap, &client_history, ent);
218 clientmap_entry_free(
this);
220 next = HT_NEXT(clientmap, &client_history, ent);
231 const char *transport_name,
240 if (!dos_enabled()) {
241 if (!options->
EntryStatistics && !should_record_bridge_info(options)) {
252 log_debug(
LD_GENERAL,
"Seen client from '%s' with transport '%s'.",
254 transport_name ? transport_name :
"<no transport>");
256 ent = geoip_lookup_client(addr, transport_name, action);
258 ent = clientmap_entry_new(action, addr, transport_name);
259 HT_INSERT(clientmap, &client_history, ent);
261 if (now / 60 <= (
int)MAX_LAST_SEEN_IN_MINUTES && now >= 0)
273 increment_v3_ns_request((
country_t) country_idx);
282 time_t cutoff = *(time_t*)_cutoff / 60;
284 clientmap_entry_free(ent);
293geoip_remove_old_clients(time_t cutoff)
295 clientmap_HT_FOREACH_FN(&client_history,
296 remove_old_client_helper_,
304geoip_lookup_client(
const tor_addr_t *addr,
const char *transport_name,
308 memset(&lookup, 0,
sizeof(lookup));
314 lookup.action = action;
315 lookup.transport_name = (
char *) transport_name;
317 return HT_FIND(clientmap, &client_history, &lookup);
323oom_clean_client_entries(time_t cutoff)
328 for (ent = HT_START(clientmap, &client_history); ent; ent = ent_next) {
331 ent_next = HT_NEXT_RMV(clientmap, &client_history, ent);
332 bytes += clientmap_entry_size(entry);
333 clientmap_entry_free(entry);
335 ent_next = HT_NEXT(clientmap, &client_history, ent);
342#define GEOIP_CLIENT_CACHE_OOM_MIN_CUTOFF (4 * 60 * 60)
344#define GEOIP_CLIENT_CACHE_OOM_STEP (15 * 50)
351geoip_client_cache_handle_oom(time_t now,
size_t min_remove_bytes)
354 size_t bytes_removed = 0;
361 k = WRITE_STATS_INTERVAL;
370 if (k <= GEOIP_CLIENT_CACHE_OOM_MIN_CUTOFF) {
375 bytes_removed += oom_clean_client_entries(cutoff);
376 k -= GEOIP_CLIENT_CACHE_OOM_STEP;
377 }
while (bytes_removed < min_remove_bytes);
379 return bytes_removed;
384geoip_client_cache_total_allocation(
void)
386 return geoip_client_history_cache_size;
391static uint32_t ns_v3_responses[GEOIP_NS_RESPONSE_NUM];
398 static int arrays_initialized = 0;
401 if (!arrays_initialized) {
402 memset(ns_v3_responses, 0,
sizeof(ns_v3_responses));
403 arrays_initialized = 1;
406 ns_v3_responses[response]++;
412#define MIN_IPS_TO_NOTE_COUNTRY 1
415#define MIN_IPS_TO_NOTE_ANYTHING 1
418#define IP_GRANULARITY 8
430c_hist_compare_(
const void **_a,
const void **_b)
433 if (a->
total > b->total)
435 else if (a->
total < b->total)
438 return strcmp(a->
country, b->country);
444#define DIRREQ_TIMEOUT (10*60)
458 unsigned int state:3;
460 unsigned int completed:1;
463 size_t response_size;
464 struct timeval completion_time;
477 return a->dirreq_id == b->dirreq_id && a->type == b->type;
484 unsigned u = (unsigned) entry->dirreq_id;
485 u += entry->type << 20;
508 old_ent = HT_REPLACE(dirreqmap, &dirreq_map, entry);
509 if (old_ent && old_ent != entry) {
510 log_warn(
LD_BUG,
"Error when putting directory request into local "
511 "map. There was already an entry for the same identifier.");
524 lookup.dirreq_id = dirreq_id;
525 return HT_FIND(dirreqmap, &dirreq_map, &lookup);
532geoip_start_dirreq(uint64_t dirreq_id,
size_t response_size,
539 ent->dirreq_id = dirreq_id;
541 ent->response_size = response_size;
543 dirreq_map_put_(ent, type, dirreq_id);
559 ent = dirreq_map_get_(type, dirreq_id);
564 if (new_state - 1 != ent->state)
566 ent->state = new_state;
567 if ((type == DIRREQ_DIRECT &&
569 (type == DIRREQ_TUNNELED &&
580geoip_get_transport_history(
void)
582 unsigned granularity = IP_GRANULARITY;
584 strmap_t *transport_counts = strmap_new();
593 static const char* no_transport_str =
"<OR>";
597 char *the_string = NULL;
600 if (HT_EMPTY(&client_history))
614 log_debug(
LD_GENERAL,
"Starting iteration for transport history. %d clients.",
615 HT_SIZE(&client_history));
618 HT_FOREACH(ent, clientmap, &client_history) {
621 const char *transport_name = (*ent)->transport_name;
623 transport_name = no_transport_str;
626 ptr = strmap_get(transport_counts, transport_name);
627 val = (uintptr_t)ptr;
630 strmap_set(transport_counts, transport_name, ptr);
636 log_debug(
LD_GENERAL,
"Client from '%s' with transport '%s'. "
637 "I've now seen %d clients.",
638 safe_str_client(
fmt_addr(&(*ent)->addr)),
639 transport_name ? transport_name :
"<no transport>",
648 void *transport_count_ptr = strmap_get(transport_counts, transport_name);
649 uintptr_t transport_count = (uintptr_t) transport_count_ptr;
651 log_debug(
LD_GENERAL,
"We got %"PRIu64
" clients with transport '%s'.",
652 ((uint64_t)transport_count), transport_name);
657 (uint64_t)transport_count,
659 } SMARTLIST_FOREACH_END(transport_name);
663 log_debug(
LD_GENERAL,
"Final bridge-ip-transports string: '%s'", the_string);
666 strmap_free(transport_counts, NULL);
668 smartlist_free(transports_used);
670 smartlist_free(string_chunks);
686 uint32_t complete = 0,
timeouts = 0, running = 0;
692 for (ptr = HT_START(dirreqmap, &dirreq_map); ptr; ptr = next) {
694 if (ent->type != type) {
695 next = HT_NEXT(dirreqmap, &dirreq_map, ptr);
698 if (ent->completed) {
701 next = HT_NEXT_RMV(dirreqmap, &dirreq_map, ptr);
703 if (
tv_mdiff(&ent->request_time, &now) / 1000 > DIRREQ_TIMEOUT)
707 next = HT_NEXT_RMV(dirreqmap, &dirreq_map, ptr);
712#define DIR_REQ_GRANULARITY 4
714 DIR_REQ_GRANULARITY);
716 DIR_REQ_GRANULARITY);
718 DIR_REQ_GRANULARITY);
721 "running=%u", complete,
timeouts, running);
723#define MIN_DIR_REQ_RESPONSES 16
724 if (complete >= MIN_DIR_REQ_RESPONSES) {
728 complete = smartlist_len(dirreq_completed);
729 dltimes = tor_calloc(complete,
sizeof(uint32_t));
731 uint32_t bytes_per_second;
732 uint32_t time_diff_ = (uint32_t)
tv_mdiff(&ent->request_time,
733 &ent->completion_time);
738 bytes_per_second = (uint32_t)(1000 * ent->response_size / time_diff_);
739 dltimes[ent_sl_idx] = bytes_per_second;
740 } SMARTLIST_FOREACH_END(ent);
741 median_uint32(dltimes, complete);
743 ",min=%u,d1=%u,d2=%u,q1=%u,d3=%u,d4=%u,md=%u,"
744 "d6=%u,d7=%u,q3=%u,d8=%u,d9=%u,max=%u",
746 dltimes[1*complete/10-1],
747 dltimes[2*complete/10-1],
748 dltimes[1*complete/4-1],
749 dltimes[3*complete/10-1],
750 dltimes[4*complete/10-1],
751 dltimes[5*complete/10-1],
752 dltimes[6*complete/10-1],
753 dltimes[7*complete/10-1],
754 dltimes[3*complete/4-1],
755 dltimes[8*complete/10-1],
756 dltimes[9*complete/10-1],
757 dltimes[complete-1]);
765 smartlist_free(dirreq_completed);
786 char **country_str,
char **ipver_str)
788 unsigned granularity = IP_GRANULARITY;
795 unsigned ipv4_count = 0, ipv6_count = 0;
800 counts = tor_calloc(n_countries,
sizeof(
unsigned));
801 HT_FOREACH(cm_ent, clientmap, &client_history) {
803 if ((*cm_ent)->action != (
int)action)
808 tor_assert(0 <= country && country < n_countries);
828 smartlist_free(chunks);
832 if (total < MIN_IPS_TO_NOTE_ANYTHING) {
841 for (i = 0; i < n_countries; ++i) {
843 const char *countrycode;
846 if (c >= MIN_IPS_TO_NOTE_COUNTRY) {
866 smartlist_free(chunks);
870 smartlist_free(entries);
880geoip_get_request_history(
void)
884 unsigned granularity = IP_GRANULARITY;
890 if ((
size_t)c_sl_idx < n_v3_ns_requests_len)
891 tot = n_v3_ns_requests[c_sl_idx];
896 ent = tor_malloc_zero(
sizeof(
c_hist_t));
900 } SMARTLIST_FOREACH_END(c);
910 smartlist_free(strings);
911 smartlist_free(entries);
917static time_t start_of_dirreq_stats_interval;
921geoip_dirreq_stats_init(time_t now)
923 start_of_dirreq_stats_interval = now;
928geoip_reset_dirreq_stats(time_t now)
930 memset(n_v3_ns_requests, 0,
931 n_v3_ns_requests_len *
sizeof(uint32_t));
934 for (ent = HT_START(clientmap, &client_history); ent != NULL;
938 next = HT_NEXT_RMV(clientmap, &client_history, ent);
939 clientmap_entry_free(
this);
941 next = HT_NEXT(clientmap, &client_history, ent);
945 memset(ns_v3_responses, 0,
sizeof(ns_v3_responses));
948 for (ent = HT_START(dirreqmap, &dirreq_map); ent != NULL; ent = next) {
950 next = HT_NEXT_RMV(dirreqmap, &dirreq_map, ent);
954 start_of_dirreq_stats_interval = now;
960geoip_dirreq_stats_term(
void)
962 geoip_reset_dirreq_stats(0);
969geoip_format_dirreq_stats(time_t now)
971 char t[ISO_TIME_LEN+1];
973 char *v3_ips_string = NULL, *v3_reqs_string = NULL,
974 *v3_direct_dl_string = NULL, *v3_tunneled_dl_string = NULL;
977 if (!start_of_dirreq_stats_interval)
980 tor_assert(now >= start_of_dirreq_stats_interval);
984 v3_reqs_string = geoip_get_request_history();
986#define RESPONSE_GRANULARITY 8
987 for (i = 0; i < GEOIP_NS_RESPONSE_NUM; i++) {
989 ns_v3_responses[i], RESPONSE_GRANULARITY);
991#undef RESPONSE_GRANULARITY
993 v3_direct_dl_string = geoip_get_dirreq_history(DIRREQ_DIRECT);
994 v3_tunneled_dl_string = geoip_get_dirreq_history(DIRREQ_TUNNELED);
999 "dirreq-v3-reqs %s\n"
1001 "served=%u,ok=%u,not-enough-sigs=%u,unavailable=%u,"
1002 "not-found=%u,not-modified=%u,busy=%u\n"
1003 "dirreq-v3-direct-dl %s\n"
1004 "dirreq-v3-tunneled-dl %s\n",
1006 (
unsigned) (now - start_of_dirreq_stats_interval),
1007 v3_ips_string ? v3_ips_string :
"",
1008 v3_reqs_string ? v3_reqs_string :
"",
1016 v3_direct_dl_string ? v3_direct_dl_string :
"",
1017 v3_tunneled_dl_string ? v3_tunneled_dl_string :
"");
1034geoip_dirreq_stats_write(time_t now)
1038 if (!start_of_dirreq_stats_interval)
1040 if (start_of_dirreq_stats_interval + WRITE_STATS_INTERVAL > now)
1044 geoip_remove_old_clients(start_of_dirreq_stats_interval);
1047 str = geoip_format_dirreq_stats(now);
1055 geoip_reset_dirreq_stats(now);
1060 return start_of_dirreq_stats_interval + WRITE_STATS_INTERVAL;
1065static time_t start_of_bridge_stats_interval;
1069geoip_bridge_stats_init(time_t now)
1071 start_of_bridge_stats_interval = now;
1077geoip_bridge_stats_term(
void)
1079 client_history_clear();
1080 start_of_bridge_stats_interval = 0;
1087validate_bridge_stats(
const char *stats_str, time_t now)
1089 char stats_end_str[ISO_TIME_LEN+1], stats_start_str[ISO_TIME_LEN+1],
1092 const char *BRIDGE_STATS_END =
"bridge-stats-end ";
1093 const char *BRIDGE_IPS =
"bridge-ips ";
1094 const char *BRIDGE_IPS_EMPTY_LINE =
"bridge-ips\n";
1095 const char *BRIDGE_TRANSPORTS =
"bridge-ip-transports ";
1096 const char *BRIDGE_TRANSPORTS_EMPTY_LINE =
"bridge-ip-transports\n";
1098 time_t stats_end_time;
1107 tmp += strlen(BRIDGE_STATS_END);
1109 if (strlen(tmp) < ISO_TIME_LEN + 6)
1111 strlcpy(stats_end_str, tmp,
sizeof(stats_end_str));
1114 if (stats_end_time < now - (25*60*60) ||
1115 stats_end_time > now + (1*60*60))
1117 seconds = (int)strtol(tmp + ISO_TIME_LEN + 2, &eos, 10);
1118 if (!eos || seconds < 23*60*60)
1145static char *bridge_stats_extrainfo = NULL;
1151geoip_format_bridge_stats(time_t now)
1154 char *country_data = NULL, *ipver_data = NULL, *transport_data = NULL;
1155 long duration = now - start_of_bridge_stats_interval;
1156 char written[ISO_TIME_LEN+1];
1160 if (!start_of_bridge_stats_interval)
1165 transport_data = geoip_get_transport_history();
1168 "bridge-stats-end %s (%ld s)\n"
1170 "bridge-ip-versions %s\n"
1171 "bridge-ip-transports %s\n",
1173 country_data ? country_data :
"",
1174 ipver_data ? ipver_data :
"",
1175 transport_data ? transport_data :
"");
1187format_bridge_stats_controller(time_t now)
1189 char *out = NULL, *country_data = NULL, *ipver_data = NULL;
1190 char started[ISO_TIME_LEN+1];
1197 "TimeStarted=\"%s\" CountrySummary=%s IPVersions=%s",
1199 country_data ? country_data :
"",
1200 ipver_data ? ipver_data :
"");
1210format_client_stats_heartbeat(time_t now)
1216 unsigned cutoff = (unsigned)( (now-n_seconds)/60 );
1218 if (!start_of_bridge_stats_interval)
1222 HT_FOREACH(ent, clientmap, &client_history) {
1226 if ((*ent)->last_seen_in_minutes < cutoff)
1232 "Since last heartbeat message, I have seen %d unique clients.",
1241geoip_bridge_stats_write(time_t now)
1246 if (now < start_of_bridge_stats_interval + WRITE_STATS_INTERVAL)
1247 return start_of_bridge_stats_interval + WRITE_STATS_INTERVAL;
1250 geoip_remove_old_clients(start_of_bridge_stats_interval);
1253 val = geoip_format_bridge_stats(now);
1259 bridge_stats_extrainfo = val;
1260 start_of_bridge_stats_interval = now;
1265 bridge_stats_extrainfo,
"bridge statistics");
1269 char *controller_str = format_bridge_stats_controller(now);
1277 return start_of_bridge_stats_interval + WRITE_STATS_INTERVAL;
1284load_bridge_stats(time_t now)
1286 char *fname, *contents;
1287 if (bridge_stats_extrainfo)
1290 fname = get_datadir_fname2(
"stats",
"bridge-stats");
1292 if (contents && validate_bridge_stats(contents, now)) {
1293 bridge_stats_extrainfo = contents;
1304geoip_get_bridge_stats_extrainfo(time_t now)
1306 load_bridge_stats(now);
1307 return bridge_stats_extrainfo;
1313geoip_get_bridge_stats_controller(time_t now)
1315 return format_bridge_stats_controller(now);
1320static time_t start_of_entry_stats_interval;
1324geoip_entry_stats_init(time_t now)
1326 start_of_entry_stats_interval = now;
1331geoip_reset_entry_stats(time_t now)
1333 client_history_clear();
1334 start_of_entry_stats_interval = now;
1340geoip_entry_stats_term(
void)
1342 geoip_reset_entry_stats(0);
1349geoip_format_entry_stats(time_t now)
1351 char t[ISO_TIME_LEN+1];
1355 if (!start_of_entry_stats_interval)
1358 tor_assert(now >= start_of_entry_stats_interval);
1363 "entry-stats-end %s (%u s)\n"
1365 t, (
unsigned) (now - start_of_entry_stats_interval),
1376geoip_entry_stats_write(time_t now)
1380 if (!start_of_entry_stats_interval)
1382 if (start_of_entry_stats_interval + WRITE_STATS_INTERVAL > now)
1386 geoip_remove_old_clients(start_of_entry_stats_interval);
1389 str = geoip_format_entry_stats(now);
1396 geoip_reset_entry_stats(now);
1401 return start_of_entry_stats_interval + WRITE_STATS_INTERVAL;
1406geoip_stats_free_all(
void)
1410 for (ent = HT_START(clientmap, &client_history); ent != NULL; ent = next) {
1412 next = HT_NEXT_RMV(clientmap, &client_history, ent);
1413 clientmap_entry_free(
this);
1415 HT_CLEAR(clientmap, &client_history);
1419 for (ent = HT_START(dirreqmap, &dirreq_map); ent != NULL; ent = next) {
1421 next = HT_NEXT_RMV(dirreqmap, &dirreq_map, ent);
1424 HT_CLEAR(dirreqmap, &dirreq_map);
uint64_t tor_addr_hash(const tor_addr_t *addr)
void tor_addr_copy(tor_addr_t *dest, const tor_addr_t *src)
int tor_addr_compare(const tor_addr_t *addr1, const tor_addr_t *addr2, tor_addr_comparison_t how)
static sa_family_t tor_addr_family(const tor_addr_t *a)
void buf_add_printf(buf_t *buf, const char *format,...)
buf_t * buf_new_with_capacity(size_t size)
char * buf_extract(buf_t *buf, size_t *sz_out)
Header file for buffers.c.
int check_or_create_data_subdir(const char *subdir)
const or_options_t * get_options(void)
int write_to_data_subdir(const char *subdir, const char *fname, const char *str, const char *descr)
Header file for config.c.
static conn_counts_t counts
void control_event_clients_seen(const char *controller_str)
Header file for control_events.c.
Header file for dnsserv.c.
#define RFTS_IGNORE_MISSING
int geoip_is_loaded(sa_family_t family)
int geoip_get_country_by_addr(const tor_addr_t *addr)
const smartlist_t * geoip_get_countries(void)
int geoip_get_n_countries(void)
const char * geoip_get_country_name(country_t num)
Header file for geoip_stats.c.
@ DIRREQ_CHANNEL_BUFFER_FLUSHED
@ DIRREQ_IS_FOR_NETWORK_STATUS
@ DIRREQ_FLUSHING_DIR_CONN_FINISHED
@ GEOIP_CLIENT_NETWORKSTATUS
@ GEOIP_REJECT_NOT_MODIFIED
@ GEOIP_REJECT_NOT_ENOUGH_SIGS
@ GEOIP_REJECT_UNAVAILABLE
void * tor_reallocarray_(void *ptr, size_t sz1, size_t sz2)
void tor_free_(void *mem)
uint32_t round_uint32_to_next_multiple_of(uint32_t number, uint32_t divisor)
unsigned round_to_next_multiple_of(unsigned number, unsigned divisor)
uint64_t round_uint64_to_next_multiple_of(uint64_t number, uint64_t divisor)
Master header file for Tor-specific functionality.
int tor_asprintf(char **strp, const char *fmt,...)
Header file for routerlist.c.
void smartlist_add_asprintf(struct smartlist_t *sl, const char *pattern,...)
void smartlist_sort_strings(smartlist_t *sl)
char * smartlist_join_strings(smartlist_t *sl, const char *join, int terminate, size_t *len_out)
void smartlist_sort(smartlist_t *sl, int(*compare)(const void **a, const void **b))
void smartlist_add_strdup(struct smartlist_t *sl, const char *string)
smartlist_t * smartlist_new(void)
void smartlist_add(smartlist_t *sl, void *element)
#define SMARTLIST_FOREACH_BEGIN(sl, type, var)
#define SMARTLIST_FOREACH(sl, type, var, cmd)
unsigned int last_seen_in_minutes
int BridgeRecordUsageByCountry
int BridgeAuthoritativeDir
int parse_iso_time(const char *cp, time_t *t)
void format_iso_time(char *buf, time_t t)
void tor_gettimeofday(struct timeval *timeval)
long tv_mdiff(const struct timeval *start, const struct timeval *end)
#define IF_BUG_ONCE(cond)
int strcmp_opt(const char *s1, const char *s2)
const char * find_str_at_start_of_line(const char *haystack, const char *needle)