source: trunk/klask @ 71

Last change on this file since 71 was 71, checked in by g7moreau, 13 years ago
  • Add VLAN columns to exportdb for html format
  • Property svn:executable set to *
  • Property svn:keywords set to Date Author Id Rev
File size: 58.1 KB
Line 
1#!/usr/bin/perl -w
2#
3# Copyright (C) 2005-2008 Gabriel Moreau.
4#
5# $Id: klask 71 2010-11-02 16:31:51Z g7moreau $
6
7use strict;
8use warnings;
9use version; our $VERSION = qv('0.5.5');
10
11use Readonly;
12use FileHandle;
13use Net::SNMP;
14#use YAML;
15use YAML::Syck;
16use Net::Netmask;
17use Net::CIDR::Lite;
18use NetAddr::IP;
19use Getopt::Long qw(GetOptions GetOptionsFromArray);;
20use Socket;
21
22# apt-get install snmp fping libnet-cidr-lite-perl libnet-netmask-perl libnet-snmp-perl libnetaddr-ip-perl libyaml-perl
23# libcrypt-des-perl libcrypt-hcesha-perl libdigest-hmac-perl
24# arping fping bind9-host arpwatch
25
26my $KLASK_VAR      = '/var/cache/klask';
27my $KLASK_CFG_FILE = '/etc/klask.conf';
28my $KLASK_DB_FILE  = "$KLASK_VAR/klaskdb";
29my $KLASK_SW_FILE  = "$KLASK_VAR/switchdb";
30
31test_running_environnement();
32
33my $KLASK_CFG = YAML::Syck::LoadFile("$KLASK_CFG_FILE");
34
35my %DEFAULT = %{ $KLASK_CFG->{default} };
36my @SWITCH  = @{ $KLASK_CFG->{switch}  };
37
38my %switch_level = ();
39my %SWITCH_DB    = ();
40LEVEL_OF_EACH_SWITCH:
41for my $sw (@SWITCH){
42   $switch_level{$sw->{hostname}} = $sw->{level} || $DEFAULT{switch_level}  || 2;
43   $SWITCH_DB{$sw->{hostname}} = $sw;
44   }
45@SWITCH = reverse sort { $switch_level{$a->{hostname}} <=> $switch_level{$b->{hostname}} } @{$KLASK_CFG->{switch}};
46
47my %SWITCH_PORT_COUNT = ();
48
49my %CMD_DB = (
50   help       => \&cmd_help,
51   version    => \&cmd_version,
52   exportdb   => \&cmd_exportdb,
53   updatedb   => \&cmd_updatedb,
54   searchdb   => \&cmd_searchdb,
55   removedb   => \&cmd_removedb,
56   search     => \&cmd_search,
57   enable     => \&cmd_enable,
58   disable    => \&cmd_disable,
59   status     => \&cmd_status,
60   updatesw   => \&cmd_updatesw,
61   exportsw   => \&cmd_exportsw,
62   iplocation => \&cmd_iplocation,
63   'ip-free'  => \&cmd_ip_free,
64   'search-mac-on-switch' => \&cmd_search_mac_on_switch,
65   );
66
67Readonly my %INTERNAL_PORT_MAP => (
68   0 => 'A',
69   1 => 'B',
70   2 => 'C',
71   3 => 'D',
72   4 => 'E',
73   5 => 'F',
74   6 => 'G',
75   7 => 'H',
76   );
77Readonly my %INTERNAL_PORT_MAP_REV => reverse %INTERNAL_PORT_MAP;
78
79Readonly my %SWITCH_KIND => (
80   J3299A => { model => 'HP224M',     match => 'HP J3299A ProCurve Switch 224M'  },
81   J4120A => { model => 'HP1600M',    match => 'HP J4120A ProCurve Switch 1600M' },
82   J9029A => { model => 'HP1800-8G',  match => 'PROCURVE J9029A'                 },
83   J9449A => { model => 'HP1810-8G',  match => 'HP ProCurve 1810G - 8 GE'        },
84   J4093A => { model => 'HP2424M',    match => 'HP J4093A ProCurve Switch 2424M' },
85   J4813A => { model => 'HP2524',     match => 'HP J4813A ProCurve Switch 2524'  },
86   J4900A => { model => 'HP2626A',    match => 'HP J4900A ProCurve Switch 2626'  },
87   J4900B => { model => 'HP2626B',    match => 'J4900B.+?Switch 2626'            },# ProCurve J4900B Switch 2626 # HP J4900B ProCurve Switch 2626
88   J4899B => { model => 'HP2650',     match => 'ProCurve J4899B Switch 2650'     },
89   J9021A => { model => 'HP2810-24G', match => 'ProCurve J9021A Switch 2810-24G' },
90   J9022A => { model => 'HP2810-48G', match => 'ProCurve J9022A Switch 2810-48G' },
91   J4903A => { model => 'HP2824',     match => 'J4903A.+?Switch 2824,'           },
92   J4110A => { model => 'HP8000M',    match => 'HP J4110A ProCurve Switch 8000M' },
93   BS350T => { model => 'BS350T',     match => 'BayStack 350T HW'                },
94   );
95
96Readonly my %OID_NUMBER => (
97   sysDescription  => '1.3.6.1.2.1.1.1.0',
98   sysName         => '1.3.6.1.2.1.1.5.0',
99   sysContact      => '1.3.6.1.2.1.1.4.0',
100   sysLocation     => '1.3.6.1.2.1.1.6.0',
101   );
102
103Readonly my $RE_MAC_ADDRESS  => qr{ [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} }xms;
104Readonly my $RE_IPv4_ADDRESS => qr{ [0-9]{1,3} \. [0-9]{1,3} \. [0-9]{1,3} \. [0-9]{1,3} }xms;
105
106
107################
108# principal
109################
110
111my $cmd = shift @ARGV || 'help';
112if (defined $CMD_DB{$cmd}) {
113   $CMD_DB{$cmd}->(@ARGV);
114   }
115else {
116   print {*STDERR} "klask: command $cmd not found\n\n";
117   $CMD_DB{help}->();
118   exit 1;
119   }
120
121exit;
122
123sub test_running_environnement {
124   die "Configuration file $KLASK_CFG_FILE does not exists. Klask need it !\n" if not -e "$KLASK_CFG_FILE";
125   die "Var folder $KLASK_VAR does not exists. Klask need it !\n"              if not -d "$KLASK_VAR";
126   return;
127   }
128
129sub test_switchdb_environnement {
130   die "Switch database $KLASK_SW_FILE does not exists. Launch updatesw before this command !\n" if not -e "$KLASK_SW_FILE";
131   return;
132   }
133
134sub test_maindb_environnement {
135   die "Main database $KLASK_DB_FILE does not exists. Launch updatedb before this command !\n" if not -e "$KLASK_DB_FILE";
136   return;
137   }
138
139###
140# fast ping dont l'objectif est de remplir la table arp de la machine
141sub fastping {
142   # Launch this command without waiting...
143   system "fping -c 1 @_ >/dev/null 2>&1 &";
144   return;
145   }
146
147sub shell_command {
148   my $cmd = shift;
149
150   my $fh     = new FileHandle;
151   my $result = '';
152   open $fh, q{-|}, "$cmd" or die "Can't exec $cmd\n";
153   $result .= <$fh>;
154   close $fh;
155   chomp $result;
156   return $result;
157   }
158
159###
160# donne l'@ ip, dns, arp en fonction du dns OU de l'ip
161sub resolve_ip_arp_host {
162   my $param_ip_or_host = shift;
163   my $interface = shift || q{*};
164   my $type      = shift || q{fast};
165
166   my %ret = (
167      hostname_fq  => 'unknow',
168      ipv4_address => '0.0.0.0',
169      mac_address  => 'unknow',
170      );
171
172#   my $cmdarping  = `arping -c 1 -w 1 -rR $param 2>/dev/null`;
173#   if ( not $param_ip_or_host =~ m/^\d+ \. \d+ \. \d+ \. \d+$/xms ) {
174#      $param_ip_or_host =~ s/ \. .* //xms;
175#      }
176
177   #my $dns_resolver =  Net::DNS::Resolver->new;
178   #my $dns_answer = $dns_resolver->query($param_ip_or_host);
179   #if ($dns_answer) {
180   #   $ret{ipv4_address} = $dns_answer->address;
181   #   }
182
183   # perl -MSocket -E 'say inet_ntoa(scalar gethostbyname("tech7meylan.hmg.inpg.fr"))'
184   my $packed_ip = scalar gethostbyname($param_ip_or_host);
185   return %ret if not defined $packed_ip;
186   $ret{ipv4_address} = inet_ntoa($packed_ip);
187
188   # perl -MSocket -E 'say scalar gethostbyaddr(inet_aton("194.254.66.240"), AF_INET)'
189   my $hostname_fq = scalar gethostbyaddr($packed_ip, AF_INET);
190#   return %ret if not defined $hostname_fq;
191   $ret{hostname_fq} = $hostname_fq if defined $hostname_fq;
192
193#print "DEBUG : $param_ip_or_host --  $ret{ipv4_address} --   $hostname_fq \n";
194
195   # controler que arpwatch tourne !
196   # resultat de la commande arpwatch
197   # /var/lib/arpwatch/arp.dat
198   # 0:13:d3:e1:92:d0        192.168.24.109  1163681980      theo8sv109
199   # my $cmd = "grep  -e '".'\b'."$param_ip_or_host".'\b'."' /var/lib/arpwatch/arp.dat | sort +2rn | head -1";
200   # my $cmd = "grep  -he '".'\b'."$param_ip_or_host".'\b'."' /var/lib/arpwatch/*.dat | sort +2rn | head -1";
201
202### BOGUE ICI
203### FAIRE LE GREP SUR L'IP !
204
205   # my $cmd = q{grep  -he '\b} . $param_ip_or_host . q{\b' } . "/var/lib/arpwatch/$interface.dat | sort -rn -k 3,3 | head -1";
206   my $cmd = q{grep  -he '\b} . $ret{ipv4_address} . q{\b' } . "/var/lib/arpwatch/$interface.dat | sort -rn -k 3,3 | head -1";
207   my $cmd_arpwatch = shell_command $cmd;
208   my ($arp, $ip, $timestamp, $host) = split m/ \s+ /xms, $cmd_arpwatch;
209
210#   $ret{ipv4_address} = $ip        if $ip;
211   $ret{mac_address}  = $arp       if $arp;
212   $ret{timestamp}    = $timestamp if $timestamp;
213
214   my $nowtimestamp = time;
215
216   if ( $type eq 'fast' and ( not defined $timestamp or $timestamp < ( $nowtimestamp - 3 * 3600 ) ) ) {
217      $ret{mac_address} = 'unknow';
218      return %ret;
219      }
220
221   # resultat de la commande arp
222   # tech7meylan.hmg.inpg.fr (194.254.66.240) at 00:14:22:45:28:A9 [ether] on eth0
223   # sw2-batF0-legi.hmg.priv (192.168.22.112) at 00:30:c1:76:9c:01 [ether] on eth0.37
224   my $cmd_arp  = shell_command "arp -a $param_ip_or_host";
225   if ( $cmd_arp =~ m{ (\S*) \s \( ( $RE_IPv4_ADDRESS ) \) \s at \s ( $RE_MAC_ADDRESS ) }xms ) {
226      ( $ret{hostname_fq}, $ret{ipv4_address}, $ret{mac_address} )  = ($1, $2, $3);
227      }
228
229   # resultat de la commande host si le parametre est ip
230   # 250.66.254.194.in-addr.arpa domain name pointer legihp2100.hmg.inpg.fr.
231#   my $cmd_host = shell_command "host $param_ip_or_host";
232#   if ( $cmd_host =~ m/domain \s name \s pointer \s (\S+) \.$/xms ) {
233#      $ret{hostname_fq} = $1;
234#      }
235
236   # resultat de la commande host si parametre est hostname
237   # tech7meylan.hmg.inpg.fr has address 194.254.66.240
238#   if ( $cmd_host =~ m/(\S*) \s has \s address \s ( $RE_IPv4_ADDRESS )$/xms ) {
239#      ( $ret{hostname_fq}, $ret{ipv4_address} ) = ($1, $2);
240#      }
241
242   # Connerie !
243   # Inverse les IP !!
244   # if ( $cmd_host =~ m/ \b ( $RE_IPv4_ADDRESS ) \. in-addr \. arpa \s/xms ) {
245   #    $ret{ipv4_address} = $1;
246   #    }
247   #$ret{hostname_fq}  = $param_ip_or_host if not defined $1 and $ret{hostname_fq} eq 'unknow';
248
249   if ($ret{mac_address} ne 'unknow') {
250      my @paquets = ();
251      foreach ( split m/ : /xms, $ret{mac_address} ) {
252         my @chars = split m//xms, uc "00$_";
253         push @paquets, "$chars[-2]$chars[-1]";
254         }
255      $ret{mac_address} = join q{:}, @paquets;
256      }
257
258   return %ret;
259   }
260
261# Find Surname of a switch
262sub get_switch_model {
263   my $sw_snmp_description = shift || 'unknow';
264
265   for my $sw_kind (keys %SWITCH_KIND) {
266      next if not $sw_snmp_description =~ m/$SWITCH_KIND{$sw_kind}->{match}/ms; # option xms break search, why ?
267
268      return $SWITCH_KIND{$sw_kind}->{model};
269      }
270
271   return $sw_snmp_description;
272   }
273
274###
275# va rechercher le nom des switchs pour savoir qui est qui
276sub init_switch_names {
277   my $verbose = shift;
278
279   printf "%-25s                %-25s %s\n",'Switch','Description','Type';
280   print "-------------------------------------------------------------------------\n" if $verbose;
281
282   INIT_EACH_SWITCH:
283   for my $sw (@SWITCH) {
284      my %session = ( -hostname   => $sw->{hostname} );
285         $session{-version} = $sw->{version}   || 1;
286         $session{-port}    = $sw->{snmpport}  || $DEFAULT{snmpport}  || 161;
287         if (exists $sw->{version} and $sw->{version} eq '3') {
288            $session{-username} = $sw->{username} || 'snmpadmin';
289            }
290         else {
291            $session{-community} = $sw->{community} || $DEFAULT{community} || 'public';
292            }
293
294      $sw->{local_session} = \%session;
295
296      my ($session, $error) = Net::SNMP->session( %{$sw->{local_session}} );
297      print "$error \n" if $error;
298
299      my $result = $session->get_request(
300         -varbindlist => [
301            $OID_NUMBER{sysDescription},
302            $OID_NUMBER{sysName},
303            $OID_NUMBER{sysContact},
304            $OID_NUMBER{sysLocation},
305            ]
306         );
307      $sw->{description} = $result->{$OID_NUMBER{sysName}} || $sw->{hostname};
308      $sw->{model} = get_switch_model( $result->{$OID_NUMBER{sysDescription}});
309      #$sw->{location} = $result->{"1.3.6.1.2.1.1.6.0"} || $sw->{hostname};
310      #$sw->{contact} = $result->{"1.3.6.1.2.1.1.4.0"} || $sw->{hostname};
311      $session->close;
312
313      # Ligne à virer car on récupère maintenant le modèle du switch
314      my ($desc, $type) = split m/ : /xms, $sw->{description}, 2;
315      printf "%-25s 0--------->>>> %-25s %s\n", $sw->{hostname}, $desc, $sw->{model} if $verbose;
316      }
317
318   print "\n" if $verbose;
319   return;
320   }
321
322###
323# convertit l'hexa (uniquement 2 chiffres) en decimal
324sub hex_to_dec {
325   #00:0F:1F:43:E4:2B
326   my $car = '00' . uc shift;
327
328   return '00' if $car eq '00UNKNOW';
329   my %table = (
330      '0'=>'0',  '1'=>'1',  '2'=>'2',  '3'=>'3',  '4'=>'4',
331      '5'=>'5',  '6'=>'6',  '7'=>'7',  '8'=>'8',  '9'=>'9',
332      'A'=>'10', 'B'=>'11', 'C'=>'12', 'D'=>'13', 'E'=>'14', 'F'=>'15',
333      );
334   my @chars = split m//xms, $car;
335   return $table{$chars[-2]}*16 + $table{$chars[-1]};
336   }
337
338###
339# convertit l'@ arp en decimal
340sub arp_hex_to_dec {
341   #00:0F:1F:43:E4:2B
342   my $arp = shift;
343
344   my @paquets = split m/ : /xms, $arp;
345   my $return = q{};
346   foreach(@paquets) {
347      $return .= q{.} . hex_to_dec($_);
348      }
349   return $return;
350   }
351
352###
353# va rechercher le port et le switch sur lequel est la machine
354sub find_switch_port {
355   my $arp             = shift;
356   my $switch_proposal = shift || q{};
357
358   my %ret;
359   $ret{switch_description} = 'unknow';
360   $ret{switch_port} = '0';
361
362   return %ret if $arp eq 'unknow';;
363
364   my @switch_search = @SWITCH;
365   if ($switch_proposal ne q{}) {
366      for my $sw (@SWITCH) {
367         next if $sw->{hostname} ne $switch_proposal;
368         unshift @switch_search, $sw;
369         last;
370         }
371      }
372
373   my $research = '1.3.6.1.2.1.17.4.3.1.2' . arp_hex_to_dec($arp);
374
375   LOOP_ON_SWITCH:
376   for my $sw (@switch_search) {
377      my ($session, $error) = Net::SNMP->session( %{$sw->{local_session}} );
378      print "$error \n" if $error;
379
380      my $result = $session->get_request(
381         -varbindlist => [$research]
382         );
383      if (not defined $result or $result->{$research} eq 'noSuchInstance') {
384         $session->close;
385         next LOOP_ON_SWITCH;
386         }
387
388         my $swport = $result->{$research};
389         $session->close;
390
391         # IMPORTANT !!
392         # ceci empeche la detection sur certains port ...
393         # en effet les switch sont relies entre eux par un cable reseau et du coup
394         # tous les arp de toutes les machines sont presentes sur ces ports (ceux choisis ici sont les miens)
395         # cette partie est a ameliore, voir a configurer dans l'entete
396         # 21->24 45->48
397#         my $flag = 0;
398         SWITCH_PORT_IGNORE:
399         foreach my $p (@{$sw->{portignore}}) {
400            next SWITCH_PORT_IGNORE if $swport ne get_numerical_port($sw->{model},$p);
401#            $flag = 1;
402            next LOOP_ON_SWITCH;
403            }
404#         if ($flag == 0) {
405            $ret{switch_hostname}    = $sw->{hostname};
406            $ret{switch_description} = $sw->{description};
407            $ret{switch_port}        = get_human_readable_port($sw->{model}, $swport); # $swport;
408
409            last LOOP_ON_SWITCH;
410#            }
411#         }
412#      $session->close;
413      }
414   return %ret;
415   }
416
417###
418# va rechercher les port et les switch sur lequel est la machine
419sub find_all_switch_port {
420   my $arp = shift;
421
422   my $ret = {};
423
424   return $ret if $arp eq 'unknow';
425
426   for my $sw (@SWITCH) {
427      $SWITCH_PORT_COUNT{$sw->{hostname}} = {} if not exists $SWITCH_PORT_COUNT{$sw->{hostname}};
428      }
429
430   my $research = '1.3.6.1.2.1.17.4.3.1.2' . arp_hex_to_dec($arp);
431   LOOP_ON_ALL_SWITCH:
432   for my $sw (@SWITCH) {
433      my ($session, $error) = Net::SNMP->session( %{$sw->{local_session}} );
434      print "$error \n" if $error;
435
436      my $result = $session->get_request(
437         -varbindlist => [$research]
438         );
439
440      if(defined $result and $result->{$research} ne 'noSuchInstance'){
441         my $swport = $result->{$research};
442
443#print "DEBUG $arp  $swport --  $sw->{hostname} \n";
444         if ( $sw->{hostname} eq 'sw10-batE1-3s.hmg.priv' and $swport == 19 ) { $swport = 20; print "DEBUG $swport --  $sw->{hostname} \n";}
445         if ( $sw->{hostname} eq 'sw8-batE1-3s.hmg.priv'  and $swport == 23 ) { $swport = 24; print "DEBUG $swport --  $sw->{hostname} \n";}
446#         if ( $sw->{hostname} eq 'sw10-batE1-3s.hmg.priv' ) {  print "DEBUG $swport --  $sw->{hostname} \n";}
447#         if ( $sw->{hostname} eq 'sw8-batE1-3s.hmg.priv'  ) {  print "DEBUG $swport --  $sw->{hostname} \n";}
448
449         $ret->{$sw->{hostname}} = {};
450         $ret->{$sw->{hostname}}{hostname}    = $sw->{hostname};
451         $ret->{$sw->{hostname}}{description} = $sw->{description};
452         $ret->{$sw->{hostname}}{port}        = get_human_readable_port($sw->{model}, $swport);
453
454         $SWITCH_PORT_COUNT{$sw->{hostname}}->{$swport}++;
455         }
456
457      $session->close;
458      }
459   return $ret;
460   }
461
462sub get_list_network {
463
464   return keys %{$KLASK_CFG->{network}};
465   }
466
467sub get_current_interface {
468   my $network = shift;
469
470   return $KLASK_CFG->{network}{$network}{interface};
471   }
472
473###
474# liste l'ensemble des adresses ip d'un réseau
475sub get_list_ip {
476   my @network = @_;
477
478   my $cidrlist = Net::CIDR::Lite->new;
479
480   for my $net (@network) {
481      my @line  = @{$KLASK_CFG->{network}{$net}{'ip-subnet'}};
482      for my $cmd (@line) {
483         for my $method (keys %{$cmd}){
484            $cidrlist->add_any($cmd->{$method}) if $method eq 'add';
485            }
486         }
487      }
488
489   my @res = ();
490
491   for my $cidr ($cidrlist->list()) {
492      my $net = new NetAddr::IP $cidr;
493      for my $ip (@{$net}) {
494         $ip =~ s{ /32 }{}xms;
495         push @res,  $ip;
496         }
497      }
498
499   return @res;
500   }
501
502# liste l'ensemble des routeurs du réseau
503sub get_list_main_router {
504   my @network = @_;
505
506   my @res = ();
507
508   for my $net (@network) {
509      push @res, $KLASK_CFG->{network}{$net}{'main-router'};
510      }
511
512   return @res;
513   }
514
515sub get_human_readable_port {
516   my $sw_model = shift;
517   my $sw_port  = shift;
518
519   if ($sw_model eq 'HP8000M') {
520
521      my $reste = (($sw_port - 1) % 8) + 1;
522      my $major = int (($sw_port - 1) / 8);
523      return "$INTERNAL_PORT_MAP{$major}$reste";
524      }
525
526   if ($sw_model eq 'HP2424M') {
527      if ($sw_port > 24) {
528         
529         my $reste = $sw_port - 24;
530         return "A$reste";
531         }
532      }
533
534   if ($sw_model eq 'HP1600M') {
535      if ($sw_port > 16) {
536         
537         my $reste = $sw_port - 16;
538         return "A$reste";
539         }
540      }
541
542   return $sw_port;
543   }
544
545sub get_numerical_port {
546   my $sw_model = shift;
547   my $sw_port  = shift;
548
549   if ($sw_model eq 'HP8000M') {
550
551      my $letter = substr $sw_port, 0, 1;
552      my $reste =  substr $sw_port, 1;
553
554      return $INTERNAL_PORT_MAP_REV{$letter} * 8 + $reste;
555      }
556
557   if ($sw_model eq 'HP2424M') {
558      if ($sw_port =~ m/^A/xms ) {
559
560         my $reste =  substr $sw_port, 1;
561
562         return 24 + $reste;
563         }
564      }
565
566   if ($sw_model eq 'HP1600M') {
567      if ($sw_port =~ m/^A/xms ) {
568
569         my $reste =  substr $sw_port, 1;
570
571         return 16 + $reste;
572         }
573      }
574
575   return $sw_port;
576   }
577
578################
579# Les commandes
580################
581
582sub cmd_help {
583
584print <<'END';
585klask - ports manager and finder for switch
586
587 klask updatedb
588 klask exportdb --format [txt|html]
589
590 klask updatesw
591 klask exportsw --format [txt|dot]
592
593 klask searchdb computer
594 klask search   computer
595 klask search-mac-on-switch switch mac_addr
596
597 klask ip-free --day number_of_day [vlan_name]
598
599 klask enable  switch port
600 klask disable switch port
601 klask status  switch port
602END
603   return;
604   }
605
606sub cmd_version {
607
608print <<'END';
609Klask - ports manager and finder for switch
610Copyright (C) 2005-2008 Gabriel Moreau
611
612END
613   print ' $Rev: 71 $'."\n";
614   print ' $Date: 2010-11-02 16:31:51 +0000 (Tue, 02 Nov 2010) $'."\n";
615   print ' $Id: klask 71 2010-11-02 16:31:51Z g7moreau $'."\n";
616   return;
617   }
618
619sub cmd_search {
620   my @computer = @_;
621
622   init_switch_names();    #nomme les switchs
623   fastping(@computer);
624   for my $clientname (@computer) {
625      my %resol_arp = resolve_ip_arp_host($clientname);          #resolution arp
626      my %where     = find_switch_port($resol_arp{mac_address}); #retrouve l'emplacement
627      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"
628         unless $where{switch_description} eq 'unknow' and $resol_arp{hostname_fq} eq 'unknow' and $resol_arp{mac_address} eq 'unknow';
629      }
630   return;
631   }
632
633sub cmd_searchdb {
634   my @computer = @_;
635
636   fastping(@computer);
637   my $computerdb = YAML::Syck::LoadFile("$KLASK_DB_FILE");
638
639   LOOP_ON_COMPUTER:
640   for my $clientname (@computer) {
641      my %resol_arp = resolve_ip_arp_host($clientname);      #resolution arp
642      my $ip = $resol_arp{ipv4_address};
643
644      next LOOP_ON_COMPUTER unless exists $computerdb->{$ip};
645
646      my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime $computerdb->{$ip}{timestamp};
647      $year += 1900;
648      $mon++;
649      my $date = sprintf '%04i-%02i-%02i %02i:%02i', $year, $mon, $mday, $hour, $min;
650
651      printf "%-22s %2s %-30s %-15s %-18s %s\n",
652         $computerdb->{$ip}{switch_name},
653         $computerdb->{$ip}{switch_port},
654         $computerdb->{$ip}{hostname_fq},
655         $ip,
656         $computerdb->{$ip}{mac_address},
657         $date;
658      }
659   return;
660   }
661
662sub cmd_updatedb {
663   my @network = @_;
664      @network = get_list_network() if not @network;
665
666   test_switchdb_environnement();
667
668   my $computerdb = {};
669      $computerdb = YAML::Syck::LoadFile("$KLASK_DB_FILE") if -e "$KLASK_DB_FILE";
670   my $timestamp = time;
671
672   my %computer_not_detected = ();
673   my $timestamp_last_week = $timestamp - (3600 * 24 * 7);
674
675   my $number_of_computer = get_list_ip(@network); # + 1;
676   my $size_of_database   = keys %{$computerdb};
677      $size_of_database   = 1 if $size_of_database == 0;
678   my $i = 0;
679   my $detected_computer = 0;
680
681   init_switch_names('yes');    #nomme les switchs
682
683   { # Remplis le champs portignore des ports d'inter-connection pour chaque switch
684   my $switch_connection = YAML::Syck::LoadFile("$KLASK_SW_FILE");
685   my %db_switch_output_port       = %{$switch_connection->{output_port}};
686   my %db_switch_connected_on_port = %{$switch_connection->{connected_on_port}};
687   my %db_switch_chained_port = ();
688   for my $swport (keys %db_switch_connected_on_port) {
689      my ($sw_connect,$port_connect) = split m/ : /xms, $swport;
690      $db_switch_chained_port{$sw_connect} .= "$port_connect:";
691      }
692   for my $sw (@SWITCH){
693      push @{$sw->{portignore}}, $db_switch_output_port{$sw->{hostname}}  if exists $db_switch_output_port{$sw->{hostname}};
694      if ( exists $db_switch_chained_port{$sw->{hostname}} ) {
695         chop $db_switch_chained_port{$sw->{hostname}};
696         push @{$sw->{portignore}}, split m/ : /xms, $db_switch_chained_port{$sw->{hostname}};
697         }
698#      print "$sw->{hostname} ++ @{$sw->{portignore}}\n";
699      }
700   }
701
702   my %router_mac_ip = ();
703   DETECT_ALL_ROUTER:
704#   for my $one_router ('194.254.66.254') {
705   for my $one_router ( get_list_main_router(@network) ) {
706      my %resol_arp = resolve_ip_arp_host($one_router);
707      $router_mac_ip{ $resol_arp{mac_address} } = $resol_arp{ipv4_address};
708      }
709
710   ALL_NETWORK:
711   for my $net (@network) {
712
713      my @computer = get_list_ip($net);
714      my $current_interface = get_current_interface($net);
715
716      fastping(@computer);
717
718      LOOP_ON_COMPUTER:
719      for my $one_computer (@computer) {
720         $i++;
721
722         my $total_percent = int (($i*100)/$number_of_computer);
723
724         my $localtime = time - $timestamp;
725         my ($sec,$min) = localtime $localtime;
726
727         my $time_elapse = 0;
728            $time_elapse = $localtime * ( 100 - $total_percent) / $total_percent if $total_percent != 0;
729         my ($sec_elapse,$min_elapse) = localtime $time_elapse;
730
731         printf "\rComputer scanned: %4i/%i (%2i%%)",  $i,                 $number_of_computer, $total_percent;
732#         printf ", Computer detected: %4i/%i (%2i%%)", $detected_computer, $size_of_database,   int(($detected_computer*100)/$size_of_database);
733         printf ', detected: %4i/%i (%2i%%)', $detected_computer, $size_of_database,   int(($detected_computer*100)/$size_of_database);
734         printf ' [Time: %02i:%02i / %02i:%02i]', int($localtime/60), $localtime % 60, int($time_elapse/60), $time_elapse % 60;
735#         printf '  [%02i:%02i/%02i:%02i]', int($localtime/60), $localtime % 60, int($time_elapse/60), $time_elapse % 60;
736         printf ' %-14s', $one_computer;
737
738         my %resol_arp = resolve_ip_arp_host($one_computer,$current_interface);
739
740         # do not search on router connection (why ?)
741         if ( exists $router_mac_ip{$resol_arp{mac_address}}) {
742            $computer_not_detected{$one_computer} = $current_interface;
743            next LOOP_ON_COMPUTER;
744            }
745
746         # do not search on switch inter-connection
747         if (exists $switch_level{$resol_arp{hostname_fq}}) {
748            $computer_not_detected{$one_computer} = $current_interface;
749            next LOOP_ON_COMPUTER;
750            }
751
752         my $switch_proposal = q{};
753         if (exists $computerdb->{$resol_arp{ipv4_address}} and exists $computerdb->{$resol_arp{ipv4_address}}{switch_hostname}) {
754            $switch_proposal = $computerdb->{$resol_arp{ipv4_address}}{switch_hostname};
755            }
756
757         # do not have a mac address
758         if ($resol_arp{mac_address} eq 'unknow' or (exists $resol_arp{timestamps} and $resol_arp{timestamps} < ($timestamp - 3 * 3600))) {
759            $computer_not_detected{$one_computer} = $current_interface;
760            next LOOP_ON_COMPUTER;
761            }
762
763         my %where = find_switch_port($resol_arp{mac_address},$switch_proposal);
764
765         #192.168.24.156:
766         #  arp: 00:0B:DB:D5:F6:65
767         #  hostname: pcroyon.hmg.priv
768         #  port: 5
769         #  switch: sw-batH-legi:hp2524
770         #  timestamp: 1164355525
771
772         # do not have a mac address
773#         if ($resol_arp{mac_address} eq 'unknow') {
774#            $computer_not_detected{$one_computer} = $current_interface;
775#            next LOOP_ON_COMPUTER;
776#            }
777
778         # detected on a switch
779         if ($where{switch_description} ne 'unknow') {
780            $detected_computer++;
781            $computerdb->{$resol_arp{ipv4_address}} = {
782               hostname_fq        => $resol_arp{hostname_fq},
783               mac_address        => $resol_arp{mac_address},
784               switch_hostname    => $where{switch_hostname},
785               switch_description => $where{switch_description},
786               switch_port        => $where{switch_port},
787               timestamp          => $timestamp,
788               network            => $net,
789               };
790            next LOOP_ON_COMPUTER;
791            }
792
793         # new in the database but where it is ?
794         if (not exists $computerdb->{$resol_arp{ipv4_address}}) {
795            $detected_computer++;
796            $computerdb->{$resol_arp{ipv4_address}} = {
797               hostname_fq        => $resol_arp{hostname_fq},
798               mac_address        => $resol_arp{mac_address},
799               switch_hostname    => $where{switch_hostname},
800               switch_description => $where{switch_description},
801               switch_port        => $where{switch_port},
802               timestamp          => $resol_arp{timestamp},
803               network            => $net,
804               };
805            }
806
807         # mise a jour du nom de la machine si modification dans le dns
808         $computerdb->{$resol_arp{ipv4_address}}{hostname_fq} = $resol_arp{hostname_fq};
809
810         # mise à jour de la date de détection si détection plus récente par arpwatch
811         $computerdb->{$resol_arp{ipv4_address}}{timestamp}   = $resol_arp{timestamp} if exists $resol_arp{timestamp} and $computerdb->{$resol_arp{ipv4_address}}{timestamp} < $resol_arp{timestamp};
812
813         # relance un arping sur la machine si celle-ci n'a pas été détectée depuis plus d'une semaine
814#         push @computer_not_detected, $resol_arp{ipv4_address} if $computerdb->{$resol_arp{ipv4_address}}{timestamp} < $timestamp_last_week;
815         $computer_not_detected{$resol_arp{ipv4_address}} = $current_interface if $computerdb->{$resol_arp{ipv4_address}}{timestamp} < $timestamp_last_week;
816
817         }
818      }
819
820   # final end of line at the end of the loop
821   printf "\n";
822
823   my $dirdb = $KLASK_DB_FILE;
824      $dirdb =~ s{ / [^/]* $}{}xms;
825   mkdir "$dirdb", 0755 unless -d "$dirdb";
826   YAML::Syck::DumpFile("$KLASK_DB_FILE", $computerdb);
827
828   for my $one_computer (keys %computer_not_detected) {
829      my $interface = $computer_not_detected{$one_computer};
830      system "arping -c 1 -w 1 -rR -i $interface $one_computer &>/dev/null";
831#      print  "arping -c 1 -w 1 -rR -i $interface $one_computer 2>/dev/null\n";
832      }
833   return;
834   }
835
836sub cmd_removedb {
837   my @computer = @_;
838
839   test_maindb_environnement();
840
841   my $computerdb = YAML::Syck::LoadFile("$KLASK_DB_FILE");
842
843   LOOP_ON_COMPUTER:
844   for my $one_computer (@computer) {
845
846      if ( $one_computer =~ m/^ $RE_IPv4_ADDRESS $/xms
847            and exists $computerdb->{$one_computer} ) {
848         delete $computerdb->{$one_computer};
849         next;
850         }
851
852      my %resol_arp = resolve_ip_arp_host($one_computer);
853
854      delete $computerdb->{$resol_arp{ipv4_address}} if exists $computerdb->{$resol_arp{ipv4_address}};
855      }
856
857   my $dirdb = $KLASK_DB_FILE;
858      $dirdb =~ s{ / [^/]* $}{}xms;
859   mkdir "$dirdb", 0755 unless -d "$dirdb";
860   YAML::Syck::DumpFile("$KLASK_DB_FILE", $computerdb);
861   return;
862   }
863
864sub cmd_exportdb {
865   my @ARGV   = @_;
866
867   my $format = 'txt';
868
869   my $ret = GetOptions(
870      'format|f=s'  => \$format,
871      );
872
873   my %possible_format = (
874      txt  => \&cmd_exportdb_txt,
875      html => \&cmd_exportdb_html,
876      );
877
878   $format = 'txt' if not defined $possible_format{$format};
879
880   $possible_format{$format}->(@ARGV);
881   return;
882   }
883
884sub cmd_exportdb_txt {
885   test_maindb_environnement();
886
887   my $computerdb = YAML::Syck::LoadFile("$KLASK_DB_FILE");
888
889   printf "%-25s %-4s            %-40s %-15s %-18s %-16s %s\n", qw(Switch Port Hostname IPv4-Address MAC-Address Date VLAN);
890   print "-------------------------------------------------------------------------------------------------------------------------------------------\n";
891
892   LOOP_ON_IP_ADDRESS:
893   foreach my $ip (Net::Netmask::sort_by_ip_address(keys %{$computerdb})) {
894
895#      next LOOP_ON_IP_ADDRESS if $computerdb->{$ip}{hostname_fq} eq 'unknow';
896
897      # to be improve in the future
898      next LOOP_ON_IP_ADDRESS if $computerdb->{$ip}{hostname_fq} eq ($computerdb->{$ip}{switch_hostname} || $computerdb->{$ip}{switch_description}); # switch on himself !
899
900# dans le futur
901#      next if $computerdb->{$ip}{hostname_fq} eq 'unknow';
902
903      my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime $computerdb->{$ip}{timestamp};
904      $year += 1900;
905      $mon++;
906      my $date = sprintf '%04i-%02i-%02i %02i:%02i', $year, $mon, $mday, $hour, $min;
907
908      printf "%-26s  %2s  <-------  %-40s %-15s %-18s %-16s %s\n",
909         $computerdb->{$ip}{switch_hostname} || $computerdb->{$ip}{switch_description},
910         $computerdb->{$ip}{switch_port},
911         $computerdb->{$ip}{hostname_fq},
912         $ip,
913         $computerdb->{$ip}{mac_address},
914         $date,
915         $computerdb->{$ip}{network} || '';
916      }
917   return;
918   }
919
920sub cmd_exportdb_html {
921   test_maindb_environnement();
922
923   my $computerdb = YAML::Syck::LoadFile("$KLASK_DB_FILE");
924
925#<link rel="stylesheet" type="text/css" href="style-klask.css" />
926#<script src="sorttable-klask.js"></script>
927
928   print <<'END_HTML';
929<table class="sortable" summary="Klask export database">
930 <caption>Klask database</caption>
931 <thead>
932  <tr>
933   <th scope="col" class="hklask-switch">Switch</th>
934   <th scope="col" class="sorttable_nosort">Port</th>
935   <th scope="col" class="sorttable_nosort">Link</th>
936   <th scope="col" class="sorttable_alpha">Hostname</th>
937   <th scope="col" class="hklask-ipv4">IPv4-Address</th>
938   <th scope="col" class="sorttable_alpha">MAC-Address</th>
939   <th scope="col" class="sorttable_alpha">VLAN</th>
940   <th scope="col" class="hklask-date">Date</th>
941  </tr>
942 </thead>
943 <tfoot>
944  <tr>
945   <th scope="col" class="fklask-switch">Switch</th>
946   <th scope="col" class="fklask-port">Port</th>
947   <th scope="col" class="fklask-link">Link</th>
948   <th scope="col" class="fklask-hostname">Hostname</th>
949   <th scope="col" class="fklask-ipv4">IPv4-Address</th>
950   <th scope="col" class="fklask-mac">MAC-Address</th>
951   <th scope="col" class="fklask-vlan">VLAN</th>
952   <th scope="col" class="fklask-date">Date</th>
953  </tr>
954 </tfoot>
955 <tbody>
956END_HTML
957
958   my %mac_count = ();
959   LOOP_ON_IP_ADDRESS:
960   foreach my $ip (keys %{$computerdb}) {
961
962      # to be improve in the future
963      next LOOP_ON_IP_ADDRESS if $computerdb->{$ip}{hostname_fq} eq ($computerdb->{$ip}{switch_hostname} || $computerdb->{$ip}{switch_description}); # switch on himself !
964
965      $mac_count{$computerdb->{$ip}{mac_address}}++;
966      }
967
968   my $typerow = 'even';
969
970   LOOP_ON_IP_ADDRESS:
971   foreach my $ip (Net::Netmask::sort_by_ip_address(keys %{$computerdb})) {
972
973      # to be improve in the future
974      next LOOP_ON_IP_ADDRESS if $computerdb->{$ip}{hostname_fq} eq ($computerdb->{$ip}{switch_hostname} || $computerdb->{$ip}{switch_description}); # switch on himself !
975
976      my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime $computerdb->{$ip}{timestamp};
977      $year += 1900;
978      $mon++;
979      my $date = sprintf '%04i-%02i-%02i %02i:%02i', $year, $mon, $mday, $hour, $min;
980
981#      $odd_or_even++;
982#      my $typerow = $odd_or_even % 2 ? 'odd' : 'even';
983      $typerow = $typerow eq 'even' ? 'odd' : 'even';
984
985      my $switch_hostname = $computerdb->{$ip}{switch_hostname} || $computerdb->{$ip}{switch_description} || 'unkown';
986      chomp $switch_hostname;
987      my $switch_hostname_sort = sprintf '%s %3s' ,$switch_hostname, $computerdb->{$ip}{switch_port};
988
989      my $ip_sort = sprintf '%03i%03i%03i%03i', split m/ \. /xms, $ip;
990
991      my $mac_sort = sprintf '%04i-%s', 9999 - $mac_count{$computerdb->{$ip}{mac_address}}, $computerdb->{$ip}{mac_address};
992
993      $computerdb->{$ip}{hostname_fq} = 'unknow' if $computerdb->{$ip}{hostname_fq} =~ m/^ \d+ \. \d+ \. \d+ \. \d+ $/xms;
994      my ( $host_short ) = split m/ \. /xms, $computerdb->{$ip}{hostname_fq};
995
996      my $vlan = $computerdb->{$ip}{network} || '';
997
998      print <<"END_HTML";
999  <tr class="$typerow">
1000   <td sorttable_customkey="$switch_hostname_sort">$switch_hostname</td>
1001   <td class="bklask-port">$computerdb->{$ip}{switch_port}</td>
1002   <td><-------</td>
1003   <td sorttable_customkey="$host_short">$computerdb->{$ip}{hostname_fq}</td>
1004   <td sorttable_customkey="$ip_sort">$ip</td>
1005   <td sorttable_customkey="$mac_sort">$computerdb->{$ip}{mac_address}</td>
1006   <td>$vlan</td>
1007   <td>$date</td>
1008  </tr>
1009END_HTML
1010      }
1011
1012   my $switch_connection = YAML::Syck::LoadFile("$KLASK_SW_FILE");
1013
1014   my %db_switch_output_port       = %{$switch_connection->{output_port}};
1015   my %db_switch_parent            = %{$switch_connection->{parent}};
1016   my %db_switch_connected_on_port = %{$switch_connection->{connected_on_port}};
1017   my %db_switch                   = %{$switch_connection->{switch_db}};
1018
1019   for my $sw (sort keys %db_switch_output_port) {
1020
1021      my $switch_hostname_sort = sprintf '%s %3s' ,$sw, $db_switch_output_port{$sw};
1022
1023      $typerow = $typerow eq 'even' ? 'odd' : 'even';
1024
1025      if (exists $db_switch_parent{$sw}) {
1026
1027      my $mac_address = $db_switch{$db_switch_parent{$sw}->{switch}}->{mac_address};
1028      my $ipv4_address = $db_switch{$db_switch_parent{$sw}->{switch}}->{ipv4_address};
1029      my $timestamp = $db_switch{$db_switch_parent{$sw}->{switch}}->{timestamp};
1030
1031      my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime $timestamp;
1032      $year += 1900;
1033      $mon++;
1034      my $date = sprintf '%04i-%02i-%02i %02i:%02i', $year, $mon, $mday, $hour, $min;
1035
1036      my $ip_sort = sprintf '%03i%03i%03i%03i', split m/ \. /xms, $ipv4_address;
1037
1038      my $mac_sort = sprintf '%04i-%s', 9999, $mac_address;
1039
1040      my ( $host_short ) = sprintf '%s %3s' , split(m/ \. /xms, $db_switch_parent{$sw}->{switch}, 1), $db_switch_parent{$sw}->{port};
1041
1042      print <<"END_HTML";
1043  <tr class="$typerow">
1044   <td sorttable_customkey="$switch_hostname_sort">$sw</td>
1045   <td class="bklask-port">$db_switch_output_port{$sw}</>
1046   <td>+--> $db_switch_parent{$sw}->{port}</td>
1047   <td sorttable_customkey="$host_short">$db_switch_parent{$sw}->{switch}</>
1048   <td sorttable_customkey="$ip_sort">$ipv4_address</td>
1049   <td sorttable_customkey="$mac_sort">$mac_address</td>
1050   <td></td>
1051   <td>$date</td>
1052  </tr>
1053END_HTML
1054         }
1055      else {
1056         print <<"END_HTML";
1057  <tr class="$typerow">
1058   <td sorttable_customkey="$switch_hostname_sort">$sw</td>
1059   <td class="bklask-port">$db_switch_output_port{$sw}</>
1060   <td>+--></td>
1061   <td sorttable_customkey="router">router</>
1062   <td sorttable_customkey="999999999999"></td>
1063   <td sorttable_customkey="99999"></td>
1064   <td></td>
1065   <td></td>
1066  </tr>
1067END_HTML
1068         }
1069      }
1070
1071   for my $swport (sort keys %db_switch_connected_on_port) {
1072      my ($sw_connect,$port_connect) = split m/ : /xms, $swport;
1073      for my $sw (keys %{$db_switch_connected_on_port{$swport}}) {
1074
1075         my $switch_hostname_sort = sprintf '%s %3s' ,$sw_connect, $port_connect;
1076
1077      my $mac_address = $db_switch{$sw}->{mac_address};
1078      my $ipv4_address = $db_switch{$sw}->{ipv4_address};
1079      my $timestamp = $db_switch{$sw}->{timestamp};
1080
1081      my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime $timestamp;
1082      $year += 1900;
1083      $mon++;
1084      my $date = sprintf '%04i-%02i-%02i %02i:%02i', $year,$mon,$mday,$hour,$min;
1085
1086      my $ip_sort = sprintf '%03i%03i%03i%03i', split m/ \. /xms, $ipv4_address;
1087
1088      my $mac_sort = sprintf '%04i-%s', 9999, $mac_address;
1089
1090      $typerow = $typerow eq 'even' ? 'odd' : 'even';
1091
1092         if (exists $db_switch_output_port{$sw}) {
1093
1094            my ( $host_short ) = sprintf '%s %3s' , split( m/\./xms, $sw, 1), $db_switch_output_port{$sw};
1095
1096            print <<"END_HTML";
1097  <tr class="$typerow">
1098   <td sorttable_customkey="$switch_hostname_sort">$sw_connect</td>
1099   <td class="bklask-port">$port_connect</>
1100   <td>&lt;--+ $db_switch_output_port{$sw}</td>
1101   <td sorttable_customkey="$host_short">$sw</>
1102   <td sorttable_customkey="$ip_sort">$ipv4_address</td>
1103   <td sorttable_customkey="$mac_sort">$mac_address</td>
1104   <td></td>
1105   <td>$date</td>
1106  </tr>
1107END_HTML
1108            }
1109         else {
1110            print <<"END_HTML";
1111  <tr class="$typerow">
1112   <td sorttable_customkey="$switch_hostname_sort">$sw_connect</td>
1113   <td class="bklask-port">$port_connect</>
1114   <td>&lt;--+</td>
1115   <td sorttable_customkey="$sw">$sw</>
1116   <td sorttable_customkey="">$ipv4_address</td>
1117   <td sorttable_customkey="">$mac_address</td>
1118   <td></td>
1119   <td>$date</td>
1120  </tr>
1121END_HTML
1122            }
1123         }
1124      }
1125
1126   print <<'END_HTML';
1127 </tbody>
1128</table>
1129END_HTML
1130   return;
1131   }
1132
1133sub cmd_iplocation {
1134   my $computerdb = YAML::Syck::LoadFile("$KLASK_DB_FILE");
1135
1136   LOOP_ON_IP_ADDRESS:
1137   foreach my $ip (Net::Netmask::sort_by_ip_address(keys %{$computerdb})) {
1138
1139      next LOOP_ON_IP_ADDRESS if $computerdb->{$ip}{hostname_fq} eq ($computerdb->{$ip}{switch_hostname} || $computerdb->{$ip}{switch_description}); # switch on himself !
1140
1141      my $sw_hostname = $computerdb->{$ip}{switch_hostname} || q{};
1142      next if $sw_hostname eq 'unknow';
1143
1144      my $sw_location = q{};
1145      for my $sw (@SWITCH) {
1146         next if $sw_hostname ne $sw->{hostname};
1147         $sw_location = $sw->{location};
1148         last;
1149         }
1150
1151      printf "%s: \"%s\"\n", $ip, $sw_location if not $sw_location eq q{};
1152      }
1153   return;
1154   }
1155
1156sub cmd_ip_free {
1157   my @vlan_name = @_;
1158
1159   my $days_to_dead = 365 * 2;
1160   my $format = 'txt';
1161
1162   my $ret = GetOptionsFromArray(\@vlan_name,
1163      'day|d=i'      => \$days_to_dead,
1164      'format|f=s'   => \$format,
1165      );
1166
1167   @vlan_name = get_list_network() if not @vlan_name;
1168
1169#   my %possible_format = (
1170#      txt  => \&cmd_exportdb_txt,
1171#      html => \&cmd_exportdb_html,
1172#      );
1173#
1174#   $format = 'txt' if not defined $possible_format{$format};
1175#
1176#   $possible_format{$format}->(@ARGV);
1177
1178   my $computerdb = {};
1179      $computerdb = YAML::Syck::LoadFile("$KLASK_DB_FILE") if -e "$KLASK_DB_FILE";
1180   my $timestamp = time;
1181
1182   my $timestamp_barrier = $timestamp - (3600 * 24 * $days_to_dead );
1183
1184   my %result_ip= ();
1185
1186   ALL_NETWORK:
1187   for my $vlan (@vlan_name) {
1188
1189      my @ip_list = get_list_ip($vlan);
1190#      my $current_interface = get_current_interface($vlan);
1191     
1192      LOOP_ON_IP_ADDRESS:
1193      for my $ip (@ip_list) {
1194
1195         next LOOP_ON_IP_ADDRESS if
1196            exists $computerdb->{$ip}
1197            && $computerdb->{$ip}{timestamp} > $timestamp_barrier;
1198
1199         my $ip_date_last_detection = '';
1200         if (exists $computerdb->{$ip}) {
1201            my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime $computerdb->{$ip}{timestamp};
1202            $year += 1900;
1203            $mon++;
1204            $ip_date_last_detection = sprintf '%04i-%02i-%02i %02i:%02i', $year, $mon, $mday, $hour, $min;
1205            }
1206
1207         $result_ip{$ip} ||= {};
1208         $result_ip{$ip}->{date_last_detection} = $ip_date_last_detection;
1209
1210         my $packed_ip = scalar gethostbyname($ip);
1211         my $hostname_fq = 'unknown';
1212            $hostname_fq = scalar gethostbyaddr($packed_ip, AF_INET) || 'unknown' if defined $packed_ip;
1213         $result_ip{$ip}->{hostname_fq} = $hostname_fq;
1214         
1215         $result_ip{$ip}->{vlan} = $vlan;
1216         }
1217      }
1218
1219   printf "%-15s %-40s %-16s %s\n", qw(IPv4-Address Hostname-FQ Date VLAN);
1220   print "-------------------------------------------------------------------------------\n";
1221   LOOP_ON_RESULT:
1222   foreach my $ip (Net::Netmask::sort_by_ip_address(keys %result_ip)) {
1223         printf "%-15s %-40s %-16s %s\n", $ip, $result_ip{$ip}->{hostname_fq}, $result_ip{$ip}->{date_last_detection}, $result_ip{$ip}->{vlan};
1224      }
1225   }
1226
1227sub cmd_enable {
1228   my $switch = shift;
1229   my $port   = shift;
1230
1231   #snmpset -v 1 -c community X.X.X.X 1.3.6.1.2.1.2.2.1.7.NoPort = 1 (up)
1232   #snmpset -v 1 -c community X.X.X.X 1.3.6.1.2.1.2.2.1.7.NoPort = 2 (down)
1233   system "snmpset -v 1 -c public $switch 1.3.6.1.2.1.2.2.1.7.$port = 1";
1234   return;
1235   }
1236
1237sub cmd_disable {
1238   my $switch = shift;
1239   my $port   = shift;
1240
1241   system "snmpset -v 1 -c public $switch 1.3.6.1.2.1.2.2.1.7.$port = 2";
1242   return;
1243   }
1244
1245sub cmd_status {
1246   my $switch = shift;
1247   my $port   = shift;
1248
1249   system "snmpget -v 1 -c public $switch 1.3.6.1.2.1.2.2.1.7.$port";
1250   return;
1251   }
1252
1253sub cmd_search_mac_on_switch {
1254   my $switch_name = shift || q{};
1255   my $mac_address = shift || q{};
1256
1257   if ($switch_name eq q{} or $mac_address eq q{}) {
1258      die "Usage: klask search-mac-on-switch SWITCH_NAME MAC_ADDRESS\n";
1259      }
1260
1261   if (not defined $SWITCH_DB{$switch_name}) {
1262      die "Switch $switch_name must be defined in klask configuration file\n";
1263      }
1264
1265   my $sw = $SWITCH_DB{$switch_name};
1266   my %session = ( -hostname => $sw->{hostname} );
1267      $session{-version} = $sw->{version}   || 1;
1268      $session{-port}    = $sw->{snmpport}  || $DEFAULT{snmpport}  || 161;
1269   if (exists $sw->{version} and $sw->{version} eq '3') {
1270      $session{-username} = $sw->{username} || 'snmpadmin';
1271      }
1272   else {
1273      $session{-community} = $sw->{community} || $DEFAULT{community} || 'public';
1274      }
1275
1276   my $research = '1.3.6.1.2.1.17.4.3.1.2' . arp_hex_to_dec($mac_address);
1277   print "Klask search OID $research on switch $switch_name\n";
1278
1279   my ($session, $error) = Net::SNMP->session( %session );
1280   print "$error \n" if $error;
1281
1282   my $result = $session->get_request(
1283      -varbindlist => [$research]
1284      );
1285
1286   if (not defined $result or $result->{$research} eq 'noSuchInstance') {
1287      print "Klask do not find MAC $mac_address on switch $switch_name\n";
1288      $session->close;
1289      }
1290
1291   my $swport = $result->{$research};
1292   $session->close;
1293
1294   print "Klask find MAC $mac_address on switch $switch_name port $swport\n";
1295   return;
1296   }
1297
1298sub cmd_updatesw {
1299
1300   init_switch_names('yes');    #nomme les switchs
1301   print "\n";
1302
1303   my %where = ();
1304   my %db_switch_output_port = ();
1305   my %db_switch_ip_hostname = ();
1306
1307   DETECT_ALL_ROUTER:
1308#   for my $one_computer ('194.254.66.254') {
1309   for my $one_router ( get_list_main_router(get_list_network()) ) {
1310      my %resol_arp = resolve_ip_arp_host($one_router, q{*}, q{low}); # resolution arp
1311      next DETECT_ALL_ROUTER if $resol_arp{mac_address} eq 'unknow';
1312      $where{$resol_arp{ipv4_address}} = find_all_switch_port($resol_arp{mac_address}); # retrouve les emplacements des routeurs
1313      }
1314
1315   ALL_ROUTER_IP_ADDRESS:
1316   for my $ip (Net::Netmask::sort_by_ip_address(keys %where)) { # '194.254.66.254')) {
1317
1318      next ALL_ROUTER_IP_ADDRESS if not exists $where{$ip}; # /a priori/ idiot car ne sers à rien...
1319
1320      ALL_SWITCH_CONNECTED:
1321      for my $switch_detected ( keys %{$where{$ip}} ) {
1322
1323         my $switch = $where{$ip}->{$switch_detected};
1324
1325         next ALL_SWITCH_CONNECTED if $switch->{port} eq '0';
1326
1327         $db_switch_output_port{$switch->{hostname}} = $switch->{port};
1328         }
1329      }
1330
1331   my %db_switch_link_with = ();
1332
1333   my @list_switch_ip = ();
1334   my @list_switch_ipv4 = ();
1335   for my $sw (@SWITCH){
1336      push @list_switch_ip, $sw->{hostname};
1337      }
1338
1339   my $timestamp = time;
1340
1341   ALL_SWITCH:
1342   for my $one_computer (@list_switch_ip) {
1343      my %resol_arp = resolve_ip_arp_host($one_computer, q{*}, q{low}); # arp resolution
1344      next ALL_SWITCH if $resol_arp{mac_address} eq 'unknow';
1345
1346      push @list_switch_ipv4,$resol_arp{ipv4_address};
1347
1348      $where{$resol_arp{ipv4_address}} = find_all_switch_port($resol_arp{mac_address}); # find port on all switch
1349#my @l = ();
1350#for my $c  ( keys %{$where{$resol_arp{ipv4_address}}} ) {
1351#push @l, "$c -+ "; #$where{$resol_arp{ipv4_address}}->{$c}{hostname};
1352#}
1353#print "DEBUG  $one_computer $resol_arp{ipv4_address} $resol_arp{mac_address} --- @l\n";
1354
1355      $db_switch_ip_hostname{$resol_arp{ipv4_address}} = $resol_arp{hostname_fq};
1356
1357      $SWITCH_DB{$one_computer}->{ipv4_address} = $resol_arp{ipv4_address};
1358      $SWITCH_DB{$one_computer}->{mac_address}  = $resol_arp{mac_address};
1359      $SWITCH_DB{$one_computer}->{timestamp}    = $timestamp;
1360      }
1361
1362   ALL_SWITCH_IP_ADDRESS:
1363   for my $ip (Net::Netmask::sort_by_ip_address(@list_switch_ipv4)) {
1364
1365      next ALL_SWITCH_IP_ADDRESS if not exists $where{$ip};
1366
1367      DETECTED_SWITCH:
1368      for my $switch_detected ( keys %{$where{$ip}} ) {
1369
1370         next DETECTED_SWITCH if not exists $SWITCH_PORT_COUNT{ $db_switch_ip_hostname{$ip}};
1371
1372         my $switch = $where{$ip}->{$switch_detected};
1373#print "DEBUG1 :  $db_switch_ip_hostname{$ip} / $switch->{hostname} : $switch->{port}\n" if  $switch->{hostname} =~ m/sw3-batA0-3s/;
1374
1375         next if $switch->{port}     eq '0';
1376         next if $switch->{port}     eq $db_switch_output_port{$switch->{hostname}};
1377         next if $switch->{hostname} eq $db_switch_ip_hostname{$ip}; # $computerdb->{$ip}{hostname};
1378
1379         $db_switch_link_with{ $db_switch_ip_hostname{$ip} } ||= {};
1380         $db_switch_link_with{ $db_switch_ip_hostname{$ip} }->{ $switch->{hostname} } = $switch->{port};
1381#print "DEBUG :  $db_switch_ip_hostname{$ip} / $switch->{hostname} : $switch->{port}\n" if $switch->{hostname} !~ m/sw3-batA0-3s/;
1382         }
1383
1384      }
1385
1386   my %db_switch_connected_on_port = ();
1387   my $maybe_more_than_one_switch_connected = 'yes';
1388
1389   while ($maybe_more_than_one_switch_connected eq 'yes') {
1390      for my $sw (keys %db_switch_link_with) {
1391         for my $connect (keys %{$db_switch_link_with{$sw}}) {
1392
1393            my $port = $db_switch_link_with{$sw}->{$connect};
1394
1395            $db_switch_connected_on_port{"$connect:$port"} ||= {};
1396            $db_switch_connected_on_port{"$connect:$port"}->{$sw}++; # Just to define the key
1397            }
1398         }
1399
1400      $maybe_more_than_one_switch_connected  = 'no';
1401
1402      SWITCH_AND_PORT:
1403      for my $swport (keys %db_switch_connected_on_port) {
1404
1405         next if keys %{$db_switch_connected_on_port{$swport}} == 1;
1406
1407         $maybe_more_than_one_switch_connected = 'yes';
1408
1409         my ($sw_connect,$port_connect) = split m/ : /xms, $swport;
1410         my @sw_on_same_port = keys %{$db_switch_connected_on_port{$swport}};
1411
1412         CONNECTED:
1413         for my $sw_connected (@sw_on_same_port) {
1414
1415            next CONNECTED if not keys %{$db_switch_link_with{$sw_connected}} == 1;
1416
1417            $db_switch_connected_on_port{$swport} = {$sw_connected => 1};
1418
1419            for my $other_sw (@sw_on_same_port) {
1420               next if $other_sw eq $sw_connected;
1421
1422               delete $db_switch_link_with{$other_sw}->{$sw_connect};
1423               }
1424
1425            # We can not do better for this switch for this loop
1426            next SWITCH_AND_PORT;
1427            }
1428         }
1429      }
1430
1431   my %db_switch_parent =();
1432
1433   for my $sw (keys %db_switch_link_with) {
1434      for my $connect (keys %{$db_switch_link_with{$sw}}) {
1435
1436         my $port = $db_switch_link_with{$sw}->{$connect};
1437
1438         $db_switch_connected_on_port{"$connect:$port"} ||= {};
1439         $db_switch_connected_on_port{"$connect:$port"}->{$sw} = $port;
1440
1441         $db_switch_parent{$sw} = {switch => $connect, port => $port};
1442         }
1443      }
1444
1445   print "Switch output port and parent port connection\n";
1446   print "---------------------------------------------\n";
1447   for my $sw (sort keys %db_switch_output_port) {
1448      if (exists $db_switch_parent{$sw}) {
1449         printf "%-25s  %2s  +-->  %2s  %-25s\n", $sw, $db_switch_output_port{$sw}, $db_switch_parent{$sw}->{port}, $db_switch_parent{$sw}->{switch};
1450         }
1451      else {
1452         printf "%-25s  %2s  +-->  router\n", $sw, $db_switch_output_port{$sw};
1453         }
1454      }
1455   print "\n";
1456
1457   print "Switch parent and children port inter-connection\n";
1458   print "------------------------------------------------\n";
1459   for my $swport (sort keys %db_switch_connected_on_port) {
1460      my ($sw_connect,$port_connect) = split m/ : /xms, $swport;
1461      for my $sw (keys %{$db_switch_connected_on_port{$swport}}) {
1462         if (exists $db_switch_output_port{$sw}) {
1463            printf "%-25s  %2s  <--+  %2s  %-25s\n", $sw_connect, $port_connect, $db_switch_output_port{$sw}, $sw;
1464            }
1465         else {
1466            printf "%-25s  %2s  <--+      %-25s\n", $sw_connect, $port_connect, $sw;
1467            }
1468         }
1469      }
1470
1471   my $switch_connection = {
1472      output_port       => \%db_switch_output_port,
1473      parent            => \%db_switch_parent,
1474      connected_on_port => \%db_switch_connected_on_port,
1475      link_with         => \%db_switch_link_with,
1476      switch_db         => \%SWITCH_DB,
1477      };
1478
1479   YAML::Syck::DumpFile("$KLASK_SW_FILE", $switch_connection);
1480   return;
1481   }
1482
1483sub cmd_exportsw {
1484   my @ARGV   = @_;
1485
1486   test_switchdb_environnement();
1487
1488   my $format = 'txt';
1489
1490   my $ret = GetOptions(
1491      'format|f=s'  => \$format,
1492      );
1493
1494   my %possible_format = (
1495      txt => \&cmd_exportsw_txt,
1496      dot => \&cmd_exportsw_dot,
1497      );
1498
1499   $format = 'txt' if not defined $possible_format{$format};
1500
1501   $possible_format{$format}->(@ARGV);
1502   return;
1503   }
1504
1505sub cmd_exportsw_txt {
1506
1507   my $switch_connection = YAML::Syck::LoadFile("$KLASK_SW_FILE");
1508
1509   my %db_switch_output_port       = %{$switch_connection->{output_port}};
1510   my %db_switch_parent            = %{$switch_connection->{parent}};
1511   my %db_switch_connected_on_port = %{$switch_connection->{connected_on_port}};
1512
1513   print "Switch output port and parent port connection\n";
1514   print "---------------------------------------------\n";
1515   for my $sw (sort keys %db_switch_output_port) {
1516      if (exists $db_switch_parent{$sw}) {
1517         printf "%-25s  %2s  +-->  %2s  %-25s\n", $sw, $db_switch_output_port{$sw}, $db_switch_parent{$sw}->{port}, $db_switch_parent{$sw}->{switch};
1518         }
1519      else {
1520         printf "%-25s  %2s  +-->  router\n", $sw, $db_switch_output_port{$sw};
1521         }
1522      }
1523   print "\n";
1524
1525   print "Switch parent and children port inter-connection\n";
1526   print "------------------------------------------------\n";
1527   for my $swport (sort keys %db_switch_connected_on_port) {
1528      my ($sw_connect,$port_connect) = split m/ : /xms, $swport;
1529      for my $sw (keys %{$db_switch_connected_on_port{$swport}}) {
1530         if (exists $db_switch_output_port{$sw}) {
1531            printf "%-25s  %2s  <--+  %2s  %-25s\n", $sw_connect, $port_connect, $db_switch_output_port{$sw}, $sw;
1532            }
1533         else {
1534            printf "%-25s  %2s  <--+      %-25s\n", $sw_connect, $port_connect, $sw;
1535            }
1536         }
1537      }
1538   return;
1539   }
1540
1541sub cmd_exportsw_dot {
1542
1543   my $switch_connection = YAML::Syck::LoadFile("$KLASK_SW_FILE");
1544
1545   my %db_switch_output_port       = %{$switch_connection->{output_port}};
1546   my %db_switch_parent            = %{$switch_connection->{parent}};
1547   my %db_switch_connected_on_port = %{$switch_connection->{connected_on_port}};
1548   my %db_switch_link_with         = %{$switch_connection->{link_with}};
1549   my %db_switch_global            = %{$switch_connection->{switch_db}};
1550
1551   my %db_building= ();
1552   for my $sw (@SWITCH) {
1553      my ($building, $location) = split m/ \/ /xms, $sw->{location}, 2;
1554      $db_building{$building} ||= {};
1555      $db_building{$building}->{$location} ||= {};
1556      $db_building{$building}->{$location}{ $sw->{hostname} } = 'y';
1557      }
1558
1559
1560   print "digraph G {\n";
1561
1562   print "site [label = \"site\", color = black, fillcolor = gold, shape = invhouse, style = filled];\n";
1563   print "internet [label = \"internet\", color = black, fillcolor = cyan, shape = house, style = filled];\n";
1564
1565   my $b=0;
1566   for my $building (keys %db_building) {
1567      $b++;
1568
1569      print "\"building$b\" [label = \"$building\", color = black, fillcolor = gold, style = filled];\n";
1570      print "site -> \"building$b\" [len = 2, color = firebrick];\n";
1571
1572      my $l = 0;
1573      for my $loc (keys %{$db_building{$building}}) {
1574         $l++;
1575
1576         print "\"location$b-$l\" [label = \"$building" . q{/} . join(q{\n}, split(m{ / }xms, $loc)) . "\", color = black, fillcolor = orange, style = filled];\n";
1577#         print "\"location$b-$l\" [label = \"$building / $loc\", color = black, fillcolor = orange, style = filled];\n";
1578         print "\"building$b\" -> \"location$b-$l\" [len = 2, color = firebrick]\n";
1579
1580         for my $sw (keys %{$db_building{$building}->{$loc}}) {
1581
1582            print "\"$sw:$db_switch_output_port{$sw}\" [label = $db_switch_output_port{$sw}, color = black, fillcolor = lightblue,  peripheries = 2, style = filled];\n";
1583
1584            my $swname  = $sw;
1585               $swname .= q{\n-\n} . "$db_switch_global{$sw}->{model}" if exists $db_switch_global{$sw} and exists $db_switch_global{$sw}->{model};
1586            print "\"$sw\" [label = \"$swname\", color = black, fillcolor = palegreen, shape = rect, style = filled];\n";
1587            print "\"location$b-$l\" -> \"$sw\" [len = 2, color = firebrick, arrowtail = dot]\n";
1588            print "\"$sw\" -> \"$sw:$db_switch_output_port{$sw}\" [len=2, style=bold, arrowhead = normal, arrowtail = invdot]\n";
1589
1590
1591            for my $swport (keys %db_switch_connected_on_port) {
1592               my ($sw_connect,$port_connect) = split m/ : /xms, $swport;
1593               next if not $sw_connect eq $sw;
1594               next if $port_connect eq $db_switch_output_port{$sw};
1595               print "\"$sw:$port_connect\" [label = $port_connect, color = black, fillcolor = plum,  peripheries = 1, style = filled];\n";
1596               print "\"$sw:$port_connect\" -> \"$sw\" [len=2, style=bold, arrowhead= normal, arrowtail = inv]\n";
1597              }
1598            }
1599         }
1600      }
1601
1602#   print "Switch output port and parent port connection\n";
1603#   print "---------------------------------------------\n";
1604   for my $sw (sort keys %db_switch_output_port) {
1605      if (exists $db_switch_parent{$sw}) {
1606#         printf "   \"%s:%s\" -> \"%s:%s\"\n", $sw, $db_switch_output_port{$sw}, $db_switch_parent{$sw}->{switch}, $db_switch_parent{$sw}->{port};
1607         }
1608      else {
1609         printf "   \"%s:%s\" -> internet\n", $sw, $db_switch_output_port{$sw};
1610         }
1611      }
1612   print "\n";
1613
1614#   print "Switch parent and children port inter-connection\n";
1615#   print "------------------------------------------------\n";
1616   for my $swport (sort keys %db_switch_connected_on_port) {
1617      my ($sw_connect,$port_connect) = split m/ : /xms, $swport;
1618      for my $sw (keys %{$db_switch_connected_on_port{$swport}}) {
1619         if (exists $db_switch_output_port{$sw}) {
1620            printf "   \"%s:%s\" -> \"%s:%s\" [color = navyblue]\n", $sw, $db_switch_output_port{$sw}, $sw_connect, $port_connect;
1621            }
1622         else {
1623            printf "   \"%s\"   -> \"%s%s\"\n", $sw, $sw_connect, $port_connect;
1624            }
1625         }
1626      }
1627
1628print "}\n";
1629   return;
1630   }
1631
1632
1633__END__
1634
1635=head1 NAME
1636
1637klask - ports manager and finder for switch
1638
1639
1640=head1 USAGE
1641
1642 klask updatedb
1643 klask exportdb --format [txt|html]
1644
1645 klask updatesw
1646 klask exportsw --format [txt|dot]
1647
1648 klask searchdb computer
1649 klask search   computer
1650 klask search-mac-on-switch switch mac_addr
1651
1652 klask ip-free --day number_of_day [vlan_name]
1653
1654 klask enable  switch port
1655 klask disable swith port
1656 klask status  swith port
1657
1658
1659=head1 DESCRIPTION
1660
1661klask is a small tool to find where is a host in a big network. klask mean search in brittany.
1662
1663Klask has now a web site dedicated for it !
1664
1665 http://servforge.legi.inpg.fr/projects/klask
1666
1667
1668=head1 COMMANDS
1669
1670
1671=head2 search
1672
1673This 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.
1674
1675
1676=head2 enable
1677
1678This command activate a port on a switch by snmp. So you need to give the switch and the port number on the command line.
1679
1680
1681=head2 disable
1682
1683This command deactivate a port on a switch by snmp. So you need to give the switch and the port number on the command line.
1684
1685
1686=head2 status
1687
1688This 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.
1689
1690
1691=head2 updatedb
1692
1693This 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.
1694
1695
1696=head2 exportdb
1697
1698This 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...
1699
1700
1701=head2 updatesw
1702
1703This 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.
1704
1705
1706=head2 exportsw --format [txt|dot]
1707
1708This 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.
1709
1710 klask exportsw --format dot > /tmp/map.dot
1711 dot -Tpng /tmp/map.dot > /tmp/map.png
1712
1713
1714
1715=head1 CONFIGURATION
1716
1717Because 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 !
1718
1719Here an example, be aware with indent, it's important in YAML, do not use tabulation !
1720
1721 default:
1722   community: public
1723   snmpport: 161
1724
1725 network:
1726   labnet:
1727     ip-subnet:
1728       - add: 192.168.1.0/24
1729       - add: 192.168.2.0/24
1730     interface: eth0
1731     main-router: gw1.labnet.local
1732
1733   schoolnet:
1734     ip-subnet:
1735       - add: 192.168.6.0/24
1736       - add: 192.168.7.0/24
1737     interface: eth0.38
1738     main-router: gw2.schoolnet.local
1739
1740 switch:
1741   - hostname: sw1.klask.local
1742     portignore:
1743       - 1
1744       - 2
1745
1746   - hostname: sw2.klask.local
1747     location: BatK / 2 / K203
1748     type: HP2424
1749     portignore:
1750       - 1
1751       - 2
1752
1753I 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.
1754
1755
1756=head1 FILES
1757
1758 /etc/klask.conf
1759 /var/cache/klask/klaskdb
1760 /var/cache/klask/switchdb
1761
1762=head1 SEE ALSO
1763
1764Net::SNMP, Net::Netmask, Net::CIDR::Lite, NetAddr::IP, YAML
1765
1766
1767=head1 VERSION
1768
1769$Id: klask 71 2010-11-02 16:31:51Z g7moreau $
1770
1771
1772=head1 AUTHOR
1773
1774Written by Gabriel Moreau, Grenoble - France
1775
1776
1777=head1 LICENSE AND COPYRIGHT
1778
1779GPL version 2 or later and Perl equivalent
1780
1781Copyright (C) 2005-2009 Gabriel Moreau.
Note: See TracBrowser for help on using the repository browser.