When divert-reply is used, keep some pf states after pcb is dropped if
authoryasuoka <yasuoka@openbsd.org>
Sat, 3 Sep 2022 14:57:54 +0000 (14:57 +0000)
committeryasuoka <yasuoka@openbsd.org>
Sat, 3 Sep 2022 14:57:54 +0000 (14:57 +0000)
its local address is translated, to prevent its source port from being
reused.  regress test by blumn.

ok blumn

sys/net/pf.c
sys/net/pfvar.h

index 81a53fe..fd36dbd 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: pf.c,v 1.1138 2022/08/30 11:53:03 bluhm Exp $ */
+/*     $OpenBSD: pf.c,v 1.1139 2022/09/03 14:57:54 yasuoka Exp $ */
 
 /*
  * Copyright (c) 2001 Daniel Hartmeier
@@ -1148,6 +1148,8 @@ pf_find_state(struct pf_pdesc *pd, struct pf_state_key_cmp *key,
 
        if (s == NULL)
                return (PF_DROP);
+       if (ISSET(s->state_flags, PFSTATE_INP_UNLINKED))
+               return (PF_DROP);
 
        if (s->rule.ptr->pktrate.limit && pd->dir == s->direction) {
                pf_add_threshold(&s->rule.ptr->pktrate);
@@ -1461,7 +1463,23 @@ pf_remove_divert_state(struct pf_state_key *sk)
                if (sk == si->s->key[PF_SK_STACK] && si->s->rule.ptr &&
                    (si->s->rule.ptr->divert.type == PF_DIVERT_TO ||
                    si->s->rule.ptr->divert.type == PF_DIVERT_REPLY)) {
-                       pf_remove_state(si->s);
+                       if (si->s->key[PF_SK_STACK]->proto == IPPROTO_TCP &&
+                           si->s->key[PF_SK_WIRE] != si->s->key[PF_SK_STACK]) {
+                               /*
+                                * If the local address is translated, keep
+                                * the state for "tcp.closed" seconds to
+                                * prevent its source port from being reused.
+                                */
+                               if (si->s->src.state < TCPS_FIN_WAIT_2 ||
+                                   si->s->dst.state < TCPS_FIN_WAIT_2) {
+                                       pf_set_protostate(si->s, PF_PEER_BOTH,
+                                           TCPS_TIME_WAIT);
+                                       si->s->timeout = PFTM_TCP_CLOSED;
+                                       si->s->expire = getuptime();
+                               }
+                               si->s->state_flags |= PFSTATE_INP_UNLINKED;
+                       } else
+                               pf_remove_state(si->s);
                        break;
                }
        }
index 6f88ff6..174eef3 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: pfvar.h,v 1.509 2022/07/20 09:33:11 mbuhl Exp $ */
+/*     $OpenBSD: pfvar.h,v 1.510 2022/09/03 14:57:54 yasuoka Exp $ */
 
 /*
  * Copyright (c) 2001 Daniel Hartmeier
@@ -784,6 +784,7 @@ struct pf_state {
 #define        PFSTATE_RANDOMID        0x0080
 #define        PFSTATE_SCRUB_TCP       0x0100
 #define        PFSTATE_SETPRIO         0x0200
+#define        PFSTATE_INP_UNLINKED    0x0400
 #define        PFSTATE_SCRUBMASK (PFSTATE_NODF|PFSTATE_RANDOMID|PFSTATE_SCRUB_TCP)
 #define        PFSTATE_SETMASK   (PFSTATE_SETTOS|PFSTATE_SETPRIO)
        u_int8_t                 log;