Understanding if-bound vs floating state policy

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

Understanding if-bound vs floating state policy

Victor Sudakov
Dear Colleagues,

I'm trying to figure out the difference between floating and if-bound
states. Let's consider a simple ruleset with just 2 rules:

root@fw:~ # pfctl -vvs rules
No ALTQ support in kernel
ALTQ related functions disabled
@0 block return in on dmz all
  [ Evaluations: 2282      Packets: 1022      Bytes: 85848       States: 0     ]
  [ Inserted: uid 0 pid 822 State Creations: 0     ]
@1 pass in on inside all flags S/SA keep state
  [ Evaluations: 1771      Packets: 511       Bytes: 42924       States: 1     ]
  [ Inserted: uid 0 pid 822 State Creations: 1     ]
root@fw:~ #

Let's ping host 172.16.1.10 (attached to the "dmz" interface) from host
192.168.10.3 (attached to the "inside" interface) via the router.

Echo requests from 192.168.10.3 to 172.16.1.10 match Rule 1 and are
passed, and echo replies from 172.16.1.10 to 192.168.10.3 match Rule 0
and are blocked by the rule.

However, pinging 172.16.1.10 from 192.168.10.3 creates the following "all" state:

root@fw:~ # pfctl -vvs state
No ALTQ support in kernel
ALTQ related functions disabled
all icmp 172.16.1.10:31234 <- 192.168.10.3:31234       0:0
   age 00:12:08, expires in 00:00:10, 694:0 pkts, 58296:0 bytes, rule 1
   id: 000000005df37f65 creatorid: 66d731d7
root@fw:~ #

Why is this state not permitting the reversed packets (echo
replies) from 172.16.1.10 to 192.168.10.3 incoming via the "dmz" interface?

It is my understanding that with the default "state-policy=floating",
reversed packets should be passed from 172.16.1.10 to 192.168.10.3,
but it is not happening.

This behaviour would be expected with "state-policy=if-bound", but
with "state-policy=floating" shouldn't the states be global?

What am I missing?


--
Victor Sudakov,  VAS4-RIPE, VAS47-RIPN
2:5005/49@fidonet http://vas.tomsk.ru/

