/** * Copies user_callback and user_data from the query buffer to the * reply buffer. This function won't fail. However, if gethostbyname() * fails ``reply->addr'' will be set to zero. */ static void adns_gethostbyname(const struct adns_request *req, struct adns_response *ans) { g_assert(NULL != req); g_assert(NULL != ans); ans->common = req->common; if (req->common.reverse) { const struct adns_reverse_query *query = &req->query.reverse; struct adns_reverse_reply *reply = &ans->reply.reverse; const char *host; if (common_dbg > 1) { g_debug("%s: resolving \"%s\" ...", G_STRFUNC, host_addr_to_string(query->addr)); } reply->addr = query->addr; host = host_addr_to_name(query->addr); clamp_strcpy(reply->hostname, sizeof reply->hostname, host ? host : ""); } else { const struct adns_query *query = &req->query.by_addr; struct adns_reply *reply = &ans->reply.by_addr; GSList *sl_addr, *sl; size_t i = 0; if (common_dbg > 1) { g_debug("%s: resolving \"%s\" ...", G_STRFUNC, query->hostname); } clamp_strcpy(reply->hostname, sizeof reply->hostname, query->hostname); sl_addr = name_to_host_addr(query->hostname, query->net); for (sl = sl_addr; NULL != sl; sl = g_slist_next(sl)) { host_addr_t *addr = sl->data; g_assert(addr); if (i >= G_N_ELEMENTS(reply->addrs)) { break; } reply->addrs[i++] = *addr; } host_addr_free_list(&sl_addr); if (i < G_N_ELEMENTS(reply->addrs)) { reply->addrs[i] = zero_host_addr; } } }
/** * Collect entropy from host. * * This uses the host's name and its IP addresses. */ static void entropy_collect_host(SHA1Context *ctx) { const char *name; GSList *hosts, *sl; name = local_hostname(); sha1_feed_string(ctx, name); hosts = name_to_host_addr(name, NET_TYPE_NONE); GM_SLIST_FOREACH(hosts, sl) { host_addr_t *addr = sl->data; struct packed_host_addr packed = host_addr_pack(*addr); SHA1Input(ctx, &packed, packed_host_addr_size(packed)); }
/** * 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 {