I have set up racoon and setkey to handle IPsec between VPN nodes. The certificate files do not exist yet, racoon would read them when the connection is used.
In /etc/ipsec-tools.conf
flush; spdflush;
/etc/racoon/racoon.conf
path pre_shared_key "/etc/racoon/psk.txt";
path certificate "/usr/local/lib/ssl";
remote anonymous {
exchange_mode main;
certificate_type x509 "../../../../var/local/lib/vpn/vpn.crt" "../../../../var/local/lib/vpn/vpn.key";
verify_cert off;
my_identifier asn1dn;
lifetime time 10 second;
peers_identifier asn1dn;
proposal {
encryption_algorithm 3des;
hash_algorithm md5;
authentication_method rsasig;
dh_group modp1024;
}
}
sainfo anonymous {
pfs_group modp768;
encryption_algorithm 3des;
authentication_algorithm hmac_md5;
compression_algorithm deflate;
}
Now you have racoon and quagga running in the background, you can peer your nodes.
First, a sample OpenSSL configuration file, saved to /usr/local/etc/vpnssl.cnf
Other object identifiers may be added as well.
#
# OpenSSL example configuration file.
# This is mostly being used for generation of certificate requests.
#
# This definition stops the following lines choking if HOME isn't
# defined.
HOME = .
RANDFILE = $ENV::HOME/.rnd
# Extra OBJECT IDENTIFIER info:
oid_file = $ENV::HOME/.oid
oid_section = new_oids
# To use this configuration file with the "-extfile" option of the
# "openssl x509" utility, name here the section containing the
# X.509v3 extensions to use:
# extensions =
# (Alternatively, use a configuration file that has only
# X.509v3 extensions in its main [= default] section.)
[ new_oids ]
# We can add new OIDs in here for use by 'ca' and 'req'.
# Add a simple OID like this:
# testoid1=1.2.3.4
# Or use config file substitution like this:
# testoid2=${testoid1}.5.6
streetAddress=2.5.4.9
postalCode=2.5.4.17
favouriteDrink=0.9.2342.19200300.100.1.5
[ policy_match ]
#countryName = match
#stateOrProvinceName = match
#streetAddress = optional
#postalCode = optional
#organizationName = optional
#organizationalUnitName = optional
commonName = supplied
#emailAddress = optional
# For the 'anything' policy
# At this point in time, you must list all acceptable 'object'
# types.
[ policy_anything ]
countryName = optional
stateOrProvinceName = optional
localityName = optional
streetAddress = optional
postalCode = optional
organizationName = optional
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
[ req ]
default_bits = 1024
default_keyfile = vpn.key
distinguished_name = req_distinguished_name
attributes = req_attributes
# Use extensions on requests and certificates
utf8 = yes
x509_extensions = v3_crt
req_extensions = v3_req
# only want UTF-8 strings
string_mask = utf8only
# we can have many LDAP style attributes
# http://www.alvestrand.no/objectid/2.5.4.html
[ req_distinguished_name ]
commonName = Common Name (eg, YOUR name)
commonName_max = 64
commonName_default = …
[ req_attributes ]
[ v3_req ]
# Extensions to add to a certificate requests
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
[ v3_crt ]
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid:always,issuer:always
basicConstraints = CA:true
Now, the main event, /usr/local/sbin/vpn
Adjust by identifying the interface with your public IPv6 address on it, so the number is copied to MYPUB.
The addresses of your peers go replace the example 2001:db8:d0be:f00d::1 2001:db8:d0be:f00d::2 2001:db8:d0be:f00d::3 addresses.
#!/bin/bash
MYPUB=$(ifconfig eth0 | grep Scope:Global | cut -f2- -d":"|cut -f1 -d"/")
MYADDR=2001:db8:d0be:f00d::1 2001:db8:d0be:f00d::2 2001:db8:d0be:f00d::3
if test "$1" == "init"
then
CRT=/var/local/lib/vpn/vpn.crt
KEY=/var/local/lib/vpn/vpn.key
openssl req -config /usr/local/etc/vpnssl.cnf -new -utf8 -x509 -newkey rsa:1024 -out $CRT -keyout $KEY -nodes -days 10203 -set_serial 0 -batch
#openssl x509 -text -noout -nameopt utf8,sep_multiline,oid -in $CRT
function c() { echo fd${1:62:3}${1:65:2}${1:68:3}${1:71:2}${1:74:2}::/128; };
MYPREFIX=$(c "$(openssl x509 -in $CRT -noout -sha1 -fingerprint)")
I=0
for N in $MYADDR
do
if test $N != $MYPUB
then
ip -6 tunnel add free$I mode ip6ip6 remote $N local $MYPUB
ip -6 addr add $MYPREFIX dev free$I
ip link set dev free$I up
# want mDNS to work here as well…
ifconfig free$I multicast
I=$((0${I} + 1))
fi
done
# Use IPsec to cipher all incoming and outgoing data…
setkey -c <<<"
spdadd $MYPREFIX fd00::/8 any -P out ipsec esp/transport//require ah/transport//require;
spdadd fd00::/8 $MYPREFIX any -P in ipsec esp/transport//require ah/transport//require;
"
fi
if test "$1" == "away"
then
I=0
for N in $MYADDR
do
if test $N != $MYPUB
then
ip -6 tunnel del free${I}
I=$((0${I} + 1))
fi
done
fi
Run as vpn init to connect, and vpn away to drop connection. Quagga should detect that links have gone up and add routes as needed. When ping6ing across the VPN, racoon should detect it, and they will then have some protection with IPSec.
As SSL files are generated randomly, deriving the IP address from the key fingerprint, which is hash of the public key, gives some degree of decentralised claim over the address selected.
The ospf6 router requires that MTU match on both ends of the vpn links in the mesh, though it can be different on different links.
It is desirable for the mtu to be large so enabling jumbograms on a network can be useful even if that does not have mesh wide coverage.
It is possible to use ping6 to find out what that is.
while true do echo try size $N if ! ping6 -Mdo -c1 -s $N $1 then exit fi N=$(($N+1)) done
It is possible to feed the key material to Wireshark to see inside the resulting encrypted IPsec
#!/bin/bash
IF=0
sudo /usr/sbin/setkey -D | while read
do
if test "${REPLY:0:1}" != " "
then
IF=$((${IF} + 1))
IN=0
read SRC DST <<<"${REPLY}"
fi
if test "${IN}" = 1
then
read MODE TUNNEL SPI REQ ETC <<<"${REPLY}"
fi
if test "${IN}" = 2
then
read CRYPT EALGO EKEY <<<"${REPLY}"
fi
if test "${IN}" = 3
then
read HASH HALGO HKEY <<<"${REPLY}"
if test "$MODE" = "esp" -a "$TUNNEL" = "mode=transport"
then
HHALGO=$'ANY'
EEALGO=$'NULL'
case $EALGO in
des-cbc)
EEALGO=$'DES-CBC [RFC2405]'
;;
3des-cbc)
EEALGO=$'TripleDES-CBC [RFC2451]'
;;
blowfish-cbc)
EEALGO=$'BLOWFISH-CBC [RFC2451]'
;;
cast128-cbc)
EEALGO=$'CAST5-CBC [RFC2144]'
;;
twofish-cbc)
EEALGO=$'TWOFISH-CBC'
;;
aes-ctr)
EEALGO=$'AES-CTR [RFC3686]'
;;
esac
case $HALGO in
hmac-md5)
HHALGO=$'HMAC-MD5-96 [RFC2403]'
;;
hmac-sha1)
HHALGO=$'HMAC-SHA1-96 [RFC2404]'
;;
hmac-sha256)
HHALGO=$'HMAC-SHA256'
;;
hmac-ripemd160)
HHALGO=$'HMAC-RIPEMD'
;;
esac
EEKEY=$'0x'"${EKEY:0:8}""${EKEY:9:8}""${EKEY:18:8}""${EKEY:27:8}""${EKEY:36:8}""${EKEY:45:8}"
HHKEY=$'0x'"${HKEY:0:8}""${HKEY:9:8}""${HKEY:18:8}""${HKEY:27:8}"
sed -i $'
s/^esp.sa_'"${IF}"$': .*$/esp.sa_'"${IF}"$': IPv6|'"${SRC}"$'|'${DST}$'|*/
s/^esp.encryption_key_'"${IF}"$': .*$/esp.encryption_key_'"${IF}"$': '"${EEKEY}"$'/
s/^esp.encryption_algorithm_'"${IF}"$': .*$/esp.encryption_algorithm_'"${IF}"$': '"${EEALGO}"$'/
s/^esp.authentication_key_'"${IF}"$': .*$/esp.authentication_key_'"${IF}"$': '"${HHKEY}"$'/
s/^esp.authentication_algorithm_'"${IF}"$': .*$/esp.authentication_algorithm_'"${IF}"$': '"${HHALGO}"$'/
' ~/.wireshark/preferences
fi
fi
IN=$((${IN} + 1))
done