This is an automated email from the ASF dual-hosted git repository.
DaanHoogland pushed a commit to branch 4.22
in repository https://gitbox.apache.org/repos/asf/cloudstack.git
The following commit(s) were added to refs/heads/4.22 by this push:
new de4ca48dfb3 Routed network ACL: match protocol-number rules with ip
protocol, not ip nexthdr (#14352)
de4ca48dfb3 is described below
commit de4ca48dfb37ef0fefef6dc816b31777be01fd83
Author: Brad House - Nexthop <[email protected]>
AuthorDate: Thu Oct 22 08:43:03 2026 -0400
Routed network ACL: match protocol-number rules with ip protocol, not ip
nexthdr (#14352)
Signed-off-by: Brad House <[email protected]>
---
systemvm/debian/opt/cloud/bin/configure.py | 2 +-
systemvm/test/TestCsAclRouting.py | 67 ++++++++++++++++++++++++++++++
2 files changed, 68 insertions(+), 1 deletion(-)
diff --git a/systemvm/debian/opt/cloud/bin/configure.py
b/systemvm/debian/opt/cloud/bin/configure.py
index 0575433ad00..95cb7360846 100755
--- a/systemvm/debian/opt/cloud/bin/configure.py
+++ b/systemvm/debian/opt/cloud/bin/configure.py
@@ -450,7 +450,7 @@ class CsAcl(CsDataBag):
if protocol != "all":
icmp_type = ""
if protocol == "protocol":
- protocol = "ip nexthdr %d" % rule['protocol']
+ protocol = "ip protocol %d" % rule['protocol']
proto = protocol
if proto == "icmp":
proto = proto_str = "icmp"
diff --git a/systemvm/test/TestCsAclRouting.py
b/systemvm/test/TestCsAclRouting.py
new file mode 100644
index 00000000000..7d67d711fb9
--- /dev/null
+++ b/systemvm/test/TestCsAclRouting.py
@@ -0,0 +1,67 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+import unittest
+from configure import CsAcl
+
+
+class FakeConfig:
+
+ def __init__(self):
+ self.fw = []
+ self.ipv6_acl = []
+ self.nft_ipv4_acl = []
+
+ def get_fw(self):
+ return self.fw
+
+ def get_ipv6_acl(self):
+ return self.ipv6_acl
+
+ def get_nft_ipv4_acl(self):
+ return self.nft_ipv4_acl
+
+ def is_vpc(self):
+ return True
+
+ def is_routed(self):
+ return True
+
+
+class TestCsAclRouting(unittest.TestCase):
+
+ def test_protocol_number_rule(self):
+ config = FakeConfig()
+ obj = {"device": "eth3", "nic_ip": "10.1.1.1", "nic_netmask": "24",
"nic_ip6_cidr": "fd00:1::/64",
+ "ingress_rules": [{"type": "protocol", "protocol": 47, "cidr":
"1.2.3.4/32,2001:db8::/64", "allowed": True}],
+ "egress_rules": [{"type": "protocol", "protocol": 47, "cidr":
"5.6.7.8/32", "allowed": False}]}
+ acl = CsAcl.AclDevice(obj, config)
+ acl.create()
+
+ # nexthdr is an IPv6 header field, nft rejects it in an ip rule
+ ip4 = [r['rule'] for r in config.nft_ipv4_acl if r.get('chain') ==
"eth3_ingress_policy" and 'rule' in r]
+ self.assertIn("ip saddr 1.2.3.4/32 ip protocol 47 accept", ip4)
+ ip6 = [r['rule'] for r in config.ipv6_acl if r.get('chain') ==
"eth3_ingress_policy" and 'rule' in r]
+ # the IPv4 match must not leak into the IPv6 rule
+ self.assertTrue(any(r.startswith("ip6 saddr 2001:db8::/64 ") and
r.endswith(" 47 accept") for r in ip6))
+ self.assertFalse(any("ip protocol" in r for r in ip6))
+ ip4 = [r['rule'] for r in config.nft_ipv4_acl if r.get('chain') ==
"eth3_egress_policy" and 'rule' in r]
+ self.assertIn("ip daddr 5.6.7.8/32 ip protocol 47 drop", ip4)
+
+
+if __name__ == '__main__':
+ unittest.main()