#
# (c) Jan Gehring <jan.gehring@gmail.com>
# 
# vim: set ts=3 sw=3 tw=0:
# vim: set expandtab:
   
package Rex::Hardware::Network::Solaris;
   
use strict;
use warnings;

use Rex::Logger;
use Rex::Commands::Run;
use Rex::Helper::Array;

sub get_network_devices {

   my @device_list = grep { $_=$1 if /^([a-z0-9]+)\:/i } run "ifconfig -a";

   @device_list = array_uniq(@device_list);
   return \@device_list;

}

sub get_network_configuration {
   
   my $devices = get_network_devices();

   my $device_info = {};

   for my $dev (@{$devices}) {

      my $ifconfig = run("LC_ALL=C ifconfig $dev");

      $device_info->{$dev} = {
         ip          => [ ( $ifconfig =~ m/inet (\d+\.\d+\.\d+\.\d+)/ ) ]->[0],
         netmask     => [ ( $ifconfig =~ m/(netmask 0x|netmask )([a-f0-9]+)/ ) ]->[1],
         broadcast   => [ ( $ifconfig =~ m/broadcast (\d+\.\d+\.\d+\.\d+)/ ) ]->[0],
         mac         => [ ( $ifconfig =~ m/(ether|address:|lladdr) (..?:..?:..?:..?:..?:..?)/ ) ]->[1],
      };

   }

   return $device_info;

}

sub route {

   my @ret = ();

   my @route = run "netstat -nr";  
   if($? != 0) {
      die("Error running netstat");
   }

   shift @route; shift @route; # remove first 2 lines
   shift @route; shift @route; # remove first 2 lines

   for my $route_entry (@route) {

      if(
         $route_entry =~ m/^$/
         || $route_entry =~ m/^Routing Table:/
         || $route_entry =~ m/^\s+Destination/
         || $route_entry =~ m/^---------/
      ) {
         next;
      }

      my ($dest, $gw, $flags, $ref, $use, $iface) = split(/\s+/, $route_entry, 6);
      push(@ret, {
         destination => $dest,
         gateway     => $gw,
         flags       => $flags,
         ref         => $ref,
         use         => $use,
         iface       => $iface,
      });
   }

   return @ret;

}

sub default_gateway {

   my ($class, $new_default_gw) = @_;

   if($new_default_gw) {
      if(default_gateway()) {
         run "route delete default " . default_gateway();
         if($? != 0) {
            die("Error running route del default");
         }
      }

      run "route add default $new_default_gw";
      if($? != 0) {
         die("Error route add default");
      }

   }
   else {
      my @route = route();

      my ($default_route) = grep { $_->{"flags"} =~ m/UG/ && ( $_->{"destination"} eq "0.0.0.0" || $_->{"destination"} eq "default" ) } @route;
      return $default_route->{"gateway"} if $default_route;
   }
}

sub netstat {

   my @ret;
   my @netstat = run "netstat -na -f inet -f inet6";
   if($? != 0) {
      die("Error running netstat");
   }


   my ($proto, $udp_v4, $udp_v6, $tcp_v4, $tcp_v6, $sctp);
   for my $line (@netstat) {

      if(
         $line =~ m/^$/
         || $line =~ m/^\s+Local/
         || $line =~ m/^--------/
      ) {
         next;
      }

      if($line =~ m/^UDP: IPv4/) {
         $udp_v4 = 0; $udp_v6 = 0; $tcp_v4 = 0; $tcp_v6 = 0; $sctp = 0;
         $udp_v4 = 1;
         $proto = "udp";
         next;
      }

      if($line =~ m/^UDP: IPv6/) {
         $udp_v4 = 0; $udp_v6 = 0; $tcp_v4 = 0; $tcp_v6 = 0; $sctp = 0;
         $udp_v6 = 1;
         $proto = "udp6";
         next;
      }

      if($line =~ m/^TCP: IPv4/) {
         $udp_v4 = 0; $udp_v6 = 0; $tcp_v4 = 0; $tcp_v6 = 0; $sctp = 0;
         $tcp_v4 = 1;
         $proto = "tcp";
         next;
      }

      if($line =~ m/^TCP: IPv6/) {
         $udp_v4 = 0; $udp_v6 = 0; $tcp_v4 = 0; $tcp_v6 = 0; $sctp = 0;
         $tcp_v6 = 1;
         $proto = "tcp6";
         next;
      }

      if($line =~ m/^SCTP:/) {
         $udp_v4 = 0; $udp_v6 = 0; $tcp_v4 = 0; $tcp_v6 = 0; $sctp = 0;
         $sctp = 1;
         $proto = "sctp";
         next;
      }

      $line =~ s/^\s+//;

      if($udp_v4) {
         $line = " $line";
         my ($local_addr, $remote_addr, $state) = ($line =~ m/\s+?([^\s]+)\s+([^\s]+)?\s+([^\s]+)/);
         push(@ret, {
            proto => $proto,
            local_addr => $local_addr,
            foreign_addr => $remote_addr,
            state => $state,
         });
         next;
      }

      if($udp_v6) {
         $line = " $line";
         my ($local_addr, $remote_addr, $state, $if) = ($line =~ m/\s+?([^\s]+)\s+([^\s]+)?\s+([^\s]+)\s+([^\s]+)/);
         push(@ret, {
            proto => $proto,
            local_addr => $local_addr,
            foreign_addr => $remote_addr,
            state => $state,
            if => $if,
         });
         next;
      }

      if($tcp_v4) {
         my ($local_addr, $remote_addr, $swind, $sendq, $rwind, $recvq, $state) = split(/\s+/, $line, 7);
         push(@ret, {
            proto => $proto,
            local_addr => $local_addr,
            foreign_addr => $remote_addr,
            swind => $swind,
            sendq => $sendq,
            rwind => $rwind,
            recvq => $recvq,
            state => $state,
         });
         next;
      }

      if($tcp_v6) {
         my ($local_addr, $remote_addr, $swind, $sendq, $rwind, $recvq, $state, $if) = split(/\s+/, $line, 8);
         push(@ret, {
            proto => $proto,
            local_addr => $local_addr,
            foreign_addr => $remote_addr,
            swind => $swind,
            sendq => $sendq,
            rwind => $rwind,
            recvq => $recvq,
            state => $state,
            if => $if,
         });
         next;
      }

      if($sctp) {
         my ($local_addr, $remote_addr, $swind, $sendq, $rwind, $recvq, $strs, $state) = split(/\s+/, $line, 8);
         push(@ret, {
            proto => $proto,
            local_addr => $local_addr,
            foreign_addr => $remote_addr,
            swind => $swind,
            sendq => $sendq,
            rwind => $rwind,
            recvq => $recvq,
            state => $state,
            strsio => $strs,
         });
         next;
      }



   }


   @netstat = run "netstat -na -f unix";
   shift @netstat; shift @netstat; shift @netstat;

   for my $line (@netstat) {
      my ($address, $type, $vnode, $conn, $local_addr, $remote_addr) = split(/\s+/, $line, 7);

      my $data = {
         proto        => "unix",
         address      => $address,
         type         => $type,
         nvnode       => $vnode,
         conn         => $conn,
         path         => $local_addr,
      };

      push(@ret, $data);

   }

   return @ret;

}



1;
