FTP Helper on non standard port not working

Hello,

I have 2 vlans at home. I need to access an Android Tablet on the first vlan from a device on the second vlan on protocol FTP. The FTP server being an Android Tablet I cannot set port 21 to be used and I can't choose the passive ports.
I added a firewall rule to allow the communication on the custom FTP port (2121) and activated the ftp helper for this rule. I installed the kmod-nf-nathelper package and restarted the firewall as indicated here.

config rule
        option name 'Allow-Forward-Lan-Tablet (FTP)'
        list proto 'tcp'
        option src 'lan'
        option dest 'restricted'
        list dest_ip '192.168.3.35'
        option target 'ACCEPT'
        option dest_port '2121'
        option helper 'ftp'

The problem is that with this configuration I can't even connect on port 2121.

ftp> open
(to) tablet.restricted 2121
ftp: Can't connect to `192.168.3.35:2121': Connection refused
ftp: Can't connect to `tablet.restricted:2121'
ftp>

If I remove the helper option, I can connect but the data transfer can't happen.

ftp> open 
(to) tablet.restricted 2121
Connected to tablet.restricted.
220 SwiFTP 3.1 ready
Name (tablet.restricted:user): myuser
331 Send password
Password: 
230 Access granted
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> ls
227 Entering Passive Mode (192,168,3,35,159,81).
ftp: Can't connect to `192.168.3.35:40785': Connection refused
200 PORT OK
425 Error opening data socket
ftp>

How come I can't even connect on port 2121 if the helper option is enabled?
Is the FTP helper working only if the FTP port is 21 (thus the rule is not even used if the open port is 2121 in my case)?
Is there a way to make it work without opening any other port(s) between the 2 vlans?

Thanks

Tried port mode instead of passive ?

What is the output of

Please run the following commands (copy-paste the whole block) and paste the output here, using the "Preformatted text </> " button:
grafik
Remember to redact passwords, MAC addresses and any public IP addresses you may have

ubus call system board; \
fw4 restart; nft list ruleset

You mean active mode? Where the server connects to the client on a random port?
That wouldn't work as the firewall would prevent the server (Android Tablet) to connect. And I also have no way to put the server (Android Tablet FTP Server) in this mode.

