#!/bin/bash
#
# description: Firewall-log filter script (arno-fwfilter)
# Last update: March 20, 2015

# Usage examples (make sure arno-fwfilter is executable!):
# --------------------------------------------------------
# Static firewall log filtering                         : cat /var/log/messages |arno-fwfilter
# or
# Static firewall log filtering                         : cat /var/log/arno-iptables-firewall |arno-fwfilter
# Realtime firewall logging on TTY10                    : tail --follow /var/log/messages |fwfilter >/dev/tty10 &
# Example on how to disable kernel debug logging        : cat /var/log/messages |grep -v kernel |arno-fwfilter
# Email firewall logs to root                           : cat /var/log/arno-iptables-firewall |arno-fwfilter --html-output --no-colors |mail -s "Firewall Log" -a "Content-Type: text/html; charset=us-ascii" root

# ------------------------------------------------------------------------------------------
#                     -= Arno's Iptables Firewall(AIF) =-
#                  Firewall-log filter script (arno-fwfilter)
#
# (C) Copyright 2001-2015 by Arno van Amersfoort
# Web                   : https://github.com/arno-iptables-firewall/aif
# Email                 : a r n o DOT v a n DOT a m e r s f o o r t AT g m a i l DOT c o m
#                         (note: you must remove all spaces and substitute the @ and the .
#                          at the proper locations!)
# ------------------------------------------------------------------------------------------
# Some of the information used to create this script was obtained from:
# - http://ports.tantalo.net/
# - http://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xml
# - http://www.speedguide.net/ports.php
# ------------------------------------------------------------------------------------------
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# version 2 as published by the Free Software Foundation.

# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.

# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
# -------------------------------------------------------------------------------------------

# Options:
##########

# Enable this option if you want to resolve IP adresses to names (requires "dig")
RESOLVE_NAMES=1

# Enable this option if you want to (try to) obtain the IPs geographical location (can be very slow!) (requires "curl")
SHOW_LOCATION=0

# Enable this option if you want to resolve both the source and target host when doing location/name lookups (slower)
FULL_INFO=0

# Enable this option to use ANSI colors (increases readability)
USE_ANSI_COLORS=1

# Enable this if you want the output to be (colored) html formatted (for emails etc.)
USE_HTML=0

# Enable this if you want want to put all information on a single line
USE_1ROW=0

# Use this variable if your awk binary is in a non-default location (use 'locate awk' or 'whereis
# awk' to manually locate it).
AWK_BIN=""

#################################################################################################
# Parse commandline options (taken from the getopt examples from the Debian util-linux package) #
#################################################################################################

# Note that we use `"$@"' to let each command-line parameter expand to a
# separate word. The quotes around `$@' are essential!
# We need CLOPTS as the `eval set --' would nuke the return value of getopt.
CLOPTS=`getopt -o h,r,o,l,c,s --long help,no-resolve,html-output,no-locations,no-colors,single-line -n 'arno-fwfilter' -- "$@"`

if [ $? != 0 ] ; then
  echo "Terminating..." >&2
  exit 1
fi

# Note the quotes around `$CLOPTS': they are essential!
eval set -- "$CLOPTS"

while true; do
  case "$1" in
    -r|--no-resolve) RESOLVE_NAMES=0; shift;;
    -o|--html-output) USE_HTML=1; shift;;
    -l|--no-locations) SHOW_LOCATION=0; shift;;
    -c|--no-colors) USE_ANSI_COLORS=0; shift;;
    -s|--single-line) USE_1ROW=1; shift;;
    -h|--help)
    echo "Options:"
    echo "-h, --help         - Print this help"
    echo "-r, --no-resolve   - Disable resolving of IPs to names"
    echo "-o, --html-output  - Use basic HTML to format the output"
    echo "-l, --no-locations - Disable obtaining the IPs geographical location"
    echo "-c, --no-colors    - Disable the use of (ANSI) colors in the output"
    echo "-s, --single-line  - Put all information about an event in a single line"
    exit 0 # nothing left to do
    ;;
    --) shift ; break ;;
    *) echo "Internal error!"; exit 1;;
  esac
done

if [ -z "$AWK_BIN" ]; then
  if [ -x '/bin/gawk' ]; then
    AWK_BIN='/bin/gawk'
  else
    if [ -x '/usr/bin/gawk' ]; then
      AWK_BIN='/usr/bin/gawk'
    else
      if [ -x '/bin/awk' ]; then
        AWK_BIN='/bin/awk'
      else
        if [ -x '/usr/bin/awk' ]; then
          AWK_BIN='/usr/bin/awk'
        fi
      fi
    fi
  fi
