#!/usr/local/bin/perl # # wu-ftpd-log analyzer # # port of original bash/awk script # # Functions : # # - Create mail to ftpadmin with yesterdays statistics, including : # * anonymous uploads (complete logentries) # * total anonymous downloads (bytes, files) # * total realuser uploads (bytes, files) # * total realuser downloads (bytes, files) # # - Create html document with statistics, including : # * total anonymous uploads yesterday (bytes, files) # * total anonymous downloads yesterday (bytes, files) # * top-most-downloaded files # # WUFTPLOG = Name of logfile to open $WUFTPLOG = "/var/adm/ftpd/xferlog"; # FTPADMIN = where to report to. "|mail -s \"FTP server usage report\" ftpadmin" to mail or ">ftpreport" to save to file $FTPADMIN = "|mail -s \"FTP server usage report\" ftpadmin"; # HTMLOUT = Name of html file to create (with the >) $HTMLOUT = ">/home/www/htdocs/system/ftpusage.html"; # HTTITLE = Title for html page $HTTITLE ="Ftp Usage for ftp.cetis.hvu.nl"; # FTPURLPRE = prepended URL for most ftped files list $FTPURLPRE ="ftp://ftp.cetis.hvu.nl"; # That's it for configuration # Initialize counters $yesterdayanondlfiles = 0; $yesterdayanondlbytes = 0; $yesterdayanonulfiles = 0; $yesterdayanonulbytes = 0; $yesterdayuserdlbytes = 0; $yesterdayuserdlfiles = 0; $yesterdayuserulbytes = 0; $yesterdayuserulfiles = 0; $totalanondlfiles = 0; $totalanondlbytes = 0; # Find yesterday's date $yesmday=(localtime(time - 86400))[3]; $yesmonth=(Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec)[(localtime(time - 86400))[4]]; $yesyear=1900+(localtime(time - 86400))[5]; # open files open (LOGFILE,$WUFTPLOG) || die "Can't open $WUFTPLOG.\n"; open (HTMLFILE,$HTMLOUT) || die "Can't open $HTMLFILE for output.\n"; open (REPORT,$FTPADMIN) || die "Can't open $REPORT for output.\n"; # write header report printf REPORT "\nFTP server usage report for $yesmday $yesmonth $yesyear\n"; printf REPORT "\nIncoming anonymous files :\n"; printf REPORT "-------------------------------------------------------------\n"; # start reading while () { # Split the line into fields # split on both single and double spaces ($weekday,$month,$monthday,$time,$year,$duration,$host,$filesize,$filename,$transmode,$underscore,$direction,$usermode,$name,$protocol,$identopts,$identname) = split(/ +/o,$_); # work on fields # check for the total anonymous d/l if ( $usermode eq "a" && $direction eq "o" ) { $totalanondlfiles ++; $totalanondlbytes += $filesize; $filecount{$filename}++; } # check for yesterday if ( $yesyear == $year && $yesmonth eq $month && $yesmday == $monthday ) { # check type # realuser, incoming if ( $usermode eq "r" && $direction eq "i" ) { $yesterdayuserulfiles ++; $yesterdayuserulbytes += $filesize; } # realuser, outgoing elsif ( $usermode eq "r" && $direction eq "o" ) { $yesterdayuserdlfiles ++; $yesterdayuserdlbytes += $filesize; } # anonymous, incoming elsif ( $usermode eq "a" && $direction eq "i" ) { $yesterdayanonulfiles ++; $yesterdayanonulbytes += $filesize; printf REPORT "$time $host $filesize $filename $name\n"; } # anonymous, outgoing elsif ( $usermode eq "a" && $direction eq "o" ) { $yesterdayanondlfiles ++; $yesterdayanondlbytes += $filesize; } } } # Make the html report.. printf HTMLFILE "\n\n$HTTITLE\n\n\n"; printf HTMLFILE "

$HTTITLE for $yesmday $yesmonth $yesyear

