# ipsec with dynamic IP



## da1 (Sep 29, 2010)

Hello fellas,

I have 2x 8.1-RELEASE machines and I need to create a vpn between them. I've been reading the handbook on this subject and following the example there, I was able to establish a link.

The only problem is that both my machines have dynamic (external) IP.

My way of "solving" this little issue would be to create a script that would check each machine for a new external IP and if it finds it, replace it wherever it is needed (gif interface, racoon conf. file)

My question to you is if there is another, cleaner, way of achieving this and if any of you faced the same situation, how did you come to solve it ?


----------



## bes (Sep 29, 2010)

perhaps dns/inadyn will be usefull?


----------



## da1 (Sep 29, 2010)

I think you missed my point and/or what I want to achieve.

inadyn is a dynamic IP client for updating the IP of a dns.

IPSEC + gif interfaces (as described in the handbook) require that you manually set all the IP's on the gif interface itself. Since you cannot set hostnames instead of IP's, inadyn pretty much helps ..... nada here 

However, it was suggested on the mailling list that I try openvpn, which I intend to do, but in the meantime I am working on a script that will update the gif interface with the appropriate IP's. 

I will post it here once it's done.



In the meantime, more ideas are welcomed.


----------



## da1 (Oct 2, 2010)

So, finally done.

The script only updates the gifX interface with the proper IP's and set's the routing tables for the other end of the VPN. It get's the other IP via: [CMD=""]dig[/CMD]

Adjusted or change it as you see fit.
I'm by far a scripting guru.

```
#!/bin/sh

#set -x                                                        # Uncoment if needed for debugging

######################## GLOBALS #################################

# Interfaces
ext_if="tun0"                                                   # Local external interface name
int_if="re0"                                                    # Local internal interface name
gif_if="gif0"                                                   # gif interface name+number

# Local section
local_int_IP="192.168.0.1"                                      # Local internal IP
local_network="192.168.0.0/24"                                  # Local network (with mask)
#local_dns="mainserver.da1.ro"                                  # Local DNS (if any)

# Remote section
remote_int_IP="192.168.1.1"                                     # Remote internal IP
remote_network="192.168.1.0/24"                                 # Remote network (with mask)
remote_dns="mainserver1.catedral.ro"                            # Remote DNS (mandatory)


######################### EXECUTABLES #############################

dig="/usr/local/bin/dig"                                        # Full path to: dig
if [ ! -f $dig ];then
echo "Cannot find $dig executable in the mentioned path. Pls adjust the path in the script ..."
echo "Exiting ..."
exit 1
fi

grep="/usr/bin/grep"                                            # Full path to: grep
if [ ! -f $grep ];then
echo "Cannot find $grep executable in the mentioned path. Pls adjust the path in the script ..."
echo "Exiting ..."
exit 1
fi

awk="/usr/bin/awk"                                              # Full path to: awk
if [ ! -f $awk ];then
echo "Cannot find $awk executable in the mentioned path. Pls adjust the path in the script ..."
echo "Exiting ..."
exit 1
fi

ifconfig="/sbin/ifconfig"                                       # Full path to: ifconfig
if [ ! -f $ifconfig ];then
echo "Cannot find $ifconfig executable in the mentioned path. Pls adjust the path in the script ..."
echo "Exiting ..."
exit 1
fi

netstat="/usr/bin/netstat"                                       # Full path to: ifconfig
if [ ! -f $netstat ];then
echo "Cannot find $netstat executable in the mentioned path. Pls adjust the path in the script ..."
echo "Exiting ..."
exit 1
fi

route="/sbin/route"                                       # Full path to: ifconfig
if [ ! -f $route ];then
echo "Cannot find $route executable in the mentioned path. Pls adjust the path in the script ..."
echo "Exiting ..."
exit 1
fi


# Check if gif_if exists. If it doesn't, create it.
$ifconfig $gif_if >> /dev/null
if [ $? != "0" ];then
echo "Interface $gif_if does not exist. Creating it ..."
$ifconfig $gif_if create
wait
echo "GIF interface $gif_if created. Remember to set gif_interfaces=\"$gif_if\" in rc.conf"
sleep 1
fi


########################### CMD's ################################

# Get the local IP from the ext_if (with ifconfig cmd)
local_IP="`$ifconfig $ext_if | $grep inet | $awk '{print $2}'`"

# Get the remote IP from a DNS server (with dig)
remote_IP="`$dig $remote_dns | $grep $remote_dns | $awk '{print $5}' | $grep -o '[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}'`"

# Assume that the gif interface mentioned above has been created and:
# Get local ("tunnel") IP from the gif interface (if any at the first run of the script)
local_gif_tunnel_IP="`$ifconfig $gif_if | $grep "tunnel inet" | $awk '{print $3}'`"

# Get the remote ("tunnel") IP from the gif interface
remote_gif_tunnel_IP="`$ifconfig $gif_if | $grep "tunnel inet" | $awk '{print $5}'`"

# Get the local IP from the gif interface (int network IP)
local_gif_IP="`$ifconfig $gif_if | $grep netmask | $awk '{print $2}'`"

# Get the remote IP from the gif interface (int network IP)
remote_gif_IP="`$ifconfig $gif_if | $grep netmask | $awk '{print $4}'`"

# Check if the route exists
check_route="`$netstat -f inet -rn | $grep $remote_network | $awk '{print $1}'`"


# Update the EXTERNAL IP's

if [ "$local_IP" != "$local_gif_tunnel_IP" ];then
           local_IP1=$local_IP
                if [ "$remote_IP" != "$remote_gif_tunnel_IP" ];then
                   remote_IP1=$remote_IP
                        $ifconfig $gif_if tunnel $local_IP1 $remote_IP1
                else
                   remote_IP2=$remote_IP
                        $ifconfig $gif_if tunnel $local_IP1 $remote_IP2
                fi
else # if equal, local_IP stays the same
                if [ "$remote_IP" != "$remote_gif_tunnel_IP" ];then
                   remote_IP2=$remote_IP
                        $ifconfig $gif_if tunnel $local_IP $remote_IP2
                fi
fi


# Update the INTERNAL IP's

if [ "$local_int_IP" != "$local_gif_IP" ];then
           local_int_IP1=$local_int_IP
               if [ "$remote_gif_IP" != "$remote_int_IP" ];then
                   remote_int_IP1=$remote_int_IP
                        $ifconfig $gif_if $local_int_IP1 $remote_int_IP1
                else
                        $ifconfig $gif_if $local_int_IP1 $remote_int_IP1
                fi
else # if equal, local_IP stays the same
                if [ "$remote_int_IP" != "$remote_gif_IP" ];then
                        $ifconfig $gif_if $local_int_IP $remote_int_IP1
                fi
fi



# A static route should be added at boot via rc.conf
# Check if it's present. If not, add it.

if [ "$check_route" != "$remote_network"  ];then
$route add -net $remote_network $remote_int_IP
fi
```

