Here are my long-promised patches to NcFTP to add support for application
proxies. These have been very lightly tested, and may therefore contain any
number of bugs I haven't caught, but they _seem_ to be working. :)
Documentation on the new functionality is in the on-line help and in the man
page, but take a close look at:
Config.h.in:
#define USE_BASTION_APP_PROXY /* enable app proxy support */
#define BH_NAME_ENV "INTERNET_HOST" /* envar for BH name */
#define BH_NAME_DEF "firewall.lehman.com" /* default BH to use */
#define BH_PORT_ENV "INTERNET_FTP_PORT" /* envar for BH ftp port */
#define BH_PORT_SERV "ftp-passthru" /* service for BH ftp port */
#define BH_PORT_DEF 21 /* default for BH ftp port */
#define BH_LOCALDOM_ENV "LOCAL_DOMAINS" /* envar for local domain list */
#define BH_LOCALDOM_DEF ".lehman.com" /* default local domain list */
#define BH_MAX_DOMAINS 100 /* max # of local domains */
Command line / open options:
-S : Always connect locally, unless overridden by open -b
-B : Always connect via the proxy, unless overridden by open -s
-s : Connect directly, ignoring the local domain matching.
-b : Connect via the proxy, ignoring the local domain matching.
Environment variables (as named in Config.h(.in)):
INTERNET_HOST
INTERNET_FTP_PORT
LOCAL_DOMAINS
--
Carson Gaspar -- carson @
cs .
columbia .
edu carson @
lehman .
com
http://www.cs.columbia.edu/~carson/home.html
<This is the boring business .sig - no outre sayings here>
diff -c ../ncftp-2.4.0/Cmdlist.c ./Cmdlist.c
*** ../ncftp-2.4.0/Cmdlist.c Thu Feb 22 22:07:18 1996
--- ./Cmdlist.c Thu Oct 17 21:30:01 1996
***************
*** 285,292 ****
--- 285,295 ----
kCmdWaitMsg,
OpenCmd,
kNoMin, kNoMax,
+ #if defined(USE_BASTION_APP_PROXY)
"[-flags] [sitename]\n\
Flags:\n\
+ -s : Connect directly, ignoring the local domain matching.\n\
+ -b : Connect via the proxy, ignoring the local domain matching.\n\
-a : Open anonymously.\n\
-u : Open with username and password prompt.\n\
-p X : Use port number X when opening.\n\
***************
*** 297,302 ****
--- 300,319 ----
open sphygmomanometer.unl.edu\n\
open -u bowser.nintendo.co.jp\n\
open -r -d 75 -g 10 sphygmomanometer.unl.edu\n",
+ #else
+ "[-flags] [sitename]\n\
+ Flags:\n\
+ -a : Open anonymously.\n\
+ -u : Open with username and password prompt.\n\
+ -p X : Use port number X when opening.\n\
+ -r : Redial until connected.\n\
+ -d X : Redial, delaying X seconds between tries.\n\
+ -g X : Give up after X redials without connection.\n\
+ Examples:\n\
+ open sphygmomanometer.unl.edu\n\
+ open -u bowser.nintendo.co.jp\n\
+ open -r -d 75 -g 10 sphygmomanometer.unl.edu\n",
+ #endif
"connects to a remote host",
kCompleteHost
},
diff -c ../ncftp-2.4.0/Config.h.in ./Config.h.in
*** ../ncftp-2.4.0/Config.h.in Wed Oct 16 19:10:21 1996
--- ./Config.h.in Thu Oct 17 20:44:27 1996
***************
*** 1,5 ****
--- 1,14 ----
/* Config.h.in. Generated automatically from configure.in by autoheader. */
+ #define USE_BASTION_APP_PROXY /* enable app proxy support */
+ #define BH_NAME_ENV "INTERNET_HOST" /* envar for BH name */
+ #define BH_NAME_DEF "firewall.lehman.com" /* default BH to use */
+ #define BH_PORT_ENV "INTERNET_FTP_PORT" /* envar for BH ftp port */
+ #define BH_PORT_SERV "ftp-passthru" /* service for BH ftp port */
+ #define BH_PORT_DEF 21 /* default for BH ftp port */
+ #define BH_LOCALDOM_ENV "LOCAL_DOMAINS" /* envar for local domain list */
+ #define BH_LOCALDOM_DEF ".lehman.com" /* default local domain list */
+ #define BH_MAX_DOMAINS 100 /* max # of local domains */
/* Don't define HOSTNAME or DOMAINNAME unless you have to. After compiling,
* a test run of the program will tell you if it couldn't determine these
diff -c ../ncftp-2.4.0/Main.c ./Main.c
*** ../ncftp-2.4.0/Main.c Wed Oct 16 18:55:12 1996
--- ./Main.c Wed Oct 23 16:50:01 1996
***************
*** 25,30 ****
--- 25,31 ----
#include <signal.h>
#include <setjmp.h>
#include <stdlib.h>
+ #include <netdb.h>
#include "Util.h"
#include "Main.h"
***************
*** 156,161 ****
--- 157,176 ----
*/
int gStartup = 0;
+ #if defined(USE_BASTION_APP_PROXY)
+ /* pointer to bastion host name */
+ char *gBastionName;
+
+ /* bastion host port */
+ int gBastionPort;
+
+ /* list of local domains */
+ char *gLocalDomains[BH_MAX_DOMAINS];
+
+ /* Are we using an application proxy? Default to no. */
+ int gUseBastionAppProxy = 0;
+ #endif
+
extern int gStdout, gRealStdout;
extern char *getlogin(void);
extern longstring gLocalCWD;
***************
*** 866,871 ****
--- 881,941 ----
int opt, result;
OpenOptions openopt;
+ #if defined(USE_BASTION_APP_PROXY)
+
+ if (!(gBastionName = getenv(BH_NAME_ENV))) {
+ gBastionName = BH_NAME_DEF;
+ }
+
+ if (gBastionName != (char *) NULL) {
+ char *domainlist,*colp,*p;
+ int nd = 0;
+ struct servent *se;
+
+ gUseBastionAppProxy = 1;
+ if (p = getenv(BH_PORT_ENV)) {
+ gBastionPort = atoi(p);
+ } else if (se = getservbyname(BH_PORT_SERV, "tcp")) {
+ gBastionPort = se->s_port;
+ } else {
+ gBastionPort = BH_PORT_DEF;
+ }
+ if (!(domainlist = getenv(BH_LOCALDOM_ENV))) {
+ domainlist = BH_LOCALDOM_DEF;
+ }
+ if (domainlist && strlen(domainlist)) {
+ p = domainlist;
+ colp = strchr(p, ':');
+ while (colp) {
+ *colp = '\0';
+ gLocalDomains[nd] = (char *) malloc(strlen(p)+1);
+ if (gLocalDomains[nd]) {
+ strcpy(gLocalDomains[nd],p);
+ nd++;
+ } else {
+ perror("malloc failed parsing local domains:");
+ exit(255);
+ }
+ p = colp+1;
+ colp = strchr(p, ':');
+ }
+ if (strlen(p)) {
+ gLocalDomains[nd] = (char *) malloc(strlen(p)+1);
+ if (gLocalDomains[nd]) {
+ strcpy(gLocalDomains[nd],p);
+ nd++;
+ } else {
+ perror("malloc failed parsing local domains:");
+ exit(255);
+ }
+ gLocalDomains[nd] = (char *) 0;
+ }
+ }
+
+ }
+
+ #endif /* USE_BASTION_APP_PROXY */
+
Init();
RunStartupScript();
***************
*** 883,892 ****
* commands' flags and the program must use mutually exclusive
* sets of flags.
*/
while ((opt = Getopt(argc, argv, "aiup:rd:g:cmCfGRn:zDLVH")) >= 0) {
if (strchr("aiup:rd:g:cmCfGRn:z", opt) == NULL) {
switch (opt) {
! case 'D':
gDebug = kDebuggingOn;
gTrace = kTracingOn;
break;
--- 953,971 ----
* commands' flags and the program must use mutually exclusive
* sets of flags.
*/
+ #if defined(USE_BASTION_APP_PROXY)
+ while ((opt = Getopt(argc, argv, "aiup:rd:g:cmCfGRn:zsbSBDLVH")) >= 0) {
+ if (strchr("aiup:rd:g:cmCfGRn:zsb", opt) == NULL) {
+ #else
while ((opt = Getopt(argc, argv, "aiup:rd:g:cmCfGRn:zDLVH")) >= 0) {
if (strchr("aiup:rd:g:cmCfGRn:z", opt) == NULL) {
+ #endif
switch (opt) {
! #if defined(USE_BASTION_APP_PROXY)
! case 'S': gUseBastionAppProxy = -1; break;
! case 'B': gUseBastionAppProxy = 2; break;
! #endif
! case 'D':
gDebug = kDebuggingOn;
gTrace = kTracingOn;
break;
***************
*** 897,914 ****
--- 976,1015 ----
usage:
EPrintF(
"Usage: ncftp [options] [hostname[:path]]\n");
+ #if defined(USE_BASTION_APP_PROXY)
EPrintF("Program options:\n\
+ -S : Always connect locally, unless overridden by open -b\n\
+ -B : Always connect via the proxy, unless overridden by open -s\n\
-D : Turn debug mode and trace mode on.\n\
-L : Don't use visual mode (use line mode).\n\
-V : Use visual mode.\n\
-H : Dump the version information.\n");
+ #else
+ EPrintF("Program options:\n\
+ -D : Turn debug mode and trace mode on.\n\
+ -L : Don't use visual mode (use line mode).\n\
+ -V : Use visual mode.\n\
+ -H : Dump the version information.\n");
+ #endif
+ #if defined(USE_BASTION_APP_PROXY)
EPrintF("Command-line open options:\n\
+ -s : Connect directly, ignoring the local domain matching.\n\
+ -b : Connect via the proxy, ignoring the local domain matching.\n\
-a : Open anonymously.\n\
-u : Open with username and password prompt.\n\
-p X : Use port number X when opening.\n\
-r : Redial until connected.\n\
-d X : Redial, delaying X seconds between tries.\n\
-g X : Give up after X redials without connection.\n");
+ #else
+ EPrintF("Command-line open options:\n\
+ -a : Open anonymously.\n\
+ -u : Open with username and password prompt.\n\
+ -p X : Use port number X when opening.\n\
+ -r : Redial until connected.\n\
+ -d X : Redial, delaying X seconds between tries.\n\
+ -g X : Give up after X redials without connection.\n");
+ #endif
EPrintF("Command-line retrieve options:\n\
-C : Force continuation (reget).\n\
-f : Force overwrite.\n\
diff -c ../ncftp-2.4.0/Open.c ./Open.c
*** ../ncftp-2.4.0/Open.c Wed Oct 16 16:33:51 1996
--- ./Open.c Wed Oct 23 16:46:41 1996
***************
*** 5,10 ****
--- 5,13 ----
#ifdef SYSLOG
# include <syslog.h>
#endif
+ #include <netinet/in.h>
+ #include <arpa/inet.h>
+ #include <netdb.h>
#include "Util.h"
#include "Open.h"
***************
*** 60,65 ****
--- 63,74 ----
int gSavePasswords = 0;
/* Open.c externs */
+ #if defined(USE_BASTION_APP_PROXY)
+ extern char *gBastionName;
+ extern int gBastionPort, gUseBastionAppProxy;
+ extern char *gLocalDomains[];
+ extern struct hostent *GetHostEntry(char *host, struct in_addr *ip_address);
+ #endif
extern char *gOptArg;
extern int gOptInd, gIsToTTY;
extern unsigned int gFTPPort;
***************
*** 105,111 ****
--- 114,193 ----
+ #if defined(USE_BASTION_APP_PROXY)
+ int LocalDomain(char *h, char **dl)
+ {
+ char *dom, *p, *q, **a;
+ int nd = 0, dlen, hlen, ret;
+ struct hostent *hp;
+ struct in_addr ha, la, lm, ipaddr;
+
+ hp = GetHostEntry(h, &ipaddr);
+
+ while (dl[nd]) {
+ if (dl[nd][0] == '!') {
+ ret = 0;
+ p = (dl[nd])+1;
+ } else {
+ ret = 1;
+ p = dl[nd];
+ }
+ if (p[0] == '.' && hp) {
+ dlen = strlen(p);
+ if (hp->h_name) {
+ hlen = strlen(hp->h_name);
+ if ((hlen > dlen) && (strcasecmp((hp->h_name)+hlen-dlen,p) == 0)) {
+ return ret;
+ }
+ }
+ for (a = hp->h_aliases; *a != 0; a++) {
+ hlen = strlen(*a);
+ if ((hlen > dlen) && (strcasecmp((*a)+hlen-dlen,p) == 0)) {
+ return ret;
+ }
+ }
+ } else if ((p[0] >= '0' && p[0] <= '9') && (hp || ipaddr.s_addr)) {
+ q = strchr(p, '/');
+ if (q == 0) {
+ lm.s_addr = 0xffffffff;
+ la.s_addr = inet_addr(p);
+ } else {
+ *q = '\0';
+ lm.s_addr = inet_addr(p+1);
+ la.s_addr = inet_addr(p);
+ }
+ if (la.s_addr == -1) {
+ fprintf(stderr, "%s is not a valid IP address!\n", p);
+ DoQuit(255);
+ }
+
+ *q = '/';
+
+ if (hp) {
+ for (a = hp->h_addr_list; *a != 0; a++) {
+ (void) memcpy(&ha.s_addr, *a, sizeof (ha.s_addr));
+ if (((la.s_addr & lm.s_addr) ^ (ha.s_addr & lm.s_addr)) == 0) {
+ return ret;
+ }
+ }
+ } else {
+ if (((la.s_addr & lm.s_addr) ^ (ipaddr.s_addr & lm.s_addr)) == 0) {
+ return ret;
+ }
+ }
+ } else if (hp || (ipaddr.s_addr && (p[0] >= '0' && p[0] <= '9'))) {
+ fprintf(stderr,"bad local domain format - does not start with a period or a digit\n");
+ DoQuit(255);
+ }
+ nd++;
+ }
+ return(0);
+ }
+
+ int Login(char *u, char *p, char *a, char *h, int port)
+ #else
int Login(char *u, char *p, char *a)
+ #endif
{
string u2, p2, a2;
ResponsePtr rp;
***************
*** 119,125 ****
--- 201,226 ----
rp = InitResponse();
if (LoginQuestion("User", u2, sizeof(u2), "anonymous", 0) < 0)
goto done;
+ #if defined(USE_BASTION_APP_PROXY)
+ if ((gUseBastionAppProxy==2) || (gUseBastionAppProxy==1 && !LocalDomain(h, gLocalDomains))) {
+ char bh_user[1024];
+ char bh_port[255];
+
+ strncpy(bh_user, u2, 1024);
+ strncat(bh_user, "@", 1024 - strlen(bh_user));
+ strncat(bh_user, h, 1024 - strlen(bh_user));
+ if (port != 21) {
+ sprintf(bh_port," %d",port);
+ strncat(bh_user, bh_port, 1024 - strlen(bh_user));
+ }
+ RCmd(rp, "USER %s", bh_user);
+ }
+ else {
+ RCmd(rp, "USER %s", u2);
+ }
+ #else
RCmd(rp, "USER %s", u2);
+ #endif
for (;;) {
/* Here's a mini finite-automaton for the login process.
***************
*** 334,341 ****
--- 435,456 ----
/* Tell Getopt() that we want to start over with a new command. */
GetoptReset();
+ #if defined(USE_BASTION_APP_PROXY)
+ while ((opt = Getopt(argc, argv, "aiup:rd:g:cmCfGRn:sb")) >= 0) {
+ switch (opt) {
+ case 's':
+ /* Don't use the proxy */
+ openopt->useproxy = -1;
+ break;
+
+ case 'b':
+ /* Use the proxy */
+ openopt->useproxy = 2;
+ break;
+ #else
while ((opt = Getopt(argc, argv, "aiup:rd:g:cmCfGRn:")) >= 0) {
switch (opt) {
+ #endif
case 'a':
/* User wants to open anonymously. */
openopt->openmode = kOpenExplicitAnon;
***************
*** 810,816 ****
--- 925,949 ----
SetBar(NULL, "CONNECTING", NULL, 1, 1);
gAttemptingConnection = 1;
+ #if defined(USE_BASTION_APP_PROXY)
+ if (openopt->useproxy == 2
+ || (openopt->useproxy != -1
+ && gUseBastionAppProxy != -1
+ && (gUseBastionAppProxy==2
+ || (gUseBastionAppProxy==1
+ && !LocalDomain(openopt->hostname, gLocalDomains))))) {
+ if (gBastionPort) {
+ hErr = OpenControlConnection(gBastionName, gBastionPort);
+ } else {
+ hErr = OpenControlConnection(gBastionName, BH_PORT_DEF);
+ }
+ }
+ else {
+ hErr = OpenControlConnection(openopt->hostname, openopt->port);
+ }
+ #else
hErr = OpenControlConnection(openopt->hostname, openopt->port);
+ #endif
if (hErr == kConnectErrFatal) {
/* Irrecoverable error, so don't bother redialing.
* The error message should have already been printed
***************
*** 826,832 ****
--- 959,969 ----
/* This updates the status bar (for visual mode). */
SetBar(NULL, "LOGGING IN", NULL, 1, 1);
SetPostHangupOnServerProc(PostCloseStuff);
+ #if defined(USE_BASTION_APP_PROXY)
+ loginResult = Login(user, pass, r_acct, openopt->hostname, openopt->port);
+ #else
loginResult = Login(user, pass, r_acct);
+ #endif
if (loginResult == 0) {
PostLoginStuff(openopt);
diff -c ../ncftp-2.4.0/Open.h ./Open.h
*** ../ncftp-2.4.0/Open.h Sun Nov 26 01:06:24 1995
--- ./Open.h Thu Oct 17 21:12:57 1996
***************
*** 21,26 ****
--- 21,27 ----
char colonModePath[256];
int interactiveColonMode;
GetOptions gopt;
+ int useproxy;
} OpenOptions;
/* Open modes. */
***************
*** 43,49 ****
--- 44,54 ----
/* Protos: */
int LoginQuestion(char *, char *, size_t, char *, int);
+ #if defined(USE_BASTION_APP_PROXY)
+ int Login(char *, char *, char *, char *, int);
+ #else
int Login(char *, char *, char *);
+ #endif
void PostCloseStuff(void);
void DoClose(int);
int CloseCmd(int, char **);
diff -c ../ncftp-2.4.0/ncftp.1 ./ncftp.1
*** ../ncftp-2.4.0/ncftp.1 Wed Oct 16 21:11:08 1996
--- ./ncftp.1 Thu Oct 17 21:36:59 1996
***************
*** 1,4 ****
! .\"-------
.\" Man page portability notes
.\"
.\" These are some notes on conventions to maintain for greatest
--- 1,4 ----
! .\"-------
.\" Man page portability notes
.\"
.\" These are some notes on conventions to maintain for greatest
***************
*** 75,86 ****
--- 75,90 ----
.\"-------
.PP
Program options:
+ -S : Always connect locally, unless overridden by open -b
+ -B : Always connect via the proxy, unless overridden by open -s
-D : Turn debug mode and trace mode on.
-L : Don't use visual mode (use line mode).
-V : Use visual mode.
-H : Dump the version information.
.PP
Command-line open options:
+ -s : Connect directly, ignoring the local domain matching.
+ -b : Connect via the proxy, ignoring the local domain matching.
-a : Open anonymously.
-u : Open with username and password prompt.
-p X : Use port number X when opening.
***************
*** 1618,1623 ****
--- 1622,1669 ----
.PP
This tries redialing that host every two minutes, and fetching all files
from the ``/pub/stuff'' directory that are 3 days old or newer.
+ .\"-------
+ .SH "ENVIRONMENT VARIABLES"
+ .\"-------
+ .I NcFTP
+ will use the proxy host listed in
+ .I INTERNET_HOST,
+ or will default to the compiled-in option (firewall.lehman.com).
+ .PP
+ .I NcFTP
+ will connect to the proxy port listed in
+ .I INTERNET_FTP_PORT.
+ If
+ .I INTERNET_FTP_PORT
+ is not set,
+ .I NcFTP
+ will fall back to the port for the service ftp-passthru/tcp. If there is no
+ entry for the service ftp-passthru/tcp,
+ .I NcFTP
+ will use a default of 21.
+ .PP
+ .I NcFTP
+ will match all hosts against those listed in
+ .I LOCAL_DOMAINS.
+ If the IP address or domain matches, it will try and connect locally (or
+ remotely if the rule is negated). Otherwise, it will try to use the bastion
+ host defined by
+ .I INTERNET_HOST.
+ This behaviour is overridden by the -S and -B program options, and by the -s
+ and -b options to open.
+ .PP
+ The format of
+ .I LOCAL_DOMAINS
+ is a colon seperated list of IP address / netmask pairs (with the netmask
+ being optional and defaulting to 255.255.255.255), and domain names with a
+ leading period. Any entry beginning with an exclamation point is treated as
+ a non-local domain (entries are matched left to right, returning on the
+ first match). For example:
+ .Ds
+ csh> setenv LOCAL_DOMAIN "!.firewall.lehman.com:.lehman.com:146.127.0.0/255.255.0.0:198.242.89.1"
+ .De
+ would match the 146.127 network, the host 198.242.89.1, and any host whose
+ name ends in .lehman.com, except for those whose names ended in .firewall.lehman.com.
.\"-------
.SH "AUTHOR"
.\"-------
|
|