{
	"kernel": "5.15.137",
	"hostname": "router",
	"system": "Intel Core Processor (Skylake)",
	"model": "QEMU Standard PC (i440FX + PIIX, 1996)",
	"board_name": "qemu-standard-pc-i440fx-piix-1996",
	"rootfs_type": "squashfs",
	"release": {
		"distribution": "OpenWrt",
		"version": "23.05.2",
		"revision": "r23630-842932a63d",
		"target": "x86/64",
		"description": "OpenWrt 23.05.2 r23630-842932a63d"
	}
}
table inet fw4 {
	ct helper ftp {
		type "ftp" protocol tcp
		l3proto inet
	}

	ct helper rtsp {
		type "rtsp" protocol tcp
		l3proto ip
	}

	chain input {
		type filter hook input priority filter; policy accept;
		iifname "lo" accept comment "!fw4: Accept traffic from loopback"
		ct state established,related accept comment "!fw4: Allow inbound established and related flows"
		tcp flags syn / fin,syn,rst,ack jump syn_flood comment "!fw4: Rate limit TCP syn packets"
		iifname "eth1" jump input_wan comment "!fw4: Handle wan IPv4/IPv6 input traffic"
		iifname "br-lan" jump input_lan comment "!fw4: Handle lan IPv4/IPv6 input traffic"
		iifname "br-restricted" jump input_restricted comment "!fw4: Handle restricted IPv4/IPv6 input traffic"
	}

	chain forward {
		type filter hook forward priority filter; policy drop;
		ct state established,related accept comment "!fw4: Allow forwarded established and related flows"
		iifname "eth1" jump forward_wan comment "!fw4: Handle wan IPv4/IPv6 forward traffic"
		iifname "br-lan" jump forward_lan comment "!fw4: Handle lan IPv4/IPv6 forward traffic"
		iifname "br-restricted" jump forward_restricted comment "!fw4: Handle restricted IPv4/IPv6 forward traffic"
		jump handle_reject
	}

	chain output {
		type filter hook output priority filter; policy accept;
		oifname "lo" accept comment "!fw4: Accept traffic towards loopback"
		ct state established,related accept comment "!fw4: Allow outbound established and related flows"
		oifname "eth1" jump output_wan comment "!fw4: Handle wan IPv4/IPv6 output traffic"
		oifname "br-lan" jump output_lan comment "!fw4: Handle lan IPv4/IPv6 output traffic"
		oifname "br-restricted" jump output_restricted comment "!fw4: Handle restricted IPv4/IPv6 output traffic"
	}

	chain prerouting {
		type filter hook prerouting priority filter; policy accept;
		iifname "br-lan" jump helper_lan comment "!fw4: Handle lan IPv4/IPv6 helper assignment"
		iifname "br-restricted" jump helper_restricted comment "!fw4: Handle restricted IPv4/IPv6 helper assignment"
	}

	chain handle_reject {
		meta l4proto tcp reject with tcp reset comment "!fw4: Reject TCP traffic"
		reject comment "!fw4: Reject any other traffic"
	}

	chain syn_flood {
		limit rate 25/second burst 50 packets return comment "!fw4: Accept SYN packets below rate-limit"
		drop comment "!fw4: Drop excess packets"
	}

	chain input_wan {
		meta nfproto ipv4 udp dport 68 counter packets 0 bytes 0 accept comment "!fw4: Allow-DHCP-Renew"
		icmp type echo-request counter packets 0 bytes 0 accept comment "!fw4: Allow-Ping"
		meta nfproto ipv4 meta l4proto igmp counter packets 0 bytes 0 accept comment "!fw4: Allow-IGMP"
		meta nfproto ipv6 udp dport 546 counter packets 0 bytes 0 accept comment "!fw4: Allow-DHCPv6"
		ip6 saddr fe80::/10 icmpv6 type . icmpv6 code { mld-listener-query . no-route, mld-listener-report . no-route, mld-listener-done . no-route, mld2-listener-report . no-route } counter packets 0 bytes 0 accept comment "!fw4: Allow-MLD"
		icmpv6 type { destination-unreachable, time-exceeded, echo-request, echo-reply, nd-router-solicit, nd-router-advert } limit rate 1000/second counter packets 0 bytes 0 accept comment "!fw4: Allow-ICMPv6-Input"
		icmpv6 type . icmpv6 code { packet-too-big . no-route, parameter-problem . no-route, nd-neighbor-solicit . no-route, nd-neighbor-advert . no-route, parameter-problem . admin-prohibited } limit rate 1000/second counter packets 3 bytes 208 accept comment "!fw4: Allow-ICMPv6-Input"
		ct status dnat accept comment "!fw4: Accept port redirections"
		jump reject_from_wan
	}

	chain output_wan {
		jump accept_to_wan
	}

	chain forward_wan {
		icmpv6 type { destination-unreachable, time-exceeded, echo-request, echo-reply } limit rate 1000/second counter packets 0 bytes 0 accept comment "!fw4: Allow-ICMPv6-Forward"
		icmpv6 type . icmpv6 code { packet-too-big . no-route, parameter-problem . no-route, parameter-problem . admin-prohibited } limit rate 1000/second counter packets 0 bytes 0 accept comment "!fw4: Allow-ICMPv6-Forward"
		ct status dnat accept comment "!fw4: Accept port forwards"
		jump reject_to_wan
	}

	chain accept_to_wan {
		meta nfproto ipv4 oifname "eth1" ct state invalid counter packets 0 bytes 0 drop comment "!fw4: Prevent NAT leakage"
		oifname "eth1" counter packets 798 bytes 62818 accept comment "!fw4: accept wan IPv4/IPv6 traffic"
	}

	chain reject_from_wan {
		iifname "eth1" counter packets 0 bytes 0 jump handle_reject comment "!fw4: reject wan IPv4/IPv6 traffic"
	}

	chain reject_to_wan {
		oifname "eth1" counter packets 0 bytes 0 jump handle_reject comment "!fw4: reject wan IPv4/IPv6 traffic"
	}

	chain drop_to_wan {
		oifname "eth1" counter packets 0 bytes 0 drop comment "!fw4: drop wan IPv4/IPv6 traffic"
	}

	chain input_lan {
		ct status dnat accept comment "!fw4: Accept port redirections"
		jump accept_from_lan
	}

	chain output_lan {
		jump accept_to_lan
	}

	chain forward_lan {
		ip daddr 192.168.3.35 tcp dport 2121 ct helper "ftp" counter packets 0 bytes 0 jump accept_to_restricted comment "!fw4: Allow-Forward-Lan-Tablet (FTP)"
		jump accept_to_wan comment "!fw4: Accept lan to wan forwarding"
		ct status dnat accept comment "!fw4: Accept port forwards"
		jump accept_to_lan
	}

	chain helper_lan {
		tcp dport 21 ct helper set "ftp" comment "!fw4: FTP passive connection tracking"
		meta nfproto ipv4 tcp dport 554 ct helper set "rtsp" comment "!fw4: RTSP connection tracking"
	}

	chain accept_from_lan {
		iifname "br-lan" counter packets 361 bytes 24228 accept comment "!fw4: accept lan IPv4/IPv6 traffic"
	}

	chain accept_to_lan {
		oifname "br-lan" counter packets 4 bytes 240 accept comment "!fw4: accept lan IPv4/IPv6 traffic"
	}

	chain input_restricted {
		tcp dport { 53, 67, 123 } counter packets 0 bytes 0 accept comment "!fw4: Allow-Input-restricted"
		udp dport { 53, 67, 123 } counter packets 0 bytes 0 accept comment "!fw4: Allow-Input-restricted"
		ct status dnat accept comment "!fw4: Accept port redirections"
		jump reject_from_restricted
	}

	chain output_restricted {
		jump accept_to_restricted
	}

	chain forward_restricted {
		ip saddr 192.168.3.35 ip daddr { 192.168.0.87, 192.168.0.89 } tcp dport 80 counter packets 0 bytes 0 jump accept_to_lan comment "!fw4: Allow-Forward-Tablet-LAN"
		ct status dnat accept comment "!fw4: Accept port forwards"
		jump reject_to_restricted
	}

	chain helper_restricted {
		tcp dport 21 ct helper set "ftp" comment "!fw4: FTP passive connection tracking"
		meta nfproto ipv4 tcp dport 554 ct helper set "rtsp" comment "!fw4: RTSP connection tracking"
	}

	chain accept_to_restricted {
		oifname "br-restricted" counter packets 10 bytes 624 accept comment "!fw4: accept restricted IPv4/IPv6 traffic"
	}

	chain reject_from_restricted {
		iifname "br-restricted" counter packets 0 bytes 0 jump handle_reject comment "!fw4: reject restricted IPv4/IPv6 traffic"
	}

	chain reject_to_restricted {
		oifname "br-restricted" counter packets 0 bytes 0 jump handle_reject comment "!fw4: reject restricted IPv4/IPv6 traffic"
	}

	chain dstnat {
		type nat hook prerouting priority dstnat; policy accept;
		iifname "eth1" jump dstnat_wan comment "!fw4: Handle wan IPv4/IPv6 dstnat traffic"
		iifname "br-lan" jump dstnat_lan comment "!fw4: Handle lan IPv4/IPv6 dstnat traffic"
		iifname "br-restricted" jump dstnat_restricted comment "!fw4: Handle restricted IPv4/IPv6 dstnat traffic"
	}

	chain srcnat {
		type nat hook postrouting priority srcnat; policy accept;
		oifname "eth1" jump srcnat_wan comment "!fw4: Handle wan IPv4/IPv6 srcnat traffic"
	}

	chain dstnat_wan {
		meta nfproto ipv4 tcp dport 80 counter packets 0 bytes 0 dnat ip to 192.168.0.87:80 comment "!fw4: Allow HTTP"
	}

	chain srcnat_wan {
		meta nfproto ipv4 masquerade comment "!fw4: Masquerade IPv4 wan traffic"
	}

	chain dstnat_lan {
		meta nfproto ipv4 tcp dport 53 counter packets 0 bytes 0 redirect to :53 comment "!fw4: Lan-DNS-Intercept"
		meta nfproto ipv4 udp dport 53 counter packets 2 bytes 120 redirect to :53 comment "!fw4: Lan-DNS-Intercept"
	}

	chain dstnat_restricted {
		meta nfproto ipv4 tcp dport 53 counter packets 0 bytes 0 redirect to :53 comment "!fw4: Restricted-DNS-Intercept"
		meta nfproto ipv4 udp dport 53 counter packets 0 bytes 0 redirect to :53 comment "!fw4: Restricted-DNS-Intercept"
	}

	chain raw_prerouting {
		type filter hook prerouting priority raw; policy accept;
	}

	chain raw_output {
		type filter hook output priority raw; policy accept;
	}

	chain mangle_prerouting {
		type filter hook prerouting priority mangle; policy accept;
	}

	chain mangle_postrouting {
		type filter hook postrouting priority mangle; policy accept;
	}

	chain mangle_input {
		type filter hook input priority mangle; policy accept;
	}

	chain mangle_output {
		type route hook output priority mangle; policy accept;
	}

	chain mangle_forward {
		type filter hook forward priority mangle; policy accept;
		iifname "eth1" tcp flags syn tcp option maxseg size set rt mtu comment "!fw4: Zone wan IPv4/IPv6 ingress MTU fixing"
		oifname "eth1" tcp flags syn tcp option maxseg size set rt mtu comment "!fw4: Zone wan IPv4/IPv6 egress MTU fixing"
	}
}

