Client IPSEC VPNs with Linux and Juniper Netscreen

Today, as promised I am going to show everyone how to set up a client IPSEC VPN to a Juniper Netscreen FW/VPN appliance from a Linux machine.  Juniper is a market leader in the Firewall and VPN space, and provides appliances from the Small office Home Office footprint all the way up to the largest enterprise data center gateways.  The small office version, currently an SSG 5, is based on Juniper’s ScreenOS.  This tutorial only covers ScreenOS configuration.  Juniper is now marketing a new platform called the SRX series. These units run JUNOS, which is Junipers Router OS outfitted with VPN and Firewall functionality pulled from ScreenOS.

The Linux system examples I show should work on Ubuntu (and Gentoo, provided your kernel has support for IPSEC configured).

So why VPN?  As I have mentioned in previous posts a VPN is a secure method for using a public network for private communications.  Most VPNs fall in to type types:  IPSEC and SSL.  We will be covering IPSEC VPNs in this posting.  I typically use a VPN for access to my employer’s network while on the road so I can be productive while traveling.  With the right technology, you can gain access to your home network the same way.

I have a small home network that is protected by a Juniper Netscreen SSG5.  This SSG 5 is configured to allow one or more “client” vpns to connect to it.  Essentially a client VPN is a single PC talking to a LAN via a VPN server or gateway, as opposed to a site to site VPN, which generally connects two networks or LANs together over the internet.

Here is a little background on IPSEC.

IPSEC VPNs generally consist of two phases.   Phase 1 is an identification phase, where two IPSEC gateways identify each other.  If the identification is successful (the two gateways trust each other) then Phase 2 which is the ‘tunnel’ phase, can occur.  During this phase, the two gateways negotiate the IP subnet traffic that will be allowed to traverse the tunnel and how to encrypt that traffic.  Generally this traffic is protected by using 3DES or AES encryption, which dynamic key rotation.  IPSEC, if set up properly is very hard to compromise.

Phase 1 typically uses UDP port 500 to perform IKE/ISAKMP negotiations.  Phase 2, in our case, will use IPSEC ESP (Encapsulated Security Payload) which is a transport layer protocol (like TCP and UDP, runs at layer 4 of of the OSI model). If a NAT firewall is detected in between the two gateways, then ESP can be encapsulated in UDP port 4500 or UDP port 500 depending on the implementation used.  This encapsulation is called IPSEC NAT traversal, or NAT-T.

We will start with the following example network layout:

Diagram of Example VPN NetworkFirst we will start with the Netscreen configuration, which is best performed from the netscreen command line.  Keep in mind that this will work on several Netscreen models sold over the last few years.  This includes the Netscreen 5XT, and 5GT.  These units can be found on Ebay for less than $100, and are highly recommended for use as a home or small office firewall.

Note:  It is best to have a static IP for the VPN gateway side of the connection.  Dynamic will work, however it will become difficult to track the ip as the ISP reassigns addressing to the Juniper via DHCP or other means.  Newer Juniper Netscreens can support dynamic dns registration with DDNS providers such as dyndns.org, which would make tracking the ip easier.

So, lets get started.  From an ssh or telnet session, login to your netscreen.  The first thing we need to do is define VPN users and a group – here is an example of creating a user “rwalters”.  This user id is used for IKE negotiation.

Phase 1: (IKE gateway negotiation)

User definition:

set user "rwalters" uid 1
set user "rwalters" ike-id u-fqdn "rettw@rtwnetwork.com" share-limit 1
set user "rwalters" type ike
set user "rwalters" "enable"

After creating a user, we should add that user to a group.  While not required, if you want more than one client VPN to be active at one time, you should add your user to a group, as the group will be used in the IKE gateway definition, and any of the users in the group will be allowed to authenticate in Phase 1.

Here we create a group called dialupusers:

set user-group "dialupusers" id 1
set user-group "dialupusers" user "rwalters"

Next we will define the IKE Phase 1 gateway definition.  In most cases, we use pre-shared key authentication, which is basically a password.  Other forms of credentials can be used as well such as RADIUS or X-AUTH but those are beyond the scope of this tutorial.  Here is an example of the ScreenOS command for IKE gateway definition:

