packets to bridged interfaces bypass input filter

classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|

packets to bridged interfaces bypass input filter

Sven M. Hallberg
hi all,

i sent the following question to misc@ on march 29th but received no
response. i hope you don't mind me retrying on tech@.

while playing around with pf, i noticed that some connections that i
thought should be blocked, were in fact not. here is my fairly standard
bridge setup between a wlan interface and a wired ethernet.

       # cat /etc/hostname.em0
       group lan
       up

       # cat /etc/hostname.athn0
       mediaopt hostap
       nwid xxx wpakey abcd1234
       group lan
       up

       # cat /etc/hostname.vether0
       group lan
       inet 192.168.22.145/28

       # cat /etc/hostname.bridge0
       add em0 add athn0 add vether0
       blocknonip athn0
       up

i then set up pf rules that should let the (w)lan interfaces talk to
the world.

        # cat /etc/pf.conf
        set skip on lo
        block return
        pass out        # ingress filter
        pass in on lan from lan:network to any

now this all works as intended. but, when i remove athn0 from the lan
group, i would expect the above ruleset to block any incoming
connections from the wlan.

        # ifconfig athn0 -group lan

and indeed, i could not ping a wired host from the wlan. however, i
could still access the router (192.168.22.145) itself from the wireless.
as far as i can tell, this is due to the following code in if_bridge.c,
bridge_process() -- comments by me:

        if (bridge_ourether(bif0->ifp, eh->ether_dhost)) {
                /* addressed to the iface it came in on */
                bif = bif0;
        } else {
                SMR_SLIST_FOREACH_LOCKED(bif, &sc->sc_iflist, bif_next) {
                        if (bif->ifp == ifp)
                                continue;
                        if (bridge_ourether(bif->ifp, eh->ether_dhost))
                                /* addressed to some other bridge member */
                                break;
                }
        }
        if (bif != NULL) {
                /* ... */
                if (bridge_filterrule(&bif0->bif_brlin, eh, m) ==
                    BRL_ACTION_BLOCK) {
                        goto bad;
                }
                /* ... */
        }

a packet that comes in on a member of a bridge and is addressed to _any_
bridge member interface, is processed as input to (only) the destination
interface. if that destination interface differs from the one that the
packet actually came in on, pf rules for the actual input interface are
not evaluated.

this seems to contradict the following statement in the NOTES section of
bridge(4) -- in any case, it certainly contradicted my intuition:

     Bridged packets pass through pf(4) filters once as input on the receiving
     interface and once as output on all interfaces on which they are
     forwarded.  In order to pass through the bridge packets must pass any in
     rules on the input and any out rules on the output interface.  Packets
     may be blocked either entering or leaving the bridge.

now, to be clear, i don't mind that the packet passes through 'in' rules for
vether0 in my example, but i wonder if it should not also pass through
the 'in' rules for 'athn0'.

i would appreciate enlightenment on this. note that (contrary to misc) i
am subscribed to tech@, so no cc needed.


thanks,
pesco

PS: at the time, i was using OpenBSD 6.6, but the code in question
appears unchanged in current.

Reply | Threaded
Open this post in threaded view
|

Re: packets to bridged interfaces bypass input filter

Stephan Mending
On Tue, May 26, 2020 at 09:26:07PM +0200, Sven M. Hallberg wrote:

> hi all,
>
> i sent the following question to misc@ on march 29th but received no
> response. i hope you don't mind me retrying on tech@.
>
> while playing around with pf, i noticed that some connections that i
> thought should be blocked, were in fact not. here is my fairly standard
> bridge setup between a wlan interface and a wired ethernet.
>
>        # cat /etc/hostname.em0
>        group lan
>        up
>
>        # cat /etc/hostname.athn0
>        mediaopt hostap
>        nwid xxx wpakey abcd1234
>        group lan
>        up
>
>        # cat /etc/hostname.vether0
>        group lan
>        inet 192.168.22.145/28
>
>        # cat /etc/hostname.bridge0
>        add em0 add athn0 add vether0
>        blocknonip athn0
>        up
>
> i then set up pf rules that should let the (w)lan interfaces talk to
> the world.
>
>         # cat /etc/pf.conf
>         set skip on lo
>         block return
>         pass out        # ingress filter
>         pass in on lan from lan:network to any
>
> now this all works as intended. but, when i remove athn0 from the lan
> group, i would expect the above ruleset to block any incoming
> connections from the wlan.
>
>         # ifconfig athn0 -group lan
Did you flush states between your tests (pfctl -F states) ? -> After you removed athn0 from lan group ?

