-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmailstats-no-such-user.php
120 lines (108 loc) · 4.63 KB
/
mailstats-no-such-user.php
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
#!/usr/local/bin/php
<?php
/**
Check for '5.1.1 No such user' mail rejections generated by the postfix config
in /etc/postfix/header_checks. If any matching rejections are found, log them in
a database and send a notification email.
*/
/*
* Copyright 2016, 2020 Shaun Cummiskey, <shaun@shaunc.com> <https://shaunc.com>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//Import MAILSTATS_DB_HOST, MAILSTATS_DB_USER, MAILSTATS_DB_PASS, MAILSTATS_DB_NAME, MAILSTATS_RECIPIENT
require_once('/etc/config/mailstats.conf');
//Get the last run timestamp
$conn = new mysqli(MAILSTATS_DB_HOST, MAILSTATS_DB_USER, MAILSTATS_DB_PASS,
MAILSTATS_DB_NAME);
if ($conn->connect_errno) {
echo 'Database is not available.';
exit(1);
}
$lastrun = $conn->query('SELECT timestamp FROM no_such_user_lastrun')->fetch_array()['timestamp'];
if (!is_numeric($lastrun) || $lastrun == 0) {
echo 'Value of no_such_user_lastrun.timestamp was invalid.';
exit(1);
}
//grep the maillog files for new entries
$return = null;
$output = null;
exec('/bin/grep "No such user" /var/log/maillog*', $output, $return);
//grep returns 0 if match, 1 if no match
if ($return === 0) {
$errors = '';
$recipients = array();
$loglines = array();
foreach ($output as $line) {
//Attempt to only process lines newer than $lastrun. This is iffy because timestamps in
//maillog don't include a year. We'll get false positives for awhile after a new year;
//we prevent recording these by using ON DUPLICATE KEY in the INSERT statement later.
list ($filename, $line) = explode(':', trim($line), 2);
$timestamp = strtotime(substr($line, 0, 15));
if ($timestamp > $lastrun) {
//Attempt to parse the sender, recipient, and origin MTA IP
if (preg_match('|from (\S+?)\[(.*?)\]; from=<(.*?)> to=<(.*?)> proto|mi',
$line, $matches)) {
$mta_host = $matches['1'];
$mta_ip = $matches['2'];
$sender = $matches['3'];
$recipient = $matches['4'];
//Log to the database
$stmt = $conn->prepare('INSERT no_such_user_rejections (sender, recipient, mta_host, mta_ip, timestamp) '
. 'VALUES (?,?,?,?,?) ON DUPLICATE KEY UPDATE id=id');
$stmt->bind_param('ssssi', $sender, $recipient, $mta_host,
$mta_ip, $timestamp);
$stmt->execute();
if ($conn->error != '') {
echo "Error: $conn->error\n";
$errors .= $conn->error . "\n";
}
//If we logged a row, track the recipient and log line for the notification mail
if ($stmt->affected_rows > 0) {
$loglines[$timestamp] = $line;
//Ternary operator won't work here; not sure why
if (@isset($recipients[$recipient])) {
$recipients[$recipient] ++;
}
else {
$recipients[$recipient] = 1;
}
}
// echo "$line \n Affected rows: " . $stmt->affected_rows . "\n";
}
}
}
//If we did anything, let's brag about it
if (count($loglines) > 0) {
//Build the email notification
$data = 'Mail rejections for "5.1.1 No such user" since '
. date('Y-m-d H:i:s', $lastrun) . " follow:\n\n";
arsort($recipients);
foreach ($recipients as $key => $value) {
$data .= '(' . $value . ') ' . $key . "\n";
}
$data .= "\nRaw log lines follow:\n\n";
ksort($loglines);
foreach ($loglines as $line) {
$data .= "$line\n";
}
if ($errors != '') {
$data = $errors . "\n" . $data;
}
//Send email notification
mail(MAILSTATS_RECIPIENT,
'[mailstats] 5.1.1 No such user rejections on ' . gethostname(),
$data, 'From: root@localhost');
}
//Update the last run timestamp
$conn->query('UPDATE no_such_user_lastrun SET timestamp=' . time());
}