#!/usr/bin/perl -w # $Id: dhcpbyport,v 1.3 2006/06/13 14:24:03 facq Exp $ # DhcpByPort v0.2 # # (c) 2006 Laurent Facq (facq@u-bordeaux.fr) - Pierre Leonard # # V0.2 Laurent Facq # V0.1 Pierre Leonard # # # This program 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 2 # 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 this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # TODO : PORTRANGE ou PORT 1 3-10 $ replaced -> like GENERATE /BIND # TODO : check descriptio content (no ?! char.) => allowed char instead # TODO : line command option -d --debug verbose ? # TODO? : PORTCONFTEMPLATE ? string where %ip %port %module ... are replaced %h_port port in hex, ... ou eval "cash" # TODO? : PORTCONF port conf in conf.(ex: no cdp ena) => one line with \n ? # TODO : check all, write after ! - or add a check flag (-n) ? # TODO : support ip range in the for ip1-ip2 $debug= 0; $verbose= 0; #lecture du fichier while ($l=<>) { $l =~ s/^\s*//; #remove heading blanks if ($l =~ /^\#/ ) { next; } #skip comments if ($l =~ /^$/ ) { next; } #skip blank lines if ($debug) { print $l; } # DEBUG if ($l =~ /^DEBUG/) { $debug= 1; next; } # VEROSE if ($l =~ /^VERBOSE/) { $verbose= 1; next; } # ROOT if ($l =~ /^ROOT /) { @root = split('\s+',$l); $root = $root[1]; $root =~ s|/*$||g; $root.="/"; # normalize $root with one slash at the end $rootclasses = $root."classes.conf"; if ($#root != 1) {print STDERR "ERROR: Bad ROOT path - $l\n";exit 1;} open (CLASSES,">$rootclasses") || die "Cannot open $rootclasses : $!"; next; } # NETWORK if ($l =~ /^NETWORK /) { @network = split('\s+',$l); $network = $network[1]; if ($#network != 1) {print STDERR "ERROR: Bad NETWORK name - $l\n";exit 1;} open (SUBNET,">$root$network.conf") || die "Cannnot open NETWORK file : $!"; print STDERR "-- Writing into $root$network.conf (NETWORK)\n" if ($verbose); next; } # SWITCH [] # mac = Base ethernet MAC Address: ... if ($l =~ /^SWITCH /) { $l =~ s/\s+$//; #supprime les blancs en fin de ligne @switch = split('\s+',$l,4); $switch_name = $switch[1]; if ($#switch==-1 || $#switch>2) {print STDERR "ERROR: Bad SWITCH command - $l\n";exit 1;} open (SWITCH,">$root$switch_name.conf") || die "Pb d'ouverture de \'$switch_name.conf\': $!"; print STDERR "-- Writing into $root$switch_name.conf (SWITCH)\n" if ($verbose); $mac = $switch[2]; if ($#switch == 2) {$switch_type = "cisco";} # default type : cisco else {$switch_type = $switch[3];} next; } # VLAN if ($l =~ /^VLAN/) { @vlan = split('\s+',$l); if ($#vlan != 1) {print STDERR "ERROR: Bad VLAN command - $l\n";exit 1;} $vlan = $vlan[1]; #conversion en hexa $vlanHexa = sprintf "%04x",$vlan[1]; $vlanHexa = substr($vlanHexa,0,2).':'.substr($vlanHexa,2,2); next; } # PORT [] if ($l =~ /^PORT/) { if (!defined($network)) { die "ERROR: PORT before NETWORK command\n"; } $l =~ s/\n$//; @port = split('\s+',$l,6); $type = $port[1]; $module = $port[2]; $port = $port[3]; $o_ip = $port[4]; $o_optional_description_line= $description= ""; if ($#port == 5) {$description = $port[5];} if ($description) { $o_optional_description_line= " description $description [*auto*] "; } if ($#port == -1 || $#port>6) {print STDERR "ERROR: Bad PORT command ($#port) - $l\n";exit 1;} $portmin= $portmax= $port; if ($port =~ m/^[0-9]+-[0-9]$/) { # port range ($portmin, $portmax)= split('-',$port); } foreach $port ($portmin .. $portmax) { # apply substitution to variable $expmatch='(\(\([^)]+\)\))'; $ip= $o_ip; $optional_description_line= $o_optional_description_line; $ip =~ s/$expmatch/eval($1)/ego; # WARNING absolutly not secure !!!! but so easy... $optional_description_line =~ s/$expmatch/eval($1)/ego; # WARNING absolutly not secure !!!! but so easy... if ($debug) {print STDERR "$o_ip -> $ip\n";} $ip= ($ip =~ s/-//); # remove dash '-' inside iprange (ip-ip -> ip ip) $moduleHexa = sprintf "%02x",$module; #conversion hexa du module if ($switch_type eq "cisco") { $hport = sprintf "%02x",$port-1; #conversion hexa du port } else { $hport = sprintf "%02x",$port; } $classes_name = $network."-vlan ".$vlanHexa."-mod ".$moduleHexa."-port ".$hport." on ".$switch_name; $port_key= "switch=$switch_name // type=$type // module=$module // port=$port"; if (defined($port_key{$port_key})) { print STDERR "WARNING: port redefined $port_key\n"; } $port_key{$port_key}= $l; $ip_key= "ip=$ip // vlan= $vlan"; if (defined($ip_key{$ip_key})) { print STDERR "WARNING: ip redefined $ip_key\n"; } $ip_key{$ip_key}= $l; open (CLASSES,">>$rootclasses") || die "Cannot reopen $rootclasses : $!"; print STDERR "Writing $rootclasses\n" if ($debug); print CLASSES "class \"".$classes_name."\"\{\n\tmatch if \(substring \(option agent\.circuit-id,2, 2\) = ".$vlanHexa."\)\n\t\t and \(substring \(option agent\.circuit-id,4,1\) = ".$moduleHexa."\)\n\t\t and \(suffix \(option agent\.circuit-id, 1\) = ".$hport."\)\n\t\t and \(suffix\(option agent\.remote-id,6\) = ".$mac."\)\;\n\}\n"; close (CLASSES); print SUBNET "pool \{\n\tallow members of \"".$classes_name."\";\n\trange ".$ip.";\n\}\n\n"; if ($switch_type eq 'cisco') { print SWITCH "" ."interface $type $module/$port\n" ." $optional_description_line\n" ." ip access-group ip=$ip in\n" ." switchport access vlan $vlan\n" ." switchport mode access\n" ." no access-list ip=$ip \n" ." access-list ip=$ip remark $optional_description_line\n" ." access-list ip=$ip permit 0.0.0.0\n" ." access-list ip=$ip permit $ip\n" ." access-list ip=$ip deny any\n" ."\n"; } else { die "Unknown switch type <$type>"; } } next; } die "Unknown command - $l"; } close (SUBNET); close (SWITCH);