diff options
author | Daniil Baturin <daniil@baturin.org> | 2018-06-24 13:06:04 +0200 |
---|---|---|
committer | Daniil Baturin <daniil@baturin.org> | 2018-06-24 13:06:04 +0200 |
commit | 1e57b56f271d55bee4e1118f4f4f9aad27b813ce (patch) | |
tree | 52644fe91c46af6dbad1edf2664e2f359ed6c992 | |
parent | a2574ad42f708aa662bc9fc7bbbf0badf8349bd1 (diff) | |
parent | 90daa5e2cf02ffd3fd5936b4f372f1e85ab62ef6 (diff) | |
download | vyatta-cfg-vpn-1e57b56f271d55bee4e1118f4f4f9aad27b813ce.tar.gz vyatta-cfg-vpn-1e57b56f271d55bee4e1118f4f4f9aad27b813ce.zip |
Merge branch 'current' into lithiumlithium
Conflicts:
scripts/vpn-config.pl
25 files changed, 919 insertions, 873 deletions
diff --git a/Makefile.am b/Makefile.am index 7ae1717..ff81363 100644 --- a/Makefile.am +++ b/Makefile.am @@ -31,9 +31,9 @@ install-exec-hook: cd templates; $(cpiop) $(DESTDIR)$(cfgdir) mkdir -p $(DESTDIR)/etc/ppp/ip-up.d mkdir -p $(DESTDIR)/etc/ppp/ip-down.d - mkdir -p $(DESTDIR)/etc/dhcp3/dhclient-exit-hooks.d/ + mkdir -p $(DESTDIR)/etc/dhcp/dhclient-exit-hooks.d/ mkdir -p $(DESTDIR)/usr/lib/ipsec/ cp scripts/vpn-ppp-up $(DESTDIR)/etc/ppp/ip-up.d/ cp scripts/vpn-ppp-down $(DESTDIR)/etc/ppp/ip-down.d/ - cp scripts/ipsecd-dhclient-hook $(DESTDIR)/etc/dhcp3/dhclient-exit-hooks.d/ipsecd + cp scripts/ipsecd-dhclient-hook $(DESTDIR)/etc/dhcp/dhclient-exit-hooks.d/ipsecd cp scripts/vti-up-down $(DESTDIR)/usr/lib/ipsec/ diff --git a/debian/changelog b/debian/changelog index 113c0a4..ff0149b 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,25 @@ +vyatta-cfg-vpn (0.12.105+vyos2+current3) unstable; urgency=medium + + * Merge StrongSWAN 5.x compatibility changes from Jeff Leung + + -- <daniil@baturin.org> Thu, 11 Feb 2016 12:31:57 -0500 + +vyatta-cfg-vpn (0.12.105+vyos2+current2) unstable; urgency=low + + * Remove dependency on vyatta-ipsec for migration to upstream + strongswan. + + -- Daniil Baturin <daniil@baturin.org> Mon, 25 Jan 2016 14:15:24 +0100 + +vyatta-cfg-vpn (0.12.105+vyos2+current1) unstable; urgency=medium + + [ Thomas Jepp ] + * Fix build depends. + + [ Kim Hagen ] + + -- Kim Hagen <kim.sidney@gmail.com> Sun, 24 Jan 2016 15:04:53 -0500 + vyatta-cfg-vpn (0.12.105+vyos2+lithium17) unstable; urgency=low [ Alex Harpin ] diff --git a/debian/control b/debian/control index cdc5e36..d0dc7bc 100644 --- a/debian/control +++ b/debian/control @@ -2,15 +2,17 @@ Source: vyatta-cfg-vpn Section: contrib/net Priority: extra Maintainer: VyOS Package Maintainers <maintainers@vyos.net> -Build-Depends: debhelper (>= 5), autotools-dev, libnfnetlink-dev -Standards-Version: 3.7.2 +Build-Depends: debhelper (>= 5), autotools-dev, libnfnetlink-dev, autoconf, automake, cpio +Standards-Version: 3.9.1 Package: vyatta-cfg-vpn Architecture: any Depends: perl, vyatta-cfg (>= 0.15.33), vyatta-bash | bash (>= 3.1), - vyatta-ipsec, + strongswan (>= 5.2), + strongswan-swanctl (>= 5.2), + libcrypt-openssl-rsa-perl, libc6 (>= 2.7-6) -Description: VyOS VPN configuration templates/scripts - VyOS VPN configuration templates and scripts. +Description: VyOS IPsec VPN configuration templates/scripts + VyOS IPsec VPN configuration templates and scripts. diff --git a/etc/logrotate.d/vyatta-ipsec-logs b/etc/logrotate.d/vyatta-ipsec-logs index fe3c83d..bc4caa5 100644 --- a/etc/logrotate.d/vyatta-ipsec-logs +++ b/etc/logrotate.d/vyatta-ipsec-logs @@ -1,5 +1,6 @@ /var/log/vyatta/ipsec.log { + missingok nocompress size 1M rotate 2 diff --git a/lib/Vyatta/VPN/Util.pm b/lib/Vyatta/VPN/Util.pm index f7dc320..315651e 100755 --- a/lib/Vyatta/VPN/Util.pm +++ b/lib/Vyatta/VPN/Util.pm @@ -27,17 +27,21 @@ use strict; use warnings; our @EXPORT = qw(rsa_get_local_key_file LOCAL_KEY_FILE_DEFAULT rsa_get_local_pubkey - is_vpn_running vpn_debug enableICMP is_tcp_udp get_protocols conv_protocol); + rsa_convert_pubkey_pem is_vpn_running vpn_debug enableICMP is_tcp_udp + get_protocols conv_protocol); use base qw(Exporter); use Vyatta::Config; +use Crypt::OpenSSL::RSA; +use MIME::Base64; +use File::Copy; use POSIX qw(strftime); use constant LOCAL_KEY_FILE_DEFAULT => '/opt/vyatta/etc/config/ipsec.d/rsa-keys/localhost.key'; sub is_vpn_running { - return ( -e '/var/run/pluto.ctl'); + return ( -e '/var/run/charon.pid'); } sub get_protocols { @@ -110,15 +114,57 @@ sub rsa_get_local_pubkey { my @raw_data=<$dat>; close($dat); + # PEM encoded private key + my $rsa = Crypt::OpenSSL::RSA->new_private_key(join("", @raw_data)); + if (defined $rsa) { + my ($n, $e) = $rsa->get_key_parameters(); + my $eb = $e->to_bin(); + return "0s" . encode_base64(pack("C", length($eb)) . $eb . $n->to_bin(), ''); + } + + # legacy private key format foreach my $line (@raw_data) { my $file_pubkey; if (($file_pubkey) = ($line =~ m/\s+\#pubkey=(\S+)/)) { + # Found a legacy private key; convert to PEM for strongSwan 5.2.x + my $key = join("", @raw_data); + $key =~ /^\s+Modulus:\s+0x([0-9a-fA-F]+)$/m; + my $n = Crypt::OpenSSL::Bignum->new_from_hex($1); + $key =~ /^\s+PublicExponent:\s+0x([0-9a-fA-F]+)$/m; + my $e = Crypt::OpenSSL::Bignum->new_from_hex($1); + $key =~ /^\s+PrivateExponent:\s+0x([0-9a-fA-F]+)$/m; + my $d = Crypt::OpenSSL::Bignum->new_from_hex($1); + $key =~ /^\s+Prime1:\s+0x([0-9a-fA-F]+)$/m; + my $p = Crypt::OpenSSL::Bignum->new_from_hex($1); + $key =~ /^\s+Prime2:\s+0x([0-9a-fA-F]+)$/m; + my $q = Crypt::OpenSSL::Bignum->new_from_hex($1); + + my $rsa = Crypt::OpenSSL::RSA->new_key_from_parameters($n, $e, $d, $p, $q); + if (defined $rsa) { + # write out PEM formatted key + move("$file", "$file.bak"); + open(my $priv, '>', "$file") + or return 0; + chmod 0600, $file; + print {$priv} $rsa->get_private_key_string(); + close($priv); + } return $file_pubkey; } } return 0; } +sub rsa_convert_pubkey_pem { + my $key = shift; + my $decoded = decode_base64(substr($key, 2)); + my $len = unpack("C", substr($decoded, 0, 1)); + my $e = Crypt::OpenSSL::Bignum->new_from_bin(substr($decoded, 1, $len)); + my $n = Crypt::OpenSSL::Bignum->new_from_bin(substr($decoded, 1 + $len)); + my $rsa = Crypt::OpenSSL::RSA->new_key_from_parameters($n, $e); + return $rsa->get_public_key_x509_string(); +} + sub vpn_debug { my $timestamp = strftime("%Y%m%d-%H:%M.%S", localtime); diff --git a/lib/Vyatta/VPN/vtiIntf.pm b/lib/Vyatta/VPN/vtiIntf.pm index daec058..4e52fff 100755 --- a/lib/Vyatta/VPN/vtiIntf.pm +++ b/lib/Vyatta/VPN/vtiIntf.pm @@ -70,7 +70,7 @@ sub parseVtiTun { if ($tunop =~ m/local ([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)/) { $local = $1; } - if ($tunop =~ m/okey ([0-9\.]+)/) { + if ($tunop =~ m/key ([0-9\.]+)/) { $mark = $1; } return($remote, $local, $tunName, $mark); diff --git a/scripts/dmvpn-config.pl b/scripts/dmvpn-config.pl index 8a8c1ff..6fa180d 100755 --- a/scripts/dmvpn-config.pl +++ b/scripts/dmvpn-config.pl @@ -21,36 +21,24 @@ use NetAddr::IP; use Vyatta::VPN::vtiIntf; my $config_file; -my $secrets_file; my $init_script; my $tunnel_context; my $tun_id; GetOptions( "config_file=s" => \$config_file, - "secrets_file=s" => \$secrets_file, "init_script=s" => \$init_script, "tunnel_context" => \$tunnel_context, "tun_id=s" => \$tun_id ); -my $CA_CERT_PATH = '/etc/ipsec.d/cacerts'; -my $CRL_PATH = '/etc/ipsec.d/crls'; -my $SERVER_CERT_PATH = '/etc/ipsec.d/certs'; -my $SERVER_KEY_PATH = '/etc/ipsec.d/private'; + my $LOGFILE = '/var/log/vyatta/ipsec.log'; my $vpn_cfg_err = "VPN configuration error:"; -my $clustering_ip = 0; -my $dhcp_if = 0; my $genout; -my $genout_secrets; my $dh_disable; -# Set $using_klips to 1 if kernel IPsec support is provided by KLIPS. -# Set it to 0 if using NETKEY. -my $using_klips = 0; - -$genout .= "# generated by $0\n\n"; -$genout_secrets .= "# generated by $0\n\n"; +$genout .= "# generated by $0\n\n"; +$genout .= "connections {\n"; # # Prepare Vyatta::Config object @@ -64,528 +52,475 @@ $vcVPN->setLevel('vpn'); # if it has not then exit my $ipsecstatus = $vcVPN->isChanged('ipsec'); if ( $ipsecstatus && $tunnel_context ) { - - # no sence to do same update twice, will be done via vpn context - exit 0; + # no sence to do same update twice, will be done via vpn context + exit 0; } if ( !$ipsecstatus ) { - my $tun_ip_changed = 0; - my @tuns = $vc->listNodes('interfaces tunnel'); - my @profs = $vcVPN->listNodes('ipsec profile'); - foreach my $prof (@profs) { - my @tuns = $vcVPN->listNodes("ipsec profile $prof bind tunnel"); - foreach my $tun (@tuns) { - my $lip_old = - $vc->returnOrigValue("interfaces tunnel $tun local-ip"); - my $lip_new = $vc->returnValue("interfaces tunnel $tun local-ip"); - if ( !( "$lip_old" eq "$lip_new" ) ) { - if ($tun_ip_changed) { - - # tunnel $tun_id is not the last tunnel with updated local-ip, so skip + my $tun_ip_changed = 0; + my @tuns = $vc->listNodes('interfaces tunnel'); + my @profs = $vcVPN->listNodes('ipsec profile'); + foreach my $prof (@profs) { + my @tuns = $vcVPN->listNodes("ipsec profile $prof bind tunnel"); + foreach my $tun (@tuns) { + my $lip_old = $vc->returnOrigValue("interfaces tunnel $tun local-ip"); + my $lip_new = $vc->returnValue("interfaces tunnel $tun local-ip"); + if ( !( "$lip_old" eq "$lip_new" ) ) { + if ($tun_ip_changed) { + # tunnel $tun_id is not the last tunnel with updated local-ip, so skip exit 0; - } - if ( "$tun" eq "$tun_id" ) { - $tun_ip_changed = 1; - } - } - } - } - if ( !$tun_ip_changed ) { - exit 0; - } + } + if ( "$tun" eq "$tun_id" ) { + $tun_ip_changed = 1; + } + } + } + } + if ( !$tun_ip_changed ) { + exit 0; + } } if ( $vcVPN->exists('ipsec') ) { - - # - # Connection configurations - # - my @profiles = $vcVPN->listNodes('ipsec profile'); - my $prev_profile = ""; - foreach my $profile (@profiles) { - my $profile_ike_group = - $vcVPN->returnValue("ipsec profile $profile ike-group"); - if ( !defined($profile_ike_group) || $profile_ike_group eq '' ) { - vpn_die( - [ "vpn", "ipsec", "profile", $profile, "ike-group" ], -"$vpn_cfg_err No IKE group specified for profile \"$profile\".\n" - ); - } - elsif ( !$vcVPN->exists("ipsec ike-group $profile_ike_group") ) { - vpn_die( - [ "vpn", "ipsec", "profile", $profile, "ike-group" ], -"$vpn_cfg_err The IKE group \"$profile_ike_group\" specified for profile " - . "\"$profile\" has not been configured.\n" - ); - } - - my $authid = - $vcVPN->returnValue("ipsec profile $profile authentication id"); - - # - # ESP group - # - my $profile_esp_group = - $vcVPN->returnValue("ipsec profile $profile esp-group"); - if ( !defined($profile_esp_group) || $profile_esp_group eq '' ) { - vpn_die( - [ "vpn", "ipsec", "profile", $profile, "esp-group" ], -"$vpn_cfg_err No ESP group specified for profile \"$profile\".\n" - ); - } - elsif ( !$vcVPN->exists("ipsec esp-group $profile_esp_group") ) { - vpn_die( - [ "vpn", "ipsec", "profile", $profile, "esp-group" ], - "$vpn_cfg_err The ESP group \"$profile_esp_group\" specified " - . "for profile \"$profile\" has not been configured.\n" - ); - } - - # - # Authentication mode - # - # - # Write shared secrets to ipsec.secrets - # - my $auth_mode = - $vcVPN->returnValue("ipsec profile $profile authentication mode"); - my $psk = ''; - if ( !defined($auth_mode) || $auth_mode eq '' ) { - vpn_die( - [ "vpn", "ipsec", "profile", $profile, "authentication" ], -"$vpn_cfg_err No authentication mode for profile \"$profile\" specified.\n" - ); - } - elsif ( defined($auth_mode) && ( $auth_mode eq 'pre-shared-secret' ) ) { - $psk = $vcVPN->returnValue( - "ipsec profile $profile authentication pre-shared-secret"); - my $orig_psk = $vcVPN->returnOrigValue( - "ipsec profile $profile authentication pre-shared-secret"); - $orig_psk = "" if ( !defined($orig_psk) ); - if ( $psk ne $orig_psk && $orig_psk ne "" ) { - print -"WARNING: The pre-shared-secret will not be updated until the next re-keying interval\n"; - print "To force the key change use: 'reset vpn ipsec-peer'\n"; - } - if ( !defined($psk) || $psk eq '' ) { - vpn_die( - [ "vpn", "ipsec", "profile", $profile, "authentication" ], -"$vpn_cfg_err No 'pre-shared-secret' specified for profile \"$profile\"" - . " while 'pre-shared-secret' authentication mode is specified.\n" - ); - } - } - else { - vpn_die( - [ "vpn", "ipsec", "profile", $profile, "authentication" ], -"$vpn_cfg_err Unknown/unsupported authentication mode \"$auth_mode\" for profile " - . "\"$profile\" specified.\n" - ); - } - - my @tunnels = $vcVPN->listNodes("ipsec profile $profile bind tunnel"); - - foreach my $tunnel (@tunnels) { - - # - # Check whether this tunnel is already in some profile - # - foreach my $prof (@profiles) { - if ( $prof != $profile ) { - if ( - $vcVPN->exists( - "ipsec profile $prof bind tunnel $tunnel") - ) + # + # Connection configurations + # + my @profiles = $vcVPN->listNodes('ipsec profile'); + my $prev_profile = ""; + foreach my $profile (@profiles) { + my $profile_ike_group = $vcVPN->returnValue("ipsec profile $profile ike-group"); + if ( !defined($profile_ike_group) || $profile_ike_group eq '' ) { + vpn_die([ "vpn", "ipsec", "profile", $profile, "ike-group" ], + "$vpn_cfg_err No IKE group specified for profile \"$profile\".\n"); + } + elsif ( !$vcVPN->exists("ipsec ike-group $profile_ike_group") ) { + vpn_die([ "vpn", "ipsec", "profile", $profile, "ike-group" ], + "$vpn_cfg_err The IKE group \"$profile_ike_group\" specified for profile " + . "\"$profile\" has not been configured.\n"); + } + + # + # ESP group + # + my $profile_esp_group = $vcVPN->returnValue("ipsec profile $profile esp-group"); + if ( !defined($profile_esp_group) || $profile_esp_group eq '' ) { + vpn_die([ "vpn", "ipsec", "profile", $profile, "esp-group" ], + "$vpn_cfg_err No ESP group specified for profile \"$profile\".\n"); + } + elsif ( !$vcVPN->exists("ipsec esp-group $profile_esp_group") ) { + vpn_die([ "vpn", "ipsec", "profile", $profile, "esp-group" ], + "$vpn_cfg_err The ESP group \"$profile_esp_group\" specified " + . "for profile \"$profile\" has not been configured.\n"); + } + + # + # Authentication mode + # + # + # Write shared secrets to ipsec.secrets + # + my $auth_mode = $vcVPN->returnValue("ipsec profile $profile authentication mode"); + my $psk = ''; + if ( !defined($auth_mode) || $auth_mode eq '' ) { + vpn_die( + [ "vpn", "ipsec", "profile", $profile, "authentication" ], + "$vpn_cfg_err No authentication mode for profile \"$profile\" specified.\n" + ); + } + elsif ( defined($auth_mode) && ( $auth_mode eq 'pre-shared-secret' ) ) { + $psk = $vcVPN->returnValue("ipsec profile $profile authentication pre-shared-secret"); + my $orig_psk = $vcVPN->returnOrigValue("ipsec profile $profile authentication pre-shared-secret"); + $orig_psk = "" if ( !defined($orig_psk) ); + if ( $psk ne $orig_psk && $orig_psk ne "" ) { + print "WARNING: The pre-shared-secret will not be updated until the next re-keying interval\n"; + print "To force the key change use: 'reset vpn ipsec-peer'\n"; + } + if ( !defined($psk) || $psk eq '' ) { + vpn_die( + [ "vpn", "ipsec", "profile", $profile, "authentication" ], + "$vpn_cfg_err No 'pre-shared-secret' specified for profile \"$profile\"" + . " while 'pre-shared-secret' authentication mode is specified.\n" + ); + } + } + else { + vpn_die( + [ "vpn", "ipsec", "profile", $profile, "authentication" ], + "$vpn_cfg_err Unknown/unsupported authentication mode \"$auth_mode\" for profile " + . "\"$profile\" specified.\n" + ); + } + + my @tunnels = $vcVPN->listNodes("ipsec profile $profile bind tunnel"); + foreach my $tunnel (@tunnels) { + # + # Check whether this tunnel is already in some profile + # + foreach my $prof (@profiles) { + if ( $prof != $profile ) { + if ( $vcVPN->exists("ipsec profile $prof bind tunnel $tunnel") ) { - vpn_die( - [ - "vpn", "ipsec", "profile", $profile, - "bind", "tunnel", $tunnel - ], -"$vpn_cfg_err Tunnel \"$tunnel\" is already configured in profile \"$prof\"." - ); - } - } - } - - my $needs_passthrough = 'false'; - my $tunKeyword = 'tunnel ' . "$tunnel"; - - my $conn_head = "conn vpnprof-tunnel-$tunnel\n"; - $genout .= $conn_head; - - my $lip = $vc->returnValue("interfaces tunnel $tunnel local-ip"); - my $leftsourceip = undef; - - $genout .= "\tleft=$lip\n"; - $leftsourceip = "\tleftsourceip=$lip\n"; - $genout .= "\tleftid=$authid\n" if defined $authid; - - my $right = '%any'; - my $any_peer = 1; - - $genout .= "\tright=$right\n"; - if ($any_peer) { - $genout .= "\trekey=no\n"; - } - - # - # Protocol/port - # - my $protocol = "gre"; - my $lprotoport = ''; - if ( defined($protocol) ) { - $lprotoport .= $protocol; - } - if ( not( $lprotoport eq '' ) ) { - $genout .= "\tleftprotoport=$lprotoport\n"; - } - - my $rprotoport = ''; - if ( defined($protocol) ) { - $rprotoport .= $protocol; - } - if ( not( $rprotoport eq '' ) ) { - $genout .= "\trightprotoport=$rprotoport\n"; - } - - # - # Write IKE configuration from group - # - my $ikelifetime = IKELIFETIME_DEFAULT; - $genout .= "\tike="; - my $ike_group = - $vcVPN->returnValue("ipsec profile $profile ike-group"); - if ( defined($ike_group) && $ike_group ne '' ) { - my @ike_proposals = - $vcVPN->listNodes("ipsec ike-group $ike_group proposal"); - - my $first_ike_proposal = 1; - foreach my $ike_proposal (@ike_proposals) { - - # - # Get encryption, hash & Diffie-Hellman key size - # - my $encryption = $vcVPN->returnValue( -"ipsec ike-group $ike_group proposal $ike_proposal encryption" - ); - my $hash = $vcVPN->returnValue( - "ipsec ike-group $ike_group proposal $ike_proposal hash" - ); - my $dh_group = $vcVPN->returnValue( -"ipsec ike-group $ike_group proposal $ike_proposal dh-group" - ); - - if ( defined($dh_group) ) { - $dh_disable = 1; - } - - # - # Write separator if not first proposal - # - if ($first_ike_proposal) { - $first_ike_proposal = 0; - } - else { - $genout .= ","; - } - - # - # Write values - # - if ( defined($encryption) && defined($hash) ) { - $genout .= "$encryption-$hash"; - if ( defined($dh_group) ) { - if ($dh_group eq '2') { - $genout .= '-modp1024'; - } elsif ($dh_group eq '5') { - $genout .= '-modp1536'; - } elsif ($dh_group eq '14') { - $genout .= '-modp2048'; - } elsif ($dh_group eq '15') { - $genout .= '-modp3072'; - } elsif ($dh_group eq '16') { - $genout .= '-modp4096'; - } elsif ($dh_group eq '17') { - $genout .= '-modp6144'; - } elsif ($dh_group eq '18') { - $genout .= '-modp8192'; - } elsif ($dh_group eq '19') { - $genout .= '-ecp256'; - } elsif ($dh_group eq '20') { - $genout .= '-ecp384'; - } elsif ($dh_group eq '21') { - $genout .= '-ecp521'; - } elsif ($dh_group eq '22') { - $genout .= '-modp1024s160'; - } elsif ($dh_group eq '23') { - $genout .= '-modp2048s224'; - } elsif ($dh_group eq '24') { - $genout .= '-modp2048s256'; - } elsif ($dh_group eq '25') { - $genout .= '-ecp192'; - } elsif ($dh_group eq '26') { - $genout .= '-ecp224'; - } - elsif ( $dh_group ne '' ) { - vpn_die(["vpn","ipsec","profile", $profile,"bind","tunnel", $tunnel],"$vpn_cfg_err Invalid 'dh-group' $dh_group specified in ". - "profile \"$profile\" for $tunKeyword. Only 2, 5, or 14 through 26 accepted.\n"); - } - } - } - } - - #why we always set strict mode? - $genout .= "!\n"; - - my $t_ikelifetime = - $vcVPN->returnValue("ipsec ike-group $ike_group lifetime"); - if ( defined($t_ikelifetime) && $t_ikelifetime ne '' ) { - $ikelifetime = $t_ikelifetime; - } - $genout .= "\tikelifetime=$ikelifetime" . "s\n"; - - # - # Check for Dead Peer Detection DPD - # - my $dpd_interval = $vcVPN->returnValue( - "ipsec ike-group $ike_group dead-peer-detection interval"); - my $dpd_timeout = $vcVPN->returnValue( - "ipsec ike-group $ike_group dead-peer-detection timeout"); - my $dpd_action = $vcVPN->returnValue( - "ipsec ike-group $ike_group dead-peer-detection action"); - if ( defined($dpd_interval) - && defined($dpd_timeout) - && defined($dpd_action) ) - { - $genout .= "\tdpddelay=$dpd_interval" . "s\n"; - $genout .= "\tdpdtimeout=$dpd_timeout" . "s\n"; - $genout .= "\tdpdaction=$dpd_action\n"; - } - } - - # - # Write ESP configuration from group - # - my $esplifetime = ESPLIFETIME_DEFAULT; - $genout .= "\tesp="; - my $esp_group = - $vcVPN->returnValue("ipsec profile $profile esp-group"); - if ( defined($esp_group) && $esp_group ne '' ) { - my @esp_proposals = - $vcVPN->listNodes("ipsec esp-group $esp_group proposal"); - my $first_esp_proposal = 1; - foreach my $esp_proposal (@esp_proposals) { - - # - # Get encryption, hash - # - my $encryption = $vcVPN->returnValue( -"ipsec esp-group $esp_group proposal $esp_proposal encryption" - ); - my $hash = $vcVPN->returnValue( - "ipsec esp-group $esp_group proposal $esp_proposal hash" - ); - - # - # Write separator if not first proposal - # - if ($first_esp_proposal) { - $first_esp_proposal = 0; - } - else { - $genout .= ","; - } - - # - # Write values - # - if ( defined($encryption) && defined($hash) ) { - $genout .= "$encryption-$hash"; - } - } - $genout .= "!\n"; - - my $t_esplifetime = - $vcVPN->returnValue("ipsec esp-group $esp_group lifetime"); - if ( defined($t_esplifetime) && $t_esplifetime ne '' ) { - $esplifetime = $t_esplifetime; - } - $genout .= "\tkeylife=$esplifetime" . "s\n"; - - my $lower_lifetime = $ikelifetime; - if ( $esplifetime < $ikelifetime ) { - $lower_lifetime = $esplifetime; - } - - # - # The lifetime values need to be greater than: - # rekeymargin*(100+rekeyfuzz)/100 - # - my $rekeymargin = REKEYMARGIN_DEFAULT; - if ( $lower_lifetime <= ( 2 * $rekeymargin ) ) { - $rekeymargin = int( $lower_lifetime / 2 ) - 1; - } - $genout .= "\trekeymargin=$rekeymargin" . "s\n"; - - # - # Mode (tunnel or transport) - # - my $espmode = - $vcVPN->returnValue("ipsec esp-group $esp_group mode"); - if ( !defined($espmode) || $espmode eq '' ) { - $espmode = "tunnel"; - } - $genout .= "\ttype=$espmode\n"; - - # - # Perfect Forward Secrecy - # - my $pfs = $vcVPN->returnValue("ipsec esp-group $esp_group pfs"); - if (defined($pfs)) { - if ( $pfs eq 'enable' && defined($dh_disable) ) { - $genout .= "\tpfs=yes\n"; - } elsif ($pfs eq 'dh-group2') { - $genout .= "\tpfs=yes\n"; - $genout .= "\tpfsgroup=modp1024\n"; - } elsif ($pfs eq 'dh-group5') { - $genout .= "\tpfs=yes\n"; - $genout .= "\tpfsgroup=modp1536\n"; - } elsif ($pfs eq 'dh-group14') { - $genout .= "\tpfs=yes\n"; - $genout .= "\tpfsgroup=modp2048\n"; - } elsif ($pfs eq 'dh-group15') { - $genout .= "\tpfs=yes\n"; - $genout .= "\tpfsgroup=modp3072\n"; - } elsif ($pfs eq 'dh-group16') { - $genout .= "\tpfs=yes\n"; - $genout .= "\tpfsgroup=modp4096\n"; - } elsif ($pfs eq 'dh-group17') { - $genout .= "\tpfs=yes\n"; - $genout .= "\tpfsgroup=modp6144\n"; - } elsif ($pfs eq 'dh-group18') { - $genout .= "\tpfs=yes\n"; - $genout .= "\tpfsgroup=modp8192\n"; - } elsif ($pfs eq 'dh-group19') { - $genout .= "\tpfs=yes\n"; - $genout .= "\tpfsgroup=ecp256\n"; - } elsif ($pfs eq 'dh-group20') { - $genout .= "\tpfs=yes\n"; - $genout .= "\tpfsgroup=ecp384\n"; - } elsif ($pfs eq 'dh-group21') { - $genout .= "\tpfs=yes\n"; - $genout .= "\tpfsgroup=ecp521\n"; - } elsif ($pfs eq 'dh-group22') { - $genout .= "\tpfs=yes\n"; - $genout .= "\tpfsgroup=modp1024s160\n"; - } elsif ($pfs eq 'dh-group23') { - $genout .= "\tpfs=yes\n"; - $genout .= "\tpfsgroup=modp2048s224\n"; - } elsif ($pfs eq 'dh-group24') { - $genout .= "\tpfs=yes\n"; - $genout .= "\tpfsgroup=modp2048s256\n"; - } elsif ($pfs eq 'dh-group25') { - $genout .= "\tpfs=yes\n"; - $genout .= "\tpfsgroup=ecp192\n"; - } elsif ($pfs eq 'dh-group26') { - $genout .= "\tpfs=yes\n"; - $genout .= "\tpfsgroup=ecp224\n"; - } else { - $genout .= "\tpfs=no\n"; - } - } - - # - # Compression - # - my $compression = - $vcVPN->returnValue("ipsec esp-group $esp_group compression"); - if ( defined($compression) ) { - if ( $compression eq 'enable' ) { - $genout .= "\tcompress=yes\n"; - } - else { - $genout .= "\tcompress=no\n"; - } - } - } - - # - # Authentication - # - $right = '%any'; - if ( not( $prev_profile eq $profile ) ) { - $genout_secrets .= "\n$lip $right "; - if ( defined($authid) ) { - $genout_secrets .= "$authid "; - } - $genout_secrets .= ": PSK \"$psk\" "; - } - $prev_profile = $profile; - if ( defined($auth_mode) && ( $auth_mode eq 'pre-shared-secret' ) ) - { - $genout .= "\tauthby=secret\n"; - } - - # - # Start automatically - # - if ($any_peer) { - $genout .= "\tauto=add\n"; - $genout .= "\tkeyingtries=%forever\n"; - } - else { - $genout .= "\tauto=start\n"; - } - $genout .= "#$conn_head"; # to identify end of connection definition - # used by clear vpn op-mode command - } - } - + vpn_die(["vpn", "ipsec", "profile", $profile,"bind", "tunnel", $tunnel], + "$vpn_cfg_err Tunnel \"$tunnel\" is already configured in profile \"$prof\"."); + } + } + } + + my $needs_passthrough = 'false'; + my $tunKeyword = 'tunnel ' . "$tunnel"; + + my $conn_head = "\tvpnprof-dmvpn-$tunnel {\n"; + $genout .= $conn_head; + + my $lip = $vc->returnValue("interfaces tunnel $tunnel local-ip"); + my $leftsourceip = undef; + + # + # Write IKE configuration from group + # + my $ikelifetime = IKELIFETIME_DEFAULT; + $genout .= "\t\tproposals = "; + my $ike_group = $vcVPN->returnValue("ipsec profile $profile ike-group"); + if ( defined($ike_group) && $ike_group ne '' ) { + my @ike_proposals = $vcVPN->listNodes("ipsec ike-group $ike_group proposal"); + my $first_ike_proposal = 1; + foreach my $ike_proposal (@ike_proposals) { + # + # Get encryption, hash & Diffie-Hellman key size + # + my $encryption = $vcVPN->returnValue("ipsec ike-group $ike_group proposal $ike_proposal encryption"); + my $hash = $vcVPN->returnValue("ipsec ike-group $ike_group proposal $ike_proposal hash"); + my $dh_group = $vcVPN->returnValue("ipsec ike-group $ike_group proposal $ike_proposal dh-group"); + + if ( defined($dh_group) ) { + $dh_disable = 1; + } + + # + # Write separator if not first proposal + # + if ($first_ike_proposal) { + if ( !defined($dh_group) ) { + vpn_die(["vpn","ipsec","profile", $profile,"bind","tunnel", $tunnel],"$vpn_cfg_err 'dh-group' must be specified in ". + "ike-group \"$ike_group\" proposal \"$ike_proposal\" dh-group. \n"); + } + $first_ike_proposal = 0; + } + else { + $genout .= ","; + } + + # + # Write values + # + if ( defined($encryption) && defined($hash) ) { + $genout .= "$encryption-$hash"; + if ( defined($dh_group) ) { + my $cipher_out = get_dh_cipher_result($dh_group); + if ($cipher_out eq 'unknown') { + vpn_die(["vpn","ipsec","profile", $profile,"bind","tunnel", $tunnel],"$vpn_cfg_err Invalid 'dh-group' $dh_group specified in ". + "profile \"$profile\" for $tunKeyword. Only 2, 5, or 14 through 26 accepted.\n"); + } else { + $genout .= "-$cipher_out"; + } + } + } + } + $genout .= "\n"; + + # + # Get IKE version setting + # + my $key_exchange = $vcVPN->returnValue("ipsec ike-group $ike_group key-exchange"); + if ( defined($key_exchange) ) { + if ( $key_exchange eq 'ikev1' ) { + $genout .= "\t\tversion = 1\n"; + } + if ( $key_exchange eq 'ikev2' ) { + $genout .= "\t\tversion = 2\n"; + } + }else { + $genout .= "\t\tversion = 0\n"; + } + + # + # Get ikev2-reauth configuration + # Check IKE Lifetime + # + my $ikev2_group_reauth = $vcVPN->returnValue("ipsec ike-group $ike_group ikev2-reauth"); + my $t_ikelifetime = $vcVPN->returnValue("ipsec ike-group $ike_group lifetime"); + if ( defined($t_ikelifetime) && $t_ikelifetime ne '' ) { + $ikelifetime = $t_ikelifetime; + } + if ( defined($ikev2_group_reauth) ) { + if ( $ikev2_group_reauth eq 'yes' && defined($ikelifetime) ) { + $genout .= "\t\treauth_time = $ikelifetime" . "s\n"; + }else { + $genout .= "\t\trekey_time = $ikelifetime" . "s\n"; + } + } else { + $genout .= "\t\trekey_time = $ikelifetime" . "s\n"; + } + + # + # Allow the user to disable MOBIKE for IKEv2 connections + # + my $mob_ike = $vcVPN->returnValue("ipsec ike-group $ike_group mobike"); + + if (defined($mob_ike)) { + if (defined($key_exchange) && $key_exchange eq 'ikev2') { + if ($mob_ike eq 'enable') { + $genout .= "\t\tmobike = yes"; + } + if ($mob_ike eq 'disable') { + $genout .= "\t\tmobike = no"; + } + }else { + $genout .= "\t\tmobike = no"; + } + } + + # + # Check for Dead Peer Detection DPD + # + my $dpd_interval = $vcVPN->returnValue("ipsec ike-group $ike_group dead-peer-detection interval"); + my $dpd_timeout = $vcVPN->returnValue("ipsec ike-group $ike_group dead-peer-detection timeout"); + my $dpd_action = $vcVPN->returnValue("ipsec ike-group $ike_group dead-peer-detection action"); + if ( defined($dpd_interval) && defined($dpd_timeout) && defined($dpd_action) ) { + $genout .= "\t\tdpd_delay = $dpd_interval" . "s\n"; + $genout .= "\t\tdpd_timeou = $dpd_timeout" . "s\n"; + } + } + + $genout .= "\t\tkeyingtries = 0\n"; + + # + # Authentication + # + $genout .="\t\tlocal {\n"; + if ( defined($auth_mode) && ( $auth_mode eq 'pre-shared-secret' ) ) { + $genout .= "\t\t\tauth = psk\n"; + } + $genout .="\t\t}\n"; + $genout .="\t\tremote {\n"; + if ( defined($auth_mode) && ( $auth_mode eq 'pre-shared-secret' ) ) { + $genout .= "\t\t\tauth = psk\n"; + } + $genout .="\t\t}\n"; + + # + # Write ESP configuration from group + # + $genout .="\t\tchildren {\n"; + $genout .="\t\t\tdmvpn {\n"; + my $esplifetime = ESPLIFETIME_DEFAULT; + $genout .= "\t\t\t\tesp_proposals = "; + my $esp_group = $vcVPN->returnValue("ipsec profile $profile esp-group"); + if ( defined($esp_group) && $esp_group ne '' ) { + my @esp_proposals = $vcVPN->listNodes("ipsec esp-group $esp_group proposal"); + my $first_esp_proposal = 1; + foreach my $esp_proposal (@esp_proposals) { + # + # Get encryption, hash + # + my $encryption = $vcVPN->returnValue("ipsec esp-group $esp_group proposal $esp_proposal encryption"); + my $hash = $vcVPN->returnValue("ipsec esp-group $esp_group proposal $esp_proposal hash"); + my $pfs = $vcVPN->returnValue("ipsec esp-group $esp_group pfs"); + + # + # Write separator if not first proposal + # + if ($first_esp_proposal) { + $first_esp_proposal = 0; + } + else { + $genout .= ","; + } + if (defined($pfs)) { + if ($pfs eq 'enable') { + # Get the first IKE group's dh-group and use that as our PFS setting + my $default_pfs = $vcVPN->returnValue("ipsec ike-group $ike_group proposal 1 dh-group"); + $pfs = get_dh_cipher_result($default_pfs); + if ( !defined($default_pfs) && $pfs eq 'unknown' ) { + vpn_die(["vpn","ipsec","profile", $profile,"bind","tunnel", $tunnel],"$vpn_cfg_err 'pfs enabled' needs 'dh-group' specified in ". + "ike-group \"$ike_group\" proposal 1 dh-group. \n"); + } + } elsif ($pfs eq 'disable') { + undef $pfs; + } else { + $pfs = get_dh_cipher_result($pfs); + } + } + + # + # Write values + # + if ( defined($encryption) && defined($hash) ) { + $genout .= "$encryption-$hash"; + if (defined($pfs)) { + $genout .= "-$pfs"; + } + } + } + $genout .= "\n"; + + my $t_esplifetime = $vcVPN->returnValue("ipsec esp-group $esp_group lifetime"); + if ( defined($t_esplifetime) && $t_esplifetime ne '' ) { + $esplifetime = $t_esplifetime; + } + $genout .= "\t\t\t\trekey_time = $esplifetime" . "s\n"; + + my $lower_lifetime = $ikelifetime; + if ( $esplifetime < $ikelifetime ) { + $lower_lifetime = $esplifetime; + } + + # + # The lifetime values need to be greater than: + # rekeymargin*(100+rekeyfuzz)/100 + # + my $rekeymargin = REKEYMARGIN_DEFAULT; + if ($lower_lifetime <= (2 * $rekeymargin)) { + $rekeymargin = int($lower_lifetime / 2) - 1; + } + $genout .= "\t\t\t\trand_time = $rekeymargin" . "s\n"; + + # + # Protocol/port + # + my $protocol = "gre"; + my $lprotoport = ''; + if ( defined($protocol) ) { + $lprotoport .= $protocol; + } + if ( not( $lprotoport eq '' ) ) { + $genout .= "\t\t\t\tlocal_ts = dynamic[$lprotoport]\n"; + } + + my $rprotoport = ''; + if ( defined($protocol) ) { + $rprotoport .= $protocol; + } + if ( not( $rprotoport eq '' ) ) { + $genout .= "\t\t\t\tremote_ts = dynamic[$rprotoport]\n"; + } + + # + # Mode (tunnel or transport) + # + my $espmode = $vcVPN->returnValue("ipsec esp-group $esp_group mode"); + if ( !defined($espmode) || $espmode eq '' ) { + $espmode = "transport"; + } + $genout .= "\t\t\t\tmode = $espmode\n"; + + # + # Check for Dead Peer Detection DPD + # + my $dpd_interval = $vcVPN->returnValue("ipsec ike-group $ike_group dead-peer-detection interval"); + my $dpd_timeout = $vcVPN->returnValue("ipsec ike-group $ike_group dead-peer-detection timeout"); + my $dpd_action = $vcVPN->returnValue("ipsec ike-group $ike_group dead-peer-detection action"); + if ( defined($dpd_interval) && defined($dpd_timeout) && defined($dpd_action) ) { + + $genout .= "\t\t\t\tdpd_action = $dpd_action\n"; + } + + + # + # Compression + # + my $compression = $vcVPN->returnValue("ipsec esp-group $esp_group compression"); + if ( defined($compression) ) { + if ( $compression eq 'enable' ) { + $genout .= "\t\t\t\tipcomp=yes\n"; + } + } + } + + $genout .= "\t\t\t}\n"; + $genout .= "\t\t}\n"; + $genout .= "\t}\n"; # to identify end of connection definition + # used by clear vpn op-mode command + } + $genout .= "}\n"; + $genout .= "secrets {\n"; + my @tunnels = $vcVPN->listNodes("ipsec profile $profile bind tunnel"); + foreach my $tunnel (@tunnels) { + # + # Check whether this tunnel is already in some profile + # + foreach my $prof (@profiles) { + if ( $prof != $profile ) { + if ($vcVPN->exists("ipsec profile $prof bind tunnel $tunnel")){ + vpn_die(["vpn", "ipsec", "profile", $profile,"bind", "tunnel", $tunnel], + "$vpn_cfg_err Tunnel \"$tunnel\" is already configured in profile \"$prof\"."); + } + } + } + my $ike_id = "\tike-dmvpn-$tunnel {\n"; + $genout .= $ike_id; + $genout .= "\t\tsecret = $psk\n"; + $genout .= "\t}\n"; + } + $genout .= "}\n"; + } } else { - - # - # remove any previous config lines, so that when "clear vpn ipsec-process" - # is called it won't find the vyatta keyword and therefore will not try - # to start the ipsec process. - # - $genout = ''; - $genout .= "# No VPN configuration exists.\n"; - $genout_secrets .= "# No VPN configuration exists.\n"; + # + # remove any previous config lines, so that when "clear vpn ipsec-process" + # is called it won't find the vyatta keyword and therefore will not try + # to start the ipsec process. + # + $genout = ''; + $genout .= "# No VPN configuration exists.\n"; } -if ( - !( - defined($config_file) - && ( $config_file ne '' ) - && defined($secrets_file) - && ( $secrets_file ne '' ) - ) - ) -{ - print "Regular config file output would be:\n\n$genout\n\n"; - print "Secrets config file output would be:\n\n$genout_secrets\n\n"; - exit(0); +if (!(defined($config_file) && ( $config_file ne '' ))) { + print "Regular config file output would be:\n\n$genout\n\n"; + exit(0); } -write_config( $genout, $config_file, $genout_secrets, $secrets_file ); +write_config( $genout, $config_file); my $update_interval = $vcVPN->returnValue("ipsec auto-update"); my $update_interval_orig = $vcVPN->returnOrigValue("ipsec auto-update"); $update_interval_orig = 0 if !defined($update_interval_orig); if ( is_vpn_running() ) { - vpn_exec( 'ipsec rereadall >&/dev/null', 're-read secrets and certs' ); - vpn_exec( 'ipsec update >&/dev/null', 'update changes to ipsec.conf' ); + vpn_exec( 'ipsec rereadall >&/dev/null', 're-read secrets and certs' ); + vpn_exec( 'ipsec reload >&/dev/null', 'reload changes to ipsec.conf' ); + vpn_exec( 'swanctl -q >&/dev/null', 'reload changes to swanctl.conf' ); } else { - if ( !defined($update_interval) ) { - vpn_exec( 'ipsec start >&/dev/null', 'start ipsec' ); - } - else { - vpn_exec( - 'ipsec start --auto-update ' . $update_interval . ' >&/dev/null', - 'start ipsec with auto-update $update_interval' ); - } + if ( !defined($update_interval) ) { + vpn_exec( 'ipsec start >&/dev/null', 'start ipsec' ); + my $counter = 10; + while($counter > 0){ + if (-e "/var/run/charon.pid") { + vpn_exec( 'swanctl -q >&/dev/null', 'reload changes to swanctl.conf' ); + last; + } + $counter--; + sleep(1); + if($counter == 0){ + vpn_die("$vpn_cfg_err Ipsec is not running."); + } + } + } + else { + vpn_exec( + 'ipsec start --auto-update ' . $update_interval . ' >&/dev/null', + 'start ipsec with auto-update $update_interval' ); + my $counter = 10; + while($counter > 0){ + if (-e "/var/run/charon.pid") { + vpn_exec( 'swanctl -q >&/dev/null', 'reload changes to swanctl.conf' ); + last; + } + $counter--; + sleep(1); + if($counter == 0){ + vpn_die("$vpn_cfg_err Ipsec is not running."); + } + } + } } # @@ -594,101 +529,130 @@ else { exit 0; sub vpn_die { - my ( @path, $msg ) = @_; - Vyatta::Config::outputError( @path, $msg ); - exit 1; + my ( @path, $msg ) = @_; + Vyatta::Config::outputError( @path, $msg ); + exit 1; } sub write_config { - my ( $genout, $config_file, $genout_secrets, $secrets_file ) = @_; + my ( $genout, $config_file) = @_; - open my $output_config, '>', $config_file - or die "Can't open $config_file: $!"; - print ${output_config} $genout; - close $output_config; - - open my $output_secrets, '>', $secrets_file - or die "Can't open $secrets_file: $!"; - print ${output_secrets} $genout_secrets; - close $output_secrets; + open my $output_config, '>', $config_file + or die "Can't open $config_file: $!"; + print ${output_config} $genout; + close $output_config; } sub vpn_exec { - my ( $command, $desc ) = @_; - - open my $logf, '>>', $LOGFILE - or die "Can't open $LOGFILE: $!"; - - use POSIX; - my $timestamp = strftime( "%Y-%m-%d %H:%M.%S", localtime ); - - print ${logf} "$timestamp\nExecuting: $command\nDescription: $desc\n"; - - my $cmd_out = qx($command); - my $rval = ( $? >> 8 ); - print ${logf} "Output:\n$cmd_out\n---\n"; - print ${logf} "Return code: $rval\n"; - if ($rval) { - if ( $command =~ /^ipsec.*--asynchronous$/ - && ( $rval == 104 || $rval == 29 ) ) - { - print ${logf} "OK when bringing up VPN connection\n"; - } - else { - - # - # We use to consider the commit failed if we got a error - # from the call to ipsec, but this causes the configuration - # to not get included in the running config. Now that - # we support dynamic interface/address (e.g. dhcp, pppoe) - # we want a valid config to get committed even if the - # interface doesn't exist yet. That way we can use - # "clear vpn ipsec-process" to bring up the tunnel once - # the interface is instantiated. For pppoe we will add - # a script to /etc/ppp/ip-up.d to bring up the vpn - # tunnel. - # - print ${logf} - "VPN commit error. Unable to $desc, received error code $?\n"; - - # - # code 768 is for a syntax error in the secrets file - # this happens when a dhcp interface is configured - # but no address is assigned yet. - # only the line that has the syntax error is not loaded - # So we can safely ignore this error since our code generates - # secrets file. - # - if ( $? ne '768' ) { - print "Warning: unable to [$desc], received error code $?\n"; - print "$cmd_out\n"; - } - } - } - print ${logf} "---\n\n"; - close $logf; + my ( $command, $desc ) = @_; + + open my $logf, '>>', $LOGFILE + or die "Can't open $LOGFILE: $!"; + + use POSIX; + my $timestamp = strftime( "%Y-%m-%d %H:%M.%S", localtime ); + + print ${logf} "$timestamp\nExecuting: $command\nDescription: $desc\n"; + + my $cmd_out = qx($command); + my $rval = ( $? >> 8 ); + print ${logf} "Output:\n$cmd_out\n---\n"; + print ${logf} "Return code: $rval\n"; + if ($rval) { + if ( $command =~ /^ipsec.*--asynchronous$/ && ( $rval == 104 || $rval == 29 ) ) { + print ${logf} "OK when bringing up VPN connection\n"; + } + else { + # + # We use to consider the commit failed if we got a error + # from the call to ipsec, but this causes the configuration + # to not get included in the running config. Now that + # we support dynamic interface/address (e.g. dhcp, pppoe) + # we want a valid config to get committed even if the + # interface doesn't exist yet. That way we can use + # "clear vpn ipsec-process" to bring up the tunnel once + # the interface is instantiated. For pppoe we will add + # a script to /etc/ppp/ip-up.d to bring up the vpn + # tunnel. + # + print ${logf} "VPN commit error. Unable to $desc, received error code $?\n"; + + # + # code 768 is for a syntax error in the secrets file + # this happens when a dhcp interface is configured + # but no address is assigned yet. + # only the line that has the syntax error is not loaded + # So we can safely ignore this error since our code generates + # secrets file. + # + if ( $? ne '768' ) { + print "Warning: unable to [$desc], received error code $?\n"; + print "$cmd_out\n"; + } + } + } + print ${logf} "---\n\n"; + close $logf; } sub printTree { - my ( $vc, $path, $depth ) = @_; - - my @children = $vc->listNodes($path); - foreach my $child (@children) { - print ' ' x $depth; - print $child . "\n"; - printTree( $vc, "$path $child", $depth + 1 ); - } + my ( $vc, $path, $depth ) = @_; + + my @children = $vc->listNodes($path); + foreach my $child (@children) { + print ' ' x $depth; + print $child . "\n"; + printTree( $vc, "$path $child", $depth + 1 ); + } } sub printTreeOrig { - my ( $vc, $path, $depth ) = @_; - - my @children = $vc->listOrigNodes($path); - foreach my $child (@children) { - print ' ' x $depth; - print $child . "\n"; - printTreeOrig( $vc, "$path $child", $depth + 1 ); - } + my ( $vc, $path, $depth ) = @_; + + my @children = $vc->listOrigNodes($path); + foreach my $child (@children) { + print ' ' x $depth; + print $child . "\n"; + printTreeOrig( $vc, "$path $child", $depth + 1 ); + } } +sub get_dh_cipher_result { + my ($cipher) = @_; + my $ciph_out; + if ($cipher eq '2' || $cipher eq 'dh-group2') { + $ciph_out = 'modp1024'; + } elsif ($cipher eq '5' || $cipher eq 'dh-group5') { + $ciph_out = 'modp1536'; + } elsif ($cipher eq '14' || $cipher eq 'dh-group14') { + $ciph_out = 'modp2048'; + } elsif ($cipher eq '15' || $cipher eq 'dh-group15') { + $ciph_out = 'modp3072'; + } elsif ($cipher eq '16' || $cipher eq 'dh-group16') { + $ciph_out = 'modp4096'; + } elsif ($cipher eq '17' || $cipher eq 'dh-group17') { + $ciph_out = 'modp6144'; + } elsif ($cipher eq '18' || $cipher eq 'dh-group18') { + $ciph_out = 'modp8192'; + } elsif ($cipher eq '19' || $cipher eq 'dh-group19') { + $ciph_out = 'ecp256'; + } elsif ($cipher eq '20' || $cipher eq 'dh-group20') { + $ciph_out = 'ecp384'; + } elsif ($cipher eq '21' || $cipher eq 'dh-group21') { + $ciph_out = 'ecp521'; + } elsif ($cipher eq '22' || $cipher eq 'dh-group22') { + $ciph_out = 'modp1024s160'; + } elsif ($cipher eq '23' || $cipher eq 'dh-group23') { + $ciph_out = 'modp2048s224'; + } elsif ($cipher eq '24' || $cipher eq 'dh-group24') { + $ciph_out = 'modp2048s256'; + } elsif ($cipher eq '25' || $cipher eq 'dh-group25') { + $ciph_out = 'ecp192'; + } elsif ($cipher eq '26' || $cipher eq 'dh-group26') { + $ciph_out = 'ecp224'; + } else { + $ciph_out = 'unknown'; + } + return $ciph_out; +} # end of file diff --git a/scripts/vpn-config.pl b/scripts/vpn-config.pl index 184d1f2..071b3b8 100755 --- a/scripts/vpn-config.pl +++ b/scripts/vpn-config.pl @@ -37,7 +37,6 @@ use Vyatta::TypeChecker; use Vyatta::VPN::Util; use Getopt::Long; use Vyatta::Misc; -use NetAddr::IP; use Vyatta::VPN::vtiIntf; my $config_file; @@ -53,13 +52,16 @@ my $CRL_PATH = '/etc/ipsec.d/crls'; my $SERVER_CERT_PATH = '/etc/ipsec.d/certs'; my $SERVER_KEY_PATH = '/etc/ipsec.d/private'; my $LOGFILE = '/var/log/vyatta/ipsec.log'; +my $STRONGSWAN_INTF_CONFIG = '/etc/strongswan.d/interfaces_use.conf'; my $vpn_cfg_err = "VPN configuration error:"; my $clustering_ip = 0; my $dhcp_if = 0; my $genout; my $genout_secrets; +my $interfaces_use; my %key_file_list; +my %public_keys; # Set $using_klips to 1 if kernel IPsec support is provided by KLIPS. # Set it to 0 us using NETKEY. @@ -67,6 +69,7 @@ my $using_klips = 0; $genout .= "# generated by $0\n\n"; $genout_secrets .= "# generated by $0\n\n"; +$interfaces_use .= "# generated by $0\n\n"; # # Prepare Vyatta::Config object @@ -212,21 +215,26 @@ if ($vcVPN->exists('ipsec')) { } # - # Version 2 + # Configuration of system wide options # - $genout .= "version 2.0\n"; - $genout .= "\n"; $genout .= "config setup\n"; - $genout .= "\tcharonstart=yes\n"; + # # Interfaces # my @interfaces = $vcVPN->returnValues('ipsec ipsec-interfaces interface'); - if (@interfaces == 0) { - #*THIS CHECK'S ALSO USED BY OP-MODE CMNDS TO CHECK IF IPSEC IS CONFIGURED*# - vpn_die(["vpn", "ipsec","ipsec-interfaces"],"$vpn_cfg_err No IPSEC interfaces specified.\n"); - } else { + if (scalar(@interfaces) > 0) { + + $interfaces_use .= "charon {\n\tinterfaces_use = "; + foreach my $interface (@interfaces) { + if (!(-d "/sys/class/net/$interface")) { + print "Warning: unable to configure non-existent interface\n"; + } + $interfaces_use .= "$interface, "; + } + $interfaces_use .= "\n}"; + # We need to generate an "interfaces=..." entry in the setup section # only if the underlying IPsec kernel code we are using is KLIPS. # If we are using NETKEY, the "interfaces=..." entry is essentially @@ -252,7 +260,8 @@ if ($vcVPN->exists('ipsec')) { $genout .= '%defaultroute'; } $genout .= "\"\n"; - } else { + } + else { my $counter = 0; $genout .= "\t"; if (hasLocalWildcard($vcVPN, 0)) { @@ -264,13 +273,18 @@ if ($vcVPN->exists('ipsec')) { ++$counter; } $genout .= '%defaultroute"'; - } else { + } + else { $genout .= 'interfaces="%none"'; } $genout .= "\n"; + } - } + } else { + $interfaces_use .= ""; + + } # # NAT traversal # @@ -308,26 +322,6 @@ if ($vcVPN->exists('ipsec')) { $genout .= "\"\n"; } - # - # log-mode - # - my @logmodes = $vcVPN->returnValues('ipsec logging log-modes'); - if (@logmodes > 0) { - my $debugmode = ''; - foreach my $mode (@logmodes) { - if ($mode eq "all") { - $debugmode = "all"; - last; - } - if ($debugmode eq '') { - $debugmode = "$mode"; - } else { - $debugmode .= " $mode"; - } - } - $genout .= "\tplutodebug=\"$debugmode\"\n"; - } - # Set plutoopts: # Disable uniqreqids? # @@ -336,15 +330,6 @@ if ($vcVPN->exists('ipsec')) { } # - # Disable implicit connections - # - foreach my $conn (qw/clear clear-or-private private-or-clear private block packetdefault/){ - $genout .= "\n"; - $genout .= "conn $conn\n"; - $genout .= "\tauto=ignore\n"; - } - - # # Default keyengine is ikev1 # $genout .= "\n"; @@ -517,16 +502,6 @@ if ($vcVPN->exists('ipsec')) { $lip = get_dhcp_addr($dhcp_iface); } - # -> leftsourceip is the internal source IP to use in a tunnel - # -> we use leftsourceip to add a route to the rightsubnet - # only when rightsubnet is defined and is not 0.0.0.0/0. we do not - # want to add a vpn route for everything i.e. rightsubnet = 0.0.0.0/0 - # -> if leftsubnet is defined and is not 0.0.0.0/0; we try and find - # an interface on the system that has an IP address lying within - # the leftsubnet and use that as leftsourceip. if leftsubnet is not - # defined or is 0.0.0.0/0 then we use local-address as leftsourceip. - my $leftsourceip = undef; - # # Assign left and right to local and remote interfaces # @@ -537,11 +512,8 @@ if ($vcVPN->exists('ipsec')) { "for peer \"$peer\" $tunKeyword.\n"); } $genout .= "\tleft=%defaultroute\n"; - - # no need for leftsourceip as a defaultroute is must for this to work } else { $genout .= "\tleft=$lip\n"; - $leftsourceip = "\tleftsourceip=$lip\n"; } if (defined($authidfromcert)) { $genout .= "\tleftid=%fromcert\n"; @@ -597,19 +569,6 @@ if ($vcVPN->exists('ipsec')) { if (defined($leftsubnet)) { $genout .= "\tleftsubnet=$leftsubnet\n"; - if (!($leftsubnet eq '0.0.0.0/0')) { - my $localsubnet_object = new NetAddr::IP($leftsubnet); - - # leftsourceip should now be an IP on system lying within the leftsubnet - my @system_ips = Vyatta::Misc::getIP(undef, '4'); - foreach my $system_ip (@system_ips) { - my $systemip_object = new NetAddr::IP($system_ip); - if (CheckIfAddressInsideNetwork($systemip_object, $localsubnet_object)){ - my $sourceip = $systemip_object->addr(); - $leftsourceip = "\tleftsourceip=$sourceip\n"; - } - } - } } my $remotesubnet = $vcVPN->returnValue("ipsec site-to-site peer $peer $tunKeyword remote prefix"); @@ -667,21 +626,8 @@ if ($vcVPN->exists('ipsec')) { } if (defined($rightsubnet)) { $genout .= "\trightsubnet=$rightsubnet\n"; - - # not adding vpn route if remote prefix is 0.0.0.0/0 - # user should add a route [default/static] manually - $leftsourceip = undef if $rightsubnet eq '0.0.0.0/0'; - if ($rightsubnet =~ /vhost:%priv/) { - - # can't add route when rightsubnet is not specific - $leftsourceip = undef; - } - } else { - $leftsourceip =undef; # no need for vpn route if rightsubnet not defined } - $genout .= $leftsourceip if defined $leftsourceip; - # # Protocol/port # @@ -784,39 +730,12 @@ if ($vcVPN->exists('ipsec')) { if (defined($encryption) && defined($hash)) { $genout .= "$encryption-$hash"; if (defined($dh_group)) { - if ($dh_group eq '2') { - $genout .= '-modp1024'; - } elsif ($dh_group eq '5') { - $genout .= '-modp1536'; - } elsif ($dh_group eq '14') { - $genout .= '-modp2048'; - } elsif ($dh_group eq '15') { - $genout .= '-modp3072'; - } elsif ($dh_group eq '16') { - $genout .= '-modp4096'; - } elsif ($dh_group eq '17') { - $genout .= '-modp6144'; - } elsif ($dh_group eq '18') { - $genout .= '-modp8192'; - } elsif ($dh_group eq '19') { - $genout .= '-ecp256'; - } elsif ($dh_group eq '20') { - $genout .= '-ecp384'; - } elsif ($dh_group eq '21') { - $genout .= '-ecp521'; - } elsif ($dh_group eq '22') { - $genout .= '-modp1024s160'; - } elsif ($dh_group eq '23') { - $genout .= '-modp2048s224'; - } elsif ($dh_group eq '24') { - $genout .= '-modp2048s256'; - } elsif ($dh_group eq '25') { - $genout .= '-ecp192'; - } elsif ($dh_group eq '26') { - $genout .= '-ecp224'; - } elsif ($dh_group ne '') { + my $cipher_out = get_dh_cipher_result($dh_group); + if ($cipher_out eq 'unknown') { vpn_die(["vpn","ipsec","site-to-site","peer",$peer,"tunnel", $tunnel],"$vpn_cfg_err Invalid 'dh-group' $dh_group specified for ". "peer \"$peer\" $tunKeyword. Only 2, 5, or 14 through 26 accepted.\n"); + } else { + $genout .= "-$cipher_out"; } } } @@ -875,6 +794,21 @@ if ($vcVPN->exists('ipsec')) { } } + # + # Allow the user to specify aggressive mode for IKEv1 connections + # + my $aggressive_mode = $vcVPN->returnValue("ipsec ike-group $ike_group mode"); + + if (defined($aggressive_mode)) { + if (defined($key_exchange) && $key_exchange eq 'ikev2') { + vpn_die(["vpn","ipsec","ike-group", $ike_group, "mode"], "$vpn_cfg_err Selection of Main/Aggressive modes is only valid for IKEv1 configurations"); + } + if ($aggressive_mode eq 'aggressive') { + $genout .= "\taggressive=yes\n"; + } else { + $genout .= "\taggressive=no\n"; + } + } my $t_ikelifetime =$vcVPN->returnValue("ipsec ike-group $ike_group lifetime"); if (defined($t_ikelifetime) && $t_ikelifetime ne '') { $ikelifetime = $t_ikelifetime; @@ -895,6 +829,19 @@ if ($vcVPN->exists('ipsec')) { $genout .= "\tdpdtimeout=$dpd_timeout" . "s\n"; $genout .= "\tdpdaction=$dpd_action\n"; } + + # + # Allow the user for force UDP encapsulation for the ESP + # payload. + # + my $forceencaps = $vcVPN->returnValue("ipsec site-to-site peer $peer force-encapsulation"); + if (defined($forceencaps)) { + if ($forceencaps eq 'enable') { + $genout .= "\tforceencaps=yes\n"; + } else { + $genout .= "\tforceencaps=no\n"; + } + } } # @@ -912,10 +859,11 @@ if ($vcVPN->exists('ipsec')) { foreach my $esp_proposal (@esp_proposals) { # - # Get encryption, hash + # Get encryption, hash and PFS group settings # my $encryption = $vcVPN->returnValue("ipsec esp-group $esp_group proposal $esp_proposal encryption"); my $hash = $vcVPN->returnValue("ipsec esp-group $esp_group proposal $esp_proposal hash"); + my $pfs = $vcVPN->returnValue("ipsec esp-group $esp_group pfs"); # # Write separator if not first proposal @@ -925,45 +873,25 @@ if ($vcVPN->exists('ipsec')) { } else { $genout .= ","; } + if (defined($pfs)) { + if ($pfs eq 'enable') { + # Get the first IKE group's dh-group and use that as our PFS setting + my $default_pfs = $vcVPN->returnValue("ipsec ike-group $ike_group proposal 1 dh-group"); + $pfs = get_dh_cipher_result($default_pfs); + } elsif ($pfs eq 'disable') { + undef $pfs; + } else { + $pfs = get_dh_cipher_result($pfs); + } + } # # Write values # if (defined($encryption) && defined($hash)) { $genout .= "$encryption-$hash"; - my $pfs = $vcVPN->returnValue("ipsec esp-group $esp_group pfs"); if (defined($pfs)) { - if ($pfs eq 'dh-group2') { - $genout .= "\-modp1024"; - } elsif ($pfs eq 'dh-group5') { - $genout .= "\-modp1536"; - } elsif ($pfs eq 'dh-group14') { - $genout .= "\-modp2048"; - } elsif ($pfs eq 'dh-group15') { - $genout .= "\-modp3072"; - } elsif ($pfs eq 'dh-group16') { - $genout .= "\-modp4096"; - } elsif ($pfs eq 'dh-group17') { - $genout .= "\-modp6144"; - } elsif ($pfs eq 'dh-group18') { - $genout .= "\-modp8192"; - } elsif ($pfs eq 'dh-group19') { - $genout .= "\-ecp256"; - } elsif ($pfs eq 'dh-group20') { - $genout .= "\-ecp384"; - } elsif ($pfs eq 'dh-group21') { - $genout .= "\-ecp521"; - } elsif ($pfs eq 'dh-group22') { - $genout .= "\-modp1024s160"; - } elsif ($pfs eq 'dh-group23') { - $genout .= "\-modp2048s224"; - } elsif ($pfs eq 'dh-group24') { - $genout .= "\-modp2048s256"; - } elsif ($pfs eq 'dh-group25') { - $genout .= "\-ecp192"; - } elsif ($pfs eq 'dh-group26') { - $genout .= "\-ecp224"; - } + $genout .= "-$pfs"; } } } @@ -1009,63 +937,6 @@ if ($vcVPN->exists('ipsec')) { $genout .= "\ttype=$espmode\n"; # - # Perfect Forward Secrecy - # - my $pfs = $vcVPN->returnValue("ipsec esp-group $esp_group pfs"); - if (defined($pfs)) { - if ($pfs eq 'enable') { - $genout .= "\tpfs=yes\n"; - } elsif ($pfs eq 'dh-group2') { - $genout .= "\tpfs=yes\n"; - $genout .= "\tpfsgroup=modp1024\n"; - } elsif ($pfs eq 'dh-group5') { - $genout .= "\tpfs=yes\n"; - $genout .= "\tpfsgroup=modp1536\n"; - } elsif ($pfs eq 'dh-group14') { - $genout .= "\tpfs=yes\n"; - $genout .= "\tpfsgroup=modp2048\n"; - } elsif ($pfs eq 'dh-group15') { - $genout .= "\tpfs=yes\n"; - $genout .= "\tpfsgroup=modp3072\n"; - } elsif ($pfs eq 'dh-group16') { - $genout .= "\tpfs=yes\n"; - $genout .= "\tpfsgroup=modp4096\n"; - } elsif ($pfs eq 'dh-group17') { - $genout .= "\tpfs=yes\n"; - $genout .= "\tpfsgroup=modp6144\n"; - } elsif ($pfs eq 'dh-group18') { - $genout .= "\tpfs=yes\n"; - $genout .= "\tpfsgroup=modp8192\n"; - } elsif ($pfs eq 'dh-group19') { - $genout .= "\tpfs=yes\n"; - $genout .= "\tpfsgroup=ecp256\n"; - } elsif ($pfs eq 'dh-group20') { - $genout .= "\tpfs=yes\n"; - $genout .= "\tpfsgroup=ecp384\n"; - } elsif ($pfs eq 'dh-group21') { - $genout .= "\tpfs=yes\n"; - $genout .= "\tpfsgroup=ecp521\n"; - } elsif ($pfs eq 'dh-group22') { - $genout .= "\tpfs=yes\n"; - $genout .= "\tpfsgroup=modp1024s160\n"; - } elsif ($pfs eq 'dh-group23') { - $genout .= "\tpfs=yes\n"; - $genout .= "\tpfsgroup=modp2048s224\n"; - } elsif ($pfs eq 'dh-group24') { - $genout .= "\tpfs=yes\n"; - $genout .= "\tpfsgroup=modp2048s256\n"; - } elsif ($pfs eq 'dh-group25') { - $genout .= "\tpfs=yes\n"; - $genout .= "\tpfsgroup=ecp192\n"; - } elsif ($pfs eq 'dh-group26') { - $genout .= "\tpfs=yes\n"; - $genout .= "\tpfsgroup=ecp224\n"; - } else { - $genout .= "\tpfs=no\n"; - } - } - - # # Compression # my $compression =$vcVPN->returnValue("ipsec esp-group $esp_group compression"); @@ -1177,7 +1048,10 @@ if ($vcVPN->exists('ipsec')) { vpn_die(["vpn","ipsec","site-to-site","peer",$peer,"authentication"],"$vpn_cfg_err Unable to determine local public key from local key". " file \"$local_key_file\" for peer \"$peer\".\n"); } else { - $genout .= "\tleftrsasigkey=\"$local_key\"\n"; + if (!defined($public_keys{localhost})) { + $public_keys{localhost} = $local_key; + $genout .= "\tleftsigkey=localhost.pub\n"; + } } my $rsa_key_name = $vcVPN->returnValue("ipsec site-to-site peer $peer authentication rsa-key-name"); @@ -1190,13 +1064,16 @@ if ($vcVPN->exists('ipsec')) { vpn_die(["vpn","ipsec","site-to-site","peer",$peer,"authentication"],"$vpn_cfg_err No remote key configured for rsa key name ". "\"$rsa_key_name\" that is specified for peer \"$peer\".\n"); } else { - $genout .= "\trightrsasigkey=\"$remote_key\"\n"; + if (!defined($public_keys{$rsa_key_name})) { + $public_keys{$rsa_key_name} = $remote_key; + $genout .= "\trightsigkey=$rsa_key_name.pub\n"; + } } } # Prevent duplicate includes for rsa keys. if (!defined($key_file_list{$local_key_file})) { $key_file_list{$local_key_file} = 1; - $genout_secrets .= "include $local_key_file\n"; + $genout_secrets .= ": RSA $local_key_file\n"; } } else { vpn_die(["vpn","ipsec","site-to-site","peer",$peer,"authentication"],"$vpn_cfg_err Unknown authentication mode \"$auth_mode\" for peer ". @@ -1274,11 +1151,23 @@ if ($vcVPN->exists('ipsec')) { } } } - if (-e '/etc/dmvpn.conf') { - $genout .= "\ninclude /etc/dmvpn.conf\n"; + + # + # Include a custom configuration file + # + my $custom_include = $vcVPN->returnValue("ipsec include-ipsec-conf"); + my $custom_secrets = $vcVPN->returnValue("ipsec include-ipsec-secrets"); + if (defined($custom_include)) { + if ( ! -e $custom_include ) { + vpn_die(["vpn","ipsec","include-ipsec-conf"],"$vpn_cfg_err The specified file for inclusion inside ipsec.conf does not exist."); + } + $genout .= "\ninclude $custom_include\n"; } - if (-e '/etc/dmvpn.secrets') { - $genout_secrets .= "\ninclude /etc/dmvpn.secrets\n"; + if (defined($custom_secrets)) { + if ( ! -e $custom_secrets) { + vpn_die(["vpn","ipsec","include-ipsec-secrets"],"$vpn_cfg_err The specified file for inclusion inside ipsec.secrets does not exist."); + } + $genout_secrets .= "\ninclude $custom_secrets\n"; } } else { @@ -1313,13 +1202,13 @@ if ( $vcVPN->isDeleted('.') if (!enableICMP('1')) { vpn_die(["vpn","ipsec"],"VPN commit error. Unable to re-enable ICMP redirects.\n"); } - write_config($genout, $config_file, $genout_secrets, $secrets_file, $dhcp_if); + write_config($genout, $interfaces_use, $STRONGSWAN_INTF_CONFIG, $config_file, $genout_secrets, $secrets_file, $dhcp_if, %public_keys); } else { if (!enableICMP('0')) { vpn_die(["vpn","ipsec"],"VPN commit error. Unable to disable ICMP redirects.\n"); } - write_config($genout, $config_file, $genout_secrets, $secrets_file, $dhcp_if); + write_config($genout, $interfaces_use, $STRONGSWAN_INTF_CONFIG, $config_file, $genout_secrets, $secrets_file, $dhcp_if, %public_keys); # Assumming that if there was a local IP missmatch and clustering is enabled, # then the clustering scripts will take care of starting the VPN daemon. @@ -1342,8 +1231,51 @@ if ( $vcVPN->isDeleted('.') print "Re-starting IPsec daemon to deactivate auto-update...\n"; vpn_exec('ipsec restart >&/dev/null', 're-starting ipsec'); }else { - vpn_exec('ipsec rereadall >&/dev/null', 're-read secrets and certs'); - vpn_exec('ipsec update >&/dev/null', 'update changes to ipsec.conf'); + + # Grab the list of old peers and tunnels + my @tunnel_cfg_new = $vcVPN->listNodes('ipsec site-to-site peer'); + my @tunnel_cfg_old = $vcVPN->listOrigNodes('ipsec site-to-site peer'); + my @old_tunnels; + my %seen; + @seen{@tunnel_cfg_new} = (); + + # Find the old tunnels in previous configuration + foreach my $tunnel (@tunnel_cfg_old) { + push (@old_tunnels, $tunnel) unless exists $seen{$tunnel}; + } + + # Issue an ipsec down on the old tunnel since charon doesn't clean up + # connections removed from ipsec.conf + foreach my $old_peer (@old_tunnels) { + my @tunnels = $vcVPN->listOrigNodes("ipsec site-to-site peer $old_peer tunnel"); + foreach my $tunnel (@tunnels) + { + vpn_exec("ipsec down peer-$old_peer-tunnel-$tunnel", "Cleaning up site-to-site peer $old_peer at tunnel $tunnel"); + } + } + # Check if returnValues equals returnOrigValues for ipsec-interfaces and restart if they are not equal + my $equals = 1; + my @working_interfaces = $vcVPN->returnValues("ipsec ipsec-interfaces interface"); + my @active_interfaces = $vcVPN->returnOrigValues("ipsec ipsec-interfaces interface"); + if (scalar(@working_interfaces) != scalar(@active_interfaces)){ + $equals = 0; + } + else { + my @sorted_working = sort @working_interfaces; + my @sorted_active = sort @active_interfaces; + foreach (my $i = 0; $i < @sorted_working; $i++) { + if ($sorted_working[$i] ne $sorted_active[$i]) { + $equals = 0; + last; + } + } + } + if ($equals == 0) { + vpn_exec('ipsec restart >&/dev/null', 're-starting ipsec'); + }else { + vpn_exec('ipsec rereadall >&/dev/null', 're-read secrets and certs'); + vpn_exec('ipsec reload >&/dev/null', 'reload changes to ipsec.conf'); + } } } else { if (!defined($update_interval)) { @@ -1352,6 +1284,24 @@ if ( $vcVPN->isDeleted('.') vpn_exec('ipsec start --auto-update '.$update_interval.' >&/dev/null','start ipsec with auto-update $update_interval'); } } + + # Activate any debugging options by + # calling ipsec stroke loglevel <source> <level> + my @logmodes = $vcVPN->returnValues('ipsec logging log-modes'); + my @oldmodes = $vcVPN->returnOrigValues('ipsec logging log-modes'); + my $charonloglevel = $vcVPN->returnValue('ipsec logging log-level'); + # Clean up any logging modes if present + if (@oldmodes > 0) { + foreach my $mode (@oldmodes) { + vpn_exec("ipsec stroke loglevel $mode 0", "Deactivating log source $mode"); + } + } + # Finally activate our new logger configuration + if (@logmodes > 0) { + foreach my $mode (@logmodes) { + vpn_exec("ipsec stroke loglevel $mode $charonloglevel", "Stroking log source $mode to loglevel $charonloglevel"); + } + } } } @@ -1367,13 +1317,19 @@ sub vpn_die { } sub write_config { - my ($genout, $config_file, $genout_secrets, $secrets_file, $dhcp_if) = @_; + my ($genout, $interfaces_use, $STRONGSWAN_INTF_CONFIG, $config_file, $genout_secrets, $secrets_file, $dhcp_if, %public_keys) = @_; open my $output_config, '>', $config_file or die "Can't open $config_file: $!"; print ${output_config} $genout; close $output_config; + + open my $strong_config, '>', $STRONGSWAN_INTF_CONFIG + or die "Can't open $STRONGSWAN_INTF_CONFIG: $!"; + print ${strong_config} $interfaces_use; + close $strong_config; + my @lines = split("\n", $genout_secrets); my @any = grep(/%any/, @lines); if (scalar(@any) > 0) { @@ -1388,6 +1344,14 @@ sub write_config { print ${output_secrets} $genout_secrets; close $output_secrets; dhcp_hook($dhcp_if); + + for my $name (keys %public_keys) { + my $output_path = "/etc/ipsec.d/certs/$name.pub"; + open my $output_file, '>', $output_path + or die "Can't open $output_path: $!"; + print ${output_file} rsa_convert_pubkey_pem($public_keys{$name}); + close $output_file; + } } sub vpn_exec { @@ -1496,26 +1460,6 @@ sub hasLocalWildcard { return 0; } -sub CheckIfAddressInsideNetwork { - my ($address, $naipNetwork) = @_; - - if (!defined($address) || !defined($naipNetwork)) { - return 0; - } - - my $naipSM = new NetAddr::IP($address); - if (defined($naipSM)) { - my $subnetIA = $naipSM->network()->addr(); - my $naipIA = new NetAddr::IP($subnetIA, $naipSM->masklen()); - - if (defined($naipIA) && $naipNetwork->within($naipIA)) { - return 1; - } - } - - return 0; -} - sub get_x509 { my $peer = pop(@_); @@ -1601,11 +1545,50 @@ sub dhcp_hook { /opt/vyatta/bin/sudo-users/vyatta-ipsec-dhcp.pl --interface=\"\$interface\" --new_ip=\"\$new_ip_address\" --reason=\"\$reason\" --old_ip=\"\$old_ip_address\" EOS } - my $hook = "/etc/dhcp3/dhclient-exit-hooks.d/ipsecd"; + my $hook = "/etc/dhcp/dhclient-exit-hooks.d/ipsecd"; open my $dhcp_hook, '>', $hook or die "cannot open $hook"; print ${dhcp_hook} $str; close $dhcp_hook; } +sub get_dh_cipher_result { + my ($cipher) = @_; + my $ciph_out; + if ($cipher eq '2' || $cipher eq 'dh-group2') { + $ciph_out = 'modp1024'; + } elsif ($cipher eq '5' || $cipher eq 'dh-group5') { + $ciph_out = 'modp1536'; + } elsif ($cipher eq '14' || $cipher eq 'dh-group14') { + $ciph_out = 'modp2048'; + } elsif ($cipher eq '15' || $cipher eq 'dh-group15') { + $ciph_out = 'modp3072'; + } elsif ($cipher eq '16' || $cipher eq 'dh-group16') { + $ciph_out = 'modp4096'; + } elsif ($cipher eq '17' || $cipher eq 'dh-group17') { + $ciph_out = 'modp6144'; + } elsif ($cipher eq '18' || $cipher eq 'dh-group18') { + $ciph_out = 'modp8192'; + } elsif ($cipher eq '19' || $cipher eq 'dh-group19') { + $ciph_out = 'ecp256'; + } elsif ($cipher eq '20' || $cipher eq 'dh-group20') { + $ciph_out = 'ecp384'; + } elsif ($cipher eq '21' || $cipher eq 'dh-group21') { + $ciph_out = 'ecp521'; + } elsif ($cipher eq '22' || $cipher eq 'dh-group22') { + $ciph_out = 'modp1024s160'; + } elsif ($cipher eq '23' || $cipher eq 'dh-group23') { + $ciph_out = 'modp2048s224'; + } elsif ($cipher eq '24' || $cipher eq 'dh-group24') { + $ciph_out = 'modp2048s256'; + } elsif ($cipher eq '25' || $cipher eq 'dh-group25') { + $ciph_out = 'ecp192'; + } elsif ($cipher eq '26' || $cipher eq 'dh-group26') { + $ciph_out = 'ecp224'; + } else { + $ciph_out = 'unknown'; + } + return $ciph_out; +} + # end of file diff --git a/scripts/vyatta-vti-config.pl b/scripts/vyatta-vti-config.pl index fbfad64..81abf97 100755 --- a/scripts/vyatta-vti-config.pl +++ b/scripts/vyatta-vti-config.pl @@ -25,7 +25,7 @@ # # For each VTI tunnel (vpn ipsec site-to-site peer ip-address sti); find the vti tunnel, local address, mark. # Find the corresponding tunnel (interfaces vti vtiXXX), tunnel address, disable, mtu -# if not configured: ip tunnel add vtiXXX mode esp local $local remote $remote i_key $mark +# if not configured: ip tunnel add vtiXXX mode esp local $local remote $remote ikey $mark okey $mark # if (mtu): configure mtu # if (tunnel-addres): configur ip link vtiXXX address # if (!disable): enable the interface. @@ -207,7 +207,7 @@ foreach my $peer (@peers) { # By default we delete the tunnel... my $genmark = $mark; $gencmds .= "sudo /sbin/ip link delete $tunName type vti &> /dev/null\n"; - $gencmds .= "sudo /sbin/ip link add $tunName type vti local $lip remote $peer okey $genmark\n"; + $gencmds .= "sudo /sbin/ip link add $tunName type vti local $lip remote $peer okey $genmark ikey $genmark\n"; foreach my $tunIP (@tunIPs) { $gencmds .= "sudo /sbin/ip addr add $tunIP dev $tunName\n"; } diff --git a/templates/vpn/ipsec/esp-group/node.tag/proposal/node.tag/encryption/node.def b/templates/vpn/ipsec/esp-group/node.tag/proposal/node.tag/encryption/node.def index 0e8fd2d..ba66828 100644 --- a/templates/vpn/ipsec/esp-group/node.tag/proposal/node.tag/encryption/node.def +++ b/templates/vpn/ipsec/esp-group/node.tag/proposal/node.tag/encryption/node.def @@ -1,10 +1,10 @@ help: Encryption algorithm type: txt default: "aes128" -syntax:expression: $VAR(@) in "aes128", "aes256", "3des"; "must be aes128, or aes256, or 3des" -syntax:expression: $VAR(@) in "aes128", "aes256", "3des", "aes128gcm128", "aes256gcm128"; "must be aes128, or aes128gcm128, or aes256, or aes256gcm128, or 3des" +syntax:expression: $VAR(@) in "aes128", "aes256", "aes128gcm128", "aes256gcm128", "3des", "chacha20poly1305"; "must be aes128, aes256, 3des, or chacha20poly1305" val_help: aes128; AES-128 encryption (default) val_help: aes256; AES-256 encryption val_help: aes128gcm128; AES-128 encryption with Galois Counter Mode 128-bit val_help: aes256gcm128; AES-256 encryption with Galois Counter Mode 128-bit val_help: 3des; 3DES encryption +val_help: chacha20poly1305; ChaCha20-Poly1305 encryption diff --git a/templates/vpn/ipsec/ike-group/node.tag/dead-peer-detection/interval/node.def b/templates/vpn/ipsec/ike-group/node.tag/dead-peer-detection/interval/node.def index 4fdebe9..e6175c9 100644 --- a/templates/vpn/ipsec/ike-group/node.tag/dead-peer-detection/interval/node.def +++ b/templates/vpn/ipsec/ike-group/node.tag/dead-peer-detection/interval/node.def @@ -1,5 +1,5 @@ help: Keep-alive interval -type: u32 +type: u32 default: 30 -syntax:expression: ($VAR(@) >= 15 && $VAR(@) <= 86400) ; "must be between 15-86400 seconds" -val_help: u32:15-86400; Keep-alive interval in seconds (default 30) +syntax:expression: ($VAR(@) >= 2 && $VAR(@) <= 86400) ; "must be between 2-86400 seconds" +val_help: u32:2-86400; Keep-alive interval in seconds (default 30) diff --git a/templates/vpn/ipsec/ike-group/node.tag/dead-peer-detection/timeout/node.def b/templates/vpn/ipsec/ike-group/node.tag/dead-peer-detection/timeout/node.def index 939be1c..3378cb5 100644 --- a/templates/vpn/ipsec/ike-group/node.tag/dead-peer-detection/timeout/node.def +++ b/templates/vpn/ipsec/ike-group/node.tag/dead-peer-detection/timeout/node.def @@ -1,7 +1,5 @@ help: Keep-alive timeout -type: u32 +type: u32 default: 120 -syntax:expression: ($VAR(@) >= 30 && $VAR(@) <= 86400) ; "must be between 30-86400 seconds" -val_help: u32:30-86400; Keep-alive timeout in seconds (default 120) - - +syntax:expression: ($VAR(@) >= 10 && $VAR(@) <= 86400) ; "must be between 10-86400 seconds" +val_help: u32:10-86400; Keep-alive timeout in seconds (default 120) diff --git a/templates/vpn/ipsec/ike-group/node.tag/mode/node.def b/templates/vpn/ipsec/ike-group/node.tag/mode/node.def new file mode 100644 index 0000000..2b67dad --- /dev/null +++ b/templates/vpn/ipsec/ike-group/node.tag/mode/node.def @@ -0,0 +1,5 @@ +help: IKEv1 Phase 1 Mode Selection +type: txt +syntax:expression: $VAR(@) in "main", "aggressive"; "must be main or aggressive" +val_help: main; Use Main mode for Key Exchanges in the IKEv1 Protocol (Recommended Default) +val_help: aggressive; Use Aggressive mode for Key Exchanges in the IKEv1 protocol - We do not recommend users to use aggressive mode as it is much more insecure compared to Main mode. diff --git a/templates/vpn/ipsec/ike-group/node.tag/proposal/node.tag/dh-group/node.def b/templates/vpn/ipsec/ike-group/node.tag/proposal/node.tag/dh-group/node.def index 307dc09..32deb66 100644 --- a/templates/vpn/ipsec/ike-group/node.tag/proposal/node.tag/dh-group/node.def +++ b/templates/vpn/ipsec/ike-group/node.tag/proposal/node.tag/dh-group/node.def @@ -1,5 +1,6 @@ help: Diffie-Hellman (DH) key exchange group type: u32 +default: 2 syntax:expression: ($VAR(@) == 2 || $VAR(@) == 5 || ($VAR(@) >= 14 && $VAR(@) <= 26)); "must be 2, 5 or 14 through 26" val_help: 2; DH group 2 (modp1024) val_help: 5; DH group 5 (modp1536) diff --git a/templates/vpn/ipsec/ike-group/node.tag/proposal/node.tag/encryption/node.def b/templates/vpn/ipsec/ike-group/node.tag/proposal/node.tag/encryption/node.def index 0e8fd2d..ba66828 100644 --- a/templates/vpn/ipsec/ike-group/node.tag/proposal/node.tag/encryption/node.def +++ b/templates/vpn/ipsec/ike-group/node.tag/proposal/node.tag/encryption/node.def @@ -1,10 +1,10 @@ help: Encryption algorithm type: txt default: "aes128" -syntax:expression: $VAR(@) in "aes128", "aes256", "3des"; "must be aes128, or aes256, or 3des" -syntax:expression: $VAR(@) in "aes128", "aes256", "3des", "aes128gcm128", "aes256gcm128"; "must be aes128, or aes128gcm128, or aes256, or aes256gcm128, or 3des" +syntax:expression: $VAR(@) in "aes128", "aes256", "aes128gcm128", "aes256gcm128", "3des", "chacha20poly1305"; "must be aes128, aes256, 3des, or chacha20poly1305" val_help: aes128; AES-128 encryption (default) val_help: aes256; AES-256 encryption val_help: aes128gcm128; AES-128 encryption with Galois Counter Mode 128-bit val_help: aes256gcm128; AES-256 encryption with Galois Counter Mode 128-bit val_help: 3des; 3DES encryption +val_help: chacha20poly1305; ChaCha20-Poly1305 encryption diff --git a/templates/vpn/ipsec/include-ipsec-conf/node.def b/templates/vpn/ipsec/include-ipsec-conf/node.def new file mode 100644 index 0000000..fc82a45 --- /dev/null +++ b/templates/vpn/ipsec/include-ipsec-conf/node.def @@ -0,0 +1,2 @@ +type: txt +help: Sets to include an additional configuration directive file for strongSwan. Use an absolute path to specify the included file. diff --git a/templates/vpn/ipsec/include-ipsec-secrets/node.def b/templates/vpn/ipsec/include-ipsec-secrets/node.def new file mode 100644 index 0000000..37b73e1 --- /dev/null +++ b/templates/vpn/ipsec/include-ipsec-secrets/node.def @@ -0,0 +1,2 @@ +type: txt +help: Sets to include an additional secrets file for strongSwan. Use an absolute path to specify the included file. diff --git a/templates/vpn/ipsec/logging/log-level/node.def b/templates/vpn/ipsec/logging/log-level/node.def new file mode 100644 index 0000000..54cf698 --- /dev/null +++ b/templates/vpn/ipsec/logging/log-level/node.def @@ -0,0 +1,5 @@ +help: strongSwan Logger Level +type: u32 +default: 1 +syntax:expression: ($VAR(@) >= 0 && $VAR(@) <= 2) ; "must be between levels 0-2" +val_help: u32:0-2; Logger Verbosity Level (default 0) diff --git a/templates/vpn/ipsec/logging/log-modes/node.def b/templates/vpn/ipsec/logging/log-modes/node.def index f0dd9f4..5662a4e 100644 --- a/templates/vpn/ipsec/logging/log-modes/node.def +++ b/templates/vpn/ipsec/logging/log-modes/node.def @@ -1,11 +1,21 @@ multi: -help: Log mode +help: Log mode. To see what each log mode exactly does, please refer to the strongSwan documentation type: txt -syntax:expression: $VAR(@) in "raw", "crypt", "parsing", "emitting", "control", "all", "private" ; "must be one of the following: raw, crypt, parsing, emitting, control, all, private" -val_help: raw; Debug log option for pluto -val_help: crypt; Debug log option for pluto -val_help: parsing; Debug log option for pluto -val_help: emitting; Debug log option for pluto -val_help: control; Debug log option for pluto -val_help: all; Debug log option for pluto -val_help: private; Debug log option for pluto +syntax:expression: $VAR(@) in "dmn", "mgr", "ike", "chd", "job", "cfg", "knl", "net", "asn", "enc", "lib", "esp", "tls", "tnc", "imc", "imv", "pts" ; "must be one of the following: dmn, mgr, ike, chd, job, cfg, knl, net, asn, enc, lib, esp, tls, tnc, imc, imv, pts" +val_help: dmn; Debug log option for strongSwan +val_help: mgr; Debug log option for strongSwan +val_help: ike; Debug log option for strongSwan +val_help: chd; Debug log option for strongSwan +val_help: job; Debug log option for strongSwan +val_help: cfg; Debug log option for strongSwan +val_help: knl; Debug log option for strongSwan +val_help: net; Debug log option for strongSwan +val_help: asn; Debug log option for strongSwan +val_help: enc; Debug log option for strongSwan +val_help: lib; Debug log option for strongSwan +val_help: esp; Debug log option for strongSwan +val_help: tls; Debug log option for strongSwan +val_help: tnc; Debug log option for strongSwan +val_help: imc; Debug log option for strongSwan +val_help: imv; Debug log option for strongSwan +val_help: pts; Debug log option for strongSwan diff --git a/templates/vpn/ipsec/site-to-site/peer/node.tag/default-esp-group/node.def b/templates/vpn/ipsec/site-to-site/peer/node.tag/default-esp-group/node.def index f754c32..d389bab 100644 --- a/templates/vpn/ipsec/site-to-site/peer/node.tag/default-esp-group/node.def +++ b/templates/vpn/ipsec/site-to-site/peer/node.tag/default-esp-group/node.def @@ -1,4 +1,4 @@ help: Defult ESP group name type: txt -allowed: cli-shell-api listActiveNodes vpn ipsec esp-group +allowed: cli-shell-api listNodes vpn ipsec esp-group diff --git a/templates/vpn/ipsec/site-to-site/peer/node.tag/dhcp-interface/node.def b/templates/vpn/ipsec/site-to-site/peer/node.tag/dhcp-interface/node.def index a25e076..026b175 100644 --- a/templates/vpn/ipsec/site-to-site/peer/node.tag/dhcp-interface/node.def +++ b/templates/vpn/ipsec/site-to-site/peer/node.tag/dhcp-interface/node.def @@ -2,6 +2,6 @@ type: txt help: DHCP interface to listen on allowed: local -a array ; - array=( /var/lib/dhcp3/eth* /var/lib/dhcp3/br* /var/lib/dhcp3/bond* ) ; + array=( /var/lib/dhcp/eth* /var/lib/dhcp/br* /var/lib/dhcp/bond* ) ; echo -n ${array[@]##*/} diff --git a/templates/vpn/ipsec/site-to-site/peer/node.tag/force-encapsulation/node.def b/templates/vpn/ipsec/site-to-site/peer/node.tag/force-encapsulation/node.def new file mode 100644 index 0000000..bc71729 --- /dev/null +++ b/templates/vpn/ipsec/site-to-site/peer/node.tag/force-encapsulation/node.def @@ -0,0 +1,6 @@ +help: Force UDP Encapsulation for ESP Payloads +type: txt +syntax:expression: $VAR(@) in "enable", "disable"; "Must be enable or disable" +val_help: enable; This endpoint will force UDP encapsulation for this peer +val_help: disable; This endpoint will not force UDP encapsulation for this peer + diff --git a/templates/vpn/ipsec/site-to-site/peer/node.tag/ike-group/node.def b/templates/vpn/ipsec/site-to-site/peer/node.tag/ike-group/node.def index 343f1fb..146805c 100644 --- a/templates/vpn/ipsec/site-to-site/peer/node.tag/ike-group/node.def +++ b/templates/vpn/ipsec/site-to-site/peer/node.tag/ike-group/node.def @@ -1,3 +1,3 @@ help: Internet Key Exchange (IKE) group name [REQUIRED] type: txt -allowed: cli-shell-api listActiveNodes vpn ipsec ike-group +allowed: cli-shell-api listNodes vpn ipsec ike-group diff --git a/templates/vpn/ipsec/site-to-site/peer/node.tag/tunnel/node.tag/esp-group/node.def b/templates/vpn/ipsec/site-to-site/peer/node.tag/tunnel/node.tag/esp-group/node.def index d773b96..16300c5 100644 --- a/templates/vpn/ipsec/site-to-site/peer/node.tag/tunnel/node.tag/esp-group/node.def +++ b/templates/vpn/ipsec/site-to-site/peer/node.tag/tunnel/node.tag/esp-group/node.def @@ -1,3 +1,3 @@ help: ESP group name type: txt -allowed: cli-shell-api listActiveNodes vpn ipsec esp-group +allowed: cli-shell-api listNodes vpn ipsec esp-group diff --git a/templates/vpn/node.def b/templates/vpn/node.def index 7c6b56a..ae2d6a9 100644 --- a/templates/vpn/node.def +++ b/templates/vpn/node.def @@ -2,8 +2,7 @@ priority: 900 help: Virtual Private Network (VPN) end:sudo /opt/vyatta/sbin/vyatta-vti-config.pl || exit 1 sudo /opt/vyatta/sbin/dmvpn-config.pl \ - --config_file='/etc/dmvpn.conf' \ - --secrets_file='/etc/dmvpn.secrets' \ + --config_file='/etc/swanctl/swanctl.conf' \ --init_script='/etc/init.d/ipsec' || exit 1 sudo /opt/vyatta/sbin/vyos-update-nhrp.pl --set_ipsec || exit 1 sudo /opt/vyatta/sbin/vpn-config.pl \ |