#/bin/bash

##
## zplog [-a] [-e string] [-f fn] [-i] [-m nm] [-n] [-p] [-s] [-v]
##
## displays ipchains packet logs. commmand line switches can be in any order
## no arguments will display packet logs using defaults where applicable
##
## -a  show ACCEPTs and MASQs (these are excluded by default)
## -e string  is a string to search for (i.e. only include lines containing it)
##            if -e is used more than once then the patterns from all of them
##            are matched (i.e. a line must contain all the patterns). matches
##            are done before the site names, services, or ICMP type names from
##            any of -h -i -n -p are included so you cannot match any of these
##            (you can match numeric IP addresses, services and ICMP types)
## -f fn  is messages file e.g. messages.fn (default of messages if -f missing)
##        useful if the (syslog) messages file has recenty been cleared
## -i  show ICMP type names
## -m nm  is number of messages to display (default of 10 if -m is missing)
## -n  show the site name by doing a host commmand on IP addresses
##     this slows up the log output. ignored if followed by -p
## -p  do a ping on IP addresses to try to get the site name. this
##     is slower than using -n but shows you if the site is still
##     on line when the log is output. ignored if followed by -n
## -s  show the service (port) name for TCP and UDP if it is in /etc/services
## -v  match all but ALL the -e strings (ignored if no -e's)
##
## any argument other than any of the above will display this description
##

# Copyright (c) by John H Bagster and Silicon Chip Publications, 2002

# This script is freeware and remains the property of John H. Bagster (the
# author), and Silicon Chip Publications (the publisher). You may use it and
# modify it to suit your needs at no cost, and you may distribute it unmodified
# provided you make no charge for it whatsoever and all distribution costs are
# met by you. If you modify it and distribute it you must include your name.
# This protects the author in case you muck it up, and gives you credit if you
# do a good job! This script must not be included as part of a package without
# prior arrangement with the author and publisher. If you substantially modify
# it to the point where you do a total rewrite you may distribute it and charge
# whatever you want, providing you include the following two lines:
# Based on an original script written by John H. Bagster
# and published in Silicon Chip by Silicon Chip Publications

# This script works well on the author's RedHat 7.0 distribution which uses
# ipchains, but the author and publisher accept no responsibility for its use,
# and do not guarantee that it will work on all installations of RedHat 7.0
# nor any other versions of Linux.

# process command line
#
num=10
fn=""
gs=""
gsv=""
doping=1
dohost=1
grepapat=$'ACCEPT\nMASQ'
grepahow="-v"
services=""
icmptypes=""

while [ "$1" != "" ]
do
 case "$1" in
  "-a")
   grepapat="*"
   grepahow=""
   ;;
  "-m")
   shift
   let num=$1+0
   ;;
  "-f")
   shift
   fn="."$1
   ;;
  "-e")
   shift
   [ "$gs" != "" ] && gs="$gs"$'\n'
   gs="$gs$1"
   ;;
  "-v")
   gsv="-v"
   ;;
  "-p")
   doping=0
   dohost=1
   ;;
  "-n")
   dohost=0
   doping=1
   ;;
  "-s")
   [ -f /etc/services ] && services=$(echo $(awk '!/^#/ {if ($0 != "") print $2 "/" $1}' /etc/services))
   ;;
  "-i")
   icmptypes=$(echo $(awk '/^#i/ {print $2 "/" $3 "/" $4}' $0))
   ;;
  *)
   awk -F'##' -v sn=$(echo $0|awk -F'/' '{print $NF}') '/^##/ {print gensub("zplog",sn,"e",gensub(" ","",1,$2))}' $0
   exit 1
   ;;
  esac
 shift
done

# don't invert pattern match if none specified
#
[ "$gs" == "" ] && gsv=""

# number of messages to display
#
[ $num -le 0 ] && num=10

# hostname of this machine
# 
hn=$(hostname|awk -F'.' '{print $1}')

# messages file
#
mf="/var/log/messages$fn"
if [ ! -f $mf ]
then
 echo "syslog file $mf does not exist"
 exit 1
fi

# get internal and external interfaces. this assumes you have one network card
# with a fixed IP address (internal network) and either a second card with a
# dynamic IP address or a modem, either of which will be the external network
#
INTIF=""
EXTIF=""
for i in /etc/sysconfig/network-scripts/ifcfg-*
do
 [[ $i == *"ppp"* ]] && EXTIF=$DEVICE
 if [[ $i == *"eth"* ]]
 then
  BOOTPROTO=""
  . "$i"
  if [ "$BOOTPROTO" == "dhcp" ]
  then
   EXTIF=$DEVICE
  else
   INTIF=$DEVICE
  fi
 fi
