I don’t have a repo or anything for this as I am not a programmer by trade. But I thought I’d share here if someone wants to take what I’ve done and roll with it. Rewrite and package it however you’d like, but some credit would be nice
I’d love to see what people can do with this.
I basically described how I created a pipeline to extract fields from Mikrotik Firewall logs and throw them at various functions such as geo ip lookups, reverse dns, spamhaus, tor exit nodes. I had OTX working as well but I hit it too much and reach limits fast. I did try to contact them to see how much to pay for full access but never got replies back. Anyway the link to my blog post is here.
Hmm link doesn’t seem to be working, not sure why.
But here is the actual Pipeline rule to get you started.
rule "mikrotik_firewall_log_parsing"
when
has_field("message") &&
contains(to_string($message.message), "firewall,info")
then
let message = to_string($message.message);
// Updated Grok pattern with optional prio field
let extracted_data = grok(
pattern: "%{WORD:log_type},%{WORD:log_level} %{NOTSPACE:log_prefix} %{WORD:firewall_chain}: in:%{DATA:in_interface} out:%{DATA:out_interface}, connection-state:%{WORD:connection_state} src-mac %{MAC:src_mac}, proto (%{WORD:protocol}( \\(%{DATA:flags}\\))?|%{INT:protocol_num}), %{IPV4:src_ip}(:%{INT:src_port})?->%{IPV4:dest_ip}(:%{INT:dest_port})?(, prio %{INT:src_prio}->%{INT:dest_prio})?, len %{INT:length}",
value: message
);
// Set fields based on the extracted data
set_field("log_type", extracted_data.log_type); // firewall type (e.g., firewall)
set_field("log_level", extracted_data.log_level); // log level (e.g., info)
set_field("log_prefix", extracted_data.log_prefix); // First log prefix
set_field("firewall_chain", extracted_data.firewall_chain); // Chain (input/output/forward/custom)
set_field("in_interface", extracted_data.in_interface); // Input interface (e.g., ether7)
set_field("out_interface", extracted_data.out_interface); // Output interface (e.g., (unknown 0))
set_field("connection_state", extracted_data.connection_state); // Connection state (e.g., new, invalid)
set_field("src_mac", extracted_data.src_mac); // Source MAC address
set_field("protocol", extracted_data.protocol); // Named protocol (e.g., TCP, UDP)
set_field("flags", extracted_data.flags); // TCP flags (e.g., SYN, ACK,FIN) or NULL for UDP
set_field("protocol_num", extracted_data.protocol_num); // Protocol number (e.g., 2 for IGMP)
set_field("src_ip", extracted_data.src_ip); // Source IP (e.g., 172.170.162.149)
set_field("src_port", extracted_data.src_port); // Source port (e.g., 33215)
set_field("dest_ip", extracted_data.dest_ip); // Destination IP (e.g., 1.10.22.1)
set_field("dest_port", extracted_data.dest_port); // Destination port (e.g., 80)
set_field("src_prio", extracted_data.src_prio); // Source priority (optional)
set_field("dest_prio", extracted_data.dest_prio); // Destination priority (optional)
set_field("length", extracted_data.length); // Packet length (e.g., 51)
end