description: "Pipeline for Cisco ASA"
processors:

 - grok: 
     field: message
     patterns: 
      - "(:?%{ASA_DATE:_temp_.raw_date})?%{ASA_PREFIX}-(:?%{ASA_SUFFIX:cisco.asa.suffix}-)?%{POSINT:event.severity:int}-%{POSINT:cisco.asa.message_id}:?\\s*%{GREEDYDATA:log.original}"
     pattern_definitions: 
      ASA_PREFIX: "%{DATA}%ASA"
      ASA_SUFFIX: "[^0-9-]+"
      ASA_DATE: "(:?%{DAY} )?%{MONTH}  *%{MONTHDAY}(:? %{YEAR})? %{TIME}(:? %{TZ})?"

#
# Drop messages above configured log_level
#
 - drop:
    if: "ctx.event.severity > {< .log_level >}"

#
# Parse the date included in ASA logs
#
 - date:
     field: "_temp_.raw_date"
     ignore_failure: true
     formats: 
      - "MMM  d HH:mm:ss"
      - "MMM dd HH:mm:ss"
      - "EEE MMM  d HH:mm:ss"
      - "EEE MMM dd HH:mm:ss"
      - "MMM  d HH:mm:ss z"
      - "MMM dd HH:mm:ss z"
      - "EEE MMM  d HH:mm:ss z"
      - "EEE MMM dd HH:mm:ss z"
      - "MMM  d yyyy HH:mm:ss"
      - "MMM dd yyyy HH:mm:ss"
      - "EEE MMM  d yyyy HH:mm:ss"
      - "EEE MMM dd yyyy HH:mm:ss"
      - "MMM  d yyyy HH:mm:ss z"
      - "MMM dd yyyy HH:mm:ss z"
      - "EEE MMM  d yyyy HH:mm:ss z"
      - "EEE MMM dd yyyy HH:mm:ss z"
 - date:
     if: "ctx.event.timezone != null"
     field: "@timestamp"
     formats: ["ISO8601"]
     timezone: "{{ event.timezone }}"
     on_failure: [{"append": {"field": "error.message", "value": "{{ _ingest.on_failure_message }}"}}]

#
# Set log.level
#
 - set: 
     field: "log.level"
     if: "ctx.event.severity == 1"
     value: alert
 - set: 
     field: "log.level"
     if: "ctx.event.severity == 2"
     value: critical
 - set: 
     field: "log.level"
     if: "ctx.event.severity == 3"
     value: error
 - set: 
     field: "log.level"
     if: "ctx.event.severity == 4"
     value: warning
 - set: 
     field: "log.level"
     if: "ctx.event.severity == 5"
     value: notification
 - set: 
     field: "log.level"
     if: "ctx.event.severity == 6"
     value: informational
 - set: 
     field: "log.level"
     if: "ctx.event.severity == 7"
     value: debug

