Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a reverse dns processor #7927

Merged
merged 5 commits into from
Aug 21, 2018

Conversation

andrewkroh
Copy link
Member

@andrewkroh andrewkroh commented Aug 9, 2018

Package dns implements a processor that can perform DNS lookups by sending
a DNS request over UDP to a recursive nameserver. Each instance of the
processor is independent (no shared cache) so it's best to only define one
instance of the processor.

It caches DNS results in memory and honors the record's TTL. It also caches
failures for the configured failure TTL.

This filter, like all filters, only processes 1 event at a time, so the use
of this plugin can significantly slow down your pipeline's throughput if you
have a high latency network. By way of example, if each DNS lookup takes 2
milliseconds, the maximum throughput you can achieve with a single filter
worker is 500 events per second (1000 milliseconds / 2 milliseconds).

Simple config example:

processors:
- dns:
    type: reverse
    fields:
      source.ip: source.hostname
      destination.ip: destination.hostname

Full config example:

processors:
- dns:
    type: reverse
    action: append
    fields:
      server.ip: server.hostname
      client.ip: client.hostname
    success_cache:
      capacity.initial: 1000
      capacity.max: 10000
    failure_cache:
      capacity.initial: 1000
      capacity.max: 10000
      ttl: 1m
    nameservers: ['192.0.2.1', '203.0.113.1']
    timeout: 500ms
    tag_on_failure: [_dns_reverse_lookup_failed]

Closes #7770

@andrewkroh andrewkroh added in progress Pull request is currently in progress. review libbeat :Processors labels Aug 9, 2018
@ruflin
Copy link
Contributor

ruflin commented Aug 9, 2018

This is great. @andrewvc This could also be interesting for heartbeat.

@andrewkroh andrewkroh removed the in progress Pull request is currently in progress. label Aug 9, 2018
@andrewkroh
Copy link
Member Author

Other than needing documentation added this is ready for review. I wanted to wait on docs in case there are changes to the config.

@andrewvc andrewvc self-requested a review August 10, 2018 19:31
Copy link
Contributor

@andrewvc andrewvc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Started my review, looking very nice, very clean and readable.

Left a partial review of the cache code. Will continue tomorrow with the rest.


