#!/usr/bin/perl -T $version = '$Id: gencryptolists.pl,v 1.2 2005/07/01 08:20:44 torh Exp torh $ '; # # (c) torh@bogus.net 2005 # # generates access-lists for use with Cisco IOS crypto maps # # this version supports the following two topologies: # - full mesh # - hub and spoke (star) # # please note that the PEER keyword is not used in this version. # my(%PEERS); # hash of array containing each peer's networks use Getopt::Long; GetOptions("v","h","d", "t=s" => \$topology, "c=s" => \$config); if(!$config) { $config = "./domains.cfg"; } if($opt_v) { print "$0 (c) torh\@bogus.net 2005\n"; print $version,"\n"; exit(0); } if($opt_h) { print <] [-t ] -h : this stuff -v : print version -c : use alternate (default is '$config') -t : topology type (default is full mesh) -d : print to stdout only, don\'t write to file EOM exit(0); } if($topology =~ /star/i) { ReadConfig_HS($config); GenerateHS(); } else { ReadConfig_FM($config); GenerateFM(); } exit(0); # generatehs() - generates lists for a hub and spoke (star) network # # this means that if there are 3 networks, A, B and C, communication # is as such: # # 10.0.0.0/24 A --- B 172.16.0.0/24 # \ # \ # C 192.168.0.0/24 # # the current version does not produce access-lists which allow communication # between B and C via A (should be possible to use lists generated for full # mesh) # # the following lists must exist # # ip access-list extended HUB-SITE-A # permit ip 10.0.0.0 0.0.0.255 172.16.0.0 0.0.0.255 # permit ip 10.0.0.0 0.0.0.255 192.168.0.0 0.0.0.255 # # ip access-list extended SPOKE-SITE-B # permit ip 172.16.0.0 0.0.0.255 10.0.0.0 0.0.0.255 # # ip access-list extended SPOKE-SITE-C # permit ip 192.168.0.0 0.0.0.255 10.0.0.0 0.0.0.255 # sub GenerateHS { my($siteA,$siteB,$soure,$aclA,$aclB,$type); foreach $siteA (sort keys %PEERS) { if($HUB{$siteA}) { $type="HUB"; } else { $type="SPOKE"; } open(OUT,">$siteA-$type-conf.txt") unless ($opt_d); PrintConfig($siteA); print "ip access-list extended $type-CRYPTO-".$siteA."\n"; print OUT "ip access-list extended $type-CRYPTO-".$siteA."\n" unless($opt_d); foreach $siteB (sort keys %PEERS) { next if($siteA eq $siteB); print " ! from ".lc($siteA." to ".$siteB),"\n" if ($HUB{$siteB}); print OUT " ! from ".lc($siteA." to ".$siteB),"\n" if($HUB{$siteB}); if($HUB{$siteA}) { foreach $aclA (@{$PEERS{$siteA}}) { my($src_net); next if($siteA =~ /PEER/i); if($aclA =~ /^\s*[\+|\-]\s*(.*)/) { $src_net = $1; } foreach $aclB (@{$PEERS{$siteB}}) { my($dst_net,$tmp_net); next if($siteB =~ /PEER/i); if($aclB =~ /^\s*[\+|\-]\s*(.*)/) { $tmp_net = $1; } if($aclB =~ /^\s*\+.*/ && $aclA =~ /^\s*\+.*/) { $access_expr=" permit ip"; $dst_net = $tmp_net; } if($aclB =~ /^\s*\-.*/ || $aclA =~ /^\s*\-.*/) { $access_expr=" deny ip"; $dst_net = $tmp_net; } if($src_net && $dst_net) { print " $access_expr $src_net $dst_net\n"; print OUT " $access_expr $src_net $dst_net\n"; } } } } else { foreach $aclA (@{$PEERS{$siteA}}) { my($src_net); next if($siteA =~ /PEER/i); if($aclA =~ /^\s*[\+|\-]\s*(.*)/) { $src_net = $1; } foreach $aclB (@{$PEERS{$siteB}}) { next unless $HUB{$siteB}; my($dst_net,$tmp_net); next if($siteB =~ /PEER/i); if($aclB =~ /^\s*[\+|\-]\s*(.*)/) { $tmp_net = $1; } if($aclB =~ /^\s*\+.*/ && $aclA =~ /^\s*\+.*/) { $access_expr=" permit ip"; $dst_net = $tmp_net; } if($aclB =~ /^\s*\-.*/ || $aclA =~ /^\s*\-.*/) { $access_expr=" deny ip"; $dst_net = $tmp_net; } if($src_net && $dst_net) { print " $access_expr $src_net $dst_net\n"; print OUT " $access_expr $src_net $dst_net\n"; } } } } } print "\n"; close(OUT) unless ($opt_d); } } # generatefm() - generates list for fully meshed network # # for the following 3 networks to communicate, # # 10.0.0.0/24 A --- B 172.16.0.0/24 # \ / # \ / # C # 192.168.0.0/24 # # the following lists must exist # # ip access-list extended SITE-A # permit ip 10.0.0.0 0.0.0.255 172.16.0.0 0.0.0.255 # permit ip 10.0.0.0 0.0.0.255 192.168.0.0 0.0.0.255 # # ip access-list extended SITE-B # permit ip 172.16.0.0 0.0.0.255 10.0.0.0 0.0.0.255 # permit ip 172.16.0.0 0.0.0.255 192.168.0.0 0.0.0.255 # # ip access-list extended SITE-C # permit ip 192.168.0.0 0.0.0.255 10.0.0.0 0.0.0.255 # permit ip 192.168.0.0 0.0.0.255 172.16.0.0 0.0.0.255 # # this becomes a configuration nightmare as the topology grows, hence # the reason i wrote this code! :-} sub GenerateFM { my($siteA,$siteB,$soure,$aclA,$aclB); foreach $siteA (sort keys %PEERS) { open(OUT,">$siteA-conf.txt") unless ($opt_d); PrintConfig($siteA) unless ($opt_d); print "ip access-list extended CRYPTO-".$siteA."\n"; print OUT "ip access-list extended CRYPTO-".$siteA."\n" unless ($opt_d); foreach $siteB (sort keys %PEERS) { next if($siteA eq $siteB); print " ! from ".lc($siteA." to ".$siteB),"\n"; print OUT " ! from ".lc($siteA." to ".$siteB),"\n"; foreach $aclA (@{$PEERS{$siteA}}) { my($src_net); next if($siteA =~ /PEER|HUB|SPOKE/i); if($aclA =~ /^\s*[\+|\-]\s*(.*)/) { $src_net = $1; } foreach $aclB (@{$PEERS{$siteB}}) { my($dst_net,$tmp_net); next if($siteB =~ /PEER|HUB|SPOKE/i); if($aclB =~ /^\s*[\+|\-]\s*(.*)/) { $tmp_net = $1; } if($aclB =~ /^\s*\+.*/ && $aclA =~ /^\s*\+.*/) { $access_expr=" permit ip"; $dst_net = $tmp_net; } if($aclB =~ /^\s*\-.*/ || $aclA =~ /^\s*\-.*/) { $access_expr=" deny ip"; $dst_net = $tmp_net; } if($src_net && $dst_net) { print " $access_expr $src_net $dst_net\n"; print OUT " $access_expr $src_net $dst_net\n"; } } } } print "\n"; close(OUT) unless ($opt_d); } } sub PrintConfig { my($s) = @_; print "! SITE: $s\n"; print "! FILE: $s-conf.txt\n"; foreach $cfg (@{$PEERS{$s}}) { print "! $cfg\n"; } print "!\n"; } sub ReadConfig_FM { my($c) = @_; die "STOP. Can't read config file '$c'.\n" unless (-r $c); my($br)=0; # brace counter my($peer); # current peer open(IN,$c); # read in the encryption domain's configuration file # peer network groups should be defined as follows (for full mesh): # # please note that the peer keyword is currently unused. the IP addresses # used are purely fictional. # # Oslo-Ulven { # peer 193.214.208.184 # + 192.168.0.0 0.0.0.255 ; /24 development servers # + 192.168.16.0 0.0.0.1.255 ; /23 desktop pc's # } # # Oslo-Gronland { # peer 218.212.15.53 # + host 172.16.0.1 ; loner in the arse end of oslo # } # # London-City { # peer 80.102.43.2 # + 10.0.0.0 0.0.0.255 ; it helpdesk # - host 10.0.0.16 ; this provides remote access (static nat) # } while () { chomp($_); next if(/^\s*$/); # skip blank lines $br++ if(/\{/); die "STOP. Open brace mismatch in '$c'.\n" if ($br>1); $br-- if(/\}/); die "STOP. Closing brace mismatch in '$c'.\n" if ($br<0); if (/(\S+)\s+\{/) { my($match); $peer=$1; while($peer =~ /\G[A-Z0-9_\+\-]/gi) { $match++; } die "STOP. Site names gives me indigestion (alphanumeric, + and - only please).\n" if(length($peer)!=$match); } if($br) { die "STOP. No peer defined - this should never happen!\n" if(!$peer); if(/^\s*((PEER\s+\d+\.\d+\.\d+\.\d+[(\s+\S+)]*)|((\+|\-)\s+(host|\d+\.\d+\.\d+\.\d+)\s+\d+\.\d+\.\d+\.\d+))/i) { my(@tmp)=@{$PEERS{$peer}}; push(@tmp,$1); @{$PEERS{$peer}}=@tmp; } } } close(IN); } sub ReadConfig_HS { my($c) = @_; die "STOP. Can't read config file '$c'.\n" unless (-r $c); my($br)=0; # brace counter my($peer); # current peer open(IN,$c); # for hub-spoke configuration, the config file is thus: # # HUB NO-Oslo { # PEER 172.16.0.1 ; NO-Oslo router's external address # - host 10.0.0.128 ; remote login box, don't match packets to this IP # + 10.0.0.0 0.0.1.255 ; /23 for internal dhcp hosts # + 10.0.8.0 0.0.0.255 ; /24 used for servers # # SPOKE NO-Stavanger { # PEER 172.16.0.10 ; NO-Stavanger router's external address # - host 192.168.10.16 ; remote login box # + 192.168.10.0 0.0.0.255 ; internal /24 # } # } while () { chomp($_); next if(/^\s*$/); # skip blank lines $br++ if(/\{/); die "STOP. Open brace mismatch in '$c'.\n" if (($br>1 && !$peer) || $br>2); # dirty $br-- if(/\}/); die "STOP. Closing brace mismatch in '$c'.\n" if ($br<0); # dirty if (/(\S+)\s+\{/) { my($match); $peer=$1; while($peer =~ /\G[A-Z0-9_\+\-]/gi) { $match++; } die "STOP. Site names gives me indigestion (alphanumeric, + and - only please).\n" if(length($peer)!=$match); } $HUB{$peer}=1 if(/HUB/i && $peer); $HUB{$peer}=0 if(/SPOKE/i && $peer); if($br) { die "STOP. No peer defined - this should never happen!\n" if(!$peer); if(/^\s*((PEER\s+\d+\.\d+\.\d+\.\d+[(\s+\S+)]*)|((\+|\-)\s+(host|\d+\.\d+\.\d+\.\d+)\s+\d+\.\d+\.\d+\.\d+))/i) { my(@tmp)=@{$PEERS{$peer}}; push(@tmp,$1); @{$PEERS{$peer}}=@tmp; } } } close(IN); } # end #