/** * 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; }
/** 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) init_geoip_countries(); if (!geoip_entries) geoip_entries = smartlist_new(); while (TOR_ISSPACE(*line)) ++line; if (*line == '#') return 0; if (tor_sscanf(line,"%u,%u,%2s", &low, &high, b) == 3) { geoip_add_entry(low, high, b); return 0; } else if (tor_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 true iff we need to quote and escape the string <b>s</b> to encode * it. */ static bool needs_escape(const char *s, bool as_keyless_val) { if (as_keyless_val && *s == 0) return true; for (; *s; ++s) { if (*s >= 127 || TOR_ISSPACE(*s) || ! TOR_ISPRINT(*s) || *s == '\'' || *s == '\"') { return true; } } return false; }
/** Add an entry to the GeoIP table indicated by <b>family</b>, * parsing it from <b>line</b>. The format is as for geoip_load_file(). */ /*private*/ int geoip_parse_entry(const char *line, sa_family_t family) { tor_addr_t low_addr, high_addr; char c[3]; char *country = NULL; if (!geoip_countries) init_geoip_countries(); if (family == AF_INET) { if (!geoip_ipv4_entries) geoip_ipv4_entries = smartlist_new(); } else if (family == AF_INET6) { if (!geoip_ipv6_entries) geoip_ipv6_entries = smartlist_new(); } else { log_warn(LD_GENERAL, "Unsupported family: %d", family); return -1; } while (TOR_ISSPACE(*line)) ++line; if (*line == '#') return 0; if (family == AF_INET) { unsigned int low, high; if (tor_sscanf(line,"%u,%u,%2s", &low, &high, c) == 3 || tor_sscanf(line,"\"%u\",\"%u\",\"%2s\",", &low, &high, c) == 3) { tor_addr_from_ipv4h(&low_addr, low); tor_addr_from_ipv4h(&high_addr, high); } else goto fail; country = c; } else { /* AF_INET6 */ char buf[512]; char *low_str, *high_str; struct in6_addr low, high; char *strtok_state; strlcpy(buf, line, sizeof(buf)); low_str = tor_strtok_r(buf, ",", &strtok_state); if (!low_str) goto fail; high_str = tor_strtok_r(NULL, ",", &strtok_state); if (!high_str) goto fail; country = tor_strtok_r(NULL, "\n", &strtok_state); if (!country) goto fail; if (strlen(country) != 2) goto fail; if (tor_inet_pton(AF_INET6, low_str, &low) <= 0) goto fail; tor_addr_from_in6(&low_addr, &low); if (tor_inet_pton(AF_INET6, high_str, &high) <= 0) goto fail; tor_addr_from_in6(&high_addr, &high); } geoip_add_entry(&low_addr, &high_addr, country); return 0; fail: log_warn(LD_GENERAL, "Unable to parse line from GEOIP %s file: %s", family == AF_INET ? "IPv4" : "IPv6", escaped(line)); return -1; }
/** * Helper function to parse out a line in the measured bandwidth file * into a measured_bw_line_t output structure. * * If <b>line_is_after_headers</b> is true, then if we encounter an incomplete * bw line, return -1 and warn, since we are after the headers and we should * only parse bw lines. Return 0 otherwise. * * If <b>line_is_after_headers</b> is false then it means that we are not past * the header block yet. If we encounter an incomplete bw line, return -1 but * don't warn since there could be additional header lines coming. If we * encounter a proper bw line, return 0 (and we got past the headers). * * If the line contains "vote=0", stop parsing it, and return -1, so that the * line is ignored during voting. */ STATIC int measured_bw_line_parse(measured_bw_line_t *out, const char *orig_line, int line_is_after_headers) { char *line = tor_strdup(orig_line); char *cp = line; int got_bw = 0; int got_node_id = 0; char *strtok_state; /* lame sauce d'jour */ if (strlen(line) == 0) { log_warn(LD_DIRSERV, "Empty line in bandwidth file"); tor_free(line); return -1; } /* Remove end of line character, so that is not part of the token */ if (line[strlen(line) - 1] == '\n') { line[strlen(line) - 1] = '\0'; } cp = tor_strtok_r(cp, " \t", &strtok_state); if (!cp) { log_warn(LD_DIRSERV, "Invalid line in bandwidth file: %s", escaped(orig_line)); tor_free(line); return -1; } if (orig_line[strlen(orig_line)-1] != '\n') { log_warn(LD_DIRSERV, "Incomplete line in bandwidth file: %s", escaped(orig_line)); tor_free(line); return -1; } do { // If the line contains vote=0, ignore it. if (strcmpstart(cp, "vote=0") == 0) { log_debug(LD_DIRSERV, "Ignoring bandwidth file line that contains " "vote=0: %s",escaped(orig_line)); tor_free(line); return -1; } else if (strcmpstart(cp, "bw=") == 0) { int parse_ok = 0; char *endptr; if (got_bw) { log_warn(LD_DIRSERV, "Double bw= in bandwidth file line: %s", escaped(orig_line)); tor_free(line); return -1; } cp+=strlen("bw="); out->bw_kb = tor_parse_long(cp, 10, 0, LONG_MAX, &parse_ok, &endptr); if (!parse_ok || (*endptr && !TOR_ISSPACE(*endptr))) { log_warn(LD_DIRSERV, "Invalid bandwidth in bandwidth file line: %s", escaped(orig_line)); tor_free(line); return -1; } got_bw=1; } else if (strcmpstart(cp, "node_id=$") == 0) { if (got_node_id) { log_warn(LD_DIRSERV, "Double node_id= in bandwidth file line: %s", escaped(orig_line)); tor_free(line); return -1; } cp+=strlen("node_id=$"); if (strlen(cp) != HEX_DIGEST_LEN || base16_decode(out->node_id, DIGEST_LEN, cp, HEX_DIGEST_LEN) != DIGEST_LEN) { log_warn(LD_DIRSERV, "Invalid node_id in bandwidth file line: %s", escaped(orig_line)); tor_free(line); return -1; } strlcpy(out->node_hex, cp, sizeof(out->node_hex)); got_node_id=1; } } while ((cp = tor_strtok_r(NULL, " \t", &strtok_state))); if (got_bw && got_node_id) { tor_free(line); return 0; } else if (line_is_after_headers == 0) { /* There could be additional header lines, therefore do not give warnings * but returns -1 since it's not a complete bw line. */ log_debug(LD_DIRSERV, "Missing bw or node_id in bandwidth file line: %s", escaped(orig_line)); tor_free(line); return -1; } else { log_warn(LD_DIRSERV, "Incomplete line in bandwidth file: %s", escaped(orig_line)); tor_free(line); return -1; } }