source: trunk/klask @ 36

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