I have it running every 10 minutes via crontab and I have a static route option in rc.conf


More to come. PHASE2 will include changing the IP's for racoon2 in racoon.conf.


----------



## da1 (Oct 17, 2010)

Finally done.

racoon.sh:

```
#!/bin/sh

#set -x

. /root/scripts/util/library.sh

# LOCAL
local_int_net="192.168.0.0/24"                                  # Local internal network (with netmask)
local_ext_if="tun0"
wrk_dir="/tmp"
setkey_file="/etc/ipsec.conf"
racoon_file="/usr/local/etc/racoon2/racoon2.conf"
racoon_log="/var/log/racoon.log"
racoon_pre_shared_key="/usr/local/etc/racoon2/psk.txt"

######################### server1 #############################

server1_dns="server1.com"                                       # DNS
server1_int_net="192.168.1.0/24"                                # internal network (with netmask)



######################### server2 #############################

server2_dns="server2.com"                                       # DNS
server2_int_net="192.168.2.0/24"                                # internal network (with netmask)


######################### EXECUTABLES #############################

local_ext_IP="`$ifconfig $local_ext_if | $grep inet | $awk '{print $2}'`"
server1_ext_IP="`$dig $server1_dns | $grep $server1_dns | $awk '{print $5}' | $grep -o '[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\
{1,3\}'`"
server2_ext_IP="`$dig $server2_dns | $grep $server2_dns | $awk '{print $5}' | $grep -o '[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\
{1,3\}'`"


if [ "$local_ext_IP" != "`$cat $wrk_dir/local_current_IP`" ] || [ "$server1_ext_IP" != "`$cat $wrk_dir/server1_current_ext_IP`" ] || [ 
"$server2_ext_IP" != "`$cat $wrk_dir/server2_current_ext_IP`" ];then
echo "\
#
#
# !!! DO NOT CHANGE THIS FILE SINCE IT IT OVERWRITEN PERIODICALY !!!
# !!!      MODIFY /root/scripts/racoon.sh INSTEAD    !!!
#
#
#
flush;
#
spdflush;
#
# local -> server1
#      local internal remote internal                        local external remote external
#          IP               IP                                    IP          IP
spdadd $local_int_net $server1_int_net any -P out ipsec esp/tunnel/$local_ext_IP-$server1_ext_IP/require;
#
#      remote internal local internal                        remote external  local external
#          IP               IP                                    IP          IP
spdadd $server1_int_net $local_int_net any -P in ipsec esp/tunnel/$server1_ext_IP-$local_ext_IP/require;


# local -> server2
#      local internal remote internal                        local external remote external
#          IP               IP                                    IP          IP
spdadd $local_int_net $server2_int_net any -P out ipsec esp/tunnel/$local_ext_IP-$server2_ext_IP/require;
#
#      remote internal local internal                        remote external  local external
#          IP               IP                                    IP          IP
spdadd $server2_int_net $local_int_net any -P in ipsec esp/tunnel/$server1_ext_IP-$local_ext_IP/require;



# local -> server3
#      local internal remote internal                        local external remote external
#          IP               IP                                    IP          IP
#spdadd $local_int_net $server3_int_net any -P out ipsec esp/tunnel/$local_ext_IP-$server3_ext_IP/require;
#
#      remote internal local internal                        remote external  local external
#          IP               IP                                    IP          IP
#spdadd $server3_int_net $local_int_net any -P in ipsec esp/tunnel/$server3_ext_IP-$local_ext_IP/require;
" > $setkey_file
/etc/rc.d/ipsec onerestart

##################### RACOON SECTION #########################################

echo "\
#
#
#
# !!! DO NOT CHANGE THIS FILE SINCE IT IS OVERWRITEN PERIODICALY !!!
# !!!      MODIFY /root/scripts/util/racoon.sh INSTEAD    !!!
#
#
#
path    pre_shared_key  \"$racoon_pre_shared_key\"; #location of pre-shared key file
log     debug;  #log verbosity setting: set to 'notify' when testing and debugging is complete

padding # options are not to be changed
{
        maximum_length  20;
        randomize       off;
        strict_check    off;
        exclusive_tail  off;
}

timer   # timing options. change as needed
{
        counter         5;
        interval        20 sec;
        persend         1;
#       natt_keepalive  15 sec;
        phase1          30 sec;
        phase2          15 sec;
}

listen  # address [port] that racoon will listening on
{
        isakmp          $local_ext_IP [500];
        isakmp_natt     $local_ext_IP [4500];
}

# server1
remote  $server1_ext_IP [500]
{
        exchange_mode   main,aggressive;
        doi             ipsec_doi;
        situation       identity_only;
        my_identifier   address $local_ext_IP;
        peers_identifier        address $server1_ext_IP;
        lifetime        time 8 hour;
        passive         off;
        proposal_check  obey;
#       nat_traversal   off;
        generate_policy off;

                        proposal {
                                encryption_algorithm    blowfish;
                                hash_algorithm          md5;
                                authentication_method   pre_shared_key;
                                lifetime time           30 sec;
                                dh_group                1;
                        }
}

# server2
remote  $server2_ext_IP [500]
{
        exchange_mode   main,aggressive;
        doi             ipsec_doi;
        situation       identity_only;
        my_identifier   address $local_ext_IP;
        peers_identifier        address $server2_ext_IP;
        lifetime        time 8 hour;
        passive         off;
        proposal_check  obey;
#       nat_traversal   off;
        generate_policy off;

                        proposal {
                                encryption_algorithm    blowfish;
                                hash_algorithm          md5;
                                authentication_method   pre_shared_key;
                                lifetime time           30 sec;
                                dh_group                1;
                        }
}

# server3
#remote  $server3_ext_IP [500]
#{
#        exchange_mode   main,aggressive;
#        doi             ipsec_doi;
#        situation       identity_only;
#        my_identifier   address $local_ext_IP;
#        peers_identifier        address $server3_ext_IP;
#        lifetime        time 8 hour;
#        passive         off;
#        proposal_check  obey;
##       nat_traversal   off;
#        generate_policy off;
#
#                        proposal {
#                                encryption_algorithm    blowfish;
#                                hash_algorithm          md5;
#                                authentication_method   pre_shared_key;
#                                lifetime time           30 sec;
#                                dh_group                1;
#                        }
#}


# server1
sainfo  (address $local_int_net any address $server1_int_net any)    # address $network/$netmask $type address $network/$netmask $type ( $type 
being any or esp)
{                               # $network must be the two internal networks you are joining.
        pfs_group       1;
        lifetime        time    36000 sec;
        encryption_algorithm    blowfish,3des,des;
        authentication_algorithm        hmac_md5,hmac_sha1;
        compression_algorithm   deflate;
}

# server2
sainfo  (address $local_int_net any address $server2_int_net any)    # address $ne
{                               # $network must be the two internal networks you
        pfs_group       1;
        lifetime        time    36000 sec;
        encryption_algorithm    blowfish,3des,des;
        authentication_algorithm        hmac_md5,hmac_sha1;
        compression_algorithm   deflate;
}

# server3
#sainfo  (address $local_int_net any address $server3_int_net any)    # address $n
#{                               # $network must be the two internal networks yo
#        pfs_group       1;
#        lifetime        time    36000 sec;
#        encryption_algorithm    blowfish,3des,des;
#        authentication_algorithm        hmac_md5,hmac_sha1;
#        compression_algorithm   deflate;
#}" > $racoon_file

echo "\
$server1_ext_IP key_1234567890_qwertyuiop
$server2_ext_IP key_1234567890_qwertyuiop" > $racoon_pre_shared_key

   if $pgrep racoon > /dev/null
      then
        $pkill racoon > /dev/null
        wait
        $racoon -f $racoon_file -l $racoon_log
      else
        $racoon -f $racoon_file -l $racoon_log
   fi

echo "$local_ext_IP" > $wrk_dir/local_current_IP
echo "$server1_ext_IP" > $wrk_dir/server1_current_ext_IP
echo "$server2_ext_IP" > $wrk_dir/server2_current_ext_IP
else
   if ! $pgrep racoon > /dev/null
     then
        $racoon -f $racoon_file -l $racoon_log
   fi
fi
```