set ike gateway "Publicdialupvpn" dialup "dialupusers" Aggr outgoing-interface "ethernet0/0" preshare "<password>" proposal "pre-g2-3des-sha"
set ike gateway "Publicdialupvpn" nat-traversal udp-checksum
set ike gateway "Publicdialupvpn" nat-traversal keepalive-frequency 5

The first command creates an IKE gateway called “Publicdialupvpn” and associates the “dialupusers” group with it.  It also defines the outgoing interface, ethernet0/0 and the preshared key or password.  You should use a complex password in place of the <password> shown in the command.    The Aggr means aggressive mode, which is used when the IP address of one of the gateways is dynamic – this case the laptop will almost always have a dynamic IP address.  The remaining commands set nat-traversal capabilities.  Without NAT-T, Phase 2 will not come up if a NAT-Router or firewall is present in the middle of the network.  The last piece is the encryption used for IKE traffic – in this case 3DES, with SHA-1 hashing algorithm.

Next, we will define the Phase 2 tunnel.  An example is below:

set vpn "Publicdialupvpn" gateway "Publicdialupvpn" no-replay tunnel idletime 0 proposal "g2-esp-3des-sha"

This command is pretty simple.  It defines a VPN (or tunnel) called Publicdialupvpn, using the IKE gateway definition of the same name. It also turns on no-replay, which prevents replaying of traffic (a common method of hacking VPNs) and sets the transport to ESP, and encryption to 3DES, with SHA-1 hashing.

The last piece of Netscreen configuration is the Firewall policy to allow the encrypted traffic to the internal network.  This policy is actually used as part of phase 2 as well, since phase 2 requires the exchange and agreement on the ip addresses that will be allowed to traverse the tunnel (known as a policy based VPN in Juniper terminology).

In this example we will create an address object for the local LAN:

set address "Trust" "Local LAN" 192.168.0.0 255.255.255.0

Then we will create a policy to allow it to be tunnelled to from the outside.  Note that Dial-Up VPN is a default address book entry that ships with ScreenOS.  Note that you can limit the ports/protocols allowed through the tunnel by changing the “ANY” to a specific service, such as http, for instance.

set policy id 8 from "Untrust" to "Trust" "Dial-Up VPN" "Local LAN" "ANY" tunnel vpn "Publicdialupvpn" id 0x3 log
set policy id 8
set log session-init
exit

So, that should take care of the Netscreen side of the equation.  Next we will tackle the Linux side which is the fun part.  The beauty of Linux IPSEC is that its one of those built in features that you would have to pay for if using one of those operating systems made in Redmond, WA.

Linux IPSEC has a few requirements.  If using Ubuntu, all the kernel requirements are already fulfilled.  If you’re using Gentoo or a custom kernel, make sure the following is set in your kernel config:

Under networking:

CONFIG_INET_AH=m
CONFIG_INET_ESP=m
CONFIG_INET_IPCOMP=m
CONFIG_INET_XFRM_TUNNEL=m
CONFIG_INET_TUNNEL=m
CONFIG_INET_XFRM_MODE_TRANSPORT=m
CONFIG_INET_XFRM_MODE_TUNNEL=m
CONFIG_INET_XFRM_MODE_BEET=m

Under Cypto/Block:

CONFIG_CRYPTO_MD5=y
CONFIG_CRYPTO_SHA1=m

Under Crypto/Ciphers:

CONFIG_CRYPTO_AES=m
CONFIG_CRYPTO_AES_X86_64=m
CONFIG_CRYPTO_DES=m

Linux IPSEC is handed by the kernel in conjunction with two different packages:  ipsec-tools, and racoon.  Both of these must be installed and configured for our VPN to work properly.  On Ubuntu you can install these with:

apt-get install ipsec-tools


apt-get install racoon

On gentoo, just a simple:

emerge ipsec-tools

Should install the necessary software.

Three files files need to be customized for Linux IPSEC VPNs to work with a Juniper Netscreen.  The first file, ipsec-tools.conf, usually resides in /etc, and the second, psk.txt in /etc/racoon. The third file, is racoon.conf, which is also in the /etc/racoon directory.

The ipsec-tools.conf file handled Phase 2 security association, and the racoon.conf/psk.txt file provide IKE (Phase 1) and dynamic re-keying of encryption between two VPN endpoints.  Here is an example of an ipsec-tools.conf file that would work for our sample VPN diagram and Juniper configuration above.

#!/usr/sbin/setkey -f


