# Copyright (c) 2010 Flowerfire, Inc. All Rights Reserved. merak_smtp = { plugin_version = "1.2.1" info.1.manfacturer = "Merak" info.1.device = "SMTP Server" info.1.version.1 = "9" # 9.4.0 # 2006-12-13 - 1.0beta - KBB - initial creation - supports format with no date - finds size on # From: line if it is there - based on merak_smtp.cfg # 2007-09-13 - 1.0 - KBB - renumbered per new beta policy # 2007-10-26 - 1.1 - KBB - fixed bug where leading < could become part of source_address - # allow source_address to be empty where From line exists and email address is <> # 2009-07-22 - 1.2 - GMF - Added support for variant: accept on "accepted for delivery", and default date to current day, # and allow somewhat more flexible date-in-filename. # 2009-07-29 - 1.2.1 - GMF - Turned on full IP tracking for source_ip # The name of the log format log.format.format_label = "Merak SMTP Log Format" log.miscellaneous.log_data_type = "mail_server" log.miscellaneous.log_format_type = "mail_server" # The log is in this format # log.format.autodetect_regular_expression = "ESMTP Merak|SYSTEM *\\[00000000\\] [A-Z][a-z][a-z], [0-9][0-9] [A-Z][a-z][a-z] [0-9][0-9][0-9][0-9] [0-9][0-9]:[0-9][0-9]:[0-9][0-9]" #log.format.autodetect_regular_expression = "\\[[0-9A-Z]+\\] [A-Z][a-z][a-z], [0-9][0-9] [A-Z][a-z][a-z] [0-9][0-9][0-9][0-9] [0-9][0-9]:[0-9][0-9]:[0-9][0-9] [-+][0-9]+ (Connected|Disconnected)$" #255.255.255.255 [00000B38] Wed, 7 Jun 2006 00:00:00 +0300 Connected #67.18.135.154 [0DFC] 19:20:39 Connected #142.225.137.7 [0CF8] 10:05:02 Client session Connected log.format.autodetect_expression = ` matches_regular_expression(volatile.log_data_line, "\\[[0-9A-Z]+\\] [A-Z][a-z][a-z], [0-9]{1,2} [A-Z][a-z][a-z] [0-9][0-9][0-9][0-9] [0-9][0-9]:[0-9][0-9]:[0-9][0-9] [-+][0-9]+ (Connected|Disconnected|Client session Connected)$") or matches_regular_expression(volatile.log_data_line, "\\[[0-9A-Z]+\\] [0-9][0-9]:[0-9][0-9]:[0-9][0-9] (Connected|Disconnected|Client session Connected)$") ` #Search this many lines for a match log.format.autodetect_lines = "100" # All log field parsing will be done using the parsing filters log.format.parse_only_with_filters = "true" # The format of dates and times in this log log.format.date_format = "auto" log.format.time_format = "auto" # Log fields log.fields = { date = "" time = "" source_address = "" destination_address = "" source_ip.type = "host" source_hostname = "" size = "" result = "" message_count = "" } # log.fields # Log Parsing Filters log.parsing_filters.parse = ` v.message = ""; if (matches_regular_expression(current_log_line(), '^([^ ]+) *\\\\[([0-9A-Z]+)\\\\] [A-Z][a-z][a-z], ([0-9]+ [A-Z][a-z][a-z] [0-9][0-9][0-9][0-9]) ([0-9][0-9]:[0-9][0-9]:[0-9][0-9]) [+-][0-9][0-9][0-9][0-9] (.*)$')) then ( v.key = $2; set_collected_field(v.key, 'source_ip', $1); set_collected_field(v.key, 'date', $3); set_collected_field(v.key, 'time', $4); v.message = $5; ); # date must come from file name if it isn't part of the format else if (matches_regular_expression(current_log_line(), '^([^ ]+) *\\\\[([0-9A-Z]+)\\\\] ([0-9][0-9]:[0-9][0-9]:[0-9][0-9]) (.*)$')) then ( v.key = $2; set_collected_field(v.key, 'source_ip', $1); set_collected_field(v.key, 'time', $3); v.message = $4; # 2009-09-22 - GMF - Extended this to support formats like sZ20090710-00.zip if (matches_regular_expression(current_log_pathname(), 's[A-Z]+([21][09][0-9]{2})([0-9]{2})([0-9]{2}).*[.]')) then ( set_collected_field(v.key, 'date', $1 . "/" . $2 . "/" . $3); ); # Default to current date if nothing available else ( set_collected_field(v.key, 'date', substr(epoc_to_date_time(now()), 0, 11)); ); ); # debug #if (v.message eq "") then ( # echo("1 no match " . current_log_line()); #); if (matches_regular_expression(v.message, '^Client session (.*)$')) then ( v.message = $1; ); if (matches_regular_expression(v.message, '^[<>]+ [HE][EH]LO (.*)$')) then ( set_collected_field(v.key, 'source_hostname', $1); ); #else if (matches_regular_expression(v.message, '^[<>]+ [Mm][Aa][Ii][Ll] [Ff][Rr][Oo][Mm]:[< ]([^ >]*)[ >]?(.*)')) then ( else if (matches_regular_expression(v.message, '^[<>]+ [Mm][Aa][Ii][Ll] [Ff][Rr][Oo][Mm]: *]*)([> ]+SIZE=([0-9]+))?')) then ( v.address = $1; if (v.address eq '') then ( v.address = '-'; # Avoid having it set to '(empty)' so it will pass the check below & show in reports ); set_collected_field(v.key, 'source_address', v.address); set_collected_field(v.key, 'size', $3); # v.remainder = $2; # if (matches_regular_expression(v.remainder, '[Ss][Ii][Zz][Ee]=([0-9]+)')) then ( # set_collected_field(v.key, 'size', $3); # ); ); else if (matches_regular_expression(v.message, '^\\\\*\\\\*\\\\* <[^>]*> <[^>]*> ([0-9]+) ([0-9]+) ')) then ( set_collected_field(v.key, 'message_count', $1); set_collected_field(v.key, 'size', $2); ); #else if (matches_regular_expression(v.message, '^[<>]+ [Rr][Cc][Pp][Tt] [Tt][Oo]:[< ]*([^>]*)>*$')) then ( else if (matches_regular_expression(v.message, '^[<>]+ [Rr][Cc][Pp][Tt] [Tt][Oo]:[< ]*([^ <>]*)>?')) then ( v.to = $1; v.address = get_collected_field(v.key, 'destination_address'); if (!(v.address eq '(empty)')) then ( v.to = v.to . '|' . get_collected_field(v.key, 'destination_address'); ); # Change to regular expression makes replace_all unnecessary #set_collected_field(v.key, 'destination_address', replace_all(v.to, '<', '')); set_collected_field(v.key, 'destination_address', v.to); ); else if (matches_regular_expression(v.message, '(Message accepted for delivery|Go ahead|Queued mail for delivery|Sender refused|User unknown|Syntax error|we do not relay|sender domain must exist|mailbox unavailable|Message deleted by filter Anti Spam|content filter rejection|Command unrecognized|Sender domain must resolve|Incorrect command sequence|Sender refused|User unknown)')) then ( set_collected_field(v.key, 'result', $1); ); else if (matches_regular_expression(v.message, '^[<>]+ [Qq][Uu][Ii][Tt]')) then ( if (get_collected_field(v.key, 'source_address') ne '(empty)') then ( accept_collected_entry(v.key, false); ); ); # 2009-07-22 - GMF - There isn't always a QUIT after a message is sent; there can be multiple messages per connection, # e.g. in example log file sZ20090710-00.zip. So, accept when we see "accepted for delivery" lines, which occur on delivery. # 66.210.173.250 [0298] 13:19:55 >>> 250 2.6.0 605 bytes received in 00:00:00; Message id RZD65255 accepted for delivery else if (matches_regular_expression(v.message, '^>>> [0-9]+ [^ ]+ [0-9]+ bytes received in [0-9:]+; Message id [^ ]+ accepted for delivery')) then ( if (get_collected_field(v.key, 'source_address') ne '(empty)') then ( accept_collected_entry(v.key, false); ); ); #else ( # debug # echo("2 no match " . v.message); #); ` # Database fields database.fields = { date_time = "" day_of_week = "" hour_of_day = "" source_ip = "" source_hostname = "" location.suppress_bottom = 3 source_address = "" destination_address = "" result = "" } # database.fields # Log Filters log.filters = { mark_entry = { label = '$lang_admin.log_filters.mark_entry_label' comment = '$lang_admin.log_filters.mark_entry_comment' value = "if (message_count eq '(empty)') then message_count = 1; messages = message_count;" } # mark_entry } # log.filters database.numerical_fields = { messages = { default = true requires_log_field = false entries_field = true } # messages size = { type = "float" display_format_type = "bandwidth" } # size } # database.numerical_fields create_profile_wizard_options = { # How the reports should be grouped in the report menu report_groups = { date_time_group = "" } # report_groups } # create_profile_wizard_options } # merak_smtp