⬢ DragonFlyBSD Kernel Audit
DF-3379 / trigger_df3379.c
← back to finding ↓ download raw
/*
 * DF-3379 trigger: configure pfsync0 the way an HA deployment would
 * (syncdev=lo0 plus a UNICAST sync peer 10.0.2.2), so that a working
 * pfsync engine would serialize every pf state change and emit proto-240
 * packets to 10.0.2.2 within the 1-second pfsync tick.
 *
 * On DragonFly the engine is dead: the global `pfsyncif` is never
 * assigned (only `struct pfsync_softc *pfsyncif = NULL;` at
 * sys/net/pf/if_pfsync.c:90 -- pfsync_clone_create never does
 * `pfsyncif = sc`), so pfsync_pack_state()/pfsync_request_update()/
 * pfsync_clear_states() all take their `sc == NULL` early-out and no
 * packet is ever built or sent, no matter how many states exist.
 *
 * The unicast peer matters: with the default multicast peer and no
 * listener, pfsync_pack_state() would early-out anyway (if_pfsync.c:1294);
 * with syncdev + unicast peer configured, the only thing that can stop
 * transmission is the dead engine itself.
 *
 * Build: cc -o trigger_df3379 trigger_df3379.c
 * Run:   ./trigger_df3379            (then create pf states and watch for proto 240)
 */
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <netinet/in.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <err.h>

struct pfsyncreq {
	char		 pfsyncr_syncdev[IFNAMSIZ];
	struct in_addr	 pfsyncr_syncpeer;
	int		 pfsyncr_maxupdates;
	int		 pfsyncr_authlevel;
};
#define SIOCSETPFSYNC	_IOW('i', 247, struct ifreq)
#define SIOCGETPFSYNC	_IOWR('i', 248, struct ifreq)

int
main(void)
{
	struct ifreq ifr;
	struct pfsyncreq preq;
	int s;

	s = socket(AF_INET, SOCK_DGRAM, 0);
	if (s < 0)
		err(1, "socket");

	memset(&ifr, 0, sizeof(ifr));
	memset(&preq, 0, sizeof(preq));
	strlcpy(ifr.ifr_name, "pfsync0", sizeof(ifr.ifr_name));
	strlcpy(preq.pfsyncr_syncdev, "lo0", sizeof(preq.pfsyncr_syncdev));
	inet_pton(AF_INET, "10.0.2.2", &preq.pfsyncr_syncpeer);
	preq.pfsyncr_maxupdates = 128;
	ifr.ifr_data = (caddr_t)&preq;

	printf("[*] SIOCSETPFSYNC(syncdev=lo0, syncpeer=10.0.2.2, maxupd=128)\n");
	if (ioctl(s, SIOCSETPFSYNC, &ifr) < 0)
		err(1, "SIOCSETPFSYNC");
	printf("[+] pfsync0 configured; a live engine would now sync every pf state to 10.0.2.2\n");

	memset(&ifr, 0, sizeof(ifr));
	memset(&preq, 0, sizeof(preq));
	strlcpy(ifr.ifr_name, "pfsync0", sizeof(ifr.ifr_name));
	ifr.ifr_data = (caddr_t)&preq;
	if (ioctl(s, SIOCGETPFSYNC, &ifr) == 0)
		printf("[+] SIOCGETPFSYNC: syncdev=%s maxupd=%d\n",
		    preq.pfsyncr_syncdev, preq.pfsyncr_maxupdates);
	close(s);
	return (0);
}