#
# Firewall messages
#
 - set: 
     field: "event.action"
     value: "firewall-rule"
 - dissect: 
     if: "ctx.cisco.asa.message_id == '106001'"
     field: "log.original"
     pattern: "%{network.direction} %{network.transport} connection %{event.outcome} from %{source.ip}/%{source.port} to %{destination.ip}/%{destination.port} flags %{} on interface %{cisco.asa.source_interface}"
 - dissect: 
     if: "ctx.cisco.asa.message_id == '106002'"
     field: "log.original"
     pattern: "%{network.transport} Connection %{event.outcome} by %{network.direction} list %{cisco.asa.list_id} src %{source.ip} dest %{destination.ip}"
 - dissect: 
     if: "ctx.cisco.asa.message_id == '106006'"
     field: "log.original"
     pattern: "%{event.outcome} %{network.direction} %{network.transport} from %{source.ip}/%{source.port} to %{destination.ip}/%{destination.port} on interface %{cisco.asa.source_interface}"
 - dissect: 
     if: "ctx.cisco.asa.message_id == '106007'"
     field: "log.original"
     pattern: "%{event.outcome} %{network.direction} %{network.transport} from %{source.ip}/%{source.port} to %{destination.ip}/%{destination.port} due to %{network.protocol} %{}"
 - dissect: 
     if: "ctx.cisco.asa.message_id == '106010'"
     field: "log.original"
     pattern: "%{event.outcome} %{network.direction} %{network.transport} src %{cisco.asa.source_interface}:%{source.ip}/%{source.port} %{} dst %{cisco.asa.destination_interface}:%{destination.ip}/%{destination.port} %{}"
 - dissect: 
     if: "ctx.cisco.asa.message_id == '106013'"
     field: "log.original"
     pattern: "Dropping echo request from %{source.ip} to PAT address %{destination.ip}"
 - set: 
     if: "ctx.cisco.asa.message_id == '106013'"
     field: "network.transport"
     value: icmp
 - set: 
     if: "ctx.cisco.asa.message_id == '106013'"
     field: "network.direction"
     value: inbound
 - dissect: 
     if: "ctx.cisco.asa.message_id == '106014'"
     field: "log.original"
     pattern: "%{event.outcome} %{network.direction} %{network.transport} src %{cisco.asa.source_interface}:%{source.ip} %{}dst %{cisco.asa.destination_interface}:%{destination.ip} %{}"
 - dissect: 
     if: "ctx.cisco.asa.message_id == '106015'"
     field: "log.original"
     pattern: "%{event.outcome} %{network.transport} (no connection) from %{source.ip}/%{source.port} to %{destination.ip}/%{destination.port} flags %{} on interface %{cisco.asa.source_interface}"
 - dissect:
     if: "ctx.cisco.asa.message_id == '106016'"
     field: "log.original"
     pattern: "%{event.outcome} IP spoof from (%{source.ip}) to %{destination.ip} on interface %{cisco.asa.source_interface}"
 - dissect: 
     if: "ctx.cisco.asa.message_id == '106017'"
     field: "log.original"
     pattern: "%{event.outcome} IP due to Land Attack from %{source.ip} to %{destination.ip}"
 - dissect: 
     if: "ctx.cisco.asa.message_id == '106018'"
     field: "log.original"
     pattern: "%{network.transport} packet type %{cisco.asa.icmp_type} %{event.outcome} by %{network.direction} list %{cisco.asa.list_id} src %{source.ip} dest %{destination.ip}"
 - dissect: 
     if: "ctx.cisco.asa.message_id == '106020'"
     field: "log.original"
     pattern: "%{event.outcome} IP teardrop fragment (size = %{}, offset = %{}) from %{source.ip} to %{destination.ip}"
 - dissect: 
     if: "ctx.cisco.asa.message_id == '106021'"
     field: "log.original"
     pattern: "%{event.outcome} %{network.transport} reverse path check from %{source.ip} to %{destination.ip} on interface %{cisco.asa.source_interface}"
 - dissect: 
     if: "ctx.cisco.asa.message_id == '106022'"
     field: "log.original"
     pattern: "%{event.outcome} %{network.transport} connection spoof from %{source.ip} to %{destination.ip} on interface %{cisco.asa.source_interface}"
 - dissect: 
     if: "ctx.cisco.asa.message_id == '106023'"
     field: "log.original"
     pattern: "%{event.outcome} %{network.transport} src %{cisco.asa.source_interface}:%{source.ip}/%{source.port} dst %{cisco.asa.destination_interface}:%{destination.ip}/%{destination.port} %{} access%{}group \"%{cisco.asa.list_id}\"%{}"
 - dissect: 
     if: "ctx.cisco.asa.message_id == '106027'"
     field: "log.original"
     pattern: "%{} %{event.outcome} src %{source.ip} dst %{destination.ip} by access-group \"%{cisco.asa.list_id}\""
 - dissect: 
     if: "ctx.cisco.asa.message_id == '106100'"
     field: "log.original"
     pattern: "access-list %{cisco.asa.list_id} %{event.outcome} %{network.transport} %{cisco.asa.source_interface}/%{source.ip}(%{source.port}) -> %{cisco.asa.destination_interface}/%{destination.ip}(%{destination.port}) %{}"
 - dissect: 
     if: "ctx.cisco.asa.message_id == '106102'"
     field: "log.original"
     pattern: "access-list %{cisco.asa.list_id} %{event.outcome} %{network.transport} for user %{cisco.asa.username} %{cisco.asa.source_interface}/%{source.ip} %{source.port} %{cisco.asa.destination_interface}/%{destination.ip} %{destination.port} %{}"
 - dissect: 
     if: "ctx.cisco.asa.message_id == '106103'"
     field: "log.original"
     pattern: "access-list %{cisco.asa.list_id} %{event.outcome} %{network.transport} for user %{cisco.asa.username} %{cisco.asa.source_interface}/%{source.ip} %{source.port} %{cisco.asa.destination_interface}/%{destination.ip} %{destination.port} %{}"
 - dissect: 
     if: "ctx.cisco.asa.message_id == '304001'"
     field: "log.original"
     pattern: "%{source.ip} %{}ccessed URL %{destination.ip}:%{url.original}"
 - set: 
     if: "ctx.cisco.asa.message_id == '304001'"
     field: "event.outcome"
     value: allow
 - dissect: 
     if: "ctx.cisco.asa.message_id == '304002'"
     field: "log.original"
     pattern: "Access %{event.outcome} URL %{url.original} SRC %{source.ip} %{}EST %{destination.ip} on interface %{cisco.asa.source_interface}"
 - dissect: 
     if: "ctx.cisco.asa.message_id == '313001'"
     field: "log.original"
     pattern: "%{event.outcome} %{network.transport} type=%{cisco.asa.icmp_type}, code=%{cisco.asa.icmp_code} from %{source.ip} on interface %{cisco.asa.source_interface}"
 - dissect: 
     if: "ctx.cisco.asa.message_id == '313004'"
     field: "log.original"
     pattern: "%{event.outcome} %{network.transport} type=%{cisco.asa.icmp_type}, from%{}addr %{source.ip} on interface %{cisco.asa.source_interface} to %{destination.ip}: no matching session"
 - dissect: 
     if: "ctx.cisco.asa.message_id == '313005'"
     field: "log.original"
     pattern: "No matching connection for %{network.transport} error message: %{} on %{cisco.asa.source_interface} interface.%{}riginal IP payload: %{}"
 - dissect: 
     if: "ctx.cisco.asa.message_id == '313008'"
     field: "log.original"
     pattern: "%{event.outcome} %{network.transport} type=%{cisco.asa.icmp_type} , code=%{cisco.asa.icmp_code} from %{source.ip} on interface %{cisco.asa.source_interface}"
 - dissect: 
     if: "ctx.cisco.asa.message_id == '313009'"
     field: "log.original"
     pattern: "%{event.outcome} invalid %{network.transport} code %{cisco.asa.icmp_code} , for %{cisco.asa.source_interface}:%{source.ip}/%{source.port} (%{cisco.asa.mapped_source_ip}/%{cisco.asa.mapped_source_port}) to %{cisco.asa.destination_interface}:%{destination.ip}/%{destination.port} (%{cisco.asa.mapped_destination_ip}/%{cisco.asa.mapped_destination_port})%{}"
 - dissect: 
     if: "ctx.cisco.asa.message_id == '322001'"
     field: "log.original"
     pattern: "%{event.outcome} MAC address %{source.mac}, possible spoof attempt on interface %{cisco.asa.source_interface}"
 - dissect: 
     if: "ctx.cisco.asa.message_id == '338001'"
     field: "log.original"
     pattern: "Dynamic filter %{event.outcome} black%{}d %{network.transport} traffic from %{cisco.asa.source_interface}:%{source.ip}/%{source.port} (%{cisco.asa.mapped_source_ip}/%{cisco.asa.mapped_source_port}) to %{cisco.asa.destination_interface}:%{destination.ip}/%{destination.port} (%{cisco.asa.mapped_destination_ip}/%{cisco.asa.mapped_destination_port})%{}source %{} resolved from %{cisco.asa.list_id} list: %{source.domain}, threat-level: %{cisco.asa.threat_level}, category: %{cisco.asa.threat_category}"
 - set: 
     if: "ctx.cisco.asa.message_id == '338001'"
     field: "server.domain"
     value: "{{source.domain}}"
 - dissect: 
     if: "ctx.cisco.asa.message_id == '338002'"
     field: "log.original"
     pattern: "Dynamic %{}ilter %{event.outcome} black%{}d %{network.transport} traffic from %{cisco.asa.source_interface}:%{source.ip}/%{source.port} (%{cisco.asa.mapped_source_ip}/%{cisco.asa.mapped_source_port}) to %{cisco.asa.destination_interface}:%{destination.ip}/%{destination.port} (%{cisco.asa.mapped_destination_ip}/%{cisco.asa.mapped_destination_port})%{}destination %{} resolved from %{cisco.asa.list_id} list: %{destination.domain}"
 - set: 
     if: "ctx.cisco.asa.message_id == '338002'"
     field: "server.domain"
     value: "{{destination.domain}}"
 - dissect: 
     if: "ctx.cisco.asa.message_id == '338003'"
     field: "log.original"
     pattern: "Dynamic %{}ilter %{event.outcome} black%{}d %{network.transport} traffic from %{cisco.asa.source_interface}:%{source.ip}/%{source.port} (%{cisco.asa.mapped_source_ip}/%{cisco.asa.mapped_source_port}) to %{cisco.asa.destination_interface}:%{destination.ip}/%{destination.port} (%{cisco.asa.mapped_destination_ip}/%{cisco.asa.mapped_destination_port})%{}source %{} resolved from %{cisco.asa.list_id} list: %{}, threat-level: %{cisco.asa.threat_level}, category: %{cisco.asa.threat_category}"
 - dissect: 
     if: "ctx.cisco.asa.message_id == '338004'"
     field: "log.original"
     pattern: "Dynamic %{}ilter %{event.outcome} black%{}d %{network.transport} traffic from %{cisco.asa.source_interface}:%{source.ip}/%{source.port} (%{cisco.asa.mapped_source_ip}/%{cisco.asa.mapped_source_port}) to %{cisco.asa.destination_interface}:%{destination.ip}/%{destination.port} (%{cisco.asa.mapped_destination_ip}/%{cisco.asa.mapped_destination_port})%{}destination %{} resolved from %{cisco.asa.list_id} list: %{}, threat-level: %{cisco.asa.threat_level}, category: %{cisco.asa.threat_category}"
 - dissect: 
     if: "ctx.cisco.asa.message_id == '338005'"
     field: "log.original"
     pattern: "Dynamic %{}ilter %{event.outcome} black%{}d %{network.transport} traffic from %{cisco.asa.source_interface}:%{source.ip}/%{source.port} (%{cisco.asa.mapped_source_ip}/%{cisco.asa.mapped_source_port}) to %{cisco.asa.destination_interface}:%{destination.ip}/%{destination.port} (%{cisco.asa.mapped_destination_ip}/%{cisco.asa.mapped_destination_port})%{}source %{} resolved from %{cisco.asa.list_id} list: %{source.domain}, threat-level: %{cisco.asa.threat_level}, category: %{cisco.asa.threat_category}"
 - set: 
     if: "ctx.cisco.asa.message_id == '338005'"
     field: "server.domain"
     value: "{{source.domain}}"
 - dissect: 
     if: "ctx.cisco.asa.message_id == '338006'"
     field: "log.original"
     pattern: "Dynamic %{}ilter %{event.outcome} black%{}d %{network.transport} traffic from %{cisco.asa.source_interface}:%{source.ip}/%{source.port} (%{cisco.asa.mapped_source_ip}/%{cisco.asa.mapped_source_port}) to %{cisco.asa.destination_interface}:%{destination.ip}/%{destination.port} (%{cisco.asa.mapped_destination_ip}/%{cisco.asa.mapped_destination_port})%{}destination %{} resolved from %{cisco.asa.list_id} list: %{destination.domain}, threat-level: %{cisco.asa.threat_level}, category: %{cisco.asa.threat_category}"
 - set: 
     if: "ctx.cisco.asa.message_id == '338006'"
     field: "server.domain"
     value: "{{destination.domain}}"
 - dissect: 
     if: "ctx.cisco.asa.message_id == '338007'"
     field: "log.original"
     pattern: "Dynamic %{}ilter %{event.outcome} black%{}d %{network.transport} traffic from %{cisco.asa.source_interface}:%{source.ip}/%{source.port} (%{cisco.asa.mapped_source_ip}/%{cisco.asa.mapped_source_port}) to %{cisco.asa.destination_interface}:%{destination.ip}/%{destination.port} (%{cisco.asa.mapped_destination_ip}/%{cisco.asa.mapped_destination_port})%{}source %{} resolved from %{cisco.asa.list_id} list: %{}, threat-level: %{cisco.asa.threat_level}, category: %{cisco.asa.threat_category}"
 - dissect: 
     if: "ctx.cisco.asa.message_id == '338008'"
     field: "log.original"
     pattern: "Dynamic %{}ilter %{event.outcome} black%{}d %{network.transport} traffic from %{cisco.asa.source_interface}:%{source.ip}/%{source.port} (%{cisco.asa.mapped_source_ip}/%{cisco.asa.mapped_source_port}) to %{cisco.asa.destination_interface}:%{destination.ip}/%{destination.port} (%{cisco.asa.mapped_destination_ip}/%{cisco.asa.mapped_destination_port})%{}destination %{} resolved from %{cisco.asa.list_id} list: %{}, threat-level: %{cisco.asa.threat_level}, category: %{cisco.asa.threat_category}"
 - dissect: 
     if: "ctx.cisco.asa.message_id == '338101'"
     field: "log.original"
     pattern: "Dynamic %{}ilter %{event.outcome} white%{}d %{network.transport} traffic from %{cisco.asa.source_interface}:%{source.ip}/%{source.port} (%{cisco.asa.mapped_source_ip}/%{cisco.asa.mapped_source_port}) to %{cisco.asa.destination_interface}:%{destination.ip}/%{destination.port} (%{cisco.asa.mapped_destination_ip}/%{cisco.asa.mapped_destination_port})%{}source %{} resolved from %{cisco.asa.list_id} list: %{source.domain}"
 - set: 
     if: "ctx.cisco.asa.message_id == '338101'"
     field: "server.domain"
     value: "{{source.domain}}"
 - dissect: 
     if: "ctx.cisco.asa.message_id == '338102'"
     field: "log.original"
     pattern: "Dynamic %{}ilter %{event.outcome} white%{}d %{network.transport} traffic from %{cisco.asa.source_interface}:%{source.ip}/%{source.port} (%{cisco.asa.mapped_source_ip}/%{cisco.asa.mapped_source_port}) to %{cisco.asa.destination_interface}:%{destination.ip}/%{destination.port} (%{cisco.asa.mapped_destination_ip}/%{cisco.asa.mapped_destination_port})%{}destination %{} resolved from %{cisco.asa.list_id} list: %{destination.domain}"
 - set: 
     if: "ctx.cisco.asa.message_id == '338102'"
     field: "server.domain"
     value: "{{destination.domain}}"
 - dissect: 
     if: "ctx.cisco.asa.message_id == '338103'"
     field: "log.original"
     pattern: "Dynamic %{}ilter %{event.outcome} white%{}d %{network.transport} traffic from %{cisco.asa.source_interface}:%{source.ip}/%{source.port} (%{cisco.asa.mapped_source_ip}/%{cisco.asa.mapped_source_port}) to %{cisco.asa.destination_interface}:%{destination.ip}/%{destination.port} (%{cisco.asa.mapped_destination_ip}/%{cisco.asa.mapped_destination_port})%{}source %{} resolved from %{cisco.asa.list_id} list: %{}"
 - dissect: 
     if: "ctx.cisco.asa.message_id == '338104'"
     field: "log.original"
     pattern: "Dynamic %{}ilter %{event.outcome} white%{}d %{network.transport} traffic from %{cisco.asa.source_interface}:%{source.ip}/%{source.port} (%{cisco.asa.mapped_source_ip}/%{cisco.asa.mapped_source_port}) to %{cisco.asa.destination_interface}:%{destination.ip}/%{destination.port} (%{cisco.asa.mapped_destination_ip}/%{cisco.asa.mapped_destination_port})%{}destination %{} resolved from %{cisco.asa.list_id} list: %{}"
 - dissect: 
     if: "ctx.cisco.asa.message_id == '338201'"
     field: "log.original"
     pattern: "Dynamic %{}ilter %{event.outcome} grey%{}d %{network.transport} traffic from %{cisco.asa.source_interface}:%{source.ip}/%{source.port} (%{cisco.asa.mapped_source_ip}/%{cisco.asa.mapped_source_port}) to %{cisco.asa.destination_interface}:%{destination.ip}/%{destination.port} (%{cisco.asa.mapped_destination_ip}/%{cisco.asa.mapped_destination_port})%{}source %{} resolved from %{cisco.asa.list_id} list: %{source.domain}, threat-level: %{cisco.asa.threat_level}, category: %{cisco.asa.threat_category}"
 - set: 
     if: "ctx.cisco.asa.message_id == '338201'"
     field: "server.domain"
     value: "{{source.domain}}"
 - dissect: 
     if: "ctx.cisco.asa.message_id == '338202'"
     field: "log.original"
     pattern: "Dynamic %{}ilter %{event.outcome} grey%{}d %{network.transport} traffic from %{cisco.asa.source_interface}:%{source.ip}/%{source.port} (%{cisco.asa.mapped_source_ip}/%{cisco.asa.mapped_source_port}) to %{cisco.asa.destination_interface}:%{destination.ip}/%{destination.port} (%{cisco.asa.mapped_destination_ip}/%{cisco.asa.mapped_destination_port})%{}destination %{} resolved from %{cisco.asa.list_id} list: %{destination.domain}, threat-level: %{cisco.asa.threat_level}, category: %{cisco.asa.threat_category}"
 - set: 
     if: "ctx.cisco.asa.message_id == '338202'"
     field: "server.domain"
     value: "{{destination.domain}}"
 - dissect: 
     if: "ctx.cisco.asa.message_id == '338203'"
     field: "log.original"
     pattern: "Dynamic %{}ilter %{event.outcome} grey%{}d %{network.transport} traffic from %{cisco.asa.source_interface}:%{source.ip}/%{source.port} (%{cisco.asa.mapped_source_ip}/%{cisco.asa.mapped_source_port}) to %{cisco.asa.destination_interface}:%{destination.ip}/%{destination.port} (%{cisco.asa.mapped_destination_ip}/%{cisco.asa.mapped_destination_port})%{}source %{} resolved from %{cisco.asa.list_id} list: %{source.domain}, threat-level: %{cisco.asa.threat_level}, category: %{cisco.asa.threat_category}"
 - set: 
     if: "ctx.cisco.asa.message_id == '338203'"
     field: "server.domain"
     value: "{{source.domain}}"
 - dissect: 
     if: "ctx.cisco.asa.message_id == '338204'"
     field: "log.original"
     pattern: "Dynamic %{}ilter %{event.outcome} grey%{}d %{network.transport} traffic from %{cisco.asa.source_interface}:%{source.ip}/%{source.port} (%{cisco.asa.mapped_source_ip}/%{cisco.asa.mapped_source_port}) to %{cisco.asa.destination_interface}:%{destination.ip}/%{destination.port} (%{cisco.asa.mapped_destination_ip}/%{cisco.asa.mapped_destination_port})%{}destination %{} resolved from %{cisco.asa.list_id} list: %{destination.domain}, threat-level: %{cisco.asa.threat_level}, category: %{cisco.asa.threat_category}"
 - set: 
     if: "ctx.cisco.asa.message_id == '338204'"
     field: "server.domain"
     value: "{{destination.domain}}"
 - dissect: 
     if: "ctx.cisco.asa.message_id == '338301'"
     field: "log.original"
     pattern: "Intercepted DNS reply for domain %{source.domain} from %{cisco.asa.source_interface}:%{source.ip}/%{source.port} to %{cisco.asa.destination_interface}:%{destination.ip}/%{destination.port}, matched %{cisco.asa.list_id}"
 - set: 
     if: "ctx.cisco.asa.message_id == '338301'"
     field: "client.ip"
     value: "{{destination.ip}}"
 - set: 
     if: "ctx.cisco.asa.message_id == '338301'"
     field: "client.port"
     value: "{{destination.port}}"
 - set: 
     if: "ctx.cisco.asa.message_id == '338301'"
     field: "server.ip"
     value: "{{source.ip}}"
 - set: 
     if: "ctx.cisco.asa.message_id == '338301'"
     field: "server.port"
     value: "{{source.port}}"

