xref: /freebsd/tests/sys/net/routing/test_rtsock_lladdr.c (revision 2e3507c25e42292b45a5482e116d278f5515d04d)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 2019 Alexander V. Chernikov
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  */
27 
28 #include "rtsock_common.h"
29 #include "rtsock_config.h"
30 
31 static void
32 jump_vnet(struct rtsock_test_config *c, const atf_tc_t *tc)
33 {
34 	char vnet_name[512];
35 
36 	snprintf(vnet_name, sizeof(vnet_name), "vt-%s", atf_tc_get_ident(tc));
37 	RLOG("jumping to %s", vnet_name);
38 
39 	vnet_switch_one(vnet_name, c->ifname);
40 
41 	/* Update ifindex cache */
42 	c->ifindex = if_nametoindex(c->ifname);
43 }
44 
45 static inline struct rtsock_test_config *
46 presetup_ipv6(const atf_tc_t *tc)
47 {
48 	struct rtsock_test_config *c;
49 	int ret;
50 
51 	c = config_setup(tc, NULL);
52 
53 	jump_vnet(c, tc);
54 
55 	ret = iface_turn_up(c->ifname);
56 	ATF_REQUIRE_MSG(ret == 0, "Unable to turn up %s", c->ifname);
57 	ret = iface_enable_ipv6(c->ifname);
58 	ATF_REQUIRE_MSG(ret == 0, "Unable to enable IPv6 on %s", c->ifname);
59 
60 	c->rtsock_fd = rtsock_setup_socket();
61 
62 	return (c);
63 }
64 
65 static inline struct rtsock_test_config *
66 presetup_ipv4(const atf_tc_t *tc)
67 {
68 	struct rtsock_test_config *c;
69 	int ret;
70 
71 	c = config_setup(tc, NULL);
72 
73 	jump_vnet(c, tc);
74 
75 	/* assumes ifconfig doing IFF_UP */
76 	ret = iface_setup_addr(c->ifname, c->addr4_str, c->plen4);
77 	ATF_REQUIRE_MSG(ret == 0, "ifconfig failed");
78 
79 	c->rtsock_fd = rtsock_setup_socket();
80 
81 	return (c);
82 }
83 
84 static void
85 prepare_route_message(struct rt_msghdr *rtm, int cmd, struct sockaddr *dst,
86   struct sockaddr *gw)
87 {
88 
89 	rtsock_prepare_route_message(rtm, cmd, dst, NULL, gw);
90 
91 	rtm->rtm_flags |= (RTF_HOST | RTF_STATIC | RTF_LLDATA);
92 }
93 
94 /* TESTS */
95 #define	DECLARE_TEST_VARS					\
96 	char buffer[2048], msg[512];				\
97 	ssize_t len;						\
98 	int ret;						\
99 	struct rtsock_test_config *c;				\
100 	struct rt_msghdr *rtm = (struct rt_msghdr *)buffer;	\
101 	struct sockaddr *sa;					\
102 								\
103 
104 #define	DECLARE_CLEANUP_VARS					\
105 	struct rtsock_test_config *c = config_setup(tc);	\
106 								\
107 
108 #define	DESCRIBE_ROOT_TEST(_msg)	config_describe_root_test(tc, _msg)
109 #define	CLEANUP_AFTER_TEST	config_generic_cleanup(tc)
110 
111 #define	RTM_DECLARE_ROOT_TEST(_name, _descr)			\
112 ATF_TC_WITH_CLEANUP(_name);					\
113 ATF_TC_HEAD(_name, tc)						\
114 {								\
115 	DESCRIBE_ROOT_TEST(_descr);				\
116 }								\
117 ATF_TC_CLEANUP(_name, tc)					\
118 {								\
119 	CLEANUP_AFTER_TEST;					\
120 }
121 
122 RTM_DECLARE_ROOT_TEST(rtm_add_v6_ll_lle_success, "Tests addition of link-local IPv6 ND entry");
123 ATF_TC_BODY(rtm_add_v6_ll_lle_success, tc)
124 {
125 	DECLARE_TEST_VARS;
126 
127 	c = presetup_ipv6(tc);
128 
129 	char str_buf[128];
130 	struct sockaddr_in6 sin6;
131 	/* Interface here is optional. XXX: verify kernel side. */
132 	char *v6addr = "fe80::4242:4242";
133 	snprintf(str_buf, sizeof(str_buf), "%s%%%s", v6addr, c->ifname);
134 	sa_convert_str_to_sa(str_buf, (struct sockaddr *)&sin6);
135 
136 	struct sockaddr_dl ether;
137 	snprintf(str_buf, sizeof(str_buf), "%s%%%s", c->remote_lladdr, c->ifname);
138 	sa_convert_str_to_sa(str_buf, (struct sockaddr *)&ether);
139 
140 	prepare_route_message(rtm, RTM_ADD, (struct sockaddr *)&sin6, (struct sockaddr *)&ether);
141 	rtsock_send_rtm(c->rtsock_fd, rtm);
142 
143 	/*
144 	 * Got message of size 240 on 2019-12-17 15:06:51
145 	 * RTM_ADD: Add Route: len 240, pid: 0, seq 0, errno 0, flags: <UP,HOST,DONE,LLINFO>
146 	 * sockaddrs: 0x3 <DST,GATEWAY>
147 	 *  af=inet6 len=28 addr=fe80::4242:4242 scope_id=3 if_name=tap4242
148 	 *  af=link len=54 sdl_index=3 if_name=tap4242 addr=52:54:00:14:E3:10
149 	 */
150 
151 	rtm = rtsock_read_rtm_reply(c->rtsock_fd, buffer, sizeof(buffer), rtm->rtm_seq);
152 
153 	sa = rtsock_find_rtm_sa(rtm, RTA_DST);
154 	ret = sa_equal_msg(sa, (struct sockaddr *)&sin6, msg, sizeof(msg));
155 	RTSOCK_ATF_REQUIRE_MSG(rtm, ret != 0, "DST sa diff: %s", msg);
156 
157 	sa = rtsock_find_rtm_sa(rtm, RTA_GATEWAY);
158 	int sa_flags = SA_F_IGNORE_IFNAME | SA_F_IGNORE_IFTYPE | SA_F_IGNORE_MEMCMP;
159 	ret = sa_equal_msg_flags(sa, (struct sockaddr *)&ether, msg, sizeof(msg), sa_flags);
160 	RTSOCK_ATF_REQUIRE_MSG(rtm, ret != 0, "GATEWAY sa diff: %s", msg);
161 
162 #if 0
163 	/* Disable the check until https://reviews.freebsd.org/D22003 merge */
164 	/* Some additional checks to verify kernel has filled in interface data */
165 	struct sockaddr_dl *sdl = (struct sockaddr_dl *)sa;
166 	RTSOCK_ATF_REQUIRE_MSG(rtm, sdl->sdl_type > 0, "sdl_type not set");
167 #endif
168 }
169 
170 RTM_DECLARE_ROOT_TEST(rtm_add_v6_gu_lle_success, "Tests addition of global IPv6 ND entry");
171 ATF_TC_BODY(rtm_add_v6_gu_lle_success, tc)
172 {
173 	DECLARE_TEST_VARS;
174 
175 	c = presetup_ipv6(tc);
176 
177 	char str_buf[128];
178 
179 	struct sockaddr_in6 sin6;
180 	sin6 = c->net6;
181 #define _s6_addr32 __u6_addr.__u6_addr32
182 	sin6.sin6_addr._s6_addr32[3] = htonl(0x42424242);
183 #undef _s6_addr32
184 
185 	struct sockaddr_dl ether;
186 	snprintf(str_buf, sizeof(str_buf), "%s%%%s", c->remote_lladdr, c->ifname);
187 	sa_convert_str_to_sa(str_buf, (struct sockaddr *)&ether);
188 
189 	prepare_route_message(rtm, RTM_ADD, (struct sockaddr *)&sin6, (struct sockaddr *)&ether);
190 
191 	rtsock_send_rtm(c->rtsock_fd, rtm);
192 
193 	/*
194 	 * Got message of size 240 on 2019-12-17 14:56:43
195 	 * RTM_ADD: Add Route: len 240, pid: 0, seq 0, errno 0, flags: <UP,HOST,DONE,LLINFO>
196 	 * sockaddrs: 0x3 <DST,GATEWAY>
197 	 *  af=inet6 len=28 addr=2001:db8::4242:4242
198  	 *  af=link len=54 sdl_index=3 if_name=tap4242 addr=52:54:00:14:E3:10
199 	 */
200 
201 	/* XXX: where is uRPF?! this should fail */
202 
203 	rtm = rtsock_read_rtm_reply(c->rtsock_fd, buffer, sizeof(buffer), rtm->rtm_seq);
204 
205 	sa = rtsock_find_rtm_sa(rtm, RTA_DST);
206 	ret = sa_equal_msg(sa, (struct sockaddr *)&sin6, msg, sizeof(msg));
207 	RTSOCK_ATF_REQUIRE_MSG(rtm, ret != 0, "DST sa diff: %s", msg);
208 
209 	sa = rtsock_find_rtm_sa(rtm, RTA_GATEWAY);
210 	int sa_flags = SA_F_IGNORE_IFNAME | SA_F_IGNORE_IFTYPE | SA_F_IGNORE_MEMCMP;
211 	ret = sa_equal_msg_flags(sa, (struct sockaddr *)&ether, msg, sizeof(msg), sa_flags);
212 	RTSOCK_ATF_REQUIRE_MSG(rtm, ret != 0, "GATEWAY sa diff: %s", msg);
213 
214 #if 0
215 	/* Disable the check until https://reviews.freebsd.org/D22003 merge */
216 	/* Some additional checks to verify kernel has filled in interface data */
217 	struct sockaddr_dl *sdl = (struct sockaddr_dl *)sa;
218 	RTSOCK_ATF_REQUIRE_MSG(rtm, sdl->sdl_type > 0, "sdl_type not set");
219 #endif
220 }
221 
222 RTM_DECLARE_ROOT_TEST(rtm_add_v4_gu_lle_success, "Tests addition of IPv4 ARP entry");
223 ATF_TC_BODY(rtm_add_v4_gu_lle_success, tc)
224 {
225 	DECLARE_TEST_VARS;
226 
227 	c = presetup_ipv4(tc);
228 
229 	char str_buf[128];
230 
231 	struct sockaddr_in sin;
232 	sin = c->addr4;
233 	/* Use the next IPv4 address after self */
234 	sin.sin_addr.s_addr = htonl(ntohl(sin.sin_addr.s_addr) + 1);
235 
236 	struct sockaddr_dl ether;
237 	snprintf(str_buf, sizeof(str_buf), "%s%%%s", c->remote_lladdr, c->ifname);
238 	sa_convert_str_to_sa(str_buf, (struct sockaddr *)&ether);
239 
240 	prepare_route_message(rtm, RTM_ADD, (struct sockaddr *)&sin, (struct sockaddr *)&ether);
241 
242 	len = rtsock_send_rtm(c->rtsock_fd, rtm);
243 
244 	/*
245 	 * RTM_ADD: Add Route: len 224, pid: 43131, seq 42, errno 0, flags: <HOST,DONE,LLINFO,STATIC>
246 	 * sockaddrs: 0x3 <DST,GATEWAY>
247 	 *  af=inet len=16 addr=192.0.2.2
248 	 *  af=link len=54 sdl_index=3 if_name=tap4242 addr=52:54:00:14:E3:10
249 	 */
250 
251 	rtm = rtsock_read_rtm_reply(c->rtsock_fd, buffer, sizeof(buffer), rtm->rtm_seq);
252 
253 	sa = rtsock_find_rtm_sa(rtm, RTA_DST);
254 	ret = sa_equal_msg(sa, (struct sockaddr *)&sin, msg, sizeof(msg));
255 	RTSOCK_ATF_REQUIRE_MSG(rtm, ret != 0, "DST sa diff: %s", msg);
256 
257 	sa = rtsock_find_rtm_sa(rtm, RTA_GATEWAY);
258 	int sa_flags = SA_F_IGNORE_IFNAME | SA_F_IGNORE_IFTYPE | SA_F_IGNORE_MEMCMP;
259 	ret = sa_equal_msg_flags(sa, (struct sockaddr *)&ether, msg, sizeof(msg), sa_flags);
260 	RTSOCK_ATF_REQUIRE_MSG(rtm, ret != 0, "GATEWAY sa diff: %s", msg);
261 
262 	/*
263 	 * TODO: Currently kernel code does not set sdl_type, contrary to IPv6.
264 	 */
265 }
266 
267 RTM_DECLARE_ROOT_TEST(rtm_del_v6_ll_lle_success, "Tests removal of link-local IPv6 ND entry");
268 ATF_TC_BODY(rtm_del_v6_ll_lle_success, tc)
269 {
270 	DECLARE_TEST_VARS;
271 
272 	c = presetup_ipv6(tc);
273 
274 	char str_buf[128];
275 
276 	struct sockaddr_in6 sin6;
277 	/* Interface here is optional. XXX: verify kernel side. */
278 	char *v6addr = "fe80::4242:4242";
279 	snprintf(str_buf, sizeof(str_buf), "%s%%%s", v6addr, c->ifname);
280 	sa_convert_str_to_sa(str_buf, (struct sockaddr *)&sin6);
281 
282 	struct sockaddr_dl ether;
283 	snprintf(str_buf, sizeof(str_buf), "%s%%%s", c->remote_lladdr, c->ifname);
284 	sa_convert_str_to_sa(str_buf, (struct sockaddr *)&ether);
285 
286 	prepare_route_message(rtm, RTM_ADD, (struct sockaddr *)&sin6, (struct sockaddr *)&ether);
287 
288 	rtsock_send_rtm(c->rtsock_fd, rtm);
289 
290 	/* Successfully added an entry, let's try to remove it. */
291 	prepare_route_message(rtm, RTM_DELETE, (struct sockaddr *)&sin6, (struct sockaddr *)&ether);
292 
293 	rtsock_send_rtm(c->rtsock_fd, rtm);
294 
295 	rtm = rtsock_read_rtm_reply(c->rtsock_fd, buffer, sizeof(buffer), rtm->rtm_seq);
296 
297 	RTSOCK_ATF_REQUIRE_MSG(rtm, rtm->rtm_type == RTM_DELETE, "rtm_type is not delete");
298 
299 	sa = rtsock_find_rtm_sa(rtm, RTA_DST);
300 	ret = sa_equal_msg(sa, (struct sockaddr *)&sin6, msg, sizeof(msg));
301 	RTSOCK_ATF_REQUIRE_MSG(rtm, ret != 0, "DST sa diff: %s", msg);
302 
303 	sa = rtsock_find_rtm_sa(rtm, RTA_GATEWAY);
304 	int sa_flags = SA_F_IGNORE_IFNAME | SA_F_IGNORE_IFTYPE | SA_F_IGNORE_MEMCMP;
305 	ret = sa_equal_msg_flags(sa, (struct sockaddr *)&ether, msg, sizeof(msg), sa_flags);
306 	RTSOCK_ATF_REQUIRE_MSG(rtm, ret != 0, "GATEWAY sa diff: %s", msg);
307 
308 	/*
309 	 * TODO: Currently kernel code does not set sdl_type on delete.
310 	 */
311 }
312 
313 RTM_DECLARE_ROOT_TEST(rtm_del_v6_gu_lle_success, "Tests removal of global IPv6 ND entry");
314 ATF_TC_BODY(rtm_del_v6_gu_lle_success, tc)
315 {
316 	DECLARE_TEST_VARS;
317 
318 	c = presetup_ipv6(tc);
319 
320 	char str_buf[128];
321 
322 	struct sockaddr_in6 sin6;
323 	sin6 = c->net6;
324 #define _s6_addr32 __u6_addr.__u6_addr32
325 	sin6.sin6_addr._s6_addr32[3] = htonl(0x42424242);
326 #undef _s6_addr32
327 
328 	struct sockaddr_dl ether;
329 	snprintf(str_buf, sizeof(str_buf), "%s%%%s", c->remote_lladdr, c->ifname);
330 	sa_convert_str_to_sa(str_buf, (struct sockaddr *)&ether);
331 
332 	prepare_route_message(rtm, RTM_ADD, (struct sockaddr *)&sin6, (struct sockaddr *)&ether);
333 
334 	len = rtsock_send_rtm(c->rtsock_fd, rtm);
335 
336 	/* Successfully added an entry, let's try to remove it. */
337 	prepare_route_message(rtm, RTM_DELETE, (struct sockaddr *)&sin6, (struct sockaddr *)&ether);
338 
339 	rtsock_send_rtm(c->rtsock_fd, rtm);
340 
341 	rtm = rtsock_read_rtm_reply(c->rtsock_fd, buffer, sizeof(buffer), rtm->rtm_seq);
342 
343 	RTSOCK_ATF_REQUIRE_MSG(rtm, rtm->rtm_type == RTM_DELETE, "rtm_type is not delete");
344 
345 	sa = rtsock_find_rtm_sa(rtm, RTA_DST);
346 	ret = sa_equal_msg(sa, (struct sockaddr *)&sin6, msg, sizeof(msg));
347 	RTSOCK_ATF_REQUIRE_MSG(rtm, ret != 0, "DST sa diff: %s", msg);
348 
349 	sa = rtsock_find_rtm_sa(rtm, RTA_GATEWAY);
350 	int sa_flags = SA_F_IGNORE_IFNAME | SA_F_IGNORE_IFTYPE | SA_F_IGNORE_MEMCMP;
351 	ret = sa_equal_msg_flags(sa, (struct sockaddr *)&ether, msg, sizeof(msg), sa_flags);
352 	RTSOCK_ATF_REQUIRE_MSG(rtm, ret != 0, "GATEWAY sa diff: %s", msg);
353 
354 	/*
355 	 * TODO: Currently kernel code does not set sdl_type on delete.
356 	 */
357 }
358 
359 RTM_DECLARE_ROOT_TEST(rtm_del_v4_gu_lle_success, "Tests removal of IPv4 ARP entry");
360 ATF_TC_BODY(rtm_del_v4_gu_lle_success, tc)
361 {
362 	DECLARE_TEST_VARS;
363 
364 	c = presetup_ipv4(tc);
365 
366 	char str_buf[128];
367 
368 	struct sockaddr_in sin;
369 	sin = c->addr4;
370 	/* Use the next IPv4 address after self */
371 	sin.sin_addr.s_addr = htonl(ntohl(sin.sin_addr.s_addr) + 1);
372 
373 	struct sockaddr_dl ether;
374 	snprintf(str_buf, sizeof(str_buf), "%s%%%s", c->remote_lladdr, c->ifname);
375 	sa_convert_str_to_sa(str_buf, (struct sockaddr *)&ether);
376 
377 	prepare_route_message(rtm, RTM_ADD, (struct sockaddr *)&sin, (struct sockaddr *)&ether);
378 
379 	rtsock_send_rtm(c->rtsock_fd, rtm);
380 
381 	/* We successfully added an entry, let's try to remove it. */
382 	prepare_route_message(rtm, RTM_DELETE, (struct sockaddr *)&sin, (struct sockaddr *)&ether);
383 
384 	rtsock_send_rtm(c->rtsock_fd, rtm);
385 
386 	rtm = rtsock_read_rtm_reply(c->rtsock_fd, buffer, sizeof(buffer), rtm->rtm_seq);
387 
388 	RTSOCK_ATF_REQUIRE_MSG(rtm, rtm->rtm_type == RTM_DELETE, "rtm_type is not delete");
389 
390 	sa = rtsock_find_rtm_sa(rtm, RTA_DST);
391 	ret = sa_equal_msg(sa, (struct sockaddr *)&sin, msg, sizeof(msg));
392 	RTSOCK_ATF_REQUIRE_MSG(rtm, ret != 0, "DST sa diff: %s", msg);
393 
394 	sa = rtsock_find_rtm_sa(rtm, RTA_GATEWAY);
395 	int sa_flags = SA_F_IGNORE_IFNAME | SA_F_IGNORE_IFTYPE | SA_F_IGNORE_MEMCMP;
396 	ret = sa_equal_msg_flags(sa, (struct sockaddr *)&ether, msg, sizeof(msg), sa_flags);
397 	RTSOCK_ATF_REQUIRE_MSG(rtm, ret != 0, "GATEWAY sa diff: %s", msg);
398 
399 	/*
400 	 * TODO: Currently kernel code does not set sdl_type, contrary to IPv6.
401 	 */
402 }
403 
404 ATF_TP_ADD_TCS(tp)
405 {
406 	ATF_TP_ADD_TC(tp, rtm_add_v6_ll_lle_success);
407 	ATF_TP_ADD_TC(tp, rtm_add_v6_gu_lle_success);
408 	ATF_TP_ADD_TC(tp, rtm_add_v4_gu_lle_success);
409 	ATF_TP_ADD_TC(tp, rtm_del_v6_ll_lle_success);
410 	ATF_TP_ADD_TC(tp, rtm_del_v6_gu_lle_success);
411 	ATF_TP_ADD_TC(tp, rtm_del_v4_gu_lle_success);
412 
413 	return (atf_no_error());
414 }
415 
416 
417