done

# internal network
#
INTLAN=""
[ "$INTIF" != "" ] && INTLAN="`/sbin/ifconfig $INTIF|awk -F ':' '/inet addr/ {print $2 " " $4}'|awk '{print $1 "." $3}'|awk -F '.' 'function a(b,c){return (int(b/(256-c))*(256-c))} {il="";if (a($1,$5) == $1) {il=$1;if (a($2,$6) == $2) {il=il "." $2;if (a($3,$7) ==$3) {il=il "." $3;if (a($4,$8) == $4) il=il "." $4}}};print il}'`"

# external IP address
#
EXTLAN=""
[ "$EXTIF" != "" ] && EXTLAN="`/sbin/ifconfig $EXTIF|awk '/inet addr/ {print $2}'|awk -F: '{print $2}'`"

# list of protocols
#
if [ -f /etc/protocols ]
then
 pc=$(awk '{if ($0 != "") {if ($1 != "#") print $2 "=" $1}}' /etc/protocols)
 pc=$(echo $pc|awk '{print gensub(" ","=","g")}')
else
 pc=""
fi

# find the required packet logs
#
z="$(grep -e "kernel: Packet log:" $mf|grep -e "$gs" $gsv|grep -E "$grepapat" $grepahow|tail -n $num)"

if [ "$z" == "" ]
then
 echo "No Packet Logs were found"
 exit 0
fi

# convert them to a more meaningful appearance
#
z="$(echo "$z"|awk -F$hn' kernel: Packet log: ' -v il=$INTLAN -v xl=$EXTLAN -v ii=$INTIF -v xi=$EXTIF -v pc=$pc '{npc=0;if (pc !="") npc=split(pc,pcs,"=");split($2,z," L=");split(z[2],y," T=");x = $1 z[1] substr(y[2],index(y[2]," "));b=x;if (il != "") {if (ii != "") {a=split(x,w,il);b=w[1];if (a>1) {b=b ii w[2];if (a > 2) b=b ii w[3]}}};a=b;if (xl != "") {if (xi != "") {a=split(b,w,xl);b=w[1];if (a>1) {b=b xi w[2];if (a > 2) b=b xi w[3]}}};if (npc > 0) {if (split(b,ab," PROTO=") > 1) {a=index(ab[2]," ");c=ab[2]+0;d="";e=1;while (e++ < npc) {if (pcs[e] == c) {d=" " pcs[e+1];break}};if (d != "") b=ab[1] d substr(ab[2],a)}};print b}')"

# include the TCP/UDP service (port) and/or ICMP type name if required
#
[ "$services" != "" -o "$icmptypes" != "" ] && z="$(echo "$z"|awk -F: -v s="$services" -v it="$icmptypes" -v x=0 'function ser(n){split($n,sd," ");if (sc[sd[1],p]!="") $n=gensub(sd[1],sd[1] "=" sc[sd[1],p],1,$n)} {OFS=":";if (x==0) {split(s,sa," ");for (z in sa) {split(sa[z],sb,"/");sc[sb[1],sb[2]]=sb[3]};split(it,ia," ");for (z in ia) {split(ia[z],ib,"/");if (ib[2]=="s") {ic4[ib[1]]=ib[3]} else ic5[ib[1],ib[2]]=ib[3]};x=1};split($3,sd," ");p=sd[5];if (p=="icmp") {split($4,sd," ");i=sd[1];if (ic4[i]!="") {$4=gensub(i,i "=" ic4[i],1,$4);split($5,sd," ");if (ic5[i,sd[1]]!="") $5=gensub(sd[1],sd[1] "=" ic5[i,sd[1]],1,$5)}} else {ser(4);ser(5)};print $0}')"

# find the name belonging to an IP address via ping if required. this is slower
# than host, but it tells you if the site is on line ($z2 is null if it isn't)
#
if [ $doping -eq 0 ]
then
 z1="ping"
 z2=" -c 1 -w 1 2>>/dev/null|awk -F' bytes from ' '/bytes from/ {split(\$2,a,\":\");b=gensub(\")\",\"\",\"g\",a[1]);c=index(b,\" (\");if (c>0) print \" (\" substr(b,1,c-1) \")\"}'"
