# Copyright (c) 2010 Flowerfire, Inc. All Rights Reserved. # OpenVPN log format definition file for Sawmill openvpn = { plugin_version = "2.0" # Initial creation - 1.0 # 2011-07-08 - 1.0.1 - MSG - Edited info lines. # 2014-02-09 - 2.0 - GMF - Substantially rewrote the plug-in so it doesn't use subroutines (expensive), uses syslog plug-ins, supports the latest version, and other changes. This plug-in was apparently originally written by someone who was quite clever, but not an expert in Sawmill. Cleaned it up. # 2015-08-11 - 2.1 - gas - changed log_format_type to network_device to match convention info.1.manufacturer = "OpenVPN technologies" info.1.device = "OpenVPN" info.1.version.1 = "" log.format.format_label = "OpenVPN Log Format" log.miscellaneous.log_data_type = "syslog_required" log.miscellaneous.log_format_type = "network_device" # log.format.autodetect_regular_expression = "openvpn[^[]*[[][^]]*]: " log.format.autodetect_regular_expression = "OVPN [0-9]+ " # log.format.date_format = "mmm dd" # log.format.time_format = "hh:mm:ss" log.format.default_log_date_year = "thisyear" log.format.collected_entry_lifespan = 0 log.format.accept_expired_entries = false log.format.parse_only_with_filters = true log.fields = { date = { label = "$lang_stats.field_labels.date" type = "date" } time = { label = "$lang_stats.field_labels.time" type = "time" } client_ip = { label = "$lang_stats.field_labels.client_ip" type = "flat" } client_port = { label = "$lang_stats.field_labels.client_port" type = "flat" } user = { label = "$lang_stats.field_labels.user" type = "flat" } result = { label = "$lang_stats.field_labels.result" type = "flat" } duration = { label = "$lang_stats.field_labels.duration" type = "flat" } login_date = '' login_time = '' } # log.fields database.fields = { date_time = { label = "$lang_stats.field_labels.date_time" log_field = "date_time" type = "string" display_format_type = "date_time" } day_of_week = { label = "$lang_stats.field_labels.day_of_week" log_field = "day_of_week" type = "string" display_format_type = "day_of_week" } hour_of_day = { label = "$lang_stats.field_labels.hour_of_day" log_field = "hour_of_day" type = "string" display_format_type = "hour_of_day" } client_ip = { label = "$lang_stats.field_labels.client_ip" log_field = "client_ip" type = "string" } user = { label = "$lang_stats.field_labels.user" log_field = "user" type = "string" } result = { label = "$lang_stats.field_labels.result" log_field = "result" type = "string" } } # database.fields database.numerical_fields = { duration = { label = "$lang_stats.field_labels.duration" log_field = "duration" type = "float" display_format_type = "duration_compact" default = true } sessions = { label = "$lang_stats.field_labels.sessions" requires_log_field = false type = "int" display_format_type = "integer" default = true } } # database.numerical_fields log.filter_initialization = ` string key; # 2014-02-09 - GMF - This plug-in was made by a very clever person, unknown, who either didn't know about Sawmill's syslog header functionality or didn't know how to use it. This use of a header string to each regexp, is made unnecessary by type 'syslog' plug-ins, and ties this plug-in to a particular syslog; so I'm switching it to use that method. # string re_syslog = '^([A-Z][a-z][a-z] [0-9 ][0-9]) ([0-9][0-9]:[0-9][0-9]:[0-9][0-9]) [^ ]* .*[[][^]]*]: '; # key.list = '(empty)'; #echo('initial: ' . key.list); # subroutine(echo_list, ( # string k; # k = key.list; ## echo('BEGIN'); # while (k ne '(empty)') ( ## echo(k); # k = get_collected_field(k, 'next'); # ); ## echo('END'); # )); # subroutine(set_common_fields(string key), ( # set_collected_field(key, 'date', $1); # set_collected_field(key, 'time', $2); # )); # subroutine(time_seconds(string d, string t), ( # date_time_to_epoc( # normalize_date(d, 'mmm dd') . ' ' . # normalize_time(t, 'h:m:s') # ) # )); # subroutine(link_key(string key), ( # #echo('link_key BEGIN'); # #echo_list(); # set_collected_field(key, 'next', key.list); # set_collected_field(key, 'prev', '(empty)'); # if (key.list ne '(empty)') then ( # set_collected_field(key.list, 'prev', key); # ); # key.list = key; # #echo('link_key END'); # #echo_list(); # )); # subroutine(unlink_key(string key), ( # #echo('unlink_key BEGIN'); # #echo_list(); # string p = get_collected_field(key, 'prev'); # string n = get_collected_field(key, 'next'); # if (p ne '(empty)') then ( set_collected_field(p, 'next', n); ); # if (n ne '(empty)') then ( set_collected_field(n, 'prev', p); ); # if (key.list eq key) then ( key.list = n; ); # #echo('unlink_key END'); # #echo_list(); # )); # subroutine(accept_unlink_key(string key), ( # unlink_key(key); # accept_collected_entry(key, false); # )); # subroutine(exit_all, ( # while (key.list ne '(empty)') ( # set_collected_field(key.list, 'result', 'ACCEPTED'); # set_collected_field(key.list, 'duration', # time_seconds($1, $2) - # time_seconds( # get_collected_field(key.list, 'date'), # get_collected_field(key.list, 'time') # ) # ); # #echo('exit: ' . key.list); # accept_unlink_key(key.list); # ) # )); # subroutine(drop_user(string u), ( # #echo('drop_user BEGIN ' . u); # #echo_list(); # string k = key.list; # bool first = true; # while (k ne '(empty)') ( # string p = k; # k = get_collected_field(p, 'next'); # if (get_collected_field(p, 'user') eq u) then ( # if (first) then ( # first = false; # added last, the only not deleted # ) else ( # set_collected_field(p, 'result', 'ACCEPTED'); # set_collected_field(p, 'duration', # time_seconds($1, $2) - # time_seconds( # get_collected_field(p, 'date'), # get_collected_field(p, 'time') # ) # ); # accept_unlink_key(p); # ) # ) # ); # #echo('drop_user END ' . u); # #echo_list(); # )) ` log.parsing_filters = { year_from_filename = ` if (matches_regular_expression(current_log_pathname(), '((20|19)[0-9][0-9])\\\\.log')) then log.processing.default_log_date_year = $1; ` # Chop off the extra header OVPN N OUT: 'Date #2014-02-04 19:44:00-0500 [-] OVPN 3 OUT: 'Wed Feb 5 00:44:00 2014 209.117.47.248:52563 [tobrien] Peer Connection Initiated with 209.117.47.248:52563' remove_extra_header = ` if (matches_regular_expression(v.syslog_message, "^OVPN [0-9]+ OUT: ['\\"][A-Za-z]+ [A-Za-z]+ +[0-9]+ [0-9:]+ [0-9]+ (.*)$")) then v.syslog_message = $1; ` session_start = ` if (matches_regular_expression(v.syslog_message, '^([0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+):([0-9]+) [[]([^]]*)] Peer Connection Initiated')) then ( key = $1 . ':' . $2; set_collected_field(key, 'date', get_collected_field('', 'date')); set_collected_field(key, 'time', get_collected_field('', 'time')); # link_key(key); set_collected_field(key, 'login_date', get_collected_field('', 'date')); set_collected_field(key, 'login_time', get_collected_field('', 'time')); set_collected_field(key, 'client_ip', $1); set_collected_field(key, 'client_port', $2); set_collected_field(key, 'user', $3); ) ` #2014-02-04 16:53:33-0500 [-] OVPN 3 OUT: 'Tue Feb 4 21:53:33 2014 abc/12.34.56.78:61047 [abc] Inactivity timeout (--ping-restart), restarting' session_timeout = ` if (matches_regular_expression(v.syslog_message, '^[^/]*/*([0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+):([0-9]+) [[][^]]*] Inactivity timeout')) then ( key = $1 . ':' . $2; set_collected_field(key, 'date', get_collected_field('', 'date')); set_collected_field(key, 'time', get_collected_field('', 'time')); set_collected_field(key, 'result', 'ACCEPTED'); if (get_collected_field(key, 'login_date') ne '(empty)') then set_collected_field(key, 'duration', date_time_to_epoc(normalize_date(get_collected_field('', 'date'), 'auto') . ' ' . normalize_time(get_collected_field('', 'time'), 'auto')) - date_time_to_epoc(normalize_date(get_collected_field(key, 'login_date'), 'auto') . ' ' . normalize_time(get_collected_field(key, 'login_time'), 'auto'))); # set_collected_field(key, 'duration', # time_seconds($1, $2) - # time_seconds( # get_collected_field(key, 'date'), # get_collected_field(key, 'time') # ) # ); # accept_unlink_key(key); accept_collected_entry(key, false); ) ` #2014-02-04 16:10:14-0500 [-] OVPN 3 OUT: "Tue Feb 4 21:10:14 2014 12.34.56.78:41557 SENT CONTROL [abc]: 'AUTH_FAILED,SESSION: Your session has expired, please reauthenticate' (status=1)" auth_fail = ` if (matches_regular_expression(v.syslog_message, '^[^/]*/*([0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+):([0-9]+) SENT CONTROL .*AUTH_FAILED')) then ( key = $1 . ':' . $2; set_collected_field(key, 'date', get_collected_field('', 'date')); set_collected_field(key, 'time', get_collected_field('', 'time')); set_collected_field(key, 'result', 'REJECTED'); if (get_collected_field(key, 'login_date') ne '(empty)') then set_collected_field(key, 'duration', date_time_to_epoc(normalize_date(get_collected_field('', 'date'), 'auto') . ' ' . normalize_time(get_collected_field('', 'time'), 'auto')) - date_time_to_epoc(normalize_date(get_collected_field(key, 'login_date'), 'auto') . ' ' . normalize_time(get_collected_field(key, 'login_time'), 'auto'))); # time_seconds($1, $2) - # time_seconds( # get_collected_field(key, 'date'), # get_collected_field(key, 'time') # ) # ); # accept_unlink_key(key); accept_collected_entry(key, false); ) ` # exit = ` # if (matches_regular_expression(v.syslog_message, # 'SIGTERM.*hard')) # then ( # exit_all(); # ) #` # drop_multi = ` # label = "drop_multi" # comment = "dropping previous sessions of the same client" # value = " # if (matches_regular_expression(v.syslog_message, # `^MULTI: new connection by client '(.*)' will cause .* dropped`)) # then ( # drop_user($1); # ) # " # } # drop_multi } # log.parsing_filters log.filters = { # Counting sessions mark_entry = { label = "$lang_admin.log_filters.mark_entry_label" comment = "$lang_admin.log_filters.mark_entry_comment" value = "sessions = 1;" } } # log.filters create_profile_wizard_options = { date_time_tracking = true date_time_group = "" day_of_week = true hour_of_day = true client_ip = true user = true result = true } # create_profile_wizard_options } # openvpn