. /root/scripts/util/library.sh contains different paths used throughout the script. If a certain path does not exist, the script exists with error code "1".
ex:

```
dig="/usr/local/bin/dig"                                        # Full path to: dig
if [ ! -f $dig ];then
echo "Cannot find $dig executable in the mentioned path. Pls adjust the path in the script ..."
echo "Exiting ..."
exit 1
fi

grep="/usr/bin/grep"                                            # Full path to: grep
if [ ! -f $grep ];then
echo "Cannot find $grep executable in the mentioned path. Pls adjust the path in the script ..."
echo "Exiting ..."
exit 1
fi
```


----------



## da1 (Oct 17, 2010)

In the racoon.sh script, one only needs to update the "header" with 2 machines (int_IP, dns). A 3rd machine is configured inside the racoon.conf file but it's variables are not set in the header of the racoon.sh script.

I'm sure it can be written better but for now, this is what I am using. The scripts (gif*.sh + racoon.sh) runs via crontab every 10 minutes.

Tested and working on 3x 8.1-RELEASE i386 gateways (4th machine to come).

*@DD:* maybe this thread should be moved to "scripts" ?


----------



## TheHolm (Mar 26, 2013)

Big thanks for posting your script. It saves me lots of time to write it myself. I guess racoon port needs /contrib portion for stuff like that.


