#!/bin/bash
# $Id: iptables-trace,v 1.14 2004/11/13 00:31:15 apc Exp $
# Tony Clayton <t ny-netfilter@clayt n.ca>

# You may use and edit this code freely.  If you make changes to
# it that are generally useful, please email them to me and/or
# post them on the netfilter mailing list <netfilter@lists.netfilter.org>

LOGPREFIX='${table:0:1}:${chain:0:14}:$rulenumber:${target:0:14}'
MAXPREFIXSIZE=27
PRINT=0
IPTABLES="iptables"

log_entry() {
  local action=$1
  local table=$3 cmd=$4 chain=$5
  local rulenumber="-"
  shift 5
  if [ "$last_chain" != "$chain" ]; then 
    rulenum=1
  fi
  case $action in
  (add|addpolicy)
    local rulespec
    if [ "$action" = "add" ]; then
      cmd="-I"
      rulespec=$rulenum
      rulenumber=$rulenum
      let rulenum=$rulenum+2
    fi
    while [ "$1" != "-j" ]; do
      rulespec="$rulespec $1"
      shift;
    done
    shift;
    target=$1
    eval prefix="${LOGPREFIX}"

    $IPTABLES -t $table $cmd $chain $rulespec -j LOG \
      --log-prefix "*${prefix:0:$MAXPREFIXSIZE}:" 
    ;;
  (skip)
    let rulenum=$rulenum+1
    ;;
  (delete)
    $IPTABLES -t $table -D $chain $rulenum
    ;;
  esac
  last_chain=$chain
}

start() {
  for table in $(cat /proc/net/ip_tables_names); do
    rulenum=1
    iptables-save -t $table | grep '^-' | \
    while read rule; do 
      log_entry add -t $table $rule
    done
    # log default policy for each chain
    iptables-save -t $table | grep '^:' | tr -d : | \
    while read chain target rest; do
      if [ "$target" != "-" ]; then
        log_entry addpolicy -t $table -A $chain -j $target
      fi
    done
  done
}

stop() {
  for table in $(cat /proc/net/ip_tables_names); do
    iptables-save -t $table | grep '^-' | \
    while read cmd; do 
      echo $cmd | grep -q -e '--log-prefix "\*'
      if [ $? -eq 0 ]; then
        log_entry delete -t $table $cmd
      else
        log_entry skip -t $table $cmd
      fi
    done
  done
}

case "$1" in 
  start) start
  ;;
  stop) stop
  ;;
  start_test) IPTABLES="echo iptables"; start
  ;;
  stop_test) IPTABLES="echo iptables"; stop
  ;;
  *) echo $"Usage: $0 {start|stop}"
     exit 1
esac

exit 0
