Combining Transparent Proxying with SSH Port Forwarding

Markus Friedl markus at openbsd.org
Fri Sep 12 19:05:15 EST 2003


On Fri, Sep 12, 2003 at 12:04:33AM -0500, Greg Houlette wrote:
> The Dynamic Forwarding that is currently in OpenSSH (-D option)
> which uses the SOCKS protocol, still requires an application-level
> 'socksifier' to provide transparency on the client side, but lacks
> other features of a traditional transparent proxy (such as NAT)?

using the attached patch you can redirect
traffic to the -D port.  using OpenBSD's NAT
this wold look like:

   rdr on eth0 inet proto tcp from any to 10/8 -> 127.0.0.1 port 8080

> I haven't seen or used any of the patches that Damien mentioned, and

see below.

> [...]
> The idea of a standalone transparent NAT -> SOCKS gateway daemon
> is something that I haven't seen, let alone with the other features
> that I mentioned in my post.  That does seem like a good starting
> point though.  And I like the independent utility aspect of it.
> 
> I wish Markus would elaborate about what he's using?

a process listens to a port, the kernel NAT rules redirect traffic
to this port, process does NAT lookup and connects to ssh's -D port
after converting the NAT state to a SOCKS4 request.

Index: channels.c
===================================================================
RCS file: /cvs/src/usr.bin/ssh/channels.c,v
retrieving revision 1.194
diff -u -r1.194 channels.c
--- channels.c	29 Aug 2003 10:04:36 -0000	1.194
+++ channels.c	11 Sep 2003 15:59:59 -0000
@@ -41,6 +41,10 @@
 #include "includes.h"
 RCSID("$OpenBSD: channels.c,v 1.194 2003/08/29 10:04:36 markus Exp $");
 
+#include <netinet/in.h>
+#include <net/if.h>
+#include <net/pfvar.h>
+
 #include "ssh.h"
 #include "ssh1.h"
 #include "ssh2.h"
@@ -870,6 +874,73 @@
 	}
 }
 
+static int
+natlookup(int fd, struct sockaddr_in *server)
+{
+	struct pfioc_natlook natlook;
+	struct sockaddr_in from, to;
+	socklen_t slen;
+	int pfd;
+
+	slen = sizeof(from);
+	if (getpeername(fd, (struct sockaddr *)&from, &slen) != 0) {
+		debug("getpeername failed: %s", strerror(errno));
+		return (-1);
+	}
+	slen = sizeof(to);
+	if (getsockname(fd, (struct sockaddr *)&to, &slen) != 0) {
+		debug("getsockname failed: %s", strerror(errno));
+		return (-1);
+	}
+
+	memset(&natlook, 0, sizeof(natlook));
+	natlook.af = AF_INET;
+	natlook.saddr.addr32[0] = from.sin_addr.s_addr;
+	natlook.daddr.addr32[0] = to.sin_addr.s_addr;
+	natlook.proto = IPPROTO_TCP;
+	natlook.sport = from.sin_port;
+	natlook.dport = to.sin_port;
+	natlook.direction = PF_OUT;
+
+	if ((pfd = open("/dev/pf", O_RDWR)) == -1) {
+		debug("open /dev/pf failed: %s", strerror(errno));
+		return (-1);
+	}
+	if (ioctl(pfd, DIOCNATLOOK, &natlook) == -1) {
+		error("pf nat lookup failed: %s", strerror(errno));
+		close(pfd);
+		return (-1);
+	}
+	close(pfd);
+
+	server->sin_port = natlook.rdport;
+	server->sin_addr.s_addr = natlook.rdaddr.addr32[0];
+	server->sin_len = sizeof(struct sockaddr_in);
+	server->sin_family = AF_INET;
+	return (0);
+}
+
+static int
+channel_try_nat(Channel *c)
+{
+	char *host;
+	struct sockaddr_in server;
+
+	memset(&server, 0, sizeof(server));
+
+	if (natlookup(c->rfd, &server) < 0)
+		return (0);
+
+	host = inet_ntoa(server.sin_addr);
+	strlcpy(c->path, host, sizeof(c->path));
+	c->host_port = ntohs(server.sin_port);
+
+	debug("channel %d: nat request: host %s port %u",
+	    c->self, host, c->host_port);
+
+	return (1);
+}
+
 /* try to decode a socks4 header */
 static int
 channel_decode_socks4(Channel *c, fd_set * readset, fd_set * writeset)
@@ -1060,6 +1131,10 @@
 
 	have = buffer_len(&c->input);
 	c->delayed = 0;
+
+	if ((ret = channel_try_nat(c)))
+		goto done;
+
 	debug2("channel %d: pre_dynamic: have %d", c->self, have);
 	/* buffer_dump(&c->input); */
 	/* check if the fixed size part of the packet is in buffer. */
@@ -1081,6 +1156,8 @@
 		ret = -1;
 		break;
 	}
+
+done:
 	if (ret < 0) {
 		chan_mark_dead(c);
 	} else if (ret == 0) {
@@ -1168,6 +1245,8 @@
 	    "connect from %.200s port %d",
 	    rtype, c->listening_port, c->path, c->host_port,
 	    remote_ipaddr, remote_port);
+
+debug("%s", buf);
 
 	xfree(c->remote_name);
 	c->remote_name = xstrdup(buf);




More information about the openssh-unix-dev mailing list