aboutsummaryrefslogtreecommitdiffstats
path: root/config/lightsquid
diff options
context:
space:
mode:
Diffstat (limited to 'config/lightsquid')
-rw-r--r--config/lightsquid/lightsquid.inc121
-rw-r--r--config/lightsquid/lightsquid.xml26
-rw-r--r--config/lightsquid/sqstat.class.php582
-rw-r--r--config/lightsquid/sqstat.css68
-rw-r--r--config/lightsquid/sqstat.php417
-rw-r--r--config/lightsquid/zhabascript.js118
6 files changed, 1280 insertions, 52 deletions
diff --git a/config/lightsquid/lightsquid.inc b/config/lightsquid/lightsquid.inc
index 5e16587a..5fd89470 100644
--- a/config/lightsquid/lightsquid.inc
+++ b/config/lightsquid/lightsquid.inc
@@ -33,7 +33,21 @@ require_once('pfsense-utils.inc');
require_once('pkg-utils.inc');
require_once('filter.inc');
require_once('service-utils.inc');
-require_once('squid.inc');
+
+if (file_exists('squid.inc')) {
+ require_once('squid.inc');
+}
+else update_log("File 'squid.inc' not found.");
+
+$pfs_version = substr(trim(file_get_contents("/etc/version")),0,3);
+switch ($pfs_version) {
+ case "1.2":
+ case "2.0":
+ define('LIGHTSQUID_BASE','/usr/local');
+ break;
+ default:
+ define('LIGHTSQUID_BASE', '/usr/pbi/lightsquid-' . php_uname("m"));
+}
define ('CMD_PKGDELETE', 'pkg_delete lightsquid-1.7.1');
@@ -42,19 +56,26 @@ define('LS_GUI_DEBUG', 'on');
define('LS_LOG_FILE', '/tmp/lightsquid_gui.log');
// configuration settings !-- CHECK THIS --!
-define('LS_CONFIGPATH', '/usr/local/etc/lightsquid');
+define('LS_CONFIGPATH', LIGHTSQUID_BASE . '/etc/lightsquid');
define('LS_CONFIGFILE', 'lightsquid.cfg');
define('LS_CONFIGFILE_DIST', 'lightsquid.cfg.dist');
-define('LS_WWWPATH', '/usr/local/www/lightsquid');
-define('LS_TEMPLATEPATH', '/usr/local/www/lightsquid/tpl');
-define('LS_LANGPATH', '/usr/local/share/lightsquid/lang');
+define('LS_WWWPATH', LIGHTSQUID_BASE . '/www/lightsquid');
+define('LS_TEMPLATEPATH', LIGHTSQUID_BASE . '/www/lightsquid/tpl');
+define('LS_LANGPATH', LIGHTSQUID_BASE . '/share/lightsquid/lang');
define('LS_REPORTPATH', '/var/lightsquid/report');
-define('LS_SQUIDLOGPATH', '/var/squid/log');
+
+global $config;
+if (isset($config['installedpackages']['squid']['config'][0])) {
+ if (!empty($config['installedpackages']['squid']['config'][0]['log_dir']))
+ define('LS_SQUIDLOGPATH', $config['installedpackages']['squid']['config'][0]['log_dir']);
+ else
+ define('LS_SQUIDLOGPATH', '/var/squid/logs');
+}
define('LS_SQUIDLOG', 'access.log');
-define('LS_IP2NAMEPATH', '/usr/local/libexec/lightsquid');
+define('LS_IP2NAMEPATH', LIGHTSQUID_BASE . '/libexec/lightsquid');
define('CRONTAB_FILE', '/var/cron/tabs/root');
-define('CRONTAB_LS_TEMPLATE', '/usr/bin/perl /usr/local/www/lightsquid/lightparser.pl');
+define('CRONTAB_LS_TEMPLATE', '/usr/bin/perl ' . LIGHTSQUID_BASE . '/www/lightsquid/lightparser.pl');
define('CRONTAB_LS_JOBKEY', '/lightparser.pl');
define('CRONTAB_SQUID_TEMPLATE', '/usr/local/sbin/squid -k rotate > /dev/null');
define('CRONTAB_SQUID_JOBKEY', '/squid -k rotate');
@@ -119,11 +140,6 @@ function lightsquid_deinstall() {
// delete cron task's
ls_setup_cron("lightsquid_squid_rotate", "", "", false);
ls_setup_cron("lightsquid_parser", "", "", false);
- // control shoot to head :)
-# mwexec(CMD_PKGDELETE);
- // remove '/usr/local/www/lightsquid' dir - any time can't be removed by templates
-# if (file_exists(LS_WWWPATH))
-# mwexec("rm -rf " . LS_WWWPATH);
update_log("lightsquid_deinstall: stopped");
}
@@ -143,7 +159,7 @@ function lightsquid_resync() {
mwexec("mkdir -p " . LS_REPORTPATH);
}
- mwexec("/bin/chmod -R u+w /usr/local/etc/lightsquid");
+ mwexec("/bin/chmod -R u+w " . LIGHTSQUID_BASE . "/etc/lightsquid");
// debug
$light_test = array();
@@ -213,10 +229,10 @@ function lightsquid_resync() {
foreach ($lsconf_var as $key => $val) {
for($i = 0; $i < count($lsconf); $i++) {
$s = trim($lsconf[$i]);
- $e_key = "^[$]" . $key . "[ ]*[=]+";
-# update_log("Regular: eregi(\"$e_key," . "'$s')"); // debug regular template
- if (eregi($e_key, $s)) {
-# update_log("Regular PASSED: eregi(\"$e_key," . "'$s')"); // debug regular template
+ $e_key = "/^[$]" . $key . "[ ]*[=]+/i";
+# update_log("Regular: preg_match(\"$e_key," . "'$s')"); // debug regular template
+ if (preg_match($e_key, $s)) {
+# update_log("Regular PASSED: preg_match(\"$e_key," . "'$s')"); // debug regular template
$lsconf[$i] = '$' . "$key = $val;";
update_log("Update config: $key=$val");
}
@@ -259,43 +275,35 @@ function lightsquid_resync() {
ls_setup_cron("lightsquid_parser_yesterday", "", "", false);
}
- // set shedule - squid rotate
-# if ($tm_squid) {
-# $on = false;
-# $opt = array("0", "0", "*", "*", "*", "root", CRONTAB_SQUID_TEMPLATE);
-# switch($tm_squid) {
-# // day of month
-# case 'lsr_none':$on = false; break;
-# case 'lsr_d1': $on = true; $opt[2]= "*/1"; break;
-# case 'lsr_d2': $on = true; $opt[2]= "*/2"; break;
-# case 'lsr_d3': $on = true; $opt[2]= "*/3"; break;
-# case 'lsr_d4': $on = true; $opt[2]= "*/4"; break;
-# case 'lsr_d5': $on = true; $opt[2]= "*/5"; break;
-# case 'lsr_d6': $on = true; $opt[2]= "*/6"; break;
-# case 'lsr_d10': $on = true; $opt[2]= "*/10"; break;
-# case 'lsr_d15': $on = true; $opt[2]= "*/15"; break;
-# case 'lsr_d20': $on = true; $opt[2]= "*/20"; break;
-# case 'lsr_d25': $on = true; $opt[2]= "*/25"; break;
-# case 'lsr_d30': $on = true; $opt[2]= "*/30"; break;
-# // day of week
-# case 'lsr_w1': $on = true; $opt[4]= "*/1"; break;
-# case 'lsr_w2': $on = true; $opt[4]= "*/1"; break;
-# case 'lsr_w3': $on = true; $opt[4]= "*/1"; break;
-# case 'lsr_w4': $on = true; $opt[4]= "*/1"; break;
-# case 'lsr_w5': $on = true; $opt[4]= "*/1"; break;
-# case 'lsr_w6': $on = true; $opt[4]= "*/1"; break;
-# case 'lsr_w7': $on = true; $opt[4]= "*/1"; break;
-# }
-# ls_setup_cron("lightsquid_squid_rotate", $opt, CRONTAB_SQUID_JOBKEY, $on);
-# } else
- ls_setup_cron("lightsquid_squid_rotate", "", "", false);
+ ls_setup_cron("lightsquid_squid_rotate", "", "", false);
// update squid conf
if (isset($config['installedpackages']['squid']['config'][0])) {
- $config['installedpackages']['squid']['config'][0]['log_enabled'] = 'on';
- $config['installedpackages']['squid']['config'][0]['log_dir'] = LS_SQUIDLOGPATH;
+ $squid_settings = $config['installedpackages']['squid']['config'][0];
+ $squid_settings['log_enabled'] = 'on';
+ if (empty($squid_settings['log_dir']))
+ $squid_settings['log_dir'] = LS_SQUIDLOGPATH;
+
+ # sqstat
+ $ifmgr = "127.0.0.1;";
+ $iface = ($squid_settings['active_interface'] ? $squid_settings['active_interface'] : 'lan');
+ $iface = explode(",", $iface);
+ foreach ($iface as $i => $if) {
+ $realif = ls_get_real_interface_address($if);
+ if ($realif[0])
+ $ifmgr = $ifmgr . $realif[0] . ";";
+ }
+
+ # ? delete ?
+ $config['installedpackages']['squidcache']['config'][0]['ext_cachemanager'] = $ifmgr;
+ # now right
+ $config['installedpackages']['squidnac']['config'][0]['ext_cachemanager'] = $ifmgr;
+
write_config();
- squid_resync();
+ if (function_exists('squid_resync')) {
+ squid_resync();
+ }
+ else update_log("Function 'squid_resync' not found.");
}
}
@@ -418,4 +426,15 @@ function refresh_full() {
update_log("refresh_full: stop");
}
+function ls_get_real_interface_address($iface)
+{
+ global $config;
+
+ $iface = convert_friendly_interface_to_real_interface_name($iface);
+ $line = trim(shell_exec("ifconfig $iface | grep inet | grep -v inet6"));
+ list($dummy, $ip, $dummy2, $netmask) = explode(" ", $line);
+
+ return array($ip, long2ip(hexdec($netmask)));
+}
+
?> \ No newline at end of file
diff --git a/config/lightsquid/lightsquid.xml b/config/lightsquid/lightsquid.xml
index cb481943..b8ce2bc8 100644
--- a/config/lightsquid/lightsquid.xml
+++ b/config/lightsquid/lightsquid.xml
@@ -47,7 +47,7 @@
<faq>Currently there are no FAQ items provided.</faq>
<name>lightsquid</name>
<version>1.7.1</version>
- <title>Services: Proxy server Report(LightSquid) -> Settings</title>
+ <title>Services: Proxy Reports (LightSquid, SQStat) -> Settings</title>
<category>Status</category>
<include_file>/usr/local/pkg/lightsquid.inc</include_file>
<menu>
@@ -66,6 +66,10 @@
<text>Lightsquid Report</text>
<url>/lightsquid/index.cgi</url>
</tab>
+ <tab>
+ <text>Proxy State</text>
+ <url>/sqstat/sqstat.php</url>
+ </tab>
</tabs>
<additional_files_needed>
<prefix>/usr/local/pkg/</prefix>
@@ -77,6 +81,26 @@
<chmod>0755</chmod>
<item>http://files.pfsense.org/packages/All/lightsquid_tpl.tbz</item>
</additional_files_needed>
+ <additional_files_needed>
+ <prefix>/usr/local/www/sqstat/</prefix>
+ <chmod>0644</chmod>
+ <item>http://www.pfsense.org/packages/config/lightsquid/sqstat.class.php</item>
+ </additional_files_needed>
+ <additional_files_needed>
+ <prefix>/usr/local/www/sqstat/</prefix>
+ <chmod>0644</chmod>
+ <item>http://www.pfsense.org/packages/config/lightsquid/sqstat.php</item>
+ </additional_files_needed>
+ <additional_files_needed>
+ <prefix>/usr/local/www/sqstat/</prefix>
+ <chmod>0644</chmod>
+ <item>http://www.pfsense.org/packages/config/lightsquid/sqstat.css</item>
+ </additional_files_needed>
+ <additional_files_needed>
+ <prefix>/usr/local/www/sqstat/</prefix>
+ <chmod>0644</chmod>
+ <item>http://www.pfsense.org/packages/config/lightsquid/zhabascript.js</item>
+ </additional_files_needed>
<fields>
<field>
<fielddescr>Language</fielddescr>
diff --git a/config/lightsquid/sqstat.class.php b/config/lightsquid/sqstat.class.php
new file mode 100644
index 00000000..228aecfe
--- /dev/null
+++ b/config/lightsquid/sqstat.class.php
@@ -0,0 +1,582 @@
+<?php
+/* $Id$ */
+/*
+ sqstat.class.php
+ Squid Proxy Server realtime stat
+
+ (c) Alex Samorukov, samm@os2.kiev.ua
+ modification by 2011 Serg Dvoriancev, dv_serg@mail.ru
+ Squid Proxy Server realtime stat
+
+ part of pfSense (www.pfSense.com)
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+*/
+
+// sqstat class
+DEFINE('SQSTAT_VERSION', '1.20');
+DEFINE('SQSTAT_SHOWLEN', 60);
+
+class squidstat{
+ var $fp;
+
+ # conection
+ var $squidhost;
+ var $squidport;
+
+ # hosts
+ var $hosts_file;
+ var $hosts;
+
+ # versions
+ var $server_version;
+ var $sqstat_version;
+
+ # other
+ var $group_by;
+ var $resolveip;
+ var $autorefresh;
+ var $use_sessions = false;
+
+ # cache manager
+ var $cachemgr_passwd;
+
+ # errors
+ var $errno;
+ var $errstr;
+
+ function squidstat(){
+ $this->sqstat_version = SQSTAT_VERSION;
+
+ $this->squidhost = '127.0.0.1';
+ $this->squidport = '3128';
+
+ $This->group_by = 'host';
+ $this->resolveip = true;
+ $this->hosts_file = '';
+ $this->autorefresh = 0;
+ $this->cachemgr_passwd = '';
+
+ $errno = 0;
+ $errstr = '';
+
+ if (!function_exists("preg_match")) { $this->errorMsg(5, 'You need to install <a href="http://www.php.net/pcre/" target="_blank">PHP pcre extension</a> to run this script');
+ $this->showError();
+ exit(5);
+ }
+
+ // we need session support to gather avg. speed
+ if (function_exists("session_start")){
+ $this->use_sessions=true;
+ }
+
+ }
+
+ function formatXHTML($body, $refresh, $use_js = false){
+ $text='<?xml version="1.0" encoding="UTF-8"?>'."\n".
+ '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">'."\n"
+ .'<html>'
+ .'<head>'
+ .'<link href="sqstat.css" rel="stylesheet" type="text/css"/>';
+ if($refresh) $text.='<META HTTP-EQUIV=Refresh CONTENT="'.$refresh.'; URL='.$_SERVER["PHP_SELF"].'?refresh='.$refresh.'&config='.$GLOBALS["config"].'"/>';
+ $text.='<title>SqStat '.SQSTAT_VERSION.'</title>'
+ .($use_js?'<script src="zhabascript.js" type="text/javascript"></script>':'').'</head>'
+ .($use_js?'<body onload="jsInit();"><div id="dhtmltooltip"></div><img id="dhtmlpointer" src="arrow.gif">':'<body>')
+ .$body.'</body></html>';
+ return $text;
+ }
+
+ function showError(){
+ $text='<h1>SqStat error</h1>'.
+ '<h2 style="color:red">Error ('.$this->errno.'): '.$this->errstr.'</span>';
+ echo $this->formatXHTML($text,0);
+ }
+
+ function connect($squidhost, $squidport){
+ $this->fp = false;
+ # connecting to the squidhost
+ $this->fp = @fsockopen($squidhost, $squidport, $this->errno, $this->errstr, 10);
+ if (!$this->fp) {
+ # failed to connect
+ return false;
+ }
+ return true;
+ }
+
+ # based @ (c) moritz at barafranca dot com
+ function duration ($seconds) {
+ $takes_time = array(604800,86400,3600,60,0);
+ $suffixes = array("w","d","h","m","s");
+ $output = "";
+ foreach ($takes_time as $key=>$val) {
+ ${$suffixes[$key]} = ($val == 0) ? $seconds : floor(($seconds/$val));
+ $seconds -= ${$suffixes[$key]} * $val;
+ if (${$suffixes[$key]} > 0) {
+ $output .= ${$suffixes[$key]};
+ $output .= $suffixes[$key]." ";
+ }
+ }
+ return trim($output);
+ }
+
+ /**
+ * Format a number of bytes into a human readable format.
+ * Optionally choose the output format and/or force a particular unit
+ *
+ * @param int $bytes The number of bytes to format. Must be positive
+ * @param string $format Optional. The output format for the string
+ * @param string $force Optional. Force a certain unit. B|KB|MB|GB|TB
+ * @return string The formatted file size
+ */
+ function filesize_format($bytes, $format = '', $force = '')
+ {
+ $force = strtoupper($force);
+ $defaultFormat = '%01d %s';
+ if (strlen($format) == 0)
+ $format = $defaultFormat;
+ $bytes = max(0, (int) $bytes);
+ $units = array('b', 'Kb', 'Mb', 'Gb', 'Tb', 'Pb');
+ $power = array_search($force, $units);
+ if ($power === false)
+ $power = $bytes > 0 ? floor(log($bytes)/log(1024)) : 0;
+ return sprintf($format, $bytes / pow(1024, $power), $units[$power]);
+ }
+
+ function makeQuery($pass = ""){
+ $raw = array();
+ # sending request
+ if(!$this->fp)
+ die("Please connect to server");
+
+ $out = "GET cache_object://localhost/active_requests HTTP/1.0\r\n";
+ if ($pass != "")
+ $out .= "Authorization: Basic ".base64_encode("cachemgr:$pass")."\r\n";
+ $out .= "\r\n";
+
+ fwrite($this->fp, $out);
+
+ while (!feof($this->fp)) {
+ $raw[] = trim(fgets($this->fp, 2048));
+ }
+ fclose($this->fp);
+
+ if ($raw[0]!="HTTP/1.0 200 OK") { $this->errorMsg(1, "Cannot get data. Server answered: $raw[0]");
+ return false;
+ }
+
+ # parsing output;
+ $header = 1;
+ $connection = 0;
+ $parsed["server_version"] = "Unknown";
+ foreach($raw as $key=>$v){
+ # cutoff http header
+ if ($header==1 && $v=="") $header=0;
+ if ($header) {
+ if(substr(strtolower($v),0,7) == "server:") { # parsing server version
+ $parsed["server_version"] = substr($v,8);
+ }
+ }
+ else {
+ if(substr($v,0,11) == "Connection:") { # parsing connection
+ $connection = substr($v,12);
+ }
+ if ($connection) {
+ # username field is avaible in Squid 2.6 stable
+ if(substr($v,0,9) == "username ") $parsed["con"][$connection]["username"] = substr($v, 9);
+ if(substr($v,0,5) == "peer:") $parsed["con"][$connection]["peer"] = substr($v, 6);
+ if(substr($v,0,3) == "me:") $parsed["con"][$connection]["me"] = substr($v, 4);
+ if(substr($v,0,4) == "uri ") $parsed["con"][$connection]["uri"] = substr($v, 4);
+ if(substr($v,0,10) == "delay_pool") $parsed["con"][$connection]["delay_pool"] = substr($v, 11);
+
+ if (preg_match('/out.offset \d+, out.size (\d+)/', $v, $matches)) {
+ $parsed["con"][$connection]["bytes"] = $matches[1];
+ }
+ if (preg_match('/start \d+\.\d+ \((\d+).\d+ seconds ago\)/', $v, $matches)){
+ $parsed["con"][$connection]["seconds"] = $matches[1];
+ }
+ }
+ }
+ }
+ return $parsed;
+ }
+
+ function implode_with_keys($array, $glue) {
+ foreach ($array as $key => $v){
+ $ret[] = $key . '=' . htmlspecialchars($v);
+ }
+ return implode($glue, $ret);
+ }
+
+ function makeHtmlReport($data, $resolveip = false, $hosts_array = array(), $use_js = true) {
+ global $group_by;
+ if($this->use_sessions){
+ session_name('SQDATA');
+ session_start();
+ }
+
+ $total_avg = $total_curr = 0;
+ // resort data array
+ $users=array();
+ switch($group_by){
+ case "host":
+ $group_by_name="Host";
+ $group_by_key='return $ip;';
+ break;
+ case "username":
+ $group_by_name="User";
+ $group_by_key='return $v["username"];';
+ break;
+ default:
+ die("wrong group_by!");
+ }
+
+ foreach($data["con"] as $key => $v){
+ if(substr($v["uri"],0,13)=="cache_object:") continue; // skip myself
+ $ip=substr($v["peer"],0,strpos($v["peer"],":"));
+ if(isset($hosts_array[$ip])){
+ $ip=$hosts_array[$ip];
+ }
+ // i use ip2long() to make ip sorting work correctly
+ elseif($resolveip){
+ $hostname=gethostbyaddr($ip);
+ if($hostname==$ip) $ip=ip2long($ip);// resolve failed
+ else $ip=$hostname;
+ }
+ else{
+ $ip=ip2long(substr($v["peer"],0,strpos($v["peer"],":")));
+ }
+ $v['connection'] = $key;
+ if(!isset($v["username"])) $v["username"]="N/A";
+ $users[eval($group_by_key)][]=$v;
+ }
+ ksort($users);
+ $refresh=0;
+ if(isset($_GET["refresh"]) && !isset($_GET["stop"])) $refresh=(int)$_GET["refresh"];
+ $text='';
+ if(count($GLOBALS["configs"])==1) $servers=$GLOBALS["squidhost"].':'.$GLOBALS["squidport"];
+ else{
+ $servers='<select onchange="this.form.submit();" name="config">';
+ foreach ($GLOBALS["configs"] as $key=>$v){
+ $servers.='<option '.($GLOBALS["config"]==$key?' selected="selected" ':'').' value="'.$key.'">'.htmlspecialchars($v).'</option>';
+ }
+ $servers.='</select>';
+ }
+ $text.='<div class="header"><form method="get" action="'.$_SERVER["PHP_SELF"].'">'.
+ 'Squid RealTime stat for the '.$servers.' proxy server ('.$data["server_version"].').<br/>'.
+ 'Auto refresh: <input name="refresh" type="text" size="4" value="'.$refresh.'"/> sec. <input type="submit" value="Update"/> <input name="stop" type="submit" value="Stop"/> Created at: <tt>'.date("h:i:s d/m/Y").'</tt><br/>'.
+ '</div>'.
+ '<table class="result" align="center" width="100%" border="0">'.
+ '<tr>'.
+ '<th>'.$group_by_name.'</th><th>URI</th>'.
+ ($this->use_sessions?'<th>Curr. Speed</th><th>Avg. Speed</th>':'').
+ '<th>Size</th><th>Time</th>'.
+ '</tr>';
+ $ausers=$acon=0;
+ unset($session_data);
+ if (isset($_SESSION['time']) && ((time() - $_SESSION['time']) < 3*60) && isset($_SESSION['sqdata']) && is_array($_SESSION['sqdata'])) {
+ //only if the latest data was less than 3 minutes ago
+ $session_data = $_SESSION['sqdata'];
+ }
+ $table='';
+ foreach($users as $key=>$v){
+ $ausers++;
+ $table.='<tr><td style="border-right:0;" colspan="2"><b>'.(is_int($key)?long2ip($key):$key).'</b></td>'.
+ '<td style="border-left:0;" colspan="5">&nbsp;</td></tr>';
+ $user_avg = $user_curr = $con_color = 0;
+ foreach ($v as $con){
+ if(substr($con["uri"],0,7)=="http://" || substr($con["uri"],0,6)=="ftp://"){
+ if(strlen($con["uri"])>SQSTAT_SHOWLEN) $uritext=htmlspecialchars(substr($con["uri"],0,SQSTAT_SHOWLEN)).'</a> ....';
+ else $uritext=htmlspecialchars($con["uri"]).'</a>';
+ $uri='<a target="_blank" href="'.htmlspecialchars($con["uri"]).'">'.$uritext;
+ }
+ else $uri=htmlspecialchars($con["uri"]);
+ $acon++;
+ //speed stuff
+ $con_id = $con['connection'];
+ $is_time = time();
+ $curr_speed=0;
+ $avg_speed=0;
+ if (isset($session_data[$con_id]) && $con_data = $session_data[$con_id] ) {
+ // if we have info about current connection, we do analyze its data
+ // current speed
+ $was_time = $con_data['time'];
+ $was_size = $con_data['size'];
+ if ($was_time && $was_size) {
+ $delta = $is_time - $was_time;
+ if ($delta == 0) {
+ $delta = 1;
+ }
+ if ($con['bytes'] >= $was_size) {
+ $curr_speed = ($con['bytes'] - $was_size) / 1024 / $delta;
+ }
+ } else {
+ $curr_speed = $con['bytes'] / 1024;
+ }
+
+ //avg speed
+ $avg_speed = $con['bytes'] / 1024;
+ if ($con['seconds'] > 0) {
+ $avg_speed /= $con['seconds'];
+ }
+ }
+
+ $new_data[$con_id]['time'] = $is_time;
+ $new_data[$con_id]['size'] = $con['bytes'];
+
+ //sum speeds
+ $total_avg += $avg_speed;
+ $user_avg += $avg_speed;
+ $total_curr += $curr_speed;
+ $user_curr += $curr_speed;
+
+ if($use_js) $js='onMouseout="hideddrivetip()" onMouseover="ddrivetip(\''.$this->implode_with_keys($con,'<br/>').'\')"';
+ else $js='';
+ $table.='<tr'.( (++$con_color % 2 == 0) ? ' class="odd"' : '' ).'><td id="white"></td>'.
+ '<td nowrap '.$js.' width="80%" >'.$uri.'</td>';
+ if($this->use_sessions){
+ $table .= '<td nowrap align="right">'.( (round($curr_speed, 2) > 0) ? sprintf("%01.2f KB/s", $curr_speed) : '' ).'</td>'.
+ '<td nowrap align="right">'.( (round($avg_speed, 2) > 0) ? sprintf("%01.2f KB/s", $avg_speed) : '' ). '</td>';
+ }
+ $table .= '<td nowrap align="right">'.$this->filesize_format($con["bytes"]).'</td>'.
+ '<td nowrap align="right">'.$this->duration($con["seconds"],"short").'</td>'.
+ '</tr>';
+ }
+ if($this->use_sessions){
+ $table.=sprintf("<tr><td colspan=\"2\"></td><td align=\"right\" id=\"highlight\">%01.2f KB/s</td><td align=\"right\" id=\"highlight\">%01.2f KB/s</td><td colspan=\"2\"></td>",
+ $user_curr, $user_avg);
+ }
+
+ }
+ $_SESSION['time'] = time();
+ if(isset($new_data)) $_SESSION['sqdata'] = $new_data;
+ $stat_row='';
+ if($this->use_sessions){
+ $stat_row.=sprintf("<tr class=\"total\"><td><b>Total:</b></td><td align=\"right\" colspan=\"5\"><b>%d</b> users and <b>%d</b> connections @ <b>%01.2f/%01.2f</b> KB/s (CURR/AVG)</td></tr>",
+ $ausers, $acon, $total_curr, $total_avg);
+ }
+ else {
+ $stat_row.=sprintf("<tr class=\"total\"><td><b>Total:</b></td><td align=\"right\" colspan=\"5\"><b>%d</b> users and <b>%d</b> connections</td></tr>",
+ $ausers, $acon);
+ }
+ if($ausers==0){
+ $text.='<tr><td colspan=6><b>No active connections</b></td></tr>';
+ }
+ else {
+ $text.=$stat_row.$table.$stat_row;
+ }
+ $text .= '</table>'.
+ '<p class="copyleft">&copy; <a href="mailto:samm@os2.kiev.ua?subject=SqStat '.SQSTAT_VERSION.'">Alex Samorukov</a>, 2006</p>';
+ return $this->formatXHTML($text,$refresh,$use_js);
+ }
+
+ function parseRequest($data, $group_by = 'host', $resolveip = false) { $parsed = array();
+ if ($this->use_sessions) {
+ session_name('SQDATA');
+ session_start();
+ }
+
+ # resort data array
+ $users = array();
+ switch ($group_by) {
+ case "username":
+ $group_by_name = "User";
+ $group_by_key = "username";
+ break;
+ case "host":
+ default:
+ $group_by_name = "Host";
+ $group_by_key = "peer";
+ break;
+ }
+
+ # resolve IP & group
+ foreach ($data["con"] as $key => $v) { # skip myself
+ if (substr($v["uri"], 0, 13) == "cache_object:") continue;
+
+ $ip = substr($v["peer"], 0, strpos($v["peer"], ":"));
+ $v["peer"] = $ip;
+
+ # name from hosts
+ if (isset($this->hosts[$ip])) {
+ $ip = $this->hosts[$ip];
+ }
+ else
+ # i use ip2long() to make ip sorting work correctly
+ if ($resolveip) {
+ $hostname = gethostbyaddr($ip);
+ if ($hostname == $ip)
+ $ip = ip2long($ip); # resolve failed. use (ip2long) key
+ else $ip = $hostname;
+ }
+ else {
+ $ip = ip2long(substr($v["peer"], 0, strpos($v["peer"], ":")));
+ }
+ $v['con_id'] = $key;
+ $v["username"] = isset($v["username"]) ? $v["username"] : "N/A";
+
+ # users [key => conn_array]
+ $users[$v[$group_by_key]][] = $v;
+ }
+ ksort($users);
+
+ unset($session_data);
+ if (isset($_SESSION['time']) && ((time() - $_SESSION['time']) < 3*60) &&
+ isset($_SESSION['sqdata']) && is_array($_SESSION['sqdata'])) {
+ # only if the latest data was less than 3 minutes ago
+ $session_data = $_SESSION['sqdata'];
+ }
+
+ # users count & con cont
+ $ausers = $acon = 0;
+ $total_avg = $total_curr = 0;
+ foreach ($users as $key => $v) { $ausers++;
+
+ $user_avg = $user_curr = $con_color = 0;
+ foreach ($v as $con_key => $con){ $cres = array();
+ $acon++;
+
+ $uritext = $con["uri"];
+ if (substr($con["uri"], 0, 7) == "http://" || substr($con["uri"], 0, 6) == "ftp://") {
+ if (strlen($uritext) > SQSTAT_SHOWLEN)
+ $uritext = htmlspecialchars(substr($uritext, 0, SQSTAT_SHOWLEN)) . ' ....';
+ }
+ else $uritext = htmlspecialchars($uritext);
+ $cres['uritext'] = $uritext;
+ $cres['uri'] = $con["uri"];
+
+ # speed stuff
+ $con_id = $con['connection'];
+ $is_time = time();
+ $curr_speed = $avg_speed = 0;
+ if (isset($session_data[$con_id]) && $con_data = $session_data[$con_id] ) {
+ # if we have info about current connection, we do analyze its data
+ # current speed
+ $was_time = $con_data['time'];
+ $was_size = $con_data['size'];
+ if ($was_time && $was_size) {
+ $delta = $is_time - $was_time;
+ if ($delta == 0) {
+ $delta = 1;
+ }
+ if ($con['bytes'] >= $was_size) {
+ $curr_speed = ($con['bytes'] - $was_size) / 1024 / $delta;
+ }
+ } else {
+ $curr_speed = $con['bytes'] / 1024;
+ }
+
+ # avg speed
+ $avg_speed = $con['bytes'] / 1024;
+ if ($con['seconds'] > 0) {
+ $avg_speed /= $con['seconds'];
+ }
+ }
+ $cres['cur_speed'] = $curr_speed;
+ $cres['avg_speed'] = $avg_speed;
+ $cres['seconds'] = $con["seconds"];
+ $cres['bytes'] = $con["bytes"];
+
+ # groupped parsed[key => conn_key]
+ $parsed['users'][$key]['con'][$con_key] = $cres;
+
+ # for sessions
+ $new_data[$con_id]['time'] = $is_time;
+ $new_data[$con_id]['size'] = $con['bytes'];
+
+ # sum speeds
+ $total_avg += $avg_speed;
+ $user_avg += $avg_speed;
+ $total_curr += $curr_speed;
+ $user_curr += $curr_speed;
+ }
+
+ # total per user
+ $parsed['users'][$key]['user_curr'] = $user_curr;
+ $parsed['users'][$key]['user_avg'] = $user_avg;
+ }
+
+ # total info
+ $parsed['ausers'] = $ausers;
+ $parsed['acon'] = $acon;
+ $parsed['total_avg'] = $total_avg;
+ $parsed['total_curr'] = $total_curr;
+
+ # update session info
+ $_SESSION['time'] = time();
+ if (isset($new_data)) $_SESSION['sqdata'] = $new_data;
+
+ return $parsed;
+ }
+
+ function errorMsg($errno, $errstr)
+ { $this->errno = $errno;
+ $this->errstr = $errstr;
+ }
+
+ function load_hosts()
+ {
+ # loading hosts file
+ $hosts_array = array();
+
+ if (!empty($this->hosts_file)) {
+ if (is_file($this->hosts_file)) {
+ $handle = @fopen($this->hosts_file, "r");
+ if ($handle) {
+ while (!feof($handle)) {
+ $buffer = fgets($handle, 4096);
+ unset($matches);
+ if (preg_match('/^([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})[ \t]+(.+)$/i', $buffer, $matches)) {
+ $hosts_array[$matches[1]]=$matches[2];
+ }
+ }
+ fclose($handle);
+ }
+ $this->hosts = $hosts_array;
+ }
+ else {
+ #error
+ $this->errorMsg(4, "Hosts file not found. Cant read <tt>'{$this->hosts_file}'</tt>.");
+ return $this->errno;
+ }
+ }
+
+ return 0;
+ }
+
+ function query_exec()
+ {
+ $data = "";
+
+ $this->server_version = '(unknown)';
+ if ($this->connect($this->squidhost, $this->squidport)) {
+ $data = $this->makeQuery($this->cachemgr_passwd);
+ if ($this->errno == 0) {
+ $this->server_version = $data['server_version'];
+ $data = $this->parseRequest($data, 'host', true);
+ }
+ }
+
+ return $data;
+ }
+
+}
+?> \ No newline at end of file
diff --git a/config/lightsquid/sqstat.css b/config/lightsquid/sqstat.css
new file mode 100644
index 00000000..7575933e
--- /dev/null
+++ b/config/lightsquid/sqstat.css
@@ -0,0 +1,68 @@
+/* "connections" table */
+TABLE.result{
+ border:1px solid #ccccdd;border-collapse:collapse;
+}
+TABLE.result TH{
+ font-family: Verdana;font-size:14px;
+}
+TABLE.result TD{
+ font-family: Verdana;font-size:11px;border:1px solid #c0c0c0;padding:2px;
+}
+TABLE.result TR.total TD{
+ background-color:#DCDAD5;
+}
+
+TABLE.result TH{
+ background-color:#ccccdd;
+ white-space: nowrap; padding: 0px 2px;
+}
+
+TABLE.result tr.odd td {
+ background-color: #eef;
+}
+TABLE.result tr.odd td#white {
+ background-color: #fff;
+}
+TABLE.result td#highlight {
+ background-color: #e9e9e9;
+}
+
+
+/* top header */
+DIV.header{
+ border:3px solid #ccccdd;margin-bottom:10px;padding:3px;
+ font-family: Verdana;font-size:12pt;
+}
+.copyleft,SELECT{
+ font-family: Verdana;font-size:10px;
+}
+.copyleft A{
+ text-decoration:none
+}
+.copyleft A:HOVER{
+ text-decoration:underline
+}
+FORM{
+ margin:0;padding:0;
+}
+
+#dhtmltooltip{
+ position: absolute;
+ /* width: 350px; */
+ border: 2px solid black;
+ padding: 2px;
+ background-color: lightyellow;
+ visibility: hidden;
+ z-index: 100;
+ font-family: Verdana; font-size: 10px;
+}
+
+
+#dhtmlpointer{
+ position:absolute;
+ left: -300px;
+ z-index: 101;
+ visibility: hidden;
+}
+
+
diff --git a/config/lightsquid/sqstat.php b/config/lightsquid/sqstat.php
new file mode 100644
index 00000000..a56b604a
--- /dev/null
+++ b/config/lightsquid/sqstat.php
@@ -0,0 +1,417 @@
+<?php
+/* $Id$ */
+/*
+ sqstat.php
+ Squid Proxy Server realtime stat
+
+ (c) Alex Samorukov, samm@os2.kiev.ua
+ modification by 2011 Serg Dvoriancev, dv_serg@mail.ru
+
+ part of pfSense (www.pfSense.com)
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+*** sqstat - Squid Proxy Server realtime stat ***
+(c) Alex Samorukov, samm@os2.kiev.ua
+*/
+
+require_once('guiconfig.inc');
+require_once('sqstat.class.php');
+
+# init
+$squidclass = new squidstat();
+
+# ------------------------------------------------------------------------------
+# Requests
+# ------------------------------------------------------------------------------
+
+# AJAX responce
+if ($_REQUEST['getactivity'])
+{
+ header("Content-type: text/javascript");
+ echo sqstat_AJAX_response( $_REQUEST );
+ exit;
+}
+
+# ------------------------------------------------------------------------------
+# HTML Page
+# ------------------------------------------------------------------------------
+
+$pgtitle = "Proxy Squid: Realtime stat (sqstat)";
+
+require_once("head.inc");
+
+?>
+
+<link href="sqstat.css" rel="stylesheet" type="text/css"/>
+<script type="text/javascript" src="/javascript/scriptaculous/prototype.js"></script>
+<script type="text/javascript" src="zhabascript.js"></script>
+
+<!-- Ajax Script -->
+<script type="text/javascript">
+
+var intervalID = 0;
+
+function el(id) {
+ return document.getElementById(id);
+}
+
+function getactivity(action) {
+ var url = "<?php echo ($_SERVER["PHP_SELF"]); ?>";
+ var pars = "getactivity=yes";
+
+ var myAjax = new Ajax.Request( url,
+ {
+ method: 'post',
+ parameters: pars,
+ onComplete: activitycallback
+ });
+}
+
+function activitycallback(transport) {
+
+ if (200 == transport.status) {
+ result = transport.responseText;
+ }
+}
+
+function update_start() {
+ var cmax = parseInt(el('refresh').value);
+
+ update_stop();
+
+ if (cmax > 0) {
+ intervalID = window.setInterval('getactivity();', cmax * 1000);
+ }
+}
+
+function update_stop() {
+ window.clearInterval(intervalID);
+ intervalID = 0;
+}
+
+// pre-call
+window.setTimeout('update_start()', 150);
+
+</script>
+
+<!-- HTML -->
+
+<!-- begin -->
+<body link="#0000CC" vlink="#0000CC" alink="#0000CC">
+<?php include("fbegin.inc"); ?>
+
+<?php
+ # prepare page data
+ $data = '';
+ sqstat_loadconfig();
+ if (sqstat_loadconfig() == 0) {
+ $data = $squidclass->query_exec();
+ }
+
+ if ($squidclass->errno == 0) {
+ $data = sqstat_resultHTML($data);
+ }
+ else {
+ # error
+ $data = sqstat_errorHTML();
+ }
+?>
+
+<!-- form -->
+<div id="sqstat_header" class="header" >
+ <?php echo ( sqstat_headerHTML() ); ?>
+</div>
+
+<!-- result table -->
+<div id="sqstat_result" class="result">
+ <?php echo ($data); ?>
+</div>
+
+<!-- end -->
+<?php include("fend.inc"); ?>
+</body>
+</html>
+
+<?php
+
+# ------------------------------------------------------------------------------
+# Functions
+# ------------------------------------------------------------------------------
+
+function sqstat_AJAX_response( $request )
+{
+ global $squidclass, $data;
+ $res = '';
+
+ if (sqstat_loadconfig() != 0) {
+ return sqstat_AJAX_error(sqstat_errorHTML());
+ }
+
+ # Actions
+ $data = $squidclass->query_exec();
+
+ $ver = sqstat_serverInfoHTML();
+ $res .= "el('sqstat_serverver').innerHTML = '$ver';";
+
+ $time = date("h:i:s d/m/Y");
+ $res .= "el('sqstat_updtime').innerHTML = '$time';";
+
+ $data = sqstat_resultHTML( $data );
+ if ($squidclass->errno == 0) {
+ $data = sqstat_AJAX_prep($data);
+ $res .= "el('sqstat_result').innerHTML = '$data';";
+ }
+ else {
+ # error
+ $res .= sqstat_AJAX_error(sqstat_errorHTML());
+ }
+
+ return $res;
+}
+
+function sqstat_AJAX_prep($text)
+{
+ $text = str_replace("'", "\'", $text);
+ $text = str_replace("\n", "\\r\\n", $text);
+ return $text;
+}
+
+function sqstat_AJAX_error($err)
+{
+ $err = sqstat_AJAX_prep($err);
+ $t .= "el('sqstat_result').innerHTML = '$err';";
+ return $t;
+}
+
+# ------------------------------------------------------------------------------
+# Reports
+# ------------------------------------------------------------------------------
+
+function sqstat_headerHTML()
+{
+ global $squidclass;
+
+ $date = date("h:i:s d/m/Y");
+ $squidinfo = sqstat_serverInfoHTML();
+
+ if (empty($squidclass->autorefresh)) $squidclass->autorefresh = 0;
+
+ return
+<<<EOD
+ <form method="get" action="{$_SERVER["PHP_SELF"]}">
+ <input id="counter" name="counter" type="hidden" value=0/>
+ Squid RealTime stat {$squidclass->sqstat_version} for the {$servers} proxy server <a id='sqstat_serverver'>{$squidinfo}</a>.<br/>
+ Auto refresh:
+ <input id="refresh" name="refresh" type="text" size="4" value="{$squidclass->autorefresh}"/> sec.
+ <input type="button" value="Update" onclick="update_start();"/>
+ <input type="button" value="Stop" onclick="update_stop();"/> Created at: <tt id='sqstat_updtime'>{$date}</tt><br/>
+ </form>
+EOD;
+}
+
+function sqstat_serverInfoHTML()
+{
+ global $squidclass;
+ return $squidclass->server_version . " ({$squidclass->squidhost}:{$squidclass->squidport})";
+}
+
+function sqstat_resultHTML($data)
+{
+ global $squidclass;
+
+ $group_by_name = $squidclass->group_by_name;
+ $use_js = true;
+
+ $t = array();
+
+ # table header
+ $t[] = "<table class='result' align='center' width='100%' border='0'>";
+ $t[] = "<tr>";
+ $t[] = "<th>{$group_by_name}</th><th>URI</th>";
+ if ($squidclass->use_sessions)
+ $t[] = "<th>Curr. Speed</th><th>Avg. Speed</th>";
+ $t[] = "<th>Size</th><th>Time</th>";
+ $t[] = "</tr>";
+
+ # table body
+ if (is_array($data['users'])) {
+ $tbl = array();
+
+ $con_color = 0;
+ foreach($data['users'] as $key => $v) {
+ # skeep total info
+ if ($key == 'total') continue;
+ # group row
+ $tbl[] = "<tr>";
+ $tbl[] = "<td style='border-right:0;' colspan='2'><b>" . (is_int($key) ? long2ip($key) : $key) . "</b></td>";
+ $tbl[] = "<td style='border-left:0;' colspan='5'>&nbsp;</td>";
+ $tbl[] = "</tr>";
+
+ # connections row
+ foreach ($v['con'] as $con) {
+ if ($use_js)
+ $js = "onMouseout='hideddrivetip()' onMouseover='ddrivetip(\"" . $squidclass->implode_with_keys($con,"<br/>") . "\")'";
+ else $js='';
+
+ # begin new row
+ $class = (++$con_color % 2 == 0) ? " class='odd'" : "";
+ $tbl[] = "<tr ($class)>";
+
+ # URL
+ $uri = "<a target='_blank' href='" . htmlspecialchars($con["uri"]) ."'>{$con['uritext']}</a>";
+ $tbl[] = "<td id='white'></td>";
+ $tbl[] = "<td nowrap {$js} width='80%'>{$uri}</td>";
+
+ # speed
+ if ($squidclass->use_sessions) {
+ $cur_s = round($con['cur_speed'], 2) > 0 ? sprintf("%01.2f KB/s", $con['cur_speed']) : '';
+ $avg_s = round($con['avg_speed'], 2) > 0 ? sprintf("%01.2f KB/s", $con['avg_speed']) : '';
+ $tbl[] = "<td nowrap align='right'>{$cur_s}</td>";
+ $tbl[] = "<td nowrap align='right'>{$avg_s}</td>";
+ }
+
+ # file size
+ $filesize = $squidclass->filesize_format($con["bytes"]);
+ $duration = $squidclass->duration($con["seconds"], "short");
+ $tbl[] = "<td nowrap align='right'>{$filesize}</td>";
+ $tbl[] = "<td nowrap align='right'>{$duration}</td>";
+
+ # end row
+ $tbl[] = "</tr>";
+ }
+
+ # total user speed
+ if ($squidclass->use_sessions) {
+ $user_curr = sprintf("%01.2f KB/s", $v['user_curr']);
+ $user_avg = sprintf("%01.2f KB/s", $v['user_avg']);
+ $tbl[] ="<tr>";
+ $tbl[] ="<td colspan='2'></td>";
+ $tbl[] ="<td align='right' id='highlight'>{$user_curr}</td>";
+ $tbl[] ="<td align='right' id='highlight'>{$user_avg}</td>";
+ $tbl[] ="<td colspan='2'></td>";
+ }
+ }
+
+
+ # status row
+ $stat = array();
+ $ausers = sprintf("%d", $data['ausers']);
+ $acon = sprintf("%d", $data['acon']);
+ $stat[] = "<tr class='total'><td><b>Total:</b></td>";
+ if ($squidclass->use_sessions) {
+ $total_curr = sprintf("%01.2f", $data['total_curr']);
+ $total_avg = sprintf("%01.2f", $data['total_avg']);
+ $stat[] = "<td align='right' colspan='5'><b>{$ausers}</b> users and <b>{$acon}</b> connections @ <b>{$total_curr}/{$total_avg}</b> KB/s (CURR/AVG)</td>";
+ }
+ else {
+ $stat[] = "<td align='right' colspan='5'><b>{$ausers}</b> users and <b>{$acon}</b> connections</td>";
+ }
+ $t[] = "</tr>";
+ }
+
+ if ($ausers == 0) {
+ $t[] = "<tr><td colspan=6><b>No active connections</b></td></tr>";
+ }
+ else {
+ $stat = implode("\n", $stat);
+ $tbl = implode("\n", $tbl);
+ $t[] = $stat . $tbl . $stat;
+ }
+
+ $t[] = "</table>";
+ $t[] = "<p class='copyleft'>Report based on SQStat &copy; <a href='mailto:samm@os2.kiev.ua?subject=SqStat '" . SQSTAT_VERSION . "'>Alex Samorukov</a>, 2006</p>";
+
+ return implode("\n", $t);
+}
+
+function sqstat_errorHTML()
+{
+ global $squidclass;
+ $t = array();
+
+ # table header
+ $t[] = "<table class='result' align='center' width='100%' border='0'>";
+ $t[] = "<tr><th align='left'>SqStat error</th></tr>";
+ $t[] = "<tr><td>";
+ $t[] = '<p style="color:red">Error (' . $squidclass->errno . '): ' . $squidclass->errstr . '</p>';
+ $t[] = "</td></tr>";
+ $t[] = "</table>";
+
+ return implode ("\n", $t);
+}
+
+function sqstat_loadconfig()
+{
+ global $squidclass, $config;
+
+ $squidclass->errno = 0;
+ $squidclass->errstr = '';
+
+ $squidclass->sqstat_version = SQSTAT_VERSION;
+
+ # === load config from pfSense ===
+ $iface = '127.0.0.1';
+ $iport = 3128;
+ $squid_settings = $config['installedpackages']['squid']['config'][0];
+ if (!empty($squid_settings)) {
+ # squid interface IP & port
+ $realif = array();
+ $iface = ($squid_settings['active_interface'] ? $squid_settings['active_interface'] : 'lan');
+ $iface = explode(",", $iface);
+ foreach ($iface as $i => $if) {
+ $realif[] = sqstat_get_real_interface_address($if);
+ $iface = $realif[$i][0] ? $realif[$i][0] : '127.0.0.1';
+ }
+ $iport = $squid_settings['proxy_port'] ? $squid_settings['proxy_port'] : 3128;
+ }
+ $squidclass->squidhost = $iface;
+ $squidclass->squidport = $iport;
+
+ $squidclass->group_by = "host";
+ $squidclass->resolveip = true;
+ $squidclass->hosts_file = ''; # hosts file not used
+ $squidclass->autorefresh = 3; # refresh 3 sec by default
+ $squidclass->cachemgr_passwd = '';
+
+ # load hosts file, if defined
+ if (!empty($squidclass->hosts_file)) {
+ $squidclass->load_hosts();
+ }
+
+ return $squidclass->errno;
+}
+
+function sqstat_get_real_interface_address($iface)
+{
+ global $config;
+
+ $iface = convert_friendly_interface_to_real_interface_name($iface);
+ $line = trim(shell_exec("ifconfig $iface | grep inet | grep -v inet6"));
+ list($dummy, $ip, $dummy2, $netmask) = explode(" ", $line);
+
+ return array($ip, long2ip(hexdec($netmask)));
+}
+
+?> \ No newline at end of file
diff --git a/config/lightsquid/zhabascript.js b/config/lightsquid/zhabascript.js
new file mode 100644
index 00000000..311e5fe9
--- /dev/null
+++ b/config/lightsquid/zhabascript.js
@@ -0,0 +1,118 @@
+/***********************************************
+* Cool DHTML tooltip script- © Dynamic Drive DHTML code library (www.dynamicdrive.com)
+* This notice MUST stay intact for legal use
+* Visit Dynamic Drive at http://www.dynamicdrive.com/ for full source code
+***********************************************/
+
+var offsetxpoint=-60 //Customize x offset of tooltip
+var offsetypoint=20 //Customize y offset of tooltip
+var ie=document.all
+var ns6=document.getElementById && !document.all
+var enabletip=false
+var tipobj=false;
+
+function jsInit(){
+
+ if (ie||ns6)
+ tipobj=document.all? document.all["dhtmltooltip"] : document.getElementById? document.getElementById("dhtmltooltip") : ""
+ //alert(tipobj);
+}
+
+/***********************************************
+* Cool DHTML tooltip script II- © Dynamic Drive DHTML code library (www.dynamicdrive.com)
+* This notice MUST stay intact for legal use
+* Visit Dynamic Drive at http://www.dynamicdrive.com/ for full source code
+***********************************************/
+
+var offsetfromcursorX=12 //Customize x offset of tooltip
+var offsetfromcursorY=10 //Customize y offset of tooltip
+
+var offsetdivfrompointerX=10 //Customize x offset of tooltip DIV relative to pointer image
+var offsetdivfrompointerY=14 //Customize y offset of tooltip DIV relative to pointer image. Tip: Set it to (height_of_pointer_image-1).
+
+//document.write('<div id="dhtmltooltip"></div>') //write out tooltip DIV
+document.write('<img id="dhtmlpointer" src="arrow.gif">') //write out pointer image
+
+var ie=document.all
+var ns6=document.getElementById && !document.all
+var enabletip=false
+if (ie||ns6)
+ var tipobj=document.all? document.all["dhtmltooltip"] : document.getElementById? document.getElementById("dhtmltooltip") : ""
+
+var pointerobj=document.all? document.all["dhtmlpointer"] : document.getElementById? document.getElementById("dhtmlpointer") : ""
+
+function ietruebody(){
+ return (document.compatMode && document.compatMode!="BackCompat")? document.documentElement : document.body
+}
+
+function ddrivetip(thetext, thewidth, thecolor){
+ if(!tipobj) return false;
+ if (ns6||ie){
+ if (typeof thewidth!="undefined") tipobj.style.width=thewidth+"px"
+ if (typeof thecolor!="undefined" && thecolor!="") tipobj.style.backgroundColor=thecolor
+ tipobj.innerHTML=thetext
+ enabletip=true
+ return false
+ }
+}
+
+function positiontip(e){
+ if (enabletip){
+ var nondefaultpos=false
+ var curX=(ns6)?e.pageX : event.clientX+ietruebody().scrollLeft;
+ var curY=(ns6)?e.pageY : event.clientY+ietruebody().scrollTop;
+ //Find out how close the mouse is to the corner of the window
+ var winwidth=ie&&!window.opera? ietruebody().clientWidth : window.innerWidth-20
+ var winheight=ie&&!window.opera? ietruebody().clientHeight : window.innerHeight-20
+
+ var rightedge=ie&&!window.opera? winwidth-event.clientX-offsetfromcursorX : winwidth-e.clientX-offsetfromcursorX
+ var bottomedge=ie&&!window.opera? winheight-event.clientY-offsetfromcursorY : winheight-e.clientY-offsetfromcursorY
+
+ var leftedge=(offsetfromcursorX<0)? offsetfromcursorX*(-1) : -1000
+
+ //if the horizontal distance isn't enough to accomodate the width of the context menu
+/* if (rightedge<tipobj.offsetWidth){
+ //move the horizontal position of the menu to the left by it's width
+ tipobj.style.left=curX-tipobj.offsetWidth+"px"
+ nondefaultpos=true
+ alert(1);
+ }
+ else */
+ if (curX<leftedge)
+ tipobj.style.left="5px"
+ else{
+ //position the horizontal position of the menu where the mouse is positioned
+ tipobj.style.left=curX+offsetfromcursorX-offsetdivfrompointerX+"px"
+ pointerobj.style.left=curX+offsetfromcursorX+"px"
+ }
+
+ //same concept with the vertical position
+ if (bottomedge<tipobj.offsetHeight){
+ tipobj.style.top=curY-tipobj.offsetHeight-offsetfromcursorY+"px"
+ nondefaultpos=true
+ }
+ else{
+ tipobj.style.top=curY+offsetfromcursorY+offsetdivfrompointerY+"px"
+ pointerobj.style.top=curY+offsetfromcursorY+"px"
+ }
+ tipobj.style.visibility="visible"
+ if (!nondefaultpos)
+ pointerobj.style.visibility="visible"
+ else
+ pointerobj.style.visibility="hidden"
+ }
+}
+
+function hideddrivetip(){
+ if (ns6||ie){
+ enabletip=false
+ tipobj.style.visibility="hidden"
+ pointerobj.style.visibility="hidden"
+ tipobj.style.left="-1000px"
+ tipobj.style.backgroundColor=''
+ tipobj.style.width=''
+ }
+}
+
+document.onmousemove=positiontip
+