WEBVTT

00:00.000 --> 00:14.960
Ladies, gentlemen, the otherwise fabulous welcome.

00:14.960 --> 00:19.220
As stated, we're going to be talking about a package journey through PF, so yes, yet another

00:19.220 --> 00:20.220
firewall.

00:20.220 --> 00:22.520
We're free BSE, we get that a lot.

00:22.520 --> 00:24.920
Yes, another firewall.

00:24.920 --> 00:26.280
Very briefly, who am I?

00:26.280 --> 00:27.280
I'm Christoph.

00:27.280 --> 00:30.480
You can get me on KPF3BSD.org.

00:30.480 --> 00:39.240
I've been maintaining the FN3BSD since 2015, and yes, I do feel old when I say this.

00:39.240 --> 00:45.040
Started out 10 years ago, looking at PF, it doesn't really handle IPv6 fragments, particularly

00:45.040 --> 00:47.840
well, I bet I could fix that.

00:47.840 --> 00:51.480
Those of you who have experienced with open source projects are groaning right now because

00:51.480 --> 00:55.160
you can never ever escape this again.

00:55.160 --> 01:00.720
So as I said, I've been doing that since 2015, since 2021, and that's why I brought

01:00.720 --> 01:01.720
the hat.

01:01.720 --> 01:07.280
I've been contracting for nitgate, and I've been maintaining PF in PF since then,

01:07.280 --> 01:13.480
so thank you very much nitgate because I do like food.

01:13.480 --> 01:20.480
Very briefly, this talk is based on 3BSE main as of about today.

01:20.480 --> 01:23.640
There's been a little bit of refactoring work that has been stolen.

01:23.640 --> 01:29.280
And I mean, imported from openBSD, they still have theirs, it's fine.

01:29.280 --> 01:35.480
This talk is also inspired by, there we go, I've avoided the S-word, by a talk called

01:35.480 --> 01:40.000
a package journey through the openBSD network stack by Alexander Bloom.

01:40.000 --> 01:41.400
It's quite good talk.

01:41.400 --> 01:47.120
It's on YouTube, it was presented at EuroBSD in Dublin, in September.

01:47.120 --> 01:52.480
Here are the slides, we'd recommend it, especially because this talk is sort of a spiritual

01:52.480 --> 01:53.480
successor.

01:53.480 --> 01:59.400
Alexander talked about the network stack at large, I'm going to talk about the firewall,

01:59.400 --> 02:10.280
but you kind of have to, yeah, but I don't want to be on the camera anyway, nobody wants

02:10.280 --> 02:12.080
to see that.

02:12.080 --> 02:15.720
So Alexander talked about the network stack at large, you kind of have to understand

02:15.720 --> 02:20.320
how the network stack works, to understand how the firewall fits into it.

02:20.400 --> 02:25.720
Unfortunately, I ran into trouble compressing a 50 minute talk into an introduction to

02:25.720 --> 02:27.880
a 25 minute talk.

02:27.880 --> 02:31.040
So there we go, there's already essence, everybody's seen this, everybody's on the

02:31.040 --> 02:33.080
stood this, moving on.

02:33.080 --> 02:39.960
No, so the main thing to keep in mind here is this, this is a very simplified version

02:39.960 --> 02:45.240
of how stuff works, but essentially, packets arrive on the hardware, the device driver

02:45.240 --> 02:50.280
does things to speak to the hardware, the liver's ethernet packets into the ethernet.

02:50.360 --> 02:55.680
ether input function, yes, I have assumes that all networking is ethernet, it's okay,

02:55.680 --> 02:58.880
everybody does it, because all networking is ethernet.

02:58.880 --> 03:06.120
The ethernet function will demultiplex this, we'll go look at the packet on the side, you know,

03:06.120 --> 03:12.920
what type of packet is this, this is an R packet, is it an IPv6 packet, is it an IPv4 packet,

03:12.920 --> 03:18.360
but this is a legacy presentation, so this is IPv4, it really should have been IPv6.

03:18.920 --> 03:23.800
You reason that input function goes into your IP input function, which depending on where the packet

03:23.800 --> 03:31.320
is intended to go to, might call forwarding to happen, so you know, pass the packet onto to the

