The branch main has been updated by ks:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=ad6562ec858fffbed83560ed3f79375a44be2705

commit ad6562ec858fffbed83560ed3f79375a44be2705
Author:     Kajetan Staszkiewicz <k...@freebsd.org>
AuthorDate: 2024-11-29 22:20:14 +0000
Commit:     Kajetan Staszkiewicz <k...@freebsd.org>
CommitDate: 2024-12-05 22:03:12 +0000

    pf: Don't pfsync states with unrecoverable routing information
    
    States created by route-to rules can't be trusted when received with
    pfsync version 1301 as they lack the rt and rt_kif information. They
    are imported, though, and pf_route() function attempts to recover
    the missing information for every forwarded packet.
    
    Move the recovery operation to pfsync_state_import() so that it's
    performed only once and if it's impossible don't import the state.
    Add an additional check for cases when recovery might produce wrong
    results.
    
    Reviewed by:            kp
    Approved by:            kp (mentor)
    Sponsored by:           InnoGames GmbH
    Differential Revision:  https://reviews.freebsd.org/D47906
---
 sys/netpfil/pf/if_pfsync.c     |  90 ++++++++++++---
 sys/netpfil/pf/pf.c            |  78 ++++---------
 tests/sys/netpfil/pf/pfsync.sh | 256 ++++++++++++++++++++++++++++++++++++-----
 3 files changed, 323 insertions(+), 101 deletions(-)

diff --git a/sys/netpfil/pf/if_pfsync.c b/sys/netpfil/pf/if_pfsync.c
index 8dd3d875dc0b..5923675ff144 100644
--- a/sys/netpfil/pf/if_pfsync.c
+++ b/sys/netpfil/pf/if_pfsync.c
@@ -110,6 +110,8 @@
 
 #include <netpfil/pf/pfsync_nv.h>
 
+#define        DPFPRINTF(n, x) if (V_pf_status.debug >= (n)) printf x
+
 struct pfsync_bucket;
 struct pfsync_softc;
 
@@ -521,10 +523,13 @@ pfsync_state_import(union pfsync_state_union *sp, int 
flags, int msg_version)
 #endif
        struct pfsync_state_key *kw, *ks;
        struct pf_kstate        *st = NULL;
-       struct pf_state_key *skw = NULL, *sks = NULL;
-       struct pf_krule *r = NULL;
-       struct pfi_kkif *kif;
-       int error;
+       struct pf_state_key     *skw = NULL, *sks = NULL;
+       struct pf_krule         *r = NULL;
+       struct pfi_kkif         *kif;
+       struct pfi_kkif         *rt_kif = NULL;
+       struct pf_kpooladdr     *rpool_first;
+       int                      error;
+       uint8_t                  rt = 0;
 
        PF_RULES_RASSERT();
 
@@ -556,6 +561,67 @@ pfsync_state_import(union pfsync_state_union *sp, int 
flags, int msg_version)
        else
                r = &V_pf_default_rule;
 
+       /*
+        * Check routing interface early on. Do it before allocating memory etc.
+        * because there is a high chance there will be a lot more such states.
+        */
+       switch (msg_version) {
+       case PFSYNC_MSG_VERSION_1301:
+               /*
+                * On FreeBSD <= 13 the routing interface and routing operation
+                * are not sent over pfsync. If the ruleset is identical,
+                * though, we might be able to recover the routing information
+                * from the local ruleset.
+                */
+               if (r != &V_pf_default_rule) {
+                       /*
+                        * The ruleset is identical, try to recover. If the rule
+                        * has a redirection pool with a single interface, there
+                        * is a chance that this interface is identical as on
+                        * the pfsync peer. If there's more than one interface,
+                        * give up, as we can't be sure that we will pick the
+                        * same one as the pfsync peer did.
+                        */
+                       rpool_first = TAILQ_FIRST(&(r->rpool.list));
+                       if ((rpool_first == NULL) ||
+                           (TAILQ_NEXT(rpool_first, entries) != NULL)) {
+                               DPFPRINTF(PF_DEBUG_MISC,
+                                   ("%s: can't recover routing information "
+                                   "because of empty or bad redirection 
pool\n",
+                                   __func__));
+                               return ((flags & PFSYNC_SI_IOCTL) ? EINVAL : 0);
+                       }
+                       rt = r->rt;
+                       rt_kif = rpool_first->kif;
+               } else if (!PF_AZERO(&sp->pfs_1301.rt_addr, sp->pfs_1301.af)) {
+                       /*
+                        * Ruleset different, routing *supposedly* requested,
+                        * give up on recovering.
+                        */
+                       DPFPRINTF(PF_DEBUG_MISC,
+                           ("%s: can't recover routing information "
+                           "because of different ruleset\n", __func__));
+                       return ((flags & PFSYNC_SI_IOCTL) ? EINVAL : 0);
+               }
+       break;
+       case PFSYNC_MSG_VERSION_1400:
+               /*
+                * On FreeBSD 14 and above we're not taking any chances.
+                * We use the information synced to us.
+                */
+               if (sp->pfs_1400.rt) {
+                       rt_kif = pfi_kkif_find(sp->pfs_1400.rt_ifname);
+                       if (rt_kif == NULL) {
+                               DPFPRINTF(PF_DEBUG_MISC,
+                                   ("%s: unknown route interface: %s\n",
+                                   __func__, sp->pfs_1400.rt_ifname));
+                               return ((flags & PFSYNC_SI_IOCTL) ? EINVAL : 0);
+                       }
+                       rt = sp->pfs_1400.rt;
+               }
+       break;
+       }
+
        if ((r->max_states &&
            counter_u64_fetch(r->states_cur) >= r->max_states))
                goto cleanup;