it's usually the other way around.

port mode uses port 20 and 21, passive is random, unless you define a port/range.

but I guess port 20 is a no go for you, unless the active data port can be configured too.

Helper is looking at port 21 not 2121, try to change the port on the server and the rule on the firewall to 21.

2 Likes

Like I said, I can't change anything on the server as it is an Android tablet.
Shouldn't fw4 also add a rule for the dest_port mentionned in the rule in addition to the standard port?

I am not sure if it should or not adjust for the destination port.
In any way you can try to add the nft command manually.

1 Like

I'm not very familiar with nft rules (I have more knowledge with iptables), but I managed to manually add the rule (first only on helper_lan chain, and then also on helper_restricted), but it is still not working. I get "connection refused" on port 2121, meaning that not even the connection on that port works with the helper rule. If I remove the helper, I can connect on port 2121, but can't do any transfer.

chain forward_lan {
		ip daddr 192.168.3.35 tcp dport 2121 ct helper "ftp" counter packets 0 bytes 0 jump accept_to_restricted comment "!fw4: Allow-Forward-Lan-Tablet (FTP)"
		jump accept_to_wan comment "!fw4: Accept lan to wan forwarding"
		ct status dnat accept comment "!fw4: Accept port forwards"
		jump accept_to_lan
	}

	chain helper_lan {
		tcp dport 2121 ct helper set "ftp" comment "test"
		tcp dport 21 ct helper set "ftp" comment "!fw4: FTP passive connection tracking"
		meta nfproto ipv4 tcp dport 554 ct helper set "rtsp" comment "!fw4: RTSP connection tracking"
	}

	chain helper_restricted {
		tcp dport 2121 ct helper set "ftp" comment "test"
		tcp dport 21 ct helper set "ftp" comment "!fw4: FTP passive connection tracking"
		meta nfproto ipv4 tcp dport 554 ct helper set "rtsp" comment "!fw4: RTSP connection tracking"
	}
