#!/usr/bin/awk -f

BEGIN {
	# split input fields by a colon
	FS=":"
	# set default language
	LANGUAGE="en_US.UTF8"
	# set translation domain
	TEXTDOMAIN = "alterator-ulogd"
	readmsg=0
	LOGFILE="/var/log/configd.log"
	EFW="/etc/net/scripts/contrib/efw"
	IP="/sbin/ip"
	SERVPREFIX="/etc/alterator/alterator-firewall-"
	SQLITE3DB="/var/lib/ulogd/sqlite3.db"
	SQLITE3="/usr/bin/sqlite3"
	PROTOCOLS="/etc/protocols"

	while ((error = getline line < PROTOCOLS) > 0) {
		if (line ~ /^#/ || line ~ /^[[:space:]]*$/)
                        continue
		split(line, list, /[[:space:]]+/)
		if (list[1] && list[2])
			protocols[list[1]] = list[2]
	}

# open a persistent connection to the database
	dbpipe = SQLITE3 " -batch " SQLITE3DB
	PROCINFO[dbpipe, "pty"] = 1

	#close(dbpipe)
	#exit
}

# error reporting function
function debug(text, errno) {
	printf "%s " TEXTDOMAIN ": %s: %s\n", strftime("%B %d %H:%M:%S"), text, errno >> LOGFILE
	fflush(LOGFILE)
}

# choose if IP is internal ether external
function ip_location(addr,	ip) {
	if (match(addr, /^([[:digit:]]+)\.([[:digit:]]+)\.([[:digit:]]+)\.([[:digit:]]+)$/, ip) == 0)
		return "wrong"
	else {
		# rfc1918 10/8 prefix
		if (ip[1] == 10)
			return N_("internal")
		# rfc1918 172.16/12 prefix
		else if (ip[1] == 172 && ip[2] >= 16 && ip[2] <= 31)
			return N_("internal")
		# rfc1918 192.168/16 prefix
		else if (ip[1] == 192 && ip[2] == 168)
			return N_("internal")
		else
			return N_("external")
	}
}

# list interfaces
function iptables_list_ifaces(		cmd, error, line, list, iface, ip, loc, ifaces, idx, i, n) {
	cmd = IP " addr show"
	while ((error = cmd | getline line) > 0) {
		if (match(line, /^[[:digit:]]:+[[:space:]]+([^[:space:]]+):/, list) > 0) {
			iface = list[1]
			continue
		}
		if (match(line, /^[[:space:]]*inet[[:space:]]+([[:digit:].]+)\//, ip) > 0) {
			loc = ip_location(ip[1])
			if (loc != "wrong")
				ifaces[iface "/" ip[1]] = iface " - " ip[1] " - " loc
		}
	}
	n = asorti(ifaces, idx)
	for (i = 1; i <= n; i++) {
		if (idx[i] ~ /^lo\//)
			continue
		print "(\"" idx[i] "\" label \"" ifaces[idx[i]] "\")"
	}
	if (error == -1)
		debug("error reading interface list '" cmd "'", errno)
	close(cmd)
}

# list services for interface
function iptables_list_services(iface, ip, from, to,		cmd, error1, error2, file, service, desc, domain, drop, line, list, n, i) {
	cmd = "ls -1 " SERVPREFIX "*"
	totalsumin = 0
	totalsumout = 0
	while ((error1 = cmd | getline file) > 0) {
		if (file ~ /~$/ || file ~ /\.rpm/)
			continue
		desc = ""
		drop = 0
		localsumin = 0
		localsumout = 0
		while ((error2 = getline line < file) > 0) {
			if (line ~ /^port/) {
				split(line, list, /[[:space:]]+/)
				localsumin += iptables_acct_port(iface, ip, list[2], list[3], "in", from, to)
				localsumout += iptables_acct_port(iface, ip, list[2], list[3], "out", from, to)
				continue
			}
			if (line !~ /^description\y/)
				continue
			if ((n = split(line, list, /[[:space:]]+/)) < 3)
				continue
			domain = list[2]
			desc = list[3]
			for(i = 4; i <= n; i++)
				desc = desc " " list[i]
		}
		if (error2 == -1)
			debug("Error reading file '" file "'", ERRNO)
		close(file)
		service = gensub(SERVPREFIX, "", "g", file)
		printf "(\"%s\" service \"%s\" description \"%s\" in \"%0.1f\" out \"%0.1f\")",
		       service, service, N_(desc, domain), localsumin/1024.0, localsumout/1024.0
		totalsumin += localsumin
		totalsumout += localsumout
	}
	if (error1 == -1)
		debug("Error running command '" cmd "'", ERRNO)
	close(cmd)

	totalin = iptables_acct_port(iface, ip, "", "", "in", from, to)
	totalout = iptables_acct_port(iface, ip, "", "", "out", from, to)
	bytes = 9
	printf "(\"other\" service \"other\" description \"%s\" in \"%0.1f\" out \"%0.1f\")",
		N_("Other"), (totalin-totalsumin)/1024.0, (totalout-totalsumout)/1024.0
	printf "(\"total\" service \"total\" description \"%s\" in \"%0.1f\" out \"%0.1f\")",
		N_("Total"), totalin/1024.0, totalout/1024.0
}

function make_date(day,		list, date) {
	if (day && day >= 0 && split(day, list, /-/) > 0) {
		date = ""
		for (i = 1; i < 7; i++)
			if (list[i])
				date = date " " list[i]
			else
				date = date " 0"
		return mktime(date)
	}
	return -1
}

function iptables_acct_port(iface, ip, protocol, port, direction, from, to,		cmd, sql, error, bytes) {

	switch(direction) {
		case "in":
			d = "d"
			c = "i"
			break
		case "out":
			d = "s"
			c = "o"
			break
		default:
			return 0
	}

	sql = "SELECT SUM(bytes) FROM ulog_daily WHERE prefix='" c "count'"
	
	if (iface)
		sql = sql " AND iface='" iface "'"
	if (ip)
		sql = sql " AND " d "addr='" ip "'"
	if (protocol)
		sql = sql " AND protocol=" protocols[protocol]
	if (port)
		sql = sql " AND " d "port=" port

	from = make_date(from)
	if (from != -1)
		sql = sql " AND time>=" from
	to = make_date(to)
	if (to != -1)
		sql = sql " AND time<" to

	sql = sql ";"
	print sql |& dbpipe

	if ((error = dbpipe |& getline bytes) == -1)
		debug("Error running command '" cmd "'", ERRNO)

	if (bytes == "")
	    bytes = 0

	return bytes
}

# show translation
# overwriting locale settings
function N_(text, domain,			list, cmd, line) {
	if (!domain)
		domain = TEXTDOMAIN
	split(LANGUAGE, list, /:/)
	cmd = "LANGUAGE=\"" LANGUAGE "\" LANG=\"" list[1] ".UTF8\" gettext " domain " \"" text "\""
	cmd | getline line
	close(cmd)
	return line
}

# start message reading
/^_message:begin$/ {
	readmsg=1
	next
}

# stop message reading
/^_message:end$/ {
	readmsg=0
#	debug("==========", "==========")
#	for (attribute in params)
#		debug("params[" attribute "]", params[attribute])
	# overwrite current language
	if (params["language"] != "")
		LANGUAGE = gensub(/;/, ":", "g", params["language"])

	switch (params["action"]) {
		case "constraints":
			print "("
			printf " name (label \"%s\")", N_("Interface")
			printf " service (label \"%s\")", N_("Service")
			printf " in (label \"%s\")", N_("In")
			printf " out (label \"%s\")", N_("Out")
			printf " checkip (default #f label \"%s\")", N_("Check IP")
			print ")"
			break
		case "list":
			print "("
			switch (params["_objects"]) {
				case /\yservices$/:
					if (split(params["_objects"], list, /\//) > 1)
						if (list[5] != "checkip")
							iptables_list_services(list[1], "", list[3], list[4])
						else
							iptables_list_services(list[1], list[2], list[3], list[4])
					break
				default:
					iptables_list_ifaces()
			}
			print ")"
			break
		case "read":
			print "("
			if (split(params["_objects"], list, /\//) > 0) {
				printf " iface \"%s%s\"", list[1], (list[2]) ? "/" list[2] : ""
				if (list[3] && list[3] != -1)
					printf " from \"%s\"", list[3]
				if (list[4] && list[4] != -1)
					printf " to \"%s\"", list[4]
				if (list[5] == "checkip")
					print " checkip #t"
			}
			print ")"
			break
		case "write":
		case "new":
		case "delete":
			print "()"
			break
		default:
			print "#f"
	}
	fflush()
	# delete attribute/value pairs before next cycle
	delete params
	#exit
	next
}

# save attribute/value pairs
{
	if (! readmsg)
		next
	attribute=$1
	value=$2
	# join the rest of fields with a colon
	for (n = 3; n <= NF; n++)
		value=value ":" $n
	value = gensub(/([^\\])\\n/, "\\1\n", "g", value)
	params[attribute]=value
}
