/** Initializes the service descriptor cache. */ void rend_cache_init(void) { rend_cache = strmap_new(); rend_cache_v2_dir = digestmap_new(); rend_cache_failure = strmap_new(); }
/** Add an entry to the GeoIP table, parsing it from <b>line</b>. The * format is as for geoip_load_file(). */ /*private*/ int geoip_parse_entry(const char *line) { unsigned int low, high; char b[3]; if (!geoip_countries) { geoip_countries = smartlist_create(); geoip_entries = smartlist_create(); country_idxplus1_by_lc_code = strmap_new(); } while (TOR_ISSPACE(*line)) ++line; if (*line == '#') return 0; if (sscanf(line,"%u,%u,%2s", &low, &high, b) == 3) { geoip_add_entry(low, high, b); return 0; } else if (sscanf(line,"\"%u\",\"%u\",\"%2s\",", &low, &high, b) == 3) { geoip_add_entry(low, high, b); return 0; } else { log_warn(LD_GENERAL, "Unable to parse line from GEOIP file: %s", escaped(line)); return -1; } }
/** Return a new empty routerset. */ routerset_t * routerset_new(void) { routerset_t *result = tor_malloc_zero(sizeof(routerset_t)); result->list = smartlist_new(); result->names = strmap_new(); result->digests = digestmap_new(); result->policies = smartlist_new(); result->country_names = smartlist_new(); return result; }
/** Set up a new list of geoip countries with no countries (yet) set in it, * except for the unknown country. */ static void init_geoip_countries(void) { geoip_country_t *geoip_unresolved; geoip_countries = smartlist_new(); /* Add a geoip_country_t for requests that could not be resolved to a * country as first element (index 0) to geoip_countries. */ geoip_unresolved = tor_malloc_zero(sizeof(geoip_country_t)); strlcpy(geoip_unresolved->countrycode, "??", sizeof(geoip_unresolved->countrycode)); smartlist_add(geoip_countries, geoip_unresolved); country_idxplus1_by_lc_code = strmap_new(); strmap_set_lc(country_idxplus1_by_lc_code, "??", (void*)(1)); }
/** Clear the GeoIP database and reload it from the file * <b>filename</b>. Return 0 on success, -1 on failure. * * Recognized line formats are: * INTIPLOW,INTIPHIGH,CC * and * "INTIPLOW","INTIPHIGH","CC","CC3","COUNTRY NAME" * where INTIPLOW and INTIPHIGH are IPv4 addresses encoded as 4-byte unsigned * integers, and CC is a country code. * * It also recognizes, and skips over, blank lines and lines that start * with '#' (comments). */ int geoip_load_file(const char *filename, or_options_t *options) { FILE *f; const char *msg = ""; int severity = options_need_geoip_info(options, &msg) ? LOG_WARN : LOG_INFO; clear_geoip_db(); if (!(f = fopen(filename, "r"))) { log_fn(severity, LD_GENERAL, "Failed to open GEOIP file %s. %s", filename, msg); return -1; } if (!geoip_countries) { geoip_countries = smartlist_create(); country_idxplus1_by_lc_code = strmap_new(); } if (geoip_entries) { SMARTLIST_FOREACH(geoip_entries, geoip_entry_t *, e, tor_free(e)); smartlist_free(geoip_entries); } geoip_entries = smartlist_create(); log_notice(LD_GENERAL, "Parsing GEOIP file."); while (!feof(f)) { char buf[512]; if (fgets(buf, (int)sizeof(buf), f) == NULL) break; /* FFFF track full country name. */ geoip_parse_entry(buf); } /*XXXX abort and return -1 if no entries/illformed?*/ fclose(f); smartlist_sort(geoip_entries, _geoip_compare_entries); /* Okay, now we need to maybe change our mind about what is in which * country. */ refresh_all_country_info(); return 0; }
/** Replace the v3 consensus networkstatus of type <b>flavor_name</b> that * we're serving with <b>networkstatus</b>, published at <b>published</b>. No * validation is performed. */ void dirserv_set_cached_consensus_networkstatus(const char *networkstatus, size_t networkstatus_len, const char *flavor_name, const common_digests_t *digests, const uint8_t *sha3_as_signed, time_t published) { cached_dir_t *new_networkstatus; cached_dir_t *old_networkstatus; if (!cached_consensuses) cached_consensuses = strmap_new(); new_networkstatus = new_cached_dir(tor_memdup_nulterm(networkstatus, networkstatus_len), published); memcpy(&new_networkstatus->digests, digests, sizeof(common_digests_t)); memcpy(&new_networkstatus->digest_sha3_as_signed, sha3_as_signed, DIGEST256_LEN); old_networkstatus = strmap_set(cached_consensuses, flavor_name, new_networkstatus); if (old_networkstatus) cached_dir_decref(old_networkstatus); }
/** * Protects all the strings in the sandbox's parameter list configuration. It * works by calculating the total amount of memory required by the parameter * list, allocating the memory using mmap, and protecting it from writes with * mprotect(). */ static int prot_strings(scmp_filter_ctx ctx, sandbox_cfg_t* cfg) { int ret = 0; size_t pr_mem_size = 0, pr_mem_left = 0; char *pr_mem_next = NULL, *pr_mem_base; sandbox_cfg_t *el = NULL; strmap_t *locations = NULL; // get total number of bytes required to mmap. (Overestimate.) for (el = cfg; el != NULL; el = el->next) { pr_mem_size += strlen((char*) el->param->value) + 1; if (el->param->value2) pr_mem_size += strlen((char*) el->param->value2) + 1; } // allocate protected memory with MALLOC_MP_LIM canary pr_mem_base = (char*) mmap(NULL, MALLOC_MP_LIM + pr_mem_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); if (pr_mem_base == MAP_FAILED) { log_err(LD_BUG,"(Sandbox) failed allocate protected memory! mmap: %s", strerror(errno)); ret = -1; goto out; } pr_mem_next = pr_mem_base + MALLOC_MP_LIM; pr_mem_left = pr_mem_size; locations = strmap_new(); // change el value pointer to protected for (el = cfg; el != NULL; el = el->next) { if (prot_strings_helper(locations, &pr_mem_next, &pr_mem_left, &el->param->value) < 0) { ret = -2; goto out; } if (prot_strings_helper(locations, &pr_mem_next, &pr_mem_left, &el->param->value2) < 0) { ret = -2; goto out; } el->param->prot = 1; } // protecting from writes if (mprotect(pr_mem_base, MALLOC_MP_LIM + pr_mem_size, PROT_READ)) { log_err(LD_BUG,"(Sandbox) failed to protect memory! mprotect: %s", strerror(errno)); ret = -3; goto out; } /* * Setting sandbox restrictions so the string memory cannot be tampered with */ // no mremap of the protected base address ret = seccomp_rule_add_1(ctx, SCMP_ACT_KILL, SCMP_SYS(mremap), SCMP_CMP(0, SCMP_CMP_EQ, (intptr_t) pr_mem_base)); if (ret) { log_err(LD_BUG,"(Sandbox) mremap protected memory filter fail!"); goto out; } // no munmap of the protected base address ret = seccomp_rule_add_1(ctx, SCMP_ACT_KILL, SCMP_SYS(munmap), SCMP_CMP(0, SCMP_CMP_EQ, (intptr_t) pr_mem_base)); if (ret) { log_err(LD_BUG,"(Sandbox) munmap protected memory filter fail!"); goto out; } /* * Allow mprotect with PROT_READ|PROT_WRITE because openssl uses it, but * never over the memory region used by the protected strings. * * PROT_READ|PROT_WRITE was originally fully allowed in sb_mprotect(), but * had to be removed due to limitation of libseccomp regarding intervals. * * There is a restriction on how much you can mprotect with R|W up to the * size of the canary. */ ret = seccomp_rule_add_3(ctx, SCMP_ACT_ALLOW, SCMP_SYS(mprotect), SCMP_CMP(0, SCMP_CMP_LT, (intptr_t) pr_mem_base), SCMP_CMP(1, SCMP_CMP_LE, MALLOC_MP_LIM), SCMP_CMP(2, SCMP_CMP_EQ, PROT_READ|PROT_WRITE)); if (ret) { log_err(LD_BUG,"(Sandbox) mprotect protected memory filter fail (LT)!"); goto out; } ret = seccomp_rule_add_3(ctx, SCMP_ACT_ALLOW, SCMP_SYS(mprotect), SCMP_CMP(0, SCMP_CMP_GT, (intptr_t) pr_mem_base + pr_mem_size + MALLOC_MP_LIM), SCMP_CMP(1, SCMP_CMP_LE, MALLOC_MP_LIM), SCMP_CMP(2, SCMP_CMP_EQ, PROT_READ|PROT_WRITE)); if (ret) { log_err(LD_BUG,"(Sandbox) mprotect protected memory filter fail (GT)!"); goto out; } out: strmap_free(locations, NULL); return ret; }
/* * load_config_to_str_map * * Takes a config file on disk and parses it into a string map. Can fail if the * file doesn't exist or doesn't have the correct permissions. * * Parameters: filename - Filename and path of the config file. * new_config_table - Will contain the new string map. * * Returns: One of LOAD_CONFIG_RET_CODES. */ int load_config_to_str_map(char *filename, StrMap **new_config_table) { /* * Local Variables */ int rc = CONFIG_LOAD_OK; FILE *config_file = NULL; char line[MAX_CONFIG_FILE_LINE_LEN]; int discard_char; StrMap *config_table; /* * Create a new string map. This returns null on allocation failure. */ config_table = strmap_new(DEFAULT_CONFIG_TABLE_SIZE); if (config_table == NULL) { rc = CONFIG_TABLE_ALLOCATION_FAILURE; goto EXIT_LABEL; } /* * Attempt to open the file. If this fails then return an error code. */ config_file = fopen(filename, "r"); if (config_file == NULL) { rc = CONFIG_FILE_OPEN_FAILURE; goto EXIT_LABEL; } while(fgets(line, MAX_CONFIG_FILE_LINE_LEN, config_file)) { /* * If the line was too long to fit in the buffer then fgets will only read * some of the line. In order to skip the line we test for this and if it * is the case then we read all remaining characters until we find either * an EOF or a newline character. */ if (line[strlen(line) - 1] != '\n' && !feof(config_file)) { DT_DEBUG_LOG("Long(%i) line found: %s\n", strlen(line), line); do { discard_char = fgetc(config_file); } while (discard_char != '\n' && discard_char != EOF); } else { DT_DEBUG_LOG("Good config file line found: %s\n", line); parse_config_file_line(config_table, line); } } EXIT_LABEL: /* * It is feasible that this function failed without opening the config file. * In that case we don't want to make a call to close it. */ if (config_file != NULL) { fclose(config_file); } *new_config_table = config_table; return(rc); }
/** Run unit tests for string-to-void* map functions */ static void test_container_strmap(void) { strmap_t *map; strmap_iter_t *iter; const char *k; void *v; char *visited = NULL; smartlist_t *found_keys = NULL; map = strmap_new(); test_assert(map); test_eq(strmap_size(map), 0); test_assert(strmap_isempty(map)); v = strmap_set(map, "K1", (void*)99); test_eq_ptr(v, NULL); test_assert(!strmap_isempty(map)); v = strmap_set(map, "K2", (void*)101); test_eq_ptr(v, NULL); v = strmap_set(map, "K1", (void*)100); test_eq_ptr(v, (void*)99); test_eq_ptr(strmap_get(map,"K1"), (void*)100); test_eq_ptr(strmap_get(map,"K2"), (void*)101); test_eq_ptr(strmap_get(map,"K-not-there"), NULL); strmap_assert_ok(map); v = strmap_remove(map,"K2"); strmap_assert_ok(map); test_eq_ptr(v, (void*)101); test_eq_ptr(strmap_get(map,"K2"), NULL); test_eq_ptr(strmap_remove(map,"K2"), NULL); strmap_set(map, "K2", (void*)101); strmap_set(map, "K3", (void*)102); strmap_set(map, "K4", (void*)103); test_eq(strmap_size(map), 4); strmap_assert_ok(map); strmap_set(map, "K5", (void*)104); strmap_set(map, "K6", (void*)105); strmap_assert_ok(map); /* Test iterator. */ iter = strmap_iter_init(map); found_keys = smartlist_new(); while (!strmap_iter_done(iter)) { strmap_iter_get(iter,&k,&v); smartlist_add(found_keys, tor_strdup(k)); test_eq_ptr(v, strmap_get(map, k)); if (!strcmp(k, "K2")) { iter = strmap_iter_next_rmv(map,iter); } else { iter = strmap_iter_next(map,iter); } } /* Make sure we removed K2, but not the others. */ test_eq_ptr(strmap_get(map, "K2"), NULL); test_eq_ptr(strmap_get(map, "K5"), (void*)104); /* Make sure we visited everyone once */ smartlist_sort_strings(found_keys); visited = smartlist_join_strings(found_keys, ":", 0, NULL); test_streq(visited, "K1:K2:K3:K4:K5:K6"); strmap_assert_ok(map); /* Clean up after ourselves. */ strmap_free(map, NULL); map = NULL; /* Now try some lc functions. */ map = strmap_new(); strmap_set_lc(map,"Ab.C", (void*)1); test_eq_ptr(strmap_get(map,"ab.c"), (void*)1); strmap_assert_ok(map); test_eq_ptr(strmap_get_lc(map,"AB.C"), (void*)1); test_eq_ptr(strmap_get(map,"AB.C"), NULL); test_eq_ptr(strmap_remove_lc(map,"aB.C"), (void*)1); strmap_assert_ok(map); test_eq_ptr(strmap_get_lc(map,"AB.C"), NULL); done: if (map) strmap_free(map,NULL); if (found_keys) { SMARTLIST_FOREACH(found_keys, char *, cp, tor_free(cp)); smartlist_free(found_keys); } tor_free(visited); }
/** Initialize addressmap. */ void addressmap_init(void) { addressmap = strmap_new(); virtaddress_reversemap = strmap_new(); }
/** Run unit tests for threading logic. */ static void test_threads_basic(void *arg) { char *s1 = NULL, *s2 = NULL; int done = 0, timedout = 0; time_t started; #ifndef _WIN32 struct timeval tv; tv.tv_sec=0; tv.tv_usec=100*1000; #endif (void) arg; set_main_thread(); thread_test_mutex_ = tor_mutex_new(); thread_test_start1_ = tor_mutex_new(); thread_test_start2_ = tor_mutex_new(); thread_test_strmap_ = strmap_new(); s1 = tor_strdup("thread 1"); s2 = tor_strdup("thread 2"); tor_mutex_acquire(thread_test_start1_); tor_mutex_acquire(thread_test_start2_); spawn_func(thread_test_func_, s1); spawn_func(thread_test_func_, s2); tor_mutex_release(thread_test_start2_); tor_mutex_release(thread_test_start1_); started = time(NULL); while (!done) { tor_mutex_acquire(thread_test_mutex_); strmap_assert_ok(thread_test_strmap_); if (strmap_get(thread_test_strmap_, "thread 1") && strmap_get(thread_test_strmap_, "thread 2")) { done = 1; } else if (time(NULL) > started + 150) { timedout = done = 1; } tor_mutex_release(thread_test_mutex_); #ifndef _WIN32 /* Prevent the main thread from starving the worker threads. */ select(0, NULL, NULL, NULL, &tv); #endif } tor_mutex_acquire(thread_test_start1_); tor_mutex_release(thread_test_start1_); tor_mutex_acquire(thread_test_start2_); tor_mutex_release(thread_test_start2_); tor_mutex_free(thread_test_mutex_); if (timedout) { printf("\nTimed out: %d %d", t1_count, t2_count); tt_assert(strmap_get(thread_test_strmap_, "thread 1")); tt_assert(strmap_get(thread_test_strmap_, "thread 2")); tt_assert(!timedout); } /* different thread IDs. */ tt_assert(strcmp(strmap_get(thread_test_strmap_, "thread 1"), strmap_get(thread_test_strmap_, "thread 2"))); tt_assert(!strcmp(strmap_get(thread_test_strmap_, "thread 1"), strmap_get(thread_test_strmap_, "last to run")) || !strcmp(strmap_get(thread_test_strmap_, "thread 2"), strmap_get(thread_test_strmap_, "last to run"))); tt_int_op(thread_fns_failed, ==, 0); tt_int_op(thread_fn_tid1, !=, thread_fn_tid2); done: tor_free(s1); tor_free(s2); tor_free(thread1_name_); tor_free(thread2_name_); if (thread_test_strmap_) strmap_free(thread_test_strmap_, NULL); if (thread_test_start1_) tor_mutex_free(thread_test_start1_); if (thread_test_start2_) tor_mutex_free(thread_test_start2_); }