[Patch] SSH through HTTP proxy using CONNECT

Archie Cobbs archie at packetdesign.com
Thu Jul 18 09:18:32 EST 2002


Hi,

I'm not a subscriber to this list so please CC: me in any replies.

I found myself in a situation where I was behind a corporate firewall
that allowed only web requests to the outside world (and furthermore
those requests had to be via their proxy server). Therefore, I couldn't
SSH to the outside world.

However, the HTTP proxy 'CONNECT' method, which is normally used to
support SSL requests, can be used to do this. This worked great for me.

Attached is a patch to SSH version 2.9 (comes with FreeBSD 4.5-REL)
to implement 'ProxyServer' and 'ProxyPort' options, also specifiable
on the command line using '-r'.

E.g.:

  ssh -r 10.12.114.3:8080 foobar at some.server.com

Then ssh will go through the HTTP proxy at 10.12.114.3 8080
and tell it to 'CONNECT' to 'some.server.com:22'.

I found it useful so perhaps others would too. Please let me know
whether or not you decide to include it in the standard SSH.

Thanks,
-Archie

__________________________________________________________________________
Archie Cobbs     *     Packet Design     *     http://www.packetdesign.com
-------------- next part --------------
diff -ur -x CVS /usr/src/crypto/openssh/readconf.c src/readconf.c
--- /usr/src/crypto/openssh/readconf.c	Thu Sep 27 18:33:34 2001
+++ src/readconf.c	Wed Jul 17 16:14:44 2002
@@ -108,6 +108,7 @@
 #endif
 	oIdentityFile, oHostName, oPort, oCipher, oRemoteForward, oLocalForward,
 	oUser, oHost, oEscapeChar, oRhostsRSAAuthentication, oProxyCommand,
+	oProxyServer, oProxyPort,
 	oGlobalKnownHostsFile, oUserKnownHostsFile, oConnectionAttempts,
 	oBatchMode, oCheckHostIP, oStrictHostKeyChecking, oCompression,
 	oCompressionLevel, oKeepAlives, oNumberOfPasswordPrompts,
@@ -158,6 +159,8 @@
 	{ "hostname", oHostName },
 	{ "hostkeyalias", oHostKeyAlias },
 	{ "proxycommand", oProxyCommand },
+	{ "proxyserver", oProxyServer },
+	{ "proxyport", oProxyPort },
 	{ "port", oPort },
 	{ "cipher", oCipher },
 	{ "ciphers", oCiphers },
@@ -484,6 +487,14 @@
 			xfree(string);
 		return 0;
 
+	case oProxyServer:
+		charptr = &options->proxy_server;
+		goto parse_string;
+
+	case oProxyPort:
+		intptr = &options->proxy_port;
+		goto parse_int;
+
 	case oPort:
 		intptr = &options->port;
 parse_int:
@@ -765,6 +776,8 @@
 	options->hostname = NULL;
 	options->host_key_alias = NULL;
 	options->proxy_command = NULL;
+	options->proxy_server = NULL;
+	options->proxy_port = -1;
 	options->user = NULL;
 	options->escape_char = -1;
 	options->system_hostfile = NULL;
@@ -894,6 +907,7 @@
 	if (options->log_level == (LogLevel) - 1)
 		options->log_level = SYSLOG_LEVEL_INFO;
 	/* options->proxy_command should not be set by default */
+	/* options->proxy_server should not be set by default */
 	/* options->user will be set in the main program if appropriate */
 	/* options->hostname will be set in the main program if appropriate */
 	/* options->host_key_alias should not be set by default */
diff -ur -x CVS /usr/src/crypto/openssh/readconf.h src/readconf.h
--- /usr/src/crypto/openssh/readconf.h	Thu Sep 27 18:33:34 2001
+++ src/readconf.h	Wed Jul 17 16:14:44 2002
@@ -83,6 +83,8 @@
 	char   *hostname;	/* Real host to connect. */
 	char   *host_key_alias;	/* hostname alias for .ssh/known_hosts */
 	char   *proxy_command;	/* Proxy command for connecting the host. */
+	char   *proxy_server;	/* HTTP proxy server to relay through. */
+	int	proxy_port;	/* HTTP proxy server port. */
 	char   *user;		/* User to log in as. */
 	int     escape_char;	/* Escape character; -2 = none */
 
