/** * Read the whole persistent cache into memory. */ static G_GNUC_COLD void sha1_read_cache(void) { FILE *f; file_path_t fp[1]; bool truncated = FALSE; g_return_if_fail(settings_config_dir()); file_path_set(fp, settings_config_dir(), "sha1_cache"); f = file_config_open_read("SHA-1 cache", fp, G_N_ELEMENTS(fp)); if (f) { for (;;) { char buffer[4096]; if (NULL == fgets(buffer, sizeof buffer, f)) break; if (!file_line_chomp_tail(buffer, sizeof buffer, NULL)) { truncated = TRUE; } else if (truncated) { truncated = FALSE; } else { parse_and_append_cache_entry(buffer); } } fclose(f); dump_cache(TRUE); } }
/** * Loads the whitelist into memory. */ static void G_COLD whitelist_retrieve(void) { char line[1024]; FILE *f; filestat_t st; unsigned linenum = 0; file_path_t fp[1]; whitelist_generation++; file_path_set(fp, settings_config_dir(), whitelist_file); f = file_config_open_read_norename("Host Whitelist", fp, N_ITEMS(fp)); if (!f) return; if (fstat(fileno(f), &st)) { g_warning("%s(): fstat() failed: %m", G_STRFUNC); fclose(f); return; } while (fgets(line, sizeof line, f)) { pslist_t *sl_addr, *sl; const char *endptr, *start; host_addr_t addr; uint16 port; uint8 bits; bool item_ok; bool use_tls; char *hname; linenum++; if (!file_line_chomp_tail(line, sizeof line, NULL)) { g_warning("%s(): line %u too long, aborting", G_STRFUNC, linenum); break; } if (file_line_is_skipable(line)) continue; sl_addr = NULL; addr = zero_host_addr; endptr = NULL; hname = NULL; endptr = is_strprefix(line, "tls:"); if (endptr) { use_tls = TRUE; start = endptr; } else { use_tls = FALSE; start = line; } port = 0; if (string_to_host_addr_port(start, &endptr, &addr, &port)) { sl_addr = name_to_host_addr(host_addr_to_string(addr), settings_dns_net()); } else if (string_to_host_or_addr(start, &endptr, &addr)) { uchar c = *endptr; switch (c) { case '\0': case ':': case '/': break; default: if (!is_ascii_space(c)) endptr = NULL; } if (!endptr) { g_warning("%s(): line %d: " "expected a hostname or IP address \"%s\"", G_STRFUNC, linenum, line); continue; } /* Terminate the string for name_to_host_addr() */ hname = h_strndup(start, endptr - start); } else { g_warning("%s(): line %d: expected hostname or IP address \"%s\"", G_STRFUNC, linenum, line); continue; } g_assert(sl_addr != NULL || hname != NULL); g_assert(NULL != endptr); bits = 0; item_ok = TRUE; /* * When an explicit address is given (no hostname) and with no * port, one can suffix the address with bits to indicate a CIDR * range of whitelisted addresses. */ if (0 == port) { /* Ignore trailing items separated by a space */ while ('\0' != *endptr && !is_ascii_space(*endptr)) { uchar c = *endptr++; if (':' == c) { int error; uint32 v; if (0 != port) { g_warning("%s(): line %d: multiple colons after host", G_STRFUNC, linenum); item_ok = FALSE; break; } v = parse_uint32(endptr, &endptr, 10, &error); port = (error || v > 0xffff) ? 0 : v; if (0 == port) { g_warning("%s(): line %d: " "invalid port value after host", G_STRFUNC, linenum); item_ok = FALSE; break; } } else if ('/' == c) { const char *ep; uint32 mask; if (0 != bits) { g_warning("%s(): line %d: " "multiple slashes after host", G_STRFUNC, linenum); item_ok = FALSE; break; } if (string_to_ip_strict(endptr, &mask, &ep)) { if (!host_addr_is_ipv4(addr)) { g_warning("%s(): line %d: " "IPv4 netmask after non-IPv4 address", G_STRFUNC, linenum); item_ok = FALSE; break; } endptr = ep; if (0 == (bits = netmask_to_cidr(mask))) { g_warning("%s(): line %d: " "IPv4 netmask after non-IPv4 address", G_STRFUNC, linenum); item_ok = FALSE; break; } } else { int error; uint32 v; v = parse_uint32(endptr, &endptr, 10, &error); if ( error || 0 == v || (v > 32 && host_addr_is_ipv4(addr)) || (v > 128 && host_addr_is_ipv6(addr)) ) { g_warning("%s(): line %d: " "invalid numeric netmask after host", G_STRFUNC, linenum); item_ok = FALSE; break; } bits = v; } } else { g_warning("%s(): line %d: " "unexpected character after host", G_STRFUNC, linenum); item_ok = FALSE; break; } } } if (item_ok) { struct whitelist *item; if (hname) { item = whitelist_hostname_create(use_tls, hname, port); whitelist_dns_resolve(item, FALSE); } else { PSLIST_FOREACH(sl_addr, sl) { host_addr_t *aptr = sl->data; g_assert(aptr != NULL); item = whitelist_addr_create(use_tls, *aptr, port, bits); whitelist_add(item); } } } else {
/** * Load bogons data from the supplied FILE. * * @returns the amount of entries loaded. */ static G_GNUC_COLD int bogons_load(FILE *f) { char line[1024]; uint32 ip, netmask; int linenum = 0; int bits; iprange_err_t error; filestat_t buf; bogons_db = iprange_new(); if (-1 == fstat(fileno(f), &buf)) { g_warning("cannot stat %s: %m", bogons_file); } else { bogons_mtime = buf.st_mtime; } while (fgets(line, sizeof line, f)) { linenum++; /* * Remove all trailing spaces in string. * Otherwise, lines which contain only spaces would cause a warning. */ if (!file_line_chomp_tail(line, sizeof line, NULL)) { g_warning("%s, line %d: too long a line", bogons_file, linenum); break; } if (file_line_is_skipable(line)) continue; if (!string_to_ip_and_mask(line, &ip, &netmask)) { g_warning("%s, line %d: invalid IP or netmask \"%s\"", bogons_file, linenum, line); continue; } bits = netmask_to_cidr(netmask); error = iprange_add_cidr(bogons_db, ip, bits, 1); switch (error) { case IPR_ERR_OK: break; /* FALL THROUGH */ default: g_warning("%s, line %d: rejected entry \"%s\" (%s/%d): %s", bogons_file, linenum, line, ip_to_string(ip), bits, iprange_strerror(error)); continue; } } iprange_sync(bogons_db); if (GNET_PROPERTY(reload_debug)) { g_debug("loaded %u bogus IP ranges (%u hosts)", iprange_get_item_count(bogons_db), iprange_get_host_count4(bogons_db)); } return iprange_get_item_count(bogons_db); }
/** * Load geographic IP data from the supplied FILE. * * @return The amount of entries loaded. */ static G_GNUC_COLD uint gip_load(FILE *f, unsigned idx) { char line[1024]; int linenum = 0; filestat_t buf; g_assert(f != NULL); g_assert(uint_is_non_negative(idx)); g_assert(idx < G_N_ELEMENTS(gip_source)); switch (idx) { case GIP_IPV4: iprange_reset_ipv4(geo_db); break; case GIP_IPV6: iprange_reset_ipv6(geo_db); break; default: g_assert_not_reached(); } if (-1 == fstat(fileno(f), &buf)) { g_warning("cannot stat %s: %m", gip_source[idx].file); } else { gip_source[idx].mtime = buf.st_mtime; } while (fgets(line, sizeof line, f)) { linenum++; /* * Remove all trailing spaces in string. * Otherwise, lines which contain only spaces would cause a warning. */ if (!file_line_chomp_tail(line, sizeof line, NULL)) { g_warning("%s: line %d too long, aborting", gip_source[idx].file, linenum); break; } if (file_line_is_skipable(line)) continue; if (GIP_IPV4 == idx) gip_parse_ipv4(line, linenum); else gip_parse_ipv6(line, linenum); } iprange_sync(geo_db); if (GNET_PROPERTY(reload_debug)) { if (GIP_IPV4 == idx) { g_debug("loaded %u geographical IPv4 ranges (%u hosts)", iprange_get_item_count4(geo_db), iprange_get_host_count4(geo_db)); } else { g_debug("loaded %u geographical IPv6 ranges", iprange_get_item_count6(geo_db)); } } return GIP_IPV4 == idx ? iprange_get_item_count4(geo_db) : iprange_get_item_count6(geo_db); }