firehol/netdata

View on GitHub
src/go/plugin/go.d/modules/ping/prober.go

Summary

Maintainability
A
0 mins
Test Coverage
// SPDX-License-Identifier: GPL-3.0-or-later

package ping

import (
    "errors"
    "fmt"
    "net"
    "time"

    "github.com/netdata/netdata/go/plugins/logger"

    probing "github.com/prometheus-community/pro-bing"
)

func newPingProber(conf pingProberConfig, log *logger.Logger) prober {
    var source string
    if conf.iface != "" {
        if addr, err := getInterfaceIPAddress(conf.iface); err != nil {
            log.Warningf("error getting interface '%s' IP address: %v", conf.iface, err)
        } else {
            log.Infof("interface '%s' IP address '%s', will use it as the source", conf.iface, addr)
            source = addr
        }
    }

    return &pingProber{
        network:    conf.network,
        privileged: conf.privileged,
        packets:    conf.packets,
        source:     source,
        interval:   conf.interval,
        deadline:   conf.deadline,
        Logger:     log,
    }
}

type pingProberConfig struct {
    network    string
    privileged bool
    packets    int
    iface      string
    interval   time.Duration
    deadline   time.Duration
}

type pingProber struct {
    *logger.Logger

    network    string
    privileged bool
    packets    int
    source     string
    interval   time.Duration
    deadline   time.Duration
}

func (p *pingProber) ping(host string) (*probing.Statistics, error) {
    pr := probing.New(host)

    pr.SetNetwork(p.network)

    if err := pr.Resolve(); err != nil {
        return nil, fmt.Errorf("DNS lookup '%s' : %v", host, err)
    }

    pr.Source = p.source
    pr.RecordRtts = false
    pr.Interval = p.interval
    pr.Count = p.packets
    pr.Timeout = p.deadline
    pr.SetPrivileged(p.privileged)
    pr.SetLogger(nil)

    if err := pr.Run(); err != nil {
        return nil, fmt.Errorf("pinging host '%s' (ip %s): %v", pr.Addr(), pr.IPAddr(), err)
    }

    stats := pr.Statistics()

    p.Debugf("ping stats for host '%s' (ip '%s'): %+v", pr.Addr(), pr.IPAddr(), stats)

    return stats, nil
}

func getInterfaceIPAddress(ifaceName string) (ipaddr string, err error) {
    iface, err := net.InterfaceByName(ifaceName)
    if err != nil {
        return "", err
    }

    addresses, err := iface.Addrs()
    if err != nil {
        return "", err
    }

    // FIXME: add IPv6 support
    var v4Addr string
    for _, addr := range addresses {
        if ipnet, ok := addr.(*net.IPNet); ok && ipnet.IP.To4() != nil {
            v4Addr = ipnet.IP.To4().String()
            break
        }
    }

    if v4Addr == "" {
        return "", errors.New("ipv4 addresses not found")
    }

    return v4Addr, nil
}