################################################################# # logstash parsing logic and tagging for elk-hole # # created by n9nes # # feel free to star the rep - https://github.com/nin9s/elk-hole # ################################################################# input { beats { port => 5141 type => "logs" tags => ["pihole","5141"] } } filter { if "pihole" in [tags] { grok { patterns_dir => ["/etc/logstash/patterns/"] match => { "message" => [ # request - query type "^%{DNSMASQPREFIX} query\[%{WORD:query_type}\] %{FQDN:domain_request} from %{IP:request_from}$", # reponse domain to ip "^%{DNSMASQPREFIX} reply %{FQDN:domain_request} is %{IP:ip_response}$", # response domain is NXDOMAIN "^%{DNSMASQPREFIX} reply %{FQDN:domain_request} is NXDOMAIN$", # response config domain is NXDOMAIN "^%{DNSMASQPREFIX} config %{FQDN:domain_request} is NXDOMAIN$", # response config domain is no-DATA "^%{DNSMASQPREFIX} config %{FQDN:domain_request} is NODATA-IPv[4,6]$", # reponse domain to ip cname "^%{DNSMASQPREFIX} reply %{FQDN:domain_request} is \<CNAME\>$", # respone ip to domain "^%{DNSMASQPREFIX} reply %{IP:ip_request} is %{FQDN:domain_response}$", # piholed "^%{DNSMASQPREFIX} \/etc\/pihole\/gravity\.list %{FQDN:blocked_domain} is %{IP:pihole}$", # piholed local "^%{DNSMASQPREFIX} \/etc\/pihole\/local\.list %{FQDN:blocked_domain} is %{IP:pihole}$", # blacklist "^%{DNSMASQPREFIX} \/etc\/pihole\/black\.list %{FQDN:blocked_domain} is %{IP:pihole}$", # regex "^%{DNSMASQPREFIX} \/etc\/pihole\/regex\.list %{FQDN:blocked_domain} is %{IP:pihole}$", # reverse response etc hosts ip to domain "^%{DNSMASQPREFIX} \/etc\/hosts %{IP:ip_request} is %{FQDN:domain_response}$", # reverse response etc hosts domain to ip "^%{DNSMASQPREFIX} \/etc\/hosts %{FQDN:domain_request} is %{IP:ip_response}$", # forward dns to "^%{DNSMASQPREFIX} forwarded %{FQDN:domain_request} to %{IP:dns_forward_to}$", # cached domain to ip "^%{DNSMASQPREFIX} cached %{FQDN:domain_request} is %{IP:ip_response}$", # cached ip to domain "^%{DNSMASQPREFIX} cached %{IP:ip_request} is %{FQDN:domain_response}$", # cached domain to ip cname "^%{DNSMASQPREFIX} cached %{FQDN:domain_request} is \<CNAME\>$", # cached domain is NXDOMAIN "^%{DNSMASQPREFIX} cached %{FQDN:domain_request} is NXDOMAIN$", # cached domain is no-DATA "^%{DNSMASQPREFIX} cached %{FQDN:domain_request} is NODATA-IPv[4,6]$", # domain is no-DATA "^%{DNSMASQPREFIX} reply %{FQDN:domain_request} is NODATA-IPv[4,6]$", # SRV "^%{DNSMASQPREFIX} query\[%{WORD:query_type}\] %{HOSTNAMEPTR:request} from %{IP:request_from}$", # SRV forwarded "^%{DNSMASQPREFIX} forwarded %{HOSTNAMEPTR:request} to %{IP:dns_forward_to}$" , # SERVFAIL "^%{DNSMASQPREFIX} reply error is SERVFAIL" ] } } # to do cached and cached reverse if [message] =~ "cached" and [message] =~ "NXDOMAIN" { mutate { add_tag => [ "cached NXDOMAIN" ] } } else if [NODATA-IPv4] { mutate { add_tag => [ "NODATA" ] } } else if [NODATA-IPv6] { mutate { add_tag => [ "NODATA" ] } } else if [request_from] and [message] =~ "query" { mutate { add_tag => [ "request and query type" ] } } else if [ip_response] and [message] =~ "reply" { geoip { source => "ip_response" } mutate { add_tag => [ "response domain to ip" ] } } else if [message] =~ "CNAME" and [message] =~ "reply" { mutate { add_tag => [ "response domain to ip CNAME" ] } } else if [domain_response] and [message] =~ "reply" { mutate { add_tag => [ "response ip to domain" ] } geoip { source => "ip_request" } } else if [blocked_domain] { mutate { add_tag => [ "piholed" ] } } else if [message] =~ "\/etc\/hosts" { mutate { add_tag => [ "reverse hostsfile" ] } } else if [dns_forward_to] { mutate { add_tag => [ "dns forward" ] } } else if [ip_request] and [message] =~ "cached" { mutate { add_tag => [ "cached ip to domain" ] } geoip { source => "ip_request" } } else if [domain_request] and [message] =~ "cached" and [message] =~ "CNAME" { mutate { add_tag => [ "cached domain to ip cname" ] } } else if [domain_request] and [message] =~ "cached" { mutate { add_tag => [ "cached domain to ip" ] } geoip { source => "ip_response" } } mutate { add_field => { "[source_fqdn]" => "%{source_host}" } } dns { reverse => ["source_fqdn"] action => "replace" hit_cache_size => 4096 hit_cache_ttl => 900 failed_cache_size => 512 failed_cache_ttl => 900 } date { match => [ "date", "MMM d HH:mm:ss","MMM dd HH:mm:ss" ] } } } output { # stdout { codec => rubydebug } if "pihole" in [tags]{ elasticsearch { hosts => ["ELASTICSEARCHHOST:PORT"] manage_template => false index => "logstash-syslog-dns-%{+YYYY.MM}" } } }