signature.asc (465 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: Understanding if-bound vs floating state policy

Igor Podlesny
[...]
> What am I missing?

You're missing correct understanding of how states are handled in Pf.

https://docs.oracle.com/cd/E37838_01/html/E60993/pfovw-rls.html#NWSECpfovw-passin

--
End of message. Next message?
Reply | Threaded
Open this post in threaded view
|

Re: Understanding if-bound vs floating state policy

Alexandr Nedvedicky
In reply to this post by Victor Sudakov
Hello,
On Fri, Dec 13, 2019 at 02:23:38PM +0700, Victor Sudakov wrote:

> Dear Colleagues,
>
> I'm trying to figure out the difference between floating and if-bound
> states. Let's consider a simple ruleset with just 2 rules:
>
> root@fw:~ # pfctl -vvs rules
> No ALTQ support in kernel
> ALTQ related functions disabled
> @0 block return in on dmz all
>   [ Evaluations: 2282      Packets: 1022      Bytes: 85848       States: 0     ]
>   [ Inserted: uid 0 pid 822 State Creations: 0     ]
> @1 pass in on inside all flags S/SA keep state
>   [ Evaluations: 1771      Packets: 511       Bytes: 42924       States: 1     ]
>   [ Inserted: uid 0 pid 822 State Creations: 1     ]
> root@fw:~ #
>
> Let's ping host 172.16.1.10 (attached to the "dmz" interface) from host
> 192.168.10.3 (attached to the "inside" interface) via the router.
>
> Echo requests from 192.168.10.3 to 172.16.1.10 match Rule 1 and are
> passed, and echo replies from 172.16.1.10 to 192.168.10.3 match Rule 0
> and are blocked by the rule.
>
> However, pinging 172.16.1.10 from 192.168.10.3 creates the following "all" state:
>
> root@fw:~ # pfctl -vvs state
> No ALTQ support in kernel
> ALTQ related functions disabled
> all icmp 172.16.1.10:31234 <- 192.168.10.3:31234       0:0
>    age 00:12:08, expires in 00:00:10, 694:0 pkts, 58296:0 bytes, rule 1
>    id: 000000005df37f65 creatorid: 66d731d7
> root@fw:~ #
>
> Why is this state not permitting the reversed packets (echo
> replies) from 172.16.1.10 to 192.168.10.3 incoming via the "dmz" interface?
>
> It is my understanding that with the default "state-policy=floating",
> reversed packets should be passed from 172.16.1.10 to 192.168.10.3,
> but it is not happening.
>
> This behaviour would be expected with "state-policy=if-bound", but
> with "state-policy=floating" shouldn't the states be global?
>
> What am I missing?

    according to my understanding the state got created by
    inbound rule bound to 'inside' interface. Such state allows
    further packets:

        192.168.10.3 -> 172.16.1.10  @ inbound
        172.16.1.10  -> 192.168.10.3 @ outbound

    these are all packets, which are allowed by by state created
    by your 'pass in' rule.

    The forwarding essentially means the packets cross two interfaces.
    It means the PF running on your host sees the packet two times.  The first
    time the packet is seen as inbound second time it is seen as outbound.
    For ICMP requests story goes like this:

        192.168.10.3 -> 172.16.1.10  @ inbound
        192.168.10.3 -> 172.16.1.10  @ outbound

    for ICMP replies:
        172.16.1.10  -> 192.168.10.3 @ inbound
        172.16.1.10  -> 192.168.10.3 @ outbound

    Now it should become obvious your firewall is missing state, which allows
    replies. There is no state, which allows inbound ICMP reply, and there is
    no such rule, which allows inbound ICMP rule.

    you need to adjust a policy bit:
        block return in on dmz all
        pass out on dmz all
        pass in on inside all

    the 'pass out' rule will create the state, which will allow inbound ICMP
    replies sent by hosts attached to dmz.

I hope my explanation sounds clear.

regards
sashan
Reply | Threaded
Open this post in threaded view
|

Re: Understanding if-bound vs floating state policy

Victor Sudakov
In reply to this post by Igor Podlesny
Igor Podlesny wrote:
> [...]
> > What am I missing?
>
> You're missing correct understanding of how states are handled in Pf.

Obviously. Therefore I came here for enlightenment.

>
> https://docs.oracle.com/cd/E37838_01/html/E60993/pfovw-rls.html#NWSECpfovw-passin

A good explanation, thank you for the link.  It's a pity this
explanation is not in the pf documentation (or is it?).

However, the link above does not cover the difference between if-bound
and global state policies. And from man pf.conf I made the conclusion
(mistakenly) that with state-policy=floating, pf states would work like
those in ipf/ipfw.

Where is floating vs if-bound explained at length?

--
Victor Sudakov,  VAS4-RIPE, VAS47-RIPN
2:5005/49@fidonet http://vas.tomsk.ru/

signature.asc (465 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: Understanding if-bound vs floating state policy

Victor Sudakov
In reply to this post by Alexandr Nedvedicky
Alexandr Nedvedicky wrote:

[dd]

> > Why is this state not permitting the reversed packets (echo
> > replies) from 172.16.1.10 to 192.168.10.3 incoming via the "dmz" interface?
> >
> > It is my understanding that with the default "state-policy=floating",
> > reversed packets should be passed from 172.16.1.10 to 192.168.10.3,
> > but it is not happening.
> >
> > This behaviour would be expected with "state-policy=if-bound", but
> > with "state-policy=floating" shouldn't the states be global?
> >
> > What am I missing?
>
>     according to my understanding the state got created by
>     inbound rule bound to 'inside' interface.

Correct. That was my intention.

> Such state allows
>     further packets:
>
> 192.168.10.3 -> 172.16.1.10  @ inbound
> 172.16.1.10  -> 192.168.10.3 @ outbound

Well, if the "pfctl -vvs state" showed those inbound and outbound
markers, I would have probably suspected something. Unfortunately it
presents the state as "all."

>
>     these are all packets, which are allowed by by state created
>     by your 'pass in' rule.
>
>     The forwarding essentially means the packets cross two interfaces.
>     It means the PF running on your host sees the packet two times.


This is certainly true for pf rules. However, states are processed
before rules, arent't they?


>     time the packet is seen as inbound second time it is seen as outbound.

Seen by the rules, yes. But isn't the state table supposed to be checked
*before* rules?

>     For ICMP requests story goes like this:
>
> 192.168.10.3 -> 172.16.1.10  @ inbound
> 192.168.10.3 -> 172.16.1.10  @ outbound
>
>     for ICMP replies:
> 172.16.1.10  -> 192.168.10.3 @ inbound
> 172.16.1.10  -> 192.168.10.3 @ outbound
>
>     Now it should become obvious your firewall is missing state, which allows
>     replies. There is no state, which allows inbound ICMP reply, and there is
>     no such rule, which allows inbound ICMP rule.
I see now. The state-policy=floating mislead me into believing that the
state table was global. Thank you for explaining.

But then, what is the real difference betwttn if-bound and global?


--
Victor Sudakov,  VAS4-RIPE, VAS47-RIPN
2:5005/49@fidonet http://vas.tomsk.ru/

signature.asc (465 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: Understanding if-bound vs floating state policy

Igor Podlesny
On Fri, 13 Dec 2019 at 22:00, Victor Sudakov <[hidden email]> wrote:
[...]
> But then, what is the real difference betwttn if-bound and global?

it's not global but rather "floating". man pf.conf says:

"... floating States can match packets on any interfaces (the default). ..."

IOW, floating state doesn't care which interface gets reply traffic,
meanwhile if-bound does.
This adds something like urpf-failed protection to the state table.

--
End of message. Next message?
Reply | Threaded
Open this post in threaded view
|

Re: Understanding if-bound vs floating state policy

Kenneth Gober
In reply to this post by Victor Sudakov
On Fri, Dec 13, 2019 at 10:02 AM Victor Sudakov <[hidden email]> wrote:
But then, what is the real difference betwttn if-bound and global?

My understanding is that the difference applies when you have multiple paths to the same destination.  For example, suppose you have a hardwired ethernet connection on em0, and you also have a wireless connection on iwn0, and you freely switch back and forth between them but use the same IP address on both.  With if-bound states, switching from one interface to another would require you to restart all your already-in-progress sessions in order to re-establish states on the new interface.  With floating states, a state established on one interface could be used directly if packets for that connection suddenly start appearing on a different interface.  (this is a bad example, I know, because ARP issues would make it hard for an IP to float back and forth transparently, but a more proper example is harder to explain).

It is a more useful setting on a router in a mesh network, where packets you're forwarding might move between different interfaces, as their path through the network is adjusted due to congestion or whatever.  On an endpoint it's not particularly useful unless you want to allow sessions to migrate between different interfaces (all using the same IP address), which is a somewhat rare use case and one you would normally use trunk interfaces to support, rather than floating states.

-ken
Reply | Threaded
Open this post in threaded view
|

Re: Understanding if-bound vs floating state policy

Alexandr Nedvedicky
In reply to this post by Victor Sudakov
Hello,

</snip>

>
> >     For ICMP requests story goes like this:
> >
> > 192.168.10.3 -> 172.16.1.10  @ inbound
> > 192.168.10.3 -> 172.16.1.10  @ outbound
> >
> >     for ICMP replies:
> > 172.16.1.10  -> 192.168.10.3 @ inbound
> > 172.16.1.10  -> 192.168.10.3 @ outbound
> >
> >     Now it should become obvious your firewall is missing state, which allows
> >     replies. There is no state, which allows inbound ICMP reply, and there is
> >     no such rule, which allows inbound ICMP rule.
>
> I see now. The state-policy=floating mislead me into believing that the
> state table was global. Thank you for explaining.
>
> But then, what is the real difference betwttn if-bound and global?
>

    assuming we talk about if-bound vs. floating state policy.

    you have to note the packet direction and interface as two different
    attributes to match.

    If you enable if-bound state match policy then PF continues to
    check for direction where packet is traveling (@inbounc vs. @outbound),
    furthermore PF also requires the packet to be seen on the interface,
    where PF saw packet, which has created the state.

    floating relaxes the requirement such interface is omitted, think of packet
    may match any/all interfaces, but must travel in expected direction.

    to be honest I don't know at top of my head, what is a good/typical
    use-case for if-bound state policy. I assume those set-ups must be
    rare/special.

regards
sashan
Reply | Threaded
Open this post in threaded view
|

Re: Understanding if-bound vs floating state policy

Igor Podlesny
[...]
>     to be honest I don't know at top of my head, what is a good/typical
>     use-case for if-bound state policy. I assume those set-ups must be
>     rare/special.

anti-spoofing.

In case one suspects a spoofing attack can be carried out on some "side" network
interface(s), leveraging if-bound state option allows to eliminate the threat.

An example: https://www.openwall.com/lists/oss-security/2019/12/05/1

--
End of message. Next message?
Reply | Threaded
Open this post in threaded view
|

Re: Understanding if-bound vs floating state policy

Victor Sudakov
In reply to this post by Igor Podlesny
Igor Podlesny wrote:
> [...]
> > But then, what is the real difference betwttn if-bound and global?
>
> it's not global but rather "floating". man pf.conf says:
>
> "... floating States can match packets on any interfaces (the default). ..."

Of course I meant "floating", it's in the Subject line.

>
> IOW, floating state doesn't care which interface gets reply traffic,
> meanwhile if-bound does.

Is there yet another policy which doesn't care what direction the
stateful traffic goes? The state table should work before the rules
anyway.

The documentation you gave at
https://docs.oracle.com/cd/E37838_01/html/E60993/pfovw-rls.html#NWSECpfovw-passin
mentions some "sloppy" option for the kept state, is not what I'm
looking for?


> This adds something like urpf-failed protection to the state table.

And a bit of confusion too.

--
Victor Sudakov,  VAS4-RIPE, VAS47-RIPN
2:5005/49@fidonet http://vas.tomsk.ru/
Reply | Threaded
Open this post in threaded view
|

Re: Understanding if-bound vs floating state policy

Victor Sudakov
In reply to this post by Alexandr Nedvedicky
Alexandr Nedvedicky wrote:

> >
> > I see now. The state-policy=floating mislead me into believing that the
> > state table was global. Thank you for explaining.
> >
> > But then, what is the real difference betwttn if-bound and global?
> >
>
>     assuming we talk about if-bound vs. floating state policy.
>
>     you have to note the packet direction and interface as two different
>     attributes to match.
>
>     If you enable if-bound state match policy then PF continues to
>     check for direction where packet is traveling (@inbounc vs. @outbound),
>     furthermore PF also requires the packet to be seen on the interface,
>     where PF saw packet, which has created the state.
>
>     floating relaxes the requirement such interface is omitted, think of packet
>     may match any/all interfaces, but must travel in expected direction.
>
>     to be honest I don't know at top of my head, what is a good/typical
>     use-case for if-bound state policy. I assume those set-ups must be
>     rare/special.

Maybe to emulate the Cisco reflexive ACL behaviour?

Frankly I'd like to see yet another state-policy, could be called
"global" if you wish, which emulates ipfw/ipf bidirectional state behavior.

--
Victor Sudakov,  VAS4-RIPE, VAS47-RIPN
2:5005/49@fidonet http://vas.tomsk.ru/
Reply | Threaded
Open this post in threaded view
|

Re: Understanding if-bound vs floating state policy

Victor Sudakov
In reply to this post by Igor Podlesny
Igor Podlesny wrote:
> [...]
> >     to be honest I don't know at top of my head, what is a good/typical
> >     use-case for if-bound state policy. I assume those set-ups must be
> >     rare/special.
>
> anti-spoofing.
>
> In case one suspects a spoofing attack can be carried out on some "side" network
> interface(s), leveraging if-bound state option allows to eliminate the threat.

Isn't "antispoof" for that already?
>
> An example: https://www.openwall.com/lists/oss-security/2019/12/05/1

--
Victor Sudakov,  VAS4-RIPE, VAS47-RIPN
2:5005/49@fidonet http://vas.tomsk.ru/
Reply | Threaded
Open this post in threaded view
|

Re: Understanding if-bound vs floating state policy

Igor Podlesny
On Sun, 15 Dec 2019 at 15:01, Victor Sudakov <[hidden email]> wrote:

> Igor Podlesny wrote:
> > [...]
> > >     to be honest I don't know at top of my head, what is a good/typical
> > >     use-case for if-bound state policy. I assume those set-ups must be
> > >     rare/special.
> >
> > anti-spoofing.
> >
> > In case one suspects a spoofing attack can be carried out on some "side" network
> > interface(s), leveraging if-bound state option allows to eliminate the threat.
>
> Isn't "antispoof" for that already?

If we're talking about __new__ connections attempts it will work, of course.

But we discussed "states" instead so far.

Also being attentive enough (obviously) you'll find that "antispoof"
__requires__ an interface name to function

    ("urpf-failed" doesn't but still you'll need to bypass state
look-ups for this to be effective)

meanwhile "if-bound" can be applied independently.

--
End of message. Next message?