Date: Thu, 27 Feb 2025 15:33:55 GMT From: Kajetan Staszkiewicz <ks@FreeBSD.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org Subject: git: f6f116cdbd2a - main - pf: Make af-to work on outbound interface Message-ID: <202502271533.51RFXtl7065945@gitrepo.freebsd.org>
next in thread | raw e-mail | index | archive | help
The branch main has been updated by ks: URL: https://cgit.FreeBSD.org/src/commit/?id=f6f116cdbd2a406d2913df5368299ba4cdbf40a1 commit f6f116cdbd2a406d2913df5368299ba4cdbf40a1 Author: Kajetan Staszkiewicz <ks@FreeBSD.org> AuthorDate: 2025-02-23 18:13:48 +0000 Commit: Kajetan Staszkiewicz <ks@FreeBSD.org> CommitDate: 2025-02-27 15:28:27 +0000 pf: Make af-to work on outbound interface Currently af-to works only on inbound interface by creating a reversed NAT state key which is used to match traffic returning on the outbound interface. Such limitation is not necessary. When an af-to state is created for an outbound rule do not reverse the NAT state key, making it work just like if it was created for a normal NAT rule. Depending on firewall design it might be easier and more natural to use af-to on the outbound interface. Reviewed by: kp Approved by: kp (mentor) Sponsored by: InnoGames GmbH Differential Revision: https://reviews.freebsd.org/D49122 --- sys/net/pfvar.h | 7 +- sys/netpfil/pf/pf.c | 245 +++++++++++++++++++++++------------------ sys/netpfil/pf/pf_lb.c | 42 ++----- tests/sys/netpfil/pf/nat64.sh | 247 +++++++++++++++++++++++++++++++++++------- 4 files changed, 368 insertions(+), 173 deletions(-) diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h index b481f767725d..b9b7f71c07d1 100644 --- a/sys/net/pfvar.h +++ b/sys/net/pfvar.h @@ -1005,9 +1005,10 @@ struct pf_state_key { TAILQ_HEAD(, pf_kstate) states[2]; }; -#define PF_REVERSED_KEY(key, family) \ - ((key[PF_SK_WIRE]->af != key[PF_SK_STACK]->af) && \ - (key[PF_SK_WIRE]->af != (family))) +#define PF_REVERSED_KEY(state, family) \ + (((state)->key[PF_SK_WIRE]->af != (state)->key[PF_SK_STACK]->af) && \ + ((state)->key[PF_SK_WIRE]->af != (family)) && \ + ((state)->direction == PF_IN)) /* Keep synced with struct pf_kstate. */ struct pf_state_cmp { diff --git a/sys/netpfil/pf/pf.c b/sys/netpfil/pf/pf.c index 24ddf75936de..72e648b84b2f 100644 --- a/sys/netpfil/pf/pf.c +++ b/sys/netpfil/pf/pf.c @@ -351,9 +351,13 @@ static int pf_create_state(struct pf_krule *, struct pf_krule *, static int pf_state_key_addr_setup(struct pf_pdesc *, struct pf_state_key_cmp *, int); static int pf_tcp_track_full(struct pf_kstate **, - struct pf_pdesc *, u_short *, int *); + struct pf_pdesc *, u_short *, int *, + struct pf_state_peer *, struct pf_state_peer *, + u_int8_t, u_int8_t); static int pf_tcp_track_sloppy(struct pf_kstate **, - struct pf_pdesc *, u_short *); + struct pf_pdesc *, u_short *, + struct pf_state_peer *, struct pf_state_peer *, + u_int8_t, u_int8_t); static int pf_test_state(struct pf_kstate **, struct pf_pdesc *, u_short *); int pf_icmp_state_lookup(struct pf_state_key_cmp *, @@ -458,7 +462,7 @@ BOUND_IFACE(struct pf_kstate *st, struct pf_pdesc *pd) * Initially set to all, because we don't know what interface we'll be * sending this out when we create the state. */ - if (st->rule->rt == PF_REPLYTO || (pd->af != pd->naf)) + if (st->rule->rt == PF_REPLYTO || (pd->af != pd->naf && st->direction == PF_IN)) return (V_pfi_all); /* @@ -1739,11 +1743,18 @@ pf_state_key_setup(struct pf_pdesc *pd, u_int16_t sport, u_int16_t dport, */ bzero(&(*nk)->addr[0], sizeof((*nk)->addr[0])); bzero(&(*nk)->addr[1], sizeof((*nk)->addr[1])); + if (pd->dir == PF_IN) { + PF_ACPY(&(*nk)->addr[pd->didx], &pd->nsaddr, pd->naf); + PF_ACPY(&(*nk)->addr[pd->sidx], &pd->ndaddr, pd->naf); + (*nk)->port[pd->didx] = pd->nsport; + (*nk)->port[pd->sidx] = pd->ndport; + } else { + PF_ACPY(&(*nk)->addr[pd->sidx], &pd->nsaddr, pd->naf); + PF_ACPY(&(*nk)->addr[pd->didx], &pd->ndaddr, pd->naf); + (*nk)->port[pd->sidx] = pd->nsport; + (*nk)->port[pd->didx] = pd->ndport; + } - PF_ACPY(&(*nk)->addr[pd->didx], &pd->nsaddr, pd->naf); - PF_ACPY(&(*nk)->addr[pd->sidx], &pd->ndaddr, pd->naf); - (*nk)->port[pd->didx] = pd->nsport; - (*nk)->port[pd->sidx] = pd->ndport; switch (pd->proto) { case IPPROTO_ICMP: (*nk)->proto = IPPROTO_ICMPV6; @@ -5934,24 +5945,25 @@ nextrule: nat64 = pd->af != pd->naf; if (nat64) { - struct pf_state_key *_sk; int ret; if (sk == NULL) sk = (*sm)->key[pd->dir == PF_IN ? PF_SK_STACK : PF_SK_WIRE]; if (nk == NULL) nk = (*sm)->key[pd->dir == PF_IN ? PF_SK_WIRE : PF_SK_STACK]; - if (pd->dir == PF_IN) - _sk = sk; - else - _sk = nk; - - ret = pf_translate(pd, - &_sk->addr[pd->didx], - _sk->port[pd->didx], - &_sk->addr[pd->sidx], - _sk->port[pd->sidx], - virtual_type, icmp_dir); + + if (pd->dir == PF_IN) { + ret = pf_translate(pd, &sk->addr[pd->didx], + sk->port[pd->didx], &sk->addr[pd->sidx], + sk->port[pd->sidx], virtual_type, + icmp_dir); + } else { + ret = pf_translate(pd, &sk->addr[pd->sidx], + sk->port[pd->sidx], &sk->addr[pd->didx], + sk->port[pd->didx], virtual_type, + icmp_dir); + } + if (ret < 0) goto cleanup; @@ -6383,37 +6395,15 @@ pf_translate(struct pf_pdesc *pd, struct pf_addr *saddr, u_int16_t sport, static int pf_tcp_track_full(struct pf_kstate **state, struct pf_pdesc *pd, - u_short *reason, int *copyback) + u_short *reason, int *copyback, struct pf_state_peer *src, + struct pf_state_peer *dst, u_int8_t psrc, u_int8_t pdst) { struct tcphdr *th = &pd->hdr.tcp; - struct pf_state_peer *src, *dst; u_int16_t win = ntohs(th->th_win); u_int32_t ack, end, data_end, seq, orig_seq; - u_int8_t sws, dws, psrc, pdst; + u_int8_t sws, dws; int ackskew; - if (pd->dir == (*state)->direction) { - if (PF_REVERSED_KEY((*state)->key, pd->af)) { - src = &(*state)->dst; - dst = &(*state)->src; - } else { - src = &(*state)->src; - dst = &(*state)->dst; - } - psrc = PF_PEER_SRC; - pdst = PF_PEER_DST; - } else { - if (PF_REVERSED_KEY((*state)->key, pd->af)) { - src = &(*state)->src; - dst = &(*state)->dst; - } else { - src = &(*state)->dst; - dst = &(*state)->src; - } - psrc = PF_PEER_DST; - pdst = PF_PEER_SRC; - } - if (src->wscale && dst->wscale && !(tcp_get_flags(th) & TH_SYN)) { sws = src->wscale & PF_WSCALE_MASK; dws = dst->wscale & PF_WSCALE_MASK; @@ -6733,23 +6723,11 @@ pf_tcp_track_full(struct pf_kstate **state, struct pf_pdesc *pd, } static int -pf_tcp_track_sloppy(struct pf_kstate **state, struct pf_pdesc *pd, u_short *reason) +pf_tcp_track_sloppy(struct pf_kstate **state, struct pf_pdesc *pd, + u_short *reason, struct pf_state_peer *src, struct pf_state_peer *dst, + u_int8_t psrc, u_int8_t pdst) { struct tcphdr *th = &pd->hdr.tcp; - struct pf_state_peer *src, *dst; - u_int8_t psrc, pdst; - - if (pd->dir == (*state)->direction) { - src = &(*state)->src; - dst = &(*state)->dst; - psrc = PF_PEER_SRC; - pdst = PF_PEER_DST; - } else { - src = &(*state)->dst; - dst = &(*state)->src; - psrc = PF_PEER_DST; - pdst = PF_PEER_SRC; - } if (tcp_get_flags(th) & TH_SYN) if (src->state < TCPS_SYN_SENT) @@ -6932,15 +6910,29 @@ pf_test_state(struct pf_kstate **state, struct pf_pdesc *pd, u_short *reason) STATE_LOOKUP(&key, *state, pd); if (pd->dir == (*state)->direction) { - src = &(*state)->src; - dst = &(*state)->dst; - psrc = PF_PEER_SRC; - pdst = PF_PEER_DST; + if (PF_REVERSED_KEY(*state, pd->af)) { + src = &(*state)->dst; + dst = &(*state)->src; + psrc = PF_PEER_DST; + pdst = PF_PEER_SRC; + } else { + src = &(*state)->src; + dst = &(*state)->dst; + psrc = PF_PEER_SRC; + pdst = PF_PEER_DST; + } } else { - src = &(*state)->dst; - dst = &(*state)->src; - psrc = PF_PEER_DST; - pdst = PF_PEER_SRC; + if (PF_REVERSED_KEY(*state, pd->af)) { + src = &(*state)->src; + dst = &(*state)->dst; + psrc = PF_PEER_SRC; + pdst = PF_PEER_DST; + } else { + src = &(*state)->dst; + dst = &(*state)->src; + psrc = PF_PEER_DST; + pdst = PF_PEER_SRC; + } } switch (pd->virtual_proto) { @@ -6967,13 +6959,14 @@ pf_test_state(struct pf_kstate **state, struct pf_pdesc *pd, u_short *reason) return (PF_DROP); } if ((*state)->state_flags & PFSTATE_SLOPPY) { - if (pf_tcp_track_sloppy(state, pd, reason) == PF_DROP) + if (pf_tcp_track_sloppy(state, pd, reason, src, dst, + psrc, pdst) == PF_DROP) return (PF_DROP); } else { int ret; ret = pf_tcp_track_full(state, pd, reason, - ©back); + ©back, src, dst, psrc, pdst); if (ret == PF_DROP) return (PF_DROP); } @@ -7069,26 +7062,32 @@ pf_test_state(struct pf_kstate **state, struct pf_pdesc *pd, u_short *reason) struct pf_state_key *nk; int afto, sidx, didx; - if (PF_REVERSED_KEY((*state)->key, pd->af)) + if (PF_REVERSED_KEY(*state, pd->af)) nk = (*state)->key[pd->sidx]; else nk = (*state)->key[pd->didx]; afto = pd->af != nk->af; - sidx = afto ? pd->didx : pd->sidx; - didx = afto ? pd->sidx : pd->didx; + + if (afto && (*state)->direction == PF_IN) { + sidx = pd->didx; + didx = pd->sidx; + } else { + sidx = pd->sidx; + didx = pd->didx; + } if (afto || PF_ANEQ(pd->src, &nk->addr[sidx], pd->af) || nk->port[sidx] != pd->osport) pf_change_ap(pd->m, pd->src, pd->sport, pd->ip_sum, - pd->pcksum, &nk->addr[pd->sidx], + pd->pcksum, &nk->addr[sidx], nk->port[sidx], pd->virtual_proto == IPPROTO_UDP, pd->af, nk->af); if (afto || PF_ANEQ(pd->dst, &nk->addr[didx], pd->af) || nk->port[didx] != pd->odport) pf_change_ap(pd->m, pd->dst, pd->dport, pd->ip_sum, - pd->pcksum, &nk->addr[pd->didx], + pd->pcksum, &nk->addr[didx], nk->port[didx], pd->virtual_proto == IPPROTO_UDP, pd->af, nk->af); @@ -7114,12 +7113,12 @@ pf_sctp_track(struct pf_kstate *state, struct pf_pdesc *pd, { struct pf_state_peer *src; if (pd->dir == state->direction) { - if (PF_REVERSED_KEY(state->key, pd->af)) + if (PF_REVERSED_KEY(state, pd->af)) src = &state->dst; else src = &state->src; } else { - if (PF_REVERSED_KEY(state->key, pd->af)) + if (PF_REVERSED_KEY(state, pd->af)) src = &state->src; else src = &state->dst; @@ -7679,15 +7678,21 @@ pf_test_state_icmp(struct pf_kstate **state, struct pf_pdesc *pd, struct pf_state_key *nk; int afto, sidx, didx; - if (PF_REVERSED_KEY((*state)->key, pd->af)) + if (PF_REVERSED_KEY(*state, pd->af)) nk = (*state)->key[pd->sidx]; else nk = (*state)->key[pd->didx]; afto = pd->af != nk->af; - sidx = afto ? pd->didx : pd->sidx; - didx = afto ? pd->sidx : pd->didx; - iidx = afto ? !iidx : iidx; + + if (afto && (*state)->direction == PF_IN) { + sidx = pd->didx; + didx = pd->sidx; + iidx = !iidx; + } else { + sidx = pd->sidx; + didx = pd->didx; + } switch (pd->af) { #ifdef INET @@ -7894,7 +7899,7 @@ pf_test_state_icmp(struct pf_kstate **state, struct pf_pdesc *pd, STATE_LOOKUP(&key, *state, pd); if (pd->dir == (*state)->direction) { - if (PF_REVERSED_KEY((*state)->key, pd->af)) { + if (PF_REVERSED_KEY(*state, pd->af)) { src = &(*state)->src; dst = &(*state)->dst; } else { @@ -7902,7 +7907,7 @@ pf_test_state_icmp(struct pf_kstate **state, struct pf_pdesc *pd, dst = &(*state)->src; } } else { - if (PF_REVERSED_KEY((*state)->key, pd->af)) { + if (PF_REVERSED_KEY(*state, pd->af)) { src = &(*state)->dst; dst = &(*state)->src; } else { @@ -7958,7 +7963,7 @@ pf_test_state_icmp(struct pf_kstate **state, struct pf_pdesc *pd, struct pf_state_key *nk; - if (PF_REVERSED_KEY((*state)->key, pd->af)) + if (PF_REVERSED_KEY(*state, pd->af)) nk = (*state)->key[pd->sidx]; else nk = (*state)->key[pd->didx]; @@ -7967,8 +7972,14 @@ pf_test_state_icmp(struct pf_kstate **state, struct pf_pdesc *pd, int afto, sidx, didx; afto = pd->af != nk->af; - sidx = afto ? pd2.didx : pd2.sidx; - didx = afto ? pd2.sidx : pd2.didx; + + if (afto && (*state)->direction == PF_IN) { + sidx = pd2.didx; + didx = pd2.sidx; + } else { + sidx = pd2.sidx; + didx = pd2.didx; + } if (afto) { if (pf_translate_icmp_af(nk->af, @@ -8073,7 +8084,7 @@ pf_test_state_icmp(struct pf_kstate **state, struct pf_pdesc *pd, (*state)->key[PF_SK_STACK]) { struct pf_state_key *nk; - if (PF_REVERSED_KEY((*state)->key, pd->af)) + if (PF_REVERSED_KEY(*state, pd->af)) nk = (*state)->key[pd->sidx]; else nk = (*state)->key[pd->didx]; @@ -8082,8 +8093,14 @@ pf_test_state_icmp(struct pf_kstate **state, struct pf_pdesc *pd, int afto, sidx, didx; afto = pd->af != nk->af; - sidx = afto ? pd2.didx : pd2.sidx; - didx = afto ? pd2.sidx : pd2.didx; + + if (afto && (*state)->direction == PF_IN) { + sidx = pd2.didx; + didx = pd2.sidx; + } else { + sidx = pd2.sidx; + didx = pd2.didx; + } if (afto) { if (pf_translate_icmp_af(nk->af, @@ -8183,12 +8200,12 @@ pf_test_state_icmp(struct pf_kstate **state, struct pf_pdesc *pd, STATE_LOOKUP(&key, *state, pd); if (pd->dir == (*state)->direction) { - if (PF_REVERSED_KEY((*state)->key, pd->af)) + if (PF_REVERSED_KEY(*state, pd->af)) src = &(*state)->src; else src = &(*state)->dst; } else { - if (PF_REVERSED_KEY((*state)->key, pd->af)) + if (PF_REVERSED_KEY(*state, pd->af)) src = &(*state)->dst; else src = &(*state)->src; @@ -8207,7 +8224,7 @@ pf_test_state_icmp(struct pf_kstate **state, struct pf_pdesc *pd, struct pf_state_key *nk; - if (PF_REVERSED_KEY((*state)->key, pd->af)) + if (PF_REVERSED_KEY(*state, pd->af)) nk = (*state)->key[pd->sidx]; else nk = (*state)->key[pd->didx]; @@ -8216,8 +8233,14 @@ pf_test_state_icmp(struct pf_kstate **state, struct pf_pdesc *pd, int afto, sidx, didx; afto = pd->af != nk->af; - sidx = afto ? pd2.didx : pd2.sidx; - didx = afto ? pd2.sidx : pd2.didx; + + if (afto && (*state)->direction == PF_IN) { + sidx = pd2.didx; + didx = pd2.sidx; + } else { + sidx = pd2.sidx; + didx = pd2.didx; + } if (afto) { if (pf_translate_icmp_af(nk->af, @@ -8325,7 +8348,7 @@ pf_test_state_icmp(struct pf_kstate **state, struct pf_pdesc *pd, (*state)->key[PF_SK_STACK]) { struct pf_state_key *nk; - if (PF_REVERSED_KEY((*state)->key, pd->af)) + if (PF_REVERSED_KEY(*state, pd->af)) nk = (*state)->key[pd->sidx]; else nk = (*state)->key[pd->didx]; @@ -8334,9 +8357,15 @@ pf_test_state_icmp(struct pf_kstate **state, struct pf_pdesc *pd, int afto, sidx, didx; afto = pd->af != nk->af; - sidx = afto ? pd2.didx : pd2.sidx; - didx = afto ? pd2.sidx : pd2.didx; - iidx = afto ? !iidx : iidx; + + if (afto && (*state)->direction == PF_IN) { + sidx = pd2.didx; + didx = pd2.sidx; + iidx = !iidx; + } else { + sidx = pd2.sidx; + didx = pd2.didx; + } if (afto) { if (nk->af != AF_INET6) @@ -8437,7 +8466,7 @@ pf_test_state_icmp(struct pf_kstate **state, struct pf_pdesc *pd, (*state)->key[PF_SK_STACK]) { struct pf_state_key *nk; - if (PF_REVERSED_KEY((*state)->key, pd->af)) + if (PF_REVERSED_KEY(*state, pd->af)) nk = (*state)->key[pd->sidx]; else nk = (*state)->key[pd->didx]; @@ -8446,9 +8475,15 @@ pf_test_state_icmp(struct pf_kstate **state, struct pf_pdesc *pd, int afto, sidx, didx; afto = pd->af != nk->af; - sidx = afto ? pd2.didx : pd2.sidx; - didx = afto ? pd2.sidx : pd2.didx; - iidx = afto ? !iidx : iidx; + + if (afto && (*state)->direction == PF_IN) { + sidx = pd2.didx; + didx = pd2.sidx; + iidx = !iidx; + } else { + sidx = pd2.sidx; + didx = pd2.didx; + } if (afto) { if (nk->af != AF_INET) @@ -8732,7 +8767,9 @@ pf_route(struct mbuf **m, struct pf_krule *r, struct ifnet *oifp, PF_STATE_UNLOCK(s); return; } else { - skip_test = true; + if (r_dir == PF_IN) { + skip_test = true; + } } } @@ -9014,7 +9051,9 @@ pf_route6(struct mbuf **m, struct pf_krule *r, struct ifnet *oifp, PF_STATE_UNLOCK(s); return; } else { - skip_test = true; + if (r_dir == PF_IN) { + skip_test = true; + } } } diff --git a/sys/netpfil/pf/pf_lb.c b/sys/netpfil/pf/pf_lb.c index d1ba2495dc30..cb1d7af258f3 100644 --- a/sys/netpfil/pf/pf_lb.c +++ b/sys/netpfil/pf/pf_lb.c @@ -1053,37 +1053,19 @@ pf_get_transaddr_af(struct pf_krule *r, struct pf_pdesc *pd) } if (pd->proto == IPPROTO_ICMPV6 && pd->naf == AF_INET) { - if (pd->dir == PF_IN) { - NTOHS(pd->ndport); - if (pd->ndport == ICMP6_ECHO_REQUEST) - pd->ndport = ICMP_ECHO; - else if (pd->ndport == ICMP6_ECHO_REPLY) - pd->ndport = ICMP_ECHOREPLY; - HTONS(pd->ndport); - } else { - NTOHS(pd->nsport); - if (pd->nsport == ICMP6_ECHO_REQUEST) - pd->nsport = ICMP_ECHO; - else if (pd->nsport == ICMP6_ECHO_REPLY) - pd->nsport = ICMP_ECHOREPLY; - HTONS(pd->nsport); - } + NTOHS(pd->ndport); + if (pd->ndport == ICMP6_ECHO_REQUEST) + pd->ndport = ICMP_ECHO; + else if (pd->ndport == ICMP6_ECHO_REPLY) + pd->ndport = ICMP_ECHOREPLY; + HTONS(pd->ndport); } else if (pd->proto == IPPROTO_ICMP && pd->naf == AF_INET6) { - if (pd->dir == PF_IN) { - NTOHS(pd->ndport); - if (pd->ndport == ICMP_ECHO) - pd->ndport = ICMP6_ECHO_REQUEST; - else if (pd->ndport == ICMP_ECHOREPLY) - pd->ndport = ICMP6_ECHO_REPLY; - HTONS(pd->ndport); - } else { - NTOHS(pd->nsport); - if (pd->nsport == ICMP_ECHO) - pd->nsport = ICMP6_ECHO_REQUEST; - else if (pd->nsport == ICMP_ECHOREPLY) - pd->nsport = ICMP6_ECHO_REPLY; - HTONS(pd->nsport); - } + NTOHS(pd->ndport); + if (pd->ndport == ICMP_ECHO) + pd->ndport = ICMP6_ECHO_REQUEST; + else if (pd->ndport == ICMP_ECHOREPLY) + pd->ndport = ICMP6_ECHO_REPLY; + HTONS(pd->ndport); } /* get the destination address and port */ diff --git a/tests/sys/netpfil/pf/nat64.sh b/tests/sys/netpfil/pf/nat64.sh index 94c6c5fd8c8f..0bba1470c4c5 100644 --- a/tests/sys/netpfil/pf/nat64.sh +++ b/tests/sys/netpfil/pf/nat64.sh @@ -26,7 +26,7 @@ . $(atf_get_srcdir)/utils.subr -nat64_setup() +nat64_setup_base() { pft_init @@ -51,22 +51,70 @@ nat64_setup() jexec dst ping -c 1 192.0.2.1 jexec rtr pfctl -e +} + +nat64_setup_in() +{ + nat64_setup_base pft_set_rules rtr \ "set reassemble yes" \ "set state-policy if-bound" \ "pass in on ${epair}b inet6 from any to 64:ff9b::/96 af-to inet from (${epair_link}a)" } -atf_test_case "icmp_echo" "cleanup" -icmp_echo_head() +nat64_setup_out() +{ + nat64_setup_base + jexec rtr sysctl net.inet6.ip6.forwarding=1 + # AF translation happens post-routing, traffic must be directed + # towards the outbound interface using routes for the original AF. + # jexec rtr ifconfig ${epair_link}a inet6 2001:db8:2::1/64 up no_dad + jexec rtr route add -inet6 64:ff9b::/96 -iface ${epair_link}a; + pft_set_rules rtr \ + "set reassemble yes" \ + "set state-policy if-bound" \ + "pass quick inet6 proto icmp6 icmp6-type { neighbrsol, neighbradv }" \ + "pass in quick on ${epair}b from any to 64:ff9b::/96" \ + "pass out quick on ${epair_link}a from any to 64:ff9b::/96 af-to inet from (${epair_link}a)" \ + "block" +} + +atf_test_case "icmp_echo_in" "cleanup" +icmp_echo_in_head() +{ + atf_set descr 'Basic NAT64 ICMP echo test on inbound interface' + atf_set require.user root +} + +icmp_echo_in_body() +{ + nat64_setup_in + + # One ping + atf_check -s exit:0 -o ignore \ + ping6 -c 1 64:ff9b::192.0.2.2 + + # Make sure packets make it even when state is established + atf_check -s exit:0 \ + -o match:'5 packets transmitted, 5 packets received, 0.0% packet loss' \ + ping6 -c 5 64:ff9b::192.0.2.2 +} + +icmp_echo_in_cleanup() +{ + pft_cleanup +} + +atf_test_case "icmp_echo_out" "cleanup" +icmp_echo_out_head() { - atf_set descr 'Basic NAT64 ICMP echo test' + atf_set descr 'Basic NAT64 ICMP echo test on outbound interface' atf_set require.user root } -icmp_echo_body() +icmp_echo_out_body() { - nat64_setup + nat64_setup_out # One ping atf_check -s exit:0 -o ignore \ @@ -78,21 +126,21 @@ icmp_echo_body() ping6 -c 5 64:ff9b::192.0.2.2 } -icmp_echo_cleanup() +icmp_echo_out_cleanup() { pft_cleanup } -atf_test_case "fragmentation" "cleanup" -fragmentation_head() +atf_test_case "fragmentation_in" "cleanup" +fragmentation_in_head() { - atf_set descr 'Test fragmented packets' + atf_set descr 'Test fragmented packets on inbound interface' atf_set require.user root } -fragmentation_body() +fragmentation_in_body() { - nat64_setup + nat64_setup_in atf_check -s exit:0 -o ignore \ ping6 -c 1 -s 1280 64:ff9b::192.0.2.2 @@ -105,21 +153,48 @@ fragmentation_body() ping6 -c 3 -s 10000 -b 20000 64:ff9b::192.0.2.2 } -fragmentation_cleanup() +fragmentation_in_cleanup() { pft_cleanup } -atf_test_case "tcp" "cleanup" -tcp_head() +atf_test_case "fragmentation_out" "cleanup" +fragmentation_out_head() { - atf_set descr 'TCP NAT64 test' + atf_set descr 'Test fragmented packets on outbound interface' atf_set require.user root } -tcp_body() +fragmentation_out_body() { - nat64_setup + nat64_setup_out + + atf_check -s exit:0 -o ignore \ + ping6 -c 1 -s 1280 64:ff9b::192.0.2.2 + + atf_check -s exit:0 \ + -o match:'3 packets transmitted, 3 packets received, 0.0% packet loss' \ + ping6 -c 3 -s 2000 64:ff9b::192.0.2.2 + atf_check -s exit:0 \ + -o match:'3 packets transmitted, 3 packets received, 0.0% packet loss' \ + ping6 -c 3 -s 10000 -b 20000 64:ff9b::192.0.2.2 +} + +fragmentation_out_cleanup() +{ + pft_cleanup +} + +atf_test_case "tcp_in" "cleanup" +tcp_in_head() +{ + atf_set descr 'TCP NAT64 test on inbound interface' + atf_set require.user root +} + +tcp_in_body() +{ + nat64_setup_in echo "foo" | jexec dst nc -l 1234 & @@ -135,21 +210,81 @@ tcp_body() fi } -tcp_cleanup() +tcp_in_cleanup() { pft_cleanup } -atf_test_case "udp" "cleanup" -udp_head() +atf_test_case "tcp_out" "cleanup" +tcp_out_head() { - atf_set descr 'UDP NAT64 test' + atf_set descr 'TCP NAT64 test on outbound interface' atf_set require.user root } -udp_body() +tcp_out_body() { - nat64_setup + nat64_setup_out + + echo "foo" | jexec dst nc -l 1234 & + + # Sanity check & delay for nc startup + atf_check -s exit:0 -o ignore \ + ping6 -c 1 64:ff9b::192.0.2.2 + + rcv=$(nc -w 3 -6 64:ff9b::c000:202 1234) + if [ "${rcv}" != "foo" ]; + then + echo "rcv=${rcv}" + atf_fail "Failed to connect to TCP server" + fi +} + +tcp_out_cleanup() +{ + pft_cleanup +} + +atf_test_case "udp_in" "cleanup" +udp_in_head() +{ + atf_set descr 'UDP NAT64 test on inbound interface' + atf_set require.user root +} + +udp_in_body() +{ + nat64_setup_in + + echo "foo" | jexec dst nc -u -l 1234 & + + # Sanity check & delay for nc startup + atf_check -s exit:0 -o ignore \ + ping6 -c 1 64:ff9b::192.0.2.2 + + rcv=$(echo bar | nc -w 3 -6 -u 64:ff9b::c000:202 1234) + if [ "${rcv}" != "foo" ]; + then + echo "rcv=${rcv}" + atf_fail "Failed to connect to UDP server" + fi +} + +udp_in_cleanup() +{ + pft_cleanup +} + +atf_test_case "udp_out" "cleanup" +udp_out_head() +{ + atf_set descr 'UDP NAT64 test on outbound interface' + atf_set require.user root +} + +udp_out_body() +{ + nat64_setup_out echo "foo" | jexec dst nc -u -l 1234 & @@ -165,21 +300,54 @@ udp_body() fi } -udp_cleanup() +udp_out_cleanup() +{ + pft_cleanup +} + +atf_test_case "sctp_in" "cleanup" +sctp_in_head() +{ + atf_set descr 'SCTP NAT64 test on inbound interface' + atf_set require.user root +} + +sctp_in_body() +{ + nat64_setup_in + if ! kldstat -q -m sctp; then + atf_skip "This test requires SCTP" + fi + + echo "foo" | jexec dst nc --sctp -N -l 1234 & + + # Sanity check & delay for nc startup + atf_check -s exit:0 -o ignore \ + ping6 -c 1 64:ff9b::192.0.2.2 + + rcv=$(echo bar | nc --sctp -w 3 -6 64:ff9b::c000:202 1234) + if [ "${rcv}" != "foo" ]; + then + echo "rcv=${rcv}" + atf_fail "Failed to connect to SCTP server" + fi +} + +sctp_in_cleanup() { pft_cleanup } -atf_test_case "sctp" "cleanup" -sctp_head() +atf_test_case "sctp_out" "cleanup" +sctp_out_head() { - atf_set descr 'SCTP NAT64 test' + atf_set descr 'SCTP NAT64 test on outbound interface' atf_set require.user root } -sctp_body() +sctp_out_body() { - nat64_setup + nat64_setup_out if ! kldstat -q -m sctp; then atf_skip "This test requires SCTP" fi @@ -198,7 +366,7 @@ sctp_body() fi } -sctp_cleanup() +sctp_out_cleanup() { pft_cleanup } @@ -212,7 +380,7 @@ tos_head() tos_body() { - nat64_setup + nat64_setup_in # Ensure we can distinguish ToS on the destination jexec dst pfctl -e @@ -862,11 +1030,16 @@ v6_gateway_cleanup() atf_init_test_cases() { - atf_add_test_case "icmp_echo" - atf_add_test_case "fragmentation" - atf_add_test_case "tcp" - atf_add_test_case "udp" - atf_add_test_case "sctp" + atf_add_test_case "icmp_echo_in" + atf_add_test_case "icmp_echo_out" + atf_add_test_case "fragmentation_in" + atf_add_test_case "fragmentation_out" + atf_add_test_case "tcp_in" + atf_add_test_case "tcp_out" + atf_add_test_case "udp_in" + atf_add_test_case "udp_out" + atf_add_test_case "sctp_in" + atf_add_test_case "sctp_out" atf_add_test_case "tos" atf_add_test_case "no_v4" atf_add_test_case "range"
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202502271533.51RFXtl7065945>