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