pf offers the ability to use interface groups to build dynamic rules or to simplify your ruleset. It also makes them more portable to other servers which might have different interface names, etc. While testing my firewall with FreeBSD instead of OpenBSD I was having a lot of trouble with my rules until I identified that the group keywords were not working. From FreeBSD's pf.conf(5): on <interface> This rule applies only to packets coming in on, or going out through, this particular interface or interface group. For more information on interface groups, see the group keyword in ifconfig(8). any will match any existing interface except loopback ones. So our ifconfig needs to support groups, which it appears to do according to our ifconfig(8): group group-name Assign the interface to a “group”. Any interface can be in mul‐ tiple groups. Cloned interfaces are members of their interface family group by default. For example, a PPP interface such as ppp0 is a member of the PPP interface family group, ppp. The problem appears to be that we do not have interfaces in groups by default. OpenBSD has the following in their ifconfig(8): Some interfaces belong to specific groups by default: - All interfaces are members of the all interface group. - Cloned interfaces are members of their interface family group. For example, a PPP interface such as ppp0 is a member of the ppp interface family group. - pppx(4) interfaces are members of the pppx interface group. - The interface(s) the default route(s) point to are members of the egress interface group. - IEEE 802.11 wireless interfaces are members of the wlan interface group. - Any interfaces used for network booting are members of the netboot interface group. As I learned the hard way, the following rule will not work without additional configuration: pass in quick on egress inet proto tcp from any to (egress) port 80 If I manually add the egress keyword to an interface it appears to work, but doesn't show up in ifconfig output. You have to explicitly request group members which is confusing. vm# ifconfig vtnet0 group egress vm# ifconfig vtnet0 vtnet0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> metric 0 mtu 1500 options=6c03bb<RXCSUM,TXCSUM,VLAN_MTU,VLAN_HWTAGGING,JUMBO_MTU,VLAN_HWCSUM,TSO4,TSO6,VLAN_HWTSO,LINKSTATE,RXCSUM_IPV6,TXCSUM_IPV6> ether 52:54:00:4e:65:cf inet 108.61.119.181 netmask 0xffffff00 broadcast 108.61.119.255 inet6 fe80::5054:ff:fe4e:65cf%vtnet0 prefixlen 64 scopeid 0x1 inet6 2001:19f0:5c00:8014::64 prefixlen 64 nd6 options=23<PERFORMNUD,ACCEPT_RTADV,AUTO_LINKLOCAL> media: Ethernet 10Gbase-T <full-duplex> status: active vm# ifconfig -g egress vtnet0 vs OpenBSD's ifconfig output which clearly states the groups (except "all"): $ ifconfig re0 re0: flags=28843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST,NOINET6> mtu 1500 lladdr 00:0d:b9:34:19:5c description: charter priority: 0 groups: egress media: Ethernet autoselect (1000baseT full-duplex,master,rxpause,txpause) status: active inet 68.117.126.78 netmask 0xfffffffc broadcast 68.117.126.79 The keywords do work once you manually add them to interfaces, but specifically the concept of the "egress" and "ingress" keywords are defeated without them being dynamically added to interfaces. It would be nice if we could improve the ifconfig output and also dynamically add interfaces to some sane default groups.
From my not-so-scientific research I see that FreeBSD and OpenBSD have an identical getifgroups() except OpenBSD has a free at the end that perhaps we might want to cherry pick: free(ifgr.ifgr_groups); getifgroups() appears to do the printing: if (strcmp(ifg->ifgrq_group, "all")) { if (cnt == 0) printf("\tgroups:"); cnt++; printf(" %s", ifg->ifgrq_group); } FreeBSD's ifconfig doesn't print this and I can't find anywhere that we're calling getifgroups();
I've figured out the missing "groups:" data from ifconfig's output. It's hidden behind the poorly documented -v flag. Things -v shows: - lots of detailed 802.11 stuff - LAGG: lag id, state, peer format (LACP, etc) - groups Groups are exposed by default on OpenBSD, which is nice. NetBSD and Dragonfly don't have groups. I would personally prefer to see groups by default.
A commit references this bug: Author: feld Date: Wed Nov 19 13:57:40 UTC 2014 New revision: 274710 URL: https://svnweb.freebsd.org/changeset/base/274710 Log: Expose groups by default in ifconfig output. This was never hidden by OpenBSD; unsure why we chose to do so. As groups are a requirement for pf, exposing them by default will make our pf implementation less confusing. While here add a missing free() that OpenBSD fixed 7 years ago. PR: 194925 Differential Revision: https://reviews.freebsd.org/D1185 Approved by: des Obtained from: OpenBSD Changes: head/sbin/ifconfig/ifgroup.c
Committed as 274710.
(In reply to Mark Linimon from comment #4) The groups are exposed by default with ifconfig, but automatic group membership functionality is missing in FreeBSD. I lost track of this after my research showed it was beyond my capabilities. OpenBSD has some code to automatically add interfaces to groups such as "egress" for interfaces with default routes. This would be greatly beneficial to FreeBSD users who are move pf configurations from OpenBSD to FreeBSD. I'm undecided if that warrants keeping this PR open or not, but felt worth noting.
reopening as someone else ran into this problem
CC original review approver
The problem I fixed was that "groups" were hidden from ifconfig(8) output. The outstanding issue is that when pf was ported to FreeBSD we never made automatic group membership work. As originally stated in this PR: The problem appears to be that we do not have interfaces in groups by default. OpenBSD has the following in their ifconfig(8): Some interfaces belong to specific groups by default: - All interfaces are members of the all interface group. - Cloned interfaces are members of their interface family group. For example, a PPP interface such as ppp0 is a member of the ppp interface family group. - pppx(4) interfaces are members of the pppx interface group. - The interface(s) the default route(s) point to are members of the egress interface group. - IEEE 802.11 wireless interfaces are members of the wlan interface group. - Any interfaces used for network booting are members of the netboot interface group. This functionality is extremely valuable and expected to work when you read the pf docs.
There is another issue as well: adding an interface to a group has no effect until the pf ruleset is reloaded. I'm not sure if removing an interface from a group works as intended.
(In reply to Dag-Erling Smørgrav from comment #9) I think that's expected to work (i.e. it's not a missing feature, I'm not saying it can't be broken right now). There's certainly code in pf_if.c handling group_change_event.
^Triage: D1185 was committed some time ago.