The 'reverse ftp-proxy' patch adds a command line option -R to ftp-proxy which proxies connection from external ftp clients to an internal ftp server, supporting client passive mode (where server listens on a random port for data connections, and the client connects to the server for data connections). This is the reverse mode to normal operation, where ftp-proxy proxies connections from local clients to external servers, supporting client active mode. This is against OpenBSD 3.4-stable. # cd /usr/src/libexec/ftp-proxy # patch Index: libexec/ftp-proxy/ftp-proxy.c =================================================================== RCS file: /cvs/src/libexec/ftp-proxy/ftp-proxy.c,v retrieving revision 1.22 diff -u -r1.22 ftp-proxy.c --- libexec/ftp-proxy/ftp-proxy.c 9 Jun 2002 01:03:12 -0000 1.22 +++ libexec/ftp-proxy/ftp-proxy.c 22 Jun 2002 08:48:26 -0000 @@ -126,6 +126,7 @@ struct sockaddr_in real_server_sa; struct sockaddr_in client_listen_sa; struct sockaddr_in server_listen_sa; +struct sockaddr_in proxy_sa; int client_listen_socket = -1; /* Only used in PASV mode */ int client_data_socket = -1; /* Connected socket to real client */ @@ -136,6 +137,7 @@ int AnonFtpOnly; int Verbose; int NatMode; +int ReverseMode; char ClientName[NI_MAXHOST]; char RealServerName[NI_MAXHOST]; @@ -916,7 +918,10 @@ new_dataconn(0); connection_mode = PASV_MODE; - iap = &(server->sa.sin_addr); + if (ReverseMode) + iap = &(proxy_sa.sin_addr); + else + iap = &(server->sa.sin_addr); debuglog(1, "we want client to use %s:%u", inet_ntoa(*iap), htons(client_listen_sa.sin_port)); @@ -960,7 +965,7 @@ long timeout_seconds = 0; struct timeval tv; - while ((ch = getopt(argc, argv, "D:g:m:M:t:u:AnVwr")) != -1) { + while ((ch = getopt(argc, argv, "D:g:m:M:R:t:u:AnVwr")) != -1) { char *p; switch (ch) { case 'A': @@ -994,6 +999,37 @@ case 'r': Use_Rdns = 1; /* look up hostnames */ break; + case 'R': { + char *s, *t; + + if (!*optarg) + usage(); + if ((s = strdup(optarg)) == NULL) { + syslog (LOG_NOTICE, + "Insufficient memory (malloc failed)"); + exit(EX_UNAVAILABLE); + } + memset(&real_server_sa, 0, sizeof(real_server_sa)); + real_server_sa.sin_len = sizeof(struct sockaddr_in); + real_server_sa.sin_family = AF_INET; + t = strchr(s, ':'); + if (t == NULL) + real_server_sa.sin_port = htons(21); + else { + long port = strtol(t + 1, &p, 10); + + if (*p || port <= 0 || port > 65535) + usage(); + real_server_sa.sin_port = htons(port); + *t = 0; + } + real_server_sa.sin_addr.s_addr = inet_addr(s); + if (real_server_sa.sin_addr.s_addr == INADDR_NONE) + usage(); + free(s); + ReverseMode = 1; + break; + } case 't': timeout_seconds = strtol(optarg, &p, 10); if (!*optarg || *p) @@ -1027,7 +1063,8 @@ memset(&client_iob, 0, sizeof(client_iob)); memset(&server_iob, 0, sizeof(server_iob)); - if (get_proxy_env(0, &real_server_sa, &client_iob.sa) == -1) + if (get_proxy_env(0, &real_server_sa, &client_iob.sa, + &proxy_sa) == -1) exit(EX_PROTOCOL); /* Index: libexec/ftp-proxy/util.h =================================================================== RCS file: /cvs/src/libexec/ftp-proxy/util.h,v retrieving revision 1.3 diff -u -r1.3 util.h --- libexec/ftp-proxy/util.h 23 May 2002 10:22:14 -0000 1.3 +++ libexec/ftp-proxy/util.h 22 Jun 2002 08:48:26 -0000 @@ -55,7 +55,7 @@ struct csiob *telnet_passthrough); extern int get_proxy_env(int fd, struct sockaddr_in *server_sa_ptr, - struct sockaddr_in *client_sa_ptr); + struct sockaddr_in *client_sa_ptr, struct sockaddr_in *proxy_sa_ptr); extern int get_backchannel_socket(int type, int min_port, int max_port, int start_port, int direction, struct sockaddr_in *sap); Index: libexec/ftp-proxy/util.c =================================================================== RCS file: /cvs/src/libexec/ftp-proxy/util.c,v retrieving revision 1.9 diff -u -r1.9 util.c --- libexec/ftp-proxy/util.c 9 Jun 2002 01:03:12 -0000 1.9 +++ libexec/ftp-proxy/util.c 22 Jun 2002 08:48:26 -0000 @@ -58,6 +58,8 @@ #include "util.h" +extern int ReverseMode; + int Debug_Level; int Use_Rdns; @@ -74,13 +76,13 @@ int get_proxy_env(int connected_fd, struct sockaddr_in *real_server_sa_ptr, - struct sockaddr_in *client_sa_ptr) + struct sockaddr_in *client_sa_ptr, struct sockaddr_in *proxy_sa_ptr) { struct pfioc_natlook natlook; int slen, fd; - slen = sizeof(*real_server_sa_ptr); - if (getsockname(connected_fd, (struct sockaddr *)real_server_sa_ptr, + slen = sizeof(*proxy_sa_ptr); + if (getsockname(connected_fd, (struct sockaddr *)proxy_sa_ptr, &slen) != 0) { syslog(LOG_ERR, "getsockname failed (%m)"); return(-1); @@ -92,6 +94,9 @@ return(-1); } + if (ReverseMode) + return(0); + /* * Build up the pf natlook structure. * Just for IPv4 right now @@ -99,10 +104,10 @@ memset((void *)&natlook, 0, sizeof(natlook)); natlook.af = AF_INET; natlook.saddr.addr32[0] = client_sa_ptr->sin_addr.s_addr; - natlook.daddr.addr32[0] = real_server_sa_ptr->sin_addr.s_addr; + natlook.daddr.addr32[0] = proxy_sa_ptr->sin_addr.s_addr; natlook.proto = IPPROTO_TCP; natlook.sport = client_sa_ptr->sin_port; - natlook.dport = real_server_sa_ptr->sin_port; + natlook.dport = proxy_sa_ptr->sin_port; natlook.direction = PF_OUT; /* Index: libexec/ftp-proxy/ftp-proxy.8 =================================================================== RCS file: /cvs/src/libexec/ftp-proxy/ftp-proxy.8,v retrieving revision 1.20 diff -u -r1.20 ftp-proxy.8 --- libexec/ftp-proxy/ftp-proxy.8 17 Jun 2002 00:21:28 -0000 1.20 +++ libexec/ftp-proxy/ftp-proxy.8 22 Jun 2002 08:48:27 -0000 @@ -119,6 +119,14 @@ Use reverse host (reverse DNS) lookups for logging and libwrap use. By default the proxy does not look up hostnames for libwrap or logging purposes. +.It Fl R Ar address:[port] +Reverse proxy mode for FTP servers running behind a NAT gateway. +In this mode, no redirection is needed. +The proxy is run from +.Xr inetd 8 +on the port that external clients connect to (usually 21). +Control connections and passive data connections are forwarded +to the server. .It Fl m Ar minport Specify the lower end of the port range the proxy will use for all data connections it establishes.