source: trunk/klask @ 33

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