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
jump_vnet(struct rtsock_test_config * c,const atf_tc_t * tc)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 *
presetup_ipv6(const atf_tc_t * tc)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 *
presetup_ipv4(const atf_tc_t * tc)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
prepare_route_message(struct rt_msghdr * rtm,int cmd,struct sockaddr * dst,struct sockaddr * gw)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");
ATF_TC_BODY(rtm_add_v6_ll_lle_success,tc)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 *)ðer);
139
140 prepare_route_message(rtm, RTM_ADD, (struct sockaddr *)&sin6, (struct sockaddr *)ðer);
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 *)ðer, 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");
ATF_TC_BODY(rtm_add_v6_gu_lle_success,tc)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 *)ðer);
188
189 prepare_route_message(rtm, RTM_ADD, (struct sockaddr *)&sin6, (struct sockaddr *)ðer);
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 *)ðer, 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");
ATF_TC_BODY(rtm_add_v4_gu_lle_success,tc)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 *)ðer);
239
240 prepare_route_message(rtm, RTM_ADD, (struct sockaddr *)&sin, (struct sockaddr *)ðer);
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 *)ðer, 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");
ATF_TC_BODY(rtm_del_v6_ll_lle_success,tc)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 *)ðer);
285
286 prepare_route_message(rtm, RTM_ADD, (struct sockaddr *)&sin6, (struct sockaddr *)ðer);
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 *)ðer);
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 *)ðer, 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");
ATF_TC_BODY(rtm_del_v6_gu_lle_success,tc)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 *)ðer);
331
332 prepare_route_message(rtm, RTM_ADD, (struct sockaddr *)&sin6, (struct sockaddr *)ðer);
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 *)ðer);
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 *)ðer, 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");
ATF_TC_BODY(rtm_del_v4_gu_lle_success,tc)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 *)ðer);
376
377 prepare_route_message(rtm, RTM_ADD, (struct sockaddr *)&sin, (struct sockaddr *)ðer);
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 *)ðer);
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 *)ðer, 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
ATF_TP_ADD_TCS(tp)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