\n
\n"; printf HTMLFILE "

Yesterday's anonymous downloads :

\n"; printf HTMLFILE "
Files : %u\n" , $yesterdayanondlfiles;
printf HTMLFILE "Bytes : %u
\n
\n", $yesterdayanondlbytes; printf HTMLFILE "

Yesterday's anonymous uploads :

\n"; printf HTMLFILE "
Files : %u\n" , $yesterdayanonulbytes;
printf HTMLFILE "Bytes : %u
\n
\n", $yesterdayanonulbytes; printf HTMLFILE "

Yesterday's realuser downloads :

\n"; printf HTMLFILE "
Files : %u\n" , $yesterdayuserdlfiles;
printf HTMLFILE "Bytes : %u
\n
\n", $yesterdayuserdlbytes; printf HTMLFILE "

Yesterday's realuser uploads :

\n"; printf HTMLFILE "
Files : %u\n" , $yesterdayuserulfiles;
printf HTMLFILE "Bytes : %u
\n
\n", $yesterdayuserulbytes; printf HTMLFILE "

Total anonymous downloads :

\n"; printf HTMLFILE "
Files : %u\n", $totalanondlfiles;
printf HTMLFILE "Bytes : %u
\n
\n", $totalanondlbytes; printf HTMLFILE "

Most anon-ftped files:

\n"; printf HTMLFILE "
\n";

# The tricky stuff : make two arrays of the names and number of times
# ftped of the anon-ftped files, sorted by descending number of times
# downloaded.
# This got me wondering for a time, until I dug around the 'Programming Perl'
# book (Nutshell).
# The solution : Sorting one array while looking in another array for the keys
# to sort on. (chapter 5 : 'Sorting an array by a computable field')
#
# Better good copied work then badly self-written.

@names=keys(%filecount);
local(@datanum,@sortarr);
foreach $file (keys(%filecount)){
	push(@datanum,$filecount{$file});
}

sub bydatanum { $datanum[$a] <=> $datanum[$b]; }

# here I do an extra trick : because I need the array twice (once for the names
# and once for the downloadcounters) I keep the sorting array in a temp array,
# to avoid doing a sort run twice.

@sortarr=reverse sort bydatanum $[..$#names;
@sortdata=@names[@sortarr];
@sortnum=@datanum[@sortarr];
undef %filecount;
undef @sortarr;

foreach $cnt ($[..$#sortdata){
	printf HTMLFILE "%5d %s\n", @sortnum[$cnt], $FTPURLPRE, @sortdata[$cnt], @sortdata[$cnt];
}

# finish HTML report

printf HTMLFILE "
Created with wu-ftpd-log.pl by Koos van den Hout.\n"; printf HTMLFILE "\n\n\n"; # finish report printf REPORT "-------------------------------------------------------------\n"; printf REPORT "Files : %u\n",$yesterdayanonulfiles; printf REPORT "Bytes : %u\n",$yesterdayanonulbytes; printf REPORT "-------------------------------------------------------------\n"; printf REPORT "Outgoing anonymous traffic :\n"; printf REPORT "-------------------------------------------------------------\n"; printf REPORT "Files : %u\n",$yesterdayanondlfiles; printf REPORT "Bytes : %u\n",$yesterdayanondlbytes; printf REPORT "-------------------------------------------------------------\n"; printf REPORT "Outgoing realuser traffic :\n"; printf REPORT "-------------------------------------------------------------\n"; printf REPORT "Files : %u\n",$yesterdayuserdlfiles; printf REPORT "Bytes : %u\n",$yesterdayuserdlbytes; printf REPORT "-------------------------------------------------------------\n"; printf REPORT "Incoming realuser traffic :\n"; printf REPORT "-------------------------------------------------------------\n"; printf REPORT "Files : %u\n",$yesterdayuserulfiles; printf REPORT "Bytes : %u\n",$yesterdayuserulbytes; printf REPORT "-------------------------------------------------------------\n"; #thatsit