LinuxQuestions.org
Share your knowledge at the LQ Wiki.
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices

Reply
 
Search this Thread
Old 12-07-2011, 12:21 PM   #1
sudhagud
LQ Newbie
 
Registered: Dec 2011
Location: London
Posts: 4
Blog Entries: 5

Rep: Reputation: 0
Pitching a script to find improvements and suggestions: Firewall and Network Auditor


Hello all,

Recently I had to write a script to gather and audit some network info from Linux servers. I would appreciate suggestions and improvement tweaks and further inclusions to make the script more robust.

- Bellamkonda Sudhakar

The script itself:

Code:
#!/bin/bash
##################################################################
#
# Script to check / audit systems process using network resources
# and report a detailed info from various system file, process and
# outputs
#
##################################################################
#
# Author: Bellamkonda Sudhakar
# License: GNU GPL v3
##################################################################
VERSION=0.5
##################################################################
AUDITFL=`hostname -s`
CHKPID="/var/run/netaudchk-ppid"
FLWPID="/var/run/netaudchk-fpid"
TMPFD="/tmp/netadtchk"
TMPFL1="tmpfl1"
TMPFL2="tmpfl2"
TMPFL3="tmpfl3"
OPSYS=`uname -o`
OPKER=`uname -s`
OPDST=`uname -r`
HSTNM=$AUDITFL
FLTC="tcpflen"
FWTSTIN="fwtest.in"
FETSTOUT="fwtest.out"
HNIC=`lspci | grep -ic ethernet`
VNIC=`ip -d link | grep ^[0-9] | awk '{ print $2 }' | sed 's/://' | grep -vi "lo" | grep -vc "eth"`
LNIC=`ip -d link | grep ^[0-9] | awk '{ print $2 }' | sed 's/://' | grep -ic "lo"`
TNIC=`expr $HNIC + $VNIC + $LNIC`
IP4E=`ip -d addr | grep -ic inet`
IP6E=`ip -d addr | grep -ic inet6`
TTCP=`ss -t | wc -l`
TTCPL=`ss -t -l | wc -l`
TTCPC=`ss -t -a | wc -l`
IPFW=`cat /proc/sys/net/ipv4/ip_forward`
IPMQ=`cat /proc/sys/net/ipv4/ip_dynaddr`
IPPROC=""
MJR=${OPDST:0:1}
MIR=${OPDST:2:1}
FWILBIN="None"
FWON="Off"
FWIN="False"
FWOT="False"
FWFW="False"
FWMQ="False"
NMSR=`grep nameserver /etc/resolv.conf | grep -v ^# | head -1 | awk '{ print $2 } '`
DFGW=`ip route | grep default | sed 's/default\|proto\|static//g'`
###################################################################
# Functions
function lpnt {
for r in {1..80..1}
do
   printf "%c" $1
done 
printf "\n"
}
#
###################################################################
function cleanup {
rm -f $CHKPID
rm -f $FLWPID
}
###################################################################
function create_workspace {
mkdir $TMPFD
}
###################################################################
function remove_workspace {
rm -Rf $TMPFD
}
###################################################################
function pause {
echo -n "Press enter to continue..."
read
}
###################################################################
function line {
echo >> $TMPFD/$AUDITFL
}
###################################################################
#Main Program
if [ $UID -ne 0 ]
then
    echo
    echo "No root previleges"
    exit 0
fi
if [ "$1" == "-c" ]
then
   cleanup
   echo "PID files removed"
   exit 0
fi
if [ "$1" == "-h" ]
then
    echo
    echo "Usage: "
    echo "netadtchk [option]"
    echo "          -a All"
    echo "          -h Help"
    echo "          -c Clear PID files"
    echo "           no option prints the summery information to the stdout and into the /tmp/netadtchk/$AUDITFL file."
    echo
    exit 0
fi
if [ -f $CHKPID ] 
then
    echo " Net Auditor running with PID `cat $CHKPID`"
    echo " To clear the PID files use the -c option"    
    exit 0
else
    echo $$ > $CHKPID
