#!/usr/bin/perl # $RedRiver$ ######################################################################## # su.cgi *** a CGI for Trango SU utilities. # # 2007.02.07 #*#*# andrew fresh ######################################################################## # Copyright (C) 2007 by Andrew Fresh # # This program is free software; you can redistribute it and/or modify # it under the same terms as Perl itself. ######################################################################## use strict; use warnings; my $host_file = '/conf/wstationinfo/hosts.xml'; my $default_mac = '0001DE'; my $default_suid = 'all'; my $default_cir = 256; my $default_mir = 9999; my $Start_SUID = 3; use CGI qw/:standard/; use XML::Simple; use Net::Telnet::Trango; use File::Basename; my $me = basename($0); print header, start_html('Trango SU Utilities'), h1('Trango SU Utilities'); my $aps = get_aps($host_file); if (param()) { my $AP = param('AP'); unless (exists $aps->{$AP}) { print h3("AP '$AP' does not exist!"); print end_html; exit; } my $sumac = param('sumac'); $sumac =~ s/[^0-9A-Fa-f]//g; $sumac = uc($sumac); my $suid = param('suid'); if (length $sumac == 12) { add_su($aps->{$AP}, $sumac); } elsif (length $suid) { testrflink($aps->{$AP}, $suid); } else { print h3("Invalid SUID '$suid' and MAC '$sumac'"); show_form($aps, $default_mac); } } else { show_form($aps, $default_mac); } print end_html; sub get_aps { my $file = shift; my $conf = Read_Hosts($file); my %aps; foreach my $ap (@{ $conf }) { if ($ap->{'group'} eq 'Trango') { my $name = $ap->{'comment'} || $ap->{'name'}; $aps{ $name } = $ap; } } return \%aps; return { 'rrlhcwap0000' => { group => 'Trango', version => 1, name => '192.168.1.1', port => 161, Read_Community => 'private', Write_Community => 'private', } }; } sub show_form { my $aps = shift; my %cache = (); my @ap_names = sort { my @a = $a =~ /(\d+)\.(\d+)\.(\d+)\.(\d+)/; my @b = $b =~ /(\d+)\.(\d+)\.(\d+)\.(\d+)/; if (@a) { $cache{$a} ||= pack('C4' => @a); } else { $cache{$a} ||= lc($a); } if (@b) { $cache{$b} ||= pack('C4' => @b); } else { $cache{$b} ||= lc($b); } $cache{$a} cmp $cache{$b}; } keys %{ $aps }; print p(start_form(-method => 'GET'), 'AP: ', popup_menu(-name=>'AP', -values=>\@ap_names),br, 'SUMAC: ', textfield(-name=>'sumac',-default=>$default_mac),br, 'SUID: ', textfield(-name=>'suid',-default=>$default_suid),br, submit, end_form); print p('Fill in the SUMAC if you wish to add an SU ', 'or fill in the SUID to run an rflinktest.'); return 1; } sub login { my $host = shift; my $password = shift; my $t = new Net::Telnet::Trango ( Timeout => 5 ); #$t->input_log('/tmp/telnet_log'); #$t->dump_log('/tmp/telnet_log'); unless ($t->open( Host => $host )) { print h3("Error connecting!"); $t->close; return undef; } unless ($t->login( $password ) ) { print h3("Couldn't log in: $!"); $t->exit; $t->close; return undef; } return $t; } sub add_su { my $ap = shift; my $sumac = shift; my $t = login($ap->{'name'}, $ap->{'Telnet_Password'}); my $cur_sus = $t->sudb_view; my $new_suid = next_suid($cur_sus); foreach my $su (@{ $cur_sus }) { if ($sumac eq $su->{'mac'}) { print h3("MAC '$sumac' already in AP '$ap->{'name'}' with SUID '$su->{'suid'}'"); $t->exit; $t->close; return undef; } } unless ($t->sudb_add( $new_suid, 'reg', $default_cir, $default_mir, $sumac ) ) { print h3("Error adding SU!"); $t->exit; $t->close; return undef; } my $new_sus = $t->sudb_view; my $added = 0; foreach my $su (@{ $new_sus }) { if ($su->{'suid'} == $new_suid) { $added = 1; last; } } unless ($added) { print h3("Couldn't add su id: $new_suid"); $t->exit; $t->close; return undef; } unless ($t->save_sudb) { print h3("Couldn't save sudb"); $t->exit; $t->close; return undef; } print p( "Added new SU with ID '$new_suid' " . "and MAC '$sumac' " . "to '$ap->{'name'}'. " . 'Test SU RFLink' ); $t->exit; $t->close; return 1; } sub testrflink { my $ap = shift; my $suid = shift; my $t = login($ap->{'name'}, $ap->{'Telnet_Password'}); my $result = $t->su_testrflink( $suid ); unless ($result) { print h3("Error testing SU rflink!"); $t->exit; $t->close; return undef; } my @keys = ('suid', 'AP Tx', 'AP Rx', 'SU Rx'); my @table; foreach my $su (@{ $result }) { next unless ref $su eq 'HASH'; next unless exists $su->{'suid'}; $su->{'suid'} =~ s/\D//g; next unless $su->{'suid'}; push @table, td([ @{ $su }{ @keys } ]); } print table({-border=>1,-cellspacing=>0,-cellpadding=>1}, caption($ap->{'name'} . ': su testrflink ' . $suid), Tr({-align=>'CENTER', -valign=>'TOP'}, [ th(\@keys), @table ] ) ); $t->exit; $t->close; return 1; } sub next_suid { my $sudb = shift; my $next_id = $Start_SUID; my %ids = map { $_->{'suid'} => 1 } @{ $sudb }; my $next_key = sprintf('%04d', $next_id); while (exists $ids{$next_key}) { $next_id++; $next_key = sprintf('%04d', $next_id); } return $next_id; } sub Read_Hosts { my $file = shift; my $xs = XML::Simple->new(); my %Default_SNMP = ( Read_Community => 'public', Telnet_Password => 'password', port => 161, version => 1, ); my @hosts; my $hosts = $xs->XMLin($file, keyattr => [ 'Station' ], ForceArray => qr/^Host$/, ); foreach my $group (keys %{ $hosts }) { next if $group eq 'Read_Community'; foreach my $host (@{ $hosts->{$group}->{Host} }) { foreach my $item ('Read_Community', 'Telnet_Password', 'port', 'version') { $host->{$item} = $host->{$item} || $hosts->{$group}->{$item} || $hosts->{$item} || $Default_SNMP{$item}; } $host->{group} = $group; push @hosts, $host; } } return \@hosts; }