03:31.320 --> 03:38.320
next router, or it might be an input packet, again, with demultiplexing, based on your IP protocol

03:38.320 --> 03:46.240
field, is this a TCP packet, is it UDP, is it ICMP, is it God knows what else, and then we might

03:46.240 --> 03:51.360
hand it to the socket layer for local processing, same thing on the output side, if you're

03:51.360 --> 03:56.880
have a TCP socket, you will TCP output, you will IP output, ethernet output, hand it off to the

03:56.880 --> 04:01.120
device, which will throw it on the network, and if you're very, very lucky your packet will

04:01.120 --> 04:08.280
actually turn up somewhere else, main things to remember when you're hacking on network

04:08.280 --> 04:13.640
stacks is the order of operations here is difference, when packets come in, you do ethernet

04:13.640 --> 04:21.560
first, and then IP, and then TCP, when packets go out, you do TCP first, then IP, then ethernet,

04:21.560 --> 04:28.160
or possibly you do, you know, ethernet IP, ethernet, when you're thwarting, so where does the

04:28.160 --> 04:36.120
firewall fit into this, right there, so in 3bSD we have your choice of firewalls, you can

04:36.120 --> 04:42.120
have PS, that's the one I work on, you can have IPFW, that's the one done by smart people,

04:42.120 --> 04:47.320
and then there's also IPF, so because we've got these multiple firewalls, we just don't

04:47.320 --> 04:54.920
have code in the kernel that goes if PS, then call PF inputs, if IPFW, do IPF check, IPF

04:54.920 --> 05:02.200
W check or whatever, we've got an abstraction layer called NetPefill or PFO, and that hooks

05:02.200 --> 05:07.360
in an appropriate location, so I've only really illustrated inputs and outputs on the IP layer

05:07.360 --> 05:13.040
here, there are also hooks where you can do layer 3 filtering, there's even some very strange

05:13.040 --> 05:20.080
things that NetPefillings do where they actually hook into the device driver, even lower,

05:20.080 --> 05:26.920
there are layer 2 hooks here, I've not shown them here because PF does do ethernet filtering that

05:26.920 --> 05:35.880
we're not going to talk about that here, P Concepts for PF is, it is a stateful firewall,

05:35.880 --> 05:41.400
so states are important, you need to remember that those exist, and we are a stateful

05:41.400 --> 05:47.000
firewall even for stateless protocols, so I'm sure we all know that UDP is a stateless protocol,

05:47.000 --> 05:52.360
you send the UDP packet and as far as the protocol is concerned there is no other packets,

05:52.360 --> 06:00.440
it's just a UDP packet, in practice however you like to do things like get a reply, so what

06:00.520 --> 06:08.200
do we use UDP for basically only DNS, right? And when you send the DNS query, it is a UDP

06:08.200 --> 06:15.480
packet that goes out to port 53 from whatever source port you've selected, but to be really useful,

06:15.480 --> 06:20.200
you kind of want to get an answer to that packet, so there is a reply packet that is source

06:20.200 --> 06:27.000
port 53 destination port whatever source port you picked, and then PF will recognize that actually

06:27.080 --> 06:34.600
this UDP packet belongs to states that I've created for this UDP packet, so you can configure

06:34.600 --> 06:41.400
your firewall and say, I will allow outbound connections to port 53, and you don't need to worry

06:41.400 --> 06:48.680
about the reply, that is implicitly going to be allowed as part of that state, the next concept

06:48.680 --> 06:53.640
of course is rules, your firewall is not particularly useful if you can't tell it what you want it to

06:54.600 --> 07:00.520
so I like to describe firewalls as policy instruments, where you can decide that you know this is

07:00.520 --> 07:05.720
the type of traffic I want to allow traffic to these addresses to these ports, these protocols,

07:05.720 --> 07:13.480
whatever you want it to be, and that's defined in rules, so rules will end up creating states,

07:15.160 --> 07:21.960
what happens when we hit the people inputs, these are the main functions that you need to

07:21.960 --> 07:30.600
understand, we hit PF test, actually that's a lie, we hit PF check in or PF check six in or PF check

07:30.600 --> 07:36.680
out, but those functions don't do much, they all just call PF test, so you end up in PF test,

