File: dhcp_probe_notify

package info (click to toggle)
dhcp-probe 1.3.1-1.1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 1,316 kB
  • sloc: sh: 4,783; ansic: 2,400; perl: 381; xml: 51; makefile: 50
file content (153 lines) | stat: -rwxr-xr-x 5,703 bytes parent folder | download | duplicates (5)
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;
}