func (c *ptrCache) evict() {
var key string
for k := range c.data {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could use a comment, maybe it's because I'm a go noob, I'd appreciate a comment on this function:

// Evict removes a random key from the cache

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, not something that belongs in an initial impl, but it might be nice to add a real LRU at some point.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree that a better cache implementation would be nice. I tested a few different cache libs and none of them seemed all that great or efficient. So opted to keep is simple (this was also the approach I found in the coredns cache).

In addition to improving on the algorithm, optimizing for the Go garbage collector would be nice too. When you get above 100k objects in a map the GC times start to grow. I looked at the bigcache which addresses this issue, and it worked very well, but it doesn't implement LRU.

But let's see how this gets used before optimizing. I plan to mark this as beta in the docs for the first release.


// Logger logs debug messages.
type Logger interface {
Debugw(msg string, keysAndValues ...interface{})
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we define a new type vs. using Logger from libbeat/logp?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wanted use an interface in my method signatures rather than accepting a concrete type to decouple the implementation from the choice of logging libraries (facilitate reuse). But then I later injected a *monitoring.Registry so it's pretty tightly couple to libbeat stuff.

But now I have done some refactoring and it no longer uses a logger (instead it returns detailed errors).

}
c.stats.Miss.Inc()

ptr, err = c.resolver.LookupPTR(ip)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might be nice to have a stat for actual DNS queries sent to help users determine if their cache size is appropriate. They could check if increasing the cache size diminishes the number of queries sent.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't the number of cache misses be the metric to look when doing this testing? You'd see if the miss number decreased, right?

Additionally there are metrics reported by the resolver that could indicate the total number of lookups if you summed success and failures across each DNS server.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, cache misses is an even better statistic.

I think I missed that we report those stats already, but it does make sense that cache misses would be a good stat.

c := &PTRLookupCache{
success: &ptrCache{
data: make(map[string]ptrRecord, conf.SuccessCache.InitialCapacity),
maxSize: max(100, max(conf.SuccessCache.InitialCapacity, conf.SuccessCache.MaxCapacity)),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This behavior is a little weird. It essentially says you can't set a cache size < 100. I'm not so certain we want to get into the business of overriding user preferences silently. Shouldn't we fail to start and log a warning?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree. I'll change this to do validation that the maxSize is >0.

delete(c.data, key)
}

func (c *failureCache) get(now time.Time, key string) error {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My read here is that the tradeoff is between:

  1. Dual cache impl, one per type
  2. 'Generic' cache impl, with entries of (key,success|failure) (probably using two pointers, only one of which is non-null

where the first option is more memory efficient at the cost of duplicated code, while the second is a little less memory efficient but more DRY approach (though there is some extra complexity in methods since they have to determine the type they're working with).

I'm neutral on the choice. It's a tradeoff, and the difference in terms of both isn't very large since 1. the code is simple. 2. finding the hash code of a short string is fast, but I thought I'd just bring this up because I'm curious if there's general guidance on this issue.

In previous PL's I've used professionally the answer is generics. Not having them forces this choice, so I'd like to hear from more experience go programmers how this is handled.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I chose what I thought was a more memory efficient implementation (1) at the cost of some duplication. This was mainly because there could be many of these items in memory, and secondly because the code was simple.

I don't have any general advice 🤷‍♂️ other than to weigh the pros and cons for the choice like you have done here.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense, thanks for the feedback.

@webmat
Copy link
Contributor

webmat commented Aug 13, 2018

Can this new processor be used with when? This will be important, in order to help preserve throughput, if users know they only want to do reverse DNS on a subset of their traffic (only private, or only public).

}
}

return nil, &dnsError{"no PTR record was found the response"}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/the/in the/

s.Handler = h
go s.ActivateAndServe()
return s.Shutdown, s.PacketConn.LocalAddr().String(), err

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove this newline.

Copy link
Contributor

@andrewvc andrewvc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Excellent impl, left some notes for discussion.

This will need more asciidoc in processors_using.asciidoc etc. before it is mergeable of course.

Worked well when tested manually at the CLI:

❰andrewcholakian❙~/golang/src/github.com/elastic/beats/filebeat(git✱feature/libbeat/dns-processor)❱✔≻ ./filebeat
8.8.8.8
{
  "@timestamp": "2018-08-13T16:20:20.782Z",
  "@metadata": {
    "beat": "filebeat",
    "type": "doc",
    "version": "7.0.0-alpha1"
  },
  "prospector": {
    "type": "stdin"
  },
  "input": {
    "type": "stdin"
  },
  "beat": {
    "version": "7.0.0-alpha1",
    "name": "MacBook-Pro.scoutworkshop.com",
    "hostname": "MacBook-Pro.scoutworkshop.com"
  },
  "host": {
    "name": "MacBook-Pro.scoutworkshop.com"
  },
  "resolved": "google-public-dns-a.google.com",
  "message": "8.8.8.8",
  "source": "",
  "offset": 0
}
1.2.3
{
  "@timestamp": "2018-08-13T16:20:27.705Z",
  "@metadata": {
    "beat": "filebeat",
    "type": "doc",
    "version": "7.0.0-alpha1"
  },
  "beat": {
    "name": "MacBook-Pro.scoutworkshop.com",
    "hostname": "MacBook-Pro.scoutworkshop.com",
    "version": "7.0.0-alpha1"
  },
  "host": {
    "name": "MacBook-Pro.scoutworkshop.com"
  },
  "source": "",
  "offset": 0,
  "message": "1.2.3",
  "prospector": {
    "type": "stdin"
  },
  "input": {
    "type": "stdin"
  }
}

vs.OnFloat(w.h.StdDev())
vs.OnKey("median")
vs.OnFloat(ps[0])
vs.OnKey("p75")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are we returning these constant values? I assume this was intended to be the derived values at those percentiles from the actual histogram data?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The percentiles are derived from samples stored in the histogram. The p75 is the key name used to hold the 75th percentile which is obtained up on line 106 and stored in ps, the percentiles slice.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, I misread that code. Thanks for the clarification.

ptr, err = c.resolver.LookupPTR(ip)
if err != nil {
c.log.Debugw("Reverse DNS lookup failed.", "error", err, "ip", ip)
if _, cacheable := err.(*dnsError); cacheable {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Timeouts with DNS enrichment are a tricky problem. I think we want timeouts to be cacheable by default. Even a small number of timeouts can cause a large number of real-world problems. See logstash-plugins/logstash-filter-dns#13 for what we found in the field with Logstash.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point. I think the simplest answer is to cache all failures. I will do that here.

I think a future improvement would be to have the resolver keep state information about each nameserver. If a server is non-responsive it could be taken out of the rotation temporarily. And if one server is much faster than another then it could be preferred.

@@ -73,6 +73,7 @@ https://github.com/elastic/beats/compare/v6.4.0...master[Check the HEAD diff]
internal monitoring data. {issue}7807[7807]
- Allow for cloud-id to specify a custom port. This makes cloud-id work in ECE contexts. {pull}7887[7887]
- Add support to grow or shrink an existing spool file between restarts. {pull}7859[7859]
- Add DNS processor with support for performing reverse lookups on IP addresses. {issue}7770[7770]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thoughts on forward lookups? Wouldn't have to be in this PR, but those are really useful for log lines where a hostname is specified, but an IP is not.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can see this being useful for certain use cases where the forward lookup (A or AAAA) has a deterministic response. I could see this being used to resolve hostnames from syslog events against your internal DNS. I don't plan to add this now but the config takes this into account with the lookup type field.

Someone might also want to lookup TXT records, where the query is derived from a field value. For example a lookup like %{[source][ip]}.origin.asn.cymru.com (for ip-to-asn lookup), but this is probably best suited to a centralized enrichment process.

for _, l := range c.Lookup {
l.Type = strings.ToLower(l.Type)
switch l.Type {
case "reverse", "ptr":
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we really want two names for the same thing? Since there's no backward compatibility requirement here maybe we could just pick one and go with it.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll go with only reverse.

return nil
}

old, err := event.PutValue(target, name.Host)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a bit weird to read, where we overwrite the old value, but retain it, then, optionally overwrite that later with an array if an append behavior is specified.

There are lots of ways to implement this (maybe even a func pointer passed in on startup), but I suspect perf-wise they are all a wash.

It feels like a higher level switch statement would be the most clear, we need the conditional branch regardless, and I think it's the most defensive, so something like:

switch action {
case ActionReplace:
    ...
case ActionAppend:
   ...
default:
    panic("Unexpected action type encountered. This should never happen")
}

"github.com/elastic/beats/libbeat/monitoring"
)

const (
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These consts are used in dns_test.go as well. Would be nice to extract to constants_test.go or similar IMHO.

//
// This filter, like all filters, only processes 1 event at a time, so the use
// of this plugin can significantly slow down your pipeline’s throughput if you
// have a high latency network. By way of example, if each DNS lookup takes 2
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe make a note about caching and perf? The calculation here would be heavily affected by that.


// Try the nameservers until we get a response.
var rtnErr error
for _, server := range res.servers {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might be nice to alternate requests among servers instead of hitting the first one preferentially.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Based on man /etc/resolv.conf I think honoring the order in which the user listed the servers is the way to go.

If there are multiple servers, the resolver library queries them in the order listed.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, well, then nevermind!

)

// Config defines the configuration options for the DNS processor.
type Config struct {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a very complete config structure, but its quite clunky to write.

processors:
- dns:
    lookup:
      - type: reverse
        fields:
          message: resolved

This could be improved IMHO. Maybe to:

dns:
  type: reverse
  fields:
    message: resolved

If you need multiple types of lookup you'd use different processors. An added bonus here is that you'd separate caches by type (forward vs. reverse).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SGTM. I'll make the changes.


name, err := p.resolver.LookupPTR(maybeIP)
if err != nil {
return nil
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might be nice to actually set an error field. I think most users are expecting this to always do something. If there's a bad record that goes in (say 1.shoe.2), the user might want to find those records in ES. They might be able to do it searching for a missing field, but it would be nicer if we could just tag the event with a user-definable tag.

The only alternative would be parsing the log output of the beat to check for errors.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added a tag_on_failure configuration option.

Package dns implements a processor that can perform DNS lookups by sending
a DNS request over UDP to a recursive nameserver. Each instance of the
processor is independent (no shared cache) so it's best to only define one
instance of the processor.

It caches DNS results in memory and honors the record's TTL. It also caches
failures for the configured failure TTL.

This filter, like all filters, only processes 1 event at a time, so the use
of this plugin can significantly slow down your pipeline’s throughput if you
have a high latency network. By way of example, if each DNS lookup takes 2
milliseconds, the maximum throughput you can achieve with a single filter
worker is 500 events per second (1000 milliseconds / 2 milliseconds).

Simple config example:
```
processors:
- dns.lookup:
    - type: reverse
      action: append
      fields:
        ip: server.hostname
        client_ip: client.hostname
```

Full config example:
```
processors:
- dns:
    lookup:
      - type: reverse
        action: append
        fields:
          ip: hostname
          client_ip: client_hostname
    timeout: 500ms
    success_cache:
      capacity.initial: 1000
      capacity.max: 10000
    failure_cache:
      capacity.initial: 1000
      capacity.max: 10000
      ttl: 1m
    nameservers: ['1.1.1.1', '8.8.8.8']
```

Closes elastic#7770
@andrewkroh andrewkroh force-pushed the feature/libbeat/dns-processor branch from 9107649 to 2e56736 Compare August 17, 2018 01:36
return nil
}

func (c *CacheConfig) Validate() error {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

exported method CacheConfig.Validate should have comment or be unexported

Copy link
Member Author

@andrewkroh andrewkroh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the review @andrewvc . Your feedback was very helpful.

I've made the requested changes and also added documentation. Please have another look.

@@ -73,6 +73,7 @@ https://github.com/elastic/beats/compare/v6.4.0...master[Check the HEAD diff]
internal monitoring data. {issue}7807[7807]
- Allow for cloud-id to specify a custom port. This makes cloud-id work in ECE contexts. {pull}7887[7887]
- Add support to grow or shrink an existing spool file between restarts. {pull}7859[7859]
- Add DNS processor with support for performing reverse lookups on IP addresses. {issue}7770[7770]
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can see this being useful for certain use cases where the forward lookup (A or AAAA) has a deterministic response. I could see this being used to resolve hostnames from syslog events against your internal DNS. I don't plan to add this now but the config takes this into account with the lookup type field.

Someone might also want to lookup TXT records, where the query is derived from a field value. For example a lookup like %{[source][ip]}.origin.asn.cymru.com (for ip-to-asn lookup), but this is probably best suited to a centralized enrichment process.

vs.OnFloat(w.h.StdDev())
vs.OnKey("median")
vs.OnFloat(ps[0])
vs.OnKey("p75")
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The percentiles are derived from samples stored in the histogram. The p75 is the key name used to hold the 75th percentile which is obtained up on line 106 and stored in ps, the percentiles slice.


func (c *ptrCache) evict() {
var key string
for k := range c.data {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree that a better cache implementation would be nice. I tested a few different cache libs and none of them seemed all that great or efficient. So opted to keep is simple (this was also the approach I found in the coredns cache).

In addition to improving on the algorithm, optimizing for the Go garbage collector would be nice too. When you get above 100k objects in a map the GC times start to grow. I looked at the bigcache which addresses this issue, and it worked very well, but it doesn't implement LRU.

But let's see how this gets used before optimizing. I plan to mark this as beta in the docs for the first release.

delete(c.data, key)
}

func (c *failureCache) get(now time.Time, key string) error {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I chose what I thought was a more memory efficient implementation (1) at the cost of some duplication. This was mainly because there could be many of these items in memory, and secondly because the code was simple.

I don't have any general advice 🤷‍♂️ other than to weigh the pros and cons for the choice like you have done here.


// Logger logs debug messages.
type Logger interface {
Debugw(msg string, keysAndValues ...interface{})
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wanted use an interface in my method signatures rather than accepting a concrete type to decouple the implementation from the choice of logging libraries (facilitate reuse). But then I later injected a *monitoring.Registry so it's pretty tightly couple to libbeat stuff.

But now I have done some refactoring and it no longer uses a logger (instead it returns detailed errors).

ptr, err = c.resolver.LookupPTR(ip)
if err != nil {
c.log.Debugw("Reverse DNS lookup failed.", "error", err, "ip", ip)
if _, cacheable := err.(*dnsError); cacheable {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point. I think the simplest answer is to cache all failures. I will do that here.

I think a future improvement would be to have the resolver keep state information about each nameserver. If a server is non-responsive it could be taken out of the rotation temporarily. And if one server is much faster than another then it could be preferred.

)

// Config defines the configuration options for the DNS processor.
type Config struct {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SGTM. I'll make the changes.

for _, l := range c.Lookup {
l.Type = strings.ToLower(l.Type)
switch l.Type {
case "reverse", "ptr":
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll go with only reverse.


name, err := p.resolver.LookupPTR(maybeIP)
if err != nil {
return nil
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added a tag_on_failure configuration option.


// Try the nameservers until we get a response.
var rtnErr error
for _, server := range res.servers {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Based on man /etc/resolv.conf I think honoring the order in which the user listed the servers is the way to go.

If there are multiple servers, the resolver library queries them in the order listed.

Copy link
Contributor

@andrewvc andrewvc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changes look great. LGTM!

@andrewvc
Copy link
Contributor

Waiting on a likely unrelated travis ci failure, respinning

@andrewvc andrewvc merged commit 3b89051 into elastic:master Aug 21, 2018
@andrewkroh andrewkroh added the needs_backport PR is waiting to be backported to other branches. label Aug 29, 2018
@andrewkroh andrewkroh removed the needs_backport PR is waiting to be backported to other branches. label Aug 29, 2018
andrewkroh added a commit to andrewkroh/beats that referenced this pull request Sep 17, 2018
Package dns implements a processor that can perform DNS lookups by sending
a DNS request over UDP to a recursive nameserver. Each instance of the
processor is independent (no shared cache) so it's best to only define one
instance of the processor.

It caches DNS results in memory and honors the record's TTL. It also caches
failures for the configured failure TTL.

This filter, like all filters, only processes 1 event at a time, so the use
of this plugin can significantly slow down your pipeline’s throughput if you
have a high latency network. By way of example, if each DNS lookup takes 2
milliseconds, the maximum throughput you can achieve with a single filter
worker is 500 events per second (1000 milliseconds / 2 milliseconds).

Simple config example:
```
processors:
- dns:
    - type: reverse
      action: append
      fields:
        ip: server.hostname
        client_ip: client.hostname
```

Full config example:
```
processors:
- dns:
    - type: reverse
      action: append
      fields:
        ip: hostname
        client_ip: client_hostname
    timeout: 500ms
    success_cache:
      capacity.initial: 1000
      capacity.max: 10000
    failure_cache:
      capacity.initial: 1000
      capacity.max: 10000
      ttl: 1m
    nameservers: ['1.1.1.1', '8.8.8.8']
```

Closes elastic#7770

This also updates golang/x/net to let us build correctly on netbsd/arm, which was failing with some of the new includes this requires.

(cherry picked from commit 3b89051)
andrewkroh added a commit that referenced this pull request Sep 17, 2018
Package dns implements a processor that can perform DNS lookups by sending
a DNS request over UDP to a recursive nameserver. Each instance of the
processor is independent (no shared cache) so it's best to only define one
instance of the processor.

It caches DNS results in memory and honors the record's TTL. It also caches
failures for the configured failure TTL.

This filter, like all filters, only processes 1 event at a time, so the use
of this plugin can significantly slow down your pipeline’s throughput if you
have a high latency network. By way of example, if each DNS lookup takes 2
milliseconds, the maximum throughput you can achieve with a single filter
worker is 500 events per second (1000 milliseconds / 2 milliseconds).

Simple config example:
```
processors:
- dns:
    - type: reverse
      action: append
      fields:
        ip: server.hostname
        client_ip: client.hostname
```

Full config example:
```
processors:
- dns:
    - type: reverse
      action: append
      fields:
        ip: hostname
        client_ip: client_hostname
    timeout: 500ms
    success_cache:
      capacity.initial: 1000
      capacity.max: 10000
    failure_cache:
      capacity.initial: 1000
      capacity.max: 10000
      ttl: 1m
    nameservers: ['1.1.1.1', '8.8.8.8']
```

Closes #7770

This also updates golang/x/net to let us build correctly on netbsd/arm, which was failing with some of the new includes this requires.

(cherry picked from commit 3b89051)
@andrewkroh andrewkroh deleted the feature/libbeat/dns-processor branch November 8, 2018 20:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants