On Mon, Jan 25, 2021 at 01:11:35PM +0100, Alexandr Nedvedicky wrote: > Hello, > > </snip> > > > > > > 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? > > yes they do. let's say 10.10.10.10 is reached over em1, 172.16.1.1 is > reached over em2. sorry I have not specified that in my earlier email.
npz. > > > > > 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. > > If I understand the idea right, then basically 'match out on em0....' > figures out the new 'outbound interface' so either 'pass out on em1...' or > 'pass out on em2...' will kick in. In other words: > > depending on the destination picked up from <hops> table, > the route-to action will override the em0 interface to > either em1 or em2. yes. i dont understand the kif lifetimes though. can we just point a pdesc at an arbitrary kif or do we need ot reference count? > I think this might be way to go. > > My only concern now is that such change is subtle. I mean the > > pass out ... route-to <hops> > > will change behavior in sense that current code will dispatch > packet to new interface and run pf_test() again. Once your diff > will be in the same rule will be accepted, but will bring entirely > different behaviour: just dispatch packet to new interface. yeah. the counter example is that i was extremely surprised when i discovered that pf_test gets run again when the outgoing interface is changed with a route-to rule. there's subtlety either way, we're just figuring out which one we're going for. > > > 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. > > you are right, I did not think much of a local bound traffic. > in this case reply-to needs to be kept as-is. > > > > > > 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. > > I think this is acceptable. If this will cause a friction we can always > adjust the code in follow up commit to allow state-less route-to/reply-to > with no support from pfsync(4). if we're going to support route-to on match rules i think this will be easy to implement. > > > > > > > > > > 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 > > > > Is there use case for the @interface syntax apart from the current > > route-to rules? If not, we can just delete it. > > perhaps I'm still not quite on the same page as you then. I also > had no time to entirely test you diff. The way I understand your > effort is to change route-to behavior such it will be using > a destination instead of next-hop@interface. Or are you planning > to keep current form ('route-to next-hop@interface') working? if we ignore route-to, what's the use case for the interface part of address@interface? it doesnt seem to be accepted as part of an address in other parts of the grammar: dlg@kbuild ~$ echo pass in from 192.168.0.0@vmx0 | sudo pfctl -nf - stdin:1: @if syntax not permitted in from or to stdin:1: skipping rule due to errors stdin:1: rule expands to no valid combination dlg@kbuild ~$ echo pass from 192.168.0.0@vmx0 | sudo pfctl -nf - stdin:1: @if syntax not permitted in from or to stdin:1: skipping rule due to errors stdin:1: rule expands to no valid combination dlg@kbuild ~$ echo pass nat-to 192.168.0.0@vmx0 | sudo pfctl -nf - stdin:1: @if not permitted stdin:1: nat-to and rdr-to require a direction stdin:1: skipping rule due to errors stdin:1: rule expands to no valid combination dlg@kbuild ~$ echo pass nat-to 192.168.0.0@vmx0 | sudo pfctl -nf - if route-to isn't going to use it, can we cut the @interface part out of fthe address parser? > > > 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. > > > > unless we don't want to support yet another way of doing block/block > return > we should fail with error, I think. ok. i'll update my diff to have pf_route{,6} check these flags tomorrow. cheers, dlg