fi

# find the name belonging to an IP address via host if required. this is faster
# than ping and will probably still work if the site is not currently on line
# $z2 is null if the host command cannot determine the name belonging to the IP
#
if [ $dohost -eq 0 ]
then
 z1="host"
 z2=" 2>>/dev/null|awk -F'domain name pointer ' '{if (\$2 != \"\") print \" (\" \$2 \")\"}'"
fi

if [ $doping -eq 0 -o $dohost -eq 0 ]
then
 # output the log including the site name after its IP address if required
 #
 echo "$z"|awk -v ii=$INTIF -v xi=$EXTIF -v q='"' -v sq="'" -v cmd=$z1 -v pipe="$z2" '{if (ii != "") {print "n=$" sq ii "\\n" xi "\\n" sq;ii=""};an=split($0,a,":");bn=split(a[an-2],b," ");cn=split(a[an-1],c," ");p2=b[bn];p4=c[cn];z1=index($0,p2);p1=substr($0,1,z1-1);z=substr($0,z1+length(p2));z1=index(z,p4);p3=substr(z,1,z1-1);p5=substr(z,z1+length(p4));print "[ " q "$(echo " q "$n" q "|grep -e " q p2 q ")" q " == " q q " ] && n=" q "${n}" p2 "$(" cmd " " p2 pipe ")" q "$" sq "\\n" sq;print "[ " q "$(echo " q "$n" q "|grep -e " q p4 q ")" q " == " q q " ] && n=" q "${n}" p4 "$(" cmd " " p4 pipe ")" q "$" sq "\\n" sq;print "echo " q p1 "$(echo " q "$n" q "|grep -e " q p2 q ")" p3 "$(echo " q "$n" q "|grep -e " q p4 q ")" p5 q}'|bash
else
 # otherwise just output the log
 #
 echo "$z"
fi

exit 0

#i 0 s pong
#i 1 s unassigned
#i 2 s unassigned
#i 3 s destination-unreachable
#i 3 0 network-unreachable
#i 3 1 host-unreachable
#i 3 2 protocol-unreachable
#i 3 3 port-unreachable
#i 3 4 fragmentation-needed
#i 3 5 source-route-failed
#i 3 6 network-unknown
#i 3 7 host-unknown
#i 3 8 source-host-isolated
#i 3 9 network-prohibited
#i 3 10 host-prohibited
#i 3 11 TOS-network-unreachable
#i 3 12 TOS-host-unreachable
#i 3 13 communication-prohibited
#i 3 14 host-precedence-violation
#i 3 15 precedence-cutoff
#i 4 s source-quench
#i 5 s redirect
#i 5 0 network
#i 5 1 host
#i 5 2 TOS-network
#i 5 3 TOS-host
#i 6 s alt-host-address
#i 7 s unassigned
#i 8 s ping
#i 9 s router-advert
#i 9 0 normal
#i 9 16 does-not-route-common-traffic
#i 10 s router-solicitation
#i 11 s time-exceeded
#i 11 0 transit
#i 11 1 reassembly
#i 12 s parameter-problem
#i 12 0 pointer-indicates-the-error
#i 12 1 required-option-missing
#i 12 2 bad-length
#i 13 s timestamp-request
#i 14 s timestamp-reply
#i 15 s information-request
#i 16 s information-reply
#i 17 s address-mask-request
#i 18 s address-mask-reply
#i 19 s security
#i 20 s robustness-experiment
#i 21 s robustness-experiment
#i 22 s robustness-experiment
#i 23 s robustness-experiment
#i 24 s robustness-experiment
#i 25 s robustness-experiment
#i 26 s robustness-experiment
#i 27 s robustness-experiment
#i 28 s robustness-experiment
#i 29 s robustness-experiment
#i 30 s traceroute
#i 31 s datagram-conversion-error
#i 32 s mobile-host-redirect
#i 33 s IPv6-where-are-you
#i 34 s IPv6-I-am-here
#i 35 s mobile-registration-request
#i 36 s mobile-registration-reply
#i 37 s domain-name-request
#i 38 s domain-name-reply
#i 39 s SKIP
#i 40 s photuris
#i 40 0 bad-SPI
#i 40 1 authentication-failed
#i 40 2 decompression-failed
#i 40 3 decryption-failed
#i 40 4 need-authentication
#i 40 5 need-authorization
