Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F107464390
D48453.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
7 KB
Referenced Files
None
Subscribers
None
D48453.diff
View Options
diff --git a/sbin/pfctl/parse.y b/sbin/pfctl/parse.y
--- a/sbin/pfctl/parse.y
+++ b/sbin/pfctl/parse.y
@@ -173,7 +173,7 @@
PF_STATE_OPT_MAX_SRC_CONN_RATE, PF_STATE_OPT_MAX_SRC_NODES,
PF_STATE_OPT_OVERLOAD, PF_STATE_OPT_STATELOCK,
PF_STATE_OPT_TIMEOUT, PF_STATE_OPT_SLOPPY,
- PF_STATE_OPT_PFLOW };
+ PF_STATE_OPT_PFLOW, PF_STATE_OPT_ALLOW_RELATED };
enum { PF_SRCTRACK_NONE, PF_SRCTRACK, PF_SRCTRACK_GLOBAL, PF_SRCTRACK_RULE };
@@ -526,7 +526,7 @@
%token DNPIPE DNQUEUE RIDENTIFIER
%token LOAD RULESET_OPTIMIZATION PRIO
%token STICKYADDRESS ENDPI MAXSRCSTATES MAXSRCNODES SOURCETRACK GLOBAL RULE
-%token MAXSRCCONN MAXSRCCONNRATE OVERLOAD FLUSH SLOPPY PFLOW
+%token MAXSRCCONN MAXSRCCONNRATE OVERLOAD FLUSH SLOPPY PFLOW ALLOW_RELATED
%token TAGGED TAG IFBOUND FLOATING STATEPOLICY STATEDEFAULTS ROUTE SETTOS
%token DIVERTTO DIVERTREPLY BRIDGE_TO RECEIVEDON NE LE GE AFTO
%token <v.string> STRING
@@ -2651,6 +2651,14 @@
}
r.rule_flag |= PFRULE_PFLOW;
break;
+ case PF_STATE_OPT_ALLOW_RELATED:
+ if (r.rule_flag & PFRULE_ALLOW_RELATED) {
+ yyerror("state allow-related option: "
+ "multiple definitions");
+ YYERROR;
+ }
+ r.rule_flag |= PFRULE_ALLOW_RELATED;
+ break;
case PF_STATE_OPT_TIMEOUT:
if (o->data.timeout.number ==
PFTM_ADAPTIVE_START ||
@@ -4494,6 +4502,14 @@
$$->next = NULL;
$$->tail = $$;
}
+ | ALLOW_RELATED {
+ $$ = calloc(1, sizeof(struct node_state_opt));
+ if ($$ == NULL)
+ err(1, "state_opt_item: calloc");
+ $$->type = PF_STATE_OPT_ALLOW_RELATED;
+ $$->next = NULL;
+ $$->tail = $$;
+ }
| STRING NUMBER {
int i;
@@ -6429,6 +6445,7 @@
{ "af-to", AFTO},
{ "all", ALL},
{ "allow-opts", ALLOWOPTS},
+ { "allow-related", ALLOW_RELATED},
{ "altq", ALTQ},
{ "anchor", ANCHOR},
{ "antispoof", ANTISPOOF},
diff --git a/share/man/man5/pf.conf.5 b/share/man/man5/pf.conf.5
--- a/share/man/man5/pf.conf.5
+++ b/share/man/man5/pf.conf.5
@@ -27,7 +27,7 @@
.\" ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
-.Dd December 6, 2024
+.Dd January 10, 2025
.Dt PF.CONF 5
.Os
.Sh NAME
@@ -2508,6 +2508,10 @@
States created by this rule are exported on the
.Xr pflow 4
interface.
+.It Ar allow-related
+Automatically allow connections related to this one, regardless of rules that
+might otherwise affect them.
+This currently only applies to SCTP multihomed connection.
.El
.Pp
Multiple options can be specified, separated by commas:
diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h
--- a/sys/net/pfvar.h
+++ b/sys/net/pfvar.h
@@ -1658,6 +1658,7 @@
#define PFDESC_SCTP_ADD_IP 0x1000
u_int16_t sctp_flags;
u_int32_t sctp_initiate_tag;
+ struct pf_krule *related_rule;
struct pf_sctp_multihome_jobs sctp_multihome_jobs;
};
diff --git a/sys/netpfil/pf/pf.h b/sys/netpfil/pf/pf.h
--- a/sys/netpfil/pf/pf.h
+++ b/sys/netpfil/pf/pf.h
@@ -617,6 +617,7 @@
#define PFRULE_IFBOUND 0x00010000 /* if-bound */
#define PFRULE_STATESLOPPY 0x00020000 /* sloppy state tracking */
#define PFRULE_PFLOW 0x00040000
+#define PFRULE_ALLOW_RELATED 0x00080000
#ifdef _KERNEL
#define PFRULE_REFS 0x0080 /* rule has references */
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
@@ -462,6 +462,14 @@
if (st->rule->rt == PF_REPLYTO || (pd->af != pd->naf))
return (V_pfi_all);
+ /*
+ * If this state is created based on another state (e.g. SCTP
+ * multihome) always set it floating initially. We can't know for sure
+ * what interface the actual traffic for this state will come in on.
+ */
+ if (pd->related_rule)
+ return (V_pfi_all);
+
/* Don't overrule the interface for states created on incoming packets. */
if (st->direction == PF_IN)
return (k);
@@ -5700,6 +5708,10 @@
}
while (r != NULL) {
+ if (pd->related_rule) {
+ *rm = pd->related_rule;
+ break;
+ }
pf_counter_u64_add(&r->evaluations, 1);
PF_TEST_ATTRIB(pfi_kkif_match(r->kif, pd->kif) == r->ifnot,
r->skip[PF_SKIP_IFP]);
@@ -7180,6 +7192,15 @@
dst->scrub->pfss_v_tag = pd->sctp_initiate_tag;
}
+ /*
+ * Bind to the correct interface if we're if-bound. For multihomed
+ * extra associations we don't know which interface that will be until
+ * here, so we've inserted the state on V_pf_all. Fix that now.
+ */
+ if ((*state)->kif == V_pfi_all &&
+ (*state)->rule->rule_flag & PFRULE_IFBOUND)
+ (*state)->kif = pd->kif;
+
if (pd->sctp_flags & (PFDESC_SCTP_COOKIE | PFDESC_SCTP_HEARTBEAT_ACK)) {
if (src->state < SCTP_ESTABLISHED) {
pf_set_protostate(*state, psrc, SCTP_ESTABLISHED);
@@ -7396,6 +7417,9 @@
j->pd.sctp_flags |= PFDESC_SCTP_ADD_IP;
PF_RULES_RLOCK();
sm = NULL;
+ if (s->rule->rule_flag & PFRULE_ALLOW_RELATED) {
+ j->pd.related_rule = s->rule;
+ }
ret = pf_test_rule(&r, &sm,
&j->pd, &ra, &rs, NULL);
PF_RULES_RUNLOCK();
diff --git a/tests/sys/netpfil/pf/sctp.py b/tests/sys/netpfil/pf/sctp.py
--- a/tests/sys/netpfil/pf/sctp.py
+++ b/tests/sys/netpfil/pf/sctp.py
@@ -426,6 +426,82 @@
assert re.search(r"all sctp 192.0.2.4:.*192.0.2.3:1234", states)
assert re.search(r"all sctp 192.0.2.4:.*192.0.2.2:1234", states)
+ @pytest.mark.require_user("root")
+ def test_disallow_related(self):
+ srv_vnet = self.vnet_map["vnet2"]
+
+ ToolsHelper.print_output("/sbin/pfctl -e")
+ ToolsHelper.pf_rules([
+ "block proto sctp",
+ "pass inet proto sctp to 192.0.2.3",
+ "pass on lo"])
+
+ # Sanity check, we can communicate with the primary address.
+ client = SCTPClient("192.0.2.3", 1234)
+ client.send(b"hello", 0)
+ rcvd = self.wait_object(srv_vnet.pipe)
+ print(rcvd)
+ assert rcvd['ppid'] == 0
+ assert rcvd['data'] == "hello"
+
+ # This shouldn't work
+ success=False
+ try:
+ client.newpeer("192.0.2.2")
+ client.send(b"world", 0)
+ rcvd = self.wait_object(srv_vnet.pipe)
+ print(rcvd)
+ assert rcvd['ppid'] == 0
+ assert rcvd['data'] == "world"
+ success=True
+ except:
+ success=False
+ assert not success
+
+ # Check that we have a state for 192.0.2.3, but not 192.0.2.2 to 192.0.2.1
+ states = ToolsHelper.get_output("/sbin/pfctl -ss")
+ assert re.search(r"all sctp 192.0.2.1:.*192.0.2.3:1234", states)
+ assert not re.search(r"all sctp 192.0.2.1:.*192.0.2.2:1234", states)
+
+ @pytest.mark.require_user("root")
+ def test_allow_related(self):
+ srv_vnet = self.vnet_map["vnet2"]
+
+ ToolsHelper.print_output("/sbin/pfctl -e")
+ ToolsHelper.pf_rules([
+ "set state-policy if-bound",
+ "block proto sctp",
+ "pass inet proto sctp to 192.0.2.3 keep state (allow-related)",
+ "pass on lo"])
+
+ # Sanity check, we can communicate with the primary address.
+ client = SCTPClient("192.0.2.3", 1234)
+ client.send(b"hello", 0)
+ rcvd = self.wait_object(srv_vnet.pipe)
+ print(rcvd)
+ assert rcvd['ppid'] == 0
+ assert rcvd['data'] == "hello"
+
+ success=False
+ try:
+ client.newpeer("192.0.2.2")
+ client.send(b"world", 0)
+ rcvd = self.wait_object(srv_vnet.pipe)
+ print(rcvd)
+ assert rcvd['ppid'] == 0
+ assert rcvd['data'] == "world"
+ success=True
+ finally:
+ # Debug output
+ ToolsHelper.print_output("/sbin/pfctl -ss")
+ ToolsHelper.print_output("/sbin/pfctl -sr -vv")
+ assert success
+
+ # Check that we have a state for 192.0.2.3 and 192.0.2.2 to 192.0.2.1
+ states = ToolsHelper.get_output("/sbin/pfctl -ss")
+ assert re.search(r"epair.*sctp 192.0.2.1:.*192.0.2.3:1234", states)
+ assert re.search(r"epair.*sctp 192.0.2.1:.*192.0.2.2:1234", states)
+
class TestSCTPv6(VnetTestTemplate):
REQUIRED_MODULES = ["sctp", "pf"]
TOPOLOGY = {
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Wed, Jan 15, 1:22 PM (7 h, 28 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
15811013
Default Alt Text
D48453.diff (7 KB)
Attached To
Mode
D48453: pf: add 'allow-related' to always allow SCTP multihome extra connections
Attached
Detach File
Event Timeline
Log In to Comment