#!/usr/bin/perl -w # # Copyright (C) 2005-2008 Gabriel Moreau. # # $Id: klask 51 2009-07-23 22:22:32Z g7moreau $ use strict; use warnings; use Readonly; use Net::SNMP; #use YAML; use YAML::Syck; use Net::Netmask; use Net::CIDR::Lite; use NetAddr::IP; use Getopt::Long; # apt-get install snmp fping libnet-cidr-lite-perl libnet-netmask-perl libnet-snmp-perl libnetaddr-ip-perl libyaml-perl # libcrypt-des-perl libcrypt-hcesha-perl libdigest-hmac-perl # arping fping bind9-host arpwatch my $KLASK_VAR = '/var/cache/klask'; my $KLASK_CFG_FILE = '/etc/klask.conf'; my $KLASK_DB_FILE = "$KLASK_VAR/klaskdb"; my $KLASK_SW_FILE = "$KLASK_VAR/switchdb"; test_running_environnement(); my $KLASK_CFG = YAML::Syck::LoadFile("$KLASK_CFG_FILE"); my %DEFAULT = %{ $KLASK_CFG->{default} }; my @SWITCH = @{ $KLASK_CFG->{switch} }; my %switch_level = (); my %SWITCH_DB = (); LEVEL_OF_EACH_SWITCH: for my $sw (@SWITCH){ $switch_level{$sw->{hostname}} = $sw->{level} || $DEFAULT{switch_level} || 2; $SWITCH_DB{$sw->{hostname}} = $sw; } @SWITCH = sort { $switch_level{$b->{hostname}} <=> $switch_level{$a->{hostname}} } @{$KLASK_CFG->{switch}}; my %SWITCH_PORT_COUNT = (); my %CMD_DB = ( help => \&cmd_help, version => \&cmd_version, exportdb => \&cmd_exportdb, updatedb => \&cmd_updatedb, searchdb => \&cmd_searchdb, removedb => \&cmd_removedb, search => \&cmd_search, enable => \&cmd_enable, disable => \&cmd_disable, status => \&cmd_status, updatesw => \&cmd_updatesw, exportsw => \&cmd_exportsw, iplocation => \&cmd_iplocation, 'search-mac-on-switch' => \&cmd_search_mac_on_switch, ); Readonly my %INTERNAL_PORT_MAP => ( 0 => 'A', 1 => 'B', 2 => 'C', 3 => 'D', 4 => 'E', 5 => 'F', 6 => 'G', 7 => 'H', ); Readonly my %INTERNAL_PORT_MAP_REV => reverse %INTERNAL_PORT_MAP; Readonly my %SWITCH_KIND => ( J3299A => { model => 'HP224M', match => 'HP J3299A ProCurve Switch 224M' }, J4120A => { model => 'HP1600M', match => 'HP J4120A ProCurve Switch 1600M' }, J9029A => { model => 'HP1800-8G', match => 'PROCURVE J9029A' }, J4093A => { model => 'HP2424M', match => 'HP J4093A ProCurve Switch 2424M' }, J4813A => { model => 'HP2524', match => 'HP J4813A ProCurve Switch 2524' }, J4900A => { model => 'HP2626A', match => 'HP J4900A ProCurve Switch 2626' }, J4900B => { model => 'HP2626B', match => 'J4900B.+?Switch 2626' },# ProCurve J4900B Switch 2626 # HP J4900B ProCurve Switch 2626 J4899B => { model => 'HP2650', match => 'ProCurve J4899B Switch 2650' }, J9021A => { model => 'HP2810-24G', match => 'ProCurve J9021A Switch 2810-24G' }, J9022A => { model => 'HP2810-48G', match => 'ProCurve J9022A Switch 2810-48G' }, J4903A => { model => 'HP2824', match => 'J4903A.+?Switch 2824,' }, J4110A => { model => 'HP8000M', match => 'HP J4110A ProCurve Switch 8000M' }, BS350T => { model => 'BS350T', match => 'BayStack 350T HW' }, ); Readonly my %OID_NUMBER => ( sysDescription => '1.3.6.1.2.1.1.1.0', sysName => '1.3.6.1.2.1.1.5.0', sysContact => '1.3.6.1.2.1.1.4.0', sysLocation => '1.3.6.1.2.1.1.6.0', ); Readonly my $RE_MAC_ADDRESS => qr{ [0-9,A-Z]{2} : [0-9,A-Z]{2} : [0-9,A-Z]{2} : [0-9,A-Z]{2} : [0-9,A-Z]{2} : [0-9,A-Z]{2} }xms; Readonly my $RE_IPv4_ADDRESS => qr{ [0-9]{1,3} \. [0-9]{1,3} \. [0-9]{1,3} \. [0-9]{1,3} }xms; ################ # principal ################ my $cmd = shift @ARGV || 'help'; if (defined $CMD_DB{$cmd}) { $CMD_DB{$cmd}->(@ARGV); } else { print STDERR "klask: command $cmd not found\n\n"; $CMD_DB{help}->(); exit 1; } exit; sub test_running_environnement { die "Configuration file $KLASK_CFG_FILE does not exists. Klask need it !\n" if not -e "$KLASK_CFG_FILE"; die "Var folder $KLASK_VAR does not exists. Klask need it !\n" if not -d "$KLASK_VAR"; return; } sub test_switchdb_environnement { die "Switch database $KLASK_SW_FILE does not exists. Launch updatesw before this command !\n" if not -e "$KLASK_SW_FILE"; return; } sub test_maindb_environnement { die "Main database $KLASK_DB_FILE does not exists. Launch updatedb before this command !\n" if not -e "$KLASK_DB_FILE"; return; } ### # fast ping dont l'objectif est de remplir la table arp de la machine sub fastping { system "fping -c 1 @_ >/dev/null 2>&1"; return; } ### # donne l'@ ip, dns, arp en fonction du dns OU de l'ip sub resolve_ip_arp_host { my $param_ip_or_host = shift; my $interface = shift || '*'; my $type = shift || 'fast'; my %ret = ( hostname_fq => 'unknow', ipv4_address => '0.0.0.0', mac_address => 'unknow', ); # my $cmdarping = `arping -c 1 -w 1 -rR $param 2>/dev/null`; if ( not $param_ip_or_host =~ m/^\d+ \. \d+ \. \d+ \. \d+$/x ) { $param_ip_or_host =~ s/ \. .* //x; } # controler que arpwatch tourne ! # resultat de la commande arpwatch # /var/lib/arpwatch/arp.dat # 0:13:d3:e1:92:d0 192.168.24.109 1163681980 theo8sv109 # my $cmd = "grep -e '".'\b'."$param_ip_or_host".'\b'."' /var/lib/arpwatch/arp.dat | sort +2rn | head -1"; # my $cmd = "grep -he '".'\b'."$param_ip_or_host".'\b'."' /var/lib/arpwatch/*.dat | sort +2rn | head -1"; my $cmd = "grep -he '".'\b'."$param_ip_or_host".'\b'."' /var/lib/arpwatch/$interface.dat | sort -rn -k 3,3 | head -1"; my $cmd_arpwatch = `$cmd`; chomp $cmd_arpwatch; my ($arp, $ip, $timestamp, $host) = split m/ \s+ /x, $cmd_arpwatch; $ret{ipv4_address} = $ip if $ip; $ret{mac_address} = $arp if $arp; $ret{timestamp} = $timestamp if $timestamp; my $nowtimestamp = time(); if ( $type eq 'fast' and ( not defined $timestamp or $timestamp < ( $nowtimestamp - 3 * 3600 ) ) ) { $ret{mac_address} = 'unknow'; return %ret; } # resultat de la commande arp # tech7meylan.hmg.inpg.fr (194.254.66.240) at 00:14:22:45:28:A9 [ether] on eth0 # sw2-batF0-legi.hmg.priv (192.168.22.112) at 00:30:c1:76:9c:01 [ether] on eth0.37 my $cmd_arp = `arp -a $param_ip_or_host 2> /dev/null`; chomp $cmd_arp; if ( $cmd_arp =~ m{ (\S*) \s \( ( $RE_IPv4_ADDRESS ) \) \s at \s ( $RE_MAC_ADDRESS ) }xms ) { ( $ret{hostname_fq}, $ret{ipv4_address}, $ret{mac_address} ) = ($1, $2, $3); } # resultat de la commande host si le parametre est ip # 250.66.254.194.in-addr.arpa domain name pointer legihp2100.hmg.inpg.fr. my $cmd_host = `host $param_ip_or_host 2> /dev/null`; chomp $cmd_host; if ( $cmd_host =~ m/domain \s name \s pointer \s (\S+) \.$/xms ) { $ret{hostname_fq} = $1; } # resultat de la commande host si parametre est hostname # tech7meylan.hmg.inpg.fr has address 194.254.66.240 if ( $cmd_host =~ m/(\S*) \s has \s address \s ( $RE_IPv4_ADDRESS )$/xms ) { ( $ret{hostname_fq}, $ret{ipv4_address} ) = ($1, $2); } if ( $cmd_host =~ m/ \b ( $RE_IPv4_ADDRESS ) \. in-addr \. arpa \s/xms ) { $ret{ipv4_address} = $1; } #$ret{hostname_fq} = $param_ip_or_host if not defined $1 and $ret{hostname_fq} eq 'unknow'; unless ($ret{mac_address} eq 'unknow') { my @paquets = (); foreach ( split m/ : /x, $ret{mac_address} ) { my @chars = split m//xms, uc("00$_"); push @paquets, "$chars[-2]$chars[-1]"; } $ret{mac_address} = join ':', @paquets; } return %ret; } # Find Surname of a switch sub get_switch_model { my $sw_snmp_description = shift || 'unknow'; for my $sw_kind (keys %SWITCH_KIND) { next if not $sw_snmp_description =~ m/$SWITCH_KIND{$sw_kind}->{match}/x; return $SWITCH_KIND{$sw_kind}->{model}; } return $sw_snmp_description; } ### # va rechercher le nom des switchs pour savoir qui est qui sub init_switch_names { my $verbose = shift; printf "%-25s %-25s %s\n",'Switch','Description','Type'; # print "Switch description\n" if $verbose; print "-------------------------------------------------------------------------\n" if $verbose; INIT_EACH_SWITCH: for my $sw (@SWITCH) { my %session = ( -hostname => $sw->{hostname} ); $session{-version} = $sw->{version} || 1; $session{-port} = $sw->{snmpport} || $DEFAULT{snmpport} || 161; if (exists $sw->{version} and $sw->{version} eq '3') { $session{-username} = $sw->{username} || 'snmpadmin'; } else { $session{-community} = $sw->{community} || $DEFAULT{community} || 'public'; } $sw->{local_session} = \%session; my ($session, $error) = Net::SNMP->session( %{$sw->{local_session}} ); print "$error \n" if $error; my $result = $session->get_request( -varbindlist => [ $OID_NUMBER{sysDescription}, $OID_NUMBER{sysName}, $OID_NUMBER{sysContact}, $OID_NUMBER{sysLocation}, ] ); $sw->{description} = $result->{$OID_NUMBER{sysName}} || $sw->{hostname}; $sw->{model} = get_switch_model( $result->{$OID_NUMBER{sysDescription}}); #$sw->{location} = $result->{"1.3.6.1.2.1.1.6.0"} || $sw->{hostname}; #$sw->{contact} = $result->{"1.3.6.1.2.1.1.4.0"} || $sw->{hostname}; $session->close; # Ligne à virer car on récupère maintenant le modèle du switch my ($desc, $type) = split ':', $sw->{description}, 2; printf "%-25s 0--------->>>> %-25s %s\n", $sw->{hostname}, $desc, $sw->{model} if $verbose; } print "\n" if $verbose; return; } ### # convertit l'hexa (uniquement 2 chiffres) en decimal sub hex_to_dec { #00:0F:1F:43:E4:2B my $car = '00' . uc(shift); return '00' if $car eq '00UNKNOW'; my %table = ( "0"=>"0", "1"=>"1", "2"=>"2", "3"=>"3", "4"=>"4", "5"=>"5", "6"=>"6", "7"=>"7", "8"=>"8", "9"=>"9", "A"=>"10", "B"=>"11", "C"=>"12", "D"=>"13", "E"=>"14", "F"=>"15" ); my @chars = split m//x, $car; return $table{$chars[-2]}*16 + $table{$chars[-1]}; } ### # convertit l'@ arp en decimal sub arp_hex_to_dec { #00:0F:1F:43:E4:2B my $arp = shift; my @paquets = split m/ : /x, $arp; my $return = ''; foreach(@paquets) { $return .= ".".hex_to_dec($_); } return $return; } ### # va rechercher le port et le switch sur lequel est la machine sub find_switch_port { my $arp = shift; my $switch_proposal = shift || ''; my %ret; $ret{switch_description} = "unknow"; $ret{switch_port} = "0"; return %ret if $arp eq 'unknow';; my @switch_search = @SWITCH; if ($switch_proposal ne '') { for my $sw (@SWITCH) { next if $sw->{hostname} ne $switch_proposal; unshift @switch_search, $sw; last; } } my $research = "1.3.6.1.2.1.17.4.3.1.2".arp_hex_to_dec($arp); LOOP_ON_SWITCH: for my $sw (@switch_search) { my ($session, $error) = Net::SNMP->session( %{$sw->{local_session}} ); print "$error \n" if $error; my $result = $session->get_request( -varbindlist => [$research] ); if (not defined($result) or $result->{$research} eq 'noSuchInstance') { $session->close; next LOOP_ON_SWITCH; } my $swport = $result->{$research}; $session->close; # IMPORTANT !! # ceci empeche la detection sur certains port ... # en effet les switch sont relies entre eux par un cable reseau et du coup # tous les arp de toutes les machines sont presentes sur ces ports (ceux choisis ici sont les miens) # cette partie est a ameliore, voir a configurer dans l'entete # 21->24 45->48 # my $flag = 0; SWITCH_PORT_IGNORE: foreach my $p (@{$sw->{portignore}}) { next SWITCH_PORT_IGNORE if $swport ne get_numerical_port($sw->{model},$p); # $flag = 1; next LOOP_ON_SWITCH; } # if ($flag == 0) { $ret{switch_hostname} = $sw->{hostname}; $ret{switch_description} = $sw->{description}; $ret{switch_port} = get_human_readable_port($sw->{model}, $swport); # $swport; last LOOP_ON_SWITCH; # } # } # $session->close; } return %ret; } ### # va rechercher les port et les switch sur lequel est la machine sub find_all_switch_port { my $arp = shift; my $ret = {}; return $ret if $arp eq 'unknow'; for my $sw (@SWITCH) { $SWITCH_PORT_COUNT{$sw->{hostname}} = {} if not exists $SWITCH_PORT_COUNT{$sw->{hostname}}; } my $research = "1.3.6.1.2.1.17.4.3.1.2".arp_hex_to_dec($arp); LOOP_ON_ALL_SWITCH: for my $sw (@SWITCH) { my ($session, $error) = Net::SNMP->session( %{$sw->{local_session}} ); print "$error \n" if $error; my $result = $session->get_request( -varbindlist => [$research] ); if(defined($result) and $result->{$research} ne 'noSuchInstance'){ my $swport = $result->{$research}; $ret->{$sw->{hostname}} = {}; $ret->{$sw->{hostname}}{hostname} = $sw->{hostname}; $ret->{$sw->{hostname}}{description} = $sw->{description}; $ret->{$sw->{hostname}}{port} = get_human_readable_port($sw->{model}, $swport); $SWITCH_PORT_COUNT{$sw->{hostname}}->{$swport}++; } $session->close; } return $ret; } sub get_list_network { return keys %{$KLASK_CFG->{network}}; } sub get_current_interface { my $network = shift; return $KLASK_CFG->{network}{$network}{interface}; } ### # liste l'ensemble des adresses ip d'un réseau sub get_list_ip { my @network = @_; my $cidrlist = Net::CIDR::Lite->new; for my $net (@network) { my @line = @{$KLASK_CFG->{network}{$net}{'ip-subnet'}}; for my $cmd (@line) { for my $method (keys %$cmd){ $cidrlist->add_any($cmd->{$method}) if $method eq 'add'; } } } my @res = (); for my $cidr ($cidrlist->list()) { my $net = new NetAddr::IP $cidr; for my $ip (@$net) { $ip =~ s{ /32 }{}x; push @res, $ip; } } return @res; } # liste l'ensemble des routeurs du réseau sub get_list_main_router { my @network = @_; my @res = (); for my $net (@network) { push @res, $KLASK_CFG->{network}{$net}{'main-router'}; } return @res; } sub get_human_readable_port { my $sw_model = shift; my $sw_port = shift; return $sw_port if not $sw_model eq 'HP8000M'; my $reste = (($sw_port - 1) % 8) + 1; my $major = int( ($sw_port - 1) / 8 ); return "$INTERNAL_PORT_MAP{$major}$reste"; } sub get_numerical_port { my $sw_model = shift; my $sw_port = shift; return $sw_port if not $sw_model eq 'HP8000'; my $letter = substr($sw_port, 0, 1); # return $port if $letter =~ m/\d/; my $reste = substr($sw_port, 1); return $INTERNAL_PORT_MAP_REV{$letter} * 8 + $reste; } ################ # Les commandes ################ sub cmd_help { print <<'END'; klask - ports manager and finder for switch klask updatedb klask exportdb klask updatesw klask exportsw klask searchdb computer klask search computer klask enable switch port klask disable switch port klask status switch port END return; } sub cmd_version { print <<'END'; Klask - ports manager and finder for switch Copyright (C) 2005-2008 Gabriel Moreau END print ' $Rev: 51 $'."\n"; print ' $Date: 2009-07-23 22:22:32 +0000 (Thu, 23 Jul 2009) $'."\n"; print ' $Id: klask 51 2009-07-23 22:22:32Z g7moreau $'."\n"; return; } sub cmd_search { my @computer = @_; init_switch_names(); #nomme les switchs fastping(@computer); for my $clientname (@computer) { my %resol_arp = resolve_ip_arp_host($clientname); #resolution arp my %where = find_switch_port($resol_arp{mac_address}); #retrouve l'emplacement printf "%-22s %2i %-30s %-15s %18s", $where{switch_description}, $where{switch_port}, $resol_arp{hostname_fq}, $resol_arp{ipv4_address}, $resol_arp{mac_address}."\n" unless $where{switch_description} eq 'unknow' and $resol_arp{hostname_fq} eq 'unknow' and $resol_arp{mac_address} eq 'unknow'; } return; } sub cmd_searchdb { my @computer = @_; fastping(@computer); my $computerdb = YAML::Syck::LoadFile("$KLASK_DB_FILE"); LOOP_ON_COMPUTER: for my $clientname (@computer) { my %resol_arp = resolve_ip_arp_host($clientname); #resolution arp my $ip = $resol_arp{ipv4_address}; next LOOP_ON_COMPUTER unless exists $computerdb->{$ip}; my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($computerdb->{$ip}{timestamp}); $year += 1900; $mon++; my $date = sprintf "%04i-%02i-%02i %02i:%02i", $year,$mon,$mday,$hour,$min; printf "%-22s %2s %-30s %-15s %-18s %s\n", $computerdb->{$ip}{switch_name}, $computerdb->{$ip}{switch_port}, $computerdb->{$ip}{hostname_fq}, $ip, $computerdb->{$ip}{mac_address}, $date; } return; } sub cmd_updatedb { my @network = @_; @network = get_list_network() if not @network; test_switchdb_environnement(); my $computerdb = {}; $computerdb = YAML::Syck::LoadFile("$KLASK_DB_FILE") if -e "$KLASK_DB_FILE"; my $timestamp = time; my %computer_not_detected = (); my $timestamp_last_week = $timestamp - (3600 * 24 * 7); my $number_of_computer = get_list_ip(@network); # + 1; my $size_of_database = keys %$computerdb; $size_of_database = 1 if $size_of_database == 0; my $i = 0; my $detected_computer = 0; init_switch_names('yes'); #nomme les switchs { # Remplis le champs portignore des ports d'inter-connection pour chaque switch my $switch_connection = YAML::Syck::LoadFile("$KLASK_SW_FILE"); my %db_switch_output_port = %{$switch_connection->{output_port}}; my %db_switch_connected_on_port = %{$switch_connection->{connected_on_port}}; my %db_switch_chained_port = (); for my $swport (keys %db_switch_connected_on_port) { my ($sw_connect,$port_connect) = split ':', $swport; $db_switch_chained_port{$sw_connect} .= "$port_connect:"; } for my $sw (@SWITCH){ push @{$sw->{portignore}}, $db_switch_output_port{$sw->{hostname}} if exists $db_switch_output_port{$sw->{hostname}}; if ( exists $db_switch_chained_port{$sw->{hostname}} ) { chop $db_switch_chained_port{$sw->{hostname}}; push @{$sw->{portignore}}, split(':',$db_switch_chained_port{$sw->{hostname}}); } # print "$sw->{hostname} ++ @{$sw->{portignore}}\n"; } } my %router_mac_ip = (); DETECT_ALL_ROUTER: # for my $one_router ('194.254.66.254') { for my $one_router ( get_list_main_router(@network) ) { my %resol_arp = resolve_ip_arp_host($one_router); $router_mac_ip{ $resol_arp{mac_address} } = $resol_arp{ipv4_address}; } ALL_NETWORK: for my $net (@network) { my @computer = get_list_ip($net); my $current_interface = get_current_interface($net); fastping(@computer); LOOP_ON_COMPUTER: for my $one_computer (@computer) { $i++; my $total_percent = int(($i*100)/$number_of_computer); my $localtime = time - $timestamp; my ($sec,$min) = localtime($localtime); my $time_elapse = 0; $time_elapse = $localtime * ( 100 - $total_percent) / $total_percent if $total_percent != 0; my ($sec_elapse,$min_elapse) = localtime($time_elapse); printf "\rComputer scanned: %4i/%i (%2i%%)", $i, $number_of_computer, $total_percent; # printf ", Computer detected: %4i/%i (%2i%%)", $detected_computer, $size_of_database, int(($detected_computer*100)/$size_of_database); printf ", detected: %4i/%i (%2i%%)", $detected_computer, $size_of_database, int(($detected_computer*100)/$size_of_database); printf " [Time: %02i:%02i / %02i:%02i]", int($localtime/60), $localtime % 60, int($time_elapse/60), $time_elapse % 60; # printf " [%02i:%02i/%02i:%02i]", int($localtime/60), $localtime % 60, int($time_elapse/60), $time_elapse % 60; printf " %-14s", $one_computer; my %resol_arp = resolve_ip_arp_host($one_computer,$current_interface); # do not search on router connection (why ?) if ( exists $router_mac_ip{$resol_arp{mac_address}}) { $computer_not_detected{$one_computer} = $current_interface; next LOOP_ON_COMPUTER; } # do not search on switch inter-connection if (exists $switch_level{$resol_arp{hostname_fq}}) { $computer_not_detected{$one_computer} = $current_interface; next LOOP_ON_COMPUTER; } my $switch_proposal = ''; if (exists $computerdb->{$resol_arp{ipv4_address}} and exists $computerdb->{$resol_arp{ipv4_address}}{switch_hostname}) { $switch_proposal = $computerdb->{$resol_arp{ipv4_address}}{switch_hostname}; } # do not have a mac address if ($resol_arp{mac_address} eq 'unknow' or (exists $resol_arp{timestamps} and $resol_arp{timestamps} < ($timestamp - 3 * 3600))) { $computer_not_detected{$one_computer} = $current_interface; next LOOP_ON_COMPUTER; } my %where = find_switch_port($resol_arp{mac_address},$switch_proposal); #192.168.24.156: # arp: 00:0B:DB:D5:F6:65 # hostname: pcroyon.hmg.priv # port: 5 # switch: sw-batH-legi:hp2524 # timestamp: 1164355525 # do not have a mac address # if ($resol_arp{mac_address} eq 'unknow') { # $computer_not_detected{$one_computer} = $current_interface; # next LOOP_ON_COMPUTER; # } # detected on a switch if ($where{switch_description} ne 'unknow') { $detected_computer++; $computerdb->{$resol_arp{ipv4_address}} = { hostname_fq => $resol_arp{hostname_fq}, mac_address => $resol_arp{mac_address}, switch_hostname => $where{switch_hostname}, switch_description => $where{switch_description}, switch_port => $where{switch_port}, timestamp => $timestamp, network => $net, }; next LOOP_ON_COMPUTER; } # new in the database but where it is ? if (not exists $computerdb->{$resol_arp{ipv4_address}}) { $detected_computer++; $computerdb->{$resol_arp{ipv4_address}} = { hostname_fq => $resol_arp{hostname_fq}, mac_address => $resol_arp{mac_address}, switch_hostname => $where{switch_hostname}, switch_description => $where{switch_description}, switch_port => $where{switch_port}, timestamp => $resol_arp{timestamp}, network => $net, }; } # mise a jour du nom de la machine si modification dans le dns $computerdb->{$resol_arp{ipv4_address}}{hostname_fq} = $resol_arp{hostname_fq}; # mise à jour de la date de détection si détection plus récente par arpwatch $computerdb->{$resol_arp{ipv4_address}}{timestamp} = $resol_arp{timestamp} if exists $resol_arp{timestamp} and $computerdb->{$resol_arp{ipv4_address}}{timestamp} < $resol_arp{timestamp}; # relance un arping sur la machine si celle-ci n'a pas été détectée depuis plus d'une semaine # push @computer_not_detected, $resol_arp{ipv4_address} if $computerdb->{$resol_arp{ipv4_address}}{timestamp} < $timestamp_last_week; $computer_not_detected{$resol_arp{ipv4_address}} = $current_interface if $computerdb->{$resol_arp{ipv4_address}}{timestamp} < $timestamp_last_week; } } # final end of line at the end of the loop printf "\n"; my $dirdb = $KLASK_DB_FILE; $dirdb =~ s{ / [^/]* $}{}x; mkdir "$dirdb", 0755 unless -d "$dirdb"; YAML::Syck::DumpFile("$KLASK_DB_FILE", $computerdb); for my $one_computer (keys %computer_not_detected) { my $interface = $computer_not_detected{$one_computer}; system "arping -c 1 -w 1 -rR -i $interface $one_computer &>/dev/null"; # print "arping -c 1 -w 1 -rR -i $interface $one_computer 2>/dev/null\n"; } return; } sub cmd_removedb { my @computer = @_; test_maindb_environnement(); my $computerdb = YAML::Syck::LoadFile("$KLASK_DB_FILE"); LOOP_ON_COMPUTER: for my $one_computer (@computer) { my %resol_arp = resolve_ip_arp_host($one_computer); delete $computerdb->{$resol_arp{ipv4_address}} if exists $computerdb->{$resol_arp{ipv4_address}}; } my $dirdb = $KLASK_DB_FILE; $dirdb =~ s{ / [^/]* $}{}x; mkdir "$dirdb", 0755 unless -d "$dirdb"; YAML::Syck::DumpFile("$KLASK_DB_FILE", $computerdb); return; } sub cmd_exportdb { my @ARGV = @_; my $format = 'txt'; my $ret = GetOptions( 'format|f=s' => \$format, ); my %possible_format = ( txt => \&cmd_exportdb_txt, html => \&cmd_exportdb_html, ); $format = 'txt' if not defined $possible_format{$format}; $possible_format{$format}->(@ARGV); return; } sub cmd_exportdb_txt { test_maindb_environnement(); my $computerdb = YAML::Syck::LoadFile("$KLASK_DB_FILE"); printf "%-24s %-4s %-30s %-15s %-18s %-s\n", qw(Switch Port Hostname IPv4-Address MAC-Address Date); print "---------------------------------------------------------------------------------------------------------------------------\n"; LOOP_ON_IP_ADDRESS: foreach my $ip (Net::Netmask::sort_by_ip_address(keys %$computerdb)) { # next LOOP_ON_IP_ADDRESS if $computerdb->{$ip}{hostname_fq} eq 'unknow'; # to be improve in the future next LOOP_ON_IP_ADDRESS if $computerdb->{$ip}{hostname_fq} eq ($computerdb->{$ip}{switch_hostname} || $computerdb->{$ip}{switch_description}); # switch on himself ! # dans le futur # next if $computerdb->{$ip}{hostname_fq} eq 'unknow'; my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($computerdb->{$ip}{timestamp}); $year += 1900; $mon++; my $date = sprintf "%04i-%02i-%02i %02i:%02i", $year,$mon,$mday,$hour,$min; printf "%-25s %2s <------- %-30s %-15s %-18s %s\n", $computerdb->{$ip}{switch_hostname} || $computerdb->{$ip}{switch_description}, $computerdb->{$ip}{switch_port}, $computerdb->{$ip}{hostname_fq}, $ip, $computerdb->{$ip}{mac_address}, $date; } return; } sub cmd_exportdb_html { test_maindb_environnement(); my $computerdb = YAML::Syck::LoadFile("$KLASK_DB_FILE"); # # print <<'END_HTML';
Switch | Port | Link | Hostname | IPv4-Address | MAC-Address | Date |
---|---|---|---|---|---|---|
Switch | Port | Link | Hostname | IPv4-Address | MAC-Address | Date |
$switch_hostname | $computerdb->{$ip}{switch_port} | <------- | $computerdb->{$ip}{hostname_fq} | $ip | $computerdb->{$ip}{mac_address} | $date |
$sw | $db_switch_output_port{$sw}> | +--> $db_switch_parent{$sw}->{port} | $db_switch_parent{$sw}->{switch}> | $ipv4_address | $mac_address | $date |
$sw | $db_switch_output_port{$sw}> | +--> | router> | |||
$sw_connect | $port_connect> | <--+ $db_switch_output_port{$sw} | $sw> | $ipv4_address | $mac_address | $date |
$sw_connect | $port_connect> | <--+ | $sw> | $ipv4_address | $mac_address | $date |