fi
#
#
if [ -d $TMPFD ] 
then
    remove_workspace
    create_workspace
else
    create_workspace
fi
#
case "$MJR" in
    "2" )
        case "$MIR" in
             "0" | "1" )
                 FWILBIN="ipfwadm";
                 IPPROC="ip_[mfp][ao][rs][wqt][qha]*";;
             "2" | "3" )
                 FWILBIN="ipchains";
                 IPPROC="ip_[fm][wa][cns]*";;
             * ) 
                 FWILBIN="iptables";
                 IPPROC="ip_tables*";;
        esac;;
    "3" )
      FWILBIN="iptables";
      IPPROC="ip_table*";;
    * )
      FWILBIN="Unknown";;
esac
if [ $IP4E ]; then IPV="IPV4"; fi
if [ $IP6E ]; then IPV=$IPV"/IPV6"; fi
FWILPROC1=`ls /proc/net/$IPPROC 2>/dev/null | grep -c ip_tables`
FWILPROC2=`which $FWILBIN 2>/dev/null | grep -c $FWILBIN`
if [ $FWILPROC1 -ne 0 -a $FWILPROC2 -ne 0 ] ; then FWILSTAT="IP_Tables"; else FWILSTAT="None"; fi
#
if [ $FWILBIN == "iptables" ]
then
    $FWILBIN -L | grep -i chain > $TMPFD/$TMPFL1
    for C in `awk ' { print $2 } ' $TMPFD/$TMPFL1`
    do
      if [ $C == "INPUT" ]  
      then
          if [ `$FWILBIN -L $C | grep -wc 'all\|tcp\|udp'` -gt 0 ] ; then FWIN="True"; fi
      fi
      if [ $C == "OUTPUT" ]
      then
          if [ `$FWILBIN -L $C | grep -wc 'all\|tcp\|udp'` -gt 0 ] ; then FWOT="True"; fi
      fi
      if [ $C == "FORWARD" ]
      then
          if [ `$FWILBIN -L $C | grep -wc 'all\|tcp\|udp'` -gt 0 ] ; then FWFW="True"; fi
      fi
    done
fi
#
FWR=`$FWILBIN -L | sed '/^$/d' | grep -iv chain | grep -ivc "target\|source\|destination"`
if [ $FWR -gt 0 -a $FWIN == "True" ] ; then FWON="On"; fi
#
printf "%12s %12s %20s %20s %9s\n" "Hostname" "OS" "Kernel" "Release" "IPV" >> $TMPFD/$AUDITFL
printf "%12s %12s %20s %20s %9s\n\n" "$AUDITFL" "$OPSYS" "$OPKER" "$OPDST" "$IPV" >> $TMPFD/$AUDITFL
#
printf "%15s%12s%20s%20s%25s\n" "FW Binary" "Forwarding" "Masquerading" "1st Name Srv" "Default Gateway" >> $TMPFD/$AUDITFL
printf "%15s%12s%20s%20s%25s\n\n" "$FWILBIN" "$IPFW" "$IPMQ" "$NMSR" "$DFGW" >> $TMPFD/$AUDITFL
#
printf "%14s%14s%14s%14s%14s\n" "FW Status" "FW In" "FW Out" "FW Forward" "FW Masq" >> $TMPFD/$AUDITFL
printf "%14s%14s%14s%14s%14s\n" "$FWON" "$FWIN" "$FWOT" "$FWFW" "$FWMQ" >> $TMPFD/$AUDITFL
#
printf "\n%15s %15s %20s\n" "Type" "Name" "IP Details" >> $TMPFD/$AUDITFL
for N in `ip -d link | grep ^[0-9] | awk '{ print $2 }' | sed 's/://'`
do
   case "$N" in 
        "lo" )
            TYPE="Loopback";;
        "eth0" | "eth1" | "eth2" | "eth3" | "eth4" | "eth5" )
            TYPE="Hardware";;
        * )
            TYPE="Virtual/Other"
   esac 
   IPDET=`ifconfig $N | grep -w "inet"`
   printf "%15s %15s %s\n" "$TYPE" "$N" "$IPDET" >> $TMPFD/$AUDITFL
