{
    "description" : "Pipeline for IPTables",
        "processors" : [
            {
                "grok": {
                    "field": "message",
                    "patterns": [
                        "%{SYSLOGTIMESTAMP:iptables.raw_date}%{GREEDYDATA}\\[%{UBIQUITI_LABEL}\\]%{IPTABLES}%{SPACE}",
                        "%{SYSLOGTIMESTAMP:iptables.raw_date}%{GREEDYDATA}%{IPTABLES}%{SPACE}",
                        "%{GREEDYDATA}\\[%{UBIQUITI_LABEL}\\]%{IPTABLES}%{SPACE}",
                        "%{GREEDYDATA}%{IPTABLES}%{SPACE}"
                    ],
                    "pattern_definitions": {
                        "UNSIGNED_INT": "[0-9]+",
                        "ETHTYPE": "(?:[A-Fa-f0-9]{2}):(?:[A-Fa-f0-9]{2})",
                        "ETHTYPE_DISCARD": "(?::[A-Fa-f0-9]{2})*",
                        "NETFILTERMAC": "(?:%{MAC:destination.mac}:%{MAC:source.mac}:%{ETHTYPE:iptables.ether_type}?%{ETHTYPE_DISCARD}|%{MAC:destination.mac}%{ETHTYPE_DISCARD}:%{ETHTYPE:iptables.ether_type}?)",
                        "IPTABLES_ETHERNET": "IN=%{DATA:iptables.input_device} OUT=%{DATA:iptables.output_device}?(?: MAC=%{NETFILTERMAC})?",
                        "IPTABLES_PORT_PAIR": "SPT=%{UNSIGNED_INT:source.port:int} DPT=%{UNSIGNED_INT:destination.port:int}",
                        "IPTABLES_TCP_FLAGS": "((?<= )(CWR|ECE|URG|ACK|PSH|RST|SYN|FIN))*",
                        "IPTABLES_TCP_SEQ": "SEQ=%{UNSIGNED_INT:iptables.tcp.seq:int} ACK=%{UNSIGNED_INT:iptables.tcp.ack:int}",
                        "IPTABLES_TCP_DETAILS": "(?:%{IPTABLES_TCP_SEQ} )?WINDOW=%{UNSIGNED_INT:iptables.tcp.window:int} RES=0x%{BASE16NUM:iptables.tcp_reserved_bits} %{IPTABLES_TCP_FLAGS:iptables.tcp.flags}",
                        "IPTABLES_INCOMPLETE_PACKET": "INCOMPLETE \\[%{UNSIGNED_INT:iptables.incomplete_bytes:int} bytes\\]",
                        "IPTABLES_UDP_DETAILS": "LEN=%{UNSIGNED_INT:iptables.udp.length:int}",
                        "IPTABLES_ICMP_EXTRA_ECHO": "ID=%{UNSIGNED_INT:iptables.icmp.id:int} SEQ=%{UNSIGNED_INT:iptables.icmp.seq:int}",
                        "IPTABLES_ICMP_EXTRA_PARAM": "PARAMETER=%{UNSIGNED_INT:iptables.icmp.parameter:int}",
                        "IPTABLES_ICMP_EXTRA_REDIRECT": "GATEWAY=%{IP:iptables.icmp.redirect}",
                        "IPTABLES_ICMP_EXTRA": "( (?:%{IPTABLES_ICMP_EXTRA_ECHO}|%{IPTABLES_ICMP_EXTRA_PARAM}|%{IPTABLES_ICMP_EXTRA_REDIRECT}))*",
                        "IPTABLES_ICMP_DETAILS": "TYPE=%{UNSIGNED_INT:iptables.icmp.type:int} CODE=%{UNSIGNED_INT:iptables.icmp.code:int}(( %{IPTABLES_INCOMPLETE_PACKET})|%{IPTABLES_ICMP_EXTRA})",
                        "IPTABLES_PROTOCOL": "PROTO=(?<network.transport>[a-zA-Z0-9]+)",
                        "IPTABLES_IP_PAYLOAD": "%{IPTABLES_PROTOCOL}( %{IPTABLES_PORT_PAIR})?( (%{IPTABLES_TCP_DETAILS}|%{IPTABLES_UDP_DETAILS}|%{IPTABLES_ICMP_DETAILS}|%{IPTABLES_INCOMPLETE_PACKET}))?",
                        "IPTABLES_IP_FRAGFLAG": "((?<= )(CE|DF|MF))*",
                        "IPTABLES_IP_START": "SRC=%{IPV4:source.ip} DST=%{IPV4:destination.ip} LEN=%{UNSIGNED_INT:iptables.length:int} TOS=0x%{BASE16NUM:iptables.tos} PREC=0x%{BASE16NUM:iptables.precedence_bits} TTL=%{UNSIGNED_INT:iptables.ttl:int} ID=%{UNSIGNED_INT:iptables.id:int}(?: %{IPTABLES_IP_FRAGFLAG:iptables.fragment_flags})?(?: FRAG: %{UNSIGNED_INT:iptables.fragment_offset:int})?",
                        "IPTABLES_IP": "%{IPTABLES_IP_START} %{IPTABLES_IP_PAYLOAD}",
                        "IPTABLES_IPV6_START": "SRC=%{IPV6:source.ip} DST=%{IPV6:destination.ip} LEN=%{UNSIGNED_INT:iptables.length:int} TC=%{UNSIGNED_INT:iptables.tos} HOPLIMIT=%{UNSIGNED_INT:iptables.ttl:int} FLOWLBL=%{UNSIGNED_INT:iptables.flow_label:int}",
                        "IPTABLES_IPV6": "%{IPTABLES_IPV6_START} %{IPTABLES_IP_PAYLOAD}",
                        "IPTABLES": "%{IPTABLES_ETHERNET} (:?%{IPTABLES_IP}|%{IPTABLES_IPV6})",
                        "UBIQUITI_FIELD": "[^-\\]]*",
                        "UBIQUITI_RULESET_NAME": "[^\\]]*",
                        "UBIQUITI_LABEL": "%{UBIQUITI_RULESET_NAME:iptables.ubiquiti.rule_set}-%{UBIQUITI_FIELD:iptables.ubiquiti.rule_number}-%{UBIQUITI_FIELD:event.outcome}"
                    }
                }
            },
            {
                "rename": {
                    "field": "message",
                    "target_field": "log.original"
                }
            },
            {
                "grok": {
                    "field": "iptables.ubiquiti.rule_set",
                    "ignore_missing": true,
                    "ignore_failure": true,
                    "patterns": [
                        "%{UBIQUITI_FIELD:iptables.ubiquiti.input_zone}-%{UBIQUITI_FIELD:iptables.ubiquiti.output_zone}"
                    ],
                    "pattern_definitions": {
                        "UBIQUITI_FIELD": "[^-]*"
                    }
                }
            },
            {
                "date": {
                    "field": "iptables.raw_date",
                    "ignore_failure": true,
                    "formats": [
                        "MMM  d HH:mm:ss",
                        "MMM dd HH:mm:ss"
                    ]
                }
            },
            {
                "date": {
                    "if": "ctx.event.timezone != null",
                    "field": "@timestamp",
                    "formats": ["ISO8601"],
                    "timezone": "{{ event.timezone }}",
                    "on_failure": [{"append": {"field": "error.message", "value": "{{ _ingest.on_failure_message }}"}}]
                }
            },
            {
                "remove": {
                    "field": "iptables.raw_date",
                    "ignore_missing": true
                }
            },

            {
                "lowercase": {
                    "field": "network.transport",
                    "ignore_missing": true
                }
            },
            {
                "geoip": {
                    "field": "source.ip",
                    "target_field": "source.geo",
                    "ignore_missing": true
                }
            },
            {
                "geoip": {
                    "field": "destination.ip",
                    "target_field": "destination.geo",
                    "ignore_missing": true
                }
            },
            {
                "script": {
                    "lang": "painless",
                    "params": {
                        "mappings": [
                            {
                                "source": {
                                    "object": "iptables",
                                    "key": "ether_type"
                                },
                                "destination": {
                                    "object": "network",
                                    "key": "type"
                                },
                                "map": {
                                    "08:00": "ipv4",
                                    "86:dd": "ipv6"
                                }
                            },
                            {
                                "source": {
                                    "object": "event",
                                    "key": "outcome"
                                },
                                "destination": {
                                    "object": "event",
                                    "key": "outcome"
                                },
                                "map": {
                                    "D": "deny",
                                    "A": "allow"
                                }
                            },
                            {
                                "source": {
                                    "object": "network",
                                    "key": "transport"
                                },
                                "destination": {
                                    "object": "network",
                                    "key": "transport"
                                },
                                "map": {
                                    "icmpv6": "ipv6-icmp"
                                }
                            }
                        ]
                    },
                    "source": "for (action in params.mappings) { def src = ctx[action.source.object]; if (src != null) { Map map = action.map; String key = src[action.source.key]; String mapping = map[key]; if (mapping != null) { Map dst = ctx[action.destination.object]; if (dst == null) { dst = new HashMap(); ctx[action.destination.object] = dst;} dst[action.destination.key] = mapping; } } }"
                }
            },
            {
                "script": {
                    "lang": "painless",
                    "params": {
                        "hex_fields_to_convert": [
                            "ether_type",
                            "tos",
                            "precedence_bits",
                            "tcp_reserved_bits"
                        ]
                    },
                    "source": "def iptables = ctx['iptables']; if (iptables != null) { for (key in params.hex_fields_to_convert) { long value = 0; def field = iptables[key]; if (field == null) continue; char[] hex = field.toLowerCase().toCharArray(); for (chr in hex) { long v = -1; if (chr >= (char)'a' && chr <= (char)'f') v = (long)chr - (char)'a' + 10; else if (chr >= (char)'0' && chr <= (char)'9') v = (long)chr - (char)'0'; if (v >= 0) {value = value*16 + v;} } iptables[key] = value; } }"
                }
            },
            {
                "rename": {
                    "field": "iptables.tcp_reserved_bits",
                    "target_field": "iptables.tcp.reserved_bits",
                    "ignore_missing": true
                }
            }
        ],
        "on_failure" : [{
            "set" : {
                "field" : "error.message",
                "value" : "{{ _ingest.on_failure_message }}"
            }
        }]
}
