diff options
author | John Southworth <john.southworth@vyatta.com> | 2011-02-16 19:16:25 -0600 |
---|---|---|
committer | John Southworth <john.southworth@vyatta.com> | 2011-02-16 19:16:25 -0600 |
commit | eca11479b369dc04894da775f394e306b452d5b4 (patch) | |
tree | 7c9e50c5c4cf420e6083faa5d18d6da11918b415 | |
parent | 241734ed6dc0c63411c78b82b8a85254fc311809 (diff) | |
download | vyatta-cfg-vpn-eca11479b369dc04894da775f394e306b452d5b4.tar.gz vyatta-cfg-vpn-eca11479b369dc04894da775f394e306b452d5b4.zip |
Initial support for configuring dhcp-interfaces for IPSEC, needs testing
-rw-r--r-- | Makefile.am | 3 | ||||
-rwxr-xr-x | scripts/vpn-config.pl | 66 | ||||
-rwxr-xr-x | scripts/vyatta-ipsec-dhcp.pl | 92 | ||||
-rw-r--r-- | templates/vpn/ipsec/site-to-site/peer/node.tag/dhcp-interface/node.def | 7 |
4 files changed, 159 insertions, 9 deletions
diff --git a/Makefile.am b/Makefile.am index a9ca91a..eb1336a 100644 --- a/Makefile.am +++ b/Makefile.am @@ -4,12 +4,13 @@ libudevdir = /lib/udev etcudevdir = /etc/udev initddir = /etc/init.d curverdir = $(sysconfdir)/config-migrate/current +bin_sudo_usersdir = $(bindir)/sudo-users sbin_SCRIPTS = sbin_SCRIPTS += scripts/vpn-config.pl sbin_SCRIPTS += scripts/vyatta-vpn-ppp-updown.pl - +bin_sudo_users_SCRIPTS = scripts/vyatta-ipsec-dhcp.pl share_perl5_DATA = lib/Vyatta/VPN/Util.pm curver_DATA = cfg-version/ipsec@3 diff --git a/scripts/vpn-config.pl b/scripts/vpn-config.pl index f265f55..a9b9bf8 100755 --- a/scripts/vpn-config.pl +++ b/scripts/vpn-config.pl @@ -54,6 +54,7 @@ my $SERVER_KEY_PATH = '/etc/ipsec.d/private'; my $vpn_cfg_err = "VPN configuration error:"; my $clustering_ip = 0; +my $dhcp_if = 0; my $genout; my $genout_secrets; @@ -398,12 +399,22 @@ if ( $vcVPN->exists('ipsec') ) { } my $lip = $vcVPN->returnValue("ipsec site-to-site peer $peer local-ip"); + my $dhcp_iface = $vcVPN->returnValue("ipsec site-to-site peer $peer dhcp-interface"); + if (defined($lip) && defined($dhcp_iface)){ + vpn_die(["vpn","ipsec","site-to-site","peer",$peer], + "$vpn_cfg_err Only one of local-ip or dhcp-interface may be defined"); + } + if (defined($dhcp_iface)){ + $dhcp_if = $dhcp_if + 1; + $lip = get_dhcp_addr($dhcp_iface); + } my $authid = $vcVPN->returnValue("ipsec site-to-site peer $peer authentication id"); my $authremoteid = $vcVPN->returnValue( "ipsec site-to-site peer $peer authentication remote-id"); - if ( !defined($lip) || $lip eq "" ) { - vpn_die(["vpn","ipsec","site-to-site","peer",$peer,"local-ip"],"$vpn_cfg_err No local-ip specified for peer \"$peer\"\n"); + if ( (!defined($lip) || $lip eq "") && (!defined($dhcp_iface) || $dhcp_iface eq "") ) { + vpn_die(["vpn","ipsec","site-to-site","peer",$peer,"local-ip"], + "$vpn_cfg_err No local-ip specified for peer \"$peer\"\n"); } elsif ( $lip ne '0.0.0.0' ) { # not '0.0.0.0' special case. @@ -478,6 +489,13 @@ if ( $vcVPN->exists('ipsec') ) { my $conn_head = "\nconn peer-$peer-tunnel-$tunnel\n"; $conn_head =~ s/ peer-@/ peer-/; $genout .= $conn_head; + + # Support for dhcp-interfaces + # The comment dhcp-interface will be used by the dhclient hook to do connection updates. + if (defined($dhcp_iface)){ + $genout .= "\t\#dhcp-interface=$dhcp_iface\n"; + $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 @@ -945,11 +963,16 @@ if ( $vcVPN->exists('ipsec') ) { # tag the secrets lines with 3 entries so the op mode command can # deal with them properly. (LEFT means localid, RIGHT means remoteid) if ((!defined($authid)) && (defined($authremoteid))) { - $genout_secrets .= ": PSK \"$psk\" #RIGHT#\n"; + $genout_secrets .= ": PSK \"$psk\" #RIGHT# "; } elsif ((defined($authid)) && (!defined($authremoteid))) { - $genout_secrets .= ": PSK \"$psk\" #LEFT#\n"; + $genout_secrets .= ": PSK \"$psk\" #LEFT# "; + } else { + $genout_secrets .= ": PSK \"$psk\" "; + } + if (defined($dhcp_iface)){ + $genout_secrets .= "#dhcp-interface=$dhcp_iface#\n"; } else { - $genout_secrets .= ": PSK \"$psk\"\n"; + $genout_secrets .= "\n"; } } $prev_peer = $peer; @@ -1094,14 +1117,14 @@ if ( $vcVPN->isDeleted('.') vpn_die(["vpn","ipsec"], "VPN commit error. Unable to re-enable ICMP redirects.\n"); } - write_config( $genout, $config_file, $genout_secrets, $secrets_file ); + write_config( $genout, $config_file, $genout_secrets, $secrets_file, $dhcp_if); } 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 ); + write_config( $genout, $config_file, $genout_secrets, $secrets_file, $dhcp_if ); # 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. @@ -1153,7 +1176,7 @@ sub vpn_die { exit 1; } sub write_config { - my ( $genout, $config_file, $genout_secrets, $secrets_file ) = @_; + my ( $genout, $config_file, $genout_secrets, $secrets_file, $dhcp_if ) = @_; open my $output_config, '>', $config_file or die "Can't open $config_file: $!"; @@ -1164,6 +1187,7 @@ sub write_config { or die "Can't open $secrets_file: $!"; print ${output_secrets} $genout_secrets; close $output_secrets; + dhcp_hook($dhcp_if); } sub vpn_exec { @@ -1348,5 +1372,31 @@ sub get_x509_secret { return $str; } +sub get_dhcp_addr { + my $dhcp_iface = pop(@_); + my @dhcp_addr = Vyatta::Misc::getIP($dhcp_iface,4); + my $addr = pop(@dhcp_addr); + @dhcp_addr = split(/\//, $addr); + $addr = $dhcp_addr[0]; + $addr = '0.0.0.0' if ($addr eq ''); + return $addr; +} + +sub dhcp_hook { + my $dhcp_iface = pop(@_); + my $str = ''; + if ($dhcp_iface > 0){ + $str =<<EOS; +#!/bin/sh +/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"; + open my $dhcp_hook, '>', $hook + or die "cannot open $hook"; + print ${dhcp_hook} $str; + close $dhcp_hook; +} + # end of file diff --git a/scripts/vyatta-ipsec-dhcp.pl b/scripts/vyatta-ipsec-dhcp.pl new file mode 100755 index 0000000..f20a65f --- /dev/null +++ b/scripts/vyatta-ipsec-dhcp.pl @@ -0,0 +1,92 @@ +#!/usr/bin/perl +use Getopt::Long; +use strict; + +my $config_file = "/etc/ipsec.conf"; +my $secrets_file = "/etc/ipsec.secrets"; +my ($iface, $config_iface, $nip, $oip, $reason); +GetOptions("interface=s" => \$iface, + "new_ip=s" => \$nip, + "old_ip=s" => \$oip, + "reason=s" => \$reason); + +# check if an update is needed +exit(0) if (($oip eq $nip) && ($reason ne "BOUND")); + +# open ipsec config +open (my $FD, '<', $config_file); +my $header = ''; +my $footer = ''; +my $finheader = 0; +my %connhash = (); +my $curconn = ''; +foreach my $line (<$FD>){ + next if (($line =~/^\s*$/) && $finheader); + if ($line =~ /\#conn.*/){ + $curconn = ''; + next; + } + if ($line =~ /(peer-.*-tunnel.*)/){ + $finheader = 1; + my $connid = $1; + $curconn = $connid; + if (not exists $connhash{$connid}){ + $connhash{$connid} = { + _dhcp_iface => undef, + _lip => undef, + _lines => [] + }; + } + } elsif (($line =~ /dhcp-interface=(.*)/) && ($curconn ne '') ){ + $connhash{$curconn}->{_dhcp_iface}=$1; + } elsif (($line =~ /left=(.*)/) && ($curconn ne '') ){ + $connhash{$curconn}->{_lip}=$1; + } elsif (!$finheader){ + $header .= $line; + } elsif ($curconn ne ''){ + push (@{$connhash{"$curconn"}->{_lines}}, $line); + } elsif ($curconn eq ''){ + $footer .= $line; + } +} +close($FD); + +# output new ipsec.conf +open my $output_config, '>', $config_file + or die "Can't open $config_file: $!"; + +print ${output_config} "$header\n"; +foreach my $connid ( keys (%connhash)){ + print ${output_config} "conn $connid\n"; + if (defined($connhash{$connid}->{_dhcp_iface})){ + if ($connhash{$connid}->{_dhcp_iface} eq $iface){ + $connhash{$connid}->{_lip} = $nip; + } + print ${output_config} "\t\#dhcp-interface=$connhash{$connid}->{_dhcp_iface}\n"; + } + print ${output_config} "\tleft=$connhash{$connid}->{_lip}\n"; + foreach my $line (@{$connhash{$connid}->{_lines}}){ + print ${output_config} $line; + } + print ${output_config} "\#conn $connid\n\n"; +} +print ${output_config} "$footer\n"; +close $output_config; + +# change ipsec.secrets +open (my $FD, '<', $secrets_file); +my @lines = <$FD>; +close FD; +open my $output_secrets, '>', $secrets_file + or die "Can't open $secrets_file"; +foreach my $line (@lines){ + if (($line =~ /\#dhcp-interface=(.*)\#/) && ($1 eq $iface)){ + $line =~ s/^$oip /$nip /; + if (!($line =~ /^oip/)){ + $line =~ s/^/$nip /; + } + } + print ${output_secrets} $line; +} +close $output_secrets; +system ("/usr/sbin/ipsec update"); 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 new file mode 100644 index 0000000..5297f5a --- /dev/null +++ b/templates/vpn/ipsec/site-to-site/peer/node.tag/dhcp-interface/node.def @@ -0,0 +1,7 @@ +type: txt +help: DHCP interface to listen on +allowed: + local -a array ; + array=( /var/lib/dhcp3/eth* /var/lib/dhcp3/br* ) ; + echo -n ${array[@]##*/} + |