Bug 194925 - [pf] [ifconfig] interface group keywords do not work by default
Summary: [pf] [ifconfig] interface group keywords do not work by default
Status: Open
Alias: None
Product: Base System
Classification: Unclassified
Component: kern (show other bugs)
Version: 10.0-RELEASE
Hardware: Any Any
: --- Affects Many People
Assignee: freebsd-bugs (Nobody)
URL: https://reviews.freebsd.org/D1185
Keywords:
Depends on:
Blocks:
 
Reported: 2014-11-10 13:36 UTC by Mark Felder
Modified: 2016-02-25 15:45 UTC (History)
2 users (show)

See Also:
koobs: mfc-stable10?


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Mark Felder freebsd_committer freebsd_triage 2014-11-10 13:36:16 UTC
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.
Comment 1 Mark Felder freebsd_committer freebsd_triage 2014-11-10 14:15:15 UTC
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();
Comment 2 Mark Felder freebsd_committer freebsd_triage 2014-11-17 19:15:18 UTC
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.
Comment 3 commit-hook freebsd_committer freebsd_triage 2014-11-19 13:58:12 UTC
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
Comment 4 Mark Linimon freebsd_committer freebsd_triage 2015-03-10 01:45:38 UTC
Committed as 274710.
Comment 5 Mark Felder freebsd_committer freebsd_triage 2015-03-10 11:21:34 UTC
(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.
Comment 6 Mark Felder freebsd_committer freebsd_triage 2016-02-24 13:11:24 UTC
reopening as someone else ran into this problem
Comment 7 Kubilay Kocak freebsd_committer freebsd_triage 2016-02-24 13:16:42 UTC
CC original review approver
Comment 8 Mark Felder freebsd_committer freebsd_triage 2016-02-24 13:21:39 UTC
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.
Comment 9 Dag-Erling Smørgrav freebsd_committer freebsd_triage 2016-02-25 15:19:02 UTC
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.
Comment 10 Kristof Provost freebsd_committer freebsd_triage 2016-02-25 15:45:06 UTC
(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.