# Copyright (c) 2010 Flowerfire, Inc. All Rights Reserved. cisco_pix = { plugin_version = "2.8.1" info.1.manufacturer = "Cisco Systems" info.1.device = "PIX/ASA Security Appliance" info.1.version = "500 Series" # 2006/03/10 - 2.0beta - added support for router/switch messages. # 2006/04/12 - 2.0.1beta - added support for "permitted" lines -GMF # 2006/06/05 - 2.0.2beta - KBB - added extraction of user name from Built # and Teardown lines - for systems where users authenticated with TACACS - # (note - "user_name" added and "user" commented out in datebase and log # fields, since "user" already existed, but lines where "user" is collected # were already commented out) # 2006/06/13 - 2.0.3beta - KBB - user name from Accessed URL lines # 2006/11/07 - 2.0.4beta - KBB - handle negative connection numbers in Built and Teardown lines # 2006/11/20 - 2.0.5beta - KBB - count connections on teardown and check for inbound/outbound when # determining which port is the source and which the destination # 2006/11/30 - 2.0.6beta - KBB - count connections on built as well as teardown and check for # inbound/outbound when determining which port is the source and which the destination for Built # events as well as Teardown events # 2006/12/04 - 2.0.7beta - KBB - reverse direction of 2.0.5 - was reversing to/from if inbound - now # reversing if outbound # 2006/12/29 - 2.0.8beta - KBB - added inclusion of direction with Teardown event - now collecting # Username, Group and IP from certain ASA lines - added support for more types of operations/messages # 2007/01/05 - 2.0.9beta - KBB - excluded translations from Built and Teardown events - added support # for several types of Deny events # 2007/01/11 - 2.1beta - KBB - fixed bug in look_up_service log filter - also commented out setting # service to "(unknown)" (1/15) - see comment in log filters section # 2007/02/23 - 2.2beta - KBB - added support for some types of "crashinfo" entries and # SEC-6-IPACCESSLOGP # 2007/08/09 - 2.2.1beta - KBB - added support for some VPN and AAA entries (PIX) # 2007/08/27 - 2.2.2beta - KBB - compensated for a Cisco bug where a negative number of bytes results # in huge number. # 2007/09/11 - 2.2.2 - KBB - renumbered per new beta policy and renamed from beta_cisco_pix.cfg # 2008/01/16 - 2.3 - GMF - Extracted facility, severity, and mnemonic from message code, into separate fields. # 2008/03/06 - 2.4 - GMF - Added support for CRYPTO lines. # 2009/07/01 - 2.5 - KBB & MSG - Added support for Session disconnected lines and added new fields session_type, bytes_xmt and bytes_rcv. # 2008/03/06 - 2.6 - MSG - Added support for bytes field containing a colon before the value # 2009/08/31 - 2.6.1 - GMF - Fixed extraction of client_application_version # 2009/11/20 - 2.6.2 - GMF - Fixed extraction of h:mm:ss durations on Teardown lines; removed reversal on outbound teardown events [ThreadID:699166]. # 2010/02/02 - 2.6.3 - MSG & KBB - Fixed parsing of bytes from Teardown lines. # 2010/12/28 - 2.6.4 - GMF - Changed reversal of to/from to happen on outbound, instead of on inbound [ThreadID:974447]. #2006-06-02 13:37:13 Local4.Info 44.84.4.4 :Jun 02 13:37:13 EDT: %PIX-6-302013: Built outbound TCP connection 30594850 for outside:49.14.143.45/80 (64.14.414.94/80) to inside:14.415.41.4/1451 (499.453.478.454/5454) (hwells) #2006-06-02 13:37:13 Local4.Notice 44.40.4.1 :Jun 02 13:37:13 EDT: %PIX-5-304001: hwells@10.115.81.9 Accessed URL 44.134.164.104:/urchin.js # 2010-10-06 - 2.6.4 - MSG - Edited info lines. # 2011/09/13 - 2.6.5 - GMF - Restored reversal of to/from on Teardown lines. # 2012/01/10 - 2.6.6 - GMF - Changed from using insertions for hit-cnt, to setting the events field to hit-cnt. This is much faster for high hit-cnt values, and makes the database much smaller, and what's the downside? # 2012/01/31 - 2.7 - GMF - Added top_level_domain; toned down the simplify_url filter; changed field name to URL; extracted User/Group/IP from WebVPN lines; extracted URL from WebVPN lines # 2012/02/14 - 2.7.1 - GMF - Changed User parser to put value in user_name field, since user field was disabled above. Probably OK to put both User and Username values in the same field. # 2012/03/11 - 2.7.2 - GMF - Added support for Power lines (Power Device detected, PD removed, Power granted) # 2012/11/20 - 2.7.3 - GMF - Copied "bytes" field to "bytes_xmt" or "bytes_rcv" based on direction, when bytes is specified by the other two aren't. # 2013/01/14 - 2.7.4 - GMF - Moved top_level_domain to destination_group # 2013-04-21 - 2.7.5 - GMF - Added parsing of "Privilege level" lines # 2013-04-21 - 2.7.6 - GMF - Added parsing of "User: * logged command" lines # 2013-04-21 - 2.7.6 - GMF - Added parsing of "Received BPDU with inconsistent peer vlan" lines # 2013-04-21 - 2.7.6 - GMF - Added parsing of "Blocking" lines # 2013-04-21 - 2.7.6 - GMF - Added parsing of "Unblocking" lines # 2013-11-18 - 2.7.7 - gas - added support for "for user 'username'" section of access-list lines # 2013-11-19 - 2.7.8 - gas - added support for collection of user name in access-list lines # 2014-02-18 - 2.7.9 - GMF - Added support for "Teardown dynamic TCP translation" lines # 2014-09-22 - 2.8.0 - MSG - Removed the ? from the Handle duration/flags expression, since it seemed to add a space in front of the bytes value. # 2014-11-04 - 2.8.1 - Lew - Added code to remove "translation from" from message field, also removed "from" from the from.to variable # The name of the log format log.format.format_label = "Cisco PIX/ASA/Router/Switch Log Format" log.miscellaneous.log_data_type = "syslog_required" log.miscellaneous.log_format_type = "firewall" # The log is in this format if any of the first ten lines match this regular expression log.format.autodetect_regular_expression = "%(PIX|IDS|FW|AUTH|IKE|PPTP|ASA|SEC|CDP|SYS|LINK|DUAL|ETHCNTR|LINEPROTO|PLATFORM|PM|RADIUS|SNMP|SPANTREE|STANDBY)[^ ]*: " log.format.autodetect_lines = "200" # All log field parsing will be done using the parsing filters log.format.parse_only_with_filters = "true" # Log fields log.fields = { source_ip.type = "host" source_hostname = "" source_mac_address = "" destination_ip = "" destination_hostname = "" source_port = "" source_network_port = "" destination_port = "" destination_network_port = "" destination_service = "" source_side = "" destination_side = "" interface = "" url = "" operation = "" message_code = "" message_facility = "" message_severity = "" message_mnemonic = "" # destination_bytes = "" protocol = "" flags = "" bytes = "" faddr_host = "" faddr_port = "" faddr_service = "" gaddr_host = "" gaddr_port = "" gaddr_service = "" laddr_host = "" laddr_port = "" laddr_service = "" duration = "" access_group = "" access_list = "" page.type = "page" message = "" #user = "" command = "" type = "" direction = "" user_name = "" group = "" list = "" #action = "" reason = "" icmp_type = "" icmp_code = "" state = "" vty_line = "" privilege_level = "" aaa_status = "" aaa_server = "" group_policy = "" private_ip = "" packets = "" vlan_id = "" # CRYPTO fields client_type = "" client_public_addr = "" client_application_version = "" server_public_addr = "" assigned_public_addr = "" # Fields from "Session disconnected." lines session_type = "" bytes_xmt = "" bytes_rcv = "" } # log.fields # log.filter_initialization = ` #int hit_cnt_index; #int hit_cnt_i; #int hit_cnt; #string insert_line; #` # Log Parsing Filters log.parsing_filters.parse = ` # Parse leading number: # 16: 000014: *Mar 1 00:28:47: %SEC-6-IPACCESSLOGP: list 100 permitted ... if (matches_regular_expression(v.syslog_message, '^[0-9]+: (.*)$')) then v.syslog_message = $1; if (matches_regular_expression(v.syslog_message, '^[0-9]+: (.*)$')) then v.syslog_message = $1; # Parse leading date/time # Oct 08 2005 04:32:54: if (matches_regular_expression(v.syslog_message, '^([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]): (.*)$')) then ( set_collected_field('', 'date', $2 . '/' . $1 . '/' . $3); set_collected_field('', 'time', $4); v.syslog_message = $5; ); # Parse leading date/time # :Oct 08 04:32:54 EST: else if (matches_regular_expression(v.syslog_message, '^:[A-Z][a-z][a-z] [0-9][0-9] [0-9][0-9]:[0-9][0-9]:[0-9][0-9][^:]*: (.*)$')) then ( v.syslog_message = $1; ); # Chop off leading date/time # e.g. Oct 08 04:32:54.123: # e.g. *Mar 1 00:21:22: # e.g. *Mar 1 00:21:22.456: # e.g. 16: 00:05:04: %SEC-6-IPACCESSLOGP: list 100 ... if (matches_regular_expression(v.syslog_message, '^\\\\*?[A-Z][a-z][a-z] [0-9 ][0-9] (.*)$')) then ( v.syslog_message = $1; ); if (matches_regular_expression(v.syslog_message, '^[0-9][0-9]:[0-9][0-9]:[0-9][0-9][.0-9]*: (.*)')) then ( v.syslog_message = $1; ); # Parse out the message code if (matches_regular_expression(v.syslog_message, '%([^:]+): (.*)$')) then ( set_collected_field('', 'message_code', $1); v.message_code = $1; v.message = $2; v.from = ''; v.to = ''; v.remainder = ''; # Break message code into facility, severity, and mnemonic if (matches_regular_expression(v.message_code, '^([^-]+)-([^-]+)-([^-]+)$')) then ( set_collected_field('', 'message_facility', $1); set_collected_field('', 'message_severity', $2); set_collected_field('', 'message_mnemonic', $3); ); #Dec 5 01:00:22 1.1.1.10 %ASA-4-113019: Group = 2.3.4.5, Username = 2.3.4.5, IP = 2.3.4.5, Session disconnected. Session Type: IPSecLAN2LAN, Duration: 2h:59m:59s, Bytes xmt: 19992, Bytes rcv: 0, Reason: User Requested #Dec 5 01:00:22 1.1.1.10 %ASA-5-713050: Group = 2.3.4.5, IP = 2.3.4.5, Connection terminated for peer 2.3.4.5. Reason: Peer Terminate Remote Proxy 199.129.9.99, Local Proxy 179.19.29.9 #<165>:Jul 01 10:56:11 CST: %PIX-vpn-5-713131: Group = XYZ_default, Username = user1, IP = 222.222.222.22, Received unknown transaction mode attribute: 28683 # get leading user, group and ip information - assume any kind of message can follow since these # messages are shown without this info at # http://www.cisco.com/en/US/products/ps6120/products_system_message_guide_chapter09186a00805452d3.html # Note that these values might be overwritten by values in the message. if (matches_regular_expression(v.message, '^Group = ([^,]+), (.*)$')) then ( set_collected_field('', 'group', $1); v.message = $2; ); # 11/22/2011 8:96 PM 192.168.9.10:192.168.9.10 ASA-6-716009 Nov 22 2011 20:96:46: %ASA-6-716009: Group User IP <68.105.48.159> WebVPN access GRANTED: http://citrixtest//Citrix/Metaframe/media/TabSelectedRight.png if (matches_regular_expression(v.message, '^Group <([^>]*)> User <([^>]*)> IP <([^>]*)> (.*)$')) then ( set_collected_field('', 'group', $1); set_collected_field('', 'user_name', $2); set_collected_field('', 'source_ip', $3); v.message = $4; ); if (matches_regular_expression(v.message, '^Username = ([^,]+), (.*)$')) then ( set_collected_field('', 'user_name', $1); v.message = $2; ); if (matches_regular_expression(v.message, '^IP = ([^,]+), (.*)$')) then ( set_collected_field('', 'source_ip', $1); v.message = $2; ); # Put the complete message in the message field set_collected_field('', 'message', v.message); # Handle Session disconnected lines #Dec 5 01:00:22 1.1.1.10 %ASA-4-113019: Group = 2.3.4.5, Username = 2.3.4.5, IP = 2.3.4.5, Session disconnected. Session Type: IPSecLAN2LAN, Duration: 2h:59m:59s, Bytes xmt: 19992, Bytes rcv: 0, Reason: User Requested #Jun 29 13:28:43 asa1 %ASA-4-113019: Group = ra-webvpn, Username = SCP, IP = 66.246.66.66, Session disconnected. Session Type: SSL, Duration: 0h:31m:03s, Bytes xmt: 281419, Bytes rcv: 128102, Reason: Idle Timeout if (matches_regular_expression(v.message, 'Session disconnected. (.*)')) then ( set_collected_field('', 'operation', 'Session disconnected'); collect_listed_fields('', $1, ', ', ': ', ''); if (matches_regular_expression(get_collected_field('', 'duration'), '^([0-9]*)h:([0-9]*)m:([0-9]*)s')) then ( set_collected_field('', 'duration', (60 * 60 * $1) + (60 * $2) + $3); ) ); # Handle "list" lines #2006-03-01 11:16:22 Local7.Info 10.11.11.11 24: 00:18:27: %SEC-6-IPACCESSLOGP: list 100 permitted tcp 255.255.255.255(0) -> 255.255.255.254(0), 1 packet #2006-03-01 11:21:55 Local7.Info 10.11.11.11 121: 00:23:59: %SEC-6-IPACCESSLOGP: list 100 permitted udp 10.11.11.12(0) -> 10.10.25.52(0), 1 packet #2002-08-26 13:14:10 Local7.Info 255.255.255.251 11643: 5w5d: %SEC-6-IPACCESSLOGDP: list 101 denied icmp 255.255.255.253 (Serial2/0 *PPP*) -> 255.255.255.252 (3/13), 1 packet #2006-02-27 10:11:52 Local7.Info 192.168.22.22 1009: Feb 27 02:07:45.707: %SEC-6-IPACCESSLOGP: list sdm_fastethernet0/1_in permitted tcp 192.168.22.23(0) -> 192.168.22.22(0), 1 packet else if (matches_regular_expression(v.message, '^list ([^ ]*) ([a-z]+) ([^ ]+) (.*)$')) then ( set_collected_field('', 'list', $1); set_collected_field('', 'operation', $2); set_collected_field('', 'protocol', $3); v.from_to = $4; # Extract "from" and "to" parts of the message v.to_index = index(v.from_to, ' -> '); if (v.to_index != -1) then ( v.from = substr(v.from_to, 0, v.to_index); v.to = substr(v.from_to, v.to_index + 4); # Get packets from the end of the line if (matches_regular_expression(v.to, '^(.*), ([0-9]+) packet')) then ( v.to = $1; set_collected_field('', 'packets', $2); ); ); # if to_index != -1 # Handle v.from and v.to in a list-specific way (the handler below works for PIX, but can't easily be extended to work for PIX and "list" lines). if (matches_regular_expression(v.from, '^([0-9.]+)(.*)$')) then ( set_collected_field('', 'source_ip', $1); v.from = $2; if (matches_regular_expression(v.from, '^\\\\(([0-9]+)\\\\)(.*)$')) then ( set_collected_field('', 'source_port', $1); v.from = $2; ); if (matches_regular_expression(v.from, '^ \\\\(([^)]+)\\\\)')) then ( set_collected_field('', 'source_network_port', $1); ); ); if (matches_regular_expression(v.to, '^([0-9.]+)(.*)$')) then ( set_collected_field('', 'destination_ip', $1); v.to = $2; if (matches_regular_expression(v.to, '^\\\\(([0-9]+)\\\\)(.*)$')) then ( set_collected_field('', 'destination_port', $1); v.to = $2; ); if (matches_regular_expression(v.to, '^ \\\\(([^)]+)\\\\)')) then ( set_collected_field('', 'destination_network_port', $1); ); ); v.from = ""; v.to = ""; ); # list # Handle Built connections - note that dynamic and static connections are really translations - # exclude them (for now) and lines actually described as translations - also exclude lines like # this: Built local-host outside:99.99.99.99 #if (matches_regular_expression(v.message, '^(Built) (inbound|outbound|dynamic) (TCP|UDP|ICMP) connection [0-9]+ for (.*)$')) then ( #) #else if (matches_regular_expression(v.message, '^(Built) (.*)$')) then ( #) #else if (matches_regular_expression(v.message, '^(Built) ((inbound|outbound|dynamic|static)? ?([A-Z]+)? (connection|translation).*)')) then ( #) else if (matches_regular_expression(v.message, '^(Built) ((inbound|outbound)? ?([A-Z]+)? connection.*)')) then ( set_collected_field('', 'operation', $1); v.message = $2; v.direction = ""; # Extract the direction, if any #if (matches_regular_expression(v.message, '^(inbound|outbound|dynamic) (.*)$')) then ( if (matches_regular_expression(v.message, '^(inbound|outbound) (.*)$')) then ( set_collected_field('', 'direction', $1); v.message = $2; v.direction = $1; ); # Extract user name, if any if (matches_regular_expression(v.message, '^(.*)[ ]+\\\\(([a-zA-Z]+[a-zA-Z0-9._]+)\\\\)$')) then ( set_collected_field('', 'user_name', $2); v.message = $1; ); # Extract the protocol if (matches_regular_expression(v.message, '^(TCP|UDP|ICMP) (.*)$')) then ( set_collected_field('', 'protocol', $1); v.message = $2; ); # Discard "connection for" v.connection_id = "unspecified"; if (matches_regular_expression(v.message, '^connection for (.*)$')) then v.message = $1; else if (matches_regular_expression(v.message, '^connection ([0-9-]+) for (.*)$')) then ( v.message = $2; v.connection_id = $1; set_collected_field($1, 'direction', v.direction); ); # Discard "translation from" if (matches_regular_expression(v.message, '^translation from (.*)$')) then v.message = $1; v.from_to = v.message; # Extract "from" and "to" parts of the message v.to_index = index(v.from_to, ' to '); if (v.to_index != -1) then ( # Reverse from and to if outbound # 2010-12-28 - GMF - Changed reversal of to/from to happen on outbound, instead of on inbound [ThreadID:974447]. # 2010-12-28 - GMF - the comment says we're reversing if outbound, but the code was actually reversing if *not* outbound (v.direction eq 'outbound') # And ThreadID:974447 indicates that the reversal is happening for inbound when it shouldn't. So, changing # this to reverse on outbound as the comment says we're doing. if (v.direction ne 'outbound') then ( v.from = substr(v.from_to, 0, v.to_index); v.to = substr(v.from_to, v.to_index + 4); ); else ( v.to = substr(v.from_to, 0, v.to_index); v.from = substr(v.from_to, v.to_index + 4); ); ); # Extract faddr/gaddr/laddr information from the message else if (matches_regular_expression(v.from_to, '^faddr ([0-9.]+)/([0-9]+) gaddr ([0-9.]+)/([0-9]+) laddr ([0-9.]+)/([0-9]+)')) then ( set_collected_field('', 'faddr_host', $1); set_collected_field('', 'faddr_port', $2); set_collected_field('', 'gaddr_host', $3); set_collected_field('', 'gaddr_port', $4); set_collected_field('', 'laddr_host', $5); set_collected_field('', 'laddr_port', $6); ); # if faddr/laddr/gaddr set_collected_field('', 'connections_built', 1); # count connections at build ); # Built # handle No route to IP from IP else if (matches_regular_expression(v.message, '(No route) to ([0-9.]+) from ([0-9.]+)')) then ( set_collected_field('', 'operation', $1); set_collected_field('', 'message', $1); set_collected_field('', 'destination_ip', $2); set_collected_field('', 'source_ip', $3); ); # handle CDP duplex mismatch message else if (matches_regular_expression(v.message, '(duplex [^,]*), with ([^ ]*) (.*)$' )) then ( set_collected_field('', 'operation', 'CDP'); set_collected_field('', 'message', $1); set_collected_field('', 'source_ip', $2); set_collected_field('', 'interface', $3); ); # Handle AAA lines #<166>Jul 01 2007 10:56:11: %PIX-6-113012: AAA user authentication Successful : local database : user = user1 # from cisco.com: %ASA-6-113004: AAA user authentication Successful : server = 192.168.130.66 : user = user1 # from oreilly.com: # %PIX-6-113004: AAA user aaa_type Successful : server = server_IP_address, User = username # %PIX-6-113005: AAA user authentication Rejected : reason = reason : server = server_IP_address, User = username else if (matches_regular_expression(v.message, '^(AAA user [^ ]+) ([^ ]+) : (.*)$')) then ( set_collected_field('', 'operation', $1); set_collected_field('', 'aaa_status', $2); v.rest = $3; if (matches_regular_expression(v.rest, 'reason = ([^:]+) : (.*)$')) then ( set_collected_field('', 'reason', $1); v.rest = $2; ); if (matches_regular_expression(v.rest, '(local database)( +: +|, +)[Uu]ser += +(.*)$')) then ( set_collected_field('', 'aaa_server', $1); set_collected_field('', 'user_name', $3); ); else if (matches_regular_expression(v.rest, 'server += +([0-9.]+)( +: +|, +)[Uu]ser += +(.*)$')) then ( set_collected_field('', 'aaa_server', $1); set_collected_field('', 'user_name', $3); ); ); # AAA user authentication #<166>Jul 01 2007 10:56:11: %PIX-6-113003: AAA group policy for user user1 is being set to XYZ_default else if (matches_regular_expression(v.message, '^(AAA group policy) for user ([^ ]+) is being set to ([^ ]+)$')) then ( set_collected_field('', 'operation', $1); set_collected_field('', 'user_name', $2); set_collected_field('', 'group_policy', $3); ); # AAA group policy #<166>Jul 01 2007 10:56:11: %PIX-6-113011: AAA retrieved user specific group policy (XYZ_default) for user = user1 #<166>Jul 01 2007 10:56:11: %PIX-6-113009: AAA retrieved default group policy (XYZ_default) for user = user1 else if (matches_regular_expression(v.message, '^(AAA retrieved [a-z ]+ group policy) \\\\(([^)]+)\\\\) for user = ([^ ]+)$')) then ( set_collected_field('', 'operation', $1); set_collected_field('', 'group_policy', $2); set_collected_field('', 'user_name', $3); ); # AAA group policy #<166>Jul 01 2007 10:56:11: %PIX-6-113008: AAA transaction status ACCEPT : user = user1 else if (matches_regular_expression(v.message, '^(AAA transaction status) ([^ ]+) : user = ([^ ]+)$')) then ( set_collected_field('', 'operation', $1); set_collected_field('', 'aaa_status', $2); set_collected_field('', 'user_name', $3); ); # AAA transaction status # 11/22/2011 8:96 PM 192.168.9.10:192.168.9.10 ASA-6-716009 Nov 22 2011 20:96:25: %ASA-6-716009: Group User IP <68.105.48.159> WebVPN access GRANTED: http://citrixtest//Citrix/Metaframe/media/Error24.gif else if (matches_regular_expression(v.message, "^(WebVPN access GRANTED): (.*)$")) then ( set_collected_field('', 'operation', $1); set_collected_field('', 'url', $2); ); # WebVPN access GRANTED # Handle VPN lines #<166>:Jul 02 13:50:43 CST: %PIX-vpn-6-713172: Group = XYZ_default, IP = 222.222.222.22, Automatic NAT Detection Status: Remote end IS behind a NAT device This end IS behind a NAT device else if (matches_regular_expression(v.message, '^(Automatic NAT Detection Status): +Remote end +([Ii][Ss]|[Ii][Ss] [Nn][Oo][Tt]) +behind a NAT device +This +end +([Ii][Ss]|[Ii][Ss] [Nn][Oo][Tt]) +behind a NAT device')) then ( set_collected_field('', 'operation', $1); set_collected_field('', 'remote_end_nat_status', lowercase($2)); set_collected_field('', 'this_end_nat_status', lowercase($3)); ); # VPN #<166>:Jul 01 10:56:11 CST: %PIX-vpn-6-713184: Group = XYZ_default, Username = user1, IP = 222.222.222.22, Client Type: WinNT Client Application Version: 4.6.03.0021 else if (matches_regular_expression(v.message, '^Client Type: (.*[^ ]) +Client Application Version: (.*)$')) then ( set_collected_field('', 'client_type', $1); set_collected_field('', 'client_application_version', $2); ); # VPN #<166>:Jul 01 10:56:11 CST: %PIX-vpn-6-713184: Group = XYZ_default, Username = user1, IP = 222.222.222.22, Assigned private IP address 10.1.1.1 to remote user else if (matches_regular_expression(v.message, '^(Assigned private IP address) ([0-9.]+) to remote user')) then ( set_collected_field('', 'operation', $1); set_collected_field('', 'private_ip', $2); ); # VPN #<163>:Jul 01 10:56:11 CST: %PIX-vpn-3-713119: Group = XYZ_default, Username = user1, IP = 222.222.222.22, PHASE 1 COMPLETED #<165>:Jul 01 10:56:11 CST: %PIX-vpn-5-713120: Group = XYZ_default, Username = user1, IP = 222.222.222.22, PHASE 2 COMPLETED (msgid=580f3682) else if (matches_regular_expression(v.message, '^(PHASE [0-9]+ COMPLETED)')) then ( set_collected_field('', 'operation', $1); ); # VPN #<165>:Jul 01 10:56:11 CST: %PIX-vpn-5-713049: Group = XYZ_default, Username = user1, IP = 222.222.222.22, Security negotiation complete for User (user1) Responder, Inbound SPI = 0x431ef9de, Outbound SPI = 0x5d483240 else if (matches_regular_expression(v.message, '^(Security negotiation complete) for User \\\\(([^]]*)\\\\) Responder, Inbound SPI = ([^,]*), Outbound SPI = ([^,]*)')) then ( set_collected_field('', 'operation', $1); set_collected_field('', 'user_name', $2); set_collected_field('', 'inbound_spi', lowercase($3)); set_collected_field('', 'outbound_spi', lowercase($4)); ); # VPN #<166>:Jul 01 10:56:11 CST: %PIX-vpn-6-602303: IPSEC: An outbound remote access SA (SPI= 0x5D483240) between 10.123.123.123 and 222.222.222.22 (user= user1) has been created. #<166>:Jul 01 10:56:11 CST: %PIX-vpn-6-602303: IPSEC: An inbound remote access SA (SPI= 0x431EF9DE) between 10.123.123.123 and 222.222.222.22 (user= user1) has been created. #<166>:Jul 01 10:57:13 CST: %PIX-vpn-6-602304: IPSEC: An inbound remote access SA (SPI= 0x431EF9DE) between 10.123.123.123 and 222.222.222.22 (user= user1) has been deleted. #<166>:Jul 01 10:57:13 CST: %PIX-vpn-6-602304: IPSEC: An outbound remote access SA (SPI= 0x5D483240) between 10.123.123.123 and 222.222.222.22 (user= user1) has been deleted. #Note that ips don't change positions based on direction as they do with Built/Teardown else if (matches_regular_expression(v.message, '^(IPSEC: An (inbound|outbound) remote access SA) \\\\(SPI= ([^)]+)\\\\) between ([0-9.]+) and ([0-9.]+) \\\\(user= ([^)]+)\\\\)( has been (created|deleted))')) then ( v.direction = lowercase($2); set_collected_field('', 'operation', $1 . $7); set_collected_field('', 'direction', v.direction); set_collected_field('', v.direction . '_spi', $3); set_collected_field('', 'destination_ip', $4); set_collected_field('', 'source_ip', $5); set_collected_field('', 'user_name', $6); ); # VPN #<165>:Jul 01 10:57:13 CST: %PIX-vpn-5-713050: Group = XYZ_default, Username = user1, IP = 222.222.222.22, Connection terminated for peer user1. +Reason: Peer Terminate Remote Proxy 10.1.1.1, Local Proxy 0.0.0.0 else if (matches_regular_expression(v.message, '^(Connection terminated for peer) ([^.]+). +Reason: (.*[^ ]) +Remote Proxy ([0-9.]+), Local Proxy')) then ( set_collected_field('', 'operation', $1); set_collected_field('', 'user_name', $2); set_collected_field('', 'reason', $3); set_collected_field('', 'private_ip', $4); ); # VPN # VPN lines not processed - seemingly not important #<165>:Jul 01 10:56:11 CST: %PIX-vpn-5-713131: Group = XYZ_default, Username = user1, IP = 222.222.222.22, Received unknown transaction mode attribute: 28683 #<165>:Jul 01 10:56:11 CST: %PIX-vpn-5-713075: Group = XYZ_default, Username = user1, IP = 222.222.222.22, Overriding Initiator's IPSec rekeying duration from 2147483 to 28800 seconds #<166>:Jul 01 10:56:11 CST: %PIX-vpn-6-713905: Group = XYZ_default, Username = user1, IP = 222.222.222.22, Starting P2 Rekey timer to expire in 27359 seconds # Handle Deny lines else if (matches_regular_expression(v.message, '^(Deny) (TCP|UDP|ICMP) \\\\(no connection\\\\) from (.*)$')) then ( set_collected_field('', 'operation', $1); set_collected_field('', 'protocol', uppercase($2)); v.from_to = $3; # Extract "from" and "to" parts of the message v.to_index = index(v.from_to, ' to '); if (v.to_index != -1) then ( v.from = substr(v.from_to, 0, v.to_index); v.to = substr(v.from_to, v.to_index + 4); # Get access-group from the end of the line v.flags_index = index(v.to, ' flags '); if ((v.flags_index != -1) and (matches_regular_expression(v.to, ' flags ([A-Z ]*) on interface (.*)$'))) then ( v.to = substr(v.to, 0, v.flags_index); set_collected_field('', 'flags', $1); set_collected_field('', 'interface', $2); ); ); # if to_index != -1 ); # if Deny TCP # Handle "Deny inbound TCP from" lines # %PIX-2-106006: Deny inbound UDP from 61.16.42.217 (unresolved) /37722 to 66.133.60.12 (66-133-60-12.somewhere) /1027 on interface outside else if (matches_regular_expression(v.message, '^(Deny) (inbound|outbound) (TCP|UDP|ICMP) from (.*)')) then ( set_collected_field('', 'operation', $1); set_collected_field('', 'direction', $2); set_collected_field('', 'protocol', $3); v.from_to = $4; # Extract "from" and "to" parts of the message v.to_index = index(v.from_to, ' to '); if (v.to_index != -1) then ( v.from = substr(v.from_to, 0, v.to_index); v.to = substr(v.from_to, v.to_index + 4); # Get "on interface" from the end of the line v.on_interface_index = index(v.to, ' on interface '); if ((v.on_interface_index != -1) and matches_regular_expression(v.to, ' on interface (.*)$')) then ( v.to = substr(v.to, 0, v.on_interface_index); set_collected_field('', 'interface', $1); ); ); # if to_index != -1 ); # Deny inbound ... # Handle "Deny inbound tcp" lines #%PIX-3-106011: Deny inbound (No xlate) tcp src outside:66.143.107.49 (TSNS2-LBA0LPW6A) /1724 dst outside:66.143.60.112 (66-143-60-112.datacoremarketing.com) /139 else if (matches_regular_expression(v.message, '^(Deny) (inbound|outbound) (.*)$')) then ( set_collected_field('', 'operation', $1); set_collected_field('', 'direction', $2); v.remainder = $3; # Extract no xlate if (matches_regular_expression(v.remainder, '^\\\\(No xlate\\\\) (.*)$')) then v.remainder = $1; # Get protocol and src/dst if (matches_regular_expression(v.remainder, '^(tcp|udp|icmp) src (.*)$')) then ( set_collected_field('', 'protocol', $1); v.from_to = $2; # Extract "from" and "to" parts of the message v.to_index = index(v.from_to, ' dst '); if (v.to_index != -1) then ( v.from = substr(v.from_to, 0, v.to_index); v.to = substr(v.from_to, v.to_index + 5); # Get access-group from the end of the line v.by_access_group_index = index(v.to, ' by access-group '); if ((v.by_access_group_index != -1) and (matches_regular_expression(v.to, ' by access-group "([^"]+)"'))) then ( v.to = substr(v.to, 0, v.by_access_group_index); set_collected_field('', 'access_group', $1); ); # Get type,code from the end of the line v.type_code_index = index(v.to, ' (type '); if ((v.type_code_index != -1) and (matches_regular_expression(v.to, ' \\\\(type [0-9]+.*$'))) then ( v.to = substr(v.to, 0, v.type_code_index); ); ); # if to_index != -1 ); # if no xlate ); # Deny inbound ... # Handle "Inbound TCP connection denied" lines # %PIX-2-106001: Inbound TCP connection denied from 61.143.107.49 (ASNS5-LBB0LPW6A) /1724 to 61.143.60.112 (61-143-60-112.somewhere.com) /139 flags SYN on interface outside else if (matches_regular_expression(v.message, '^(Inbound|Outbound) (TCP|UDP|ICMP) connection (denied) from (.*)')) then ( set_collected_field('', 'direction', lowercase($1)); set_collected_field('', 'operation', 'Deny'); set_collected_field('', 'protocol', $2); v.from_to = $4; # Extract "from" and "to" parts of the message v.to_index = index(v.from_to, ' to '); if (v.to_index != -1) then ( v.from = substr(v.from_to, 0, v.to_index); v.to = substr(v.from_to, v.to_index + 4); # Get "on interface" from the end of the line v.on_interface_index = index(v.to, ' on interface '); if ((v.on_interface_index != -1) and matches_regular_expression(v.to, ' on interface (.*)$')) then ( v.to = substr(v.to, 0, v.on_interface_index); set_collected_field('', 'interface', $1); ); # Get "flags" from the end of the line v.flags_index = index(v.to, ' flags '); if ((v.flags_index != -1) and matches_regular_expression(v.to, ' flags (.*)$')) then ( v.to = substr(v.to, 0, v.flags_index); v.flags = $1; while (ends_with(v.flags, ' ')) v.flags = substr(v.flags, 0, length(v.flags) - 1); set_collected_field('', 'flags', v.flags); ); ); # if to_index != -1 ); # Deny inbound ... # Handle Deny...src lines #Dec 31 23:41:05 here.there.edu Dec 31 2006 23:41:05: %FWSM-4-106023: Deny icmp src outside:166.66.66.66 dst inside:mail.here.there.com (type 8, code 0) by access-group "INBOUND" #2006-12-22 10:39:19 Local4.Warning 192.168.1.137 Dec 21 2006 18:36:14: %ASA-4-106023: Deny icmp src outside:192.168.1.135 dst inside:192.168.1.138 (type 8, code 0) by access-group "outside_access_in" [0x0, 0x0] #Dec 31 23:33:22 fx-45-pri.net.wisc.edu Dec 31 2006 23:33:23: %FWSM-4-106023: Deny udp src outside:244.44.44.44/59787 dst inside:LJPrinter/1026 by access-group "INBOUND" #Oct 31 09:12:48 tdn-ar03-outside %FWSM-5-106023: Deny protocol 46 src outside:211.11.11.11 dst inside:1.1.1.10 by access-group "outside" #Dec 31 23:33:23 here.there.edu Dec 31 2006 23:33:23: %FWSM-4-106023: Deny udp src outside:244.46.248.44/59828 dst inside:Carol/1027 by access-group "INBOUND" else if (matches_regular_expression(v.message, '^(Deny) (tcp|udp|icmp|protocol [^ ]+) src (.*)')) then ( set_collected_field('', 'operation', $1); v.protocol = $2; v.from_to = $3; if (matches_regular_expression(v.protocol, '^protocol ([^ ]+)$')) then ( v.protocol = $1; ); else ( v.protocol = uppercase(v.protocol); ); set_collected_field('', 'protocol', v.protocol); # Extract "from" and "to" parts of the message v.to_index = index(v.from_to, ' dst '); if (v.to_index != -1) then ( v.from = substr(v.from_to, 0, v.to_index); v.to = substr(v.from_to, v.to_index + 5); # get icmp type and code if present if (matches_regular_expression(v.to, '^(.*) \\\\(type ([0-9]+), code ([0-9]+)\\\\)')) then ( v.to = $1; set_collected_field('', 'icmp_type', $2); set_collected_field('', 'icmp_code', $3); ); # Get access-group from the end of the line v.by_access_group_index = index(v.to, ' by access-group '); if ((v.by_access_group_index != -1) and (matches_regular_expression(v.to, ' by access-group "([^"]+)"'))) then ( v.to = substr(v.to, 0, v.by_access_group_index); set_collected_field('', 'access_group', $1); ); ); # if to_index != -1 ); # Deny # Handle "UDP access denied by ACL" lines # %ASA-3-710003: UDP access denied by ACL from 19.25.235.19/138 to DMZ:19.25.235.255/138 else if (matches_regular_expression(v.message, '^([A-Z]+) access denied by ACL from (.*)')) then ( set_collected_field('', 'protocol', $1); set_collected_field('', 'operation', 'Deny by ACL'); v.from_to = $2; # Extract "from" and "to" parts of the message v.to_index = index(v.from_to, ' to '); if (v.to_index != -1) then ( v.from = substr(v.from_to, 0, v.to_index); v.to = substr(v.from_to, v.to_index + 4); ); # if to_index != -1 ); # UDP access denied by ACL # Handle "Denied ICMP..." lines #2006-12-19 17:03:58 Local4.Error 192.168.1.137 Dec 19 2006 01:01:15: %ASA-3-313001: Denied ICMP type=8, code=0 from 192.168.1.135 on interface outside #Dec 5 04:17:38 1.1.1.10 %ASA-3-313001: Denied ICMP type=3, code=3 from 233.33.33.33 on interface outside #Oct 31 08:17:50 tdn-ar03-outside %FWSM-4-313004: Denied ICMP type=3, from laddr 254.54.54.54 on interface inside to 1.1.1.10: no matching session else if (matches_regular_expression(v.message, '^Denied ([A-Z]+) (.*)')) then ( set_collected_field('', 'operation', 'Deny'); set_collected_field('', 'protocol', $1); v.from_to = $2; # note compensation for Boost non-greediness if (matches_regular_expression(v.from_to, '^type=([^, ]+)[, ]+([^, ].*)')) then ( set_collected_field('', 'icmp_type', $1); v.from_to = $2; ); if (matches_regular_expression(v.from_to, '^code=([^, ]+)[, ]+([^, ].*)')) then ( set_collected_field('', 'icmp_code', $1); v.from_to = $2; ); if (matches_regular_expression(v.from_to, '^from (.*)$')) then ( v.from_to = $1; ); # Extract "from", "to", "interface" and "reason" parts of the message v.on_interface_index = index(v.from_to, ' on interface '); if (v.on_interface_index != -1) then ( v.from = substr(v.from_to, 0, v.on_interface_index); v.interface = substr(v.from_to, v.on_interface_index + 14); ); # if on_interface_index != -1 v.to_index = index(v.interface, ' to '); if (v.to_index != -1) then ( v.to = substr(v.interface, v.to_index + 4); v.interface = substr(v.interface, 0, v.to_index); # for now, assume this doesn't happen if there is no "to" part if (matches_regular_expression(v.to, '([^:]+): (.*)')) then ( v.to = $1; set_collected_field('', 'reason', $2); ); ); # if to_index != -1 set_collected_field('', 'interface', v.interface); if (matches_regular_expression(v.from, 'laddr (.*)')) then ( set_collected_field('', 'laddr_host', $1); v.from = ''; ); ); # Denied ICMP # Handle "Deny UDP reverse path check" #2006-12-19 13:08:47 Local4.Alert 192.168.1.137 Dec 18 2006 21:06:05: %ASA-1-106021: Deny UDP reverse path check from 192.168.1.134 to 192.168.1.255 on interface inside else if (matches_regular_expression(v.message, '^Deny UDP reverse path check from (.*)')) then ( v.from_to = $1; set_collected_field('', 'operation', 'Deny UDP reverse path check'); v.to_index = index(v.from_to, ' to '); if (v.to_index != -1) then ( v.from = substr(v.from_to, 0, v.to_index); v.to = substr(v.from_to, v.to_index + 4); # Get "on interface" from the end of the line v.on_interface_index = index(v.to, ' on interface '); if ((v.on_interface_index != -1) and matches_regular_expression(v.to, ' on interface (.*)$')) then ( v.to = substr(v.to, 0, v.on_interface_index); set_collected_field('', 'interface', $1); ); ); # if v.to_index != -1 ); # Deny UDP reverse path check # Handle Teardown lines else if (matches_regular_expression(v.message, '^(Teardown) (dynamic )?(UDP|TCP|ICMP) (connection|translation) (.*)')) then ( set_collected_field('', 'operation', $1); set_collected_field('', 'protocol', $3); v.from_to = $5; v.direction = "outbound"; # default if there was no Built line, or there is no connection number # Extract user name, if any if (matches_regular_expression(v.from_to, '^(.*)[ ]+\\\\(([a-zA-Z]+[a-zA-Z0-9._]+)\\\\)$')) then ( set_collected_field('', 'user_name', $2); v.from_to = $1; ); # Discard connection number, if any if (matches_regular_expression(v.from_to, '^([0-9-]+) (.*)$')) then ( v.from_to = $2; #if (get_collected_field($1, 'direction') eq 'inbound') then # might be 'outbound', '' or 'dynamic' # v.direction = "inbound"; v.direction = get_collected_field($1, 'direction'); set_collected_field('', 'direction', v.direction); if (v.direction eq "") then v.direction = 'outbound'; ); # Discard "for" if (matches_regular_expression(v.from_to, '^for (.*)$')) then v.from_to = $1; # Discard "from" if (matches_regular_expression(v.from_to, '^from (.*)$')) then v.from_to = $1; # Handle faddr/laddr/gaddr syntax if (matches_regular_expression(v.from_to, '^faddr ([0-9.]+)/([0-9]+) gaddr ([0-9.]+)/([0-9]+) laddr ([0-9.]+)/([0-9]+)(.*)$')) then ( set_collected_field('', 'faddr_host', $1); set_collected_field('', 'faddr_port', $2); set_collected_field('', 'gaddr_host', $3); set_collected_field('', 'gaddr_port', $4); set_collected_field('', 'laddr_host', $5); set_collected_field('', 'laddr_port', $6); v.remainder = $7; ); # if faddr/laddr/gaddr # Handle for/to syntax else ( # Extract "from" and "to" parts of the message v.to_index = index(v.from_to, ' to '); if (v.to_index != -1) then ( v.from_part = substr(v.from_to, 0, v.to_index); v.to_part = substr(v.from_to, v.to_index + 4); # Extract duration, bytes, and flags from end of line (end of v.to_part) v.duration_index = index(v.to_part, ' duration '); if (v.duration_index != -1) then ( v.remainder = substr(v.to_part, v.duration_index); v.to_part = substr(v.to_part, 0, v.duration_index); ); # if duration # Reverse from and to if outbound # 2009-11-20 - GMF - Maybe we should do this, but I'm not convinced. Look at this log data below [ThreadID:699166]. Clearly, 1.2.3.4 is the "to" address. # Indeed, the customer reports that reversing this is wrong, and that 1.2.3.4 *is* the "to" address in this case. Lacking any example # to the contrary, I'm commenting out this reversal. # # Oct 6 06:03:14 10.28.254.116 %ASA-6-302013: Built outbound TCP connection 1008993 for outside:A_BC-DE006/80 (A_BC-DE006/80) to inside:1.2.3.4/4594 (1.2.3.4/4594) # Oct 6 06:53:14 10.28.254.116 %ASA-6-302014: Teardown TCP connection 1008993 for outside:A_BC-DE006/80 to inside:1.2.3.4/4594 duration 0:50:00 bytes 354 TCP FINs # # 2011-09-13 - GMF - Restoring this reversal, as per ThreadID:1125928. Graham provides the following log sample (and references http://www.cisco.com/en/US/docs/security/pix/pix63/system/message/pixemsgs.html). In this case, it surely doesn't make sense for the "source" address to be 192.168.0.209 for Built, and for the "source" address to be 213.107.110.196 for Teardown. Both are the same connection, so both have the same source and destination. The Cisco doc says, "If inbound is specified, then the original control connection is initiated from the outside," so "source" is "inside" for outbound connections, and "source" is "outside" for inbound connections. So, I'm re-enabling this. # # 2011-05-06 00:00:10 Local4.Info 192.168.0.2 %PIX-6-302015: Built outbound UDP connection 685499 for outside:213.107.110.196/36363 (213.107.110.196/36363) to inside:192.168.0.209/29400 (195.248.193.82/56815) # 2011-05-06 00:02:21 Local4.Info 192.168.0.2 %PIX-6-302016: Teardown UDP connection 685499 for outside:213.107.110.196/36363 to inside:192.168.0.209/29400 duration 0:02:11 bytes 456 # if (v.direction eq 'outbound') then ( v.from = v.to_part; v.to = v.from_part; ); else ( v.from = v.from_part; v.to = v.to_part; ); ); # if for/to ); # if not faddr/laddr/gaddrbytes # Handle duration/flags section at end of line # The "?" in the expression seems to break the parser # if (matches_regular_expression(v.remainder, '^ duration ([0-9:]+) ?(.*)$')) then ( if (matches_regular_expression(v.remainder, '^ duration ([0-9:]+) (.*)$')) then ( set_collected_field('', 'duration', $1); v.remainder = $2; if (matches_regular_expression(get_collected_field('', 'duration'), '^([0-9]*):([0-9]*):([0-9]*)')) then ( set_collected_field('', 'duration', (60 * 60 * $1) + (60 * $2) + $3); ); v.bytes = 0; if (matches_regular_expression(v.remainder, '^bytes ([0-9]+) (.*)$')) then ( #set_collected_field('', 'bytes', $1); v.bytes = $1; set_collected_field('', 'flags', replace_first(replace_first($2, ')', ']'), '(', '[')); ); # if bytes and flags else if (matches_regular_expression(v.remainder, '^bytes ([0-9]+)$')) then ( #set_collected_field('', 'bytes', $1); v.bytes = $1; ); else if (matches_regular_expression(v.remainder, '^bytes ([0-9]+):')) then ( #set_collected_field('', 'bytes', $1); v.bytes = $1; ); # if just bytes # Compensate for Cisco bug where if bytes is (incorrectly) a small negative number # it will appear to be a huge number because the type is unsigned. #<166>:Jul 05 03:46:29 EST: %PIX-session-6-302014: Teardown TCP connection 181441 for Outside:222.22.222.22/80 to inside:10.22.2.22/1071 duration 0:00:03 bytes 4294967288 TCP FINs if (v.bytes > 4200000000) then ( v.bytes = 0; ); set_collected_field('', 'bytes', v.bytes); ); # extract duration # If "bytes" is specified in the line, but bytes_xmt and bytes_rcv are not, set them appropriately based on v.direction if ((get_collected_field('', 'bytes') != 0) and (get_collected_field('', 'bytes_xmt') == 0) and (get_collected_field('', 'bytes_rcv') == 0)) then ( if (v.direction eq "inbound") then set_collected_field('', 'bytes_rcv', get_collected_field('', 'bytes')); else set_collected_field('', 'bytes_xmt', get_collected_field('', 'bytes')); ); set_collected_field('', 'connections_torn_down', 1); # count connections at teardown ); # Teardown # Handle access-list lines #Oct 31 08:17:56 tdn-ar03-outside %FWSM-5-106100: access-list outside permitted tcp outside/133.133.133.133(24333) -> inside/1.1.22.220(80) hit-cnt 1 (600-second interval) # Note: the following example isn't supported - Cisco says "no action required" #2006-03-01 11:21:58 Local7.Info 10.10.22.22 122: 00:24:02: %SEC-6-IPACCESSLOGRL: access-list logging rate-limited or missed 51 packets #2013-11-13 06:13:24 Local7.Warning 10.100.0.1 Nov 13 2013 06:13:33: %ASA-4-106102: access-list Somesuch_VPN permitted tcp for user 'who' VPN-Inside/100.100.100.21(57634) -> VPN-Inside/100.108.126.90(445) hit-cnt 1 first hit [0x1c80ed66, 0xb8be1cf9] else if (matches_regular_expression(v.message, '^access-list ([^ ]*) (permitted|denied) (tcp|udp|icmp) (.*)$')) then ( #([^ ]*) -> ([^ ]*) (.*)$')) then ( set_collected_field('', 'access_list', $1); set_collected_field('', 'operation', $2); set_collected_field('', 'protocol', uppercase($3)); v.remainder = $4; if (matches_regular_expression(v.remainder, 'for user .([^ ]+). (.*)$')) then ( set_collected_field('', 'user_name', $1); v.remainder = $2; ); if (matches_regular_expression(v.remainder, '([^ ]*) -> ([^ ]*) (.*)$')) then ( v.from = $1; v.to = $2; if (matches_regular_expression(v.from, '^([^/]*)/([0-9.]+)\\\\(([0-9]+)\\\\)$')) then ( set_collected_field('', 'source_side', $1); set_collected_field('', 'source_ip', $2); set_collected_field('', 'source_port', $3); v.from = ""; ); if (matches_regular_expression(v.to, '^([^/]*)/([0-9.]+)\\\\(([0-9]+)\\\\)$')) then ( set_collected_field('', 'destination_side', $1); set_collected_field('', 'destination_ip', $2); set_collected_field('', 'destination_port', $3); v.to = ""; ); ); ); # Handle "Portmapped translation built" lines else if (matches_regular_expression(v.message, '^(Portmapped translation built) for (.*)$')) then ( set_collected_field('', 'operation', $1); v.for = $2; # Handle laddr/gaddr syntax if (matches_regular_expression(v.for, '^gaddr ([0-9.]+)/([0-9]+) laddr ([0-9.]+)/([0-9]+)')) then ( set_collected_field('', 'gaddr_host', $1); set_collected_field('', 'gaddr_port', $2); set_collected_field('', 'laddr_host', $3); set_collected_field('', 'laddr_port', $4); ); # if laddr/gaddr ); # Portmapped translation built # Handle "No translation group found" lines else if (matches_regular_expression(v.message, '^(No translation group found) for (tcp|udp|icmp) ')) then ( set_collected_field('', 'operation', $1); set_collected_field('', 'protocol', uppercase($2)); ); # Handle "Invalid destination" lines #Mar 4 12:23:31 here.there.com Mar 04 2003 13:40:08: %PIX-4-313003: Invalid destination for ICMP error message: ICMP source 211.11.11.11 destination 244.44.44.44 (type 3, code 1) on outside interface. Original IP payload: TCP source 222.22.22.22/8080 destination 229.9.9.9/ #Jan 1 06:54:58 here.there.org %PIX-4-313003: Invalid destination for ICMP error message: icmp src service1:172.16.6.73 dst outside:206.38.38.36 (type 3, code 3) on service1 interface. Original IP payload: udp src 236.33.33.63/53 dst 172.16.16.16/3968. #else if (matches_regular_expression(v.message, '^(Invalid destination) for ([A-Z]+) error message: ([A-Z]+) source ([0-9.]+) destination ([0-9.]+) \\\\(type ([0-9]+), code ([0-9]+)\\\\) (.*)$')) then ( else if (matches_regular_expression(v.message, '^(Invalid destination) for ([^ ]+) error message: ([^ ]+) (src|source) (.*)')) then ( set_collected_field('', 'operation', $1); set_collected_field('', 'protocol', uppercase($2)); v.src = $4; v.from_to = $5; if (matches_regular_expression(v.from_to, '^(.*) \\\\(type ([0-9]+), code ([0-9]+)\\\\) on ([^ ]+) interface')) then ( set_collected_field('', 'icmp_type', $2); set_collected_field('', 'icmp_code', $3); set_collected_field('', 'interface', $4); v.from_to = $1; ); # no examples, but if this can happen for other protocols, it probably looks like this else if (matches_regular_expression(v.from_to, '^(.*) on ([^ ]+) interface')) then ( set_collected_field('', 'interface', $2); v.from_to = $1; ); # Extract "from" and "to" parts of the message v.splitter = " dst "; v.slength = 5; if (v.src eq 'source') then ( v.splitter = " destination "; v.slength = 13; ); v.to_index = index(v.from_to, v.splitter); if (v.to_index != -1) then ( v.from = substr(v.from_to, 0, v.to_index); v.to = substr(v.from_to, v.to_index + v.slength); ); ); # if Invalid destination # Handle "Denied SSH session" lines. # e.g. Denied SSH session from 11.12.220.50 on interface abc else if (matches_regular_expression(v.message, '^(Denied SSH session) from (.*)$')) then ( set_collected_field('', 'operation', $1); v.from = $2; # v.from is now '11.12.220.50 on interface abc' in the e.g. above. # Extract interface from end of line (end of v.from) v.on_interface_index = index(v.from, ' on interface '); if (v.on_interface_index != -1) then ( set_collected_field('', 'interface', substr(v.from, v.on_interface_index + 14)); v.from = substr(v.from, 0, v.on_interface_index); ); # if on interface ); # if Denied SSH session # Handle "Received ARP request collision" lines # e.g. Received ARP request collision from 12.126.51.13/01e0.81a3.4ff1 on interface abc else if (matches_regular_expression(v.message, '^(Received ARP request collision) from ([0-9.]+)/([0-9a-zA-Z.]+) on interface (.*)$')) then ( set_collected_field('', 'operation', $1); set_collected_field('', 'source_ip', $2); set_collected_field('', 'source_mac_address', $3); set_collected_field('', 'interface', $4); ); # if Received ARP request collision # Handle "Accessed URL" else if (contains(v.message, ' Accessed URL ')) then ( set_collected_field('', 'operation', 'Accessed URL'); v.accessed_url_index = index(v.message, ' Accessed URL '); v.source = substr(v.message, 0, v.accessed_url_index); v.url = substr(v.message, v.accessed_url_index + 14); # Extract source information if (matches_regular_expression(v.source, '^([A-Za-z][A-Za-z0-9_.]+)@(.*)$')) then ( set_collected_field('', 'user_name', $1); v.source = $2; ); if (matches_regular_expression(v.source, '^([0-9.]+)(.*)$')) then ( set_collected_field('', 'source_ip', $1); v.source = $2; if (matches_regular_expression(v.source, '^ \\\\([^)]+\\\\)$')) then set_collected_field('', 'source_hostname', $1); ); # Extract page information if (matches_regular_expression(v.url, '^([^:]+):(.*)$')) then ( v.destination = $1; set_collected_field('', 'url', $2); ); # Extract destination information if (matches_regular_expression(v.destination, '^([0-9.]+)(.*)$')) then ( set_collected_field('', 'destination_ip', $1); v.destination = $2; if (matches_regular_expression(v.destination, '^ \\\\([^)]+\\\\)$')) then set_collected_field('', 'destination_hostname', $1); ); ); # if Accessed URL #2006-12-19 11:05:00 Local4.Notice 199.169.9.139 Dec 18 2006 19:02:18: %ASA-5-111008: User 'user1' executed the 'match protocol yahoo-im msn-im' command. else if (matches_regular_expression(v.message, "^User '([^']+)' executed the '([^']+)' command\\\\.")) then ( set_collected_field('', 'operation', "Command executed"); set_collected_field('', 'user_name', $1); set_collected_field('', 'command', $2); ); #2013-04-10 13:12:19 Syslog.Notice 192.168.255.222 614: cs-abcdef: Apr 10 2013 13:12:18.587 est: %PARSER-5-CFGLOG_LOGGEDCMD: User: logged command:!exec: enable else if (matches_regular_expression(v.message, "^User: <([^>]+)> logged command:(.*)$")) then ( set_collected_field('', 'operation', "User logged command"); set_collected_field('', 'user_name', $1); set_collected_field('', 'command', $2); ); # Handle crashinfo entries # these examples come from http://www.cisco.com/warp/public/63/crashinfo.html #%LINK-5-CHANGED: Interface Ethernet0/5, changed state to administratively down #%LINK-5-CHANGED: Interface FastEthernet9/1/0, changed state to administratively down #%LINK-3-UPDOWN: Interface Ethernet0/0, changed state to up #%LINK-3-UPDOWN: Interface Hssi9/0/1, changed state to up #%SYS-5-CONFIG_I: Configured from console by console #%SYS-5-CONFIG_I: Configured from console by vty0 (144.254.2.77) #%SYS-5-CONFIG_I: Configured from memory by console #2007-01-16 10:39:26 Local7.Notice 10.20.20.20 866: 1w3d: %LINK-5-CHANGED: Interface FastEthernet0/36, changed state to administratively down #2007-01-16 10:39:28 Local7.Error 10.20.20.20 867: 1w3d: %LINK-3-UPDOWN: Interface FastEthernet0/36, changed state to down else if (matches_regular_expression(v.message, '^Interface ([^,]+), (changed state) to (.*)')) then ( set_collected_field('', 'operation', $2); set_collected_field('', 'interface', $1); set_collected_field('', 'state', $3); ); # Feb 28 23:59:29 172.30.203.6 6488749: 6488745: Feb 28 23:59:28.566 NZDT: %ILPOWER-5-IEEE_DISCONNECT: Interface Fa0/6: PD removed # Feb 28 23:59:21 172.30.203.6 6488745: 6488741: Feb 28 23:59:20.966 NZDT: %ILPOWER-7-DETECT: Interface Fa0/6: Power Device detected: Cisco PD # Feb 29 00:01:54 172.30.203.6 6488805: 6488801: Feb 29 00:01:53.531 NZDT: %ILPOWER-5-POWER_GRANTED: Interface Fa0/6: Power granted else if (matches_regular_expression(v.message, '^Interface ([^,]+): (Power.*|PD.*)')) then ( set_collected_field('', 'operation', $2); set_collected_field('', 'interface', $1); ); #2007-01-16 10:39:37 Local7.Notice 10.20.20.20 868: 1w3d: %SYS-5-CONFIG_I: Configured from console by netadmin on vty0 (10.20.20.25) else if (matches_regular_expression(v.message, '^(Configured) from ([^ ]+) by (.*)')) then ( set_collected_field('', 'operation', $1); set_collected_field('', 'location', $2); v.user = $3; if (matches_regular_expression(v.user, '^(.*) on (vty[0-9]+) \\\\(([^)]+)\\\\)')) then ( v.user = $1; set_collected_field('', 'vty_line', $2); v.from = $3; ); else if (matches_regular_expression(v.user, '^(vty[0-9]+) \\\\(([^)]+)\\\\)')) then ( set_collected_field('', 'vty_line', $1); v.from = $2; v.user = ""; ); #else ( # don't know what to call the "by" field if it isn't a user - using user for now #v.user = ''; #); set_collected_field('', 'user_name', v.user); ); #2013-04-10 13:12:19 Syslog.Notice 192.168.255.222 613: cs-abcdef: Apr 10 2013 13:12:18.587 est: %SYS-5-PRIV_I: Privilege level set to 15 by on vty0 (192.168.150.15) else if (matches_regular_expression(v.message, '^Privilege level set to ([0-9]+) by <([^>]+)> on ([^ ]+) [(]([^)]+)[)]')) then ( set_collected_field('', 'privilege_level', $1); set_collected_field('', 'user_name', $2); set_collected_field('', 'vty_line', $3); v.from = $4; ); # if Privilege level # 2013-04-11 03:50:12 Local7.Critical 192.168.72.11 38: Apr 11 03:50:10.776 est: %SPANTREE-2-RECV_PVID_ERR: Received BPDU with inconsistent peer vlan id 20 on GigabitEthernet0/1 VLAN1. else if (matches_regular_expression(v.message, '^(Received BPDU with inconsistent peer vlan id) ([0-9]+) on ([^.]+)[.]')) then ( set_collected_field('', 'operation', $1); set_collected_field('', 'vlan_id', $2); set_collected_field('', 'interface', $3); ); # 2013-04-11 03:50:12 Local7.Critical 192.168.72.11 38: Apr 11 03:50:10.776 est: %SPANTREE-2-RECV_PVID_ERR: Received BPDU with inconsistent peer vlan id 20 on GigabitEthernet0/1 VLAN1. else if (matches_regular_expression(v.message, '^(Received BPDU with inconsistent peer vlan id) ([0-9]+) on ([^.]+)[.]')) then ( set_collected_field('', 'operation', $1); set_collected_field('', 'vlan_id', $2); set_collected_field('', 'interface', $3); ); # 2013-04-11 03:50:12 Local7.Critical 192.168.72.11 39: Apr 11 03:50:10.776 est: %SPANTREE-2-BLOCK_PVID_PEER: Blocking GigabitEthernet0/1 on VLAN0020. Inconsistent peer vlan. # 2013-04-11 03:50:27 Local7.Critical 192.168.72.11 42: Apr 11 03:50:25.777 est: %SPANTREE-2-UNBLOCK_CONSIST_PORT: Unblocking GigabitEthernet0/1 on VLAN0020. Port consistency restored. else if (matches_regular_expression(v.message, '^(Blocking|Unblocking) ([^ ]+) on ([^.]+)[.] (Inconsistent peer vlan|Port consistency restored)[.]')) then ( set_collected_field('', 'operation', $1 . ': ' . $4); set_collected_field('', 'interface', $2); set_collected_field('', 'vlan_id', $3); ); #Mar 5 17:03:52 something.somewhere.com 414331: a12345: Mar 5 17:03:52.051: %CRYPTO-6-EZVPN_CONNECTION_UP: (Server) Mode=CLIENT_OR_NEM_PLUS Client_type=UNKNOWN User=someone\somegroup Group=GROUP_USERS Client_public_addr=12.34.56.78 Server_public_addr=98.76.54.32 Assigned_client_addr=23.45.67.89 else if (get_collected_field('', 'message_facility') eq 'CRYPTO') then ( if (matches_regular_expression(v.message, '^[(]Server[)] (.*)$')) then ( v.message = $1; v.double_space_index = index(v.message, ' '); set_collected_field('', 'operation', substr(v.message, 0, v.double_space_index)); v.message = substr(v.message, v.double_space_index + 2); collect_listed_fields('', v.message, ' ', '=', 'User=user_name'); ); ); # Parse "from" information if (v.from ne '') then ( if (matches_regular_expression(v.from, '^([^:]+):(.*)$')) then ( set_collected_field('', 'source_side', $1); v.from = $2; ); if (matches_regular_expression(v.from, '^([^ ]*)/([0-9]+)')) then ( set_collected_field('', 'source_ip', $1); set_collected_field('', 'source_port', $2); ); else if (matches_regular_expression(v.from, '^([0-9.]+) \\\\(([^)]+)\\\\)(.*)$')) then ( set_collected_field('', 'source_ip', $1); set_collected_field('', 'source_hostname', $2); v.remainder = $3; if (matches_regular_expression(v.remainder, '^ /([0-9]+)')) then set_collected_field('', 'source_port', $1); ); else if (matches_regular_expression(v.from, '^([0-9.]+)$')) then ( set_collected_field('', 'source_ip', $1); ); ); # Parse "to" information if (v.to ne '') then ( if (matches_regular_expression(v.to, '^([^:]+):(.*)$')) then ( set_collected_field('', 'destination_side', $1); v.to = $2; ); if (matches_regular_expression(v.to, '^([^ ]*)/([0-9]+)')) then ( set_collected_field('', 'destination_ip', $1); set_collected_field('', 'destination_port', $2); ); else if (matches_regular_expression(v.to, '^([0-9.]+) \\\\(([^)]+)\\\\)(.*)$')) then ( set_collected_field('', 'destination_ip', $1); set_collected_field('', 'destination_hostname', $2); v.remainder = $3; if (matches_regular_expression(v.remainder, '^ /([0-9]+)')) then set_collected_field('', 'destination_port', $1); ); else if (matches_regular_expression(v.to, '^([0-9.]+)$')) then ( set_collected_field('', 'destination_ip', $1); ); ); # Accept this log entry accept_collected_entry('', false); # 2012-01-10 - GMF - This way of handling hit-cnt (using insertions) is problemat for very large hit-cnt values (ThreadID:1257752). Use events=hit-cnt approach instead # Handle repeat lines (specified with hit-cnt) # hit_cnt_index = index(v.message, 'hit-cnt'); # if (hit_cnt_index != -1) then ( # if (matches_regular_expression(current_log_line(), '^(.*) hit-cnt ([0-9]+)(.*)$')) then ( # hit_cnt = $2; # insert_line = $1 . $3; # for (hit_cnt_i = 1; hit_cnt_i < hit_cnt; hit_cnt_i++) # set_subnode_value('volatile.log_line_insertions', hit_cnt_i, insert_line); # ); # ); ); # if message code extracted ` # Database fields database.fields = { operation = "" message = "" message_code = "" message_facility = "" message_severity = "" message_mnemonic = "" protocol = "" source_ip = "" source_mac_address = "" location = "" destination_ip = "" source_hostname = "" destination_hostname = "" source_port = "" destination_port = "" source_side = "" destination_side = "" destination_service = "" interface = "" direction = "" user_name = "" group = "" access_group = "" access_list = "" faddr_host = "" faddr_port = "" faddr_service = "" gaddr_host = "" gaddr_port = "" gaddr_service = "" laddr_host = "" laddr_port = "" laddr_service = "" url = "" flags = "" #user = "" command = "" type = "" list = "" reason = "" icmp_type = "" icmp_code = "" state = "" vty_line = "" privilege_level = "" aaa_status = "" aaa_server = "" group_policy = "" private_ip = "" vlan_id = "" # CRYPTO fields client_type = "" client_public_addr = "" client_application_version = "" server_public_addr = "" assigned_public_addr = "" session_type = "" } # database.fields # Log Filters log.filters = { set_page_for_worm = { label = "$lang_admin.log_filters.set_page_for_worm_label" comment = "$lang_admin.log_filters.set_page_for_worm_comment" value = "if (starts_with(worm, '(')) then '' else url = '[worm]';" } # set_page_for_worm detect_page_views = { label = '$lang_admin.log_filters.detect_page_views_label' comment = '$lang_admin.log_filters.detect_page_views_comment' value = "if ((url eq '(empty)') or (file_type eq 'JPEG') or (file_type eq 'JPG') or (file_type eq 'GIF') or (file_type eq 'ICO') or (file_type eq 'PNG') or (file_type eq 'CSS') or (file_type eq 'SWF') or (file_type eq 'JS')) then page_views = 0; else page_views = 1;" } # detect_page_views # strip_non_page_views = { # label = '$lang_admin.log_filters.strip_non_page_views_label' # comment = '$lang_admin.log_filters.strip_non_page_views_comment' # value = "if (page_views == 0) then url = substr(url, 0, last_index(url, '/') + 1) . '(nonpage)';" # } # strip_non_page_views simplify_url = { label = "$lang_admin.log_filters.simplify_url_label" comment = "$lang_admin.log_filters.simplify_url_comment" value = "if (matches_regular_expression(url, '^(([^:]+://|/)?[^/]+/)')) then url = $1 . '(omitted)'" disabled = false } # simplify_url strip_message = { label = '$lang_admin.log_filters.strip_message_label' comment = '$lang_admin.log_filters.strip_message_comment' value = "message = '[message removed]'" } # strip_message mark_entry = { label = '$lang_admin.log_filters.mark_entry_label' comment = '$lang_admin.log_filters.mark_entry_comment' value = ` if (matches_regular_expression(v.message, ' hit-cnt ([0-9]+) ')) then events = $1; else events = 1; ` } # mark_entry # Setting the service to "(unknown)" was removed at the request of an IOS user # who feels that the port and protocol are valuable information in this context. # It is left commented out to make it easy to put back if anyone wants to. look_up_service = { label = '$lang_admin.log_filters.look_up_service' comment = '$lang_admin.log_filters.look_up_comment' value = ` if ((destination_port eq '(empty)') and (protocol eq '(empty)')) then ( destination_service = '(empty)'; ); else ( destination_service = destination_port . "_" . lowercase(protocol); if (subnode_exists('rewrite_rules.services', destination_service)) then destination_service = node_value(subnode_by_name("rewrite_rules.services", destination_service)); #else # destination_service = '(unknown)'; ); ` } # look_up_service look_up_faddr_service = { label = 'Look up faddr service' comment = 'Compute faddr service from faddr port and protocol' value = ` faddr_service = faddr_port . "_" . (if (starts_with(protocol, '.')) then 'tcp' else lowercase(protocol)); if (subnode_exists('rewrite_rules.services', faddr_service)) then faddr_service = node_value(subnode_by_name("rewrite_rules.services", faddr_service)); else faddr_service = '(unknown)'; ` } # look_up_faddr_service look_up_gaddr_service = { label = 'Look up gaddr service' comment = 'Compute gaddr service from gaddr port and protocol' value = ` gaddr_service = gaddr_port . "_" . (if (starts_with(protocol, '.')) then 'tcp' else lowercase(protocol)); if (subnode_exists('rewrite_rules.services', gaddr_service)) then gaddr_service = node_value(subnode_by_name("rewrite_rules.services", gaddr_service)); else gaddr_service = '(unknown)'; ` } # look_up_gaddr_service look_up_laddr_service = { label = 'Look up laddr service' comment = 'Compute laddr service from laddr port and protocol' value = ` laddr_service = laddr_port . "_" . (if (starts_with(protocol, '.')) then 'tcp' else lowercase(protocol)); if (subnode_exists('rewrite_rules.services', laddr_service)) then laddr_service = node_value(subnode_by_name("rewrite_rules.services", laddr_service)); else laddr_service = '(unknown)'; ` } # look_up_laddr_service } # log.filters log.field_options = { sessions_page_field = "destination_ip" sessions_visitor_id_field = "source_ip" sessions_event_field = "page_views" } # log.field_options database.numerical_fields = { events = { default = true requires_log_field = false entries_field = true } # events connections_built = { default = true requires_log_field = false } # connections_built connections_torn_down = { default = true requires_log_field = false } # connections_torn_down page_views = { requires_log_field = false } # page_views unique_source_ips = { log_field = "source_ip" type = "unique" display_format_type = "integer" } # unique_source_ips bytes = { type = "int" integer_bits = 64 display_format_type = "bandwidth" } # bytes bytes_xmt = { type = "int" integer_bits = 64 display_format_type = "bandwidth" } # bytes_xmt bytes_rcv = { type = "int" integer_bits = 64 display_format_type = "bandwidth" } # bytes_rcv # destination_bytes = { # type = "int" # integer_bits = 64 # display_format_type = "bandwidth" # } # destination_bytes duration = { type = int display_format_type = duration_compact } # duration packets = "" } # database.numerical_fields create_profile_wizard_options = { host_tracking = true # How the reports should be grouped in the report menu report_groups = { date_time_group = "" source_group = { source_ip = true source_hostname = true source_port = true source_side = true source_mac_address = true #user = true interface = true laddr_host = true laddr_port = true laddr_service = true location = true user_name = true group = true } destination_group = { destination_ip = true destination_hostname = true destination_port = true destination_side = true top_level_domain = true url = true faddr_host = true faddr_port = true faddr_service = true gaddr_host = true gaddr_port = true gaddr_service = true destination_service = true destination_ip_by_source_ip = true destination_service_by_source_ip = true faddr_host_by_laddr_host = true faddr_service_by_laddr_host = true gaddr_host_by_laddr_host = true gaddr_service_by_laddr_host = true } crypto_group = { client_type = true client_public_addr = true server_public_addr = true assigned_public_addr = true } # crypto_group other_group = { logging_device = true syslog_priority = true list = true operation = true direction = true access_group = true access_list = "" message = true message_code = true message_facility = true message_severity = true message_mnemonic = true protocol = true flags = true command = true type = true reason = true icmp_type = true icmp_code = true state = true vty_line = true privilege_level = true aaa_status = true aaa_server = true group_policy = true private_ip = true vlan_id = true session_type = true } } # report_groups snapons = { # Attach a top_level_domain snapon top_level_domain = { snapon = "top_level_domain" name = "top_level_domain" label = "$lang_admin.snapons.top_level_domain.label" parameters = { url_field.parameter_value = "url" field_name = { parameter_value = "$lang_admin.field_labels.top_level_domain" final_node_name = "top_level_domain" } report_group_name.parameter_value = "destination_group" } # parameters } # top_level_domain # Add the standard reports add_standard_reports = { name = "add_standard_reports" label = "add_standard_reports" snapon = "add_standard_reports" } # add_standard_reports } # snapons } # create_profile_wizard_options } # cisco_pix