DIOCADDRULE / DIOCCHANGERULE

miniupnp <[email protected]>
Newsgroups gmane.os.openbsd.pf
Message-ID <[email protected]>
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.
testpf47.c (text/x-csrc, 4.4 KB)
/* Thomas Bernard
 * [email protected] 
 *
 * 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;
}
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.