-
Notifications
You must be signed in to change notification settings - Fork 116
/
target.go
172 lines (141 loc) · 3.41 KB
/
target.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
// SPDX-License-Identifier: MIT
package main
import (
"context"
"fmt"
"net"
"strconv"
"sync"
"time"
mon "github.com/digineo/go-ping/monitor"
log "github.com/sirupsen/logrus"
)
// ipVersion represents the IP protocol version of an address
type ipVersion uint8
type target struct {
host string
addresses []net.IPAddr
delay time.Duration
resolver *net.Resolver
mutex sync.Mutex
}
type targets struct {
t []*target
mutex sync.RWMutex
}
func (t *targets) SetTargets(tar []*target) {
t.mutex.Lock()
defer t.mutex.Unlock()
t.t = tar
}
func (t *targets) Contains(tar *target) bool {
t.mutex.RLock()
defer t.mutex.RUnlock()
for _, ta := range t.t {
if ta.host == tar.host {
return true
}
}
return false
}
func (t *targets) Get(host string) *target {
t.mutex.RLock()
defer t.mutex.RUnlock()
for _, ta := range t.t {
if ta.host == host {
return ta
}
}
return nil
}
func (t *targets) Targets() []*target {
t.mutex.RLock()
defer t.mutex.RUnlock()
ret := make([]*target, len(t.t))
copy(ret, t.t)
return ret
}
type targetOpts struct {
disableIPv4 bool
disableIPv6 bool
}
const (
ipv4 ipVersion = 4
ipv6 ipVersion = 6
)
func (t *target) removeFromMonitor(monitor *mon.Monitor) {
for _, addr := range t.addresses {
monitor.RemoveTarget(t.nameForIP(addr))
}
}
func (t *target) addOrUpdateMonitor(monitor *mon.Monitor, opts targetOpts) error {
t.mutex.Lock()
defer t.mutex.Unlock()
addrs, err := t.resolver.LookupIPAddr(context.Background(), t.host)
if err != nil {
return fmt.Errorf("error resolving target '%s': %w", t.host, err)
}
var sanitizedAddrs []net.IPAddr
for _, addr := range addrs {
if getIPVersion(addr) == ipv6 && opts.disableIPv6 {
log.Infof("IPv6 disabled: skipping target for host %s (%v)", t.host, addr)
continue
}
if getIPVersion(addr) == ipv4 && opts.disableIPv4 {
log.Infof("IPv4 disabled: skipping target for host %s (%v)", t.host, addr)
continue
}
sanitizedAddrs = append(sanitizedAddrs, addr)
}
for _, addr := range sanitizedAddrs {
err := t.addIfNew(addr, monitor)
if err != nil {
return err
}
}
t.cleanUp(sanitizedAddrs, monitor)
t.addresses = sanitizedAddrs
return nil
}
func (t *target) addIfNew(addr net.IPAddr, monitor *mon.Monitor) error {
if isIPAddrInSlice(addr, t.addresses) {
return nil
}
return t.add(addr, monitor)
}
func (t *target) cleanUp(addr []net.IPAddr, monitor *mon.Monitor) {
for _, o := range t.addresses {
if !isIPAddrInSlice(o, addr) {
name := t.nameForIP(o)
log.Infof("removing target for host %s (%v)", t.host, o)
monitor.RemoveTarget(name)
}
}
}
func (t *target) add(addr net.IPAddr, monitor *mon.Monitor) error {
name := t.nameForIP(addr)
log.Infof("adding target for host %s (%v)", t.host, addr)
return monitor.AddTargetDelayed(name, addr, t.delay)
}
func (t *target) nameForIP(addr net.IPAddr) string {
return fmt.Sprintf("%s %s %s", t.host, addr.IP, getIPVersion(addr))
}
func isIPAddrInSlice(ipa net.IPAddr, slice []net.IPAddr) bool {
for _, x := range slice {
if x.IP.Equal(ipa.IP) {
return true
}
}
return false
}
// getIPVersion returns the version of IP protocol used for a given address
func getIPVersion(addr net.IPAddr) ipVersion {
if addr.IP.To4() == nil {
return ipv6
}
return ipv4
}
// String converts ipVersion to a string represention of the IP version used (i.e. "4" or "6")
func (ipv ipVersion) String() string {
return strconv.Itoa(int(ipv))
}