/* Recheck /etc/hosts at most once every 2s */
#define ETC_HOSTS_RECHECK_USEC (2*USEC_PER_SEC)
-typedef struct EtcHostsItem {
- struct in_addr_data address;
-
- char **names;
-} EtcHostsItem;
-
-typedef struct EtcHostsItemByName {
- char *name;
-
- struct in_addr_data **addresses;
- size_t n_addresses, n_allocated;
-} EtcHostsItemByName;
-
static inline void etc_hosts_item_free(EtcHostsItem *item) {
strv_free(item->names);
free(item);
free(item);
}
-static void etc_hosts_free(EtcHosts *hosts) {
+void etc_hosts_free(EtcHosts *hosts) {
hosts->by_address = hashmap_free_with_destructor(hosts->by_address, etc_hosts_item_free);
hosts->by_name = hashmap_free_with_destructor(hosts->by_name, etc_hosts_item_by_name_free);
}
* nothing. */
item = NULL;
else {
- /* If this is a normal address, then, simply add entry mapping it to the specified names */
+ /* If this is a normal address, then simply add entry mapping it to the specified names */
item = hashmap_get(hosts->by_address, &address);
if (!item) {
return 0;
}
-static int etc_hosts_parse(EtcHosts *hosts, FILE *f) {
+int etc_hosts_parse(EtcHosts *hosts, FILE *f) {
_cleanup_(etc_hosts_free) EtcHosts t = {};
char line[LINE_MAX];
unsigned nr = 0;
#include "resolved-dns-question.h"
#include "resolved-dns-answer.h"
+typedef struct EtcHostsItem {
+ struct in_addr_data address;
+
+ char **names;
+} EtcHostsItem;
+
+typedef struct EtcHostsItemByName {
+ char *name;
+
+ struct in_addr_data **addresses;
+ size_t n_addresses, n_allocated;
+} EtcHostsItemByName;
+
+int etc_hosts_parse(EtcHosts *hosts, FILE *f);
+void etc_hosts_free(EtcHosts *hosts);
+
void manager_etc_hosts_flush(Manager *m);
int manager_etc_hosts_lookup(Manager *m, DnsQuestion* q, DnsAnswer **answer);
--- /dev/null
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include "fd-util.h"
+#include "fileio.h"
+#include "fs-util.h"
+#include "log.h"
+#include "resolved-etc-hosts.h"
+
+static void test_parse_etc_hosts_system(void) {
+ _cleanup_fclose_ FILE *f = NULL;
+
+ f = fopen("/etc/hosts", "r");
+ if (!f) {
+ assert_se(errno == -ENOENT);
+ return;
+ }
+
+ _cleanup_(etc_hosts_free) EtcHosts hosts = {};
+ assert_se(etc_hosts_parse(&hosts, f) == 0);
+}
+
+static void test_parse_etc_hosts(const char *fname) {
+ _cleanup_(unlink_tempfilep) char
+ t[] = "/tmp/test-resolved-etc-hosts.XXXXXX";
+
+ int fd;
+ _cleanup_fclose_ FILE *f;
+
+ if (fname) {
+ f = fopen(fname, "r");
+ assert_se(f);
+ } else {
+ fd = mkostemp_safe(t);
+ assert_se(fd >= 0);
+
+ f = fdopen(fd, "r+");
+ fputs("1.2.3.4 some.where\n", f);
+ fputs("1.2.3.5 some.where\n", f);
+ fputs("::0 some.where some.other\n", f);
+ fputs("0.0.0.0 black.listed\n", f);
+ fputs("::5 some.where some.other foobar.foo.foo\n", f);
+ fputs(" \n", f);
+ fflush(f);
+ rewind(f);
+ }
+
+ _cleanup_(etc_hosts_free) EtcHosts hosts = {};
+ assert_se(etc_hosts_parse(&hosts, f) == 0);
+
+ if (fname)
+ return;
+
+ EtcHostsItemByName *bn;
+ assert_se(bn = hashmap_get(hosts.by_name, "some.where"));
+ assert_se(bn->n_addresses == 3);
+ assert_se(bn->n_allocated >= 3);
+
+ assert_se(bn->addresses[0]->family == AF_INET);
+ assert_se(memcmp(&bn->addresses[0]->address.in,
+ &(struct in_addr) { .s_addr = htobe32(0x01020304) }, 4) == 0);
+ assert_se(bn->addresses[1]->family == AF_INET);
+ assert_se(memcmp(&bn->addresses[1]->address.in,
+ &(struct in_addr) { .s_addr = htobe32(0x01020305) }, 4) == 0);
+ assert_se(bn->addresses[2]->family == AF_INET6);
+ assert_se(memcmp(&bn->addresses[2]->address.in6,
+ &(struct in6_addr) { .s6_addr = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5} }, 16 ) == 0);
+
+ assert_se(bn = hashmap_get(hosts.by_name, "some.other"));
+ assert_se(bn->n_addresses == 1);
+ assert_se(bn->n_allocated >= 1);
+ assert_se(bn->addresses[0]->family == AF_INET6);
+ assert_se(memcmp(&bn->addresses[0]->address.in6,
+ &(struct in6_addr) { .s6_addr = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5} }, 16 ) == 0);
+}
+
+int main(int argc, char **argv) {
+ log_set_max_level(LOG_DEBUG);
+ log_parse_environment();
+ log_open();
+
+ if (argc == 1)
+ test_parse_etc_hosts_system();
+ test_parse_etc_hosts(argv[1]);
+
+ return 0;
+}