07:37.480 --> 07:42.280
first thing the PF test function does, and it does this for every single packet that PF deals with,

07:43.560 --> 07:50.200
is it calls a PF set of P-desk, which parses the packet, it sets up a P-desk or a packet descriptor,

07:50.200 --> 07:55.640
with a whole bunch of information about the packet, so all of stuff like what's the source IP address,

07:55.640 --> 08:00.680
what's the destination IP address, what interface did it come in on, what's the protocol,

08:00.680 --> 08:06.840
what's the source port, what's the destination port, all of those things get set up in a separate

08:06.840 --> 08:10.920
descriptor, so we don't have to parse and reparse and reparse the packet, we do that once,

08:12.520 --> 08:18.280
would it also does is what PF calls packet normalization, and the most important thing it does

08:18.280 --> 08:25.240
in the normalization step is reassembly, because packet fragmentation is a thing, yes even in IPv6,

08:26.040 --> 08:31.080
which is part of the reason that I have this much gray hair is IPv6, packet fragmentation,

08:31.960 --> 08:36.520
but we have to reassemble the packet, because if we don't see the full packet, it is entirely

08:36.520 --> 08:43.880
possible that we don't see the headers, so if we want to make a firewall decision on a packet,

08:43.880 --> 08:51.560
quite typically we care about the layer 4 protocol, TCP, UDP, SCP, ICMP, and we want to say,

08:51.560 --> 08:58.520
we want to allow TCP to port 4, 4, 3 for instance, we really need the TCP header to be able to make

08:58.520 --> 09:04.600
that decision, so we reassemble the packet and we look at the fully reassembled packet until we're

09:04.600 --> 09:10.040
all the way done with it, there's a special case for V6, which hopefully we'll get to,

09:10.120 --> 09:20.440
typically we only really look at layer 3, the IPv6 header and layer 4, TCP UDP, if it does not

09:20.440 --> 09:26.840
find state, this is a packet that is creating a new connection, so ideally it's TCP sin or it's

09:26.840 --> 09:34.760
the first UDP packet you've seen, then we will evaluate the rules, which is PF test rule, it's

09:34.760 --> 09:39.000
right through all of the rules that we have configured see if they match the packet and eventually

09:39.000 --> 09:44.360
get to a point where we make a decision. Either way, eventually there's output handling and

09:44.360 --> 09:49.480
there's only so many things that you can do to a packet, right? You can pass the packet, you can say,

09:49.480 --> 09:55.320
yes, I approve of this packet, you can continue on your way on the lessons, we can drop the packet,

09:55.320 --> 10:00.120
which is when we don't approve of, you know, the packet sense of style or whatever,

10:00.120 --> 10:05.400
why ever we decided that it's not a good packet, we drop it on the floor and buy its goal.

10:05.960 --> 10:12.280
We can route to, which is PF's policy routing, where you can say that, yeah, okay, my default routes

10:12.280 --> 10:17.160
is that the packets need to go that way, but actually if it's this specific port and this specific

10:17.160 --> 10:24.120
protocol, I would like you to send it that way instead. We also have F2, this is new,

10:25.000 --> 10:31.560
well it's new in 3b as the, it's other family translation, it's not 6-4, it's doing unspeakable

10:31.560 --> 10:39.400
things so that your IPv6 clients can talk to the IPv4 internet. This is very new, this is work sponsored by

10:39.400 --> 10:51.640
NetGates and it's going to be in 3b as the 15 and the upcoming PF sense 2503. And then IPv6 is special

10:51.640 --> 10:57.480
for your output handling because we may have to refragment. So we're familiar with fragmentation,

10:57.480 --> 11:03.720
right, we have a large packet, we want to send 20,000 bytes of data, unfortunately Ethernet is

11:03.720 --> 11:09.880
terrible and you can only send 1500 bytes of data in one go. So you chop the data up into fragments,

11:09.880 --> 11:15.640
you shove all of the fragments through the network all by individually and then eventually you put

11:15.640 --> 11:20.760
them all back together. As we've discussed, your firewall has to put them back together as well.

11:20.760 --> 11:25.560
And for IPv4, this is simple, you've put the packet back together and then we just hand it to the

