Skip to content

Commit

Permalink
Use Resolver for dns resolution
Browse files Browse the repository at this point in the history
  • Loading branch information
dbutler-starry committed Mar 10, 2020
1 parent e734785 commit 4b17151
Show file tree
Hide file tree
Showing 2 changed files with 76 additions and 27 deletions.
66 changes: 42 additions & 24 deletions plugins/inputs/ping/ping.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ import (
// for unit test purposes (see ping_test.go)
type HostPinger func(binary string, timeout float64, args ...string) (string, error)

type HostResolver func(ctx context.Context, ipv6 bool, host string) (*net.IPAddr, error)

type IsCorrectNetwork func(ip net.IPAddr) bool

type Ping struct {
wg sync.WaitGroup

Expand Down Expand Up @@ -60,6 +64,9 @@ type Ping struct {
// host ping function
pingHost HostPinger

// resolve host function
resolveHost HostResolver

// listenAddr is the address associated with the interface defined.
listenAddr string
}
Expand Down Expand Up @@ -187,37 +194,47 @@ func hostPinger(binary string, timeout float64, args ...string) (string, error)
return string(out), err
}

func ResolveIP(ctx context.Context, network string, destination string) (*net.IPAddr, error) {
success := make(chan *net.IPAddr)
error := make(chan error)

go func() {
addrs, err := net.ResolveIPAddr(network, destination)
if err == nil {
success <- addrs
} else {
error <- err
func filterIPs(addrs []net.IPAddr, filterFunc IsCorrectNetwork) []net.IPAddr {
n := 0
for _, x := range addrs {
if filterFunc(x) {
addrs[n] = x
n++
}
}()
}
return addrs[:n]
}

func hostResolver(ctx context.Context, ipv6 bool, destination string) (*net.IPAddr, error) {
resolver := &net.Resolver{}
ips, err := resolver.LookupIPAddr(ctx, destination)

select {
case addrs := <-success:
return addrs, nil
case err := <-error:
if err != nil {
return nil, err
case <-ctx.Done():
return nil, errors.New("ResolveIp timeout")
}
}

func (p *Ping) pingToURLNative(destination string, acc telegraf.Accumulator) {
ctx := context.Background()
if ipv6 {
ips = filterIPs(ips, isV6)
} else {
ips = filterIPs(ips, isV4)
}

network := "ip4"
if p.IPv6 {
network = "ip6"
if len(ips) == 0 {
return nil, errors.New("Cannot resolve ip address")
}
return &ips[0], err
}

func isV4(ip net.IPAddr) bool {
return ip.IP.To4() != nil
}

func isV6(ip net.IPAddr) bool {
return !isV4(ip)
}

func (p *Ping) pingToURLNative(destination string, acc telegraf.Accumulator) {
ctx := context.Background()
interval := p.PingInterval
if interval < 0.2 {
interval = 0.2
Expand All @@ -237,7 +254,7 @@ func (p *Ping) pingToURLNative(destination string, acc telegraf.Accumulator) {
defer cancel()
}

host, err := ResolveIP(ctx, network, destination)
host, err := p.resolveHost(ctx, p.IPv6, destination)
if err != nil {
acc.AddFields(
"ping",
Expand Down Expand Up @@ -408,6 +425,7 @@ func init() {
inputs.Add("ping", func() telegraf.Input {
return &Ping{
pingHost: hostPinger,
resolveHost: hostResolver,
PingInterval: 1.0,
Count: 1,
Timeout: 1.0,
Expand Down
37 changes: 34 additions & 3 deletions plugins/inputs/ping/ping_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
package ping

import (
"context"
"errors"
"net"
"reflect"
"sort"
"testing"
Expand Down Expand Up @@ -340,6 +342,12 @@ func TestPingBinary(t *testing.T) {
acc.GatherError(p.Gather)
}

func mockHostResolver(ctx context.Context, ipv6 bool, host string) (*net.IPAddr, error) {
ipaddr := net.IPAddr{}
ipaddr.IP = net.IPv4(127, 0, 0, 1)
return &ipaddr, nil
}

// Test that Gather function works using native ping
func TestPingGatherNative(t *testing.T) {
if testing.Short() {
Expand All @@ -348,12 +356,35 @@ func TestPingGatherNative(t *testing.T) {

var acc testutil.Accumulator
p := Ping{
Urls: []string{"localhost", "127.0.0.2"},
Method: "native",
Count: 5,
Urls: []string{"localhost", "127.0.0.2"},
Method: "native",
Count: 5,
resolveHost: mockHostResolver,
}

assert.NoError(t, acc.GatherError(p.Gather))
assert.True(t, acc.HasPoint("ping", map[string]string{"url": "localhost"}, "packets_transmitted", 5))
assert.True(t, acc.HasPoint("ping", map[string]string{"url": "localhost"}, "packets_received", 5))
}

func mockHostResolverError(ctx context.Context, ipv6 bool, host string) (*net.IPAddr, error) {
return nil, errors.New("myMock error")
}

// Test failed DNS resolutions
func TestDNSLookupError(t *testing.T) {
if testing.Short() {
t.Skip("Skipping test due to permission requirements.")
}

var acc testutil.Accumulator
p := Ping{
Urls: []string{"localhost"},
Method: "native",
IPv6: false,
resolveHost: mockHostResolverError,
}

acc.GatherError(p.Gather)
assert.True(t, len(acc.Errors) > 0)
}

0 comments on commit 4b17151

Please sign in to comment.