flush;
spdflush;


#outbound
spdadd 99.99.99.99 192.168.0.0/24 any
-P out ipsec esp/tunnel/99.99.99.99-77.77.77.77/require;


#inbound
spdadd 192.168.0.0/24 99.99.99.99 any
-P in ipsec esp/tunnel/77.77.77.77-99.99.99.99/require;

The information in this file is pretty straight forward.  Essentially its a tunnelling policy.  It basically states that all traffic to 192.168.0.0/24, which is our remote LAN behind the Juniper from 99.99.99.99 (the Internet IP of our laptop) be tunnelled through the esp tunnel between 77.77.77.77 (the internet IP of our Juniper) and 99.99.99.99 (our laptop) and vice versa.  Note that is file must be updated with the existing IP address on the laptop or remote PC every time a VPN is started. For instance if your laptop gets an ip address of 101.100.111.1 from the ISP your using to connect to the internet, all of the 99.99.99.99 ip addresses in the ipsec-tools.conf file will have to be changed to 101.100.111.1.

The other two files /etc/racoon/psk.txt, and /etc/racoon/racoon.conf are relatively static.   The first file, psk.txt, is essentially a list of IP addresses of remote VPN gateways and the pre-shared key to use for a password when doing IKE with that gateway.

The password in this file should match the password used in the netscreen Phase 1 IKE configuration shown above.  Here is a sample of that file:

# IPv4/v6 addresses
77.77.77.77    <your pre-shared key password>
10.160.94.3    mekmitasdigoat
172.16.1.133    0x12345678
194.100.55.1    whatcertificatereally
3ffe:501:410:ffff:200:86ff:fe05:80fa    mekmitasdigoat
3ffe:501:410:ffff:210:4bff:fea2:8baa    mekmitasdigoat
# USER_FQDN
foo@kame.net    mekmitasdigoat
# FQDN
foo.kame.net    hoge

The last file, racoon.conf controls Phase 1 IKE negotiation, Phase 2 VPN SA setup and VPN re-key.  This file rarely changes for a particular vpn definition.

Here is a sample racoon.conf:

path pre_shared_key "/etc/racoon/psk.txt";


# Remote host
remote 77.77.77.77
{
exchange_mode aggressive;


# Change this to your local ID
my_identifier user_fqdn "rettw@rtwnetwork.com";
lifetime time 28800 sec;
proposal {
encryption_algorithm 3des;
hash_algorithm sha1;
authentication_method pre_shared_key;
dh_group modp1024;
}
}


# A sample sainfo section
# Create one for each subnet you want to access, etc.
#sainfo address 172.20.0.3 any address 192.168.0.0/24 any
sainfo anonymous
{
pfs_group modp1024;
lifetime time 3600 sec;
encryption_algorithm 3des;
authentication_algorithm hmac_sha1;
compression_algorithm deflate;
}

Generally there are two sections to racoon.conf.  The first section controls IKE parameters, and Phase 1 negotiations.  The second section controls Phase 2 negotiations.  There are a couple of things I would like to point out about.  First, notice the local id or user fqdn.  This should be the same as one of the users created on the Juniper side.   The second item is the lifetime and encryption types.  The first lifetime value in the IKE/Phase 1 section dictates the length of time the two gateways will trust each other without re-identification.  The Phase 2 section has its own lifetime parameter as well.  This controls the re-key time on the tunnel, in this case every 3600 seconds or one hour, the tunnel encryption keys will be renegotiated.

Note also the “aggressive mode” statement – this should match the Phase 1 definition on the Juniper as well.

So, after the files have been configured correctly, you need to start the VPN.  The first step is to run the ipsec-tools.conf file, so it should be executable.  The last step is to start racoon.  Here are the example commands.

/etc/ipsec-tools.conf


/etc/init.d/racoon start

After the racoon daemon is started, try to ping something on the remote LAN – for example, 192.168.0.2.  The ping will start the IPSEC negotiations.  Watching your /var/log/daemon.log or /var/log/messages will show you what is happening.

So – what if it doesn’t work?  Double check your configuration.  Juniper ScreenOS event log (command: get event) is very helpful in determing what is happening.  The linux /var/log/daemon.log and /var/log/messages will also be helpful.

