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 *)ð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"); 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"); 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"); 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"); 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"); 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 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