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; }