VPN Server

Build the kernel

To start, you probably need to rebuild your kernel for the server.

You need to make sure that the following kernel options are turned on in addition to basic networking and everything else that you might need.

If you've never built your own kernel before, read the Kernel HOWTO.

For 2.0 kernels:
  • CONFIG_FIREWALL

  • CONFIG_IP_FORWARD

  • CONFIG_IP_FIREWALL

  • CONFIG_IP_ROUTER

  • CONFIG_PPP

For 2.2 kernels:

  • CONFIG_FIREWALL

  • CONFIG_IP_ADVANCED_ROUTER

  • CONFIG_IP_FIREWALL

  • CONFIG_IP_ROUTER

  • CONFIG_PPP

Configure Networking

If you are building a server that has only one network card, I suggest that you think about buying another, and rewiring your network. The best way to keep your network private is to keep it on it's own wires. So if you do have two network cards, you'll need to know how to configure both of them. We'll use eth0 for the external interface, and eth1 for the internal interface.

Configuring the interfaces

We first should configure the external interface of the server. You should already know how to do this, and probably already have it done. If you don't, then do so now. If you don't know how, go back and read the Networking HOWTO

Now we bring up the internal interface. According to the numbers that we've chosen, the internal interface of the server is 192.168.40.254. so we have to configure that interface.

For 2.0 kernels, use the following:


# /sbin/ifconfig eth1 192.168.40.254 netmask 255.255.255.0 broadcast 192.168.40.255
# /sbin/route add -net 192.168.40.0 netmask 255.255.255.0 dev eth1

For 2.2 kernels, use the following:


# /sbin/ifconfig eth1 192.168.40.254 netmask 255.255.255.0 broadcast 192.168.40.255

That gets our basic interfaces up. You can now talk to machines on both local networks that are attached to the server.

Setting routes

We can now talk to machines on our local nets, but we can't get to the rest of our internal network. That requires a few more lines of code. In order to reach the other machines on other subnets, we need have a route that tells traffic to go to the Cisco router. Here's that line:


# /sbin/route add -net 192.168.0.0 gw 192.168.254.254 netmask 255.255.0.0 dev eth1

That line tells the kernel that any traffic destined for the 192.168.0.0 network should go out eth1, and that it should be handed off to the Cisco. Traffic for our local net still gets where it is supposed to because the routing tables are ordered by the size of the netmask. If we were to have other internal nets in our network, we would have a line like the above for each net.

Making filter rules

Now that we can reach every machine that we could need to, we need to write the firewall filtering rules that allow or deny access through the VPN server.

To set the rules with ipfwadm, run it like so:


# /sbin/ipfwadm -F -f
# /sbin/ipfwadm -F -p deny
# /sbin/ipfwadm -F -a accept -S 192.168.40.0/24 -D 192.168.0.0/16
# /sbin/ipfwadm -F -a accept -b -S 192.168.10.0/24 -D 192.168.0.0/16
# /sbin/ipfwadm -F -a accept -b -S 192.168.11.0/24 -D 192.168.0.0/16

To set the rules with ipchains, run it like so:


# /sbin/ipchains -F forward
# /sbin/ipchains -P forward DENY
# /sbin/ipchains -A forward -j ACCEPT -s 192.168.40.0/24 -d 192.168.0.0/16
# /sbin/ipchains -A forward -j ACCEPT -b -s 192.168.10.0/24 -d 192.168.0.0/16
# /sbin/ipchains -A forward -j ACCEPT -b -s 192.168.11.0/24 -d 192.168.0.0/16

This tells the kernel to deny all traffic except for the traffic that is coming from the 192.168.40.0/24 network and destined for the 192.168.0.0/16 network. It also tells the kernel that traffic going between the 192.168.10.0/24 and 192.168.0.0/16 nets is allowed, and the same for the 192.168.11.0 net. These last two are bidirectional rules, this is important for getting the routing to work going both ways.

Routing

For home users, everything will work fine to here. However for the remote offices, we need to do some routing. First of all, we need to tell the main router, or Cisco, that the remote offices are behind the VPN server. So specify routes on the Cisco that tell it to send traffic destined for the remote offices to the VPN server. Now that that is taken care of, we must tell the VPN server what to do with the traffic destined for the remote offices. To do this, we run the route command on the server. The only problem is that in order for the route command to work, the link must be up, and if it goes down, the route will be lost. The solution is to add the routes when the clients connects, or more simply, to run the route command frequently as it's not a problem to run it more than is necessary. So, create a script and add it to your crontab to be run every few minutes, in the script, put the following:


/sbin/route add -net 192.168.11.0 gw 192.168.10.253 netmask 255.255.255.0
/sbin/route add -net 192.168.10.0 gw 192.168.11.253 netmask 255.255.255.0

Configure pppd

Now we will configure pppd on the server to handle VPN connections. If you are already using this server to handle dialup users or even dialing out yourself, then you should note that these changes may affect those services. I go over how to avoid conflicts at the end of this section.

/etc/ppp/

This directory may contain a number of files. You probably already have a file called options. This file holds all of the global options for pppd. These options cannot be overridden by pppd on the command line.

/etc/ppp/options

Your options file should contain at least the following:


ipcp-accept-local
ipcp-accept-remote
proxyarp
noauth

The first two lines tell pppd to accept what the other end specifies for IP addresses. This is necessary when hooking up remote offices, but can be disabled if you are only connecting home users. It's okay to leave it on, as it does not prevent the server from assigning addresses, it only says it that it's okay to accept what the client asks for.

The third line is very important. From the pppd man page:


proxyarp
       Add an entry to this system's ARP [Address  Resolu-
       tion  Protocol]  table  with  the IP address of the
       peer and the Ethernet address of this system.  This
       will  have  the effect of making the peer appear to
       other systems to be on the local ethernet.		

This is important because if it is not done, local traffic will not be able to get back through the tunnel.

The last line is just as important. This tells pppd to allow connections without username and password. This is safe since authentication is already handled by sshd.

Avoiding conflicts

If you are handling other services with pppd, you should consider that the configurations for these other services may not be the same as what the VPN system needs. pppd is designed such that the options in the main options file /etc/ppp/options cannot be overridden by options specified at runtime. This is done for security reasons. In order to avoid conflict, determine which options cause the conflict, and move them from the main file into a separate options file that is loaded when the appropriate application of pppd is run.

Configure sshd

The following is what my /etc/sshd_config file looks like. Yours should look the same or similar:


# This is the ssh server system wide configuration file.

Port 22
ListenAddress 0.0.0.0
HostKey /etc/ssh_host_key
RandomSeed /etc/ssh_random_seed
ServerKeyBits 768
LoginGraceTime 600
KeyRegenerationInterval 3600
PermitRootLogin yes
IgnoreRhosts yes
StrictModes yes
QuietMode no
FascistLogging yes
CheckMail no
IdleTimeout 3d
X11Forwarding no
PrintMotd no
KeepAlive yes
SyslogFacility DAEMON
RhostsAuthentication no
RhostsRSAAuthentication no
RSAAuthentication yes
PasswordAuthentication no
PermitEmptyPasswords no
UseLogin no

The important points to note are that password authentication is disabled as are all of the "R" services. I have also turned off mail checking and the message of the day as they can confuse pppd on the client side. I still allow root login, but as this can only be done with a key, it is adequately safe.