]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd-network/test-ndisc-rs.c
icmp6-util: Bind Router Advertisement socket
[thirdparty/systemd.git] / src / libsystemd-network / test-ndisc-rs.c
CommitLineData
f20a35cc
PF
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>
1e7a0e21 21#include <arpa/inet.h>
f20a35cc 22
07630cea 23#include "sd-ndisc.h"
f20a35cc 24
1e7a0e21
LP
25#include "alloc-util.h"
26#include "hexdecoct.h"
940367a0 27#include "icmp6-util.h"
07630cea 28#include "socket-util.h"
1e7a0e21 29#include "strv.h"
f20a35cc
PF
30
31static struct ether_addr mac_addr = {
32 .ether_addr_octet = {'A', 'B', 'C', '1', '2', '3'}
33};
34
35static bool verbose = false;
36static sd_event_source *test_hangcheck;
37static int test_fd[2];
38
99af546d
PF
39typedef int (*send_ra_t)(uint8_t flags);
40static send_ra_t send_ra_function;
41
1e7a0e21
LP
42static 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
f20a35cc
PF
180static int test_rs_hangcheck(sd_event_source *s, uint64_t usec,
181 void *userdata) {
787784c4 182 assert_se(false);
f20a35cc
PF
183
184 return 0;
185}
186
940367a0 187int icmp6_bind_router_solicitation(int index) {
787784c4 188 assert_se(index == 42);
f20a35cc
PF
189
190 if (socketpair(AF_UNIX, SOCK_DGRAM, 0, test_fd) < 0)
191 return -errno;
192
193 return test_fd[0];
194}
195
6142bb37
PF
196int icmp6_bind_router_advertisement(int index) {
197
198 return -ENOSYS;
199}
200
f20a35cc
PF
201static int send_ra(uint8_t flags) {
202 uint8_t advertisement[] = {
203 0x86, 0x00, 0xde, 0x83, 0x40, 0xc0, 0x00, 0xb4,
204 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
205 0x03, 0x04, 0x40, 0xc0, 0x00, 0x00, 0x01, 0xf4,
206 0x00, 0x00, 0x01, 0xb8, 0x00, 0x00, 0x00, 0x00,
207 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef,
208 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
209 0x19, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
210 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef,
211 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
212 0x1f, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
213 0x03, 0x6c, 0x61, 0x62, 0x05, 0x69, 0x6e, 0x74,
214 0x72, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
215 0x01, 0x01, 0x78, 0x2b, 0xcb, 0xb3, 0x6d, 0x53,
216 };
217
218 advertisement[5] = flags;
219
787784c4 220 assert_se(write(test_fd[1], advertisement, sizeof(advertisement)) ==
f20a35cc
PF
221 sizeof(advertisement));
222
223 if (verbose)
224 printf(" sent RA with flag 0x%02x\n", flags);
225
226 return 0;
227}
228
940367a0 229int icmp6_send_router_solicitation(int s, const struct ether_addr *ether_addr) {
99af546d 230 return send_ra_function(0);
f20a35cc
PF
231}
232
1e7a0e21 233static void test_callback(sd_ndisc *nd, sd_ndisc_event event, sd_ndisc_router *rt, void *userdata) {
f20a35cc 234 sd_event *e = userdata;
cb53894d 235 static unsigned idx = 0;
1e7a0e21 236 uint64_t flags_array[] = {
9d96e6c3
TG
237 0,
238 0,
239 0,
240 ND_RA_FLAG_OTHER,
241 ND_RA_FLAG_MANAGED
f20a35cc 242 };
1e7a0e21 243 uint64_t flags;
8d7f2c6a
PF
244 uint32_t mtu;
245
787784c4 246 assert_se(nd);
f20a35cc 247
1e7a0e21
LP
248 if (event != SD_NDISC_EVENT_ROUTER)
249 return;
250
251 router_dump(rt);
252
253 assert_se(sd_ndisc_router_get_flags(rt, &flags) >= 0);
9d96e6c3 254 assert_se(flags == flags_array[idx]);
f20a35cc
PF
255 idx++;
256
257 if (verbose)
1e7a0e21 258 printf(" got event 0x%02" PRIx64 "\n", flags);
f20a35cc 259
9d96e6c3
TG
260 if (idx < ELEMENTSOF(flags_array)) {
261 send_ra(flags_array[idx]);
8d7f2c6a
PF
262 return;
263 }
264
1e7a0e21 265 assert_se(sd_ndisc_get_mtu(nd, &mtu) == -ENODATA);
8d7f2c6a
PF
266
267 sd_event_exit(e, 0);
f20a35cc
PF
268}
269
99af546d
PF
270static void test_rs(void) {
271 sd_event *e;
4d7b83da 272 sd_ndisc *nd;
99af546d 273 usec_t time_now = now(clock_boottime_or_monotonic());
f20a35cc
PF
274
275 if (verbose)
276 printf("* %s\n", __FUNCTION__);
277
99af546d
PF
278 send_ra_function = send_ra;
279
280 assert_se(sd_event_new(&e) >= 0);
281
4d7b83da 282 assert_se(sd_ndisc_new(&nd) >= 0);
787784c4 283 assert_se(nd);
f20a35cc 284
4d7b83da 285 assert_se(sd_ndisc_attach_event(nd, e, 0) >= 0);
f20a35cc 286
2f8e7633 287 assert_se(sd_ndisc_set_ifindex(nd, 42) >= 0);
4d7b83da 288 assert_se(sd_ndisc_set_mac(nd, &mac_addr) >= 0);
1e7a0e21 289 assert_se(sd_ndisc_set_callback(nd, test_callback, e) >= 0);
f20a35cc 290
787784c4 291 assert_se(sd_event_add_time(e, &test_hangcheck, clock_boottime_or_monotonic(),
f20a35cc
PF
292 time_now + 2 *USEC_PER_SEC, 0,
293 test_rs_hangcheck, NULL) >= 0);
294
4d7b83da 295 assert_se(sd_ndisc_stop(nd) >= 0);
1e7a0e21 296 assert_se(sd_ndisc_start(nd) >= 0);
4d7b83da 297 assert_se(sd_ndisc_stop(nd) >= 0);
836cf090 298
1e7a0e21 299 assert_se(sd_ndisc_start(nd) >= 0);
f20a35cc
PF
300
301 sd_event_loop(e);
302
303 test_hangcheck = sd_event_source_unref(test_hangcheck);
304
4d7b83da 305 nd = sd_ndisc_unref(nd);
787784c4 306 assert_se(!nd);
f20a35cc 307
f20a35cc 308 close(test_fd[1]);
99af546d
PF
309
310 sd_event_unref(e);
f20a35cc
PF
311}
312
313int main(int argc, char *argv[]) {
f20a35cc
PF
314
315 log_set_max_level(LOG_DEBUG);
316 log_parse_environment();
317 log_open();
318
99af546d 319 test_rs();
f20a35cc
PF
320
321 return 0;
322}