#
# Handle 302xxx messages (Flow expiration a.k.a "Teardown")
#
 - set:
     if: "[\"302014\", \"302016\", \"302018\", \"302021\", \"302036\", \"302304\", \"302306\"].contains(ctx.cisco.asa.message_id)"
     field: "event.action"
     value: "flow-expiration"
 - grok:
     field: "log.original"
     if: "[\"302014\", \"302016\", \"302018\", \"302021\", \"302036\", \"302304\", \"302306\"].contains(ctx.cisco.asa.message_id)"
     patterns:
      - "Teardown %{NOTSPACE:network.transport} (:?state-bypass )?connection %{NOTSPACE:cisco.asa.connection_id} (:?for|from) %{NOTCOLON:cisco.asa.source_interface}:%{IP:source.ip}/%{NUMBER:source.port:int} (:?%{NOTSPACE:cisco.asa.source_username} )?to %{NOTCOLON:cisco.asa.destination_interface}:%{IP:destination.ip}/%{NUMBER:destination.port:int} (:?%{NOTSPACE:cisco.asa.destination_username} )?(:?duration %{TIME:_temp_.duration_hms} bytes %{NUMBER:network.bytes:int})%{GREEDYDATA}"
      - "Teardown %{NOTSPACE:network.transport} connection for faddr (:?%{NOTCOLON:cisco.asa.source_interface}:)?%{IP:source.ip}/%{NUMBER:source.port:int} (:?%{NOTSPACE:cisco.asa.source_username} )?gaddr (:?%{NOTCOLON}:)?%{IP}/%{NUMBER} laddr (:?%{NOTCOLON:cisco.asa.destination_interface}:)?%{IP:destination.ip}/%{NUMBER:destination.port:int}(:? %{NOTSPACE:cisco.asa.destination_username})?%{GREEDYDATA}"
     pattern_definitions:
      NOTCOLON: "[^:]*"

