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
31static void
32jump_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
45static inline struct rtsock_test_config *
46presetup_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
65static inline struct rtsock_test_config *
66presetup_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
84static void
85prepare_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)			\
112ATF_TC_WITH_CLEANUP(_name);					\
113ATF_TC_HEAD(_name, tc)						\
114{								\
115	DESCRIBE_ROOT_TEST(_descr);				\
116}								\
117ATF_TC_CLEANUP(_name, tc)					\
118{								\
119	CLEANUP_AFTER_TEST;					\
120}
121
122RTM_DECLARE_ROOT_TEST(rtm_add_v6_ll_lle_success, "Tests addition of link-local IPv6 ND entry");
123ATF_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
170RTM_DECLARE_ROOT_TEST(rtm_add_v6_gu_lle_success, "Tests addition of global IPv6 ND entry");
171ATF_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
222RTM_DECLARE_ROOT_TEST(rtm_add_v4_gu_lle_success, "Tests addition of IPv4 ARP entry");
223ATF_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
267RTM_DECLARE_ROOT_TEST(rtm_del_v6_ll_lle_success, "Tests removal of link-local IPv6 ND entry");
268ATF_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
313RTM_DECLARE_ROOT_TEST(rtm_del_v6_gu_lle_success, "Tests removal of global IPv6 ND entry");
314ATF_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
359RTM_DECLARE_ROOT_TEST(rtm_del_v4_gu_lle_success, "Tests removal of IPv4 ARP entry");
360ATF_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
404ATF_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