For no particular reason, I've collected a lot of tools and trick for
tunneling one network through another. In addition to OpenVPN, IPSec,
and other dedicated tools designed to provide Virtual Private Network
functionality, I've played around a lot with running IP traffic through
SSH, SSL, and even plain HTTP tunnels.
This is typically done when you want to get around someone's firewall, but also can be convenient for bridging local area protocols (such as old school LAN games like DOOM) across the Internet. Yeah, OK, but mostly its for piercing firewalls.
This is typically done when you want to get around someone's firewall, but also can be convenient for bridging local area protocols (such as old school LAN games like DOOM) across the Internet. Yeah, OK, but mostly its for piercing firewalls.
At one time I had a script that called a custom piece of C code that would set up a pseudo TTY master/slave pair, then it would fork() to create a child process, running pppd on the parent process/master TTY and an ssh session on the child process/slave TTY. On the other end of the SSH session it would run another instance of pppd. The result was basically a hacked up virtual serial port with a Point-to-Point Protocol network link running over it.
Today that approach is superseded in a number of ways. I use OpenVPN in most situations, because tunneling is what it was designed meant for, yet its easier than setting up IPSec, and it has a higher interoperability track record. But there are times where even OpenVPN has too much configuration overhead, especially if I'm looking for a temporary solution. pppd now has a "pty" command, which let me replace my hacky C program but otherwise follows the same virtual serial port design described above. Even more recently, OpenSSH's ssh client has the "-w" flag, which in Linux and probably other free OSes instructs the local and remote machines to set up virtual network interfaces ("tun" devices). socat has a similar ability with the TUN "address specification". OpenVPN and other some tunneling software use the same kind of "tun" device. VirtualBox can "tun" devices to create a virtual network between the virtual computer and the real one.
However, until now every tunneling solution I came up with required that I have root access on both sides of the tunnel. This is usually not a problem, but just for kicks I developed a solution where you only need root access on the local side. You still need to be able to run a process on the remote machine, but it can be as an unprivileged user. There's very little local configuration. There's also no configuration on the remote side other than having login access (through SSH) and knowing where the slirp binary is.
The key piece of this solution is slirp. slirp is a SLIP/PPP emulator. (Does anyone still use SLIP?) It receives IP packets from a (virtual or physical) serial link, but converts the data into regular BSD socket system calls--that's why it doesn't need to run as root. So really, I'm not doing anything too clever, because this is more or less what slirp was designed for. I just came up with what I think is a pretty slick script for easily setting up a slirp-based PPP session running through an SSH session.
EXAMPLE
anu@pctipsbyanu:~$ sudo ~/bin/pppsshslirp foo.com
running under sudo, assuming you want to run ssh as anu, not as root
Using interface ppp0
Connect: ppp0 <--> /dev/pts/11
local IP address 10.0.2.15
remote IP address 192.168.50.3
anu@pctipsbyanu:~$ sleep 10 && ifconfig ppp0
ppp0 Link encap:Point-to-Point Protocol
inet addr:10.0.2.15 P-t-P:192.168.50.3 Mask:255.255.255.255
UP POINTOPOINT RUNNING NOARP MULTICAST MTU:1500 Metric:1
RX packets:12 errors:1 dropped:0 overruns:0 frame:0
TX packets:12 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:3
RX bytes:104 (104.0 b) TX bytes:113 (113.0 b)
anu@pctipsbyanu:~$
It takes a few seconds to set up, which is why I had it sleep 10 seconds before looking at the ppp0 interface. The delay is a factor of how long the remote login takes.
USAGE
anu@pctipsbyanu:~$ pppsshslirp -h
Usage: pppsshslirp [-h] [-u #] [-d] [-i /path/to/ssh/privkey] [-p ssh_port] [username@]remotehost
-h This helpful information.
-u # Specify the ppp device number (e.g. ppp0, ppp4, etc).
-d Don't let pppd go into the background.
-i /path/... Specify the ssh private key. pppsshslirp will use the
default ssh file (~/.ssh/id_rsa) UNLESS run through
sudo, when it will try to guess the private key of the user calling
the script, rather than root. If pppsshslirp guesses wrong, use this flag
to override it.
-p ssh_port Tell ssh to use another network port.
username@... The user on the remote host to log in as. If
username is not specified, pppsshslirp will use the
current user UNLESS run through sudo, when it will try to guess
the user calling the script, rather than root. If pppsshslirp guesses
wrong, or you just need to log in as a different user, set the
username accordingly.
remotehost The only required option, the remote host
where slirp will be run.
pppsshslirp is copyright 2008 by Jeremy D. Impson.
Licensed under the Apache License, Version 2.0 (the License); you
may not use this file except in compliance with the License. You may
obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an AS IS BASIS, WITHOUT
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
License for the specific language governing permissions and limitations
under the License.
You may want to skip to the end of the code, because all the interesting stuff happens down there.
#!/bin/sh
###
# pppsshslirp sets up pppd to connect to a remote machine via SSH,
# where it runs slirp to complete the PPP connection.
###
# Copyright 2008 by Jeremy D. Impson
###
# User tunable parameters
###
# location of slirp on the remote machine; can't figure out an elegant way to make this dynamic if the remote PATH variable isn't set right.
SLIRP=/home/anu/bin/slirp;
SLIRPARGS=""
TIMEOUT=6;
###
# this stuff needs to be set before parsing command line args so
# the user can override them.
###
# figure out the user; used later
if [ ! -z "$SUDO_USER" ]; then
echo "running under sudo, assuming you want to run ssh as $SUDO_USER, not as root" >&2 ;
MYUSER=$SUDO_USER;
TMP="/home/$MYUSER/.ssh/id_rsa";
if test -e "$TMP"; then
SSHKEY="-i $TMP";
else
SSHKEY="";
fi
else
if [ -z "$USER" ]; then MYUSER="$LOGNAME"; else MYUSER="$USER"; fi
fi
PPPDETACH=updetach;
###
# parse the command line
###
while [ ! -z "$1" ]; do
case "$1" in
"-h") HELP=1;;
"-d") PPPDETACH=nodetach;;
"-p") shift; SSHOPTS="$SSHOPTS -p $1";;
"-i") shift; SSHKEY="-i $1";;
"-u") shift; PPPARGS="$PPPARGS unit $1";;
*) SSHDEST="$1";
esac;
shift;
done
if [ ! -z "$SUDO_USER" ] && [ -z "$SSHKEY" ]; then
echo "can't find SSH key material for $MYUSER (tried $TMP), falling back to ssh default behaviour (which will probably be to use root's keys)" >&2;
fi
###
# usage
###
if [ -z "$SSHDEST" ] || [ ! -z $HELP ]; then
ME=`basename "$0"`;
echo "Usage: $ME [-h] [-u #] [-d] [-i /path/to/ssh/privkey] [-p ssh_port] [username@]remotehost";
echo "
-h This helpful information.
-u # Specify the ppp device number (e.g. ppp0, ppp4, etc).
-d Don't let pppd go into the background.
-i /path/... Specify the ssh private key. $ME will use the
default ssh file (~/.ssh/id_rsa) UNLESS run through
sudo, when it will try to guess the private key of the user calling
the script, rather than root. If $ME guesses wrong, use this flag
to override it.
-p ssh_port Tell ssh to use another network port.
username@... The user on the remote host to log in as. If
username is not specified, $ME will use the
current user UNLESS run through sudo, when it will try to guess
the user calling the script, rather than root. If $ME guesses
wrong, or you just need to log in as a different user, set the
username accordingly.
remotehost The only required option, the remote host
where slirp will be run.
$ME is copyright 2008 by Jeremy D. Impson.
Licensed under the Apache License, Version 2.0 (the "License"); you
may not use this file except in compliance with the License. You may
obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
License for the specific language governing permissions and limitations
under the License.
";
exit 1;
fi
###
# rest of the configuratin'
###
# if the user didn't specify the remote account name, set it.
if ! echo $SSHDEST | grep -q '@'; then
SSHDEST="$MYUSER@$SSHDEST";
fi
# PPP config (local machine)
PPPD=/usr/sbin/pppd
PPPARGS="$PPPARGS connect-delay ${TIMEOUT}000";
PPPARGS="$PPPARGS noproxyarp";
PPPARGS="$PPPARGS $PPPDETACH";
# ssh config
SSHPTY="/usr/bin/ssh -e none -t -q -x \
-o \"Batchmode yes\" \
-o \"StrictHostKeyChecking no\" \
$SSHKEY \
$SSHOPTS \
$SSHDEST \
\"$SLIRP -P $SLIRPARGS\"";
###
# start pppd here, connect to remote machine via ssh, and start slirp there.
###
cd /tmp
$PPPD $PPPARGS pty "$SSHPTY"
exit 0
The easiest way to understand this script is to start from the bottom. The second to last line (starting "$PPPD") runs pppd with some PPPARGS and a pty command. See pppd's man page to understand the $PPPARGS, and be aware that you might have to increase the value of $TIMEOUT at the top if it takes a while to log in to the remote host. pppd uses the pty command to set up the actual link to the other side of the PPP connection. The pty command is in $SSHPTY, an ssh command which connects to $SSHDEST (the remote system) and runs $SLIRP (slirp). slirp and pppd can now talk to each other over the ssh session as though it were a physical serial connection. The rest of the arguments to ssh basically make the virtual serial connection behave correctly as a tunnel.
I specifically wrote this script to work when run under sudo. As mentioned above, you do need root access on the local system to run this script. Normally if you run ssh under sudo, ssh will try to use root's key material, and try to log in to the remote machine as root. pppsshslirp assumes you don't want this behaviour, but instead want to use your normal user's key material on the local machine, and to connect to the remote machine as the same user. This is why there's all that up front code to determine $MYUSER and $SSHKEY. You can override this behaviour either by using the right command line options, or becoming root to run the script rather than using sudo. (But if you have root access to the remote machine, why do you need pppsshslirp?)
pppsshslirp suffers from the same limitation of any pppd-based VPN--pppd actually rate limits itself, because it thinks it's attached to a dedicated physical link e.g. (serial port), and it has to know how much capacity is there, so it doesn't exceed it and either block or drop packets. At least, I think it's rate limited. It used to be, but perhaps by now it knows that if it's not attached to a real TTY (aka serial port), not to restrain itself. An investigation for a later date...
Another limitation, this one stemming through the use of slirp, is that while your local machine has an IP tunnel to the remote machine, and ultimately to any other computer or network that the remote machine has access to, the reverse is not true. The remote machine has no idea that it's the endpoint for your tunnel. Specifically, the IP address assigned to the local machine is not publicly routable. In fact, nothing is aware of it except for your local machine. This is identical to the limitations found when doing IP Masquerading (like most Broadband Routers can do). However, slirp can be configured to do port redirection (again, like most Broadband Router can do). Since slirp is running as a normal user on the remote machine, this means you probably can't redirect on well-known ports for services like HTTP and SSH. You can put additional slirp commandline arguments in the SLIRPARGS variable. See slirp's man page for more details on port redirection.
While PPP and pppd work with more than IP (e.g. IPX and IPv6), slirp does not, so no getting too clever.
It might be cool to integrate this capability into the system-wide PPP setup (all the stuff in /etc/ppp/*) so that you could just do "ifup ppp0" or use a GUI tool, but that's a subject for future investigation. It would also be cool to replace SSH with SSL (using stunnel or socat, perhaps), although both of those approaches would require slightly more configuration on the remote side.
I haven't tested what happens when you don't have SSH key material set up. It should work, but it's possible that the password prompt from ssh will get messed up because it's being run through pppd.
CREDIT GOES TO : jdimpson
Thanks...
1 comments:
csmuukraine.blogspot.com
excelishan.blogspot.com
Post a Comment