1*4e6f6c83SCody Peter Mello /* 2*4e6f6c83SCody Peter Mello * This file and its contents are supplied under the terms of the 3*4e6f6c83SCody Peter Mello * Common Development and Distribution License ("CDDL"), version 1.0. 4*4e6f6c83SCody Peter Mello * You may only use this file in accordance with the terms of version 5*4e6f6c83SCody Peter Mello * 1.0 of the CDDL. 6*4e6f6c83SCody Peter Mello * 7*4e6f6c83SCody Peter Mello * A full copy of the text of the CDDL should have accompanied this 8*4e6f6c83SCody Peter Mello * source. A copy of the CDDL is also available via the Internet at 9*4e6f6c83SCody Peter Mello * http://www.illumos.org/license/CDDL. 10*4e6f6c83SCody Peter Mello */ 11*4e6f6c83SCody Peter Mello 12*4e6f6c83SCody Peter Mello /* 13*4e6f6c83SCody Peter Mello * Copyright 2015 Joyent, Inc. All rights reserved. 14*4e6f6c83SCody Peter Mello */ 15*4e6f6c83SCody Peter Mello 16*4e6f6c83SCody Peter Mello #include <strings.h> 17*4e6f6c83SCody Peter Mello #include <stdio.h> 18*4e6f6c83SCody Peter Mello #include <stdlib.h> 19*4e6f6c83SCody Peter Mello #include <errno.h> 20*4e6f6c83SCody Peter Mello #include <err.h> 21*4e6f6c83SCody Peter Mello #include <sys/types.h> 22*4e6f6c83SCody Peter Mello #include <sys/socket.h> 23*4e6f6c83SCody Peter Mello #include <sys/sockio.h> 24*4e6f6c83SCody Peter Mello #include <sys/wait.h> 25*4e6f6c83SCody Peter Mello #include <unistd.h> 26*4e6f6c83SCody Peter Mello #include <signal.h> 27*4e6f6c83SCody Peter Mello #include <netinet/in_systm.h> /* legacy network types needed by ip_icmp.h */ 28*4e6f6c83SCody Peter Mello #include <netinet/in.h> 29*4e6f6c83SCody Peter Mello #include <netinet/ip.h> 30*4e6f6c83SCody Peter Mello #include <netinet/ip6.h> 31*4e6f6c83SCody Peter Mello #include <netinet/ip_icmp.h> 32*4e6f6c83SCody Peter Mello #include <netinet/icmp6.h> 33*4e6f6c83SCody Peter Mello #include <net/if.h> 34*4e6f6c83SCody Peter Mello #include <arpa/inet.h> 35*4e6f6c83SCody Peter Mello #include <priv.h> 36*4e6f6c83SCody Peter Mello 37*4e6f6c83SCody Peter Mello /* 38*4e6f6c83SCody Peter Mello * This program is meant to test the behaviour of processing incoming Router 39*4e6f6c83SCody Peter Mello * Advertisements when IP spoofing protection (ip-nospoof) is enabled. When 40*4e6f6c83SCody Peter Mello * run, it creates an etherstub on which it places two VNICs: a source VNIC, 41*4e6f6c83SCody Peter Mello * and a destination VNIC with protection enabled. It then sends out spoofed 42*4e6f6c83SCody Peter Mello * Router Advertisements with varying incorrect values. 43*4e6f6c83SCody Peter Mello * 44*4e6f6c83SCody Peter Mello * IMPORTANT: These tests expect that there is no other IPv6 traffic on the 45*4e6f6c83SCody Peter Mello * machine that would be delivered to a VNIC with spoofing protection enabled, 46*4e6f6c83SCody Peter Mello * since this would trip the DTrace probes installed by this suite of tests. 47*4e6f6c83SCody Peter Mello * Care should therefore be taken to not run it as a part of any series of 48*4e6f6c83SCody Peter Mello * tests which may be executed in such an environment, as it could lead to 49*4e6f6c83SCody Peter Mello * spurious failures. 50*4e6f6c83SCody Peter Mello */ 51*4e6f6c83SCody Peter Mello 52*4e6f6c83SCody Peter Mello #define DLADM(args...) spoof_run_proc("/usr/sbin/dladm", \ 53*4e6f6c83SCody Peter Mello (char *[]) { "dladm", args, NULL }) 54*4e6f6c83SCody Peter Mello #define IFCONFIG(args...) spoof_run_proc("/usr/sbin/ifconfig", \ 55*4e6f6c83SCody Peter Mello (char *[]) { "ifconfig", args, NULL }) 56*4e6f6c83SCody Peter Mello 57*4e6f6c83SCody Peter Mello typedef struct sockaddr_in6 sin6_t; 58*4e6f6c83SCody Peter Mello typedef int (spoof_test_f)(int, struct lif_nd_req *, sin6_t *); 59*4e6f6c83SCody Peter Mello 60*4e6f6c83SCody Peter Mello /* 61*4e6f6c83SCody Peter Mello * Get the link-layer address of the given interface by querying 62*4e6f6c83SCody Peter Mello * the neighbour cache. 63*4e6f6c83SCody Peter Mello */ 64*4e6f6c83SCody Peter Mello static int 65*4e6f6c83SCody Peter Mello spoof_get_lla(int s, const char *iface, struct lifreq *addrp, 66*4e6f6c83SCody Peter Mello struct lifreq *llap) 67*4e6f6c83SCody Peter Mello { 68*4e6f6c83SCody Peter Mello if (strstr(iface, ":")) { 69*4e6f6c83SCody Peter Mello warnx("Specified interface should be the zeroth " 70*4e6f6c83SCody Peter Mello "logical interface on the physical device."); 71*4e6f6c83SCody Peter Mello } 72*4e6f6c83SCody Peter Mello 73*4e6f6c83SCody Peter Mello bzero(addrp, sizeof (*addrp)); 74*4e6f6c83SCody Peter Mello bzero(llap, sizeof (*llap)); 75*4e6f6c83SCody Peter Mello 76*4e6f6c83SCody Peter Mello (void) strlcpy(addrp->lifr_name, iface, LIFNAMSIZ); 77*4e6f6c83SCody Peter Mello if (ioctl(s, SIOCGLIFADDR, addrp) < 0) { 78*4e6f6c83SCody Peter Mello warn("Unable to get link-local address"); 79*4e6f6c83SCody Peter Mello return (-1); 80*4e6f6c83SCody Peter Mello } 81*4e6f6c83SCody Peter Mello 82*4e6f6c83SCody Peter Mello (void) strlcpy(llap->lifr_name, iface, LIFNAMSIZ); 83*4e6f6c83SCody Peter Mello bcopy(&addrp->lifr_addr, &llap->lifr_nd.lnr_addr, 84*4e6f6c83SCody Peter Mello sizeof (struct sockaddr_storage)); 85*4e6f6c83SCody Peter Mello 86*4e6f6c83SCody Peter Mello if (ioctl(s, SIOCLIFGETND, llap) < 0) { 87*4e6f6c83SCody Peter Mello warn("Failed to get link-layer address"); 88*4e6f6c83SCody Peter Mello return (-1); 89*4e6f6c83SCody Peter Mello } 90*4e6f6c83SCody Peter Mello 91*4e6f6c83SCody Peter Mello return (0); 92*4e6f6c83SCody Peter Mello } 93*4e6f6c83SCody Peter Mello 94*4e6f6c83SCody Peter Mello static void 95*4e6f6c83SCody Peter Mello spoof_prepare_lla(struct nd_opt_lla *llap, struct lif_nd_req *nce, 96*4e6f6c83SCody Peter Mello struct iovec *iov) 97*4e6f6c83SCody Peter Mello { 98*4e6f6c83SCody Peter Mello uint_t optlen; 99*4e6f6c83SCody Peter Mello 100*4e6f6c83SCody Peter Mello bzero(llap, sizeof (*llap)); 101*4e6f6c83SCody Peter Mello llap->nd_opt_lla_type = ND_OPT_SOURCE_LINKADDR; 102*4e6f6c83SCody Peter Mello optlen = ((sizeof (struct nd_opt_hdr) + 103*4e6f6c83SCody Peter Mello nce->lnr_hdw_len + 7) / 8) * 8; 104*4e6f6c83SCody Peter Mello llap->nd_opt_lla_len = optlen / 8; 105*4e6f6c83SCody Peter Mello bcopy(&nce->lnr_hdw_addr, 106*4e6f6c83SCody Peter Mello &llap->nd_opt_lla_hdw_addr, nce->lnr_hdw_len); 107*4e6f6c83SCody Peter Mello 108*4e6f6c83SCody Peter Mello iov->iov_base = (caddr_t)llap; 109*4e6f6c83SCody Peter Mello iov->iov_len = optlen; 110*4e6f6c83SCody Peter Mello } 111*4e6f6c83SCody Peter Mello 112*4e6f6c83SCody Peter Mello static void 113*4e6f6c83SCody Peter Mello spoof_prepare_pi(const char *prefix, int prefix_len, 114*4e6f6c83SCody Peter Mello struct nd_opt_prefix_info *pip, struct iovec *iov) 115*4e6f6c83SCody Peter Mello { 116*4e6f6c83SCody Peter Mello bzero(pip, sizeof (*pip)); 117*4e6f6c83SCody Peter Mello 118*4e6f6c83SCody Peter Mello pip->nd_opt_pi_type = ND_OPT_PREFIX_INFORMATION; 119*4e6f6c83SCody Peter Mello pip->nd_opt_pi_len = 4; 120*4e6f6c83SCody Peter Mello pip->nd_opt_pi_prefix_len = prefix_len; 121*4e6f6c83SCody Peter Mello pip->nd_opt_pi_flags_reserved = 122*4e6f6c83SCody Peter Mello ND_OPT_PI_FLAG_AUTO | ND_OPT_PI_FLAG_ONLINK; 123*4e6f6c83SCody Peter Mello pip->nd_opt_pi_valid_time = 86400; 124*4e6f6c83SCody Peter Mello pip->nd_opt_pi_preferred_time = 86400; 125*4e6f6c83SCody Peter Mello if (inet_pton(AF_INET6, prefix, &pip->nd_opt_pi_prefix) == 0) { 126*4e6f6c83SCody Peter Mello errx(EXIT_FAILURE, "The prefix \"%s\" is " 127*4e6f6c83SCody Peter Mello "not a valid input prefix", prefix); 128*4e6f6c83SCody Peter Mello } 129*4e6f6c83SCody Peter Mello 130*4e6f6c83SCody Peter Mello iov->iov_base = (caddr_t)pip; 131*4e6f6c83SCody Peter Mello iov->iov_len = sizeof (*pip); 132*4e6f6c83SCody Peter Mello } 133*4e6f6c83SCody Peter Mello 134*4e6f6c83SCody Peter Mello static void 135*4e6f6c83SCody Peter Mello spoof_prepare_header(struct nd_router_advert *ichdrp, struct iovec *iov) 136*4e6f6c83SCody Peter Mello { 137*4e6f6c83SCody Peter Mello bzero(ichdrp, sizeof (*ichdrp)); 138*4e6f6c83SCody Peter Mello 139*4e6f6c83SCody Peter Mello ichdrp->nd_ra_type = ND_ROUTER_ADVERT; 140*4e6f6c83SCody Peter Mello ichdrp->nd_ra_curhoplimit = 0; 141*4e6f6c83SCody Peter Mello 142*4e6f6c83SCody Peter Mello iov->iov_base = (caddr_t)ichdrp; 143*4e6f6c83SCody Peter Mello iov->iov_len = sizeof (*ichdrp); 144*4e6f6c83SCody Peter Mello } 145*4e6f6c83SCody Peter Mello 146*4e6f6c83SCody Peter Mello static int 147*4e6f6c83SCody Peter Mello spoof_set_max_hops(int s) 148*4e6f6c83SCody Peter Mello { 149*4e6f6c83SCody Peter Mello int ttl = 255; 150*4e6f6c83SCody Peter Mello 151*4e6f6c83SCody Peter Mello if (setsockopt(s, IPPROTO_IPV6, IPV6_UNICAST_HOPS, 152*4e6f6c83SCody Peter Mello (char *)&ttl, sizeof (ttl)) < 0) { 153*4e6f6c83SCody Peter Mello warn("Failed to set IPV6_UNICAST_HOPS socket option"); 154*4e6f6c83SCody Peter Mello return (-1); 155*4e6f6c83SCody Peter Mello } 156*4e6f6c83SCody Peter Mello if (setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, 157*4e6f6c83SCody Peter Mello (char *)&ttl, sizeof (ttl)) < 0) { 158*4e6f6c83SCody Peter Mello warn("Failed to set IPV6_UNICAST_HOPS socket option"); 159*4e6f6c83SCody Peter Mello return (-1); 160*4e6f6c83SCody Peter Mello } 161*4e6f6c83SCody Peter Mello 162*4e6f6c83SCody Peter Mello return (0); 163*4e6f6c83SCody Peter Mello } 164*4e6f6c83SCody Peter Mello 165*4e6f6c83SCody Peter Mello /* 166*4e6f6c83SCody Peter Mello * Send bad option lengths in the Link-Layer Source Address option 167*4e6f6c83SCody Peter Mello */ 168*4e6f6c83SCody Peter Mello static int 169*4e6f6c83SCody Peter Mello spoof_bad_lla_optlen_test(int s, struct lif_nd_req *nce, sin6_t *multicast) 170*4e6f6c83SCody Peter Mello { 171*4e6f6c83SCody Peter Mello struct msghdr msg6; 172*4e6f6c83SCody Peter Mello struct iovec iovs[3]; 173*4e6f6c83SCody Peter Mello struct nd_router_advert ichdr; 174*4e6f6c83SCody Peter Mello struct nd_opt_lla lla; 175*4e6f6c83SCody Peter Mello struct nd_opt_prefix_info pi; 176*4e6f6c83SCody Peter Mello uint8_t old_lla_len; 177*4e6f6c83SCody Peter Mello 178*4e6f6c83SCody Peter Mello spoof_prepare_header(&ichdr, &iovs[0]); 179*4e6f6c83SCody Peter Mello spoof_prepare_lla(&lla, nce, &iovs[1]); 180*4e6f6c83SCody Peter Mello spoof_prepare_pi("fd00::", 64, &pi, &iovs[2]); 181*4e6f6c83SCody Peter Mello 182*4e6f6c83SCody Peter Mello /* Prepare message */ 183*4e6f6c83SCody Peter Mello bzero(&msg6, sizeof (struct msghdr)); 184*4e6f6c83SCody Peter Mello msg6.msg_name = multicast; 185*4e6f6c83SCody Peter Mello msg6.msg_namelen = sizeof (sin6_t); 186*4e6f6c83SCody Peter Mello msg6.msg_iov = iovs; 187*4e6f6c83SCody Peter Mello msg6.msg_iovlen = 3; 188*4e6f6c83SCody Peter Mello 189*4e6f6c83SCody Peter Mello old_lla_len = lla.nd_opt_lla_len; 190*4e6f6c83SCody Peter Mello 191*4e6f6c83SCody Peter Mello 192*4e6f6c83SCody Peter Mello /* 193*4e6f6c83SCody Peter Mello * Length is now smaller than the option is, so this should 194*4e6f6c83SCody Peter Mello * be rejected. 195*4e6f6c83SCody Peter Mello */ 196*4e6f6c83SCody Peter Mello lla.nd_opt_lla_len = 0; 197*4e6f6c83SCody Peter Mello if (sendmsg(s, &msg6, 0) < 0) { 198*4e6f6c83SCody Peter Mello warn("Failed to send ICMPv6 message"); 199*4e6f6c83SCody Peter Mello return (-1); 200*4e6f6c83SCody Peter Mello } 201*4e6f6c83SCody Peter Mello 202*4e6f6c83SCody Peter Mello /* 203*4e6f6c83SCody Peter Mello * Length is bigger than the option, so the following prefix 204*4e6f6c83SCody Peter Mello * will be offset. 205*4e6f6c83SCody Peter Mello */ 206*4e6f6c83SCody Peter Mello lla.nd_opt_lla_len = 2; 207*4e6f6c83SCody Peter Mello if (sendmsg(s, &msg6, 0) < 0) { 208*4e6f6c83SCody Peter Mello warn("Failed to send ICMPv6 message"); 209*4e6f6c83SCody Peter Mello return (-1); 210*4e6f6c83SCody Peter Mello } 211*4e6f6c83SCody Peter Mello 212*4e6f6c83SCody Peter Mello /* 213*4e6f6c83SCody Peter Mello * Restore the length, but shorten the amount of data to send, so we're 214*4e6f6c83SCody Peter Mello * sending truncated packets. (Stop before 0, so that we still send part 215*4e6f6c83SCody Peter Mello * of the option.) 216*4e6f6c83SCody Peter Mello */ 217*4e6f6c83SCody Peter Mello lla.nd_opt_lla_len = old_lla_len; 218*4e6f6c83SCody Peter Mello for (iovs[1].iov_len--; iovs[1].iov_len > 0; iovs[1].iov_len--) { 219*4e6f6c83SCody Peter Mello if (sendmsg(s, &msg6, 0) < 0) { 220*4e6f6c83SCody Peter Mello warn("Failed to send ICMPv6 message"); 221*4e6f6c83SCody Peter Mello return (-1); 222*4e6f6c83SCody Peter Mello } 223*4e6f6c83SCody Peter Mello } 224*4e6f6c83SCody Peter Mello 225*4e6f6c83SCody Peter Mello return (0); 226*4e6f6c83SCody Peter Mello } 227*4e6f6c83SCody Peter Mello 228*4e6f6c83SCody Peter Mello /* 229*4e6f6c83SCody Peter Mello * Send bad option lengths in the Prefix Information option 230*4e6f6c83SCody Peter Mello */ 231*4e6f6c83SCody Peter Mello static int 232*4e6f6c83SCody Peter Mello spoof_bad_pi_optlen_test(int s, struct lif_nd_req *nce, sin6_t *multicast) 233*4e6f6c83SCody Peter Mello { 234*4e6f6c83SCody Peter Mello struct msghdr msg6; 235*4e6f6c83SCody Peter Mello struct iovec iovs[3]; 236*4e6f6c83SCody Peter Mello struct nd_router_advert ichdr; 237*4e6f6c83SCody Peter Mello struct nd_opt_lla lla; 238*4e6f6c83SCody Peter Mello struct nd_opt_prefix_info pi; 239*4e6f6c83SCody Peter Mello uint8_t old_pi_len; 240*4e6f6c83SCody Peter Mello 241*4e6f6c83SCody Peter Mello spoof_prepare_header(&ichdr, &iovs[0]); 242*4e6f6c83SCody Peter Mello spoof_prepare_lla(&lla, nce, &iovs[1]); 243*4e6f6c83SCody Peter Mello spoof_prepare_pi("fd00::", 64, &pi, &iovs[2]); 244*4e6f6c83SCody Peter Mello 245*4e6f6c83SCody Peter Mello /* Prepare message */ 246*4e6f6c83SCody Peter Mello bzero(&msg6, sizeof (struct msghdr)); 247*4e6f6c83SCody Peter Mello msg6.msg_name = multicast; 248*4e6f6c83SCody Peter Mello msg6.msg_namelen = sizeof (sin6_t); 249*4e6f6c83SCody Peter Mello msg6.msg_iov = iovs; 250*4e6f6c83SCody Peter Mello msg6.msg_iovlen = 3; 251*4e6f6c83SCody Peter Mello 252*4e6f6c83SCody Peter Mello old_pi_len = pi.nd_opt_pi_len; 253*4e6f6c83SCody Peter Mello 254*4e6f6c83SCody Peter Mello /* 255*4e6f6c83SCody Peter Mello * Length is now smaller than the option is, so this should 256*4e6f6c83SCody Peter Mello * be rejected. 257*4e6f6c83SCody Peter Mello */ 258*4e6f6c83SCody Peter Mello pi.nd_opt_pi_len = 0; 259*4e6f6c83SCody Peter Mello if (sendmsg(s, &msg6, 0) < 0) { 260*4e6f6c83SCody Peter Mello warn("Failed to send ICMPv6 message"); 261*4e6f6c83SCody Peter Mello return (-1); 262*4e6f6c83SCody Peter Mello } 263*4e6f6c83SCody Peter Mello 264*4e6f6c83SCody Peter Mello /* 265*4e6f6c83SCody Peter Mello * Length is smaller than a PI option should be. 266*4e6f6c83SCody Peter Mello */ 267*4e6f6c83SCody Peter Mello pi.nd_opt_pi_len = 3; 268*4e6f6c83SCody Peter Mello if (sendmsg(s, &msg6, 0) < 0) { 269*4e6f6c83SCody Peter Mello warn("Failed to send ICMPv6 message"); 270*4e6f6c83SCody Peter Mello return (-1); 271*4e6f6c83SCody Peter Mello } 272*4e6f6c83SCody Peter Mello 273*4e6f6c83SCody Peter Mello /* 274*4e6f6c83SCody Peter Mello * Length is bigger than the option, so the following prefix 275*4e6f6c83SCody Peter Mello * will be offset. 276*4e6f6c83SCody Peter Mello */ 277*4e6f6c83SCody Peter Mello pi.nd_opt_pi_len = 5; 278*4e6f6c83SCody Peter Mello if (sendmsg(s, &msg6, 0) < 0) { 279*4e6f6c83SCody Peter Mello warn("Failed to send ICMPv6 message"); 280*4e6f6c83SCody Peter Mello return (-1); 281*4e6f6c83SCody Peter Mello } 282*4e6f6c83SCody Peter Mello 283*4e6f6c83SCody Peter Mello /* 284*4e6f6c83SCody Peter Mello * Restore the length, but shorten the amount of data to send, so we're 285*4e6f6c83SCody Peter Mello * sending truncated packets. (Stop before 0, so that we still send part 286*4e6f6c83SCody Peter Mello * of the option.) 287*4e6f6c83SCody Peter Mello */ 288*4e6f6c83SCody Peter Mello pi.nd_opt_pi_len = old_pi_len; 289*4e6f6c83SCody Peter Mello for (iovs[2].iov_len--; iovs[2].iov_len > 0; iovs[2].iov_len--) { 290*4e6f6c83SCody Peter Mello if (sendmsg(s, &msg6, 0) < 0) { 291*4e6f6c83SCody Peter Mello warn("Failed to send ICMPv6 message"); 292*4e6f6c83SCody Peter Mello return (-1); 293*4e6f6c83SCody Peter Mello } 294*4e6f6c83SCody Peter Mello } 295*4e6f6c83SCody Peter Mello 296*4e6f6c83SCody Peter Mello return (0); 297*4e6f6c83SCody Peter Mello } 298*4e6f6c83SCody Peter Mello 299*4e6f6c83SCody Peter Mello /* 300*4e6f6c83SCody Peter Mello * Advertise a prefix with a prefix length greater than 128. 301*4e6f6c83SCody Peter Mello */ 302*4e6f6c83SCody Peter Mello static int 303*4e6f6c83SCody Peter Mello spoof_bad_plen_test(int s, struct lif_nd_req *nce, sin6_t *multicast) 304*4e6f6c83SCody Peter Mello { 305*4e6f6c83SCody Peter Mello struct msghdr msg6; 306*4e6f6c83SCody Peter Mello struct iovec iovs[3]; 307*4e6f6c83SCody Peter Mello struct nd_router_advert ichdr; 308*4e6f6c83SCody Peter Mello struct nd_opt_lla lla; 309*4e6f6c83SCody Peter Mello struct nd_opt_prefix_info pi; 310*4e6f6c83SCody Peter Mello 311*4e6f6c83SCody Peter Mello spoof_prepare_header(&ichdr, &iovs[0]); 312*4e6f6c83SCody Peter Mello spoof_prepare_lla(&lla, nce, &iovs[1]); 313*4e6f6c83SCody Peter Mello spoof_prepare_pi("fd00::", 130, &pi, &iovs[2]); 314*4e6f6c83SCody Peter Mello 315*4e6f6c83SCody Peter Mello /* Prepare message */ 316*4e6f6c83SCody Peter Mello bzero(&msg6, sizeof (struct msghdr)); 317*4e6f6c83SCody Peter Mello msg6.msg_name = multicast; 318*4e6f6c83SCody Peter Mello msg6.msg_namelen = sizeof (sin6_t); 319*4e6f6c83SCody Peter Mello msg6.msg_iov = iovs; 320*4e6f6c83SCody Peter Mello msg6.msg_iovlen = 3; 321*4e6f6c83SCody Peter Mello 322*4e6f6c83SCody Peter Mello if (sendmsg(s, &msg6, 0) < 0) { 323*4e6f6c83SCody Peter Mello warn("Failed to send ICMPv6 message"); 324*4e6f6c83SCody Peter Mello return (-1); 325*4e6f6c83SCody Peter Mello } 326*4e6f6c83SCody Peter Mello 327*4e6f6c83SCody Peter Mello return (0); 328*4e6f6c83SCody Peter Mello } 329*4e6f6c83SCody Peter Mello 330*4e6f6c83SCody Peter Mello /* 331*4e6f6c83SCody Peter Mello * Advertise a link-local prefix, which should be disallowed and ignored. 332*4e6f6c83SCody Peter Mello */ 333*4e6f6c83SCody Peter Mello static int 334*4e6f6c83SCody Peter Mello spoof_link_local_test(int s, struct lif_nd_req *nce, sin6_t *multicast) 335*4e6f6c83SCody Peter Mello { 336*4e6f6c83SCody Peter Mello struct msghdr msg6; 337*4e6f6c83SCody Peter Mello struct iovec iovs[3]; 338*4e6f6c83SCody Peter Mello struct nd_router_advert ichdr; 339*4e6f6c83SCody Peter Mello struct nd_opt_lla lla; 340*4e6f6c83SCody Peter Mello struct nd_opt_prefix_info pi; 341*4e6f6c83SCody Peter Mello 342*4e6f6c83SCody Peter Mello spoof_prepare_header(&ichdr, &iovs[0]); 343*4e6f6c83SCody Peter Mello spoof_prepare_lla(&lla, nce, &iovs[1]); 344*4e6f6c83SCody Peter Mello spoof_prepare_pi("fe80::", 64, &pi, &iovs[2]); 345*4e6f6c83SCody Peter Mello 346*4e6f6c83SCody Peter Mello /* Prepare message */ 347*4e6f6c83SCody Peter Mello bzero(&msg6, sizeof (struct msghdr)); 348*4e6f6c83SCody Peter Mello msg6.msg_name = multicast; 349*4e6f6c83SCody Peter Mello msg6.msg_namelen = sizeof (sin6_t); 350*4e6f6c83SCody Peter Mello msg6.msg_iov = iovs; 351*4e6f6c83SCody Peter Mello msg6.msg_iovlen = 3; 352*4e6f6c83SCody Peter Mello 353*4e6f6c83SCody Peter Mello if (sendmsg(s, &msg6, 0) < 0) { 354*4e6f6c83SCody Peter Mello warn("Failed to send ICMPv6 message"); 355*4e6f6c83SCody Peter Mello return (-1); 356*4e6f6c83SCody Peter Mello } 357*4e6f6c83SCody Peter Mello 358*4e6f6c83SCody Peter Mello return (0); 359*4e6f6c83SCody Peter Mello } 360*4e6f6c83SCody Peter Mello 361*4e6f6c83SCody Peter Mello static int 362*4e6f6c83SCody Peter Mello spoof_good_test(int s, struct lif_nd_req *nce, sin6_t *multicast) 363*4e6f6c83SCody Peter Mello { 364*4e6f6c83SCody Peter Mello struct msghdr msg6; 365*4e6f6c83SCody Peter Mello struct iovec iovs[3]; 366*4e6f6c83SCody Peter Mello struct nd_router_advert ichdr; 367*4e6f6c83SCody Peter Mello struct nd_opt_lla lla; 368*4e6f6c83SCody Peter Mello struct nd_opt_prefix_info pi; 369*4e6f6c83SCody Peter Mello 370*4e6f6c83SCody Peter Mello spoof_prepare_header(&ichdr, &iovs[0]); 371*4e6f6c83SCody Peter Mello spoof_prepare_lla(&lla, nce, &iovs[1]); 372*4e6f6c83SCody Peter Mello spoof_prepare_pi("fd00::", 64, &pi, &iovs[2]); 373*4e6f6c83SCody Peter Mello 374*4e6f6c83SCody Peter Mello /* Prepare message */ 375*4e6f6c83SCody Peter Mello bzero(&msg6, sizeof (struct msghdr)); 376*4e6f6c83SCody Peter Mello msg6.msg_name = multicast; 377*4e6f6c83SCody Peter Mello msg6.msg_namelen = sizeof (sin6_t); 378*4e6f6c83SCody Peter Mello msg6.msg_iov = iovs; 379*4e6f6c83SCody Peter Mello msg6.msg_iovlen = 3; 380*4e6f6c83SCody Peter Mello 381*4e6f6c83SCody Peter Mello if (sendmsg(s, &msg6, 0) < 0) { 382*4e6f6c83SCody Peter Mello warn("Failed to send ICMPv6 message"); 383*4e6f6c83SCody Peter Mello return (-1); 384*4e6f6c83SCody Peter Mello } 385*4e6f6c83SCody Peter Mello 386*4e6f6c83SCody Peter Mello return (0); 387*4e6f6c83SCody Peter Mello } 388*4e6f6c83SCody Peter Mello 389*4e6f6c83SCody Peter Mello static spoof_test_f *test_cases[] = { 390*4e6f6c83SCody Peter Mello spoof_bad_lla_optlen_test, 391*4e6f6c83SCody Peter Mello spoof_bad_pi_optlen_test, 392*4e6f6c83SCody Peter Mello spoof_bad_plen_test, 393*4e6f6c83SCody Peter Mello spoof_link_local_test 394*4e6f6c83SCody Peter Mello }; 395*4e6f6c83SCody Peter Mello 396*4e6f6c83SCody Peter Mello static int test_cases_count = sizeof (test_cases) / sizeof (spoof_test_f *); 397*4e6f6c83SCody Peter Mello 398*4e6f6c83SCody Peter Mello static pid_t 399*4e6f6c83SCody Peter Mello spoof_dtrace_launch(void) 400*4e6f6c83SCody Peter Mello { 401*4e6f6c83SCody Peter Mello pid_t child_pid = fork(); 402*4e6f6c83SCody Peter Mello if (child_pid == (pid_t)-1) { 403*4e6f6c83SCody Peter Mello err(EXIT_FAILURE, "Failed to fork to execute dtrace"); 404*4e6f6c83SCody Peter Mello } else if (child_pid == (pid_t)0) { 405*4e6f6c83SCody Peter Mello (void) execl("/usr/sbin/dtrace", "dtrace", "-q", 406*4e6f6c83SCody Peter Mello "-n", "sdt:mac:insert_slaac_ip:generated-addr { exit(10) }", 407*4e6f6c83SCody Peter Mello NULL); 408*4e6f6c83SCody Peter Mello err(EXIT_FAILURE, "Failed to execute dtrace"); 409*4e6f6c83SCody Peter Mello } 410*4e6f6c83SCody Peter Mello 411*4e6f6c83SCody Peter Mello return (child_pid); 412*4e6f6c83SCody Peter Mello } 413*4e6f6c83SCody Peter Mello 414*4e6f6c83SCody Peter Mello static pid_t 415*4e6f6c83SCody Peter Mello spoof_dtrace_wait(pid_t dtrace, int *stat) 416*4e6f6c83SCody Peter Mello { 417*4e6f6c83SCody Peter Mello int retpid; 418*4e6f6c83SCody Peter Mello 419*4e6f6c83SCody Peter Mello /* Give time for probe to fire before checking status */ 420*4e6f6c83SCody Peter Mello (void) sleep(5); 421*4e6f6c83SCody Peter Mello 422*4e6f6c83SCody Peter Mello while ((retpid = waitpid(dtrace, stat, WNOHANG)) == -1) { 423*4e6f6c83SCody Peter Mello if (errno == EINTR) 424*4e6f6c83SCody Peter Mello continue; 425*4e6f6c83SCody Peter Mello 426*4e6f6c83SCody Peter Mello err(EXIT_FAILURE, "Failed to wait on child"); 427*4e6f6c83SCody Peter Mello } 428*4e6f6c83SCody Peter Mello 429*4e6f6c83SCody Peter Mello return (retpid); 430*4e6f6c83SCody Peter Mello } 431*4e6f6c83SCody Peter Mello 432*4e6f6c83SCody Peter Mello /* 433*4e6f6c83SCody Peter Mello * Run a function that's going to exec in a child process, and don't return 434*4e6f6c83SCody Peter Mello * until it exits. 435*4e6f6c83SCody Peter Mello */ 436*4e6f6c83SCody Peter Mello static int 437*4e6f6c83SCody Peter Mello spoof_run_proc(char *path, char *args[]) 438*4e6f6c83SCody Peter Mello { 439*4e6f6c83SCody Peter Mello pid_t child_pid; 440*4e6f6c83SCody Peter Mello int childstat = 0, status = 0; 441*4e6f6c83SCody Peter Mello 442*4e6f6c83SCody Peter Mello child_pid = fork(); 443*4e6f6c83SCody Peter Mello if (child_pid == (pid_t)-1) { 444*4e6f6c83SCody Peter Mello err(EXIT_FAILURE, "Unable to fork to execute %s", path); 445*4e6f6c83SCody Peter Mello } else if (child_pid == (pid_t)0) { 446*4e6f6c83SCody Peter Mello (void) execv(path, args); 447*4e6f6c83SCody Peter Mello err(EXIT_FAILURE, "Failed to execute %s", path); 448*4e6f6c83SCody Peter Mello } 449*4e6f6c83SCody Peter Mello 450*4e6f6c83SCody Peter Mello while (waitpid(child_pid, &childstat, 0) == -1) { 451*4e6f6c83SCody Peter Mello if (errno == EINTR) 452*4e6f6c83SCody Peter Mello continue; 453*4e6f6c83SCody Peter Mello 454*4e6f6c83SCody Peter Mello warn("Failed to wait on child"); 455*4e6f6c83SCody Peter Mello return (-1); 456*4e6f6c83SCody Peter Mello } 457*4e6f6c83SCody Peter Mello 458*4e6f6c83SCody Peter Mello status = WEXITSTATUS(childstat); 459*4e6f6c83SCody Peter Mello if (status != 0) { 460*4e6f6c83SCody Peter Mello warnx("Child process %s exited with %d", path, status); 461*4e6f6c83SCody Peter Mello return (-1); 462*4e6f6c83SCody Peter Mello } 463*4e6f6c83SCody Peter Mello 464*4e6f6c83SCody Peter Mello return (0); 465*4e6f6c83SCody Peter Mello } 466*4e6f6c83SCody Peter Mello 467*4e6f6c83SCody Peter Mello static void 468*4e6f6c83SCody Peter Mello spoof_network_teardown(char *testether, char *testvnic0, char *testvnic1) 469*4e6f6c83SCody Peter Mello { 470*4e6f6c83SCody Peter Mello // Delete dest vnic 471*4e6f6c83SCody Peter Mello (void) IFCONFIG(testvnic1, "inet6", "unplumb"); 472*4e6f6c83SCody Peter Mello (void) DLADM("delete-vnic", testvnic1); 473*4e6f6c83SCody Peter Mello 474*4e6f6c83SCody Peter Mello // Delete source vnic 475*4e6f6c83SCody Peter Mello (void) IFCONFIG(testvnic0, "inet6", "unplumb"); 476*4e6f6c83SCody Peter Mello (void) DLADM("delete-vnic", testvnic0); 477*4e6f6c83SCody Peter Mello 478*4e6f6c83SCody Peter Mello // Delete etherstub 479*4e6f6c83SCody Peter Mello (void) DLADM("delete-etherstub", testether); 480*4e6f6c83SCody Peter Mello } 481*4e6f6c83SCody Peter Mello 482*4e6f6c83SCody Peter Mello static int 483*4e6f6c83SCody Peter Mello spoof_network_setup(char *testether, char *testvnic0, char *testvnic1) 484*4e6f6c83SCody Peter Mello { 485*4e6f6c83SCody Peter Mello // Create etherstub 486*4e6f6c83SCody Peter Mello if (DLADM("create-etherstub", "-t", testether) != 0) { 487*4e6f6c83SCody Peter Mello warnx("Failed to create etherstub for test network"); 488*4e6f6c83SCody Peter Mello return (-1); 489*4e6f6c83SCody Peter Mello } 490*4e6f6c83SCody Peter Mello 491*4e6f6c83SCody Peter Mello // Create source vnic 492*4e6f6c83SCody Peter Mello if (DLADM("create-vnic", "-t", "-l", testether, testvnic0) != 0) { 493*4e6f6c83SCody Peter Mello warnx("Failed to create source VNIC for test network"); 494*4e6f6c83SCody Peter Mello return (-1); 495*4e6f6c83SCody Peter Mello } 496*4e6f6c83SCody Peter Mello 497*4e6f6c83SCody Peter Mello if (IFCONFIG(testvnic0, "inet6", "plumb", "up") != 0) { 498*4e6f6c83SCody Peter Mello warnx("Failed to plumb source VNIC for test network"); 499*4e6f6c83SCody Peter Mello return (-1); 500*4e6f6c83SCody Peter Mello } 501*4e6f6c83SCody Peter Mello 502*4e6f6c83SCody Peter Mello // Create dest vnic 503*4e6f6c83SCody Peter Mello if (DLADM("create-vnic", "-t", "-l", testether, 504*4e6f6c83SCody Peter Mello "-p", "protection=mac-nospoof,restricted,ip-nospoof,dhcp-nospoof", 505*4e6f6c83SCody Peter Mello testvnic1) != 0) { 506*4e6f6c83SCody Peter Mello warnx("Failed to create destination VNIC for test network"); 507*4e6f6c83SCody Peter Mello return (-1); 508*4e6f6c83SCody Peter Mello } 509*4e6f6c83SCody Peter Mello 510*4e6f6c83SCody Peter Mello if (IFCONFIG(testvnic1, "inet6", "plumb", "up") != 0) { 511*4e6f6c83SCody Peter Mello warnx("Failed to plumb destination VNIC for test network"); 512*4e6f6c83SCody Peter Mello return (-1); 513*4e6f6c83SCody Peter Mello } 514*4e6f6c83SCody Peter Mello 515*4e6f6c83SCody Peter Mello return (0); 516*4e6f6c83SCody Peter Mello } 517*4e6f6c83SCody Peter Mello 518*4e6f6c83SCody Peter Mello static void 519*4e6f6c83SCody Peter Mello spoof_run_test(spoof_test_f *func, int s, struct lif_nd_req *nce, 520*4e6f6c83SCody Peter Mello sin6_t *multicast) 521*4e6f6c83SCody Peter Mello { 522*4e6f6c83SCody Peter Mello static int cas = 1; 523*4e6f6c83SCody Peter Mello (void) printf("Executing test case #%d...", cas++); 524*4e6f6c83SCody Peter Mello if (func(s, nce, multicast) == 0) { 525*4e6f6c83SCody Peter Mello (void) printf(" Done.\n"); 526*4e6f6c83SCody Peter Mello } else { 527*4e6f6c83SCody Peter Mello (void) printf(" Error while running!\n"); 528*4e6f6c83SCody Peter Mello } 529*4e6f6c83SCody Peter Mello } 530*4e6f6c83SCody Peter Mello 531*4e6f6c83SCody Peter Mello static int 532*4e6f6c83SCody Peter Mello spoof_run_tests(int s, struct lif_nd_req *nce) 533*4e6f6c83SCody Peter Mello { 534*4e6f6c83SCody Peter Mello int cas, stat; 535*4e6f6c83SCody Peter Mello pid_t dtrace; 536*4e6f6c83SCody Peter Mello sin6_t multicast; 537*4e6f6c83SCody Peter Mello 538*4e6f6c83SCody Peter Mello /* Prepare all-nodes multicast address */ 539*4e6f6c83SCody Peter Mello bzero(&multicast, sizeof (multicast)); 540*4e6f6c83SCody Peter Mello multicast.sin6_family = AF_INET6; 541*4e6f6c83SCody Peter Mello (void) inet_pton(AF_INET6, "ff02::1", &multicast.sin6_addr); 542*4e6f6c83SCody Peter Mello 543*4e6f6c83SCody Peter Mello dtrace = spoof_dtrace_launch(); 544*4e6f6c83SCody Peter Mello 545*4e6f6c83SCody Peter Mello /* Wait an adequate amount of time for the probes to be installed */ 546*4e6f6c83SCody Peter Mello (void) sleep(5); 547*4e6f6c83SCody Peter Mello 548*4e6f6c83SCody Peter Mello /* 549*4e6f6c83SCody Peter Mello * We send a packet where everything is good, except for the hop limit. 550*4e6f6c83SCody Peter Mello * This packet should be rejected. 551*4e6f6c83SCody Peter Mello */ 552*4e6f6c83SCody Peter Mello spoof_run_test(spoof_good_test, s, nce, &multicast); 553*4e6f6c83SCody Peter Mello 554*4e6f6c83SCody Peter Mello if (spoof_set_max_hops(s) != 0) { 555*4e6f6c83SCody Peter Mello warnx("Failed to set hop limit on socket"); 556*4e6f6c83SCody Peter Mello return (EXIT_FAILURE); 557*4e6f6c83SCody Peter Mello } 558*4e6f6c83SCody Peter Mello 559*4e6f6c83SCody Peter Mello for (cas = 0; cas < test_cases_count; cas++) { 560*4e6f6c83SCody Peter Mello spoof_run_test(test_cases[cas], s, nce, &multicast); 561*4e6f6c83SCody Peter Mello } 562*4e6f6c83SCody Peter Mello 563*4e6f6c83SCody Peter Mello 564*4e6f6c83SCody Peter Mello if (spoof_dtrace_wait(dtrace, &stat) != 0) { 565*4e6f6c83SCody Peter Mello (void) printf("One or more tests of bad behaviour failed!\n"); 566*4e6f6c83SCody Peter Mello return (EXIT_FAILURE); 567*4e6f6c83SCody Peter Mello } 568*4e6f6c83SCody Peter Mello 569*4e6f6c83SCody Peter Mello /* 570*4e6f6c83SCody Peter Mello * Now that we've executed all of the test cases that should fail, we 571*4e6f6c83SCody Peter Mello * can execute the test that should succeed, to make sure the normal 572*4e6f6c83SCody Peter Mello * case works properly. This should trip the dtrace probe. 573*4e6f6c83SCody Peter Mello */ 574*4e6f6c83SCody Peter Mello spoof_run_test(spoof_good_test, s, nce, &multicast); 575*4e6f6c83SCody Peter Mello 576*4e6f6c83SCody Peter Mello if (spoof_dtrace_wait(dtrace, &stat) != 0 && WIFEXITED(stat) && 577*4e6f6c83SCody Peter Mello WEXITSTATUS(stat) == 10) { 578*4e6f6c83SCody Peter Mello (void) printf("Tests completed successfully!\n"); 579*4e6f6c83SCody Peter Mello } else { 580*4e6f6c83SCody Peter Mello if (kill(dtrace, SIGKILL) != 0) { 581*4e6f6c83SCody Peter Mello warn("Failed to kill dtrace child (pid %d)", dtrace); 582*4e6f6c83SCody Peter Mello } 583*4e6f6c83SCody Peter Mello (void) printf("Test of normal behaviour didn't succeed!\n"); 584*4e6f6c83SCody Peter Mello return (EXIT_FAILURE); 585*4e6f6c83SCody Peter Mello } 586*4e6f6c83SCody Peter Mello 587*4e6f6c83SCody Peter Mello return (0); 588*4e6f6c83SCody Peter Mello } 589*4e6f6c83SCody Peter Mello 590*4e6f6c83SCody Peter Mello /* 591*4e6f6c83SCody Peter Mello * Make sure that we have all of the privileges we need to execute these tests, 592*4e6f6c83SCody Peter Mello * so that we can error out before we would fail. 593*4e6f6c83SCody Peter Mello */ 594*4e6f6c83SCody Peter Mello void 595*4e6f6c83SCody Peter Mello spoof_check_privs(void) 596*4e6f6c83SCody Peter Mello { 597*4e6f6c83SCody Peter Mello priv_set_t *privset = priv_allocset(); 598*4e6f6c83SCody Peter Mello 599*4e6f6c83SCody Peter Mello if (privset == NULL) { 600*4e6f6c83SCody Peter Mello err(EXIT_FAILURE, "Failed to allocate memory for " 601*4e6f6c83SCody Peter Mello "checking privileges"); 602*4e6f6c83SCody Peter Mello } 603*4e6f6c83SCody Peter Mello 604*4e6f6c83SCody Peter Mello if (getppriv(PRIV_EFFECTIVE, privset) != 0) { 605*4e6f6c83SCody Peter Mello err(EXIT_FAILURE, "Failed to get current privileges"); 606*4e6f6c83SCody Peter Mello } 607*4e6f6c83SCody Peter Mello 608*4e6f6c83SCody Peter Mello if (!priv_ismember(privset, PRIV_DTRACE_KERNEL)) { 609*4e6f6c83SCody Peter Mello errx(EXIT_FAILURE, "These tests need to be run as a user " 610*4e6f6c83SCody Peter Mello "capable of tracing the kernel."); 611*4e6f6c83SCody Peter Mello } 612*4e6f6c83SCody Peter Mello 613*4e6f6c83SCody Peter Mello if (!priv_ismember(privset, PRIV_SYS_NET_CONFIG)) { 614*4e6f6c83SCody Peter Mello errx(EXIT_FAILURE, "These tests need to be run as a user " 615*4e6f6c83SCody Peter Mello "capable of creating and configuring network interfaces."); 616*4e6f6c83SCody Peter Mello } 617*4e6f6c83SCody Peter Mello 618*4e6f6c83SCody Peter Mello if (!priv_ismember(privset, PRIV_NET_ICMPACCESS)) { 619*4e6f6c83SCody Peter Mello errx(EXIT_FAILURE, "These tests need to be run as a user " 620*4e6f6c83SCody Peter Mello "capable of sending ICMP packets."); 621*4e6f6c83SCody Peter Mello } 622*4e6f6c83SCody Peter Mello 623*4e6f6c83SCody Peter Mello priv_freeset(privset); 624*4e6f6c83SCody Peter Mello } 625*4e6f6c83SCody Peter Mello 626*4e6f6c83SCody Peter Mello int 627*4e6f6c83SCody Peter Mello main(void) 628*4e6f6c83SCody Peter Mello { 629*4e6f6c83SCody Peter Mello struct lifreq addr, llar; 630*4e6f6c83SCody Peter Mello int error, s; 631*4e6f6c83SCody Peter Mello char testether[LIFNAMSIZ]; 632*4e6f6c83SCody Peter Mello char testvnic0[LIFNAMSIZ]; 633*4e6f6c83SCody Peter Mello char testvnic1[LIFNAMSIZ]; 634*4e6f6c83SCody Peter Mello pid_t curpid = getpid(); 635*4e6f6c83SCody Peter Mello 636*4e6f6c83SCody Peter Mello spoof_check_privs(); 637*4e6f6c83SCody Peter Mello 638*4e6f6c83SCody Peter Mello /* 639*4e6f6c83SCody Peter Mello * Set up the socket and test network for sending 640*4e6f6c83SCody Peter Mello */ 641*4e6f6c83SCody Peter Mello s = socket(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6); 642*4e6f6c83SCody Peter Mello if (s < 0) { 643*4e6f6c83SCody Peter Mello err(EXIT_FAILURE, "Failed to open ICMPv6 socket"); 644*4e6f6c83SCody Peter Mello } 645*4e6f6c83SCody Peter Mello 646*4e6f6c83SCody Peter Mello (void) snprintf(testether, sizeof (testether), "testether%d", curpid); 647*4e6f6c83SCody Peter Mello (void) snprintf(testvnic0, sizeof (testvnic0), "testvnic%d_0", curpid); 648*4e6f6c83SCody Peter Mello (void) snprintf(testvnic1, sizeof (testvnic1), "testvnic%d_1", curpid); 649*4e6f6c83SCody Peter Mello 650*4e6f6c83SCody Peter Mello if (spoof_network_setup(testether, testvnic0, testvnic1) != 0) { 651*4e6f6c83SCody Peter Mello warnx("Failed to set up test network"); 652*4e6f6c83SCody Peter Mello error = EXIT_FAILURE; 653*4e6f6c83SCody Peter Mello goto cleanup; 654*4e6f6c83SCody Peter Mello } 655*4e6f6c83SCody Peter Mello 656*4e6f6c83SCody Peter Mello if (spoof_get_lla(s, testvnic0, &addr, &llar) != 0) { 657*4e6f6c83SCody Peter Mello warnx("Failed to get link-layer address"); 658*4e6f6c83SCody Peter Mello error = EXIT_FAILURE; 659*4e6f6c83SCody Peter Mello goto cleanup; 660*4e6f6c83SCody Peter Mello } 661*4e6f6c83SCody Peter Mello 662*4e6f6c83SCody Peter Mello if (setsockopt(s, IPPROTO_IPV6, IPV6_BOUND_IF, 663*4e6f6c83SCody Peter Mello (char *)&((sin6_t *)&addr.lifr_addr)->sin6_scope_id, 664*4e6f6c83SCody Peter Mello sizeof (int)) < 0) { 665*4e6f6c83SCody Peter Mello warn("Failed to set IPV6_UNICAST_HOPS socket option"); 666*4e6f6c83SCody Peter Mello return (-1); 667*4e6f6c83SCody Peter Mello } 668*4e6f6c83SCody Peter Mello 669*4e6f6c83SCody Peter Mello if (bind(s, (struct sockaddr *)&addr.lifr_addr, sizeof (sin6_t)) != 0) { 670*4e6f6c83SCody Peter Mello warnx("Failed to bind to link-local address"); 671*4e6f6c83SCody Peter Mello error = EXIT_FAILURE; 672*4e6f6c83SCody Peter Mello goto cleanup; 673*4e6f6c83SCody Peter Mello } 674*4e6f6c83SCody Peter Mello 675*4e6f6c83SCody Peter Mello error = spoof_run_tests(s, &llar.lifr_nd); 676*4e6f6c83SCody Peter Mello 677*4e6f6c83SCody Peter Mello cleanup: 678*4e6f6c83SCody Peter Mello if (close(s) != 0) { 679*4e6f6c83SCody Peter Mello warnx("Failed to close ICMPv6 socket"); 680*4e6f6c83SCody Peter Mello } 681*4e6f6c83SCody Peter Mello spoof_network_teardown(testether, testvnic0, testvnic1); 682*4e6f6c83SCody Peter Mello return (error); 683*4e6f6c83SCody Peter Mello } 684