#!/usr/bin/perl # udptunnel-reconf # Set up the relevant stuff in /etc/userv/vpn, and then run # this. It should tell you what to do to inittab and ipif-networks. # This file is part of ipif, part of userv-utils # # Copyright 1996-2013 Ian Jackson # Copyright 1998 David Damerell # Copyright 1999,2003 # Chancellor Masters and Scholars of the University of Cambridge # Copyright 2010 Tony Finch # # This is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with userv-utils; if not, see http://www.gnu.org/licenses/. use Socket; # @@@- $shareuserv= "`pwd`"; $etcvpn= "`pwd`"; $varlibvpn= "`pwd`"; # -@@@ sub badusage () { die "usage: udptunnel-reconf []\n"; } $debug=0; sub fault ($) { die "$0: $_[0]\n"; } while ($ARGV[0] =~ m/^-/) { $_= shift @ARGV; last if m/^--$/; if (m/^-d$/) { $debug++; next; } badusage(); } if (@ARGV) { $etcvpn= shift @ARGV; } badusage() if @ARGV; chdir $etcvpn or fault("$etcvpn: $!"); sub run_m4 ($$$) { my ($wanted, $site, $variable) = @_; $x= "m4 -P -DWANTED=$wanted -DWHVARIABLE=V_$variable -DV_global=global ". "-DV_site=$site -DV_varlibvpn=$varlibvpn ". "-DV_defaults=$shareuserv/udptunnel-vpn-defaults ". "$shareuserv/udptunnel-vpn-config.m4"; print STDERR $x,"\n" if $debug>=2; open X, "$x |" or die $!; undef $/; $m4out= ; $/= "\n"; $!=0; close X; $? and die "m4 failed with code $? $!"; $m4out =~ s/^\s+//; $m4out =~ s/\n+/\n/g; $m4out =~ s/\s+$//; print STDERR "$wanted/$variable($site) -> \`$m4out'\n" if $debug>=1; # $m4out='' if $wanted eq 'VARIABLE' && substr($m4out,0,2) eq 'V_'; return $m4out; } sub check_junk ($$) { my ($emsg, $site) = @_; $j= run_m4('JUNK',$site,''); $j =~ s/^\# //g; fault("$emsg: $j") if length $j; } sub var_global ($) { return run_m4('VARIABLE','',$_[0]) } sub var_site ($) { return run_m4('VARIABLE',$site,$_[0]) } check_junk("error in config",''); @actives= split /\s+/, run_m4('ACTIVES','',''); @passives= split /\s+/, run_m4('PASSIVES','',''); foreach $site (@actives, @passives) { check_junk("error in config for site $site",$site); } sub parse_addr_mask ($) { my ($r) = @_; my ($mask,$iaddr); if ($r =~ s,/(\d+)$,,) { $mask=$1; } else { $mask=32; } fault("invalid mask length $1") if $mask<0 || $mask>32; $mask= $mask ? ~0 << (32-$mask) : 0; $iaddr= inet_aton($r); fault("invalid address $r") unless defined $iaddr; $iaddr= (unpack "N",$iaddr)[0]; return ($iaddr, $mask); } sub ipif_permit ($$$$) { my ($group,$local,$net,$why) = @_; my ($pmask,$piaddr,$fmask,$fiaddr,@lgroup,$lgid); @lgroup= getgrnam($group); @lgroup or fault("invalid group \`$group' ($why)"); $lgid= $lgroup[2]; if (!$local) { ($piaddr,$pmask) = parse_addr_mask($net); foreach $fref (@forbid_remote) { ($fiaddr,$fmask) = @$fref; $jmask= $fmask & $pmask; #printf STDERR "%8lx %8lx %l8x %8lx", $pmask,$pmask fault("local network $net claimed as remote ($why)") if (($fiaddr&$jmask) == ($piaddr&$jmask)); } } $ipif_file .= "$lgid,$local$net, $group, $why\n"; } $glgroup= var_global('lgroup'); $glend= var_site('lend')."/32"; if ($glend !~ m/^V_/ && $glgroup !~ m/^V_/ && length $glend && length $glgroup) { ipif_permit($glgroup, '=', "$glend", 'local endpoint'); } else { $glend='X'; $glgroup='X'; } foreach $site (@actives, @passives) { $forbid_remote= var_site('forbid_remote'); @forbid_remote= (); if ($forbid_remote ne '-') { foreach $r (split /[, \t]+/, $forbid_remote) { push @forbid_remote, [ parse_addr_mask($r) ]; } } $tlend= var_site('lend')."/32"; $tlgroup= var_site('lgroup'); if ($tlend ne $glend || $tlgroup ne $glgroup) { ipif_permit($tlgroup, '=', $tlend, "$site - local endpoint"); } $trend= var_site('rend').'/32'; $ix= 0; $trnets= var_site('rnets'); ipif_permit($tlgroup, '', $trend, "$site - remote endpoint"); if ($trnets ne '-') { foreach $rnet (split /,/, $trnets) { ipif_permit($tlgroup, '', $rnet, "$site - remote network #$ix"); $ix++; } } } sub write_file ($$$$) { my ($fn,$why,$head,$body) = @_; length $fn or fault("location to write $why not specified"); open F, ">$fn.new" or fault("create $fn.new: $!"); print F $head."\n# AUTOGENERATED BY $0 - DO NOT EDIT\n".$body or die $!; close F or die $!; rename "$fn.new",$fn or die $!; } $ipifnetsfile= var_global(ipifnetsfile); write_file($ipifnetsfile,'ipifnetsfile','', $ipif_file); $active_file= ''; $knownhosts_file= ''; $inittab= ''; $ix= 0; foreach $site (@actives) { $active_file.= "$site\t".var_site('activesxinfo')."\n"; $inittab.= sprintf("t%d", $ix++).':'.var_site('inittab_line')."\n"; $hostkey= var_site('rhostkey'); $knownhosts_file.= var_site('sshdest').' '.$hostkey."\n" if length $hostkey; $invoke_file= var_site('invoke_file'); write_file($invoke_file, 'invoke_file', var_site('invoke_head')."\n", var_site('invoke_body')); chmod 0777&~umask, $invoke_file or die $!; } write_file(var_global('knownhostsfile'),'knownhostsfile', '',$knownhosts_file); write_file(var_global('activesfile'),'activesfile', '',$active_file); print "# You can cut and paste all or part of this into your inittab if you like:\n", $inittab; print "# And consider adding this line, or some of this file's contents,\n". "# to your /etc/userv/ipif-networks:\n", "$ipifnetsfile\n" if $ipifnetsfile =~ m,^/,; $passive_file= ''; foreach $site (@passives) { $passive_file.= "$site\t".var_site('passivesxinfo')."\n"; } write_file(var_global('passivesfile'),'passivesfile', '',$passive_file); system var_global('postconfigure'); $? and exit -1; exit 0;