Moving the pf rc.d scripts to run before netif

View: New views
6 Messages — Rating Filter:   Alert me  

Moving the pf rc.d scripts to run before netif

by Doug Barton :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Howdy,

As you can see below, I've made a change to the order of execution of
the rc.d scripts in 8-current (soon to be 8-release) to run all of the
firewalls, including pf, before the network is up. However the
following PR gives an example of why this might be bad:

http://www.freebsd.org/cgi/query-pr.cgi?pr=130381

This leaves me with a few questions.

1. When the _kernel_ first starts, what is the condition of the pf
firewall? In other words, you have pf in the kernel, and let's pretend
that there is no rc.d/pf initialization script. What's going to happen
to the packets when the network comes up?

2. The previous rcorder for the pf script was right after netif (the
network coming up) and before routing .... why? Is this related to how
pf does its work? The reason I ask this question is that in order to
fix the IPv6 rcorder problem in the pr the way that Gert is suggesting
the "BEFORE: routing" would have to be removed because our IPv6
startup depends on RA which depends on routing being up. (Side note,
in the long term I'd like to revise this so that an IPv6-only host
and/or a host with statically assigned IPv6 addresses can easily be
configured within rc.d, but that's another thing altogether.)

3. Is the need to be able to use $ext_if after the network is up so
overwhelmingly important that it justifies running pf after netif? Or
is using ($ext_if) a reasonable solution?

Anything else y'all would like to add is welcome at this point.


Thanks,

Doug


-------- Original Message --------
Subject: Re: svn commit: r193198 - head/etc/rc.d
Date: Mon, 01 Jun 2009 10:38:41 -0700
From: Doug Barton <dougb@...>

Bjoern A. Zeeb wrote:

> On Mon, 1 Jun 2009, Doug Barton wrote:
>
>> Author: dougb Date: Mon Jun  1 05:35:03 2009 New Revision: 193198
>>  URL: http://svn.freebsd.org/changeset/base/193198
>>
>> Log: Make the pf and ipfw firewalls start before netif, just like
>>  ipfilter already does. This eliminates a logical inconsistency,
>> and a small window where the system is open after the network
>> comes up.
>
> Unfortunetaly this is contrary to a lot of PRs and requests on
> mailing lists out there that actually want the netif/network_ipv6
> to be run _before_ things come up.

Can you provide links to some of those PRs? I'd love to learn more
about this issue.

> Espescially pf really needs this to avoid rules that needs to do
> per paket lookups of the interface address.

Not sure what you mean here.

> Further ipfw has a default option being setaable at compile time
> and as TUNABLE to handle this window.

And what happens if someone sets the default to accept? You could
argue that they are knowingly opening a window of vulnerability but I
would argue that the right thing to do is to have the firewall rules
loaded before the network comes up regardless of the default. That way
you avoid both the potential window of vulnerability AND the window of
time between the network being loaded and the firewall allowing access
to the box.

To give a little more history, this patch was discussed and reviewed a
while back and someone told me that they would incorporate it into
some overall work they were doing to improve the way that rc.d handles
networking, so I stopped paying attention to it. Last night a user
pointed out to me that another patch that this same person said they
would handle never got in, so I reviewed other outstanding work and
found that this one had not been done either.

Obviously if this change breaks something it will have to be reverted.
However from the security standpoint (primary concern) it would seem
to be the right thing to do, and the previous rcorder was not
logically consistent in any case.

Max Laier wrote:
> Can you please add a note about this in UPDATING?

Yes. I was on the fence about this anyways, so now you've pushed me
over. :)

> It might be a slight POLA violation for people who rely on the
> interfaces being configured to setup the firewall.  For instance
> when one doesn't use dynamic address rules in pf i.e. "from/to ifX"
> instead of "from/to (ifX)".

I don't understand what you've written here. It seems to me that if
the interfaces are always the same then the firewall rules will be
fine, but if they are using dynamic rules it doesn't matter if it
starts before or after the network is up.

Doug


--

    This .signature sanitized for your protection

_______________________________________________
freebsd-pf@... mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-pf
To unsubscribe, send any mail to "freebsd-pf-unsubscribe@..."

Re: Moving the pf rc.d scripts to run before netif

by Max Laier :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On Monday 01 June 2009 20:38:45 Doug Barton wrote:

> Howdy,
>
> As you can see below, I've made a change to the order of execution of
> the rc.d scripts in 8-current (soon to be 8-release) to run all of the
> firewalls, including pf, before the network is up. However the
> following PR gives an example of why this might be bad:
>
> http://www.freebsd.org/cgi/query-pr.cgi?pr=130381
>
> This leaves me with a few questions.
>
> 1. When the _kernel_ first starts, what is the condition of the pf
> firewall? In other words, you have pf in the kernel, and let's pretend
> that there is no rc.d/pf initialization script. What's going to happen
> to the packets when the network comes up?

The default behavior is to pass everything unconditionally.

> 2. The previous rcorder for the pf script was right after netif (the
> network coming up) and before routing .... why? Is this related to how
> pf does its work? The reason I ask this question is that in order to
> fix the IPv6 rcorder problem in the pr the way that Gert is suggesting
> the "BEFORE: routing" would have to be removed because our IPv6
> startup depends on RA which depends on routing being up. (Side note,
> in the long term I'd like to revise this so that an IPv6-only host
> and/or a host with statically assigned IPv6 addresses can easily be
> configured within rc.d, but that's another thing altogether.)
>
> 3. Is the need to be able to use $ext_if after the network is up so
> overwhelmingly important that it justifies running pf after netif? Or
> is using ($ext_if) a reasonable solution?

Traditionally pf has had some issues with startup before netif.  e.g. it
was not possible to configure ALTQ on interfaces before they are created.  
Over the years most of these restrictions have been fixed (though you
still need to specify an absolute bandwidth for ALTQ if you want to
configure non-existing interfaces).  The last remaining issue with non-
existing interfaces is the "set loginterface".

In addition people seem to like to use symbolic hostnames in their pf.conf
for some reason.  It's a bad idea from the security perspective, but who
am I to decide how one shoots oneself?  Symbolic hostnames, as well as
non-dynamic interface statements are evaluated at ruleset load-time in pf.  
Thus the resolver must work when we load a ruleset with rules like that.

> Anything else y'all would like to add is welcome at this point.

It might make sense to have the ability for two points to configure the
firewall.  One "firewall_early" to setup a minimal "block all/allow
dhcp/RA/DNS/..." and "firewall_late" to setup the final thing.

In any case setting up the firewall is a non-trivial task and I doubt that
there really is a good "one size fits all" solution.  I'd prefer your
version over the previous incarnation - as it is secure by default.

--
/"\  Best regards,                      | mlaier@...
\ /  Max Laier                          | ICQ #67774661
 X   http://pf4freebsd.love2party.net/  | mlaier@EFnet
/ \  ASCII Ribbon Campaign              | Against HTML Mail and News

_______________________________________________
freebsd-pf@... mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-pf
To unsubscribe, send any mail to "freebsd-pf-unsubscribe@..."

Re: Moving the pf rc.d scripts to run before netif

by Doug Barton :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Max Laier wrote:

> On Monday 01 June 2009 20:38:45 Doug Barton wrote:
>> Howdy,
>>
>> As you can see below, I've made a change to the order of execution of
>> the rc.d scripts in 8-current (soon to be 8-release) to run all of the
>> firewalls, including pf, before the network is up. However the
>> following PR gives an example of why this might be bad:
>>
>> http://www.freebsd.org/cgi/query-pr.cgi?pr=130381
>>
>> This leaves me with a few questions.
>>
>> 1. When the _kernel_ first starts, what is the condition of the pf
>> firewall? In other words, you have pf in the kernel, and let's pretend
>> that there is no rc.d/pf initialization script. What's going to happen
>> to the packets when the network comes up?
>
> The default behavior is to pass everything unconditionally.

That's what I was afraid of. Traditionally this has been viewed as a
Bad Thing(TM) and I'm surprised that it was ever set up that way to
start with.

>> 2. The previous rcorder for the pf script was right after netif (the
>> network coming up) and before routing .... why? Is this related to how
>> pf does its work? The reason I ask this question is that in order to
>> fix the IPv6 rcorder problem in the pr the way that Gert is suggesting
>> the "BEFORE: routing" would have to be removed because our IPv6
>> startup depends on RA which depends on routing being up. (Side note,
>> in the long term I'd like to revise this so that an IPv6-only host
>> and/or a host with statically assigned IPv6 addresses can easily be
>> configured within rc.d, but that's another thing altogether.)
>>
>> 3. Is the need to be able to use $ext_if after the network is up so
>> overwhelmingly important that it justifies running pf after netif? Or
>> is using ($ext_if) a reasonable solution?
>
> Traditionally pf has had some issues with startup before netif.  e.g. it
> was not possible to configure ALTQ on interfaces before they are created.  
> Over the years most of these restrictions have been fixed (though you
> still need to specify an absolute bandwidth for ALTQ if you want to
> configure non-existing interfaces).  The last remaining issue with non-
> existing interfaces is the "set loginterface".

Ok.

> In addition people seem to like to use symbolic hostnames in their pf.conf
> for some reason.  It's a bad idea from the security perspective, but who
> am I to decide how one shoots oneself?  Symbolic hostnames, as well as
> non-dynamic interface statements are evaluated at ruleset load-time in pf.  
> Thus the resolver must work when we load a ruleset with rules like that.

Well the previous order had pf starting before routing anyway (and
therefore also starting before IPv6, nsswitch, resolv, named, etc.) so
I don't think this would have worked in any case.

>> Anything else y'all would like to add is welcome at this point.
>
> It might make sense to have the ability for two points to configure the
> firewall.  One "firewall_early" to setup a minimal "block all/allow
> dhcp/RA/DNS/..." and "firewall_late" to setup the final thing.

I would definitely be supportive of a pf-late script that runs after
the network is up. I'll even write the thing if someone can tell me
what it needs to have. Would calling "/etc/rc.d/pf reload" do the
right thing? And if this is the best way to handle the problem, how
late should it start? (IOW, what should it REQUIRE to make sure it
will have everything it needs when it is run, and what would it need
to run BEFORE to make sure the system is still as secure as possible?)

> In any case setting up the firewall is a non-trivial task and I doubt that
> there really is a good "one size fits all" solution.  I'd prefer your
> version over the previous incarnation - as it is secure by default.

Thanks for the well-informed response, and the note of support. :)

Doug

--

    This .signature sanitized for your protection

_______________________________________________
freebsd-pf@... mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-pf
To unsubscribe, send any mail to "freebsd-pf-unsubscribe@..."

Re: Moving the pf rc.d scripts to run before netif

by Gert Doering-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hi Doug,

thanks for taking this up - and sorry for not responding more timely.

I can't answer all the questions but might have a yet-unmentioned idea
that could solve all this in one go :-)