----------



## Anonymous (Mar 26, 2013)

@TheHolm

If you use dhclient(8)() for obtaining the dynamic IP address, then you could run that script from /etc/dhclient-exit-hooks, by this way, the IP settings of racoon are updated immediately after dhclient got a new IP, otherwise with a crontab there might be a significant lag until the IP gets updated.

If by chance you have NAT and ipfw(8)() already running on the machine, then it would be perhaps less involved, to let racoon listen on an internal static IP and use NAT for redirecting external connections to it. If you don't have and don't need NAT/ipfw otherwise, then I suggest to keep the script solution.


----------



## da1 (Mar 27, 2013)

Latest version of the script(s) (no longer needs library.sh ):

For updating the gif interfaces:

```
#!/bin/sh
#
#
# Date: 01.10.2010
# Author: Claudiu Vasadi
# Licence: BSD
#
######################## Description ##########################
#                                                             #
#      Script to update the IP's for 1x "gif" interface       #
#                                                             #
# CHECK THE "GLOBALS" VARIABLES BEFORE LAUNCHING THE SCRIPT ! #
#							      #
###############################################################
# Copyright 2010 Claudiu Vasadi. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without modification, are
# permitted provided that the following conditions are met:
#
#   1. Redistributions of source code must retain the above copyright notice, this list of
#      conditions and the following disclaimer.
#
#   2. Redistributions in binary form must reproduce the above copyright notice, this list
#      of conditions and the following disclaimer in the documentation and/or other materials
#      provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY Claudiu Vasadi ``AS IS'' AND ANY EXPRESS OR IMPLIED
# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Claudiu Vasadi OR
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# The views and conclusions contained in the software and documentation are those of the
# authors and should not be interpreted as representing official policies, either expressed
# or implied, of Claudiu Vasadi.

PATH=/bin:/sbin:/usr/bin:/usr/sbin

#set -x								# Uncoment if needed for debugging


######################## GLOBALS #################################

# Interfaces
ext_if="tun0"							# Local external interface name
int_if="rl0"							# Local internal interface name
gif_if="gif0"							# gif interface name+number

# Local section
local_int_IP="192.168.1.1"					# Local internal IP
local_network="192.168.1.0/24"					# Local network (with mask)
#local_dns="local_DNS_if_any.com"				# Local DNS (if any)

# Remote section
remote_int_IP="192.168.0.1"					# Remote internal IP
remote_network="192.168.0.0/24"					# Remote network (with mask)
remote_dns="remote_DNS_goes_here.com"				# Remote DNS (mandatory)


########################### CMD's ################################

# Check if gif_if exists. If it doesn't, create it.
ifconfig $gif_if >> /dev/null
if [ $? != "0" ];then
ifconfig $gif_if create
fi

# Get the local IP from the ext_if (with ifconfig cmd)
local_IP="`ifconfig $ext_if | grep inet | awk '{print $2}'`"

# Get the remote IP from a DNS server (with dig)
remote_IP="`dig $remote_dns | grep $remote_dns | awk '{print $5}' | grep -o '[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}'`"

if [ -z $remote_IP ];then
   echo "Cannot get ${remote_dns}'s IP. Exiting ..."
   exit 1
fi

# Assume that the gif interface mentioned above has been created and:
# Get local ("tunnel") IP from the gif interface (if any at the first run of the script)
local_gif_tunnel_IP="`ifconfig $gif_if | grep "tunnel inet" | awk '{print $3}'`"

# Get the remote ("tunnel") IP from the gif interface
remote_gif_tunnel_IP="`ifconfig $gif_if | grep "tunnel inet" | awk '{print $5}'`"

# Get the local IP from the gif interface (int network IP)
local_gif_IP="`ifconfig $gif_if | grep netmask | awk '{print $2}'`"

# Get the remote IP from the gif interface (int network IP)
remote_gif_IP="`ifconfig $gif_if | grep netmask | awk '{print $4}'`"

# Check if the route exists
check_route="`netstat -f inet -rn | grep $remote_network | awk '{print $1}'`"


# Update the EXTERNAL IP's

if [ "$local_IP" != "$local_gif_tunnel_IP" ];then
	   local_IP1=$local_IP
		if [ "$remote_IP" != "$remote_gif_tunnel_IP" ];then
           	   remote_IP1=$remote_IP
			ifconfig $gif_if tunnel $local_IP1 $remote_IP1
		else
		   remote_IP2=$remote_IP
			ifconfig $gif_if tunnel $local_IP1 $remote_IP2
		fi
else # if equal, local_IP stays the same
		if [ "$remote_IP" != "$remote_gif_tunnel_IP" ];then
                   remote_IP2=$remote_IP
                        ifconfig $gif_if tunnel $local_IP $remote_IP2
                fi
fi


# Update the INTERNAL IP's

if [ "$local_int_IP" != "$local_gif_IP" ];then
           local_int_IP1=$local_int_IP
               if [ "$remote_gif_IP" != "$remote_int_IP" ];then
                   remote_int_IP1=$remote_int_IP
                        ifconfig $gif_if $local_int_IP1 $remote_int_IP1
                else
                        ifconfig $gif_if $local_int_IP1 $remote_int_IP1
                fi
else # if equal, local_IP stays the same
                if [ "$remote_int_IP" != "$remote_gif_IP" ];then
                        ifconfig $gif_if $local_int_IP $remote_int_IP1
                fi
fi



# Add a static route
if [ "$check_route" != "$remote_network"  ];then
route add -net $remote_network $remote_int_IP
fi
```

racoon.sh is also attached (could not post the code because it's too long).


----------

