diff --git a/systemvm/debian/opt/cloud/bin/configure.py b/systemvm/debian/opt/cloud/bin/configure.py index 77b56779d5b8..19995af9c207 100755 --- a/systemvm/debian/opt/cloud/bin/configure.py +++ b/systemvm/debian/opt/cloud/bin/configure.py @@ -1535,6 +1535,22 @@ def processForwardRule(self, rule): self.forward_vpc(rule) else: self.forward_vr(rule) + self.forward_ftp_helper(rule) + + def forward_ftp_helper(self, rule): + # Linux 6.0 no longer attaches the ftp helper after DNAT, so attach it + # to the public port that is forwarded to port 21 + if rule["protocol"] != "tcp" or "any" in [rule["public_ports"], rule["internal_ports"]]: + return + public_start = int(rule["public_ports"].split(":")[0]) + internal_ports = rule["internal_ports"].split(":") + internal_start = int(internal_ports[0]) + internal_end = int(internal_ports[-1]) + if not internal_start <= 21 <= internal_end: + return + public_port = public_start + 21 - internal_start + self.fw.append(["raw", "", "-A PREROUTING -d %s/32 -p tcp -m tcp --dport %s -j CT --helper ftp" % + (rule["public_ip"], public_port)]) def forward_vr(self, rule): # Prefetch iptables variables @@ -1679,6 +1695,7 @@ def processStaticNatRule(self, rule): self.fw.append(["mangle", "front", "-A %s -d %s -j RETURN" % (chain_name, static_route['network'])]) + self.fw.append(["raw", "", "-A PREROUTING -d %s/32 -p tcp -m tcp --dport 21 -j CT --helper ftp" % rule["public_ip"]]) self.fw.append(["nat", "front", "-A PREROUTING -d %s/32 -j DNAT --to-destination %s" % (rule["public_ip"], rule["internal_ip"])]) self.fw.append(["nat", "front", diff --git a/systemvm/debian/opt/cloud/bin/setup/common.sh b/systemvm/debian/opt/cloud/bin/setup/common.sh index ef1576ab588c..ef610c914079 100755 --- a/systemvm/debian/opt/cloud/bin/setup/common.sh +++ b/systemvm/debian/opt/cloud/bin/setup/common.sh @@ -164,7 +164,9 @@ enable_fwding() { enable_passive_ftp() { log_it "cloud: enabling passive FTP for guest VMs" - echo "$1" > /proc/sys/net/netfilter/nf_conntrack_helper + # Linux 6.0 removed the nf_conntrack_helper sysctl, the ftp helper is + # attached by raw table rules for static nat and port forwarding + modprobe nf_nat_ftp } disable_rpfilter() { diff --git a/systemvm/debian/opt/cloud/bin/setup/router.sh b/systemvm/debian/opt/cloud/bin/setup/router.sh index 5c72105f47a3..dc4fb9d0a691 100755 --- a/systemvm/debian/opt/cloud/bin/setup/router.sh +++ b/systemvm/debian/opt/cloud/bin/setup/router.sh @@ -70,7 +70,7 @@ setup_router() { disable_rpfilter_domR enable_fwding 1 enable_rpsrfs 1 - enable_passive_ftp 1 + enable_passive_ftp restore_ipv6 # Only allow DNS service for current network diff --git a/systemvm/debian/opt/cloud/bin/setup/vpcrouter.sh b/systemvm/debian/opt/cloud/bin/setup/vpcrouter.sh index 767f87848dd3..cf88e6cac480 100755 --- a/systemvm/debian/opt/cloud/bin/setup/vpcrouter.sh +++ b/systemvm/debian/opt/cloud/bin/setup/vpcrouter.sh @@ -82,7 +82,7 @@ setup_vpcrouter() { enable_vpc_rpsrfs 1 disable_rpfilter enable_fwding 1 - enable_passive_ftp 1 + enable_passive_ftp cp /etc/iptables/iptables-vpcrouter /etc/iptables/rules.v4 cp /etc/vpcdnsmasq.conf /etc/dnsmasq.conf cp /etc/cloud-nic.rules /etc/udev/rules.d/cloud-nic.rules diff --git a/systemvm/test/TestCsForwardingRules.py b/systemvm/test/TestCsForwardingRules.py new file mode 100644 index 000000000000..50ec370ea9d4 --- /dev/null +++ b/systemvm/test/TestCsForwardingRules.py @@ -0,0 +1,63 @@ +# 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 +import mock +from configure import CsForwardingRules + + +class TestCsForwardingRules(unittest.TestCase): + + def ftp_helper_rules(self, protocol, public_ports, internal_ports): + forwarding = CsForwardingRules.__new__(CsForwardingRules) + forwarding.fw = [] + forwarding.forward_ftp_helper({"public_ip": "10.0.0.2", "internal_ip": "10.1.1.10", "protocol": protocol, + "public_ports": public_ports, "internal_ports": internal_ports}) + return forwarding.fw + + def test_ftp_helper_on_other_public_port(self): + self.assertEqual(self.ftp_helper_rules("tcp", "2121:2121", "21:21"), + [["raw", "", "-A PREROUTING -d 10.0.0.2/32 -p tcp -m tcp --dport 2121 -j CT --helper ftp"]]) + + def test_ftp_helper_on_port_range(self): + self.assertEqual(self.ftp_helper_rules("tcp", "1020:1030", "20:30"), + [["raw", "", "-A PREROUTING -d 10.0.0.2/32 -p tcp -m tcp --dport 1021 -j CT --helper ftp"]]) + + def test_ftp_helper_on_port_21(self): + self.assertEqual(self.ftp_helper_rules("tcp", "21:21", "21:21"), + [["raw", "", "-A PREROUTING -d 10.0.0.2/32 -p tcp -m tcp --dport 21 -j CT --helper ftp"]]) + + def test_no_ftp_helper(self): + self.assertEqual(self.ftp_helper_rules("tcp", "2121:2121", "2121:2121"), []) + self.assertEqual(self.ftp_helper_rules("udp", "2121:2121", "21:21"), []) + self.assertEqual(self.ftp_helper_rules("tcp", "any", "any"), []) + + @mock.patch.object(CsForwardingRules, 'getStaticRoutes', return_value=[]) + @mock.patch.object(CsForwardingRules, 'getPrivateGatewayNetworks', return_value=[]) + @mock.patch.object(CsForwardingRules, 'getGuestIpByIp', return_value="10.1.1.1") + @mock.patch.object(CsForwardingRules, 'getNetworkByIp', return_value="10.1.1.0/24") + @mock.patch.object(CsForwardingRules, 'getDeviceByIp', return_value="eth2") + def test_ftp_helper_on_static_nat(self, *_): + forwarding = CsForwardingRules.__new__(CsForwardingRules) + forwarding.fw = [] + forwarding.processStaticNatRule({"public_ip": "10.0.0.2", "internal_ip": "10.1.1.10"}) + self.assertIn(["raw", "", "-A PREROUTING -d 10.0.0.2/32 -p tcp -m tcp --dport 21 -j CT --helper ftp"], + forwarding.fw) + + +if __name__ == '__main__': + unittest.main()