done
line
echo "Routes:" >> $TMPFD/$AUDITFL
netstat -rn >> $TMPFD/$AUDITFL
line
ss -nl4 | awk ' { print $3 } ' | grep -iv local | sed 's/*/0.0.0.0/g' > $TMPFD/$TMPFL1
ss -nl6 | awk ' { print $3 } ' | grep -iv local | sed 's/\(.*\)\:/\1 /' > $TMPFD/$TMPFL2
sed -i 's/\:/ /g' $TMPFD/$TMPFL1
sort $TMPFD/$TMPFL1 > $TMPFD/$TMPFL3
sort $TMPFD/$TMPFL2 >> $TMPFD/$TMPFL3
echo "This system has `expr $TTCPL - 1` Listening Sockets (IPv4/IPv6) at TCP/Ports: " >> $TMPFD/$AUDITFL
cp $TMPFD/$TMPFL3 $TMPFD/$FLTC
#
#
for P in `awk ' { print $2 } ' $TMPFD/$FLTC`
do
   PP=$PP$P,
   lsof -i tcp:$P | grep LISTEN | awk -v P=$P -v TMPFL=$TMPFD/$TMPFL3 ' { printf " %12s %12s %20s\n", P, $1, $2 >> TMPFL } '
done
echo "$PP details" >> $TMPFD/$AUDITFL
sort -g -k3 $TMPFD/$TMPFL3 > $TMPFD/$TMPFL2
awk -v TMPFL3=$TMPFD/$TMPFL3 ' BEGIN { }
            { if(cf != $2)
              printf "%12s %12s %20s\n", $1, $2, $3 > TMPFL3
              cf = $2 }
      END { } ' $TMPFD/$TMPFL2 
line
lsof -i tcp:$PP | grep LISTEN | sort -d > $TMPFD/$TMPFL2
awk -v TMPFL1=$TMPFD/$TMPFL1 ' BEGIN { }
            { if(cf != $1)
              print $1, $2, $9 > TMPFL1
              cf = $1 }
            END { } ' $TMPFD/$TMPFL2 
printf "%5s %10s %8s %30s %20s %s\n" "PID" "Process" "Port" "As per /proc" "As per Which" "Working Dir" >> $TMPFD/$AUDITFL
for ID in `awk ' { print $2 } ' $TMPFD/$TMPFL1`
do
    PROCEXE=`ls -l --full-time /proc/$ID/exe | awk ' { print $11 } '`
    PROCPWS=`ls -l --full-time /proc/$ID/cwd | awk ' { print $11 } '`
    PROC=`awk -v P=$ID ' { if (P == $2) print $1 } ' $TMPFD/$TMPFL1`
    WPROC=`which 2>/dev/null $PROC`
    P=`awk -v ID=$ID ' BEGIN { } { if (ID == $3) print $1 } END { } ' $TMPFD/$TMPFL3`
    printf "%5s %10s %8s %30s %20s %s\n" "$ID" "$PROC" "$P" "-$PROCEXE" "-$WPROC" "-$PROCPWS" >> $TMPFD/$AUDITFL
done
line
netstat -tulnp | grep LISTEN | awk ' { print $4, $7 } ' | sed 's/\(.*\)\:/\1 /' | sed 's/\// /g' > $TMPFD/$TMPFL1
printf "%20s %8s %8s %20s\n" "IP" "PORT" "PID" "PROCESS" >> $TMPFD/$AUDITFL
awk ' {  printf "%20s %8s %8s %20s\n", $1, $2, $3, $4 } ' $TMPFD/$TMPFL1 >> $TMPFD/$AUDITFL
line
lpnt "#" >> $TMPFD/$AUDITFL
##################################################################
## Print details from Audit file
clear
cat $TMPFD/$AUDITFL
echo "Complete Information is stored at $TMPFD/$AUDITFL"
if [ "$1" == "-a" ] 
then
    echo "All TCP Listening Process Details" >> $TMPFD/$AUDITFL
    netstat -tunlp | grep -v udp >> $TMPFD/$AUDITFL
    line
    echo "ALL UDP Listening Process Details" >> $TMPFD/$AUDITFL
    netstat -tunlp | grep -v tcp >> $TMPFD/$AUDITFL
    line
    echo "Current established connections - NETSTAT" >> $TMPFD/$AUDITFL
    netstat -tunap >> $TMPFD/$AUDITFL
    line
    echo "Current established connections - SS" >> $TMPFD/$AUDITFL
    ss -o state established >> $TMPFD/$AUDITFL
    line
    lpnt "#" >> $TMPFD/$AUDITFL