>
> and indeed, i could not ping a wired host from the wlan. however, i
> could still access the router (192.168.22.145) itself from the wireless.
> as far as i can tell, this is due to the following code in if_bridge.c,
> bridge_process() -- comments by me:
>
>         if (bridge_ourether(bif0->ifp, eh->ether_dhost)) {
>                 /* addressed to the iface it came in on */
>                 bif = bif0;
>         } else {
>                 SMR_SLIST_FOREACH_LOCKED(bif, &sc->sc_iflist, bif_next) {
>                         if (bif->ifp == ifp)
>                                 continue;
>                         if (bridge_ourether(bif->ifp, eh->ether_dhost))
>                                 /* addressed to some other bridge member */
>                                 break;
>                 }
>         }
>         if (bif != NULL) {
>                 /* ... */
>                 if (bridge_filterrule(&bif0->bif_brlin, eh, m) ==
>                     BRL_ACTION_BLOCK) {
>                         goto bad;
>                 }
>                 /* ... */
>         }
>
> a packet that comes in on a member of a bridge and is addressed to _any_
> bridge member interface, is processed as input to (only) the destination
> interface. if that destination interface differs from the one that the
> packet actually came in on, pf rules for the actual input interface are
> not evaluated.
>
> this seems to contradict the following statement in the NOTES section of
> bridge(4) -- in any case, it certainly contradicted my intuition:
>
>      Bridged packets pass through pf(4) filters once as input on the receiving
>      interface and once as output on all interfaces on which they are
>      forwarded.  In order to pass through the bridge packets must pass any in
>      rules on the input and any out rules on the output interface.  Packets
>      may be blocked either entering or leaving the bridge.
>
> now, to be clear, i don't mind that the packet passes through 'in' rules for
> vether0 in my example, but i wonder if it should not also pass through
> the 'in' rules for 'athn0'.
>
> i would appreciate enlightenment on this. note that (contrary to misc) i
> am subscribed to tech@, so no cc needed.
>
>
> thanks,
> pesco
>
> PS: at the time, i was using OpenBSD 6.6, but the code in question
> appears unchanged in current.
>

Reply | Threaded
Open this post in threaded view
|

Re: packets to bridged interfaces bypass input filter

Sven M. Hallberg
Stephan Mending on Wed, May 27 2020:
>> [bridge0 with members athn0 em0 vether0, all in group lan]
>>
>>         # ifconfig athn0 -group lan
> Did you flush states between your tests (pfctl -F states) ? -> After
> you removed athn0 from lan group ?

Yes, I did.

>> [sys/net/if_bridge.c: bridge_process()]
>>
>> a packet that comes in on a member of a bridge and is addressed to _any_
>> bridge member interface, is processed as input to (only) the destination
>> interface. if that destination interface differs from the one that the
>> packet actually came in on, pf rules for the actual input interface are
>> not evaluated.

Note that the responsible code at the end of the function will set "ifp"
to the interface that the packet arrived on and branch to

    reenqueue:
            bridge_ifinput(ifp, m);

So if I'm reading this right, the idea is to reevaluate a packet that
arrives on one interface for the address of another as having come in on
the latter, and I'm guessing pf processing happens only after that.

Correct me if I'm wrong: My expectation was that a packet that comes
in on bridge member athn0 has to pass the "in" rules for athn0,
regardless of destination. What I'm unsure about is how/if any rules for
the destination member should apply. Should a packet coming in on athn0
but destined for the address of vether0 have to pass "in" rules for both
athn0 and vether0?

Regards,
pesco