This is a patch for ssh (tested with version 1.2.21, may need minor modifications for other versions) to be able to have socks-like transparent forwarding through ssh. Advantages: - You do only need a normal sshd on the other side (no socksd or alike). - You have encryption to the host on the other side (no to the target!) - You dont have to change your software (like with socks) - You can use this on a local router to route a whole local network (untested under heavier load) Disadvantages: - You need linux on the client machine - You cant forward udp If you add this patch to a ssh distribution (which I would appreciate), please put my name somewhere in it and send me a little note. If you have replies for me, please contact me directly, I am not in the ssh mailing list. DniQ.
Building a transparent proxy through firewalls using ssh ======================================================== Prerequisites: Linux on your machine A host which is not firewalled on which you have an ssh-able account This patch This patch is needed to have dynamic port forwarding with ssh (probably only under Linux). How to use: 1. Create a transparent firewall rule for all connections to be routed through ssh on local port <port> 2. Run ssh with -L <port>:DYN:0. 3. Make a connect to any address covered by the above firewalling rule. The connection will be routed through ssh and connect from the remote host to the target How it works: If the target host name is "DYN", ssh will check via getsockname which host/port the connection is for. At least under Linux, Kernel 2.0.35 this will be the original target, not the local port which ssh is listening on. Hint: If you want to forward connections originating from the local host, you wont be able to simple make a firewalling rule like -I -D <dest> -P tcp -r <port>, because this will only route incoming connections. The only workaround I found was to route the connection to be forwarded through the loopback device and then apply the firewalling rule, because connections through lo will be handled as outgoing and incoming connections at the same time (You'll have to take a larger netmask for lo than). Comment: This was tested on my computer for several months. I am behind a firewall in our universitary network and running Linux 2.0.35. There is no change on the sshd needed. Sample: # if forwarding shall be for routed connections only: # Reroute connections to be forwarded ipfwadm -I -a accept -D <what to forward> -r <someport> # Tell ssh to forward ssh <normal connection information> -L <someport>:DYN:0 # end # or, if locally originating connections should be forwarded, too # To be able to route everything through it ifconfig lo netmask 0.0.0.0 # Route connections to be forwarded through lo route add -net <net to be routed> netmask <netmask for net> dev lo # Dont reroute normal loopback traffic ipfwadm -I -a accept -D 127.0.0.0/8 -W lo # Reroute connections to be forwarded ipfwadm -I -a accept -P tcp -D 0/0 -W lo -r <someport> # Tell ssh to forward ssh <normal connection information> -L <someport>:DYN:0 # end diff -u -r ssh-1.2.21-old/newchannels.c ssh-1.2.21/newchannels.c --- newchannels.c Fri Aug 22 02:28:27 1997 +++ newchannels.c Tue Oct 13 23:53:43 1998 @@ -969,8 +969,27 @@ xstrdup(buf)); packet_start(SSH_MSG_PORT_OPEN); packet_put_int(newch); - packet_put_string(ch->path, strlen(ch->path)); - packet_put_int(ch->host_port); + if (strcmp(ch->path,"DYN")) { + packet_put_string(ch->path, strlen(ch->path)); + packet_put_int(ch->host_port); + } else { + struct sockaddr_in dyntarg; + size_t dyntargsize; + const char *dyn_host; + int dyn_port; + + dyntargsize = sizeof(dyntarg); + if (getsockname(newsock,(struct sockaddr *)&dyntarg, &dyntargsize)<0) { + error("getsockname: %.100s", strerror(errno)); + channel_free(newch); + break; + }; + dyn_host = inet_ntoa(dyntarg.sin_addr); + dyn_port = htons(dyntarg.sin_port); + log_msg("Dyncamic channel to %.30s:%d",dyn_host,dyn_port); + packet_put_string(dyn_host,strlen(dyn_host)); + packet_put_int(dyn_port); + }; if (have_hostname_in_open) packet_put_string(buf, strlen(buf)); packet_send();