Ok – so this seems like a lot of work, modifying files and starting services – I agree its not quite optimal, at least on the Linux side.  So, I wrote a couple of scripts – one to determine your PC/Laptop’s IP address, create the ipsec-tools.conf file, run it, and then run racoon.  As a bonus, it also replaces your resolv.conf with another resolve.conf – in case there is a dns server for your remote network you would like to use to be able to resolve machine names on your protected LAN.  The second script clears the ipsec-tools.conf policies, and stops racoon, and replaces the resolv.conf with the original one.

With the scripts below, starting a VPN to your office or home lan is as simple as connecting to the internet, and running a the script.  Afterwards, the to undo the changes, you run another script.  This way, there are only one time changes needed to /etc/racoon/psk.txt and /etc/racoon/racoon.conf

Here is the script for starting the vpn:

#!/usr/bin/python


#script to find outgoing internet interface (by opening a socket to google.com)
#and build a vpn policy file for ... and turn up the VPN tunnel


import socket
import os


def OutputSpace2file():
filehandle.write ( ' ' )
s = socket.socket()
# Connect to google.com to find out going IP address
s.connect(('google.com',80))
ipport = s.getsockname()
ipaddr = ipport[0]
destip = '77.77.77.77'
destsubnet = '192.168.0.0/24'
print "Setting VPN tunnel up from Source:",ipaddr,"To IP address:",destip
print "For destination subnet",destsubnet
print "Generating ipsec-tools.conf file in /etc"
filehandle = open ('/etc/ipsec-tools.conf','w')
filehandle.write ( '#!/usr/sbin/setkey -fn' )
filehandle.write ( 'n')
filehandle.write ( 'flush;n' )
filehandle.write ( 'spdflush;nn' )
filehandle.write ( '#outboundn' )
filehandle.write ( 'spdadd ' )
filehandle.write ( ipaddr )
OutputSpace2file()
filehandle.write ( destsubnet )
OutputSpace2file()
filehandle.write ( 'anyn' )
filehandle.write ( '    -P out ipsec esp/tunnel/' )
filehandle.write ( ipaddr )
filehandle.write ( '-' )
filehandle.write ( destip )
filehandle.write ( '/require;nn' )
filehandle.write ( '#inboundn' )
filehandle.write ( 'spdadd ' )
filehandle.write ( destsubnet )
OutputSpace2file()
filehandle.write ( ipaddr )
OutputSpace2file()
filehandle.write ( 'anyn' )
filehandle.write ( '    -P in ipsec esp/tunnel/' )
filehandle.write ( destip )
filehandle.write ( '-' )
filehandle.write ( ipaddr )
filehandle.write ( '/require;n' )
filehandle.close()
# set permissions on new policy file
rc = os.system( 'chmod a+x /etc/ipsec-tools.conf' )
# Check return code for permissions command
if rc != 0:
print "Error Setting permissions!"
os._exit(1)
# Continue by runninng ipsec-tools.conf script
print "Running ipsec-tools.conf script."
rc = os.system( '/etc/ipsec-tools.conf' )
# Check return code for command
if rc != 0:
print "Error running ipsec-tools.conf script!"
os._exit(1)
# Continue by reloading racoon
print "Reloading racoon IKE server."
rc = os.system( '/etc/init.d/racoon reload' )
# Check return code for command
if rc != 0:
print "Error running /etc/init.d/racoon reload!"
os._exit(1)


# backup existing /etc/resolv.conf and build new one for remote lan


print "Backing up /etc/resolv.conf and setting resolv.conf to rtwsecurenet.com DNS"
rc = os.system( 'mv /etc/resolv.conf /etc/resolv.conf.bak' )
if rc != 0:
print "Error backing up /etc/resolv.conf"
os._exit(1)
filehandle = open ('/etc/resolv.conf','w')
filehandle.write ( '# File created by LPU vpn-start.py scriptn' )
filehandle.write ( 'search homelan.comn' )
filehandle.write ( 'nameserver 192.168.0.17n' )
filehandle.close()

And for stopping the VPN:

#!/usr/bin/python


#script to stop vpn started by vpn-start.py and restore resolv.conf


import socket
import os


