| 1 | #!/usr/bin/perl |
| 2 | # udptunnel-reconf |
| 3 | # Set up the relevant stuff in /etc/userv/vpn, and then run |
| 4 | # this. It should tell you what to do to inittab and ipif-networks. |
| 5 | |
| 6 | # This file is part of ipif, part of userv-utils |
| 7 | # |
| 8 | # Copyright 1996-2013 Ian Jackson <ijackson@chiark.greenend.org.uk> |
| 9 | # Copyright 1998 David Damerell <damerell@chiark.greenend.org.uk> |
| 10 | # Copyright 1999,2003 |
| 11 | # Chancellor Masters and Scholars of the University of Cambridge |
| 12 | # Copyright 2010 Tony Finch <fanf@dotat.at> |
| 13 | # |
| 14 | # This is free software; you can redistribute it and/or modify it |
| 15 | # under the terms of the GNU General Public License as published by |
| 16 | # the Free Software Foundation; either version 3 of the License, or |
| 17 | # (at your option) any later version. |
| 18 | # |
| 19 | # This program is distributed in the hope that it will be useful, but |
| 20 | # WITHOUT ANY WARRANTY; without even the implied warranty of |
| 21 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 22 | # General Public License for more details. |
| 23 | # |
| 24 | # You should have received a copy of the GNU General Public License |
| 25 | # along with userv-utils; if not, see http://www.gnu.org/licenses/. |
| 26 | |
| 27 | use Socket; |
| 28 | |
| 29 | # @@@- |
| 30 | $shareuserv= "`pwd`"; |
| 31 | $etcvpn= "`pwd`"; |
| 32 | $varlibvpn= "`pwd`"; |
| 33 | # -@@@ |
| 34 | |
| 35 | sub badusage () { die "usage: udptunnel-reconf [<directory>]\n"; } |
| 36 | $debug=0; |
| 37 | |
| 38 | sub fault ($) { die "$0: $_[0]\n"; } |
| 39 | |
| 40 | while ($ARGV[0] =~ m/^-/) { |
| 41 | $_= shift @ARGV; |
| 42 | last if m/^--$/; |
| 43 | if (m/^-d$/) { $debug++; next; } |
| 44 | badusage(); |
| 45 | } |
| 46 | |
| 47 | if (@ARGV) { $etcvpn= shift @ARGV; } |
| 48 | badusage() if @ARGV; |
| 49 | |
| 50 | chdir $etcvpn or fault("$etcvpn: $!"); |
| 51 | |
| 52 | sub run_m4 ($$$) { |
| 53 | my ($wanted, $site, $variable) = @_; |
| 54 | $x= "m4 -P -DWANTED=$wanted -DWHVARIABLE=V_$variable -DV_global=global ". |
| 55 | "-DV_site=$site -DV_varlibvpn=$varlibvpn ". |
| 56 | "-DV_defaults=$shareuserv/udptunnel-vpn-defaults ". |
| 57 | "$shareuserv/udptunnel-vpn-config.m4"; |
| 58 | print STDERR $x,"\n" if $debug>=2; |
| 59 | open X, "$x |" or die $!; |
| 60 | undef $/; |
| 61 | $m4out= <X>; |
| 62 | $/= "\n"; |
| 63 | $!=0; close X; $? and die "m4 failed with code $? $!"; |
| 64 | $m4out =~ s/^\s+//; |
| 65 | $m4out =~ s/\n+/\n/g; |
| 66 | $m4out =~ s/\s+$//; |
| 67 | print STDERR "$wanted/$variable($site) -> \`$m4out'\n" if $debug>=1; |
| 68 | # $m4out='' if $wanted eq 'VARIABLE' && substr($m4out,0,2) eq 'V_'; |
| 69 | return $m4out; |
| 70 | } |
| 71 | |
| 72 | sub check_junk ($$) { |
| 73 | my ($emsg, $site) = @_; |
| 74 | $j= run_m4('JUNK',$site,''); |
| 75 | $j =~ s/^\# //g; |
| 76 | fault("$emsg: $j") if length $j; |
| 77 | } |
| 78 | |
| 79 | sub var_global ($) { return run_m4('VARIABLE','',$_[0]) } |
| 80 | sub var_site ($) { return run_m4('VARIABLE',$site,$_[0]) } |
| 81 | |
| 82 | check_junk("error in config",''); |
| 83 | |
| 84 | @actives= split /\s+/, run_m4('ACTIVES','',''); |
| 85 | @passives= split /\s+/, run_m4('PASSIVES','',''); |
| 86 | |
| 87 | foreach $site (@actives, @passives) { |
| 88 | check_junk("error in config for site $site",$site); |
| 89 | } |
| 90 | |
| 91 | sub parse_addr_mask ($) { |
| 92 | my ($r) = @_; |
| 93 | my ($mask,$iaddr); |
| 94 | if ($r =~ s,/(\d+)$,,) { $mask=$1; } else { $mask=32; } |
| 95 | fault("invalid mask length $1") if $mask<0 || $mask>32; |
| 96 | $mask= $mask ? ~0 << (32-$mask) : 0; |
| 97 | $iaddr= inet_aton($r); fault("invalid address $r") unless defined $iaddr; |
| 98 | $iaddr= (unpack "N",$iaddr)[0]; |
| 99 | return ($iaddr, $mask); |
| 100 | } |
| 101 | |
| 102 | sub ipif_permit ($$$$) { |
| 103 | my ($group,$local,$net,$why) = @_; |
| 104 | my ($pmask,$piaddr,$fmask,$fiaddr,@lgroup,$lgid); |
| 105 | |
| 106 | @lgroup= getgrnam($group); |
| 107 | @lgroup or fault("invalid group \`$group' ($why)"); |
| 108 | $lgid= $lgroup[2]; |
| 109 | |
| 110 | if (!$local) { |
| 111 | ($piaddr,$pmask) = parse_addr_mask($net); |
| 112 | foreach $fref (@forbid_remote) { |
| 113 | ($fiaddr,$fmask) = @$fref; |
| 114 | $jmask= $fmask & $pmask; |
| 115 | #printf STDERR "%8lx %8lx %l8x %8lx", $pmask,$pmask |
| 116 | fault("local network $net claimed as remote ($why)") |
| 117 | if (($fiaddr&$jmask) == ($piaddr&$jmask)); |
| 118 | } |
| 119 | } |
| 120 | $ipif_file .= "$lgid,$local$net, $group, $why\n"; |
| 121 | } |
| 122 | |
| 123 | $glgroup= var_global('lgroup'); |
| 124 | $glend= var_site('lend')."/32"; |
| 125 | if ($glend !~ m/^V_/ && $glgroup !~ m/^V_/ && |
| 126 | length $glend && length $glgroup) { |
| 127 | ipif_permit($glgroup, '=', "$glend", 'local endpoint'); |
| 128 | } else { |
| 129 | $glend='X'; $glgroup='X'; |
| 130 | } |
| 131 | |
| 132 | foreach $site (@actives, @passives) { |
| 133 | $forbid_remote= var_site('forbid_remote'); |
| 134 | @forbid_remote= (); |
| 135 | if ($forbid_remote ne '-') { |
| 136 | foreach $r (split /[, \t]+/, $forbid_remote) { |
| 137 | push @forbid_remote, [ parse_addr_mask($r) ]; |
| 138 | } |
| 139 | } |
| 140 | |
| 141 | $tlend= var_site('lend')."/32"; |
| 142 | $tlgroup= var_site('lgroup'); |
| 143 | if ($tlend ne $glend || $tlgroup ne $glgroup) { |
| 144 | ipif_permit($tlgroup, '=', $tlend, "$site - local endpoint"); |
| 145 | } |
| 146 | $trend= var_site('rend').'/32'; |
| 147 | $ix= 0; |
| 148 | $trnets= var_site('rnets'); |
| 149 | ipif_permit($tlgroup, '', $trend, "$site - remote endpoint"); |
| 150 | if ($trnets ne '-') { |
| 151 | foreach $rnet (split /,/, $trnets) { |
| 152 | ipif_permit($tlgroup, '', $rnet, "$site - remote network #$ix"); |
| 153 | $ix++; |
| 154 | } |
| 155 | } |
| 156 | } |
| 157 | |
| 158 | sub write_file ($$$$) { |
| 159 | my ($fn,$why,$head,$body) = @_; |
| 160 | length $fn or fault("location to write $why not specified"); |
| 161 | open F, ">$fn.new" or fault("create $fn.new: $!"); |
| 162 | print F $head."\n# AUTOGENERATED BY $0 - DO NOT EDIT\n".$body or die $!; |
| 163 | close F or die $!; |
| 164 | rename "$fn.new",$fn or die $!; |
| 165 | } |
| 166 | |
| 167 | $ipifnetsfile= var_global(ipifnetsfile); |
| 168 | write_file($ipifnetsfile,'ipifnetsfile','', $ipif_file); |
| 169 | |
| 170 | $active_file= ''; |
| 171 | $knownhosts_file= ''; |
| 172 | $inittab= ''; |
| 173 | $ix= 0; |
| 174 | foreach $site (@actives) { |
| 175 | $active_file.= "$site\t".var_site('activesxinfo')."\n"; |
| 176 | $inittab.= sprintf("t%d", $ix++).':'.var_site('inittab_line')."\n"; |
| 177 | $hostkey= var_site('rhostkey'); |
| 178 | $knownhosts_file.= var_site('sshdest').' '.$hostkey."\n" |
| 179 | if length $hostkey; |
| 180 | $invoke_file= var_site('invoke_file'); |
| 181 | write_file($invoke_file, 'invoke_file', |
| 182 | var_site('invoke_head')."\n", var_site('invoke_body')); |
| 183 | chmod 0777&~umask, $invoke_file or die $!; |
| 184 | } |
| 185 | write_file(var_global('knownhostsfile'),'knownhostsfile', '',$knownhosts_file); |
| 186 | write_file(var_global('activesfile'),'activesfile', '',$active_file); |
| 187 | |
| 188 | print |
| 189 | "# You can cut and paste all or part of this into your inittab if you like:\n", |
| 190 | $inittab; |
| 191 | |
| 192 | print |
| 193 | "# And consider adding this line, or some of this file's contents,\n". |
| 194 | "# to your /etc/userv/ipif-networks:\n", |
| 195 | "$ipifnetsfile\n" |
| 196 | if $ipifnetsfile =~ m,^/,; |
| 197 | |
| 198 | $passive_file= ''; |
| 199 | foreach $site (@passives) { |
| 200 | $passive_file.= "$site\t".var_site('passivesxinfo')."\n"; |
| 201 | } |
| 202 | write_file(var_global('passivesfile'),'passivesfile', '',$passive_file); |
| 203 | |
| 204 | system var_global('postconfigure'); $? and exit -1; |
| 205 | |
| 206 | exit 0; |