From 78a2d0d47a493ef7845c86d4a1ba3e9a77a071ff Mon Sep 17 00:00:00 2001 From: root Date: Tue, 29 Aug 2017 19:36:43 +0100 Subject: proxy support and ILOv2 support --- INF.pm | 6 +- INF/DSRx020.pm | 13 ++ INF/ILO2.pm | 587 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ Makefile | 4 + ilo/myvtdpolicy | 10 + ilo/rc175p08.jar | Bin 0 -> 56077 bytes ilo/vtd191p06.jar | Bin 0 -> 122536 bytes inf.pl | 29 ++- 8 files changed, 644 insertions(+), 5 deletions(-) create mode 100644 INF/ILO2.pm create mode 100644 ilo/myvtdpolicy create mode 100644 ilo/rc175p08.jar create mode 100644 ilo/vtd191p06.jar diff --git a/INF.pm b/INF.pm index 46500e4..962b15a 100644 --- a/INF.pm +++ b/INF.pm @@ -2,6 +2,7 @@ package INF; use INF::APC; use INF::DSRx020; use INF::ILO; +use INF::ILO2; #$infs = [ @@ -30,9 +31,10 @@ sub new ($;$) { } elsif ( $inf->{inf_type} eq 'apc' ) { return INF::APC->new($inf); - } - elsif ( $inf->{inf_type} eq 'ilo' ) { + } elsif ( $inf->{inf_type} eq 'ilo' ) { return INF::ILO->new($inf); + } elsif ( $inf->{inf_type} eq 'ilo2' ) { + return INF::ILO2->new($inf); } else { return undef; diff --git a/INF/DSRx020.pm b/INF/DSRx020.pm index d99cfad..fad319c 100644 --- a/INF/DSRx020.pm +++ b/INF/DSRx020.pm @@ -8,6 +8,7 @@ use IO::Socket::SSL qw(); use HTML::TreeBuilder; use HTTP::Request::Common; use LWP::UserAgent; +use LWP::Protocol::socks; use URI::Escape; use File::Temp qw/ tempfile tempdir /; use XML::Simple; @@ -477,7 +478,13 @@ sub view($$) { #print join( ' ', ( "java", "-cp", $cp, "com.avocent.video.Stingray", @$args ) ), "\n"; + if ($self->{proxy_host}) { + system( "echo","java", "-DsocksProxyHost=".$self->{proxy_host},"-DsocksProxyPort=".$self->{proxy_port},"-cp", $cp, "com.avocent.video.Stingray", @$args ); + system( "java", "-DsocksProxyHost=".$self->{proxy_host},"-DsocksProxyPort=".$self->{proxy_port},"-cp", $cp, "com.avocent.video.Stingray", @$args ); + + } else { system( "java", "-cp", $cp, "com.avocent.video.Stingray", @$args ); + } } @@ -604,6 +611,12 @@ sub new ($;$) { $self->{host} = $parm->{host} || "127.0.0.1"; + if (defined $parm->{proxy_host}) { + $self->{ua}->proxy([qw(http https)] => "socks://".$parm->{proxy_host}.":".$parm->{proxy_port}); + $self->{proxy_host}= $parm->{proxy_host}; + $self->{proxy_port}= $parm->{proxy_port}; + } + $self->{user} = $parm->{user} || "Admin"; $self->{password} = $parm->{password} || ""; diff --git a/INF/ILO2.pm b/INF/ILO2.pm new file mode 100644 index 0000000..de31e2a --- /dev/null +++ b/INF/ILO2.pm @@ -0,0 +1,587 @@ +#!/usr/bin/env perl + +IO::Socket::SSL::set_ctx_defaults( SSL_verify_mode => SSL_VERIFY_NONE ); + +package INF::ILO2; + +use HTTP::Daemon::SSL; +use HTTP::Server::Brick; +use HTTP::Status; + +use IO::Socket::SSL qw(); +use HTML::TreeBuilder; +use HTTP::Request::Common; +use LWP::UserAgent; +use URI::Escape; +use File::Temp qw/ tempfile tempdir /; +use XML::Simple; +use Data::Dumper; +use JSON::PP; + +use MIME::Base64 qw( encode_base64 ); + +sub b64($) +{ +my $ret=shift; +$ret=encode_base64($ret); +$ret =~ s/[\n\s\r]//g; + +return $ret; +} + +sub read_file($) { + my ($name) = @_; + + my $fh = new IO::File "<" . $name; + local $/; + my $guts = $fh->getline; + $fh->close; + undef $fh; + + return $guts; +} + +sub setup_port_proxy($$$) { + my ( $local_port, $remote_host, $remote_port ) = @_; + + my $child = fork(); + + print STDERR "balance ", + join( + ' ', + ( + "balance", "-d", "-f", "127.0.0.1", $local_port, + $remote_host . ":" . $remote_port + ) + ), + "\n"; + + if ( $child == 0 ) { + + exec( "balance", "-d", "-f", "-b", "127.0.0.1", $local_port, + $remote_host . ":" . $remote_port ); + print STDERR "failed to start port proxy"; + sleep(10000); + } + + print "Setup proxy $local_port -> $remote_host:$remote_port\n"; + + return $child; +} + +sub proxy($$$) { + my ( $self, $req, $res ) = @_; + + if ( $req->uri->as_string =~ /^\/html\/java_irc.html/ ) { + + $res->header( 'Content-type' => 'text/html' ); + $res->add_content( $self->{java_html} ); + $res->code(200); + + return; + + } + + if ( $req->uri->as_string =~ /^\/html\/rc.*\.jar/ ) { + + $res->header( 'Content-type' => 'application/x-ms-application' ); + $res->add_content( + read_file('/usr/local/share/inf/ilo/rc175p08.jar') ); + $res->code(200); + + return; + } + + if ( $req->uri->as_string =~ /^\/html\/vtd.*\.jar/ ) { + + $res->header( 'Content-type' => 'application/x-ms-application' ); + $res->add_content( + read_file('/usr/local/share/inf/ilo/vtd191p06.jar') ); + $res->code(200); + + return; + } + + print "Another url...". $req->uri->as_string."\n"; + + die "meh"; + +# +# my $proxy_req = +# HTTP::Request->new( $req->method, $self->{ilo_url} . $req->uri->as_string, +# [], $req->content ); +# +# $proxy_req->header( 'cookie' => 'sessionKey=' . $self->{stoken} ); +# +# my $proxy_res = $self->{ua}->request($proxy_req); +# +# unless ( $proxy_res->is_success ) { +# print STDERR "request failed - did not get 200\n"; +# } +# +# print "URI:", $req->uri->as_string, " code ", $proxy_res->code, " type ", +# $proxy_res->header('Content-type'), "\n"; +# +# $res->code( $proxy_res->code ); +# $res->header( 'Content-type' => $proxy_res->header('Content-type') ); +# +# my $content = $proxy_res->content; +# +# if ( $req->uri->as_string =~ /^\/json\/rc_info/ ) { +# +# my $local_port = int( rand(30000) ) + 30000; +# +# $content =~ s/"rc_port":(\d+),/"rc_port":$local_port,/; +# push @{ $self->{to_kill} }, +# setup_port_proxy( $local_port, $self->{host}, $1 ); +# +# $local_port = int( rand(30000) ) + 30000; +# +# $content =~ s/"vm_port":(\d+),/"vm_port":$local_port,/; +# push @{ $self->{to_kill} }, +# setup_port_proxy( $local_port, $self->{host}, $1 ); +# +# } +# +# $res->add_content($content); +# +} + +sub login($) { + my $self = shift; + + $self->{stoken} = undef; + $self->{skey} = undef; + $self->{sindex} = undef; + + my $get = GET( $self->{ilo_url} . '/login.htm' ); + + my $res = $self->{ua}->request($get); + + unless ( $res->is_success ) { + print STDERR "Get nonce failed - did not get 200\n"; + + print Dumper($res); + + return -1; + } + + my $content=$res->content; + + return -1 unless $content =~ /sessionkey="([A-Z0-9]+)"/ ; + + $self->{skey}=$1; + + print"skey=".$self->{skey}."\n"; + + return -1 unless $content =~ /sessionindex="([0-9]+)"/ ; + + $self->{sindex}=$1; + print"sindex=".$self->{sindex}."\n"; + + + $self->{slogin}="hp-iLO-Login=".$self->{sindex}.":".b64($self->{user}) . ":" . b64($self->{password}).":".$self->{skey}; + + print "Session login ".$self->{slogin}."\n"; + + $get = GET( $self->{ilo_url} . '/index.htm' ); + $get->header( 'cookie' => $self->{slogin} ); + $get->header( 'Referer' => $self->{ilo_url} . '/login.htm' ); + + $res = $self->{ua}->request($get); + + unless ( $res->is_success ) { + print STDERR "Get nonce failed - did not get 200\n"; + + print Dumper($res); + + return -1; + } + + my $content=$res->content; + + return -1 unless $content =~ /ie_index.htm/; + + $self->{stoken}='hp-iLO-Session='.$self->{sindex}.':::'.$self->{skey}.';'.$self->{slogin}; + + print "Session token ".$self->{stoken}."\n"; + + return 0; +} + +sub view($) { + + + my $self = shift; + + $self->login() unless defined $self->{stoken}; + + + my $get = GET( $self->{ilo_url} . '/drc2fram.htm?restart=0' ); + + $get->header( 'cookie' => $self->{stoken} ); + + my $res = $self->{ua}->request($get); + + unless ( $res->is_success ) { + print STDERR "drc2fram frequest failed - did not get 200\n"; + return -1; + } + my $content = $res->content; + + unless ( $content =~ /com.hp.ilo2.remcons.remcons.class/ ) { + print STDERR "returned html doesn't look right\n"; + return -1; + } + + my $things={}; + + + for my $thing ( qw( consoleWidth consoleHeight info1 info2 info3 info4 info5 info6 infomp infoscp info7 info8 slot_number info0 irc_fullscreen rcseize_timeout infoa infob infoc infod infom infomm infok infosc infocc infoae infomu infoms infon infoo infoscp infopriv)) +{ + + + return -1 unless $content =~ /${thing}=([^;]*);/; + + $things->{$thing}=$1; + $things->{$thing} =~ s/[\\"']//g ; +} + + +my $local_port = int( rand(30000) ) + 30000; + + push @{ $self->{to_kill} }, setup_port_proxy( $local_port, $self->{host}, $things->{info6} ); + +$things->{info6}=$local_port; +$things->{consoleWidth}=1024; +$things->{consoleHeight}=768; + + +my $document=''."\n"; + +$document .=''."\n"; +$document .=''."\n"; +$document .=''."\n"; +$document .=''."\n"; +$document .=''."\n"; +$document .=''."\n"; +$document .=''."\n"; +$document .=''."\n"; +$document .=''."\n"; +$document .=''."\n"; +$document .=''."\n"; +$document .=''."\n"; +$document .=''."\n"; +$document .=''."\n"; +$document .=''."\n"; +$document .=''; + + + $document = "" . $document . ""; + +print Dumper($document); + + $self->{java_html} = $document; + + my $webserver_pid = fork(); + + if ( $webserver_pid == 0 ) { + $SIG{INT} = sub { kill 'KILL', ( @{ $self->{to_kill} } ); die; }; + $SIG{TERM} = sub { kill 'KILL', ( @{ $self->{to_kill} } ); die; }; + + $self->{server}->start; + print STDERR "failed to web server"; + sleep(100000); + } + + push @{ $self->{to_kill} }, $webserver_pid; + + $SIG{INT} = sub { kill 'INT', ( @{ $self->{to_kill} } ); die; }; + $SIG{TERM} = sub { kill 'TERM', ( @{ $self->{to_kill} } ); die; }; + + system( +# "strace","-f","-o","t2","-s","8192", +# "/bin/appletviewer", + "appletviewer", + "-J-Djava.security.manager", + "-J-Djava.security.policy=/usr/local/share/inf/ilo/mypolicy", + "-J-Djavax.net.ssl.trustStore=/usr/local/share/inf/ilo/server.jks", + $self->{proxy_url} . "/html/java_irc.html" + ); + + kill 'TERM', ( @{ $self->{to_kill} } ); +} + + +sub media($) { + my $self = shift; + + $self->login() unless defined $self->{stoken}; + + + my $get = GET( $self->{ilo_url} . '/vtd028.htm' ); + + $get->header( 'cookie' => $self->{stoken} ); + + my $res = $self->{ua}->request($get); + + unless ( $res->is_success ) { + print STDERR "vtd frequest failed - did not get 200\n"; + return -1; + } + my $content = $res->content; + + unless ( $content =~ /com.hp.ilo2.virtdevs.virtdevs.class/ ) { + print STDERR "returned html doesn't look right\n"; + return -1; + } + + my $things={}; + + + for my $thing ( qw( info0v info1v usbcfg serverName dp)) +{ + + + return -1 unless $content =~ /${thing}=([^;]*);/; + + $things->{$thing}=$1; + $things->{$thing} =~ s/[\\"']//g ; +} + + +my $local_port = int( rand(30000) ) + 30000; + + push @{ $self->{to_kill} }, setup_port_proxy( $local_port, $self->{host}, $things->{info1v} ); + +$things->{info1v}=$local_port; + + +my $document=''."\n"; +$document .=''."\n"; +$document .=''."\n"; +$document .=''."\n"; +$document .=''."\n"; +$document .=''."\n"; +$document .=''."\n" if $things->{dp} != 0; +$document .=''; + + + $document = "" . $document . ""; + +print Dumper($document); + + $self->{java_html} = $document; + + my $webserver_pid = fork(); + + if ( $webserver_pid == 0 ) { + $SIG{INT} = sub { kill 'KILL', ( @{ $self->{to_kill} } ); die; }; + $SIG{TERM} = sub { kill 'KILL', ( @{ $self->{to_kill} } ); die; }; + + $self->{server}->start; + print STDERR "failed to web server"; + sleep(100000); + } + + push @{ $self->{to_kill} }, $webserver_pid; + + $SIG{INT} = sub { kill 'INT', ( @{ $self->{to_kill} } ); die; }; + $SIG{TERM} = sub { kill 'TERM', ( @{ $self->{to_kill} } ); die; }; + + system( +# "strace","-f","-o","t2","-s","8192", +# "/bin/appletviewer", + "appletviewer", + "-J-Djava.security.manager", + "-J-Djava.security.policy=/usr/local/share/inf/ilo/myvtdpolicy", + "-J-Djavax.net.ssl.trustStore=/usr/local/share/inf/ilo/server.jks", + $self->{proxy_url} . "/html/java_irc.html" + ); + + kill 'TERM', ( @{ $self->{to_kill} } ); +} + +sub get_host_power($) { + my ($self) = @_; + die "soup"; + + $self->login() unless defined $self->{stoken}; + + my $get = GET( $self->{ilo_url} . '/json/host_power' ); + + $get->header( 'cookie' => 'sessionKey=' . $self->{stoken} ); + + my $res = $self->{ua}->request($get); + + unless ( $res->is_success ) { + print STDERR " get host power - did not get 200\n"; + return undef; + } + + my $state = decode_json $res->content; + + return $state->{'hostpwr_state'}; + +} + +sub set_host_power($$) { + my ( $self, $what ) = @_; + + die "fish"; + + $self->login() unless defined $self->{stoken}; + + my $post = POST( $self->{ilo_url} . '/json/host_power' ); + my $json = + '{"method":"' . $what . '","session_key":"' . $self->{stoken} . '"}'; + $post->header( 'Content-Type' => 'application/json' ); + $post->header( 'Content-Length' => length($json) ); + $post->content($json); + $post->header( 'cookie' => 'sessionKey=' . $self->{stoken} ); + + my $res = $self->{ua}->request($post); + + unless ( $res->is_success ) { + print STDERR " $what - did not get 200\n"; + return 0; + } + + return 1; +} + +sub cold_boot($) { + my $self = shift; + return $self->set_host_power('system_coldboot'); +} + +sub reset($) { + my $self = shift; + return $self->set_host_power('system_reset'); +} + +sub off($) { + my $self = shift; + if ( $self->get_host_power =~ /ON/i ) { + return $self->set_host_power('hold_power_button'); + } + return 1; +} + +sub on($) { + my $self = shift; + if ( $self->get_host_power =~ /OFF/i ) { + return $self->set_host_power('press_power_button'); + } + return 1; +} + +sub port_on($$) { + my $self = shift; + return $self->on(); +} + +sub port_off($$) { + my $self = shift; + return $self->off(); +} + +sub port_cycle($$) { + my $self = shift; + return $self->cold_boot(); +} + +sub port_state_get_no_cache($$) { + my $self = shift; + return $self->get_host_power(); +} + +sub port_state_get($$) { + my $self = shift; + return $self->get_host_power(); +} + +sub port_name_get($$) { + my $self = shift; + return $self->{name}; +} + +sub name_get($) { + my $self = shift; + return $self->{name}; +} + +sub pdu_load_get($) { + return "N/A"; +} + +sub psu_status($) { + return "N/A"; +} + +sub port_count($) { + return 1; +} + +sub port_id_get_by_number($$) { + return "K0"; +} + +sub new ($;$) { + my ( $class, $parm ) = @_; + my $self; + + + $self->{ua} = my $ua = LWP::UserAgent->new; + + $self->{host} = $parm->{host} || "127.0.0.1"; + + $self->{user} = $parm->{user} || "Administrator"; + $self->{password} = $parm->{password} || ""; + + $self->{name} = $parm->{name} || $self->{host}; + + $self->{ilo_url} = $parm->{ilo_url} + || 'https://' . $self->{host}; + $self->{userid} = undef; + + $self->{ua}->ssl_opts( + SSL_verify_mode => IO::Socket::SSL::SSL_VERIFY_NONE, + verify_hostname => 0, + ); + + my $local_port = int( rand(30000) ) + 30000; + + $self->{proxy_url} = 'https://127.0.0.1:' . $local_port; + + $self->{server} = HTTP::Server::Brick->new( + port => $local_port, + daemon_class => 'HTTP::Daemon::SSL', + daemon_args => [ + LocalAddr => '127.0.0.1', + SSL_key_file => '/usr/local/share/inf/ilo/server.key', + SSL_cert_file => '/usr/local/share/inf/ilo/server.crt', + ], + ); + $self->{server}->mount( + '/' => { + handler => sub { + my ( $req, $res ) = @_; + + $self->proxy( $req, $res ); + 1; + }, + wildcard => 1, + } + ); + + $self->{stoken} = undef; + $self->{to_kill} = []; + + return bless $self, $class; + +} + +1; + diff --git a/Makefile b/Makefile index d9d401e..307448d 100644 --- a/Makefile +++ b/Makefile @@ -11,6 +11,7 @@ install: install -m 644 INF/APC.pm /usr/local/share/inf/INF install -m 644 INF/DSRx020.pm /usr/local/share/inf/INF install -m 644 INF/ILO.pm /usr/local/share/inf/INF + install -m 644 INF/ILO2.pm /usr/local/share/inf/INF install -m 644 mibs/PowerNet-MIB.mib /usr/local/share/inf/mibs/ install -m 644 mibs/RFC1155-SMI.mib /usr/local/share/inf/mibs/ install -m 644 mibs/RFC-1212.mib /usr/local/share/inf/mibs/ @@ -30,7 +31,10 @@ install: install -m 644 avocent/jpcscso.jar /usr/local/share/inf/avocent/ install -m 644 ilo/certs /usr/local/share/inf/ilo/ install -m 644 ilo/intgapp_221.jar /usr/local/share/inf/ilo/ + install -m 644 ilo/rc175p08.jar /usr/local/share/inf/ilo/ + install -m 644 ilo/vtd191p06.jar /usr/local/share/inf/ilo/ install -m 644 ilo/mypolicy /usr/local/share/inf/ilo/ + install -m 644 ilo/myvtdpolicy /usr/local/share/inf/ilo/ install -m 644 ilo/server.cnf /usr/local/share/inf/ilo/ install -m 644 ilo/server.crt /usr/local/share/inf/ilo/ install -m 644 ilo/server.jks /usr/local/share/inf/ilo/ diff --git a/ilo/myvtdpolicy b/ilo/myvtdpolicy new file mode 100644 index 0000000..e3311ae --- /dev/null +++ b/ilo/myvtdpolicy @@ -0,0 +1,10 @@ +grant { + permission java.net.SocketPermission "localhost", "connect, accept ,resolve, listen"; + permission java.util.PropertyPermission "java.io.tmpdir","read"; + permission java.io.FilePermission "/tmp/-", "read, write"; + permission java.io.FilePermission "/tmp", "read, write"; + permission java.io.FilePermission "/", "read, write"; + permission java.io.FilePermission "/-", "read, write"; + permission java.util.PropertyPermission "*", "read,write"; + permission java.lang.RuntimePermission "loadLibrary.*"; +}; diff --git a/ilo/rc175p08.jar b/ilo/rc175p08.jar new file mode 100644 index 0000000..0e44e75 Binary files /dev/null and b/ilo/rc175p08.jar differ diff --git a/ilo/vtd191p06.jar b/ilo/vtd191p06.jar new file mode 100644 index 0000000..4688a46 Binary files /dev/null and b/ilo/vtd191p06.jar differ diff --git a/inf.pl b/inf.pl index 4861240..fe9d4a1 100755 --- a/inf.pl +++ b/inf.pl @@ -16,6 +16,15 @@ sub view($$) { exit(0); } + +sub media($$) { + my ( $inf, $port ) = @_; + + $inf->media($port); + + exit(0); +} + sub thing($$$$) { my ( $inf, $port, $thing, $force ) = @_; @@ -28,8 +37,11 @@ sub thing($$$$) { my $name = $inf->name_get(); my $port_name = $inf->port_name_get($port); + view( $inf, $port ) if $thing eq 'view'; + media( $inf, $port ) if $thing eq 'media'; + unless ( $force == 1 ) { print "Are you sure you want to $thing\n"; print "$port_name, port $port on PDU $host($name)\n"; @@ -104,6 +116,7 @@ sub thing_search($$$$) { my $n = $inf->port_count(); + for ( my $i = 1 ; $i <= $n ; ++$i ) { my $port = $inf->port_id_get_by_number($i); my $o = $inf->port_name_get($port); @@ -199,10 +212,10 @@ sub usage() { print "Usage:\n"; print "inf -s hostname [-p port] -n name\n"; print " set name or switch, or port of switch to name\n"; - print "inf -s hostname -p port {-c|-o|-f|-v}\n"; + print "inf -s hostname -p port {-c|-o|-f|-v|-m}\n"; print " cycle -c, turn on -o or turn off -f or view -v,\n"; print " port on switch\n"; - print "inf [-s hostname] [-F] {-c|-o|-f|-v} regexp\n"; + print "inf [-s hostname] [-F] {-c|-o|-f|-v|-m} regexp\n"; print " cycle -c, turn on -o or turn off -f or view -v,\n"; print " the first thing found which matches regex.\n"; print " -s limits search to only one switch, -F doesn't\n"; @@ -217,7 +230,7 @@ sub usage() { my $options = {}; -getopts( "Fv:c:o:f:s:n:p:lh", $options ); +getopts( "Fv:m:c:o:f:s:n:p:lh", $options ); my $infs = []; my $port = undef; @@ -295,6 +308,16 @@ if ( exists $options->{v} ) { } } +if ( exists $options->{m} ) { + if ( defined $port ) { + thing( INF->new( $infs->[0] ), $port, 'media', $force ); + exit(0); + } + else { + thing_search( $infs, $options->{v}, 'media', $force ); + } +} + if ( $options->{n} ) { if ( scalar(@$infs) != 1 ) { print "Use of -n requires use of -s\n"; -- cgit v1.2.3