<?php
/*
$Id: functions.php 579 2014-05-17 21:23:44Z bhockney $
(C) 2003-2014 by Bob Hockney <zeus@ix.netcom.com>

functions for webfwlog

This code is distributed under the terms of GNU GPL
*/
?>
<?php

// This function does all database access, and is intended to be 
// data source transparent to the calling statement.  The caller
// neither knows nor cares whether we are using a mysql server,
// a postgresql server, syslog files, etc.

function db ($action, $target)
{
	// Called with (action, target [, db_data]);
	// if optional third argument is "syslog", use syslog functions;
	// if optional third argument is database link, pass to db function
	// as third argument.
	
	global $FWLOG, $config;
	
	if (func_num_args() > 2)
		$db_data = func_get_arg(2);
	else
		$db_data = "";

	if (is_string($db_data) and $db_data == "syslog") {
		return db_syslog($action, $target);
	} else {
		switch ("{$config["db"]}") {
			case "mysql":
				return db_mysql($action, $target, $db_data);
				break;
			case "pgsql":
				return db_pgsql($action, $target, $db_data);
				break;
			default:
				return false;
				break;
		}
	}
}

function db_syslog ($action, $target)
{
	global $config, $colnum, $rownum, $fields;
	switch ("$action") {
		case "init":
			$config["iptype"] = "text";
			$config["iptype_g"] = "text";
			$config["addr_type"] = "";
			$config["have_family"] = true;
			$config["mac_str"] = "raw_mac";
			return;
			break;
		case "init_webfwlog":
			return false;
			break;
		case "open":
			return false;
			break;
		case "close":
			return false;
			break;
		case "escape":
			return addslashes("$target");
			break;
		case "statement":
			return false;
			break;
		case "nextrow":
			$line = $target[$rownum];
			$rownum = $rownum + 1;
			$flds = count($fields);
			if ($flds < 1) {
				if ($line == "") {
					$ret = false;
				} else {
					$ret = $line;
				}
			} else {
				if ($line == "") {
					$ret = false;
				} else {
					$ret = array();
					$thisline = explode("\t", $line);
					$j = 0;
					$k = 0;
					while ($j < $flds) {
						if (isset($thisline[$j])) {
							$ret["{$fields[$j]}"] = "{$thisline[$j]}";
						} else {
							$ret["{$fields[$j]}"] = "";
						}
						$j = $j + 1;
					}
				}
			}
			return $ret;
			break;
		case "nextfield":
			$line = explode("\t", $target[$rownum]);
			if (!isset($line[$colnum])) {
				$ret = false;
			} else {
				$ret = $line[$colnum];
			}
			$colnum = $colnum + 1;
			return $ret;
			break;
		case "totalrows":
			return false;
			break;
		case "exists": // Doesn't quit if statement produces SQL error
			return false;
			break;
		case "listfields":
			return false;
			break;
		case "listtables":
			return false;
			break;
	}
}

