diff options
author | Lennart Poettering <lennart@poettering.net> | 2016-01-22 12:24:20 +0100 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2016-01-25 17:19:19 +0100 |
commit | dd0bc0f1414cc1d0fa73a29470bd14944e4942d3 (patch) | |
tree | 9ac5ed0c4f799b260ae93cb8254898ea458fa4e9 | |
parent | 528e685ebd3657f2531f8666c9e4bba6fbd38acd (diff) |
resolved: synthesize RRs for data from /etc/hosts
This way the difference between lookups via NSS and our native bus API should become minimal.
-rw-r--r-- | Makefile.am | 2 | ||||
-rw-r--r-- | src/resolve/resolved-dns-query.c | 53 | ||||
-rw-r--r-- | src/resolve/resolved-dns-synthesize.c | 35 | ||||
-rw-r--r-- | src/resolve/resolved-dns-synthesize.h | 6 | ||||
-rw-r--r-- | src/resolve/resolved-etc-hosts.c | 448 | ||||
-rw-r--r-- | src/resolve/resolved-etc-hosts.h | 28 | ||||
-rw-r--r-- | src/resolve/resolved-manager.c | 5 | ||||
-rw-r--r-- | src/resolve/resolved-manager.h | 5 |
8 files changed, 549 insertions, 33 deletions
diff --git a/Makefile.am b/Makefile.am index 5036a2bfc9..4218a6dcdf 100644 --- a/Makefile.am +++ b/Makefile.am @@ -5208,6 +5208,8 @@ systemd_resolved_SOURCES = \ src/resolve/resolved-dns-dnssec.c \ src/resolve/resolved-dns-trust-anchor.h \ src/resolve/resolved-dns-trust-anchor.c \ + src/resolve/resolved-etc-hosts.h \ + src/resolve/resolved-etc-hosts.c \ src/resolve/dns-type.c \ src/resolve/dns-type.h diff --git a/src/resolve/resolved-dns-query.c b/src/resolve/resolved-dns-query.c index 734b6ff770..1fe37a6813 100644 --- a/src/resolve/resolved-dns-query.c +++ b/src/resolve/resolved-dns-query.c @@ -25,6 +25,7 @@ #include "local-addresses.h" #include "resolved-dns-query.h" #include "resolved-dns-synthesize.h" +#include "resolved-etc-hosts.h" #include "string-util.h" /* How long to wait for the query in total */ @@ -550,13 +551,14 @@ fail: static int dns_query_synthesize_reply(DnsQuery *q, DnsTransactionState *state) { _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL; - DnsProtocol protocol; - int family, r; + int r; assert(q); assert(state); - /* Tries to synthesize localhost RR replies (and others) where appropriate */ + /* Tries to synthesize localhost RR replies (and others) where appropriate. Note that this is done *after* the + * the normal lookup finished. The data from the network hence takes precedence over the data we + * synthesize. (But note that many scopes refuse to resolve certain domain names) */ if (!IN_SET(*state, DNS_TRANSACTION_RCODE_FAILURE, @@ -571,10 +573,7 @@ static int dns_query_synthesize_reply(DnsQuery *q, DnsTransactionState *state) { q->manager, q->question_utf8, q->ifindex, - q->flags, - &answer, - &protocol, - &family); + &answer); if (r <= 0) return r; @@ -584,8 +583,8 @@ static int dns_query_synthesize_reply(DnsQuery *q, DnsTransactionState *state) { q->answer = answer; answer = NULL; q->answer_rcode = DNS_RCODE_SUCCESS; - q->answer_protocol = protocol; - q->answer_family = family; + q->answer_protocol = dns_synthesize_protocol(q->flags); + q->answer_family = dns_synthesize_family(q->flags); q->answer_authenticated = true; *state = DNS_TRANSACTION_SUCCESS; @@ -593,6 +592,34 @@ static int dns_query_synthesize_reply(DnsQuery *q, DnsTransactionState *state) { return 1; } +static int dns_query_try_etc_hosts(DnsQuery *q) { + _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL; + int r; + + assert(q); + + /* Looks in /etc/hosts for matching entries. Note that this is done *before* the normal lookup is done. The + * data from /etc/hosts hence takes precedence over the network. */ + + r = manager_etc_hosts_lookup( + q->manager, + q->question_utf8, + &answer); + if (r <= 0) + return r; + + dns_query_reset_answer(q); + + q->answer = answer; + answer = NULL; + q->answer_rcode = DNS_RCODE_SUCCESS; + q->answer_protocol = dns_synthesize_protocol(q->flags); + q->answer_family = dns_synthesize_family(q->flags); + q->answer_authenticated = true; + + return 1; +} + int dns_query_go(DnsQuery *q) { DnsScopeMatch found = DNS_SCOPE_NO; DnsScope *s, *first = NULL; @@ -604,6 +631,14 @@ int dns_query_go(DnsQuery *q) { if (q->state != DNS_TRANSACTION_NULL) return 0; + r = dns_query_try_etc_hosts(q); + if (r < 0) + return r; + if (r > 0) { + dns_query_complete(q, DNS_TRANSACTION_SUCCESS); + return 1; + } + LIST_FOREACH(scopes, s, q->manager->dns_scopes) { DnsScopeMatch match; const char *name; diff --git a/src/resolve/resolved-dns-synthesize.c b/src/resolve/resolved-dns-synthesize.c index d93741b736..f4a43dee8c 100644 --- a/src/resolve/resolved-dns-synthesize.c +++ b/src/resolve/resolved-dns-synthesize.c @@ -22,7 +22,7 @@ #include "local-addresses.h" #include "resolved-dns-synthesize.h" -static int SYNTHESIZE_IFINDEX(int ifindex) { +int dns_synthesize_ifindex(int ifindex) { /* When the caller asked for resolving on a specific * interface, we synthesize the answer for that @@ -36,7 +36,7 @@ static int SYNTHESIZE_IFINDEX(int ifindex) { return LOOPBACK_IFINDEX; } -static int SYNTHESIZE_FAMILY(uint64_t flags) { +int dns_synthesize_family(uint64_t flags) { /* Picks an address family depending on set flags. This is * purely for synthesized answers, where the family we return @@ -54,9 +54,9 @@ static int SYNTHESIZE_FAMILY(uint64_t flags) { return AF_UNSPEC; } -static DnsProtocol SYNTHESIZE_PROTOCOL(uint64_t flags) { +DnsProtocol dns_synthesize_protocol(uint64_t flags) { - /* Similar as SYNTHESIZE_FAMILY() but does this for the + /* Similar as dns_synthesize_family() but does this for the * protocol. If resolving via DNS was requested, we claim it * was DNS. Similar, if nothing specific was * requested. However, if only resolving via LLMNR was @@ -92,7 +92,7 @@ static int synthesize_localhost_rr(Manager *m, const DnsResourceKey *key, int if rr->a.in_addr.s_addr = htobe32(INADDR_LOOPBACK); - r = dns_answer_add(*answer, rr, SYNTHESIZE_IFINDEX(ifindex), DNS_ANSWER_AUTHENTICATED); + r = dns_answer_add(*answer, rr, dns_synthesize_ifindex(ifindex), DNS_ANSWER_AUTHENTICATED); if (r < 0) return r; } @@ -106,7 +106,7 @@ static int synthesize_localhost_rr(Manager *m, const DnsResourceKey *key, int if rr->aaaa.in6_addr = in6addr_loopback; - r = dns_answer_add(*answer, rr, SYNTHESIZE_IFINDEX(ifindex), DNS_ANSWER_AUTHENTICATED); + r = dns_answer_add(*answer, rr, dns_synthesize_ifindex(ifindex), DNS_ANSWER_AUTHENTICATED); if (r < 0) return r; } @@ -140,7 +140,7 @@ static int synthesize_localhost_ptr(Manager *m, const DnsResourceKey *key, int i if (r < 0) return r; - r = answer_add_ptr(answer, DNS_RESOURCE_KEY_NAME(key), "localhost", SYNTHESIZE_IFINDEX(ifindex), DNS_ANSWER_AUTHENTICATED); + r = answer_add_ptr(answer, DNS_RESOURCE_KEY_NAME(key), "localhost", dns_synthesize_ifindex(ifindex), DNS_ANSWER_AUTHENTICATED); if (r < 0) return r; } @@ -243,14 +243,14 @@ static int synthesize_system_hostname_rr(Manager *m, const DnsResourceKey *key, if (af == AF_INET || af == AF_UNSPEC) buffer[n++] = (struct local_address) { .family = AF_INET, - .ifindex = SYNTHESIZE_IFINDEX(ifindex), + .ifindex = dns_synthesize_ifindex(ifindex), .address.in.s_addr = htobe32(0x7F000002), }; if (af == AF_INET6 || af == AF_UNSPEC) buffer[n++] = (struct local_address) { .family = AF_INET6, - .ifindex = SYNTHESIZE_IFINDEX(ifindex), + .ifindex = dns_synthesize_ifindex(ifindex), .address.in6 = in6addr_loopback, }; @@ -278,15 +278,15 @@ static int synthesize_system_hostname_ptr(Manager *m, int af, const union in_add if (r < 0) return r; - r = answer_add_ptr(answer, "2.0.0.127.in-addr.arpa", m->llmnr_hostname, SYNTHESIZE_IFINDEX(ifindex), DNS_ANSWER_AUTHENTICATED); + r = answer_add_ptr(answer, "2.0.0.127.in-addr.arpa", m->llmnr_hostname, dns_synthesize_ifindex(ifindex), DNS_ANSWER_AUTHENTICATED); if (r < 0) return r; - r = answer_add_ptr(answer, "2.0.0.127.in-addr.arpa", m->mdns_hostname, SYNTHESIZE_IFINDEX(ifindex), DNS_ANSWER_AUTHENTICATED); + r = answer_add_ptr(answer, "2.0.0.127.in-addr.arpa", m->mdns_hostname, dns_synthesize_ifindex(ifindex), DNS_ANSWER_AUTHENTICATED); if (r < 0) return r; - r = answer_add_ptr(answer, "2.0.0.127.in-addr.arpa", "localhost", SYNTHESIZE_IFINDEX(ifindex), DNS_ANSWER_AUTHENTICATED); + r = answer_add_ptr(answer, "2.0.0.127.in-addr.arpa", "localhost", dns_synthesize_ifindex(ifindex), DNS_ANSWER_AUTHENTICATED); if (r < 0) return r; @@ -341,10 +341,7 @@ int dns_synthesize_answer( Manager *m, DnsQuestion *q, int ifindex, - uint64_t flags, - DnsAnswer **ret, - DnsProtocol *ret_protocol, - int *ret_family) { + DnsAnswer **ret) { _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL; DnsResourceKey *key; @@ -412,11 +409,5 @@ int dns_synthesize_answer( answer = NULL; } - if (ret_protocol) - *ret_protocol = SYNTHESIZE_PROTOCOL(flags); - - if (ret_family) - *ret_family = SYNTHESIZE_FAMILY(flags); - return r; } diff --git a/src/resolve/resolved-dns-synthesize.h b/src/resolve/resolved-dns-synthesize.h index e43d96cb2c..5d829bb2e7 100644 --- a/src/resolve/resolved-dns-synthesize.h +++ b/src/resolve/resolved-dns-synthesize.h @@ -23,4 +23,8 @@ #include "resolved-dns-question.h" #include "resolved-manager.h" -int dns_synthesize_answer(Manager *m, DnsQuestion *q, int ifindex, uint64_t flags, DnsAnswer **ret, DnsProtocol *ret_protocol, int *ret_family); +int dns_synthesize_ifindex(int ifindex); +int dns_synthesize_family(uint64_t flags); +DnsProtocol dns_synthesize_protocol(uint64_t flags); + +int dns_synthesize_answer(Manager *m, DnsQuestion *q, int ifindex, DnsAnswer **ret); diff --git a/src/resolve/resolved-etc-hosts.c b/src/resolve/resolved-etc-hosts.c new file mode 100644 index 0000000000..467754774f --- /dev/null +++ b/src/resolve/resolved-etc-hosts.c @@ -0,0 +1,448 @@ +/*** + This file is part of systemd. + + Copyright 2016 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include "fd-util.h" +#include "fileio.h" +#include "hostname-util.h" +#include "resolved-etc-hosts.h" +#include "resolved-dns-synthesize.h" +#include "string-util.h" +#include "strv.h" +#include "time-util.h" + +/* Recheck /etc/hosts at most once every 2s */ +#define ETC_HOSTS_RECHECK_USEC (2*USEC_PER_SEC) + +typedef struct EtcHostsItem { + int family; + union in_addr_union address; + + char **names; +} EtcHostsItem; + +typedef struct EtcHostsItemByName { + char *name; + + EtcHostsItem **items; + size_t n_items, n_allocated; +} EtcHostsItemByName; + +void manager_etc_hosts_flush(Manager *m) { + EtcHostsItem *item; + EtcHostsItemByName *bn; + + while ((item = set_steal_first(m->etc_hosts_by_address))) { + strv_free(item->names); + free(item); + } + + while ((bn = hashmap_steal_first(m->etc_hosts_by_name))) { + free(bn->name); + free(bn->items); + free(bn); + } + + m->etc_hosts_by_address = set_free(m->etc_hosts_by_address); + m->etc_hosts_by_name = hashmap_free(m->etc_hosts_by_name); + + m->etc_hosts_mtime = USEC_INFINITY; +} + +static void etc_hosts_item_hash_func(const void *p, struct siphash *state) { + const EtcHostsItem *item = p; + + siphash24_compress(&item->family, sizeof(item->family), state); + + if (item->family == AF_INET) + siphash24_compress(&item->address.in, sizeof(item->address.in), state); + else if (item->family == AF_INET6) + siphash24_compress(&item->address.in6, sizeof(item->address.in6), state); +} + +static int etc_hosts_item_compare_func(const void *a, const void *b) { + const EtcHostsItem *x = a, *y = b; + + if (x->family != x->family) + return x->family - y->family; + + if (x->family == AF_INET) + return memcmp(&x->address.in.s_addr, &y->address.in.s_addr, sizeof(struct in_addr)); + + if (x->family == AF_INET6) + return memcmp(&x->address.in6.s6_addr, &y->address.in6.s6_addr, sizeof(struct in6_addr)); + + return trivial_compare_func(a, b); +} + +static const struct hash_ops etc_hosts_item_ops = { + .hash = etc_hosts_item_hash_func, + .compare = etc_hosts_item_compare_func, +}; + +static int add_item(Manager *m, int family, const union in_addr_union *address, char **names) { + + EtcHostsItem key = { + .family = family, + .address = *address, + }; + EtcHostsItem *item; + char **n; + int r; + + assert(m); + assert(address); + + r = in_addr_is_null(family, address); + if (r < 0) + return r; + if (r > 0) + /* This is an 0.0.0.0 or :: item, which we assume means that we shall map the specified hostname to + * nothing. */ + item = NULL; + else { + /* If this is a normal address, then, simply add entry mapping it to the specified names */ + + item = set_get(m->etc_hosts_by_address, &key); + if (item) { + r = strv_extend_strv(&item->names, names, true); + if (r < 0) + return log_oom(); + } else { + + r = set_ensure_allocated(&m->etc_hosts_by_address, &etc_hosts_item_ops); + if (r < 0) + return log_oom(); + + item = new0(EtcHostsItem, 1); + if (!item) + return log_oom(); + + item->family = family; + item->address = *address; + item->names = names; + + r = set_put(m->etc_hosts_by_address, item); + if (r < 0) { + free(item); + return log_oom(); + } + } + } + + STRV_FOREACH(n, names) { + EtcHostsItemByName *bn; + + bn = hashmap_get(m->etc_hosts_by_name, *n); + if (!bn) { + r = hashmap_ensure_allocated(&m->etc_hosts_by_name, &dns_name_hash_ops); + if (r < 0) + return log_oom(); + + bn = new0(EtcHostsItemByName, 1); + if (!bn) + return log_oom(); + + bn->name = strdup(*n); + if (!bn->name) { + free(bn); + return log_oom(); + } + + r = hashmap_put(m->etc_hosts_by_name, bn->name, bn); + if (r < 0) { + free(bn->name); + free(bn); + return log_oom(); + } + } + + if (item) { + if (!GREEDY_REALLOC(bn->items, bn->n_allocated, bn->n_items+1)) + return log_oom(); + + bn->items[bn->n_items++] = item; + } + } + + return 0; +} + +static int parse_line(Manager *m, unsigned nr, const char *line) { + _cleanup_free_ char *address = NULL; + _cleanup_strv_free_ char **names = NULL; + union in_addr_union in; + bool suppressed = false; + int family, r; + + assert(m); + assert(line); + + r = extract_first_word(&line, &address, NULL, EXTRACT_RELAX); + if (r < 0) + return log_error_errno(r, "Couldn't extract address, in line /etc/hosts:%u.", nr); + if (r == 0) { + log_error("Premature end of line, in line /etc/hosts:%u.", nr); + return -EINVAL; + } + + r = in_addr_from_string_auto(address, &family, &in); + if (r < 0) + return log_error_errno(r, "Address '%s' is invalid, in line /etc/hosts:%u.", address, nr); + + for (;;) { + _cleanup_free_ char *name = NULL; + + r = extract_first_word(&line, &name, NULL, EXTRACT_RELAX); + if (r < 0) + return log_error_errno(r, "Couldn't extract host name, in line /etc/hosts:%u.", nr); + if (r == 0) + break; + + r = dns_name_is_valid(name); + if (r <= 0) + return log_error_errno(r, "Hostname %s is not valid, ignoring, in line /etc/hosts:%u.", name, nr); + + if (is_localhost(name)) { + /* Suppress the "localhost" line that is often seen */ + suppressed = true; + continue; + } + + r = strv_push(&names, name); + if (r < 0) + return log_oom(); + + name = NULL; + } + + if (strv_isempty(names)) { + + if (suppressed) + return 0; + + log_error("Line is missing any host names, in line /etc/hosts:%u.", nr); + return -EINVAL; + } + + /* Takes possession of the names strv */ + r = add_item(m, family, &in, names); + if (r < 0) + return r; + + names = NULL; + return r; +} + +int manager_etc_hosts_read(Manager *m) { + _cleanup_fclose_ FILE *f = NULL; + char line[LINE_MAX]; + struct stat st; + usec_t ts; + unsigned nr = 0; + int r; + + assert_se(sd_event_now(m->event, clock_boottime_or_monotonic(), &ts) >= 0); + + /* See if we checked /etc/hosts recently already */ + if (m->etc_hosts_last != USEC_INFINITY && m->etc_hosts_last + ETC_HOSTS_RECHECK_USEC > ts) + return 0; + + m->etc_hosts_last = ts; + + if (m->etc_hosts_mtime != USEC_INFINITY) { + if (stat("/etc/hosts", &st) < 0) { + if (errno == ENOENT) { + r = 0; + goto clear; + } + + return log_error_errno(errno, "Failed to stat /etc/hosts: %m"); + } + + /* Did the mtime change? If not, there's no point in re-reading the file. */ + if (timespec_load(&st.st_mtim) == m->etc_hosts_mtime) + return 0; + } + + f = fopen("/etc/hosts", "re"); + if (!f) { + if (errno == ENOENT) { + r = 0; + goto clear; + } + + return log_error_errno(errno, "Failed to open /etc/hosts: %m"); + } + + /* Take the timestamp at the beginning of processing, so that any changes made later are read on the next + * invocation */ + r = fstat(fileno(f), &st); + if (r < 0) + return log_error_errno(errno, "Failed to fstat() /etc/hosts: %m"); + + manager_etc_hosts_flush(m); + + FOREACH_LINE(line, f, return log_error_errno(errno, "Failed to read /etc/hosts: %m")) { + char *l; + + nr ++; + + l = strstrip(line); + if (isempty(l)) + continue; + if (l[0] == '#') + continue; + + r = parse_line(m, nr, l); + if (r == -ENOMEM) /* On OOM we abandon the half-built-up structure. All other errors we ignore and proceed */ + goto clear; + } + + m->etc_hosts_mtime = timespec_load(&st.st_mtim); + m->etc_hosts_last = ts; + + return 1; + +clear: + manager_etc_hosts_flush(m); + return r; +} + +int manager_etc_hosts_lookup(Manager *m, DnsQuestion* q, DnsAnswer **answer) { + bool found_a = false, found_aaaa = false; + EtcHostsItemByName *bn; + EtcHostsItem k = {}; + DnsResourceKey *t; + const char *name; + unsigned i; + int r; + + assert(m); + assert(q); + assert(answer); + + r = manager_etc_hosts_read(m); + if (r < 0) + return r; + + name = dns_question_first_name(q); + if (!name) + return 0; + + r = dns_name_address(name, &k.family, &k.address); + if (r > 0) { + EtcHostsItem *item; + DnsResourceKey *found_ptr = NULL; + + item = set_get(m->etc_hosts_by_address, &k); + if (!item) + return 0; + + /* We have an address in /etc/hosts that matches the queried name. Let's return successful. Actual data + * we'll only return if the request was for PTR. */ + + DNS_QUESTION_FOREACH(t, q) { + if (!IN_SET(t->type, DNS_TYPE_PTR, DNS_TYPE_ANY)) + continue; + if (!IN_SET(t->class, DNS_CLASS_IN, DNS_CLASS_ANY)) + continue; + + r = dns_name_equal(DNS_RESOURCE_KEY_NAME(t), name); + if (r < 0) + return r; + if (r > 0) { + found_ptr = t; + break; + } + } + + if (found_ptr) { + char **n; + + r = dns_answer_reserve(answer, strv_length(item->names)); + if (r < 0) + return r; + + STRV_FOREACH(n, item->names) { + _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL; + + rr = dns_resource_record_new(found_ptr); + if (!rr) + return -ENOMEM; + + rr->ptr.name = strdup(*n); + if (!rr->ptr.name) + return -ENOMEM; + + r = dns_answer_add(*answer, rr, 0, DNS_ANSWER_AUTHENTICATED); + if (r < 0) + return r; + } + } + + return 1; + } + + bn = hashmap_get(m->etc_hosts_by_name, name); + if (!bn) + return 0; + + r = dns_answer_reserve(answer, bn->n_items); + if (r < 0) + return r; + + DNS_QUESTION_FOREACH(t, q) { + if (!IN_SET(t->type, DNS_TYPE_A, DNS_TYPE_AAAA, DNS_TYPE_ANY)) + continue; + if (!IN_SET(t->class, DNS_CLASS_IN, DNS_CLASS_ANY)) + continue; + + r = dns_name_equal(DNS_RESOURCE_KEY_NAME(t), name); + if (r < 0) + return r; + if (r == 0) + continue; + + if (IN_SET(t->type, DNS_TYPE_A, DNS_TYPE_ANY)) + found_a = true; + if (IN_SET(t->type, DNS_TYPE_AAAA, DNS_TYPE_ANY)) + found_aaaa = true; + + if (found_a && found_aaaa) + break; + } + + for (i = 0; i < bn->n_items; i++) { + _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL; + + if ((found_a && bn->items[i]->family != AF_INET) && + (found_aaaa && bn->items[i]->family != AF_INET6)) + continue; + + r = dns_resource_record_new_address(&rr, bn->items[i]->family, &bn->items[i]->address, bn->name); + if (r < 0) + return r; + + r = dns_answer_add(*answer, rr, 0, DNS_ANSWER_AUTHENTICATED); + if (r < 0) + return r; + } + + return 1; +} diff --git a/src/resolve/resolved-etc-hosts.h b/src/resolve/resolved-etc-hosts.h new file mode 100644 index 0000000000..9d5a175f18 --- /dev/null +++ b/src/resolve/resolved-etc-hosts.h @@ -0,0 +1,28 @@ +#pragma once + +/*** + This file is part of systemd. + + Copyright 2016 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include "resolved-manager.h" +#include "resolved-dns-question.h" +#include "resolved-dns-answer.h" + +void manager_etc_hosts_flush(Manager *m); +int manager_etc_hosts_read(Manager *m); +int manager_etc_hosts_lookup(Manager *m, DnsQuestion* q, DnsAnswer **answer); diff --git a/src/resolve/resolved-manager.c b/src/resolve/resolved-manager.c index 4ee19ca382..704f012c37 100644 --- a/src/resolve/resolved-manager.c +++ b/src/resolve/resolved-manager.c @@ -37,10 +37,11 @@ #include "random-util.h" #include "resolved-bus.h" #include "resolved-conf.h" +#include "resolved-etc-hosts.h" #include "resolved-llmnr.h" #include "resolved-manager.h" -#include "resolved-resolv-conf.h" #include "resolved-mdns.h" +#include "resolved-resolv-conf.h" #include "socket-util.h" #include "string-table.h" #include "string-util.h" @@ -485,6 +486,7 @@ int manager_new(Manager **ret) { m->dnssec_mode = DNSSEC_NO; m->read_resolv_conf = true; m->need_builtin_fallbacks = true; + m->etc_hosts_last = m->etc_hosts_mtime = USEC_INFINITY; r = dns_trust_anchor_load(&m->trust_anchor); if (r < 0) @@ -594,6 +596,7 @@ Manager *manager_free(Manager *m) { free(m->mdns_hostname); dns_trust_anchor_flush(&m->trust_anchor); + manager_etc_hosts_flush(m); free(m); diff --git a/src/resolve/resolved-manager.h b/src/resolve/resolved-manager.h index 5a8c2c8750..a4291d57ff 100644 --- a/src/resolve/resolved-manager.h +++ b/src/resolve/resolved-manager.h @@ -124,6 +124,11 @@ struct Manager { unsigned n_transactions_total; unsigned n_dnssec_verdict[_DNSSEC_VERDICT_MAX]; + + /* Data from /etc/hosts */ + Set* etc_hosts_by_address; + Hashmap* etc_hosts_by_name; + usec_t etc_hosts_last, etc_hosts_mtime; }; /* Manager */ |