<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">#!/usr/bin/perl -w
#+##############################################################################
#                                                                              #
# File: big_brother.pl                                                         #
#                                                                              #
# Description: check the network sockets with lsof to detect new connections   #
#									       #
# Contributed by Lionel Cons &lt;Lionel.Cons@cern.ch&gt;			       #
#                                                                              #
#-##############################################################################

# @(#)big_brother	1.12 08/14/96 Written by Lionel.Cons@cern.ch

# no waranty! use this at your own risks!

#
# init &amp; setup
#
$verbose = 1;
$lsof_opt = "-itcp -iudp -Di -FcLPn -r 5";
$SIG{'HUP'} = \&amp;hangup;
chop($hostname = `/bin/hostname`);
$fq_hostname = (gethostbyname($hostname))[0];

# Set path to lsof.

if (($LSOF = &amp;isexec("../lsof")) eq "") {	# Try .. first
    if (($LSOF = &amp;isexec("lsof")) eq "") {	# Then try . and $PATH
	print "can't execute $LSOF\n"; exit 1
    }
}

#
# spy forever...
#
$| = 1;
die "$LSOF is not executable\n" unless -x $LSOF;
while (1) {
    $lsof_pid = open(PIPE, "$LSOF $lsof_opt 2&gt;&amp;1 |")
	|| die "can't start $LSOF: $!\n";
    print "# ", &amp;timestamp, " $LSOF $lsof_opt, pid=$lsof_pid\n"
	if $verbose;
    print "#COMMAND     PID     USER P NAME\n";
    $printed = $hanguped = $pid = $proto = 0;
    while (&lt;PIPE&gt;) {
	if (/^lsof: PID \d+, /) {
	    # fatal error message?
	    print "*** $_";
	    last;
	} elsif (/^lsof: /) {
	    # warning
	    warn "* $_";
	} elsif (/^p(\d+)$/) {
	    &amp;flush;
	    $pid = $1;
	    $proto = 0;
	} elsif (/^c(.*)$/) {
	    $command = $1;
	} elsif (/^L(.*)$/) {
	    $user = $1;
	} elsif (/^P(.*)$/) {
	    &amp;flush;
	    $proto = $1;
	} elsif (/^n(.*)$/) {
	    $name = $1;
	    # replace local hostname by 'localhost'
	    $name =~ s/\Q$fq_hostname\E/localhost/g;
	    $name =~ s/[0-9hms]+ ago//g;
	} elsif (/^m$/) {
	    &amp;flush;
	    &amp;clean;
	} else {
	    warn "* bad output ignored: $_";
	}
    }
    kill('INT',  $lsof_pid);
    kill('KILL', $lsof_pid);
    close(PIPE);
}

sub hangup {
    $hanguped = 1;
    $SIG{'HUP'} = \&amp;hangup;
}

sub flush {
    return unless $pid &amp;&amp; $proto;
    return if &amp;skip;
    $tag = sprintf("%-9s %5d %8s %1s %s", $command, $pid, $user,
		   substr($proto, 0, 1), $name);
    unless (defined($seen{$tag})) {
	print "+$tag\n";
	$printed++;
    }
    $seen{$tag} = 1;
}

sub clean {
    my(@to_delete, $tag);

    if ($hanguped) {
	$hanguped = 0;
	@to_delete = keys(%seen);
	print "# ", &amp;timestamp, " hangup received, rescanning all connections\n"
	    if $verbose;
    } else {
	@to_delete = ();
	foreach $tag (keys(%seen)) {
	    if ($seen{$tag} == 0) {
		# not seen this time: delete it
		push(@to_delete, $tag);
		print "-$tag\n";
		$printed++;
	    } else {
		# seen this time: reset the flag
		$seen{$tag} = 0;
	    }
	}
    }
    grep(delete($seen{$_}), @to_delete);
    if ($printed &gt; 10) {
	print "# ", &amp;timestamp, "\n" if $verbose;
	$printed = 0;
    }
}

sub skip {
    #
    # put stuff here to ignore some connections, for instance:
    #

    # what we get when the socket gets created...
    return(1) if $name eq '*:0';
    return(1) if $name =~ /^localhost:(\d+)$/ &amp;&amp; $1 &gt; 1000;
#
# UDP &amp; TCP stuff
#
    #
    # ignore common daemons
    #
    if ($name =~ /^\*:/ &amp;&amp; $user eq 'root' &amp;&amp; $pid &lt; 300) {
	return(1) if $command =~ /^inetd(\.afs)?$/;
	return(1) if $command =~ /^rpc\.(stat|lock)d$/;
	return(1) if $command eq 'syslogd' &amp;&amp; $name eq '*:syslog';
    }
    #
    # forking beasts: portmap, ypbind, inetd
    #
    if ($command eq 'portmap' &amp;&amp; $user eq 'daemon') {
	return(1) if $name =~ /^\*:/;
    } elsif ($command eq 'ypbind') {
	return(1) if $name =~ /^\*:\d+$/;
    }
#
# TCP-only stuff
#
    return(0) unless $proto eq 'TCP';
    #
    # outgoing commands: ftp, telnet, r*
    #
    if ($command eq 'ftp') {
	return(1) if $name =~ /:ftp(-data)?$/;
    } elsif ($command eq 'telnet') {
	return(1) if $name =~ /:telnet$/;
    } elsif ($command eq 'remsh') {
	if ($name =~ /:(\d?\d\d\d)-&gt;.+:(\d?\d\d\d)$/) {
	    return(1) if $1 &lt; 1024 &amp;&amp; $1 &gt; 990 &amp;&amp; $2 &lt; 1024 &amp;&amp; $2 &gt; 990;
	} elsif ($name =~ /:(\d?\d\d\d)-&gt;.+:(shell|ta-rauth)$/) {
	    return(1) if $1 &lt; 1024 &amp;&amp; $1 &gt; 990;
	} elsif ($name =~ /^\*:(\d?\d\d\d)$/) {
	    return(1) if $1 &lt; 1024 &amp;&amp; $1 &gt; 990;
	}
    }
    return(0);
}

sub timestamp {
    my($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst);

    ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
    sprintf("%d/%02d/%02d-%02d:%02d:%02d", $year + 1900, $mon+1, $mday,
      $hour, $min, $sec);
}


## isexec($path) -- is $path executable
#
# $path   = absolute or relative path to file to test for executabiity.
#	    Paths that begin with neither '/' nor '.' that arent't found as
#	    simple references are also tested with the path prefixes of the
#	    PATH environment variable.

sub
isexec {
    my ($path) = @_;
    my ($i, @P, $PATH);

    $path =~ s/^\s+|\s+$//g;
    if ($path eq "") { return(""); }
    if (($path =~ m#^[\/\.]#)) {
	if (-x $path) { return($path); }
	return("");
    }
    $PATH = $ENV{PATH};
    @P = split(":", $PATH);
    for ($i = 0; $i &lt;= $#P; $i++) {
	if (-x "$P[$i]/$path") { return("$P[$i]/$path"); }
    }
    return("");
}
</pre></body></html>