11:25.560 --> 11:34.360
output codes to IP outputs and if the 20,000 bytes don't fit down that link, it'll just refragment

11:34.360 --> 11:41.960
it for us and everything will be okay. IPv6 is fragmentation is different, so those of you who were

11:41.960 --> 11:48.200
taught IPv6 might have been taught that there is no fragmentation in IPv6, that's not quite true,

11:48.200 --> 11:55.160
there is no intermediate router fragmentation in IPv6. So in IPv4 every single hop can chop your packets

11:55.160 --> 12:00.920
up into smaller pieces. In IPv6 they are not allowed to do this. If you get to a point where

12:00.920 --> 12:05.960
your packet cannot fit down the link, you don't fragment it, you send the network message back

12:05.960 --> 12:11.160
to the sender with, yeah, I'm sorry, but you send me 1500 bytes and I can only fit

12:11.160 --> 12:18.440
1400 bytes down this link and then the sender will split his packet up into 1400 bytes chunks

12:18.440 --> 12:23.720
and send them all. And then potentially discovered that the next router says, yeah, I can only

12:23.880 --> 12:30.120
fit 1300 bytes down this and then an error message goes back and you try again with an even smaller one.

12:30.120 --> 12:37.000
This is called path empty you discovery. If people don't walk I see MP, this actually sometimes

12:37.000 --> 12:44.760
even works. But we can't break this in our firewall, so we've got this reassemble IPv6 packet

12:44.760 --> 12:53.000
that's 20,000 bytes and we can't shove it down 1500 byte interface. So we have to refragment the

12:53.960 --> 13:00.600
packet but we have to remember what size of fragments we got when they came in. And then we refragment

13:00.600 --> 13:05.320
along the same size, actually for simplification what we do is we look at what is the largest

13:05.320 --> 13:14.040
fragment that we've seen and we refragment basal that size. Now typically your implementation

13:14.040 --> 13:18.360
is not going to be stupid and that is just going to match exactly the same packet sizes that

13:18.680 --> 13:24.680
came in. But it means that we, because we respect this packet size, your path empty you discovery

13:24.680 --> 13:29.400
is going to keep working. Which is kind of important. Even though fragmentation is not typically

13:29.400 --> 13:37.720
a thing, all of the internet is TCP right and in TCP you make sure that a single frame, a single TCP

13:37.720 --> 13:43.720
packet passes in whatever you want to do. It's a stream and TCP takes care of all of the reassembly.

13:44.680 --> 13:51.160
Now there are some implications to this design. You may remember that the first thing we did

13:51.160 --> 13:59.560
for a packet in PF test states protocol is we look up a state. Now this implies that it doesn't

13:59.560 --> 14:04.600
matter what your rule set is if there is an existing state for a connection it will pass.

14:06.600 --> 14:11.560
So as a PF user you should be aware of this that when you change the rules

14:12.520 --> 14:18.280
even if your new rules that would mean that a specific connection is not allowed if the

14:18.280 --> 14:23.880
connection was established before you set your rules the connection will continue. Sometimes you want this

14:23.880 --> 14:29.400
sometimes you don't. If you don't want this you can flush existing states you can kill specific states

14:29.400 --> 14:36.760
but be aware that this is a thing. As I said you know, block all might not actually block everything.

14:37.480 --> 14:45.400
What it also implies is that the state look up is quite important because we do this for every

14:45.400 --> 14:52.200
packet. How does this work? We keep a hash table of state so we have a very big hash table

14:53.560 --> 15:00.120
and we hash states based on their source and destination IP address source and destination port.

15:00.200 --> 15:05.560
Others family so that you know we don't mistake IPv4 and IPv6 connections for each other

15:06.360 --> 15:12.280
and then whatever protocol it is. Based on these things we can find a specific hash row and then

15:12.280 --> 15:17.560
every hash row has a little linked list that we can iterate through and go or you my state or you my state.

15:17.560 --> 15:24.680
Oh your my state and now we can continue. You can configure how big this hash table is there's a

15:24.680 --> 15:33.320
Cisco or tunable rather nettle pf.states on the score hash size. This is important because if you