fi
#
cleanup
exit 0
#
###################################################################
 
Click here to see the post LQ members have rated as the most helpful post in this thread.
Old 12-10-2011, 11:42 AM   #2
catkin
LQ 5k Club
 
Registered: Dec 2008
Location: Tamil Nadu, India
Distribution: Servers: Debian Squeeze and Wheezy. Desktop: Slackware64 14.0. Netbook: Slackware 13.37
Posts: 8,551
Blog Entries: 28

Rep: Reputation: 1176Reputation: 1176Reputation: 1176Reputation: 1176Reputation: 1176Reputation: 1176Reputation: 1176Reputation: 1176Reputation: 1176
That's a lot of code to comment on and it looks pretty tidy; two reasons why nobody has commented?

As said, it's tidy code but some things you might like to consider:
  • $( ... ) is recommended over ` ... ` for reasons explained here.
  • [[ ... ]] is recommended over [ ... ] for reasons explained here.
  • A common but not universal convention is to use upper case variable names for environment variables and lower case names for the rest.
  • Some of the command output string manipulation looks as if it could be simplified. For example
    Code:
    ip -d link | grep ^[0-9] | awk '{ print $2 }' | sed 's/://' | grep -vi "lo" | grep -vc "eth"
    ... can be simplified to
    Code:
    ip -d link | grep -c '^[0-9]*: eth'
  • Errors conventionally result in a message to stderr and a non-zero return code. If you regard it as an error, this code
    Code:
    if [ $UID -ne 0 ]
    then
        echo
        echo "No root previleges"
        exit 0
    fi
    could be changed to
    Code:
    if [ $UID -ne 0 ]
    then
        echo "No root privileges" >&2
        exit 1
    fi
  • The single command line option could more conveniently be handled using a case statement, here including an error trap for an invalid option and assuming usage is moved to a function which gives verbose output if called with -v (and otherwise could suggest using the -h option):
    Code:
    case $1 in
        -a )
            echo 'Unserviced option -a' >&2
            exit 1
            ;;
        -c )
           cleanup
           echo "PID files removed"
           exit 0
           ;;
        -h )
           usage -v
           ;;
        * )
           echo "Invalid option $1" >&2
           usage
           exit 1
    esac
    More complex command line parsing, facilitating trapping invalid extra arguments is best handled by getopts.
  • Purely a matter of style, no right and no wrong way; it is more compact to use
    Code:
    if [[ <test expression> ]];then
        <commands>
    fi
  • Again purely a matter of style, no right and no wrong way; you may prefer, instead of
    Code:
    if [ $IP4E ]; then IPV="IPV4"; fi
    to use
    Code:
    [[ $IP4E ]] && IPV="IPV4"
    ... but beware; [[ <test expression> ]] && <commands 1> || <commands 2> can behave unexpectedly (if <commands 1> set a non zero return code, <commands 2> is executed).
  • If strings do not contain anything to be substituted by bash, they may be in single quotes, not double (for example "IPV4" above).
  • Aliases can make what are intended to be external commands behave unexpectedly. ls is often aliased and so troublesome. Safest for scripts to unset all aliases with unalias -a
  • In case the script's name is changed, the usage message could use ${0##*/} for its name.
  • The usage message could be done with a single echo (but is not then so easy to indent prettily):
    Code:
    echo '
    Usage: netadtchk [-a | -h | -c]
        -a All
        -h Help. Prints this usage message and exits
        -c Clear PID files"
        If no option is given, prints the summary information to the stdout and into the /tmp/netadtchk/$AUDITFL file
    '
    Note: the -a option is not serviced in the script.
  • Spelling: privilege and summary

