source: trunk/klask @ 30

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