15:33.320 --> 15:39.080
have many more states than you have rows in your hash table you will end up with many states in

15:39.080 --> 15:44.200
every single row and there are many hopes on the linked list that you need to walk through before

15:44.200 --> 15:51.400
you find your packet. As a general guideline you know try to have as many rows in your state

15:51.960 --> 15:59.240
hash table as you expect to have states. So if you're dimensioning your firewall for 10,000 states

15:59.240 --> 16:07.960
or 100,000 or a million you want 10,000 or 100,000 a million rows you can be off you know by a factor

16:07.960 --> 16:14.520
of two in either direction and it'll mostly be fine but if you're off by more than that it's going

16:14.520 --> 16:20.360
to hurt. If you have too many rows you know you've based memory memory is cheap.

16:21.720 --> 16:27.960
Probably almost always better off wasting memory rather than having enough rows but it is something

16:27.960 --> 16:35.800
to keep in mind. There's actually a dethrase probe that is quite interesting so dethrase let's

16:35.800 --> 16:40.920
you do dynamic probing you can you can know when certain events happen in the kernel in the middle of

16:40.920 --> 16:47.960
a function we have some static probe points or defined in the codes that when you get here these are

16:47.960 --> 16:53.480
the values that you can measure and one of them runs in the purge thread so that's a background

16:53.480 --> 17:00.600
maintenance task in pf where it will clean up old states and potentially old rules and so it runs

17:00.600 --> 17:08.200
through this entire state table every so often and for every row that it runs through it can tell you

17:08.200 --> 17:14.600
you know I'm in row number 45 and actually I had three states in this row and I'm in row number 46 and

17:14.600 --> 17:20.520
I have one state and I'm in 47 I have zero states so you can build a histogram you can monitor

17:20.520 --> 17:27.400
how your utilization is there. Another thing to remember that is potentially interesting to know

17:27.400 --> 17:34.120
is due to the way state limits are implemented actually hitting your state limit is quite expensive

17:35.080 --> 17:39.960
so you don't want to be in a situation where you're constantly pushing up against that limit.

17:42.600 --> 17:49.720
What else is important we have a control plane which is how you interact with pf either through

17:49.720 --> 17:57.400
a utility pf cut all which you may all be familiar with or programmatically for the kernel it's

17:57.480 --> 18:04.040
all the same thing there's an api towards the kernel and right now in pf there are three different

18:04.040 --> 18:10.200
ways to do this this is because of historical reasons it started out with an octal interface

18:10.200 --> 18:16.680
basically where you copy structures in and out of the kernel this is simple this is relatively

18:16.680 --> 18:24.440
efficient and this is a pain in the everywhere when you want to make changes because you know you

18:24.520 --> 18:29.560
modify the struct and all of your fields move around and use of space and kernel have a different

18:29.560 --> 18:35.000
idea of what the struct layout is and nothing works so it becomes very difficult to make extensions

18:36.520 --> 18:42.440
to teach pf new tricks which we've been doing so one of the ways to deal with this is actually what

18:42.440 --> 18:48.920
they did in previous what they described in the previous talk for npf is nv list name value pairs

18:49.000 --> 18:54.440
you have an abstract representation of what you're sending backwards and forwards into the kernel

18:54.440 --> 19:00.200
a lot of the kernel and that means that when you add fields and one side or the other doesn't know

19:00.200 --> 19:07.160
about this field just ignore it and everything works so this is good but there are performance

19:07.160 --> 19:13.640
implications as discussed in the previous talk the experience in 3b as d was it worked fine

19:14.520 --> 19:19.880
right up until we try to use it for state exports so you can get pf give you a list of all of the

19:19.880 --> 19:25.320
states it knows about and you know if you have a hundred this is fine if you have a hundred thousand

19:25.320 --> 19:33.080
or a million this is very much not fine not fine to the extent that I think we topped out at

19:33.080 --> 19:39.000
maybe two million states and then we were copying four gigabytes of data between the kernel and

19:39.080 --> 19:51.080
user space yeah that was painful painfully slow as well so the new shineiness is not link yes that

19:51.080 --> 19:59.320
Linux thing I like to describe it as solving more of the problem than what I optal plus nv list does

