Hello,

the issue has been reported by Gianni Kapetanakis month ago [1]. It took
several emails to figure out relayd(8) exists after hosts got disabled
by 'relayctl host dis ...'

The thing is that relayd(8) relies on pf(4) to create persistent
tables (PFR_TFLAG_PERSIST) as relayd requests that:

 47 void
 48 init_tables(struct relayd *env)
 49 {
 ...
 62         TAILQ_FOREACH(rdr, env->sc_rdrs, entry) {
 63                 if (strlcpy(tables[i].pfrt_anchor, RELAYD_ANCHOR "/",
 64                     sizeof(tables[i].pfrt_anchor)) >= PF_ANCHOR_NAME_SIZE)
 65                         goto toolong;
 66                 if (strlcat(tables[i].pfrt_anchor, rdr->conf.name,
 67                     sizeof(tables[i].pfrt_anchor)) >= PF_ANCHOR_NAME_SIZE)
 68                         goto toolong;
 69                 if (strlcpy(tables[i].pfrt_name, rdr->conf.name,
 70                     sizeof(tables[i].pfrt_name)) >=
 71                     sizeof(tables[i].pfrt_name))
 72                         goto toolong;
 73                 tables[i].pfrt_flags |= PFR_TFLAG_PERSIST;
 74                 i++;
 75         }

unfortunately it's not the case as further investigation revealed [2].

the issue can be easily reproduced by pfctl(8) which also creates
persistent tables on behalf of command line:

    pfctl -t foo -T add ...

command above always asks pf(4) to create persistent table, however
pf(4) does not honor persistent flag when <foo> table exists already.
One can verify that using commands as follows:

    ## create 'referenced' table only (table exists but has no active flag)
    # echo 'pass from in <foo> to any' |pfctl -f -
    # pfctl -sT -vg
    ----r-- foo
    # create instance of table <foo> using command line:
    # pfctl -t foo -T add 192.168.1.0/24
    1/1 addresses added.
    # pfctl -sT -vg
    --a-r-- foo
    ## create instance of table <bar>, note the table will get 'p' flag
    # pfctl -t bar -T add 192.168.10.0/24
    1 table created.
    1/1 addresses added.
    # pfctl -sT -vg
    -pa---- bar
    --a-r-- foo

one-liner change to sys/net/pf_table.c fixes that it also works for Gianni
Kapetanakis. I'm also adding tests to regress/sys/net/pf_table/Makefile
to cover it.

On system which runs current the test fails with error as follows:

    pfctl -a regress/ttest -t instance -T add 192.168.1.0/24
    1/1 addresses added.
    pfctl -a regress/ttest -sT -vg | diff table-persist.out -
    1c1
    < -pa-r--       instance        regress/ttest
    ---
    > --a-r--       instance        regress/ttest
    *** Error 1 in . (Makefile:96 'flags')
    FAILED

the failure is expected on system without patch. On system with
patch applied all tests do pass.

OK to commit?

thanks and
regards
sashan


[1] https://marc.info/?t=168811270400005&r=1&w=2

[2] https://marc.info/?l=openbsd-bugs&m=168868165801905&w=2

--------8<---------------8<---------------8<------------------8<--------
diff --git a/sys/net/pf_table.c b/sys/net/pf_table.c
index 6f23a6f795d..c862c804f84 100644
--- a/sys/net/pf_table.c
+++ b/sys/net/pf_table.c
@@ -1565,8 +1565,10 @@ pfr_add_tables(struct pfr_table *tbl, int size, int 
*nadd, int flags)
                        xadd++;
                } else if (!(flags & PFR_FLAG_DUMMY) &&
                    !(p->pfrkt_flags & PFR_TFLAG_ACTIVE)) {
-                       p->pfrkt_nflags = (p->pfrkt_flags &
-                           ~PFR_TFLAG_USRMASK) | PFR_TFLAG_ACTIVE;
+                       p->pfrkt_nflags =
+                           (p->pfrkt_flags & ~PFR_TFLAG_USRMASK) |
+                           (n->pfrkt_flags & PFR_TFLAG_USRMASK) |
+                           PFR_TFLAG_ACTIVE;
                        SLIST_INSERT_HEAD(&changeq, p, pfrkt_workq);
                }
        }
diff --git a/regress/sys/net/pf_table/Makefile 
b/regress/sys/net/pf_table/Makefile
index a71f0190c73..8911e8a1d35 100644
--- a/regress/sys/net/pf_table/Makefile
+++ b/regress/sys/net/pf_table/Makefile
@@ -1,15 +1,26 @@
 #      $OpenBSD: Makefile,v 1.3 2017/07/07 23:15:27 bluhm Exp $
 