function db_mysql ($action, $target, $db_data)
{
	global $config, $colnum, $data_t, $hostnames, $services;

	switch ("$action") {
		case "init":
			// tests attributes of database log table/view
			$link = db("open", "");
			if ($result = db("exists", "SELECT ip_saddr_bin FROM $data_t[0] LIMIT 1;", $link))
				$config["addr_type"] = "_bin";
			elseif ($result = db("exists", "SELECT ip_saddr FROM $data_t[0] LIMIT 1;", $link))
				$config["addr_type"] = "";
			else
				$config["addr_type"] = "";
			if ($result) {
				$row = db("nextrow", db("statement", "SHOW COLUMNS FROM $data_t[0] LIKE 'ip_saddr{$config["addr_type"]}';", $link));
				$type = $row["Type"];
			} else
				$type = "";
			if (preg_match("/int/", "$type")) {
				$config["iptype"] = "int";
			} elseif (preg_match("/binary/", "$type")) {
				if (preg_match("/varbinary/", "$type") or ! preg_match("/\(16\)/", "$type"))
					die("<p STYLE=\"color: red\"><strong>ip_saddr column type is $type," .
					" binary field must have fixed length of 16</strong></p>");
				$config["iptype"] = "bin";
			} else {
				$config["iptype"] = "text";
			}
			// icmp_gateway field may have different type
			$result = db("exists", "SHOW COLUMNS FROM $data_t[0] LIKE 'icmp_gateway';", $link);
			if ($result) {
				$row = db("nextrow", $result); 
				$type = $row["Type"];
			} else
				$type = "";
			if (preg_match("/int/", "$type")) {
				$config["iptype_g"] = "int";
			} else {
				$config["iptype_g"] = "text";
			}
			$result = db("exists", "SELECT local_time FROM $data_t[0] LIMIT 1", $link);
			if ($result)
				$config["have_local_time"] = true;
			else
				$config["have_local_time"] = false;
			$result = db("exists", "SELECT oob_family FROM $data_t[0] LIMIT 1", $link);
			if ($result)
				$config["have_family"] = true;
			else
				$config["have_family"] = false;
			$result = db("exists", "SELECT _id FROM $data_t[0] LIMIT 1", $link);
			if ($result)
				$config["data_id"] = "_id";
			else
				$config["data_id"] = "id";
			$result = db("exists", "SELECT mac_str FROM $data_t[0] LIMIT 1", $link);
			if ($result)
				$config["mac_str"] = "mac_str";
			else
				$config["mac_str"] = "raw_mac";
			db("close", $link);
			return;
			break;
		case "init_webfwlog":
			// tests attributes of webfwlog tables
			// link is open when called
			if (db("exists", "SELECT count(*) FROM $services LIMIT 1", $db_data))
				$config["have_services"]  = 1;
			$result = db("exists", "SHOW COLUMNS FROM $hostnames LIKE 'ip_addr';", $db_data);
			if ($result) {
				$config["have_hostnames"] = 1;
				$row = db("nextrow", $result); 
				$type = $row["Type"];
			} else
				$type = "";
			if (preg_match("/int/", "$type")) {
				$config["wfwl_iptype"] = "int";
			} elseif (preg_match("/binary/", "$type")) {
				$config["wfwl_iptype"] = "bin";
			} else {
				$config["wfwl_iptype"] = false;
			}
			return;
			break;
		case "open":
			$link = $config["mysql_connect"]("{$config["mysql_server"]}",
								  "{$config["mysql_user"]}",
								  "{$config["mysql_pass"]}");
			if ($link)
				return $link;
			else
				if ("{$config["mysql_ext"]}" == "mysqli")
					die(mysqli_error($link) . "<br>Cannot Connect to Server!");
				else
					die(mysql_error() . "<br>Cannot Connect to Server!");
			break;
		case "close":
			$config["mysql_close"]($target)
				or die($config["mysql_error"]($target) . "<br>Cannot close link!");
			return;
			break;
		case "escape":
			if ("{$config["mysql_ext"]}" == "mysqli")
				$escaped = $config["mysql_escape_string"]($db_data, "$target");
			else
				$escaped = $config["mysql_escape_string"]("$target");
			return "$escaped";
			break;
		case "statement":
			if ($config["debug"] >=2) print "<pre>".htmlspecialchars("$target", ENT_QUOTES)."</pre>\n";
			if ("{$config["mysql_ext"]}" == "mysqli")
				$result = $config["mysql_query"]($db_data, $target);
			else
				$result = $config["mysql_query"]($target);
			if (!$result) {
				if ($config["debug"] >= 1) include "include/debug.php";
				if ($config["allow_be_verbose"]) print "<pre>".htmlspecialchars("$target", ENT_QUOTES)."</pre><br>\n";
				die ("<p STYLE=\"color: red\"><strong>Query failed!<br>"
				 . $config["mysql_error"]($db_data) . "</strong></p>");
			}
			return $result;
			break;
		case "nextrow":
			$row = $config["mysql_fetch_assoc"]($target);
			return $row;
			break;
		case "nextfield":
			if ($config["mysql_ext"] == "mysqli") {
				if ($colnum >= mysqli_field_count($db_data)) return false;
				$field_info = mysqli_fetch_field_direct($target, $colnum);
				$field = $field_info->name;
			} else {
				if ($colnum >= mysql_num_fields($target)) return false;
				$field = mysql_field_name($target, $colnum);
			}
			$colnum = $colnum + 1;
			return $field;
			break;
		case "totalrows":
			return $config["mysql_num_rows"]($target);
			break;
		case "exists": // Doesn't quit if statement produces SQL error
			if ($config["debug"] >=2) print "<pre>".htmlspecialchars("$target", ENT_QUOTES)."</pre>\n";
			if ("{$config["mysql_ext"]}" == "mysqli")
				return $config["mysql_query"]($db_data, $target);
			else
				return $config["mysql_query"]($target);
			break;
		case "listfields":
			// call with "db.table"
			// returns array
			$query = "SHOW COLUMNS FROM $target;";
			$result = db("exists", "$query", $db_data);
			$columnnames = array();
			if (! $result) return $columnnames;
			$row = db("nextrow", $result);
			while ($row) {
				$columnnames[] = $row["Field"];
				$row = db("nextrow", $result);
			}
			return $columnnames;
			break;
		case "listtables":
			$result = db("exists", "SHOW TABLES FROM $target", $db_data);
			# the columns we want to have in the tables we are going to list
			$w_columns = array();
			$wantedcolumns = array(
				"ip_saddr","ip_daddr","ip_protocol","tcp_sport","tcp_dport",
				"udp_sport","udp_dport","icmp_type","icmp_code");
			$w_columns[] = $wantedcolumns;
			$wantedcolumns = array(
				"oob_family","ip_saddr_bin","ip_daddr_bin","ip_protocol","tcp_sport","tcp_dport",
				"udp_sport","udp_dport","icmp_type","icmp_code");
			$w_columns[] = $wantedcolumns;

			$out = array();
			while ($result and $row = $config["mysql_fetch_row"]($result)) {
				$columnnames = db("listfields", "$target.$row[0]", $db_data);
				$colnames = array_flip($columnnames);
				$is_data_table = false;
				for ($j=0; ! $is_data_table; $j++) {
					if (! isset($w_columns[$j])) break;
					$is_data_table = true;
					# check each wanted column name against the ones we have
					foreach($w_columns[$j] as $i) {
						if(!isset($colnames["$i"])) {
							$is_data_table = false;
						}
					}
				}
				# if this table contains all our wanted columns, add it to the list
				if($is_data_table) {
					$out[] = $row[0];
				}
			}
			return $out;
			break;
	}
}

