#! /usr/bin/perl -w
#
# socksumm -- socket usage summary
#
# Copyright (C) 2005-2006 David Landgren
use strict;
use Getopt::Long;
my $VERSION = '1.1';
my $ok = GetOptions(
'help', \my $help,
'localport=s', \my $watch_local_port,
'remoteport=s', \my $watch_remote_port,
'port=s', \my $watch_port,
'sleep=i', \my $sleep,
'version', \my $version,
'num=i', \my $num,
);
if( not $ok or $help ) {
eval "use Pod::Usage";
if( $@ ) {
print <<HELP;
$0 [-localport=?] [-remoteport=?] [-port=?] [-sleep=n] [-num=n]
(install Pod::Usage for detailed help)
HELP
}
else {
pod2usage(1);
}
exit;
}
$sleep ||= 60;
if( $version ) {
eval "use File::Basename";
print +($@ ? $0 : basename($0)), " v$VERSION\n";
exit 0;
}
my $netstat_re;
my $args;
# platform-specific settings;
{
my $ip_re = '\d+(?:\.\d+){3}';
if( $^O eq 'freebsd' ) {
$args = '-nf inet';
$netstat_re = qr/^\S+(?:\s+\d+){2}\s+($ip_re)[:.](\d+)\s+($ip_
+re)[:.](\d+)\s+(\S+)\s*$/;
}
elsif( $^O eq 'linux' ) {
$args = '-n --inet';
$netstat_re = qr/^\S+(?:\s+\d+){2}\s+($ip_re)[:.](\d+)\s+($ip_
+re)[:.](\d+)\s+(\S+)\s*$/;
}
elsif( $^O eq 'solaris' ) {
$args = '-nf inet';
$netstat_re = qr/^($ip_re)\.(\d+)\s+($ip_re)\.(\d+)(?:\s+\d+){
+4}\s+(\S+)\s*$/;
}
elsif( $^O eq 'MSWin32' ) {
$args = '-n';
$netstat_re = qr/^\s+TCP\s+($ip_re):(\d+)\s+($ip_re):(\d+)\s+(
+\S+)\s*$/;
}
else {
die "Don't know how to decode netstat on $^O\n" unless defined
+ $args;
}
}
# resolve service names if we can
defined $_ and /\D/ and $_ = getservbyname($_,'tcp') || $_
for ($watch_local_port, $watch_remote_port, $watch_port);
my %state;
my @col = qw(
ESTABLISHED CLOSE_WAIT TIME_WAIT FIN_WAIT_1 FIN_WAIT_2 SYN_SENT SY
+N_RECV LAST_ACK
);
print "estab close twait finw1 finw2 syntx synrx lastk total\n";
while( 1 ) {
my $total = 0;
@state{@col} = (0) x @col;
open my $in, "netstat $args |"
or die "Cannot open pipe from netstat: $!\n";
while( <$in> ) {
chomp;
next unless my($local_host, $local_port, $remote_host, $remote
+_port, $state)
= /$netstat_re/;
next if $watch_port
and $local_port != $watch_port
and $remote_port != $watch_port
;
next if $watch_local_port and $local_port != $watch_local_po
+rt;
next if $watch_remote_port and $remote_port != $watch_remote_p
+ort;
$state =~ s/^(FIN_WAIT)(\d+)$/$1_$2/; # munge Linux variant
++$state{$state};
++$total;
}
close $in;
# display one line of data
my $timestamp = sprintf( '%02d:%02d:%02d', (localtime)[2,1,0] );
printf "%5d %5d %5d %5d %5d %5d %5d %5d %5d %s",
@state{@col}, $total, $timestamp;
delete @state{@col};
# deal with unknown or don't-care socket states
if( %state ) {
print ' ', join( ' ', map {"$_=$state{$_}"} sort keys %state )
+;
%state = ();
}
print "\n";
last if defined $num and --$num <= 0;
sleep $sleep;
}
exit 0;
__END__
=head1 NAME
socksumm - Display a summary of open sockets
=head1 SYNOPSIS
B<socksumm> [B<-l>,B<-localport>] [B<-r>,B<-remoteport>] [B<-p>,B<-por
+t>] [B<-s>,B<-sleep>] [B<-n>,B<-num>] [B<-version>]
=head1 DESCRIPTION
Parse the output of the C<netstat(1)> command and produce a summary
of the socket connections on a port.
=head1 OPTIONS
=over 5
=item B<-l>,B<-localport>
Summarise socket connections on this local port. Numeric or symbolic n
+ames
(for example 389 or C<ldap>) are recognised. In otherwords, use this t
+o
monitor inbound connections.
=item B<-r>,B<-remoteport>
Summarise socket connections on this remote port. Numeric or symbolic
+names
are recognised. Use this to monitor outbound connections.
=item B<-p>,B<-port>
Summarise socket connections on this port. Numeric or symbolic names
are recognised. Use this to monitor eitherbound connections.
=item B<-s>,B<-sleep>
Time to sleep between invocations of C<netstat>. A sixty (60) second s
+leep
time is assumed if this switch is omitted.
=item B<-n>,B<-number>
Produce this many summaries of C<netstat> and then exit.
=back
=head1 EXAMPLES
C<socksumm -l=ldap -s=10>
Summarise the inbound connections to the LDAP listener port. Will prod
+uce
output that looks similar to the following:
estab close twait finw1 finw2 syntx synrx lastk total
519 0 4 0 0 0 0 0 523 12:42:50
524 0 2 0 0 0 0 1 527 12:43:00
516 0 3 0 0 0 0 0 519 12:43:11
C<socksumm -r=22 -s=3600>
See how many outbound C<ssh> connections are open every hour.
=head1 BUGS
Assumes that C<netstat> can be found on the PATH. If you are running
C<netstat> on a platform other than FreeBSD, Linux or Solaris the
script will die. Please mail me the output and I'll endeavour to
incorporate it (or, better yet, send me patches).
=head1 COPYRIGHT
Copyright 2005-2006 David Landgren.
This script is free software; you can redistribute it and/or modify it
under the same terms as Perl itself.
=head1 AUTHOR
David Landgren
join chr(0x40) => reverse qw[landgren.net david]
=cut
|