This patch was supplied by Landon Curt Noll, http://www.isthe.com/chongo/ ------------------------------------------------------------------------- To apply this patch: cd sftpd-1.40/.. (sftpd's parent dir) patch < if.patch.txt The patch below allows the Un*x client and server to function this way by allowing the following: * The sftpd daemon can optionally listen for new clients on a port of specific interface / IP address. * The sftpd daemon can connect to a ftpd server on a different machine. * The myinetd can optionally listen for new clients on a port of specific interface / IP address. The mods to sftpd extend functionality of -p port and -f port to be: -p Ihost:port Listen for new clients on 'port' for the interface 'Ihost'. The 'Ihost' must be one of the hostnames or IP address of the machine on which sftpd is running. Note that the Ihost: part is optional. The ``-p port'' still works in the old way. -f Fhost:port Connect to an ftpd server on host 'Fhost' port 'port'. The 'Fhost' may be any hostname / IP address. Note that the Fhost: part is optional. The ``-f port'' still works in the old way. Also for myinetd, the port arg may be ``Ihost:port'' as well. =-= Example: Say you have a firewall with 2 IP addresses, 1 public and 1 private. Assume that the private connect is a dedicated / securite / private network segment to an ftp server. So the firewall has: 200.100.50.25 ftp.public.foo.com 10.1.0.1 gateway.firewall.foo.com And say there is an ftp server on the private network: 10.1.0.30 ftp.private.foo.com The following sftpd command will allow this to work: sftpd -p200.100.50.25:353 -f10.1.0.30:21 ... Or one can run myinetd as follows: myinetd 200.100.50.25:353 /sbin/sftpd -s -f10.1.0.30:21 ... A more complex example: Say you have a firewall with 4 IP addresses, 3 public and 1 private. Assume that the private connect is a dedicated / securite / private network segment to several ftp servers. So the firewall has: 200.100.50.25 ftp.public.foo.com 200.100.55.10 ftp.public.bar.com 200.100.65.5 ftp.public.baz.com 10.1.0.1 gateway.firewall.foo.com And say there are multiple ftp servers on the private network: 10.1.0.30 ftp.private.foo.com 10.1.0.31 ftp.private.bar.com 10.1.0.32 ftp.private.baz.com One can run several sftpd daemons to the ftp servers from the firewall: sftpd -p200.100.50.25:353 -f10.1.0.30:21 -y/etc/key1 ... sftpd -p200.100.55.10:353 -f10.1.0.31:21 -y/etc/key2 ... sftpd -p200.100.65.5:353 -f10.1.0.32:21 -y/etc/key3 ... Or one can run multiple myinetd's as follows: myinetd 200.100.50.25:353 /sbin/sftpd -f10.1.0.30:21 -y/etc/key1 ... myinetd 200.100.55.10:353 /sbin/sftpd -f10.1.0.31:21 -y/etc/key2 ... myinetd 200.100.65.5:353 /sbin/sftpd -f10.1.0.32:21 -y/etc/key3 ... =-= *** ./sftpd-1.40/doc/sftpd.html.init Sun Feb 27 05:08:52 2000 --- ./sftpd-1.40/doc/sftpd.html Sun Feb 27 05:19:47 2000 *************** *** 64,73 **** --- 64,100 ----

+

-pIhost:N +
+ Alternate way to specify where to listen for clients. + Instead of listening for a port from any interface, sftpd will + only listen on the interface Ihost port N. + Note that Ihost must + be a hostname / IP address of an interface on the system in which + sftpd is running. + This option is only useful when + sftpd is not run from inetd. (I.e., the + -s switch is not specified.) + +

+

-fN
Specifies the port on which to contact ftpd. This option overrides the raw-ftp entry of /etc/services. + +

+ +

-fRhost:N +
+ Specifies to contact ftpd on host Rhost port N. + Note that communication between sftpd and the remote ftpd + is NOT encrypted. + To help ensure security, communication between the + host on which sftpd is running and Rhost should either + go over a private link, go over an encrypted link, go over an VPN + or otherwise be protected in some way. + This option overrides the raw-ftp entry of /etc/services.

