Category: Networking Code
Author/Contact Info grinder @ perlmonks

I've had this lying around for some time. It just takes the output of netstat and summarises the information la vmstat, iostat. I have used it for keeping an eye on large daemons that have shown a tendency to go mad.

I don't see that there's anything else to add to it, but I'd be interested in seeing if anyone has suggestions and ways it could be improved.

update: now with Win32 support! thanks Discipulus for the suggestion

#! /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)
    else {

$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_
    elsif( $^O eq 'linux' ) {
        $args = '-n --inet';
        $netstat_re = qr/^\S+(?:\s+\d+){2}\s+($ip_re)[:.](\d+)\s+($ip_
    elsif( $^O eq 'solaris' ) {
        $args = '-nf inet';
        $netstat_re = qr/^($ip_re)\.(\d+)\s+($ip_re)\.(\d+)(?:\s+\d+){
    elsif( $^O eq 'MSWin32' ) {
        $args = '-n';
        $netstat_re = qr/^\s+TCP\s+($ip_re):(\d+)\s+($ip_re):(\d+)\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(
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> ) {
        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
        next if $watch_remote_port and $remote_port != $watch_remote_p

        $state =~ s/^(FIN_WAIT)(\d+)$/$1_$2/; # munge Linux variant
    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;


=head1 NAME

socksumm - Display a summary of open sockets


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>]


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
(for example 389 or C<ldap>) are recognised. In otherwords, use this t
monitor inbound connections.

=item B<-r>,B<-remoteport>

Summarise socket connections on this remote port. Numeric or symbolic 
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
time is assumed if this switch is omitted.

=item B<-n>,B<-number>

Produce this many summaries of C<netstat> and then exit.



C<socksumm -l=ldap -s=10>

Summarise the inbound connections to the LDAP listener port. Will prod
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).


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[ david]