/*
* This file and its contents are supplied under the terms of the
* Common Development and Distribution License ("CDDL"), version 1.0.
* You may only use this file in accordance with the terms of version
* 1.0 of the CDDL.
*
* A full copy of the text of the CDDL should have accompanied this
* source. A copy of the CDDL is also available via the Internet at
*/
/*
* Copyright 2015 Joyent, Inc. All rights reserved.
*/
#include <strings.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <err.h>
#include <unistd.h>
#include <signal.h>
#include <priv.h>
/*
* This program is meant to test the behaviour of processing incoming Router
* Advertisements when IP spoofing protection (ip-nospoof) is enabled. When
* run, it creates an etherstub on which it places two VNICs: a source VNIC,
* and a destination VNIC with protection enabled. It then sends out spoofed
* Router Advertisements with varying incorrect values.
*
* IMPORTANT: These tests expect that there is no other IPv6 traffic on the
* machine that would be delivered to a VNIC with spoofing protection enabled,
* since this would trip the DTrace probes installed by this suite of tests.
* Care should therefore be taken to not run it as a part of any series of
* tests which may be executed in such an environment, as it could lead to
* spurious failures.
*/
/*
* Get the link-layer address of the given interface by querying
* the neighbour cache.
*/
static int
{
warnx("Specified interface should be the zeroth "
"logical interface on the physical device.");
}
warn("Unable to get link-local address");
return (-1);
}
sizeof (struct sockaddr_storage));
warn("Failed to get link-layer address");
return (-1);
}
return (0);
}
static void
{
optlen = ((sizeof (struct nd_opt_hdr) +
}
static void
{
"not a valid input prefix", prefix);
}
}
static void
{
ichdrp->nd_ra_curhoplimit = 0;
}
static int
spoof_set_max_hops(int s)
{
warn("Failed to set IPV6_UNICAST_HOPS socket option");
return (-1);
}
warn("Failed to set IPV6_UNICAST_HOPS socket option");
return (-1);
}
return (0);
}
/*
* Send bad option lengths in the Link-Layer Source Address option
*/
static int
{
/* Prepare message */
/*
* Length is now smaller than the option is, so this should
* be rejected.
*/
lla.nd_opt_lla_len = 0;
warn("Failed to send ICMPv6 message");
return (-1);
}
/*
* Length is bigger than the option, so the following prefix
* will be offset.
*/
warn("Failed to send ICMPv6 message");
return (-1);
}
/*
* Restore the length, but shorten the amount of data to send, so we're
* sending truncated packets. (Stop before 0, so that we still send part
* of the option.)
*/
warn("Failed to send ICMPv6 message");
return (-1);
}
}
return (0);
}
/*
* Send bad option lengths in the Prefix Information option
*/
static int
{
/* Prepare message */
/*
* Length is now smaller than the option is, so this should
* be rejected.
*/
pi.nd_opt_pi_len = 0;
warn("Failed to send ICMPv6 message");
return (-1);
}
/*
* Length is smaller than a PI option should be.
*/
warn("Failed to send ICMPv6 message");
return (-1);
}
/*
* Length is bigger than the option, so the following prefix
* will be offset.
*/
warn("Failed to send ICMPv6 message");
return (-1);
}
/*
* Restore the length, but shorten the amount of data to send, so we're
* sending truncated packets. (Stop before 0, so that we still send part
* of the option.)
*/
warn("Failed to send ICMPv6 message");
return (-1);
}
}
return (0);
}
/*
* Advertise a prefix with a prefix length greater than 128.
*/
static int
{
/* Prepare message */
warn("Failed to send ICMPv6 message");
return (-1);
}
return (0);
}
/*
* Advertise a link-local prefix, which should be disallowed and ignored.
*/
static int
{
/* Prepare message */
warn("Failed to send ICMPv6 message");
return (-1);
}
return (0);
}
static int
{
/* Prepare message */
warn("Failed to send ICMPv6 message");
return (-1);
}
return (0);
}
};
static pid_t
spoof_dtrace_launch(void)
{
"-n", "sdt:mac:insert_slaac_ip:generated-addr { exit(10) }",
NULL);
}
return (child_pid);
}
static pid_t
{
int retpid;
/* Give time for probe to fire before checking status */
(void) sleep(5);
continue;
}
return (retpid);
}
/*
* Run a function that's going to exec in a child process, and don't return
* until it exits.
*/
static int
{
}
continue;
warn("Failed to wait on child");
return (-1);
}
if (status != 0) {
return (-1);
}
return (0);
}
static void
{
// Delete dest vnic
// Delete source vnic
// Delete etherstub
}
static int
{
// Create etherstub
warnx("Failed to create etherstub for test network");
return (-1);
}
// Create source vnic
warnx("Failed to create source VNIC for test network");
return (-1);
}
warnx("Failed to plumb source VNIC for test network");
return (-1);
}
// Create dest vnic
"-p", "protection=mac-nospoof,restricted,ip-nospoof,dhcp-nospoof",
testvnic1) != 0) {
warnx("Failed to create destination VNIC for test network");
return (-1);
}
warnx("Failed to plumb destination VNIC for test network");
return (-1);
}
return (0);
}
static void
{
(void) printf(" Done.\n");
} else {
(void) printf(" Error while running!\n");
}
}
static int
{
/* Prepare all-nodes multicast address */
/* Wait an adequate amount of time for the probes to be installed */
(void) sleep(5);
/*
* We send a packet where everything is good, except for the hop limit.
* This packet should be rejected.
*/
if (spoof_set_max_hops(s) != 0) {
warnx("Failed to set hop limit on socket");
return (EXIT_FAILURE);
}
}
(void) printf("One or more tests of bad behaviour failed!\n");
return (EXIT_FAILURE);
}
/*
* Now that we've executed all of the test cases that should fail, we
* can execute the test that should succeed, to make sure the normal
* case works properly. This should trip the dtrace probe.
*/
(void) printf("Tests completed successfully!\n");
} else {
}
(void) printf("Test of normal behaviour didn't succeed!\n");
return (EXIT_FAILURE);
}
return (0);
}
/*
* Make sure that we have all of the privileges we need to execute these tests,
* so that we can error out before we would fail.
*/
void
spoof_check_privs(void)
{
"checking privileges");
}
}
"capable of tracing the kernel.");
}
"capable of creating and configuring network interfaces.");
}
"capable of sending ICMP packets.");
}
}
int
main(void)
{
int error, s;
/*
* Set up the socket and test network for sending
*/
if (s < 0) {
}
warnx("Failed to set up test network");
goto cleanup;
}
warnx("Failed to get link-layer address");
goto cleanup;
}
sizeof (int)) < 0) {
warn("Failed to set IPV6_UNICAST_HOPS socket option");
return (-1);
}
warnx("Failed to bind to link-local address");
goto cleanup;
}
if (close(s) != 0) {
warnx("Failed to close ICMPv6 socket");
}
return (error);
}