From aac0f7118f0630a1987324c4d29c642be06a9f94 Mon Sep 17 00:00:00 2001 From: Christian Schmidt Date: Sat, 28 Aug 2010 08:38:10 +0200 Subject: [PATCH] First integration of imspector, some more work to do. --- config/backup/includes/imspector | 3 + config/imspector/imspector.conf | 24 ++ config/menu/EX-imspector.menu | 5 + config/rootfiles/common/initscripts | 1 + config/rootfiles/packages/imspector | 27 ++ doc/packages-list.txt | 1 + html/cgi-bin/imspector.cgi | 607 ++++++++++++++++++++++++++++ lfs/imspector | 87 ++++ lfs/initscripts | 3 + make.sh | 1 + src/initscripts/init.d/imspector | 54 +++ 11 files changed, 813 insertions(+) create mode 100644 config/backup/includes/imspector create mode 100644 config/imspector/imspector.conf create mode 100644 config/menu/EX-imspector.menu create mode 100644 config/rootfiles/packages/imspector create mode 100644 html/cgi-bin/imspector.cgi create mode 100644 lfs/imspector create mode 100644 src/initscripts/init.d/imspector diff --git a/config/backup/includes/imspector b/config/backup/includes/imspector new file mode 100644 index 0000000000..cc7ef16bf5 --- /dev/null +++ b/config/backup/includes/imspector @@ -0,0 +1,3 @@ +/etc/imspector/acl.txt +/etc/imspector/badwords.txt +/etc/imspector/imspector.conf \ No newline at end of file diff --git a/config/imspector/imspector.conf b/config/imspector/imspector.conf new file mode 100644 index 0000000000..a37241df60 --- /dev/null +++ b/config/imspector/imspector.conf @@ -0,0 +1,24 @@ +# The listening port for redirected connections +port=16667 + +# For dropping privs - you probably want to do this. +user=nobody +group=nobody + +# Prefix and postfix to all responses using all responder plugins +response_prefix=Message from IMSpector: -= +response_postfix==- + +# Will load enabled plugins in plugin_dir +icq_protocol=on +irc_protocol=on +msn_protocol=on +yahoo_protocol=on +gg_protocol=on +jabber_protocol=on + +# Location where the file logging plugin will start from. +file_logging_dir=/var/log/imspector/ +log_typing_events=on + +plugin_dir=/usr/lib/imspector diff --git a/config/menu/EX-imspector.menu b/config/menu/EX-imspector.menu new file mode 100644 index 0000000000..c88866f5f9 --- /dev/null +++ b/config/menu/EX-imspector.menu @@ -0,0 +1,5 @@ + $subipfire->{'30.imspector'} = {'caption' => 'Imspector', + 'uri' => '/cgi-bin/imspector.cgi', + 'title' => 'Imspector', + 'enabled' => 1, + }; diff --git a/config/rootfiles/common/initscripts b/config/rootfiles/common/initscripts index 180666fe77..87f4318d5f 100644 --- a/config/rootfiles/common/initscripts +++ b/config/rootfiles/common/initscripts @@ -33,6 +33,7 @@ etc/rc.d/init.d/functions etc/rc.d/init.d/halt #etc/rc.d/init.d/hostapd #etc/rc.d/init.d/icecream +#etc/rc.d/init.d/imspector #etc/rc.d/init.d/ipfireseeder etc/rc.d/init.d/ipsec #etc/rc.d/init.d/lcd4linux diff --git a/config/rootfiles/packages/imspector b/config/rootfiles/packages/imspector new file mode 100644 index 0000000000..0cd6ee8bc5 --- /dev/null +++ b/config/rootfiles/packages/imspector @@ -0,0 +1,27 @@ +etc/imspector +#etc/imspector/acl.txt +#etc/imspector/badwords.txt +#etc/imspector/imspector.conf +usr/lib/imspector +usr/lib/imspector/aclfilterplugin.so +usr/lib/imspector/badwordsfilterplugin.so +usr/lib/imspector/catsloggingplugin.so +usr/lib/imspector/censordfilterplugin.so +usr/lib/imspector/debugloggingplugin.so +usr/lib/imspector/fileloggingplugin.so +usr/lib/imspector/ggprotocolplugin.so +usr/lib/imspector/httpsprotocolplugin.so +usr/lib/imspector/icqprotocolplugin.so +usr/lib/imspector/ircprotocolplugin.so +usr/lib/imspector/jabberprotocolplugin.so +usr/lib/imspector/miscfilterplugin.so +usr/lib/imspector/msnprotocolplugin.so +usr/lib/imspector/yahooprotocolplugin.so +usr/lib/libimspector.so +usr/sbin/imspector +var/ipfire/backup/addons/includes/imspector +var/lib/imspector +var/log/imspector +etc/rc.d/init.d/imspector +srv/web/ipfire/cgi-bin/imspector.cgi +var/ipfire/menu.d/EX-imspector.menu diff --git a/doc/packages-list.txt b/doc/packages-list.txt index 1f60b70b62..c8dbc2e5ed 100644 --- a/doc/packages-list.txt +++ b/doc/packages-list.txt @@ -149,6 +149,7 @@ * icegenerator-0.5.5-pre2 * iftop-0.17 * igmpproxy-0.1 +* imspector-0.9 * inetutils-1.4.2 * ipaddr-1.2 * iperf-2.0.4 diff --git a/html/cgi-bin/imspector.cgi b/html/cgi-bin/imspector.cgi new file mode 100644 index 0000000000..7cc2e64a5e --- /dev/null +++ b/html/cgi-bin/imspector.cgi @@ -0,0 +1,607 @@ +#!/usr/bin/perl +# +# IMSpector real-time log viewer +# (c) SmoothWall Ltd 2008 +# +# Released under the GPL v2. + +use POSIX qw(strftime); + +# Common configuration parameters. + +my $logbase = "/var/log/imspector/"; +my $oururl = '/cgi-bin/imspector.cgi'; + +# Colours + +my $protocol_colour = '#06264d'; +my $local_colour = '#1d398b'; +my $remote_colour = '#2149c1'; +my $conversation_colour = '#335ebe'; + +my $local_user_colour = 'blue'; +my $remote_user_colour = 'green'; + +# No need to change anything from this point + +# Page declaration, The following code should parse the CGI headers, and render the page +# accordingly... How you do this depends what environment you're in. + +my %cgiparams; + +print "Content-type: text/html\n"; +print "\n"; + +if ($ENV{'QUERY_STRING'}) +{ + my @vars = split('\&', $ENV{'QUERY_STRING'}); + foreach $_ (@vars) + { + my ($var, $val) = split(/\=/); + $cgiparams{$var} = $val; + } +} + +# Act in Tail mode (as in just generate the raw logs and pass back to the other CGI + +if ( defined $cgiparams{'mode'} and $cgiparams{'mode'} eq "render" ){ + &parser( $cgiparams{'section'}, $cgiparams{'offset'}, $cgiparams{'conversation'}, $cgiparams{'skimhtml'} ); + exit; +} + +# Start rendering the Page using Express' rendering functions + +my $script = &scriptheader(); + +# Print Some header information + +print qq| + + + + IMSpector real-time log viewer + $script + + +|; + +print &pagebody(); + +# and now finish off the HTML page. + +print qq| + + +|; + +exit; + +# ----------------------------------------------------------------------------- +# ---------------------- IMSPector Log Viewer Code ---------------------------- +# ----------------------------------------------------------------------------- +# ^"^ ^"^ + +# Scriptheader +# ------------ +# Return the bulk of the page, which should reside in the pages field + +sub scriptheader +{ + my ( $sec, $min, $hour, $mday, $mon, $year, $wday, $yday ) = localtime( time() ); + $year += 1900; $mon++; + my $conversation = sprintf( "%.4d-%.2d-%.2d", $year, $mon, $mday ); + + my $script = qq { + + }; + + return $script; +} + +# pagebody function +# ----------------- +# Return the HTML fragment which includes the page body. + +sub pagebody +{ + my $body = qq { +
 
