One thing i could not understand, the ftp-proxy.c file has the following lines:
int server_parse(struct session *s) { struct sockaddr *client_sa, *orig_sa, *proxy_sa, *server_sa; int prepared = 0; if (s->cmd == CMD_NONE || linelen < 4 || linebuf[0] != '2') goto out; /* * The pf rules below do quite some NAT rewriting, to keep up * appearances. Points to keep in mind: * 1) The client must think it's talking to the real server, * for both control and data connections. Transparently. * 2) The server must think that the proxy is the client. * 3) Source and destination ports are rewritten to minimize * port collisions, to aid security (some systems pick weak * ports) or to satisfy RFC requirements (source port 20). */ /* Cast this once, to make code below it more readable. */ client_sa = sstosa(&s->client_ss); server_sa = sstosa(&s->server_ss); proxy_sa = sstosa(&s->proxy_ss); if (fixed_server) /* Fixed server: data connections must appear to come from / go to the original server, not the fixed one. */ orig_sa = sstosa(&s->orig_server_ss); else /* Server not fixed: orig_server == server. */ orig_sa = sstosa(&s->server_ss); /* Passive modes. */ if ((s->cmd == CMD_PASV && strncmp("227 ", linebuf, 4) == 0) || (s->cmd == CMD_EPSV && strncmp("229 ", linebuf, 4) == 0)) { s->port = parse_port(s->cmd); if (s->port < MIN_PORT) { logmsg(LOG_CRIT, "#%d bad port in '%s'", s->id, linebuf); return (0); } s->proxy_port = pick_proxy_port(); logmsg(LOG_INFO, "#%d passive: client to server port %d" " via port %d", s->id, s->port, s->proxy_port); if (prepare_commit(s->id) == -1) goto fail; prepared = 1; proxy_reply(s->cmd, orig_sa, s->proxy_port); logmsg(LOG_DEBUG, "#%d proxy: %s", s->id, linebuf); /* rdr from $client to $orig_server port $proxy_port -> $server port $port */ if (add_rdr(s->id, client_sa, orig_sa, s->proxy_port, server_sa, s->port) == -1) goto fail; /* nat from $client to $server port $port -> $proxy */ if (add_nat(s->id, client_sa, server_sa, s->port, proxy_sa, PF_NAT_PROXY_PORT_LOW, PF_NAT_PROXY_PORT_HIGH) == -1) goto fail; /* pass in from $client to $server port $port */ if (add_filter(s->id, PF_IN, client_sa, server_sa, s->port) == -1) goto fail; /* pass out from $proxy to $server port $port */ if (add_filter(s->id, PF_OUT, proxy_sa, server_sa, s->port) == -1) goto fail; } /* Active modes. */ if ((s->cmd == CMD_PORT || s->cmd == CMD_EPRT) && strncmp("200 ", linebuf, 4) == 0) { logmsg(LOG_INFO, "#%d active: server to client port %d" " via port %d", s->id, s->port, s->proxy_port); if (prepare_commit(s->id) == -1) goto fail; prepared = 1; /* rdr from $server to $proxy port $proxy_port -> $client port $port */ if (add_rdr(s->id, server_sa, proxy_sa, s->proxy_port, client_sa, s->port) == -1) goto fail; /* nat from $server to $client port $port -> $orig_server port $natport */ if (rfc_mode && s->cmd == CMD_PORT) { /* Rewrite sourceport to RFC mandated 20. */ if (add_nat(s->id, server_sa, client_sa, s->port, orig_sa, 20, 20) == -1) goto fail; } else { /* Let pf pick a source port from the standard range. */ if (add_nat(s->id, server_sa, client_sa, s->port, orig_sa, PF_NAT_PROXY_PORT_LOW, PF_NAT_PROXY_PORT_HIGH) == -1) goto fail; } /* pass in from $server to $client port $port */ if (add_filter(s->id, PF_IN, server_sa, client_sa, s->port) == -1) goto fail; /* pass out from $orig_server to $client port $port */ if (add_filter(s->id, PF_OUT, orig_sa, client_sa, s->port) == -1) goto fail; } /* Commit rules if they were prepared. */ if (prepared && (do_commit() == -1)) { if (errno != EBUSY) goto fail; /* One more try if busy. */ usleep(5000); if (do_commit() == -1) goto fail; } out: s->cmd = CMD_NONE; s->port = 0; return (1); fail: logmsg(LOG_CRIT, "#%d pf operation failed: %s", s->id, strerror(errno)); if (prepared) do_rollback(); return (0); } In the passive modes session, i counted 4 pf rules being added, as also in the active modes. But reading ftp-proxy(8) i can see the following reference: In case of active mode (PORT or EPRT): rdr from $server to $proxy port $port -> $client pass quick inet proto tcp \ from $server to $client port $port flags S/SAFR keep state In case of passive mode (PASV or EPSV): nat from $client to $server port $port -> $proxy pass in quick inet proto tcp \ from $client to $server port $port flags S/SAFR keep state pass out quick inet proto tcp \ from $proxy to $server port $port flags S/SAFR keep state I.e., two rules for active mode and three for passive mode. I could not understand what happened to the others listed in the source code. I could not understand why the first filter rules is necessary, since after being natted, the proxy address is the only one to been seen by pf. thanks in advance for any clarifications.