Hello,

I'm trying to programmaticaly add rules in pf new version (OpenBSD 4.7).

I had no problem to do it in previous versions of OpenBSD.
I tried to adapt my code to the new version but without success :(
I have a "Device busy" error when the DIOCCHANGERULE ioctl is called and
I dont know why. I also tried DIOCADDRULE without more success.

See the attached file if you understand something to this stuff.


/* Thomas Bernard
 * miniu...@free.fr 
 *
 * Test for adding a rule with OpenBSD 4.7 */

#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/param.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <net/if.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <net/pfvar.h>

/*
 * what I'm trying to do is to add the rule
 *    pass in quick on xl1 inet proto udp from any to any port 54321 \
 *        label "test label" rdr-to 192.168.0.141 port 12345
 * in the anchor "miniupnpd" */
void addrule(const char * ifname, unsigned short eport,
             const char * iaddr, unsigned short iport, int proto,
             const char * desc)
{
	struct pfioc_trans trans; 
	struct pfioc_trans_e trans_e; 
	struct pfioc_rule pcr;
	int dev;
	dev = open("/dev/pf", O_RDWR);
	if(dev < 0) {
		perror("open(\"/dev/pf\")");
		return;
	}
	memset(&trans_e, 0, sizeof(trans_e));
	trans_e.type = PF_TRANS_RULESET;
	strlcpy(trans_e.anchor, "miniupnpd", MAXPATHLEN);
	memset(&trans, 0, sizeof(trans));
	trans.size = 1;
	trans.esize = sizeof(struct pfioc_trans_e);
	trans.array = &trans_e;
	if(ioctl(dev, DIOCXBEGIN, &trans) < 0) {
		perror("ioctl(dev, DIOCXBEGIN, ...)");
	}
	printf("ticket=%d\n", trans_e.ticket);

	memset(&pcr, 0, sizeof(pcr));
	pcr.ticket = trans_e.ticket;
	strlcpy(pcr.anchor, "miniupnpd", MAXPATHLEN);
	pcr.rule.direction = PF_IN;
	pcr.rule.src.addr.type = PF_ADDR_NONE;
	//pcr.rule.src.addr.type = PF_ADDR_ADDRMASK;
	pcr.rule.dst.addr.type = PF_ADDR_NONE;
	//pcr.rule.dst.addr.type = PF_ADDR_ADDRMASK;
	pcr.rule.nat.addr.type = PF_ADDR_NONE;
	pcr.rule.rdr.addr.type = PF_ADDR_ADDRMASK;
	pcr.rule.dst.port_op = PF_OP_EQ;
	pcr.rule.dst.port[0] = htons(eport);
	pcr.rule.dst.port[1] = htons(eport);
	pcr.rule.action = PF_PASS;
	pcr.rule.af = AF_INET;
	if(ifname)
		strlcpy(pcr.rule.ifname, ifname, IFNAMSIZ);
	pcr.rule.proto = proto;
	pcr.rule.rtableid = -1;
	pcr.rule.quick = 1;
	pcr.rule.keep_state = PF_STATE_NORMAL;
	strlcpy(pcr.rule.label, desc, PF_RULE_LABEL_SIZE);
	pcr.rule.rdr.proxy_port[0] = iport;
	pcr.rule.rdr.proxy_port[1] = iport;
	if(inet_pton(AF_INET, iaddr, &pcr.rule.rdr.addr.v.a.addr.v4.s_addr) <= 0)
		fprintf(stderr, "inet_pton() failed\n");
	pcr.rule.rdr.addr.v.a.mask.v4.s_addr = htonl(INADDR_NONE);

	if(ioctl(dev, DIOCADDRULE, &pcr) < 0) {
		perror("ioctl(dev, DIOCADDRULE, ...)");
		close(dev);
		return;
	}
	if(ioctl(dev, DIOCXCOMMIT, &trans) < 0) {
		perror("ioctl(dev, DIOCXCOMMIT, ...)");
	}
	close(dev);
}

/* I'm trying the same thing using DIOCCHANGERULE */
void addrule2(const char * ifname, unsigned short eport,
             const char * iaddr, unsigned short iport, int proto,
             const char * desc)
{
	struct pfioc_rule pcr;
	int dev;
	dev = open("/dev/pf", O_RDWR);
	if(dev < 0) {
		perror("open(\"/dev/pf\")");
		return;
	}
	memset(&pcr, 0, sizeof(pcr));
	strlcpy(pcr.anchor, "miniupnpd", MAXPATHLEN);
	pcr.rule.direction = PF_IN;
	pcr.rule.src.addr.type = PF_ADDR_NONE;
	//pcr.rule.src.addr.type = PF_ADDR_ADDRMASK;
	pcr.rule.dst.addr.type = PF_ADDR_NONE;
	//pcr.rule.dst.addr.type = PF_ADDR_ADDRMASK;
	pcr.rule.nat.addr.type = PF_ADDR_NONE;
	pcr.rule.rdr.addr.type = PF_ADDR_ADDRMASK;
	pcr.rule.dst.port_op = PF_OP_EQ;
	pcr.rule.dst.port[0] = htons(eport);
	pcr.rule.dst.port[1] = htons(eport);
	pcr.rule.action = PF_PASS;
	pcr.rule.af = AF_INET;
	if(ifname)
		strlcpy(pcr.rule.ifname, ifname, IFNAMSIZ);
	pcr.rule.proto = proto;
	pcr.rule.rtableid = -1;
	pcr.rule.quick = 1;
	pcr.rule.keep_state = PF_STATE_NORMAL;
	strlcpy(pcr.rule.label, desc, PF_RULE_LABEL_SIZE);
	pcr.rule.rdr.proxy_port[0] = iport;
	pcr.rule.rdr.proxy_port[1] = iport;
	if(inet_pton(AF_INET, iaddr, &pcr.rule.rdr.addr.v.a.addr.v4.s_addr) <= 0)
		fprintf(stderr, "inet_pton() failed\n");
	pcr.rule.rdr.addr.v.a.mask.v4.s_addr = htonl(INADDR_NONE);

	pcr.action = PF_CHANGE_GET_TICKET;
	if(ioctl(dev, DIOCCHANGERULE, &pcr) < 0) {
		perror("ioctl(dev, DIOCCHANGERULE, ...) PF_CHANGE_GET_TICKET");
	}
	printf("ticket=%d\n", pcr.ticket);

	pcr.action = PF_CHANGE_ADD_TAIL;
	if(ioctl(dev, DIOCCHANGERULE, &pcr) < 0) {
		perror("ioctl(dev, DIOCCHANGERULE, ...) PF_CHANGE_ADD_TAIL");
	}
	close(dev);
}

/* main() */
int main(int argc, char * * argv)
{
	printf("Calling addrule()\n");
	addrule("dc0", 12345, "192.168.55.66", 54321, IPPROTO_TCP, "coucou");
	printf("Calling addrule2()\n");
	addrule2("dc0", 12345, "192.168.77.88", 54321, IPPROTO_TCP, "coucou2");
	return 0;
}

Reply via email to