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