pfctl errata Nov 17
17 November, 2014 by sthen@openbsd.org | openbsd
Patches are now available for 5.5 and 5.6 to fix an issue with pfctl and certain rules combining IPv4 and IPv6 addresses (in that order) with a dynamic interface address using the "(interface)" format. The patch for 5.6 follows. This problem can be worked around by reversing the order of addresses (listing IPv6 first, then IPv4). untrusted comment: signature from openbsd 5.6 base private key RWR0EANmo9nqhlxzEl3gBOqqoVrDRpZgSYhTqFK031hbFJ9tX84ZYqS72CcubFWty11KDc7YCvei+VSQu1PdYPo/MU/nReUdBQU OpenBSD 5.6 errata 7, Nov 17, 2014: A PF rule using an IPv4 address followed by an IPv6 address and then a dynamic address, e.g. "pass from {192.0.2.1 2001:db8::1} to (pppoe0)", will have an incorrect /32 mask applied to the dynamic address. Apply patch using: signify -Vep /etc/signify/openbsd-56-base.pub -x 007.pfctl.patch.sig \ -m - | (cd /usr/src && patch -p0) Then build and install pfctl: cd /usr/src/sbin/pfctl make obj make make install Index: sbin/pfctl/parse.y =================================================================== RCS file: /cvs/src/sbin/pfctl/parse.y,v retrieving revision 1.636 retrieving revision 1.636.4.1 diff -u -p -r1.636 -r1.636.4.1 --- sbin/pfctl/parse.y 2 Jul 2014 13:03:41 -0000 1.636 +++ sbin/pfctl/parse.y 29 Oct 2014 15:29:33 -0000 1.636.4.1 @@ -4516,7 +4516,7 @@ expand_rule(struct pf_rule *r, int keepr char tagname[PF_TAG_NAME_SIZE]; char match_tagname[PF_TAG_NAME_SIZE]; u_int8_t flags, flagset, keep_state; - struct node_host *srch, *dsth; + struct node_host *srch, *dsth, *osrch, *odsth; struct redirspec binat; struct pf_rule rb; int dir = r->direction; @@ -4607,6 +4607,18 @@ expand_rule(struct pf_rule *r, int keepr r->af, src_host, src_port, dst_host, dst_port, proto->proto); + osrch = odsth = NULL; + if (src_host->addr.type == PF_ADDR_DYNIFTL) { + osrch = src_host; + if ((src_host = gen_dynnode(src_host, r->af)) == NULL) + err(1, "expand_rule: calloc"); + } + if (dst_host->addr.type == PF_ADDR_DYNIFTL) { + odsth = dst_host; + if ((dst_host = gen_dynnode(dst_host, r->af)) == NULL) + err(1, "expand_rule: calloc"); + } + error += check_netmask(src_host, r->af); error += check_netmask(dst_host, r->af); @@ -4757,6 +4769,14 @@ expand_rule(struct pf_rule *r, int keepr uid, gid, rcv, icmp_type, anchor_call); } + if (osrch && src_host->addr.type == PF_ADDR_DYNIFTL) { + free(src_host); + src_host = osrch; + } + if (odsth && dst_host->addr.type == PF_ADDR_DYNIFTL) { + free(dst_host); + dst_host = odsth; + } )))))))))); if (!keeprule) { Index: sbin/pfctl/pfctl_parser.c =================================================================== RCS file: /cvs/src/sbin/pfctl/pfctl_parser.c,v retrieving revision 1.298 retrieving revision 1.298.6.1 diff -u -p -r1.298 -r1.298.6.1 --- sbin/pfctl/pfctl_parser.c 20 Jan 2014 02:59:13 -0000 1.298 +++ sbin/pfctl/pfctl_parser.c 29 Oct 2014 15:29:34 -0000 1.298.6.1 @@ -1244,16 +1244,12 @@ int check_netmask(struct node_host *h, sa_family_t af) { struct node_host *n = NULL; - struct pf_addr *m; + struct pf_addr *m; for (n = h; n != NULL; n = n->next) { if (h->addr.type == PF_ADDR_TABLE) continue; m = &h->addr.v.a.mask; - /* fix up netmask for dynaddr */ - if (af == AF_INET && h->addr.type == PF_ADDR_DYNIFTL && - unmask(m, AF_INET6) > 32) - set_ipmask(n, 32); /* netmasks > 32 bit are invalid on v4 */ if (af == AF_INET && (m->addr32[1] || m->addr32[2] || m->addr32[3])) { @@ -1263,6 +1259,30 @@ check_netmask(struct node_host *h, sa_fa } } return (0); +} + +struct node_host * +gen_dynnode(struct node_host *h, sa_family_t af) +{ + struct node_host *n; + struct pf_addr *m; + + if (h->addr.type != PF_ADDR_DYNIFTL) + return (NULL); + + if ((n = calloc(1, sizeof(*n))) == NULL) + return (NULL); + bcopy(h, n, sizeof(*n)); + n->ifname = NULL; + n->next = NULL; + n->tail = NULL; + + /* fix up netmask */ + m = &n->addr.v.a.mask; + if (af == AF_INET && unmask(m, AF_INET6) > 32) + set_ipmask(n, 32); + + return (n); } /* interface lookup routines */ Index: sbin/pfctl/pfctl_parser.h =================================================================== RCS file: /cvs/src/sbin/pfctl/pfctl_parser.h,v retrieving revision 1.102 retrieving revision 1.102.4.1 diff -u -p -r1.102 -r1.102.4.1 --- sbin/pfctl/pfctl_parser.h 19 Apr 2014 14:22:32 -0000 1.102 +++ sbin/pfctl/pfctl_parser.h 29 Oct 2014 15:29:34 -0000 1.102.4.1 @@ -265,6 +265,7 @@ extern const struct pf_timeout pf_timeou void set_ipmask(struct node_host *, u_int8_t); int check_netmask(struct node_host *, sa_family_t); int unmask(struct pf_addr *, sa_family_t); +struct node_host *gen_dynnode(struct node_host *, sa_family_t); void ifa_load(void); unsigned int ifa_nametoindex(const char *); char *ifa_indextoname(unsigned int, char *);