]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd-network/test-ndisc-rs.c
Merge pull request #3431 from poettering/network-fixes
[thirdparty/systemd.git] / src / libsystemd-network / test-ndisc-rs.c
1 /***
2 This file is part of systemd.
3
4 Copyright (C) 2014 Intel Corporation. All rights reserved.
5
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
10
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
18 ***/
19
20 #include <netinet/icmp6.h>
21 #include <arpa/inet.h>
22
23 #include "sd-ndisc.h"
24
25 #include "alloc-util.h"
26 #include "hexdecoct.h"
27 #include "icmp6-util.h"
28 #include "socket-util.h"
29 #include "strv.h"
30
31 static struct ether_addr mac_addr = {
32 .ether_addr_octet = {'A', 'B', 'C', '1', '2', '3'}
33 };
34
35 static bool verbose = false;
36 static sd_event_source *test_hangcheck;
37 static int test_fd[2];
38
39 typedef int (*send_ra_t)(uint8_t flags);
40 static send_ra_t send_ra_function;
41
42 static void router_dump(sd_ndisc_router *rt) {
43 struct in6_addr addr;
44 char buf[FORMAT_TIMESTAMP_MAX];
45 uint8_t hop_limit;
46 uint64_t t, flags;
47 uint32_t mtu;
48 uint16_t lifetime;
49 unsigned preference;
50 int r;
51
52 assert_se(rt);
53
54 log_info("--");
55 assert_se(sd_ndisc_router_get_address(rt, &addr) == -ENODATA);
56
57 assert_se(sd_ndisc_router_get_timestamp(rt, CLOCK_REALTIME, &t) >= 0);
58 log_info("Timestamp: %s", format_timestamp(buf, sizeof(buf), t));
59
60 assert_se(sd_ndisc_router_get_timestamp(rt, CLOCK_MONOTONIC, &t) >= 0);
61 log_info("Monotonic: %" PRIu64, t);
62
63 if (sd_ndisc_router_get_hop_limit(rt, &hop_limit) < 0)
64 log_info("No hop limit set");
65 else
66 log_info("Hop limit: %u", hop_limit);
67
68 assert_se(sd_ndisc_router_get_flags(rt, &flags) >= 0);
69 log_info("Flags: <%s|%s>",
70 flags & ND_RA_FLAG_OTHER ? "OTHER" : "",
71 flags & ND_RA_FLAG_MANAGED ? "MANAGED" : "");
72
73 assert_se(sd_ndisc_router_get_preference(rt, &preference) >= 0);
74 log_info("Preference: %s",
75 preference == SD_NDISC_PREFERENCE_LOW ? "low" :
76 preference == SD_NDISC_PREFERENCE_HIGH ? "high" : "medium");
77
78 assert_se(sd_ndisc_router_get_lifetime(rt, &lifetime) >= 0);
79 log_info("Lifetime: %" PRIu16, lifetime);
80
81 if (sd_ndisc_router_get_mtu(rt, &mtu) < 0)
82 log_info("No MTU set");
83 else
84 log_info("MTU: %" PRIu32, mtu);
85
86 r = sd_ndisc_router_option_rewind(rt);
87 for (;;) {
88 uint8_t type;
89
90 assert_se(r >= 0);
91
92 if (r == 0)
93 break;
94
95 assert_se(sd_ndisc_router_option_get_type(rt, &type) >= 0);
96
97 log_info(">> Option %u", type);
98
99 switch (type) {
100
101 case SD_NDISC_OPTION_SOURCE_LL_ADDRESS:
102 case SD_NDISC_OPTION_TARGET_LL_ADDRESS: {
103 _cleanup_free_ char *c = NULL;
104 const void *p;
105 size_t n;
106
107 assert_se(sd_ndisc_router_option_get_raw(rt, &p, &n) >= 0);
108 assert_se(n > 2);
109 assert_se(c = hexmem((uint8_t*) p + 2, n - 2));
110
111 log_info("Address: %s", c);
112 break;
113 }
114
115 case SD_NDISC_OPTION_PREFIX_INFORMATION: {
116 uint32_t lifetime_valid, lifetime_preferred;
117 unsigned prefix_len;
118 uint8_t pfl;
119 struct in6_addr a;
120 char buff[INET6_ADDRSTRLEN];
121
122 assert_se(sd_ndisc_router_prefix_get_valid_lifetime(rt, &lifetime_valid) >= 0);
123 log_info("Valid Lifetime: %" PRIu32, lifetime_valid);
124
125 assert_se(sd_ndisc_router_prefix_get_preferred_lifetime(rt, &lifetime_preferred) >= 0);
126 log_info("Preferred Lifetime: %" PRIu32, lifetime_preferred);
127
128 assert_se(sd_ndisc_router_prefix_get_flags(rt, &pfl) >= 0);
129 log_info("Flags: <%s|%s>",
130 pfl & ND_OPT_PI_FLAG_ONLINK ? "ONLINK" : "",
131 pfl & ND_OPT_PI_FLAG_AUTO ? "AUTO" : "");
132
133 assert_se(sd_ndisc_router_prefix_get_prefixlen(rt, &prefix_len) >= 0);
134 log_info("Prefix Length: %u", prefix_len);
135
136 assert_se(sd_ndisc_router_prefix_get_address(rt, &a) >= 0);
137 log_info("Prefix: %s", inet_ntop(AF_INET6, &a, buff, sizeof(buff)));
138
139 break;
140 }
141
142 case SD_NDISC_OPTION_RDNSS: {
143 const struct in6_addr *a;
144 uint32_t lt;
145 int n, i;
146
147 n = sd_ndisc_router_rdnss_get_addresses(rt, &a);
148 assert_se(n > 0);
149
150 for (i = 0; i < n; i++) {
151 char buff[INET6_ADDRSTRLEN];
152 log_info("DNS: %s", inet_ntop(AF_INET6, a + i, buff, sizeof(buff)));
153 }
154
155 assert_se(sd_ndisc_router_rdnss_get_lifetime(rt, &lt) >= 0);
156 log_info("Lifetime: %" PRIu32, lt);
157 break;
158 }
159
160 case SD_NDISC_OPTION_DNSSL: {
161 _cleanup_strv_free_ char **l = NULL;
162 uint32_t lt;
163 int n, i;
164
165 n = sd_ndisc_router_dnssl_get_domains(rt, &l);
166 assert_se(n > 0);
167
168 for (i = 0; i < n; i++)
169 log_info("Domain: %s", l[i]);
170
171 assert_se(sd_ndisc_router_dnssl_get_lifetime(rt, &lt) >= 0);
172 log_info("Lifetime: %" PRIu32, lt);
173 break;
174 }}
175
176 r = sd_ndisc_router_option_next(rt);
177 }
178 }
179
180 static int test_rs_hangcheck(sd_event_source *s, uint64_t usec,
181 void *userdata) {
182 assert_se(false);
183
184 return 0;
185 }
186
187 int icmp6_bind_router_solicitation(int index) {
188 assert_se(index == 42);
189
190 if (socketpair(AF_UNIX, SOCK_DGRAM, 0, test_fd) < 0)
191 return -errno;
192
193 return test_fd[0];
194 }
195
196 static int send_ra(uint8_t flags) {
197 uint8_t advertisement[] = {
198 0x86, 0x00, 0xde, 0x83, 0x40, 0xc0, 0x00, 0xb4,
199 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
200 0x03, 0x04, 0x40, 0xc0, 0x00, 0x00, 0x01, 0xf4,
201 0x00, 0x00, 0x01, 0xb8, 0x00, 0x00, 0x00, 0x00,
202 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef,
203 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
204 0x19, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
205 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef,
206 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
207 0x1f, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
208 0x03, 0x6c, 0x61, 0x62, 0x05, 0x69, 0x6e, 0x74,
209 0x72, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
210 0x01, 0x01, 0x78, 0x2b, 0xcb, 0xb3, 0x6d, 0x53,
211 };
212
213 advertisement[5] = flags;
214
215 assert_se(write(test_fd[1], advertisement, sizeof(advertisement)) ==
216 sizeof(advertisement));
217
218 if (verbose)
219 printf(" sent RA with flag 0x%02x\n", flags);
220
221 return 0;
222 }
223
224 int icmp6_send_router_solicitation(int s, const struct ether_addr *ether_addr) {
225 return send_ra_function(0);
226 }
227
228 static void test_callback(sd_ndisc *nd, sd_ndisc_event event, sd_ndisc_router *rt, void *userdata) {
229 sd_event *e = userdata;
230 static unsigned idx = 0;
231 uint64_t flags_array[] = {
232 0,
233 0,
234 0,
235 ND_RA_FLAG_OTHER,
236 ND_RA_FLAG_MANAGED
237 };
238 uint64_t flags;
239 uint32_t mtu;
240
241 assert_se(nd);
242
243 if (event != SD_NDISC_EVENT_ROUTER)
244 return;
245
246 router_dump(rt);
247
248 assert_se(sd_ndisc_router_get_flags(rt, &flags) >= 0);
249 assert_se(flags == flags_array[idx]);
250 idx++;
251
252 if (verbose)
253 printf(" got event 0x%02" PRIx64 "\n", flags);
254
255 if (idx < ELEMENTSOF(flags_array)) {
256 send_ra(flags_array[idx]);
257 return;
258 }
259
260 assert_se(sd_ndisc_get_mtu(nd, &mtu) == -ENODATA);
261
262 sd_event_exit(e, 0);
263 }
264
265 static void test_rs(void) {
266 sd_event *e;
267 sd_ndisc *nd;
268 usec_t time_now = now(clock_boottime_or_monotonic());
269
270 if (verbose)
271 printf("* %s\n", __FUNCTION__);
272
273 send_ra_function = send_ra;
274
275 assert_se(sd_event_new(&e) >= 0);
276
277 assert_se(sd_ndisc_new(&nd) >= 0);
278 assert_se(nd);
279
280 assert_se(sd_ndisc_attach_event(nd, e, 0) >= 0);
281
282 assert_se(sd_ndisc_set_ifindex(nd, 42) >= 0);
283 assert_se(sd_ndisc_set_mac(nd, &mac_addr) >= 0);
284 assert_se(sd_ndisc_set_callback(nd, test_callback, e) >= 0);
285
286 assert_se(sd_event_add_time(e, &test_hangcheck, clock_boottime_or_monotonic(),
287 time_now + 2 *USEC_PER_SEC, 0,
288 test_rs_hangcheck, NULL) >= 0);
289
290 assert_se(sd_ndisc_stop(nd) >= 0);
291 assert_se(sd_ndisc_start(nd) >= 0);
292 assert_se(sd_ndisc_stop(nd) >= 0);
293
294 assert_se(sd_ndisc_start(nd) >= 0);
295
296 sd_event_loop(e);
297
298 test_hangcheck = sd_event_source_unref(test_hangcheck);
299
300 nd = sd_ndisc_unref(nd);
301 assert_se(!nd);
302
303 close(test_fd[1]);
304
305 sd_event_unref(e);
306 }
307
308 int main(int argc, char *argv[]) {
309
310 log_set_max_level(LOG_DEBUG);
311 log_parse_environment();
312 log_open();
313
314 test_rs();
315
316 return 0;
317 }