# stop vpn by flushing ipsec policies
print "Flushing IPSEC policies"
rc = os.system( '/usr/sbin/setkey -FP' )
# Check return code for permissions command
if rc != 0:
print "Error flushing policies!"
os._exit(1)
# Continue by runninng ipsec-tools.conf script
print "Restoring /etc/resolv.conf to previous state"
rc = os.system( 'cp /etc/resolv.conf.bak /etc/resolv.conf' )
# Check return code for command
if rc != 0:
print "Error restoring /etc/resolv.conf - name resolution will not work properly!"
os._exit(1)
# Continue by reloading racoon
print "Stopping racoon IKE server."
rc = os.system( '/etc/init.d/racoon stop' )
# Check return code for command
if rc != 0:
print "Error running /etc/init.d/racoon stop!"
os._exit(1)

So, there you have it.  I use this type of vpn set up regularly to access my home network when on the road.  So far, I haven’t found anything that keeps it from working, unless the hotel ISP network assigns my laptop a 192.168.0 IP.  This of course would render the vpn useless, since you can’t tunnel from 192.168.0.0 to 192.168.0.0 as it will confuse the ip stack and routing processes.  Feel free to use these scripts in your own environment.

While some purists may say, why not use linux for both ends of the tunnel. While this can be done, its hard to beat the price and usability of Juniper’s Netscreen line. It is an excellent firewall, and used units can be found on Ebay for less than $100 now – look for Netscreen 5GT or 5XT.

I have tried to cover some key concepts of IPSEC VPNs, but this is by no means a complete overview, but more of a implementation for a specific application. There are several IPSEC references available on the internet via this Wikipedia article.

16 comments on Client IPSEC VPNs with Linux and Juniper Netscreen

  1. I have follow this intruction but, i’m confused about the script to start the vpn?? can you give me an answer??

  2. If you want to try out Linux before you convert your computer to a Linux box, try virtual PC from the Microsoft.com website it’s free! You can run the Linux in it’s own window while windows is running. Have you decided on which Linux you’ll be using? If not try BART PE, Open SuSe, Ubuntu (Mandriva is cool too but you have to pay for it). Linux is a VERY lightweight Operating system that takes very little space. In fact some developers have been able to stuff it in a 256 MB thumb drive. Also, check out OpenOffice.org for a free office suite to run on Linux.

  3. Thanks so much for sharing. It is becoming more uncommon to find quality material. Appears plenty of sites are offering nothing unique – just scraped content or rehashed rss feed. Your work is appreciated. Anytime we can learn more good ideas about building our business is a good thing like what we share on http://www.provenprofitsystems.com.

  4. Hi admin,
    I’m just newbee for these but your help is much appreciated. How to run ipsec-tools.conf? is it /etc/init.d/setkey start? if that’s the case, what should I do if their is no setkey and racoon daemon under init.d? And also, what would be a filename for the vpn script and which path is better to save the vpn stop and start script file?

    /etc/ipsec-tools.conf
    /etc/init.d/racoon start

    Thank you

    1. Just saw your comment – the ipsec-tools.conf script is run by “just running it” the first line in the file is a line that looks like this:

      #!/usr/sbin/setkey -f

      This tells bash to run the following commands using the setkey command. So, just set the execute bit for the owner of the file (should be root) with:

      chmod u+x ipsec-tools.conf

      and then as root you get run it from the /etc directory with

      ./ipsec-tools.conf.

      Then you should reload racoon with

      /etc/init.d/racoon restart.

      Hope that helps.

      Rett

  5. Hello, this article helps me a lot. Thank you. One question though, what if the laptop is assigned a NAT address? Would it be the NAT address that would go where you have 99.99.99.99 in your example, or would it be the hotel’s address assigned to them by their ISP? Thanks.

    1. This should work either way. The address you put in the example would be the actual address that the laptop has been assigned. NATing should pose an issue. I will double check the content to make sure I accounted for NAT traversal.

      Rett

    1. Remove the “required” keyword and replace with “unique” instead in /etc/ipsec-tools.conf file.

      That should take care of your issue.

      -Rett

  6. Great article, it was extremely helpful in setting up a VPN for my office.

    One tip for others who may be using this: if you have multiple subnets behind your Juniper, you need to specify your lines in ipsec.conf using the ‘unique’ directive at the end, not ‘require.’ Until I made this change, I could only access one network at a time.

    1. Good point – thanks for bringing this to my attention… I had actually set this up to a large multi-subnet network in the past, but missed that piece when writing the article. I will update the content.

Leave a Reply

Your email address will not be published. Required fields are marked *