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