Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 20 Mar 2013 14:49:41 +0100
From:      Andreas Longwitz <longwitz@incore.de>
To:        freebsd-pf@freebsd.org
Subject:   Re: [pach] Reloading pf rules   breaks connections on lo0
Message-ID:  <5149BE75.3040308@incore.de>
In-Reply-To: <5134C218.6060701@incore.de>
References:  <5134C218.6060701@incore.de>

next in thread | previous in thread | raw e-mail | index | archive | help
Am 04.03.2013 16:47, schrieb Andreas Longwitz:
> I run FreeBSD 8 Stable with pf enabled and have the line
>      set skip on lo0
> in my /etc/pf.conf. Reloading the pf rules with
>      pfctl -f /etc/pf.conf
> breaks any active running connections on lo0.
>
> Example:
> -> scp bigfile 127.0.0.1:bigfile.copy
> bigfile                                      10%   96MB  10.5MB/s
> 01:15 ETA
> Write failed: Operation not permitted
> lost connection
>
> In pflog I see
> 15:33:37.310320    127.0.0.1 -> 127.0.0.1   TCP 164 [block lo0/0]
>    ssh > 52650 [PSH, ACK] Seq=1 Ack=1 Win=8960 Len=48
> 15:33:37.310732    127.0.0.1 -> 127.0.0.1    TCP 14452 [block lo0/0]
>    52650 > ssh [ACK] Seq=1 Ack=1 Win=8960 Len=14336
> 15:33:37.311153    127.0.0.1 -> 127.0.0.1    TCP 2212 [block lo0/0]
>    52650 > ssh [FIN, PSH, ACK] Seq=14337 Ack=1 Win=8960 Len=2096
> 15:33:37.314473    127.0.0.1 -> 127.0.0.1    TCP 116 [block lo0/0]
>    ssh > 52650 [FIN, ACK] Seq=49 Ack=1 Win=8960 Len=0
>
> I can avoid the break on active connections on lo0 using the commands
>     pfctl -d
>     pfctl -f /etc/pf.conf
>     pfctl -e
> but this may break other things and is not what I want.
>
>  From man pf.conf "set skip on .."
> Packets passing in or out on such interfaces are passed as if pf was
> disabled, i.e. pf does not process them in any way.
>
> I think this should be true for reloading the rules too.
>
>
This problem is caused by the way pfctl -f works: In a first step the 
kernel is requested to clear all interface flags, therefore the kernel 
does not respect an old skip lo0 rule anymore. In a second step the new 
file pf.conf - with skip lo0 included - is loaded in the kernel. So 
there is a short time window between step 1 and step 2 without any 
active skip rule in the kernel. A running socket on lo0 will break 
immediately. This behavior of pfctl is well known, see kern/166336.

To get rid of the problem I use the following patch for pfctl. The patch 
executes the first step only if a new option c (=clearifflag) is given. 
Therefore a simple pfctl -f /etc/pf.conf does not break running 
connections on lo0 anymore.

--- pfctl_parser.h.orig 2013-01-14 15:17:48.000000000 +0100
+++ pfctl_parser.h      2013-03-19 18:22:39.000000000 +0100
@@ -51,6 +51,7 @@
  #define PF_OPT_NUMERIC         0x1000
  #define PF_OPT_MERGE           0x2000
  #define PF_OPT_RECURSE         0x4000
+#define PF_OPT_CLRIFFLAG       0x10000

  #define PF_TH_ALL              0xFF

--- pfctl.c.orig        2013-01-14 15:17:48.000000000 +0100
+++ pfctl.c             2013-03-19 18:40:02.000000000 +0100
@@ -235,7 +235,7 @@
  {
      extern char *__progname;

-    fprintf(stderr, "usage: %s [-AdeghmNnOPqRrvz] ", __progname);
+    fprintf(stderr, "usage: %s [-AcdeghmNnOPqRrvz] ", __progname);
      fprintf(stderr, "[-a anchor] [-D macro=value] [-F modifier]\n");
      fprintf(stderr, "\t[-f file] [-i interface] [-K host | network] ");
      fprintf(stderr, "[-k host | network ]\n");
@@ -301,7 +301,8 @@
  {
         struct pfioc_iface      pi;

-       if ((opts & PF_OPT_NOACTION) == 0) {
+       if (((opts & PF_OPT_NOACTION) == 0) &&
+           ((opts & PF_OPT_CLRIFFLAG) != 0)) {
                 bzero(&pi, sizeof(pi));
                 pi.pfiio_flags = PFI_IFLAG_SKIP;

@@ -1980,11 +1981,14 @@
                 usage();

         while ((ch = getopt(argc, argv,
-           "a:AdD:eqf:F:ghi:k:K:mnNOo::Pp:rRs:t:T:vx:z")) != -1) {
+           "a:AcdD:eqf:F:ghi:k:K:mnNOo::Pp:rRs:t:T:vx:z")) != -1) {
                 switch (ch) {
                 case 'a':
                         anchoropt = optarg;
                         break;
+               case 'c':
+                       opts |= PF_OPT_CLRIFFLAG;
+                       break;
                 case 'd':
                         opts |= PF_OPT_DISABLE;
                         mode = O_RDWR;

A better solution for the skip-problem requires assistence of the 
kernel. With a function pfctl_get_interface_flags() pfctl could show the 
active skip interfaces (not possible now) and realize a one shot 
solution for reloading all rules.

Andreas Longwitz



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?5149BE75.3040308>