GithubHelp home page GithubHelp logo

logstash-filter-dns's Introduction

Logstash Plugin

Travis Build Status

This is a plugin for Logstash.

It is fully free and fully open source. The license is Apache 2.0, meaning you are pretty much free to use it however you want in whatever way.

Documentation

Logstash provides infrastructure to automatically generate documentation for this plugin. We use the asciidoc format to write documentation so any comments in the source code will be first converted into asciidoc and then into html. All plugin documentation are placed under one central location.

Need Help?

Need help? Try #logstash on freenode IRC or the https://discuss.elastic.co/c/logstash discussion forum.

Developing

1. Plugin Developement and Testing

Code

  • To get started, you'll need JRuby with the Bundler gem installed.

  • Create a new plugin or clone and existing from the GitHub logstash-plugins organization. We also provide example plugins.

  • Install dependencies

bundle install

Test

  • Update your dependencies
bundle install
  • Run tests
bundle exec rspec

2. Running your unpublished Plugin in Logstash

2.1 Run in a local Logstash clone

  • Edit Logstash Gemfile and add the local plugin path, for example:
gem "logstash-filter-awesome", :path => "/your/local/logstash-filter-awesome"
  • Install plugin
# Logstash 2.3 and higher
bin/logstash-plugin install --no-verify

# Prior to Logstash 2.3
bin/plugin install --no-verify
  • Run Logstash with your plugin
bin/logstash -e 'filter {awesome {}}'

At this point any modifications to the plugin code will be applied to this local Logstash setup. After modifying the plugin, simply rerun Logstash.

2.2 Run in an installed Logstash

You can use the same 2.1 method to run your plugin in an installed Logstash by editing its Gemfile and pointing the :path to your local plugin development directory or you can build the gem and install it using:

  • Build your plugin gem
gem build logstash-filter-awesome.gemspec
  • Install the plugin from the Logstash home
# Logstash 2.3 and higher
bin/logstash-plugin install --no-verify

# Prior to Logstash 2.3
bin/plugin install --no-verify
  • Start Logstash and proceed to test the plugin

Contributing

All contributions are welcome: ideas, patches, documentation, bug reports, complaints, and even something you drew up on a napkin.

Programming is not a required skill. Whatever you've seen about open source and maintainers or community members saying "send patches or die" - you will not see that here.

It is more important to the community that you are able to contribute.

For more information about contributing, see the CONTRIBUTING file.

logstash-filter-dns's People

Contributors

aldenks avatar andrewvc avatar andsel avatar bradvido avatar colinsurprenant avatar dedemorton avatar electrical avatar jakelandis avatar jordansissel avatar jsvd avatar karenzone avatar kares avatar mashhurs avatar mtopper avatar ph avatar phaedrusthegreek avatar prehor avatar robbavey avatar robcowart avatar smokris avatar suyograo avatar yaauie avatar ycombinator avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

logstash-filter-dns's Issues

The dns filter (dns.rb) produces a lot of SocketError messages for reverse lookups

We are using the dns filter in logstash quite heavily to do a reverse lookup for the IP of every incoming log message. We get a lot of "DNS: Encountered SocketError" errors. The SocketError object contains the message "bind: name or service not known".

The IPs the reverse lookups are done for are all properly registered in our DNS and most of the time the dns filter can successfully make the reverse lookup. Running tcpdump I could not find any problems on the network layer while the SocketError in the dns filter appeared.

The volume of messages and hence of reverse lookups per 24h is roughly 7.3 millions, of which are 700 thousand socket errors.

Some more information about our environment:

Enterprise Linux 6.6 with nscd running. Turning nscd on/off doesn't change anything. We also changed the JVM dns caching from completely off to infinite. No effects either.

Logstash Crash with ConcurrencyError: interrupted waiting for mutex: null

Under a concrete set of circumstances there might be a concurrency problem while processing the /etc/hosts file to setup necessary resolvers. This situation might only happen when the one filter instance is stuck setting up the hosts but this thread and then another instance got kill while waiting, making this tricky so reproduce with a living LS instance.

The condition could be reproduced independently of logstash using https://gist.github.com/purbon/106e80a5d85b3a6fbf1e5f10b5d0d643 code.

The exception reported is:

"exception"=>#<ConcurrencyError: interruptedwaitingformutex: null>,
    "backtrace"=>["org/jruby/ext/thread/Mutex.java:94:in `lock'",
    "org/jruby/ext/thread/Mutex.java:147:in `synchronize'",
    "/opt/logstash/vendor/jruby/lib/ruby/1.9/resolv.rb:190:in `lazy_initialize'",
    "/opt/logstash/vendor/jruby/lib/ruby/1.9/resolv.rb:268:in `each_name'",
    "/opt/logstash/vendor/jruby/lib/ruby/1.9/resolv.rb:151:in `each_name'",
    "org/jruby/RubyArray.java:1613:in `each'",
    "/opt/logstash/vendor/jruby/lib/ruby/1.9/resolv.rb:150:in `each_name'",
    "/opt/logstash/vendor/jruby/lib/ruby/1.9/resolv.rb:132:in `getname'",
    "/opt/logstash/vendor/bundle/jruby/1.9/gems/logstash-filter-dns-2.1.3/lib/logstash/filters/dns.rb:244:in `getname'",
    "/opt/logstash/vendor/bundle/jruby/1.9/gems/logstash-filter-dns-2.1.3/lib/logstash/filters/dns.rb:231:in `retriable_getname'",
    "org/jruby/RubyProc.java:281:in `call'",
    "/opt/logstash/vendor/bundle/jruby/1.9/gems/logstash-filter-dns-2.1.3/lib/logstash/filters/dns.rb:216:in `retriable_request'",
    "org/jruby/ext/timeout/Timeout.java:115:in `timeout'",
    "/opt/logstash/vendor/bundle/jruby/1.9/gems/logstash-filter-dns-2.1.3/lib/logstash/filters/dns.rb:215:in `retriable_request'",
    "/opt/logstash/vendor/bundle/jruby/1.9/gems/logstash-filter-dns-2.1.3/lib/logstash/filters/dns.rb:230:in `retriable_getname'",
    "/opt/logstash/vendor/bundle/jruby/1.9/gems/logstash-filter-dns-2.1.3/lib/logstash/filters/dns.rb:178:in `reverse'",
    "org/jruby/RubyArray.java:1613:in `each'",
    "/opt/logstash/vendor/bundle/jruby/1.9/gems/logstash-filter-dns-2.1.3/lib/logstash/filters/dns.rb:156:in `reverse'",

This problem is independant of LS code, it has been reported in several different environments see [1] and [2] as examples.

Plan of action:

  • There is an upstream issue opened jruby/jruby#4048
  • Will wrap the resolv operations under a mutex inside the plugin, this will help making this operation thread safe, but certainly will need proper test by environments that can reproduce this issue inside LS.

Option to define the type of address to retrieve in the resolve

Hi,

By default, using resolve retrieves only the first IP address, often in IPv4.
In the case of a domain with IPv4 and IPv6, it would be interesting to choose to recover IPv4 or IPv6 or both.

We can for example add the type of record that we would like the resolve to retrieve. Values could be [ "A", "AAAA" ]

Best regards,

DNS: timeout on resolving address on all requests after hours of operation

After upgrading to 6.7.1 version of logstash, the DNS filter works fine for a while and then suddenly starts timing out continuously, thus slowing down pipeline performance dramatically.

[2019-04-23T22:27:49,497][WARN ][logstash.filters.dns ] DNS: timeout on resolving address. {:field=>"[source][host]", :value=>"10.48.91.99"}

Troubleshooting Steps

  • Remove failed & hit caches form config
  • Downgraded plugin to 3.0.11
  • Returned to previously built Logstash 6.5.1 container

The behaviour continued in the first two steps on LS 6.7.1. The behaviour occured straight away after removing the cache size and ttl settings.

Things seem stable again back at LS 6.5.1.

Investigation

After leaving a comment on #40, @colinsurprenant replied with the following:

@berglh Thanks for the followup.

I believe I found the source of the problem. I will need to validate tomorrow but there seems to be a leak (a request id cache fills up which lead to an infinite loop that is aborted by the timeout) in the new version of the resolver code that was updated starting with 6.7. For now, as you noticed, the only workaround is to downgrade to 6.6 (6.6.2 as of now) and just downgrading the dns filter will not help.

Environment

I'm using the official Logstash containers.
I'm use a caching-only BIND server to service the requests of Logstash, I've configured the name server at the Docker container level.
The BIND server is always able to correctly resolve the requests correctly if I test against the IPs or host names detailed in the Logstash warning events.

Details

  • Version: Logstash 6.7.1, Plugin Version 3.0.12
  • Operating System: Oracle Enterprise Linux 7.3 (Official Docker Container)
  • Config:
2-general/400000-ad-smb.conf:      dns {
2-general/400000-ad-smb.conf-        resolve => ["[@metadata][destination][address]"]
2-general/400000-ad-smb.conf-        action => "replace"
2-general/400000-ad-smb.conf-        failed_cache_size => 1000
2-general/400000-ad-smb.conf-        failed_cache_ttl => 60
2-general/400000-ad-smb.conf-        hit_cache_size => 10000
2-general/400000-ad-smb.conf-        hit_cache_ttl => 300
2-general/400000-ad-smb.conf-      }
--
2-general/400000-ad-smb.conf:            dns {
2-general/400000-ad-smb.conf-              reverse => ["[@metadata][ip]"]
2-general/400000-ad-smb.conf-              action => "replace"
2-general/400000-ad-smb.conf-              failed_cache_size => 1000
2-general/400000-ad-smb.conf-              failed_cache_ttl => 60
2-general/400000-ad-smb.conf-              hit_cache_size => 10000
2-general/400000-ad-smb.conf-              hit_cache_ttl => 300
2-general/400000-ad-smb.conf-            }

java.lang.IllegalArgumentException on wrong resolve field string cause logstash to crash

Hi,
I found a bug in latest dns.rb file.
When the resolve field in dns filter is a wrong string, it cause an not handled exception, like in case "www.repubblica.it..":

[2016-12-07T11:22:01,798][ERROR][logstash.pipeline ] Exception in pipelineworker, the pipeline stopped processing new events, please check your filter configuration and restart Logstash. {"exception"=>java.lang.IllegalArgumentException: Empty label is not a legal name, "backtrace"=>["java.net.IDN.toASCIIInternal(java/net/IDN.java:283)", "java.net.IDN.toASCII(java/net/IDN.java:122)", "java.net.IDN.toASCII(java/net/IDN.java:151)", "java.lang.reflect.Method.invoke(java/lang/reflect/Method.java:498)", "LogStash::Filters::DNS.getaddress(/usr/share/logstash/vendor/bundle/jruby/1.9/gems/logstash-filter-dns-3.0.3/lib/logstash/filters/dns.rb:279)", "LogStash::Filters::DNS.getaddress(/usr/share/logstash/vendor/bundle/jruby/1.9/gems/logstash-filter-dns-3.0.3/lib/logstash/filters/dns.rb:279)", "LogStash::Filters::DNS.retriable_getaddress(/usr/share/logstash/vendor/bundle/jruby/1.9/gems/logstash-filter-dns-3.0.3/lib/logstash/filters/dns.rb:267)", "LogStash::Filters::DNS.retriable_getaddress(/usr/share/logstash/vendor/bundle/jruby/1.9/gems/logstash-filter-dns-3.0.3/lib/logstash/filters/dns.rb:267)", "org.jruby.RubyProc.call(org/jruby/RubyProc.java:281)", "LogStash::Filters::DNS.retriable_request(/usr/share/logstash/vendor/bundle/jruby/1.9/gems/logstash-filter-dns-3.0.3/lib/logstash/filters/dns.rb:245)", "LogStash::Filters::DNS.retriable_request(/usr/share/logstash/vendor/bundle/jruby/1.9/gems/logstash-filter-dns-3.0.3/lib/logstash/filters/dns.rb:245)", "org.jruby.ext.timeout.Timeout.timeout(org/jruby/ext/timeout/Timeout.java:115)", "LogStash::Filters::DNS.retriable_request(/usr/share/logstash/vendor/bundle/jruby/1.9/gems/logstash-filter-dns-3.0.3/lib/logstash/filters/dns.rb:244)", "LogStash::Filters::DNS.retriable_request(/usr/share/logstash/vendor/bundle/jruby/1.9/gems/logstash-filter-dns-3.0.3/lib/logstash/filters/dns.rb:244)", "LogStash::Filters::DNS.retriable_getaddress(/usr/share/logstash/vendor/bundle/jruby/1.9/gems/logstash-filter-dns-3.0.3/lib/logstash/filters/dns.rb:266)", "LogStash::Filters::DNS.retriable_getaddress(/usr/share/logstash/vendor/bundle/jruby/1.9/gems/logstash-filter-dns-3.0.3/lib/logstash/filters/dns.rb:266)", "LogStash::Filters::DNS.resolve(/usr/share/logstash/vendor/bundle/jruby/1.9/gems/logstash-filter-dns-3.0.3/lib/logstash/filters/dns.rb:140)", "LogStash::Filters::DNS.resolve(/usr/share/logstash/vendor/bundle/jruby/1.9/gems/logstash-filter-dns-3.0.3/lib/logstash/filters/dns.rb:140)", "LruRedux::Cache.getset(/usr/share/logstash/vendor/bundle/jruby/1.9/gems/lru_redux-1.1.0/lib/lru_redux/cache.rb:34)", "LruRedux::Cache.getset(/usr/share/logstash/vendor/bundle/jruby/1.9/gems/lru_redux-1.1.0/lib/lru_redux/cache.rb:34)", "LruRedux::Util::SafeSync.getset(/usr/share/logstash/vendor/bundle/jruby/1.9/gems/lru_redux-1.1.0/lib/lru_redux/util/safe_sync_jruby.rb:6)", "LruRedux::Util::SafeSync.getset(/usr/share/logstash/vendor/bundle/jruby/1.9/gems/lru_redux-1.1.0/lib/lru_redux/util/safe_sync_jruby.rb:6)", "MonitorMixin.mon_synchronize(/usr/share/logstash/vendor/jruby/lib/ruby/1.9/monitor.rb:211)", "MonitorMixin.mon_synchronize(/usr/share/logstash/vendor/jruby/lib/ruby/1.9/monitor.rb:211)", "MonitorMixin.mon_synchronize(/usr/share/logstash/vendor/jruby/lib/ruby/1.9/monitor.rb:210)", "MonitorMixin.mon_synchronize(/usr/share/logstash/vendor/jruby/lib/ruby/1.9/monitor.rb:210)", "LruRedux::Util::SafeSync.getset(/usr/share/logstash/vendor/bundle/jruby/1.9/gems/lru_redux-1.1.0/lib/lru_redux/util/safe_sync_jruby.rb:5)", "LruRedux::Util::SafeSync.getset(/usr/share/logstash/vendor/bundle/jruby/1.9/gems/lru_redux-1.1.0/lib/lru_redux/util/safe_sync_jruby.rb:5)", "LogStash::Filters::DNS.resolve(/usr/share/logstash/vendor/bundle/jruby/1.9/gems/logstash-filter-dns-3.0.3/lib/logstash/filters/dns.rb:140)", "LogStash::Filters::DNS.resolve(/usr/share/logstash/vendor/bundle/jruby/1.9/gems/logstash-filter-dns-3.0.3/lib/logstash/filters/dns.rb:140)", "org.jruby.RubyArray.each(org/jruby/RubyArray.java:1613)", "LogStash::Filters::DNS.resolve(/usr/share/logstash/vendor/bundle/jruby/1.9/gems/logstash-filter-dns-3.0.3/lib/logstash/filters/dns.rb:125)", "LogStash::Filters::DNS.resolve(/usr/share/logstash/vendor/bundle/jruby/1.9/gems/logstash-filter-dns-3.0.3/lib/logstash/filters/dns.rb:125)", "LogStash::Filters::DNS.filter(/usr/share/logstash/vendor/bundle/jruby/1.9/gems/logstash-filter-dns-3.0.3/lib/logstash/filters/dns.rb:98)", "LogStash::Filters::DNS.filter(/usr/share/logstash/vendor/bundle/jruby/1.9/gems/logstash-filter-dns-3.0.3/lib/logstash/filters/dns.rb:98)", "LogStash::Filters::Base.multi_filter(/usr/share/logstash/logstash-core/lib/logstash/filters/base.rb:156)", "LogStash::Filters::Base.multi_filter(/usr/share/logstash/logstash-core/lib/logstash/filters/base.rb:156)", "org.jruby.RubyArray.each(org/jruby/RubyArray.java:1613)", "LogStash::Filters::Base.multi_filter(/usr/share/logstash/logstash-core/lib/logstash/filters/base.rb:153)", "LogStash::Filters::Base.multi_filter(/usr/share/logstash/logstash-core/lib/logstash/filters/base.rb:153)", "LogStash::FilterDelegator.multi_filter(/usr/share/logstash/logstash-core/lib/logstash/filter_delegator.rb:41)", "LogStash::FilterDelegator.multi_filter(/usr/share/logstash/logstash-core/lib/logstash/filter_delegator.rb:41)", "RUBY.initialize((eval):2343)", "org.jruby.RubyArray.each(org/jruby/RubyArray.java:1613)", "RUBY.initialize((eval):2340)", "org.jruby.RubyProc.call(org/jruby/RubyProc.java:281)", "RUBY.initialize((eval):2358)", "org.jruby.RubyArray.each(org/jruby/RubyArray.java:1613)", "RUBY.initialize((eval):2355)", "org.jruby.RubyProc.call(org/jruby/RubyProc.java:281)", "RUBY.initialize((eval):2374)", "org.jruby.RubyArray.each(org/jruby/RubyArray.java:1613)", "RUBY.initialize((eval):2369)", "org.jruby.RubyProc.call(org/jruby/RubyProc.java:281)", "RUBY.initialize((eval):2396)", "org.jruby.RubyArray.each(org/jruby/RubyArray.java:1613)", "RUBY.initialize((eval):2386)", "org.jruby.RubyProc.call(org/jruby/RubyProc.java:281)", "RUBY.initialize((eval):2441)", "org.jruby.RubyArray.each(org/jruby/RubyArray.java:1613)", "RUBY.initialize((eval):2428)", "org.jruby.RubyProc.call(org/jruby/RubyProc.java:281)", "RUBY.filter_func((eval):784)", "RUBY.filter_batch(/usr/share/logstash/logstash-core/lib/logstash/pipeline.rb:260)", "org.jruby.RubyProc.call(org/jruby/RubyProc.java:281)", "RUBY.each(/usr/share/logstash/logstash-core/lib/logstash/util/wrapped_synchronous_queue.rb:186)", "org.jruby.RubyHash.each(org/jruby/RubyHash.java:1342)", "RUBY.each(/usr/share/logstash/logstash-core/lib/logstash/util/wrapped_synchronous_queue.rb:185)", "RUBY.filter_batch(/usr/share/logstash/logstash-core/lib/logstash/pipeline.rb:258)", "RUBY.worker_loop(/usr/share/logstash/logstash-core/lib/logstash/pipeline.rb:246)", "RUBY.start_workers(/usr/share/logstash/logstash-core/lib/logstash/pipeline.rb:225)", "java.lang.Thread.run(java/lang/Thread.java:745)"]}

I simply added a rescue to the exception, so logstash will not crash, but simply skip this event.
The patch is the following:

273,278c273
<     begin
<         idn = IDN.toASCII(name)
<     rescue java.lang.IllegalArgumentException => e
<         @logger.error("DNS: Illegal Argument Exception.", :exception => e)
<         return
<     end
---
>     idn = IDN.toASCII(name)

Have a good day.
Simone

Reverse: Stop processing on first error when processing an array

Moved from LOGSTASH-2103
Using the DNS filter reverse with an array I noticed subsequent elements will only be resolved if the ones before it succeed.
E.g. Config:

dns {
 reverse => [ "src", "dst"]
}

WORKS

input = {"src":"8.8.8.8","dst":"169.0.0.1"}
output = {"src":["8.8.8.8","google-public-dns-a.google.com"],"dst":"169.0.0.1"}

FAILS

input = {"src":"169.0.0.1","dst":"8.8.8.8"}
output = {"src":"169.0.0.1","dst":"8.8.8.8"}
expected output = {"src":"169.0.0.1","dst":["8.8.8.8","google-public-dns-a.google.com"]}

I suppose the return should be replace by continue within the reverse() method

ipv6 dns does not work

Hello,
My logstash indexers are running on double stacked (ipv4, ipv6). My resolv.conf is configured with ipv6 nameservers.

I must tell an ipv4 nameserver to have "dns" filter working. Worst with ipv6 nameserver, I did not read any problem from the logs !

plugin fails (doing TCP fallback) with big DNS records

Plugin version 3.1.4 (and bellow) will likely run into issues with DNS records >~ 65.500 bytes.

Description of the problem including expected versus actual behavior

DNS primarily uses UDP and a response usually fits into a UDP datagram.
However, in rare cases the payload might be bigger than 65k, in which case the Resolv library will attempt to do a TCP fallback. This fallback mechanism has a bug when multiple name-servers are involved in a query.

There's no actual reproducer but here's what I assume happens :

  • with multiple nameservers we setup a UDP sender
  • the sender is supposed to "cache" UDP sockets (in case we try multiple servers)
  • the UDP (from a given server) packet we get back is detected as too big
  • switch over to trying a TCP sender next
    (the problem is the TCP sender does not share the original assumption of "caching" multiple sockets)
  • the same server is tried over TCP - perhaps fails (or timeouts)
  • we carry on trying the next name-server from the list using the same TCP sender
    (the TCP sender detects a different IP/port and fails with the host/port don't match: ... error)

Provide logs (if relevant): N/A 3.1.4 did not have backtrace/class logging for unknown errors.
DNS: Unexpected Error.


Seems to be a known upstream Resolv bug: https://bugs.ruby-lang.org/issues/8285

The DNS filter is removing the @metadata field

I am using a simple configuration and reading from elasticsearch. Steps to reproduce:

POST testcase/test
{
  "ipaddress": "127.0.0.1"
}
input {
  elasticsearch {
    hosts    => "127.0.0.1:9200"
    index    => "testcase"
    docinfo  => true
  }
}

filter {
  mutate {
    add_field => { 
      "hostname" => "%{ipaddress}"
      "index" => "%{[@metadata][_index]}"
      "document_type" => "%{[@metadata][_type]}"
      "document_id" => "%{[@metadata][_id]}"
    }
  }
  dns {
    nameserver => "127.0.0.1"
    reverse => [ "hostname" ]
    action  => "replace"
  }
}

output {
  stdout { 
    codec  => rubydebug {
      metadata => true
    }
  }
}

Output:

{
        "ipaddress" => "127.0.0.1",
         "@version" => "1",
       "@timestamp" => "2016-02-05T17:15:43.881Z",
         "hostname" => "localhost",
            "index" => "testcase",
    "document_type" => "test",
      "document_id" => "1"
}

If i remove the DNS filter, i get the desired result:

{
        "ipaddress" => "127.0.0.1",
         "@version" => "1",
       "@timestamp" => "2016-02-05T17:44:21.851Z",
         "hostname" => "127.0.0.1",
            "index" => "testcase",
    "document_type" => "test",
      "document_id" => "1",
        "@metadata" => {
        "_index" => "testcase",
         "_type" => "test",
           "_id" => "1"
    }
}

Looks like the DNS filter is removing the metadata?

FR: Option to disable logging DNS lookup failures

Hi,

I noticed in my Logstash (v6.4.3) logs many many instances of WARN level messages detailing all the times an IP address could not be reversed to a hostname in my pipeline that leverages logstash-filter-dns reverse lookup. Certainly this information is good to know and good default behavior but in my scenario it's fine if an IP address has no reverse name (PTR record) and I'd like the option to disable logging these reverse lookup failures.

Perhaps adding a Boolean setting called something like 'log_failures' that defaults to 'true' is the way to go?

Or if this is already controllable via Logstash's Log4J properties file, then please update logstash-filter-dns documentation (https://www.elastic.co/guide/en/logstash/current/plugins-filters-dns.html) to explain what to modify in the L4J file to accomplish this without disabling other WARN level messages.

Thanks,
Patrick

DNS: timeout on resolving address.

After updating to 3.0.7, the plugin starts spamming DNS: timeout on resolving address. {:field=>"host", :value=>"172.20.54.3" errors in the logs after some time.

If I do a manual lookup on the indexer, the IP resolves fine. So it seems like some kind of cache or memory buffer is breaking lookups permanently. It seems after 1 timeout, no new DNS queries are even made (I checked with tcpdump).

If I restart the indexer, the plugin works fine for a while until it breaks again.

Config:

    dns {
                        reverse => ["host"]
                        action => "replace"
                }

Memory Leak related to many DNS lookup failures

We have seen multiple reports of a memory leak, and have so far traced it down to the exceptions being raised by the underlying Resolv library when it cannot perform a lookup or a reverse-lookup.

An analysis of the memory dump finds that the exceptions raised by the resolv library and immediately caught by this plugin are not being dereferenced as we would expect them to, and end up flagged as the cause of a subsequent exception, producing an endless chain from the most recent exception to the first.

I believe the root issue to be beyond the scope of this plugin, as the exceptions are rescue'd and immediately allowed to fall out of scope, but that the volume of exceptions raised by this implementation when it is failing many lookups may exacerbate the issue.

Reports:

  • v3.0.13 (Logstash 7.5.0)
  • v3.0.12 (Logstash 7.1.1)

Improve throughput for for failed lookups

I use this filter to reverse-lookup every IP in our events, but it has become a huge bottleneck.
When the lookup is successful, it gets cached by our DNS server and is generally not a bottleneck. But when it fails, the timeout parameter hits its limit and the event continues to the next filter in our pipeline (and it never gets cached at the DNS server).

The problem is that a sane timeout of 2 seconds (to allow time for successful lookups) is still way too long. e.g. when you are processing 100 events per second, even if only 5% of those events have failed lookups, it will take 10 seconds to process 1 second worth of events.

I'd propose adding a short-term (expiring) cache that remembers failed lookups and doesn't try them again for a configurable amount of time. This obviously only helps when the IPs being processed are somewhat repetitive (as they are in our case, and I'd guess most other use-cases).

Reverse Lookup fails on uppercase "IN-ADDR.ARPA"

Under Logstash 5.6.5, reverse lookups will fail when the case of the in-addr.arpa zone name is in anything other than lower case. This was not reproducible under Win2k16 or Bind 9.9.4 (default CentOS 7), but was reproducible under a custom bind 9.10.6 installation that has since changed behaviour to preserve case sensitivity.

A zone configured like this would pass:

zone "1.168.192.in-addr.arpa" IN {
        type master;
        file "1.168.192.IN-ADDR.ARPA";
        allow-update { none; };
};

But the slightest difference in case in the zone name would case a failure:

zone "1.168.192.IN-addr.arpa" IN {
        type master;
        file "1.168.192.IN-ADDR.ARPA";
        allow-update { none; };
};

Some extra debugging reveals this error:

 DNS: couldn't resolve the address. {:field=>"message", :value=>"192.168.1.10", :message=>"no name for 192.168.1.10"}

Which (as best as I could tell) traces back to Ruby's Resolv::DNS.getaddresses failing to be case insensitive as it should be , according to RFC 4343.

OK now the good news - The bug tested fixed as of Logstash 6.0.0! So, problem solved!!

Please add support for DNS suffix list

Please add the option to provide a list of suffixes to try and resolve with. i.e. If resolve fails, append each suffix in order until one succeeds, and fail if the list is exhausted.

dns {
suffixes => ["domain1.com", "domain2.org"]
resolve => ["hostname1", "hostname2"]
}

Assuming hostname1 = bob and hostname2 = jim, tries:

returns first success:

  • bob
  • bob.domain1.com
  • bob.domain2.org

returns first success

  • jim
  • jim.domain1.com
  • jim.domain2.org

This would be very useful for Windows Eventlogs. They tend to contain unqualified hostnames, and suffixes can contain a list of known AD dns names.

Thank you & regards, -Thorben

Many ResolvTimeouts cause logstash crash

Created by @Danko90, moved from elastic/logstash#6115


Hi,
I tried to use the dns filter (dns.rb) to cache the requests in a dns local server. I noticed that sometimes if you try to resolve several domain names using even the dig tool, you will get SERVfailed error (the dns server doesn’t respond).
This error may be caused by a bad dns server configuration, and therefore, logstash waits for an answer until the timeout.
Meanwhile logstash is waiting for that answer, its queue will become full due to the other requests, that causes a crash whether logstash tries to resolve many requests of which it won’t get any response.
For istance, if logstash has just one request that causes a ResolvTimeout and N other requests, logstash works well. If logstash has N requests that causes ResolvTimeout error and other N requests, logstash crashes.
To fix this problem I modified the file dns.rb as you can see below

 ##set this flag to "true" for save dns requests timeout
  config :enable_cache_timeout, :validate => :boolean, :default => false


      rescue Resolv::ResolvError
        @failed_cache[raw] = true if @failed_cache
        @logger.debug("DNS: couldn't resolve the hostname.",
                      :field => field, :value => raw)
        return
      rescue Resolv::ResolvTimeout, Timeout::Error
        if enable_cache_timeout == true
                        @failed_cache[raw] = true if @failed_cache
        end
        @logger.error("DNS: timeout on resolving the hostname.",
                      :field => field, :value => raw)
        return
      rescue SocketError => e
        @logger.error("DNS: Encountered SocketError.",
                      :field => field, :value => raw, :message => e.message)
        return
      end

At line 66 I added a variable to enable cache in case of timeout.
At line 128 now I’m able to cache the failed dns requests if the cache timeout is enabled.

I don’t know if this change is logically correct, but it serves me in order to avoid others logstash crashes.
I would like to have an opinion from a logstash expert, any help will be appreciated.

Thanks,
Danilo

Exceptions are expensive and may be avoided for lookup misses

The Resolv APIs this plugin uses throw exceptions when there is no name associated with an address (or vice versa; read: lookup miss, not lookup failure), and our implmentation relies on these costly exceptions for flow control (Resolv#getname(address), Resolv#getaddress(name)).

But Resolv also provides public APIs that treat a lookup misses as non-exceptional (Resolv#each_name(address,&block), Resolv#each_address(name,&block), which still handle lookup failure exceptionally). I believe that we should look into using these APIs, and will need to modify our implementation to handle these lookup misses in the normal (non-exceptional) flow control.

Query for txt records?

From the documentation it seems you can only query A, CNAME or Pointer records. It would be useful to be able to query txt records as well.

tag on failure

after retrying N times, we should tag the event like we do for grok, time, and other filters

getaddress() and getname() don't return strings

I was looking through the code and ran across these two statements:

dns.rb Lines 114-115:

# in JRuby 1.7.11 outputs as US-ASCII
address = @resolv.getaddress(raw).force_encoding(Encoding::UTF_8)

and dns.rb Lines 173-174:

# in JRuby 1.7.11 outputs as US-ASCII
hostname = @resolv.getname(raw).force_encoding(Encoding::UTF_8)

Both try to run .force_encoding() on the results of getaddress() and getname() but they return objects that don't have a .force_encoding() method on them:

$ jpry -r resolv
Pry running on 1.9.3-p551 with RubyGems 2.4.8 and .
[1] (pry) main: 0> r = Resolv::DNS.new
[2] (pry) main: 0> r.getaddress('google.com').force_encoding(Encoding::UTF_8)
NoMethodError: undefined method `force_encoding' for #<Resolv::IPv4 74.125.29.139>
from (pry):2:in `evaluate_ruby'
[3] (pry) main: 0> r.getname('74.125.29.113').force_encoding(Encoding::UTF_8)
NoMethodError: undefined method `force_encoding' for #<Resolv::DNS::Name: qg-in-f113.1e100.net.>
from (pry):3:in `evaluate_ruby'

Should there be a .to_s before the .force_encoding()?

No DNS lookups issued when doing a reverse and forward lookup with cache on IP fields

Logstash information:

  1. Logstash version: 7.17.9
  2. Logstash installation source: docker
  3. How is Logstash being run: docker container
  4. How was the Logstash Plugin installed: as provided (3.1.5) and updated via logstash-filter (3.2.0)

JVM (e.g. java -version): using bundled jdk

OS version (uname -a if on a Unix-like system): docker container

Description of the problem including expected versus actual behavior:

When using the dns filter plugin with reverse, resolve and hit_cache on fields containing only IP addresses, no lookup is done at all. As soon as the cache is disabled, the reverse lookup works.

Some log sources provide host information in a mixed format. Sometimes as IP address and sometimes as hostname/FQDN. This value is copied as reported into the field source.address. Then this value is copied into the fields source.ip and source.domain and the dns filter plugin should do a reverse lookup on the source.domain field and a normal resolve on source.ip. Hence if source.domain would contain an IP address, it will be replaced with the appropriate hostname and source.ip would be left unchanged; and vice versa.

I confirmed with tcpdump, that not a single DNS query is sent to the DNS server. If a hostname/fqdn is specified instead of an ip address, the dns-filter works as expected and replaced the hostname with an ip address in one field an leaves the other one unchanged.

If the hit cache is disabled, the dns-filter replaces the ip address with the hostname in one field, and leaves the other one unchanged.

If the resolve parameter is removed and the hit cache stays enabled, the dns-filter replaces the ip address with the hostname as intended.

Steps to reproduce:

input {
  generator {
    ecs_compatibility => "v8"
    count => 1
    lines => [
"8.8.8.8"
]}
}

filter {
  mutate {
    add_field => {
      "[source][domain]" => "%{message}"
      "[source][ip]" => "%{message}"
    }
  }

  dns {
    action => "replace"
    resolve => "[source][domain]"
    reverse => "[source][ip]"
    hit_cache_ttl => 60
    hit_cache_size => 10
  }
}
output {
  stdout { codec => rubydebug }
}

Provide logs (if relevant):
Only DEBUG lines of the dns module are contained in the log output

# logstash --log.level debug
Using bundled JDK: /usr/share/logstash/jdk
OpenJDK 64-Bit Server VM warning: Option UseConcMarkSweepGC was deprecated in version 9.0 and will likely be removed in a future release.
Sending Logstash logs to /usr/share/logstash/logs which is now configured via log4j2.properties
[2023-04-22T22:50:48,249][INFO ][logstash.runner          ] Log4j configuration path used is: /usr/share/logstash/config/log4j2.properties
[2023-04-22T22:50:48,258][INFO ][logstash.runner          ] Starting Logstash {"logstash.version"=>"7.17.9", "jruby.version"=>"jruby 9.2.20.1 (2.5.8) 2021-11-30 2a2962fbd1 OpenJDK 64-Bit Server VM 11.0.18+10 on 11.0.18+10 +indy +jit [linux-x86_64]"}
[2023-04-22T22:50:48,260][INFO ][logstash.runner          ] JVM bootstrap flags: [-Xms1g, -Xmx1g, -XX:+UseConcMarkSweepGC, -XX:CMSInitiatingOccupancyFraction=75, -XX:+UseCMSInitiatingOccupancyOnly, -Djava.awt.headless=true, -Dfile.encoding=UTF-8, -Djdk.io.File.enableADS=true, -Djruby.compile.invokedynamic=true, -Djruby.jit.threshold=0, -Djruby.regexp.interruptible=true, -XX:+HeapDumpOnOutOfMemoryError, -Djava.security.egd=file:/dev/urandom, -Dlog4j2.isThreadContextMapInheritable=true, -Dls.cgroup.cpuacct.path.override=/, -Dls.cgroup.cpu.path.override=/]
[2023-04-22T22:50:49,495][INFO ][logstash.agent           ] Successfully started Logstash API endpoint {:port=>9600, :ssl_enabled=>false}
[2023-04-22T22:50:50,545][INFO ][org.reflections.Reflections] Reflections took 52 ms to scan 1 urls, producing 119 keys and 419 values
[2023-04-22T22:50:51,232][WARN ][deprecation.logstash.codecs.plain] Relying on default value of `pipeline.ecs_compatibility`, which may change in a future major release of Logstash. To avoid unexpected changes when upgrading Logstash, please explicitly declare your desired ECS Compatibility mode.
[2023-04-22T22:50:51,257][WARN ][deprecation.logstash.inputs.generator] Relying on default value of `pipeline.ecs_compatibility`, which may change in a future major release of Logstash. To avoid unexpected changes when upgrading Logstash, please explicitly declare your desired ECS Compatibility mode.
[2023-04-22T22:50:51,355][DEBUG][logstash.plugins.registry] On demand adding plugin to the registry {:name=>"dns", :type=>"filter", :class=>LogStash::Filters::DNS}
[2023-04-22T22:50:51,365][DEBUG][logstash.filters.dns     ] config LogStash::Filters::DNS/@action = "replace"
[2023-04-22T22:50:51,365][DEBUG][logstash.filters.dns     ] config LogStash::Filters::DNS/@hit_cache_size = 10000
[2023-04-22T22:50:51,365][DEBUG][logstash.filters.dns     ] config LogStash::Filters::DNS/@id = "32e1cf6783f1e24aad525c2a1db225c8fd292767b1c72c16afd9b51cc43f72c4"
[2023-04-22T22:50:51,365][DEBUG][logstash.filters.dns     ] config LogStash::Filters::DNS/@resolve = ["[source][domain]"]
[2023-04-22T22:50:51,365][DEBUG][logstash.filters.dns     ] config LogStash::Filters::DNS/@reverse = ["[source][ip]"]
[2023-04-22T22:50:51,365][DEBUG][logstash.filters.dns     ] config LogStash::Filters::DNS/@hit_cache_ttl = 60
[2023-04-22T22:50:51,365][DEBUG][logstash.filters.dns     ] config LogStash::Filters::DNS/@enable_metric = true
[2023-04-22T22:50:51,365][DEBUG][logstash.filters.dns     ] config LogStash::Filters::DNS/@add_tag = []
[2023-04-22T22:50:51,365][DEBUG][logstash.filters.dns     ] config LogStash::Filters::DNS/@remove_tag = []
[2023-04-22T22:50:51,365][DEBUG][logstash.filters.dns     ] config LogStash::Filters::DNS/@add_field = {}
[2023-04-22T22:50:51,365][DEBUG][logstash.filters.dns     ] config LogStash::Filters::DNS/@remove_field = []
[2023-04-22T22:50:51,366][DEBUG][logstash.filters.dns     ] config LogStash::Filters::DNS/@periodic_flush = false
[2023-04-22T22:50:51,366][DEBUG][logstash.filters.dns     ] config LogStash::Filters::DNS/@timeout = 0.5
[2023-04-22T22:50:51,366][DEBUG][logstash.filters.dns     ] config LogStash::Filters::DNS/@max_retries = 2
[2023-04-22T22:50:51,366][DEBUG][logstash.filters.dns     ] config LogStash::Filters::DNS/@failed_cache_size = 0
[2023-04-22T22:50:51,366][DEBUG][logstash.filters.dns     ] config LogStash::Filters::DNS/@failed_cache_ttl = 5
[2023-04-22T22:50:51,366][DEBUG][logstash.filters.dns     ] config LogStash::Filters::DNS/@tag_on_timeout = ["_dnstimeout"]
[2023-04-22T22:50:51,534][DEBUG][logstash.javapipeline    ] Starting pipeline {:pipeline_id=>"main"}
[2023-04-22T22:50:51,623][INFO ][logstash.javapipeline    ][main] Starting pipeline {:pipeline_id=>"main", "pipeline.workers"=>4, "pipeline.batch.size"=>125, "pipeline.batch.delay"=>50, "pipeline.max_inflight"=>500, "pipeline.sources"=>["/usr/share/logstash/pipeline/mypipeline.conf"], :thread=>"#<Thread:0x2486058b run>"}
[2023-04-22T22:50:52,261][INFO ][logstash.javapipeline    ][main] Pipeline Java execution initialization time {"seconds"=>0.63}
[2023-04-22T22:50:52,316][INFO ][logstash.javapipeline    ][main] Pipeline started {"pipeline.id"=>"main"}
[2023-04-22T22:50:52,440][INFO ][logstash.agent           ] Pipelines running {:count=>1, :running_pipelines=>[:main], :non_running_pipelines=>[]}
[2023-04-22T22:50:52,557][DEBUG][logstash.javapipeline    ][main] Shutdown waiting for worker thread {:pipeline_id=>"main", :thread=>"#<LogStash::WorkerLoopThread:0x7b81e378 run>"}
{
        "source" => {
            "ip" => "8.8.8.8",
        "domain" => "8.8.8.8"
    },
       "message" => "8.8.8.8",
      "sequence" => 0,
      "@version" => "1",
    "@timestamp" => 2023-04-22T20:50:52.420Z,
          "host" => "3493941a8650"
}
[2023-04-22T22:50:52,740][INFO ][logstash.javapipeline    ][main] Pipeline terminated {"pipeline.id"=>"main"}
[2023-04-22T22:50:52,986][INFO ][logstash.pipelinesregistry] Removed pipeline from registry successfully {:pipeline_id=>:main}
[2023-04-22T22:50:53,023][INFO ][logstash.runner          ] Logstash shut down.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.