diff -ur -x CVS /usr/src/crypto/openssh/ssh.c src/ssh.c
--- /usr/src/crypto/openssh/ssh.c	Thu Sep 27 18:33:35 2001
+++ src/ssh.c	Wed Jul 17 16:14:44 2002
@@ -175,6 +175,7 @@
 	fprintf(stderr, "  -R listen-port:host:port   Forward remote port to local address\n");
 	fprintf(stderr, "              These cause %s to listen for connections on a port, and\n", __progname);
 	fprintf(stderr, "              forward them to the other side by connecting to host:port.\n");
+	fprintf(stderr, "  -r host:prt Connect using specified HTTP proxy.\n");
 	fprintf(stderr, "  -C          Enable compression.\n");
 	fprintf(stderr, "  -N          Do not execute a shell or command.\n");
 	fprintf(stderr, "  -g          Allow remote hosts to connect to forwarded ports.\n");
@@ -309,7 +310,7 @@
 		opt = av[optind][1];
 		if (!opt)
 			usage();
-		if (strchr("eilcmpLRDo", opt)) {   /* options with arguments */
+		if (strchr("eilcmpLRDor", opt)) {  /* options with arguments */
 			optarg = av[optind] + 2;
 			if (strcmp(optarg, "") == 0) {
 				if (optind >= ac - 1)
@@ -481,6 +482,15 @@
 				/* NOTREACHED */
 			}
 			add_local_forward(&options, fwd_port, buf, fwd_host_port);
+			break;
+		case 'r':
+			if (sscanf(optarg, "%255[^:]:%u", buf,
+			    &options.proxy_port) != 2) {
+				fprintf(stderr, "Bad HTTP proxy '%s'.\n", optarg);
+				usage();
+				/* NOTREACHED */
+			}
+			options.proxy_server = xstrdup(buf);
 			break;
 
 		case 'D':
diff -ur -x CVS /usr/src/crypto/openssh/sshconnect.c src/sshconnect.c
--- /usr/src/crypto/openssh/sshconnect.c	Thu Sep 27 18:33:35 2001
+++ src/sshconnect.c	Wed Jul 17 16:14:44 2002
@@ -198,7 +198,9 @@
 	int gaierr;
 	int on = 1;
 	int sock = -1, attempt;
+	int connect_port;
 	char ntop[NI_MAXHOST], strport[NI_MAXSERV];
+	const char *connect_host;
 	struct addrinfo hints, *ai, *aitop;
 	struct linger linger;
 	struct servent *sp;
@@ -218,14 +220,21 @@
 	if (proxy_command != NULL)
 		return ssh_proxy_connect(host, port, pw, proxy_command);
 
-	/* No proxy command. */
+	/* If an HTTP proxy is given, connect to it first. */
+	if (options.proxy_server != NULL) {
+		connect_host = options.proxy_server;
+		connect_port = options.proxy_port;
+	} else {
+		connect_host = host;
+		connect_port = port;
+	}
 
 	memset(&hints, 0, sizeof(hints));
 	hints.ai_family = IPv4or6;
 	hints.ai_socktype = SOCK_STREAM;
-	snprintf(strport, sizeof strport, "%d", port);
-	if ((gaierr = getaddrinfo(host, strport, &hints, &aitop)) != 0)
-		fatal("%s: %.100s: %s", __progname, host,
+	snprintf(strport, sizeof strport, "%d", connect_port);
+	if ((gaierr = getaddrinfo(connect_host, strport, &hints, &aitop)) != 0)
+		fatal("%s: %.100s: %s", __progname, connect_host,
 		    gai_strerror(gaierr));
 
 	/*
@@ -293,6 +302,29 @@
 	/* Return failure if we didn't get a successful connection. */
 	if (attempt >= connection_attempts)
 		return 0;
+
+	/* Connect through HTTP proxy. */
+	if (options.proxy_server != NULL) {
+		char buf[512];
+		int state;
+		char byte;
+
+		debug("Sending proxy CONNECT.");
+
+		snprintf(buf, sizeof(buf), "CONNECT %s:%d HTTP/1.0\r\n\r\n",
+		    host, port);
+		write(sock, buf, strlen(buf));
+		for (state = 0; state < 4; ) {
+			if (read(sock, &byte, 1) != 1)
+				return 0;
+			if (byte == ((state & 1) ? '\n' : '\r'))
+				state++;
+			else
+				state = 0;
+		}
+
+		debug("Read proxy response.");
+	}
 
 	debug("Connection established.");
 


More information about the openssh-unix-dev mailing list