#
# Process the flow duration "hh:mm:ss" present in some messages
# This will fill event.start, event.end and event.duration
#
 - script:
     lang: painless
     if: "ctx?._temp_?.duration_hms != null"
     source: >
       long parse_hms(String s) {
           long cur = 0, total = 0;
           for (char c: s.toCharArray()) {
               if (c >= (char)'0' && c <= (char)'9') {
                   cur = (cur*10) + (long)c - (char)'0';
               } else if (c == (char)':') {
                   total = (total + cur) * 60;
                   cur = 0;
               } else {
                   return 0;
               }
           }
           return total + cur;
       }
       if (ctx?.event == null) {
           ctx['event'] = new HashMap();
       }
       String end = ctx['@timestamp'];
       ctx.event['end'] = end;
       long nanos = parse_hms(ctx._temp_.duration_hms) * 1000000000L;
       ctx.event['duration'] = nanos;
       ctx.event['start'] = ZonedDateTime.ofInstant(
           Instant.parse(end).minusNanos(nanos),
           ZoneOffset.UTC);

#
# Normalize protocol names
#
 - lowercase: 
     field: "network.transport"
     ignore_missing: true
 - lowercase: 
     field: "network.protocol"
     ignore_missing: true

#
# Normalize event.outcome
#
 - lowercase: 
     field: "event.outcome"
     ignore_missing: true
 - set: 
     field: "event.outcome"
     if: "ctx.event?.outcome == \"est-allowed\""
     value: allow
 - set: 
     field: "event.outcome"
     if: "ctx.event?.outcome == \"permitted\""
     value: allow
 - set: 
     field: "event.outcome"
     if: "ctx.event?.outcome == \"denied\""
     value: deny
 - set:
     field: "event.outcome"
     if: "ctx.event?.outcome == \"dropped\""
     value: deny

 - set: 
     field: "network.transport"
     if: "ctx.network?.transport == \"icmpv6\""
     value: "ipv6-icmp"

#
# Convert integer fields, as output of dissect processor is always a string
#
 - convert: 
     field: "source.port"
     type: integer
     ignore_failure: true
 - convert:
     field: "destination.port"
     type: integer
     ignore_failure: true
 - convert:
     field: "cisco.asa.mapped_source_port"
     type: integer
     ignore_failure: true
 - convert:
     field: "cisco.asa.mapped_destination_port"
     type: integer
     ignore_failure: true
 - convert:
     field: "cisco.asa.icmp_code"
     type: integer
     ignore_failure: true
 - convert:
     field: "cisco.asa.icmp_type"
     type: integer
     ignore_failure: true

#
# Geolocation for source and destination addresses
#
 - geoip:
     field: "source.ip"
     target_field: "source.geo"
     ignore_missing: true
 - geoip: 
     field: "destination.ip"
     target_field: "destination.geo"
     ignore_missing: true

#
# Remove temporary fields
#
 - remove: 
     field: 
      - message
      - _temp_
     ignore_missing: true

on_failure: 
 - set: 
     field: "error.message"
     value: "{{ _ingest.on_failure_message }}"
 - remove: 
     field:
     - _temp_
     ignore_missing: true
