#!/usr/bin/perl
# USAGE
#	perl lsof-1.2.pl
# SEE ALSO
#
#   perldoc lsof-1.2.pl



#/proc files to get data
$PROC_TCP="/proc/net/tcp";
$PROC_TCP6 = "/proc/net/tcp6";
$PROC_UDP="/proc/net/udp";
$PROC_UDP6="/proc/net/udp6";

my @tcp = read_file($PROC_TCP);
my @udp = read_file($PROC_UDP);
my @tcp6 = read_file($PROC_TCP6);
my @udp6 = read_file($PROC_UDP6);

get_ports('TCP',@tcp);
get_ports('TCP6',@tcp6);
get_ports('UDP',@udp);
get_ports('UD6P',@udp6);


sub get_ports
{
   my($proto,@lines) = @_;
   print "-------------\n";
   print "$proto\n";
   print "-------------\n";
   print align("UID",4) . align("PID",8)  . align("L_IP",17) . align("L_Port",8) . align("R_IP",17) . align("R_Port",8)  . align("Exe",4) . "\n";
   foreach $line (@lines)
    {
     my($dump,$sl,$local_address,$rem_address,$st,$rx_queue,$tr,$retrnsmt,$uid,$timeout,$inode,$inodeid) = split(/\s+/,$line);
     if($sl eq "sl") { next;}; #ignore the header
#     if(!($inode eq "0"))
#        {
          my($l_ip,$l_port) = hextoip($local_address);
          my($r_ip,$r_port) = hextoip($rem_address);
          
          my $PID = get_pid_of_inode($inode);
          print  align($uid,4) . align($PID,8)  .  align($l_ip,17) . align($l_port,8) .  align($r_ip,17) . align($r_port,8) .  get_process_exe_path($PID) . " \n";        
#        }
    }
}



sub read_file
{
  my($file) = @_;
  open(FILE, $file);
  my @lines = <FILE>;
  close(FILE);
  return @lines;
}


sub hextoip
{
 my($hexvalue) = @_;
 my($hexip,$hexport) = split(/\:/,$hexvalue);
 my $port = hex($hexport);
 my $ipvalue = hexip_to_normalip($hexip);
 return $ipvalue,$port;
}


sub align
{
   my($str,$digits) = @_;
   my $spacestoadd = $digits - length($str);
   for ($i=1;$i<=$spacestoadd;$i++)
     {
         $str = $str . " ";
     }
   return $str;
}

sub hexip_to_normalip
{
 my($hexvalue) = @_;
 my($h4,$h3,$h2,$h1) = $hexvalue =~ m/([\d.a-f.A-F][\d.a-f.A-F])([\d.a-f.A-F][\d.a-f.A-F])([\d.a-f.A-F][\d.a-f.A-F])([\d.a-f.A-F][\d.a-f.A-F])/;
 my $normal = hex($h1).".".hex($h2).".".hex($h3).".".hex($h4);
 return $normal;
}

sub get_pid_of_inode
{
 my($inode) = @_;
 opendir (PROC, "/proc") || die "proc";
 for $f (readdir(PROC))
 {
     next if (! ($f=~/[0-9]+/) );
     if (! opendir (PORTS, "/proc/$f/fd")) 
     {
  	closedir PORTS;
	next;
     }
    for $g (readdir(PORTS)) 
    {
    next if (! ($g=~/[0-9]+/) );
    $r=readlink("/proc/$f/fd/$g");
    ($dev,$ino)=($r=~/^(socket|\[[0-9a-fA-F]+\]):\[?([0-9]+)\]?$/);
    if (($dev == "[0000]" || $dev == "socket") && $ino eq $inode) 
	{
	  closedir PORTS;
	  closedir PROC;
          return $f;
        }
	    closedir PORTS;
	}
	closedir PROC;
    }
}

sub get_process_exe_path
{
  my($pid) = @_;
  return readlink("/proc/$pid/exe");
}

__END__

=head1 NAME

lsof-1.2.pl - Show open ports information 

=head1 SCRIPT CATEGORIES

Networking

=head1 README

This script retrive the information of Listening and active ports and show the output similar to lsof -i. It can be used on compromised systems where lsof is infected and hide the processes or connections.


=head1 OSNAMES

Linux

=head1 PREREQUISITES

=head1 COREQUISITES

=head1 SYNOPSIS

=head1 AUTHOR

Jamshaid Faisal

 { 
   domain   => "gmail", 
   tld      => "com", 
   username => "j.faisal" 
 }

=cut
