LDP/LDP/howto/docbook/VPN-PPP-SSH-HOWTO/ppp-ssh.sgml

1626 lines
44 KiB
Plaintext
Raw Permalink Blame History

<!DOCTYPE Article PUBLIC "-//OASIS//DTD DocBook V4.1//EN" [
<!-- Is there any HOWTO on SysV Initscripts? Put it in section 7.1 (search for "System V") -->
<!-- Bring in the vpn-pppssh shell script -->
<!ENTITY pppsshlisting SYSTEM "vpn-pppssh">
<!-- HOWTOs referenced from this one -->
<!ENTITY advroutehowto '<ulink URL="http://www.linuxdoc.org/HOWTO/Adv-Routing-HOWTO.html">http://www.linuxdoc.org/HOWTO/Adv-Routing-HOWTO.html</ulink>'>
<!ENTITY bashscriptinghowto '<ulink URL="http://www.linuxdoc.org/HOWTO/Bash-Prog-Intro-HOWTO.html">BASH Programming Introduction</ulink>'>
<!ENTITY cipemasq '<ulink url="http://www.linuxdoc.org/HOWTO/mini/Cipe+Masq.html">http://www.linuxdoc.org/HOWTO/mini/Cipe+Masq.html</ulink>'>
<!ENTITY firewallhowto '<ulink URL="http://www.linuxdoc.org/HOWTO/Firewall-HOWTO.html">Linux Firewall HOWTO</ulink>'>
<!ENTITY ipchainshowto '<ulink URL="http://www.linuxdoc.org/HOWTO/IPCHAINS-HOWTO.html">IPChains HOWTO</ulink>'>
<!ENTITY kernhowto '<ulink URL="http://www.linuxdoc.org/HOWTO/Kernel-HOWTO.html">Linux Kernel HOWTO</ulink>'>
<!ENTITY linsechowto '<ulink URL="http://www.linuxdoc.org/HOWTO/Security-HOWTO.html">Linux Security HOWTO</ulink>'>
<!ENTITY masqhowto '<ulink URL="http://www.linuxdoc.org/HOWTO/IP-Masquerade-HOWTO.html">IP Masquerade HOWTO</ulink>'>
<!ENTITY networkhowto '<ulink URL="http://www.linuxdoc.org/HOWTO/Networking-Overview-HOWTO.html">http://www.linuxdoc.org/HOWTO/Networking-Overview-HOWTO.html</ulink>'>
<!ENTITY ppphowto '<ulink URL="http://www.linuxdoc.org/HOWTO/PPP-HOWTO/index.html">http://www.linuxdoc.org/HOWTO/PPP-HOWTO/index.html</ulink>'>
<!ENTITY vihowto '<ulink URL="http://www.linuxdoc.org/HOWTO/Vim-HOWTO.html">VIM HOWTO</ulink>'>
<!-- Guides referenced from this howto -->
<!-- (guides should all have a homepage where the user can select the format to download -->
<!-- for now, we'll just force the user to download the HTML) -->
<!ENTITY advbashguide '<ulink URL="http://www.linuxdoc.org/LDP/abs/html/index.html">Advanced Bash Scripting Guide</ulink>'>
<!ENTITY lasg '<ulink URL="http://www.seifried.org/lasg/">Linux Administrator&#39;s Security Guide</ulink>'>
<!-- Other documents referenced from this howto -->
<!ENTITY openssh '<ulink URL="http://www.openssh.org/">OpenSSH</ulink>'>
<!ENTITY sudoshomepage '<ulink URL="http://www.courtesan.com/sudo/">sudo&#39;s home page</ulink>'>
<!ENTITY vpnfaq '<ulink URL="http://kubarb.phsx.ukans.edu/~tbird/vpn/FAQ.html">http://kubarb.phsx.ukans.edu/~tbird/vpn/FAQ.html</ulink>'>
]>
<article id="index">
<articleinfo>
<title>VPN PPP-SSH Mini-HOWTO</Title>
<author>
<firstname>Scott</firstname> <surname>Bronson</surname>
<affiliation>
<address><email>bronson@trestle.com</email></address>
</affiliation>
</author>
<abstract>
<para>
A PPP-SSH VPN is probably the easiest type of VPN to set up.
It uses nothing more than the very common PPP and SSH utilities
to form an encrypted network tunnel between two hosts.
</para>
</abstract>
<pubdate>2001-07-29</pubdate>
<revhistory>
<!-- most recent rev belongs at top -->
<revision>
<revnumber>v1.00</revnumber>
<date>2002-01-16</date>
<authorinitials>sb</authorinitials>
<revremark>Initial (public) release. </revremark>
</revision>
</revhistory>
</articleinfo>
<sect1 id="intro">
<title>Introduction</title>
<para>
The technique described in this HOWTO uses PPP to convert packets
into a character stream and SSH to encrypt it
and transmit it to the remote computer. Most system administrators
are well acquainted with the tools and configuration files needed
to set up a PPP-SSH VPN.
</para>
<para>
While it works well with moderate loads over a reliable
connection, be warned that a PPP-SSH VPN is subject to
some scalability problems. I've included a list of benefits in
<xref linkend="benefits"> and drawbacks in
<xref linkend="drawbacks"> so you can decide
for yourself if a PPP-SSH VPN is a good fit for your needs.
</para>
<sect2>
<title>Copyright</title>
<para>
Copyright &copy; 2001 Scott Bronson. This document may be distributed
under the terms set forth in the GNU Free Documentation License.
A copy of this license can be found at
<ulink url="http://www.fsf.org/licenses/fdl.html">http://www.fsf.org/licenses/fdl.html</ulink>.
</para>
</sect2>
<sect2>
<title>Disclaimer</title>
<para>
You use the information in this document entirely at your own risk.
I especially make no guarantees as to the legality or cryptographic strength
of the techniques described here.
If you feel that you cannot take full responsibility
for your setup, then you need to put
down this HOWTO and hire one of the many excellent companies who
provide accountable, professional VPN service.
</para>
</sect2>
<sect2>
<title>Credits</title>
<para>
I took some notes as I adapted Bart Trojanowski's excellent
<ulink url="http://www.jukie.net/~bart/security/vpn/">
instructions</ulink> to a newer version of PPP running on
my Debian system.
A few weeks later, I converted the notes into SGML.
Eventually, those evolved into this HOWTO.
</para>
<para>
Bart's instructions were based on Arpad Magosanyi's
good but now fairly dated
<ulink url="http://www.linuxdoc.org/HOWTO/mini/VPN.html">
VPN Mini-HOWTO</ulink>.
If you run into troubles and my document doesn't seem to help,
or if you're running an older version of the Linux kernel or PPP,
you'll definitely want to give his HOWTO a read.
</para>
</sect2>
</sect1>
<sect1 id="Introduction">
<title>Introduction</title>
<sect2 id="benefits">
<title>PPP-SSH Benefits</title>
<para>
There are a number of benefits to setting up a PPP-SSH VPN.
It's relatively simple, it uses common off-the-shelf tools,
and it probably won't require a reboot before bringing up the link.
Here's a more comprehensive list:
</para>
<variablelist>
<varlistentry>
<term>Easy to install</term>
<listitem>
<para>
You probably won't need to patch or recompile your kernel, run
LILO, reboot, or perform any other perilous administration activities.
PPP and SSH are included with most distributions, and
most kernels come preconfigured to use them properly.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Easy to set up</term>
<listitem>
<para>
You should not have to edit any existing configuration files.
You simply customize the script file provided later in this document,
which contains all the VPN configuration info, and then execute it
on the client machine. Any existing PPP or SSH configurations
should continue to work just fine.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>No mucking with firewalling</term>
<listitem>
<para>
If the SSH protocol currently traverses your firewall,
then PPP over SSH will traverse your firewall as well.
(If you aren't using SSH, then why not? It is almost
a required tool for system administrators nowadays.)
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>No mucking with manual routing</term>
<listitem>
<para>
pppd automatically sets up routing for you.
And, if you have very complex routing needs, it's very easy
to put the custom routing commands in the script file.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>No need for static IP addresses</term>
<listitem>
<para>
PPP-SSH VPNs have no trouble whatsoever with dynamic IP addressess.
The client must be able to find the server to connect to, of course,
but dynamic DNS would work fine for that.
Setting up a VPN over a dialup connection is no problem.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Multiple Tunnels are Easy</term>
<listitem>
<para>
It's easy to set up multiple tunnels to a single computer.
You simply need to make sure that the IP address for
each tunnel's network interface is distinct.
</para>
</listitem>
</varlistentry>
</variablelist>
</sect2>
<sect2 id="drawbacks">
<title>PPP-SSH Drawbacks</title>
<para>
This type of VPN is not without a few difficulties.
Basically, it doesn't run unattended very well. If you're
looking for a production-quality VPN that you can
set up and forget about, you will proabably find
PPP-SSH a little disappointing. Some alternatives
are described in <xref linkend="alternatives">.
</para>
<variablelist>
<varlistentry>
<term>Trying to maintain a TCP connection</term>
<listitem>
<para>
If the SSH TCP connection is broken for any reason,
your VPN goes down hard and takes all tunnelled TCP connections with it.
If you have a less than reliable link --
say it's difficult to download more than a few tens of megabytes
at one go -- you will be re-starting the VPN a lot.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Running IP packets over a TCP stream</term>
<listitem>
<para>
The TCP protocol consists of streams layered on top
of IP packets.
When you <emphasis>then</emphasis> run IP packets
over the TCP stream (as we're attempting to do),
the personality conflict between the two can become very apparent.
Mostly, this manifests itself as weird delays, dropouts, and oscillations.
Sometimes you'll see problems at load, sometimes with next to no traffic.
Short of changing the entire OSI model (ha ha), there's not much that can
be done about this.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Tends to be bursty</term>
<listitem>
<para>
For some reason, when network load gets
high, one tunneled TCP connection tends to get all the bandwidth
and the others get ignored.
This leads to timeouts and dropped connections.
Theoretically, this is fixable.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Can't reliably tell when link is down</term>
<listitem>
<para>
Keepalives are small packets sent to tell the machine
on the other end that the connection is still up.
If the network load gets too high, keepalives
will be delayed. The other machine will mistakenly
assume the connection has
been dropped and take down its end of the link.
</para>
<para>
Without keepalives, however, there's no way for either machine tell if the
link has been dropped. When one machine tries to bring the link back up,
if the other machine thinks it already has it up, confusion can reign.
Most often this will show up as multiple ppp network devices,
duplicate routes, and tunnels that appear to be up but drop every packet.
A liberal use of "killall -9 pppd" will usually set things back in order.
A more intelligent start script could probably improve this.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Too many simultaneous connections avalanches fast</term>
<listitem>
<para>
When I use regular PPP over a 56K modem and Postfix opens 10+
connections to deliver my outgoing mail, everything works well.
However, when I try to run this exact traffic over a VPN tunneled
over a much faster DSL link, it stalls out.
Ping times skyrocket for a spell (2 minutes and beyond), traffic moves
at a trickle for a while, then it stops completely.
The only way to get packets moving again is to restart the tunnel.
I'm not sure if this is a bug or an inherent
limitation. Reducing the number of connections that Postfix maintains
for outgoing mail fixed this problem for me..
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>It's high-overhead, high-latency</term>
<listitem>
<para>
Ping times over my 57.6 modem connection are normally in the
130-170 ms range. However, ping times for a PPP-SSH VPN running
over the same modem connection are in the 300-330 ms range. Turning
on PPP compression can help a lot if you're transmitting compressible
data. Email is compressible, Vorbis files are not.
</para>
</listitem>
</varlistentry>
</variablelist>
</sect2>
<sect2>
<title>Suggested Reading</title>
<variablelist>
<varlistentry>
<term>VPN FAQ</term>
<listitem>
<para>
The VPN FAQ at &vpnfaq; is a very good resource. It's comprehensive,
kept reasonably up-to-date,
and not afraid to express an opinion.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Linux Kernel HOWTO</term>
<listitem>
<para>
If your kernel doesn't already have PPP and IP Forwarding capability
built-in, the &kernhowto; will tell you how to recompile your kernel
to add it. It will also tell you how to load and unload the PPP kernel
modules.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>PPP HOWTO</term>
<listitem>
<para>
Tells how to install and set up the PPP daemon if your distribution
did not automatically install it for you.
Also has an excellent section on linking two networks using PPP. That's
pretty much what we're doing, except that we're also encrypting it.
You can find it at &ppphowto;.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>SSH HOWTO</term>
<listitem>
<para>
I wish there were an SSH HOWTO! For now, the documentation that
comes with your distribution should be a good start. You might
also check the <ulink url="http://www.openssh.org/">OpenSSH web site</ulink>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Networking Documentation</term>
<listitem>
<para>
If you're not very familiar with networking, you'll want to scour the
<ulink url="http://www.linuxdoc.org/LDP/nag2/index.html">
Linux Network Administrators Guide</ulink>.
It's an excellent introduction to most of the concepts we'll be using here.
You may also find the Linux Networking HOWTO at &networkhowto; to be a useful introduction, especially
itse sections on TCP/IP, PPP, and tunneling.
</para>
</listitem>
</varlistentry>
</variablelist>
</sect2>
<sect2 id="alternatives">
<title>Alternatives</title>
<para>
There are a ton of VPN technologies in the world now. If PPP-SSH
doesn't fit all your needs, you might want to check one of the
following packages.
</para>
<variablelist>
<varlistentry>
<term>ipsec</term>
<listitem>
<para>
ipsec describes a set of low-level protocols,
<ulink url="http://andrew2.andrew.cmu.edu/rfc/rfc2406.html">ESP</ulink> and
<ulink url="http://andrew2.andrew.cmu.edu/rfc/rfc2402.html">AH</ulink>,
to perform authentication and encryption
at the packet level. It also uses a higher-level protocol,
<ulink url="http://andrew2.andrew.cmu.edu/rfc/rfc2408.html">IKE</ulink>,
to negotiate connection parameters and exchange encryption keys.
</para>
<para>
FreeS/WAN is probably the best Linux ipsec implementation today.
Although it can be very difficult to set up, especially for those
who are not terribly familiar with networking,
it is amazingly stable once it is working.
You can find out more at the
<ulink url="http://www.freeswan.org/">FreeS/WAN home page</ulink>.
</para>
<para>
Another good, free ipsec implementation is
<ulink url="http://www.antd.nist.gov/cerberus/">Cerberus</ulink>.
Unfortunately, the National Institute of Standards and Technology
only distributes Cerberus to US or Candadian citizens currently
located in either the US or Canada. Therefore, depending on who
you are, obtaining Cerberus ranges from moderately
difficult to effectively impossible.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>PPTP</term>
<listitem>
<para>
PPTP (Point-to-Point Tunnelling Protocol) is a Microsoft-developed
VPN protocol, described in
<ulink url="http://andrew2.andrew.cmu.edu/rfc/rfc2637.html">RFC2637</ulink>.
It is a very common and well-understood technology and has many
mature implementations on all commonly-used computer platforms.
However PPTP is generally considered to have
<ulink url="http://www.counterpane.com/pptp.html">somewhat weak security</ulink>.
</para>
<para>
Probably the best Linux PPTP implementation is PoPToP, found at
<ulink url="http://poptop.lineo.com/">http://poptop.lineo.com/</ulink>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>CIPE</term>
<listitem>
<para>
CIPE is Olaf Titz's protocol to encapsulate IP traffic over UDP packets.
It has both a
<ulink url="http://sites.inka.de/sites/bigred/devel/cipe.html">Linux version</ulink>
and a
<ulink url="http://cipe-win32.sourceforge.net/">Windows version</ulink>.
I haven't used it yet, but it is in strong development and looks very
promising. For more information, the
<ulink url="http://www.linuxdoc.org/HOWTO/mini/Cipe+Masq.html">CIPE-MASQ
Mini-HOWTO</ulink> is a terse but informative read.
</para>
</listitem>
</varlistentry>
</variablelist>
</sect2>
</sect1>
<sect1 id="installation">
<title>Software Installation</title>
<sect2>
<title>Terminology</title>
<para>
Because setting up the VPN very much resembles a client-server
transaction, I'll borrow from that terminology to give a name
to the computer at each end of the tunnel:
</para>
<variablelist>
<varlistentry>
<term>Server</term>
<listitem><para>
This is the computer that passively waits
for incoming VPN connection requests.
It runs completely unattended.
</para></listitem>
</varlistentry>
<varlistentry>
<term>Client</term>
<listitem><para>
This is the computer that initiates the connection
request, asking the Server to bring up the VPN.
</para></listitem>
</varlistentry>
</variablelist>
</Sect2>
<sect2>
<title>Requirements</title>
<itemizedlist>
<listitem>
<para>
Your kernel must have support for TCP/IP and PPP compiled in.
Almost all distributions ship with PPP support straight
out of the box. If yours didn't, or if you're using a custom kernel,
I'll include a little more detail about this in
<xref linkend="kernel">.
</para>
</ListItem>
<listitem>
<para>
You must install the pppd daemon. This most likely comes with your
distribution. I'm using ppp-2.3.11. Later versions should work just
fine, and earlier versions should also work as
well as long as they support the "pty" option. You don't need to install
chat or any of the other tools designed to work with PPP -- you just need
pppd.
</para>
</listitem>
<listitem>
<para>
The client machine needs to have the ssh client installed.
There are many different versions of ssh floating around,
but they should all work.
I'm using OpenBSD's &openssh; package version 2.2.0p1.
</para>
</listitem>
<listitem>
<para>
The server machine needs the sshd daemon to field ssh requests from
the client. OpenSSH includes a very good ssh daemon.
</para>
</listitem>
<listitem>
<para>
Finally, you want to install the sudo tool on the server.
You can find out more about sudo in the &lasg, in the Administration Tools
section, and the &linsechowto;, in the Root Security section.
You might also want to look at &sudoshomepage;.
</para>
</listitem>
</itemizedlist>
</sect2>
<sect2 id="planning">
<title>Planning</title>
<para>
To set up a PPP-SSH link, you need to specify the following parameters:
</para>
<variablelist>
<varlistentry>
<term>Server Hostname</term>
<listitem>
<para>
What is the hostname or IP address for your VPN server?
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Server VPN Username</term>
<listitem>
<para>
On your server, what username will the VPN software run under?
This HOWTO includes instructions on how to create a
user named "vpn" specifically for this.
This should <emphasis>not</emphasis> be root!
For security and logging, this should be a dedicated account.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Server Interface IP Address</term>
<listitem>
<para>
The PPP-SSH VPN sets up dedicated network interfaces on both the client
and the server. The interface will be pppN, where N is the number of
the first unused ppp interface (i.e. it will be ppp1 if you're already
using ppp0 to dial out over your modem).
</para>
<para>
You will need to specify the IP address for the interface on the server.
This address is only visible to the client and server (and to any machines
on subnets that the client and server may be forwarding
unmasqueraded packets for).
</para>
<para>
If you don't know what IP address to pick, read chapter 2.2 in the
<ulink url="http://www.linuxdoc.org/LDP/nag2/index.html">
Linux Network Administrators Guide</ulink>
and especially look at Table 2-1.
For example, 192.168.0.1 is a good choice.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Client Interface IP Address</term>
<listitem>
<para>
You need to select the IP address for the interface on the
client. It must, of course, be on the same network as the
server's IP address.
It must not conflict with any other networks on the client, nor can
it be the same as the server's network interface IP address.
If you selected 192.168.0.1 for the previous answer, you
would probably use 192.168.0.2 here.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
My setup looks like this:
</para>
<screen>
SERVER_HOSTNAME = eldivino.domain.com
SERVER_USERNAME = vpn
SERVER_IFIPADDR = 192.168.3.1
CLIENT_IFIPADDR = 192.168.3.2
</screen>
</sect2>
<sect2 id="kernel">
<title>Set Up PPP</title>
<para>
The kernel's PPP code can either be compiled into the kernel
itself or it can be put in loadable kernel modules.
If you compiled it into the kernel, you can
skip on to the next step -- you're done here.
However, if you're loading PPP as modules, you need to make
sure the modules get properly loaded.
</para>
<para>
You can check to see if ppp is listed, along with all other
currently loaded modules, when you run lsmod. Remember to check
that the PPP module is loaded on both the client and the server.
</para>
<screen>
server$ /sbin/lsmod
Module Size Used by
ppp 20780 0 (unused)
slhc 4376 0 [ppp]
3c59x 21636 1
client$ lsmod
Module Size Used by
ppp_deflate 40308 0 (autoclean)
bsd_comp 4076 0 (autoclean)
ppp 20844 2 [ppp_deflate bsd_comp]
slhc 4376 1 [ppp]
</screen>
<para>
If you're sure ppp was compiled as a module, but it's not loaded into
the kernel, try loading it with modprobe:
</para>
<screen>
# modprobe ppp
</screen>
<para>
If modprobe didn't return any errors, check lsmod again --
it should be listed this time. If so, then your ppp module
is not being loaded at boot time.
This is OK if you're running the kernel daemon as the PPP modules
will be loaded on demand.
If you're not, however, you'll need to manually load the
modules at boot time by putting a single line consisting
entirely of the word "ppp" in your /etc/modules file.
</para>
<para>
See the &kernhowto; for more on this subject.
</para>
</sect2>
<sect2 id="sshfirewall">
<title>Allow SSH Through the Firewall</title>
<para>
The only network traffic between the two machines
(as a result of the tunnel, of course) will be over the
SSH protocol.
</para>
<para>
SSH uses only TCP streams -- no UDP or ICMP.
The ssh server (sshd) listens on port 22.
Our client (because we use the -P flag) only uses the unpriveleged ports
from 1024 through 65535. This description should have given you
enough information to set up your firewall.
</para>
<para>
For example, here are the ipchains commands needed to allow
ssh connections to the server.
We allow incoming SSH connection between port 22 on the local
machine and any port on the remote.
Replace eth0 with the interface
that will be carrying the ssh traffic and $IPADDR with the IP
address of that interface.
</para>
<screen>
ipchains -A input -i eth0 -p tcp -d $IPADDR 22 -j ACCEPT
ipchains -A output -i eth0 -p tcp ! -y -s $IPADDR 22 -j ACCEPT
</screen>
<para>
And, here are the commands needed to set up the firewall on
the client. We don't allow incoming ssh connections, and we only allow
the protocol to pass between port 22 on the remote machine and unprivileged
ports on this machine.
Again, replace eth0 with the interface that will be carrying
the ssh traffic, and $IPADDR with the IP address of that interface..
</para>
<screen>
ipchains -A input -i eth0 -p tcp ! -y --source-port 22 -d $IPADDR 1024:65535 -j ACCEPT
ipchains -A output -i eth0 -p tcp -s $IPADDR 1024:65535 --destination-port 22 -j ACCEPT
</screen>
</sect2>
</sect1>
<sect1 id="configserver">
<title>Configure the Server</title>
<para>
We need to set up the server to respond to the client's request
to bring up the tunnel.
</para>
<sect2>
<title>Create a VPN User</title>
<para>
The incoming SSH VPN requests must be directed to a particular user
on the server. For security and accountability, I recommend you
use a dedicated user to field VPN requests. The following steps will
set up a system user named "vpn" to do just that.
</para>
<orderedlist>
<listitem>
<para>
First, we create the user's account. Accounts come in two ranges:
the system range (typically 100-999) and the regular user range (1000+).
"--system" tells adduser to add the user in the system range and
to give him /bin/false for the login shell. "--group"
tells adduser to also create a group of the same name as the user,
and to add the user to the group.
</para>
<screen>
server# adduser --sytem --group vpn
</screen>
</listitem>
<listitem>
<para>
Since the vpn user needs to log in via ssh, change vpn's shell from
/bin/false to /bin/bash in the /etc/passwd file. You can simply
edit /etc/passwd using vi or any other decent text editor.
</para>
</listitem>
<listitem>
<para>
Create a password for the vpn user. It can (and should) be very
complex, since you'll only type it a few times while setting up the
VPN. After that, you'll never type it again.
</para>
<screen>
server# passwd vpn
Enter new UNIX password:
Retype new UNIX password:
passwd: password updated successfully
</screen>
</listitem>
<listitem>
<para>
Now, try connecting to the server to ensure that you've created the account properly.
</para>
<screen>
client% ssh eldivino.domain.com -l vpn
vpn@eldivino's password:
Linux eldivino 2.2.19 #6 Mon Jun 4 10:32:19 PDT 2001 i686 unknown
No mail.
vpn@eldivino:~$
</screen>
<para>
It may take a while for ssh to connect if
you don't have reverse DNS set up properly. You can fix that whenever
you want. It will only delay bringing up the VPN -- it won't prevent it
from working.
</para>
<para>
If it just stalls, then the ssh protocol is probably
being dropped by a firewall between the two machines.
Have a look at section <xref linkend="sshfirewall"> again.
</para>
</listitem>
</orderedlist>
</sect2>
<sect2>
<title>Set up Authenticated Login</title>
<para>
It would be terrible to have to type in a password every time you
wanted to bring the VPN link up, so we'll set up SSH's RSA
authentication. Skip this section if you truly don't mind
typing a password every time.
</para>
<orderedlist>
<listitem>
<para>
Ensure that the root account on the client machine has a public
key in root's home directory (~/root/.ssh/identity.pub). If this
file doesn't exist, then you must create it. As root, run ssh-keygen:
</para>
<screen>
# ssh-keygen
Generating public/private rsa1 key pair.
Enter file in which to save the key (/root/.ssh/identity):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /root/.ssh/identity.
Your public key has been saved in /root/.ssh/identity.pub.
The key fingerprint is:
15:61:57:7e:5c:26:91:09:5c:e6:10:b7:a1:74:bd:25 root@paradis
</screen>
</listitem>
<listitem>
<para>
Now, copy identity.pub to the vpn account's authorized_keys file
on the server.
You will almost certainly have to create this. As
root, perform the following commands on the server:
</para>
<screen>
server# cd ~vpn
server# mkdir .ssh
server# chown root.vpn .ssh
server# chmod 755 .ssh
server# cd .ssh
</screen>
<para>
Now, copy th the client's /root/.ssh/identity.pub file
(it's only one line) to
the server's ~vpn/.ssh/authorized_keys file.
You can add more lines to authorized_keys, one for each client,
if you want to allow multiple clients to connect.
</para>
<screen>
server# chown root.vpn authorized_keys
server# chmod 644 authorized_keys
</screen>
</listitem>
<listitem>
<para>
Now, become root on the client, and try SSHing to the server.
You may or may not need to use the -P option, depending on how your
client's firewall is set up. If port 22 is blocked on your client
(not a bad idea if it's not running an SSH server),
then -P tells ssh to use an unprivileged port even though it's
running as a priveleged user.
</para>
<screen>
client# ssh -P eldivino.domain.com -l vpn
Linux eldivino 2.2.19 #6 Mon Jun 4 11:03:22 PDT 2001 i686 unknown
No mail.
vpn@eldivino:~$
</screen>
<para>
There, we were just RSA-authenticated. Keep your private key
(the client's ~root/.ssh/identity file) private! Anyone who
has access to this file can log into the VPN account on the
server.
</para>
</listitem>
</orderedlist>
</sect2>
<sect2>
<title>Set Up sudo</title>
<para>
pppd needs to run as root. However, on the server, we're running
everything as the "vpn" user. How can the vpn user run pppd?
</para>
<para>
There are a number of ways of solving this problem. One is to use
the suid bit, and arrange permissions by groups. However, this can get
confusing and difficult to administer pretty fast, leading to unintentional
security holes. Personally,
I find the sudo utility to be a much better solution.
</para>
<para>
sudo gives ordinary users superuser powers,
but only for a very limited set of commands.
The system administrator gets to decide what commands are allowed
and how much logging to perform. In this case, we want to
allow the user "vpn" to run pppd with superuser privilege, but
not be allowed to do anything else.
</para>
<orderedlist>
<listitem>
<para>
We need to edit sudo's configuration file, /etc/sudoers.
To use proper locking, hopefully preventing accidents and race conditions,
use the visudo command to edit /etc/sudoers.
If you're not faimiliar with vi, see the &vihowto;.
</para>
<screen>
server# visudo
</screen>
<para>
Add these two lines to the bottom of the file:
</para>
<screen>
Cmnd_Alias VPN=/usr/sbin/pppd
vpn ALL=NOPASSWD: VPN
</screen>
</listitem>
<listitem>
<para>
Now, verify that sudo is set up correctly. As the "vpn" user on the
server, try running pppd using sudo:
</para>
<screen>
server# su - vpn
server$ sudo /usr/sbin/pppd noauth
~9}#<23>Z}!}!} }9}"}k} }r} }'}%}zt2-<2D>}'}"}
</screen>
<para>
If you get a whole bunch of PPP garbage to the screen
(like the last line above), this is
good. It means that the vpn user is allowed to run pppd. You can
now switch to another terminal to kill it off, or you can just
let pppd finish on its own. It should give up trying to connect
after 30 seconds or so.
</para>
<para>
However, if you get "bash: /usr/sbin/pppd: Permission denied"
or some other sort of error,
or it asks for a password, then sudo is probably not working.
You'll need to try figure out what is going wrong. Verify
that pppd is in /usr/sbin, and that you set up the sudoers
file correctly.
</para>
</listitem>
</orderedlist>
</sect2>
</sect1>
<sect1 id="configclient">
<title>Configure the Client</title>
<para>
If ppp and ssh are set up on the client, and the server is ready
to connect, then all we need to do on the client is create the
script to bring up the link.
</para>
<sect2>
<title>Install the Script</title>
<para>
The VPN connection is initiated using the vpn-pppssh script
below.
</para>
<orderedlist>
<listitem>
<para>
Save this file on the client (it doesn't matter where --
/usr/local/bin/vpn-pppssh is a good place) and make it
executable by running "chmod a+x vpn-pppssh".
</para>
</listitem>
<listitem>
<para>
Fill in the settings at the top of the file with the values
you decided on in <xref linkend="planning">.
</para>
<para>
Remember that this is running under bash so you'll
need to avoid whitespace around the equals sign, use quotes where
necessary, and escape metacharacters such as $. See the
&bashscriptinghowto; or &advbashguide; for more.
</para>
<screen>
SERVER_HOSTNAME=eldivino.domain.com
SERVER_USERNAME=vpn
SERVER_IFIPADDR=192.168.3.2
CLIENT_IFIPADDR=192.168.3.1
</screen>
<para>
Run "vpn-pppssh config" to print out a list of the
configuration variables. This way, you can confirm that
your settings are being interpreted correctly.
</para>
</listitem>
</orderedlist>
</sect2>
<sect2>
<title>The vpn-pppssh Script</title>
<para>
Here is vpn-pppssh. All the action is on one line.
(the one beginning with "PPPD" in the start clause).
All the rest of this file is just support code.
</para>
<programlisting>&pppsshlisting;</programlisting>
</sect2>
</sect1>
<sect1 id="bringup">
<title>Bring up the Link</title>
<para>
Everything should now be set up. Now it's time to take
a deep breath and try to bring up the link.
</para>
<orderedlist>
<listitem>
<para>
Become root on the client machine and execute the vpn-pppssh script.
</para>
<screen>
client# /usr/local/bin/vpn-pppssh start
</screen>
</listitem>
<listitem>
<para>
It will take a while to connect, but then it should come back with
something like the following
</para>
<screen>
Using interface ppp1
Connect: ppp1 <--> /dev/pts/1
local IP address 192.168.3.1
remote IP address 192.168.3.2
</screen>
</listitem>
<listitem>
<para>
Did it work? First try pinging the client's VPN interface:
</para>
<screen>
client$ ping 192.168.3.2
</screen>
</listitem>
<listitem>
<para>
If this worked, then you can reach the interface on the client OK.
Don't get excited yet -- that was the easy part. Now, try pinging
the server's VPN interface:
</para>
<screen>
client$ ping 192.168.3.1
</screen>
<para>
If you get echoes back, then congratulations! Your PPP-SSH VPN
appears to be healthy.
Packets are successfully travelling the route in both directions.
You might want to log into your server and try initiating pings
from the server to the client, but at this stage of the game,
that's almost guaranteed to work.
</para>
</listitem>
</orderedlist>
<para>
You bring the VPN down with "vpn-pppssh stop".
</para>
<para>
Now that the tunnel works, you might want to integrate it
into your system so it comes up automatically as described
in <xref linkend="integration">.
Also, if you want to forward packets from an entire subnet over the
link (rather than just the packets originating on the client and
server as we have set up now) see <xref linkend="forwarding">.
</para>
<sect2>
<title>Troubleshooting</title>
<para>
The script itself is fairly simple. The entire system, however,
involves a lot of small parts. If any one of them is misconfigured,
it can prevent your VPN from working without so much as
a message why. Here is a list of things to check if you run
into difficulties:
</para>
<itemizedlist>
<listitem>
<para>
Double and triple check your network values. Try running
"vpn-pppssh config" to ensure the configuration
is correct and the shell hasn't ruined any of your values.
</para>
</listitem>
<listitem>
<para>
Go back over
each step and make sure that it all checks out.
</para>
</listitem>
<listitem>
<para>
Try temporarially turning
off any firewalls on the client, on the server, and on any machines in
between to see if any of them are getting in the way (not likely if
you can SSH between the two machines).
</para>
</listitem>
<listitem>
<para>
Ensure that your routes are correct. You can list your routes
using "route -n". See the
<ulink url="http://www.linuxdoc.org/LDP/nag2/index.html">
Linux Network Administrators Guide</ulink>
and &advroutehowto; for more.
</para>
</listitem>
</itemizedlist>
<sect3>
<title>sendto: Operation not permitted</title>
<para>
When you try to ping the VPN interfaces, if you get a
"sendto: Operation not permitted" error, you are probably running
into a firewall on the local machine that is denying packets before they
even reach the VPN network interface. Your firewall must allow
SSH traffic over your regular network <emphasis>and</emphasis>
it must allow all traffic over your VPN interfacess.
</para>
<para>
The ipchains commands to smash a hole in your firewall for your
PPP interface will something like this:
</para>
<screen>
ipchains -I input 1 -i ppp1 -s 192.168.3.0/24 -j ACCEPT
ipchains -I output 1 -i ppp1 -d 192.168.3.0/24 -j ACCEPT
</screen>
<para>
ppp1 must, of course, be the network interface of your PPP-SSH
VPN, and the IP addresses must match the address of the local
interface. Make sure that packets are allowed on both the
client and server.
</para>
<para>
See the &firewallhowto;, the &ipchainshowto; for kernel 2.2, or
documentation on iptables for kernel 2.4.
</para>
</sect3>
</sect2>
</sect1>
<sect1 id="integration">
<title>Integrating the VPN into your system</title>
<para>
Bringing up the link by hand gets tiring after a while. You probably
want your VPN to come up either at boot time or when your
dial-up connection comes up.
</para>
<sect2>
<title>Connecting at Boot Time</title>
<para>
It's quite easy to get this script to run at boot time.
I assume you're using the very common System V initscript setup.
If not, you'll have to figure out how to integrate this with your
system on your own.
</para>
<orderedlist>
<listitem>
<para>
Either copy or symlink the vpn-pppssh script to /etc/init.d.
</para>
<screen>
cp /usr/local/bin/vpn-pppssh /etc/init.d/vpn-pppssh
</screen>
</listitem>
<listitem>
<para>
Uncomment the echo lines in the start and stop
clauses in the vpn-pppssh script
to enable the boot-time "Starting" and
"done." messages.
</para>
</listitem>
<listitem>
<para>
Put "&gt; /dev/null 2&gt;&amp;1" after the line beginning
"${PPPD}" in the start section of the script. This just prevents
pppd's verbose messages from mucking up your boot screen.
You could also redirect pppd's messages (which may include
a very informative error) to a log file or, if you're not aesthetically
inclined, leave it alone and let your screen get all mucked up.
</para>
</listitem>
<listitem>
<para>
Now, you simply link your script in to each of the six runlevels.
</para>
<screen>
client$ ln -s /etc/init.d/vpn-pppssh /etc/rc0.d/K10vpn-pppssh
client$ ln -s /etc/init.d/vpn-pppssh /etc/rc1.d/K10vpn-pppssh
client$ ln -s /etc/init.d/vpn-pppssh /etc/rc2.d/S99vpn-pppssh
client$ ln -s /etc/init.d/vpn-pppssh /etc/rc3.d/S99vpn-pppssh
client$ ln -s /etc/init.d/vpn-pppssh /etc/rc4.d/S99vpn-pppssh
client$ ln -s /etc/init.d/vpn-pppssh /etc/rc5.d/S99vpn-pppssh
client$ ln -s /etc/init.d/vpn-pppssh /etc/rc6.d/K10vpn-pppssh
</screen>
</listitem>
</orderedlist>
<para>
Now, when you reboot your machine, the vpn should come up
near the end of the boot process.
When it hits this script, your machine will wait
until the VPN is up before it continues booting. If this is an
issue, you can write your own /etc/init.d/vpn-pppssh
script that calls the /usr/local/bin/vpn-pppssh script in the
background. The link will come up as your machine finishes
booting.
</para>
<para>
To manually bring the link down or up, just run the vpn-pppssh
script directly from /etc/init.d:
</para>
<screen>
client$ /etc/init.d/vpn-pppssh stop
client$ /etc/init.d/vpn-pppssh start
</screen>
</sect2>
<sect2 id="conndialup">
<title>Connecting via Dial-Up</title>
<para>
If you're dialing into the internet with PPP, you can bring the VPN
up every time you bring up the dial-up connection.
This is not difficult, but it does require a fairly recent
version of pppd, one that supports both the ipparam option,
and the ip-up.d and ip-down.d directories.
</para>
<orderedlist>
<listitem>
<para>
Create the "vpn-up" file in /etc/ppp/ip-up.d:
</para>
<programlisting>
#!/bin/sh
if [ "$PPP_IPPARAM" = "vpn" ]; then
# Don't bring up the vpn if we're bringing up the vpn.
exit 0
fi
/usr/local/bin/vpn start
</programlisting>
<para>
There's a re-entrancy here that the if statement takes care of. If we're
bringing up the regular PPP link, we want to bring up the VPN.
But, the VPN is a PPP link itself! If we didn't do anything
about this, PPP would recursively spawn itself until it ground
your machine to a halt.
</para>
<para>
The secret is the "ipparam vpn" parameter in the vpn-pppssh script.
This sets the IPPARAM variable for this
invocation to "vpn", which we then check in the startup script.
If it's set to vpn, then we know we're in the middle of bringing
up the vpn, so we just exit without error. Otherwise, we fire it up.
</para>
</listitem>
<listitem>
<para>
If you want to punch a hole in your firewall for your VPN
when you bring it up,
you can simply create an /etc/ppp/ip-up.d/vpn-fw file with the
following contents. All the shell variables below are supplied
by pppd, so you should be able to use this script unmodified.
</para>
<programlisting>
#!/bin/sh
# Punch a hole in the firewall for the VPN
if [ "$PPP_IPPARAM" = "vpn" ]; then
ipchains -I input 1 -i $PPP_IFACE -s $PPP_REMOTE -d $PPP_LOCAL -j ACCEPT
ipchains -I output 1 -i $PPP_IFACE -s $PPP_LOCAL -d $PPP_REMOTE -j ACCEPT
fi
</programlisting>
</listitem>
<listitem>
<para>
Create the "vpn-down" file in /etc/ppp/ip-down.d/vpn-pppssh:
</para>
<programlisting>
#!/bin/sh
if [ "$PPP_IPPARAM" = "vpn" ]; then
# Don't bring down the VPN if we're bringing down the vpn.
exit 0
fi
/usr/local/bin/vpn stop
</programlisting>
</listitem>
</orderedlist>
<para>
Make sure to make all the scripts above executable
(chmod a+x /etc/ppp/ip-up.d/vpn-pppssh).
Now, when you bring up your PPP link, the VPN should come up with it.
And, when you shut it down, the VPN will disappear. Easy as pie.
</para>
</sect2>
</sect1>
<sect1 id="forwarding">
<title>Forwarding Between Subnets</title>
<para>
You only need to read this section if you're trying to connect
networks, not just hosts. I assume your host-to
host tunnel works so now your client and
server computers can exchange pings flawlessly. Now, it's time
to allow networks connected to the client and server machines to
use the tunnel as well.
</para>
<sect2>
<title>Forwarding</title>
<para>
First of all, you need to be sure that you're allowing packets
to be forwarded across your interfaces. You turn this on through
the proc configuration interface. It's best to do this once at
boot time, but you can also put it in the vpn-pppssh script or even
create a script in the /etc/init.d/ip-up.d directory (see
<xref linkend="conndialup">) if you want.
</para>
<screen>
echo 1 > /proc/sys/net/ipv4/ip_forward
echo 1 > /proc/sys/net/ipv4/conf/ppp1<co id="fwdif">/forwarding
</screen>
<calloutlist>
<callout arearefs="fwdif">
<para>
Of course, you need to replace ppp1 with the appropriate VPN interface
(the interface associated with SERVER_IFIPADDR or CLIENT_IFIPADDR
depending on if you're doing this on the server or the client).
</para>
</callout>
</calloutlist>
</sect2>
<sect2>
<title>Gatewaying</title>
<para>
On all computers in the subnet, you need to set up the local VPN host as the
gateway to all the networks on the other side of the tunnel.
This just tells the
computers "if you have any packets destined for the opposite side of
the VPN, send them to the local VPN host".
Note that if the VPN host
is already the default gateway for all the computers, then you don't need
to worry about this step -- the packets will be forwarded automatically.
</para>
<para>
In the example below, my VPN host has IP address 192.168.1.1 on the local network.
and IP address 192.168.3.2 on the VPN network. The VPN network, containing both
the client and server VPN interfaces and all computers on the opposite side of the
link, is 192.168.3.0/24.
Therefore, on every local computer that I want to be able to send packets through
the VPN, I need to run the following command:
</para>
<screen>
# route add -net 192.168.3.0 netmask 255.255.255.0 gw 192.168.1.1
</screen>
<para>
Now, any packet destined for the 192.168.3.0/24 network on the local machine
will be relayed to host 192.168.1.1 on the local network to be forwarded through
the VPN.
</para>
</sect2>
<sect2>
<title>Routing</title>
<para>
There should be no need to set up custom routing -- pppd
tries to do it all for you. However, if you find that pppd
doesn't cover your needs, the place for your routing commands is in
the vpn-pppssh script itself. To change the routing on the client,
simply run route. To change the route on the server, use
ssh to send those commands to the server.
Here's an example:
</para>
<screen>
route add -net $NET1 gw $SERVER_IFIPADDR
ssh -o Batchmode=yes $SERVER_HOSTNAME -l$SERVER_USERNAME route add -net $NET2 gw $CLIENT_IFIPADDR
</screen>
</sect2>
<sect2>
<title>Masquerading</title>
<para>
You can even set up one or both hosts to masquerade all
connections through the VPN tunnel.
See the &masqhowto; for more.
</para>
<screen>
# ipchains -A forward -i ppp1 -s 192.168.0.0/24 -j MASQ
</screen>
</sect2>
<sect2>
<title>Now try it</title>
<para>
That should be all you need to forward packets from subnets
connected to the client or server to the opposite machine.
May your PPP-SSH VPNs serve you quietly and reliably for many
years to come.
</para>
</sect2>
</sect1>
</article>