logwatch-7.12/0000775000211400021140000000000014744023426013453 5ustar logwatchlogwatchlogwatch-7.12/README0000664000211400021140000000704114743365001014332 0ustar logwatchlogwatchWhat is Logwatch? Logwatch is a customizable, pluggable log-monitoring system. It will go through your logs for a given period of time and make a report in the areas that you wish with the detail that you wish. Perl 5.8 or newer is recommended to run Logwatch. [But it will work with 5.6.1+] ------------------------------------------------------------------ How do I install it? An rpm file is available. The following describes how to install if you prefer to install from the source tar file: The simplest setup is to follow the default configurations. Simply make a directory (/usr/share/logwatch) and copy the scripts, conf, and lib directories into that directory. You will also need to make the /etc/logwatch dir if you want to make configuration changes without having to modify the default config files. The steps to follow to get the default setup going are something like this. [However we recommend using the install_logwatch.sh script when possible.] Untar logwatch. cd logwatch-x.x mkdir /etc/logwatch mkdir /etc/logwatch/scripts mkdir /etc/logwatch/conf mkdir /etc/logwatch/conf/logfiles mkdir /etc/logwatch/conf/services touch /etc/logwatch/conf/logwatch.conf touch /etc/logwatch/conf/ignore.conf touch /etc/logwatch/conf/override.conf mkdir /usr/share/logwatch mkdir /usr/share/logwatch/dist.conf mkdir /usr/share/logwatch/dist.conf/logfiles mkdir /usr/share/logwatch/dist.conf/services mv conf/ /usr/share/logwatch/default.conf mv scripts/ /usr/share/logwatch/scripts mv lib /usr/share/logwatch/lib mkdir /var/cache/logwatch ln -s /usr/share/logwatch/scripts/logwatch.pl /etc/cron.daily/0logwatch ln -s /usr/share/logwatch/scripts/logwatch.pl /usr/sbin/logwatch Instead of cron you may also use systemd timer unit for scheduled runs: mv logwatch.service /etc/systemd/system mv logwatch.timer /etc/systemd/system systemd enable logwatch.timer This is only a suggestion and if you look at the logwatch.pl script and the logwatch.conf file you will see that you can configure the system layout in many different ways. See also the file HOWTO-Customize-LogWatch for more information. ------------------------------------------------------------------ How do I use it? Well, it should pretty much work on its own, sending you an email every night. For more configuration options, run 'logwatch --help' or edit /usr/share/logwatch/default.conf/logwatch.conf or /etc/logwatch/logwatch.conf. See the file HOWTO-Customize-LogWatch for more information. You can also use it from the command line (as documented in the man page). ------------------------------------------------------------------ If you want me to add support for a new set of log entries, please email me all the log entries you can from that service from as many machines as possible! Or, better yet, read the HOWTO-Customize-LogWatch and write your own! ------------------------------------------------------------------ Mailing lists available! Logwatch Development List: For discussion about Logwatch development. To Subscribe: visit https://lists.sourceforge.net/lists/listinfo/logwatch-devel Send Mail To: logwatch-devel@lists.sourceforge.net ------------------------------------------------------------------ Please send suggestions, bug reports, and patches to: logwatch-devel@lists.sourceforge.net Please ask questions at: logwatch@kaybee.org ------------------------------------------------------------------ AUTHOR CONTACT INFORMATION: Kirk Bauer http://www.kaybee.org/kirk/ Newest releases can be found at: https://sourceforge.net/projects/logwatch/files/ logwatch-7.12/postfix-logwatch.10000664000211400021140000010636314743365003017047 0ustar logwatchlogwatch.TH POSTFIX-LOGWATCH 1 .ad .fi .SH NAME postfix-logwatch \- A Postfix log parser and analysis utility .SH "SYNOPSIS" .na .nf .fi \fBpostfix-logwatch\fR [\fIoptions\fR] [\fIlogfile ...\fR] .SH DESCRIPTION .ad .fi The \fBpostfix-logwatch\fR(1) utility is a Postfix MTA log parser that produces summaries, details, and statistics regarding the operation of Postfix. .PP This utility can be used as a standalone program, or as a Logwatch filter module to produce Postfix summary and detailed reports from within Logwatch. .PP \fBPostfix-logwatch\fR is able to produce a wide range of reports with data grouped and sorted as much as possible to reduce noise and highlight patterns. Brief summary reports provide a quick overview of general Postfix operations and message delivery, calling out warnings that may require attention. Detailed reports provide easy to scan, hierarchically-arranged and organized information, with as much or little detail as desired. .PP \fBPostfix-logwatch\fR outputs two principal sections: a \fBSummary\fR section and a \fBDetailed\fR section. For readability and quick scanning, all event or hit counts appear in the left column, followed by brief description of the event type, and finally additional statistics or count representations may appear in the rightmost column. The following segment from a sample Summary report illustrates: .RS 4 .nf ****** Summary ******************************************** 81 *Warning: Connection rate limit reached (anvil) 146 Warned 68.310M Bytes accepted 71,628,177 97.645M Bytes delivered 102,388,245 ======== ================================================ 3464 Accepted 41.44% 4895 Rejected 58.56% -------- ------------------------------------------------ 8359 Total 100.00% ======== ================================================ .fi .RE 0 The report warns that anvil's connection rate was hit 81 times, a Postfix access check WARN action was logged 146 times, and a total of 68.310 megabytes (71,628,177 bytes) were accepted into the Postfix system, delivering 97.645 megabytes of data (due to multiple recipients). The Accepted and Rejected lines show that Postfix accepted 3464 (41.44% of the total messages) and rejected 4895 (the remaining 58.56%) of the 8359 total messages (temporary rejects show up elsewhere). .PP There are dozens of sub-sections available in the \fBDetailed\fR report, each of whose output can be controlled in various ways. Each sub-section attempts to group and present the most meaningful data at superior levels, while pushing less useful or \fInoisy\fR data towards inferior levels. The goal is to provide as much benefit as possible from smart grouping of data, to allow faster report scanning, pattern identification, and problem solving. Data is always sorted in descending order by count, and then numerically by IP address or alphabetically as appropriate. .PP The following MX errors segment from a sample \fBDetailed\fR report illustrates the basic hierarchical level structure of \fBpostfix-logwatch\fR: .RS 4 .nf ****** Detailed ******************************************* 261 MX errors -------------------------------------- 261 Unable to look up MX host 222 Host not found 73 foolishspammer.local 60 completely.bogus.domain.example 11 friend.example.com 39 No address associated with hostname 23 dummymx.sample.net 16 pushn.spam.sample.com .fi .RE 0 .PP The \fBpostfix-logwatch\fR utility reads from STDIN or from the named Postfix \fIlogfile\fR. Multiple \fIlogfile\fR arguments may be specified, each processed in order. The user running \fBpostfix-logwatch\fR must have read permission on each named log file. .PP .SS Options The options listed below affect the operation of \fBpostfix-logwatch\fR. Options specified later on the command line override earlier ones. Any option may be abbreviated to an unambiguous length. .IP "\fB-f \fIconfig_file\fR" .PD 0 .IP "\fB--config_file \fIconfig_file\fR" .PD Use an alternate configuration file \fIconfig_file\fR instead of the default. This option may be used more than once. Multiple configuration files will be processed in the order presented on the command line. See \fBCONFIGURATION FILE\fR below. .IP "\fB--debug \fIkeywords\fR" Output debug information during the operation of \fBpostfix-logwatch\fR. The parameter \fIkeywords\fR is one or more comma or space separated keywords. To obtain the list of valid keywords, use --debug xxx where xxx is any invalid keyword. .IP "\fB--[no]delays\fR" Enables (disables) output of the message delays percentiles report. The delays percentiles report shows percentiles for each of the 4 delivery latency times reported by Postfix (available in version 2.3 and later) in the form \fBdelays=\fIa\fR/\fIb\fR/\fIc\fR/\fId\fR, where \fIa\fR is the amount of time before the active queue (includes time for previous delivery attempts and time in the deferred queue), \fIb\fR is the amount of time in the active queue up to delivery agent handoff, \fIc\fR is the amount of time spent making connections (including DNS, HELO and TLS) and \fId\fR is the amount of time spent delivering the message. The total delay shown comes from the \fBdelay=\fR field in a message delivery log line. \fBNote:\fR This report may consume a large amount of memory; if you have no use for it, disable the delays report. .IP "\fB--delays_percentiles \fIp1 [p2 ...]\fR" Specifies the percentiles to be used in the message delays percentiles report. The percentiles \fIp1\fR, \fIp2\fR, \fI...\fR range from 0 to 100, inclusively. The order of the list is not sorted - the report will output the percentiles columns in the order you specify. .IP "\fB--detail \fIlevel\fR" Sets the maximum detail level for \fBpostfix-logwatch\fR to \fIlevel\fR. This option is global, overriding any other output limiters described below. The \fBpostfix-logwatch\fR utility produces a \fBSummary\fR section, a \fBDetailed\fR section, and additional report sections. With \fIlevel\fR less than 5, \fBpostfix-logwatch\fR will produce only the \fBSummary\fR section. At \fIlevel\fR 5 and above, the \fBDetailed\fR section, and any additional report sections are candidates for output. Each incremental increase in \fIlevel\fR generates one additional hierarchical sub-level of output in the \fBDetailed\fR section of the report. At \fIlevel\fR 10, all levels are output. Lines that exceed the maximum report width (specified with \fBmax_report_width\fR) will be cut. Setting \fIlevel\fR to 11 will prevent lines in the report from being cut (see also \fB--line_style\fR). .IP "\fB--help\fR" Print usage information and a brief description about command line options. .IP "\fB--ignore_service \fIpattern\fR" Ignore log lines that contain the postfix service name \fBpostfix/\fIservice\fR. The parameter \fIservice\fR is a regular expression. \fBNote:\fR if you use parenthesis in your regular expression, be sure they are cloistering and not capturing: use \fB(?:\fIpattern\fB)\fR instead of \fB(\fIpattern\fB)\fR. .IP "\fB--ipaddr_width \fIwidth\fR" Specifies that IP addresses in address/hostname pairs should be printed with a field width of \fIwidth\fR characters. Increasing the default may be useful for systems using long IPv6 addresses. .IP "\fB-l limiter=levelspec\fR" .PD 0 .IP "\fB--limit limiter=levelspec\fR" .PD Sets the level limiter \fIlimiter\fR with the specification \fIlevelspec\fR. .IP "\fB--line_style \fIstyle\fR" Specifies how to handle long report lines. Three styles are available: \fBfull\fR, \fBtruncate\fR, and \fBwrap\fR. Setting \fIstyle\fR to \fBfull\fR will prevent cutting lines to \fBmax_report_width\fR; this is what occurs when \fBdetail\fR is 11 or higher. When \fIstyle\fR is \fBtruncate\fR (the default), long lines will be truncated according to \fBmax_report_width\fR. Setting \fIstyle\fR to \fBwrap\fR will wrap lines longer than \fBmax_report_width\fR such that left column hit counts are not obscured. This option takes precedence over the line style implied by the \fBdetail\fR level. The options \fB--full\fR, \fB--truncate\fR, and \fB--wrap\fR are synonyms. .IP "\fB--[no]long_queue_ids\fR" Enables (disables) interpretation of long queue IDs in Postfix (>= 2.9) logs. .IP "\fB--nodetail\fR" Disables the \fBDetailed\fR section of the report, and all supplemental reports. This option provides a convenient mechanism to quickly disable all sections under the \fBDetailed\fR report, where subsequent command line options may re-enable one or more sections to create specific reports. .IP "\fB--[no]summary\fR" .IP "\fB--show_summary\fR" Enables (disables) displaying of the the \fBSummary\fR section of the report. The variable postfix_Show_Summary in used in a configuration file. .IP "\fB--recipient_delimiter \fIdelimiter\fR" Split email delivery addresses using the recipient delimiter character \fIdelimiter\fR. This should generally match the \fBrecipient_delimiter\fR specified in the Postfix parameter file \fBmain.cf\fR, or the default value indicated in \fBpostconf -d recipient_delimiter\fR. This is very useful for obtaining per-alias statistics when a recipient delimiter is used for mail delivery. .IP "\fB--reject_reply_patterns \fIr1 [r2 ...]\fR" Specifies the list of reject reply patterns used to create reject groups. Each entry in the list \fIr1 [r2 ...]\fR must be either a three character regular expression reply code of the form [45][0-9.][0-9.], or the word "Warn". The "." in the regular expression is a literal dot which matches any reject reply subcode; this wildcarding allows creation of broad rejects groups. List order is preserved, in that reject reports will be output in the same order as the entries in the list. Specific reject reply codes will take priority over wildcard patterns, regardless of the list order. The default list is "5.. 4.. Warn", which creates three groups of rejects: permanent rejects, temporary reject failures, and reject warnings (as in warn_if_reject). This feature allows, for example, distinguishing 421 transmission channel closures from 45x errors (eg. 450 mailbox unavailable, 451 local processing errors, 452 insufficient storage). Such a grouping would be configured with the list: "421 4.. 5.. Warn". See RFC 2821 for more information about reply codes. See also \fBCONFIGURATION FILE\fR regarding using \fBreject_reply_patterns\fR within a configuration file. .IP "\fB--[no]sect_vars\fR" .PD 0 .IP "\fB--show_sect_vars \fIboolean\fR" .PD Enables (disables) supplementing each \fBDetailed\fR section title with the name of that section's level limiter. The name displayed is the command line option (or configuration file variable) used to limit that section's output. . With the large number of level limiters available in \fBpostfix-logwatch\fR, this a convenient mechanism for determining exactly which level limiter affects a section. .IP "\fB--syslog_name \fInamepat\fR" Specifies the syslog service name that \fBpostfix-logwatch\fR uses to match syslog lines. Only log lines whose service name matches the perl regular expression \fInamepat\fR will be used by \fBpostfix-logwatch\fR; all non-matching lines are silently ignored. This is useful when a pre-installed Postfix package uses a name other than the default (\fBpostfix\fR), or when multiple Postfix instances are in use and per-instance reporting is desired. The pattern \fInamepat\fR should match the \fBsyslog_name\fR configuration parameter specified in the Postfix parameter file \fBmain.cf\fR, the master control file \fBmaster.cf\fR, or the default value as indicated by the output of \fBpostconf -d syslog_name\fR. \fBNote:\fR if you use parenthesis in your regular expression, be sure they are cloistering and not capturing: use \fB(?:\fIpattern\fB)\fR instead of \fB(\fIpattern\fB)\fR. .IP "\fB--[no]unknown\fR" .PD 0 .IP "\fB--show_unknown \fIboolean\fR" .PD Enables (disables) display of the postfix-generated name of 'unknown' in formated IP/hostname pairs in \fBDetailed\fR reports. Default: enabled. .IP "\fB--version\fR" Print \fBpostfix-logwatch\fR version information. .SS Level Limiters .PP The output of every section in the \fBDetailed\fR report is controlled by a level limiter. The name of the level limiter variable will be output when the \fBsect_vars\fR option is set. Level limiters are set either via command line in standalone mode with \fB--limit \fIlimiter\fB=\fIlevelspec\fR option, or via configuration file variable \fB$postfix_\fIlimiter\fB=\fIlevelspec\fR. Each limiter requires a \fIlevelspec\fR argument, which is described below in \fBLEVEL CONTROL\fR. The list of level limiters is shown below. There are several level limiters that control reject sub-sections (eg. \fBrejectbody\fR, \fBrejectsender\fR, etc.). Because the list of reject variants is not known until runtime after \fBreject_reply_patterns\fR is seen, these reject limiters are shown below generically, with the prefix \fB###\fR. To use one of these reject limiters, substitute \fB###\fR with one of the reject reply codes in effect, replacing each dot with an \fBx\fR character. For example, using the default \fBreject_reply_patterns\fR list of "5.. 4.. Warn", three \fBrejectbody\fR variants are valid: \fB--limit 5xxrejectbody\fR, \fB--limit 4xxrejectbody\fR and \fB--limit warnrejectbody\fR. As a convenience, you may entirely eliminate the \fB###\fR prefix, and instead use the bare \fBreject\fIXXX\fR option, and all reject level limiter variations will be auto-generated based on the \fBreject_reply_patterns\fR list. For example, the command line segment: .nf ... --reject_reply_patterns "421 5.." \\ --limit rejectrbl="1:10:" .fi would automatically become: .nf ... --reject_reply_patterns "421 5.." \\ --limit 421rejectrbl="1:10:" --limit 5xxrejectrbl="1:10:" .fi See \fBreject_reply_patterns\fR above, and comments in the configuration file \fBpostfix-logwatch.conf\fR. .de TQ . br . ns . TP \\$1 .. [ THIS SECTION IS NOT YET COMPLETE ] .PD 0 .IP "\fBAttrError" Errors obtaining attribute data from service. .IP "\fBBCCed" Messages that triggered access, header_checks or body_checks BCC action. (postfix 2.6 experimental branch) .IP "\fBBounceLocal" .IP "\fBBounceRemote" Local and remote bounces. A bounce is considered a local bounce if the relay was one of none, local, virtual, avcheck, maildrop or 127.0.0.1. .IP "\fBByIpRejects" Regrouping by client host IP address of all 5xx (permanent) reject variants. .IP "\fBCommunicationError" Postfix errors talking to one of its services. .IP "\fBAnvil" Anvil rate or concurrency limits. .IP "\fBConnectionInbound" Connections made to the \fBsmtpd\fR server. .IP "\fBConnectionLostInbound" Connections lost to the \fBsmtpd\fR server. .IP "\fBConnectionLostOutbound" Connections lost during \fBsmtp\fR communications with remote MTA. .IP "\fBConnectToFailure" Failures reported by \fBsmtp\fR when connecting to remote MTA. .IP "\fBDatabaseGeneration" Warnings noted when binary database map file requires \fBpostmap\fR update from newer source file. .IP "\fBDeferrals" .IP "\fBDeferred" Message delivery deferrals. A single \fBdeferred\fR message will have one or more \fBdeferrals\fR many times. .IP "\fBDeliverable" Address verification indicates recipient address is deliverable. .IP "\fBDelivered" Number of messages handed-off to a delivery agent such as local or virtual. .IP "\fBDiscarded" Messages that triggered access, header_checks or body_checks DISCARD action. .IP "\fBDNSError" Any one of several errors encountered during DNS lookups. .IP "\fBEnvelopeSenderDomains" List of sending domains. (2 levels: envelope sender domain, localpart) .IP "\fBEnvelopeSenders" List of envelope senders. (1 level: envelope sender) .IP "\fBError" Postfix general \fBerror\fR messages. .IP "\fBFatalConfigError" Fatal main.cf or master.cf configuration errors. .IP "\fBFatalError" Postfix general \fBfatal\fR messages. .IP "\fBFiltered" Messages that triggered access, header_checks or body_checks FILTER action. .IP "\fBForwarded" Messages forwarded by MDA for one address class to another (eg. local -> virtual). .IP "\fBHeloError" XXXXXXXXXXX .IP "\fBHold" Messages that were placed on hold by postsuper, or triggered by access, header_checks or body_checks HOLD action. .IP "\fBHostnameValidationError" Invalid hostname detected. .IP "\fBHostnameVerification" Lookup of hostname does not map back to the IP of the peer (ie. the remote system connecting to \fBsmtpd\fR). Also known as forward-confirmed reverse DNS (FCRDNS). When the reverse name has no DNS entry, the message "host not found, try again" is included; otherwise, it is not (e.g. when the reverse has some IP address, but not the one Postfix expects). .IP "\fBIllegalAddrSyntax" Illegal syntax in an email address provided during the MAIL FROM or RCPT TO dialog. .IP "\fBLdapError" Any LDAP errors during LDAP lookup. .IP "\fBMailerLoop" An MX lookup for the best mailer to use to deliver mail would result in a sending to ourselves. .IP "\fBMapProblem" Problem with an access table map that needs correcting. .IP "\fBMessageWriteError" Postfix encountered an error when trying to create a message file somewhere in the spool directory. .IP "\fBNumericHostname" A hostname was found that was numeric, instead of alphabetic. .IP "\fBPanicError" Postfix general \fBpanic\fR messages. .IP "\fBPixWorkaround" Workarounds were enabled to avoid remote Cisco PIX SMTP "fixups". .IP "\fBPolicydWeight" Summarization of policyweight/policydweight results. .IP "\fBPolicySpf" Summarization of PolicySPF results. .IP "\fBPostgrey" Summarization of Postgrey results. .IP "\fBPostscreen" Summarization of 2.7's postscreen and verify services. .IP "\fBDNSBLog" Summarization of 2.7's dnsblog service. .IP "\fBPrepended" Messages that triggered header_checks or body_checks PREPEND action. .IP "\fBProcessExit" Postfix services that exited unexpectedly. .IP "\fBProcessLimit" A Postfix service has reached or exceeded the maximum number of processes allowed. .IP "\fBQueueWriteError" Problems writing a Postfix queue file. .IP "\fBRblError" Lookup errors for RBLs. .IP "\fBRedirected" Messages that triggered access, header_checks or body_checks REDIRECT action. .IP "\fB###RejectBody" Messages that triggered body_checks REJECT action. .IP "\fB###RejectClient" Messages rejected by client access controls (smtpd_client_restrictions). .IP "\fB###RejectConfigError" Message rejected due to server configuration errors. .IP "\fB###RejectContent" Messages rejected by message_reject_characters. .IP "\fB###RejectData" Messages rejected at DATA stage in SMTP conversation (smtpd_data_restrictions). .IP "\fB###RejectEtrn" Messages rejected at ETRN stage in SMTP conversation (smtpd_etrn_restrictions). .IP "\fB###RejectHeader" Messages that triggered header_checks REJECT action. .IP "\fB###RejectHelo" Messages rejected at HELO/EHLO stage in SMTP conversation (smtpd_helo_restrictions). .IP "\fB###RejectInsufficientSpace" Messages rejected due to insufficient storage space. .IP "\fB###RejectLookupFailure" Messages rejected due to temporary DNS lookup failures. .IP "\fB###RejectMilter" Milter rejects. No reject reply code is available for these rejects, but an extended 5.7.1 DSN is provided. These rejects are forced into the generic 5xx rejects group. If you redefine \fBreject_reply_patterns\fR such that it does not contain the pattern \fB5..\fR, milter rejects will not be output. .IP "\fB###RejectRbl" Messages rejected by an RBL hit. .IP "\fB###RejectRecip" Messages rejected by recipient access controls (smtpd_recipient_restrictions). .IP "\fB###RejectRelay" Messages rejected by relay access controls. .IP "\fB###RejectSender" Messages rejected by sender access controls (smtpd_sender_restrictions). .IP "\fB###RejectSize" Messages rejected due to excessive message size. .IP "\fB###RejectUnknownClient" Messages rejected by unknown client access controls. .IP "\fB###RejectUnknownReverseClient" Messages rejected by unknown reverse client access controls. .IP "\fB###RejectUnknownUser" Messages rejected by unknown user access controls. .IP "\fB###RejectUnverifiedClient" Messages rejected by unverified client access controls. .IP "\fB###RejectVerify" Messages rejected dueo to address verification failures. .IP "\fBReplaced" Messages that triggered header_checks or body_checks REPLACE action. .IP "\fBReturnedToSender" Messages returned to sender due to exceeding queue lifetime (maximal_queue_lifetime). .IP "\fBSaslAuth" SASL authentication successes, includes SASL method, username, and sender when present. .IP "\fBSaslAuthFail" SASL authentication failures. .IP "\fBSent" Messages sent via the SMTP delivery agent. .IP "\fBSentLmtp" Messages sent via the LMTP delivery agent. .IP "\fBSmtpConversationError" Errors during the SMTP/ESMTP dialog. .IP "\fBSmtpProtocolViolation" Protocol violation during the SMTP/ESMTP dialog. .IP "\fBStartupError" Errors during Postfix server startup. .IP "\fBTimeoutInbound" Connections to \fBsmtpd\fR that timed out. .IP "\fBTlsClientConnect" TLS client connections. .IP "\fBTlsOffered" TLS communication offered. .IP "\fBTlsServerConnect" TLS server connections. .IP "\fBTlsUnverified" Unverified TLS connections. .IP "\fBUndeliverable" Address verification indicates recipient address is undeliverable. .IP "\fBWarn" Messages that triggered access, header_checks or body_checks WARN action. .IP "\fBWarnConfigError" Warnings regarding Postfix configuration errors. .IP "\fBWarningsOther" Postfix general \fBwarning\fR messages. .PD .SH LEVEL CONTROL .ad .fi The \fBDetailed\fR section of the report consists of a number of sub-sections, each of which is controlled both globally and independently. Two settings influence the output provided in the \fBDetailed\fR report: a global detail level (specified with \fB--detail\fR) which has final (big hammer) output-limiting control over the \fBDetailed\fR section, and sub-section specific detail settings (small hammer), which allow further limiting of the output for a sub-section. Each sub-section may be limited to a specific depth level, and each sub-level may be limited with top N or threshold limits. The \fIlevelspec\fR argument to each of the level limiters listed above is used to accomplish this. It is probably best to continue explanation of sub-level limiting with the following well-known outline-style hierarchy, and some basic examples: .nf level 0 level 1 level 2 level 3 level 4 level 4 level 2 level 3 level 4 level 4 level 4 level 3 level 4 level 3 level 1 level 2 level 3 level 4 .fi .PP The simplest form of output limiting suppresses all output below a specified level. For example, a \fIlevelspec\fR set to "2" shows only data in levels 0 through 2. Think of this as collapsing each sub-level 2 item, thus hiding all inferior levels (3, 4, ...), to yield: .nf level 0 level 1 level 2 level 2 level 1 level 2 .fi .PP Sometimes the volume of output in a section is too great, and it is useful to suppress any data that does not exceed a certain threshold value. Consider a dictionary spam attack, which produces very lengthy lists of hit-once recipient email or IP addresses. Each sub-level in the hierarchy can be threshold-limited by setting the \fIlevelspec\fR appropriately. Setting \fIlevelspec\fR to the value "2::5" will suppress any data at level 2 that does not exceed a hit count of 5. .PP Perhaps producing a top N list, such as top 10 senders, is desired. A \fIlevelspec\fR of "3:10:" limits level 3 data to only the top 10 hits. .PP With those simple examples out of the way, a \fIlevelspec\fR is defined as a whitespace- or comma-separated list of one or more of the following: .IP "\fIl\fR" Specifies the maximum level to be output for this sub-section, with a range from 0 to 10. if \fIl\fR is 0, no levels will be output, effectively disabling the sub-section (level 0 data is already provided in the Summary report, so level 1 is considered the first useful level in the \fBDetailed\fR report). Higher values will produce output up to and including the specified level. .IP "\fIl\fB.\fIn\fR" Same as above, with the addition that \fIn\fR limits this section's level 1 output to the top \fIn\fR items. The value for \fIn\fR can be any integer greater than 1. (This form of limiting has less utility than the syntax shown below. It is provided for backwards compatibility; users are encouraged to use the syntax below). .IP "\fIl\fB:\fIn\fB:\fIt\fR" This triplet specifies level \fIl\fR, top \fIn\fR, and minimum threshold \fIt\fR. Each of the values are integers, with \fIl\fR being the level limiter as described above, \fIn\fR being a top \fIn\fR limiter for the level \fIl\fR, and \fIt\fR being the threshold limiter for level \fIl\fR. When both \fIn\fR and \fIt\fR are specified, \fIn\fR has priority, allowing top \fIn\fR lists (regardless of threshold value). If the value of \fIl\fR is omitted, the specified values for \fIn\fR and/or \fIt\fR are used for all levels available in the sub-section. This permits a simple form of wildcarding (eg. place minimum threshold limits on all levels). However, specific limiters always override wildcard limiters. The first form of level limiter may be included in \fIlevelspec\fR to restrict output, regardless of how many triplets are present. .PP All three forms of limiters are effective only when \fBpostfix-logwatch\fR's detail level is 5 or greater (the \fBDetailed\fR section is not activated until detail is at least 5). .PP See the \fBEXAMPLES\fR section for usage scenarios. .SH CONFIGURATION FILE .ad \fBPostfix-logwatch\fR can read configuration settings from a configuration file. Essentially, any command line option can be placed into a configuration file, and these settings are read upon startup. Because \fBpostfix-logwatch\fR can run either standalone or within Logwatch, to minimize confusion, \fBpostfix-logwatch\fR inherits Logwatch's configuration file syntax requirements and conventions. These are: .IP \(bu 4'. White space lines are ignored. .IP \(bu 4'. Lines beginning with \fB#\fR are ignored .IP \(bu 4'. Settings are of the form: .nf \fIoption\fB = \fIvalue\fR .fi .IP \(bu 4'. Spaces or tabs on either side of the \fB=\fR character are ignored. .IP \(bu 4'. Any \fIvalue\fR protected in double quotes will be case-preserved. .IP \(bu 4'. All other content is reduced to lowercase (non-preserving, case insensitive). .IP \(bu 4'. All \fBpostfix-logwatch\fR configuration settings must be prefixed with "\fB$postfix_\fR" or \fBpostfix-logwatch\fR will ignore them. .IP \(bu 4'. When running under Logwatch, any values not prefixed with "\fB$postfix_\fR" are consumed by Logwatch; it only passes to \fBpostfix-logwatch\fR (via environment variable) settings it considers valid. .IP \(bu 4'. The values \fBTrue\fR and \fBYes\fR are converted to 1, and \fBFalse\fR and \fBNo\fR are converted to 0. .IP \(bu 4'. Order of settings is not preserved within a configuration file (since settings are passed by Logwatch via environment variables, which have no defined order). .PP To include a command line option in a configuration file, prefix the command line option name with the word "\fB$postfix_\fR". The following configuration file setting and command line option are equivalent: .nf \fB$postfix_Line_Style = Truncate\fR \fB--line_style Truncate\fR .fi Level limiters are also prefixed with \fB$postfix_\fR, but on the command line are specified with the \fB--limit\fR option: .nf \fB$postfix_Sent = 2\fR \fB--limit Sent=2\fR .fi The order of command line options and configuration file processing occurs as follows: 1) The default configuration file is read if it exists and no \fB--config_file\fR was specified on a command line. 2) Configuration files are read and processed in the order found on the command line. 3) Command line options override any options already set either via command line or from any configuration file. Command line options are interpreted when they are seen on the command line, and later options will override previously set options. The notable exception is with limiter variables, which are interpreted in the order found, but only after all other options have been processed. This allows \fB--reject_reply_patterns\fR to determine the dynamic list of the various reject limiters. See also \fB--reject_reply_patterns\fR. .SH "EXIT STATUS" .na .nf .ad .fi The \fBpostfix-logwatch\fR utility exits with a status code of 0, unless an error occurred, in which case a non-zero exit status is returned. .SH "EXAMPLES" .na .nf .ad .fi .SS Running Standalone \fBNote:\fR \fBpostfix-logwatch\fR reads its log data from one or more named Postfix log files, or from STDIN. For brevity, where required, the examples below use the word \fIfile\fR as the command line argument meaning \fI/path/to/postfix.log\fR. Obviously you will need to substitute \fIfile\fR with the appropriate path. .nf .PP To run \fBpostfix-logwatch\fR in standalone mode, simply run: .nf .RS 4 .PP \fBpostfix-logwatch \fIfile\fR .RE 0 .nf .PP A complete list of options and basic usage is available via: .nf .RS 4 .PP \fBpostfix-logwatch --help\fR .RE 0 .nf .PP To print a summary only report of Postfix log data: .nf .RS 4 .PP \fBpostfix-logwatch --detail 1 \fIfile\fR .RE 0 .fi .PP To produce a summary report and a one-level detail report for May 25th: .nf .RS 4 .PP \fBgrep 'May 25' \fIfile\fB | postfix-logwatch --detail 5\fR .RE 0 .fi .PP To produce only a top 10 list of Sent email domains, the summary report and detailed reports are first disabled. Since commands line options are read and enabled left-to-right, the Sent section is re-enabled to level 1 with a level 1 top 10 limiter: .nf .RS 4 .PP \fBpostfix-logwatch --nosummary --nodetail --limit sent='1 1:10:' \fIfile\fR .RE 0 .fi .PP The following command and its sample output shows a more complex level limiter example. The command gives the top 3 Sent email addresses from the top 5 domains, in addition, all level 3 items with a hit count of 2 or less are suppressed (in the Sent sub-section, this happens to be email's Original To address). Ellipses indicate top N or threshold-limited data: .nf .RS 4 .PP \fBpostfix-logwatch --nosummary --nodetail \\ --limit sent '1:5: 2:3: 3::2' \fIfile\fR .nf 1762 Sent via SMTP ----------------------------------- 352 example.com 310 joe 255 joe.bob@virtdomain.example.com 7 info@virtdomain.example.com 21 pooryoda3 11 hot93uh ... 244 sample.net 97 buzz 26 leroyjones 14 sally ... 152 example.net 40 jim_jameson 23 sam_sampson 19 paul_paulson ... 83 sample.us 44 root 39 jenny1 69 dom3.example.us 10 kay 7 ron 6 mrsmith ... ... .fi .RE 0 .fi .PP The next command uses both \fBreject_reply_patterns\fR and level limiters to see 421 RBL rejects, threshold-limiting level 2 output to hits greater than 5 (level 2 in the Reject RBL sub-section is the client's IP address / hostname pair). This makes for a very nice RBL offenders list, shown in the sample output (note the use of the unambiguous, abbreviated command line option reject_reply_pat): .nf .RS 4 .PP \fBpostfix-logwatch --reject_reply_pat '421 4.. 5.. Warn' \\ --nosummary --nodetail --limit 421rejectrbl='2 2::5' \fIfile\fR .nf 300 421 Reject RBL --------------------------------------- 243 zen.spamhaus.org=127.0.0.2 106 10.0.0.129 129.0.0.example.com 41 192.168.10.70 hostx10.sample.net 40 192.168.42.39 hostz42.sample.net 15 10.1.1.152 dsl-10-1-1-152.example.us 14 10.10.10.122 mail122.sample.com 7 192.168.3.44 smalltime-spammer.example.com ... 48 zen.spamhaus.org=127.0.0.4 17 10.29.124.92 10-29-124-92.adsl-static.sample.us ... 8 zen.spamhaus.org=127.0.0.11 ... 1 zen.spamhaus.org=127.0.0.10 ... .fi .RE 4 .SS Running within Logwatch \fBNote:\fR Logwatch versions prior to 7.3.6, unless configured otherwise, required the \fB--print\fR option to print to STDOUT instead of sending reports via email. Since version 7.3.6, STDOUT is the default output destination, and the \fB--print\fR option has been replaced by \fB--output stdout\fR. Check your configuration to determine where report output will be directed, and add the appropriate option to the commands below. .PP To print a summary report for today's Postfix log data: .nf .RS 4 .PP \fBlogwatch --service postfix --range today --detail 1\fR .RE 0 .nf .PP To print a report for today's Postfix log data, with one level of detail in the \fBDetailed\fR section: .nf .RS 4 .PP \fBlogwatch --service postfix --range today --detail 5\fR .RE 0 .fi .PP To print a report for yesterday, with two levels of detail in the \fBDetailed\fR section: .nf .RS 4 .PP \fBlogwatch --service postfix --range yesterday --detail 6\fR .RE 0 .fi .PP To print a report from Dec 12th through Dec 14th, with four levels of detail in the \fBDetailed\fR section: .nf .RS 4 .PP \fBlogwatch --service postfix --range \\ 'between 12/12 and 12/14' --detail 8\fR .RE 0 .PP To print a report for today, with all levels of detail: .nf .RS 4 .PP \fBlogwatch --service postfix --range today --detail 10\fR .RE 0 .PP Same as above, but leaves long lines uncut: .nf .RS 4 .PP \fBlogwatch --service postfix --range today --detail 11\fR .RE 0 .SH "ENVIRONMENT" .na .nf .ad .fi The \fBpostfix-logwatch\fR program uses the following (automatically set) environment variables when running under Logwatch: .IP \fBLOGWATCH_DETAIL_LEVEL\fR This is the detail level specified with the Logwatch command line argument \fB--detail\fR or the \fBDetail\fR setting in the ...conf/services/postfix.conf configuration file. .IP \fBLOGWATCH_DEBUG\fR This is the debug level specified with the Logwatch command line argument \fB--debug\fR. .IP \fBpostfix_\fIxxx\fR The Logwatch program passes all settings \fBpostfix_\fIxxx\fR in the configuration file ...conf/services/postfix.conf to the \fBpostfix\fR filter (which is actually named .../scripts/services/postfix) via environment variable. .SH "FILES" .na .nf .SS Standalone mode .IP "/usr/local/bin/postfix-logwatch" The \fBpostfix-logwatch\fR program .IP "/usr/local/etc/postfix-logwatch.conf" The \fBpostfix-logwatch\fR configuration file in standalone mode .SS Logwatch mode .IP "/etc/logwatch/scripts/services/postfix" The Logwatch \fBpostfix\fR filter .IP "/etc/logwatch/conf/services/postfix.conf" The Logwatch \fBpostfix\fR filter configuration file .SH "SEE ALSO" .na .nf logwatch(8), system log analyzer and reporter .SH "README FILES" .na .ad .nf README, an overview of \fBpostfix-logwatch\fR Changes, the version change list history Bugs, a list of the current bugs or other inadequacies Makefile, the rudimentary installer LICENSE, the usage and redistribution licensing terms .SH "LICENSE" .na .nf .ad Covered under the included MIT/X-Consortium License: http://www.opensource.org/licenses/mit-license.php .SH "AUTHOR(S)" .na .nf Mike Cappella .fi The original \fBpostfix\fR Logwatch filter was written by Kenneth Porter, and has had many contributors over the years. They are entirely not responsible for any errors, problems or failures since the current author's hands have touched the source code. logwatch-7.12/scripts/0000775000211400021140000000000014744021376015144 5ustar logwatchlogwatchlogwatch-7.12/scripts/services/0000775000211400021140000000000014743601205016761 5ustar logwatchlogwatchlogwatch-7.12/scripts/services/zz-zfs0000664000211400021140000001375514736641236020174 0ustar logwatchlogwatch ######################################################## # Please file all bug reports, patches, and feature # requests under: # https://sourceforge.net/p/logwatch/_list/tickets # Help requests and discusion can be filed under: # https://sourceforge.net/p/logwatch/discussion/ ######################################################## ########################################################################### # zz-zfs: Output states of ZFS pools and datasets # # Detail Levels: # 0: Output list of pools and capacities # 5: Output full pool status (automatic if any pools are not healthy) # ########################################################################### ####################################################### ## Copyright 2011 Cloyce D. Spradling ## Covered under the included MIT/X-Consortium License: ## http://www.opensource.org/licenses/mit-license.php ## All modifications and contributions by other persons to ## this script are assumed to have been donated to the ## Logwatch project and thus assume the above copyright ## and licensing terms. If you want to make contributions ## under your own copyright or a different license this ## must be explicitly stated in the contribution an the ## Logwatch project reserves the right to not accept such ## contributions. If you have made significant ## contributions to this script and want to claim ## copyright please contact logwatch-devel@lists.sourceforge.net. ######################################################### use strict; use vars qw($logwatch_hostname $DebugCounter); use POSIX; # Keep the pipes hot $| = 1; $ENV{PRINTING} = "y"; my $debug = $ENV{'LOGWATCH_DEBUG'} || 0; my $detail = $ENV{'LOGWATCH_DETAIL_LEVEL'} || $ENV{'zfs_detail'} || 0; my ($os_name, $host, $os_release, $version, $machine) = POSIX::uname(); # Check to see if we should even be looking at this... $host =~ s/\..*//; # Trim domain (if any) if ($ENV{'LOGWATCH_ONLY_HOSTNAME'} && ($logwatch_hostname ne $host)) { exit 0; } my $pathto_zpool = $ENV{'pathto_zpool'} || '/sbin/zpool'; my $pathto_zfs = $ENV{'pathto_zfs'} || '/sbin/zfs'; my $summary_only = $ENV{'summary_only'} || ($detail < 5); my $detail_only = $ENV{'detail_only'} || 0; if (!-x $pathto_zpool) { # Doesn't support ZFS exit 0; } if ( $debug >= 5 ) { print STDERR "\n\nDEBUG: Inside zz-zfs\n\n"; $DebugCounter = 1; } my @pools = (); my %poolinfo = (); my %counts = ( 'mounted' => 0, 'filesystem' => 0, 'snapshot' => 0, 'volume' => 0, ); my $total_pools = 0; # Table for converting things to kibibytes my %units = ( 'P' => 1024 * 1024 * 1024 * 1024, 'T' => 1024 * 1024 * 1024, 'G' => 1024 * 1024, 'M' => 1024, 'K' => 1, ); my $unit_re = '['.join('', keys %units).']'; # Discover the pools open POOLS, "$pathto_zpool list -H -o name,size,allocated,free,dedupratio,capacity,health 2>/dev/null |" or die "Error running 'zpool list': $!\n"; while() { chomp; my ($name, $size, $used, $avail, $dedup, $cap, $health) = split(/\s+/); next unless $name ne ''; $size = convert_to_kb($size); $used = convert_to_kb($used); $avail = convert_to_kb($avail); print STDERR "\nPOOLS: \"$_\" name=\"$name\" size=$size used=$used avail=$avail dedup=$dedup cap=\"$cap\" health=\"$health\"\n" if ($debug); push @pools, [ $name, $size, $used, $avail, $dedup, $cap, $health ]; } close(POOLS); exit 0 unless @pools; # Nothing to do? # Read filesystem information for each pool foreach my $type (qw( filesystem volume snapshot ) ) { foreach my $pool (map { $_->[0] } @pools) { open POOLINFO, '-|', "${pathto_zfs} list -H -t $type -o name,referenced,available,mountpoint -r $pool" or die "Error running 'zfs list': $!\n"; while() { next if /no datasets available/i; chomp; my ($name, $used, $avail, $mountpoint) = split(/\s+/); next unless $name ne ''; $used = convert_to_kb($used); $avail = convert_to_kb($avail); print STDERR "\nPOOLINFO: \"$_\" name=\"$name\" used=$used avail=$avail mountpoint=\"$mountpoint\"\n" if ($debug); push @{$poolinfo{$pool}->{$type}}, [ $name, $used, $avail, $mountpoint ]; $counts{$type}++; $counts{'mounted'}++ if ($type eq 'filesystem' && $mountpoint ne 'none'); } close(POOLINFO) } } print "Total ZFS pools: ".(@pools+0)."\n"; print "Total filesystems: $counts{'filesystem'} ($counts{'mounted'} mounted)\n"; print "Total snapshots: $counts{'snapshot'}\n"; print "Total volumes: $counts{'volume'}\n"; if (!$detail_only) { my $pool_format = "%2s%-15s %-10s %-10s %-10s %-10s %s\n"; print "\n------------------- ZFS Pool Summary -------------------\n\n"; printf $pool_format, '', 'Pool Name', 'Size (MiB)', 'Used (MiB)', 'Free (MiB)', 'Dedup', 'Cap'; foreach my $poolref (@pools) { my ($name, $size, $used, $avail, $dedup, $cap, $health) = @{$poolref}; my $badflag = ($health eq 'ONLINE') ? '' : '!!'; $detail = 1000 if $badflag ne ''; # Show status if something's wrong printf $pool_format, $badflag, $name, convert_to_mb($size, 10), convert_to_mb($used, 10), convert_to_mb($avail, 10), $dedup, $cap; } print "\n--------------------------------------------------------\n\n"; } if (!$summary_only || $detail > 999) { print "\n------------------- ZFS Pool Status -------------------\n\n"; foreach my $pool (map { $_->[0] } @pools) { system $pathto_zpool, 'status', $pool; } print "\n-------------------------------------------------------\n\n"; } sub convert_to_kb { my ($val) = @_; my ($num, $unit) = ($val =~ /([\.\d]+)\s*($unit_re)?/io); return 0 if $num eq ''; $unit = uc($unit); return $num * $units{$unit}; } sub convert_to_mb { my ($kb, $width) = @_; $width = 0 unless defined($width); $kb /= 1024; $kb = int(($kb * 10) + 0.5) / 10; return sprintf '%*.1f', $width, $kb; } # vi: shiftwidth=3 tabstop=3 syntax=perl et logwatch-7.12/scripts/services/syslog-ng0000664000211400021140000006304514743365005020643 0ustar logwatchlogwatch ######################################################## # Please file all bug reports, patches, and feature # requests under: # https://sourceforge.net/p/logwatch/_list/tickets # and copy: # Stefan Jakobs # Help requests and discusion can be filed under: # https://sourceforge.net/p/logwatch/discussion/ ######################################################## ########################################################################### # This was written and is maintained by: # Stefan Jakobs # # Please send all comments, suggestions, bug reports, # etc, to logwatch at localside.net. ########################################################################### ########################################################################### ## Copyright (c) 2008-2013 Stefan Jakobs ## Covered under the included MIT/X-Consortium License: ## http://www.opensource.org/licenses/mit-license.php ## All modifications and contributions by other persons to ## this script are assumed to have been donated to the ## Logwatch project and thus assume the above copyright ## and licensing terms. If you want to make contributions ## under your own copyright or a different license this ## must be explicitly stated in the contribution an the ## Logwatch project reserves the right to not accept such ## contributions. If you have made significant ## contributions to this script and want to claim ## copyright please contact logwatch-devel@lists.sourceforge.net. ######################################################### #use warnings; use strict; use HTML::Entities qw(encode_entities); my $Detail = $ENV{'LOGWATCH_DETAIL_LEVEL'} || 0; my $Version = "1.4-20130219"; my $format = $ENV{'LOGWATCH_FORMAT_TYPE'} || 'other'; # initialize logwatch variables my $ThisLine = ""; my %OtherList = (); # initialize variables which save the stats my ($Starts,$Stops,$Reloads) = ( 0, 0, 0); my ($Perms,$FileOpenErrors) = ( 0, 0); my ($Drops, $WriteErrsSum) = ( 0, 0); my ($ExceedConns) = ( 0); my (%PermFiles, %OpenFiles) = ( (), ()); my (%WriteErrs, %Connections) = ( (), ()); my (%Conns, %ConnsSum) = (); my (%Stats_center, %Stats_source, %Stats_dest) = ( (), (), ()); my (%Stats_dropped, %Stats_supp, %Stats_global) = ( (), (), ()); my (%Stats_program, %Stats_stored, %Stats_net) = ( (), (), ()); my (%Stats_dropped_program, %Stats_supp_program) = ( (), ()); my (%Stats_dropped_net, %Stats_supp_net) = ( (), ()); my (%Warnings, %IntErrors) = ( (), ()); ### Parse the lines ### while (defined($ThisLine = )) { chomp($ThisLine); #TD syslog-ng[2351]: New configuration initialized; if ( ($ThisLine =~ /^[Nn]ew configuration initialized/ ) || ($ThisLine =~ /^Configuration reload finished;/ ) || ($ThisLine =~ /^EOF on control channel, closing connection;/ ) || ($ThisLine =~ /^(?:POLLERR|EOF) occurred while idle;/ ) ) { #ignore } #TD syslog-ng[9754]: Changing permissions on special file /dev/xconsole elsif ($ThisLine =~ /^Changing permissions on special file ((\/[a-zA-Z0-9_]*)*)$/) { %PermFiles = (%PermFiles, $1 => $PermFiles{$1}+1); $Perms++; } #TD syslog-ng[9754]: Cannot open file /tmp/.adir/afile for writing (No such file or directory) elsif ($ThisLine =~ /^Cannot open file ((\/[a-zA-Z0-9_.]*)*) .*/) { # $1 fq file name, $2 only filename %OpenFiles = (%OpenFiles, $1 => $OpenFiles{$1}+1); $FileOpenErrors++; } #TD syslog-ng[9754]: SIGHUP received, restarting syslog-ng #TD syslog-ng[4027]: Configuration reload request received, reloading configuration; elsif ($ThisLine =~ /^SIGHUP received, restarting syslog-ng$/ || $ThisLine =~ /^Configuration reload request received, reloading configuration;/) { $Reloads++; } #TD syslog-ng[9754]: syslog-ng version 1.6.2 starting #TD syslog-ng[3956]: syslog-ng starting up; version='2.0.9' elsif ($ThisLine =~ /^syslog-ng version [\d.]+ starting$/ || $ThisLine =~ /^syslog-ng starting up; version='[\d.]+'$/) { $Starts++; } #TD syslog-ng[9754]: syslog-ng version 1.6.2 going down #TD syslog-ng[20043]: syslog-ng shutting down; version='2.0.9' elsif ($ThisLine =~ /^syslog-ng version [\d.]+ going down$/ || $ThisLine =~ /^syslog-ng shutting down; version='[\d.]+'$/) { $Stops++; } #TD syslog-ng[20043]: Termination requested via signal, terminating; elsif ($ThisLine =~ /^Termination requested via signal, terminating;/) { # happens with shutdown, but it's not for extra accounting } # syslog-ng v1.X #TD syslog-ng[4833]: STATS: dropped 0 elsif ($ThisLine =~ /^STATS: dropped ([0-9]*)$/) { if ($1 != 0) { $Drops = $Drops + $1; } } #TD syslog-ng[4833]: Syslog connection closed; fd='45', client='AF_INET(192.168.1.1:40280)', local='AF_INET(192.168.1.10:625)' #TD syslog-ng[4833]: Syslog connection accepted; fd='52', client='AF_INET(192.168.1.1:40280)', local='AF_INET(192.168.1.10:625)' # syslog-ng v3.X #TD Syslog connection broken; fd='63', server='AF_INET(192.169.1.1:514)', time_reopen='60' : 44 Time(s) #TD Syslog connection established; fd='48', server='AF_INET(192.168.1.1:514)', local='AF_INET(0.0.0.0:0)' elsif ($ThisLine =~ /^Syslog connection (\S+); fd='\d+', (server|client)='AF_INET\(([.\d]+):\d+\)', (?:local='AF_INET\(([.\d]+:\d+)\)'|time_reopen='\d+')?$/) { my $loc = defined($4) ? $4 : '0.0.0.0'; $Connections{"$1 ($2)"}{$loc}{$3}++; } #TD syslog-ng[4833]: Connection broken to AF_INET(XXX.YYY.ZZZ.AAA:BBB), reopening in 60 seconds elsif ($ThisLine =~ /^Connection broken to [A-Z_]*\((([0-9]{1,3}\.){3}[0-9]{1,3}:[0-9]{1,5})\), reopening in [0-9]* seconds$/) { $Conns{'Connection broken'}{$1}++; $ConnsSum{'Connection broken'}++; } # syslog-ng v2.X #TD syslog-ng[4833]: Connection failed; error='Connection timed out (110)', time_reopen='60' #TD syslog-ng[4833]: Connection failed; error='Connection refused (111)', time_reopen='60' #TD syslog-ng[4833]: Connection broken; time_reopen='60' elsif ($ThisLine =~ /^(Connection \w+); (?:error='([^\(']+) \(\d+\)', )?time_reopen='\d+'/ ) { $Conns{$1}{$2}++; $ConnsSum{$1}++; } #TD syslog-ng[4869]: io.c: do_write: write() failed (errno 111), Connection refused #TD syslog-ng[4869]: I/O error occurred while writing; fd='66', error='Connection refused (111)' elsif ( ($ThisLine =~ /^io\.c: do_write: write\(\) failed \(errno ([\d]+)\)/) or ($ThisLine =~ /I\/O error occurred while writing; fd='\d+', error='[^'(]+ \((\d+)\)'/) ) { $WriteErrs{$1}++; $WriteErrsSum++; } # Log statistics from syslog-ng v2.X #TD syslog-ng[4883]: Log statistics; dropped='program(/path/to/p)=12', # processed='center(queued)=1717', processed='center(received)=916', ... # suppressed='program(/path/to/p)=0' # Log statisctics from syslog-ng v3.X #TD syslog-ng[1625]: Log statistics; processed='destination(newsnotice)=0', # processed='center(queued)=0', processed='src.internal(src#0)=7', # stamp='src.internal(src#0)=1283808150', processed='global(msg_clones)=0', ... elsif ($ThisLine =~ /^Log statistics; /) { my @processed = $ThisLine =~ /processed='([a-z.]*)\((\S*)\)=([0-9]*)'/g; for (my $i=0; $i<@processed; $i=$i+3) { if ($processed[$i] eq "center") { $Stats_center{$processed[$i+1]} = $Stats_center{$processed[$i+1]} + $processed[$i+2]; } elsif ($processed[$i] eq "destination") { $Stats_dest{$processed[$i+1]} = $Stats_dest{$processed[$i+1]} + $processed[$i+2]; } elsif ($processed[$i] eq "source" || $processed[$i] eq "src.internal" || $processed[$i] eq 'src.none' || $processed[$i] eq 'src.journald') { $Stats_source{$processed[$i+1]} = $Stats_source{$processed[$i+1]} + $processed[$i+2]; } elsif ($processed[$i] eq "global") { $Stats_global{$processed[$i+1]} = $Stats_global{$processed[$i+1]} + $processed[$i+2]; } elsif ($processed[$i] eq "dst.program") { $Stats_program{$processed[$i+1]} = $Stats_program{$processed[$i+1]} + $processed[$i+2]; } elsif ($processed[$i] =~ /(?:dst\.)?(?:udp|tcp)/) { $Stats_net{$processed[$i+1]} = $Stats_net{$processed[$i+1]} + $processed[$i+2]; } else { chomp($ThisLine); $OtherList{$ThisLine}++; } } my @dropped = $ThisLine =~ /dropped='([a-z.]*)\((\S*)\)=([0-9]*)'/g; for (my $i=0; $i<@dropped; $i=$i+3) { if ($dropped[$i] eq "program" || $dropped[$i] eq "pipe") { if ($dropped[$i+2] > 0) { $Stats_dropped{$dropped[$i+1]} = $Stats_dropped{$dropped[$i+1]} + $dropped[$i+2]; } } elsif ($dropped[$i] =~ /(?:dst\.)?(?:tcp|udp)/) { if ($dropped[$i+2] > 0) { $Stats_dropped_net{$dropped[$i+1]} = $Stats_dropped_net{$dropped[$i+1]} + $dropped[$i+2]; } } elsif ($dropped[$i] eq "dst.program") { if ($dropped[$i+2] > 0) { $Stats_dropped_program{$dropped[$i+1]} = $Stats_dropped_program{$dropped[$i+1]} + $dropped[$i+2]; } } else { chomp($ThisLine); $OtherList{$ThisLine}++; } } my @suppressed = $ThisLine =~ /suppressed='([a-z.]*)\((\S*)\)=([0-9]*)'/g; for (my $i=0; $i<@suppressed; $i=$i+3) { if ($suppressed[$i] eq "program" || $suppressed[$i] eq "pipe") { if ($suppressed[$i+2] > 0) { $Stats_supp{$suppressed[$i+1]} = $Stats_supp{$suppressed[$i+1]} + $suppressed[$i+2]; } } elsif ($suppressed[$i] =~ /(?:dst\.)?(?:tcp|udp)/) { if ($suppressed[$i+2] > 0) { $Stats_supp_net{$suppressed[$i+1]} = $Stats_supp_net{$suppressed[$i+1]} + $suppressed[$i+2]; } } elsif ($suppressed[$i] eq "dst.program") { if ($suppressed[$i+2] > 0) { $Stats_supp_program{$suppressed[$i+1]} = $Stats_supp_program{$suppressed[$i+1]} + $suppressed[$i+2]; } } else { chomp($ThisLine); $OtherList{$ThisLine}++; } } my @stored = $ThisLine =~ /stored='([a-z.]*)\((\S*)\)=([0-9]*)'/g; for (my $i=0; $i<@stored; $i=$i+3) { if ($stored[$i] =~ "(?:dst\.)?(?:program|tcp|udp)" || $stored[$i] eq "pipe") { if ($stored[$i+2] > 0) { $Stats_stored{$stored[$i+1]} = $Stats_stored{$stored[$i+1]} + $stored[$i+2]; } } else { chomp($ThisLine); $OtherList{$ThisLine}++; } } } # syslog-ng v2.X #TD syslog-ng[1796]: Number of allowed concurrent connections exceeded; num='10', max='10' elsif ($ThisLine =~ /^Number of allowed concurrent connections exceeded/) { $ExceedConns++; } # syslog-ng v3.X #TD syslog-ng[1601]: WARNING: global: the default value of chain_hostnames is changing to # 'no' in version 3.0, please update your configuration accordingly; #TD syslog-ng[1601]: WARNING: you are using the pipe driver, underlying file is not a # FIFO, it should be used by file(); filename='/dev/tty10' elsif ($ThisLine =~ /^WARNING: (.*)$/) { $Warnings{$1}++; } # syslog-ng v3.X #TD syslog-ng[1601]: Configuration file has no version number, assuming ... elsif ($ThisLine =~ /(Configuration file has no version number)/) { $Warnings{$1}++; } # syslog-ng v2.X #TD syslog-ng[1602]: Error initializing new configuration, reverting to old config; elsif ($ThisLine =~ /^Error initializing new configuration, reverting to old config;/) { $IntErrors{"Error initializing new configuration"}{"reverting to old config"}++; } #TD syslog-ng[2550]: Internal error, duplicate configuration elements refer to # the same persistent config; name='afsocket_sd_connections(dgram,AF_INET(0.0.0.0:514))' elsif ($ThisLine =~ /Internal error, ([^;]*); name='([^']*)'/) { $IntErrors{$1}{$2}++; } # syslog-ng v2.X #TD syslog-ng[20709]: Referenced filter rule not found; rule='f_dhcpd' elsif ($ThisLine =~ /(Referenced filter rule not found); (.+)/) { $IntErrors{$1}{$2}++ } # syslog-ng v2.X #TD syslog-ng[2000]: Error in configuration, unresolved filter reference; filter='f_host_dhcp_dns0' elsif ($ThisLine =~ /^Error in configuration, ([^;]+); (.+)/) { $IntErrors{$1}{$2}++; } else { # Report any unmatched entries... chomp($ThisLine); $OtherList{$ThisLine}++; } } sub outCount { my ($msg, $count, $category, $subcat) = @_; if ($format ne 'xml') { print $msg; } else { print "\n"; } } ### generate the output ### if ($format eq 'xml') { # todo, embargo the output until the first actual output.. print "\n"; print "\n"; } if (($Starts || $Stops || $Reloads) && $Detail) { print "\n" if $format eq 'xml'; } if ($Starts && $Detail) { outCount(sprintf("\n%-48s %5i Time(s)", "Syslog-ng started:", $Starts), $Starts, "Service", "started"); } if ($Stops && $Detail) { outCount(sprintf("\n%-48s %5i Time(s)", "Syslog-ng stopped:", $Stops), $Stops, "Service", "stopped"); } if ($Reloads && $Detail) { outCount(sprintf("\n%-48s %5i Time(s)", "Syslog-ng reloaded:", $Reloads), $Reloads, "Service", "reloaded"); } if (($Starts || $Stops || $Reloads) && $Detail) { print "" if $format eq 'xml'; print "\n"; } if ($Perms) { print "\n" if $format eq 'xml'; if ($Detail >= 5) { print "\nSyslog-ng changed the permission on the file(s):" unless $format eq 'xml'; foreach my $file (keys %PermFiles) { outCount(sprintf("\n\t%-41s %5i Time(s)", $file, $PermFiles{$file}), $PermFiles{$file}, 'Perms', $file); } print "\n"; } else { outCount(sprintf("\n%-48s %5i Time(s)\n", "Syslog-ng changed permission on file(s):", $Perms), $Perms, 'Perms'); } print "\n" if $format eq 'xml'; } if ($FileOpenErrors) { print "\n" if $format eq 'xml'; if ($Detail >= 5) { print "\nSyslog-ng could not open the file(s):" unless $format eq 'xml'; foreach my $file (keys %OpenFiles) { outCount(sprintf("\n\t%-41s %5i Time(s)", $file, $OpenFiles{$file}),$OpenFiles{$file},'FileOpenErrors',$file); } print "\n"; } else { outCount(sprintf("\n%-48s %5i Time(s)\n", "Syslog-ng could not open file:", $FileOpenErrors),$FileOpenErrors,'FileOpenErrors'); } print "\n" if $format eq 'xml'; } if (keys %Conns) { print "\n" if $format eq 'xml'; foreach my $cat (keys %Conns) { print "\n" if $format eq 'xml'; if ($Detail >= 5) { print "\n$cat:" unless $format eq 'xml'; foreach my $IP (keys %{$Conns{$cat}}) { outCount(sprintf("\n\t%-41s %5i Time(s)", $IP, $Conns{$cat}{$IP}),$Conns{$cat}{$IP},$cat,$IP); } print "\n"; } else { outCount(sprintf("\n%-48s %5i Time(s)\n", "$cat:", $ConnsSum{$cat}),$ConnsSum{$cat},$cat); } print "\n" if $format eq 'xml'; } print "\n" if $format eq 'xml'; } if (keys %WriteErrs) { print "\n" if $format eq 'xml'; if ($Detail >= 5) { print "\nWrite Error(s):" unless $format eq 'xml'; foreach my $err (keys %WriteErrs) { outCount(sprintf("\n\t%-41s %5i Time(s)", "Error Number $err:", $WriteErrs{$err}),$WriteErrs{$err},'WriteErrors',$err); } print "\n"; } else { outCount(sprintf("\n%-48s %5i Time(s)\n", "Write Error(s):", $WriteErrsSum),$WriteErrsSum,'WriteErrors'); } print "\n" if $format eq 'xml'; } if ($ExceedConns && $Detail >= 5) { print "\n" if $format eq 'xml'; outCount(sprintf("\n%-48s %5i Time(s)\n", "Concurrent Connections Exceeded:", $ExceedConns),$ExceedConns,'ExceedConns'); print "\n" if $format eq 'xml'; } if (keys %Stats_center || keys %Stats_dest || keys %Stats_source || keys %Stats_dropped || keys %Stats_supp || keys %Stats_global || keys %Stats_stored || keys %Stats_program || keys %Stats_net) { my ($lost_rcvd, $lost_dest) = ( 0, 0); print '' if $format eq 'xml'; if ($Stats_center{received} && %Stats_source) { $lost_rcvd = 0 - $Stats_center{received}; map { # skip 'src#X' as this seams to be aggregated into 'src' # skip 'journal' as this is not counted. $lost_rcvd = $lost_rcvd + $Stats_source{$_} unless ($_ =~ /(?:src#\d+|journal)/); } keys %Stats_source; } if ($Stats_center{queued} && %Stats_dest) { $lost_dest = $Stats_center{queued}; map { $lost_dest = $lost_dest - $Stats_dest{$_} } keys %Stats_dest; } if ($Detail >= 6 and $format ne 'xml') { print "\nLog Statistics:"; } if ($lost_rcvd != 0 || $lost_dest != 0) { if ($lost_rcvd != 0) { if ($Detail >= 5) { outCount("\n- Failed to receive $lost_rcvd message(s)!",$lost_rcvd,'Log Statistics','Failed to receive messages'); } } if ($lost_dest != 0) { if ($Detail >= 5 ) { outCount("\n- Failed to save $lost_dest message(s) in logfile(s)!",$lost_dest,'Log Statistics','Failed to save messages'); } else { $Drops = $Drops + $lost_dest; } } if ($Detail >= 5) { print "\n"; } } if ($Detail >= 6) { if (keys %Stats_center) { print "\nCenter:" unless $format eq 'xml'; foreach my $center (sort {$a cmp $b} keys %Stats_center) { outCount(sprintf("\n\t%-34s %12i", $center, $Stats_center{$center}), $Stats_center{$center}, "Center", $center); } } if (keys %Stats_dest) { print "\nDestination:" unless $format eq 'xml'; foreach my $dest (sort {$a cmp $b} keys %Stats_dest) { outCount(sprintf("\n\t%-34s %12i", $dest, $Stats_dest{$dest}), $Stats_dest{$dest}, "Destination", $dest); } } if (keys %Stats_source) { print "\nSource:" unless $format eq 'xml'; foreach my $source (sort {$a cmp $b} keys %Stats_source) { outCount(sprintf("\n\t%-34s %12i", $source, $Stats_source{$source}),$Stats_source{$source},"Source",$source); } } if (keys %Stats_net) { print "\nNetwork:" unless $format eq 'xml'; foreach my $source (sort {$a cmp $b} keys %Stats_net) { (my $short_source) = ($source =~ /,?([^,]*)/); outCount(sprintf("\n\t%-34s %12i", $short_source, $Stats_net{$source}),$Stats_net{$source},"Network",$short_source); } } if (keys %Stats_program) { print "\nProgram:" unless $format eq 'xml'; foreach my $source (sort {$a cmp $b} keys %Stats_program) { (my $short_source) = ($source =~ /,?([^,]*)/); outCount(sprintf("\n\t%-34s %12i", $short_source, $Stats_program{$source}),$Stats_program{$source},"Program",$short_source); } } if (keys %Stats_supp) { print "\nSuppressed:" unless $format eq 'xml'; foreach my $source (sort {$a cmp $b} keys %Stats_supp) { outCount(sprintf("\n\t%-34s %12i", $source, $Stats_supp{$source}),$Stats_supp{$source},"Suppressed",$source); } } if (keys %Stats_supp_net) { print "\nSuppressed(net):"; foreach my $source (sort {$a cmp $b} keys %Stats_supp_net) { outCount(sprintf("\n\t%-34s %12i", $source, $Stats_supp_net{$source}),$Stats_supp_net{$source},"Suppressed(net)",$source); } } if (keys %Stats_supp_program) { print "\nSuppressed(program):" unless $format eq 'xml'; foreach my $source (sort {$a cmp $b} keys %Stats_supp_program) { outCount(sprintf("\n\t%-34s %12i", $source, $Stats_supp_program{$source}),$Stats_supp_program{$source},"Suppressed(program)",$source); } } if (keys %Stats_stored) { print "\nStored:" unless $format eq 'xml'; foreach my $source (sort {$a cmp $b} keys %Stats_stored) { (my $short_source) = ($source =~ /,?([^,]*)/); outCount(sprintf("\n\t%-34s %12i", $short_source, $Stats_stored{$source}),$Stats_stored{$source},"Stored",$short_source); } } if (keys %Stats_global) { print "\nGlobal:" unless $format eq 'xml'; foreach my $source (sort {$a cmp $b} keys %Stats_global) { outCount(sprintf("\n\t%-34s %12i", $source, $Stats_global{$source}),$Stats_global{$source},"Global",$source); } } } if (keys %Stats_dropped) { print "\nDropped:" unless $format eq 'xml'; foreach my $source (sort {$a cmp $b} keys %Stats_dropped) { outCount(sprintf("\n\t%-34s %12i", $source, $Stats_dropped{$source}),$Stats_dropped{$source},'Dropped',$source); } } if (keys %Stats_dropped_net) { print "\nDropped(net):" unless $format eq 'xml'; foreach my $source (sort {$a cmp $b} keys %Stats_dropped_net) { outCount(sprintf("\n\t%-34s %12i", $source, $Stats_dropped_net{$source}),$Stats_dropped_net{$source},'Dropped(net)',$source); } } if (keys %Stats_dropped_program) { print "\nDropped(program):" unless $format eq 'xml'; foreach my $source (sort {$a cmp $b} keys %Stats_dropped_program) { outCount(sprintf("\n\t%-34s %12i", $source, $Stats_dropped_program{$source}),$Stats_dropped_program{$source},'Dropped(program)',$source); } } if (keys %Stats_center or keys %Stats_dropped or keys %Stats_dropped_net or keys %Stats_dropped_program) { print "\n"; } print '' if $format eq 'xml'; } if (keys %Connections) { print '' if $format eq 'xml'; print "syslog-ng:" unless $format eq 'xml'; foreach my $state (sort {$a cmp $b} keys %Connections) { my $sum = 0; print "" if $format eq 'xml'; print "\nConnections $state: " unless $format eq 'xml'; print "\n" if $Detail > 2; foreach my $localip (sort {$a cmp $b} keys %{$Connections{$state}}) { print "" if $Detail > 2 and $format eq 'xml'; print " $localip: " if $Detail > 2 and $format ne 'xml'; print "\n" if $Detail > 5; my $sum_pro_ip = 0; foreach my $extip (sort {$a cmp $b} keys %{$Connections{$state}{$localip}}) { outCount("\t$extip : $Connections{$state}{$localip}{$extip} Time(s)\n", $Connections{$state}{$localip}{$extip},'Sum',$extip) if $Detail > 5; $sum = $sum + $Connections{$state}{$localip}{$extip}; $sum_pro_ip = $sum_pro_ip + $Connections{$state}{$localip}{$extip}; } outCount("$sum_pro_ip\n",$sum_pro_ip,'Sum') if $Detail > 2 and $Detail <= 5; print "" if $Detail > 2 and $format eq 'xml'; } outCount("$sum\n",$sum,'Sum') if $Detail <= 2; print '' if $format eq 'xml'; } print '' if $format eq 'xml'; } if ($Drops) { print '' if $format eq 'xml'; outCount("\nSyslog-ng dropped " . $Drops ." line(s)\n",$Drops,'Dropped','lines'); print '' if $format eq 'xml'; } if (keys %IntErrors) { print '' if $format eq 'xml'; print "\nInternal Errors:" unless $format eq 'xml'; foreach my $class (sort {$a cmp $b} keys %IntErrors) { print "\n $class" unless $format eq 'xml'; print "" if $format eq 'xml'; foreach my $error (sort {$a cmp $b} keys %{$IntErrors{$class}}) { outCount(sprintf("\n\t%-41s %5i Time(s)", "$error:", $IntErrors{$class}{$error}),$IntErrors{$class}{$error},'IntErrors',$class); } } print '' if $format eq 'xml'; print "\n"; } if (keys %Warnings) { print '' if $format eq 'xml'; print "\nWarnings:" unless $format eq 'xml'; foreach my $warning (keys %Warnings) { outCount(sprintf("\n\t%-41s %5i Time(s)", "$warning:", $Warnings{$warning}),$Warnings{$warning},'Warning',$warning); } print '' if $format eq 'xml'; print "\n"; } if (keys %OtherList) { print '' if $format eq 'xml'; print "\n**** Unmatched entries ****\n" unless $format eq 'xml'; foreach my $Error (keys %OtherList) { outCount(" $Error : $OtherList{$Error} Time(s)\n",$OtherList{$Error},'UnmatchedEntry',$Error); } print '' if $format eq 'xml'; } if ($format eq 'xml') { # todo, embargo the output until the first actual output.. print "\n"; } ### return without a failure ### exit(0); # vi: shiftwidth=3 tabstop=3 syntax=perl et logwatch-7.12/scripts/services/qmail-smtpd0000664000211400021140000016565014274101042021142 0ustar logwatchlogwatch ######################################################## # Please file all bug reports, patches, and feature # requests under: # https://sourceforge.net/p/logwatch/_list/tickets # Help requests and discusion can be filed under: # https://sourceforge.net/p/logwatch/discussion/ ######################################################## ####################################################### ## Copyright (c) 2008 Bob Hutchinson ## Covered under the included MIT/X-Consortium License: ## http://www.opensource.org/licenses/mit-license.php ## All modifications and contributions by other persons to ## this script are assumed to have been donated to the ## Logwatch project and thus assume the above copyright ## and licensing terms. If you want to make contributions ## under your own copyright or a different license this ## must be explicitly stated in the contribution an the ## Logwatch project reserves the right to not accept such ## contributions. If you have made significant ## contributions to this script and want to claim ## copyright please contact logwatch-devel@lists.sourceforge.net. ######################################################### use strict; my $Detail = $ENV{'LOGWATCH_DETAIL_LEVEL'}; my $QmailDetail = $ENV{'qmail_high_detail'}; my $QmailThreshold = ($ENV{'threshold'} ? $ENV{'threshold'} : 0 ); my $ToThreshold = $ENV{'to_threshold'}; my $FromThreshold = $ENV{'from_threshold'}; my $BlockedThreshold = $ENV{'blocked_threshold'}; #Init String Containers my ( $Badmailfromtot, $Badmailtotot, $Blocked, $GrandTotalFrom, $LocalServer, $Maxscantimeattach, $Maxscantimeregex, $Maxscantimespam, $Maxscantimevirus, $Quarantine, $RemoteServer, $SimscanAttachTotal, $SimscanCleanTotal, $SimscanPassthruTotal, $SimscanRegexTotal, $SimscanRelayClientTotal, $SimscanSpamdroppedTotal, $SimscanSpamrejectTotal, $SimscanTotal, $SimscanVirusTotal, $Total, $TotalAccept, $TotalAcceptRelay, $TotalBlocked, $TotalFrom, $TotalNoAuthResource, $TotalOverquota, $TotalReject, $TotalRejectRelay, $TotalRejectedIntrusion, $TotalTo, $Totalscantimeattach, $Totalscantimeregex, $Totalscantimespam, $Totalscantimevirus, $Warning, $attach, $attachfrom, $attachto, $d, $email, $from, $ip, $passthrufrom, $passthruipfrom, $passthrulimits, $passthruto, $pid1, $pid2, $ptl1, $ptl2, $rbl, $reason, $regex, $regexfrom, $regexto, $remote, $remotedomain, $remotedomain2, $rest, $scantime, $sct, $spamdroppedfrom, $spamdroppedipfrom, $spamdroppedto, $spamrejectfrom, $spamrejectipfrom, $spamrejectto, $threshold_reached, $to, $virus, $virusfrom, $virusto, ); #Init Hashes my ( %Badmailfromemail, %Badmailfromip, %Badmailtoemail, %Badmailtoip, %Blockeds, %ChkuserAcceptedNullSenderFrom, %ChkuserAcceptedNullSenderRemote, %ChkuserAcceptedSenderFrom, %ChkuserAcceptedSenderRemote, %ChkuserAcceptsFrom, %ChkuserAcceptsRelayFrom, %ChkuserAcceptsRelayTo, %ChkuserAcceptsTo, %ChkuserNoAuthResourceFrom, %ChkuserNoAuthResourceTo, %ChkuserOverquotaTo, %ChkuserRejectedIntrusionFrom, %ChkuserRejectedIntrusionTo, %ChkuserRejectedSenderFrom, %ChkuserRejectedSenderReason, %ChkuserRejectedSenderRemote, %ChkuserRejectsFrom, %ChkuserRejectsReason, %ChkuserRejectsRelayFrom, %ChkuserRejectsRelayRemote, %ChkuserRejectsRelayTo, %ChkuserRejectsRemote, %ChkuserRejectsTo, %Domains, %From, %Rbl, %Simscan, %SimscanAttach, %SimscanAttachFrom, %SimscanAttachTo, %SimscanFrom, %SimscanPassthruFrom, %SimscanPassthruIpFrom, %SimscanPassthruTo, %SimscanRegex, %SimscanRegexFrom, %SimscanRegexTo, %SimscanSpamdroppedFrom, %SimscanSpamdroppedIpFrom, %SimscanSpamdroppedTo, %SimscanSpamrejectFrom, %SimscanSpamrejectIpFrom, %SimscanSpamrejectTo, %SimscanTo, %To, %Warnings, ); #Init Arrays my @OtherList = (); # simscan my $SimscanThreshold = $ENV{'simscan_threshold'}; my $SimscanFromThreshold = $ENV{'simscan_from_threshold'}; my $SimscanToThreshold = $ENV{'simscan_to_threshold'}; my $SimscanAttachThreshold = $ENV{'simscan_attach_threshold'}; my $SimscanRegexThreshold = $ENV{'simscan_regex_threshold'}; my $ShowSimscanPassthru = $ENV{'show_simscan_passthru'}; my $SimscanPassthruIpFromThreshold = $ENV{'simscan_passthru_ip_from_threshold'}; my $SimscanPassthruFromThreshold = $ENV{'simscan_passthru_from_threshold'}; my $SimscanPassthruToThreshold = $ENV{'simscan_passthru_to_threshold'}; my $ShowSimscanSpamReject = $ENV{'show_simscan_spam_reject'}; my $SimscanSpamRejectIpFromThreshold = $ENV{'simscan_spam_reject_ip_from_threshold'}; my $SimscanSpamRejectFromThreshold = $ENV{'simscan_spam_reject_from_threshold'}; my $SimscanSpamRejectToThreshold = $ENV{'simscan_spam_reject_to_threshold'}; my $ShowSimscanSpamDropped = $ENV{'show_simscan_spam_dropped'}; my $SimscanSpamDroppedIpFromThreshold = $ENV{'simscan_spam_dropped_ip_from_threshold'}; my $SimscanSpamDroppedFromThreshold = $ENV{'simscan_spam_dropped_from_threshold'}; my $SimscanSpamDroppedToThreshold = $ENV{'simscan_spam_dropped_to_threshold'}; # chkuser my $ShowChkuserRejects = $ENV{'show_chkuser_rejects'}; my $ChkuserRejectsFromThreshold = $ENV{'chkuser_rejects_from_threshold'}; my $ChkuserRejectsToThreshold = $ENV{'chkuser_rejects_to_threshold'}; my $ChkuserRejectsRemoteThreshold = $ENV{'chkuser_rejects_remote_threshold'}; my $ChkuserRejectsReasonThreshold = $ENV{'chkuser_rejects_reason_threshold'}; my $ShowChkuserRejectsRelay = $ENV{'show_chkuser_rejects_relay'}; my $ChkuserRejectsRelayFromThreshold = $ENV{'chkuser_rejects_relay_from_threshold'}; my $ChkuserRejectsRelayToThreshold = $ENV{'chkuser_rejects_relay_to_threshold'}; my $ChkuserRejectsRelayRemoteThreshold = $ENV{'chkuser_rejects_relay_remote_threshold'}; my $ShowChkuserAccepts = $ENV{'show_chkuser_accepts'}; my $ChkuserAcceptsFromThreshold = $ENV{'chkuser_accepts_from_threshold'}; my $ChkuserAcceptsToThreshold = $ENV{'chkuser_accepts_to_threshold'}; my $ShowChkuserAcceptsRelay = $ENV{'show_chkuser_accepts_relay'}; my $ChkuserAcceptsRelayFromThreshold = $ENV{'chkuser_accepts_relay_from_threshold'}; my $ChkuserAcceptsRelayToThreshold = $ENV{'chkuser_accepts_relay_to_threshold'}; my $ShowChkuserOther = $ENV{'show_chkuser_other'}; my $ChkuserNoAuthResourceThreshold = $ENV{'chkuser_noauthresource_threshold'}; my $ChkuserOverquotaThreshold = $ENV{'chkuser_overquota_threshold'}; my $ChkuserRejectedIntrusionThreshold = $ENV{'chkuser_rejected_intrusion_threshold'}; my $ShowChkuserAcceptedSender = $ENV{'show_chkuser_accepted_sender'}; my $ChkuserAcceptedSenderFromThreshold = $ENV{'chkuser_accepted_sender_from_threshold'}; my $ChkuserAcceptedSenderRemoteThreshold = $ENV{'chkuser_accepted_sender_remote_threshold'}; my $ChkuserAcceptedNullSenderFromThreshold = $ENV{'chkuser_accepted_null_sender_from_threshold'}; my $ShowChkuserRejectedSender = $ENV{'show_chkuser_rejected_sender'}; my $ChkuserRejectedSenderFromThreshold = $ENV{'chkuser_rejected_sender_from_threshold'}; my $ChkuserRejectedSenderRemoteThreshold = $ENV{'chkuser_rejected_sender_remote_threshold'}; my $ChkuserRejectedSenderReasonThreshold = $ENV{'chkuser_rejected_sender_reason_threshold'}; my $BadMailToIpThreshold = $ENV{'badmailto_ip_threshold'}; my $BadMailToEmailThreshold = $ENV{'badmailto_email_threshold'}; my $BadMailFromIpThreshold = $ENV{'badmailfrom_ip_threshold'}; my $BadMailFromEmailThreshold = $ENV{'badmailfrom_email_threshold'}; my $IgnoreUnmatched = $ENV{'ignoreunmatched'}; while (defined(my $ThisLine = )) { if ( ( $ThisLine =~ /status: / ) or ( $ThisLine =~ /end (\d+) status \d+/ ) or ( $ThisLine =~ /simscan: Putting the message in quarantine/ ) ) { # We don't care about these } elsif ( ($pid1, $RemoteServer) = ( $ThisLine =~ /pid (\d+) from (.*)/ ) ) { $From{$RemoteServer}++; $TotalFrom++; $GrandTotalFrom++; } elsif ( ($pid2,$LocalServer,$rest) = ( $ThisLine =~ /ok (\d+) \d+:(.*):\d+\s+(.*)/ ) ) { $To{$LocalServer}++; $TotalTo++; $Total++; if ( $rest !~ /^\:/) { # we have a domain ($d, $ip ) = ($rest =~ /^(.*):(.*)::\d+$/); $Domains{$ip} = $d; } } elsif ( ($Warning) = ( $ThisLine =~ /warning: (.*)/i ) ) { $Warnings{$Warning}++; } # rblsmtpd elsif ( ($Blocked, $rbl) = ( $ThisLine =~ /rblsmtpd: (.*) pid \d+: 451 (.*)$/ ) ) { $Blockeds{$Blocked}++; $TotalBlocked++; $Rbl{$Blocked} = $rbl; # remove it from previous parse if ( defined( $From{$Blocked} ) ) { $From{$Blocked}--; $TotalFrom--; } } # CHKUSER rejected rcpt elsif (($from,$remotedomain, $remote, $to, $reason) = ( $ThisLine =~ /CHKUSER rejected rcpt: from <(.*):.*:> remote <(.*):.*:(.*)> rcpt <(.*)> : (.*)/ )) { $ChkuserRejectsFrom{$from}++; $ChkuserRejectsRemote{$remote}++; $Domains{$remote} = $remotedomain if($remotedomain); $ChkuserRejectsTo{$to}++; $ChkuserRejectsReason{$reason}++; $TotalReject++; # remove it from previous parse if ( defined( $From{$from} ) ) { $From{$from}--; $TotalFrom--; } } # CHKUSER rejected relaying elsif (($from, $remotedomain, $remotedomain2, $remote, $to, $reason) = ( $ThisLine =~ /CHKUSER rejected relaying: from <(.*):.*:> remote <(.*):(.*):(.*)> rcpt <(.*)> : (.*)/ )) { $ChkuserRejectsRelayFrom{$from}++; $ChkuserRejectsRelayTo{$to}++; $ChkuserRejectsRelayRemote{$remote}++; if (! $Domains{$remote} ) { if ( $remotedomain2 && $remotedomain2 != 'unknown' ) { $Domains{$remote} = $remotedomain2; } elsif ( $remotedomain ) { $Domains{$remote} = $remotedomain; } } $ChkuserRejectsReason{$reason}++; $TotalRejectRelay++; # remove it from previous parse if ( defined( $From{$from} ) ) { $From{$from}--; $TotalFrom--; } } # CHKUSER accepted rcpt elsif (($from, $to) = ( $ThisLine =~ /CHKUSER accepted rcpt: from <(.*):.*:> .* rcpt <(.*)> : found existing recipient/ )) { $ChkuserAcceptsFrom{$from}++; $ChkuserAcceptsTo{$to}++; $TotalAccept++; } # CHKUSER relaying rcpt elsif (($from, $to) = ( $ThisLine =~ /CHKUSER relaying rcpt: from <(.*):.*:> .* rcpt <(.*)> : client allowed to relay/ )) { $ChkuserAcceptsRelayFrom{$from}++; $ChkuserAcceptsRelayTo{$to}++; $TotalAcceptRelay++; } # CHKUSER no auth resource elsif (($from, $to) = ( $ThisLine =~ /CHKUSER no auth resource: from <(.*):.*:> .* rcpt <(.*)> :/ )) { $ChkuserNoAuthResourceFrom{$from}++; $ChkuserNoAuthResourceTo{$to}++; $TotalNoAuthResource++; # remove it from previous parse if ( defined( $From{$from} ) ) { $From{$from}--; $TotalFrom--; } } # CHKUSER mbx overquota elsif (($from, $to) = ( $ThisLine =~ /CHKUSER mbx overquota: from <(.*):.*:> .* rcpt <(.*)> :/ )) { $ChkuserOverquotaTo{$to}++; $TotalOverquota++; # remove it from previous parse if ( defined( $From{$from} ) ) { $From{$from}--; $TotalFrom--; } } # CHKUSER rejected intrusion elsif (($from, $to) = ( $ThisLine =~ /CHKUSER rejected intrusion: from <(.*):.*:> .* rcpt <(.*)> :/ )) { $ChkuserRejectedIntrusionFrom{$from}++; $ChkuserRejectedIntrusionTo{$to}++; $TotalRejectedIntrusion++; # remove it from previous parse if ( defined( $From{$from} ) ) { $From{$from}--; $TotalFrom--; } } # CHKUSER accepted sender elsif (($from, $remote) = ( $ThisLine =~ /CHKUSER accepted sender: from <(.*):.*:> remote <.*:.*:(.*)> rcpt <>/ )) { $ChkuserAcceptedSenderFrom{$from}++; $ChkuserAcceptedSenderRemote{$remote}++; } # CHKUSER accepted null sender elsif (($remote) = ( $ThisLine =~ /CHKUSER accepted null sender: from <:.*:> remote <.*:.*:(.*)> rcpt <> : accepted null sender always/ )) { $ChkuserAcceptedNullSenderRemote{$remote}++; } # CHKUSER rejected sender elsif (($from, $remotedomain, $remotedomain2, $remote, $reason) = ( $ThisLine =~ /CHKUSER rejected sender: from <(.*):.*:> remote <(.*):(.*):(.*)> rcpt <> : (.*)/ )) { $ChkuserRejectedSenderFrom{$from}++; $ChkuserRejectedSenderRemote{$remote}++; if (! $Domains{$remote} ) { if ( $remotedomain2 && $remotedomain2 != 'unknown' ) { $Domains{$remote} = $remotedomain2; } elsif ( $remotedomain ) { $Domains{$remote} = $remotedomain; } } $ChkuserRejectedSenderReason{$reason}++; } # simscan-1.1 virus elsif ( ($virus, $virusfrom, $virusto, $scantime) = ($ThisLine =~ /simscan:.*virus: (.*) from: (.*) to: (.*) time: (.*)s/)) { $Simscan{$virus}++; $SimscanTotal++; $SimscanVirusTotal++; $SimscanFrom{$virusfrom}++; $SimscanTo{$virusto}++; if ($Maxscantimevirus < $scantime) { $Maxscantimevirus = $scantime; } $Totalscantimevirus += $scantime; } # simscan-1.2 virus elsif ( (($scantime, $virus, $virusfrom, $virusto ) = ($ThisLine =~ /simscan:\[\d+\]:VIRUS:(.*)s:(.*):.*:(.*):(.*)/)) || (($scantime, $virus, $virusfrom, $virusto ) = ($ThisLine =~ /simscan:\[\d+\]:VIRUS DROPPED:(.*)s:(.*):.*:(.*):(.*)/)) ) { $Simscan{$virus}++; $SimscanTotal++; $SimscanVirusTotal++; $SimscanFrom{$virusfrom}++; $SimscanTo{$virusto}++; if ($Maxscantimevirus < $scantime) { $Maxscantimevirus = $scantime; } $Totalscantimevirus += $scantime; } # simscan attach elsif ( ($attach, $attachfrom, $attachto, $scantime) = ($ThisLine =~ /simscan:.*invalid attachment: (.*) from: (.*) to: (.*) time: (.*)s/) ) { $SimscanTotal++; $SimscanAttach{$attach}++; $SimscanAttachFrom{$attachfrom}++; $SimscanAttachTo{$attachto}++; $SimscanAttachTotal++; if ($Maxscantimeattach < $scantime) { $Maxscantimeattach = $scantime; } $Totalscantimeattach += $scantime; } # simscan-1.2 attach elsif ( ($scantime, $attach, $attachfrom, $attachto ) = ($ThisLine =~ /simscan:\[\d+\]:ATTACH:(.*)s:(.*):.*:(.*):(.*)/)) { $SimscanTotal++; $SimscanAttach{$attach}++; $SimscanAttachFrom{$attachfrom}++; $SimscanAttachTo{$attachto}++; $SimscanAttachTotal++; if ($Maxscantimeattach < $scantime) { $Maxscantimeattach = $scantime; } $Totalscantimeattach += $scantime; } # simscan-1.2 regex elsif ( ($scantime, $regex, $regexfrom, $regexto ) = ($ThisLine =~ /simscan:\[\d+\]:REGEX:(.*)s:(.*):.*:(.*):(.*)/)) { $SimscanTotal++; $SimscanRegex{$regex}++; $SimscanRegexFrom{$regexfrom}++; $SimscanRegexTo{$regexto}++; $SimscanRegexTotal++; if ($Maxscantimeregex < $scantime) { $Maxscantimeregex = $scantime; } $Totalscantimeregex += $scantime; } # simscan-1.2 passthru elsif ( ($passthrulimits, $scantime, $passthruipfrom, $passthrufrom, $passthruto ) = ($ThisLine =~ /simscan:\[\d+\]:PASSTHRU \((.*)\):(.*)s:.*:(.*):(.*):(.*)/)) { $SimscanTotal++; ($ptl1,$ptl2) = split(/\//, $passthrulimits); if( $ptl1 >= $ptl2 ) { $SimscanPassthruIpFrom{$passthruipfrom}++; $SimscanPassthruFrom{$passthrufrom}++; $SimscanPassthruTo{$passthruto}++; $SimscanPassthruTotal++; } if ($Maxscantimespam < $scantime) { $Maxscantimespam = $scantime; } $Totalscantimespam += $scantime; } # simscan-1.2 spam reject elsif ( ( $scantime, $spamrejectipfrom, $spamrejectfrom, $spamrejectto ) = ($ThisLine =~ /simscan:\[\d+\]:SPAM REJECT \(.*\):(.*)s:.*:(.*):(.*):(.*)/)) { $SimscanTotal++; $SimscanSpamrejectIpFrom{$spamrejectipfrom}++; $SimscanSpamrejectFrom{$spamrejectfrom}++; $SimscanSpamrejectTo{$spamrejectto}++; $SimscanSpamrejectTotal++; if ($Maxscantimespam < $scantime) { $Maxscantimespam = $scantime; } $Totalscantimespam += $scantime; } # simscan-1.2 spam dropped elsif ( ( $scantime, $spamdroppedipfrom, $spamdroppedfrom, $spamdroppedto ) = ($ThisLine =~ /simscan:\[\d+\]:SPAM DROPPED \(.*\):(.*)s:.*:(.*):(.*):(.*)/)) { $SimscanTotal++; $SimscanSpamdroppedIpFrom{$spamdroppedipfrom}++; $SimscanSpamdroppedFrom{$spamdroppedfrom}++; $SimscanSpamdroppedTo{$spamdroppedto}++; $SimscanSpamdroppedTotal++; if ($Maxscantimespam < $scantime) { $Maxscantimespam = $scantime; } $Totalscantimespam += $scantime; } # simscan-1.2 clean elsif ( ($scantime) = ($ThisLine =~ /simscan:\[\d+\]:CLEAN \(.*\):(.*)s:.*:.*:.*:.*/) ) { if ($Maxscantimespam < $scantime) { $Maxscantimespam = $scantime; } $Totalscantimespam += $scantime; $SimscanCleanTotal++; } # simscan-1.2 relayclient elsif ( ($scantime) = ($ThisLine =~ /simscan:\[\d+\]:RELAYCLIENT:(.*)s:.*:.*:.*:.*/) ) { if ($Maxscantimespam < $scantime) { $Maxscantimespam = $scantime; } $Totalscantimespam += $scantime; $SimscanRelayClientTotal++; } # simscan quarantine elsif ( $ThisLine =~ /simscan: Putting the message in quarantine/ ) { $Quarantine++; } # badmailfrom elsif ( ($email,$ip) = ($ThisLine =~ /qmail-smtpd: badmailfrom: (.*) at (.*)/) ) { $Badmailfromemail{$email}++; $Badmailfromip{$ip}++; $Badmailfromtot++; } # badmailto elsif ( ($email,$ip) = ($ThisLine =~ /qmail-smtpd: badmailto: (.*) at (.*)/) ) { $Badmailtoemail{$email}++; $Badmailtoip{$ip}++; $Badmailtotot++; } else { # Report any unmatched entries... $ThisLine =~ s/^\s+//g; $ThisLine =~ s/\s+$//g; if ( ! $IgnoreUnmatched && $ThisLine != "" ) { push @OtherList,$ThisLine; } } } if ($QmailDetail >= 1) { if (($FromThreshold < 0) or ($FromThreshold eq '')) { $FromThreshold = $QmailThreshold; } if (($ToThreshold < 0) or ($ToThreshold eq '')) { $ToThreshold = $QmailThreshold; } if (($BlockedThreshold < 0) or ($BlockedThreshold eq '')) { $BlockedThreshold = $QmailThreshold; } if (($SimscanThreshold < 0) or ($SimscanThreshold eq '')) { $SimscanThreshold = $QmailThreshold; } if (($SimscanFromThreshold < 0) or ($SimscanFromThreshold eq '')) { $SimscanFromThreshold = $QmailThreshold; } if (($SimscanToThreshold < 0) or ($SimscanToThreshold eq '')) { $SimscanToThreshold = $QmailThreshold; } if (($SimscanAttachThreshold < 0) or ($SimscanAttachThreshold eq '')) { $SimscanAttachThreshold = $QmailThreshold; } if (($SimscanRegexThreshold < 0) or ($SimscanRegexThreshold eq '')) { $SimscanRegexThreshold = $QmailThreshold; } if (($SimscanPassthruIpFromThreshold < 0) or ($SimscanPassthruIpFromThreshold eq '')) { $SimscanPassthruIpFromThreshold = $QmailThreshold; } if (($SimscanPassthruFromThreshold < 0) or ($SimscanPassthruFromThreshold eq '')) { $SimscanPassthruFromThreshold = $QmailThreshold; } if (($SimscanPassthruToThreshold < 0) or ($SimscanPassthruToThreshold eq '')) { $SimscanPassthruToThreshold = $QmailThreshold; } if (($SimscanSpamRejectIpFromThreshold < 0) or ($SimscanSpamRejectIpFromThreshold eq '')) { $SimscanSpamRejectIpFromThreshold = $QmailThreshold; } if (($SimscanSpamRejectFromThreshold < 0) or ($SimscanSpamRejectFromThreshold eq '')) { $SimscanSpamRejectFromThreshold = $QmailThreshold; } if (($SimscanSpamRejectToThreshold < 0) or ($SimscanSpamRejectToThreshold eq '')) { $SimscanSpamRejectToThreshold = $QmailThreshold; } if (($SimscanSpamDroppedIpFromThreshold < 0) or ($SimscanSpamDroppedIpFromThreshold eq '')) { $SimscanSpamDroppedIpFromThreshold = $QmailThreshold; } if (($SimscanSpamDroppedFromThreshold < 0) or ($SimscanSpamDroppedFromThreshold eq '')) { $SimscanSpamDroppedFromThreshold = $QmailThreshold; } if (($SimscanSpamDroppedToThreshold < 0) or ($SimscanSpamDroppedToThreshold eq '')) { $SimscanSpamDroppedToThreshold = $QmailThreshold; } if (($ChkuserRejectsFromThreshold < 0) or ($ChkuserRejectsFromThreshold eq '')) { $ChkuserRejectsFromThreshold = $QmailThreshold; } if (($ChkuserRejectsToThreshold < 0) or ($ChkuserRejectsToThreshold eq '')) { $ChkuserRejectsToThreshold = $QmailThreshold; } if (($ChkuserRejectsRemoteThreshold < 0) or ($ChkuserRejectsRemoteThreshold eq '')) { $ChkuserRejectsRemoteThreshold = $QmailThreshold; } if (($ChkuserRejectsRelayFromThreshold < 0) or ($ChkuserRejectsRelayFromThreshold eq '')) { $ChkuserRejectsRelayFromThreshold = $QmailThreshold; } if (($ChkuserRejectsRelayToThreshold < 0) or ($ChkuserRejectsRelayToThreshold eq '')) { $ChkuserRejectsRelayToThreshold = $QmailThreshold; } if (($ChkuserRejectsRelayRemoteThreshold < 0) or ($ChkuserRejectsRelayRemoteThreshold eq '')) { $ChkuserRejectsRelayRemoteThreshold = $QmailThreshold; } if (($ChkuserRejectsReasonThreshold < 0) or ($ChkuserRejectsReasonThreshold eq '')) { $ChkuserRejectsReasonThreshold = $QmailThreshold; } if (($ChkuserAcceptsFromThreshold < 0) or ($ChkuserAcceptsFromThreshold eq '')) { $ChkuserAcceptsFromThreshold = $QmailThreshold; } if (($ChkuserAcceptsToThreshold < 0) or ($ChkuserAcceptsToThreshold eq '')) { $ChkuserAcceptsToThreshold = $QmailThreshold; } if (($ChkuserAcceptsRelayFromThreshold < 0) or ($ChkuserAcceptsRelayFromThreshold eq '')) { $ChkuserAcceptsRelayFromThreshold = $QmailThreshold; } if (($ChkuserAcceptsRelayToThreshold < 0) or ($ChkuserAcceptsRelayToThreshold eq '')) { $ChkuserAcceptsRelayToThreshold = $QmailThreshold; } if (($ChkuserNoAuthResourceThreshold < 0) or ($ChkuserNoAuthResourceThreshold eq '')) { $ChkuserNoAuthResourceThreshold = $QmailThreshold; } if (($ChkuserOverquotaThreshold < 0) or ($ChkuserOverquotaThreshold eq '')) { $ChkuserOverquotaThreshold = $QmailThreshold; } if (($ChkuserRejectedIntrusionThreshold <0) or ($ChkuserRejectedIntrusionThreshold eq '')) { $ChkuserRejectedIntrusionThreshold = $QmailThreshold; } if (($ChkuserAcceptedSenderFromThreshold <0) or ($ChkuserAcceptedSenderFromThreshold eq '')) { $ChkuserAcceptedSenderFromThreshold = $QmailThreshold; } if (($ChkuserAcceptedSenderRemoteThreshold <0) or ($ChkuserAcceptedSenderRemoteThreshold eq '')) { $ChkuserAcceptedSenderRemoteThreshold = $QmailThreshold; } if (($ChkuserAcceptedNullSenderFromThreshold <0) or ($ChkuserAcceptedNullSenderFromThreshold eq '')) { $ChkuserAcceptedNullSenderFromThreshold = $QmailThreshold; } if (($ChkuserRejectedSenderFromThreshold <0) or ($ChkuserRejectedSenderFromThreshold eq '')) { $ChkuserRejectedSenderFromThreshold = $QmailThreshold; } if (($ChkuserRejectedSenderRemoteThreshold <0) or ($ChkuserRejectedSenderRemoteThreshold eq '')) { $ChkuserRejectedSenderRemoteThreshold = $QmailThreshold; } if (($ChkuserRejectedSenderReasonThreshold <0) or ($ChkuserRejectedSenderReasonThreshold eq '')) { $ChkuserRejectedSenderReasonThreshold = $QmailThreshold; } if (($BadMailToIpThreshold <0) or ($BadMailToIpThreshold eq '')) { $BadMailToIpThreshold = $QmailThreshold; } if (($BadMailToEmailThreshold <0) or ($BadMailToEmailThreshold eq '')) { $BadMailToEmailThreshold = $QmailThreshold; } if (($BadMailFromIpThreshold <0) or ($BadMailFromIpThreshold eq '')) { $BadMailFromIpThreshold = $QmailThreshold; } if (($BadMailFromEmailThreshold <0) or ($BadMailFromEmailThreshold eq '')) { $BadMailFromEmailThreshold = $QmailThreshold; } # start output if ( (keys %From) ) { print "\nConnections from (Threshold of " . $FromThreshold . "):\n"; $threshold_reached=0; foreach my $Line (sort {$From{$b} <=> $From{$a}} keys %From) { if ($From{$Line} >= $FromThreshold) { $threshold_reached=1; if ($Domains{$Line}) { print "\t" . $Domains{$Line} . " [$Line] - ". $From{$Line} . " Time(s)\n"; } else { print "\t" . $Line . " - ". $From{$Line} . " Time(s)\n"; } } } if ($threshold_reached < 1) { print "\t" . "None found above the threshold\n"; } } if ( (keys %To) ) { print "\nConnections to (Threshold of " . $ToThreshold . "):\n"; $threshold_reached=0; foreach my $Line (sort {$To{$b} <=> $To{$a}} keys %To) { if ($To{$Line} >= $ToThreshold) { $threshold_reached=1; if ($Domains{$Line}) { print "\t" . $Domains{$Line} . " [$Line] - ". $To{$Line} . " Time(s)\n"; } else { print "\t" . $Line . " - ". $To{$Line} . " Time(s)\n"; } } } if ($threshold_reached < 1) { print "\t" . "None found above the threshold\n"; } } if ( (keys %Blockeds) ) { print "\nBlocked (Threshold of " . $BlockedThreshold . "):\n"; $threshold_reached=0; foreach my $Line (sort {$Blockeds{$b} <=> $Blockeds{$a}} keys %Blockeds) { if ($Blockeds{$Line} >= $BlockedThreshold) { $threshold_reached=1; if ($Domains{$Line}) { print "\t" . $Domains{$Line} . " [$Line] - ". $Blockeds{$Line} . " Time(s)" . ($Rbl{$Line} ? " By ".$Rbl{$Line} : "") . "\n"; } else { print "\t" . $Line . " - ". $Blockeds{$Line} . " Time(s)" . ($Rbl{$Line} ? " By ".$Rbl{$Line} : "") . "\n"; } } } if ($threshold_reached < 1) { print "\t" . "None found above the threshold\n"; } } # chkuser if ( $ShowChkuserRejects ) { if ( (keys %ChkuserRejectsFrom) ) { print "\nChkuser Rejects From (Threshold of " . $ChkuserRejectsFromThreshold . "):\n"; $threshold_reached=0; foreach my $Line (sort {$ChkuserRejectsFrom{$b} <=> $ChkuserRejectsFrom{$a}} keys %ChkuserRejectsFrom) { if ($ChkuserRejectsFrom{$Line} >= $ChkuserRejectsFromThreshold) { $threshold_reached=1; if ($Domains{$Line}) { print "\t" . $Domains{$Line} . " [$Line] - ". $ChkuserRejectsFrom{$Line} . " Time(s)\n"; } else { print "\t" . $Line . " - ". $ChkuserRejectsFrom{$Line} . " Time(s)\n"; } } } if ($threshold_reached < 1) { print "\t" . "None found above the threshold\n"; } } if ( (keys %ChkuserRejectsTo) ) { print "\nChkuser Rejects To (Threshold of " . $ChkuserRejectsToThreshold . "):\n"; $threshold_reached=0; foreach my $Line (sort {$ChkuserRejectsTo{$b} <=> $ChkuserRejectsTo{$a}} keys %ChkuserRejectsTo) { if ($ChkuserRejectsTo{$Line} >= $ChkuserRejectsToThreshold) { $threshold_reached=1; if ($Domains{$Line}) { print "\t" . $Domains{$Line} . " [$Line] - ". $ChkuserRejectsTo{$Line} . " Time(s)\n"; } else { print "\t" . $Line . " - ". $ChkuserRejectsTo{$Line} . " Time(s)\n"; } } } if ($threshold_reached < 1) { print "\t" . "None found above the threshold\n"; } } if ( (keys %ChkuserRejectsRemote) ) { print "\nChkuser Rejects Remote (Threshold of " . $ChkuserRejectsRemoteThreshold . "):\n"; $threshold_reached=0; foreach my $Line (sort {$ChkuserRejectsRemote{$b} <=> $ChkuserRejectsRemote{$a}} keys %ChkuserRejectsRemote) { if ($ChkuserRejectsRemote{$Line} >= $ChkuserRejectsRemoteThreshold) { $threshold_reached=1; if ($Domains{$Line}) { print "\t" . $Domains{$Line} . " [$Line] - ". $ChkuserRejectsRemote{$Line} . " Time(s)\n"; } else { print "\t" . $Line . " - ". $ChkuserRejectsRemote{$Line} . " Time(s)\n"; } } } if ($threshold_reached < 1) { print "\t" . "None found above the threshold\n"; } } } if ( $ShowChkuserRejectsRelay ) { if ( (keys %ChkuserRejectsRelayFrom) ) { print "\nChkuser Rejects Relay From (Threshold of " . $ChkuserRejectsRelayFromThreshold . "):\n"; $threshold_reached=0; foreach my $Line (sort {$ChkuserRejectsRelayFrom{$b} <=> $ChkuserRejectsRelayFrom{$a}} keys %ChkuserRejectsRelayFrom) { if ($ChkuserRejectsRelayFrom{$Line} >= $ChkuserRejectsRelayFromThreshold) { $threshold_reached=1; if ($Domains{$Line}) { print "\t" . $Domains{$Line} . " [$Line] - ". $ChkuserRejectsRelayFrom{$Line} . " Time(s)\n"; } else { print "\t" . $Line . " - ". $ChkuserRejectsRelayFrom{$Line} . " Time(s)\n"; } } } if ($threshold_reached < 1) { print "\t" . "None found above the threshold\n"; } } if ( (keys %ChkuserRejectsRelayTo) ) { print "\nChkuser Rejects Relay To (Threshold of " . $ChkuserRejectsRelayToThreshold . "):\n"; $threshold_reached=0; foreach my $Line (sort {$ChkuserRejectsRelayTo{$b} <=> $ChkuserRejectsRelayTo{$a}} keys %ChkuserRejectsRelayTo) { if ($ChkuserRejectsRelayTo{$Line} >= $ChkuserRejectsRelayToThreshold) { $threshold_reached=1; if ($Domains{$Line}) { print "\t" . $Domains{$Line} . " [$Line] - ". $ChkuserRejectsRelayTo{$Line} . " Time(s)\n"; } else { print "\t" . $Line . " - ". $ChkuserRejectsRelayTo{$Line} . " Time(s)\n"; } } } if ($threshold_reached < 1) { print "\t" . "None found above the threshold\n"; } } if ( (keys %ChkuserRejectsRelayRemote) ) { print "\nChkuser Rejects Relay Remote (Threshold of " . $ChkuserRejectsRelayRemoteThreshold . "):\n"; $threshold_reached=0; foreach my $Line (sort {$ChkuserRejectsRelayRemote{$b} <=> $ChkuserRejectsRelayRemote{$a}} keys %ChkuserRejectsRelayRemote) { if ($ChkuserRejectsRelayRemote{$Line} >= $ChkuserRejectsRelayRemoteThreshold) { $threshold_reached=1; if ($Domains{$Line}) { print "\t" . $Domains{$Line} . " [$Line] - ". $ChkuserRejectsRelayRemote{$Line} . " Time(s)\n"; } else { print "\t" . $Line . " - ". $ChkuserRejectsRelayRemote{$Line} . " Time(s)\n"; } } } if ($threshold_reached < 1) { print "\t" . "None found above the threshold\n"; } } } if ( $ShowChkuserRejects ) { if ( (keys %ChkuserRejectsReason) ) { print "\nChkuser Rejects Reason (Threshold of " . $ChkuserRejectsReasonThreshold . "):\n"; $threshold_reached=0; foreach my $Line (sort {$ChkuserRejectsReason{$b} <=> $ChkuserRejectsReason{$a}} keys %ChkuserRejectsReason) { if ($ChkuserRejectsReason{$Line} >= $ChkuserRejectsReasonThreshold) { $threshold_reached=1; if ($Domains{$Line}) { print "\t" . $Domains{$Line} . " [$Line] - ". $ChkuserRejectsReason{$Line} . " Time(s)\n"; } else { print "\t" . $Line . " - ". $ChkuserRejectsReason{$Line} . " Time(s)\n"; } } } if ($threshold_reached < 1) { print "\t" . "None found above the threshold\n"; } } } if ( $ShowChkuserAccepts ) { if ( (keys %ChkuserAcceptsFrom) ) { print "\nChkuser Accepts from (Threshold of " . $ChkuserAcceptsFromThreshold . "):\n"; $threshold_reached=0; foreach my $Line (sort {$ChkuserAcceptsFrom{$b} <=> $ChkuserAcceptsFrom{$a}} keys %ChkuserAcceptsFrom) { if ($ChkuserAcceptsFrom{$Line} >= $ChkuserAcceptsFromThreshold) { $threshold_reached=1; if ($Domains{$Line}) { print "\t" . $Domains{$Line} . " [$Line] - ". $ChkuserAcceptsFrom{$Line} . " Time(s)\n"; } else { print "\t" . $Line . " - ". $ChkuserAcceptsFrom{$Line} . " Time(s)\n"; } } } if ($threshold_reached < 1) { print "\t" . "None found above the threshold\n"; } } if ( (keys %ChkuserAcceptsTo) ) { print "\nChkuser Accepts to (Threshold of " . $ChkuserAcceptsToThreshold . "):\n"; $threshold_reached=0; foreach my $Line (sort {$ChkuserAcceptsTo{$b} <=> $ChkuserAcceptsTo{$a}} keys %ChkuserAcceptsTo) { if ($ChkuserAcceptsTo{$Line} >= $ChkuserAcceptsToThreshold) { $threshold_reached=1; if ($Domains{$Line}) { print "\t" . $Domains{$Line} . " [$Line] - ". $ChkuserAcceptsTo{$Line} . " Time(s)\n"; } else { print "\t" . $Line . " - ". $ChkuserAcceptsTo{$Line} . " Time(s)\n"; } } } if ($threshold_reached < 1) { print "\t" . "None found above the threshold\n"; } } } if ( $ShowChkuserAcceptsRelay ) { if ( (keys %ChkuserAcceptsRelayFrom) ) { print "\nChkuser Accepts Relay from (Threshold of " . $ChkuserAcceptsRelayFromThreshold . "):\n"; $threshold_reached=0; foreach my $Line (sort {$ChkuserAcceptsRelayFrom{$b} <=> $ChkuserAcceptsRelayFrom{$a}} keys %ChkuserAcceptsRelayFrom) { if ($ChkuserAcceptsRelayFrom{$Line} >= $ChkuserAcceptsRelayFromThreshold) { $threshold_reached=1; if ($Domains{$Line}) { print "\t" . $Domains{$Line} . " [$Line] - ". $ChkuserAcceptsRelayFrom{$Line} . " Time(s)\n"; } else { print "\t" . $Line . " - ". $ChkuserAcceptsRelayFrom{$Line} . " Time(s)\n"; } } } if ($threshold_reached < 1) { print "\t" . "None found above the threshold\n"; } } if ( (keys %ChkuserAcceptsRelayTo) ) { print "\nChkuser Accepts Relay to (Threshold of " . $ChkuserAcceptsRelayToThreshold . "):\n"; $threshold_reached=0; foreach my $Line (sort {$ChkuserAcceptsRelayTo{$b} <=> $ChkuserAcceptsRelayTo{$a}} keys %ChkuserAcceptsRelayTo) { if ($ChkuserAcceptsRelayTo{$Line} >= $ChkuserAcceptsRelayToThreshold) { $threshold_reached=1; if ($Domains{$Line}) { print "\t" . $Domains{$Line} . " [$Line] - ". $ChkuserAcceptsRelayTo{$Line} . " Time(s)\n"; } else { print "\t" . $Line . " - ". $ChkuserAcceptsRelayTo{$Line} . " Time(s)\n"; } } } if ($threshold_reached < 1) { print "\t" . "None found above the threshold\n"; } } } if ( $ShowChkuserOther ) { if ( (keys %ChkuserNoAuthResourceFrom) ) { print "\nChkuser No Auth Resource from (Threshold of " . $ChkuserNoAuthResourceThreshold . "):\n"; $threshold_reached=0; foreach my $Line (sort {$ChkuserNoAuthResourceFrom{$b} <=> $ChkuserNoAuthResourceFrom{$a}} keys %ChkuserNoAuthResourceFrom) { if ($ChkuserNoAuthResourceFrom{$Line} >= $ChkuserNoAuthResourceThreshold) { $threshold_reached=1; if ($Domains{$Line}) { print "\t" . $Domains{$Line} . " [$Line] - ". $ChkuserNoAuthResourceFrom{$Line} . " Time(s)\n"; } else { print "\t" . $Line . " - ". $ChkuserNoAuthResourceFrom{$Line} . " Time(s)\n"; } } } if ($threshold_reached < 1) { print "\t" . "None found above the threshold\n"; } } if ( (keys %ChkuserNoAuthResourceTo) ) { print "\nChkuser No Auth resource to (Threshold of " . $ChkuserNoAuthResourceThreshold . "):\n"; $threshold_reached=0; foreach my $Line (sort {$ChkuserNoAuthResourceTo{$b} <=> $ChkuserNoAuthResourceTo{$a}} keys %ChkuserNoAuthResourceTo) { if ($ChkuserNoAuthResourceTo{$Line} >= $ChkuserNoAuthResourceThreshold) { $threshold_reached=1; if ($Domains{$Line}) { print "\t" . $Domains{$Line} . " [$Line] - ". $ChkuserNoAuthResourceTo{$Line} . " Time(s)\n"; } else { print "\t" . $Line . " - ". $ChkuserNoAuthResourceTo{$Line} . " Time(s)\n"; } } } if ($threshold_reached < 1) { print "\t" . "None found above the threshold\n"; } } if ( (keys %ChkuserOverquotaTo) ) { print "\nChkuser Over Quota (Threshold of " . $ChkuserOverquotaThreshold . "):\n"; $threshold_reached=0; foreach my $Line (sort {$ChkuserOverquotaTo{$b} <=> $ChkuserOverquotaTo{$a}} keys %ChkuserOverquotaTo) { if ($ChkuserOverquotaTo{$Line} >= $ChkuserOverquotaThreshold) { $threshold_reached=1; if ($Domains{$Line}) { print "\t" . $Domains{$Line} . " [$Line] - ". $ChkuserOverquotaTo{$Line} . " Time(s)\n"; } else { print "\t" . $Line . " - ". $ChkuserOverquotaTo{$Line} . " Time(s)\n"; } } } if ($threshold_reached < 1) { print "\t" . "None found above the threshold\n"; } } if ( (keys %ChkuserRejectedIntrusionFrom) ) { print "\nChkuser Rejected Intrusions from (Threshold of " . $ChkuserRejectedIntrusionThreshold . "):\n"; $threshold_reached=0; foreach my $Line (sort {$ChkuserRejectedIntrusionFrom{$b} <=> $ChkuserRejectedIntrusionFrom{$a}} keys %ChkuserRejectedIntrusionFrom) { if ($ChkuserRejectedIntrusionFrom{$Line} >= $ChkuserRejectedIntrusionThreshold) { $threshold_reached=1; if ($Domains{$Line}) { print "\t" . $Domains{$Line} . " [$Line] - ". $ChkuserRejectedIntrusionFrom{$Line} . " Time(s)\n"; } else { print "\t" . $Line . " - ". $ChkuserRejectedIntrusionFrom{$Line} . " Time(s)\n"; } } } if ($threshold_reached < 1) { print "\t" . "None found above the threshold\n"; } } if ( (keys %ChkuserRejectedIntrusionTo) ) { print "\nChkuser Rejected Intrusions to (Threshold of " . $ChkuserRejectedIntrusionThreshold . "):\n"; $threshold_reached=0; foreach my $Line (sort {$ChkuserRejectedIntrusionTo{$b} <=> $ChkuserRejectedIntrusionTo{$a}} keys %ChkuserRejectedIntrusionTo) { if ($ChkuserRejectedIntrusionTo{$Line} >= $ChkuserRejectedIntrusionThreshold) { $threshold_reached=1; if ($Domains{$Line}) { print "\t" . $Domains{$Line} . " [$Line] - ". $ChkuserRejectedIntrusionTo{$Line} . " Time(s)\n"; } else { print "\t" . $Line . " - ". $ChkuserRejectedIntrusionTo{$Line} . " Time(s)\n"; } } } if ($threshold_reached < 1) { print "\t" . "None found above the threshold\n"; } } } if ( $ShowChkuserAcceptedSender ) { if ( (keys %ChkuserAcceptedSenderFrom) ) { print "\nChkuser accepted senders from (Threshold of " . $ChkuserAcceptedSenderFromThreshold . "):\n"; $threshold_reached=0; foreach my $Line (sort {$ChkuserAcceptedSenderFrom{$b} <=> $ChkuserAcceptedSenderFrom{$a}} keys %ChkuserAcceptedSenderFrom) { if ($ChkuserAcceptedSenderFrom{$Line} >= $ChkuserAcceptedSenderFromThreshold) { $threshold_reached=1; if ($Domains{$Line}) { print "\t" . $Domains{$Line} . " [$Line] - ". $ChkuserAcceptedSenderFrom{$Line} . " Time(s)\n"; } else { print "\t" . $Line . " - ". $ChkuserAcceptedSenderFrom{$Line} . " Time(s)\n"; } } } if ($threshold_reached < 1) { print "\t" . "None found above the threshold\n"; } } if ( (keys %ChkuserAcceptedSenderRemote) ) { print "\nChkuser accepted senders remote (Threshold of " . $ChkuserAcceptedSenderRemoteThreshold . "):\n"; $threshold_reached=0; foreach my $Line (sort {$ChkuserAcceptedSenderRemote{$b} <=> $ChkuserAcceptedSenderRemote{$a}} keys %ChkuserAcceptedSenderRemote) { if ($ChkuserAcceptedSenderRemote{$Line} >= $ChkuserAcceptedSenderRemoteThreshold) { $threshold_reached=1; if ($Domains{$Line}) { print "\t" . $Domains{$Line} . " [$Line] - ". $ChkuserAcceptedSenderRemote{$Line} . " Time(s)\n"; } else { print "\t" . $Line . " - ". $ChkuserAcceptedSenderRemote{$Line} . " Time(s)\n"; } } } if ($threshold_reached < 1) { print "\t" . "None found above the threshold\n"; } } if ( (keys %ChkuserAcceptedNullSenderFrom) ) { print "\nChkuser accepted null senders from (Threshold of " . $ChkuserAcceptedNullSenderFromThreshold . "):\n"; $threshold_reached=0; foreach my $Line (sort {$ChkuserAcceptedNullSenderFrom{$b} <=> $ChkuserAcceptedNullSenderFrom{$a}} keys %ChkuserAcceptedNullSenderFrom) { if ($ChkuserAcceptedNullSenderFrom{$Line} >= $ChkuserAcceptedNullSenderFromThreshold) { $threshold_reached=1; if ($Domains{$Line}) { print "\t" . $Domains{$Line} . " [$Line] - ". $ChkuserAcceptedNullSenderFrom{$Line} . " Time(s)\n"; } else { print "\t" . $Line . " - ". $ChkuserAcceptedNullSenderFrom{$Line} . " Time(s)\n"; } } } if ($threshold_reached < 1) { print "\t" . "None found above the threshold\n"; } } } if ( $ShowChkuserRejectedSender ) { if ( (keys %ChkuserRejectedSenderFrom) ) { print "\nChkuser rejected senders from (Threshold of " . $ChkuserRejectedSenderFromThreshold . "):\n"; $threshold_reached=0; foreach my $Line (sort {$ChkuserRejectedSenderFrom{$b} <=> $ChkuserRejectedSenderFrom{$a}} keys %ChkuserRejectedSenderFrom) { if ($ChkuserRejectedSenderFrom{$Line} >= $ChkuserRejectedSenderFromThreshold) { $threshold_reached=1; if ($Domains{$Line}) { print "\t" . $Domains{$Line} . " [$Line] - ". $ChkuserRejectedSenderFrom{$Line} . " Time(s)\n"; } else { print "\t" . $Line . " - ". $ChkuserRejectedSenderFrom{$Line} . " Time(s)\n"; } } } if ($threshold_reached < 1) { print "\t" . "None found above the threshold\n"; } } if ( (keys %ChkuserRejectedSenderRemote) ) { print "\nChkuser rejected senders remote (Threshold of " . $ChkuserRejectedSenderRemoteThreshold . "):\n"; $threshold_reached=0; foreach my $Line (sort {$ChkuserRejectedSenderRemote{$b} <=> $ChkuserRejectedSenderRemote{$a}} keys %ChkuserRejectedSenderRemote) { if ($ChkuserRejectedSenderRemote{$Line} >= $ChkuserRejectedSenderRemoteThreshold) { $threshold_reached=1; if ($Domains{$Line}) { print "\t" . $Domains{$Line} . " [$Line] - ". $ChkuserRejectedSenderRemote{$Line} . " Time(s)\n"; } else { print "\t" . $Line . " - ". $ChkuserRejectedSenderRemote{$Line} . " Time(s)\n"; } } } if ($threshold_reached < 1) { print "\t" . "None found above the threshold\n"; } } if ( (keys %ChkuserRejectedSenderReason) ) { print "\nChkuser rejected senders reason (Threshold of " . $ChkuserRejectedSenderReasonThreshold . "):\n"; $threshold_reached=0; foreach my $Line (sort {$ChkuserRejectedSenderReason{$b} <=> $ChkuserRejectedSenderReason{$a}} keys %ChkuserRejectedSenderReason) { if ($ChkuserRejectedSenderReason{$Line} >= $ChkuserRejectedSenderReasonThreshold) { $threshold_reached=1; if ($Domains{$Line}) { print "\t" . $Domains{$Line} . " [$Line] - ". $ChkuserRejectedSenderReason{$Line} . " Time(s)\n"; } else { print "\t" . $Line . " - ". $ChkuserRejectedSenderReason{$Line} . " Time(s)\n"; } } } if ($threshold_reached < 1) { print "\t" . "None found above the threshold\n"; } } } # simscan if ( (keys %Simscan) ) { print "\nSimscan Viruses (Threshold of " . $SimscanThreshold . "):\n"; $threshold_reached=0; foreach my $Line (sort {$Simscan{$b} <=> $Simscan{$a}} keys %Simscan) { if ($Simscan{$Line} >= $SimscanThreshold) { $threshold_reached=1; if ($Domains{$Line}) { print "\t" . $Domains{$Line} . " [$Line] - ". $Simscan{$Line} . " Time(s)\n"; } else { print "\t" . $Line . " - ". $Simscan{$Line} . " Time(s)\n"; } } } if ($threshold_reached < 1) { print "\t" . "None found above the threshold\n"; } } # simscan from if ( (keys %SimscanFrom) ) { print "\nSimscan Viruses From (Threshold of " . $SimscanFromThreshold . "):\n"; $threshold_reached=0; foreach my $Line (sort {$SimscanFrom{$b} <=> $SimscanFrom{$a}} keys %SimscanFrom) { if ($SimscanFrom{$Line} >= $SimscanFromThreshold) { $threshold_reached=1; if ($Domains{$Line}) { print "\t" . $Domains{$Line} . " [$Line] - ". $SimscanFrom{$Line} . " Time(s)\n"; } else { print "\t" . $Line . " - ". $SimscanFrom{$Line} . " Time(s)\n"; } } } if ($threshold_reached < 1) { print "\t" . "None found above the threshold\n"; } } # simscan to if ( (keys %SimscanTo) ) { print "\nSimscan Viruses To (Threshold of " . $SimscanToThreshold . "):\n"; $threshold_reached=0; foreach my $Line (sort {$SimscanTo{$b} <=> $SimscanTo{$a}} keys %SimscanTo) { if ($SimscanTo{$Line} >= $SimscanToThreshold) { $threshold_reached=1; if ($Domains{$Line}) { print "\t" . $Domains{$Line} . " [$Line] - ". $SimscanTo{$Line} . " Time(s)\n"; } else { print "\t" . $Line . " - ". $SimscanTo{$Line} . " Time(s)\n"; } } } if ($threshold_reached < 1) { print "\t" . "None found above the threshold\n"; } } # simscan attach if ( (keys %SimscanAttach) ) { print "\nSimscan Attachments (Threshold of " . $SimscanAttachThreshold . "):\n"; $threshold_reached=0; foreach my $Line (sort {$SimscanAttach{$b} <=> $SimscanAttach{$a}} keys %SimscanAttach) { if ($SimscanAttach{$Line} >= $SimscanAttachThreshold) { $threshold_reached=1; if ($Domains{$Line}) { print "\t" . $Domains{$Line} . " [$Line] - ". $SimscanAttach{$Line} . " Time(s)\n"; } else { print "\t" . $Line . " - ". $SimscanAttach{$Line} . " Time(s)\n"; } } } if ($threshold_reached < 1) { print "\t" . "None found above the threshold\n"; } } # simscan attach from if ( (keys %SimscanAttachFrom) ) { print "\nSimscan Attachments From (Threshold of " . $SimscanAttachThreshold . "):\n"; $threshold_reached=0; foreach my $Line (sort {$SimscanAttachFrom{$b} <=> $SimscanAttachFrom{$a}} keys %SimscanAttachFrom) { if ($SimscanAttachFrom{$Line} >= $SimscanAttachThreshold) { $threshold_reached=1; if ($Domains{$Line}) { print "\t" . $Domains{$Line} . " [$Line] - ". $SimscanAttachFrom{$Line} . " Time(s)\n"; } else { print "\t" . $Line . " - ". $SimscanAttachFrom{$Line} . " Time(s)\n"; } } } if ($threshold_reached < 1) { print "\t" . "None found above the threshold\n"; } } # simscan attach to if ( (keys %SimscanAttachTo) ) { print "\nSimscan Attachments To (Threshold of " . $SimscanAttachThreshold . "):\n"; $threshold_reached=0; foreach my $Line (sort {$SimscanAttachTo{$b} <=> $SimscanAttachTo{$a}} keys %SimscanAttachTo) { if ($SimscanAttachTo{$Line} >= $SimscanAttachThreshold) { $threshold_reached=1; if ($Domains{$Line}) { print "\t" . $Domains{$Line} . " [$Line] - ". $SimscanAttachTo{$Line} . " Time(s)\n"; } else { print "\t" . $Line . " - ". $SimscanAttachTo{$Line} . " Time(s)\n"; } } } if ($threshold_reached < 1) { print "\t" . "None found above the threshold\n"; } } # simscan regex if ( (keys %SimscanRegex) ) { print "\nSimscan Regex (Threshold of " . $SimscanRegexThreshold . "):\n"; $threshold_reached=0; foreach my $Line (sort {$SimscanRegex{$b} <=> $SimscanRegex{$a}} keys %SimscanRegex) { if ($SimscanRegex{$Line} >= $SimscanRegexThreshold) { $threshold_reached=1; if ($Domains{$Line}) { print "\t" . $Domains{$Line} . " [$Line] - ". $SimscanRegex{$Line} . " Time(s)\n"; } else { print "\t" . $Line . " - ". $SimscanRegex{$Line} . " Time(s)\n"; } } } if ($threshold_reached < 1) { print "\t" . "None found above the threshold\n"; } } # simscan regex from if ( (keys %SimscanRegexFrom) ) { print "\nSimscan Regex From (Threshold of " . $SimscanRegexThreshold . "):\n"; $threshold_reached=0; foreach my $Line (sort {$SimscanRegexFrom{$b} <=> $SimscanRegexFrom{$a}} keys %SimscanRegexFrom) { if ($SimscanRegexFrom{$Line} >= $SimscanRegexThreshold) { $threshold_reached=1; if ($Domains{$Line}) { print "\t" . $Domains{$Line} . " [$Line] - ". $SimscanRegexFrom{$Line} . " Time(s)\n"; } else { print "\t" . $Line . " - ". $SimscanRegexFrom{$Line} . " Time(s)\n"; } } } if ($threshold_reached < 1) { print "\t" . "None found above the threshold\n"; } } # simscan regex to if ( (keys %SimscanRegexTo) ) { print "\nSimscan Regex To (Threshold of " . $SimscanRegexThreshold . "):\n"; $threshold_reached=0; foreach my $Line (sort {$SimscanRegexTo{$b} <=> $SimscanRegexTo{$a}} keys %SimscanRegexTo) { if ($SimscanRegexTo{$Line} >= $SimscanRegexThreshold) { $threshold_reached=1; if ($Domains{$Line}) { print "\t" . $Domains{$Line} . " [$Line] - ". $SimscanRegexTo{$Line} . " Time(s)\n"; } else { print "\t" . $Line . " - ". $SimscanRegexTo{$Line} . " Time(s)\n"; } } } if ($threshold_reached < 1) { print "\t" . "None found above the threshold\n"; } } if($ShowSimscanPassthru) { # simscan passthru ip from if ( (keys %SimscanPassthruIpFrom) ) { print "\nSimscan Passthru Ip From (Threshold of " . $SimscanPassthruIpFromThreshold . "):\n"; $threshold_reached=0; foreach my $Line (sort {$SimscanPassthruIpFrom{$b} <=> $SimscanPassthruIpFrom{$a}} keys %SimscanPassthruIpFrom) { if ($SimscanPassthruIpFrom{$Line} >= $SimscanPassthruIpFromThreshold) { $threshold_reached=1; if ($Domains{$Line}) { print "\t" . $Domains{$Line} . " [$Line] - ". $SimscanPassthruIpFrom{$Line} . " Time(s)\n"; } else { print "\t" . $Line . " - ". $SimscanPassthruIpFrom{$Line} . " Time(s)\n"; } } } if ($threshold_reached < 1) { print "\t" . "None found above the threshold\n"; } } # simscan passthru from if ( (keys %SimscanPassthruFrom) ) { print "\nSimscan Passthru From (Threshold of " . $SimscanPassthruFromThreshold . "):\n"; $threshold_reached=0; foreach my $Line (sort {$SimscanPassthruFrom{$b} <=> $SimscanPassthruFrom{$a}} keys %SimscanPassthruFrom) { if ($SimscanPassthruFrom{$Line} >= $SimscanPassthruFromThreshold) { $threshold_reached=1; if ($Domains{$Line}) { print "\t" . $Domains{$Line} . " [$Line] - ". $SimscanPassthruFrom{$Line} . " Time(s)\n"; } else { print "\t" . $Line . " - ". $SimscanPassthruFrom{$Line} . " Time(s)\n"; } } } if ($threshold_reached < 1) { print "\t" . "None found above the threshold\n"; } } # simscan passthru to if ( (keys %SimscanPassthruTo) ) { print "\nSimscan Passthru To (Threshold of " . $SimscanPassthruToThreshold . "):\n"; $threshold_reached=0; foreach my $Line (sort {$SimscanPassthruTo{$b} <=> $SimscanPassthruTo{$a}} keys %SimscanPassthruTo) { if ($SimscanPassthruTo{$Line} >= $SimscanPassthruToThreshold) { $threshold_reached=1; if ($Domains{$Line}) { print "\t" . $Domains{$Line} . " [$Line] - ". $SimscanPassthruTo{$Line} . " Time(s)\n"; } else { print "\t" . $Line . " - ". $SimscanPassthruTo{$Line} . " Time(s)\n"; } } } if ($threshold_reached < 1) { print "\t" . "None found above the threshold\n"; } } } if ($ShowSimscanSpamReject) { # simscan spamreject ip from if ( (keys %SimscanSpamrejectIpFrom) ) { print "\nSimscan Spam reject Ip From (Threshold of " . $SimscanSpamRejectIpFromThreshold . "):\n"; $threshold_reached=0; foreach my $Line (sort {$SimscanSpamrejectIpFrom{$b} <=> $SimscanSpamrejectIpFrom{$a}} keys %SimscanSpamrejectIpFrom) { if ($SimscanSpamrejectIpFrom{$Line} >= $SimscanSpamRejectIpFromThreshold) { $threshold_reached=1; if ($Domains{$Line}) { print "\t" . $Domains{$Line} . " [$Line] - ". $SimscanSpamrejectIpFrom{$Line} . " Time(s)\n"; } else { print "\t" . $Line . " - ". $SimscanSpamrejectIpFrom{$Line} . " Time(s)\n"; } } } if ($threshold_reached < 1) { print "\t" . "None found above the threshold\n"; } } # simscan spamreject from if ( (keys %SimscanSpamrejectFrom) ) { print "\nSimscan Spam reject From (Threshold of " . $SimscanSpamRejectFromThreshold . "):\n"; $threshold_reached=0; foreach my $Line (sort {$SimscanSpamrejectFrom{$b} <=> $SimscanSpamrejectFrom{$a}} keys %SimscanSpamrejectFrom) { if ($SimscanSpamrejectFrom{$Line} >= $SimscanSpamRejectFromThreshold) { $threshold_reached=1; if ($Domains{$Line}) { print "\t" . $Domains{$Line} . " [$Line] - ". $SimscanSpamrejectFrom{$Line} . " Time(s)\n"; } else { print "\t" . $Line . " - ". $SimscanSpamrejectFrom{$Line} . " Time(s)\n"; } } } if ($threshold_reached < 1) { print "\t" . "None found above the threshold\n"; } } # simscan spamreject to if ( (keys %SimscanSpamrejectTo) ) { print "\nSimscan Spam reject To (Threshold of " . $SimscanSpamRejectToThreshold . "):\n"; $threshold_reached=0; foreach my $Line (sort {$SimscanSpamrejectTo{$b} <=> $SimscanSpamrejectTo{$a}} keys %SimscanSpamrejectTo) { if ($SimscanSpamrejectTo{$Line} >= $SimscanSpamRejectToThreshold) { $threshold_reached=1; if ($Domains{$Line}) { print "\t" . $Domains{$Line} . " [$Line] - ". $SimscanSpamrejectTo{$Line} . " Time(s)\n"; } else { print "\t" . $Line . " - ". $SimscanSpamrejectTo{$Line} . " Time(s)\n"; } } } if ($threshold_reached < 1) { print "\t" . "None found above the threshold\n"; } } } if ($ShowSimscanSpamDropped) { # simscan spamdropped ip from if ( (keys %SimscanSpamdroppedIpFrom) ) { print "\nSimscan Spam dropped Ip From (Threshold of " . $SimscanSpamDroppedIpFromThreshold . "):\n"; $threshold_reached=0; foreach my $Line (sort {$SimscanSpamdroppedIpFrom{$b} <=> $SimscanSpamdroppedIpFrom{$a}} keys %SimscanSpamdroppedIpFrom) { if ($SimscanSpamdroppedIpFrom{$Line} >= $SimscanSpamDroppedIpFromThreshold) { $threshold_reached=1; if ($Domains{$Line}) { print "\t" . $Domains{$Line} . " [$Line] - ". $SimscanSpamdroppedIpFrom{$Line} . " Time(s)\n"; } else { print "\t" . $Line . " - ". $SimscanSpamdroppedIpFrom{$Line} . " Time(s)\n"; } } } if ($threshold_reached < 1) { print "\t" . "None found above the threshold\n"; } } # simscan spam dropped from if ( (keys %SimscanSpamdroppedFrom) ) { print "\nSimscan Spam dropped From (Threshold of " . $SimscanSpamDroppedFromThreshold . "):\n"; $threshold_reached=0; foreach my $Line (sort {$SimscanSpamdroppedFrom{$b} <=> $SimscanSpamdroppedFrom{$a}} keys %SimscanSpamdroppedFrom) { if ($SimscanSpamdroppedFrom{$Line} >= $SimscanSpamDroppedFromThreshold) { $threshold_reached=1; if ($Domains{$Line}) { print "\t" . $Domains{$Line} . " [$Line] - ". $SimscanSpamdroppedFrom{$Line} . " Time(s)\n"; } else { print "\t" . $Line . " - ". $SimscanSpamdroppedFrom{$Line} . " Time(s)\n"; } } } if ($threshold_reached < 1) { print "\t" . "None found above the threshold\n"; } } # simscan spamdropped to if ( (keys %SimscanSpamdroppedTo) ) { print "\nSimscan Spam dropped To (Threshold of " . $SimscanSpamDroppedToThreshold . "):\n"; $threshold_reached=0; foreach my $Line (sort {$SimscanSpamdroppedTo{$b} <=> $SimscanSpamdroppedTo{$a}} keys %SimscanSpamdroppedTo) { if ($SimscanSpamdroppedTo{$Line} >= $SimscanSpamDroppedToThreshold) { $threshold_reached=1; if ($Domains{$Line}) { print "\t" . $Domains{$Line} . " [$Line] - ". $SimscanSpamdroppedTo{$Line} . " Time(s)\n"; } else { print "\t" . $Line . " - ". $SimscanSpamdroppedTo{$Line} . " Time(s)\n"; } } } if ($threshold_reached < 1) { print "\t" . "None found above the threshold\n"; } } } # qmail-smtpd reports if ( keys %Badmailfromemail) { print "\nEmails caught by badmailfrom by email (Threshold of " . $BadMailFromEmailThreshold . "):\n"; $threshold_reached=0; foreach my $Line (sort {$Badmailfromemail{$b} <=> $Badmailfromemail{$a}} keys %Badmailfromemail) { if ($Badmailfromemail{$Line} >= $BadMailFromEmailThreshold) { $threshold_reached=1; print "\t" . $Line . " - ". $Badmailfromemail{$Line} . " Time(s)\n"; } } if ($threshold_reached < 1) { print "\t" . "None found above the threshold\n"; } } if ( keys %Badmailfromip) { print "\nEmails caught by badmailfrom by ip: (Threshold of " . $BadMailFromIpThreshold . ")\n"; $threshold_reached=0; foreach my $Line (sort {$Badmailfromip{$b} <=> $Badmailfromip{$a}} keys %Badmailfromip) { if ($Badmailfromip{$Line} >= $BadMailFromIpThreshold) { $threshold_reached=1; print "\t" . $Line . " - ". $Badmailfromip{$Line} . " Time(s)\n"; } } if ($threshold_reached < 1) { print "\t" . "None found above the threshold\n"; } } if ( keys %Badmailtoemail) { print "\nEmails caught by badmailto by email (Threshold of " . $BadMailToEmailThreshold . "):\n"; $threshold_reached=0; foreach my $Line (sort {$Badmailtoemail{$b} <=> $Badmailtoemail{$a}} keys %Badmailtoemail) { if ($Badmailtoemail{$Line} >= $BadMailToEmailThreshold) { $threshold_reached=1; print "\t" . $Line . " - ". $Badmailtoemail{$Line} . " Time(s)\n"; } } if ($threshold_reached < 1) { print "\t" . "None found above the threshold\n"; } } if ( keys %Badmailtoip) { print "\nEmails caught by badmailto by ip (Threshold of " . $BadMailToIpThreshold . "):\n"; $threshold_reached=0; foreach my $Line (sort {$Badmailtoip{$b} <=> $Badmailtoip{$a}} keys %Badmailtoip) { if ($Badmailtoip{$Line} >= $BadMailToIpThreshold) { $threshold_reached=1; print "\t" . $Line . " - ". $Badmailtoip{$Line} . " Time(s)\n"; } } if ($threshold_reached < 1) { print "\t" . "None found above the threshold\n"; } } } # end high detail # show totals if ($TotalFrom or $TotalTo) { print "\nTotals:\n"; printf("%27s %9s\n", "Remote connections:", $TotalFrom); printf("%27s %9s\n", "Local connections:", $TotalTo); } if ($TotalBlocked) { printf("%27s %9s\n", "RBL blocked:", $TotalBlocked); printf("%27s %9s\n", "Grand Total From:", $GrandTotalFrom); printf("%27s %2.3f %%\n", "Percentage blocked:", (($TotalBlocked/$GrandTotalFrom)*100)); } print "\nChkuser Totals:\n"; printf("%27s %9s\n", "Rejected:", ($TotalReject>0 ? $TotalReject : 0)); printf("%27s %9s\n", "Accepted:", ($TotalAccept>0 ? $TotalAccept : 0)); printf("%27s %9s\n", "Total accepted relays:", ($TotalAcceptRelay>0 ? $TotalAcceptRelay : 0)); printf("%27s %9s\n", "Total rejected relays:", ($TotalRejectRelay>0 ? $TotalRejectRelay : 0)); printf("%27s %9s\n", "Total viruses caught:", ($SimscanVirusTotal>0 ? $SimscanVirusTotal : 0)); if ($TotalNoAuthResource) { print "\nTotal No Auth Resources: $TotalNoAuthResource\n"; } if ($TotalOverquota) { print "\nTotal Over quota: $TotalOverquota\n"; } if ($TotalRejectedIntrusion) { print "\nTotal Rejected Intrusions: $TotalRejectedIntrusion\n"; } if ($SimscanTotal) { print "\nSimscan Total: $SimscanTotal\n"; $sct = sprintf("%.2f", ($Totalscantimevirus + $Totalscantimeattach + $Totalscantimeregex + $Totalscantimespam) ); $Maxscantimevirus = sprintf("%.2f", $Maxscantimevirus); printf("%30s %9s", "Maximum Virus Scanning Time:", $Maxscantimevirus); print "\n"; $Maxscantimeattach = sprintf("%.2f", $Maxscantimeattach); printf("%30s %9s", "Maximum Attach Scanning Time:", $Maxscantimeattach); print "\n"; $Maxscantimeregex = sprintf("%.2f", $Maxscantimeregex); printf("%30s %9s", "Maximum Regex Scanning Time:", $Maxscantimeregex); print "\n"; $Maxscantimespam = sprintf("%.2f", $Maxscantimespam); printf("%30s %9s", "Maximum Spam Scanning Time:", $Maxscantimespam); print "\n"; $Totalscantimevirus = sprintf("%.2f", $Totalscantimevirus); printf("%30s %9s", "Total Virus Scanning Time:", $Totalscantimevirus); print "\n"; $Totalscantimeattach = sprintf("%.2f", $Totalscantimeattach); printf("%30s %9s", "Total Attach Scanning Time:", $Totalscantimeattach); print "\n"; $Totalscantimeregex = sprintf("%.2f", $Totalscantimeregex); printf("%30s %9s", "Total Regex Scanning Time:", $Totalscantimeregex); print "\n"; $Totalscantimespam = sprintf("%.2f", $Totalscantimespam); printf("%30s %9s", "Total Spam Scanning Time:", $Totalscantimespam); print "\n"; printf("%30s %9s", "Total Scanning Time:", $sct); print "\n"; } if( $SimscanSpamrejectTotal ) { print "\nSimscan Spam Reject: $SimscanSpamrejectTotal emails\n"; } if( $SimscanCleanTotal ) { print "\nSimscan Clean: $SimscanCleanTotal emails\n"; if ( $SimscanSpamrejectTotal ) { printf("%30s %2.3f %%\n", "Percentage clean:", (($SimscanCleanTotal/($SimscanSpamrejectTotal+$SimscanCleanTotal))*100)); } } if( $SimscanRelayClientTotal ) { print "\nSimscan RelayClient: $SimscanRelayClientTotal emails\n"; } # simscan quarantine if ( $Quarantine ) { print "\nSimscan Quarantine: $Quarantine emails\n"; } if ($Badmailtotot) { print "\nTotal badmailto: $Badmailtotot\n"; } if ($Badmailfromtot) { print "\nTotal badmailfrom: $Badmailfromtot\n"; } if ($Total) { print "\nTotal mail: $Total\n"; } # warnings if ( (keys %Warnings) ) { print "\nWarnings:\n"; foreach my $Line (sort {$Warnings{$b} <=> $Warnings{$a}} keys %Warnings) { print "\t" . $Line . " - ". $Warnings{$Line} . " Time(s)\n"; } } # other if (($#OtherList >= 0) and (! $IgnoreUnmatched)) { print "\n**Unmatched Entries**\n"; print @OtherList; } exit(0); # vi: shiftwidth=3 tabstop=3 syntax=perl et # Local Variables: # mode: perl # perl-indent-level: 3 # indent-tabs-mode: nil # End: logwatch-7.12/scripts/services/qmail-pop3d0000664000211400021140000001111714274101042021024 0ustar logwatchlogwatch ######################################################## # Please file all bug reports, patches, and feature # requests under: # https://sourceforge.net/p/logwatch/_list/tickets # Help requests and discusion can be filed under: # https://sourceforge.net/p/logwatch/discussion/ ######################################################## ####################################################### ## Copyright (c) 2008 Bob Hutchinson ## Covered under the included MIT/X-Consortium License: ## http://www.opensource.org/licenses/mit-license.php ## All modifications and contributions by other persons to ## this script are assumed to have been donated to the ## Logwatch project and thus assume the above copyright ## and licensing terms. If you want to make contributions ## under your own copyright or a different license this ## must be explicitly stated in the contribution an the ## Logwatch project reserves the right to not accept such ## contributions. If you have made significant ## contributions to this script and want to claim ## copyright please contact logwatch-devel@lists.sourceforge.net. ######################################################### use strict; my $Detail = $ENV{'LOGWATCH_DETAIL_LEVEL'}; my $QmailDetail = $ENV{'qmail_high_detail'}; my $QmailThreshold = $ENV{'threshold'}; my $ToThreshold = $ENV{'to_threshold'}; my $FromThreshold = $ENV{'from_threshold'}; #Init String Containers my ( $IgnoreUnmatched, $LocalServer, $RemoteServer, $TotalFrom, $TotalTo, $Warning, $d, $ip, $pid1, $pid2, $rest, $threshold_reached, ); #Init Hashes my ( %Domains, %From, %To, %Warnings, ); my @OtherList = (); #@4000000041c6c5331d3bfc64 tcpserver: ok 24416 0:213.228.232.199:110 host81-130-125-141.in-addr.btopenworld.com:81.130.125.141::34887 while (defined(my $ThisLine = )) { if (( $ThisLine =~ /status: / ) or ( $ThisLine =~ /end (\d+) status \d+/ )) { # We don't care about these } elsif ( ($pid1,$RemoteServer) = ( $ThisLine =~ /pid (\d+) from (.*)/ )) { $From{$RemoteServer}++; $TotalFrom++; } elsif ( ($pid2,$LocalServer, $rest) = ( $ThisLine =~ /ok (\d+) \d+:(.*):110\s+(.*)/ ) ) { $To{$LocalServer}++; $TotalTo++; if ( $rest !~ /^\:/) { # we have a domain ($d, $ip ) = ($rest =~ /^(.*):(.*)::\d+$/); $Domains{$ip} = $d; } } elsif ( ($Warning) = ( $ThisLine =~ /warning: (.*)/i ) ) { $Warnings{$Warning}++; } else { # Report any unmatched entries... push @OtherList,$ThisLine; } } if ($QmailDetail >= 1) { if ($QmailThreshold > 0) { if (($FromThreshold < 0) or ($FromThreshold eq '')) { $FromThreshold = $QmailThreshold; } if (($ToThreshold < 0) or ($ToThreshold eq '')) { $ToThreshold = $QmailThreshold; } } if (($FromThreshold < 0) or ($FromThreshold eq '')) { $FromThreshold = 0; } if (($ToThreshold < 0) or ($ToThreshold eq '')) { $ToThreshold = 0; } if ( (keys %From) ) { print "\nConnections from (Threshold of " . $FromThreshold . "):\n"; $threshold_reached=0; foreach my $Line (sort {$From{$b} <=> $From{$a}} keys %From) { if ($From{$Line} >= $FromThreshold) { $threshold_reached=1; if ($Domains{$Line}) { print "\t" . $Domains{$Line} . " [$Line] - ". $From{$Line} . " Time(s)\n"; } else { print "\t" . $Line . " - ". $From{$Line} . " Time(s)\n"; } } } if ($threshold_reached < 1) { print "\t" . "None found above the threshold\n"; } } if ( (keys %To) ) { print "\nConnections to (Threshold of " . $ToThreshold . "):\n"; $threshold_reached=0; foreach my $Line (sort {$To{$b} <=> $To{$a}} keys %To) { if ($To{$Line} >= $ToThreshold) { $threshold_reached=1; if ($Domains{$Line}) { print "\t" . $Domains{$Line} . " [$Line] - ". $To{$Line} . " Time(s)\n"; } else { print "\t" . $Line . " - ". $To{$Line} . " Time(s)\n"; } } } if ($threshold_reached < 1) { print "\t" . "None found above the threshold\n"; } } } if ($TotalFrom or $TotalTo) { print "\nTotals:\n"; print "\tRemote connections $TotalFrom\n"; print "\tLocal connections $TotalTo\n"; } if ( (keys %Warnings) ) { print "\nWarnings:\n"; foreach my $Line (sort {$Warnings{$b} <=> $Warnings{$a}} keys %Warnings) { print "\t" . $Line . " - ". $Warnings{$Line} . " Time(s)\n"; } } if (($#OtherList >= 0) and (not $IgnoreUnmatched)){ print "\n**Unmatched Entries**\n"; print @OtherList; } exit(0); # vi: shiftwidth=3 tabstop=3 syntax=perl et # Local Variables: # mode: perl # perl-indent-level: 3 # indent-tabs-mode: nil # End: logwatch-7.12/scripts/services/portsentry0000664000211400021140000001306214274101041021127 0ustar logwatchlogwatch ######################################################## # Please file all bug reports, patches, and feature # requests under: # https://sourceforge.net/p/logwatch/_list/tickets # and copy: # Osma Ahvenlampi # Help requests and discusion can be filed under: # https://sourceforge.net/p/logwatch/discussion/ ######################################################## ######################################################## # This was written and is maintained by: # Osma Ahvenlampi ######################################################## ####################################################### ## Copyright (c) 2008 Osma Ahvenlampi ## Covered under the included MIT/X-Consortium License: ## http://www.opensource.org/licenses/mit-license.php ## All modifications and contributions by other persons to ## this script are assumed to have been donated to the ## Logwatch project and thus assume the above copyright ## and licensing terms. If you want to make contributions ## under your own copyright or a different license this ## must be explicitly stated in the contribution an the ## Logwatch project reserves the right to not accept such ## contributions. If you have made significant ## contributions to this script and want to claim ## copyright please contact logwatch-devel@lists.sourceforge.net. ######################################################### use Logwatch ':ip'; use strict; my $Detail = $ENV{'LOGWATCH_DETAIL_LEVEL'} || 0; #Init String Containers my ($host, $list, $mode, $prev, $port, $proto, $scan); #Init Hashes my ( %Blocked, %Exclude, %Ignored, %Scans, %Unknown ); while (defined(my $ThisLine = )) { chomp($ThisLine); next if ($ThisLine eq ""); if ( ( $ThisLine =~ /Starting portsentry/ ) or ( $ThisLine =~ /PortSentry is now active/ ) or ( $ThisLine =~ /Psionic PortSentry .* (starting|shutting)/ ) or ( $ThisLine =~ /portsentry shutdown/ ) ) { # don't care } elsif( ($scan,$host,$proto,$port) = ( $ThisLine =~ m|attackalert: (.+) scan from host: [^/]+/(\S+) to (\w+) port: (\d+)| ) ){ $host = LookupIP($host); $Scans{$scan}{$host}{$port}++; } elsif ( ($host) = ( $ThisLine =~ /Host (\S+) has been blocked/ ) ){ $host = LookupIP($host); $Blocked{$host}++; } elsif( ($host) = ( $ThisLine =~ /Host: (\S+) is already blocked/ ) ){ # ignore } elsif( ($mode,$proto,$port) = ( $ThisLine =~ /: (.+) scan detection mode activated. Ignored (\w+) port: (\d+)/ ) ){ $Ignored{$mode}{$proto}{$port}++; } elsif( ($mode,$port) = ( $ThisLine =~ /: (.+) mode will manually exclude port: (\d+)/ ) ){ $Exclude{$mode}{$port}++; } else{ $Unknown{$ThisLine}++; } } if (keys %Scans) { print "\nWarning: Portscans detected"; foreach my $mode (sort {$a cmp $b} keys %Scans) { print "\n " . $mode . " from:"; foreach my $host (sort {$a cmp $b} keys %{$Scans{$mode}}) { print "\n " . $host . ": ports:"; my $ports = $prev = $list = undef; foreach my $port (sort {$a <=> $b} keys %{$Scans{$mode}{$host}}) { if ($prev && ($port-1) == $prev) { $ports .= "-" if (!$list); $list = 1; } elsif ($list) { $ports .= "$prev $port"; $list = undef; } else { $ports .= " $port"; } $prev = $port; } $ports .= $prev if ($list); # don't display the port list if it doesn't fit on one line if (length($ports) > 55 && $Detail < 10) { print " (too many, set Detail to High for complete list)"; } else { print $ports; } } } print "\n"; } if (keys %Blocked) { print "\n"; foreach my $host (keys %Blocked) { print "Warning: Blocked route from/to $host $Blocked{$host} times(s).\n"; } } if ( ($Detail >= 10) and (keys %Ignored) ) { print "\nIgnored following ports"; foreach my $mode (sort {$a cmp $b} keys %Ignored) { print "\n " . $mode . ":"; foreach my $proto (sort {$a cmp $b} keys %{$Ignored{$mode}}) { print "\n " . $proto . ": ports:"; my $prev = $list = undef; foreach $port (sort {$a <=> $b} keys %{$Ignored{$mode}{$proto}}) { if ($prev && ($port-1) == $prev) { print "-" if (!$list); $list = 1; } elsif ($list) { print "$prev $port"; $list = undef; } else { print " $port"; } $prev = $port; } print $prev if ($list); } } print "\n"; } if ( ($Detail >= 10) and (keys %Exclude) ) { print "\nExcluded following ports"; foreach my $mode (sort {$a cmp $b} keys %Exclude) { print "\n " . $mode . ": ports:"; my $prev = $list = undef; foreach my $port (sort {$a <=> $b} keys %{$Exclude{$mode}}) { if ($prev && ($port-1) == $prev) { print "-" if (!$list); $list = 1; } elsif ($list) { print "$prev $port"; $list = undef; } else { print " $port"; } $prev = $port; } print $prev if ($list); } print "\n"; } if ( ($Detail >= 5) and (keys %Unknown) ) { print "\n**Unmatched entries**\n"; foreach my $ThisOne (sort {$a cmp $b} keys %Unknown) { print $Unknown{$ThisOne} . " Time(s): " . $ThisOne . "\n"; } } exit(0); # vi: shiftwidth=3 tabstop=3 syntax=perl et # Local Variables: # mode: perl # perl-indent-level: 3 # indent-tabs-mode: nil # End: logwatch-7.12/scripts/services/ftpd-messages0000664000211400021140000002027314274101037021447 0ustar logwatchlogwatch ######################################################## # Please file all bug reports, patches, and feature # requests under: # https://sourceforge.net/p/logwatch/_list/tickets # Help requests and discusion can be filed under: # https://sourceforge.net/p/logwatch/discussion/ ######################################################## ######################################################## ## Copyright (c) 2008 Kirk Bauer ## Covered under the included MIT/X-Consortium License: ## http://www.opensource.org/licenses/mit-license.php ## All modifications and contributions by other persons to ## this script are assumed to have been donated to the ## Logwatch project and thus assume the above copyright ## and licensing terms. If you want to make contributions ## under your own copyright or a different license this ## must be explicitly stated in the contribution an the ## Logwatch project reserves the right to not accept such ## contributions. If you have made significant ## contributions to this script and want to claim ## copyright please contact logwatch-devel@lists.sourceforge.net. ######################################################### use strict; my $Detail = $ENV{'LOGWATCH_DETAIL_LEVEL'} || 0; my $IgnoreUnmatched = $ENV{'ftpd_ignore_unmatched'} || 0; my $SegFault = 0; #Init String Containers my ( $Temp, $Temp2, $Class, $Email, $File, $Host, $IP, $Limit, $Pass, $User, ); #Init Arrays my @OtherList = (); #Init Hashes my ( %AnonLogins, %DeletedFiles, %FailedLogins, %RefusedAnonLogins, %RefusedPorts, %SecurityViolations, %TimedOut, %UserLogins ); while (defined(my $ThisLine = )) { if ( ( $ThisLine =~ /FTP session closed$/ ) or ( $ThisLine =~ /^getpeername \(in.ftpd\): Transport endpoint is not connected$/ ) or ( $ThisLine =~ /^QUIT$/ ) or ( $ThisLine =~ /^[\w\.]+: connected: IDLE\s\[\d+\]: failed login from/ ) or ( $ThisLine =~ /^lost connection to / ) or ( $ThisLine =~ /^wu-ftpd - TLS settings:/ ) or # The connect info is extracted elsewhere: ( $ThisLine =~ /^USER / ) or ( $ThisLine =~ /^[^ ]+: [^ ]+: USER [^ ]+\[\d+\]:/ ) or ( $ThisLine =~ /^PASS / ) or ( $ThisLine =~ /^[^ ]+: [^ ]+: IDLE\[\d+\]: PASS password$/ ) or # These are uninteresting: ( $ThisLine =~ /^[^ ]+: [^ ]+: TYPE / ) or ( $ThisLine =~ /^[^ ]+: [^ ]+: PORT / ) or ( $ThisLine =~ /^[^ ]+: [^ ]+: STOR / ) or ( $ThisLine =~ /^[^ ]+: [^ ]+: RNFR / ) or ( $ThisLine =~ /^[^ ]+: [^ ]+: RNTO / ) or ( $ThisLine =~ /^[^ ]+: [^ ]+: SYST\[\d+\]: SYST$/ ) or ( $ThisLine =~ /^[^ ]+: [^ ]+: QUIT\[\d+\]: QUIT$/ ) or ( $ThisLine =~ /^[^ ]+: [^ ]+: PASV\[\d+\]: PASV$/ ) or # Some people may want these things below, but not in a simple upfront security ( $ThisLine =~ /^[^ ]+: [^ ]+: RETR / ) or ( $ThisLine =~ /^[^ ]+: [^ ]+: LIST / ) or ( $ThisLine =~ /^[^ ]+: [^ ]+: NLST / ) or # 62.161.227.69: connected: SYST[27800]: cmd failure - not logged in ( $ThisLine =~ /^[^ ]+: [^ ]+: SYST\[\d+\]: cmd failure - not logged in$/ ) or ( $ThisLine =~ /^User .* timed out after .* seconds at .*$/ ) ) { # We don't care about any of these } elsif ( ($Host,$IP,$Email) = ( $ThisLine =~ /^ANONYMOUS FTP LOGIN FROM ([^ ]+) \[(.*)\], (.*)$/ ) ) { $Temp = " " . $Host . " (" . $IP . "): " . $Email . " - "; $AnonLogins{$Temp}++; } elsif ( ($Host,$IP,$User) = ( $ThisLine =~ /FTP LOGIN FROM ([^ ]+) \[(.*)\], (.*)$/ ) ) { $Temp = " " . $Host . " (" . $IP . "): " . $User . " - "; $UserLogins{$Temp}++; } elsif ( ($Host,$IP,$User) = ( $ThisLine =~ /^FTP LOGIN REFUSED \(.+\) FROM ([^ ]+) \[(.*)\], (.*)$/ ) ) { $Temp = " " . $Host . " (" . $IP . "): " . $User . " - "; $FailedLogins{$Temp}++; } elsif ( ($Host,$IP,$User) = ( $ThisLine =~ /REFUSED .+ from ([^ ]+) \[(.*)\], (.*)$/i ) ) { $Temp = " " . $Host . " (" . $IP . "): " . $User . " - "; $FailedLogins{$Temp}++; } elsif ( ($Host,$IP,$User) = ( $ThisLine =~ /^failed login from ([^ ]+) \[(.*)\], (.*)$/ ) ) { $Temp = " " . $Host . " (" . $IP . "): " . $User . " - "; $FailedLogins{$Temp}++; } elsif ( ($Limit,$Class,$Host,$IP) = ( $ThisLine =~ /^ACCESS DENIED \(user limit (.*)\; class (.*)\) TO (.*) \[(.*)\]/ ) ) { $Temp = " " . $Host . " (" . $IP . "): class " . $Class . " (Limit: " . $Limit . ") - "; $FailedLogins{$Temp}++; } elsif ( ($Host,$IP) = ( $ThisLine =~ /^FTP ACCESS REFUSED \(anonymous password not rfc822\) from (.*) \[(.*)\]/ ) ) { $Temp = " " . $Host . " (" . $IP . ") - "; $FailedLogins{$Temp}++; } elsif ( ($Host,$IP,$User) = ( $ThisLine =~ /failed login from ([^ ]+) \[(.*)\]$/ ) ) { $Temp = " " . $Host . " (" . $IP . ") - "; $FailedLogins{$Temp}++; } elsif ( ($IP,$Host) = ( $ThisLine =~ /^refused PORT ([\d.]+),\d+ from (.*)$/ ) ) { $Temp = " " . $Host . " (" . $IP . ") - "; $RefusedPorts{$Temp}++; } elsif ( $ThisLine =~ /^exiting on signal 11: Segmentation fault$/ ) { $SegFault++; } elsif ( ($User,$Host,$IP,$File) = ( $ThisLine =~ /^([^ ]+) of ([^ ]*) \[(.*)\] deleted (.*)$/ ) ) { $Temp = " " . $Host . " (" . $IP . "): " . $User . "\n"; $Temp2 = " " . $File . "\n"; push @{$DeletedFiles{$Temp}}, $Temp2; } elsif ( ($User,$Pass,$Host,$IP) = ( $ThisLine =~ /(.*)\((.*)\) of (.*) \[(.*)\] tried to/) ) { $Temp = " " . $Host . " ($IP): " . $User . " ($Pass) - "; $SecurityViolations{$Temp}++; } elsif ( ($Host,$User,$IP) = ( $ThisLine =~ /(.*)\: (.*)\: SITE .* \[(.*)\] tried to/) ) { $Temp = " " . $Host . " ($IP): " . $User . " - "; $SecurityViolations{$Temp}++; } elsif ( ($Host,$IP) = ( $ThisLine =~ /^FTP LOGIN FAILED \(cannot set guest privileges\) for ([^ ]+) \[(.*)\], ftp$/ ) ) { $Temp = " " . $Host . " (" . $IP . "): - "; $RefusedAnonLogins{$Temp}++; } elsif ( ($Host, $User) = ( $ThisLine =~ /^([^ ]+): ([^ ]+): IDLE\[\d+\]: User [^ ]+ timed out after / ) ) { # dhcp024-208-136-047.insight.rr.com: visitor: IDLE[23195]: User visitor timed out after 900 seconds at Mon Jan 13 00:25:24 2003 $TimedOut{" " . $Host . " : " . $User}++; } else { # Report any unmatched entries... push @OtherList,$ThisLine; } } if ( (keys %AnonLogins) and ($Detail >= 10) ) { print "\nAnonymous FTP Logins:\n"; foreach my $ThisOne (keys %AnonLogins) { print $ThisOne . $AnonLogins{$ThisOne} . " Time(s)\n"; } } if ((keys %DeletedFiles) and ($Detail >= 10)) { print "\nFiles deleted through FTP:\n"; foreach my $ThisOne (keys %DeletedFiles) { print $ThisOne; print @{$DeletedFiles{$ThisOne}}; } } if ((keys %UserLogins) and ($Detail >= 5)) { print "\nUser FTP Logins:\n"; foreach my $ThisOne (keys %UserLogins) { print $ThisOne . $UserLogins{$ThisOne} . " Time(s)\n"; } } if (keys %FailedLogins) { print "\nFailed FTP Logins:\n"; foreach my $ThisOne (keys %FailedLogins) { print $ThisOne . $FailedLogins{$ThisOne} . " Time(s)\n"; } } if ( (keys %RefusedPorts) and ($Detail >= 10) ) { print "\nRefused PORTs:\n"; foreach my $ThisOne (keys %RefusedPorts) { print $ThisOne . $RefusedPorts{$ThisOne} . " Time(s)\n"; } } if (keys %TimedOut) { print "\nConnections timed out:\n"; foreach my $ThisOne (keys %TimedOut) { print $ThisOne . $TimedOut{$ThisOne} . " Time(s)\n"; } } if ( (keys %SecurityViolations) and ($Detail >= 5) ) { print "\nFailed filesystem violations:\n"; foreach my $ThisOne (keys %SecurityViolations) { print $ThisOne . $SecurityViolations{$ThisOne} . " Time(s)\n"; } } if (keys %RefusedAnonLogins) { print "\nRefused anonymous FTP Logins:\n"; foreach my $ThisOne (keys %RefusedAnonLogins) { print $ThisOne . $RefusedAnonLogins{$ThisOne} . " Time(s)\n"; } } if ($SegFault > 0) { print "\nexiting on signal 11: Segmentation fault: $SegFault Time(s)\n"; } if (($#OtherList >= 0) and (not $IgnoreUnmatched)){ print "\n**Unmatched Entries**\n"; print @OtherList; } exit(0); # vi: shiftwidth=3 tabstop=3 syntax=perl et # Local Variables: # mode: perl # perl-indent-level: 3 # indent-tabs-mode: nil # End: logwatch-7.12/scripts/services/clamav0000664000211400021140000001533514743365003020161 0ustar logwatchlogwatch ######################################################## # Please file all bug reports, patches, and feature # requests under: # https://sourceforge.net/p/logwatch/_list/tickets # Help requests and discusion can be filed under: # https://sourceforge.net/p/logwatch/discussion/ ######################################################## ######################################################## # # Written by S. Schimkat . # ######################################################## ######################################################## ## Copyright (c) 2008 S. Schimkat ## Copyright (c) 2015 Orion Poplawski ## Covered under the included MIT/X-Consortium License: ## http://www.opensource.org/licenses/mit-license.php ## All modifications and contributions by other persons to ## this script are assumed to have been donated to the ## Logwatch project and thus assume the above copyright ## and licensing terms. If you want to make contributions ## under your own copyright or a different license this ## must be explicitly stated in the contribution an the ## Logwatch project reserves the right to not accept such ## contributions. If you have made significant ## contributions to this script and want to claim ## copyright please contact logwatch-devel@lists.sourceforge.net. ######################################################### use strict; my $Detail = $ENV{'LOGWATCH_DETAIL_LEVEL'} || $ENV{'clamav_detail_level'} || 0; my $IgnoreUnmatched = $ENV{'clamav_ignoreunmatched'} || 0; my $DaemonStart; my $DaemonStartTime; my $DaemonStop; my $DatabaseReloads; my $DatabaseViruses; my @OtherList; my %BoundToIP; my %BoundToPort; my %Limits; my %lstatFail; my %SelfCheck; my %SocketFile; my %VirusList; while (defined(my $ThisLine = )) { #If LogTime = yes in clamd.conf then strip it $ThisLine =~ s/^... ... .. ..:..:.. .... \-\> //; if (( $ThisLine =~ /^Setting connection queue length to \d+/ ) or ( $ThisLine =~ /^Log file size limited to \d+ bytes\./ ) or ( $ThisLine =~ /^Exiting \(clean\)/ ) or ( $ThisLine =~ /^Self checking every \d+ seconds\./ ) or ( $ThisLine =~ /^Unix socket file/ ) or ( $ThisLine =~ /^Protecting against \d+ viruses\./ ) or ( $ThisLine =~ /^Reading databases from/ ) or ( $ThisLine =~ /^Activating the newly loaded database/ ) or ( $ThisLine =~ /file removed\./ ) or ( $ThisLine =~ / (?:dis|en)abled\.$/ ) or ( $ThisLine =~ /^Archive/ ) or ( $ThisLine =~ /^Running as user/ ) or ( $ThisLine =~ /^Log file size limit/ ) or ( $ThisLine =~ /^Bound to.*port \d*/ ) or ( $ThisLine =~ /^SIGHUP caught: re-opening log file./ ) or ( $ThisLine =~ /^Loaded \d+ signatures/ ) or ( $ThisLine =~ /^Mail: Recursion level limit set to \d+/ ) or ( $ThisLine =~ /clamd shutdown\s+succeeded/ ) or ( $ThisLine =~ /clamd startup\s+succeeded/ ) or ( $ThisLine =~ /Not loading PUA signatures/ ) or ( $ThisLine =~ /^(?:LOCAL|TCP): Setting connection queue length to/ ) or ( $ThisLine =~ /MaxQueue set to: / ) or ( $ThisLine =~ /^(?:LOCAL|TCP): Removing stale socket file/ ) or ( $ThisLine =~ /Listening daemon: PID: / ) or ( $ThisLine =~ /Bytecode: Security mode set to /) or ( $ThisLine =~ /^No stats for Database check/ ) or ( $ThisLine =~ /^Received \d+ file descriptor\(s\) from systemd\.$/) or ( $ThisLine =~ /^Activating the newly loaded database/i ) or 0 # This line prevents blame shifting as lines are added above ) { # We do not care about these. } elsif (my ($Check) = ($ThisLine =~ /^SelfCheck: (.*?)\.?\s?\n/i)) { $SelfCheck{$Check}++; } elsif (my ($Virus) = ($ThisLine =~ /^.+?: (.*?) FOUND/i )) { $VirusList{$Virus}++; } elsif (my ($Viruses) = ($ThisLine =~ /^Database correctly reloaded \((\d+) (signatures|viruses)\)/i )) { $DatabaseReloads++; $DatabaseViruses = $Viruses; } elsif (($ThisLine =~ /Stopped at/)) { $DaemonStop++; } elsif (($ThisLine =~ /(?:Daemon started|clamd daemon [\d.]{1,10})/)) { $DaemonStart++; } elsif (($ThisLine =~ /\+\+\+ Started at (.*)/)) { $DaemonStartTime = $1; } elsif (($ThisLine =~ /LOCAL: Unix socket file ([^ \n]*)/)) { $SocketFile{$1}++; } elsif (($ThisLine =~ /TCP: Bound to address ([^ ]*) on port (\d+)/)) { $BoundToIP{$1}++; $BoundToPort{$1}=$2; } elsif (($ThisLine =~ /TCP: Bound to \[([^ ]+)\]:(\d+)/)) { $BoundToIP{$1}++; $BoundToPort{$1}=$2; } elsif (my ($Limit,$Value) = ($ThisLine =~ /Limits: (.*) limit (?:set to|is) (.*)\./)) { $Limits{$Limit} = $Value; } elsif (($ThisLine =~ /lstat\(\) failed on: (\S+)/ )) { $lstatFail{$1}++; } else { push @OtherList,$ThisLine; } } if (($DaemonStop) and ($Detail >= 5)) { print "\nDaemon stopped: ". $DaemonStop." Time(s)\n"; } if (($DaemonStart) and ($Detail >= 5)) { print "\nDaemon started: ". $DaemonStart." Time(s)"; if ($DaemonStartTime ne '') { print " (most recently at $DaemonStartTime)"; } print "\n"; } if (keys %VirusList) { print "\nViruses detected:\n"; foreach my $Virus (sort {$a cmp $b} keys %VirusList) { printf " %-50s %5i Time(s)\n", $Virus .":", $VirusList{$Virus}; } } if ((keys %SelfCheck) and ($Detail >= 5)) { print "\nDaemon check list:\n"; foreach my $Check (sort {$a cmp $b} keys %SelfCheck) { printf " %-50s %5i Time(s)\n", $Check .":", $SelfCheck{$Check}; } } if ($DatabaseReloads and ($Detail > 0)) { print "\nVirus database reloaded $DatabaseReloads time(s) (last time with $DatabaseViruses viruses)\n"; } if ($Detail > 8) { if (keys %SocketFile) { print "\nBound to Unix socket:\n"; foreach my $Socket (keys %SocketFile) { print "\t$Socket\t$SocketFile{$Socket} Time(s)\n"; } } if (keys %BoundToIP) { print "\nBound to IP:Port:\n"; foreach my $IP (keys %BoundToIP) { print "\t$IP:$BoundToPort{$IP}\t\t\t$BoundToIP{$IP} Time(s)\n"; } } if (keys %Limits) { print "\nLimits:\n"; foreach my $Limit (sort { $a cmp $b} keys %Limits) { printf "\t%-20s ","$Limit:",; if (my ($Bytes) = ($Limits{$Limit} =~ /(\d+) bytes/)) { printf "%d MiB\n",$Bytes/1024/1024; } else { print "$Limits{$Limit}\n"; } } } } if (keys %lstatFail) { print "\nlstat() failed on:\n"; foreach my $file (keys %lstatFail) { printf " %-50s %5i Time(s)\n", $file .":", $lstatFail{$file}; } } if (($#OtherList >= 0) and (not $IgnoreUnmatched)){ print "\n**Unmatched Entries**\n"; print @OtherList; } exit(0); # vi: shiftwidth=3 tabstop=3 syntax=perl et # Local Variables: # mode: perl # perl-indent-level: 3 # indent-tabs-mode: nil # End: logwatch-7.12/scripts/services/zz-disk_space0000664000211400021140000001467614743365006021476 0ustar logwatchlogwatch ######################################################## # Please file all bug reports, patches, and feature # requests under: # https://sourceforge.net/p/logwatch/_list/tickets # Help requests and discusion can be filed under: # https://sourceforge.net/p/logwatch/discussion/ ######################################################## ####################################################### ## Copyright (c) 2008 Kirk Bauer ## Covered under the included MIT/X-Consortium License: ## http://www.opensource.org/licenses/mit-license.php ## All modifications and contributions by other persons to ## this script are assumed to have been donated to the ## Logwatch project and thus assume the above copyright ## and licensing terms. If you want to make contributions ## under your own copyright or a different license this ## must be explicitly stated in the contribution an the ## Logwatch project reserves the right to not accept such ## contributions. If you have made significant ## contributions to this script and want to claim ## copyright please contact logwatch-devel@lists.sourceforge.net. ######################################################### $| = 1; use POSIX qw(uname); use strict; my (%Config); my $Debug = $ENV{'LOGWATCH_DEBUG'} || 0; my $Detail = $ENV{'LOGWATCH_DETAIL_LEVEL'} || 0; my $logwatch_hostname = $ENV{'LOGWATCH_ONLY_HOSTNAME'}; my $show_home_dir_sizes = $ENV{'show_home_dir_sizes'} || 0; my $home_dir = $ENV{'home_dir'} || 0; my $show_mail_dir_sizes = $ENV{'show_mail_dir_sizes'} || 0; my $mail_dir = $ENV{'mail_dir'} || 0; my $show_disk_usage = $ENV{'show_disk_usage'} || 0; my $diskfull_threshold = $ENV{'diskfull_threshold'} || 90; my $diskfull_exclude_dirs = $ENV{'diskfull_exclude_dirs'} || '$'; my $local_disks_only = $ENV{'local_disks_only'} || 0; my $suppress_listing = $ENV{'suppress_listing'} || 0; my $df_options; my $disk_cmd; my $DebugCounter=0; my ($OSname, $hostname, $release, $version, $machine) = POSIX::uname(); $hostname =~ s/\..*//; exit (0) if ($ENV{'LOGWATCH_ONLY_HOSTNAME'} and ($logwatch_hostname ne $hostname)); if ( $Debug >= 5 ) { print STDERR "\n\nDEBUG: Inside zz-disk-space Filter \n\n"; $DebugCounter = 1; } sub DirUsage { my $Dir = $_[0]; if ( !-d $Dir ) { print STDERR "Directory $Dir not found\n"; return }; if ($OSname eq "Linux") { system("du -s --block-size=1048576 -h $Dir | sort -n -r -k 1"); } elsif ($OSname eq "Darwin") { system("du -s --block-size=1048576 -h $Dir | sort -n -r -k 1"); } elsif ($OSname eq "SunOS") { if ( ($release eq "5.10") || ($release eq "5.9") || ($release eq "5.11") ) { system("/usr/xpg4/bin/du -s -h $Dir | sort -n -r -k 1"); } else { system("du -s $Dir | sort -n -r -k 1"); } } elsif ($OSname eq "HP-UX") { system("du -s -k $Dir | sort -n -r -k 1"); } elsif ($OSname eq "AIX") { system("du -s -k $Dir | sort -n -r -k 1"); } else { system("du -s -h $Dir | sort -n -r -k 1"); } } sub DirectorySizes { my $Dir = $_[0]; DirUsage($Dir.'/*'); } sub HomeDirectorySizes { my $HomeDir = $_[0]; print "\n\n------------- Home Directory Sizes ---------------\n\n"; print "Size Location\n"; DirectorySizes($HomeDir); print "\n\n------------- Home Directory Sizes ---------------\n\n"; } sub MailDirectorySizes { my $MailDir = $_[0]; print "\n\n------------- Mail Directory Sizes ---------------\n\n"; print "Size Location\n"; DirectorySizes($MailDir); print "\n\n------------- Mail Directory Sizes ---------------\n\n"; } sub DiskUsage () { my $Dir = $_[0]; print "\n\n------------- Directory Sizes ---------------\n\n"; print "Size Location\n"; if ($OSname eq "Linux") { DirUsage("/var/log"); DirUsage("/usr"); } elsif ($OSname eq "Darwin") { DirUsage("/var/log"); DirUsage("/usr"); } elsif ($OSname eq "SunOS") { DirUsage("/var/log"); DirUsage("/usr"); DirUsage("/opt"); } elsif ($OSname eq "HP-UX") { DirUsage("/var/adm"); DirUsage("/usr"); DirUsage("/opt"); } else { DirUsage("/var/log"); DirUsage("/usr"); DirUsage("/opt"); } print "\n\n------------- Directory Sizes ---------------\n\n"; } sub DiskSpace () { system($disk_cmd); print "\n"; } sub DiskFull { my @rows = split('\n', `$disk_cmd`); # Remove header shift @rows; foreach my $row (@rows) { my ($source,$used,$target) = ($row =~ /^(.*?)(?:\s+[\d\.]+[KMGTP]?){3}\s+(\d+)%\s+(.*)$/); if (($used > $diskfull_threshold) && ($source !~ /\/dev\/scd/ ) && ($source !~ /\/dev\/sr/ ) && ($source !~ /\/dev\/loop./) && ($target !~ /^$diskfull_exclude_dirs/i)) { print "$target ($source) => $used% Used. Warning: Disk Filling up.\n"; } } } ##################### #Main if ($OSname eq "Linux") { $df_options = "-h -x tmpfs -x devtmpfs -x udf -x iso9660 -x squashfs -x overlay"; if ($local_disks_only) { $df_options .= " -l"; } } elsif ($OSname eq "Darwin") { $df_options = "-h -T nodevfs,autofs"; if ($local_disks_only) { $df_options .= " -l"; } } elsif ($OSname eq "SunOS") { if ( ($release eq "5.10") || ($release eq "5.9") || ($release eq "5.11") ) { $df_options = "-h"; } if ($local_disks_only) { $df_options .= " -l"; } } elsif ($OSname eq "AIX") { $df_options = "-P"; if ($local_disks_only) { $df_options .= " -T local"; } } elsif ($OSname eq "GNU/kFreeBSD") { $df_options = "-h -x tmpfs -x devtmpfs -x udf -x iso9660 -x devfs -x linprocfs -x sysfs -x fdescfs"; if ($local_disks_only) { $df_options .= " -l"; } } else { $df_options = ""; if ($local_disks_only) { $df_options .= " -l"; } } if ( $ENV{'df_options'} ) { $df_options = $ENV{'df_options'}; }; if ($OSname eq "SunOS") { $disk_cmd = "/usr/xpg4/bin/df $df_options"; } elsif ($OSname eq "HP-UX") { $disk_cmd = "bdf $df_options"; } else { $disk_cmd = "df $df_options"; } if ( $ENV{'disk_cmd'} ) { $disk_cmd = $ENV{'disk_cmd'}; }; #Only show disk space "df" by default -mgt DiskSpace() if ( !$suppress_listing and (($ENV{PRINTING} eq 'y') or $Detail)); if ( $show_disk_usage == 1 ) { DiskUsage(); }; #Turn on in zz-disk_space.conf if (($Detail > 10) || ($show_home_dir_sizes == 1)) { #set in zz-disk_space.conf -mgt HomeDirectorySizes($home_dir); } if (($Detail > 10) || ($show_mail_dir_sizes == 1)) { #set in zz-disk_space.conf -mgt MailDirectorySizes($mail_dir); } if ($diskfull_threshold > 0) { DiskFull(); } # vi: shiftwidth=3 tabstop=3 syntax=perl et # Local Variables: # mode: perl # perl-indent-level: 3 # indent-tabs-mode: nil # End: logwatch-7.12/scripts/services/smartd0000664000211400021140000004312514624723073020211 0ustar logwatchlogwatch ######################################################## # Please file all bug reports, patches, and feature # requests under: # https://sourceforge.net/p/logwatch/_list/tickets # Help requests and discusion can be filed under: # https://sourceforge.net/p/logwatch/discussion/ ######################################################## ####################################################### ## Copyright (c) 2008 Jaco Botha ## Covered under the included MIT/X-Consortium License: ## http://www.opensource.org/licenses/mit-license.php ## All modifications and contributions by other persons to ## this script are assumed to have been donated to the ## Logwatch project and thus assume the above copyright ## and licensing terms. If you want to make contributions ## under your own copyright or a different license this ## must be explicitly stated in the contribution an the ## Logwatch project reserves the right to not accept such ## contributions. If you have made significant ## contributions to this script and want to claim ## copyright please contact logwatch-devel@lists.sourceforge.net. ######################################################### use strict; my ($Device, $Msg, $Test); my %ParamChanges = (); my %TempChanges = (); my %TempLimit = (); my %TempCritLimit = (); my %Pendsectors = (); my %NumPendsectors = (); my %Offsectors = (); my %NumOffsectors = (); my %Warnings = (); my %UnableToReg = (); my $ShutdownFailed = 0; my $StartupFailed = 0; my %NotInDatabase = (); my %CantMonitor = (); my $UnableToMonitor = 0; my %DriveTest = (); my %Failed = (); my %OtherList = (); my $DLine = 0; my %UnavailableDev = (); my %SataDisk = (); my %CheckFailed = (); my %Monitoring = (); my %DeviceInfo = (); my %Reconnected = (); my %Removed = (); my $Detail = $ENV{'LOGWATCH_DETAIL_LEVEL'} || 0; my $IgnoreUnmatched = $ENV{'smartd_ignore_unmatched'} || 0; my $IgnoreCapabilities = $ENV{'smartd_ignore_capabilities'} || 0; my $IgnorePower = $ENV{'smartd_ignore_power'} || 0; my $IgnoreRemoval = $ENV{'smartd_ignore_removal'} || '^$'; #Init String Containers my ( $AttribType, $Code, $Limit, $Name, $NewVal, $Num, $RawVal, $TestType, $Text, ); while (defined(my $ThisLine = )) { chomp($ThisLine); if ( ($Device,$Msg) = ($ThisLine =~ /^Device: ([^,]+), No such device(?: or address)?, open\(\) failed/ )) { # ignore } elsif ( ($Device,$Msg) = ($ThisLine =~ /^Device: ([^,]+), open\(\) failed: No such device(?: or address)?/ )) { # ignore } elsif ( ($Device,$Msg) = ($ThisLine =~ /^Device: ([^,]+), found in smartd database./ )) { # ignore } elsif ( ($Device,$Msg) = ($ThisLine =~ /^Device: ([^,]+), not found in smartd database./ )) { # ignore } elsif ( ($Device,$Msg) = ($ThisLine =~ /^Device: ([^,]+), opened/)) { # ignore } elsif ( ($Device,$Msg) = ($ThisLine =~ /^Device: ([^,]+), appears to lack SMART*/ )) { # ignore } elsif ( ($Device) = ($ThisLine =~ /^Device: ([^,]+), enabled autosave \(cleared GLTSD bit\)\./ )) { # ignore } elsif ( ($Device) = ($ThisLine =~ /^Device: ([^,]+), enabled SMART Attribute Autosave/ )) { # ignore } elsif ( ($Device) = ($ThisLine =~ /^Device: ([^,]+), enabled SMART Automatic Offline Testing/ )) { # ignore } elsif ( ($Device) = ($ThisLine =~ /^Device: ([^,]+), Self-Test Log error count increased from \d+ to \d+/ )) { # ignore } elsif ( ($Device,$Msg) = ($ThisLine =~ /^Device: ([^,]+), new Self-Test Log error at hour timestamp \d+/ )) { # ignore } elsif ( ($Device,$Msg) = ($ThisLine =~ /^Device: ([^,]+), same Attribute has different ID numbers:/ )) { # ignore } elsif ( ($Device,$Msg) = ($ThisLine =~ /^Num *Test_Description *Status *Remaining *LifeTime/ )) { # ignore } elsif ( ($Device,$Msg) = ($ThisLine =~ /^# *[0-9]+ Short offline *Completed:/ )) { # ignore } elsif ( ($Device,$Msg) = ($ThisLine =~ /^# *[0-9]+ Extended offline *Completed:/ )) { # ignore } elsif ( ($Device,$Msg) = ($ThisLine =~ /^# *[0-9]+ Offline *Fatal or unknown error/ )) { # ignore } elsif ( ($Device) = ($ThisLine =~ /^Device: ([^,]+), not capable of SMART (Health Status |self-)check/ )) { # ignore } elsif ( ($Device) = ($ThisLine =~ /^Device: ([^,]+), is in STANDBY mode, skipping checks/ )) { # ignore } elsif ( ($Device) = ($ThisLine =~ /^Device: ([^,]+), self-test in progress, [0-9]+% remaining/ )) { # ignore } elsif ( ($Device) = ($ThisLine =~ /^Device: ([^,]+), previous self-test completed without error/ )) { # ignore } elsif ( ($Device) = ($ThisLine =~ /^Device: ([^,]+), type changed from \'[\w,+]+\' to \'[\w,+]+\'/ )) { # ignore } elsif ( ($Device) = ($ThisLine =~ /^Device: ([^,]+), state (?:read from|written to)/ )) { # ignore } elsif ( ($Device) = ($ThisLine =~ /^Device: ([^,]+), CHECK POWER STATUS spins up disk/ )) { # ignore } elsif ( ($Device) = ($ThisLine =~ /^Device: ([^,]+), STANDBY mode ignored due to reached limit of skipped checks/ )) { # ignore } elsif ( ($Device) = ($ThisLine =~ /^Device: ([^,]+), is back in ACTIVE or IDLE mode, resuming checks/ )) { # ignore } elsif ( $ThisLine =~ /^file \/var\/run\/smartd.pid written containing PID [0-9]+/ ) { # ignore } elsif ( ($Device,$Msg) = ($ThisLine =~ /^ *$/ )) { # ignore empty lines } elsif ( ($ThisLine =~ /^smartd version/) || ($ThisLine =~ /^smartd [0-9.]+ [0-9-]+ r[0-9]+ \[.*\]/) || ($ThisLine =~ /^Home page/) || ($ThisLine =~ /Copyright \(C\) [0-9-]+(?: by|,) Bruce Allen/) || ($ThisLine =~ /configuration file/i) || ($ThisLine =~ /\[trip Temperature is \d+ Celsius\]/) || ($ThisLine =~ /^Monitoring/) || ($ThisLine =~ /smartd received signal 15: Terminated/) || ($ThisLine =~ /smartd is exiting \(exit status 0\)/) || ($ThisLine =~ /smartd has fork/) || ($ThisLine =~ /written containing PID/) || ($ThisLine =~ /smartd (startup|shutdown) succeeded/) || ($ThisLine =~ /Unable to register device (.*) \(no Directive -d removable\). Exiting/) || ($ThisLine =~ /Device .*, SATA disks accessed via libata are not currently supported by smartmontools./) || ($ThisLine =~ /Device: .*, IE \(SMART\) not enabled, skip device/) || ($ThisLine =~ /Device: .*, not ATA, no IDENTIFY DEVICE Structure/) || ($ThisLine =~ /^Try '.*' to turn on SMART features/) || ($ThisLine =~ /Device: (.*), Bad IEC (SMART) mode page, err=-5, skip device/) || ($ThisLine =~ /Drive: DEVICESCAN, implied '-a' Directive on line [\d]+ of file/) || ($ThisLine =~ /packet devices \[this device CD\/DVD\] not SMART capable/) || ($ThisLine =~ /System clock time adjusted to the past/) ) { # ignore } elsif ( $ThisLine =~ /--capabilites is set/ and $IgnoreCapabilities ) { # ignore } elsif ( $ThisLine =~ /no ATA CHECK POWER STATUS support, ignoring -n Directive/ and $IgnorePower ) { # ignore } elsif ( ($Device,$Msg) = ($ThisLine =~ /^Device: ([^,]+), is SMART capable. Adding to "monitor" list./ )) { $Monitoring{$Device} = 1; } elsif ( ($Device,$Msg) = ($ThisLine =~ /^Device: ([^,]+), ([^,]+, S\/N:[^,]+,.* FW:.*)/ )) { $DeviceInfo{$Device} = $Msg; } elsif ( ($Device,$Msg) = ($ThisLine =~ /^Device: ([^,]+), (\[[^,]+, lu id: .*)/ )) { $DeviceInfo{$Device} = $Msg; # } elsif ( ($Device,$Msg) = ($ThisLine =~ /^Device: ([^,]+), (.*)$/)) { # $ParamChanges{$Device}{$Msg}++; } elsif ( ($Device) = ($ThisLine =~ /^Device: ([^,]+), not found in smartd database./ )) { $NotInDatabase{$Device}++; } elsif ( ($Device,$AttribType,$Code,$Name,undef,undef,undef,$RawVal) = ($ThisLine =~ /^Device: ([^,]+), SMART ([A-Za-z]+) Attribute: ([0-9]+) (Temperature_Celsius) changed from ([0-9]+) (\[Raw [0-9]+(?: \([0-9]+\s[0-9]+\s[0-9]+\s[0-9]+(?:\s[0-9])?\))?\]) to ([0-9]+) \[Raw ([0-9]+)(?: \([0-9]+\s[0-9]+\s[0-9]+\s[0-9]+(?:\s[0-9])?\))?\]/)) { push @{$TempChanges{$Device}}, $RawVal; # smartd reports temperature changes this way only for SCSI disks } elsif ( ($Device,$AttribType,$Code,$Name,undef,undef,$NewVal) = ($ThisLine =~ /^Device: ([^,]+), SMART ([A-Za-z]+) Attribute: ([0-9]+) ([A-Za-z_]+) changed from ([0-9]+) (\[Raw [0-9]+\] )?to (.*)/)) { push (@{$ParamChanges{$Device}{"$AttribType: $Name ($Code)"}}, $NewVal); } elsif ( ($Device,$Name,undef,$NewVal) = ($ThisLine =~ /^Device: ([^,]+), (.*) increased from ([0-9]+) to ([0-9]+)/) ) { push (@{$ParamChanges{$Device}{"information: $Name"}}, $NewVal); } elsif ( ($Device,$NewVal) = ($ThisLine =~ /^Device: ([^,]+), initial Temperature is (\d+) Celsius/)) { push @{$TempChanges{$Device}},$NewVal; } elsif ( ($Device,$Limit) = ($ThisLine =~ /^Device: ([^,]+), Temperature \d+ Celsius reached limit of (\d+) Celsius/)) { # Device: /dev/sda, Temperature 37 Celsius reached limit of 10 Celsius (Min/Max 37/37) $TempLimit{"$Device,$Limit"}++; } elsif ( ($Device,$Limit) = ($ThisLine =~ /^Device: ([^,]+), Temperature \d+ Celsius reached critical limit of (\d+) Celsius/)) { # Device: /dev/sda, Temperature 38 Celsius reached critical limit of 15 Celsius (Min/Max 38!/39) $TempCritLimit{"$Device,$Limit"}++; } elsif ( ($Device,$NewVal) = ($ThisLine =~ /^Device: ([^,]+), Temperature changed [-+]?\d+ Celsius to (\d+) Celsius/)) { push @{$TempChanges{$Device}},$NewVal; } elsif ( ($Device, $Num) = ($ThisLine =~ /^Device: ([^,]+), (\d+) Currently unreadable \(pending\) sectors/) ) { $Pendsectors{$Device}++; $NumPendsectors{$Device} = $Num; } elsif ( ($Device, $Num) = ($ThisLine =~ /^Device: ([^,]+), (\d+) Offline uncorrectable sectors/) ) { $Offsectors{$Device}++; $NumOffsectors{$Device} = $Num; } elsif ( ($Device,$TestType) = ($ThisLine =~ /^Device: ([^,]+), starting scheduled ((?:Short|Long|Conveyance|Selective) Self-|Offline Immediate )Test/) ) { $DriveTest{$Device}{$TestType}++; } elsif ( ($Device,$AttribType,$Code,$Name) = ($ThisLine =~ /^Device: ([^,]+), Failed SMART ([A-Za-z]+) Attribute: ([0-9]+) ([A-Za-z_]+)/)) { $Failed{$Device}{"$AttribType attribute: $Name ($Code)"}++; } elsif ( ($Device, $Text) = ($ThisLine =~ /^Device: ([^,]+), (?:failed|SMART Failure:) (.*)$/) ) { $Failed{$Device}{"$Text"}++; } elsif ( ($Device, $Text) = ($ThisLine =~ /^Device: ([^,]+), (.*) (?:[Ff]ailed)$/) ) { $Failed{$Device}{"$Text"}++; } elsif ( ( $ThisLine =~ /warning/i ) ) { $Warnings{$ThisLine}++; } elsif ( ($Device, $Text) = ( $ThisLine =~ /^Device: ([^,]+), (can't monitor.*)$/i ) ) { $CantMonitor{$Device}{$Text}++; } elsif ( ($ThisLine =~ /smartd startup failed/ ) ) { $StartupFailed++; } elsif ( ($ThisLine =~ /smartd shutdown failed/ ) ) { $ShutdownFailed++; } elsif ( ($Device,$DLine) = ($ThisLine =~ /Unable to register SCSI device (.*) at line ([0-9]*) of file/) ) { $UnableToReg{"$Device,$DLine"}++ } elsif ( ($Device) = ($ThisLine =~ /Device ([^ ]+) not available/)) { $UnavailableDev{$Device}++; } elsif ( ($Device) = ($ThisLine =~ /Device (.*): SATA disks accessed via libata are supported by Linux kernel versions 2.6.15-rc1 and above/) ) { $SataDisk{"$Device"}++; } elsif ( ($Device) = ($ThisLine =~ /^Device: ([^,]+), reconnected / )) { $Reconnected{$Device}++ if $Device !~ /$IgnoreRemoval/; } elsif ( ($Device) = ($ThisLine =~ /^Device: ([^,]+), removed / )) { $Removed{$Device}++ if $Device !~ /$IgnoreRemoval/; } elsif ($ThisLine =~ /Unable to monitor any SMART enabled devices\. Try debug \(-d\) option\. Exiting/) { $UnableToMonitor++; } elsif ( ($Device) = ($ThisLine =~ /Device: ([^,]+), FAILED SMART self-check/) ) { $CheckFailed{$Device}++; } else { # Report any unmatched entries... $OtherList{$ThisLine}++; } } if (keys %CheckFailed) { print "\nFAILED SMART self-check !!!"; print "\n---------------------------"; foreach my $Device (sort keys %CheckFailed) { printf "\n %s: BACK UP DATA NOW!", $Device; } print "\n====================================\n"; } if ($UnableToMonitor > 0) { print "\nUnable to monitor any SMART enabled devices."; print "\n Try debug (-d) option: $UnableToMonitor Time(s)\n"; } if (keys %NotInDatabase) { print "\n"; foreach my $Device (sort keys %NotInDatabase) { print "$Device not in smartd database.\n"; } } if (keys %CantMonitor and $Detail) { foreach my $Device (sort keys %CantMonitor) { print "\n$Device :\n"; foreach my $Line (sort keys %{$CantMonitor{$Device}}) { print " $Line - " . $CantMonitor{$Device}{$Line} . " Time(s)\n"; } } } if (keys %ParamChanges) { foreach my $Device (sort keys %ParamChanges) { print "\n$Device :\n"; foreach my $Msg (sort keys %{$ParamChanges{$Device}}) { print " $Msg changed to "; my $count=0; foreach (@{$ParamChanges{$Device}{$Msg}}) { # print 12 values to each line if ($count % 12 == 0) { print "\n "; } print "$_, "; $count++; } print "\n"; } } } if (keys %TempChanges) { print "Temperature Changes\n==================\n"; my (@min,@max,@sorttemp); foreach my $Device (sort keys %TempChanges) { if($Detail < 10) { @sorttemp = sort @{$TempChanges{$Device}}; push @min, $sorttemp[0]; push @max, $sorttemp[$#sorttemp]; } elsif($Detail < 20) { @sorttemp = sort @{$TempChanges{$Device}}; print "$Device : $sorttemp[0] - $sorttemp[$#sorttemp]\n"; } else { print "$Device : "; print join ", ",@{$TempChanges{$Device}}; print "\n"; } } if($Detail < 10) { @sorttemp = sort @min; my $mint = $sorttemp[0]; @sorttemp = sort @max; my $maxt = $sorttemp[$#sorttemp]; print "All devices: $mint - $maxt\n"; } } if (keys %TempCritLimit) { printf "\nReached critical temperature limit:\n"; foreach (keys %TempCritLimit) { my ($Device,$Limit)=split ","; print "\t" . $Device . ": reached limit of " . $Limit . " Celsius: ". $TempCritLimit{"$Device,$Limit"} . " Time(s)\n"; } } if (keys %TempLimit) { printf "\nReached temperature limit:\n"; foreach (keys %TempLimit) { my ($Device,$Limit)=split ","; print "\t" . $Device . ": reached limit of " . $Limit . " Celsius: ". $TempLimit{"$Device,$Limit"} . " Time(s)\n"; } } if (keys %Pendsectors){ print "\nCurrently unreadable (pending) sectors detected:\n"; foreach my $Device (sort keys %Pendsectors) { print "\t" . $Device . " - " . $Pendsectors{$Device} . " Time(s)\n"; print "\t" . $NumPendsectors{$Device} . " unreadable sectors detected\n"; } } if (keys %Offsectors){ print "\nOffline uncorrectable sectors detected:\n"; foreach my $Device (sort keys %Offsectors) { print "\t" . $Device . " - " . $Offsectors{$Device} . " Time(s)\n"; print "\t" . $NumOffsectors{$Device} . " offline uncorrectable sectors detected\n"; } } if (keys %Failed) { foreach my $Device (sort keys %Failed) { print "\n$Device :\n"; foreach my $Msg (sort keys %{$Failed{$Device}}) { print " Failed $Msg " . $Failed{$Device}{$Msg} . " Time(s)\n"; } } } if (keys %DriveTest) { foreach my $Device (sort keys %DriveTest) { print "\n$Device :\n"; foreach my $Type (sort keys %{$DriveTest{$Device}}) { print " started scheduled ${Type}Test " . $DriveTest{$Device}{$Type} . " Time(s)\n"; } } } if ( (keys %Warnings) ) { print "\nWarnings:\n"; foreach my $Line (sort {$Warnings{$b} <=> $Warnings{$a}} keys %Warnings) { print "\t" . $Line . " - ". $Warnings{$Line} . " Time(s)\n"; } } if ($StartupFailed) { print "\n Smartd startup failed: " . $StartupFailed . " Time(s)\n"; } if ($ShutdownFailed) { print "\n Smartd shutdown failed: " . $ShutdownFailed . " Time(s)\n"; } if ( (keys %UnableToReg) ) { print "\n Wrong configuration for devices:\n"; foreach (sort keys %UnableToReg) { ($Device,$DLine) = split ","; print " " . $Device . (" (line ") . $DLine . ") : ". $UnableToReg{"$Device,$DLine"} . " Time(s)\n"; } } if (%UnavailableDev) { print "\nUnavailable device:\n"; foreach my $Device (sort keys %UnavailableDev) { print " Device " . $Device . " : " . $UnavailableDev{$Device} . " Time(s)\n"; } } if (%SataDisk) { print "\nSATA disk(s) supported by Linux kernel >= 2.6.15-rc1:\n"; foreach my $Device (sort keys %SataDisk) { print " " .$Device .": Try adding '-d ata' or '-d sat' to the smartd.conf config file line\n"; } print "\n"; } if (%Removed) { print "\Devices removed:\n"; foreach my $Device (sort keys %Removed) { print " " .$Device .": Removed " . $Removed{$Device} . " Time(s)\n"; } print "\n"; } if (%Reconnected) { print "\Devices reconnected:\n"; foreach my $Device (sort keys %Reconnected) { print " " .$Device .": Reconnected " . $Reconnected{$Device} . " Time(s)\n"; } print "\n"; } if (keys %Monitoring and $Detail > 7) { print "\nMonitoring:\n"; foreach my $Device (sort keys %Monitoring) { print "\t$Device"; if (defined($DeviceInfo{$Device})) { print ": $DeviceInfo{$Device}\n"; } else { print "\n"; } } } if ((%OtherList) and (not $IgnoreUnmatched)){ print "\n**Unmatched Entries**\n"; foreach my $line (sort keys %OtherList) { print $line." : " .$OtherList{$line}." time(s)\n"; } } exit(0); # vi: shiftwidth=3 tabstop=3 syntax=perl et # Local Variables: # mode: perl # perl-indent-level: 3 # indent-tabs-mode: nil # End: logwatch-7.12/scripts/services/mysql0000664000211400021140000001162414274101040020044 0ustar logwatchlogwatch ######################################################## # Please file all bug reports, patches, and feature # requests under: # https://sourceforge.net/p/logwatch/_list/tickets # Help requests and discusion can be filed under: # https://sourceforge.net/p/logwatch/discussion/ ######################################################## ######################################################## # Processes all messages and summarizes them # Each message is given with a timestamp and RMS ######################################################## ## Copyright (c) 2006 by Jeremias Reith ## Modified 2009 by Michael Baierl ## Covered under the included MIT/X-Consortium License: ## http://www.opensource.org/licenses/mit-license.php ## All modifications and contributions by other persons to ## this script are assumed to have been donated to the ## Logwatch project and thus assume the above copyright ## and licensing terms. If you want to make contributions ## under your own copyright or a different license this ## must be explicitly stated in the contribution an the ## Logwatch project reserves the right to not accept such ## contributions. If you have made significant ## contributions to this script and want to claim ## copyright please contact logwatch-devel@lists.sourceforge.net. ######################################################### use strict; use Logwatch ':dates'; use Time::Local; use POSIX qw(strftime); my $date_format = '%y%m%d %H:%M:%S'; my $filter = TimeFilter($date_format); my $detail = exists $ENV{'LOGWATCH_DETAIL_LEVEL'} ? $ENV{'LOGWATCH_DETAIL_LEVEL'} : 0; # we do not use any Date:: package (or strptime) as they are probably not available my %month2num = ( Jan => 0, Feb => 1, Mar => 2, Apr => 3, May => 4, Jun => 5, Jul => 6, Aug => 7, Sep => 8, Oct => 9, Nov => 10, Dec => 11 ); # array of message categories (we do not use a hash to keep the order) # first element: category name # second element: matching regexp ($1 should contain the message) # third element: anonymous hash ref (stores message counts) my @message_categories = (['Errors', qr/\[ERROR\] (.*)$/o, {}], ['Note', qr/\[Note\] (.*)$/o, {}], ['Warnings', qr/\[Warning] (.*)$/o, {}], ['Other', qr/(.*)$/o, {}]); # counting messages while(<>) { my $line = $_; # skipping messages that are not within the requested range next unless $line =~ /^($filter)/o; $1 =~ /(\d\d)(\d\d)(\d\d)\s+(\d+):(\d+):(\d+)/; my $time; { # timelocal is quite chatty local $SIG{'__WARN__'} = sub {}; $time = timelocal($6, $5, $4, $3, $2-1, $1); } # Count lines with increasing number as one: # [Warning] Aborted connection 107194 to db: ... $line =~ s/(Aborted connection) \d+ (to db)/$1 $2/; foreach my $cur_cat (@message_categories) { if($line =~ /$cur_cat->[1]/) { my $msgs = $cur_cat->[2]; $msgs->{$1} = {count => '0', first_occurrence => $time, sum => 0, sqrsum => 0} unless exists $msgs->{$1}; $msgs->{$1}->{'count'}++; # summing up timestamps and squares of timestamps # in order to calculate the rms # using first occurrence of message as offset in calculation to # prevent an integer overflow $msgs->{$1}->{'sum'} += $time - $msgs->{$1}->{'first_occurrence'}; $msgs->{$1}->{'sqrsum'} += ($time - $msgs->{$1}->{'first_occurrence'}) ** 2; last; } } } # generating summary foreach my $cur_cat (@message_categories) { # skipping non-requested message types next unless keys %{$cur_cat->[2]}; my ($name, undef, $msgs) = @{$cur_cat}; print $name, ":\n"; my $last_count = 0; # sorting messages by count my @sorted_msgs = sort { $msgs->{$b}->{'count'} <=> $msgs->{$a}->{'count'} } keys %{$msgs}; foreach my $msg (@sorted_msgs) { # grouping messages by number of occurrence print "\n", $msgs->{$msg}->{'count'}, " times:\n" unless $last_count == $msgs->{$msg}->{'count'}; my $rms = 0; # printing timestamp print '['; if($msgs->{$msg}->{'count'} > 1) { # calculating rms $rms = int(sqrt( ($msgs->{$msg}->{'count'} * $msgs->{$msg}->{'sqrsum'} - $msgs->{$msg}->{'sum'}) / ($msgs->{$msg}->{'count'} * ($msgs->{$msg}->{'count'} - 1)))); print strftime($date_format, localtime($msgs->{$msg}->{'first_occurrence'}+int($rms/2))); print ' +/-'; # printing rms if($rms > 86400) { print int($rms/86400) , ' day(s)'; } elsif($rms > 3600) { print int($rms/3600) , ' hour(s)'; } elsif($rms > 60) { print int($rms/60) , ' minute(s)'; } else { print $rms, ' seconds'; } } else { # we have got this message a single time print strftime($date_format, localtime($msgs->{$msg}->{'first_occurrence'})); } print '] ', $msg, "\n"; $last_count = $msgs->{$msg}->{'count'}; } print "\n"; } # vi: shiftwidth=3 tabstop=3 et # Local Variables: # mode: perl # perl-indent-level: 3 # indent-tabs-mode: nil # End: logwatch-7.12/scripts/services/postgresql0000664000211400021140000001316714743365005021124 0ustar logwatchlogwatch ######################################################## # Please file all bug reports, patches, and feature # requests under: # https://sourceforge.net/p/logwatch/_list/tickets # Help requests and discusion can be filed under: # https://sourceforge.net/p/logwatch/discussion/ ######################################################## ########################################################################## # # Logwatch service for postgresql error log # # Processes all messages and summarizes them # Each message is given with a timestamp and RMS # ######################################################## # (C) 2011 by Dalibo - http://www.dalibo.com/ # written by Gilles Darold. # # Heavily based on the mysql script by Jeremias Reith ######################################################## ## Covered under the included MIT/X-Consortium License: ## http://www.opensource.org/licenses/mit-license.php ## All modifications and contributions by other persons to ## this script are assumed to have been donated to the ## Logwatch project and thus assume the above copyright ## and licensing terms. If you want to make contributions ## under your own copyright or a different license this ## must be explicitly stated in the contribution and the ## Logwatch project reserves the right to not accept such ## contributions. If you have made significant ## contributions to this script and want to claim ## copyright please contact logwatch-devel@lists.sourceforge.net. ######################################################## use strict; use Logwatch ':dates'; use Time::Local; use POSIX qw(strftime); # Allow timestamp from two different logfile format: syslog and stderr my $date_format1 = '%Y-%m-%d %H:%M:%S'; my $date_format2 = '%b %e %H:%M:%S'; my $filter1 = TimeFilter($date_format1); my $filter2 = TimeFilter($date_format2); # Allow summarization of WARNING and HINT too if wanted my $detail = exists $ENV{'LOGWATCH_DETAIL_LEVEL'} ? $ENV{'LOGWATCH_DETAIL_LEVEL'} : 0; # Used to replace the month trigram into the syslog timestamp my %month2num = ( Jan => 0, Feb => 1, Mar => 2, Apr => 3, May => 4, Jun => 5, Jul => 6, Aug => 7, Sep => 8, Oct => 9, Nov => 10, Dec => 11 ); # Array of the relevant lines in the log file. # First element: type of event # Second element: matching regexp ($1 should contain the message) # Third element: anonymous hash ref (stores message counts) my @message_categories = ( ['Panics', qr/PANIC: (.*)$/o, {}], ['Fatals', qr/FATAL: (.*)$/o, {}], ['Errors', qr/ERROR: (.*)$/o, {}] ); if ($detail) { # Add more log information push(@message_categories, ['Warnings', qr/WARNING: (.*)$/o, {}], ['Hints', qr/HINT: (.*)$/o, {}] ); } # Set the current year as syslog don't have this information. my $cur_year = (localtime(time))[5]; # Parse messages from stdin while(<>) { my $line = $_; # skipping messages that are not within the requested range next unless $line =~ /^($filter1|$filter2)/o; my $datetime = $1; my $time = ''; # Date/time format differ following the log_destination (stderr or syslog) if ($datetime =~ /(\d{4})-(\d{2})-(\d{2})\s+(\d+):(\d+):(\d+)/) { { # timelocal is quite chatty local $SIG{'__WARN__'} = sub {}; $time = timelocal($6, $5, $4, $3, $2-1, $1-1900); } } elsif ($datetime =~ /(\w)\s+(\d+)\s+(\d+):(\d+):(\d+)/) { { # timelocal is quite chatty local $SIG{'__WARN__'} = sub {}; $time = timelocal($5, $4, $3, $2, $month2num{$1}, $cur_year); } } # Remove character position $line =~ s/ at character \d+//; foreach my $cur_cat (@message_categories) { if($line =~ /$cur_cat->[1]/) { my $msgs = $cur_cat->[2]; $msgs->{$1} = {count => '0', first_occurrence => $time, sum => 0, sqrsum => 0} unless exists $msgs->{$1}; $msgs->{$1}->{'count'}++; # summing up timestamps and squares of timestamps # in order to calculate the rms # using first occurrence of message as offset in calculation to # prevent an integer overflow $msgs->{$1}->{'sum'} += $time - $msgs->{$1}->{'first_occurrence'}; $msgs->{$1}->{'sqrsum'} += ($time - $msgs->{$1}->{'first_occurrence'}) ** 2; last; } } } # generating summary foreach my $cur_cat (@message_categories) { # skipping non-requested message types next unless keys %{$cur_cat->[2]}; my ($name, undef, $msgs) = @{$cur_cat}; print $name, ":\n"; print '-' x (length($name)+1), "\n"; my $last_count = 0; # sorting messages by count my @sorted_msgs = sort { $msgs->{$b}->{'count'} <=> $msgs->{$a}->{'count'} } keys %{$msgs}; foreach my $msg (@sorted_msgs) { # grouping messages by number of occurrence print "\n", $msgs->{$msg}->{'count'}, " times:\n" unless $last_count == $msgs->{$msg}->{'count'}; my $rms = 0; # printing timestamp print '['; if($msgs->{$msg}->{'count'} > 1) { # calculating rms $rms = int(sqrt( ($msgs->{$msg}->{'count'} * $msgs->{$msg}->{'sqrsum'} - $msgs->{$msg}->{'sum'}) / ($msgs->{$msg}->{'count'} * ($msgs->{$msg}->{'count'} - 1)))); print strftime($date_format1, localtime($msgs->{$msg}->{'first_occurrence'}+int($rms/2))); print ' +/-'; # printing rms if($rms > 86400) { print int($rms/86400) , ' day(s)'; } elsif($rms > 3600) { print int($rms/3600) , ' hour(s)'; } elsif($rms > 60) { print int($rms/60) , ' minute(s)'; } else { print $rms, ' seconds'; } } else { # we have got this message a single time print strftime($date_format1, localtime($msgs->{$msg}->{'first_occurrence'})); } print '] ', $msg, "\n"; $last_count = $msgs->{$msg}->{'count'}; } print "\n"; } logwatch-7.12/scripts/services/bfd0000664000211400021140000000411614274101034017433 0ustar logwatchlogwatch ######################################################## # Please file all bug reports, patches, and feature # requests under: # https://sourceforge.net/p/logwatch/_list/tickets # Help requests and discusion can be filed under: # https://sourceforge.net/p/logwatch/discussion/ ######################################################## ######################################################## ## Copyright (c) 2008 Andy Bolstridge ## Covered under the included MIT/X-Consortium License: ## http://www.opensource.org/licenses/mit-license.php ## All modifications and contributions by other persons to ## this script are assumed to have been donated to the ## Logwatch project and thus assume the above copyright ## and licensing terms. If you want to make contributions ## under your own copyright or a different license this ## must be explicitly stated in the contribution an the ## Logwatch project reserves the right to not accept such ## contributions. If you have made significant ## contributions to this script and want to claim ## copyright please contact logwatch-devel@lists.sourceforge.net. ######################################################### use strict; my $Debug = $ENV{'LOGWATCH_DEBUG'} || 0; my $DebugCounter = 0; #Init Array my @OtherList = (); #Init Hashes my (%Banned); if ( $Debug >= 5 ) { print STDERR "\n\nDEBUG: Inside BFD Filter \n\n"; $DebugCounter = 1; } while (defined(my $ThisLine = )) { if ( $Debug >= 5 ) { print STDERR "DEBUG($DebugCounter): $ThisLine"; $DebugCounter++; } $ThisLine =~ s/^[^ ]* [^ ]* //; if ( $ThisLine =~ s/.*apf \-d ([^ ]+).*\{([^\}]+).*/$1 : \($2\)/ ) { $Banned{$ThisLine}++; } else { # Report any unmatched entries... push @OtherList,$ThisLine; } } if (keys %Banned) { print "\nBanned:\n"; foreach my $ThisOne (keys %Banned) { print " ". $ThisOne; } } if ($#OtherList >= 0) { print "\n**Unmatched Entries**\n"; print @OtherList; } exit(0); # vi: shiftwidth=3 tabstop=3 et # Local Variables: # mode: perl # perl-indent-level: 3 # indent-tabs-mode: nil # End: logwatch-7.12/scripts/services/tac_acc0000664000211400021140000001006414274101044020255 0ustar logwatchlogwatch ######################################################## # Please file all bug reports, patches, and feature # requests under: # https://sourceforge.net/p/logwatch/_list/tickets # and copy: # frank@fam-breedijk.com. # Help requests and discusion can be filed under: # https://sourceforge.net/p/logwatch/discussion/ ######################################################## ####################################################### ## Copyright (c) 2008 Kirk Bauer ## Covered under the included MIT/X-Consortium License: ## http://www.opensource.org/licenses/mit-license.php ## All modifications and contributions by other persons to ## this script are assumed to have been donated to the ## Logwatch project and thus assume the above copyright ## and licensing terms. If you want to make contributions ## under your own copyright or a different license this ## must be explicitly stated in the contribution an the ## Logwatch project reserves the right to not accept such ## contributions. If you have made significant ######################################################## use strict; my ($ThisLine, @fields, %activity, %isdn, @OtherList); my $Detail = $ENV{'LOGWATCH_DETAIL_LEVEL'} || 0; while (defined($ThisLine = )) { @fields = split /\t/, $ThisLine; if ( @fields == 11 && $fields[10] =~ /^cmd=/ ) { unless ( exists $activity{$fields[1]} ) { $activity{$fields[1]} = {}; } unless ( exists $activity{$fields[1]}->{$fields[2]} ) { $activity{$fields[1]}->{$fields[2]} = {}; } chomp $fields[10]; $fields[10] =~ s/^cmd=//; $activity{$fields[1]}->{$fields[2]}->{$fields[10]}++; } elsif ( @fields == 12 && $fields[11] =~ /^cmd=/ ) { unless ( exists $activity{$fields[1]} ) { $activity{$fields[1]} = {}; } unless ( exists $activity{$fields[1]}->{$fields[2]} ) { $activity{$fields[1]}->{$fields[2]} = {}; } chomp $fields[11]; $fields[11] =~ s/^cmd=//; $activity{$fields[1]}->{$fields[2]}->{$fields[11]}++; } elsif ( @fields == 27 && $fields[24] =~ /^elapsed_time=/ ) { unless ( exists $isdn{$fields[2]} ) { $isdn{$fields[2]} = {}; } unless ( exists $isdn{$fields[2]}->{$fields[4]} ) { $isdn{$fields[2]}->{$fields[4]} = {}; $isdn{$fields[2]}->{$fields[4]}->{'seconds'} = 0; } chomp $fields[24]; $fields[24] =~ s/^elapsed_time=//; $isdn{$fields[2]}->{$fields[4]}->{'seconds'} += $fields[24]; } elsif ( @fields == 10 && $fields[5] =~ /^start/ ) { unless ( exists $isdn{$fields[2]} ) { $isdn{$fields[2]} = {}; } unless ( exists $isdn{$fields[2]}->{$fields[4]} ) { $isdn{$fields[2]}->{$fields[4]}->{'start'} = 0; } $isdn{$fields[2]}->{$fields[4]}->{'start'}++; } else { # Report any unmatched entries... push @OtherList,$ThisLine; } } if ((keys %activity) and ($Detail >= 5)) { foreach my $host ( sort keys %activity ) { print "\nActivity on $host:\n"; foreach my $user ( sort keys %{$activity{$host}} ) { print "User: $user\n"; foreach my $command ( sort keys %{$activity{$host}->{$user}} ) { print "$command\t$activity{$host}->{$user}->{$command} time(s)\n"; } } } } if ((keys %isdn) and ($Detail >= 5)) { foreach my $host ( sort keys %isdn ) { print "\nISDN on $host:\n"; foreach my $number ( sort keys %{$isdn{$host}} ) { print "Number: $number dialed total $isdn{$host}->{$number}->{'seconds'} seconds"; if ($isdn{$host}->{$number}->{'start'}) { print " started $isdn{$host}->{$number}->{'start'} times\n"; } else { print "\n"; } } } } if ($#OtherList >= 0) { print "\n**Unmatched Entries**\n\n"; print @OtherList; } exit(0); # vi: shiftwidth=3 tabstop=3 syntax=perl et # Local Variables: # mode: perl # perl-indent-level: 3 # indent-tabs-mode: nil # End: logwatch-7.12/scripts/services/automount0000664000211400021140000001305614274101034020736 0ustar logwatchlogwatch ######################################################## # Please file all bug reports, patches, and feature # requests under: # https://sourceforge.net/p/logwatch/_list/tickets # and copy: # Gerald Teschl # Help requests and discusion can be filed under: # https://sourceforge.net/p/logwatch/discussion/ ######################################################## ######################################################## # This was written and is maintained by: # Gerald Teschl ######################################################## ######################################################## ## Copyright (c) 2008 Kirk Bauer ## Covered under the included MIT/X-Consortium License: ## http://www.opensource.org/licenses/mit-license.php ## All modifications and contributions by other persons to ## this script are assumed to have been donated to the ## Logwatch project and thus assume the above copyright ## and licensing terms. If you want to make contributions ## under your own copyright or a different license this ## must be explicitly stated in the contribution an the ## Logwatch project reserves the right to not accept such ## contributions. If you have made significant ## contributions to this script and want to claim ## copyright please contact logwatch-devel@lists.sourceforge.net. ######################################################### use strict; my $Detail = $ENV{'LOGWATCH_DETAIL_LEVEL'} || 0; my $MountAttempts = 0; #Init String containers my ( $Key, $ThisMount, $ThisOne ); #Init Hashes my ( %Failed, %FailedStartup, %KeyNotFound, %OtherList, %StartStop ); while (defined(my $ThisLine = )) { if ( ($ThisLine =~ /^using kernel protocol version .*$/) or ($ThisLine =~ /^expired .*$/) or ($ThisLine =~ /^lookup\(ldap\): got answer, but no first entry for /) or ($ThisLine =~ /^>>.*mount: .*$/) or ($ThisLine =~ /lookup_read_master: lookup\(nisplus\): couldn't locate? nis\+ table auto.master/) or ($ThisLine =~ /create_(tcp|udp)_client: hostname lookup failed: (No such process|Operation not permitted)/) or ($ThisLine =~ /lookup_mount: exports lookup failed for .*directory/) or ($ThisLine =~ /master_do_mount: failed to startup mount/) ) { # don't care about these } elsif ( ($ThisMount) = ($ThisLine =~ /^attempting to mount entry (.*)$/) ) { # store Mount #$Mount = $ThisMount; something is wrong with this -mgt $MountAttempts++; } elsif ($ThisLine =~ /^mount\(nfs\): nfs: mount failure .*:.* on (.*)$/) { $Failed{$1}{'nfsm'}++; } elsif ($ThisLine =~ /^mount\(nfs\): entry (.*) lookup failure$/) { $Failed{$1}{'nfsl'}++; } elsif (( $ThisLine =~ /^mount\(generic\): failed to mount .* on (.*)$/) or ( $ThisLine =~ /^handle_mounts: mount on (.*) failed!/) ) { $Failed{$1}{'mnt'}++; } elsif ( $ThisLine =~ /^failed to mount \/(\w+).*$/) { $Failed{$1}{'mnt'}++; } elsif ( ($ThisMount) = ( $ThisLine =~ /^(.*): mount failed!$/) ) { $FailedStartup{$ThisMount}++; } elsif ( $ThisLine =~ /^lookup\((file|program)\): lookup for (.*) failed$/) { $Failed{$2}{$1}++; } elsif ( ($ThisMount) = ($ThisLine =~ /^starting automounter version .* path = (.*), maptype = .*, mapname = .*$/) ) { $StartStop{$ThisMount}{'start'}++; $StartStop{$ThisMount}{'stop'}+=0; } elsif ( ($ThisMount) = ($ThisLine =~ /^shutting down, path = (.*)$/) ) { $StartStop{$ThisMount}{'stop'}++; } elsif ( ($Key) = ( $ThisLine =~ /^key "(.*)" not found in map source\(s\)\.$/) ) { $KeyNotFound{$Key}++; } else { # Report any unmatched entries... chomp($ThisLine); $OtherList{$ThisLine}++; } } if (keys %FailedStartup) { print "\nFailed Startups:\n"; foreach $ThisOne (keys %FailedStartup) { print " $ThisOne " . $FailedStartup{$ThisOne} . " Time(s)\n"; } } if (keys %Failed) { print "\nFailed mounts:\n"; foreach $ThisOne (sort keys %Failed) { printf (" %-20s", $ThisOne); if ($Failed{$ThisOne}{'nfsm'}) { print "NFS Mount Failure $Failed{$ThisOne}{'nfsm'} Time(s)"; } if ($Failed{$ThisOne}{'nfsl'}) { print "NFS Lookup Failure $Failed{$ThisOne}{'nfsl'} Time(s)"; } if ($Failed{$ThisOne}{'mnt'}) { print "Mount Failure $Failed{$ThisOne}{'mnt'} Time(s)"; } if ($Failed{$ThisOne}{'file'}) { print "File Lookup Failure $Failed{$ThisOne}{'file'} Time(s)"; } if ($Failed{$ThisOne}{'program'}) { print "Program Lookup Failure $Failed{$ThisOne}{'program'} Time(s)"; } print "\n"; } } if ( ($Detail >= 5) and (keys %KeyNotFound) ) { print "\nKeys not found:\n"; foreach $Key (keys %KeyNotFound) { print " $Key: $KeyNotFound{$Key} Time(s)\n"; } } if ( ($Detail >= 10) and (keys %StartStop) ) { print "\nStatistics:\n"; print " Total number of mount attempts: $MountAttempts\n"; foreach $ThisOne (keys %StartStop) { $StartStop{$ThisOne}{'start'} = 0 unless defined $StartStop{$ThisOne}{'start'}; $StartStop{$ThisOne}{'stop'} = 0 unless defined $StartStop{$ThisOne}{'stop'}; print " $ThisOne: Started $StartStop{$ThisOne}{'start'} and stopped $StartStop{$ThisOne}{'stop'} Time(s)\n"; } } if (keys %OtherList) { print "\n**Unmatched Entries**\n"; foreach $ThisOne (keys %OtherList) { print "$ThisOne: $OtherList{$ThisOne} Time(s)\n"; } } exit(0); # vi: shiftwidth=3 tabstop=3 syntax=perl et # Local Variables: # mode: perl # perl-indent-level: 3 # indent-tabs-mode: nil # End: logwatch-7.12/scripts/services/evtsystem0000664000211400021140000003764614743365004020773 0ustar logwatchlogwatch ######################################################## # Please file all bug reports, patches, and feature # requests under: # https://sourceforge.net/p/logwatch/_list/tickets # Help requests and discusion can be filed under: # https://sourceforge.net/p/logwatch/discussion/ ######################################################## ######################################################## ## Copyright (c) 2008 Orion Poplawski ## Covered under the included MIT/X-Consortium License: ## http://www.opensource.org/licenses/mit-license.php ## All modifications and contributions by other persons to ## this script are assumed to have been donated to the ## Logwatch project and thus assume the above copyright ## and licensing terms. If you want to make contributions ## under your own copyright or a different license this ## must be explicitly stated in the contribution an the ## Logwatch project reserves the right to not accept such ## contributions. If you have made significant ## contributions to this script and want to claim ## copyright please contact logwatch-devel@lists.sourceforge.net. ######################################################### use strict; my $Detail = $ENV{'LOGWATCH_DETAIL_LEVEL'} || 0; my $Ignore_messages = $ENV{'ignore_messages'} || '^$'; my %Errors; my %RestartRequired; my %Systems; my %Updates; my %UpdatesInstalled; my %UpdatesReadyForInstall; sub human() { my $b=$_; my $i; for ($i=0;$b>1024;$i++) { $b/=1024 } my $u=qw{B K M G T}[$i]; return "$b$u"; } while (defined(my $ThisLine = )) { # User specified ignore messages, lower cased next if $ThisLine =~ /$Ignore_messages/i; my ($Hostname,$Criticality,$SourceName,$DateTime,$EventID,$System,$UserName,$SIDType,$EventLogType,$CategoryString,$DataString,$ExpandedString,$Extra); #Determine format if ($ThisLine =~ /MSWinEventLog\[/) { # Snare 4 #Parse ($Criticality,$SourceName,$DateTime,$EventID,$System,$UserName,$SIDType,$EventLogType,$Hostname,$CategoryString,$DataString,$ExpandedString,$Extra) = ($ThisLine =~ /MSWinEventLog\[(\d+)\]:(\w+)\t\d+\t([^\t]+)\t(\d+)\t([^\t]+)\t([^\t]+)\t([^\t]+)\t([^\t]+)\t([^\t]+)\t?([^\t]*)\t?([^\t]*)\t?([^\t]*)\t?([^\t]*)/); } elsif ($ThisLine =~ /MSWinEventLog\t/) { # Snare 3 #Parse ($Criticality,$SourceName,$DateTime,$EventID,$System,$UserName,$SIDType,$EventLogType,$Hostname,$CategoryString,$DataString,$ExpandedString,$Extra) = ($ThisLine =~ /MSWinEventLog\t(\d+)\t(\w+)\t\d+\t([^\t]+)\t(\d+)\t([^\t]+)\t([^\t]+)\t([^\t]+)\t([^\t]+)\t([^\t]+)\t?([^\t]*)\t?([^\t]*)\t?([^\t]*)\t?([^\t]*)/); } if (!defined($Hostname)) { print STDERR "Cannot parse $ThisLine"; next; } #print STDERR "ExpandedString = $ExpandedString\n"; next if ($EventLogType eq "Verbose"); next if ($EventLogType eq "Information" and $Detail < 10); # Modify some items that prevent de-duplication if ($Detail < 10) { $ExpandedString =~ s/\d+ time\(s\)/XX times(s)/; $ExpandedString =~ s/requested by PID\s+\S+\s+//; $ExpandedString =~ s/processor \d+/processor X/; $ExpandedString =~ s/for \d+ seconds/for XX seconds/; $ExpandedString =~ s/(APPID|CLSID)\s+\{[0-9A-F\-]+\}/$1 {XXX}/g; $ExpandedString =~ s/(Time:) \d+:\d+:\d+\.\d+ \d+\/\d+\/\d+ Z/$1 TIME/g; while ($ExpandedString =~ /(\d{4,}) bytes/) { my $h = &human($1); $ExpandedString =~ s/$1 bytes/${h}b/g; } } if ($System eq "Application Popup") { #Ignore these next if $ExpandedString =~ /Initialization Failed : The application failed to initialize because the window station is shutting down/; next if $ExpandedString =~ /^Application popup: Windows : Other people are logged on to this computer. Shutting down Windows might cause them to lose data\. Do you want to continue shutting down\?$/; next if $ExpandedString =~ /^Application popup: Message from .*: Automatic software deployment is currently updating your system\. Please save all your documents as the the system might reboot without further notice\. Thank you\./; next if $ExpandedString =~ /^Application popup: Message from .*: The automated software installation utility has completed installing or updating software on your system\. No reboot was necessary\. All updates are complete\./; } if ($System eq "BTHUSB") { next if $ExpandedString =~ /^Windows cannot store Bluetooth authentication codes \(link keys\) on the local adapter\. Bluetooth keyboards might not work in the system BIOS during startup\.$/ and $Detail < 5; } if ($System =~ "EventLog") { #Ignore these next if $ExpandedString =~ /Microsoft \(R\) Windows \(R\) \d+\.\d+\. \d+ +(Multiprocessor Free|Service Pack \d)/; next if $ExpandedString =~ /^The Event log service was started./; next if $ExpandedString =~ /^The Event log service was stopped./; next if $ExpandedString =~ /^The system uptime is \d+ seconds/; } if ($System =~ "LsaSrv") { #Ignore these next if $ExpandedString =~ /^A logon cache entry for user .* was the oldest entry and was removed\. The timestamp of this entry was/; } if ($System eq "Microsoft-Windows-Application-Experience") { #Ignore these next if $ExpandedString eq "The Program Compatibility Assistant service successfully performed phase two initialization."; } if ($System eq "Microsoft-Windows-DfsSvc") { #Ignore these next if $ExpandedString =~ /^DFS has finished building all namespaces\.$/; next if $ExpandedString =~ /^DFS server has finished initializing\.$/; } if ($System eq "Microsoft-Windows-DNS-Client") { next if $ExpandedString =~ /^Name resolution for the name .* timed out/; next if $ExpandedString =~ /^The system failed to (?:register|update and remove) host .* resource records/; next if $ExpandedString =~ /^The system could not remove these host .* RRs/; } if ($System eq "Microsoft-Windows-FilterManager") { #Ignore these next if $ExpandedString =~ /^File System Filter .* has successfully loaded and registered with Filter Manager\.$/; } if ($System eq "Microsoft-Windows-Iphlpsvc") { #High Detail next if $ExpandedString =~ /^Isatap interface .* with address .* has been brought up\.$/ and $Detail < 10; next if $ExpandedString =~ /^Isatap interface .* is no longer active\.$/ and $Detail < 10; } if ($System eq "Microsoft-Windows-Kernel-Boot") { #High Detail next if $ExpandedString =~ /^The boot type was/ and $Detail < 10; next if $ExpandedString =~ /^The bootmgr spent .* waiting for user input/ and $Detail < 10; next if $ExpandedString =~ /^The last shutdown's success status was true. The last boot's success status was true\.$/ and $Detail < 10; next if $ExpandedString =~ /^There are .* boot options on this system/ and $Detail < 10; } if ($System eq "Microsoft-Windows-Kernel-General") { #High Detail next if $ExpandedString =~ /^The operating system started at system time/ and $Detail < 10; next if $ExpandedString =~ /^The operating system is shutting down at system time/ and $Detail < 10; next if $ExpandedString =~ /^The access history in hive .* was cleared updating \d+ keys/ and $Detail < 10; #TODO - We should warn is this is big next if $ExpandedString =~ /^The system time has changed to .* from/; } if ($System eq "Microsoft-Windows-Kernel-Power") { #High Detail next if $ExpandedString =~ /^The system is entering sleep/ and $Detail < 10; next if $ExpandedString =~ /^The kernel power manager has initiated a shutdown transition\.$/ and $Detail < 10; #Ignore these next if $ExpandedString =~ /^ACPI thermal zone .* has been enumerated/; next if $ExpandedString =~ /^Processor \d+ in group \d+ exposes the following power management capabilities/; } if ($System eq "Microsoft-Windows-Kernel-Processor-Power") { #Ignore these next if $ExpandedString =~ /^Processor \d+ in group \d+ exposes the following/; } if ($System eq "Microsoft-Windows-GroupPolicy") { #Ignore these next if $ExpandedString =~ /^The Group Policy settings for the (computer|user) were processed successfully\. There were no changes detected since the last successful processing of Group Policy\.$/; next if $ExpandedString =~ /^The Group Policy settings for the (computer|user) were processed successfully\. New settings from \d+ Group Policy objects were detected and applied\.$/ and $Detail == 0; } if ($System eq "Microsoft-Windows-Ntfs") { #Ignore these next if $ExpandedString =~ /^Volume .* is healthy\. No action is needed\.$/; } if ($System eq "Microsoft-Windows-Power-Troubleshooter") { #High Detail next if $ExpandedString =~ /^The system has resumed from sleep/ and $Detail < 10; } if ($System eq "Microsoft-Windows-Time-Service") { #High Detail next if $ExpandedString =~ /^The time provider NtpClient is currently receiving valid time data from/ and $Detail < 10; next if $ExpandedString =~ /^The time service is now synchronizing the system time with the time source/ and $Detail < 10; } if ($System eq "Microsoft-Windows-WAS") { #High Detail next if $ExpandedString =~ /^A worker process with process id of .* serving application pool .* has requested a recycle because the worker process reached its allowed processing time limit/ and $Detail < 10; } if ($System eq "Microsoft-Windows-WindowsUpdateClient" or $System eq "Windows Update Agent") { #High Detail next if $ExpandedString =~ /^Automatic Updates is now paused\.$/ and $Detail < 10; next if $ExpandedString =~ /^Windows Update started downloading an update\.$/ and $Detail < 10; #Updates if (my ($InstallDateTime, $Updates) = $ExpandedString =~ /^Installation Ready: The following updates are downloaded and ready for installation(?:\. )?(?:This computer is currently scheduled to install these updates on (.*)|To install the updates, an administrator should log on.*|): - (.*)$/) { $InstallDateTime =~ s/\?//g; foreach my $Update (split(" - ",$Updates)) { $InstallDateTime = "Now" if $InstallDateTime eq ""; $UpdatesReadyForInstall{$Hostname}->{$Update} = $InstallDateTime; } next; } if (my ($Update) = $ExpandedString =~ /^Installation Successful: Windows successfully installed the following update: (.*)$/) { delete($UpdatesReadyForInstall{$Hostname}->{$Update}); push(@{$UpdatesInstalled{$Hostname}},$Update); next; } if ($ExpandedString =~ /^Installation Failure:/) { $Errors{$System}->{"$Hostname $ExpandedString"}++; next; } if ($ExpandedString =~ /^Installation Started:/) { next; } if ($ExpandedString =~ /^Restart Required:/) { $RestartRequired{$Hostname} = 1; next; } } if ($System eq "Microsoft-Windows-WHEA-Logger") { $Errors{$System}->{"$Hostname $ExpandedString"}++; next; } if ($System eq "Microsoft-Windows-Winlogon") { #High Detail next if $ExpandedString =~ /User \w+ Notification for Customer Experience Improvement Program/ and $Detail < 10; } if ($System eq "Microsoft-Windows-WinRM") { #High Detail next if $ExpandedString =~ /^The WinRM service is listening for WS-Management requests/ and $Detail < 10; } if ($System eq "NPS") { #High Detail next if $ExpandedString =~ /^A LDAP connection with domain controller .* for domain .* is established/ and $Detail < 10; } if ($System eq "Service Control Manager") { #Ignore these next if $ExpandedString =~ /^The (.*) service entered the running state\./; next if $ExpandedString =~ /^The (.*) service entered the stopped state\./; next if $ExpandedString =~ /^The (.*) service was successfully sent a start control\./; next if $ExpandedString =~ /^The (.*) service was successfully sent a stop control\./; } if ($System eq "USER32") { #High Detail next if $ExpandedString =~ /^The process .* has initiated the power off of computer \w+ on behalf of user .* for the following reason: .*$/ and $Detail < 10; } if ($System eq "Virtual Disk Service") { #High Detail next if $ExpandedString =~ /Service (started|stopped)/ and $Detail < 10; } if ($System eq "atikmdag") { #Ignore these next if $ExpandedString =~ /^UVD Information$/; #High Detail next if $ExpandedString =~ /^Display is not active$/ and $Detail < 10; } if ($System eq "volsnap") { #Med Detail next if $ExpandedString =~ /^The oldest shadow copy of volume .* was deleted to keep disk space usage for shadow copies of volume .* below the user defined limit\.$/ and $Detail < 5; } next if $ExpandedString =~ /client service is started$/ and $Detail < 10; next if $ExpandedString =~ /started successfully\.$/ and $Detail < 10; next if $ExpandedString =~ /has successfully (?:started|stopped)\./ and $Detail < 10; next if $ExpandedString =~ /service .* (?:started|stopped)/i and $Detail < 10; next if $ExpandedString =~ /Module has (?:started|stopped)/ and $Detail < 10; next if $ExpandedString =~ /Driver initialized successfully\.$/ and $Detail < 10; next if $ExpandedString =~ /Network controller configured for .* link\.$/ and $Detail < 10; next if $ExpandedString =~ /Network link has been established/ and $Detail < 10; next if $ExpandedString =~ /^The driver package installation has succeeded\.$/ and $Detail < 10; next if $ExpandedString =~ /^The .* service entered the .* state/ and $Detail < 10; next if $ExpandedString =~ /^The process .* has initiated the (?:power off|restart|shutdown) of computer .* on behalf of user .* for the following reason/ and $Detail < 5; next if $ExpandedString =~ /^UVD Information$/; next if $ExpandedString =~ /Link has been established:/; # Add to the list $Systems{$System}->{"$Hostname $ExpandedString"}++; } # Handle high priority errors first my $System = "Microsoft-Windows-WER-SystemErrorReporting"; if (defined($Systems{$System})) { print "\nSYSTEM ERRORS!:\n"; foreach my $Error (sort(keys %{$Systems{$System}})) { print " $Error : $Systems{$System}->{$Error} Times\n"; } delete($Systems{$System}); } print "\n"; # Next output items marked as errors if (keys %Errors) { print "\nERRORS:"; foreach my $System (sort(keys %Errors)) { print "\n $System\n"; foreach my $Error (sort(keys %{$Errors{$System}})) { print " $Error : $Errors{$System}->{$Error} Times\n"; } } } if (keys %Systems) { foreach my $System (sort(keys %Systems)) { print "\n$System\n"; foreach my $Error (sort(keys %{$Systems{$System}})) { print " $Error : $Systems{$System}->{$Error} Times\n"; } } } if (keys %UpdatesReadyForInstall or keys %UpdatesInstalled) { print "\nWindows Update Summary:\n"; foreach my $Hostname (sort(keys %UpdatesReadyForInstall)) { # We may have removed all updates from this list when installed if (keys %{$UpdatesReadyForInstall{$Hostname}}) { print " Updates ready for install on $Hostname:\n"; foreach my $Update (sort(keys %{$UpdatesReadyForInstall{$Hostname}})) { print " $Update at $UpdatesReadyForInstall{$Hostname}->{$Update}\n"; } } } print "\n" if keys %UpdatesReadyForInstall; foreach my $Hostname (sort(keys %UpdatesInstalled)) { print " Updates successfully installed on $Hostname:\n"; foreach my $Update (@{$UpdatesInstalled{$Hostname}}) { print " $Update\n"; } } print "\n Restart required on hosts: " if keys %RestartRequired; foreach my $Hostname (sort(keys %RestartRequired)) { print "$Hostname "; } print "\n"; } exit(0); # vi: shiftwidth=3 tabstop=3 syntax=perl et # Local Variables: # mode: perl # perl-indent-level: 3 # indent-tabs-mode: nil # End: logwatch-7.12/scripts/services/saslauthd0000664000211400021140000000712114274101043020667 0ustar logwatchlogwatch ######################################################## # Please file all bug reports, patches, and feature # requests under: # https://sourceforge.net/p/logwatch/_list/tickets # and copy: # Paweł Gołaszewski # Help requests and discusion can be filed under: # https://sourceforge.net/p/logwatch/discussion/ ######################################################## ####################################################### ## Copyright (c) 2008 Paweł Gołaszewski ## Covered under the included MIT/X-Consortium License: ## http://www.opensource.org/licenses/mit-license.php ## All modifications and contributions by other persons to ## this script are assumed to have been donated to the ## Logwatch project and thus assume the above copyright ## and licensing terms. If you want to make contributions ## under your own copyright or a different license this ## must be explicitly stated in the contribution an the ## Logwatch project reserves the right to not accept such ## contributions. If you have made significant ## contributions to this script and want to claim ## copyright please contact logwatch-devel@lists.sourceforge.net. ######################################################### ######################################################## # This was written by: # Paweł Gołaszewski ######################################################## use strict; my $Detail = $ENV{'LOGWATCH_DETAIL_LEVEL'} || 0; my $Debug = $ENV{'LOGWATCH_DEBUG'} || 0; #Init Counters my $AuthFailures = 0; my $Startups = 0; my $Shutdowns = 0; #Init Array my @OtherList = (); #Init Hashes my ( %AuthFail, %AuthFailRealmCount, %AuthFailServiceCount, ); while (defined(my $ThisLine = )) { if ( ( $ThisLine =~ m/^DEBUG: / ) or ( $ThisLine =~ m/^ipc_init : listening on socket:/ ) or ( $ThisLine =~ m/^pam_sm_authenticate:/ ) or ( $ThisLine =~ m/^pam_\w+\(\w+:auth\): / ) ) { # We don't care about these } elsif ( my ($User,$Service,$Realm,$Mechanism,$Reason) = ($ThisLine =~ /^do_auth : auth failure: \[user=(.*)\] \[service=([^ ]*)\] \[realm=([^ ]*)\] \[mech=([^ ]*)\] \[reason=(.*)\]$/) ) { $AuthFailures++; $AuthFailServiceCount{"$Service ($Mechanism)"}++; $AuthFailRealmCount{"$Service ($Mechanism)"}{$Realm}++; $AuthFail{"$Service ($Mechanism)"}{$Realm}{"$User - $Reason"}++; } elsif ( $ThisLine =~ m/^detach_tty : master pid is: \d+$/) { $Startups++; } elsif ( $ThisLine =~ m/^server_exit : master exited: \d+$/) { $Shutdowns++; } else { push @OtherList,$ThisLine; } } ################################################################## if ($Startups > 0) { print "Startups: $Startups\n"; } if ($Shutdowns > 0) { print "Shutdowns: $Shutdowns\n"; } if (keys %AuthFail) { print "\nSASL Authentications failed $AuthFailures Time(s)\n"; foreach my $Service (sort {$a cmp $b} keys %AuthFail) { print "Service $Service - $AuthFailServiceCount{$Service} Time(s):\n"; foreach my $Realm (sort {$a cmp $b} keys %{$AuthFail{$Service}} ) { print " Realm $Realm - $AuthFailRealmCount{$Service}{$Realm} Time(s):\n"; foreach my $User (sort {$a cmp $b} keys %{$AuthFail{$Service}{$Realm}} ) { print " User: $User - $AuthFail{$Service}{$Realm}{$User} Time(s):\n"; } } } } if ($#OtherList >= 0) { print "\n\n**Unmatched Entries**\n\n"; print @OtherList; } exit(0); # vi: shiftwidth=3 tabstop=3 syntax=perl et # Local Variables: # mode: perl # perl-indent-level: 3 # indent-tabs-mode: nil # End: logwatch-7.12/scripts/services/citadel0000664000211400021140000016536214743365003020331 0ustar logwatchlogwatch ######################################################## # Please file all bug reports, patches, and feature # requests under: # https://sourceforge.net/p/logwatch/_list/tickets # and copy: # Stefan Jakobs # Help requests and discusion can be filed under: # https://sourceforge.net/p/logwatch/discussion/ ######################################################## ########################################################################### # This was written and is maintained by: # Stefan Jakobs # # Please send all comments, suggestions, bug reports, # etc, to logwatch at localside.net. ########################################################################### # Copyright (c) 2011 Stefan Jakobs # Covered under the included MIT/X-Consortium License: # http://www.opensource.org/licenses/mit-license.php # Permission is hereby granted, free of charge, to any person obtaining a # copy of this software and associated documentation files (the "Software"), # to deal in the Software without restriction, including without limitation # the rights to use, copy, modify, merge, publish, distribute, sublicense, # and/or sell copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. # IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY # CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ########################################################################### #use warnings; use strict; my $Detail = $ENV{'LOGWATCH_DETAIL_LEVEL'} || 0; my $Version = "0.1-20110109"; # initialize logwatch variables my $ThisLine = ""; my %OtherList = (); # initialize variables which save the stats my ($Starts,%Stops,$Reloads,$Crashs,$Upgrades); my (%Warnings); my (%RSSfeeds, %RSSerrors); my (%SMTPclientRelay, %SMTPclientStats, %SMTPclientCMDS); my (%SMTPclientDelivery, %SMTPclientBounce, %SMTPclientConnect); my ($SMTPclient_queuerun, $SMTPclient_messages, $SMTPclientBounces) = (0, 0, 0); my ($SMTPclientTime) = (0); my (%SMTPserverStats, %SMTPserverRelay, %SMTPserverCMDS); my (%SMTPserverHELO, %SMTPserverRCPT, %SMTPserverFROM); my (%SMTPserverEval, %SMTPserverAuth, %SMTPSSLError); my ($SMTPBytesAccepted, $SMTPAccepted, $SMTPRejected) = (0, 0 ,0, 0); my ($SMTPserverStatsSum) = (0); my ($serv_extnotify_queuerun) = (0); my (%Threads); my (%IMAPCmds, %IMAPexpunge, %IMAPUserLogin); my ($IMAPCompletedCmds, $IMAPCmdDuration) = (0, 0); my (%Ctdlcmds, %CtdlCleanup, %Ctdlqp_encode, %CtdlValRcpt, %CtdlMsgCorrupted); my (%CtdlReplChecks, %CtdlAddContact, %CtdlFileOp, %CtdlGenerate); my (%CtdlWriteFail); my ($CtdlMsgDeleted) = (0); my (@CtdlLogDeleted, @CtdlUserDeleted, @CtdlUserCreated, @CtdlRoomDeleted); my ($NetProcessingTime, $NetProcessingCount) = (0, 0); my (%NetStarts, %NetNodes, %NetNoConnect, %NetFilesRemoved); my (%WebClientEngine, %WebClientHost, %WebLoginFailure, %WebUserLogin); my ($SieveMsgID, $SieveName, $SieveStarts, $SieveNoProcessing); my (%SieveMsg, %SieveExecute, %SieveProcFor); my (%POPCmds, %POPClientConnects, %POPErrors, %POPUserLogin); my ($POPCompletedCmds, $POPClientStarted, $POPClientEnded) = (0, 0, 0); my ($POPClientFetched, $POPClientProcessTime) = (0, 0); my (%POPDauth, %POPDCmds); my (%SessionStarted); my (%ClamdConnects); my ($ClamdIP) = ""; # status variables my ($NetNode, $NetHost); my $Session = ""; ### Functions ### sub print_asterisks() { printf "\n ******** Details (%2i) ***************************************\n", $Detail; } sub print_line() { print " -------- --------------------------------------------------\n"; } sub print_doubleline() { print " ======== ==================================================\n\n"; } sub print_hash($$) { my $out = ""; my $sum = 0; my %hash = %{$_[0]}; my $desc = $_[1]; foreach my $item (sort {$hash{$b} <=> $hash{$a}} keys %hash) { $out .= sprintf " %8i %s\n", $hash{$item}, $item; $sum += $hash{$item}; } printf "\n %8i %-36s\n", $sum, $desc; if ($Detail > 4) { printf "$out"; } } sub print_2xhash($$) { my $out = ""; my $sum = 0; my %hash = %{$_[0]}; my $desc = $_[1]; foreach my $item (sort {$a cmp $b} keys %hash) { my $out2 = ""; my $sum2 = ""; foreach my $item2 (sort {$hash{$item}{$b} <=> $hash{$item}{$a}} keys %{$hash{$item}}) { $out2 .= sprintf " %8i %s\n", $hash{$item}{$item2}, $item2; $sum2 += $hash{$item}{$item2}; } $out .= sprintf " %8i %s\n", $sum2, $item; $sum += $sum2; if ($Detail > 9) { $out .= $out2; } } printf "\n %8i %-36s\n", $sum, $desc; if ($Detail > 4) { printf "$out"; } } sub print_3xhash($$) { my $out = ""; my $sum = 0; my %hash = %{$_[0]}; my $desc = $_[1]; foreach my $item (sort {$a cmp $b} keys %hash) { my $out2 = ""; my $sum2 = 0; foreach my $item2 (sort {$a cmp $b} keys %{$hash{$item}}) { my $out3 = ""; my $sum3 = 0; foreach my $item3 (sort {$hash{$item}{$item2}{$b} <=> $hash{$item}{$item2}{$a}} keys %{$hash{$item}{$item2}}) { ## foreach my $nr (sort {$a cmp $b} keys %{$Threads{$action}{$thread}}) { ## printf "\t\t%-40s: %5i Time(s)\n", $nr, $Threads{$action}{$thread}{$nr}; $out3 .= sprintf " %8i %s\n", $hash{$item}{$item2}{$item3}, $item3; $sum3 += $hash{$item}{$item2}{$item3}; } $out2 .= sprintf " %8i %s\n", $sum3, $item2; $sum2 += $sum3; if ($Detail > 9) { $out2 .= $out3; } } $out .= sprintf " %8i %s\n", $sum2, $item; $sum += $sum2; if ($Detail > 4) { $out .= $out2; } } printf "\n %8i %-36s\n", $sum, $desc; if ($Detail > 4) { printf "$out"; } } ### Parse the lines ### while (defined($ThisLine = )) { chomp($ThisLine); # ignore general messages if ( ($ThisLine =~ /^-- db checkpoint --$/) || ($ThisLine =~ /^\s*$/) || ($ThisLine =~ /^This program is distributed under the terms/) || ($ThisLine =~ /^Copyright \(C\) [-\d]+ by the Citadel/) || ($ThisLine =~ /^(?:Sieve: )?libSieve is written and maintained by Aaron Stone/) || ($ThisLine =~ /^(?:CC\[\d+\])?<.*> \d+ new of \d+ total messages$/) || ($ThisLine =~ /^(?:TDAP_)?AdjRefCount\(\) msg -?\d+/) || ($ThisLine =~ /^Closing the AdjRefCount queue file/) || ($ThisLine =~ /^Closing (?:-\d+ )listener on/) || ($ThisLine =~ /^Called as: /) || ($ThisLine =~ /(?:zlib| libcurl|libssh2)\/\d/) || # ($ThisLine =~ /^\[\d+\]\[.+\]/) || # this conflicts with the web stats ($ThisLine =~ /^Caught signal 15; shutting down/) || ($ThisLine =~ /^\$Id\$/) || ($ThisLine =~ /^errno is \d+$/) || ($ThisLine =~ /\[\d+\]\[\w+\(\d+\)\]\s+$/) ) { # ignore these lines } ### Start, Stop, Reload ### elsif ($ThisLine =~ /^\*\*\* Citadel server engine/) { $Starts++; } #TD: citserver: Exiting with status 15 elsif ($ThisLine =~ /^citserver: Exiting with status (\d+)$/) { $Stops{$1}++; } #TD: Posting crash message elsif ($ThisLine =~ /^Posting crash message$/) { $Crashs++; } #TD: upgrade elsif ($ThisLine =~ /^upgrade$/) { $Upgrades++; } ### Warnings (message) (reason) #TD: unable to change into directory [/var/run/citadel/]: No such file or directory elsif ($ThisLine =~ /^unable to change into directory \[(.*)\]: (.*)$/) { $Warnings{$2}{$1}++; } #TD: citserver: unable to lock /var/lib/citadel/data/citadel.control. elsif ($ThisLine =~ /^citserver: (unable to lock .+)\.$/ ) { $Warnings{$1}{""}++ } #TD: Is another citserver already running? elsif ($ThisLine =~ /^(Is another citserver already running\?)$/ ) { $Warnings{$1}{""}++; } #TD: This message has a zero length. Probable data corruption. elsif ($ThisLine =~ /^(This message has a zero length)\. {1,2}(Probable data corruption)\.$/) { $Warnings{$2}{$1}++; } #TD: pthread_create() : Cannot allocate memory elsif ($ThisLine =~ /^pthread_create\(\) : (Cannot allocate memory)$/) { $Warnings{$1}{""}++; } ### Thread processing ### elsif ( ($ThisLine =~ /^\S+_thread\(\) exiting/) || ($ThisLine =~ /^Garbage collection on own thread/) || ($ThisLine =~ /^Startup thread \d+ becoming garbage collector/) || ($ThisLine =~ /^Interrupted CtdlThreadSelect/) ) { # ignore lines } elsif ($ThisLine =~ /^(?:Thread|Created a new thread|Garbage Collection for thread|Waiting for thread)/) { if ( ($ThisLine =~ /^Thread system stopping thread/) || ($ThisLine =~ /^Waiting for thread/) || ($ThisLine =~ /^Thread .* caught signal/) ) { # ignore these lines } #TD: Created a new thread "SMTP Send" (0x40504950). elsif ($ThisLine =~ /Created a new thread "(.+)" \(([x0-9a-fA-F]+)\)/) { $Threads{"created"}{$1}{$2}++; } #TD: Thread "SMTP Send" (0x40504950) exited. #TD: Thread "RSS Client" (0x40605950) exited. elsif ($ThisLine =~ /^Thread "(.+)" \(([x0-9a-fA-F]+)\) exited/) { $Threads{"exited"}{$1}{$2}++; } #TD: Garbage Collection for thread "RSS Client" (0x40605950). elsif ($ThisLine =~ /^Garbage Collection for thread "(.+)" \(([x0-9a-fA-F]+)\)/) { $Threads{"garbage collection"}{$1}{$2}++; } else { # Report any unmatched entries... chomp($ThisLine); $OtherList{$ThisLine}++; } } ### Sessions ### elsif ( ($ThisLine =~ /^\[[ \d]+\] Session ended/) || ($ThisLine =~ /^Context: \[[ \d]+\]SRV\[(?:citadel-(?:TCP|UDS)|CitNetworker|rssclient|POP1aggr|POP3|POP3S|DICT_TCP|IMAP|IMAPS|LMTP|SMTP_Send|SMTP-MSA)\] Session ended/) || ($ThisLine =~ /^C(?:itadel c)?lient disconnected: ending session\.$/) || ($ThisLine =~ /^New client socket \d+$/) || ($ThisLine =~ /^Terminated \d+ idle sessions$/) || ($ThisLine =~ /^Context: Scheduled \d+ idle sessions for termination$/) || ($ThisLine =~ /^Context: Flushed \d+ stuck sessions$/) || ($ThisLine =~ /^Context: terminate_all_sessions\(\) is murdering/) || ($ThisLine =~ /^(Modules: )?\[(?:citadel-TCP|DICT_TCP)\] closing service$/) ) { # ignore these lines } #TD: Session (IMAPS) started from myhost (192.168.36.150) #TD: Session (citadel-TCP) started from localhost.localdomain (127.0.0.1). #TD: Session (LMTP) started via local socket UID:101. elsif ($ThisLine =~ /^Session \(([\w-]+)\) started (?:from (\S+) \(([\da-fA-F.:]+)\)|via (local socket) (UID:-?\d+))/) { $SessionStarted{$1}{"$2$4 [$3$5]"}++; $Session = "$1"; } ### RSS feed processing ### elsif ( ($ThisLine =~ /^\S+ has already been seen/) || ($ThisLine =~ /^RSS: XML Status \[\(null\)\]/) || ($ThisLine =~ /^RSS: This is an (?:RSS|RDF) feed/) || ($ThisLine =~ /^RSS: saving item/) || ($ThisLine =~ /^rssclient (?:started|ended)/) ) { # ignore these lines } #TD: Fetching RSS feed elsif ($ThisLine =~ /Fetching RSS feed <(\S+)>/) { $RSSfeeds{$1}++; } #TD: IO[968]CC[968][72]RSSPneed a 200, got a 302 ! elsif ($ThisLine =~ /^IO\[[ \d]+\]CC\[[ \d]+\]\[\d+\](RSS.?need a \d+, got a \d+)/) { $RSSerrors{"$1 (libcurl too old?)"}++; } ### serv_something processing ### elsif ($ThisLine =~ /^serv_extnotify: queue run completed/) { # ignore these lines } elsif ($ThisLine =~ /^serv_extnotify: processing notify queue/) { $serv_extnotify_queuerun++; } ### SMTP Client ### elsif ( ($ThisLine =~ /^SMTP(?:CQ| client): processing outbound queue/) || ($ThisLine =~ /^SMTP client: smtp_do_procmsg\(\d+\)$/) || ($ThisLine =~ /^SMTP(?:C| client): Trying <.*>/) || ($ThisLine =~ /^SMTP client: Attempting delivery to /) || ($ThisLine =~ /^SMTP client: connected!/) || ($ThisLine =~ /Number of MX hosts for /) || ($ThisLine =~ /^ addr=<.*> status=\d+ dsn=<.*>$/) || ($ThisLine =~ /^Done processing bounces$/) || ($ThisLine =~ /^SMTPCQ: Msg No \d+: already in progress!$/) ) { # ignore these lines } #TD: SMTP client: connecting to localhost : 25 ... #TD: SMTPC:IO[1025]CC[1025]S[198261][0] connecting to localhost [127.0.0.1]:25 ... elsif ($ThisLine =~ /^SMTP(?:C| client):(?:IO\[[ \d]+\]CC\[\d+\]S\[\d+\]\[\d+\])? connecting to (\S+) (?:\[[\.:\da-fA-F]*\])?: ?(\d+)/) { $SMTPclientConnect{"$1:$2"}++; } #TD: >EHLO valaskjalf.localside.net #TD: >MAIL FROM: #TD: >QUIT elsif ($ThisLine =~ /^>([A-Z ]+)(?::<(.+)>)?/) { $SMTPclientCMDS{$1}{$2}++; } #TD: SMTP client: delivery to @ (user) succeeded elsif ($ThisLine =~ /SMTP client: delivery to <(.*)> @ <(.*)> \(.*\) (\w+)$/) { $SMTPclientDelivery{$3}{$2}{$1}++; } #TD: SMTPC:IO[1025]CC[1025]S[198261][0] Delivery successful. Time[19.466858s] Recipient @ (name) Status message: 2.0.0 from MTA(smtp:[127.0.0.1]:10025): 250 2.0.0 Ok: queued as A61BE66B8008 elsif ($ThisLine =~ /^SMTPC:IO\[[ \d]+\]CC\[\d+\]S\[\d+\]\[\d+\] Delivery ([^.]+)\. Time\[([\d\.]+)s\] Recipient <(.*)> @ <(.*)> \(.*\) Status message: ([\d\.]{3,5}|[\s\w]+)/) { $SMTPclientDelivery{$1}{$4}{$3}++; $SMTPclientStats{$5}++; $SMTPclientTime+=$2; } #TD: 108319: to=, relay=localhost, stat=2.0.0 Ok, id=10168-06, from MTA([127.0.0.1]:10025): 250 2.0.0 Ok: queued as 2901498D0082 elsif ($ThisLine =~ /^\d+: to=<(.*)>, relay=(\S*), stat=([\d\.]{3,5}.*?),/) { if ($2 != "") { $SMTPclientRelay{$2}{$1}++; } $SMTPclientStats{$3}++; } #TD: key= addr= status=0 dsn=<> elsif ($ThisLine =~ /^key= addr=<(.*)> status=(\d+) dsn=<(.*)>$/) { $SMTPclientBounce{$1}{"$2: $3"}++; } #TD: num_bounces = 0 elsif ($ThisLine =~ /^num_bounces = (\d+)$/) { $SMTPclientBounces += $1; } #TD: SMTPCQ: queue run completed; 1 messages processed 1 activated elsif ($ThisLine =~ /^(?:SMTPCQ|SMTP client): queue run completed; (\d+) messages processed/) { $SMTPclient_queuerun++; $SMTPclient_messages += $1; } ### SMTP Server ### elsif ( ($ThisLine =~ /^Directory key is <.*>$/) || ($ThisLine =~ /is being forwarded to/) || ($ThisLine =~ /^[:\[] get \S*\]?$/) || ($ThisLine =~ /^<\d{3}[ -]\w+/) || ($ThisLine =~ /^SSL\/TLS using /) || ($ThisLine =~ /Ending SSL\/TLS$/) || ($ThisLine =~ /^(?:Performing|Finished) SMTP cleanup hook$/) || ($ThisLine =~ /^SMTP module clean up for shutdown/) || ($ThisLine =~ /^(Modules: )?\[LMTP(?:-UnF)?\] Closed UNIX domain socket/) || ($ThisLine =~ /^(Modules: )?\[SMTPs?-(?:MTA|MSA)\] closing service$/) || ($ThisLine =~ /^SMTP: client disconnected: ending session\.$/) || ($ThisLine =~ /^sending \d+ [A-Z]+ for the room/) # this belongs to validate_recipients() ) { # ignore these lines } elsif ($ThisLine =~ /^SMTP server:/) { #TD: SMTP server: LHLO vs243073.vserver.de if ($ThisLine =~ /^SMTP server: (?:LHLO|HELO|EHLO) (\S+)/i) { $SMTPserverHELO{$1}++; } #TD: SMTP server: RCPT TO: elsif ($ThisLine =~ /^SMTP server: RCPT TO: *]+)>?$/i) { $SMTPserverRCPT{$1}++; } #TD: SMTP server: MAIL FROM: SIZE=2982 BODY=7BIT elsif ($ThisLine =~ /^SMTP server: MAIL FROM: *]*)>?(?: SIZE=(\d+))?/i) { $SMTPserverFROM{$1}++; $SMTPBytesAccepted += $2; } #TD: SMTP server: DATA elsif ($ThisLine =~ /^SMTP server: (DATA|QUIT|STARTTLS|AUTH PLAIN|RSET)/i) { $SMTPserverCMDS{$1}++; } else { # Report any unmatched entries... chomp($ThisLine); $OtherList{$ThisLine}++; } } #TD: SMTP authenticated Stefan elsif ($ThisLine =~ /^SMTP authenticated (.*)$/) { $SMTPserverAuth{$1}++; } #TD: 108347: from=, nrcpts=1, relay= [], stat=250 Message accepted elsif ($ThisLine =~ /^\d+: from=<(.*)>, nrcpts=(\d+), relay=(.*) \[(\S*)\], stat=(\d{3})(.*)\./) { ## $SMTPserverNumRCPTs += $2; if ($4 != "") { $SMTPserverRelay{"$4 ($3)"}{$1}++; } $SMTPserverStats{$5}{$6}++; $SMTPserverStatsSum++; if ($5 =~ /^2\d\d$/) { $SMTPAccepted++; } if ($5 =~ /^[45]\d\d$/) { $SMTPRejected++; } } #TD: Evaluating recipient #0: stefan@localside.net elsif ($ThisLine =~ /^Evaluating recipient #\d+: (?:.*<)?([^\s<>]+)>?$/) { $SMTPserverEval{$1}++; } #TD: SSL_read got error 5 #TD: SSL_accept failed: retval=0, errval=5, err=error:00000005:lib(0):func(0):DH lib elsif ($ThisLine =~ /^SSL_(\S+) (?:got error |failed: retval=[-0-9]+, errval=)(\d+)/) { $SMTPSSLError{$1}{$2}++; } ### IMAP processing ### elsif ( ($ThisLine =~ /^\(That translates to/) || ($ThisLine =~ /^imap_do_expunge\(\) called/) || ($ThisLine =~ /^[\w ]+ already exists\.$/) || ($ThisLine =~ /^(?:before| after) update:/) || ($ThisLine =~ /^(?:Performing|Finished) IMAP cleanup hook$/) || ($ThisLine =~ /^Section is: \[.*\]/) || ($ThisLine =~ /^Converting CRLF to LF$/) || ($ThisLine =~ /^IMAP(?:CC\[[ \d]+\]|:) client disconnected: ending session/) || ($ThisLine =~ /^(Modules: )?\[IMAPS?\] closing service$/) ) { # ignore these lines } elsif ($ThisLine =~ /^IMAP/) { if ( ($ThisLine =~ /^IMAP(?:CC\[[ \d]+\]|:) $/) || ($ThisLine =~ /^IMAPCC\[[ \d]+\] not subordinate to inbox$/) ) { # ignore these lines } # improve: IMAPCmdDuration per Command. #TD: IMAP command completed in 0.1437 seconds elsif ($ThisLine =~ /^IMAP command completed in (\d+\.\d+) seconds/) { $IMAPCompletedCmds++; $IMAPCmdDuration += $1; } #TD: IMAP: 10117 NOOP #TD: IMAP: 10120 LIST "" "Server Level/%" #TD: IMAP: a003 LOGOUT elsif ($ThisLine =~ /^IMAP: \w?\d+ ([A-Z ]+)/) { $IMAPCmds{$1}++; } #TD: IMAP: LOGIN... #TD: IMAPCC[51121] LOGIN... elsif ($ThisLine =~ /^IMAP(?:CC\[[ \d]+\]|:) (LOGIN)/) { $IMAPCmds{$1}++; } else { # Report any unmatched entries... chomp($ThisLine); $OtherList{$ThisLine}++; } } #TD: logged in #TD: Context: logged in elsif ($ThisLine =~ /^(?:Context: )?<(.+)> logged in$/) { # this can be a POP or IMAP login my $user = lc($1); if ($Session =~ /^IMAPS?$/) { $IMAPUserLogin{$user}++; } elsif ($Session =~ /^POPS?/) { $POPUserLogin{$user}++; } elsif ($Session =~ /^(?:citadel-TCP|LMTP)$/) { #ignore } else { chomp($ThisLine); $OtherList{$ThisLine}++; } # $Session = ""; ## this may be wrong } #TD: Expunged 0 messages from elsif ($ThisLine =~ /^Expunged (\d+) messages from <(.+)>/) { if ($1 > 0) { $IMAPexpunge{$2} += $1; } } ### Citadel internal processing ### elsif ( ($ThisLine =~ /^Selected room/) || ($ThisLine =~ /^Performing before-save hooks$/) || ($ThisLine =~ /^Skipping hooks$/) || ($ThisLine =~ /^Saving to disk$/) || ($ThisLine =~ /^Creating MetaData record$/) || ($ThisLine =~ /^Storing pointers$/) || ($ThisLine =~ /^Updating user$/) || ($ThisLine =~ /^\d+ unique messages to be merged$/) || ($ThisLine =~ /^Performing room hooks for <.+>$/) || ($ThisLine =~ /^Performing after-save hooks$/) || ($ThisLine =~ /^Wordbreaking message \d+/) || ($ThisLine =~ /^Purge use table: /) || ($ThisLine =~ /^Purge (?:euid|EUID) index: /) || ($ThisLine =~ /^dead_session_purge\(\): purging session/) || ($ThisLine =~ /^RemoveContext\([\w-]+\) session/) || ($ThisLine =~ /^---- Looking up \[[A-Z]+\] -----$/) || ($ThisLine =~ /^(?:CC\[[ \d]+\])?Changed to <.*>$/) || ($ThisLine =~ /^do_fulltext_indexing\(\)/) || ($ThisLine =~ /^Indexed \d+ of \d+ messages/) || ($ThisLine =~ /^ft_index_message\(\) (?:adding|removing) msg/) || ($ThisLine =~ /^fixed_output(?:_pre|_post)?\(\) (?:part|type)/) || ($ThisLine =~ /^Skipping part \d+/) || ($ThisLine =~ /^Indexing message \d+ \[\d+ tokens\]/) || ($ThisLine =~ /^Indexing message #\d+ <.*>/) || ($ThisLine =~ /^Flush(?:ing|ed) index cache to disk/) || ($ThisLine =~ /^Delivering to room <.*>$/) || ($ThisLine =~ /^Returning to original room/) || ($ThisLine =~ /^(?:Context: )?User \d+ maps to/) || ($ThisLine =~ /^Auto-purger: (?:starting|finished)/) || ($ThisLine =~ /^Auto purger found a user \d+ with name <.*>$/) || ($ThisLine =~ /^Delivering private local mail to <.*>$/) || ($ThisLine =~ /^(?:CC\[[ \d]+\])?Final selection: /) || ($ThisLine =~ /^Processed \d+ message reference count adjustments/) || ($ThisLine =~ /^Generating delivery instructions$/) || ($ThisLine =~ /^Initializing (?:server extensions|ipgm secret)/) || ($ThisLine =~ /^Seeding the pseudo-random number generator/) || ($ThisLine =~ /^Registered (?:server command|a new .+ function)/) || ($ThisLine =~ /^Creating base rooms/) || ($ThisLine =~ /^Floor \d{1,3}: \d+ rooms/) || ($ThisLine =~ /^Server-hosted upgrade level is/) || ### report this as status ??? ($ThisLine =~ /^(?:Sieve: )?Extensions:/) || ($ThisLine =~ /registered\.$/) || ($ThisLine =~ /^Initiali(?:s|z)e modules, /) || ($ThisLine =~ /(?:_thread|startup|databases)\(\) (?:initializing|finished|started)/) || ($ThisLine =~ /^(?:Modules: )?Service \S+ has been manually disabled, skipping/) || ($ThisLine =~ /^Checking floor reference counts$/) || ($ThisLine =~ /^Changing uid to \d+$/) || ### report these files ??? ($ThisLine =~ /^Loading (?:citadel.config|\S+\/public_clients)$/) || ($ThisLine =~ /^Checking\/re-building control record$/) || ($ThisLine =~ /^Acquiring control record$/) || ($ThisLine =~ /^Path is /) || ($ThisLine =~ /^Cleaning up fulltext noise words\.$/) || ($ThisLine =~ /^Saving calendar UID <\S+>$/) || ($ThisLine =~ /^Raw length is \d+$/) || ($ThisLine =~ /^Allocating$/) || ($ThisLine =~ /Server hosted updates need to be processed at this time/) || ($ThisLine =~ /^User (?:0|-\d+) not found$/) || ($ThisLine =~ /^Deleted \d+ other msgs of this type$/) || ($ThisLine =~ /^diff length is \d+ bytes$/) || ($ThisLine =~ /^diff cmd/) || ($ThisLine =~ /^History page not being historied$/) || ($ThisLine =~ /^UID of vNote is: [0-9a-f-]+$/) || ($ThisLine =~ /^Part \d+ contains a vNote/) || ($ThisLine =~ /^\.\.\. yes its local\.$/) || ($ThisLine =~ /^Loaded module: /) || ($ThisLine =~ /^Waiting \d+ seconds for \d+ worker threads to exit$/) || ($ThisLine =~ /^Existing database version on disk is/) || ($ThisLine =~ /^Upgrad(?:ing|e) modules/) || ($ThisLine =~ /^Modules: (?:upgrade|Upgrade modules|Destroyed service)/) || ### report this as warning ??? ($ThisLine =~ /^Modules: Initializing\. CtdlThreads not yet enabled\.$/) || ($ThisLine =~ /^libcitadel\(unnumbered\)$/) || ($ThisLine =~ /^(Modules: )?\[citadel-UDS\] Closed UNIX domain socket/) || ($ThisLine =~ /^Found\.$/) || ($ThisLine =~ /^No external notifiers configured on system\/user$/) ) { # ignore these lines } #TD: validate_recipients() #TD: local: 1 #TD: room: 0 <> #TD: inet: 0 <> #TD: ignet: 0 <> #TD: error: -1 elsif ($ThisLine =~ /^(validate_recipients)\(\)$/) { $Ctdlcmds{$1}++; } elsif ($ThisLine =~ /^\s{1,2}(local|room|inet|ignet|error): -?(\d+) <(.*)>$/) { if ($2 > 0) { $CtdlValRcpt{$1}{$3} += $2; } } #TD: Deleting message <103425> elsif ($ThisLine =~ /Deleting message <(\d+)>$/) { $CtdlMsgDeleted++; } #TD: 7 message(s) deleted. elsif ($ThisLine =~ /(\d+) message\(s\) deleted\.$/) { # This belongs to CtdlDeleteMessages if ($1 > 0) { $CtdlMsgDeleted += $1; } } #TD: Expired 147 messages. #TD: Expired 0 rooms. #TD: Purged 0 visits. elsif ($ThisLine =~ /^(Expired|Purged) (\d+) (messages|rooms|visits|users|entries from the EUID index|stale OpenID associations|entries from the use table)/) { $CtdlCleanup{$1}{$3} += $2; } #TD: Context: New user created elsif ($ThisLine =~ /^(?:Context: )?New user <(.*)> created$/) { push(@CtdlUserCreated, $1); } #TD: Deleting log: /var/lib/citadel/data/log.0000004270 elsif ($ThisLine =~ /Deleting log: (.*)$/) { push(@CtdlLogDeleted, $1); } #TD: Deleting user #TD: Context: Deleting user elsif ($ThisLine =~ /^(?:Context: )?Deleting user <(.*)>$/) { push(@CtdlUserDeleted, $1); } #TD: Deleting room <00000000033.Tasks> elsif ($ThisLine =~ /^(?:Context: )?Deleting room <(.*)>$/) { push(@CtdlRoomDeleted, $1); } #TD: PurgeMessages() called elsif ($ThisLine =~ /(Purge(?:Messages|Rooms|Users))\(\) called$/) { $Ctdlcmds{$1}++; } #TD: qp_encode_email_addrs: [postfix-users@postfix.org] elsif ($ThisLine =~ /qp_encode_email_addrs: \[(.+)\]$/) { $Ctdlqp_encode{$1}++; } #TD: Message 0 appears to be corrupted elsif ($ThisLine =~ /Message (\d+) appears to be corrupted/) { $CtdlMsgCorrupted{$1}++; } #TD: Performing replication checks in elsif ($ThisLine =~ /Performing replication checks in <(.+)>$/) { $CtdlReplChecks{$1}{$2}++; } #TD: Adding contact: "Full Name" elsif ($ThisLine =~ /Adding contact: (.*)$/) { $CtdlAddContact{$1}++; } elsif ($ThisLine =~ /^Ctdl/) { if ($ThisLine =~ /^$/) { # ignore these lines } # ToDo: This can be done better #TD: CtdlFetchMessage(108265, 1) #TD: CtdlOutputPreLoadedMsg(TheMessage=not null, 1, 0, 0, 1 #TD: CtdlDeleteMessages(SpamAssassin-user, 1 msgs, ) #TD: CtdlCreateRoom(name=Contacts, type=4, view=2) # Contacts already exists. elsif ($ThisLine =~ /^Ctdl(\w+)\(/) { $Ctdlcmds{$1}++; } } #TD: chmod(/srv/citadel/data//cdb.03, 0600) returned 0 #TD: chown(/var/lib/citadel/data//cdb.08, CTDLUID, -1) returned 0 elsif ($ThisLine =~ /^(chown|chmod)\((.*), [A-Z0-9]+(?:, -?\d+)?\) returned (\d+)/) { $CtdlFileOp{$1}{$2}++; } #TD: Generating a self-signed certificate. #TD: Generating RSA key pair. elsif ($ThisLine =~ /^Generating(?: a)? (.+)\.$/ ) { $CtdlGenerate{$1}++; } #TD: client_write(13 bytes) failed: Broken pipe (32) elsif ($ThisLine =~ /^client_write\((\d+) bytes\) failed: (.+)$/) { $CtdlWriteFail{$2} += $1; } ### IGnet Networking ### elsif ( ($ThisLine =~ /^network: (?:running|loading) outbound queue$/) || ($ThisLine =~ /^network: (?:nothing in|processing) inbound queue/) || ($ThisLine =~ /^network: queue run completed/) || ($ThisLine =~ /^network: polling/) || ($ThisLine =~ /^NW\[\w*\]\[\d+\]: polling/) || ($ThisLine =~ /^>[0-9]{3} \w* (?:Citadel|as network|talking to)/) || ($ThisLine =~ /^nttlist= to <\S+>$/) || ($ThisLine =~ /^network_process_buffer\(\) processing \d+ bytes$/) || ($ThisLine =~ /^Expecting to transfer \d+ bytes$/) || ($ThisLine =~ /^network_usetable\(\) : /) || ($ThisLine =~ /^(?:CC\[[ \d]+\])?(?:Not )?(?:s|S)ending to \S+$/) || ($ThisLine =~ /^(?:Appending to|Consolidate) \//) || ($ThisLine =~ /^(?:CC\[[ \d]+\])?Invalid node (?:name )?<\S+>$/) || ($ThisLine =~ /^(?:CC\[[ \d]+\])?skipping Spoolcleanup because of \d+ files unprocessed\.$/) ) { # ignore these lines } #TD: Networking started for <0000000007.Mail> elsif ($ThisLine =~ /^Networking started for <(.+)>$/) { $NetStarts{$1}++; } #TD: Network full processing in 1021 seconds. elsif ($ThisLine =~ /^Network full processing in (\d+) seconds/) { $NetProcessingCount++; $NetProcessingTime += $1; } #TD: Network node logged in from example.com [10.0.0.1] elsif ($ThisLine =~ /^Network node <(.+)> logged in from (.*)/) { $NetNodes{"Logins from"}{$1}{$2}++; } #TD: Connecting to at example.com:504 #TD: IO[13221]CC[13221]NW[genux][8624]Connecting to at example.com:504 elsif ($ThisLine =~ /^(?:IO\[\d+\]CC\[\d+\]NW\[\w+\]\[\d+\])?Connecting to <(.+)> at (.*)/) { $NetNodes{"Connects to"}{$1}{$2}++; $NetNode=$1; $NetHost=$2; } #TD: Sent 0 octets to #TD: IO[49977]CC[49977]NW[valaskjalf][49972]Sent 0 octets to elsif ($ThisLine =~ /^(?:IO\[\d+\]CC\[\d+\]NW\[\w+\]\[\d+\])?Sent (\d+) octets to <(.+)>/) { $NetNodes{"Bytes sent to"}{$2}{""} += $1; } #TD: Can't connect to example.com:504: Connection timed out elsif ($ThisLine =~ /^Can't connect to (.+): (.+)$/) { $NetNoConnect{"Can't connect to"}{$1}{$2}++; } #TD: connect() failed: Connection timed out elsif ($ThisLine =~ /^connect\(\) failed: Connection timed out$/) { $NetNoConnect{"Can't connect to"}{$NetNode}{$NetHost}++; } #TD: Can't get example.com host entry: Connection timed out elsif ($ThisLine =~ /^Can't get (.+) host entry: (.+)$/) { $NetNoConnect{"Can't get host entry"}{$1}{$2}++; } #TD: EVCURL:IO[4515]CC[4515] error description: Failed to connect to 2a00:1450:8005::79: Network is unreachable elsif ($ThisLine =~ /^EVCURL:IO\[[ \d]+\]CC\[\d+\] error description: (Failed (?:to )?connect to) (.*)(?::|;) (.*)/) { $NetNoConnect{"$3"}{$1}{$2}++; $NetNode=$1; $NetHost=$2; } #TD: EVCURL:IO[4515]CC[4515] error description: Recv failure: Connection reset by peer #TD: EVCURL:IO[2152]CC[2752] error description: The requested URL returned error: 404 elsif ($ThisLine =~ /^EVCURL:IO\[[ \d]+\]CC\[\d+\] error description: (Recv failure: |Couldn't resolve host |Empty reply from server|The requested URL returned error: )(.*)/) { $NetNoConnect{"$2"}{"$1"}{""}++; } #TD: EVCURL:IO[4515]CC[4515] error performing request: Couldn't connect to server elsif ($ThisLine =~ /^EVCURL:IO\[[ \d]+\]CC\[\d+\] error performing request: (.*)/) { $NetNoConnect{"$1"}{$NetNode}{$NetHost}++; # That isn't correct !!! } #TD: network: processing 0 bytes from /var/spool/citadel/network/spoolin//genux.0e73.012a #TD: CC[0]network: processing 426944 bytes from /var/spool/citadel/network/spoolin//wk.64c1.000a elsif ($ThisLine =~ /^(?:CC\[[ \d]+\])?network: processing (\d+) bytes from \/\S+\/spool\/citadel\/network\/spoolin\/+(\w+)\.[\.0-9a-f]+$/) { $NetNodes{"Bytes download from"}{$2}{""} += $1 } #TD: Duplicate session for network node elsif ($ThisLine =~ /^Duplicate session for network node <(\S+)>$/) { $NetNodes{"Duplicate session"}{$1}{""}++; } #TD: IO[50917]CC[50917]NW[wk][31235]Already talking to wk; skipping this time. elsif ($ThisLine =~ /^IO\[[ \d]+\]CC\[\d+\]NW\[(\w+)\]\[\d+\]Already talking to \w+; skipping this time\.$/) { $NetNodes{"Already talking to"}{$1}{""}++; } #TD: Removing elsif ($ThisLine =~ /^Removing <(\S+)>$/) { $NetFilesRemoved{$1}++; } #TD: >540 authentication failed elsif ($ThisLine =~ /^>5\d\d authentication failed$/) { $NetNodes{"Authentication failed to"}{$NetNode}{$NetHost}++; } #TD: An unknown Citadel server called "node" attempted to connect from name [1.1.1.1]. elsif ($ThisLine =~ /^An unknown Citadel server called "(\S*)" attempted to connect from (\S*) \[(\S+)\]/) { $NetNodes{"Attempted connects"}{$1}{"$2 [$3]"}++; } #TD: Connected to node "" but I was expecting to connect to node "node". elsif ($ThisLine =~ /^Connected to node "(\S*)" but I was expecting to connect to node "(\S*)"/) { $NetNodes{"Connects to server with wrong node name"}{"$2 (as $1)"}{""}++; } #TD: A Citadel server at example.com [10.0.0.1] failed to authenticate as network node "node". elsif ($ThisLine =~ /A Citadel server at (\S+) \[(\S+)\] failed to authenticate as network node "(\S*)"/) { $NetNodes{"Authentication failed from"}{$3}{"$1 [$2]"}++; } ### web access ### elsif ( ($ThisLine =~ /^New client socket \d+/) || ($ThisLine =~ /^Closing socket -?\d+/) || ($ThisLine =~ /^Checking whether [0-9a-fA-F:.]+ is a local or public client/) || ($ThisLine =~ /^\.\.\. yes it is/) || ($ThisLine =~ /^Looking up hostname '/) || ($ThisLine =~ /^Client \d\/\d\/[\d.]+ \(.*\)/) || ($ThisLine =~ /^(?:\[\d+\]\[.*\] )?

: doveadm: ::1 - - "POST /doveadm/v1 HTTP/1.1" 200 249 "http://localhost:8080/doveadm/v1" "" # IGNORE # Dovecot 2.0 proxy } elsif ( ($User, $Host) = ( $ThisLine =~ /^$dovecottag pop3-login: proxy\((.*)\): started proxying to .*: user=<.*>, method=.*, rip=(.*), lip=/ ) ) { if ($Host !~ /$IgnoreHost/) { $ProxyLogin{$User}{$Host}++; $ProxyLoginPOP3{$User}++; $ProxyConnectionPOP3{$Host}++; $ProxyConnection{$Host}++; } } elsif ( ($User, $Host) = ( $ThisLine =~ /^$dovecottag imap-login: proxy\((.*)\): started proxying to .*: user=<.*>, method=.*, rip=(.*), lip=/ ) ) { if ($Host !~ /$IgnoreHost/) { $ProxyLogin{$User}{$Host}++; $ProxyLoginIMAP{$User}++; $ProxyConnectionIMAP{$Host}++; $ProxyConnection{$Host}++; } } elsif ( ($Reason) = ( $ThisLine =~ /proxy\(.*\): disconnecting .* \(Disconnected (.*)\)/ ) ) { $ProxyDisconnected{$Reason}++; } elsif ($ThisLine =~ /Disconnected (\[|bytes|top)/) { $Disconnected{"No reason"}++; # Oct 24 14:10:24 host dovecot[114]: imap-login: Disconnected: Connection closed (auth failed, 1 attempts in 2 secs): user=, method=PLAIN, rip=192.168.1.110, lip=192.168.1.3, TLS, session= } elsif ( ($User, $IP) = ($ThisLine =~ /Disconnected: .* \(auth failed, .*\): user=<([^>]+)>,.*rip=([^,]+).*/) ) { $AuthFail{$User}{$IP}++; } elsif ( ($Reason) = ($ThisLine =~ /Disconnected: (.*) \[/) ) { $Disconnected{$Reason}++; } elsif ( ($Reason) = ($ThisLine =~ /Disconnected: (.*) (bytes|top|in)=.*/) ) { $Disconnected{$Reason}++; } elsif ($ThisLine =~ /Logged out (rcvd|bytes|top|in)=.*/) { $Disconnected{"Logged out"}++; } elsif ( ($Reason) = ($ThisLine =~ /Disconnected(?:: Inactivity.*)? \((.*)\):/) ) { $Reason =~ s/ in \d+ secs//; $Reason =~ s/, waited \d+ secs//; $Disconnected{$Reason}++; } elsif ($ThisLine =~ /Server shutting down./) { $ConnectionClosed{"Server shutting down"}++; } elsif ( ($Reason, $Host) = ($ThisLine =~ /TLS initialization failed/) ) { $TLSInitFail++; } elsif ( ($Host) = ($ThisLine =~ /Aborted login:.* rip=(.*),/) ) { $Host = hostName($Host); $Aborted{$Host}++; } elsif ( ($Host) = ($ThisLine =~ /Aborted login \[(.*)\]/) ) { $Host = hostName($Host); $Aborted{$Host}++; } elsif ( ($Reason) = ($ThisLine =~ /Aborted login \((.*)\):/)) { $Aborted{$Reason}++; } elsif ( ($User,$IP) = ($ThisLine =~ /auth: (?:LOGIN|login)\((.*),(\d+\.\d+\.\d+\.\d+)\): Request timed out waiting for client to continue authentication/) ) { $AuthTimedOut{$User}{$IP}++; } elsif ( ($Reason) = ($ThisLine =~ /auth: Warning: auth client \d+ disconnected with \d+ pending requests: (.*)/) ) { $AuthDisconnectedWithPending{$Reason}++; } elsif ( ($IP) = ($ThisLine =~ /auth: login\(.*,(\d+\.\d+\.\d+\.\d+)\): Username character disallowed by auth_username_chars: .* \(username: .*\)/) ) { $AuthUsernameChars{$IP}++; } elsif ( ($user, $rip, $lip) = ($ThisLine =~ /Maximum number of connections.* exceeded.* user=<([^>]+)>.*rip=([^,]+), lip=([^,]+)/)) { # dovecot: [ID 583609 mail.info] imap-login: Maximum number of connections from user+IP exceeded (mail_max_userip_connections=10): user=, method=CRAM-MD5, rip=102.225.17.52, lip=14.105.322.67, TLS $LimitExceeded{"max_userip_connections: $user from $rip to $lip"}++; # This is for Dovecot 1.0 series # Overly general matches in this section -mgt } elsif ($ThisLine =~ /Disconnected for inactivity/) { $Disconnected{"Inactivity"}++; } elsif ($ThisLine =~ /Disconnected in IDLE/) { $Disconnected{"in IDLE"}++; } elsif ($ThisLine =~ /Disconnected in APPEND/) { $Disconnected{"in APPEND"}++; } elsif (($ThisLine =~ /Disconnected$/) or ($ThisLine =~ /(IMAP|POP3)\(.+\): Disconnected (bytes|top|rip|user|method)=/) or ($ThisLine =~ /(imap\-login|pop3\-login): Disconnected: (bytes|top|rip|user|method)=/) ) { $Disconnected{"No reason"}++; } elsif ( ( ($Reason) = ($ThisLine =~ /(?:IMAP|POP3).+: Disconnected: (.+) (bytes|top)=/i)) or ( ($Reason) = ($ThisLine =~ /(?:imap\-login|pop3\-login): Disconnected: \(?(.+)\)?: /)) or #This one should go away also -mgt ( ($Reason) = ($ThisLine =~ /IMAP.+: Disconnected: (.+)/i)) ) { $Disconnected{$Reason}++; } elsif ($ThisLine =~ /(IMAP|POP3).+: Connection closed (top|bytes)=/i) { $ConnectionClosed{"No reason"}++; } elsif ( ($Reason) = ($ThisLine =~ /(?:IMAP|POP3).+: Connection closed: (.*) (?:bytes|method|top|rip|user)=/i) ) { $ConnectionClosed{$Reason}++; } elsif ($ThisLine =~ /(IMAP|POP3).+: (Connection closed.*)/) { $Disconnected{$2}++; } elsif ( ($Host) = ($ThisLine =~ /(?:imap\-login|pop3\-login): Aborted login: .*rip=(?:::ffff:)?(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})/) ) { $Aborted{$Host}++; } elsif ( ($Error) = ($ThisLine =~ /child \d* (?:\(login\) )?returned error (.*)/)) { # dovecot: child 23747 (login) returned error 89 # dovecot: log: Error: service(auth): child 19654 returned error 89 (Fatal failure) $ChildErr{$Error}++; } elsif ( ($Name) = ($ThisLine =~ /$dovecottag IMAP\((.*)\): .*(.*) failed: Disk quota exceeded/i)) { # dovecot: IMAP(podracka): mkdir(/home/LF/KLINIKY/podracka/mail/.imap/saved-messages) failed: Disk quota exceeded $DiskQuotaExceed{$Name}++; # This is with imap_id_log = * enabled } elsif ( ($User,$MUA) = ($ThisLine =~ /imap\((.*)\): ID sent: name=(.*)/)) { $MUAList{$MUA}{$User}++; # Need to match these later } elsif ( ($MUA, $Session) = ($ThisLine =~ /imap-login: ID sent: name=(.*): user=.*, session=<([^>]+)>/)) { $MUASessionList{$Session} = $MUA; # These are failed connections with imap_id_log = * enabled } elsif ($ThisLine =~ /imap-login: ID sent: (?:name|vendor)=/) { # Ignore } elsif ( ($Fatal) = ($ThisLine =~ /^(?:$dovecottag )?(.* Fatal:.*)/)) { $Fatal{$Fatal}++; } elsif ( ($Error) = ($ThisLine =~ /^(?:$dovecottag )?(.* Error:.*)/)) { $Error{$Error}++; } else { # Report any unmatched entries... chomp($ThisLine); $OtherList{$ThisLine}++; } } ################################################ if ( $End ) { print "\nDovecot was killed, and not restarted afterwards.\n"; } if ( keys %Fatal ) { print "\nDovecot Fatal Errors:\n"; foreach my $Fatal (sort keys %Fatal) { print " ${Fatal}: $Fatal{$Fatal} Time(s)\n"; } } if ( keys %Error ) { print "\nDovecot Errors:\n"; foreach my $Error (sort keys %Error) { print " ${Error}: $Error{$Error} Time(s)\n"; } } if ( ( $Detail >=5 ) and $Restarts ) { print "\nDovecot restarted $Restarts time(s).\n"; } if ( ( $Detail >= 5 ) and (keys %Connection)) { print "\n[Dovecot IMAP and POP3] Connections:". "\n====================================". "\nPOP3 IMAP Total Host". "\n" . "-" x 72; $TLSInitFail = 0; my $IMAPCount = 0; my $POP3Count = 0; my $TotalCount = 0; foreach my $Host (sort { $Connection{$b} <=> $Connection{$a} } keys %Connection) { my $Total = $Connection{$Host}; my $Conns = 0; my $IMAP = 0; if (defined ($ConnectionPOP3{$Host})) { $Conns = $ConnectionPOP3{$Host}; } if (defined ($ConnectionIMAP{$Host})) { $IMAP = $ConnectionIMAP{$Host}; } # Cleanly display IPv4 addresses $Host=~ s/::ffff://; printf "\n%4s %4s %5s %s", $Conns, $IMAP, $Total, $Host; $POP3Count += $Conns; $IMAPCount += $IMAP; $TotalCount += $Total; } print "\n" . "-" x 72; printf "\n%4s %4s %5s %s", $POP3Count, $IMAPCount, $TotalCount, "Total"; } if (keys %Deliver) { my $DeliverCount = 0; my $DeliverUserCount; foreach my $User (keys %Deliver) { foreach my $Mailbox (keys %{$Deliver{$User}}) { $DeliverUserCount{$User} += $Deliver{$User}{$Mailbox}; } $DeliverCount += $DeliverUserCount{$User}; } printf "\n" if ($Detail >= 5); printf "\nDovecot Deliveries: %s", $DeliverCount; if ($Detail >= 5) { foreach my $User (sort { $DeliverUserCount{$b} <=> $DeliverUserCount{$a} } keys %DeliverUserCount) { printf "\n %4s %s", $DeliverUserCount{$User}, $User; if ($Detail >= 10) { foreach my $Mailbox (sort { $Deliver{$User}{$b} <=> $Deliver{$User}{$a} } keys %{$Deliver{$User}}) { printf "\n %4s %s", $Deliver{$User}{$Mailbox}, $Mailbox; } } } } } if (($Detail >= 10) and (keys %Forwarded)) { my $TotalForwarded = 0; print "\n\nDovecot LDA sieve forwards:"; foreach my $User (sort keys %Forwarded) { print "\n\n User $User"; foreach my $Recip (sort keys %{$Forwarded{$User}}) { print "\n To $Recip: $Forwarded{$User}{$Recip} time(s)"; $TotalForwarded += $Forwarded{$User}{$Recip}; } } print "\n\n Total: $TotalForwarded Time(s)"; } if (($Detail >= 10) and (keys %VacationResponse)) { my $TotalVacResp = 0; print "\n\nDovecot LDA sieve vacation responses:"; foreach my $User (sort keys %VacationResponse) { print "\n\n User $User"; foreach my $Recip (sort keys %{$VacationResponse{$User}}) { print "\n To $Recip: $VacationResponse{$User}{$Recip} time(s)"; $TotalVacResp += $VacationResponse{$User}{$Recip}; } } print "\n\n Total: $TotalVacResp Time(s)"; } if (($Detail >= 10) and (keys %VacationDup)) { my $TotalVacDup = 0; print "\n\nDovecot LDA sieve duplicate vacation responses not sent:"; foreach my $User (sort keys %VacationDup) { print "\n User $User"; foreach my $Recip (sort keys %{$VacationDup{$User}}) { print "\n To $Recip: $VacationDup{$User}{$Recip} time(s)"; $TotalVacDup += $VacationDup{$User}{$Recip}; } } print "\n\n Total: $TotalVacDup Time(s)"; } if (keys %Login) { my $LoginCount = 0; my %LoginUserCount; foreach my $User (keys %Login) { foreach my $Host (keys %{$Login{$User}}) { $LoginUserCount{$User} += $Login{$User}{$Host}; } $LoginCount += $LoginUserCount{$User}; $LoginPOP3{$User} = 0 if (not defined $LoginPOP3{$User}); $LoginIMAP{$User} = 0 if (not defined $LoginIMAP{$User}); } printf "\n" if ($Detail >= 5); printf "\nDovecot IMAP and POP3 Successful Logins: %s", $LoginCount; if ($Detail >= 5) { foreach my $User (sort { $LoginUserCount{$b} <=> $LoginUserCount{$a} } keys %LoginUserCount) { printf("\n %4s %s", $LoginUserCount{$User}, $User); if ($Detail >= 10) { print " ("; if ($LoginPOP3{$User} > 0) { print "$LoginPOP3{$User} POP3"; }; if ($LoginPOP3{$User} > 0 && $LoginIMAP{$User} > 0) { print ", "; }; if ($LoginIMAP{$User} > 0) { print "$LoginIMAP{$User} IMAP"; }; print ")"; foreach my $Host (sort { $Login{$User}{$b} <=> $Login{$User}{$a} } keys %{$Login{$User}}) { # Cleanly display IPv4 addresses $Host=~ s/::ffff://; printf "\n %4s %s", $Login{$User}{$Host}, $Host; } } } } } if ( ( $Detail >= 10 ) and (keys %SieveLogin)) { print "\n\nDovecot ManageSieve Successful Logins:"; my $LoginCount = 0; foreach my $User (sort keys %SieveLogin) { print "\n\n User $User:"; my $UserCount = 0; my $NumHosts = 0; foreach my $Host (sort keys %{$SieveLogin{$User}}) { $NumHosts++; my $HostCount = $SieveLogin{$User}{$Host}; # Cleanly display IPv4 addresses $Host=~ s/::ffff://; print "\n From $Host: $HostCount Time(s)"; $UserCount += $HostCount; } $LoginCount += $UserCount; if ($NumHosts > 1) { print "\n Total: $UserCount Time(s)"; } } print "\n\nTotal: $LoginCount successful ManageSieve logins"; } if (keys %LimitExceeded) { print "\n\nDovecot limits exceeded:"; foreach my $Reason (sort keys %LimitExceeded) { print "\n $Reason: $LimitExceeded{$Reason} Time(s)"; } } if ( ( $Detail >= 10 ) and (keys %AuthDisconnectedWithPending)) { print "\n\nAuth client disconnected with pending requests:"; foreach my $Reason (sort keys %AuthDisconnectedWithPending) { print "\n $Reason: $AuthDisconnectedWithPending{$Reason} Time(s)"; } } if ( ( $Detail >= 10 ) and (keys %AuthTimedOut)) { print "\n\nRequest timed out waiting for client to continue authentication:"; foreach my $User (sort(keys %AuthTimedOut)) { print "\n User: $User (IPs: "; print join(", ",sort(keys %{$AuthTimedOut{$User}})); my $Total = 0; foreach my $IP (keys %{$AuthTimedOut{$User}}) { $Total += $AuthTimedOut{$User}{$IP}; } print ") $Total Time(s)"; } } if (keys %AuthFail) { my $AuthFailCount = 0; my %AuthFailUserCount; foreach my $User (keys %AuthFail) { foreach my $IP (keys %{$AuthFail{$User}}) { $AuthFailUserCount{$User} += $AuthFail{$User}{$IP}; } $AuthFailCount += $AuthFailUserCount{$User}; } printf "\n" if ($Detail >= 5); printf "\nDovecot Failed Logins: %s", $AuthFailCount; if ($Detail >= 5) { foreach my $User (sort { $AuthFailUserCount{$b} <=> $AuthFailUserCount{$a} } keys %AuthFailUserCount) { printf("\n %4s %s", $AuthFailUserCount{$User}, $User); if ($Detail >= 10) { foreach my $IP (sort { $AuthFail{$User}{$b} <=> $AuthFail{$User}{$a} } keys %{$AuthFail{$User}}) { printf "\n %4s %s", $AuthFail{$User}{$IP}, $IP; } } } } } if ( ( $Detail >= 10 ) and (keys %AuthUsernameChars)) { print "\n\nUsername character disallowed by auth_username_chars:"; foreach my $IP (sort keys %AuthUsernameChars) { print "\n $IP: $AuthUsernameChars{$IP} Time(s)"; } } if (keys %Disconnected) { my $Disconnects = 0; foreach my $Reason (%Disconnected) { $Disconnects += (exists $Disconnected{$Reason}) ? $Disconnected{$Reason} : 0; } printf "\n\nDovecot disconnects: %s Total", $Disconnects; if ($Detail >= 5) { foreach my $Reason (sort { $Disconnected{$b} <=> $Disconnected{$a} } keys %Disconnected) { printf "\n %4s %s", $Disconnected{$Reason}, $Reason; } } } if (keys %ConnectionClosed) { print "\n\nDovecot connections closed:"; foreach my $Reason (sort keys %ConnectionClosed) { print "\n $Reason: $ConnectionClosed{$Reason} Time(s)"; } } if (keys %ChildErr) { print "\n\nDovecot child error:"; foreach my $Error (sort keys %ChildErr) { print "\n error number ". $Error . ": ". $ChildErr{$Error} ." Time(s)"; } } if ((keys %Aborted) && ($Detail >= 10)) { print "\n\nLogout/aborts:"; foreach my $Host (sort keys %Aborted) { print "\n $Host: $Aborted{$Host} Time(s)"; } } if ($TLSInitFail > 0) { print "\n\nTLS Initialization failed $TLSInitFail Time(s)"; } if (keys %DiskQuotaExceed) { print "\n\nDisk quota exceeded:"; foreach my $Name (sort keys %DiskQuotaExceed) { print "\n disk quota for user '". $Name . "' exceeded: ". $DiskQuotaExceed{$Name} ." Time(s)"; } } # This has to be explicitly enabled in dovecot config to log this, # so we'll assume people want it if enabled if (keys %MUAList) { print "\n\nIMAP Mail User Agent Strings:"; foreach my $MUA (sort(keys %MUAList)) { print "\n $MUA: (Users: "; print join(", ",sort(keys %{$MUAList{$MUA}})); my $Total = 0; foreach my $User (keys %{$MUAList{$MUA}}) { $Total += $MUAList{$MUA}{$User}; } print ") $Total Time(s)"; } } if ( ( $Detail >= 5 ) and (keys %ProxyLogin)) { print "\n\nDovecot Proxy IMAP and POP3 Successful Logins:"; my $LoginCount = 0; foreach my $User (sort keys %ProxyLogin) { print "\n User $User:"; if ( ($Detail >= 10) and ($ProxyLoginPOP3{$User} > 0 || $ProxyLoginIMAP{$User} > 0) ) { print " ("; if ($ProxyLoginPOP3{$User} > 0) { print "$ProxyLoginPOP3{$User} POP3"; }; if ($ProxyLoginPOP3{$User} > 0 && $ProxyLoginIMAP{$User} > 0) { print ", "; }; if ($ProxyLoginIMAP{$User} > 0) { print "$ProxyLoginIMAP{$User} IMAP"; }; print ")"; } my $UserCount = 0; my $NumHosts = 0; foreach my $Host (sort keys %{$ProxyLogin{$User}}) { $NumHosts++; my $HostCount = $ProxyLogin{$User}{$Host}; # Cleanly display IPv4 addresses $Host=~ s/::ffff://; print "\n From $Host: $HostCount Time(s)" if ($Detail >= 10); $UserCount += $HostCount; } $LoginCount += $UserCount; if ($Detail >= 10) { if ($NumHosts > 1) { print "\n Total: $UserCount Time(s)\n"; } else { print "\n"; } } elsif ($Detail >= 5) { print " $UserCount Time(s)"; } } print "\nTotal: $LoginCount successful logins"; } if (keys %ProxyDisconnected) { print "\n\nDovecot Proxy disconnects:\n"; foreach my $Reason (sort keys %ProxyDisconnected) { print " $Reason: $ProxyDisconnected{$Reason} Time(s)\n"; } } if (keys %UnknownUsers) { my $UserCount = 0; foreach my $User (keys %UnknownUsers) { $UserCount += $UnknownUsers{$User}; } print "\n\nUnknown users blocked: $UserCount Total\n"; if ($Detail >= 10) { foreach my $User (sort keys %UnknownUsers) { print " $UnknownUsers{$User} $User\n"; } } } if (keys %OtherList) { print "\n\n**Unmatched Entries**\n"; foreach my $line (sort {$a cmp $b} keys %OtherList) { print " $line: $OtherList{$line} Time(s)\n"; } } exit(0); # vi: shiftwidth=3 tabstop=3 syntax=perl et # Local Variables: # mode: perl # perl-indent-level: 3 # indent-tabs-mode: nil # End: logwatch-7.12/scripts/services/dirsrv0000664000211400021140000001625114743365003020225 0ustar logwatchlogwatch ######################################################## # Please file all bug reports, patches, and feature # requests under: # https://sourceforge.net/p/logwatch/_list/tickets # Help requests and discusion can be filed under: # https://sourceforge.net/p/logwatch/discussion/ ######################################################## ######################################################## ## Copyright (c) 2014-2019 Orion Poplawski ## Covered under the included MIT/X-Consortium License: ## http://www.opensource.org/licenses/mit-license.php ## All modifications and contributions by other persons to ## this script are assumed to have been donated to the ## Logwatch project and thus assume the above copyright ## and licensing terms. If you want to make contributions ## under your own copyright or a different license this ## must be explicitly stated in the contribution an the ## Logwatch project reserves the right to not accept such ## contributions. If you have made significant ## contributions to this script and want to claim ## copyright please contact logwatch-devel@lists.sourceforge.net. ######################################################### use strict; my $Detail = $ENV{'LOGWATCH_DETAIL_LEVEL'} || 0; my %ErrorThreshold; if (defined($ENV{'error_threshold'})) { foreach my $entry (split(',',$ENV{'error_threshold'})) { my ($regex,$limit) = split(';',$entry); $ErrorThreshold{$regex} = $limit; } } my %Errors; my %Warnings; my %Startup; my $Stop; my %BackupStarted; my $BackupCompleted; my %BackupFile; my %Export; my %NSSCiphers; my %SSLInit; my %Info; my %OtherList; my $PreviousLine = ''; while (defined(my $ThisLine = )) { chomp($ThisLine); if ($ThisLine =~ /^Listening for new connections again$/ or $ThisLine =~ /^Beginning export of / or $ThisLine =~ /^Export finished/ or $ThisLine =~ /Listening on .* (for LDAPI requests|port)/ or $ThisLine =~ /^Waiting for \d+ database threads to stop/ or $ThisLine =~ /^slapd shutting down - / or $ThisLine =~ /^SSL alert: Configured NSS Ciphers$/ or $ThisLine =~ /^ldbm_back_.* - conn=/ or $ThisLine =~ /^ldbm_usn_init - backend: / # https://pagure.io/389-ds-base/issue/48973 or $ThisLine =~ /default_mr_indexer_create.*- [Pp]lugin \[caseIgnoreIA5Match\] does not handle caseExactIA5Match/ or $ThisLine =~ /^WARN - Security Initialization - SSL alert: Sending pin request to SVRCore. You may need to run systemd-tty-ask-password-agent to provide the password/ # Will not be a warning in future versions or $ThisLine =~ /^WARN - content-sync-plugin - sync_update_persist_betxn_pre_op - DB retried operation targets .* => op not changed in PL/ or $ThisLine =~ /^ERR - NSACLPlugin - acl_parse - The ACL target .* does not exist/ or $ThisLine =~ /^ERR - cos-plugin - cos_dn_defs_cb - Skipping CoS Definition .*no CoS Templates found, which should be added before the CoS Definition/ ) { #Ignore } elsif ($ThisLine =~ /^ERR - / or $ThisLine =~ /error/i or $ThisLine =~ /^Detected Disorderly Shutdown/) { # Remove some items that prevent de-duplication $ThisLine =~ s/:\s+\d+\s+\d+//; $ThisLine =~ s/change record \d+/change record/; $Errors{$ThisLine}++; } elsif ($ThisLine =~ /^WARN - / or $ThisLine =~ /warning/i or $ThisLine =~ /^Not listening for new connections/) { $Warnings{$ThisLine}++; } elsif ($ThisLine =~ /^(.*) starting up$/) { $Startup{$1}++; } elsif ($ThisLine =~ /^slapd stopped\.$/) { $Stop++; } elsif ($ThisLine =~ /^Beginning backup of '(.*)'$/) { $BackupStarted{$1}++; } elsif ($ThisLine =~ /^Backup finished\.$/) { $BackupCompleted++; } elsif ($ThisLine =~ /^Backing up file \d+ \((.*)\)$/) { $BackupFile{$1}++; } elsif ($ThisLine =~ /^Copying (.*) to /) { $BackupFile{$1}++; } elsif ($ThisLine =~ /^export (\w+: Processed \d+ entries \(\d+%\)\.)$/) { $Export{$1}++; } elsif ($ThisLine =~ /^SSL alert:\s+(\S+): (\w+)/) { $NSSCiphers{$1} = $2; } elsif ($ThisLine =~ /^SSL Initialization - (.*)/) { $SSLInit{$1}++; } elsif ($ThisLine =~ /^(Total entry cache size:.*)/ or $ThisLine =~ /^(userRoot: entry cache size:.*)/) { $Info{$1}++; } elsif ($ThisLine =~ /^All database threads now stopped$/) { #This line follows the previous normally in backups or shutdown $OtherList{$ThisLine}++ unless $PreviousLine =~ /^(export \w+: Processed \d+ entries|Waiting for \d+ database threads to stop|Backing up file|Copying .* to )/; } else { next if $ThisLine =~ /^INFO -/ and $Detail < 10; next if $ThisLine =~ /^NOTICE -/ and $Detail < 5; $OtherList{$ThisLine}++; } $PreviousLine = $ThisLine; } if (keys %Errors and keys %ErrorThreshold) { LINE: foreach my $line (keys %Errors) { foreach my $regex (keys %ErrorThreshold) { if ($line =~ /$regex/i and $Errors{$line} <= $ErrorThreshold{$regex}) { delete $Errors{$line}; next LINE; } } } } if (keys %Warnings and keys %ErrorThreshold) { LINE: foreach my $line (keys %Warnings) { foreach my $regex (keys %ErrorThreshold) { if ($line =~ /$regex/i and $Warnings{$line} <= $ErrorThreshold{$regex}) { delete $Warnings{$line}; next LINE; } } } } if (keys %Errors) { print "\n** ERRORS **\n"; foreach my $line (sort {$a cmp $b} keys %Errors) { print " $line: $Errors{$line} Time(s)\n"; } } if (keys %Warnings) { print "\n** Warnings:\n"; foreach my $line (sort {$a cmp $b} keys %Warnings) { print " $line: $Warnings{$line} Time(s)\n"; } } if (keys %Startup and $Detail >= 5) { foreach my $Version (keys %Startup) { print "\nStart up version $Version: $Startup{$Version} Time(s)\n"; } } if ($Stop and $Detail) { print "\nStopped: $Stop Time(s)\n"; } if (keys %BackupStarted and $Detail) { foreach my $Database (keys %BackupStarted) { print "\nBackup started for $Database: $BackupStarted{$Database} Time(s)\n"; } } if (keys %BackupFile and $Detail >= 7) { print "\nBacked up files:\n"; foreach my $File (sort {$a cmp $b} keys %BackupFile) { print " $File: $BackupFile{$File} Time(s)\n"; } } if ($BackupCompleted and $Detail) { print "\nBackup completed: $BackupCompleted Time(s)\n"; } if (keys %Export and $Detail) { print "\nExports:\n"; foreach my $Line (keys %Export) { print " $Line $Export{$Line} Time(s)\n"; } } if (keys %Info and $Detail >= 7) { print "\nInformational Messages::\n"; foreach my $Line (keys %Info) { print " $Line $Info{$Line} Time(s)\n"; } } if (keys %SSLInit and $Detail >= 7) { print "\nSSL Initialization:\n"; foreach my $Message (sort {$a cmp $b} keys %SSLInit) { print " $Message\n"; } } if (keys %NSSCiphers and $Detail >= 7) { print "\nNSS Ciphers:\n"; foreach my $Cipher (sort {$a cmp $b} keys %NSSCiphers) { print " $Cipher: $NSSCiphers{$Cipher}\n"; } } if (keys %OtherList) { print "\n**Unmatched Entries**\n"; foreach my $line (sort {$a cmp $b} keys %OtherList) { print " $line: $OtherList{$line} Time(s)\n"; } } logwatch-7.12/scripts/services/pluto0000664000211400021140000003032114274101041020036 0ustar logwatchlogwatch ######################################################## # Please file all bug reports, patches, and feature # requests under: # https://sourceforge.net/p/logwatch/_list/tickets # Help requests and discusion can be filed under: # https://sourceforge.net/p/logwatch/discussion/ ######################################################## ########################################################################## # Note (8/28/2005, BL): # # This script was apparently written for FreeS/WAN, which is no longer # supported (see http://www.freeswan.org). But it also appears to work # with Openswan (http://www.openswan.org), which is described as a code # fork of FreeS/WAN. # # Also, notice that in this script, many variables are set, but not # printed. And many logged statements are filtered by this script. # # So this script would probably benefit from an update to clean it up # and ensure full compatibility with the newer Openswan. ########################################################################## # This is a scanner for logwatch that processes FreeSWAN's # Pluto log files and attempts to # make some sense out of them. # # Please CC suggestions to mcr@freeswan.org and/or design@lists.freeswan.org # the vendorID hash maps vendor IDs to products. VendorIDs are hashs of # internal stuff from each vendor. Grow this table as you encounter new # products. ####################################################### ## Copyright (c) 2008 Kirk Bauer ## Covered under the included MIT/X-Consortium License: ## http://www.opensource.org/licenses/mit-license.php ## All modifications and contributions by other persons to ## this script are assumed to have been donated to the ## Logwatch project and thus assume the above copyright ## and licensing terms. If you want to make contributions ## under your own copyright or a different license this ## must be explicitly stated in the contribution an the ## Logwatch project reserves the right to not accept such ## contributions. If you have made significant ## contributions to this script and want to claim ## copyright please contact logwatch-devel@lists.sourceforge.net. ######################################################### use strict; #Init String Container my ( $baddelete, $ipaddr, $ipport, $lastattempt, $oldinfo, $phase2, $rest, $stateinfo, $today, $vid ); #Init Hashes my ( %badexch, %conns, %crlUpdate, %crlUpdateSince, %ipsecSAs, %loglines, %maxattempts, %peerID, %peerIP, %quickmode, %rekeyfail, %rekeyfailI1, %rekeyfailQI1, %rekeyfailQR1, %rekeyfailR1, %rekeyfail_ICMPunreachable, %rekeyfail_notknown, %rekeysuccess, %relevantlog, %setupfail, %statechain, %xauthsuccess, %vendorID ); my $debug=0; $vendorID{"p....}..&..i...5..............................."}="KAME/Racoon"; while(<>) { # May 4 04:04:33 abigail Pluto[24170]: "abigail-istari" #1479: ISAKMP SA expired (LATEST!) chop; my ($month,$day,undef,undef,$process,$conn,$msg)=split(/ +/,$_,7); $today="$month $day"; next unless ($process =~ /pluto/i); my $iserror=0; if ($conn eq "ERROR:") { $iserror = 1; (undef,$conn,$msg)=split(/ +/,$msg,3); } $loglines{$today}++; print STDERR "Msg: $msg\n" if $debug>1; if($msg =~ /([^\#]*)\#(\d*)\:(.*)/) { $ipaddr = $1; $stateinfo = $2; $rest = $3; } elsif($msg =~ /no Phase 1 state for Delete/) { # baddelete not currently used #$baddelete++; next; } elsif($msg =~ /from ([^:]*)\:([^:]*)\: Main Mode message is part of an unknown exchange/) { $ipaddr = $1; $ipport = $2; $badexch{"[$ipaddr]:$ipport"}++; next; } else { print STDERR "Failed to decode: $msg (of $_)\n" if $debug; next; } # print STDERR "conn: $conn IP: $ipaddr STATE: $stateinfo\n" if $debug; $conn =~ s/\"(.*)\"/$1/; $conn =~ s/\[\d\]$//; $conns{$conn}++; if(!defined($peerIP{"$conn|$ipaddr"})) { #print STDERR "Adding $ipaddr to $conn\n" if $debug; $peerIP{$conn}=$peerIP{$conn}.$ipaddr." "; } $peerIP{"$conn|$ipaddr"}++; # This code no longer seems to be active #$stateobjects{$stateinfo}++; #if(!defined($peer{$stateinfo}) && length($ipaddr)>0) { # $peer{$stateinfo}=$ipaddr; #} # ignore following next if($rest =~ /ISAKMP SA expired/); next if($rest =~ /responding to Main Mode/); next if($rest =~ /responding to Quick Mode/); next if($rest =~ /IPsec SA expired/); next if($rest =~ /ignoring informational payload, type IPSEC_INITIAL_CONTACT/); next if($rest =~ /regenerating DH private secret to avoid Pluto 1.0 bug handling public value with leading zero/); next if($rest =~ /regenerating DH private secret to avoid Pluto 1.0 bug handling shared secret with leading zero/); next if($rest =~ /shared DH secret has leading zero -- triggers Pluto 1.0 bug/); next if($rest =~ /(received|ignoring) Delete SA(|\(0x.*\)) payload/); next if($rest =~ /received and ignored informational message/); next if($rest =~ /discarding duplicate packet; already STATE_MAIN_../); next if($rest =~ /discarding duplicate packet; already STATE_QUICK_../); next if($rest =~ /deleting state \(STATE_MAIN_..\)/); next if($rest =~ /deleting state \(STATE_QUICK_..\)/); next if($rest =~ /Quick Mode .. message is unacceptable because it uses a previously used Message ID/); next if($rest =~ /deleting connection .* instance with peer .*/); next if($rest =~ /dropping and reinitiating exchange to avoid Pluto 1.0 bug handling DH shared secret with leading zero byte/); next if($rest =~ /KE has 191 byte DH public value; 192 required/); next if($rest =~ /retransmitting in response to duplicate packet; already STATE_MAIN_../); next if($rest =~ /(Main mode p|P)eer ID is /); next if($rest =~ /transition from state .* to state/); next if($rest =~ /NAT-Traversal: Result using/); next if($rest =~ /no crl from issuer/); next if($rest =~ /I am sending (a certificate request|my cert)/); next if($rest =~ /no suitable connection for peer/); next if($rest =~ /sending encrypted notification/); next if($rest =~ /enabling possible NAT-traversal with method/); next if($rest =~ /(received|ignoring) Vendor ID payload/); next if($rest =~ /ignoring unknown Vendor ID payload/); next if($rest =~ /Dead Peer Detection \(RFC 3706\): enabled/); next if($rest =~ /DPD: No response from peer - declaring peer dead/); next if($rest =~ /DPD Error: could not find newest phase 1 state/); next if($rest =~ /Informational Exchange message is invalid because it has a previously used Message ID/); next if($rest =~ /discarding packet received during asynchronous work \(DNS or crypto\) in STATE_(MAIN|QUICK)_../); next if($rest =~ /STATE_(MAIN|QUICK)_[RI][1-3]: sent [MQ][RI][1-3], expecting [MQ][IR][1-3]/); next if($rest =~ /STATE_QUICK_R1: sent QR1, inbound IPsec SA installed, expecting QI2/); next if($rest =~ /down-client output/); next if($rest =~ /(restore|update)resolvconf-client output/); next if($rest =~ /transform .* ignored/); next if($rest =~ /multiple DH groups were set in aggressive mode\./); next if($rest =~ /received mode cfg reply/); next if($rest =~ /modecfg: Sending IP request/); next if($rest =~ /setting .* address to/); next if($rest =~ /STATE_XAUTH_I1: XAUTH client - awaiting CFG_set/); next if($rest =~ /initiating Aggressive Mode/); next if($rest =~ /Aggressive mode peer ID is/); next if($rest =~ /protocol\/port in Phase \d ID Payload must be/); next if($rest =~ /XAUTH: Bad Message: /); next if($rest =~ /XAUTH: Answering XAUTH challenge with user/); next if($rest =~ /Received IP4|DNS|subnet /); next if($rest =~ /sendto on .* to .* failed in delete notify/); $relevantlog{"$today"}++; print STDERR "Rest is $rest\n" if $debug>1; # but process these. if($rest =~ /initiating Main Mode to replace \#(.*)/) { $oldinfo = $1; $statechain{$conn.$stateinfo}="$conn|$oldinfo"; next; } elsif($rest =~ /initiating Main Mode/) { $statechain{$conn.$stateinfo}="$conn"; next; } elsif($rest =~ /initiating Quick Mode (.*) to replace \#(.*)/) { $oldinfo = $2; $phase2 = $1; $statechain{"$conn|$stateinfo"}="$conn|$oldinfo"; $quickmode{"$conn"}=$quickmode{"$conn"}." ".$phase2; next; } elsif($rest =~ /initiating Quick Mode (.*)/) { $phase2 = $1; $statechain{"$conn|$stateinfo"}="$conn"; $quickmode{"$conn"}=$quickmode{"$conn"}." ".$phase2; next; } elsif($rest =~ /ISAKMP SA established/) { $rekeysuccess{$conn}++; next; } elsif($rest =~ /cannot respond to IPsec SA request because no connection is known for (.*)/) { $rekeyfail{$conn}++; #$rekeyfail_notknown{$1}++; } elsif($rest =~ /crl update is overdue since (.*)/) { $crlUpdate{$conn}++; $crlUpdateSince{$conn} = $1; next; } elsif($rest =~ /max number of retransmissions \((.*)\) reached STATE_QUICK_I./) { $rekeyfail{$conn}++; #$rekeyfailQI1{$conn}++; next; } elsif($rest =~ /max number of retransmissions \((.*)\) reached STATE_QUICK_R./) { $rekeyfail{$conn}++; #$rekeyfailQR1{$conn}++; next; } elsif($rest =~ /max number of retransmissions \((.*)\) reached STATE_MAIN_I./) { $rekeyfail{$conn}++; #$rekeyfailI1{$conn}++; next; } elsif($rest =~ /max number of retransmissions \((.*)\) reached STATE_MAIN_R./) { $rekeyfail{$conn}++; #$rekeyfailR1{$conn}++; next; } elsif($rest =~ /ERROR: asynchronous network error report on .* for message to .* port 500, complainant .*:.*errno (.*), origin ICMP type (.*) code (.*)/) { $rekeyfail{$conn}++; #$rekeyfail_ICMPunreachable{$conn}++; } elsif($rest =~ /ERROR: asynchronous network error report on .* for message to .* port 500, complainant .*:.*errno (.*), origin ICMP type (.*) code (.*)/) { $rekeyfail{$conn}++; #$rekeyfail_ICMPunreachable{$conn}++; } elsif($rest =~ /XAUTH: Successfully Authenticated/) { $xauthsuccess{$conn}++; } elsif($rest =~ /starting keying attempt (.*) of an unlimited number/) { $lastattempt=$1; if($maxattempts{$conn} < $lastattempt) { $maxattempts{$conn} = $lastattempt; } next; } elsif($rest =~ /Vendor ID: (.*)/) { $vid=$1; if(defined($vendorID{$vid})) { $peerID{$conn}=$vendorID{$vid}; } else { $peerID{$conn}="unknown $vid"; $vendorID{$vid}="unknown $vid at $stateinfo/$ipaddr\n"; } next; } elsif($rest =~ /prepare-client output.*/) { $setupfail{$conn}++; } elsif(($rest =~ /sent QI2, IPsec SA established/) || ($rest =~ /IPsec SA established/)) { $ipsecSAs{$conn}++; next; } else { print STDERR "UNKNOWN: $_"."\n"; } } if (keys %loglines) { print "Overview summary of log files:\n"; foreach my $day (keys %loglines) { print "\t $day had ".$loglines{$day}." entries of which ".$relevantlog{$day}." were relevant\n"; } } if (keys %conns) { print "Summary by peer:\n"; foreach my $conn (keys %conns) { print " Peer $conn caused $conns{$conn} lines of output.\n"; print "\tconnected from:".$peerIP{$conn}."\n"; if(defined($peerID{$conn})) { print "\tVID: ".$peerID{$conn}."\n"; } print "\tKeyed: ".($rekeysuccess{$conn}+0)." successes ",($rekeyfail{$conn}+0)." failures (max retries: ".($maxattempts{$conn}+0).")\n"; print "\tIPsec SAs: ".($ipsecSAs{$conn}+0)."\n"; if($setupfail{$conn} > 0) { print "\tSetup failures: ".$setupfail{$conn}."\n"; } if($xauthsuccess{$conn} > 0) { print "\tXAUTH successful connections: ".$xauthsuccess{$conn}."\n"; } if($crlUpdate{$conn} > 0) { print "\tOverdue CRL update since: ".$crlUpdateSince{$conn}." (".$crlUpdate{$conn}." times)\n"; } } } if (keys %badexch) { print "Summary of bad peers\n"; foreach my $badpeer (keys %badexch) { print "\t".$badpeer." caused ".$badexch{$badpeer}." bad exchanges\n"; } } # vi: shiftwidth=3 tabstop=3 syntax=perl et # Local Variables: # mode: perl # perl-indent-level: 3 # indent-tabs-mode: nil # End: logwatch-7.12/scripts/services/http0000664000211400021140000006130214743601205017665 0ustar logwatchlogwatch ######################################################## # Please file all bug reports, patches, and feature # requests under: # https://sourceforge.net/p/logwatch/_list/tickets # Help requests and discusion can be filed under: # https://sourceforge.net/p/logwatch/discussion/ ######################################################## ##################################################### # Copyright (c) 2008 Michael Romeo # Covered under the included MIT/X-Consortium License: # http://www.opensource.org/licenses/mit-license.php # All modifications and contributions by other persons to # this script are assumed to have been donated to the # Logwatch project and thus assume the above copyright # and licensing terms. If you want to make contributions # under your own copyright or a different license this # must be explicitly stated in the contribution an the # Logwatch project reserves the right to not accept such # contributions. If you have made significant # contributions to this script and want to claim # copyright please contact logwatch-devel@lists.sourceforge.net. ######################################################## #use diagnostics; use strict; use Logwatch ':sort'; # use re "debug"; # # parse httpd access_log # # Get the detail level and # Build tables of the log format to parse it and determine whats what # my $detail = $ENV{'LOGWATCH_DETAIL_LEVEL'} || 0; my $ignoreURLs = $ENV{'http_ignore_urls'}; my $ignoreIPs = $ENV{'http_ignore_ips'}; my $ignoreEval = $ENV{'http_ignore_eval'}; my $ignore_error_hacks = $ENV{'http_ignore_error_hacks'} || 0; my $user_display = $ENV{'http_user_display'}; my $logformat = "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"|%h %l %u %t \"%r\" %>s %b|%t %h %{SSL_PROTOCOL}x %{SSL_CIPHER}x \"%r\" %b"; if (defined $ENV{'logformat'}) { $logformat = $ENV{'logformat'}; } my @log_fields = (); my @log_format = (); if ((defined $ENV{'http_fields'}) and (defined $ENV{'http_format'})) { @log_fields = split(" ", $ENV{'http_fields'}); @log_format = split(" ", $ENV{'http_format'}); } # # Initialization etc. # my $byte_summary = 0; my $failed_requests = 0; my %field = (); my %hacks =(); my %hack_success =(); my %needs_exam =(); my %users_logged =(); my %ban_ip =(); my %robots =(); my $pattern = ""; my $isahack = 0; my $a5xx_resp = 0; my $a4xx_resp = 0; my $a3xx_resp = 0; my $a2xx_resp = 0; my $a1xx_resp = 0; my $image_count = 0; my $image_bytes = 0; my $docs_count = 0; my $docs_bytes = 0; my $archive_count = 0; my $archive_bytes = 0; my $sound_count = 0; my $sound_bytes = 0; my $movie_count = 0; my $movie_bytes = 0; my $winexec_count = 0; my $winexec_bytes = 0; my $content_count = 0; my $content_bytes = 0; my $redirect_count = 0; my $redirect_bytes = 0; my $other_count = 0; my $other_bytes = 0; my $total_hack_count = 0; my $wpad_count = 0; my $wpad_bytes = 0; my $src_count = 0; my $src_bytes = 0; my $logs_count = 0; my $logs_bytes = 0; my $images_count = 0; my $images_bytes = 0; my $fonts_count = 0; my $fonts_bytes = 0; my $config_count = 0; my $config_bytes = 0; my $xpcomext_count = 0; my $xpcomext_bytes = 0; my $mozext_count = 0; my $mozext_bytes = 0; my $proxy_count = 0; my $proxy_bytes = 0; my %proxy_host = (); my $host = ""; my $notparsed = ""; my $notparsed_count =0; ###################### # file type comparisons are case-insensitive my $image_types = '(\.bmp|\.cdr|\.emz|\.gif|\.ico|\.jpe?g|\.png|\.svg|\.sxd|\.tiff?|\.wbmp|\.webp|\.wmf|\.wmz|\.xdm)'; my $content_types = '('; $content_types = $content_types.'\/server-status|\/server-info'; $content_types = $content_types.'|\.htm|\.html|\.jhtml|\.phtml|\.shtml|\/\.?'; $content_types = $content_types.'|\.html\.[a-z]{2,3}(_[A-Z]{2,3})?'; $content_types = $content_types.'|\.inc|\.php|\.php3|\.asmx|\.asp|\.pl|\.wml'; $content_types = $content_types.'|^\/mailman\/.*'; $content_types = $content_types.'|\/sqwebmail.*'; $content_types = $content_types.'|^\/announce|^\/scrape'; # BitTorrent tracker mod_bt $content_types = $content_types.'|\.torrent'; $content_types = $content_types.'|\.css|\.js|\.cgi'; $content_types = $content_types.'|\.fla|\.swf|\.rdf'; $content_types = $content_types.'|\.class|\.jsp|\.jar|\.java'; $content_types = $content_types.'|COPYRIGHT|README|FAQ|INSTALL|\.txt)'; my $docs_types = '(\.asc|\.bib|\.djvu|\.docx?|\.dot|\.dtd|\.dvi|\.gnumeric|\.mcd|\.mso|\.pdf|\.pps|\.pptx?|\.ps|\.rtf|\.sxi|\.tex|\.text|\.tm|\.xlsx?|\.xml)'; my $archive_types = '(\.7z|\.ace|\.bz2|\.cab|\.deb|\.dsc|\.ed2k|\.gz|\.hqx|\.md5|\.rar|\.rpm|\.sig|\.sign|\.tar|\.tbz2|\.tgz|\.vl2|\.z|\.zip|\.hdr)'; my $sound_types = '(\.aac|\.au|\.aud|\.m4a|\.mid|\.mp3|\.oga|\.pls|\.ram|\.raw|\.rm|\.wav|\.wma|\.xsm)'; my $movie_types = '(\.asf|\.ass|\.avi|\.idx|\.flv|\.m2?ts|\.mkv|\.mp4|\.mpe?g|\.mov|\.ogg|\.ogv|\.qt|\.psb|\.srt|\.ssa|\.smi|\.sub|\.webm|\.wmv)'; my $winexec_types = '(\.bat|\.com|\.exe|\.dll)'; my $wpad_files = '(wpad\.dat|wspad\.dat|proxy\.pac)'; my $program_src = '('; $program_src = $program_src.'\.bas|\.cs?|\.cpp|\.diff|\.f|\.h|\.init|\.m|\.mo|\.pas|\.patch|\.po|\.pot|\.py|\.sh|\.spec'; $program_src = $program_src.'|Makefile|Makefile_c|Makefile_f77)'; my $images_types = '(\.bin|\.cue|\.img|\.iso|\.run)'; my $logs_types = '(\.log|_log|-log|\.logs|\.out|\.wyniki)'; my $fonts_types = '(\.aft|\.otf|\.ttf|\.woff)'; my $config_types = '(\.cfg|\.conf|\.config|\.ini|\.properties)'; my $xpcomext_types = '(\.xpt)'; my $mozext_types = '(\.xul)'; # HTTP Status codes from HTTP/Status.pm, to avoid loading package # that may or may not exist. We only need those >=400, but all # are included for potential future use. Those labeled with the # NGINX comment are NGINX-specific only, and not approved by IANA. # They need to be changed if a future conflict arises in the code's # definition. my %StatusCode = ( 100 => 'Continue', 101 => 'Switching Protocols', 102 => 'Processing', 103 => 'Early Hints', 200 => 'OK', 201 => 'Created', 202 => 'Accepted', 203 => 'Non-Authoritative Information', 204 => 'No Content', 205 => 'Reset Content', 206 => 'Partial Content', 207 => 'Multi-Status', 208 => 'Already Reported', 226 => 'IM Used', 300 => 'Multiple Choices', 301 => 'Moved Permanently', 302 => 'Found', 303 => 'See Other', 304 => 'Not Modified', 305 => 'Use Proxy', 307 => 'Temporary Redirect', 308 => 'Permanent Redirect', 400 => 'Bad Request', 401 => 'Unauthorized', 402 => 'Payment Required', 403 => 'Forbidden', 404 => 'Not Found', 405 => 'Method Not Allowed', 406 => 'Not Acceptable', 407 => 'Proxy Authentication Required', 408 => 'Request Timeout', 409 => 'Conflict', 410 => 'Gone', 411 => 'Length Required', 412 => 'Precondition Failed', 413 => 'Request Entity Too Large', 414 => 'Request-URI Too Large', 415 => 'Unsupported Media Type', 416 => 'Request Range Not Satisfiable', 417 => 'Expectation Failed', 421 => 'Misdirected Request', 422 => 'Unprocessable Entity', 423 => 'Locked', 424 => 'Failed Dependency', 425 => 'Too Early', 426 => 'Upgrade Required', 428 => 'Precondition Required', 429 => 'Too Many Requests', 431 => 'Request Header Fields Too Large', 444 => 'Closed Without Response', # NGINX 451 => 'Unavailable for Legal Reasons', 494 => 'Request Header Too Large', # NGINX 495 => 'Cert Error', # NGINX 496 => 'No Cert', # NGINX 497 => 'To HTTPS', # NGINX 499 => 'Client Closed Request', # NGINX 500 => 'Internal Server Error', 501 => 'Not Implemented', 502 => 'Bad Gateway', 503 => 'Service Unavailable', 504 => 'Gateway Timeout', 505 => 'HTTP Version Not Supported', 507 => 'Insufficient Storage', 508 => 'Loop Detected', 510 => 'Not Extended', 511 => 'Network Authentication Required' ); # # what to look for as an attack USE LOWER CASE!!!!!! # my @exploits = ( '/\.\./\.\./\.\./', '\.\./\.\./config\.sys', '/\.\./\.\./\.\./autoexec\.bat', '/\.\./\.\./windows/user\.dat', '\\\x02\\\xb1', '\\\x04\\\x01', '\\\x05\\\x01', '\\\x90\\\x02\\\xb1\\\x02\\\xb1', '\\\x90\\\x90\\\x90\\\x90', '\\\xff\\\xff\\\xff\\\xff', '\\\xe1\\\xcd\\\x80', '\\\xff\xe0\\\xe8\\\xf8\\\xff\\\xff\\\xff-m', '\\\xc7f\\\x0c', '\\\x84o\\\x01', '\\\x81', '\\\xff\\\xe0\\\xe8', '\/c\+dir', '\/c\+dir\+c', '\.htpasswd', 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', 'author\.exe', 'boot\.ini', 'cmd\.exe', 'c%20dir%20c', 'default\.ida', 'fp30reg\.dll', 'httpodbc\.dll', 'nsiislog\.dll', 'passwd$', 'root\.exe', 'shtml\.exe', 'win\.ini', 'xxxxxxxxxxxxxxxxxxxxxx', ); # # Define some useful RE patterns # my %re_pattern = ( space => '(.*)', brace => '\[(.*)\]', quote => '\"(.*)\"'); # # Build the regex to parse the line # for (my $i = 0; $i < @log_format; $i++) { $pattern = $pattern.$re_pattern{$log_format[$i]}.'\\s'; } # this is easier than coding last element logic in the loop chop($pattern); chop($pattern); # The following are used to build up pattern matching strings for # the log format used in the access_log files. my @parse_string = (); my @parse_field = (); my $parse_index = 0; my $parse_subindex = 0; $parse_string[$parse_index] = ""; $parse_field[$parse_index] = (); if ($pattern) { # accommodate usage of HTTP_FIELDS and HTTP_FORMAT $parse_string[0] = $pattern; $parse_field[0] = [@log_fields]; $parse_index++; } $parse_string[$parse_index] = ""; $parse_field[$parse_index] = (); my $end_loop = 1; $logformat =~ s/%[\d,!]*/%/g; while ($end_loop) { if ($logformat =~ /\G%h/gc) { $parse_string[$parse_index] .= "(\\S*?)"; $parse_field[$parse_index][$parse_subindex++] = "client_ip"; } elsif ($logformat =~ /\G%l/gc) { $parse_string[$parse_index] .= "(\\S*?)"; $parse_field[$parse_index][$parse_subindex++] = "ident"; } elsif ($logformat =~ /\G%u/gc) { $parse_string[$parse_index] .= "(\\S*?)"; $parse_field[$parse_index][$parse_subindex++] = "userid"; } elsif ($logformat =~ /\G%t/gc) { $parse_string[$parse_index] .= "(\\[.*\\])"; $parse_field[$parse_index][$parse_subindex++] = "timestamp"; } elsif ($logformat =~ /\G%r/gc) { $parse_string[$parse_index] .= "(.*)"; $parse_field[$parse_index][$parse_subindex++] = "request"; } elsif ($logformat =~ /\G%>?s/gc) { $parse_string[$parse_index] .= "(\\d{3})"; $parse_field[$parse_index][$parse_subindex++] = "http_rc"; } elsif ($logformat =~ /\G%b/gc) { # "transfered" is misspelled, but not corrected because this string # comes from the configuration file, and would create a compatibility # issue $parse_field[$parse_index][$parse_subindex++] = "bytes_transfered"; $parse_string[$parse_index] .= "(-|\\d*)"; } elsif ($logformat =~ /\G%V/gc) { $parse_string[$parse_index] .= "(\\S*?)"; $parse_field[$parse_index][$parse_subindex++] = "server_name"; } elsif ($logformat =~ /\G%I/gc) { $parse_field[$parse_index][$parse_subindex++] = "bytes_in"; $parse_string[$parse_index] .= "(-|\\d*)"; } elsif ($logformat =~ /\G%O/gc) { $parse_field[$parse_index][$parse_subindex++] = "bytes_out"; $parse_string[$parse_index] .= "(-|\\d*)"; } elsif ($logformat =~ /\G%\{Referer}i/gci) { $parse_string[$parse_index] .= "(.*)"; $parse_field[$parse_index][$parse_subindex++] = "referrer"; } elsif ($logformat =~ /\G%\{User-Agent}i/gci) { $parse_string[$parse_index] .= "(.*)"; $parse_field[$parse_index][$parse_subindex++] = "agent"; } elsif ($logformat =~ /\G%(\{.*?\})?./gc) { $parse_string[$parse_index] .= "(.*?)"; $parse_field[$parse_index][$parse_subindex++] = "not_used"; } elsif ($logformat =~ /\G\|/gc) { $parse_index++; $parse_subindex = 0; $parse_string[$parse_index] = ""; $parse_field[$parse_index] = (); # perl 5.6 does not detect end of string properly in next elsif block, # so we test it explicitly here } elsif ($logformat =~ /\G$/gc) { $end_loop = 0; } elsif ((my $filler) = ($logformat =~ /\G([^%\|]*)/gc)) { $parse_string[$parse_index] .= $filler; # perl 5.6 loses track of match position, so we force it. Perl 5.8 # and later does it correctly, so it was fixed in 5.7 development. if ($] < 5.007) {pos($logformat) += length($filler);} } else { $end_loop = 0; } } ################# print "RE pattern = $pattern \n"; # # Process log file on stdin # while (my $line = ) { chomp($line); ################## print "Line = $line \n"; # # parse the line per the input spec # my @parsed_line; for $parse_index (0..$#parse_string) { if (@parsed_line = $line =~ /$parse_string[$parse_index]/) { @log_fields = @{$parse_field[$parse_index]}; last; } } if (not @parsed_line) { $notparsed_count++; if ($notparsed_count <= 10) { $notparsed = $notparsed . " " . $line . "\n"; } next; } # hash the results so we can identify the fields # for my $i (0..$#log_fields) { # print "$i $log_fields[$i] $parsed_line[$i] \n"; $field{$log_fields[$i]} = $parsed_line[$i]; } ## ## Do the default stuff ## # # Break up the request into method, url and protocol # ($field{method},$field{url},$field{protocol}) = split(/ +/,$field{"request"}); if (! $field{url}) { $field{url}='null'; } $field{lc_url} = lc $field{url}; # # Bytes sent Summary # Apache uses "-" to represent 0 bytes transferred # if ($field{bytes_transfered} eq "-") {$field{bytes_transfered} = 0}; $byte_summary += $field{bytes_transfered}; # # loop to check for typical exploit attempts # if (!$ignore_error_hacks) { for (my $i = 0; $i < @exploits; $i++) { # print "$i $exploits[$i] $field{lc_url} \n"; if ( ($field{lc_url} =~ /$exploits[$i]/i) && !((defined $ignoreURLs) && ($field{url} =~ /$ignoreURLs/i)) && !((defined $ignoreIPs) && ($field{client_ip} =~ /$ignoreIPs/)) ) { $hacks{$field{client_ip}}{$exploits[$i]}++; $total_hack_count += 1; $ban_ip{$field{client_ip}} = " "; if ($field{http_rc} < 300) { $hack_success{$field{url}} = $field{http_rc}; } } } } # # Count types and bytes # # this is only printed if detail > 4 but it also looks # for 'strange' stuff so it needs to run always # ($field{base_url},$field{url_parms}) = split(/\?/,$field{"lc_url"}); if ($field{base_url} =~ /$image_types$/oi) { $image_count += 1; $image_bytes += $field{bytes_transfered}; } elsif ($field{base_url} =~ /$docs_types$/oi) { $docs_count += 1; $docs_bytes += $field{bytes_transfered}; } elsif ($field{base_url} =~ /$archive_types$/oi) { $archive_count += 1; $archive_bytes += $field{bytes_transfered}; } elsif ($field{base_url} =~ /$sound_types$/oi) { $sound_count += 1; $sound_bytes += $field{bytes_transfered}; } elsif ($field{base_url} =~ /$movie_types$/oi) { $movie_count += 1; $movie_bytes += $field{bytes_transfered}; } elsif ($field{base_url} =~ /$winexec_types$/oi) { $winexec_count += 1; $winexec_bytes += $field{bytes_transfered}; } elsif ($field{base_url} =~ /$content_types$/oi) { $content_count += 1; $content_bytes += $field{bytes_transfered}; } elsif ($field{base_url} =~ /$wpad_files$/oi) { $wpad_count += 1; $wpad_bytes += $field{bytes_transfered}; } elsif ($field{base_url} =~ /$program_src$/oi) { $src_count += 1; $src_bytes += $field{bytes_transfered}; } elsif ($field{base_url} =~ /$images_types$/oi) { $images_count += 1; $images_bytes += $field{bytes_transfered}; } elsif ($field{base_url} =~ /$logs_types$/oi) { $logs_count += 1; $logs_bytes += $field{bytes_transfered}; } elsif ($field{base_url} =~ /$fonts_types$/oi) { $fonts_count += 1; $fonts_bytes += $field{bytes_transfered}; } elsif ($field{base_url} =~ /$config_types$/oi) { $config_count += 1; $config_bytes += $field{bytes_transfered}; } elsif ($field{base_url} =~ /$xpcomext_types$/oi) { $xpcomext_count += 1; $xpcomext_bytes += $field{bytes_transfered}; } elsif ($field{base_url} =~ /$mozext_types$/oi) { $mozext_count += 1; $mozext_bytes += $field{bytes_transfered}; } elsif ($field{http_rc} =~ /3\d\d/) { $redirect_count += 1; $redirect_bytes += $field{bytes_transfered}; } elsif ($field{method} =~ /CONNECT/) { $proxy_count += 1; $proxy_bytes += $field{bytes_transfered}; $proxy_host{"$field{client_ip} -> $field{base_url}"}++; } else { $other_count += 1; $other_bytes += $field{bytes_transfered}; } if ( ($field{http_rc} >= 400) && !shouldIgnore("needs_exam") ) { my $fmt_url = $field{url}; if (length($field{url}) > 60) { $fmt_url = substr($field{url},0,42) . " ... " . substr($field{url},-15,15); } $needs_exam{$field{http_rc}}{$fmt_url}++; } if (defined $field{userid} && $field{userid} ne "-" && (eval $user_display) && !shouldIgnore("users_logged") ) { $users_logged{$field{userid}}{$field{client_ip}}++; } ## ## Do the > 4 stuff ## # # Response Summary # if ($field{http_rc} > 499 ) { $a5xx_resp += 1; } elsif ($field{http_rc} > 399 ) { $a4xx_resp += 1; } elsif($field{http_rc} > 299 ) { $a3xx_resp += 1; } elsif($field{http_rc} > 199 ) { $a2xx_resp += 1; } else { $a1xx_resp += 1; } # # Count the robots who actually ask for the robots.txt file # if ($field{lc_url} =~ /^\/robots.txt$/) { if (defined $field{agent}) { if ($field{agent} eq "-") {$field{agent} = '(Unidentified agent)'}; $robots{$field{agent}} +=1; } } } ## End of while loop ############################################# ## output the results ## if ($detail >4) { printf "%.2f MB transferred " , $byte_summary/(1024*1024); print "in "; print my $resp_total = ($a1xx_resp + $a2xx_resp + $a3xx_resp + $a4xx_resp + $a5xx_resp); print " responses "; print " (1xx $a1xx_resp, 2xx $a2xx_resp, 3xx $a3xx_resp,"; print " 4xx $a4xx_resp, 5xx $a5xx_resp) \n"; my $lr = length($resp_total); if ($image_count > 0) { printf " %*d Images (%.2f MB),\n" , $lr, $image_count, $image_bytes/(1024*1024); } if ($docs_count > 0) { printf " %*d Documents (%.2f MB),\n" , $lr, $docs_count, $docs_bytes/(1024*1024); } if ($archive_count > 0) { printf " %*d Archives (%.2f MB),\n" , $lr, $archive_count, $archive_bytes/(1024*1024); } if ($sound_count > 0) { printf " %*d Sound files (%.2f MB),\n" , $lr, $sound_count, $sound_bytes/(1024*1024); } if ($movie_count > 0) { printf " %*d Movies files (%.2f MB),\n" , $lr, $movie_count, $movie_bytes/(1024*1024); } if ($winexec_count > 0) { printf " %*d Windows executable files (%.2f MB),\n" , $lr, $winexec_count, $winexec_bytes/(1024*1024); } if ($content_count > 0) { printf " %*d Content pages (%.2f MB),\n" , $lr, $content_count, $content_bytes/(1024*1024); } if ($redirect_count > 0) { printf " %*d Redirects (%.2f MB),\n" , $lr, $redirect_count, $redirect_bytes/(1024*1024); } if ($wpad_count > 0) { printf " %*d Proxy Configuration Files (%.2f MB),\n" , $lr, $wpad_count, $wpad_bytes/(1024*1024); } if ($src_count > 0) { printf " %*d Program source files (%.2f MB),\n" , $lr, $src_count, $src_bytes/(1024*1024); } if ($images_count > 0) { printf " %*d CD Images (%.2f MB),\n" , $lr, $images_count, $images_bytes/(1024*1024); } if ($logs_count > 0) { printf " %*d Various Logs (%.2f MB),\n" , $lr, $logs_count, $logs_bytes/(1024*1024); } if ($fonts_count > 0) { printf " %*d Fonts (%.2f MB),\n" , $lr, $fonts_count, $fonts_bytes/(1024*1024); } if ($config_count > 0) { printf " %*d Configs (%.2f MB),\n" , $lr, $config_count, $config_bytes/(1024*1024); } if ($xpcomext_count > 0) { printf " %*d XPCOM Type Libraries (%.2f MB),\n" , $lr, $xpcomext_count, $xpcomext_bytes/(1024*1024); } if ($mozext_count > 0) { printf " %*d Mozilla extensions (%.2f MB),\n" , $lr, $mozext_count, $mozext_bytes/(1024*1024); } if ($proxy_count > 0) { printf " %*d mod_proxy requests (%.2f MB),\n" , $lr, $proxy_count, $proxy_bytes/(1024*1024); } if ($other_count > 0) { printf " %*d Other (%.2f MB) \n" , $lr, $other_count, $other_bytes/(1024*1024); } } # # List attempted exploits # if (($detail >4) and $total_hack_count) { print "\nAttempts to use known hacks by ".(keys %hacks). " hosts were logged $total_hack_count time(s) from:\n"; my $order = TotalCountOrder(%hacks); foreach my $i (sort $order keys %hacks) { my $hacks_per_ip = 0; foreach my $j ( keys %{$hacks{$i}} ) { $hacks_per_ip += $hacks{$i}{$j}; } print " $i: $hacks_per_ip Time(s)\n"; if ($detail > 9) { foreach my $j ( keys %{$hacks{$i}} ) { print " $j $hacks{$i}{$j} Time(s) \n"; } } } } if (keys %proxy_host) { print "\nConnection attempts using mod_proxy:\n"; foreach $host (sort {$a cmp $b} keys %proxy_host) { print " $host: $proxy_host{$host} Time(s)\n"; } } # # List (wannabe) blackhat sites # if (keys %ban_ip and $detail) { print "\nA total of ".scalar(keys %ban_ip)." sites probed the server \n"; if ($detail > 4) { foreach my $i (sort keys %ban_ip) { print " $i\n"; } } } # # List possible successful probes # if (keys %hack_success) { print "\nA total of " . scalar(keys %hack_success) . " possible successful probes were detected (the following URLs\n"; print "contain strings that match one or more of a listing of strings that\n"; print "indicate a possible exploit):\n\n"; foreach my $i (keys %hack_success) { print " $i HTTP Response $hack_success{$i} \n"; } } # # List error response codes # if (keys %needs_exam and ($detail or $a5xx_resp)) { print "\nRequests with error response codes\n"; for my $code (sort keys %needs_exam) { if (not defined $StatusCode{$code}) { $StatusCode{$code} = "\(undefined\)"; } if ($detail || ($code >= 500) || (($ENV{"http_rc_detail_rep_$code"} || $detail) < $detail)) { if ( ($ENV{"http_rc_detail_rep_$code"} || $detail) > $detail ) { # only display summary for this code my $t = 0; my $u = 0; foreach my $k ( keys %{$needs_exam{$code}}) { $u += 1; $t += $needs_exam{$code}{$k}; } print " $code $StatusCode{$code} SUMMARY - $u URLs, total: $t Time(s)\n"; } else { print " $code $StatusCode{$code}\n"; for my $url (sort { ($needs_exam{$code}{$b} <=> $needs_exam{$code}{$a}) or ($a cmp $b) } keys %{$needs_exam{$code}}) { print " $url: $needs_exam{$code}{$url} Time(s)\n"; } } } } } if (keys %users_logged) { print "\nUsers logged successfully\n"; for my $user (sort keys %users_logged) { my %userips = %{$users_logged{$user}}; # If one user name logged from many IPs, don't print them all. 5 is arbitrary if (scalar(keys %userips) > 5) { my $count = 0; for my $ip (keys %userips) { $count += $userips{$ip}; } print " $user: $count Time(s) from ".scalar(keys %userips)." addresses\n"; } else { print " $user\n"; for my $ip (sort keys %userips) { print " $ip: $userips{$ip} Time(s)\n"; } } } } # # List robots that identified themselves # if (keys %robots and ($detail > 4)) { print "\nA total of ".scalar(keys %robots)." ROBOTS were logged \n"; foreach my $i (keys %robots) { if ($detail > 9) { print " $i $robots{$i} Time(s) \n"; } } } if ($notparsed) { print "\nThis is a listing of log lines that were not parsed correctly.\n"; print "Perhaps the variable \$LogFormat in file conf/services/http.conf\n"; print "is not correct?\n\n"; if ($notparsed_count > 10) { print "(Only the first ten are printed; there were a total of $notparsed_count)\n"; } print $notparsed; } exit (0); sub shouldIgnore { my($context)=@_; if( ((defined $ignoreURLs) && ($field{url} =~ /$ignoreURLs/i)) || ((defined $ignoreIPs) && ($field{client_ip} =~ /$ignoreIPs/)) ) { return 1; } return (eval $ignoreEval); } # vi: shiftwidth=3 tabstop=3 syntax=perl et # Local Variables: # mode: perl # perl-indent-level: 3 # indent-tabs-mode: nil # End: logwatch-7.12/scripts/services/sudo0000664000211400021140000001570114736640305017670 0ustar logwatchlogwatch ######################################################## # Please file all bug reports, patches, and feature # requests under: # https://sourceforge.net/p/logwatch/_list/tickets # Help requests and discusion can be filed under: # https://sourceforge.net/p/logwatch/discussion/ ######################################################## ########################################################################### # sudo: A logwatch script to collate and format sudo log entries from # the secure log. Entries are broken down by the user who issued # the command, and further by the effective user of the command. # # Detail Levels: # 0: Just print the command # 20: Include the current directory when the command was executed # (on a separate line) # 30: Include the TTY on the directory line ########################################################################### ####################################################### ## Copyright (c) 2008 Kirk Bauer ## Covered under the included MIT/X-Consortium License: ## http://www.opensource.org/licenses/mit-license.php ## All modifications and contributions by other persons to ## this script are assumed to have been donated to the ## Logwatch project and thus assume the above copyright ## and licensing terms. If you want to make contributions ## under your own copyright or a different license this ## must be explicitly stated in the contribution an the ## Logwatch project reserves the right to not accept such ## contributions. If you have made significant ## contributions to this script and want to claim ## copyright please contact logwatch-devel@lists.sourceforge.net. ######################################################### use strict; my %OtherList; my (%byUser, %byUserSum); my $Debug = $ENV{'LOGWATCH_DEBUG'} || 0; my $Detail = $ENV{'sudo_detail'} || $ENV{'LOGWATCH_DETAIL_LEVEL'} || 0; # maximum number of commands user ran to display at low detail my $CmdsThresh = $ENV{'command_run_threshold'} || 0; my %IgnoreCmds; my %IgnoreCmdArgs; my ($user, $error, $tty, $dir, $euser, $egroup, $tsid, $cmd, $args); my %ConFailed; my %ParseErrors; my $contlines = 0; my $argsprinted = 0; if (defined($ENV{'ignore_commands'})) { foreach my $entry (split(',',$ENV{'ignore_commands'})) { $entry =~ s/['"]//g; my ($from_user,$to_user,$cmd) = split(';',$entry); if ($cmd =~ " ") { push(@{$IgnoreCmdArgs{$from_user}{$to_user}},$cmd); } else { push(@{$IgnoreCmds{$from_user}{$to_user}},$cmd); } } } while (defined(my $ThisLine = )) { if ($ThisLine =~ /pam_unix\(sudo:auth\): authentication failure; logname=\S* uid=[0-9]* euid=[0-9]* tty=\S* ruser=\S* rhost=\S* user=\S*/ or # handled in pam_unix $ThisLine =~ /pam_unix\(sudo:auth\): auth could not identify password for/ or $ThisLine =~ /pam_unix\(sudo:auth\): Couldn't open / or $ThisLine =~ /pam_unix\(sudo:session\): session (?:opened|closed) for user \S+/ or $ThisLine =~ /pam_sss\(sudo:auth\): (?:authentication|received for user) / or $ThisLine =~ /pam_sss\(sudo:auth\): User info message:/ or $ThisLine =~ /pam_systemd\(sudo:session\): Cannot create session: Already (?:running in|occupied by) a session/ or $ThisLine =~ /pam_systemd\(sudo:session\): Failed to create session: Start job for unit user-0.slice failed with 'canceled'/ ) { # Ignore } elsif ($ThisLine =~ /(.+): conversation failed/) { $ConFailed{$1}++; } elsif ($ThisLine =~ /parse error in (.*)/) { $ParseErrors{$1}++; } elsif ( ($user, $error, $tty, $dir, $euser, $egroup, $tsid, $cmd, $args) = $ThisLine =~ m/^\s*(\S+) : ([^=]+; )?(?:TTY=(\S+) ; )?PWD=(.*?) ; USER=(\S+) ;(?: GROUP=(\S+) ;)?(?: TSID=(\S+) ;)? COMMAND=(\S+)( ?.*)/) { next if (defined($IgnoreCmds{$user}{$euser}) && $cmd =~ join("|",@{$IgnoreCmds{$user}{$euser}})); next if (defined($IgnoreCmds{'any'}{$euser}) && $cmd =~ join("|",@{$IgnoreCmds{'any'}{$euser}})); next if (defined($IgnoreCmds{$user}{'any'}) && $cmd =~ join("|",@{$IgnoreCmds{$user}{'any'}})); next if (defined($IgnoreCmdArgs{$user}{$euser}) && "$cmd$args" =~ join("|",@{$IgnoreCmdArgs{$user}{$euser}})); next if (defined($IgnoreCmdArgs{'any'}{$euser}) && "$cmd$args" =~ join("|",@{$IgnoreCmdArgs{'any'}{$euser}})); next if (defined($IgnoreCmdArgs{$user}{'any'}) && "$cmd$args" =~ join("|",@{$IgnoreCmdArgs{$user}{'any'}})); if ($egroup) { $euser .= ":${egroup}"; } push @{$byUser{$user}{$euser}}, [((defined $error)? $error : "") . $cmd, $args, $dir, $tty]; $byUserSum{$user}{$euser}{$cmd} += 1; } elsif ( ($user,$euser) = $ThisLine =~ /^\s*(\S+) : no passwd entry for (\S+)\!$/) { push @{$byUser{$user}{$euser . " (No such user)"}}, ["No password entry"]; } elsif ( $ThisLine =~ m/^\s*\S+ : \(command continued\)/ ) { $contlines++; } else { chomp($ThisLine); $OtherList{$ThisLine}++; } } if (keys %ParseErrors) { print "\nConfiguration parse errors:"; print "\n---------------------------"; foreach my $error (sort keys %ParseErrors) { printf "\n%-30s - %3i Time(s)", $error, $ParseErrors{$error}; } print "\n"; } foreach my $user (sort keys %byUser) { foreach my $euser (sort keys %{$byUser{$user}}) { print "\n$user => $euser\n", "-" x length("$user => $euser"), "\n"; foreach my $cmd (sort keys %{$byUserSum{$user}{$euser}}) { if ($Detail < 10 && $CmdsThresh <= $byUserSum{$user}{$euser}{$cmd}) { printf "%-30s - %3i Time(s).\n", $cmd, $byUserSum{$user}{$euser}{$cmd}; } # if $Detail < 10 } # foreach $gcmd foreach my $row (@{$byUser{$user}{$euser}}) { if ($Detail >= 10 || $CmdsThresh > $byUserSum{$user}{$euser}{$$row[0]}) { my ($gcmd, $args, $dir, $tty) = @$row; my $cmd = "$gcmd$args"; # make long commands easier to read $cmd =~ s/(?=.{74,})(.{1,74}) /${1} \\\n /g if (length($cmd) > 75); print "$cmd\n"; if ($Detail >= 20) { my $ttydetail = ""; $ttydetail = "($tty) " if $Detail >= 30; print "\t$ttydetail$dir\n"; } # if $Detail >= 20 $argsprinted=1; } # if $Detail >= 10 } # foreach $row } # foreach $euser } # foreach $user if (keys %ConFailed) { print "\nConversation failed with:"; print "\n-------------------------"; foreach my $conv (sort keys %ConFailed) { printf "\n%-30s - %3i Time(s)", $conv, $ConFailed{$conv}; } print "\n"; } if($contlines && $argsprinted) { print "\nThe argument list of some of above commands might be incomplete\n"; } if (keys %OtherList) { print "\n\n**Unmatched Entries**"; foreach my $line (sort {$OtherList{$b}<=>$OtherList{$a} } keys %OtherList) { print "\n $line: $OtherList{$line} Time(s)"; } } # vi: shiftwidth=3 tabstop=3 syntax=perl et # Local Variables: # mode: perl # perl-indent-level: 3 # indent-tabs-mode: nil # End: logwatch-7.12/scripts/services/knockd0000664000211400021140000000505414743365004020165 0ustar logwatchlogwatch ######################################################## # Please file all bug reports, patches, and feature # requests under: # https://sourceforge.net/p/logwatch/_list/tickets # Help requests and discusion can be filed under: # https://sourceforge.net/p/logwatch/discussion/ ######################################################## ######################################################## # Copyright (c) 2013 Brian Masney ## Covered under the included MIT/X-Consortium License: ## http://www.opensource.org/licenses/mit-license.php ## All modifications and contributions by other persons to ## this script are assumed to have been donated to the ## Logwatch project and thus assume the above copyright ## and licensing terms. If you want to make contributions ## under your own copyright or a different license this ## must be explicitly stated in the contribution an the ## Logwatch project reserves the right to not accept such ## contributions. If you have made significant ## contributions to this script and want to claim ## copyright please contact logwatch-devel@lists.sourceforge.net. ######################################################### use strict; my %commands; my %stages; my %unknown; while (defined(my $ThisLine = )) { chomp($ThisLine); next if $ThisLine =~ /^starting up, listening on /; next if $ThisLine =~ /OPEN SESAME$/; next if $ThisLine =~ /: sequence timeout /; my ($name, $command) = $ThisLine =~ /^(.*?): running command: (.*)/; if (defined($name)) { $commands{"$name: $command"}++; next; } my ($ip, $name, $stage) = $ThisLine =~ /^(\d+\.\d+\.\d+\.\d+): (.*?): Stage (\d+)/; if (defined ($ip)) { $stages{$name}{$stage}{$ip}++; next; } $unknown{$ThisLine}++; } if (keys %stages) { print "knockd stages reached\n"; foreach my $name (sort keys %stages) { print "\t$name\n"; foreach my $stage (sort keys %{$stages{$name}}) { print "\t\tStage $stage\n"; foreach my $ip (sort keys %{$stages{$name}{$stage}}) { print "\t\t\tFrom $ip: " . $stages{$name}{$stage}{$ip} . " time(s)\n"; } } } } if (keys %commands) { print "\n"; print "knockd commands executed\n"; foreach my $command (sort keys %commands) { print "\t" . $commands{$command} . " time(s): $command\n"; } } if (keys %unknown) { print "\n"; print "knockd unknown log entries\n"; foreach my $line (sort keys %unknown) { print "\t" . $unknown{$line} . " time(s): $line\n"; } } logwatch-7.12/scripts/services/netscreen0000664000211400021140000005424614274101040020674 0ustar logwatchlogwatch ######################################################## # Please file all bug reports, patches, and feature # requests under: # https://sourceforge.net/p/logwatch/_list/tickets # and copy: # Laurent DUFOUR # Help requests and discusion can be filed under: # https://sourceforge.net/p/logwatch/discussion/ ######################################################## ######################################################## # This was written and is maintained by: # Laurent DUFOUR , # based on the work of # Kirk Bauer # # Please send all comments, suggestions, bug reports, # etc, to laurent.dufour@havas.com ######################################################## ##################################################### ## Copyright (c) 2008 Laurent DUFOUR ## Covered under the included MIT/X-Consortium License: ## http://www.opensource.org/licenses/mit-license.php ## All modifications and contributions by other persons to ## this script are assumed to have been donated to the ## Logwatch project and thus assume the above copyright ## and licensing terms. If you want to make contributions ## under your own copyright or a different license this ## must be explicitly stated in the contribution an the ## Logwatch project reserves the right to not accept such ## contributions. If you have made significant ## contributions to this script and want to claim ## copyright please contact logwatch-devel@lists.sourceforge.net. ######################################################### use Logwatch ':all'; use strict; my $Debug = ValueOrDefault($ENV{'LOGWATCH_DEBUG'}, 0); my $Detail = ValueOrDefault($ENV{'LOGWATCH_DETAIL_LEVEL'}, 0); my $DebugCounter = 0; #Init String Containers my ( $Temp, $dst_ip, $interface, $src_ip, ); #Init hashes my ( %BadLogins, %BadSPI, %DHCPAssigned, %DHCPReleased, %DNSRefreshed, %HeartBeatDisabled, %HeartBeatLost, %HeartBeatMissing, %IllegalUsers, %InitAggMode, %InitMainMode, %InitPh2, %NTPFailed, %NTPUpdated, %NegoCompleted, %Ph1Aborted, %Ph1CompleteAggMode, %Ph1CompleteMainMode, %Ph1DstStartAggMode, %Ph1DstStartMainMode, %Ph2NegoAdded, %Ph2NegoAlready, %Ph2RcvMsg, %ReceiveDOI, %ReceivedDOI, %ReloadRequested, %Restarted, %RetransmissionReached, %Started, %SysCfgSaved, %SyslogFacility, %SyslogHost, %Users, %VPNDown, %VPNUp, ); #Init Array my @OtherList = (); # Avoid "Use of uninitialized value" warning messages. sub ValueOrDefault { my ($value, $default) = @_; return ($value ? $value : $default); } if ( $Debug >= 5 ) { print STDERR "\n\nDEBUG: Inside NETSCREEN Filter \n\n"; $DebugCounter = 1; } my ($month,$day,$time,$host_ip,$host,$conn,$msg,$message); while (defined(my $ThisLine = )) { if ( $Debug >= 30 ) { print STDERR "DEBUG($DebugCounter): $ThisLine"; $DebugCounter++; } ($month,$day,$time,$host_ip,$host,$msg)=split(/ +/,$ThisLine,7); if ( ($ThisLine =~ /traffic/ ) or ($ThisLine =~ /Copyright/ ) or ($ThisLine =~ /removed due to simultaneous rekey/ ) or ($ThisLine =~ /Responded to the first peer message/ ) or ($ThisLine =~ /NBR change/ ) or ($ThisLine =~ /accept udp/ ) or ($ThisLine =~ /accept tcp/ ) or ($ThisLine =~ /accept icmp/ ) or ($ThisLine =~ /accept ip/ ) or ($ThisLine =~ /denied udp/ ) or ($ThisLine =~ /denied tcp/ ) or ($ThisLine =~ /denied icmp/ ) or ($ThisLine =~ /denied ip/ ) ) { # don't care about this, will code this later } elsif ( ($interface) = ($ThisLine =~ /vpn "(.*)" is up./) ) { $VPNUp{$host}{$interface}++; } elsif ( ($interface) = ($ThisLine =~ /vpn "(.*)" is down./) ) { $VPNDown{$host}{$interface}++; } elsif ( ($src_ip,$dst_ip,$msg) = ($ThisLine =~ /IKE<(.+)> >> <(.+)> Phase 1: Initiated negotiations in aggressive mode. (.*)/) ) { $InitAggMode{$host}{$src_ip," ",$dst_ip}++; } elsif ( ($src_ip,$dst_ip,$msg) = ($ThisLine =~ /IKE<(.+)> >> <(.+)> Phase 1: Initiated negotiations in main mode. (.*)/) ) { $InitMainMode{$host}{$src_ip," ",$dst_ip}++; } elsif ( ($dst_ip,$msg) = ($ThisLine =~ /IKE<(.+)> Phase 2: Initiated negotiation. (.*)/) ) { $InitPh2{$host}{$dst_ip}++; } elsif ( ($dst_ip,$msg) = ($ThisLine =~ /IKE<(.+)> Phase 1: Completed Main mode negotiations (.*)/) ) { $Ph1CompleteMainMode{$host}{$dst_ip}++; } elsif ( ($dst_ip,$msg) = ($ThisLine =~ /IKE<(.+)> Phase 1: Aborted negotiations because the time limit has elapsed. (.*)/) ) { $Ph1Aborted{$host}{$dst_ip}++; } elsif ( ($dst_ip,$msg) = ($ThisLine =~ /IKE<(.+)> Phase 1: Completed Aggressive mode negotiations (.*)/) ) { $Ph1CompleteAggMode{$host}{$dst_ip}++; } elsif ( ($dst_ip,$msg) = ($ThisLine =~ /IKE<(.+)> Heartbeats have been disabled because the peer is not sending them. (.*)/) ) { $HeartBeatDisabled{$host}{LookupIP($dst_ip)}++; } elsif ( ($dst_ip,$msg) = ($ThisLine =~ /IKE<(.+)> Heartbeats have been lost (.*)/) ) { $HeartBeatLost{$host}{LookupIP($dst_ip)}++; } elsif ( ($dst_ip,$msg) = ($ThisLine =~ /IKE<(.+)> Received notify message for DOI (.*)/) ) { $ReceiveDOI{$host}{LookupIP($dst_ip)}++; } elsif ( ($dst_ip,$msg) = ($ThisLine =~ /IKE<(.+)> Missing heartbeats have exceeded the threshold. (.*)/) ) { $HeartBeatMissing{$host}{LookupIP($dst_ip)}++; } elsif ( ($dst_ip,$msg) = ($ThisLine =~ /IKE<(.+)>: Received a bad SPI (.*)/) ) { $BadSPI{$host}{$dst_ip}++; } elsif ( ($dst_ip,$msg) = ($ThisLine =~ /IKE<(.+)> Phase 1: Responder starts AGGRESSIVE mode negotiations. (.*)/) ) { $Ph1DstStartAggMode{$host}{$dst_ip}++; } elsif ( ($dst_ip,$msg) = ($ThisLine =~ /IKE<(.+)> Phase 1: Responder starts MAIN mode negotiations. (.*)/) ) { $Ph1DstStartMainMode{$host}{$dst_ip}++; } elsif ( ($dst_ip,$msg) = ($ThisLine =~ /IKE<(.+)> Added Phase 2 session tasks to the task list. (.*)/) ) { $Ph2NegoAdded{$host}{$dst_ip}++; } elsif ( ($dst_ip,$msg) = ($ThisLine =~ /IKE<(.+)> Phase 2 negotiation request is already in the task list. (.*)/) ) { $Ph2NegoAlready{$host}{$dst_ip}++; } elsif ( ($dst_ip,$msg) = ($ThisLine =~ /System Config saved from host (\d+\.\d+\.\d+\.\d+) (.*)/) ) { $SysCfgSaved{$host}{LookupIP($dst_ip)}++; } elsif ( ($dst_ip,$msg) = ($ThisLine =~ /The system configuration was saved from host (.+) by (.*)/) ) { $SysCfgSaved{$host}{LookupIP($dst_ip)}++; } elsif ( ($dst_ip,$msg) = ($ThisLine =~ /IKE<(.+)> Phase 2: Received a message but did not check a policy because id-mode is set to IP or policy-checking is disabled. (.*)/) ) { $Ph2RcvMsg{$host}{$dst_ip}++; } elsif ( ($ThisLine =~ /Compiled/) ) { $Started{$host}++; } elsif ( ($ThisLine =~ /Phase 1: Retransmission limit has been reached./) ) { $RetransmissionReached{$host}++; } elsif ( ($ThisLine =~ /Completed negotiations with SPI/) ) { $NegoCompleted{$host}++; } elsif ( ($ThisLine =~ /DNS entries have been automatically refreshed./) ) { $DNSRefreshed{$host}++; } elsif ( ($ThisLine =~ /DNS has been refreshed./) ) { $DNSRefreshed{$host}++; } elsif ( ($ThisLine =~ /Syslog host domain name has been changed/) ) { $SyslogHost{$host}++; } elsif ( ($ThisLine =~ /Syslog facility has been changed/) ) { $SyslogFacility{$host}++; } elsif ( ($ThisLine =~ /Syslog security facility has been changed/) ) { $SyslogFacility{$host}++; } elsif ( ($ThisLine =~ /The system clock has been updated through NTP./) ) { $NTPUpdated{$host}++; } elsif ( ($ThisLine =~ /failed to get clock through NTP/) ) { $NTPFailed{$host}++; } elsif ( ($message) = ($ThisLine =~ /A DHCP- assigned IP address (.*)/) ) { $DHCPAssigned{$host}{"A DHCP- assigned IP address"}++; } elsif ( ($message) = ($ThisLine =~ /One or more DHCP-assigned IP addresses have been manually released. (.*)/) ) { $DHCPReleased{$host}{"One or more DHCP-assigned IP addresses have been manually released."}++; } elsif ( ($message) = ($ThisLine =~ /RELOAD: (.*)/) ) { $ReloadRequested{$host}{$message}++; } elsif ( ($message) = ($ThisLine =~ /RESTART: (.*)/) ) { $Restarted{$host}{$message}++; } elsif ( ($interface) = ($ThisLine =~ /Admin User "(\S+)" logged in for Web\((\S+)\) management \(port (\d+)\) from (.+):(.+). (.*)/) ) { if ($Debug >= 5) { print STDERR "DEBUG: Found -$1 logged in from $4 using $2\n"; } if ($Detail >= 20) { $Users{$host}{$2}{$4}{$1}++; } else { $Users{$host}{$2}{$4}{"(all)"}++; } } elsif ( $ThisLine =~ m/Admin user (\S+) login attempt for (\S+) management \(port (\d+)\) from (.+):(.+). failed. (.*)/ ) { if ( $Debug >= 5 ) { print STDERR "DEBUG: Found -Failed login- line\n"; } my $name = LookupIP($4); $BadLogins{$host}{"$1/$2 from $name"}++; } elsif ( $ThisLine =~ m/SSH client at (.+) has attempted to make an SCS connection to interface untrust with IP (.+) but failed (.*)/ ) { my $name = LookupIP($2); $Temp = "SSH from $name"; $BadLogins{$host}{$Temp}++; $IllegalUsers{$host}{$Temp}++; } else { # Report any unmatched entries... push @OtherList,$ThisLine; } } if (keys %Started) { print "\nDevice started :\n"; foreach my $ThisOne (keys %Started) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (keys %{$Started{$ThisOne}}) { print "\t Started" .$ThatOne . "\t: " . $Started{$ThisOne}{$ThatOne} . "{ Time(s)\n"; } } } if (keys %RetransmissionReached) { print "\nDevice where retransmission limit has been reached:\n"; foreach my $ThisOne (keys %RetransmissionReached) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (keys %{$RetransmissionReached{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $RetransmissionReached{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if ( ( $Detail >= 15 ) and (keys %NegoCompleted) ) { print "\nDevice wich completed negotiations with SPI:\n"; foreach my $ThisOne (keys %NegoCompleted) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (keys %{$NegoCompleted{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $NegoCompleted{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if (keys %NTPUpdated) { print "\nDevice where The system clock has been updated through NTP :\n"; foreach my $ThisOne (keys %NTPUpdated) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (keys %{$NTPUpdated{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $NTPUpdated{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if (keys %NTPFailed) { print "\nDevice where failed to get clock through NTP :\n"; foreach my $ThisOne (keys %NTPFailed) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (keys %{$NTPFailed{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $NTPFailed{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if (keys %DNSRefreshed) { print "\nDevice where DNS have been refreshed :\n"; foreach my $ThisOne (keys %DNSRefreshed) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (keys %{$DNSRefreshed{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $DNSRefreshed{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if (keys %DNSRefreshed) { print "\nDevice where DNS have been refreshed :\n"; foreach my $ThisOne (keys %DNSRefreshed) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (keys %{$DNSRefreshed{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $DNSRefreshed{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if ( ( $Detail >= 15 ) and (keys %DHCPAssigned) ) { print "\nDevice where DHCP have been assigned :\n"; foreach my $ThisOne (keys %DHCPAssigned) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (keys %{$DHCPAssigned{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $DHCPAssigned{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if ( ( $Detail >= 15 ) and (keys %DHCPReleased) ) { print "\nDevice where DHCP have been released :\n"; foreach my $ThisOne (keys %DHCPReleased) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (keys %{$DHCPReleased{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $DHCPReleased{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if (keys %SyslogFacility) { print "\nDevice where Syslog facility has been changed :\n"; foreach my $ThisOne (keys %SyslogFacility) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (keys %{$SyslogFacility{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $SyslogFacility{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if (keys %SyslogHost) { print "\nDevice where Syslog host has been changed :\n"; foreach my $ThisOne (keys %SyslogHost) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (keys %{$SyslogHost{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $SyslogHost{$ThisOne}{$ThisOne} . " Time(s)\n"; } } } if (keys %Restarted) { print "\nDevice restarted :\n"; foreach my $ThisOne (keys %Restarted) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (keys %{$Restarted{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $Restarted{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if (keys %ReloadRequested) { print "\nDevice reload requested :\n"; foreach my $ThisOne (keys %ReloadRequested) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (keys %{$ReloadRequested{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $ReloadRequested{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if (keys %HeartBeatDisabled) { print "\nDevice where heartbeat have been disabled because of peer :\n"; foreach my $ThisOne (keys %HeartBeatDisabled) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (keys %{$HeartBeatDisabled{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $HeartBeatDisabled{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if (keys %HeartBeatLost) { print "\nDevice where heartbeat have been lost :\n"; foreach my $ThisOne (keys %HeartBeatLost) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (keys %{$HeartBeatLost{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $HeartBeatLost{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if (keys %HeartBeatMissing) { print "\nDevice where missing heartbeats have exceeded the threshold. :\n"; foreach my $ThisOne (keys %HeartBeatMissing) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (keys %{$HeartBeatMissing{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $HeartBeatMissing{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if (keys %BadSPI) { print "\nDevice receiving a bad SPI :\n"; foreach my $ThisOne (keys %BadSPI) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (keys %{$BadSPI{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $BadSPI{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if (keys %ReceivedDOI) { print "\nDevice where notify message for DOI hed been received :\n"; foreach my $ThisOne (keys %ReceivedDOI) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (keys %{$ReceivedDOI{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $ReceivedDOI{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if (keys %VPNUp) { print "\nVPN Up on :\n"; foreach my $ThisOne (keys %VPNUp) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (keys %{$VPNUp{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $VPNUp{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if (keys %VPNDown) { print "\nVPN Down on :\n"; foreach my $ThisOne (keys %VPNDown) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (keys %{$VPNDown{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $VPNDown{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if ($Detail >= 15) { if (keys %InitAggMode) { print "\nDevice initiating phase 1 aggressive mode:\n"; foreach my $ThisOne (keys %InitAggMode) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (keys %{$InitAggMode{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $InitAggMode{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if (keys %InitMainMode) { print "\nDevice initiating phase 1 main mode:\n"; foreach my $ThisOne (keys %InitMainMode) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (keys %{$InitMainMode{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $InitMainMode{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if (keys %Ph1DstStartAggMode) { print "\nDevice with Phase 1: Responder starts AGGRESSIVE mode negotiations. :\n"; foreach my $ThisOne (keys %Ph1DstStartAggMode) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (keys %{$Ph1DstStartAggMode{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $Ph1DstStartAggMode{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if (keys %Ph1DstStartMainMode) { print "\nDevice with Phase 1: Responder starts MAIN mode negotiations. :\n"; foreach my $ThisOne (keys %Ph1DstStartMainMode) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (keys %{$Ph1DstStartMainMode{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $Ph1DstStartMainMode{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if (keys %Ph1CompleteAggMode) { print "\nDevice with Phase 1: Completed Aggressive mode negotiations :\n"; foreach my $ThisOne (keys %Ph1CompleteAggMode) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (keys %{$Ph1CompleteAggMode{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $Ph1CompleteAggMode{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if (keys %Ph1CompleteMainMode) { print "\nDevice with Phase 1: Completed Main mode negotiations :\n"; foreach my $ThisOne (keys %Ph1CompleteMainMode) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (keys %{$Ph1CompleteMainMode{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $Ph1CompleteMainMode{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if (keys %Ph1Aborted) { print "\nDevice with Phase 1: Aborted negotiations because the time limit has elapsed. :\n"; foreach my $ThisOne (keys %Ph1Aborted) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (keys %{$Ph1Aborted{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $Ph1Aborted{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if (keys %InitPh2) { print "\nDevice initiating phase 2 :\n"; foreach my $ThisOne (keys %InitPh2) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (keys %{$InitPh2{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $InitPh2{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if (keys %Ph2NegoAdded) { print "\nDevice with Added Phase 2 session tasks to the task list. :\n"; foreach my $ThisOne (keys %Ph2NegoAdded) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (keys %{$Ph2NegoAdded{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $Ph2NegoAdded{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if (keys %Ph2NegoAlready) { print "\nDevice with Phase 2 negotiation request is already in the task list. :\n"; foreach my $ThisOne (keys %Ph2NegoAlready) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (keys %{$Ph2NegoAlready{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $Ph2NegoAlready{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if (keys %Ph2RcvMsg) { print "\nDevice with Phase 2: Received a message but did not check a policy because id-mode is set to IP or policy-checking is disabled. :\n"; foreach my $ThisOne (keys %Ph2RcvMsg) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (keys %{$Ph2RcvMsg{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $Ph2RcvMsg{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } } if (keys %SysCfgSaved) { print "\nDevice where system config have been saved :\n"; foreach my $ThisOne (keys %SysCfgSaved) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (keys %{$SysCfgSaved{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $SysCfgSaved{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if (keys %BadLogins) { print "\nFailed logins from these:\n"; foreach my $ThisOne (keys %BadLogins) { print " " . $ThisOne . ":\n"; for (sort keys %{$BadLogins{$ThisOne}}) { print "\t $_: $BadLogins{$ThisOne}{$_} Time(s)\n"; } } } if (keys %IllegalUsers) { print "\nIllegal users from these:\n"; foreach my $ThisOne (keys %IllegalUsers) { print " " . $ThisOne . ":\n"; for (sort keys %{$IllegalUsers{$ThisOne}}) { print "\t $_: $IllegalUsers{$ThisOne}{$_} Time(s)\n"; } } } if (keys %Users) { print "\nUsers logging in through :\n"; foreach my $ThisOne (keys %Users) { print " " . $ThisOne . ":\n"; foreach my $user (sort {$a cmp $b} keys %{$Users{$ThisOne}}) { print " $user:\n"; my $totalSort = TotalCountOrder(%{$Users{$ThisOne}{$user}}, \&SortIP); foreach my $ip (sort $totalSort keys %{$Users{$ThisOne}{$user}}) { my $name = LookupIP($ip); if ($Detail >= 20) { print " $name:\n"; my $sort = CountOrder(%{$Users{$ThisOne}{$user}{$ip}}); foreach my $method (sort $sort keys %{$Users{$ThisOne}{$user}{$ip}}) { my $val = $Users{$ThisOne}{$user}{$ip}{$method}; my $plural = ($val > 1) ? "s" : ""; print " $method: $val time$plural\n"; } } else { my $val = (values %{$Users{$ThisOne}{$user}{$ip}})[0]; my $plural = ($val > 1) ? "s" : ""; print " $name: $val time$plural\n"; } } } } } if ($#OtherList >= 0) { print "\n**Unmatched Entries**\n"; print @OtherList; } exit(0); # Local Variables: # mode: perl # perl-indent-level: 3 # indent-tabs-mode: nil # End: logwatch-7.12/scripts/services/zz-sys0000664000211400021140000000444414462364761020204 0ustar logwatchlogwatch ######################################################## # Please file all bug reports, patches, and feature # requests under: # https://sourceforge.net/p/logwatch/_list/tickets # Help requests and discusion can be filed under: # https://sourceforge.net/p/logwatch/discussion/ ######################################################## ######################################################## ####################################################### ## Copyright (c) 2008 Laurent Dufour ## Covered under the included MIT/X-Consortium License: ## http://www.opensource.org/licenses/mit-license.php ## All modifications and contributions by other persons to ## this script are assumed to have been donated to the ## Logwatch project and thus assume the above copyright ## and licensing terms. If you want to make contributions ## under your own copyright or a different license this ## must be explicitly stated in the contribution an the ## Logwatch project reserves the right to not accept such ## contributions. If you have made significant ## contributions to this script and want to claim ## copyright please contact logwatch-devel@lists.sourceforge.net. ######################################################### use strict; use POSIX qw(uname); my %CPUModel; my $Model; my ($OSname, $hostname, $release, $version, $machine) = POSIX::uname(); print " Machine: $machine\n"; my $OStitle; $OStitle = $OSname; $OStitle = "Solaris" if ($OSname eq "SunOS" && $release >= 2); print (" Release: $OStitle $release\n"); if (open FH, '<', '/proc/cpuinfo') { while () { if (($Model) = $_ =~ /^model name\s*: (.*)$/) { $CPUModel{$Model}++; } } close(FH); } if (keys %CPUModel) { print ("\n CPU Model(s):"); foreach my $cpu (keys %CPUModel) { print ("\n CPU Model: $cpu: $CPUModel{$cpu} processors"); } } print ("\n\n"); if (open FH, '<', '/proc/meminfo') { while (my $ThisLine = ) { if ($ThisLine =~ /^(Mem|Swap)(Total|Free)/) { chomp ($ThisLine); print (" " . $ThisLine); my @fields = split(' ', $ThisLine); printf (" (%.2f GB)\n", @fields[1]/(1024*1024)); } } close(FH); } # vi: shiftwidth=3 tabstop=3 syntax=perl et # Local Variables: # mode: perl # perl-indent-level: 3 # indent-tabs-mode: nil # End: logwatch-7.12/scripts/services/pureftpd0000664000211400021140000001721614274101042020535 0ustar logwatchlogwatch ######################################################## # Please file all bug reports, patches, and feature # requests under: # https://sourceforge.net/p/logwatch/_list/tickets # Help requests and discusion can be filed under: # https://sourceforge.net/p/logwatch/discussion/ ######################################################## ####################################################### ## Copyright (c) 2008 Chris Smith ## Covered under the included MIT/X-Consortium License: ## http://www.opensource.org/licenses/mit-license.php ## All modifications and contributions by other persons to ## this script are assumed to have been donated to the ## Logwatch project and thus assume the above copyright ## and licensing terms. If you want to make contributions ## under your own copyright or a different license this ## must be explicitly stated in the contribution an the ## Logwatch project reserves the right to not accept such ## contributions. If you have made significant ## contributions to this script and want to claim ## copyright please contact logwatch-devel@lists.sourceforge.net. ######################################################### ########################################################################## # Written & Maintained by Chris Smith (csmith@squiz.net) ########################################################################## use strict; my $Detail = $ENV{'LOGWATCH_DETAIL_LEVEL'}; my $ShowLogins = $ENV{'show_logins'}; my $ShowLogouts = $ENV{'show_logouts'}; my $ShowDataStats = $ENV{'show_data_stats'}; my $ShowDataTransfers = $ENV{'show_data_transfers'}; my $ShowNewConnections = $ENV{'show_new_connections'}; my $IgnoreUnmatched = $ENV{'pureftpd_ignore_unmatched'} || 0; #Init Counters my $PureShutdown = 0; #Init String Containers (hash obj) my ( $IP, $j, $User, $ConnectionCount, $Logins, $MinAvgSize, $Stats, $TooManyConnections, $TopPeopleNr, $Transfers, ); my $MinAvgSize = 200*1024 if (!defined ($MinAvgSize = $ENV{'min_avg_file_size'})); my $TopPeopleNr = 3 if (!defined ($TopPeopleNr = $ENV{'top_people_nr'})); #Init Arrays my @OtherList = (); #Init Hashes my ( %Logouts, %NewConnections, %SecureAnon ); while (defined(my $ThisLine = )) { if ( ( $ThisLine =~ /last message repeated/ ) or ( $ThisLine =~ /Timeout/) or ( $ThisLine =~ /Can't change directory/) or ( $ThisLine =~ /Can't create directory: File exists/) or ( $ThisLine =~ /File successfully renamed or moved/) or ( $ThisLine =~ /This is a private system - No anonymous login/) or ( $ThisLine =~ /Authentication failed for user/) or ( $ThisLine =~ /Sorry, cleartext sessions and weak ciphers not accepted on this server/) or ( $ThisLine =~ /TLS: Enabled/) or ( $ThisLine =~ /Transfer aborted/) or ( $ThisLine =~ /pure-ftpd startup( |) succeeded/) ) { #We don't care about these } elsif (($IP,$j) = ($ThisLine =~ /\@(.*?)\)(.*?)new connection/i )) { $NewConnections{$IP}++; } elsif (($IP,$j) = ($ThisLine =~ /\@(.*?)\)(.*?)logout/i )) { $Logouts{$IP}++; } elsif (($IP,$j) = ($ThisLine =~ /\@(.*?)\)(.*?)unable to set up secure anonymous ftp/i )) { $SecureAnon{$IP}++; } elsif (($IP,$User) = ($ThisLine =~ /\@(.*?)\)\s*\[info\]\s*(.*?) is now logged in/i )) { $Logins->{$IP}->{$User}++; } elsif (($j,$ConnectionCount,$IP) = ($ThisLine =~ /(.*?)too many connections \((.*?)\) from this ip\: \[(.*?)\]/i )) { $TooManyConnections->{$ConnectionCount}->{$IP}++; } elsif (my ($User,$Location,$File,$Direction, $Size, $Speed) = ($ThisLine =~ /\((.*?)\@(.*?)\)\s+\[\w+\]\s+(.*?)\s(downloaded|uploaded)\s+\((\d+) bytes, (.+)KB\/sec\)/)) { $Transfers->{$Direction}->{$User}->{$Location}->{$File}++; $Stats->{$Direction}->{"files_count"}++; $Stats->{$Direction}->{"files_size"} += $Size; $Stats->{$Direction}->{"people"}->{$User} += $Size; if ($Size >= $MinAvgSize) { $Stats->{$Direction}->{"speed"}->{"max"} = $Speed if ($Stats->{$Direction}->{"speed"}->{"max"} < $Speed); $Stats->{$Direction}->{"speed"}->{"tmp_size"} += $Size; $Stats->{$Direction}->{"speed"}->{"tmp_time"} += $Size/($Speed*1024); } } elsif ($ThisLine =~ m/pure-ftpd shutdown( |) succeeded/) { $PureShutdown++; } else { # Report any unmatched entries... push @OtherList,$ThisLine; } } ########################## # if ($PureShutdown > 0) { print "\nPure-ftpd shutdown $PureShutdown Time(s)\n"; } if ($ShowNewConnections) { if (keys %NewConnections) { print "\nNew Connections:\n"; foreach my $Line (sort {$a cmp $b} keys %NewConnections) { print "\t" . $Line . " - ". $NewConnections{$Line} . " Time(s)\n"; } } } if ($ShowLogins) { if (keys %{$Logins}) { print "\nSuccessful Logins:\n"; foreach my $Line (sort {$a cmp $b} keys %{$Logins}) { foreach my $Detail (sort {$a cmp $b} keys %{$Logins->{$Line}}) { print "\t" . $Detail. " (" . $Line . ") - ". $Logins->{$Line}->{$Detail} . " Time(s)\n"; } } } } if (keys %{$TooManyConnections}) { print "\nToo Many Connections:\n"; foreach my $Line (sort {$a cmp $b} keys %{$TooManyConnections}) { foreach my $Detail (sort {$a cmp $b} keys %{$TooManyConnections->{$Line}}) { print "\t" . $Detail. " (" . $Line . " connections) - ". $TooManyConnections->{$Line}->{$Detail} . " Time(s)\n"; } } } if ($ShowDataStats) { foreach my $Direction (keys %{$Stats}) { print "\nTransfer statistics - $Direction files:\n"; print "\t$Stats->{$Direction}->{files_count} $Direction files\n"; printf "\t%.2f $Direction MB\n", ($Stats->{$Direction}->{'files_size'}/1024)/1024; if ($Stats->{$Direction}->{speed}) { print "\t$Stats->{$Direction}->{speed}->{max}KB max speed\n"; printf "\t%.2fKB/s average speed\n", $Stats->{$Direction}->{'speed'}->{'tmp_size'}/$Stats->{$Direction}->{'speed'}->{'tmp_time'}/1024; } my @top_people = sort { $Stats->{$Direction}->{'people'}->{$b} <=> $Stats->{$Direction}->{'people'}->{$a} } keys %{ $Stats->{$Direction}->{'people'} }; if (@top_people) { print "\tTop $TopPeopleNr people:\n"; foreach my $User (splice @top_people, 0, $TopPeopleNr) { printf "\t\t%7.2fMB $User\n", $Stats->{$Direction}->{'people'}->{$User}/1024/1024; } } } } if ($ShowDataTransfers) { foreach my $Direction (keys %{$Transfers}) { print "\nData $Direction:\n"; foreach my $User (sort {$a cmp $b} keys %{ $Transfers->{$Direction} }) { foreach my $Location (sort {$a cmp $b} keys %{ $Transfers->{$Direction}->{$User} }) { foreach my $Filename (sort {$a cmp $b} keys %{ $Transfers->{$Direction}->{$User}->{$Location}}) { print "\tUser " . $User . " " . $Direction . " " . $Filename . " from " . $Location . " - ". $Direction->{$User}->{$Location}->{$Filename} . " Time(s)\n"; } } } } } if (keys %SecureAnon) { print "\nUnsuccessful Secure Anonymous Connections:\n"; foreach my $Line (sort {$a cmp $b} keys %SecureAnon) { print "\t" . $Line . " - ". $SecureAnon{$Line} . " Time(s)\n"; } } if ($ShowLogouts) { if (keys %Logouts) { print "\nLogouts:\n"; foreach my $Line (sort {$a cmp $b} keys %Logouts) { print "\t" . $Line . " - ". $Logouts{$Line} . " Time(s)\n"; } } } if (($#OtherList >= 0) and (not $IgnoreUnmatched)){ print "\n**Unmatched Entries**\n"; print @OtherList; } exit(0); # vi: shiftwidth=3 tabstop=3 syntax=perl et # Local Variables: # mode: perl # perl-indent-level: 3 # indent-tabs-mode: nil # End: logwatch-7.12/scripts/services/stunnel0000664000211400021140000001441314274101044020372 0ustar logwatchlogwatch ######################################################## # Please file all bug reports, patches, and feature # requests under: # https://sourceforge.net/p/logwatch/_list/tickets # Help requests and discusion can be filed under: # https://sourceforge.net/p/logwatch/discussion/ ######################################################## ####################################################### ## Copyright (c) 2008 Kirk Bauer ## Covered under the included MIT/X-Consortium License: ## http://www.opensource.org/licenses/mit-license.php ## All modifications and contributions by other persons to ## this script are assumed to have been donated to the ## Logwatch project and thus assume the above copyright ## and licensing terms. If you want to make contributions ## under your own copyright or a different license this ## must be explicitly stated in the contribution an the ## Logwatch project reserves the right to not accept such ## contributions. If you have made significant ## contributions to this script and want to claim ## copyright please contact logwatch-devel@lists.sourceforge.net. ######################################################### $^W=1; use strict; my $Debug = $ENV{'LOGWATCH_DEBUG'} || 0; my $Detail = $ENV{'LOGWATCH_DETAIL_LEVEL'} || 0; my $DebugCounter = 0; my $Top = $ENV{'stunnel_print_top'} || 20; if ( $Debug >= 5 ) { print STDERR "\n\nDEBUG: Inside stunnel Filter \n\n"; $DebugCounter = 1; } my @OtherList = (); my %OtherList = (); my %connections = (); my %versioninfo = (); my %errors = (); my %notices = (); my $sockdata = 0; my $ssldata = 0; my $stops = 0; sub other { my $msg = shift; unless (exists $OtherList{$msg}) { $OtherList{$msg} = 1; push(@OtherList, $msg); } else { $OtherList{$msg}++; } } my $ThisLine; while (defined($ThisLine = )) { $ThisLine =~ s/LOG\d\[(?:\d{1,5}:\d{15}|\w+)\]: (.*)/$1/; if ( $Debug >= 5 ) { print STDERR "DEBUG($DebugCounter): $ThisLine"; $DebugCounter++; } chomp($ThisLine); my $origline = $ThisLine; if ($ThisLine =~ m/^(.+) connected from (\d+\.\d+\.\d+\.\d+)/) { my $service = $1; my $ip = $2; if (! exists($connections{$service}{$ip})) { $connections{$service}{$ip} = 0; } ++$connections{$service}{$ip}; } elsif ($ThisLine =~ m/^Configuration successful/) { # ignore } elsif ($ThisLine =~ m/^Connection (reset|closed): (\d+) bytes sent to SSL, (\d+) bytes sent to socket/) { $ssldata += $2; $sockdata += $3; } elsif ($ThisLine =~ m/^Connection (reset|closed)/) { # ignore } elsif ($ThisLine =~ m/^connect_blocking: connected/) { # ignore } elsif ($ThisLine =~ m/^connect_blocking: getsockopt ([0-9a-fA-F.:]+: Connection refused) \(\d+\)$/) { $errors{"connect_blocking: $1"}++; } elsif ($ThisLine =~ m/^DH parameters updated/) { # ignore } elsif ($ThisLine =~ m/^(?:remote socket|local socket|accept): (Too many open files) \(\d+\)$/) { $errors{"$1: increase the maximum number of open file descriptors"}++; } elsif ($ThisLine =~ m/^Log file reopened$/) { # ignore } elsif ($ThisLine =~ m/^Reading configuration from /) { # ignore } elsif ($ThisLine =~ m/^SSL socket closed on SSL_read with \d+ byte\(s\) in buffer$/) { # ignore } elsif ($ThisLine =~ m/^(stunnel [\d\.]+ on |Compiled|Threading:|FIPS)/) { $versioninfo{$ThisLine} = 1; } elsif ($ThisLine =~ m/^Service (\S+) accepted connection from ([0-9a-fA-F.:]+):\d{1,5}/) { $connections{$1}{$2}++; } elsif ($ThisLine =~ m/^Service (\S+) connected remote server from ([0-9a-fA-F.:]+):\d{1,5}/) { $connections{"remote: $1"}{$2}++; } elsif ($ThisLine =~ m/^Error detected on (SSL|socket) \((read|write)\) file descriptor: (.*) \(\d+\)/) { $errors{"$1 $2 file descriptor: $3"}++; } elsif ($ThisLine =~ m/^(SSL_write: (?:Broken pipe|Connection reset by peer)) \(\d+\)$/) { $errors{"$1"}++; } elsif ($ThisLine =~ m/^Terminated/) { $stops++; } elsif ($ThisLine =~ m/^transfer: s_poll_wait: TIMEOUTclose exceeded: closing$/) { $notices{"TIMEOUTclose exceeded: closing connection"}++; } elsif ($ThisLine =~ m/^Updating DH parameters/) { # ignore } elsif ($ThisLine =~ m/^(SSL_(?:accept|read|shutdown): .*|getpeerbyname: .*)(?: \(\d+\))?$/) { $notices{$1}++; } else { # Report any unmatched entries... other($ThisLine); } } if (keys %errors) { print "\nErrors:\n"; foreach my $e (sort keys %errors) { printf " %-50s %6d time(s)\n", $e, $errors{$e}; } } if (keys %notices) { print "\nNotices:\n"; foreach my $n (sort keys %notices) { printf " %-50s %6d time(s)\n", $n, $notices{$n}; } } if ($Detail && keys %connections) { print "\nconnections:\n"; foreach my $service (sort keys %connections) { print " $service\n"; my $ips = $connections{$service}; my $i = 0; foreach my $ip (sort {$connections{$service}{$b} <=> $connections{$service}{$a}} keys %{$connections{$service}}) { if ($i >= $Top) { printf " %-48s\n", "... only top $Top printed ..."; last; } else { printf " %-48s %6d time(s)\n", $ip, $connections{$service}{$ip}; $i++; } } } } if ($Detail && $stops > 0) { print "\nService stopped $stops Time(s)\n"; } if ($Detail && $sockdata > 0) { if ($sockdata > 1024*1024) { printf "\n%-48s %10.2f MB\n", "amount of socket data transferred:", $sockdata / 1024 / 1024; } else { printf "\n%-48s %10.2f KB\n", "amount of socket data transferred:", $sockdata / 1024; } } if ($Detail && $ssldata > 0) { if ($ssldata > 1024*1024) { printf "\n%-48s %10.2f MB\n", "amount of SSL data transferred:", $ssldata / 1024 / 1024; } else { printf "\n%-48s %10.2f KB\n", "amount of SSL data transferred:", $ssldata / 1024; } } if ($Detail > 5 && keys %versioninfo) { print "\nversion information:\n"; foreach my $v (sort keys %versioninfo) { print " $v\n"; } } if (@OtherList) { print "\n**Unmatched Entries**\n"; for (@OtherList) { my $count = $OtherList{$_}; print " $_: $count Time(s)\n"; } } exit(0); # vi: shiftwidth=3 tabstop=3 syntax=perl et # Local Variables: # mode: perl # perl-indent-level: 3 # indent-tabs-mode: nil # End: logwatch-7.12/scripts/services/fetchmail0000664000211400021140000000743514274101036020645 0ustar logwatchlogwatch ######################################################## # Please file all bug reports, patches, and feature # requests under: # https://sourceforge.net/p/logwatch/_list/tickets # and copy: # Oron Peled # Help requests and discusion can be filed under: # https://sourceforge.net/p/logwatch/discussion/ ######################################################## ######################################################## # This was written and is maintained by: # Oron Peled # ######################################################## ######################################################## ## Copyright (c) 2010 Oron Peled ## Covered under the included MIT/X-Consortium License: ## http://www.opensource.org/licenses/mit-license.php ## All modifications and contributions by other persons to ## this script are assumed to have been donated to the ## Logwatch project and thus assume the above copyright ## and licensing terms. If you want to make contributions ## under your own copyright or a different license this ## must be explicitly stated in the contribution an the ## Logwatch project reserves the right to not accept such ## contributions. If you have made significant ## contributions to this script and want to claim ## copyright please contact logwatch-devel@lists.sourceforge.net. ######################################################### use strict; my $Detail = $ENV{'LOGWATCH_DETAIL_LEVEL'} || 0; my %no_mail; my %messages_for; my %auth_fail; my %conn_fail; my %OtherList; #Inits while (defined(my $ThisLine = )) { chomp($ThisLine); $ThisLine =~ s/^[a-zA-Z0-9]+: //; if($ThisLine =~ s/^No mail for (\S+) at (\S+)//) { $no_mail{"${1} at ${2}"}++; } elsif($ThisLine =~ /^reading message /) { # ignore } elsif($ThisLine =~ s/^Query status=[23]//) { # ignore. Counted below (Authorization, Connection) } elsif($ThisLine =~ s/^Authorization failure on (\S+)//) { $auth_fail{"${1}"}++; } elsif($ThisLine =~ s/^\S+ connection to \S+ failed: .*//) { # ignore. Counted below } elsif($ThisLine =~ s/^connection to (\S+) \[[^]]+\] failed: (.*).//) { $conn_fail{"${1} -- ${2}"}++; } elsif($ThisLine =~ s/^(\d+) messages? for (\S+) at (\S+).*.//) { $messages_for{"${2} at ${3}"} += $1; } elsif($ThisLine =~ s/^(\d+) messages? \((\d+) seen\) for (\S+) at (\S+).*.//) { $messages_for{"${3} at ${4}"} += ($1-$2); } else { chomp($ThisLine); # Report any unmatched entries... $OtherList{$ThisLine}++; } } if (keys %messages_for) { my $total; print "\nMessages\n"; foreach my $who (sort keys %messages_for) { print " $who: $messages_for{$who}\n"; $total += $messages_for{$who}; } print " Total: $total\n"; } if (keys %conn_fail) { my $total; print "\nConnection failures\n"; foreach my $who (sort keys %conn_fail) { print " $who: $conn_fail{$who} Time(s)\n"; $total += $conn_fail{$who}; } print " Total: $total\n"; } if (keys %auth_fail) { my $total; print "\nAuthorization failures\n"; foreach my $who (sort keys %auth_fail) { print " $who: $auth_fail{$who} Time(s)\n"; $total += $auth_fail{$who}; } print " Total: $total\n"; } if (keys %no_mail) { my $total; print "\nNo Mail\n"; foreach my $who (sort keys %no_mail) { print " $who: $no_mail{$who} Time(s)\n"; $total += $no_mail{$who}; } print " Total: $total\n"; } if (keys %OtherList) { print "\n**Unmatched Entries**\n"; foreach my $line (sort {$OtherList{$b}<=>$OtherList{$a} } keys %OtherList) { print " $line: $OtherList{$line} Time(s)\n"; } } exit(0); # vi: shiftwidth=3 tabstop=3 syntax=perl et # Local Variables: # mode: perl # perl-indent-level: 3 # indent-tabs-mode: nil # End: logwatch-7.12/scripts/services/proftpd-messages0000664000211400021140000002346014274101042022165 0ustar logwatchlogwatch ######################################################## # Please file all bug reports, patches, and feature # requests under: # https://sourceforge.net/p/logwatch/_list/tickets # Help requests and discusion can be filed under: # https://sourceforge.net/p/logwatch/discussion/ ######################################################## ######################################################## # This was written by Simon Liddington for use with Logwatch ######################################################## ####################################################### ## Copyright (c) 2008 Simon Liddington ## Covered under the included MIT/X-Consortium License: ## http://www.opensource.org/licenses/mit-license.php ## All modifications and contributions by other persons to ## this script are assumed to have been donated to the ## Logwatch project and thus assume the above copyright ## and licensing terms. If you want to make contributions ## under your own copyright or a different license this ## must be explicitly stated in the contribution an the ## Logwatch project reserves the right to not accept such ## contributions. If you have made significant ## contributions to this script and want to claim ## copyright please contact logwatch-devel@lists.sourceforge.net. ######################################################### use strict; my $Detail = $ENV{'LOGWATCH_DETAIL_LEVEL'} || 0; my $IgnoreUnmatched = $ENV{'ftpd_ignore_unmatched'}; #Init Counters my $NoEndpoints = 0; my $UnmatchedEntries = 0; #Init String Containers my ( $Email, $Error, $Host, $IP, $Notice, $Option, $Reason, $Temp, $User ); #Init Arrays my @OtherList = (); #Init Hashes my ( %AnonLogins, %BadPasswds, %BadShell, %BadUsers, %ConnectionRefused, %DeletedFiles, %DeprecatedOptions, %ErrorLines, %MaxLoginAttempts, %NoticeLines, %RefusedPorts, %RootLoginAttempt, %TransferTimeout, %UserLogins ); while (defined(my $ThisLine = )) { if ( ( $ThisLine =~ /^FTP session closed/ ) or ( $ThisLine =~ /^(ANONYMOUS )?FTP login as \'.*\' from [^ ]+ \[.*\] to .*/ ) or ( $ThisLine =~ /(PAM|pam_unix)\(.*\): [Aa]uthentication failure/ ) or ( $ThisLine =~ /(PAM|pam_unix)\(.*\): session (opened|closed) for user/ ) or ( $ThisLine =~ /^data_sendfile/ ) or ( $ThisLine =~ /(:| \-) FTP session (closed|opened)/ ) or ( $ThisLine =~ /(:| \-) No certificate files found/ ) or ( $ThisLine =~ /FTP (no transfer|session idle) timeout, disconnected/ ) or ( $ThisLine =~ / masquerading as / ) or ( $ThisLine =~ /mod_delay\// ) or ( $ThisLine =~ /FTP login timed out, disconnected/ ) or ( $ThisLine =~ /Preparing to chroot to directory/ ) or ( $ThisLine =~ /\(.*\[.*\]\)(\:| \-) no such user '.*'/ ) ) { #We don't care about these } elsif ( ($Host,$IP,$Email,) = ( $ThisLine =~ /^FTP session opened: ftp\/ftp (.*)\[(.*)\] (.*)$/ ) ) { $Temp = " " . $Host . " (" . $IP . "): " . $Email . " - "; $AnonLogins{$Temp}++; } elsif ( ($Host, $IP) = ( $ThisLine =~ /\((.*)\[(.*)\]\)(?:\:| \-) ANON .+: Login successful\./ ) ) { $Temp = " " . $Host . " (" . $IP . ")"; $AnonLogins{$Temp}++; } elsif ( ($User,$Host,$IP) = ( $ThisLine =~ /^FTP session opened: (.*\/.*) (.*)\[(.*)\] (.*)$/ ) ) { $Temp = " $Host : $User - "; $UserLogins{$Temp}++; } elsif ( ($Host,$IP,$User) = ( $ThisLine =~ /\((.*)\[(.*)\]\)(?:\:| \-) USER (.+): Login successful/ ) ) { $Temp = " " . $Host . ": " . $User . " - "; $UserLogins{$Temp}++; } elsif ( ($User) = ( $ThisLine =~ /^failed login, can\'t find user \'(.*)\' $/ ) ) { $Temp = " " . "Unknown" . " (" . "Unknown.IP" . "): " . $User . " - "; $BadUsers{$Temp}++; } elsif ( ($User,$Host,$IP) = ( $ThisLine =~ /USER (.*): no such user found from (.*) \[(.*)\] to/ ) ) { #$Temp = " $Host : $User - "; #$BadUsers{$Temp}++; $BadUsers{$User}{$Host}++; # } elsif ( ($Host,$Ip,$User) = ( $ThisLine =~ /\((.*)\[(.*)\]\)(?:\:| \-) no such user '(.*)'/ ) ) { # #$Temp = "$Host($Ip)"; # $BadUsers{$User}{$Host}++; } elsif ( ($Host,$User) = ( $ThisLine =~ /\[(.*)\]\)(?:\:| \-) USER (.*) \(Login failed\): Incorrect password/ ) ) { $Temp = " $Host : $User - "; $BadPasswds{$Temp}++; } elsif ( ($Host,$User) = ( $ThisLine =~ /\[(.*)\]\)(?:\:| \-) USER (.*) \(Login failed\): Invalid shell/ ) ) { $Temp = " $Host : $User - "; $BadShell{$Temp}++; } elsif ( ($Host,$IP) = ( $ThisLine =~ /\((.*)\[(.*)\]\)(?:\:| \-) SECURITY VIOLATION: root login attempted/ ) ) { $RootLoginAttempt{$Host}++; } elsif ( ($Host) = ( $ThisLine =~ /\(((.*)\[(.*)\])\)(?:\:| \-) Maximum login attempts .*exceeded/ ) ) { $MaxLoginAttempts{$Host}++; } elsif ( ($Host,$Reason) = ( $ThisLine =~ /\[(.*)\]\)(?:\:| \-) Refused PORT [\d,]+ \((.*)\)/ ) ) { $Temp = " " . $Host . ": " . $Reason . " - "; $RefusedPorts{$Temp}++; } elsif ( ($Host,$Reason) = ( $ThisLine =~ /\(((.*)\[(.*)\])\)(?:\:| \-) Connection refused \((.*)\)/ ) ) { $ConnectionRefused{$Reason}{$Host}++; } elsif ( ($Host) = ( $ThisLine =~ /\(((.*)\[(.*)\])\)(?:\:| \-) Data transfer stall timeout/ ) ) { $TransferTimeout{$Host}++; } elsif ( $ThisLine =~ m/[^ ]*(?:\:| \-) Fatal: Transport endpoint is not connected/ ) { $NoEndpoints++; } elsif ( ($Option) = ( $ThisLine =~ /warning: (.*) is deprecated/ ) ) { $DeprecatedOptions{$Option}++; } elsif ( ($Host,$IP,$Error) = ( $ThisLine =~ /\((.*)\[(.*)\]\)(?:\:| \-) error: (.*)$/ ) ) { $ErrorLines{$Host}{$Error}++; } elsif ( ($Host,$IP,$Notice) = ( $ThisLine =~ /\((.*)\[(.*)\]\)(?:\:| \-) notice: (.*)$/ ) ) { $NoticeLines{$Host}{$Notice}++; } else { # Report any unmatched entries... push @OtherList,$ThisLine; } } ############################################## if (keys %DeprecatedOptions) { print "\nDeprecated options in config:\n"; foreach my $Option (sort {$a cmp $b} keys %DeprecatedOptions) { print " $Option\n"; } } if ( (keys %AnonLogins) and ($Detail >= 5) ) { print "\nAnonymous FTP Logins:\n"; foreach my $ThisOne (sort {$a cmp $b} keys %AnonLogins) { print $ThisOne . $AnonLogins{$ThisOne} . " Time(s)\n"; } } if ( (keys %DeletedFiles) and ($Detail >= 10) ) { print "\nFiles deleted through FTP:\n"; foreach my $ThisOne (sort {$a cmp $b} keys %DeletedFiles) { print $ThisOne; print @{$DeletedFiles{$ThisOne}}; } } if (keys %UserLogins) { print "\nUser FTP Logins:\n"; foreach my $ThisOne (sort {$a cmp $b} keys %UserLogins) { print $ThisOne . $UserLogins{$ThisOne} . " Time(s)\n"; } } if (keys %RootLoginAttempt) { print "\nSECURITY VIOLATION!!!!\n"; print "Root login attempt from:\n"; foreach my $Host (sort {$a cmp $b} keys %RootLoginAttempt) { print " $Host : $RootLoginAttempt{$Host} Time(s)\n"; } } if (keys %MaxLoginAttempts) { print "\nMaximum login attempts exceeded from hosts:\n"; foreach my $Host (sort {$a cmp $b} keys %MaxLoginAttempts) { print " $Host : $MaxLoginAttempts{$Host} Time(s)\n"; } } if (keys %ConnectionRefused) { print "\nConnection refused with reason:\n"; foreach my $Reason (sort {$a cmp $b} keys %ConnectionRefused) { print " $Reason :\n"; foreach my $Host (sort {$a cmp $b} keys %{$ConnectionRefused{$Reason}}) { print " $Host : $ConnectionRefused{$Reason}{$Host} Time(s)\n"; } } } if ( ( (keys %BadUsers) or (keys %BadPasswds) ) and ($Detail >= 5) ) { print "\nFailed FTP Logins:\n"; if ( (keys %BadUsers) and ($Detail >= 5) ) { print "\n Invalid Username:\n"; foreach my $User (sort {$a cmp $b} keys %BadUsers) { print " $User:\n"; foreach my $Host (sort {$a cmp $b} keys %{$BadUsers{$User}}) { print " $Host : $BadUsers{$User}{$Host} Time(s)\n"; } } } if ( (keys %BadPasswds) and ($Detail >= 5) ) { print "\n Incorrect Password:\n"; foreach my $ThisOne (sort {$a cmp $b} keys %BadPasswds) { print $ThisOne . $BadPasswds{$ThisOne} . " Time(s)\n"; } } if ( (keys %BadShell) and ($Detail >= 5) ) { print "\n Invalid Shell:\n"; foreach my $ThisOne (sort {$a cmp $b} keys %BadShell) { print $ThisOne . $BadShell{$ThisOne} . " Time(s)\n"; } } } if ( (keys %RefusedPorts) and ($Detail >= 5) ) { print "\nRefused PORTs:\n"; foreach my $ThisOne (sort {$a cmp $b} keys %RefusedPorts) { print $ThisOne . $RefusedPorts{$ThisOne} . " Time(s)\n"; } } if ( (keys %TransferTimeout) and ($Detail >= 5) ) { print "\nData transfer stall timeout:\n"; foreach my $Host (sort {$a cmp $b} keys %TransferTimeout) { print " $Host : $TransferTimeout{$Host} Time(s)\n"; } } if ( (keys %NoticeLines) and ($Detail >= 10) ) { print "\nNotices Reported by Host:\n"; foreach my $Host (sort {$a cmp $b} keys %NoticeLines) { print " $Host:\n"; foreach my $Notice (sort {$a cmp $b} keys %{$NoticeLines{$Host}}) { print " $Notice : $NoticeLines{$Host}{$Notice} Time(s)\n"; } } } if ( (keys %ErrorLines) and ($Detail >= 5) ) { print "\nErrors Reported by Host:\n"; foreach my $Host (sort {$a cmp $b} keys %ErrorLines) { print " $Host:\n"; foreach my $Errors (sort {$a cmp $b} keys %{$ErrorLines{$Host}}) { print " $Errors : $ErrorLines{$Host}{$Errors} Time(s)\n"; } } } if ($NoEndpoints > 0) { print "\nTransport endpoint is not connected error $NoEndpoints Time(s)\n"; } if (($#OtherList >= 0) and (not $IgnoreUnmatched)) { print "\n**Unmatched Entries**\n"; print @OtherList; } exit(0); # vi: shiftwidth=3 tabstop=3 syntax=perl et # Local Variables: # mode: perl # perl-indent-level: 3 # indent-tabs-mode: nil # End: logwatch-7.12/scripts/services/identd0000664000211400021140000001370714274101037020160 0ustar logwatchlogwatch ######################################################## # Please file all bug reports, patches, and feature # requests under: # https://sourceforge.net/p/logwatch/_list/tickets # Help requests and discusion can be filed under: # https://sourceforge.net/p/logwatch/discussion/ ######################################################## ##################################################### ## Copyright (c) 2008 Kirk Bauer ## Covered under the included MIT/X-Consortium License: ## http://www.opensource.org/licenses/mit-license.php ## All modifications and contributions by other persons to ## this script are assumed to have been donated to the ## Logwatch project and thus assume the above copyright ## and licensing terms. If you want to make contributions ## under your own copyright or a different license this ## must be explicitly stated in the contribution an the ## Logwatch project reserves the right to not accept such ## contributions. If you have made significant ## contributions to this script and want to claim ## copyright please contact logwatch-devel@lists.sourceforge.net. ######################################################### use strict; my $Debug = $ENV{'LOGWATCH_DEBUG'} || 0; my $Detail = $ENV{'LOGWATCH_DETAIL_LEVEL'} || 0; my $DebugCounter = 0; #Init String Containers my ( $Host, $Name, $NeedNextLine, $NextLine, $Text, $User ); #Init Arrays my (@EmptyRequests, @InvalidRequests) = (); #Init Hashes my (%Identd, %OtherList); if ( $Debug >= 5 ) { print STDERR "\n\nDEBUG: Inside Identd Filter \n\n"; $DebugCounter = 1; } # This whole NeedNextLine thing is because there are multiple lines that # go together for these log entries... my $ThisLine = ; while (defined($ThisLine)) { if ( $Debug >= 5 ) { print STDERR "DEBUG: Line Number " . $DebugCounter . ":\n"; print STDERR "DEBUG: " . $ThisLine; } $NeedNextLine = 1; if ( my ($IP,$Hostname,$Port) = ($ThisLine =~ m/^from: (\d+\.\d+\.\d+\.\d+) \( ([^ ]*) \) for: \d+, (\d+)$/) ) { # this means that somebody accessed identd... if ( $Debug >= 5 ) { print STDERR "DEBUG: Found -Connection From- Line -- Reading another line\n"; $DebugCounter++; } if (defined($NextLine = )) { if ( $Debug >= 5 ) { print STDERR "DEBUG: Line Number " . $DebugCounter . ":\n"; print STDERR "DEBUG: " . $NextLine; } if ( ($User) = ($NextLine =~ m/^Successful lookup: \d+ , \d+ : ([^ ]+)\.[^ ]+/) ) { if ( $Debug >= 5 ) { print STDERR "DEBUG: Found -Successful Lookup- line (" . $User . ")\n"; } ${Identd{$IP}}[0] = $Hostname; ${Identd{$IP}}[1]++; push @{${Identd{$IP}}[2]}, $Port; push @{${Identd{$IP}}[3]}, $User; } else { if ( $Debug >= 5 ) { print STDERR "DEBUG: No matches... keeping current line.\n"; } $ThisLine = $NextLine; $NeedNextLine = 0; } } } elsif ( ($IP,$Hostname) = ($ThisLine =~ m/^from: (\d+\.\d+\.\d+\.\d+) \(([^ ]*)\) EMPTY REQUEST$/) ) { if ( $Debug >= 5 ) { print STDERR "DEBUG: Found -Empty Request- Line\n"; } $Text = " " . $Hostname . " (" . $IP . ")"; push @EmptyRequests,$Text; } elsif ( ($IP,$Hostname,$Name) = ($ThisLine =~ m/^from: (\d+\.\d+\.\d+\.\d+) \(([^ ]*)\) INVALID REQUEST: (.*)$/) ) { if ( $Debug >= 5 ) { print STDERR "DEBUG: Found -Invalid Request- Line\n"; } $Text = " " . $Hostname . " (" . $IP . ") - " . $Name; push @InvalidRequests,$Text; } elsif ( $ThisLine =~ m/^Returned: \d+ , \d+ : NO-USER/ ) { # Do nothing... } elsif ( ($Host) = ( $ThisLine =~ /^Connection from ([^ ]+)/ ) ) { chomp($Host); if (defined($NextLine = )) { if ( $Debug >= 5 ) { print STDERR "DEBUG: Line Number " . $DebugCounter . ":\n"; print STDERR "DEBUG: " . $NextLine; } if ( ($Port,$User) = ($NextLine =~ m/^Successful lookup: \d+ , (\d+) : ([^ ]+)/) ) { if ( $Debug >= 5 ) { print STDERR "DEBUG: Found -Successful Lookup- line (" . $User . ")\n"; } chomp($Port); chomp($User); ${Identd{$Host}}[0] = $Host; ${Identd{$Host}}[1]++; push @{${Identd{$Host}}[2]}, $Port; push @{${Identd{$Host}}[3]}, $User; } else { if ( $Debug >= 5 ) { print STDERR "DEBUG: No matches... keeping current line.\n"; } $ThisLine = $NextLine; $NeedNextLine = 0; } } } elsif ($ThisLine =~ /^Successful lookup: [1234567890]+ , [1234567890]+ : [^ ]+/ ) { # skip empty entry ... } else { # Report any unmatched entries... if ( $Debug >= 5 ) { print STDERR "DEBUG: Found unmatched line\n"; } chomp($ThisLine); $OtherList{$ThisLine}++; } if ($NeedNextLine == 1) { $ThisLine = ; } } if ( (keys %Identd) and ($Detail >= 10) ) { print "Identd Lookups:\n"; foreach my $ThisOne (keys %Identd) { print " Host: " . ${Identd{$ThisOne}}[0] . " (" . $ThisOne . ") - " . ${Identd{$ThisOne}}[1] . " Connection(s).\n"; } } if (($#EmptyRequests >= 0) and ($Detail >= 5)) { print "\nEmpty requests:\n"; foreach my $ThisOne (@EmptyRequests) { print " " . $ThisOne . "\n"; } } if (($#InvalidRequests >= 0) and ($Detail >= 5)) { print "\nInvalid requests:\n"; foreach my $ThisOne (@InvalidRequests) { print " " . $ThisOne . "\n"; } } if (keys %OtherList) { print "\n**Unmatched Entries**\n"; foreach my $line (sort {$a cmp $b} keys %OtherList) { print "$line: $OtherList{$line} Time(s)\n"; } } exit(0); # vi: shiftwidth=3 tabstop=3 syntax=perl et # Local Variables: # mode: perl # perl-indent-level: 3 # indent-tabs-mode: nil # End: logwatch-7.12/scripts/services/evtapplication0000664000211400021140000002154214620242153021727 0ustar logwatchlogwatch ######################################################## # Please file all bug reports, patches, and feature # requests under: # https://sourceforge.net/p/logwatch/_list/tickets # Help requests and discusion can be filed under: # https://sourceforge.net/p/logwatch/discussion/ ######################################################## ######################################################## ## Copyright (c) 2008 Orion Poplawski ## Covered under the included MIT/X-Consortium License: ## http://www.opensource.org/licenses/mit-license.php ## All modifications and contributions by other persons to ## this script are assumed to have been donated to the ## Logwatch project and thus assume the above copyright ## and licensing terms. If you want to make contributions ## under your own copyright or a different license this ## must be explicitly stated in the contribution an the ## Logwatch project reserves the right to not accept such ## contributions. If you have made significant ## contributions to this script and want to claim ## copyright please contact logwatch-devel@lists.sourceforge.net. ######################################################### use strict; use warnings; use URI::URL; my $Detail = $ENV{'LOGWATCH_DETAIL_LEVEL'} || 0; my $Ignore_messages = $ENV{'ignore_messages'} || '^$'; my $Ignore_profile_program = $ENV{'ignore_profile_program'} || '^$'; my $Laptops = $ENV{'laptops'} || '^$'; my %Applications; while (defined(my $ThisLine = )) { # User specified ignore messages, lower cased next if $ThisLine =~ /$Ignore_messages/i; my ($Criticality,$SourceName,$DateTime,$EventID,$Application,$UserName,$SIDType,$EventLogType,$Hostname,$CategoryString,$DataString,$ExpandedString,$Extra); #Determine format if ($ThisLine =~ /MSWinEventLog\[/) { # Snare 4 #Parse ($Criticality,$SourceName,$DateTime,$EventID,$Application,$UserName,$SIDType,$EventLogType,$Hostname,$CategoryString,$DataString,$ExpandedString,$Extra) = ($ThisLine =~ /(\S+)\sMSWinEventLog\[(\d+)\]:(\w+)\t\d+\t([^\t]+)\t(\d+)\t([^\t]+)\t([^\t]+)\t([^\t]+)\t([^\t]+)\t([^\t]+)\t?([^\t]*)\t?([^\t]*)\t?([^\t]*)\t?([^\t]*)/); } elsif ($ThisLine =~ /MSWinEventLog\t/) { # Snare 3 #Parse ($Criticality,$SourceName,$DateTime,$EventID,$Application,$UserName,$SIDType,$EventLogType,$Hostname,$CategoryString,$DataString,$ExpandedString,$Extra) = ($ThisLine =~ /MSWinEventLog\t(\d+)\t(\w+)\t\d+\t([^\t]+)\t(\d+)\t([^\t]+)\t([^\t]+)\t([^\t]+)\t([^\t]+)\t([^\t]+)\t?([^\t]*)\t?([^\t]*)\t?([^\t]*)\t?([^\t]*)/); } if (!defined($Hostname)) { print STDERR "Cannot parse $ThisLine"; next; } next if $EventLogType eq "Information" and $ExpandedString !~ "BlueScreen"; next if $ExpandedString eq "N/A"; # Modify some items that prevent de-duplication if ($Detail < 10) { $ExpandedString =~ s/(NextScheduled\S+|PID) \d+/$1 XXX/; $ExpandedString =~ s,\d{4}/\d\d/\d\d \d\d:\d\d:\d\d(?:\.\d+)?,TIME,g; $ExpandedString =~ s/(?:\w{3}, )?\d{2} \w{3} \d{4},? \d\d:\d\d(?::\d\d \w{3})?/TIME/g; $ExpandedString =~ s/(SessionId|ThreadId):( ?0x)[0-9A-Fa-f]{2,16}(?::0x[0-9a-f]{5})?/$1:${2}XXXX/g; $ExpandedString =~ s/Session-trace:.*$/Session-trace: XXXX/; } #print STDERR "ExpandedString = $ExpandedString\n"; if ($Application =~ /Userenv/) { $ExpandedString = "$UserName $ExpandedString"; } if ($Application eq "Application Error") { if (my ($exe, $exever, $module, $modulever) = ($ExpandedString =~ /Faulting application name: (.*), version: (\S+), time stamp: .*Faulting module name: (.*), version: (\S+)/)) { $Applications{$Application}->{"$Hostname: Faulting application name: $exe, version: $exever, module name: $module, version $modulever"}++; next; } } elsif ($Application eq "Application Hang") { if (my ($exe, $exever, $msg) = ($ExpandedString =~ /The program (.*) version (\S+) (.*) Process ID:/)) { $Applications{$Application}->{"$Hostname: The program $exe version $exever $msg"}++; next; } else { print "Application Hang: Cannot parse $ExpandedString\n"; } } elsif ($Application eq "AutoEnrollment") { #Ignore these - we don't run active directory next if $ExpandedString =~ /Automatic certificate enrollment for local system failed to contact the active directory/; } elsif ($Application =~ /^Group Policy/) { next if $ExpandedString =~ /This error was suppressed/; next if $ExpandedString =~ /could not apply .* The network path was not found/ and $Hostname =~ /$Laptops/i; } elsif ($Application =~ /Intel Alert/) { #Ignore these next if $ExpandedString =~ /Intel Alert Originator Manager loaded without security/; next if $ExpandedString =~ /Service Initialized Successfully/; } elsif ($Application =~ /LoadPerf/) { #Ignore these next if $ExpandedString =~ /Performance counters for the .* service were loaded successfully/; next if $ExpandedString =~ /Performance counters for the .* service were removed successfully/; } elsif ($Application =~ /NSCTOP/) { #Ignore these next if $ExpandedString =~ /Service started/; } elsif ($Application eq "Microsoft-Windows-CertificationAuthority") { next if $ExpandedString =~ /The Active Directory connection to .* has been reestablished to/; } elsif ($Application eq "Microsoft-Windows-Search") { next if $ExpandedString =~ /The content source .* cannot be accessed. Context: Application, SystemIndex Catalog Details: The object was not found/; } elsif ($Application eq "Microsoft-Windows-User Profiles Service") { if ( my ($program) = ($ExpandedString =~ /^Windows detected your registry file is still in use by other applications or services. The file will be unloaded now\..* Process \d+ \(\\Device\\.*\\(.*)\) has opened key .*/)) { next if $program =~ /$Ignore_profile_program/; } } elsif ($Application =~ /Norton Ghost/) { #Ignore these next if $ExpandedString =~ /Norton Ghost service started successfully/; next if $ExpandedString =~ /A scheduled baseline backup of .* completed successfully/; next if $ExpandedString =~ /A scheduled incremental backup of .* completed successfully/; } elsif ($Application =~ /SecurityCenter/) { #Ignore these - appears to be normal http://www.eventid.net/display.asp?eventid=1807&eventno=4468&source=SecurityCenter&phase=1 next if $ExpandedString =~ /The Security Center service has been stopped. It was prevented from running by a software group policy/; } elsif ($Application eq "SceCli") { next if $ExpandedString =~ /^Security policy cannot be propagated\. Cannot access the template\. Error code = 3\./ and $Hostname =~ /$Laptops/i; } elsif ($Application eq "ShadowProtectSPX") { next if $ExpandedString =~ /^Backup Finished/; next if $ExpandedString =~ /^Backup Failed .*\(\\\\.*The backup destination is not accessible/ and $Hostname =~ /$Laptops/i; } elsif ($Application =~ /SNARE/) { #Ignore these next if $ExpandedString =~ /The service was started/; next if $ExpandedString =~ /The service was stopped/; } elsif ($Application eq "SpeechRuntime") { next if $ExpandedString =~ /^Audio Orchestrator Power Event: Battery Saver Turned On, Voice Activation Disabled/; } elsif ($Application =~ /Symantec AntiVirus/) { #Ignore these next if $ExpandedString =~ /Symantec AntiVirus services startup was successful/; next if $ExpandedString =~ /Scan Complete: Risks: 0/; next if $ExpandedString =~ /Scan started on all drives and all extensions/; next if $ExpandedString =~ /Scan started on selected drives and folders and all extensions/; next if $ExpandedString =~ /Download of virus definition file from LiveUpdate server succeeded/; next if $ExpandedString =~ /Virus definitions are current/; next if $ExpandedString =~ /Could not scan \d+ files inside .* due to extraction errors encountered by the Decomposer Engines/; } elsif ($Application eq "openvpnserv") { next if $ExpandedString eq "The operation completed successfully."; } elsif ($Application =~ /cc.*Mgr/) { #Ignore these next if $ExpandedString =~ /service is starting/; next if $ExpandedString =~ /service has started/; } my $url = URI::URL->new("http://www.eventid.net/display.asp?eventid=$EventID&source=$Application"); my $urlstr = $url->abs; $Applications{$Application}->{"$Hostname: $ExpandedString\n$url"}++; } if (keys %Applications) { foreach my $Application (sort(keys %Applications)) { print "\n$Application\n"; foreach my $Error (sort(keys %{$Applications{$Application}})) { print " $Error : $Applications{$Application}->{$Error} Times\n"; } } } exit(0); # vi: shiftwidth=3 tabstop=3 syntax=perl et # Local Variables: # mode: perl # perl-indent-level: 3 # indent-tabs-mode: nil # End: logwatch-7.12/scripts/services/mdadm0000644000211400021140000001104714667155202017775 0ustar logwatchlogwatch ######################################################## # Please file all bug reports, patches, and feature # requests under: # https://sourceforge.net/p/logwatch/_list/tickets # Help requests and discusion can be filed under: # https://sourceforge.net/p/logwatch/discussion/ ######################################################## ##################################################### ## Copyright (c) 2012 Pat Riehecky ## Covered under the included MIT/X-Consortium License: ## http://www.opensource.org/licenses/mit-license.php ## All modifications and contributions by other persons to ## this script are assumed to have been donated to the ## Logwatch project and thus assume the above copyright ## and licensing terms. If you want to make contributions ## under your own copyright or a different license this ## must be explicitly stated in the contribution an the ## Logwatch project reserves the right to not accept such ## contributions. If you have made significant ## contributions to this script and want to claim ## copyright please contact logwatch-devel@lists.sourceforge.net. ######################################################### use strict; my $Detail = $ENV{'LOGWATCH_DETAIL_LEVEL'} || 0; my $enable_scan = $ENV{'mdadm_enable_scan'} || 0; my $ignore_missing = $ENV{'mdadm_ignore_missing'} || 0; my @devices = (); my $mdadm; if ( open($mdadm, "<", "/etc/mdadm.conf") or open($mdadm, "<", "/etc/mdadm/mdadm.conf") or open($mdadm, "-|", "mdadm --detail --scan")) { while (<$mdadm>) { if (/^ARRAY/) { push(@devices,(split())[1]); } } close($mdadm); } DEV: foreach my $dev (@devices) { my %mdhash; if ($dev =~ //) { next; } open(MDADM,"mdadm --misc --detail $dev 2>&1 |"); while () { if ($_ =~ /cannot open .*: No such file or directory/) { print $_ unless $ignore_missing; close(MDADM); next DEV; } $mdhash{'level'} = $1 if ($_ =~ /Raid Level ?: ?(.*)$/); $mdhash{'active'} = $1 if ($_ =~ /Active Devices ?: ?(.*)$/); $mdhash{'working'} = $1 if ($_ =~ /Working Devices ?: ?(.*)$/); $mdhash{'failed'} = $1 if ($_ =~ /Failed Devices ?: ?(.*)$/); $mdhash{'spare'} = $1 if ($_ =~ /Spare Devices ?: ?(.*)$/); $mdhash{'state'} = $1 if ($_ =~ /State ?: ?(.*)$/); $mdhash{'rebuild'} = $1 if ($_ =~ /Rebuild Status ?: ?(.*)$/); push(@{$mdhash{'good devices'}},$1) if ($_ =~ /sync .*(\/dev\/[\w\d\-\_]*)/); push(@{$mdhash{'middle devices'}},$1) if ($_ =~ /rebuilding .*(\/dev\/[\w\d\-\_]*)/); push(@{$mdhash{'bad devices'}},$1) if ($_ =~ /faulty .*(\/dev\/[\w\d\-\_]*)/); } close(MDADM); if ($Detail <= 4) { if (lc($mdhash{'state'}) =~ /clean|active/) { print "$dev : $mdhash{'state'}\n" if $Detail; } else { print "$dev : $mdhash{'state'}\n"; if (defined($mdhash{'middle devices'})) { if (defined($mdhash{'rebuild'}) and ($mdhash{'rebuild'} ne '')) { print "\tRebuilding status: $mdhash{'rebuild'}\n"; } print "\tRebuilding @{$mdhash{'middle devices'}}\n"; } if (defined($mdhash{'bad devices'})) { print "\tFailed @{$mdhash{'bad devices'}}\n"; } } } elsif($Detail <= 9) { if (lc($mdhash{'state'}) =~ /clean|active/) { print "$dev : $mdhash{'state'} - @{$mdhash{'good devices'}}\n"; } else { print "$dev : $mdhash{'state'}\n"; if (@{$mdhash{'middle devices'}}) { if (defined($mdhash{'rebuild'}) and ($mdhash{'rebuild'} ne '')) { print "\tRebuilding status: $mdhash{'rebuild'}\n"; } print "\t Rebuilding : @{$mdhash{'middle devices'}}\n"; } if (@{$mdhash{'bad devices'}}) { print "\t Failed : @{$mdhash{'bad devices'}}\n"; } print "\t Good : @{$mdhash{'good devices'}}\n"; } } else { print "$dev : $mdhash{'state'}\n"; print "\t Raid Level : $mdhash{'level'}\n"; if (defined($mdhash{'good devices'}) and @{$mdhash{'good devices'}}) { print "\tGood Devices : @{$mdhash{'good devices'}}\n"; } if (defined ($mdhash{'middle devices'}) and @{$mdhash{'middle devices'}}) { if (defined($mdhash{'rebuild'}) and ($mdhash{'rebuild'} ne '')) { print "\tRebuilding status: $mdhash{'rebuild'}\n"; } print "\t Rebuilding : @{$mdhash{'middle devices'}}\n"; } if (defined($mdhash{'bad devices'}) and @{$mdhash{'bad devices'}}) { print "\t Failed : @{$mdhash{'bad devices'}}\n"; } if ($mdhash{'spare'} ne 0) { print "\t Spares : $mdhash{'spare'}\n"; } print "\n"; } } logwatch-7.12/scripts/services/dropbear0000664000211400021140000001520514743365003020510 0ustar logwatchlogwatch######################################################## # Please file all bug reports, patches, and feature # requests under: # https://sourceforge.net/p/logwatch/_list/tickets # Help requests and discusion can be filed under: # https://sourceforge.net/p/logwatch/discussion/ ######################################################## ####################################################### ## Copyright (c) 2021-2022 Orion Poplawski ## Covered under the included MIT/X-Consortium License: ## http://www.opensource.org/licenses/mit-license.php ## All modifications and contributions by other persons to ## this script are assumed to have been donated to the ## Logwatch project and thus assume the above copyright ## and licensing terms. If you want to make contributions ## under your own copyright or a different license this ## must be explicitly stated in the contribution an the ## Logwatch project reserves the right to not accept such ## contributions. If you have made significant ## contributions to this script and want to claim ## copyright please contact logwatch-devel@lists.sourceforge.net. ######################################################### use warnings; use strict; use Logwatch ':all'; my $Debug = $ENV{'LOGWATCH_DEBUG'} || 0; my $Detail = $ENV{'LOGWATCH_DETAIL_LEVEL'} || 0; my $IgnoreHost = $ENV{'ignore_host'} || ""; my $IllegalUsersThreshold = $ENV{'illegal_users_threshold'} || 0; $main::DoLookup = $ENV{'sshd_ip_lookup'}; my $DebugCounter = 0; #Init String Containers my ( $Host, $Key, $Method, $Port, $User, $user, ); my %Users = (); my %NonexistentUsers = (); my %BadPassword = (); my %OtherList = (); my $NetworkErrors = 0; my $Kills = 0; while (defined(my $ThisLine = )) { chomp($ThisLine); if ( ($ThisLine =~ /Connection reset by peer/) or ($ThisLine =~ /^Child connection from/) or ($ThisLine =~ /Disconnect received/) or ($ThisLine =~ /Exited normally/) or ($ThisLine =~ /Not backgrounding/) or 0 # This line prevents blame shifting as lines are added above ) { # Ignore these } elsif ( ($Method,$User,$Host,$Port) = ($ThisLine =~ /^(\S+) auth succeeded for '(.*)' from ([\d\.:a-f]+)(?:%\w+)?:(\d+)/) ) { if ($Detail >= 20) { $Users{$User}{$Host}{$Method}++; } else { if ( $Host !~ /$IgnoreHost/ ) { $Users{$User}{$Host}{"(all)"}++; } } } elsif ( ($Method,$User,$Key,$Host,$Port) = ($ThisLine =~ /^(\S+) auth succeeded for '(.*)' with.* key (.*) from ([\d\.:a-f]+)(?:%\w+)?:(\d+)/) ) { if ($Detail >= 20) { $Users{$User}{$Host}{$Method . " ($Key)"}++; } else { if ( $Host !~ /$IgnoreHost/ ) { $Users{$User}{$Host}{"(all)"}++; } } } elsif ( ($ThisLine =~ m/^Error reading/ ) or 0 ) { $NetworkErrors++; } elsif ( ($User,$Host) = ($ThisLine =~ /^Bad password attempt for '(.*)' from ([^ ]*):/)) { $BadPassword{$Host}{$User}++; } elsif ( ($Host) = ($ThisLine =~ /^Login attempt for nonexistent user from ([^ ]*):/)) { $NonexistentUsers{$Host}++; } elsif ( $ThisLine =~ /^Login attempt for nonexistent user/) { $NonexistentUsers{"unknown"}++; } elsif ( $ThisLine =~ m/Terminated by signal/) { $Kills++; } else { $OtherList{$ThisLine} += 1; } } ########################################################### sub timesplural { my ($count) = @_; my $plural = ($count > 1) ? "s" : ""; return "$count Time$plural\n"; } if ($NetworkErrors) { print "\nNetwork Read Write Errors: " . $NetworkErrors . "\n"; } if ($Kills) { print "\nKilled: " . timesplural($Kills); } if (keys %BadPassword) { print "\nBad password attempts:\n"; foreach my $ip (sort SortIP keys %BadPassword) { my $name = LookupIP($ip); my $totcount = 0; foreach my $user (keys %{$BadPassword{$ip}}) { $totcount += $BadPassword{$ip}{$user}; } print " $name: ". timesplural($totcount); if ($Detail >= 5) { my $sort = CountOrder(%{$BadPassword{$ip}}); foreach my $user (sort $sort keys %{$BadPassword{$ip}}) { my $val = $BadPassword{$ip}{$user}; print " $user: " . timesplural($val); } } } } if (keys %NonexistentUsers) { print "\nNon-existent users from"; if ($IllegalUsersThreshold) { print " (with threshold >= $IllegalUsersThreshold)"; } print ":\n"; foreach my $ip (sort SortIP keys %NonexistentUsers) { my $name = LookupIP($ip); print " $name: " . timesplural($NonexistentUsers{$ip}); } } if (keys %Users) { print "\nUsers logging in through sshd:\n"; foreach my $user (sort {$a cmp $b} keys %Users) { print " $user:\n"; if ($Detail < 20) { my $totalSort = TotalCountOrder(%{$Users{$user}}, \&SortIP); foreach my $ip (sort $totalSort keys %{$Users{$user}}) { my $name = LookupIP($ip); my $val = (values %{$Users{$user}{$ip}})[0]; print " $name: " . timesplural($val); } } else { my %Methods = (); foreach my $ip (keys %{$Users{$user}}) { foreach my $method (keys %{$Users{$user}{$ip}}) { $Methods{$method}{$ip} = $Users{$user}{$ip}{$method}; } } if (scalar keys %{$Users{$user}} < scalar %Methods) { my $totalSort = TotalCountOrder(%{$Users{$user}}, \&SortIP); foreach my $ip (sort $totalSort keys %{$Users{$user}}) { my $name = LookupIP($ip); print " $name:\n"; my $sort = CountOrder(%{$Users{$user}{$ip}}); foreach my $method (sort $sort keys %{$Users{$user}{$ip}}) { my $val = $Users{$user}{$ip}{$method}; print " $method: " . timesplural($val); } } } else { my $totalSort = TotalCountOrder(%Methods); foreach my $method (sort $totalSort keys %Methods) { print " $method:\n"; my $sort = CountOrder(%{$Methods{$method}}); foreach my $ip (sort $sort keys %{$Methods{$method}}) { my $name = LookupIP($ip); my $val = (values %{$Users{$user}{$ip}})[0]; print " $name: " . timesplural($val); } } } } } } if (keys %OtherList) { print "\n**Unmatched Entries**\n"; print "$_ : " . timesplural($OtherList{$_}) foreach sort keys %OtherList; } exit(0); # vi: shiftwidth=3 tabstop=3 syntax=perl et # Local Variables: # mode: perl # perl-indent-level: 3 # indent-tabs-mode: nil # End: logwatch-7.12/scripts/services/secure0000664000211400021140000012504014732340353020176 0ustar logwatchlogwatch ######################################################## # Please file all bug reports, patches, and feature # requests under: # https://sourceforge.net/p/logwatch/_list/tickets # Help requests and discusion can be filed under: # https://sourceforge.net/p/logwatch/discussion/ ######################################################## ####################################################### ## Copyright (c) 2008 Kirk Bauer ## Covered under the included MIT/X-Consortium License: ## http://www.opensource.org/licenses/mit-license.php ## All modifications and contributions by other persons to ## this script are assumed to have been donated to the ## Logwatch project and thus assume the above copyright ## and licensing terms. If you want to make contributions ## under your own copyright or a different license this ## must be explicitly stated in the contribution an the ## Logwatch project reserves the right to not accept such ## contributions. If you have made significant ## contributions to this script and want to claim ## copyright please contact logwatch-devel@lists.sourceforge.net. ######################################################### use strict; use Logwatch ':ip'; my $Detail = $ENV{'LOGWATCH_DETAIL_LEVEL'} || 0; DoLookup( $ENV{'secure_ip_lookup'} ); my $Ignore = $ENV{'ignore_services'} || 0; my $Summarize = $ENV{'summarize_connections'} || 0; #Init Counters my $ConsoleLock = 0; my $spop3d_opened=0; my $spop3d_errors=0; my $pwd_file_unknown = 0; my $pwd_file_too_short = 0; my $Executed_app = 0; my $PwdChange = 0; my $RequestKeyFailures = 0; #Init String Containers my ( $Client, $Connections, $DeletedGroups, $DeletedUsers, $Display, $Err, $FailedLogins, $FailedSaver, $From, $GID, $Group, $Host, $IP, $Library, $Message, $Module, $Name, $Name1, $Name2, $NewGroups, $NewName, $NewUsers, $NoIP, $PID, $PopErr, $PopUser, $Reason, $Refused, $RootLoginTTY, $RootLoginXVC, $Service, $SetGroupMembers, $Su, $Su_msg, $To, $UID1, $UID2, $User, $Username, $from, $service, ); #Init Arrays my @RemoveFromGroup = (); #Init Hashes my ( %AccountExpiry, %AddToGroup, %ChangedGID, %ChangedShell, %ChangedUID, %ChangedUserName, %ChkPasswdPam, %DeniedAccess, %DeprecateModule, %Error, %Executed_app, %FailedAddUsers, %Failures, %GidChange, %GroupChanged, %GroupRenamed, %HomeChange, %KerbList, %MissingLib, %NameVerifyFail, %NoIP, %OtherList, %PasswordExpiry, %PopErrors, %PopLogin, %PwdChange, %RootkitHunter, %ShellChange, %Su_User, %Successes, %TallyOverflow, %UidChange, %UnknownUser, %UserInfChange, %UserLogin, %XauthMessage, %cvs_passwd_mismatch, %sshguardAttackers, ); while (defined(my $ThisLine = )) { chomp($ThisLine); $ThisLine =~ s/^... .. ..:..:.. [^ ]+ //; #Solaris ID filter -mgt $ThisLine =~ s/\[ID [0-9]+ [a-z]+\.[a-z]+\] //; my $temp = $ThisLine; $temp =~ s/^([^[:]+).*/$1/; if ($Ignore =~ /(\s|^)\Q$temp\E(\s|$)/i) { next; } #current sarge if ($ThisLine =~ /^[^ :]*:( [0-9:\[\]\.]+|) \(pam_(unix|securetty)\)/i ) {next; } #Woody - specific, thanks to Michael Stovenour if ($ThisLine =~ /^PAM_unix[\[\]0-9]*:/i ) { next; } if (( $ThisLine =~ /pam_succeed_if(\([a-zA-Z-]*:[a-zA-Z]*\))?: requirement \"uid (<|>)=? (5|10)00?\" (was|not) met by user /) or ( $ThisLine =~ /pam_rhosts_auth\[\d+\]: allowed to [^ ]+ as \w+/) or ( $ThisLine =~ /pam_rhosts_auth\([^\)]+\): allowed to [^ ]+ as \w+/) or ( $ThisLine =~ /^(.*)\(pam_unix\)/) or ( $ThisLine =~ /pam_unix\(.*:.*\)/) or ( $ThisLine =~ /pam_sss\(.*:.*\)/) or ( $ThisLine =~ m/^[^ ]+\[\d+\]: connect from localhost$/ ) or ( $ThisLine =~ /^halt:/) or ( $ThisLine =~ /^com.apple.SecurityServer: Succeeded authorizing right system.(preferences|login.console|login.tty|login.done|privilege.admin) by process/) or ( $ThisLine =~ /^pam_xauth\[\d+\]: call_xauth: child returned \d/) or ( $ThisLine =~ /^su\[\d+\]: pam_authenticate: Authentication failure/) or ( $ThisLine =~ /^passwd\[\d+\]:/) or ( $ThisLine =~ /^passwd: gkr-pam: .*/) or ( $ThisLine =~ /^reboot:/) or ( $ThisLine =~ /^(?:\/usr\/bin\/)?sudo(?:\[\d+\])?:/) or ( $ThisLine =~ /^su: pam_unix2: session (started|finished) for user [^ ]+, service [^ ]+/) or ( $ThisLine =~ /^xinetd\[\d+\]: USERID: ([^ ]+) (.+)$/ ) or ( $ThisLine =~ /warning: can.t get client address: Connection refused/) or ( $ThisLine =~ /Showing Login Window/) or ( $ThisLine =~ /User Authenticated: continue login process/) or ( $ThisLine =~ /com.apple.SecurityServer: Entering service/) or ( $ThisLine =~ /^(xinetd|xinetd-ipv6)\[\d+\]: EXIT: /) or ( $ThisLine =~ /^crond\(\w+\)\[\d+\]: session /) or ( $ThisLine =~ /^dropbear\[\d+\]: /) or ( $ThisLine =~ /pam_systemd\(.+:session\): Moving/) or ( $ThisLine =~ /^sshd\(\w+\)\[\d+\]: authentication failure/) or ( $ThisLine =~ /^sshd\(\w+\)\[\d+\]: check pass; user unknown/) or ( $ThisLine =~ /^sshd\(\w+\)\[\d+\]: session /) or ( $ThisLine =~ /sshd\[\d+\]: Server listening on/) or ( $ThisLine =~ /sshd\[\d+\]: Received signal \d+; terminating/) or ( $ThisLine =~ /sshd\[\d+\]: Disconnected from user/) or ( $ThisLine =~ /sshd\[\d+\]: Received disconnect from/) or ( $ThisLine =~ /sshd\[\d+\]: message repeated/) or ( $ThisLine =~ /sshd-session\[\d+\]: Disconnected from /) or ( $ThisLine =~ /sshd-session\[\d+\]: Received disconnect from /) or ( $ThisLine =~ /^ipop3d\[\d+\]:/) or ( $ThisLine =~ /^su\[\d+\]: [+-] .+/) or ( $ThisLine =~ /^su\[\d+\]: FAILED su for \S+ by \S+/) or #debian: done in pam_unix ( $ThisLine =~ /^login\[\d+\]: ROOT LOGIN on '\S+'/) or #debian: done in pam_unix (Similar message on other system is reported) ( $ThisLine =~ /^login(?:\[\d+\])?: FAILED LOGIN \(\d+\) on ['`]\S+' FOR `\S+', (Authentication failure|User not known to the underlying authentication module)/) or #debian: done in pam_unix ( $ThisLine =~ /^login: FAILED LOGIN 2 FROM (.*) FOR .*, (Authentication failure|User not known to the underlying authentication module)/) or ( $ThisLine =~ /^login: pam_securetty(.*): unexpected response from failed conversation function/) or ( $ThisLine =~ /^login: pam_securetty(.*): access denied: tty '.*' is not secure/) or ( $ThisLine =~ /^login: pam_securetty(.*): cannot determine username/) or ( $ThisLine =~ /^pam_limits\[\d+\]/ ) or ( $ThisLine =~ /^kcheckpass(\[\d+\]|):/ ) or # done in pam_unix ( $ThisLine =~ /^cyrus\/lmtpd\[\d+\]: [^ ]+ server step [12]/ ) or ( $ThisLine =~ /^cyrus\/imapd\[\d+\]: [^ ]+ server step [12]/ ) or ( $ThisLine =~ /pam_timestamp: updated timestamp file/) or ( $ThisLine =~ /pam_timestamp\(?[^ ]*\)?: timestamp file `([^ ]+)' is only \d+ seconds old, allowing access to ([^ ]+) for user ([^ ]+)/) or ( $ThisLine =~ /pam_timestamp\(?[^ ]*\)?: timestamp file `([^ ]+)' (has unacceptable age \(\d+ seconds\)|is older than oldest login), disallowing access to ([^ ]+) for user ([^ ]+)/) or ( $ThisLine =~ /userhelper\[\d+\]: running '([^ ]+)' with [^ ]+ context/) or ( $ThisLine =~ /pam_timestamp\(.*:session\): updated timestamp file `\/var\/run\/sudo.*'/) or ( $ThisLine =~ /[^ ]*: pam_keyinit(.*:.*): Unable to change GID to [0-9]* temporarily/) or ( $ThisLine =~ /password check failed for user \(\S*\)/) or ( $ThisLine =~ /PAM pam_set_item: attempt to set conv\(\) to NULL/) or ( $ThisLine =~ /PAM pam_get_item: nowhere to place requested item/) or ( $ThisLine =~ /pam_succeed_if\(.*:.*\): error retrieving information about user [a-zA-Z]*/ ) or ( $ThisLine =~ /pam_selinux_permit\(.*:.*\):/ ) or ( $ThisLine =~ /logfile turned over/) or # newsyslog on OpenBSD ( $ThisLine =~ /vmware-authd\[[0-9]+\]: PAM \[error: [^ ]+ cannot open shared object file: No such file or directory\]/) or ( $ThisLine =~ /vmware-authd\[[0-9]+\]: PAM adding faulty module: [^ ]+/) or ( $ThisLine =~ /Connection closed by/) or ( $ThisLine =~ /Conversation error/) or ( $ThisLine =~ /sshd.*: Accepted \S+ for \S+ from [\d\.:a-f]+ port \d+/) or # ssh script reads this log ( $ThisLine =~ /userhelper.*: running (.*) with context (.*)/) or ( $ThisLine =~ /userhelper.*: pam_thinkfinger(.*): conversation failed/) or ( $ThisLine =~ /su: PAM [0-9] more authentication failure; .*/) or ( $ThisLine =~ /su: No passwd entry for user '(.*)'/) or ( $ThisLine =~ /polkit-grant-helper\[\d+\]: granted authorization for [^ ]* to uid [0-9]* \[auth=.*\]/) or ( $ThisLine =~ /polkit-grant-helper\[\d+\]: granted authorization for [^ ]* to session .* \[uid=[0-9]*\]/) or ( $ThisLine =~ /polkit-grant-helper-pam\[\d+\]: pam_thinkfinger\(polkit:auth\): conversation failed/) or ( $ThisLine =~ /polkitd(\(authority=.*\)|\[\d+\])?: (Unr|R)egistered Authentication Agent/) or ( $ThisLine =~ /polkitd(\(authority=.*\)|\[\d+\])?: Operator of unix-session:/) or ( $ThisLine =~ /polkitd(\(authority=.*\)|\[\d+\])?: Acquired the name [^ ]* on the system bus$/) or ( $ThisLine =~ /polkitd(\(authority=.*\)|\[\d+\])?: Lost the name [^ ]* - exiting$/) or ( $ThisLine =~ /polkitd(\(authority=.*\)|\[\d+\])?: Loading rules from directory /) or ( $ThisLine =~ /polkitd(\(authority=.*\)|\[\d+\])?: Reloading rules/) or ( $ThisLine =~ /polkitd(\(authority=.*\)|\[\d+\])?: Finished loading, compiling and executing \d+ rules$/) or ( $ThisLine =~ /polkitd(\(authority=.*\)|\[\d+\])?: Collecting garbage unconditionally/) or ( $ThisLine =~ /gkr-pam: gnome-keyring-daemon started properly/) or ( $ThisLine =~ /gkr-pam: no password is available for user/) or ( $ThisLine =~ /gkr-pam: stashed password to try later in open session/) or ( $ThisLine =~ /gkr-pam: the password for the login keyring was invalid/) or ( $ThisLine =~ /gkr-pam: unable to locate daemon control file/) or ( $ThisLine =~ /gkr-pam: unlocked login keyring/) or ( $ThisLine =~ /groupadd\[\d+\]: group added to /) or # Details in other messages ( $ThisLine =~ /groupmod\[\d+\]: group changed in \/etc\/gshadow /) or # Details in other messages ( $ThisLine =~ /gdm-session-worker\[\d+\]: pam_namespace\(gdm:session\): Unmount of [^ ]* failed, Device or resource busy/) or ( $ThisLine =~ /pkexec: pam_systemd(.*): /) or ( $ThisLine =~ /pkexec(?:\[\d+\])?: \S+: Executing command /) or ( $ThisLine =~ /su: pam_systemd(.*): Failed to parse message: /) or ( $ThisLine =~ /pam_systemd\(su:session\): Cannot create session: Already (running in|occupied by) a session/) or ( $ThisLine =~ /pam_systemd\(su.*:session\): Failed to release session:/) or ( $ThisLine =~ /elogind-daemon\[\d+\]: (New|Removed) session/) or ( $ThisLine =~ /systemd-logind\[\d+\]: (New|Removed) session/) or ( $ThisLine =~ /systemd-logind\[\d+\]: New seat seat\d+\./) or ( $ThisLine =~ /systemd-logind\[\d+\]: Watching system buttons on /) or ( $ThisLine =~ /systemd-logind\[\d+\]: Failed to start session scope (\S+): Transaction is destructive\./) or ( $ThisLine =~ /systemd-logind\[\d+\]: Session \d+ logged out/) or ( $ThisLine =~ /systemd\[\d+\]: pam_systemd\(login:session\): .*release session:/) or ( $ThisLine =~ /DIGEST-MD5 common mech free/) or ( $ThisLine =~ /sshguard\[\d+\]: Reloading rotated file /) or ( $ThisLine =~ /sshguard\[\d+\]: Session \d+ logged out/) or ( $ThisLine =~ /sshguard\[\d+\]: Exiting on signal/) or ( $ThisLine =~ /sshguard\[\d+\]: Monitoring attacks from /) or ( $ThisLine =~ /sshguard\[\d+\]: (?:message repeated \d+ times: \[ )?\S+: not blocking /) or ( $ThisLine =~ /sshguard\[\d+\]: Received EOF from stdin/) or ( $ThisLine =~ /sshguard\[\d+\]: .*has already been blocked/) or ( $ThisLine =~ /gnome-keyring-daemon\[\d+\]: asked to register item.*already registered/) or ( $ThisLine =~ /cannot determine display-device/) or 0 # This line prevents blame shifting as lines are added above ) { # Ignore these entries } elsif ($ThisLine =~ /^spop3d/ || $ThisLine =~ /^pop\(\w+\)\[\d+\]:/) { my @line=split(": ",$ThisLine); if ($line[1]=~/^session opened for user/) { $spop3d_opened++; my @bzz=split(" ",$line[1]); $PopUser= $bzz[4]; $PopLogin{$PopUser}++; } if ($line[1]=~/^authentication failure;/) { # authentication failure; logname= uid=0 euid=0 tty= # ruser= rhost= user=xavier $spop3d_errors++; my @bzz=split(" user=",$line[1]); $PopErr=$bzz[1]; $PopErrors{$PopErr}++; } } elsif ( ($Host,$User) = ($ThisLine =~ /^login: FAILED LOGIN \d+ FROM ([^ ]+) FOR ([^,]+),/ ) ) { $FailedLogins->{$User}->{$Host}++; } elsif ( ($Service,$IP) = ($ThisLine =~ /^([^ ]+)\[\d+\]: connect(ion)? from "?(\d+\.\d+\.\d+\.\d+).*/) ) { $Name = LookupIP($IP); if ($Summarize =~ /\Q$Service\E/) { $Connections->{$Service}++; } else { $Connections->{$Service}->{$Name}++; } } elsif ( ($Service,$Name) = ($ThisLine =~ /^(in\.rshd)\[\d+\]: (.*)/) ) { if ($Summarize =~ /\Q$Service\E/) { $Connections->{$Service}++; } else { $Connections->{$Service}->{$Name}++; } } elsif ( ($Service,$Su_msg) = ($ThisLine =~ /^(su)(?:\[\d+\])?:\s+('su \w+' succeeded for \w+) on/) ) { #Solaris su messages -mgt $Connections->{$Service}->{$Su_msg}++; } elsif ( ($Service,$Su_msg) = ($ThisLine =~ /^(su)(?:\[\d+\])?:\s+succeeded: (\w+ changing from \w+ to \w+)/) ) { #Irix su messages -mgt $Connections->{$Service}->{$Su_msg}++; } elsif ( ($Service,$IP) = ($ThisLine =~ /^([^ ]+)\[\d+\]: refused connect from (\d+\.\d+\.\d+\.\d+)$/) ) { $Name = LookupIP($IP); $Refused->{$Service}->{$Name}++; } elsif ( ($Service,$Name) = ($ThisLine =~ /^([^ ]+)\[\d+\]: refused connect from (.*)$/) ) { $Refused->{$Service}->{$Name}++; } elsif ( ($Service,$Name) = ($ThisLine =~ /^([^ ]+)\[\d+\]: connect from ([^\n]+)$/) ) { if ($Summarize =~ /\Q$Service\E/) { $Connections->{$Service}++; } else { $Connections->{$Service}->{$Name}++; } } elsif ( (undef, $Service, $IP) = ($ThisLine =~ /^(xinetd|xinetd-ipv6)\[\d+\]: START: ([^ ]+) pid=\d+ from=([^\n]+)$/) ) { if ($Ignore =~ /\b\Q$Service\E\b/i) { next; } if ($Summarize =~ /\Q$Service\E/) { $Connections->{$Service}++; } else { # the following is intended for the string, but captures # all non-IP addresses if ($IP =~ /^[A-Fa-f\d\.:]+$/ ) { $Name = LookupIP($IP); } else { $Name = $IP; } $Connections->{$Service}->{$Name}++; } #Solaris inetd this works if you start "inetd -s -t" then send daemon.notice to authlog -mgt } elsif ( ($Service, $IP) = ($ThisLine =~ /^inetd\[\d+\]: (\w+)\[\d+\] from ([^ \n]+) \d+$/) ) { if ($Ignore =~ /\b\Q$Service\E\b/i) { next; } if ($Summarize =~ /\Q$Service\E/) { $Connections->{$Service}++; } else { $Name = LookupIP($IP); $Connections->{$Service}->{$Name}++; } } elsif ( ($Service,undef,$Name) = ($ThisLine =~ /^([^ ]+)\[\d+\]: warning: ([^ ]+), line \d+: can't verify hostname: getaddrinfo\(([^ ]+), AF_INET\) failed$/) ) { $NameVerifyFail{$Service}{$Name}++; } elsif ( ($Service,undef,$Name,$IP) = ($ThisLine =~ /^([^ ]+)\[\d+\]: warning: ([^ ]+), line \d+: host name\/name mismatch: ([^ ]+) != ([^ ]+)$/) ) { $NameVerifyFail{$Service}{"$Name != $IP"}++; } elsif ( ($Display, $User) = ($ThisLine =~ /^xscreensaver\[\d+\]: FAILED LOGIN \d ON DISPLAY \"([^ ]+)\", FOR \"([^ ]+)\"$/) ) { $FailedSaver->{$User}->{$Display}++; } elsif ( $ThisLine =~ s/^([^ ]+)\[\d+\]: warning: can\'t get client address: No route to host$/$1/ ) { $NoIP->{$ThisLine}++; } elsif ( $ThisLine =~ s/^([^ ]+)\[\d+\]: warning: can\'t get client address: Network is unreachable$/$1/ ) { $NoIP->{$ThisLine}++; } elsif ( $ThisLine =~ s/^([^ ]+)\[\d+\]: warning: can\'t get client address: Connection reset by peer$/$1/ ) { $NoIP->{$ThisLine}++; } elsif ( $ThisLine =~ s/^([^ ]+)\[\d+\]: warning: can\'t get client address: Connection timed out$/$1/ ) { $NoIP->{$ThisLine}++; } elsif ( $ThisLine =~ s/^([^ ]+)\[\d+\]: connect from unknown$/$1/ ) { $NoIP->{$ThisLine}++; } elsif ( ($Service,$Err) = ($ThisLine =~ /^([^ ]+)\[\d+\]: error: (.+)$/) ) { $Error{$Service}{$Err}++; } elsif ( ($Service,$Err) = ($ThisLine =~ /^([^ ]+): (FAILED LOGIN SESSION FROM [^ ]+ FOR ([^ ]+)?, .*)$/ ) ) { $Error{$Service}{$Err}++; } elsif ( ($Service,$Err) = ($ThisLine =~ /^([^ ]+): (password mismatch for [^ ]+ in [^ ]+):.*$/ ) ) { $Error{$Service}{$Err}++; } elsif ( ($Service,$Err) = ($ThisLine =~ /^([^ ]+)\[\d+\]: (changed POP3 password for .*)$/ ) ) { $Error{$Service}{$Err}++; } elsif ( ($Service,$Err) = ($ThisLine =~ /^systemd\[\d+\]: ([^ ]+)\([^ ]+\): (.*failed.*)$/ ) ) { $Error{$Service}{$Err}++; } elsif ( ($Service,$Err) = ($ThisLine =~ /^(su)(?:\[\d+\])?: ('su \w+' failed for \w+)/ ) ) { #Solaris 10 su failed -mgt $Error{$Service}{$Err}++; } elsif ( ($Service,$Err) = ($ThisLine =~ /^(su): (FAILED SU \(to \w+\) \w+ on [^ ]+)/ ) ) { #SuSe su failed $Error{$Service}{$Err}++; } elsif ( ($Service,$Err) = ($ThisLine =~ /^(su): (BAD SU \w+ to \w+ on [^ ]+)/ ) ) { #OpenBSD su failed $Error{$Service}{$Err}++; } elsif ( $ThisLine =~ /^login(\[\d+\])*: ROOT LOGIN\s+(ON|on)\s+`?tty[0-9]+/) { $RootLoginTTY++ } elsif ( $ThisLine =~ /^login(\[\d+\])*: ROOT LOGIN\s+(ON|on)\s+`?xvc[0-9]+/) { $RootLoginXVC++ } elsif ( $ThisLine =~ /^com.apple.SecurityServer: authinternal authenticated user root .*/) { $RootLoginTTY++ } elsif ( (undef,undef,$User) = ($ThisLine =~ /^login(\[\d+\])*: LOGIN ON (tty|pts\/)[0-9]+ BY ([^ ]+)/ )) { $UserLogin{$User}++; } elsif ( ($User,undef) = ($ThisLine =~ /^com.apple.SecurityServer: authinternal authenticated user ([^ ]+) .*/ )) { $UserLogin{$User}++; } elsif ( $ThisLine =~ s/^userdel(?:\[\d+\])?: delete user [`'](.+)'/$1/ ) { $DeletedUsers .= " $ThisLine\n"; } elsif ( $ThisLine =~ s/^(?:useradd|adduser)(?:\[\d+\])?: new user: name=(.+), (?:uid|UID)=(\d+).*$/$1 ($2)/ ) { $NewUsers .= " $ThisLine\n"; } elsif ( $ThisLine =~ s/^userdel(?:\[\d+\])?: remove(?:d)? (?:shadow )?group [`'](\S+)'( owned by \S+)?/$1/ ) { $DeletedGroups .= " $ThisLine\n"; } elsif ( $ThisLine =~ s/^groupdel(?:\[\d+\])?: remove group `(.+)'/$1/ ) { $DeletedGroups .= " $ThisLine\n"; } elsif ( $ThisLine =~ s/^(?:useradd|adduser)(?:\[\d+\])?: new group: name=(.+), (?:gid|GID)=(\d+).*$/$1 ($2)/ ) { $NewGroups .= " $ThisLine\n"; } elsif ( (undef,$User,,undef,$Group) = ($ThisLine =~ /(usermod|useradd)(?:\[\d+\])?: add [`']([^ ]+)' to (shadow ?|)group [`']([^ ]+)'/ )) { $AddToGroup{$Group}{$User}++; } elsif ( ($User,undef,$Group) = ($ThisLine =~ /gpasswd: user (.+) added by (.+) to group (.+)/)) { $AddToGroup{$Group}{$User}++; } elsif ( $ThisLine =~ s/^groupadd(?:\[\d+\])?: new group: name=(.+), (?:gid|GID)=(\d+).*$/$1 ($2)/ ) { $NewGroups .= " $ThisLine\n"; } elsif ( $ThisLine =~ s/^gpasswd(?:\[\d+\])?: set members of // ) { $SetGroupMembers .= " $ThisLine\n"; } elsif ( $ThisLine =~ /^(?:userdel|usermod)(?:\[\d+\])?: delete [`'](.*)' from (shadow |)group [`'](.*)'\s*$/ ) { push @RemoveFromGroup, " user $1 from group $3\n"; # This is an inetd lookup... $1 is the service (i.e. ftp), $2 is the response # I don't think these are important to log at this time } elsif ( ($service, $from) = ($ThisLine =~ /^xinetd\[\d+\]: FAIL: (.+) (?:address|libwrap|service_limit|connections per second) from=([\d.]+)/)) { if ($Ignore =~ /\b\Q$service\E\b/i) { next; } $Refused->{$service}->{$from}++; } elsif ( ($from, $service, $User) = ($ThisLine =~ /^pam_abl\[\d+\]: Blocking access from (.+) to service (.+), user (.+)/)) { if ($Detail >= 5) { $Refused->{$service}->{$from."/".$User}++; } else { $Refused->{$service}->{$from}++; } } elsif ( ($User) = ($ThisLine =~ /^chage\[\d+\]: changed password expiry for ([^ ]+)/)) { $PasswordExpiry{$User}++; } elsif ( ($User) = ($ThisLine =~ /^chfn\[\d+\]: changed user `([^ ]+)' information/)) { $UserInfChange{$User}++; } elsif ( (undef) = ($ThisLine =~ /^pam_console\[\d+\]: console file lock already in place ([^ ]+)/ )) { $ConsoleLock++; } elsif ( ($Message) = ($ThisLine =~ /^pam_xauth\[\d+\]: call_xauth: (.+)/)) { $XauthMessage{$Message}++; } elsif ( ($Group,$NewName) = ($ThisLine =~ /^groupmod\[\d+\]: change group `(.*)' to `(.*)'/)) { $GroupRenamed{"$Group -> $NewName"}++; } elsif ( $ThisLine =~ s/^groupmod\[\d+\]: group changed in \/etc\/group \(group (.+)\/(\d+)\).*/$1 ($2)/) { $GroupChanged{"$ThisLine"}++; } elsif ( $ThisLine =~ s/^groupmod\[\d+\]: group changed in \/etc\/group \(group (.+)\/\d+, new name: (.+)\).*/$1 -> $2/) { $GroupChanged{"$ThisLine"}++; } elsif ( ($PID,$User,$From,$To) = ($ThisLine =~ /^usermod(\[\d+\])?: ?change user [`'](.*)' home from [`'](.*)' to [`'](.*)'/)) { $HomeChange{$User}{"$From -> $To"}++; } elsif ( ($PID,$User,$From,$To) = ($ThisLine =~ /^usermod(\[\d+\])?: ?change user [`'](.*)' shell from [`'](.*)' to [`'](.*)'/)) { $ShellChange{$User}{"$From -> $To"}++; } elsif ( ($PID,$User,$From,$To) = ($ThisLine =~ /^usermod(\[\d+\])?: ?change user [`'](.*)' UID from [`'](.*)' to [`'](.*)'/)) { $UidChange{"$User: $From -> $To"}++; } elsif ( ($PID,$User,$From,$To) = ($ThisLine =~ /^usermod(\[\d+\])?: ?change user [`'](.*)' GID from [`'](.*)' to [`'](.*)'/)) { $GidChange{"$User: $From -> $To"}++; } elsif ( ($PID,$User,$From,$To) = ($ThisLine =~ /^usermod(\[\d+\])?: ?change user [`'](.*)' expiration from [`'](.*)' to [`'](.*)'/)) { $AccountExpiry{"$User: $From -> $To"}++; # checkpassword-pam } elsif ( ($PID) = ($ThisLine =~ /^checkpassword-pam\[(\d+)\]: Reading username and password/)) { } elsif ( ($PID,$Username) = ($ThisLine =~ /^checkpassword-pam\[(\d+)\]: Username '([^']+)'/)) { $ChkPasswdPam{$PID}{'Username'} = $Username; } elsif ( ($PID) = ($ThisLine =~ /^checkpassword-pam\[(\d+)\]: Password read successfully/)) { } elsif ( ($PID,$Service) = ($ThisLine =~ /^checkpassword-pam\[(\d+)\]: Initializing PAM library using service name '([^']+)'/)) { $ChkPasswdPam{$PID}{'Service'} = $Service; } elsif ( ($PID) = ($ThisLine =~ /^checkpassword-pam\[(\d+)\]: Pam library initialization succeeded/)) { } elsif ( ($PID) = ($ThisLine =~ /^checkpassword-pam\[(\d+)\]: conversation\(\): msg\[0\], style PAM_PROMPT_ECHO_OFF, msg = "Password: "/)) { } elsif ( ($PID) = ($ThisLine =~ /^checkpassword-pam\[(\d+)\]: Authentication passed/)) { $ChkPasswdPam{$PID}{'Success'} = 'true'; } elsif ( ($PID) = ($ThisLine =~ /^checkpassword-pam\[(\d+)\]: Account management succeeded/)) { } elsif ( ($PID) = ($ThisLine =~ /^checkpassword-pam\[(\d+)\]: Setting PAM credentials succeeded/)) { } elsif ( ($PID) = ($ThisLine =~ /^checkpassword-pam\[(\d+)\]: Terminating PAM library/)) { } elsif ( ($PID) = ($ThisLine =~ /^checkpassword-pam\[(\d+)\]: Exiting with status 0/)) { } elsif ( ($User) = ($ThisLine =~ /^pam_tally\[\d+\]: pam_tally: pam_get_uid; no such user ([^ ]+)/)) { $UnknownUser{$User}++; } elsif ( ($User) = ($ThisLine =~ /^pam_tally\[\d+\]: Tally overflowed for user ([^ ]+)$/)) { $TallyOverflow{$User}++; } elsif ( ($User) = ($ThisLine =~ /^pam_pwdfile\[\d+\]: user not found in password database/) ) { $pwd_file_unknown++; } elsif ( ($User) = ($ThisLine =~ /^pam_pwdfile\[\d+\]: wrong password for user ([^ ]+)/)) { $UnknownUser{$User}++; } elsif ($ThisLine =~ /^pam_pwdfile\[\d+\]: password too short or NULL/) { $pwd_file_too_short++; } elsif ( ($User,$Su) = ($ThisLine =~ /^su: ([^ ]+) to ([^ ]+) on \/dev\/ttyp([0-9a-z]+)/) ) { $Su_User{$User}{$Su}++; } elsif ( ($Su,$User) = ($ThisLine =~ /^su: \(to ([^ ]+)\) ([^ ]+) on (?:none|(\/dev\/)?(pts\/|ttyp)([0-9]+))/) ) { $Su_User{$User}{$Su}++; } elsif ( ($Su,$User) = ($ThisLine =~ /^su\[\d+\]: Successful su for (\S+) by (\S+)/) ) { $Su_User{$User}{$Su}++; } elsif ($ThisLine =~ /^userhelper\[\d+\]: running '([^']+)' with ([^']+) privileges on behalf of '([^']+)'/) { $Executed_app{"$1,$2,$3"}++; } elsif ($ThisLine =~ /^polkitd\[\d+\]: Operator of unix-process:\d+:\d+ successfully authenticated as unix-user:([^ ]+) to gain ONE-SHOT authorization for action org\.freedesktop\..* for system-bus-name::[\d.]+ \[([^\]]*)\] \(owned by unix-user:(\w+)\)/) { $Executed_app{"$2,$1,$3"}++; } elsif ( ($User) = $ThisLine =~ /change user [`']([^']+)' password/) { $PwdChange{"$User"}++; } elsif ( ($User) = ($ThisLine =~ /^cvs: password mismatch for ([^']+): ([^']+) vs. ([^']+)/) ){ $cvs_passwd_mismatch{$User}++; } elsif ( ($User,$From,$To) = ($ThisLine =~ /usermod\[[0-9]*\]: change user `([^ ]*)' shell from `([^ ]*)' to `([^ ]*)'/) ) { $ChangedShell{"$User,$From,$To"}++; } elsif ( ($User,$To) = ($ThisLine =~ /chsh\[[0-9]*\]: change user [`']([^ ]*)' shell to [`']([^ ]*)'/) ) { $ChangedShell{"$User,,$To"}++; } elsif ( ($Name1,$Name2) = ($ThisLine =~ /usermod\[[0-9]*\]: change user name `([^ ]*)' to `([^ ]*)'/)) { $ChangedUserName{"$Name1,$Name2"}++; } elsif (($Name,$GID) = ($ThisLine =~ /change GID for `([^ ]*)' to ([0-9]*)/)) { $ChangedGID{"$Name,$GID"}++; } elsif (($Name,$UID1,$UID2) = ($ThisLine =~ /change user `([^ ]*)' UID from `([0-9]*)' to `([^ ]*)'/)) { $ChangedUID{"$Name,$UID1,$UID2"}++; } elsif (($Module,$Service) = ($ThisLine =~ /Deprecated (pam_[^ ]*) module called from service "([^ ]*)"/)) { $DeprecateModule{"$Module,$Service"}++; } elsif ( ($Library) = ($ThisLine =~ /vmware-authd\[\d+\]: PAM unable to dlopen\(([^ ]+)\)/) ) { $MissingLib{"$Library"}++ } elsif ( ($Client,$User) = ($ThisLine =~ /vmware-authd\[\d+\]: login from ([0-9\.]+) as ([^ ]+)/) ) { $UserLogin{$User}++; } elsif ( ($User) = ($ThisLine =~ /vmware-authd\[\d+\]: pam_unix_auth\(vmware-authd:auth\): authentication failure; logname= uid=0 euid=0 tty= ruser= rhost= user=([^ ]*)/) ) { } elsif ( ($User) = ($ThisLine =~ /useradd.*failed adding user [`'](.*)',/) ) { # useradd: failed adding user `rpcuser', data deleted # useradd: failed adding user `mysql', exit code: 9 $FailedAddUsers{$User}++; } elsif (($User,$Reason) = ($ThisLine =~ /dovecot-auth: pam_userdb\(dovecot:auth\): user `(.*)' denied access \((.*)\)/)) { # dovecot-auth: pam_userdb(dovecot:auth): user `bobok' denied access (incorrect password) $DeniedAccess{"$User,$Reason"}++; } elsif ($ThisLine =~ /^request-key: Cannot find command to construct key/) { $RequestKeyFailures++; } elsif (my ($type,$from,$response,$client,$service,$e) = ($ThisLine =~ /krb5kdc\[[0-9]*\]: (AS_REQ|TGS_REQ) \([0-9]+ etypes \{[ 0-9a-z\-\(\),]+}\) ([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+): (ISSUE|UNKNOWN_SERVER): authtime [0-9]+, (?:etypes \{rep=[0-9a-z\-\(\)]+, tkt=[0-9a-z\-\(\)]+, ses=[0-9a-z\-\(\)]+},)? ([^ ]+) for ([^ ,]+)(?:, )?(.*)$/)) { if($service=~/^krbtgt\/([^@]+)@\1/) { $service='Login'; } if($response eq 'UNKNOWN_SERVER' && $e eq 'Server not found in Kerberos database') { $response=$e; $e=''; } $KerbList{$response}{$type}{$from}{$service}{$client}{$e}++; } elsif (($type,$from,$response,$client,$service,$e) = ($ThisLine =~ /krb5kdc\[[0-9]*\]: (AS_REQ|TGS_REQ) \([0-9]+ etypes \{[ 0-9a-z\-\(\),]+}\) ([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+): (NEEDED_PREAUTH|PREAUTH_FAILED|CLIENT_NOT_FOUND): ([^ ]+) for ([^ ,]+)(?:, )?(.*)$/)) { if($service=~/^krbtgt\/([^@]+)@\1/) { $service='Login'; } if($response eq 'CLIENT_NOT_FOUND' && $e eq 'Client not found in Kerberos database') { $response=$e; $e=''; } elsif($response eq 'NEEDED_PREAUTH' && $e eq 'Additional pre-authentication required') { next unless($Detail > 9||$type ne 'AS_REQ'); $response=$e; $e=''; } $KerbList{$response}{$type}{$from}{$service}{$client}{$e}++; } elsif ($ThisLine =~ /(Rootkit Hunter|rkhunter)(\[\d+\])?:/ ) { if ($ThisLine =~ /Please inspect this machine/) { $RootkitHunter{'inspect'}++; } elsif ($ThisLine =~ /check started/) { $RootkitHunter{'runs'}++; } elsif (my ($mins, $secs) = ($ThisLine =~ /Scanning took ([0-9]*) minutes? and ([0-9]*) seconds?/)) { $RootkitHunter{'time'}+= $mins*60 + $secs; } } elsif ($ThisLine =~ /systemd-logind(?:\[\d+\])?: New session \d+ of user (.*)\.$/){ $UserLogin{$1}++; } elsif ($ThisLine =~ /sshguard\[\d+\]: Blocking (.*) for (.*)/) { my ($attacker, $details) = ($1, $2); $sshguardAttackers{$attacker} = $details; } else { # Unmatched entries... $ThisLine =~ s/\[\d+\]:/:/; $OtherList{$ThisLine}++; } } ####################################### if ($NewUsers) { print "New Users:\n$NewUsers\n"; } if ($DeletedUsers) { print "Deleted Users:\n$DeletedUsers\n"; } if (keys %FailedAddUsers) { print "Failed adding users:\n"; foreach my $User (keys %FailedAddUsers) { print " $User: ". $FailedAddUsers{$User}. " Time(s)\n"; } print"\n"; } if ($NewGroups) { print "New Groups:\n$NewGroups\n"; } if ($DeletedGroups) { print "Deleted Groups:\n$DeletedGroups\n"; } if (keys %GroupRenamed) { print "Renamed groups:\n"; foreach my $Group (sort {$a cmp $b} keys %GroupRenamed) { print " $Group\n"; } } if (keys %GroupChanged) { print "Changed groups:\n"; foreach my $Group (sort {$a cmp $b} keys %GroupChanged) { print " $Group\n"; } } if (keys %AddToGroup) { print "\nAdded User to group:\n"; foreach my $Group (sort {$a cmp $b} keys %AddToGroup) { print " $Group:\n"; foreach my $User (sort {$a cmp $b} keys %{$AddToGroup{$Group}}) { print " $User\n"; } } } if ($SetGroupMembers) { print "Set Members of Group:\n$SetGroupMembers\n"; } if (@RemoveFromGroup) { print "\nRemoved From Group:\n".join('',@RemoveFromGroup)."\n"; } if (keys %HomeChange) { print "\nChanged users home directory:\n"; foreach my $User (sort {$a cmp $b} keys %HomeChange) { print " $User:\n"; # No sorting here - show it by time... foreach my $Home (keys %{$HomeChange{$User}}) { print " $Home\n"; } } } if (keys %ShellChange) { print "\nChanged shell:\n"; foreach my $User (sort {$a cmp $b} keys %ShellChange) { # No sorting here - show it by time... foreach my $Shell (keys %{$ShellChange{$User}}) { print " $User: $Shell\n"; } } } if (keys %UidChange) { print "\nChanged users UID:\n"; foreach my $Entry (sort {$a cmp $b} keys %UidChange) { print " $Entry\n"; } } if (keys %GidChange) { print "\nChanged users GID:\n"; foreach my $Entry (sort {$a cmp $b} keys %GidChange) { print " $Entry\n"; } } if (keys %PwdChange) { print "\nChanged users password:\n"; foreach my $Entry (keys %PwdChange) { print " $Entry changed password: $PwdChange{$Entry} Time(s)\n"; } } if (keys %UnknownUser) { print "\nUnknown users:\n"; foreach my $User (sort {$a cmp $b} keys %UnknownUser) { print " $User : $UnknownUser{$User} Time(s)\n"; } } if ($pwd_file_unknown > 0) { print "\nUsers unknown in password database (pwd_file): $pwd_file_unknown\n"; } if ($pwd_file_too_short > 0) { print "\nPassword too short or NULL (pwd_file): $pwd_file_too_short Time(s)\n"; } if (keys %{$Connections}) { print "\nConnections:\n"; foreach my $ThisOne (keys %{$Connections}) { if ($Summarize =~ /\Q$ThisOne\E/) { print " Service " . $ThisOne . ": " . $Connections->{$ThisOne} . " Connection(s)\n"; } else { my $service_check = 0; if ($ENV{"secure_$ThisOne"}) { $service_check = $ENV{"secure_$ThisOne"}; print " Service " . $ThisOne . " [Connection(s) more than $service_check per day]:\n"; } else { print " Service " . $ThisOne . " [Connection(s) per day]:\n"; } my $Total_Con = 0; foreach my $OtherOne (sort SortIP keys %{$Connections->{$ThisOne}}) { $Total_Con = $Total_Con + $Connections->{$ThisOne}->{$OtherOne}; if ( $Connections->{$ThisOne}->{$OtherOne} >= $service_check) { print " " . $OtherOne . ": " . $Connections->{$ThisOne}->{$OtherOne} . " Time(s)\n"; } } print " Total Connections: $Total_Con\n"; } } } if (keys %{$Refused}) { print "\nRefused Connections:\n"; foreach my $ThisOne (sort {$a cmp $b} keys %{$Refused}) { print " Service " . $ThisOne . ":\n"; foreach my $OtherOne (sort SortIP keys %{$Refused->{$ThisOne}}) { print " " . $OtherOne . ": " . $Refused->{$ThisOne}->{$OtherOne} . " Time(s)\n"; } } } if (keys %{$FailedLogins}) { print "\nFailed logins:\n"; foreach my $ThisOne (sort {$a cmp $b} keys %{$FailedLogins}) { print " User " . $ThisOne . ":\n"; foreach my $OtherOne (sort {$a cmp $b} keys %{$FailedLogins->{$ThisOne}}) { print " " . $OtherOne . ": " . $FailedLogins->{$ThisOne}->{$OtherOne} . " Time(s)\n"; } } } if (keys %{$FailedSaver}) { print "\nFailed screensaver disable:\n"; foreach my $User (sort {$a cmp $b} keys %{$FailedSaver}) { print " User $User on displays:\n"; foreach my $Display (sort {$a cmp $b} keys %{$FailedSaver->{$User}}) { print " $Display : " . $FailedSaver->{$User}->{$Display} . " Time(s)\n"; } } } if (keys %DeniedAccess) { print "\ndovecot-auth: Denied access\n"; foreach (keys %DeniedAccess) { ($User,$Reason) = split ","; print " for user " . $User . " (reason: " . $Reason . ") :" . $DeniedAccess{"$User,$Reason"} . " Time(s)\n"; } } if (keys %NoIP) { print "\nCouldn't get client IPs for connections to:\n"; foreach my $ThisOne (sort {$a cmp $b} keys %NoIP) { print " $ThisOne: $NoIP{$ThisOne} Time(s)\n"; } } if (keys %NameVerifyFail) { print "\nHostname verification failed:\n"; foreach my $Service (sort {$a cmp $b} keys %NameVerifyFail) { print " Service $Service:\n"; foreach my $Namev (sort {$a cmp $b} keys %{$NameVerifyFail{$Service}}) { print " $Namev: $NameVerifyFail{$Service}{$Namev} Time(s)\n"; } } } if (keys %Error) { print "\nErrors:\n"; foreach my $Service (sort {$a cmp $b} keys %Error) { print " Service $Service:\n"; foreach my $Err (sort {$a cmp $b} keys %{$Error{$Service}}) { print " $Err: $Error{$Service}{$Err} Time(s)\n"; } } } if ($RootLoginTTY) { print "\nRoot logins on ttys: $RootLoginTTY Time(s).\n"; } if ($RootLoginXVC) { print "\nRoot logins on xvcs: $RootLoginXVC Time(s).\n"; } if (keys %UserLogin) { print "\nUser Logins:\n"; foreach my $User (sort {$a cmp $b} keys %UserLogin) { print " $User : $UserLogin{$User} Time(s)\n"; } } if (keys %Su_User) { print "\nUsers performing Su Changes:\n"; foreach my $User (sort {$a cmp $b} keys %Su_User) { print " $User:\n"; foreach my $Su ( keys %{$Su_User{$User}}) { my $val = $Su_User{$User}{$Su}; print " $Su $val time(s)\n"; } } } if ($ConsoleLock > 0) { print "\nConsole file lock already in place: $ConsoleLock Time(s).\n"; } if (keys %AccountExpiry) { print "\nChanged account expiry for users:\n"; foreach my $User (sort {$a cmp $b} keys %AccountExpiry) { print " $User : $AccountExpiry{$User} Time(s)\n"; } } if (keys %PasswordExpiry) { print "\nChanged password expiry for users:\n"; foreach my $User (sort {$a cmp $b} keys %PasswordExpiry) { print " $User : $PasswordExpiry{$User} Time(s)\n"; } } if (keys %UserInfChange) { print "\nChanged user information:\n"; foreach my $User (sort {$a cmp $b} keys %UserInfChange) { print " $User : $UserInfChange{$User} Time(s)\n"; } } if (keys %XauthMessage) { print "\nReported by call_xauth:\n"; foreach my $Message (sort {$a cmp $b} keys %XauthMessage) { print " $Message : $XauthMessage{$Message} Time(s)\n"; } } if (keys %PopLogin) { print "\nspop3d user connections:\n"; foreach my $PopUser (sort {$a cmp $b} keys %PopLogin) { print " $PopUser\:\t$PopLogin{$PopUser} Time(s)\n"; } } if (keys %PopErrors) { print "\nspop3d connection failures:\n"; foreach my $PopErr (sort {$a cmp $b} keys %PopErrors) { print " $PopErr\:\t$PopErrors{$PopErr} Time(s)\n"; } } if ($spop3d_opened > 0) { print "\nspop3d connections(sum):\t".$spop3d_opened."\n"; } if ($spop3d_errors > 0) { print "spop3d connection errors:\t".$spop3d_errors."\n"; } if (keys %ChkPasswdPam) { print "\ncheckpassword-pam (SUID root PAM client):\n"; foreach my $PID (sort {$a cmp $b} keys %ChkPasswdPam) { my $ServiceUsernamePair = $ChkPasswdPam{$PID}{'Username'}.' => '.$ChkPasswdPam{$PID}{'Service'}; if ($ChkPasswdPam{$PID}{'Success'} eq 'true') { $Successes{$ServiceUsernamePair}++; } else { $Failures{$ServiceUsernamePair}++; } } foreach my $ServiceUsernamePair (sort {$a cmp $b} keys %Successes) { my $S = $Successes{$ServiceUsernamePair} ? $Successes{$ServiceUsernamePair} : 0; my $F = $Failures{$ServiceUsernamePair} ? $Failures{$ServiceUsernamePair} : 0; print " $ServiceUsernamePair : $S success(es), $F failure(s)\n"; } } if (keys %TallyOverflow) { print "\nTally overflowed for user:\n"; foreach my $User (sort {$a cmp $b} keys %TallyOverflow) { print " $User : $TallyOverflow{$User} Time(s)\n"; } } if (keys %Executed_app) { print "\nUserhelper executed applications:\n"; foreach (keys %Executed_app) { my ($longapp,$asuser,$user) = split ","; my $longapp_orig = $longapp; my $i = index($longapp, " "); if ($i > 0) { $longapp = substr($longapp, 0, $i); } my $app = substr($longapp,rindex($longapp,"/")+1); print " $user -> $app as $asuser: ".$Executed_app{"$longapp_orig,$asuser,$user"}." Time(s)\n"; } } if (keys %ChangedUserName) { my $ChangedUserName; #I think this bug -mgt print "\nChanged users names:\n"; foreach (keys %ChangedUserName) { ($Name1,$Name2) = split ","; print " User " . $Name1 . " change name to " . $Name2 . $ChangedUserName . "\n"; } } if (keys %ChangedUID) { print "\nChanged UID:\n"; foreach (keys %ChangedUID) { ($Name,$UID1,$UID2) = split ","; print " User " . $Name . " changed UID from " . $UID1 . " to " . $UID2 . "\n"; } } if (keys %ChangedShell) { print "\nChanged users default login shell: \n"; foreach (keys %ChangedShell) { ($User,$From,$To) = split ","; if ($From ne '') { print " User " . $User . " change shell from " . $From . " to " . $To . ": " . $ChangedShell{"$User,$From,$To"} . " Time(s)\n"; } else { print " User " . $User . " change shell to " . $To . ": " . $ChangedShell{"$User,$From,$To"} . " Time(s)\n"; } } } if (keys %ChangedGID) { print "\nChanged GID:\n"; foreach (keys %ChangedGID) { ($Name,$GID) = split ","; print " Group " . $Name . " change GID to " . $GID . "\n"; } } if (keys %cvs_passwd_mismatch) { print "\ncvs:"; print "\n Authentication Failures:\n"; foreach my $User (keys %cvs_passwd_mismatch) { print " $User : $cvs_passwd_mismatch{$User} Time(s)\n"; } } if (keys %DeprecateModule){ print "\nDeprecated pam module:\n"; foreach (keys %DeprecateModule) { ($Module,$Service) = split ","; print " deprecated module $Module called from service $Service: " . $DeprecateModule{"$Module,$Service"} . " Time(s)\n"; } } if ($RequestKeyFailures) { print "\nRequest Key Failures (nfs-utils/kernel mismatch): $RequestKeyFailures Time(s)\n"; } if (keys %KerbList) { print "\nKerberos Entries:\n"; foreach my $response (sort {$a cmp $b} keys %KerbList) { print " $response:\n"; foreach my $type (sort {$a cmp $b} keys %{$KerbList{$response}}) { print " $type:\n"; foreach my $from (sort {$a cmp $b} keys %{$KerbList{$response}{$type}}) { print " $from:\n"; foreach my $service (sort {$a cmp $b} keys %{$KerbList{$response}{$type}{$from}}) { print " $service:\n"; foreach my $client (sort {$a cmp $b} keys %{$KerbList{$response}{$type}{$from}{$service}}) { if(scalar(keys %{$KerbList{$response}{$type}{$from}{$service}{$client}})==1&&defined($KerbList{$response}{$type}{$from}{$service}{$client}{''})){ print " $client: $KerbList{$response}{$type}{$from}{$service}{$client}{''} Time(s)\n"; }else{ print " $client:\n"; foreach my $e (sort {$a cmp $b} keys %{$KerbList{$response}{$type}{$from}{$service}{$client}}) { print " $e: $KerbList{$response}{$type}{$from}{$service}{$client}{$e} Time(s)\n"; } } } } } } } } if (keys %RootkitHunter) { use integer; my ($mins, $secs) = ($RootkitHunter{'time'} / 60, $RootkitHunter{'time'} % 60); $RootkitHunter{'inspect'} = 0 unless $RootkitHunter{'inspect'}; print "\nRootkitHunter:\n"; print " Runs: $RootkitHunter{'runs'}\n"; print " Suggested Inspection: $RootkitHunter{'inspect'} Time(s)\n"; print " Total Runtime: $mins minute(s) $secs second(s)\n"; } if (keys %sshguardAttackers) { print "\nSSHGuard blocked:\n"; foreach my $attacker (sort {$a cmp $b} keys %sshguardAttackers) { my $details = $sshguardAttackers{$attacker}; print " $attacker: $details\n"; } } if (keys %OtherList) { print "\n**Unmatched Entries**\n"; foreach my $line (sort {$a cmp $b} keys %OtherList) { print " $line: $OtherList{$line} Time(s)\n"; } } if (keys %MissingLib) { print "\n Missing libraries:\n"; foreach my $Lib (keys %MissingLib) { print " $Lib : $MissingLib{$Lib} Time(s)\n"; } } exit(0); # vi: shiftwidth=3 tabstop=3 syntax=perl et # Local Variables: # mode: perl # perl-indent-level: 3 # indent-tabs-mode: nil # End: logwatch-7.12/scripts/services/emerge0000664000211400021140000001177614274101036020160 0ustar logwatchlogwatch ######################################################## # Please file all bug reports, patches, and feature # requests under: # https://sourceforge.net/p/logwatch/_list/tickets # and copy: # Laurent DUFOUR # Help requests and discusion can be filed under: # https://sourceforge.net/p/logwatch/discussion/ ######################################################## ######################################################## # This was written and is maintained by: # Laurent DUFOUR , # based on the work of # Kirk Bauer # # Please send all comments, suggestions, bug reports, # etc, to laurent.dufour@havas.com ######################################################## ######################################################## ## Copyright (c) 2008 Laurent DUFOUR ## Covered under the included MIT/X-Consortium License: ## http://www.opensource.org/licenses/mit-license.php ## All modifications and contributions by other persons to ## this script are assumed to have been donated to the ## Logwatch project and thus assume the above copyright ## and licensing terms. If you want to make contributions ## under your own copyright or a different license this ## must be explicitly stated in the contribution an the ## Logwatch project reserves the right to not accept such ## contributions. If you have made significant ## contributions to this script and want to claim ## copyright please contact logwatch-devel@lists.sourceforge.net. ######################################################### use strict; my $Debug = $ENV{'LOGWATCH_DEBUG'} || 0; #Init Counters my $DebugCounter = 0; my $EmergeStarted = 0; my $NumberOfPackageInstalled = 0; my $NumberOfPackageUnmerged = 0; #Init Arrays my @OtherList = (); #Init Hashes my ( %EmergeSyncCompleted, %ExitUnsuccessful, %PackageDepInstalled, %PackageInstalled, %PackageUnmerged, %PackageUpdated ); if ( $Debug >= 5 ) { print STDERR "\n\nDEBUG: Inside EMERGE Filter \n\n"; $DebugCounter = 1; } while (defined(my $ThisLine = )) { if ( $Debug >= 5 ) { print STDERR "DEBUG($DebugCounter): $ThisLine"; $DebugCounter++; } $ThisLine =~ s/^[^ ]* [^ ]* //; if ( ($ThisLine =~ /Finished. Cleaning up/) or ($ThisLine =~ /exiting successfully/) or ($ThisLine =~ /terminating/) or ($ThisLine =~ /Compiling/) or ($ThisLine =~ /=== sync/) or ($ThisLine =~ /Starting rsync with/i) or ($ThisLine =~ /Merging/) or ($ThisLine =~ /Unmerging./) or ($ThisLine =~ /Resuming merge/) or ($ThisLine =~ /AUTOCLEAN/) or ($ThisLine =~ />>> emerge /) or ($ThisLine =~ />>> depclean/) or ($ThisLine =~ /\*\*\* emerge /) or ($ThisLine =~ /Cleaning/) or ($ThisLine =~ /Updating world file/) or ($ThisLine =~ /Post-Build/) or ($ThisLine =~ /Starting retry \d+ of \d+ with/) ) { # Don't care about these... } elsif ( $ThisLine =~ s/emerge on: ([^ ]+) $2/$1 / ) { $EmergeStarted++; } elsif ( $ThisLine =~ s/Sync completed ([^ ]+) $2/$1 / ) { $EmergeSyncCompleted{$ThisLine}++; } elsif ( $ThisLine =~ s/completed emerge ([^ ]+) $2/$1 to / ) { $PackageInstalled{$ThisLine}++; $NumberOfPackageInstalled++; } elsif ( $ThisLine =~ s/unmerge success: $2/$1 to / ) { $PackageUnmerged{$ThisLine}++; $NumberOfPackageUnmerged++; } elsif ( $ThisLine =~ s/^Dep Installed: ([^ ]+)/$1 / ) { $PackageDepInstalled{$ThisLine}++; } elsif ( $ThisLine =~ /exiting unsuccessfully with status \'(\d)\'/ ) { $ExitUnsuccessful{$1}++; } else { # Report any unmatched entries... push @OtherList,$ThisLine; } } if ($EmergeStarted > 0) { print "\nEmerge Started: $EmergeStarted times\n"; } if (keys %EmergeSyncCompleted) { print "\nEmerge Sync Completed:\n"; foreach my $ThisOne (keys %EmergeSyncCompleted) { print " " . $ThisOne; } } if (keys %PackageUnmerged) { print "\nPackage Unmerged: $NumberOfPackageUnmerged times\n"; foreach my $ThisOne (keys %PackageUnmerged) { print " " . $ThisOne; } } if (keys %PackageInstalled) { print "\nPackage Installed: $NumberOfPackageInstalled times\n"; foreach my $ThisOne (keys %PackageInstalled) { print " " . $ThisOne; } } if (keys %PackageDepInstalled) { print "\nPackage Dependency Installed:\n"; foreach my $ThisOne (keys %PackageDepInstalled) { print " " . $ThisOne; } } if (keys %PackageUpdated) { print "\nPackage Updated:\n"; foreach my $ThisOne (keys %PackageUpdated) { print " ". $ThisOne; } } if (keys %ExitUnsuccessful) { print "\nUnsuccessfull exit with:\n"; foreach my $ThisOne (keys %ExitUnsuccessful) { print " Status $ThisOne : $ExitUnsuccessful{$ThisOne} Time(s)\n"; } } if ($#OtherList >= 0) { print "\n**Unmatched Entries**\n"; print @OtherList; } exit(0); # vi: shiftwidth=3 tabstop=3 syntax=perl et # Local Variables: # mode: perl # perl-indent-level: 3 # indent-tabs-mode: nil # End: logwatch-7.12/scripts/services/kernel0000664000211400021140000002656414533417014020201 0ustar logwatchlogwatch ######################################################## # Please file all bug reports, patches, and feature # requests under: # https://sourceforge.net/p/logwatch/_list/tickets # Help requests and discusion can be filed under: # https://sourceforge.net/p/logwatch/discussion/ ######################################################## ##################################################### ## Copyright (c) 2008 Kirk Bauer ## Covered under the included MIT/X-Consortium License: ## http://www.opensource.org/licenses/mit-license.php ## All modifications and contributions by other persons to ## this script are assumed to have been donated to the ## Logwatch project and thus assume the above copyright ## and licensing terms. If you want to make contributions ## under your own copyright or a different license this ## must be explicitly stated in the contribution an the ## Logwatch project reserves the right to not accept such ## contributions. If you have made significant ## contributions to this script and want to claim ## copyright please contact logwatch-devel@lists.sourceforge.net. ######################################################### use strict; use Logwatch ':ip'; my $Detail = $ENV{'LOGWATCH_DETAIL_LEVEL'} || 0; my $Ignore_cpu_throttled = $ENV{'ignore_cpu_throttled'} || 0; my $Ignore_faults = $ENV{'ignore_faults'}; my $Ignore_rpcsec_expired = $ENV{'ignore_rpcsec_expired'} || 0; my $Ignore_messages = $ENV{'kernel_ignore_messages'} || '^$'; my $CPUThrottled = 0; my %SYNflood = (); my %RAIDErrors = (); my %DRBDErrors = (); my %SegFaults = (); my %GPFaults = (); my %TrapInt3s = (); my %UnalignedErrors = (); my %FPAssists = (); my %OOM = (); my %Errors = (); my %Kernel = (); my %EDACs = (); my %NFS = (); my %EXT4Volume = (); my %EXT4 = (); #Init String Containers my ( $Volume, $errormsg, $from, $host, $on ); while (defined(my $ThisLine = )) { chomp($ThisLine); next if ($ThisLine eq ''); # Remove timestamp if present $ThisLine =~ s/^\[\s*\d+\.\d+\]\s*//; if ( # filter out audit messages - these should be parsed by the audit # service ($ThisLine =~ /(type=\d+\s+)?audit\(/) # following now in iptables service or ($ThisLine =~ /^Packet log: .*PROTO=/) or ($ThisLine =~ /IN=.*OUT=.*SRC=.*DST=.*PROTO=/) or ($ThisLine =~ /RAS: Correctable Errors collector initialized/) # user specified ignore messages, lower cased or ($ThisLine =~ /$Ignore_messages/i) ) { # ignore the above strings } elsif ( ($from,$on) = ( $ThisLine =~ /^Warning: possible SYN flood from ([^ ]+) on ([^ ]+):.+ Sending cookies/ ) ) { my $Fullfrom = LookupIP($from); my $Fullon = LookupIP($on); $SYNflood{$Fullon}{$Fullfrom}++; } elsif ($ThisLine =~ /temperature above threshold, cpu clock throttled/) { $CPUThrottled++ if not $Ignore_cpu_throttled; } elsif ($ThisLine =~ /continuing in degraded mode/) { $RAIDErrors{$ThisLine}++; } elsif ($ThisLine =~ /([^(]*)\[\d+\]: segfault at/) { $SegFaults{$1}++; } elsif ($ThisLine =~ /([^(]*)\[\d+\] general protection/) { $GPFaults{$1}++; } elsif ($ThisLine =~ /([^(]*)\[\d+\] trap int3 /) { $TrapInt3s{$1}++; } elsif ($ThisLine =~ /([^(]*)\(\d+\): unaligned access to/) { $UnalignedErrors{$1}++; } elsif ($ThisLine =~ /([^(]*)\(\d+\): floating-point assist fault at ip/) { $FPAssists{$1}++; } elsif ($ThisLine =~ /(?:[Kk]illed|[Kk]ill) process \d+ \((.*)\)/) { $OOM{$1}++; } elsif ($ThisLine =~ /(EDAC (?:igen6 )?(?:MC|PCI)\d:.*)/) { # Standard boot messages next if $ThisLine =~ /(?:Giving out device to |HANDLING IBECC MEMEORY )/; $EDACs{$1}++; } elsif ($ThisLine =~ /(block drbd\d+): Online verify found (\d+) \d+k block out of sync/) { $DRBDErrors{$1}{"$2 block(s) out of sync"} = 1; } elsif ($ThisLine =~ /(block drbd\d+): \[.*\] sock_sendmsg time expired/) { $DRBDErrors{$1}{"sock_sendmsg time expired"}++; } elsif ($ThisLine =~ /(block drbd\d+): Began resync as (SyncSource|SyncTarget)/) { $DRBDErrors{$1}{"Began resync as $2"}++; } elsif ( $ThisLine =~ /raid.*CRIT/) { # kernel: megaraid_sas 0000:88:00.0: 781934 (727946738s/0x0004/CRIT) - Enclosure PD 08(c Port 0 - 3/p1) phy bad for slot 19 # de-dupe $ThisLine =~ s/: \d+ /: /; $ThisLine =~ s/\(\d+s\//(Xs\//; $Errors{$ThisLine}++; } elsif ( ( $errormsg ) = ( $ThisLine =~ /(.*?error.{0,17})/i ) ) { # filter out smb open/read errors cased by insufficient permissions my $SkipError = 0; $SkipError = 1 if $ThisLine =~ /smb_readpage_sync: .*open failed, error=-13/; $SkipError = 1 if $ThisLine =~ /smb_open: .* open failed, result=-13/; $SkipError = 1 if $ThisLine =~ /smb_open: .* open failed, error=-13/; # filter out error_exit in stack traces caused by OOM conditions $SkipError = 1 if $ThisLine =~ /\[<[\da-f]+>\] error_exit\+0x/; # These are informative, not errors $SkipError = 1 if $ThisLine =~ /ACPI _OSC request failed \(AE_ERROR\), returned control mask: 0x1d/; $SkipError = 1 if $ThisLine =~ /ERST: Error Record Serialization Table \(ERST\) support is initialized/; $SkipError = 1 if $ThisLine =~ /GHES: Generic hardware error source: \d+ notified via .* is not supported/; $SkipError = 1 if $ThisLine =~ /HEST: Enabling Firmware First mode for corrected errors/; $SkipError = 1 if $ThisLine =~ /PCIe errors handled by (?:BIOS|OS)/; # These happen when kerberos tickets expire, which can be normal $SkipError = 1 if $ThisLine =~ /Error: state manager encountered RPCSEC_GSS session expired against NFSv4 server/ && $Ignore_rpcsec_expired; $SkipError = 1 if $ThisLine =~ /RAS: Correctable Errors collector initialized/; # filter out mount options $SkipError = 1 if $ThisLine =~ /errors=(?:continue|remount-ro|panic)/; $Errors{$errormsg}++ if ( (! $SkipError) || ($Detail > 8)); } elsif ( ( ($Volume, $errormsg) ) = ( $ThisLine =~ /^EXT4-fs \(([^)]+)\): (.*)/ ) ) { if ($errormsg =~ /INFO: recovery required on readonly filesystem/) { $EXT4Volume{$Volume} = 1; push @{$EXT4{$Volume}}, $errormsg; } elsif ($EXT4Volume{$Volume}) { push @{$EXT4{$Volume}}, $errormsg if $EXT4{$Volume}; delete $EXT4Volume{$Volume} if ($errormsg =~ /recovery complete/); } } elsif ( ( $errormsg ) = ( $ThisLine =~ /((BUG|WARNING|INFO):.{0,40})/ ) ) { $Errors{$errormsg}++; } elsif ( ( $host ) = ( $ThisLine =~ /^nfs: server (.*) not responding/ ) ) { $NFS{$host}++; # OTHER } else { # XXX For now, going to ignore all other kernel messages as there # XXX are practically an infinite number and most of them are obviously # XXX not parsed here at this time. # filter out smb open/read errors cased by insufficient permissions my $SkipError = 0; $SkipError = 1 if $ThisLine =~ /smb_readpage_sync: .*open failed, error=-13/; $SkipError = 1 if $ThisLine =~ /smb_open: .* open failed, result=-13/; $SkipError = 1 if $ThisLine =~ /smb_open: .* open failed, error=-13/; $SkipError = 1 if $ThisLine =~ /block drbd\d+: Out of sync: start=\d+/; $SkipError = 1 if $ThisLine =~ /block drbd\d+: updated( sync)? UUIDs?/i; $SkipError = 1 if $ThisLine =~ /block drbd\d+: Resync done/; $SkipError = 1 if $ThisLine =~ /block drbd\d+: cs:(?:Ahead|Behind) rs_left/; $SkipError = 1 if $ThisLine =~ /block drbd\d+: \d+ % had equal checksums, eliminated:/; $Kernel{$ThisLine}++ if ( (! $SkipError) || ($Detail > 8)) ; } } if (keys %SYNflood) { print "\nWarning: SYN flood on:\n"; foreach my $Thisone (sort {$a cmp $b} keys %SYNflood) { print " " . $Thisone . " from:\n"; foreach my $Next (sort {$a cmp $b} keys %{$SYNflood{$Thisone}}) { print " " . $Next . ": $SYNflood{$Thisone}{$Next} Time(s)\n"; } } } if (keys %RAIDErrors) { print "\nWARNING: RAID Errors Present\n"; foreach my $Thisone ( sort {$a cmp $b} keys %RAIDErrors ) { print " $Thisone ...: $RAIDErrors{$Thisone} Time(s)\n"; } } if (keys %DRBDErrors) { print "\nWARNING: DRBD Errors Present\n"; foreach my $Thisone ( sort {$a cmp $b} keys %DRBDErrors ) { foreach my $Msg (sort {$a cmp $b} keys %{$DRBDErrors{$Thisone}}) { print " $Thisone: $Msg"; print " : $DRBDErrors{$Thisone}{$Msg} Time(s)" if $DRBDErrors{$Thisone}{$Msg} > 1; print "\n"; } } } if (keys %SegFaults) { my $header_printed=0; foreach my $Thisone ( sort {$a cmp $b} keys %SegFaults ) { if ($Thisone =~ /^$Ignore_faults$/) { next; } if (!$header_printed) { print "\nWARNING: Segmentation Faults in these executables\n"; $header_printed=1; } print " $Thisone : $SegFaults{$Thisone} Time(s)\n"; } } if (keys %GPFaults) { my $header_printed=0; foreach my $Thisone ( sort {$a cmp $b} keys %GPFaults ) { if ($Thisone =~ /^$Ignore_faults$/) { next; } if (!$header_printed) { print "\nWARNING: General Protection Faults in these executables\n"; $header_printed=1; } print " $Thisone : $GPFaults{$Thisone} Time(s)\n"; } } if (keys %TrapInt3s) { my $header_printed=0; foreach my $Thisone ( sort {$a cmp $b} keys %TrapInt3s ) { if ($Ignore_faults =~ /\b\Q$Thisone\E\b/i) { next; } if (!$header_printed) { print "\nWARNING: Trap int3 in these executables\n"; $header_printed=1; } print " $Thisone : $TrapInt3s{$Thisone} Time(s)\n"; } } if (keys %UnalignedErrors) { print "\nWARNING: Unaligned Errors in these executables\n"; foreach my $Thisone ( sort {$a cmp $b} keys %UnalignedErrors ) { print " $Thisone : $UnalignedErrors{$Thisone} Time(s)\n"; } } if (keys %FPAssists) { print "\nWARNING: Floating-Point Assists in these executables\n"; foreach my $Thisone ( sort {$a cmp $b} keys %FPAssists ) { print " $Thisone : $FPAssists{$Thisone} Time(s)\n"; } } if (keys %OOM) { print "\nWARNING: Out of memory killer killed these executables\n"; foreach my $Thisone ( sort {$a cmp $b} keys %OOM ) { print " $Thisone : $OOM{$Thisone} Time(s)\n"; } } if (keys %Errors) { print "\nWARNING: Kernel Errors Present\n"; foreach my $Thisone ( sort {$a cmp $b} keys %Errors ) { print " $Thisone ...: $Errors{$Thisone} Time(s)\n"; } } if (keys %EDACs) { print "\nWARNING: Kernel EDAC Messages\n"; foreach my $Thisone ( sort {$a cmp $b} keys %EDACs ) { print " $Thisone ...: $EDACs{$Thisone} Time(s)\n"; } } if (keys %NFS) { print "\nWARNING: NFS Server Not Responding Messages\n"; foreach my $Thisone ( sort {$a cmp $b} keys %NFS ) { print " $Thisone ...: $NFS{$Thisone} Time(s)\n"; } } if (keys %EXT4) { print "\nWARNING: Ext4 Errors Present\n"; foreach my $Volume ( sort {$a cmp $b} keys %EXT4 ) { print " $Volume:\n"; foreach my $Msg (@{$EXT4{$Volume}}) { print " $Msg\n"; } } } if ($CPUThrottled) { print "\nWARNING: CPU Package temperature above threshold, cpu clock throttled $CPUThrottled Time(s)\n"; } # OTHER if ( ($Detail >= 5) and (keys %Kernel) ) { print "\n"; foreach my $Thisone (sort {$a cmp $b} keys %Kernel) { print $Kernel{$Thisone} . " Time(s): " . $Thisone . "\n"; } } exit(0); # vi: shiftwidth=3 tabstop=3 syntax=perl et # Local Variables: # mode: perl # perl-indent-level: 3 # indent-tabs-mode: nil # End: logwatch-7.12/scripts/services/qmail-send0000664000211400021140000004773114274101042020743 0ustar logwatchlogwatch ######################################################## # Please file all bug reports, patches, and feature # requests under: # https://sourceforge.net/p/logwatch/_list/tickets # Help requests and discusion can be filed under: # https://sourceforge.net/p/logwatch/discussion/ ######################################################## ####################################################### ## Copyright (c) 2008 Bob Hutchinson ## Covered under the included MIT/X-Consortium License: ## http://www.opensource.org/licenses/mit-license.php ## All modifications and contributions by other persons to ## this script are assumed to have been donated to the ## Logwatch project and thus assume the above copyright ## and licensing terms. If you want to make contributions ## under your own copyright or a different license this ## must be explicitly stated in the contribution an the ## Logwatch project reserves the right to not accept such ## contributions. If you have made significant ## contributions to this script and want to claim ## copyright please contact logwatch-devel@lists.sourceforge.net. ######################################################### use strict; my $Detail = $ENV{'LOGWATCH_DETAIL_LEVEL'}; my $QmailDetail = $ENV{'qmail_high_detail'}; my $QmailThreshold = $ENV{'threshold'}; my $RemoteThreshold = $ENV{'remote_threshold'}; my $LocalThreshold = $ENV{'local_threshold'}; my $FromThreshold = $ENV{'from_threshold'}; #Init String Container my ( $DeliveryResponse, $EmailFrom, $IgnoreUnmatched, $Response, $ResponseCode, $ServerResponseOverallTotal, $ServerResponses, $ToLocal, $ToRemote, $ct, $msgid, $percentage, $threshold_reached, $triplebounce, $warning, ); #Init Hashes my ( %From, %Local, %Remote, %ServerResponseTotal, %TripleBounce, %Warning, ); #Init Arrays my @OtherList = (); #Init Info Hashes my %SmtpCode; my %ErrorCode; $SmtpCode{'211'} = "System status, or system help reply."; $SmtpCode{'214'} = "Help message."; $SmtpCode{'220'} = "Domain service ready. Ready to start TLS."; $SmtpCode{'221'} = "Domain service closing transmission channel."; $SmtpCode{'250'} = "Requested mail action OK, completed."; $SmtpCode{'251'} = "User not local, will forward to forwardpath."; $SmtpCode{'252'} = "Cannot VRFY user, but will take message for this user and attempt delivery."; $SmtpCode{'253'} = "OK, messages pending messages for node node started."; $SmtpCode{'354'} = "Start mail input; end with .."; $SmtpCode{'355'} = "Octet-offset is the transaction offset."; $SmtpCode{'421'} = "Domain service not available, closing transmission channel."; $SmtpCode{'432'} = "A password transition is needed."; $SmtpCode{'450'} = "Requested mail action not taken: mailbox unavailable. ATRN request refused."; $SmtpCode{'451'} = "Requested action aborted: local error in processing. Unable to process ATRN request now"; $SmtpCode{'452'} = "Requested action not taken: insufficient system storage."; $SmtpCode{'453'} = "You have no mail."; $SmtpCode{'454'} = "TLS not available due to temporary reason. Encryption required for requested authentication mechanism."; $SmtpCode{'458'} = "Unable to queue messages for node node."; $SmtpCode{'459'} = "Node node not allowed: reason."; $SmtpCode{'500'} = "Command not recognized: command Syntax error."; $SmtpCode{'501'} = "Syntax error, no parameters allowed."; $SmtpCode{'502'} = "Command not implemented."; $SmtpCode{'503'} = "Bad sequence of commands."; $SmtpCode{'504'} = "Command parameter not implemented."; $SmtpCode{'511'} = "Bad destination mailbox address"; $SmtpCode{'521'} = "Machine does not accept mail."; $SmtpCode{'530'} = "Must issue a STARTTLS command first. Encryption required for requested authentication mechanism."; $SmtpCode{'534'} = "Authentication mechanism is too weak."; $SmtpCode{'538'} = "Encryption required for requested authentication mechanism."; $SmtpCode{'550'} = "Requested action not taken: mailbox unavailable."; $SmtpCode{'551'} = "User not local; please try forwardpath."; $SmtpCode{'552'} = "Requested mail action aborted: exceeded storage allocation."; $SmtpCode{'553'} = "Requested action not taken: mailbox name not allowed."; $SmtpCode{'554'} = "Transaction failed."; #ErrorCodes # Success ## X.0.X Other or Undefined Status $ErrorCode{'2.0.1'} = "Success: Undefined Status"; $ErrorCode{'2.0.2'} = "Success: Undefined Status"; $ErrorCode{'2.0.3'} = "Success: Undefined Status"; $ErrorCode{'2.0.4'} = "Success: Undefined Status"; $ErrorCode{'2.0.5'} = "Success: Undefined Status"; $ErrorCode{'2.0.6'} = "Success: Undefined Status"; $ErrorCode{'2.0.7'} = "Success: Undefined Status"; $ErrorCode{'2.0.8'} = "Success: Undefined Status"; ## X.1.X Addressing Status $ErrorCode{'2.1.1'} = "Success: Bad destination mailbox address"; $ErrorCode{'2.1.2'} = "Success: Bad destination system address"; $ErrorCode{'2.1.3'} = "Success: Bad destination mailbox address syntax"; $ErrorCode{'2.1.4'} = "Success: Destination mailbox address ambiguous"; $ErrorCode{'2.1.5'} = "Success: Destination mailbox address valid"; $ErrorCode{'2.1.6'} = "Success: Mailbox has moved"; $ErrorCode{'2.1.7'} = "Success: Bad sender's mailbox address syntax"; $ErrorCode{'2.1.8'} = "Success: Bad sender's system address"; ## X.2.X Mailbox Status $ErrorCode{'2.2.0'} = "Success: Other or undefined mailbox status"; $ErrorCode{'2.2.1'} = "Success: Mailbox disabled, not accepting messages"; $ErrorCode{'2.2.2'} = "Success: Mailbox full"; $ErrorCode{'2.2.3'} = "Success: Message length exceeds administrative limit"; $ErrorCode{'2.2.4'} = "Success: Mailing list expansion problem"; ## X.3.X Mail System Status $ErrorCode{'2.3.0'} = "Success: Other or undefined mail system status"; $ErrorCode{'2.3.1'} = "Success: Mail system full"; $ErrorCode{'2.3.2'} = "Success: System not accepting network messages"; $ErrorCode{'2.3.3'} = "Success: System not capable of selected features"; $ErrorCode{'2.3.4'} = "Success: Message too big for system"; ## X.4.X Network and Routing Status $ErrorCode{'2.4.0'} = "Success: Other or undefined network or routing status"; $ErrorCode{'2.4.1'} = "Success: No answer from host"; $ErrorCode{'2.4.2'} = "Success: Bad connection"; $ErrorCode{'2.4.3'} = "Success: Routing server failure"; $ErrorCode{'2.4.4'} = "Success: Unable to route"; $ErrorCode{'2.4.5'} = "Success: Network congestion"; $ErrorCode{'2.4.6'} = "Success: Routing loop detected"; $ErrorCode{'2.4.7'} = "Success: Delivery time expired"; ## X.5.X Mail Delivery Protocol Status $ErrorCode{'2.5.0'} = "Success: Other or undefined protocol status"; $ErrorCode{'2.5.1'} = "Success: Invalid command"; $ErrorCode{'2.5.2'} = "Success: Syntax error"; $ErrorCode{'2.5.3'} = "Success: Too many recipients"; $ErrorCode{'2.5.4'} = "Success: Invalid command arguments"; $ErrorCode{'2.5.5'} = "Success: Wrong protocol version"; ## X.6.X Message Content or Media Status $ErrorCode{'2.6.0'} = "Success: Other or undefined media error"; $ErrorCode{'2.6.1'} = "Success: Media not supported"; $ErrorCode{'2.6.2'} = "Success: Conversion required and prohibited"; $ErrorCode{'2.6.3'} = "Success: Conversion required but not supported"; $ErrorCode{'2.6.4'} = "Success: Conversion with loss performed"; $ErrorCode{'2.6.5'} = "Success: Conversion failed"; ## X.7.X Security or Policy Status $ErrorCode{'2.7.0'} = "Success: Other or undefined security status"; $ErrorCode{'2.7.1'} = "Success: Delivery not authorized, message refused"; $ErrorCode{'2.7.2'} = "Success: Mailing list expansion prohibited"; $ErrorCode{'2.7.3'} = "Success: Security conversion required but not possible"; $ErrorCode{'2.7.4'} = "Success: Security features not supported"; $ErrorCode{'2.7.5'} = "Success: Cryptographic failure"; $ErrorCode{'2.7.6'} = "Success: Cryptographic algorithm not supported"; $ErrorCode{'2.7.7'} = "Success: Message integrity failure"; # Persistent Transient Failure ## X.0.X Other or Undefined Status $ErrorCode{'4.0.1'} = "Deferral: Undefined Status"; $ErrorCode{'4.0.2'} = "Deferral: Undefined Status"; $ErrorCode{'4.0.3'} = "Deferral: Undefined Status"; $ErrorCode{'4.0.4'} = "Deferral: Undefined Status"; $ErrorCode{'4.0.5'} = "Deferral: Undefined Status"; $ErrorCode{'4.0.6'} = "Deferral: Undefined Status"; $ErrorCode{'4.0.7'} = "Deferral: Undefined Status"; $ErrorCode{'4.0.8'} = "Deferral: Undefined Status"; ## X.1.X Addressing Status $ErrorCode{'4.1.1'} = "Deferral: Bad destination mailbox address"; $ErrorCode{'4.1.2'} = "Deferral: Bad destination system address"; $ErrorCode{'4.1.3'} = "Deferral: Bad destination mailbox address syntax"; $ErrorCode{'4.1.4'} = "Deferral: Destination mailbox address ambiguous"; $ErrorCode{'4.1.5'} = "Deferral: Destination mailbox address valid"; $ErrorCode{'4.1.6'} = "Deferral: Mailbox has moved"; $ErrorCode{'4.1.7'} = "Deferral: Bad sender's mailbox address syntax"; $ErrorCode{'4.1.8'} = "Deferral: Bad sender's system address"; ## X.2.X Mailbox Status $ErrorCode{'4.2.0'} = "Deferral: Other or undefined mailbox status"; $ErrorCode{'4.2.1'} = "Deferral: Mailbox disabled, not accepting messages"; $ErrorCode{'4.2.2'} = "Deferral: Mailbox full"; $ErrorCode{'4.2.3'} = "Deferral: Message length exceeds administrative limit"; $ErrorCode{'4.2.4'} = "Deferral: Mailing list expansion problem"; ## X.3.X Mail System Status $ErrorCode{'4.3.0'} = "Deferral: Other or undefined mail system status"; $ErrorCode{'4.3.1'} = "Deferral: Mail system full"; $ErrorCode{'4.3.2'} = "Deferral: System not accepting network messages"; $ErrorCode{'4.3.3'} = "Deferral: System not capable of selected features"; $ErrorCode{'4.3.4'} = "Deferral: Message too big for system"; ## X.4.X Network and Routing Status $ErrorCode{'4.4.0'} = "Deferral: Other or undefined network or routing status"; $ErrorCode{'4.4.1'} = "Deferral: No answer from host"; $ErrorCode{'4.4.2'} = "Deferral: Bad connection"; $ErrorCode{'4.4.3'} = "Deferral: Routing server failure"; $ErrorCode{'4.4.4'} = "Deferral: Unable to route"; $ErrorCode{'4.4.5'} = "Deferral: Network congestion"; $ErrorCode{'4.4.6'} = "Deferral: Routing loop detected"; $ErrorCode{'4.4.7'} = "Deferral: Delivery time expired"; ## X.5.X Mail Delivery Protocol Status $ErrorCode{'4.5.0'} = "Deferral: Other or undefined protocol status"; $ErrorCode{'4.5.1'} = "Deferral: Invalid command"; $ErrorCode{'4.5.2'} = "Deferral: Syntax error"; $ErrorCode{'4.5.3'} = "Deferral: Too many recipients"; $ErrorCode{'4.5.4'} = "Deferral: Invalid command arguments"; $ErrorCode{'4.5.5'} = "Deferral: Wrong protocol version"; ## X.6.X Message Content or Media Status $ErrorCode{'4.6.0'} = "Deferral: Other or undefined media error"; $ErrorCode{'4.6.1'} = "Deferral: Media not supported"; $ErrorCode{'4.6.2'} = "Deferral: Conversion required and prohibited"; $ErrorCode{'4.6.3'} = "Deferral: Conversion required but not supported"; $ErrorCode{'4.6.4'} = "Deferral: Conversion with loss performed"; $ErrorCode{'4.6.5'} = "Deferral: Conversion failed"; ## X.7.X Security or Policy Status $ErrorCode{'4.7.0'} = "Deferral: Other or undefined security status"; $ErrorCode{'4.7.1'} = "Deferral: Delivery not authorized, message refused"; $ErrorCode{'4.7.2'} = "Deferral: Mailing list expansion prohibited"; $ErrorCode{'4.7.3'} = "Deferral: Security conversion required but not possible"; $ErrorCode{'4.7.4'} = "Deferral: Security features not supported"; $ErrorCode{'4.7.5'} = "Deferral: Cryptographic failure"; $ErrorCode{'4.7.6'} = "Deferral: Cryptographic algorithm not supported"; $ErrorCode{'4.7.7'} = "Deferral: Message integrity failure"; # Permanent Failure ## X.0.X Other or Undefined Status $ErrorCode{'5.0.1'} = "Failure: Undefined Status"; $ErrorCode{'5.0.2'} = "Failure: Undefined Status"; $ErrorCode{'5.0.3'} = "Failure: Undefined Status"; $ErrorCode{'5.0.4'} = "Failure: Undefined Status"; $ErrorCode{'5.0.5'} = "Failure: Undefined Status"; $ErrorCode{'5.0.6'} = "Failure: Undefined Status"; $ErrorCode{'5.0.7'} = "Failure: Undefined Status"; $ErrorCode{'5.0.8'} = "Failure: Undefined Status"; ## X.1.X Addressing Status $ErrorCode{'5.1.1'} = "Failure: Bad destination mailbox address"; $ErrorCode{'5.1.2'} = "Failure: Bad destination system address"; $ErrorCode{'5.1.3'} = "Failure: Bad destination mailbox address syntax"; $ErrorCode{'5.1.4'} = "Failure: Destination mailbox address ambiguous"; $ErrorCode{'5.1.5'} = "Failure: Destination mailbox address valid"; $ErrorCode{'5.1.6'} = "Failure: Mailbox has moved"; $ErrorCode{'5.1.7'} = "Failure: Bad sender's mailbox address syntax"; $ErrorCode{'5.1.8'} = "Failure: Bad sender's system address"; ## X.2.X Mailbox Status $ErrorCode{'5.2.0'} = "Failure: Other or undefined mailbox status"; $ErrorCode{'5.2.1'} = "Failure: Mailbox disabled, not accepting messages"; $ErrorCode{'5.2.2'} = "Failure: Mailbox full"; $ErrorCode{'5.2.3'} = "Failure: Message length exceeds administrative limit"; $ErrorCode{'5.2.4'} = "Failure: Mailing list expansion problem"; ## X.3.X Mail System Status $ErrorCode{'5.3.0'} = "Failure: Other or undefined mail system status"; $ErrorCode{'5.3.1'} = "Failure: Mail system full"; $ErrorCode{'5.3.2'} = "Failure: System not accepting network messages"; $ErrorCode{'5.3.3'} = "Failure: System not capable of selected features"; $ErrorCode{'5.3.4'} = "Failure: Message too big for system"; ## X.4.X Network and Routing Status $ErrorCode{'5.4.0'} = "Failure: Other or undefined network or routing status"; $ErrorCode{'5.4.1'} = "Failure: No answer from host"; $ErrorCode{'5.4.2'} = "Failure: Bad connection"; $ErrorCode{'5.4.3'} = "Failure: Routing server failure"; $ErrorCode{'5.4.4'} = "Failure: Unable to route"; $ErrorCode{'5.4.5'} = "Failure: Network congestion"; $ErrorCode{'5.4.6'} = "Failure: Routing loop detected"; $ErrorCode{'5.4.7'} = "Failure: Delivery time expired"; ## X.5.X Mail Delivery Protocol Status $ErrorCode{'5.5.0'} = "Failure: Other or undefined protocol status"; $ErrorCode{'5.5.1'} = "Failure: Invalid command"; $ErrorCode{'5.5.2'} = "Failure: Syntax error"; $ErrorCode{'5.5.3'} = "Failure: Too many recipients"; $ErrorCode{'5.5.4'} = "Failure: Invalid command arguments"; $ErrorCode{'5.5.5'} = "Failure: Wrong protocol version"; ## X.6.X Message Content or Media Status $ErrorCode{'5.6.0'} = "Failure: Other or undefined media error"; $ErrorCode{'5.6.1'} = "Failure: Media not supported"; $ErrorCode{'5.6.2'} = "Failure: Conversion required and prohibited"; $ErrorCode{'5.6.3'} = "Failure: Conversion required but not supported"; $ErrorCode{'5.6.4'} = "Failure: Conversion with loss performed"; $ErrorCode{'5.6.5'} = "Failure: Conversion failed"; ## X.7.X Security or Policy Status $ErrorCode{'5.7.0'} = "Failure: Other or undefined security status"; $ErrorCode{'5.7.1'} = "Failure: Delivery not authorized, message refused"; $ErrorCode{'5.7.2'} = "Failure: Mailing list expansion prohibited"; $ErrorCode{'5.7.3'} = "Failure: Security conversion required but not possible"; $ErrorCode{'5.7.4'} = "Failure: Security features not supported"; $ErrorCode{'5.7.5'} = "Failure: Cryptographic failure"; $ErrorCode{'5.7.6'} = "Failure: Cryptographic algorithm not supported"; $ErrorCode{'5.7.7'} = "Failure: Message integrity failure"; while (defined(my $ThisLine = )) { if ( ( $ThisLine =~ /new msg/ ) or ( $ThisLine =~ /status: / ) or ( $ThisLine =~ /bounce msg/ ) or ( $ThisLine =~ /end msg/ ) ) { # We don't care about these } # @4000000042203bb712373f04.s:@4000000042202ab23b98282c delivery 28: deferral: Sorry,_I_wasn't_able_to_establish_an_SMTP_connection._(#4.4.1)/ elsif ( ($msgid,$DeliveryResponse,$Response) = ( $ThisLine =~ /delivery (\d+)\: (.*?)\:(.*)/ ) ) { if ( $Response =~ /did_/ ) { # ignore these. } else { if ( ($ResponseCode) = ( $Response =~ /Remote_host_said\:_(\d{3})_/ ) ) { $ServerResponses->{$DeliveryResponse}->{$ResponseCode}++; } else { #if ( $DeliveryResponse =~ /failure/ ) if ( ( $ResponseCode) = ( $ThisLine =~ /failure:.*_vpopmail_\(#(\d\.\d\.\d)\)\// ) ) { #$ResponseCode=511; $ResponseCode =~ s/\.//g; $ServerResponses->{$DeliveryResponse}->{$ResponseCode}++; } #if ( $DeliveryResponse =~ /deferral/ ) if ( ( $ResponseCode) = ( $ThisLine =~ /deferral:.*_\(#(\d\.\d\.\d)\)\// ) ) { #$ResponseCode=443; $ServerResponses->{$DeliveryResponse}->{$ResponseCode}++; } } } } elsif ( ($EmailFrom) = ( $ThisLine =~ /from \<(.*)\>/ ) ) { $From{$EmailFrom}++; } elsif ( ($ToLocal) = ( $ThisLine =~ /to local (.*)/ ) ) { $Local{$ToLocal}++; } elsif ( ($ToRemote) = ( $ThisLine =~ /to remote (.*)/ ) ) { $Remote{$ToRemote}++; } elsif( ($warning) = ($ThisLine =~ /warning: (.*)/ ) ) { $Warning{$warning}++; } elsif ( ($triplebounce) = ($ThisLine =~ /triple bounce: discarding bounce\/(\d+)$/ ) ) { $TripleBounce{$triplebounce}++; } else { # Report any unmatched entries... push @OtherList,$ThisLine; } } if ($QmailDetail >= 1) { if ($QmailThreshold > 0) { if (($RemoteThreshold < 0) or ($RemoteThreshold eq '')) { $RemoteThreshold = $QmailThreshold; } if (($FromThreshold < 0) or ($FromThreshold eq '')) { $FromThreshold = $QmailThreshold; } if (($LocalThreshold < 0) or ($LocalThreshold eq '')) { $LocalThreshold = $QmailThreshold; } } if (($RemoteThreshold < 0) or ($RemoteThreshold eq '')) { $RemoteThreshold = 0; } if (($FromThreshold < 0) or ($FromThreshold eq '')) { $FromThreshold = 0; } if (($LocalThreshold < 0) or ($LocalThreshold eq '')) { $LocalThreshold = 0; } if ( (keys %From) ) { print "\nEmails from (Threshold of " . $FromThreshold . "):\n"; $threshold_reached=0; foreach my $Line (sort {$From{$b} <=> $From{$a}} keys %From) { if ($From{$Line} >= $FromThreshold) { $threshold_reached = 1; print "\t" . $Line . " - ". $From{$Line} . " Time(s)\n"; } } if ($threshold_reached < 1) { print "\t" . "None found above the threshold ($FromThreshold)\n"; } } if ( (keys %Remote) ) { print "\nEmails to Remote Server (Threshold of " . $RemoteThreshold . "):\n"; $threshold_reached=0; foreach my $Line (sort {$Remote{$b} <=> $Remote{$a}} keys %Remote) { if ($Remote{$Line} >= $RemoteThreshold) { $threshold_reached=1; print "\t" . $Line . " - ". $Remote{$Line} . " Time(s)\n"; } } if ($threshold_reached < 1) { print "\t" . "None found above the threshold ($RemoteThreshold)\n"; } } if ( (keys %Local) ) { print "\nEmails to Local Server (Threshold of " . $LocalThreshold . "):\n"; $threshold_reached=0; foreach my $Line (sort {$Local{$b} <=> $Local{$a}} keys %Local) { if ($Local{$Line} >= $LocalThreshold) { $threshold_reached=1; print "\t" . $Line . " - ". $Local{$Line} . " Time(s)\n"; } } if ($threshold_reached < 1) { print "\t" . "None found above the threshold ($LocalThreshold)\n"; } } } if (keys %{$ServerResponses}) { print "\nRemote Server Responses:\n"; foreach my $Line (sort {$a cmp $b} keys %{$ServerResponses}) { foreach $Detail (sort {$a cmp $b} keys %{$ServerResponses->{$Line}}) { $ServerResponseTotal{$Line} += $ServerResponses->{$Line}->{$Detail}; $ServerResponseOverallTotal += $ServerResponses->{$Line}->{$Detail}; print "\t".ucfirst($Line)."(" . $Detail . ") - ". $ServerResponses->{$Line}->{$Detail} . " Time(s)"; if ( $SmtpCode{$Detail} ) { print " - ".$SmtpCode{$Detail}; } elsif ( $ErrorCode{$Detail} ) { print " - ". $ErrorCode{$Detail}; } print "\n"; } } print "\n\tPercentage(s):\n"; foreach my $Details (sort {$a cmp $b} keys %ServerResponseTotal) { $percentage = (($ServerResponseTotal{$Details} / $ServerResponseOverallTotal) * 100); print "\t\t" . ucfirst($Details) . " - "; printf("%.2f",$percentage); print " %\n"; } } if ( (keys %Warning) ) { print "\nWarnings:\n"; foreach my $Line (sort {$Warning{$b} <=> $Warning{$a}} keys %Warning) { print "\t" . $Line . " - ". $Warning{$Line} . " Time(s)\n"; } } if ( (keys %TripleBounce) ) { $ct = 0; foreach(keys %TripleBounce) { $ct++; } print "\nTripleBounces:\t"; print "$ct times\n"; } if (($#OtherList >= 0) and (not $IgnoreUnmatched)) { print "\n**Unmatched Entries**\n"; print @OtherList; } exit(0); # vi: shiftwidth=3 tabstop=3 syntax=perl et # Local Variables: # mode: perl # perl-indent-level: 3 # indent-tabs-mode: nil # End: logwatch-7.12/scripts/services/ftpd-xferlog0000664000211400021140000001521514274101037021306 0ustar logwatchlogwatch ######################################################## # Please file all bug reports, patches, and feature # requests under: # https://sourceforge.net/p/logwatch/_list/tickets # Help requests and discusion can be filed under: # https://sourceforge.net/p/logwatch/discussion/ ######################################################## ######################################################## ## Copyright (c) 2008 Kirk Bauer ## Covered under the included MIT/X-Consortium License: ## http://www.opensource.org/licenses/mit-license.php ## All modifications and contributions by other persons to ## this script are assumed to have been donated to the ## Logwatch project and thus assume the above copyright ## and licensing terms. If you want to make contributions ## under your own copyright or a different license this ## must be explicitly stated in the contribution an the ## Logwatch project reserves the right to not accept such ## contributions. If you have made significant ## contributions to this script and want to claim ## copyright please contact logwatch-devel@lists.sourceforge.net. ######################################################### use strict; use File::Basename qw(dirname); #Init String Containers my ( $Temp, $TotalKBytesIn, $TotalKBytesOut, $TotalMBytesIn, $TotalMBytesOut ); #Init Arrays my ( @AnonIn, @AnonOut, @DeletedFiles, @GuestIn, @GuestOut, @OtherList, @UserIn, @UserOut ) = (); #Init Hashes my %FilesOut; sub remove_dups { my(@info)=sort @_; my(%count,@out,$i); foreach $i (@info) { $count{$i}++; } foreach $i (keys %count) { my($j)=$i; $j =~ s/\n//; if ($count{$i} > 1) { push @out, $j . " (".$count{$i}." Times)\n"; } else { push @out, "$j\n"; } } return @out; } my $Detail = $ENV{'LOGWATCH_DETAIL_LEVEL'} || 0; my $FTPDetail = $ENV{'detail_transfer'}; my $TotalBytesOut = 0; my $TotalBytesIn = 0; while (defined(my $ThisLine = )) { # Remove transfer time if it is there if ( my ($RemoteHost,$Size,$FileName,$Direction,$AccessMode,$UserName) = ( $ThisLine =~ /^([^ ]+) (\d+) (.*) . . (.) (.) (.*) ftps? . .*$/ ) ) { if ($Detail < 15) { $FileName = dirname($FileName); } if ( $AccessMode eq 'a' ) { # Anonymous transfers if ( $Direction eq 'o' ) { # File was outgoing $TotalBytesOut += $Size; if ($Detail >= 15) { $Temp = ' ' . $FileName . ' -> ' . $RemoteHost . ' (Email: ' . $UserName . ")\n"; } else { $Temp = ' ' . $FileName . ' -> ' . $RemoteHost . "\n"; } push @AnonOut, $Temp; $FilesOut{$FileName}++; } elsif ( $Direction eq 'd' ) { $Temp = ' ' . $FileName . ' Deleted ' . $RemoteHost . ' (Email: ' . $UserName . ")\n"; push @DeletedFiles, $Temp; } else { # File was incoming $TotalBytesIn += $Size; if ($Detail >= 15) { $Temp = ' ' . $RemoteHost . ' -> ' . $FileName . ' (User: ' . $UserName . ")\n"; } else { $Temp = ' ' . $RemoteHost . ' -> ' . $FileName . "\n"; } push @AnonIn, $Temp; } } elsif ( $AccessMode eq 'g' ) { # Guest transfers if ( $Direction eq 'o' ) { # File was outgoing $TotalBytesOut += $Size; $Temp = ' ' . $FileName . ' -> ' . $RemoteHost . ' (User: ' . $UserName . ")\n"; push @GuestOut, $Temp; } elsif ( $Direction eq 'd' ) { $Temp = ' ' . $FileName . ' Deleted ' . $RemoteHost . ' (User: ' . $UserName . ")\n"; push @DeletedFiles, $Temp; } else { # File was incoming $TotalBytesIn += $Size; $Temp = ' ' . $RemoteHost . ' -> ' . $FileName . ' (User: ' . $UserName . ")\n"; push @GuestIn, $Temp; } } elsif ( $AccessMode eq 'r' ) { # User transfers if ( $Direction eq 'o' ) { # File was outgoing $TotalBytesOut += $Size; $Temp = ' ' . $FileName . ' -> ' . $RemoteHost . ' (User: ' . $UserName . ")\n"; push @UserOut, $Temp; } elsif ( $Direction eq 'd' ) { $Temp = ' ' . $FileName . ' Deleted ' . $RemoteHost . ' (User: ' . $UserName . ")\n"; push @DeletedFiles, $Temp; } else { # File was incoming $TotalBytesIn += $Size; $Temp = ' ' . $RemoteHost . ' -> ' . $FileName . ' (User: ' . $UserName . ")\n"; push @UserIn, $Temp; } } } else { # Report any unmatched entries... push @OtherList, $ThisLine; } } @AnonOut=&remove_dups(@AnonOut); @AnonIn=&remove_dups(@AnonIn); @GuestOut=&remove_dups(@GuestOut); @GuestIn=&remove_dups(@GuestIn); @UserOut=&remove_dups(@UserOut); @UserIn=&remove_dups(@UserIn); @OtherList=&remove_dups(@OtherList); @DeletedFiles=&remove_dups(@DeletedFiles); $TotalKBytesOut = int $TotalBytesOut/1000; $TotalKBytesIn = int $TotalBytesIn/1000; $TotalMBytesOut = int $TotalKBytesOut/1000; $TotalMBytesIn = int $TotalKBytesIn/1000; ($TotalKBytesOut > 0) and print "TOTAL KB OUT: " . $TotalKBytesOut . "KB (" . $TotalMBytesOut . "MB)\n"; ($TotalKBytesIn > 0) and print "TOTAL KB IN: " . $TotalKBytesIn . "KB (" . $TotalMBytesIn . "MB)\n"; if (@AnonIn) { print "\nIncoming Anonymous FTP Transfers:\n"; print sort @AnonIn; } if ( (keys %FilesOut) and ($Detail >= 5) and ($Detail < 10) ) { print "\nOutgoing Anonymous FTP Transfers (By File):\n"; foreach (sort keys %FilesOut) { print " $_: $FilesOut{$_} Time(s)\n"; } } if ( (@GuestIn) and ($Detail >= 10) and ($FTPDetail > 0)) { print "\nIncoming Guest FTP Transfers:\n"; print sort @GuestIn; } if ( (@GuestOut) and ($Detail >= 10) and ($FTPDetail > 0)) { print "\nOutgoing Guest FTP Transfers:\n"; print sort @GuestOut; } if ( (@AnonOut) and ($Detail >= 10) ) { print "\nOutgoing Anonymous FTP Transfers:\n"; print sort @AnonOut; } if ( (@UserIn) and ($Detail >= 10) and ($FTPDetail > 0)) { print "\nIncoming User FTP Transfers:\n"; print sort @UserIn; } if ( (@UserOut) and ($Detail >= 10) and ($FTPDetail > 0)) { print "\nOutgoing User FTP Transfers:\n"; print sort @UserOut; } if ( (@DeletedFiles) and ($Detail >= 10) and ($FTPDetail > 0)) { print "\nDeleted Files:\n"; print sort @DeletedFiles; } if ($#OtherList >= 0) { print "\n**Unmatched Entries**\n"; print @OtherList; } exit(0); # vi: shiftwidth=3 tabstop=3 syntax=perl et # Local Variables: # mode: perl # perl-indent-level: 3 # indent-tabs-mode: nil # End: logwatch-7.12/scripts/services/raid0000664000211400021140000000412314274101043017615 0ustar logwatchlogwatch ######################################################## # Please file all bug reports, patches, and feature # requests under: # https://sourceforge.net/p/logwatch/_list/tickets # Help requests and discusion can be filed under: # https://sourceforge.net/p/logwatch/discussion/ ######################################################## ####################################################### # Copyright (c) 2008 Anders Blomdell # Covered under the included MIT/X-Consortium License: # http://www.opensource.org/licenses/mit-license.php # All modifications and contributions by other persons to # this script are assumed to have been donated to the # Logwatch project and thus assume the above copyright # and licensing terms. If you want to make contributions # under your own copyright or a different license this # must be explicitly stated in the contribution an the # Logwatch project reserves the right to not accept such # contributions. If you have made significant # contributions to this script and want to claim # copyright please contact logwatch-devel@lists.sourceforge.net. ######################################################## use strict; my ($print, $time); while (defined($_ = )) { chomp; $print = 0; if (/^(... .. ..:..:..)/) { $time = $1; } s/^... .. ..:..:.. [^ ]* [^ ]*\[\d*\]: //; s/^... .. ..:..:.. [^ ]* [^ ]*: //; if (/^raid/) { if (/failure/) { $print = 1; } if (/redirecting/) { $print = 1; } if (/rescheduling/) { $print = 1; } } elsif (/^md/) { if (/skipping faulty/) { $print = 1; } if (/degraded mode/) { $print = 1; } } elsif (/AppleRAID/){ if (/restarting/) { $print = 1; } if (/rebuild/) { $print = 1; } if (/error/) { $print = 1; } if (/offline/) { $print = 1; } if (/online/) { $print = 1; } if (/ignoring/) { $print = 1; } } else { next; } if ($print) { print("$time $_ \n"); } } # vi: shiftwidth=3 tabstop=3 syntax=perl et # Local Variables: # mode: perl # perl-indent-level: 3 # indent-tabs-mode: nil # End: logwatch-7.12/scripts/services/dpkg0000664000211400021140000000522714274101036017633 0ustar logwatchlogwatch ######################################################## # Please file all bug reports, patches, and feature # requests under: # https://sourceforge.net/p/logwatch/_list/tickets # Help requests and discusion can be filed under: # https://sourceforge.net/p/logwatch/discussion/ ######################################################## ######################################################## ## Copyright (c) 2008 Willi Mann ## Covered under the included MIT/X-Consortium License: ## http://www.opensource.org/licenses/mit-license.php ## All modifications and contributions by other persons to ## this script are assumed to have been donated to the ## Logwatch project and thus assume the above copyright ## and licensing terms. If you want to make contributions ## under your own copyright or a different license this ## must be explicitly stated in the contribution an the ## Logwatch project reserves the right to not accept such ## contributions. If you have made significant ## contributions to this script and want to claim ## copyright please contact logwatch-devel@lists.sourceforge.net. ######################################################### use strict; my @install; my @reinstall; my @upgrade; my @remove; my @purge; my @conffile; my @unknown; while(my $line=) { chomp $line; if ( my ( $do, $pkg, $ver1, $ver2) = ( $line =~ /^\S+ \S+ (install|upgrade|remove|purge) (\S+) (\S+)(?: (\S+))?/ )) { if(($do eq "remove" or $do eq "purge") and ($ver1 ne $ver2) and ($ver2 !~ /^<\w+>$/ )) { push @unknown, $line; } elsif ($do eq "remove") { push @remove, "$pkg $ver1"; } elsif ( $do eq "purge") { push @purge, "$pkg $ver1"; } elsif ($ver1 =~ /[<>]/) { push @install, "$pkg $ver2"; } elsif ($ver1 eq $ver2) { push @reinstall, "$pkg $ver1"; } else { push @upgrade, "$pkg $ver1 => $ver2"; } } elsif ( $line =~ /^\S+ \S+ conffile / ) { my ( $conffilename, $action ) = ( $line =~ /^\S+ \S+ conffile (\S+) (\S+)/ ); push @conffile, "$action $conffilename"; } elsif ( $line =~ /^\S+ \S+ (status|configure|startup|trigproc) / ) { #ignore } else { push @unknown, $line; } } my @k = ( "Installed" , \@install, "Reinstalled" , \@reinstall, "Upgraded" , \@upgrade, "Removed", \@remove, "Purged", \@purge, "Configuration files", \@conffile, "Unknown lines", \@unknown); while (@k > 0) { my $text = shift @k; my $array = shift @k; if(@$array) { print "\n$text:\n"; foreach my $line (sort @$array) { print " $line\n"; } } } # vi: shiftwidth=3 tabstop=3 syntax=perl et # Local Variables: # mode: perl # perl-indent-level: 3 # indent-tabs-mode: nil # End: logwatch-7.12/scripts/services/in.qpopper0000664000211400021140000001237614274101037021005 0ustar logwatchlogwatch ######################################################## # Please file all bug reports, patches, and feature # requests under: # https://sourceforge.net/p/logwatch/_list/tickets # and copy: # Kenneth Porter # Help requests and discusion can be filed under: # https://sourceforge.net/p/logwatch/discussion/ ######################################################## ######################################################## # This was written and is maintained by: # Kenneth Porter # # Please send all comments, suggestions, bug reports, # etc, to shiva@well.com. ######################################################## ##################################################### ## Copyright (c) 2008 Kenneth Porter ## Covered under the included MIT/X-Consortium License: ## http://www.opensource.org/licenses/mit-license.php ## All modifications and contributions by other persons to ## this script are assumed to have been donated to the ## Logwatch project and thus assume the above copyright ## and licensing terms. If you want to make contributions ## under your own copyright or a different license this ## must be explicitly stated in the contribution an the ## Logwatch project reserves the right to not accept such ## contributions. If you have made significant ## contributions to this script and want to claim ## copyright please contact logwatch-devel@lists.sourceforge.net. ######################################################### use strict; my $Detail = $ENV{'LOGWATCH_DETAIL_LEVEL'} || 0; #Init Hashes my ( %ApopConnections, %Connections, %FailedLogin, %OtherList, %Stats ); while (defined(my $ThisLine = )) { if ( ($ThisLine =~ /xsender/) or ( $ThisLine =~ /.drac.:/ ) or ( $ThisLine =~ /Timing/ ) or ( $ThisLine =~ /-ERR \[AUTH\]/ ) or ( $ThisLine =~ /canonical name of client/ ) or ( $ThisLine =~ /I\/O error flushing output to client/ ) or ( $ThisLine =~ /-ERR SIGHUP or SIGPIPE flagged/ ) or ( $ThisLine =~ /-ERR POP hangup/ ) or ( $ThisLine =~ /-ERR POP EOF or I\/O Error/ ) or ( $ThisLine =~ /-ERR \[IN-USE\] / ) or ( $ThisLine =~ /Incorrect octet count/ ) ) { # We don't care about these } ## Stats: 0 0 0 0 elsif (my ($UserID, $NumDeleted, $BytesDeleted, $NumLeft, $BytesLeft) = ( $ThisLine =~ /Stats: ([^ ]+) ([^ ]+) ([^ ]+) ([^ ]+) ([^ ]+)/ )) { $Stats{$UserID}{"Times"}++; $Stats{$UserID}{"NumDel"} += $NumDeleted; $Stats{$UserID}{"BytesDel"} += $BytesDeleted; $Stats{$UserID}{"NumLeft"} = $NumLeft; $Stats{$UserID}{"BytesLeft"} = $BytesLeft; } elsif ( ($UserID) = ($ThisLine =~ /^\[AUTH\] Failed attempted login to ([^ ]+) from host/ )) { $FailedLogin{$UserID}++; } elsif ( $ThisLine =~ s/^connect from ([^ ]+)$/$1/ ) { $Connections{$ThisLine}++; } elsif ( $ThisLine =~ s/^\(v[0-9.]+\) POP login by user "?[^ ]+"? at \([^ ]+\) ([^ ]+)$/$1/ ) { $Connections{$ThisLine}++; } elsif ( $ThisLine =~ s/^apop \"(.*)\".*/$1/ ) { $ApopConnections{$ThisLine}++; } else { # Report any unmatched entries... chomp($ThisLine); $OtherList{$ThisLine}++; } } if ( (keys %Connections) and ($Detail >= 10) ) { print "\nPlaintext Connections:\n"; foreach my $ThisOne (keys %Connections) { print " " . $Connections{$ThisOne} . " from " . $ThisOne; } } if ( (keys %ApopConnections) and ($Detail >= 10) ) { print "\nAPOP Connections:\n"; foreach my $ThisOne (keys %ApopConnections) { print " " . $ApopConnections{$ThisOne} . " from " . $ThisOne; } } if ((keys %Stats) and ($Detail >= 10)) { my ($Times, $NumDel, $BytesDel, $NumLeft, $BytesLeft); print "\nUser Statistics:\n"; print " | Deleted | Kept |\n"; print "User Name Times | Num KBytes | Num KBytes |\n"; foreach my $UserID (sort {$Stats{$b}{"BytesDel"}<=>$Stats{$a}{"BytesDel"}} keys %Stats) { printf("%-15s %5d | %5d %6d | %5d %6d |\n", $UserID, $Stats{$UserID}{"Times"}, $Stats{$UserID}{"NumDel"}, $Stats{$UserID}{"BytesDel"}/1024, $Stats{$UserID}{"NumLeft"}, $Stats{$UserID}{"BytesLeft"}/1024); $Times += $Stats{$UserID}{"Times"}; $NumDel += $Stats{$UserID}{"NumDel"}; $BytesDel += $Stats{$UserID}{"BytesDel"}; $NumLeft += $Stats{$UserID}{"NumLeft"}; $BytesLeft += $Stats{$UserID}{"BytesLeft"}; } print "------------------------+----------------+----------------+\n"; printf("TOTALS %5d | %5d %6d | %5d %6d |\n", $Times, $NumDel, $BytesDel/1024, $NumLeft, $BytesLeft/1024); } if (keys %FailedLogin) { print "\nFailed Logins:\n"; foreach my $UserID (sort {$FailedLogin{$b}<=>$FailedLogin{$a} } keys %FailedLogin) { print " $UserID: $FailedLogin{$UserID} time(s).\n"; }; # foreach }; # if if (keys %OtherList) { print "\n**Unmatched Entries**\n"; foreach my $line (sort {$OtherList{$b}<=>$OtherList{$a} } keys %OtherList) { print " $line: $OtherList{$line} Time(s)\n"; } } exit(0); # vi: shiftwidth=3 tabstop=3 syntax=perl et # Local Variables: # mode: perl # perl-indent-level: 3 # indent-tabs-mode: nil # End: logwatch-7.12/scripts/services/audit0000664000211400021140000003712414743365003020024 0ustar logwatchlogwatch ######################################################## # Please file all bug reports, patches, and feature # requests under: # https://sourceforge.net/p/logwatch/_list/tickets # and copy: # Ron Kuris # Help requests and discusion can be filed under: # https://sourceforge.net/p/logwatch/discussion/ ######################################################## ######################################################## # selinux audit log summaries # # This was written and is maintained by: # Ron Kuris # ######################################################## ######################################################## ## (c) 2006,2008 Ron Kuris ## Covered under the included MIT/X-Consortium License: ## http://www.opensource.org/licenses/mit-license.php ## All modifications and contributions by other persons to ## this script are assumed to have been donated to the ## Logwatch project and thus assume the above copyright ## and licensing terms. If you want to make contributions ## under your own copyright or a different license this ## must be explicitly stated in the contribution an the ## Logwatch project reserves the right to not accept such ## contributions. If you have made significant ## contributions to this script and want to claim ## copyright please contact logwatch-devel@lists.sourceforge.net. ######################################################### use strict; use Logwatch ':all'; my (%denials, %allowed, %loads); my %OtherList; my $othercount = 0; my $Debug = ($ENV{'LOGWATCH_DEBUG'} || 0); my $Detail = ($ENV{'LOGWATCH_DETAIL_LEVEL'} || 0); my $NumberOfInits = 0; my $NumberOfDStarts = 0; my $NumberOfDStartsPid = 0; my $NumberOfDStops = 0; my $NumberOfDdStarts = 0; my $NumberOfDdStops = 0; my $NumberOfAllowedMessages = 0; my $NumberOfLostMessages = 0; my %InvalidContext = (); my %BugLog = (); my $UELimit = 100; my $ThisLine; my %Warning = (); my %AuditctlStatus = (); my %unconfineds = (); print STDERR "\n\nDEBUG: Inside audit filter\n\n" if ( $Debug >= 5 ); while ($ThisLine = ) { chomp($ThisLine); # Remove timestamp if present $ThisLine =~ s/^\[\s*\d+\.\d+\]\s*//; if (( $ThisLine =~ /initializing netlink (socket|subsys) \(disabled\)/) or ( $ThisLine =~ /audit_pid=[0-9]* old=[0-9]*(?: by auid=[0-9]*)?/) or ( $ThisLine =~ /(arch=[0-9]+ )?syscall=[0-9]+ (success=(no|yes) )?exit=[0-9-]+( a[0-3]=[0-9a-f]+)* items=[0-9]+ (ppid=[0-9]+ )?pid=[0-9]+ (loginuid=[0-9-]+ )?(auid=[0-9]+ )?uid=[0-9]+ gid=[0-9]+ euid=[0-9]+ suid=[0-9]+ fsuid=[0-9]+ egid=[0-9]+ sgid=[0-9]+ fsgid=[0-9]+/) or ( $ThisLine =~ /Audit daemon rotating log files/) or ( $ThisLine =~ /audit_backlog_limit=[0-9]* old=[0-9]*(?: by auid=[0-9]*)?/) or ( $ThisLine =~ /SELinux: unrecognized netlink message type=[0-9]+ for sclass=[0-9]+/) or ( $ThisLine =~ /audit\([0-9.]+:[0-9]+\): saddr=[0-9]+/) or ( $ThisLine =~ /nargs=[0-9]+ a0=[0-9a-f]+ a1=[0-9a-f]+ a2=[0-9a-f]+ a3=[0-9a-f]+ a4=[0-9a-f]+ a5=[0-9a-f]+/) or ( $ThisLine =~ /^audit\([0-9.]+:[0-9]+\): ( ?(path|cwd|item|name|flags)=["\/A-Za-z0-9]*)*$/) or ( $ThisLine =~ /: enforcing=[0-9]+ old_enforcing=[0-9]+ auid=[0-9]+/) or ( $ThisLine =~ /: policy loaded auid=[0-9]+/) or ( $ThisLine =~ /: user pid=[0-9]+ uid=[0-9]+ auid=[0-9]+ subj=system_u:system_r:system_dbusd_t:[0-9a-z:.\-]+ msg=/) or ( $ThisLine =~ /audit\([0-9.]+:[0-9]+\): (selinux=[0-9]+|auid=[0-9]+|prom=[0-9]+|old_prom=[0-9]+|[ug]id=[0-9]+|dev=[^ ]+|ses=[0-9]+| )+$/) or ( $ThisLine =~ /auditd[ ]+S [0-9A-F]+ [0-9]+ [0-9]+[ ]+[0-9]([ ]*[0-9]+[ ]*|[ ]*)[0-9]+ [0-9]+ \(NOTLB\)/) or ( $ThisLine =~ /Started dispatcher: \/sbin\/audispd pid: [0-9]+/) or ( $ThisLine =~ /dispatcher [0-9]+ reaped/) or ( $ThisLine =~ /audit\([0-9.]*:[0-9]*\): bool=.* val=.* old_val=.* auid=[0-9]*/) or ( $ThisLine =~ /type=[0-9]+ audit\([0-9.]*:[0-9]*\): audit_enabled=[0-9]* old=[0-9]* auid=[0-9]* ses=[0-9]*/) or ( $ThisLine =~ /type=[0-9]+ audit\([0-9.]*:[0-9]*\): auid=[0-9]* ses=[0-9]* subj=system_u:system_r:.*:s0 op=.* key=.* list=[0-9]* res=[0-9]*/) or ( $ThisLine =~ /type=[0-9]+ audit\([0-9.]*:[0-9]*\): pid=0 uid=0 auid=[0-9]* ses=[0-9]* subj=system_u:system_r:.*:s0 .* res=success/) or ( $ThisLine =~ /type=[0-9]+ audit\([0-9.]*:[0-9]*\): pid=1 uid=0 auid=[0-9]* ses=[0-9]* subj=system_u:system_r:init_t:s0 .* res=success/) or ( $ThisLine =~ /type=[0-9]+ audit\([0-9.]*:[0-9]*\): pid=[0-9]* uid=0 auid=[0-9]* ses=[0-9]*$/) or ( $ThisLine =~ /type=[0-9]+ audit\([0-9.]*:[0-9]*\): pid=[0-9]* uid=0 auid=[0-9]* ses=[0-9]* subj=.*res=success/) or ( $ThisLine =~ /type=[0-9]+ audit\([0-9.]*:[0-9]*\): pid=[0-9]* uid=0 old auid=[0-9]* new auid=[0-9]+ old ses=[0-9]* new ses=[0-9]+ res=1$/) or ( $ThisLine =~ /type=[0-9]+ audit\([0-9.]*:[0-9]*\): pid=[0-9]* uid=0 subj=.* old-auid=[0-9]* auid=[0-9]+ old-ses=[0-9]* ses=[0-9]+ res=1$/) or # This will generate a journal entry for the service failure, success, or start/stop ( $ThisLine =~ /type=113[01] audit\([0-9.]*:[0-9]*\): pid=1 uid=0 auid=[0-9]+ ses=[0-9]+ (?:subj=system_u:system_r:init_t:s0 )?msg='unit.* comm="systemd" .* res=.*'$/) or ( $ThisLine =~ /SERVICE_(?:START|STOP) pid=1/) or ( $ThisLine =~ /type=[0-9]+ audit\([0-9.]*:[0-9]*\): cwd=".*"/) or ( $ThisLine =~ /type=[0-9]+ audit\([0-9.]*:[0-9]*\): user/) or ( $ThisLine =~ /type=[0-9]+ audit\([0-9.]*:[0-9]*\): proctitle=/) or ( $ThisLine =~ /type=[0-9]+ audit\([0-9.]*:[0-9]*\): table=/) or ( $ThisLine =~ /audit_printk_skb: [0-9]* callbacks suppressed/) or ( $ThisLine =~ /item=[0-9] name="\S*" inode=[0-9]+ dev=\S* mode=[0-9]* ouid=[0-9]* ogid=[0-9]* rdev=[0-9:]* obj=\S*/) or ( $ThisLine =~ /^auditctl(?:\[[0-9]+\])?: No rules$/ ) ) { # Ignore these entries } elsif ( $ThisLine =~ /audit\([0-9]{10}.[0-9]{3}:[0-9]\): (?:state=)?initialized/) { $NumberOfInits++; } elsif ( $ThisLine =~ /Init complete, audit pid set to: [0-9]+/) { $NumberOfDStartsPid++; } elsif ( $ThisLine =~ /Init complete, auditd [0-9,.]+ listening for events/) { $NumberOfDStarts++; } elsif ( $ThisLine =~ /The audit daemon is exiting./) { $NumberOfDStops++; } elsif ( $ThisLine =~ /audit_lost=[0-9]+ (audit_backlog=[0-9]+ )?audit_rate_limit=[0-9]+ audit_backlog_limit=[0-9]+$/) { $NumberOfLostMessages++; } elsif ( $ThisLine =~ /auditd startup succeeded/) { $NumberOfDdStarts++; } elsif ( $ThisLine =~ /auditd shutdown succeeded/) { $NumberOfDdStops++; } elsif (( $ThisLine =~ /netlink socket too busy/) or ( $ThisLine =~ /Error sending signal_info request \(Invalid argument\)/) or ( $ThisLine =~ /major=[0-9]+ name_count=[0-9]+: freeing multiple contexts \([1-2]\)/)) { $ThisLine =~ s/audit\(:[0-9]+\): //; $BugLog{$ThisLine}++; } elsif (( $ThisLine =~ /(Audit daemon is low on disk space for logging.*)/) or ( $ThisLine =~ /(Audit daemon has no space left.*)/) or ( $ThisLine =~ /(Audit daemon is suspending logging due to.*)/)) { $Warning{$1}++; } elsif ( my ($status) = ( $ThisLine =~ /AUDIT_STATUS: (.*)/ ) ) { $AuditctlStatus{$status}++; } elsif ( ($status) = ( $ThisLine =~ /^auditctl(?:\[[0-9]+\])?: (.*)/ ) ) { $AuditctlStatus{$status}++; } elsif ( $ThisLine =~ /audit\([0-9]+\.[0-9]+:[0-9]+\): apparmor=/) { # AppArmor if ( $ThisLine =~ /apparmor="STATUS" operation="profile_(load|replace)" (?:profile="unconfined")?name="([^"]+)"/ ) { # type=1400 audit(1314853473.168:33616): apparmor="STATUS" operation="profile_replace" name="/usr/lib/apache2/mpm-prefork/apache2//DEFAULT_URI" pid=26566 comm="apparmor_parser" $loads{$2}++; } elsif ( $ThisLine =~ /apparmor="STATUS" operation="profile_(load|replace)" profile="unconfined" name="([^"]+)"/ ) { # type=1400 audit(1462209116.753:18): apparmor="STATUS" operation="profile_replace" profile="unconfined" name="/usr/sbin/named" pid=22094 comm="apparmor_parser" # type=1400 audit(1462209262.641:2): apparmor="STATUS" operation="profile_load" profile="unconfined" name="/usr/bin/freshclam" pid=1760 comm="apparmor_parser" $unconfineds{$2}++; } elsif ( $ThisLine =~ /apparmor="DENIED" operation="([^"]+)" (?:parent=\d+ )?profile="([^"]+)" name="([^"]+)" pid=\d+ comm="([^"]+)"/ ) { # type=1400 audit(1314853822.672:33649): apparmor="DENIED" operation="mknod" parent=27250 profile="/usr/lib/apache2/mpm-prefork/apache2//example.com" name="/usr/share/wordpress/1114140474e5f13bea68a4.tmp" pid=27289 comm="apache2" requested_mask="c" denied_mask="c" fsuid=33 ouid=33 # type=1400 audit(1315353795.331:33657): apparmor="DENIED" operation="exec" parent=14952 profile="/usr/lib/apache2/mpm-prefork/apache2//example.com" name="/usr/lib/sm.bin/sendmail" pid=14953 comm="sh" requested_mask="x" denied_mask="x" fsuid=33 ouid=0 # type=1400 audit(1597683992.796:8057): apparmor="DENIED" operation="exec" profile="/usr/bin/evince" name="/usr/lib/uim/uim-helper-server" pid=1687330 comm="evince" requested_mask="x" denied_mask="x" fsuid=1000 ouid=0: 1 Time(s) $denials{$1.' '.$3.' ('.$2.' via '.$4 . ')'}++; } elsif ( $ThisLine =~ /apparmor="DENIED" operation="([^"]+)" info="([^"]+)" error=-*[0-9]+ profile="([^"]+)" name="([^"]+)" pid=\d+ comm="([^"]+)"/ ) { # type=1400 audit(1597690743.153:8073): apparmor="DENIED" operation="mount" info="failed flags match" error=-13 profile="lxd-open-iscsi-review-mp389234-groovy_" name="/run/" pid=1694826 comm="mount" flags="rw, nosuid, nodev, remount": 1 Time(s) $denials{$1.' '.$4.' ('.$3.' via '.$5 .': '.$2. ')'}++; } elsif ( $ThisLine =~ /apparmor="ALLOWED" operation="([^"]+)" (info="([^"]+)" )?(error=[+-]?\d+ )?(parent=\d+ )?profile="([^"]+)" (name="([^"]+)" )?pid=\d+ comm="([^"]+)"/ ) { # type=1400 audit(1369519203.141:259049): apparmor="ALLOWED" operation="exec" parent=3733 profile="/usr/sbin/dovecot//null-1c//null-1d" name="/usr/lib/dovecot/pop3-login" pid=24634 comm="dovecot" requested_mask="x" denied_mask="x" fsuid=0 ouid=0 target="/usr/sbin/dovecot//null-1c//null-1d//null-d12" # type=1400 audit(1369627891.522:447576): apparmor="ALLOWED" operation="capable" parent=1 profile="/usr/sbin/dovecot//null-1c//null-1d" pid=3733 comm="dovecot" capability=5 capname="kill" # type=1400 audit(1369823965.682:824587): apparmor="ALLOWED" operation="getattr" info="Failed name lookup - deleted entry" error=-2 parent=1 profile="/usr/sbin/dovecot//null-1c//null-1d" name="/var/lib/dovecot/.temp.3733.d786c1fcaaa73248" pid=3733 comm="dovecot" requested_mask="r" denied_mask="r" fsuid=0 ouid=0 # type=1400 audit(1410503892.382:55490): apparmor="ALLOWED" operation="open" profile="/usr/lib/dovecot/imap" name="/root/mails/.Drafts/dovecot.index.log" pid=6305 comm="imap" requested_mask="rw" denied_mask="rw" fsuid=1003 ouid=1003 $NumberOfAllowedMessages++; } else { $ThisLine =~ s/^\s*//; $OtherList{$ThisLine}++; } } elsif ( $Detail > 9 ) { if ( $ThisLine =~ /avc:\s*denied\s*{\s*([^}]+).*scontext=(\S+)\s*tcontext=(\S+)\s*tclass=(\S+)/ ) { $denials{$2.' '.$3.' ('.$1.$4 . ')'}++; } elsif ( $ThisLine =~ /avc:\s*granted\s*{\s*([^}]+).*scontext=(\S+)\s*tcontext=(\S+)\s*tclass=(\S+)/ ) { $allowed{$2.' '.$3.' ('.$1.$4 . ')'}++; } elsif ($ThisLine =~ /security_compute_sid:\s*invalid context\s*(\S+)\s*for\s*scontext=(\S+)\s*tcontext=(\S+)\s*tclass=(\S+)/ ) { $InvalidContext{$4." running as ".$2." acting on ".$3." \nshould transit to invalid ".$1}++; } elsif ($ThisLine =~ /security_sid_mls_copy:\s*invalid context\s*(\S+)/) { $InvalidContext{"context: ".$1}++; } else { $ThisLine =~ s/^\s*//; $OtherList{$ThisLine}++; } } elsif ( $Detail > 4 ) { if ( $ThisLine =~ /avc:\s*denied\s*{\s*[^}]+.*scontext=(\S+)\s*tcontext=(\S+)\s*tclass=(\S+)/ ) { $denials{$1.' '.$2.' ('.$3 . ')'}++; } elsif ( $ThisLine =~ /avc:\s*granted\s*{\s*[^}]+}.*scontext=(\S+)\s*tcontext=(\S+)\s*tclass=(\S+)/ ) { $allowed{$1.' '.$2.' ('.$3 . ')'}++; } elsif ($ThisLine =~ /security_compute_sid:\s*invalid context\s*(\S+)\s*for\s*scontext=(\S+)\s*tcontext=\S+\s*tclass=(\S+)/ ) { $InvalidContext{$3." running as ".$2." should transit to invalid ".$1}++; } elsif ($ThisLine =~ /security_sid_mls_copy:\s*invalid context\s*(\S+)/) { $InvalidContext{"context: ".$1}++; } else { $ThisLine =~ s/^\s*//; $OtherList{$ThisLine}++; } } else { if ( $ThisLine =~ /avc:\s*denied\s*{\s*[^}]+.*scontext=([^:]+):[^:]+:\S+\s*tcontext=([^:]+):[^:]+:\S+\s*tclass=(\S+)/ ) { $denials{$1.' '.$2.' ('.$3 . ')'}++; } elsif ( $ThisLine =~ /avc:\s*granted\s*{\s*[^}]+.*scontext=([^:]+):[^:]+:\S+\s*tcontext=([^:]+):[^:]+:\S+\s*tclass=(\S+)/ ) { $allowed{$1.' '.$2.' ('.$3 . ')'}++; } elsif ($ThisLine =~ /security_compute_sid:\s*invalid context\s*(\S+)\s*for\s*scontext=(\S+)\s*tcontext=\S+\s*tclass=(\S+)/ ) { $InvalidContext{$3." running as ".$2." should transit to invalid ".$1}++; } elsif ($ThisLine =~ /security_sid_mls_copy:\s*invalid context\s*(\S+)/) { $InvalidContext{"context: ".$1}++; } else { $ThisLine =~ s/^\s*//; $OtherList{$ThisLine}++; } } } if ( %Warning) { foreach my $key (keys %Warning) { print " Warning: $key: ". $Warning{$key}. " times\n"; } } if ( keys %denials ) { print "\n\n*** Denials ***\n"; foreach my $key (sort keys %denials) { print " $key: ". $denials{$key} . " times\n"; } } if ( keys %allowed ) { print "\n\n*** Allowed ***\n"; foreach my $key (sort keys %allowed) { print " $key: ". $allowed{$key} . " times\n"; } } if ( keys %InvalidContext) { print "\n\n*** Invalid Context ***\n"; foreach my $key (sort keys %InvalidContext) { print " $key: ". $InvalidContext{$key} . " times\n"; } } if ( keys %loads ) { print "\n\n*** Loads ***\n"; foreach my $key (sort keys %loads) { print " $key: ". $loads{$key} . " times\n"; } } if ($Detail and $NumberOfDStarts+$NumberOfDStartsPid) { print "\n Number of audit daemon starts: ",$NumberOfDStarts+$NumberOfDStartsPid," \n"; } if (($Detail >9) and ($NumberOfDStartsPid)) { print " starts with pid change: $NumberOfDStartsPid \n" } if ($Detail and $NumberOfDStops) { print "\n Number of audit daemon stops: $NumberOfDStops \n"; } if ($Detail and keys(%AuditctlStatus)) { print "\n Auditctl status:\n"; foreach my $key (sort keys %AuditctlStatus) { print " $key: ". $AuditctlStatus{$key} . " times\n"; } } if ($NumberOfAllowedMessages) { print "\n Number of allowed messages: $NumberOfAllowedMessages\n"; } if ($NumberOfLostMessages) { print "\n Number of lost messages: $NumberOfLostMessages\n"; } if ($Detail>9) { if ($NumberOfInits) { print "\n Number of audit initializations: $NumberOfInits \n"; } if ($NumberOfDdStarts) { print "\n Number of auditd daemon starts: $NumberOfDdStarts \n"; } if ($NumberOfDdStops) { print "\n Number of auditd daemon stops: $NumberOfDdStops \n"; } } if ( %BugLog) { print "\n*** Logs which could mean a bug ***\n"; foreach my $Entry (keys %BugLog) { print " $Entry\n"; } } if (keys %OtherList and $Detail) { print "\n**Unmatched Entries**\n"; foreach my $line (sort {$OtherList{$b}<=>$OtherList{$a} } keys %OtherList) { print " $line: $OtherList{$line} Time(s)\n"; } } exit(0); # vi: shiftwidth=3 tabstop=3 syntax=perl et # Local Variables: # mode: perl # perl-indent-level: 3 # indent-tabs-mode: nil # End: logwatch-7.12/scripts/services/scsi0000664000211400021140000000546014274101043017644 0ustar logwatchlogwatch ######################################################## # Please file all bug reports, patches, and feature # requests under: # https://sourceforge.net/p/logwatch/_list/tickets # Help requests and discusion can be filed under: # https://sourceforge.net/p/logwatch/discussion/ ######################################################## ####################################################### ## Copyright (c) 2008 Benjamin Baudoux ## Covered under the included MIT/X-Consortium License: ## http://www.opensource.org/licenses/mit-license.php ## All modifications and contributions by other persons to ## this script are assumed to have been donated to the ## Logwatch project and thus assume the above copyright ## and licensing terms. If you want to make contributions ## under your own copyright or a different license this ## must be explicitly stated in the contribution an the ## Logwatch project reserves the right to not accept such ## contributions. If you have made significant ## contributions to this script and want to claim ## copyright please contact logwatch-devel@lists.sourceforge.net. ######################################################### ######################################################## # This was written and is maintained by: # cadtool@stepmind.com # # Heavily based on sshd script ######################################################## use strict; use Logwatch ':all'; my $Debug = $ENV{'LOGWATCH_DEBUG'} || 0; my $DebugCounter = 0; my $Diskwarning = 0; my %ListDiskWarning = (); my @OtherList = (); if ( $Debug >= 5 ) { print STDERR "\n\nDEBUG: Inside SCSI Filter \n\n"; $DebugCounter = 1; } while (defined(my $ThisLine = )) { if ( $Debug >= 5 ) { print STDERR "DEBUG($DebugCounter): $ThisLine"; $DebugCounter++; } chomp($ThisLine); if ( 0 or ($ThisLine =~ m/target/) # startup ) { # Ignore these } elsif ( ($ThisLine =~ m/WARNING:/) or ($ThisLine =~ m/Requested Block:/) or ($ThisLine =~ m/Sense Key:/) or ($ThisLine =~ m/Vendor:/) or ($ThisLine =~ m/ASC:/) ) { $ListDiskWarning{$ThisLine} += 1; if ( $ThisLine =~ m/WARNING:/ ) { $Diskwarning++; } } else { # Report any unmatched entries... push @OtherList, "$ThisLine\n"; } } ########################################################### if ($Diskwarning) { print "\nYou may have R/W errors on your device " . $Diskwarning . " Time(s)\n"; print "$_: $ListDiskWarning{$_} time(s)\n" foreach keys %ListDiskWarning; } if ($#OtherList >= 0) { print "\n**Unmatched Entries**\n"; print @OtherList; } exit(0); # vi: shiftwidth=3 tabstop=3 syntax=perl et # Local Variables: # mode: perl # perl-indent-level: 3 # indent-tabs-mode: nil # End: logwatch-7.12/scripts/services/mountd0000664000211400021140000001137514274101040020210 0ustar logwatchlogwatch ######################################################## # Please file all bug reports, patches, and feature # requests under: # https://sourceforge.net/p/logwatch/_list/tickets # Help requests and discusion can be filed under: # https://sourceforge.net/p/logwatch/discussion/ ######################################################## ##################################################### ## Copyright (c) 2008 Kirk Bauer ## Covered under the included MIT/X-Consortium License: ## http://www.opensource.org/licenses/mit-license.php ## All modifications and contributions by other persons to ## this script are assumed to have been donated to the ## Logwatch project and thus assume the above copyright ## and licensing terms. If you want to make contributions ## under your own copyright or a different license this ## must be explicitly stated in the contribution an the ## Logwatch project reserves the right to not accept such ## contributions. If you have made significant ## contributions to this script and want to claim ## copyright please contact logwatch-devel@lists.sourceforge.net. ######################################################### use Logwatch ':ip'; use strict; my $Detail = $ENV{'LOGWATCH_DETAIL_LEVEL'} || 0; #Init String Container my ( $IP, $Mount, $Name, $Number, ); #Init Array my @OtherList = (); #Init Hashes my ( %Attempted, %Mounted, %NotFound, %Rejected, %SignalExit ); while (defined(my $ThisLine = )) { if ( ($ThisLine =~ /^Unauthorized access by NFS client .*$/ ) or ($ThisLine =~ /^NFS client [^ ]+ tried to access .*$/ ) or ($ThisLine =~ /^[^ ]* exported to both [0-9.]*\/[0-5]* and [0-9.]*\/[0-9]/) ) { # don't care about this, as the next line reports the IP again } elsif ( ($IP,$Mount) = ($ThisLine =~ /^Blocked attempt of (\d+\.\d+\.\d+\.\d+) to mount (.*)$/) ) { $Name = LookupIP ($IP); $Mount = " " . $Mount; $Rejected{$Name}{$Mount}++; } elsif ( ($Name,$Mount) = ($ThisLine =~ /^refused mount request from (.+) for ([^ ]+)/) ) { $Mount = " " . $Mount; $Rejected{$Name}{$Mount}++; } elsif ( ($Mount) = ($ThisLine =~ /can.t stat exported dir (.*): No such file or directory/) ) { $Mount = " " . $Mount; $NotFound{$Mount}++; } elsif ( ($Mount,$IP) = ($ThisLine =~ /^NFS mount of (.*) attempted from (\d+\.\d+\.\d+\.\d+) $/) ) { $Name = LookupIP ($IP); $Mount = " " . $Mount; $Attempted{$Name}{$Mount}++; } elsif ( ($Name,$Mount) = ($ThisLine =~ /^authenticated (?:un)?mount request from (.+):\d+ for ([^ ]+)/) ) { $Mount = " " . $Mount; $Mounted{$Name}{$Mount}++; } elsif ( ($Name) = ($ThisLine =~ /^authenticated (?:un)?mount request from ([\w:]+)/) ) { $Mount = " unknown"; $Mounted{$Name}{$Mount}++; } elsif ( ($Mount,$IP) = ($ThisLine =~ /^(.*) has been mounted by (\d+\.\d+\.\d+\.\d+) $/) ) { $Name = LookupIP ($IP); $Mount = " " . $Mount; $Mounted{$Name}{$Mount}++; } elsif ( ($Number) = ($ThisLine =~ /Caught signal ([0-9]*), un-registering and exiting/) ) { $SignalExit{$Number}++; } else { # Report any unmatched entries... push @OtherList,$ThisLine; } } if (keys %Rejected) { print "\nRefused NFS mount attempts:\n"; foreach my $ThisOne (keys %Rejected) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (keys %{$Rejected{$ThisOne}}) { print $ThatOne . ': ' . $Rejected{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if (keys %NotFound) { print "\nAttempts to mount nonexisting files or directories:\n"; foreach my $ThisOne (keys %NotFound) { print " " . $ThisOne .":" . $NotFound{$ThisOne} . " Time(s)\n"; } } if (keys %SignalExit) { printf "\nExit after catching signal:\n"; foreach my $Number (keys %SignalExit) { print " Signal " . $Number. ": " . $SignalExit{$Number} . " Time(s)\n"; } } if (($Detail >= 5) and (keys %Mounted)) { print "\nSuccessful NFS mounts:\n"; foreach my $ThisOne (keys %Mounted) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (keys %{$Mounted{$ThisOne}}) { print $ThatOne . ': ' . $Mounted{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if (($Detail >= 10) and (keys %Attempted)) { print "\nAttempted NFS mounts:\n"; foreach my $ThisOne (keys %Attempted) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (keys %{$Attempted{$ThisOne}}) { print $ThatOne . ': ' . $Attempted{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if ($#OtherList >= 0) { print "\n**Unmatched Entries**\n"; print @OtherList; } exit(0); # vi: shiftwidth=3 tabstop=3 syntax=perl et # Local Variables: # mode: perl # perl-indent-level: 3 # indent-tabs-mode: nil # End: logwatch-7.12/scripts/services/puppet0000664000211400021140000002613614743365005020236 0ustar logwatchlogwatch ######################################################## # Please file all bug reports, patches, and feature # requests under: # https://sourceforge.net/p/logwatch/_list/tickets # Help requests and discusion can be filed under: # https://sourceforge.net/p/logwatch/discussion/ ######################################################## ######################################################## ## Copyright (c) 2011 Nathan Crawford ## Covered under the included MIT/X-Consortium License: ## http://www.opensource.org/licenses/mit-license.php ## All modifications and contributions by other persons to ## this script are assumed to have been donated to the ## Logwatch project and thus assume the above copyright ## and licensing terms. If you want to make contributions ## under your own copyright or a different license this ## must be explicitly stated in the contribution and the ## Logwatch project reserves the right to not accept such ## contributions. If you have made significant ## contributions to this script and want to claim ## copyright please contact logwatch-devel@lists.sourceforge.net. ######################################################### use strict; # Detail level my $Detail = $ENV{'LOGWATCH_DETAIL_LEVEL'} || 0; # Config my $offline = $ENV{'puppet_offline_ok'}; # Init counters my $FailedRuns = 0; my $SuccessfulRuns = 0; my $ResourceFailures = 0; my $DependencyFailures = 0; #Init String containers my ( $attr, $content, $file, $fileinfo, $from, $name, $source, $target, $to, $type ); # Init hashes my ( %Changed, %ChangedPackages, %Created, %Errors, %ExecRuns, %ExpiryChanged, %Failures, %FileBucketed, %InstalledPackages, %OtherList, %PasswordChanged, %Removed, %RemovedPackages, %Reparsed, %ScheduledRefresh, %ServiceStarts, %ServiceStops ); while (defined(my $ThisLine = )) { chomp($ThisLine); if ( ($ThisLine =~ /Using cached catalog/) or ($ThisLine =~ /Caching catalog for /) or ($ThisLine =~ /Caching node for /) or ($ThisLine =~ /Caught TERM; calling stop/) or ($ThisLine =~ /[sS]hutting down/) or ($ThisLine =~ /Reopening log files/) or ($ThisLine =~ /Starting Puppet client version /) or ($ThisLine =~ /Restarting with.+puppetd/) or ($ThisLine =~ /Caught HUP; calling restart/) or ($ThisLine =~ /Skipping because of failed dependencies/) or ($ThisLine =~ /Failed to generate additional resources/) or ($ThisLine =~ /Could not evaluate: getaddrinfo: Name or service not known/) or ($ThisLine =~ /replacing from source .+ with contents /) or ($ThisLine =~ /Starting catalog run/) or ($ThisLine =~ /Applying configuration version/) or ($ThisLine =~ /Loading facts in/) or ($ThisLine =~ /Retrieving plugin/) or ($ThisLine =~ /FileBucket adding/) or ($ThisLine =~ /^Caching certificate/) or ($ThisLine =~ /^Certificate Request fingerprint/) or ($ThisLine =~ /^Creating state file/) or ($ThisLine =~ /Provider useradd does not support features manages/) ) { # Ignore } elsif (my ($junk, $failure, $reason) = ($ThisLine =~ /^(\(.*\) |)Could not ([^:]*): (.*)/)) { if ($reason == "getaddrinfo: Name or service not known" && $offline) { $FailedRuns--; } else { $Failures{$failure}->{$reason}++; } } elsif ($ThisLine =~ /Finished catalog run in [0-9]+\.[0-9]+ seconds/) { $SuccessfulRuns++; } elsif ($ThisLine =~ /Applied catalog in [0-9]+\.[0-9]+ seconds/) { $SuccessfulRuns++; } elsif ($ThisLine =~ /skipping run/) { $FailedRuns++; } elsif ($ThisLine =~ /(Did not receive certificate)/) { $Errors{$1}++; } elsif (($file) = $ThisLine =~ /Reparsing (.*)/) { $Reparsed{$file}++; } elsif (($fileinfo) = ($ThisLine =~ /Filebucketed (.*)/)) { $FileBucketed{$1}++; } elsif ($ThisLine =~ /Dependency .+\[.+\] has ([0-9]+ |)failure/) { $DependencyFailures++; } elsif ( ($ThisLine =~ /Failed to retrieve current state of resource/) or ($ThisLine =~ /Package.+ensure.+Could not find package/) or ($ThisLine =~ /File\[.+\].+ Could not describe /) or ($ThisLine =~ /File\[.+\].+ No specified sources exist/) ) { $ResourceFailures++; } elsif ($ThisLine =~ /Package\[(.+)\].+ensure changed/) { $ChangedPackages{$1}++; } elsif ($ThisLine =~ /Package\[(.+)\].+ensure\) created/) { $InstalledPackages{$1}++; } elsif ($ThisLine =~ /Package\[(.+)\].+ensure\) removed/) { $RemovedPackages{$1}++; } elsif ($ThisLine =~ /Exec\[(.+)\].+executed successfully/) { $ExecRuns{$1}++; } elsif ($ThisLine =~ /Exec\[(.+)\].+Trigger(?:ing|ed) 'refresh' from [0-9]+ (?:dependencies|events)/) { $ExecRuns{$1}++; } elsif ($ThisLine =~ /Exec\[(.+)\].+Triggered 'refresh' from [0-9]+ events/) { $ExecRuns{$1}++; } elsif ($ThisLine =~ /Service\[(.+)\].+ensure changed \'.+\' to \'running\'/) { $ServiceStarts{$1}++; } elsif ($ThisLine =~ /Service\[(.+)\].+Trigger(?:ing|ed) 'refresh' from [0-9]+ (?:dependencies|events)/) { $ServiceStarts{$1}++; } elsif ($ThisLine =~ /Service\[(.+)\].+Triggered 'refresh' from [0-9]+ events/) { $ServiceStarts{$1}++; } elsif ($ThisLine =~ /Service\[(.+)\].+ensure changed \'.+\' to \'stopped\'/) { $ServiceStops{$1}++; } elsif ($ThisLine =~ /User\[(.+)\].+changed password/) { $PasswordChanged{$1}++; } elsif ($ThisLine =~ /User\[(.+)\].+defined \'expiry\' as \'([0-9-]{10})\'/) { $ExpiryChanged{$1}{$2}++; # Generic rules need to be last } elsif (($type, $name, $attr) = $ThisLine =~ /([^\/]+)\[([^\]]+)\]\/([^\/]+)\) (created|defined content)/) { $Created{$type}->{$name}++; } elsif (($type, $name, $attr) = $ThisLine =~ /([^\/]+)\[([^\]]+)\]\/([^\/]+)\) removed/) { $Removed{$type}->{$name}++; } elsif (($type, $name, $attr, $from, $to) = $ThisLine =~ /([^\/]+)\[([^\]]+)\]\/([^\/]+)\) .+ changed '(.*)' to '(.*)/) { if ($attr eq 'content' or $attr eq 'checksum') { # Only count these types of changes $Changed{$type}->{$name}->{$attr}++; } else { # Get details for all other types of changes $Changed{$type}->{$name}->{$attr}->{'from'} = $from; $Changed{$type}->{$name}->{$attr}->{'to'} = $to; } } elsif (($type, $name, $attr, $from) = $ThisLine =~ /([^\/]+)\[([^\]]+)\]\/([^\/]+)\) undefined '.+' from '(.*)'/) { $Changed{$type}->{$name}->{$attr}->{'from'} = $from; $Changed{$type}->{$name}->{$attr}->{'to'} = 'undefined'; } elsif (($type, $name, $content) = $ThisLine =~ /([^\/]+)\[([^\]]+)\]\/content\)(.*)/) { $content =~ s/#011/\t/g; $content =~ s/#012/\n /g or $content .= "\n "; $Changed{$type}->{$name}->{'contents'} .= $content; } elsif (($source, $target) = $ThisLine =~ /^\(\/(.*)\) Scheduling refresh of (.*)/) { $ScheduledRefresh{"$source -> $target"}++; } else { # Report any unmatched entries... $OtherList{$ThisLine}++; } } ####################################### if ($SuccessfulRuns > 0 && $Detail > 0) { print "\nSuccessful runs: $SuccessfulRuns\n"; } if ($FailedRuns > 0) { print "\nFailed runs: $FailedRuns\n"; } if (keys %Errors) { print "\nERRORS:\n"; foreach my $ThisOne (keys %Errors) { print " $ThisOne: $Errors{$ThisOne} Time(s)\n"; } } foreach my $failure (sort(keys %Failures)) { print "\nERROR: Could not $failure:\n"; foreach my $ThisOne (keys %{$Failures{$failure}}) { print " $ThisOne: $Failures{$failure}->{$ThisOne} Time(s)\n"; } } if ($ResourceFailures > 0) { print "\nResource failures: $ResourceFailures\n"; } if ($DependencyFailures > 0) { print "\nDependency failures: $DependencyFailures\n"; } if (keys %Reparsed) { print "\nReparsed:\n"; foreach my $ThisOne (keys %Reparsed) { print " $ThisOne: $Reparsed{$ThisOne} Time(s)\n"; } } if (keys %FileBucketed and $Detail >= 5) { print "\nFileBucketed files:\n"; foreach my $ThisOne (keys %FileBucketed) { print " $ThisOne\n"; } } if (keys %InstalledPackages) { print "\nInstalled packages:\n"; foreach my $ThisOne (keys %InstalledPackages) { print " $ThisOne: $InstalledPackages{$ThisOne} Time(s)\n"; } } if (keys %ChangedPackages) { print "\nChanged packages:\n"; foreach my $ThisOne (keys %ChangedPackages) { print " $ThisOne: $ChangedPackages{$ThisOne} Time(s)\n"; } } if (keys %RemovedPackages) { print "\nRemoved packages:\n"; foreach my $ThisOne (keys %RemovedPackages) { print " $ThisOne: $RemovedPackages{$ThisOne} Time(s)\n"; } } if (keys %ExecRuns) { print "\nExec runs:\n"; foreach my $ThisOne (keys %ExecRuns) { print " $ThisOne: $ExecRuns{$ThisOne} Time(s)\n"; } } if (keys %ServiceStarts) { print "\nService starts:\n"; foreach my $ThisOne (keys %ServiceStarts) { print " $ThisOne: $ServiceStarts{$ThisOne} Time(s)\n"; } } if (keys %ServiceStops) { print "\nService stops:\n"; foreach my $ThisOne (keys %ServiceStops) { print " $ThisOne: $ServiceStops{$ThisOne} Time(s)\n"; } } if (keys %PasswordChanged) { print "\nPassword changed:\n"; foreach my $ThisOne (keys %PasswordChanged) { print " $ThisOne: $PasswordChanged{$ThisOne} Time(s)\n"; } } if (keys %ExpiryChanged) { print "\nExpiry changed:\n"; foreach my $ThisOne (keys %ExpiryChanged) { print " $ThisOne:\n"; foreach my $date (keys %{${ExpiryChanged}{$ThisOne}}) { print " $date: $ExpiryChanged{$ThisOne}{$date} Time(s)\n"; } } } foreach my $Type (sort(keys %Created)) { print "\n$Type created:\n"; foreach my $Name (sort(keys %{$Created{$Type}})) { print " $Name: $Created{$Type}->{$Name} Time(s)\n"; } } foreach my $Type (sort(keys %Changed)) { print "\n$Type changed:\n"; foreach my $Name (sort(keys %{$Changed{$Type}})) { print " $Name:\n"; foreach my $Attr (sort(keys %{$Changed{$Type}->{$Name}})) { if ($Attr eq 'contents') { if ($Detail >= 3) { print " $Attr:"; print "$Changed{$Type}->{$Name}->{$Attr}\n"; } } else { print " $Attr: "; if (defined($Changed{$Type}->{$Name}->{$Attr}->{'from'})) { print "from '$Changed{$Type}->{$Name}->{$Attr}->{from}' to '$Changed{$Type}->{$Name}->{$Attr}->{to}'\n"; } else { print "$Changed{$Type}->{$Name}->{$Attr} Time(s)\n"; } } } } } foreach my $Type (sort(keys %Removed)) { print "\n$Type removed:\n"; foreach my $Name (sort(keys %{$Removed{$Type}})) { print " $Name: $Removed{$Type}->{$Name} Time(s)\n"; } } if (keys %ScheduledRefresh) { print "\nScheduled refresh:\n"; foreach my $ThisOne (keys %ScheduledRefresh) { print " $ThisOne: $ScheduledRefresh{$ThisOne} Time(s)\n"; } } if (keys %OtherList) { print "\n**Unmatched Entries**\n"; foreach my $ThisOne (keys %OtherList) { print " $ThisOne: $OtherList{$ThisOne} Time(s)\n"; } } exit(0); # vi: shiftwidth=3 tabstop=3 syntax=perl et logwatch-7.12/scripts/services/netopia0000664000211400021140000004026614274101040020342 0ustar logwatchlogwatch ######################################################## # Please file all bug reports, patches, and feature # requests under: # https://sourceforge.net/p/logwatch/_list/tickets # and copy: # Laurent DUFOUR # Help requests and discusion can be filed under: # https://sourceforge.net/p/logwatch/discussion/ ######################################################## ######################################################## # This was written and is maintained by: # Laurent DUFOUR , # based on the work of # Kirk Bauer # # Please send all comments, suggestions, bug reports, # etc, to laurent.dufour@havas.com ######################################################## ##################################################### ## Copyright (c) 2008 Laurent DUFOUR ## Covered under the included MIT/X-Consortium License: ## http://www.opensource.org/licenses/mit-license.php ## All modifications and contributions by other persons to ## this script are assumed to have been donated to the ## Logwatch project and thus assume the above copyright ## and licensing terms. If you want to make contributions ## under your own copyright or a different license this ## must be explicitly stated in the contribution an the ## Logwatch project reserves the right to not accept such ## contributions. If you have made significant ## contributions to this script and want to claim ## copyright please contact logwatch-devel@lists.sourceforge.net. ######################################################### use Logwatch ':all'; use strict; my $Debug = ValueOrDefault($ENV{'LOGWATCH_DEBUG'}, 0); my $Detail = ValueOrDefault($ENV{'LOGWATCH_DETAIL_LEVEL'}, 0); my $DebugCounter = 0; # #Init String Containers my ( $Temp, $dst_ip, $interface, $src_ip ); #Init Hashes my ( %BadLogins, %DNSRefreshed, %IPDemandCall, %IllegalUsers, %NTPFailed, %NTPUpdated, %PPPAccepted, %PPPCcpNeg, %PPPCcpUp, %PPPChannelUp, %PPPIpCpDown, %PPPIpCpNeg, %PPPNcpUp, %PPTP1Down, %PPTP2Down, %PPTPIpDown, %PPTPIpUp, %ReloadRequested, %Restarted, %Started, %SysCfgSaved, %SyslogFacility, %SyslogHost, %Users ); #Init Array my @OtherList = (); # Avoid "Use of uninitialized value" warning messages. sub ValueOrDefault { my ($value, $default) = @_; return ($value ? $value : $default); } if ( $Debug >= 5 ) { print STDERR "\n\nDEBUG: Inside NETOPIA Filter \n\n"; $DebugCounter = 1; } my ($month,$day,$time,$host_ip,$host,$conn,$msg,$message); while (defined(my $ThisLine = )) { if ( $Debug >= 30 ) { print STDERR "DEBUG($DebugCounter): $ThisLine"; $DebugCounter++; } ($month,$day,$time,$host_ip,$host,$msg)=split(/ +/,$ThisLine,7); if ( ($ThisLine =~ /traffic/ ) or ($ThisLine =~ /Copyright/ ) or ($ThisLine =~ /removed due to simultaneous rekey/ ) or ($ThisLine =~ /Responded to the first peer message/ ) or ($ThisLine =~ /NBR change/ ) or ($ThisLine =~ /accept udp/ ) or ($ThisLine =~ /accept tcp/ ) or ($ThisLine =~ /accept icmp/ ) or ($ThisLine =~ /accept ip/ ) or ($ThisLine =~ /denied udp/ ) or ($ThisLine =~ /denied tcp/ ) or ($ThisLine =~ /denied icmp/ ) or ($ThisLine =~ /denied ip/ ) ) { # don't care about this, will code this later } elsif ( ($src_ip,$dst_ip) = ($ThisLine =~ /IP: Demand call requested by (\d+\.\d+\.\d+\.\d+) to IP destination (\d+\.\d+\.\d+\.\d+)/) ) { $IPDemandCall{$host}{$src_ip," ",$dst_ip}++; } elsif ( ($interface) = ($ThisLine =~ /PPP: NCP up, (.*)/) ) { $PPPNcpUp{$host}{$interface}++; } elsif ( ($interface) = ($ThisLine =~ /PPP: IPCP down, (.*)/) ) { $PPPIpCpDown{$host}{$interface}++; } elsif ( ($interface) = ($ThisLine =~ /PPP: MSCHAP-v2 we accepted remote, (.*)/) ) { $PPPAccepted{$host}{$interface}++; } elsif ( ($interface) = ($ThisLine =~ /PPP: MSCHAP-v2 remote accepted us, (.*)/) ) { $PPPAccepted{$host}{$interface}++; } elsif ( ($interface) = ($ThisLine =~ /PPP: CCP negotiated, (.*)/) ) { $PPPCcpNeg{$host}{$interface}++; } elsif ( ($interface) = ($ThisLine =~ /PPP: IPCP negotiated, (.*)/) ) { $PPPIpCpNeg{$host}{$interface}++; } elsif ( ($dst_ip,$msg) = ($ThisLine =~ /PPP: Channel (.+) up, Dialout Profile name: (.*)/) ) { $PPPChannelUp{$host}{$dst_ip}++; } elsif ( ($dst_ip,$msg) = ($ThisLine =~ /PPP: Channel (.+) up, Answer Profile name: (.*)/) ) { $PPPChannelUp{$host}{$dst_ip}++; } elsif ( ($interface) = ($ThisLine =~ /PPTP-1 down: (.*)/) ) { $PPTP1Down{$host}{$interface}++; } elsif ( ($interface) = ($ThisLine =~ /PPTP-2 down: (.*)/) ) { $PPTP2Down{$host}{$interface}++; } elsif ( ($dst_ip,$msg) = ($ThisLine =~ /PPTP: IP down, rem: (\d+\.\d+\.\d+\.\d+) (.*)/) ) { $PPTPIpDown{$host}{$dst_ip}++; } elsif ( ($dst_ip,$msg) = ($ThisLine =~ /PPTP: IP up, rem: (\d+\.\d+\.\d+\.\d+), (.*)/) ) { $PPTPIpUp{$host}{$dst_ip}++; } elsif ( ($dst_ip,$msg) = ($ThisLine =~ /System Config saved from host (\d+\.\d+\.\d+\.\d+) (.*)/) ) { $SysCfgSaved{$host}{LookupIP($dst_ip)}++; } elsif ( ($dst_ip,$msg) = ($ThisLine =~ /The system configuration was saved from host (\d+\.\d+\.\d+\.\d+) by (.*)/) ) { $SysCfgSaved{$host}{LookupIP($dst_ip)}++; } elsif ( ($ThisLine =~ /Compiled/) ) { $Started{$host}++; } elsif ( ($ThisLine =~ /DNS entries have been automatically refreshed./) ) { $DNSRefreshed{$host}++; } elsif ( ($ThisLine =~ /DNS has been refreshed./) ) { $DNSRefreshed{$host}++; } elsif ( ($ThisLine =~ /Syslog host domain name has been changed/) ) { $SyslogHost{$host}++; } elsif ( ($ThisLine =~ /Syslog facility has been changed/) ) { $SyslogFacility{$host}++; } elsif ( ($ThisLine =~ /Syslog security facility has been changed/) ) { $SyslogFacility{$host}++; } elsif ( ($ThisLine =~ /The system clock has been updated through NTP./) ) { $NTPUpdated{$host}++; } elsif ( ($ThisLine =~ /failed to get clock through NTP/) ) { $NTPFailed{$host}++; } elsif ( ($message) = ($ThisLine =~ /RELOAD: (.*)/) ) { $ReloadRequested{$host}{$message}++; } elsif ( ($message) = ($ThisLine =~ /RESTART: (.*)/) ) { $Restarted{$host}{$message}++; } elsif ( ($interface) = ($ThisLine =~ /Admin User "(\S+)" logged in for Web\((\S+)\) management \(port (\d+)\) from (.+):(.+). (.*)/) ) { if ($Debug >= 5) { print STDERR "DEBUG: Found -$1 logged in from $4 using $2\n"; } if ($Detail >= 20) { $Users{$host}{$2}{$4}{$1}++; } else { $Users{$host}{$2}{$4}{"(all)"}++; } } elsif ( $ThisLine =~ m/Admin user (\S+) login attempt for (\S+) management \(port (\d+)\) from (.+):(.+). failed. (.*)/ ) { if ( $Debug >= 5 ) { print STDERR "DEBUG: Found -Failed login- line\n"; } my $name = LookupIP($4); $BadLogins{$host}{"$1/$2 from $name"}++; } elsif ( $ThisLine =~ m/SSH client at (.+) has attempted to make an SCS connection to interface untrust with IP (.+) but failed (.*)/ ) { my $name = LookupIP($2); $Temp = "SSH from $name"; $BadLogins{$host}{$Temp}++; $IllegalUsers{$host}{$Temp}++; } else { # Report any unmatched entries... push @OtherList,$ThisLine; } } if (keys %Started) { print "\nDevice started :\n"; foreach my $ThisOne (keys %Started) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (keys %{$Started{$ThisOne}}) { print "\t Started" .$ThatOne . "\t: " . $Started{$ThisOne}{$ThatOne} . "{ Time(s)\n"; } } } if (keys %IPDemandCall) { print "\nDevice where ip demand call have been requested :\n"; foreach my $ThisOne (keys %IPDemandCall) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (keys %{$IPDemandCall{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $IPDemandCall{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if ( ( $Detail >= 15 ) and (keys %PPPNcpUp) ) { print "\nDevice where PPP Ncp UP :\n"; foreach my $ThisOne (keys %PPPNcpUp) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (keys %{$PPPNcpUp{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $PPPNcpUp{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if ( ( $Detail >= 15 ) and (keys %PPPCcpUp) ) { print "\nDevice where PPP CCP NEGOTIATED :\n"; foreach my $ThisOne (keys %PPPCcpNeg) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (keys %{$PPPCcpNeg{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $PPPCcpNeg{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if ( ( $Detail >= 15 ) and (keys %PPPIpCpDown) ) { print "\nDevice where PPP IPCP down :\n"; foreach my $ThisOne (keys %PPPIpCpDown) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (keys %{$PPPIpCpDown{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $PPPIpCpDown{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if ( ( $Detail >= 15 ) and (keys %PPPIpCpNeg) ) { print "\nDevice where PPP IPCP NEGOTIATED :\n"; foreach my $ThisOne (keys %PPPIpCpNeg) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (keys %{$PPPIpCpNeg{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $PPPIpCpNeg{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if (keys %NTPUpdated) { print "\nDevice where The system clock has been updated through NTP :\n"; foreach my $ThisOne (keys %NTPUpdated) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (keys %{$NTPUpdated{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $NTPUpdated{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if (keys %NTPFailed) { print "\nDevice where failed to get clock through NTP :\n"; foreach my $ThisOne (keys %NTPFailed) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (keys %{$NTPFailed{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $NTPFailed{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if (keys %DNSRefreshed) { print "\nDevice where DNS have been refreshed :\n"; foreach my $ThisOne (keys %DNSRefreshed) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (keys %{$DNSRefreshed{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $DNSRefreshed{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if (keys %DNSRefreshed) { print "\nDevice where DNS have been refreshed :\n"; foreach my $ThisOne (keys %DNSRefreshed) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (keys %{$DNSRefreshed{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $DNSRefreshed{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if ( ( $Detail >= 15 ) and (keys %PPPAccepted) ) { print "\nDevice where PPP is accepted :\n"; foreach my $ThisOne (keys %PPPAccepted) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (keys %{$PPPAccepted{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $PPPAccepted{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if ( ( $Detail >= 15 ) and (keys %PPTP1Down) ) { print "\nDevice where PPTP-1 is down :\n"; foreach my $ThisOne (keys %PPTP1Down) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (keys %{$PPTP1Down{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $PPTP1Down{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if ( ( $Detail >= 15 ) and (keys %PPTP2Down) ) { print "\nDevice where PPTP-2 is down :\n"; foreach my $ThisOne (keys %PPTP2Down) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (keys %{$PPTP2Down{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $PPTP2Down{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if (keys %SyslogFacility) { print "\nDevice where Syslog facility has been changed :\n"; foreach my $ThisOne (keys %SyslogFacility) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (keys %{$SyslogFacility{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $SyslogFacility{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if (keys %SyslogHost) { print "\nDevice where Syslog host has been changed :\n"; foreach my $ThisOne (keys %SyslogHost) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (keys %{$SyslogHost{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $SyslogHost{$ThisOne}{$ThisOne} . " Time(s)\n"; } } } if (keys %Restarted) { print "\nDevice restarted :\n"; foreach my $ThisOne (keys %Restarted) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (keys %{$Restarted{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $Restarted{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if (keys %ReloadRequested) { print "\nDevice reload requested :\n"; foreach my $ThisOne (keys %ReloadRequested) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (keys %{$ReloadRequested{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $ReloadRequested{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if (keys %PPPChannelUp) { print "\nVPN Up PPP Channel :\n"; foreach my $ThisOne (keys %PPPChannelUp) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (keys %{$PPPChannelUp{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $PPPChannelUp{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if (keys %PPTPIpDown) { print "\nVPN Down on :\n"; foreach my $ThisOne (keys %PPTPIpDown) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (keys %{$PPTPIpDown{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $PPTPIpDown{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if ( ( $Detail >= 15 ) and (keys %PPTPIpUp) ) { print "\nDevice where PPTP is UP :\n"; foreach my $ThisOne (keys %PPTPIpUp) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (keys %{$PPTPIpUp{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $PPTPIpUp{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if (keys %SysCfgSaved) { print "\nDevice where system config have been saved :\n"; foreach my $ThisOne (keys %SysCfgSaved) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (keys %{$SysCfgSaved{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $SysCfgSaved{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if (keys %BadLogins) { print "\nFailed logins from these:\n"; foreach my $ThisOne (keys %BadLogins) { print " " . $ThisOne . ":\n"; for (sort keys %{$BadLogins{$ThisOne}}) { print "\t $_: $BadLogins{$ThisOne}{$_} Time(s)\n"; } } } if (keys %IllegalUsers) { print "\nIllegal users from these:\n"; foreach my $ThisOne (keys %IllegalUsers) { print " " . $ThisOne . ":\n"; for (sort keys %{$IllegalUsers{$ThisOne}}) { print "\t $_: $IllegalUsers{$ThisOne}{$_} Time(s)\n"; } } } if (keys %Users) { print "\nUsers logging in through :\n"; foreach my $ThisOne (keys %Users) { print " " . $ThisOne . ":\n"; foreach my $user (sort {$a cmp $b} keys %{$Users{$ThisOne}}) { print " $user:\n"; my $totalSort = TotalCountOrder(%{$Users{$ThisOne}{$user}}, \&SortIP); foreach my $ip (sort $totalSort keys %{$Users{$ThisOne}{$user}}) { my $name = LookupIP($ip); if ($Detail >= 20) { print " $name:\n"; my $sort = CountOrder(%{$Users{$ThisOne}{$user}{$ip}}); foreach my $method (sort $sort keys %{$Users{$ThisOne}{$user}{$ip}}) { my $val = $Users{$ThisOne}{$user}{$ip}{$method}; my $plural = ($val > 1) ? "s" : ""; print " $method: $val time$plural\n"; } } else { my $val = (values %{$Users{$ThisOne}{$user}{$ip}})[0]; my $plural = ($val > 1) ? "s" : ""; print " $name: $val time$plural\n"; } } } } } if ($#OtherList >= 0) { print "\n**Unmatched Entries**\n"; print @OtherList; } exit(0); # vi: shiftwidth=3 tabstop=3 syntax=perl et # Local Variables: # mode: perl # perl-indent-level: 3 # indent-tabs-mode: nil # End: logwatch-7.12/scripts/services/yum0000664000211400021140000000571114274101045017516 0ustar logwatchlogwatch ######################################################## # Please file all bug reports, patches, and feature # requests under: # https://sourceforge.net/p/logwatch/_list/tickets # Help requests and discusion can be filed under: # https://sourceforge.net/p/logwatch/discussion/ ######################################################## ####################################################### ## Copyright (c) 2008 Sy Beamont ## Covered under the included MIT/X-Consortium License: ## http://www.opensource.org/licenses/mit-license.php ## All modifications and contributions by other persons to ## this script are assumed to have been donated to the ## Logwatch project and thus assume the above copyright ## and licensing terms. If you want to make contributions ## under your own copyright or a different license this ## must be explicitly stated in the contribution an the ## Logwatch project reserves the right to not accept such ## contributions. If you have made significant ## contributions to this script and want to claim ## copyright please contact logwatch-devel@lists.sourceforge.net. ######################################################### use strict; my $Debug = $ENV{'LOGWATCH_DEBUG'} || 0; my $DebugCounter = 0; #Init Array my @OtherList = (); #Init Hashes my ( %PackageUpdated, %PackageInstalled, %PackageDepInstalled, %PackageErased, ); if ( $Debug >= 5 ) { print STDERR "\n\nDEBUG: Inside YUM Filter \n\n"; $DebugCounter = 1; } while (defined(my $ThisLine = )) { if ( $Debug >= 5 ) { print STDERR "DEBUG($DebugCounter): $ThisLine"; $DebugCounter++; } if ( $ThisLine =~ s/^(?:\(yumex\) )?Updated: ([^ ]+)/$1/ ) { $PackageUpdated{$ThisLine}++; } elsif ( $ThisLine =~ s/^(?:\(yumex\) )?Installed: ([^ ]+)/$1/ ) { $PackageInstalled{$ThisLine}++; } elsif ( $ThisLine =~ s/^(?:\(yumex\) )?Dep Installed: ([^ ]+)/$1/ ) { $PackageDepInstalled{$ThisLine}++; } elsif ( $ThisLine =~ s/^(?:\(yumex\) )?Erased: ([^ ]+)/$1/ ) { $PackageErased{$ThisLine}++; } else { # Report any unmatched entries... push @OtherList,$ThisLine; } } if (keys %PackageInstalled) { print "\nPackages Installed:\n"; foreach my $ThisOne (keys %PackageInstalled) { print " " . $ThisOne; } } if (keys %PackageDepInstalled) { print "\nPackages (Dependency) Installed:\n"; foreach my $ThisOne (keys %PackageDepInstalled) { print " " . $ThisOne; } } if (keys %PackageUpdated) { print "\nPackages Updated:\n"; foreach my $ThisOne (keys %PackageUpdated) { print " ". $ThisOne; } } if (keys %PackageErased) { print "\nPackages Erased:\n"; foreach my $ThisOne (keys %PackageErased) { print " ". $ThisOne; } } if ($#OtherList >= 0) { print "\n**Unmatched Entries**\n"; print @OtherList; } exit(0); # vi: shiftwidth=3 tabstop=3 syntax=perl et # Local Variables: # mode: perl # perl-indent-level: 3 # indent-tabs-mode: nil # End: logwatch-7.12/scripts/services/qmail0000664000211400021140000001446314743365005020024 0ustar logwatchlogwatch ######################################################## # Please file all bug reports, patches, and feature # requests under: # https://sourceforge.net/p/logwatch/_list/tickets # Help requests and discusion can be filed under: # https://sourceforge.net/p/logwatch/discussion/ ######################################################## ####################################################### ## Copyright (c) 2008 Kirk Bauer ## Covered under the included MIT/X-Consortium License: ## http://www.opensource.org/licenses/mit-license.php ## All modifications and contributions by other persons to ## this script are assumed to have been donated to the ## Logwatch project and thus assume the above copyright ## and licensing terms. If you want to make contributions ## under your own copyright or a different license this ## must be explicitly stated in the contribution an the ## Logwatch project reserves the right to not accept such ## contributions. If you have made significant ## contributions to this script and want to claim ## copyright please contact logwatch-devel@lists.sourceforge.net. ######################################################### use strict; my $Detail = $ENV{'LOGWATCH_DETAIL_LEVEL'} || 0; my $QmailDetail = $ENV{'qmail_high_detail'}; my $QmailThreshold = $ENV{'threshold'}; my $RemoteThreshold = $ENV{'remote_threshold'}; my $LocalThreshold = $ENV{'local_threshold'}; my $FromThreshold = $ENV{'from_threshold'}; my $IgnoreUnmatched = $ENV{'qmail_ignore_unmatched'} || 0; #Init String Containers my ( $DeliveryResponse, $EmailFrom, $Response, $ResponseCode, $ServerResponseOverallTotal, $ServerResponses, $ToLocal, $ToRemote, $percentage, $threshold_reached, ); #Init Hashes my ( %From, %Local, %Remote, %ServerResponseTotal, ); #Init Array my @OtherList = (); while (defined(my $ThisLine = )) { if ( ( $ThisLine =~ /new msg/ ) or ( $ThisLine =~ /status: / ) or ( $ThisLine =~ /bounce msg/ ) or ( $ThisLine =~ /triple bounce/ ) or ( $ThisLine =~ /tcpserver/ ) or ( $ThisLine =~ /end msg/ ) ) { # We don't care about these } elsif ( ($DeliveryResponse,$Response) = ( $ThisLine =~ /delivery (?:\d+)\: (.*?)\:(.*)/ ) ) { if ( $Response =~ /did_/ ) { # ignore these. } else { if ( ($ResponseCode) = ( $Response =~ /Remote_host_said\:_(\d{3})_/ ) ) { $ServerResponses->{$DeliveryResponse}->{$ResponseCode}++; } else { if ( $DeliveryResponse =~ /failure/ ) { $ResponseCode=511; $ServerResponses->{$DeliveryResponse}->{$ResponseCode}++; } if ( $DeliveryResponse =~ /deferral/ ) { $ResponseCode=443; $ServerResponses->{$DeliveryResponse}->{$ResponseCode}++; } } } } elsif ( ($EmailFrom) = ( $ThisLine =~ /from \<(.*)\>/ ) ) { $From{$EmailFrom}++; } elsif ( ($ToLocal) = ( $ThisLine =~ /to local (.*)/ ) ) { $Local{$ToLocal}++; } elsif ( ($ToRemote) = ( $ThisLine =~ /to remote (.*)/ ) ) { $Remote{$ToRemote}++; } else { # Report any unmatched entries... push @OtherList,$ThisLine; } } if ($QmailDetail >= 1) { if ($QmailThreshold > 0) { if (($RemoteThreshold < 0) or ($RemoteThreshold eq '')) { $RemoteThreshold = $QmailThreshold; } if (($FromThreshold < 0) or ($FromThreshold eq '')) { $FromThreshold = $QmailThreshold; } if (($LocalThreshold < 0) or ($LocalThreshold eq '')) { $LocalThreshold = $QmailThreshold; } } if (($RemoteThreshold < 0) or ($RemoteThreshold eq '')) { $RemoteThreshold = 0; } if (($FromThreshold < 0) or ($FromThreshold eq '')) { $FromThreshold = 0; } if (($LocalThreshold < 0) or ($LocalThreshold eq '')) { $LocalThreshold = 0; } if ( (keys %From) ) { print "\nEmails from (Threshold of " . $FromThreshold . "):\n"; $threshold_reached=0; foreach my $Line (sort {$a cmp $b} keys %From) { if ($From{$Line} >= $FromThreshold) { $threshold_reached=1; print "\t" . $Line . " - ". $From{$Line} . " Time(s)\n"; } } if ($threshold_reached < 1) { print "\t" . "None found above the threshold\n"; } } if ( (keys %Remote) ) { print "\nEmails to Remote Server (Threshold of " . $RemoteThreshold . "):\n"; $threshold_reached=0; foreach my $Line (sort {$a cmp $b} keys %Remote) { if ($Remote{$Line} >= $RemoteThreshold) { $threshold_reached=1; print "\t" . $Line . " - ". $Remote{$Line} . " Time(s)\n"; } } if ($threshold_reached < 1) { print "\t" . "None found above the threshold\n"; } } if ( (keys %Local) ) { print "\nEmails to Local Server (Threshold of " . $LocalThreshold . "):\n"; $threshold_reached=0; foreach my $Line (sort {$a cmp $b} keys %Local) { if ($Local{$Line} >= $LocalThreshold) { $threshold_reached=1; print "\t" . $Line . " - ". $Local{$Line} . " Time(s)\n"; } } if ($threshold_reached < 1) { print "\t" . "None found above the threshold\n"; } } } if (keys %{$ServerResponses}) { print "\nRemote Server Responses:\n"; foreach my $Line (sort {$a cmp $b} keys %{$ServerResponses}) { foreach my $Detail (sort {$a cmp $b} keys %{$ServerResponses->{$Line}}) { $ServerResponseTotal{$Line} += $ServerResponses->{$Line}->{$Detail}; $ServerResponseOverallTotal += $ServerResponses->{$Line}->{$Detail}; print "\t".ucfirst($Line)."(" . $Detail . ") - ". $ServerResponses->{$Line}->{$Detail} . " Time(s)\n"; } } print "\n\tPercentage(s):\n"; foreach my $Details (sort {$a cmp $b} keys %ServerResponseTotal) { $percentage = (($ServerResponseTotal{$Details} / $ServerResponseOverallTotal) * 100); print "\t\t" . ucfirst($Details) . " - "; printf("%.2f",$percentage); print " %\n"; } } if (($#OtherList >= 0) and (not $IgnoreUnmatched)){ print "\n**Unmatched Entries**\n"; print @OtherList; } exit(0); # vi: shiftwidth=3 tabstop=3 syntax=perl et # Local Variables: # mode: perl # perl-indent-level: 3 # indent-tabs-mode: nil # End: logwatch-7.12/scripts/services/rsyslogd0000664000211400021140000001651514743365005020567 0ustar logwatchlogwatch ######################################################## # Please file all bug reports, patches, and feature # requests under: # https://sourceforge.net/p/logwatch/_list/tickets # Help requests and discusion can be filed under: # https://sourceforge.net/p/logwatch/discussion/ ######################################################## ####################################################### ## Copyright (c) 2013 Teemu Ikonen ## Copyright (c) 2019 Orion Poplawski ## Covered under the included MIT/X-Consortium License: ## http://www.opensource.org/licenses/mit-license.php ## All modifications and contributions by other persons to ## this script are assumed to have been donated to the ## Logwatch project and thus assume the above copyright ## and licensing terms. If you want to make contributions ## under your own copyright or a different license this ## must be explicitly stated in the contribution an the ## Logwatch project reserves the right to not accept such ## contributions. If you have made significant ## contributions to this script and want to claim ## copyright please contact logwatch-devel@lists.sourceforge.net. ######################################################### use strict; my $Detail = $ENV{'LOGWATCH_DETAIL_LEVEL'} || 0; my %IgnoreActions; if (defined($ENV{'rsyslogd_ignore_actions'})) { foreach my $action (split(";",$ENV{'rsyslogd_ignore_actions'})) { $IgnoreActions{$action} = 1; } } my %IgnoreMessages; if (defined($ENV{'rsyslogd_ignore_messages'})) { foreach my $message (split(";",$ENV{'rsyslogd_ignore_messages'})) { $IgnoreMessages{$message} = 1; } } my %IgnoreModules; if (defined($ENV{'rsyslogd_ignore_modules'})) { foreach my $module (split(";",$ENV{'rsyslogd_ignore_modules'})) { $IgnoreModules{$module} = 1; } } my $RemoteClosedThreshold = $ENV{'rsyslogd_remote_closed_threshold'} || 0; #Init String Containers my $Action; my $Certificate; my $Host; my $LastError; my $Message; my $MessagesLost = 0; my $Module; my $Num; my $Reason; #Init Hashes my %ActionResumed; my %ActionSuspended; my %CannotConnect; my %ClosedError; my %DaemonActions; my %InvalidCertificate; my %InvalidCerts; my %OtherList; my %RemoteClosed; LINE: while (defined(my $ThisLine = )) { chomp($ThisLine); # Handle stdout/stderr sent to journal which ends up with an extra prefix $ThisLine =~ s/^rsyslogd: //; foreach $Message (keys %IgnoreMessages) { next LINE if $ThisLine =~ /$Message/i; } if (($Reason) = ($ThisLine =~ /^ ?\[origin software=\"rsyslogd\" .*\] (.*)/)) { $DaemonActions{$Reason}++; } elsif (($Action, $Module) = $ThisLine =~ /action '(.*)' suspended(?: \(module '(.*)'\))?/) { if (defined $Module) { $ActionSuspended{"$Action ($Module)"}++ unless defined $IgnoreActions{$Action} or defined $IgnoreModules{$Module}; } else { $ActionSuspended{$Action}++ unless defined $IgnoreActions{$Action}; } } elsif (($Action, $Module) = $ThisLine =~ /action '(.*)' resumed \(module '(.*)'\)/) { $ActionResumed{"$Action ($Module)"}++ unless defined $IgnoreActions{$Action} or defined $IgnoreModules{$Module}; } elsif (($Certificate) = $ThisLine =~ /invalid cert info: peer provided \d+ certificate\(s\)\. Certificate \d+ info: (.*); \[/) { $InvalidCertificate{$Certificate}++; } elsif (($Host, $Reason) = $ThisLine =~ /cannot connect to (.+): (.+) \[/) { $CannotConnect{"$Host ($Reason)"}++; } # These should also generate closed connection messages, but record so we can ignore normal events elsif( $ThisLine =~ /(TCPSendBuf error .*), destruct TCP Connection to/ or $ThisLine =~ /(GnuTLS handshake retry returned error:[^.]*)/ or # This proceeds unexpected GnuTLS error -54 $ThisLine =~ /(gnutls returned error on handshake:[^.]*)/ or $ThisLine =~ /(peer did not provide a certificate[^[]*)/ or $ThisLine =~ /(unexpected GnuTLS error -\d+)/ ) { $LastError = $1; } elsif (($Host) = $ThisLine =~ /^netstream session \S+ from (\S+) will be closed due to error/) { $ClosedError{$LastError}{"$Host"}++ if $LastError !~ /unexpected GnuTLS error -54/; } elsif (($Host) = $ThisLine =~ /^omfwd: remote server at (.+) seems to have closed connection/) { $RemoteClosed{"$Host"}++; } elsif (($Num) = $ThisLine =~ /(\d+) messages lost due to rate-limiting/) { $MessagesLost += $Num; } elsif ( # More detail for this in the invalid cert info line above $ThisLine =~ /^not permitted to talk to peer, certificate invalid:/ or $ThisLine =~ /^rsyslogd\'s (groupid|userid) changed to/ or $ThisLine =~ /^imjournal: journal files changed, reloading/ or $ThisLine =~ /^imjournal: journal reloaded/ or $ThisLine =~ /^imuxsock: Acquired UNIX socket .* from systemd/ or $ThisLine =~ /^message repeated \d+ times:/ or $ThisLine =~ m!^imuxsock: Acquired UNIX socket '/run/systemd/journal/syslog' \(fd 3\) from systemd! or 0 # This line prevents blame shifting as lines are added above ) { # Ignore these lines } else { # Report any unmatched entries... $OtherList{$ThisLine}++; } } if (keys %ActionSuspended) { print "Rsyslogd actions suspended:\n"; foreach my $Action (sort keys %ActionSuspended) { print " $Action: $ActionSuspended{$Action} Times\n"; } print "\n"; } if (keys %ActionResumed) { print "Rsyslogd actions resumed\n"; foreach my $Action (sort keys %ActionResumed) { print " $Action: $ActionResumed{$Action} Times\n"; } print "\n"; } if (keys %CannotConnect) { print "Cannot connect:\n"; foreach my $Item (sort keys %CannotConnect) { print " $Item: $CannotConnect{$Item} Times\n"; } print "\n"; } if (keys %InvalidCertificate) { print "Invalid certificates:\n"; foreach my $Certificate (sort keys %InvalidCertificate) { print " $Certificate: $InvalidCertificate{$Certificate} Times\n"; } print "\n"; } if ($MessagesLost) { print "$MessagesLost Messages lost due to rate-limiting\n\n"; } if (keys %ClosedError) { print "Connection closed due to error:\n"; foreach my $Error (sort keys %ClosedError) { print " $Error:\n"; foreach my $Host (sort keys %{$ClosedError{$Error}}) { print " $Host: $ClosedError{$Error}{$Host} Times\n"; } } print "\n"; } if (keys %RemoteClosed) { my $first = 1; foreach my $Host (sort keys %RemoteClosed) { if ($RemoteClosed{$Host} >= $RemoteClosedThreshold) { if ($first) { print "Remote closed connection:"; print " (with threshold >= $RemoteClosedThreshold)" if $RemoteClosedThreshold; print "\n"; $first = 0; } print " $Host: $RemoteClosed{$Host} Times\n"; } } print "\n"; } if (($Detail >=10) and (keys %DaemonActions) ) { print "Rsyslogd Actions:\n"; foreach $Reason (sort keys %DaemonActions) { print " $Reason: $DaemonActions{$Reason} Times\n"; } print "\n"; } if (keys %OtherList) { print "**** Unmatched entries ****\n"; foreach my $Error (keys %OtherList) { print " $Error : $OtherList{$Error} Times\n"; } } exit(0); # vi: shiftwidth=3 tabstop=3 syntax=perl et # Local Variables: # mode: perl # perl-indent-level: 3 # indent-tabs-mode: nil # End: logwatch-7.12/scripts/services/sssd0000664000211400021140000001456414743365005017677 0ustar logwatchlogwatch ######################################################## # Please file all bug reports, patches, and feature # requests under: # https://sourceforge.net/p/logwatch/_list/tickets # Help requests and discusion can be filed under: # https://sourceforge.net/p/logwatch/discussion/ ######################################################## ######################################################## ## Copyright (c) 2014 Orion Poplawski ## Covered under the included MIT/X-Consortium License: ## http://www.opensource.org/licenses/mit-license.php ## All modifications and contributions by other persons to ## this script are assumed to have been donated to the ## Logwatch project and thus assume the above copyright ## and licensing terms. If you want to make contributions ## under your own copyright or a different license this ## must be explicitly stated in the contribution an the ## Logwatch project reserves the right to not accept such ## contributions. If you have made significant ## contributions to this script and want to claim ## copyright please contact logwatch-devel@lists.sourceforge.net. ######################################################### use strict; my $Detail = $ENV{'LOGWATCH_DETAIL_LEVEL'} || 0; my $IgnoreBackendStatus = $ENV{'ignore_backend_status'} || 0; my $IgnoreEnumerationRequested = $ENV{'ignore_enumeration_requested'} || 0; my $OfflineOkay = $ENV{'offline_okay'} || 0; my %CannotContactKDC; my $Domain; my %Errors; my $Realm; my $Service; my %Starts; my %Stops; my %OtherList; my %BackendStatus; my %BackendOffline; my $EnumerationRequested = 0; my $ignore_p11_child_error = 0; # Lines are of the form: # sssd[service]: while (defined(my $ThisLine = )) { next unless $ThisLine =~ /^sssd/; chomp($ThisLine); # Default service, domain $Service = "Daemon"; $Domain = "unknown"; # Strip off pid: $ThisLine =~ s/\[\d+\]: /: /; # Strip off and record the service if any if ($ThisLine =~ s/^sssd\[([^]]+)(?:\[\d+\])?\]: // or $ThisLine =~ s/^sssd_([^:[]+): //) { $Service = ($1 eq "be") ? "Backend[$Domain]" : $1; } # Strip off and record the backend domain if any if ($ThisLine =~ s/^sssd\[be\[([^]]+)\](?:\[\d+\])?\]: //) { $Service = "Backend[$1]"; $Domain = $1; } # Strip off leading sssd: $ThisLine =~ s/^sssd: //; # Strip off duplicate timestamp if present $ThisLine =~ s/^\(... ... .\d \d\d:\d\d:\d\d \d\d\d\d\) //; # Remove []s from debug messages if any $ThisLine =~ s/^\[(\S+)\] /$1 /; $ThisLine =~ s/^\[(\S+)\] /$1 /; # Remove pids from debug messages if any $ThisLine =~ s/\[\d+\]//; # Ignore debug messages my ($debuglevel) = ($ThisLine =~ /\s\((0x[0-9a-f]{4})\):\s/); next if defined($debuglevel) && hex($debuglevel) > 16; if ($ThisLine =~ /Starting up/) { $Starts{$Service}++; } elsif ($ThisLine =~ /^Shutting down/) { $Stops{$Service}++; } elsif ($ThisLine =~ /error/i) { $Errors{$Service}->{$ThisLine}++; } elsif (my ($status) = ($ThisLine =~ /Backend is (.*)/)) { $BackendStatus{$Domain} = $status; $BackendOffline{$Domain}++ if $BackendStatus{$Domain} eq "offline"; } elsif ($ThisLine =~ /^Enumeration requested but not enabled/) { $EnumerationRequested++ unless $IgnoreEnumerationRequested; } elsif ($Service eq "Daemon" && $ThisLine =~ /exec_child_ex command:/) { # Ignore - https://github.com/SSSD/sssd/issues/7778 } elsif ($Service eq "Daemon" && $ThisLine =~ /Keytab successfully retrieved and stored in:/) { # Ignore } elsif ($Service eq "krb5_child" && ( $ThisLine =~ "Preauthentication failed" or $ThisLine =~ "Client's credentials have been revoked")) { # Ignore - these will generate a pam auth failed message } elsif ($Service eq "p11_child" && $ThisLine =~ /Certificate .* not valid .*Certificate key usage inadequate for attempted operation/) { # sssd ssh does not ignore certificates of different types - ignore the errors generated by it $ignore_p11_child_error = 1; } elsif ($Service eq "p11_child" && $ThisLine =~ /do_work failed/ && $ignore_p11_child_error) { } elsif ($Service eq "p11_child" && $ThisLine =~ /p11_child failed/ && $ignore_p11_child_error) { $ignore_p11_child_error = 0; } elsif (($Realm) = ($ThisLine =~ /Cannot contact any KDC for realm '(.*)'/)) { $CannotContactKDC{$Realm}++ unless $OfflineOkay; } else { $OtherList{$Service}{$ThisLine}++; } } if (keys %Errors) { print "\nSSSD ERRORS:\n"; foreach my $Service (sort {$a cmp $b} keys %Errors) { print " $Service:\n"; foreach my $Error (sort {$a cmp $b} keys %{$Errors{$Service}}) { print " $Error: " . $Errors{$Service}->{$Error} . " Time(s)\n"; } } } # sssd will generally start in offline mode, so don't alert if we've just started up foreach $Domain (keys(%BackendOffline)) { if ($BackendOffline{$Domain} and (($Starts{"Backend[$Domain]"} < $BackendOffline{$Domain}) or ($BackendStatus{$Domain} ne "online")) and not $IgnoreBackendStatus) { print "\nSSSD Backend $Domain went offline $BackendOffline{$Domain} Time(s),"; print " and started " . $Starts{"Backend[$Domain]"} . " Time(s),"; print " last status was $BackendStatus{$Domain}\n"; } } if (keys %CannotContactKDC) { print "\nCannot contact any KDC for realm:\n"; foreach my $Realm (sort {$a cmp $b} keys %CannotContactKDC) { print " $Realm: " . $CannotContactKDC{$Realm} . " Time(s)\n"; } } if (keys %Starts and $Detail) { print "\nSSSD Services Started:\n"; foreach my $Service (sort {$a cmp $b} keys %Starts) { print " $Service: " . $Starts{$Service} . " Time(s)\n"; } } if (keys %Stops and $Detail) { print "\nSSSD Services Stopped:\n"; foreach my $Service (sort {$a cmp $b} keys %Stops) { print " $Service: " . $Stops{$Service} . " Time(s)\n"; } } if ($EnumerationRequested) { print "\nEnumeration requested but not enabled: $EnumerationRequested Time(s)\n"; } if (keys %OtherList) { print "\n\n**Unmatched Entries**\n"; foreach my $service (sort {$a cmp $b} keys %OtherList) { print " $service:\n"; foreach my $line (sort {$a cmp $b} keys %{$OtherList{$service}}) { print " $line: $OtherList{$service}{$line} Time(s)\n"; } } } exit(0); # vi: shiftwidth=3 tabstop=3 syntax=perl et # Local Variables: # mode: perl # perl-indent-level: 3 # indent-tabs-mode: nil # End: logwatch-7.12/scripts/services/dnssec0000664000211400021140000001204214274101035020155 0ustar logwatchlogwatch ######################################################## # Please file all bug reports, patches, and feature # requests under: # https://sourceforge.net/p/logwatch/_list/tickets # Help requests and discusion can be filed under: # https://sourceforge.net/p/logwatch/discussion/ ######################################################## ############################################################################# #Copyright (c) 2004, Sparta, Inc #All rights reserved. # #Redistribution and use in source and binary forms, with or without #modification, are permitted provided that the following conditions are met: # #* Redistributions of source code must retain the above copyright notice, # this list of conditions and the following disclaimer. # #* Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # #* Neither the name of Sparta, Inc nor the names of its contributors may # be used to endorse or promote products derived from this software # without specific prior written permission. # #THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS #IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, #THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR #PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR #CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, #EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, #PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; #OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, #WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR #OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF #ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ############################################################################# ############################################################################# # These scripts were created as part of the dnssec-tools project. # For more information, see http://sourceforge.net/dnssec-tools. # Detailed instructions for setting up BIND 9.3.* to use these logwatch # configuration files and scripts are contained in the README file # on sourceforge. ############################################################################# use strict; my $detail = $ENV{'LOGWATCH_DETAIL_LEVEL'} || 0; my $valFail; my $valOK; my $attPosRespVal; my $attNegRespVal; my $attInsecurityProof; my $insecurityProofFail; my $rdataFail; my $rdataSuccess; my $markingAsSecure; my $nonExtProof; my $noValidSig; while (defined(my $ThisLine = )) { if ($ThisLine =~ /validation failed/) { $valFail++; } elsif ($ThisLine =~ /validation OK/) { $valOK++; } elsif ($ThisLine =~ /attempting positive response validation/) { $attPosRespVal++; } elsif ($ThisLine =~ /attempting negative response validation/) { $attNegRespVal++; } elsif ($ThisLine =~ /attempting insecurity proof/) { $attInsecurityProof++; } elsif ($ThisLine =~ /insecurity proof failed/) { $insecurityProofFail++; } elsif ($ThisLine =~ /verify rdataset: RRSIG failed to verify/) { $rdataFail++; } elsif ($ThisLine =~ /verify rdataset: success/) { $rdataSuccess++; } elsif ($ThisLine =~ /marking as/) { $markingAsSecure++; } elsif ($ThisLine =~ /nonexistence proof found/) { $nonExtProof++; } elsif ($ThisLine =~ /no valid signature found/) { $noValidSig++; } } if ($noValidSig > 0) { print "No Valid Signature received " . $noValidSig . " time(s)\n"; } my %msgHash = (); if ($detail >= 5) { print "\nDetail >= 5 log messages:\n"; if ($markingAsSecure > 0) { $msgHash{"Marking as secure"} = $markingAsSecure; } if ($rdataSuccess > 0) { $msgHash{"Verified rdataset succeeded"} = $rdataSuccess; } if ($rdataFail > 0) { $msgHash{"Verified rdataset failed"} = $rdataFail; } if ($insecurityProofFail > 0) { $msgHash{"Insecurity proof failed"} = $insecurityProofFail; } if ($attInsecurityProof > 0) { $msgHash{"Insecurity proof attempted"} = $attInsecurityProof; } if ($valFail > 0) { $msgHash{"Validation failed"} = $valFail; } if ($valOK > 0) { $msgHash{"Validation OK"} = $valOK; } if ($attPosRespVal > 0) { $msgHash{"Attempted positive response validation"} = $attPosRespVal; } if ($attNegRespVal > 0) { $msgHash{"Attempted negative response validation"} = $attNegRespVal; } if ($nonExtProof > 0) { $msgHash{"Nonexistence proof found"} = $nonExtProof; } # sort all the non-zero message types and print them in descending order # of number of occurrences my $key; foreach $key (sort { $msgHash{$b} <=> $msgHash{$a} } keys %msgHash) { print " " . $key . " " . $msgHash{$key} . " time(s)\n"; } } exit (0); # vi: shiftwidth=3 tabstop=3 et # Local Variables: # mode: perl # perl-indent-level: 3 # indent-tabs-mode: nil # End: logwatch-7.12/scripts/services/barracuda0000664000211400021140000003132614274101034020627 0ustar logwatchlogwatch ######################################################## # Please file all bug reports, patches, and feature # requests under: # https://sourceforge.net/p/logwatch/_list/tickets # Help requests and discusion can be filed under: # https://sourceforge.net/p/logwatch/discussion/ ######################################################## ########################################################################## # # Barracuda Spam Firewall parser # Written by Hugo van der Kooij (HvdK) # Based on existing code of logwatch and the documentation on: # http://www.barracudanetworks.com/ns/downloads/BarracudaSyslog.pdf # ######################################################## ## Copyright (c) 2008 Hugo van der Kooij ## Covered under the included MIT/X-Consortium License: ## http://www.opensource.org/licenses/mit-license.php ## All modifications and contributions by other persons to ## this script are assumed to have been donated to the ## Logwatch project and thus assume the above copyright ## and licensing terms. If you want to make contributions ## under your own copyright or a different license this ## must be explicitly stated in the contribution an the ## Logwatch project reserves the right to not accept such ## contributions. If you have made significant ## contributions to this script and want to claim ## copyright please contact logwatch-devel@lists.sourceforge.net. ######################################################### use strict; my $Detail = $ENV{'LOGWATCH_DETAIL_LEVEL'} || 0; my $Debug = $ENV{'LOGWATCH_DEBUG'} || 0; sub Round { my $input = $_[0]; my $digits = $_[1]; my $factor = (10**$digits); my $result = (int( ($input * $factor) + .5) / $factor); return $result; } #Init String Containers my ( $RECVtime, $SCANsize, $SCANtime, $delivery, $reason, $size, $time ); #Init Array my @RSaction = (); my @Saction = (); my @Reason = (); my @OtherList = (); #Init Hashes my ( %RECVReason, %RECVReasons, %RECVaction, %RECVreason, %RECVtime_div, %RECVtime_max, %RECVtime_min, %RECVtime_total, %SCANReason, %SCANReasons, %SCANaction, %SCANreason, %SCANsize_div, %SCANsize_total, %SCANtime_div, %SCANtime_max, %SCANtime_min, %SCANtime_total, %SENDaction, %SENDreason, %SENDresponse, %score_div, %score_max, %score_min, %score_total ); # Text messages for the RECV and SCAN action codes: $RSaction[0] = "Allowed Message(s)"; $RSaction[1] = "Aborted Message(s)"; $RSaction[2] = "Blocked Message(s)"; $RSaction[3] = "Quarantined Message(s)"; $RSaction[4] = "Tagged Message(s)"; $RSaction[5] = "Deferred Message(s)"; $RSaction[6] = "Per-User Quarantined Message(s)"; $RSaction[7] = "Whitelisted Message(s)"; # Text messages for the SEND action codes: $Saction[0] = "UNKNOWN"; $Saction[1] = "Delivered Message(s)"; $Saction[2] = "Rejected Message(s)"; $Saction[3] = "Deferred Message(s)"; $Saction[4] = "Expired Message(s)"; # Text messages for the reason codes: $Reason[0] = "Allowed"; $Reason[1] = "Virus detected"; $Reason[2] = "Banned attachment"; $Reason[3] = "RBL Match"; $Reason[4] = "Rate Control"; $Reason[5] = "Too Many Message(s) In Session"; $Reason[6] = "Timeout Exceeded"; $Reason[7] = "No such Domain"; $Reason[8] = "No such User"; $Reason[9] = "Subject Filter Match"; $Reason[10] = "UNKNOWN (10)"; $Reason[11] = "Client IP"; $Reason[12] = "Recipient Address Rejected"; $Reason[13] = "No valid Recipients"; $Reason[14] = "Domain Not Found"; $Reason[15] = "Sender Address Rejected"; $Reason[16] = "UNKNOWN (16)"; $Reason[17] = "Need Fully Qualified Recipient"; $Reason[18] = "Need Fully Qualified Sender"; $Reason[19] = "Unsupported Command"; $Reason[20] = "MAIL FROM Syntax Error"; $Reason[21] = "Bad Address Syntax"; $Reason[22] = "RCPT TO Syntax Error"; $Reason[23] = "Send EHLO/HELO First"; $Reason[24] = "Need MAIL Command"; $Reason[25] = "Nested MAIL Command"; $Reason[26] = "UNKNOWN (26)"; $Reason[27] = "EHLO/HELO Syntax Error"; $Reason[28] = "UNKNOWN (28)"; $Reason[29] = "UNKNOWN (29)"; $Reason[30] = "Mail Protocol Error"; $Reason[31] = "Score"; $Reason[32] = "UNKNOWN (32)"; $Reason[33] = "UNKNOWN (33)"; $Reason[34] = "Header Filter Match"; $Reason[35] = "Sender Block/Accept"; $Reason[36] = "Recipient Block/Accept"; $Reason[37] = "Body Filter Match"; $Reason[38] = "Message Size Bypass"; $Reason[39] = "Intention Analysis Match"; $Reason[40] = "SPF/Caller-ID"; $Reason[41] = "Client Host Rejected"; $Reason[42] = "UNKNOWN (42)"; $Reason[43] = "UNKNOWN (43)"; $Reason[44] = "Authentication Not Enabled"; $Reason[45] = "Allowed Message Size Exceeded"; $Reason[46] = "Too Many Recipients"; $Reason[47] = "Need RCPT Command"; $Reason[48] = "DATA Syntax Error"; $Reason[49] = "Internal Error"; $Reason[50] = "Too Many Hops"; $Reason[51] = "UNKNOWN (51)"; $Reason[52] = "UNKNOWN (52)"; $Reason[53] = "UNKNOWN (53)"; $Reason[54] = "UNKNOWN (54)"; $Reason[55] = "Invalid Parameter Syntax"; $Reason[56] = "STARTTLS Syntax Error"; $Reason[57] = "TLS Already Active"; $Reason[58] = "Too Many Errors"; $Reason[59] = "Need STARTTLS First"; $Reason[60] = "Spam Fingerprint Found"; while (defined(my $ThisLine = )) { if ( my ($address, $start_time, $end_time, $type, $info) = ($ThisLine =~ /([^\s]+)\s(?:[^\s]+)\s(\d+)\s(\d+)\s(RECV|SCAN|SEND)\s(.*)$/) ) { # ip variable not used # ($ip) = ($address =~ /\[(.*)\]/); $time = ($end_time - $start_time); if ( $type =~ /RECV/ ) { if ( my ($sender, $recipient, $action, $reason, $reason_extra) = ($info =~ /([^\s]+)\s([^\s]+)\s(\d+)\s(\d+)\s(.*)$/) ) { $RECVaction{$action}++; $RECVreason{$reason}++; if ( ($reason_extra =~ /^-[| ]$/) or ($reason < 1) ) { } else { $RECVReasons{$reason_extra}++; $RECVReason{$reason_extra} = $reason; } $RECVtime_total{$action} = ($RECVtime_total{$action} + $time); $RECVtime_div{$action}++; if ($time < $RECVtime_min{$action}) { $RECVtime_min{$action} = $time; } elsif ($RECVtime_min{$action} eq "") { $RECVtime_min{$action} = $time; } if ($time > $RECVtime_max{$action}) { $RECVtime_max{$action} = $time; } elsif ($RECVtime_max{$action} eq "") { $RECVtime_max{$action} = $time; } } else { push @OtherList,$ThisLine; } } elsif ( $type =~ /SCAN/ ) { if ( my ($enc, $sender, $recipient, $score, $action, $reason, $reason_extra) = ($info =~ /([^\s]+)\s([^\s]+)\s([^\s]+)\s([-\.\d+]+)\s(\d+)\s(\d+)\s(.*)\sSUBJ:(?:.*)$/) ) { if ( ($size) = ($reason_extra =~ /\sSZ:(\d+)$/) ) { $reason_extra =~ s/\sSZ:(\d+)$//; $SCANsize_total{$action} = ($SCANsize_total{$action} + $size); $SCANsize_div{$action}++; } $SCANaction{$action}++; $SCANreason{$reason}++; if ($score =~ /^-$/) { } else { $score_total{$action} = ($score_total{$action} + $score); $score_div{$action}++; if ($score < $score_min{$action}) { $score_min{$action} = $score; } elsif ($score_min{$action} eq "") { $score_min{$action} = $score; } if ($score > $score_max{$action}) { $score_max{$action} = $score; } elsif ($score_max{$action} eq "") { $score_max{$action} = $score; } } if ($reason_extra =~ /^-$/) { } else { $SCANReasons{$reason_extra}++; $SCANReason{$reason_extra} = $reason; } $SCANtime_total{$action} = ($SCANtime_total{$action} + $time); $SCANtime_div{$action}++; if ($time < $SCANtime_min{$action}) { $SCANtime_min{$action} = $time; } elsif ($SCANtime_min{$action} eq "") { $SCANtime_min{$action} = $time; } if ($time > $SCANtime_max{$action}) { $SCANtime_max{$action} = $time; } elsif ($SCANtime_max{$action} eq "") { $SCANtime_max{$action} = $time; } } else { push @OtherList,$ThisLine; } } elsif ( $type =~ /SEND/ ) { if ( my ($enc, $action, $response) = ($info =~ /([^\s]+)\s(\d+)\s(?:[^\s]+)\s(.*)$/) ) { $SENDaction{$action}++; if (($delivery) = ($response =~/^(\d+)\s.*/) ) { $SENDresponse{$delivery}++; } } else { push @OtherList,$ThisLine; } } else { push @OtherList,$ThisLine; } } elsif ( $ThisLine =~ /\s(RECV|SCAN|SEND)\s/) { push @OtherList,$ThisLine; } } ################################################################## if ($#OtherList >= 0) { print "\n\n**Unmatched Entries**\n\n"; print @OtherList; } if (keys %RECVaction) { print "\nReceive actions:\n"; foreach my $action (sort {$a cmp $b} keys %RECVaction) { print ' ' . $RSaction[$action] . ": ". $RECVaction{$action} . "\n"; } } if (keys %SCANaction) { print "\nScanning actions:\n"; foreach my $action (sort {$a cmp $b} keys %SCANaction) { print ' ' . $RSaction[$action] . ": ". $SCANaction{$action} . "\n"; } } if (keys %SENDaction) { print "\nSending actions:\n"; foreach my $action (sort {$a cmp $b} keys %SENDaction) { print ' ' . $Saction[$action] . ": ". $SENDaction{$action} . "\n"; } } if (keys %RECVreason) { print "\nBlocked incoming messages:\n"; foreach my $reason (sort {$a cmp $b} keys %RECVreason) { if ($reason > 0) { print ' ' . $Reason[$reason] . " : ". $RECVreason{$reason} . "\n"; } } } if ( ($Detail >= 10) and (keys %RECVReasons) ) { print "\nDetails of blocked incoming messages :\n"; foreach my $reason (sort {$a cmp $b} keys %RECVReasons) { print ' ' . $Reason[$RECVReason{$reason}] . " : " . $reason . " : ". $RECVReasons{$reason} . "\n"; } } if (keys %RECVtime_total) { print "\nReceive timing:\n"; foreach my $action (sort {$a cmp $b} keys %RECVtime_total) { $RECVtime = ($RECVtime_total{$action} / $RECVtime_div{$action}); print ' ' . $RSaction[$action] . " :\n"; print "\tMinimum : " . $RECVtime_min{$action} . "\n"; print "\tAverage : " . Round($RECVtime, 1) . "\n"; print "\tMaximum : " . $RECVtime_max{$action} . "\n"; } } if (keys %SCANreason) { print "\nDecisions while scanning:\n"; foreach my $reason (sort {$a cmp $b} keys %SCANreason) { print ' ' . $Reason[$reason] . " : ". $SCANreason{$reason} . "\n"; } } if ( ($Detail >= 10) and (keys %SCANReasons) ) { print "\nDetails of decisions while scanning:\n"; foreach $reason (sort {$a cmp $b} keys %SCANReasons) { print ' ' . $Reason[$SCANReason{$reason}] . " : " . $reason . " : ". $SCANReasons{$reason} . "\n"; } } if (keys %SCANtime_total) { print "\nScan timing:\n"; foreach my $action (sort {$a cmp $b} keys %SCANtime_total) { $SCANtime = ($SCANtime_total{$action} / $SCANtime_div{$action}); print ' ' . $RSaction[$action] . " :\n"; print "\tMinimum : " . $SCANtime_min{$action} . "\n"; print "\tAverage : " . Round($SCANtime, 1) . "\n"; print "\tMaximum : " . $SCANtime_max{$action} . "\n"; } } if (keys %SCANsize_total) { print "\nMessage sizes:\n"; foreach my $action (sort {$a cmp $b} keys %SCANsize_total) { $SCANsize = ($SCANsize_total{$action} / $SCANsize_div{$action}); print ' ' . $RSaction[$action] . " :\n"; # print "\tMinimum : " . $SCANsize_min{$action} . "\n"; print "\tAverage : " . Round($SCANsize, 0) . "\n"; # print "\tMaximum : " . $SCANsize_max{$action} . "\n"; } } if (keys %SENDreason) { print "\nSending reasons:\n"; foreach my $reason (sort {$a cmp $b} keys %SENDreason) { print ' ' . $Reason[$reason] . " : ". $SENDreason{$reason} . "\n"; } } if (keys %SENDresponse) { print "\nSending responses:\n"; foreach my $response (sort {$a cmp $b} keys %SENDresponse) { print ' ' . $response . ": ". $SENDresponse{$response} . "\n"; } } if (keys %score_total) { print "\nScores:\n"; foreach my $action (sort {$a cmp $b} keys %score_total) { my $score = ($score_total{$action} / $score_div{$action}); print ' ' . $RSaction[$action] . " :\n"; print "\tMinimum : " . $score_min{$action} . "\n"; print "\tAverage : " . Round($score, 3) . "\n"; print "\tMaximum : " . $score_max{$action} . "\n"; } } exit(0); # vi: shiftwidth=3 tabstop=3 syntax=perl et # Local Variables: # mode: perl # perl-indent-level: 3 # indent-tabs-mode: nil # End: logwatch-7.12/scripts/services/mysql-mmm0000664000211400021140000001210614743365004020641 0ustar logwatchlogwatch ######################################################## # Please file all bug reports, patches, and feature # requests under: # https://sourceforge.net/p/logwatch/_list/tickets # and copy: # Stefan Jakobs # Help requests and discusion can be filed under: # https://sourceforge.net/p/logwatch/discussion/ ######################################################## ########################################################################### # This was written and is maintained by: # Stefan Jakobs # # Please send all comments, suggestions, bug reports, # etc, to logwatch at localside.net. ########################################################################### # Copyright (c) 2013 Stefan Jakobs # Covered under the included MIT/X-Consortium License: # http://www.opensource.org/licenses/mit-license.php # All modifications and contributions by other persons to # this script are assumed to have been donated to the # Logwatch project and thus assume the above copyright # and licensing terms. If you want to make contributions # under your own copyright or a different license this # must be explicitly stated in the contribution and the # Logwatch project reserves the right to not accept such # contributions. If you have made significant # contributions to this script and want to claim # copyright please contact logwatch-devel@lists.sourceforge.net. ########################################################################### use strict; my $Detail = $ENV{'LOGWATCH_DETAIL_LEVEL'} || 0; my $Version = 0.1; # initialize logwatch variables my $ThisLine = ""; my %OtherList = (); # initialize variables which save the stats my (%fatal, %info, %warn); my (%mon_fatal, %mon_error); ### Parse the lines ### while (defined($ThisLine = )) { chomp($ThisLine); $ThisLine =~ s/^\d{4}\/\d\d\/\d\d \d\d:\d\d:\d\d *//; if ( ($ThisLine =~ /^INFO We have some new roles added or old rules deleted!$/) or ($ThisLine =~ /^INFO END$/) ) { # ignore } elsif ($ThisLine =~ /^FATAL State of host '(\S+)' changed from (\S+) to (\S+)(?: .* for (?:only )?(\d+) seconds)?/) { my $sec = ""; if ( $4 > 0 ) { $sec = "(for $4 s)"; } $mon_fatal{"State change"}{"$1: $2 -> $3 $sec"}++; } elsif ($ThisLine =~ /^FATAL Agent on host '(\S+)' (.*)/) { $mon_fatal{"Agent on host"}{"$1: $2"}++; } elsif ($ThisLine =~ /^FATAL Can't reach agent on host '(\S+)'/) { $mon_fatal{"Agent on host"}{"$1: can't be reached"}++; } elsif ($ThisLine =~ /^FATAL (Couldn't open status file) '([^']+)'/) { $mon_fatal{"$1"}{"$2"}++; } elsif ($ThisLine =~ /^FATAL ([^\:]+)(?:: ERROR: (.*))?/) { $fatal{"$1"}{"$2"}++; } elsif ( (my ($srv, $host, $err, $msg) ) = ($ThisLine =~ /^ERROR Check '(\S+)' on '(\S+)' has (.*) Message: ERROR: ([^(]*)/) ) { $mon_error{"$host: $srv: $err $msg"}++; } elsif ($ThisLine =~ /^ERROR The (status of the (?:system|agent on host) '\S+' could not be determined)/) { $mon_error{"$1"}++; } elsif ($ThisLine =~ /^ERROR (Can't (?:reach agent on host|send offline status notification to)) '(\S+)'/) { $mon_error{"$2: $1"}++; } elsif ( $ThisLine =~ /^WARN (.*) Message: (UNKNOWN:) ([^(]*)/) { $warn{"$2: $1 $3"}++; } elsif ( $ThisLine =~ /^WARN (.*)/ ) { $warn{"$1"}++; } elsif ( $ThisLine =~ /^INFO (.*)/) { $info{"$1"}++; } else { # Report any unmatched entries... $OtherList{$ThisLine}++; } } ### generate output ### if (keys %mon_fatal) { print "\n Monitoring FATAL:\n"; foreach my $msg (keys %mon_fatal) { printf " %-52s", $msg; foreach my $err (sort {$a cmp $b} keys %{$mon_fatal{$msg}}) { if ($err) { printf "\n\t%-48s: %4i time(s)", $err, $mon_fatal{$msg}{$err}; } else { printf ": %4i time(s)\n", $mon_fatal{$msg}{$err}; } } print "\n"; } } if (keys %mon_error) { print "\n Monitoring ERROR:\n"; foreach my $msg (sort {$a cmp $b} keys %mon_error) { printf " %-52s: %4i time(s)\n", $msg, $mon_error{$msg}; } } if (keys %fatal) { print "\n Agent FATAL:\n"; foreach my $msg (sort {$a cmp $b} keys %fatal) { printf " %-52s", $msg; foreach my $err (sort {$a cmp $b} keys %{$fatal{$msg}}) { if ($err) { printf "\n\t%-48s: %4i time(s)\n", $err, $fatal{$msg}{$err}; } else { printf ": %4i time(s)\n", $fatal{$msg}{$err}; } } } } if (keys %warn and $Detail > 1) { print "\n Agent WARN:\n"; foreach my $msg (sort {$a cmp $b} keys %warn) { printf " %-52s: %4i time(s)\n", $msg, $warn{$msg}; } } if (keys %info and $Detail > 5) { print "\n INFO:\n"; foreach my $msg (sort {$a cmp $b} keys %info) { printf " %-52s: %5i time(s)\n", $msg, $info{$msg}; } } if (keys %OtherList) { print "\n**** Unmatched entries ****\n"; foreach my $Error (keys %OtherList) { print " $Error : $OtherList{$Error} Time(s)\n"; } } ### return without a failure ### exit(0); # vi: shiftwidth=3 tabstop=3 syntax=perl et logwatch-7.12/scripts/services/evtmswindows0000664000211400021140000002024614462364757021501 0ustar logwatchlogwatch ######################################################## # Please file all bug reports, patches, and feature # requests under: # https://sourceforge.net/p/logwatch/_list/tickets # Help requests and discusion can be filed under: # https://sourceforge.net/p/logwatch/discussion/ ######################################################## ######################################################## ## Copyright (c) 2020 Orion Poplawski ## Covered under the included MIT/X-Consortium License: ## http://www.opensource.org/licenses/mit-license.php ## All modifications and contributions by other persons to ## this script are assumed to have been donated to the ## Logwatch project and thus assume the above copyright ## and licensing terms. If you want to make contributions ## under your own copyright or a different license this ## must be explicitly stated in the contribution an the ## Logwatch project reserves the right to not accept such ## contributions. If you have made significant ## contributions to this script and want to claim ## copyright please contact logwatch-devel@lists.sourceforge.net. ######################################################### use strict; use warnings; use URI::URL; my $Detail = $ENV{'LOGWATCH_DETAIL_LEVEL'} || 0; my $Ignore_messages = $ENV{'ignore_messages'} || '^$'; my @PowerShell_Summarize_Users = split(',',$ENV{'powershell_summarize_users'}); my $Laptops = $ENV{'laptops'} || '^$'; my %Applications; while (defined(my $ThisLine = )) { # User specified ignore messages, lower cased next if $ThisLine =~ /$Ignore_messages/i; my ($Criticality,$SourceName,$DateTime,$EventID,$Application,$UserName,$SIDType,$EventLogType,$Hostname,$CategoryString,$DataString,$ExpandedString,$Extra); #Determine format if ($ThisLine =~ /MSWinEventLog\[/) { # Snare 4 #Parse ($Criticality,$SourceName,$DateTime,$EventID,$Application,$UserName,$SIDType,$EventLogType,$Hostname,$CategoryString,$DataString,$ExpandedString,$Extra) = ($ThisLine =~ /(\S+)\sMSWinEventLog\[(\d+)\]:(\w+)\t\d+\t([^\t]+)\t(\d+)\t([^\t]+)\t([^\t]+)\t([^\t]+)\t([^\t]+)\t([^\t]+)\t?([^\t]*)\t?([^\t]*)\t?([^\t]*)\t?([^\t]*)/); } elsif ($ThisLine =~ /MSWinEventLog\t/) { # Snare 3 #Parse ($Criticality,$SourceName,$DateTime,$EventID,$Application,$UserName,$SIDType,$EventLogType,$Hostname,$CategoryString,$DataString,$ExpandedString,$Extra) = ($ThisLine =~ /MSWinEventLog\t(\d+)\t([^\t]+)\t\d+\t([^\t]+)\t(\d+)\t([^\t]+)\t([^\t]+)\t([^\t]+)\t([^\t]+)\t([^\t]+)\t?([^\t]*)\t?([^\t]*)\t?([^\t]*)\t?([^\t]*)/); } if (!defined($Hostname)) { print STDERR "Cannot parse $ThisLine"; next; } next if $EventLogType eq "Information" and $ExpandedString !~ "BlueScreen"; next if $ExpandedString eq "N/A"; next if $SourceName =~ /^Microsoft-(?:Windows-Store|WindowsAzure-Diagnostics\/(?:GuestAgent|Heartbeat))/; next if $SourceName eq "Microsoft-Windows-SettingSync/Debug"; next if $Application =~ /^Microsoft-Windows-SettingsSync/; next if $Application eq "Windows-ApplicationModel-Store-SDK"; next if $Application eq "Microsoft-Windows-Store"; next if $Application eq "Microsoft-Windows-WMI-Activity"; if ($Application eq "Microsoft-Windows-GroupPolicy") { next if $ExpandedString =~ /Completed Security Extension Processing in \d+ milliseconds\./; next if $ExpandedString =~ /roup Policy failed to discover the Domain Controller details in \d+ milliseconds\./; next if $ExpandedString =~ /Skipped .* Extension based on Group Policy client-side processing rules\./; } elsif ($Application eq "Microsoft-Windows-Security-LessPrivilegedAppContainer") { next if $ExpandedString =~ /^Access to the a resource has been denied for a less privileged app container/; } elsif ($Application eq "Microsoft-Windows-SMBClient") { next if $ExpandedString =~ /^A network connection was disconnected/; next if $ExpandedString =~ /^Failed to establish a network connection/; next if $ExpandedString =~ /^The client lost its session to the server/; next if $ExpandedString =~ /^The connection to the share was lost/; next if $ExpandedString =~ /^The The server name cannot be resolved/; } elsif ($Application eq "Microsoft-Windows-SMBServer") { if (my ($ClientName, $UserName, $ShareName) = ($ExpandedString =~ /The share denied access to the client.*Client Name: (.*) Client Address: .* User Name: (.*) Session ID: .* Share Name: (.*) Share Path:/)) { $ExpandedString = "Access denied to share $ShareName by $UserName from $ClientName"; } } elsif ($Application eq "Microsoft-Windows-StorPort") { next if $ExpandedString =~ /^The miniport logged an event\.$/; } elsif ($Application eq "Microsoft-Windows-TaskScheduler") { next if $ExpandedString =~ /^Task Scheduler did not launch task .* because user .* was not logged on when the launching conditions were met/; next if $ExpandedString =~ /^Task Scheduler queued instance .* of task/; } # Modify some items that prevent de-duplication if ($Detail < 10) { $ExpandedString =~ s/(Task-S-)[0-9-]+/$1XXX/g; $ExpandedString =~ s/(guid:|GUID:|Guid:|Guid is|KEY:|known folder|interface|PRINTENUM\\|TransactionId:)( ?\{)[0-9A-Fa-f-]+\}/$1${2}XXX}/g; $ExpandedString =~ s/(ClientProcessId =|ElapsedTime\(ms\):|NextScheduled\S+|Process ID:?|PID|Transaction [^:]*Time \(msec\):|Try) \d+/$1 XXX/g; $ExpandedString =~ s/[\d.]+ (milli|)seconds/XXX $1seconds/g; $ExpandedString =~ s,\d{4}/\d\d/\d\d \d\d:\d\d:\d\d(?:\.\d+)?,TIMESTAMP,g; $ExpandedString =~ s,\d{4}-\d\d-\d\d[T ]\d\d:\d\d:\d\d(?:\.\d+)?Z?,TIMESTAMP,g; $ExpandedString =~ s/(ddress|Hash|Message ID|offset|Session ID):( ?0x)[0-9A-Fa-f]{2,16}/$1:${2}XXXX/g; $ExpandedString =~ s/\d+ms/Xms/g; $ExpandedString =~ s/nstance "\{[^}]+\}"/nstance XXXX/g; $ExpandedString =~ s/location [0-9a-f]{40}/location XXXX/g; $ExpandedString =~ s/(adalCorrelationId|client|Correlation ID|ID \(request\)|Trace ID): [0-9a-f-]+/$1: XXXX/g; $ExpandedString =~ s/ddress: ([^:]+):\d+/ddress: $1:XXXXX/g; } #print STDERR "Application = $Application ExpandedString = $ExpandedString\n"; #2021-02-07T23:49:45.083111-08:00 contracting01.ad.nwra.com MSWinEventLog 2 Microsoft-Windows-PowerShell/Operational 97386 Sun Feb 07 23:49:44 2021 4104 Microsoft-Windows-PowerShell appstats User Warning contracting01.ad.nwra.com Execute a Remote Command Creating Scriptblock text (1 of 2): # Copyright © 2017 Chocolatey Software, Inc. # Copyright © 2015 - 2017 RealDimensions Software, LLC # Copyright © 2011 - 2015 RealDimensions Software, LLC & original #($Criticality,$SourceName,$DateTime,$EventID,$Application,$UserName,$SIDType,$EventLogType,$Hostname,$CategoryString,$DataString,$ExpandedString,$Extra) = #my $url = URI::URL->new("http://www.eventid.net/display.asp?eventid=$EventID&source=$Application"); #my $urlstr = $url->abs; #$Applications{$Application}->{"$Hostname: $ExpandedString\n$url"}++; if ($Application eq "Microsoft-Windows-PowerShell") { # Only capture block 1 next if $ExpandedString =~ /^Creating Scriptblock text/ && $ExpandedString !~ /^Creating Scriptblock text \(1 /; if (grep(/^$UserName$/i,@PowerShell_Summarize_Users)) { $Applications{$SourceName}->{$Application}->{"$Hostname: $UserName $CategoryString"}++; } else { $Applications{$SourceName}->{$Application}->{"$Hostname: $UserName $CategoryString " . substr($ExpandedString, 0, 120)}++; } } else { $Applications{$SourceName}->{$Application}->{"$Hostname: $ExpandedString"}++; } } if (keys %Applications) { foreach my $SourceName (sort(keys %Applications)) { print "\n$SourceName\n"; foreach my $Application (sort(keys %{$Applications{$SourceName}})) { print "\n $Application\n"; foreach my $Error (sort(keys %{$Applications{$SourceName}->{$Application}})) { print " $Error : $Applications{$SourceName}->{$Application}->{$Error} Times\n"; } } } } exit(0); # vi: shiftwidth=3 tabstop=3 syntax=perl et # Local Variables: # mode: perl # perl-indent-level: 3 # indent-tabs-mode: nil # End: logwatch-7.12/scripts/services/http-error0000664000211400021140000001106114743365004021015 0ustar logwatchlogwatch ######################################################## # Please file all bug reports, patches, and feature # requests under: # https://sourceforge.net/p/logwatch/_list/tickets # Help requests and discusion can be filed under: # https://sourceforge.net/p/logwatch/discussion/ ######################################################## # ########################################################################## ## Copyright (c) 2016 Logwatch ## Covered under the included MIT/X-Consortium License: ## http://www.opensource.org/licenses/mit-license.php ## All modifications and contributions by other persons to ## this script are assumed to have been donated to the ## Logwatch project and thus assume the above copyright ## and licensing terms. If you want to make contributions ## under your own copyright or a different license this ## must be explicitly stated in the contribution an the ## Logwatch project reserves the right to not accept such ## contributions. If you have made significant ## contributions to this script and want to claim ## copyright please contact logwatch-devel@lists.sourceforge.net. ########################################################################## use diagnostics; use strict; my $Detail = $ENV{'LOGWATCH_DETAIL_LEVEL'} || 0; sub CustomizeErrorString { my ($LogLevel, $ErrorCode, $Description) = @_; # This function is only invoked when detail is set to 8 or 9. # Here you would modify the Description. Some Description strings # may differ only on some printed parameters, and it is preferable # to group them together. Examples of these may be process numbers, # IP addresses, port numbers, or file names. The purpose of this # function is to "collapse" these different messages into the same # array entry. # For now, simply return the string. return($Description); } my %LogMessages = (); my $MatchFilter = $ENV{'http_error_matchfilter'} || ""; my $ReportFilter = $ENV{'http_error_reportfilter'} || ""; while (defined(my $ThisLine = )) { if (my ($LogLevel, $ErrorCode, $Description) = ($ThisLine =~ /:(.*?)\].*(AH\d{5}): (.*)/) ) { # $MatchFilter is a variable that is set by setting the # $HTTP_Error_MatchFilter variable in the conf/services/http-error.conf # file. It is executed here, before any other matching statements. eval $MatchFilter; if ($@) { print $@; print "While processing MatchFilter:\n$MatchFilter\n"; } # $ThisLine might have been reset (undef, or empty string) in $MatchFilter next unless $ThisLine; if (($Detail == 8) || ($Detail == 9)) { $Description = CustomizeErrorString($LogLevel, $ErrorCode, $Description); } if (($Detail >= 1) || ($LogLevel =~ "emerg|alert|crit|error")) { $LogMessages{$LogLevel}{$ErrorCode}{$Description}++; } } } # $ReportFilter is a variable that is set by setting the # $HTTP_Error_ReportFilter variable in the conf/services/http-error.conf # file. It is executed here, before any other printing statements. eval $ReportFilter; if ($@) { print $@; print "While processing ReportFilter:\n$ReportFilter\n"; } if (keys %LogMessages) { my $Count = 0; foreach my $LogLevel (keys %LogMessages) { printf("\nLevel %-6s", $LogLevel); foreach my $ErrorCode (keys %{$LogMessages{$LogLevel}}) { print "\n $LogLevel code: $ErrorCode" if $Detail >= 5; foreach my $Description (keys %{$LogMessages{$LogLevel}{$ErrorCode}}) { if ($Detail >= 9) { print "\n $Description: "; print "$LogMessages{$LogLevel}{$ErrorCode}{$Description} Time(s)"; } $Count += $LogMessages{$LogLevel}{$ErrorCode}{$Description}; } # foreach $Description if (($Detail >= 5) && ($Detail < 9)) { printf(": %5d Time(s)", $Count); $Count = 0; if ($Detail >=6) { print "\n E.g.: "; # print only first entry (index 0) my $EG_string = (keys %{$LogMessages{$LogLevel}{$ErrorCode}})[0]; if (($Detail == 6) && (length($EG_string) > 66)) { printf ("%.62s ...", $EG_string); } else { print $EG_string; } } } } # foreach $ErrorCode if ($Detail < 5) { printf("%s%5d%s", ": ", $Count, " Time(s)"); $Count = 0; } } # foreach $LogLevel } # if keys %LogMessages exit(0); # vi: shiftwidth=3 tabstop=3 syntax=perl et # Local Variables: # mode: perl # perl-indent-level: 3 # indent-tabs-mode: nil # End: logwatch-7.12/scripts/services/rt3140000664000211400021140000001041614274101043017555 0ustar logwatchlogwatch ######################################################## # Please file all bug reports, patches, and feature # requests under: # https://sourceforge.net/p/logwatch/_list/tickets # Help requests and discusion can be filed under: # https://sourceforge.net/p/logwatch/discussion/ ######################################################## ############################################################################# # rt314: logwatcher processing script for NetGear RT314 router syslog output. # Author: Daniel J. Barrett, dbarrett@blazemonger.com. ############################################################################# ####################################################### ## Copyright (c) 2008 Daniel Barrett ## Covered under the included MIT/X-Consortium License: ## http://www.opensource.org/licenses/mit-license.php ## All modifications and contributions by other persons to ## this script are assumed to have been donated to the ## Logwatch project and thus assume the above copyright ## and licensing terms. If you want to make contributions ## under your own copyright or a different license this ## must be explicitly stated in the contribution an the ## Logwatch project reserves the right to not accept such ## contributions. If you have made significant ## contributions to this script and want to claim ## copyright please contact logwatch-devel@lists.sourceforge.net. ######################################################### use Socket; use strict; my $Detail = $ENV{'LOGWATCH_DETAIL_LEVEL'} || 0; my $separator = "-------------------------------------------------------\n"; ### Partition the data into types my (@portscanlines, @genlines, @otherlines, $begin, $end); my $psl = 0; my $gl = 0; my $ol = 0; while (my $line = ) { $line =~ s/netgear RAS: //; unless ($begin) { $begin = substr($line, 0, 15); } $end = $line; if ( $line =~ /dpo=/ ) { $portscanlines[$psl++] = $line; } elsif ( $line =~ / GEN/ ) { $genlines[$gl++] = $line; } elsif ( $line =~ /last message repeated/ ) { ; } else { $otherlines[$ol++] = $line; } } exit(0) unless ($end); $end = substr($end, 0, 15); ### Print summary if ($Detail >= 10) { print "=== Summary ===\n\n"; } print "Begin:\t$begin\n"; print "End:\t$end\n"; print "\n"; # Extract the port number and source IP address. my @portarray; my %ipaddrs; foreach my $line (@portscanlines) { my $portnum; my $ipaddr; my $dup = $line; $dup =~ s/^.*Src=([0-9.]+) .* dpo=([0-9]*).*$/\1/; $ipaddr = $1; $portnum = $2; $portarray[$portnum]++; if (exists($ipaddrs{$ipaddr})) { $ipaddrs{$ipaddr}++; } else { $ipaddrs{$ipaddr} = 1; } } # Summarize port scans by port number my $total = 0; print "Port #\t\tScans\tService Name\n"; print $separator; for (my $i = 0; $i <= $#portarray; $i++) { if ( $portarray[$i] > 0 ) { print "$i\t\t" . $portarray[$i] . "\t" . getservbyport($i, "tcp") . "\n"; $total += $portarray[$i]; } } print $separator; print "Total\t\t$total\n"; print "\n"; # Summarize port scans by initiating host my @keys = sort {$a <=> $b} (keys %ipaddrs); print "Scanned by\tScans\tHostname Lookup\n"; print $separator; $total = 0; foreach my $ip (@keys) { print "$ip\t" . $ipaddrs{$ip} . "\t" . gethostbyaddr(inet_aton($ip), AF_INET) . "\n"; $total += $ipaddrs{$ip}; } print $separator; print "Total\t\t$total\n"; print "\n"; # Summarize other rule firings if ( $#genlines > 0 ) { print "Rules fired:\t" . $#genlines . "\n"; print "\n"; } # Summarize remaining output if ( $#otherlines > 0 ) { print "Uncategorized:\t" . $#otherlines . "!!!!!!!\n"; print "\n"; } if ($Detail >= 10) { ## Print all data print "=== Raw Data ===\n\n"; if ( $#portscanlines > 0 ) { print "Port scans:\n"; foreach my $line (@portscanlines) { print $line; } print "\n"; } if ( $#genlines > 0 ) { print "Rule lines:\n"; foreach my $line (@genlines) { print $line; } print "\n"; } if ( $#otherlines > 0 ) { print "Other lines:\n"; foreach my $line (@otherlines) { print $line; } print "\n"; } } exit(0); # vi: shiftwidth=3 tabstop=3 syntax=perl et # Local Variables: # mode: perl # perl-indent-level: 3 # indent-tabs-mode: nil # End: logwatch-7.12/scripts/services/postfix0000664000211400021140000074760314743365004020425 0ustar logwatchlogwatch#!/usr/bin/perl ######################################################## # Please file all bug reports, patches, and feature # requests under: # https://sourceforge.net/p/logwatch/_list/tickets # Help requests and discusion can be filed under: # https://sourceforge.net/p/logwatch/discussion/ ######################################################## ####################################################### ### All work since Dec 12, 2006 (logwatch CVS revision 1.28) ### Copyright (c) 2006-2012 Mike Cappella ### ### Covered under the included MIT/X-Consortium License: ### http://www.opensource.org/licenses/mit-license.php ### All modifications and contributions by other persons to ### this script are assumed to have been donated to the ### Logwatch project and thus assume the above copyright ### and licensing terms. If you want to make contributions ### under your own copyright or a different license this ### must be explicitly stated in the contribution an the ### Logwatch project reserves the right to not accept such ### contributions. If you have made significant ### contributions to this script and want to claim ### copyright please contact logwatch-devel@lists.sourceforge.net. ########################################################## ########################################################################## # The original postfix logwatch filter was written by # Kenneth Porter, and has had many contributors over the years. # # CVS log removed: see Changes file for postfix-logwatch at # http://logreporters.sourceforge.net/ # or included with the standalone postfix-logwatch distribution ########################################################################## ########################################################################## # # Test data included via inline comments starting with "#TD" # #use Devel::Size qw(size total_size); package Logreporters; use 5.008; use strict; use warnings; no warnings "uninitialized"; use re 'taint'; our $Version = '1.40.03'; our $progname_prefix = 'postfix'; # Specifies the default configuration file for use in standalone mode. my $config_file = "/usr/local/etc/${progname_prefix}-logwatch.conf"; # support postfix long (2.9+) or short queue ids my $re_QID_s = qr/[A-Z\d]+/; my $re_QID_l = qr/(?:NOQUEUE|[bcdfghjklmnpqrstvwxyzBCDFGHJKLMNPQRSTVWXYZ\d]+)/; our $re_QID; our $re_DSN = qr/(?:(?:\d{3})?(?: ?\d\.\d\.\d+)?)/; our $re_DDD = qr/(?:(?:conn_use=\d+ )?delay=-?[\d.]+(?:, delays=[\d\/.]+)?(?:, dsn=[\d.]+)?)/; #MODULE: ../Logreporters/Utils.pm package Logreporters::Utils; use 5.008; use strict; use re 'taint'; use warnings; BEGIN { use Exporter (); use vars qw(@ISA @EXPORT @EXPORT_OK %EXPORT_TAGS $VERSION); $VERSION = '1.003'; @ISA = qw(Exporter); @EXPORT = qw(&formathost &get_percentiles &get_percentiles2 &get_frequencies &commify &unitize &get_usable_sectvars &add_section &begin_section_group &end_section_group &get_version &unique_list); @EXPORT_OK = qw(&gen_test_log); } use subs qw (@EXPORT @EXPORT_OK); # Formats IP and hostname for even column spacing # sub formathost($ $) { # $_[0] : hostip # $_[1] : hostname; if (! $Logreporters::Config::Opts{'unknown'} and $_[1] eq 'unknown') { return $_[0]; } return sprintf "%-$Logreporters::Config::Opts{'ipaddr_width'}s %s", $_[0] eq '' ? '*unknown' : $_[0], $_[1] eq '' ? '*unknown' : lc $_[1]; } # Add a new section to the end of a section table # sub add_section($$$$$;$) { my $sref = shift; die "Improperly specified Section entry: $_[0]" if !defined $_[3]; my $entry = { CLASS => 'DATA', NAME => $_[0], DETAIL => $_[1], FMT => $_[2], TITLE => $_[3], }; $entry->{'DIVISOR'} = $_[4] if defined $_[4]; push @$sref, $entry; } { my $group_level = 0; # Begin a new section group. Groups can nest. # sub begin_section_group($;@) { my $sref = shift; my $group_name = shift; my $entry = { CLASS => 'GROUP_BEGIN', NAME => $group_name, LEVEL => ++$group_level, HEADERS => [ @_ ], }; push @$sref, $entry; } # Ends a section group. # sub end_section_group($;@) { my $sref = shift; my $group_name = shift; my $entry = { CLASS => 'GROUP_END', NAME => $group_name, LEVEL => --$group_level, FOOTERS => [ @_ ], }; push @$sref, $entry; } } # Generate and return a list of section table entries or # limiter key names, skipping any formatting entries. # If 'namesonly' is set, limiter key names are returned, # otherwise an array of section array records is returned. sub get_usable_sectvars(\@ $) { my ($sectref,$namesonly) = @_; my (@sect_list, %unique_names); foreach my $sref (@$sectref) { #print "get_usable_sectvars: $sref->{NAME}\n"; next unless $sref->{CLASS} eq 'DATA'; if ($namesonly) { $unique_names{$sref->{NAME}} = 1; } else { push @sect_list, $sref; } } # return list of unique names if ($namesonly) { return keys %unique_names; } return @sect_list; } # Print program and version info, preceeded by an optional string, and exit. # sub get_version() { print STDOUT "@_\n" if ($_[0]); print STDOUT "$Logreporters::progname: $Logreporters::Version\n"; exit 0; } # Returns a list of percentile values given a # sorted array of numeric values. Uses the formula: # # r = 1 + (p(n-1)/100) = i + d (Excel method) # # r = rank # p = desired percentile # n = number of items # i = integer part # d = decimal part # # Arg1 is an array ref to the sorted series # Arg2 is a list of percentiles to use sub get_percentiles(\@ @) { my ($aref,@plist) = @_; my ($n, $last, $r, $d, $i, @vals, $Yp); $last = $#$aref; $n = $last + 1; #printf "%6d" x $n . "\n", @{$aref}; #printf "n: %4d, last: %d\n", $n, $last; foreach my $p (@plist) { $r = 1 + ($p * ($n - 1) / 100.0); $i = int ($r); # integer part # domain: $i = 1 .. n if ($i == $n) { $Yp = $aref->[$last]; } elsif ($i == 0) { $Yp = $aref->[0]; print "CAN'T HAPPEN: $Yp\n"; } else { $d = $r - $i; # decimal part #p = Y[i] + d(Y[i+1] - Y[i]), but since we're 0 based, use i=i-1 $Yp = $aref->[$i-1] + ($d * ($aref->[$i] - $aref->[$i-1])); } #printf "\np(%6.2f), r: %6.2f, i: %6d, d: %6.2f, Yp: %6d", $p, $r, $i, $d, $Yp; push @vals, $Yp; } return @vals; } sub get_num_scores($) { my $scoretab_r = shift; my $totalscores = 0; for (my $i = 0; $i < @$scoretab_r; $i += 2) { $totalscores += $scoretab_r->[$i+1] } return $totalscores; } # scoretab # # (score1, n1), (score2, n2), ... (scoreN, nN) # $i $i+1 # # scores are 0 based (0 = 1st score) sub get_nth_score($ $) { my ($scoretab_r, $n) = @_; my $i = 0; my $n_cur_scores = 0; #print "Byscore (", .5 * @$scoretab_r, "): "; for (my $i = 0; $i < $#$scoretab_r / 2; $i++) { printf "%9s (%d) ", $scoretab_r->[$i], $scoretab_r->[$i+1]; } ; print "\n"; while ($i < $#$scoretab_r) { #print "Samples_seen: $n_cur_scores\n"; $n_cur_scores += $scoretab_r->[$i+1]; if ($n_cur_scores >= $n) { #printf "range: %s %s %s\n", $i >= 2 ? $scoretab_r->[$i - 2] : '', $scoretab_r->[$i], $i+2 > $#$scoretab_r ? '' : $scoretab_r->[$i + 2]; #printf "n: $n, i: %8d, n_cur_scores: %8d, score: %d x %d hits\n", $i, $n_cur_scores, $scoretab_r->[$i], $scoretab_r->[$i+1]; return $scoretab_r->[$i]; } $i += 2; } print "returning last score $scoretab_r->[$i]\n"; return $scoretab_r->[$i]; } sub get_percentiles2(\@ @) { my ($scoretab_r, @plist) = @_; my ($n, $last, $r, $d, $i, @vals, $Yp); #$last = $#$scoretab_r - 1; $n = get_num_scores($scoretab_r); #printf "\n%6d" x $n . "\n", @{$scoretab_r}; #printf "\n\tn: %4d, @$scoretab_r\n", $n; foreach my $p (@plist) { ###print "\nPERCENTILE: $p\n"; $r = 1 + ($p * ($n - 1) / 100.0); $i = int ($r); # integer part if ($i == $n) { #print "last:\n"; #$Yp = $scoretab_r->[$last]; $Yp = get_nth_score($scoretab_r, $n); } elsif ($i == 0) { #$Yp = $scoretab_r->[0]; print "1st: CAN'T HAPPEN\n"; $Yp = get_nth_score($scoretab_r, 1); } else { $d = $r - $i; # decimal part #p = Y[i] + d(Y[i+1] - Y[i]), but since we're 0 based, use i=i-1 my $ithvalprev = get_nth_score($scoretab_r, $i); my $ithval = get_nth_score($scoretab_r, $i+1); $Yp = $ithvalprev + ($d * ($ithval - $ithvalprev)); } #printf "p(%6.2f), r: %6.2f, i: %6d, d: %6.2f, Yp: %6d\n", $p, $r, $i, $d, $Yp; push @vals, $Yp; } return @vals; } # Returns a list of frequency distributions given an incrementally sorted # set of sorted scores, and an incrementally sorted list of buckets # # Arg1 is an array ref to the sorted series # Arg2 is a list of frequency buckets to use sub get_frequencies(\@ @) { my ($aref,@blist) = @_; my @vals = ( 0 ) x (@blist); my @sorted_blist = sort { $a <=> $b } @blist; my $bucket_index = 0; OUTER: foreach my $score (@$aref) { #print "Score: $score\n"; for my $i ($bucket_index .. @sorted_blist - 1) { #print "\tTrying Bucket[$i]: $sorted_blist[$i]\n"; if ($score > $sorted_blist[$i]) { $bucket_index++; } else { #printf "\t\tinto Bucket[%d]\n", $bucket_index; $vals[$bucket_index]++; next OUTER; } } #printf "\t\tinto Bucket[%d]\n", $bucket_index - 1; $vals[$bucket_index - 1]++; } return @vals; } # Inserts commas in numbers for easier readability # sub commify ($) { return undef if ! defined ($_[0]); my $text = reverse $_[0]; $text =~ s/(\d\d\d)(?=\d)(?!\d*\.)/$1,/g; return scalar reverse $text; } # Unitize a number, and return appropriate printf formatting string # sub unitize($ $) { my ($num, $fmt) = @_; my $kilobyte = 2**10; my $megabyte = 2**20; my $gigabyte = 2**30; my $terabyte = 2**40; if ($num >= $terabyte) { $num /= $terabyte; $fmt .= '.3fT'; } elsif ($num >= $gigabyte) { $num /= $gigabyte; $fmt .= '.3fG'; } elsif ($num >= $megabyte) { $num /= $megabyte; $fmt .= '.3fM'; } elsif ($num >= $kilobyte) { $num /= $kilobyte; $fmt .= '.3fK'; } else { $fmt .= 'd '; } return ($num, $fmt); } # Returns a sublist of the supplied list of elements in an unchanged order, # where only the first occurrence of each defined element is retained # and duplicates removed # # Borrowed from amavis 2.6.2 # sub unique_list(@) { my ($r) = @_ == 1 && ref($_[0]) ? $_[0] : \@_; # accept list, or a list ref my (%seen); my (@unique) = grep { defined($_) && !$seen{$_}++ } @$r; return @unique; } # Generate a test maillog file from the '#TD' test data lines # The test data file is placed in /var/tmp/maillog.autogen # # arg1: "postfix" or "amavis" # arg2: path to postfix-logwatch or amavis-logwatch from which to read '#TD' data # # Postfix TD syntax: # TD() log entry # sub gen_test_log($) { my $scriptpath = shift; my $toolname = $Logreporters::progname_prefix; my $datafile = "/var/tmp/maillog-${toolname}.autogen"; die "gen_test_log: invalid toolname $toolname" if ($toolname !~ /^(postfix|amavis)$/); eval { require Sys::Hostname; require Fcntl; } or die "Unable to create test data file: required module(s) not found\n$@"; my $syslogtime = localtime; $syslogtime =~ s/^....(.*) \d{4}$/$1/; my ($hostname) = split /\./, Sys::Hostname::hostname(); # # avoid -T issues # delete @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV'}; my $flags = &Fcntl::O_CREAT|&Fcntl::O_WRONLY|&Fcntl::O_TRUNC; sysopen(FH, $datafile, $flags) or die "Can't create test data file: $!"; print "Generating test log data file from $scriptpath: $datafile\n"; my $id; @ARGV = ($scriptpath); if ($toolname eq 'postfix') { my %services = ( DEF => 'smtpd', bQ => 'bounce', cN => 'cleanup', cQ => 'cleanup', lQ => 'local', m => 'master', p => 'pickup', pQ => 'pickup', ppQ => 'pipe', pfw => 'postfwd', pg => 'postgrey', pgQ => 'postgrey', ps => 'postsuper', qQ => 'qmgr', s => 'smtp', sQ => 'smtp', sd => 'smtpd', sdN => 'smtpd', sdQ => 'smtpd', spf => 'policy-spf', vN => 'virtual', vQ => 'virtual', ); $id = 'postfix/smtp[12345]'; while (<>) { if (/^\s*#TD([a-zA-Z]*[NQ]?)(\d+)?(?:\(([^)]+)\))? (.*)$/) { my ($service,$count,$qid,$line) = ($1, $2, $3, $4); #print "SERVICE: %s, QID: %s, COUNT: %s, line: %s\n", $service, $qid, $count, $line; if ($service eq '') { $service = 'DEF'; } die ("No such service: \"$service\": line \"$_\"") if (!exists $services{$service}); $id = $services{$service} . '[123]'; $id = 'postfix/' . $id unless $services{$service} eq 'postgrey'; #print "searching for service: \"$service\"\n\tFound $id\n"; if ($service =~ /N$/) { $id .= ': NOQUEUE'; } elsif ($service =~ /Q$/) { $id .= $qid ? $qid : ': DEADBEEF'; } $line =~ s/ +/ /g; $line =~ s/^ //g; #print "$syslogtime $hostname $id: \"$line\"\n" x ($count ? $count : 1); print FH "$syslogtime $hostname $id: $line\n" x ($count ? $count : 1); } } } else { #amavis my %services = ( DEF => 'amavis', dcc => 'dccproc', ); while (<>) { if (/^\s*#TD([a-z]*)(\d+)? (.*)$/) { my ($service,$count,$line) = ($1, $2, $3); if ($service eq '') { $service = 'DEF'; } die ("No such service: \"$service\": line \"$_\"") if (!exists $services{$service}); $id = $services{$service} . '[123]:'; if ($services{$service} eq 'amavis') { $id .= ' (9999-99)'; } print FH "$syslogtime $hostname $id $line\n" x ($count ? $count : 1) } } } close FH or die "Can't close $datafile: $!"; } 1; #MODULE: ../Logreporters/Config.pm package Logreporters::Config; use 5.008; use strict; use re 'taint'; use warnings; BEGIN { use Exporter (); use vars qw(@ISA @EXPORT @EXPORT_OK %EXPORT_TAGS $VERSION); $VERSION = '1.002'; @ISA = qw(Exporter); @EXPORT = qw(&init_run_mode &add_option &get_options &init_cmdline &get_vars_from_file &process_limiters &process_debug_opts &init_getopts_table_common &zero_opts @Optspec %Opts %Configvars @Limiters %line_styles $fw1 $fw2 $sep1 $sep2 &D_CONFIG &D_ARGS &D_VARS &D_TREE &D_SECT &D_UNMATCHED &D_TEST &D_ALL ); } use subs @EXPORT; our @Optspec = (); # options table used by Getopts our %Opts = (); # program-wide options our %Configvars = (); # configuration file variables our @Limiters; # Report separator characters and widths our ($fw1,$fw2) = (22, 10); our ($sep1,$sep2) = ('=', '-'); use Getopt::Long; BEGIN { import Logreporters::Utils qw(&get_usable_sectvars); } our %line_styles = ( truncate => 0, wrap => 1, full => 2, ); sub init_run_mode($); sub confighash_to_cmdline(\%); sub get_vars_from_file(\% $); sub process_limiters(\@); sub add_option(@); sub get_options($); sub init_getopts_table_common(@); sub set_supplemental_reports($$); # debug constants sub D_CONFIG () { 1<<0 } sub D_ARGS () { 1<<1 } sub D_VARS () { 1<<2 } sub D_TREE () { 1<<3 } sub D_SECT () { 1<<4 } sub D_UNMATCHED () { 1<<5 } sub D_TEST () { 1<<30 } sub D_ALL () { 1<<31 } my %debug_words = ( config => D_CONFIG, args => D_ARGS, vars => D_VARS, tree => D_TREE, sect => D_SECT, unmatched => D_UNMATCHED, test => D_TEST, all => 0xffffffff, ); # Clears %Opts hash and initializes basic running mode options in # %Opts hash by setting keys: 'standalone', 'detail', and 'debug'. # Call early. # sub init_run_mode($) { my $config_file = shift; $Opts{'debug'} = 0; # Logwatch passes a filter's options via environment variables. # When running standalone (w/out logwatch), use command line options $Opts{'standalone'} = exists ($ENV{LOGWATCH_DETAIL_LEVEL}) ? 0 : 1; # Show summary section by default $Opts{'summary'} = 1; # Do not show mail queue section by default $Opts{'mailqueue'} = 0; if ($Opts{'standalone'}) { process_debug_opts($ENV{'LOGREPORTERS_DEBUG'}) if exists ($ENV{'LOGREPORTERS_DEBUG'}); } else { $Opts{'detail'} = $ENV{'LOGWATCH_DETAIL_LEVEL'}; # XXX #process_debug_opts($ENV{'LOGWATCH_DEBUG'}) if exists ($ENV{'LOGWATCH_DEBUG'}); } # first process --debug, --help, and --version options add_option ('debug=s', sub { process_debug_opts($_[1]); 1}); add_option ('version', sub { &Logreporters::Utils::get_version(); 1;}); get_options(1); # now process --config_file, so that all config file vars are read first add_option ('config_file|f=s', sub { get_vars_from_file(%Configvars, $_[1]); 1;}); get_options(1); # if no config file vars were read if ($Opts{'standalone'} and ! keys(%Configvars) and -f $config_file) { print "Using default config file: $config_file\n" if $Opts{'debug'} & D_CONFIG; get_vars_from_file(%Configvars, $config_file); } } sub get_options($) { my $pass_through = shift; #$SIG{__WARN__} = sub { print "*** $_[0]*** options error\n" }; # ensure we're called after %Opts is initialized die "get_options: program error: %Opts is empty" unless exists $Opts{'debug'}; my $p = new Getopt::Long::Parser; if ($pass_through) { $p->configure(qw(pass_through permute)); } else { $p->configure(qw(no_pass_through no_permute)); } #$p->configure(qw(debug)); if ($Opts{'debug'} & D_ARGS) { print "\nget_options($pass_through): enter\n"; printf "\tARGV(%d): ", scalar @ARGV; print @ARGV, "\n"; print "\t$_ ", defined $Opts{$_} ? "=> $Opts{$_}\n" : "\n" foreach sort keys %Opts; } if ($p->getoptions(\%Opts, @Optspec) == 0) { print STDERR "Use ${Logreporters::progname} --help for options\n"; exit 1; } if ($Opts{'debug'} & D_ARGS) { print "\t$_ ", defined $Opts{$_} ? "=> $Opts{$_}\n" : "\n" foreach sort keys %Opts; printf "\tARGV(%d): ", scalar @ARGV; print @ARGV, "\n"; print "get_options: exit\n"; } } sub add_option(@) { push @Optspec, @_; } # untaint string, borrowed from amavisd-new sub untaint($) { no re 'taint'; my ($str); if (defined($_[0])) { local($1); # avoid Perl taint bug: tainted global $1 propagates taintedness $str = $1 if $_[0] =~ /^(.*)$/; } return $str; } sub init_getopts_table_common(@) { my @supplemental_reports = @_; print "init_getopts_table_common: enter\n" if $Opts{'debug'} & D_ARGS; add_option ('help', sub { print STDOUT Logreporters::usage(undef); exit 0 }); add_option ('gen_test_log=s', sub { Logreporters::Utils::gen_test_log($_[1]); exit 0; }); add_option ('detail=i'); add_option ('nodetail', sub { # __none__ will set all limiters to 0 in process_limiters # since they are not known (Sections table is not yet built). push @Limiters, '__none__'; # 0 = disable supplemental_reports set_supplemental_reports(0, \@supplemental_reports); }); add_option ('max_report_width=i'); add_option ('summary!'); add_option ('mailqueue!'); add_option ('show_summary=i', sub { $Opts{'summary'} = $_[1]; 1; }); add_option ('show_mailqueue=i', sub { $Opts{'mailqueue'} = $_[1]; 1; }); # untaint ipaddr_width for use w/sprintf() in Perl v5.10 add_option ('ipaddr_width=i', sub { $Opts{'ipaddr_width'} = untaint ($_[1]); 1; }); add_option ('sect_vars!'); add_option ('show_sect_vars=i', sub { $Opts{'sect_vars'} = $_[1]; 1; }); add_option ('syslog_name=s'); add_option ('wrap', sub { $Opts{'line_style'} = $line_styles{$_[0]}; 1; }); add_option ('full', sub { $Opts{'line_style'} = $line_styles{$_[0]}; 1; }); add_option ('truncate', sub { $Opts{'line_style'} = $line_styles{$_[0]}; 1; }); add_option ('line_style=s', sub { my $style = lc($_[1]); my @list = grep (/^$style/, keys %line_styles); if (! @list) { print STDERR "Invalid line_style argument \"$_[1]\"\n"; print STDERR "Option line_style argument must be one of \"wrap\", \"full\", or \"truncate\".\n"; print STDERR "Use $Logreporters::progname --help for options\n"; exit 1; } $Opts{'line_style'} = $line_styles{lc($list[0])}; 1; }); add_option ('limit|l=s', sub { my ($limiter,$lspec) = split(/=/, $_[1]); if (!defined $lspec) { printf STDERR "Limiter \"%s\" requires value (ex. --limit %s=10)\n", $_[1],$_[1]; exit 2; } foreach my $val (split(/(?:\s+|\s*,\s*)/, $lspec)) { if ($val !~ /^\d+$/ and $val !~ /^(\d*)\.(\d+)$/ and $val !~ /^::(\d+)$/ and $val !~ /^:(\d+):(\d+)?$/ and $val !~ /^(\d+):(\d+)?:(\d+)?$/) { printf STDERR "Limiter value \"$val\" invalid in \"$limiter=$lspec\"\n"; exit 2; } } push @Limiters, lc $_[1]; }); print "init_getopts_table_common: exit\n" if $Opts{'debug'} & D_ARGS; } sub get_option_names() { my (@ret, @tmp); foreach (@Optspec) { if (ref($_) eq '') { # process only the option names my $spec = $_; $spec =~ s/=.*$//; $spec =~ s/([^|]+)\!$/$1|no$1/g; @tmp = split /[|]/, $spec; #print "PUSHING: @tmp\n"; push @ret, @tmp; } } return @ret; } # Set values for the configuration variables passed via hashref. # Variables are of the form ${progname_prefix}_KEYNAME. # # Because logwatch lowercases all config file entries, KEYNAME is # case-insensitive. # sub init_cmdline() { my ($href, $configvar, $value, $var); # logwatch passes all config vars via environment variables $href = $Opts{'standalone'} ? \%Configvars : \%ENV; # XXX: this is cheeze: need a list of valid limiters, but since # the Sections table is not built yet, we don't know what is # a limiter and what is an option, as there is no distinction in # variable names in the config file (perhaps this should be changed). my @valid_option_names = get_option_names(); die "Options table not yet set" if ! scalar @valid_option_names; print "confighash_to_cmdline: @valid_option_names\n" if $Opts{'debug'} & D_ARGS; my @cmdline = (); while (($configvar, $value) = each %$href) { if ($configvar =~ s/^${Logreporters::progname_prefix}_//o) { # distinguish level limiters from general options # would be easier if limiters had a unique prefix $configvar = lc $configvar; my $ret = grep (/^$configvar$/i, @valid_option_names); if ($ret == 0) { print "\tLIMITER($ret): $configvar = $value\n" if $Opts{'debug'} & D_ARGS; push @cmdline, '-l', "$configvar" . "=$value"; } else { print "\tOPTION($ret): $configvar = $value\n" if $Opts{'debug'} & D_ARGS; unshift @cmdline, $value if defined ($value); unshift @cmdline, "--$configvar"; } } } unshift @ARGV, @cmdline; } # Obtains the variables from a logwatch-style .conf file, for use # in standalone mode. Returns an ENV-style hash of key/value pairs. # sub get_vars_from_file(\% $) { my ($href, $file) = @_; my ($var, $val); print "get_vars_from_file: enter: processing file: $file\n" if $Opts{'debug'} & D_CONFIG; my $message = undef; my $ret = stat ($file); if ($ret == 0) { $message = $!; } elsif (! -r _) { $message = "Permission denied"; } elsif ( -d _) { $message = "Is a directory"; } elsif (! -f _) { $message = "Not a regular file"; } if ($message) { print STDERR "Configuration file \"$file\": $message\n"; exit 2; } my $prog = $Logreporters::progname_prefix; open FILE, '<', "$file" or die "unable to open configuration file $file: $!"; while () { chomp; next if (/^\s*$/); # ignore all whitespace lines next if (/^\*/); # ignore logwatch's *Service lines next if (/^\s*#/); # ignore comment lines if (/^\s*\$(${prog}_[^=\s]+)\s*=\s*"?([^"]+)"?$/o) { ($var,$val) = ($1,$2); if ($val =~ /^(?:no|false)$/i) { $val = 0; } elsif ($val =~ /^(?:yes|true)$/i) { $val = 1; } elsif ($val eq '') { $var =~ s/${prog}_/${prog}_no/; $val = undef; } print "\t\"$var\" => \"$val\"\n" if $Opts{'debug'} & D_CONFIG; $href->{$var} = $val; } } close FILE or die "failed to close configuration handle for $file: $!"; print "get_vars_from_file: exit\n" if $Opts{'debug'} & D_CONFIG; } sub process_limiters(\@) { my ($sectref) = @_; my ($limiter, $var, $val, @errors); my @l = get_usable_sectvars(@$sectref, 1); if ($Opts{'debug'} & D_VARS) { print "process_limiters: enter\n"; print "\tLIMITERS: @Limiters\n"; } while ($limiter = shift @Limiters) { my @matched = (); printf "\t%-30s ",$limiter if $Opts{'debug'} & D_VARS; # disable all limiters when limiter is __none__: see 'nodetail' cmdline option if ($limiter eq '__none__') { $Opts{$_} = 0 foreach @l; next; } ($var,$val) = split /=/, $limiter; if ($val eq '') { push @errors, "Limiter \"$var\" requires value (ex. --limit limiter=10)"; next; } # try exact match first, then abbreviated match next if (scalar (@matched = grep(/^$var$/, @l)) == 1 or scalar (@matched = grep(/^$var/, @l)) == 1) { $limiter = $matched[0]; # unabbreviate limiter print "MATCH: $var: $limiter => $val\n" if $Opts{'debug'} & D_VARS; # XXX move limiters into section hash entry... $Opts{$limiter} = $val; next; } print "matched=", scalar @matched, ": @matched\n" if $Opts{'debug'} & D_VARS; push @errors, "Limiter \"$var\" is " . (scalar @matched == 0 ? "invalid" : "ambiguous: @matched"); } print "\n" if $Opts{'debug'} & D_VARS; if (@errors) { print STDERR "$_\n" foreach @errors; exit 2; } # Set the default value of 10 for each section if no limiter exists. # This allows output for each section should there be no configuration # file or missing limiter within the configuration file. foreach (@l) { $Opts{$_} = 10 unless exists $Opts{$_}; } # Enable collection for each section if a limiter is non-zero. foreach (@l) { #print "L is: $_\n"; #print "DETAIL: $Opts{'detail'}, OPTS: $Opts{$_}\n"; $Logreporters::TreeData::Collecting{$_} = (($Opts{'detail'} >= 5) && $Opts{$_}) ? 1 : 0; } #print "OPTS: \n"; map { print "$_ => $Opts{$_}\n"} keys %Opts; #print "COLLECTING: \n"; map { print "$_ => $Logreporters::TreeData::Collecting{$_}\n"} keys %Logreporters::TreeData::Collecting; } # Enable/disable supplemental reports # arg1: 0=off, 1=on # arg2,...: list of supplemental report keywords sub set_supplemental_reports($$) { my ($onoff,$aref) = @_; $Opts{$_} = $onoff foreach (@$aref); } sub process_debug_opts($) { my $optstring = shift; my @errors = (); foreach (split(/\s*,\s*/, $optstring)) { my $word = lc $_; my @matched = grep (/^$word/, keys %debug_words); if (scalar @matched == 1) { $Opts{'debug'} |= $debug_words{$matched[0]}; next; } if (scalar @matched == 0) { push @errors, "Unknown debug keyword \"$word\""; } else { # > 1 push @errors, "Ambiguous debug keyword abbreviation \"$word\": (matches: @matched)"; } } if (@errors) { print STDERR "$_\n" foreach @errors; print STDERR "Debug keywords: ", join (' ', sort keys %debug_words), "\n"; exit 2; } } # Zero the options controlling level specs and those # any others passed via Opts key. # # Zero the options controlling level specs in the # Detailed section, and set all other report options # to disabled. This makes it easy via command line to # disable the entire summary section, and then re-enable # one or more sections for specific reports. # # eg. progname --nodetail --limit forwarded=2 # sub zero_opts ($ @) { my $sectref = shift; # remaining args: list of Opts keys to zero map { $Opts{$_} = 0; print "zero_opts: $_ => 0\n" if $Opts{'debug'} & D_VARS;} @_; map { $Opts{$_} = 0 } get_usable_sectvars(@$sectref, 1); } 1; #MODULE: ../Logreporters/TreeData.pm package Logreporters::TreeData; use 5.008; use strict; use re 'taint'; use warnings; no warnings "uninitialized"; BEGIN { use Exporter (); use vars qw(@ISA @EXPORT @EXPORT_OK %EXPORT_TAGS $VERSION); $VERSION = '1.001'; @ISA = qw(Exporter); @EXPORT = qw(%Totals %Counts %Collecting $END_KEY); @EXPORT_OK = qw(&printTree &buildTree); } use subs @EXPORT_OK; BEGIN { import Logreporters::Config qw(%line_styles); } # Totals and Counts are the log line accumulator hashes. # Totals: maintains per-section grand total tallies for use in Summary section # Counts: is a multi-level hash, which maintains per-level key totals. our (%Totals, %Counts); # The Collecting hash determines which sections will be captured in # the Counts hash. Counts are collected only if a section is enabled, # and this hash obviates the need to test both existence and # non-zero-ness of the Opts{'keyname'} (either of which cause capture). # XXX The Opts hash could be used .... our %Collecting = (); sub buildTree(\% $ $ $ $ $); sub printTree($ $ $ $ $); =pod [ a:b:c, ... ] which would be interpreted as follows: a = show level a detail b = show at most b items at this level c = minimum count that will be shown =cut sub printTree($ $ $ $ $) { my ($treeref, $lspecsref, $line_style, $max_report_width, $debug) = @_; my ($entry, $line); my $cutlength = $max_report_width - 3; my $topn = 0; foreach $entry (sort bycount @$treeref) { ref($entry) ne "HASH" and die "Unexpected entry in tree: $entry\n"; #print "LEVEL: $entry->{LEVEL}, TOTAL: $entry->{TOTAL}, HASH: $entry, DATA: $entry->{DATA}\n"; # Once the top N lines have been printed, we're done if ($lspecsref->[$entry->{LEVEL}]{topn}) { if ($topn++ >= $lspecsref->[$entry->{LEVEL}]{topn} ) { print ' ', ' ' x ($entry->{LEVEL} + 3), "...\n" unless ($debug) and do { $line = ' ' . ' ' x ($entry->{LEVEL} + 3) . '...'; printf "%-130s L%d: topn reached(%d)\n", $line, $entry->{LEVEL} + 1, $lspecsref->[$entry->{LEVEL}]{topn}; }; last; } } # Once the item's count falls below the given threshold, we're done at this level # unless a top N is specified, as threshold has lower priority than top N elsif ($lspecsref->[$entry->{LEVEL}]{threshold}) { if ($entry->{TOTAL} <= $lspecsref->[$entry->{LEVEL}]{threshold}) { print ' ', ' ' x ($entry->{LEVEL} + 3), "...\n" unless ($debug) and do { $line = ' ' . (' ' x ($entry->{LEVEL} + 3)) . '...'; printf "%-130s L%d: threshold reached(%d)\n", $line, $entry->{LEVEL} + 1, $lspecsref->[$entry->{LEVEL}]{threshold}; }; last; } } $line = sprintf "%8d%s%s", $entry->{TOTAL}, ' ' x ($entry->{LEVEL} + 2), $entry->{DATA}; if ($debug) { printf "%-130s %-60s\n", $line, $entry->{DEBUG}; } # line_style full, or lines < max_report_width #printf "MAX: $max_report_width, LEN: %d, CUTLEN $cutlength\n", length($line); if ($line_style == $line_styles{'full'} or length($line) <= $max_report_width) { print $line, "\n"; } elsif ($line_style == $line_styles{'truncate'}) { print substr ($line,0,$cutlength), '...', "\n"; } elsif ($line_style == $line_styles{'wrap'}) { my $leader = ' ' x 8 . ' ' x ($entry->{LEVEL} + 2); print substr ($line, 0, $max_report_width, ''), "\n"; while (length($line)) { print $leader, substr ($line, 0, $max_report_width - length($leader), ''), "\n"; } } else { die ('unexpected line style'); } printTree ($entry->{CHILDREF}, $lspecsref, $line_style, $max_report_width, $debug) if (exists $entry->{CHILDREF}); } } my $re_IP_strict = qr/\b(25[0-5]|2[0-4]\d|[01]?\d{1,2})\.(25[0-5]|2[0-4]\d|[01]?\d{1,2})\.(25[0-5]|2[0-4]\d|[01]?\d{1,2})\.(25[0-5]|2[0-4]\d|[01]?\d{1,2})\b/; # XXX optimize this using packed default sorting. Analysis shows speed isn't an issue though sub bycount { # Sort by totals, then IP address if one exists, and finally by data as a string local $SIG{__WARN__} = sub { print "*** PLEASE REPORT:\n*** $_[0]*** Unexpected: \"$a->{DATA}\", \"$b->{DATA}\"\n" }; $b->{TOTAL} <=> $a->{TOTAL} || pack('C4' => $a->{DATA} =~ /^$re_IP_strict/o) cmp pack('C4' => $b->{DATA} =~ /^$re_IP_strict/o) || $a->{DATA} cmp $b->{DATA} } # # Builds a tree of REC structures from the multi-key %Counts hashes # # Parameters: # Hash: A multi-key hash, with keys being used as category headings, and leaf data # being tallies for that set of keys # Level: This current recursion level. Call with 0. # # Returns: # Listref: A listref, where each item in the list is a rec record, described as: # DATA: a string: a heading, or log data # TOTAL: an integer: which is the subtotal of this item's children # LEVEL: an integer > 0: representing this entry's level in the tree # CHILDREF: a listref: references a list consisting of this node's children # Total: The cumulative total of items found for a given invocation # # Use the special key variable $END_KEY, which is "\a\a" (two ASCII bell's) to end a, # nested hash early, or the empty string '' may be used as the last key. our $END_KEY = "\a\a"; sub buildTree(\% $ $ $ $ $) { my ($href, $max_level_section, $levspecref, $max_level_global, $recurs_level, $show_unique, $debug) = @_; my ($subtotal, $childList, $rec); my @treeList = (); my $total = 0; foreach my $item (sort keys %$href) { if (ref($href->{$item}) eq "HASH") { #print " " x ($recurs_level * 4), "HASH: LEVEL $recurs_level: Item: $item, type: \"", ref($href->{$item}), "\"\n"; ($subtotal, $childList) = buildTree (%{$href->{$item}}, $max_level_section, $levspecref, $max_level_global, $recurs_level + 1, $debug); if ($recurs_level < $max_level_global and $recurs_level < $max_level_section) { # me + children $rec = { DATA => $item, TOTAL => $subtotal, LEVEL => $recurs_level, CHILDREF => $childList, }; if ($debug) { $rec->{DEBUG} = sprintf "L%d: levelspecs: %2d/%2d/%2d/%2d, Count: %10d", $recurs_level + 1, $max_level_global, $max_level_section, $levspecref->[$recurs_level]{topn}, $levspecref->[$recurs_level]{threshold}, $subtotal; } push (@treeList, $rec); } } else { if ($item ne '' and $item ne $END_KEY and $recurs_level < $max_level_global and $recurs_level < $max_level_section) { $rec = { DATA => $item, TOTAL => $href->{$item}, LEVEL => $recurs_level, #CHILDREF => undef, }; if ($debug) { $rec->{DEBUG} = sprintf "L%d: levelspecs: %2d/%2d/%2d/%2d, Count: %10d", $recurs_level, $max_level_global, $max_level_section, $levspecref->[$recurs_level]{topn}, $levspecref->[$recurs_level]{threshold}, $href->{$item}; } push (@treeList, $rec); } $subtotal = $href->{$item}; } $total += $subtotal; } #print " " x ($recurs_level * 4), "LEVEL $recurs_level: Returning from recurs_level $recurs_level\n"; return ($total, \@treeList); } 1; #MODULE: ../Logreporters/RegEx.pm package Logreporters::RegEx; use 5.008; use strict; use re 'taint'; use warnings; BEGIN { use Exporter (); use vars qw(@ISA @EXPORT @EXPORT_OK %EXPORT_TAGS $VERSION); $VERSION = '1.000'; @ISA = qw(Exporter); # @EXPORT = qw($re_IP); @EXPORT_OK = qw(); } # IPv4 and IPv6 # See syntax in RFC 2821 IPv6-address-literal, # eg. IPv6:2001:630:d0:f102:230:48ff:fe77:96e #our $re_IP = '(?:(?:::(?:ffff:|FFFF:)?)?(?:\d{1,3}\.){3}\d{1,3}|(?:(?:IPv6:)?[\da-fA-F]{0,4}:){2}(?:[\da-fA-F]{0,4}:){0,5}[\da-fA-F]{0,4})'; # Modified from "dartware" case at http://forums.dartware.com/viewtopic.php?t=452# #our $re_IP = qr/(?:(?:(?:(?:[\da-f]{1,4}:){7}(?:[\da-f]{1,4}|:))|(?:(?:[\da-f]{1,4}:){6}(?::[\da-f]{1,4}|(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(?:(?:[\da-f]{1,4}:){5}(?:(?:(?::[\da-f]{1,4}){1,2})|:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(?:(?:[\da-f]{1,4}:){4}(?:(?:(?::[\da-f]{1,4}){1,3})|(?:(?::[\da-f]{1,4})?:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(?:(?:[\da-f]{1,4}:){3}(?:(?:(?::[\da-f]{1,4}){1,4})|(?:(?::[\da-f]{1,4}){0,2}:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(?:(?:[\da-f]{1,4}:){2}(?:(?:(?::[\da-f]{1,4}){1,5})|(?:(?::[\da-f]{1,4}){0,3}:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(?:(?:[\da-f]{1,4}:){1}(?:(?:(?::[\da-f]{1,4}){1,6})|(?:(?::[\da-f]{1,4}){0,4}:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(?::(?:(?:(?::[\da-f]{1,4}){1,7})|(?:(?::[\da-f]{1,4}){0,5}:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(?:%.+)?)|(?:(?:\d{1,3}\.){3}(?:\d{1,3}))/i; # IPv4 only #our $re_IP = qr/(?:\d{1,3}\.){3}(?:\d{1,3})/; 1; #MODULE: ../Logreporters/Reports.pm package Logreporters::Reports; use 5.008; use strict; use re 'taint'; use warnings; no warnings "uninitialized"; BEGIN { use Exporter (); use vars qw(@ISA @EXPORT @EXPORT_OK %EXPORT_TAGS $VERSION); $VERSION = '1.002'; @ISA = qw(Exporter); @EXPORT = qw(&inc_unmatched &print_unmatched_report &print_percentiles_report2 &print_summary_report &print_detail_report); @EXPORT_OK = qw(); } use subs @EXPORT_OK; BEGIN { import Logreporters::Config qw(%Opts $fw1 $fw2 $sep1 $sep2 &D_UNMATCHED &D_TREE); import Logreporters::Utils qw(&commify &unitize &get_percentiles &get_percentiles2); import Logreporters::TreeData qw(%Totals %Counts &buildTree &printTree); } my (%unmatched_list); our $origline; # unmodified log line, for error reporting and debug sub inc_unmatched($) { my ($id) = @_; $unmatched_list{$origline}++; print "UNMATCHED($id): \"$origline\"\n" if $Opts{'debug'} & D_UNMATCHED; } # Print unmatched lines # sub print_unmatched_report() { return unless (keys %unmatched_list); print "\n\n**Unmatched Entries**\n"; foreach my $line (sort {$unmatched_list{$b}<=>$unmatched_list{$a} } keys %unmatched_list) { printf "%8d %s\n", $unmatched_list{$line}, $line; } } =pod ****** Summary ******************************************************** 2 Miscellaneous warnings 20621 Total messages scanned ---------------- 100.00% 662.993M Total bytes scanned 695,198,092 ======== ================================================ 19664 Ham ----------------------------------- 95.36% 19630 Clean passed 95.19% 34 Bad header passed 0.16% 942 Spam ---------------------------------- 4.57% 514 Spam blocked 2.49% 428 Spam discarded (no quarantine) 2.08% 15 Malware ------------------------------- 0.07% 15 Malware blocked 0.07% 1978 SpamAssassin bypassed 18 Released from quarantine 1982 Whitelisted 3 Blacklisted 12 MIME error 51 Bad header (debug supplemental) 28 Extra code modules loaded at runtime =cut # Prints the Summary report section # sub print_summary_report (\@) { my ($sections) = @_; my ($keyname,$cur_level); my @lines; my $expand_header_footer = sub { my $line = undef; foreach my $horf (@_) { # print blank line if keyname is newline if ($horf eq "\n") { $line .= "\n"; } elsif (my ($sepchar) = ($horf =~ /^(.)$/o)) { $line .= sprintf "%s %s\n", $sepchar x 8, $sepchar x 50; } else { die "print_summary_report: unsupported header or footer type \"$horf\""; } } return $line; }; if ($Opts{'detail'} >= 5) { my $header = "****** Summary "; print $header, '*' x ($Opts{'max_report_width'} - length $header), "\n\n"; } my @headers; foreach my $sref (@$sections) { # headers and separators die "Unexpected Section $sref" if (ref($sref) ne 'HASH'); # Start of a new section group. # Expand and save headers to output at end of section group. if ($sref->{CLASS} eq 'GROUP_BEGIN') { $cur_level = $sref->{LEVEL}; $headers[$cur_level] = &$expand_header_footer(@{$sref->{HEADERS}}); } elsif ($sref->{CLASS} eq 'GROUP_END') { my $prev_level = $sref->{LEVEL}; # If this section had lines to output, tack on headers and footers, # removing extraneous newlines. if ($lines[$cur_level]) { # squish multiple blank lines if ($headers[$cur_level] and substr($headers[$cur_level],0,1) eq "\n") { if ( ! defined $lines[$prev_level][-1] or $lines[$prev_level][-1] eq "\n") { $headers[$cur_level] =~ s/^\n+//; } } push @{$lines[$prev_level]}, $headers[$cur_level] if $headers[$cur_level]; push @{$lines[$prev_level]}, @{$lines[$cur_level]}; my $f = &$expand_header_footer(@{$sref->{FOOTERS}}); push @{$lines[$prev_level]}, $f if $f; $lines[$cur_level] = undef; } $headers[$cur_level] = undef; $cur_level = $prev_level; } elsif ($sref->{CLASS} eq 'DATA') { # Totals data $keyname = $sref->{NAME}; if ($Totals{$keyname} > 0) { my ($numfmt, $desc, $divisor) = ($sref->{FMT}, $sref->{TITLE}, $sref->{DIVISOR}); my $fmt = '%8'; my $extra = ' %11s'; my $total = $Totals{$keyname}; # Z format provides unitized or unaltered totals, as appropriate if ($numfmt eq 'Z') { ($total, $fmt) = unitize ($total, $fmt); } else { $fmt .= "$numfmt "; } if ($divisor and $$divisor) { # XXX generalize this if (ref ($desc) eq 'ARRAY') { $desc = @$desc[0] . ' ' . @$desc[1] x (42 - 2 - length(@$desc[0])); } push @{$lines[$cur_level]}, sprintf "$fmt %-42s %6.2f%%\n", $total, $desc, $$divisor == $Totals{$keyname} ? 100.00 : $Totals{$keyname} * 100 / $$divisor; } else { push @{$lines[$cur_level]}, sprintf "$fmt %-37s $extra\n", $total, $desc, commify ($Totals{$keyname}); } } } else { die "print_summary_report: unexpected control..."; } } print @{$lines[0]}; print "\n"; } # Prints the Detail report section # # Note: side affect; deletes each key in Totals/Counts # after printout. Only the first instance of a key in # the Section table will result in Detail output. sub print_detail_report (\@) { my ($sections) = @_; my $header_printed = 0; return unless (keys %Counts); #use Devel::Size qw(size total_size); foreach my $sref ( @$sections ) { next unless $sref->{CLASS} eq 'DATA'; # only print detail for this section if DETAIL is enabled # and there is something in $Counts{$keyname} next unless $sref->{DETAIL}; next unless exists $Counts{$sref->{NAME}}; my $keyname = $sref->{NAME}; my $max_level = undef; my $print_this_key = 0; my @levelspecs = (); clear_level_specs($max_level, \@levelspecs); if (exists $Opts{$keyname}) { $max_level = create_level_specs($Opts{$keyname}, $Opts{'detail'}, \@levelspecs); $print_this_key = 1 if ($max_level); } else { $print_this_key = 1; } #print_level_specs($max_level,\@levelspecs); # at detail 5, print level 1, detail 6: level 2, ... #print STDERR "building: $keyname\n"; my ($count, $treeref) = buildTree (%{$Counts{$keyname}}, defined ($max_level) ? $max_level : 11, \@levelspecs, $Opts{'detail'} - 4, 0, $Opts{'debug'} & D_TREE); if ($count > 0) { if ($print_this_key) { my $desc = $sref->{TITLE}; $desc =~ s/^\s+//; if (! $header_printed) { my $header = "****** Detail ($max_level) "; print $header, '*' x ($Opts{'max_report_width'} - length $header), "\n"; $header_printed = 1; } printf "\n%8d %s %s\n", $count, $desc, $Opts{'sect_vars'} ? ('-' x ($Opts{'max_report_width'} - 18 - length($desc) - length($keyname))) . " [ $keyname ] -" : '-' x ($Opts{'max_report_width'} - 12 - length($desc)) } printTree ($treeref, \@levelspecs, $Opts{'line_style'}, $Opts{'max_report_width'}, $Opts{'debug'} & D_TREE); } #print STDERR "Total size Counts: ", total_size(\%Counts), "\n"; #print STDERR "Total size Totals: ", total_size(\%Totals), "\n"; $treeref = undef; $Totals{$keyname} = undef; delete $Totals{$keyname}; delete $Counts{$keyname}; } #print "\n"; } =pod Print out a standard percentiles report === Delivery Delays Percentiles =============================================================== 0% 25% 50% 75% 90% 95% 98% 100% ----------------------------------------------------------------------------------------------- Before qmgr 0.01 0.70 1.40 45483.70 72773.08 81869.54 87327.42 90966.00 In qmgr 0.00 0.00 0.00 0.01 0.01 0.01 0.01 0.01 Conn setup 0.00 0.00 0.00 0.85 1.36 1.53 1.63 1.70 Transmission 0.03 0.47 0.92 1.61 2.02 2.16 2.24 2.30 Total 0.05 1.18 2.30 45486.15 72776.46 81873.23 87331.29 90970.00 =============================================================================================== === Postgrey Delays Percentiles =========================================================== 0% 25% 50% 75% 90% 95% 98% 100% ------------------------------------------------------------------------------------------- Postgrey 727.00 727.00 727.00 727.00 727.00 727.00 727.00 727.00 =========================================================================================== tableref: data table: ref to array of arrays, first cell is label, subsequent cells are data title: table's title percentiles_str: string of space or comma separated integers, which are the percentiles calculated and output as table column data =cut sub print_percentiles_report2($$$) { my ($tableref, $title, $percentiles_str) = @_; return unless @$tableref; my $myfw2 = $fw2 - 1; my @percents = split /[ ,]/, $percentiles_str; # Calc y label width from the hash's keys. Each key is padded with the # string "#: ", # where # is a single-digit sort index. my $y_label_max_width = 0; for (@$tableref) { $y_label_max_width = length($_->[0]) if (length($_->[0]) > $y_label_max_width); } # Titles row my $col_titles_str = sprintf "%-${y_label_max_width}s" . "%${myfw2}s%%" x @percents , ' ', @percents; my $table_width = length($col_titles_str); # Table header row my $table_header_str = sprintf "%s %s ", $sep1 x 3, $title; $table_header_str .= $sep1 x ($table_width - length($table_header_str)); print "\n", $table_header_str; print "\n", $col_titles_str; print "\n", $sep2 x $table_width; my (@p, @coldata, @xformed); foreach (@$tableref) { my ($title, $ref) = ($_->[0], $_->[1]); #xxx my @sorted = sort { $a <=> $b } @{$_->[1]}; my @byscore = (); for my $bucket (sort { $a <=> $b } keys %$ref) { #print "Key: $title: Bucket: $bucket = $ref->{$bucket}\n"; # pairs: bucket (i.e. key), tally push @byscore, $bucket, $ref->{$bucket}; } my @p = get_percentiles2 (@byscore, @percents); printf "\n%-${y_label_max_width}s" . "%${fw2}.2f" x scalar (@p), $title, @p; } =pod foreach (@percents) { #printf "\n%-${y_label_max_width}s" . "%${fw2}.2f" x scalar (@p), substr($title,3), @p; printf "\n%3d%%", $title; foreach my $val (@{shift @xformed}) { my $unit; if ($val > 1000) { $unit = 's'; $val /= 1000; } else { $unit = ''; } printf "%${fw3}.2f%-2s", $val, $unit; } } =cut print "\n", $sep1 x $table_width, "\n"; } sub clear_level_specs($ $) { my ($max_level,$lspecsref) = @_; #print "Zeroing $max_level rows of levelspecs\n"; $max_level = 0 if (not defined $max_level); for my $x (0..$max_level) { $lspecsref->[$x]{topn} = undef; $lspecsref->[$x]{threshold} = undef; } } # topn = 0 means don't limit # threshold = 0 means no min threshold sub create_level_specs($ $ $) { my ($optkey,$gdetail,$lspecref) = @_; return 0 if ($optkey eq "0"); my $max_level = $gdetail; # default to global detail level my (@specsP1, @specsP2, @specsP3); #printf "create_level_specs: key: %s => \"%s\", max_level: %d\n", $optkey, $max_level; foreach my $sp (split /[\s,]+/, $optkey) { #print "create_level_specs: SP: \"$sp\"\n"; # original level specifier if ($sp =~ /^\d+$/) { $max_level = $sp; #print "create_level_specs: max_level set: $max_level\n"; } # original level specifier + topn at level 1 elsif ($sp =~ /^(\d*)\.(\d+)$/) { if ($1) { $max_level = $1; } else { $max_level = $gdetail; } # top n specified, but no max level # force top N at level 1 (zero based) push @specsP1, { level => 0, topn => $2, threshold => 0 }; } # newer level specs elsif ($sp =~ /^::(\d+)$/) { push @specsP3, { level => undef, topn => 0, threshold => $1 }; } elsif ($sp =~ /^:(\d+):(\d+)?$/) { push @specsP2, { level => undef, topn => $1, threshold => defined $2 ? $2 : 0 }; } elsif ($sp =~ /^(\d+):(\d+)?:(\d+)?$/) { push @specsP1, { level => ($1 > 0 ? $1 - 1 : 0), topn => $2 ? $2 : 0, threshold => $3 ? $3 : 0 }; } else { print STDERR "create_level_specs: unexpected levelspec ignored: \"$sp\"\n"; } } #foreach my $sp (@specsP3, @specsP2, @specsP1) { # printf "Sorted specs: L%d, topn: %3d, threshold: %3d\n", $sp->{level}, $sp->{topn}, $sp->{threshold}; #} my ($min, $max); foreach my $sp ( @specsP3, @specsP2, @specsP1) { ($min, $max) = (0, $max_level); if (defined $sp->{level}) { $min = $max = $sp->{level}; } for my $level ($min..$max) { #printf "create_level_specs: setting L%d, topn: %s, threshold: %s\n", $level, $sp->{topn}, $sp->{threshold}; $lspecref->[$level]{topn} = $sp->{topn} if ($sp->{topn}); $lspecref->[$level]{threshold} = $sp->{threshold} if ($sp->{threshold}); } } return $max_level; } sub print_level_specs($ $) { my ($max_level,$lspecref) = @_; for my $level (0..$max_level) { printf "LevelSpec Row %d: %3d %3d\n", $level, $lspecref->[$level]{topn}, $lspecref->[$level]{threshold}; } } 1; #MODULE: ../Logreporters/RFC3463.pm package Logreporters::RFC3463; use 5.008; use strict; use re 'taint'; use warnings; BEGIN { use Exporter (); use vars qw(@ISA @EXPORT @EXPORT_OK %EXPORT_TAGS $VERSION); $VERSION = '1.000'; @ISA = qw(Exporter); @EXPORT = qw(&get_dsn_msg); } use subs @EXPORT; #------------------------------------------------- # Enhanced Mail System Status Codes (aka: extended status codes) # # RFC 3463 http://www.ietf.org/rfc/rfc3463.txt # RFC 4954 http://www.ietf.org/rfc/rfc4954.txt # # Class.Subject.Detail # my %dsn_codes = ( class => { '2' => 'Success', '4' => 'Transient failure', '5' => 'Permanent failure', }, subject => { '0' => 'Other/Undefined status', '1' => 'Addressing status', '2' => 'Mailbox status', '3' => 'Mail system status', '4' => 'Network & routing status', '5' => 'Mail delivery protocol status', '6' => 'Message content/media status', '7' => 'Security/policy status', }, detail => { '0.0' => 'Other undefined status', '1.0' => 'Other address status', '1.1' => 'Bad destination mailbox address', '1.2' => 'Bad destination system address', '1.3' => 'Bad destination mailbox address syntax', '1.4' => 'Destination mailbox address ambiguous', '1.5' => 'Destination mailbox address valid', '1.6' => 'Mailbox has moved', '1.7' => 'Bad sender\'s mailbox address syntax', '1.8' => 'Bad sender\'s system address', '2.0' => 'Other/Undefined mailbox status', '2.1' => 'Mailbox disabled, not accepting messages', '2.2' => 'Mailbox full', '2.3' => 'Message length exceeds administrative limit.', '2.4' => 'Mailing list expansion problem', '3.0' => 'Other/Undefined mail system status', '3.1' => 'Mail system full', '3.2' => 'System not accepting network messages', '3.3' => 'System not capable of selected features', '3.4' => 'Message too big for system', '4.0' => 'Other/Undefined network or routing status', '4.1' => 'No answer from host', '4.2' => 'Bad connection', '4.3' => 'Routing server failure', '4.4' => 'Unable to route', '4.5' => 'Network congestion', '4.6' => 'Routing loop detected', '4.7' => 'Delivery time expired', '5.0' => 'Other/Undefined protocol status', '5.1' => 'Invalid command', '5.2' => 'Syntax error', '5.3' => 'Too many recipients', '5.4' => 'Invalid command arguments', '5.5' => 'Wrong protocol version', '5.6' => 'Authentication Exchange line too long', '6.0' => 'Other/Undefined media error', '6.1' => 'Media not supported', '6.2' => 'Conversion required & prohibited', '6.3' => 'Conversion required but not supported', '6.4' => 'Conversion with loss performed', '6.5' => 'Conversion failed', '7.0' => 'Other/Undefined security status', '7.1' => 'Delivery not authorized, message refused', '7.2' => 'Mailing list expansion prohibited', '7.3' => 'Security conversion required but not possible', '7.4' => 'Security features not supported', '7.5' => 'Cryptographic failure', '7.6' => 'Cryptographic algorithm not supported', '7.7' => 'Message integrity failure', }, # RFC 4954 complete => { '2.7.0' => 'Authentication succeeded', '4.7.0' => 'Temporary authentication failure', '4.7.12' => 'Password transition needed', '5.7.0' => 'Authentication required', '5.7.8' => 'Authentication credentials invalid', '5.7.9' => 'Authentication mechanism too weak', '5.7.11' => 'Encryption required for requested authentication mechanism', }, ); # Returns an RFC 3463 DSN messages given a DSN code # sub get_dsn_msg ($) { my $dsn = shift; my ($msg, $class, $subject, $detail); return "*DSN unavailable" if ($dsn =~ /^$/); unless ($dsn =~ /^(\d)\.((\d{1,3})\.\d{1,3})$/) { print "Error: not a DSN code $dsn\n"; return "Invalid DSN"; } $class = $1; $subject = $3; $detail = $2; #print "DSN: $dsn, Class: $class, Subject: $subject, Detail: $detail\n"; if (exists $dsn_codes{'class'}{$class}) { $msg = $dsn_codes{'class'}{$class}; } if (exists $dsn_codes{'subject'}{$subject}) { $msg .= ': ' . $dsn_codes{'subject'}{$subject}; } if (exists $dsn_codes{'complete'}{$dsn}) { $msg .= ': ' . $dsn_codes{'complete'}{$dsn}; } elsif (exists $dsn_codes{'detail'}{$detail}) { $msg .= ': ' . $dsn_codes{'detail'}{$detail}; } #print "get_dsn_msg: $msg\n" if ($msg); return $dsn . ': ' . $msg; } 1; #MODULE: ../Logreporters/PolicySPF.pm package Logreporters::PolicySPF; use 5.008; use strict; use re 'taint'; use warnings; BEGIN { use Exporter (); use vars qw(@ISA @EXPORT @EXPORT_OK %EXPORT_TAGS $VERSION); $VERSION = '1.000'; @ISA = qw(Exporter); @EXPORT = qw(&postfix_policy_spf); } use subs @EXPORT; BEGIN { import Logreporters::TreeData qw(%Totals %Counts $END_KEY); import Logreporters::Utils; import Logreporters::Reports qw(&inc_unmatched); } # Handle postfix/policy_spf entries # # Mail::SPF::Result # Pass the SPF record designates the host to be allowed to send accept # Fail the SPF record has designated the host as NOT being allowed to send reject # SoftFail the SPF record has designated the host as NOT being allowed to send but is in transition accept but mark # Neutral the SPF record specifies explicitly that nothing can be said about validity accept # None the domain does not have an SPF record or the SPF record does not evaluate to a result accept # PermError a permanent error has occured (eg. badly formatted SPF record) unspecified # TempError a transient error has occured accept or reject sub postfix_policy_spf($) { my $line = shift; if ( $line =~ /^Attribute: / or # handler sender_policy_framework: is decisive. $line =~ /^handler [^:]+/ or # decided action=REJECT Please see http://www.openspf.org/why.html?sender=jrzjcez%40telecomitalia.it&ip=81.178.62.236&receiver=protegate1.zmi.at $line =~ /^decided action=/ or # pypolicyd-spf-0.7.1 # # Read line: "request=smtpd_access_policy" # Found the end of entry # Config: {'Mail_From_reject': 'Fail', 'PermError_reject': 'False', 'HELO_reject': 'SPF_Not_Pass', 'defaultSeedOnly': 1, 'debugLevel': 4, 'skip_addresses': '127.0.0.0/8,::ffff:127.0.0.0//104,::1//128', 'TempError_Defer': 'False'} # spfcheck: pyspf result: "['Pass', 'sender SPF authorized', 'helo']" # ERROR: Could not match line "#helo pass and mfrom none" # Traceback (most recent call last): # File "/usr/local/bin/policyd-spf", line 405, in # line = sys.stdin.readline() # KeyboardInterrupt $line =~ /^Read line: "/ or $line =~ /^Found the end of entry$/ or $line =~ /^Config: \{/ or $line =~ /^spfcheck: pyspf result/ or $line =~ /^Starting$/ or $line =~ /^Normal exit$/ or $line =~ /^ERROR: Could not match line/ or $line =~ /^Traceback / or $line =~ /^KeyboardInterrupt/ or $line =~ /^\s\s+/ ) { #print "IGNORING...\n\tORIG: $::OrigLine\n"; return } # Keep policy-spf warnings in its section if (my ($warn,$msg) = $line =~ /^warning: ([^:]+): (.*)$/) { #TDspf warning: ignoring garbage: # No SPF $msg =~ s/^# ?//; $Totals{'policyspf'}++; $Counts{'policyspf'}{'*Warning'}{ucfirst $warn}{$msg}{$END_KEY}++ if ($Logreporters::TreeData::Collecting{'policyspf'}); return; } # pypolicyd-spf-0.7.1 # Fail; identity=helo; client-ip=192.168.0.1; helo=example.com; envelope-from=f@example.com; receiver=bogus2@example.net # Fail; identity=helo; client-ip=192.168.0.2; helo=example.com; envelope-from=<>; receiver=bogus@example.net # Neutral; identity=helo; client-ip=192.168.0.3; helo=example.com; envelope-from=f@example.com; receiver=bogus2@example.net # None; identity=helo; client-ip=192.168.0.4; helo=example.com; envelope-from=f@example.com; receiver=bogus2@example.net # None; identity=helo; client-ip=192.168.0.5; helo=example.com; envelope-from=f@example.com; receiver=bogus2@example.net # None; identity=mailfrom; client-ip=192.168.0.1; helo=example.com; envelope-from=f@example.com; receiver=bogus2@example.net # None; identity=mailfrom; client-ip=192.168.0.2; helo=example.com; envelope-from=f@example.com; receiver=bogus2@example.net # Pass; identity=helo; client-ip=192.168.0.2; helo=example.com; envelope-from=<>; receiver=bogus@example.net # Permerror; identity=helo; client-ip=192.168.0.4; helo=example.com; envelope-from=f@example.com; receiver=bogus2@example.net # Softfail; identity=mailfrom; client-ip=192.168.0.6; helo=example.com; envelope-from=f@example.com; receiver=yahl@example.org if ($line =~ /^(?:prepend Received-SPF: )?(Pass|Fail|None|Neutral|Permerror|Softfail|Temperror);? (.*)$/) { my $result = $1; my %params = $2 =~ /([-\w]+)=([^;]+)/g; #$params{'s'} = '*unknown' unless $params{'s'}; $Totals{'policyspf'}++; if ($Logreporters::TreeData::Collecting{'policyspf'}) { my ($id) = $params{'identity'}; $id =~ s/mailfrom/envelope-from/; $Counts{'policyspf'}{'Policy Action'}{"SPF: $result"}{join(': ',$params{'identity'},$params{$id})}{$params{'client-ip'}}{$params{'receiver'}}++; } return; } elsif ($line =~ /^ERROR /) { $line =~ s/^ERROR //; $Totals{'warningsother'}++; return unless ($Logreporters::TreeData::Collecting{'warningsother'}); $Counts{'warningsother'}{"$Logreporters::service_name: $line"}++; return; } # Strip QID if it exists, and trailing ": ", leaving just the message. $line =~ s/^(?:$Logreporters::re_QID|): //; # other ignored if ( $line =~ /^SPF \S+ \(.+?\): .*$/ or $line =~ /^Mail From/ or $line =~ /^:HELO check failed/ or # log entry has no space after : $line =~ /^testing:/ ) { #TDspf testing: stripped sender=jrzjcez@telecomitalia.it, stripped rcpt=hengstberger@adv.at # postfix-policyd-spf-perl-2.007 #TDspf SPF pass (Mechanism 'ip4:10.0.0.2/22' matched): Envelope-from: foo@example.com #TDspf SPF pass (Mechanism 'ip4:10.10.10.10' matched): Envelope-from: anyone@sample.net #TDspf SPF pass (Mechanism 'ip4:10.10.10.10' matched): HELO/EHLO (Null Sender): mailout2.example.com #TDspf SPF fail (Mechanism '-all' matched): HELO/EHLO: mailout1.example.com #TDspf SPF none (No applicable sender policy available): Envelope-from: efrom@example.com #TDspf SPF permerror (Included domain 'example.com' has no applicable sender policy): Envelope-from: efrom@example.com #TDspf SPF permerror (Maximum DNS-interactive terms limit (10) exceeded): Envelope-from: efrom@example.com #TDspf Mail From (sender) check failed - Mail::SPF->new(10.0.0.1, , test.DNSreport.com) failed: 'identity' option must not be empty #TDspf HELO check failed - Mail::SPF->new(, , ) failed: Missing required 'identity' option #TDspf SPF not applicable to localhost connection - skipped check #print "IGNORING...\n\tLINE: $line\n\tORIG: \"$Logreporters::Reports::origline\"\n"; return; } my ($action, $domain, $ip, $message, $mechanism); ($domain, $ip, $message, $mechanism) = ('*unknown', '*unknown', '', '*unavailable'); #print "LINE: '$line'\n"; # postfix-policyd-spf-perl: http://www.openspf.org/Software if ($line =~ /^Policy action=(.*)$/) { $line = $1; #: Policy action=DUNNO return if $line =~ /^DUNNO/; # Policy action=PREPEND X-Comment: SPF not applicable to localhost connection - skipped check return if $line =~ /^PREPEND X-Comment: SPF not applicable to localhost connection - skipped check$/; #print "LINE: '$line'\n"; if ($line =~ /^DEFER_IF_PERMIT SPF-Result=\[?(.*?)\]?: (.*) of .*$/) { my ($lookup,$message) = ($1,$2); # Policy action=DEFER_IF_PERMIT SPF-Result=[10.0.0.1]: Time-out on DNS 'SPF' lookup of '[10.0.0.1]' # Policy action=DEFER_IF_PERMIT SPF-Result=example.com: 'SERVFAIL' error on DNS 'SPF' lookup of 'example.com' $message =~ s/^(.*?) on (DNS SPF lookup)$/$2: $1/; $message =~ s/'//g; $Totals{'policyspf'}++; $Counts{'policyspf'}{'Policy Action'}{'defer_if_permit'}{$message}{$lookup}{$END_KEY}++ if ($Logreporters::TreeData::Collecting{'policyspf'}); return; } if ($line =~ m{^550(?: \d\.\d\.\d+)? Please see http://www.openspf.(?:org|net)/Why\?(.*)$}) { # Policy action=550 Please see http://www.openspf.org/Why?s=mfrom&id=from%40example.com&ip=10.0.0.1&r=example.net # Policy action=550 Please see http://www.openspf.org/Why?s=helo;id=mailout03.example.com;ip=192.168.0.1;r=mx1.example.net # Policy action=550 Please see http://www.openspf.org/Why?id=someone%40example.com&ip=10.0.0.1&receiver=vps.example.net # Policy action=550 Please see http://www.openspf.net/Why?s=helo;id=example.com;ip=10.0.0.1;r=example.net my %params; for (split /[&;]/, $1) { my ($id,$val) = split /=/, $_; $params{$id} = $val; } $params{'id'} =~ s/^.*%40//; $params{'s'} = '*unknown' unless $params{'s'}; #print "Please see...:\n\tMessage: $message\n\tIP: $ip\n\tDomain: $domain\n"; $Totals{'policyspf'}++; $Counts{'policyspf'}{'Policy Action'}{'550 reject'}{'See http://www.openspf.org/Why?...'}{$params{'s'}}{$params{'ip'}}{$params{'id'}}++ if ($Logreporters::TreeData::Collecting{'policyspf'}); return; } if ($line =~ /^[^:]+: (none|pass|fail|softfail|neutral|permerror|temperror) \((.+?)\) receiver=[^;]+(?:; (.*))?$/) { # iehc is identity, envelope-from, helo, client-ip my ($result,$message,$iehc,$subject) = ($1,$2,$3,undef); my %params = (); #TDspf Policy action=PREPEND Received-SPF: pass (bounces.example.com ... _spf.example.com: 10.0.0.1 is authorized to use 'from@bounces.example.com' in 'mfrom' identity (mechanism 'ip4:10.0.0.1/24' matched)) receiver=sample.net; identity=mfrom; envelope-from="from@bounces.example.com"; helo=out.example.com; client-ip=10.0.0.1 # Note: "identity=mailfrom" new in Mail::SPF version 2.006 Aug. 17 #TDspf Policy action=PREPEND Received-SPF: pass (example.com: 10.0.0.1 is authorized to use 'from@example.com' in 'mfrom' identity (mechanism 'ip4:10.0.0.0/24' matched)) receiver=mx.example.com; identity=mailfrom; envelope-from="from@example.com"; helo=example.com; client-ip=10.0.0.1 #TDspf Policy action=PREPEND Received-SPF: none (example.com: No applicable sender policy available) receiver=sample.net; identity=mfrom; envelope-from="f@example.com"; helo=example.com; client-ip=10.0.0.1 #TDspf Policy action=PREPEND Received-SPF: neutral (example.com: Domain does not state whether sender is authorized to use 'f@example.com' in 'mfrom' identity (mechanism '?all' matched)) receiver=sample.net identity=mfrom; envelope-from="f@example.com"; helo="[10.0.0.1]"; client-ip=192.168.0.1 #TDspf Policy action=PREPEND Received-SPF: none (example.com: No applicable sender policy available) receiver=sample.net; identity=helo; helo=example.com; client-ip=192.168.0.1 #TDspf Policy action=PREPEND Received-SPF: none (example.com: No applicable sender policy available) receiver=mx1.example #print "LINE: $iehc\n"; if ($iehc) { %params = $iehc =~ /([-\w]+)=([^;]+)/g; if (exists $params{'identity'}) { $params{'identity'} =~ s/identity=//; if ($params{'identity'} eq 'mfrom' or $params{'identity'} eq 'mailfrom') { $params{'identity'} = 'mail from'; } $params{'identity'} = uc $params{'identity'}; } $params{'envelope-from'} =~ s/"//g if exists $params{'envelope-from'}; #($helo = $params{'helo'}) =~ s/"//g if exists $params{'helo'}; $ip = $params{'client-ip'} if exists $params{'client-ip'}; } $message =~ s/^([^:]+): // and $subject = $1; if ($message =~ /^No applicable sender policy available$/) { $message = 'No sender policy'; } elsif ($message =~ s/^(Junk encountered in mechanism) '(.*?)'/$1/) { #TDspf Policy action=PREPEND Received-SPF: permerror (example.com: Junk encountered in mechanism 'a:10.0.0.1') receiver=example.net; identity=mfrom; envelope-from="ef@example.com"; helo=h; client-ip=10.0.0.2 $ip = formathost ($ip, 'mech: ' . $2); } elsif ($message =~ s/^(Included domain) '(.*?)' (has no .*)$/$1 $3/) { #TDspf Policy action=PREPEND Received-SPF: permerror (example.com: Included domain 's.example.net' has no applicable sender policy) receiver=x.sample.com; identity=mfrom; envelope-from="ef@example.com"; helo=example.net; client-ip=10.0.0.2 $subject .= " (included: $2)"; } elsif ($message =~ /^Domain does not state whether sender is authorized to use '.*?' in '\S+' identity \(mechanism '(.+?)' matched\)$/) { # Domain does not state whether sender is authorized to use 'returns@example.com' in 'mfrom' identity (mechanism '?all' matched)) ($mechanism,$message) = ($1,'Domain does not state if sender authorized to use'); } elsif ($message =~ /^(\S+) is (not )?authorized( by default)? to use '.*?' in '\S+' identity(?:, however domain is not currently prepared for false failures)? \(mechanism '(.+?)' matched\)$/) { # Sender is not authorized by default to use 'from@example.com' in 'mfrom' identity, however domain is not currently prepared for false failures (mechanism '~all' matched)) # 192.168.1.10 is authorized by default to use 'from@example.com' in 'mfrom' identity (mechanism 'all' matched)) $message = join (' ', $1 eq 'Sender' ? 'Sender' : 'IP', # canonicalize IP address $2 ? 'not authorized' : 'authorized', $3 ? 'by default to use' : 'to use', ); $mechanism = $4; } elsif ($message =~ /^Maximum DNS-interactive terms limit \S+ exceeded$/) { $message = 'Maximum DNS-interactive terms limit exceeded'; } elsif ($message =~ /^Invalid IPv4 prefix length encountered in (.*)$/) { $subject .= " (invalid: $1)"; $message = 'Invalid IPv4 prefix length encountered'; } #print "Result: $result, Identity: $params{'identity'}, Mech: $mechanism, Subject: $subject, IP: $ip\n"; $Totals{'policyspf'}++; if ($Logreporters::TreeData::Collecting{'policyspf'}) { $message = join (' ', $message, $params{'identity'}) if exists $params{'identity'}; $Counts{'policyspf'}{'Policy Action'}{"SPF $result"}{$message}{'mech: ' .$mechanism}{$subject}{$ip}++ } return; } inc_unmatched('postfix_policy_spf(2)'); return; } =pod Mail::SPF::Query libmail-spf-query-perl 1:1.999 XXX incomplete Some possible smtp_comment results: pass "localhost is always allowed." none "SPF", "domain of sender $query->{sender} does not designate mailers unknown $explanation, "domain of sender $query->{sender} does not exist" $query->{spf_error_explanation}, $query->is_looping $query->{spf_error_explanation}, $directive_set->{hard_syntax_error} $query->{spf_error_explanation}, "Missing SPF record at $query->{domain}" error $query->{spf_error_explanation}, $query->{error} $result $explanation, $comment, $query->{directive_set}->{orig_txt} Possible header_comment results: pass "$query->{spf_source} designates $ip as permitted sender" fail "$query->{spf_source} does not designate $ip as permitted sender" softfail "transitioning $query->{spf_source} does not designate $ip as permitted sender" /^unknown / "encountered unrecognized mechanism during SPF processing of $query->{spf_source}" unknown "error in processing during lookup of $query->{sender}" neutral "$ip is neither permitted nor denied by domain of $query->{sender}" error "encountered temporary error during SPF processing of $query->{spf_source}" none "$query->{spf_source} does not designate permitted sender hosts" "could not perform SPF query for $query->{spf_source}" ); =cut #TDspf 39053DC: SPF none: smtp_comment=SPF: domain of sender user@example.com does not designate mailers, header_comment=sample.net: domain of user@example.com does not designate permitted sender hosts #TDspf : SPF none: smtp_comment=SPF: domain of sender user@example.com does not designate mailers, header_comment=sample.net: domain of user@example.com does not designate permitted sender hosts #TDspf : SPF pass: smtp_comment=Please see http://www.openspf.org/why.html?sender=user%40example.com&ip=10.0.0.1&receiver=sample.net: example.com MX mail.example.com A 10.0.0.1, header_comment=example.com: domain of user@example.com designates 10.0.0.1 as permitted sender #TDspf : SPF fail: smtp_comment=Please see http://www.openspf.org/why.html?sender=user%40example.com&ip=10.0.0.1&receiver=sample.net, header_comment=sample.net: domain of user@example.com does not designate 10.0.0.1 as permitted sender #TDspf : : SPF none: smtp_comment=SPF: domain of sender does not designate mailers, header_comment=mx1.example.com: domain of does not designate permitted sender hosts if (my ($result, $reply) = ($line =~ /^(SPF [^:]+): (.*)$/)) { #print "result: $result\n\treply: $reply\n\tORIG: \"$Logreporters::Reports::origline\"\n"; if ($reply =~ /^(?:smtp_comment=)(.*)$/) { $reply = $1; # SPF none if ($reply =~ /^SPF: domain of sender (?:(?:[^@]+@)?(\S+) )?does not designate mailers/) { $domain = $1 ? $1 : '*unknown'; #print "result: $result: domain: $domain\n"; } elsif ($reply =~ /^Please see http:\/\/[^\/]+\/why\.html\?sender=(?:.+%40)?([^&]+)&ip=([^&]+)/) { ($domain,$ip) = ($1,$2); #print "result: $result: domain: $domain, IP: $ip\n"; } # SPF unknown elsif ($reply =~ /^SPF record error: ([^,]+), .*: error in processing during lookup of (?:[^@]+\@)?(\S+)/) { ($message, $domain) = ($1, $2); #print "result: $result: domain: $domain, Problem: $message\n"; } elsif ($reply =~ /^SPF record error: ([^,]+), .*: encountered unrecognized mechanism during SPF processing of domain (?:[^@]+\@)?(\S+)/) { ($message, $domain) = ($1,$2); #print "result: \"$result\": domain: $domain, Problem: $message\n"; $result = "SPF permerror" if ($result =~ /SPF unknown mx-all/); } else { inc_unmatched('postfix_policy_spf(3)'); return; } } else { inc_unmatched('postfix_policy_spf(4)'); return; } $Totals{'policyspf'}++; if ($message) { $Counts{'policyspf'}{'Policy Action'}{$result}{$domain}{$ip}{$message}{$END_KEY}++ if ($Logreporters::TreeData::Collecting{'policyspf'}); } else { $Counts{'policyspf'}{'Policy Action'}{$result}{$domain}{$ip}{$END_KEY}++ if ($Logreporters::TreeData::Collecting{'policyspf'}); } return; } inc_unmatched('postfix_policy_spf(5)'); } 1; #MODULE: ../Logreporters/Postfwd.pm package Logreporters::Postfwd; use 5.008; use strict; use re 'taint'; use warnings; BEGIN { use Exporter (); use vars qw(@ISA @EXPORT @EXPORT_OK %EXPORT_TAGS $VERSION); $VERSION = '1.000'; @ISA = qw(Exporter); @EXPORT = qw(&postfix_postfwd); } use subs @EXPORT; BEGIN { import Logreporters::TreeData qw(%Totals %Counts $END_KEY); import Logreporters::Utils; import Logreporters::Reports qw(&inc_unmatched); } # postfwd: http://postfwd.org/ # # sub postfix_postfwd($) { my $line = shift; return if ( #TDpfw [STATS] Counters: 213000 seconds uptime, 39 rules #TDpfw [LOGS info]: compare rbl: "example.com[10.1.0.7]" -> "localrbl.local" #TDpfw [DNSBL] object 10.0.0.1 listed on rbl:list.dnswl.org (answer: 127.0.15.0, time: 0s) $line =~ /^\[STATS\] / or $line =~ /^\[DNSBL\] / or $line =~ /^\[LOGS info\]/ or $line =~ /^Process Backgrounded/ or $line =~ /^Setting [ug]id to/ or $line =~ /^Binding to TCP port/ or $line =~ /^terminating\.\.\./ or $line =~ /^Setting status interval to \S+ seconds/ or $line =~ /^postfwd .+ ready for input$/ or $line =~ /postfwd .+ (?:starting|terminated)/ ); my ($type,$rule,$id,$action,$host,$hostip,$recipient); if ($line =~ /^\[(RULES|CACHE)\] rule=(\d+), id=([^,]+), client=([^[]+)\[([^]]+)\], sender=.*?, recipient=<(.*?)>,.*? action=(.*)$/) { #TDpfw [RULES] rule=0, id=OK_DNSWL, client=example.com[10.0.0.1], sender=, recipient=, helo=, proto=ESMTP, state=RCPT, delay=0s, hits=OK_DNSWL, action=DUNNO #TDpfw [CACHE] rule=14, id=GREY_NODNS, client=unknown[192.168.0.1], sender=, recipient=, helo=, proto=ESMTP, state=RCPT, delay=0s, hits=SET_NODNS;EVAL_DNSBLS;EVAL_RHSBLS;GREY_NODNS, action=greylist ($type,$rule,$id,$host,$hostip,$recipient,$action) = ($1,$2,$3,$4,$5,$6,$7); $recipient = '*unknown' if (not defined $recipient); $Counts{'postfwd'}{"Rule $rule"}{$id}{$action}{$type}{$recipient}{formathost($hostip,$host)}++ if ($Logreporters::TreeData::Collecting{'postfwd'}); } elsif (($line =~ /Can't connect to TCP port/) or ($line =~ /Pid_file already exists for running process/) ) { $line =~ s/^[-\d\/:]+ //; # strip leading date/time stamps 2009/07/18-20:09:49 $Totals{'warningsother'}++; return unless ($Logreporters::TreeData::Collecting{'warningsother'}); $Counts{'warningsother'}{"$Logreporters::service_name: $line"}++; return; } # ignoring [DNSBL] lines #elsif ($line =~ /^\[DNSBL\] object (\S+) listed on (\S+) \(answer: ([^,]+), .*\)$/) { # #TDpfw [DNSBL] object 10.0.0.60 listed on rbl:list.dnswl.org (answer: 127.0.15.0, time: 0s) # ($type,$rbl) = split (/:/, $2); # $Counts{'postfwd'}{"DNSBL: $type"}{$rbl}{$1}{$3}{''}++ if ($Logreporters::TreeData::Collecting{'postfwd'}); #} else { inc_unmatched('postfwd'); return; } $Totals{'postfwd'}++; } 1; #MODULE: ../Logreporters/Postgrey.pm package Logreporters::Postgrey; use 5.008; use strict; use re 'taint'; use warnings; my (%pgDelays,%pgDelayso); BEGIN { use Exporter (); use vars qw(@ISA @EXPORT @EXPORT_OK %EXPORT_TAGS $VERSION); $VERSION = '1.000'; @ISA = qw(Exporter); @EXPORT = qw(&postfix_postgrey &print_postgrey_reports); } use subs @EXPORT; BEGIN { import Logreporters::TreeData qw(%Totals %Counts $END_KEY); import Logreporters::Utils; import Logreporters::Config qw(%Opts); import Logreporters::Reports qw(&inc_unmatched &print_percentiles_report2); } # postgrey: http://postgrey.schweikert.ch/ # # Triplet: (client IP, envelope sender, envelope recipient address) # sub postfix_postgrey($) { my $line = shift; return if ( #TDpg cleaning up old logs... #TDpg cleaning up old entries... #TDpg cleaning clients database finished. before: 207, after: 207 #TDpg cleaning main database finished. before: 3800, after: 2539 #TDpg delayed 603 seconds: client=10.0.example.com, from=anyone@sample.net, to=joe@example.com #TDpg Setting uid to "504" #TDpg Setting gid to "1002 1002" #TDpg Process Backgrounded #TDpg 2008/03/08-15:54:49 postgrey (type Net::Server::Multiplex) starting! pid(21961) #TDpg Binding to TCP port 10023 on host 127.0.0.1 #TDpg 2007/01/25-14:58:24 Server closing! #TDpg Couldn't unlink "/var/run/postgrey.pid" [Permission denied] #TDpg ignoring garbage: #TDpg unrecognized request type: '' #TDpg rm /var/spool/postfix/postgrey/log.0000000002 #TDpg 2007/01/25-14:48:00 Pid_file already exists for running process (4775)... aborting at line 232 in file /usr/lib/perl5/vendor_perl/5.8.7/Net/Server.pm #TDpg Resolved [localhost]:10023 to [127.0.0.1]:10023, IPv4 $line =~ /^cleaning / or $line =~ /^delayed / or $line =~ /^cleaning / or $line =~ /^Setting [ug]id/ or $line =~ /^Process Backgrounded/ or $line =~ /^Binding to / or $line =~ /^Couldn't unlink / or $line =~ /^ignoring garbage: / or $line =~ /^unrecognized request type/ or $line =~ /^rm / or # unanchored last $line =~ /Pid_file already exists/ or $line =~ /postgrey .* starting!/ or $line =~ /Server closing!/ or $line =~ /Resolved .*localhost.*IPv4/ ); my ($action,$reason,$delay,$host,$ip,$sender,$recip); if ($line =~ /^(?:$Logreporters::re_QID: )?action=(.*?), reason=(.*?)(?:, delay=(\d+))?, client_name=(.*?), client_address=(.*?)(?:, sender=(.*?))?(?:, +recipient=(.*))?$/o) { #TDpg action=greylist, reason=new, client_name=example.com, client_address=10.0.0.1, sender=from@example.com, recipient=to@sample.net #TDpgQ action=greylist, reason=new, client_name=example.com, client_address=10.0.0.1, sender=from@example.com #TDpgQ action=pass, reason=triplet found, client_name=example.com, client_address=10.0.0.1, sender=from@example.com, recipient=to@sample.net #TDpg action=pass, reason=triplet found, client_name=example.com, client_address=10.0.0.1, sender=from@example.com, recipient=to@sample.net #TDpg action=pass, reason=triplet found, client_name=example.com, client_address=10.0.0.1, recipient=to@sample.net #TDpg action=pass, reason=triplet found, delay=99, client_name=example.com, client_address=10.0.0.1, recipient=to@sample.net ($action,$reason,$delay,$host,$ip,$sender,$recip) = ($1,$2,$3,$4,$5,$6,$7); $reason =~ s/^(early-retry) \(.* missing\)$/$1/; $recip = '*unknown' if (not defined $recip); $sender = '' if (not defined $sender); $Totals{'postgrey'}++; if ($Logreporters::TreeData::Collecting{'postgrey'}) { $Counts{'postgrey'}{"\u$action"}{"\u$reason"}{formathost($ip,$host)}{$recip}{$sender}++; if (defined $delay and $Logreporters::TreeData::Collecting{'postgrey_delays'}) { $pgDelays{'1: Total'}{$delay}++; push @{$pgDelayso{'Postgrey'}}, $delay } } } elsif ($line =~ /^whitelisted: (.*?)(?:\[([^]]+)\])?$/) { #TDpg: whitelisted: example.com[10.0.0.1] $Totals{'postgrey'}++; if ($Logreporters::TreeData::Collecting{'postgrey'}) { $Counts{'postgrey'}{'Whitelisted'}{defined $2 ? formathost($2,$1) : $1}{$END_KEY}++; } } elsif ($line =~ /^tarpit whitelisted: (.*?)(?:\[([^]]+)\])?$/) { #TDpg: tarpit whitelisted: example.com[10.0.0.1] $Totals{'postgrey'}++; if ($Logreporters::TreeData::Collecting{'postgrey'}) { $Counts{'postgrey'}{'Tarpit whitelisted'}{defined $2 ? formathost($2,$1) : $1}{$END_KEY}++; } } else { inc_unmatched('postgrey'); } return; } sub print_postgrey_reports() { #print STDERR "pgDelays memory usage: ", commify(Devel::Size::total_size(\%pgDelays)), "\n"; if ($Opts{'postgrey_delays'}) { my @table; for (sort keys %pgDelays) { # anon array ref: label, array ref of $Delay{key} push @table, [ substr($_,3), $pgDelays{$_} ]; } if (@table) { print_percentiles_report2(\@table, "Postgrey Delays Percentiles", $Opts{'postgrey_delays_percentiles'}); } } } 1; #MODULE: ../Logreporters/PolicydWeight.pm package Logreporters::PolicydWeight; use 5.008; use strict; use re 'taint'; use warnings; BEGIN { use Exporter (); use vars qw(@ISA @EXPORT @EXPORT_OK %EXPORT_TAGS $VERSION); $VERSION = '1.000'; @ISA = qw(Exporter); @EXPORT = qw(&postfix_policydweight); } use subs @EXPORT; BEGIN { import Logreporters::Reports qw(&inc_unmatched); import Logreporters::TreeData qw(%Totals %Counts); import Logreporters::Utils; } # Handle postfix/policydweight entries # sub postfix_policydweight($) { my $line = shift; my ($r1, $code, $reason, $reason2); if ( $line =~ /^weighted check/ or $line =~ /^policyd-weight .* started and daemonized/ or $line =~ /^(cache|child|master): / or $line =~ /^cache (?:spawned|killed)/ or $line =~ /^child \d+ exited/ or $line =~ /^Daemon terminated/ or $line =~ /^Daemon terminated/ ) { #print "$OrigLine\n"; return; } if ($line =~ s/^decided action=//) { $line =~ s/; delay: \d+s$//; # ignore, eg.: "delay: 3s" #print "....\n\tLINE: $line\n\tORIG: '$Logreporters::Reports::origline'\n"; if (($code,$r1) = ($line =~ /^(\d+)\s+(.*)$/ )) { my @problems = (); for (split /; */, $r1) { if (/^Mail appeared to be SPAM or forged\. Ask your Mail\/DNS-Administrator to correct HELO and DNS MX settings or to get removed from DNSBLs/ ) { push @problems, 'spam/forged: bad DNS/hit DNSRBLs'; } elsif (/^Your MTA is listed in too many DNSBLs/) { push @problems, 'too many DNSBLs'; } elsif (/^temporarily blocked because of previous errors - retrying too fast\. penalty: \d+ seconds x \d+ retries\./) { push @problems, 'temp blocked: retrying too fast'; } elsif (/^Please use DynDNS/) { push @problems, 'use DynDNS'; } elsif (/^please relay via your ISP \([^)]+\)/) { push @problems, 'use ISP\'s relay'; } elsif (/^in (.*)/) { push @problems, $1; } elsif (m#^check http://rbls\.org/\?q=#) { push @problems, 'see http://rbls.org'; } elsif (/^MTA helo: .* \(helo\/hostname mismatch\)/) { push @problems, 'helo/hostname mismatch'; } elsif (/^No DNS entries for your MTA, HELO and Domain\. Contact YOUR administrator\s+/) { push @problems, 'no DNS entries'; } else { push @problems, $_; } } $reason = $code; $reason2 = join (', ', @problems); } elsif ($line =~ s/^DUNNO\s+//) { #decided action=DUNNO multirecipient-mail - already accepted by previous query; delay: 0s $reason = 'DUNNO'; $reason2 = $line; } elsif ($line =~ s/^check_greylist//) { #decided action=check_greylist; delay: 16s $reason = 'Check greylist'; $reason2 = $line; } elsif ($line =~ s/^PREPEND X-policyd-weight:\s+//) { #decided action=PREPEND X-policyd-weight: using cached result; rate: -7.6; delay: 0s if ($line =~ /(using cached result); rate:/) { $reason = 'PREPEND X-policyd-weight: mail accepted'; $reason2 = "\u$1"; } else { #decided action=PREPEND X-policyd-weight: NOT_IN_SBL_XBL_SPAMHAUS=-1.5 P0F_LINUX=0 , rate: -7.6; delay: 2s $reason = 'PREPEND X-policyd-weight: mail accepted'; $reason2 = 'Varies'; } } else { return; } } elsif ($line =~ /^err/) { # coerce policyd-weight err's into general warnings $Totals{'startuperror'}++; $Counts{'startuperror'}{'Service: policyd-weight'}{$line}++ if ($Logreporters::TreeData::Collecting{'startuperror'}); return; } else { inc_unmatched('policydweight'); return; } $Totals{'policydweight'}++; $Counts{'policydweight'}{$reason}{$reason2}++ if ($Logreporters::TreeData::Collecting{'policydweight'}); } 1; package Logreporters; BEGIN { import Logreporters::Utils; import Logreporters::Config; import Logreporters::TreeData qw(%Totals %Counts %Collecting printTree buildTree $END_KEY); import Logreporters::RegEx; import Logreporters::Reports; import Logreporters::RFC3463; import Logreporters::PolicySPF; import Logreporters::Postfwd; import Logreporters::Postgrey; import Logreporters::PolicydWeight; } use 5.008; use strict; use warnings; no warnings "uninitialized"; use re 'taint'; use File::Basename; our $progname = fileparse($0); my @supplemental_reports = qw(delays postgrey_delays); # Default values for various options. These are used # to reset default values after an option has been # disabled (via undef'ing its value). This allows # a report to be disabled via config file or --nodetail, # but reenabled via subsequent command line option my %Defaults = ( detail => 10, # report level detail max_report_width => 100, # maximum line width for report output line_style => undef, # lines > max_report_width, 0=truncate,1=wrap,2=full syslog_name => 'postfix', # service name (postconf(5), syslog_name) sect_vars => 0, # show section vars in detail report hdrs unknown => 1, # show 'unknown' in address/hostname pairs ipaddr_width => 15, # width for printing ip addresses long_queue_ids => 0, # enable long queue ids (2.9+) delays => 1, # show message delivery delays report delays_percentiles => '0 25 50 75 90 95 98 100', # percentiles shown in delays report reject_reply_patterns => '5.. 4.. warn', # reject reply grouping patterns postgrey_delays => 1, # show postgrey delays report postgrey_delays_percentiles => '0 25 50 75 90 95 98 100', # percentiles shown in postgrey delays report ); my $usage_str = <<"END_USAGE"; Usage: $progname [ ARGUMENTS ] [logfile ...] ARGUMENTS can be one or more of options listed below. Later options override earlier ones. Any argument may be abbreviated to an unambiguous length. Input is read from the named logfile(s), or STDIN. --debug AREAS provide debug output for AREAS --help print usage information --version print program version --config_file FILE, -f FILE use alternate configuration file FILE --ignore_services PATTERN ignore postfix/PATTERN services --syslog_name PATTERN only consider log lines that match syslog service name PATTERN --detail LEVEL print LEVEL levels of detail (default: 10) --nodetail set all detail levels to 0 --[no]summary display the summary section --[no]mailqueue display the mail queue section --ipaddr_width WIDTH use WIDTH chars for IP addresses in address/hostname pairs --line_style wrap|full|truncate disposition of lines > max_report_width (default: truncate) --full same as --line_style=full --truncate same as --line_style=truncate --wrap same as --line_style=wrap --max_report_width WIDTH limit report width to WIDTH chars (default: 100) --limit L=V, -l L=V set level limiter L with value V --[no]long_queue_ids use long queue ids --[no]unknown show the 'unknown' hostname in formatted address/hostnames pairs --[no]sect_vars [do not] show config file var/cmd line option names in section titles --recipient_delimiter C split delivery addresses using recipient delimiter char C --reject_reply_patterns "R1 [R2 ...]" set reject reply patterns used in to group rejects to R1, [R2 ...], where patterns are [45][.0-9][.0-9] or "Warn" (default: 5.. 4.. Warn) Supplemental reports --[no]delays [do not] show msg delays percentiles report --delays_percentiles "P1 [P2 ...]" set delays report percentiles to P1 [P2 ...] (range: 0...100) --[no]postgrey_delays [do not] show postgrey delays percentiles report --postgrey_delays_percentiles "P1 [P2 ...]" set postgrey delays report percentiles to P1 [P2 ...] (range: 0...100) END_USAGE my @RejectPats; # pattern list used to match against reject replys my @RejectKeys; # 1-to-1 with RejectPats, but with 'x' replacing '.' (for report output) my (%DeferredByQid, %SizeByQid, %AcceptedByQid, %Delays); # local prototypes sub usage; sub init_getopts_table; sub init_defaults; sub build_sect_table; sub postfix_bounce; sub postfix_cleanup; sub postfix_panic; sub postfix_fatal; sub postfix_error; sub postfix_warning; sub postfix_script; sub backwards_compatible; sub postfix_postsuper; sub process_delivery_attempt; sub cleanhostreply; sub strip_ftph; sub get_reject_key; sub expand_bare_reject_limiters; sub create_ignore_list; sub in_ignore_list; sub header_body_checks; sub milter_common; # lines that match any RE in this list will be ignored. # see create_ignore_list(); my @ignore_list = (); # The Sections table drives Summary and Detail reports. For each entry in the # table, if there is data available, a line will be output in the Summary report. # Additionally, a sub-section will be output in the Detail report if both the # global --detail, and the section's limiter variable, are sufficiently high (a # non-existent section limiter variable is considered to be sufficiently high). # my @Sections = (); # List of reject variants. See also: "Add reject variants" below, and conf file(s). my @RejectClasses = qw( rejectrelay rejecthelo rejectdata rejectunknownuser rejectrecip rejectsender rejectclient rejectunknownclient rejectunknownreverseclient rejectunverifiedclient rejectrbl rejectheader rejectbody rejectcontent rejectsize rejectmilter rejectproxy rejectinsufficientspace rejectconfigerror rejectverify rejectetrn rejectlookupfailure ); # Dispatch table of the list of supported policy services # XXX have add-ins register into the dispatch table my @policy_services = ( [ qr/^postfwd/, \&Logreporters::Postfwd::postfix_postfwd ], [ qr/^postgrey/, \&Logreporters::Postgrey::postfix_postgrey ], [ qr/^policyd?-spf/, \&Logreporters::PolicySPF::postfix_policy_spf ], [ qr/^policyd-?weight/, \&Logreporters::PolicydWeight::postfix_policydweight ], ); # Initialize main running mode and basic opts init_run_mode($config_file); # Configure the Getopts options table init_getopts_table(); # Place configuration file/environment variables onto command line init_cmdline(); # Initialize default values init_defaults(); # Process command line arguments, 0=no_permute,no_pass_through get_options(0); # Build the Section table, after reject_reply_patterns is final build_sect_table(); # Expand bare rejects before generic processing expand_bare_reject_limiters(); # Run through the list of Limiters, setting the limiters in %Opts. process_limiters(@Sections); # Set collection for any enabled supplemental sections foreach (@supplemental_reports) { $Logreporters::TreeData::Collecting{$_} = (($Opts{'detail'} >= 5) && $Opts{$_}) ? 1 : 0; } if (! defined $Opts{'line_style'}) { # default line style to full if detail >= 11, or truncate otherwise $Opts{'line_style'} = ($Opts{'detail'} > 10) ? $line_styles{'full'} : $line_styles{'truncate'}; } # Set the QID RE to capture either pre-2.9 short style or 2.9+ long style. $re_QID = $Opts{'long_queue_ids'} ? $re_QID_l : $re_QID_s; # Create the list of REs used to match against log lines create_ignore_list(); # Notes: # # - IN REs, always use /o flag or qr// at end of RE when RE uses interpolated vars # - In REs, email addresses may be empty "<>" - capture using *, not + ( eg. from=<.*?> ) # - See additional notes below, search for "Note:". # - XXX indicates change, fix or thought required # Main processing loop # LINE: while ( <> ) { chomp; s/\s+$//; next unless length $_; $Logreporters::Reports::origline = $_; # Linux: Jul 1 20:08:06 mailhost postfix/smtpd[4379]: connect from unknown[10.0.0.1] # FreeBSD: Jul 1 20:08:06 mailhost postfix/smtpd[4379]: connect from unknown[10.0.0.1] # Aug 17 15:16:12 mailhost postfix/cleanup[14194]: [ID 197553 mail.info] EC2B339E5: message-id=<2616.EC2B339E5@example.com> # Dec 25 05:20:28 mailhost policyd-spf[14194]: [ID 27553 mail.info] ... policyd-spf stuff ... next unless /^[A-Z][a-z]{2} [ \d]\d \d{2}:\d{2}:\d{2} (?:<[^>]+> )?(\S+) ($Opts{'syslog_name'}(?:\/([^:[]+))?)(?:\[\d+\])?: (?:\[ID \d+ \w+\.\w+\] )?(.*)$/o; our $service_name = $3; my ($mailhost,$server_name,$p1) = ($1,$2,$4); #print "mailhost: $mailhost, servername: $server_name, servicename: $service_name, p1: $p1\n"; $service_name = $server_name unless $service_name; #print "service_name: $service_name\n"; # ignored postfix services... next if $service_name eq 'postlog'; next if $service_name =~ /^$Opts{'ignore_services'}$/o; next if $p1 =~ /^[A-Z0-9]+: passing <[^>]+> to transport=lmtp$/; # common log entries up front if ($p1 =~ s/^connect from //) { #TD25 connect from sample.net[10.0.0.1] #TD connect from mail.example.com[2001:dead:beef::1] #TD connect from localhost.localdomain[127.0.0.1] #TD connect from unknown[unknown] $Totals{'connectioninbound'}++; next unless ($Collecting{'connectioninbound'}); my $host = $p1; my $hostip; if (($host,$hostip) = ($host =~ /^([^[]+)\[([^]]+)\]/)) { $host = formathost($hostip,$host); } $Counts{'connectioninbound'}{$host}++; next; } if ($p1 =~ /^disconnect from /) { #TD25 disconnect from sample.net[10.0.0.1] #TD disconnect from mail.example.com[2001:dead:beef::1] $Totals{'disconnection'}++; next; } if ($p1 =~ s/^connect to //) { next if ($p1 =~ /^subsystem /); $Totals{'connecttofailure'}++; next unless ($Collecting{'connecttofailure'}); my ($host,$hostip,$reason,$port) = ($p1 =~ /^([^[]+)\[([^]]+)\](?::\d+)?: (.*?)(?:\s+\(port (\d+)\))?$/); # all "connect to" messages indicate a problem with the connection #TDs connect to example.org[10.0.0.1]: Connection refused (port 25) #TDs connect to mail.sample.com[10.0.0.1]: No route to host (port 25) #TDs connect to sample.net[192.168.0.1]: read timeout (port 25) #TDs connect to mail.example.com[10.0.0.1]: server dropped connection without sending the initial SMTP greeting (port 25) #TDs connect to mail.example.com[192.168.0.1]: server dropped connection without sending the initial SMTP greeting (port 25) #TDs connect to ipv6-1.example.com[2001:dead:beef::1]: Connection refused (port 25) #TDs connect to ipv6-2.example.com[FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]: Connection refused (port 25) #TDs connect to ipv6-3.example.com[1080:0:0:0:8:800:200C:4171]: Connection refused (port 25) #TDs connect to ipv6-4.example.com[3ffe:2a00:100:7031::1]: Connection refused (port 25) #TDs connect to ipv6-5.example.com[1080::8:800:200C:417A]: Connection refused (port 25) #TDs connect to ipv6-6.example.com[::192.9.5.5]: Connection refused (port 25) #TDs connect to ipv6-7.example.com[::FFFF:129.144.52.38]: Connection refused (port 25) #TDs connect to ipv6-8.example.com[2010:836B:4179::836B:4179]: Connection refused (port 25) #TDs connect to mail.example.com[10.0.0.1]: server refused to talk to me: 452 try later (port 25) $host = join(' :', $host, $port) if ($port and $port ne '25'); # Note: See ConnectToFailure below if ($reason =~ /^server (refused to talk to me): (.*)$/) { $Counts{'connecttofailure'}{ucfirst($1)}{formathost($hostip,$host)}{$2}++; } else { $Counts{'connecttofailure'}{ucfirst($reason)}{formathost($hostip,$host)}{''}++; } next; } =pod real 3m43.997s user 3m39.038s sys 0m3.005s =pod # Handle before panic, fatal, warning, so that service-specific code gets first crack # XXX replace w/dispatch table for add-ins, so user's can add their own... if ($service_name eq 'postfwd') { postfix_postfwd($p1); next; } if ($service_name eq 'postgrey') { postfix_postgrey($p1); next; } if ($service_name =~ /^policyd?-spf/) { postfix_policy_spf($p1); next; } # postfix/policy-spf if ($service_name =~ /^policyd-?weight/) { postfix_policydweight($p1); next; } # postfix/policydweight =cut # Handle policy service handlers before panic, fatal, warning, etc. # messages so that service-specific code gets first crack. # 5:25 foreach (@policy_services) { if ($service_name =~ $_->[0]) { #print "Calling policy service helper: $service_name:('$p1')\n"; &{$_->[1]}($p1); next LINE; } }; #=cut # ^warning: ... # ^fatal: ... # ^panic: ... # ^error: ... if ($p1 =~ /^warning: +(.*)$/) { postfix_warning($1); next; } if ($p1 =~ /^fatal: +(.*)$/) { postfix_fatal($1); next; } if ($p1 =~ /^panic: +(.*)$/) { postfix_panic($1); next; } if ($p1 =~ /^error: +(.*)$/) { postfix_error($1); next; } # Backwards compatibility mode if ($p1 =~ /compati/i) { backwards_compatible($p1); next; } # backwards-compatible default settings # output by all services that use table lookups - process before specific messages if ($p1 =~ /(?:lookup )?table (?:[^ ]+ )?has changed -- (?:restarting|exiting)$/) { #TD table hash:/var/mailman/data/virtual-mailman(0,lock|fold_fix) has changed -- restarting #TD table hash:/etc/postfix/helo_checks has changed -- restarting $Totals{'tablechanged'}++; next; } # postfix/postscreen and postfix/verify services if ($service_name eq 'postscreen' or $service_name eq 'verify') { postfix_postscreen($p1); next; } # postfix/postscreen, postfix/verify if ($service_name eq 'dnsblog') { postfix_dnsblog($p1); next; } # postfix/dnsblog if ($service_name =~ /^cleanup/) { postfix_cleanup($p1); next; } # postfix/cleanup* if ($service_name =~ /^bounce/) { postfix_bounce($p1); next; } # postfix/bounce* if ($service_name eq 'postfix-script') { postfix_script($p1); next; } # postfix/postfix-script if ($service_name eq 'postsuper') { postfix_postsuper($p1); next; } # postfix/postsuper # ignore tlsproxy for now if ($service_name eq 'tlsproxy') { next; } # postfix/tlsproxy my ($helo, $relay, $from, $origto, $to, $domain, $status, $type, $reason, $reason2, $filter, $site, $cmd, $qid, $rej_type, $reject_name, $host, $hostip, $dsn, $reply, $fmthost, $bytes); $rej_type = undef; # ^$re_QID: ... if ($p1 =~ s/^($re_QID): //o) { $qid = $1; next if ($p1 =~ /^host \S*\[\S*\] said: 4\d\d/); # deferrals, picked up in "status=deferred" if ($p1 =~ /^removed\s*$/ ) { # Note: See REMOVED elsewhere # 52CBDC2E0F: removed delete $SizeByQid{$qid} if (exists $SizeByQid{$qid}); $Totals{'removedfromqueue'}++; next; } # coerce into general warning if (($p1 =~ /^Cannot start TLS: handshake failure/) or ($p1 =~ /^non-E?SMTP response from/)) { postfix_warning($p1); next; } if ($p1 eq 'status=deferred (bounce failed)') { #TDqQ status=deferred (bounce failed) $Totals{'bouncefailed'}++; next; } # this test must preceed access checks below #TDsQ replace: header From: "Postmaster" : From: "Postmaster" if ($service_name eq 'smtp' and header_body_checks($p1)) { #print "main: header_body_checks\n"; next; } # Postfix access actions # REJECT optional text... # DISCARD optional text... # HOLD optional text... # WARN optional text... # FILTER transport:destination # REDIRECT user@domain # BCC user@domain (2.6 experimental branch) # The following actions are indistinguishable in the logs # 4NN text # 5NN text # DEFER_IF_REJECT optional text... # DEFER_IF_PERMIT optional text... # UCE restriction... # The following actions are not logged # PREPEND headername: headervalue # DUNNO # # Reject actions based on remote client information: # - one of host name, network address, envelope sender # or # - recipient address # Template of access controls. Rejects look like the first line, other access actions the second. # ftph is envelope from, envelope to, proto and helo. # QID: ACTION STAGE from host[hostip]: DSN trigger: explanation; ftph # QID: ACTION STAGE from host[hostip]: trigger: explanation; ftph # $re_QID: reject: RCPT|MAIL|CONNECT|HELO|DATA from ... # $re_QID: reject_warning: RCPT|MAIL|CONNECT|HELO|DATA from ... if ($p1 =~ /^(reject(?:_warning)?|discard|filter|hold|redirect|warn|bcc|replace): /) { my $action = $1; $p1 = substr($p1, length($action) + 2); #print "action: \"$action\", p1: \"$p1\"\n"; if ($p1 !~ /^(RCPT|MAIL|CONNECT|HELO|EHLO|DATA|VRFY|ETRN|END-OF-MESSAGE) from ([^[]+)\[([^]]+)\](?::\d+)?: (.*)$/) { inc_unmatched('unexpected access'); next; } my ($stage,$host,$hostip,$p1) = ($1,$2,$3,$4); #print "stage: \"$stage\", host: \"$host\", hostip: \"$hostip\", p1: \"$p1\"\n"; my ($efrom,$eto,$proto,$helo) = strip_ftph($p1); #print "efrom: \"$efrom\", eto: \"$eto\", proto: \"$proto\", helo: \"$helo\"\n"; #print "p1 now: \"$p1\"\n"; # QID: ACTION STAGE from host[hostip]: DSN trigger: explanation; ftph #TDsdN reject_warning: VRFY from host[10.0.0.1]: 450 4.1.2 <<1F4@bs>>: Recipient address rejected: Domain not found; to=<<1F4@bs>> proto=SMTP helo= #TDsdN reject: VRFY from host[10.0.0.1]: 550 5.1.1 <:>: Recipient address rejected: User unknown in local recipient table; to=<:> proto=SMTP helo=<10.0.0.1> #TDsdN reject: VRFY from host[10.0.0.1]: 450 4.1.8 : Sender address rejected: Domain not found; from= to= proto=SMTP #TDsdN reject: VRFY from host[10.0.0.1]: 554 5.7.1 Service unavailable; Client host [10.0.0.1] blocked using zen.spamhaus.org; http://www.spamhaus.org/query/bl?ip=10.0.0.1; to= proto=SMTP #TDsdN reject: RCPT from host[10.0.0.1]: 450 4.1.2 : Recipient address rejected: User unknown in local recipient table; from=<> to= proto=SMTP helo= #TDsdN reject: RCPT from host[10.0.0.1]: 550 : Recipient address rejected: User unknown in local recipient table; from=<> to= proto=SMTP helo= #TDsdN reject_warning: RCPT from host[10.0.0.1]: 550 : Recipient address rejected: User unknown in local recipient table; from=<> to= proto=SMTP helo= #TDsdN reject: RCPT from host[10.0.0.1]: 550 5.1.1 : Recipient address rejected: User unknown in virtual address table; from= to= proto=ESMTP helo= #TDsdN reject: RCPT from host[10.0.0.1]: 450 4.1.1 : Recipient address rejected: User unknown in virtual mailbox table; from= to= proto=ESMTP helo= #TDsdN reject: RCPT from host[10.0.0.1]: 550 5.5.0 : Recipient address rejected: User unknown; from= to= proto=ESMTP helo=<[10.0.0.1]> #TDsdN reject: RCPT from host[10.0.0.1]: 450 : Recipient address rejected: Greylisted; from= to= proto=ESMTP helo= #TDsdN reject: RCPT from host[10.0.0.1]: 454 4.7.1 : Recipient address rejected: Access denied; from= to= proto=SMTP helo= #TDsdN reject_warning: RCPT from host[10.0.0.1]: 454 4.7.1 : Recipient address rejected: Access denied; from= to= proto=ESMTP helo= #TDsdN reject: RCPT from host[10.0.0.1]: 450 4.1.2 : Recipient address rejected: Domain not found; from= to= proto=ESMTP helo= #TDsdN reject: RCPT from host[10.0.0.1]: 554 : Recipient address rejected: Please see http://www.openspf.org/why.html?sender=from%40example.net&ip=10.0.0.1&receiver=example.net; from= to= proto=ESMTP helo= #TDsdN reject: RCPT from host[10.0.0.1]: 550 : Recipient address rejected: undeliverable address: host example.net[192.168.0.1] said: 550 : User unknown in virtual alias table (in reply to RCPT TO command); from= to= proto=SMTP helo= #TDsdN reject: RCPT from host[10.0.0.1]: 554 : Recipient address rejected: Please see http://spf.pobox.com/why.html?sender=user%40example.com&ip=10.0.0.1&receiver=mail; from= to= proto=ESMTP helo=<10.0.0.1> #TDsdN reject: RCPT from host[10.0.0.1]: 554 : Relay access denied; from= to= proto=SMTP helo= #TDsdN reject_warning: HELO from host[10.0.0.1]: 554 : Relay access denied; proto=SMTP helo= #TDsdN reject: RCPT from host[10.0.0.1]: 450 4.1.8 : Sender address rejected: Domain not found; from= to= proto=ESMTP helo= #TDsdN reject_warning: RCPT from host[10.0.0.1]: 450 4.1.8 : Sender address rejected: Domain not found; from= to= proto=ESMTP helo= #TDsdN reject: RCPT from host[10.0.0.1]: 550 : Sender address rejected: undeliverable address: host example.net[10.0.0.1] said: 550 : User unknown in virtual alias table (in reply to RCPT TO command); from= to= proto=SMTP helo= #TDsdN reject_warning: RCPT from host[10.0.0.1]: 554 : Client host rejected: Access denied; from= to= proto=SMTP helo= #TDsdN reject: RCPT from host[10.0.0.1]: 554 : Client host rejected: Optional text; from= to= proto=SMTP helo= #TDsdN reject: CONNECT from host[10.0.0.1]: 503 5.5.0 : Client host rejected: Improper use of SMTP command pipelining; proto=SMTP #TDsdN reject_warning: RCPT from unk[10.0.0.1]: 450 Client host rejected: cannot find your hostname, [10.0.0.1]; from= to= proto=ESMTP helo= #TDsdN reject: RCPT from unk[10.0.0.1]: 450 Client host rejected: cannot find your hostname, [10.0.0.1]; from= to= proto=ESMTP helo= #TDsdN reject: RCPT from unk[10.0.0.1]: 450 Client host rejected: cannot find your hostname, [10.0.0.1]; proto=ESMTP #TDsdN reject: RCPT from unk[10.0.0.1]: 550 5.7.1 Client host rejected: cannot find your reverse hostname, [10.0.0.1] #TDsdN reject: CONNECT from unk[unknown]: 421 4.7.1 Client host rejected: cannot find your reverse hostname, [unknown]; proto=SMTP #TDsdN reject: RCPT from host[10.0.0.1]: 554 5.7.1 Service unavailable; Client host [10.0.0.1] blocked using sbl-xbl.spamhaus.org; http://www.spamhaus.org/query/bl?ip=10.0.0.1; from= to= proto=ESMTP helo= #TDsdN reject_warning: RCPT from host[10.0.0.1]: 554 5.7.1 Service unavailable; Client host [10.0.0.1] blocked using sbl-xbl.spamhaus.org; http://www.spamhaus.org/query/bl?ip=10.0.0.1; from= to= proto=ESMTP helo= #TDsdN reject: RCPT from host[10.0.0.1]: 554 Service denied; Client host [10.0.0.1] blocked using bl.spamcop.net; Blocked - see http://www.spamcop.net/bl.shtml?83.164.27.124; from= to= proto=ESMTP helo= #TDsdN reject: RCPT from host[10.0.0.1]: 454 4.7.1 : Helo command rejected: Access denied; from= to= proto=SMTP helo= #TDsdN reject_warning: RCPT from host[10.0.0.1]: 454 4.7.1 : Helo command rejected: Access denied; from= to= proto=SMTP helo= #TDsdN reject: EHLO from host[10.0.0.1]: 504 5.5.2 : Helo command rejected: need fully-qualified hostname; proto=SMTP helo= #TDsdQ reject: DATA from host[10.0.0.1]: 550 5.5.3 : Data command rejected: Multi-recipient bounce; from=<> proto=ESMTP helo= #TDsdN reject: ETRN from host[10.0.0.1]: 554 5.7.1 : Etrn command rejected: Access denied; proto=ESMTP helo= #TDsdN reject: RCPT from host[10.0.0.1]: 452 Insufficient system storage; from= to= #TDsdN reject_warning: RCPT from host[10.0.0.1]: 451 4.3.5 Server configuration error; from= to= proto=ESMTP helo= #TDsdN reject: RCPT from host[10.0.0.1]: 450 Server configuration problem; from= to= proto=ESMTP helo= #TDsdN reject: MAIL from host[10.0.0.1]: 552 Message size exceeds fixed limit; proto=ESMTP helo= #TDsdN reject: RCPT from unk[10.0.0.1]: 554 5.7.1 : Unverified Client host rejected: Access denied; from= to= proto=SMTP helo= #TDsdN reject: MAIL from host[10.0.0.1]: 451 4.3.0 : Temporary lookup failure; from= proto=ESMTP helo= # reject, reject_warning if ($action =~ /^reject/) { my ($recip); if ($p1 !~ /^($re_DSN) (.*)$/o) { inc_unmatched('reject1'); next; } ($dsn,$p1) = ($1,$2); #print "dsn: $dsn, p1: \"$p1\"\n"; $fmthost = formathost($hostip,$host); # reject_warning override temp or perm reject types $rej_type = ($action eq 'reject_warning' ? 'warn' : get_reject_key($dsn)); #print "REJECT stage: '$rej_type'\n"; if ($Collecting{'byiprejects'} and substr($rej_type,0,1) eq '5') { $Counts{'byiprejects'}{$fmthost}++; } if ($stage eq 'VRFY') { if ($p1 =~ /^(?:<(\S*)>: )?(.*);$/) { my ($trigger,$reason) = ($1,$2); $Totals{$reject_name = "${rej_type}rejectverify" }++; next unless ($Collecting{$reject_name}); if ($reason =~ /^Service unavailable; Client host \[[^]]+\] (blocked using [^;]*);/) { $reason = join (' ', 'Client host blocked using', $1); $trigger = ''; } $Counts{$reject_name}{$reason}{$fmthost}{ucfirst($trigger)}++; } else { inc_unmatched('vrfyfrom'); } next; } # XXX there may be several semicolon-separated messages # Recipient address rejected: Unknown users and via check_recipient_access if ($p1 =~ /^<(.*)>: Recipient address rejected: ([^;]*);/) { ($recip,$reason) = ($1,$2); my ($localpart,$domainpart); # Unknown users; local mailbox, alias, virtual, relay user, unspecified if ($recip eq '') { ($localpart, $domainpart) = ('<>', '*unspecified'); } else { ($localpart, $domainpart) = split (/@/, lc $recip); ($localpart, $domainpart) = ($recip, '*unspecified') if ($domainpart eq ''); } if ($reason =~ s/^User unknown *//) { $Totals{$reject_name = "${rej_type}rejectunknownuser" }++; next unless ($Collecting{$reject_name}); my ($table) = ($reason =~ /^in ((?:\w+ )+table)/); $table = 'Address table unavailable' if ($table eq ''); # when show_user_unknown_table_name=no $Counts{$reject_name}{ucfirst($table)}{$domainpart}{$localpart}{$fmthost}++; } else { # check_recipient_access $Totals{$reject_name = "${rej_type}rejectrecip" }++; next unless ($Collecting{$reject_name}); if ($reason =~ m{^Please see http://[^/]+/why\.html}) { $reason = 'SPF reject'; } elsif ($reason =~ /^undeliverable address: host ([^[]+)\[([^]]+)\](?::\d+)? said:/) { $reason = 'undeliverable address: remote host rejected recipient'; } $Counts{$reject_name}{ucfirst($reason)}{$domainpart}{$localpart}{$fmthost}++; } } elsif ($p1 =~ /^<(.*?)>.* Relay access denied/) { $Totals{$reject_name = "${rej_type}rejectrelay" }++; next unless ($Collecting{$reject_name}); $Counts{$reject_name}{$fmthost}{$eto}++; } elsif ($p1 =~ /^<(.*)>: Sender address rejected: (.*);/) { $Totals{$reject_name = "${rej_type}rejectsender" }++; next unless ($Collecting{$reject_name}); ($from,$reason) = ($1,$2); if ($reason =~ /^undeliverable address: host ([^[]+)\[([^]]+)\](?::\d+)? said:/) { $reason = 'undeliverable address: remote host rejected sender'; } $Counts{$reject_name}{ucfirst($reason)}{$fmthost}{$from ne '' ? $from : '<>'}++; } elsif ($p1 =~ /^(?:<.*>: )?Unverified Client host rejected: /) { # check_reverse_client_hostname_access (postfix 2.6+) $Totals{$reject_name = "${rej_type}rejectunverifiedclient" }++; next unless ($Collecting{$reject_name}); $Counts{$reject_name}{$fmthost}{$helo}{$eto}{$efrom}++; } elsif ($p1 =~ s/^(?:<.*>: )?Client host rejected: //) { # reject_unknown_client # client IP->name mapping fails # name->IP mapping fails # name->IP mapping =! client IP if ($p1 =~ /^cannot find your hostname/) { $Totals{$reject_name = "${rej_type}rejectunknownclient" }++; next unless ($Collecting{$reject_name}); $Counts{$reject_name}{$fmthost}{$helo}{$eto}{$efrom}++; } # reject_unknown_reverse_client_hostname (no PTR record for client's IP) elsif ($p1 =~ /^cannot find your reverse hostname/) { $Totals{$reject_name = "${rej_type}rejectunknownreverseclient" }++; next unless ($Collecting{$reject_name}); $Counts{$reject_name}{$hostip}++ } else { $Totals{$reject_name = "${rej_type}rejectclient" }++; next unless ($Collecting{$reject_name}); $p1 =~ s/;$//; $Counts{$reject_name}{ucfirst($p1)}{$fmthost}{$eto}{$efrom}++; } } elsif ($p1 =~ /^Service (?:temporarily )?(?:unavailable|denied)[^;]*; (?:(?:Unverified )?Client host |Sender address |Helo command )?\[[^ ]*\] blocked using ([^;]+);/) { # Note: similar code below: search RejectRBL # postfix 2.1 #TDsdN reject: RCPT from example.com[10.0.0.5]: 554 Service unavailable; Client host [10.0.0.5] blocked using bl.spamcop.net; Blocked - see http://www.spamcop.net/bl.shtml?10.0.0.5; from= to= proto=ESMTP helo= # postfix 2.3+ #TDsdN reject: RCPT from example.com[10.0.0.6]: 554 5.7.1 Service unavailable; Client host [10.0.0.6] blocked using bl.spamcop.net; Blocked - see http://www.spamcop.net/bl.shtml?10.0.0.6; from= to= proto=SMTP helo= #TDsdN reject: RCPT from example.com[10.0.0.1]: 550 5.7.1 Service unavailable; Client host [10.0.0.1] blocked using Trend Micro RBL+. Please see http://www.mail-abuse.com/cgi-bin/lookup?ip_address=10.0.0.1; Mail from 10.0.0.1 blocked using Trend Micro Email Reputation database. Please see ; from= to= proto=SMTP helo=<10.0.0.1> $Totals{$reject_name = "${rej_type}rejectrbl" }++; next unless ($Collecting{$reject_name}); ($site,$reason) = ($1 =~ /^(.+?)(?:$|(?:[.,] )(.*))/); $reason =~ s/^reason: // if ($reason); $Counts{$reject_name}{$site}{$fmthost}{$reason ? $reason : ''}++; } elsif ($p1 =~ /^<.*>: Helo command rejected: (.*);$/) { $Totals{$reject_name = "${rej_type}rejecthelo" }++; next unless ($Collecting{$reject_name}); $Counts{$reject_name}{ucfirst($1)}{$fmthost}{$helo}++; } elsif ($p1 =~ /^<.*>: Etrn command rejected: (.*);$/) { $Totals{$reject_name = "${rej_type}rejectetrn" }++; next unless ($Collecting{$reject_name}); $Counts{$reject_name}{ucfirst($1)}{$fmthost}{$helo}++; } elsif ($p1 =~ /^<.*>: Data command rejected: (.*);$/) { $Totals{$reject_name = "${rej_type}rejectdata" }++; next unless ($Collecting{$reject_name}); $Counts{$reject_name}{$1}{$fmthost}{$helo}++; } elsif ($p1 =~ /^Insufficient system storage;/) { $Totals{'warninsufficientspace'}++; # force display in Warnings section also $Totals{$reject_name = "${rej_type}rejectinsufficientspace" }++; next unless ($Collecting{$reject_name}); $Counts{$reject_name}{$fmthost}{$eto}{$efrom}++; } elsif ($p1 =~ /^Server configuration (?:error|problem);/) { $Totals{'warnconfigerror'}++; # force display in Warnings section also $Totals{$reject_name = "${rej_type}rejectconfigerror" }++; next unless ($Collecting{$reject_name}); $Counts{$reject_name}{$fmthost}{$eto}{$efrom}++; } elsif ($p1 =~ /^Message size exceeds fixed limit;$/) { # Postfix responds with this message after a MAIL FROM:<...> SIZE=nnn command, where postfix consider's nnn excessive # Note: similar code below: search RejectSize # Note: reject_warning does not seem to occur $Totals{$reject_name = "${rej_type}rejectsize" }++; next unless ($Collecting{$reject_name}); $Counts{$reject_name}{$fmthost}{$eto}{$efrom}++; } elsif ($p1 =~ /^<(.*?)>: Temporary lookup failure;/) { $Totals{$reject_name = "${rej_type}rejectlookupfailure" }++; next unless ($Collecting{$reject_name}); $Counts{$reject_name}{$fmthost}{$eto}{$efrom}++; # This would capture all other rejects, but I think it might be more useful to add # additional capture sections based on user reports of uncapture lines. # #} elsif ( ($reason) = ($p1 =~ /^([^;]+);/)) { # $Totals{$rej_type . 'rejectother'}++; # $Counts{$rej_type . 'rejectother'}{$reason}++; } else { inc_unmatched('rejectother'); } } # end of $re_QID: reject: # QID: ACTION STAGE from host[hostip]: trigger: reason; ftph # #TDsdN warn: RCPT from host[10.0.0.1]: TEST access WARN action; from= to= proto=ESMTP helo= #TDsdN warn: RCPT from host[10.0.0.1]: ; from= to= proto=ESMTP helo= #TDsdN discard: RCPT from host[10.0.0.1]: : Sender address TEST DISCARD action; from= to= proto=ESMTP helo= #TDsdN discard: RCPT from host[10.0.0.1]: : Client host TEST DISCARD action w/ip(client_checks); from= to= proto=ESMTP helo= #TDsdN discard: RCPT from host[10.0.0.1]: : Unverified Client host triggers DISCARD action; from= to= proto=ESMTP helo=<10.0.0.1> #TDsdN hold: RCPT from host[10.0.0.1]: : Recipient address triggers HOLD action; from= to= proto=SMTP helo=<10.0.0.1> #TDsdN hold: RCPT from host[10.0.0.1]: : Helo command optional text...; from= to= proto=ESMTP helo= #TDsdN hold: RCPT from host[10.0.0.1]: : Helo command triggers HOLD action; from= to= proto=ESMTP helo= #TDsdN hold: DATA from host[10.0.0.1]: : Helo command triggers HOLD action; from= to= proto=ESMTP helo= #TDsdN filter: RCPT from host[10.0.0.1]: <>: Sender address triggers FILTER filter:somefilter; from=<> to= proto=SMTP helo= #TDsdN filter: RCPT from host[10.0.0.1]: : Recipient address triggers FILTER smtp-amavis:[127.0.0.1]:10024; from= to= proto=SMTP helo= #TDsdN redirect: RCPT from host[10.0.0.1]: : Client host triggers REDIRECT root@localhost; from= to= proto=SMTP helo= #TDsdN redirect: RCPT from host[10.0.0.1]: : Recipient address triggers REDIRECT root@localhost; from= to= proto=ESMTP helo= # BCC action (postfix 2.6+) #TDsdN bcc: RCPT from host[10.0.0.1]: : Sender address triggers BCC root@localhost; from= to= proto=ESMTP helo= # $re_QID: discard, filter, hold, redirect, warn, bcc, replace ... else { my $trigger; ($trigger,$reason) = ($p1 =~ /^(?:<(\S*)>: )?(.*);$/ ); if ($trigger eq '') { $trigger = '*unavailable'; } else { $trigger =~ s/^<(.+)>$/$1/; } $reason = '*unavailable' if ($reason eq ''); $fmthost = formathost ($hostip,$host); #print "trigger: \"$trigger\", reason: \"$reason\"\n"; # reason -> subject text # subject -> "Helo command" : smtpd_helo_restrictions # subject -> "Client host" : smtpd_client_restrictions # subject -> "Unverified Client host" : smtpd_client_restrictions # subject -> "Client certificate" : smtpd_client_restrictions # subject -> "Sender address" : smtpd_sender_restrictions # subject -> "Recipient address" : smtpd_recipient_restrictions # subject -> "Data command" : smtpd_data_restrictions # subject -> "End-of-data" : smtpd_end_of_data_restrictions # subject -> "Etrn command" : smtpd_etrn_restrictions # text -> triggers action|triggers |optional text... my ($subject, $text) = ($reason =~ /^((?:Recipient|Sender) address|(?:Unverified )?Client host|Client certificate|(?:Helo|Etrn|Data) command|End-of-data) (.+)$/o); #printf "ACTION: '$action', SUBJECT: %-30s TEXT: \"$text\"\n", '"' . $subject . '"'; if ($action eq 'filter') { $Totals{'filtered'}++; next unless ($Collecting{'filtered'}); # See "Note: Counts" before changing $Counts below re: Filtered $text =~ s/triggers FILTER //; if ($subject eq 'Recipient address') { $Counts{'filtered'}{$text}{$subject}{$trigger}{$efrom}{$fmthost}++; } elsif ($subject =~ /Client host$/) { $Counts{'filtered'}{$text}{$subject}{$fmthost}{$eto}{$efrom}++; } else { $Counts{'filtered'}{$text}{$subject}{$trigger}{$eto}{$fmthost}++; } } elsif ($action eq 'redirect') { $Totals{'redirected'}++; next unless ($Collecting{'redirected'}); $text =~ s/triggers REDIRECT //; # See "Note: Counts" before changing $Counts below re: Redirected if ($subject eq 'Recipient address') { $Counts{'redirected'}{$text}{$subject}{$trigger}{$efrom}{$fmthost}++; } elsif ($subject =~ /Client host$/) { $Counts{'redirected'}{$text}{$subject}{$fmthost}{$eto}{$efrom}++; } else { $Counts{'redirected'}{$text}{$subject}{$trigger}{$eto}{$fmthost}++; } } # hold, discard, and warn allow "optional text" elsif ($action eq 'hold') { $Totals{'hold'}++; next unless ($Collecting{'hold'}); # See "Note: Counts" before changing $Counts below re: Hold $subject = $reason unless $text eq 'triggers HOLD action'; if ($subject eq 'Recipient address') { $Counts{'hold'}{$subject}{$trigger}{$efrom}{$fmthost}++; } elsif ($subject =~ /Client host$/) { $Counts{'hold'}{$subject}{$fmthost}{$eto}{$efrom}++; } else { $Counts{'hold'}{$subject}{$trigger}{$eto}{$fmthost}++; } } elsif ($action eq 'discard') { $Totals{'discarded'}++; next unless ($Collecting{'discarded'}); # See "Note: Counts" before changing $Counts below re: Discarded $subject = $reason unless $text eq 'triggers DISCARD action'; if ($subject eq 'Recipient address') { $Counts{'discarded'}{$subject}{$trigger}{$efrom}{$fmthost}++; } elsif ($subject =~ /Client host$/) { $Counts{'discarded'}{$subject}{$fmthost}{$eto}{$efrom}++; } else { $Counts{'discarded'}{$subject}{$trigger}{$eto}{$fmthost}++; } } elsif ($action eq 'warn') { $Totals{'warned'}++; next unless ($Collecting{'warned'}); $Counts{'warned'}{$reason}{$fmthost}{$eto}{''}++; # See "Note: Counts" before changing $Counts above... } elsif ($action eq 'bcc') { $Totals{'bcced'}++; next unless ($Collecting{'bcced'}); # See "Note: Counts" before changing $Counts below re: Filtered $text =~ s/triggers BCC //o; if ($subject eq 'Recipient address') { $Counts{'bcced'}{$text}{$subject}{$trigger}{$efrom}{$fmthost}++; } elsif ($subject =~ /Client host$/) { $Counts{'bcced'}{$text}{$subject}{$fmthost}{$eto}{$efrom}++; } else { $Counts{'bcced'}{$text}{$subject}{$trigger}{$eto}{$fmthost}++; } } else { die "Unexpected ACTION: '$action'"; } } } elsif ($p1 =~ s/^client=(([^ ]*)\[([^ ]*)\](?::(?:\d+|unknown))?)//) { my ($hip,$host,$hostip) = ($1,$2,$3); # Increment accepted when the client connection is made and smtpd has a QID. # Previously, accepted was being incorrectly incremented when the first qmgr # "from=xxx, size=nnn ..." line was seen. This is erroneous when the smtpd # client connection occurred outside the date range of the log being analyzed. $AcceptedByQid{$qid} = $hip; $Totals{'msgsaccepted'}++; #TDsdQ client=unknown[192.168.0.1] #TDsdQ client=unknown[192.168.0.1]:unknown #TDsdQ client=unknown[192.168.0.1]:10025 #TDsd client=example.com[192.168.0.1], helo=example.com #TDsdQ client=mail.example.com[2001:dead:beef::1] #TDsdQ client=localhost[127.0.0.1], sasl_sender=someone@example.com #TDsdQ client=example.com[192.168.0.1], sasl_method=PLAIN, sasl_username=anyone@sample.net #TDsdQ client=example.com[192.168.0.1], sasl_method=LOGIN, sasl_username=user@example.com, sasl_sender= #TDsdQ client=unknown[10.0.0.1], sasl_sender=user@examine.com next if ($p1 eq ''); my ($method,$user,$sender) = ($p1 =~ /^(?:, sasl_method=([^,]+))?(?:, sasl_username=([^,]+))?(?:, sasl_sender=?)?$/); # sasl_sender occurs when AUTH verb is present in MAIL FROM, typically used for relaying # the username (eg. sasl_username) of authenticated users. if ($sender or $method or $user) { $Totals{'saslauth'}++; next unless ($Collecting{'saslauth'}); $method ||= '*unknown method'; $user ||= '*unknown user'; $Counts{'saslauth'}{$user . ($sender ? " ($sender)" : '')}{$method}{formathost($hostip,$host)}++; } } # ^$re_QID: ... (not access(5) action) elsif ($p1 =~ /^from=<(.*?)>, size=(\d+), nrcpt=(\d+)/) { my ($efrom,$bytes,$nrcpt) = ($1,$2,$3); #TDsdQ from=, size=4051, nrcpt=1 (queue active) #TDsdQ(12) from=, size=25302, nrcpt=2 (queue active) #TDsdQ from=, size=5529, nrcpt=1 (queue active) #TDsdQ from=, size=5335, nrcpt=1 (queue active) # Distinguish bytes accepted vs. bytes delivered due to multiple recips # Increment bytes accepted on the first qmgr "from=..." line... next if (exists $SizeByQid{$qid}); $SizeByQid{$qid} = $bytes; # ...but only when the smtpd "client=..." line has been seen too. # This under-counts when the smtpd "client=..." connection log entry and the # qmgr "from=..." log entry span different periods (as fed to postfix-logwatch). next if (! exists $AcceptedByQid{$qid}); $Totals{'bytesaccepted'} += $bytes; $Counts{'envelopesenders'}{$efrom ne '' ? $efrom : '<>'}++ if ($Collecting{'envelopesenders'}); if ($Collecting{'envelopesenderdomains'}) { my ($localpart, $domain); if ($efrom eq '') { ($localpart, $domain) = ('<>', '*unknown'); } else { ($localpart, $domain) = split (/@/, lc $efrom); } $Counts{'envelopesenderdomains'}{$domain ne '' ? $domain : '*unknown'}{$localpart}++; } delete $AcceptedByQid{$qid}; # prevent incrementing BytesAccepted again } ### sent, forwarded, bounced, softbounce, deferred, (un)deliverable elsif ($p1 =~ s/^to=<(.*?)>,(?: orig_to=<(.*?)>,)? relay=([^,]*).*, ($re_DDD), status=(\S+) //o) { ($relay,$status) = ($3,$5); my ($to,$origto,$localpart,$domainpart,$dsn,$p1) = process_delivery_attempt ($1,$2,$4,$p1); #TD 552B6C20E: to=, relay=mail.example.net[10.0.0.1]:25, delay=1021, delays=1020/0.04/0.56/0.78, dsn=2.0.0, status=sent (250 Ok: queued as 6EAC4719EB) #TD 552B6C20E: to=, relay=mail.example.net[10.0.0.1]:25, conn_use=2 delay=1021, delays=1020/0.04/0.56/0.78, dsn=2.0.0, status=sent (250 Ok: queued as 6EAC4719EB) #TD DD925BBE2: to=, orig_to=, relay=mail.example.net[2001:dead:beef::1], delay=2, status=sent (250 Ok: queued as 5221227246) ### sent if ($status eq 'sent') { if ($p1 =~ /forwarded as /) { $Totals{'bytesforwarded'} += $SizeByQid{$qid} if (exists $SizeByQid{$qid}); $Totals{'forwarded'}++; next unless ($Collecting{'forwarded'}); $Counts{'forwarded'}{$domainpart}{$localpart}{$origto}++; } else { if ($service_name eq 'lmtp') { $Totals{'bytessentlmtp'} += $SizeByQid{$qid} if (exists $SizeByQid{$qid}); $Totals{'sentlmtp'}++; next unless ($Collecting{'sentlmtp'}); $Counts{'sentlmtp'}{$domainpart}{$localpart}{$origto}++; } elsif ($service_name eq 'smtp') { $Totals{'bytessentsmtp'} += $SizeByQid{$qid} if (exists $SizeByQid{$qid}); $Totals{'sent'}++; next unless ($Collecting{'sent'}); $Counts{'sent'}{$domainpart}{$localpart}{$origto}++; } # virtual, command, ... else { $Totals{'bytesdelivered'} += $SizeByQid{$qid} if (exists $SizeByQid{$qid}); $Totals{'delivered'}++; next unless ($Collecting{'delivered'}); $Counts{'delivered'}{$domainpart}{$localpart}{$origto}++; } } } elsif ($status eq 'deferred') { #TDsQ to=, relay=none, delay=27077, delays=27077/0/0.57/0, dsn=4.4.3, status=deferred (Host or domain name not found. Name service error for name=example.com type=MX: Host not found, try again) #TDsQ to=, relay=none, delay=141602, status=deferred (connect to mx1.example.com[10.0.0.1]: Connection refused) #TDsQ to=, relay=none, delay=141602, status=deferred (delivery temporarily suspended: connect to example.com[192.168.0.1]: Connection refused) #TDsQ to=, relay=none, delay=306142, delays=306142/0.04/0.18/0, dsn=4.4.1, status=deferred (connect to example.com[10.0.0.1]: Connection refused) #TDsQ to=, relay=example.org[10.0.0.1], delay=48779, status=deferred (lost connection with mail.example.org[10.0.0.1] while sending MAIL FROM) #TDsQ to=, relay=sample.net, delay=26541, status=deferred (conversation with mail.example.com timed out while sending end of data -- message may be sent more than once) #TDsQ to=, relay=sample.net[10.0.0.1]:25, delay=322, delays=0.04/0/322/0, dsn=4.4.2, status=deferred (conversation with example.com[10.0.0.01] timed out while receiving the initial server greeting) #TDsQ to=, orig_to=, relay=none, delay=238024, status=deferred (delivery temporarily suspended: transport is unavailable) # XXX postfix reports dsn=5.0.0, host's reply may contain its own dsn's such as 511 and #5.1.1 # XXX should these be used instead? #TDsQ to=, relay=sample.net[10.0.0.1]:25, delay=5.7, delays=0.05/0.02/5.3/0.3, dsn=4.7.1, status=deferred (host sample.net[10.0.0.1] said: 450 4.7.1 : Recipient address rejected: Greylisted (in reply to RCPT TO command)) #TDsQ to=, relay=example.com[10.0.0.1]:25, delay=79799, delays=79797/0.02/0.4/1.3, dsn=4.0.0, status=deferred (host example.com[10.0.0.1] said: 450 : User unknown in local recipient table (in reply to RCPT TO command)) #TDsQ to=, relay=example.com[10.0.0.1]:25, delay=97, delays=0.03/0/87/10, dsn=4.0.0, status=deferred (host example.com[10.0.0.1] said: 450 : Recipient address rejected: undeliverable address: User unknown in virtual alias table (in reply to RCPT TO command)) ($reply,$fmthost) = cleanhostreply($p1,$relay,$to,$domainpart); $Totals{'deferred'}++ if ($DeferredByQid{$qid}++ == 0); $Totals{'deferrals'}++; next unless ($Collecting{'deferrals'}); $Counts{'deferrals'}{get_dsn_msg($dsn)}{$reply}{$domainpart}{$localpart}{$fmthost}++; } ### bounced elsif ($status eq 'bounced' or $status eq 'SOFTBOUNCE') { # local agent #TDlQ to=, relay=local, delay=2.5, delays=2.1/0.22/0/0.21, dsn=5.1.1, status=bounced (unknown user: "friend") # smtp agent #TDsQ to=, orig_to=, relay=sample.net[10.0.0.1]:25, delay=22, delays=0.02/0.09/22/0.07, dsn=5.0.0, status=bounced (host sample.net[10.0.0.1] said: 551 invalid address (in reply to MAIL FROM command)) #TDsQ to=, relay=sample.net[10.0.0.1]:25, delay=11, delays=0.13/0.07/0.98/0.52, dsn=5.0.0, status=bounced (host sample.net[10.0.0.1] said: 550 MAILBOX NOT FOUND (in reply to RCPT TO command)) #TDsQ to=, orig_to=, relay=sample.net[10.0.0.1]:25, delay=22, delays=0.02/0.09/22/0.07, dsn=5.0.0, status=bounced (host sample.net[10.0.0.1] said: 551 invalid address (in reply to MAIL FROM command)) #TDsQ to=, relay=none, delay=0.57, delays=0.57/0/0/0, dsn=5.4.6, status=bounced (mail for sample.net loops back to myself) #TDsQ to=<>, relay=none, delay=1, status=bounced (mail for sample.net loops back to myself) #TDsQ to=, relay=none, delay=0, status=bounced (Host or domain name not found. Name service error for name=unknown.com type=A: Host not found) # XXX verify these... #TD EB0B8770: to=, orig_to=, relay=none, delay=1, status=bounced (User unknown in virtual alias table) #TD EB0B8770: to=, orig_to=, relay=sample.net[192.168.0.1], delay=1.1, status=bounced (User unknown in relay recipient table) #TD D8962E54: to=, relay=local, conn_use=2 delay=0.21, delays=0.05/0.02/0/0.14, dsn=4.1.1, status=SOFTBOUNCE (unknown user: "to") #TD F031C832: to=, orig_to=, relay=local, delay=0.17, delays=0.13/0.01/0/0.03, dsn=5.1.1, status=bounced (unknown user: "to") #TD C76431E2: to=, relay=local, delay=2, status=SOFTBOUNCE (host sample.net[192.168.0.1] said: 450 : User unknown in local recipient table (in reply to RCPT TO command)) #TD 04B0702E: to=, relay=example.com[10.0.0.1]:25, delay=12, delays=6.5/0.01/0.03/5.1, dsn=5.1.1, status=bounced (host example.com[10.0.0.1] said: 550 5.1.1 User unknown (in reply to RCPT TO command)) #TD 9DAC8B2D: to=, relay=example.com[10.0.0.1]:25, delay=1.4, delays=0.04/0/0.27/1.1, dsn=5.0.0, status=bounced (host example.com[10.0.0.1] said: 511 sorry, no mailbox here by that name (#5.1.1 - chkuser) (in reply to RCPT TO command)) #TD 79CB702D: to=, relay=example.com[10.0.0.1]:25, delay=0.3, delays=0.04/0/0.61/0.8, dsn=5.0.0, status=bounced (host example.com[10.0.0.1] said: 550 , Recipient unknown (in reply to RCPT TO command)) #TD 88B7A079: to=, relay=example.com[10.0.0.1]:25, delay=45, delays=0.03/0/5.1/40, dsn=5.0.0, status=bounced (host example.com[10.0.0.1] said: 550-"The recipient cannot be verified. Please check all recipients of this 550 message to verify they are valid." (in reply to RCPT TO command)) #TD 47B7B074: to=, relay=example.com[10.0.0.1]:25, delay=6.6, delays=6.5/0/0/0.11, dsn=5.1.1, status=bounced (host example.com[10.0.0.1] said: 550 5.1.1 User unknown; rejecting (in reply to RCPT TO command)) #TDppQ to=, relay=dbmail-pipe, delay=0.15, delays=0.09/0.01/0/0.06, dsn=5.3.0, status=bounced (Command died with signal 11: "/usr/sbin/dbmail-smtp") # print "bounce message from " . $to . " msg : " . $relay . "\n"; # See same code elsewhere "Note: Bounce" ### local bounce # XXX local v. remote bounce seems iffy, relative if ($relay =~ /^(?:none|local|virtual|127\.0\.0\.1|maildrop|avcheck)/) { $Totals{'bouncelocal'}++; next unless ($Collecting{'bouncelocal'}); $Counts{'bouncelocal'}{get_dsn_msg($dsn)}{$domainpart}{ucfirst($p1)}{$localpart}++; } else { $Totals{'bounceremote'}++; next unless ($Collecting{'bounceremote'}); ($reply,$fmthost) = cleanhostreply($p1,$relay,$to,$domainpart); $Counts{'bounceremote'}{get_dsn_msg($dsn)}{$domainpart}{$localpart}{$fmthost}{$reply}++; } } elsif ($status =~ 'undeliverable') { #TDsQ to=, relay=sample.com[10.0.0.1], delay=0, dsn=5.0.0, status=undeliverable (host sample.com[10.0.0.1] refused to talk to me: 554 5.7.1 example.com Connection not authorized) #TDsQ to=, relay=mx.example.com[10.0.0.1]:25, conn_use=2, delay=5.5, delays=0.03/0/0.21/5.3, dsn=5.0.0, status=undeliverable-but-not-cached (host mx.example.com[10.0.0.1] said: 550 RCPT TO: User unknown (in reply to RCPT TO command)) #TDvQ to=, relay=virtual, delay=0.14, delays=0.06/0/0/0.08, dsn=5.1.1, status=undeliverable (unknown user: "u@example.com") #TDlQ to=, relay=local, delay=0.02, delays=0.01/0/0/0, dsn=5.1.1, status=undeliverable-but-not-cached (unknown user: "to") $Totals{'undeliverable'}++; next unless ($Collecting{'undeliverable'}); if ($p1 =~ /^unknown user: ".+?"$/) { $Counts{'undeliverable'}{get_dsn_msg($dsn)}{'Unknown user'}{$domainpart}{$localpart}{$origto ? $origto : ''}++; } else { my ($reply,$fmthost) = cleanhostreply($p1,'',$to ne '' ? $to : '<>',$domainpart); $Counts{'undeliverable'}{get_dsn_msg($dsn)}{$reply}{$domainpart}{$localpart}{$fmthost}++; } } elsif ($status eq 'deliverable') { # address verification, sendmail -bv deliverable reports #TDvQ to=, relay=virtual, delay=0.09, delays=0.03/0/0/0.06, dsn=2.0.0, status=deliverable (delivers to maildir) $Totals{'deliverable'}++; next unless ($Collecting{'deliverable'}); my $dsn = ($p1 =~ s/^($re_DSN) // ? $1 : '*unavailable'); $Counts{'deliverable'}{$dsn}{$p1}{$origto ? "$to ($origto)" : $to}++; } else { # keep this as the last condition in this else clause inc_unmatched('unknownstatus'); } } # end of sent, forwarded, bounced, softbounce, deferred, (un)deliverable # pickup elsif ($p1 =~ /^(uid=\S* from=<.*?>)/) { #TDpQ2 uid=0 from= $AcceptedByQid{$qid} = $1; $Totals{'msgsaccepted'}++; } elsif ($p1 =~ /^from=<(.*?)>, status=expired, returned to sender$/) { #TDqQ from=, status=expired, returned to sender $Totals{'returnedtosender'}++; next unless ($Collecting{'returnedtosender'}); $Counts{'returnedtosender'}{$1 ne '' ? $1 : '<>'}++; } elsif ($p1 =~ s/^host ([^[]+)\[([^]]+)\](?::\d+)? refused to talk to me://) { #TDsQ host mail.example.com[10.0.0.1] refused to talk to me: 553 Connections are being blocked due to previous incidents of abuse #TDsQ host mail.example.com[10.0.0.1] refused to talk to me: 501 Connection from 192.168.2.1 (XY) rejected # Note: See ConnectToFailure above $Totals{'connecttofailure'}++; next unless ($Collecting{'connecttofailure'}); $Counts{'connecttofailure'}{'Refused to talk to me'}{formathost($2,$1)}{$p1}++; } elsif ($p1 =~ /^lost connection with ([^[]*)\[([^]]+)\](?::\d+)? (while .*)$/) { # outbound smtp #TDsQ lost connection with sample.net[10.0.0.1] while sending MAIL FROM #TDsQ lost connection with sample.net[10.0.0.2] while receiving the initial server greeting $Totals{'connectionlostoutbound'}++; next unless ($Collecting{'connectionlostoutbound'}); $Counts{'connectionlostoutbound'}{ucfirst($3)}{formathost($2,$1)}++; } elsif ($p1 =~ /^conversation with ([^[]*)\[([^]]+)\](?::\d+)? timed out (while .*)$/) { #TDsQ conversation with sample.net[10.0.0.1] timed out while receiving the initial SMTP greeting # Note: see TimeoutInbound below $Totals{'timeoutinbound'}++; next unless ($Collecting{'timeoutinbound'}); $Counts{'timeoutinbound'}{ucfirst($3)}{formathost($2,$1)}{''}++; } elsif ($p1 =~ /^enabling PIX (\.) workaround for ([^[]+)\[([^]]+)\](?::\d+)?/ or $p1 =~ /^enabling PIX workarounds: (.*) for ([^[]+)\[([^]]+)\](?::\d+)?/) { #TDsQ enabling PIX . workaround for example.com[192.168.0.1] #TDsQ enabling PIX . workaround for mail.sample.net[10.0.0.1]:25 #TDsQ enabling PIX workarounds: disable_esmtp delay_dotcrlf for spam.example.org[10.0.0.1]:25 $Totals{'pixworkaround'}++; next unless ($Collecting{'pixworkaround'}); $Counts{'pixworkaround'}{$1}{formathost($3,$2)}++; } # milter-reject, milter-hold, milter-discard elsif ($p1 =~ s/^milter-//) { milter_common($p1); } elsif ($p1 =~ s/^SASL (\[CACHED\] )?authentication failed; //) { #TDsQ SASL authentication failed; cannot authenticate to server smtp.example.com[10.0.0.1]: no mechanism available #TDsQ SASL authentication failed; server example.com[10.0.0.1] said: 535 Error: authentication failed #TDsQ SASL [CACHED] authentication failed; server example.com[10.0.0.1] said: 535 Error: authentication failed # see saslauthfail elsewhere $Totals{'saslauthfail'}++; next unless ($Collecting{'saslauthfail'}); my $cached = $1; if ($p1 =~ /^(authentication protocol loop with server): ([^[]+)\[([^]]+)\](?::\d+)?$/) { ($reason,$host,$hostip,$reason2) = ($1,$2,$3,''); } elsif ($p1 =~ /^(cannot authenticate to server) ([^[]+)\[([^]]+)\](?::\d+)?: (.*)$/) { ($reason,$host,$hostip,$reason2) = ($1,$2,$3,$4); } elsif ($p1 =~ /^server ([^[]+)\[([^]]+)\](?::\d+)? said: (.+)$/) { ($reason,$host,$hostip,$reason2) = ('server ... said',$1,$2,$3); } else { inc_unmatched('saslauthfail'); next; } $reason .= ': ' . $reason2 if $reason2; $Counts{'saslauthfail'}{$cached . $reason}{formathost($hostip,$host)}++; } elsif (($host,$hostip) = ($p1 =~ /abort: TLS from ([^[]+)\[([^]]+)\]: No client certificate presented/)) { $Totals{'tlsservernocert'}++; next unless ($Collecting{'tlsservernocert'}); $Counts{'tlsservernocert'}{formathost($hostip,$host)}++; } elsif (($host,$hostip) = ($p1 =~ /abort: TLS from ([^[]+)\[([^]]+)\]: Client certificate not trusted/)) { $Totals{'tlsclientcertnottrusted'}++; next unless ($Collecting{'tlsclientcertnottrusted'}); $Counts{'tlsclientcertnottrusted'}{formathost($hostip,$host)}++; } else { # keep this as the last condition in this else clause inc_unmatched('unknownqid') if ! in_ignore_list ($p1); } } # end of $re_QID section elsif ($p1 =~ /^(timeout|lost connection) (after [^ ]+)(?: \((?:approximately )?(\d+) bytes\))? from ([^[]*)\[([^]]+)\](?::\d+)?$/) { my ($lort,$reason,$bytes,$host,$hostip) = ($1,$2,$3,$4,$5); if ($lort eq 'timeout') { # see also TimeoutInbound in $re_QID section #TDsd timeout after RSET from example.com[192.168.0.1] #TDsd timeout after DATA (6253 bytes) from example.com[10.0.0.1] $Totals{'timeoutinbound'}++; next unless ($Collecting{'timeoutinbound'}); $Counts{'timeoutinbound'}{ucfirst($reason)}{formathost($hostip,$host)}{commify($bytes)}++; } else { #TDsd lost connection after CONNECT from mail.example.com[192.168.0.1] # postfix 2.5:20071003 #TDsd lost connection after DATA (494133 bytes) from localhost[127.0.0.1] # postfix 2.6:20080621 #TDsd lost connection after DATA (approximately 0 bytes) from example.com[10.0.0.1] $Totals{'connectionlostinbound'}++; next unless ($Collecting{'connectionlostinbound'}); $Counts{'connectionlostinbound'}{ucfirst($reason)}{formathost($hostip,$host)}{commify($bytes)}++; } } elsif ($p1 =~ /^(reject(?:_warning)?): RCPT from ([^[]+)\[([^]]+)\](?::\d+)?: ($re_DSN) Service (?:temporarily )?(?:unavailable|denied)[^;]*; (?:(?:Unverified )?Client host |Sender address |Helo command )?\[[^ ]*\] blocked using ([^;]+);/o) { my ($rej_type,$host,$hostip,$dsn,) = ($1,$2,$3,$4); ($site,$reason) = ($5 =~ /^(.+?)(?:$|(?:[.,] )(.*))/); $reason =~ s/^reason: // if ($reason); $rej_type = ($rej_type =~ /_warning/ ? 'warn' : get_reject_key($dsn)); #print "REJECT RBL NOQ: '$rej_type'\n"; # Note: similar code above: search RejectRBL # This section required: postfix didn't always log QID (eg. postfix 1.1) # Also, "reason:" was probably always present in this case, but I'm not certain # postfix 1.1 #TDsd reject_warning: RCPT from example.com[10.0.0.1]: 554 Service unavailable; [10.0.0.1] blocked using orbz.org, reason: Open relay. Please see http://orbz.org/?10.0.0.1; from= to= #TDsd reject: RCPT from example.com[10.0.0.2]: 554 Service unavailable; [10.0.0.2] blocked using orbz.org, reason: Open relay. Please see http://orbz.org/?10.0.0.2; from= to= #TDsd reject: RCPT from unknown[10.0.0.3]: 554 Service unavailable; [10.0.0.3] blocked using bl.spamcop.net, reason: Blocked - see http://www.spamcop.net/bl.shtml?10.0.0.3; from= to= #TDsd reject: RCPT from example.com[10.0.0.4]: 554 Service unavailable; [10.0.0.4] blocked using sbl.spamhaus.org, reason: http://www.spamhaus.org/SBL/sbl.lasso?query=B12057; from= to= if ($Collecting{'byiprejects'} and substr($rej_type,0,1) eq '5') { $fmthost = formathost($hostip,$host); $Counts{'byiprejects'}{$fmthost}++; } $Totals{$reject_name = "${rej_type}rejectrbl" }++; next unless ($Collecting{$reject_name}); $Counts{$reject_name}{$site}{$fmthost ? $fmthost : formathost($hostip,$host)}{$reason ? $reason : ''}++; } # proxy-reject, proxy-accept elsif ($p1 =~ s/^proxy-(reject|accept): ([^:]+): //) { # 2.7 #TDsdN proxy-accept: END-OF-MESSAGE: 250 2.0.0 Ok: queued as 9BE3547AFE; from= to= proto=ESMTP helo= #TDsdN proxy-reject: END-OF-MESSAGE: 554 5.7.0 Reject, id=11912-03 - INFECTED: Eicar-Test-Signature; from= to= proto=ESMTP helo= #TDsdN proxy-reject: END-OF-MESSAGE: ; from= to= proto=SMTP helo= next if $1 eq 'accept'; #ignore accepts my ($stage) = ($2); my ($efrom,$eto,$proto,$helo) = strip_ftph($p1); #print "efrom: '$efrom', eto: '$eto', proto: '$proto', helo: '$helo'\n"; #print "stage: '$stage', reply: '$p1'\n"; my ($dsn,$reject_name); ($dsn,$reply) = ($1,$2) if $p1 =~ /^($re_DSN) (.*)$/o; #print " dsn: '$dsn', reply: '$reply', key: ", get_reject_key($dsn), "\n"; # DSN may not be present. Can occur, for example, when queue file size limit is reached, # which is logged as a Warning. Ignore these, since they can't be add to any # reject section (no SMTP reply code). if (! defined $dsn) { next; } $Totals{$reject_name = get_reject_key($dsn) . 'rejectproxy' }++; next unless ($Collecting{$reject_name}); $Counts{$reject_name}{$stage}{$reply}{$eto}++; } ### smtpd_tls_loglevel >= 1 # Server TLS messages elsif (($status,$host,$hostip,$type) = ($p1 =~ /^(?:(Anonymous|Trusted|Untrusted) )?TLS connection established from ([^[]+)\[([^]]+)\](?::\d+)?(?: to [^:]+)?: (.*)$/)) { #TDsd TLS connection established from example.com[192.168.0.1]: TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits) # Postfix 2.5+: status: Untrusted or Trusted #TDsd Untrusted TLS connection established from example.com[192.168.0.1]: TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits) #TDsd Anonymous TLS connection established from localhost[127.0.0.1]: TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits) $Totals{'tlsserverconnect'}++; next unless ($Collecting{'tlsserverconnect'}); $Counts{'tlsserverconnect'}{$status ? "$status: $type" : $type}{formathost($hostip,$host)}++; } # Client TLS messages elsif ( ($status,$host,$type) = ($p1 =~ /^(?:(Verified|Trusted|Untrusted|Anonymous) )?TLS connection established to ([^ ]*): (.*)$/o)) { #TD TLS connection established to example.com: TLSv1 with cipher AES256-SHA (256/256 bits) # Postfix 2.5+: peer verification status: Untrusted, Trusted or Verified when # server's trust chain is valid and peername is matched #TD Verified TLS connection established to 127.0.0.1[127.0.0.1]:26: TLSv1 with cipher DHE-DSS-AES256-SHA (256/256 bits) $Totals{'tlsclientconnect'}++; next unless ($Collecting{'tlsclientconnect'}); $Counts{'tlsclientconnect'}{$status ? "$status: $type" : $type}{$host}++; } # smtp_tls_note_starttls_offer=yes elsif ($p1 =~ /^Host offered STARTTLS: \[(.*)\]$/o) { #TD Host offered STARTTLS: [mail.example.com] $Totals{'tlsoffered'}++; next unless ($Collecting{'tlsoffered'}); $Counts{'tlsoffered'}{$1}++; } ### smtpd_tls_loglevel >= 1 elsif ($p1 =~ /^Unverified: (.*)/o) { #TD Unverified: subject_CN=(www|smtp|mailhost).(example.com|sample.net), issuer=someuser $Totals{'tlsunverified'}++; next unless ($Collecting{'tlsunverified'}); $Counts{'tlsunverified'}{$1}++; } # Note: no QID elsif (($host,$hostip,$dsn,$from,$to) = ($p1 =~ /^reject: RCPT from ([^[]+)\[([^]]+)\](?::\d+)?: ([45]52) Message size exceeds fixed limit; from=<(.*?)> to=<(.*?)>/)) { #TD reject: RCPT from size.example.com[192.168.0.1]: 452 Message size exceeds fixed limit; from= to= #TD reject: RCPT from size.example.com[192.168.0.1]: 552 Message size exceeds fixed limit; from= to= proto=ESMTP helo= # Note: similar code above: search RejectSize # Note: reject_warning does not seem to occur if ($Collecting{'byiprejects'} and substr($dsn,0,1) eq '5') { $fmthost = formathost($hostip,$host); $Counts{'byiprejects'}{$fmthost}++; } $Totals{$reject_name = get_reject_key($dsn) . 'rejectsize' }++; next unless ($Collecting{$reject_name}); $Counts{$reject_name}{$fmthost ? $fmthost : formathost($hostip,$host)}{$to}{$from ne '' ? $from : '<>'}++; } elsif ($p1 =~ /looking for plugins in (.*)$/) { #TD looking for plugins in '/usr/lib/sasl2', failed to open directory, error: No such file or directory $Totals{'warnconfigerror'}++; next unless ($Collecting{'warnconfigerror'}); $Counts{'warnconfigerror'}{$1}++; } # SMTP/ESMTP protocol violations elsif ($p1 =~ /^(improper command pipelining) (after \S+) from ([^[]*)\[([^]]+)\](?::\d+)?/) { # ProtocolViolation #TDsd postfix/smtpd[24928]: improper command pipelining after RCPT from unknown[192.168.0.1] my ($error,$stage,$host,$hostip) = ($1,$2,$3,$4); $Totals{'smtpprotocolviolation'}++; next unless ($Collecting{'smtpprotocolviolation'}); $Counts{'smtpprotocolviolation'}{ucfirst($error)}{ucfirst($stage)}{formathost($hostip,$host)}++; } elsif ($p1 =~ /^(too many errors) (after [^ ]*)(?: \((?:approximately )?\d+ bytes\))? from ([^[]*)\[([^]]+)\](?::\d+)?$/) { my ($error,$stage,$host,$hostip) = ($1,$2,$3,$4); #TDsd too many errors after AUTH from sample.net[10.0.0.1] #TDsd too many errors after DATA (0 bytes) from 1-0-0-10.example.com[10.0.0.1] $Totals{'smtpprotocolviolation'}++; next unless ($Collecting{'smtpprotocolviolation'}); $Counts{'smtpprotocolviolation'}{ucfirst($error)}{ucfirst($stage)}{formathost($hostip,$host)}++; } # coerce these into general warnings elsif ( $p1 =~ /^cannot load Certificate Authority data/ or $p1 =~ /^SSL_connect error to /) { #TDsQ Cannot start TLS: handshake failure #TDsd cannot load Certificate Authority data #TDs SSL_connect error to mail.example.com: 0 postfix_warning($p1); } else { # add to the unmatched list if not on the ignore_list inc_unmatched('final') if ! in_ignore_list ($p1); } } ######################################## # Final tabulations, and report printing for my $code (@RejectKeys) { for my $type (@RejectClasses) { $Totals{'totalrejects' . $code} += $Totals{$code . $type}; } if ($code =~ /^5/o) { $Totals{'totalrejects'} += $Totals{'totalrejects' . $code}; } } # XXX this was naive - the goal was to avoid recounting messages # released from quarantine, but externally introduced messages may # contain resent-message-id; trying to track only internally resent # messages does not seem useful. # make some corrections now, due to double counting #$Totals{'msgsaccepted'} -= $Totals{'resent'} if ($Totals{'msgsaccepted'} >= $Totals{'resent'}); $Totals{'totalacceptplusreject'} = $Totals{'msgsaccepted'} + $Totals{'totalrejects'}; # Print the Summary report if any key has non-zero data. # Note: must explicitly check for any non-zero data, # as Totals always has some keys extant. # if ($Opts{'summary'}) { for (keys %Totals) { if ($Totals{$_}) { print_summary_report (@Sections); last; } } } # Print the Detail report, if detail is sufficiently high # if ($Opts{'detail'} >= 5) { #print STDERR "Counts memory usage: ", commify(Devel::Size::total_size(\%Counts)), "\n"; #print STDERR "Delays memory usage: ", commify(Devel::Size::total_size(\%Delays)), "\n"; print_detail_report(@Sections); if ($Opts{'delays'}) { my @table; for (sort keys %Delays) { # anon array ref: label, array ref of $Delay{key} push @table, [ substr($_,3), $Delays{$_} ]; } if (@table) { print_percentiles_report2(\@table, "Delivery Delays Percentiles", $Opts{'delays_percentiles'}); } } print_postgrey_reports(); } # Print the mailqueue if requested my $pathto_postqueue = $ENV{'pathto_postqueue'} || '/usr/sbin/postqueue'; if ($Opts{'mailqueue'} and -x $pathto_postqueue) { open(QUEUE,"$pathto_postqueue -p |"); while () { # Do not display empty queue if detail < 5 next if /Mail queue is empty/ and $Opts{'detail'} < 5; print; } close(QUEUE); print "\n"; } # debug: show which ignore_list items are hit most #my %IGNORED; #for (sort { $IGNORED{$b} <=> $IGNORED{$a} } keys %IGNORED) { # printf "%10d: KEY: %s\n", $IGNORED{$_}, $_; #} # Finally, print any unmatched lines # print_unmatched_report(); # # End of main # ################################################## # Create the list of REs against which log lines are matched. # Lines that match any of the patterns in this list are ignored. # # Note: This table is created at runtime, due to a Perl bug which # I reported as perl bug #56202: # # http://rt.perl.org/rt3/Public/Bug/Display.html?id=56202 # sub create_ignore_list() { # top 3 hitters up front push @ignore_list, qr/^statistics:/; push @ignore_list, qr/^setting up TLS connection (?:from|to)/; push @ignore_list, qr/^Verified: /; push @ignore_list, qr/^skipped, still being delivered/; # SSL info at/above mail.info level push @ignore_list, qr/^read from [a-fA-F\d]{8}/; push @ignore_list, qr/^write to [a-fA-F\d]{8}/; push @ignore_list, qr/^[a-f\d]{4} [a-f\d]{2}/; push @ignore_list, qr/^[a-f\d]{4} - ]+ /; push @ignore_list, qr/^premature end-of-input (?:on|from) .* socket while reading input attribute name$/; push @ignore_list, qr/^certificate peer name verification failed/; push @ignore_list, qr/^Peer certi?ficate could not be verified$/; # missing i was a postfix typo push @ignore_list, qr/^Peer cert verify depth=/; push @ignore_list, qr/^Peer verification:/; push @ignore_list, qr/^Server certificate could not be verified/; push @ignore_list, qr/^cannot load .SA certificate and key data/; push @ignore_list, qr/^tlsmgr_cache_run_event/; push @ignore_list, qr/^SSL_accept/; push @ignore_list, qr/^SSL_connect:/; push @ignore_list, qr/^connection (?:closed|established)/; push @ignore_list, qr/^delete smtpd session/; push @ignore_list, qr/^put smtpd session/; push @ignore_list, qr/^save session/; push @ignore_list, qr/^Reusing old/; push @ignore_list, qr/^looking up session/; push @ignore_list, qr/^lookup smtpd session/; push @ignore_list, qr/^lookup \S+ type/; push @ignore_list, qr/^xsasl_(?:cyrus|dovecot)_/; push @ignore_list, qr/^watchdog_/; push @ignore_list, qr/^read smtpd TLS/; push @ignore_list, qr/^open smtpd TLS/; push @ignore_list, qr/^write smtpd TLS/; push @ignore_list, qr/^read smtp TLS cache entry/; push @ignore_list, qr/^starting TLS engine$/; push @ignore_list, qr/^initializing the server-side TLS/; push @ignore_list, qr/^global TLS level: /; push @ignore_list, qr/^auto_clnt_/; push @ignore_list, qr/^generic_checks:/; push @ignore_list, qr/^inet_addr_/; push @ignore_list, qr/^mac_parse:/; push @ignore_list, qr/^cert has expired/; push @ignore_list, qr/^daemon started/; push @ignore_list, qr/^master_notify:/; push @ignore_list, qr/^rewrite_clnt:/; push @ignore_list, qr/^rewrite stream/; push @ignore_list, qr/^dict_/; push @ignore_list, qr/^send attr /; push @ignore_list, qr/^match_/; push @ignore_list, qr/^input attribute /; push @ignore_list, qr/^Run-time/; push @ignore_list, qr/^Compiled against/; push @ignore_list, qr/^private\//; push @ignore_list, qr/^reject_unknown_/; # don't combine or shorten these reject_ patterns push @ignore_list, qr/^reject_unauth_/; push @ignore_list, qr/^reject_non_/; push @ignore_list, qr/^permit_/; push @ignore_list, qr/^idle timeout/; push @ignore_list, qr/^get_dns_/; push @ignore_list, qr/^dns_/; push @ignore_list, qr/^chroot /; push @ignore_list, qr/^process generation/; push @ignore_list, qr/^fsspace:/; push @ignore_list, qr/^master disconnect/; push @ignore_list, qr/^resolve_clnt/; push @ignore_list, qr/^ctable_/; push @ignore_list, qr/^extract_addr/; push @ignore_list, qr/^mynetworks:/; push @ignore_list, qr/^name_mask:/; #TDm reload -- version 2.6-20080814, configuration /etc/postfix #TDm reload configuration /etc/postfix push @ignore_list, qr/^reload (?:-- version \S+, )?configuration/; push @ignore_list, qr/^terminating on signal 15$/; push @ignore_list, qr/^verify error:num=/; push @ignore_list, qr/^verify return:/; push @ignore_list, qr/^nss_ldap: /; push @ignore_list, qr/^discarding EHLO keywords: /; push @ignore_list, qr/^sql auxprop plugin/; push @ignore_list, qr/^sql plugin/; push @ignore_list, qr/^sql_select/; push @ignore_list, qr/^auxpropfunc error/; push @ignore_list, qr/^commit transaction/; push @ignore_list, qr/^begin transaction/; push @ignore_list, qr/^maps_find: /; push @ignore_list, qr/^check_access: /; push @ignore_list, qr/^check_domain_access: /; push @ignore_list, qr/^check_mail_access: /; push @ignore_list, qr/^check_table_result: /; push @ignore_list, qr/^mail_addr_find: /; push @ignore_list, qr/^mail_addr_map: /; push @ignore_list, qr/^mail_flow_put: /; push @ignore_list, qr/^smtp_addr_one: /; push @ignore_list, qr/^smtp_connect_addr: /; push @ignore_list, qr/^smtp_connect_unix: trying: /; push @ignore_list, qr/^smtp_find_self: /; push @ignore_list, qr/^smtp_get: /; push @ignore_list, qr/^smtp_fputs: /; push @ignore_list, qr/^smtp_parse_destination: /; push @ignore_list, qr/^smtp_sasl_passwd_lookup: /; push @ignore_list, qr/^smtpd_check_/; push @ignore_list, qr/^smtpd_chat_notify: /; push @ignore_list, qr/^been_here: /; push @ignore_list, qr/^set_eugid: /; push @ignore_list, qr/^deliver_/; push @ignore_list, qr/^flush_send_file: queue_id/; push @ignore_list, qr/^milter_macro_lookup/; push @ignore_list, qr/^milter8/; push @ignore_list, qr/^skipping non-protocol event/; push @ignore_list, qr/^reply: /; push @ignore_list, qr/^event: /; push @ignore_list, qr/^trying... /; push @ignore_list, qr/ all milters$/; push @ignore_list, qr/^vstream_/; push @ignore_list, qr/^server features/; push @ignore_list, qr/^skipping event/; push @ignore_list, qr/^Using /; push @ignore_list, qr/^rec_(?:put|get): /; push @ignore_list, qr/^subject=/; push @ignore_list, qr/^issuer=/; push @ignore_list, qr/^pref /; # yes, multiple spaces push @ignore_list, qr/^request: \d/; push @ignore_list, qr/^done incoming queue scan$/; push @ignore_list, qr/^qmgr_/; push @ignore_list, qr/^trigger_server_accept_fifo: /; push @ignore_list, qr/^proxymap stream/; push @ignore_list, qr/^(?:start|end) sorted recipient list$/; push @ignore_list, qr/^connecting to \S+ port /; push @ignore_list, qr/^Write \d+ chars/; push @ignore_list, qr/^Read \d+ chars/; push @ignore_list, qr/^(?:lookup|delete) smtp session/; push @ignore_list, qr/^delete smtp session/; push @ignore_list, qr/^(?:reloaded|remove|looking for) session .* cache$/; push @ignore_list, qr/^(?:begin|end) \S+ address list$/; push @ignore_list, qr/^mapping DSN status/; push @ignore_list, qr/^record [A-Z]/; push @ignore_list, qr/^dir_/; push @ignore_list, qr/^transport_event/; push @ignore_list, qr/^read [A-Z](?: |$)/; push @ignore_list, qr/^relay: /; push @ignore_list, qr/^why: /; push @ignore_list, qr/^fp: /; push @ignore_list, qr/^path: /; push @ignore_list, qr/^level: /; push @ignore_list, qr/^recipient: /; push @ignore_list, qr/^delivered: /; push @ignore_list, qr/^queue_id: /; push @ignore_list, qr/^queue_name: /; push @ignore_list, qr/^user: /; push @ignore_list, qr/^sender: /; push @ignore_list, qr/^offset: /; push @ignore_list, qr/^offset: /; push @ignore_list, qr/^verify stream disconnect/; push @ignore_list, qr/^event_request_timer: /; push @ignore_list, qr/^smtp_sasl_authenticate: /; push @ignore_list, qr/^flush_add: /; push @ignore_list, qr/^disposing SASL state information/; push @ignore_list, qr/^starting new SASL client/; push @ignore_list, qr/^error: dict_ldap_connect: /; push @ignore_list, qr/^error: to submit mail, use the Postfix sendmail command/; push @ignore_list, qr/^local_deliver[:[]/; push @ignore_list, qr/^_sasl_plugin_load /; push @ignore_list, qr/^exp_type: /; push @ignore_list, qr/^wakeup [\dA-Z]/; push @ignore_list, qr/^defer (?:site|transport) /; push @ignore_list, qr/^local: /; push @ignore_list, qr/^exp_from: /; push @ignore_list, qr/^extension: /; push @ignore_list, qr/^owner: /; push @ignore_list, qr/^unmatched: /; push @ignore_list, qr/^domain: /; push @ignore_list, qr/^initializing the client-side TLS engine/; push @ignore_list, qr/^header_token: /; push @ignore_list, qr/^(?:PUSH|POP) boundary/; push @ignore_list, qr/^recipient limit \d+$/; push @ignore_list, qr/^scan_dir_next: found/; push @ignore_list, qr/^open (?:btree|incoming)/; push @ignore_list, qr/^Renamed to match inode number/; push @ignore_list, qr/^cleanup_[^:]+:/; push @ignore_list, qr/^(?:before|after) input_transp_cleanup: /; push @ignore_list, qr/^event_enable_read: /; push @ignore_list, qr/^report recipient to all milters /; push @ignore_list, qr/_action = defer_if_permit$/; push @ignore_list, qr/^reject_invalid_hostname: /; push @ignore_list, qr/^cfg_get_/; push @ignore_list, qr/^sacl_check: /; # non-anchored #push @ignore_list, qr/: Greylisted for /; push @ignore_list, qr/certificate verification (?:depth|failed for)/; push @ignore_list, qr/re-using session with untrusted certificate, look for details earlier in the log$/; push @ignore_list, qr/socket: wanted attribute: /; push @ignore_list, qr/ smtpd cache$/; push @ignore_list, qr/ old session$/; push @ignore_list, qr/fingerprint=/; push @ignore_list, qr/TLS cipher list "/; } # Evaluates a given line against the list of ignore patterns. # sub in_ignore_list($) { my $line = shift; foreach (@ignore_list) { #return 1 if $line =~ /$_/; if ($line =~ /$_/) { #$IGNORED{$_}++; return 1; } } return 0; } # Accepts common fields from a standard delivery attempt, processing then # and returning modified values # sub process_delivery_attempt ($ $ $ $) { my ($to,$origto,$DDD,$reason) = @_; $reason =~ s/\((.*)\)/$1/; # Makes capturing nested parens easier # leave $to/$origto undefined, or strip < > chars if not null address (<>). defined $to and $to = ($to eq '') ? '<>' : lc $to; defined $origto and $origto = ($origto eq '') ? '<>' : lc $origto; my ($localpart, $domainpart) = split ('@', $to); ($localpart, $domainpart) = ($to, '*unspecified') if ($domainpart eq ''); my ($dsn); # If recipient_delimiter is set, break localpart into user + extension # and save localpart in origto if origto is empty # if ($Opts{'recipient_delimiter'} and $localpart =~ /\Q$Opts{'recipient_delimiter'}\E/o) { # special cases: never split mailer-daemon or double-bounce # or owner- or -request if delim is "-" (dash). unless ($localpart =~ /^(?:mailer-daemon|double-bounce)$/i or ($Opts{'recipient_delimiter'} eq '-' and $localpart =~ /^owner-.|.-request$/i)) { my ($user,$extension) = split (/\Q$Opts{'recipient_delimiter'}\E/, $localpart, 2); $origto = $localpart if ($origto eq ''); $localpart = $user; } } unless (($dsn) = ($DDD =~ /dsn=(\d\.\d+\.\d+)/o)) { $dsn = ''; } if ($Collecting{'delays'} and $DDD =~ m{delay=([\d.]+)(?:, delays=([\d.]+)/([\d.]+)/([\d.]+)/([\d.]+))?}) { # Message delivery time stamps # delays=a/b/c/d, where # a = time before queue manager, including message transmission # b = time in queue manager # c = connection setup including DNS, HELO and TLS; # d = message transmission time. if (defined $2) { $Delays{'1: Before qmgr'}{$2}++; $Delays{'2: In qmgr'}{$3}++; $Delays{'3: Conn setup'}{$4}++; $Delays{'4: Transmission'}{$5}++; } $Delays{'5: Total'}{$1}++; } return ($to,$origto,$localpart,$domainpart,$dsn,$reason); } # Processes postfix/bounce messages # sub postfix_bounce($) { my $line = shift; my $type; $line =~ s/^(?:$re_QID): //o; if ($line =~ /^(sender|postmaster) non-delivery notification/o) { #TDbQ postmaster non-delivery notification: 7446BCD68 #TDbQ sender non-delivery notification: 7446BCD68 $type = 'Non-delivery'; } elsif ($line =~ /^(sender|postmaster) delivery status notification/o ) { #TDbQ sender delivery status notification: 7446BCD68 $type = 'Delivery'; } elsif ($line =~ /^(sender|postmaster) delay notification: /o) { #TDbQ sender delay notification: AA61EC2F9A $type = 'Delayed'; } else { inc_unmatched('bounce') if ! in_ignore_list($line); return; } $Totals{'notificationsent'}++; return unless ($Collecting{'notificationsent'}); $Counts{'notificationsent'}{$type}{$1}++; } # Processes postfix/cleanup messages # cleanup always has a QID # sub postfix_cleanup($) { my $line = shift; my ($qid,$reply,$fmthost,$reject_name); ($qid, $line) = ($1, $2) if ($line =~ /^($re_QID): (.*)$/o ); #TDcQ message-id= return if ($line =~ /^message-id=/); # milter-reject, milter-hold, milter-discard if ($line =~ s/^milter-//) { milter_common($line); return; } ### cleanup bounced messages (always_bcc, recipient_bcc_maps, sender_bcc_maps) # Note: Bounce # See same code elsewhere "Note: Bounce" #TDcQ to=, relay=none, delay=0.11, delays=0.11/0/0/0, dsn=5.7.1, status=bounced optional text... #TDcQ to=, orig_to=, relay=none, delay=0.13, delays=0.13/0/0/0, dsn=5.7.1, status=bounced optional text... if ($line =~ /^to=<(.*?)>,(?: orig_to=<(.*?)>,)? relay=([^,]*).*, ($re_DDD), status=([^ ]+) (.*)$/o) { # ($to,$origto,$relay,$DDD,$status,$reason) = ($1,$2,$3,$4,$5,$6); ### deliverable messages reported by postfix/cleanup #TDcQ to=, relay=none, delay=0, delays=0.1/0/0/0, dsn=2.0.0, status=deliverable optional text... # if ($5 eq 'deliverable') { my ($to,$origto,$relay,$DDD,$reason) = ($1,$2,$3,$4,$6); my ($localpart,$domainpart,$dsn); ($to,$origto,$localpart,$domainpart,$dsn,$reason) = process_delivery_attempt ($to,$origto,$DDD,$reason); $Counts{'deliverable'}{$dsn}{$reason}{$origto ? "$to ($origto)" : $to}++; return; } if ($5 ne 'bounced' and $5 ne 'SOFTBOUNCE') { inc_unmatched('cleanupbounce'); return; } my ($to,$origto,$relay,$DDD,$reason) = ($1,$2,$3,$4,$6); my ($localpart,$domainpart,$dsn); ($to,$origto,$localpart,$domainpart,$dsn,$reason) = process_delivery_attempt ($to,$origto,$DDD,$reason); ### local bounce # XXX local v. remote bounce seems iffy, relative if ($relay =~ /^(?:none|local|virtual|maildrop|127\.0\.0\.1|avcheck)/) { $Totals{'bouncelocal'}++; return unless ($Collecting{'bouncelocal'}); $Counts{'bouncelocal'}{get_dsn_msg($dsn)}{$domainpart}{ucfirst($reason)}{$localpart}++; } ### remote bounce else { ($reply,$fmthost) = cleanhostreply($reason,$relay,$to ne '' ? $to : '<>',$domainpart); $Totals{'bounceremote'}++; return unless ($Collecting{'bounceremote'}); $Counts{'bounceremote'}{get_dsn_msg($dsn)}{$domainpart}{$localpart}{$fmthost}{$reply}++; } } # *header_checks and body_checks elsif (header_body_checks($line)) { #print "cleanup: header_body_checks\n"; return; } #TDcQ resent-message-id=4739073.1 #TDcQ resent-message-id= #TDcQ resent-message-id=? <120B11@samplepc> elsif ( ($line =~ /^resent-message-id=?$/o )) { $Totals{'resent'}++; } #TDcN unable to dlopen .../sasl2/libplain.so.2: .../sasl2/libplain.so.2: failed to map segment from shared object: Operation not permitted elsif ($line =~ /^unable to dlopen /) { # strip extraneous doubling of library path $line = "$1$2 $3" if ($line =~ /(unable to dlopen )([^:]+: )\2(.+)$/); postfix_warning($line); } else { inc_unmatched('cleanup(last)') if ! in_ignore_list($line); } } =pod header_body_checks Handle cleanup's header_checks and body_checks, and smtp's smtp_body_checks/smtp_*header_checks Possible actions that log are: REJECT optional text... DISCARD optional text... FILTER transport:destination HOLD optional text... REDIRECT user@domain PREPEND text... REPLACE text... WARN optional text... DUNNO and IGNORE are not logged Returns: 1: if line matched or handled 0: otherwise =cut sub header_body_checks($) { my $line = shift; # bcc, discard, filter, hold, prepend, redirect, reject, replace, warning return 0 if ($line !~ /^[bdfhprw]/) or # short circuit alternation when no match possible ($line !~ /^(re(?:ject|direct|place)|filter|hold|discard|prepend|warning|bcc): (header|body|content) (.*)$/); my ($action,$part,$p3) = ($1,$2,$3); #print "header_body_checks: action: \"$action\", part: \"$part\", p3: \"$p3\"\n"; my ($trigger,$host,$eto,$p4,$fmthost,$reject_name); # $re_QID: reject: body ... # $re_QID: reject: header ... # $re_QID: reject: content ... if ($p3 =~ /^(.*) from ([^;]+); from=<.*?>(?: to=<(.*?)>)?(?: proto=\S*)?(?: helo=<.*?>)?(?:: (.*)|$)/) { ($trigger,$host,$eto,$p4) = ($1,$2,$3,$4); # $action $part $trigger $host $eto $p4 #TDcQ reject: body Subject: Cheap cialis from local; from=: optional text... #TDcQ reject: body Quality replica watches!!! from hb.example.com[10.0.0.1]; from= to= proto=SMTP helo=: optional text... #TDcQ reject: header To: from hb.example.com[10.0.0.1]; from= to= proto=ESMTP helo=: optional text... # message_reject_characters (postfix >= 2.3) #TDcQ reject: content Received: by example.com Postfix from example.com[10.0.0.1]; from= to= proto=ESMTP helo=.example.com>: 5.7.1 disallowed character #TDcQ filter: header To: to@example.com from hb.example.com[10.0.0.1]; from= to= proto=ESMTP helo=: transport:destination #TDcQ hold: header Message-ID: from localhost[127.0.0.1]; from= to= proto=ESMTP helo=: optional text... #TDcQ hold: header Subject: Hold Test from local; from= to=: optional text... #TDcQ hold: header Received: by example.com...from x from local; from= #TDcQ hold: header Received: from x.com (x.com[10.0.0.1])??by example.com (Postfix) with ESMTP id 630BF??for ; Thu, 20 Oct 2006 13:27: from example.com[10.0.0.1]; from= to= proto=ESMTP helo= # hold: header Received: from [10.0.0.1] by example.com Thu, 9 Jan 2008 18:06:06 -0500 from sample.net[10.0.0.2]; from=<> to= proto=SMTP helo=: faked header #TDcQ redirect: header From: "Attn Men" from hb.example.com[10.0.0.1]; from= to= proto=ESMTP helo=: user@domain #TDcQ redirect: header From: "Superman" from hb.example.com[10.0.0.2]; from= to= proto=ESMTP helo=: user@domain #TDcQ redirect: body Original drugs from hb.example.com[10.0.0.1]; from= to= proto=SMTP helo=: user@domain #TDcQ discard: header Subject: **SPAM** Blah... from hb.example.com[10.0.0.1]; from= to= proto=ESMTP helo= #TDcQ prepend: header Rubble: Mr. from localhost[127.0.0.1]; from= to= proto=ESMTP helo=: text... #TDcQ replace: header Rubble: flintstone from localhost[127.0.0.1]; from= to= proto=ESMTP helo=: text... #TDcQ warning: header Date: Tues, 99:34:67 from localhost[127.0.0.1]; from= to= proto=ESMTP helo=: optional text... # BCC action (2.6 experimental branch) #TDcQ bcc: header To: to@example.com from hb.example.com[10.0.0.1]; from= to= proto=ESMTP helo=: user@domain # Note: reject_warning does not seem to occur } else { # smtp_body_checks, smtp_header_checks, smtp_mime_header_checks, smtp_nested_header_checks (postfix >= 2.5) #TDsQ replace: header Sender: : Sender: $trigger = $p3; $host = ''; $eto = ''; $p4 = $part eq 'body' ? 'smtp_body_checks' : 'smtp_*header_checks'; #inc_unmatched('header_body_checks'); #return 1; } #print " trigger: \"$trigger\", host: \"$host\", eto: \"$eto\", p4: \"$p4\"\n"; $trigger =~ s/\s+/ /g; $trigger = '*unknown reason' if ($trigger eq ''); $eto = '*unknown' if ($eto eq ''); my ($trig,$trig_opt,$text); if ($part eq 'header') { ($trig = $trigger) =~ s/^([^:]+:).*$/Header check "$1"/; } elsif ($part eq 'body') { $trig = "Body check"; } else { $trig = "Content check"; } # message_reject_characters (postfix >= 2.3) if ($p4 eq '') { $text = '*generic'; $trig_opt = $trig; } else { $text = $p4; $trig_opt = "$trig ($p4)"; } if ($host eq 'local') { $fmthost = formathost('127.0.0.1', 'local'); } elsif ($host =~ /([^[]+)\[([^]]+)\]/) { $fmthost = formathost($2,$1); } else { $fmthost = '*unknown'; } # Note: Counts # Ensure each $Counts{key} accumulator is consistently # used with the same number of hash key levels throughout the code. # For example, $Counts{'hold'} below has 4 keys; ensure that every # other usage of $Counts{'hold'} also has 4 keys. Currently, it is # OK to set the last key as '', but only the last. if ($action eq 'reject') { $Counts{'byiprejects'}{$fmthost}++ if $Collecting{'byiprejects'}; # Note: no temporary or reject_warning # Note: no reply code - force into a 5xx reject # XXX this won't be seen if the user has no 5.. entry in reject_reply_patterns $Totals{$reject_name = "5xxreject$part" }++; $Counts{$reject_name}{$text}{$eto}{$fmthost}{$trigger}++ if $Collecting{$reject_name}; } elsif ( $action eq 'filter' ) { $Totals{'filtered'}++; $Counts{'filtered'}{$text}{$trig}{$trigger}{$eto}{$fmthost}++ if $Collecting{'filtered'}; } elsif ( $action eq 'hold' ) { $Totals{'hold'}++; $Counts{'hold'}{$trig_opt}{$fmthost}{$eto}{$trigger}++ if $Collecting{'hold'}; } elsif ( $action eq 'redirect' ) { $Totals{'redirected'}++; $Counts{'redirected'}{$trig}{$text}{$eto}{$fmthost}{$trigger}++ if $Collecting{'redirected'}; } elsif ( $action eq 'discard' ) { $Totals{'discarded'}++; $Counts{'discarded'}{$trig}{$fmthost}{$eto}{$trigger}++ if $Collecting{'discarded'}; } elsif ( $action eq 'prepend' ) { $Totals{'prepended'}++; $Counts{'prepended'}{"$trig ($text)"}{$fmthost}{$eto}{$trigger}++ if $Collecting{'prepended'}; } elsif ( $action eq 'replace' ) { $Totals{'replaced'}++; $Counts{'replaced'}{"$trig ($text)"}{$fmthost}{$eto}{$trigger}++ if $Collecting{'replaced'}; } elsif ( $action eq 'warning' ) { $Totals{'warned'}++; $Counts{'warned'}{$trig}{$fmthost}{$eto}{$trigger}++ if $Collecting{'warned'}; } elsif ( $action eq 'bcc' ) { $Totals{'bcced'}++; $Counts{'bcced'}{$text}{$trig}{$trigger}{$eto}{$fmthost}++ if $Collecting{'bcced'}; } else { inc_unmatched('header_body_checks unexpected action'); } return 1; } # Handle common milter actions: # milter-reject, milter-hold, milter-discard # which are created by both smtpd and cleanup # sub milter_common($) { my $line = shift; #TDsdN milter-reject: MAIL from milterS.example.com[10.0.0.1]: 553 5.1.7 address incomplete; proto=ESMTP helo= #TDsdN milter-reject: CONNECT from milterS.example.com[10.0.0.2]: 451 4.7.1 Service unavailable - try again later; proto=SMTP #TDsdQ milter-reject: END-OF-MESSAGE from milterS.example.com[10.0.0.3]: 5.7.1 black listed URL host sample.com by ...uribl.com; from= to= proto=ESMTP helo= #TDsdQ milter-hold: END-OF-MESSAGE from milterS.example.com[10.0.0.4]: milter triggers HOLD action; from= to= proto=ESMTP helo= #TDcQ milter-reject: END-OF-MESSAGE from milterC.example.com[10.0.0.1]: 5.7.1 Some problem; from= to= proto=SMTP helo= #TDcQ milter-reject: CONNECT from milterC.example.com[10.0.0.2]: 5.7.1 Some problem; proto=SMTP #TDcQ milter-hold: END-OF-MESSAGE from milterC.example.com[10.0.0.3]: milter triggers HOLD action; from= to= proto=ESMTP helo= #TDcQ milter-discard: END-OF-MESSAGE from milterC.example.com[10.0.0.4]: milter triggers DISCARD action; from= to= proto=ESMTP helo= # 84B82AC8B3: milter-reject: END-OF-MESSAGE from localhost[127.0.0.1]: 5.7.1 Blocked my ($efrom,$eto,$proto,$helo) = strip_ftph($line); #print "efrom: '$efrom', eto: '$eto', proto: '$proto', helo: '$helo'\n"; $line =~ s/;$//; if ($line =~ /^(reject|hold|discard): (\S+) from ([^[]+)\[([^]]+)\](?::\d+)?: (.*)$/) { my ($action,$stage,$host,$hostip,$reply) = ($1,$2,$3,$4,$5); #print "action: '$action', stage: '$stage', host: '$host', hostip: '$hostip', reply: '$reply'\n"; if ($action eq 'reject') { my ($dsn,$fmthost,$reject_name); ($dsn,$reply) = ($1,$2) if $reply =~ /^($re_DSN) (.*)$/o; #print " dsn: '$dsn', reply: '$reply'\n"; if ($Collecting{'byiprejects'} and substr($dsn,0,1) eq '5') { $fmthost = formathost($hostip,$host); $Counts{'byiprejects'}{$fmthost}++; } # Note: reject_warning does not seem to occur # Note: See rejectmilter elsewhere $Totals{$reject_name = get_reject_key($dsn) . 'rejectmilter' }++; return unless ($Collecting{$reject_name}); $Counts{$reject_name}{$stage}{$fmthost ? $fmthost : formathost($hostip,$host)}{$reply}++; } # milter-hold elsif ($action eq 'hold') { $Totals{'hold'}++; return unless ($Collecting{'hold'}); $Counts{'hold'}{'milter'}{$stage}{formathost($hostip,$host)}{$eto}++; } # milter-discard else { # $action eq 'discard' $Totals{'discarded'}++; return unless ($Collecting{'discarded'}); $Counts{'discarded'}{'milter'}{$stage}{formathost($hostip,$host)}{$eto}++; } } else { inc_unmatched('milter_common)'); } } sub postfix_dnsblog { my $line = shift; #postfix/dnsblog[16943]: addr 192.168.0.1 listed by domain bl.spamcop.net as 127.0.0.2 #postfix/dnsblog[78598]: addr 192.168.0.1 blocked by domain zen.spamhaus.org as 127.0.0.11 if ($line =~ /^addr (\S+) (?:listed|blocked) by domain (\S+) as (\S+)$/) { $Counts{'dnsblog'}{$2}{$1}{$3}++ if $Collecting{'dnsblog'}; } else { inc_unmatched('dnsblog') if ! in_ignore_list($line); return; } } sub postfix_postscreen { my $line = shift; return if ( $line =~ /^cache / or $line =~ /discarding EHLO keywords: / or $line =~ /: discard_mask / or $line =~ /: sq=\d+ cq=\d+ event/ or $line =~ /: replacing command "/ ); if (($line =~ /^(PREGREET) \d+ (?:after \S+)? from \[([^]]+)\](?::\d+)?/) or # PREGREET 20 after 0.31 from [192.168.0.1]:12345: HELO 10.0.0.1?? # HANGUP after 0.7 from [192.168.0.4]:12345 ($line =~ /^(HANGUP) (?:after \S+)? from \[([^]]+)\](?::\d+)?/)) { $Counts{'postscreen'}{lc $1}{$2}{$END_KEY}++ if $Collecting{'postscreen'}; } elsif ($line =~ /^(WHITELISTED|BLACKLISTED|PASS \S+) \[([^]]+)\](?::\d+)?$/) { # PASS NEW [192.168.0.2]:12345 # PASS OLD [192.168.0.3]:12345 $Counts{'postscreen'}{lc $1}{$2}{$END_KEY}++ if $Collecting{'postscreen'}; } elsif ($line =~ /^DNSBL rank (\S+) for \[([^]]+)\](?::\d+)?$/) { $Counts{'postscreen'}{'dnsbl'}{$2}{$1}++ if $Collecting{'postscreen'}; $Counts{'dnsblranks'}{$1}{$2}++ if $Collecting{'postscreen'}; } elsif ($line =~ /^(CONNECT|COMMAND (?:(?:TIME|COUNT|LENGTH) LIMIT|PIPELINING)|NON-SMTP COMMAND|BARE NEWLINE) from \[([^\]]+)\]:\d+/) { # CONNECT from [192.168.1.1]:12345 $Counts{'postscreen'}{lc($1)}{$2}{$END_KEY}++ if $Collecting{'postscreen'}; } elsif ($line =~ /^DISCONNECT \[([^\]]+)\]:\d+$/) { # DISCONNECT [192.168.1.1]:12345 $Counts{'postscreen'}{'disconnect'}{$1}{$END_KEY}++ if $Collecting{'postscreen'}; } elsif ($line =~ /^NOQUEUE: reject: RCPT from \[([^]]+)\](?::\d+)?: ($re_DSN) ([^;]+)/o) { #NOQUEUE: reject: RCPT from [192.168.0.1]:12345: 550 5.7.1 Service unavailable; client [192.168.0.1] blocked using b.barracudacentral.org; from=, to=, proto=SMTP, helo= my ($ip,$dsn,$msg) = ($1,$2,$3); if ($dsn =~ /^([54])/) { $Counts{'postscreen'}{$1 . 'xx reject'}{"$dsn $msg"}{$ip}++ if $Collecting{'postscreen'}; } else { $Counts{'postscreen'}{'reject'}{"$dsn $msg"}{$ip}{$END_KEY}++ if $Collecting{'postscreen'}; } } elsif ($line =~ /^NOQUEUE: reject: CONNECT from \[([^]]+)\](?::\d+)?: too many connections/) { # NOQUEUE: reject: CONNECT from [192.168.0.1]:7197: too many connections $Counts{'postscreen'}{'reject'}{'Too many connections'}{$1}{$END_KEY}++ if $Collecting{'postscreen'}; } elsif ($line =~ /^reject: connect from \[([^]]+)\](?::\d+)?: (.+)$/) { # reject: connect from [192.168.0.1]:21225: all screening ports busy $Counts{'postscreen'}{'reject'}{"\u$2"}{$1}{$END_KEY}++ if $Collecting{'postscreen'}; } elsif ($line =~ /^(?:WHITELIST VETO) \[([^]]+)\](?::\d+)?$/) { # WHITELIST VETO [192.168.0.8]:43579 $Counts{'postscreen'}{'whitelist veto'}{$1}{$END_KEY}++ if $Collecting{'postscreen'}; } elsif ($line =~ /^(entering|leaving) STRESS mode with (\d+) connections$/) { # entering STRESS mode with 90 connections $Counts{'postscreen'}{'stress mode: ' . $1}{$2}{$END_KEY}++ if $Collecting{'postscreen'}; } elsif ($line =~ /^close database (\S+): No such file or directory/) { # close database /var/lib/postfix/postscreen_cache.db: No such file or directory (possible Berkeley DB bug) $Counts{'postscreen'}{'close database'}{$1}{$END_KEY}++ if $Collecting{'postscreen'}; } else { inc_unmatched('postscreen') if ! in_ignore_list($line); return; } $Totals{'postscreen'}++; } # Handles postfix/postsuper lines # sub postfix_postsuper($) { my $line = shift; return if $line =~ /^Deleted: \d+ messages?$/; if ($line =~ /^Placed on hold: (\d+) messages?$/o) { #TDps Placed on hold: 2 messages # Note: See Hold elsewhere $Totals{'hold'} += $1; return unless ($Collecting{'hold'}); $Counts{'hold'}{'Postsuper'}{'localhost'}{"bulk hold: $1"}{''} += $1; } elsif ($line =~ /^Released from hold: (\d+) messages?$/o) { #TDps Released from hold: 1 message $Totals{'releasedfromhold'} += $1; } elsif ($line =~ /^Requeued: (\d+) messages?$/o) { #TDps Requeued: 1 message $Totals{'requeued'} += $1; } elsif (my($qid,$p2) = ($line =~ /($re_QID): (.*)$/)) { # postsuper double reports the following 3 lines return if ($p2 eq 'released from hold'); return if ($p2 eq 'placed on hold'); return if ($p2 eq 'requeued'); if ($p2 =~ /^removed\s*$/o) { # Note: See REMOVED elsewhere # 52CBDC2E0F: removed delete $SizeByQid{$qid} if (exists $SizeByQid{$qid}); $Totals{'removedfromqueue'}++; } elsif (! in_ignore_list ($p2)) { inc_unmatched('postsuper2'); } } elsif (! in_ignore_list ($line)) { inc_unmatched('postsuper1'); } } # Handles postfix panic: lines # sub postfix_panic($) { #TD panic: myfree: corrupt or unallocated memory block $Totals{'panicerror'}++; return unless ($Collecting{'panicerror'}); $Counts{'panicerror'}{ucfirst($1)}++; } # Handles postfix fatal: lines # sub postfix_fatal($) { my ($reason) = shift; if ($reason =~ /^\S*\(\d+\): Message file too big$/o) { #TD fatal: root(0): Message file too big $Totals{'fatalfiletoobig'}++; # XXX its not clear this is at all useful - consider falling through to last case } elsif ( $reason =~ /^config variable (\S*): (.*)$/o ) { #TD fatal: config variable inet_interfaces: host not found: 10.0.0.1:2525 #TD fatal: config variable inet_interfaces: host not found: all:2525 $Totals{'fatalconfigerror'}++; return unless ($Collecting{'fatalconfigerror'}); $Counts{'fatalconfigerror'}{ucfirst($reason)}++; } else { #TD fatal: watchdog timeout #TD fatal: bad boolean configuration: smtpd_use_tls = #TDvN fatal: update queue file active/4B709F060E: File too large $reason =~ s/(^update queue file \w+\/)\w+:/$1*:/; $Totals{'fatalerror'}++; return unless ($Collecting{'fatalerror'}); $Counts{'fatalerror'}{ucfirst($reason)}++; } } # Handles postfix fatal: lines # sub postfix_error($) { my ($reason) = shift; # postfix/postfix-script[4271]: error: unknown command: 'rel' $Totals{'error'}++; return unless ($Collecting{'fatalerror'}); $Counts{'error'}{ucfirst($reason)}++; } # Handles postfix warning: lines # and additional lines coerced into warnings # sub postfix_warning($) { my ($warning) = shift; # Skip these return if ($warning =~ /$re_QID: skipping further client input$/o); return if ($warning =~ /^Mail system is down -- accessing queue directly$/o); return if ($warning =~ /^SASL authentication failure: (?:Password verification failed|no secret in database)$/o); return if ($warning =~ /^no MX host for .* has a valid A record$/o); return if ($warning =~ /^uid=\d+: Broken pipe$/o); #TD warning: connect to 127.0.0.1:12525: Connection refused #TD warning: problem talking to server 127.0.0.1:12525: Connection refused #TD warning: valid_ipv4_hostaddr: invalid octet count: my ($domain,$to,$type,$site,$helo,$cmd); my ($addr,$size,$hostip,$host,$port,$reason,$qid,$queue,$reason2,$process,$status,$service); if (($hostip,$host,$reason) = ($warning =~ /^(?:smtpd_peer_init: )?([^:]+): hostname ([^ ]+) verification failed: (.*)$/) or ($hostip,$reason,$host) = ($warning =~ /^(?:smtpd_peer_init: )?([^:]+): (address not listed for hostname) (.*)$/) or ($host,$reason,$hostip,$reason2) = ($warning =~ /^(?:smtpd_peer_init: )?hostname (\S+) (does not resolve to address) ([\d.]+)(: host not found, try again)?$/)) { #TD warning: 10.0.0.1: hostname sample.com verification failed: Host not found #TD warning: smtpd_peer_init: 192.168.0.1: hostname example.com verification failed: Name or service not known #TD warning: 192.168.0.1: address not listed for hostname sample.net # post 2.8 #TD warning: hostname 281.example.net does not resolve to address 192.168.0.1: host not found, try again #TD warning: hostname 281.example.net does not resolve to address 192.168.0.1 $reason .= $reason2 if $reason2; $Totals{'hostnameverification'}++; return unless ($Collecting{'hostnameverification'}); $Counts{'hostnameverification'}{ucfirst($reason)}{formathost($hostip,$host)}++; } elsif (($warning =~ /^$re_QID: queue file size limit exceeded$/o) or ($warning =~ /^uid=\d+: File too large$/o)) { $Totals{'warnfiletoobig'}++; } elsif ($warning =~ /^database (?:[^ ]*) is older than source file ([\w\/]+)$/o) { #TD warning: database /etc/postfix/client_checks.db is older than source file /etc/postfix/client_checks $Totals{'databasegeneration'}++; return unless ($Collecting{'databasegeneration'}); $Counts{'databasegeneration'}{$1}++; } elsif (($reason,$qid,$reason2) = ($warning =~ /^(open active) ($re_QID): (.*)$/o) or ($reason,$qid,$reason2) = ($warning =~ /^qmgr_active_corrupt: (save corrupt file queue active) id ($re_QID): (.*)$/o) or ($qid,$reason,$reason2) = ($warning =~ /^($re_QID): (write queue file): (.*)$/o)) { #TD warning: open active BDB9B1309F7: No such file or directory #TD warning: qmgr_active_corrupt: save corrupt file queue active id 4F4272F342: No such file or directory #TD warning: E669DE52: write queue file: No such file or directory $Totals{'queuewriteerror'}++; return unless ($Collecting{'queuewriteerror'}); $Counts{'queuewriteerror'}{"$reason: $reason2"}{$qid}++; } elsif (($qid,$reason) = ($warning =~ /^qmgr_active_done_3_generic: remove ($re_QID) from active: (.*)$/o)) { #TD warning: qmgr_active_done_3_generic: remove AF0F223FC05 from active: No such file or directory $Totals{'queuewriteerror'}++; return unless ($Collecting{'queuewriteerror'}); $Counts{'queuewriteerror'}{"remove from active: $reason"}{$qid}++; } elsif (($queue,$qid) = ($warning =~ /^([^\/]*)\/($re_QID): Error writing message file$/o )) { #TD warning: maildrop/C9E66ADF: Error writing message file $Totals{'messagewriteerror'}++; return unless ($Collecting{'messagewriteerror'}); $Counts{'messagewriteerror'}{$queue}{$qid}++; } elsif (($process,$status) = ($warning =~ /^process ([^ ]*) pid \d+ exit status (\d+)$/o)) { #TD warning: process /usr/lib/postfix/smtp pid 9724 exit status 1 $Totals{'processexit'}++; return unless ($Collecting{'processexit'}); $Counts{'processexit'}{"Exit status $status"}{$process}++; } elsif ($warning =~ /^mailer loop: (.*)$/o) { #TD warning: mailer loop: best MX host for example.com is local $Totals{'mailerloop'}++; return unless ($Collecting{'mailerloop'}); $Counts{'mailerloop'}{$1}++; } elsif ($warning =~ /^no (\S+) host for (\S+) has a valid address record$/) { #TDs warning: no MX host for example.com has a valid address record $Totals{'dnserror'}++; return unless ($Collecting{'dnserror'}); $Counts{'dnserror'}{"No $1 host has a valid address record"}{$2}{$END_KEY}++; } elsif ($warning =~ /^(Unable to look up \S+ host) (.+)$/) { #TDsd warning: Unable to look up MX host for example.com: Host not found #TDsd warning: Unable to look up MX host mail.example.com for Sender address from@example.com: hostname nor servname provided, or not known #TDsd warning: Unable to look up NS host ns1.example.local for Sender address bounce@example.local: No address associated with hostname $Totals{'dnserror'}++; return unless ($Collecting{'dnserror'}); my ($problem,$target,$reason) = ($1, split(/: /,$2)); $reason =~ s/, try again//; if ($target =~ /^for (\S+)$/) { $Counts{'dnserror'}{$problem}{ucfirst($reason)}{$1}{$END_KEY}++; } elsif ($target =~ /^(\S+)( for \S+ address) (\S+)$/) { $Counts{'dnserror'}{$problem . lc($2)}{ucfirst($reason)}{$1}{$3}++; } } elsif ($warning =~ /^((?:malformed|numeric) domain name in .+? of \S+ record) for (.*):(.*)?$/) { my ($problem,$domain,$reason) = ($1,$2,$3); #TDsd warning: malformed domain name in resource data of MX record for example.com: #TDsd warning: malformed domain name in resource data of MX record for example.com: mail.example.com\\032 #TDsd warning: numeric domain name in resource data of MX record for sample.com: 192.168.0.1 $Totals{'dnserror'}++; return unless ($Collecting{'dnserror'}); $Counts{'dnserror'}{ucfirst($problem)}{$domain}{$reason eq '' ? '*unknown' : $reason}{$END_KEY}++; } elsif ($warning =~ /^numeric hostname: ([\S]+)$/) { #TD warning: numeric hostname: 192.168.0.1 $Totals{'numerichostname'}++; return unless ($Collecting{'numerichostname'}); $Counts{'numerichostname'}{$1}++; } elsif ( ($host,$hostip,$port,$type,$reason) = ($warning =~ /^([^[]+)\[([^]]+)\](?::(\d+))? (sent \w+ header instead of SMTP command): (.*)$/) or ($type,$host,$hostip,$port,$reason) = ($warning =~ /^(non-E?SMTP command) from ([^[]+)\[([^]]+)\](?::(\d+))?: (.*)$/) or ($type,$host,$hostip,$port,$reason) = ($warning =~ /^(?:$re_QID: )?(non-E?SMTP response) from ([^[]+)\[([^]]+)\](?::(\d+))?:(?: (.*))?$/o)) { # ancient #TDsd warning: example.com[192.168.0.1] sent message header instead of SMTP command: From: "Someone" <40245426501example.com> # current #TDsd warning: non-SMTP command from sample.net[10.0.0.1]: Received: from 192.168.0.1 (HELO bogus.sample.com) #TDs warning: 6B01A8DEF: non-ESMTP response from mail.example.com[192.168.0.1]:25: $Totals{'smtpconversationerror'}++; return unless ($Collecting{'smtpconversationerror'}); $host .= ' :' . $port if ($port and $port ne '25'); $Counts{'smtpconversationerror'}{ucfirst($type)}{formathost($hostip,$host)}{$reason}++; } elsif ($warning =~ /^valid_hostname: (.*)$/o) { #TD warning: valid_hostname: empty hostname $Totals{'hostnamevalidationerror'}++; return unless ($Collecting{'hostnamevalidationerror'}); $Counts{'hostnamevalidationerror'}{$1}++; } elsif (($host,$hostip,$type,$reason) = ($warning =~ /^([^[]+)\[([^]]+)\](?::\d+)?: SASL (.*) authentication failed(.*)$/)) { #TDsd warning: unknown[10.0.0.1]: SASL LOGIN authentication failed: bad protocol / cancel #TDsd warning: example.com[192.168.0.1]: SASL DIGEST-MD5 authentication failed # see saslauthfail elsewhere $Totals{'saslauthfail'}++; return unless ($Collecting{'saslauthfail'}); if ($reason) { $reason = $type . $reason; } else { $reason = $type; } $Counts{'saslauthfail'}{$reason}{formathost($hostip,$host)}++; } elsif (($host,$reason) = ($warning =~ /^(\S+): RBL lookup error:.* Name service error for (?:name=)?\1(?: type=[^:]+)?: (.*)$/o)) { #TD warning: 192.168.0.1.sbl.spamhaus.org: RBL lookup error: Host or domain name not found. Name service error for name=192.168.0.1.sbl.spamhaus.org type=A: Host not found, try again #TD warning: 10.0.0.1.relays.osirusoft.com: RBL lookup error: Name service error for 10.0.0.1.relays.osirusoft.com: Host not found, try again $Totals{'rblerror'}++; return unless ($Collecting{'rblerror'}); $Counts{'rblerror'}{$reason}{$host}++; } elsif ( ($host,$hostip,$reason,$helo) = ($warning =~ /^host ([^[]+)\[([^]]+)\](?::\d+)? (greeted me with my own hostname) ([^ ]*)$/ ) or ($host,$hostip,$reason,$helo) = ($warning =~ /^host ([^[]+)\[([^]]+)\](?::\d+)? (replied to HELO\/EHLO with my own hostname) ([^ ]*)$/ )) { #TDs warning: host example.com[192.168.0.1] greeted me with my own hostname example.com #TDs warning: host example.com[192.168.0.1] replied to HELO/EHLO with my own hostname example.com $Totals{'heloerror'}++; return unless ($Collecting{'heloerror'}); $Counts{'heloerror'}{ucfirst($reason)}{formathost($hostip,$host)}++; } elsif (($size,$host,$hostip) = ($warning =~ /^bad size limit "([^"]+)" in EHLO reply from ([^[]+)\[([^]]+)\](?::\d+)?$/ )) { #TD warning: bad size limit "-679215104" in EHLO reply from example.com[192.168.0.1] $Totals{'heloerror'}++; return unless ($Collecting{'heloerror'}); $Counts{'heloerror'}{"Bad size limit in EHLO reply"}{formathost($hostip,$host)}{"$size"}++; } elsif ( ($host,$hostip,$cmd,$addr) = ($warning =~ /^Illegal address syntax from ([^[]+)\[([^]]+)\](?::\d+)? in ([^ ]*) command: (.*)/ )) { #TD warning: Illegal address syntax from example.com[192.168.0.1] in MAIL command: user@sample.net $addr =~ s/[<>]//g unless ($addr eq '<>'); $Totals{'illegaladdrsyntax'}++; return unless ($Collecting{'illegaladdrsyntax'}); $Counts{'illegaladdrsyntax'}{$cmd}{$addr}{formathost($hostip,$host)}++; } elsif ($warning =~ /^(timeout|premature end-of-input) on (.+) while reading (.*)$/o or $warning =~ /^(malformed (?:base64|numerical)|unexpected end-of-input) from (.+) while reading (.*)$/o) { #TDs warning: premature end-of-input on private/anvil while reading input attribute name #TDs warning: timeout on private/anvil while reading input attribute data #TDs warning: unexpected end-of-input from 127.0.0.1:10025 socket while reading input attribute name #TDs warning: malformed base64 data from %s while reading input attribute data: ... #TDs warning: malformed numerical data from %s while reading input attribute data: ... $Totals{'attrerror'}++; return unless ($Collecting{'attrerror'}); $Counts{'attrerror'}{$2}{$1}{$3}++; } elsif ($warning =~ /^(.*): (bad command startup -- throttling)/o) { #TD warning: /usr/libexec/postfix/trivial-rewrite: bad command startup -- throttling $Totals{'startuperror'}++; return unless ($Collecting{'startuperror'}); $Counts{'startuperror'}{ucfirst($2)}{$1}++; } elsif ($warning =~ /(problem talking to service [^:]*): (.*)$/o) { #TD warning: problem talking to service rewrite: Connection reset by peer #TD warning: problem talking to service rewrite: Success $Totals{'communicationerror'}++; return unless ($Collecting{'communicationerror'}); $Counts{'communicationerror'}{ucfirst($1)}{$2}++; } elsif (my ($map,$key) = ($warning =~ /^$re_QID: ([^ ]*) map lookup problem for (.*)$/o)) { #TD warning: 6F74F74431: virtual_alias_maps map lookup problem for root@example.com $Totals{'mapproblem'}++; return unless ($Collecting{'mapproblem'}); $Counts{'mapproblem'}{$map}{$key}++; } elsif (($map,$reason) = ($warning =~ /^pcre map ([^,]+), (.*)$/o)) { #TD warning: pcre map /etc/postfix/body_checks, line 92: unknown regexp option "F": skipping this rule $Totals{'mapproblem'}++; return unless ($Collecting{'mapproblem'}); $Counts{'mapproblem'}{$map}{$reason}++; } elsif (($reason) = ($warning =~ /dict_ldap_lookup: (.*)$/o)) { #TD warning: dict_ldap_lookup: Search error 80: Internal (implementation specific) error $Totals{'ldaperror'}++; return unless ($Collecting{'ldaperror'}); $Counts{'ldaperror'}{$reason}++; } elsif (($type,$size,$host,$hostip,$service) = ($warning =~ /^(.+) limit exceeded: (\d+) from ([^[]+)\[([^]]+)\](?::\d+)? for service (.*)/ )) { #TDsd warning: Connection concurrency limit exceeded: 51 from example.com[192.168.0.1] for service smtp #TDsd warning: Connection rate limit exceeded: 20 from mail.example.com[192.168.0.1] for service smtp #TDsd warning: Connection rate limit exceeded: 30 from unknown[unknown] for service smtp #TDsd warning: Recipient address rate limit exceeded: 21 from example.com[10.0.0.1] for service smtp #TDsd warning: Message delivery request rate limit exceeded: 11 from example.com[10.0.0.1] for service smtp #TDsd warning: New TLS session rate limit exceeded: 49 from example.com[10.0.0.1] for service smtp $Totals{'anvil'}++; return unless ($Collecting{'anvil'}); $Counts{'anvil'}{$service}{$type}{formathost($hostip,$host)}{$size}++; } elsif (my ($extname,$intname,$limit) = ($warning =~ /service "([^"]+)" \(([^)]+)\) has reached its process limit "([^"]+)":/o)) { #TD warning: service "smtp" (25) has reached its process limit "50": new clients may experience noticeable delays $Totals{'processlimit'}++; return unless ($Collecting{'processlimit'}); $Counts{'processlimit'}{'See http://www.postfix.org/STRESS_README.html'}{"$extname ($intname)"}{$limit}++; } else { #TDsd warning: No server certs available. TLS won't be enabled #TDs warning: smtp_connect_addr: bind : Address already in use # These two messages follow ProcessLimit message above #TDm warning: to avoid this condition, increase the process count in master.cf or reduce the service time per client #TDm warning: see http://www.postfix.org/STRESS_README.html for examples of stress-dependent configuration settings return if ($warning =~ /^to avoid this condition,/o); return if ($warning =~ /^see http:\/\/www\.postfix\.org\/STRESS_README.html/o); #TDsd warning: 009314BD9E: read timeout on cleanup socket $warning =~ s/^$re_QID: (read timeout on \S+ socket)/$1/; #TDsd warning: Read failed in network_biopair_interop with errno=0: num_read=0, want_read=11 #TDs warning: Read failed in network_biopair_interop with errno=0: num_read=0, want_read=11 $warning =~ s/^(Read failed in network_biopair_interop) with .*$/$1/; =cut $warning =~ s/^(TLS library problem: )\d+:(error:.*)$/$1$2/; $warning =~ s/^(network_biopair_interop: error reading) \d+ bytes(.*)$/$1$2/; 1 TLS library problem: 10212:error:1408A0C1:SSL routines:SSL3_GET_CLIENT_HELLO:no shared cipher... 1 TLS library problem: 10217:error:1408A0C1:SSL routines:SSL3_GET_CLIENT_HELLO:no shared cipher... 1 network_biopair_interop: error reading 1102 bytes from the network: Connection reset by peer 1 network_biopair_interop: error reading 1120 bytes from the network: Connection reset by peer =cut $Totals{'warningsother'}++; return unless ($Collecting{'warningsother'}); $Counts{'warningsother'}{$warning}++; } } # Handles postfix/postfix-script lines # sub postfix_script($) { my $line = shift; return if ($line =~ /^the Postfix mail system is running: PID: /o); if ($line =~ /^starting the Postfix mail system/o) { $Totals{'postfixstart'}++; } elsif ($line =~ /^stopping the Postfix mail system/o) { $Totals{'postfixstop'}++; } elsif ($line =~ /^refreshing the Postfix mail system/o) { $Totals{'postfixrefresh'}++; } elsif ($line =~ /^waiting for the Postfix mail system to terminate/o) { $Totals{'postfixwaiting'}++; } elsif (! in_ignore_list ($line)) { inc_unmatched('postfix_script'); } } # Handles postfix backwards compatibility mode lines # sub backwards_compatible($) { my $line = shift; if ($line =~ /^Postfix is running with backwards-compatible default settings/o) { $Totals{'backwardscompatible'}++; } elsif ($line =~ /^See http.*COMPATIBILITY_README.html for details/o) { $Totals{'backwardscompatible'}++; } elsif ($line =~ /^To disable backwards compatibility use.*/o) { $Totals{'backwardscompatible'}++; } } # Clean up a server's reply, to give some uniformity to reports # sub cleanhostreply($ $ $ $) { my ($hostreply,$relay,$recip,$domain) = @_; my $fmtdhost = ''; my ($r1, $r2, $dsn, $msg, $host, $event); #print "RELAY: $relay, RECIP: $recip, DOMAIN: $domain\n"; #print "HOSTREPLY: \"$hostreply\"\n"; return ('Accepted', '*unknown') if $hostreply =~ /^25\d/o; # Host or domain name not found. Name service error for name=example.com type=MX: Host not found... if ($hostreply =~ /^Host or domain name not found. Name service error for name=([^:]+): Host not found/o) { return ('Host not found', $1); } if (($host,$dsn,$r1) = ($hostreply =~ /host (\S+) said: ($re_DSN)[\- :]*"?(.*)"?$/o)) { # Strip recipient address from host's reply - we already have it in $recip. $r1 =~ s/[<(]?\Q$recip\E[>)]?\W*//ig; # Strip and capture "in reply to XYZ command" from host's reply if ($r1 =~ s/\s*[(]?(?:in reply to (.*) command)[)]?//o) { $r2 = ": $1"; } $r1 =~ s/^Recipient address rejected: //o; # Canonicalize numerous forms of "recipient unknown" if ( $r1 =~ /^user unknown/i or $r1 =~ /^unknown user/i or $r1 =~ /^unknown recipient address/i or $r1 =~ /^invalid recipient/i or $r1 =~ /^recipient unknown/i or $r1 =~ /^sorry, no mailbox here by that name/i or $r1 =~ /^User is unknown/ or $r1 =~ /^User not known/ or $r1 =~ /^MAILBOX NOT FOUND/ or $r1 =~ /^Recipient Rejected: No account by that name here/ or $r1 =~ /^Recipient does not exist here/ or $r1 =~ /The email account that you tried to reach does not exist./ # Google's long mess or $r1 =~ /(?:no such user|user unknown)/i ) { #print "UNKNOWN RECIP: $r1\n"; $r1 = 'Unknown recipient'; } elsif ($r1 =~ /greylisted/oi) { #print "GREYLISTED RECIP: $r1\n"; $r1 = 'Recipient greylisted'; } elsif ($r1 =~ /^Message temporarily deferred - (\d\.\d+\.\d+)\. Please refer to (.+)$/o) { # Yahoo: 421 Message temporarily deferred - 4.16.51. Please refer to http://... (in reply to end of DATA command)) $dsn = "$dsn $1"; $r1 = "see $2"; } elsif ($r1 =~ /^Resources temporarily not available - Please try again later \[#(\d\.\d+\.\d+)\]\.$/o) { #Yahoo 451 Resources temporarily not available - Please try again later [#4.16.5]. $dsn = "$dsn $1"; $r1 = "resources not available"; } elsif ($r1 =~ /^Message temporarily deferred - (\[\d+\])/o) { # Yahoo: 451 Message temporarily deferred - [160] $dsn = "$dsn $1"; $r1 = ''; } } elsif ($hostreply =~ /^connect to (\S+): (.*)$/o) { #print "CONNECT: $hostreply\n"; $host = $1; $r1 = $2; $r1 =~ s/server refused to talk to me/refused/; } elsif ($hostreply =~ /^host (\S+) refused to talk to me: (.*)$/o) { $host = $1; $msg = $2; #print "HOSTREFUSED: $hostreply\n"; #Yahoo: '421 Message from (10.0.0.1) temporarily deferred - 4.16.50. Please refer to http://... if ($msg =~ /^(\d+) Message from \([^)]+\) temporarily deferred - (\d\.\d+\.\d+)\. Please refer to (.+)$/) { $dsn = "$1 $2"; $msg = "see $3"; } #$r1 = join(': ', 'refused', $msg); $r1 = $msg; } elsif ($hostreply =~ /^(delivery temporarily suspended): connect to (\S+): (.*)$/o) { #print "DELIVERY SUSP: $hostreply\n"; $host = $2; $r1 = join(': ', $1, $3); } elsif ($hostreply =~ /^(delivery temporarily suspended: conversation) with (\S+) (.*)$/o) { # delivery temporarily suspended: conversation with example.com[10.0.0.1] timed out while receiving the initial server greeting) #print "DELIVERY SUSP2: $hostreply\n"; $host = $2; $r1 = join(' ', $1, $3); } elsif (($event,$host,$r1) = ($hostreply =~ /^(lost connection|conversation) with (\S+) (.*)$/o)) { #print "LOST conv/conn: $hostreply\n"; $r1 = join(' ',$event,$r1); } elsif ($hostreply =~ /^(.*: \S+maildrop: Unable to create a dot-lock) at .*$/o) { #print "MAILDROP: $hostreply\n"; $r1 = $1; } elsif ($hostreply =~ /^mail for (\S+) loops back to myself/o) { #print "LOOP: $hostreply\n"; $host = $1; $r1 = 'mailer loop'; } elsif ($hostreply =~ /^unable to find primary relay for (\S+)$/o) { #print "NORELAY: $hostreply\n"; $host = $1; $r1 = 'no relay found'; } elsif ($hostreply =~ /^message size \d+ exceeds size limit \d+ of server (\S+)\s*$/o) { #print "TOOBIG: $hostreply\n"; $host = $1; $r1 = 'message too big'; } else { #print "UNMATCH: $hostreply\n"; $r1 = $hostreply; } #print "R1: $r1, R2: $r2\n"; $r1 =~ s/for name=\Q$domain\E //ig; if ($host eq '') { if ($relay =~ /([^[]+)\[([^]]+)\]/) { $fmtdhost = formathost($2,$1); } else { $fmtdhost = '*unknown'; } } elsif ($host =~ /^([^[]+)\[([^]]+)\]/) { $fmtdhost = formathost($2,$1); } else { $fmtdhost = $host; } return (($dsn ? "$dsn " : '' ) . "\u$r1$r2", $fmtdhost); } # Strip and return from, to, proto, and helo information from a log line # From is set to the empty envelope sender <> as necessary, and To is # always lowercased. # # Note: modifies its input for efficiency # sub strip_ftph($) { my ($helo, $proto, $to, $from); #print "strip_ftph: '$_[0]\n"; $helo = ($_[0] =~ s/\s+helo=<(.*?)>\s*$//) == 1 ? $1 : '*unavailable'; $proto = ($_[0] =~ s/\s+proto=(\S+)\s*$//) == 1 ? $1 : '*unavailable'; $to = ($_[0] =~ s/\s+to=<(.*?)>\s*$//) == 1 ? (lc($1) || '<>') : '*unavailable'; $from = ($_[0] =~ s/\s+from=<(.*?)>\s*$//) == 1 ? ( $1 || '<>') : '*unavailable'; #print "helo: $helo, proto: $proto, to: $to, from: $from\n"; #print "strip_ftph: final: '$_[0]'\n"; return ($from,$to,$proto,$helo); } # Initialize the Getopts option list. Requires the Section table to # be built already. # sub init_getopts_table() { print "init_getopts_table: enter\n" if $Opts{'debug'} & Logreporters::D_ARGS; init_getopts_table_common(@supplemental_reports); add_option ('recipient_delimiter=s'); add_option ('delays!'); add_option ('show_delays=i', sub { $Opts{'delays'} = $_[1]; 1; }); add_option ('delays_percentiles=s'); add_option ('reject_reply_patterns=s'); add_option ('ignore_services=s'); add_option ('postgrey_delays!'); add_option ('postgrey_show_delays=i', sub { $Opts{'postgrey_delays'} = $_[1]; 1; }); add_option ('postgrey_delays_percentiles=s'); add_option ('unknown!', sub { $Opts{'unknown'} = $_[1]; 1; }); add_option ('show_unknown=i', sub { $Opts{'unknown'} = $_[1]; 1; }); add_option ('enable_long_queue_ids=i', sub { $Opts{'long_queue_ids'} = $_[1]; 1; }); add_option ('long_queue_ids!'); =pod # aliases and backwards compatibility add_option ('msgsdeferred=s', \$Opts{'deferred'}); add_option ('msgsdelivered=s', \$Opts{'delivered'}); add_option ('msgssent=s', \$Opts{'sent'}); add_option ('msgssentlmtp=s', \$Opts{'sentlmtp'}); add_option ('msgsforwarded=s', \$Opts{'forwarded'}); add_option ('msgsresent=s', \$Opts{'resent'}); add_option ('warn=s', \$Opts{'warned'}); add_option ('held=s', \$Opts{'hold'}); =cut } # Builds the entire @Section table used for data collection # # Each Section entry has as many as six fields: # # 1. Section array reference # 2. Key to %Counts, %Totals accumulator hashes, and %Collecting hash # 3. Output in Detail report? (must also a %Counts accumulator) # 4. Numeric output format specifier for Summary report # 5. Section title for Summary and Detail reports # 6. A hash to a divisor used to calculate the percentage of a total for that key # # Use begin_section_group/end_section_group to create groupings around sections. # # Sections can be freely reordered if desired, but maintain proper group nesting. # # # The reject* entries of this table are dynamic, in that they are built based # upon the value of $Opts{'reject_reply_patterns'}, which can be specified by # either command line or configuration file. This allows various flavors, of # reject sections based on SMTP reply code (eg. 421 45x, 5xx, etc.). Instead # of creating special sections for each reject variant, the primary key of each # reject section could have been the SMTP reply code. However, this would # require special-case processing to distinguish 4xx temporary rejects from 5xx # permanent rejects in various Totals{'totalrejects*'} counts, and in the # Totals{'totalrejects'} tally. # # Sections can be freely reordered if desired. sub build_sect_table() { if ($Opts{'debug'} & Logreporters::D_SECT) { print "build_sect_table: enter\n"; print "\treject patterns: $Opts{'reject_reply_patterns'}\n"; } my $S = \@Sections; # References to these are used in the Sections table below; we'll predeclare them. $Totals{'totalrejects'} = 0; $Totals{'totalrejectswarn'} = 0; $Totals{'totalacceptplusreject'} = 0; # Configuration and critical errors appear first # SECTIONREF, NAME, DETAIL, FMT, TITLE, DIVISOR begin_section_group ($S, 'warnings'); add_section ($S, 'panicerror', 1, 'd', '*Panic: General panic'); add_section ($S, 'fatalfiletoobig', 0, 'd', '*Fatal: Message file too big'); add_section ($S, 'fatalconfigerror', 1, 'd', '*Fatal: Configuration error'); add_section ($S, 'fatalerror', 1, 'd', '*Fatal: General fatal'); add_section ($S, 'error', 1, 'd', '*Error: General error'); add_section ($S, 'processlimit', 1, 'd', '*Warning: Process limit reached, clients may delay'); add_section ($S, 'warnfiletoobig', 0, 'd', '*Warning: Queue file size limit exceeded'); add_section ($S, 'warninsufficientspace', 0, 'd', '*Warning: Insufficient system storage error'); add_section ($S, 'warnconfigerror', 1, 'd', '*Warning: Server configuration error'); add_section ($S, 'queuewriteerror', 1, 'd', '*Warning: Error writing queue file'); add_section ($S, 'messagewriteerror', 1, 'd', '*Warning: Error writing message file'); add_section ($S, 'databasegeneration', 1, 'd', '*Warning: Database is older than source file'); add_section ($S, 'mailerloop', 1, 'd', '*Warning: Mailer loop'); add_section ($S, 'startuperror', 1, 'd', '*Warning: Startup error'); add_section ($S, 'mapproblem', 1, 'd', '*Warning: Map lookup problem'); add_section ($S, 'attrerror', 1, 'd', '*Warning: Error reading attribute data'); add_section ($S, 'anvil', 1, 'd', '*Warning: Anvil limit reached'); add_section ($S, 'processexit', 1, 'd', 'Process exited'); add_section ($S, 'hold', 1, 'd', 'Placed on hold'); add_section ($S, 'communicationerror', 1, 'd', 'Postfix communications error'); add_section ($S, 'saslauthfail', 1, 'd', 'SASL authentication failed'); add_section ($S, 'ldaperror', 1, 'd', 'LDAP error'); add_section ($S, 'warningsother', 1, 'd', 'Miscellaneous warnings'); add_section ($S, 'totalrejectswarn', 0, 'd', 'Reject warnings (warn_if_reject)'); end_section_group ($S, 'warnings'); begin_section_group ($S, 'bytes', "\n"); add_section ($S, 'bytesaccepted', 0, 'Z', 'Bytes accepted '); # Z means print scaled as in 1k, 1m, etc. add_section ($S, 'bytessentsmtp', 0, 'Z', 'Bytes sent via SMTP'); add_section ($S, 'bytessentlmtp', 0, 'Z', 'Bytes sent via LMTP'); add_section ($S, 'bytesdelivered', 0, 'Z', 'Bytes delivered'); add_section ($S, 'bytesforwarded', 0, 'Z', 'Bytes forwarded'); end_section_group ($S, 'bytes', $sep1); begin_section_group ($S, 'acceptreject', "\n"); begin_section_group ($S, 'acceptreject2', "\n"); add_section ($S, 'msgsaccepted', 0, 'd', 'Accepted', \$Totals{'totalacceptplusreject'}); add_section ($S, 'totalrejects', 0, 'd', 'Rejected', \$Totals{'totalacceptplusreject'}); end_section_group ($S, 'acceptreject2', $sep2); add_section ($S, 'totalacceptplusreject', 0, 'd', 'Total', \$Totals{'totalacceptplusreject'}); end_section_group ($S, 'acceptreject', $sep1); # The various Reject sections are built dynamically based upon a list of reject reply keys, # which are user-configured via $Opts{'reject_reply_patterns'} @RejectPats = (); foreach my $rejpat (split /[ ,]/, $Opts{'reject_reply_patterns'}) { if ($rejpat !~ /^(warn|[45][\d.]{2})$/io) { print STDERR usage "Invalid pattern \"$rejpat\" in reject_reply_patterns"; exit (2); } if (grep (/\Q$rejpat\E/, @RejectPats) == 0) { push @RejectPats, $rejpat } else { print STDERR "Ignoring duplicate pattern \"$rejpat\" in reject_reply_patterns\n"; } } @RejectKeys = @RejectPats; for (@RejectKeys) { s/\./x/g; } print "\tRejectPat: \"@RejectPats\", RejectKeys: \"@RejectKeys\"\n" if $Opts{'debug'} & Logreporters::D_SECT; # Add reject variants foreach my $key (@RejectKeys) { $key = lc($key); my $keyuc = ucfirst($key); my $totalsref = \$Totals{'totalrejects' . $key}; print "\t reject key: $key\n" if $Opts{'debug'} & Logreporters::D_SECT; begin_section_group ($S, 'rejects', "\n"); begin_section_group ($S, 'rejects2', "\n"); add_section ($S, $key . 'rejectrelay', 1, 'd', $keyuc . ' Reject relay denied', $totalsref); add_section ($S, $key . 'rejecthelo', 1, 'd', $keyuc . ' Reject HELO/EHLO', $totalsref); add_section ($S, $key . 'rejectdata', 1, 'd', $keyuc . ' Reject DATA', $totalsref); add_section ($S, $key . 'rejectunknownuser', 1, 'd', $keyuc . ' Reject unknown user', $totalsref); add_section ($S, $key . 'rejectrecip', 1, 'd', $keyuc . ' Reject recipient address', $totalsref); add_section ($S, $key . 'rejectsender', 1, 'd', $keyuc . ' Reject sender address', $totalsref); add_section ($S, $key . 'rejectclient', 1, 'd', $keyuc . ' Reject client host', $totalsref); add_section ($S, $key . 'rejectunknownclient', 1, 'd', $keyuc . ' Reject unknown client host', $totalsref); add_section ($S, $key . 'rejectunknownreverseclient', 1, 'd', $keyuc . ' Reject unknown reverse client host', $totalsref); add_section ($S, $key . 'rejectunverifiedclient', 1, 'd', $keyuc . ' Reject unverified client host', $totalsref); add_section ($S, $key . 'rejectrbl', 1, 'd', $keyuc . ' Reject RBL', $totalsref); add_section ($S, $key . 'rejectheader', 1, 'd', $keyuc . ' Reject header', $totalsref); add_section ($S, $key . 'rejectbody', 1, 'd', $keyuc . ' Reject body', $totalsref); add_section ($S, $key . 'rejectcontent', 1, 'd', $keyuc . ' Reject content', $totalsref); add_section ($S, $key . 'rejectsize', 1, 'd', $keyuc . ' Reject message size', $totalsref); add_section ($S, $key . 'rejectmilter', 1, 'd', $keyuc . ' Reject milter', $totalsref); add_section ($S, $key . 'rejectproxy', 1, 'd', $keyuc . ' Reject proxy', $totalsref); add_section ($S, $key . 'rejectinsufficientspace', 1, 'd', $keyuc . ' Reject insufficient space', $totalsref); add_section ($S, $key . 'rejectconfigerror', 1, 'd', $keyuc . ' Reject server config error', $totalsref); add_section ($S, $key . 'rejectverify', 1, 'd', $keyuc . ' Reject VRFY', $totalsref); add_section ($S, $key . 'rejectetrn', 1, 'd', $keyuc . ' Reject ETRN', $totalsref); add_section ($S, $key . 'rejectlookupfailure', 1, 'd', $keyuc . ' Reject temporary lookup failure', $totalsref); end_section_group ($S, 'rejects2', $sep2); add_section ($S, 'totalrejects' . $key, 0, 'd', "Total $keyuc Rejects", $totalsref); end_section_group ($S, 'rejects', $sep1); $Totals{'totalrejects' . $key} = 0; } begin_section_group ($S, 'byiprejects', "\n"); add_section ($S, 'byiprejects', 1, 'd', 'Reject by IP'); end_section_group ($S, 'byiprejects'); begin_section_group ($S, 'general1', "\n"); add_section ($S, 'connectioninbound', 1, 'd', 'Connections'); add_section ($S, 'connectionlostinbound', 1, 'd', 'Connections lost (inbound)'); add_section ($S, 'connectionlostoutbound', 1, 'd', 'Connections lost (outbound)'); add_section ($S, 'disconnection', 0, 'd', 'Disconnections'); add_section ($S, 'removedfromqueue', 0, 'd', 'Removed from queue'); add_section ($S, 'delivered', 1, 'd', 'Delivered'); add_section ($S, 'sent', 1, 'd', 'Sent via SMTP'); add_section ($S, 'sentlmtp', 1, 'd', 'Sent via LMTP'); add_section ($S, 'forwarded', 1, 'd', 'Forwarded'); add_section ($S, 'resent', 0, 'd', 'Resent'); add_section ($S, 'deferred', 1, 'd', 'Deferred'); add_section ($S, 'deferrals', 1, 'd', 'Deferrals'); add_section ($S, 'bouncelocal', 1, 'd', 'Bounced (local)'); add_section ($S, 'bounceremote', 1, 'd', 'Bounced (remote)'); add_section ($S, 'bouncefailed', 1, 'd', 'Bounce failure'); add_section ($S, 'postscreen', 1, 'd', 'Postscreen'); add_section ($S, 'dnsblog', 1, 'd', 'DNSBL log'); add_section ($S, 'dnsblranks', 1, 'd', 'DNSBL ranks'); add_section ($S, 'envelopesenders', 1, 'd', 'Envelope senders'); add_section ($S, 'envelopesenderdomains', 1, 'd', 'Envelope sender domains'); add_section ($S, 'bcced', 1, 'd', 'BCCed'); add_section ($S, 'filtered', 1, 'd', 'Filtered'); add_section ($S, 'redirected', 1, 'd', 'Redirected'); add_section ($S, 'discarded', 1, 'd', 'Discarded'); add_section ($S, 'prepended', 1, 'd', 'Prepended'); add_section ($S, 'replaced', 1, 'd', 'Replaced'); add_section ($S, 'warned', 1, 'd', 'Warned'); add_section ($S, 'requeued', 0, 'd', 'Requeued messages'); add_section ($S, 'returnedtosender', 1, 'd', 'Expired and returned to sender'); add_section ($S, 'notificationsent', 1, 'd', 'Notifications sent'); add_section ($S, 'policyspf', 1, 'd', 'Policy SPF'); add_section ($S, 'policydweight', 1, 'd', 'Policyd-weight'); add_section ($S, 'postfwd', 1, 'd', 'Postfwd'); add_section ($S, 'postgrey', 1, 'd', 'Postgrey'); end_section_group ($S, 'general1'); begin_section_group ($S, 'general2', "\n"); add_section ($S, 'connecttofailure', 1, 'd', 'Connection failures (outbound)'); add_section ($S, 'timeoutinbound', 1, 'd', 'Timeouts (inbound)'); add_section ($S, 'heloerror', 1, 'd', 'HELO/EHLO conversations errors'); add_section ($S, 'illegaladdrsyntax', 1, 'd', 'Illegal address syntax in SMTP command'); add_section ($S, 'released', 0, 'd', 'Released from hold'); add_section ($S, 'rblerror', 1, 'd', 'RBL lookup errors'); add_section ($S, 'dnserror', 1, 'd', 'DNS lookup errors'); add_section ($S, 'numerichostname', 1, 'd', 'Numeric hostname'); add_section ($S, 'smtpconversationerror', 1, 'd', 'SMTP dialog errors'); add_section ($S, 'hostnameverification', 1, 'd', 'Hostname verification errors (FCRDNS)'); add_section ($S, 'hostnamevalidationerror', 1, 'd', 'Hostname validation errors'); add_section ($S, 'smtpprotocolviolation', 1, 'd', 'SMTP protocol violations'); add_section ($S, 'deliverable', 1, 'd', 'Deliverable (address verification)'); add_section ($S, 'undeliverable', 1, 'd', 'Undeliverable (address verification)'); add_section ($S, 'tablechanged', 0, 'd', 'Restarts due to lookup table change'); add_section ($S, 'pixworkaround', 1, 'd', 'PIX workaround enabled'); add_section ($S, 'tlsserverconnect', 1, 'd', 'TLS connections (server)'); add_section ($S, 'tlsservernocert', 1, 'd', 'TLS no client certificate presented'); add_section ($S, 'tlsclientcertnottrusted', 1, 'd', 'TLS client certificate not trusted'); add_section ($S, 'tlsclientconnect', 1, 'd', 'TLS connections (client)'); add_section ($S, 'saslauth', 1, 'd', 'SASL authenticated messages'); add_section ($S, 'tlsunverified', 1, 'd', 'TLS certificate unverified'); add_section ($S, 'tlsoffered', 1, 'd', 'Host offered TLS'); end_section_group ($S, 'general2'); begin_section_group ($S, 'postfixstate', "\n"); add_section ($S, 'postfixstart', 0, 'd', 'Postfix start'); add_section ($S, 'postfixstop', 0, 'd', 'Postfix stop'); add_section ($S, 'postfixrefresh', 0, 'd', 'Postfix refresh'); add_section ($S, 'postfixwaiting', 0, 'd', 'Postfix waiting to terminate'); end_section_group ($S, 'postfixstate'); begin_section_group ($S, 'backwardscompatible', "\n"); add_section ($S, 'backwardscompatible', 1, 'd', 'Running in backwards compatibile mode'); end_section_group ($S, 'backwardscompatible'); if ($Opts{'debug'} & Logreporters::D_SECT) { print "\tSection table\n"; printf "\t\t%s\n", (ref($_) eq 'HASH' ? $_->{NAME} : $_) foreach @Sections; print "build_sect_table: exit\n" } } # XXX create array of defaults for detail <5, 5-9, >10 sub init_defaults() { map { $Opts{$_} = $Defaults{$_} unless exists $Opts{$_} } keys %Defaults; if (! $Opts{'standalone'}) { # LOGWATCH # these take affect if no env present (eg. nothing in conf file) # 0 to 4 nodelays if ($Opts{'detail'} < 5) { # detail 0 to 4, disable all supplemental reports $Opts{'delays'} = 0; $Opts{'postgrey_delays'} = 0; } } } # XXX ensure something is matched? # XXX cache values so we don't have to substitute X for . each time #match $dsn against list for best fit sub get_reject_key($) { my $reply = shift; my $replyorig = $reply; ($reply) = split / /, $reply; for (my $i = 0; $i <= $#RejectPats; $i++) { #print "TRYING: $RejectPats[$i]\n"; # we'll allow extended DSNs to match (eg. 5.7.1 will match 5..) if ($reply =~ /^$RejectPats[$i]/) { # no /o here, pattern varies #print "MATCHED: orig: $replyorig, reply $reply matched pattern $RejectPats[$i], returning $RejectKeys[$i]\n"; return $RejectKeys[$i]; } } #print "NOT MATCHED: REPLY CODE: '$replyorig', '$reply'\n"; return; } # Replace bare reject limiters with specific reject limiters # based on reject_reply_patterns # sub expand_bare_reject_limiters() { # don't reorder the list of limiters. This breaks --nodetail followed by a # bare reject such as --limit rejectrbl=10. Reordering is no longer necessary # since process_limiters was instituted and using the special __none__ pseudo- # limiter to indicate the position at which --nodetail was found on the command # line. # my ($limiter, @reject_limiters, @non_reject_limiters); my ($limiter, @new_list); # XXX check if limiter matches just one in rejectclasses while ($limiter = shift @Limiters) { if ($limiter =~ /^reject[^_]/) { foreach my $reply_code (@RejectKeys) { printf "bare_reject: \L$reply_code$limiter\n" if $Opts{'debug'} & Logreporters::D_VARS; #push @reject_limiters, lc($reply_code) . $limiter; push @new_list, lc($reply_code) . $limiter; } } elsif ($limiter =~ /^(?:[45]\.\.|Warn)reject[^_]/) { $limiter =~ s/^([45])\.\./$1xx/; #push @reject_limiters, lc $limiter; push @new_list, lc $limiter; } else { #push @non_reject_limiters, $limiter; push @new_list, $limiter; } } #@Limiters = (@reject_limiters, @non_reject_limiters); @Limiters = @new_list; } # Return a usage string, built from: # arg1 + # $usage_str + # a string built from each usable entry in the @Sections table. # reject patterns are special cased to minimize the number of # command line options presented. # sub usage($) { my $ret = ""; $ret = "@_\n" if ($_[0]); $ret .= $usage_str; my ($name, $desc, %reject_types); foreach my $sect (get_usable_sectvars(@Sections, 0)) { if (my ($code,$rej) = ($sect->{NAME} =~ /^(...|warn)(reject.*)$/oi)) { $rej = lc $rej; next if (exists $reject_types{$rej}); $reject_types{$rej}++; $name = '[###]' . $rej; $desc = '###' . substr($sect->{TITLE}, length($code)); } else { $name = lc $sect->{NAME}; $desc = $sect->{TITLE}; } $ret .= sprintf " --%-38s%s\n", "$name" . ' LEVEL', "$desc"; } $ret .= "\n"; return $ret; } 1; # vi: shiftwidth=3 tabstop=3 syntax=perl et logwatch-7.12/scripts/services/dnf-rpm0000664000211400021140000001230214274101035020240 0ustar logwatchlogwatch ######################################################## # Please file all bug reports, patches, and feature # requests under: # https://sourceforge.net/p/logwatch/_list/tickets # Help requests and discusion can be filed under: # https://sourceforge.net/p/logwatch/discussion/ ######################################################## ####################################################### ## Copyright (c) 2008 Sy Beamont ## Covered under the included MIT/X-Consortium License: ## http://www.opensource.org/licenses/mit-license.php ## All modifications and contributions by other persons to ## this script are assumed to have been donated to the ## Logwatch project and thus assume the above copyright ## and licensing terms. If you want to make contributions ## under your own copyright or a different license this ## must be explicitly stated in the contribution an the ## Logwatch project reserves the right to not accept such ## contributions. If you have made significant ## contributions to this script and want to claim ## copyright please contact logwatch-devel@lists.sourceforge.net. ######################################################### use strict; my $Debug = $ENV{'LOGWATCH_DEBUG'} || 0; my $DebugCounter = 0; my $ignoredlines = 0; if ( $Debug >= 5 ) { print STDERR "\n\nDEBUG: Inside dnf-rpm Filter \n\n"; $DebugCounter = 1; } #Init Hashes my ( %InfoMessages, %PackageDowngrade, %PackageDowngraded, %PackageErased, %PackageInstalled, %PackageObsoleted, %PackageReinstalled, %PackageUpdate, %PackageUpdated ); #Init Array my @OtherList = (); while (defined(my $ThisLine = )) { if ( $Debug >= 5 ) { print STDERR "DEBUG($DebugCounter): $ThisLine"; $DebugCounter++; } if ( $ThisLine =~ s/^.* (?:INFO|SUBDEBUG) Upgrade: ([^ ]+)/$1/ ) { $PackageUpdate{$ThisLine}++; } elsif ( $ThisLine =~ s/^.* (?:INFO|SUBDEBUG) Upgraded: ([^ ]+)/$1/ ) { $PackageUpdated{$ThisLine}++; } elsif ( $ThisLine =~ s/^.* (?:INFO|SUBDEBUG) Installed: ([^ ]+)/$1/ ) { $PackageInstalled{$ThisLine}++; } elsif ( $ThisLine =~ s/^.* (?:INFO|SUBDEBUG) Reinstalled: ([^ ]+)/$1/ ) { $PackageReinstalled{$ThisLine}++; } elsif ( $ThisLine =~ s/^.* (?:INFO|SUBDEBUG) Erased?: ([^ ]+)/$1/ ) { $PackageErased{$ThisLine}++; } elsif ( $ThisLine =~ s/^.* (?:INFO|SUBDEBUG) Obsoleted: ([^ ]+)/$1/ ) { $PackageObsoleted{$ThisLine}++; } elsif ( $ThisLine =~ s/^.* (?:INFO|SUBDEBUG) Downgrade: ([^ ]+)/$1/ ) { $PackageDowngrade{$ThisLine}++; } elsif ( $ThisLine =~ s/^.* (?:INFO|SUBDEBUG) Downgraded: ([^ ]+)/$1/ ) { $PackageDowngraded{$ThisLine}++; } elsif ( $ThisLine =~ m/INFO --- logging initialized ---/ ) { $ignoredlines++; } elsif ( $ThisLine =~ m/(?:INFO|SUBDEBUG) (Obsolete|Reinstall|Cleanup): / ) { $ignoredlines++; } elsif ( $ThisLine =~ s/^.* INFO ([^ ]+)/$1/ ) { chomp($ThisLine); $InfoMessages{$ThisLine}++; } else { # Report any unmatched entries... push @OtherList,$ThisLine; } } if (keys %PackageInstalled) { print "\nPackages Installed:\n"; foreach my $ThisOne (sort {lc($a) cmp lc($b)} keys %PackageInstalled) { print " " . $ThisOne; } } if (keys %PackageReinstalled) { print "\nPackages Reinstalled:\n"; foreach my $ThisOne (sort {lc($a) cmp lc($b)} keys %PackageReinstalled) { print " ". $ThisOne; } } if (keys %PackageUpdate == keys %PackageUpdated) { if (keys %PackageUpdate) { print "\nPackages Updated:\n"; chomp(my @Updated = sort {lc($a) cmp lc($b)} keys %PackageUpdated); foreach my $ThisOne (sort {lc($a) cmp lc($b)} keys %PackageUpdate) { print " ". shift(@Updated) ." -> ". $ThisOne; } } } else { print "\nPackages Updated (Count Mismatch)"; if (keys %PackageUpdate) { print "\nPackages To Be Updated:\n"; foreach my $ThisOne (sort {lc($a) cmp lc($b)} keys %PackageUpdate) { print " ". $ThisOne; } } if (keys %PackageUpdated) { print "\nPackages Updated To:\n"; foreach my $ThisOne (sort {lc($a) cmp lc($b)} keys %PackageUpdated) { print " ". $ThisOne; } } } if (keys %PackageDowngrade) { print "\nPackages Downgraded:\n"; chomp(my @Downgraded = sort {lc($a) cmp lc($b)} keys %PackageDowngraded); foreach my $ThisOne (sort {lc($a) cmp lc($b)} keys %PackageDowngrade) { print " ". shift(@Downgraded) ." -> ". $ThisOne; } } if (keys %PackageErased) { print "\nPackages Erased:\n"; foreach my $ThisOne (sort {lc($a) cmp lc($b)} keys %PackageErased) { print " ". $ThisOne; } } if (keys %PackageObsoleted) { print "\nPackages Obsoleted:\n"; foreach my $ThisOne (sort {lc($a) cmp lc($b)} keys %PackageObsoleted) { print " ". $ThisOne; } } if (keys %InfoMessages) { print "\nInformation Messages:\n"; foreach my $ThisOne (sort {$a cmp $b} keys %InfoMessages) { print " ". $ThisOne . ": ". $InfoMessages{$ThisOne} . " Times(s)\n"; } } if ($#OtherList >= 0) { print "\n**Unmatched Entries**\n"; print @OtherList; } exit(0); # vi: shiftwidth=3 tabstop=3 syntax=perl et # Local Variables: # mode: perl # perl-indent-level: 3 # indent-tabs-mode: nil # End: logwatch-7.12/scripts/services/autorpm0000664000211400021140000000441514274101034020371 0ustar logwatchlogwatch ######################################################## # Please file all bug reports, patches, and feature # requests under: # https://sourceforge.net/p/logwatch/_list/tickets # Help requests and discusion can be filed under: # https://sourceforge.net/p/logwatch/discussion/ ######################################################## ######################################################## ## Copyright (c) 2008 Kirk Bauer ## Covered under the included MIT/X-Consortium License: ## http://www.opensource.org/licenses/mit-license.php ## All modifications and contributions by other persons to ## this script are assumed to have been donated to the ## Logwatch project and thus assume the above copyright ## and licensing terms. If you want to make contributions ## under your own copyright or a different license this ## must be explicitly stated in the contribution an the ## Logwatch project reserves the right to not accept such ## contributions. If you have made significant ## contributions to this script and want to claim ## copyright please contact logwatch-devel@lists.sourceforge.net. ######################################################### use strict; my (@Unmatched, $line, %Actions); while (defined($line = )) { chomp($line); if ($line =~ s/^Uninstalled //) { $Actions{$line} = 'REMOVED'; } elsif ($line =~ s/^Installed //) { if ($line =~ /^(.+)-([^-]+-[^-]+)$/) { $Actions{$1} = $2; } } elsif (my ($v1, $v2) = ($line =~ /^(.+) -> (.+)$/)) { if ($v2 =~ s/^.+-([^-]+-[^-]+)$/$1/) { if ($v1 =~ s/^(.+)-([^-]+-[^-]+)$/$2/) { $Actions{$1} = []; $Actions{$1}->[0] = $v1; $Actions{$1}->[1] = $v2; } } } else { push @Unmatched, $line; } } foreach (sort keys %Actions) { if ($Actions{$_} eq 'REMOVED') { print "[ REMOVED] $_\n"; } elsif (ref $Actions{$_} eq 'ARRAY') { print "[ UPGRADED] $_: $Actions{$_}->[0] -> $Actions{$_}->[1]\n"; } else { print "[INSTALLED] $_-$Actions{$_}\n"; } } if (@Unmatched) { print "Unmatched Entries:\n"; foreach (@Unmatched) { print " $_\n"; } } exit 0; # vi: shiftwidth=3 tabstop=3 syntax=perl et # Local Variables: # mode: perl # perl-indent-level: 3 # indent-tabs-mode: nil # End: logwatch-7.12/scripts/services/evtsecurity0000664000211400021140000003642414743365003021306 0ustar logwatchlogwatch# Process Windows security events logged to a server, using Snare Agent or # similar. ######################################################## ## Copyright (c) 2008-2014 Orion Poplawski ## Covered under the included MIT/X-Consortium License: ## http://www.opensource.org/licenses/mit-license.php ## All modifications and contributions by other persons to ## this script are assumed to have been donated to the ## Logwatch project and thus assume the above copyright ## and licensing terms. If you want to make contributions ## under your own copyright or a different license this ## must be explicitly stated in the contribution an the ## Logwatch project reserves the right to not accept such ## contributions. If you have made significant ## contributions to this script and want to claim ## copyright please contact logwatch-devel@lists.sourceforge.net. ######################################################### use strict; use URI::URL; my $Detail = $ENV{'LOGWATCH_DETAIL_LEVEL'} || 0; my $Ignore_messages = $ENV{'ignore_messages'} || '^$'; my $SuccessAudits = 0; my %SuccessAuditUsers; my %FailureAudits; my %SuccessAudits; my %ClockSkew; my %Errors; my %Information; my %UnknownUser; my %UnknownClient; my %BadPasswords; my %TicketExpired; my %AccessDenied; my %AccountChanged; my %AccountCreated; my %AccountDeleted; my %AccountDisabled; my %AccountEnabled; my %AccountLocked; my %AuditPolicyChanged; my %ExpiredPassword; my %PasswordChanged; my %Logon; my %PrivilegedLogon; my %Logoff; my %WorkstationLocked; my %WorkstationUnlocked; my %OtherList; while (defined(my $ThisLine = )) { # User specified ignore messages, lower cased next if $ThisLine =~ /$Ignore_messages/i; my ($Hostname,$Criticality,$SourceName,$DateTime,$EventID,$SourceName2,$UserName,$SIDType,$EventLogType,$CategoryString,$DataString,$ExpandedString,$Extra); #Determine format if ($ThisLine =~ /MSWinEventLog\[/) { # Snare 4 #Parse ($Criticality,$SourceName,$DateTime,$EventID,$SourceName2,$UserName,$SIDType,$EventLogType,$Hostname,$CategoryString,$DataString,$ExpandedString,$Extra) = ($ThisLine =~ /MSWinEventLog\[(\d+)\]:(\w+)\t\d+\t([^\t]+)\t(\d+)\t([^\t]+)\t([^\t]+)\t([^\t]+)\t([^\t]+)\t([^\t]+)\t?([^\t]*)\t?([^\t]*)\t?([^\t]*)\t?([^\t]*)/); } elsif ($ThisLine =~ /MSWinEventLog\t/) { # Snare 3 #Parse ($Criticality,$SourceName,$DateTime,$EventID,$SourceName2,$UserName,$SIDType,$EventLogType,$Hostname,$CategoryString,$DataString,$ExpandedString,$Extra) = ($ThisLine =~ /MSWinEventLog\t(\d+)\t(\w+)\t\d+\t([^\t]+)\t(\d+)\t([^\t]+)\t([^\t]+)\t([^\t]+)\t([^\t]+)\t([^\t]+)\t?([^\t]*)\t?([^\t]*)\t?([^\t]*)\t?([^\t]*)/); } if (!defined($Hostname)) { print STDERR "Cannot parse $ThisLine"; next; } # Modify some items that prevent de-duplication if ($Detail < 10) { $ExpandedString =~ s/Filter Run-Time ID: \d+/Filter Run-Time ID: XXX/; $ExpandedString =~ s/(Key Name:)\s+\{[0-9A-F\-]+\}/$1 {XXX}/g; $ExpandedString =~ s/Logon ID:\s+0x[0-9A-F]+/Logon ID: 0xXXX/; } if ($Detail < 5) { # Reduce ephemeral ports $ExpandedString =~ s/(Client|Destination|Source) Port:(\s+)[3-6]\d{4}/$1 Port:${2}XXXXX/g; $ExpandedString =~ s/Relative Target Name: ([^\t]+)/Relative Target Name: XXX/; } my $url = URI::URL->new("https://www.ultimatewindowssecurity.com/securitylog/encyclopedia/event.aspx?eventID=$EventID"); if ($EventID == 4673 or $EventID == 4674) { # An operation was attempted on a privileged object. # These are basically noise # https://www.ultimatewindowssecurity.com/securitylog/encyclopedia/event.aspx?eventID=4673 # https://www.ultimatewindowssecurity.com/securitylog/encyclopedia/event.aspx?eventID=4674 # Ignore } elsif ($EventLogType eq "Success Audit") { if ($EventID == 4608 # Windows is starting up. (startups logged by evtsystem) or $EventID == 4688 # A new process has been created. or $EventID == 4689 # A process has exited. ) { # Ignore } elsif ($EventID == 4624 or $EventID == 4648) { $Logon{"$Hostname $UserName"}++ if $Detail >= 5; } elsif ($EventID == 4634 or $EventID == 4647) { $Logoff{"$Hostname $UserName"}++ if $Detail >= 5; } elsif ($EventID == 4672) { $PrivilegedLogon{"$Hostname $UserName"}++ if $Detail > 0; } elsif ($EventID == 4719) { $AuditPolicyChanged{$Hostname}++; } elsif ($EventID == 4720) { $AccountCreated{$UserName}++; } elsif ($EventID == 4722) { $AccountEnabled{$UserName}++; } elsif ($EventID == 4723) { $PasswordChanged{$UserName}++; } elsif ($EventID == 4725) { $AccountDisabled{$UserName}++; } elsif ($EventID == 4726) { $AccountDeleted{$UserName}++; } elsif ($EventID == 4738 or $EventID == 4742) { $AccountChanged{$UserName}++; } elsif ($EventID == 4800) { $WorkstationLocked{"$Hostname $UserName"}++ if $Detail >= 10; } elsif ($EventID == 4801) { $WorkstationUnlocked{"$Hostname $UserName"}++ if $Detail >= 10; } else { $SuccessAudits++; $SuccessAuditUsers{$UserName}++; $SuccessAudits{"$Hostname $ExpandedString\n$url"}++ if $Detail >= 10; } } elsif ($EventLogType eq "Failure Audit") { if ($EventID == 4625) { # An account failed to log on if (my ($account,$domain,$reason) = ($ExpandedString =~ /Account For Which Logon Failed:.*Account Name:\s+(\S+)\s+Account Domain:\s+(\S+).*Failure Reason:\s+(.+)\s+Status:.*Sub Status:/)) { $FailureAudits{"$Hostname Log On Failure for $domain\\$account: $reason"}++; } elsif (my ($account,$domain,$reason,$process) = ($ExpandedString =~ /Account Name:\s+(\S+)\s+Account Domain:\s+(\S+).*Failure Reason:\s+(.+)\s+Status:.*Sub Status:.*Caller Process Name:\s+(.*)\s+Network Informaion:/)) { $FailureAudits{"$Hostname Log On Failure for $domain\\$account by $process: $reason"}++; } } elsif (my ($account,$domain,$process) = ($ExpandedString =~ /^A privileged service was called\..*Account Name:\s+(\S+)\s+Account Domain:\s+(\S+).*Process Name:\s+(.+)\sService/)) { $FailureAudits{"$Hostname Privileged service called for $domain\\$account: $process"}++ if $Detail; } elsif ($EventID == 4768) { # A Kerberos authentication ticket (TGT) was requested my ($Account,$Realm,$Client,$FailureCode) = $ExpandedString =~ /Account Name:\s+(\S*)\s.*Supplied Realm Name:\s+(\S*)\s.*Client Address:\s+(\S+)\s.*Result Code:\s+(\w+)/; if ($FailureCode eq "0x6") { # Client not found in Kerberos database $UnknownClient{"$Account\\$Realm $Client"}++; } elsif ($FailureCode eq "0x12") { $AccountDisabled{"$Account\@$Realm $Client"}++; } elsif ($FailureCode eq "0x17") { # Password has expired $ExpiredPassword{"$UserName"}++; } else { $FailureAudits{"$Hostname $ExpandedString\n$url"}++; } } elsif ($EventID == 4769) { # A Kerberos service ticket was requested my ($Client,$FailureCode) = $ExpandedString =~ /Client Address:\s+(\S+)\s.*Failure Code:\s+(\w+)/; #print STDER "EventID=$EventID Client=$Client FailureCode=$FailureCode ExpandedString=$ExpandedString\n"; if ($FailureCode eq "0x12") { $AccountDisabled{"$Client"}++; } elsif ($FailureCode eq "0x1B") { # KDC_ERR_MUST_USE_USER2USER Server principal valid for user-to-user only # This is an informational response and not an issue } elsif ($FailureCode eq "0x20") { # Ticket expired $TicketExpired{$Client}++; } elsif ($FailureCode eq "0x25") { # Clock skew too great $ClockSkew{$Client}++; } else { $FailureAudits{"$Hostname $ExpandedString\n$url"}++; } } elsif ($EventID == 4771) { # Kerberos pre-authentication failed my ($Account,$Client,$FailureCode) = $ExpandedString =~ /Account Name:\s+(\S+)\s.*Client Address:\s+(\S+)\s.*Failure Code:\s+(\w+)/; if ($FailureCode eq "0x12") { #Clients credentials have been revoked Account disabled, expired, locked out, logon hours. $AccountLocked{"$Account $Client"}++; } elsif ($FailureCode eq "0x18") { #Pre-authentication information was invalid - bad password $BadPasswords{"$Account $Client"}++; } elsif ($FailureCode eq "0x25") { # Clock skew too great $ClockSkew{$Client}++; } else { $FailureAudits{"$Hostname $ExpandedString\n$url"}++; } } elsif ($EventID == 4776) { # The domain controller attempted to validate the credentials for an account my ($Account,$Client,$FailureCode) = $ExpandedString =~ /Logon Account:\s+(\S+)\s+Source Workstation:\s+(\S*)\s.*Error Code:\s+(\w+)/; if (lc($FailureCode) eq "0xc0000064") { # user name does not exist $UnknownUser{"$Account $Client"}++; } elsif (lc($FailureCode) eq "0xc000006a") { # user name is correct but the password is wrong $BadPasswords{"$Account $Client"}++; } elsif (lc($FailureCode) eq "0xc0000071") { # expired password $ExpiredPassword{"$Account $Client"}++; } elsif (lc($FailureCode) eq "0xc0000234") { # account locked $AccountLocked{"$UserName $Client"}++; } else { $FailureAudits{"$Hostname $ExpandedString\n$url"}++; } } elsif ($EventID == 4957 and $ExpandedString =~ /resolved to an empty set/) { # Windows Firewall did not apply the following rule - because it was not applicable } elsif ($EventID == 6273) { my ($account,$domain,$client) = ($ExpandedString =~ /Account Name:\s+(\S+)\s+Account Domain:\s+(\S+).*Client Friendly Name:\s+(\S+)/); $AccessDenied{"$account\\$domain $client"}++; } else { $FailureAudits{"$Hostname $ExpandedString\n$url"}++; } } elsif ($EventLogType eq "Error") { $ExpandedString =~ s/\s+\d+\s+\d+//; $Errors{"$Hostname $ExpandedString\n$url"}++; } elsif ($EventLogType eq "Information") { next if $ExpandedString =~ /The event logging service has shut down/; next if $Detail < 5; $Information{"$Hostname $ExpandedString\n$url"}++; } else { # Report any unmatched entries... chomp($ThisLine); $OtherList{"Type=$EventLogType $ThisLine"}++; } } if (keys %Errors) { print "\nERRORS:\n"; foreach my $Error (sort keys %Errors) { print " $Error : $Errors{$Error} Times\n"; } } if (keys %ClockSkew) { print "\nClock skew too great\n"; foreach my $Client (sort keys %ClockSkew) { print " $Client : $ClockSkew{$Client} Times\n"; } } if (keys %AccountCreated) { print "\nAccount Created\n"; foreach my $Account (sort keys %AccountCreated) { print " $Account : $AccountCreated{$Account} Times\n"; } } if (keys %AccountDeleted) { print "\nAccount Deleted\n"; foreach my $Account (sort keys %AccountDeleted) { print " $Account : $AccountDeleted{$Account} Times\n"; } } if (keys %AccountDisabled) { print "\nAccount Disabled\n"; foreach my $Account (sort keys %AccountDisabled) { print " $Account : $AccountDisabled{$Account} Times\n"; } } if (keys %AccountEnabled) { print "\nAccount Enabled\n"; foreach my $Account (sort keys %AccountEnabled) { print " $Account : $AccountEnabled{$Account} Times\n"; } } if (keys %AccountChanged) { print "\nAccount Changed\n"; foreach my $Account (sort keys %AccountChanged) { print " $Account : $AccountChanged{$Account} Times\n"; } } if (keys %PasswordChanged) { print "\nPassword Changed\n"; foreach my $Account (sort keys %PasswordChanged) { print " $Account : $PasswordChanged{$Account} Times\n"; } } if (keys %AccountLocked) { print "\nAccount Locked\n"; foreach my $Account (sort keys %AccountLocked) { print " $Account : $AccountLocked{$Account} Times\n"; } } if (keys %ExpiredPassword) { print "\nPassword Expired\n"; foreach my $Account (sort keys %ExpiredPassword) { print " $Account : $ExpiredPassword{$Account} Times\n"; } } if (keys %AccessDenied) { print "\nAccess Denied\n"; foreach my $Item (sort keys %AccessDenied) { print " $Item : $AccessDenied{$Item} Times\n"; } } if (keys %UnknownUser) { print "\nUnknown Users\n"; foreach my $Account (sort keys %UnknownUser) { print " $Account : $UnknownUser{$Account} Times\n"; } } if (keys %UnknownClient) { print "\nUnknown Clients\n"; foreach my $Account (sort keys %UnknownClient) { print " $Account : $UnknownClient{$Account} Times\n"; } } if (keys %BadPasswords) { print "\nBad Passwords\n"; foreach my $Account (sort keys %BadPasswords) { print " $Account : $BadPasswords{$Account} Times\n"; } } if (keys %TicketExpired) { print "\nTicket Expired\n"; foreach my $Client (sort keys %TicketExpired) { print " $Client : $TicketExpired{$Client} Times\n"; } } if (keys %FailureAudits) { print "\nFailure Audits\n"; foreach my $Error (sort keys %FailureAudits) { print " $Error : $FailureAudits{$Error} Times\n"; } } if (keys %AuditPolicyChanged) { print "\nAudit Policy Changed\n"; foreach my $Hostname (sort keys %AuditPolicyChanged) { print " $Hostname : $AuditPolicyChanged{$Hostname} Times\n"; } } # Detail > 0 if (keys %PrivilegedLogon) { print "\nPrivileged Logons\n"; foreach my $User (sort keys %PrivilegedLogon) { print " $User : $PrivilegedLogon{$User} Times\n"; } } # Detail >= 5 if (keys %Logon) { print "\nLogons\n"; foreach my $User (sort keys %Logon) { print " $User : $Logon{$User} Times\n"; } } # Detail >= 5 if (keys %Logoff) { print "\nLogoffs\n"; foreach my $User (sort keys %Logoff) { print " $User : $Logoff{$User} Times\n"; } } # Detail >= 10 if (keys %WorkstationLocked) { print "\nWorkstation Locked\n"; foreach my $User (sort keys %WorkstationLocked) { print " $User : $WorkstationLocked{$User} Times\n"; } } # Detail >= 10 if (keys %WorkstationUnlocked) { print "\nWorkstation Unlocked\n"; foreach my $User (sort keys %WorkstationUnlocked) { print " $User : $WorkstationUnlocked{$User} Times\n"; } } # Detail >= 5 if ($SuccessAudits and ($Detail >= 5) ) { print "\nSuccess Audits " . $SuccessAudits . " Time(s)\n"; foreach my $User (keys %SuccessAuditUsers) { print " $User : $SuccessAuditUsers{$User} Times\n"; } if ($Detail >= 10) { print "\nSuccess Audits\n"; foreach my $Error (sort keys %SuccessAudits) { print " $Error : $SuccessAudits{$Error} Times\n"; } } } if (keys %Information) { print "\nInformational Messages:\n"; foreach my $Item (sort keys %Information) { print " $Item : $Information{$Item} Times\n"; } } if (keys %OtherList) { print "\n**** Unmatched entries ****\n"; foreach my $Error (keys %OtherList) { print " $Error : $OtherList{$Error} Times\n"; } } exit(0); # vi: shiftwidth=3 tabstop=3 syntax=perl et # Local Variables: # mode: perl # perl-indent-level: 3 # indent-tabs-mode: nil # End: logwatch-7.12/scripts/services/fail2ban0000664000211400021140000003251514620267415020375 0ustar logwatchlogwatch ######################################################## # Please file all bug reports, patches, and feature # requests under: # https://sourceforge.net/p/logwatch/_list/tickets # Help requests and discusion can be filed under: # https://sourceforge.net/p/logwatch/discussion/ ######################################################## ######################################################## ## Copyright (c) 2008 Yaroslav Halchenko ## Covered under the included MIT/X-Consortium License: ## http://www.opensource.org/licenses/mit-license.php ## All modifications and contributions by other persons to ## this script are assumed to have been donated to the ## Logwatch project and thus assume the above copyright ## and licensing terms. If you want to make contributions ## under your own copyright or a different license this ## must be explicitly stated in the contribution an the ## Logwatch project reserves the right to not accept such ## contributions. If you have made significant ## contributions to this script and want to claim ## copyright please contact logwatch-devel@lists.sourceforge.net. ######################################################### use strict; use Logwatch ':all'; my $Debug = $ENV{'LOGWATCH_DEBUG'} || 0; my $Detail = $ENV{'LOGWATCH_DETAIL_LEVEL'} || 0; my $IgnoreHost = $ENV{'sshd_ignore_host'} || ""; my $IgnoreFlushing = $ENV{'fail2ban_ignore_flushing'} || ""; my $IgnoreLatency = $ENV{'fail2ban_ignore_latency'} || "^\$"; my $ErrLen = $ENV{'fail2ban_error_length'} || 80; my $DebugCounter = 0; my $ReInitializations = 0; my @IptablesErrors = (); my @ActionErrors = (); my $NotValidIP = 0; # reported invalid IPs number my %ErrorList = (); my %WarningList = (); my %InfoList = (); my %NoticeList = (); my %OtherList = (); my %Flushing = (); # keep track of which services being flushed my %LatencyIssues = (); my %ServicesBans = (); my %ServicesFound = (); my %ServicesIgnored = (); # IP lookups disabled by default. Set in fail2ban services # configuration file to enable. DoLookup( $ENV{'fail2ban_ip_lookup'} ); #Init String Containers my ( $Action, $Host, $Message, $NumFailures, $Service, $Increase ); if ( $Debug >= 5 ) { print STDERR "\n\nDEBUG: Inside Fail2Ban Filter \n\n"; $DebugCounter = 1; } while (defined(my $ThisLine = )) { if ( $Debug >= 5 ) { print STDERR "DEBUG($DebugCounter): $ThisLine"; $DebugCounter++; } chomp($ThisLine); if ( ($ThisLine =~ /..,... DEBUG: /) or ($ThisLine =~ /..,... \S*\s*: DEBUG /) or # syntax of 0.7.? fail2ban ($ThisLine =~ /..,... INFO: (Fail2Ban v.* is running|Exiting|Enabled sections:)/) or ($ThisLine =~ /INFO\s+Log rotation detected for/) or ($ThisLine =~ /INFO\s+Jail.+(?:stopped|started|uses )/) or ($ThisLine =~ /INFO\s+Changed logging target to/) or ($ThisLine =~ /INFO\s+Creating new jail/) or ($ThisLine =~ /INFO\s+(Set |Socket|Gamin|Created|Added|Using|Connected to |rollover performed)/) or # syntax of 0.7.? fail2ban ($ThisLine =~ /..,... WARNING: Verbose level is /) or ($ThisLine =~ /..,... WARNING: Restoring firewall rules/) or ($ThisLine =~ /WARNING Determined IP using DNS Lookup/) or ($ThisLine =~ /INFO\s+Initiated '.*' backend/) or ($ThisLine =~ /INFO\s+(Added logfile = .*|Set maxRetry = \d+|Set findtime = \d+|Set banTime = \d+)/) or ($ThisLine =~ /Unable to find a corresponding IP address for .*: \[Errno -2\] Name or service not known/) ) { if ( $Debug >= 6 ) { print STDERR "DEBUG($DebugCounter): line ignored\n"; } } elsif ( ($Service,$Action,$Host) = ($ThisLine =~ m/NOTICE:?\s+\[?(.*?)[]:]?\s(Restore Ban)[^\.]* (\S+)/)) { $ServicesBans{$Service}{$Host}{'ReBan'}++; $ServicesBans{$Service}{"(all)"}{'ReBan'}++; } elsif ( ($Service,$Increase,$Action,$Host) = ($ThisLine =~ m/(?:WARNING|NOTICE):?\s+\[?(.*?)[]:]?\s(Increase\s)?(Ban|Unban)[^\.]* (\S+)/)) { if ( $Increase ) { $Service .= " increase" } if ( $Debug >= 6 ) { print STDERR "DEBUG($DebugCounter): Found $Action for $Service from $Host\n"; } if (exists $Flushing{$Service}) { if ($Action =~ /Unban/) { $ServicesBans{$Service}{$Host}{'FlushUnban'}++; $ServicesBans{$Service}{"(all)"}{'FlushUnban'}++; } elsif ( ! $IgnoreFlushing ) { print STDERR "ERROR: Lost track of flushing services\n"; } } else { $ServicesBans{$Service}{$Host}{$Action}++; $ServicesBans{$Service}{"(all)"}{$Action}++; } } elsif ( ($Service,$Host,$NumFailures) = ($ThisLine =~ m/INFO: (\S+): (.+) has (\d+) login failure\(s\). Banned./)) { if ($Debug >= 4) { print STDERR "DEBUG: Found host $Host trying to access $Service - failed $NumFailures times\n"; } push @{$ServicesBans{$Service}{$Host}{'Failures'}}, $NumFailures; } elsif ( ($Service,$Host) = ($ThisLine =~ m/ ERROR:\s(.*):\s(\S+)\salready in ban list/)) { $ServicesBans{$Service}{$Host}{'AlreadyInTheList'}++; } elsif ( ($Service,$Host) = ($ThisLine =~ m/(?:INFO|WARNING|NOTICE)\s*\[(.*)\]\s*(\S+)\s*already banned/)) { $ServicesBans{$Service}{$Host}{'AlreadyInTheList'}++; } elsif ( ($Service,$Message) = ($ThisLine =~ m/WARNING\s*\[(.*)\].* (latency problem|timing issue)/)) { next if $Service =~ /$IgnoreLatency/; $LatencyIssues{$Service}++ if $Message eq "latency problem"; } elsif ( ($Service,$Host) = ($ThisLine =~ m/ WARNING:\s(.*):\sReBan (\S+)/)) { $ServicesBans{$Service}{$Host}{'ReBan'}++; } elsif ($ThisLine =~ / ERROR:?\s*(Execution of command )?\'?iptables/) { push @IptablesErrors, "$ThisLine\n"; } elsif ($ThisLine =~ /ERROR.*returned \d+$/) { push @ActionErrors, "$ThisLine\n"; } elsif (($ThisLine =~ /..,... WARNING: \#\S+ reinitialization of firewalls/) or ($ThisLine =~ / ERROR\s*Invariant check failed. Trying to restore a sane environment/)) { $ReInitializations++; } elsif ($ThisLine =~ /..,... WARNING: is not a valid IP address/) { # just ignore - this will be fixed within fail2ban and is harmless warning } elsif ( ($Service,$Host) = ($ThisLine =~ /INFO\s+\[(.*)\] Found (\S+)/)) { $ServicesFound{$Service}{$Host}++; } elsif ( ($Service,$Host) = ($ThisLine =~ /INFO\s+\[(.*)\] Ignore (\S+)/)) { $ServicesIgnored{$Service}{$Host}++; # Generic messages } elsif ( ($Message) = ($ThisLine =~ / ERROR (.*)$/)) { # Fail2ban can dump huge error messages in its logs if ($ErrLen > 3 && length($Message) > $ErrLen) { $ErrorList{substr($Message,0,$ErrLen-3).'...'}++; } else { $ErrorList{$Message}++; } } elsif ( ($Message) = ($ThisLine =~ / WARNING (.*)$/)) { $WarningList{$Message}++; } elsif ( ($Message) = ($ThisLine =~ / INFO (.*)$/)) { $InfoList{$Message}++; if ( ($Service) = ($Message =~ /Jail \'(.*)\' stopped/)) { delete $Flushing{$Service}; } if ( ($Service) = ($Message =~ /Stopping all jails|Exiting Fail2ban/)) { %Flushing = (); } } elsif ( ($Message) = ($ThisLine =~ / NOTICE (.*)$/)) { $NoticeList{$Message}++; if ( ($Service) = ($Message =~ /\[(.*)\] Flush ticket/)) { $Flushing{$Service} = 1; } } else { # Report any unmatched entries... $OtherList{$ThisLine}++; } } ########################################################### if (keys %ServicesBans and ($Detail > 0)) { printf("\nBanned services with Fail2Ban: Bans:Unbans ReBans:Flush\n"); foreach my $service (sort {$a cmp $b} keys %ServicesBans) { # Perl handles autoincrement of the uninitialized key values, # but it can issue a warning when used in a print statement. # So we check for existence before printing its value. printf(" %-50s [%3d:%-3d] [%3d:%-3d]\n", "$service:", (exists $ServicesBans{$service}{'(all)'}{'Ban'}) ? $ServicesBans{$service}{'(all)'}{'Ban'} : 0, (exists $ServicesBans{$service}{'(all)'}{'Unban'}) ? $ServicesBans{$service}{'(all)'}{'Unban'} : 0, (exists $ServicesBans{$service}{'(all)'}{'ReBan'}) ? $ServicesBans{$service}{'(all)'}{'ReBan'} : 0, (exists $ServicesBans{$service}{'(all)'}{'FlushUnban'}) ? $ServicesBans{$service}{'(all)'}{'FlushUnban'} : 0); delete $ServicesBans{$service}{'(all)'}; my $totalSort = TotalCountOrder(%{$ServicesBans{$service}}, \&SortIP); if ($Detail >= 5) { foreach my $ip (sort $totalSort keys %{$ServicesBans{$service}}) { my @name = split(/ /, LookupIP($ip)); # As explained above, we check for existence of hashes # that are autoincremented. printf(" %-48s %3d:%-3d %3d:%-3d\n", $name[0], (exists $ServicesBans{$service}{$ip}{'Ban'}) ? $ServicesBans{$service}{$ip}{'Ban'} : 0, (exists $ServicesBans{$service}{$ip}{'Unban'}) ? $ServicesBans{$service}{$ip}{'Unban'} : 0, (exists $ServicesBans{$service}{$ip}{'ReBan'}) ? $ServicesBans{$service}{$ip}{'ReBan'} : 0, (exists $ServicesBans{$service}{$ip}{'FlushUnban'}) ? $ServicesBans{$service}{$ip}{'FlushUnban'} : 0); if (scalar @name > 1) { printf(" %s\n", $name[1]); } if (($Detail >= 10) and (exists $ServicesBans{$service}{$ip}{'Failures'}) and ($ServicesBans{$service}{$ip}{'Failures'}>0)) { print " Failed "; foreach my $fails (@{$ServicesBans{$service}{$ip}{'Failures'}}) { print " $fails"; } print " times"; } if (($Detail >= 10) and (exists $ServicesBans{$service}{$ip}{'AlreadyInTheList'}) and ($ServicesBans{$service}{$ip}{'AlreadyInTheList'}>0)) { printf(" (%d Duplicate Ban attempts)\n", $ServicesBans{$service}{$ip}{'AlreadyInTheList'}) ; } } } } } if (keys %ServicesFound and $Detail>5) { printf("\nFail2Ban hosts found:\n"); foreach my $service (sort {$a cmp $b} keys %ServicesFound) { print(" $service:\n"); foreach my $ip (sort {$a cmp $b} keys %{$ServicesFound{$service}}) { my @name = split(/ /, LookupIP($ip)); printf(" %-15s (%3d Times)\n", "$ip", $ServicesFound{$service}{$ip}); if (scalar @name > 1) { printf(" %s\n", $name[1]); } } } } if (keys %ServicesIgnored and $Detail>5) { printf("\nFail2Ban hosts ignored:\n"); foreach my $service (sort {$a cmp $b} keys %ServicesIgnored) { print(" $service:\n"); foreach my $ip (sort {$a cmp $b} keys %{$ServicesIgnored{$service}}) { my @name = split(/ /, LookupIP($ip)); printf(" %-15s (%3d Times)\n", "$ip", $ServicesIgnored{$service}{$ip}); if (scalar @name > 1) { printf(" %s\n", $name[1]); } } } } if (keys(%ErrorList)) { print "\n** ERRORS **\n"; foreach my $line (sort {$a cmp $b} keys %ErrorList) { print " $line: $ErrorList{$line} Time(s)\n"; } } if (keys(%WarningList)) { print "\n** WARNINGS **\n"; foreach my $line (sort {$a cmp $b} keys %WarningList) { print " $line: $WarningList{$line} Time(s)\n"; } } if (keys %LatencyIssues) { printf("\nJails with latency issues:\n"); foreach my $service (sort {$a cmp $b} keys %LatencyIssues) { printf(" $service: %d Times\n", $LatencyIssues{$service}); } } if (keys(%InfoList) && $Detail>5) { print "\nInformational Messages:\n"; foreach my $line (sort {$a cmp $b} keys %InfoList) { print " $line: $InfoList{$line} Time(s)\n"; } } if (keys(%NoticeList) && $Detail>7) { print "\nNotices:\n"; foreach my $line (sort {$a cmp $b} keys %NoticeList) { print " $line: $NoticeList{$line} Time(s)\n"; } } if ($Detail>0) { if ($#IptablesErrors > 0) { printf("\n%d faulty iptables invocation(s)", $#IptablesErrors); if ($Detail > 5) { print ":\n"; print @IptablesErrors ; } } if ($#ActionErrors > 0) { printf("\n%d error(s) returned from actions", $#ActionErrors); if ($Detail > 5) { print ":\n"; print @ActionErrors ; } } if ($ReInitializations > 0) { printf("\n%d fail2ban rules reinitialization(s)", $ReInitializations); } } if (keys(%OtherList)) { print "\n**Unmatched Entries**\n"; foreach my $line (sort {$a cmp $b} keys %OtherList) { print " $line: $OtherList{$line} Time(s)\n"; } } exit(0); # vi: shiftwidth=3 tabstop=3 syntax=perl et # Local Variables: # mode: perl # perl-indent-level: 3 # indent-tabs-mode: nil # End: logwatch-7.12/scripts/services/pound0000664000211400021140000000760714274101042020034 0ustar logwatchlogwatch ######################################################## # Please file all bug reports, patches, and feature # requests under: # https://sourceforge.net/p/logwatch/_list/tickets # and copy: # luuk - luuk@planet.nl # Help requests and discusion can be filed under: # https://sourceforge.net/p/logwatch/discussion/ ######################################################## ######################################################## # This was written and is maintained by: # luuk - luuk@planet.nl # # Please send all comments, suggestions, bug reports, # etc, to luuk@planet.nl. # ######################################################## ####################################################### ## Copyright (c) 2008 Kirk Bauer ## Covered under the included MIT/X-Consortium License: ## http://www.opensource.org/licenses/mit-license.php ## All modifications and contributions by other persons to ## this script are assumed to have been donated to the ## Logwatch project and thus assume the above copyright ## and licensing terms. If you want to make contributions ## under your own copyright or a different license this ## must be explicitly stated in the contribution an the ## Logwatch project reserves the right to not accept such ## contributions. If you have made significant ## contributions to this script and want to claim ## copyright please contact logwatch-devel@lists.sourceforge.net. ######################################################### use strict; my $Debug = $ENV{'LOGWATCH_DEBUG'}; my $DoLookup = $ENV{'pound_ip_lookup'}; my $Detail = $ENV{'LOGWATCH_DETAIL_LEVEL'} || 0; #Init String Container my ($tmpcode, $tmphost); #Init Hashes my ( %OtherList, %error, %ip, %user ); $DoLookup = 1; sub LookupIP { my ($name, $a1, $a2,$a3,$a4,$PackedAddr,$Addr); $Addr = $_[0]; ($a1,$a2,$a3,$a4) = split /\./,$Addr; $PackedAddr = pack('C4',$a1,$a2,$a3,$a4); if ($DoLookup) { if ($name = gethostbyaddr ($PackedAddr,2)) { return ($name . " (" . $Addr . ")"); } else { return ($Addr); } } else { return ($Addr); } } if ( $Debug >= 5 ) { print STDERR "\n\nDEBUG: Inside Pound Filter \n\n"; } while (defined(my $ThisLine = )) { chomp($ThisLine); if ($ThisLine =~ /error read from ([\d|\.]+): Succes/) { $error{'read'}{$1}++; } elsif ($ThisLine =~ /([\d|\.]+) \w+ \S+ \S+ - \S+ 301 Unauthorized/) { $error{'unauthorized'}{$1}++; } elsif ($ThisLine =~ /([\d|\.]+) \w+ \/exchange\/([\w|\.]+)\/.* \S+/) { $user{$1}{$2}++; } elsif ($ThisLine =~ /([\d|\.]+) \w+ \/.* (\d\d\d .*?)$/) { $tmphost = $1; $tmpcode = $2; $ip{$tmphost}{'total'}++; $ip{$tmphost}{$tmpcode}++; } else { # Report any unmatched entries... $OtherList{$ThisLine}++; } } if ( ( $Detail >= 5 ) and (keys %user) ) { print "\nUsage by user:\n"; foreach my $host (keys %user) { my $rhost = LookupIP($host); print " $rhost:\n"; foreach my $usr (keys %{$user{$host}}) { print " $usr: $user{$host}{$usr}\n"; } } } if ( ( $Detail >= 10 ) and (keys %ip) ) { print "\nUsage by host:\n"; foreach my $host (keys %ip) { my $rhost = LookupIP($host); print " $rhost: $ip{$host}{'total'}\n"; foreach my $code (keys %{$ip{$host}}) { print " $code: $ip{$host}{$code}\n" if ($code ne 'total'); } } } if ( ( $Detail >= 5 ) and (keys %error) ) { print "\nError read from - Succes message:\n"; foreach my $host (keys %{$error{'read'}}) { my $rhost = LookupIP($host); print " $rhost: $error{'read'}{$host} \n"; } } if (keys %OtherList) { print "\n**Unmatched Entries**\n"; foreach my $line (sort {$a cmp $b} keys %OtherList) { print " $line: $OtherList{$line} Time(s)\n"; } } exit(0); # vi: shiftwidth=3 tabstop=3 syntax=perl et # Local Variables: # mode: perl # perl-indent-level: 3 # indent-tabs-mode: nil # End: logwatch-7.12/scripts/services/extreme-networks0000664000211400021140000003000514462364760022237 0ustar logwatchlogwatch ######################################################## # Please file all bug reports, patches, and feature # requests under: # https://sourceforge.net/p/logwatch/_list/tickets # and copy: # Laurent DUFOUR , # Help requests and discusion can be filed under: # https://sourceforge.net/p/logwatch/discussion/ ######################################################## ######################################################## # This was written and is maintained by: # Laurent DUFOUR , # based on the work of # Kirk Bauer ######################################################## ######################################################## ## Copyright (c) 2008 Laurent DUFOUR ## Covered under the included MIT/X-Consortium License: ## http://www.opensource.org/licenses/mit-license.php ## All modifications and contributions by other persons to ## this script are assumed to have been donated to the ## Logwatch project and thus assume the above copyright ## and licensing terms. If you want to make contributions ## under your own copyright or a different license this ## must be explicitly stated in the contribution an the ## Logwatch project reserves the right to not accept such ## contributions. If you have made significant ## contributions to this script and want to claim ## copyright please contact logwatch-devel@lists.sourceforge.net. ######################################################### use Logwatch ':all'; use strict; my $Debug = ValueOrDefault($ENV{'LOGWATCH_DEBUG'}, 0); my $Detail = ValueOrDefault($ENV{'LOGWATCH_DETAIL_LEVEL'}, 30); my $DebugCounter = 0; #Init Strings my ( $Temp, $config, $dst_ip, $interface, ); #Init Hashes my ( %BadLogins, %IllegalUsers, %NTPFailed, %NTPUpdated, %ReloadRequested, %Restarted, %SYST, %Started, %SysCfgSaved, %SysCfgSavedCompleted, %SyslogFacility, %SyslogHost, %Users, %UsersOut, ); #Init Arrays my @OtherList = (); # Avoid "Use of uninitialized value" warning messages. sub ValueOrDefault { my ($value, $default) = @_; return ($value ? $value : $default); } if ( $Debug >= 5 ) { print STDERR "\n\nDEBUG: Inside EXTREME NETWORKS Filter \n\n"; $DebugCounter = 1; } my ($month,$day,$time,$host_ip,$host,$conn,$msg,$message); while (defined(my $ThisLine = )) { if ( $Debug >= 30 ) { print STDERR "DEBUG($DebugCounter): $ThisLine"; $DebugCounter++; } ($month,$day,$time,$host,$msg)=split(/ +/,$ThisLine,6); if ( ($ThisLine =~ /traffic/ ) or ($ThisLine =~ /Copyright/ ) or ($ThisLine =~ /removed due to simultaneous rekey/ ) or ($ThisLine =~ /Responded to the first peer message/ ) or ($ThisLine =~ /NBR change/ ) or ($ThisLine =~ /accept udp/ ) or ($ThisLine =~ /accept tcp/ ) or ($ThisLine =~ /accept icmp/ ) or ($ThisLine =~ /accept ip/ ) or ($ThisLine =~ /denied udp/ ) or ($ThisLine =~ /denied tcp/ ) or ($ThisLine =~ /denied icmp/ ) or ($ThisLine =~ /denied ip/ ) ) { # don't care about this, will code this later } elsif ( ($config,$msg) = ($ThisLine =~ /SYST: Save to the (\S+) configuration completed/) ) { $SysCfgSavedCompleted{$host}{$config}++; } elsif ( ($dst_ip,$msg) = ($ThisLine =~ /SYST: (\d+\.\d+\.\d+\.\d+) admin: save (.*)/) ) { $SysCfgSaved{$host}{LookupIP($dst_ip)}++; } elsif ( ($ThisLine =~ /Compiled/) ) { $Started{$host}++; } elsif ( ($ThisLine =~ /Syslog host domain name has been changed/) ) { $SyslogHost{$host}++; } elsif ( ($ThisLine =~ /Syslog facility has been changed/) ) { $SyslogFacility{$host}++; } elsif ( ($ThisLine =~ /Syslog security facility has been changed/) ) { $SyslogFacility{$host}++; } elsif ( ($ThisLine =~ /The system clock has been updated through NTP./) ) { $NTPUpdated{$host}++; } elsif ( ($ThisLine =~ /failed to get clock through NTP/) ) { $NTPFailed{$host}++; } elsif ( ($message) = ($ThisLine =~ /RELOAD: (.*)/) ) { $ReloadRequested{$host}{$message}++; } elsif ( ($message) = ($ThisLine =~ /RESTART: (.*)/) ) { $Restarted{$host}{$message}++; } elsif ( ($interface) = ($ThisLine =~ /(\S+) logged in through (\S+) \((\d+\.\d+\.\d+\.\d+)\)/) ) { if ($Debug >= 5) { print STDERR "DEBUG: Found -$1 logged in from $3 using $2\n"; } if ($Detail >= 20) { $Users{$host}{$2}{$3}{$1}++; } else { $Users{$host}{$2}{$3}{"(all)"}++; } } elsif ( ($interface) = ($ThisLine =~ /SYST: User (\S+) logged out from (\S+) \((\d+\.\d+\.\d+\.\d+)\)/) ) { if ($Debug >= 5) { print STDERR "DEBUG: Found -$1 logged out from $3 using $2\n"; } if ($Detail >= 20) { $UsersOut{$host}{$2}{$3}{$1}++; } else { $UsersOut{$host}{$2}{$3}{"(all)"}++; } } elsif ( $ThisLine =~ m/Admin user (\S+) login attempt for (\S+) management \(port (\d+)\) from (.+):(.+). failed. (.*)/ ) { if ( $Debug >= 5 ) { print STDERR "DEBUG: Found -Failed login- line\n"; } my $name = LookupIP($4); $BadLogins{$host}{"$1/$2 from $name"}++; } elsif ( $ThisLine =~ m/SSH client at (.+) has attempted to make an SCS connection to interface untrust with IP (.+) but failed (.*)/ ) { my $name = LookupIP($2); $Temp = "SSH from $name"; $BadLogins{$host}{$Temp}++; $IllegalUsers{$host}{$Temp}++; } elsif ( ($message) = ($ThisLine =~ /SYST: (.*)/) ) { $SYST{$host}{$message}++; } else { # Report any unmatched entries... push @OtherList,$ThisLine; } } if (keys %Started) { print "\nDevice started :\n"; foreach my $ThisOne (keys %Started) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (keys %{$Started{$ThisOne}}) { print "\t Started" .$ThatOne . "\t: " . $Started{$ThisOne}{$ThatOne} . "{ Time(s)\n"; } } } if (keys %SYST) { print "\nDevice where system command where used :\n"; foreach my $ThisOne (keys %SYST) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (keys %{$SYST{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $SYST{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if (keys %NTPUpdated) { print "\nDevice where The system clock has been updated through NTP :\n"; foreach my $ThisOne (keys %NTPUpdated) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (keys %{$NTPUpdated{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $NTPUpdated{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if (keys %NTPFailed) { print "\nDevice where failed to get clock through NTP :\n"; foreach my $ThisOne (keys %NTPFailed) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (keys %{$NTPFailed{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $NTPFailed{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if (keys %SyslogFacility) { print "\nDevice where Syslog facility has been changed :\n"; foreach my $ThisOne (keys %SyslogFacility) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (keys %{$SyslogFacility{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $SyslogFacility{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if (keys %SyslogHost) { print "\nDevice where Syslog host has been changed :\n"; foreach my $ThisOne (keys %SyslogHost) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (keys %{$SyslogHost{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $SyslogHost{$ThisOne}{$ThisOne} . " Time(s)\n"; } } } if (keys %Restarted) { print "\nDevice restarted :\n"; foreach my $ThisOne (keys %Restarted) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (keys %{$Restarted{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $Restarted{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if (keys %ReloadRequested) { print "\nDevice reload requested :\n"; foreach my $ThisOne (keys %ReloadRequested) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (keys %{$ReloadRequested{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $ReloadRequested{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if (keys %SysCfgSaved) { print "\nDevice where system config have been saved :\n"; foreach my $ThisOne (keys %SysCfgSaved) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (keys %{$SysCfgSaved{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $SysCfgSaved{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if (keys %SysCfgSavedCompleted) { print "\nDevice where system config have been completely saved :\n"; foreach my $ThisOne (keys %SysCfgSavedCompleted) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (keys %{$SysCfgSavedCompleted{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $SysCfgSavedCompleted{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if (keys %BadLogins) { print "\nFailed logins from these:\n"; foreach my $ThisOne (keys %BadLogins) { print " " . $ThisOne . ":\n"; for (sort keys %{$BadLogins{$ThisOne}}) { print "\t $_: $BadLogins{$ThisOne}{$_} Time(s)\n"; } } } if (keys %IllegalUsers) { print "\nIllegal users from these:\n"; foreach my $ThisOne (keys %IllegalUsers) { print " " . $ThisOne . ":\n"; for (sort keys %{$IllegalUsers{$ThisOne}}) { print "\t $_: $IllegalUsers{$ThisOne}{$_} Time(s)\n"; } } } if (keys %Users) { print "\nUsers logging in through :\n"; foreach my $ThisOne (keys %Users) { print " " . $ThisOne . ":\n"; foreach my $user (sort {$a cmp $b} keys %{$Users{$ThisOne}}) { print " $user:\n"; my $totalSort = TotalCountOrder(%{$Users{$ThisOne}{$user}}, \&SortIP); foreach my $ip (sort $totalSort keys %{$Users{$ThisOne}{$user}}) { my $name = LookupIP($ip); if ($Detail >= 20) { print " $name:\n"; my $sort = CountOrder(%{$Users{$ThisOne}{$user}{$ip}}); foreach my $method (sort $sort keys %{$Users{$ThisOne}{$user}{$ip}}) { my $val = $Users{$ThisOne}{$user}{$ip}{$method}; my $plural = ($val > 1) ? "s" : ""; print " $method: $val time$plural\n"; } } else { my $val = (values %{$Users{$ThisOne}{$user}{$ip}})[0]; my $plural = ($val > 1) ? "s" : ""; print " $name: $val time$plural\n"; } } } } } if (keys %UsersOut) { print "\nUsers logging out through :\n"; foreach my $ThisOne (keys %UsersOut) { print " " . $ThisOne . ":\n"; foreach my $user (sort {$a cmp $b} keys %{$UsersOut{$ThisOne}}) { print " $user:\n"; my $totalSort = TotalCountOrder(%{$UsersOut{$ThisOne}{$user}}, \&SortIP); foreach my $ip (sort $totalSort keys %{$UsersOut{$ThisOne}{$user}}) { my $name = LookupIP($ip); if ($Detail >= 20) { print " $name:\n"; my $sort = CountOrder(%{$UsersOut{$ThisOne}{$user}{$ip}}); foreach my $method (sort $sort keys %{$UsersOut{$ThisOne}{$user}{$ip}}) { my $val = $UsersOut{$ThisOne}{$user}{$ip}{$method}; my $plural = ($val > 1) ? "s" : ""; print " $method: $val time$plural\n"; } } else { my $val = (values %{$UsersOut{$ThisOne}{$user}{$ip}})[0]; my $plural = ($val > 1) ? "s" : ""; print " $name: $val time$plural\n"; } } } } } if ($#OtherList >= 0) { print "\n**Unmatched Entries**\n"; print @OtherList; } exit(0); # vi: shiftwidth=3 tabstop=3 syntax=perl et # Local Variables: # mode: perl # perl-indent-level: 3 # indent-tabs-mode: nil # End: logwatch-7.12/scripts/services/systemd0000664000211400021140000004536114743365005020412 0ustar logwatchlogwatch ######################################################## # Please file all bug reports, patches, and feature # requests under: # https://sourceforge.net/p/logwatch/_list/tickets # Help requests and discusion can be filed under: # https://sourceforge.net/p/logwatch/discussion/ ######################################################## ######################################################## ## Copyright (c) 2016 Orion Poplawski ## Covered under the included MIT/X-Consortium License: ## http://www.opensource.org/licenses/mit-license.php ## All modifications and contributions by other persons to ## this script are assumed to have been donated to the ## Logwatch project and thus assume the above copyright ## and licensing terms. If you want to make contributions ## under your own copyright or a different license this ## must be explicitly stated in the contribution an the ## Logwatch project reserves the right to not accept such ## contributions. If you have made significant ## contributions to this script and want to claim ## copyright please contact logwatch-devel@lists.sourceforge.net. ######################################################### use strict; my $Detail = $ENV{'LOGWATCH_DETAIL_LEVEL'} || 0; my $Ignore_failed = $ENV{'ignore_failed'} || ""; my $Ignore_leftover = $ENV{'ignore_leftover'} || ""; my %ConfigError; my %Activated; my %Failed; my %Deactivated; my %LeftOver; my %NotStopped; my $Reexecuted = 0; my %ReexecutedRequested; my %Reloaded; my %Skipped; my %Slice; my %Slow; my %Started; my %Target; my $TimeChanged = 0; my $LastTarget; my %UserSession; my %OtherList; #init String Containers my ( $Exe, $Service, $name, $pidfile, $reason, $service, $session, $target, $user, ); # Failure will generate multiple messages like: # EL7: # Feb 5 16:37:50 hostname systemd: ansible-pull.service: main process exited, code=exited, status=2/INVALIDARGUMENT # Feb 5 16:37:50 hostname systemd: Failed to start Run ansible-pull on boot. # Feb 5 16:37:50 hostname systemd: Unit ansible-pull.service entered failed state. # Feb 5 16:37:50 hostname systemd: ansible-pull.service failed. # EL8: # Feb 5 16:37:50 hostname systemd[1]: ansible-pull.service: Main process exited, code=exited, status=2/INVALIDARGUMENT # Feb 5 16:37:50 hostname systemd[1]: ansible-pull.service: Failed with result 'exit-code'. while (defined(my $ThisLine = )) { chomp($ThisLine); if ($ThisLine =~ /^(Activat|Deactivat|Expect|Mount|Unmount|Reload|Start|Stopp)ing / or $ThisLine =~ /^Finished / or # sssd users @ in usernames $ThisLine =~ /^Accepting user\/group name '.*\@.*', which does not match strict user\/group name rules\.$/ or # These events will be caught with the Failed with or failed message $ThisLine =~ /^Failed to start / or $ThisLine =~ /Failed to .* socket / or $ThisLine =~ /Failed at step / or $ThisLine =~ /([Cc]ontrol|[Mm]ain|[Mm]ount|[Ss]wap) process exited, code=(exited|killed|dumped),? status=/ or $ThisLine =~ /^Timed out / or $ThisLine =~ /^Unit.* entered failed state\.$/ or # Informational $ThisLine =~ /^(?:bpf-lsm: )?LSM BPF program attached/ or $ThisLine =~ /^Closed .*\.$/ or $ThisLine =~ /: Consumed .+? CPU time/ or # crond will never restart process when it is restarted $ThisLine =~ /^crond\.service: Found left-over process \d+ \(.*\) in control group while starting unit\. Ignoring\.$/ or $ThisLine =~ /Current command vanished from the unit file, execution of the command list won't be resumed/ or $ThisLine =~ /^Received SIGINT\./ or $ThisLine =~ /^Detected (architecture|virtualization) / or # Spurious warning - should be fixed in later systemd (EL8.4) $ThisLine =~ /^Failed to connect to API bus: Connection refused/ or # Extransous scope messages with LanSweeper - revisit with EL8.4 $ThisLine =~ /: Failed to add PIDs to scope's control group: No such process/ or $ThisLine =~ /\.scope: Couldn't move process \d+ to requested cgroup '.*': No such process/ or $ThisLine =~ /scope: Failed with result 'resources'/ or $ThisLine =~ /session-[[:xdigit:]]+\.scope: Deactivated successfully\./ or $ThisLine =~ /^Found device / or $ThisLine =~ /Found dependency on / or $ThisLine =~ /Got automount request for \/proc\// or $ThisLine =~ /^Hostname set to / or $ThisLine =~ /^Inserted module / or $ThisLine =~ /^Listening on / or $ThisLine =~ /^Mounted / or $ThisLine =~ /^Queued start job for default target / or $ThisLine =~ /^Queuing reload/ or $ThisLine =~ /^Relabell?ed / or $ThisLine =~ /^Reloading\.+$/ or # Happens on each boot at switch root $ThisLine =~ /^RTC configured in / or $ThisLine =~ /^Running in init(?:ial RAM disk|rd)\.$/ or $ThisLine =~ /^selinux: avc: *received policyload notice/ or $ThisLine =~ /^selinux: avc: *op=load_policy / or $ThisLine =~ /^Set hostname to / or $ThisLine =~ /^(?:Set up|Unset) automount.*Arbitrary Executable File Formats File System Automount Point\.$/ or $ThisLine =~ /^Shutting down\.$/ or $ThisLine =~ /^Startup finished in / or $ThisLine =~ /^Stopped / or $ThisLine =~ /^Switching root\.$/ or $ThisLine =~ /: Succeeded\.$/ or $ThisLine =~ /^Successfully loaded SELinux policy in / or $ThisLine =~ /already active, refusing\./ or $ThisLine =~ /^Failed to propagate agent release message:/ or $ThisLine =~ /: Supervising process .* which is not our child\. We'll most likely not notice when it exits\.$/ or $ThisLine =~ /: Got notification message from PID \d+, but reception is disabled\./ or $ThisLine =~ /: Got notification message from PID \d+, but reception only permitted for main PID \d+/ or $ThisLine =~ /Cannot find unit for notify message of PID \d+/ or $ThisLine =~ /^systemd .* running in system mode/ or # This is preceeded by a more descriptive message $ThisLine =~ /^This usually indicates unclean termination of a previous run, or service implementation deficiencies\.$/ or $ThisLine =~ /Transaction (for .*)?is destructive/ or $ThisLine =~ /^Unit .* is bound to inactive unit .*\. Stopping, too\./ or $ThisLine =~ /Unit (.* is )?not needed anymore\. Stopping\./ or $ThisLine =~ /[Ss]tart(-pre)? operation timed out\. Terminating\./ or $ThisLine =~ /Job .* timed out\./ or $ThisLine =~ /[Ss]top.* timed out\. Killing\./ or $ThisLine =~ /hold-?off time over, scheduling restart\./ or $ThisLine =~ /has no hold-off time.*, scheduling restart\./ or $ThisLine =~ /Service Restart.* expired, scheduling restart\./ or $ThisLine =~ /Scheduled restart job, restart counter is at .*\./ or $ThisLine =~ /: Watchdog timeout/ or $ThisLine =~ /Watchdog running with a (?:hardware )?timeout of/ or $ThisLine =~ /^Dependency failed for / or # This is preceeded by a more descriptive message $ThisLine =~ / Triggering OnFailure= dependencies\./ or $ThisLine =~ /Processes still around after .*SIGKILL\./ or $ThisLine =~ /^Unmounted / or $ThisLine =~ /: Unit is bound to inactive unit / or $ThisLine =~ /[Hh]ardware watchdog / or # This is now trapped as a Slow Start error #$ThisLine =~ /PID file .* not readable \(yet\?\) after start/ or $ThisLine =~ /Failed to (read|parse) PID from file / or # Units can depend on files that do not exist $ThisLine =~ /Cannot add dependency job(:? for unit .*)?, ignoring: Unit (:?.* failed to load: No such file or directory|not found)\.$/ or # https://bugs.freedesktop.org/show_bug.cgi?id=90386 $ThisLine =~ /Dev(ice)? .* appeared twice with different sysfs paths .* and / or # Inactive units are sometimes reloaded $ThisLine =~ /^Unit .* cannot be reloaded because it is inactive\.$/ or $ThisLine =~ /^.*: Unit cannot be reloaded because it is inactive\.$/ or $ThisLine =~ / is not active\.$/ or $ThisLine =~ / is inactive\.$/ or # https://bugzilla.redhat.com/show_bug.cgi?id=1306452 $ThisLine =~ /^[^ ]*\.mount: Directory \/[^ ]* to mount over is not empty, mounting anyway\.$/ or # A known issue - reported by multiple distributions $ThisLine =~ /^user\@\d+\.service: Failed at step CGROUP spawning \/usr\/lib\/systemd\/systemd: No such file or directory$/ or $ThisLine =~ /^Received SIGRTMIN\+2[01] from PID \d+ \((?:plymouthd|n\/a)\)\.$/ or # https://bugzilla.redhat.com/show_bug.cgi?id=1072368 $ThisLine =~ /^Received SIGRTMIN\+24 from PID \d+ \((?:kill|n\/a)\)\.$/ or $ThisLine =~ /: Killing process \d+ \(.*\) with signal SIG.+\.$/ or $ThisLine =~ /: Sent signal SIGHUP to main process .* on client request\.$/ or $ThisLine =~ /^Removed slice / or $ThisLine =~ /^pam_unix\(systemd-user:session\): session (?:opened|closed) for user/ or $ThisLine =~ /Adding .* random time\.$/ or # https://bugzilla.redhat.com/show_bug.cgi?id=1890632 $ThisLine =~ /Not generating service for XDG autostart .*,/ or $ThisLine =~ /gnome-systemd-autostart-condition not found/ or $ThisLine =~ /kde-systemd-start-condition not found/ or $ThisLine =~ /Unknown key name .* in section 'Desktop Entry'/ or # These happen on every shutdown - downgraded to debug message in systemd v235 # https://github.com/systemd/systemd/issues/6777 $ThisLine =~ /^Failed to propagate agent release message: (?:Connection reset by peer|Transport endpoint is not connected)/ or $ThisLine =~ /^cgroup compatibility translation between legacy and unified hierarchy settings activated\. See cgroup-compat debug messages for details\.$/ or $ThisLine =~ /^\(This warning is only shown for the first unit using IP firewalling\.\)$/ or $ThisLine =~ /^.*\.socket: Socket service .* already active/ ) { # Ignore these } elsif (($service,$reason) = ($ThisLine =~ /^Configuration file ([^ ]*) is ([^.]*)\./)) { $ConfigError{$reason}{$service}++; } elsif (($service,$reason) = ($ThisLine =~ /^\[(.*)\] (Support for option .* has been removed) and it is ignored/)) { $ConfigError{$reason}{$service}++; } elsif (($service,$reason) = ($ThisLine =~ /^(.*):\d+: (.* is obsolete, .*)\. /)) { $ConfigError{$reason}{$service}++; } elsif (($service,$reason) = ($ThisLine =~ /^(.*):\d+: (.* this is not safe!)/)) { $ConfigError{$reason}{$service}++; } elsif (($service,$reason) = ($ThisLine =~ /^(.*):\d+: (PIDFile= references a path below legacy directory .*), /)) { $ConfigError{$reason}{$service}++; } elsif (($service,$reason) = ($ThisLine =~ /^\[?([^\]:]+(?::\d+)?)[\]:]? (Unknown .* in section '.*')/)) { $ConfigError{$reason}{$service}++; } elsif (($service,$reason) = ($ThisLine =~ /^(.*): (unit configures an IP firewall, but not running as root)\.$/)) { $ConfigError{$reason}{$service}++; } elsif (($service,$reason) = ($ThisLine =~ /^(bpf-lsm): (.*)$/)) { $ConfigError{$reason}{$service}++; } elsif (($reason,$service) = ($ThisLine =~ /^((BPF LSM) .*, LSM BPF not supported)$/)) { $ConfigError{$reason}{$service}++; } elsif (($reason,$service) = ($ThisLine =~ /^(ConfigurationDirectory .*)\. \((.*)\)$/)) { $ConfigError{$reason}{$service}++; } elsif (($reason,$service) = ($ThisLine =~ /^(System is tainted): (.*)$/)) { $ConfigError{$reason}{$service}++; # Skipped goes before failed to catch "was skipped because all trigger condition checks failed." } elsif (($name) = ($ThisLine =~ /^Condition check resulted in (.*) being skipped\.$/)) { $Skipped{$name}++ if $Detail; } elsif (($name) = ($ThisLine =~ /^(.*): Skipped due to /)) { $Skipped{$name}++ if $Detail; } elsif (($name) = ($ThisLine =~ /^(.*) was skipped because/)) { $Skipped{$name}++ if $Detail; } elsif (($service) = ($ThisLine =~ /(\S+): Failed (:?to execute command|with result)/)) { $Failed{$service}++; } elsif (($service) = ($ThisLine =~ /(\S+) failed\.$/)) { $Failed{$service}++; } elsif (($service) = ($ThisLine =~ /^(.*) failed with ((error code)|(exit status)) \d+\.$/)) { $Failed{$service}++; } elsif (($service) = ($ThisLine =~ /^(.*): Start request repeated too quickly\.$/)) { $Failed{$service}++; } elsif (($service) = ($ThisLine =~ /^(.*): Job .* failed with result/)) { $Failed{$service}++; } elsif (($service) = ($ThisLine =~ /^Job (.*) failed with result/)) { $Failed{$service}++; } elsif (($service) = ($ThisLine =~ /^Failed (unmounting .*)\.$/)) { $Failed{$service}++; } elsif (($service) = ($ThisLine =~ /^Failed to (listen on .*)\.$/)) { $Failed{$service}++; } elsif (($target) = ($ThisLine =~ /^Reached target (.*)\.$/)) { $Target{$target}++; $LastTarget = $target; } elsif (($session, $user) = ($ThisLine =~ /^Started (?:session-[[:xdigit:]]+\.scope - )?Session ([[:xdigit:]]+) of [uU]ser (.*)\.$/)) { $UserSession{$user}->{$session}++; } elsif (($service) = ($ThisLine =~ /^Activated (.*)\.$/)) { $Activated{$service}++; } elsif (($service) = ($ThisLine =~ /^Started (.*)\.$/)) { $Started{$service}++; } elsif (($service) = ($ThisLine =~ /^Reloaded (.*)\.$/)) { $Reloaded{$service}++; } elsif (($service) = ($ThisLine =~ /^Deactivated (.*)\.$/)) { $Deactivated{$service}++; } elsif (($service) = ($ThisLine =~ /(.*): Deactivated /)) { $Deactivated{$service}++; } elsif ($ThisLine eq "Reexecuting.") { $Reexecuted++ if $Detail; } elsif ($ThisLine =~ "Reexecuting requested from client (.*)") { $ReexecutedRequested{$1}++ if $Detail; } elsif ($ThisLine =~ /^Time has been changed$/) { $TimeChanged++; } elsif (my ($slice) = ($ThisLine =~ /^Created slice (.*)\.$/)) { $Slice{$slice}++; } elsif (($pidfile) = ($ThisLine =~ /^PID file (.*) not readable \(yet\?\) after start\.$/)) { $Slow{$pidfile}++; } elsif (($pidfile) = ($ThisLine =~ /Can't open PID file (.*) \(yet\?\) after start:/)) { $Slow{$pidfile}++; } elsif (($Service, $Exe) = ($ThisLine =~ /^(.*): Found left-over process \d+ \((.*)\) in control group while starting unit\. Ignoring\.$/)) { $LeftOver{"$Service:$Exe"}++ unless "$Service:$Exe" =~/^$Ignore_leftover$/i; } elsif (($Service, $Exe) = ($ThisLine =~ /^(.*): Unit process \d+ \((.*)\) remains running after unit stopped\.$/)) { $NotStopped{"$Service:$Exe"}++ unless "$Service:$Exe" =~/^$Ignore_leftover$/i; } else { $OtherList{$ThisLine}++; } } if (keys %ConfigError) { print "Configuration errors:\n"; foreach my $reason (sort {$a cmp $b} keys %ConfigError) { my $tot = 0; print " $reason"; foreach my $service (sort {$a cmp $b} keys %{$ConfigError{$reason}}) { $tot += $ConfigError{$reason}{$service}; if ($Detail >= 10) { print "\n $service: $ConfigError{$reason}{$service} Time(s)"; } } if ($Detail < 10) { print ": $tot Time(s)" } print "\n"; } print "\n"; } # Because we set Failed in multiple locations, cleanup once here foreach my $item (keys %Failed) { delete $Failed{$item} if ($item =~ /^$Ignore_failed$/i); } if (keys %Failed) { print "ERROR: Failed state:\n"; foreach my $item (sort {$a cmp $b} keys %Failed) { print " $item: $Failed{$item} Time(s)\n"; } print "\n"; } # Detail >= 1 if ($Reexecuted) { if (keys %ReexecutedRequested) { print "Reexecuted sytemd requested by:\n"; foreach my $item (sort {$a cmp $b} keys %ReexecutedRequested) { print " $item: $ReexecutedRequested{$item} Time(s)\n"; } print "\n"; } else { print "Reexecuted systemd: $Reexecuted Time(s)\n\n"; } } if (keys %Skipped) { print "Condition check resulted in the following being skipped:\n"; foreach my $item (sort {$a cmp $b} keys %Skipped) { print " $item: $Skipped{$item} Time(s)\n"; } print "\n"; } if (keys %LeftOver) { print "Warning: Found left-over process in control group while starting unit:\n"; foreach my $item (sort {$a cmp $b} keys %LeftOver) { my ($service, $exe) = split(":", $item); print " $service($exe): $LeftOver{$item} Time(s)\n"; } print "\n"; } if (keys %NotStopped) { print "Warning: Remained running after unit stopped:\n"; foreach my $item (sort {$a cmp $b} keys %NotStopped) { my ($service, $exe) = split(":", $item); print " $service($exe): $NotStopped{$item} Time(s)\n"; } print "\n"; } if (keys %Target && $Detail > 3) { print "Reached target $LastTarget: $Target{$LastTarget} Time(s)"; if ($Detail > 10) { print ", and:\n"; foreach my $target (sort {$a cmp $b} keys %Target) { print " $target: $Target{$target} Time(s)\n"; } } else { print "\n"; } print "\n"; } if (keys %Started && $Detail > 3) { print "Started:\n"; foreach my $started (sort {$a cmp $b} keys %Started) { print " $started: $Started{$started} Time(s)\n"; } print "\n"; } if (keys %Activated && $Detail > 3) { print "Activated:\n"; foreach my $item (sort {$a cmp $b} keys %Activated) { print " $item: $Activated{$item} Time(s)\n"; } print "\n"; } if (keys %Slow && $Detail > 3) { print "Slow to start:\n"; foreach my $pidfile (sort {$a cmp $b} keys %Slow) { print " $pidfile: $Slow{$pidfile} Time(s)\n"; } print "\n"; } if (keys %Reloaded && $Detail > 5) { print "Reloaded:\n"; foreach my $item (sort {$a cmp $b} keys %Reloaded) { print " $item: $Reloaded{$item} Time(s)\n"; } print "\n"; } if (keys %Deactivated && $Detail > 5) { print "Deactivated:\n"; foreach my $item (sort {$a cmp $b} keys %Deactivated) { print " $item: $Deactivated{$item} Time(s)\n"; } print "\n"; } if ($TimeChanged && $Detail > 5) { print "Time Changed: $TimeChanged Time(s)\n\n"; } if (keys %UserSession && $Detail > 3) { print "User Sessions:\n"; foreach my $user (sort {$a cmp $b} keys %UserSession) { print " $user: "; if ($Detail >= 10) { foreach my $session (sort {$a cmp $b} keys %{$UserSession{$user}}) { print " $session"; } print "\n"; } else { print scalar(keys %{$UserSession{$user}}) . ": Time(s)"; } print "\n"; } } if (keys %Slice && $Detail > 5) { print "Slices created:\n"; foreach my $slice (sort {$a cmp $b} keys %Slice) { print " $slice: $Slice{$slice} Time(s)\n"; } print "\n"; } if (keys %OtherList) { print "\n\n**Unmatched Entries**\n"; foreach my $line (sort {$a cmp $b} keys %OtherList) { print " $line: $OtherList{$line} Time(s)\n"; } } exit(0); # vi: shiftwidth=3 tabstop=3 syntax=perl et # Local Variables: # mode: perl # perl-indent-level: 3 # indent-tabs-mode: nil # End: logwatch-7.12/scripts/services/sendmail0000664000211400021140000027467114743365005020526 0ustar logwatchlogwatch ######################################################## # Please file all bug reports, patches, and feature # requests under: # https://sourceforge.net/p/logwatch/_list/tickets # Help requests and discusion can be filed under: # https://sourceforge.net/p/logwatch/discussion/ ######################################################## ####################################################### ## Copyright (c) 2008 Kirk Bauer ## Covered under the included MIT/X-Consortium License: ## http://www.opensource.org/licenses/mit-license.php ## All modifications and contributions by other persons to ## this script are assumed to have been donated to the ## Logwatch project and thus assume the above copyright ## and licensing terms. If you want to make contributions ## under your own copyright or a different license this ## must be explicitly stated in the contribution an the ## Logwatch project reserves the right to not accept such ## contributions. If you have made significant ## contributions to this script and want to claim ## copyright please contact logwatch-devel@lists.sourceforge.net. ######################################################### use diagnostics; use strict; use Logwatch ':sort'; use Errno; use POSIX qw(strerror); # PrettyHost decomposes host names and IP addresses and # formats them to align vertically sub PrettyHost { # $_[0] is the line to format my $Line = $_[0]; # $_[1] is the length available my $LineLength = $_[1]; # if ((not defined $main::sendmail_prettyhost) or ($main::sendmail_prettyhost == 0)) { return($Line); } my ($Name, $Addr, $Other) = ($Line =~ /^\s*(.*?)\s*(\[[\d\.:]*\])\s*(.*?)\s*$/); if (index($Line, "\[") < 0) { $Name = $Line; } if (not defined $Name) {$Name=""}; if (not defined $Addr) {$Addr=""}; if (not defined $Other) {$Other=""}; if ($Other ne "") { $Name = $Name . " " . $Other; } # From LineLength, we will use 18 chars for one space # and a full IPv4 address if (length($Line) > $LineLength) { while ((length($Name) > $LineLength-21) and (($Name =~ tr/\./\./) > 1) ) { $Name =~ s/[^\.]*\.(.*)/$1/; } $Name = "..." . $Name; } sprintf ("%*s %-17s", 18-$LineLength, $Name, $Addr); } # PrettyTimes simply formats the lines with counts "Time(s)" to # align with the results of the PrettyHost routine sub PrettyTimes { # $_[0] is the event to format (string) my $Line = $_[0]; # $_[1] is the number of times it occurs (integer) my $Amount = $_[1]; # if ((not defined $main::sendmail_prettyprint) or ($main::sendmail_prettyprint == 0)) { printf "\n%s: %d Time%s", $Line, $Amount, ($Amount == 1) ? "" : "s"; } else { my $line_length = 72-length($Line); printf "\n%s %*d Time%s", $Line, ($line_length > 0)? $line_length : 0, $Amount, ($Amount == 1) ? "" : "s"; } return 0; } my $LogwatchDetail = $ENV{'LOGWATCH_DETAIL_LEVEL'} || 0; my $Debug = $ENV{'LOGWATCH_DEBUG'} || 0; my $sendmail_milterheaderstocount = $ENV{'sendmail_milterheaderstocount'} || ""; my @MilterHeadersToCount = split(/\|/, $sendmail_milterheaderstocount); my $MatchFilter = $ENV{'sendmail_matchfilter'} || ""; my $ReportFilter = $ENV{'sendmail_reportfilter'} || ""; # Extract formatting directives. If Sendmail_PrettyHost is set, # assume that Sendmail_PrettyPrint is also desired our $sendmail_prettyhost = $ENV{'sendmail_prettyhost'}; if (not defined $sendmail_prettyhost) {$sendmail_prettyhost = 1}; our $sendmail_prettyprint = $ENV{'sendmail_prettyprint'}; if ((not defined $sendmail_prettyprint) || $sendmail_prettyhost) {$sendmail_prettyprint = 1}; my $Detail = $ENV{'sendmail_detail'}; if (not defined $Detail) { print "\n\nDetail Level of output is inherited from conf/logwatch.conf." if $Debug; $Detail = $LogwatchDetail; } else { print "\n\nUsing Detail Level = $Detail from conf/services/sendmail.conf" if $Debug; } #print "\nSee file conf/services/sendmail.conf on how to customize output."; # The following variables are auto-increment counts, so are initialized my $AddrRcpts = my $BytesTransferred = my $CantCreateOutput = my $DaemonThrottle = my $Errno = my $LoadAvgQueueSkip = my $LoadAvgReject = my $MsgsNoRcpt = my $MsgsSent = my $NoMilterFilters = my $NoMoreSpace = my $OutdatedAliasdb = my $OverSize = my $OverSizeBytes = my $RelayLocalhost = my $RemoteProtocolError =my $SendmailStarts = my $SendmailStopped = my $TLSPeerReset = my $TooManyRcpts = my $XS4ALL = 0; # The following variables are always initialized before usage, so they are merely declared here. # (Someday it might be useful to reduce their scope, but most of them are used in the large # if..elsif structure, making that hard. my ( $Address, $Arg, $Attack, $Auth, $BlSite, $Bytes, $CommonName, $DeliverStat, $Dest, $DetailReason, $Domain, $Error, $ErrorCount, $ETRN, $File, $Forward, $FromUser, $Header, $HeaderMod, $Host, $IP, $LastIndex, $LastIndex2, $Load, $Luser, $MailerName, $MailerString, $MailerType, $NewQueueID, $NoCommonName, $NumRcpts, $Owner, $OtherListFound, $QueueID, $Reason, $RejCmd, $Relay, $RelayDeniedCount, $RelayHost, $RelayName, $Ruser, $Size, $Source, $StarttlsCipherEntry, $StarttlsCipherType, $StarttlsMode, $StarttlsNumBits, $StarttlsReason, $StarttlsVerify, $StatError, $StatFile, $Temp, $Temp1, $ThisLine, $ThisOne, $TimeoutSend, $TimeoutSendWarning, $TLSFile, $TLSFrom, $TLSReason, $TotalBytes, $TotalNum, $ToUser, $User, $Usr, $Warning, $Directory, $Cause ); # The following arrays and hashes need to have file-wide scopes my @SizeDist; my ( %Abuse, %AddressError, %AttackAttempt, %AUTHfailure, %AUTHnouser, %AuthWarns, %BadAuth, %BadRcptThrottle, %BlackHoled, %BlackHoles, %CheckMailReject, %CheckRcptReject, %CollectError, %CommandUnrecognized, %DisabledMailbox, %DNSMap, %DomainErrors, %DummyConnection, %ETRNs, %ForwardErrors, %KnownSpammer, %LargeHdrs, %LargeMsgs, %LastCmd, %LoadAvg, %LostInputChannel, %LostQueueFile, %LowSpace, %MailBomber, %MailBomberConn, %Mailers, %MailRejected, %MilterDeferrals, %MilterErrors, %MilterHeaderCount, %Msgs, %NotLocal, %OtherList, %PREGreeting, %PREGreetingQueue, %Quarantined, %RelayDenied, %RelayReject, %ReturnReceipts, %RuleSets, %SaslError, %SenderIDResults, %SentTimeouts, %SortedUsers, %SPFResults, %Starttls, %StarttlsCert, %StarttlsCipher, %StatDeferred, %StatFileError, %StatRejected, %StatRejectedLog, %SysErr, %Timeouts, %TLSAcceptFailed, %TLSConnectFailed, %TLSErrno, %TLSFileMissing, %ToList, %TooManyHops, %UnknownUsers, %UnknownUsersCheckRcpt, %WUnsafe ); # Initialize $SizeDist array for my $i (0..9) { $SizeDist[$i]{'Num'} = 0; $SizeDist[$i]{'Bytes'} = 0; } # QueueID formats: in 8.11 it was \w{7}\d{5}, in 8.12+ it is \w{8}\d{6} # Also, PID can now be up to seven digits in 64-bit systems my $QueueIDFormat = "(?:\\w{7,9}\\d{5,7}|NOQUEUE)"; # ENOENT refers to "no such file or directory" my $ENOENT = Errno::ENOENT(); while (defined($ThisLine = )) { # not all log entries have a queue id ($QueueID) = ($ThisLine =~ /^($QueueIDFormat): /o ); if (defined $QueueID) {$ThisLine =~ s/^$QueueID: //;} # $MatchFilter is a variable that is set by setting the $Sendmail_MatchFilter variable # in the conf/services/sendmail.conf file. It is executed here, before any other # matching statements eval $MatchFilter; if ($@) { print $@; print "While processing MatchFilter:\n$MatchFilter\n"; } # $ThisLine might have been reset (undef, or empty string) in $MatchFilter next unless $ThisLine; if ( # informational statements of little value # file=alias.c, LogLevel>7, LOG_NOTICE ( $ThisLine =~ /^alias database [^ ]* (auto)?rebuilt by/ ) or # file=alias.c, LogLevel>7, LOG_INFO ( $ThisLine =~ /[0-9]* aliases, longest [0-9]* bytes, [0-9]* bytes total/ ) or # file=util.c, LogLevel>9, LOG_INFO ( $ThisLine =~ /^started as: / ) or # file=daemon.c, LogLevel>8, LOG_INFO ( $ThisLine =~ /accepting new messages \(again\)/ ) or # the following is captured later, as detailed info is also printed # file=collect.c, LogLevel>1, LOG_WARNING ( $ThisLine =~ /^collect: premature EOM: / ) or # the following is captured later, as detailed info is also printed # file=milter.c, LogLevel>0, LOG_INFO ( $ThisLine =~ /^Milter \(.*\): to error state$/ ) or # milter statements # file=milter.c, LogLevel>8, LOG_INFO ( $ThisLine =~ /^Milter message: body replaced$/ ) or # file=milter.c, LogLevel>9, LOG_INFO ( $ThisLine =~ /^Milter accept: message$/ ) or # file=milter.c, LogLevel>9, LOG_INFO #( $ThisLine =~ /^Milter \(\w*\): init success to / ) or # milter name may contain none \w symbols such as hyphen ( $ThisLine =~ /^Milter \(\S*\): init success to / ) or # file=milter.c, LogLevel>9, LOG_INFO ( $ThisLine =~ /^Milter: connect/ ) or # file=milter.c, LogLevel>10, LOG_INFO ( $ThisLine =~ /^Milter \(\w*\): abort filter/ ) or # file=milter.c, LogLevel>10, LOG_INFO ( $ThisLine =~ /^milter=\w*, action=\w*, accepted/ ) or # file=milter.c, LogLevel>10, LOG_INFO ( $ThisLine =~ /^milter=\w*, action=\w*, tempfail/ ) or # file=milter.c, LogLevel>12, LOG_INFO ( $ThisLine =~ /^milter=\w*, action=\w*, continue/ ) or # the following is captured later in srvrsmtp.c, except for milter service name # file=milter.c, LogLevel>12, LOG_INFO ( $ThisLine =~ /^milter=\w*, (reject|discard)/ ) or # file=milter.c, LogLevel>14, LOG_INFO ( $ThisLine =~ /^Milter: (rcpts|senders?):/ ) or # file=milter.c, LogLevel>17, LOG_INFO ( $ThisLine =~ /^Milter \(\w*\): (headers|body), sen[dt]/ ) or # file=milter.c, LogLevel>18, LOG_INFO ( $ThisLine =~ /^Milter \(\w*\): quit filter/ ) or # file=milter.c, LogLevel>21, LOG_INFO ( $ThisLine =~ /^Milter \(\w*\): time command / ) or # file=milter.c, LogLevel>21, LOG_INFO ( $ThisLine =~ /^Milter \(\w*\): header, / ) or # the following two return errors that are caught in the "to=" statements # file=srvrsmtp.c, LogLevel>3, LOG_INFO ( $ThisLine =~ /^Milter: data, reject=55[0-9] 5\.7\.1 (.*)/ ) or # file=srvrsmtp.c, LogLevel>3, LOG_INFO ( $ThisLine =~ /^Milter: data, discard$/ ) or # file=srvrsmtp.c, LogLevel>9, LOG_INFO ( $ThisLine =~ /^Sending .* to Milter$/ ) or # file=srvrsmtp.c, LogLevel>3, LOG_INFO # SMTP codes # status code 0XX is informational ( $ThisLine =~ /^--- 0[0-9]{2}(-| )/ ) or # status code 2XX is success - but hold onto the Hello response ( ( $ThisLine =~ /^--- 2[0-9]{2}(-| )/ ) and not ( $ThisLine =~ /^--- 250[ -].* Hello .*, pleased to meet you$/ )) or # status codes 4XX are for transient failures ( ( $ThisLine =~ /^--- 4[0-9]{2}(-| )/ ) and not # but note bad commands, because we'll need it later ( $ThisLine =~ /^--- 421 4\.7\.0 .* Too many bad commands; closing connection$/)) or # status code 334 is used for STARTTLS verification ( $ThisLine =~ /^--- 334 / ) or # status code 354 used to request data ( $ThisLine =~ /^--- 354 Enter mail, end with \"\.\" on a line by itself/ ) or ( $ThisLine =~ /^--- 354 End data with ./) or # invalid smtp commands detected later ($RejCmd) ( $ThisLine =~ /^--- 502 5(\.[0-9]){2} Sorry, we do not allow this operation$/ ) or # Need RCPT most likely because of incorrect RCPT command, in which case ignore it ( ( $ThisLine =~ /^--- 503 5(\.[0-9]){2} Need RCPT \(recipient\)$/ ) and ( $Msgs{$QueueID}{"BadRCPT"} > 0)) or ( $ThisLine =~ /^--- 530 5\.7\.0 Authentication required$/ ) or # AUTH failure detected later with %AUTHfailure ( $ThisLine =~ /^--- 535 5\.7\.0 authentication failed$/ ) or # Mailbox disabled detected later by ruleset=check_rcpt ( $ThisLine =~ /^--- 550 5(\.[0-9]){2} .* Mailbox disabled for this recipient$/ ) or # bogus HELO detected later by rulteset=check_rcpt ( $ThisLine =~ /^--- 550 5(\.[0-9]){2} .* bogus HELO name used/ ) or # Commands rejected are from greet_pause or milter ( $ThisLine =~ /^--- 550 5(\.[0-9]){2} Command rejected$/ ) or # User unknown detected later by ruleset=check_rcpt ( $ThisLine =~ /^--- 550 5(\.[0-9]){2} .*\.\.\. User unknown/ ) or # Relaying denied detected later by ruleset=check_rcpt ( $ThisLine =~ /^--- 550 5(\.[0-9]){2} .*\.\.\. Relaying denied/ ) or # Access denied detected later by ruleset=check_relay ( $ThisLine =~ /^--- 550 5(\.[0-9]){2} .*\.\.\. Access denied/ ) or # Domain errors detected later by ruleset=check_mail ( $ThisLine =~ /^--- 553 5(\.[0-9]){2} .*\.\.\. Domain of sender address .* does not exist$/ ) or ( $ThisLine =~ /^--- 553 5(\.[0-9]){2} .*\.\.\. Domain name required for sender address/ ) or # detected later as Hostname required ($ThisLine =~ /^--- 553 5(?:\.\d){2} (.*)\.\.\. Hostname required$/ ) or # the following used by milter, which is detected later ( $ThisLine =~ /^--- 554 5\.7\.1 / ) or # the following used by greet_pause feature ( $ThisLine =~ /^--- 554 .* not accepting messages/ ) or # detected by "invalid domain name" statement elsewhere ( $ThisLine =~ /^--- 501 5(\.[0-9]){2} Invalid domain name$/ ) or # out-of-sequence commands ( $ThisLine =~ /^--- 503 5(\.[0-9]){2} Polite people say HELO first$/ ) or ( $ThisLine =~ /^--- 501 5(\.[0-9]){2} HELO requires domain address$/ ) or ( $ThisLine =~ /^--- 501 5(\.[0-9]){2} EHLO requires domain address$/ ) or ( $ThisLine =~ /^--- 503 5(\.[0-9]){2} Need MAIL command$/ ) or ( $ThisLine =~ /^--- 503 5(\.[0-9]){2} Need MAIL before RCPT$/ ) or # these are the valid commands ( $ThisLine =~ /<-- (EHLO|HELO|STARTTLS|MAIL FROM|RCPT TO|DATA|RSET|QUIT|NOOP)/i ) or ( $ThisLine =~ /<-- (ETRN|VERB|EXPN|VRFY|HELP|AUTH|NOOP|VERB)/i ) or # file=daemon.c, LogLevel>11, LOG_INFO ( $ThisLine =~ /SMTP outgoing connect on/ ) or # file=envelope.c, LogLevel>9, LOG_INFO ( $ThisLine =~ /done; delay=[0-9:\+]*, ntries=/ ) or # file=alias.c, LogLevel>10, LOG_INFO ( $ThisLine =~ /^alias.*=>/ ) or # file=main.c, LogLevel>9, LOG_INFO ( $ThisLine =~ /^connect from / ) or # file=srvrsmtp.c, LogLevel>11, LOG_INFO ( $ThisLine =~ /^AUTH: available mech=/ ) or # we should probably count the following... # file=deliver.c, LogLevel>9, LOG_INFO ( $ThisLine =~ /^AUTH=client, relay=.*, mech=.*, bits=\d*/ ) or # file=srvrsmtp.c, LogLevel>11, LOG_INFO ( $ThisLine =~ /^AUTH=server, relay=.*, authid=.*, mech=.*, bits=\d*/ ) or # we should probably count the following... # file=deliver.c, LogLevel>4, LOG_INFO ( $ThisLine =~ /^discarded$/ ) or # STARTTLS # file=tls.c, LogLevel>14, LOG_INFO ( $ThisLine =~ /^STARTTLS=(server|client), get_verify:/ ) or # file=tls.c, LogLevel>11, LOG_INFO ( $ThisLine =~ /^STARTTLS=(server|client), cert-subject=/ ) or # file=tls.c, LogLevel>13, LOG_INFO ( $ThisLine =~ /^STARTTLS=(server|client), Diffie-Hellman init, key=/ ) or # file=tls.c, LogLevel>12, LOG_INFO ( $ThisLine =~ /^STARTTLS=(server|client), init=1/ ) or # file=deliver.c, LogLevel>13, LOG_INFO ( $ThisLine =~ /^STARTTLS=client, start=ok$/ ) or # file=readcf.c, LogLevel>9, LOG_NOTICE, starting in 8.16.1 # because the features string can be many things, we ignore those # strings that are known to be non-errors. (Other error strings are # possible, but they don't match because they have more arguments, # such as option/value pairs, "error=", "opt=", etc.) # The "stat=" string was added in 8.17.1, and can be non-error # (value of stat=0). ( $ThisLine =~ m/^tls_(srv|clt)_features= (?!too_short|only_one_of_CertFile\/KeyFile_specified)[^,]*, \ (stat=0,\ )?relay=([^\ ])*\ \[.*\]$/x ) or # file=tls.c, LogLevel>13, LOG_DEBUG, starting in 8.16.1 ( $ThisLine =~ /engine=.*, path=.*, ispre=\d+, pre=\d+, initialized=\d+$/ ) or # the following is described in tls.c as a bug in OpenSSL, and # recommends that the error message be ignored (last checked on 8.15.2) # file=tls.c, LogLevel>15, LOG_WARNING ( $ThisLine =~ /^STARTTLS=(server|client), SSL_shutdown not done$/ ) or # and something similar occurs for the one sending the shutdown after the # connection is already closed by the other side # file=tls.c, LogLevel>11, LOG_WARNING ( $ThisLine =~ /^STARTTLS=(server|client), SSL_shutdown failed/ ) or # for reads, the timeout is later captured by either a "lost channel" or # a "collect: I/O error" statement, so we ignore the STARTTLS one # and similarly for a read timeout # file=sfsasl.c, LogLevel>7, LOG_WARNING ( $ThisLine =~ /^STARTTLS: read error=timeout$/ ) or # file=srvsmtp.c, LogLevel>5, LOG_WARNING ( $ThisLine =~ /^STARTTLS=server, error: accept failed=-1, reason=unknown, SSL_error=5, errno=${\Errno::ECONNRESET}, retry=/ ) or # and yet another symptom of a connection shut down (EPIPE refers to "Broken pipe") # file=srvsmtp.c, LogLevel>5, LOG_WARNING ( $ThisLine =~ /^STARTTLS=server, error: accept failed=-1, reason=unknown, SSL_error=5, errno=${\Errno::EPIPE}, retry=/ ) or # the following is a detailed SSL error log (from tlslogerr) # always preceded by a more user-friendly error message # file=srvrsmtp.c, LogLevel>8, LOG_WARNING ( $ThisLine =~ /STARTTLS=(?:\w*): \d*:error:\w{8}:[^:]*:[^:]*:([^:]*):/ ) or # the following is a log message introduced in 8.13.6 # file=sfsasl.c, LogLevel>14, LOG_INFO # tls_retry errors are either transient, or additional log info is issued and parsed ( $ThisLine =~ /^STARTTLS=(server|client|read|write), info: fds=\d+\/\d+, err=\d$/ ) or # Messages from ruleset try_tls, these can be ignored # ruleset=try_tls, arg1=..., relay=..., reject=550 5.7.1 ... do not try TLS with ... ( $ThisLine=~ /^ruleset=try_tls, arg1=(.*?).*?, reject=550.*do not try TLS with.*/ ) or # AUTH offered, but not authenticated # file=sendmail.cf ( $ThisLine =~ /^ruleset=trust_auth, .* reject=550 5\.7\.1 .*\.\.\. not authenticated$/ ) or # file=queue.c, LogLevel>8, LOG_INFO ( $ThisLine =~ /^runqueue: Flushing queue from/ ) or # file=daemon.c, LogLevel>8, LOG_INFO ( $ThisLine =~ /^accepting connections again for daemon / ) or # do we want to count these? # file=srvrsmtp.c, LogLevel>-1, LOG_INFO ( $ThisLine =~ /probable open proxy: / ) or # the following return error is caught in the "to=" statement ( $ThisLine =~ /^makeconnection \(.*\) failed: / ) or # LOG_DEBUG statements # file=queue.c, LogLevel>79, LOG_DEBUG ( $ThisLine =~ /^queueup / ) or # file=queue.c, LogLevel>69, LOG_DEBUG ( $ThisLine =~ /^runqueue .*, pid=\d*, forkflag=\d*$/ ) or # file=queue.c, LogLevel>76, LOG_DEBUG ( $ThisLine =~ /^dowork, pid=\d*$/ ) or # file=queue.c, LogLevel>76, LOG_DEBUG ( $ThisLine =~ /^doworklist, pid=\d*$/ ) or # file=queue.c, LogLevel>19, LOG_DEBUG ( $ThisLine =~ /^locked$/ ) or # file=queue.c, LogLevel>19, LOG_DEBUG ( $ThisLine =~ /^changed$/ ) or # file=queue.c, LogLevel>19, LOG_DEBUG ( $ThisLine =~ /^too young \(.*\)$/ ) or # file=queue.c, LogLevel>93, LOG_DEBUG ( $ThisLine =~ /^assigned id/ ) or # file=queue.c, LogLevel>87, LOG_DEBUG ( $ThisLine =~ /^unlock$/ ) or # file=main.c, LogLevel>78, LOG_DEBUG ( $ThisLine =~ /^finis, pid=\d*$/ ) or # file=main.c, LogLevel>79, LOG_DEBUG ( $ThisLine =~ /^interrupt$/ ) or # file=main.c, LogLevel>93, LOG_DEBUG ( $ThisLine =~ /^disconnect level \d*$/ ) or # file=main.c, LogLevel>71, LOG_DEBUG ( $ThisLine =~ /^in background, pid=\d*$/ ) or # file=util.c, LogLevel>98, LOG_DEBUG ( $ThisLine =~ /^unlink / ) or # file=deliver.c, LogLevel>80, LOG_DEBUG ( $ThisLine =~ /^sendenvelope, flags=0x[0-9a-fA-F]*$/ ) or # file=envelope.c, LogLevel>84, LOG_DEBUG ( $ThisLine =~ /^dropenvelope, e_flags=0x[0-9a-fA-F]*, OpMode=., pid=\d*$/ ) or # for the following, any return code is still at LogLevel>97, but we only # check for ENOENT return codes, as others are maybe worth looking into # file=queue.c, LogLevel>97, LOG_DEBUG ( $ThisLine =~ /$QueueIDFormat: unlink-fail $ENOENT/o ) or # dumpfd() output ( $ThisLine =~ /\d+: fl=0x\d+, mode=\d+/ ) or # generic DEBUG statement ( $ThisLine =~ /^DEBUG: / ) ) { # We don't care about these statements above # file=srvrsmtp.c } elsif ( ($RelayHost) = ($ThisLine =~ /^--- 250[ -].* Hello (.*), pleased to meet you$/) ) { # record the host for errors on SMTP commands $Msgs{$QueueID}{"Relay"} = $RelayHost; $Msgs{$QueueID}{"BadRCPT"} = 0; # file=headers.c, LogLevel>-1, LOG_INFO } elsif ( ($FromUser, $Bytes, $NumRcpts, $RelayHost) = ($ThisLine =~ /^from=(.*?), .*size=([0-9]+),.*nrcpts=([0-9]+).*relay=(.*)/) ) { if ($NumRcpts > 0) { $MsgsSent++; $AddrRcpts += $NumRcpts; $BytesTransferred += $Bytes; $MailBomber{$RelayHost} += $NumRcpts; $MailBomberConn{$RelayHost}++; if ($Bytes <= 10240) { $SizeDist[0]{'Num'}++; $SizeDist[0]{'Bytes'} += $Bytes; } elsif ($Bytes <= 20480) { $SizeDist[1]{'Num'}++; $SizeDist[1]{'Bytes'} += $Bytes; } elsif ($Bytes <= 51200) { $SizeDist[2]{'Num'}++; $SizeDist[2]{'Bytes'} += $Bytes; } elsif ($Bytes <= 102400) { $SizeDist[3]{'Num'}++; $SizeDist[3]{'Bytes'} += $Bytes; } elsif ($Bytes <= 512000) { $SizeDist[4]{'Num'}++; $SizeDist[4]{'Bytes'} += $Bytes; } elsif ($Bytes <= 1048576) { $SizeDist[5]{'Num'}++; $SizeDist[5]{'Bytes'} += $Bytes; } elsif ($Bytes <= 2097152) { $SizeDist[6]{'Num'}++; $SizeDist[6]{'Bytes'} += $Bytes; } elsif ($Bytes <= 5242880) { $SizeDist[7]{'Num'}++; $SizeDist[7]{'Bytes'} += $Bytes; } elsif ($Bytes <= 10485760) { $SizeDist[8]{'Num'}++; $SizeDist[8]{'Bytes'} += $Bytes; } else { $SizeDist[9]{'Num'}++; $SizeDist[9]{'Bytes'} += $Bytes; } } else { $MsgsNoRcpt++; } # Add info from message to a hash $Msgs{$QueueID}{"Relay"} = $RelayHost; $Msgs{$QueueID}{"FromUser"} = $FromUser; $Msgs{$QueueID}{"Size"} = $Bytes; # file=deliver.c, LogLevel>-1, LOG_INFO } elsif ( ($ToUser, $MailerString, $DeliverStat) = ($ThisLine =~ /^to=(.*?), (.*)stat=(.*)/ ) ) { if ( $DeliverStat =~ /^Sent/ ) { ( ($MailerType) = ( $MailerString =~ /mailer=(.*?),/)); ( ($RelayName) = ( $MailerString =~ /relay=(.*?),/)); if (not defined $MailerType) { $MailerType = "(unspecified)"; } $MailerType =~ s/^\s*$/\(unspecified\)/; # remove the entries from MSP (Mail Submission Program) relay to # localhost if (($MailerType =~ /^relay$/) && (defined $RelayName) && ($RelayName =~ /\[127\.0\.0\.1\]/)) { $RelayLocalhost++; } else { $Mailers{$MailerType}++; } # if $MailerType !~ /^relay$/ ... #This the Top X Email Addresses seen matching -mgt #Build address hash my $CleanTo = $ToUser; $CleanTo =~ s/\//g; $CleanTo =~ s/\"[\w\s]+\"\s?//g; $CleanTo =~ tr/A-Z/a-z/; if (($CleanTo =~ m/\w+\@.+\,\w+/) && (defined $RelayName) && ($RelayName !~ m/\[127\.0\.0\.1\]/)) { my @CleanList = split(/,/, $CleanTo); for my $ListAddr (@CleanList) { $ToList{$ListAddr}++; } } elsif (($CleanTo =~ m/\w+\@[\w\.]+/) && (defined $RelayName) && ($RelayName !~ m/\[127\.0\.0\.1\]/)) { $ToList{$CleanTo}++; } elsif ($CleanTo =~ m/\w+/) { # Match a simple name $ToList{$CleanTo}++; } #Else ignore it if (defined $Msgs{$QueueID}{"Size"}) { if ($Msgs{$QueueID}{"Size"} > 5242880) { #10485760 $LargeMsgs{$Msgs{$QueueID}{"FromUser"} . " \-\> " .$ToUser}++; } # if size > 5242880 } # if defined } elsif ( $DeliverStat =~ /^queued$/ ) { # do nothing if being queued } elsif ( ($Reason) = ( $DeliverStat =~ /^Deferred: (.*)/ ) ) { $StatDeferred{$Reason}{$ToUser}++; } elsif ( $DeliverStat =~ /^Please try again later$/ ) { $StatDeferred{"Milter"}{$ToUser}++; } elsif ( ($Reason) = ( $DeliverStat =~ /(.*)/ ) ) { $StatRejected{$Reason}{$ToUser}++; $StatRejectedLog{$Reason}{$QueueID}++; } } elsif ( ($NewQueueID, $Reason) = ( $ThisLine =~ /^($QueueIDFormat): (?:return to sender|sender notify|postmaster notify|DSN): (.*)/o )) { if (defined $StatRejectedLog{$Reason}{$QueueID}) { # this is a type of error that has been logged, but it is creating a new message $Msgs{$NewQueueID}{"Relay"} = $Msgs{$QueueID}{"Relay"}; $Msgs{$NewQueueID}{"Size"} = $Msgs{$QueueID}{"Size"}; $Msgs{$NewQueueID}{"FromUser"} = "system_notify"; } elsif ($Reason =~ /^Unable to deliver mail$/) { $StatRejected{"Unable to deliver mail"}{"system notify"}++; # Return Receipts from successful delivery } elsif ($Reason =~ /^Return receipt$/) { if (not defined $Msgs{$QueueID}{"FromUser"}) { # The most likely reason for this condition is that the # original email, which identifies the sender, was received # before the --range period specified. $ReturnReceipts{"(Unknown Sender)"}++; } else { $ReturnReceipts{$Msgs{$QueueID}{"FromUser"}}++; } # Timeouts } elsif ($Reason =~ /^(Warning: could not send message for past .*)/ ) { $SentTimeouts{$Reason}++; } elsif ($Reason =~ /^(Cannot send message for .*)/ ) { $SentTimeouts{$Reason}++; } # These are transient errors } elsif (($Reason) = ($ThisLine =~ /^Milter: (?:data|to=.*|from=.*), reject=4\d\d (?:\d\.\d\.\d )?(.*)/) ) { $MilterDeferrals{$Reason}++; # file=deliver.c, LogLevel>4, LOG_INFO } elsif ( ($NewQueueID, $Owner) = ( $ThisLine =~ /($QueueIDFormat): clone: owner=(.*)/o ) ) { $Msgs{$NewQueueID}{"FromUser"} = $Owner; # file=deliver.c, LogLevel>4, LOG_INFO (versions 8.11 and earlier) } elsif ( ($NewQueueID, $Owner) = ( $ThisLine =~ /^clone ($QueueIDFormat), owner=(.*)/o ) ) { $Msgs{$NewQueueID}{"FromUser"} = $Owner; # file=main.c, LogLevel>-1, LOG_INFO } elsif ( $ThisLine =~ /^starting daemon/) { $SendmailStarts++; $SendmailStopped = 0; # file=daemon.c, LogLevel>3, LOG_INFO } elsif ( $ThisLine =~ /^restarting .* due to/) { $SendmailStarts++; $SendmailStopped = 0; # file=daemon.c, LogLevel>9, LOG_INFO } elsif ( $ThisLine =~ /^stopping daemon, reason=/ ) { $SendmailStopped = 1; # After some testing this was removed and EOM is ignored -mgt # file=collect.c, LogLevel>1, LOG_WARNING #} elsif ( ($Reason) = ($ThisLine =~ /^collect: premature EOM: (.*)/) ) { # if (defined $Msgs{$QueueID}{"Relay"}) { # $Source = "From " . $Msgs{$QueueID}{"Relay"}; # } else { # $Source = "Processing $QueueID"; # } # $CollectError{$Reason}{$Source}++; # file=collect.c, LogLevel>0, LOG_NOTICE } elsif ( ($Reason, $Source) = ($ThisLine =~ /collect: (unexpected close|I\/O error|read timeout) on connection from (.*)?, /) ) { $CollectError{$Reason}{$Source}++; # file=collect.c, LogLevel>0, LOG_NOTICE } elsif ( ($Source, $Reason) = ($ThisLine =~ /collect: relay=(.*), from=.*, info=(.*), where=/) ) { $CollectError{$Reason}{$Source}++; # file=collect.c, LogLevel>6, LOG_NOTICE } elsif (($Size) = ($ThisLine =~ /^message size \(([0-9]+)\) exceeds maximum/)) { $OverSize++; $OverSizeBytes += $Size; # file: sendmail.cf } elsif ( ($User) = ($ThisLine =~ /^ruleset=check_rcpt, arg1=([^,]*), relay=[^,]*, reject=550\s*[\d.]*\s*[^ ]*\.\.\. Mailbox disabled for this recipient/) ) { $DisabledMailbox{$User}{$QueueID}++; $Msgs{$QueueID}{"BadRCPT"}++; # test for unknown relay users (users we would have relayed elsewhere) # file: sendmail.cf } elsif ( ($User) = ($ThisLine =~ /^ruleset=check_rcpt, arg1=(.*?), .*\.\.\. User unknown$/) ) { $UnknownUsersCheckRcpt{$User}{$QueueID}++; $Msgs{$QueueID}{"BadRCPT"}++; } elsif ( ($User) = ($ThisLine =~ /^(.*)\.\.\. (User unknown|No such user( here)?)$/i) ) { $UnknownUsers{lc $User}{$QueueID}++; $Msgs{$QueueID}{"BadRCPT"}++; # file: sendmail.cf } elsif ($ThisLine =~ /^--- 553 5\.1\.3 .* User address required$/) { $UnknownUsers{"(unspecified)"}{$QueueID}++; # file: sendmail.cf } elsif ( ($Dest,$Relay) = ($ThisLine =~ /^ruleset=check_rcpt, arg1=([^,]*), relay=([^,]*)(?: \(may be forged\))?, reject=550\s*[\d.]*\s*.*\.\.\. Relaying denied/) ) { $RelayDenied{$Relay}{$Dest}++; $Msgs{$QueueID}{"BadRCPT"}++; } elsif ( ($Auth) = ($ThisLine =~ /^--- 504 5\.3\.3 AUTH mechanism (.*) not available$/) ) { $BadAuth{$Auth}++; # file=sendmail.cf #} elsif ( ($User) = ($ThisLine =~ /^--- 553 5(?:\.\d){2} (.*)\.\.\. Hostname required$/) ) { } elsif ( ($User) = ($ThisLine =~ /^(.*)\.\.\. Hostname required$/) ) { if (not defined $Msgs{$QueueID}{"Relay"}) { # most likely a split envelope. We check for previous QueueId of same timestamp # and process number, with previous sequence number in index 6 and 7. my $QueueIdChars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; $QueueIdChars .= "abcdefghijklmnopqrstuvwxyz"; my $CharIndex0 = index($QueueIdChars,substr($QueueID, 6, 1)); my $CharIndex1 = index($QueueIdChars,substr($QueueID, 7, 1)); $CharIndex1--; if ($CharIndex1 < 0) { $CharIndex1 = length($QueueIdChars) - 1; $CharIndex0--; if ($CharIndex0 < 0) { $CharIndex0 = length($QueueIdChars) - 1; } } my $OldQueueID = substr($QueueID, 0, 6) . substr($QueueIdChars, $CharIndex0, 1) . substr($QueueIdChars, $CharIndex1, 1) . substr($QueueID, 8); if (defined $Msgs{$OldQueueID}{"Relay"}) { # Previous QueueID found for same host $DomainErrors{$Msgs{$OldQueueID}{"Relay"}}{$User}++; } else { # Unknown host $DomainErrors{"(Missing hostname)"}{$User}++; } } else { # No split envelope; we already have hostname $DomainErrors{$Msgs{$QueueID}{"Relay"}}{$User}++; } # file: sendmail.cf } elsif ( ($User, $RelayHost) = ($ThisLine =~ /^ruleset=check_(?:mail|rcpt), arg1=(.*), relay=(.*), reject=451\s*[\d.]*\s*Domain of sender address .* does not resolve/) ) { # I don't think we should include this, because it is a temporary error # $DomainErrors{$RelayHost}{$User . ": (does not resolve)"}++; # file: sendmail.cf } elsif ( ($RelayHost,$User) = ($ThisLine =~ /^ruleset=check_(?:mail|rcpt), arg1=.*, relay=(.*), reject=553\s*[\d.]*\s*.*\.\.\. Domain of sender address (.*) does not exist/) ) { $User =~ s/^.+\@(.+)$/$1/ if ($Detail < 15); $DomainErrors{$RelayHost}{$User . " (sender does not exist)"}++; $Msgs{$QueueID}{"BadRCPT"}++; # file: sendmail.cf } elsif ( ($User,$RelayHost) = ($ThisLine =~ /^ruleset=check_mail, arg1=(.*), relay=(.*), reject=553\s*[\d.]*\s*.*\.\.\. Domain name required for sender address .*/) ) { $DomainErrors{$RelayHost}{$User . " (sender domain missing)"}++; # file: sendmail.cf NOT STOCK moved for order detection reasons -mgt } elsif ($ThisLine =~ /^ruleset=(?:check_relay|check_rcpt), arg1=([^,]*),(?: arg2=[^,]*,)?(?: relay=[^,]*,)? reject=55\d\s*[\d.]*\s*.*(?:Mail from|Rejected:) [^ ]* (?:refused by blackhole site|listed at|found in) (.*)/) { $Temp = "From " . $1 . " by " . $2; $BlackHoled{$Temp}++; $BlackHoles{$2}++; } elsif ( ($Relay,$BlSite) = ($ThisLine =~ /^ruleset=(?:check_relay|check_rcpt), arg1=[^,]*,(?: arg2=[^,]*,)? relay=([^,]*), reject=55\d\s*[\d.]*\s*.*http:\/\/([^\/\s]*)/) ) { $Temp = "From " . $Relay . " by " . $BlSite; $BlackHoled{$Temp}++; $BlackHoles{$BlSite}++; } elsif ( ($Relay,$BlSite) = ($ThisLine =~ /^ruleset=(?:check_relay|check_rcpt), arg1=([^,]*),(?: arg2=[^,]*,)? reject=55\d\s*[\d.]*\s*.*http:\/\/([^\/\s]*)/) ) { #Example 553 error with NO RELAY -mgt #ruleset=check_relay, arg1=s010600402b39ee29.vf.shawcable.net, arg2=127.0.0.2, reject=553 5.3.0 #Spam blocked see: http://spamcop.net/bl.shtml?70.68.8.182: 1 Time(s) $Temp = "From " . $Relay . " by " . $BlSite; $BlackHoled{$Temp}++; $BlackHoles{$BlSite}++; } elsif ( ($Relay,$BlSite) = ($ThisLine =~ /reject=553\s*[\d.]*\s*<[^ ]*>\.\.\. +Mail from ([\d\.]+) rejected\;see http:\/\/([^\/\s]*)/) ) { #This is the another blackhole tag -mgt $Temp = "From " . $Relay . " by " . $BlSite; $BlackHoled{$Temp}++; $BlackHoles{$BlSite}++; } elsif ( ($BlSite, $Relay) = ($ThisLine =~ /reject=553\s*[\d.]*\s*<[^ ]*>\.\.\. +Email blocked using ORDB.org - see \\.\.\. Mail from [^ ]* refused by blackhole site ([^ ]*)/) ) { # $Temp = "From " . $Relay . " by " . $BlSite; # $BlackHoled{$Temp}++; # $BlackHoles{$BlSite}++; # $Msgs{$QueueID}{"BadRCPT"}++; # test for all kinds of rejects due to check_mail # file: sendmail.cf } elsif( ($Arg,$Relay,$Reason) = ($ThisLine =~ /^ruleset=check_mail, arg1=(.*), relay=.*?\[(.*)\].*, reject=(.*)/) ) { $Temp = "[$Relay] $Arg\n\t$Reason"; $CheckMailReject{$Temp}++; # file: sendmail.cf } elsif( ($Arg,$Relay,$Reason) = ($ThisLine =~ /^ruleset=check_rcpt, arg1=(.*), relay=.*?\[(.*)\].*, reject=(.*)/) ) { $Reason =~ s/\Q$Arg\E\.\.\. //; $Temp = "$Arg ($Reason)"; $CheckRcptReject{$Temp}++; $Msgs{$QueueID}{"BadRCPT"}++; # file=srvrsmtp.c, LogLevel>1, LOG_NOTICE } elsif ( ($Temp) = ($ThisLine =~ /^lost input channel from (.*) to .* after .*/) ) { $LostInputChannel{$Temp}++; # file=collect.c, LogLevel>2, LOG_NOTICE # file=control.c, LogLevel>2, LOG_NOTICE # file=util.c, LogLevel>1, LOG_NOTICE } elsif ( ($Temp) = ($ThisLine =~ /^timeout waiting for input (from \S+|during control command)/) ) { $Timeouts{$Temp}++; # file=milter.c, LogLevel>10, LOG_INFO } elsif ( $ThisLine =~ /Milter: no active filter/) { $NoMilterFilters++; # file=srvrsmtp.c } elsif ( ($Temp) = ($ThisLine=~ /\-\-\- 500 5\.5\.1 Command unrecognized: \"([^\"]*)/) ) { chomp($Temp); # And we write it like the incoming SMTP command, so we can later # check it against unmatched entries ($OtherList). $Temp1 = "<-- $Temp"; # It uses "..." to indicate shortened strings, so we ignore the # rest of the line. $Temp1 =~ s/\.\.\..*//; # We normalize tab, newline, and return to use their octal values, # as sendmail converts escaped octals. $Temp1 =~ s/\\t/\\011/g; $Temp1 =~ s/\\n/\\012/g; $Temp1 =~ s/\\r/\\015/g; # Remove non-printable space(s) at the end $Temp1 =~ s/\s*$//; # we try to delete it from the list of Unmatched Entries if (defined $OtherList{$Temp1}) { $OtherListFound = 1; if ($OtherList{$Temp1} == 1) { delete ($OtherList{$Temp1}); } elsif ($OtherList{$Temp1} > 1) { $OtherList{$Temp1}--; } else { # This should not happen. So we punt it to the # OtherList to be printed at the end. $OtherList{"Command unrecognized: " . $Temp}++; } } else { $OtherListFound = 0; $OtherList{$Temp1}++; } # Ignore commands from connects that failed greeting if (not defined $PREGreetingQueue{$QueueID}) { if ($Temp =~ /^$/) { $Temp = ""}; if ($OtherListFound == 0) { if (not defined $CommandUnrecognized{$QueueID}) { # initialize string, as we will concatenate commands $CommandUnrecognized{$QueueID} = ""; } $CommandUnrecognized{$QueueID} .= "\t" . $Temp . "\n"; } } # similarly, delete last unmatched entry when too many bad commands } elsif ( $ThisLine =~ /^--- 421 4\.\d\.\d .* Too many bad commands; closing connection$/) { if (defined $OtherList{$LastCmd{$QueueID}}) { delete ($OtherList{$LastCmd{$QueueID}}); } # file=srvrsmtp.c, LogLevel>9, LOG_INFO } elsif ( ( $User, $Host ) = $ThisLine =~ /^invalid domain name \((.*)\) from (.*)/ ) { $DomainErrors{$Host}{$User . " (invalid domain name)"}++; # file=srvrsmtp.c, LogLevel>5, LOG_INFO } elsif ( ( $Host ) = ($ThisLine =~ /(.*) (\(may be forged\) )?did not issue MAIL\/EXPN\/VRFY\/ETRN during connection to /) ) { # we test if they previously sent junk, because the connection is expected to fail if (defined $CommandUnrecognized{$QueueID}) { $CommandUnrecognized{$QueueID} .= " ... and then exited without communicating\n"; } else { $DummyConnection{$Host}++; } # file=srvrsmtp.c, LogLevel>-1, LOG_INFO } elsif ($ThisLine =~ /rejecting commands from (.*) due to pre-greeting traffic/ ) { $PREGreeting{$1}++; $PREGreetingQueue{$QueueID}++; } elsif ($ThisLine =~ /rejecting server EHLO from (.*) due to traffic before response/ ){ $PREGreeting{$1}++; $PREGreetingQueue{$QueueID}++; # possible "(may be forged)" after IP address # file=srvrsmtp.c, LogLevel>5, LOG_INFO } elsif ( ($Temp) = ($ThisLine =~ /^.*\[(.*?)\].*: Possible SMTP RCPT flood, throttling./) ) { $BadRcptThrottle{$Temp}++; # file=srvrsmtp.c } elsif ($ThisLine =~ /^Too many recipients$/) { $TooManyRcpts++; # file=deliver.c (note: while this is a syserr, I think it's reasonable to extract it here, as there is not # much the sender can do if they don't own the recipient address } elsif ( ($Temp) = ($ThisLine =~ /^.*?Too many hops (.*)/) ) { $TooManyHops{$Temp}++; # file=main.c LogLevel>3, LOG_INFO } elsif ( ($Warning) = ($ThisLine =~ /Authentication-Warning: (.*)/) ) { $AuthWarns{$Warning}++; # file=alias.c, LogLevel>2, LOG_ERR } elsif ( ($Forward,$Error) = ($ThisLine =~ /^forward ([^ ]*): transient error: (.*)/) ) { $Temp = $Forward . ": " . $Error; $ForwardErrors{$Temp}++; # file=alias.c, LogLevel>2,10, LOG_WARNING } elsif ( ($Forward,$Error) = ($ThisLine =~ /^forward ([^ ]*): (.*)/) ) { $Temp = $Forward . ": " . $Error; $ForwardErrors{$Temp}++; # file=collect.c, LogLevel>-1, LOG_NOTICE } elsif ($ThisLine=~ /^headers too large .* from (.*) during message collect$/) { $LargeHdrs{$1}++; # file=srvrsmtp.c, LogLevel>5, LOG_INFO } elsif ($ThisLine=~ /(\S*) ?\[(IPv6:)?([0-9A-F\.:]+)\](?: \(may be forged\))?: (\S+) (\S+) \[rejected\]/i) { chomp($Host=$3." ". (defined($1) ? "(".$1.")" : "(unresolved)") ); $Luser=$5; $RejCmd=uc $4; $Abuse{$Host}{$Luser}{$RejCmd}++; # file=srvrsmtp.c, LogLevel>5, LOG_INFO } elsif ( $ThisLine =~ /\[(IPv6:)?([0-9A-F\.:]+)]: ETRN (\S+)/i ) { chomp($ETRN=$3." from ".$2); $ETRNs{$ETRN}++; # file=conf.c, LogLevel>8, LOG_NOTICE } elsif ( $ThisLine =~ /rejecting connections on daemon [^ ]+: load average: ([0-9]+)/ ) { $LoadAvg{$1}++; $LoadAvgReject++; # file=conf.c, LogLevel>8, LOG_INFO } elsif ( ($Reason) = ($ThisLine =~ /(deferring connections on daemon .*): \d+ per second/) ) { $RuleSets{$Reason}++; # file=conf.c, LogLevel>3, LOG_NOTICE } elsif ($ThisLine=~ /tcpwrappers \((.+), (.+)\)/) { chomp($Host=$2); $MailRejected{$Host}++; } elsif ( # file=queue.c, LogLevel>8, LOG_INFO ($ThisLine =~ /Aborting queue run: load average too high/ ) or # file=queue.c, LogLevel>8, LOG_INFO ($ThisLine =~ /Skipping queue run -- load average too high/ ) ){ $LoadAvgQueueSkip++; # file=stats.c, LogLevel>12, LOG_INFO } elsif ( ($StatFile, $StatError) = ($ThisLine=~ /^poststats: (.*?): (.*)/) ) { $StatFileError{$StatFile}{$StatError}++; # file=srvrsmtp.c, LogLevel>9, LOG_WARNING } elsif ( ($Auth, $Reason, $DetailReason, $RelayHost) = ($ThisLine =~ /^AUTH failure \((.*)?\): ([^\(]*)(\(.*) relay=(.*)/) ) { if ( $Reason =~ /^user not found / ) { (($User) = ($DetailReason =~ /\(-20\) SASL\(-13\): user not found: .*user(?:=|: )([^ ,]*)/)); $AUTHnouser{$User}++; } else { $AUTHfailure{$RelayHost}{$Reason}++; } # file=tls.c, LogLevel>7, LOG_INFO } elsif ($ThisLine=~ /STARTTLS=.* field=cn_issuer, status=failed to extract CN/ ) { $NoCommonName++; # file=tls.c, LogLevel>12, LOG_WARNING } elsif ( ($TLSFile) = ($ThisLine=~ /STARTTLS: (.* missing)/) ) { $TLSFileMissing{$TLSFile}++; # file=tls.c, LogLevel>7, LOG_WARNING } elsif ( ($TLSFile) = ($ThisLine=~ /STARTTLS=((server|client): file .* unsafe: .*)/) ) { $TLSFileMissing{$TLSFile}++; # file=srvrsmtp.c, LogLevel>5, LOG_WARNING; reason given as of 8.14.6 } elsif ( ($TLSReason, $TLSFrom) = ($ThisLine=~ /STARTTLS=server, error: accept failed=-?\d+, reason=([^,]*), (?:[^,]*,){3} relay=(.*)/) ) { $TLSAcceptFailed{$TLSReason}{$TLSFrom}++; # handle pre-8.14.6 } elsif ( ($TLSFrom) = ($ThisLine=~ /STARTTLS=server, error: accept failed=-?\d+, SSL_error=(?:[^,]*,){3} relay=(.*)/) ) { $TLSAcceptFailed{"no reason given"}{$TLSFrom}++; # file=deliver.c, LogLevel>5, LOG_WARNING; reason given as of 8.14.6 } elsif ( ($TLSReason) = ($ThisLine=~ /STARTTLS=client, error: connect failed=-?\d+. reason=([^,]*),/) ) { $TLSConnectFailed{$TLSReason}++; # handle pre-8.14.6 } elsif ($ThisLine=~ /STARTTLS=client, error: connect failed=-?\d+. SSL_error=/) { $TLSConnectFailed{"no reason given"}++; # file=tls.c, LogLevel>-1, LOG_INFO } elsif (($CommonName,$StarttlsReason) = ($ThisLine =~ /^STARTTLS: (?:x509|TLS) cert verify: depth=[0-9]+ .*\/CN=([^\/,]*).* state=[0-9]+, reason=(.*)$/ )) { # "reason=ok" now printing in sendmail 8.16.1; not an error if ($StarttlsReason !~ /^ok$/) { $StarttlsCert{$StarttlsReason}{$CommonName}++; } # do the same if, incorrectly, Common Name is not defined } elsif (($StarttlsReason) = ($ThisLine =~ /^STARTTLS: (?:x509|TLS) cert verify: depth=[0-9]+ .* state=[0-9]+, reason=(.*)$/ )) { # "reason=ok" now printing in sendmail 8.16.1; not an error if ($StarttlsReason !~ /^ok$/) { $StarttlsCert{$StarttlsReason}{"(undefined CommonName)"}++; } # file=tls.c, LogLevel>8, LOG_INFO } elsif ( ($StarttlsMode, $StarttlsVerify, $StarttlsCipherType, $StarttlsNumBits) = ($ThisLine =~ /^STARTTLS=(server|client), relay=.*, version=.*, verify=(\w*), cipher=(.*), bits=(\w*\/\w*)/) ) { if ($StarttlsVerify =~ /^OK$|^TEMP$|^PROTOCOL$|^SOFTWARE$|^NO$|^NOT$|^FAIL$|^NONE$/) { $Starttls{$StarttlsMode}{$StarttlsVerify}++; } else { $Starttls{$StarttlsMode}{'Other'}++; } $StarttlsCipher{"Cipher: " . $StarttlsCipherType . " Bits: " . $StarttlsNumBits}++; # We capture only certain STARTTLS errors. Currently, only EPIPE (broken pipe) and # ECONNRESET (connection reset by peer). # Not strictly a STARTTLS error, but it happens when a client ungracefully # exits during a STARTTLS exchange, often after actually delivering mail. # But we make a note of it, anyway. Unfortunately, there is no QueueID. # We might add more errnos in the future, but need to make sure they are not # due to a problem that can be resolved. # file=sfsasl.c, LogLevel>7, LOG_WARNING } elsif ( ($Errno) = ($ThisLine =~ /^STARTTLS: (?:read|write) error=syscall error \(-1\), errno=(${\Errno::EPIPE}|${\Errno::ECONNRESET}|${\Errno::ETIMEDOUT}), / )) { $TLSErrno{$Errno}++; # file=queue.c, LogLevel>-1, LOG_ALERT } elsif ( ($Reason) = ($ThisLine=~ /^Losing (.*)/ ) ) { $LostQueueFile{$Reason}++; # file=queue.c, LogLevel>0, LOG_ALERT } elsif ( ($File) = ($ThisLine=~ /^low on space \(.* in (.*)\), max avail/ ) ) { $LowSpace{$File}++; # file=daemon.c, LogLevel>8, LOG_INFO } elsif ($ThisLine=~ /^rejecting new messages/) { $DaemonThrottle++; # this appears to be the result of EX_PROTOCOL return code, so it should be handled with other EX_ messages } elsif ($ThisLine=~ /Remote protocol error/) { $RemoteProtocolError++; } elsif ( # file=util.c, LogLevel>-1, LOG_NOTICE (($Host,$Attack) = ($ThisLine =~ /POSSIBLE ATTACK from ([^ ]+): (.*)/)) or # fqdn may be missing before IP address # file=srvrsmtp.c, LogLevel>5, LOG_INFO (($Host,$Attack) = ($ThisLine =~ /(.*\[[^ ]+\])(?:\s+\(may be forged\))?: possible SMTP attack: (.*)$/)) ) { $AttackAttempt{$Host}{$Attack}++; #file=headers.c, LogLevel>-1, LOG_ALERT } elsif (($Attack) = ($ThisLine =~ /^(.*) \(possible attack\)$/)) { $AttackAttempt{"UNKNOWN"}{$Attack}++; # file=usersmtp.c, LogLevel>8, LOG_WARNING } elsif ( ($File,$Error) = ($ThisLine =~ /error: safesasl\(([^ ]+)\) failed: (.*)$/) ) { $SaslError{$File}{$Error}++; # can't find the following } elsif ( $ThisLine =~ /Can\'t create output/ ) { $CantCreateOutput++; # file=alias.c, LogLevel>3, LOG_INFO } elsif ( $ThisLine =~ /alias database [^ ]+ out of date/ ) { $OutdatedAliasdb++; # We'll filter the "No space left" error because they tend to manifest # in many different ways # file=err.c, LogLevel>0, LOG_CRIT, LOG_ALERT } elsif ( $ThisLine =~ /No space left on device$/ ) { $NoMoreSpace++; # SYSERR are usually serious... # file=err.c, LogLevel>0, LOG_CRIT, LOG_ALERT } elsif ( ($User,$Reason) = ($ThisLine =~ /SYSERR\((.*)\): (.*)/) ) { $SysErr{$User}{$Reason}++; # file=milter.c, LogLevel>8, LOG_INFO } elsif ( ($HeaderMod) = ($ThisLine =~ /Milter (?:\(\w*\) )?(?:add|insert|change|delete).*: header: (.*)/) ) { foreach $Header (@MilterHeadersToCount) { if ($HeaderMod =~ /$Header/) { $MilterHeaderCount{$Header}++; } } # file=milter.c, LogLevel>3, LOG_INFO } elsif ((my $Milter,$Reason) = ($ThisLine =~ /milter\=(.*), quarantine\=(.*)/)) { my $QuarantineReason = $Milter . ": " . $Reason; $Quarantined{$QuarantineReason}++; } elsif ( # file=parseaddr.c, LogLevel>3, LOG_NOTICE ($Address,$Reason) = ($ThisLine =~ /^Syntax error in mailbox address "(.+)" \(([^ ]+)\)/) or # file=sendmail.cf ($Address,$Reason) = ($ThisLine =~ /^<(.+)>\.\.\. (Colon illegal in host name part)/) or # file=parseaddr.c, LogLevel>3, LOG_NOTICE ($Reason,$Address) = ($ThisLine =~ /^(8-bit character in mailbox address) "<(.+)>"/) ) { $AddressError{$Reason}{$Address}++; } elsif ($ThisLine =~ /ruleset=check_relay, arg1=([^,]*),.* reject=550 5\.7\.1 Access denied/) { # We block some particularly annoying spam domains with the # following in /etc/mail/access... # From:example.com ERROR:550 5.7.1 Access denied # Remember the error message is user defined in /etc/mail/access # So if anyone can make a better check please do -mgt # Note (-bl): the same output is achieved by using the label REJECT in /etc/mail/access file: # From:example.com REJECT $KnownSpammer{$1}++; # add support for DISCARD in /etc/mail/access } elsif ($ThisLine =~ /ruleset=check_(?:mail|rcpt), arg1=([^,]*), relay=.*\[.+\]( \(may be forged\))?, discard/) { $KnownSpammer{$1}++; } elsif ( # file=milter.c, LogLevel>8, LOG_INFO ( $ThisLine =~ /Milter (?:\(\w*\) )?(add|change|insert|delete): /) ) { # We don't care about these statements above # DNS Map lookups: file=map.c, LogLevel>9, LOG_INFO } elsif ($ThisLine=~ /dns (\S+)\. =\> (\d+.\d+.\d+.\d+)/) { chomp($Domain=$1); chomp($IP=$2); $DNSMap{$Domain}{$IP}++; # Here are the statements whose source are not from the stock sendmail: # This is from libspf } elsif ( (my $SPFStatus) = ($ThisLine =~ /^Received-SPF: (fail|softfail|neutral|none|error|unknown|pass) /) ) { $SPFResults{$SPFStatus}++; # This is for the Sendmail Sender-ID milter } elsif ( (my $SenderIDStatus, $SPFStatus) = ($ThisLine =~ /^Milter (?:\(\w*\) )?insert \(1\): header: Authentication-Results:.*; sender-id=(fail.*|softfail|neutral|none|error|unknown|pass); spf=(fail.*|softfail|neutral|none|error|unknown|pass)/) ) { # Example string # Milter insert (1): header: Authentication-Results: my.host.name # sender=list-users-bounces+list-users=host.name@another.org; # sender-id=neutral; spf=neutral $SPFResults{$SPFStatus}++; $SenderIDResults{$SenderIDStatus}++; # file: access #This looks to be a custom ruleset added by Hugo van der Kooij -mgt #Probably would be better renamed as localrule or something. #Google showed me http://hvdkooij.xs4all.nl/email-sendmail.cms } elsif ($ThisLine=~ /ruleset=check_XS4ALL/) { $XS4ALL++; } elsif ( # This one appears to be the result of a file/socket read; it's not clear to me why we want to ignore it ( $ThisLine =~ /Broken pipe|Connection (reset|timed out)/ ) or ( $ThisLine =~ /Milter: from=/ ) ) { # do nothing; statements are filtered out } elsif ($ThisLine =~ /reject=550 5\.7\.1 <[^ ]*@([^ ]*)>\.\.\. Relaying Denied/) { # We block some particularly annoying spam domains with the following in /etc/mail/access... # From:example.com ERROR:550 5.7.1 Relaying Denied (Spammer) # Note (-bl): this is the same as an earlier check_rcpt, except that the word Denied is capitalized here. # So to avoid confusion I suggest that we use the REJECT label in the access file. $KnownSpammer{$1}++; } elsif ( ($Host) = ($ThisLine =~ /relay=([^ ]+ \[[^ ]+\]), reject=553 5\.3\.0 .*/) or ($Host) = ($ThisLine =~ /relay=([^ ]+ \[[^ ]+\] \(may be forged\)), reject=553 5\.3\.0 .*/) ) { $KnownSpammer{$Host}++; } elsif ($ThisLine=~ /relay=(\S+)*.*\[(\d+.\d+.\d+.\d+)\], reject=444 4.4.4 \<([^\>]+)\>\.\.\. Sorry (\S*)/) { chomp($Host=$2." ". (defined($1) ? "(".$1.")" : "(unresolved)") ); chomp($Luser=$3); chomp($Ruser=$4); $Ruser="none" if (length($Ruser)==0); $RelayReject{$Host}{$Ruser}{$Luser}++; } elsif ($ThisLine=~ /arg1=\<([^\>]+)\>, relay=(\S+)*.*\[([^\]]+)\], reject=444 4.4.4 Sorry (\S*)/) { chomp($Host=$3." ". (defined($2) ? "(".$2.")" : "(unresolved)") ); chomp($Ruser=$1); $Luser="none"; $RelayReject{$Host}{$Ruser}{$Luser}++; } elsif ($ThisLine=~ /relay=(\S+)*.*\[(\d+.\d+.\d+.\d+)\], reject=441 4.4.1 \<([^\>]+)\>/) { chomp($Host=$2." ". (defined($1) ? "(".$1.")" : "(unresolved)") ); chomp($Luser=$3); $NotLocal{$Host}{$Luser}++; } elsif ($ThisLine=~ /reject=.*MESSAGE NOT ACCEPTED - (.+)/) { chomp($Host=$1); $MailRejected{$Host}++; # default for ruleset checks. } elsif ( ($Reason) = ($ThisLine =~ /^ruleset=.*, arg1=.*, reject=(?:\d{3} )?(?:\d\.\d\.\d )?(.*)$/) ) { $RuleSets{$Reason}++; } elsif ($ThisLine=~/Warning: program (.*) unsafe: (.*)/) { chomp($Directory=$1); chomp($Cause=$2); $WUnsafe{$Directory}{$Cause}++; # the following is the catch-all: } elsif ( ($Milter,$Error) = ($ThisLine =~ /^Milter \((.*)\): (.+)/) ) { $MilterErrors{$Milter}{$Error}++; } elsif ( $ThisLine =~ /$QueueIDFormat\[[2-9]\]: / ) { # For very large input command lines (hundreds of # characters), sendmail breaks them down and puts an # index after the QueueID when echoing in debug mode # (level > 14). So we'll process the first one, and # ignore the other ones. } else { $ThisLine =~ s/.*\: (DSN\: .*)/$1/; $ThisLine =~ s/.*\: (postmaster notify\: .*)/$1/; chomp($ThisLine); # Report any unmatched entries... # Remove any whitespace at the end $ThisLine =~ s/\s*$//; # For the very first of the very long debug echo lines, # handle the case of the first indexed QueueID. $ThisLine =~ s/${QueueIDFormat}\[1\]: <-- /<-- /; if ($ThisLine =~ /<--/) { # We got here because these are unmatched entries. Often it # is because a client sends binary code when it shouldn't. # When sendmail reads SMTP commands, it converts these # non-printable characters into escaped sequences, so we do # the same here. # First, we deal with the special case of a string containing # \200, as it becomes a null character, terminating the string. #$ThisLine =~ s/(.*)\\200(.*)/$1\\0/g; $ThisLine =~ s/\\200(.*)//; $ThisLine =~ s/\\([23]\d{2})/ # clear the most significant bit if set my $tempchar = oct($1 - 200); if ($tempchar == 92) { # backslash is escaped with another backslash sprintf("\\\\"); } elsif (($tempchar >= 32) && ($tempchar != 127)) { # if the new value is a printable ASCII character, print it chr($tempchar); } else { # if not printable ASCII, leave as octal code sprintf("\\%03o", $tempchar); }/eg; # When a string has embedded double-quotes, sendmail stops processing. $ThisLine =~ s/".*//; # We normalize tab, newline, and return to octal values $ThisLine =~ s/\\t/\\011/g; $ThisLine =~ s/\\n/\\012/g; $ThisLine =~ s/\\r/\\015/g; # Remove non-printable space(s) at the end $ThisLine =~ s/\s*$//; } $OtherList{$ThisLine}++; # Store last unmatched entry, in case it is needed later. But note that some # statements have no QueueID. if (defined $QueueID) { $LastCmd{$QueueID} = $ThisLine; } } } ####################################################### # The following variables are used to print a header # only if there is subsequent data to print for each category my $HeaderPrinted = 0; my $TotalHeaderPrinted = 0; my $CurrentHeader = ""; my $PrintCond = "unless (\$HeaderPrinted) {print \$CurrentHeader; \$HeaderPrinted = 1;}"; $CurrentHeader = "\n\nSEVERE ERRORS\n-------------"; $HeaderPrinted = 0; if ($SendmailStopped) { eval "$PrintCond"; print "\n\nSendmail IS NOT RUNNING!\ If you do not wish to run sendmail, delete the mail log\ file (such as /var/log/maillog) to suppress this message."; } my @TotalSevereError = (); my $SevereErrorIndex = 0; $TotalSevereError[0] = 0; if (keys %SysErr) { eval "$PrintCond"; print "\n\nSystem Error Messages:"; # don't sort, as error order may help foreach $User (keys %SysErr) { foreach $Reason (keys %{$SysErr{$User}}) { PrettyTimes(" $Reason", $SysErr{$User}{$Reason}); $TotalSevereError[$SevereErrorIndex] += $SysErr{$User}{$Reason}; } } } $TotalSevereError[++$SevereErrorIndex] = 0; if (keys %LostQueueFile) { eval "$PrintCond"; print "\n\nLost Queue Files:"; # don't sort and don't list counts (Queue ID is included) foreach $Reason (keys %LostQueueFile) { print "\n $Reason"; $TotalSevereError[$SevereErrorIndex] += $LostQueueFile{$Reason}; } } $TotalSevereError[++$SevereErrorIndex] = 0; if ($NoMoreSpace > 0) { eval "$PrintCond"; print "\n\nError \"No space left on device\" occurred $NoMoreSpace time(s)"; $TotalSevereError[$SevereErrorIndex] += $NoMoreSpace; } $TotalSevereError[++$SevereErrorIndex] = 0; my $TotalCount = 0; foreach $ErrorCount (@TotalSevereError) { if (defined $ErrorCount) { $TotalCount+= $ErrorCount; } } if ($TotalCount > 0) { print "\n\nTotal SEVERE ERRORS: $TotalCount"; } $TotalHeaderPrinted += $HeaderPrinted; $CurrentHeader = "\n\nSENDMAIL CONFIGURATION\n----------------------"; $HeaderPrinted = 0; if (keys %LowSpace) { eval "$PrintCond"; print "\n\nWarning: Low space when writing to:"; foreach $File (keys %LowSpace) { print "\n $File"; } } if ($DaemonThrottle > 0) { eval "$PrintCond"; print "\n\nDaemon started rejecting messages $DaemonThrottle times due to lack of space"; } if (keys %TLSFileMissing) { eval "$PrintCond"; print "\n\nWarning: STARTTLS file errors:"; foreach $TLSFile (sort keys %TLSFileMissing) { print "\n $TLSFile"; } } if (keys %StatFileError) { eval "$PrintCond"; print "\n\nWarning: Error opening statistics files:"; foreach $StatFile (sort keys %StatFileError) { print "\n $StatFile:"; foreach $StatError (keys %{$StatFileError{$StatFile}}) { print "\n $StatError"; } } } if ($NoMilterFilters > 0) { eval "$PrintCond"; print "\n\nNo active milter filters"; } if ($OutdatedAliasdb > 0) { eval "$PrintCond"; print "\n"; PrettyTimes("Aliases database out of date", $OutdatedAliasdb); } if (keys %WUnsafe) { print "\n\nUnsafe permissions:\n"; foreach $Directory (keys %WUnsafe) { print " In program " . $Directory . ":"; foreach $Cause (keys %{$WUnsafe{$Directory}}) { PrettyTimes(" $Cause", $WUnsafe{$Directory}{$Cause}); } } } if (keys %SaslError) { eval "$PrintCond"; print "\n\nSASL database Errors:\n"; foreach $File (sort {$a cmp $b} keys %SaslError) { print " In file $File:"; foreach $Error (sort {$a cmp $b} keys %{$SaslError{$File}}) { PrettyTimes(" $Error", $SaslError{$File}{$Error}); } } } if (keys %TooManyHops) { eval "$PrintCond"; print "\n\nToo many hops:"; foreach $ThisOne (sort keys %TooManyHops) { PrettyTimes(" $ThisOne", $TooManyHops{$ThisOne}); } } $TotalHeaderPrinted += $HeaderPrinted; $CurrentHeader = "\n\nSTATISTICS\n----------"; $HeaderPrinted = 0; if (($SendmailStarts or $BytesTransferred or $MsgsSent or $AddrRcpts) and ($Detail >= 1)) { eval "$PrintCond"; if ($SendmailStarts > 0) { print "\n\nSendmail was started $SendmailStarts time(s)"; } printf("\n\nMessages To Recipients:%11d", $MsgsSent); # Each explicitly addressed recipient in an email is counted as an # "Addressed Recipient" printf("\nAddressed Recipients:%13d", $AddrRcpts); printf("\nBytes Transferred:%16d", $BytesTransferred); # Messages with no valid recipients (for example, fails # some other check) are not delivered printf("\nMessages No Valid Rcpts:%10d", $MsgsNoRcpt); } if (($Detail >= 10) and $HeaderPrinted) { # eval $PrintCond not needed, because tested for $HeaderPrinted print "\n\nMessage Size Distribution:\n"; print "Range # Msgs KBytes\n"; $TotalNum = 0; # Initialise the Size distribution array my @SizeNames = ('0 - 10k', '10k - 20k', '20k - 50k', '50k - 100k', '100k - 500k', '500k - 1Mb', '1Mb - 2Mb', '2Mb - 5Mb', '5Mb - 10Mb', '10Mb+'); foreach $LastIndex (0..9) { $LastIndex2=9-$LastIndex; last if ($SizeDist[$LastIndex2]{'Bytes'} > 0); } foreach $ThisOne (0..$LastIndex2) { printf("%-12s %6d %10d\n", $SizeNames[$ThisOne], $SizeDist[$ThisOne]{'Num'}, $SizeDist[$ThisOne]{'Bytes'}/1024); $TotalNum += $SizeDist[$ThisOne]{'Num'}; $TotalBytes += $SizeDist[$ThisOne]{'Bytes'}; } print "----------------------------------\n"; printf("TOTAL %6d %10d\n", $TotalNum, $TotalBytes/1024); if ($TotalNum > 0) { printf("Avg. Size %10d\n", ($TotalBytes / $TotalNum)/1024); } } if (($Detail >= 5) and (keys %LargeMsgs)) { eval "$PrintCond"; print "\n\nLarge Messages (From \-\> To):"; foreach $ThisOne (sort keys %LargeMsgs) { PrettyTimes(" $ThisOne", ${LargeMsgs{$ThisOne}}); } } # Message recipients are the actual recipients - one for each # recipient to which to which a copy of email is sent if (($Detail >= 10) and (keys %Mailers)) { eval "$PrintCond"; my @DefinedMailers = ('smtp', 'esmtp', 'smtp8', 'dsmtp', 'relay', 'procmail', 'local', 'prog', '*file*'); print "\n\nMessage recipients per delivery agent:"; $TotalNum = 0; print "\nName # Rcpts"; # first we print the common mailers, to maintains some logical grouping foreach $MailerName (@DefinedMailers) { if ($Mailers{$MailerName}) { printf("\n%-12s %6d", $MailerName, $Mailers{$MailerName}); $TotalNum += $Mailers{$MailerName}; delete($Mailers{$MailerName}); } } # now we print all remaining mailers foreach $MailerName (keys %Mailers) { printf("\n%-12s %6d", $MailerName, $Mailers{$MailerName}); $TotalNum += $Mailers{$MailerName}; } printf("\n---------------------\nTOTAL: %6d", $TotalNum); if ($RelayLocalhost > 0) { printf("\nin addition to %6d relay", $RelayLocalhost); print "\n submission\(s\) from MSP"; } } if (($Detail >= 10) && (keys %ToList)) { eval "$PrintCond"; my $ToListCount = 0; #Set default -mgt my $ToListThreshold = $ENV{'sendmail_tolistthreshold'} || "10"; #Set sendmail_tolistthreshold = Null to suppress this report -mgt if ($ToListThreshold !~ m/NULL/i) { print "\n\nTop $ToListThreshold Email Recipients\n"; foreach my $ToAddr (sort {$ToList{$b}<=>$ToList{$a}} keys %ToList) { if ($ToListCount >= $ToListThreshold) { last; }; PrettyTimes(" " . $ToAddr, $ToList{$ToAddr}); $ToListCount++; } } } if (($Detail>=10) and (keys %MailBomber)) { eval "$PrintCond"; my $MailBombCount = 0; #Set up are defaults -mgt my $MailbombListThreshold = $ENV{'sendmail_mailbomblistthreshold'} || "50"; my $MailbombThreshold = $ENV{'sendmail_mailbombthreshold'} || "10"; foreach $ThisOne (sort {$MailBomber{$b}<=>$MailBomber{$a}} keys %MailBomber) { if ($MailBomber{$ThisOne} >= $MailbombThreshold and $MailBombCount < $MailbombListThreshold) { print "\n\nTop relays (recipients / connections - min $MailbombThreshold rcpts, max $MailbombListThreshold lines):" if ! $MailBombCount; printf("\n %s%5d / %4d", PrettyHost($ThisOne, 63), $MailBomber{$ThisOne}, $MailBomberConn{$ThisOne}); } $MailBombCount++; } } if (($Detail >= 5) and (keys %LoadAvg)) { eval "$PrintCond"; print "\n\nWarning!!!: "; print "Connections Rejected due to high load average $LoadAvgReject Time(s)"; my $MaxLoadAvg = 0; foreach $Load (sort keys %LoadAvg) { PrettyTimes(" Load Avg $Load", $LoadAvg{$Load}); if ($Load > $MaxLoadAvg) { $MaxLoadAvg = $Load; } } print "\n Max. Load Avg reached: $MaxLoadAvg"; } if (($Detail >= 5) and ($LoadAvgQueueSkip > 0)) { eval "$PrintCond"; print "\n"; PrettyTimes("Aborted/skipped mail queue run - load average too high", $LoadAvgQueueSkip); } if ($Detail >= 10) { foreach $StarttlsMode ('server', 'client') { if (keys %{$Starttls{$StarttlsMode}}) { eval "$PrintCond"; print "\n\nFor STARTTLS in $StarttlsMode mode,"; if (defined $Starttls{$StarttlsMode}{'OK'}) { PrettyTimes(" Requests were authenticated", $Starttls{$StarttlsMode}{'OK'}); } if (defined $Starttls{$StarttlsMode}{'TEMP'}) { PrettyTimes(" Requests had temporary errors", $Starttls{$StarttlsMode}{'TEMP'}); } if (defined $Starttls{$StarttlsMode}{'PROTOCOL'}) { PrettyTimes(" Requests had SMTP protocol errors", $Starttls{$StarttlsMode}{'PROTOCOL'}); } if (defined $Starttls{$StarttlsMode}{'SOFTWARE'}) { PrettyTimes(" Requests failed STARTTLS handshake", $Starttls{$StarttlsMode}{'SOFTWARE'}); } if (defined $Starttls{$StarttlsMode}{'NO'}) { PrettyTimes(" No cert was presented", $Starttls{$StarttlsMode}{'NO'}); } if (defined $Starttls{$StarttlsMode}{'NOT'}) { PrettyTimes(" No cert was requested", $Starttls{$StarttlsMode}{'NOT'}); } if (defined $Starttls{$StarttlsMode}{'FAIL'}) { PrettyTimes(" Cert was presented, but not verified", $Starttls{$StarttlsMode}{'FAIL'}); } if (defined $Starttls{$StarttlsMode}{'NONE'}) { PrettyTimes(" STARTTLS was not performed", $Starttls{$StarttlsMode}{'NONE'}); } if (defined $Starttls{$StarttlsMode}{'Other'}) { PrettyTimes(" Requests had unknown errors", $Starttls{$StarttlsMode}{'Other'}); } } } if (defined keys %StarttlsCipher) { eval "$PrintCond"; print "\n\nSTARTTLS used the following encryption mechanisms"; foreach $StarttlsCipherEntry (sort keys %StarttlsCipher) { PrettyTimes(" " . $StarttlsCipherEntry, $StarttlsCipher{$StarttlsCipherEntry}); } } if ($NoCommonName) { eval "$PrintCond"; # The following is a frequent occurrence, but not an error print "\n"; PrettyTimes("For STARTTLS, no CommonName given", $NoCommonName); } } if (($Detail >= 5) and (keys %ETRNs)) { eval "$PrintCond"; print "\n\nETRNs Received:"; foreach $ThisOne (sort keys %ETRNs) { PrettyTimes(" $ThisOne", $ETRNs{$ThisOne}); } } if(($Detail >= 10) and (keys %ReturnReceipts > 0)) { eval "$PrintCond"; print "\n\nSuccessful Return Receipts:"; foreach $ThisOne (sort keys %ReturnReceipts) { PrettyTimes(" $ThisOne", $ReturnReceipts{$ThisOne}); } } if (($Detail >= 5) and (keys %MilterHeaderCount)) { eval "$PrintCond"; print "\n\nHeaders modified by Milter:"; foreach $Header (sort keys %MilterHeaderCount) { PrettyTimes( " $Header", $MilterHeaderCount{$Header}); } } if (($Detail >= 3) and (keys %MilterDeferrals)) { eval "$PrintCond"; print "\n\nMilter transient failures:"; foreach $Reason (sort keys %MilterDeferrals) { PrettyTimes( " $Reason", $MilterDeferrals{$Reason}); } } if (($Detail >= 10) and (keys %DNSMap)) { print "\n\nDNS Map lookups:"; foreach $Domain (sort keys %DNSMap) { foreach $IP (sort keys %{$DNSMap{$Domain}}) { PrettyTimes( " $Domain => $IP", $DNSMap{$Domain}{$IP}); } } } if (($Detail >= 10) and (keys %SenderIDResults)) { print "\n\nSender-ID Results:"; foreach my $SenderIDStatus (sort keys %SenderIDResults) { PrettyTimes(" $SenderIDStatus", $SenderIDResults{$SenderIDStatus}); } } if (($Detail >= 10) and (keys %SPFResults)) { print "\n\nSPF Results:"; foreach my $SPFStatus (sort keys %SPFResults) { PrettyTimes(" $SPFStatus", $SPFResults{$SPFStatus}); } } $TotalHeaderPrinted += $HeaderPrinted; $CurrentHeader = "\n\nSMTP SESSION, MESSAGE, OR RECIPIENT ERRORS\n------------------------------------------"; $HeaderPrinted = 0; my $ErrorIndex = 0; my @TotalError = (); $TotalError[0] = 0; # SMTP Errors if (keys %TLSConnectFailed) { eval "$PrintCond" if ($Detail >= 3); print "\n\nTLS Connect Failed" if ($Detail >=3); foreach $TLSReason (sort keys %TLSConnectFailed) { PrettyTimes(" " . $TLSReason, $TLSConnectFailed{$TLSReason}) if ($Detail >= 5); $TotalError[$ErrorIndex] += $TLSConnectFailed{$TLSReason}; } print "\n\tTotal: $TotalError[$ErrorIndex]" if( $Detail >=3 ); } $TotalError[++$ErrorIndex] = 0; if (keys %TLSAcceptFailed) { eval "$PrintCond" if ($Detail >= 3); print "\n\nTLS Failed Access" if ($Detail >=3); foreach $TLSReason (sort keys %TLSAcceptFailed) { print "\n $TLSReason" if ($Detail >= 5); foreach $TLSFrom (sort keys %{$TLSAcceptFailed{$TLSReason}}) { PrettyTimes(" " . PrettyHost($TLSFrom, 59), $TLSAcceptFailed{$TLSReason}{$TLSFrom}) if ($Detail >= 5); $TotalError[$ErrorIndex] += $TLSAcceptFailed{$TLSReason}{$TLSFrom}; } } print "\n\tTotal: $TotalError[$ErrorIndex]" if ($Detail >= 3); } $TotalError[++$ErrorIndex] = 0; if (keys %TLSErrno) { eval "$PrintCond" if ($Detail >= 3); print "\n\nSTARTTLS Errors" if ($Detail >= 3); foreach $Errno (sort {$a <=> $b} keys %TLSErrno) { PrettyTimes(" Error Code " . sprintf("%3d: ", $Errno) . strerror($Errno), $TLSErrno{$Errno}) if ($Detail >=5); $TotalError[$ErrorIndex] += $TLSErrno{$Errno}; } } $TotalError[++$ErrorIndex] = 0; if (keys %BadAuth) { eval "$PrintCond" if ($Detail >= 3); print "\n\nBad AUTH mechanism requests" if ($Detail >= 3); foreach $Auth (sort keys %BadAuth) { PrettyTimes(" " . $Auth, $BadAuth{$Auth}) if ($Detail >= 5); $TotalError[$ErrorIndex] += $BadAuth{$Auth}; } print "\n\tTotal: $TotalError[$ErrorIndex]" if( $Detail >=3 ); } $TotalError[++$ErrorIndex] = 0; if (keys %AUTHfailure) { eval "$PrintCond" if ($Detail >= 3); print "\n\nFailed AUTH requests" if ($Detail >= 3); foreach $Host (sort keys %AUTHfailure) { print "\n From " . PrettyHost($Host, 58) if ($Detail >=5); foreach $Auth (sort keys %{$AUTHfailure{$Host}}) { PrettyTimes(" $Auth", $AUTHfailure{$Host}{$Auth}) if ($Detail >= 5); $TotalError[$ErrorIndex] += $AUTHfailure{$Host}{$Auth}; } } print "\n\tTotal: $TotalError[$ErrorIndex]" if ($Detail >= 3); } $TotalError[++$ErrorIndex] = 0; if (keys %AUTHnouser) { eval "$PrintCond" if ($Detail >= 3); print "\n\nFailed AUTH requests because of No User" if ($Detail >= 3); my $UserCount = CountOrder(%AUTHnouser); foreach $User (sort $UserCount keys %AUTHnouser) { PrettyTimes(" $User", $AUTHnouser{$User}) if ($Detail >=5); $TotalError[$ErrorIndex] += $AUTHnouser{$User}; } print "\n\tTotal: $TotalError[$ErrorIndex]" if ($Detail >= 3); } $TotalError[++$ErrorIndex] = 0; if($RemoteProtocolError > 0) { eval "$PrintCond" if ($Detail >= 3); print "\n\n" . $RemoteProtocolError . " Remote Protocol Errors" if ($Detail >= 3); $TotalError[$ErrorIndex] += $RemoteProtocolError } $TotalError[++$ErrorIndex] = 0; if (keys %AttackAttempt) { eval "$PrintCond"; print "\n\nWARNING!!!! Possible Attack:"; foreach $Host (sort {$a cmp $b} keys %AttackAttempt) { print "\n Attempt from $Host with:"; foreach $Attack (sort {$a cmp $b} keys %{$AttackAttempt{$Host}}) { PrettyTimes(" $Attack", $AttackAttempt{$Host}{$Attack}); $TotalError[$ErrorIndex] += $AttackAttempt{$Host}{$Attack}; } } print "\n\tTotal: $TotalError[$ErrorIndex]"; } $TotalError[++$ErrorIndex] = 0; if (keys %KnownSpammer) { eval "$PrintCond" if ($Detail >= 3); #Set Threshold default my $KnownSpammerThreshold = $ENV{'sendmail_knownspammerthreshold'} || "1"; my $KnownSpammerCount = CountOrder(%KnownSpammer); print "\n\nMail attempts from known spammers: [Occurrences >= $KnownSpammerThreshold]" if ($Detail >= 3); foreach $ThisOne (sort $KnownSpammerCount keys %KnownSpammer) { if ($KnownSpammer{$ThisOne} >= $KnownSpammerThreshold) { PrettyTimes(" " . PrettyHost($ThisOne, 63), $KnownSpammer{$ThisOne}) if ($Detail >= 5); } $TotalError[$ErrorIndex] += $KnownSpammer{$ThisOne}; } print "\n\tTotal: $TotalError[$ErrorIndex]" if ($Detail >= 3); } $TotalError[++$ErrorIndex] = 0; if (keys %RelayDenied) { eval "$PrintCond" if ($Detail >= 3); #Set Threshold default my $RelayDeniedThreshold = $ENV{'sendmail_relaydeniedthreshold'} || "1"; print "\n\nRelaying denied: [Occurrences >= $RelayDeniedThreshold]" if ($Detail >= 3); my $RelayCount = TotalCountOrder(%RelayDenied); foreach $Relay (sort $RelayCount keys %RelayDenied) { $RelayDeniedCount = 0; my $DestCount = CountOrder(%{$RelayDenied{$Relay}}); foreach $Dest (sort $DestCount keys %{$RelayDenied{$Relay}}) { $RelayDeniedCount += $RelayDenied{$Relay}{$Dest}; $TotalError[$ErrorIndex] += $RelayDenied{$Relay}{$Dest}; } if ($RelayDeniedCount >= $RelayDeniedThreshold) { printf("\n From %s", PrettyHost($Relay, 58)) if ($Detail >=5); foreach $Dest (keys %{$RelayDenied{$Relay}}) { PrettyTimes(" to " . $Dest, $RelayDenied{$Relay}{$Dest}) if ($Detail >= 5); } } } print "\n\tTotal: $TotalError[$ErrorIndex]" if ($Detail >= 3); } $TotalError[++$ErrorIndex] = 0; if (keys %CheckMailReject) { eval "$PrintCond" if ($Detail >= 3); #Set Threshold default my $CheckMailRejectThreshold = $ENV{'sendmail_checkmailrejectthreshold'} || "1"; print "\n\nRejected incoming mail: [Occurrences >= $CheckMailRejectThreshold]" if ($Detail >= 3); foreach $ThisOne (keys %CheckMailReject) { if ($CheckMailReject{$ThisOne} >= $CheckMailRejectThreshold) { PrettyTimes(" $ThisOne", $CheckMailReject{$ThisOne}) if ($Detail >= 5); } $TotalError[$ErrorIndex] += $CheckMailReject{$ThisOne}; } print "\n\tTotal: $TotalError[$ErrorIndex]" if ($Detail >= 3); } $TotalError[++$ErrorIndex] = 0; if (keys %PREGreeting) { eval "$PrintCond" if ($Detail >= 3); #Set up default -mgt my $PREGreetingThreshold = $ENV{'sendmail_pregreetingthreshold'} || "1"; my $PREGreetingCount = CountOrder(%PREGreeting); print "\n\nGreet Pause Rejections: [Occurrences >= $PREGreetingThreshold]" if ($Detail >= 3); foreach my $ip (sort $PREGreetingCount keys %PREGreeting) { PrettyTimes(" " . PrettyHost($ip, 63), $PREGreeting{$ip}) if ($Detail >= 5) && ($PREGreeting{$ip} >= $PREGreetingThreshold); $TotalError[$ErrorIndex] += $PREGreeting{$ip}; } print "\n\tTotal: $TotalError[$ErrorIndex]" if ($Detail >= 3); } $TotalError[++$ErrorIndex] = 0; if (keys %LostInputChannel) { eval "$PrintCond" if ($Detail >= 3); #Set Threshold default my $LostInputChannelThreshold = $ENV{'sendmail_lostinputchannelthreshold'} || "1"; my $LostInputChannelCount = CountOrder(%LostInputChannel); print "\n\nLost input channel: [Occurrences >= $LostInputChannelThreshold]" if ($Detail >= 3); foreach $ThisOne (sort $LostInputChannelCount keys %LostInputChannel) { if ($LostInputChannel{$ThisOne} >= $LostInputChannelThreshold) { PrettyTimes(" " . PrettyHost($ThisOne, 63), $LostInputChannel{$ThisOne}) if ($Detail >= 5); } $TotalError[$ErrorIndex] += $LostInputChannel{$ThisOne}; } print "\n\tTotal: $TotalError[$ErrorIndex]" if ($Detail >= 3); } $TotalError[++$ErrorIndex] = 0; if (keys %DummyConnection) { eval "$PrintCond" if ($Detail >= 3); #Set Threshold default my $DummyConnectionThreshold = $ENV{'sendmail_dummyconnectionthreshold'} || "1"; my $DummyConnectionCount = CountOrder(%DummyConnection); print "\n\nClient quit before communicating: [Occurrences >= $DummyConnectionThreshold]" if ($Detail >= 3); foreach $ThisOne (sort $DummyConnectionCount keys %DummyConnection) { if ($DummyConnection{$ThisOne} >= $DummyConnectionThreshold) { PrettyTimes(" " . PrettyHost($ThisOne, 63), $DummyConnection{$ThisOne}) if ($Detail >= 5); } $TotalError[$ErrorIndex] += $DummyConnection{$ThisOne}; } print "\n\tTotal: $TotalError[$ErrorIndex]" if ($Detail >= 3); } $TotalError[++$ErrorIndex] = 0; if (keys %DomainErrors) { eval "$PrintCond" if ($Detail >= 3); #Set up default -mgt my $DomainErrorsThreshold = $ENV{'sendmail_domainerrorsthreshold'} || "1"; print "\n\nUnresolveable or non-existent domains: [Occurrences >= $DomainErrorsThreshold]" if ($Detail >= 3); my $count = TotalCountOrder(%DomainErrors); foreach $ThisOne (sort $count keys %DomainErrors) { my $subcount=CountOrder(%{$DomainErrors{$ThisOne}}); my $sublist; my $subcounter = 0; foreach $User (sort $subcount keys %{$DomainErrors{$ThisOne}}) { $subcounter += $DomainErrors{$ThisOne}{$User}; } if ( $subcounter >= $DomainErrorsThreshold) { PrettyTimes(" From " . PrettyHost($ThisOne, 58), $subcounter) if ($Detail >=5); foreach $User (sort $subcount keys %{$DomainErrors{$ThisOne}}) { PrettyTimes(" $User", $DomainErrors{$ThisOne}{$User}) if ($Detail >= 10); } } $TotalError[$ErrorIndex] += $subcounter; } print "\n\tTotal: $TotalError[$ErrorIndex]" if ($Detail >= 3); } $TotalError[++$ErrorIndex] = 0; if (keys %AuthWarns) { eval "$PrintCond" if ($Detail >= 3); print "\n\nAuthentication warnings:" if ($Detail >= 3); foreach $ThisOne (sort keys %AuthWarns) { PrettyTimes(" $ThisOne", $AuthWarns{$ThisOne}) if ($Detail >= 5);; $TotalError[$ErrorIndex] += $AuthWarns{$ThisOne}; } print "\n\tTotal: $TotalError[$ErrorIndex]" if ($Detail >= 3); } $TotalError[++$ErrorIndex] = 0; if (keys %Timeouts) { eval "$PrintCond" if ($Detail >= 3); #Set up default -mgt my $TimeoutThreshold = $ENV{'sendmail_timeoutthreshold'} || "1"; print "\n\nTimeouts: [Occurrences >= $TimeoutThreshold]" if ($Detail >= 3); my $TimeoutCount = CountOrder(%Timeouts); foreach $ThisOne (sort $TimeoutCount keys %Timeouts) { PrettyTimes(" $ThisOne", $Timeouts{$ThisOne}) if (($Detail >= 5) && ($Timeouts{$ThisOne} >= $TimeoutThreshold)); $TotalError[$ErrorIndex] += $Timeouts{$ThisOne}; } print "\n\tTotal: $TotalError[$ErrorIndex]" if ($Detail >= 3); } $TotalError[++$ErrorIndex] = 0; if (keys %Abuse) { eval "$PrintCond" if ($Detail >= 3); my $TotalAbuse; print "\n\nRejected VRFY/EXPN/ETRN (host,ruser):" if ($Detail >= 3); foreach $Host (sort keys %Abuse) { print "\n $Host" if ($Detail >= 5); $TotalAbuse = 0; foreach $Luser (sort keys %{$Abuse{$Host}}) { print "\n $Luser:" if ($Detail >= 5); foreach $RejCmd (sort keys %{$Abuse{$Host}{$Luser}}) { PrettyTimes(" $RejCmd", $Abuse{$Host}{$Luser}{$RejCmd}) if ($Detail >= 5); $TotalAbuse += $Abuse{$Host}{$Luser}{$RejCmd}; } } print "\n Total per host: $TotalAbuse" if ($Detail >= 5); $TotalError[$ErrorIndex] += $TotalAbuse; } print "\n\tTotal: $TotalError[$ErrorIndex]" if ($Detail >= 3); } $TotalError[++$ErrorIndex] = 0; if (keys %CommandUnrecognized) { eval "$PrintCond" if ($Detail >= 3); print "\n\nSet(s) of unrecognized SMTP commands:" if ($Detail >= 3); foreach $ThisOne (keys %CommandUnrecognized) { print "\n From QueueID: $ThisOne" if ($Detail >= 5); print "\n$CommandUnrecognized{$ThisOne}" if ($Detail >= 5); $TotalError[$ErrorIndex] ++; } print "\n\tTotal: $TotalError[$ErrorIndex]" if ($Detail >= 3); } $TotalError[++$ErrorIndex] = 0; if (keys %StarttlsCert) { eval "$PrintCond" if ($Detail >= 3); print "\n\nSTARTTLS failed to verify certificates:" if ($Detail >= 3); foreach $ThisOne (sort keys %StarttlsCert) { printf "\n %s:", $ThisOne if ($Detail >= 5); foreach $CommonName (sort keys %{$StarttlsCert{$ThisOne}}) { PrettyTimes(" CN: $CommonName", $StarttlsCert{$ThisOne}{$CommonName}) if ($Detail >= 5); $TotalError[$ErrorIndex] += $StarttlsCert{$ThisOne}{$CommonName}; } } print "\n\tTotal: $TotalError[$ErrorIndex]" if ($Detail >= 3); } $TotalError[++$ErrorIndex] = 0; # Message errors if ($OverSize > 0) { eval "$PrintCond" if ($Detail >= 3); print "\n\nRejected $OverSizeBytes bytes in $OverSize message(s)" if ($Detail >= 3); $TotalError[$ErrorIndex] += $OverSize; } $TotalError[++$ErrorIndex] = 0; if (keys %CollectError) { eval "$PrintCond" if ($Detail >= 3); #Set Threshold default per Reason my $CollectErrorThreshold = $ENV{'sendmail_collecterrorthreshold'} || "1"; print "\n\nErrors during Collect:" if ($Detail >= 3); foreach $Reason (sort keys %CollectError) { print "\n $Reason: [Occurrences >= $CollectErrorThreshold]" if ($Detail >= 5); my $colerror = 0; foreach $Source (keys %{$CollectError{$Reason}}) { if ($CollectError{$Reason}{$Source} >= $CollectErrorThreshold) { PrettyTimes(" $Source", $CollectError{$Reason}{$Source}) if ($Detail >= 5); } $colerror = $colerror + $CollectError{$Reason}{$Source}; } $TotalError[$ErrorIndex] += $colerror; } print "\n\tTotal: $TotalError[$ErrorIndex]" if ($Detail >= 3); } $TotalError[++$ErrorIndex] = 0; if (keys %BadRcptThrottle) { eval "$PrintCond" if ($Detail >= 3); my $BadRcptThrottleThreshold = $ENV{'sendmail_badrcptthrottlethreshold'} || "1"; my $BadRcptCount = CountOrder(%BadRcptThrottle); print "\n\nClient submitted too many bad recipients: [Occurrences >= $BadRcptThrottleThreshold]" if ($Detail >= 3); foreach $ThisOne (sort $BadRcptCount keys %BadRcptThrottle) { PrettyTimes(" " . PrettyHost($ThisOne,61), $BadRcptThrottle{$ThisOne}) if ($Detail >= 5) && ( $BadRcptThrottle{$ThisOne} >= $BadRcptThrottleThreshold ); $TotalError[$ErrorIndex] += $BadRcptThrottle{$ThisOne}; } print "\n\tTotal: $TotalError[$ErrorIndex]" if ($Detail >= 3); } $TotalError[++$ErrorIndex] = 0; if ($TooManyRcpts > 0) { eval "$PrintCond" if ($Detail >= 3); print "\n\n$TooManyRcpts messages with too many recipients" if ($Detail >= 3); $TotalError[$ErrorIndex] += $TooManyRcpts; } $TotalError[++$ErrorIndex] = 0; if (keys %LargeHdrs) { eval "$PrintCond" if ($Detail >= 3); print "\n\nToo large headers from:" if ($Detail >= 3); foreach $Host ( sort {$LargeHdrs{$b}<=>$LargeHdrs{$a}} keys %LargeHdrs ) { PrettyTimes(" $Host", $LargeHdrs{$Host}) if ($Detail >= 5); $TotalError[$ErrorIndex] += $LargeHdrs{$Host}; } print "\n\tTotal: $TotalError[$ErrorIndex]" if ($Detail >= 3); } $TotalError[++$ErrorIndex] = 0; if (keys %AddressError) { eval "$PrintCond" if ($Detail >= 3); print "\n\nErrors in mail address:" if ($Detail >= 3); foreach $Reason (sort {$a cmp $b} keys %AddressError) { print "\n $Reason:" if ($Detail >= 5); foreach $Address (sort {$a cmp $b} keys %{$AddressError{$Reason}}) { PrettyTimes(" $Address", $AddressError{$Reason}{$Address}) if ($Detail >= 5); $TotalError[$ErrorIndex] += $AddressError{$Reason}{$Address}; } } print "\n\tTotal: $TotalError[$ErrorIndex]" if ($Detail >= 3); } $TotalError[++$ErrorIndex] = 0; if (keys %Quarantined) { eval "$PrintCond" if ($Detail >= 3); #Set Threshold default my $QuarantinedThreshold = $ENV{'sendmail_quarantinedthreshold'} || "1"; my $QuarantinedCount = CountOrder(%Quarantined); print "\n\nMessages quarantined by milter: [Occurrences >= $QuarantinedThreshold]" if ($Detail >= 3); foreach $ThisOne (sort $QuarantinedCount keys %Quarantined) { if ($Quarantined{$ThisOne} >= $QuarantinedThreshold) { PrettyTimes(" $ThisOne", $Quarantined{$ThisOne}) if ($Detail >= 5); } $TotalError[$ErrorIndex] += $Quarantined{$ThisOne}; } print "\n\tTotal: $TotalError[$ErrorIndex]" if ($Detail >= 3); } $TotalError[++$ErrorIndex] = 0; # Recipient errors if (keys %SentTimeouts) { eval "$PrintCond" if ($Detail >= 3); print "\n\nMessages delayed by recipients:" if ($Detail >= 3); foreach $ThisOne (keys %SentTimeouts) { PrettyTimes(" $ThisOne", $SentTimeouts{$ThisOne}) if ($Detail >=5); $TotalError[$ErrorIndex] += $SentTimeouts{$ThisOne}; } print "\n\tTotal: $TotalError[$ErrorIndex]" if ($Detail >= 3); } $TotalError[++$ErrorIndex] = 0; if (keys %UnknownUsers) { eval "$PrintCond" if ($Detail >= 3); %SortedUsers = (); foreach $Usr (sort keys %UnknownUsers) { foreach $QueueID (sort keys %{ $UnknownUsers{$Usr} }) { $SortedUsers{$Usr}{$Msgs{$QueueID}{"Relay"}}++; $TotalError[$ErrorIndex] ++; } } my $UnknownUsersThreshold = $ENV{'sendmail_unknownusersthreshold'} || "1"; if ($UnknownUsersThreshold) { print "\n\nUnknown local users: [Occurrences >= $UnknownUsersThreshold]" if ($Detail >= 3); } else { print "\n\nUnknown local users:" if ($Detail >= 3); } if ($Detail >= 5) { my $count = TotalCountOrder( %SortedUsers ); foreach $Usr (sort $count keys %SortedUsers) { my $subcount = CountOrder( %{$SortedUsers{$Usr}} ); my $UnknownUsersCount = 0; foreach $RelayHost (sort $subcount keys %{ $SortedUsers{$Usr} }) { $UnknownUsersCount += $SortedUsers{$Usr}{$RelayHost}; } if ($UnknownUsersCount >= $UnknownUsersThreshold) { PrettyTimes(" " . $Usr, $UnknownUsersCount); if ($Detail >= 15) { foreach $RelayHost (sort $subcount keys %{ $SortedUsers{$Usr} }) { PrettyTimes(" from " . PrettyHost($RelayHost, 54), $SortedUsers{$Usr}{$RelayHost}); } } } } } print "\n\tTotal: $TotalError[$ErrorIndex]" if ($Detail >= 3); } $TotalError[++$ErrorIndex] = 0; if (keys %UnknownUsersCheckRcpt) { eval "$PrintCond" if ($Detail >= 3); %SortedUsers = (); foreach $Usr (sort keys %UnknownUsersCheckRcpt) { foreach $QueueID (sort keys %{ $UnknownUsersCheckRcpt{$Usr} }) { $SortedUsers{$Usr}{$Msgs{$QueueID}{"Relay"}}++; $TotalError[$ErrorIndex] ++; } } my $UnknownUsersThreshold = $ENV{'sendmail_unknownusersthreshold'} || "1"; if ($UnknownUsersThreshold) { print "\n\nUnknown users: [Occurrences >= $UnknownUsersThreshold]" if ($Detail >= 3); } else { print "\n\nUnknown users:" if ($Detail >= 3); } if ($Detail >= 5) { my $count = TotalCountOrder( %SortedUsers ); foreach $Usr (sort $count keys %SortedUsers) { my $subcount = CountOrder( %{$SortedUsers{$Usr}} ); my $UnknownUsersCount = 0; foreach $RelayHost (sort $subcount keys %{ $SortedUsers{$Usr} }) { $UnknownUsersCount += $SortedUsers{$Usr}{$RelayHost}; } if ($UnknownUsersCount >= $UnknownUsersThreshold) { PrettyTimes(" " . $Usr, $UnknownUsersCount); if ($Detail >= 15) { foreach $RelayHost (sort $subcount keys %{ $SortedUsers{$Usr} }) { PrettyTimes(" from " . PrettyHost($RelayHost, 54), $SortedUsers{$Usr}{$RelayHost}); } } } } } print "\n\tTotal: $TotalError[$ErrorIndex]" if ($Detail >= 3); } $TotalError[++$ErrorIndex] = 0; if (keys %DisabledMailbox) { eval "$PrintCond" if ($Detail >= 3); %SortedUsers = (); foreach $Usr (sort keys %DisabledMailbox) { foreach $QueueID (sort keys %{ $DisabledMailbox{$Usr} }) { $SortedUsers{$Usr}{$Msgs{$QueueID}{"Relay"}}++; $TotalError[$ErrorIndex] ++; } } print "\n\nDisabled mailboxes:" if ($Detail >= 3); foreach $Usr (sort keys %SortedUsers) { print "\n $Usr" if ($Detail >= 5); foreach $RelayHost (sort keys %{ $SortedUsers{$Usr} }) { PrettyTimes(" from " . PrettyHost($RelayHost, 54), $SortedUsers{$Usr}{$RelayHost}) if ($Detail >= 5); } } print "\n\tTotal: $TotalError[$ErrorIndex]" if ($Detail >= 3); } $TotalError[++$ErrorIndex] = 0; if (keys %CheckRcptReject) { eval "$PrintCond" if ($Detail >= 3); #Set Threshold default my $CheckRcptRejectThreshold = $ENV{'sendmail_checkrcptrejectthreshold'} || "1"; print "\n\nRejected mail: [Occurrences >= $CheckRcptRejectThreshold]" if ($Detail >= 3); foreach $ThisOne (keys %CheckRcptReject) { if ($CheckRcptReject{$ThisOne} >= $CheckRcptRejectThreshold) { PrettyTimes(" $ThisOne", $CheckRcptReject{$ThisOne}) if ($Detail >= 5); } $TotalError[$ErrorIndex] += $CheckRcptReject{$ThisOne}; } print "\n\tTotal: $TotalError[$ErrorIndex]" if ($Detail >= 3); } $TotalError[++$ErrorIndex] = 0; if (keys %StatRejected) { eval "$PrintCond" if ($Detail >= 3); print "\n\nMail Rejected:" if ($Detail >= 3); foreach $Reason (sort keys %StatRejected) { print "\n $Reason:" if ($Detail >= 5); foreach $ToUser (keys %{$StatRejected{$Reason}}) { PrettyTimes(" " . $ToUser, $StatRejected{$Reason}{$ToUser}) if ($Detail >= 5); $TotalError[$ErrorIndex] += $StatRejected{$Reason}{$ToUser}; } } print "\n\tTotal: $TotalError[$ErrorIndex]" if ($Detail >= 3); } $TotalError[++$ErrorIndex] = 0; if (keys %StatDeferred) { eval "$PrintCond" if ($Detail >= 3); print "\n\nMail Deferred:" if ($Detail >= 3); foreach $Reason (sort keys %StatDeferred) { print "\n $Reason" if ($Detail >= 5); foreach $ToUser (keys %{$StatDeferred{$Reason}}) { PrettyTimes(" To: $ToUser", $StatDeferred{$Reason}{$ToUser}) if ($Detail >= 5); $TotalError[$ErrorIndex] += $StatDeferred{$Reason}{$ToUser}; } } print "\n\tTotal: $TotalError[$ErrorIndex]" if ($Detail >= 3); } $TotalError[++$ErrorIndex] = 0; if (keys %ForwardErrors) { eval "$PrintCond" if ($Detail >= 3); print "\n\nForwarding errors:" if ($Detail >= 3); my $FECount = CountOrder(%ForwardErrors); foreach $ThisOne (sort $FECount keys %ForwardErrors) { PrettyTimes(" $ThisOne", $ForwardErrors{$ThisOne}) if ($Detail >= 5); $TotalError[$ErrorIndex] += $ForwardErrors{$ThisOne}; } print "\n\tTotal: $TotalError[$ErrorIndex]" if ($Detail >= 3); } $TotalError[++$ErrorIndex] = 0; # Other errors not originating in base (stock) sendmail distribution if (keys %BlackHoled) { eval "$PrintCond" if ($Detail >= 3); print "\n\nBlackHole Totals:" if ($Detail >= 3); foreach $ThisOne (sort keys %BlackHoles) { PrettyTimes(" $ThisOne", $BlackHoles{$ThisOne}) if ($Detail >= 5); $TotalError[$ErrorIndex] += $BlackHoles{$ThisOne}; } if ($Detail >= 10) { print "\n\nBlackholed:"; my $BlackHoleThreshold = $ENV{'sendmail_blackholethreshold'} || "1"; foreach $ThisOne (sort keys %BlackHoled) { if ($BlackHoled{$ThisOne} >= $BlackHoleThreshold) { PrettyTimes(" $ThisOne", $BlackHoled{$ThisOne}); } } } print "\n\tTotal: $TotalError[$ErrorIndex]" if ($Detail >= 3); } $TotalError[++$ErrorIndex] = 0; if($XS4ALL > 0) { eval "$PrintCond" if ($Detail >= 3); print "\n\n$XS4ALL messages discarded from XS4ALL" if ($Detail >= 3); $TotalError[$ErrorIndex] += $XS4ALL; } $TotalError[++$ErrorIndex] = 0; if ($CantCreateOutput > 0) { eval "$PrintCond" if ($Detail >= 3); print "\n\nCan't create output $CantCreateOutput Time(s)" if ($Detail >= 3); $TotalError[$ErrorIndex] += $CantCreateOutput; } $TotalError[++$ErrorIndex] = 0; if (keys %MailRejected) { eval "$PrintCond" if ($Detail >= 3); print "\n\nMail was rejected because of the following entries in the access database:" if ($Detail >= 3); foreach $ThisOne (sort keys %MailRejected) { PrettyTimes(" $ThisOne", $MailRejected{$ThisOne}) if ($Detail >= 5); $TotalError[$ErrorIndex] += $MailRejected{$ThisOne}; } print "\n\tTotal: $TotalError[$ErrorIndex]" if ($Detail >= 3); } $TotalError[++$ErrorIndex] = 0; if (keys %RelayReject) { eval "$PrintCond" if ($Detail >= 3); print "\n\nWe do not relay for these (host,ruser,luser):" if ($Detail >= 3);; foreach $Host (sort keys %RelayReject) { print "\n $Host" if ($Detail >= 5); foreach $Ruser (sort keys %{ $RelayReject{$Host} }) { print "\n $Ruser" if ($Detail >= 5); foreach $Luser (sort keys %{$RelayReject{$Host}{$Ruser}}) { printf "\n %-30s %i", $Luser,$RelayReject{$Host}{$Ruser}{$Luser} if ($Detail >= 5); $TotalError[$ErrorIndex] += $RelayReject{$Host}{$Ruser}{$Luser}; } } } print "\n\tTotal: $TotalError[$ErrorIndex]" if ($Detail >= 3);; } $TotalError[++$ErrorIndex] = 0; if (keys %NotLocal) { eval "$PrintCond" if ($Detail >= 3); print "\n\nAddress not local from these (host, user):" if ($Detail >= 3);; foreach $Host (sort keys %NotLocal ) { print "\n $Host" if ($Detail >= 5); foreach $Luser (sort keys %{ $NotLocal{$Host} }) { printf "\n %-30s %i",$Luser,$NotLocal{$Host}{$Luser} if ($Detail >= 5); $TotalError[$ErrorIndex] += $NotLocal{$Host}{$Luser}; } } print "\n\tTotal: $TotalError[$ErrorIndex]" if ($Detail >= 3);; } $TotalError[++$ErrorIndex] = 0; if (keys %RuleSets) { print "\n\nRuleset violations:"; foreach $Reason (sort keys %RuleSets) { PrettyTimes(" $Reason", $RuleSets{$Reason}); $TotalError[$ErrorIndex] += $RuleSets{$Reason}; } } $TotalError[++$ErrorIndex] = 0; eval $ReportFilter; if ($@) { print $@; print "While processing ReportFilter:\n$ReportFilter\n"; } $TotalCount = 0; foreach $ErrorCount (@TotalError) { if (defined $ErrorCount) { $TotalCount += $ErrorCount; } } if ( ($TotalCount > 0) && ($Detail >= 3)) { eval "$PrintCond"; print "\n\nSummary of SMTP Session, Message, and Recipient Errors handled by Sendmail:"; print "\n\tTotal: $TotalCount"; } if (keys %MilterErrors) { eval "$PrintCond"; print "\n\nMilter Errors:\n"; foreach my $Milter (sort {$a cmp $b} keys %MilterErrors) { print " $Milter:\n"; foreach $Error (sort {$a cmp $b} keys %{$MilterErrors{$Milter}}) { PrettyTimes(" $Error", $MilterErrors{$Milter}{$Error}); } } } if (keys %OtherList) { $HeaderPrinted = 1; print "\n\n**Unmatched Entries**"; foreach my $line (sort {$OtherList{$b}<=>$OtherList{$a} } keys %OtherList) { PrettyTimes(" $line", $OtherList{$line}); } } if ($TotalHeaderPrinted > 0) { print "\n"; } exit(0); # vi: shiftwidth=3 tabstop=3 syntax=perl et # Local Variables: # mode: perl # perl-indent-level: 3 # indent-tabs-mode: nil # End: logwatch-7.12/scripts/services/pix0000664000211400021140000003317414274101041017504 0ustar logwatchlogwatch ######################################################## # Please file all bug reports, patches, and feature # requests under: # https://sourceforge.net/p/logwatch/_list/tickets # Help requests and discusion can be filed under: # https://sourceforge.net/p/logwatch/discussion/ ######################################################## ####################################################### ## Copyright (c) 2008 Bob Hendry ## Covered under the included MIT/X-Consortium License: ## http://www.opensource.org/licenses/mit-license.php ## All modifications and contributions by other persons to ## this script are assumed to have been donated to the ## Logwatch project and thus assume the above copyright ## and licensing terms. If you want to make contributions ## under your own copyright or a different license this ## must be explicitly stated in the contribution an the ## Logwatch project reserves the right to not accept such ## contributions. If you have made significant ## contributions to this script and want to claim ## copyright please contact logwatch-devel@lists.sourceforge.net. ######################################################### use Logwatch ':all'; ########################################################################## # Apply date for Cisco PIX ########################################################################## use POSIX qw(strftime); use Logwatch ':dates'; use strict; my $SearchDate = TimeFilter('%b %e %H:%M:%S'); my $Debug = $ENV{'LOGWATCH_DEBUG'} || 0; my $Detail = $ENV{'LOGWATCH_DETAIL_LEVEL'} || 0; my $DebugCounter = 0; #Init String Containers my ( $DNS_packets, $FTP_packets, $ICMP_packets, $IPV6_packets, $NTP_packets, $SSH_packets, $SYSLOG_packets, $TELNET_packets, $accesslist, $action, $connection_id, $count, $destination, $destination_ip, $destination_port, $icmp_type, $packets, $protocol, $source, $source_ip, $source_port, $testline ); #Init Arrays my @testfields = (); #Init Hashes my ( %ACL, %ACTION, %CONNECTION_ID, %DNS, %FTP, %ICMP, %NTP, %OtherList, %SSH, %SYSLOG, %TELNET ); if ( $Debug >= 5 ) { print STDERR "\n\nDEBUG: Inside PIX Filter \n\n"; $DebugCounter = 1; } my ($month,$day,$time,$host,$process,$conn,$msg); while (defined(my $ThisLine = )) { if ($ThisLine =~ m/^$SearchDate/o) { # added if ( $Debug >= 30 ) { print STDERR "DEBUG($DebugCounter): $ThisLine"; $DebugCounter++; } ($month,$day,$time,$host,$process,$conn,$msg)=split(/ +/,$ThisLine,7); if ( ($ThisLine =~ /(ISDN-6-.+)/ ) or ($ThisLine =~ /Copyright/ ) or ($ThisLine =~ /Cisco Internetwork Operating System Software/ ) or ($ThisLine =~ /IOS \(tm\)/ ) or ($ThisLine =~ /TAC:Home:SW:IOS:Specials/ ) ) { # don't care about this, will code this later } elsif ( $ThisLine =~ /%PIX-4-106023:/) { $testline = $ThisLine; chomp $testline; $testline =~ s/^.*PIX-4-106023: Deny //; $testline =~ s/\[0x0, 0x0\]//; $testline =~ s/"/ /g; $testline =~ s/by access-group//; $testline =~ s/[:,]/ /g; $testline =~ s/\// /g; @testfields = split(' ',$testline); $accesslist = @testfields[$#testfields]; $action = "Deny"; $protocol = @testfields[0]; if ($protocol =~ /(tcp|udp)/) { $source = @testfields[3]; $destination = @testfields[7]; $icmp_type = ""; $count = 1; $source_ip = @testfields[3]; $source_port = @testfields[4]; $destination_ip = @testfields[7]; $destination_port = @testfields[8]; } elsif ($protocol =~ /icmp/) { $source = @testfields[3]; $destination = @testfields[7]; $icmp_type = @testfields[8]; $count = 1; $source_ip = @testfields[3]; $destination_ip = @testfields[7]; } elsif ($protocol =~ /41/) { #IPv6 $source = @testfields[3]; $destination = @testfields[7]; $icmp_type = ""; $count = 1; $source_ip = @testfields[3]; $source_port = @testfields[4]; $destination_ip = @testfields[7]; $destination_port = @testfields[8]; } else { $count = 0; } $ACL{$accesslist} += $count; $ACTION{$action} += $count; $packets += $count; if ( ($destination_port == 22) and ($protocol =~ /TCP|tcp/) ) { $SSH{$source_ip} += $count; $SSH_packets += $count; } if ( ($destination_port == 23) and ($protocol =~ /TCP|tcp/) ) { $TELNET{$source_ip} += $count; $TELNET_packets += $count; } } elsif ($ThisLine =~ /%PIX-6-106100:/) { $testline = $ThisLine; chomp $testline; $testline =~ s/^.*%PIX-6-106100://; $testline =~ s/ ->//; $testline =~ s/[:,]/ /g; $testline =~ s/\// /g; $testline =~ s/[()]/ /g; @testfields = split(' ',$testline); $accesslist = @testfields[1]; $action = @testfields[2]; $protocol = @testfields[3]; if ($protocol =~ /(TCP|UDP|tcp|udp)/) { $count = 1; $source_ip = @testfields[5]; $source_port = @testfields[6]; $destination_ip = @testfields[8]; $destination_port = @testfields[9]; } elsif ($protocol =~ /icmpv6/) { # not implemented } else { $count = 0; } $ACL{$accesslist} += $count; $ACTION{$action} += $count; $packets += $count; if ( ($destination_port == 22) and ($protocol =~ /TCP|tcp/) ) { $SSH{$source_ip} += $count; $SSH_packets += $count; } if ( ($destination_port == 23) and ($protocol =~ /TCP|tcp/) ) { $TELNET{$source_ip} += $count; $TELNET_packets += $count; } if ( ($destination_port == 21) and ($protocol =~ /TCP|tcp/) ) { $FTP{$source_ip} += $count; $FTP_packets += $count; } } #Error Message %PIX|ASA-6-302013 elsif ($ThisLine =~ /%PIX-6-302013: Built/) { $testline = $ThisLine; chomp $testline; $testline =~ s/^.*%PIX-6-302013: Built//; $testline =~ s/[:,]/ /g; $testline =~ s/\// /g; $testline =~ s/[()]/ /g; @testfields = split(' ',$testline); $connection_id = @testfields[3]; $CONNECTION_ID{$connection_id} = $connection_id; } #Error Message %PIX|ASA-6-302015 elsif ($ThisLine =~ /%PIX-6-302015: Built/) { $testline = $ThisLine; chomp $testline; $testline =~ s/^.*%PIX-6-302015: Built//; $testline =~ s/[:,]/ /g; $testline =~ s/\// /g; $testline =~ s/[()]/ /g; @testfields = split(' ',$testline); $connection_id = @testfields[3]; $CONNECTION_ID{$connection_id} = $connection_id; } #Error Message %PIX|ASA-6-302014 elsif ($ThisLine =~ /%PIX-6-302014: Teardown/) { $testline = $ThisLine; chomp $testline; $testline =~ s/^.*%PIX-6-302014: Teardown//; $testline =~ s/[:,]/ /g; $testline =~ s/\// /g; $testline =~ s/[()]/ /g; @testfields = split(' ',$testline); $protocol = @testfields[0]; $connection_id = @testfields[2]; $count = 1; $source_ip = @testfields[5]; $source_port = @testfields[6]; $destination_ip = @testfields[11]; $destination_port = @testfields[12]; if ($connection_id == $CONNECTION_ID{$connection_id}) { if ( ($destination_port == 21) and ($protocol =~ /TCP|tcp/) ) { $FTP{$source_ip} += $count; $FTP_packets += $count; } if ( ($destination_port == 22) and ($protocol =~ /TCP|tcp/) ) { $SSH{$source_ip} += $count; $SSH_packets += $count; } if ( ($destination_port == 23) and ($protocol =~ /TCP|tcp/) ) { $TELNET{$source_ip} += $count; $TELNET_packets += $count; } } } #Error Message %PIX|ASA-6-302016 elsif ($ThisLine =~ /%PIX-6-302016: Teardown/) { $testline = $ThisLine; chomp $testline; $testline =~ s/^.*%PIX-6-302016: Teardown//; $testline =~ s/[:,]/ /g; $testline =~ s/\// /g; $testline =~ s/[()]/ /g; @testfields = split(' ',$testline); $protocol = @testfields[0]; $connection_id = @testfields[2]; $count = 1; $source_ip = @testfields[5]; $source_port = @testfields[6]; $destination_ip = @testfields[11]; $destination_port = @testfields[12]; if ($connection_id == $CONNECTION_ID{$connection_id}) { if ( ($source_port == 53) and ($protocol =~ /UDP|udp/) ) { $DNS{$source_ip} += $count; $DNS_packets += $count; } if ( ($source_port == 123) and ($protocol =~ /UDP|udp/) ) { $NTP{$source_ip} += $count; $NTP_packets += $count; } if ( ($source_port == 514) and ($protocol =~ /UDP|udp/) ) { $SYSLOG{$source_ip} += $count; $SYSLOG_packets += $count; } } } elsif ( $ThisLine =~ /%PIX-3-710003:/) { $testline = $ThisLine; chomp $testline; $testline =~ s/^.*%PIX-3-710003://; $testline =~ s/[:,]/ /g; $testline =~ s/\// /g; @testfields = split(' ',$testline); $accesslist = @testfields[4]; $action = "denied"; $protocol = @testfields[0]; if ($protocol =~ /(TCP|UDP|tcp|udp)/) { $icmp_type = ""; $count = 1; $source_ip = @testfields[6]; $source_port = @testfields[7]; $destination_ip = @testfields[10]; $destination_port = @testfields[11]; } elsif ($protocol =~ /icmpv6/) { $source_ip = @testfields[3]; $source_port = 0; $destination_ip = @testfields[4]; $destination_port = 0; $icmp_type = @testfields[5]; $count = @testfields[6]; } else { $count = 0; } $ACL{$accesslist} += $count; $ACTION{$action} += $count; $packets += $count; if ( ($destination_port == 22) and ($protocol =~ /TCP|tcp/) ) { $SSH{$source_ip} += $count; $SSH_packets += $count; } }#Error Message %PIX|ASA-6-302020 elsif ($ThisLine =~ /%PIX-6-302020: Built ICMP connection for faddr/) { $testline = $ThisLine; chomp $testline; $testline =~ s/^.*%PIX-6-302020: Built ICMP connection for faddr//; $testline =~ s/[:,]/ /g; $testline =~ s/\// /g; $testline =~ s/[()]/ /g; @testfields = split(' ',$testline); $connection_id = @testfields[0]; $CONNECTION_ID{$connection_id} = $connection_id; } #Error Message %PIX|ASA-6-302021 elsif ($ThisLine =~ /%PIX-6-302021: Teardown ICMP connection for faddr/) { $testline = $ThisLine; chomp $testline; $testline =~ s/^.*%PIX-6-302021: Teardown ICMP connection for faddr//; $testline =~ s/[:,]/ /g; $testline =~ s/\// /g; $testline =~ s/[()]/ /g; @testfields = split(' ',$testline); $connection_id = @testfields[0]; $count = 1; $source_ip = $connection_id; if ($connection_id == $CONNECTION_ID{$connection_id}) { $ICMP{$source_ip} += $count; $ICMP_packets += $count; } } else { # Report any unmatched entries... chomp $ThisLine; $OtherList{$ThisLine}++; } } } if (keys %ACL) { print "\nAccess Control Lists:\n"; foreach my $ThisOne (sort keys %ACL) { print " " . $ThisOne . " : " . $ACL{$ThisOne} . " Hit(s)\n"; } print " Total : " . $packets . " Hit(s)\n"; if ($IPV6_packets >0) {print " IPv6 Total : " . $IPV6_packets . " Hit(s)\n"} } if (keys %ACTION) { print "\nActions:\n"; foreach my $ThisOne (sort keys %ACTION) { print " " . $ThisOne . " : " . $ACTION{$ThisOne} . " Hit(s)\n"; } print " Total : " . $packets . " Hit(s)\n"; if ($IPV6_packets >0) {print " IPv6 Total : " . $IPV6_packets . " Hit(s)\n"} } if (keys %ICMP) { print "\nICMP Requests:\n"; foreach my $ThisOne (sort keys %ICMP) { print " " . $ThisOne . " : " . $ICMP{$ThisOne} . " Hit(s)\n"; } print " Total : " . $ICMP_packets . " Hit(s)\n"; } if (keys %SSH) { print "\nSSH access:\n"; foreach my $ThisOne (sort keys %SSH) { print " " . $ThisOne . " : " . $SSH{$ThisOne} . " Hit(s)\n"; } print " Total : " . $SSH_packets . " Hit(s)\n"; } if (keys %TELNET) { print "\nTELNET access:\n"; foreach my $ThisOne (sort keys %TELNET) { print " " . $ThisOne . " : " . $TELNET{$ThisOne} . " Hit(s)\n"; } print " Total : " . $TELNET_packets . " Hit(s)\n"; } if (keys %FTP) { print "\nFTP access:\n"; foreach my $ThisOne (sort keys %FTP) { print " " . $ThisOne . " : " . $FTP{$ThisOne} . " Hit(s)\n"; } print " Total : " . $FTP_packets . " Hit(s)\n"; } if (keys %DNS) { print "\nDNS access:\n"; foreach my $ThisOne (sort keys %DNS) { print " " . $ThisOne . " : " . $DNS{$ThisOne} . " Hit(s)\n"; } print " Total : " . $DNS_packets . " Hit(s)\n"; } if (keys %NTP) { print "\nNTP access:\n"; foreach my $ThisOne (sort keys %NTP) { print " " . $ThisOne . " : " . $NTP{$ThisOne} . " Hit(s)\n"; } print " Total : " . $NTP_packets . " Hit(s)\n"; } if (keys %SYSLOG) { print "\nSYSLOG access:\n"; foreach my $ThisOne (sort keys %SYSLOG) { print " " . $ThisOne . " : " . $SYSLOG{$ThisOne} . " Hit(s)\n"; } print " Total : " . $SYSLOG_packets. " Hit(s)\n"; } #if (keys %OtherList) { # print "\n**Unmatched Entries**\n"; # foreach $line (sort {$OtherList{$b}<=>$OtherList{$a} } keys %OtherList) { # print " $line: $OtherList{$line} Time(s)\n"; # } #} exit(0); # vi: shiftwidth=3 tabstop=3 syntax=perl et # Local Variables: # mode: perl # perl-indent-level: 3 # indent-tabs-mode: nil # End: logwatch-7.12/scripts/services/clamav-milter0000664000211400021140000001153614274101035021442 0ustar logwatchlogwatch ######################################################## # Please file all bug reports, patches, and feature # requests under: # https://sourceforge.net/p/logwatch/_list/tickets # Help requests and discusion can be filed under: # https://sourceforge.net/p/logwatch/discussion/ ######################################################## ######################################################## # # Written by S. Schimkat . # # Find latest version here: www.schimkat.dk/clamav # ######################################################## ######################################################## ## Copyright (c) 2008 S. Schimkat ## Covered under the included MIT/X-Consortium License: ## http://www.opensource.org/licenses/mit-license.php ## All modifications and contributions by other persons to ## this script are assumed to have been donated to the ## Logwatch project and thus assume the above copyright ## and licensing terms. If you want to make contributions ## under your own copyright or a different license this ## must be explicitly stated in the contribution an the ## Logwatch project reserves the right to not accept such ## contributions. If you have made significant ## contributions to this script and want to claim ## copyright please contact logwatch-devel@lists.sourceforge.net. ######################################################### use strict; my $Detail = $ENV{'LOGWATCH_DETAIL_LEVEL'}; my $IgnoreUnmatched = $ENV{'clamav_ignoreunmatched'} || 0; #Init Counters my ( $CleanMessage, $DaemonStart, $DaemonStop, $DatabaseReloads, $DatabaseViruses ); #Init Hashes my ( %MaxChildrenLimit, %OtherList, %VirusList ); while (defined(my $ThisLine = )) { chomp($ThisLine); if ( ( $ThisLine =~ /^clamav-milter (startup|shutdown) succeeded$/ ) or ( $ThisLine =~ /^clamav-milter started at/i ) or ( $ThisLine =~ /^(WARNING: )?No clamd server appears to be available/i ) or ( $ThisLine =~ /^Database has changed, loading updated database/ ) or ( $ThisLine =~ /^Quarantined infected mail as/ ) or ( $ThisLine =~ /^\w+ quarantined as/ ) or ( $ThisLine =~ /^ClamAv: mi_stop/i ) or ( $ThisLine =~ m#^\/tmp\/clamav-.* .* FOUND# ) or # These two go along with "max-children limit" so we ignore them ( $ThisLine =~ /n_children \d+: waiting \d+ seconds for some to exit/ ) or ( $ThisLine =~ /Finished waiting, n_children = \d+/ ) or # These 3 precede "correctly reloaded" (we hope) # - Toss-up: Keep "correctly reloaded" or "Protecting against"? ( $ThisLine =~ /^Database has changed, loading updated database/ ) or ( $ThisLine =~ /^Loaded ClamAV \d+\./ ) or ( $ThisLine =~ /^ClamAV: Protecting against \d+ viruses/ ) or 0 ) { # We do not care about these. } elsif (($ThisLine =~ /clean message from/)) { $CleanMessage++; } elsif (($ThisLine =~ /.*: (.+?) Intercepted virus/i ) or ($ThisLine =~ /Message from .* to .* infected by (.+)/)) { $VirusList{$1}++; } elsif (my ($ChildLimit) = ($ThisLine =~ /hit max-children limit \((\d+ >= \d+)\): waiting for some to exit/)) { $MaxChildrenLimit{$ChildLimit}++; } elsif (($ThisLine =~ /^Stopping/)) { $DaemonStop++; } elsif (($ThisLine =~ /^(Starting|\+\+\+ Started)/)) { $DaemonStart++; } elsif (my ($Viruses) = ($ThisLine =~ /^Database correctly reloaded \((\d+) (signatures|viruses)\)/i )) { $DatabaseReloads++; $DatabaseViruses = $Viruses; } else { $OtherList{$ThisLine}++; } } if (($DaemonStop) and ($Detail >= 5)) { print "\nDaemon stopped: " . $DaemonStop . " Time(s)\n"; } if (($DaemonStart) and ($Detail >= 5)) { print "\nDaemon started: " . $DaemonStart . " Time(s)\n"; } if (($DatabaseReloads) and ($Detail >= 5)) { print "\nVirus database reloaded $DatabaseReloads time(s) (last time with $DatabaseViruses viruses)\n"; } if (keys %MaxChildrenLimit) { print "\nHit max-children limit:\n"; foreach my $Limit (sort {$a cmp $b} keys %MaxChildrenLimit) { print ' Limit ' . $Limit . ' children(s) exceeded ' . $MaxChildrenLimit{$Limit} . " Time(s)\n" } } if ($CleanMessage) { print "\nClean messages: " . $CleanMessage . " Message(s)\n"; } if (keys %VirusList) { my $Total = 0; print "\nInfected messages:\n"; foreach my $Virus (sort {$a cmp $b} keys %VirusList) { print ' ' . $Virus . ": ". $VirusList{$Virus} . " Message(s)\n"; $Total += $VirusList{$Virus}; } print " Total: $Total\n"; } if ((keys %OtherList) and (not $IgnoreUnmatched)){ print "\n**Unmatched Entries**\n"; foreach my $line (sort {$OtherList{$b}<=>$OtherList{$a} } keys %OtherList) { print "\n $line: $OtherList{$line} Time(s)"; } } exit(0); # vi: shiftwidth=3 tabstop=3 syntax=perl et # Local Variables: # mode: perl # perl-indent-level: 3 # indent-tabs-mode: nil # End: logwatch-7.12/scripts/services/nut0000664000211400021140000003031314743365004017516 0ustar logwatchlogwatch######################################################## # Please file all bug reports, patches, and feature # requests under: # https://sourceforge.net/p/logwatch/_list/tickets # Help requests and discusion can be filed under: # https://sourceforge.net/p/logwatch/discussion/ ######################################################## ######################################################## ## Copyright (c) 2019-2022 Orion Poplawski ## Covered under the included MIT/X-Consortium License: ## http://www.opensource.org/licenses/mit-license.php ## All modifications and contributions by other persons to ## this script are assumed to have been donated to the ## Logwatch project and thus assume the above copyright ## and licensing terms. If you want to make contributions ## under your own copyright or a different license this ## must be explicitly stated in the contribution an the ## Logwatch project reserves the right to not accept such ## contributions. If you have made significant ## contributions to this script and want to claim ## copyright please contact logwatch-devel@lists.sourceforge.net. ######################################################### use strict; use warnings; my $Detail = $ENV{'LOGWATCH_DETAIL_LEVEL'} || 0; my ($Hostname) = ($ENV{'HOSTNAME'} =~ /^([^.]+)/); my $CannotConnectThreshold = $ENV{'cannot_connect_threshold'} || 0; my %BatteryLow; my %BatteryReplace; my %CannotConnect; my %Commands; my %CommunicationLost; my %CommunicationState; my %Connected; my %ConnectionFailure; my %DataStale; my %DataStaleState; my %Logins; my %OnBattery; my %State; my %OtherList; my %Unavailable; my $SelfTestPassed = 0; my $SelfTestFailed = 0; my $UpsdrvctlMessages; while (defined(my $ThisLine = )) { chomp($ThisLine); # Strip PID $ThisLine =~ s/^([^[]+)\[\d+\]:/$1:/; my $ups; my $state; my $user; my $command; if ($ThisLine =~ /^(?:nut-server|upsd): User .* logged out/ # CUPS matches our generous service regex or $ThisLine =~ /^cupsd:/ or $ThisLine =~ /: Could not find PID file/ # TODO - count start/stops or $ThisLine =~ /: Running as foreground process/ or $ThisLine =~ /Signal 15: exiting/ or $ThisLine =~ /Startup successful/ or $ThisLine =~ /^upsdrvctl: Detected .* on host / or $ThisLine =~ /^upsdrvctl: Network UPS Tools - / or $ThisLine =~ /^upsdrvctl: USB communication driver/ or $ThisLine =~ /^upsdrvctl: Using subdriver:/ or $ThisLine =~ /^upsdrvctl: using '.*' to set battery low state/ or $ThisLine =~ /^(?:nut-server|upsd): \/etc\/pki\/nssdb is world readable/ # TODO - Report at high detail level or $ThisLine =~ /^(?:nut-server|upsd): Found \d+ UPS defined in ups.conf/ or $ThisLine =~ /^(?:nut-server|upsd): Intend to retrieve password for NSS User Private Key and Certificate Services \/ NSS Certificate DB: password configured/ or $ThisLine =~ /^(?:nut-server|upsd): Limit\s*Soft Limit/ or $ThisLine =~ /^(?:nut-server|upsd): listening on / or $ThisLine =~ /^(?:nut-server|upsd): mainloop: Interrupted system call/ or $ThisLine =~ /^(?:nut-server|upsd): Max open files/ or $ThisLine =~ /^(?:nut-server|upsd): Network UPS Tools upsd/ or $ThisLine =~ /^(?:nut-server|upsd): fopen \S+\/upsd.pid: No such file or directory/ or $ThisLine =~ /^(?:nut-server|upsd): SSL handshake done successfully with client/ or $ThisLine =~ /^(?:nut-monitor|upsmon): Connected to/ or $ThisLine =~ /^(?:nut-monitor|upsmon): Connecting in SSL to/ or $ThisLine =~ /^(?:nut-monitor|upsmon): Certificate verification is disabled/ or $ThisLine =~ /^(?:nut-monitor|upsmon): Do not intend to authenticate server/ or $ThisLine =~ /^(?:nut-monitor|upsmon): fopen \S+\/upsmon.pid: No such file or directory/ or $ThisLine =~ /^(?:nut-monitor|upsmon): Init SSL without certificate database/ or $ThisLine =~ /^(?:nut-monitor|upsmon): Network UPS Tools upsmon/ # This will generate a communication lost message - TODO - track reasons? or $ThisLine =~ /^(?:nut-monitor|upsmon): Poll UPS \[(\S+)\] failed -/ or $ThisLine =~ /^(?:nut-monitor|upsmon): SSL handshake done successfully with server/ or $ThisLine =~ /^(?:nut-monitor|upsmon): UPS: \S+ \((?:master:primary)\)/ or $ThisLine =~ /^(?:nut-monitor|upsmon): UPS: \S+ \((?:slave:secondary)\)/ or $ThisLine =~ /^(?:nut-monitor|upsmon): Using power down flag file/ # This is going away - https://bugzilla.redhat.com/show_bug.cgi?id=1608176 or $ThisLine =~ /^(?:nut-monitor|upsmon): wall: cannot get tty name: Inappropriate ioctl for device/ or $ThisLine =~ /^(?:nut-monitor|nut-server): upsnotify: logged the systemd watchdog situation once, will not spam more about it/ or $ThisLine =~ /^upssched: (?:Cancelling|New) timer:/ or $ThisLine =~ /^upssched: Timer daemon started/ or $ThisLine =~ /^upssched: Timer queue empty/ or $ThisLine =~ /^snmp-ups: \[(\S+)\] snmp_ups_walk: data (:?resumed|stale)/ or $ThisLine =~ /^UPS: No longer on battery power/ # Should get a particular ups on battery power message or $ThisLine =~ /^UPS: On battery power in response to an input power problem/ or $ThisLine =~ /^UPS: UPS: Restored the local network management interface-to-UPS communication/ or $ThisLine =~ /^UPS: Started a self-test/ ) { # Ignore these } elsif (($ups) = ($ThisLine =~ /^(?:nut-monitor|upsmon): UPS (\S+) battery is low/)) { $BatteryLow{$ups}++; } elsif (($ups) = ($ThisLine =~ /^(?:nut-monitor|upsmon): UPS (\S+) battery needs to be replaced/)) { $BatteryReplace{$ups}++; } elsif (($ups) = ($ThisLine =~ /^(?:nut-server|upsd): Can't connect to UPS \[(\S+)\]/)) { $CannotConnect{$ups}++; } elsif (($user, $command, $ups) = ($ThisLine =~ /^(?:nut-server|upsd): Instant command: (\S+) did (\S+) on (\S+)/)) { $Commands{$ups}->{$user}->{$command}++; } elsif (($ups) = ($ThisLine =~ /^(?:nut-server|upsd): Connected to UPS \[(\S+)\]/)) { $Connected{$ups}++; } elsif (($ups) = ($ThisLine =~ /^(?:nut-monitor|upsmon): Communications with UPS (\S+) lost/)) { $CommunicationLost{$ups}++; $CommunicationState{$ups} = "lost"; } elsif (($ups) = ($ThisLine =~ /^(?:nut-monitor|upsmon): Communications with UPS (\S+) established/)) { $CommunicationState{$ups} = "established"; # At Detail 0, we don't want to know about recovered disconnects if ($Detail == 0) { $Unavailable{$ups}--; delete $Unavailable{$ups} if $Unavailable{$ups} <= 0; } # This may always be paired with the "unavailable" message below - so may want to ignore or move to higher detail } elsif (($ups) = ($ThisLine =~ /^(?:nut-monitor|upsmon): UPS \[(.+)\]: connect failed:/)) { $ConnectionFailure{$ups}++; } elsif (($ups) = ($ThisLine =~ /^(?:nut-monitor|upsmon): UPS (.+)\ is unavailable/)) { $Unavailable{$ups}++; } elsif (($ups, $state) = ($ThisLine =~ /^(?:nut-monitor|upsmon): UPS (\S+) on (.*)/)) { my ($host) = ($ups =~ /@([^.]+)/); next unless $host eq "localhost" or $host eq $Hostname; $State{$ups} = $state; $OnBattery{$ups}++ if $state eq "battery"; } elsif (($ups, $state) = ($ThisLine =~ /^(?:nut-monitor|upsmon): UPS: (\S+) \(\S+\) \((.*)\)/)) { my ($host) = ($ups =~ /@([^.]+)/); next unless $host eq "localhost" or $host eq $Hostname; $State{$ups} = $state; #$OnBattery{$ups}++ if $state eq "battery"; } elsif (($ups) = ($ThisLine =~ /^(?:nut-server|upsd): Data for UPS \[(\S+)\] is stale/)) { $DataStale{$ups}++; $DataStaleState{$ups}++; } elsif (($ups) = ($ThisLine =~ /^(?:nut-server|upsd): UPS \[(\S+)\] data is no longer stale/)) { $DataStaleState{$ups}--; } elsif (($user, $ups) = ($ThisLine =~ /^(?:nut-server|upsd): User (\S+) logged into UPS \[(\S+)\]/)) { $Logins{$user}->{$ups}++; } elsif (my ($msg) = ($ThisLine =~ /^upsdrvctl: (.*)/)) { $UpsdrvctlMessages .= " $msg\n"; } elsif ($ThisLine =~ /^UPS: Passed a self-test/) { $SelfTestPassed++; } else { $OtherList{$ThisLine}++; } } if (keys %BatteryReplace) { print "WARNING: UPS battery needs to be replaced:\n"; foreach my $ups (sort {$a cmp $b} keys %BatteryReplace) { print " $ups: $BatteryReplace{$ups} Time(s)\n"; } print "\n"; } if (keys %CannotConnect) { my $first = 1; foreach my $ups (sort {$a cmp $b} keys %CannotConnect) { if ($CannotConnect{$ups} >= $CannotConnectThreshold) { if ($first) { print "Cannot connect to UPS:\n"; print " (with threshold >= $CannotConnectThreshold)" if $CannotConnectThreshold; print "\n"; $first = 0; } print " $ups: $CannotConnect{$ups} Time(s)\n"; } } print "\n"; } if (keys %ConnectionFailure) { my $first = 1; foreach my $ups (sort {$a cmp $b} keys %ConnectionFailure) { if ($ConnectionFailure{$ups} >= $CannotConnectThreshold) { if ($first) { print "Cannot connect to UPS server:\n"; print " (with threshold >= $CannotConnectThreshold)" if $CannotConnectThreshold; print "\n"; $first = 0; } print " $ups: $ConnectionFailure{$ups} Time(s)\n"; } } print "\n"; } if (keys %Unavailable) { print "UPS is unavailable:\n"; foreach my $ups (sort {$a cmp $b} keys %Unavailable) { print " $ups: $Unavailable{$ups} Time(s)\n"; } print "\n"; } if ($UpsdrvctlMessages) { print "upsdrvctl Messages:\n"; print $UpsdrvctlMessages; } if (keys %BatteryLow) { print "UPS battery low:\n"; foreach my $ups (sort {$a cmp $b} keys %BatteryLow) { print " $ups: $BatteryLow{$ups} Time(s)\n"; } print "\n"; } if (keys %OnBattery) { print "UPS on battery:\n"; foreach my $ups (sort {$a cmp $b} keys %OnBattery) { print " $ups: $OnBattery{$ups} Time(s)\n"; } print "\n"; } # TODO - Alert if too many disconnects? my $CommunicationLostCurrent = 0; foreach my $ups (keys %CommunicationLost) { $CommunicationLostCurrent += 1 if $CommunicationState{$ups} eq "lost"; } if (keys %CommunicationLost and ($Detail or $CommunicationLostCurrent)) { print "Communication lost:\n"; foreach my $ups (sort {$a cmp $b} keys %CommunicationLost) { print " $ups: $CommunicationLost{$ups} Time(s)"; print " * Currently " . $CommunicationState{$ups}; print "\n"; } print "\n"; } # TODO - Alert if too many? my $DataStaleStateTotal = 0; foreach my $ups (keys %DataStale) { $DataStaleStateTotal += $DataStaleState{$ups}; } if (keys %DataStale and ($Detail or $DataStaleStateTotal)) { print "Data is stale:\n"; foreach my $ups (sort {$a cmp $b} keys %DataStale) { print " $ups: $DataStale{$ups} Time(s)"; print " * Currently stale" if $DataStaleState{$ups}; print "\n"; } print "\n"; } if ($SelfTestPassed and ($Detail >= 5)) { print "UPS Self-Test Passed $SelfTestPassed Time(s)\n\n"; } if (keys %Connected and ($Detail >= 5)) { print "Connected to UPS:\n"; foreach my $ups (sort {$a cmp $b} keys %Connected) { print " $ups: $Connected{$ups} Time(s)\n"; } print "\n"; } if (keys %Commands and $Detail) { print "Commands run:\n"; foreach my $ups (sort {$a cmp $b} keys %Commands) { print " UPS $ups:\n"; foreach my $user (sort {$a cmp $b} keys %{$Commands{$ups}}) { print " User $user:\n"; foreach my $command (sort {$a cmp $b} keys %{$Commands{$ups}{$user}}) { print " $command: $Commands{$ups}->{$user}->{$command} Time(s)\n"; } } } print "\n"; } if (keys %Logins and ($Detail >= 10)) { print "Logins:\n"; foreach my $user (sort {$a cmp $b} keys %Logins) { print " $user:\n"; foreach my $ups (sort {$a cmp $b} keys %{$Logins{$user}}) { print " $ups: $Logins{$user}{$ups} Time(s)\n"; } } print "\n"; } if (keys %OtherList) { print "\n\n**Unmatched Entries**\n"; foreach my $line (sort {$a cmp $b} keys %OtherList) { print " $line: $OtherList{$line} Time(s)\n"; } } exit(0); # vi: shiftwidth=3 tabstop=3 syntax=perl et # Local Variables: # mode: perl # perl-indent-level: 3 # indent-tabs-mode: nil # End: logwatch-7.12/scripts/services/zypp0000664000211400021140000000546114743365006017722 0ustar logwatchlogwatch ######################################################## # Please file all bug reports, patches, and feature # requests under: # https://sourceforge.net/p/logwatch/_list/tickets # Help requests and discusion can be filed under: # https://sourceforge.net/p/logwatch/discussion/ ######################################################## ######################################################## ## Copyright (c) 2013-2016 Stefan Jakobs ## Covered under the included MIT/X-Consortium License: ## http://www.opensource.org/licenses/mit-license.php ## All modifications and contributions by other persons to ## this script are assumed to have been donated to the ## Logwatch project and thus assume the above copyright ## and licensing terms. If you want to make contributions ## under your own copyright or a different license this ## must be explicitly stated in the contribution an the ## Logwatch project reserves the right to not accept such ## contributions. If you have made significant ## contributions to this script and want to claim ## copyright please contact logwatch-devel@lists.sourceforge.net. ######################################################### use strict; my @install; my @remove; my @rremove; my @radd; my %commands; my @unknown; while(my $line=) { chomp $line; if ( my ( $do, $pkg, $ver, $arch, $user, $repo, $hash) = ( $line =~ /^\S+ \S+\|(?:(install|remove) ?)\|([^\|\s]+)\|([^\|\s]+)\|([^\|\s]+)\|([^\|\s]+)?(?:\|([^\|\s]+)\|([^\|\s]+))?/ )) { if ($do eq "remove") { push @remove, "$pkg $ver"; } elsif ($do eq "install") { push @install, "$pkg $ver"; } } elsif ( my ( $do, $repo, $url) = ( $line =~ /^\S+ \S+\|(?:(rremove|radd) {0,3})\|([^\|\s]+)(?:\|([^\|]+))?/) ) { if ($repo eq "_tmpRPMcache_") { # ignore } elsif ($do eq "radd") { push @radd, "$repo: $url"; } elsif ($do eq "rremove") { push @rremove, "$repo"; } } elsif ( my ( $do, $who, $cmd) = ( $line =~ /^\S+ \S+\|(?:(command)\|([^\|\s]+)\|([^\|]+)\|)/ )) { $cmd =~ tr/'//d; $commands{$who}{$cmd}++; } else { push @unknown, $line; } } if (keys %commands) { print "\nCommands:\n"; foreach my $who (keys %commands) { print " $who:\n"; foreach my $cmd (keys %{$commands{$who}}) { printf " %3d: %s\n", $commands{$who}{$cmd}, $cmd; } } } my @k = ( "Installed" , \@install, "Removed", \@remove, "Repository added", \@radd, "Repository removed", \@rremove, "Unknown lines", \@unknown); while (@k > 0) { my $text = shift @k; my $array = shift @k; if(@$array) { print "\n$text:\n"; foreach my $line (sort @$array) { print " $line\n"; } } } # vi: shiftwidth=3 tabstop=3 syntax=perl et logwatch-7.12/scripts/services/zz-network0000664000211400021140000001601514274101045021035 0ustar logwatchlogwatch ######################################################## # Please file all bug reports, patches, and feature # requests under: # https://sourceforge.net/p/logwatch/_list/tickets # Help requests and discusion can be filed under: # https://sourceforge.net/p/logwatch/discussion/ ######################################################## ####################################################### ## Copyright (c) 2008 Laurent Dufour ## Francis Borras ## Covered under the included MIT/X-Consortium License: ## http://www.opensource.org/licenses/mit-license.php ## All modifications and contributions by other persons to ## this script are assumed to have been donated to the ## Logwatch project and thus assume the above copyright ## and licensing terms. If you want to make contributions ## under your own copyright or a different license this ## must be explicitly stated in the contribution an the ## Logwatch project reserves the right to not accept such ## contributions. If you have made significant ## contributions to this script and want to claim ## copyright please contact logwatch-devel@lists.sourceforge.net. ######################################################### $| = 1; use POSIX qw(uname); use strict; my (%Config); $ENV{PRINTING} = "y"; my $Debug = $ENV{'LOGWATCH_DEBUG'} || 0; my $Detail = $ENV{'LOGWATCH_DETAIL_LEVEL'} || 0; my $pathto_chkconfig = $ENV{'pathto_chkconfig'} || '/sbin/chkconfig'; my $pathto_sysctl_conf = $ENV{'pathto_sysctl_conf'} || '/etc/sysctl.conf'; my $pathto_vtysh = $ENV{'pathto_vtysh'} || '/usr/bin/vtysh'; my $pathto_routeadm = $ENV{'pathto_routeadm'} || '/usr/sbin/routeadm'; my $pathto_ip = $ENV{'pathto_ip'} || '/sbin/ip'; my $pathto_ifconfig = $ENV{'pathto_ifconfig'} || '/sbin/ifconfig'; my @ethernet_iface_list; my @other_iface_list; my @short_ethernet_iface_list; my @short_other_iface_list; my $total_iface=0; my $total_ethernet_iface=0; my $total_other_iface=0; my $DebugCounter=0; my ($OSname, $hostname, $release, $version, $machine) = POSIX::uname(); if ( $Debug >= 5 ) { print STDERR "\n\nDEBUG: Inside zz-network Filter \n\n"; $DebugCounter = 1; } sub show_which { my ($cmd) = $_[0]; my $path = $ENV{'PATH'} || '.'; my @path_array = split(/:/,$path); foreach my $element (@path_array) { my $testfile=$element .'/'.$cmd; if ( -f $testfile) { print "$testfile\n"; } } } sub chkcfg { my ($service) = $_[0]; if (($OSname eq "Linux") && ( -f $pathto_chkconfig)) { system("$pathto_chkconfig --list $service"); } else { show_which($service); } } sub routingCapabilities () { print "\n\n------------- Routing capabilities----------\n\n"; chkcfg('routed'); chkcfg('gated'); chkcfg('zebra'); chkcfg('ripd'); chkcfg('ripngd'); chkcfg('isisd'); chkcfg('ospfd'); chkcfg('ospf6d'); chkcfg('bgpd'); if ( -f $pathto_vtysh ) { print "\n"; system("$pathto_vtysh -e 'sh ver'"); } if ($OSname eq "SunOS") { if ( ($release eq "5.10") || ($release eq "5.11") ) { if ( -f $pathto_routeadm) { open(FILE1, "$pathto_routeadm -p |") || die "can't open $!"; while () { print $_; } close(FILE1) || die "can't close $!"; } } } print "\n\n------------- Routing capabilities----------\n\n"; print "\n"; } sub routingState () { print "\n\n------------- Routing states ---------------\n\n"; if ($OSname eq "Linux") { if ( -f $pathto_sysctl_conf) { open(SYSCTL, "< $pathto_sysctl_conf") || die "can't open $!"; while () { if ($_ =~ /ip_forward/ ) { print "IP Forwarding enabled"; } } } else { open(SYSCTL,"< /proc/sys/net/ipv4/ip_forward") || die "can't open $!"; while () { print "/proc/sys/net/ipv4/ip_forward set to $_"; } close(SYSCTL) || die "can't close $!"; } } elsif ($OSname eq "SunOS") { if ( ($release eq "5.10") || ($release eq "5.11") ) { if ( -f $pathto_routeadm) { open(FILE1, "$pathto_routeadm -p |") || die "can't open $!"; while () { if (/ipv(\d+)-forwarding .*default=(\S+) current=(\S+)/) { print "IPv$1 forwarding is $3 (normal state is $2)\n"; } } close(FILE1) || die "can't close $!"; } } } else { print "Unable to find routing information in your system.\n"; } print "\n\n------------- Routing states ---------------\n\n"; print "\n"; } sub routingReport () { print "\n\n------------- Network routes ---------------\n\n"; if ($OSname eq "Linux") { open(NET, "netstat -r -n |") || die "can't run netstat: $!"; while () { print $_; } close(NET) || die "can't close netstat: $!"; } else { open(NET, "netstat -r -n |") || die "can't run netstat: $!"; while () { print $_; } close(NET) || die "can't close netstat: $!"; } print "\n\n------------- Network routes ---------------\n\n"; print "\n"; } sub ListeningSockets () { print "\n\n------------- Listening sockets ---------------\n\n"; if ($OSname eq "Linux") { open(NET, "netstat -lnptu |") || die "can't run netstat: $!"; while () { print $_; } close(NET) || die "can't run netstat: $!"; } else { open(NET, "netstat -a -n |") || die "can't run netstat: $!"; while () { if ($_ =~ /LISTEN/ ) {# grep LISTEN if (($_ =~ /LISTENING/ ) == 0 ) { # grep -v LISTENING print $_; } } } close(NET) || die "can't run netstat: $!"; } print "\n\n------------- Listening sockets ---------------\n\n"; print "\n"; } sub NetworkStats() { print "\n\n------------- Network statistics ---------------\n\n"; if ($OSname eq "Linux") { my $cmd_to_show_int=""; if ( -f $pathto_ip) { $cmd_to_show_int=$pathto_ip." -s -h a"; } else { $cmd_to_show_int="$pathto_ifconfig -s -a"; } open(NET, "$cmd_to_show_int |") || die "can't run $cmd_to_show_int: $!"; while () { print $_; } close(NET) || die "can't close $cmd_to_show_int: $!"; } else { my $netstat_cmd = "netstat -i"; if ($OSname eq "SunOS") { $netstat_cmd .= " -a"; } open(NET, "$netstat_cmd |") || die "can't run netstat: $!"; while () { print $_; } close(NET) || die "can't close netstat: $!"; } print "\n\n------------- Network statistics ---------------\n\n"; print "\n"; } NetworkStats(); ListeningSockets(); if ($Detail > 5) { routingState(); routingCapabilities(); routingReport(); } # vi: shiftwidth=3 tabstop=3 syntax=perl et # Local Variables: # mode: perl # perl-indent-level: 3 # indent-tabs-mode: nil # End: logwatch-7.12/scripts/services/freeradius0000664000211400021140000003537014743365004021051 0ustar logwatchlogwatch ######################################################## # Please file all bug reports, patches, and feature # requests under: # https://sourceforge.net/p/logwatch/_list/tickets # Help requests and discusion can be filed under: # https://sourceforge.net/p/logwatch/discussion/ ######################################################## ######################################################## # freeradius logwatch filter # written by Jonas Marczona 28.12.2011 # ## Covered under the included MIT/X-Consortium License: ## http://www.opensource.org/licenses/mit-license.php ## All modifications and contributions by other persons to ## this script are assumed to have been donated to the ## Logwatch project and thus assume the above copyright ## and licensing terms. If you want to make contributions ## under your own copyright or a different license this ## must be explicitly stated in the contribution an the ## Logwatch project reserves the right to not accept such ## contributions. If you have made significant ## contributions to this script and want to claim ## copyright please contact logwatch-devel@lists.sourceforge.net. ######################################################## $^W=1; use strict; my $Debug = $ENV{'LOGWATCH_DEBUG'} || 0; my $Detail = $ENV{'LOGWATCH_DETAIL_LEVEL'} || 0; my $DebugCounter = 0; if ( $Debug >= 5 ) { print STDERR "\n\nDEBUG: Inside freeradius Filter \n\n"; $DebugCounter = 1; } my %OtherList = (); my %loginsOk = (); my %certificateExpired = (); my %wrongPassword = (); my %wrongUser = (); my %wrong_client = (); my %invalidUser = (); my %discards = (); my %warnings = (); my %givingUps = (); my $crlExpired = 0; my $killedChilds = 0; my $reloaded = 0; my $requests = 0; my $requests_duration = 0; my $started = 0; my $stopped = 0; my $ThisLine; while (defined($ThisLine = )) { if ( $Debug >= 5 ) { print STDERR "DEBUG($DebugCounter): $ThisLine"; $DebugCounter++; } chomp($ThisLine); # Strip leading session id my ($SessionID) = ($ThisLine =~ s/^\((\d+)\) *//); if ( ( $ThisLine =~ /^(?:Info: )?F-TICKS/ ) || ( $ThisLine =~ /^(?:Info: )?Access-Request from/ ) || ( $ThisLine =~ /^(?:Info: )? \.\.\. (?:closing|adding new) socket/ ) || ( $ThisLine =~ /^(?:Info: )?(?:SSL|TLS|rlm_(?:unix|eap|sql|radutmp)| TLS_accept| \[ldap\])/ ) || ( $ThisLine =~ /^(?:Info: )?Ready to process requests/ ) || ( $ThisLine =~ /^(?:Info: )?Debugger not attached/ ) || ( $ThisLine =~ /^(?:Info: )?Exiting normally/ ) || ( $ThisLine =~ /^(?:Info: )?Loaded virtual server/ ) || ( $ThisLine =~ /^(?:Info: )?HUP - / ) || ( $ThisLine =~ /^(?:Info: )?Ignoring / ) || ( $ThisLine =~ /^(?:Info: )?Received HUP signal/ ) || ( $ThisLine =~ /^(?:Info: )? ?Module: Reloaded module/ ) || ( $ThisLine =~ /^(?:Info: )?Signalled to terminate/ ) || # TD: # Skipping contents of 'if' as it is always 'false' -- /etc/raddb/sites-enabled/inner-tunnel # This is a standard config item ( $ThisLine =~ /^(?:Info: )? *# Skipping contents of 'if' as it is always 'false' -- .*inner-tunnel/ ) || # TD: [/etc/raddb/mods-config/attr_filter/access_reject]:11 Check item "FreeRADIUS-Response-Delay-USec" found in filter list for realm "DEFAULT". # This is triggered by a standard config item and is harmless ( $ThisLine =~ /access_reject\]:\d+ Check item "FreeRADIUS-Response-Delay(?:-USec)?"\s*found in filter list for realm/ ) || # These should precede Login incoreect messages ( $ThisLine =~ /^eap_tls: *ERROR: \(TLS\) .*(?:certificate.*expired|Error in error)/ ) || # We count completed events below ( $ThisLine =~ /^(?:Info: )?(?:Start|Stopp|Reload)ing FreeRADIUS/ ) ) { # ignore } # TD: Login OK: [user@example.com] (from client radius port 0) # TD: Login OK: [user@example.com] (from client radius port 9 cli 00-11-22-33-44-AA;eduroam via TLS tunnel) elsif ( my ($user) = ($ThisLine =~ m/^(?:Auth: )?Login OK: \[(.+)\] \(from client [^ ]* port \d{1,10}(?: cli [-0-9a-fA-F.:]+)?(?:;\w+)?(?: via TLS tunnel)?\)/) ) { $loginsOk{$user}++; } # TD: Login incorrect ( [ldap] User not found): [user@example.com] (from client radius port 13 cli 38-16-dd-aa-bb-cc via TLS tunnel) # TD: Login incorrect (mschap: External script says Logon failure (0xc000006d)): [user@example.com] (from client radius port 13 cli aa-bb-cc-11-22-33 via TLS tunnel) # TD: Login incorrect (TLS Alert write:fatal:handshake failure): [user@example.com] (from client radius port 13 cli aa-bb-cc-11-22-33) # TD: Login incorrect (No Auth-Type found: rejecting the user via Post-Auth-Type = Reject): [04d9f5bc5541] (from client nwra port 50104 cli 04-D9-F5-BC-55-41) elsif ( my ($user, $client) = ( $ThisLine =~ m/^(?:Auth: )?Login incorrect(?: \([^)]+\))?: \[(.*)\] \(from client [^ ]* port \d{1,10}(?: cli ([-0-9a-fA-F.:]+)(?:;\w+)?)?(?: via TLS tunnel)?\)/) ) { if (! $client) { $client = "*not named*"; } $wrongUser{$client}{$user}++; $wrong_client{$client}++; } # TD: Login incorrect: [user@example.com] (from client radius port 175143 cli cc08.e051.a240) # TD: Login incorrect: [user@example.com] (from client radius1 port 0) elsif ( my ($user, $client) = ($ThisLine =~ m/^(?:Auth: )?Login incorrect: \[(.+)\] \(from client [^ ]* port \d{1,10}(?: cli ([-0-9a-fA-F.:]+))?(?: via TLS tunnel)?\)/) ) { if (! $client) { $client = "*not named*"; } $wrongPassword{$client}{$user}++; $wrong_client{$client}++; } # TD: Login incorrect (eap_tls: (TLS) OpenSSL says error 10 : certificate has expired): [USERNAME] (from client CLIENTNAME port 50427 cli F8-E4-3B-F1-80-90) elsif ( my ($user, $client) = ( $ThisLine =~ m/^(?:Auth: )?Login incorrect \(.*certificate has expired\): \[(.*)\] \(from client [^ ]* port \d{1,10}(?: cli ([-0-9a-fA-F.:]+)(?:;\w+)?)?(?: via TLS tunnel)?\)/) ) { if (! $client) { $client = "*not named*"; } $certificateExpired{$client}{$user}++; $wrong_client{$client}++; } # TD: Invalid user ( [ldap] Access Attribute denies access): [user@example.com] (from client radius port 13 cli aa-bb-cc-dd-ee-11 via TLS tunnel) # TD: Invalid user: [user@example.com] (from client port 13 cli aa-bb-cc-dd-ee-11) elsif ( my ($reason, $user, $client) = ($ThisLine =~ m/^(?:Auth: )?Invalid user(?: \(\s*(.+)\))?: \[(.+)\] \(from client [^ ]* port \d{1,10}(?: cli ([-0-9a-fA-F.:]+))?(?: via TLS tunnel)?\)/) ) { if (! $client) { $client = "*not named*"; } if (! $reason) { $reason = "*no reason*"; } $invalidUser{$reason}{$user}++; } # TD: Discarding duplicate request from client port 47609 - ID: 182 due to unfinished request 12713766 # TD: Discarding conflicting packet from client port 42221 - ID: 85 due to recent request 9008535. elsif ( my ($reason, $client) = ($ThisLine =~ /Discarding (duplicate request|conflicting packet) from client (\S+) port \d+ - ID: \d+ due to (unfinished|recent) request/) ) { $discards{$reason}{$client}++; } # TD: Received conflicting packet from client radius2 port 60612 - ID: 30 due to unfinished request 1136681. Giving up on old request. elsif ( my ($client) = ($ThisLine =~ /Received conflicting packet from client ([^ ]+) port \d{1,10} - ID: \d+ due to unfinished request \d+/) ) { $givingUps{$client}++; } # TD: eap_tls: ERROR: SSL says error 12 : CRL has expired elsif ( $ThisLine =~ m/CRL has expired/ ) { $crlExpired++; } # TD: Child PID 57436 is taking too much time: forcing failure and killing child. elsif ( $ThisLine =~ m/Child PID \d+ is taking too much time: forcing failure and killing child/ ) { $killedChilds++; } # TD: Started FreeRADIUS high performance RADIUS server.. elsif ( $ThisLine =~ /^Started FreeRADIUS/ ) { $started++; } # TD: Stopping FreeRADIUS high performance RADIUS server.. elsif ( $ThisLine =~ /^Stopped FreeRADIUS/ ) { $stopped++; } # TD: Reloading FreeRADIUS high performance RADIUS server elsif ( $ThisLine =~ /^Reloaded FreeRADIUS/ ) { $reloaded++; } # TD: Request 67678577 has been waiting in the processing queue for 378 seconds. Check that all databases are running properly! elsif ($ThisLine =~ m/^Request \d+ has been waiting in the processing queue for (\d+) seconds/) { $requests++; $requests_duration += $1; } # TD: WARNING: Unresponsive child for request 4737598, in component accounting module unix # TD: WARNING: Child is hung for request 4737598 in component accounting module unix. elsif ( $ThisLine =~ m/^WARNING: (Unresponsive child|Child is hung) for request \d+,? in component ([<>\w]+) module ?([<>\w]*)/ ) { $warnings{"$1 in component:"}{"$2 [module: $3]"}++; } # TD: WARNING: Allowing fast client radius2 port 60612 - ID: 102 for recent request 9035637. elsif ( $ThisLine =~ m/^WARNING: (Allowing fast client) ([^ ]+) port \d{1,10} - ID: \d+/ ) { $warnings{"${1}s:"}{$2}++; } else { # Report any unmatched entries... $OtherList{$ThisLine}++; } } ################################# # Output section ################################ if ($requests > 0) { printf "Long running requests: Check that all databases are running properly!\n"; printf " %-40s : %5d\n", 'Long running requests', $requests; printf " %-40s : %5d s\n", 'avg queue time per long running request', $requests_duration / $requests; print "\n"; } sub compPerMacAddr { return $wrong_client{$b} <=> $wrong_client{$a}; } if ($Detail >= 8) { if (keys %wrong_client) { print "\nSum of failed logins per client (wrong password or user)\n"; foreach my $client (sort compPerMacAddr keys %wrong_client) { printf " %-40s : %5d time(s)\n", $client, $wrong_client{$client}; } } } if (keys %certificateExpired) { if ($Detail >= 3) { print "\nFailed logins - certificate expired:\n"; foreach my $client (sort compPerMacAddr keys %certificateExpired) { my $users = $certificateExpired{$client}; printf " %-40s\n", $client ; foreach my $user (sort {$users->{$b} <=> $users->{$a}} keys %$users) { #print " $user ", $users->{$user}, " time(s)\n"; printf " %-38s : %5d time(s)\n", $user, $users->{$user}; } } } else { my $certificateExpiredSum = 0; foreach my $client (%certificateExpired) { my $users = $certificateExpired{$client}; foreach my $user (keys %$users) { $certificateExpiredSum += $users->{$user}; } } printf "\n%-42s : %5d time(s)\n", "Failed logins - certificate expired", $certificateExpiredSum; } } if (keys %wrongUser) { if ($Detail >= 3) { print "\nFailed logins - wrong user name:\n"; foreach my $client (sort compPerMacAddr keys %wrongUser) { printf " %-40s\n", $client; my $users = $wrongUser{$client}; foreach my $user (sort {$users->{$b} <=> $users->{$a}} keys %$users) { printf " %-38s : %5d time(s)\n", $user, $users->{$user}; } } } else { my $userSum = 0; foreach my $client (keys %wrongUser) { my $users = $wrongUser{$client}; foreach my $user (keys %$users) { $userSum += $users->{$user}; } } printf "\n%-42s : %5d time(s)\n", "Failed logins - wrong user name", $userSum; } } if (keys %wrongPassword) { if ($Detail >= 6) { print "\nFailed logins - wrong password:\n"; foreach my $client (sort compPerMacAddr keys %wrongPassword) { my $users = $wrongPassword{$client}; printf " %-40s\n", $client ; foreach my $user (sort {$users->{$b} <=> $users->{$a}} keys %$users) { #print " $user ", $users->{$user}, " time(s)\n"; printf " %-38s : %5d time(s)\n", $user, $users->{$user}; } } } else { my $wrongPasswordSum = 0; foreach my $client (%wrongPassword) { my $users = $wrongPassword{$client}; foreach my $user (keys %$users) { $wrongPasswordSum += $users->{$user}; } } printf "\n%-42s : %5d time(s)\n", "Failed logins - wrong password", $wrongPasswordSum; } } if (keys %invalidUser) { if ($Detail >= 6) { print "\nInvalid User:\n"; foreach my $reason (keys %invalidUser) { my $users = $invalidUser{$reason}; printf " %-40s\n", $reason; foreach my $user (sort {$users->{$b} <=> $users->{$a}} keys %$users) { printf " %-38s : %5d time(s)\n", $user, $users->{$user}; } } } else { my $invalidUserSum = 0; foreach my $reason (keys %invalidUser) { my $users = $invalidUser{$reason}; foreach my $user (keys %$users) { $invalidUserSum += $users->{$user}; } } printf "\n%-42s : %5d time(s)\n", "Invalid Users", $invalidUserSum; } } if (keys %discards) { print "\nDiscards:\n"; foreach my $reason (keys %discards) { my $clients = $discards{$reason}; printf " %-40s\n", $reason; foreach my $client (keys %$clients) { printf " %-38s : %5d time(s)\n", $client, $clients->{$client}; } } } if (keys %givingUps) { print "\nGiving up on old requests:\n"; foreach my $client (keys %givingUps) { printf " %-40s : %5d time(s)\n", $client, $givingUps{$client}; } } if ($crlExpired) { printf "\nCRL Expired: %5d time(s)\n", $crlExpired; } if ($killedChilds) { printf "\n%-42s : %5d time(s)\n", "Killed Childs (taking too much time)", $killedChilds; } if (%warnings) { print "\nWarnings:\n"; foreach my $warning (keys %warnings) { my $components = $warnings{$warning}; printf " %-40s\n", $warning; foreach my $component (keys %$components) { printf " %-38s : %5d time(s)\n", $component, $components->{$component}; } } } if (keys %loginsOk) { if ($Detail >= 10) { print "\nSuccessful logins:\n"; foreach my $user (sort {$loginsOk{$b} <=> $loginsOk{$a}} keys %loginsOk) { printf " %-40s : %5d time(s)\n", $user, $loginsOk{$user}; } } elsif ($Detail >= 6) { my $loginsOkSum = 0; foreach my $user (keys %loginsOk) { $loginsOkSum += $loginsOk{$user}; } printf "\n%-42s : %5d time(s)\n", "Successful logins", $loginsOkSum; } } if ($Detail >= 5 && $started) { printf "\nServer started: %5d time(s)\n", $started; } if ($Detail >= 5 && $stopped) { printf "\nServer stopped: %5d time(s)\n", $stopped; } if ($Detail >= 5 && $reloaded) { printf "\nServer reloaded: %5d time(s)\n", $reloaded; } if (keys %OtherList) { print "\n**** Unmatched entries ****\n"; foreach (keys %OtherList) { print " $_ : $OtherList{$_} Time(s)\n"; } } exit(0); # vi: shiftwidth=3 tabstop=3 syntax=perl et logwatch-7.12/scripts/services/exim0000664000211400021140000007236114274101036017653 0ustar logwatchlogwatch ######################################################## # Please file all bug reports, patches, and feature # requests under: # https://sourceforge.net/p/logwatch/_list/tickets # Help requests and discusion can be filed under: # https://sourceforge.net/p/logwatch/discussion/ ######################################################## ######################################################## # Originally written by: # Dariusz Nierada ######################################################## ######################################################## # Default Detail Levels: # 0: Prints MisFormatted log lines (should never happen) # Virus/Malware blocks (if AntiVirus configured) # Prints protocol violations (by category) # Prints address verification rejections # Prints administrative rejections (by category) # Prints Refused Relay count # # 5: Prints Queue Run count # Prints server Stop/Start # # 10: Prints Refused Relay (individual lines) # Prints Per Message Tracking ######################################################## ######################################################## ## Copyright (c) 2008 Gary Allen Vollink ## Covered under the included MIT/X-Consortium License: ## http://www.opensource.org/licenses/mit-license.php ## All modifications and contributions by other persons to ## this script are assumed to have been donated to the ## Logwatch project and thus assume the above copyright ## and licensing terms. If you want to make contributions ## under your own copyright or a different license this ## must be explicitly stated in the contribution an the ## Logwatch project reserves the right to not accept such ## contributions. If you have made significant ## contributions to this script and want to claim ## copyright please contact logwatch-devel@lists.sourceforge.net. ######################################################### use Logwatch ':dates'; use warnings; use strict; my $Detail = $ENV{'LOGWATCH_DETAIL_LEVEL'} || 0; my $LvlBadFormat = $ENV{'exim_misformat'} || 0; my $LvlRestarts = $ENV{'exim_restart'} || 5; my $LvlVirus = $ENV{'exim_virus'} || 0; my $LvlProtocol = $ENV{'exim_protocol'} || 0; my $LvlProtocolLines = $ENV{'exim_protocol_lines'}|| 5; my $LvlDontAccept = $ENV{'exim_dontaccept'} || 0; my $LvlDontAcceptLines = $ENV{'exim_dontaccept_lines'} || 0; my $LvlVerify = $ENV{'exim_verify'} || 0; my $LvlVerifyLines = $ENV{'exim_verify_lines'} || 5; my $LvlRuns = $ENV{'exim_runs'} || 5; my $LvlRelay = $ENV{'exim_relay'} || 0; my $LvlRelayLines = $ENV{'exim_relay_lines'} || 10; my $LvlMsgs = $ENV{'exim_mesgs'} || 10; #Init String Containers my ( $Greylist, $KeepEnv, $Lookup, $NextLine, $Purging, $RecipVerify, $Relay, $ReverseLookup, $SendVerify, $aa, $bb, $cc, $day1, $h1, $licze, $m1, $mdate, $mid, $month1, $mrest, $mtime, $qttmsg, $s1, $tmsg, $ttmsg, $year1 ); #Init Hashes my ( %BadFormat, %DontAccept, %OtherList, %Proto, %RecipVerify, %SendVerify, %Virus, %h, %mmsg, ); #Init Arrays my ( @GreylistH, @LookupH, @RecipVerify, @RelayH, @Restart, @ReverseLookupH, @SendVerify, @errList, ) = (); # procedura sortujaca tak jak ja chce (bo tamta sotrowala po ASCII) # procedure to compare numbers at the beginning of submitted strings. # .. Which in this case is the message count for a given message ID. sub wedlug_liczb { ($aa) = ($a =~ /^(\d+).+/); ($bb) = ($b =~ /^(\d+).+/); $aa <=> $bb; } # START my $SearchDate = TimeFilter("%Y-%m-%d %H:%M:%S"); my $StartQueue = 0; my $EndQueue = 0; # Regex to match IPv4 addresses and IPv6 addresses # IPv6 part could be made more strict my $IPAddress = qr/\d+\.\d+\.\d+\.\d+|[a-fA-F0-9]*:[a-fA-F0-9:]+/; my $MatchedDate = 0; my @SelfSignedH; while (defined(my $ThisLine = )) { chomp($ThisLine); # pobierz dzisiejsza date z 2002-03-31 22:13:48 ... # Collect this line's date, e.g. 2002-03-31 22:13:48 ... do { if ( $ThisLine =~ /^ Suggested action: use keep_environment./ ) { $KeepEnv++ if $MatchedDate; next; } if ( $ThisLine =~ /^ Suggested action: either install a certificate or change tls_advertise_hosts option/ ) { # ignore this; outside of date range next; } $BadFormat{$ThisLine}++; next; } unless ($year1,$month1,$day1,$h1,$m1,$s1) = ($ThisLine =~ /^(\d+)\-(\d+)\-(\d+)\s(\d+):(\d+):(\d+)\s.+/); unless ($ThisLine =~ /^$SearchDate /o) { $MatchedDate = 0; next; } $MatchedDate = 1; if ( $ThisLine =~ /End queue run\:/ ) { $EndQueue++; } elsif ( $ThisLine =~ /Start queue run\:/ ) { $StartQueue++; } elsif ( $ThisLine =~ /sender verify defer/ ) { # ignore this; it's temporary } elsif ( $ThisLine =~ /unknown variable name/ ) { # ignore this temporarily } elsif ( $ThisLine =~ /ignoring AUTH=.*? \(client not authenticated\)/ ) { # ignore this; it is a warning. } elsif ( $ThisLine =~ /cwd=.*? \d args: / ) { # ignore this; it is exim (or an Exim sub-command) starting. } elsif ( $ThisLine =~ /[Rr]ecipient verify fail/ ) { $RecipVerify{$ThisLine}++; } elsif ( $ThisLine =~ /[Ss]ender verify fail/ ) { $SendVerify{$ThisLine}++; } elsif ( $ThisLine =~ /Warning: purging the environment./ ) { $Purging++; } elsif ( $ThisLine =~ /fragments administratively prohib/ ) { $DontAccept{$ThisLine}++; } elsif ( $ThisLine =~ /unqualified (sender|recipient) rejected/ ) { $DontAccept{$ThisLine}++; } elsif ( $ThisLine =~ /do not accept mail / ) { $DontAccept{$ThisLine}++; } elsif ( $ThisLine =~ /rejected connection in .connect. ACL/ ) { # Likely policy rejections $DontAccept{$ThisLine}++; } elsif ( $ThisLine =~ /believed to be spam/ ) { $DontAccept{$ThisLine}++; } elsif ( $ThisLine =~ /[Ww]arning: dnsbl\.sorbs\.net/ ) { $DontAccept{$ThisLine}++; } elsif ( $ThisLine =~ /mail not permitted from/ ) { $DontAccept{$ThisLine}++; } elsif ( $ThisLine =~ /file, which is blacklisted/ ) { $DontAccept{$ThisLine}++; } elsif ( $ThisLine =~ /not accept Windows executables/ ) { $DontAccept{$ThisLine}++; } elsif ( $ThisLine =~ /remote host address is the local host/ ) { $DontAccept{$ThisLine}++; } elsif ( $ThisLine =~ /message contains malware/ ) { # Exim <= 4.44 with ExiScan-ACL Patch (Running AntiVirus Software) $Virus{$ThisLine}++; } elsif ( $ThisLine =~ /message contains a [vV]irus/ ) { # Exim >= 4.50 compiled with WITH_CONTENT_SCAN=yes (Running AntiVirus Software) $Virus{$ThisLine}++; } elsif ( $ThisLine =~ /SMTP connection from/ ) { # Common error from SPAM hosts. $Proto{$ThisLine}++; } elsif ( $ThisLine =~ /SMTP syntax error in/ ) { # Common error from SPAM hosts. $Proto{$ThisLine}++; } elsif ( $ThisLine =~ /remote host used my name in HELO/ ) { # Common error from SPAM hosts. $Proto{$ThisLine}++; } elsif ( $ThisLine =~ /remote host used IP address in HELO/ ) { # Common error from SPAM hosts. $Proto{$ThisLine}++; } elsif ( $ThisLine =~ /unexpected disconnection while reading SMTP command/ ) { # Common error from SPAM hosts. $Proto{$ThisLine}++; } elsif ( $ThisLine =~ /SMTP protocol violation/ ) { # Common error from SPAM hosts. $Proto{$ThisLine}++; } elsif ( $ThisLine =~ /SMTP command timeout/ ) { # Common error from SPAM hosts. $Proto{$ThisLine}++; } elsif ( $ThisLine =~ /SMTP data timeout/ ) { # Common error from SPAM hosts. $Proto{$ThisLine}++; } elsif ( $ThisLine =~ /incomplete transaction \(([\s\w]+)\) from/ ) { # Common error from SPAM hosts (after recipient reject/callout). $Proto{$ThisLine}++; } elsif ( $ThisLine =~ /SMTP protocol synchronization error \(([\s\w:]+)\):/ ) { # Spammer who does not wait before sending crap $Proto{$ThisLine}++; } elsif ( $ThisLine =~ /AUTH command used when not advertised/ ) { # Spammer who does not read protocol $Proto{$ThisLine}++; } elsif ( $ThisLine =~ /dropped: too many nonmail commands/ ) { # Often someone who tries lots of transactions $Proto{$ThisLine}++; } elsif ( $ThisLine =~ /dropped: too many syntax or protocol errors/ ) { # Often someone who tries lots of transactions $Proto{$ThisLine}++; } elsif ( $ThisLine =~ /SMTP protocol error in \"[^\"]+\"/ ) { # Some hosts ask for TLS even when not offered (generalised to all cmds) $Proto{$ThisLine}++; } elsif ( $ThisLine =~ /TLS error on connection from/ ) { # Various TLS errrors $Proto{$ThisLine}++; } elsif ( $ThisLine =~ /authenticator failed for/ ) { $Proto{$ThisLine}++; } elsif ( $ThisLine =~ /Connection from .* too many connections from that IP address/ ) { # Some hosts make lots of simultaneous connections # this is an extra error message when logging is high # and since another message duplicates it, we can just ignore this } elsif ( $ThisLine =~ /rejected [HE][EH]LO from\s/ ) { # Typically due to underscores _ in the HELO line # (a common protocol violation) # Also can be due to odd escape sequences # (never seen from a valid MX) $Proto{$ThisLine}++; } elsif ( $ThisLine =~ /SIGHUP received\: re-exec/ ) { push @Restart, "$year1-$month1-$day1 $h1:$m1:$s1 (stop)"; } elsif ( $ThisLine =~ /daemon started\:/ ) { push @Restart, "$year1-$month1-$day1 $h1:$m1:$s1 (start)"; } elsif ( $ThisLine =~ /rejected RCPT.*greylist/) { $Greylist++; push @GreylistH, $ThisLine; } elsif ( $ThisLine =~ /refused relay/ || $ThisLine =~ /rejected RCPT/ ) { $Relay++; push @RelayH, $ThisLine; } elsif ( $ThisLine =~ /no host name found for IP address/ ) { $ReverseLookup++; push @ReverseLookupH, $ThisLine; } elsif ( $ThisLine =~ /no IP address found for host/ ) { $Lookup++; push @LookupH, $ThisLine; } elsif ( $ThisLine =~ /No server certificate defined; will use a selfsigned one/ ) { $NextLine = ; chomp($NextLine); $ThisLine .= "\n" . $NextLine; push @SelfSignedH, $ThisLine; } elsif ( $ThisLine =~ /DKIM: .* \[verification succeeded\]/ ) { # Ignore successful DKIM verification reports # http://www.exim.org/exim-html-current/doc/html/spec_html/ch-support_for_dkim_domainkeys_identified_mail.html } elsif ( $ThisLine =~ /^\d+\-\d+\-\d+\s\d+\:\d+\:\d+\s(\+\d+\s)?\w+\-\w+\-\w+\s/ ) { # inne wiadomosci przesylane przez EXIMA # Collect Message ID specific notes... ($mdate,$mtime,$mid,$mrest) = ($ThisLine =~ /^(\d+\-\d+\-\d+)\s(\d+\:\d+\:\d+)\s(?:\+\d+\s)?(\w+\-\w+\-\w+)(.+)/); # Count of individual Message Lines, used for sort $licze++; # Dodaje taki licznik aby potem przy wypisaniu posortowac po nim, bo wypisywal nie po kolei $mmsg{$mid}{$licze.$mrest} = "$mdate $mtime"; } else { $OtherList{$ThisLine}++; } } #end while # Print MisFormatted log lines (should never happen) if ($Detail >= $LvlBadFormat) { if (%BadFormat) { print "\n***** BAD FORMAT (Possible data corruption or Exim bug) *****\n"; foreach my $ThisOne (keys %BadFormat) { print "$ThisOne\n"; } } } # Print server Stops/Starts if ($Detail >= $LvlRestarts) { if (@Restart) { print "\n--- Exim Restarted ---\n"; foreach my $ThisOne (sort @Restart) { print " $ThisOne\n"; } } } if ($Purging) { print " Warning: purging the environment. : $Purging Time(s)\n"; } if ($KeepEnv) { print " ... Suggested action: use keep_environment. : $KeepEnv Time(s)\n"; } if ($Detail >= $LvlRuns) { if (($StartQueue >0 ) or ($EndQueue > 0)) { print "\n--- Queue Runners ---\n"; # Start Queue $StartQueue and print " Start queue run: $StartQueue Time(s)\n"; # End Queue $EndQueue and print " End queue run: $EndQueue Time(s)\n"; } } if (@SelfSignedH) { my $SelfSignedH = @SelfSignedH; print "\n--- Self-Signed Certificate in use ($SelfSignedH Time(s))\n"; if ($Detail >= $LvlMsgs) { foreach my $ThisOne (@SelfSignedH) { print "$ThisOne\n"; } } } if ($Detail >= $LvlVerify) { if ((@SendVerify) and (@RecipVerify)) { print "\n--- Address Verification ---\n"; } if (@SendVerify) { # Sender Verifies $SendVerify and print "\nSender Verify failures: $SendVerify Time(s)\n"; if ($Detail >= $LvlVerifyLines) { foreach my $ThisOne (@SendVerify) { print " $ThisOne\n"; } } } if (@RecipVerify) { # Recip Verifies $RecipVerify and print "Recipient Verify failures: $RecipVerify Time(s)\n"; if ($Detail >= $LvlVerifyLines) { foreach my $ThisOne (@RecipVerify) { print " $ThisOne\n"; } } } } if ($Detail >= $LvlRelay) { if (@GreylistH) { print "\n--- Greylisted $Greylist times\n"; if ( $Detail >= $LvlRelayLines ) { print "--- Lines follow:\n\n"; foreach my $ThisOne (@GreylistH) { print "$ThisOne\n"; } } } if (@RelayH) { print "\n--- Refused Relays $Relay times\n"; if ( $Detail >= $LvlRelayLines ) { print "--- Lines follow:\n\n"; foreach my $ThisOne (@RelayH) { print "$ThisOne\n"; } } } } if ($Detail >= $LvlVirus) { # Print Blocked Viruses/Malware if (%Virus) { my (%vir); print "\n--- Virus/Malware Blocked ---\n"; foreach my $ThisOne (sort(keys %Virus)) { # Need mid empty... $mid = ""; # Virus name holder... $cc = ""; # Extract exim date and time string... ($mdate, $mtime) = ($ThisOne =~ m/^(\d+-\d+-\d+)\s(\d+\:\d+\:\d+)\s/); # Link date and time (looks cleaner)... $aa = "$mdate $mtime"; # Extract the REAL IP address... ($bb) = ($ThisOne =~ m/\s\[($IPAddress)\][\s:]/); # Exim >= 4.50 compiled with, WITH_CONTENT_SCAN=yes # Default warning looks like this... # rejected after DATA: This message contains a [vV]irus (%s). if ($ThisOne =~ m/virus \((.*?)\)/) { $cc = $1; } # Exim <= 4.44 with ExiScan-ACL patch # rejected after DATA: This message contains malware (%s) elsif ($ThisOne =~ m/malware \((.*?)\)/) { $cc = $1; } # There is probably a more graceful way to do this... if (defined( $vir{$cc} )) { # Assign current value to temporary (mid) $mid = $vir{$cc}; } # Set current value to (old value)+new value+',' $vir{$cc} = "$mid$aa : IP:$bb,"; } # Print the results... foreach my $ThisOne (sort(keys %vir)) { print "Virus: [$ThisOne]\n"; foreach $aa ( sort( split /,/, $vir{$ThisOne} )) { print " $aa\n"; } } } } if ($Detail >= $LvlDontAccept) { # Print Administrative Prohibitions if (%DontAccept) { my (%spam, %detail); my (@errList); # Probable SPAM hosts... print "\n--- Admin Policy Blocking ---\n"; foreach my $ThisOne (sort(keys %DontAccept)) { # We need this blank. $mid = ""; # IP address/current issue holder. $bb = ""; # Extract exim date and time string... ($mdate, $mtime) = ($ThisOne =~ m/^(\d+-\d+-\d+)\s(\d+\:\d+\:\d+)\s/); # Link date and time (looks cleaner)... $aa = "$mdate $mtime"; if ( $ThisOne =~ m/do not accept mail from ([\w\*-._]+)@([\w.-_]+)/ ) { $cc = "Blocked Email Domain"; $bb = "$1\@$2"; } elsif ( $ThisOne =~ m/rejected connection in .connect. ACL/ ) { $cc = "Blocked Host"; ( $bb ) = ($ThisOne =~ m/\[(\d+\.\d+\.\d+\.\d+)\]/); } elsif ( $ThisOne =~ m/mail not permitted from sender ([\w\*-_.]+)@([\w.-_]+)/ ) { $cc = "Blocked Email Address"; $bb = "$1\@$2"; } elsif ( $ThisOne =~ m/contains attached ".(.*)" file, which is blacklisted/ ) { $cc = "Blocked Attachment"; ( $bb ) = ($ThisOne =~ m/\[($IPAddress)\]/); } elsif ( $ThisOne =~ /believed to be spam/ ) { $cc = "Blocked Fragmented Message"; ( $bb ) = ($ThisOne =~ m/\[($IPAddress)\]/); } elsif ( $ThisOne =~ /[Ww]arning: dnsbl\.sorbs\.net/ ) { $cc = "Blocked by DNSBL (SORBS)"; ( $bb ) = ($ThisOne =~ m/\[($IPAddress)\]/); } elsif ( $ThisOne =~ /fragments administratively prohibited/ ) { $cc = "Blocked Fragmented Message"; ( $bb ) = ($ThisOne =~ m/\[($IPAddress)\]/); } elsif ( $ThisOne =~ m/unqualified sender rejected: <(.*)>/ ) { $cc = "Unqualified Sender"; $bb = "$1"; } elsif ( $ThisOne =~ m/unqualified recipient rejected: <(.*)>/ ) { $cc = "Unqualified Receipient"; $bb = "$1"; } elsif ( $ThisOne =~ m/not accept Windows executables/ ) { $cc = "Blocked Attachment"; ( $bb ) = ($ThisOne =~ m/\[($IPAddress)\]/); } elsif ( $ThisOne =~ m/remote host address is the local host/ ) { $cc = "Invalid local domain"; ( $bb ) = ($ThisOne =~ m/\@[^>]+/); } else { # If we picked up a malfunction but didn't collect it here, # no need to make the user suffer with superfluous error # messages. print "Didn't Summarize: $ThisOne\n"; next; } if ($cc =~ m/Blocked/ ) { # hash of blocked things my $h = {}; if (!defined($detail{$cc})) { # debug print "add type $cc\n" ; $detail{$cc} = $h; } $h = $detail{$cc}; if (defined($h{$bb})) { # debug print "add $bb to ".$h{$bb}."\n" ; $h{$bb} = $h{$bb} + 1; } else { $h{$bb} = 1; # debug print "start $bb at ".$h{$bb}."\n" ; } # marker $spam{$cc} = ""; } else { if (defined( $spam{$cc} )) { $mid = $spam{$cc}; } $spam{$cc} = "$mid$aa : $bb,"; } } foreach my $ThisOne (sort(keys %spam)) { if ($Detail >= $LvlDontAcceptLines) { if ($spam{$cc} eq "") { print " $ThisOne\n"; my $h = $detail{$ThisOne}; foreach $aa (sort(keys %h) ) { print " $aa : ".$h{$aa}." times\n"; } } else { print " $ThisOne\n"; foreach $aa ( sort( split /,/, $spam{$ThisOne} )) { print " $aa\n"; } } } else { @errList = split /,/, $spam{$ThisOne}; print " $ThisOne ".scalar @errList." times\n"; } } } } if ($Detail >= $LvlProtocol) { # Print Protocol Violations if (%Proto) { my (%spam); my (%SmtpConnection); my (%SmtpProblemHosts); my (%TlsProblemClasses); my (%TlsProblemHosts); # Probable SPAM hosts... print "\n--- Bad Hosts ---\n"; foreach my $ThisOne (sort(keys %Proto)) { # We need this blank. $mid = ""; # IP address/current issue holder. $bb = ""; $cc = ""; # Extract exim date and time string... ($mdate, $mtime) = ($ThisOne =~ m/^(\d+-\d+-\d+)\s(\d+\:\d+\:\d+)\s/); # Link date and time (looks cleaner)... $aa = "$mdate $mtime"; if ( $ThisOne =~ m/SMTP protocol violation\:\s(.*?\(.*?\))\:/ ) { $cc = $1; ( $bb ) = ($ThisOne =~ m/\[($IPAddress)\]/); } elsif ( $ThisOne =~ /unexpected disconnection while reading SMTP command/ ) { $cc = "Sudden disconnect while expecting remote input"; ( $bb ) = ($ThisOne =~ m/\[($IPAddress)\]/); } elsif ( $ThisOne =~ m/rejected ([HE][EH])LO from \[($IPAddress)\]\:\s(.*?):\s(.*?)$/ ) { $cc = "Rejected HELO/EHLO: $3"; $bb = "$2 ($1LO $4)"; } elsif ( $ThisOne =~ /SMTP data timeout \(message abandoned\) on connection from/ ) { $cc = "SMTP Timeout errors"; ( $bb ) = ($ThisOne =~ m/\[($IPAddress)\]/); } elsif ( $ThisOne =~ /SMTP command timeout on connection from/ ) { $cc = "SMTP Timeout errors"; ( $bb ) = ($ThisOne =~ m/\[($IPAddress)\]/); } elsif ( $ThisOne =~ /syntactically invalid argument/ ) { $cc = "SMTP Syntax errors"; ( $bb ) = ($ThisOne =~ m/\[($IPAddress)\]/); } elsif ( $ThisOne =~ /SMTP syntax error in/ ) { $cc = "SMTP Syntax errors"; ( $bb ) = ($ThisOne =~ m/\[($IPAddress)\]/); } elsif ( $ThisOne =~ /remote host used my name in HELO/ ) { $cc = "My name in HELO"; ( $bb ) = ($ThisOne =~ m/\[($IPAddress)\]/); } elsif ( $ThisOne =~ /remote host used IP address in HELO/ ) { $cc = "IP address in HELO"; ( $bb ) = ($ThisOne =~ m/\[($IPAddress)\]/); } elsif ( $ThisOne =~ /incomplete transaction (\(.*\))/ ) { $bb = "SMTP transaction cut short $1"; $SmtpConnection{$bb}++; } elsif ( $ThisOne =~ /SMTP protocol synchronization error/ ) { $bb = "SMTP protocol synchronization error"; $SmtpConnection{$bb}++; } elsif ( $ThisOne =~ /dropped: too many nonmail commands/ ) { $bb = "Connection dropped after too many nonmail SMTP commands"; $SmtpConnection{$bb}++; } elsif ( $ThisOne =~ /dropped: too many syntax or protocol errors/ ) { $bb = "Connection dropped after too many syntax/protocol errors"; $SmtpConnection{$bb}++; } elsif ( $ThisOne =~ /(SMTP protocol error in \"\w+\")/ ) { $bb = $1; $SmtpConnection{$bb}++; } elsif ( $ThisOne =~ /\[([^]]+)\] (AUTH command used when not advertised)/ ) { my $key = $1; $bb = $2; $SmtpProblemHosts{$key}++; $SmtpConnection{$bb}++; } elsif ( $ThisOne =~ /authenticator failed for (?:\S+ |)\([^)]*\) \[($IPAddress)\](?::\d+ |)(?:I=\[$IPAddress\]:\d+|): ([^(]*)/ ) { my $key = $1; $bb = $2; $bb =~ s/\s+$//; $SmtpProblemHosts{$key}++; $SmtpConnection{$bb}++; } elsif ( $ThisOne =~ /TLS error on connection from (?:(\S+) |)(?:\(([^)]*)\) |)\[($IPAddress)\](?::\d+|) (?:I=\[$IPAddress\](?::\d+|) |)\(([^)]+)\): (.*)/ ) { my ($reverseHost, $hostLabel, $hostAddress, $action, $message) = ($1, $2, $3, $4, $5); $message =~ s/\.$//; my $key = "$hostAddress"; if ($Detail > 50) { $key .= " ($hostLabel)" if ($hostLabel); $key .= " $reverseHost" if ($reverseHost); } elsif ($reverseHost) { $key = "$reverseHost"; if ($hostLabel && (() = $reverseHost =~ /\./g) > 2) { my ($common) = ($reverseHost =~ /^[^.]+(\..*)$/); $key = "($hostLabel)" if ($hostLabel =~ /^[^.]+\Q$common\E$/); } } $TlsProblemHosts{$key}++; $TlsProblemClasses{"$action: $message"}++; } elsif ( $ThisOne =~ /SMTP connection from/ ) { if ( $ThisOne =~ /lost while reading message data/ ) { $bb = "SMTP connection lost while reading message data"; } elsif ( $ThisOne =~ /Connection reset by peer/ ) { $bb = "SMTP connection lost when connection reset by peer "; } elsif ( $ThisOne =~ /lost/ ) { $bb = "SMTP connection lost (non-specific)"; } elsif ( $ThisOne =~ /closed by QUIT/ ) { $bb = "SMTP connection closed by QUIT"; } elsif ( $ThisOne =~ /closed after SIGTERM/ ) { $bb = "SMTP connection closed after SIGTERM"; } elsif ( $ThisOne =~ /TCP\/IP connection count/ ) { $bb = "SMTP connection TCP/IP connection count (warning)"; } if ( $bb ne "" ) { $SmtpConnection{$bb}++; } } else { # If we picked up a malfunction but didn't collect it here, # no need to make the user suffer with superfluous error # messages. #next; print "Didn't Summarize: $ThisOne\n"; } if (defined( $spam{$cc} )) { $mid = $spam{$cc}; } # We're picking things up in this larger block that do not # ... fit into this mold, so - let's make sure that this is valid # ... before we set it: if (( $cc ne '' ) && ( $bb ne '' )) { $spam{$cc} = "$mid$aa : IP:$bb,"; } } foreach my $ThisOne (sort(keys %spam)) { if ($Detail >= $LvlProtocolLines) { print " $ThisOne:\n"; foreach $aa ( sort( split /,/, $spam{$ThisOne} )) { print " $aa\n"; } } else { @errList = split /,/, $spam{$ThisOne}; print " $ThisOne ".scalar @errList." times\n"; } } if ( %TlsProblemClasses ) { print "\n--- TLS Connection Issues \n"; foreach my $ThisOne (sort keys %TlsProblemClasses) { $bb = $TlsProblemClasses{$ThisOne}; print " $ThisOne: $bb Time(s)\n"; } print "\n From these hosts:\n"; foreach my $ThisOne (sort keys %TlsProblemHosts) { $bb = $TlsProblemHosts{$ThisOne}; print " $ThisOne: $bb Time(s)\n"; } } if ( %SmtpConnection ) { print "\n--- SMTP Connection Issues \n"; foreach my $ThisOne (sort keys %SmtpConnection) { $bb = $SmtpConnection{$ThisOne}; print " $ThisOne: $bb Time(s)\n"; } print "\n From these hosts:\n"; foreach my $ThisOne (sort keys %SmtpProblemHosts) { $bb = $SmtpProblemHosts{$ThisOne}; print " $ThisOne: $bb Time(s)\n"; } } if (@ReverseLookupH) { print "\n--- Failed Reverse Lookups \n"; print "--- $ReverseLookup Time(s)\n\n"; if ($Detail >= $LvlProtocolLines) { foreach my $ThisOne (@ReverseLookupH) { print " $ThisOne\n"; } } } if (@LookupH) { print "\n--- Failed Reverse Lookups \n"; print "--- (e.g. spam try): $Lookup Time(s)\n\n"; if ($Detail >= $LvlProtocolLines) { foreach my $ThisOne (@LookupH) { print "$ThisOne\n"; } } } } } if ($Detail >= $LvlMsgs) { # Messages by ID if (keys %mmsg ) { my $tmsgcount=0; my $tmsgrcpts=0; print "\n--- Messages history ---\n\n"; # mmsg is hashed by message id, which is sorted by time foreach $tmsg (sort keys %mmsg) { my @tmsgkeys = sort {wedlug_liczb} keys %{$mmsg{$tmsg}}; my $immed_deliv = 1; $immed_deliv = 0 unless $tmsgkeys[0] =~ /^\d+ <=/; foreach my $key (@tmsgkeys[1..$#tmsgkeys-1]) { $immed_deliv = 0 unless $key =~ /^\d+ [-=]>/; } $immed_deliv = 0 unless $tmsgkeys[$#tmsgkeys] =~ /^\d+ Completed/; my $qttmsgcount = 0; my $oldqttmsg = ''; if (!$immed_deliv) { print "\-MsgID: $tmsg\: \n"; foreach $ttmsg (@tmsgkeys) { $qttmsg = $ttmsg; $qttmsg =~ s/^\d+//; # wywal licznik na poczatku (te od sortowania) $qttmsg =~ s/P\=e*smtp S.+//; # wywal koncowki typu: P=smtp S=372023 id= if ($oldqttmsg eq $qttmsg) { $qttmsgcount++; } else { $oldqttmsg = $qttmsg; if ($qttmsgcount > 0) { print "\tlast message repeated $qttmsgcount times\n"; $qttmsgcount = 0; } print "\t$mmsg{$tmsg}{$ttmsg}$qttmsg\n"; } } if ($qttmsgcount > 0) { print "\tlast message repeated $qttmsgcount times\n"; } } else { $tmsgcount++; $tmsgrcpts+=$#tmsgkeys-1; } } print "$tmsgcount messages delivered immediately "; print "to $tmsgrcpts total recipients\n"; } } # INNE Badziewia if (keys %OtherList) { print "\n**Unmatched Entries**\n"; foreach my $line (sort {$a cmp $b} keys %OtherList) { print "$line: $OtherList{$line} Time(s)\n"; } } exit(0); # vi: shiftwidth=3 tabstop=3 syntax=perl et # Local Variables: # mode: perl # perl-indent-level: 3 # indent-tabs-mode: nil # End: logwatch-7.12/scripts/services/vdr0000664000211400021140000002017614743365006017513 0ustar logwatchlogwatch ######################################################## # Please file all bug reports, patches, and feature # requests under: # https://sourceforge.net/p/logwatch/_list/tickets # Help requests and discusion can be filed under: # https://sourceforge.net/p/logwatch/discussion/ ######################################################## ########################################################################## # VDR script for Logwatch # # Copyright (c) 2012 Reiner Buehl ## Covered under the included MIT/X-Consortium License: ## http://www.opensource.org/licenses/mit-license.php ## All modifications and contributions by other persons to ## this script are assumed to have been donated to the ## Logwatch project and thus assume the above copyright ## and licensing terms. If you want to make contributions ## under your own copyright or a different license this ## must be explicitly stated in the contribution an the ## Logwatch project reserves the right to not accept such ## contributions. If you have made significant ## contributions to this script and want to claim ## copyright please contact logwatch-devel@lists.sourceforge.net. ######################################################### use strict; use Logwatch ':ip'; my $Detail = $ENV{'LOGWATCH_DETAIL_LEVEL'} || 0; my $IgnoreUnmatched = $ENV{'vdr_ignore_unmatched'} || 0; my $TSContinuityErrors = 0; my $PESPacketShortened = 0; my %FrontendTimeout = (); my $TransferBufferOverflow = 0; my @UnknownPicTypeError = (); my %ChannelNameChange = (); my %TimerSet = (); my %RecordingDeleted = (); my @OtherList; while (defined(my $ThisLine = )) { next if ($ThisLine eq ''); if ( # filter out svdrp connect messages ($ThisLine =~ /connect from .*, port .* - accepted/) or ($ThisLine =~ /closing SVDRP connection/) # filter out EPGSearch and Text2Skin messages or ($ThisLine =~ /EPGSearch:/) or ($ThisLine =~ /Text2Skin:/) # filter out pid, ca and caid changes or ($ThisLine =~ /changing pids of channel/) or ($ThisLine =~ /changing ca descriptors of channel/) or ($ThisLine =~ /changing caids of channel .* from .* to .*/) or ($ThisLine =~ /changing portal name of channel .* from .* to .*/) # filter out event status messages or ($ThisLine =~ /channel [0-9]+ \(.+\) event.*status [0-9]+/) # filter out directory scanner thread messages or ($ThisLine =~ /video directory scanner thread started/) or ($ThisLine =~ /video directory scanner thread ended/) # filter out delete recordings thread messages or ($ThisLine =~ /remove deleted recordings thread started/) or ($ThisLine =~ /remove deleted recordings thread ended/) # filter out file name truncate messages or ($ThisLine =~ /timer file name too long for VFAT file system/) or ($ThisLine =~ /timer file name truncated to/) or ($ThisLine =~ /timer .* modified/) # filter out timer status change messages or ($ThisLine =~ /timer .* added/) or ($ThisLine =~ /timer .* start/) or ($ThisLine =~ /timer .* stop/) or ($ThisLine =~ /deleting timer/) or ($ThisLine =~ /cleaning up schedules data/) # filter out additional timer start messages or ($ThisLine =~ /vdr: \[[0-9]+\] Title:/) or ($ThisLine =~ /vdr: \[[0-9]+\] executing .*vdr-recordingaction before/) or ($ThisLine =~ /vdr: \[[0-9]+\] executing .*vdr-recordingaction after/) or ($ThisLine =~ /vdr: \[[0-9]+\] record /) or ($ThisLine =~ /vdr: \[[0-9]+\] recording to /) or ($ThisLine =~ /vdr: \[[0-9]+\] creating directory /) or ($ThisLine =~ /vdr: \[[0-9]+\] recording thread started /) or ($ThisLine =~ /vdr: \[[0-9]+\] recording thread ended /) or ($ThisLine =~ /vdr: \[[0-9]+\] transfer thread started /) or ($ThisLine =~ /vdr: \[[0-9]+\] transfer thread ended /) or ($ThisLine =~ /vdr: \[[0-9]+\] file writer thread started /) or ($ThisLine =~ /vdr: \[[0-9]+\] file writer thread ended /) or ($ThisLine =~ /vdr: \[[0-9]+\] receiver on device [0-9]+ thread started /) or ($ThisLine =~ /vdr: \[[0-9]+\] receiver on device [0-9]+ thread ended /) or ($ThisLine =~ /vdr: \[[0-9]+\] TS buffer on device [0-9]+ thread started /) or ($ThisLine =~ /vdr: \[[0-9]+\] TS buffer on device [0-9]+ thread ended /) # filter out other messages or ($ThisLine =~ /vdr: \[[0-9]+\] switching device [0-9]+ to channel [0-9]+/) or ($ThisLine =~ /vdr: \[[0-9]+\] buffer stats: [0-9]+ \([0-9]+%\) used/) or ($ThisLine =~ /timer ([0-9]+) \(.*\) set to no event/) or ($ThisLine =~ /timer ([0-9]+) \(.*\) entered VPS margin/) or ($ThisLine =~ /switching to channel [0-9]+/) or ($ThisLine =~ /setting audio track to [0-9]+/) or ($ThisLine =~ /retuning due to modification of channel [0-9]+/) ) { # ignore the above strings } elsif ($ThisLine =~ /TS continuity error/) { $TSContinuityErrors++; } elsif ($ThisLine =~ /PES packet shortened/) { $PESPacketShortened++; } elsif ( my ($Frontend,$Channel) = ($ThisLine =~ /frontend ([0-9]+) timed out while tuning to channel ([0-9]+)/) ) { push @{$FrontendTimeout{$Frontend}}, $Channel; } elsif ($ThisLine =~ /clearing transfer buffer to avoid overflows/) { $TransferBufferOverflow++; } elsif ($ThisLine =~ /buffer usage: [0-9]+%/) { # ignore the above string } elsif ( my ($PicType) = ($ThisLine =~ /ERROR: unknown picture type '([0-9]+)'/) ) { push @UnknownPicTypeError,$PicType; } elsif ( my ($Channel, $From, $To) = ($ThisLine =~ /changing name of channel ([0-9]+) from '(.+)' to '(.+)'/) ) { $ChannelNameChange{$Channel} = "'$From' to '$To'"; } elsif ( my ($TimerNumber, $TimerEvent) = ($ThisLine =~ /timer ([0-9]+) \(.*\) set to event (.*)$/) ) { $TimerSet{$TimerEvent} = "$TimerNumber"; } elsif ( my ($RecordingName) = ($ThisLine =~ /removing recording (.*)$/) ) { $RecordingDeleted{$RecordingName} = "1"; } else { # Report any unmatched entries... push @OtherList,$ThisLine; } } if ($TSContinuityErrors > 0) { print "\n$TSContinuityErrors TS continuity error(s)\n"; } if ($PESPacketShortened > 0) { print "\n$PESPacketShortened PES packets shortened\n"; } if (keys %FrontendTimeout) { print "\n"; foreach my $Frontend (sort keys %FrontendTimeout) { my %counts = (); for (@{$FrontendTimeout{$Frontend}}) { $counts{$_}++; } my $result = ""; foreach my $keys (keys %counts) { $result .= "$keys ($counts{$keys} times), "; } $result =~ s/, $//; print "Frontend $Frontend timed out when changing to channels: $result\n"; } } if ($TransferBufferOverflow > 0) { print "\n$TransferBufferOverflow transfer buffer overflows\n"; } if ($#UnknownPicTypeError > 0) { print "\nUnknown picture type errors for picture types: "; my %counts = (); for (@UnknownPicTypeError) { $counts{$_}++; } my $result = ""; foreach my $keys (keys %counts) { $result .= "$keys ($counts{$keys} times), "; } $result =~ s/, $//; print "$result\n"; } if (keys %ChannelNameChange) { if($Detail >= 10) { print "\n"; foreach my $Channel (sort keys %ChannelNameChange) { print "Name of channel $Channel changed from ", $ChannelNameChange{$Channel}, "\n"; } } elsif ($Detail >= 5) { my $number = keys %ChannelNameChange; print "\n$number channel name changes\n"; } } if (keys %TimerSet) { if($Detail >= 15) { print "\n"; foreach my $Timer (sort keys %TimerSet) { print "Timer set to event $Timer\n"; } } elsif ($Detail >= 10) { my $number = keys %TimerSet; print "\n$number timers set\n"; } } if (keys %RecordingDeleted) { if($Detail >= 15) { print "\n"; foreach my $Recording (sort keys %RecordingDeleted) { print "DEleted recording $Recording\n"; } } elsif ($Detail >= 10) { my $number = keys %RecordingDeleted; print "\n$number recordings deleted\n"; } } if (($#OtherList >= 0) and (not $IgnoreUnmatched)) { print "\n**Unmatched Entries**\n"; print @OtherList; } exit(0); # vi: shiftwidth=3 tabstop=3 syntax=perl et logwatch-7.12/scripts/services/snort0000664000211400021140000001354614743365005020067 0ustar logwatchlogwatch#!/usr/bin/perl ######################################################## # Please file all bug reports, patches, and feature # requests under: # https://sourceforge.net/p/logwatch/_list/tickets # Help requests and discusion can be filed under: # https://sourceforge.net/p/logwatch/discussion/ ######################################################## ########################################################################## # # Logwatch service for snort log # # Processes all messages and summarizes them # Each message is given with a timestamp and RMS # ######################################################## # (C) 2023 by MigOps Inc - https://www.migops.com/ # written by Gilles Darold. # ######################################################## ## Covered under the included MIT/X-Consortium License: ## http://www.opensource.org/licenses/mit-license.php ## All modifications and contributions by other persons to ## this script are assumed to have been donated to the ## Logwatch project and thus assume the above copyright ## and licensing terms. If you want to make contributions ## under your own copyright or a different license this ## must be explicitly stated in the contribution and the ## Logwatch project reserves the right to not accept such ## contributions. If you have made significant ## contributions to this script and want to claim ## copyright please contact logwatch-devel@lists.sourceforge.net. ######################################################## use strict; use Logwatch ':dates'; use Time::Local; use POSIX qw(strftime); # Allow timestamp from two different logfile format: syslog and stderr my $date_format1 = '%m/%d-%H:%M:%S'; my $filter1 = TimeFilter($date_format1); # Allow summarization of WARNING and HINT too if wanted my $detail = exists $ENV{'LOGWATCH_DETAIL_LEVEL'} ? $ENV{'LOGWATCH_DETAIL_LEVEL'} : 0; # Used to replace the month trigram into the syslog timestamp my %month2num = ( Jan => 0, Feb => 1, Mar => 2, Apr => 3, May => 4, Jun => 5, Jul => 6, Aug => 7, Sep => 8, Oct => 9, Nov => 10, Dec => 11 ); # Array of the relevant lines in the log file. # First element: type of event # Second element: matching regexp ($1 should contain the message) # Third element: anonymous hash ref (stores message counts) my @message_categories = ( ['Priority 5', qr/\[\*\*\] \[\d+:\d+:\d+\] (.*?) \[\*\*\](?: \[(Classification: [^\]]+)\])? \[Priority: 5\] (?:\{([^\}]+)\})?/o, {}], ['Priority 4', qr/\[\*\*\] \[\d+:\d+:\d+\] (.*?) \[\*\*\](?: \[(Classification: [^\]]+)\])? \[Priority: 4\] (?:\{([^\}]+)\})?/o, {}], ['Priority 3', qr/\[\*\*\] \[\d+:\d+:\d+\] (.*?) \[\*\*\](?: \[(Classification: [^\]]+)\])? \[Priority: 3\] (?:\{([^\}]+)\})?/o, {}], ); if ($detail) { # Add more log information push(@message_categories, ['Priority 2', qr/\[\*\*\] \[\d+:\d+:\d+\] (.*?) \[\*\*\](?: \[(Classification: [^\]]+)\])? \[Priority: 2\] (?:\{([^\}]+)\})?/o, {}], ); if ($detail > 5) { push(@message_categories, ['Priority 1', qr/\[\*\*\] \[\d+:\d+:\d+\] (.*?) \[\*\*\](?: \[(Classification: [^\]]+)\])? \[Priority: 1\] (?:\{([^\}]+)\})?/o, {}], ); } } # Set the current year as syslog don't have this information. my $cur_year = (localtime(time))[5]; # Parse messages from stdin while (my $line = <>) { # skipping messages that are not within the requested range next unless $line =~ /^($filter1)/o; my $datetime = $1; my $time = ''; # Date/time format differ following the log_destination (stderr or syslog) if ($datetime =~ /(\d{2})\/(\d{2})-(\d+):(\d+):(\d+)/) { $time = timelocal($5, $4, $3, $2, $1-1, $cur_year); } foreach my $cur_cat (@message_categories) { if ($line =~ /$cur_cat->[1]/) { my $msgs = $cur_cat->[2]; my $rule = $1; my $class = $2; my $priority = $3; my $key = "$rule" || $priority; $key .= ", $priority" if ($priority && $rule); $msgs->{$key} = { count => '0', first_occurrence => $time, sum => 0, sqrsum => 0 } unless exists $msgs->{$key}; $msgs->{$key}->{'count'}++; # summing up timestamps and squares of timestamps # in order to calculate the rms # using first occurrence of message as offset in calculation to # prevent an integer overflow $msgs->{$key}->{'sum'} += $time - $msgs->{$key}->{'first_occurrence'}; $msgs->{$key}->{'sqrsum'} += ($time - $msgs->{$key}->{'first_occurrence'}) ** 2; last; } } } # generating summary foreach my $cur_cat (@message_categories) { # skipping non-requested message types next unless keys %{$cur_cat->[2]}; my ($name, undef, $msgs) = @{$cur_cat}; print $name, ":\n"; print '-' x (length($name)+1), "\n"; my $last_count = 0; # sorting messages by count my @sorted_msgs = sort { $msgs->{$b}->{'count'} <=> $msgs->{$a}->{'count'} } keys %{$msgs}; foreach my $msg (@sorted_msgs) { # grouping messages by number of occurrence print "\n", $msgs->{$msg}->{'count'}, " times:\n" unless $last_count == $msgs->{$msg}->{'count'}; my $rms = 0; # printing timestamp print '['; if($msgs->{$msg}->{'count'} > 1) { # calculating rms $rms = int(sqrt( ($msgs->{$msg}->{'count'} * $msgs->{$msg}->{'sqrsum'} - $msgs->{$msg}->{'sum'}) / ($msgs->{$msg}->{'count'} * ($msgs->{$msg}->{'count'} - 1)))); print strftime($date_format1, localtime($msgs->{$msg}->{'first_occurrence'}+int($rms/2))); print ' +/-'; # printing rms if($rms > 86400) { print int($rms/86400) , ' day(s)'; } elsif($rms > 3600) { print int($rms/3600) , ' hour(s)'; } elsif($rms > 60) { print int($rms/60) , ' minute(s)'; } else { print $rms, ' seconds'; } } else { # we have got this message a single time print strftime($date_format1, localtime($msgs->{$msg}->{'first_occurrence'})); } print '] ', $msg, "\n"; $last_count = $msgs->{$msg}->{'count'}; } print "\n"; } logwatch-7.12/scripts/services/lvm0000664000211400021140000001416614743365004017516 0ustar logwatchlogwatch ######################################################## # Please file all bug reports, patches, and feature # requests under: # https://sourceforge.net/p/logwatch/_list/tickets # Help requests and discusion can be filed under: # https://sourceforge.net/p/logwatch/discussion/ ######################################################## ######################################################## ## Copyright (c) 2014-2019 Orion Poplawski ## Covered under the included MIT/X-Consortium License: ## http://www.opensource.org/licenses/mit-license.php ## All modifications and contributions by other persons to ## this script are assumed to have been donated to the ## Logwatch project and thus assume the above copyright ## and licensing terms. If you want to make contributions ## under your own copyright or a different license this ## must be explicitly stated in the contribution an the ## Logwatch project reserves the right to not accept such ## contributions. If you have made significant ## contributions to this script and want to claim ## copyright please contact logwatch-devel@lists.sourceforge.net. ######################################################### use strict; use warnings; my $Detail = $ENV{'LOGWATCH_DETAIL_LEVEL'} || 0; my $PoolThreshold = $ENV{'pool_threshold'} || 0; my $PoolMetadataThreshold = $ENV{'pool_metadata_threshold'} || 0; my %Active; my %PoolUsed; my %PoolMetadataUsed; my $SnapshotThreshold = $ENV{'snapshot_threshold'} || 0; my %SnapshotUsed; my %MonitoringOn; my %MonitoringOff; my %MonitoringSnapshot; my %MonitoringSnapshotOff; my %Resize; my %OtherList; while (defined(my $ThisLine = )) { chomp($ThisLine); # Seeing leading space on Fedora 26 $ThisLine =~ s/^ *//; if ($ThisLine =~ /^(pvscan\[\d+\] )?PV .* online(?:|, VG .* is complete)\.$/ or $ThisLine =~ /(pvscan\[\d+\] )?activating all complete VGs for init/ or $ThisLine =~ /(pvscan\[\d+\] )?PVID .* read from .* last written to/ or $ThisLine =~ /(pvscan\[\d+\] )?VG .* not using quick activation/ or $ThisLine =~ /(pvscan\[\d+\] )?VG .* run autoactivation/ # This happens often at startup or $ThisLine =~ /WARNING: lvmetad is being updated, retrying/ # This happens on shutdown or $ThisLine =~ /dmeventd detected break while being idle for 0 second\(s\), exiting/ # This happens when dmeventd autostarted or $ThisLine =~ /dmeventd ready for processing\.$/ or $ThisLine =~ /dmeventd shutting down\.$/ or $ThisLine =~ /dmeventd was idle for .*, exiting\.$/ # Misc cleanups or $ThisLine =~ /Logical volume .* successfully resized/ ) { # Ignore } elsif ($ThisLine =~ /^(?:WARNING: )?Thin (\S+) is now (\d+(\.\d+)?)% full/) { $PoolUsed{$1} = $2 if $2 >= $PoolThreshold; } elsif ($ThisLine =~ /^(?:WARNING: )?Thin metadata (\S+) is now (\d+(\.\d+)?)% full/) { $PoolMetadataUsed{$1} = $2 if $2 >= $PoolMetadataThreshold; } elsif ($ThisLine =~ /^Monitoring thin pool (\S+)\./) { $MonitoringOn{$1}++; } elsif ($ThisLine =~ /^Monitoring snapshot (\S+)\./) { $MonitoringSnapshot{$1}++; } elsif ($ThisLine =~ /^No longer monitoring thin pool (\S+)\./) { $MonitoringOff{$1}++; } elsif ($ThisLine =~ /^No longer monitoring snapshot (\S+)\./) { $MonitoringSnapshotOff{$1}++; } elsif ($ThisLine =~ /^(?:WARNING: )?Snapshot (\S+) is now (\d+(\.\d+)?)% full/) { $SnapshotUsed{$1} = $2 if $2 >= $SnapshotThreshold; } elsif ($ThisLine =~ /^(\d+) logical volume\(s\) in volume group "(\S+)" monitored/) { $MonitoringOn{$2}++; } elsif ($ThisLine =~ /^(\d+) logical volume\(s\) in volume group "(\S+)" unmonitored/) { $MonitoringOff{$2}++; } elsif ($ThisLine =~ /^(\d+) logical volume\(s\) in volume group "(\S+)" now active/) { $Active{$2}=$1; } elsif ($ThisLine =~ /^Size of logical volume (\S+) changed from (.*) to (.*)\.$/) { $Resize{$1}="$3" } else { $OtherList{$ThisLine}++; } } if (keys %PoolUsed) { print "Thin Pool Usage:\n"; foreach my $Pool (sort {$a cmp $b} keys %PoolUsed) { print " $Pool: $PoolUsed{$Pool}% full\n"; } print "\n"; } if (keys %PoolMetadataUsed) { print "Thin Pool Metadata Usage:\n"; foreach my $Pool (sort {$a cmp $b} keys %PoolMetadataUsed) { print " $Pool: $PoolMetadataUsed{$Pool}% full\n"; } print "\n"; } if (keys %SnapshotUsed) { print "Snapshot Usage:\n"; foreach my $Snapshot (sort {$a cmp $b} keys %SnapshotUsed) { print " $Snapshot: $SnapshotUsed{$Snapshot}% full\n"; } print "\n"; } if (keys %Resize) { print "Resize snapshot:\n"; foreach my $Snapshot (sort {$a cmp $b} keys %Resize) { print " $Snapshot: $Resize{$Snapshot}\n"; } print "\n"; } if (keys %Active and $Detail) { print "LVM active:\n"; foreach my $VG (sort {$a cmp $b} keys %MonitoringOn) { print " $VG: $Active{$VG} logical volume(s)\n"; } print "\n"; } if (keys %MonitoringOn and $Detail) { print "Monitoring started for:\n"; foreach my $Pool (sort {$a cmp $b} keys %MonitoringOn) { print " $Pool: $MonitoringOn{$Pool} Time(s)\n"; } print "\n"; } if (keys %MonitoringOff and $Detail) { print "Monitoring stopped for:\n"; foreach my $Pool (sort {$a cmp $b} keys %MonitoringOff) { print " $Pool: $MonitoringOff{$Pool} Time(s)\n"; } print "\n"; } if (keys %MonitoringSnapshot and $Detail) { print "Monitoring snapshot:\n"; foreach my $Snapshot (sort {$a cmp $b} keys %MonitoringSnapshot) { print " $Snapshot: $MonitoringSnapshot{$Snapshot} Time(s)\n"; } print "\n"; } if (keys %MonitoringSnapshotOff and $Detail) { print "Monitoring stopped for snapshot:\n"; foreach my $Snapshot (sort {$a cmp $b} keys %MonitoringSnapshotOff) { print " $Snapshot: $MonitoringSnapshotOff{$Snapshot} Time(s)\n"; } print "\n"; } if (keys %OtherList) { print "\n**Unmatched Entries**\n"; foreach my $line (sort {$a cmp $b} keys %OtherList) { print " $line: $OtherList{$line} Time(s)\n"; } } exit(0); # vi: shiftwidth=3 tabstop=3 syntax=perl et # Local Variables: # mode: perl # perl-indent-level: 3 # indent-tabs-mode: nil # End: logwatch-7.12/scripts/services/tivoli-smc0000664000211400021140000001102314743365006020775 0ustar logwatchlogwatch ######################################################## # Please file all bug reports, patches, and feature # requests under: # https://sourceforge.net/p/logwatch/_list/tickets # Help requests and discusion can be filed under: # https://sourceforge.net/p/logwatch/discussion/ ######################################################## ######################################################## ## Copyright (c) 2013 Stefan Jakobs ## Covered under the included MIT/X-Consortium License: ## http://www.opensource.org/licenses/mit-license.php ## All modifications and contributions by other persons to ## this script are assumed to have been donated to the ## Logwatch project and thus assume the above copyright ## and licensing terms. If you want to make contributions ## under your own copyright or a different license this ## must be explicitly stated in the contribution an the ## Logwatch project reserves the right to not accept such ## contributions. If you have made significant ## contributions to this script and want to claim ## copyright please contact logwatch-devel@lists.sourceforge.net. ######################################################### use strict; my $Detail = $ENV{'LOGWATCH_DETAIL_LEVEL'} || 0; my $Version = "20130212"; my ($ThisLine, %OtherList); my (%IncBackup, %IncBackupFailure); my (%Object, %ObjectSend, %ObjectName); my (%Error, %NoConnection, %File); my $Interrupted; ### functions ### sub print_2xhash($$) { my %hash = %{$_[0]}; my $desc = $_[1]; print "$desc\n"; foreach my $item (keys %hash) { printf(" %-44s\n", $item); foreach my $item2 (keys %{$hash{$item}}) { printf(" %-42s %5d time(s)\n", $item2, $hash{$item}{$item2}); } } print "\n"; } ### main ### while(defined ($ThisLine = )) { chomp $ThisLine; # remove when filter script is done #$ThisLine =~ s/^\d{4}-\d\d-\d\d \d\d:\d\d:\d\d //; if ( ($ThisLine =~ /^\w+ Could not establish a session with a TSM server or client agent/ ) || ($ThisLine =~ /^\w+ Communication with the TSM server is lost/ ) ) { # ignore } elsif ($ThisLine =~ /(\w+) Incremental backup of '([^']+)' finished with (\d+) failure/) { $IncBackup{"$2"}++; $IncBackupFailure{"$2"}+=$3; } elsif ($ThisLine =~ /(\w+) Sending of object '([^']+)' (.+)/) { $ObjectSend{"$3"}{"$2"}++; } elsif ($ThisLine =~ /(\w+) Object name '([^']+)' (.+)/) { $ObjectName{"$3"}{"$2"}++; } elsif ($ThisLine =~ /(\w+) Object '([^']+)' (.+)/) { $Object{"$3"}{"$2"}++; } elsif ($ThisLine =~ /cuGetBackQryResp: (.*):0,(.*)$/) { $Object{$1}{$2}++; } elsif ($ThisLine =~ /(\w+) An interrupt has occurred/) { $Interrupted++; } elsif ($ThisLine =~ /(\w+) (.+)\.\s+The TSM return code is ([-0-9]+)/) { $Error{$3}{"$2"}++; } elsif ($ThisLine =~ /(\w+) (Session rejected): (.+)/) { $Error{"$2"}{$3}++; } elsif ($ThisLine =~ /(\w+) (Error processing) '([^']+)': (.+)/) { $Error{"$2"}{$4}++; } elsif ($ThisLine =~ /(\w+) Could not establish a TCP\/IP connection with address '([^']+)'\. The TCP\/IP error is '([^']+)'/) { $NoConnection{"$2"}{$3}++; } elsif ($ThisLine =~ /(\w+) (An invalid TCP\/IP address was specified)/) { $Error{"$2"}{$1}++; } elsif ($ThisLine =~ /File '(?:[^']+)' (.*)/) { $File{"$1"}++; } else { chomp($ThisLine); $OtherList{$ThisLine}++; } } # end of while ### generate output ### if (keys %Error) { print_2xhash(\%Error, "Errors:"); } if ($Interrupted) { printf("%-46s %5d time(s)\n\n", "Interrupted", $Interrupted); } if (keys %File) { print "File:\n"; foreach my $msg (keys %File) { printf(" %-44s %5d time(s)\n", $msg, $File{$msg}); } print "\n"; } if (keys %IncBackup) { print "Incremental Backups finished:\n"; foreach my $dir (sort {$IncBackup{$b} <=> $IncBackup{$a}} keys %IncBackup) { printf(" %-44s %5d time(s) with %3d failure(s)\n", $dir, $IncBackup{$dir}, $IncBackupFailure{$dir}); } print "\n"; } if (keys %ObjectSend) { print_2xhash(\%ObjectSend, "Sending of objects:"); } if (keys %ObjectName) { print_2xhash(\%ObjectName, "Object Names:"); } if (keys %Object) { print_2xhash(\%Object, "Object:"); } if (keys %NoConnection) { print_2xhash(\%NoConnection, "NoConnections:"); } if (keys %OtherList) { print "\n**** Unmatched entries ****\n"; foreach my $Error (keys %OtherList) { print " $Error : $OtherList{$Error} Time(s)\n"; } } ### return without a failure ### exit(0); # vi: shiftwidth=3 tabstop=3 syntax=perl et logwatch-7.12/scripts/services/syslogd0000664000211400021140000000441014274101044020362 0ustar logwatchlogwatch ######################################################## # Please file all bug reports, patches, and feature # requests under: # https://sourceforge.net/p/logwatch/_list/tickets # Help requests and discusion can be filed under: # https://sourceforge.net/p/logwatch/discussion/ ######################################################## ####################################################### ## Copyright (c) 2008 Kirk Bauer ## Covered under the included MIT/X-Consortium License: ## http://www.opensource.org/licenses/mit-license.php ## All modifications and contributions by other persons to ## this script are assumed to have been donated to the ## Logwatch project and thus assume the above copyright ## and licensing terms. If you want to make contributions ## under your own copyright or a different license this ## must be explicitly stated in the contribution an the ## Logwatch project reserves the right to not accept such ## contributions. If you have made significant ## contributions to this script and want to claim ## copyright please contact logwatch-devel@lists.sourceforge.net. ######################################################### use strict; my $Detail = $ENV{'LOGWATCH_DETAIL_LEVEL'} || 0; #Init Counters my $Kills= my $Starts= my $Errors= 0; #Init Hashes my ( %OtherList, ); while (defined(my $ThisLine = )) { chomp($ThisLine); if ( $ThisLine =~ /^(exiting|going down) on signal 15$/ ) { #$Kills++; } elsif ($ThisLine =~ /^syslogd .* restart\.$/) { $Starts++; } elsif ($ThisLine =~ /^restart( \(remote reception\))?\.?$/) { $Starts++; } elsif ($ThisLine =~ /^Cannot glue message parts together$/) { $Errors++; } else { # Report any unmatched entries... $OtherList{$ThisLine}++; } } if ($Errors) { print "\nCould not glue message parts together " . $Errors . " Time(s)\n"; } if ($Starts and ($Detail >=10) ) { print "\nSyslogd started " . $Starts . " Time(s)\n"; } if (keys %OtherList) { print "\n**** Unmatched entries ****\n"; foreach my $Error (keys %OtherList) { print " $Error : $OtherList{$Error} Times\n"; } } exit(0); # vi: shiftwidth=3 tabstop=3 syntax=perl et # Local Variables: # mode: perl # perl-indent-level: 3 # indent-tabs-mode: nil # End: logwatch-7.12/scripts/services/pam_pwdb0000664000211400021140000002075614274101041020477 0ustar logwatchlogwatch ######################################################## # Please file all bug reports, patches, and feature # requests under: # https://sourceforge.net/p/logwatch/_list/tickets # Help requests and discusion can be filed under: # https://sourceforge.net/p/logwatch/discussion/ ######################################################## ##################################################### ## Copyright (c) 2008 Kirk Bauer ## Covered under the included MIT/X-Consortium License: ## http://www.opensource.org/licenses/mit-license.php ## All modifications and contributions by other persons to ## this script are assumed to have been donated to the ## Logwatch project and thus assume the above copyright ## and licensing terms. If you want to make contributions ## under your own copyright or a different license this ## must be explicitly stated in the contribution an the ## Logwatch project reserves the right to not accept such ## contributions. If you have made significant ## contributions to this script and want to claim ## copyright please contact logwatch-devel@lists.sourceforge.net. ######################################################### # NOTE: This script is for older (6.X era) Red Hat boxes use strict; my $Detail = $ENV{'LOGWATCH_DETAIL_LEVEL'} || 0; #Init String Containers my ( $EndName, $From, $Num, $Orig, $RemoteHost, $Service, $ServiceName, $StartName, $StartUID, $Temp, $ThisKey, $User ); #Init Arrays my (@BadName, @Expired, @PWChanges) = (); #Init Hashes my ( %AuthFailures, %CouldNotIDPW, %FailedLogins, %LocalLogins, %OpenedSessions, %OtherList, %RemoteLogins, %RootLogins, %SUList ); while (defined(my $ThisLine = )) { if ( ( $ThisLine =~ /(.*) session closed for user .*$/ ) or ( $ThisLine =~ /^Logout user .* host .*$/ ) or ( $ThisLine =~ /^log: Password authentication/ ) or # apparently SSHD messages ( $ThisLine =~ /^log: Closing connection/ ) or # apparently SSHD messages ( $ThisLine =~ /^check pass; user unknown/ ) or ( $ThisLine =~ /^User account has expired/ ) or # This one is caught below (2-line message) ( $ThisLine =~ /^get passwd; pwdb: structure is no longer valid$/) or ( $ThisLine =~ /^fatal: Read error from remote host: Connection reset by peer$/) or ( $ThisLine =~ /^new password not acceptable$/ ) or ( $ThisLine =~ /^FTP session closed$/) or ( $ThisLine =~ /^FTP LOGIN REFUSED/) or ( $ThisLine =~ /^FAILED LOGIN SESSION FROM \S+ FOR , Error in service module/) or ( $ThisLine =~ /^FTP LOGIN FROM/ ) # I will let ftpd handle FTP messages.... ) { # We don't care about these } elsif ( $ThisLine =~ /password for \(.*\) changed by \(.*\)$/ ) { chomp($ThisLine); push @PWChanges, $ThisLine; } elsif ( ($RemoteHost,$User) = ( $ThisLine =~ /^failed login from ([^ ]+) \[.*\], ([^ ]+)$/) or ($RemoteHost,$User) = ( $ThisLine =~ /^Login failure user=(\S+) host=([^ ]+)$/) ) { chomp ($User); push @{$FailedLogins{$RemoteHost}}, $User; } elsif ( $ThisLine =~ s/auth could not identify password for \[([^ ]+)\]$/$1/ ) { chomp ($ThisLine); $CouldNotIDPW{$ThisLine}++; } elsif ( $ThisLine =~ s/^expiry check failed for \'([^ ]+)\'/$1/ ) { # user account expired? chomp($ThisLine); push @Expired, $ThisLine; } elsif ( $ThisLine =~ s/bad username \[(.*)\]$/$1/ ) { chomp($ThisLine); push @BadName, $ThisLine; } elsif ( ($StartName,$StartUID,$EndName,$ServiceName) = ( $ThisLine =~ m/authentication failure.*; ([^ ]*)\(uid=(\d+)\) -> ([^ ]+) for ([^ ]+) service$/ ) ) { $StartName = " " if (!$StartName); $ThisKey = $StartName . "(uid=" . $StartUID . ") -> " . $EndName; $AuthFailures{$ThisKey}{$ServiceName}++; } elsif ( ($Num,$StartName,$StartUID,$EndName,$ServiceName) = ( $ThisLine =~ m/^(\d+) authentication failure.*; ([^ ]*)\(uid=(\d+)\) -> ([^ ]+) for ([^ ]+) service$/ ) ) { $StartName = " " if (!$StartName); $ThisKey = $StartName . "(uid=" . $StartUID . ") -> " . $EndName; $AuthFailures{$ThisKey}{$ServiceName}+=$Num; } elsif ( ($ThisKey,$ServiceName) = ( $ThisLine =~ /([^ ]+) authentication failed for ([^ ]+)$/ ) ) { chomp($ThisKey); chomp($ServiceName); $AuthFailures{$ThisKey}{$ServiceName}++; } elsif ( ($RemoteHost, $User) = ( $ThisLine =~ m/^FAILED LOGIN .* FROM ([^ ]+) FOR (.+), .*$/ ) ) { push @{$FailedLogins{$RemoteHost}}, $User; } elsif ( $ThisLine =~ s/^ROOT LOGIN ON ([^ ]+)/$1/ ) { chomp ($ThisLine); $RootLogins{$ThisLine}++; } elsif ( ($User,$From) = ( $ThisLine =~ /^LOGIN ON [^ ]+ BY ([^ ]+) FROM ([^ ]+)$/ ) or ($User,$From) = ( $ThisLine =~ /^Login user=([^ ]+) host=([^ ]+)$/ ) ) { chomp ($From); ${$RemoteLogins{$User}}{$From}++; } elsif ( $ThisLine =~ s/^LOGIN ON [^ ]+ BY ([^ ]+$)/$1/ ) { chomp ($ThisLine); $LocalLogins{$ThisLine}++; } elsif ( ($ServiceName,$StartName,$StartUID,$EndName) = ( $ThisLine =~ m/([^ ]+)\[[0-9]+\]:\s+authentication\s+failure;\s*logname=([^ ]+)\s+uid=([^ ]+).*user=([^ ]+)/ ) ) { $StartName = " " if (!$StartName); $ThisKey = $StartName . "(uid=" . $StartUID . ") -> " . $EndName; $AuthFailures{$ThisKey}{$ServiceName}++; } elsif ( ($Service, $User, $Orig) = ( $ThisLine =~ /^\((.*)\) session opened for user ([^ ]+) by (.*\(uid=.*\))/ ) ) { if (( $Service eq "su" ) and ($Orig =~ /[^ ]+\(uid=.*\)$/)) { $Temp = " " . $Orig . " -> " . $User; $SUList{$Temp}++; } else { ${$OpenedSessions{$Service}}{$User}++; } } else { # Report any unmatched entries... chomp($ThisLine); $OtherList{$ThisLine}++; } } if (keys %SUList) { print "\nSU Sessions:\n"; foreach my $SU (keys %SUList) { print " " . $SU . " - " . $SUList{$SU} . " Time(s)\n"; } } if (($Detail >= 10) and (keys %CouldNotIDPW)) { print "\nCould not identify password for:\n"; foreach my $User (keys %CouldNotIDPW) { print " " . $User . " - " . $CouldNotIDPW{$User} . " Time(s)\n"; } } if (@PWChanges) { print "\nPassword Changes:\n"; foreach my $Change (@PWChanges) { print " " . $Change . "\n"; } } if (($Detail >= 5) and (@BadName)) { print "\nBad Usernames Received:\n"; foreach my $User (@BadName) { print " " . $User . "\n"; } } if (@Expired) { print "\nExpired User Accounts:\n"; foreach my $User (@Expired) { print " " . $User . "\n"; } } if (keys %OpenedSessions) { print "\nOpened Sessions:\n"; foreach my $Service (keys %OpenedSessions) { print " Service: " . $Service . "\n"; foreach my $User (keys %{$OpenedSessions{$Service}}) { print " User " . $User . " - " . ${$OpenedSessions{$Service}}{$User} . " Time(s)\n"; } } } if (keys %RemoteLogins) { print "\nRemote Logins:\n"; foreach my $User (keys %RemoteLogins) { print " User " . $User . ":\n"; foreach my $Remote (keys %{$RemoteLogins{$User}} ) { print " Remote Host " . $Remote . " - " . ${$RemoteLogins{$User}}{$Remote} . " Time(s)\n"; } } } if (keys %LocalLogins) { print "\nLocal Logins:\n"; foreach my $User (keys %LocalLogins) { print " " . $User . " - " . $LocalLogins{$User} . " Time(s)\n"; } } if (keys %RootLogins) { print "\nRoot Logins:\n"; foreach my $tty (keys %RootLogins) { print " " . $tty . ": " . $RootLogins{$tty} . " time(s)\n"; } } if (($Detail >= 5) and (keys %AuthFailures)) { print "\nAuthentication Failures:\n"; foreach my $Users (keys %AuthFailures) { print " " . $Users . "\n"; foreach my $Service (keys %{$AuthFailures{$Users}}) { print " Service: " . $Service . ": " . ${$AuthFailures{$Users}}{$Service} . " time(s)\n"; } } } if (($Detail >= 5) and (keys %FailedLogins)) { print "\nLogin Failures:\n"; foreach my $RemoteHost (keys %FailedLogins) { print " " . $RemoteHost . ": "; foreach my $User ( @{$FailedLogins{$RemoteHost}} ) { print $User . ", "; } print "\n"; } } if (keys %OtherList) { print "\n**Unmatched Entries**\n"; foreach my $line (sort {$a cmp $b} keys %OtherList) { print "$line: $OtherList{$line} Time(s)\n"; } } exit(0); # vi: shiftwidth=3 tabstop=3 syntax=perl et # Local Variables: # mode: perl # perl-indent-level: 3 # indent-tabs-mode: nil # End: logwatch-7.12/scripts/services/qmail-pop3ds0000664000211400021140000001011614743365005021221 0ustar logwatchlogwatch ######################################################## # Please file all bug reports, patches, and feature # requests under: # https://sourceforge.net/p/logwatch/_list/tickets # Help requests and discusion can be filed under: # https://sourceforge.net/p/logwatch/discussion/ ######################################################## ####################################################### ## Copyright (c) 2008 Bob Hutchinson ## Covered under the included MIT/X-Consortium License: ## http://www.opensource.org/licenses/mit-license.php ## All modifications and contributions by other persons to ## this script are assumed to have been donated to the ## Logwatch project and thus assume the above copyright ## and licensing terms. If you want to make contributions ## under your own copyright or a different license this ## must be explicitly stated in the contribution an the ## Logwatch project reserves the right to not accept such ## contributions. If you have made significant ## contributions to this script and want to claim ## copyright please contact logwatch-devel@lists.sourceforge.net. ######################################################### use strict; my $Detail = $ENV{'LOGWATCH_DETAIL_LEVEL'}; my $QmailDetail = $ENV{'qmail_high_detail'}; my $QmailThreshold = $ENV{'threshold'}; my $ToThreshold = $ENV{'to_threshold'}; my $FromThreshold = $ENV{'from_threshold'}; #Init String Containers my ( $IgnoreUnmatched, $LocalServer, $RemoteServer, $TotalFrom, $TotalTo, $Warning, $pid1, $pid2, $threshold_reached, ); #Init Hashes my ( %From, %To, %Warnings, ); #Init Arrays my @OtherList = (); while (defined(my $ThisLine = )) { if ( ( $ThisLine =~ /status: / ) or ( $ThisLine =~ /end (\d+) status \d+/ ) or ( $ThisLine =~ / LOG5/ ) or ( $ThisLine =~ /qmail-popup/ ) ) { # We don't care about these } elsif ( ($pid1,$RemoteServer) = ( $ThisLine =~ /pid (\d+) from (.*)/ ) ) { $From{$RemoteServer}++; $TotalFrom++; } elsif ( ($pid2,$LocalServer) = ( $ThisLine =~ /ok (\d+) \d+:(.*):995\s+.*/ ) ) { $To{$LocalServer}++; $TotalTo++; } elsif ( ($Warning) = ( $ThisLine =~ /warning: (.*)/i ) ) { $Warnings{$Warning}++; } else { # Report any unmatched entries... push @OtherList,$ThisLine; } } if ($QmailDetail >= 1) { if ($QmailThreshold > 0) { if (($FromThreshold < 0) or ($FromThreshold eq '')) { $FromThreshold = $QmailThreshold; } if (($ToThreshold < 0) or ($ToThreshold eq '')) { $ToThreshold = $QmailThreshold; } } if (($FromThreshold < 0) or ($FromThreshold eq '')) { $FromThreshold = 0; } if (($ToThreshold < 0) or ($ToThreshold eq '')) { $ToThreshold = 0; } if ( (keys %From) ) { print "\nConnections from (Threshold of " . $FromThreshold . "):\n"; $threshold_reached=0; foreach my $Line (sort {$From{$b} <=> $From{$a}} keys %From) { if ($From{$Line} >= $FromThreshold) { $threshold_reached=1; print "\t" . $Line . " - ". $From{$Line} . " Time(s)\n"; } } if ($threshold_reached < 1) { print "\t" . "None found above the threshold\n"; } } if ( (keys %To) ) { print "\nConnections to (Threshold of " . $ToThreshold . "):\n"; $threshold_reached=0; foreach my $Line (sort {$To{$b} <=> $To{$a}} keys %To) { if ($To{$Line} >= $ToThreshold) { $threshold_reached=1; print "\t" . $Line . " - ". $To{$Line} . " Time(s)\n"; } } if ($threshold_reached < 1) { print "\t" . "None found above the threshold\n"; } } } if ($TotalFrom or $TotalTo) { print "\nTotals:\n"; print "\tRemote connections $TotalFrom\n"; print "\tLocal connections $TotalTo\n"; } if ( (keys %Warnings) ) { print "\nWarnings:\n"; foreach my $Line (sort {$Warnings{$b} <=> $Warnings{$a}} keys %Warnings) { print "\t" . $Line . " - ". $Warnings{$Line} . " Time(s)\n"; } } if (($#OtherList >= 0) and (not $IgnoreUnmatched)){ print "\n**Unmatched Entries**\n"; print @OtherList; } exit(0); # vi: shiftwidth=3 tabstop=3 syntax=perl et # Local Variables: # mode: perl # perl-indent-level: 3 # indent-tabs-mode: nil # End: logwatch-7.12/scripts/services/cron0000664000211400021140000003440014743365003017651 0ustar logwatchlogwatch ######################################################## # Please file all bug reports, patches, and feature # requests under: # https://sourceforge.net/p/logwatch/_list/tickets # Help requests and discusion can be filed under: # https://sourceforge.net/p/logwatch/discussion/ ######################################################## ######################################################## ## Copyright (c) 2008-2016 Kirk Bauer ## Covered under the included MIT/X-Consortium License: ## http://www.opensource.org/licenses/mit-license.php ## All modifications and contributions by other persons to ## this script are assumed to have been donated to the ## Logwatch project and thus assume the above copyright ## and licensing terms. If you want to make contributions ## under your own copyright or a different license this ## must be explicitly stated in the contribution an the ## Logwatch project reserves the right to not accept such ## contributions. If you have made significant ## contributions to this script and want to claim ## copyright please contact logwatch-devel@lists.sourceforge.net. ######################################################### use strict; my $Detail = $ENV{'LOGWATCH_DETAIL_LEVEL'} || 0; #Init Counters my $BFMFile= my $INCRONDSS= my $INCRONDStS= my $MailErrors= my $Ntpdate= my $Orphans= my $ntpdatemaxoffset= my $ntpdateminoffset= my $ntpdatenosync= my $Reloads= my $Shutdowns= my $Startups= my $CHUSERHErr= my $PAMAUTHErr= 0; #Init Reusable strings my $Error = ""; my $User = ""; my $FileName = ""; my $Cause = ""; my $Table = ""; #Init Array my @OtherList = (); my $Runs = (); #Init Hashes my ( %ExecutedCommand, %CrontabDeny, %InodeError, %Errors, %BFMFile, %WFO, %SELCONTErr, %UserReloads, %INCRONDSTCr, %INCRONDSTCh, %INCRONDSTDe, %INCRONDUTCr, %INCRONDUTCh, %INCRONDUTDe, %INCRONDErr, %CRONDErr, %CHDIRErr, ); while (defined(my $ThisLine = )) { chomp($ThisLine); if ( ($ThisLine =~ /Updated timestamp for job/) or ($ThisLine =~ /INFO \(pidfile fd = \d+\)/) or ($ThisLine =~ /rsyncd/) or ($ThisLine =~ /INFO \(Running \@(re)?boot jobs\)/) or ($ThisLine =~ /INFO \(Skipping \@(re)?boot jobs -- not system startup\)/) or ($ThisLine =~ /INFO \(not boot nor reboot\)/) or ($ThisLine =~ /INFO \(running with inotify support\)/) or ($ThisLine =~ /INFO \(\@reboot jobs will be run at computer's startup.\)/) or ($ThisLine =~ /INFO \(RANDOM_DELAY will be scaled with factor/) or ($ThisLine =~ /logfile turned over/) or ($ThisLine =~ /ready to process filesystem events/) or # newsyslog on OpenBSD ($ThisLine =~ /loading (system|user) tables/) or ($ThisLine =~ /loading table .*/) or ($ThisLine =~ /void Inotify::Remove\(InotifyWatch\*\): removing watch failed/) or ($ThisLine =~ /error: \(22\) Invalid argument/) or ($ThisLine =~ /pam_unix\(crond:session\): session (?:opened|closed) for user/) or # This is paired with PAM ERROR handled below ($ThisLine =~ /FAILED to authorize user with PAM/) or ($ThisLine =~ /PAM pam_end: NULL pam handle passed/) ) { # Ignore } elsif ( ($ThisLine =~ s/^([^ ]+) \([^ ]+\)\s+//) or ($ThisLine =~ s/^\S+\s+\S+\s+..:..:..\s+\S+\s+\S+\[(\d+)\]:\s+\((\S+)\)\s+//) ) { my $PID = $1; $User = $2; #Not happy with User being everywhere if ($ThisLine =~ s/^CMD \((.+)\)\s*$/$1/) { $Runs->{$User}->{$ThisLine}++; $ExecutedCommand{$PID} = {command=>$ThisLine, user=>$User}; } elsif ($ThisLine =~ /^CMDEND/) { # Ignore - already counted above next; } elsif ($ThisLine =~ s/^CMD FINISH \((.+)\)\s*$/$1/) { $Runs->{$User}->{$ThisLine}++; } elsif ($ThisLine =~ s/^(END|CMD START) \((.+)\)\s*$/$1/) { #Ignore for now, NetBSD users could get tricky with #How many commands started vs finished -mgt } elsif ($ThisLine =~ /ORPHAN \(no passwd entry\)/) { $Orphans++; } elsif ($ThisLine =~ s/^(BEGIN|END) EDIT \((.+)\)\s*$/$2/) { $Runs->{$ThisLine}->{'personal crontab edited'} += 0.5; } elsif ($ThisLine =~ s/^REPLACE \((.+)\)\s*$/$1/) { $Runs->{$ThisLine}->{'personal crontab replaced'}++; } elsif ($ThisLine =~ s/^LIST \((.+)\)\s*$/$1/) { $Runs->{$ThisLine}->{'personal crontab listed'}++; } elsif ($ThisLine =~ s/^DELETE \((.+)\)\s*$/$1/) { $Runs->{$User}->{'personal crontab deleted'}++; } elsif ($ThisLine =~ /^STARTUP \(.*\)\s*$/ ) { $Startups++; } elsif ($ThisLine =~ /^INFO \(Shutting down\)/ ) { $Shutdowns++; } elsif ( $ThisLine =~ /^RELOAD \(.+\)\s*$/ ) { $Runs->{$User}->{'personal crontab reloaded'}++; } elsif ( $ThisLine =~ /^MAIL \(mailed \d+ bytes of output but got status [^ ]+/) { $MailErrors++; } elsif ( $ThisLine =~ /^AUTH \(crontab command not allowed\)/) { $CrontabDeny{$User}++; } elsif ( ($Error) = $ThisLine =~ /^PAM ERROR \((.*)\)/) { $Errors{$User}{$Error}++; } elsif ( $ThisLine =~ /^WRONG INODE INFO \([^ ]+\)/) { $InodeError{$User}++; } elsif ( $ThisLine =~ /session opened/ || $ThisLine =~ /session closed/ ) { # ignore } elsif ( my ($Reason) = ($ThisLine =~ /^error \((.+)\)$/) ) { if ($Reason =~ /^grandchild #(\d+) failed with exit status (\d+)/ && \ $ExecutedCommand{$1}) { # $Reason = $ExecutedCommand{$1}{user}.": command failed with error (".$2."): ".$ExecutedCommand{$1}{command}; $Reason = "failed with error (".$2."): ".$ExecutedCommand{$1}{command}; } $Errors{$ExecutedCommand{$1}{user}}{$Reason}++; } elsif ( ($FileName) = ($ThisLine =~ /BAD FILE MODE \((.+)\)/) ) { $BFMFile{$FileName}++; } elsif ( ($FileName) = ($ThisLine =~ /WRONG FILE OWNER \((.+)\)/) ) { $WFO{$FileName}++; } elsif ($ThisLine =~ /NULL security context for user, but SELinux in permissive mode/ ) { $SELCONTErr{$ThisLine}++; } else { # Report any unmatched entries... push @OtherList, "$ThisLine\n"; } } elsif ( $ThisLine =~ /^RELOAD \(.+\)\s*$/ ) { $Reloads++; } elsif ( ($User) = ($ThisLine =~ /^(.*) \([^ ]+\) RELOAD \(.*\)$/ ) ) { $UserReloads{$User}++; } elsif ( $ThisLine =~ /.*?: Job (.*) started for user ([^ ]*)/) { $Runs->{$2}->{$1}++; } elsif ( ($ThisLine =~ /.*?: Job (.*) (completed|terminated)/) or ($ThisLine =~ /.*?: updating configuration from/) or ($ThisLine =~ /.*?: Exiting with code 0/) or ($ThisLine =~ /.*?: SIGTERM signal received/) ) { # Ignore } elsif ( ($User) = ($ThisLine =~ /.*?: editing ([^ ]*)'s fcrontab.*/)) { $Runs->{$User}->{'-- personal crontab edited'}++; } elsif ( ($User) = ($ThisLine =~ /.*?: listing ([^ ]*)'s fcrontab.*/)) { $Runs->{$User}->{'-- personal crontab listed'}++; } elsif ( ($User) = ($ThisLine =~ /.*?: adding (?:new )?file ([^ ]+)/)) { $Runs->{$User}->{'-- personal crontab updated'}++; $UserReloads{$User}++; } elsif ( $ThisLine =~ /.*?: fcron.* started/) { $Startups++; } elsif ( my ($offset) = ($ThisLine =~ /ntpdate\[\d+\]: adjust time server .* offset (.*) sec/)) { $Ntpdate++; if ( $ntpdateminoffset > $offset ) { $ntpdateminoffset = $offset; } if ( $ntpdatemaxoffset < $offset ) { $ntpdatemaxoffset = $offset; } } elsif ($ThisLine =~ /ntpdate\[\d+\]: no server suitable for synchronization found/) { $ntpdatenosync++; } elsif (($ThisLine =~ /incrond/) && ($ThisLine =~ /starting service/)) { $INCRONDSS++; } elsif (($ThisLine =~ /incrond/) && ($ThisLine =~ /stopping service/)) { $INCRONDStS++; } elsif (($ThisLine =~ /incrond/) && (($Table) = ($ThisLine =~ /system table (.*) created, loading/))) { $INCRONDSTCr{$Table}++; } elsif (($ThisLine =~ /incrond/) && (($User) = ($ThisLine =~ /table for user (.*) created, loading/))) { $INCRONDUTCr{$User}++; } elsif (($ThisLine =~ /incrond/) && (($Table) = ($ThisLine =~ /system table (.*) changed, reloading/))) { $INCRONDSTCh{$Table}++; } elsif (($ThisLine =~ /incrond/) && (($User) = ($ThisLine =~ /table for user (.*) changed, reloading/))) { $INCRONDUTCh{$User}++; } elsif (($ThisLine =~ /incrond/) && (($Table) = ($ThisLine =~ /system table (.*) destroyed, removing/))) { $INCRONDSTDe{$Table}++; } elsif (($ThisLine =~ /incrond/) && (($User) = ($ThisLine =~ /table for user (.*) destroyed, removing/))) { $INCRONDUTDe{$User}++; } elsif ( ($ThisLine =~ /incrond/) && ( (($Error) = ($ThisLine =~ /(cannot create watch for (system table|user) .*: \(2\) No such file or directory)/)) || (($Error) = ($ThisLine =~ /(access denied on (.*) - events will be discarded silently)/)) || (($Error) = ($ThisLine =~ /(unhandled exception occurred)/)) || (($Error) = ($ThisLine =~ /(cannot exec process.*)/)) ) ) { $INCRONDErr{$Error}++; } elsif ( ($ThisLine =~ /crond/) && (($Error) = ($ThisLine =~ /(failed to open PAM security session: (Permission denied|Module is unknown))/)) ) { $CRONDErr{$Error}++; } elsif (( ($Error) = ($ThisLine =~ /ERROR: (failed to change SELinux context)/)) or (($Error) = ($ThisLine =~ /ERROR:(Could not set exec context to .* for .*)/))) { $SELCONTErr{$Error}++; } elsif ($ThisLine =~ /FAILED to authorize user with PAM \(User not known to the underlying authentication module\)/) { $PAMAUTHErr++; } elsif ( ($FileName,$Cause) = ($ThisLine =~ /ERROR chdir failed \((.*)\): (.*)/) ) { $CHDIRErr{"$FileName,$Cause"}++; } elsif ($ThisLine =~ /ERROR \(failed to change user\)/) { $CHUSERHErr++; } else { # Report any unmatched entries... push @OtherList, "$ThisLine\n"; } } ####################################### if (%CrontabDeny) { print "Attempt to use crontab by unauthorized users:\n"; foreach my $User (sort {$a cmp $b} keys %CrontabDeny) { print " $User : $CrontabDeny{$User} Time(s)\n"; } } if (%InodeError) { print "\nInode errors in crontab files of users:\n"; foreach my $User (sort {$a cmp $b} keys %InodeError) { print " $User : $InodeError{$User} Time(s)\n"; } } if (keys %Errors) { print "Errors when running cron:\n"; foreach my $User (sort {$a cmp $b} keys %Errors) { print " User $User:\n"; foreach my $Reason (sort {$a cmp $b} keys %{$Errors{$User}}) { print " $Reason: $Errors{$User}{$Reason} Time(s)\n"; } } } if (%CRONDErr) { printf "\n crond daemon errors \n"; for my $key (keys %CRONDErr) { print " " . $key . ": " . $CRONDErr{$key} . " time(s)\n"; } } if (%INCRONDErr) { printf "\n incrond daemon errors \n"; for my $key (keys %INCRONDErr) { print " " . $key . ": " . $INCRONDErr{$key} . " time(s)\n"; } } if (%SELCONTErr) { printf "\n SELinux context error \n"; for my $key (keys %SELCONTErr) { print " " . $key . ": " . $SELCONTErr{$key} . " time(s)\n"; } } if ($PAMAUTHErr) { printf "\nPAM authentication error: " . $PAMAUTHErr . " time(s)\n"; } if (%CHDIRErr) { printf "\nchdir command failed\n"; foreach (keys %CHDIRErr) { my ($File,$Cause) = split ","; print " for directory " . $File . " (" . $Cause . ")". ": " . $CHDIRErr{"$File,$Cause"} . " time(s)\n"; } } if ($CHUSERHErr) { printf "\nUser change error: " . $CHUSERHErr . " time(s)\n"; } if (keys %{$Runs} and ($Detail >= 5)) { print "\n\nCommands Run:\n"; foreach my $i (sort {$a cmp $b} keys %{$Runs}) { print " User $i:\n"; foreach my $j (sort {$a cmp $b} keys %{$Runs->{$i}}) { print " $j: " . $Runs->{$i}->{$j} . " Time(s)\n"; } } } if ($Orphans) { print " ORPHAN entries: $Orphans\n"; } if ($MailErrors > 0) { print "\nMAIL sending errors $MailErrors Time(s)\n"; } if (keys %BFMFile) { print "\nFiles with bad mode:\n"; foreach my $i (keys %BFMFile) { print " $i\n"; } } if (keys %WFO) { foreach my $i (keys %WFO) { printf "\n Wrong file owner (". $i ."): " . $WFO{$i}. " Time(s)\n"; } } if ($Ntpdate) { print "\nNtpdate: adjusted $Ntpdate times\n"; print "\tMinimum offset $ntpdateminoffset\n"; print "\tMaximum offset $ntpdatemaxoffset\n"; } if($ntpdatenosync) { print "\nNtpDate could not sync: $ntpdatenosync times\n"; } if ($Detail >= 10) { if (keys %UserReloads) { print " User crontabs reloaded:\n"; foreach my $i (keys %UserReloads) { print " $i $UserReloads{$i} Time(s)\n"; } } if ($Startups > 0) { print "\nCRON Started $Startups Time(s)\n"; } if ($Shutdowns > 0) { print "\nCRON Shutdown $Shutdowns Time(s)\n"; } if ($Reloads > 0) { print "\nCRON Reloaded system crontab $Reloads Time(s)\n"; } if ($INCRONDSS) { printf "\n service incrond started " . $INCRONDSS . ": time(s)\n"; } if ($INCRONDStS) { printf "\n service incrond stoped " . $INCRONDStS . ": time(s)\n"; } if ((%INCRONDSTCr) || (%INCRONDUTCr)) { printf "\n created tables \n"; for my $key (keys %INCRONDSTCr) { print " system table " . $key . " created " . $INCRONDSTCr{$key} . ": time(s)\n"; } for my $key (keys %INCRONDUTCr) { print " table for user " . $key . " created " . $INCRONDUTCr{$key}. ": time(s)\n"; } } if ((%INCRONDSTCh) || (%INCRONDUTCh)) { printf "\n changes of tables \n"; for my $key (keys %INCRONDSTCh) { print " system table " . $key . " changed " . $INCRONDSTCh{$key} . ": time(s)\n"; } for my $key (keys %INCRONDUTCh) { print " table for user " . $key . "changed " . $INCRONDUTCh{$key} . ": time(s)\n"; } } if ((%INCRONDSTDe) || (%INCRONDUTDe)) { printf "\n destroyed tables \n"; for my $key (keys %INCRONDSTDe) { print " system table " . $key . " destroyed " . $INCRONDSTDe{$key} . ": time(s)\n"; } for my $key (keys %INCRONDUTDe) { print " table for user ". $key ." destroyed " .$INCRONDUTDe{$key} . ": time(s)\n"; } } } if ($#OtherList >= 0) { print "\n**Unmatched Entries**\n"; print @OtherList; } exit(0); # vi: shiftwidth=3 tabstop=3 syntax=perl et # Local Variables: # mode: perl # perl-indent-level: 3 # indent-tabs-mode: nil # End: logwatch-7.12/scripts/services/mod_security20000664000211400021140000001720014274101040021463 0ustar logwatchlogwatch ######################################################## # Please file all bug reports, patches, and feature # requests under: # https://sourceforge.net/p/logwatch/_list/tickets # and copy: # Torben Hansen # Help requests and discusion can be filed under: # https://sourceforge.net/p/logwatch/discussion/ ######################################################## ########################################################################## # This script is written an maintained by: # Torben Hansen # # To send comments, suggestions, bugreports, etc, please use: # https://github.com/derhansen/logwatch-modsec2 ########################################################################## ########################################################################## ## Copyright © 2013 Torben Hansen ## Covered under the included MIT/X-Consortium License: ## http://www.opensource.org/licenses/mit-license.php ## All modifications and contributions by other persons to ## this script are assumed to have been donated to the ## Logwatch project and thus assume the above copyright ## and licensing terms. If you want to make contributions ## under your own copyright or a different license this ## must be explicitly stated in the contribution an the ## Logwatch project reserves the right to not accept such ## contributions. If you have made significant ## contributions to this script and want to claim ## copyright please contact logwatch-devel@lists.sourceforge.net. ######################################################### use Logwatch ':dates'; use strict; # Disable warnings about unused variables #no warnings qw(once); my $Detail = $ENV{'LOGWATCH_DETAIL_LEVEL'} || 0; my $Debug = $ENV{'LOGWATCH_DEBUG'} || 0; my $SearchDate = TimeFilter('%d/%b/%Y:%H:%M:%S'); my $within_range = 0; my %tmpEntry = (); #This gets reset in STDIN loop perhaps in error my $count = 0; my %messages = (); my %topips = (); my %toprules = (); my $check = 0; my $option = ''; if ( $Debug >= 5 ) { print STDERR "\n\nDEBUG MODE \n\n"; } # Initialize array $tmpEntry{$count}{"action"} = ""; $tmpEntry{$count}{"hostname"} = ""; $tmpEntry{$count}{"message"} = ""; $tmpEntry{$count}{"ruleid"} = ""; while (defined(my $ThisLine = )) { chomp($ThisLine); # Reset $check if line starts with two dashes if ( $ThisLine =~ /-[A-Z]--/ ) { $check = 0; $option = ""; } if ($check == 1) { if ($option eq "audit-log-header") { my ($timestamp, $transactionID, $sourceIP, $sourcePort, $destIP, $destPort ) = ($ThisLine =~ /\[(.*?)\] (.*?) (.*?) (.*?) (.*?) (.*?)$/ ); $tmpEntry{$count}{"timestamp"} = $timestamp; $tmpEntry{$count}{"sourceIp"} = $sourceIP; $tmpEntry{$count}{"sourcePort"} = $sourcePort; $tmpEntry{$count}{"destIp"} = $destIP; $tmpEntry{$count}{"destPort"} = $destPort; if ( $Debug >= 5 ) { print STDERR "\n"; print STDERR "DATE: " . $timestamp . "\n"; print STDERR "FROM: ". $sourceIP . ":" . $sourcePort . "\n"; print STDERR "TO: ". $destIP . ":" . $destPort . "\n"; } } if ($option eq "request-header") { if ( my ($method, $requestUri) = ($ThisLine =~ /^(POST|GET) (.*?)$/) ) { $tmpEntry{$count}{"method"} = $method; $tmpEntry{$count}{"uri"} = $requestUri; if ( $Debug >= 5 ) { print STDERR "METHOD: " . $method . "\n"; print STDERR "URI: " . $requestUri . "\n"; } } elsif ( my ($hostname) = ($ThisLine =~ /^Host: (.*?)$/) ) { $tmpEntry{$count}{"hostname"} = $hostname; if ( $Debug >= 5 ) { print STDERR "HOST: " . $hostname . "\n"; } } } if ($option eq "audit-log-trailer") { if ( $ThisLine =~ /^Message:/ ) { my ($ruleId, $msg); if ( ($ruleId) = ($ThisLine =~ /\[id \"(.*?)\"\]/) ) { if ( $Debug >= 5 ) { print STDERR "Rule ID: " . $ruleId. "\n"; } } if ( ($msg) = ($ThisLine =~ /\[msg \"(.*?)\"\]/) ) { if ( $Debug >= 5 ) { print STDERR "Message: " . $msg. "\n"; } } $tmpEntry{$count}{"ruleid"} = $ruleId; $tmpEntry{$count}{"message"} = $msg; } if ( my ($action) = ($ThisLine =~ /^Action: (.*?)$/) ) { $tmpEntry{$count}{"action"} = $action; if ( $Debug >= 5 ) { print STDERR "Action: " . $action. "\n"; } } if ( my ($engineMode) = ($ThisLine =~ /^Engine-Mode: (.*?)$/) ) { $tmpEntry{$count}{"engine"} = $engineMode; if ( $Debug >= 5 ) { print STDERR "Engine mode: " . $engineMode. "\n"; } } } } if ( $ThisLine =~ /-A--/ ) { $check = 1; $option = "audit-log-header"; } elsif ( $ThisLine =~ /-B--/ ) { $check = 1; $option = "request-header"; } elsif ( $ThisLine =~ /-H--/ ) { $check = 1; $option = "audit-log-trailer"; } elsif ( $ThisLine =~ /-Z--/ ) { $check = 0; $option = ""; # Create new summary entry if date matches searchdate if ( $tmpEntry{$count}{"timestamp"} =~ /$SearchDate/ ) { if ( $tmpEntry{$count}{"action"} ne "" && $tmpEntry{$count}{"hostname"} ne "" && $tmpEntry{$count}{"message"} ne "" && $tmpEntry{$count}{"ruleid"} ne "" ) { $messages{$tmpEntry{$count}{"hostname"}}{"numAttacks"}++; $messages{$tmpEntry{$count}{"hostname"}}{"attack"}{$tmpEntry{$count}{"sourceIp"}}{$tmpEntry{$count}{"ruleid"}} = $tmpEntry{$count}{"message"}; $messages{$tmpEntry{$count}{"hostname"}}{$tmpEntry{$count}{"sourceIp"}}{$tmpEntry{$count}{"ruleid"}}++; $topips{$tmpEntry{$count}{"sourceIp"}}++; $toprules{$tmpEntry{$count}{"ruleid"}}++; } } # Increase counter $count++; # Reset values #$tmpEntry = (); $tmpEntry{$count}{"action"} = ""; $tmpEntry{$count}{"hostname"} = ""; $tmpEntry{$count}{"message"} = ""; $tmpEntry{$count}{"ruleid"} = ""; if ( $Debug >= 5 ) { print STDERR "---------------------------------------\n"; } } } # Start summary if (keys %messages) { print "\nATTACKS BLOCKED ON VHOSTS:\n"; foreach my $vhost ( sort {$a cmp $b} keys %messages ) { print "\n" . $vhost . " - " . $messages{$vhost}{"numAttacks"} . " time(s)\n"; foreach my $fromip (sort {$a cmp $b} keys %{$messages{$vhost}{"attack"}}) { foreach my $ruleid (sort {$a cmp $b} keys %{$messages{$vhost}{"attack"}{$fromip}}) { print " [ip: " . sprintf("%-15s", $fromip) . "] "; print "[id: " . $ruleid . " ] [msg: " . $messages{$vhost}{"attack"}{$fromip}{$ruleid} . "] "; print " - " . $messages{$vhost}{$fromip}{$ruleid} . " time(s)\n"; } } } } # Top 10 blocked IPs if (keys %topips) { print "\nTOP 10 BLOCKED IPS:\n"; my $cnt = 0; foreach my $ip ( sort {$topips{$b} <=> $topips{$a}} keys %topips ) { print "\n " . sprintf("%2s", ($cnt + 1)) . ". " . $ip . " - " . $topips{$ip} . " time(s)"; $cnt++; if($cnt == 10) { last(); } } print "\n"; } exit(0) logwatch-7.12/scripts/services/iptables0000664000211400021140000003652514743365004020526 0ustar logwatchlogwatch ######################################################## # Please file all bug reports, patches, and feature # requests under: # https://sourceforge.net/p/logwatch/_list/tickets # Help requests and discusion can be filed under: # https://sourceforge.net/p/logwatch/discussion/ ######################################################## ########################################################################## # iptables, ipchains, and ipfwadm script for Logwatch. # Ipfwadm and ipchains are deprecated, but is included # here for backwards compatibility. # # This script was extracted from the kernel script, # which processed netfilter (iptables, ipchains, and # ipfwadm) statements until kernel script Revision 1.29. ########################################################################## ##################################################### ## Copyright (c) 2008 Kirk Bauer ## Covered under the included MIT/X-Consortium License: ## http://www.opensource.org/licenses/mit-license.php ## All modifications and contributions by other persons to ## this script are assumed to have been donated to the ## Logwatch project and thus assume the above copyright ## and licensing terms. If you want to make contributions ## under your own copyright or a different license this ## must be explicitly stated in the contribution an the ## Logwatch project reserves the right to not accept such ## contributions. If you have made significant ## contributions to this script and want to claim ## copyright please contact logwatch-devel@lists.sourceforge.net. ######################################################### use Logwatch ':ip'; use strict; my $Detail = $ENV{'LOGWATCH_DETAIL_LEVEL'} || 0; my $MinFilter = $ENV{'iptables_host_min_count'} || 0; DoLookup( $ENV{'iptables_ip_lookup'} ); my $ListByHost = $ENV{'iptables_list_by_host'} || 0; my $ListByService = $ENV{'iptables_list_by_service'} || 0; my $ListByCidrBits = $ENV{'iptables_list_by_cidr_mask'} || 0; #Init String Containers my ( $TU, $action, $actionType, $chain, $chain_info, $from, $fromHostCount, $fromip, $if, $ifin, $ifout, $inout, $interface, $interfaceCount, $outputMain, $outputSection, $outputServices, $packetCount, $port, $proto, $protocol, $repcnt, $rest, $service, $to, $toHostCount, $toip, $toport, ); #Init Hashes my ( %TCPscan, %hostList, %ipt, %ipt2, %port_list ); # Keep old behaviour if nothing is configured $ListByHost = 1 unless ($ListByService || $ListByCidrBits ); my $MaxFlood = 10; my $MaxNum = 0; # this happens at runtime, not compile time - so we don't need the module # unless we need the module. :) if ($ListByCidrBits) { require Net::CIDR; } sub lookupService { my ($port, $proto, $service); ($port, $proto) = ($_[0], $_[1]); if ($service = getservbyport ($port, $proto)) { return($service); } else { return($port); } } sub lookupProtocol { my ($proto, $name); $proto = $_[0]; if ($name = getprotobynumber ($proto)) { return($name); } else { return($proto); } } sub lookupAction { my ($chain, $actionType); $chain = $_[0]; # choose an action type if ( $chain =~ /reject/i ) { $actionType = "Rejected"; } elsif ( $chain =~ /drop/i ) { $actionType = "Dropped"; } elsif ( $chain =~ /deny/i ) { $actionType = "Denied"; } elsif ( $chain =~ /denied/i ) { $actionType = "Denied"; } elsif ( $chain =~ /accept/i ) { $actionType = "Accepted"; } else { $actionType = "Logged"; } return $actionType; } # SORT COMPARISONS sub compStr { return $a cmp $b; } sub compNum { return $a <=> $b; } while (defined(my $ThisLine = )) { chomp($ThisLine); next if ($ThisLine eq ''); # the format for ulogd/ulogd.syslogmenu and messages differ in that # the earlier has no service name after the date. So RemoveHeaders # doesn't work. Therefore, we extract it here: $ThisLine =~ s/^... .. ..:..:.. ([^ ]*) (kernel: )?(\[\s*\d+\.\d+\] )?//; # IPCHAINS if( ($TU,$from,$port) = ( $ThisLine =~ /IP fw-in deny \w+ (\w+) ([^:]+):\d+ ([^:]+):(?:\d+) / ) ){ if($MaxNum < ++$TCPscan{$TU}{$from}) { $MaxNum = $TCPscan{$TU}{$from} } $port=0; } elsif ( ($chain,$action,$if,$proto,$fromip,$toip,$toport) = ( $ThisLine =~ /^Packet log: ([^ ]+) (\w+) (\w+) PROTO=(\d+) ([\d|\.]+):\d+ ([\d|\.]+):(\d+)/ ) ) { $actionType = lookupAction($action); $ipt{$actionType}{$if}{$fromip}{$toip}{$toport}{$proto}{"$chain,$if"}++; $ipt2{$actionType}{$if}{$toport}{$proto}{$fromip}{$toip}{"$chain,$if"}++; } # IPTABLES elsif (($chain,$ifin,$ifout,$fromip,$toip,$proto,$rest) = ($ThisLine =~ /^(.*?)\s*IN=([\w\.\-]*).*?OUT=([\w\.\-]*).*?SRC=([\w\.:]+).*?DST=([\w\.:]+).*?PROTO=(\w+)(.*)/ )) { # STATE_INVALID_DROP is generally uninteresting next if ($chain eq "STATE_INVALID_DROP:" and $Detail < 10); # get a destination port number (or icmp type) if there is one if (! ( ($toport) = ( $rest =~ /TYPE=(\w+)/ ) ) ) { if (! ( ($toport) = ( $rest =~ /DPT=(\w+)/ ) ) ) { $toport = 0; } } # get the action type $actionType = lookupAction($chain); # determine the dominant interface if ($ifin =~ /\w+/ && $ifout =~ /\w+/) { $interface = $ifin; } elsif ($ifin =~ /\w+/) { $interface = $ifin; $ifout = "none"; } else { $interface = $ifout; $ifin = "none"; } if ($chain eq "") { $chain_info = ""; } else { $chain_info = "(" . $chain . ") "; } # add the packet # $ipt{$actionType}{$interface}{$fromip}{$toip}{$toport}{$proto}{"$chain,$ifin,$ifout"}++; if ( $ListByCidrBits ) { my $cidrblock=( reverse( Net::CIDR::addr2cidr($fromip) ) )[$ListByCidrBits]; $ipt{$actionType}{$interface}{$cidrblock}{$toip}{$toport}{$proto}{$chain_info}++; } else { $ipt{$actionType}{$interface}{$fromip}{$toip}{$toport}{$proto}{$chain_info}++; } $ipt2{$actionType}{$interface}{$toport}{$proto}{$fromip}{$toip}{$chain_info}++; } # IPF elsif (($repcnt,$if,$chain,$fromip,$toip,$toport,$proto,$rest) = ($ThisLine =~ /^.*\d{2,2}:\d{2,2}:\d{2,2}\.\d{6,6}\s*(?:(\d{1,})x)*\s*(\w*)\s*@[-]*\d{1,}:[-]*\d{1,}\s*(\w*)\s*([\w\.:]+\w),*(?:\d*)\s*->\s*([\w\.:]+\w),*(\d*)\s*PR\s*(\w*)\s*(.*((?:IN|OUT)).*)/)) { if ($chain eq 'b') { $actionType = "drop"; } elsif ($chain eq 'p') { $actionType = "accept"; } if ($repcnt eq '') { $repcnt = 1; } while ($repcnt >= 1) { $ipt{$actionType}{$if}{$fromip}{$toip}{$toport}{$proto}{"$actionType,$if"}++; $ipt2{$actionType}{$if}{$toport}{$proto}{$fromip}{$toip}{"$actionType,$if"}++; $repcnt = $repcnt - 1; } } } # IPCHAINS if (keys %TCPscan and $MaxNum>$MaxFlood) { print "\nWarning: ipfwadm scan detected on:\n"; foreach my $ThisOne (sort compStr keys %TCPscan) { print " " . $ThisOne . " from:\n"; foreach my $Next (sort compStr keys %{$TCPscan{$ThisOne}}) { $TCPscan{$ThisOne}{$Next}>$MaxFlood && print " " . LookupIP($Next). ": $TCPscan{$ThisOne}{$Next} Time(s)\n"; } } } if ((keys %ipt2) and $ListByService) { foreach my $actionType (sort compStr keys %ipt2) { foreach my $interface (sort compStr keys %{$ipt2{$actionType}}) { my $outputMain = ''; my $interfaceCount = 0; foreach my $toport (sort compNum keys %{$ipt2{$actionType}{$interface}}) { foreach my $proto (sort compStr keys %{$ipt2{$actionType}{$interface}{$toport}}) { my $outputSection = ''; my $portCount = 0; my $hostCount = 0; undef %hostList; my %host_list = (); my $protocol; # determine the protocol if ( $proto =~ /^\d+$/ ) { $protocol = lookupProtocol($proto); } else { $protocol = lc($proto); } # determine the name of the service my $service = lookupService($toport,$protocol); foreach my $fromip (sort SortIP keys %{$ipt2{$actionType}{$interface}{$toport}{$proto}}) { my $fromHostCount = 0; my $from = LookupIP($fromip); my $outputDetails = ""; foreach my $toip (sort SortIP keys %{$ipt2{$actionType}{$interface}{$toport}{$proto}{$fromip}}) { my $toHostCount = 0; my $to = LookupIP($toip); foreach my $details (sort keys %{$ipt2{$actionType}{$interface}{$toport}{$proto}{$fromip}{$toip}}) { my $packetCount = $ipt2{$actionType}{$interface}{$toport}{$proto}{$fromip}{$toip}{$details}; $toHostCount += $packetCount; if ( $Detail > 9 and ( $outputDetails !~ /\Q$details\E/ ) ) { $outputDetails .= $details . ", "; } } $fromHostCount += $toHostCount; } if ( $Detail > 9 ) { chop $outputDetails; chop $outputDetails; push @{$hostList{"$fromHostCount"}}, $from . " " . $outputDetails; } else { push @{$hostList{"$fromHostCount"}}, $from; } $portCount += $fromHostCount; $hostCount++; } $interfaceCount += $portCount; if ($Detail > 5 ) { $outputMain .= sprintf(" To port %d/%s (%s) - ". "%d packet%s from %d host%s\n", $toport, $protocol, ( $service =~ /^\d+$/ ) ? "?" : $service, $portCount, ( $portCount > 1 ) ? "s" : " ", $hostCount, ( $hostCount > 1 ) ? "s" : " " ); foreach my $hc (sort { $b <=> $a } keys %hostList) { foreach my $h (@{$hostList{"$hc"}}) { $outputMain .= sprintf(" %6d packet%s from %s\n", $hc, ( $hc > 1 ) ? "s" : " ", $h); } } } elsif ($Detail > 3 ) { my $topHostCount; ($topHostCount, undef) = sort { $b <=> $a } keys %hostList; my $topHost = ${$hostList{"$topHostCount"}}[0]; $outputMain .= sprintf( " To port %5d/%s - %5d packet%s ". "from %4d host%s (%d from %s)\n", $toport, $protocol, $portCount, ( $portCount > 1 ) ? "s" : " ", $hostCount, ( $hostCount > 1 ) ? "s" : " ", $topHostCount, $topHost ); } else { $outputMain .= sprintf(" To port %5d/%s - %5d packet%s ". "from %4d host%s\n", $toport, $protocol, $portCount, ( $portCount > 1 ) ? "s" : " ", $hostCount, ( $hostCount > 1 ) ? "s" : " " ); } } } print "Listed by target ports:"; print "\n$actionType $interfaceCount " . ( ( $interfaceCount > 1 ) ? "packets" : "packet" ) . " on interface $interface\n"; print $outputMain; } } } # IPCHAINS / IPTABLES if ((keys %ipt) and $ListByHost) { foreach my $actionType (sort compStr keys %ipt) { foreach my $interface (sort compStr keys %{$ipt{$actionType}}) { $outputMain = ''; $interfaceCount = 0; foreach my $fromip (sort SortIP keys %{$ipt{$actionType}{$interface}}) { $outputSection = ''; $fromHostCount = 0; $from = LookupIP($fromip); undef %port_list; foreach my $toip (sort SortIP keys %{$ipt{$actionType}{$interface}{$fromip}}) { $toHostCount = 0; $to = LookupIP($toip); $outputServices = ''; foreach my $toport (sort compNum keys %{$ipt{$actionType}{$interface}{$fromip}{$toip}}) { foreach my $proto (sort compStr keys %{$ipt{$actionType}{$interface}{$fromip}{$toip}{$toport}}) { # determine the protocol if ( $proto =~ /^\d+$/ ) { $protocol = lookupProtocol($proto); } else { $protocol = lc($proto); } # determine the name of the service $service = lookupService($toport,$protocol); foreach my $details (sort keys %{$ipt{$actionType}{$interface}{$fromip}{$toip}{$toport}{$proto}}) { $packetCount = $ipt{$actionType}{$interface}{$fromip}{$toip}{$toport}{$proto}{$details}; $toHostCount += $packetCount; if ( $Detail > 0 ) { $outputServices .= " Service: $service ($protocol/$toport) $details- $packetCount " . ( ( $packetCount > 1 ) ? "packets\n" : "packet\n" ); } else { ${ $port_list{ $protocol } }{$toport}++; } } } } $fromHostCount += $toHostCount; if ( $Detail > 0 ) { $outputSection .= " To $to - $toHostCount " . ( ( $toHostCount > 1 ) ? "packets\n" : "packet\n" ); } $outputSection .= $outputServices; } $interfaceCount += $fromHostCount; if ($fromHostCount >= $MinFilter) { if ($Detail > 0) { $outputMain .= " From $from - $fromHostCount " . ( ( $fromHostCount > 1 ) ? "packets\n" : "packet\n" ); } else { $outputMain .= " From $from - $fromHostCount " . ( ($fromHostCount > 1) ? "packets" : "packet" ) . " to " ; foreach my $protocol ( sort keys %port_list ) { my $num_ports = keys %{$port_list { $protocol } }; if ($num_ports > 10) { $outputMain .= "$num_ports $protocol ports "; } else { $outputMain .= "$protocol(" . join(",", sort compNum keys %{ $port_list{ $protocol } } ) . ") " ; } } $outputMain .="\n"; } $outputMain .= $outputSection; } } print "\nListed by source hosts:"; print "\n$actionType $interfaceCount " . ( ( $interfaceCount > 1 ) ? "packets" : "packet" ) . " on interface $interface\n"; print $outputMain; } } } exit(0); # vi: shiftwidth=3 tabstop=3 syntax=perl et # Local Variables: # mode: perl # perl-indent-level: 3 # indent-tabs-mode: nil # End: logwatch-7.12/scripts/services/rsnapshot0000664000211400021140000001036714274101043020726 0ustar logwatchlogwatch ######################################################## # Please file all bug reports, patches, and feature # requests under: # https://sourceforge.net/p/logwatch/_list/tickets # Help requests and discusion can be filed under: # https://sourceforge.net/p/logwatch/discussion/ ######################################################## # # rsnapshot backup tool log parsing script # ######################################################## ## Copyright (c) 2016 Hayden Lau ## Covered under the included MIT/X-Consortium License: ## http://www.opensource.org/licenses/mit-license.php ## All modifications and contributions by other persons to ## this script are assumed to have been donated to the ## Logwatch project and thus assume the above copyright ## and licensing terms. If you want to make contributions ## under your own copyright or a different license this ## must be explicitly stated in the contribution an the ## Logwatch project reserves the right to not accept such ## contributions. If you have made significant ## contributions to this script and want to claim ## copyright please contact logwatch-devel@lists.sourceforge.net. ######################################################## ## Permission is hereby granted, free of charge, to any person obtaining a ## copy of this software and associated documentation files (the "Software"), ## to deal in the Software without restriction, including without limitation ## the rights to use, copy, modify, merge, publish, distribute, sublicense, ## and/or sell copies of the Software, and to permit persons to whom the ## Software is furnished to do so, subject to the following conditions: ## ## The above copyright notice and this permission notice shall be included ## in all copies or substantial portions of the Software. ## ## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS ## OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ## MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. ## IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY ## CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, ## TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE ## SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ############################################################################ use strict; my $Debug = $ENV{'LOGWATCH_DEBUG'} || 0; my $Detail = $ENV{'LOGWATCH_DETAIL_LEVEL'} || 0; my %Error; my %Warning; my %Started; my %Successful; my %OtherList; my %Commands; while (defined(my $ThisLine = )) { chomp($ThisLine); if ($Debug) { print "$ThisLine\n"; } if ($ThisLine =~ /ERROR: (\N+)/) { $Error{$1}++; } elsif ($ThisLine =~ /WARNING: (\N+)/) { $Warning{$1}++; } elsif ($ThisLine =~ / (\S+): started/) { $Started{$1}++; } elsif ($ThisLine =~ / (\S+): completed successfully/) { $Successful{$1}++; } elsif ($ThisLine =~ /^(?:\/usr|\/bin|mv|rm|rsync|echo|mkdir|touch)(?:\/| )/) { $Commands{$ThisLine}++; } else { $OtherList{$ThisLine}++; } } if (keys %Error) { print "ERRORS:\n"; foreach my $line (sort {$a cmp $b} keys %Error) { print " $line: $Error{$line} Time(s)\n"; } print "\n"; } if (keys %Warning) { print "Warnings:\n"; foreach my $line (sort {$a cmp $b} keys %Warning) { print " $line: $Warning{$line} Time(s)\n"; } print "\n"; } if (($Detail > 5) and keys %Started) { print "Started:\n"; foreach my $retain (sort { $Started{$b} <=> $Started{$a} } keys %Started) { print " $retain: $Started{$retain} Time(s)\n"; } print "\n"; } if ($Detail and keys %Successful) { print "Completed Successfully:\n"; foreach my $retain (sort { $Successful{$b} <=> $Successful{$a} } keys %Successful) { print " $retain: $Successful{$retain} Time(s)\n"; } print "\n"; } if ($Detail > 5 and keys %Commands) { print "Commands:\n"; foreach my $cmd (sort { $Commands{$b} <=> $Commands{$a} } keys %Commands) { printf " %3d Time(s): %s\n", $Commands{$cmd}, $cmd; } print "\n"; } if (keys %OtherList) { print "\n**Unmatched Entries**\n"; foreach my $line (sort {$a cmp $b} keys %OtherList) { print " $line: $OtherList{$line} Time(s)\n"; } print "\n"; } exit(0); logwatch-7.12/scripts/services/php0000664000211400021140000001212014274101041017457 0ustar logwatchlogwatch ######################################################## # Please file all bug reports, patches, and feature # requests under: # https://sourceforge.net/p/logwatch/_list/tickets # Help requests and discusion can be filed under: # https://sourceforge.net/p/logwatch/discussion/ ######################################################## ############################################################################### # # Logwatch service for php error logs # # Processes all messages and summarizes them # Each message is given with a timestamp and RMS ####################################################### ## Copyright (C) 2006 by Jeremias Reith ## Covered under the included MIT/X-Consortium License: ## http://www.opensource.org/licenses/mit-license.php ## All modifications and contributions by other persons to ## this script are assumed to have been donated to the ## Logwatch project and thus assume the above copyright ## and licensing terms. If you want to make contributions ## under your own copyright or a different license this ## must be explicitly stated in the contribution an the ## Logwatch project reserves the right to not accept such ## contributions. If you have made significant ## contributions to this script and want to claim ## copyright please contact logwatch-devel@lists.sourceforge.net. ######################################################### use strict; use Logwatch ':dates'; use Time::Local; use POSIX qw(strftime); my $date_format = '%d-%b-%Y %H:%M:%S'; my $filter = TimeFilter($date_format); my $detail = exists $ENV{'LOGWATCH_DETAIL_LEVEL'} ? $ENV{'LOGWATCH_DETAIL_LEVEL'} : 0; # we do not use any Date:: package (or strptime) as they are probably not available my %month2num = ( Jan => 0, Feb => 1, Mar => 2, Apr => 3, May => 4, Jun => 5, Jul => 6, Aug => 7, Sep => 8, Oct => 9, Nov => 10, Dec => 11 ); # array of message categories (we do not use a hash to keep the order) # first element: category name # second element: matching regexp ($1 should contain the message) # third element: anonymous hash ref (stores message counts) my @message_categories = (['Fatal errors', qr/\] PHP Fatal error: (.*)$/o, {}], ['Warnings', qr/\] PHP Warning: (.*)$/o, {}], ['Notices', qr/\] PHP Notice: (.*)$/o, {}]); # skipping categories depending on detail level pop(@message_categories) if $detail < 10; pop(@message_categories) if $detail < 5; # counting messages while(<>) { my $line = $_; # skipping messages that are not within the requested range # the last part of the regex matches optionally occurring specification # of timezones, either in Continent/City or abbreviations like UTC next unless $line =~ /^\[($filter)(?: \w+(?:\/\w+)?)?\]/o; $1 =~ /(\d+)-(\w+)-(\d+) (\d+):(\d+):(\d+)/; my $time; { # timelocal is quite chatty local $SIG{'__WARN__'} = sub {}; $time = timelocal($6, $5, $4, $1, $month2num{$2}, $3-1900); } foreach my $cur_cat (@message_categories) { if($line =~ /$cur_cat->[1]/) { my $msgs = $cur_cat->[2]; $msgs->{$1} = {count => '0', first_occurrence => $time, sum => 0, sqrsum => 0} unless exists $msgs->{$1}; $msgs->{$1}->{'count'}++; # summing up timestamps and squares of timestamps # in order to calculate the rms # using first occurrence of message as offset in calculation to # prevent an integer overflow $msgs->{$1}->{'sum'} += $time - $msgs->{$1}->{'first_occurrence'}; $msgs->{$1}->{'sqrsum'} += ($time - $msgs->{$1}->{'first_occurrence'}) ** 2; last; } } } # generating summary foreach my $cur_cat (@message_categories) { # skipping non-requested message types next unless keys %{$cur_cat->[2]}; my ($name, undef, $msgs) = @{$cur_cat}; print $name, ":\n"; my $last_count = 0; # sorting messages by count my @sorted_msgs = sort { $msgs->{$b}->{'count'} <=> $msgs->{$a}->{'count'} } keys %{$msgs}; foreach my $msg (@sorted_msgs) { # grouping messages by number of occurrence print "\n", $msgs->{$msg}->{'count'}, " times:\n" unless $last_count == $msgs->{$msg}->{'count'}; my $rms = 0; # printing timestamp print '['; if($msgs->{$msg}->{'count'} > 1) { # calculating rms $rms = int(sqrt( ($msgs->{$msg}->{'count'} * $msgs->{$msg}->{'sqrsum'} - $msgs->{$msg}->{'sum'}) / ($msgs->{$msg}->{'count'} * ($msgs->{$msg}->{'count'} - 1)))); print strftime($date_format, localtime($msgs->{$msg}->{'first_occurrence'}+int($rms/2))); print ' +/-'; # printing rms if($rms > 86400) { print int($rms/86400) , ' day(s)'; } elsif($rms > 3600) { print int($rms/3600) , ' hour(s)'; } elsif($rms > 60) { print int($rms/60) , ' minute(s)'; } else { print $rms, ' seconds'; } } else { # we have got this message a single time print strftime($date_format, localtime($msgs->{$msg}->{'first_occurrence'})); } print '] ', $msg, "\n"; $last_count = $msgs->{$msg}->{'count'}; } print "\n"; } # vi: shiftwidth=3 tabstop=3 et # Local Variables: # mode: perl # perl-indent-level: 3 # indent-tabs-mode: nil # End: logwatch-7.12/scripts/services/courier0000664000211400021140000005607714274101035020366 0ustar logwatchlogwatch ######################################################## # Please file all bug reports, patches, and feature # requests under: # https://sourceforge.net/p/logwatch/_list/tickets # Help requests and discusion can be filed under: # https://sourceforge.net/p/logwatch/discussion/ ######################################################## ####################################################### ### Copyright 2003-2006 by Willi Mann ### Covered under the included MIT/X-Consortium License: ### http://www.opensource.org/licenses/mit-license.php ### All modifications and contributions by other persons to ### this script are assumed to have been donated to the ### Logwatch project and thus assume the above copyright ### and licensing terms. If you want to make contributions ### under your own copyright or a different license this ### must be explicitly stated in the contribution an the ### Logwatch project reserves the right to not accept such ### contributions. If you have made significant ### contributions to this script and want to claim ### copyright please contact logwatch-devel@lists.sourceforge.net. ####################################################### ####################################################### # # Please don't change the formatting: # # if (...) { # ... # } # # but # # (while|foreach) .. # { # ... # } # ####################################################### use strict; #Could be necessary in some environments unless ($ENV{'courier_enable'} == 1) {exit 0}; my $Debug = $ENV{'LOGWATCH_DEBUG'}; my $DoLookup = $ENV{'courier_ip_lookup'}; my $Detail = $ENV{'LOGWATCH_DETAIL_LEVEL'}; my $overrideDetail = $ENV{'courier_override_detail_level'}; my $printAllUnmatched = $ENV{'courier_print_all_unmatched'}; $Detail = $overrideDetail if defined $overrideDetail; my $PrintMailQueue = $ENV{'courier_printmailqueue'}; my $Tables = $ENV{'courier_tables'}; my $RemoveAdditionalInfo = $ENV{'courier_removeadditionalinfo'}; my $MostFrequentSender = $ENV{'courier_mostfrequentsender'}; my $DeliverMailSize = 0; my $LastLine; my %OtherList; sub LookupIP { my ($name, $a1, $a2,$a3,$a4,$PackedAddr,$Addr); $Addr = $_[0]; ($a1,$a2,$a3,$a4) = split /\./,$Addr; $PackedAddr = pack('C4',$a1,$a2,$a3,$a4); if ($DoLookup) { if ($name = gethostbyaddr ($PackedAddr,2)) { return ($name . " (" . $Addr . ")"); } else { return ($Addr); } } else { return ($Addr); } } #Make pseudo IPv6 to IPv4 sub LookupIPv46 { my $IPv4Addr; my $Addr = shift; if ( ($IPv4Addr) = ($Addr =~ /::ffff:([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})/ ) ) { return $IPv4Addr; } else { return $Addr; } } sub PushUnmatched { my $service = shift; my $line = shift; if ( $printAllUnmatched or $service =~ /courier/ or $service =~ /^authdaemon/ ) { $OtherList{$service}{$line}++; } } sub recprint1 { my $hash = shift; my $depth = shift; my $prefar = shift; my $IPar = shift; my $indention = shift || 0; my $calldepth = shift || $depth; my $sizehash = shift; my $out = ""; my $inum = 0; my $size = 0; my @prefar = @{$prefar} if defined $prefar; my $pref = shift(@prefar); $pref .= " " if defined $pref; $pref = "" if not defined $pref; my @IPar = @{$IPar} if defined $IPar; my $IP = shift(@IPar); foreach my $key1 (sort keys %{$hash}) { my ( $rout, $nmb, $rsize); if ($depth > 1) { ($rout, $nmb, $rsize) = recprint1($hash->{$key1}, $depth - 1, \@prefar, \@IPar, $indention + 3, $calldepth, defined $sizehash ? $sizehash->{$key1} : undef) if $depth > 1; } else { $rout = ""; $nmb = $hash->{$key1}; $rsize = $sizehash->{$key1} if defined $sizehash; } if ($key1 ne "-" or $rout ne "") { $out .= (" " x $indention).$pref; if ($IP) { $out .= LookupIP(LookupIPv46($key1)); } else { $out .= $key1; } $out .= " - ".nTimes($nmb); $out .= ", ".$rsize." Bytes" if defined $sizehash; $out .= "\n"; $out .= $rout; } $out .= "\n" if $depth == $calldepth; $inum += $nmb; $size += $rsize; } if (wantarray) { return ($out, $inum, $size); } else { return $out; } } sub tblprint1 { my $hash = shift; my $sizehash = shift; my $onerec = shift || 0; #boolean my $IP = shift || 0; #boolean my $onerectitle = shift || ""; my $tablecolumns = shift; #LISTREF my $tabletitle = shift || ""; if (not $onerec){ return maketbl1($hash, $sizehash, $IP, $tablecolumns, $tabletitle); } else { my ( $out, $nmb, $size ) = ("", 0,0); my ( $lout, $lnmb, $lsize); foreach my $key1 (sort keys %{$hash}) { ($lout, $lnmb, $lsize) = maketbl1($hash->{$key1}, defined $sizehash ? $sizehash->{$key1} : undef, $IP, $tablecolumns, undef, "-"); if ($onerectitle) { $out .= "$onerectitle: $key1\n"; $out .= "-" x (2 + length($onerectitle) + length($key1))."\n"; } else { $out .= "$key1\n"; $out .= "-" x (length($key1))."\n"; } $out .= $lout; $nmb += $lnmb; $size += $lsize; } if ($tabletitle) { my $tout = $tabletitle; $tout .= ", ".nTimes($nmb); $tout .= ", ".$size." Bytes" if defined $sizehash; $tout .= "\n"."=" x length($tabletitle)."\n\n"; $out = $tout.$out; } return ($out, $nmb, $size); } } sub max { my $ret = shift; foreach my $val (@_) { $ret = $val if $val > $ret; } return $ret; } sub maketbl1 { my $hash = shift; my $sizehash = shift; my $IP = shift || 0; #boolean my $tablecolumns = shift; #LISTREF my $tabletitle = shift; my $uchar = shift || "="; my @columnmax; my $out = ""; my $inmb = 0; my $size = 0; foreach my $column (@{$tablecolumns}) { push @columnmax, length("$column"); } # Get the max length for column 1, ("main") # column 2, ("number") # column 3, ("size") # TODO: Enhance; max can take any number of arguments, so make use of that # (maybe it turns out to be a bad idea) my %IPhash; foreach my $key1 (keys %{$hash}) { if ($IP) { $IPhash{$key1} = LookupIP(LookupIPv46($key1)); $columnmax[0] = max ($columnmax[0], length($IPhash{$key1})); } else { $columnmax[0] = max ($columnmax[0], length("$key1")); } $columnmax[1] = max ($columnmax[1], length($hash->{$key1})); $inmb += $hash->{$key1}; $columnmax[2] = max ($columnmax[2], length($sizehash->{$key1})) if defined $sizehash; $size += $sizehash->{$key1} if defined $sizehash; } #for last line $columnmax[1] = max $columnmax[1], length $inmb; $columnmax[2] = max $columnmax[2], length $size; if (defined $tabletitle) { $out .= "$tabletitle\n"; $out .= $uchar x length($tabletitle)."\n"; } #first line $out .= " " x ($columnmax[0] - length($tablecolumns->[0])).$tablecolumns->[0]; $out .= " | "; $out .= " " x ($columnmax[1] - length($tablecolumns->[1])).$tablecolumns->[1]; $out .= " | " if defined $sizehash; $out .= " " x ($columnmax[2] - length($tablecolumns->[2])).$tablecolumns->[2] if defined $sizehash; $out .= "\n"; #second line $out .= "-" x $columnmax[0]. " | ". "-" x $columnmax[1]; $out .= " | ". "-" x $columnmax[2] if defined $sizehash; $out .= "\n"; #tablebody foreach my $key1 (sort keys %{$hash}) { my $nmb = $hash->{$key1}; #col1 #whitespace if ($IP) { $out .= " " x ($columnmax[0] - length($IPhash{$key1})); $out .= $IPhash{$key1}; } else { $out .= " " x ($columnmax[0] - length($key1)); $out .= $key1; } $out .= " | "; #col2 $out .= " " x ($columnmax[1] - length($nmb)). $hash->{$key1}; if (defined $sizehash) { $out .= " | ". " " x ($columnmax[2] - length($sizehash->{$key1})).$sizehash->{$key1}; } $out .= "\n"; } #second line (copied from above, if someone has a better idea, tell me.) $out .= "-" x $columnmax[0]. " | ". "-" x $columnmax[1]; $out .= " | ". "-" x $columnmax[2] if defined $sizehash; $out .= "\n"; #last line $out .= " " x ($columnmax[0] + 3 + $columnmax[1] - length($inmb)). $inmb; $out .= " " x ($columnmax[2] + 3 - length($size) ). $size if defined $sizehash; $out .= "\n\n"; return ($out, $inmb, $size); } sub MakeTblReason { my $OrigReason = shift; my $TblReason; if ( (!(( $TblReason) = ( $OrigReason =~ /^(".*?").*/ )) and (!(( $TblReason) = ( $OrigReason =~ /^(.*?): .*/ )))) or !($RemoveAdditionalInfo) ) { $TblReason = $OrigReason; } return $TblReason; } sub nTimes { my $nmb = shift; if ($nmb == 1) { return "1 Time"; } else { return "$nmb Times"; } } if ( $Debug >= 5 ) { print STDERR "\n\nDEBUG: Inside Courier Filter \n\n"; } #List vars here to avoid case-sensitive typos my $AuthdRestart; my $BrokenPipe; my %Connection; my %ConnTimeout; my $ConResetBP; my %Deferred; my %DeSu; my %DeSuSz; my %DeSuTbl; my %DeSuTblSz; my %DfrdTbl; my %ErrorMsgs; my %ErrorTbl; my %ErrorTbl2; my %Failed; my %FailRe; my $From; my $Host; my $ID; my $LastSMTPErrCode; my %Login; my %LoginFailed; my %Logout; my %Logout2; my %LogoutSize; my %LogoutSize2; my $RespawnCourier = 0; my $ShutdownCourier; my $Size; my $SSLstop; my $StartCourier = 0; my $Startpfilter; my $StopCourier = 0; my $Stoppfilter; my $ThisLine; my $To; my $User; my $service; while (defined($ThisLine = )) { chomp $ThisLine; my $Size2 = 0; my $Size = 0; #TODO: Make this more accurate (expand to \d+ times) if ( $ThisLine =~ /^... .. ..:..:.. \S+ last message repeated \d+ times/ ) { $ThisLine = $LastLine; } else { if (not (($service ) = ( $ThisLine =~ /^... .. ..:..:.. \S+ ([^\s:\[\]]+)(?:\[[0-9]+\]|): / ))) { next; } $ThisLine = $'; #$POSTMATCH } if ( ($ThisLine =~ /^Initializing */) or ($ThisLine =~ /^Installing */) or ($ThisLine =~ /^Installed: */) or ($ThisLine =~ /^Installation complete: / ) or ($ThisLine =~ /^stopping authdaemond children/ ) or ($ThisLine =~ /^Started .\/courier.*, pid=.*, maxdels=.*, maxhost=.*, maxrcpt=.*1/ ) or ($ThisLine =~ /^Waiting\. shutdown time=.*, wakeup time=.*, queuedelivering=.*, inprogress=.*/) or ($ThisLine =~ /^Loading STATIC transport module libraries./) or ($ThisLine =~ /^Purging /) or ($ThisLine =~ /^completed,id=/) or ($ThisLine =~ /^queuelo=.*, queuehi=.*/) or # Do we really want to ignore these? # currently i'm too lazy to include this ($ThisLine =~ /^started,ip=.*/) or ##courieresmtpd # example line: # id=00081D7A.3E9E0C51.000037A4,from=,addr=,size=53223,status: success: 1 Time(s) ($ThisLine =~ /id=.*?,from=<.*?>,addr=<.*?>,size=[0-9]*,status:.*/) ##courieresmtp ) { # Don't care about these... } # ESMTP, including all delivery elsif ( $service =~ /^(courierd|courieresmtpd|courieresmtp|courierlocal|courieruucp|courierfax|courierdsn)$/ ){ #First the don't cares if ( $ThisLine =~ /^newmsg,id=/ ) { } elsif ( $ThisLine =~ /started,id=.*?,from=<(.*?)>,module=(.*?),host=(.*?),addr=<(.*?)>/ ) { #Now starting, restarting ... } elsif ( $ThisLine =~ /^Courier .* Copyright/ ) { $StartCourier++; } elsif ( $ThisLine =~ /^SHUTDOWN: respawnlo limit reached/ ) { $RespawnCourier++; } elsif ( $ThisLine =~ /^SHUTDOWN: Stopping.../ ) { $StopCourier++; #Now it's getting interesting } elsif ( ($Host) = ( $ThisLine =~ /^error,relay=([^,]*?),/ ) ) { ##courieresmtpd # example lines: # error,relay=::ffff:209.214.170.188,from=,to=: 513 Relaying denied. # error,relay=::ffff:218.70.112.124,from=: 517 Invalid domain, see # error,relay=::ffff:62.67.54.144,msg="502 ESMTP command error",cmd: DATA $ThisLine = $'; my ( $From ,$To, $Msg ) = (undef, undef, undef); if ( $ThisLine =~ /^ident=[^,]*,/ ) { $ThisLine = $'; } if ( ($From) = ( $ThisLine =~ /^from=<([^<>]*?)>(:?,|)/ )) { $ThisLine = $'; } if (( $To ) = ( $ThisLine =~ /^to=<([^<>]*?)>/ ) ) { $ThisLine = $'; } if (( $Msg ) = ( $ThisLine =~ /^msg=(.*)/ )) { } $ThisLine =~ s/^: //; #Extract it my ($SMTPErrCode) = ($ThisLine =~ /^([0-9]{3})/); # next if already seen if($ThisLine =~ /^[0-9]{3} / and $LastSMTPErrCode == $SMTPErrCode) { $LastSMTPErrCode = 0; next; } #next if already seen but not last line. next if $LastSMTPErrCode == $SMTPErrCode and not defined $Msg; my $Reason = $ThisLine; $Reason = $Msg if defined $Msg; $ErrorMsgs{$Reason}{$Host}{$From || "-"}{$To || "-"}++ if not $Tables; my $TblReason = MakeTblReason($Reason) if $Tables; $ErrorTbl{$TblReason}{$Host}++ if $Tables; $LastSMTPErrCode = $SMTPErrCode; #zero it if done $LastSMTPErrCode = 0 if $ThisLine =~ /^[0-9]{3} / or defined $Msg; } elsif ( ($From, $To, $Size) = ( $ThisLine =~ /^id=.*?,from=<(.*?)>,addr=<(.*?)>,size=([0-9]*),success: .*/ ) ) { ##courieresmtp, courierlocal #example line: #id=00081D7A.3E9E0B39.000036E4,from=,addr=,size=35861,success: delivered: ff.ff.at [111.111.111.111] #DeliverSuccess = DeSu !!!!!!!! $DeSu{$From}{$To}++; $DeSuSz{$From}{$To} += $Size; $DeSuTbl{$To}++; $DeSuTblSz{$To} += $Size; } elsif ( ($ID, $From, $To, my $status) = ( $ThisLine =~ /^id=(.*),from=<(.*?)>,addr=<(.*?)>,status: (deferred|failure)/ ) ) { ##courieresmtp #example lines: deferred, failed delivery attempts #id=00081D03.3E850D34.000076BD,from=,addr=,status: deferred #id=00081D7B.3E9167E7.00002B27,from=,addr=,status: failure my $Reason = $FailRe{$ID}{$From}{$To}; if ($Reason eq "") { $Reason = "-"; } my $TblReason = MakeTblReason($Reason); if ( $status =~ /deferred/ ){ $Deferred{$Reason}{$From}{$To}++; $DfrdTbl{$TblReason}{$To}++; } else { #failure $Failed{$Reason}{$From}{$To}++; $ErrorTbl2{$TblReason}{$To}++; } } elsif ( ($ID, $From, $To, my $Reason) = ( $ThisLine =~ /^id=(.*?),from=<(.*?)>,addr=<(.*?)>:(.*)/ ) ) { ##courierd, courieresmtp #example line: #id=00079ED0.3E8A45E7.000042AF,from=,addr=: Connection timed out #id=00079ED0.3E975385.00005B66,from=,addr=: DNS lookup failed. #This is for the following lines to have the reason for failed or deferred. $FailRe{$ID}{$From}{$To} = $Reason; } elsif ( $ThisLine =~ /^Unexpected SSL connection shutdown./ ) { $SSLstop++; } elsif ( $ThisLine =~ /^writev: Broken pipe/ ) { $BrokenPipe++; } elsif ( $ThisLine =~ /^writev: Connection reset by peer/ ) { $ConResetBP++; } elsif ( ( $Host ) = ( $ThisLine =~ /^\[([^\]]*)\]: Connection timed out/ )) { $ConnTimeout{$Host}++; } else { PushUnmatched $service, $ThisLine; } } elsif ( $service =~ /^authdaemond/ ) { if ( $ThisLine =~ /^modules="[^"]*", daemons=\d*$/ ) { # Ignore } elsif ( $ThisLine =~ /^restarting authdaemond children/ ) { $AuthdRestart++; } else { PushUnmatched $service, $ThisLine; } } elsif ( $service =~ /^submit$/ ) { if ( $ThisLine =~ /^Broken pipe/ ) { $BrokenPipe++; } elsif ( $ThisLine =~ /^Connection reset by peer/ ) { $ConResetBP++; } else { PushUnmatched $service, $ThisLine; } } elsif ( $service =~ /^courierfilter$/ ) { if ( $ThisLine =~ /^Starting perlfilter/ ) { $Startpfilter++; } elsif ( $ThisLine =~ /^Stopping perlfilter/ ) { $Stoppfilter++; } else { PushUnmatched $service, $ThisLine; } } elsif ( $service =~ /^(:?pop3login|imaplogin|courierpop3login|pop3d|pop3d-ssl|imapd|imapd-ssl)$/ ) { my $proto = $service; $proto =~ s/.*pop.*/POP3/i; $proto =~ s/.*imap.*/IMAP/i; if ( ($Host) = ( $ThisLine =~ /^Connection, ip=\[(.*?)\]/ ) ) { ##pop3login, imaplogin, courierpop3login, pop3d, imapd #example line pop3, imapd?? #Connection, ip=[::ffff:192.168.0.24] $Connection{$proto}{$Host}++; } elsif ( ($User, $Host) = ( $ThisLine =~ /^LOGIN, user=(.*?), ip=\[(.*?)\]/ ) ) { ##pop3login, imaplogin, courierpop3login, pop3d, imapd #example line #LOGIN, user=xy, ip=[::ffff:192.168.0.12] $Login{$proto}{$User}{$Host}++; } elsif ( ( ( $User, $Host, $Size) = ( $ThisLine =~ /^LOGOUT, user=(.*?), ip=\[(.*?)\], (?:port=\[\d+\], )?(?:top|headers)=[0-9]*, (?:retr|body)=([0-9]*)/ ) ) || ( ( $User, $Host, $Size, $Size2) = ( $ThisLine =~ /^DISCONNECTED, user=(.*?), ip=\[(.*?)\], headers=([0-9]*?), body=([0-9]*)/ ) ) ) { ###pop3login, imaplogin, courierpop3login, pop3d, imapd #example line #LOGOUT, user=xy, ip=[::ffff:192.168.0.24], top=0, retr=0 #DISCONNECTED, user=zz@uu.ch, ip=[::ffff:192.168.0.1], headers=0, body=1100 $Size += $Size2 if defined $Size2; $Logout{$proto}{$User}{$Host}++; $Logout2{$proto}{$User}++; $LogoutSize{$proto}{$User}{$Host} += $Size; $LogoutSize2{$proto}{$User} += $Size; } elsif ( ($Host) = ( $ThisLine =~ /^LOGIN FAILED, ip=\[(.*?)\]/ ) ) { ## pop3login, imaplogin, courierpop3login, pop3d, imapd #example line #LOGIN FAILED, ip=[::ffff:192.168.200.199] $LoginFailed{$proto}{$Host}++; } else { PushUnmatched $service, $ThisLine; } } else { # Report any unmatched entries... PushUnmatched $service, $ThisLine; } $LastLine = $ThisLine; } if ( ( $Detail >= 5 ) and ($PrintMailQueue ) ) { print "\n\n\nCurrent State of the Mail Queue:\n". "================================\n\n"; my $MailqPath = `which mailq` || "/usr/bin/mailq"; chomp $MailqPath; if (-x $MailqPath) { print `$MailqPath`; print "\n\n"; } } #StartCourier ... if ( $Detail >= 5 ) { my $SelfRestart = $RespawnCourier; print "Courier restarted itself ".nTimes($SelfRestart)."\n" if $SelfRestart; my $HandStart = $StartCourier - $SelfRestart; print "Courier was started by hand (or init) ".nTimes($HandStart)."\n" if $HandStart; my $HandStop = $StopCourier; print "Courier was stopped by hand (or init) ".nTimes($HandStop)."\n" if $HandStop; print "The authdaemon was restarted ".nTimes($AuthdRestart)."\n" if $AuthdRestart; print "\n" if $RespawnCourier + $StartCourier + $StopCourier > 0; } print "Unexpected SSL connection shutdowns: ".nTimes($SSLstop)."\n" if $SSLstop; print "Broken Pipes: ".nTimes($BrokenPipe)."\n" if $BrokenPipe; print "Connection Reset by Peer: ".nTimes($ConResetBP)."\n" if $ConResetBP; if ( keys %ConnTimeout ) { my ($out, $nmb) = recprint1(\%ConnTimeout, 1, [ "Host" ], [1], 2, 2); print "\nConnections timed out: ".nTimes($nmb)."\n"; print $out."\n"; } if ( ( $Detail >= 5 ) and (keys %Connection) and (!$Tables)) { my ($out, $nmb) = recprint1(\%Connection, 2, [ "Protocol", "Host" ], [0,1], 2); print "\nConnections: ".nTimes($nmb)."\n"; print $out."\n"; } if ( ( $Detail >= 5 ) and (keys %Connection) and ($Tables)) { my ( $out, $nmb, $size) = tblprint1(\%Connection, undef, 1, 1, "Connections", [ "Host", "#" ], ""); print $out; } if ( ( $Detail >= 0 ) and (keys %LoginFailed) and ($Tables)) { my ( $out, $nmb, $size) = tblprint1(\%LoginFailed, undef, 1, 1, "Login Failures", [ "Host", "#" ], ""); print "\n".$out; } if ( ( $Detail >= 0 ) and (keys %LoginFailed) and (!$Tables)) { my ($out, $nmb) = recprint1(\%LoginFailed, 2, [ "Protocol", "Host" ], [0,1], 2); print "\nLogin Failed: ".nTimes($nmb)."\n"; print $out."\n"; } if ( ( $Detail >= 5 ) and (keys %Logout2) and ($Tables)) { my ( $out, $nmb, $size) = tblprint1(\%Logout2, \%LogoutSize2, 1, 1, "Logins", [ "Host", "#", "Size" ], ""); print $out; } if ( ( $Detail >= 5 ) and (keys %Logout) and (!$Tables)) { my ($out, $nmb) = recprint1(\%Logout, 3, [ "Protocol", "User", "Host" ], [0,0,1], 2, undef, \%LogoutSize); print "\nLogins: ".nTimes($nmb)."\n"; print $out."\n"; } #Fixme why have login and logout has print 2 login reports -mgt if ( ( $Detail >= 10 ) and (keys %Login) and (!$Tables)) { my ($out, $nmb) = recprint1(\%Login, 3, [ "Protocol", "User", "Host" ], [0,0,1], 2, undef); print "\nSuccessful Logins: ".nTimes($nmb)."\n"; print $out."\n"; } if ( ( $Detail >= 0 ) and (keys %ErrorTbl) and ($Tables)) { my ( $out, $nmb, $size) = tblprint1(\%ErrorTbl, undef, 1, 1, "", [ "Host", "#" ], "Errors in remote to local connections"); print $out; } if ( ( $Detail >= 0 ) and (keys %ErrorMsgs) and (!$Tables) ) { my ($out, $nmb) = recprint1 ( \%ErrorMsgs, 4, [ "because", "Host", "From", "To" ], [0,1,0,0], 2); print "\nErrors in remote to local connections: ".nTimes($nmb)."\n\n"; print "$out\n"; } if ( ( $Detail >= 0 ) and (keys %DfrdTbl) and ($Tables)) { my ( $out, $nmb, $size) = tblprint1(\%DfrdTbl, undef, 1, 0, "", [ "Recipient", "#" ], "Deferred delivery attempts"); print $out; } if ( ( $Detail >= 0 ) and (keys %Deferred) and (!$Tables)) { my ($out, $nmb) = recprint1(\%Deferred, 3, [ "because", "From", "To" ], undef, 2,4); print "\nDeferred delivery attempts: ".nTimes($nmb)."\n"; print $out; } if ( ( $Detail >= 0 ) and (keys %ErrorTbl2) and ($Tables)) { my ( $out, $nmb, $size) = tblprint1(\%ErrorTbl2, undef, 1, 0, "", [ "Recipient", "#" ], "Failed delivery attempts"); print $out; } if ( ( $Detail >= 0 ) and (keys %Failed) and (!$Tables)) { my ($out, $nmb) = recprint1(\%Failed, 3, [ "because", "From", "To" ], undef, 2); print "\nFailed delivery attempts: ".nTimes($nmb)."\n\n"; print "$out\n"; } if ( ( $Detail >= 5 ) and (keys %DeSu) and (!$Tables) ) { my ($out, $nmb, $size) = recprint1 ( \%DeSu, 2, [ "From", "To" ], [0,0], 2, undef, \%DeSuSz); print "\n\nSuccessful deliveries: ".nTimes($nmb).", $size Bytes\n\n"; print "$out\n"; } if ( ( $Detail >= 5 ) and (keys %DeSuTbl) and ($Tables)) { my ( $out, $nmb, $size) = tblprint1(\%DeSuTbl, \%DeSuTblSz, 0, 0, "", [ "Recipient", "#", "Size" ], "Successful deliveries"); print $out; } if (keys %OtherList) { print "\n**Unmatched Entries**\n"; my $out = recprint1( \%OtherList, 2, undef,undef, 2); print "$out\n"; } # vi: shiftwidth=3 tabstop=3 syntax=perl et # Local Variables: # mode: perl # perl-indent-level: 3 # indent-tabs-mode: nil # End: logwatch-7.12/scripts/services/shaperd0000664000211400021140000001172614274101043020333 0ustar logwatchlogwatch ######################################################## # Please file all bug reports, patches, and feature # requests under: # https://sourceforge.net/p/logwatch/_list/tickets # and copy: # Paweł Gołaszewski # Help requests and discusion can be filed under: # https://sourceforge.net/p/logwatch/discussion/ ######################################################## ######################################################## # This was written and is maintained by: # Paweł Gołaszewski ######################################################## ##################################################### ## Copyright (c) 2008 Paweł Gołaszewski ## Covered under the included MIT/X-Consortium License: ## http://www.opensource.org/licenses/mit-license.php ## All modifications and contributions by other persons to ## this script are assumed to have been donated to the ## Logwatch project and thus assume the above copyright ## and licensing terms. If you want to make contributions ## under your own copyright or a different license this ## must be explicitly stated in the contribution an the ## Logwatch project reserves the right to not accept such ## contributions. If you have made significant ## contributions to this script and want to claim ## copyright please contact logwatch-devel@lists.sourceforge.net. ######################################################### use strict; ## Initial initialization: my $DelayIncCount = 0; my $DelayDecCount = 0; my $MaxDelay = 0; my $MinDelay = 0; my $TooOldSoft = 0; #Init String Containers my ( $Delay, $Direction, $Ip ); #Init Hashes my ( %BandwidthControl, %DecreasingDelay, %IncreasingDelay, %OtherList, %RemovingClass, ); while (defined(my $ThisLine = )) { chomp($ThisLine); if ( ($ThisLine =~ m/^upload ip: /) or ($ThisLine =~ m/^download ip: /) or ($ThisLine =~ m/^Delay parameter has too low amount for this number of IP's or possibility of server.$/) or ($ThisLine =~ m/^Dlay parameter has too high amount./) or ($ThisLine =~ m/^starting: LAN Traffic shaper/) or ($ThisLine =~ m/^using IP [^ ]* for [^ ]* (local|internet) interface/) or ($ThisLine =~ m/^running, PID=/) or ($ThisLine =~ m/^divide_upload active/) or ($ThisLine =~ m/^Normal termination./) or ($ThisLine =~ m/^Initialisation finished/) or ($ThisLine =~ m/^HTB3 found - quantum option enabled./) or ($ThisLine =~ m/^HTB Upload Class type activated/) or ($ThisLine =~ m/^HTB Download Class type activated/) or ($ThisLine =~ m/^Continuous traffic control enabled/) ) { #ignore these } elsif ( ($Direction,$Ip) = ($ThisLine =~ /^Can't control ([^ ]*) bandwidth of IP ([^ ]*)$/)) { $BandwidthControl{$Direction}{$Ip}++; } elsif ( ($Direction,$Ip) = ( $ThisLine =~ /^Removing ([^ ]*) class of IP ([^ ]*)$/ ) ) { $RemovingClass{$Direction}{$Ip}++; } elsif ( ($Delay) = ( $ThisLine =~ /^Increasing delay to ([0-9]*) seconds$/) ) { $IncreasingDelay{$Delay}++; $DelayIncCount++; } elsif ( ($Delay) = ( $ThisLine =~ /^Decreasing delay to ([0-9]*) seconds$/) ) { $DecreasingDelay{$Delay}++; $DelayDecCount++; } elsif ( $ThisLine =~ m/^It seems that iproute2 didn't work correctly. Please upgrade your iproute2 and\/or kernel./) { $TooOldSoft++; } else { $OtherList{$ThisLine}++; } } ########################### # Print report: if ($TooOldSoft > 0) { print "\nWarning:\n"; print "Too old or broken iproute2/kernel reported $TooOldSoft Time(s)\n"; } if (keys %IncreasingDelay) { foreach my $Delay (keys %IncreasingDelay) { if ($Delay > $MaxDelay) { $MaxDelay = $Delay; } } print "\nDelay increased $DelayIncCount Time(s) up to $MaxDelay seconds.\n"; } if (keys %DecreasingDelay) { foreach my $Delay (keys %DecreasingDelay) { if ($Delay < $MinDelay) { $MinDelay = $Delay; } } print "\nDelay decreased $DelayDecCount Time(s) to $MinDelay seconds.\n"; } if (keys %BandwidthControl) { print "\nCan't control bandwidth:\n"; foreach my $Direction (sort {$a cmp $b} keys %BandwidthControl) { print " $Direction:\n"; foreach my $Ip (sort {$a cmp $b} keys %{$BandwidthControl{$Direction}}) { print " $Ip : $BandwidthControl{$Direction}{$Ip} Time(s)\n"; } } } if (keys %RemovingClass) { print "\nRemoving class for:\n"; foreach my $Direction (sort {$a cmp $b} keys %RemovingClass) { print " $Direction:\n"; foreach my $Ip (sort {$a cmp $b} keys %{$RemovingClass{$Direction}}) { print " $Ip : $RemovingClass{$Direction}{$Ip} Time(s)\n"; } } } if (keys %OtherList) { print "\n**Unmatched Entries**\n"; foreach my $line (sort {$a cmp $b} keys %OtherList) { print "$line: $OtherList{$line} Time(s)\n"; } } exit(0); # vi: shiftwidth=3 tabstop=3 syntax=perl et # Local Variables: # mode: perl # perl-indent-level: 3 # indent-tabs-mode: nil # End: logwatch-7.12/scripts/services/imapd0000664000211400021140000003142514274101037020000 0ustar logwatchlogwatch ######################################################## # Please file all bug reports, patches, and feature # requests under: # https://sourceforge.net/p/logwatch/_list/tickets # Help requests and discusion can be filed under: # https://sourceforge.net/p/logwatch/discussion/ ######################################################## ######################################################## # The imap script was written by: # Paweł Gołaszewski ######################################################## ##################################################### ## Copyright (c) 2008 Paweł Gołaszewski ## Covered under the included MIT/X-Consortium License: ## http://www.opensource.org/licenses/mit-license.php ## All modifications and contributions by other persons to ## this script are assumed to have been donated to the ## Logwatch project and thus assume the above copyright ## and licensing terms. If you want to make contributions ## under your own copyright or a different license this ## must be explicitly stated in the contribution an the ## Logwatch project reserves the right to not accept such ## contributions. If you have made significant ## contributions to this script and want to claim ## copyright please contact logwatch-devel@lists.sourceforge.net. ######################################################### use strict; my $Debug = $ENV{'LOGWATCH_DEBUG'}; my $Detail = $ENV{'LOGWATCH_DETAIL_LEVEL'}; if ( $Debug >= 5 ) { print STDERR "\n\nDEBUG \n\n"; } #Init String Containers my ( $Conns, $CountLength, $CountSpaceLength, $Down, $DownLength, $DownSpaceLength, $HostCount, $HostLength, $HostSpaceLength, $NonSSLCount, $NonSSLLength, $NonSSLSpaceLength, $SSL, $SSLCount, $SSLLength, $SSLSpaceLength, $Size, $SizeLength, $SizeSpaceLength, $TotalCount, $TotalLength, $TotalSpaceLength, $UserLength, $UserSpaceLength, $totalSpaceLength, $DownloadSize1, $DownloadSize2, $Host, $Num, $Reason, $User, ); #Init Hashes my ( %AutoLogout, %Connection, %ConnectionNonSSL, %ConnectionSSL, %DownloadedMessagesSize, %KilledSession, %Login, %LoginFailed, %Logout, %Logout2, %OtherList, %SocketErrors ); while (defined(my $ThisLine = )) { if ( ($ThisLine =~ /^Initializing */) or ($ThisLine =~ /^spgetpwnam: can't find user: */) or ($ThisLine =~ /^couriertls: read: Connection reset by peer/ ) or # timeouts are reported in some other scripts - maybe it should be here too? ($ThisLine =~ /^couriertls: read: Connection timed out/ ) or ($ThisLine =~ /^LOGOUT, ip=\[.*\], rcvd=\d+, sent=\d+$/) or ($ThisLine =~ /^Disconnected, ip=\[.*\]/) or # uw-imapd ($ThisLine =~ /^Moved \d+ bytes of new mail to.*$/) or ($ThisLine =~ /^Unexpected client disconnect, while reading line.*$/) or ($ThisLine =~ /^ip=\[.*\], An unexpected TLS packet was received.*$/) or ($ThisLine =~ /^ip=\[.*\], Unexpected SSL connection shutdown.*$/) ) { # Don't care about these... } elsif ( ($User, $Host) = ( $ThisLine =~ /^Login user=(.*?) host=(.*\[.*\])$/ ) ) { $Login{$User}{$Host}++; } elsif ( ($User, $Host) = ( $ThisLine =~ /^LOGIN, user=(.*?), ip=\[([^ ,]+)\](?:, port=\[\d+\])?, protocol=IMAP$/o ) ) { $Login{$User}{$Host}++; } elsif ( ($User,$Host) = ( $ThisLine =~ /^Authenticated user=(.*) host=(.*\[.*\]).*$/ ) ) { $Login{$User}{$Host}++; } elsif ( ($User,$Host) = ( $ThisLine =~ /^Preauthenticated user=(.*) host=(.*)$/ ) ) { $Login{$User}{$Host}++; } elsif ( ($Host) = ( $ThisLine =~ /^imap service init from (.*)$/ ) ) { $ConnectionNonSSL{$Host}++; $Connection{$Host}++; } elsif ( ($Host) = ( $ThisLine =~ /^imaps SSL service init from (.*)$/ ) ) { $ConnectionSSL{$Host}++; $Connection{$Host}++; } elsif ( ($Host) = ( $ThisLine =~ /^Connection, ip=\[(.*)\]$/o ) ) { $Connection{$Host}++; } elsif ( ($Num, $Host) = ( $ThisLine =~ /^message repeated (.*) times: \[ Connection, ip=\[(.*)\]$/o ) ) { $Connection{$Host} += $Num; # } elsif ( ($User,$Downloaded,$DownloadSize,$Left,$LeftSize) = ( $ThisLine =~ /^Stats: (.*?) (.*?) (.*?) (.*?) (.*?)$/) ) { # $DownloadedMessages{$User} += $Downloaded; # $DownloadedMessagesSize{$User} += $DownloadSize; # $MessagesLeft{$User} = $Left; # $MboxSize{$User} = $LeftSize; # } elsif ( ($User,$Host) = ( $ThisLine =~ /^authentication failed for user (.*?) - (.*)/ ) ) { # $LoginFailed{"$Host ($User)"}++; } elsif ( ($User, $Host) = ( $ThisLine =~ /^Logout user=(.*?) host=(.*\[.*\])$/) ) { $Logout{$User}{$Host}++; $Logout2{$User}++; # More generic pattern for uw-imapd } elsif ( ($User, $Host) = ( $ThisLine =~ /^Logout user=(.*?) host=(.*)$/) ) { $Logout{$User}{$Host}++; $Logout2{$User}++; } elsif ( ($User, $Host, $DownloadSize1, $DownloadSize2) = ( $ThisLine =~ /^(?:LOGOUT|TIMEOUT|DISCONNECTED), user=(.*?), ip=\[([^ ,]+)\](?:, port=\[\d+\])?, headers=(\d+), body=(\d+)/o ) ) { $Logout{$User}{$Host}++; $Logout2{$User}++; $DownloadedMessagesSize{$User} += $DownloadSize1 + $DownloadSize2; if ( ( $ThisLine =~ /, starttls=1/o ) ) { $ConnectionSSL{$Host}++; } else { $Connection{$Host}++; } } elsif ( ($User,$Host) = ( $ThisLine =~ /^Autologout user=(.*) host=(.*\[.*\])$/ ) ) { $AutoLogout{$User}{$Host}++; $Logout{$User}{$Host}++; $Logout2{$User}++; } elsif ( ($Reason,$User,$Host) = ( $ThisLine =~ /^Killed (.*) user=(.*) host=(.*\[.*\])$/ ) ) { $Logout{$User}{$Host}++; $Logout2{$User}++; $KilledSession{$User}{$Reason}++; } elsif ( ( ($User,$Host) = ( $ThisLine =~ /^Broken pipe, while reading line user=(.*) host=(.*\[.*\])$/ )) or ( ($User,$Host) = ( $ThisLine =~ /^Command stream end of file, while reading line user=(.*) host=(.*\[.*\])$/ )) or ( ($User,$Host) = ( $ThisLine =~ /^Connection (?:reset by peer|timed out), while reading line user=(.*) host=(.*\[.*\])$/ )) or ( ($User,$Host) = ( $ThisLine =~ /^No route to host, while reading line user=(.*) host=(.*\[.*\])$/ )) or ( ($User,$Host) = ( $ThisLine =~ /^Unexpected client disconnect, while reading line user=(.*) host=(.*\[.*\])$/ )) ) { $Logout{$User}{$Host}++; $Logout2{$User}++; $SocketErrors{$Host}++; } elsif ( (( $ThisLine =~ /^.*error:1408F10B:SSL routines:SSL3_GET_RECORD:wrong version number.*$/)) or (( $ThisLine =~ /^.*error:1408A0C1:SSL routines:SSL3_GET_CLIENT_HELLO:no shared cipher.*$/)) ) { $SocketErrors{'unknown'}++; } else { # Report any unmatched entries... # remove PID from named messages $ThisLine =~ s/^(client [.0-9]+)\S+/$1/; chomp($ThisLine); $OtherList{$ThisLine}++; } } ################################################ if ( ( $Detail >= 0 ) and (keys %LoginFailed)) { print "\n\n[IMAPd] Login failures:". "\n=========================". "\n Host (user) | # ". "\n------------------------------------------------------------- | -----------"; my $ConnCount = 0; foreach my $Host (sort keys %LoginFailed) { $Conns = $LoginFailed{$Host}; $HostLength = length($Host); $HostSpaceLength = 61 - $HostLength; $CountLength = length("$Conns"); $CountSpaceLength = 12 - $CountLength; print "\n" ." " x $HostSpaceLength . $Host . " |" . " " x $CountSpaceLength . $Conns . ""; $ConnCount += $Conns; } $CountLength = length("$ConnCount"); $CountSpaceLength = 75 - $CountLength; print "\n" . "-" x 75; print "\n" . " " x $CountSpaceLength . "$ConnCount\n\n\n"; } if ( ( $Detail >= 5 ) and (keys %Connection)) { print "\n[IMAPd] Connections:". "\n=========================". "\n Host | Connections | SSL | Total ". "\n-------------------------------------- | ----------- | -------- | ---------"; my $ConnCount = 0; foreach my $Host (sort keys %Connection) { my $Total = $Connection{$Host}; if (defined ($ConnectionNonSSL{$Host})) { $Conns = $ConnectionNonSSL{$Host}; } else { $Conns = 0; } if (defined ($ConnectionSSL{$Host})) { $SSL = $ConnectionSSL{$Host}; } else { $SSL = 0; } $HostLength = length($Host); $HostSpaceLength = 38 - $HostLength; $CountLength = length("$Conns"); $CountSpaceLength = 12 - $CountLength; $SSLLength = length("$SSL"); $SSLSpaceLength = 9 - $SSLLength; $TotalLength = length("$Total"); $TotalSpaceLength = 10 - $TotalLength; print "\n" ." " x $HostSpaceLength . $Host . " |" . " " x $CountSpaceLength . $Conns . " |" . " " x $SSLSpaceLength . $SSL . " |" . " " x $TotalSpaceLength . $Total; $NonSSLCount += $Conns; $SSLCount += $SSL; $TotalCount += $Total; } $NonSSLLength = length("$NonSSLCount"); $NonSSLSpaceLength = 52 - $NonSSLLength; $SSLLength = length("$SSLCount"); $SSLSpaceLength = 9 - $SSLLength; $TotalLength = length("$TotalCount"); $totalSpaceLength = 10 - $TotalLength; print "\n" . "-" x 75; print "\n" . " " x $NonSSLSpaceLength . $NonSSLCount . " |" . " " x $SSLSpaceLength . $SSLCount . " |" . " " x $totalSpaceLength . $TotalCount . "\n\n\n"; } if (keys %Logout2) { print "\n[IMAPd] Logout stats:". "\n====================". "\n User | Logouts | Downloaded | Mbox Size". "\n--------------------------------------- | ------- | ---------- | ----------"; my $ConnCount = 0; my $SizeAll = 0; my $DownAll = 0; foreach my $User (sort keys %Logout2) { $Conns = $Logout2{$User}; $UserLength = length($User); $UserSpaceLength = 39 - $UserLength; $CountLength = length("$Conns"); $CountSpaceLength = 8 - $CountLength; $Down = $DownloadedMessagesSize{$User}; if (! defined $Down) { $Down = 0; #Hack } $DownSpaceLength = 11 - length($Down); #$Size = $MboxSize{$User}; $Size = 0; #Hack $SizeSpaceLength = 11 - length($Size); print "\n" ." " x $UserSpaceLength . $User . " |" . " " x $CountSpaceLength . $Conns . " |" . " " x $DownSpaceLength . $Down . " |" . " " x $SizeSpaceLength . $Size; $ConnCount += $Conns; $SizeAll += $Size; $DownAll += $Down; } $CountLength = length("$ConnCount"); $CountSpaceLength = 49 - $CountLength; $DownLength = length($DownAll); $DownSpaceLength = 11 - $DownLength; $SizeLength = length($SizeAll); $SizeSpaceLength = 11 - $SizeLength; print "\n" . "-" x 75; print "\n" . " " x $CountSpaceLength . "$ConnCount" . " |" . " " x $DownSpaceLength . $DownAll . " |" . " " x $SizeSpaceLength . $SizeAll . "\n\n\n"; } if ( ( $Detail >= 10 ) and (keys %Login)) { print "\n[IMAPd] Successful Logins:\n"; my $LoginCount = 0; foreach my $User (sort keys %Login) { print " User $User: \n"; my $UserCount = 0; foreach my $Host (keys %{$Login{$User}}) { $HostCount = $Login{$User}{$Host}; print " From $Host: $HostCount Time(s)\n"; $UserCount += $HostCount; } $LoginCount += $UserCount; print " Total $UserCount Time(s)\n"; print "\n"; } print "Total $LoginCount successful logins\n\n"; } if ( ( $Detail >= 10 ) and (keys %AutoLogout)) { print "\nAutologout:\n"; foreach my $User (sort {$a cmp $b} keys %AutoLogout) { print " $User:\n"; foreach my $Host (sort {$a cmp $b} keys %{$AutoLogout{$User}}) { print " $Host: $AutoLogout{$User}{$Host} Time(s)\n"; } } } if ( ( $Detail >= 10 ) and (keys %KilledSession)) { print "\nKilled IMAP sessions:\n"; foreach my $User (sort {$a cmp $b} keys %KilledSession) { print " $User:\n"; foreach my $Reason (sort {$a cmp $b} keys %{$KilledSession{$User}}) { print " $Reason: $KilledSession{$User}{$Reason} Time(s)\n"; } } } if ( ( $Detail >= 10 ) and (keys %SocketErrors)) { print "\nSocket Errors in connections with:\n"; foreach my $Host (sort {$a cmp $b} keys %SocketErrors) { print " $Host: $SocketErrors{$Host} Time(s)\n"; } } if (keys %OtherList) { print "\n**Unmatched Entries**\n"; foreach my $line (sort {$a cmp $b} keys %OtherList) { print " $line: $OtherList{$line} Time(s)\n"; } } exit(0); # vi: shiftwidth=3 tabstop=3 syntax=perl et # Local Variables: # mode: perl # perl-indent-level: 3 # indent-tabs-mode: nil # End: logwatch-7.12/scripts/services/dnf-automatic0000664000211400021140000000434414723234714021451 0ustar logwatchlogwatch ######################################################### # Please file all bug reports, patches, and feature # requests under: # https://sourceforge.net/p/logwatch/_list/tickets # Help requests and discusion can be filed under: # https://sourceforge.net/p/logwatch/discussion/ ######################################################### ######################################################### ## Copyright (c) 2024 Clive Lin ## Covered under the included MIT/X-Consortium License: ## http://www.opensource.org/licenses/mit-license.php ## All modifications and contributions by other persons to ## this script are assumed to have been donated to the ## Logwatch project and thus assume the above copyright ## and licensing terms. If you want to make contributions ## under your own copyright or a different license this ## must be explicitly stated in the contribution an the ## Logwatch project reserves the right to not accept such ## contributions. If you have made significant ## contributions to this script and want to claim ## copyright please contact logwatch-devel@lists.sourceforge.net. ######################################################### use strict; my @DnfAutoLogs = (); my $DebugCounter = 0; my $Debug = $ENV{'LOGWATCH_DEBUG'} || 0; my $always_show_dnf_last_check = $ENV{'always_show_dnf_last_check'} || 0; my $ThisLine; if ( $Debug >= 5 ) { print STDERR "\n\nDEBUG: Inside DNF-AUTOMATIC Filter \n\n"; $DebugCounter = 1; } while (defined($ThisLine = )) { if ( $Debug >= 5 ) { print STDERR "DEBUG($DebugCounter): $ThisLine"; $DebugCounter++; } # no special filter for "Last metadata expiration check: ..." # it seems to be the first and only one line # when Range=today or Range=yesterday # but when Range=all, it's a different situation. push @DnfAutoLogs,$ThisLine; } if ( ($#DnfAutoLogs eq 0) && ($always_show_dnf_last_check)) { # instead, check if there's only one line. # skip this line unless $always_show_dnf_last_check print @DnfAutoLogs; } elsif ($#DnfAutoLogs > 0) { # if more then one line, print all print @DnfAutoLogs; } exit(0); # vi: shiftwidth=3 tabstop=3 syntax=perl et # Local Variables: # mode: perl # perl-indent-level: 3 # indent-tabs-mode: nil # End: logwatch-7.12/scripts/services/zz-lm_sensors0000664000211400021140000000642214743365006021543 0ustar logwatchlogwatch ######################################################## # Please file all bug reports, patches, and feature # requests under: # https://sourceforge.net/p/logwatch/_list/tickets # Help requests and discusion can be filed under: # https://sourceforge.net/p/logwatch/discussion/ ######################################################## ########################################################################## # Copyright (c) 2013 gulikoza # Covered under the included MIT/X-Consortium License: # http://www.opensource.org/licenses/mit-license.php # Permission is hereby granted, free of charge, to any person obtaining a # copy of this software and associated documentation files (the "Software"), # to deal in the Software without restriction, including without limitation # the rights to use, copy, modify, merge, publish, distribute, sublicense, # and/or sell copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. # IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY # CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ########################################################################### #Main use strict; #use warnings; #Exit early if undesired exit 0 unless $ENV{LOGWATCH_DETAIL_LEVEL} || $ENV{PRINTING} && $ENV{PRINTING} eq 'y'; #Exit early if the report is not for the current host. if( $ENV{LOGWATCH_ONLY_HOSTNAME} ) { my $hostname = $ENV{HOSTNAME}; # see scripts/logwatch.pl, line 702! $hostname ||= do { require POSIX; ( POSIX::uname() )[1]; }; # fallback ;-) # "ONLY_HOSTNAME" is a misnomer, as it is actually defined as "hostlimit" # @ scripts/logwatch.pl, line 702 # which is a list of hosts, per scripts/logwatch.pl, line 1131 # so, actually bailout if "current host" is NOT included in this list. my $found = 0; for my $wanted ( split /[,]/, $ENV{LOGWATCH_ONLY_HOSTNAME} ) { my $match_to = $hostname; # shorten only if that's also short if( -1 == index( $wanted, '.' ) ) { $match_to =~ s/[.].*//; } if( $wanted eq $match_to ) { $found = 1; last; } } exit 0 if !$found; } #Exit early if running in some virtual environment my $kvm = 0; if( $ENV{get_kvm_status} ) { $kvm = qx($ENV{get_kvm_status}); } else { if( open my $fh, '<', '/proc/cpuinfo' ) { while( my $line = <$fh> ) { next if -1 == index( $line, 'QEMU Virtual CPU' ); $kvm = 1; last; } close $fh; } } exit 0 if $kvm; #Output sensors stats for my $exe ( $ENV{pathto_sensors}, '/usr/bin/sensors' ) { if( defined $exe && -x $exe ) { my $sensors = qx($exe); if ($sensors) { print $sensors; } } } # vi: shiftwidth=4 tabstop=4 syntax=perl expandtab logwatch-7.12/scripts/services/eximstats0000664000211400021140000000422614743365004020735 0ustar logwatchlogwatch ######################################################## # Please file all bug reports, patches, and feature # requests under: # https://sourceforge.net/p/logwatch/_list/tickets # and copy: # jeff.frost@frostconsultingllc.com # Help requests and discusion can be filed under: # https://sourceforge.net/p/logwatch/discussion/ ######################################################## ########################################################################## # This is a wrapper for the eximstats program ######################################################## ######################################################## ## Copyright (c) 2008 Jeff Frost ## Covered under the included MIT/X-Consortium License: ## http://www.opensource.org/licenses/mit-license.php ## All modifications and contributions by other persons to ## this script are assumed to have been donated to the ## Logwatch project and thus assume the above copyright ## and licensing terms. If you want to make contributions ## under your own copyright or a different license this ## must be explicitly stated in the contribution an the ## Logwatch project reserves the right to not accept such ## contributions. If you have made significant ## contributions to this script and want to claim ## copyright please contact logwatch-devel@lists.sourceforge.net. ######################################################### use Logwatch ':all'; use strict; my $Debug = $ENV{'LOGWATCH_DEBUG'} || 0; my $Detail = $ENV{'LOGWATCH_DETAIL_LEVEL'} || 0; my $DebugCounter = 0; my $SearchDate = TimeFilter("%Y-%m-%d %H:%M:%S"); if ( $Debug >= 5 ) { print STDERR "\n\nDEBUG: Inside eximstats Filter \n\n"; $DebugCounter = 1; } #Should probably verify the ENV variable -mgt open(EXIMSTATS,"| $ENV{'eximstats'}"); while (defined(my $ThisLine = )) { next unless $ThisLine =~ /^$SearchDate /o; if ( $Debug >= 5 ) { print STDERR "DEBUG($DebugCounter): $ThisLine"; $DebugCounter++; } print EXIMSTATS $ThisLine; } close EXIMSTATS; exit(0); # vi: shiftwidth=3 tabstop=3 syntax=perl et # Local Variables: # mode: perl # perl-indent-level: 3 # indent-tabs-mode: nil # End: logwatch-7.12/scripts/services/pop30000664000211400021140000004015514743365004017576 0ustar logwatchlogwatch ######################################################## # Please file all bug reports, patches, and feature # requests under: # https://sourceforge.net/p/logwatch/_list/tickets # Help requests and discusion can be filed under: # https://sourceforge.net/p/logwatch/discussion/ ######################################################## ######################################################## # The pop-3 script was written by: # Paweł Gołaszewski ######################################################## ####################################################### ## Copyright (c) 2008 Paweł Gołaszewski ## Covered under the included MIT/X-Consortium License: ## http://www.opensource.org/licenses/mit-license.php ## All modifications and contributions by other persons to ## this script are assumed to have been donated to the ## Logwatch project and thus assume the above copyright ## and licensing terms. If you want to make contributions ## under your own copyright or a different license this ## must be explicitly stated in the contribution an the ## Logwatch project reserves the right to not accept such ## contributions. If you have made significant ## contributions to this script and want to claim ## copyright please contact logwatch-devel@lists.sourceforge.net. ######################################################### use strict; my $Debug = $ENV{'LOGWATCH_DEBUG'}; my $Detail = $ENV{'LOGWATCH_DETAIL_LEVEL'}; #Init Counters my $ReadSocketError = 0; my $WriteSocketError = 0; my $Startups = 0; my $Shutdowns = 0; my $AuthDrivers = 0; my $sslTempkey = 0; my $OutOfMemory = 0; #Init String Containers my ( $Box, $DownloadSize, $DownloadSize1, $DownloadSize2, $Downloaded, $Drivers, $File, $Host, $Iface, $Left, $LeftSize, $Listen, $Mbox, $Mechanism, $Size, $User, $dummy ); #Init Hashes my ( %AutoLogout, %Connect, %Connection, %DamagedMbox, %DownloadedMessages, %DownloadedMessagesSize, %ListenOn, %Login, %LoginFailed, %Logout, %Logout2, %MboxSize, %MessagesLeft, %NoApopSecret, %OtherList, %PermissionDenied, %sslMechanism ); #Make pseudo IPv6 to IPv4 sub LookupIPv46 { my $IPv4Addr; my $Addr = $_[0]; if ( ($IPv4Addr) = ($Addr =~ /::ffff:([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})/ ) ) { return $IPv4Addr; } else { return $Addr; } } if ( $Debug >= 5 ) { print STDERR "\n\nDEBUG \n\n"; } while (defined(my $ThisLine = )) { if ( ($ThisLine =~ /^auth: PAM error: Authentication failure$/) or ($ThisLine =~ /^authcontext_new_user_pass: began session for/) or ($ThisLine =~ /^cclient_steal_lock: attempting to grab c-client lock from PID \d+$/) or ($ThisLine =~ /^getpeername: Socket operation on non-socket$/) or ($ThisLine =~ /^Initializing */) or ($ThisLine =~ /^Installing */) or ($ThisLine =~ /^ioabs_tcp_post_select: client .*: connection closed by peer$/) or ($ThisLine =~ /^listener_new: (.*:\d+): cannot obtain domain suffix for this address$/) or ($ThisLine =~ /^listener_new: (.*:\d+): using fallback domain suffix `(.*)'$/) or ($ThisLine =~ /^listener_new: gethostbyaddr\((.*)\): cannot resolve name$/) or ($ThisLine =~ /^(mailbox: )?open: No such file or directory$/) or ($ThisLine =~ /^(sktbuff|maildrop): write: Broken pipe$/) or ($ThisLine =~ /^maildrop: can't read message$/) or ($ThisLine =~ /^mailbox: mailbox content has been changed$/) or ($ThisLine =~ /^(sktbuff|maildrop): write: Connection reset by peer$/) or ($ThisLine =~ /^(sktbuff|maildrop): write: Connection timed out$/) or ($ThisLine =~ /^mailspool_build_index.*: skipping c-client metadata$/) or ($ThisLine =~ /^open: Permission denied$/) or ($ThisLine =~ /^read: Broken pipe$/) or ($ThisLine =~ /^read: Connection reset by peer$/) or ($ThisLine =~ /^spgetpwnam: can't find user: */) or ($ThisLine =~ /^sptls: SSL_accept error: (-|)\d+$/) or ($ThisLine =~ /^sptls: do need at least RSA or DSA cert\/key data$/) or ($ThisLine =~ /^tpop3d shutdown succeeded$/) or ($ThisLine =~ /tpop3d startup succeeded$/) or ($ThisLine =~ /^disconnected, user=/i) or ($ThisLine =~ /^timeout, user=/i) or ($ThisLine =~ /^(connection|disconnected), ip=/io) ) { # Don't care about these... } elsif ( (($User, $Host) = ( $ThisLine =~ /^user (.*?) authenticated - (.*)$/ )) or (($User, $Host) = ( $ThisLine =~ /^fork_child: \[\d\].*\((.*)\): began session for `(.*)' with .*; child PID is \d+$/ )) or (($User, $Host) = ( $ThisLine =~ /^LOGIN, user=([^ ,]+), ip=\[([^ ,]+)\](?:, port=\[\d+\](?:, stls=\d+)?)?$/ )) ) { $Login{$User}{$Host}++; } elsif ( ($User,$Downloaded,$DownloadSize,$Left,$LeftSize) = ( $ThisLine =~ /^Stats: (.*?) (.*?) (.*?) (.*?) (.*?)$/) ) { $DownloadedMessages{$User} += $Downloaded; $DownloadedMessagesSize{$User} += $DownloadSize; $MessagesLeft{$User} = $Left; $MboxSize{$User} = $LeftSize; } elsif ( ($User, $Host) = ( $ThisLine =~ /^session ended for user (.*?) - (.*)/) ) { $Logout{$User}{$Host}++; $Logout2{$User}++; $Connection{$Host}++; } elsif ( ($Host) = ( $ThisLine =~ /^session ended - (.*)$/) or ($Host) = ( $ThisLine =~ /^LOGOUT, ip=\[(.*)\]$/) ) { $Logout{"UNKNOWN"}{$Host}++; $Connection{$Host}++; } elsif ( (($User,$Host,$DownloadSize,undef) = ( $ThisLine =~ /^connections_post_select: client \[\d+\](.*)\((.*)\): disconnected; (.*?)\/(.*?) bytes read\/written$/) ) or (($Host,$User) = ( $ThisLine =~ /^connections_post_select: client \[\d\].*\((.*)\): finished session for `(.*)' with pam/) ) ) { $DownloadedMessagesSize{$User} += $DownloadSize; $Logout{$User}{$Host}++; $Logout2{$User}++; $Connection{$Host}++; } elsif (($dummy, $User, $Host, $DownloadSize1, $DownloadSize2) = ( $ThisLine =~ /^(LOGOUT|TIMEOUT|DISCONNECTED), user=(.*?), ip=\[([^ ,]+)\](?:, port=\[\d+\])?, top=(\d+), retr=(\d+)/o)) { $DownloadedMessagesSize{$User} += $DownloadSize1 + $DownloadSize2; $Logout{$User}{$Host}++; $Logout2{$User}++; $Connection{$Host}++; if ( $ThisLine =~ /^(TIMEOUT|DISCONNECTED),/o ) { $AutoLogout{$Host}++; } } elsif (($Host) = ( $ThisLine =~ /^connections_post_select: client \[\d\](.*)\/.*: disconnected; \d+\/\d+ bytes read\/written$/) ) { $Connection{$Host}++; } elsif ( (($User,$Host) = ( $ThisLine =~ /^authentication failed for user (.*?) - (.*)/ )) or (($Host,$User) = ( $ThisLine =~ /^connection_do: client `\[\d+\](.*)\/.*': username `(.*)': \d authentication failures/ )) ) { $LoginFailed{"$Host ($User)"}++; } elsif (($User,$Host) = ( $ThisLine =~ /^LOGIN FAILED, user=([^,]*), ip=\[([0-9.:a-f]*)\]/ )) { $Host = LookupIPv46($Host); $LoginFailed{"$Host ($User)"}++; } elsif ( ($User,$Host) = ( $ThisLine =~ /^authentication failed: no such user: (.*?) - (.*)/ ) ) { $LoginFailed{"$Host (UNKNOWN: $User)"}++; } elsif ( ($User) = ( $ThisLine =~ /^auth_pam_new_user_pass: pam_authenticate\((.*)\): Authentication failure/) ){ $LoginFailed{$User}++; } elsif ( ($User) = ( $ThisLine =~ /^authcontext_new_user_pass: rejecting login attempt by `(.*)' with empty password$/) ) { $LoginFailed{"EMPTY PASSWORD: $User"}++; } elsif ( ($Mechanism) = ( $ThisLine =~ /^sptls: TLS connection established: (.*)$/ ) ) { $sslMechanism{$Mechanism}++; } elsif ($ThisLine =~ /^sptls: created \d+bit temporary [^ ].* key$/ ) { $sslTempkey++; } elsif ( ($User,$Host) = ( $ThisLine =~ /^ioabs_tls_shutdown: client \[\d\](.*)\((.*)\): underlying connection closed by peer during shutdown$/) ) { # FIXME: # What to with that?? } elsif ( (($Host) = ( $ThisLine =~ /^autologout time elapsed - (.*)$/ )) or (($Host) = ( $ThisLine =~ /^net_loop: timed out client \[\d\](.*)\// )) or (($Host) = ( $ThisLine =~ /^net_loop: timed out client \[\d\].*\((.*)\)$/ )) ) { $AutoLogout{$Host}++; } elsif ( (($File) = ( $ThisLine =~ /^can't open or create file: (.*)$/ )) or (($File) = ( $ThisLine =~ /^mailbox: can't open mailbox file: (.*)$/ )) ) { $PermissionDenied{$File}++; } elsif ( ($User, $Host) = ( $ThisLine =~ /^can't find APOP secret for user (.*?) - (.*)$/ ) ) { $NoApopSecret{$User}++; $Logout{$User}{$Host}++; $Connection{$Host}++; $Logout2{$User}++; } elsif ($ThisLine =~ /^mailbox: no memory available$/ ) { $OutOfMemory++; } elsif ( ($Mbox) = ( $ThisLine =~ /^mailbox: mailbox (.*) is damaged$/ ) or ($Mbox) = ( $ThisLine =~ /^mailbox: mailbox is damaged: (.*)$/ ) ) { $DamagedMbox{$Mbox}++; } elsif ( ($ThisLine =~ /^(sktbuff|maildrop): can't read from socket$/) or ($ThisLine =~ /^ioabs_tls_read: client .*: connection closed by peer$/) or ($ThisLine =~ /^(ioabs_tls_read|ioabs_tls_post_select): client .*: connection unexpectedly closed by peer$/) ) { $ReadSocketError++; } elsif ($ThisLine =~ /^(sktbuff|maildrop): can't write to socket$/ ) { $WriteSocketError++; } elsif ( ($Box,$Size) = ( $ThisLine =~ /^mailspool_new_from_file: indexed mailspool (.*) \((\d+) bytes\) in/ ) ) { # What to do with that? #$MboxSize{$User} = $LeftSize; } elsif ( ($Host,$Iface) = ( $ThisLine =~ /^listeners_post_select: client \[\d\](.*)\/.*: connected to local address (.*:\d+)$/ ) ) { $Connection{$Host}++; $Connect{$Iface}{$Host}++; } elsif ( ($Listen) = ( $ThisLine =~ /^parse_listeners: listening on address (.*)$/ ) ) { $ListenOn{$Listen}++; } elsif ($ThisLine =~ /^net_loop: tpop3d version \d+\.\d+\.\d+ successfully started$/ ) { $Startups++; } elsif ($ThisLine =~ /^net_loop: terminating on signal \d+$/ ) { $Shutdowns++; } elsif ( ($Drivers) = ($ThisLine =~ /^(\d+) authentication drivers successfully loaded$/) ) { $AuthDrivers = $Drivers; } else { # Report any unmatched entries... # remove PID from named messages $ThisLine =~ s/^(client [.0-9]+)\S+/$1/; chomp($ThisLine); $OtherList{$ThisLine}++; } #$LastLine = $ThisLine; } ################################################ if ($Startups > 0) { print "Startups: $Startups"; if ($AuthDrivers > 0) { print " with $AuthDrivers authentication drivers\n"; } else { print "\n"; } if (keys %ListenOn) { print "Listening on:\n"; foreach my $Listen (sort {$a cmp $b} keys %ListenOn) { print " $Listen\n"; } } } if ($Shutdowns > 0) { print "\nShutdowns: $Shutdowns\n"; } if ( ( $Detail >= 0 ) and (keys %PermissionDenied)) { print "WARNING:\n"; print "Can't open or create files:\n"; foreach my $File (sort {$a cmp $b} keys %PermissionDenied) { print " $File: $PermissionDenied{$File} Time(s)\n"; } } if ( ( $Detail >= 0 ) and (keys %DamagedMbox)) { print "WARNING:\n"; print "Damaged mailbox in your system:\n"; foreach my $Mbox (sort {$a cmp $b} keys %DamagedMbox) { print " $Mbox: $DamagedMbox{$Mbox} Time(s)\n"; } } if ( ( $Detail >= 0 ) and (keys %DamagedMbox)) { print "WARNING:\n"; print "Damaged mailbox in your system:\n"; foreach my $Mbox (sort {$a cmp $b} keys %DamagedMbox) { print " $Mbox: $DamagedMbox{$Mbox} Time(s)\n"; } } if ( ( $Detail >= 0 ) and ($OutOfMemory > 0) ) { print "\nPOP3 processes were running out of memory $OutOfMemory Time(s)\n"; } if ( ( $Detail >= 0 ) and (keys %LoginFailed)) { print "\n\n[POP3] Login failures:". "\n=========================". "\n Host (user) | # ". "\n------------------------------------------------------------- | -----------"; my $ConnCount = 0; foreach my $Host (sort keys %LoginFailed) { my $Conns = $LoginFailed{$Host}; printf "\n%61s | %11.0f", $Host, $Conns; $ConnCount += $Conns; } print "\n" . "-" x 75; printf "\n%75s\n\n\n", $ConnCount; } if ( ( $Detail >= 5 ) and (keys %Connection)) { print "\n[POP3] Connections:". "\n=========================". "\n Host | Connections". "\n------------------------------------------------------------- | -----------"; my $ConnCount = 0; foreach $Host (sort keys %Connection) { my $Conns = $Connection{$Host}; printf "\n%61s | %11.0f", $Host, $Conns; $ConnCount += $Conns; } print "\n" . "-" x 75; printf "\n%75s\n\n\n", $ConnCount; } if (keys %Logout2) { print "\n[POP3] Logout stats (in MB):". "\n============================". "\n User | Logouts | Downloaded | Mbox Size". "\n--------------------------------------- | ------- | ---------- | ----------"; my $ConnCount = 0; my $SizeAll = 0; my $DownAll = 0; foreach my $User (sort keys %Logout2) { my $Conns = $Logout2{$User}; my $Down = $DownloadedMessagesSize{$User}/(1024*1024); my $Size = $MboxSize{$User}/(1024*1024); printf "\n%39s | %7d | ", $User, $Conns; if ($Down > 0) { printf "%10.2f | ",$Down; } else { printf "%10.0f | ",$Down; } if ($Size > 0) { printf "%10.2f",$Size; } else { printf "%10.0f",$Size; } $ConnCount += $Conns; $SizeAll += $Size; $DownAll += $Down; } print "\n" . "-" x 75; printf "\n%49d | %10.2f | %10.2f\n\n\n",$ConnCount,$DownAll,$SizeAll; } if ( ( $Detail >= 10 ) and (keys %Login)) { print "\n[POP3] Successful Logins:\n"; my $LoginCount = 0; foreach my $User (keys %Login) { print " User $User: \n"; my $UserCount = 0; foreach $Host (keys %{$Login{$User}}) { my $HostCount = $Login{$User}{$Host}; print " From $Host: $HostCount Time(s)\n"; $UserCount += $HostCount; } $LoginCount += $UserCount; print " Total $UserCount Time(s)\n"; print "\n"; } print "Total $LoginCount successful logins\n\n\n"; } if ($sslTempkey > 0) { print "\nTemporary SSL key created and used $sslTempkey Time(s)\n"; } if ( ( $Detail >= 5 ) and (keys %sslMechanism)) { print "\nTLS Connection types:\n"; my $TotalConnections = 0; foreach my $Mechanism (keys %sslMechanism) { print " $Mechanism $sslMechanism{$Mechanism} Time(s)\n"; $TotalConnections += $sslMechanism{$Mechanism}; } print "Total TLS connections: $TotalConnections Time(s)\n"; } if ( ( $Detail >= 5 ) and (keys %AutoLogout)) { print "\nAutologout:\n"; foreach my $Host (sort {$a cmp $b} keys %AutoLogout) { print " $Host: $AutoLogout{$Host} Time(s)\n"; } } if ( ( $Detail >= 5 ) and (keys %NoApopSecret)) { print "\nCan't find APOP secret:\n"; my $TotalAPOP = 0; foreach my $User (keys %NoApopSecret) { print " $User: $NoApopSecret{$User} Time(s)\n"; $TotalAPOP += $NoApopSecret{$User}; } print "Total APOP errors: $TotalAPOP Time(s)\n"; } if ( ( $Detail >= 5 ) and ( $ReadSocketError > 0 ) ) { print "Socket Read Error $ReadSocketError Time(s)\n"; } if ( ( $Detail >= 5 ) and ( $WriteSocketError > 0 ) ) { print "Socket Write Error $WriteSocketError Time(s)\n"; } if ( ( $Detail >= 5 ) and ( $ReadSocketError > 0 ) ) { print "Socket Read Error $ReadSocketError Time(s)\n"; } if ( ( $Detail >= 5 ) and ( $WriteSocketError > 0 ) ) { print "Socket Write Error $WriteSocketError Time(s)\n"; } if (keys %Connect) { print "\nConnection to interface:\n"; foreach my $Iface (sort {$a cmp $b} keys %Connect) { print " $Iface:\n"; foreach my $Host (sort {$a cmp $b} keys %{$Connect{$Iface}}) { print " $Host: $Connect{$Iface}{$Host} Time(s)\n"; } } } if (keys %OtherList) { print "\n**Unmatched Entries**\n"; foreach my $line (sort {$a cmp $b} keys %OtherList) { print " $line: $OtherList{$line} Time(s)\n"; } } exit(0); # vi: shiftwidth=3 tabstop=3 syntax=perl et # Local Variables: # mode: perl # perl-indent-level: 3 # indent-tabs-mode: nil # End: logwatch-7.12/scripts/services/arpwatch0000664000211400021140000000321614274101034020511 0ustar logwatchlogwatch ######################################################## # Please file all bug reports, patches, and feature # requests under: # https://sourceforge.net/p/logwatch/_list/tickets # Help requests and discusion can be filed under: # https://sourceforge.net/p/logwatch/discussion/ ######################################################## ######################################################## ## Copyright (c) 2008 Kirk Bauer ## Covered under the included MIT/X-Consortium License: ## http://www.opensource.org/licenses/mit-license.php ## All modifications and contributions by other persons to ## this script are assumed to have been donated to the ## Logwatch project and thus assume the above copyright ## and licensing terms. If you want to make contributions ## under your own copyright or a different license this ## must be explicitly stated in the contribution an the ## Logwatch project reserves the right to not accept such ## contributions. If you have made significant ## contributions to this script and want to claim ## copyright please contact logwatch-devel@lists.sourceforge.net. ######################################################### use strict; my $Detail = $ENV{'LOGWATCH_DETAIL_LEVEL'} || 0; #Init Hash my %ARPWatch; while (defined(my $ThisLine = )) { chomp($ThisLine); next if ($ThisLine eq ""); $ARPWatch{$ThisLine}++; } if ( ($Detail >= 10) and (keys %ARPWatch) ) { print "\n"; foreach my $ThisOne (sort {$a cmp $b} keys %ARPWatch) { print $ThisOne . "\n"; } } exit(0); # vi: shiftwidth=3 tabstop=3 syntax=perl et # Local Variables: # mode: perl # perl-indent-level: 3 # indent-tabs-mode: nil # End: logwatch-7.12/scripts/services/spamassassin0000664000211400021140000001715414743365005021426 0ustar logwatchlogwatch ######################################################## # Please file all bug reports, patches, and feature # requests under: # https://sourceforge.net/p/logwatch/_list/tickets # Help requests and discusion can be filed under: # https://sourceforge.net/p/logwatch/discussion/ ######################################################## ####################################################### ### Copyright (c) 2008 Win Bent ### Covered under the included MIT/X-Consortium License: ### http://www.opensource.org/licenses/mit-license.php ### All modifications and contributions by other persons to ### this script are assumed to have been donated to the ### Logwatch project and thus assume the above copyright ### and licensing terms. If you want to make contributions ### under your own copyright or a different license this ### must be explicitly stated in the contribution an the ### Logwatch project reserves the right to not accept such ### contributions. If you have made significant ### contributions to this script and want to claim ### copyright please contact logwatch-devel@lists.sourceforge.net. ########################################################## use Logwatch ':sort'; use strict; my $Detail = $ENV{'LOGWATCH_DETAIL_LEVEL'} || 0; my $Debug = $ENV{'LOGWATCH_DEBUG'} || 0; my $Ignore_connections = $ENV{'ignore_connections'}; #Init Counters my $StillRoot = 0; my $CleanTotal = 0; my $SpamTotal = 0; my $PyzorTerminated = 0; #Init Hashes my %Child; my %Clean; my %Spam; my %Users; my %Connections; my %OtherList; my %SpamRelay; my %msg; #Init String containers my ( $User, $from, $msgid, $relay, $score, $spam ); #Todo # meta test DIGEST_MULTIPLE has undefined dependency 'DCC_CHECK' : 2 Time(s) # server started on port 783/tcp (running version 3.1.9) : 2 Time(s) # meta test DIGEST_MULTIPLE has undefined dependency 'RAZOR2_CHECK' : 2 Time(s) # server hit by SIGHUP, restarting : 1 Time(s) # server killed by SIGTERM, shutting down : 1 Time(s) # meta test DIGEST_MULTIPLE has undefined dependency 'PYZOR_CHECK' : 1 Time(s) # meta test SARE_SPEC_PROLEO_M2a has dependency 'MIME_QP_LONG_LINE' with a zero score : 1 Time(s) while (defined(my $ThisLine = )) { if ( # We don't care about these # Note that we DO care about "connection from" non-localhost ( $ThisLine =~ m/connection from localhost / ) or ( $ThisLine =~ m/setuid to / ) or ( $ThisLine =~ m/processing message / ) or ( $ThisLine =~ m/^spamd: result: .*,mid=\(unknown\)/ ) or ( $ThisLine =~ m/^prefork: child states: / ) or ( $ThisLine =~ m/^spamd: alarm *$/ ) or ( $ThisLine =~ m/^spamd: handled cleanup of child / ) or ( $ThisLine =~ m/^spamd: server successfully spawned child process, / ) or ( $ThisLine =~ m/^logger: removing stderr method/ ) or ( $ThisLine =~ m/^spamd: server pid:/ ) or ( $ThisLine =~ m/^prefork: adjust: \d+ idle children (less|more) than \d+ (min|max)imum idle children/ ) or # Sendmail messages to ignore ( $ThisLine =~ m/^alias database / ) or ( $ThisLine =~ m/^started as: / ) or ( $ThisLine =~ m/[0-9]* aliases, longest [0-9]* bytes, [0-9]* bytes total/ ) or ( $ThisLine =~ m/^AUTH=/ ) or ( $ThisLine =~ m/^STARTTLS/ ) or ( $ThisLine =~ m/^starting daemon \(/ ) or ( $ThisLine =~ m/^ruleset=trust_auth/ ) or ( $ThisLine =~ m/^ruleset=check_relay/ ) or ( $ThisLine =~ m/^tls_srv_features=/ ) or ( $ThisLine =~ m/^tls_clt_features=/ ) or ( $ThisLine =~ m/^engine=/ ) or 0 # Always last in the list, so all above can say "or" at the end ) { ; # We don't care about these } elsif ( ($User) = ($ThisLine =~ m/clean message .* for (.+?):\d+ / )) { $Clean{ $User}++; $Users{ $User}++; } elsif ( ($User) = ($ThisLine =~ m/identified spam .* for (.+?):\d+ / )) { $Spam{ $User}++; $Users{ $User}++; } elsif ( $ThisLine =~ m/still running as root: / ) { $StillRoot++; } elsif ( $ThisLine =~ m/^spamd: connection from (.*) at port / ) { $Connections{$1}++; # These are caused by pyzor taking too long and being terminated } elsif ( $ThisLine =~ m/^pyzor:.* error: TERMINATED, signal 15/ ) { $PyzorTerminated++; } elsif ( $ThisLine =~ m/\bchild\b/ ) { chomp($ThisLine); # Many perl errors report pseudo-line-numbers, e.g. # ... at /usr/bin/spamd line 1085, line 212 $ThisLine =~ s/\d+/___/g; # Make all numbers "generic" $Child{ $ThisLine }++; # ...and count generic error types } elsif ( ($spam, $score, $msgid) = ($ThisLine =~ m/^spamd: result: (.) (-?\d+).*,mid=<(.*)>/) ) { # Only record the first scan if (!defined($msg{$msgid}->{"score"}) and $spam eq "Y") { $msg{$msgid}->{"score"} = $score; $SpamRelay{$msg{$msgid}->{"relay"}}++; } } elsif ( $ThisLine =~ m/^\w+:/ ) { # Sendmail lines for statistics if ( ($from, $msgid, $relay) = ($ThisLine =~ m/^\w+: from=<(.*)>, .*, msgid=<(.*)>, .*, relay=(.*)/) ) { $msg{$msgid}->{"from"} = $from; $msg{$msgid}->{"relay"} = $relay; } # EVERYTHING ELSE, or, Incentive to identify all "We don't care" lines # We on-purpose allow warnings about --max-children to go here } else { chomp($ThisLine); # Report any unmatched entries... $OtherList{$ThisLine}++; } } ####################################################### #XX print "# Detail:${Detail}\n"; #XX debugging if ( keys %Users ) { my ($u, $cl, $sp); print "\nMail Recipients:\n"; # Some might want to limit this output based on $Detail, but we want it all! foreach $u (sort {$a cmp $b} keys %Users) { $cl = 0 + $Clean{$u}; # Avoid "undefined" error $sp = 0 + $Spam{$u}; # Avoid "undefined" error $CleanTotal += $cl; $SpamTotal += $sp; #OLD: If one user gets over 9999 messages, you have our sympathies #NOW: If one user gets over 99999 messages, you have our sympathies printf " %-8s : %4d clean, %5d spam\n", $u, $cl, $sp; } } if ( $CleanTotal || $SpamTotal ) { my $ttotal = $CleanTotal + $SpamTotal; print "\nSummary:\n"; printf "\tTotal Clean: %5d (%3d%%)\n", $CleanTotal, int ((100.0 * $CleanTotal / $ttotal) + 0.5); printf "\tTotal Spam: %5d (%3d%%)\n", $SpamTotal, int ((100.0 * $SpamTotal / $ttotal) + 0.5); } if (keys %SpamRelay) { print "\nTop 10 Spam Relays:\n"; my $i = 0; foreach $relay (sort {$SpamRelay{$b}<=>$SpamRelay{$a} } keys %SpamRelay) { print " $relay: $SpamRelay{$relay} Time(s)\n"; last if ++$i == 10; } } if ( $StillRoot ) { print qq{\n"still running as root" error: $StillRoot time(s)\n}; } if (keys %Child) { print "\nChild-related errors\n"; foreach my $line (sort {$Child{$b}<=>$Child{$a} } keys %Child) { print " $line: $Child{$line} Time(s)\n"; } } if (keys %Connections) { my $header_printed = 0; foreach my $connection ( sort {$a cmp $b} keys %Connections ) { if ($Ignore_connections && $connection =~ /$Ignore_connections/) { next; } if (!$header_printed) { print "\nConnections from:\n"; $header_printed = 1; } print " $connection : $Connections{$connection} Time(s)\n"; } } if ( $PyzorTerminated) { print "\nPyzor TERMINATED errors: $PyzorTerminated time(s)\n"; } if (keys %OtherList) { print "\n**Unmatched Entries**\n"; foreach my $line (sort {$OtherList{$b}<=>$OtherList{$a} } keys %OtherList) { print " $line: $OtherList{$line} Time(s)\n"; } } exit(0); # vi: shiftwidth=3 tabstop=3 syntax=perl et # Local Variables: # mode: perl # perl-indent-level: 3 # indent-tabs-mode: nil # End: logwatch-7.12/scripts/services/cisco0000664000211400021140000013571714743365003020025 0ustar logwatchlogwatch ######################################################## # Please file all bug reports, patches, and feature # requests under: # https://sourceforge.net/p/logwatch/_list/tickets # and copy: # Laurent DUFOUR , # Help requests and discusion can be filed under: # https://sourceforge.net/p/logwatch/discussion/ ######################################################## ######################################################## # This was written and is maintained by: # Laurent DUFOUR , # Heavily modified by: # Hugo van der Kooij # based on the work of # Kirk Bauer # # Please send all comments, suggestions, bug reports, # etc, to laurent.dufour@havas.com and hvdkooij@vanderkooij.org ######################################################## ######################################################## ## Copyright (c) 2008 Laurent DUFOUR ## Covered under the included MIT/X-Consortium License: ## http://www.opensource.org/licenses/mit-license.php ## All modifications and contributions by other persons to ## this script are assumed to have been donated to the ## Logwatch project and thus assume the above copyright ## and licensing terms. If you want to make contributions ## under your own copyright or a different license this ## must be explicitly stated in the contribution an the ## Logwatch project reserves the right to not accept such ## contributions. If you have made significant ## contributions to this script and want to claim ## copyright please contact logwatch-devel@lists.sourceforge.net. ######################################################### use Logwatch ':all'; use strict; my $Debug = ValueOrDefault($ENV{'LOGWATCH_DEBUG'}, 0); my $Detail = ValueOrDefault($ENV{'LOGWATCH_DETAIL_LEVEL'}, 0); my $CatchUnknown = ValueOrDefault($ENV{'catch_unknown'}, 1); my $DebugCounter = 0; #Init String Containers my ( $ACL, $IPV6_packets, $InspectDrop, $JavaBlock, $SSH_packets, $Unit, $accesslist, $action, $address, $count, $destination, $destination_ip, $destination_port, $drophttppkts, $dropsmtppkts, $errortype, $file, $hash, $icmp_type, $interface, $interface_experiencing_error, $line, $lines, $message, $ntppear, $packets, $protocol, $radio, $source, $source_ip, $source_port, $state, $testline, $unmatched, $username, $vlan_number, $vty, $withwho, ); #Init Arrays my (@dfields, @sfields, @testfields) = (); #Init Hashes my ( %AAABadReg, %AAAServerUndef, %ACL, %ACLmissed, %ACTION, %ConfigChange, %Configured, %CountersMsg, %DHCPConflict, %DHCPPingConflict, %Dot11Assoc, %Dot11Disassoc, %Dot11FreqUsed, %Dot11LoadingRadio, %Dot11NoSSID, %Dot11Retrys, %Dot11Roamed, %DuplexMismatched, %DuplicateAddress, %ExcessiveCollision, %Flapping, %ICMP_Echo_Rep, %ICMP_Echo_Req, %InterfaceError, %InterfaceState, %InvalidMulticast, %LateCollision, %LineProtocolInterfaceState, %LoginFail, %LostCarrier, %MLSFlowmaskChanged, %MLSMcastStatus, %MLSMultiLayerDisabled, %MLSMultiLayerEnabled, %MLSNetflowDisabled, %MLSNetflowEnabled, %MgmtResetMindown, %ModemChange, %NTPpeerReach, %NTPpeerSync, %NTPpeerUnreach, %OtherList, %PORT_IN_ERRORS, %PORT_SSUPOK, %PortStateBridge, %RSHELLFail, %RSPSlaveChange, %RSPSlaveDown, %RSPSlaveUp, %RUNCFGEnabled, %ReloadRequested, %Restarted, %SNMPColdStart, %SSH, %SYSCpuHog, %SYSImgSyncFinished, %SYSImgSyncStart, %SYSModuleInserted, %SYSModuleMinorFail, %SYSModuleOk, %SYSModulePowerOn, %SYSModulePowerSupplyUp, %SYSModuleReset, %SYSModuleStandby, %SYSSupervisorEngineReset, %SYSSupervisorErr, %SYSWaitOnline, %SYSWarn, %SpantreeFailure, %StartConfigChange, %Started, %TRUNKPORTOFF, %TRUNKPORTON, %Underflow, %VLANMismatched, %drophttphost, %dropigmp, %dropsmtphost, ); # Avoid "Use of uninitialized value" warning messages. sub ValueOrDefault { my ($value, $default) = @_; return ($value ? $value : $default); } if ( $Debug >= 5 ) { print STDERR "\n\nDEBUG: Inside CISCO Filter \n\n"; $DebugCounter = 1; } my ($month,$day,$time,$host,$process,$conn,$msg); while (defined(my $ThisLine = )) { if ( $Debug >= 30 ) { print STDERR "DEBUG($DebugCounter): $ThisLine"; $DebugCounter++; } ($month,$day,$time,$host,$process,$conn,$msg)=split(/ +/,$ThisLine,7); if ( ($ThisLine =~ /(ISDN-6-.+)/ ) or ($ThisLine =~ /Copyright/ ) or ($ThisLine =~ /Cisco Internetwork Operating System Software/ ) or ($ThisLine =~ /IOS \(tm\)/ ) or ($ThisLine =~ /Cisco IOS/ ) or ($ThisLine =~ /Technical Support/ ) or ($ThisLine =~ /self test passed/ ) or ($ThisLine =~ /TAC:Home:SW:IOS:Specials/ ) ) { # don't care about this, will code this later } elsif ( $ThisLine =~ /%SEC-6-IPACCESSLOG(|D|N)P/) { $testline = $ThisLine; chomp $testline; $testline =~ s/^.*SEC-6-IPACCESSLOG(|D|N)P: list //; $testline =~ s/ ->//; $testline =~ s/, / /; $testline =~ s/ packets//; $testline =~ s/ packet//; @testfields = split(/ /,$testline); $accesslist = @testfields[0]; $action = @testfields[1]; $protocol = @testfields[2]; if ($protocol =~ /(tcp|udp)/) { $source = @testfields[3]; $destination = @testfields[4]; $icmp_type = ""; $count = @testfields[5]; @sfields = split(/\(/, $source); $source_ip = @sfields[0]; $source_port = @sfields[1]; $source_port =~ s/\)//; @dfields = split(/\(/, $destination); $destination_ip = @dfields[0]; $destination_port = @dfields[1]; $destination_port =~ s/\)//; } elsif ($protocol =~ /icmp/) { $source_ip = @testfields[3]; $source_port = 0; $destination_ip = @testfields[4]; $destination_port = 0; $icmp_type = @testfields[5]; $count = @testfields[6]; } elsif ($protocol =~ /41/) { $source_ip = @testfields[3]; $source_port = 0; $destination_ip = @testfields[4]; $destination_port = 0; $icmp_type = ""; $count = @testfields[5]; } else { $count = 0; } $ACL{$accesslist} += $count; $ACTION{$action} += $count; $packets += $count; if ( ($destination_port == 22) and ($protocol =~ /tcp/) ) { $SSH{$source_ip} += $count; $SSH_packets += $count; } } elsif ( $ThisLine =~ /%IPV6-6-ACCESSLOG(|D|N)P/) { $testline = $ThisLine; chomp $testline; $testline =~ s/^.*IPV6-6-ACCESSLOG(|D|N)P: list //; $testline =~ s/ ->//; $testline =~ s/, / /; $testline =~ s/ packets//; $testline =~ s/ packet//; @testfields = split(/ /,$testline); $accesslist = @testfields[0]; $action = @testfields[1]; $protocol = @testfields[2]; if ($protocol =~ /(tcp|udp)/) { $source = @testfields[3]; $destination = @testfields[4]; $icmp_type = ""; $count = @testfields[5]; @sfields = split(/\(/, $source); $source_ip = @sfields[0]; $source_port = @sfields[1]; $source_port =~ s/\)//; @dfields = split(/\(/, $destination); $destination_ip = @dfields[0]; $destination_port = @dfields[1]; $destination_port =~ s/\)//; } elsif ($protocol =~ /icmpv6/) { $source_ip = @testfields[3]; $source_port = 0; $destination_ip = @testfields[4]; $destination_port = 0; $icmp_type = @testfields[5]; $count = @testfields[6]; } else { $count = 0; } $ACL{$accesslist} += $count; $ACTION{$action} += $count; $IPV6_packets += $count; if ( ($destination_port == 22) and ($protocol =~ /tcp/) ) { $SSH{$source_ip} += $count; $SSH_packets += $count; } } elsif ( ($protocol,$source,$destination) = ($ThisLine =~ /%FW-6-DROP_PKT: Dropping (\S+) pkt (\S+) => (\S+)/) ) { @sfields = split(/:/, $source); $source_ip = @sfields[0]; $source_port = @sfields[1]; @dfields = split(/:/, $destination); $destination_ip = @dfields[0]; $destination_port = @dfields[1]; if ($source_port == 25) { $dropsmtphost{$destination_ip}++; $dropsmtppkts++; } if ($destination_port == 25) { $dropsmtphost{$source_ip}++; $dropsmtppkts++; } if ($source_port == 80) { $drophttphost{$source_ip}++; $drophttppkts++; } if ($destination_port == 80) { $drophttphost{$destination_ip}++; $drophttppkts++; } $InspectDrop++; } elsif ( ($ACL,$source,$count) = ($ThisLine =~ /SEC-6-IPACCESSLOGSP: list (.*) denied igmp (.*) -> 224.0.0.1 \(17\), (.*) packet(|s)/) ) { $dropigmp{$host}{$ACL}{$source} += $count; } elsif ($ThisLine =~ /%FW-3-HTTP_JAVA_BLOCK/) { $JavaBlock++; } elsif ( ($username,$vty,$address) = ($ThisLine =~ /%SYS-5-CONFIG_I: Configured from console by (\S+) on (\S+) \((\S+)\)/) ) { $Configured{$host}{"Configured from $vty by $username at ".LookupIP($address)}++; } elsif ( ($username,$vty) = ($ThisLine =~ /%SYS-5-CONFIG_I: Configured from console by (\S+) on (\S+)/) ) { $Configured{$host}{"Configured from $vty by $username"}++; } elsif ( ($username,$vty) = ($ThisLine =~ /%SYS-5-CONFIG_I: Configured from console by (\S+) \((\S+)\)/) ) { $Configured{$host}{"Configured from ".LookupIP($vty)." by $username"}++; } elsif ( ($file,$vty) = ($ThisLine =~ /%SYS-5-CONFIG_I: Configured from (\S+) by (console)/) ) { $Configured{$host}{"Configured from ".$vty." using $file"}++; } elsif ( ($unmatched) = ($ThisLine =~ /%SYS-5-CONFIG_I: (.+)/) ) { $Configured{$host}{"UNMATCHED: $unmatched"}++; } elsif ( ($unmatched) = ($ThisLine =~ /%AUDIT-5-RUN_CONFIG/) ) { $ConfigChange{$host}++; } elsif ( ($interface,$errortype,$withwho) = ($ThisLine =~ /duplex mismatch discovered on (.+) \(.*\), with (.*)/) ) { $DuplexMismatched{$host}{$interface." with ".$errortype}++; } elsif ( ($interface,$vlan_number,$withwho) = ($ThisLine =~ /Native VLAN mismatch discovered on (.+) \(([^ ]+)\), with ([^ ]+)/) ) { $VLANMismatched{$host}{$interface." vlan ".$vlan_number}++; } elsif ( ($interface) = ($ThisLine =~ /NVLANMISMATCH:Native vlan mismatch detected on port (.*)/) ) { $VLANMismatched{$host}{$interface}++; } elsif ( ($interface,$state) = ($ThisLine =~ /Line protocol on Interface (.+), changed state to (.*)/) ) { $LineProtocolInterfaceState{$host}{$interface." ".$state}++; } elsif ( ($interface,$state) = ($ThisLine =~ /Interface (.+), changed state to (.*)/) ) { $InterfaceState{$host}{$interface." ".$state}++; } elsif ( ($interface_experiencing_error) = ($ThisLine =~ /ERROR: (.*) is experiencing errors/) ) { $InterfaceError{$host}{$interface_experiencing_error}++; } elsif ( ($interface) = ($ThisLine =~ /DUPLEXMISMATCH:Full\/half duplex mismatch detected on port (.*)/) ) { $DuplexMismatched{$host}{$interface}++; } elsif ( ($interface) = ($ThisLine =~ /ETHCNTR-3-HALF_DUX_COLLISION_EXCEED_THRESHOLD: (.*)/) ) { $DuplexMismatched{$host}{$interface}++; } elsif ( ($interface,$state,$destination_port) = ($ThisLine =~ /PORTFROMSTP:Port (.+) (.+) bridge port (.*)/) ) { $PortStateBridge{$host}{$interface." ".$state." ".$destination_port}++; } elsif ( ($interface,$state,$destination_port) = ($ThisLine =~ /PORTTOSTP:Port (.+) (.+) bridge port (.*)/) ) { $PortStateBridge{$host}{$interface." ".$state." ".$destination_port}++; } elsif ( ($Unit) = ($ThisLine =~ /Unit (.*), excessive modem control changes/) ) { $ModemChange{$host}{$Unit}++; } elsif ( ($ThisLine =~ /Compiled/) ) { $Started{$host}++; } elsif ( ($message) = ($ThisLine =~ /RELOAD: (.*)/) ) { $ReloadRequested{$host}{$message}++; } elsif ( ($message) = ($ThisLine =~ /RESTART: (.*)/) ) { $Restarted{$host}{$message}++; } elsif ( ($interface) = ($ThisLine =~ /LOSTCARR: (.*)/) ) { $LostCarrier{$host}{$interface}++; } elsif ( ($interface) = ($ThisLine =~ /DUPADDR: (.*)/) ) { $DuplicateAddress{$host}{$interface}++; } elsif ( ($interface) = ($ThisLine =~ /TRUNKPORTON:Port (.*)/) ) { $TRUNKPORTON{$host}{$interface}++; } elsif ( ($interface) = ($ThisLine =~ /TRUNKPORTOFF:Port (.*)/) ) { $TRUNKPORTOFF{$host}{$interface}++; } elsif ( ($interface) = ($ThisLine =~ /SYS-3-PORT_IN_ERRORS:(.*)/) ) { $PORT_IN_ERRORS{$host}{$interface}++; } elsif ( ($interface) = ($ThisLine =~ /SYS-5-PORT_SSUPOK:(.*)/) ) { $PORT_SSUPOK{$host}{$interface}++; } elsif ( ($interface) = ($ThisLine =~ /EXCESSCOLL: (.*)/) ) { $ExcessiveCollision{$host}{$interface}++; } elsif ( ($interface) = ($ThisLine =~ /LATECOLL: (.*)/) ) { $LateCollision{$host}{$interface}++; } elsif ( ($interface) = ($ThisLine =~ /UNDERFLO: (.*)/) ) { $Underflow{$host}{$interface}++; } elsif ( ($interface) = ($ThisLine =~ /SYS-4-P2_WARN: (.*)/) ) { $SYSWarn{$host}{$interface}++; } elsif ( ($interface) = ($ThisLine =~ /P2_WARN: (.*)/) ) { $InvalidMulticast{$host}{$interface}++; } elsif ( ($interface) = ($ThisLine =~ /LINK_FLAP: (.*)/) ) { $Flapping{$host}{$interface}++; } elsif ( ($interface) = ($ThisLine =~ /ERR_DISABLE: (.*)/) ) { $Flapping{$host}{$interface}++; } elsif ( ($interface) = ($ThisLine =~ /LOGIN_FAIL:User (.*)/) ) { $LoginFail{$host}{$interface}++; } elsif ( ($interface) = ($ThisLine =~ /RSHPORTATTEMPT: (.*)/) ) { $RSHELLFail{$host}{$interface}++; } elsif ( ($interface) = ($ThisLine =~ /SPANTREE.+: (.*)/) ) { $SpantreeFailure{$host}{$interface}++; } elsif ( ($interface) = ($ThisLine =~ /DHCPD-4-DECLINE_CONFLICT: (.*)/) ) { $DHCPConflict{$host}{$interface}++; } elsif ( ($interface) = ($ThisLine =~ /DHCPD-4-PING_CONFLICT: (.*)/) ) { $DHCPPingConflict{$host}{$interface}++; } elsif ( ($interface) = ($ThisLine =~ /AAAA-4-SERVUNDEF: (.*)/) ) { $AAAServerUndef{$host}{$interface}++; } elsif ( ($interface) = ($ThisLine =~ /AAAA-3-BADREG: (.*)/) ) { $AAABadReg{$host}{$interface}++; } elsif ( ($interface) = ($ThisLine =~ /MGMT-5-NVRAM_MINDOWN: (.*)/) ) { $MgmtResetMindown{$host}{$interface}++; } elsif ( ($interface) = ($ThisLine =~ /RUNCFGSYNC-6-SYNCEVENT: (.*)/) ) { $RUNCFGEnabled{$host}{$interface}++; } elsif ( ($interface) = ($ThisLine =~ /RSP-3-SLAVECHANGE: (.*)/) ) { $RSPSlaveChange{$host}{$interface}++; } elsif ( ($interface) = ($ThisLine =~ /RSP-3-SLAVEUP: (.*)/) ) { $RSPSlaveUp{$host}{$interface}++; } elsif ( ($interface) = ($ThisLine =~ /RSP-3-SLAVEDOWN: (.*)/) ) { $RSPSlaveDown{$host}{$interface}++; } elsif ( ($interface) = ($ThisLine =~ /MLS-5-MLSENABLED: (.*)/) ) { $MLSMultiLayerEnabled{$host}{$interface}++; } elsif ( ($interface) = ($ThisLine =~ /MLS-5-MLSDISABLED: (.*)/) ) { $MLSMultiLayerDisabled{$host}{$interface}++; } elsif ( ($interface) = ($ThisLine =~ /MLS-5-MCAST_STATUS: (.*)/) ) { $MLSMcastStatus{$host}{$interface}++; } elsif ( ($interface) = ($ThisLine =~ /MLS-5-NDEENABLED: (.*)/) ) { $MLSNetflowEnabled{$host}{$interface}++; } elsif ( ($interface) = ($ThisLine =~ /MLS-5-NDEDISABLED: (.*)/) ) { $MLSNetflowDisabled{$host}{$interface}++; } elsif ( ($interface) = ($ThisLine =~ /MLS-5-FLOWMASKCHANGE: (.*)/) ) { $MLSFlowmaskChanged{$host}{$interface}++; } elsif ( ($interface) = ($ThisLine =~ /SYS-3-CPUHOG: (.*)/) ) { $SYSCpuHog{$host}{$interface}++; } elsif ( ($interface) = ($ThisLine =~ /SYS-5-MOD_PWRON:Module (.+) (.*)/) ) { $SYSModulePowerOn{$host}{$interface}++; } elsif ( ($interface) = ($ThisLine =~ /SYS-1-SYS_ENABLEPS: (.*)/) ) { $SYSModulePowerSupplyUp{$host}{$interface}++; } elsif ( ($interface) = ($ThisLine =~ /SYS-5-MOD_OK:Module (.+) (.*)/) ) { $SYSModuleOk{$host}{$interface}++; } elsif ( ($interface) = ($ThisLine =~ /SYS-5-MOD_INSERT:Module (.+) (.*)/) ) { $SYSModuleInserted{$host}{$interface}++; } elsif ( ($interface) = ($ThisLine =~ /SYS-3-MOD_MINORFAIL:Module (.+) (.*)/) ) { $SYSModuleMinorFail{$host}{$interface}++; } elsif ( ($interface) = ($ThisLine =~ /SYS-5-MOD_RESET:Module (.+) (.*)/) ) { $SYSModuleReset{$host}{$interface}++; } elsif ( ($interface) = ($ThisLine =~ /SYS-5-SUP_MODSBY:(.*)/) ) { $SYSModuleStandby{$host}{$interface}++; } elsif ( ($interface) = ($ThisLine =~ /SYS-3-SUP_WAITSBYSUPONLINE: (.*)/) ) { $SYSWaitOnline{$host}{$interface}++; } elsif ( ($interface) = ($ThisLine =~ /SYS-3-SUP_THISSUPRESET: (.*)/) ) { $SYSSupervisorEngineReset{$host}{$interface}++; } elsif ( ($interface) = ($ThisLine =~ /SYS-5-SUP_IMGSYNCSTART: (.*)/) ) { $SYSImgSyncStart{$host}{$interface}++; } elsif ( ($interface) = ($ThisLine =~ /SYS-5-SUP_IMGSYNCFINISH: (.*)/) ) { $SYSImgSyncFinished{$host}{$interface}++; } elsif ( ($interface) = ($ThisLine =~ /SYS-4-SUPERVISOR_ERR:Forwarding engine IP (checksum|length|too short) error counter (.*)/) ) { $SYSSupervisorErr{$host}{$interface}++; } elsif ( ($interface) = ($ThisLine =~ /SNMP-5-COLDSTART: (.*)/) ) { $SNMPColdStart{$host}{$interface}++; } elsif ( ($interface) = ($ThisLine =~ /COUNTERS: (.*)/) ) { $CountersMsg{$host}{$interface}++; } elsif ( ($interface) = ($ThisLine =~ /DOT11-4-MAXRETRIES: Packet to client ....\.....\..... reached(.*)/) ) { $Dot11Retrys{$host}{$interface}++; } elsif ( ($radio,$interface) = ($ThisLine =~ /DOT11-6-ASSOC: Interface (.*), Station +(.*)/) ) { $Dot11Assoc{$host}{"$radio $interface"}++; } elsif ( ($radio,$interface) = ($ThisLine =~ /DOT11-6-DISASSOC: Interface (.*), Deauthenticating Station (.*)/) ) { $Dot11Disassoc{$host}{"$radio $interface"}++; } elsif ( ($interface) = ($ThisLine =~ /DOT11-6-ROAMED: Station (.*)/) ) { $Dot11Roamed{$host}{$interface}++; } elsif ( ($interface) = ($ThisLine =~ /DOT11-4-NO_SSID: (.*)/) ) { $Dot11NoSSID{$host}{$interface}++; } elsif ( ($interface) = ($ThisLine =~ /DOT11-6-FREQ_USED: (.*)/) ) { $Dot11FreqUsed{$host}{$interface}++; } elsif ( ($radio,$interface) = ($ThisLine =~ /DOT11-4-LOADING_RADIO: Interface (.*), loading the radio firmware (.*)/) ) { $Dot11LoadingRadio{$host}{"$radio $interface"}++; } elsif ( ($interface) = ($ThisLine =~ /ICMP Echo Req: (.*)/) ) { $ICMP_Echo_Req{$host}{$interface}++; } elsif ( ($interface) = ($ThisLine =~ /ICMP Echo Rply: (.*)/) ) { $ICMP_Echo_Rep{$host}{$interface}++; } elsif ( ($interface) = ($ThisLine =~ /AMDP2_FE-5-COLL: (.*)/) ) { $ExcessiveCollision{$host}{$interface}++; } elsif ( ($hash) = ($ThisLine =~ /AUDIT-5-STARTUP_CONFIG: Startup Configuration changed. Hash: (.*)/) ) { $StartConfigChange{$host}++; } elsif ( ($ntppear) = ($ThisLine =~ /NTP-4-PEERUNREACH: Peer (.*) is unreachable/) ) { $NTPpeerUnreach{$host}{$ntppear}++; } elsif ( ($ntppear) = ($ThisLine =~ /NTP-5-PEERSYNC: NTP synced to peer (.*)/) ) { $NTPpeerSync{$host}{$ntppear}++; } elsif ( ($ntppear) = ($ThisLine =~ /NTP-6-PEERREACH: Peer (.*) is reachable/) ) { $NTPpeerReach{$host}{$ntppear}++; } elsif ( ($count) = ($ThisLine =~ /SEC-6-IPACCESSLOGRL: access-list logging rate-limited or missed (.*) packet(|s)/) ) { $ACLmissed{$host} += $count; } elsif ( $CatchUnknown >= 1 ) { # Report any unmatched entries... chomp $ThisLine; ($msg) = ($ThisLine =~ /(%.*)/); $msg ||= $ThisLine; $OtherList{"$host: $msg"}++; } } if (keys %Started) { print "\nDevice started :\n"; foreach my $ThisOne (sort keys %Started) { print " " . $ThisOne . ":\n"; print "\t Started: " . $Started{$ThisOne} . " Time(s)\n"; } } if (keys %Restarted) { print "\nDevice restarted :\n"; foreach my $ThisOne (sort keys %Restarted) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (sort keys %{$Restarted{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $Restarted{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if (keys %ReloadRequested) { print "\nDevice reload requested :\n"; foreach my $ThisOne (sort keys %ReloadRequested) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (sort keys %{$ReloadRequested{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $ReloadRequested{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if (keys %DuplexMismatched) { print "\nDuplex Mismatch warning:\n"; foreach my $ThisOne (sort keys %DuplexMismatched) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (sort keys %{$DuplexMismatched{$ThisOne}}) { print "\tPort or Interface " .$ThatOne . "\t: " . $DuplexMismatched{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if (keys %VLANMismatched) { print "\nNative VLAN mismatch warning:\n"; foreach my $ThisOne (sort keys %VLANMismatched) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (sort keys %{$VLANMismatched{$ThisOne}}) { print "\tPort or Interface " .$ThatOne . "\t: " . $VLANMismatched{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if (keys %TRUNKPORTON) { print "\nPort/Interface trunk on :\n"; foreach my $ThisOne (sort keys %TRUNKPORTON) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (sort keys %{$TRUNKPORTON{$ThisOne}}) { print "\tPort or Interface " .$ThatOne . "\t: " . $TRUNKPORTON{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if (keys %TRUNKPORTOFF) { print "\nPort/Interface trunk off :\n"; foreach my $ThisOne (sort keys %TRUNKPORTOFF) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (sort keys %{$TRUNKPORTOFF{$ThisOne}}) { print "\tPort or Interface " .$ThatOne . "\t: " . $TRUNKPORTOFF{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if (keys %PORT_IN_ERRORS) { print "\nPort/Interface in errors :\n"; foreach my $ThisOne (sort keys %PORT_IN_ERRORS) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (sort keys %{$PORT_IN_ERRORS{$ThisOne}}) { print "\tPort or Interface " .$ThatOne . "\t: " . $PORT_IN_ERRORS{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if (keys %PORT_SSUPOK) { print "\nPort in Standy Mode :\n"; foreach my $ThisOne (sort keys %PORT_SSUPOK) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (sort keys %{$PORT_SSUPOK{$ThisOne}}) { print "\tPort or Interface " .$ThatOne . "\t: " . $PORT_SSUPOK{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if (keys %PortStateBridge) { print "\nPort/Interface left/joined bridge :\n"; foreach my $ThisOne (sort keys %PortStateBridge) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (sort keys %{$PortStateBridge{$ThisOne}}) { print "\tPort or Interface " .$ThatOne . "\t: " . $PortStateBridge{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if (keys %Flapping) { print "\nPort/Interface Flapping :\n"; foreach my $ThisOne (sort keys %Flapping) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (sort keys %{$Flapping{$ThisOne}}) { print "\tPort or Interface " .$ThatOne . "\t: " . $Flapping{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if (keys %DuplicateAddress) { print "\nPort/Interface duplicate address :\n"; foreach my $ThisOne (sort keys %DuplicateAddress) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (sort keys %{$DuplicateAddress{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $DuplicateAddress{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if (keys %InvalidMulticast) { print "\nPort/Interface invalid multicast :\n"; foreach my $ThisOne (sort keys %InvalidMulticast) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (sort keys %{$InvalidMulticast{$ThisOne}}) { print "\tPort or Interface " .$ThatOne . "\t: " . $InvalidMulticast{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if (keys %SpantreeFailure) { print "\nPort/Interface spantree failure :\n"; foreach my $ThisOne (sort keys %SpantreeFailure) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (sort keys %{$SpantreeFailure{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $SpantreeFailure{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if ($Detail >= 5 && keys %LineProtocolInterfaceState) { print "\nLine protocol on Port/Interface changed state :\n"; foreach my $ThisOne (sort keys %LineProtocolInterfaceState) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (sort keys %{$LineProtocolInterfaceState{$ThisOne}}) { print "\tPort or Interface " .$ThatOne . "\t: " . $LineProtocolInterfaceState{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if (( $Detail >= 5 ) and (keys %InterfaceState)) { print "\nPort/Interface state change :\n"; foreach my $ThisOne (sort keys %InterfaceState) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (sort keys %{$InterfaceState{$ThisOne}}) { print "\tPort or Interface " .$ThatOne . "\t: " . $InterfaceState{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if (keys %Underflow) { print "\nPort/Interface transmit error(underflow) :\n"; foreach my $ThisOne (sort keys %Underflow) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (sort keys %{$Underflow{$ThisOne}}) { print "\tPort or Interface " .$ThatOne . "\t: " . $Underflow{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if (keys %LostCarrier) { print "\nPort/Interface transmit error (lost carrier) :\n"; foreach my $ThisOne (sort keys %LostCarrier) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (sort keys %{$LostCarrier{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $LostCarrier{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if (keys %LateCollision) { print "\nPort/Interface transmit error (Late collision) :\n"; foreach my $ThisOne (sort keys %LateCollision) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (sort keys %{$LateCollision{$ThisOne}}) { print "\tPort or Interface " .$ThatOne . "\t: " . $LateCollision{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if (keys %ExcessiveCollision) { print "\nPort/Interface Excessive collision :\n"; foreach my $ThisOne (sort keys %ExcessiveCollision) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (sort keys %{$ExcessiveCollision{$ThisOne}}) { print "\tPort or Interface " .$ThatOne . "\t: " . $ExcessiveCollision{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if (keys %InterfaceError) { print "\nPort/Interface experiencing error :\n"; foreach my $ThisOne (sort keys %InterfaceError) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (sort keys %{$InterfaceError{$ThisOne}}) { print "\tPort or Interface " .$ThatOne . "\t: " . $InterfaceError{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if (keys %ModemChange) { print "\nExcessive modem control changes:\n"; foreach my $ThisOne (sort keys %ModemChange) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (sort keys %{$ModemChange{$ThisOne}}) { print "\tUnit " .$ThatOne . "\t: " . $ModemChange{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if (keys %CountersMsg) { print "\nCounters changes:\n"; foreach my $ThisOne (sort keys %CountersMsg) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (sort keys %{$CountersMsg{$ThisOne}}) { print "\t" .$ThatOne . "\t: " . $CountersMsg{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if (keys %Configured) { print "\nDevice configured by :\n"; foreach my $ThisOne (sort keys %Configured) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (sort keys %{$Configured{$ThisOne}}) { print "\t" .$ThatOne . "\t: " . $Configured{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if (keys %ConfigChange) { print "\nDevice config changes :\n"; foreach my $ThisOne (sort keys %ConfigChange) { print " " . $ThisOne . ": " . $ConfigChange{$ThisOne} . " Time(s)\n"; } } if (keys %StartConfigChange) { print "\nDevice start config changes :\n"; foreach my $ThisOne (sort keys %StartConfigChange) { print " " . $ThisOne . ": " . $StartConfigChange{$ThisOne} . " Time(s)\n"; } } if (keys %LoginFail) { print "\nLogin failed on device :\n"; foreach my $ThisOne (sort keys %LoginFail) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (sort keys %{$LoginFail{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $LoginFail{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if (keys %RSHELLFail) { print "\nRemote Shell Login failed on device :\n"; foreach my $ThisOne (sort keys %RSHELLFail) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (sort keys %{$RSHELLFail{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $RSHELLFail{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if (keys %DHCPConflict) { print "\nDHCP Conflict on device :\n"; foreach my $ThisOne (sort keys %DHCPConflict) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (sort keys %{$DHCPConflict{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $DHCPConflict{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if (keys %DHCPPingConflict) { print "\nDHCP Address Conflict on device :\n"; foreach my $ThisOne (sort keys %DHCPPingConflict) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (sort keys %{$DHCPPingConflict{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $DHCPPingConflict{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if (keys %AAAServerUndef) { print "\nAAA Server Undefined on device :\n"; foreach my $ThisOne (sort keys %AAAServerUndef) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (sort keys %{$AAAServerUndef{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $AAAServerUndef{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if (keys %AAABadReg) { print "\nAAA Bad Register on device :\n"; foreach my $ThisOne (sort keys %AAABadReg) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (sort keys %{$AAABadReg{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $AAABadReg{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if (keys %RUNCFGEnabled) { print "\nHigh-Availability Redundancy Feature is enabled on device :\n"; foreach my $ThisOne (sort keys %RUNCFGEnabled) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (sort keys %{$RUNCFGEnabled{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $RUNCFGEnabled{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if (keys %RSPSlaveUp) { print "\nHigh-Availability Redundancy Feature, Card is manually reset, Slave is up on device :\n"; foreach my $ThisOne (sort keys %RSPSlaveUp) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (sort keys %{$RSPSlaveUp{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $RSPSlaveUp{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if (keys %RSPSlaveDown) { print "\nHigh-Availability Redundancy Feature, Card is manually reset, Slave is down on device :\n"; foreach my $ThisOne (sort keys %RSPSlaveDown) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (sort keys %{$RSPSlaveDown{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $RSPSlaveDown{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if (keys %RSPSlaveChange) { print "\nHigh-Availability Redundancy Feature, Card is manually reset, Slave is changing state on device :\n"; foreach my $ThisOne (sort keys %RSPSlaveChange) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (sort keys %{$RSPSlaveChange{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $RSPSlaveChange{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if (keys %MLSFlowmaskChanged) { print "\nFlow Mask Changed on device :\n"; foreach my $ThisOne (sort keys %MLSFlowmaskChanged) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (sort keys %{$MLSFlowmaskChanged{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $MLSFlowmaskChanged{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if (keys %MLSMcastStatus) { print "\nIP Multicast status on device :\n"; foreach my $ThisOne (sort keys %MLSMcastStatus) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (sort keys %{$MLSMcastStatus{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $MLSMcastStatus{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if (keys %MLSMultiLayerEnabled) { print "\nIP Multilayer switching enabled on device :\n"; foreach my $ThisOne (sort keys %MLSMultiLayerEnabled) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (sort keys %{$MLSMultiLayerEnabled{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $MLSMultiLayerEnabled{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if (keys %MLSMultiLayerDisabled) { print "\nIP Multilayer switching disabled on device :\n"; foreach my $ThisOne (sort keys %MLSMultiLayerDisabled) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (sort keys %{$MLSMultiLayerDisabled{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $MLSMultiLayerDisabled{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if (keys %MLSNetflowEnabled) { print "\nNetflow enabled on device :\n"; foreach my $ThisOne (sort keys %MLSNetflowEnabled) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (sort keys %{$MLSNetflowEnabled{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $MLSNetflowEnabled{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if (keys %MLSNetflowDisabled) { print "\nNetflow disabled on device :\n"; foreach my $ThisOne (sort keys %MLSNetflowDisabled) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (sort keys %{$MLSNetflowDisabled{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $MLSNetflowDisabled{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if (keys %MgmtResetMindown) { print "\nReset mindown on device :\n"; foreach my $ThisOne (sort keys %MgmtResetMindown) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (sort keys %{$MgmtResetMindown{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $MgmtResetMindown{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if (keys %SYSWarn) { print "\nModule timeout on device :\n"; foreach my $ThisOne (sort keys %SYSWarn) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (sort keys %{$SYSWarn{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $SYSWarn{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if (keys %SYSCpuHog) { print "\nCpu Hog on device :\n"; foreach my $ThisOne (sort keys %SYSCpuHog) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (sort keys %{$SYSCpuHog{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $SYSCpuHog{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if (keys %SYSModulePowerSupplyUp) { print "\nModule power supply up on device :\n"; foreach my $ThisOne (sort keys %SYSModulePowerSupplyUp) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (sort keys %{$SYSModulePowerSupplyUp{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $SYSModulePowerSupplyUp{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if (keys %SYSModulePowerOn) { print "\nModule power up on device :\n"; foreach my $ThisOne (sort keys %SYSModulePowerOn) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (sort keys %{$SYSModulePowerOn{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $SYSModulePowerOn{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if (keys %SYSModuleOk) { print "\nModule online on device :\n"; foreach my $ThisOne (sort keys %SYSModuleOk) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (sort keys %{$SYSModuleOk{$ThisOne}}) { print "\t Module " .$ThatOne . "\t: " . $SYSModuleOk{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if (keys %SYSModuleInserted) { print "\nModule inserted on device :\n"; foreach my $ThisOne (sort keys %SYSModuleInserted) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (sort keys %{$SYSModuleInserted{$ThisOne}}) { print "\t Module " .$ThatOne . "\t: " . $SYSModuleInserted{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if (keys %SYSModuleMinorFail) { print "\nModule minor failure on device :\n"; foreach my $ThisOne (sort keys %SYSModuleMinorFail) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (sort keys %{$SYSModuleMinorFail{$ThisOne}}) { print "\t Module " .$ThatOne . "\t: " . $SYSModuleMinorFail{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if (keys %SYSModuleReset) { print "\nModule reset on device :\n"; foreach my $ThisOne (sort keys %SYSModuleReset) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (sort keys %{$SYSModuleReset{$ThisOne}}) { print "\t Module " .$ThatOne . "\t: " . $SYSModuleReset{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if (keys %SYSWaitOnline) { print "\nSupervisor engine in the process on being online on device :\n"; foreach my $ThisOne (sort keys %SYSWaitOnline) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (sort keys %{$SYSWaitOnline{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $SYSWaitOnline{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if (keys %SYSModuleStandby) { print "\nModule standby on device :\n"; foreach my $ThisOne (sort keys %SYSModuleStandby) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (sort keys %{$SYSModuleStandby{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $SYSModuleStandby{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if (keys %SYSSupervisorEngineReset) { print "\nSupervisor engine reset on device :\n"; foreach my $ThisOne (sort keys %SYSSupervisorEngineReset) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (sort keys %{$SYSSupervisorEngineReset{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $SYSSupervisorEngineReset{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if (keys %SYSImgSyncStart) { print "\nSwitch of supervisor engine started :\n"; foreach my $ThisOne (sort keys %SYSImgSyncStart) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (sort keys %{$SYSImgSyncStart{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $SYSImgSyncStart{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if (keys %SYSSupervisorErr) { print "\nForwarding engine IP error :\n"; foreach my $ThisOne (sort keys %SYSSupervisorErr) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (sort keys %{$SYSSupervisorErr{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $SYSSupervisorErr{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if (keys %SYSImgSyncFinished) { print "\nSwitch of supervisor engine finished :\n"; foreach my $ThisOne (sort keys %SYSImgSyncFinished) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (sort keys %{$SYSImgSyncFinished{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $SYSImgSyncFinished{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if (keys %SNMPColdStart) { print "\nSNMP Cold (Re)start on device :\n"; foreach my $ThisOne (sort keys %SNMPColdStart) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (sort keys %{$SNMPColdStart{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $SNMPColdStart{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if (keys %Dot11Retrys) { print "\nAccess Point Dot11 Max retries on device :\n"; foreach my $ThisOne (sort keys %Dot11Retrys) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (sort keys %{$Dot11Retrys{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $Dot11Retrys{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if ($Detail >= 5 && keys %Dot11Assoc) { print "\nAccess Point Dot11 associated with device :\n"; foreach my $ThisOne (sort keys %Dot11Assoc) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (sort keys %{$Dot11Assoc{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $Dot11Assoc{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if ($Detail >= 5 && keys %Dot11Disassoc) { print "\nAccess Point Dot11 disassociated with device :\n"; foreach my $ThisOne (sort keys %Dot11Disassoc) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (sort keys %{$Dot11Disassoc{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $Dot11Disassoc{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if (keys %Dot11Roamed) { print "\nAccess Point Dot11 roaming with device :\n"; foreach my $ThisOne (sort keys %Dot11Roamed) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (sort keys %{$Dot11Roamed{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $Dot11Roamed{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if (keys %Dot11NoSSID) { print "\nAccess Point Dot11 no SSID with device :\n"; foreach my $ThisOne (sort keys %Dot11NoSSID) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (sort keys %{$Dot11NoSSID{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $Dot11NoSSID{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if (keys %Dot11FreqUsed) { print "\nAccess Point Dot11 Frequency selected with device :\n"; foreach my $ThisOne (sort keys %Dot11FreqUsed) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (sort keys %{$Dot11FreqUsed{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $Dot11FreqUsed{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if (keys %Dot11LoadingRadio) { print "\nAccess Point Dot11 Loading Radio firmware with device :\n"; foreach my $ThisOne (sort keys %Dot11LoadingRadio) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (sort keys %{$Dot11LoadingRadio{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $Dot11LoadingRadio{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if (keys %ICMP_Echo_Req) { print "\nICMP Echo Request on device :\n"; foreach my $ThisOne (sort keys %ICMP_Echo_Req) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (sort keys %{$ICMP_Echo_Req{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $ICMP_Echo_Req{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if (keys %NTPpeerSync) { print "\nNTP peer synced on device :\n"; foreach my $ThisOne (sort keys %NTPpeerSync) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (sort keys %{$NTPpeerSync{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $NTPpeerSync{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if (keys %NTPpeerReach) { print "\nNTP peer reachable on device :\n"; foreach my $ThisOne (sort keys %NTPpeerReach) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (sort keys %{$NTPpeerReach{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $NTPpeerReach{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if (keys %NTPpeerUnreach) { print "\nNTP peer unreachable on device :\n"; foreach my $ThisOne (sort keys %NTPpeerUnreach) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (sort keys %{$NTPpeerUnreach{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $NTPpeerUnreach{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if (keys %ACLmissed) { print "\nACL logging missed/rate-limited on device :\n"; foreach my $ThisOne (sort keys %ACLmissed) { print " " . $ThisOne . " : " . $ACLmissed{$ThisOne} . " Time(s)\n"; } } if (keys %dropigmp) { print "\nACL IGMP on device :\n"; foreach my $ThisOne (sort keys %dropigmp) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (sort keys %{$dropigmp{$ThisOne}}) { print "\t " .$ThatOne . "\t:\n"; foreach my $WhichOne (sort keys %{$dropigmp{$ThisOne}{$ThatOne}}) { print "\t " .$WhichOne . "\t: " . $dropigmp{$ThisOne}{$ThatOne}{$WhichOne} . " Time(s)\n"; } } } } if (keys %ICMP_Echo_Rep) { print "\nICMP Echo Reply on device :\n"; foreach my $ThisOne (sort keys %ICMP_Echo_Rep) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (sort keys %{$ICMP_Echo_Rep{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $ICMP_Echo_Rep{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if (keys %ACL) { print "\nAccess Control Lists:\n"; foreach my $ThisOne (sort {($a =~/\/(\d+)/)[0] <=> ($b =~ /\/(\d+)/)[0]} keys %ACL) { print " " . $ThisOne . " : " . $ACL{$ThisOne} . " Hit(s)\n"; } print " Total : " . $packets . " Hit(s)\n"; print " IPv6 Total : " . $IPV6_packets . " Hit(s)\n"; } if (keys %ACTION) { print "\nActions:\n"; foreach my $ThisOne (sort keys %ACTION) { print " " . $ThisOne . " : " . $ACTION{$ThisOne} . " Hit(s)\n"; } print " Total : " . $packets . " Hit(s)\n"; print " IPv6 Total : " . $IPV6_packets . " Hit(s)\n"; } if ($InspectDrop > 0) { print "\nInspect rule drops : $InspectDrop\n"; } if (keys %dropsmtphost) { print " SMTP servers:\n"; foreach my $ThisOne (sort SortIP keys %dropsmtphost) { if ($dropsmtphost{$ThisOne} > 1) { print " " . $ThisOne . " : " . $dropsmtphost{$ThisOne} . " Drops\n"; } } print " Total : " . $dropsmtppkts . "\n"; } if (keys %drophttphost) { print " HTTP servers:\n"; foreach my $ThisOne (sort SortIP keys %drophttphost) { if ($drophttphost{$ThisOne} > 1) { print " " . $ThisOne . " : " . $drophttphost{$ThisOne} . " Drop(s)\n"; } } print " Total : " . $drophttppkts . "\n"; } if ($JavaBlock > 0) { print "\nJAVA applet(s) blocked : $JavaBlock\n"; } if (keys %SSH) { print "\nSSH access:\n"; foreach my $ThisOne (sort SortIP keys %SSH) { print " " . $ThisOne . " : " . $SSH{$ThisOne} . " Hit(s)\n"; } print " Total : " . $SSH_packets . " Hit(s)\n"; } if (keys %OtherList) { print "\n**Unmatched Entries**\n"; $lines = 0; $count = 0; foreach $line (sort keys %OtherList) { if ($OtherList{$line} > 1 || $Detail >= 5) { print " $line: $OtherList{$line} Time(s)\n"; } else { $lines++; $count += $OtherList{$line}; } } if ($lines) { print " $count messages from $lines lines suppressed\n"; } } exit(0); # vi: shiftwidth=3 tabstop=3 syntax=perl et # Local Variables: # mode: perl # perl-indent-level: 3 # indent-tabs-mode: nil # End: logwatch-7.12/scripts/services/windows0000664000211400021140000004106714274101045020402 0ustar logwatchlogwatch ######################################################## # Please file all bug reports, patches, and feature # requests under: # https://sourceforge.net/p/logwatch/_list/tickets # Help requests and discusion can be filed under: # https://sourceforge.net/p/logwatch/discussion/ ######################################################## ########################################################################## # This is a logwatch script that looks at a log file composed of windows auth # security logs counts the number of times a user failed to login and # optionally the number times they successfully logged in and some other account # creation/modification audits. # # See the following sites for event id documentation: # http://www.microsoft.com/technet/prodtechnol/windowsserver2003/technologies/security/bpactlck.mspx # http://support.microsoft.com/?id=299475 # http://support.microsoft.com/?id=301677 ####################################################### ## Copyright (c) 2008 William Roumier ## Covered under the included MIT/X-Consortium License: ## http://www.opensource.org/licenses/mit-license.php ## All modifications and contributions by other persons to ## this script are assumed to have been donated to the ## Logwatch project and thus assume the above copyright ## and licensing terms. If you want to make contributions ## under your own copyright or a different license this ## must be explicitly stated in the contribution an the ## Logwatch project reserves the right to not accept such ## contributions. If you have made significant ## contributions to this script and want to claim ## copyright please contact logwatch-devel@lists.sourceforge.net. ######################################################### use Logwatch ':all'; use strict; my $detail = $ENV{'LOGWATCH_DETAIL_LEVEL'} || 0; #Init Hashes my ( %accountChanged, %accountDeleted, %accountEnabled, %accountTypeChange, %auditLogCleared, %auditPolChange, %changePasswordAttempt, %domainPolicyChanged, %firewall, %groupMemberAdded, %groupMemberRemoved, %ikeSecNegFail, %krbAuthFailByAccount, %krbAuthFailByHost, %lockedOut, %loginFailByAccount, %loginFailByHost, %loginSuccess, %newAccount, %newDomainTrust, %passwordSet, %renewed, %rightsAdded, %rightsRemoved, %rmDomainTrust, %second_total, %sgtGranted, %tgtGranted, %third_total, %unmatchedFail, ); my ($month, $day, $time, $host, $process, $eventid, $msg); # Loop through the given input and parse it first to make sure we need to, # then to sort it into various categories. while (defined(my $line = )) { ($month, $day, $time, $host, $process, $eventid, $msg) = split(/\s+/, $line, 7); chomp($host); chomp($process); chomp($eventid); chomp($msg); if ($process =~ /security\[failure\]/) { # failure events # First count the number of failed logins - we always want that. # Events 529 - 537, 539 if (($eventid >= 529 && $eventid <= 537) || $eventid == 539 || $eventid == 680) { $msg =~ /(User Name|Logon account):\s*(\S+)\s+.+(Address|Workstation( Name)?):\s*\\{0,2}(\S+)/; # print "DEBUG Logon Failure: name:$2 source:$4\n"; $loginFailByAccount{$2}{$5}++; $loginFailByHost{$5}{$2}++; } # IKE Failures: Events 544 - 547 #elsif ($eventid >= 544 && $eventid <= 547 && $line =~ /some_meaningful_pattern/) { #} elsif ($eventid == 547) { # IKE security association negotiation failed $msg =~ /IKE Peer Addr\s+(\S+)\s+.+Failure Reason:\s*(.+)\s+Extra Status:/; #print "DEBUG IKE security association negotiation failed: host:$host peer:$1 reason:$2\n"; $ikeSecNegFail{$host}{$1}{$2}++; } elsif ($eventid == 644) { # User Account Locked Out $msg =~ /Target Account Name:\s*(\S+)\s+.+Caller User Name:\s*(\S+)/; #print "DEBUG User Account Locked Out: $1 on $2 by $3\n"; $lockedOut{$host}{$1}{$2}++; } elsif ($eventid == 675 || $eventid == 676 || $eventid == 677) { # Kerberos authentication failed $msg =~ /User Name:\s*(\S+)\s+.+Client Address:\s*(\S+)/; #print "DEBUG Pre-Authentication failed: $1 on $2\n"; #$krbAuthFail{$host}{$1}{$2}++; $krbAuthFailByAccount{$1}{$2}++; $krbAuthFailByHost{$2}{$1}++; } #elsif ($eventid == 681) { # Logon Failure - not used in Windows 2003/XP # $msg =~ /The logon to account:\s*(\S+)\s+by:\s*(\S+)\s+from workstation:\s*(\S+)\s+failed/; # print "DEBUG Logon Failure to $1 by $2 from $3\n"; # $logonFailure{$1}{$2}{$3}++; #} elsif ($eventid == 861) { # The Windows Firewall has detected an application listenin for incoming traffic. $msg =~ /Path:\s*(\S+)\s+.+User account:\s*(\S+)\s+.+IP protocol:(\S+)\s+Port number:\s*(\S+)\s+Allowed:\s*(\S+)/; #print "DEBUG Server Application Firewalled: path:$1 account:$2 port:$3 $4 allowed:$5\n"; $firewall{$host}{$2}{$1}{$3}{$4}{$5}++; } else { # unmatched catch all chomp($msg); $unmatchedFail{$eventid . " " . $msg}++; } } elsif ($detail > 3 && $process =~ /security\[success\]/) { # success events if ($eventid == 528 || $eventid == 540 || $eventid == 680) { # Successful Logon $msg =~ /(User Name|Logon account|Account Name):\s*(\S+)\s+.+(Address|Workstation( Name)?):\s*\\{0,2}(\S+)/; if ($2 !~ /^-|\S+\$$/) { # ignore machines and anonymous #print "DEBUG Logon Success name:$2 source:$5\n"; $loginSuccess{$2}{$5}++; } } elsif ($eventid == 517) { # Audit log was cleared. $msg =~ /Primary User Name:\s*(\S+)\s+.*Client User Name:\s*(\S+)/; # print "DEBUG Audit log cleared: host:$host primary:$1 client:$2\n"; $auditLogCleared{$host}{$1}{$2}++; } elsif ($eventid == 608) { # User Right Assigned $msg =~ /User Right:\s*(\S+)\s+Assigned To:\s*(\S+)\s+Assigned By:\s+User Name:\s*(\S+)/; # print "DEBUG Rights Added: right:$1 to:$2 by:$3\n"; $rightsAdded{$host}{$3}{$2}{$1}++; } elsif ($eventid == 609) { # User Right Removed $msg =~ /User Right:\s*(\S+)\s+Removed From:\s*(\S+)\s+Removed By:\s+User Name:\s*(\S+)/; # print "DEBUG Rights Removed: right:$1 from:$2 by:$3\n"; $rightsRemoved{$host}{$3}{$2}{$1}++; } elsif ($eventid == 610) { # New Trusted Domain $msg =~ /New Trusted Domain\s+Domain( Name)?:\s*(\S+)\s+.*Established By:\s+User Name:\s*(\S+)/; # print "DEBUG New Trusted Domain: domain:$2 user:$3 host:$host\n"; $newDomainTrust{$host}{$2}{$3}++; } elsif ($eventid == 611) { # Removing Trusted Domain $msg =~ /Removing Trusted Domain\s+Domain( Name)?:\s*(\S+)\s+.*Established By:\s+User Name:\s*(\S+)/; # print "DEBUG New Trusted Domain: domain:$2 user:$3 host:$host\n"; $rmDomainTrust{$host}{$2}{$3}++; } elsif ($eventid == 612) { # Audit Policy Changed $msg =~ /Changed By:\s+User Name:\s*(\S+)/; # print "DEBUG Audit Policy Changed by $1 on $host\n"; $auditPolChange{$host}{$1}++; } # Group all account types together - should be clear what's what. elsif ($eventid == 624 || $eventid == 631 || $eventid == 635 || $eventid == 645 || $eventid == 653 || $eventid == 658 || $eventid == 663) { # Account Created $msg =~ /New Account Name:\s*(\S+)\s+.*Caller User Name:\s*(\S+)/; #print "DEBUG Account Created: $1 by $2 on $host\n"; $newAccount{$host}{$2}{$1}++; } elsif ($eventid == 625) { # User Account Type Change $msg =~ /Target Account Name:\s*(\S+)\s+.+New Type:\s*(\S+)\s*Caller User Name:\s*(\S+)/; # print "DEBUG User Account Type Change: $1 to $2 by $3 on $host\n"; $accountTypeChange{$host}{$3}{$1}{$2}++; } elsif ($eventid == 626) { # User Account Enabled $msg =~ /Target Account Name:\s*(\S+)\s+.+Caller User Name:\s*(\S+)/; # print "DEBUG User Account Enabled: $1 by $2 on $host\n"; $accountEnabled{$host}{$2}{$1}++; } elsif ($eventid == 627) { # Change Password Attempt $msg =~ /Target Account Name:\s*(\S+)\s+.+Caller User Name:\s*(\S+)/; # print "DEBUG Change Password Attempt: $1 by $2 on $host\n"; $changePasswordAttempt{$host}{$2}{$1}++; } elsif ($eventid == 628) { # User Account password set $msg =~ /Target Account Name:\s*(\S+)\s+.+Caller User Name:\s*(\S+)/; # print "DEBUG User Account password set: $1 by $2 on $host\n"; $passwordSet{$host}{$2}{$1}++; } elsif ($eventid == 630 || $eventid == 634 || $eventid == 638 || $eventid == 647 || $eventid == 652 || $eventid == 657 || $eventid == 662 || $eventid == 667) { # User Account Deleted $msg =~ /Target Account Name:\s*(\S+)\s+.+Caller User Name:\s*(\S+)/; # print "DEBUG Account Deleted: $1 by $2 on $host\n"; $accountDeleted{$host}{$2}{$1}++; } # Note: This doesn't distinguish between Global and Local Groups elsif ($eventid == 632 || $eventid == 636 || $eventid == 650 || $eventid == 655 || $eventid == 660 || $eventid == 665) { # Group Member Added $msg =~ /Member Name:\s*(\S+)\s+.+Target Account Name:\s*(\S+)\s+.+Caller User Name:\s*(\S+)/; # print "DEBUG Group Member Added: $1 to $2 by $3 on $host\n"; $groupMemberAdded{$host}{$2}{$3}{$1}++; } elsif ($eventid == 633 || $eventid == 637 || $eventid == 651 || $eventid == 656 || $eventid == 661 || $eventid == 666) { # Group Member Removed $msg =~ /Member Name:\s*(\S+)\s+.+Target Account Name:\s*(\S+)\s+.+Caller User Name:\s*(\S+)/; #print "DEBUG Group Member Removed: $1 to $2 by $3 on $host\n"; $groupMemberRemoved{$host}{$2}{$3}{$1}++; } elsif ($eventid == 639 || $eventid == 641 || $eventid == 642 || $eventid == 646 || $eventid == 649 || $eventid == 654 || $eventid == 659 || $eventid == 664 || $eventid == 668) { # Account Changed $msg =~ /Target Account Name:\s*(\S+)\s+.+Caller User Name:\s*(\S+)/; #print "DEBUG Account Changed: $1 by $2 on $host\n"; $accountChanged{$host}{$2}{$1}++; } elsif ($eventid == 643) { # Domain Policy Changed $msg =~ /Domain Policy Changed:\s*(.+) modified.+Caller User Name:\s*(\S+)/; #print "DEBUG Domain Policy Changed: $2 on $host to $1\n"; $domainPolicyChanged{$host}{$2}{$1}++; } elsif ($detail > 5 && $eventid == 672) { # Authentication Ticket Granted $msg =~ /User Name:\s*(\S+)\s+.+Service Name:\s*(\S+)\s+.+Client Address:\s*(\S+)/; #print "DEBUG TGT Granted to $1 for $2 from $3\n"; $tgtGranted{$host}{$1}{$2}{$3}++; } elsif ($detail > 5 && $eventid == 673) { # Service Ticket Granted $msg =~ /User Name:\s*(\S+)\s+.+Service Name:\s*(\S+)\s+.+Client Address:\s*(\S+)/; #print "DEBUG SGT Granted to $1 for $2 from $3\n"; $sgtGranted{$host}{$1}{$2}{$3}++; } elsif ($detail > 5 && $eventid == 674) { # Ticket Granted Renewed $msg =~ /User Name:\s*(\S+)\s+.+Service Name:\s*(\S+)\s+.+Client Address:\s*(\S+)/; #print "DEBUG Ticket Renewal granted to $1 for $2 from $3\n"; $renewed{$host}{$1}{$2}{$3}++; } } } # Always print login failures grouped by name and host in that order. if (keys %loginFailByAccount) { printLevel2("Windows Failed Logins by Account, Host", \%loginFailByAccount); } if (keys %loginFailByHost) { printLevel2("Windows Failed Logins by Host, Account", \%loginFailByHost); } if (keys %krbAuthFailByAccount) { printLevel2("Kerberos Authentication Failures by Account, Host", \%krbAuthFailByAccount); } if (keys %krbAuthFailByHost) { printLevel2("Kerberos Authentication Failures by Host, Account", \%krbAuthFailByHost); } if (keys %lockedOut) { printLevel3("Account Locked Out by Host, Target, Caller", \%lockedOut); } if (keys %ikeSecNegFail) { printLevel3("IKE Security Association Negotiation Failed by Host, Peer, Reason", \%ikeSecNegFail); } if (keys %unmatchedFail) { print "\t---- Unmatched Failure Audits ----\n\n"; foreach $msg (keys %unmatchedFail) { print "\t" . $unmatchedFail{$msg} . " Time(s): $msg\n"; } } # Start printing some other optional data like login successes, account creation/modification audits, etc. if ($detail > 3) { if (keys %loginSuccess) { printLevel2("Windows Successful Logins by Account, Host", \%loginSuccess); } if ($detail > 5) { if (keys %tgtGranted) { printLevel4("TGT Granted by Host, Account, Service, Client Addr", \%tgtGranted); } if (keys %sgtGranted) { printLevel4("SGT Granted by Host, Account, Service, Client Addr", \%sgtGranted); } if (keys %renewed) { printLevel4("Ticket Renewed by Host, Account, Service, Client Addr", \%renewed); } } if (keys %auditLogCleared) { printLevel3("Audit Log Cleared by Host, Primary Account, Client Account", \%auditLogCleared); } if (keys %rightsAdded) { printLevel4("User Rights Added by Host, Modifier, Account, Right", \%rightsAdded); } if (keys %rightsRemoved) { printLevel4("User Rights Removed by Host, Modifier, Account, Right", \%rightsRemoved); } if (keys %newDomainTrust) { printLevel3("New Domain Trust by Host, Domain, Modifier", \%newDomainTrust); } if (keys %rmDomainTrust) { printLevel3("Domain Trust Removed by Host, Domain, Modifier", \%rmDomainTrust); } if (keys %auditPolChange) { printLevel2("Audit Policy Changed by Host, Modifier", \%auditPolChange); } if (keys %newAccount) { printLevel3("New Accounts by Host, Modifier, Account", \%newAccount); } if (keys %accountTypeChange) { printLevel4("Account Type Changed by Host, Modifier, Account, Type", \%accountTypeChange); } if (keys %accountEnabled) { printLevel3("Account Enabled by Host, Modifier, Account", \%accountEnabled); } if (keys %changePasswordAttempt) { printLevel3("Change Password Attempt by Host, Modifier, Account", \%changePasswordAttempt); } if (keys %passwordSet) { printLevel3("Password Set by Host, Modifier, Account", \%passwordSet); } if (keys %accountDeleted) { printLevel3("Account Deleted by Host, Modifier, Account", \%accountDeleted); } if (keys %groupMemberAdded) { printLevel4("Group Member Added by Host, Group, Modifier, Account", \%groupMemberAdded); } if (keys %groupMemberRemoved) { printLevel4("Group Member Removed by Host, Group, Modifier, Account", \%groupMemberRemoved); } if (keys %accountChanged) { printLevel3("Account Changed by Host, Modifier, Account", \%accountChanged); } if (keys %domainPolicyChanged) { printLevel3("Domain Policy Changed by Host, Modifier, Change", \%domainPolicyChanged); } } # Prints a hash that's two levels deep in a generic hierarchical manor sub printLevel2 { my $msg = $_[0]; my %data = %{$_[1]}; print "\n\t---- $msg ----\n\n"; foreach my $first (sort(keys %data)) { my $total = 0; foreach my $second (keys %{$data{$first}}) { $total += $data{$first}{$second}; } print "\t" . LookupIP($first) . " $total Time(s)\n"; foreach my $second (sort(keys %{$data{$first}})) { print "\t\t" . LookupIP($second) . " " . $data{$first}{$second} . " Time(s)\n"; } print "\n"; } } # Prints a hash that's three levels deep in a generic hierarchical manor sub printLevel3 { my $msg = $_[0]; my %data = %{$_[1]}; print "\n\t---- $msg ----\n\n"; foreach my $first (sort(keys %data)) { my $first_total = 0; foreach my $second (keys %{$data{$first}}) { $second_total{$second} = 0; foreach my $third (keys %{$data{$first}{$second}}) { $second_total{$second} += $data{$first}{$second}{$third}; } $first_total += $second_total{$second}; } print "\t" . LookupIP($first) . ": $first_total Time(s)\n"; foreach my $second (sort(keys %{$data{$first}})) { print "\t\t" . LookupIP($second) . ": $second_total{$second} Time(s)\n"; foreach my $third (sort(keys %{$data{$first}{$second}})) { print "\t\t\t" . LookupIP($third) . " $data{$first}{$second}{$third} Time(s)\n"; } } print "\n"; } } # Prints a hash that's four levels deep in a generic hierarchical manor sub printLevel4 { my $msg = $_[0]; my %data = %{$_[1]}; print "\n\t---- $msg ----\n\n"; foreach my $first (sort(keys %data)) { my $first_total = 0; foreach my $second (keys %{$data{$first}}) { $second_total{$second} = 0; foreach my $third (keys %{$data{$first}{$second}}) { $third_total{$second}{$third} = 0; foreach my $fourth (keys %{$data{$first}{$second}{$third}}) { $third_total{$second}{$third} += $data{$first}{$second}{$third}{$fourth}; } $second_total{$second} += $third_total{$second}{$third}; } $first_total += $second_total{$second}; } print "\t" . LookupIP($first) . ": $first_total Time(s)\n"; foreach my $second (sort(keys %{$data{$first}})) { print "\t\t" . LookupIP($second) . ": $second_total{$second} Time(s)\n"; foreach my $third (sort(keys %{$data{$first}{$second}})) { print "\t\t\t" . LookupIP($third) . ": $third_total{$second}{$third} Time(s)\n"; foreach my $fourth (sort(keys %{$data{$first}{$second}{$third}})) { print "\t\t\t\t" . LookupIP($fourth) . " $data{$first}{$second}{$third}{$fourth} Time(s)\n"; } } } print "\n"; } } exit(0); # vi: shiftwidth=3 tabstop=3 syntax=perl et # Local Variables: # mode: perl # perl-indent-level: 3 # indent-tabs-mode: nil # End: logwatch-7.12/scripts/services/up2date0000664000211400021140000001217114274101045020246 0ustar logwatchlogwatch ######################################################## # Please file all bug reports, patches, and feature # requests under: # https://sourceforge.net/p/logwatch/_list/tickets # and copy: # Eric Moret # Help requests and discusion can be filed under: # https://sourceforge.net/p/logwatch/discussion/ ######################################################## ######################################################## # This was written and is maintained by: # Eric Moret ######################################################## ####################################################### ## Copyright (c) 2008 Eric Moret ## Covered under the included MIT/X-Consortium License: ## http://www.opensource.org/licenses/mit-license.php ## All modifications and contributions by other persons to ## this script are assumed to have been donated to the ## Logwatch project and thus assume the above copyright ## and licensing terms. If you want to make contributions ## under your own copyright or a different license this ## must be explicitly stated in the contribution an the ## Logwatch project reserves the right to not accept such ## contributions. If you have made significant ## contributions to this script and want to claim ## copyright please contact logwatch-devel@lists.sourceforge.net. ######################################################### use strict; my $Debug = $ENV{'LOGWATCH_DEBUG'} || 0; #my $Detail = $ENV{'LOGWATCH_DETAIL_LEVEL'} || 0; my $DebugCounter = 0; my $RHNRegistration = 0; my @OtherList = (); #Init Hashes my ( %PackageInstalled, %PackageAddedToProfile, %PackageRemovedFromProfile, ); if ( $Debug >= 5 ) { print STDERR "\n\nDEBUG: Inside up2date Filter \n\n"; $DebugCounter = 1; } while (defined(my $ThisLine = )) { if ( $Debug >= 5 ) { print STDERR "DEBUG($DebugCounter): $ThisLine"; $DebugCounter++; } if ( ( $ThisLine =~ /^updating login info$/ ) or ( $ThisLine =~ /^updateLoginInfo\(\) login info$/ ) or ( $ThisLine =~ /^Opening rpmdb in \/var\/lib\/rpm\/ with option .$/ ) or ( $ThisLine =~ /^successfully retrieved authentication token from up2date server$/ ) or ( $ThisLine =~ /^(getA|a)vailablePackageList from network$/ ) or ( $ThisLine =~ /^getAdvisoryInfo for / ) or ( $ThisLine =~ /^logging into up2date server$/ ) or ( $ThisLine =~ /^A socket error occurred/ ) or ( $ThisLine =~ /^new up2date run started/ ) or ( $ThisLine =~ /^Creating rollback packages\.\.\./ ) or ( $ThisLine =~ /^Updating transaction list/ ) or ( $ThisLine =~ /^A protocol error occurred/ ) or ( $ThisLine =~ /^Error communicating with server\.\s+The message was:$/ ) or ( $ThisLine =~ /^Updating package profile/) or ( $ThisLine =~ /^Unable to import repomd/) or ( $ThisLine =~ /^deleting \/var\/spool\/up2date\// ) or ( $ThisLine =~ /^solving dep for: \[('.*')*\]/) or ( $ThisLine =~ /^Adding [^ ]* to bootloader config/) or ( $ThisLine =~ /^Modifying bootloader config to include the new kernel info/) or ( $ThisLine =~ /rhn_register $/) or ( $ThisLine =~ /rhn_register Registered login info/) or ( $ThisLine =~ /rhn_register Wrote system id to disk/) or ( $ThisLine =~ /rhn_register Sent package list./) or ( $ThisLine =~ /rhn_register updating login info/) or ( $ThisLine =~ /rhn_register Sent hardware profile./) or ( $ThisLine =~ /rhn_register logging into up2date server/) or ( $ThisLine =~ /rhn_register successfully retrieved authentication token from up2date server/) or ( $ThisLine =~ /rhn_register An exception was raised causing login to fail. This is usually correct. Exception information:/) or ( $ThisLine =~ /^Running elilo with the new configuration/) ) { # We don't care about these } elsif ( $ThisLine =~ s/^installing packages: ([^ ]+)/$1/ ) { $PackageInstalled{$ThisLine}++; } elsif ( $ThisLine =~ s/^Adding packages to package profile: ([^ ]+)/$1/ ) { $PackageAddedToProfile{$ThisLine}++; } elsif ( $ThisLine =~ s/^Removing packages from package profile: ([^ ]+)/$1/ ) { $PackageRemovedFromProfile{$ThisLine}++; } elsif ( $ThisLine =~ /rhn_register Registered system./) { $RHNRegistration++; } else { # Report any unmatched entries... push @OtherList,$ThisLine; } } if (keys %PackageInstalled) { print "\nPackage Installed:\n"; foreach my $ThisOne (keys %PackageInstalled) { print " " . $ThisOne; } } if (keys %PackageAddedToProfile) { print "\nPackage Added To Profile:\n"; foreach my $ThisOne (keys %PackageAddedToProfile) { print " " . $ThisOne; } } if (keys %PackageRemovedFromProfile) { print "\nPackage Removed From Profile:\n"; foreach my $ThisOne (keys %PackageRemovedFromProfile) { print " ". $ThisOne; } } if ($RHNRegistration) { print "\nSystem registered to rhn " . $RHNRegistration . " time(s)\n"; } if ($#OtherList >= 0) { print "\n**Unmatched Entries**\n"; print @OtherList; } exit(0); # vi: shiftwidth=3 tabstop=3 syntax=perl et # Local Variables: # mode: perl # perl-indent-level: 3 # indent-tabs-mode: nil # End: logwatch-7.12/scripts/services/zz-runtime0000664000211400021140000000270014274101046021024 0ustar logwatchlogwatch ######################################################## # Please file all bug reports, patches, and feature # requests under: # https://sourceforge.net/p/logwatch/_list/tickets # Help requests and discusion can be filed under: # https://sourceforge.net/p/logwatch/discussion/ ######################################################## ####################################################### ## Copyright (c) 2008 Kirk Bauer ## Covered under the included MIT/X-Consortium License: ## http://www.opensource.org/licenses/mit-license.php ## All modifications and contributions by other persons to ## this script are assumed to have been donated to the ## Logwatch project and thus assume the above copyright ## and licensing terms. If you want to make contributions ## under your own copyright or a different license this ## must be explicitly stated in the contribution an the ## Logwatch project reserves the right to not accept such ## contributions. If you have made significant ## contributions to this script and want to claim ## copyright please contact logwatch-devel@lists.sourceforge.net. ######################################################### use strict; my $uptime=`uptime`; my $show_uptime = $ENV{'show_uptime'} || 0; if (($ENV{'PRINTING'} eq "y" ) && $show_uptime && $uptime) { print "\nUptime: $uptime\n"; } # vi: shiftwidth=3 tabstop=3 syntax=perl et # Local Variables: # mode: perl # perl-indent-level: 3 # indent-tabs-mode: nil # End: logwatch-7.12/scripts/services/resolver0000664000211400021140000000675014274101043020547 0ustar logwatchlogwatch ######################################################## # Please file all bug reports, patches, and feature # requests under: # https://sourceforge.net/p/logwatch/_list/tickets # Help requests and discusion can be filed under: # https://sourceforge.net/p/logwatch/discussion/ ######################################################## ############################################################################# #Copyright (c) 2004, Sparta, Inc #All rights reserved. # #Redistribution and use in source and binary forms, with or without #modification, are permitted provided that the following conditions are met: # #* Redistributions of source code must retain the above copyright notice, # this list of conditions and the following disclaimer. # #* Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # #* Neither the name of Sparta, Inc nor the names of its contributors may # be used to endorse or promote products derived from this software # without specific prior written permission. # #THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS #IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, #THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR #PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR #CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, #EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, #PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; #OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, #WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR #OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF #ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ############################################################################# ############################################################################# # These scripts were created as part of the dnssec-tools project. # For more information, see http://sourceforge.net/dnssec-tools. # Detailed instructions for setting up BIND 9.3.* to use these logwatch # configuration files and scripts are contained in the README file # on sourceforge. ############################################################################# use strict; my $detail = $ENV{'LOGWATCH_DETAIL_LEVEL'} || 0; my $valComplete; my $valOK; my $nonextValOK; while (defined(my $ThisLine = )) { if ($ThisLine =~ /validation completion event/) { $valComplete++; } elsif ($ThisLine =~ /nonexistence validation OK/) { $nonextValOK++; } elsif ($ThisLine =~ /validation OK/) { $valOK++; } } if ($detail >= 5) { my %msgHash = (); print "\n"; if ($valComplete > 0) { $msgHash{"Received validation completion event "} = $valComplete; } if ($nonextValOK > 0) { $msgHash{"Nonexistence validation OK received "} = $nonextValOK; } if ($valOK > 0) { $msgHash{"Validation OK "} = $valOK; } # sort all the non-zero message types and print them in descending order # of number of occurrences my $key; foreach $key (sort { $msgHash{$b} <=> $msgHash{$a} } keys %msgHash) { print " " . $key . " " . $msgHash{$key} . " time(s)\n"; } } exit (0); # vi: shiftwidth=3 tabstop=3 et # Local Variables: # mode: perl # perl-indent-level: 3 # indent-tabs-mode: nil # End: logwatch-7.12/scripts/services/sonicwall0000664000211400021140000006441714743365005020720 0ustar logwatchlogwatch ######################################################## # Please file all bug reports, patches, and feature # requests under: # https://sourceforge.net/p/logwatch/_list/tickets # and copy: # Laurent DUFOUR , # Help requests and discusion can be filed under: # https://sourceforge.net/p/logwatch/discussion/ ######################################################## ######################################################## # This was written and is maintained by: # Laurent DUFOUR , # based on the work of # Kirk Bauer ######################################################## ####################################################### ## Copyright (c) 2008 Laurent DUFOUR ## Covered under the included MIT/X-Consortium License: ## http://www.opensource.org/licenses/mit-license.php ## All modifications and contributions by other persons to ## this script are assumed to have been donated to the ## Logwatch project and thus assume the above copyright ## and licensing terms. If you want to make contributions ## under your own copyright or a different license this ## must be explicitly stated in the contribution an the ## Logwatch project reserves the right to not accept such ## contributions. If you have made significant ## contributions to this script and want to claim ## copyright please contact logwatch-devel@lists.sourceforge.net. ######################################################### use Logwatch ':all'; use strict; my $Debug = $ENV{'LOGWATCH_DEBUG'} || 0; my $Detail = $ENV{'LOGWATCH_DETAIL_LEVEL'} || 0; my $DebugCounter = 0; #Init String Containers my ( $Msg, $Temp, $args, $dst_ip, $dst_name, $host_id, $host_sn, $http_result, $interface, $interface_dst, $interface_src, $ip_proto, $number, $op_type, $pad, $port_dst, $port_src, $src_ip, $src_name, $url, $xfer_byte, $xfer_byte_rcvd, $xfer_byte_sent, $xfer_port_type, $xfer_way, ); #Init Array my @OtherList = (); #Init Hashes my ( %AccessRuleAdded, %BadAdminLogins, %BadLogins, %ByteReceived, %ByteSent, %DNSRefreshed, %ICMP_dropped, %IllegalUsers, %Msg, %NTPFailed, %NTPUpdated, %PortPacketReceived, %PortPacketSent, %ProtoPacketReceived, %ProtoPacketSent, %ReloadRequested, %Restarted, %Started, %SysCfgSaved, %SyslogFacility, %SyslogHost, %TCP_NULL_scan, %TCP_dropped, %TotalProtoByteReceived, %TotalProtoByteSent, %UDP_dropped, %URL_GET, %URL_HEAD, %URL_OTHER, %URL_POST, %Users, ); my %configConvert = ( 'human-readable' => 0, 'Human-readable' => 1, 'truncate-readable' => 2, ); # Taken from DiskUsage.pm inside Filesys-DiskUsage-0.02 # # Jose Castro, C<< # Please report any bugs or feature requests to # C, or through the web interface at # L. I will be notified, and then you'll # automatically be notified of progress on your bug as I make changes. # # Copyright 2004 Jose Castro, All Rights Reserved. # #This program is free software; you can redistribute it and/or modify it #under the same terms as Perl itself. # # # convert size to human readable format sub _convert { defined (my $size = shift) || return undef; my $config = {@_}; # $config->{human} || return $size; my $block = $config->{'Human-readable'} ? 1000 : 1024; my @args = qw/B K M G/; while (@args && $size > $block) { shift @args; $size /= $block; } if ($config->{'truncate-readable'} > 0) { $size = sprintf("%.$config->{'truncate-readable'}f",$size); } return "$size$args[0]"; } if ( $Debug >= 5 ) { print STDERR "\n\nDEBUG: Inside SONICWALL Filter \n\n"; $DebugCounter = 1; } my ($month,$day,$time,$host_ip,$host,$conn,$msg,$message); while (defined(my $ThisLine = )) { if ( $Debug >= 30 ) { print STDERR "DEBUG($DebugCounter): $ThisLine"; $DebugCounter++; } ($month,$day,$time,$host_ip,$host_id,$host_sn,$msg)=split(/ +/,$ThisLine,7); if ($ThisLine =~ /sn=/ ) { #mean that we ave to deal with a sonicwall log file line if ( ($ThisLine =~ /traffic/ ) or ($ThisLine =~ /Copyright/ ) or ($ThisLine =~ /removed due to simultaneous rekey/ ) or ($ThisLine =~ /Administrator logged out/ ) or ($ThisLine =~ /Connection (Closed|Opened)/ ) or ($ThisLine =~ /(TCP|UDP) connection dropped/ ) ) { # don't care about this, will code this later } elsif ( ($number,$src_ip,$port_src,$interface_src,$src_name,$dst_ip,$port_dst,$interface_dst,$dst_name,$pad) = ($ThisLine =~ /msg="UDP packet dropped" n=(\d+) src=(\d+\.\d+\.\d+\.\d+):(\d+):(WAN|LAN|DMZ):?(.*)? dst=(\d+\.\d+\.\d+\.\d+):(\d+):(WAN|LAN|DMZ):?(.*)? (.*)?/) ) { $UDP_dropped{$host_ip}{LookupIP($src_ip)," to ",LookupIP($dst_ip)}++ } elsif ( ($number,$src_ip,$port_src,$interface_src,$src_name,$dst_ip,$port_dst,$interface_dst,$dst_name,$pad) = ($ThisLine =~ /msg="TCP packet dropped" n=(\d+) src=(\d+\.\d+\.\d+\.\d+):(\d+):(WAN|LAN|DMZ):?(.*)? dst=(\d+\.\d+\.\d+\.\d+):(\d+):(WAN|LAN|DMZ):?(.*)? (.*)?/) ) { $TCP_dropped{$host_ip}{LookupIP($src_ip)," to ",LookupIP($dst_ip)}++ } elsif ( ($number,$src_ip,$port_src,$interface_src,$src_name,$dst_ip,$port_dst,$interface_dst,$dst_name,$pad) = ($ThisLine =~ /msg="ICMP packet dropped" n=(\d+) src=(\d+\.\d+\.\d+\.\d+):(\d+):(WAN|LAN|DMZ):?(.*)? dst=(\d+\.\d+\.\d+\.\d+):(\d+):(WAN|LAN|DMZ):?(.*)? (.*)?/) ) { $ICMP_dropped{$host_ip}{LookupIP($src_ip)," to ",LookupIP($dst_ip)}++ } elsif ( ($number,$src_ip,$port_src,$interface_src,$src_name,$dst_ip,$port_dst,$interface_dst,$dst_name,$ip_proto,$xfer_port_type,$op_type,$http_result) = ($ThisLine =~ /n=(\d+) src=(\d+\.\d+\.\d+\.\d+):(\d+):(WAN|LAN|DMZ):?(.*)? dst=(\d+\.\d+\.\d+\.\d+):(\d+):(WAN|LAN|DMZ):?(.*)? proto=(udp|tcp)\/(http|80) op=(HEAD|Other) result=(\d+)/) ) { if ($op_type eq "HEAD") { $URL_HEAD{$host_ip}{$url}++; } else { $URL_OTHER{$host_ip}{$url}++; } } elsif ( ($number,$src_ip,$port_src,$interface_src,$src_name,$dst_ip,$port_dst,$interface_dst,$dst_name,$ip_proto,$xfer_port_type,$op_type,$xfer_way,$xfer_byte,$http_result,$url,$args) = ($ThisLine =~ /n=(\d+) src=(\d+\.\d+\.\d+\.\d+):(\d+):(WAN|LAN|DMZ):?(.*)? dst=(\d+\.\d+\.\d+\.\d+):(\d+):(WAN|LAN|DMZ):?(.*)? proto=(udp|tcp|icmp)\/(http|80) op=(GET|POST) (rcvd|sent)=(\d+) result=(\d+) dstname=(.*) arg=(.*)(.*)/) ) { if ($op_type eq "GET") { $URL_GET{$host_ip}{$url}++; } else { $URL_POST{$host_ip}{$url}++; } if ($xfer_way eq "sent") { $ProtoPacketSent{$host_ip}{$ip_proto}++; $TotalProtoByteSent{$host_ip}{$ip_proto}=$TotalProtoByteSent{$host_ip}{$ip_proto}+$xfer_byte; if (($ip_proto eq "tcp") or ($ip_proto eq "udp")) { $ByteSent{$host_ip}{$ip_proto,"/",$xfer_port_type}=$ByteSent{$ip_proto}{$ip_proto,"/",$xfer_port_type}+$xfer_byte; $PortPacketSent{$host_ip}{$ip_proto,"/",$xfer_port_type}++; } } else { $ProtoPacketReceived{$host_ip}{$ip_proto}++; $TotalProtoByteReceived{$host_ip}{$ip_proto}=$TotalProtoByteReceived{$host_ip}{$ip_proto}+$xfer_byte; if (($ip_proto eq "tcp") or ($ip_proto eq "udp")) { $ByteReceived{$host_ip}{$ip_proto,"/",$xfer_port_type}=$ByteReceived{$ip_proto}{$ip_proto,"/",$xfer_port_type}+$xfer_byte; $PortPacketReceived{$host_ip}{$ip_proto,"/",$xfer_port_type}++; } } } elsif ( ($number,$src_ip,$port_src,$interface_src,$src_name,$dst_ip,$port_dst,$interface_dst,$dst_name,$ip_proto,$xfer_port_type,$op_type,$xfer_byte_sent,$xfer_byte_rcvd,$http_result,$url,$args) = ($ThisLine =~ /n=(\d+) src=(\d+\.\d+\.\d+\.\d+):(\d+):(WAN|LAN|DMZ):?(.*)? dst=(\d+\.\d+\.\d+\.\d+):(\d+):(WAN|LAN|DMZ):?(.*)? proto=(udp|tcp|icmp)\/(http|80) op=(GET|POST) sent=(\d+) rcvd=(\d+) result=(\d+) dstname=(.*) (arg=(.*))?/) ) { if ($op_type eq "GET") { $URL_GET{$host_ip}{$url}++; } else { $URL_POST{$host_ip}{$url}++; } $ProtoPacketSent{$host_ip}{$ip_proto}++; $TotalProtoByteSent{$host_ip}{$ip_proto}=$TotalProtoByteSent{$host_ip}{$ip_proto}+$xfer_byte_sent; if (($ip_proto eq "tcp") or ($ip_proto eq "udp")) { $ByteSent{$host_ip}{$ip_proto,"/",$xfer_port_type}=$ByteSent{$ip_proto}{$ip_proto,"/",$xfer_port_type}+$xfer_byte_sent; $PortPacketSent{$host_ip}{$ip_proto,"/",$xfer_port_type}++; } $ProtoPacketReceived{$host_ip}{$ip_proto}++; $TotalProtoByteReceived{$host_ip}{$ip_proto}=$TotalProtoByteReceived{$host_ip}{$ip_proto}+$xfer_byte_rcvd; if (($ip_proto eq "tcp") or ($ip_proto eq "udp")) { $ByteReceived{$host_ip}{$ip_proto,"/",$xfer_port_type}=$ByteReceived{$ip_proto}{$ip_proto,"/",$xfer_port_type}+$xfer_byte_rcvd; $PortPacketReceived{$host_ip}{$ip_proto,"/",$xfer_port_type}++; } } elsif ( ($number,$src_ip,$port_src,$interface_src,$src_name,$dst_ip,$port_dst,$interface_dst,$dst_name,$ip_proto,$xfer_port_type,$xfer_way,$xfer_byte) = ($ThisLine =~ /n=(\d+) src=(\d+\.\d+\.\d+\.\d+):(\d+):(WAN|LAN|DMZ):?(.*)? dst=(\d+\.\d+\.\d+\.\d+):(\d+):(WAN|LAN|DMZ):?(.*)? proto=(udp|tcp|icmp)\/(.*) (rcvd|sent)=(\d+)(.*)/) ) { if ($xfer_way eq "sent") { $ProtoPacketSent{$host_ip}{$ip_proto}++; $TotalProtoByteSent{$host_ip}{$ip_proto}=$TotalProtoByteSent{$host_ip}{$ip_proto}+$xfer_byte; if (($ip_proto eq "tcp") or ($ip_proto eq "udp")) { $ByteSent{$host_ip}{$ip_proto,"/",$xfer_port_type}=$ByteSent{$ip_proto}{$ip_proto,"/",$xfer_port_type}+$xfer_byte; $PortPacketSent{$host_ip}{$ip_proto,"/",$xfer_port_type}++; } } else { $ProtoPacketReceived{$host_ip}{$ip_proto}++; $TotalProtoByteReceived{$host_ip}{$ip_proto}=$TotalProtoByteReceived{$host_ip}{$ip_proto}+$xfer_byte; if (($ip_proto eq "tcp") or ($ip_proto eq "udp")) { $ByteReceived{$host_ip}{$ip_proto,"/",$xfer_port_type}=$ByteReceived{$ip_proto}{$ip_proto,"/",$xfer_port_type}+$xfer_byte; $PortPacketReceived{$host_ip}{$ip_proto,"/",$xfer_port_type}++; } } } #time="2005-03-23 09:03:27" fw=62.2.84.91 pri=5 c=128 m=37 msg="UDP packet dropped" n=3759 src=64.74.133.26:11379:WAN dst=62.2.84.91:33436:WAN^M #Mar 23 12:45:32 10.15.30.1 id=firewall sn=004010144097 time="2005-03-23 11:08:20" fw=62.2.84.91 pri=6 c=1024 m=98 n=61505 src=195.143.213.210:4992:WAN dst=62.2.84.92:1802:DMZ proto=tcp/1802 rcvd=106 ^M elsif ( ($dst_ip,$msg) = ($ThisLine =~ /System Config saved from host (\d+\.\d+\.\d+\.\d+) (.*)/) ) { $SysCfgSaved{$host_ip}{LookupIP($dst_ip)}++; } elsif ( ($dst_ip,$msg) = ($ThisLine =~ /The system configuration was saved from host (\d+\.\d+\.\d+\.\d+) by (.*)/) ) { $SysCfgSaved{$host_ip}{LookupIP($dst_ip)}++; } elsif ( ($ThisLine =~ /Compiled/) ) { $Started{$host_ip}++; } elsif ( ($ThisLine =~ /DNS entries have been automatically refreshed./) ) { $DNSRefreshed{$host_ip}++; } elsif ( ($ThisLine =~ /DNS has been refreshed./) ) { $DNSRefreshed{$host_ip}++; } elsif ( ($ThisLine =~ /Log successfully sent via email/) ) { $SyslogHost{$host_ip}{$host_ip}++; } elsif ( ($ThisLine =~ /Syslog facility has been changed/) ) { $SyslogFacility{$host_ip}++; } elsif ( ($ThisLine =~ /Syslog security facility has been changed/) ) { $SyslogFacility{$host_ip}++; } elsif ( ($ThisLine =~ /The system clock has been updated through NTP./) ) { $NTPUpdated{$host_ip}++; } elsif ( ($ThisLine =~ /failed to get clock through NTP/) ) { $NTPFailed{$host_ip}++; } elsif ( ($ThisLine =~ /Access Rule added/) ) { $AccessRuleAdded{$host_ip}++; } elsif ( ($message) = ($ThisLine =~ /RELOAD: (.*)/) ) { $ReloadRequested{$host_ip}{$message}++; } elsif ( ($message) = ($ThisLine =~ /RESTART: (.*)/) ) { $Restarted{$host_ip}{$message}++; } elsif ( $ThisLine =~ m/msg="Probable TCP NULL scan " n=(\d+) src=(\d+\.\d+\.\d+\.\d+) (.*)/ ) { if ( $Debug >= 5 ) { print STDERR "DEBUG: Found -TCP NULL scan- line\n"; } my $name = LookupIP($2); $Temp = "TCP NULL scan from $name"; $TCP_NULL_scan{$host_ip}{$Temp}++; } elsif ( ($interface) = ($ThisLine =~ /msg="Successful administrator login" n=(\d+) src=(\d+\.\d+\.\d+\.\d+) (.*)/) ) { if ($Debug >= 5) { print STDERR "DEBUG: Found -$1 logged in from $4 using $2\n"; } if ($Detail >= 20) { $Users{$host_ip}{"from ",$2}{"using port 80"}{$1}++; } else { $Users{$host_ip}{"from ",$2}{"using port 80"}{"(all)"}++; } } elsif ( ($interface) = ($ThisLine =~ /msg="(WAN zone administrator login allowed|Web management request allowed)" n=(\d+) usr=(\w+) src=(\d+\.\d+\.\d+\.\d+)(.*)?/) ) { if ($Debug >= 5) { print STDERR "DEBUG: Found -$1 logged in from $5 using $3\n"; } if ($Detail >= 20) { $Users{$host_ip}{"from ",$3}{"using port 80"}{$1}++; } else { $Users{$host_ip}{"from ",$3}{"using port 80"}{"(all)"}++; } } elsif ( $ThisLine =~ m/msg="Administrator login failed - incorrect password" n=(\d+) src=(\d+\.\d+\.\d+\.\d+) (.*)/ ) { if ( $Debug >= 5 ) { print STDERR "DEBUG: Found -Failed login- line\n"; } my $name = LookupIP($2); $Temp = "HTTP from $name"; $BadAdminLogins{$host_ip}{"Administrator login failed - incorrect password from $name"}++; $IllegalUsers{$host_ip}{$Temp}++; } elsif ( $ThisLine =~ m/msg="Unknown user attempted to log in" n=(\d+) src=(\d+\.\d+\.\d+\.\d+) dst=(\d+\.\d+\.\d+\.\d+) user=(.*)/ ) { if ( $Debug >= 5 ) { print STDERR "DEBUG: Found -Failed login- line\n"; } my $name = LookupIP($2); $Temp = "HTTP from $name"; $BadLogins{$host_ip}{"$4 user attempted to log in from $name"}++; $IllegalUsers{$host_ip}{$Temp}++; } elsif ( $ThisLine =~ m/SSH client at (.+) has attempted to make an SCS connection to interface untrust with IP (.+) but failed (.*)/ ) { my $name = LookupIP($2); $Temp = "SSH from $name"; $BadLogins{$host_ip}{$Temp}++; $IllegalUsers{$host_ip}{$Temp}++; } elsif ( ($Msg,$number,$src_ip,$port_src,$interface_src,$src_name,$dst_ip,$port_dst,$interface_dst,$dst_name,$pad) = ($ThisLine =~ /msg="(Ping of death dropped|Smurf Amplification attack dropped)" n=(\d+) src=(\d+\.\d+\.\d+\.\d+):(\d+):(WAN|LAN|DMZ):?(.*)? dst=(\d+\.\d+\.\d+\.\d+):(\d+):(WAN|LAN|DMZ):?(.*)?/) ) { $Msg{$host_ip}{$Msg," for ",LookupIP($src_ip)," to ",LookupIP($dst_ip)}++ } elsif ( ($Msg,$number,$src_ip,$port_src,$interface_src,$src_name,$dst_ip,$port_dst,$interface_dst,$dst_name,$pad) = ($ThisLine =~ /msg="(.*)" n=(\d+) src=(\d+\.\d+\.\d+\.\d+):(\d+):(WAN|LAN|DMZ):?(.*)? dst=(\d+\.\d+\.\d+\.\d+):(\d+):(WAN|LAN|DMZ):?(.*)?(S+)?(.*)?/) ) { $Msg{$host_ip}{$Msg," for ",LookupIP($src_ip)," to ",LookupIP($dst_ip)}++ } else { # Report any unmatched entries... push @OtherList,$ThisLine; } } } #end of mean we have a sonic wall logfile line if (keys %Started) { print "\nDevice started :\n"; foreach my $ThisOne (keys %Started) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (keys %{$Started{$ThisOne}}) { print "\t Started" .$ThatOne . "\t: " . $Started{$ThisOne}{$ThatOne} . "{ Time(s)\n"; } } } if (keys %UDP_dropped) { print "\nDevice where ip UDP packets have been dropped :\n"; foreach my $ThisOne (keys %UDP_dropped) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (keys %{$UDP_dropped{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $UDP_dropped{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if (keys %TCP_dropped) { print "\nDevice where ip TCP packets have been dropped :\n"; foreach my $ThisOne (keys %TCP_dropped) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (keys %{$TCP_dropped{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $TCP_dropped{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if (keys %ICMP_dropped) { print "\nDevice where ip ICMP packets have been dropped :\n"; foreach my $ThisOne (keys %ICMP_dropped) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (keys %{$ICMP_dropped{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $ICMP_dropped{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if (keys %Msg) { print "\nDevice others message :\n"; foreach my $ThisOne (keys %Msg) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (keys %{$Msg{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $Msg{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if ( ( $Detail >= 5 ) and (keys %URL_GET) ) { print "\nDevice URL GET :\n"; foreach my $ThisOne (keys %URL_GET) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (keys %{$URL_GET{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $URL_GET{$ThisOne}{$ThatOne} . " times(s)\n"; } } } if ( ( $Detail >= 5 ) and (keys %URL_POST) ) { print "\nDevice URL POST :\n"; foreach my $ThisOne (keys %URL_POST) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (keys %{$URL_POST{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $URL_POST{$ThisOne}{$ThatOne} . " times(s)\n"; } } } if ( ( $Detail >= 5 ) and (keys %URL_HEAD) ) { print "\nDevice URL HEAD :\n"; foreach my $ThisOne (keys %URL_HEAD) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (keys %{$URL_HEAD{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $URL_HEAD{$ThisOne}{$ThatOne} . " times(s)\n"; } } } if ( ( $Detail >= 5 ) and (keys %URL_OTHER) ) { print "\nDevice URL OTHER :\n"; foreach my $ThisOne (keys %URL_OTHER) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (keys %{$URL_OTHER{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $URL_OTHER{$ThisOne}{$ThatOne} . " times(s)\n"; } } } if ( ( $Detail >= 5 ) and (keys %ProtoPacketReceived) ) { print "\nDevice Total packets received by protocols :\n"; foreach my $ThisOne (keys %ProtoPacketReceived) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (keys %{$ProtoPacketReceived{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $ProtoPacketReceived{$ThisOne}{$ThatOne} . " packet(s)\n"; } } } if ( ( $Detail >= 5 ) and (keys %PortPacketReceived) ) { print "\nDevice Total packets received by ports :\n"; foreach my $ThisOne (keys %PortPacketReceived) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (keys %{$PortPacketReceived{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $PortPacketReceived{$ThisOne}{$ThatOne} . " packet(s)\n"; } } } if ( ( $Detail >= 5 ) and (keys %TotalProtoByteReceived) ) { print "\nDevice Total Bytes received by protocols :\n"; foreach my $ThisOne (keys %TotalProtoByteReceived) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (keys %{$TotalProtoByteReceived{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . _convert($TotalProtoByteReceived{$ThisOne}{$ThatOne}, %configConvert ) . " Byte(s)\n"; } } } if ( ( $Detail >= 5 ) and (keys %ByteReceived) ) { print "\nDevice Total Bytes received by ports :\n"; foreach my $ThisOne (keys %ByteReceived) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (keys %{$ByteReceived{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . _convert($ByteReceived{$ThisOne}{$ThatOne}, %configConvert ) . " Byte(s)\n"; } } } if ( ( $Detail >= 5 ) and (keys %ProtoPacketSent) ) { print "\nDevice Total packets sent by protocols :\n"; foreach my $ThisOne (keys %ProtoPacketSent) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (keys %{$ProtoPacketSent{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $ProtoPacketSent{$ThisOne}{$ThatOne} . " packet(s)\n"; } } } if ( ( $Detail >= 5 ) and (keys %PortPacketSent) ) { print "\nDevice Total packets sent by ports :\n"; foreach my $ThisOne (keys %PortPacketSent) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (keys %{$PortPacketSent{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $PortPacketSent{$ThisOne}{$ThatOne} . " packet(s)\n"; } } } if ( ( $Detail >= 5 ) and (keys %TotalProtoByteSent) ) { print "\nDevice Total Bytes sent by protocols :\n"; foreach my $ThisOne (keys %TotalProtoByteSent) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (keys %{$TotalProtoByteSent{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . _convert($TotalProtoByteSent{$ThisOne}{$ThatOne}, %configConvert ) . " Byte(s)\n"; } } } if ( ( $Detail >= 5 ) and (keys %ByteSent) ) { print "\nDevice Total Bytes sent by ports :\n"; foreach my $ThisOne (keys %ByteSent) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (keys %{$ByteSent{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . _convert($ByteSent{$ThisOne}{$ThatOne}, %configConvert ) . " Byte(s)\n"; } } } if (keys %NTPUpdated) { print "\nDevice where The system clock has been updated through NTP :\n"; foreach my $ThisOne (keys %NTPUpdated) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (keys %{$NTPUpdated{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $NTPUpdated{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if (keys %NTPFailed) { print "\nDevice where failed to get clock through NTP :\n"; foreach my $ThisOne (keys %NTPFailed) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (keys %{$NTPFailed{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $NTPFailed{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if (keys %DNSRefreshed) { print "\nDevice where DNS have been refreshed :\n"; foreach my $ThisOne (keys %DNSRefreshed) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (keys %{$DNSRefreshed{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $DNSRefreshed{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if (keys %SyslogFacility) { print "\nDevice where Syslog facility has been changed :\n"; foreach my $ThisOne (keys %SyslogFacility) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (keys %{$SyslogFacility{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $SyslogFacility{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if (keys %SyslogHost) { print "\nDevice where Syslog have been mail successfully :\n"; foreach my $ThisOne (keys %SyslogHost) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (keys %{$SyslogHost{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $SyslogHost{$ThisOne}{$ThisOne} . " Time(s)\n"; } } } if (keys %Restarted) { print "\nDevice restarted :\n"; foreach my $ThisOne (keys %Restarted) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (keys %{$Restarted{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $Restarted{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if (keys %AccessRuleAdded) { print "\nDevice where rules have been added :\n"; foreach my $ThisOne (keys %AccessRuleAdded) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (keys %{$AccessRuleAdded{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $AccessRuleAdded{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if (keys %ReloadRequested) { print "\nDevice reload requested :\n"; foreach my $ThisOne (keys %ReloadRequested) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (keys %{$ReloadRequested{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $ReloadRequested{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if (keys %SysCfgSaved) { print "\nDevice where system config have been saved :\n"; foreach my $ThisOne (keys %SysCfgSaved) { print " " . $ThisOne . ":\n"; foreach my $ThatOne (keys %{$SysCfgSaved{$ThisOne}}) { print "\t " .$ThatOne . "\t: " . $SysCfgSaved{$ThisOne}{$ThatOne} . " Time(s)\n"; } } } if (keys %BadLogins) { print "\nFailed logins from these:\n"; foreach my $ThisOne (keys %BadLogins) { print " " . $ThisOne . ":\n"; for (sort keys %{$BadLogins{$ThisOne}}) { print "\t $_: $BadLogins{$ThisOne}{$_} Time(s)\n"; } } } if (keys %TCP_NULL_scan) { print "\nDevice whcih had been ports scanned :\n"; foreach my $ThisOne (keys %TCP_NULL_scan) { print " " . $ThisOne . ":\n"; for (sort keys %{$TCP_NULL_scan{$ThisOne}}) { print "\t $_: $TCP_NULL_scan{$ThisOne}{$_} Time(s)\n"; } } } if (keys %BadAdminLogins) { print "\nFailed administrator logins from these:\n"; foreach my $ThisOne (keys %BadAdminLogins) { print " " . $ThisOne . ":\n"; for (sort keys %{$BadAdminLogins{$ThisOne}}) { print "\t $_: $BadAdminLogins{$ThisOne}{$_} Time(s)\n"; } } } if (keys %IllegalUsers) { print "\nIllegal users from these:\n"; foreach my $ThisOne (keys %IllegalUsers) { print " " . $ThisOne . ":\n"; for (sort keys %{$IllegalUsers{$ThisOne}}) { print "\t $_: $IllegalUsers{$ThisOne}{$_} Time(s)\n"; } } } if (keys %Users) { print "\nUsers logging in through :\n"; foreach my $ThisOne (keys %Users) { print " " . $ThisOne . ":\n"; foreach my $user (sort {$a cmp $b} keys %{$Users{$ThisOne}}) { print " $user:\n"; my $totalSort = TotalCountOrder(%{$Users{$ThisOne}{$user}}, \&SortIP); foreach my $ip (sort $totalSort keys %{$Users{$ThisOne}{$user}}) { my $name = LookupIP($ip); if ($Detail >= 20) { print " $name:\n"; my $sort = CountOrder(%{$Users{$ThisOne}{$user}{$ip}}); foreach my $method (sort $sort keys %{$Users{$ThisOne}{$user}{$ip}}) { my $val = $Users{$ThisOne}{$user}{$ip}{$method}; my $plural = ($val > 1) ? "s" : ""; print " $method: $val time$plural\n"; } } else { my $val = (values %{$Users{$ThisOne}{$user}{$ip}})[0]; my $plural = ($val > 1) ? "s" : ""; print " $name: $val time$plural\n"; } } } } } if ($#OtherList >= 0) { print "\n**Unmatched Entries**\n"; print @OtherList; } exit(0); # vi: shiftwidth=3 tabstop=3 syntax=perl et # Local Variables: # mode: perl # perl-indent-level: 3 # indent-tabs-mode: nil # End: logwatch-7.12/scripts/services/sshd20000664000211400021140000000445114274101044017726 0ustar logwatchlogwatch ######################################################## # Please file all bug reports, patches, and feature # requests under: # https://sourceforge.net/p/logwatch/_list/tickets # and copy: # Gerald Teschl # Help requests and discusion can be filed under: # https://sourceforge.net/p/logwatch/discussion/ ######################################################## ######################################################## # This was written and is maintained by: # Gerald Teschl ######################################################## ####################################################### ## Copyright (c) 2008 Kirk Bauer ## Covered under the included MIT/X-Consortium License: ## http://www.opensource.org/licenses/mit-license.php ## All modifications and contributions by other persons to ## this script are assumed to have been donated to the ## Logwatch project and thus assume the above copyright ## and licensing terms. If you want to make contributions ## under your own copyright or a different license this ## must be explicitly stated in the contribution an the ## Logwatch project reserves the right to not accept such ## contributions. If you have made significant ## contributions to this script and want to claim ## copyright please contact logwatch-devel@lists.sourceforge.net. ######################################################### use strict; my $Detail = $ENV{'LOGWATCH_DETAIL_LEVEL'} || 0; my $Started = 0; my %OtherList; while (defined(my $ThisLine = )) { if ( ($ThisLine =~ /^Daemon is running.$/) or ($ThisLine =~ /^Listener created on port .*$/) or ($ThisLine =~ /^sshd2$/) ) { # don't care about these } elsif ( $ThisLine =~ /^Starting sshd2: $/ ) { $Started++; } else { # Report any unmatched entries... chomp($ThisLine); $OtherList{$ThisLine}++; } } if ( ($Detail >= 10) and ($Started) ) { print "\nStatistics:\n"; print " Sshd2 started: $Started Time(s)\n"; } if (keys %OtherList) { print "\n**Unmatched Entries**\n"; foreach my $ThisOne (keys %OtherList) { print "$ThisOne: $OtherList{$ThisOne} Time(s)\n"; } } exit(0); # vi: shiftwidth=3 tabstop=3 syntax=perl et # Local Variables: # mode: perl # perl-indent-level: 3 # indent-tabs-mode: nil # End: logwatch-7.12/scripts/services/ipop3d0000664000211400021140000000762214274101037020106 0ustar logwatchlogwatch ######################################################## # Please file all bug reports, patches, and feature # requests under: # https://sourceforge.net/p/logwatch/_list/tickets # Help requests and discusion can be filed under: # https://sourceforge.net/p/logwatch/discussion/ ######################################################## ##################################################### ## Copyright (c) 2008 Pawel Jarosz ## Covered under the included MIT/X-Consortium License: ## http://www.opensource.org/licenses/mit-license.php ## All modifications and contributions by other persons to ## this script are assumed to have been donated to the ## Logwatch project and thus assume the above copyright ## and licensing terms. If you want to make contributions ## under your own copyright or a different license this ## must be explicitly stated in the contribution an the ## Logwatch project reserves the right to not accept such ## contributions. If you have made significant ## contributions to this script and want to claim ## copyright please contact logwatch-devel@lists.sourceforge.net. ######################################################### use strict; my $Detail = $ENV{'LOGWATCH_DETAIL_LEVEL'} || 0; my %Conn_loginok; my %Conn_loginfail; my %Connections; my %OtherList; while (defined(my $ThisLine = )) { chomp($ThisLine); #Solaris ID filter -mgt $ThisLine =~ s/\[ID [0-9]+ [a-z]+\.[a-z]+\] //; # next unless ( $ThisLine=~s/^... .. ..:..:.. [^ ]+ ipop3d\[\d+\]: //); #For testing only next unless (defined($ThisLine)); if ( $ThisLine =~/^Command stream end of file/ ) { next; } if ( $ThisLine =~/^(Autol|L)ogout/ ) { next; } if ( $ThisLine =~/^Trying to get mailbox lock/ ) { next; } if ( $ThisLine =~/^Connection reset by peer/ ) { next; } if ( $ThisLine =~/^Error opening or locking/ ) { next; } if ( $ThisLine =~/^Login failure user=(\S+) host=[\w\. 0-9\-]*\[(\d+.\d+.\d+.\d+)\]/ || $ThisLine =~/^Login failed user=(\S+) auth=\S+ host=[\w\. 0-9\-]*\[(\d+.\d+.\d+.\d+)\]/ || $ThisLine =~/^Login excessive login failures user=(\S+) auth=\S+ host=[\w\. 0-9\-]*\[(\d+.\d+.\d+.\d+)\]/ ) { $Conn_loginfail{$1}{$2}++; next; } if ( $ThisLine =~/service init from (\d+.\d+.\d+.\d+)$/ ) { $Connections{$1}++; next; } if ( $ThisLine =~/^(Login|Auth|APOP|Update) user=(\S+) host=[^\[]*\[(\d+.\d+.\d+.\d+)\]/ ) { $Conn_loginok{$2}{$3}++; next; } if ( $ThisLine =~/^AUTHENTICATE (\S+) failure host=[\w\. 0-9\-]*\[(\d+.\d+.\d+.\d+)\]/ ) { $Conn_loginfail{$1}{$2}++; next; } # Report any unmatched entries... $OtherList{$ThisLine}++; } if ( (keys %Connections) and ($Detail >= 15) ) { print "\nInitialized Connections:\n"; foreach my $ThisOne (sort {$Connections{$b}<=>$Connections{$a}} keys %Connections) { printf " %4i from %s\n" , $Connections{$ThisOne} , $ThisOne; } } if ( (keys %Conn_loginfail) and ($Detail >= 5) ) { print "\nFailed to log in:\n"; foreach my $user (keys %Conn_loginfail) { print "User: $user from:\n"; foreach my $host ( sort keys %{ $Conn_loginfail{$user} } ) { printf " %-35s %4i\n",$host,$Conn_loginfail{$user}{$host}; } } } if ( (keys %Conn_loginok) and ($Detail >=15) ) { print "\nSuccess in log in:\n"; foreach my $user (keys %Conn_loginok) { print "User: $user from:\n"; foreach my $host ( sort keys %{ $Conn_loginok{$user} } ) { printf " %-35s %4i\n",$host,$Conn_loginok{$user}{$host}; } } } if (keys %OtherList) { print "\n**Unmatched Entries**\n"; foreach my $line (sort {$OtherList{$b}<=>$OtherList{$a} } keys %OtherList) { print " $line: $OtherList{$line} Time(s)\n"; } } exit(0); # vi: shiftwidth=3 tabstop=3 syntax=perl et # Local Variables: # mode: perl # perl-indent-level: 3 # indent-tabs-mode: nil # End: logwatch-7.12/scripts/services/mailscanner0000664000211400021140000007225114274101040021176 0ustar logwatchlogwatch ######################################################## # Please file all bug reports, patches, and feature # requests under: # https://sourceforge.net/p/logwatch/_list/tickets # and copy: # Mike Tremaine # Help requests and discusion can be filed under: # https://sourceforge.net/p/logwatch/discussion/ ######################################################## ######################################################## # This was written and is maintained by: # Mike Tremaine # # Sophos Support and other improvements by Mark W. Nienberg # MailScan_Spam_Act contributed by Kev Green # # Some more clean up rules based on extensive use of some MailScanner # settings and F-Prot and ClamAV as dual scanners by Hugo van der Kooij # # More F-Prot code from John Wilcock # ######################################################## ##################################################### ## Copyright (c) 2008 Mike Tremaine ## Covered under the included MIT/X-Consortium License: ## http://www.opensource.org/licenses/mit-license.php ## All modifications and contributions by other persons to ## this script are assumed to have been donated to the ## Logwatch project and thus assume the above copyright ## and licensing terms. If you want to make contributions ## under your own copyright or a different license this ## must be explicitly stated in the contribution an the ## Logwatch project reserves the right to not accept such ## contributions. If you have made significant ## contributions to this script and want to claim ## copyright please contact logwatch-devel@lists.sourceforge.net. ######################################################### #use diagnostics; use strict; my $Detail = $ENV{'LOGWATCH_DETAIL_LEVEL'} || 0; my $phishing_detail = $ENV{'mailscanner_phishing_detail'} || 0; my $mailscanner_phishingthreshold = $ENV{'mailscanner_phishingthreshold'} || 0; #Init Counters my $MailScan_bytes = my $MailScan_Content = my $MailScan_Delivered = my $MailScan_Other = my $MailScan_RBL = my $MailScan_Received = my $MailScan_Spam = my $MailScan_Unscanned = my $MailScan_Virus = my $SA_timeout = my $MailScan_ScannerTimeout = my $MailScan_GoodWatermark = my $MailScan_BadWatermark = my $MailScan_SkipWatermark = my $SpamAssassin_Rule_Actions = my $MailScan_Deleted_pdb = my $MailScan_Found_pdb = my $MailScan_Spam_Virus = my $MailScan_VirtualHost= my $MailScan_Virus_Antivir= my $MailScan_Virus_BitDefender= my $MailScan_Virus_ClamAv= my $MailScan_Virus_Clamd= my $MailScan_Virus_ClamAVModule= my $MailScan_Virus_Fprot= my $MailScan_Virus_McAfee= my $MailScan_Virus_Kaspersky= my $MailScan_Virus_Sophos= my $MailScan_Virus_SophosSavi= my $MailScan_FilenameAllow= my $MailScan_FilenameBanned= my $MailScan_FiletypeAllow= my $MailScan_FiletypeBanned= my $MailScan_Whitelisted= my $MailScan_Blacklisted= my $MailScan_Phishing= my $MailScan_FormTag= my $MailScan_ScriptTag= my $MailScan_IframeTag= my $MailScan_ObjectTag= my $MailScan_ImgTag= my $MailWatchSQL= my $DisarmedQuarantined= my $SACacheHit= my $MailScan_Skipwatermark= 0; #Initalize hashes my ( %Spam_Virus_Found, %OtherList, %SpamAssassin_Action, %SpamAssassin_Message, %ImgTagSource, %ObjectTagSource, %SpamAssassin_Rule, %IframeTagSource, %FormTagSource, %ScriptTagSource, %PhishingSourceDest, %PhishingSource, %FilenameAllow, %FiletypeAllow, %FilenameType, %FiletypeType, %ContentType, %RBLType, %Blacklisted_Host, %Whitelisted_Host, %Hostlist, %VirusType_Antivir, %VirusType_BitDefender, %VirusType_ClamAv, %VirusType_Clamd, %VirusType_Fprot, %VirusType_ClamAVModule, %VirusType_McAfee, %VirusType_Kaspersky, %VirusType_Sophos, %MailScan_Spam_Act, %VirusScannerTimeout, %VirusType_SophosSavi, ); while (defined(my $ThisLine = )) { #($QueueID) = ($ThisLine =~ m/^([a-zA-Z0-9]+): / ); $ThisLine =~ s/^[a-zA-Z0-9]+: //; if ( ( $ThisLine =~ m/^Saved infected/ ) or ( $ThisLine =~ m/^Expanding TNEF archive/ ) or #TNEF Noise remove for now. IF anyone wants this counted just speak up -mgt ( $ThisLine =~ m/has had TNEF winmail.dat removed/ ) or ( $ThisLine =~ m/added TNEF contents/ ) or ( $ThisLine =~ m/^Warned about/ ) or ( $ThisLine =~ m/^Sender Warnings:/ ) or ( $ThisLine =~ m/X-Spam/ ) or ( $ThisLine =~ m/Using locktype = (flock|posix)/ ) or ( $ThisLine =~ m/Creating hardcoded struct_flock subroutine for / ) or ( $ThisLine =~ m/New Batch: Found/ ) or ( $ThisLine =~ m/Attempting to disinfect/ ) or ( $ThisLine =~ m/Rescan found/ ) or ( $ThisLine =~ m/Virus Re-scanning:/ ) or ( $ThisLine =~ m/Content Checks: Fixed awkward MIME boundary for Cyrus IMAP/ ) or ( $ThisLine =~ m/Delete bayes lockfile/ ) or ( $ThisLine =~ m/MailScanner E-Mail Virus Scanner version/ ) or ( $ThisLine =~ m/MailScanner child dying of old age/ ) or ( $ThisLine =~ m/MailScanner child caught a SIGHUP/ ) or ( $ThisLine =~ m/Virus and Content Scanning/ ) or ( $ThisLine =~ m/Virus Scanning: [\w]+ found/ ) or ( $ThisLine =~ m/Found spam based virus Sanesecurity\./ ) or ( $ThisLine =~ m/Virus Scanning: ClamAV Module found [\d]+ infections/ ) or ( $ThisLine =~ m/^ClamAV virus database has been updated/ ) or ( $ThisLine =~ m/^ClamAV update of/ ) or ( $ThisLine =~ m/^ClamAV scanner using unrar command / ) or ( $ThisLine =~ m/Saved entire message to/ ) or ( $ThisLine =~ m/Spam Checks: Starting/ ) or ( $ThisLine =~ m/SophosSAVI .+ recognizing [0-9]+ viruses/ ) or ( $ThisLine =~ m/SophosSAVI using [0-9]+ IDE files/ ) or ( $ThisLine =~ m/Sophos SAVI library has been updated/ ) or ( $ThisLine =~ m/Sophos.*update.* detected, resetting SAVI/ ) or #( $ThisLine =~ m/RBL checks: .+ found in RFC-IGNORANT-POSTMASTER/ ) or ( $ThisLine =~ m/F-Prot found/ ) or ( $ThisLine =~ m/SpamAssassin Bayes database rebuild starting|preparing|completed/ ) or ( $ThisLine =~ m/Rebuilding SpamAssassin Bayes database/ ) or ( $ThisLine =~ m/Skipping SpamAssassin while waiting for Bayes/ ) or ( $ThisLine =~ m/Enabling SpamAssassin auto-whitelist functionality/ ) or ( $ThisLine =~ m/Bayes database rebuild is due/ ) or ( $ThisLine =~ m/Content Checks: Detected and will convert|disarm HTML/ ) or ( $ThisLine =~ m/Content Checks: Detected and have disarmed HTML message/ ) or ( $ThisLine =~ m/Content Checks: Found [0-9]+ problems/ ) or ( $ThisLine =~ m/Read [0-9]+ hostnames from the phishing whitelist/ ) or ( $ThisLine =~ m/completed at [0-9]+ bytes per second/ ) or ( $ThisLine =~ m/Message .+ from .+ to .+ is/ ) or ( $ThisLine =~ m/^[A-F0-9]+\.[A-F0-9]{5} to/ ) or #for postfix Requeue: ( $ThisLine =~ m/^calling custom .* function/ ) or ( $ThisLine =~ m/^Initialising database connection/ ) or ( $ThisLine =~ m/^Finished initialising database connection/ ) or ( $ThisLine =~ m/^Disconnected from the database/ ) or ( $ThisLine =~ m/^ tag found in message/ ) or ( $ThisLine =~ m/^Viruses marked as silent:/ ) or ( $ThisLine =~ m/^Saved archive copies of/ ) or ( $ThisLine =~ m/^Logging message .+ to SQL/ ) or ( $ThisLine =~ m/^Started SQL Logging child/ ) or ( $ThisLine =~ m/^Starting up SQL Whitelist|Blacklist/ ) or ( $ThisLine =~ m/^Read .+ whitelist|blacklist entries/ ) or ( $ThisLine =~ m/^Closing down by-domain spam whitelist|blacklist/ ) or ( $ThisLine =~ m/^Connected to SpamAssassin cache database/ ) or ( $ThisLine =~ m/^Using SpamAssassin results cache/ ) or ( $ThisLine =~ m/^Expired .+ records from the SpamAssassin cache/ ) or ( $ThisLine =~ m/^Batch (\([0-9]+ messages?\) )?processed in .+ seconds/ ) or ( $ThisLine =~ m/^\"Always Looked Up Last\" took .+ seconds/ ) or ( $ThisLine =~ m/^MailScanner child dying after Bayes rebuild/ ) or ( $ThisLine =~ m/^Files hidden in very deeply nested archive/ ) or #IPBlocking -mgt ( $ThisLine =~ m/^Initialising IP blocking/ ) or ( $ThisLine =~ m/^Closing down IP blocking/ ) or ( $ThisLine =~ m/Whitelist refresh time reached/ ) or ( $ThisLine =~ m/Skipping sender of precedence list/ ) or ( $ThisLine =~ m/^Read \d+ IP blocking entries from/ ) or #This for Kaspersky I guess it is duplicated by Content checks, remove if not -mgt ( $ThisLine =~ m/^\/var\/spool\/MailScanner\/incoming\/.+SUSPICION/ ) or # New processing database ( $ThisLine =~ m/Connected to [Pp]rocessing(?:-messages| Attempts) [Dd]atabase/ ) or ( $ThisLine =~ m/Found 0 messages in the [Pp]rocessing(?:-messages| Attempts) [Dd]atabase/ ) or ( $ThisLine =~ m/Reading configuration file/ ) or ( $ThisLine =~ m/^SpamAssassin temporary working directory is/ ) or ( $ThisLine =~ m/ignored whitelist, had .+ recipients/ ) ) { # We don't care about these } elsif ( $ThisLine =~ m/New Batch: Scanning ([0-9]+) messages, ([0-9]+) bytes/i) { $MailScan_Received = $MailScan_Received + $1; $MailScan_bytes = $MailScan_bytes + $2; } elsif ( $ThisLine =~ m/New Batch: Forwarding ([0-9]+) unscanned messages, ([0-9]+) bytes/i) { $MailScan_Received = $MailScan_Received + $1; $MailScan_Unscanned = $MailScan_Unscanned + $1; $MailScan_bytes = $MailScan_bytes + $2; } elsif ( $ThisLine =~ m/Delivered ([0-9]+)( cleaned)? messages/) { $MailScan_Delivered = $MailScan_Delivered + $1; } elsif ( $ThisLine =~ m/Spam Checks: Found ([0-9]+) spam messages/) { $MailScan_Spam = $MailScan_Spam + $1; } elsif ( $ThisLine =~ m/Virus Scanning: Found ([0-9]+) viruses/) { $MailScan_Virus = $MailScan_Virus + $1; } elsif ( $ThisLine =~ m/Found spam-virus (\S+) in/i) { $MailScan_Spam_Virus++; $Spam_Virus_Found{$1}++; } elsif ( $ThisLine =~ m/infected message .+ came from (.*)/i) { $MailScan_VirtualHost = $MailScan_VirtualHost + 1; $Hostlist{$1}++; } elsif ( $ThisLine =~ m/Other Checks: Found ([0-9]+) problems/) { $MailScan_Other = $MailScan_Other + $1; } elsif ($ThisLine =~ m/Contains signature of the worm (.+)/) { $VirusType_Antivir{$1}++; $MailScan_Virus_Antivir++; } elsif ($ThisLine =~ m/:infected: (.+)/i) { #without the leading : this would match Fprot so error on the side of matching to much -mgt $VirusType_BitDefender{$1}++; $MailScan_Virus_BitDefender++; } elsif ( ($ThisLine =~ m/^\/var\/spool\/MailScanner\/incoming\/.+: ([\w\_\-\.\/]+) FOUND/i) or ($ThisLine =~ m/Clamd::INFECTED:: ?(\S+) ::/i) ) { $VirusType_ClamAv{$1}++; $MailScan_Virus_ClamAv++; } elsif ($ThisLine =~ m/ClamAVModule::INFECTED:: ?(.+)::/) { $VirusType_ClamAVModule{$1}++; $MailScan_Virus_ClamAVModule++; } elsif ($ThisLine =~ m/INFECTED:: ?(.+) (FOUND )?::/) { $VirusType_Clamd{$1}++; $MailScan_Virus_Clamd++; } elsif ($ThisLine =~ m/\/.+ Infection: (.+)/i) { $VirusType_Fprot{$1}++; $MailScan_Virus_Fprot++; } elsif ($ThisLine =~ m/\/.+ is a security risk named (.+)/i) { $VirusType_Fprot{$1}++; $MailScan_Virus_Fprot++; } elsif ($ThisLine =~ m/\/.+ is a dropper for (.+)/i) { $VirusType_Fprot{$1}++; $MailScan_Virus_Fprot++; } elsif ($ThisLine =~ m/\/.+ contains (.+)/i) { $VirusType_Fprot{$1}++; $MailScan_Virus_Fprot++; } elsif ($ThisLine =~ m/\/.+ could be/i) { $MailScan_Virus_Fprot++; } elsif ($ThisLine =~ m/Found the (.+) virus !!!/) { $VirusType_McAfee{$1}++; $MailScan_Virus_McAfee++; } elsif ($ThisLine =~ m/^\/var\/spool\/MailScanner\/incoming\/.+INFECTED\s+([\w\_\-\.\/]+)/i) { $VirusType_Kaspersky{$1}++; $MailScan_Virus_Kaspersky++; } elsif ($ThisLine =~ m/infected:\s+([\w\_\-\.\/]+)\^M/i) { $VirusType_Kaspersky{$1}++; $MailScan_Virus_Kaspersky++; } elsif ($ThisLine =~ m/>>> Virus \'(.+)\' found/) { $VirusType_Sophos{$1}++; $MailScan_Virus_Sophos++; } elsif ($ThisLine =~ m/SophosSAVI::INFECTED:: ?(.+)::/) { $VirusType_SophosSavi{$1}++; $MailScan_Virus_SophosSavi++; } elsif ($ThisLine =~ m/Commercial scanner (.+) timed out!/){ $VirusScannerTimeout{$1}++; $MailScan_ScannerTimeout++; } elsif ($ThisLine =~ m/Content Checks: Detected and have disarmed (.+) in HTML message in [\w]+/i) { $ContentType{$1}++; $MailScan_Content++; } elsif ($ThisLine =~ m/Content Checks: Detected (.+) in [\w]+/i) { $ContentType{$1}++; $MailScan_Content++; } elsif ($ThisLine =~ m/Filename Checks: Allowing (.+)/i) { if ($ThisLine =~ m/Allowing.*msg\-[0-9]*\-[0-9]*\.[txt|dat|html]/) { # we don't care about these, regular messages } else { #filter sendmail or postfix tag and "(no rule matched)" my $temp_fc = $1; $temp_fc =~ s/[a-z0-9]{14}\s//i; $temp_fc =~ s/[a-z0-9]{9,12}\.[a-z0-9]{5}\s//i; $temp_fc =~ s/\(no rule matched\)//i; $FilenameAllow{$temp_fc}++; $MailScan_FilenameAllow++; } } elsif ($ThisLine =~ m/Filename Checks: (.+)/i) { #filter sendmail or postfix tag my $temp_fc = lc($1); $temp_fc =~ s/\([a-z0-9]{14}\s/\(/i; $temp_fc =~ s/\([a-z0-9]{9,12}\.[a-z0-9]{5}\s/\(/i; $temp_fc =~ s/\s{10,}/ -space- /; $FilenameType{$temp_fc}++; $MailScan_FilenameBanned++; } elsif ($ThisLine =~ m/Filetype Checks: Allowing (.+)/i) { if ($ThisLine =~ m/Allowing.*msg\-[0-9]*\-[0-9]*\.[txt|dat|html]/) { # we don't care about these, regular messages } else { #filter sendmail or postfix tag and "(no match found)" my $temp_fc = $1; $temp_fc =~ s/[a-z0-9]{14}\s//i; $temp_fc =~ s/[a-z0-9]{9,12}\.[a-z0-9]{5}\s//i; $temp_fc =~ s/\(no match found\)//i; $FiletypeAllow{$temp_fc}++; $MailScan_FiletypeAllow++; } } elsif ($ThisLine =~ m/Filetype Checks: (.+)/i) { #filter sendmail or postfix tag my $temp_fc = lc($1); $temp_fc =~ s/\([a-z0-9]{14}\s/\(/i; $temp_fc =~ s/\([a-z0-9]{9,12}\.[a-z0-9]{5}\s/\(/i; $temp_fc =~ s/\s{10,}/ -space- /; $FiletypeType{$temp_fc}++; $MailScan_FiletypeBanned++; } elsif ($ThisLine =~ m/(Password\-protected archive \(.+\)) in \w+/i) { $MailScan_Other = $MailScan_Other + 1; $FilenameType{$1}++; $MailScan_FilenameBanned++; } elsif ($ThisLine =~ /Spam Actions: .+ actions are (.*)/) { $MailScan_Spam_Act{$1}++; } elsif ($ThisLine =~ /SpamAssassin timed out and was killed/) { $SA_timeout++; } elsif ( $ThisLine =~ m/Message .+ from (.+ \(.+\)) is whitelisted/ ) { $MailScan_Whitelisted++; $Whitelisted_Host{$1}++; } elsif ( $ThisLine =~ m/Message .+ from (.+ \(.+\)) to .+ is spam \(blacklisted\)/ ) { $MailScan_Blacklisted++; $Blacklisted_Host{$1}++; } elsif ($ThisLine =~ m/^Found phishing fraud from (.+) claiming to be (.+) in (.+)/) { $MailScan_Phishing++; #Detailed phishing output set in mailscanner.conf #With variable mailscanner_phishing_detail = 1 if ($phishing_detail) { $PhishingSourceDest{"$1 claiming to be $2 in $3"}++; } else { $PhishingSourceDest{"$1 claiming to be $2"}++; } my $temp_ph = $1; if ($temp_ph =~ m/^https?:\/\/([^\/\? ]+)/i) { $PhishingSource{$1}++; } else { $PhishingSource{$temp_ph}++; } } elsif ($ThisLine =~ m/^Found ip-based phishing fraud from (.+) in/) { $MailScan_Phishing++; my $temp_ph = $1; if ($temp_ph =~ m/^https?:\/\/([\d\.]+)/i) { $PhishingSource{$1}++; } else { $PhishingSource{$temp_ph}++; } $PhishingSource{$1}++; } elsif ($ThisLine =~ m/^Found definite phishing fraud from (.+) in/) { $MailScan_Phishing++; my $temp_ph = $1; if ($temp_ph =~ m/^https?:\/\/([^\/\? ]+)/i) { $PhishingSource{$1}++; } else { $PhishingSource{$temp_ph}++; } } elsif ($ThisLine =~ m/^HTML-Form tag found in message .+ from (.+)/) { $MailScan_FormTag++; $FormTagSource{$1}++; } elsif ($ThisLine =~ m/^HTML-Script tag found in message .+ from (.+)/) { $MailScan_ScriptTag++; $ScriptTagSource{$1}++; } elsif ($ThisLine =~ m/^HTML-IFrame tag found in message .+ from (.+)/) { $MailScan_IframeTag++; $IframeTagSource{$1}++; } elsif ($ThisLine =~ m/^HTML-Object tag found in message .+ from (.+)/) { $MailScan_ObjectTag++; $ObjectTagSource{$1}++; } elsif ($ThisLine =~ m/^HTML Img tag found in message .+ from (.+)/) { $MailScan_ImgTag++; $ImgTagSource{$1}++; } elsif ($ThisLine =~ m/Logged to MailWatch SQL/) { $MailWatchSQL++; } elsif ($ThisLine =~ m/Quarantining modified message for/) { $DisarmedQuarantined++; } elsif ($ThisLine =~ m/SpamAssassin cache hit for message/) { $SACacheHit++; } elsif ($ThisLine =~ m/RBL checks: .+ found in (.+)/i) { $RBLType{$1}++; $MailScan_RBL++; } elsif ($ThisLine =~ m/Valid Watermark HASH found in Message/) { $MailScan_Skipwatermark++; } elsif ($ThisLine =~ m/Message .+ from .+ has valid watermark/) { $MailScan_GoodWatermark++; } elsif ( ($ThisLine =~ m/Message .+ had bad watermark/) || ($ThisLine =~ m/Message .+ from .+ has no \(or invalid\) watermark or sender address/) ) { $MailScan_BadWatermark++; } elsif ($ThisLine =~ m/SpamAssassin Rule Actions: rule ([^ ]*) caused action ([^ ]*) .*in message ([0-9a-f.]*)/i) { $SpamAssassin_Rule_Actions++; $SpamAssassin_Rule{$1}++; $SpamAssassin_Action{$2}++; $SpamAssassin_Message{$3}++; } elsif ($ThisLine =~ m/Deleted (\d+) messages from processing-database/) { $MailScan_Deleted_pdb += $1; } elsif ($ThisLine =~ m/Found (\d+) messages in the [Pp]rocessing(?:-messages| Attempts) [Dd]atabase/) { $MailScan_Found_pdb += $1; } else { chomp($ThisLine); # Report any unmatched entries... $OtherList{$ThisLine}++; } } if ($MailScan_Received > 0) { print "\nMailScanner Status:"; print "\n\t" . $MailScan_Received . ' messages Scanned by MailScanner'; my $size_total = 1 ; if ($MailScan_bytes < 1024) { $size_total = $MailScan_bytes . ' Total Bytes'; } elsif ($MailScan_bytes < 1048576) { $size_total = sprintf("%.1f", ($MailScan_bytes / 1024)) . ' Total KB'; } else { $size_total = sprintf("%.1f", ($MailScan_bytes / 1048576)) . ' Total MB'; } print "\n\t" . $size_total ; } if ($MailScan_Spam > 0) { print "\n\t" . $MailScan_Spam . ' Spam messages detected by MailScanner'; } if (keys %MailScan_Spam_Act) { foreach my $ThisOne (sort keys %MailScan_Spam_Act) { if ($MailScan_Spam_Act{$ThisOne} > 0) { print "\n\t\t" . $MailScan_Spam_Act{$ThisOne} . ' Spam messages with action(s) ' .$ThisOne ; } } } if ($SACacheHit > 0) { print "\n\t\t" . $SACacheHit . ' hits from MailScanner SpamAssassin cache'; } #if ($MailScan_Spam_Virus > 0) { # print "\n\t" . $MailScan_Spam_Virus . ' Spam messages detected by Virus signatures'; #} if ($MailScan_Unscanned > 0) { print "\n\t" . $MailScan_Unscanned . ' Messages forwarded unscanned by MailScanner'; } if ($MailScan_Virus > 0) { print "\n\t" . $MailScan_Virus . ' Viruses found by MailScanner'; } if ($MailScan_Other > 0) { print "\n\t" . $MailScan_Other . ' Banned attachments found by MailScanner'; } if ($MailScan_Content > 0) { print "\n\t" . $MailScan_Content . ' Content Problems found by MailScanner'; } if ($MailScan_Deleted_pdb > 0) { print "\n\t" . $MailScan_Deleted_pdb . " Messages deleted from processing-database"; } if ($MailScan_Found_pdb > 0) { print "\n\t" . $MailScan_Found_pdb . " Messages found in processing-database"; } if ($MailScan_Delivered > 0) { print "\n\t" . $MailScan_Delivered . " Messages delivered by MailScanner\n"; } if ($MailWatchSQL > 0) { print "\n\t" . $MailWatchSQL . " Messages logged to MailWatch database\n"; } if ($SA_timeout > 0) { print "\n\t" . $SA_timeout . " SpamAssassin timeout(s)\n"; } if (keys %VirusScannerTimeout) { print "\n\t" . $MailScan_ScannerTimeout . " virus scanner timeout(s)\n"; foreach my $ThisOne (sort keys %VirusScannerTimeout) { print "\t " . $ThisOne . ": " . $VirusScannerTimeout{$ThisOne} . " Time(s)\n"; } } if (keys %VirusType_Antivir) { print "\nAntivir Virus Report: (Total Seen = $MailScan_Virus_Antivir)\n"; foreach my $ThisOne (sort keys %VirusType_Antivir) { print ' ' . $ThisOne . ': ' . $VirusType_Antivir{$ThisOne} . " Times(s)\n"; } } if (keys %VirusType_BitDefender) { print "\nBitDefender Virus Report: (Total Seen = $MailScan_Virus_BitDefender)\n"; foreach my $ThisOne (sort keys %VirusType_BitDefender) { print ' ' . $ThisOne . ': ' . $VirusType_BitDefender{$ThisOne} . " Times(s)\n"; } } if (keys %VirusType_ClamAv) { print "\nClamAV Virus Report: (Total Seen = $MailScan_Virus_ClamAv)\n"; foreach my $ThisOne (sort keys %VirusType_ClamAv) { print ' ' . $ThisOne . ': ' . $VirusType_ClamAv{$ThisOne} . " Time(s)\n"; } } if (keys %VirusType_ClamAVModule) { print "\nClamAVModule Virus Report: (Total Seen = $MailScan_Virus_ClamAVModule)\n"; foreach my $ThisOne (sort keys %VirusType_ClamAVModule) { print ' ' . $ThisOne . ': ' . $VirusType_ClamAVModule{$ThisOne} . " Time(s)\n"; } } if (keys %VirusType_Clamd) { print "\nClamd Virus Report: (Total Seen = $MailScan_Virus_Clamd)\n"; foreach my $ThisOne (sort keys %VirusType_Clamd) { print ' ' . $ThisOne . ': ' . $VirusType_Clamd{$ThisOne} . " Time(s)\n"; } } if (keys %VirusType_Fprot) { print "\nF-Prot Virus Report: (Total Seen = $MailScan_Virus_Fprot)\n"; foreach my $ThisOne (sort keys %VirusType_Fprot) { print ' ' . $ThisOne . ': ' . $VirusType_Fprot{$ThisOne} . " Time(s)\n"; } } if (keys %VirusType_Kaspersky) { print "\nKaspersky Virus Report: (Total Seen = $MailScan_Virus_Kaspersky)\n"; foreach my $ThisOne (sort keys %VirusType_Kaspersky) { print ' ' . $ThisOne . ': ' . $VirusType_Kaspersky{$ThisOne} . " Time(s)\n"; } } if (keys %VirusType_McAfee) { print "\nMcAfee Virus Report: (Total Seen = $MailScan_Virus_McAfee)\n"; foreach my $ThisOne (sort keys %VirusType_McAfee) { print ' ' . $ThisOne . ': ' . $VirusType_McAfee{$ThisOne} . " Time(s)\n"; } } if (keys %VirusType_Sophos) { print "\nSophos Virus Report: (Total Seen = $MailScan_Virus_Sophos)\n"; foreach my $ThisOne (sort keys %VirusType_Sophos) { print ' ' . $ThisOne . ': ' . $VirusType_Sophos{$ThisOne} . " Time(s)\n"; } } if (keys %VirusType_SophosSavi) { print "\nSophosSavi Virus Report: (Total Seen = $MailScan_Virus_SophosSavi)\n"; foreach my $ThisOne (sort keys %VirusType_SophosSavi) { print ' ' . $ThisOne . ': ' . $VirusType_SophosSavi{$ThisOne} . " Time(s)\n"; } } if (keys %Spam_Virus_Found) { print "\nSpam Virus Report: (Total Seen = $MailScan_Spam_Virus)\n"; foreach my $ThisOne (sort keys %Spam_Virus_Found) { print ' ' . $ThisOne . ': ' . $Spam_Virus_Found{$ThisOne} . " Time(s)\n"; } } if (keys %Hostlist) { print "\nVirus Sender Report: (Total Seen = $MailScan_VirtualHost)\n"; foreach my $ThisOne (sort keys %Hostlist) { print ' ' . $ThisOne . ': ' . $Hostlist{$ThisOne} . " Time(s)\n"; } } if (keys %Whitelisted_Host) { print "\nSpam Whitelisted Host Report: (Total Seen = $MailScan_Whitelisted)\n"; foreach my $ThisOne (sort keys %Whitelisted_Host) { print ' ' . $ThisOne . ': ' . $Whitelisted_Host{$ThisOne} . " Time(s)\n"; } } if (keys %Blacklisted_Host) { print "\nSpam Blacklisted Host Report: (Total Seen = $MailScan_Blacklisted)\n"; foreach my $ThisOne (sort keys %Blacklisted_Host) { print ' ' . $ThisOne . ': ' . $Blacklisted_Host{$ThisOne} . " Time(s)\n"; } } if (keys %RBLType) { print "\nRBL Report: (Total Seen = $MailScan_RBL)\n"; foreach my $ThisOne (sort keys %RBLType) { print ' ' . $ThisOne . ': ' . $RBLType{$ThisOne} . " Time(s)\n"; } } if (keys %ContentType) { print "\nContent Report: (Total Seen = $MailScan_Content)"; if ($DisarmedQuarantined > 0) { print " (Quarantined = $DisarmedQuarantined)"; } print "\n"; foreach my $ThisOne (sort keys %ContentType) { print ' ' . $ThisOne . ': ' . $ContentType{$ThisOne} . " Time(s)\n"; } } if (keys %FilenameAllow) { print "\nAllowed Filename Report: (Total Seen = $MailScan_FilenameAllow)\n"; if ($Detail >= 10) { foreach my $ThisOne (sort keys %FilenameAllow) { print ' ' . $ThisOne . ': ' . $FilenameAllow{$ThisOne} . " Time(s)\n"; } } else { print ' ' . "Details Suppressed at level $Detail. Level 10 required.\n"; } } if (keys %FilenameType) { print "\nBanned Filename Report: (Total Seen = $MailScan_FilenameBanned)\n"; foreach my $ThisOne (sort keys %FilenameType) { print ' ' . $ThisOne . ': ' . $FilenameType{$ThisOne} . " Time(s)\n"; } } if (keys %FiletypeAllow) { print "\nAllowed Filetype Report: (Total Seen = $MailScan_FiletypeAllow)\n"; if ($Detail >= 10) { foreach my $ThisOne (sort keys %FiletypeAllow) { print ' ' . $ThisOne . ': ' . $FiletypeAllow{$ThisOne} . " Time(s)\n"; } } else { print ' ' . "Details Suppressed at level $Detail. Level 10 required.\n"; } } if (keys %FiletypeType) { print "\nBanned Filetype Report: (Total Seen = $MailScan_FiletypeBanned)\n"; foreach my $ThisOne (sort keys %FiletypeType) { print ' ' . $ThisOne . ': ' . $FiletypeType{$ThisOne} . " Time(s)\n"; } } if ( (keys %PhishingSource) && ($mailscanner_phishingthreshold > 0) ) { print "\nPhishing Report: (Total Seen = $MailScan_Phishing)\n"; foreach my $ThisOne (sort keys %PhishingSource) { if ( $PhishingSource{$ThisOne} >= $mailscanner_phishingthreshold ) { print ' ' . $ThisOne . ': ' . $PhishingSource{$ThisOne} . " Time(s)\n"; } }; if ($Detail >= 10) { print "\n Detail:\n"; foreach my $ThisOne (sort keys %PhishingSourceDest) { if ( $PhishingSourceDest{$ThisOne} >= $mailscanner_phishingthreshold ) { print ' ' . $ThisOne . ': ' . $PhishingSourceDest{$ThisOne} . " Time(s)\n"; } } } } if (keys %FormTagSource) { print "\nHTML

tag report: (Total Seen = $MailScan_FormTag)\n"; foreach my $ThisOne (sort keys %FormTagSource) { print ' ' . $ThisOne . ': ' . $FormTagSource{$ThisOne} . " Time(s)\n"; } } if (keys %ScriptTagSource) { print "\nHTML