On Mon, Jun 01, 2009 at 11:38:45AM -0700, Doug Barton wrote:

> 2. The previous rcorder for the pf script was right after netif (the
> network coming up) and before routing .... why? Is this related to how
> pf does its work? The reason I ask this question is that in order to
> fix the IPv6 rcorder problem in the pr the way that Gert is suggesting
> the "BEFORE: routing" would have to be removed because our IPv6
> startup depends on RA which depends on routing being up. (Side note,
> in the long term I'd like to revise this so that an IPv6-only host
> and/or a host with statically assigned IPv6 addresses can easily be
> configured within rc.d, but that's another thing altogether.)
>
> 3. Is the need to be able to use $ext_if after the network is up so
> overwhelmingly important that it justifies running pf after netif? Or
> is using ($ext_if) a reasonable solution?

Well - let's turn this one around: since we *have* the functionality in
pf(4), let's not cripple it by building a framework that makes using this
functionality effectively impossible.  If I understand Bjoern right, this
is also a performance issue - ($ext_if) needs a per-packet lookup to
get the now-current address, while $ext_if reads the address at pf setup
time.


I can see the arguments for having the firewall initialization right at
the start - to avoid opening an window of opportunity where services are
"up" but the firewall hasn't yet been loaded.


So what about the following approach:

 - split the firewall initialization into two halves

 - the first half is run before any other networking stuff is configured
   and basically sets up a "deny everything incoming" filter (with
   exceptions for IPv6 RD/ND, of course).  

   Optionally this could permit outbound connections (with state), to
   enable things like bgpd to run.

 - after this, run interface configuration, set up routing, ...

 - when all this is finished, load the "real" set of firewall rules,
   which can now (if so desired) safely use $ext_if


gert
--
USENET is *not* the non-clickable part of WWW!
                                                           //www.muc.de/~gert/
Gert Doering - Munich, Germany                             gert@...
fax: +49-89-35655025                        gert@...
_______________________________________________
freebsd-pf@... mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-pf
To unsubscribe, send any mail to "freebsd-pf-unsubscribe@..."

Re: Moving the pf rc.d scripts to run before netif

by Doug Barton :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Gert Doering wrote:

> Hi Doug,
>
> thanks for taking this up - and sorry for not responding more timely.
>
> I can't answer all the questions but might have a yet-unmentioned idea
> that could solve all this in one go :-)
>
> On Mon, Jun 01, 2009 at 11:38:45AM -0700, Doug Barton wrote:
>> 2. The previous rcorder for the pf script was right after netif (the
>> network coming up) and before routing .... why? Is this related to how
>> pf does its work? The reason I ask this question is that in order to
>> fix the IPv6 rcorder problem in the pr the way that Gert is suggesting
>> the "BEFORE: routing" would have to be removed because our IPv6
>> startup depends on RA which depends on routing being up. (Side note,
>> in the long term I'd like to revise this so that an IPv6-only host
>> and/or a host with statically assigned IPv6 addresses can easily be
>> configured within rc.d, but that's another thing altogether.)
>>
>> 3. Is the need to be able to use $ext_if after the network is up so
>> overwhelmingly important that it justifies running pf after netif? Or
>> is using ($ext_if) a reasonable solution?
>
> Well - let's turn this one around: since we *have* the functionality in
> pf(4), let's not cripple it by building a framework that makes using this
> functionality effectively impossible.  If I understand Bjoern right, this
> is also a performance issue - ($ext_if) needs a per-packet lookup to
> get the now-current address, while $ext_if reads the address at pf setup
> time.
>
>
> I can see the arguments for having the firewall initialization right at
> the start - to avoid opening an window of opportunity where services are
> "up" but the firewall hasn't yet been loaded.
>
>
> So what about the following approach:
>
>  - split the firewall initialization into two halves
>
>  - the first half is run before any other networking stuff is configured
>    and basically sets up a "deny everything incoming" filter (with
>    exceptions for IPv6 RD/ND, of course).  
>
>    Optionally this could permit outbound connections (with state), to
>    enable things like bgpd to run.
>
>  - after this, run interface configuration, set up routing, ...
>
>  - when all this is finished, load the "real" set of firewall rules,
>    which can now (if so desired) safely use $ext_if

I already said I support this solution, I'm just waiting for someone
with some real pf knowledge to propose something.

Doug
_______________________________________________
freebsd-pf@... mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-pf
To unsubscribe, send any mail to "freebsd-pf-unsubscribe@..."

Re: Moving the pf rc.d scripts to run before netif

by Maxim Khitrov :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On Mon, Jun 15, 2009 at 3:26 PM, Doug Barton <dougb@...> wrote:

> Gert Doering wrote:
>> Hi Doug,
>>
>> thanks for taking this up - and sorry for not responding more timely.
>>
>> I can't answer all the questions but might have a yet-unmentioned idea
>> that could solve all this in one go :-)
>>
>> On Mon, Jun 01, 2009 at 11:38:45AM -0700, Doug Barton wrote:
>>> 2. The previous rcorder for the pf script was right after netif (the
>>> network coming up) and before routing .... why? Is this related to how
>>> pf does its work? The reason I ask this question is that in order to
>>> fix the IPv6 rcorder problem in the pr the way that Gert is suggesting
>>> the "BEFORE: routing" would have to be removed because our IPv6
>>> startup depends on RA which depends on routing being up. (Side note,
>>> in the long term I'd like to revise this so that an IPv6-only host
>>> and/or a host with statically assigned IPv6 addresses can easily be
>>> configured within rc.d, but that's another thing altogether.)
>>>
>>> 3. Is the need to be able to use $ext_if after the network is up so
>>> overwhelmingly important that it justifies running pf after netif? Or
>>> is using ($ext_if) a reasonable solution?
>>
>> Well - let's turn this one around: since we *have* the functionality in
>> pf(4), let's not cripple it by building a framework that makes using this
>> functionality effectively impossible.  If I understand Bjoern right, this
>> is also a performance issue - ($ext_if) needs a per-packet lookup to
>> get the now-current address, while $ext_if reads the address at pf setup
>> time.
>>
>>
>> I can see the arguments for having the firewall initialization right at
>> the start - to avoid opening an window of opportunity where services are
>> "up" but the firewall hasn't yet been loaded.
>>
>>
>> So what about the following approach:
>>
>>  - split the firewall initialization into two halves
>>
>>  - the first half is run before any other networking stuff is configured
>>    and basically sets up a "deny everything incoming" filter (with
>>    exceptions for IPv6 RD/ND, of course).
>>
>>    Optionally this could permit outbound connections (with state), to
>>    enable things like bgpd to run.
>>
>>  - after this, run interface configuration, set up routing, ...
>>
>>  - when all this is finished, load the "real" set of firewall rules,
>>    which can now (if so desired) safely use $ext_if
>
> I already said I support this solution, I'm just waiting for someone
> with some real pf knowledge to propose something.
>
> Doug

Hello all,

I just ran into this problem of pf start-up order on 7.2. I have a
number of nat and rdr rules that allow people on the outside to access
some internal servers (web, mail, etc.). To avoid having to specify
public and private IPs once in the DNS server, which is on the
internal interface, and a second time in the pf configuration, all of
these rules use host names. During start-up, the DNS server cannot be
reached, so pf.conf is not loaded due to unresolved hostnames.

The solution I used is basically as explained by Gert. It works for
me, but would be much better if someone could commit a more permanent
fix. The idea is to have two separate pf configuration files and rc
scripts. One rc script (I called mine pf_init and put it into
/usr/local/etc/rc.d/ for now) runs instead of the current /etc/rc.d/pf
(before routing is enabled). This script loads /etc/pf.init which
contains the following configuration:

# pf configuration that is loaded before routing
set skip on lo
scrub in
block in

Just a basic filter that has no external dependencies and blocks all
incoming traffic. Outgoing traffic, like DNS queries, would be allowed
by the default pass rule.

The second rc script is a modified version of the current
/etc/rc.d/pf. All I did was change two lines:

--- /usr/src/etc/rc.d/pf        2009-04-14 23:14:26.000000000 -0400
+++ /etc/rc.d/pf        2009-09-15 13:06:07.000000000 -0400
@@ -7,2 +7,2 @@
-# REQUIRE: FILESYSTEMS netif pflog pfsync
-# BEFORE:  routing
+# REQUIRE: FILESYSTEMS netif pflog pfsync named
+# BEFORE:  DAEMON ntpdate

I added named to the REQUIRE list, which in my case is provided by
dnsmasq. This allows the firewall to query ISP and internal DNS
servers before the real pf.conf is loaded. I also wanted pf.conf
loaded before other network-related scripts like ntpdate. Not sure if
there are some other things that need to be included for a more
general solution, but this works for me.

My pf_init script is at the bottom of this message. Feel free to take
any of my work, improve it, and commit to the source tree. You would
need to move pf_init_rules variable, which is currently defined in
pf_init to /etc/defaults/rc.conf. That would allow people to specify a
config to use other than /etc/pf.init.

The only thing I wasn't sure about is if there is a better way to
disable stop and restart rc commands than to set stop_cmd and
restart_cmd to an empty function.  We don't want to use pf_init to
reload or restart the firewall, since that would replace the correct
ruleset with the pre-routing one.

- Max

/usr/local/etc/rc.d/pf_init:
#!/bin/sh
#
# PROVIDE: pf_init
# REQUIRE: FILESYSTEMS netif pflog pfsync
# BEFORE:  routing
# KEYWORD: nojail

. /etc/rc.subr

name="pf_init"
rcvar=`set_rcvar`
load_rc_config "pf"
start_cmd=""
stop_cmd="pf_pass"
restart_cmd="pf_pass"
pf_init_rules="/etc/pf.init"
required_files="$pf_init_rules"
required_modules="pf"

pf_start()
{
        echo "Enabling pf (init)."
        $pf_program -F all > /dev/null 2>&1
        $pf_program -f "$pf_init_rules" $pf_flags
        if ! $pf_program -s info | grep -q "Enabled" ; then
                $pf_program -e
        fi
}

pf_pass()
{
}

run_rc_command "$1"
_______________________________________________
freebsd-pf@... mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-pf
To unsubscribe, send any mail to "freebsd-pf-unsubscribe@..."