⬢ DragonFlyBSD Kernel Audit
DF-5847 / df5847_cycler.c
← back to finding ↓ download raw
/* DF-5847 stock repro harness - IPv6 address add/delete cycler (ROOT).
 *
 * Derived from the DF-3389 pack cycler.c; lifetime handling made explicit:
 * the two panics captured in findings/poc/DF-3389/logs/ (transcripts show
 * "in6_update_ifa: valid lifetime is 0" spam) came from cycling with
 * ia6t_vltime=ia6t_pltime=0.  Default here is 0 (transcript-faithful);
 * -l selects the infinite-lifetime variant (control).
 *
 * build:  cc -O2 -o df5847_cycler df5847_cycler.c
 * run:    ./df5847_cycler <seconds> [-l]
 */
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <net/if.h>
#include <netinet/in.h>
#include <netinet6/in6_var.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

int
main(int argc, char **argv)
{
	double dur = argc > 1 ? atof(argv[1]) : 60.0;
	int infinite = (argc > 2 && strcmp(argv[2], "-l") == 0);
	struct in6_aliasreq ifra;
	struct timeval t0, t1;
	unsigned long addok = 0, adderr = 0, delok = 0, delerr = 0, last = 0;
	double el, lastel = 0;
	int s;

	s = socket(AF_INET6, SOCK_DGRAM, 0);
	if (s < 0) {
		perror("socket");
		return 1;
	}

	memset(&ifra, 0, sizeof(ifra));
	strncpy(ifra.ifra_name, "lo0", sizeof(ifra.ifra_name) - 1);
	ifra.ifra_addr.sin6_family = AF_INET6;
	ifra.ifra_addr.sin6_len = sizeof(struct sockaddr_in6);
	if (inet_pton(AF_INET6, "fd99:3389::1",
	    &ifra.ifra_addr.sin6_addr) != 1) {
		fprintf(stderr, "inet_pton\n");
		return 1;
	}
	/* /64 prefix mask */
	ifra.ifra_prefixmask.sin6_family = AF_INET6;
	ifra.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6);
	memset(&ifra.ifra_prefixmask.sin6_addr, 0xff, 8);
	ifra.ifra_lifetime.ia6t_vltime = infinite ? 0xffffffffu : 0;
	ifra.ifra_lifetime.ia6t_pltime = infinite ? 0xffffffffu : 0;

	gettimeofday(&t0, NULL);
	for (;;) {
		if (ioctl(s, SIOCAIFADDR_IN6, &ifra) == 0)
			addok++;
		else
			adderr++;
		if (ioctl(s, SIOCDIFADDR_IN6, &ifra) == 0)
			delok++;
		else
			delerr++;

		gettimeofday(&t1, NULL);
		el = (t1.tv_sec - t0.tv_sec) + (t1.tv_usec - t0.tv_usec) / 1e6;
		if (el - lastel >= 5.0) {
			printf("cycler cycles=%.0f/s addok=%lu adderr=%lu "
			    "delok=%lu delerr=%lu (lasterr=%d)\n",
			    (addok - last) / (el - lastel),
			    addok, adderr, delok, delerr, errno);
			fflush(stdout);
			last = addok;
			lastel = el;
		}
		if (el >= dur)
			break;
	}
	printf("cycler DONE addok=%lu adderr=%lu delok=%lu delerr=%lu\n",
	    addok, adderr, delok, delerr);
	return 0;
}