test-resolved-etc-hosts: add tests for /etc/hosts parsing

Calling 'build/test-resolved-etc-hosts filename' parses just that file.
This is useful to test against https://hosts.ubuntu101.co.za/hosts.
This commit is contained in:
Zbigniew Jędrzejewski-Szmek 2018-07-31 11:01:21 +02:00
parent 37b7cc8d9a
commit 78fc21a11a
4 changed files with 115 additions and 16 deletions

View file

@ -192,6 +192,16 @@ tests += [
libm],
'ENABLE_RESOLVE'],
[['src/resolve/test-resolved-etc-hosts.c',
'src/resolve/resolved-etc-hosts.c',
'src/resolve/resolved-etc-hosts.h'],
[libsystemd_resolve_core,
libshared],
[libgcrypt,
libgpg_error,
libm],
'ENABLE_RESOLVE'],
[['src/resolve/test-resolved-packet.c',
dns_type_headers],
[libsystemd_resolve_core,

View file

@ -12,19 +12,6 @@
/* 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);
@ -36,7 +23,7 @@ static inline void etc_hosts_item_by_name_free(EtcHostsItemByName *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);
}
@ -76,7 +63,7 @@ static int parse_line(EtcHosts *hosts, unsigned nr, const char *line) {
* 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) {
@ -161,7 +148,7 @@ static int parse_line(EtcHosts *hosts, unsigned nr, const char *line) {
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;

View file

@ -5,5 +5,21 @@
#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);

View file

@ -0,0 +1,86 @@
/* 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;
}