ftp> open
(to) tablet.restricted 2121
ftp: Can't connect to `192.168.3.35:2121': Connection refused
ftp: Can't connect to `tablet.restricted:2121'
ftp>

I managed to make it work by removing the FTP Helper from the rule and manually adding a rule with port 2121 on helper_lan chain.

chain forward_lan {
		ip daddr 192.168.3.35 tcp dport 2121 counter packets 0 bytes 0 jump accept_to_restricted comment "!fw4: Allow-Forward-Lan-Tablet (FTP)"
		jump accept_to_wan comment "!fw4: Accept lan to wan forwarding"
		ct status dnat accept comment "!fw4: Accept port forwards"
		jump accept_to_lan
	}

	chain helper_lan {
		tcp dport 2121 ct helper set "ftp" comment "test"
		tcp dport 21 ct helper set "ftp" comment "!fw4: FTP passive connection tracking"
		meta nfproto ipv4 tcp dport 554 ct helper set "rtsp" comment "!fw4: RTSP connection tracking"
	}

I don't know why I can't even connect on port 2121 when the helper is included in the rule from the chain forward_lan.
Also I am not sure how I can add the rule that I added manually in the helper_lan chain from uci config (or firewall config file), if it is possible at all...

cat << EOF >> /etc/hotplug.d/iface/20-firewall
nft add ...
EOF

This should do the trick.

1 Like

Will try.
Thanks.