mirror of
https://github.com/systemd/systemd.git
synced 2024-12-25 01:34:28 +03:00
Merge pull request #9760 from yuwata/resolve-etc-hosts-cleanup
resolve: several cleanups of handing /etc/hosts
This commit is contained in:
commit
48e0e10ff5
@ -571,3 +571,34 @@ int in_addr_prefix_from_string_auto(
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
void in_addr_data_hash_func(const void *p, struct siphash *state) {
|
||||
const struct in_addr_data *a = p;
|
||||
|
||||
siphash24_compress(&a->family, sizeof(a->family), state);
|
||||
|
||||
if (a->family == AF_INET)
|
||||
siphash24_compress(&a->address.in, sizeof(a->address.in), state);
|
||||
else if (a->family == AF_INET6)
|
||||
siphash24_compress(&a->address.in6, sizeof(a->address.in6), state);
|
||||
}
|
||||
|
||||
int in_addr_data_compare_func(const void *a, const void *b) {
|
||||
const struct in_addr_data *x = a, *y = b;
|
||||
|
||||
if (x->family != y->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);
|
||||
}
|
||||
|
||||
const struct hash_ops in_addr_data_hash_ops = {
|
||||
.hash = in_addr_data_hash_func,
|
||||
.compare = in_addr_data_compare_func,
|
||||
};
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include <stddef.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include "hash-funcs.h"
|
||||
#include "macro.h"
|
||||
#include "util.h"
|
||||
|
||||
@ -53,3 +54,7 @@ static inline size_t FAMILY_ADDRESS_SIZE(int family) {
|
||||
}
|
||||
|
||||
#define IN_ADDR_NULL ((union in_addr_union) {})
|
||||
|
||||
void in_addr_data_hash_func(const void *p, struct siphash *state);
|
||||
int in_addr_data_compare_func(const void *a, const void *b);
|
||||
extern const struct hash_ops in_addr_data_hash_ops;
|
||||
|
@ -13,8 +13,7 @@
|
||||
#define ETC_HOSTS_RECHECK_USEC (2*USEC_PER_SEC)
|
||||
|
||||
typedef struct EtcHostsItem {
|
||||
int family;
|
||||
union in_addr_union address;
|
||||
struct in_addr_data address;
|
||||
|
||||
char **names;
|
||||
} EtcHostsItem;
|
||||
@ -22,76 +21,54 @@ typedef struct EtcHostsItem {
|
||||
typedef struct EtcHostsItemByName {
|
||||
char *name;
|
||||
|
||||
EtcHostsItem **items;
|
||||
size_t n_items, n_allocated;
|
||||
struct in_addr_data **addresses;
|
||||
size_t n_addresses, n_allocated;
|
||||
} EtcHostsItemByName;
|
||||
|
||||
void manager_etc_hosts_flush(Manager *m) {
|
||||
EtcHostsItem *item;
|
||||
EtcHostsItemByName *bn;
|
||||
|
||||
while ((item = set_steal_first(m->etc_hosts_by_address))) {
|
||||
while ((item = hashmap_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->addresses);
|
||||
free(bn);
|
||||
}
|
||||
|
||||
m->etc_hosts_by_address = set_free(m->etc_hosts_by_address);
|
||||
m->etc_hosts_by_address = hashmap_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 != y->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) {
|
||||
_cleanup_strv_free_ char **dummy = names;
|
||||
EtcHostsItem key = {
|
||||
.family = family,
|
||||
.address = *address,
|
||||
};
|
||||
static int parse_line(Manager *m, unsigned nr, const char *line) {
|
||||
_cleanup_free_ char *address_str = NULL;
|
||||
struct in_addr_data address = {};
|
||||
bool suppressed = false;
|
||||
EtcHostsItem *item;
|
||||
char **n;
|
||||
int r;
|
||||
|
||||
assert(m);
|
||||
assert(address);
|
||||
assert(line);
|
||||
|
||||
r = in_addr_is_null(family, address);
|
||||
r = extract_first_word(&line, &address_str, 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_ifindex_from_string_auto(address_str, &address.family, &address.address, NULL);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Address '%s' is invalid, in line /etc/hosts:%u.", address_str, nr);
|
||||
|
||||
r = in_addr_is_null(address.family, &address.address);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r > 0)
|
||||
@ -101,99 +78,29 @@ static int add_item(Manager *m, int family, const union in_addr_union *address,
|
||||
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);
|
||||
item = hashmap_get(m->etc_hosts_by_address, &address);
|
||||
if (!item) {
|
||||
r = hashmap_ensure_allocated(&m->etc_hosts_by_address, &in_addr_data_hash_ops);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
|
||||
item = new(EtcHostsItem, 1);
|
||||
item = new0(EtcHostsItem, 1);
|
||||
if (!item)
|
||||
return log_oom();
|
||||
|
||||
*item = (EtcHostsItem) {
|
||||
.family = family,
|
||||
.address = *address,
|
||||
.names = names,
|
||||
};
|
||||
item->address = address;
|
||||
|
||||
r = set_put(m->etc_hosts_by_address, item);
|
||||
r = hashmap_put(m->etc_hosts_by_address, &item->address, item);
|
||||
if (r < 0) {
|
||||
free(item);
|
||||
return log_oom();
|
||||
}
|
||||
|
||||
dummy = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
EtcHostsItemByName *bn;
|
||||
|
||||
r = extract_first_word(&line, &name, NULL, EXTRACT_RELAX);
|
||||
if (r < 0)
|
||||
@ -211,29 +118,47 @@ static int parse_line(Manager *m, unsigned nr, const char *line) {
|
||||
continue;
|
||||
}
|
||||
|
||||
r = strv_push(&names, name);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
if (item) {
|
||||
r = strv_extend(&item->names, name);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
}
|
||||
|
||||
name = NULL;
|
||||
bn = hashmap_get(m->etc_hosts_by_name, name);
|
||||
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();
|
||||
|
||||
r = hashmap_put(m->etc_hosts_by_name, name, bn);
|
||||
if (r < 0) {
|
||||
free(bn);
|
||||
return log_oom();
|
||||
}
|
||||
|
||||
bn->name = TAKE_PTR(name);
|
||||
}
|
||||
|
||||
if (item) {
|
||||
if (!GREEDY_REALLOC(bn->addresses, bn->n_allocated, bn->n_addresses + 1))
|
||||
return log_oom();
|
||||
|
||||
bn->addresses[bn->n_addresses++] = &item->address;
|
||||
}
|
||||
|
||||
suppressed = true;
|
||||
}
|
||||
|
||||
if (strv_isempty(names)) {
|
||||
|
||||
if (suppressed)
|
||||
return 0;
|
||||
|
||||
if (!suppressed) {
|
||||
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;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int manager_etc_hosts_read(Manager *m) {
|
||||
@ -313,8 +238,8 @@ clear:
|
||||
|
||||
int manager_etc_hosts_lookup(Manager *m, DnsQuestion* q, DnsAnswer **answer) {
|
||||
bool found_a = false, found_aaaa = false;
|
||||
struct in_addr_data k = {};
|
||||
EtcHostsItemByName *bn;
|
||||
EtcHostsItem k = {};
|
||||
DnsResourceKey *t;
|
||||
const char *name;
|
||||
unsigned i;
|
||||
@ -340,7 +265,7 @@ int manager_etc_hosts_lookup(Manager *m, DnsQuestion* q, DnsAnswer **answer) {
|
||||
EtcHostsItem *item;
|
||||
DnsResourceKey *found_ptr = NULL;
|
||||
|
||||
item = set_get(m->etc_hosts_by_address, &k);
|
||||
item = hashmap_get(m->etc_hosts_by_address, &k);
|
||||
if (!item)
|
||||
return 0;
|
||||
|
||||
@ -393,7 +318,7 @@ int manager_etc_hosts_lookup(Manager *m, DnsQuestion* q, DnsAnswer **answer) {
|
||||
if (!bn)
|
||||
return 0;
|
||||
|
||||
r = dns_answer_reserve(answer, bn->n_items);
|
||||
r = dns_answer_reserve(answer, bn->n_addresses);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@ -418,14 +343,14 @@ int manager_etc_hosts_lookup(Manager *m, DnsQuestion* q, DnsAnswer **answer) {
|
||||
break;
|
||||
}
|
||||
|
||||
for (i = 0; i < bn->n_items; i++) {
|
||||
for (i = 0; i < bn->n_addresses; 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))
|
||||
if ((!found_a && bn->addresses[i]->family == AF_INET) ||
|
||||
(!found_aaaa && bn->addresses[i]->family == AF_INET6))
|
||||
continue;
|
||||
|
||||
r = dns_resource_record_new_address(&rr, bn->items[i]->family, &bn->items[i]->address, bn->name);
|
||||
r = dns_resource_record_new_address(&rr, bn->addresses[i]->family, &bn->addresses[i]->address, bn->name);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
@ -114,7 +114,7 @@ struct Manager {
|
||||
unsigned n_dnssec_verdict[_DNSSEC_VERDICT_MAX];
|
||||
|
||||
/* Data from /etc/hosts */
|
||||
Set* etc_hosts_by_address;
|
||||
Hashmap* etc_hosts_by_address;
|
||||
Hashmap* etc_hosts_by_name;
|
||||
usec_t etc_hosts_last, etc_hosts_mtime;
|
||||
bool read_etc_hosts;
|
||||
|
Loading…
Reference in New Issue
Block a user