#!/usr/bin/perl ##################################### # This script is distributed on the understanding # that if you make improvements you will return # them to the community of Perl and Mac users. This # is pint-ware -- if you find it particularly useful # a thank you pint would be appreciated but is not # required. # # For more information visit http://www.reades.com/ # # Please note that I *cannot* offer support on VPN # configuration from the systems side -- not only # is each and every VPN different but, frankly, I do # not know enough about how they work to be of any # use. # # Enjoy, # jon reades #################################### BEGIN { # Normally, you will want to # keep your script and files # here. push @INC, "/etc/racoon"; } use Cwd; use strict; use Templates; # The default profile my $profile = "./Profiles.pm"; # Assume that you should use # the current working directory # unless one is specified in the # command-line args my $dir = getcwd; my $to_do; unless (@ARGV) { print STDOUT "Usage:\n"; print STDOUT "\tperl setup.pl [dir=/path/to/output/files] [profile=/path/to/profile.txt] config|restart|all\n"; print STDOUT "\tDefault profile is in ./Profile.pm\n"; print STDOUT "\tDefault output directory is cwd ($dir)\n"; exit 0; } foreach(@ARGV) { my ($key, $val) = split /=/; # Override the profile $profile = $val if ($key eq 'profile'); # Override the output directory $dir = $val if ($key eq 'dir'); # What to do? $to_do = "configure" if ($key eq 'config'); $to_do = "restart" if ($key eq 'restart'); $to_do = "all" if ($key eq 'all'); } # Are we generating a config file? if ($to_do eq 'all' || $to_do eq 'configure') { print STDOUT "\nFiles will be output to $dir\n"; generateConfig($profile, $dir); } # Are we restarting racoon and setting the tunnels? if ($to_do eq 'all' || $to_do eq 'restart') { print STDOUT "\nLooking for configuration files in $dir\n"; restartRacoon($dir); } exit 0; # Reads in the profile file and splits # it based on a key => val syntax sub parseProfile { my $profile = shift; my %lookup; # We slurp it in so that we can # properly handle arrays and hashes # spread across multiple lines of # the profile file my $delimiter = $/; $/ = undef; open (PROFILE, "<$profile") or die ("Couldn't open profile ($profile) to read: $!"); my $slurp = ; close PROFILE; my (@params) = split /\;/, $slurp; foreach my $param (@params) { # Remove any comments $param =~ s|^\#.*?$||gm; # Parse out the parameter my ($key, $val) = parseParam($param); # And assign it to the lookup # hash for interpolation $lookup{$key} = $val if ($key); } $/ = $delimiter; return \%lookup; } sub parseParam { my $param = shift; # We're assuming that everything # after the '=>' is part of the value my ($key, $val) = $param =~ m/(\S+)\s+=>\s+(.*)$/s; # This 'vivifies' the # hash or array my $ref = eval ($val); return $key, $ref; } sub interpolate { my $string = shift; my $lookup = shift; $string =~ s/@@([^@]+)@@/$lookup->{$1}/g; return $string; } sub generateConfig { my $profile = shift; my $dir = shift; my %lookup = %{parseProfile($profile)}; # Look for a recognisable IP address # on the interface specified in # the profile file my $match; open (IP, "/sbin/ifconfig |") or die ("Couldn't open pipe (/sbin/ifconfig) to read: $!"); while () { $match = 'found' if ($_ =~ m|$lookup{INTERFACE}|); next if ($match ne 'found'); if ($_ =~ m|inet (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})|) { $lookup{client_ip} = $1; last; } } $lookup{client_ip} = $lookup{CLIENT_IP} unless ($lookup{client_ip}); close IP; print STDOUT "\nSetting up racoon on " . $lookup{INTERFACE} . " : " . $lookup{client_ip} . "\n\n"; if ($lookup{client_ip} eq '169.254.0.1') { print STDOUT "Warning: you don't appear to have properly configured the interface\n"; print STDOUT "It is higly unlikely that you really want to run racoon on " . $lookup{client_ip} . "\n"; print STDOUT "Try checking the INTERFACE parameter in $profile\n"; print STDOUT "or setting the CLIENT_IP parameter to your machine's IP.\n"; exit 0; } ############################ # Set up the tunnels to be # run via a shell script ############################ my $tunnels = ""; print STDOUT "Setting up tunnels on " . $lookup{INTERFACE} . "\n"; foreach my $profile (@{$lookup{PROFILES}}) { print STDOUT "\tSetting up profile: " . $profile->{NAME} . "\n"; $lookup{server_ip} = $profile->{SERVER_IP}; foreach my $network (@{$profile->{NETWORKS}}) { $lookup{network} = $network; $tunnels .= interpolate(TUNNEL_TMPL, \%lookup); print STDOUT "\t\tSetting up subnet: " . $network . "\n"; } } $lookup{tunnels} = $tunnels; open (OUT, ">$dir/interface.sh") or die ("Couldn't open $dir/interface.sh to write: $!"); print OUT interpolate(SCRIPT_TMPL, \%lookup); close OUT; print STDOUT "\nTunnel script (interface.sh) complete.\n"; print STDOUT "Next time you can just run 'sudo ${dir}interface.sh'.\n\n"; ############################ # Set up the SAInfo section # of the racoon.conf file ############################ my $sainfo = ""; print STDOUT "Setting up SAInfo section for racoon.conf\n"; foreach my $profile (@{$lookup{PROFILES}}) { print STDOUT "\tSetting up profile: " . $profile->{NAME} . "\n"; foreach my $network (@{$profile->{NETWORKS}}) { $lookup{network} = $network; $sainfo .= interpolate(SAINFO_TMPL, \%lookup); } } $lookup{sainfo} = $sainfo; ############################ # Set up the remote servers section # of the racoon.conf file ############################ my $remote = ""; print STDOUT "Setting up Remote Server section for racoon.conf\n"; foreach my $profile (@{$lookup{PROFILES}}) { print STDOUT "\tSetting up profile: " . $profile->{NAME} . "\n"; foreach (keys %$profile) { $lookup{$_} = $profile->{$_}; } $remote .= interpolate(REMOTE_SERVER_TMPL, \%lookup); } $lookup{remote} = $remote; ############################ # Set up the racoon.conf file ############################ print STDOUT "Setting up racoon.conf\n"; open (OUT, ">$dir/racoon.conf") or die ("Couldn't open $dir/racoon.conf to write: $!"); print OUT interpolate(RACOON_TMPL, \%lookup); close OUT; print STDOUT "\nRacoon setup (racoon.conf) complete.\n"; print STDOUT "Next time you can just run: 'sudo racoon -f ${dir}racoon.conf'.\n\n"; print STDOUT "Setup complete\n"; return; } sub restartRacoon { my $dir = shift; print STDOUT "\nRestarting\n"; my $retval1 = system('sudo', 'killall', 'racoon'); if ($retval1) { print STDOUT "Couldn't kill any running racoon processes: $retval1\n"; } my $retval2 = system ('sudo', '/bin/sh', $dir . '/interface.sh'); if ($retval2) { print STDOUT "Couldn't run interface.sh: $retval2\n"; } my $retval3 = system ('sudo', '/usr/sbin/racoon', '-f', $dir . '/racoon.conf'); if ($retval3) { print "Couldn't start racoon: $retval3\n"; } if (!($retval1 || $retval2 || $retval3)) { print STDOUT "Restart complete\n"; } else { print STDOUT "May not have restarted cleanly\n"; } return; }