Passive ftp uses two connections
Code:
- ftp command channel
client: client_ip:port>1023 --> server_ip:port_21
server: server_ip:port_21 --> client_ip:port>1023
- data channel
client: client_ip:port>1023 --> server_ip:port>1023
server: server_ip:port>1023 --> client_ip:port>1023
So the second rule
Code:
pass out proto tcp from self to any keep state
will allow the ftp command channel.
Because most people find a rule like this rather permissive (it allows for example MSN connections), a proxy is needed.
See
ftp-proxy(8) for the details.