*** ./sftpd-1.40/sockutil.cpp.init Thu Feb 24 10:41:40 2000 --- ./sftpd-1.40/sockutil.cpp Sun Feb 27 04:52:48 2000 *************** *** 14,19 **** --- 14,23 ---- // ------------ global variables --------------------- int socketsOpen = 0; + IPAddress sftpdHost = INADDR_ANY; // can be changed by -p host:port + + IPAddress ftpdHost = INADDR_ANY; // can be changed by -f host:port + // ---------- diagnostic facilities ------------------ // general diagnostic *************** *** 272,286 **** } ! ! // create a listener socket on the specified port ! SOCKET listen_socket(int port) { // create the address structure sockaddr_in saddr; memset((char *)&saddr, 0, sizeof(saddr)); saddr.sin_family = AF_INET; ! saddr.sin_addr.s_addr = htonl(INADDR_ANY); // don't care who we connect to saddr.sin_port = htons((short)port); // correct byte order // create the socket --- 276,289 ---- } ! // create a listener socket on the specified port for an interface ! SOCKET interface_listen_socket(IPAddress interface, int port) { // create the address structure sockaddr_in saddr; memset((char *)&saddr, 0, sizeof(saddr)); saddr.sin_family = AF_INET; ! saddr.sin_addr.s_addr = htonl(interface); saddr.sin_port = htons((short)port); // correct byte order // create the socket *************** *** 323,328 **** --- 326,338 ---- } + // listen to port on any interface + SOCKET listen_socket(int port) + { + return interface_listen_socket(INADDR_ANY, port); + } + + // Linux has the length parameter to several fns as // unsigned, whereas most others have it as int // (in 2.2 kernel that's been changed?) *************** *** 489,494 **** --- 499,521 ---- return ntohl(saddr.sin_addr.s_addr); } + + // returns the host address given to the -f arg, unless is it INADDR_ANY + // (which happens when -f arg us just port or not given). In the last + // case we return the host in which the remote client connected (i.e., + // the address of OUR side of the connection from the remote client). + IPAddress getftpdAddress(SOCKET s) + { + sockaddr_in saddr; + if (ftpdHost == INADDR_ANY) { + getSockName(s, saddr); + return ntohl(saddr.sin_addr.s_addr); + } else { + return ftpdHost; + } + } + + int getLocalPort(SOCKET s) { sockaddr_in saddr; *************** *** 984,986 **** --- 1011,1064 ---- #endif // NEED_ENDIAN_CONVERSIONS + + // split a -f hostname:port into ip_addr and port + // + int parse_f_arg(char *argString) + { + int is_ftpd_port; + char *p; + + // If we have :, then we split it into host : port + p = strchr(argString, ':'); + if (p != NULL) { + + // extract the port + *p++ = '\0'; + is_ftpd_port = atoi(p); + + // convert the host into an IP address + ftpdHost = resolveHostName(argString); + + // no :, so the entire arg is a port + } else { + is_ftpd_port = atoi(argString); + } + return is_ftpd_port; + } + + + // split a -p hostname:port into ip_addr and port + // + int parse_p_arg(char *argString) + { + int is_sftpd_port; + char *p; + + // If we have :, then we split it into host : port + p = strchr(argString, ':'); + if (p != NULL) { + + // extract the port + *p++ = '\0'; + is_sftpd_port = atoi(p); + + // convert the host into an IP address + sftpdHost = resolveHostName(argString); + + // no :, so the entire arg is a port + } else { + is_sftpd_port = atoi(argString); + } + return is_sftpd_port; + } *** ./sftpd-1.40/sftpd.cpp.init Wed Feb 23 02:51:19 2000 --- ./sftpd-1.40/sftpd.cpp Sun Feb 27 05:08:35 2000 *************** *** 310,320 **** break; case 'p': // listen port ! sftpdPort = atoi(argString); break; case 'f': // ftpd port ! ftpdPort = atoi(argString); break; case 'D': --- 310,320 ---- break; case 'p': // listen port ! sftpdPort = parse_p_arg(argString); break; case 'f': // ftpd port ! ftpdPort = parse_f_arg(argString); break; case 'D': *************** *** 419,425 **** --- 419,427 ---- " options:\n" " -v print version\n" " -pN listen for incoming connections on port N (default: %d)\n" + " -pIhost:N or on interface Ihost, port N\n" " -fN contact ftpd on port N (default: %d)\n" + " -fRhost:N or on host Rhost port N\n" " -s use stdin as control connection (for use with inetd)\n" " -d1 log diagnostic (debugging) messages\n" " -d2 log even more detailed diagnostic messages\n" *************** *** 503,514 **** // NOTE: we must run as root here, if sftpdPort is < 1024 // establish a listener on the sftpd port ! SOCKET listener = listen_socket(sftpdPort); addEntropy(); // wait for a connection ! log("Waiting for connection to sftpd port " << sftpdPort << ! "..."); client_control = accept_socket(listener); addEntropy(); --- 505,516 ---- // NOTE: we must run as root here, if sftpdPort is < 1024 // establish a listener on the sftpd port ! SOCKET listener = interface_listen_socket(sftpdHost, sftpdPort); addEntropy(); // wait for a connection ! log("Waiting for connection to sftpd " << ! formatAddress(sftpdHost, sftpdPort) << "..."); client_control = accept_socket(listener); addEntropy(); *************** *** 532,545 **** // it appears that typical ftpd implementations do not allow arbitrary // PORT command IP addresses when their control connection is to // localhost (127.0.0.1); therefore, we find out which IP address the ! // client connected to, and use that IP when connecting to ftpd; this ! // is necessary only when data channel protection is *off*, because // in that situation we let the client's PORT commands through ! // unmodified ! // open connection to real ftp server ! diagnostic("connecting to local ftpd at on port " << ftpdPort << ! "..."); ! server_control = connect_socket(getLocalAddress(client_control), ftpdPort); addEntropy(); diagnostic("connected to ftpd"); --- 534,550 ---- // it appears that typical ftpd implementations do not allow arbitrary // PORT command IP addresses when their control connection is to // localhost (127.0.0.1); therefore, we find out which IP address the ! // client connected to, and use that IP when connecting to ftpd unless ! // a hostname was given given via -f arg in which case we connect to ! // the ftpd on that host instead. ! // ! // This is necessary only when data channel protection is *off*, because // in that situation we let the client's PORT commands through ! // unmodified open connection to real ftp server ! diagnostic("connecting to host " << ! formatAddress(getftpdAddress(client_control), ftpdPort) << ! " ftpd ..."); ! server_control = connect_socket(getftpdAddress(client_control), ftpdPort); addEntropy(); diagnostic("connected to ftpd"); *************** *** 1256,1262 **** if (!skipQuery) { security = SecurityProvider:: findSecurityMechanism(methodName, NULL /*i.e., am server*/, ! getLocalAddress(client_control), getRemoteAddress(client_control)); } --- 1261,1267 ---- if (!skipQuery) { security = SecurityProvider:: findSecurityMechanism(methodName, NULL /*i.e., am server*/, ! getftpdAddress(client_control), getRemoteAddress(client_control)); } *************** *** 1708,1714 **** // open a local port for listening for ftpd to connect void SFTPD::listenServerDataPort() { ! server_listen = listen_socket(PORT_ANY); // before, I had some comment about port 20 here, but that's // all wrong... --- 1713,1720 ---- // open a local port for listening for ftpd to connect void SFTPD::listenServerDataPort() { ! server_listen = interface_listen_socket(getLocalAddress(server_control), ! PORT_ANY); // before, I had some comment about port 20 here, but that's // all wrong... *************** *** 1798,1804 **** // ---------- deal with the client ------------ // open a local socket to await the client's connection bassert(client_listen == INVALID_SOCKET); ! client_listen = listen_socket(PORT_ANY); int localPort = getLocalPort(client_listen); diagnostic("listening for client to connect on port " << localPort); --- 1804,1810 ---- // ---------- deal with the client ------------ // open a local socket to await the client's connection bassert(client_listen == INVALID_SOCKET); ! client_listen = interface_listen_socket(sftpdHost, sftpdHost); int localPort = getLocalPort(client_listen); diagnostic("listening for client to connect on port " << localPort); *************** *** 1806,1812 **** // send an affirmative reply to the client clientReply(RC_ENTERING_PASSIVE, stringb("Entering passive mode (" << ! constructPortArg(getLocalAddress(client_control), localPort) << ").")); } --- 1812,1818 ---- // send an affirmative reply to the client clientReply(RC_ENTERING_PASSIVE, stringb("Entering passive mode (" << ! constructPortArg(sftpdHost, localPort) << ").")); } *** ./sftpd-1.40/sockutil.h.init Wed Feb 23 02:55:43 2000 --- ./sftpd-1.40/sockutil.h Sun Feb 27 04:53:50 2000 *************** *** 51,56 **** --- 51,59 ---- // this is (# of successful socket()/accept() calls) - // (# of successful closesocket() calls) + extern IPAddress sftpdHost; // can be changed by -p host:port + + extern IPAddress ftpdHost; // can be changed by -f host:port // ---------------- standalone funcs ---------------------- // ------ receive helpers ------ *************** *** 144,152 **** --- 147,157 ---- // ------ socket open and close ------ enum { PORT_ANY=0 }; + SOCKET interface_listen_socket(IPAddress hostaddr, int port); SOCKET listen_socket(int port); // create a socket to listen to a specific port // when port=PORT_ANY, the OS picks the port to listen to + // when hostaddr=INADDR_ANY, thw OS listens to port from all interfaces SOCKET accept_socket(SOCKET s); // accept a connection on the given listening socket *************** *** 165,170 **** --- 170,177 ---- IPAddress getLocalAddress(SOCKET s); int getLocalPort(SOCKET s); // retrieve socket local address and local port + IPAddress getftpdAddress(SOCKET s); + // retrieve socket local or remote ftpd host address and port void getSockPeer(SOCKET s, sockaddr_in &addr); IPAddress getRemoteAddress(SOCKET s); *************** *** 236,241 **** --- 243,256 ---- // (blocking) // map string into address; correctly handles addresses in // decimal-dot notation; + + + int parse_f_arg(char *argString); + // used to convert -f host:port into IPADDR and port + + int parse_p_arg(char *argString); + // used to convert -p host:port into IPADDR and port + // ---------------- SocketSet ------------------- *** ./sftpd-1.40/sec_de3s.cpp.init Sun Feb 27 02:01:55 2000 --- ./sftpd-1.40/sec_de3s.cpp Sun Feb 27 04:54:00 2000 *************** *** 342,352 **** // pull apart concatenated pieces IPAddress serverIP = removeIPAddress(block); - if (serverIP != peerAddress) { - xsecurity(stringb("Server claims its IP address is " << - formatAddress(serverIP) << ", but I think it is " << - formatAddress(peerAddress) << ".")); - } serverChallenge = removeBlock(block, CHALLENGE_LENGTH); diagDataBlock1(serverChallenge, "server challenge"); --- 342,347 ---- *** ./sftpd-1.40/myinetd.cpp.init Sun Feb 27 15:01:56 2000 --- ./sftpd-1.40/myinetd.cpp Mon Feb 28 05:12:23 2000 *************** *** 16,32 **** int entry(int argc, char *argv[]) { if (argc < 3) { ! printf("usage: %s port prog-to-run [prog's arguments]\n", argv[0]); printf(" (note: must run as root if port < 1024)\n"); return 0; } // interpret arguments ! int port = atoi(argv[1]); char const *progToRun = argv[2]; // listen for a connection ! SOCKET listener = listen_socket(port); // declare socket to carry info outside loop SOCKET conn; --- 16,32 ---- int entry(int argc, char *argv[]) { if (argc < 3) { ! printf("usage: %s [Ihost:]port prog-to-run [prog's arguments]\n", argv[0]); printf(" (note: must run as root if port < 1024)\n"); return 0; } // interpret arguments ! int port = parse_p_arg(argv[1]); char const *progToRun = argv[2]; // listen for a connection ! SOCKET listener = interface_listen_socket(sftpdHost, port); // declare socket to carry info outside loop SOCKET conn; *************** *** 42,51 **** } // wait for incoming, and make a new socket for it when it arrives ! fprintf(stderr, "listening for incoming connection on port %d...\n", port); conn = accept_socket(listener); ! fprintf(stderr, "received connection %s, starting %s\n", ! sockInfo(conn).pcharc(), progToRun); // fork a child to finish up and run the real server --- 42,59 ---- } // wait for incoming, and make a new socket for it when it arrives ! if (sftpdHost == INADDR_ANY) { ! fprintf(stderr, ! "%s: listening for incoming connection on %s port %d ...\n", ! argv[0], "localhost", port); ! } else { ! fprintf(stderr, ! "%s: listening for incoming connection on %s port %d ...\n", ! argv[0], argv[1], port); ! } conn = accept_socket(listener); ! fprintf(stderr, "%s: received connection %s, starting %s\n", ! argv[0], sockInfo(conn).pcharc(), progToRun); // fork a child to finish up and run the real server *** ./sftpd-1.40/doc/mkhtml.init Tue Feb 22 02:33:25 2000 --- ./sftpd-1.40/doc/mkhtml Tue Feb 22 02:33:51 2000 *************** *** 4,8 **** # create sftpc.html echo "Creating sftpc.html" ../sftpc -@ > sftpc_at.html ! insert insert-command-docs sftpc_at.html < sftpc_in.html > sftpc.html --- 4,8 ---- # create sftpc.html echo "Creating sftpc.html" ../sftpc -@ > sftpc_at.html ! ./insert insert-command-docs sftpc_at.html < sftpc_in.html > sftpc.html