+ + + + + + +
+
+
+
+
+ For conversations on:  + +
+
+ [HTML] + [SCROLL LOCK] +
+
+
+ + }; + return $body; +} + +# Parser function ... +# --------------- +# Retrieves the IMspector logs from their nestling place and displays them accordingly. + +sub parser +{ + my ( $section, $offset, $conversationdate, $skimhtml ) = @_; + # render the user list ... + + chomp $offset; + + unless ( $offset =~ /^([\d]*)$/ ){ + print STDERR "Illegal offset ($offset $1) resetting...\n"; + $offset = 0; + } + + # browse for the available protocols + unless ( opendir DIR, $logbase ){ + exit; + } + + my %conversationaldates; + my @protocols = grep {!/^\./} readdir(DIR); + + foreach my $protocol ( @protocols ){ + unless ( opendir LUSER, "$logbase$protocol" ){ + next; + } + + my @localusers = grep {!/^\./} readdir(LUSER); + foreach my $localuser ( @localusers ){ + unless ( opendir RUSER, "$logbase$protocol/$localuser/" ){ + next; + } + my @remoteusers = grep {!/^\./} readdir( RUSER ); + foreach my $remoteuser ( @remoteusers ){ + unless ( opendir CONVERSATIONS, "$logbase$protocol/$localuser/$remoteuser/" ){ + next; + } + my @conversations = grep {!/^\./} readdir( CONVERSATIONS ); + foreach my $conversation ( @conversations ){ + $conversationaldates{ $conversation } = $localuser; + } + + closedir CONVERSATIONS; + + my ( $sec, $min, $hour, $mday, $mon, $year, $wday, $yday ) = localtime( time() ); + $year += 1900; $mon++; + my $conversation = sprintf( "%.4d-%.2d-%.2d", $year, $mon, $mday ); + + $conversation = $conversationdate if ( defined $conversationdate and $conversationdate ne "" ); + + if ( -e "$logbase$protocol/$localuser/$remoteuser/$conversation" ){ + my $modi = -M "$logbase$protocol/$localuser/$remoteuser/$conversation"; + print "|$protocol|$localuser|$remoteuser|$conversation|$modi\n"; + } + } + closedir RUSER; + } + closedir LUSER; + } + closedir DIR; + + print "--END--\n"; + + # display a list of conversational dates .. i.e. the dates which we have conversations on. + foreach my $key ( sort keys %conversationaldates ){ + print "$key\n"; + } + + print "--END--\n"; + + + # now check the log file ... + + if ( $section ne "none" ){ + my ( $protocol, $localuser, $remoteuser, $conversation ) = split /\|/, $section; + + print "$protocol, $localuser, $remoteuser, $conversation\n"; + print "--END--\n"; + + my $filename = "$logbase$protocol/$localuser/$remoteuser/$conversation"; + + unless ( open(FD, "$filename" ) ){ + exit; + }; + + # perform some *reasonably* complicated file hopping and stuff of that ilk. + # it's not beyond reason that logs *could* be extremely large, so what we + # should do to speed up their processing is to jump to the end of the file, + # then backtrack a little (say a meg, which is a reasonably amount of logs) + # and parse from that point onwards. This, *post* filtering might of course + # not leave us with the desired resolution for the tail. If this is the case, + # we keep that array and jump back another meg and have another go, concatinating + # the logs as we go.... + + my $jumpback = 100000; # not quite a meg, but hey ho + my $goneback = 0; + my $gonebacklimit = 1000000000; # don't go back more than 100MB + + # firstly jump to the end of the file. + seek( FD, 0, 2 ); + + my $log_position = tell( FD ); + my $end = $log_position; + my $end_position = $log_position; + + my $lines; + my @content; + + my $TAILSIZE = 100; + + do { + $end_position = $log_position; + + if ( $offset != 0 ){ + # we were given a hint as to where we should have been anyhow .. + # so we might as well use that to go back to. + $log_position = $offset; + $goneback = $end_position - $log_position; + } else { + $log_position -= $jumpback; + $goneback += $jumpback; + } + + last if ( $goneback > $gonebacklimit ); + + if ( $log_position > 0 ){ + seek( FD, $log_position, 0 ); + } else { + seek( FD, 0, 0 ); + } + + my @newcontent; + + while ( my $line = and ( tell( FD ) <= $end_position ) ){ + chomp $line; + push @content, $line; + } + shift @content if $#content >= $TAILSIZE; + } while ( $#content < $TAILSIZE and $log_position > 0 and $offset == 0 ); + + # trim the content down as we may have more entries than we should. + + while ( $#content > $TAILSIZE ){ shift @content; }; + close FD; + + print "$end_position\n--END--\n"; + + foreach my $line ( @content ){ + my ( $address, $timestamp, $direction, $type, $filtered, $cat, $data ); + + ( $address, $timestamp, $direction, $type, $filtered, $cat, $data ) = ( $line =~ /([^,]*),(\d+),(\d+),(\d+),(\d+),([^,]*),(.*)/ ); + + # are we using the oldstyle or new style logs ? + if ( not defined $address and not defined $timestamp ){ + ( $address, $timestamp, $type, $data ) = ( $line =~ /([^,]*),([^,]*),([^,]*),(.*)/ ); + if ( $type eq "1" ){ + $direction = 0; + $type = 1; + } elsif ( $type eq "2" ){ + $direction = 1; + $type = 1; + } elsif ( $type eq "3" ){ + $direction = 0; + $type = 2; + } elsif ( $type eq "4" ){ + $direction = 1; + $type = 4; + } + } + + my ( $severity, $classification ) = '0', 'None'; + if ($cat) { + ( $severity, $classification) = split(/ /, $cat, 2); } + else { + $cat = 'N/A'; } + + my $red = 255; + my $green = 255; + my $blue = 255; + + if ($severity < 0 && $severity >= -5) { + $red = 0; $green = abs($severity) * (255 / 5); $blue = 0; } + elsif ($severity > 0 && $severity <= 5) { + $red = $severity * (255 / 5); $green = 0; $blue = 0; } + else { + $red = 0; $green = 0; $blue = 0; } + + my $severitycolour = ''; + if ($cat ne 'N/A') { + $severitycolour = sprintf("background-color: #%02x%02x%02x;", $red, $green, $blue); } + + # some protocols (ICQ, I'm looking in your direction) have a habit of starting + # and ending each sentence with HTML (evil program) + + if ( defined $skimhtml and $skimhtml eq "1" ){ + $data =~ s/^]*>]*>//ig; + $data =~ s/<\/FONT><\/BODY><\/HTML>//ig; + } + + $data = &htmlescape($data); + $data =~ s/\r\\n/
\n/g; + my $user = ""; + + my $bstyle = ""; + $bstyle = "style='background-color: #FFE4E1;'" if ( $filtered eq "1" ); + + if ( $type eq "1" ){ + # a message message (from remote user) + if ( $direction eq "0" ){ + # incoming + my $u = $remoteuser; + $u =~ s/\@.*//g; + $user = "<$u>"; + } else { + # outgoing message + my $u = $localuser; + $u =~ s/\@.*//g; + $user = "<$u>"; + } + } elsif ($type eq "2") { + if ( $direction eq "0" ){ + # incoming file + my $u = $remoteuser; + $u =~ s/\@.*//g; + $user = "<$u>"; + } else { + # outgoing file + my $u = $localuser; + $u =~ s/\@.*//g; + $user = "<$u>"; + } + } + + my $t = strftime "%H:%M:%S", localtime($timestamp); + if ($type eq "3" or $type eq "4") { + $data = "$data"; + } + print "[$t]$user$data"; + } + } + return; +} + +sub htmlescape +{ + my ($value) = @_; + $value =~ s/&/\&/g; + $value =~ s//\>/g; + $value =~ s/"/\"/g; + $value =~ s/'/\'/g; + return $value; +} diff --git a/lfs/imspector b/lfs/imspector new file mode 100644 index 0000000000..31e358dcbd --- /dev/null +++ b/lfs/imspector @@ -0,0 +1,87 @@ +############################################################################### +# # +# IPFire.org - A linux based firewall # +# Copyright (C) 2010 Michael Tremer & Christian Schmidt # +# # +# This program is free software: you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation, either version 3 of the License, or # +# (at your option) any later version. # +# # +# This program is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program. If not, see . # +# # +############################################################################### + +############################################################################### +# Definitions +############################################################################### + +include Config + +VER = 0.9 + +THISAPP = imspector-$(VER) +DL_FILE = $(THISAPP).tar.gz +DL_FROM = $(URL_IPFIRE) +DIR_APP = $(DIR_SRC)/$(THISAPP) +TARGET = $(DIR_INFO)/$(THISAPP) +PROG = imspector +PAK_VER = 1 + +DEPS = "" + +############################################################################### +# Top-level Rules +############################################################################### + +objects = $(DL_FILE) + +$(DL_FILE) = $(DL_FROM)/$(DL_FILE) + +$(DL_FILE)_MD5 = 626abf7c2b8f15d56df679ad66624575 + +install : $(TARGET) + +check : $(patsubst %,$(DIR_CHK)/%,$(objects)) + +download :$(patsubst %,$(DIR_DL)/%,$(objects)) + +md5 : $(subst %,%_MD5,$(objects)) + +dist: + @$(PAK) + +############################################################################### +# Downloading, checking, md5sum +############################################################################### + +$(patsubst %,$(DIR_CHK)/%,$(objects)) : + @$(CHECK) + +$(patsubst %,$(DIR_DL)/%,$(objects)) : + @$(LOAD) + +$(subst %,%_MD5,$(objects)) : + @$(MD5) + +############################################################################### +# Installation Details +############################################################################### + +$(TARGET) : $(patsubst %,$(DIR_DL)/%,$(objects)) + @$(PREBUILD) + @rm -rf $(DIR_APP) && cd $(DIR_SRC) && tar zxf $(DIR_DL)/$(DL_FILE) + cd $(DIR_APP) && make install + -mv /usr/etc/imspector /etc/imspector + install -v -m 755 $(DIR_CONF)/imspector/imspector.conf /etc/imspector.conf + install -v -m 644 $(DIR_SRC)/config/backup/includes/imspector /var/ipfire/backup/addons/includes/imspector + chmod 755 /srv/web/ipfire/cgi-bin/imspector.cgi + chown nobody:nobody -R /var/log/imspector + @rm -rf $(DIR_APP) + @$(POSTBUILD) diff --git a/lfs/initscripts b/lfs/initscripts index a9fadf4de8..ffb18c942f 100644 --- a/lfs/initscripts +++ b/lfs/initscripts @@ -146,6 +146,9 @@ $(TARGET) : ln -sf ../init.d/motion /etc/rc.d/rc3.d/S99motion ln -sf ../init.d/motion /etc/rc.d/rc0.d/K01motion ln -sf ../init.d/motion /etc/rc.d/rc6.d/K01motion + ln -sf ../init.d/imspetor /etc/rc.d/rc3.d/S99imspetor + ln -sf ../init.d/imspetor /etc/rc.d/rc0.d/K01imspetor + ln -sf ../init.d/imspetor /etc/rc.d/rc6.d/K01imspetor ln -sf ../init.d/cyrus-sasl /etc/rc.d/rc0.d/K49cyrus-sasl ln -sf ../init.d/cyrus-sasl /etc/rc.d/rc3.d/S24cyrus-sasl ln -sf ../init.d/cyrus-sasl /etc/rc.d/rc6.d/K49cyrus-sasl diff --git a/make.sh b/make.sh index a7cda0919a..4e72c00839 100755 --- a/make.sh +++ b/make.sh @@ -643,6 +643,7 @@ buildipfire() { ipfiremake pound ipfiremake minicom ipfiremake ddrescue + ipfiremake imspector echo Build on $HOSTNAME > $BASEDIR/build/var/ipfire/firebuild cat /proc/version >> $BASEDIR/build/var/ipfire/firebuild echo >> $BASEDIR/build/var/ipfire/firebuild diff --git a/src/initscripts/init.d/imspector b/src/initscripts/init.d/imspector new file mode 100644 index 0000000000..7a5a986539 --- /dev/null +++ b/src/initscripts/init.d/imspector @@ -0,0 +1,54 @@ +#!/bin/sh +# Begin $rc_base/init.d/imspector + +. /etc/sysconfig/rc +. $rc_functions + +case "$1" in + start) + boot_mesg "Inserting imspector redirects..." + iptables -t nat -A CUSTOMPREROUTING -p tcp --destination-port 1863 -j REDIRECT --to-ports 16667 + iptables -t nat -A CUSTOMPREROUTING -p tcp --destination-port 5222 -j REDIRECT --to-ports 16667 + iptables -t nat -A CUSTOMPREROUTING -p tcp --destination-port 5223 -j REDIRECT --to-ports 16667 + iptables -t nat -A CUSTOMPREROUTING -p tcp --destination-port 5190 -j REDIRECT --to-ports 16667 + iptables -t nat -A CUSTOMPREROUTING -p tcp --destination-port 5050 -j REDIRECT --to-ports 16667 + iptables -t nat -A CUSTOMPREROUTING -p tcp --destination-port 6667 -j REDIRECT --to-ports 16667 + iptables -t nat -A CUSTOMPREROUTING -p tcp --destination-port 8074 -j REDIRECT --to-ports 16667 + + boot_mesg "Starting imspector Deamon..." + loadproc imspector -c /etc/imspector/imspector.conf + evaluate_retval + ;; + + stop) + boot_mesg "Stopping imspector Deamon..." + killproc /usr/sbin/imspector + evaluate_retval + + boot_mesg "Remove imspector redirects..." + iptables -t nat -D CUSTOMPREROUTING -p tcp --destination-port 1863 -j REDIRECT --to-ports 16667 + iptables -t nat -D CUSTOMPREROUTING -p tcp --destination-port 5222 -j REDIRECT --to-ports 16667 + iptables -t nat -D CUSTOMPREROUTING -p tcp --destination-port 5223 -j REDIRECT --to-ports 16667 + iptables -t nat -D CUSTOMPREROUTING -p tcp --destination-port 5190 -j REDIRECT --to-ports 16667 + iptables -t nat -D CUSTOMPREROUTING -p tcp --destination-port 5050 -j REDIRECT --to-ports 16667 + iptables -t nat -D CUSTOMPREROUTING -p tcp --destination-port 6667 -j REDIRECT --to-ports 16667 + iptables -t nat -D CUSTOMPREROUTING -p tcp --destination-port 8074 -j REDIRECT --to-ports 16667 + ;; + + restart) + $0 stop + sleep 1 + $0 start + ;; + + status) + statusproc /usr/sbin/imspector + ;; + + *) + echo "Usage: $0 {start|stop|restart|status}" + exit 1 + ;; +esac + +# End $rc_base/init.d/imspector -- 2.39.2