| How
to easily build a VPN with KAME IPSec (Kernel 2.6) by Cristiano da Cunha Duarte (cunha17@gmail.com) homepage at http://cunha17.cristianoduarte.pro.br |
|
Page created: Jan 04, 2005 Page last modified: Nov 12, 2005 |
![]() |
![]() ![]() ![]() ![]() ![]() ![]() |
![]() ![]() ![]() ![]() ![]() ![]() |
![]() |
|||||
| Net1 |
Gw1 |
IPSec
Channels |
Internet |
IPSec
Channels |
Gw2 |
Net2 |
||
![]() ![]() ![]() ![]() ![]() ![]() |
![]() |
![]() ![]() ![]() ![]() ![]() ![]() |
![]() ![]() ![]() ![]() ![]() |
|||
| Client |
IPSec
Channels |
Dial-up |
IPSec
Channels |
Internet |
IPSec
Channels |
Server |
| ATTENTION: a SA can only be used if it's "associated" with a policy, this association can only be established if there is a policy which rule has the same parameters as the SA. |
NOTE: There may exist
a functional SP without a SA in two ways:
|
| ATTENTION:
if you want to create more restrictive rules(and you should), just add
the source and destination address of the gateways to the rules above.
Don't forget that those address are Internet(or non-secure) source and
destination address of the gateways. |
| CAREFUL: the kernel
parameter /proc/sys/net/ipv4/conf/all/rp_filter
blocks
for IP spoofing and, as it is now disabled, the cheking must be done by
your own IPTABLES rules! However these rules must appear after the ones
above. |
| IMPORTANT NOTE
1: The IP header of an ESP packet cannot be modified by NAT, so
we cannot do NAT with a IPSec channel(at least directly,
NATT exists for this matter): there must not be any NAT between the
Gateways. If you use NAT at your firewall, add the following rules
before any other to tell iptables to not do NAT with the packets
flowing in the VPN: #We don't do NAT for ESP iptables -t nat -I PREROUTING 1 -j ACCEPT -p 50 iptables -t nat -I POSTROUTING 1 -j ACCEPT -p 50 |
IMPORTANT NOTE 2: There must not exist NAT between the networks connected by the tunnel if they
are mutually routeable. It is not necessary that the internal address
be valid, neither are the creation of static routes: IPSec
handles the routing of the packets to the remote gateway every time
that the destination address is within the remote network range. Ex:
|
||||||||||||||||||
| NOTE: This tutorial
assumes that at the other end an Aker Firewall is correctly configured.
If you wish to use a host with Linux
and kernel 2.6 as Gateway2, perform the same steps above with this
second machine, just replacing in with out
and vice versa at step 2 and the remote address at step
3. |
| Before going any further, check if the remote gateway doen't have a firewall blocking your packets. Verifiy the firewall's log and run TCPDUMP to see if the ICMP ECHO REQUEST packet arrives and the ICMP ECHO REPLY leaves. |
| Aplication | |
| Message |
|
| Transport | |
| Segment |
|
| Inter-network | |
| Datagram |
|
| Network Interface | |
| Frame |
|
| Intra-network |
#!/bin/bash
#Forces a fixed MSS to deal with the Path MTU Discovery problem
#ATTENTION:
# 1.You must allow ICMP echo-request and echo-response packets exchange between the LOCAL and REMOTE gateways
# 2.You must allow ICMP redirect and destination-unreachable from the INTERNET
# 3.You will need the BC and IPROUTE packages installed
#definition of the remote gateway and network
REMOTE_GATEWAY=200.200.200.200
REMOTE_NETWORK=172.16.0.0/24
#DEBUG option: set to 1 to enable messages
DEBUG=0
function compute_mss() {
#compute the MSS for IPSec based on the MTU passed as a parameter
#returns the computed value on the MSS variable
local MTU
local IP_HEADER_LENGTH
local ESP_HEADER_LENGTH
local AH_HEADER_LENGTH
local IPSEC_HEADER_LENGTH
local ENCRYPTION_HEADER_LENGTH
local SUBTOTAL_DATA_LENGTH
local DISCARDED_DATA_LENGTH
local DATA_LENGTH
MTU=$1
#average IP header length(20<->60)
IP_HEADER_LENGTH=40
#ESP header length
ESP_HEADER_LENGTH=8
#AH header length
AH_HEADER_LENGTH=12
#IPSec header length = ESP + AH
IPSEC_HEADER_LENGTH=`echo "$ESP_HEADER_LENGTH + $AH_HEADER_LENGTH" | bc`
#Encryption algorithm header length
ENCRYPTION_HEADER_LENGTH=16 #CBC initial value
#Final length = MSS
SUBTOTAL_DATA_LENGTH=`echo "$MTU - $IP_HEADER_LENGTH - $IPSEC_HEADER_LENGTH - $ENCRYPTION_HEADER_LENGTH" | bc`
DISCARDED_DATA_LENGTH=`echo "$SUBTOTAL_DATA_LENGTH % 16" | bc`
DATA_LENGTH=`echo "$SUBTOTAL_DATA_LENGTH - $DISCARDED_DATA_LENGTH" | bc`
MSS=$DATA_LENGTH
}
function pmtu_discovery()
{
#Do a PMTU discovery through ICMP packets between the LOCAL and REMOTE gateways.
#In fact, it uses a binary search algorithm to find the maximum PAYLOAD length of a ICMP packet on the channel
#and, with this information, computes the PMTU
local MIN
local MAX
local MTU
local TARGET
local OK
local AVG
local IP_HEADER_LENGTH
local ICMP_PAYLOAD_MAX
#IP header MINIMUM length (20<->60 bytes)
IP_HEADER_LENGTH=20
#ICMP header length (echo-request/echo-reply)
ICMP_HEADER_LENGTH=8
#definition of a BC function that returns the absolute value of a number, that is, the number without sign
LOADABS="
define abs(x) {
if (x>=0) return(x)
return(-x)
}
"
#destination host (firewall -> internet interface)
TARGET=$1
#minimum ICMP PAYLOAD length
MIN=400
#get the MTU from the interface that will be used on the gateway communication
MTU=`ip route get $TARGET | xargs | sed "s/.*mtu \([[:digit:]]\+\) .*/\1/"`
#maximum ICMP PAYLOAD length => MTU - IP HEADER - ICMP HEADER
MAX=`echo "$MTU-$IP_HEADER_LENGTH-$ICMP_HEADER_LENGTH" | bc`
#Path MTU Discovery through binary search
while [ `echo "$LOADABS abs($MIN - $MAX)" | bc` -gt 1 ]; do
#Compute the average value between MIN and MAX
AVG=`echo "scale=0;($MIN + $MAX) / 2" | bc`
if [ $DEBUG -eq 1 ]; then
echo -n "AVG=$AVG "
fi
#We send a ICMP packet:
# -s $AVG : with the PAYLOAD size of $AVG
# -q : quiet
# -M do : with the DF(Don't Fragment) flag set
# -W 2 : wait the answer for 2 seconds
# -c 1 : only one packet
# $TARGET : to the $TARGET host
#and redirect the output to /dev/null since we just need the exit code(or $?)
ping -s $AVG -q -M do -W 2 -c 1 $TARGET 1>/dev/null 2>/dev/null
OK=$?
if [ $OK == 0 ]; then
#It worked! So, the minimum is set to the average, that is, MIN=AVG
if [ $DEBUG -eq 1 ]; then
echo "[OK]"
fi
MIN=$AVG
else
#It doesn't work... so, the maximum is set to the average - 1, that is, MAX=AVG-1
if [ $DEBUG -eq 1 ]; then
echo "[NOK]"
fi
MAX=`echo "$AVG-1" | bc`
fi
#we send ICMP packets each 0.5 seconds trying not to wake an IDS or FIREWALL
sleep 0.5
done
#the $MIN value will be the maximum ICMP PAYLOAD length allowed between LOCAL and REMOTE gateways
ICMP_PAYLOAD_MAX=$MIN
#now we compute the PMTU => PAYLOAD + ICMP HEADER + IP HEADER
PMTU=`echo "$ICMP_PAYLOAD_MAX+$ICMP_HEADER_LENGTH+$IP_HEADER_LENGTH" | bc`
}
#variable initialization
MSS=-1
PMTU=-1
#do the PMTU discovery to the remote gateway. The variable PMTU will have the final value.
pmtu_discovery $REMOTE_GATEWAY
#computes the MSS based on the PMTU returned. The variable MSS will have the final value.
compute_mss $PMTU
#We include the following IPTABLES rules to FORCE the MSS on any connection establishment with the remote network
iptables -I FORWARD 1 -p tcp -d $REMOTE_NETWORK --tcp-flags SYN,RST SYN -j TCPMSS --set-mss $MSS
iptables -I FORWARD 2 -p tcp -s $REMOTE_NETWORK --tcp-flags SYN,RST SYN -j TCPMSS --set-mss $MSS
iptables -I OUTPUT 1 -p tcp -d $REMOTE_NETWORK --tcp-flags SYN,RST SYN -j TCPMSS --set-mss $MSS
iptables -I OUTPUT 2 -p tcp -s $REMOTE_NETWORK --tcp-flags SYN,RST SYN -j TCPMSS --set-mss $MSS
if [ $DEBUG -eq 1 ]; then
echo "PMTU=$PMTU"
echo "MSS=$MSS"
fi
exit 0
| Mode |
Host1 (10.0.0.216) | Host2 (10.0.0.11): |
| AH/transport | ipsec-transport-on-ah-216 #!/sbin/setkey -f flush; spdflush; #AH add 10.0.0.11 10.0.0.216 ah 15700 -A hmac-sha1 "12345678901234567890"; add 10.0.0.216 10.0.0.11 ah 24500 -A hmac-sha1 "12345678901234567890"; spdadd 10.0.0.216 10.0.0.11 any -P out ipsec ah/transport//require; spdadd 10.0.0.11 10.0.0.216 any -P in ipsec ah/transport//require; |
ipsec-transport-on-ah-11 #!/sbin/setkey -f flush ah; flush esp; spdflush; #AH add 10.0.0.11 10.0.0.216 ah 15700 -A hmac-sha1 "12345678901234567890"; add 10.0.0.216 10.0.0.11 ah 24500 -A hmac-sha1 "12345678901234567890"; spdadd 10.0.0.216 10.0.0.11 any -P in ipsec ah/transport//require; spdadd 10.0.0.11 10.0.0.216 any -P out ipsec ah/transport//require; |
| ESP/transport | ipsec-transport-on-esp-216 #!/sbin/setkey -f flush ah; flush esp; spdflush; #ESP add 10.0.0.11 10.0.0.216 esp 15701 -E rijndael-cbc "123456789012123456789012"; add 10.0.0.216 10.0.0.11 esp 24501 -E rijndael-cbc "123456789012123456789012"; spdadd 10.0.0.216 10.0.0.11 any -P out ipsec esp/transport//require; spdadd 10.0.0.11 10.0.0.216 any -P in ipsec esp/transport//require; |
ipsec-transport-on-esp-11 #!/sbin/setkey -f flush ah; flush esp; spdflush; #ESP add 10.0.0.11 10.0.0.216 esp 15701 -E rijndael-cbc "123456789012123456789012"; add 10.0.0.216 10.0.0.11 esp 24501 -E rijndael-cbc "123456789012123456789012"; spdadd 10.0.0.216 10.0.0.11 any -P in ipsec esp/transport//require; spdadd 10.0.0.11 10.0.0.216 any -P out ipsec esp/transport//require; |
| AH/ESP/transport | ipsec-transport-on-ah-esp-216 #!/sbin/setkey -f flush ah; flush esp; spdflush; #AH add 10.0.0.11 10.0.0.216 ah 15700 -A hmac-sha1 "12345678901234567890"; add 10.0.0.216 10.0.0.11 ah 24500 -A hmac-sha1 "12345678901234567890"; #ESP add 10.0.0.11 10.0.0.216 esp 15701 -E rijndael-cbc "123456789012123456789012"; add 10.0.0.216 10.0.0.11 esp 24501 -E rijndael-cbc "123456789012123456789012"; spdadd 10.0.0.216 10.0.0.11 any -P out ipsec esp/transport//require ah/transport//require; spdadd 10.0.0.11 10.0.0.216 any -P in ipsec esp/transport//require ah/transport//require; |
ipsec-transport-on-ah-esp-11 #!/sbin/setkey -f flush ah; flush esp; spdflush; #AH add 10.0.0.11 10.0.0.216 ah 15700 -A hmac-sha1 "12345678901234567890"; add 10.0.0.216 10.0.0.11 ah 24500 -A hmac-sha1 "12345678901234567890"; #ESP add 10.0.0.11 10.0.0.216 esp 15701 -E rijndael-cbc "123456789012123456789012"; add 10.0.0.216 10.0.0.11 esp 24501 -E rijndael-cbc "123456789012123456789012"; spdadd 10.0.0.216 10.0.0.11 any -P in ipsec esp/transport//require ah/transport//require; spdadd 10.0.0.11 10.0.0.216 any -P out ipsec esp/transport//require ah/transport//require; |
| ESP/tunnel | ipsec-tunnel-on-esp-216 #!/sbin/setkey -f flush ah; flush esp; spdflush; #ESP add 10.0.0.11 10.0.0.216 esp 15701 -m tunnel -E rijndael-cbc "123456789012123456789012"; add 10.0.0.216 10.0.0.11 esp 24501 -m tunnel -E rijndael-cbc "123456789012123456789012"; spdadd 10.0.0.216 0.0.0.0/0 any -P out ipsec esp/tunnel/10.0.0.216-10.0.0.11/require; spdadd 0.0.0.0/0 10.0.0.216 any -P in ipsec esp/tunnel/10.0.0.11-10.0.0.216/require; |
ipsec-tunnel-on-esp-11 #!/sbin/setkey -f flush ah; flush esp; spdflush; #ESP add 10.0.0.11 10.0.0.216 esp 15701 -m tunnel -E rijndael-cbc "123456789012123456789012"; add 10.0.0.216 10.0.0.11 esp 24501 -m tunnel -E rijndael-cbc "123456789012123456789012"; spdadd 10.0.0.216 0.0.0.0/0 any -P in ipsec esp/tunnel/10.0.0.216-10.0.0.11/require; spdadd 0.0.0.0/0 10.0.0.216 any -P out ipsec esp/tunnel/10.0.0.11-10.0.0.216/require; |
| ESP+Auth/tunnel | ipsec-tunnel-on-esp-auth-216 #!/sbin/setkey -f flush ah; flush esp; spdflush; #ESP+AUTH add 10.0.0.11 10.0.0.216 esp 15701 -m tunnel -E rijndael-cbc "123456789012123456789012" -A hmac-sha1 "12345678901234567890"; add 10.0.0.216 10.0.0.11 esp 24501 -m tunnel -E rijndael-cbc "123456789012123456789012" -A hmac-sha1 "12345678901234567890"; spdadd 10.0.0.216 0.0.0.0/0 any -P out ipsec esp/tunnel/10.0.0.216-10.0.0.11/require; spdadd 0.0.0.0/0 10.0.0.216 any -P in ipsec esp/tunnel/10.0.0.11-10.0.0.216/require; |
ipsec-tunnel-on-esp-auth-11 #!/sbin/setkey -f flush ah; flush esp; spdflush; #ESP+AUTH add 10.0.0.11 10.0.0.216 esp 15701 -m tunnel -E rijndael-cbc "123456789012123456789012" -A hmac-sha1 "12345678901234567890"; add 10.0.0.216 10.0.0.11 esp 24501 -m tunnel -E rijndael-cbc "123456789012123456789012" -A hmac-sha1 "12345678901234567890"; spdadd 10.0.0.216 0.0.0.0/0 any -P in ipsec esp/tunnel/10.0.0.216-10.0.0.11/require; spdadd 0.0.0.0/0 10.0.0.216 any -P out ipsec esp/tunnel/10.0.0.11-10.0.0.216/require; |
| AH/ESP/tunnel | ipsec-tunnel-on-ah-esp-216 #!/sbin/setkey -f flush ah; flush esp; spdflush; #AH add 10.0.0.11 10.0.0.216 ah 15700 -m tunnel -A hmac-sha1 "12345678901234567890"; add 10.0.0.216 10.0.0.11 ah 24500 -m tunnel -A hmac-sha1 "12345678901234567890"; #ESP add 10.0.0.11 10.0.0.216 esp 15701 -m tunnel -E rijndael-cbc "123456789012123456789012"; add 10.0.0.216 10.0.0.11 esp 24501 -m tunnel -E rijndael-cbc "123456789012123456789012"; spdadd 10.0.0.216 0.0.0.0/0 any -P out ipsec esp/tunnel/10.0.0.216-10.0.0.11/require ah/tunnel/10.0.0.216-10.0.0.11/require; spdadd 0.0.0.0/0 10.0.0.216 any -P in ipsec esp/tunnel/10.0.0.11-10.0.0.216/require ah/tunnel/10.0.0.11-10.0.0.216/require; |
ipsec-tunnel-on-ah-esp-11 #!/sbin/setkey -f flush ah; flush esp; spdflush; #AH add 10.0.0.11 10.0.0.216 ah 15700 -m tunnel -A hmac-sha1 "12345678901234567890"; add 10.0.0.216 10.0.0.11 ah 24500 -m tunnel -A hmac-sha1 "12345678901234567890"; #ESP add 10.0.0.11 10.0.0.216 esp 15701 -m tunnel -E rijndael-cbc "123456789012123456789012"; add 10.0.0.216 10.0.0.11 esp 24501 -m tunnel -E rijndael-cbc "123456789012123456789012"; spdadd 10.0.0.216 0.0.0.0/0 any -P in ipsec esp/tunnel/10.0.0.216-10.0.0.11/require ah/tunnel/10.0.0.216-10.0.0.11/require; spdadd 0.0.0.0/0 10.0.0.216 any -P out ipsec esp/tunnel/10.0.0.11-10.0.0.216/require ah/tunnel/10.0.0.11-10.0.0.216/require; |
| IMPORTANT: The script
execution must be made in a related manner. The
execution of a script that creates an ESP/tunnel at host1 must be
related with the execution of a script that creates an ESP/tunnel at
host2. |