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 |
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
Are you new to LinuxQuestions.org? Visit the following links:
Site Howto |
Site FAQ |
Sitemap |
Register Now
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
 |
GNU/Linux Basic Guide
This 255-page guide will provide you with the keys to understand the philosophy of free software, teach you how to use and handle it, and give you the tools required to move easily in the world of GNU/Linux. Many users and administrators will be taking their first steps with this GNU/Linux Basic guide and it will show you how to approach and solve the problems you encounter.
Click Here to receive this Complete Guide absolutely free. |
|
 |
12-07-2011, 12:21 PM
|
#1
|
|
LQ Newbie
Registered: Dec 2011
Location: London
Posts: 4
Rep:
|
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.
|
12-10-2011, 11:42 AM
|
#2
|
|
LQ 5k Club
Registered: Dec 2008
Location: Tamil Nadu, India
Distribution: Debian Squeeze (server), Slackware 13.37 (netbook), Slackware64 14.0 (desktop),
Posts: 8,357
|
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.
|
12-10-2011, 02:26 PM
|
#3
|
|
Member
Registered: Mar 2005
Location: 127.0.0.0
Distribution: Red Hat / Fedora
Posts: 342
Rep:
|
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
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.
|
|
|
|
12-11-2011, 08:18 AM
|
#4
|
|
Moderator
Registered: May 2001
Posts: 24,792
|
Quote:
Originally Posted by sudhagud
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.
|
|
|
|
12-11-2011, 02:38 PM
|
#5
|
|
Bash Guru
Registered: Jun 2004
Location: Osaka, Japan
Distribution: Debian sid + kde 3.5 & 4.4
Posts: 6,577
|
- 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.
|
12-11-2011, 08:51 PM
|
#6
|
|
Guru
Registered: Sep 2009
Location: Perth
Distribution: Manjaro
Posts: 6,312
|
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.
|
12-11-2011, 11:28 PM
|
#7
|
|
LQ 5k Club
Registered: Dec 2008
Location: Tamil Nadu, India
Distribution: Debian Squeeze (server), Slackware 13.37 (netbook), Slackware64 14.0 (desktop),
Posts: 8,357
|
Quote:
Originally Posted by grail
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.
|
12-11-2011, 11:44 PM
|
#8
|
|
Member
Registered: Mar 2005
Location: 127.0.0.0
Distribution: Red Hat / Fedora
Posts: 342
Rep:
|
Its just me - I usually get impatient when OP forgets to respond/acknowledge.
|
|
|
|
12-12-2011, 02:57 PM
|
#9
|
|
LQ Newbie
Registered: Dec 2011
Location: London
Posts: 4
Original Poster
Rep:
|
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.
|
|
|
|
| Thread Tools |
Search this Thread |
|
|
|
Posting Rules
|
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts
HTML code is Off
|
|
|
All times are GMT -5. The time now is 02:36 AM.
|
|
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.
|
Latest Threads
LQ News
|
|