@@ -629,6 +695,9 @@ pfsync_state_import(union pfsync_state_union *sp, int 
flags, int msg_version)
        st->act.log = sp->pfs_1301.log;
        st->timeout = sp->pfs_1301.timeout;
 
+       st->act.rt = rt;
+       st->act.rt_kif = rt_kif;
+
        switch (msg_version) {
                case PFSYNC_MSG_VERSION_1301:
                        st->state_flags = sp->pfs_1301.state_flags;
@@ -680,17 +749,6 @@ pfsync_state_import(union pfsync_state_union *sp, int 
flags, int msg_version)
                        st->act.max_mss = ntohs(sp->pfs_1400.max_mss);
                        st->act.set_prio[0] = sp->pfs_1400.set_prio[0];
                        st->act.set_prio[1] = sp->pfs_1400.set_prio[1];
-                       st->act.rt = sp->pfs_1400.rt;
-                       if (st->act.rt && (st->act.rt_kif = 
pfi_kkif_find(sp->pfs_1400.rt_ifname)) == NULL) {
-                               if (V_pf_status.debug >= PF_DEBUG_MISC)
-                                       printf("%s: unknown route interface: 
%s\n",
-                                           __func__, sp->pfs_1400.rt_ifname);
-                               if (flags & PFSYNC_SI_IOCTL)
-                                       error = EINVAL;
-                               else
-                                       error = 0;
-                               goto cleanup_keys;
-                       }
                        break;
                default:
                        panic("%s: Unsupported pfsync_msg_version %d",
@@ -737,7 +795,7 @@ pfsync_state_import(union pfsync_state_union *sp, int 
flags, int msg_version)
 
 cleanup:
        error = ENOMEM;
-cleanup_keys:
+
        if (skw == sks)
                sks = NULL;
        uma_zfree(V_pf_state_key_z, skw);
diff --git a/sys/netpfil/pf/pf.c b/sys/netpfil/pf/pf.c
index 8d9d595dc1ec..a0c9a92c6b84 100644
--- a/sys/netpfil/pf/pf.c
+++ b/sys/netpfil/pf/pf.c
@@ -7690,14 +7690,14 @@ pf_route(struct mbuf **m, struct pf_krule *r, struct 
ifnet *oifp,
        struct mbuf             *m0, *m1, *md;
        struct sockaddr_in      dst;
        struct ip               *ip;
-       struct ifnet            *ifp = NULL;
-       struct pf_addr           naddr;
+       struct ifnet            *ifp;
        int                      error = 0;
        uint16_t                 ip_len, ip_off;
        uint16_t                 tmp;
        int                      r_dir;
 
-       KASSERT(m && *m && r && oifp, ("%s: invalid parameters", __func__));
+       KASSERT(m && *m && r && oifp && pd->act.rt_kif,
+           ("%s: invalid parameters", __func__));
 
        SDT_PROBE4(pf, ip, route_to, entry, *m, pd, s, oifp);
 
@@ -7720,13 +7720,15 @@ pf_route(struct mbuf **m, struct pf_krule *r, struct 
ifnet *oifp,
                goto bad_locked;
        }
 
+       if ((ifp = pd->act.rt_kif->pfik_ifp) == NULL) {
+               m0 = *m;
+               *m = NULL;
+               SDT_PROBE1(pf, ip, route_to, drop, __LINE__);
+               goto bad_locked;
+       }
+
        if (pd->act.rt == PF_DUPTO) {
                if ((pd->pf_mtag->flags & PF_MTAG_FLAG_DUPLICATED)) {
-                       ifp = pd->act.rt_kif ? pd->act.rt_kif->pfik_ifp : NULL;
-                       /* If pfsync'd from FreeBSD < 14 */
-                       if (ifp == NULL && r->rpool.cur != NULL)
-                               ifp = r->rpool.cur->kif ?
-                                   r->rpool.cur->kif->pfik_ifp : NULL;
                        if (s != NULL) {
                                PF_STATE_UNLOCK(s);
                        }
@@ -7764,36 +7766,18 @@ pf_route(struct mbuf **m, struct pf_krule *r, struct 
ifnet *oifp,
        dst.sin_len = sizeof(dst);
        dst.sin_addr = ip->ip_dst;
        dst.sin_addr.s_addr = pd->act.rt_addr.v4.s_addr;
-       ifp = pd->act.rt_kif ? pd->act.rt_kif->pfik_ifp : NULL;
-
-       bzero(&naddr, sizeof(naddr));
 
        if (s != NULL){
-               struct pfi_kkif *kif;
-
-               kif = pd->act.rt_kif;
-               /* If pfsync'd from FreeBSD < 14 */
-               if (ifp == NULL && r->rpool.cur != NULL) {
-                       ifp = r->rpool.cur->kif ?
-                           r->rpool.cur->kif->pfik_ifp : NULL;
-                       kif = r->rpool.cur->kif;
-               }
-               if (ifp != NULL && kif != NULL &&
-                   r->rule_flag & PFRULE_IFBOUND &&
+               if (r->rule_flag & PFRULE_IFBOUND &&
                    pd->act.rt == PF_REPLYTO &&
                    s->kif == V_pfi_all) {
-                       s->kif = kif;
+                       s->kif = pd->act.rt_kif;
                        s->orig_kif = oifp->if_pf_kif;
                }
 
                PF_STATE_UNLOCK(s);
        }
 
-       if (ifp == NULL) {
-               SDT_PROBE1(pf, ip, route_to, drop, __LINE__);
-               goto bad;
-       }
-
        if (pd->dir == PF_IN) {
                if (pf_test(AF_INET, PF_OUT, PFIL_FWD, ifp, &m0, inp,
                    &pd->act) != PF_PASS) {
@@ -7943,10 +7927,10 @@ pf_route6(struct mbuf **m, struct pf_krule *r, struct 
ifnet *oifp,
        struct sockaddr_in6     dst;
        struct ip6_hdr          *ip6;
        struct ifnet            *ifp = NULL;
-       struct pf_addr           naddr;
        int                      r_dir;
 
-       KASSERT(m && *m && r && oifp, ("%s: invalid parameters", __func__));
+       KASSERT(m && *m && r && oifp && pd->act.rt_kif,
+           ("%s: invalid parameters", __func__));
 
        SDT_PROBE4(pf, ip6, route_to, entry, *m, pd, s, oifp);
 
@@ -7969,13 +7953,15 @@ pf_route6(struct mbuf **m, struct pf_krule *r, struct 
ifnet *oifp,
                goto bad_locked;
        }
 
+       if ((ifp = pd->act.rt_kif->pfik_ifp) == NULL) {
+               m0 = *m;
+               *m = NULL;
+               SDT_PROBE1(pf, ip6, route_to, drop, __LINE__);
+               goto bad_locked;
+       }
+
        if (pd->act.rt == PF_DUPTO) {
                if ((pd->pf_mtag->flags & PF_MTAG_FLAG_DUPLICATED)) {
-                       ifp = pd->act.rt_kif ? pd->act.rt_kif->pfik_ifp : NULL;
-                       /* If pfsync'd from FreeBSD < 14 */
-                       if (ifp == NULL && r->rpool.cur != NULL)
-                               ifp = r->rpool.cur->kif ?
-                                   r->rpool.cur->kif->pfik_ifp : NULL;
                        if (s != NULL) {
                                PF_STATE_UNLOCK(s);
                        }
@@ -8013,35 +7999,17 @@ pf_route6(struct mbuf **m, struct pf_krule *r, struct 
ifnet *oifp,
        dst.sin6_len = sizeof(dst);
        dst.sin6_addr = ip6->ip6_dst;
        PF_ACPY((struct pf_addr *)&dst.sin6_addr, &pd->act.rt_addr, AF_INET6);
-       bzero(&naddr, sizeof(naddr));
-       ifp = pd->act.rt_kif ? pd->act.rt_kif->pfik_ifp : NULL;
 
        if (s != NULL) {
-               struct pfi_kkif *kif;
-
-               kif = pd->act.rt_kif;
-               /* If pfsync'd from FreeBSD < 14 */
-               if (ifp == NULL && r->rpool.cur != NULL) {
-                       ifp = r->rpool.cur->kif ?
-                           r->rpool.cur->kif->pfik_ifp : NULL;
-                       kif = r->rpool.cur->kif;
-               }
-               if (ifp != NULL && kif != NULL &&
-                   r->rule_flag & PFRULE_IFBOUND &&
+               if (r->rule_flag & PFRULE_IFBOUND &&
                    pd->act.rt == PF_REPLYTO &&
                    s->kif == V_pfi_all) {
-                       s->kif = kif;
+                       s->kif = pd->act.rt_kif;
                        s->orig_kif = oifp->if_pf_kif;
                }
-
                PF_STATE_UNLOCK(s);
        }
 
-       if (ifp == NULL) {
-               SDT_PROBE1(pf, ip6, route_to, drop, __LINE__);
-               goto bad;
-       }
-
        if (pd->dir == PF_IN) {
                if (pf_test(AF_INET6, PF_OUT, PFIL_FWD | PF_PFIL_NOREFRAGMENT,
                    ifp, &m0, inp, &pd->act) != PF_PASS) {
diff --git a/tests/sys/netpfil/pf/pfsync.sh b/tests/sys/netpfil/pf/pfsync.sh
index b97b06c5f9a2..0f3505460b50 100644
--- a/tests/sys/netpfil/pf/pfsync.sh
+++ b/tests/sys/netpfil/pf/pfsync.sh
@@ -835,16 +835,11 @@ basic_ipv6_cleanup()
        pfsynct_cleanup
 }
 
-atf_test_case "route_to" "cleanup"
-route_to_head()
+route_to_common_head()
 {
-       atf_set descr 'Test route-to with default rule'
-       atf_set require.user root
-       atf_set require.progs scapy
-}
+       pfsync_version=$1
+       shift
 
-route_to_body()
-{
        pfsynct_init
 
        epair_sync=$(vnet_mkepair)
@@ -866,40 +861,111 @@ route_to_body()
        jexec one ifconfig pfsync0 \
                syncdev ${epair_sync}a \
                maxupd 1 \
+               version $pfsync_version \
                up
 
        jexec two ifconfig ${epair_sync}b 192.0.2.2/24 up
        jexec two ifconfig ${epair_two}a 198.51.100.2/24 up
        jexec two ifconfig ${epair_out_two}a 203.0.113.2/24 up
-       #jexec two ifconfig ${epair_out_two}a name outif
+       jexec two ifconfig ${epair_out_two}a name outif
        jexec two sysctl net.inet.ip.forwarding=1
        jexec two arp -s 203.0.113.254 00:01:02:03:04:05
        jexec two ifconfig pfsync0 \
                syncdev ${epair_sync}b \
                maxupd 1 \
+               version $pfsync_version \
                up
 
-       # Enable pf!
+       ifconfig ${epair_one}b 198.51.100.254/24 up
+       ifconfig ${epair_two}b 198.51.100.253/24 up
+       route add -net 203.0.113.0/24 198.51.100.1
+       ifconfig ${epair_two}b up
+       ifconfig ${epair_out_one}b up
+       ifconfig ${epair_out_two}b up
+}
+
+route_to_common_tail()
+{
+       atf_check -s exit:0 env PYTHONPATH=${common_dir} \
+               ${common_dir}/pft_ping.py \
+               --sendif ${epair_one}b \
+               --fromaddr 198.51.100.254 \
+               --to 203.0.113.254 \
+               --recvif ${epair_out_one}b
+
+       # Allow time for sync
+       sleep 2
+
+       states_one=$(mktemp)
+       states_two=$(mktemp)
+       jexec one pfctl -qvvss | normalize_pfctl_s > $states_one
+       jexec two pfctl -qvvss | normalize_pfctl_s > $states_two
+}
+
+atf_test_case "route_to_1301_body" "cleanup"
+route_to_1301_head()
+{
+       atf_set descr 'Test route-to with pfsync version 13.1'
+       atf_set require.user root
+       atf_set require.progs scapy
+}
+
+route_to_1301_body()
+{
+       route_to_common_head 1301
+
        jexec one pfctl -e
        pft_set_rules one \
                "set skip on ${epair_sync}a" \
                "pass out route-to (outif 203.0.113.254)"
+
        jexec two pfctl -e
+       pft_set_rules two \
+               "set skip on ${epair_sync}b" \
+               "pass out route-to (outif 203.0.113.254)"
+
+       route_to_common_tail
 
-       # Make sure we have different rulesets so the synced state is 
associated with
-       # V_pf_default_rule
+       # Sanity check
+       grep -qE 'all icmp 198.51.100.254 -> 203.0.113.254:8 .*, rule 0 .* 
route-to: 203.0.113.254@outif origif: outif' $states_one ||
+               atf_fail "State missing on router one"
+
+       # With identical ruleset the routing information is recovered from the 
matching rule.
+       grep -qE 'all icmp 198.51.100.254 -> 203.0.113.254:8 .*, rule 0 .* 
route-to: 203.0.113.254@outif' $states_two ||
+               atf_fail "State missing on router two"
+
+       true
+}
+
+route_to_1301_cleanup()
+{
+       pfsynct_cleanup
+}
+
+atf_test_case "route_to_1301_bad_ruleset" "cleanup"
+route_to_1301_bad_ruleset_head()
+{
+       atf_set descr 'Test route-to with pfsync version 13.1 and incompatible 
ruleset'
+       atf_set require.user root
+       atf_set require.progs scapy
+}
+
+route_to_1301_bad_ruleset_body()
+{
+       route_to_common_head 1301
+
+       jexec one pfctl -e
+       pft_set_rules one \
+               "set skip on ${epair_sync}a" \
+               "pass out route-to (outif 203.0.113.254)"
+
+       jexec two pfctl -e
        pft_set_rules two \
+               "set debug loud" \
                "set skip on ${epair_sync}b" \
                "pass out route-to (outif 203.0.113.254)" \
                "pass out proto tcp"
 
-       ifconfig ${epair_one}b 198.51.100.254/24 up
-       ifconfig ${epair_two}b 198.51.100.253/24 up
-       route add -net 203.0.113.0/24 198.51.100.1
-       ifconfig ${epair_two}b up
-       ifconfig ${epair_out_one}b up
-       ifconfig ${epair_out_two}b up
-
        atf_check -s exit:0 env PYTHONPATH=${common_dir} \
                ${common_dir}/pft_ping.py \
                --sendif ${epair_one}b \
@@ -907,25 +973,151 @@ route_to_body()
                --to 203.0.113.254 \
                --recvif ${epair_out_one}b
 
-       # Allow time for sync
-       ifconfig ${epair_one}b inet 198.51.100.254 -alias
-       route del -net 203.0.113.0/24 198.51.100.1
-       route add -net 203.0.113.0/24 198.51.100.2
+       route_to_common_tail
 
-       sleep 2
+       # Sanity check
+       grep -qE 'all icmp 198.51.100.254 -> 203.0.113.254:8 .*, rule 0 .* 
route-to: 203.0.113.254@outif origif: outif' $states_one ||
+               atf_fail "State missing on router one"
 
-       # Now try to trigger the state on the other pfsync member
-       env PYTHONPATH=${common_dir} \
+       # Different ruleset on each router means the routing information 
recovery
+       # from rule is impossible. The state is not synced.
+       grep -qE 'all icmp 198.51.100.254 -> 203.0.113.254:8 .*' $states_two &&
+               atf_fail "State present on router two"
+
+       true
+}
+
+route_to_1301_bad_ruleset_cleanup()
+{
+       pfsynct_cleanup
+}
+
+atf_test_case "route_to_1301_bad_rpool" "cleanup"
+route_to_1301_bad_rpool_head()
+{
+       atf_set descr 'Test route-to with pfsync version 13.1 and different 
interface'
+       atf_set require.user root
+       atf_set require.progs scapy
+}
+
+route_to_1301_bad_rpool_body()
+{
+       route_to_common_head 1301
+
+       jexec one pfctl -e
+       pft_set_rules one \
+               "set skip on ${epair_sync}a" \
+               "pass out route-to { (outif 203.0.113.254) (outif 
203.0.113.254) }"
+
+       jexec two pfctl -e
+       pft_set_rules two \
+               "set skip on ${epair_sync}b" \
+               "pass out route-to { (outif 203.0.113.254) (outif 
203.0.113.254) }"
+
+       atf_check -s exit:0 env PYTHONPATH=${common_dir} \
                ${common_dir}/pft_ping.py \
-               --sendif ${epair_two}b \
+               --sendif ${epair_one}b \
                --fromaddr 198.51.100.254 \
                --to 203.0.113.254 \
-               --recvif ${epair_out_two}b
+               --recvif ${epair_out_one}b
+
+       route_to_common_tail
+
+       # Sanity check
+       grep -qE 'all icmp 198.51.100.254 -> 203.0.113.254:8 .*, rule 0 .* 
route-to: 203.0.113.254@outif origif: outif' $states_one ||
+               atf_fail "State missing on router one"
+
+       # The ruleset is identical but since the redirection pool contains 
multiple interfaces
+       # pfsync will not attempt to recover the routing information from the 
rule.
+       grep -qE 'all icmp 198.51.100.254 -> 203.0.113.254:8 .*' $states_two &&
+               atf_fail "State present on router two"
+
+       true
+}
+
+route_to_1301_bad_rpool_cleanup()
+{
+       pfsynct_cleanup
+}
+
+atf_test_case "route_to_1400_bad_ruleset" "cleanup"
+route_to_1400_bad_ruleset_head()
+{
+       atf_set descr 'Test route-to with pfsync version 14.0'
+       atf_set require.user root
+       atf_set require.progs scapy
+}
+
+route_to_1400_bad_ruleset_body()
+{
+       route_to_common_head 1400
+
+       jexec one pfctl -e
+       pft_set_rules one \
+               "set skip on ${epair_sync}a" \
+               "pass out route-to (outif 203.0.113.254)"
+
+       jexec two pfctl -e
+       pft_set_rules two \
+               "set skip on ${epair_sync}b"
+
+       route_to_common_tail
+
+       # Sanity check
+       grep -qE 'all icmp 198.51.100.254 -> 203.0.113.254:8 .*, rule 0 .* 
route-to: 203.0.113.254@outif origif: outif' $states_one ||
+               atf_fail "State missing on router one"
+
+       # Even with a different ruleset FreeBSD 14 syncs the state just fine.
+       # There's no recovery involved, the pfsync packet contains the routing 
information.
+       grep -qE 'all icmp 198.51.100.254 -> 203.0.113.254:8 .* route-to: 
203.0.113.254@outif' $states_two ||
+               atf_fail "State missing on router two"
+
+       true
+}
+
+route_to_1400_bad_ruleset_cleanup()
+{
+       pfsynct_cleanup
+}
+
+atf_test_case "route_to_1400_bad_ifname" "cleanup"
+route_to_1400_bad_ifname_head()
+{
+       atf_set descr 'Test route-to with pfsync version 14.0'
+       atf_set require.user root
+       atf_set require.progs scapy
+}
+
+route_to_1400_bad_ifname_body()
+{
+       route_to_common_head 1400
+
+       jexec one pfctl -e
+       pft_set_rules one \
+               "set skip on ${epair_sync}a" \
+               "pass out route-to (outif 203.0.113.254)"
+
+       jexec two pfctl -e
+       jexec two ifconfig outif name outif_new
+       pft_set_rules two \
+               "set skip on ${epair_sync}b" \
+               "pass out route-to (outif_new 203.0.113.254)"
+
+       route_to_common_tail
+
+       # Sanity check
+       grep -qE 'all icmp 198.51.100.254 -> 203.0.113.254:8 .*, rule 0 .* 
route-to: 203.0.113.254@outif origif: outif' $states_one ||
+               atf_fail "State missing on router one"
+
+       # Since FreeBSD 14 never attempts recovery of missing routing 
information
+       # a state synced to a router with a different interface name is dropped.
+       grep -qE 'all icmp 198.51.100.254 -> 203.0.113.254:8 .*' $states_two &&
+               atf_fail "State present on router two"
 
        true
 }
 
-route_to_cleanup()
+route_to_1400_bad_ifname_cleanup()
 {
        pfsynct_cleanup
 }
@@ -942,5 +1134,9 @@ atf_init_test_cases()
        atf_add_test_case "timeout"
        atf_add_test_case "basic_ipv6_unicast"
        atf_add_test_case "basic_ipv6"
-       atf_add_test_case "route_to"
+       atf_add_test_case "route_to_1301"
+       atf_add_test_case "route_to_1301_bad_ruleset"
+       atf_add_test_case "route_to_1301_bad_rpool"
+       atf_add_test_case "route_to_1400_bad_ruleset"
+       atf_add_test_case "route_to_1400_bad_ifname"
 }

Reply via email to