github.com/netdata/go.d.plugin@v0.58.1/modules/ping/prober.go (about)

     1  // SPDX-License-Identifier: GPL-3.0-or-later
     2  
     3  package ping
     4  
     5  import (
     6  	"errors"
     7  	"fmt"
     8  	"net"
     9  	"time"
    10  
    11  	"github.com/netdata/go.d.plugin/logger"
    12  
    13  	probing "github.com/prometheus-community/pro-bing"
    14  )
    15  
    16  func newPingProber(conf pingProberConfig, log *logger.Logger) prober {
    17  	var source string
    18  	if conf.iface != "" {
    19  		if addr, err := getInterfaceIPAddress(conf.iface); err != nil {
    20  			log.Warningf("error getting interface '%s' IP address: %v", conf.iface, err)
    21  		} else {
    22  			log.Infof("interface '%s' IP address '%s', will use it as the source", conf.iface, addr)
    23  			source = addr
    24  		}
    25  	}
    26  
    27  	return &pingProber{
    28  		network:    conf.network,
    29  		privileged: conf.privileged,
    30  		packets:    conf.packets,
    31  		source:     source,
    32  		interval:   conf.interval,
    33  		deadline:   conf.deadline,
    34  		Logger:     log,
    35  	}
    36  }
    37  
    38  type pingProberConfig struct {
    39  	network    string
    40  	privileged bool
    41  	packets    int
    42  	iface      string
    43  	interval   time.Duration
    44  	deadline   time.Duration
    45  }
    46  
    47  type pingProber struct {
    48  	*logger.Logger
    49  
    50  	network    string
    51  	privileged bool
    52  	packets    int
    53  	source     string
    54  	interval   time.Duration
    55  	deadline   time.Duration
    56  }
    57  
    58  func (p *pingProber) ping(host string) (*probing.Statistics, error) {
    59  	pr := probing.New(host)
    60  
    61  	pr.SetNetwork(p.network)
    62  
    63  	if err := pr.Resolve(); err != nil {
    64  		return nil, fmt.Errorf("DNS lookup '%s' : %v", host, err)
    65  	}
    66  
    67  	pr.Source = p.source
    68  	pr.RecordRtts = false
    69  	pr.Interval = p.interval
    70  	pr.Count = p.packets
    71  	pr.Timeout = p.deadline
    72  	pr.SetPrivileged(p.privileged)
    73  	pr.SetLogger(nil)
    74  
    75  	if err := pr.Run(); err != nil {
    76  		return nil, fmt.Errorf("pinging host '%s' (ip %s): %v", pr.Addr(), pr.IPAddr(), err)
    77  	}
    78  
    79  	stats := pr.Statistics()
    80  
    81  	p.Debugf("ping stats for host '%s' (ip '%s'): %+v", pr.Addr(), pr.IPAddr(), stats)
    82  
    83  	return stats, nil
    84  }
    85  
    86  func getInterfaceIPAddress(ifaceName string) (ipaddr string, err error) {
    87  	iface, err := net.InterfaceByName(ifaceName)
    88  	if err != nil {
    89  		return "", err
    90  	}
    91  
    92  	addresses, err := iface.Addrs()
    93  	if err != nil {
    94  		return "", err
    95  	}
    96  
    97  	// FIXME: add IPv6 support
    98  	var v4Addr string
    99  	for _, addr := range addresses {
   100  		if ipnet, ok := addr.(*net.IPNet); ok && ipnet.IP.To4() != nil {
   101  			v4Addr = ipnet.IP.To4().String()
   102  			break
   103  		}
   104  	}
   105  
   106  	if v4Addr == "" {
   107  		return "", errors.New("ipv4 addresses not found")
   108  	}
   109  
   110  	return v4Addr, nil
   111  }