fi

if [ -z "$AWK_BIN" ]; then
  echo "ERROR: Could not locate the AWK binary (is it installed?)."
  echo "You may want to configure it yourself inside this script."
else
  # Test what awk version is used (gawk, mawk etc...)
  test=`$AWK_BIN -W version 2>/dev/null |grep -i mawk`
  if [ -n "$test" ]; then
    # AWK_BIN=$(echo "$AWK_BIN -W interactive")
    echo "The configured AWK binary is MAWK, which does not work with the script. Please use GAWK instead"
    exit 1
  fi

  if [ "$USE_HTML" = "1" ]; then
    echo '<html><head><title>Firewall Log</title>'
    echo '<meta http-equiv="Content-Type" content="text/html; charset=us-ascii"></head>'
    echo '<body>'
  fi

  $AWK_BIN '

  # This is the function which performs the portname lookups
  ##########################################################
  function portname_lookup(port_str)
  {
     port=strtonum(port_str)

     if (port==0) return("Invalid Port(0)")
     if (port==1) return("SGI Irix TCPMUX(1)")
     if (port==7) return("Echo-Server(7)")
     if (port==9) return("Discard-Server(9)")
     if (port==11) return("Unix Sysstat(11)")
     if (port==13) return("Daytime-Server(13)")
     if (port==19) return("Chargen(19)")
     if (port==20) return("FTP-Data(20)")
     if (port==21) return("FTP(21)")
     if (port==22) return("SSH(22)")
     if (port==23) return("Telnet(23)")
     if (port==25) return("SMTP(25)")
     if (port==37) return("Time(37)")
     if (port==43) return("Who-IS(43)")
     if (port==53) return("DNS(53)")
     if (port==59) return("Ident(59)")
     if (port==67) return("BootP Server(67)")
     if (port==68) return("BootP Client(68)")
     if (port==69) return("TFTP(69)")
     if (port==79) return("Finger(79)")
     if (port==80) return("HTTP(80)")
     if (port==88) return("KRB5(88)")
     if (port==98) return("LinuxConf(98)")
     if (port==109) return("POP2(109)")
     if (port==110) return("POP3(110)")
     if (port==111) return("SunRPC/RPCbind(111)")
     if (port==113) return("IDENT(113)")
     if (port==119) return("NNTP News(119)")
     if (port==123) return("NTP(123)")
     if (port==135) return("MS RPC(135)")
     if (port==137) return("SMB Name(137)")
     if (port==138) return("SMB Data(138)")
     if (port==139) return("SMB Session(139)")
     if (port==143) return("IMAP(143)")
     if (port==161) return("SNMP(161)")
     if (port==177) return("XDMCP(177)")
     if (port==389) return("LDAP(389)")
     if (port==427) return("SLP(427)")
     if (port==443) return("HTTPS(443)")
     if (port==445) return("MSFT DS(445)")
     if (port==464) return("KPASSWD(464)")
     if (port==465) return("SMTP-SSL(465)")
     if (port==500) return("Appleshare(500)")
     if (port==513) return("Rwho(513)")
     if (port==515) return("Printer(515)")
     if (port==520) return("Route(520)")
     if (port==524) return("NCP(524)")
     if (port==525) return("TimeServer(525)")
     if (port==535) return("CORBA IIOP(535)")
     if (port==554) return("RealServer(554)")
     if (port==555) return("phAse zero(555)")
     if (port==587) return("SMTP-msa(587)")
     if (port==600) return("PC Server Backdoor(600)")
     if (port==635) return("Linux Mountd bug(635)")
     if (port==636) return("LDAPs(636)")
     if (port==691) return("MS-Exchange(691)")
     if (port==873) return("Rsync(873)")
     if (port==990) return("FTPs(990)")
     if (port==993) return("IMAPs(993)")
     if (port==995) return("POP3s(995)")
     if (port==1025) return("NFS(1025)")
     if (port==1026) return("Windows-Message-Service(1026)")
     if (port==1027) return("Windows-Message-Service(1027)")
     if (port==1080) return("SOCKS(1080)")
     if (port==1114) return("SQL(1114)")
     if (port==1214) return("KaZaa(1214)")
     if (port==1243) return("Sub-7(1243)")
     if (port==1394) return("Network Log Client(1394)")
     if (port==1433) return("MS-SQL(1433)")
     if (port==1434) return("MS-SQL monitor(1434)")
     if (port==1524) return("Trin 00(1524)")
     if (port==1662) return("Netview-aix-2(1662)")
     if (port==1723) return("PPtP(1723)")
     if (port==1883) return("IBM MQSeries SCADA(1883)")
     if (port==1900) return("UPnP(1900)")
     if (port==1999) return("Backdoor-G or Sub-7 2.x(1999)")
     if (port==2002) return("Cisco Secure ACS WebServer(2002)")
     if (port==2049) return("NFS(2049)")
     if (port==2243) return("Magicom Protocol(2243)")
     if (port==2343) return("Nati logos(2343)")
     if (port==2772) return("Sub-7 ScreenCapture(2772)")
     if (port==2773) return("Sub-7 KeyLogger(2773)")
     if (port==3127) return("MyDoom Backdoor(3127)")
     if (port==3128) return("Squid(3128)")
     if (port==3129) return("Masters Paradise(3129)")
     if (port==3268) return("globalcat-LDAP(3268)")
     if (port==3449) return("HotU Chat(3449)")
     if (port==3544) return("Teredo IPv6-IPv4 Tunnel(3544)")
     if (port==4500) return("MS IPsec NAT-T(4500)")
     if (port==4662) return("eDonkey(4662)")
     if (port==5000) return("UPnP(5000)")
     if (port==5060) return("SIP(5060)")
     if (port==5061) return("SIP over TLS(5061)")
     if (port==5222) return("Jabber/xmpp-client(5222)")
     if (port==5223) return("Jabber-SSL(5223)")
     if (port==5228) return("Android Market(5228)")
     if (port==5500) return("VNC(5500)")
     if (port==5554) return("Sasser-backdoor(5554)")
     if (port==5623) return("pcAnywhere(5623)")
     if (port==5800) return("VNC-data(5800)")
     if (port==5900) return("VNC-HTTP(5900)")
     if (port==5938) return("Teamviewer(5938)")
     if (port==6346) return("GNUtella(6346)")
     if (port==6670) return("Deep Throat(6670)")
     if (port==6711) return("Sub-7(6711)")
     if (port==6712) return("Sub-7(6712)")
     if (port==6713) return("Sub-7(6713)")
     if (port==6776) return("Backdoor-G or Sub-7(6776)")
     if (port==6969) return("GateCrasher(6969)")
     if (port==6970) return("RealAudio(6970)")
     if (port==7215) return("Sub-7 Matrix Chat(7215)")
     if (port==7777) return("Unreal or Klingon Honor Guard(7777)")
     if (port==7778) return("Unreal Tournament(7778)")
     if (port==8000) return("Seafile-seahub(8000)")
     if (port==8030) return("iTunes Radio Streams(8030)")
     if (port==8080) return("HTTP Alternate(8080)")
     if (port==8082) return("Seafile-fileserver(8082)")
     if (port==9100) return("JetDirect(9100)")
     if (port==9418) return("Git(9418)")
     if (port==10000) return("Webadmin(10000)")
     if (port==10001) return("Seafile-ccnet(10001)")
     if (port==10008) return("Cheeseworm(10008)")
     if (port==12001) return("Seafile-service(12001)")
     if (port==12345) return("Netbus(12345)")
     if (port==12346) return("Netbus(12346)")
     if (port==13223) return("PowWow(13223)")
     if (port>=16384 && port<=16472) return(sprintf("Real-Time Transport Protocol(RTP) (%i)",port))
     if (port==16660) return("Stacheldraht(16660)")
     if (port==16959) return("Sub-7(16959)")
     if (port==17027) return("Conducent(17027)")
     if (port==20034) return("Netbus 2 Pro(20034)")
     if (port==20002) return("Acidkor(20002)")
     if (port==21544) return("Girlfriend(21544)")
     if (port==22450) return("Sin(22450)")
     if (port==23456) return("EvilFTP(23456)")
     if (port==26000) return("Quake(26000)")
     if (port==26900) return("Hexen 2(26900)")
     if (port==26950) return("Hexen World(26950)")
     if (port==27015) return("Half-life Or Team Fortress Classic(27015)")
     if (port==27374) return("Backdoor-G or Sub-7(27374)")
     if (port==27444) return("Trin 00(27444)")
     if (port==27500) return("Quake World(27500)")
     if (port==27665) return("Trin 00(27665)")
     if (port>=27910 && port<=27961) return(sprintf("Quake(%i)", port))
     if (port>=28000 && port<=28008) return(sprintf("Starsiege Tribes(%i)", port))
     if (port==28910) return("Heretic 2(28910)")
     if (port==30100) return("NetSphere(30100)")
     if (port==31335) return("Trin 00(31335)")
     if (port==31337) return("Back Orifice(31337)")
     if (port==31338) return("Back Orifice(31338)")
     if (port==31789) return("Hack'a'Tack(31789)")
     if (port==31337) return("Back Orifice(31337)")
     if (port>=32770 && port<=32900) return(sprintf("SUN-RPC Portmapper(%i)",port))
     if (port==33270) return("Trinity v3(33270)")
     if (port>=33434 && port<=33600) return(sprintf("Traceroute?(%i)",port))
     if (port==41508) return("Inoculan(41508)")
     if (port==50505) return("Sockets de Troi(50505)")
     if (port==54283) return("Sub-7 Spy port(54283)")
     if (port==54320) return("Back Orifice 2K(54320)")
     if (port==54321) return("Back Orifice 2K(54321)")
     if (port==60001) return("Stacheldraht(60001)")
     if (port==65000) return("Stacheldraht(65000)")

     # If nothing else matches just return the port number
     return(port_str)
  }

  # This is the function which performs the ICMP lookups
  ######################################################
  function ICMP_lookup(type, code)
  {
     if (type==0 && code==0) return ("Echo reply")
     if (type==3 && code==0) return ("Network unreachable")
     if (type==3 && code==1) return ("Host unreachable")
     if (type==3 && code==2) return ("Protocol unreachable")
     if (type==3 && code==3) return ("Port unreachable")
     if (type==3 && code==4) return ("Fragmentation needed but no frag. bit set")
     if (type==3 && code==5) return ("Source routing failed")
     if (type==3 && code==6) return ("Destination network unknown")
     if (type==3 && code==7) return ("Destination host unknown")
     if (type==3 && code==8) return ("Source host isolated")
     if (type==3 && code==9) return ("Destination network administratively prohibited")
     if (type==3 && code==10) return ("Destination host administratively prohibited")
     if (type==3 && code==11) return ("Network unreachable for TOS")
     if (type==3 && code==12) return ("Host unreachable for TOS")
     if (type==3 && code==13) return ("Communication administratively prohibited by filtering")
     if (type==3 && code==14) return ("Host precedence violation")
     if (type==3 && code==15) return ("Precedence cutoff in effect")
     if (type==4 && code==0) return ("Source quench")
     if (type==5 && code==0) return ("Redirect for network")
     if (type==5 && code==1) return ("Redirect for host")
     if (type==5 && code==2) return ("Redirect for TOS and network")
     if (type==5 && code==3) return ("Redirect for TOS and host")
     if (type==8 && code==0) return ("Echo request")
     if (type==9 && code==0) return ("Router advertisement")
     if (type==9 && code==16) return ("Does not route common traffic")
     if (type==10 && code==0) return ("Route solicitation")
     if (type==11 && code==0) return ("TTL equals 0 during transit")
     if (type==11 && code==1) return ("TTL equals 0 during reassembly")
     if (type==12 && code==0) return ("IP header bad (catchall error)")
     if (type==12 && code==1) return ("Required options missing")
     if (type==12 && code==2) return ("Bad Length")
     if (type==13 && code==0) return ("Timestamp request")
     if (type==14 && code==0) return ("Timestamp reply (obsolete)")
     if (type==15 && code==0) return ("Information request")
     if (type==16 && code==0) return ("Information reply")
     if (type==17 && code==0) return ("Address mask request")
     if (type==18 && code==0) return ("Address mask reply")
     if (type==30 && code==0) return ("Outbound Packet succesfully forwarded")
     if (type==30 && code==1) return ("No route for Outbound Packet; packet discarded")
     if (type==40 && code==0) return ("Bad SPI")
     if (type==40 && code==1) return ("Authentication Failed")
     if (type==40 && code==2) return ("Decompression Failed")
     if (type==40 && code==3) return ("Decryption Failed")
     if (type==40 && code==4) return ("Need Authentication")
     if (type==40 && code==5) return ("Need Authorization")

     # If nothing else matches just return unknown
     return("Unknown ICMP type/code")
  }


  # Main program
  ##############
  {
    if (match($0, "IN=") != 0 || match($0, "firewall") != 0 || match($0, "Firewall") != 0 || match($0, "kernel") != 0)
    {
      if (match($0, "IN=") == 0)
      {
        printf("%s", $0)
      }
      else
      {
        # Check whether it is an incoming or outgoing packet
        if (match($0, "IN= ") != 0) INPUT=0; else INPUT=1
        if (match($0, "OUT= ") != 0) OUTPUT=0; else OUTPUT=1

        for (i = 1; i <= NF; i++)
        # First show message, SRC etc.
        {
          if (substr($i,1,4) == "SRC=") SRC_HOST=substr($i, 5, length($i) - 4)
          if (substr($i,1,4) == "DST=") DST_HOST=substr($i, 5, length($i) - 4)

          if (substr($i,1,4) != "MAC=" && substr($i,1,4) != "SRC=" && substr($i,1,4) != "DST=" && $i != "IN=" && $i != "OUT=" )
          {
            if ($(i+1) != "kernel:" && $i != "kernel:" && $i != "[kernel]" )
            {
              if (i==1)
                printf("%s", $i)
              else
                if (i==2 && length($2)==1)
                  # We always want 2 digits for the date-day:
                  printf(" 0%s", $i)
                else
                  printf(" %s", $i)
            }
          }

          if (substr($i,1,4) == "SRC=")
          {
            if (USE_ANSI_COLORS==1) printf("\033[0m\033[1;36m")
            if (USE_HTML==1) printf("<font color=turquoise>")

            printf(" %s", $i)
            
            if (USE_ANSI_COLORS==1) printf("\033[0m")
            if (USE_HTML==1) printf("</font>")

          }

          if (substr($i,1,4) == "DST=")
          {
            # Show destination
            ##################
            if (USE_ANSI_COLORS==1) printf("\033[0m\033[1;35m")
            if (USE_HTML==1) printf("<font color=dark purple>")

            printf(" %s", $i)

            if (USE_ANSI_COLORS==1) printf("\033[0m")
            if (USE_HTML==1) printf("</font>")
 
            if (INPUT==1 || FULL_INFO==1)
            {
              if (RESOLVE_NAMES==1 || SHOW_LOCATION==1)
                if (USE_1ROW==0)
                {
                  if (USE_HTML==1) printf("<br>\n                         "); else printf("\n               ")
                }

              if (USE_ANSI_COLORS==1) printf("\033[0m\033[1;36m")
              if (USE_HTML==1) printf("<font color=turquoise>")

              if (RESOLVE_NAMES==1)
              {
                # If multiple names exist for one IP then only use the first (head -n1)
                syscall=sprintf("printf \" $(dig +short +time=1 +tries=1 -x %s 2>/dev/null |head -n1 |grep -v \";;.*\" |sed s,.$,\"  \",)\" 2>/dev/null", SRC_HOST)
                system(syscall)
              }

              if (SHOW_LOCATION==1)
              {
                syscall=sprintf("curl -L --silent --connect-timeout 1 http://api.hostip.info/get_html.php?ip=%s 2>/dev/null |grep -e \"Country:\" -e \"City:\" |while read line; do printf \" $line\"; done", SRC_HOST)
                system(syscall)
              }
            }

            if (OUTPUT==1 || FULL_INFO==1)
            {
              if (RESOLVE_NAMES==1 || SHOW_LOCATION==1)
                if (USE_1ROW==0)
                {
                  if (USE_HTML==1) printf("<br>\n                         "); else printf("\n               ")
                }

              if (USE_ANSI_COLORS==1) printf("\033[0m\033[1;35m")
              if (USE_HTML==1) printf("<font color=dark purple>")
             
              if (RESOLVE_NAMES==1)
              {
                # If multiple names exist for one IP then only use the first (head -n1)
                syscall=sprintf("printf \" $(dig +short +time=1 +tries=1 -x %s 2>/dev/null |head -n1 |grep -v \";;.*\" |sed s,.$,\"  \",)\" 2>/dev/null", DST_HOST)
                system(syscall)
              }

              if (SHOW_LOCATION==1)
              {
                syscall=sprintf("curl -L --silent --connect-timeout 1 http://api.hostip.info/get_html.php?ip=%s 2>/dev/null |grep -e \"Country:\" -e \"City:\" |while read line; do printf \" $line\"; done", DST_HOST)
                system(syscall)
              }
            }

            if (USE_ANSI_COLORS==1) printf("\033[0m")
            if (USE_HTML==1) printf("</font>")

            break
          }
        }

        if (i==NF)
        {
          if (USE_HTML==1) printf("<br>")
          printf("\n")
        }
        else
        {
          offset=i+1
          if (USE_1ROW==0)
          {
            if (USE_HTML==1) printf("<br>\n                         "); else printf("\n               ")
          }
          else printf(" ")
        }

        save_offset=++offset;
        for (i = offset; i <= NF; i++) if (substr($i,1,6) == "PROTO=") break;

        offset=i

        # First show PROTO=
        if ($offset == "PROTO=UDP")
        {
          if (USE_ANSI_COLORS==1) printf("\033[0m\033[1;33m")
          if (USE_HTML==1) printf("<font color=yellow>")

          printf(" %s", $offset)

          if (USE_ANSI_COLORS==1) printf("\033[0m")
          if (USE_HTML==1) printf("</font>")
        }
        else
        if ($offset == "PROTO=TCP")
        {
          if (USE_ANSI_COLORS==1) printf("\033[0m\033[1;32m")
          if (USE_HTML==1) printf("<font color=green>")

          printf(" %s", $offset)

          if (USE_ANSI_COLORS==1) printf("\033[0m")
          if (USE_HTML==1) printf("</font>")
        }
        else
        if ($offset == "PROTO=ICMP")
        {
          if (USE_ANSI_COLORS==1) printf("\033[0m\033[1;34m")
          if (USE_HTML==1) printf("<font color=blue>")

          printf(" %s", $offset)

          if (USE_ANSI_COLORS==1) printf("\033[0m")
          if (USE_HTML==1) printf("</font>")
        }
        else
        {
          printf(" %s", $offset)
        }

        if (substr($(offset+1),1,4)=="SPT=")
        {
          # Second show DPT=
          if (USE_ANSI_COLORS==1) printf("\033[0m\033[1;31m")
          if (USE_HTML==1) printf("<font color=red>")

          printf(" DPT=%s", portname_lookup(substr($(offset+2), 5, length($(offset+2))-4)))

          if (USE_ANSI_COLORS==1) printf("\033[0m")
          if (USE_HTML==1) printf("</font>")

          # Third show SPT=
          printf(" SPT=%s", portname_lookup(substr($(offset+1), 5, length($(offset+1))-4)))
        }

        if ($(offset)=="PROTO=ICMP")
        {
          # Resolve type/code
          if (USE_ANSI_COLORS==1) printf("\033[0m\033[1;31m")
          if (USE_HTML==1) printf("<font color=red>")

          type=strtonum(substr($(offset+1), 6, length($(offset+1))-5))
          code=strtonum(substr($(offset+2), 6, length($(offset+2))-5))
          printf(" TYPE/CODE=%s(%i,%i)", ICMP_lookup(type, code), type, code)

          if (USE_ANSI_COLORS==1) printf("\033[0m")
          if (USE_HTML==1) printf("</font>")
        }

        ICMP_INFO=0
        for (i = save_offset; i <= NF; i++)
        # Show all other info
        {
          if (substr($i,1,1) == "[") ICMP_INFO=1
          if (ICMP_INFO==1)
          {
            if (substr($i,1,5) != "PREC=" && substr($i,1,4) != "TOS=" && substr($i,1,3) != "ID=" \
              && i != 4 && i != 5 && substr($i,1,2) != "DF" \
              && $i != "RES=0x00" && $i != "URGP=0")
                printf(" %s", $i)
          }
          else
          {
            if (substr($i,1,6) != "PROTO=" && substr($i,1,5) != "PREC=" && substr($i,1,4) != "TOS=" && substr($i,1,3) != "ID=" \
              && substr($i,1,4) != "LEN=" && i != 4 && i != 5 && substr($i,1,2) != "DF" && substr($i,1,4) != "SPT=" && substr($i,1,4) != "DPT=" \
              && $i != "RES=0x00" && $i != "URGP=0" && substr($i,1,7) != "WINDOW=" && substr($i,1,5) != "TYPE=" && substr($i,1,5) != "CODE=")
                printf(" %s", $i)
          }
        }
      }
      if (USE_HTML==1) printf("<br>")
      printf("\n")
    }
  }
  ' RESOLVE_NAMES=$RESOLVE_NAMES SHOW_LOCATION=$SHOW_LOCATION USE_ANSI_COLORS=$USE_ANSI_COLORS USE_1ROW=$USE_1ROW USE_HTML=$USE_HTML

  if [ "$USE_HTML" = "1" ]; then
    echo "</body></html>"
  fi
fi
