source: trunk/klask @ 43

Last change on this file since 43 was 43, checked in by g7moreau, 15 years ago
  • Add HP3500-24G HP switch model J8692A
  • Property svn:executable set to *
  • Property svn:keywords set to Date Author Id Rev
File size: 44.7 KB
Line 
1#!/usr/bin/perl -w
2#
3# Copyright (C) 2005-2008 Gabriel Moreau.
4#
5# $Id: klask 43 2008-11-27 14:03:01Z g7moreau $
6
7use strict;
8use warnings;
9
10use Net::SNMP;
11use YAML;
12use Net::Netmask;
13use Net::CIDR::Lite;
14use NetAddr::IP;
15use Getopt::Long;
16
17# apt-get install snmp fping libnet-cidr-lite-perl libnet-netmask-perl libnet-snmp-perl libnetaddr-ip-perl libyaml-perl
18# libcrypt-des-perl libcrypt-hcesha-perl libdigest-hmac-perl
19# arping fping bind9-host arpwatch
20
21my $KLASK_VAR      = '/var/cache/klask';
22my $KLASK_CFG_FILE = '/etc/klask.conf';
23my $KLASK_DB_FILE  = "$KLASK_VAR/klaskdb";
24my $KLASK_SW_FILE  = "$KLASK_VAR/switchdb";
25
26test_running_environnement();
27
28my $KLASK_CFG = YAML::LoadFile("$KLASK_CFG_FILE");
29
30my %DEFAULT = %{$KLASK_CFG->{default}};
31my @SWITCH  = @{$KLASK_CFG->{switch}};
32
33my %switch_level = ();
34my %SWITCH_DB = ();
35LEVEL_OF_EACH_SWITCH:
36for my $sw (@SWITCH){
37   $switch_level{$sw->{hostname}} = $sw->{level} || $DEFAULT{switch_level}  || 2;
38   $SWITCH_DB{$sw->{hostname}} = $sw;
39   }
40@SWITCH = sort { $switch_level{$b->{hostname}} <=> $switch_level{$a->{hostname}} } @{$KLASK_CFG->{switch}}; 
41
42my %SWITCH_PORT_COUNT = ();
43
44my %CMD_DB = (
45   help       => \&cmd_help,
46   version    => \&cmd_version,
47   exportdb   => \&cmd_exportdb,
48   updatedb   => \&cmd_updatedb,
49   searchdb   => \&cmd_searchdb,
50   removedb   => \&cmd_removedb,
51   search     => \&cmd_search,
52   enable     => \&cmd_enable,
53   disable    => \&cmd_disable,
54   status     => \&cmd_status,
55   updatesw   => \&cmd_updatesw,
56   exportsw   => \&cmd_exportsw,
57   dotsw      => \&cmd_exportsw_dot,
58   iplocation => \&cmd_iplocation,
59   'search-mac-on-switch' => \&cmd_search_mac_on_switch,
60   );
61
62my %INTERNAL_PORT_MAP = (
63   0 => 'A',
64   1 => 'B',
65   2 => 'C',
66   3 => 'D',
67   4 => 'E',
68   5 => 'F',
69   6 => 'G',
70   7 => 'H',
71   );
72my %INTERNAL_PORT_MAP_REV = reverse %INTERNAL_PORT_MAP;
73
74my %SWITCH_KIND = (
75   J3299A => { model => 'HP224M',     match => 'HP J3299A ProCurve Switch 224M'  },
76   J4120A => { model => 'HP1600M',    match => 'HP J4120A ProCurve Switch 1600M' },
77   J9029A => { model => 'HP1800-8G',  match => 'PROCURVE J9029A'                 },
78   J4093A => { model => 'HP2424M',    match => 'HP J4093A ProCurve Switch 2424M' },
79   J4813A => { model => 'HP2524',     match => 'HP J4813A ProCurve Switch 2524'  },
80   J4900A => { model => 'HP2626A',    match => 'HP J4900A ProCurve Switch 2626'  },
81   J4900B => { model => 'HP2626B',    match => 'J4900B.+?Switch 2626'            },# ProCurve J4900B Switch 2626 # HP J4900B ProCurve Switch 2626
82   J4899B => { model => 'HP2650',     match => 'ProCurve J4899B Switch 2650'     },
83   J9021A => { model => 'HP2810-24G', match => 'ProCurve J9021A Switch 2810-24G' },
84   J9022A => { model => 'HP2810-48G', match => 'ProCurve J9022A Switch 2810-48G' },
85   J4903A => { model => 'HP2824',     match => 'J4903A.+?Switch 2824,'           },
86   J8692A => { model => 'HP3500-24G', match => 'J8692A'                          },
87   J4110A => { model => 'HP8000M',    match => 'HP J4110A ProCurve Switch 8000M' },
88   BS350T => { model => 'BS350T',     match => 'BayStack 350T HW'                },
89   );
90 
91my %OID_NUMBER = (
92   sysDescr    => '1.3.6.1.2.1.1.1.0',
93   sysName     => '1.3.6.1.2.1.1.5.0',
94   sysContact  => '1.3.6.1.2.1.1.4.0',
95   sysLocation => '1.3.6.1.2.1.1.6.0',
96   );
97
98################
99# principal
100################
101
102my $cmd = shift @ARGV || 'help';
103if (defined $CMD_DB{$cmd}) {
104   $CMD_DB{$cmd}->(@ARGV);
105   }
106else {
107   print STDERR "klask: command $cmd not found\n\n";
108   $CMD_DB{help}->();
109   exit 1;
110   }
111
112exit;
113
114sub test_running_environnement {
115   die "Configuration file $KLASK_CFG_FILE does not exists. Klask need it !\n" if not -e "$KLASK_CFG_FILE";
116   die "Var folder $KLASK_VAR does not exists. Klask need it !\n"              if not -d "$KLASK_VAR";
117   }
118
119sub test_switchdb_environnement {
120   die "Switch database $KLASK_SW_FILE does not exists. Launch updatesw before this command !\n" if not -e "$KLASK_SW_FILE";
121   }
122
123sub test_maindb_environnement {
124   die "Main database $KLASK_DB_FILE does not exists. Launch updatedb before this command !\n" if not -e "$KLASK_DB_FILE";
125   }
126
127###
128# fast ping dont l'objectif est de remplir la table arp de la machine
129sub fastping {
130   system "fping -c 1 @_ >/dev/null 2>&1";
131   }
132
133###
134# donne l'@ ip, dns, arp en fonction du dns OU de l'ip
135sub resolve_ip_arp_host {
136   my $param_ip_or_host = shift;
137   my $interface = shift || '*';
138   my $type      = shift || 'fast';
139
140   my %ret = (
141      hostname_fq  => 'unknow',
142      ipv4_address => '0.0.0.0',
143      mac_address  => 'unknow',
144      );
145
146#   my $cmdarping  = `arping -c 1 -w 1 -rR $param 2>/dev/null`;
147
148   # controler que arpwatch tourne !
149   # resultat de la commande arpwatch
150   # /var/lib/arpwatch/arp.dat
151   # 0:13:d3:e1:92:d0        192.168.24.109  1163681980      theo8sv109
152   #my $cmd = "grep  -e '".'\b'."$param_ip_or_host".'\b'."' /var/lib/arpwatch/arp.dat | sort +2rn | head -1";
153#   my $cmd = "grep  -he '".'\b'."$param_ip_or_host".'\b'."' /var/lib/arpwatch/*.dat | sort +2rn | head -1";
154   my $cmd = "grep  -he '".'\b'."$param_ip_or_host".'\b'."' /var/lib/arpwatch/$interface.dat | sort -rn -k 2 | head -1";
155   my $cmd_arpwatch = `$cmd`;
156   chomp $cmd_arpwatch;
157   my ($arp, $ip, $timestamp, $host) = split /\s+/, $cmd_arpwatch;
158#print "OOO $cmd\n";
159#print "TTT arp $arp -> $ip pour host $host\n";
160   $ret{ipv4_address} = $ip        if $ip;
161   $ret{mac_address}  = $arp       if $arp;
162   $ret{timestamp}    = $timestamp if $timestamp;
163
164   my $nowtimestamp = time();
165
166   if ( $type eq 'fast' and ( not defined $timestamp or $timestamp < ( $nowtimestamp - 3 * 3600 ) ) ) {
167      $ret{mac_address} = 'unknow';
168      return %ret;
169      }
170
171  # resultat de la commande arp
172   # tech7meylan.hmg.inpg.fr (194.254.66.240) at 00:14:22:45:28:A9 [ether] on eth0
173   my $cmd_arp  = `arp -a $param_ip_or_host 2>/dev/null`;
174   chomp $cmd_arp;
175   $cmd_arp =~ /(\S*)\s\(([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})\)\sat\s([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})/;
176   $ret{hostname_fq}  = $1 if(defined($1));
177   $ret{ipv4_address} = $2 if(defined($2));
178   $ret{mac_address}  = $3 if(defined($3));
179
180#   if ($ret{ipv4_address} eq '0.0.0.0' and $ret{mac_address} eq 'unknow'and $ret{hostname_fq} eq 'unknow') {
181      # resultat de la commande host si le parametre est ip
182      # 250.66.254.194.in-addr.arpa domain name pointer legihp2100.hmg.inpg.fr.
183      my $cmd_host = `host $param_ip_or_host 2>/dev/null`;
184      chomp $cmd_host;
185      $cmd_host =~ m/domain\sname\spointer\s(\S+)\.$/;
186      $ret{hostname_fq} = $1 if defined $1;
187
188      # resultat de la commande host si parametre est hostname
189      # tech7meylan.hmg.inpg.fr has address 194.254.66.240
190      $cmd_host =~ m/\shas\saddress\s([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})$/;
191      $ret{ipv4_address} = $1 if defined $1;
192
193      $cmd_host =~ m/\b([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\.in-addr\.arpa\s/;
194      $ret{ipv4_address} = "$4.$3.$2.$1"     if defined $1 and  defined $2 and  defined $3 and  defined $4;
195      $ret{hostname_fq}  = $param_ip_or_host if not defined $1 and $ret{hostname_fq} eq 'unknow';
196#      }
197
198   unless ($ret{mac_address} eq 'unknow') {
199      my @paquets = ();
200      foreach ( split(/:/, $ret{mac_address}) ) {
201         my @chars = split //, uc("00$_");
202         push @paquets, "$chars[-2]$chars[-1]";
203         }
204      $ret{mac_address} = join ':', @paquets;
205      }
206
207   return %ret;
208   }
209
210# Find Surname of a switch
211sub get_switch_model {
212   my $sw_snmp_description = shift || 'unknow';
213   
214   for my $sw_kind (keys %SWITCH_KIND) {
215      next if not $sw_snmp_description =~ m/$SWITCH_KIND{$sw_kind}->{match}/;
216     
217      return $SWITCH_KIND{$sw_kind}->{model};
218      }
219     
220   return $sw_snmp_description;
221   }
222
223###
224# va rechercher le nom des switchs pour savoir qui est qui
225sub init_switch_names {
226   my $verbose = shift;
227   
228   printf "%-25s                %-25s %s\n",'Switch','Description','Type';
229#   print "Switch description\n" if $verbose;
230   print "-------------------------------------------------------------------------\n" if $verbose;
231
232   INIT_EACH_SWITCH:
233   for my $sw (@SWITCH) {
234      my %session = ( -hostname   => $sw->{hostname} );
235         $session{-version} = $sw->{version}   || 1;
236         $session{-port}    = $sw->{snmpport}  || $DEFAULT{snmpport}  || 161;
237         if (exists $sw->{version} and $sw->{version} eq 3) {
238            $session{-username} = $sw->{username} || 'snmpadmin';
239            }
240         else {
241            $session{-community} = $sw->{community} || $DEFAULT{community} || 'public';
242            }
243
244      $sw->{local_session} = \%session;
245
246      my ($session, $error) = Net::SNMP->session( %{$sw->{local_session}} );
247      print "$error \n" if $error;
248
249      my $result = $session->get_request(
250         -varbindlist => [
251            $OID_NUMBER{sysDescr},
252            $OID_NUMBER{sysName},
253            $OID_NUMBER{sysContact},
254            $OID_NUMBER{sysLocation},
255            ]
256         );
257      $sw->{description} = $result->{$OID_NUMBER{sysName}} || $sw->{hostname};
258      $sw->{model} = get_switch_model( $result->{$OID_NUMBER{sysDescr}});
259      #$sw->{location} = $result->{"1.3.6.1.2.1.1.6.0"} || $sw->{hostname};
260      #$sw->{contact} = $result->{"1.3.6.1.2.1.1.4.0"} || $sw->{hostname};
261      $session->close;
262
263      # Ligne à virer car on récupère maintenant le modèle du switch
264      my ($desc, $type) = split ':', $sw->{description}, 2;
265#      printf "%-25s 0--------->>>> %-25s %s\n", $sw->{hostname}, $desc, uc($type)."**" if $verbose;
266      printf "%-25s 0--------->>>> %-25s %s\n", $sw->{hostname}, $desc, $sw->{model} if $verbose;
267      }
268
269   print "\n" if $verbose;
270   }
271
272###
273# convertit l'hexa (uniquement 2 chiffres) en decimal
274sub hex_to_dec {
275   #00:0F:1F:43:E4:2B
276   my $car = '00' . uc(shift);
277
278   return '00' if $car eq '00UNKNOW';
279   my %table = (
280      "0"=>"0",  "1"=>"1",  "2"=>"2",  "3"=>"3",  "4"=>"4",  "5"=>"5", "6"=>"6", "7"=>"7", "8"=>"8", "9"=>"9",
281      "A"=>"10", "B"=>"11", "C"=>"12", "D"=>"13", "E"=>"14", "F"=>"15"
282      );
283   my @chars = split(//, $car);
284   return $table{$chars[-2]}*16 + $table{$chars[-1]};
285   }
286
287###
288# convertit l'@ arp en decimal
289sub arp_hex_to_dec {
290   #00:0F:1F:43:E4:2B
291   my $arp = shift;
292
293   my @paquets = split /:/, $arp;
294   my $return = '';
295   foreach(@paquets) {
296      $return .= ".".hex_to_dec($_);
297      }
298   return $return;
299   }
300
301###
302# va rechercher le port et le switch sur lequel est la machine
303sub find_switch_port {
304   my $arp = shift;
305   my $switch_proposal = shift || '';
306   
307   my %ret;
308   $ret{switch_description} = "unknow";
309   $ret{switch_port} = "0";
310
311   return %ret if $arp eq 'unknow';;
312
313   my @switch_search = @SWITCH;
314   if ($switch_proposal ne '') {
315      for my $sw (@SWITCH) {
316         next if $sw->{hostname} ne $switch_proposal;
317         unshift @switch_search, $sw;
318         last;
319         }
320      }
321
322   my $research = "1.3.6.1.2.1.17.4.3.1.2".arp_hex_to_dec($arp);
323   
324   LOOP_ON_SWITCH:
325   for my $sw (@switch_search) {
326      my ($session, $error) = Net::SNMP->session( %{$sw->{local_session}} );
327      print "$error \n" if $error;
328
329      my $result = $session->get_request(
330         -varbindlist => [$research]
331         );
332      if (not defined($result) or $result->{$research} eq 'noSuchInstance') {
333         $session->close;
334         next LOOP_ON_SWITCH;
335         }
336
337         my $swport = $result->{$research};
338         $session->close;
339
340         # IMPORTANT !!
341         # ceci empeche la detection sur certains port ...
342         # en effet les switch sont relies entre eux par un cable reseau et du coup
343         # tous les arp de toutes les machines sont presentes sur ces ports (ceux choisis ici sont les miens)
344         # cette partie est a ameliore, voir a configurer dans l'entete
345         # 21->24 45->48
346#         my $flag = 0;
347         SWITCH_PORT_IGNORE:
348         foreach my $p (@{$sw->{portignore}}) {
349            next SWITCH_PORT_IGNORE if $swport ne get_numerical_port($sw->{model},$p);
350#            $flag = 1;
351            next LOOP_ON_SWITCH;
352            }
353#         if ($flag == 0) {
354            $ret{switch_hostname}    = $sw->{hostname};
355            $ret{switch_description} = $sw->{description};
356            $ret{switch_port}        = get_human_readable_port($sw->{model}, $swport); # $swport;
357           
358            last LOOP_ON_SWITCH;
359#            }
360#         }
361#      $session->close;
362      }
363   return %ret;
364   }
365
366###
367# va rechercher les port et les switch sur lequel est la machine
368sub find_all_switch_port {
369   my $arp = shift;
370
371   my $ret = {};
372
373   return $ret if $arp eq 'unknow';
374
375   for my $sw (@SWITCH) {
376      $SWITCH_PORT_COUNT{$sw->{hostname}} = {} if not exists $SWITCH_PORT_COUNT{$sw->{hostname}};
377      }
378
379   my $research = "1.3.6.1.2.1.17.4.3.1.2".arp_hex_to_dec($arp);
380   LOOP_ON_ALL_SWITCH:
381   for my $sw (@SWITCH) {
382      my ($session, $error) = Net::SNMP->session( %{$sw->{local_session}} );
383      print "$error \n" if $error;
384
385      my $result = $session->get_request(
386         -varbindlist => [$research]
387         );
388
389      if(defined($result) and $result->{$research} ne 'noSuchInstance'){
390         my $swport = $result->{$research};
391
392         $ret->{$sw->{hostname}} = {};
393         $ret->{$sw->{hostname}}{hostname}    = $sw->{hostname};
394         $ret->{$sw->{hostname}}{description} = $sw->{description};
395         $ret->{$sw->{hostname}}{port}        = get_human_readable_port($sw->{model}, $swport);
396
397         $SWITCH_PORT_COUNT{$sw->{hostname}}->{$swport}++;
398         }
399
400      $session->close;
401      }
402   return $ret;
403   }
404
405sub get_list_network {
406
407   return keys %{$KLASK_CFG->{network}};
408   }
409
410sub get_current_interface {
411   my $network = shift;
412
413   return $KLASK_CFG->{network}{$network}{interface};
414   }
415 
416###
417# liste l'ensemble des adresses ip d'un réseau
418sub get_list_ip {
419   my @network = @_;
420
421   my $cidrlist = Net::CIDR::Lite->new;
422
423   for my $net (@network) {
424      my @line  = @{$KLASK_CFG->{network}{$net}{'ip-subnet'}};
425      for my $cmd (@line) {
426         for my $method (keys %$cmd){
427            $cidrlist->add_any($cmd->{$method}) if $method eq 'add';
428            }
429         }
430      }
431
432   my @res = ();
433
434   for my $cidr ($cidrlist->list()) {
435      my $net = new NetAddr::IP $cidr;
436      for my $ip (@$net) {
437         $ip =~ s#/32##;
438         push @res,  $ip;
439         }
440      }
441
442   return @res;
443   }
444
445# liste l'ensemble des routeurs du réseau
446sub get_list_main_router {
447   my @network = @_;
448
449   my @res = ();
450
451   for my $net (@network) {
452      push @res, $KLASK_CFG->{network}{$net}{'main-router'};
453      }
454
455   return @res;
456   }
457
458sub get_human_readable_port {
459   my $sw_model = shift;
460   my $sw_port  = shift;
461   
462   return $sw_port if not $sw_model eq 'HP8000M';
463   
464   my $reste = (($sw_port - 1) % 8) + 1;
465   my $major = int( ($sw_port - 1) / 8 );
466
467   return "$INTERNAL_PORT_MAP{$major}$reste";
468   }
469
470sub get_numerical_port {
471   my $sw_model = shift;
472   my $sw_port  = shift;
473   
474   return $sw_port if not $sw_model eq 'HP8000';
475
476   my $letter = substr($sw_port, 0, 1);
477   
478#   return $port if $letter =~ m/\d/;
479   
480   my $reste =  substr($sw_port, 1);
481   
482   return $INTERNAL_PORT_MAP_REV{$letter} * 8 + $reste;
483   }
484
485################
486# Les commandes
487################
488
489sub cmd_help {
490
491print <<END;
492klask - ports manager and finder for switch
493
494 klask updatedb
495 klask exportdf
496
497 klask searchdb computer
498 klask search   computer
499
500 klask enable  switch port
501 klask disable switch port
502 klask status  switch port
503END
504   }
505
506sub cmd_version {
507
508print <<END;
509Klask - ports manager and finder for switch
510Copyright (C) 2005-2008 Gabriel Moreau
511
512END
513   print ' $Rev: 43 $'."\n";
514   print ' $Date: 2008-11-27 14:03:01 +0000 (Thu, 27 Nov 2008) $'."\n";
515   print ' $Id: klask 43 2008-11-27 14:03:01Z g7moreau $'."\n";
516   }
517
518sub cmd_search {
519   my @computer = @_;
520   
521   init_switch_names();    #nomme les switchs
522   fastping(@computer);
523   for my $clientname (@computer) {
524      my %resol_arp = resolve_ip_arp_host($clientname);          #resolution arp
525      my %where     = find_switch_port($resol_arp{mac_address}); #retrouve l'emplacement
526      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"
527         unless $where{switch_description} eq 'unknow' and $resol_arp{hostname_fq} eq 'unknow' and $resol_arp{mac_address} eq 'unknow';
528      }
529   }
530
531sub cmd_searchdb {
532   my @computer = @_;
533
534   fastping(@computer);
535   my $computerdb = YAML::LoadFile("$KLASK_DB_FILE");
536   
537   LOOP_ON_COMPUTER:
538   for my $clientname (@computer) {
539      my %resol_arp = resolve_ip_arp_host($clientname);      #resolution arp
540      my $ip = $resol_arp{ipv4_address};
541     
542      next LOOP_ON_COMPUTER unless exists $computerdb->{$ip};
543     
544      my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($computerdb->{$ip}{timestamp});
545      $year += 1900;
546      $mon++;
547      my $date = sprintf "%04i-%02i-%02i %02i:%02i", $year,$mon,$mday,$hour,$min;
548
549      printf "%-22s %2s %-30s %-15s %-18s %s\n",
550         $computerdb->{$ip}{switch_name},
551         $computerdb->{$ip}{switch_port},
552         $computerdb->{$ip}{hostname_fq},
553         $ip,
554         $computerdb->{$ip}{mac_address},
555         $date;
556      }
557   }
558
559sub cmd_updatedb {
560   my @network = @_;
561      @network = get_list_network() if not @network;
562
563   test_switchdb_environnement();
564
565   my $computerdb = {};
566      $computerdb = YAML::LoadFile("$KLASK_DB_FILE") if -e "$KLASK_DB_FILE";
567   my $timestamp = time;
568
569   my %computer_not_detected = ();
570   my $timestamp_last_week = $timestamp - (3600 * 24 * 7);
571
572   my $number_of_computer = get_list_ip(@network); # + 1;
573   my $size_of_database   = keys %$computerdb;
574      $size_of_database   = 1 if $size_of_database == 0;
575   my $i = 0;
576   my $detected_computer = 0;
577
578   init_switch_names('yes');    #nomme les switchs
579
580   { # Remplis le champs portignore des ports d'inter-connection pour chaque switch
581   my $switch_connection = YAML::LoadFile("$KLASK_SW_FILE");
582   my %db_switch_output_port       = %{$switch_connection->{output_port}};
583   my %db_switch_connected_on_port = %{$switch_connection->{connected_on_port}};
584   my %db_switch_chained_port = ();
585   for my $swport (keys %db_switch_connected_on_port) {       
586      my ($sw_connect,$port_connect) = split ':', $swport;
587      $db_switch_chained_port{$sw_connect} .= "$port_connect:";
588      }
589   for my $sw (@SWITCH){
590      push @{$sw->{portignore}}, $db_switch_output_port{$sw->{hostname}}  if exists $db_switch_output_port{$sw->{hostname}};
591      if ( exists $db_switch_chained_port{$sw->{hostname}} ) {
592         chop $db_switch_chained_port{$sw->{hostname}};
593         push @{$sw->{portignore}}, split(':',$db_switch_chained_port{$sw->{hostname}});
594         }
595#      print "$sw->{hostname} ++ @{$sw->{portignore}}\n";
596      }
597   }
598
599   my %router_mac_ip = ();
600   DETECT_ALL_ROUTER:
601#   for my $one_router ('194.254.66.254') {
602   for my $one_router ( get_list_main_router(@network) ) {
603      my %resol_arp = resolve_ip_arp_host($one_router);
604      $router_mac_ip{ $resol_arp{mac_address} } = $resol_arp{ipv4_address};
605      }
606
607   ALL_NETWORK:
608   for my $net (@network) {
609
610      my @computer = get_list_ip($net);
611      my $current_interface = get_current_interface($net);
612
613      fastping(@computer);
614
615      LOOP_ON_COMPUTER:
616      for my $one_computer (@computer) {
617         $i++;
618         
619         my $total_percent = int(($i*100)/$number_of_computer);
620
621         my $localtime = time - $timestamp;
622         my ($sec,$min) = localtime($localtime);
623
624         my $time_elapse = 0;
625            $time_elapse = $localtime * ( 100 - $total_percent) / $total_percent if $total_percent != 0;
626         my ($sec_elapse,$min_elapse) = localtime($time_elapse);
627
628         printf "\rComputer scanned: %4i/%i (%2i%%)",  $i,                 $number_of_computer, $total_percent;
629#         printf ", Computer detected: %4i/%i (%2i%%)", $detected_computer, $size_of_database,   int(($detected_computer*100)/$size_of_database);
630         printf ", detected: %4i/%i (%2i%%)", $detected_computer, $size_of_database,   int(($detected_computer*100)/$size_of_database);
631         printf " [Time: %02i:%02i / %02i:%02i]", int($localtime/60), $localtime % 60, int($time_elapse/60), $time_elapse % 60;
632#         printf "  [%02i:%02i/%02i:%02i]", int($localtime/60), $localtime % 60, int($time_elapse/60), $time_elapse % 60;
633         printf " %-14s", $one_computer;
634
635         my %resol_arp = resolve_ip_arp_host($one_computer,$current_interface);
636         
637         # do not search on router connection (why ?)
638         if ( exists $router_mac_ip{$resol_arp{mac_address}}) {
639            $computer_not_detected{$one_computer} = $current_interface;
640            next LOOP_ON_COMPUTER;
641            }
642
643         # do not search on switch inter-connection
644         if (exists $switch_level{$resol_arp{hostname_fq}}) {
645            $computer_not_detected{$one_computer} = $current_interface;
646            next LOOP_ON_COMPUTER;
647            }
648
649         my $switch_proposal = '';
650         if (exists $computerdb->{$resol_arp{ipv4_address}} and exists $computerdb->{$resol_arp{ipv4_address}}{switch_hostname}) {
651            $switch_proposal = $computerdb->{$resol_arp{ipv4_address}}{switch_hostname};
652            }
653
654         # do not have a mac address
655         if ($resol_arp{mac_address} eq 'unknow' or (exists $resol_arp{timestamps} and $resol_arp{timestamps} < ($timestamp - 3 * 3600))) {
656            $computer_not_detected{$one_computer} = $current_interface;
657            next LOOP_ON_COMPUTER;
658            }
659
660         my %where = find_switch_port($resol_arp{mac_address},$switch_proposal);
661
662         #192.168.24.156:
663         #  arp: 00:0B:DB:D5:F6:65
664         #  hostname: pcroyon.hmg.priv
665         #  port: 5
666         #  switch: sw-batH-legi:hp2524
667         #  timestamp: 1164355525
668
669         # do not have a mac address
670#         if ($resol_arp{mac_address} eq 'unknow') {
671#            $computer_not_detected{$one_computer} = $current_interface;
672#            next LOOP_ON_COMPUTER;
673#            }
674
675         # detected on a switch
676         if ($where{switch_description} ne 'unknow') {
677            $detected_computer++;
678            $computerdb->{$resol_arp{ipv4_address}} = {
679               hostname_fq        => $resol_arp{hostname_fq},
680               mac_address        => $resol_arp{mac_address},
681               switch_hostname    => $where{switch_hostname},
682               switch_description => $where{switch_description},
683               switch_port        => $where{switch_port},
684               timestamp          => $timestamp,
685               };
686            next LOOP_ON_COMPUTER;
687            }
688
689         # new in the database but where it is ?
690         if (not exists $computerdb->{$resol_arp{ipv4_address}}) {
691            $detected_computer++;
692            $computerdb->{$resol_arp{ipv4_address}} = {
693               hostname_fq        => $resol_arp{hostname_fq},
694               mac_address        => $resol_arp{mac_address},
695               switch_hostname    => $where{switch_hostname},
696               switch_description => $where{switch_description},
697               switch_port        => $where{switch_port},
698               timestamp          => $resol_arp{timestamp},
699               };
700            }
701
702         # mise a jour du nom de la machine si modification dans le dns
703         $computerdb->{$resol_arp{ipv4_address}}{hostname_fq} = $resol_arp{hostname_fq};
704       
705         # mise à jour de la date de détection si détection plus récente par arpwatch
706         $computerdb->{$resol_arp{ipv4_address}}{timestamp}   = $resol_arp{timestamp} if exists $resol_arp{timestamp} and $computerdb->{$resol_arp{ipv4_address}}{timestamp} < $resol_arp{timestamp};
707
708         # provisoire car changement de nom des attributs
709#         $computerdb->{$resol_arp{ipv4_address}}{mac_address}        = $computerdb->{$resol_arp{ipv4_address}}{arp};
710#         $computerdb->{$resol_arp{ipv4_address}}{switch_description} = $computerdb->{$resol_arp{ipv4_address}}{switch};
711#         $computerdb->{$resol_arp{ipv4_address}}{switch_port}        = $computerdb->{$resol_arp{ipv4_address}}{port};
712       
713         # relance un arping sur la machine si celle-ci n'a pas été détectée depuis plus d'une semaine
714#         push @computer_not_detected, $resol_arp{ipv4_address} if $computerdb->{$resol_arp{ipv4_address}}{timestamp} < $timestamp_last_week;
715         $computer_not_detected{$resol_arp{ipv4_address}} = $current_interface if $computerdb->{$resol_arp{ipv4_address}}{timestamp} < $timestamp_last_week;
716       
717         }
718      }
719
720   # final end of line at the end of the loop
721   printf "\n";
722
723   my $dirdb = $KLASK_DB_FILE;
724      $dirdb =~ s#/[^/]*$##;
725   mkdir "$dirdb", 0755 unless -d "$dirdb";
726   YAML::DumpFile("$KLASK_DB_FILE", $computerdb);
727
728   for my $one_computer (keys %computer_not_detected) {
729      my $interface = $computer_not_detected{$one_computer};
730      system "arping -c 1 -w 1 -rR -i $interface $one_computer &>/dev/null";
731#      print  "arping -c 1 -w 1 -rR -i $interface $one_computer 2>/dev/null\n";
732      }
733   }
734
735sub cmd_removedb {
736   my @computer = @_;
737
738   test_maindb_environnement();
739
740   my $computerdb = YAML::LoadFile("$KLASK_DB_FILE");
741
742   LOOP_ON_COMPUTER:
743   for my $one_computer (@computer) {
744
745      my %resol_arp = resolve_ip_arp_host($one_computer);
746
747      delete $computerdb->{$resol_arp{ipv4_address}} if exists $computerdb->{$resol_arp{ipv4_address}};
748      }
749
750   my $dirdb = $KLASK_DB_FILE;
751      $dirdb =~ s#/[^/]*$##;
752   mkdir "$dirdb", 0755 unless -d "$dirdb";
753   YAML::DumpFile("$KLASK_DB_FILE", $computerdb);
754   }
755
756sub cmd_exportdb {
757   test_maindb_environnement();
758
759   my $computerdb = YAML::LoadFile("$KLASK_DB_FILE");
760
761   printf "%-24s %-4s            %-30s %-15s %-18s %-s\n", qw(Switch Port Hostname IPv4-Address MAC-Address Date);
762   print "---------------------------------------------------------------------------------------------------------------------------\n";
763
764   LOOP_ON_IP_ADDRESS:
765   foreach my $ip (Net::Netmask::sort_by_ip_address(keys %$computerdb)) {
766   
767#      next LOOP_ON_IP_ADDRESS if $computerdb->{$ip}{hostname_fq} eq 'unknow';
768
769      # to be improve in the future
770      next LOOP_ON_IP_ADDRESS if $computerdb->{$ip}{hostname_fq} eq ($computerdb->{$ip}{switch_hostname} || $computerdb->{$ip}{switch_description}); # switch on himself !
771
772# dans le futur
773#      next if $computerdb->{$ip}{hostname_fq} eq 'unknow';
774     
775      my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($computerdb->{$ip}{timestamp});
776      $year += 1900;
777      $mon++;
778      my $date = sprintf "%04i-%02i-%02i %02i:%02i", $year,$mon,$mday,$hour,$min;
779
780      printf "%-25s  %2s  <-------  %-30s %-15s %-18s %s\n",
781         $computerdb->{$ip}{switch_hostname} || $computerdb->{$ip}{switch_description},
782         $computerdb->{$ip}{switch_port},
783         $computerdb->{$ip}{hostname_fq},
784         $ip,
785         $computerdb->{$ip}{mac_address},
786         $date;
787      }
788   }
789
790sub cmd_iplocation {
791   my $computerdb = YAML::LoadFile("$KLASK_DB_FILE");
792
793   LOOP_ON_IP_ADDRESS:
794   foreach my $ip (Net::Netmask::sort_by_ip_address(keys %$computerdb)) {
795
796      next LOOP_ON_IP_ADDRESS if $computerdb->{$ip}{hostname_fq} eq ($computerdb->{$ip}{switch_hostname} || $computerdb->{$ip}{switch_description}); # switch on himself !
797
798      my $sw_hostname = $computerdb->{$ip}{switch_hostname} || '';
799      next if $sw_hostname eq 'unknow';
800 
801      my $sw_location = '';
802      for my $sw (@SWITCH) {
803         next if $sw_hostname ne $sw->{hostname};
804         $sw_location = $sw->{location};
805         last;
806         }
807
808      printf "%s: \"%s\"\n", $ip, $sw_location if not $sw_location eq '';
809      }
810   }
811
812sub cmd_enable {
813   my $switch = shift;
814   my $port   = shift;
815   
816   #snmpset -v 1 -c community X.X.X.X 1.3.6.1.2.1.2.2.1.7.NoPort = 1 (up)
817   #snmpset -v 1 -c community X.X.X.X 1.3.6.1.2.1.2.2.1.7.NoPort = 2 (down)
818   system "snmpset -v 1 -c public $switch 1.3.6.1.2.1.2.2.1.7.$port = 1";
819   }
820
821sub cmd_disable {
822   my $switch = shift;
823   my $port   = shift;
824   
825   system "snmpset -v 1 -c public $switch 1.3.6.1.2.1.2.2.1.7.$port = 2";
826   }
827
828sub cmd_status {
829   my $switch = shift;
830   my $port   = shift;
831   
832   system "snmpget -v 1 -c public $switch 1.3.6.1.2.1.2.2.1.7.$port";
833   }
834
835sub cmd_search_mac_on_switch {
836   my $switch_name = shift || '';
837   my $mac_address = shift || '';
838   
839   if ($switch_name eq '' or $mac_address eq '') {
840      die "Usage: klask search-mac-on-switch SWITCH_NAME MAC_ADDRESS\n";
841      }
842
843   if (not defined $SWITCH_DB{$switch_name}) {
844      die "Switch $switch_name must be defined in klask configuration file\n"; 
845      }
846
847   my $sw = $SWITCH_DB{$switch_name};
848   my %session = ( -hostname => $sw->{hostname} );
849      $session{-version} = $sw->{version}   || 1;
850      $session{-port}    = $sw->{snmpport}  || $DEFAULT{snmpport}  || 161;
851   if (exists $sw->{version} and $sw->{version} eq 3) {
852      $session{-username} = $sw->{username} || 'snmpadmin';
853      }
854   else {
855      $session{-community} = $sw->{community} || $DEFAULT{community} || 'public';
856      }
857
858   my $research = "1.3.6.1.2.1.17.4.3.1.2".arp_hex_to_dec($mac_address);
859   print "Klask search OID $research on switch $switch_name\n";
860
861   my ($session, $error) = Net::SNMP->session( %session );
862   print "$error \n" if $error;
863
864   my $result = $session->get_request(
865      -varbindlist => [$research]
866      );
867   
868   if (not defined($result) or $result->{$research} eq 'noSuchInstance') {
869      print "Klask do not find MAC $mac_address on switch $switch_name\n";
870      $session->close;
871      }
872
873   my $swport = $result->{$research};
874   $session->close;
875
876   print "Klask find MAC $mac_address on switch $switch_name port $swport\n";
877   }
878
879sub cmd_updatesw {
880
881   init_switch_names('yes');    #nomme les switchs
882   print "\n";
883
884   my %where = ();
885   my %db_switch_output_port = ();
886   my %db_switch_ip_hostname = ();
887
888   DETECT_ALL_ROUTER:
889#   for my $one_computer ('194.254.66.254') {
890   for my $one_router ( get_list_main_router(get_list_network()) ) {
891      my %resol_arp = resolve_ip_arp_host($one_router,'*','low');            # resolution arp
892      next DETECT_ALL_ROUTER if $resol_arp{mac_address} eq 'unknow';
893     
894      $where{$resol_arp{ipv4_address}} = find_all_switch_port($resol_arp{mac_address}); # retrouve les emplacements des routeurs
895      }
896
897   ALL_ROUTER_IP_ADDRESS:
898   for my $ip (Net::Netmask::sort_by_ip_address(keys %where)) { # '194.254.66.254')) {
899   
900      next ALL_ROUTER_IP_ADDRESS if not exists $where{$ip}; # /a priori/ idiot car ne sers à rien...
901
902      ALL_SWITCH_CONNECTED:
903      for my $switch_detected ( keys %{$where{$ip}} ) {
904
905         my $switch = $where{$ip}->{$switch_detected};
906
907         next ALL_SWITCH_CONNECTED if $switch->{port} eq '0';
908         
909         $db_switch_output_port{$switch->{hostname}} = $switch->{port};
910         }
911      }   
912
913#   print "Switch output port\n"; 
914#   print "------------------\n";
915#   for my $sw (sort keys %db_switch_output_port) {
916#      printf "%-25s %2s\n", $sw, $db_switch_output_port{$sw};
917#      }
918#   print "\n";
919
920
921   my %db_switch_link_with = ();
922
923   my @list_switch_ip = ();
924   my @list_switch_ipv4 = ();
925   for my $sw (@SWITCH){
926      push @list_switch_ip, $sw->{hostname};
927      }
928
929   ALL_SWITCH:
930   for my $one_computer (@list_switch_ip) {
931      my %resol_arp = resolve_ip_arp_host($one_computer,'*','low'); # arp resolution
932      next ALL_SWITCH if $resol_arp{mac_address} eq 'unknow';
933     
934      push @list_switch_ipv4,$resol_arp{ipv4_address};
935     
936      $where{$resol_arp{ipv4_address}} = find_all_switch_port($resol_arp{mac_address}); # find port on all switch
937
938      $db_switch_ip_hostname{$resol_arp{ipv4_address}} = $resol_arp{hostname_fq};
939      }
940     
941   ALL_SWITCH_IP_ADDRESS:
942   for my $ip (Net::Netmask::sort_by_ip_address(@list_switch_ipv4)) {
943   
944      next ALL_SWITCH_IP_ADDRESS if not exists $where{$ip};
945
946      DETECTED_SWITCH:
947      for my $switch_detected ( keys %{$where{$ip}} ) {
948
949         next DETECTED_SWITCH if not exists $SWITCH_PORT_COUNT{ $db_switch_ip_hostname{$ip}};
950
951         my $switch = $where{$ip}->{$switch_detected};
952
953         next if $switch->{port}     eq '0';
954         next if $switch->{port}     eq $db_switch_output_port{$switch->{hostname}};
955         next if $switch->{hostname} eq $db_switch_ip_hostname{$ip}; # $computerdb->{$ip}{hostname};
956
957         $db_switch_link_with{ $db_switch_ip_hostname{$ip} } ||= {};
958         $db_switch_link_with{ $db_switch_ip_hostname{$ip} }->{ $switch->{hostname} } = $switch->{port};
959         }
960
961      }
962   
963   my %db_switch_connected_on_port = ();
964   my $maybe_more_than_one_switch_connected = 'yes';
965   
966   while ($maybe_more_than_one_switch_connected eq 'yes') {
967      for my $sw (keys %db_switch_link_with) {
968         for my $connect (keys %{$db_switch_link_with{$sw}}) {
969         
970            my $port = $db_switch_link_with{$sw}->{$connect};
971         
972            $db_switch_connected_on_port{"$connect:$port"} ||= {};
973            $db_switch_connected_on_port{"$connect:$port"}->{$sw}++; # Just to define the key
974            }
975         }
976
977      $maybe_more_than_one_switch_connected  = 'no';
978
979      SWITCH_AND_PORT:
980      for my $swport (keys %db_switch_connected_on_port) {
981         
982         next if keys %{$db_switch_connected_on_port{$swport}} == 1;
983         
984         $maybe_more_than_one_switch_connected = 'yes';
985
986         my ($sw_connect,$port_connect) = split ':', $swport;
987         my @sw_on_same_port = keys %{$db_switch_connected_on_port{$swport}};
988
989         CONNECTED:
990         for my $sw_connected (@sw_on_same_port) {
991           
992            next CONNECTED if not keys %{$db_switch_link_with{$sw_connected}} == 1;
993           
994            $db_switch_connected_on_port{$swport} = {$sw_connected => 1};
995           
996            for my $other_sw (@sw_on_same_port) {
997               next if $other_sw eq $sw_connected;
998               
999               delete $db_switch_link_with{$other_sw}->{$sw_connect};
1000               }
1001           
1002            # We can not do better for this switch for this loop
1003            next SWITCH_AND_PORT;
1004            }
1005         }
1006      }
1007
1008   my %db_switch_parent =();
1009
1010   for my $sw (keys %db_switch_link_with) {
1011      for my $connect (keys %{$db_switch_link_with{$sw}}) {
1012     
1013         my $port = $db_switch_link_with{$sw}->{$connect};
1014     
1015         $db_switch_connected_on_port{"$connect:$port"} ||= {};
1016         $db_switch_connected_on_port{"$connect:$port"}->{$sw} = $port;
1017       
1018         $db_switch_parent{$sw} = {switch => $connect, port => $port};
1019         }
1020      }
1021
1022   print "Switch output port and parent port connection\n"; 
1023   print "---------------------------------------------\n";
1024   for my $sw (sort keys %db_switch_output_port) {
1025      if (exists $db_switch_parent{$sw}) {
1026         printf "%-25s  %2s  +-->  %2s  %-25s\n", $sw, $db_switch_output_port{$sw}, $db_switch_parent{$sw}->{port}, $db_switch_parent{$sw}->{switch};
1027         }
1028      else {
1029         printf "%-25s  %2s  +-->  router\n", $sw, $db_switch_output_port{$sw};
1030         }
1031      }
1032   print "\n";
1033
1034   print "Switch parent and children port inter-connection\n";
1035   print "------------------------------------------------\n";
1036   for my $swport (sort keys %db_switch_connected_on_port) {       
1037      my ($sw_connect,$port_connect) = split ':', $swport;
1038      for my $sw (keys %{$db_switch_connected_on_port{$swport}}) {
1039         if (exists $db_switch_output_port{$sw}) {
1040            printf "%-25s  %2s  <--+  %2s  %-25s\n", $sw_connect, $port_connect, $db_switch_output_port{$sw}, $sw;
1041            }
1042         else {
1043            printf "%-25s  %2s  <--+      %-25s\n", $sw_connect, $port_connect, $sw;
1044            }
1045         }
1046      }
1047
1048   my $switch_connection = {
1049      output_port       => \%db_switch_output_port,
1050      parent            => \%db_switch_parent,
1051      connected_on_port => \%db_switch_connected_on_port,
1052      link_with         => \%db_switch_link_with,
1053      switch_db         => \%SWITCH_DB,
1054      };
1055     
1056   YAML::DumpFile("$KLASK_SW_FILE", $switch_connection);
1057   }
1058
1059sub cmd_exportsw {
1060   my @ARGV   = @_;
1061
1062   test_switchdb_environnement();
1063
1064   my $format = 'txt';
1065
1066   my $ret = GetOptions(
1067      'format|f=s'  => \$format,
1068      );
1069
1070   my %possible_format = (
1071      txt => \&cmd_exportsw_txt,
1072      dot => \&cmd_exportsw_dot,
1073      );
1074
1075   $format = 'txt' if not defined $possible_format{$format};
1076   
1077   $possible_format{$format}->(@ARGV);
1078   }
1079
1080sub cmd_exportsw_txt {
1081
1082   my $switch_connection = YAML::LoadFile("$KLASK_SW_FILE");
1083
1084   my %db_switch_output_port       = %{$switch_connection->{output_port}};
1085   my %db_switch_parent            = %{$switch_connection->{parent}};
1086   my %db_switch_connected_on_port = %{$switch_connection->{connected_on_port}};
1087
1088   print "Switch output port and parent port connection\n"; 
1089   print "---------------------------------------------\n";
1090   for my $sw (sort keys %db_switch_output_port) {
1091      if (exists $db_switch_parent{$sw}) {
1092         printf "%-25s  %2s  +-->  %2s  %-25s\n", $sw, $db_switch_output_port{$sw}, $db_switch_parent{$sw}->{port}, $db_switch_parent{$sw}->{switch};
1093         }
1094      else {
1095         printf "%-25s  %2s  +-->  router\n", $sw, $db_switch_output_port{$sw};
1096         }
1097      }
1098   print "\n";
1099
1100   print "Switch parent and children port inter-connection\n";
1101   print "------------------------------------------------\n";
1102   for my $swport (sort keys %db_switch_connected_on_port) {       
1103      my ($sw_connect,$port_connect) = split ':', $swport;
1104      for my $sw (keys %{$db_switch_connected_on_port{$swport}}) {
1105         if (exists $db_switch_output_port{$sw}) {
1106            printf "%-25s  %2s  <--+  %2s  %-25s\n", $sw_connect, $port_connect, $db_switch_output_port{$sw}, $sw;
1107            }
1108         else {
1109            printf "%-25s  %2s  <--+      %-25s\n", $sw_connect, $port_connect, $sw;
1110            }
1111         }
1112      }
1113   }
1114
1115sub cmd_exportsw_dot {
1116
1117   my $switch_connection = YAML::LoadFile("$KLASK_SW_FILE");
1118   
1119   my %db_switch_output_port       = %{$switch_connection->{output_port}};
1120   my %db_switch_parent            = %{$switch_connection->{parent}};
1121   my %db_switch_connected_on_port = %{$switch_connection->{connected_on_port}};
1122   my %db_switch_link_with         = %{$switch_connection->{link_with}};
1123   my %db_switch_global            = %{$switch_connection->{switch_db}};
1124
1125   my %db_building= ();
1126   for my $sw (@SWITCH) {
1127      my ($building, $location) = split /\//, $sw->{location}, 2;
1128      $db_building{$building} ||= {};
1129      $db_building{$building}->{$location} ||= {};
1130      $db_building{$building}->{$location}{ $sw->{hostname} } = 'y';
1131      }
1132 
1133 
1134   print "digraph G {\n";
1135
1136   print "site [label = \"site\", color = black, fillcolor = gold, shape = invhouse, style = filled];\n";
1137   print "internet [label = \"internet\", color = black, fillcolor = cyan, shape = house, style = filled];\n";
1138
1139   my $b=0;
1140   for my $building (keys %db_building) {
1141      $b++;
1142     
1143      print "\"building$b\" [label = \"$building\", color = black, fillcolor = gold, style = filled];\n";
1144      print "site -> \"building$b\" [len = 2, color = firebrick];\n";
1145
1146      my $l = 0;
1147      for my $loc (keys %{$db_building{$building}}) {
1148         $l++;
1149 
1150         print "\"location$b-$l\" [label = \"$building".'/'.join('\n',split("/",$loc))."\", color = black, fillcolor = orange, style = filled];\n";
1151#         print "\"location$b-$l\" [label = \"$building / $loc\", color = black, fillcolor = orange, style = filled];\n";
1152         print "\"building$b\" -> \"location$b-$l\" [len = 2, color = firebrick]\n";
1153
1154         for my $sw (keys %{$db_building{$building}->{$loc}}) {
1155
1156            print "\"$sw:$db_switch_output_port{$sw}\" [label = $db_switch_output_port{$sw}, color = black, fillcolor = lightblue,  peripheries = 2, style = filled];\n";
1157
1158            my $swname  = $sw;
1159               $swname .= '\n-\n'."$db_switch_global{$sw}->{model}" if exists $db_switch_global{$sw} and exists $db_switch_global{$sw}->{model};
1160            print "\"$sw\" [label = \"$swname\", color = black, fillcolor = palegreen, shape = rect, style = filled];\n";
1161            print "\"location$b-$l\" -> \"$sw\" [len = 2, color = firebrick, arrowtail = dot]\n";
1162            print "\"$sw\" -> \"$sw:$db_switch_output_port{$sw}\" [len=2, style=bold, arrowhead = normal, arrowtail = invdot]\n";
1163
1164
1165            for my $swport (keys %db_switch_connected_on_port) {
1166               my ($sw_connect,$port_connect) = split ':', $swport;
1167               next if not $sw_connect eq $sw;
1168               next if $port_connect eq $db_switch_output_port{$sw};
1169               print "\"$sw:$port_connect\" [label = $port_connect, color = black, fillcolor = plum,  peripheries = 1, style = filled];\n";
1170               print "\"$sw:$port_connect\" -> \"$sw\" [len=2, style=bold, arrowhead= normal, arrowtail = inv]\n";
1171              }
1172            }
1173         }
1174      }
1175
1176#   print "Switch output port and parent port connection\n"; 
1177#   print "---------------------------------------------\n";
1178   for my $sw (sort keys %db_switch_output_port) {
1179      if (exists $db_switch_parent{$sw}) {
1180#         printf "   \"%s:%s\" -> \"%s:%s\"\n", $sw, $db_switch_output_port{$sw}, $db_switch_parent{$sw}->{switch}, $db_switch_parent{$sw}->{port};
1181         }
1182      else {
1183         printf "   \"%s:%s\" -> internet\n", $sw, $db_switch_output_port{$sw};
1184         }
1185      }
1186   print "\n";
1187
1188#   print "Switch parent and children port inter-connection\n";
1189#   print "------------------------------------------------\n";
1190   for my $swport (sort keys %db_switch_connected_on_port) {       
1191      my ($sw_connect,$port_connect) = split ':', $swport;
1192      for my $sw (keys %{$db_switch_connected_on_port{$swport}}) {
1193         if (exists $db_switch_output_port{$sw}) {
1194            printf "   \"%s:%s\" -> \"%s:%s\" [color = navyblue]\n", $sw, $db_switch_output_port{$sw}, $sw_connect, $port_connect;
1195            }
1196         else {
1197            printf "   \"%s\"   -> \"%s%s\"\n", $sw, $sw_connect, $port_connect;
1198            }
1199         }
1200      }
1201
1202print "}\n";
1203   }
1204
1205
1206__END__
1207
1208
1209=head1 NAME
1210
1211klask - ports manager and finder for switch
1212
1213
1214=head1 SYNOPSIS
1215
1216 klask updatedb
1217 klask exportdb
1218
1219 klask updatesw
1220 klask exportsw --format [txt|dot]
1221
1222 klask searchdb computer
1223 klask search   computer
1224
1225 klask enable  switch port
1226 klask disable swith port
1227 klask status  swith port
1228
1229
1230=head1 DESCRIPTION
1231
1232klask is a small tool to find where is a host in a big network. klask mean search in brittany.
1233
1234Klask has now a web site dedicated for it !
1235
1236 http://servforge.legi.inpg.fr/projects/klask
1237
1238
1239=head1 COMMANDS
1240
1241
1242=head2 search
1243
1244This command takes one or more computer in argument. It search a computer on the network and give the port and the switch on which the computer is connected.
1245
1246
1247=head2 enable
1248
1249This command activate a port on a switch by snmp. So you need to give the switch and the port number on the command line.
1250
1251
1252=head2 disable
1253
1254This command deactivate a port on a switch by snmp. So you need to give the switch and the port number on the command line.
1255
1256
1257=head2 status
1258
1259This command return the status of a port number on a switch by snmp. So you need to give the switch name and the port number on the command line.
1260
1261
1262=head2 updatedb
1263
1264This command will scan networks and update a database. To know which are the cmputer scan, you have to configure the file /etc/klask.conf This file is easy to read and write because klask use YAML format and not XML.
1265
1266
1267=head2 exportdb
1268
1269This command print the content of the database. There is actually only one format. It's very easy to have more format, it's just need times...
1270
1271
1272=head2 updatesw
1273
1274This command build a map of your manageable switch on your network. The list of the switch must be given in the file /etc/klask.conf.
1275
1276
1277=head2 exportsw --format [txt|dot]
1278
1279This command print the content of the switch database. There is actually two format. One is just txt for terminal and the other is the dot format from the graphviz environnement.
1280
1281 klask exportsw --format dot > /tmp/map.dot
1282 dot -Tpng /tmp/map.dot > /tmp/map.png
1283
1284
1285
1286=head1 CONFIGURATION
1287
1288Because klask need many parameters, it's not possible actually to use command line parameters. The configuration is done in a /etc/klask.conf YAML file. This format have many advantage over XML, it's easier to read and to write !
1289
1290Here an example, be aware with indent, it's important in YAML, do not use tabulation !
1291
1292 default:
1293   community: public
1294   snmpport: 161
1295
1296 network:
1297   labnet:
1298     ip-subnet:
1299       - add: 192.168.1.0/24
1300       - add: 192.168.2.0/24
1301     interface: eth0
1302     main-router: gw1.labnet.local
1303
1304   schoolnet:
1305     ip-subnet:
1306       - add: 192.168.6.0/24
1307       - add: 192.168.7.0/24
1308     interface: eth0.38
1309     main-router: gw2.schoolnet.local
1310
1311 switch:
1312   - hostname: sw1.klask.local
1313     portignore:
1314       - 1
1315       - 2
1316
1317   - hostname: sw2.klask.local
1318     location: BatK / 2 / K203
1319     type: HP2424
1320     portignore:
1321       - 1
1322       - 2
1323
1324I think it's pretty easy to understand. The default section can be overide in any section, if parameter mean something in theses sections. Network to be scan are define in the network section. You must put a add by network. Maybe i will make a delete line to suppress specific computers. The switch section define your switch. You have to write the port number to ignore, this is important if your switchs are cascade. Juste put the ports numbers between switch.
1325
1326
1327=head1 FILES
1328
1329 /etc/klask.conf
1330 /var/cache/klask/klaskdb
1331 /var/cache/klask/switchdb
1332
1333=head1 SEE ALSO
1334
1335Net::SNMP, Net::Netmask, Net::CIDR::Lite, NetAddr::IP, YAML
1336
1337
1338=head1 VERSION
1339
1340$Id: klask 43 2008-11-27 14:03:01Z g7moreau $
1341
1342
1343=head1 AUTHOR
1344
1345Written by Gabriel Moreau, Grenoble - France
1346
1347
1348=head1 COPYRIGHT
1349       
1350Copyright (C) 2005-2008 Gabriel Moreau.
1351
1352
1353=head1 LICENCE
1354
1355GPL version 2 or later and Perl equivalent
Note: See TracBrowser for help on using the repository browser.