function db_pgsql ($action, $target, $db_data)
{
	global $config, $colnum, $rownum, $data_t, $database, $version_php, $pg_version, $regexp, $hostnames, $services;
	if ($version_php[0] > 4 or ($version_php[0] == 4 and $version_php[1] >= 2)) {
		$pg_connect = "pg_connect";
		$pg_query = "pg_query";
		$pg_last_error = "pg_last_error";
		$pg_fetch_array = "pg_fetch_array";
		$pg_fetch_row = "pg_fetch_row";
		$pg_close = "pg_close";
		$pg_field_type = "pg_field_type";
		$pg_num_rows = "pg_num_rows";
		$pg_num_fields = "pg_num_fields";
		$pg_field_name = "pg_field_name";
		if (isset($pg_version[0]) and ($pg_version[0] > 7 or ($pg_version[0] == 7 and $pg_version[1] >= 2))) {
			$pg_escape_string = "pg_escape_string";
		} else {
			$pg_escape_string = "addslashes";
		}
	} else {
		$pg_connect = "pg_connect";
		$pg_query = "pg_exec";
		$pg_last_error = "pg_errormessage";
		$pg_fetch_array = "pg_fetch_array";
		$pg_fetch_row = "pg_fetch_row";
		$pg_close = "pg_close";
		$pg_field_type = "pg_fieldtype";
		$pg_num_rows = "pg_numrows";
		$pg_num_fields = "pg_numfields";
		$pg_field_name = "pg_fieldname";
		$pg_escape_string = "addslashes";
	}
	switch ("$action") {
		case "init":
			// tests attributes of database log table/view
			$link = db("open", "$database");
			if ($result = db("exists", "SELECT ip_saddr_str FROM $data_t[0] LIMIT 1", $link))
				$config["addr_type"] = "_str";
			elseif ($result = db("exists", "SELECT ip_saddr FROM $data_t[0] LIMIT 1", $link))
				$config["addr_type"] = "";
			else
				$config["addr_type"] = "";
			if ($result)
				$type = $pg_field_type($result, 0);
			else
				$type = "";
			if (preg_match("/int/", "$type")) {
				$config["iptype"] = "int";
			} elseif (preg_match("/inet/", "$type")) {
				$config["iptype"] = "inet";
			} else {
				$config["iptype"] = "text";
			}
			// icmp_gateway field may have different type
			$result = db("exists", "SELECT icmp_gateway FROM $data_t[0] LIMIT 1", $link);
			if ($result)
				$type = $pg_field_type($result, 0);
			else
				$type = "";
			if (preg_match("/int/", "$type")) {
				$config["iptype_g"] = "int";
			} elseif (preg_match("/inet/", "$type")) {
				$config["iptype_g"] = "inet";
			} else {
				$config["iptype_g"] = "text";
			}
			$result = db("exists", "SELECT local_time FROM $data_t[0] LIMIT 1", $link);
			if ($result)
				$config["have_local_time"] = true;
			else
				$config["have_local_time"] = false;
			$result = db("exists", "SELECT oob_family FROM $data_t[0] LIMIT 1", $link);
			if ($result)
				$config["have_family"] = true;
			else
				$config["have_family"] = false;
			$result = db("exists", "SELECT _id FROM $data_t[0] LIMIT 1", $link);
			if ($result)
				$config["data_id"] = "_id";
			else
				$config["data_id"] = "id";
			$result = db("exists", "SELECT mac_str FROM $data_t[0] LIMIT 1", $link);
			if ($result)
				$config["mac_str"] = "mac_str";
			else
				$config["mac_str"] = "raw_mac";
			db("close", $link);
			return;
			break;
		case "init_webfwlog":
			// tests attributes of webfwlog tables
			// link is open when called
			if (db("exists", "SELECT count(*) FROM $services LIMIT 1", $db_data))
				$config["have_services"]  = 1;
			$result = db("exists", "SELECT ip_addr FROM $hostnames LIMIT 1;", $db_data);
			if ($result) {
				$config["have_hostnames"] = 1;
				$type = $pg_field_type($result, 0);
			} else
				$type = "";
			if (preg_match("/int/", "$type")) {
				$config["wfwl_iptype"] = "int";
			} elseif (preg_match("/inet/", "$type")) {
				$config["wfwl_iptype"] = "inet";
			} else {
				$config["wfwl_iptype"] = false;
			}
			return;
			break;
		case "open":
			if (isset($config["pgsql_server"])) {
				$host = "host={$config["pgsql_server"]}";
			} else {
				$host = "";
			}
			$link = $pg_connect("$host
								   user={$config["pgsql_user"]}
								   password={$config["pgsql_pass"]}
								   dbname=$target")
				or die($pg_last_error() . "<br>Cannot Connect to Server!");
			return $link;
			break;
		case "close":
			$pg_close($target)
				or die($pg_last_error() . "<br>Cannot close link!");
			return;
			break;
		case "escape":
			$escaped = $pg_escape_string("$target");
			return "$escaped";
			break;
		case "statement":
			if ($config["debug"] >=2) print "<pre>".htmlspecialchars("$target", ENT_QUOTES)."</pre>\n";
			$result = @$pg_query($target);
			if (!$result) {
				if ($config["debug"] >= 1) include "include/debug.php";
				if ($config["allow_be_verbose"]) print "<pre>".htmlspecialchars("$target", ENT_QUOTES)."</pre><br>\n";
				die ("<p STYLE=\"color: red\"><strong>Query failed!<br>"
				 . $pg_last_error() . "</strong></p>");
			}
			return $result;
			break;
		case "nextrow":
			if ($rownum >=$pg_num_rows($target)) return false;
			$row = $pg_fetch_array($target, $rownum, PGSQL_ASSOC);
			$rownum = $rownum + 1;
			return $row;
			break;
		case "nextfield":
			if ($colnum >=$pg_num_fields($target)) return false;
			$field = $pg_field_name($target, $colnum);
			$colnum = $colnum + 1;
			return "$field";
			break;
		case "totalrows":
			return $pg_num_rows($target);
			break;
		case "exists": // Doesn't quit if statement produces SQL error
			if ($config["debug"] >=2) print "<pre>".htmlspecialchars("$target", ENT_QUOTES)."</pre>\n";
			return @$pg_query("$target");
			break;
		case "listfields":
			// call with "schema.table"
			// returns array
			$table = explode(".", "$target");
			# build a list of column names
			if ($config["have_namespace"]) {
				$pg_statement = 
				"SELECT a.attname FROM pg_catalog.pg_attribute a\n" .
				"	LEFT JOIN pg_catalog.pg_class c ON c.oid = a.attrelid\n" .
				"	LEFT JOIN pg_catalog.pg_namespace n ON n.oid=c.relnamespace\n" .
				"WHERE n.nspname $regexp '^$table[0]$'\n" .
				"	AND c.relname $regexp '^$table[1]$'\n" .
				"	AND a.attnum >0\n" .
				"	AND NOT a.attisdropped;";
			} else {
				$pg_statement = 
				"SELECT a.attname FROM pg_class c, pg_attribute a\n" .
				"WHERE c.relname $regexp '^$table[0]$'\n" .
				"	AND a.attnum > 0 AND a.attrelid = c.oid\n" .
				"ORDER BY a.attnum;";
			}
			$fieldlist = db("statement", "$pg_statement", $db_data);
			$columnnames = array();
			while ($fields = $pg_fetch_row($fieldlist)) {
				$columnnames[] = "$fields[0]";
			}
			return $columnnames;
			break;
		case "listtables":
			if ($config["have_namespace"]) {
				$pg_statement = 
				"SELECT c.relname FROM pg_catalog.pg_class c\n" .
				"	LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace\n" .
				"WHERE c.relkind IN ('r','v') AND n.nspname $regexp '^$target$'\n" .
				"ORDER BY c.relname";
				$schema = "$target.";
			} else {
				$pg_statement = 
				"SELECT relname FROM pg_class WHERE relkind='r' OR relkind='v' ORDER BY relname";
				$schema = "";
			}

			$result = db("statement", "$pg_statement", $db_data);

			# the columns we want to have in the tables we are going to list
			$w_columns = array();
			$wantedcolumns = array(
				"ip_saddr","ip_daddr","ip_protocol","tcp_sport","tcp_dport",
				"udp_sport","udp_dport","icmp_type","icmp_code");
			$w_columns[] = $wantedcolumns;
			$wantedcolumns = array(
				"oob_family", "ip_saddr_str","ip_daddr_str","ip_protocol","tcp_sport","tcp_dport",
				"udp_sport","udp_dport","icmp_type","icmp_code");
			$w_columns[] = $wantedcolumns;

			$out = array();
			while ($row = $pg_fetch_row($result)) {
				$columnnames = db("listfields", "$schema$row[0]", $db_data);
				$colnames = array_flip($columnnames);
				$is_data_table = false;
				for ($j=0; ! $is_data_table; $j++) {
					if (! isset($w_columns[$j])) break;
					$is_data_table = true;
					# check each wanted column name against the ones we have
					foreach($w_columns[$j] as $i) {
						if(!isset($colnames["$i"])) {
							$is_data_table = false;
						}
					}
				}
				# if this table contains all our wanted columns, add it to the list
				if($is_data_table) {
					$out[] = $row[0];
				}
			}
			return $out;
			break;
	}
}

// Returns decimal representation of $value

function get_number ($value) {
	$a = trim("$value");
	if (strlen("$a") > 1 and $a[0] == 0) {
		if ($a[1] == "x") {
			$ret = intval("$a", 16);
		} elseif ($a[1] == "b") {
			$ret = intval(substr("$a", 2), 2);
		} else {
			$ret = intval("$a", 8);
		}
	} else {
		$ret = intval("$a", 10);
	}
	return $ret;
}

// Test value to see if it is numeric, including binary values

function wfwl_is_numeric ($value) {
	$a = trim("$value");
	$ret = false;
	if (substr("$a", 0,2) == '0b' and is_numeric(substr("$a", 2)))
		$ret = true;
	elseif (is_numeric("$a"))
		$ret = true;

	return $ret;
}

// This function creates numeric where clause for $field, splitting for
// possible range and multiple values, and validating numeric values.
// Second parameter is exclusion from the test for which the
// rule applies, or false if it applies to all values.

function where_num ($field, $extra) {
	global $FWLOG; 
	if (isset($FWLOG["i_$field"])) {$inv=" NOT";} else {$inv="";}
	$values = explode(",", "{$FWLOG["w_$field"]}");
	if ($extra) {
		$ret = "\tAND (NOT ($extra) OR$inv (";
	} elseif ($inv) {
		$ret = "\tAND (t.$field IS NULL OR NOT (";
	} else {
		$ret = "\tAND (";
	}
	foreach($values as $k => $value) {
		if ($k > 0)
			 $ret .= " OR ";
		$range = explode(":", "$value");
		if (count($range) > 1) {
			if (!wfwl_is_numeric(trim($range[0])) or !wfwl_is_numeric(trim($range[1]))) return "";
			$ret .= "t.$field BETWEEN ".get_number($range[0])." AND ".get_number($range[1]);
		} else {
			if (!wfwl_is_numeric(trim($value))) return "";
			$ret .= "t.$field=".get_number($value);
		}
	}
	if ($extra or $inv)
		$ret .= ")";
	return "$ret" . ")\n";
}

// This function is used to generate the uri used in  
// links on html reports

function makewhere ($field, $value, $sname, $family) {
	global $config, $FWLOG, $c_extra_split, $count, $source;

	switch ("$field") {
		case "oob_time_sec":
		case "oob_time_usec":	 // These never get
		case "dst_host":	 // links.  Need
		case "src_host":	 // parameter check
		case "dst_service":	 // but this serves
		case "src_service":	 // as fail-safe
		case "local_time":
		case "oob_earliest":
		case "oob_latest":
		case "earliest":
		case "latest":
			$ret = false;
			break;
		
		case "tcp_options":
			$uri = "";
			if ((strlen($value) and $value[0] =="s") or preg_match("/SYN/", "$value")) {$flag = "on";} else {$flag = "";} $uri = $uri . "&w_tcp_syn=$flag";
			if (strlen($value) > 1 and $value[1] =="a") {$flag = "on";} else {$flag = "";}; $uri = $uri . "&w_tcp_ack=$flag";
			if (strlen($value) > 2 and $value[2] =="f") {$flag = "on";} else {$flag = "";}; $uri = $uri . "&w_tcp_fin=$flag";
			if (strlen($value) > 3 and $value[3] =="r") {$flag = "on";} else {$flag = "";}; $uri = $uri . "&w_tcp_rst=$flag";
			if (strlen($value) > 4 and $value[4] =="p") {$flag = "on";} else {$flag = "";}; $uri = $uri . "&w_tcp_psh=$flag";
			if (strlen($value) > 5 and $value[5] =="u") {$flag = "on";} else {$flag = "";}; $uri = $uri . "&w_tcp_urg=$flag";
			$ret = $uri . "&w_tcp_options=on";
			break;
		case "id":
			if ($source == "syslog") {
				$ret = "&w_id=".urlencode("$value")."&syslog_file=".urlencode("$sname");
			} else {
				$ret = "&w_id=".urlencode("$value")."&w_sname=".urlencode("$sname");
			}
			$ret .= "&reporttype=packet";
			break;
		case "count":
			global $line, $temp;
			$uri = "";
			$count = "yes";
			foreach ($line as $col => $v) {
				if ("$col" == "ip_saddr_t" or "$col" == "ip_daddr_t" or "$col" == "oob_family_t" or "$col" == "ip_protocol_t"
					or "$col" == "tcp_sport_t" or "$col" == "udp_sport_t"
						or "$col" == "tcp_dport_t" or "$col" == "udp_dport_t")
					continue;
				if ($source == "syslog") {
					$field = "$col";
				} else {
					$field = "{$temp["$col"]}";
				}
				if (!("$field" == "id" or "$field" == "count")) {
					$uri = "{$uri}" . makewhere("$field", "$v", "", "$family"); // . " ";
				}
			}
			$ret = "$uri&c_count=&summarize=&c_earliest=&c_latest=&c_oob_earliest=&c_oob_latest=&c_id=0&l_id=on";
			break;

		case "dport":
			if ($count) {
				$ret = "&w_tcp_dport=".urlencode("$value")."&w_udp_dport=".urlencode("$value").""
				."&i_tcp_dport=&i_udp_dport=";
			} else {
				$ret = "&w_ip_protocol=1,58&i_ip_protocol=on&w_tcp_dport=".urlencode("$value")."&w_udp_dport=".urlencode("$value").""
				."&i_tcp_dport=&i_udp_dport=";
			}
			break;
		case "sport":
			if ($count) {
				$ret = "&w_tcp_sport=".urlencode("$value")."&w_udp_sport=".urlencode("$value").""
				."&i_tcp_sport=&i_udp_sport=";
			} else {
				$ret = "&w_ip_protocol=1,58&i_ip_protocol=on&w_tcp_sport=".urlencode("$value")."&w_udp_sport=".urlencode("$value").""
				."&i_tcp_sport=&i_udp_sport=";
			}
			break;
		case "ip_protocol":
			$ip_proto = $value;
			if (!is_numeric($ip_proto)) $ip_proto = getprotobyname($ip_proto);
			$ret = "&i_ip_protocol=&w_ip_protocol=".urlencode("{$ip_proto}");
			break;
		case "extra":
			if (!is_numeric($value)) $value = "'".urlencode($value)."'";
			if (isset($FWLOG["g_extra"])) { // set if no aggregate function in arbitrary column
				if (isset($FWLOG["w_extra"]) and $FWLOG["w_extra"]) {
					$ret = "&w_extra=".urlencode("{$FWLOG["w_extra"]})\n\tAND ({$c_extra_split["key"]} = $value");
				} else {
					$ret = "&w_extra=".urlencode("{$c_extra_split["key"]} = $value");
				}
			} else {
				if (isset($FWLOG["h_extra"]) and $FWLOG["h_extra"]) {
					$ret = "&h_extra=".urlencode("{$FWLOG["h_extra"]})\n\tAND ({$c_extra_split["key"]} = $value");
				} else {
					$ret = "&h_extra=".urlencode("{$c_extra_split["key"]} = $value");
				}
			}
			break;
		case "sname":
			if ($source == "syslog") {
				$ret = "&syslog_file=".urlencode("$value");
			} else {
				$ret = "&w_{$field}=".urlencode(trim("$value"));
			}
			break;
		case "oob_prefix":
		case "local_hostname":
		case "oob_in":
		case "oob_out":
		case "mac_saddr_str":
		case "mac_daddr_str":
		case "raw_mac":
			$ret = "&w_{$field}=".urlencode("^".addcslashes("$value", '^.[$()|*+?\{')."$")."&i_{$field}=";
			break;
		case "icmptype":
		case "icmpcode":
		case "icmpechoid":
		case "icmpechoseq":
			$t = preg_replace('/^icmp/','',"$field");
			if ($family == AF_INET)
				$ret = "&w_icmp_{$t}=".urlencode("$value")."&i_icmp_{$t}=";
			else
				$ret = "&w_icmpv6_{$t}=".urlencode("$value")."&i_icmpv6_{$t}=";
			break;
		default: 			// If not listed above print link
			if ($value == '') {
				$ret = "";
			} 
			$ret = "&w_{$field}=".urlencode("$value")."&i_{$field}=";
			break;
	}
	return "$ret";
}

// This function sets failsafe defaults, and is 
// only called when nothing else is available
function set_defaults ($FWLOG) {
	global $config;
	unset($FWLOG);
	$FWLOG = array();
	$FWLOG["summarize"] = "on";
	$FWLOG["page_length"] = "20";
	$FWLOG["refresh"] = "300";
	$FWLOG["description"] = "Summarized activity since yesterday";
	$FWLOG["data_source"] = "{$config["default_data_source"]}";
	$FWLOG["s_ip_protocol"] = "1";
	$FWLOG["o_ip_protocol"] = "on";
	$FWLOG["s_dport"] = "2";
	$FWLOG["s_ip_saddr"] = "3";
	$FWLOG["l_count"] = "on";
	$FWLOG["c_count"] = "1";
	$FWLOG["l_oob_prefix"] = "on";
	$FWLOG["c_oob_prefix"] = "2";
	$FWLOG["l_ip_protocol"] = "on";
	$FWLOG["c_ip_protocol"] = "3";
	$FWLOG["l_ip_saddr"] = "on";
	$FWLOG["c_ip_saddr"] = "4";
	$FWLOG["l_ip_daddr"] = "on";
	$FWLOG["c_ip_daddr"] = "5";
	$FWLOG["l_dport"] = "on";
	$FWLOG["c_dport"] = "6";
	$FWLOG["l_tcp_options"] = "on";
	$FWLOG["c_tcp_options"] = "7";
	$FWLOG["w_min_date"] = "yesterday";
	$FWLOG["w_max_date"] = "Today";
	$FWLOG["w_tcp_syn"] = "on";
	$FWLOG["w_tcp_fin"] = "on";
	$FWLOG["w_tcp_rst"] = "on";
	$FWLOG["w_tcp_ack"] = "on";
	$FWLOG["w_tcp_urg"] = "on";
	$FWLOG["w_tcp_psh"] = "on";
	return $FWLOG;
}

// Returns a comparison expression for selecting by IP/netmask
function where_ip($ip, $cmp_ip, $ip_type, $db_data)
{
	global $config, $data_t, $inet_aton, $inet_pton, $inet_contains, $true;

	$nethost = explode('/', $cmp_ip);
	$ret = '';
	if ("$ip_type" == "inet") {
		if (count($nethost) == 1) {
			$ret = "$ip = '$cmp_ip'";
		} else {
			$mask = explode('.', $nethost[1]);
			if (count($mask) > 1) {
				die("<p STYLE=\"color: red\"><strong>Column type is inet, netmask must be in CIDR notation: a.b.c.d/yy<br>" .
				"Test value was " . htmlspecialchars("$cmp_ip", ENT_QUOTES) . "</strong></p>");
			} else {
				$ret = "$ip << '$cmp_ip'";
			}
		}
	} elseif ("$ip_type" == "bin") {
		if (strpos($nethost[0], ':')) { 
			//ipv6
			$family = AF_INET6;
		} else {
			//ipv4
			$family = AF_INET;
		}
		if (count($nethost) == 1) {
			$ret =	"t.oob_family=$family AND $ip = $inet_pton(".AF_INET6.", '{$nethost[0]}')";
		} else {
			$mask = explode('.', $nethost[1]);
			if (count($mask) > 1 and $family == AF_INET6) {
				die("<p STYLE=\"color: red\"><strong>Column type is binary, prefix bits must follow '/': " .
				"aa:bb::cc:dd/yyy<br>Test value was " . htmlspecialchars("$cmp_ip", ENT_QUOTES) . "</strong></p>");
			} else {
				$ret = "$inet_contains(t.oob_family, $ip, '$cmp_ip')";
			}
		}
	} else { // ip_type = int or text
		$cmp_addr = ip2long($nethost[0]);

		if (count($nethost) > 1) {
			$mask = explode('.', $nethost[1]);
			if (count($mask) == 1 and is_numeric($mask[0])) {
				$netmask = (pow(2,(32 - $mask[0]))) ;
				if ($netmask < pow(2,32) ) $netmask = ~($netmask -1);
			} elseif (count($mask) <= 4) {
				$netmask = ($mask[0] << 24) + ($mask[1] << 16) + ($mask[2] << 8) + $mask[3];
			} else {
				die ("Error in netmask $nethost[1]");
			}
		} else {
			$netmask = pow(2,32) - 1;
		}

		if ($cmp_addr < 0 ) $cmp_addr += pow(2,32);

		if ("$ip_type" == "text") {
			$ret = "$inet_aton($ip) & $netmask = $cmp_addr & $netmask";
		} elseif ("{$config["db"]}" == "pgsql" and !db("exists", "SELECT ".pow(2,31)." & 100000", $db_data)) {
			$ret = "$ip::int8 & $netmask::int8 = $cmp_addr::int8 & $netmask::int8";
		} else {
			$ret = "$ip & $netmask = $cmp_addr & $netmask";
		}
	}

	return "$ret";
}

// Returns string representation of IP address from binary string
// Used with PHP < 5.1 which does not have an internal inet_ntop function
function wfwl_inet_ntop ($addr) {
	if (strlen($addr) <=4) {
		$len = 4;
		$fmt = "C1p1/C1p2/C1p3/C1p4";
		$delim = ".";
	} elseif (strlen($addr) <= 16) {
		$len = 16;
		$fmt = "H4p1/H4p2/H4p3/H4p4/H4p5/H4p6/H4p7/H4p8/";
		$delim = ":";
	} else
		return "";

	$unpacked = unpack("$fmt", str_pad($addr, $len));

	$ret = implode("$delim", $unpacked);

	return "$ret";
}

// Returns SQL casting expression based on database in use
// MySQL 3.23 does not support CAST, and does automatic type conversion
function cast ($value, $type) {
	global $config;
	if ($config["have_cast"]) {
		return "CAST($value AS $type)";
	} else {
		return "$value";
	}
}

function sortit ($target) {
// Update order of Sorting options
// $sortorder is set to presentation list of all possible columns

global $dsortorder, $sortorder; 

foreach ($sortorder as $k => $v) {
	unset ($sortorder["$k"]);
}

$tempset = array();

foreach ($dsortorder as $a) {
	if (isset($target["$a"])) {
		$tempset["$a"] = $target["$a"];
	}
}

asort($tempset);
$sortorder = array_keys($tempset);

foreach ($dsortorder as $a) {
	if (!isset($tempset["$a"])) {
		$sortorder[] = "$a";
	} 
}

foreach ($sortorder as $a => $b) {
	if (isset($target["$b"])) $target["$b"] = "$a" + 1;
}

unset ($tempset);

return $target;

}

function print_scrollbar($prefix,$currentstart,$total,$pagesize,$barsize)
{
	$currentpage = floor((($currentstart + $pagesize)/ $pagesize) - 1);

	# put the current listed page somewhere in the middle of the bar, so the start = bar / 2
	$startpage = $currentpage - floor($barsize/2);
	# if the start falls of the front, set it to 0
	if($startpage < 0)
	{
		$startpage = 0;
	}
	# bar should be $barsize long, or less
	$endpage = $startpage + ($barsize-1);
	# if there's not enough results, shorten the bar
	if(($endpage+1) * $pagesize > $total)
	{
		$endpage = floor((($total+$pagesize-1) / $pagesize) - 1);
	}
	# if there is only 1page of results...
	if($endpage < 0)
	{
		$endpage = 0;
	}

	print "\t<a href='$prefix"."0'>&lt;&lt;</a>\n";
	
	if($currentpage != 0)
	{
		$s = ($currentpage - 1) * $pagesize;
		print "\t<a href='$prefix$s'>&lt;</a>\n";
	}

	for($i = $startpage; $i <= $endpage; $i++)
	{
		$s = $i * $pagesize;
		print "\t<a href='$prefix$s'>";
		
		if($i == $currentpage)
		{
			print "<strong>[".($i+1)."]</strong>";
		}
		else
		{
			print ($i+1);
		}
		
		print "</a>\n";
	}

	if($currentstart + $pagesize < $total)
	{
		$s = ($currentpage + 1) * $pagesize;
		print "\t<a href='$prefix$s'>&gt;</a>\n";
	}

	$s = (floor(($total + $pagesize - 1) / $pagesize) - 1) * $pagesize;
	print "\t<a href='$prefix$s'>&gt;&gt;</a>\n";
}

// Removes escapes on a single variable or recursively on an array
function stripslashes_deep($value) {
	$value = is_array($value) ?
		array_map('stripslashes_deep', $value) :
		stripslashes($value);

	return $value;
}

// vim:set ts=4:

?>