Last edited by catkin; 12-10-2011 at 11:45 AM.
 
2 members found this post helpful.
Old 12-10-2011, 02:26 PM   #3
asimba
Member
 
Registered: Mar 2005
Location: 127.0.0.0
Distribution: Red Hat / Fedora
Posts: 349

Rep: Reputation: 42
I apologize - I need to learn quite q few things. Bear with me .

Still reading script - and catkin's insight was good. I am unsure about command

Code:
uname -o
I mean script if script is already meant for *nix why would you need that - that too if you intend to use it just once. I think a static value would have been good enough.


Following variable seems unused
Code:
TTCPC=`ss -t -a | wc -l`

Last edited by asimba; 12-10-2011 at 02:35 PM.
 
Old 12-11-2011, 08:18 AM   #4
unSpawn
Moderator
 
Registered: May 2001
Posts: 27,470
Blog Entries: 54

Rep: Reputation: 2900Reputation: 2900Reputation: 2900Reputation: 2900Reputation: 2900Reputation: 2900Reputation: 2900Reputation: 2900Reputation: 2900Reputation: 2900Reputation: 2900
Quote:
Originally Posted by sudhagud View Post
I would appreciate suggestions and improvement tweaks and further inclusions to make the script more robust.
Moved: This thread is more suitable in the Programming forum since you're only interested in robustness (I would first look at existing functionality tools like GNU Tiger, LSAT or OpenVAS provide) and has been moved accordingly to help your thread/question get the exposure it deserves.
 
Old 12-11-2011, 02:38 PM   #5
David the H.
Bash Guru
 
Registered: Jun 2004
Location: Osaka, Japan
Distribution: Debian sid + kde 3.5 & 4.4
Posts: 6,823

Rep: Reputation: 1949Reputation: 1949Reputation: 1949Reputation: 1949Reputation: 1949Reputation: 1949Reputation: 1949Reputation: 1949Reputation: 1949Reputation: 1949Reputation: 1949
  • You have a lot of unquoted variables in your script. While this is ok as long as their contents don't contain spaces or other reserved characters, if for some reason this should change, then you're going to have trouble.

    You should get into the habit of always quoting variable expansions by default, then you only have to worry about those few times when they need to be unquoted.

  • You make four individual calls to "ip". It might be more efficient if you call "id -d addr" only once and store its entire output into a variable. Then you could simply parse that for all the values you want.

  • As catkin pointed out, you have lots of useless uses of grep and related tools. If your command uses sed or awk, then you already have grep-like ability built in and generally shouldn't need it. Also, don't forget that grep and sed have -e options allowing you to apply multiple expressions at once.

    Finally, always quote your expressions to avoid conflicts with shell grammar.

    Code:
    #NMSR=`grep nameserver /etc/resolv.conf | grep -v ^# | head -1 | awk '{ print $2 } '`
    NMSR=$( awk '/nameserver/ { print $2 ; exit }' /etc/resolv.conf )
    
    #DFGW=`ip route | grep default | sed 's/default\|proto\|static//g'`
    DFGW=$( sed ' /default/ s/default\|proto\|static//g' < <( ip route ) )
  • BTW, the -1 syntax for head/tail is deprecated; you should use -n 1 instead.

  • Notice too in the above that process substitution can be used instead of a pipe.

  • As the guys at Greg's Wiki say: "expr is a relic of ancient Rome. Do not wield it". Bash has integer math ability built in.

    Code:
    #TNIC=`expr $HNIC + $VNIC + $LNIC`
    TNIC=$(( $HNIC + $VNIC + $LNIC ))
  • The < redirector works stand-alone inside a command substitution, so bash can import a file into a variable without using cat. And please use $(), as catkin mentioned. It's so much more readable and flexible.

    Code:
    #IPFW=`cat /proc/sys/net/ipv4/ip_forward`
    #IPMQ=`cat /proc/sys/net/ipv4/ip_dynaddr`
    IPFW=$( < /proc/sys/net/ipv4/ip_forward )
    IPMQ=$( < /proc/sys/net/ipv4/ip_dynaddr )
  • catkin stated that [[..]] is better than [..], but also, ((..)) is better than either when doing numerical evaluations.

    Code:
    #if [ $UID -ne 0 ]
    if (( UID != 0 ))
    #or even just...
    if (( UID ))

