Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F102554729
D42142.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
21 KB
Referenced Files
None
Subscribers
None
D42142.diff
View Options
diff --git a/sys/netinet/ip_divert.c b/sys/netinet/ip_divert.c
--- a/sys/netinet/ip_divert.c
+++ b/sys/netinet/ip_divert.c
@@ -171,11 +171,19 @@
u_int16_t nport;
struct sockaddr_in divsrc;
struct m_tag *mtag;
+ uint16_t cookie;
NET_EPOCH_ASSERT();
mtag = m_tag_locate(m, MTAG_IPFW_RULE, 0, NULL);
- if (mtag == NULL) {
+ if (mtag != NULL) {
+ cookie = ((struct ipfw_rule_ref *)(mtag+1))->rulenum;
+ nport = htons((uint16_t)
+ (((struct ipfw_rule_ref *)(mtag+1))->info));
+ } else if ((mtag = m_tag_locate(m, MTAG_PF_DIVERT, 0, NULL)) != NULL) {
+ cookie = ((struct pf_divert_mtag *)(mtag+1))->idir;
+ nport = htons(((struct pf_divert_mtag *)(mtag+1))->ndir);
+ } else {
m_freem(m);
return;
}
@@ -216,7 +224,7 @@
divsrc.sin_len = sizeof(divsrc);
divsrc.sin_family = AF_INET;
/* record matching rule, in host format */
- divsrc.sin_port = ((struct ipfw_rule_ref *)(mtag+1))->rulenum;
+ divsrc.sin_port = cookie;
/*
* Record receive interface address, if any.
* But only for incoming packets.
@@ -265,7 +273,6 @@
}
/* Put packet on socket queue, if any */
- nport = htons((uint16_t)(((struct ipfw_rule_ref *)(mtag+1))->info));
SLIST_FOREACH(dcb, &V_divhash[DIVHASH(nport)], dcb_next)
if (dcb->dcb_port == nport)
break;
@@ -304,6 +311,7 @@
const struct ip *ip;
struct m_tag *mtag;
struct ipfw_rule_ref *dt;
+ struct pf_divert_mtag *pfdt;
int error, family;
if (control)
@@ -390,13 +398,30 @@
return (EAFNOSUPPORT);
}
+ mtag = m_tag_locate(m, MTAG_PF_DIVERT, 0, NULL);
+ if (mtag == NULL) {
+ /* this should be normal */
+ mtag = m_tag_alloc(MTAG_PF_DIVERT, 0,
+ sizeof(struct pf_divert_mtag), M_NOWAIT | M_ZERO);
+ if (mtag == NULL) {
+ m_freem(m);
+ return (ENOBUFS);
+ }
+ m_tag_prepend(m, mtag);
+ }
+ pfdt = (struct pf_divert_mtag *)(mtag+1);
+ if (sin)
+ pfdt->idir = sin->sin_port;
+
/* Reinject packet into the system as incoming or outgoing */
NET_EPOCH_ENTER(et);
if (!sin || sin->sin_addr.s_addr == 0) {
dt->info |= IPFW_IS_DIVERT | IPFW_INFO_OUT;
+ pfdt->ndir = PF_DIVERT_MTAG_DIR_OUT;
error = div_output_outbound(family, so, m);
} else {
dt->info |= IPFW_IS_DIVERT | IPFW_INFO_IN;
+ pfdt->ndir = PF_DIVERT_MTAG_DIR_IN;
error = div_output_inbound(family, so, m, sin);
}
NET_EPOCH_EXIT(et);
diff --git a/sys/netinet/ip_var.h b/sys/netinet/ip_var.h
--- a/sys/netinet/ip_var.h
+++ b/sys/netinet/ip_var.h
@@ -326,6 +326,16 @@
extern int (*ng_ipfw_input_p)(struct mbuf **, struct ip_fw_args *, bool);
extern int (*ip_dn_ctl_ptr)(struct sockopt *);
extern int (*ip_dn_io_ptr)(struct mbuf **, struct ip_fw_args *);
+
+/* pf specific mtag for divert(4) support */
+enum { PF_DIVERT_MTAG_DIR_IN=1, PF_DIVERT_MTAG_DIR_OUT=2 };
+struct pf_divert_mtag {
+ uint16_t idir; // initial pkt direction
+ uint16_t ndir; // a) divert(4) port upon initial diversion
+ // b) new direction upon pkt re-enter
+};
+#define MTAG_PF_DIVERT 1262273569
+
#endif /* _KERNEL */
#endif /* !_NETINET_IP_VAR_H_ */
diff --git a/sys/netpfil/pf/pf.c b/sys/netpfil/pf/pf.c
--- a/sys/netpfil/pf/pf.c
+++ b/sys/netpfil/pf/pf.c
@@ -7628,7 +7628,7 @@
u_short action, reason = 0;
struct mbuf *m = *m0;
struct ip *h = NULL;
- struct m_tag *ipfwtag;
+ struct m_tag *mtag;
struct pf_krule *a = NULL, *r = &V_pf_default_rule, *tr, *nr;
struct pf_kstate *s = NULL;
struct pf_kruleset *ruleset = NULL;
@@ -7718,21 +7718,26 @@
off = h->ip_hl << 2;
if (__predict_false(ip_divert_ptr != NULL) &&
- ((ipfwtag = m_tag_locate(m, MTAG_IPFW_RULE, 0, NULL)) != NULL)) {
- struct ipfw_rule_ref *rr = (struct ipfw_rule_ref *)(ipfwtag+1);
- if (rr->info & IPFW_IS_DIVERT && rr->rulenum == 0) {
+ ((mtag = m_tag_locate(m, MTAG_PF_DIVERT, 0, NULL)) != NULL)) {
+ struct pf_divert_mtag *dt = (struct pf_divert_mtag *)(mtag+1);
+ if ((dt->idir == PF_DIVERT_MTAG_DIR_IN && dir == PF_IN) ||
+ (dt->idir == PF_DIVERT_MTAG_DIR_OUT && dir == PF_OUT)) {
if (pd.pf_mtag == NULL &&
((pd.pf_mtag = pf_get_mtag(m)) == NULL)) {
action = PF_DROP;
goto done;
}
pd.pf_mtag->flags |= PF_MTAG_FLAG_PACKET_LOOPED;
- m_tag_delete(m, ipfwtag);
}
if (pd.pf_mtag && pd.pf_mtag->flags & PF_MTAG_FLAG_FASTFWD_OURS_PRESENT) {
m->m_flags |= M_FASTFWD_OURS;
pd.pf_mtag->flags &= ~PF_MTAG_FLAG_FASTFWD_OURS_PRESENT;
}
+ m_tag_delete(m, mtag);
+
+ mtag = m_tag_locate(m, MTAG_IPFW_RULE, 0, NULL);
+ if (mtag != NULL)
+ m_tag_delete(m, mtag);
} else if (pf_normalize_ip(m0, kif, &reason, &pd) != PF_PASS) {
/* We do IP header normalization and packet reassembly here */
action = PF_DROP;
@@ -8014,17 +8019,19 @@
if (__predict_false(ip_divert_ptr != NULL) && action == PF_PASS &&
r->divert.port && !PACKET_LOOPED(&pd)) {
- ipfwtag = m_tag_alloc(MTAG_IPFW_RULE, 0,
- sizeof(struct ipfw_rule_ref), M_NOWAIT | M_ZERO);
- if (ipfwtag != NULL) {
- ((struct ipfw_rule_ref *)(ipfwtag+1))->info =
+ mtag = m_tag_alloc(MTAG_PF_DIVERT, 0,
+ sizeof(struct pf_divert_mtag), M_NOWAIT | M_ZERO);
+ if (mtag != NULL) {
+ ((struct pf_divert_mtag *)(mtag+1))->ndir =
ntohs(r->divert.port);
- ((struct ipfw_rule_ref *)(ipfwtag+1))->rulenum = dir;
+ ((struct pf_divert_mtag *)(mtag+1))->idir =
+ (dir == PF_IN) ? PF_DIVERT_MTAG_DIR_IN :
+ PF_DIVERT_MTAG_DIR_OUT;
if (s)
PF_STATE_UNLOCK(s);
- m_tag_prepend(m, ipfwtag);
+ m_tag_prepend(m, mtag);
if (m->m_flags & M_FASTFWD_OURS) {
if (pd.pf_mtag == NULL &&
((pd.pf_mtag = pf_get_mtag(m)) == NULL)) {
@@ -8052,6 +8059,9 @@
("pf: failed to allocate divert tag\n"));
}
}
+ /* this flag will need revising if the pkt is forwarded */
+ if (pd.pf_mtag)
+ pd.pf_mtag->flags &= ~PF_MTAG_FLAG_PACKET_LOOPED;
if (pd.act.log) {
struct pf_krule *lr;
diff --git a/tests/sys/netpfil/pf/Makefile b/tests/sys/netpfil/pf/Makefile
--- a/tests/sys/netpfil/pf/Makefile
+++ b/tests/sys/netpfil/pf/Makefile
@@ -2,10 +2,12 @@
PACKAGE= tests
TESTSDIR= ${TESTSBASE}/sys/netpfil/pf
+BINDIR= ${TESTSDIR}
TESTS_SUBDIRS+= ioctl
ATF_TESTS_SH+= altq \
anchor \
+ divert-to \
dup \
ether \
forward \
@@ -45,6 +47,8 @@
# Tests reuse jail names and so cannot run in parallel.
TEST_METADATA+= is_exclusive=true
+PROGS= divapp
+
${PACKAGE}FILES+= CVE-2019-5597.py \
CVE-2019-5598.py \
daytime_inetd.conf \
diff --git a/tests/sys/netpfil/pf/divapp.c b/tests/sys/netpfil/pf/divapp.c
new file mode 100644
--- /dev/null
+++ b/tests/sys/netpfil/pf/divapp.c
@@ -0,0 +1,149 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2023 Igor Ostapenko <pm@igoro.pro>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/* Used by tests like divert-to.sh */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <err.h>
+#include <sysexits.h>
+#include <string.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+
+
+struct context {
+ unsigned short divert_port;
+ bool divert_back;
+
+ int fd;
+ struct sockaddr_in sin;
+ socklen_t sin_len;
+ char pkt[IP_MAXPACKET];
+ ssize_t pkt_n;
+};
+
+static void
+init(struct context *c)
+{
+ c->fd = socket(PF_DIVERT, SOCK_RAW, 0);
+ if (c->fd == -1)
+ errx(EX_OSERR, "init: Cannot create divert socket.");
+
+ memset(&c->sin, 0, sizeof(c->sin));
+ c->sin.sin_family = AF_INET;
+ c->sin.sin_port = htons(c->divert_port);
+ c->sin.sin_addr.s_addr = INADDR_ANY;
+ c->sin_len = sizeof(struct sockaddr_in);
+
+ if (bind(c->fd, (struct sockaddr *) &c->sin, c->sin_len) != 0)
+ errx(EX_OSERR, "init: Cannot bind divert socket.");
+}
+
+static ssize_t
+recv_pkt(struct context *c)
+{
+ fd_set readfds;
+ struct timeval timeout;
+ int s;
+
+ FD_ZERO(&readfds);
+ FD_SET(c->fd, &readfds);
+ timeout.tv_sec = 3;
+ timeout.tv_usec = 0;
+
+ s = select(c->fd + 1, &readfds, 0, 0, &timeout);
+ if (s == -1)
+ errx(EX_IOERR, "recv_pkt: select() errors.");
+ if (s != 1) // timeout
+ return -1;
+
+ c->pkt_n = recvfrom(c->fd, c->pkt, sizeof(c->pkt), 0,
+ (struct sockaddr *) &c->sin, &c->sin_len);
+ if (c->pkt_n == -1)
+ errx(EX_IOERR, "recv_pkt: recvfrom() errors.");
+
+ return (c->pkt_n);
+}
+
+static void
+send_pkt(struct context *c)
+{
+ ssize_t n;
+ char errstr[32];
+
+ n = sendto(c->fd, c->pkt, c->pkt_n, 0,
+ (struct sockaddr *) &c->sin, c->sin_len);
+ if (n == -1) {
+ strerror_r(errno, errstr, sizeof(errstr));
+ errx(EX_IOERR, "send_pkt: sendto() errors: %d %s.", errno, errstr);
+ }
+ if (n != c->pkt_n)
+ errx(EX_IOERR, "send_pkt: sendto() sent %zd of %zd bytes.",
+ n, c->pkt_n);
+}
+
+int
+main(int argc, char *argv[])
+{
+ struct context c;
+ int npkt;
+
+ if (argc < 2)
+ errx(EX_USAGE,
+ "Usage: %s <divert-port> [divert-back]", argv[0]);
+
+ memset(&c, 0, sizeof(struct context));
+
+ c.divert_port = (unsigned short) strtol(argv[1], NULL, 10);
+ if (c.divert_port == 0)
+ errx(EX_USAGE, "divert port is not defined.");
+
+ if (argc >= 3 && strcmp(argv[2], "divert-back") == 0)
+ c.divert_back = true;
+
+
+ init(&c);
+
+ npkt = 0;
+ while (recv_pkt(&c) > 0) {
+ if (c.divert_back)
+ send_pkt(&c);
+ npkt++;
+ if (npkt >= 10)
+ break;
+ }
+
+ if (npkt != 1)
+ errx(EXIT_FAILURE, "%d: npkt=%d.", c.divert_port, npkt);
+
+ return EXIT_SUCCESS;
+}
diff --git a/tests/sys/netpfil/pf/divert-to.sh b/tests/sys/netpfil/pf/divert-to.sh
new file mode 100644
--- /dev/null
+++ b/tests/sys/netpfil/pf/divert-to.sh
@@ -0,0 +1,413 @@
+#
+# SPDX-License-Identifier: BSD-2-Clause
+#
+# Copyright (c) 2023 Igor Ostapenko <pm@igoro.pro>
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+
+#
+# pf divert-to action test cases
+#
+# -----------| |-- |----| ----| |-----------
+# ( ) inbound |pf_check_in| ) -> |host| -> ( ) |pf_check_out| outbound )
+# -----------| | |-- |----| ----| | |-----------
+# | |
+# \|/ \|/
+# |------| |------|
+# |divapp| |divapp|
+# |------| |------|
+#
+# The basic cases:
+# - inbound > diverted | divapp terminated
+# - inbound > diverted > inbound | host terminated
+# - inbound > diverted > outbound | network terminated
+# - outbound > diverted | divapp terminated
+# - outbound > diverted > outbound | network terminated
+# - outbound > diverted > inbound | e.g. host terminated
+#
+# When a packet is diverted, forwarded, and possibly diverted again:
+# - inbound > diverted > inbound > forwarded
+# > outbound | network terminated
+# - inbound > diverted > inbound > forwarded
+# > outbound > diverted > outbound | network terminated
+#
+# Test case naming legend:
+# in - inbound
+# div - diverted
+# out - outbound
+# fwd - forwarded
+# ipfwon - with ipfw enabled, which allows all
+#
+
+. $(atf_get_srcdir)/utils.subr
+
+divert_init()
+{
+ if ! kldstat -q -m ipdivert; then
+ atf_skip "This test requires ipdivert"
+ fi
+}
+
+ipfw_init()
+{
+ if ! kldstat -q -m ipfw; then
+ atf_skip "This test requires ipfw"
+ fi
+}
+
+assert_ipfw_is_off()
+{
+ if kldstat -q -m ipfw; then
+ atf_skip "This test is for the case when ipfw is not loaded"
+ fi
+}
+
+atf_test_case "ipfwoff_in_div" "cleanup"
+ipfwoff_in_div_head()
+{
+ atf_set descr 'Test inbound > diverted | divapp terminated'
+ atf_set require.user root
+}
+ipfwoff_in_div_body()
+{
+ local ipfwon
+
+ pft_init
+ divert_init
+ test "$1" == "ipfwon" && ipfwon="yes"
+ test $ipfwon && ipfw_init || assert_ipfw_is_off
+
+ epair=$(vnet_mkepair)
+ vnet_mkjail div ${epair}b
+ ifconfig ${epair}a 192.0.2.1/24 up
+ jexec div ifconfig ${epair}b 192.0.2.2/24 up
+ test $ipfwon && jexec div ipfw add 65534 allow all from any to any
+
+ # Sanity check
+ atf_check -s exit:0 -o ignore ping -c3 192.0.2.2
+
+ jexec div pfctl -e
+ pft_set_rules div \
+ "pass all" \
+ "pass in inet proto icmp icmp-type echoreq divert-to 127.0.0.1 port 2000"
+
+ jexec div $(atf_get_srcdir)/divapp 2000 &
+ divapp_pid=$!
+ # Wait for the divapp to be ready
+ sleep 1
+
+ # divapp is expected to "eat" the packet
+ atf_check -s not-exit:0 -o ignore ping -c1 192.0.2.2
+
+ wait $divapp_pid
+}
+ipfwoff_in_div_cleanup()
+{
+ pft_cleanup
+}
+
+atf_test_case "ipfwon_in_div" "cleanup"
+ipfwon_in_div_head()
+{
+ atf_set descr 'Test inbound > diverted | divapp terminated, with ipfw enabled'
+ atf_set require.user root
+}
+ipfwon_in_div_body()
+{
+ ipfwoff_in_div_body "ipfwon"
+}
+ipfwon_in_div_cleanup()
+{
+ pft_cleanup
+}
+
+atf_test_case "ipfwoff_in_div_in" "cleanup"
+ipfwoff_in_div_in_head()
+{
+ atf_set descr 'Test inbound > diverted > inbound | host terminated'
+ atf_set require.user root
+}
+ipfwoff_in_div_in_body()
+{
+ local ipfwon
+
+ pft_init
+ divert_init
+ test "$1" == "ipfwon" && ipfwon="yes"
+ test $ipfwon && ipfw_init || assert_ipfw_is_off
+
+ epair=$(vnet_mkepair)
+ vnet_mkjail div ${epair}b
+ ifconfig ${epair}a 192.0.2.1/24 up
+ jexec div ifconfig ${epair}b 192.0.2.2/24 up
+ test $ipfwon && jexec div ipfw add 65534 allow all from any to any
+
+ # Sanity check
+ atf_check -s exit:0 -o ignore ping -c3 192.0.2.2
+
+ jexec div pfctl -e
+ pft_set_rules div \
+ "pass all" \
+ "pass in inet proto icmp icmp-type echoreq divert-to 127.0.0.1 port 2000 no state"
+
+ jexec div $(atf_get_srcdir)/divapp 2000 divert-back &
+ divapp_pid=$!
+ # Wait for the divapp to be ready
+ sleep 1
+
+ # divapp is NOT expected to "eat" the packet
+ atf_check -s exit:0 -o ignore ping -c1 192.0.2.2
+
+ wait $divapp_pid
+}
+ipfwoff_in_div_in_cleanup()
+{
+ pft_cleanup
+}
+
+atf_test_case "ipfwon_in_div_in" "cleanup"
+ipfwon_in_div_in_head()
+{
+ atf_set descr 'Test inbound > diverted > inbound | host terminated, with ipfw enabled'
+ atf_set require.user root
+}
+ipfwon_in_div_in_body()
+{
+ ipfwoff_in_div_in_body "ipfwon"
+}
+ipfwon_in_div_in_cleanup()
+{
+ pft_cleanup
+}
+
+atf_test_case "ipfwoff_out_div" "cleanup"
+ipfwoff_out_div_head()
+{
+ atf_set descr 'Test outbound > diverted | divapp terminated'
+ atf_set require.user root
+}
+ipfwoff_out_div_body()
+{
+ local ipfwon
+
+ pft_init
+ divert_init
+ test "$1" == "ipfwon" && ipfwon="yes"
+ test $ipfwon && ipfw_init || assert_ipfw_is_off
+
+ epair=$(vnet_mkepair)
+ vnet_mkjail div ${epair}b
+ ifconfig ${epair}a 192.0.2.1/24 up
+ jexec div ifconfig ${epair}b 192.0.2.2/24 up
+ test $ipfwon && jexec div ipfw add 65534 allow all from any to any
+
+ # Sanity check
+ atf_check -s exit:0 -o ignore ping -c3 192.0.2.2
+
+ jexec div pfctl -e
+ pft_set_rules div \
+ "pass all" \
+ "pass in inet proto icmp icmp-type echoreq no state" \
+ "pass out inet proto icmp icmp-type echorep divert-to 127.0.0.1 port 2000 no state"
+
+ jexec div $(atf_get_srcdir)/divapp 2000 &
+ divapp_pid=$!
+ # Wait for the divapp to be ready
+ sleep 1
+
+ # divapp is expected to "eat" the packet
+ atf_check -s not-exit:0 -o ignore ping -c1 192.0.2.2
+
+ wait $divapp_pid
+}
+ipfwoff_out_div_cleanup()
+{
+ pft_cleanup
+}
+
+atf_test_case "ipfwon_out_div" "cleanup"
+ipfwon_out_div_head()
+{
+ atf_set descr 'Test outbound > diverted | divapp terminated, with ipfw enabled'
+ atf_set require.user root
+}
+ipfwon_out_div_body()
+{
+ ipfwoff_out_div_body "ipfwon"
+}
+ipfwon_out_div_cleanup()
+{
+ pft_cleanup
+}
+
+atf_test_case "ipfwoff_out_div_out" "cleanup"
+ipfwoff_out_div_out_head()
+{
+ atf_set descr 'Test outbound > diverted > outbound | network terminated'
+ atf_set require.user root
+}
+ipfwoff_out_div_out_body()
+{
+ local ipfwon
+
+ pft_init
+ divert_init
+ test "$1" == "ipfwon" && ipfwon="yes"
+ test $ipfwon && ipfw_init || assert_ipfw_is_off
+
+ epair=$(vnet_mkepair)
+ vnet_mkjail div ${epair}b
+ ifconfig ${epair}a 192.0.2.1/24 up
+ jexec div ifconfig ${epair}b 192.0.2.2/24 up
+ test $ipfwon && jexec div ipfw add 65534 allow all from any to any
+
+ # Sanity check
+ atf_check -s exit:0 -o ignore ping -c3 192.0.2.2
+
+ jexec div pfctl -e
+ pft_set_rules div \
+ "pass all" \
+ "pass in inet proto icmp icmp-type echoreq no state" \
+ "pass out inet proto icmp icmp-type echorep divert-to 127.0.0.1 port 2000 no state"
+
+ jexec div $(atf_get_srcdir)/divapp 2000 divert-back &
+ divapp_pid=$!
+ # Wait for the divapp to be ready
+ sleep 1
+
+ # divapp is NOT expected to "eat" the packet
+ atf_check -s exit:0 -o ignore ping -c1 192.0.2.2
+
+ wait $divapp_pid
+}
+ipfwoff_out_div_out_cleanup()
+{
+ pft_cleanup
+}
+
+atf_test_case "ipfwon_out_div_out" "cleanup"
+ipfwon_out_div_out_head()
+{
+ atf_set descr 'Test outbound > diverted > outbound | network terminated, with ipfw enabled'
+ atf_set require.user root
+}
+ipfwon_out_div_out_body()
+{
+ ipfwoff_out_div_out_body "ipfwon"
+}
+ipfwon_out_div_out_cleanup()
+{
+ pft_cleanup
+}
+
+atf_test_case "ipfwoff_in_div_in_fwd_out_div_out" "cleanup"
+ipfwoff_in_div_in_fwd_out_div_out_head()
+{
+ atf_set descr 'Test inbound > diverted > inbound > forwarded > outbound > diverted > outbound | network terminated'
+ atf_set require.user root
+}
+ipfwoff_in_div_in_fwd_out_div_out_body()
+{
+ local ipfwon
+
+ pft_init
+ divert_init
+ test "$1" == "ipfwon" && ipfwon="yes"
+ test $ipfwon && ipfw_init || assert_ipfw_is_off
+
+ # host <a--epair0--b> router <a--epair1--b> site
+ epair0=$(vnet_mkepair)
+ epair1=$(vnet_mkepair)
+
+ vnet_mkjail router ${epair0}b ${epair1}a
+ ifconfig ${epair0}a 192.0.2.1/24 up
+ jexec router sysctl net.inet.ip.forwarding=1
+ jexec router ifconfig ${epair0}b 192.0.2.2/24 up
+ jexec router ifconfig ${epair1}a 198.51.100.1/24 up
+ test $ipfwon && jexec router ipfw add 65534 allow all from any to any
+
+ vnet_mkjail site ${epair1}b
+ jexec site ifconfig ${epair1}b 198.51.100.2/24 up
+ jexec site route add default 198.51.100.1
+ test $ipfwon && jexec site ipfw add 65534 allow all from any to any
+
+ route add -net 198.51.100.0/24 192.0.2.2
+
+ # Sanity check
+ atf_check -s exit:0 -o ignore ping -c3 192.0.2.2
+
+ # Should be routed without pf
+ atf_check -s exit:0 -o ignore ping -c3 198.51.100.2
+
+ jexec router pfctl -e
+ pft_set_rules router \
+ "pass all" \
+ "pass in inet proto icmp icmp-type echoreq divert-to 127.0.0.1 port 2001 no state" \
+ "pass out inet proto icmp icmp-type echoreq divert-to 127.0.0.1 port 2002 no state"
+
+ jexec router $(atf_get_srcdir)/divapp 2001 divert-back &
+ indivapp_pid=$!
+ jexec router $(atf_get_srcdir)/divapp 2002 divert-back &
+ outdivapp_pid=$!
+ # Wait for the divappS to be ready
+ sleep 1
+
+ # Both divappS are NOT expected to "eat" the packet
+ atf_check -s exit:0 -o ignore ping -c1 198.51.100.2
+
+ wait $indivapp_pid && wait $outdivapp_pid
+}
+ipfwoff_in_div_in_fwd_out_div_out_cleanup()
+{
+ pft_cleanup
+}
+
+atf_test_case "ipfwon_in_div_in_fwd_out_div_out" "cleanup"
+ipfwon_in_div_in_fwd_out_div_out_head()
+{
+ atf_set descr 'Test inbound > diverted > inbound > forwarded > outbound > diverted > outbound | network terminated, with ipfw enabled'
+ atf_set require.user root
+}
+ipfwon_in_div_in_fwd_out_div_out_body()
+{
+ ipfwoff_in_div_in_fwd_out_div_out_body "ipfwon"
+}
+ipfwon_in_div_in_fwd_out_div_out_cleanup()
+{
+ pft_cleanup
+}
+
+atf_init_test_cases()
+{
+ atf_add_test_case "ipfwoff_in_div"
+ atf_add_test_case "ipfwoff_in_div_in"
+ atf_add_test_case "ipfwon_in_div"
+ atf_add_test_case "ipfwon_in_div_in"
+
+ atf_add_test_case "ipfwoff_out_div"
+ atf_add_test_case "ipfwoff_out_div_out"
+ atf_add_test_case "ipfwon_out_div"
+ atf_add_test_case "ipfwon_out_div_out"
+
+ atf_add_test_case "ipfwoff_in_div_in_fwd_out_div_out"
+ atf_add_test_case "ipfwon_in_div_in_fwd_out_div_out"
+}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Fri, Nov 15, 12:03 AM (9 h, 6 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
14635505
Default Alt Text
D42142.diff (21 KB)
Attached To
Mode
D42142: Fix pf divert-to loop
Attached
Detach File
Event Timeline
Log In to Comment