mirror of
https://github.com/BlackLight/Snort_AIPreproc.git
synced 2024-11-27 14:15:13 +01:00
Updated documentation and Makefile
This commit is contained in:
parent
d7b3d1aff1
commit
e9dd3ebfa2
8 changed files with 129 additions and 307 deletions
14
Makefile.am
14
Makefile.am
|
@ -47,15 +47,14 @@ doc:
|
|||
doxygen; \
|
||||
fi
|
||||
|
||||
doc-install:
|
||||
if test ! -z "${DOC_PREFIX}"; then \
|
||||
mkdir -p "${DOC_PREFIX}"; \
|
||||
cp -r doc/* "${DOC_PREFIX}"; \
|
||||
fi
|
||||
|
||||
install-data-hook:
|
||||
if test ! -z "${PWD}/doc"; then \
|
||||
mkdir -p "${SHARE_PREFIX}/doc"; \
|
||||
cp -r "${PWD}/doc/"* "${SHARE_PREFIX}/doc"; \
|
||||
fi
|
||||
mkdir -p "${SHARE_PREFIX}/htdocs"
|
||||
mkdir -p "${SHARE_PREFIX}/htdocs/js"
|
||||
mkdir -p "${SHARE_PREFIX}/schemas"
|
||||
install -m 0644 "${PWD}/htdocs/index.html" "${SHARE_PREFIX}/htdocs"
|
||||
install -m 0755 "${PWD}/htdocs/pcap.cgi" "${SHARE_PREFIX}/htdocs"
|
||||
install -m 0644 "${PWD}/htdocs/js/Curry-1.0.1.js" "${SHARE_PREFIX}/htdocs/js"
|
||||
|
@ -64,3 +63,6 @@ install-data-hook:
|
|||
install -m 0644 "${PWD}/htdocs/js/dracula_graph.js" "${SHARE_PREFIX}/htdocs/js"
|
||||
install -m 0644 "${PWD}/htdocs/js/raphael.js" "${SHARE_PREFIX}/htdocs/js"
|
||||
install -m 0644 "${PWD}/htdocs/js/seedrandom.js" "${SHARE_PREFIX}/htdocs/js"
|
||||
install -m 0644 "${PWD}/schemas/mysql.sql" "${SHARE_PREFIX}/schemas"
|
||||
install -m 0644 "${PWD}/schemas/postgresql.sql" "${SHARE_PREFIX}/schemas"
|
||||
install -m 0644 "${PWD}/schemas/database_ER.png" "${SHARE_PREFIX}/schemas"
|
||||
|
|
14
Makefile.in
14
Makefile.in
|
@ -823,15 +823,14 @@ doc:
|
|||
doxygen; \
|
||||
fi
|
||||
|
||||
doc-install:
|
||||
if test ! -z "${DOC_PREFIX}"; then \
|
||||
mkdir -p "${DOC_PREFIX}"; \
|
||||
cp -r doc/* "${DOC_PREFIX}"; \
|
||||
fi
|
||||
|
||||
install-data-hook:
|
||||
if test ! -z "${PWD}/doc"; then \
|
||||
mkdir -p "${SHARE_PREFIX}/doc"; \
|
||||
cp -r "${PWD}/doc/"* "${SHARE_PREFIX}/doc"; \
|
||||
fi
|
||||
mkdir -p "${SHARE_PREFIX}/htdocs"
|
||||
mkdir -p "${SHARE_PREFIX}/htdocs/js"
|
||||
mkdir -p "${SHARE_PREFIX}/schemas"
|
||||
install -m 0644 "${PWD}/htdocs/index.html" "${SHARE_PREFIX}/htdocs"
|
||||
install -m 0755 "${PWD}/htdocs/pcap.cgi" "${SHARE_PREFIX}/htdocs"
|
||||
install -m 0644 "${PWD}/htdocs/js/Curry-1.0.1.js" "${SHARE_PREFIX}/htdocs/js"
|
||||
|
@ -840,6 +839,9 @@ install-data-hook:
|
|||
install -m 0644 "${PWD}/htdocs/js/dracula_graph.js" "${SHARE_PREFIX}/htdocs/js"
|
||||
install -m 0644 "${PWD}/htdocs/js/raphael.js" "${SHARE_PREFIX}/htdocs/js"
|
||||
install -m 0644 "${PWD}/htdocs/js/seedrandom.js" "${SHARE_PREFIX}/htdocs/js"
|
||||
install -m 0644 "${PWD}/schemas/mysql.sql" "${SHARE_PREFIX}/schemas"
|
||||
install -m 0644 "${PWD}/schemas/postgresql.sql" "${SHARE_PREFIX}/schemas"
|
||||
install -m 0644 "${PWD}/schemas/database_ER.png" "${SHARE_PREFIX}/schemas"
|
||||
|
||||
# Tell versions [3.59,3.63) of GNU make to not export all variables.
|
||||
# Otherwise a system limit (for SysV at least) may be exceeded.
|
||||
|
|
107
README
107
README
|
@ -28,7 +28,9 @@ Table of contents:
|
|||
3.2 Configure options
|
||||
4. Basic configuration
|
||||
5. Correlation rules
|
||||
6. Additional documentation
|
||||
6. Output database
|
||||
7. Web interface
|
||||
8. Additional documentation
|
||||
|
||||
|
||||
===============================
|
||||
|
@ -119,6 +121,14 @@ disabled by the default, and can be enabled by specifying the option
|
|||
--with-postgresql to ./configure. On a Debian-based system you may need to
|
||||
install libpq-dev.
|
||||
|
||||
- A DBMS (RECOMMANDED), MySQL and PostgreSQL are supported for now, for writing
|
||||
clusters, correlations and packet streams information on a DBMS, making the
|
||||
analysis easier.
|
||||
|
||||
- Perl (OPTIONAL), used for the CGI script in the web interface that saves a
|
||||
packet stream associated to an alert in .pcap format, to be analyzed by tools
|
||||
like tcpdump and Wireshark.
|
||||
|
||||
|
||||
=====================
|
||||
3.2 Configure options
|
||||
|
@ -145,8 +155,6 @@ following:
|
|||
|
||||
|
||||
preprocessor ai: \
|
||||
hashtable_cleanup_interval 300 \
|
||||
tcp_stream_expire_interval 300 \
|
||||
alertfile "/your/snort/dir/log/alert" \
|
||||
alert_history_file "/your/snort/dir/log/alert_history" \
|
||||
alert_serialization_interval 3600 \
|
||||
|
@ -158,9 +166,6 @@ preprocessor ai: \
|
|||
correlation_rules_dir "/your/snort/dir/etc/corr_rules" \
|
||||
correlated_alerts_dir "/your/snort/dir/log/correlated_alerts" \
|
||||
correlation_threshold_coefficient 0.5 \
|
||||
database ( type="dbtype", name="snort", user="snortusr", password="snortpass", host="dbhost" ) \
|
||||
output_database ( type="dbtype", name="snort", user="snortusr", password="snortpass", host="dbhost" ) \
|
||||
database_parsing_interval 30 \
|
||||
cluster_max_alert_interval 14400 \
|
||||
clusterfile "/your/snort/dir/log/clustered_alerts" \
|
||||
cluster ( class="dst_port", name="privileged_ports", range="1-1023" ) \
|
||||
|
@ -170,7 +175,16 @@ preprocessor ai: \
|
|||
cluster ( class="src_addr", name="vpn_net", range="10.8.0.0/24" ) \
|
||||
cluster ( class="dst_addr", name="local_net", range="192.168.1.0/24" ) \
|
||||
cluster ( class="dst_addr", name="dmz_net", range="155.185.0.0/16" ) \
|
||||
cluster ( class="dst_addr", name="vpn_net", range="10.8.0.0/24" )
|
||||
cluster ( class="dst_addr", name="vpn_net", range="10.8.0.0/24" ) \
|
||||
database ( type="dbtype", name="snort", user="snortusr", password="snortpass", host="dbhost" ) \
|
||||
database_parsing_interval 30 \
|
||||
hashtable_cleanup_interval 300 \
|
||||
output_database ( type="dbtype", name="snort", user="snortusr", password="snortpass", host="dbhost" ) \
|
||||
tcp_stream_expire_interval 300 \
|
||||
webserv_banner "Snort AIPreprocessor module" \
|
||||
webserv_dir "/prefix/share/htdocs" \
|
||||
webserv_port 7654
|
||||
|
||||
|
||||
The options are the following:
|
||||
|
||||
|
@ -298,6 +312,19 @@ stream as "expired", if no more packets are received inside of that and it's not
|
|||
"marked" as suspicious (default if not specified: 300 seconds)
|
||||
|
||||
|
||||
- webserv_banner: Banner of the web server, to be placed on the error pages and
|
||||
in the "Server" HTTP reply header
|
||||
|
||||
- webserver_dir: Directory containing the contents of the web server running
|
||||
over the module (default if none is specified:
|
||||
$PREFIX/share/snort_ai_preprocessor/htdocs)
|
||||
|
||||
- webserver_port: Port where the web server will listen (default if none is
|
||||
specified: 7654). Set this value to 0 if you don't want to run the web server
|
||||
over the module for having the web interface (in this case, if you want to see
|
||||
the web graphical visualization of the alerts, you should manually copy the
|
||||
files contained in htdocs/ in a web server directory)
|
||||
|
||||
====================
|
||||
5. Correlation rules
|
||||
====================
|
||||
|
@ -365,11 +392,73 @@ matching would fail. Any new predicates can be defined as well in
|
|||
hyperalerts, provided that it respects this constraint.
|
||||
|
||||
|
||||
==================
|
||||
6. Output database
|
||||
==================
|
||||
|
||||
If the output_database option is specified in the documentation, the alerts, and
|
||||
the relative clusters, correlations and packet streams information, will be
|
||||
saved on a database as well. This is strongly suggested, first for making the
|
||||
management of the module's information easier (a SELECT query needs to be done
|
||||
for doing also complex searches instead of grep-ing or manually
|
||||
searching inside of a text file), second because the web interface of
|
||||
the module can work ONLY if the output_database option is specified (the web
|
||||
interface strongly depends on the unique IDs assigned to the alerts by
|
||||
the database interface). Note that for using this option you should
|
||||
explicitly tell to the ./configure script which DBMS you're going to use, so
|
||||
that it knows which APIs to use for interfacing with the database, e.g. via
|
||||
--with-mysql or --with-postgresql.
|
||||
|
||||
After you compile the module, you should pick up the right .sql file from
|
||||
schemas/ directory (for example mysql.sql or postgresql.sql), or from
|
||||
$PREFIX/share/snort_ai_preprocessor/schemas after the installation of the
|
||||
module, and import it in your database,
|
||||
|
||||
$ mysql -uusername -ppassword dbname < schemas/mysql.sql (for MySQL)
|
||||
$ psql -U username -W dbname < schemas/postgresql.sql (for PostgreSQL)
|
||||
|
||||
You can check the structure of the database from the SQL file for your DBMS, or
|
||||
from the E/R schema saved in schemas/database_ER.png.
|
||||
|
||||
|
||||
================
|
||||
7. Web interface
|
||||
================
|
||||
|
||||
The module provides an optional (but strongly recommanded) web interface for
|
||||
browsing the triggered (and already clustered) security alerts, their
|
||||
correlations and their packet streams information from your browser. This
|
||||
feature can be switched off by setting the configuration option "webserv_port"
|
||||
of the module to 0. Otherwise, if none between webserv_dir and webserv_port are
|
||||
specified, the web server thread starts with the module picking by default the
|
||||
directory $PREFIX/share/snort_ai_preproc/htdocs as document root and listening
|
||||
for incoming connections on the port 7654.
|
||||
|
||||
You should use a browser supporting JavaScript, AJAX and SVG technologies in
|
||||
order to view correctly the alert web interface on your browser (successfully
|
||||
tested with Firefox 3.5, Chrome and Opera 10), for example, connecting
|
||||
to the address http://localhost:7654. You can drag and drop the nodes in the
|
||||
graph, modifying the layout of the graph on the fly or using the "redraw"
|
||||
function. Each node represents a clustered alert. For viewing the information
|
||||
over that cluster and the alerts group inside, just click on the node. You can
|
||||
optionally save the stream of packets associated to a certain alert in .pcap
|
||||
format (analyzable by tools like tcpdump and Wireshark) from this same
|
||||
interface. This feature, anyway, is based on the CGI script pcap.cgi inside of
|
||||
the document root, and it requires the Perl interpreter to be installed on the
|
||||
machine.
|
||||
|
||||
The web server running over the module is a true web server with its own
|
||||
document path, so you can use it as stand-alone web server as well and place
|
||||
your documents and files inside. You can moreover place some CGI scripts or
|
||||
applications made in the language you prefer, as long as they are files
|
||||
executable by any users and they have the extension ".cgi".
|
||||
|
||||
|
||||
===========================
|
||||
6. Additional documentation
|
||||
8. Additional documentation
|
||||
===========================
|
||||
|
||||
The additional documentation over the code, functions and data structures can
|
||||
be automatically generated by Doxygen by typing `make doc', and installed in
|
||||
SNORT_DIR/doc then typing `make doc-install'.
|
||||
$PREFIX/share/snort_ai_preproc/doc then after `make install'.
|
||||
|
||||
|
|
3
TODO
3
TODO
|
@ -6,9 +6,9 @@ AVERAGE/HIGH PRIORITY:
|
|||
- Modules for correlation coefficients
|
||||
- Code profiling
|
||||
- Comment all the code!!!
|
||||
- Saving packet flows as .pcap
|
||||
- Neural network for computing k
|
||||
- Testing more scenarios, making more hyperalert models
|
||||
- Manual alert correlation from the web interface
|
||||
|
||||
=============
|
||||
LOW PRIORITY:
|
||||
|
@ -36,4 +36,5 @@ DONE:
|
|||
+ Full PostgreSQL support for output db
|
||||
+ Web interface
|
||||
+ Function names (private functions with _ or __ ?)
|
||||
+ Saving packet flows as .pcap
|
||||
|
||||
|
|
|
@ -211,19 +211,19 @@ window.onload = function() {
|
|||
|
||||
switch ( month )
|
||||
{
|
||||
case 'Jan': month = 1; break;
|
||||
case 'Feb': month = 2; break;
|
||||
case 'Mar': month = 3; break;
|
||||
case 'Apr': month = 4; break;
|
||||
case 'May': month = 5; break;
|
||||
case 'Jun': month = 6; break;
|
||||
case 'Jul': month = 7; break;
|
||||
case 'Ago': month = 8; break;
|
||||
case 'Sep': month = 9; break;
|
||||
case 'Oct': month = 10; break;
|
||||
case 'Nov': month = 11; break;
|
||||
case 'Dec': month = 12; break;
|
||||
default : month = 1; break;
|
||||
case 'Jan': month = 0; break;
|
||||
case 'Feb': month = 1; break;
|
||||
case 'Mar': month = 2; break;
|
||||
case 'Apr': month = 3; break;
|
||||
case 'May': month = 4; break;
|
||||
case 'Jun': month = 5; break;
|
||||
case 'Jul': month = 6; break;
|
||||
case 'Ago': month = 7; break;
|
||||
case 'Sep': month = 8; break;
|
||||
case 'Oct': month = 9; break;
|
||||
case 'Nov': month = 10; break;
|
||||
case 'Dec': month = 11; break;
|
||||
default : month = 0; break;
|
||||
}
|
||||
|
||||
var timestamp = new Date ( year, month, day, hour, min, sec).getTime().toString();
|
||||
|
|
|
@ -1,143 +0,0 @@
|
|||
/**
|
||||
*
|
||||
* Base64 encode / decode
|
||||
* http://www.webtoolkit.info/
|
||||
*
|
||||
**/
|
||||
|
||||
var Base64 = {
|
||||
|
||||
// private property
|
||||
_keyStr : "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",
|
||||
|
||||
// public method for encoding
|
||||
encode : function (input) {
|
||||
var output = "";
|
||||
var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
|
||||
var i = 0;
|
||||
|
||||
input = Base64._utf8_encode(input);
|
||||
|
||||
while (i < input.length) {
|
||||
|
||||
chr1 = input.charCodeAt(i++);
|
||||
chr2 = input.charCodeAt(i++);
|
||||
chr3 = input.charCodeAt(i++);
|
||||
|
||||
enc1 = chr1 >> 2;
|
||||
enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
|
||||
enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
|
||||
enc4 = chr3 & 63;
|
||||
|
||||
if (isNaN(chr2)) {
|
||||
enc3 = enc4 = 64;
|
||||
} else if (isNaN(chr3)) {
|
||||
enc4 = 64;
|
||||
}
|
||||
|
||||
output = output +
|
||||
this._keyStr.charAt(enc1) + this._keyStr.charAt(enc2) +
|
||||
this._keyStr.charAt(enc3) + this._keyStr.charAt(enc4);
|
||||
|
||||
}
|
||||
|
||||
return output;
|
||||
},
|
||||
|
||||
// public method for decoding
|
||||
decode : function (input) {
|
||||
var output = "";
|
||||
var chr1, chr2, chr3;
|
||||
var enc1, enc2, enc3, enc4;
|
||||
var i = 0;
|
||||
|
||||
input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
|
||||
|
||||
while (i < input.length) {
|
||||
|
||||
enc1 = this._keyStr.indexOf(input.charAt(i++));
|
||||
enc2 = this._keyStr.indexOf(input.charAt(i++));
|
||||
enc3 = this._keyStr.indexOf(input.charAt(i++));
|
||||
enc4 = this._keyStr.indexOf(input.charAt(i++));
|
||||
|
||||
chr1 = (enc1 << 2) | (enc2 >> 4);
|
||||
chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
|
||||
chr3 = ((enc3 & 3) << 6) | enc4;
|
||||
|
||||
output = output + String.fromCharCode(chr1);
|
||||
|
||||
if (enc3 != 64) {
|
||||
output = output + String.fromCharCode(chr2);
|
||||
}
|
||||
if (enc4 != 64) {
|
||||
output = output + String.fromCharCode(chr3);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
output = Base64._utf8_decode(output);
|
||||
|
||||
return output;
|
||||
|
||||
},
|
||||
|
||||
// private method for UTF-8 encoding
|
||||
_utf8_encode : function (string) {
|
||||
string = string.replace(/\r\n/g,"\n");
|
||||
var utftext = "";
|
||||
|
||||
for (var n = 0; n < string.length; n++) {
|
||||
|
||||
var c = string.charCodeAt(n);
|
||||
|
||||
if (c < 128) {
|
||||
utftext += String.fromCharCode(c);
|
||||
}
|
||||
else if((c > 127) && (c < 2048)) {
|
||||
utftext += String.fromCharCode((c >> 6) | 192);
|
||||
utftext += String.fromCharCode((c & 63) | 128);
|
||||
}
|
||||
else {
|
||||
utftext += String.fromCharCode((c >> 12) | 224);
|
||||
utftext += String.fromCharCode(((c >> 6) & 63) | 128);
|
||||
utftext += String.fromCharCode((c & 63) | 128);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return utftext;
|
||||
},
|
||||
|
||||
// private method for UTF-8 decoding
|
||||
_utf8_decode : function (utftext) {
|
||||
var string = "";
|
||||
var i = 0;
|
||||
var c = c1 = c2 = 0;
|
||||
|
||||
while ( i < utftext.length ) {
|
||||
|
||||
c = utftext.charCodeAt(i);
|
||||
|
||||
if (c < 128) {
|
||||
string += String.fromCharCode(c);
|
||||
i++;
|
||||
}
|
||||
else if((c > 191) && (c < 224)) {
|
||||
c2 = utftext.charCodeAt(i+1);
|
||||
string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
|
||||
i += 2;
|
||||
}
|
||||
else {
|
||||
c2 = utftext.charCodeAt(i+1);
|
||||
c3 = utftext.charCodeAt(i+2);
|
||||
string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
|
||||
i += 3;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return string;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,129 +0,0 @@
|
|||
var dom = (document.getElementById) ? true : false;
|
||||
var ns5 = ((navigator.userAgent.indexOf("Gecko")>-1) && dom) ? true: false;
|
||||
var ie5 = ((navigator.userAgent.indexOf("MSIE")>-1) && dom) ? true : false;
|
||||
var ns4 = (document.layers && !dom) ? true : false;
|
||||
var ie4 = (document.all && !dom) ? true : false;
|
||||
var nodyn = (!ns5 && !ns4 && !ie4 && !ie5) ? true : false;
|
||||
|
||||
var origWidth, origHeight;
|
||||
if (ns4) {
|
||||
origWidth = window.innerWidth; origHeight = window.innerHeight;
|
||||
window.onresize = function() { if (window.innerWidth != origWidth || window.innerHeight != origHeight) history.go(0); }
|
||||
}
|
||||
|
||||
if (nodyn) { event = "nope" }
|
||||
var tipFollowMouse = true;
|
||||
var tipWidth = 160;
|
||||
var offX = 12; // how far from mouse to show tip
|
||||
var offY = 12;
|
||||
var tipFontFamily = "Verdana, arial, helvetica, sans-serif";
|
||||
var tipFontSize = "8pt";
|
||||
var tipFontColor = "#000000";
|
||||
var tipBgColor = "#DDECFF";
|
||||
var origBgColor = tipBgColor; // in case no bgColor set in array
|
||||
var tipBorderColor = "#000080";
|
||||
var tipBorderWidth = 2;
|
||||
var tipBorderStyle = "ridge";
|
||||
var tipPadding = 4;
|
||||
|
||||
var messages = new Array();
|
||||
messages[0] = new Array('http://planmagic.com/images/plmbiz.jpg','Professional business planning software.',"#FFFFFF");
|
||||
messages[1] = new Array('http://planmagic.com/images/plmmar.jpg','Professional marketing planning software.',"#DDECFF");
|
||||
messages[2] = new Array('http://planmagic.com/images/plmfinance.jpg','Financial calculations and projections made easy.',"#E9E9E9");
|
||||
|
||||
if (document.images) {
|
||||
var theImgs = new Array();
|
||||
for (var i=0; i<messages.length; i++) {
|
||||
theImgs[i] = new Image();
|
||||
theImgs[i].src = messages[i][0];
|
||||
}
|
||||
}
|
||||
|
||||
var startStr = '<table width="' + tipWidth + '"><tr><td align="center" width="100%"><img src="';
|
||||
var midStr = '" border="0"></td></tr><tr><td valign="top">';
|
||||
var endStr = '</td></tr></table>';
|
||||
|
||||
var tooltip, tipcss;
|
||||
function initTip() {
|
||||
if (nodyn) return;
|
||||
tooltip = (ns4)? document.tipDiv.document: (ie4)? document.all['tipDiv']: (ie5||ns5)? document.getElementById('tipDiv'): null;
|
||||
tipcss = (ns4)? document.tipDiv: tooltip.style;
|
||||
if (ie4||ie5||ns5) { // ns4 would lose all this on rewrites
|
||||
tipcss.width = tipWidth+"px";
|
||||
tipcss.fontFamily = tipFontFamily;
|
||||
tipcss.fontSize = tipFontSize;
|
||||
tipcss.color = tipFontColor;
|
||||
tipcss.backgroundColor = tipBgColor;
|
||||
tipcss.borderColor = tipBorderColor;
|
||||
tipcss.borderWidth = tipBorderWidth+"px";
|
||||
tipcss.padding = tipPadding+"px";
|
||||
tipcss.borderStyle = tipBorderStyle;
|
||||
}
|
||||
if (tooltip&&tipFollowMouse) {
|
||||
if (ns4) document.captureEvents(Event.MOUSEMOVE);
|
||||
document.onmousemove = trackMouse;
|
||||
}
|
||||
}
|
||||
|
||||
window.onload = initTip;
|
||||
|
||||
var t1,t2; // for setTimeouts
|
||||
var tipOn = false; // check if over tooltip link
|
||||
function doTooltip(evt,num) {
|
||||
|
||||
if (!tooltip) return;
|
||||
if (t1) clearTimeout(t1); if (t2) clearTimeout(t2);
|
||||
tipOn = true;
|
||||
// set colors if included in messages array
|
||||
if (messages[num][2]) var curBgColor = messages[num][2];
|
||||
else curBgColor = tipBgColor;
|
||||
if (messages[num][3]) var curFontColor = messages[num][3];
|
||||
else curFontColor = tipFontColor;
|
||||
if (ns4) {
|
||||
var tip = '<table bgcolor="' + tipBorderColor + '" width="' + tipWidth + '" cellspacing="0" cellpadding="' + tipBorderWidth + '" border="0"><tr><td><table bgcolor="' + curBgColor + '" width="100%" cellspacing="0" cellpadding="' + tipPadding + '" border="0"><tr><td>'+ startStr + messages[num][0] + midStr + '<span style="font-family:' + tipFontFamily + '; font-size:' + tipFontSize + '; color:' + curFontColor + ';">' + messages[num][1] + '</span>' + endStr + '</td></tr></table></td></tr></table>';
|
||||
tooltip.write(tip);
|
||||
tooltip.close();
|
||||
} else if (ie4||ie5||ns5) {
|
||||
var tip = startStr + messages[num][0] + midStr + '<span style="font-family:' + tipFontFamily + '; font-size:' + tipFontSize + '; color:' + curFontColor + ';">' + messages[num][1] + '</span>' + endStr;
|
||||
tipcss.backgroundColor = curBgColor;
|
||||
tooltip.innerHTML = tip;
|
||||
}
|
||||
if (!tipFollowMouse) positionTip(evt);
|
||||
else t1=setTimeout("tipcss.visibility='visible'",100);
|
||||
}
|
||||
|
||||
var mouseX, mouseY;
|
||||
function trackMouse(evt) {
|
||||
mouseX = (ns4||ns5)? evt.pageX: window.event.clientX + document.body.scrollLeft;
|
||||
mouseY = (ns4||ns5)? evt.pageY: window.event.clientY + document.body.scrollTop;
|
||||
if (tipOn) positionTip(evt);
|
||||
}
|
||||
|
||||
function positionTip(evt) {
|
||||
if (!tipFollowMouse) {
|
||||
mouseX = (ns4||ns5)? evt.pageX: window.event.clientX + document.body.scrollLeft;
|
||||
mouseY = (ns4||ns5)? evt.pageY: window.event.clientY + document.body.scrollTop;
|
||||
}
|
||||
// tooltip width and height
|
||||
var tpWd = (ns4)? tooltip.width: (ie4||ie5)? tooltip.clientWidth: tooltip.offsetWidth;
|
||||
var tpHt = (ns4)? tooltip.height: (ie4||ie5)? tooltip.clientHeight: tooltip.offsetHeight;
|
||||
// document area in view (subtract scrollbar width for ns)
|
||||
var winWd = (ns4||ns5)? window.innerWidth-20+window.pageXOffset: document.body.clientWidth+document.body.scrollLeft;
|
||||
var winHt = (ns4||ns5)? window.innerHeight-20+window.pageYOffset: document.body.clientHeight+document.body.scrollTop;
|
||||
// check mouse position against tip and window dimensions
|
||||
// and position the tooltip
|
||||
if ((mouseX+offX+tpWd)>winWd)
|
||||
tipcss.left = (ns4)? mouseX-(tpWd+offX): mouseX-(tpWd+offX)+"px";
|
||||
else tipcss.left = (ns4)? mouseX+offX: mouseX+offX+"px";
|
||||
if ((mouseY+offY+tpHt)>winHt)
|
||||
tipcss.top = (ns4)? winHt-(tpHt+offY): winHt-(tpHt+offY)+"px";
|
||||
else tipcss.top = (ns4)? mouseY+offY: mouseY+offY+"px";
|
||||
if (!tipFollowMouse) t1=setTimeout("tipcss.visibility='visible'",100);
|
||||
}
|
||||
|
||||
function hideTip() {
|
||||
if (!tooltip) return;
|
||||
t2=setTimeout("tipcss.visibility='hidden'",100);
|
||||
tipOn = false;
|
||||
}
|
||||
|
BIN
schemas/database_ER.png
Normal file
BIN
schemas/database_ER.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 22 KiB |
Loading…
Reference in a new issue