19:59.320 --> 20:05.320
it also has this notion of type length value encoding for your fields so you can add new field

20:05.400 --> 20:10.360
types without confusing the other end of the connection even if they don't know about it but the

20:10.360 --> 20:18.520
really nice thing is its efficiency it's essentially just as fast as the old I optal style but because

20:18.520 --> 20:26.920
it can stream data out when you're exporting two million states get a peak memory use of 16 megabytes

20:26.920 --> 20:33.240
you know trivial amounts of memory actually in use so it is both fast and memory efficient

20:33.240 --> 20:41.320
and it gives us the flexibility of of extending interactions which again is really important if you

20:41.320 --> 20:46.680
want to have new features because if you want to teach pf to do things like address translation

20:46.680 --> 20:52.760
address family translation that's six four things you need a way to configure this you need additional

20:52.760 --> 21:01.320
fields in your rule structure so you need to be able to make those changes my hope is to migrate to

21:01.400 --> 21:09.240
net link for everything and then you just get rid of the old interface I point this out because if you

21:09.240 --> 21:15.080
are writing an application to interact with pf there are multiple ways that you can do this right you

21:15.080 --> 21:23.320
can just exec pf cuttle and pass information into its standard in or standard out which sometimes is

21:23.320 --> 21:29.640
the right thing to do but I abore the notion of forking off other binaries to do work for you it's

21:29.640 --> 21:38.040
just ugly and error handling is terrible but sometimes it's the right thing to do what you want to do

21:38.040 --> 21:43.960
is there is a library called lib pf cuttle that makes abstraction of these things so it just gives

21:43.960 --> 21:49.880
you some functions and some structures that you can fill out and interact with or get information

21:49.880 --> 21:56.920
out of pf that way it's actually what pf uses it is also a work in progress so no everything is

21:57.000 --> 22:03.240
implemented this way but every time I make changes or I convert stuff to net link they get a lib pf cuttle

22:05.080 --> 22:12.920
function for this so if you're going to build new tool to interact with pf please please please look at this

22:13.880 --> 22:20.360
or just exec pf cuttle do not try to interact with the actual interface yourself because sooner or later

22:20.360 --> 22:30.840
I'm going to break it for you you've been warned you know we're in free bz we try to be very good about

22:33.640 --> 22:39.720
about backwards compatibility and things like that but I'm not going to keep maintaining the

22:39.720 --> 22:47.000
old ideal code once it's it's no longer relevant for for mainline pf it is going to go away at some point

22:47.560 --> 22:55.400
I think we have some time for questions if you would like otherwise I have some spare slides and I can

22:55.400 --> 23:15.800
talk about some other things was everything completely clear yes so the question is how close is

23:15.800 --> 23:25.800
free bz pf to open bz pf and net bz pf so I'm not at all familiar with net bz pf my understanding is that

23:25.800 --> 23:31.400
it is essentially on main time there but they're in mind that I'm not very familiar so I might

23:31.400 --> 23:38.440
make completely wrong but I do see the net bz people nodding I saw some noise in net bz that they would

23:38.440 --> 23:44.920
like to kick it out at some points but that has not happened right okay so pf in net bz is going to

23:45.000 --> 23:52.360
go away soon so I can stop talking about that one open bz pf is the source of free bz pf that's where it

23:52.360 --> 24:01.400
came from so they share a history the implementation is different so free bz pf has a couple of

24:01.400 --> 24:09.880
features that open bz pf doesn't have and vice versa definitely the main things that pf gained in free

24:09.880 --> 24:15.960
bz the art performance changes so open bz d still have they are in the process of removing it but

24:15.960 --> 24:21.160
they still have essentially one big kernel lock or one big network stack lock so you get into pf there

24:21.160 --> 24:28.200
is one lock and there is only one core that can work on pf at a time free bz pf and this is what work

24:28.200 --> 24:37.400
I did this is work that glove smirnov did I believe years ago to make pf be able to use multiple

24:37.400 --> 24:44.120
cores at the same time and essentially the way this works is you have a read right lock of the rules

24:44.680 --> 24:48.760
so every time you come into pf and you need to do something with the rules you take a read lock

24:48.760 --> 24:53.400
and you can have as many cores as you like with that read lock at a time and then when they need

