IPSec Tunneling Using FreeBSD

ipsec

IPsec is a protocol which sits on top of the Internet Protocol (IP) layer. IPsec allows communication between hosts in a secure manner. The FreeBSD IPsec based on the KAME implementation.

I’ll use FreeBSD 7.2 for this howto, before we start to configure IPsec we need to compile IPSEC module into FreeBSD kernel if you don’t know to recompile FreeBSD kernel then please follow this document. To enable IPsec support into your kernel, add the following options in kernel configuration file:

Options IPSEC 		#IP security
Options IPSEC_DEBUG 	#debug IP security
Device  crypto

Let’s draw the scenario which will be use throughout this tutorial

IPSec FreeBSD

In the above diagram two public IP addresses has been used (172.17.1.254, 172.18.1.254). We will use these IP addresses as a reference in the rest of this article. Anywhere you see those ip addresses, replace them with your own public IP address.

Note for the local network I used (192.168.1.x) for 172.17.1.254 and (192.168.2.x) for 172.18.1.254.

All the machines on (192.168.1.x) network side assigned 192.168.1.1 as a default gateway.

All machines on (192.168.2.x) network side assigned 192.168.2.1 as a default gateway.

Creating a “virtual” network link

We will use a “tunnel” between the two networks. The two “tunnel mouths” are the IP addresses 172.16.17.254 and 172.18.1.254, and the tunnel must be told the addresses of the private IP addresses that will be allowed to pass through it. The tunnel is used to transfer traffic with private IP addresses across the public Internet.

This tunnel is created by using the generic interface or gif devices on FreeBSD. As you can imagine, the gif interface on each gateway host must be configured with four IP addresses; two for the public IP addresses, and two for the private IP addresses.

FreeBSD 7.x already include gif support into kernel, but you can also do this by adding the line:

device gif

Now let’s create our first tunnel on the machine (172.17.1.254) you would run the following commands to configure the tunnel.

ifconfig gif0 create
ifconfig gif0 tunnel 172.17.1.254 172.18.1.254
ifconfig gif0 inet 192.168.1.1 192.168.2.1 netmask 255.255.255.0

On 2nd machine (172.18.1.254) you would run the following commands to configure the tunnel.

ifconfig gif0 create
ifconfig gif0 tunnel 172.18.1.254 172.17.1.254
ifconfig gif0 inet 192.168.2.1 192.168.1.1 netmask 255.255.255.0

Now check the gif0 interface either its up or not, you can run ifconfig command on both machines:

ifconfig gif0

On the machine(172.17.1.254) you would see this kind of information:

gif0: flags=8051< ,POINTOPOINT,RUNNING,MULTICAST> metric 0 mtu 1280
        tunnel inet 172.17.1.254 --> 172.18.1.254
        inet 192.168.1.1 --> 192.168.2.1 netmask 0xffffff00 

In the above output you can see, a tunnel has been created between the two hosts 172.17.1.254 and 172.18.1.254. The traffic between 192.168.1.1 and 192.168.2.1 pass through this tunnel, latter on we will secure this tunnel through IPSec.

On the other end (172.18.1.254) you would see this:

gif0: flags=8051< ,POINTOPOINT,RUNNING,MULTICAST> metric 0 mtu 1280
        tunnel inet 172.18.1.254 --> 172.17.1.254
        inet 192.168.2.1 --> 192.168.1.1 netmask 0xffffff00 

In the above output you can see, a tunnel has been created between the two hosts 172.18.1.254 and 172.17.1.254. The traffic between 192.168.2.1 and 192.168.1.1 pass through this tunnel.

A new entry will be added automatically in the routing table on both sides, which you can examine with the command netstat -rn. you would see a output like this.

netstat -rn
192.168.2.1    192.168.1.1   UH    1   1    gif0 

Securing the link

We want to secure our both side tunnels for this we will be use IPsec. IPsec provides a mechanism for two hosts to agree on an encryption key to encrypt data between the two hosts.

Security associations and security policies are both maintained by the kernel, and can be modified by userland programs. However, before you can do this you must configure the kernel to support IPsec and the Encapsulated Security Payload (ESP) protocol. This is done by configuring a kernel with:

Options IPSEC 		#IP security
Options IPSEC_DEBUG 	#debug IP security
Device  crypto

We don’t need to do this again, as you know we already compiled these options into our kernel.

IPSec Configuration

There are a number of choices for daemons to manage security associations with FreeBSD. In this article we will describe how to use one of these, racoon¬†– which is available from security/ipsec-tools in the FreeBSD Ports collection.

