[pptp-server] log analysing
Phil Verghese
philv at ridgerun.com
Mon Sep 11 16:12:20 CDT 2000
Here's a script I wrote to look through the logs and generate a report.
This is my first significant Perl script, so forgive me if it's not
optimal.
Phil
------------------------------------------------------
#!/usr/bin/perl
#
# pptplog.pl
# This program parses /var/log/messages looking for login attempts
# through pptpd & pppd to generate a report of failed, insecure and
# valid login attempts
#
# USAGE: pptplog [-f filename] [-kh]
# -f Specifies log file to read (default is /var/log/messages)
# -k Keep temporary files in /tmp (default is to delete these files)
# -n Do not send any mail (default is to send to root)
# -h Show usage
#
# Copyright (C) 2000 Phil Verghese <Phil_Verghese at bigfoot.com>
#
# 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 2
# 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, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
USA,
# or visit http://www.gnu.org/copyleft/gpl.html
use IO::File;
use Getopt::Std;
sub PPTP_Header;
sub WriteReport;
# Parse command line
$arg_err = getopts('f:knh');
if ($arg_err == 0 || $opt_h == 1) {
print "Usage: pptplog [-f filename] [-kh]\n";
print "-f Specifies log file to read (default is
/var/log/messages)\n";
print "-k Keep temporary files in /tmp (default is to delete these
files)\n";
print "-n Do not send any mail (default is to send to root)\n";
print "-h Show this message\n";
exit;
}
if ($opt_f ne "") {
$messages_file = $opt_f;
}
else {
$messages_file = "/var/log/messages";
}
# Input file
open(MESSAGES, $messages_file) or die "Can't open messages file:$!\n";
# Output files for failed logins, insecure logins, and valid logins
$failed_file = "/tmp/vpn_failed";
$insecure_file = "/tmp/vpn_insecure";
$valid_file = "/tmp/vpn_valid";
$report_file = "/tmp/vpn_report";
open(FAILED, "> " . $failed_file) or die "Can't open $! for output\n";
open(INSECURE, "> " . $insecure_file) or die "Can't open $! for output\n";
open(VALID, "> " . $valid_file) or die "Can't open $! for output\n";
print FAILED "-" x 10 . " Failed login attempts " . "-" x 10 . "\n";
print INSECURE "-" x 10 . " Insecure logins " . "-" x 10 . "\n";
print VALID "-" x 10 . " Valid logins " . "-" x 10 . "\n";
while ($line = <MESSAGES>) {
if ($line =~ /pptpd\[\d+\]:\sCTRL:.*control connection started/) {
PPTP_Header; # Process the start of the PPTP connection
}
elsif ($line =~ /pppd\[(\d+)\]:\s.*peer authentication/) {
# User authentication
$ppp_id = $1;
$_ = $line;
if (/\d+\]: ([\w\-]+)/) {
$chaptype{$ppp_id} = $1;
}
if (/authentication (\w+) for.* (\w+)$/) {
$username{$ppp_id} = $2;
if ($1 eq "failed") {
$loginok{$ppp_id} = 0;
}
else {
$loginok{$ppp_id} = 1;
}
}
}
elsif ($line =~ /pppd\[(\d+)\]:\s.*compression/i) {
$ppp_id = $1;
$_ = $line;
if (/Compression disabled/) {
$crypt{$ppp_id} = "NONE";
}
elsif (/(MPPE \d+ bit)/) {
$crypt{$ppp_id} = $1;
}
elsif (/Deflate.*compression enabled/) {
$crypt{$ppp_id} = "Deflate";
}
}
elsif ($line =~ /pptpd\[(\d+)\]:\sCTRL: PTY read or GRE write failed/) {
$errors{$1} .= "r/w ";
}
elsif ($line =~ /pptpd\[(\d+)\]:\sCTRL: Session timed out, ending call/)
{
$errors{$1} .= "session-timeout ";
}
elsif ($line =~ /pptpd\[(\d+)\]:\sLCP: timeout sending Config/) {
$errors{$1} .= "cfg-req-timeout ";
}
elsif ($line =~ /pptpd\[(\d+)\]:\sCTRL: EOF or bad error reading ctrl/)
{
$pptp_id = $1;
if (!($errors{$pptp_id} =~ /ctrl-packet-bad/)) { # Only log one bad ctrl
packet
$errors{$pptp_id} .= "ctrl-packet-bad ";
}
}
elsif ($line =~ /pptpd\[(\d+)\]:\sGRE: Discarding/) {
$pptp_id = $1;
if (!($errors{$pptp_id} =~ /GRE-discard/)) { # Only log one GRE error
$errors{$pptp_id} .= "GRE-discard ";
}
}
elsif ($line =~ /pppd\[(\d+)\]: Connect time (\d+\.\d+) min/) {
$time{$1} = $2;
}
elsif ($line =~ /pppd\[(\d+)\]: Sent (\d+) by.* (\d+) by/) {
$sent{$1} = $2;
$rcvd{$1} = $3;
}
elsif ($line =~ /pppd\[(\d+)\]: Exit/) {
$ppp_id = $1;
WriteReport;
}
}
# Write out blank lines for readability
print FAILED "\n";
print INSECURE "\n";
close (FAILED);
close (INSECURE);
close (VALID);
`cat $failed_file $insecure_file $valid_file > $report_file`;
if ($opt_n != 1) {
`mail -s "VPN Report" root < $report_file`;
}
if ($opt_k != 1) {
`rm $failed_file $insecure_file $valid_file $report_file`;
}
#########################################################################
# Process the start of the PPTP connection. Hash tables are used to track
# information because it's possible to having overlapping sessions with
# starts & ends interleaved.
sub PPTP_Header {
$_ = $line;
if (/^(\w{3}\s+\d+\s+..:..:..).*pptpd\[(\d+)\]:\sCTRL: Client
(\d+.\d+.\d+.\d+)/)
{
$date = $1;
$pptp_id = $2;
$ip = $3;
}
# Find the line that launches pppd so we can track that PID
while ($line = <MESSAGES>) {
if ($line =~ /pppd\[(\d+)\]:\s.*started by/) {
$ppp_id = $1;
last;
}
}
# Track values that are keyed to the PID of pptpd. This is needed
because
# it's possible to have interleaving start/end pptpd connection messages
$ppp_id_hash{$pptp_id} = $ppp_id; # The PID of the pppd that was
launched by pptpd
$pptp_id_hash{$ppp_id} = $pptp_id; # The PID of the pptp that launched
this pppd
$date_hash{$pptp_id} = $date;
$ip_hash{$pptp_id} = $ip;
}
#########################################################################
# Finished with one session, so write to the appropriate report file
sub WriteReport {
$pptp_id = $pptp_id_hash{$ppp_id};
# Fixup null strings
if ($crypt{$ppp_id} eq "") {
$crypt{$ppp_id} = "Empty";
}
if ($errors{$pptp_id} eq "") {
$errors{$pptp_id} = "none";
}
# Failed login?
if ($loginok{$ppp_id} == 0)
print FAILED "$date_hash{$pptp_id} USER:$username{$ppp_id}
IP:$ip_hash{$pptp_id}\n";
}
# Insecure login?
elsif (($chaptype{$ppp_id} ne "MSCHAP-v2") ||
(($crypt{$ppp_id} ne "MPPE 128 bit") && ($crypt{$ppp_id} ne "MPPE 40
bit"))) {
print INSECURE "$date_hash{$pptp_id} USER:$username{$ppp_id}
IP:$ip_hash{$pptp_id} ";
print INSECURE "AUTH:$chaptype{$ppp_id} CRYPT:$crypt{$ppp_id} ";
print INSECURE "TIME:$time{$ppp_id} SENT:$sent{$ppp_id} RCVD:$rcvd{$ppp_id}
ERRS:$errors{$pptp_id} \n";
}
# Valid login
else {
print VALID "$date_hash{$pptp_id} USER:$username{$ppp_id}
IP:$ip_hash{$pptp_id} ";
print VALID "AUTH:$chaptype{$ppp_id} CRYPT:$crypt{$ppp_id} ";
print VALID "TIME:$time{$ppp_id} SENT:$sent{$ppp_id} RCVD:$rcvd{$ppp_id}
ERRS:$errors{$pptp_id} \n";
}
}
More information about the pptp-server
mailing list