Branch data Line data Source code
1 : : /* SPDX-License-Identifier: LGPL-2.1+ */
2 : :
3 : : #include <arpa/inet.h>
4 : : #include <netinet/in.h>
5 : : #include <sys/socket.h>
6 : :
7 : : #include "fd-util.h"
8 : : #include "fileio.h"
9 : : #include "fs-util.h"
10 : : #include "log.h"
11 : : #include "resolved-etc-hosts.h"
12 : : #include "strv.h"
13 : : #include "tests.h"
14 : : #include "tmpfile-util.h"
15 : :
16 : 4 : static void test_parse_etc_hosts_system(void) {
17 [ + - ]: 4 : _cleanup_fclose_ FILE *f = NULL;
18 : :
19 [ + - ]: 4 : log_info("/* %s */", __func__);
20 : :
21 : 4 : f = fopen("/etc/hosts", "re");
22 [ - + ]: 4 : if (!f) {
23 [ # # ]: 0 : assert_se(errno == ENOENT);
24 : 0 : return;
25 : : }
26 : :
27 : 4 : _cleanup_(etc_hosts_free) EtcHosts hosts = {};
28 [ - + ]: 4 : assert_se(etc_hosts_parse(&hosts, f) == 0);
29 : : }
30 : :
31 : : #define address_equal_4(_addr, _address) \
32 : : ((_addr)->family == AF_INET && \
33 : : !memcmp(&(_addr)->address.in, &(struct in_addr) { .s_addr = (_address) }, 4))
34 : :
35 : : #define address_equal_6(_addr, ...) \
36 : : ((_addr)->family == AF_INET6 && \
37 : : !memcmp(&(_addr)->address.in6, &(struct in6_addr) { .s6_addr = __VA_ARGS__}, 16) )
38 : :
39 : 4 : static void test_parse_etc_hosts(void) {
40 : : _cleanup_(unlink_tempfilep) char
41 : 4 : t[] = "/tmp/test-resolved-etc-hosts.XXXXXX";
42 : :
43 [ + - ]: 4 : log_info("/* %s */", __func__);
44 : :
45 : : int fd;
46 : 4 : _cleanup_fclose_ FILE *f;
47 : : const char *s;
48 : :
49 : 4 : fd = mkostemp_safe(t);
50 [ - + ]: 4 : assert_se(fd >= 0);
51 : :
52 : 4 : f = fdopen(fd, "r+");
53 [ - + ]: 4 : assert_se(f);
54 : 4 : fputs("1.2.3.4 some.where\n"
55 : : "1.2.3.5 some.where\n"
56 : : "1.2.3.6 dash dash-dash.where-dash\n"
57 : : "1.2.3.7 bad-dash- -bad-dash -bad-dash.bad-\n"
58 : : "1.2.3.8\n"
59 : : "1.2.3.9 before.comment # within.comment\n"
60 : : "1.2.3.10 before.comment#within.comment2\n"
61 : : "1.2.3.11 before.comment# within.comment3\n"
62 : : "1.2.3.12 before.comment#\n"
63 : : "1.2.3 short.address\n"
64 : : "1.2.3.4.5 long.address\n"
65 : : "1::2::3 multi.colon\n"
66 : :
67 : : "::0 some.where some.other\n"
68 : : "0.0.0.0 black.listed\n"
69 : : "::5\t\t\t \tsome.where\tsome.other foobar.foo.foo\t\t\t\n"
70 : : " \n", f);
71 [ - + ]: 4 : assert_se(fflush_and_check(f) >= 0);
72 : 4 : rewind(f);
73 : :
74 : 4 : _cleanup_(etc_hosts_free) EtcHosts hosts = {};
75 [ - + ]: 4 : assert_se(etc_hosts_parse(&hosts, f) == 0);
76 : :
77 : : EtcHostsItemByName *bn;
78 [ - + ]: 4 : assert_se(bn = hashmap_get(hosts.by_name, "some.where"));
79 [ - + ]: 4 : assert_se(bn->n_addresses == 3);
80 [ - + ]: 4 : assert_se(bn->n_allocated >= 3);
81 [ + - - + ]: 4 : assert_se(address_equal_4(bn->addresses[0], inet_addr("1.2.3.4")));
82 [ + - - + ]: 4 : assert_se(address_equal_4(bn->addresses[1], inet_addr("1.2.3.5")));
83 [ + - - + ]: 4 : assert_se(address_equal_6(bn->addresses[2], {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5}));
84 : :
85 [ - + ]: 4 : assert_se(bn = hashmap_get(hosts.by_name, "dash"));
86 [ - + ]: 4 : assert_se(bn->n_addresses == 1);
87 [ - + ]: 4 : assert_se(bn->n_allocated >= 1);
88 [ + - - + ]: 4 : assert_se(address_equal_4(bn->addresses[0], inet_addr("1.2.3.6")));
89 : :
90 [ - + ]: 4 : assert_se(bn = hashmap_get(hosts.by_name, "dash-dash.where-dash"));
91 [ - + ]: 4 : assert_se(bn->n_addresses == 1);
92 [ - + ]: 4 : assert_se(bn->n_allocated >= 1);
93 [ + - - + ]: 4 : assert_se(address_equal_4(bn->addresses[0], inet_addr("1.2.3.6")));
94 : :
95 : : /* See https://tools.ietf.org/html/rfc1035#section-2.3.1 */
96 [ + + ]: 16 : FOREACH_STRING(s, "bad-dash-", "-bad-dash", "-bad-dash.bad-")
97 [ - + ]: 12 : assert_se(!hashmap_get(hosts.by_name, s));
98 : :
99 [ - + ]: 4 : assert_se(bn = hashmap_get(hosts.by_name, "before.comment"));
100 [ - + ]: 4 : assert_se(bn->n_addresses == 4);
101 [ - + ]: 4 : assert_se(bn->n_allocated >= 4);
102 [ + - - + ]: 4 : assert_se(address_equal_4(bn->addresses[0], inet_addr("1.2.3.9")));
103 [ + - - + ]: 4 : assert_se(address_equal_4(bn->addresses[1], inet_addr("1.2.3.10")));
104 [ + - - + ]: 4 : assert_se(address_equal_4(bn->addresses[2], inet_addr("1.2.3.11")));
105 [ + - - + ]: 4 : assert_se(address_equal_4(bn->addresses[3], inet_addr("1.2.3.12")));
106 : :
107 [ - + ]: 4 : assert(!hashmap_get(hosts.by_name, "within.comment"));
108 [ - + ]: 4 : assert(!hashmap_get(hosts.by_name, "within.comment2"));
109 [ - + ]: 4 : assert(!hashmap_get(hosts.by_name, "within.comment3"));
110 [ - + ]: 4 : assert(!hashmap_get(hosts.by_name, "#"));
111 : :
112 [ - + ]: 4 : assert(!hashmap_get(hosts.by_name, "short.address"));
113 [ - + ]: 4 : assert(!hashmap_get(hosts.by_name, "long.address"));
114 [ - + ]: 4 : assert(!hashmap_get(hosts.by_name, "multi.colon"));
115 [ - + ]: 4 : assert_se(!set_contains(hosts.no_address, "short.address"));
116 [ - + ]: 4 : assert_se(!set_contains(hosts.no_address, "long.address"));
117 [ - + ]: 4 : assert_se(!set_contains(hosts.no_address, "multi.colon"));
118 : :
119 [ - + ]: 4 : assert_se(bn = hashmap_get(hosts.by_name, "some.other"));
120 [ - + ]: 4 : assert_se(bn->n_addresses == 1);
121 [ - + ]: 4 : assert_se(bn->n_allocated >= 1);
122 [ + - - + ]: 4 : assert_se(address_equal_6(bn->addresses[0], {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5}));
123 : :
124 [ - + ]: 4 : assert_se( set_contains(hosts.no_address, "some.where"));
125 [ - + ]: 4 : assert_se( set_contains(hosts.no_address, "some.other"));
126 [ - + ]: 4 : assert_se( set_contains(hosts.no_address, "black.listed"));
127 [ - + ]: 4 : assert_se(!set_contains(hosts.no_address, "foobar.foo.foo"));
128 : 4 : }
129 : :
130 : 0 : static void test_parse_file(const char *fname) {
131 : 0 : _cleanup_(etc_hosts_free) EtcHosts hosts = {};
132 : 0 : _cleanup_fclose_ FILE *f;
133 : :
134 [ # # ]: 0 : log_info("/* %s(\"%s\") */", __func__, fname);
135 : :
136 [ # # ]: 0 : assert_se(f = fopen(fname, "re"));
137 [ # # ]: 0 : assert_se(etc_hosts_parse(&hosts, f) == 0);
138 : 0 : }
139 : :
140 : 4 : int main(int argc, char **argv) {
141 : 4 : test_setup_logging(LOG_DEBUG);
142 : :
143 [ + - ]: 4 : if (argc == 1) {
144 : 4 : test_parse_etc_hosts_system();
145 : 4 : test_parse_etc_hosts();
146 : : } else
147 : 0 : test_parse_file(argv[1]);
148 : :
149 : 4 : return 0;
150 : : }
|