whitehat237
whitehat237

Reputation: 379

Script to count number of connections using a range of TCP ports

I am using the following script to count the number of connections in established, and time wait state for a specific range of TCP ports.

The script uses netstat and egrep to try and filter out valid connections. The script also reads input from a file and counts the number of connections observed.

#!/bin/bash
START=121
END=9089

[ -f /tmp/ports.txt ] && rm -f /tmp/ports.txt

for ((a=$START; a <= $END; a++)); do
    netstat -an | nawk '/TIME_WAIT|ESTABLISHED/ && !/127.0.0.1/{split($4,a,".");print a[5]}' | egrep -c ^${a}$ | \
    awk -v x=$a '\
    $0 != 0 {printf("%d %d\n",x,$0)}' | tee -a /tmp/ports.txt
done

awk -v s=$START -v e=$END '\
    BEGIN{t=0}
    {t=t+$2}
    END{printf("\nTotal Connections on ports %d-%d: %d\n",s,e,t)}' /tmp/ports.txt

rm -f /tmp/ports.txt

I'm looking for ways to improve the performance of the script. With the current range of ports (121-9089) it takes about 77 seconds to finish.

I'm looking for suggestions for improving the performance along with an example script.

Upvotes: 2

Views: 4443

Answers (3)

whitehat237
whitehat237

Reputation: 379

Birei, using your example above, the script has been changed slightly.

#!/bin/bash
OS=$(uname)

case "$OS" in
    'SunOS')
            AWK=/usr/bin/nawk
            ;;
    'Linux')
            AWK=/bin/awk
            ;;
    'AIX')
            AWK=/usr/bin/awk
            ;;
esac

netstat -an | $AWK -v start=1 -v end=65535 ' $NF ~ /TIME_WAIT|ESTABLISHED/ && $4 !~ /127\.0\.0\.1/ {
    if ($1 ~ /\./)
            {sip=$1}
    else {sip=$4}

    if ( sip ~ /:/ )
            {d=2}
    else {d=5}

    split( sip, a, /:|\./ )

    if ( a[d] >= start && a[d] <= end ) {
            ++connections;
            }
    }
    END {print connections}'

We are using this with our network monitoring tool. (zabbix) I have tested the script with solaris 10, Linux 6.3 and AIX 7, and the script works as intended and accounts for the differences in the way netstat outputs it's columns and for the difference in delimeter characters. I.E. the . or the : appearing in either the 2nd or 4th columns. It checks to see if the first column contains a . and sets the variable sip accordingly, and then determines if a : or a . is used as the port separator character.

The rest is much the same.

Thank you for your example!

Upvotes: 2

Birei
Birei

Reputation: 36262

One way:

netstat -an | 
awk -v start=121 -v end=9089 '
    $NF ~ /TIME_WAIT|ESTABLISHED/ && $4 !~ /127\.0\.0\.1/ { 
        split( $4, a, /:/ ); 
        if ( a[2] >= start && a[2] <= end ) { 
            ++connections; 
        } 
    } 
    END { 
        printf("\nTotal Connections on ports %d-%d: %d\n", start, end, connections ); 
    }
'

Upvotes: 1

Majid Laissi
Majid Laissi

Reputation: 19788

You are running netstat -an over 8000 times and extracting only one port at a time.

I would change your main loop with a different logic:

netstat -na | grep -E "TIME_WAIT|ESTABLISHED" | while read line; do
    port=`echo $line | awk -F":" ' { print $2 }' | awk ' { print $1 }'` #<--- get here your port
    [ $port -ge $START ] && [ $port -le $END ] && echo $line | tee -a /tmp/ports.txt #<---- put only the selected range
 done

This way you will netstat only once.

Note that you'll need to change the awk logic in my example.

Upvotes: 3

Related Questions