I could go on, but this post is getting to be a bit tiring to work on, so I think I'll stop here.
 
2 members found this post helpful.
Old 12-11-2011, 08:51 PM   #6
grail
Guru
 
Registered: Sep 2009
Location: Perth
Distribution: Manjaro
Posts: 7,564

Rep: Reputation: 1939Reputation: 1939Reputation: 1939Reputation: 1939Reputation: 1939Reputation: 1939Reputation: 1939Reputation: 1939Reputation: 1939Reputation: 1939Reputation: 1939
I believe the above is plenty enough for you to digest at the moment, so my only addition is a personal view.
The use of a function is generally tied to reducing the need to repeat the same lines of code several times.
You have functions like create_workspace which ultimately are only required at one point in the entire script,
so I probably would not have worried about creating a function for this example.

Look forward to your next revision
 
1 members found this post helpful.
Old 12-11-2011, 11:28 PM   #7
catkin
LQ 5k Club
 
Registered: Dec 2008
Location: Tamil Nadu, India
Distribution: Servers: Debian Squeeze and Wheezy. Desktop: Slackware64 14.0. Netbook: Slackware 13.37
Posts: 8,551
Blog Entries: 28

Rep: Reputation: 1176Reputation: 1176Reputation: 1176Reputation: 1176Reputation: 1176Reputation: 1176Reputation: 1176Reputation: 1176Reputation: 1176
Quote:
Originally Posted by grail View Post
The use of a function is generally tied to reducing the need to repeat the same lines of code several times.
Another reason for a function is to make the code more comprehensible; it has been suggested that no section of code should be more than X lines where X is what is visible on a screen (a lot bigger than it used to be!). Like all such "rules" it is a judgement call.
 
1 members found this post helpful.
Old 12-11-2011, 11:44 PM   #8
asimba
Member
 
Registered: Mar 2005
Location: 127.0.0.0
Distribution: Red Hat / Fedora
Posts: 349

Rep: Reputation: 42
Its just me - I usually get impatient when OP forgets to respond/acknowledge.
 
Old 12-12-2011, 02:57 PM   #9
sudhagud
LQ Newbie
 
Registered: Dec 2011
Location: London
Posts: 4
Blog Entries: 5

Original Poster
Rep: Reputation: 0
Smile

that's a big WOW, Thanks a lot, in fact you can say that my BASH scripting knowledge is a bit of an ancient relic and I have used some of the suggestions in other scripts that i have been writing. I guess that I will rewrite the script and revise it with all there in mind.

I appreciate all you guys and especially Catkin and David the H.

@asimba : so that i can use this script in different *nix other than linux, i.e. freebsd etc. hopefully.

Thanks a lot.
Sudhagud
(Till the revised script )

Last edited by sudhagud; 12-12-2011 at 03:02 PM.
 
  


Reply

Tags
auditor, firewall, network


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
improvements/suggestions for smb.conf ferradura Linux - Server 0 09-27-2007 07:46 PM
Firewall Suggestions sbabcock23 Linux - Security 8 06-10-2007 02:59 AM
Backtrack & Auditor boot cd's dont find NIC lexnlondon Linux - General 2 08-04-2006 06:35 AM
WEP cracking with auditor live cd doesn't find wireless card?!!!!!! yottabyte james Linux - Wireless Networking 2 01-29-2006 02:40 PM
can't find modules for firewall script strimp099 Linux - Networking 1 10-05-2004 10:26 PM


All times are GMT -5. The time now is 05:17 AM.

Main Menu
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
identi.ca: @linuxquestions
Facebook: linuxquestions Google+: linuxquestions
Open Source Consulting | Domain Registration