On Sun, Jan 24, 2021 at 11:51 PM David Gwynne <da...@gwynne.id.au> wrote:

> On Mon, Jan 25, 2021 at 02:50:12AM +0100, Alexandr Nedvedicky wrote:
> > Hello,
> >
> > >
> > > ok. i don't know how to split up the rest of the change though.
> > >
> > > here's an updated diff that includes the rest of the kernel changes and
> > > the pfctl and pf.conf tweaks.
> > >
> > > it's probably useful for me to try and explain at a high level what
> > > i think the semantics should be, otherwise we might end up arguing
> about
> > > which bits of the current config i broke.
> > >
> > > so, from an extremely high level point of view, and apologies if
> > > this is condescending, pf sits between the network stack and an
> > > interface that a packet travels on. for connections handled by the
> > > local box, this means packets come from the stack and get an output
> > > interface selected by a route lookup, then pf checks it, and then
> > > it goes out the selected interface. replies come into an interface,
> > > get checked by pf, and then enter the stack. when forwarding, a
> > > packet comes into an interface, pf checks it, the stack does a route
> > > lookup to pick an interface, pf checks it again, and then it goes
> > > out the interface.
> > >
> > > so what does it mean when route-to (or reply-to) gets involved? i'm
> > > saying that when route-to is applied to a packet, pf takes the packet
> > > away from the stack and immediately forwards it toward to specified
> > > destination address. for a packet entering the system, ie, when the
> > > packet is going from the interface into the stack, route-to should
> > > pretend that it is forwarding the packet and basically push it
> > > straight out an interface. however, like normal forwarding via the
> > > stack, there might be some policy on packets leaving that interface
> that
> > > you want to apply, so pf should run pf_test in that situation so the
> > > policy can be applied. this is especially useful if you need to apply
> > > nat-to when packets leave a particular interface.
> > >
> > > however, if you route-to when a packet is on the way out of the
> > > stack, i'm arguing that pf should not run again against that packet.
> > > currently route-to rules run pf_test again if the interface the packet
> > > is routed out of changes, which means pf runs multiple times against a
> > > packet if rules keep changing which interface it goes out. this means
> > > there's loop prevention in pf to mitigate against this, and weird
> > > potentials for multiple states to be created when nat gets involved.
> > >
> > > for simplicity, both in terms of reasoning and code i think pf should
> > > only be run once when a packet enters the system, and only once when it
> > > leaves the system. the only reason i can come up with for running
> > > pf_test multiple times when route-to changes the outgoing interface is
> > > so you can check the packet with "pass out on $new_if" type rules. we
> > > don't rerun pf again when nat/rdr changes addresses, so this feels
> > > inconsistent to me.
> >
> >     I understand that simple is better here, so I won't object
> >     if we will lean towards simplified model above. However I still
> >     would like to share my view on current PF.
> >
> >     the way I understand how things (should) work currently is fairly
> simple:
> >
> >       we always run pf_test() as packet crosses interface.
> >       packet can cross interface either in outbound or
> >       inbound direction.
>
> That's how I understand the current code. I'm proposing that we change
> the semantics so they are:
>
> - we always run pf_test as a packet enters or leaves the network stack.
> - pf is able to filter or apply policy based on various attributes
>   of the packet such as addresses and ports, but also metadata about
>   the packet such as the current prio, or the interface it came
>   from or is going to.
> - changing a packet or it's metadata does not cause a rerun of pf_test.
> - route-to on an incoming packet basically bypasses the default
>   stack processing with a "fast route" out of the stack.
>
> >     this way we can always create a complex route-to loops,
> >     however it can also solve some route-to vs. NAT issues.
> >     consider those fairly innocent rules:
> >
> > --------8<---------------8<---------------8<------------------8<--------
> > table <hops> { 10.10.10.10, 172.16.1.1 }
> >
> > pass out on em0 from 192.168.1.0/24 to any route-to <hops>
> > pass out on em1 from 192.168.1.0 to any nat-to (em1)
> > pass out on em2 all
> > --------8<---------------8<---------------8<------------------8<--------
> >
> >     Rules above should currently work, but will stop if we will
> >     go with simplified model.
>
> The entries in <hops> make the packet go out em1 and em2?
>
> I'm ok with breaking configs like that. We don't run pf_test again for
> other changes to the packet, so if we do want to support something like
> that I think we should make the following work:
>
>   # pf_pdesc kif is em0
>   match out on em0 from 192.168.1.0/24 to any route-to <hops>
>   # pf_pdesc kif is now em1
>   pass out on em1 from 192.168.1.0 to any nat-to (em1)
>   pass out on em2 all
>
> This is more in line with how NAT rules operate.
>
> >     I'll be OK with your simplified model if it will make things
> >     more explicit:
> >
> >       route-to option should be applied on inbound rules
> >       only
>
> This would restrict how we currently write rules. See below about how we
> would be using it.
>
> >       reply-to option should be applied on outbound rule
> >       only
>
> I'm using reply-to on inbound rules. On these boxes I have a service
> (it's a dns resolver running unbound) that is accessible only via
> gre(4) tunnels, and I need the replies to those connections to go
> out the same interface they came in on. I'm running an older version of
> my diff, so I can have rules like this to make it work:
>
>   pass in quick on gre0 reply-to gre0:peer
>   pass in quick on gre1 reply-to gre1:peer
>
> The DNS traffic isn't going through this box, the replies that
> unbound is generating match the state created by the inbound rule.
>
> If I'm remembering correctly, sthen@ had a similar use case.
>
> >       dup-to option can go either way (in/out)
>
> Yep.
>
> >     does it make sense? IMO yes, because doing route-to
> >     on outbound path feels unnatural to me.
>
> I agree that it feels a bit unnatural, but so far all the route-to rules
> I've been writing have been on pass out rules. That could be peculiar to
> my setup, but we generally allow packets in on our external links, and
> apply policy on the outbound interface heading towards the relevant
> service. eg:
>
>   block
>   pass in on $if_external
>   pass out on $if_webservers proto tcp to port { http https }
>   pass out on $if_relays proto { tcp udp } to port domain
>
> We'd be sprinkling route-to on these pass out rules to tie connections
> to specific backends.
>
> >
> > </snip>
> >
> > >
> > > this also breaks the ability to do route-to without states. is there a
> > > reason to do that apart from the DSR type things? did we agree that
> > > those use cases could be handled by sloppy states instead?
> >
> >     If I remember correct we need to make 'keep state' mandatory
> >     for route-to so it can work well with pfsync(4), right?
>
> That's correct.
>
> > >
> > > lastly, the "argument" or address specified with route-to (and
> > > reply-to and dup-to) is a destination address, not a next-hop. this
> > > has been discussed on the lists a couple of times before, so i won't
> > > go over it again, except to reiterate that it allows pf to force
> > > "sticky" path selection while opening up the possibility for ecmp
> > > and failover for where that path traverses.
> >
> >     I keep forgetting about it as I still stick to current
> interpretation.
> >
> >
> > I've seen changes to pfctl. Diff below still allows rule:
> >
> >     pass in on net0 from 192.168.1.0/24 to any route-to 10.10.10.10@em0
>

I am using this currently with reply-to  and i think it would be quite
messy to change if em0 is inside a specific rtable.

I have to use reply to because
I accept connexion from adresses that can be toutes to multiple interface.

I truly hope you don’t break things just to get rid of this.

Reply to is working for me and there s just this ip@iface stuff which was
not very well documented , I didn’t replicate(pf sync) it since a long time
though




> Is there use case for the @interface syntax apart from the current
> route-to rules? If not, we can just delete it.
>
> > it also allows rule:
> >
> >     pass in on net0 from 192.168.1.0/24 to any route-to em0
> >
> > I think we don't want support those two anymore, is that correct?
>
> em0 gets resolved to the addresses on the interface. It's a silly
> config, but it's not wrong.
>
>   $ echo pass in on vmx0 from 192.168.1.0/24 to any route-to vmx0 | pfctl
> -vnf -
>   pass in on vmx0 inet from 192.168.1.0/24 to any flags S/SA route-to
> 192.0.2.34
>
> It does raise the question of what pf_route should do if it resolves
> something with RTF_LOCAL set. Or RTF_BLACKHOLE and RTF_REJECT for that
> matter.
>
> dlg
>
> >
> > thanks and
> > regards
> > sashan
>
> --
--
---------------------------------------------------------------------------------------------------------------------
Knowing is not enough; we must apply. Willing is not enough; we must do

Reply via email to