master
go 97 lines 2.06 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 package portcheck
4
5 import (
6 "errors"
7 "fmt"
8 "net"
9 "strconv"
10 "strings"
11 "sync"
12 "time"
13 )
14
15 func (c *Collector) collect() (map[string]int64, error) {
16 wg := &sync.WaitGroup{}
17
18 for _, port := range c.tcpPorts {
19 wg.Add(1)
20 port := port
21 go func() { defer wg.Done(); c.checkTCPPort(port) }()
22 }
23
24 if c.doUdpPorts {
25 for _, port := range c.udpPorts {
26 wg.Add(1)
27 port := port
28 go func() { defer wg.Done(); c.checkUDPPort(port) }()
29 }
30 }
31
32 wg.Wait()
33
34 mx := make(map[string]int64)
35
36 now := time.Now()
37
38 for _, p := range c.tcpPorts {
39 if !c.seenTcpPorts[p.number] {
40 c.seenTcpPorts[p.number] = true
41 c.addTCPPortCharts(p)
42 }
43
44 px := fmt.Sprintf("tcp_port_%d_", p.number)
45
46 mx[px+"current_state_duration"] = int64(now.Sub(p.statusChangeTs).Seconds())
47 mx[px+"latency"] = int64(p.latency)
48 mx[px+tcpPortCheckStateSuccess] = 0
49 mx[px+tcpPortCheckStateTimeout] = 0
50 mx[px+tcpPortCheckStateFailed] = 0
51 mx[px+p.status] = 1
52 }
53
54 if c.doUdpPorts {
55 for _, p := range c.udpPorts {
56 if p.err != nil {
57 if isListenOpNotPermittedError(p.err) {
58 c.doUdpPorts = false
59 break
60 }
61 continue
62 }
63
64 if !c.seenUdpPorts[p.number] {
65 c.seenUdpPorts[p.number] = true
66 c.addUDPPortCharts(p)
67 }
68
69 px := fmt.Sprintf("udp_port_%d_", p.number)
70
71 mx[px+"current_status_duration"] = int64(now.Sub(p.statusChangeTs).Seconds())
72 mx[px+udpPortCheckStateOpenFiltered] = 0
73 mx[px+udpPortCheckStateClosed] = 0
74 mx[px+p.status] = 1
75 }
76 }
77
78 return mx, nil
79 }
80
81 func (c *Collector) address(port int) string {
82 // net.JoinHostPort expects literal IPv6 address, it adds []
83 host := strings.Trim(c.Host, "[]")
84 return net.JoinHostPort(host, strconv.Itoa(port))
85 }
86
87 func durationToMs(duration time.Duration) int {
88 return int(duration) / (int(time.Millisecond) / int(time.Nanosecond))
89 }
90
91 func isListenOpNotPermittedError(err error) bool {
92 // icmp.ListenPacket failed (socket: operation not permitted)
93 var opErr *net.OpError
94 return errors.As(err, &opErr) &&
95 opErr.Op == "listen" &&
96 strings.Contains(opErr.Error(), "operation not permitted")
97 }