i think these code chunks are around the wrong way.

pfsync may want to defer the transmission of a packet. it does this so
it can try and get a state over to a peer firewall before a host may
send a reply to the peer, which would get dropped cos there's no
matching state.

i think the once rule processing should happen before that. the state
is created from the rule, whether the packet the state is for goes out
immediately or not shouldn't matter.

ok?

Index: pf.c
===================================================================
RCS file: /cvs/src/sys/net/pf.c,v
retrieving revision 1.1104
diff -u -p -U8 -r1.1104 pf.c
--- pf.c        27 Jan 2021 23:53:35 -0000      1.1104
+++ pf.c        28 Jan 2021 01:43:22 -0000
@@ -3932,45 +3932,45 @@ pf_test_rule(struct pf_pdesc *pd, struct
                }
        }
 
        /* copy back packet headers if needed */
        if (rewrite && pd->hdrlen) {
                m_copyback(pd->m, pd->off, pd->hdrlen, &pd->hdr, M_NOWAIT);
        }
 
-#if NPFSYNC > 0
-       if (*sm != NULL && !ISSET((*sm)->state_flags, PFSTATE_NOSYNC) &&
-           pd->dir == PF_OUT && pfsync_up()) {
-               /*
-                * We want the state created, but we dont
-                * want to send this in case a partner
-                * firewall has to know about it to allow
-                * replies through it.
-                */
-               if (pfsync_defer(*sm, pd->m))
-                       return (PF_DEFER);
-       }
-#endif /* NPFSYNC > 0 */
-
        if (r->rule_flag & PFRULE_ONCE) {
                u_int32_t       rule_flag;
 
                /*
                 * Use atomic_cas() to determine a clear winner, which will
                 * insert an expired rule to gcl.
                 */
                rule_flag = r->rule_flag;
                if (((rule_flag & PFRULE_EXPIRED) == 0) &&
                    atomic_cas_uint(&r->rule_flag, rule_flag,
                        rule_flag | PFRULE_EXPIRED) == rule_flag) {
                        r->exptime = gettime();
                        SLIST_INSERT_HEAD(&pf_rule_gcl, r, gcle);
                }
        }
+
+#if NPFSYNC > 0
+       if (*sm != NULL && !ISSET((*sm)->state_flags, PFSTATE_NOSYNC) &&
+           pd->dir == PF_OUT && pfsync_up()) {
+               /*
+                * We want the state created, but we dont
+                * want to send this in case a partner
+                * firewall has to know about it to allow
+                * replies through it.
+                */
+               if (pfsync_defer(*sm, pd->m))
+                       return (PF_DEFER);
+       }
+#endif /* NPFSYNC > 0 */
 
        return (action);
 
 cleanup:
        while ((ctx.ri = SLIST_FIRST(&ctx.rules))) {
                SLIST_REMOVE_HEAD(&ctx.rules, entry);
                pool_put(&pf_rule_item_pl, ctx.ri);
        }

Reply via email to