#!/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`$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/>$wanipWAN-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$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$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='sort' ;; dst) dstimg='sort' ;; esac # create html table cat >/tmp/sed.$$ </g s/^// 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.$$ </dev/null | grep -e "$expr_est" | grep -v -e "$fcmd" ;; *) get_conntrack_data 2>/dev/null | grep -e "$expr_est" ;; esac > /tmp/conntrack.$$ ipv6_short ip_to_wan ip_to_hostnames case $FORM_dns in yes) unique `cat /tmp/conntrack.$$ | sed "s/^\([^ ]*\) *\([^ ]*\) *\([^ ]*\) *\(\([^ ]\+\) \)\{2,4\}src=\([^ ]*\) dst=\([^ ]*\).*$/\6 \7/"` ip_to_dnsname ;; esac cat <$_CONT_numcon: `cat /tmp/conntrack.$$ | grep -c use`

EOF eval 'cat /tmp/conntrack.'$$' | '$scmd ' sed -f /tmp/sed.'$$ rm /tmp/sort.$$ /tmp/sed.$$ /tmp/conntrack.$$ 2>/dev/null echo '
$_CONT_layer3$_CONT_prot$_CONT_src$srcimg$_CONT_dest$dstimg$_CONT_state
  $_CONT_IP$_CONT_port$_CONT_IP$_CONT_port
' show_tab_footer show_html_footer