cd /usr/ports/security/ipsec-tools
make install clean 

After the installation of ipsec-toosl create a directory /usr/local/etc/racoon

mkdir /usr/local/etc/racoon

The racoon software must be run on both sides. Each host it is configured with the IP address of the other end VPN, and a secret key (which we will create in /usr/local/etc/racoon/psk.txt.

Before configuring racoon.conf file we should create /etc/ipsec.conf keys on both machines.

Now let’s create a key on 172.17.1.254 machine.

 vi /etc/ipsec.conf 
spdadd 172.17.1.254/32 172.18.1.254/32 ipencap -P out ipsec
esp/tunnel/192.168.1.1-192.168.2.1/require;
spdadd 172.18.1.254/32 172.17.1.254/32 ipencap -P in ipsec
esp/tunnel/192.168.2.1-192.168.1.1/require;

On the 172.18.1.254 side.

 vi /etc/ipsec.conf 
spdadd 172.18.1.254/32 172.17.1.254/32 ipencap -P out ipsec
esp/tunnel/192.168.2.1-192.168.1.1/require;
spdadd 172.17.1.254/32 172.18.1.254/32 ipencap -P in ipsec
esp/tunnel/192.168.1.1-192.168.2.1/require;

The above racoon’s policies will encrypt all traffic following between the following hosts 172.17.1.254 & 172.18.1.254 and by using tunnel mode it will also provide protection(‚Äúauthentication‚Äù) of the IP packet.

We need to enable ipsec in /etc/rc.conf on both sides so ipsec automatically run when machine is boot.

ipsec_enable="YES"
ipsec_file="/etc/ipsec.conf"

Now let’s configure racoon.conf on the machine A side (172.17.1.254).

vi /usr/local/etc/racoon/racoon.conf

path include "/usr/local/etc/racoon";
path pre_shared_key "/usr/local/etc/racoon/psk.txt"; 
# "padding" defines some padding parameters.
{
        maximum_length 20;      # maximum padding length.
        randomize off;          # enable randomize length.
        strict_check off;       # enable strict check.
        exclusive_tail off;     # extract last one octet.
}
listen
{
        isakmp 172.17.1.254 [500];
}
# Specify various default timers.
timer
{
        # These value can be changed per remote node.
        counter 5;              # maximum trying count to send.
        interval 20 sec;        # maximum interval to resend.
        persend 1;              # the number of packets per send.
        phase1 30 sec;
        phase2 15 sec;
}
remote anonymous
{
        exchange_mode main,aggressive;
        doi ipsec_doi;
        situation identity_only; 
        my_identifier asn1dn;
        certificate_type x509 "my.cert.pem" "my.key.pem"; 
        nonce_size 16;
        initial_contact on;
        proposal_check obey;    # obey, strict, or claim 
        proposal {
                encryption_algorithm 3des;
                hash_algorithm sha1;
                authentication_method rsasig;
                dh_group 2;
        }
} 
remote 172.18.1.254 [500]
{
        exchange_mode aggressive,main;
        doi ipsec_doi;
        situation identity_only;
        nonce_size 16;
        lifetime time 1 min;    # sec,min,hour
        initial_contact on;
        proposal_check obey;
        proposal {
                encryption_algorithm blowfish;
                hash_algorithm sha1;
                authentication_method pre_shared_key;
                dh_group 2;
        }
} 
sainfo anonymous
{
        pfs_group 2;
        encryption_algorithm 3des;
        authentication_algorithm hmac_sha1;
        compression_algorithm deflate;
} 
sainfo address 172.17.1.254 any address 172.18.1.254 any
{
        pfs_group 1;
        lifetime time 3600 sec;
        encryption_algorithm blowfish;
        authentication_algorithm hmac_md5;
        compression_algorithm deflate;
} 

As you can see I used isakmp 172.17.1.254 [500] on A side machine.

Thes listen section tells the demon what ip address and port to bind to. If you don’t specify anything under the Listen section, the daemon will attempt to bind port 500 on all available interfaces.

In the remote section I have defined Side B ip address (172.18.1.254) and tell the daemon to use shared-key authentication on both sides.

The remote section is for IKE phase 1 & the sainfo is for IKE phase 2.

Now we need to create psk.txt file for shared key. In this file we will define Side B ip address with shared password. The file permission should be 644 on both sides.

cd /usr/local/etc/racoon/
echo "172.18.1.254 shared_password" > psk.txt
chmod 644 psk.txt 

Side A is configured we need to edit racoon.conf on Side B

Let’s configure /usr/local/etc/racoon/racoon.conf on the machine (172.18.1.254).

vi /usr/local/etc/racoon/racoon.conf

path include "/usr/local/etc/racoon";
path pre_shared_key "/usr/local/etc/racoon/psk.txt"; 
# "padding" defines some padding parameters.
{
        maximum_length 20;      # maximum padding length.
        randomize off;          # enable randomize length.
        strict_check off;       # enable strict check.
        exclusive_tail off;     # extract last one octet.
}
listen
{
        isakmp 172.18.1.254 [500];
}
# Specify various default timers.
timer
{
        # These value can be changed per remote node.
        counter 5;              # maximum trying count to send.
        interval 20 sec;        # maximum interval to resend.
        persend 1;              # the number of packets per send.
        phase1 30 sec;
        phase2 15 sec;
}
remote anonymous
{
        exchange_mode main,aggressive;
        doi ipsec_doi;
        situation identity_only; 
        my_identifier asn1dn;
        certificate_type x509 "my.cert.pem" "my.key.pem"; 
        nonce_size 16;
        initial_contact on;
        proposal_check obey;    # obey, strict, or claim 
        proposal {
                encryption_algorithm 3des;
                hash_algorithm sha1;
                authentication_method rsasig;
                dh_group 2;
        }
} 
remote 172.17.1.254 [500]
{
        exchange_mode aggressive,main;
        doi ipsec_doi;
        situation identity_only;
        nonce_size 16;
        lifetime time 1 min;    # sec,min,hour
        initial_contact on;
        proposal_check obey;
        proposal {
                encryption_algorithm blowfish;
                hash_algorithm sha1;
                authentication_method pre_shared_key;
                dh_group 2;
        }
} 
sainfo anonymous
{
        pfs_group 2;
        encryption_algorithm 3des;
        authentication_algorithm hmac_sha1;
        compression_algorithm deflate;
} 
sainfo address 172.18.1.254 any address 172.17.1.254 any
{
        pfs_group 1;
        lifetime time 3600 sec;
        encryption_algorithm blowfish;
        authentication_algorithm hmac_md5;
        compression_algorithm deflate;
} 

As you can see I used isakmp 172.18.1.254 [500] on 172.18.1.254 machine.

In the remote section I have defined Side A ip address (172.17.1.254)

Let’s create shared key authentication file on Side B machine. In this file we will define other Side A ip address and shared password

cd /usr/local/etc/racoon/
echo "172.17.1.254 shared_password" > psk.txt
chmod 644 psk.txt 

Everything is configured and placed, we need to enable racoon in /etc/rc.conf on both sides and then start racoon daemon.

racoon_enable="YES"
racoon_flags="-l /var/log/racoon.log && echo -n ' racoon'" 

Let’s start racoon on both machines.

/usr/local/etc/rc.d/racoon start 

After starting the racoon daemon you can test your encrypted tunnel with setkey -DP, Let’s run this command on Side A (172.17.1.254)

setkey -DP 

The ouput of above command should be like this.

172.18.1.254[any] 172.17.1.254[any] ip4
        in ipsec
        esp/tunnel/172.18.1.254-172.17.1.254/require
        spid=2 seq=1 pid=1144
        refcnt=1
172.17.1.254[any] 172.18.1.254[any] ip4
        out ipsec
        esp/tunnel/172.17.1.254-172.18.1.254/require
        spid=1 seq=0 pid=1144
        refcnt=1 

Above output means you have successfully configred your IPSec on FreeBSD.

Let’s test our IPSec tunnel to ensure that everything is running fine. On Side A we will ping Side B internal ip address e.g.

ping 192.168.2.1 

And get a response, you should be able to do the same thing on the other Side B machine.

However, you will not be able to reach other internal machines on both sides. This is because of the routing — although the gateway machines know how to reach one another, but they do not know how to reach the entire network.

To solve this problem we have to add a static route on each Sides. The command to do this on the first Side A (172.17.1.254)

route add 192.168.2.0 192.168.2.1 

This says “In order to reach on the entire network 192.168.2.0, send the packets to the host 192.168.2.1”.

On Side B (17.18.1.254) would be:

route add 192.168.1.0 192.168.1.1 

This says “In order to reach on the entire network 192.168.1.0, send the packets to the host 192.168.1.1”.

We need to set these entries in /etc/rc.conf so whenever computer is rebooting it’s automatically up and running.

On machine 172.17.1.254 add these entries in /etc/rc.conf

gif_interfaces="gif0"
gifconfig_gif0="172.17.1.254 17.18.1.254"
ifconfig_gif0="192.168.1.1 192.168.2.1 netmask 255.255.255.0"
static_routes="vpn"
route_vpn="192.168.2.0/24 192.168.2.1" 

And machine 172.18.1.254 add these entries in /etc/rc.conf

gif_interfaces="gif0"
gifconfig_gif0="172.18.1.254 17.17.1.254"
ifconfig_gif0="192.168.2.1 192.168.1.1 netmask 255.255.255.0"
static_routes="vpn"
route_vpn="192.168.2.0/24 192.168.2.1" 

Firewall Setup:

It is likely that you are running a firewall on both machines. In this regards you might want to allow all traffic between both networks, or you might want to include firewall rules that protect both ends of the VPN from one another.

If you are using pf then you will need to run this command on both gateway hosts.

pass in quick on gif0 from any to any keep state 

It will allow all traffic between the two end points of the VPN

This solution was configured and test successfully on FreeBSD 7.2. But We do not assume any responsibility or we are not liable for any damage which may have been occurred tu to implementation of this solution.

Your comments on this post helpful for us to make more competent howtos for you.

8 comments

  1. Vimuth Dayaratne says:

    What an excellent piece of guide. Out of curiosity Sir can we do this exercise having only one NIC’s installed on either of those BSD boxes which we are creating the tunnel in between? Possibly by means of IP aliasing may be if at all supported? Please upload more BSD guides. Thank you very much.

    Best Regards
    Vimuth
    PS: Who is the author of this article? Please mention the name of the gentleman who wrote this. :)

  2. admin says:

    Hmm.

    I haven’t try it. But I think it is possible on single NIC.

    BTW: thanks for your nice comment.

    Regards,
    Tech Babu

  3. Ilya says:

    Very good article, but I don’t understand how you obtain from this rules in

    /etc/ipsec.conf
    spdadd 172.17.1.254/32 172.18.1.254/32 ipencap -P out ipsec
    esp/tunnel/192.168.1.1-192.168.2.1/require;
    spdadd 172.18.1.254/32 172.17.1.254/32 ipencap -P in ipsec
    esp/tunnel/192.168.2.1-192.168.1.1/require;

    this result of setkey -DP
    172.18.1.254[any] 172.17.1.254[any] ip4
    in ipsec
    esp/tunnel/172.18.1.254-172.17.1.254/require
    spid=2 seq=1 pid=1144
    refcnt=1
    172.17.1.254[any] 172.18.1.254[any] ip4
    out ipsec
    esp/tunnel/172.17.1.254-172.18.1.254/require
    spid=1 seq=0 pid=1144
    refcnt=1

    ????
    P.S. Sorry for my english ):

  4. TechBabu says:

    Hi

    The rules are very clear, we have two hosts ( Host -A 172.17.1.254 ) and ( Host -B 172.18.1.254). with tunnels both end (Host -A 192.168.1.1) and (Host -B 192.168.2.1). the above rules are very simple. From (Host -A) traffic for (Host -B) will pass through (192.168.1.1).

    Regards

  5. Ilya says:

    Thanks for your answer.

    Regards,
    Ilya

  6. [...] here Tags: bsd, freebsd, how to install ipsec on freebsd, ipsec, ipsec for freebsd, ipsec freebsd, [...]

  7. Zaeedh says:

    Techbabu, you have a systematic vision ! and this is shows on your tutorial, thanks a lot :)
    now I’ll should be have an “A” on my college paper.hehe..

    Kind Regards,
    Zaeedh

  8. Aulia says:

    Hi,
    can I have an ask for something with my configuration ?

    I have finished this tutorial to build ipsec site to site, and the step has finished completely.
    I have a simulation with a local design topology with two PC’s (FreeBSD 7.0) and the replace for public network (internet media) with a single switch device in the middle, it’s look like this :

    (PC-A)
    Local Network A : 192.168.0.1/24
    Network (Gateway) A : 202.10.10.1/24

    SWITCH

    (PC-B)
    Network (Gateway) B : 202.10.10.2/24
    Local Network B : 172.168.0.1/24

    I got connect all this host by used a static routing, at first the communication between two site is completely connect eg. (Ping to Local Network B to Local Network A).

    but when I’ve finished config the tunnel (GIF interface), started the racoon and ipsec daemon with those all configuration, I can’t any longer ping the outside local network (Request Time out).

    and sure there’s no ESP protokol packet in the output of tcpdump on the traffic, I’ve tried Racoon-F command too, but the output is stack and look’s not running.

    Please, any suggest from this problem :)

    I’m really appreciated with the respons, Thank’s in advance :)

    Aulia.

Leave a Reply

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

*