source: trunk/klask @ 38

Last change on this file since 38 was 38, checked in by g7moreau, 16 years ago
  • Put default argument on the command line.
  • Property svn:executable set to *
  • Property svn:keywords set to Date Author Id Rev
File size: 44.0 KB
Line 
1#!/usr/bin/perl -w
2#
3# Copyright (C) 2005-2008 Gabriel Moreau.
4#
5# $Id: klask 38 2008-02-13 13:55:29Z 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 ' $Rev: 38 $'."\n";
512   print ' $Date: 2008-02-13 13:55:29 +0000 (Wed, 13 Feb 2008) $'."\n";
513   print ' $Id: klask 38 2008-02-13 13:55:29Z 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   if ($switch_name eq '' or $mac_address eq '') {
838      print "Usage: klask search-mac-on-switch SWITCH_NAME MAC_ADDRESS\n";
839      exit 1;
840      }
841   
842   my $research = "1.3.6.1.2.1.17.4.3.1.2".arp_hex_to_dec($mac_address);
843   print "Klask search OID $research on switch $switch_name\n";
844
845   my ($session, $error) = Net::SNMP->session( -hostname => $switch_name );
846   print "$error \n" if $error;
847
848   my $result = $session->get_request(
849      -varbindlist => [$research]
850      );
851   
852   if (not defined($result) or $result->{$research} eq 'noSuchInstance') {
853      print "Klask do not find MAC $mac_address on switch $switch_name\n";
854      $session->close;
855      }
856
857   my $swport = $result->{$research};
858   $session->close;
859
860   print "Klask find MAC $mac_address on switch $switch_name port $swport\n";
861   }
862
863sub cmd_updatesw {
864
865   init_switch_names('yes');    #nomme les switchs
866   print "\n";
867
868   my %where = ();
869   my %db_switch_output_port = ();
870   my %db_switch_ip_hostname = ();
871
872   DETECT_ALL_ROUTER:
873#   for my $one_computer ('194.254.66.254') {
874   for my $one_router ( get_list_main_router(get_list_network()) ) {
875      my %resol_arp = resolve_ip_arp_host($one_router,'*','low');            # resolution arp
876      next DETECT_ALL_ROUTER if $resol_arp{mac_address} eq 'unknow';
877     
878      $where{$resol_arp{ipv4_address}} = find_all_switch_port($resol_arp{mac_address}); # retrouve les emplacements des routeurs
879      }
880
881   ALL_ROUTER_IP_ADDRESS:
882   for my $ip (Net::Netmask::sort_by_ip_address(keys %where)) { # '194.254.66.254')) {
883   
884      next ALL_ROUTER_IP_ADDRESS if not exists $where{$ip}; # /a priori/ idiot car ne sers à rien...
885
886      ALL_SWITCH_CONNECTED:
887      for my $switch_detected ( keys %{$where{$ip}} ) {
888
889         my $switch = $where{$ip}->{$switch_detected};
890
891         next ALL_SWITCH_CONNECTED if $switch->{port} eq '0';
892         
893         $db_switch_output_port{$switch->{hostname}} = $switch->{port};
894         }
895      }   
896
897#   print "Switch output port\n"; 
898#   print "------------------\n";
899#   for my $sw (sort keys %db_switch_output_port) {
900#      printf "%-25s %2s\n", $sw, $db_switch_output_port{$sw};
901#      }
902#   print "\n";
903
904
905   my %db_switch_link_with = ();
906
907   my @list_switch_ip = ();
908   my @list_switch_ipv4 = ();
909   for my $sw (@SWITCH){
910      push @list_switch_ip, $sw->{hostname};
911      }
912
913   ALL_SWITCH:
914   for my $one_computer (@list_switch_ip) {
915      my %resol_arp = resolve_ip_arp_host($one_computer,'*','low'); # arp resolution
916      next ALL_SWITCH if $resol_arp{mac_address} eq 'unknow';
917     
918      push @list_switch_ipv4,$resol_arp{ipv4_address};
919     
920      $where{$resol_arp{ipv4_address}} = find_all_switch_port($resol_arp{mac_address}); # find port on all switch
921
922      $db_switch_ip_hostname{$resol_arp{ipv4_address}} = $resol_arp{hostname_fq};
923      }
924     
925   ALL_SWITCH_IP_ADDRESS:
926   for my $ip (Net::Netmask::sort_by_ip_address(@list_switch_ipv4)) {
927   
928      next ALL_SWITCH_IP_ADDRESS if not exists $where{$ip};
929
930      DETECTED_SWITCH:
931      for my $switch_detected ( keys %{$where{$ip}} ) {
932
933         next DETECTED_SWITCH if not exists $SWITCH_PORT_COUNT{ $db_switch_ip_hostname{$ip}};
934
935         my $switch = $where{$ip}->{$switch_detected};
936
937         next if $switch->{port}     eq '0';
938         next if $switch->{port}     eq $db_switch_output_port{$switch->{hostname}};
939         next if $switch->{hostname} eq $db_switch_ip_hostname{$ip}; # $computerdb->{$ip}{hostname};
940
941         $db_switch_link_with{ $db_switch_ip_hostname{$ip} } ||= {};
942         $db_switch_link_with{ $db_switch_ip_hostname{$ip} }->{ $switch->{hostname} } = $switch->{port};
943         }
944
945      }
946   
947   my %db_switch_connected_on_port = ();
948   my $maybe_more_than_one_switch_connected = 'yes';
949   
950   while ($maybe_more_than_one_switch_connected eq 'yes') {
951      for my $sw (keys %db_switch_link_with) {
952         for my $connect (keys %{$db_switch_link_with{$sw}}) {
953         
954            my $port = $db_switch_link_with{$sw}->{$connect};
955         
956            $db_switch_connected_on_port{"$connect:$port"} ||= {};
957            $db_switch_connected_on_port{"$connect:$port"}->{$sw}++; # Just to define the key
958            }
959         }
960
961      $maybe_more_than_one_switch_connected  = 'no';
962
963      SWITCH_AND_PORT:
964      for my $swport (keys %db_switch_connected_on_port) {
965         
966         next if keys %{$db_switch_connected_on_port{$swport}} == 1;
967         
968         $maybe_more_than_one_switch_connected = 'yes';
969
970         my ($sw_connect,$port_connect) = split ':', $swport;
971         my @sw_on_same_port = keys %{$db_switch_connected_on_port{$swport}};
972
973         CONNECTED:
974         for my $sw_connected (@sw_on_same_port) {
975           
976            next CONNECTED if not keys %{$db_switch_link_with{$sw_connected}} == 1;
977           
978            $db_switch_connected_on_port{$swport} = {$sw_connected => 1};
979           
980            for my $other_sw (@sw_on_same_port) {
981               next if $other_sw eq $sw_connected;
982               
983               delete $db_switch_link_with{$other_sw}->{$sw_connect};
984               }
985           
986            # We can not do better for this switch for this loop
987            next SWITCH_AND_PORT;
988            }
989         }
990      }
991
992   my %db_switch_parent =();
993
994   for my $sw (keys %db_switch_link_with) {
995      for my $connect (keys %{$db_switch_link_with{$sw}}) {
996     
997         my $port = $db_switch_link_with{$sw}->{$connect};
998     
999         $db_switch_connected_on_port{"$connect:$port"} ||= {};
1000         $db_switch_connected_on_port{"$connect:$port"}->{$sw} = $port;
1001       
1002         $db_switch_parent{$sw} = {switch => $connect, port => $port};
1003         }
1004      }
1005
1006   print "Switch output port and parent port connection\n"; 
1007   print "---------------------------------------------\n";
1008   for my $sw (sort keys %db_switch_output_port) {
1009      if (exists $db_switch_parent{$sw}) {
1010         printf "%-25s  %2s  +-->  %2s  %-25s\n", $sw, $db_switch_output_port{$sw}, $db_switch_parent{$sw}->{port}, $db_switch_parent{$sw}->{switch};
1011         }
1012      else {
1013         printf "%-25s  %2s  +-->  router\n", $sw, $db_switch_output_port{$sw};
1014         }
1015      }
1016   print "\n";
1017
1018   print "Switch parent and children port inter-connection\n";
1019   print "------------------------------------------------\n";
1020   for my $swport (sort keys %db_switch_connected_on_port) {       
1021      my ($sw_connect,$port_connect) = split ':', $swport;
1022      for my $sw (keys %{$db_switch_connected_on_port{$swport}}) {
1023         if (exists $db_switch_output_port{$sw}) {
1024            printf "%-25s  %2s  <--+  %2s  %-25s\n", $sw_connect, $port_connect, $db_switch_output_port{$sw}, $sw;
1025            }
1026         else {
1027            printf "%-25s  %2s  <--+      %-25s\n", $sw_connect, $port_connect, $sw;
1028            }
1029         }
1030      }
1031
1032   my $switch_connection = {
1033      output_port       => \%db_switch_output_port,
1034      parent            => \%db_switch_parent,
1035      connected_on_port => \%db_switch_connected_on_port,
1036      link_with         => \%db_switch_link_with,
1037      switch_db         => \%SWITCH_DB,
1038      };
1039     
1040   YAML::DumpFile("$KLASK_SW_FILE", $switch_connection);
1041   }
1042
1043sub cmd_exportsw {
1044   my @ARGV   = @_;
1045
1046   test_switchdb_environnement();
1047
1048   my $format = 'txt';
1049
1050   my $ret = GetOptions(
1051      'format|f=s'  => \$format,
1052      );
1053
1054   my %possible_format = (
1055      txt => \&cmd_exportsw_txt,
1056      dot => \&cmd_exportsw_dot,
1057      );
1058
1059   $format = 'txt' if not defined $possible_format{$format};
1060   
1061   $possible_format{$format}->(@ARGV);
1062   }
1063
1064sub cmd_exportsw_txt {
1065
1066   my $switch_connection = YAML::LoadFile("$KLASK_SW_FILE");
1067
1068   my %db_switch_output_port       = %{$switch_connection->{output_port}};
1069   my %db_switch_parent            = %{$switch_connection->{parent}};
1070   my %db_switch_connected_on_port = %{$switch_connection->{connected_on_port}};
1071
1072   print "Switch output port and parent port connection\n"; 
1073   print "---------------------------------------------\n";
1074   for my $sw (sort keys %db_switch_output_port) {
1075      if (exists $db_switch_parent{$sw}) {
1076         printf "%-25s  %2s  +-->  %2s  %-25s\n", $sw, $db_switch_output_port{$sw}, $db_switch_parent{$sw}->{port}, $db_switch_parent{$sw}->{switch};
1077         }
1078      else {
1079         printf "%-25s  %2s  +-->  router\n", $sw, $db_switch_output_port{$sw};
1080         }
1081      }
1082   print "\n";
1083
1084   print "Switch parent and children port inter-connection\n";
1085   print "------------------------------------------------\n";
1086   for my $swport (sort keys %db_switch_connected_on_port) {       
1087      my ($sw_connect,$port_connect) = split ':', $swport;
1088      for my $sw (keys %{$db_switch_connected_on_port{$swport}}) {
1089         if (exists $db_switch_output_port{$sw}) {
1090            printf "%-25s  %2s  <--+  %2s  %-25s\n", $sw_connect, $port_connect, $db_switch_output_port{$sw}, $sw;
1091            }
1092         else {
1093            printf "%-25s  %2s  <--+      %-25s\n", $sw_connect, $port_connect, $sw;
1094            }
1095         }
1096      }
1097   }
1098
1099sub cmd_exportsw_dot {
1100
1101   my $switch_connection = YAML::LoadFile("$KLASK_SW_FILE");
1102   
1103   my %db_switch_output_port       = %{$switch_connection->{output_port}};
1104   my %db_switch_parent            = %{$switch_connection->{parent}};
1105   my %db_switch_connected_on_port = %{$switch_connection->{connected_on_port}};
1106   my %db_switch_link_with         = %{$switch_connection->{link_with}};
1107   my %db_switch_global            = %{$switch_connection->{switch_db}};
1108
1109   my %db_building= ();
1110   for my $sw (@SWITCH) {
1111      my ($building, $location) = split /\//, $sw->{location}, 2;
1112      $db_building{$building} ||= {};
1113      $db_building{$building}->{$location} ||= {};
1114      $db_building{$building}->{$location}{ $sw->{hostname} } = 'y';
1115      }
1116 
1117 
1118   print "digraph G {\n";
1119
1120   print "site [label = \"site\", color = black, fillcolor = gold, shape = invhouse, style = filled];\n";
1121   print "internet [label = \"internet\", color = black, fillcolor = cyan, shape = house, style = filled];\n";
1122
1123   my $b=0;
1124   for my $building (keys %db_building) {
1125      $b++;
1126     
1127      print "\"building$b\" [label = \"$building\", color = black, fillcolor = gold, style = filled];\n";
1128      print "site -> \"building$b\" [len = 2, color = firebrick];\n";
1129
1130      my $l = 0;
1131      for my $loc (keys %{$db_building{$building}}) {
1132         $l++;
1133 
1134         print "\"location$b-$l\" [label = \"$building".'/'.join('\n',split("/",$loc))."\", color = black, fillcolor = orange, style = filled];\n";
1135#         print "\"location$b-$l\" [label = \"$building / $loc\", color = black, fillcolor = orange, style = filled];\n";
1136         print "\"building$b\" -> \"location$b-$l\" [len = 2, color = firebrick]\n";
1137
1138         for my $sw (keys %{$db_building{$building}->{$loc}}) {
1139
1140            print "\"$sw:$db_switch_output_port{$sw}\" [label = $db_switch_output_port{$sw}, color = black, fillcolor = lightblue,  peripheries = 2, style = filled];\n";
1141
1142            my $swname  = $sw;
1143               $swname .= '\n-\n'."$db_switch_global{$sw}->{model}" if exists $db_switch_global{$sw} and exists $db_switch_global{$sw}->{model};
1144            print "\"$sw\" [label = \"$swname\", color = black, fillcolor = palegreen, shape = rect, style = filled];\n";
1145            print "\"location$b-$l\" -> \"$sw\" [len = 2, color = firebrick, arrowtail = dot]\n";
1146            print "\"$sw\" -> \"$sw:$db_switch_output_port{$sw}\" [len=2, style=bold, arrowhead = normal, arrowtail = invdot]\n";
1147
1148
1149            for my $swport (keys %db_switch_connected_on_port) {
1150               my ($sw_connect,$port_connect) = split ':', $swport;
1151               next if not $sw_connect eq $sw;
1152               next if $port_connect eq $db_switch_output_port{$sw};
1153               print "\"$sw:$port_connect\" [label = $port_connect, color = black, fillcolor = plum,  peripheries = 1, style = filled];\n";
1154               print "\"$sw:$port_connect\" -> \"$sw\" [len=2, style=bold, arrowhead= normal, arrowtail = inv]\n";
1155              }
1156            }
1157         }
1158      }
1159
1160#   print "Switch output port and parent port connection\n"; 
1161#   print "---------------------------------------------\n";
1162   for my $sw (sort keys %db_switch_output_port) {
1163      if (exists $db_switch_parent{$sw}) {
1164#         printf "   \"%s:%s\" -> \"%s:%s\"\n", $sw, $db_switch_output_port{$sw}, $db_switch_parent{$sw}->{switch}, $db_switch_parent{$sw}->{port};
1165         }
1166      else {
1167         printf "   \"%s:%s\" -> internet\n", $sw, $db_switch_output_port{$sw};
1168         }
1169      }
1170   print "\n";
1171
1172#   print "Switch parent and children port inter-connection\n";
1173#   print "------------------------------------------------\n";
1174   for my $swport (sort keys %db_switch_connected_on_port) {       
1175      my ($sw_connect,$port_connect) = split ':', $swport;
1176      for my $sw (keys %{$db_switch_connected_on_port{$swport}}) {
1177         if (exists $db_switch_output_port{$sw}) {
1178            printf "   \"%s:%s\" -> \"%s:%s\" [color = navyblue]\n", $sw, $db_switch_output_port{$sw}, $sw_connect, $port_connect;
1179            }
1180         else {
1181            printf "   \"%s\"   -> \"%s%s\"\n", $sw, $sw_connect, $port_connect;
1182            }
1183         }
1184      }
1185
1186print "}\n";
1187   }
1188
1189
1190__END__
1191
1192
1193=head1 NAME
1194
1195klask - ports manager and finder for switch
1196
1197
1198=head1 SYNOPSIS
1199
1200 klask updatedb
1201 klask exportdb
1202
1203 klask updatesw
1204 klask exportsw --format [txt|dot]
1205
1206 klask searchdb computer
1207 klask search   computer
1208
1209 klask enable  switch port
1210 klask disable swith port
1211 klask status  swith port
1212
1213
1214=head1 DESCRIPTION
1215
1216klask is a small tool to find where is a host in a big network. klask mean search in brittany.
1217
1218Klask has now a web site dedicated for it !
1219
1220 http://servforge.legi.inpg.fr/projects/klask
1221
1222
1223=head1 COMMANDS
1224
1225
1226=head2 search
1227
1228This 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.
1229
1230
1231=head2 enable
1232
1233This command activate 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 disable
1237
1238This command deactivate a port on a switch by snmp. So you need to give the switch and the port number on the command line.
1239
1240
1241=head2 status
1242
1243This 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.
1244
1245
1246=head2 updatedb
1247
1248This 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.
1249
1250
1251=head2 exportdb
1252
1253This 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...
1254
1255
1256=head2 updatesw
1257
1258This 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.
1259
1260
1261=head2 exportsw --format [txt|dot]
1262
1263This 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.
1264
1265 klask exportsw --format dot > /tmp/map.dot
1266 dot -Tpng /tmp/map.dot > /tmp/map.png
1267
1268
1269
1270=head1 CONFIGURATION
1271
1272Because 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 !
1273
1274Here an example, be aware with indent, it's important in YAML, do not use tabulation !
1275
1276 default:
1277   community: public
1278   snmpport: 161
1279
1280 network:
1281   labnet:
1282     ip-subnet:
1283       - add: 192.168.1.0/24
1284       - add: 192.168.2.0/24
1285     interface: eth0
1286     main-router: gw1.labnet.local
1287
1288   schoolnet:
1289     ip-subnet:
1290       - add: 192.168.6.0/24
1291       - add: 192.168.7.0/24
1292     interface: eth0.38
1293     main-router: gw2.schoolnet.local
1294
1295 switch:
1296   - hostname: sw1.klask.local
1297     portignore:
1298       - 1
1299       - 2
1300
1301   - hostname: sw2.klask.local
1302     location: BatK / 2 / K203
1303     type: HP2424
1304     portignore:
1305       - 1
1306       - 2
1307
1308I 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.
1309
1310
1311=head1 FILES
1312
1313 /etc/klask.conf
1314 /var/cache/klask/klaskdb
1315 /var/cache/klask/switchdb
1316
1317=head1 SEE ALSO
1318
1319Net::SNMP, Net::Netmask, Net::CIDR::Lite, NetAddr::IP, YAML
1320
1321
1322=head1 VERSION
1323
1324$Id: klask 38 2008-02-13 13:55:29Z g7moreau $
1325
1326
1327=head1 AUTHOR
1328
1329Written by Gabriel Moreau, Grenoble - France
1330
1331
1332=head1 COPYRIGHT
1333       
1334Copyright (C) 2005-2008 Gabriel Moreau.
1335
1336
1337=head1 LICENCE
1338
1339GPL version 2 or later and Perl equivalent
Note: See TracBrowser for help on using the repository browser.