-REGRESS_TARGETS=       hit miss cleanup
-CLEANFILES=            stamp-*
+REGRESS_TARGETS=       hit miss cleanup flags
+CLEANFILES=            stamp-* \
+                       pf-reftab.conf          \
+                       pf-instance.conf        \
+                       table-ref.conf          \
+                       table-pgone.out         \
+                       table-persist.out       \
+                       table-ref.out           \
+                       table-refgone.out
+
 
 stamp-setup:
+       ${SUDO} pfctl -a regress/ttest -Fa
        ${SUDO} pfctl -qt __regress_tbl -T add -f ${.CURDIR}/table.in
        date >$@
 
 cleanup:
        rm -f stamp-setup
        ${SUDO} pfctl -qt __regress_tbl -T kill
+       ${SUDO} pfctl -q -a regress/ttest -Fr
+       ${SUDO} pfctl -q -a regress/ttest -qt instance -T kill
 
 hit: stamp-setup
        for i in `cat ${.CURDIR}/table.hit`; do \
@@ -27,6 +38,77 @@ miss: stamp-setup
        done; \
        exit 0
 
-.PHONY: hit miss
+#
+# tables <instance> and <reference> are both referenced by rule only
+#
+pf-instab.conf:
+       @echo 'table <instance> { 192.168.1.0/24 }' > $@
+       @echo 'pass in from <instance> to <reference>' >> $@
+
+#
+# table <instance> is active and referred by rule, table <reference>
+# is referenced only.
+pf-reftab.conf:
+       @echo 'pass in from <instance> to <reference>' > $@
+
+#
+# check persistent flag (p) is gone from table <instance> after
+# we load pf-instab.conf. Deals with case when persistent table <instance>
+# exists before pf-instab.conf gets loaded.
+#
+table-pgone.out:
+       @echo '--a-r--  instance        regress/ttest' > $@
+       @echo '----r--  reference       regress/ttest' >> $@
+
+#
+# verify table <instance> got persistent flag after we
+# run 'pfctl -t instance -T add ...'
+#
+table-persist.out:
+       @echo '-pa-r--  instance        regress/ttest' > $@
+       @echo '----r--  reference       regress/ttest' >> $@
+
+#
+# verify tables <instance> and <reference> are created on behalf of
+# reference by rule after pf-reftab.conf got loaded.
+#
+table-ref.out:
+       @echo '----r--  instance        regress/ttest' > $@
+       @echo '----r--  reference       regress/ttest' >> $@
+
+#
+# verify reference to <instance> table (persistent) is gone
+# after rules got flushed
+#
+table-refgone.out:
+       @echo '-pa----  instance        regress/ttest' > $@
+
+flags: pf-instab.conf pf-reftab.conf table-pgone.out table-persist.out \
+    table-ref.out table-refgone.out
+       @echo 'loading pf-reftab,conf (tables referenced by rules only)'
+       @cat pf-reftab.conf
+       ${SUDO} pfctl -a regress/ttest -f pf-reftab.conf
+       @echo 'tables <reference> and <instance> should both have ----r--'
+       ${SUDO} pfctl -a regress/ttest -sT -vg | diff table-ref.out -
+       @echo 'creating <instance> table on command line, flags should be:'
+       @cat table-persist.out
+       ${SUDO} pfctl -a regress/ttest -t instance -T add 192.168.1.0/24
+       ${SUDO} pfctl -a regress/ttest -sT -vg | diff table-persist.out -
+       @echo 'flushing rules'
+       ${SUDO} pfctl -a regress/ttest -Fr
+       @echo 'table <reference> should be gone, table <instance> should stay'
+       ${SUDO} pfctl -a regress/ttest -sT -vg | diff table-refgone.out -
+       @echo 'loading pf-instab.conf'
+       @cat pf-instab.conf
+       ${SUDO} pfctl -a regress/ttest -f pf-instab.conf
+       @echo 'table <instance> loses -p- flag:'
+       @cat table-pgone.out
+       ${SUDO} pfctl -a regress/ttest -sT -vg | diff table-pgone.out -
+       @echo 'flusing rules, both tables should be gone'
+       ${SUDO} pfctl -a regress/ttest -Fr
+       @echo 'anchor regress/ttest must be gone'
+       ${SUDO} pfctl -a regress/ttest -sr 2>&1 | grep 'pfctl: Anchor does not 
exist'
+
+.PHONY: hit miss flags
 
 .include <bsd.regress.mk>

Reply via email to