#!/bin/sh -e

# CGI parameters                                default
#       generate_header=yes|no                  yes

. /usr/html/axis-cgi/lib/functions.sh

CGI_HDGEN=yes

croak() {
	[ $CGI_HDGEN != yes ] || __cgi_errhd 500 "$*"
	echo "$*" >&2
	exit 1
}

parse_port_addr() {
	# Function parses addresses:port on IPv4, IPV6 and IPv4-mapped IPv6
	# format and separates address and port.
	# $1 - Input
	# $2 - variable to save address
	# $3 - variable to save port
	local _addr=$1 _port

	_port=${_addr##*:} # Parse out local port
	_addr=${_addr%:*} # Remove trailing :port

	case $_addr in
		*:*.*)
			_addr=${_addr##*:} # Remove ::ffff:
			;
	esac
	eval $2=\$_addr && eval $3=\$_port
}

get_connection_list() {
	# Getting connection information from netstat and presents it
	# Only looks at ESTABLISHED connections
	local prot recq sendq localaddr remaddr status pid_prog pid process
	local service_name ign pname nname portptot serv_f=/etc/services
	local stat_f print_header=1 progset=0
	#	      ip    proto service/port process
	local format='%-39s %-9s %-22s %-40s\n'

	# Use policykit to get netstat information.
	dbus-send --system --print-reply --dest=com.axis.PolicyKitSystem 	--type=method_call /com/axis/PolicyKitSystem 	com.axis.PolicyKitSystem.GetActiveNetworkInfo string:"tcp-udp" |
	while read prot recq sendq localaddr remaddr status pid_prog; do
		# Default values
		pid=-1
		process=unknown
		service_name=unknown

		# Check that status == ESTABLISHED
		[ "$status" ] && [ $status = ESTABLISHED ] || continue

		# Parse port and addr to separate variables
		# and also remove ::ffff: prefix if it exists
		parse_port_addr $localaddr localaddr localport ||
			croak "Failed to parse local address and port"
		parse_port_addr $remaddr remaddr ign ||
			croak "Failed to parse remote address and port"

		# Get the pid from netstat
		case $pid_prog in
			*/*)
				pid=${pid_prog%/*}
				;
		esac
		# guard against no permission to lookup pid
		if [ $pid -le 0 ]; then
			pid=-
		else
			# OK netstat -p is bugged when reading program name,
			# it reads from /proc/pid/cmdline, no thx, parse
			# /proc/pid/stat instead. Ignore PIDs that
			# no longer exist.
			stat_f=/proc/$pid/stat
			while read ign pname ign; do
				process=${pname##*(}
				process=${process%)*}
			done 2>/dev/null <$stat_f || :
		fi

		# read /etc/services and map name to port/protocol
		while read nname portprot ign; do
			# Rename "tcp6" connections reported by netstat to
			# "tcp" in order to match entries in /etc/services
			local prot_temp=$prot
			[ $prot_temp != tcp6 ] || prot_temp=tcp

			case $portprot in
				$localport/$prot_temp)
					service_name=$nname
					break
					;
			esac
		done <$serv_f || croak "Couldn't read file '$serv_f'"

		# Formatting of table, both header and values
		# Print header just once
		[ $print_header -ne 1 ] || {
			printf "$format" IP PROTOCOL "SERVICE(PORT)" "PID/PROCESS"
			print_header=0
		}

		# Fill the table
		printf "$format" 			$remaddr $prot "$service_name($localport)" "$pid/$process"
	done
}

! tmp=$(__qs_getparam generate_header) || [ -z "$tmp" ] || CGI_HDGEN=$tmp
[ $CGI_HDGEN != yes ] || __cgi_errhd 200
get_connection_list