static void NS(test_main)(void *arg) { const routerset_t *set; int needs_geoip; (void)arg; set = NULL; needs_geoip = routerset_needs_geoip(set); tt_int_op(needs_geoip, ==, 0); set = routerset_new(); needs_geoip = routerset_needs_geoip(set); routerset_free((routerset_t *)set); tt_int_op(needs_geoip, ==, 0); set = NULL; set = routerset_new(); smartlist_add(set->country_names, tor_strndup("xx", 2)); needs_geoip = routerset_needs_geoip(set); routerset_free((routerset_t *)set); set = NULL; tt_int_op(needs_geoip, !=, 0); done: ; }
/** Parse a log severity pattern in *<b>cfg_ptr</b>. Advance cfg_ptr after * the end of the severityPattern. Set the value of <b>severity_out</b> to * the parsed pattern. Return 0 on success, -1 on failure. * * The syntax for a SeverityPattern is: * <pre> * SeverityPattern = *(DomainSeverity SP)* DomainSeverity * DomainSeverity = (DomainList SP)? SeverityRange * SeverityRange = MinSeverity ("-" MaxSeverity )? * DomainList = "[" (SP? DomainSpec SP? ",") SP? DomainSpec "]" * DomainSpec = "*" | Domain | "~" Domain * </pre> * A missing MaxSeverity defaults to ERR. Severities and domains are * case-insensitive. "~" indicates negation for a domain; negation happens * last inside a DomainList. Only one SeverityRange without a DomainList is * allowed per line. */ int parse_log_severity_config(const char **cfg_ptr, log_severity_list_t *severity_out) { const char *cfg = *cfg_ptr; int got_anything = 0; int got_an_unqualified_range = 0; memset(severity_out, 0, sizeof(*severity_out)); cfg = eat_whitespace(cfg); while (*cfg) { const char *dash, *space; char *sev_lo, *sev_hi; int low, high, i; log_domain_mask_t domains = ~0u; if (*cfg == '[') { int err = 0; char *domains_str; smartlist_t *domains_list; log_domain_mask_t neg_domains = 0; const char *closebracket = strchr(cfg, ']'); if (!closebracket) return -1; domains = 0; domains_str = tor_strndup(cfg+1, closebracket-cfg-1); domains_list = smartlist_create(); smartlist_split_string(domains_list, domains_str, ",", SPLIT_SKIP_SPACE, -1); tor_free(domains_str); SMARTLIST_FOREACH(domains_list, const char *, domain, { if (!strcmp(domain, "*")) { domains = ~0u; } else { int d; int negate=0; if (*domain == '~') { negate = 1; ++domain; } d = parse_log_domain(domain); if (!d) { log_warn(LD_CONFIG, "No such logging domain as %s", domain); err = 1; } else { if (negate) neg_domains |= d; else domains |= d; } } }); SMARTLIST_FOREACH(domains_list, char *, d, tor_free(d)); smartlist_free(domains_list); if (err) return -1; domains &= ~neg_domains; cfg = eat_whitespace(closebracket+1); } else {
static void NS(test_main)(void *arg) { routerset_t *set = routerset_new(); (void)arg; NS_MOCK(geoip_is_loaded); NS_MOCK(geoip_get_n_countries); NS_MOCK(geoip_get_country); smartlist_add(set->country_names, tor_strndup("foo", 3)); routerset_refresh_countries(set); tt_ptr_op(set->countries, !=, NULL); tt_int_op(set->n_countries, ==, 2); tt_int_op(CALLED(geoip_is_loaded), ==, 1); tt_int_op(CALLED(geoip_get_n_countries), ==, 1); tt_int_op(CALLED(geoip_get_country), ==, 1); tt_int_op((unsigned int)(*set->countries), ==, 0); done: NS_UNMOCK(geoip_is_loaded); NS_UNMOCK(geoip_get_n_countries); NS_UNMOCK(geoip_get_country); routerset_free(set); }
static void NS(test_main)(void *arg) { routerset_t *set; addr_policy_t *policy; int is_list; (void)arg; /* len(set->country_names) == 0, len(set->policies) == 0 */ set = routerset_new(); is_list = routerset_is_list(set); routerset_free(set); set = NULL; tt_int_op(is_list, !=, 0); /* len(set->country_names) != 0, len(set->policies) == 0 */ set = routerset_new(); smartlist_add(set->country_names, tor_strndup("foo", 3)); is_list = routerset_is_list(set); routerset_free(set); set = NULL; tt_int_op(is_list, ==, 0); /* len(set->country_names) == 0, len(set->policies) != 0 */ set = routerset_new(); policy = tor_malloc_zero(sizeof(addr_policy_t)); smartlist_add(set->policies, (void *)policy); is_list = routerset_is_list(set); routerset_free(set); set = NULL; tt_int_op(is_list, ==, 0); /* len(set->country_names) != 0, len(set->policies) != 0 */ set = routerset_new(); smartlist_add(set->country_names, tor_strndup("foo", 3)); policy = tor_malloc_zero(sizeof(addr_policy_t)); smartlist_add(set->policies, (void *)policy); is_list = routerset_is_list(set); routerset_free(set); set = NULL; tt_int_op(is_list, ==, 0); done: ; }
/** * Split a string <b>str</b> along all occurrences of <b>sep</b>, * adding the split strings, in order, to <b>sl</b>. * * If <b>flags</b>&SPLIT_SKIP_SPACE is true, remove initial and * trailing space from each entry. * If <b>flags</b>&SPLIT_IGNORE_BLANK is true, remove any entries * of length 0. * If <b>flags</b>&SPLIT_STRIP_SPACE is true, strip spaces from each * split string. * * If max>0, divide the string into no more than <b>max</b> pieces. If * <b>sep</b> is NULL, split on any sequence of horizontal space. */ int smartlist_split_string(smartlist_t *sl, const char *str, const char *sep, int flags, int max) { const char *cp, *end, *next; int n = 0; tor_assert(sl); tor_assert(str); cp = str; while (1) { if (flags&SPLIT_SKIP_SPACE) { while (TOR_ISSPACE(*cp)) ++cp; } if (max>0 && n == max-1) { end = strchr(cp,'\0'); } else if (sep) { end = strstr(cp,sep); if (!end) end = strchr(cp,'\0'); } else { for (end = cp; *end && *end != '\t' && *end != ' '; ++end) ; } tor_assert(end); if (!*end) { next = NULL; } else if (sep) { next = end+strlen(sep); } else { next = end+1; while (*next == '\t' || *next == ' ') ++next; } if (flags&SPLIT_SKIP_SPACE) { while (end > cp && TOR_ISSPACE(*(end-1))) --end; } if (end != cp || !(flags&SPLIT_IGNORE_BLANK)) { char *string = tor_strndup(cp, end-cp); if (flags&SPLIT_STRIP_SPACE) tor_strstrip(string, " "); smartlist_add(sl, string); ++n; } if (!next) break; cp = next; } return n; }
/** Read a tagged-data file from <b>fname</b> into the * <b>data_out_len</b>-byte buffer in <b>data_out</b>. Check that the * typestring matches <b>typestring</b>; store the tag into a newly allocated * string in <b>tag_out</b>. Return -1 on failure, and the number of bytes of * data on success. Preserves the errno from reading the file. */ ssize_t crypto_read_tagged_contents_from_file(const char *fname, const char *typestring, char **tag_out, uint8_t *data_out, ssize_t data_out_len) { char prefix[33]; char *content = NULL; struct stat st; ssize_t r = -1; size_t st_size = 0; int saved_errno = 0; *tag_out = NULL; st.st_size = 0; content = read_file_to_str(fname, RFTS_BIN|RFTS_IGNORE_MISSING, &st); if (! content) { saved_errno = errno; goto end; } if (st.st_size < 32 || st.st_size > 32 + data_out_len) { saved_errno = EINVAL; goto end; } st_size = (size_t)st.st_size; memcpy(prefix, content, 32); prefix[32] = 0; /* Check type, extract tag. */ if (strcmpstart(prefix, "== ") || strcmpend(prefix, " ==") || ! tor_mem_is_zero(prefix+strlen(prefix), 32-strlen(prefix))) { saved_errno = EINVAL; goto end; } if (strcmpstart(prefix+3, typestring) || 3+strlen(typestring) >= 32 || strcmpstart(prefix+3+strlen(typestring), ": ")) { saved_errno = EINVAL; goto end; } *tag_out = tor_strndup(prefix+5+strlen(typestring), strlen(prefix)-8-strlen(typestring)); memcpy(data_out, content+32, st_size-32); r = st_size - 32; end: if (content) memwipe(content, 0, st_size); tor_free(content); if (saved_errno) errno = saved_errno; return r; }
/** If <b>c</b> is a country code in the form {cc}, return a newly allocated * string holding the "cc" part. Else, return NULL. */ static char * routerset_get_countryname(const char *c) { char *country; if (strlen(c) < 4 || c[0] !='{' || c[3] !='}') return NULL; country = tor_strndup(c+1, 2); tor_strlower(country); return country; }
/** Parse a string of the form "host[:port]" from <b>addrport</b>. If * <b>address</b> is provided, set *<b>address</b> to a copy of the * host portion of the string. If <b>addr</b> is provided, try to * resolve the host portion of the string and store it into * *<b>addr</b> (in host byte order). If <b>port_out</b> is provided, * store the port number into *<b>port_out</b>, or 0 if no port is given. * If <b>port_out</b> is NULL, then there must be no port number in * <b>addrport</b>. * Return 0 on success, -1 on failure. */ int parse_addr_port(int severity, const char *addrport, char **address, uint32_t *addr, uint16_t *port_out) { const char *colon; char *_address = NULL; int _port; int ok = 1; assert(addrport); colon = strchr(addrport, ':'); if (colon) { _address = tor_strndup(addrport, colon-addrport); _port = (int) parse_long(colon+1,10,1,65535,NULL,NULL); if (!_port) { fprintf(stderr, "Port %s out of range\n", colon+1); ok = 0; } if (!port_out) { fprintf(stderr, "Port %s given on %s when not required\n", colon+1, addrport); ok = 0; } } else { _address = strdup(addrport); _port = 0; } if (addr) { /* There's an addr pointer, so we need to resolve the hostname. */ if (lookup_hostname(_address,addr)) { fprintf(stderr, "Couldn't look up %s\n", _address); ok = 0; *addr = 0; } } if (address && ok) { *address = _address; } else { if (address) *address = NULL; free(_address); } if (port_out) *port_out = ok ? ((uint16_t) _port) : 0; return ok ? 0 : -1; }
static void NS(test_main)(void *arg) { routerset_t *set = NULL; char *s = NULL; (void)arg; set = NULL; s = routerset_to_string(set); tt_str_op(s, ==, ""); tor_free(s); set = routerset_new(); s = routerset_to_string(set); tt_str_op(s, ==, ""); tor_free(s); routerset_free(set); set = NULL; set = routerset_new(); smartlist_add(set->list, tor_strndup("a", 1)); s = routerset_to_string(set); tt_str_op(s, ==, "a"); tor_free(s); routerset_free(set); set = NULL; set = routerset_new(); smartlist_add(set->list, tor_strndup("a", 1)); smartlist_add(set->list, tor_strndup("b", 1)); s = routerset_to_string(set); tt_str_op(s, ==, "a,b"); tor_free(s); routerset_free(set); set = NULL; done: tor_free(s); routerset_free((routerset_t *)set); }
/** Tell the dns request waiting for an answer on <b>conn</b> that we have an * answer of type <b>answer_type</b> (RESOLVE_TYPE_IPV4/IPV6/ERR), of length * <b>answer_len</b>, in <b>answer</b>, with TTL <b>ttl</b>. Doesn't do * any caching; that's handled elsewhere. */ void dnsserv_resolved(entry_connection_t *conn, int answer_type, size_t answer_len, const char *answer, int ttl) { struct evdns_server_request *req = conn->dns_server_request; const char *name; int err = DNS_ERR_NONE; if (!req) return; name = evdns_get_orig_address(req, answer_type, conn->socks_request->address); /* XXXX Re-do; this is dumb. */ if (ttl < 60) ttl = 60; /* The evdns interface is: add a bunch of reply items (corresponding to one * or more of the questions in the request); then, call * evdns_server_request_respond. */ if (answer_type == RESOLVED_TYPE_IPV6) { evdns_server_request_add_aaaa_reply(req, name, 1, answer, ttl); } else if (answer_type == RESOLVED_TYPE_IPV4 && answer_len == 4 && conn->socks_request->command == SOCKS_COMMAND_RESOLVE) { evdns_server_request_add_a_reply(req, name, 1, answer, ttl); } else if (answer_type == RESOLVED_TYPE_HOSTNAME && answer_len < 256 && conn->socks_request->command == SOCKS_COMMAND_RESOLVE_PTR) { char *ans = tor_strndup(answer, answer_len); evdns_server_request_add_ptr_reply(req, NULL, name, ans, ttl); tor_free(ans); } else if (answer_type == RESOLVED_TYPE_ERROR) { err = DNS_ERR_NOTEXIST; } else { /* answer_type == RESOLVED_TYPE_ERROR_TRANSIENT */ err = DNS_ERR_SERVERFAILED; } evdns_server_request_respond(req, err); conn->dns_server_request = NULL; }
/** Remove all TRACKEXIT mappings from the addressmap for which the target * host is unknown or no longer allowed, or for which the source address * is no longer in trackexithosts. */ void addressmap_clear_excluded_trackexithosts(const or_options_t *options) { const routerset_t *allow_nodes = options->ExitNodes; const routerset_t *exclude_nodes = options->ExcludeExitNodesUnion_; if (!addressmap) return; if (routerset_is_empty(allow_nodes)) allow_nodes = NULL; if (allow_nodes == NULL && routerset_is_empty(exclude_nodes)) return; STRMAP_FOREACH_MODIFY(addressmap, address, addressmap_entry_t *, ent) { size_t len; const char *target = ent->new_address, *dot; char *nodename; const node_t *node; if (!target) { /* DNS resolving in progress */ continue; } else if (strcmpend(target, ".exit")) { /* Not a .exit mapping */ continue; } else if (ent->source != ADDRMAPSRC_TRACKEXIT) { /* Not a trackexit mapping. */ continue; } len = strlen(target); if (len < 6) continue; /* malformed. */ dot = target + len - 6; /* dot now points to just before .exit */ while (dot > target && *dot != '.') dot--; if (*dot == '.') dot++; nodename = tor_strndup(dot, len-5-(dot-target));; node = node_get_by_nickname(nodename, 0); tor_free(nodename); if (!node || (allow_nodes && !routerset_contains_node(allow_nodes, node)) || routerset_contains_node(exclude_nodes, node) || !hostname_in_track_host_exits(options, address)) { /* We don't know this one, or we want to be rid of it. */ addressmap_ent_remove(address, ent); MAP_DEL_CURRENT(address); } } STRMAP_FOREACH_END;
/** Read the passphrase from the passphrase fd. */ static int load_passphrase(void) { char *cp; char buf[1024]; /* "Ought to be enough for anybody." */ ssize_t n = read_all(passphrase_fd, buf, sizeof(buf), 0); if (n < 0) { log_err(LD_GENERAL, "Couldn't read from passphrase fd: %s", strerror(errno)); return -1; } cp = memchr(buf, '\n', n); passphrase_len = cp-buf; passphrase = tor_strndup(buf, passphrase_len); memset(buf, 0, sizeof(buf)); return 0; }
/** Read the passphrase from the passphrase fd. */ static int load_passphrase(void) { char *cp; char buf[1024]; /* "Ought to be enough for anybody." */ memset(buf, 0, sizeof(buf)); /* should be needless */ ssize_t n = read_all(passphrase_fd, buf, sizeof(buf), 0); if (n < 0) { log_err(LD_GENERAL, "Couldn't read from passphrase fd: %s", strerror(errno)); return -1; } /* We'll take everything from the buffer except for optional terminating * newline. */ cp = memchr(buf, '\n', n); if (cp == NULL) { passphrase_len = n; } else { passphrase_len = cp-buf; } passphrase = tor_strndup(buf, passphrase_len); memwipe(buf, 0, sizeof(buf)); return 0; }
/** Helper: sends a message to the appropriate logfiles, at loglevel * <b>severity</b>. If provided, <b>funcname</b> is prepended to the * message. The actual message is derived as from tor_snprintf(format,ap). */ static void logv(int severity, log_domain_mask_t domain, const char *funcname, const char *format, va_list ap) { char buf[10024]; size_t msg_len = 0; int formatted = 0; logfile_t *lf; char *end_of_prefix=NULL; /* Call assert, not tor_assert, since tor_assert calls log on failure. */ assert(format); /* check that severity is sane. Overrunning the masks array leads to * interesting and hard to diagnose effects */ assert(severity >= LOG_ERR && severity <= LOG_DEBUG); LOCK_LOGS(); lf = logfiles; while (lf) { if (! (lf->severities->masks[SEVERITY_MASK_IDX(severity)] & domain)) { lf = lf->next; continue; } if (! (lf->fd >= 0 || lf->is_syslog || lf->callback)) { lf = lf->next; continue; } if (lf->callback && (domain & LD_NOCB)) { lf = lf->next; continue; } if (lf->seems_dead) { lf = lf->next; continue; } if (!formatted) { end_of_prefix = format_msg(buf, sizeof(buf), domain, severity, funcname, format, ap, &msg_len); formatted = 1; } if (lf->is_syslog) { #ifdef HAVE_SYSLOG_H char *m = end_of_prefix; #ifdef MAXLINE /* Some syslog implementations have limits on the length of what you can * pass them, and some very old ones do not detect overflow so well. * Regrettably, they call their maximum line length MAXLINE. */ #if MAXLINE < 64 #warn "MAXLINE is a very low number; it might not be from syslog.h after all" #endif if (msg_len >= MAXLINE) m = tor_strndup(end_of_prefix, MAXLINE-1); #endif syslog(severity, "%s", m); #ifdef MAXLINE if (m != end_of_prefix) { tor_free(m); } #endif #endif lf = lf->next; continue; } else if (lf->callback) { lf->callback(severity, domain, end_of_prefix); lf = lf->next; continue; } if (write_all(lf->fd, buf, msg_len, 0) < 0) { /* error */ /* don't log the error! mark this log entry to be blown away, and * continue. */ lf->seems_dead = 1; } lf = lf->next; } UNLOCK_LOGS(); }