#!/bin/sh
#------------------------------------------------------------------------------
# conntrack.cgi - show conntrack table
#
# Creation: 17.10.2005 hh
# Last Update: $Id$
#
#------------------------------------------------------------------------------
# get main helper functions
. /srv/www/include/cgi-helper
LOCALHOST4="127.0.0.1"
LOCALHOST6="0000:0000:0000:0000:0000:0000:0000:0001"
# Functions
unique ()
{
list=' '
for i in $*
do
case "$list" in
*" $i "*) continue ;;
esac
list="$list$i "
done
}
ip_to_dnsname ()
{ # lookup unkown IPs
for ip in $list
do
get_dns_name $ip
[ "$res" ] && echo "s/>`shorten_ipv6 $ip` title=\"$ip\">$res> /tmp/sed.$$
done
}
ip_to_wan ()
{ # replace IP of default route interface in conntrack with "WAN-IP"
if [ -f /etc/default-route-interface ]
then
dev=`cat /etc/default-route-interface`
if [ -f /var/run/$dev.ip ]
then
wanip=`cat /var/run/$dev.ip`
echo "s/>$wanip title=\"$wanip\">WAN-IP> /tmp/sed.$$
fi
fi
}
ip_to_hostnames ()
{ # replace IPs of hosts in conntrack with names
hosts=' '
sed -n -e '/^[0-9a-z]/s/^\([^[:space:]]\+\)[[:space:]]\+\([^[:space:]]\+\).*/\1 \2/p' /etc/hosts /etc/hosts.d/* | while read ip name; do
case "$hosts" in
*" $ip "*) continue ;;
esac
hosts="$hosts$ip "
case "$ip" in
*:*) sip=`shorten_ipv6 $ip` ;;
*) sip=$ip ;;
esac
echo "s/>$sip title=\"$ip\">$name> /tmp/sed.$$
case $OPT_DHCP_$DHCP_TYPE in
yes_dnsmasq)
set -f
while read line
do
set -- $line
case $4 in
"*") continue ;;
esac
case "$hosts" in
*" $4 "*) continue ;;
esac
hosts="$hosts$4 "
echo "s/>$3 title=\"$3\">$4> /tmp/sed.$$
set +f
;;
esac
}
expand_ipv6 ()
{
echo $1 | sed -e 's/^:/0000:/;s/:$/:0000/' \
-e 's/^\(\([^:]\+:\)\{1\}\)\(\(:[^:]\+\)\{1,5\}\)$/\10000:\3/' \
-e 's/^\(\([^:]\+:\)\{2\}\)\(\(:[^:]\+\)\{1,4\}\)$/\10000:\3/' \
-e 's/^\(\([^:]\+:\)\{3\}\)\(\(:[^:]\+\)\{1,3\}\)$/\10000:\3/' \
-e 's/^\(\([^:]\+:\)\{4\}\)\(\(:[^:]\+\)\{1,2\}\)$/\10000:\3/' \
-e 's/^\(\([^:]\+:\)\{5\}\)\(\(:[^:]\+\)\{1\}\)$/\10000:\3/' \
-e 's/::/:0000:/' \
-e 's/:\(\([^:]\)\{1\}\):/:000\1:/' \
-e 's/:\(\([^:]\)\{1\}\):/:000\1:/' \
-e 's/:\(\([^:]\)\{1\}\):/:000\1:/' \
-e 's/:\(\([^:]\)\{1\}\):/:000\1:/' \
-e 's/:\(\([^:]\)\{1\}\):/:000\1:/' \
-e 's/:\(\([^:]\)\{1\}\):/:000\1:/' \
-e 's/:\(\([^:]\)\{2\}\):/:00\1:/' \
-e 's/:\(\([^:]\)\{2\}\):/:00\1:/' \
-e 's/:\(\([^:]\)\{2\}\):/:00\1:/' \
-e 's/:\(\([^:]\)\{2\}\):/:00\1:/' \
-e 's/:\(\([^:]\)\{2\}\):/:00\1:/' \
-e 's/:\(\([^:]\)\{2\}\):/:00\1:/' \
-e 's/:\(\([^:]\)\{3\}\):/:0\1:/' \
-e 's/:\(\([^:]\)\{3\}\):/:0\1:/' \
-e 's/:\(\([^:]\)\{3\}\):/:0\1:/' \
-e 's/:\(\([^:]\)\{3\}\):/:0\1:/' \
-e 's/:\(\([^:]\)\{3\}\):/:0\1:/' \
-e 's/:\(\([^:]\)\{3\}\):/:0\1:/' \
-e 's/^\(\([^:]\)\{1\}\):/000\1:/g' \
-e 's/^\(\([^:]\)\{2\}\):/00\1:/g' \
-e 's/^\(\([^:]\)\{3\}\):/0\1:/g' \
-e 's/:\(\([^:]\)\{1\}\)$/:000\1/g' \
-e 's/:\(\([^:]\)\{2\}\)$/:00\1/g' \
-e 's/:\(\([^:]\)\{3\}\)$/:0\1/g'
}
shorten_ipv6 ()
{
# The regular expressions below compress IPv6 addresses according to
# RFC 1884 §2.2/2. They work as follows:
#
# Expressions 1 & 2 compress for every octet all leading zeros to one.
# Expressions 3 & 4 remove for every non-zero octet all leading zeros.
# Expression 5 compresses the first two successive zero octets to '::'.
# Expressions 6-9 includes up to four successive zero octets into '::'.
# Expression 10 includes the first octet into '::' if it is zero.
# Expression 11 includes the last octet into '::' if it is zero.
#
# CAVEAT 1: Note that these expressions do not necessarily yield the most
# compact address because the first compressable zero-octet range (i.e.
# at least two successive zero octets) is compressed and not the longest
# one. To achieve the latter one has to determine the longest zero-octet
# range which, however, must be programmed by a shell script and costs
# processor time which can be spent for more useful tasks (I think).
#
# CAVEAT 2: These expressions only work for *uncompressed* addresses. If
# applied to an address already compressed, the resulting address may
# contain multiple '::' abbreviations, which is explicitly forbidden by
# RFC 1884 §2.2/2.
echo "$1" | sed -e 's/^0\{2,4\}/0/;s/:0\{2,4\}/:0/g;s/^0\([1-9a-fA-F]\)/\1/;s/:0\([1-9a-fA-F]\)/:\1/g;s/\:0:0:/::/;s/::0:/::/;s/::0:/::/;s/::0:/::/;s/::0:/::/;s/^0::/::/;s/::0$/::/'
}
ipv6_short ()
{
unique `grep -o -E "(([0-9a-f]{4}:){7}([0-9a-f]{4}))" /tmp/conntrack.$$`
for ip in $list
do
short_ip=`shorten_ipv6 $ip`
echo "s/$ip/$short_ip/g" >> /tmp/sed.$$
done
}
# calculates a modulo b
# $1 = first argument
# $2 = second argument
mod ()
{
expr $1 - \( $1 / $2 \) \* $2
}
# adds a regex for a single-digit range to $result
# $1 = first digit
# $2 = second digit
# $3 = ignore leading zero
gen_ipv4_range_filter_digits ()
{
# echo "filter_digits: first=$1 last=$2 ignore=$3" >&2
local begin=$1
if [ $1 -eq 0 -a $3 -ne 0 ]; then
[ $2 -eq 0 ] && return 1 || begin=1
fi
if [ $begin -eq $2 ]; then
result="$result$begin"
elif [ `expr $begin + 1` -lt $2 ]; then
result="$result[$begin-$2]"
else
result="$result[$begin$2]"
fi
[ $1 -eq 0 -a $3 -ne 0 ] && result="$result\?"
return 0
}
# adds a regex for a range with a given arity to $result
# $1 = first digit
# $2 = second digit
# $3 = arity
# $4 = ignore leading zero
gen_ipv4_range_filter_complete_range ()
{
# echo "filter_complete_range: first=$1 last=$2 arity=$3 ignore=$4" >&2
[ $1 -eq 0 -a $3 -gt 1 -a $4 -ne 0 ] && local ignore=1 || local ignore=0
gen_ipv4_range_filter_digits $1 $2 $ignore
local i=$3
while [ $i -gt 1 ]
do
[ $i -gt 10 ] || ignore=0
gen_ipv4_range_filter_digits 0 9 $ignore
i=`expr $i / 10`
done
}
# adds a regex for a range with a given arity to $result
# $1 = start of range
# $2 = end of range
# $3 = arity (1, 10, 100, ...)
# $4 = 1 if suppress leading zeros, 0 otherwise
# $5 = 1 if bracket expression, 0 if it is optional
gen_ipv4_range_filter ()
{
local f1=`expr $1 / $3`
local r1=`mod $1 $3`
local f2=`expr $2 / $3`
local r2=`mod $2 $3`
local limit=`expr $3 - 1`
# echo "filter: first=$1 last=$2 arity=$3 ignore=$4 bracket=$5 f1=$f1 r1=$r1 f2=$f2 r2=$r2 limit=$limit" >&2
if [ $f1 -eq $f2 ]; then
[ $f1 -eq 0 -a $4 -ne 0 ] && local ignore=1 || local ignore=0
gen_ipv4_range_filter_digits $f1 $f1 $ignore
gen_ipv4_range_filter $r1 $r2 `expr $3 / 10` $ignore $5
else
local parts=0
local old="$result"
result=""
ignore=$4
if [ $r1 -ne 0 ]; then
[ $f1 -eq 0 -a $4 -ne 0 ] && local ignore=1 || local ignore=0
gen_ipv4_range_filter_digits $f1 $f1 $ignore
[ $? -eq 0 ] && local bracket=1 || local bracket=0
gen_ipv4_range_filter `mod $1 $3` $limit `expr $3 / 10` $ignore $bracket
f1=`expr $f1 + 1`
parts=1
fi
local prefix="$result"
result=""
if [ $r2 -ne $limit ]; then
[ $f2 -eq 0 -a $4 -ne 0 ] && local ignore=1 || local ignore=0
gen_ipv4_range_filter_digits $f2 $f2 $ignore
[ $? -eq 0 ] && local bracket=1 || local bracket=0
gen_ipv4_range_filter 0 `mod $2 $3` `expr $3 / 10` $ignore $bracket
f2=`expr $f2 - 1`
parts=`expr $parts + 1`
fi
local suffix="$result"
result=""
if [ $f1 -le $f2 ]; then
[ $f1 -eq 0 -a $4 -ne 0 ] && local ignore=1 || local ignore=0
gen_ipv4_range_filter_complete_range $f1 $f2 $3 $ignore
parts=`expr $parts + 1`
fi
local middle="$result"
[ -n "$suffix" -a -n "$prefix$middle" ] && suffix="\|$suffix"
[ -n "$middle" -a -n "$prefix" ] && middle="\|$middle"
result="$old"
[ $parts -gt 1 -a $5 -ne 0 ] && result="$result\("
result="$result$prefix$middle$suffix"
[ $parts -gt 1 -a $5 -ne 0 ] && result="$result\)"
fi
}
# creates a regex for all hosts within a subnet
# $1 = net
# $2 = subnet mask (number of bits to use from the left, between 0 and 32)
create_ipv4_submask_filter ()
{
local net="$1"
local bits="$2"
local missing=`expr 32 - $bits`
local suffix=""
while [ $missing -ge 8 ]
do
[ -n "$suffix" ] && suffix="$suffix\\."
suffix="$suffix[^ ]*"
missing=`expr $missing - 8`
done
local prefix=""
while [ $bits -ge 8 ]
do
[ -n "$prefix" ] && prefix="$prefix\\."
prefix="$prefix${net%%.*}"
net="${net#*.}"
bits=`expr $bits - 8`
done
local middle=""
if [ $bits -gt 0 ]
then
local next="${net%%.*}"
local w=256
while [ $bits -gt 0 ]
do
w=`expr $w / 2`
bits=`expr $bits - 1`
done
local last=`expr $next + $w - 1`
result=""
gen_ipv4_range_filter $next $last 100 1 1
middle="$result"
[ -n "$prefix" ] && prefix="$prefix\\."
fi
[ -n "$prefix$middle" -a -n "$suffix" ] && suffix="\\.$suffix"
echo "$prefix$middle$suffix"
}
create_gen_filter ()
{
# [ -f /var/run/hc_no_generic_filter ] && return 1
# if [ -f /var/run/hc_generic_filter ]; then
# read host_expr < /var/run/hc_generic_filter
# return
# fi
dri_ips=' '
dri=`ip r s | sed -n -e '/^default/s/.*dev //p'`
[ "$dri" ] && for dri_ip in `ip a s $dri | sed -n -e 's/^ *inet6\? \([^ ]*\).*/\1/p'`
do
dri_ips="$dri_ips$dri_ip "
done
for net in `ip a s | sed -n -e 's/^ *inet6\? \([^ ]*\).*/\1/p'`; do
case "$dri_ips" in
*" $net "*) continue ;;
esac
[ "$dri_ip" = "$net" ] && continue
filter="create_ipv4_filter"
case $net in
*.*/*)
mask=${net#*/} # 127.0.0.1/8 -> 8
net=`netcalc network $net` # normalize network
;;
*:*/*)
mask=${net#*/} # 2001::1/64 -> 64
net=`prefixcalc6 \`expandv6.sh $net\`` # normalize network
filter="create_ipv6_filter"
;;
*.*)
mask=32
;;
*:*)
mask=128
filter="create_ipv6_filter"
;;
esac
if ! eval $filter $net $mask; then
return 1
fi
done
# echo "$host_expr" > /var/run/hc_generic_filter
return 0
}
create_ipv4_filter ()
{
expr=
case $2 in
8) ip=${1%%.*} ;; # 127.0.0.1 -> 127
16) ip=${1%.*.*} ;; # 127.0.0.1 -> 127.0
24) ip=${1%.*} ;; # 127.0.0.1 -> 127.0.0
32) ip=${1%.*} ; expr="\\.${1##*.}" ;; # 127.0.0, .1
*) ip=""; expr="`create_ipv4_submask_filter $1 $2`" ;;
esac
[ "$expr" ] || expr='\.[^ ]*'
ip=`echo $ip | sed -e 's/\./\\\\./g'`
if [ "$host_expr" ]; then
host_expr="$host_expr\|$ip$expr"
else
host_expr="$ip$expr"
fi
}
create_ipv6_filter ()
{
# TODO: adapt create_ipv4_submask_filter to work with hexadecimal numbers
return 1
}
create_filter ()
{
if ! create_gen_filter; then
host_expr=
unique $LOCALHOST4 $LOCALHOST6 `sed -n -e '/^[0-9a-z]/s/[[:space:]].*//p' /etc/hosts /etc/hosts.d/*`
for ip in $list; do
case $ip in
*:*) ip=`expand_ipv6 $ip` ;;
esac
if [ "$host_expr" ]; then
host_expr="$host_expr\|$ip"
else
host_expr="$ip"
fi
done
fi
port_expr='53'
[ "$HTTPD_PORT" ] && port_expr="$port_expr\|$HTTPD_PORT"
[ "$IMOND_PORT" ] && port_expr="$port_expr\|$IMOND_PORT"
[ "$TELMOND_PORT" ] && port_expr="$port_expr\|$TELMOND_PORT"
fcmd="\(\(src\|dst\)=\($host_expr\) \)\{2\}.*dport=\($port_expr\) "
}
get_conntrack_data()
{
conntrack -L -f ipv4 | sed 's/.*/ipv4 2 &/'
conntrack -L -f ipv6 | sed 's/.*/ipv6 10 &/'
}
# Security
check_rights "conntrack" "view"
show_html_header "$_MP_contrck"
if [ -f /srv/www/admin/status_rrdconntrack.cgi ]
then
show_tab_header "$_CONT_aconn" no "$_MP_contrckrrd" status_rrdconntrack.cgi
else
show_tab_header "$_CONT_aconn" no
fi
case $FORM_filter in yes) fchecked="checked" ;; esac
case $FORM_dns in yes) dchecked="checked" ;; esac
cat <
EOF
case $FORM_sort in
src) srcimg='' ;;
dst) dstimg='' ;;
esac
# create html table
cat >/tmp/sed.$$ </g
s/^/ %
EOF
case $FORM_sort in
src|dst)
case $FORM_sort in
src) sstr='\3:\5' ;;
dst) sstr='\5:\3' ;;
esac
scmd='sed -f /tmp/sort.$$ | sort | sed -e "s/sort=[^ ]* *//" |'
cat >/tmp/sort.$$ </
s%$%
$_CONT_layer3 | $_CONT_prot | $_CONT_src$srcimg | $_CONT_dest$dstimg | $_CONT_state | ||
---|---|---|---|---|---|---|
$_CONT_IP | $_CONT_port | $_CONT_IP | $_CONT_port |