1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153
|
#!/usr/local/bin/perl -w
# dhcp_probe_notify calling_prog_name interface_name IPaddress MACaddress
#
# External program called by dhcp_probe upon response of a response from an unexpected BootP/DHCP server.
#
# This version obeys the syntax provided by the old 'alert_program_name' statement,
# not the syntax provided by the newer 'alert_program_name2' statement.
# Use of the newer syntax is preferred; dhcp_probe_notify2 supports that newer syntax.
#
# Called via specification of 'alert_program_name' in /etc/dhcp_probe.cf file.
#
# Arguments:
# calling_prog_name the name of the calling program (e.g. 'dhcp_probe')
# interface_name the name of the interface on which the unexpected response packet arrived (e.g. 'qfe0')
# IPaddress the IP source address of the unexpected response packet (e.g. '192.168.0.1')
# MACaddress the Ethernet source address of the unexpected response packet (e.g. '0:1:2:3:4:5')
#
# May send email subject to throttling.
# May send page subject to throttling.
#
# You will need to edit the definitions below.
#
#
# XXX Sometimes our calls to THROTTLE_MAIL_CMD or THROTTLE_PAGE_CMD command fail.
# I've made the possible failures (open() and close() calls) more verbose when they fail,
# to attempt to provide more info, but I still don't know what causes the failures.
#
# Irwin Tillman
use Sys::Hostname;
use Sys::Syslog qw(:DEFAULT setlogsock);
use Time::HiRes qw(gettimeofday); # from CPAN
use strict;
my $SYSLOG_FACILITY="daemon"; # name of facility to use if syslogging
my $SYSLOG_OPT = 'pid,cons'; # syslog options to use if syslogging, ignored otherwise
use vars qw($VERBOSE);
$VERBOSE = 1; # produce more verbose messages
# we may send one piece of mail this way, subject to frequency throttling.
# Use these for regular email (not a page).
use vars qw($THROTTLE_MAIL_CMD $THROTTLE_MAIL_TIMEOUT $THROTTLE_MAIL_FROM $THROTTLE_MAIL_RECIPIENT $THROTTLE_MAIL_RECIPIENT_TEST $THROTTLE_MAIL_SUBJECT);
$THROTTLE_MAIL_CMD = "/usr/local/etc/mail-throttled"; # set to "" to disable
$THROTTLE_MAIL_TIMEOUT = 600; # seconds
$THROTTLE_MAIL_FROM = "root";
$THROTTLE_MAIL_RECIPIENT = "root someone\@example.org";
$THROTTLE_MAIL_SUBJECT = "unexpected BootP/DHCP server";
# we may also send another piece of email this way, subject to frequency throttling.
# Use these for paging.
use vars qw($THROTTLE_PAGE_CMD $THROTTLE_PAGE_TIMEOUT $THROTTLE_PAGE_RECIPIENT);
$THROTTLE_PAGE_CMD = "/usr/local/etc/mail-throttled"; # set to "" to disable
$THROTTLE_PAGE_TIMEOUT = 600; # seconds
$THROTTLE_PAGE_RECIPIENT = "rootpager someones-pager\@example.org";
# You shouldn't need to edit anything below
(my $prog = $0) =~ s/.*\///;
# init our use of syslog
# setlogsock('unix'); # talk to syslog with UNIX domain socket, not INET domain. XXX causes failure in Solaris 7
openlog($prog, $SYSLOG_OPT, $SYSLOG_FACILITY);
my $hostname = hostname();
my ($calling_program, $ifname, $ip_src, $ether_src) = @ARGV;
my ($seconds, $microseconds) = gettimeofday; # from Time::HiRes on CPAN
my $timestamp = scalar(localtime($seconds));
$timestamp =~ s/(\d\d:\d\d:\d\d)/$1.$microseconds/; # glue microsends to end of seconds
if ($THROTTLE_MAIL_CMD) {
# This command suppresses the message if it's sent a message to 'key' within 'throttle_seconds'
# I use the calling program's name and the offender's hardware address as the key.
unless (open(THROTTLE_MAIL, "| $THROTTLE_MAIL_CMD -l -k ${calling_program}_mail_$ether_src -t $THROTTLE_MAIL_TIMEOUT -f \"$THROTTLE_MAIL_FROM\" -r \"$THROTTLE_MAIL_RECIPIENT\" -s\"$THROTTLE_MAIL_SUBJECT (MAC=${ether_src}, IP=${ip_src})\"")) {
my_message('LOG_ERR', "${prog}: failure trying to send throttled email: can't execute '${THROTTLE_MAIL_CMD}': open(): $!");
exit 20;
}
print THROTTLE_MAIL
$timestamp, "\n",
"\n",
"$calling_program detected an unexpected BootP/DHCP server.\n",
"$hostname interface=${ifname}, IP source=${ip_src}, Ethernet source=${ether_src}\n";
print THROTTLE_MAIL "\nThis means there *is* a rogue BootP/DHCP server operating.\n" if $VERBOSE;
unless (close(THROTTLE_MAIL)) {
my_message('LOG_ERR',
"${prog}: failure trying to send throttled email: error executing '${THROTTLE_MAIL_CMD}': close(): " .
($! ?
"syserr closing pipe: $!"
:
"wait status $? from pipe"
) .
"\n"
);
exit 21;
}
}
if ($THROTTLE_PAGE_CMD) {
# This command suppresses the message if it's sent a message to 'key' within 'throttle_seconds'
# I use the calling program's name and the offender's hardware address as the key.
unless (open(THROTTLE_PAGE, "| $THROTTLE_PAGE_CMD -l -k ${calling_program}_page_$ether_src -t $THROTTLE_PAGE_TIMEOUT -r \"$THROTTLE_PAGE_RECIPIENT\"")) {
my_message('LOG_ERR', "${prog}: failure trying to send throttled page: can't execute '${THROTTLE_PAGE_CMD}': open(): $!\n");
exit 30;
}
print THROTTLE_PAGE "rogue DHCP server IP=$ip_src MAC=$ether_src seen via $hostname interface $ifname\n";
print THROTTLE_PAGE "This means there *is* a rogue BootP/DHCP server operating.\n" if $VERBOSE;
unless (close(THROTTLE_PAGE)) {
my_message('LOG_ERR',
"${prog}: failure trying to send throttled page: error executing '${THROTTLE_PAGE_CMD}': close(): " .
($! ?
"syserr closing pipe: $!"
:
"wait status $? from pipe"
) .
"\n"
);
exit 31;
}
}
exit 0;
sub my_message {
# Call with a syslog priority constant and a message string.
# We write the message to syslog, using the specified priority.
# Your message should not contain a newline.
my($priority, $msg) = @_;
syslog($priority, $msg);
return;
}
|