24:53.400 --> 25:01.320
to manipulate states they will lock the hash row of that state so as long as there's no other

25:01.320 --> 25:07.640
states in that row or not too many other states in that row other cores can be operating on

25:07.640 --> 25:18.040
other states at the same time so that's locking so you do get a fairly substantial performance

25:18.040 --> 25:24.840
difference there the other one of the other differences is five minutes thank you

25:25.320 --> 25:32.440
is vnet support it's the the virtual IP stack thing for jails that we have in free bz pf is

25:32.440 --> 25:40.600
aware of this so you can have a pf per jail which is a really really really useful feature to have

25:40.600 --> 25:46.520
both because it gives you flexibility in your jails but also because I use it for testing

25:46.520 --> 25:51.800
so I can spin up two jails set a pf rule set in one of them throw packets from one jail at the

25:51.800 --> 25:58.040
other jail and see what happens so a whole bunch of automated tests in free bz d for pf thanks to

25:58.040 --> 26:06.520
that feature they also recently added a ctp support to pf that's also only in free bz dp f

26:09.160 --> 26:14.760
other than that there's a whole bunch of refactoring work that is in open bz dp f that is

26:14.760 --> 26:20.520
multi in free bz pf although a lot of it has been moved over already so when I said that

26:20.520 --> 26:27.640
there is only one pf you enter pf you get into pf test you used to be pf test and pf test six

26:28.200 --> 26:32.520
those have now been unified in free bz d main and that's something that was imported from open

26:32.520 --> 26:39.080
bz d so I'm in the process of importing patches from open bz d minor bug fixes small new features

26:39.560 --> 26:45.720
but there's still a lot of stuff in open bz d that's small in free bz d yet some of it might never

26:45.720 --> 26:52.840
get into free bz d uh the open bz d people take a little bit more of a liberal attitudes towards

26:52.840 --> 26:59.560
backwards compatibility so they will just change the syntax and then it'll break you know existing rules

26:59.560 --> 27:04.040
that will break and there are good arguments for doing things that way but there are also good

27:04.040 --> 27:07.640
arguments for backwards compatibility and that's kind of a philosophical difference there

27:10.040 --> 27:17.400
next question can you can you comment on the difference between free bz dp f and mp f because

27:17.400 --> 27:26.440
both are kind of as you said working on making the multi core story yeah so can I comment on the

27:26.440 --> 27:34.200
difference the design difference between pf and bz dn pf unfortunately not really I'm not very familiar

27:34.200 --> 27:40.680
with the n pf internals so I can't really tell you I can't say anything meaningful about the

27:40.680 --> 27:49.400
n pf design I just don't know what it is I work your ability really powerful to use the

27:49.400 --> 27:57.000
base tile well that would have to invest so if question is if I want to build a powerful

27:57.320 --> 28:05.000
pf based fire wall what do I invest in so now because my customer is here my obvious answer is

28:05.000 --> 28:11.480
you should just give them money but what you care about well in part you want to fasten it

28:11.480 --> 28:16.120
work cards you know we can we can talk about one gig a bit network cards it doesn't matter

28:16.120 --> 28:21.640
what firewall you use they'll all do it just fine so you want to 1040 100 gig network cards

28:22.040 --> 28:29.080
you'll want multiple cores because pf is actually able to make use of that to some extent you know

28:29.080 --> 28:37.400
there is still contention internal to it but it can do this you want some memory but really it's not

28:37.400 --> 28:43.560
that's insanely much memory if you're buying you know 32 64 gigs of memory it's almost certainly

28:43.560 --> 28:49.880
going to be plenty I don't know the numbers off the top of my head but you can go a long way with 32 gigs of

28:49.880 --> 28:58.680
memory so be on that you know fast individual cores but a sizable number of cores last time I

28:58.680 --> 29:06.600
ran performance numbers I think pf topped out on my hardware in my specific setup something out

29:06.600 --> 29:12.920
in the only order of 18 million packets per second thank you all very much for your attention

29:13.000 --> 29:22.040
and your time but I'm going to be quick out now I'm going to be down at the freebie as

29:22.040 --> 29:28.280
the stand in k so if you have further questions feel free to find me there

