@cryptotaxi247 / netdata-1 / commits / 288d311af

go.d: sd local-listeners: discover /proc/net/tcp6 only apps (#17252)

Ilya Mashchenko committed Mar 25, 2024 at 21:34 UTC 288d311afdf3b9f7e4c0fcc5eb82d4031a4b609c
4 files changed +78 -68
src/go/collectors/go.d.plugin/agent/discovery/sd/discoverer/netlisteners/netlisteners.go
+50 -26
@@ -13,6 +13,8 @@ import (
13 "os"
14 "os/exec"
15 "path/filepath"
16 + "sort"
17 + "strconv"
18 "strings"
19 "time"
20
@@ -183,8 +185,12 @@ func (d *Discoverer) processTargets(tgts []model.Target) []model.TargetGroup {
185 }
186
187 func (d *Discoverer) parseLocalListeners(bs []byte) ([]model.Target, error) {
186 - var tgts []model.Target
187 - set := make(map[string]bool)
188 + const (
189 + local4 = "127.0.0.1"
190 + local6 = "::1"
191 + )
192 +
193 + var targets []target
194 sc := bufio.NewScanner(bytes.NewReader(bs))
195
196 for sc.Scan() {
@@ -207,11 +213,6 @@ func (d *Discoverer) parseLocalListeners(bs []byte) ([]model.Target, error) {
213 Cmdline: parts[3],
214 }
215
210 - const (
211 - local4 = "127.0.0.1"
212 - local6 = "::1"
213 - )
214 -
216 if tgt.IPAddress == "0.0.0.0" || strings.HasPrefix(tgt.IPAddress, "127") {
217 tgt.IPAddress = local4
218 } else if tgt.IPAddress == "::" {
@@ -220,21 +221,6 @@ func (d *Discoverer) parseLocalListeners(bs []byte) ([]model.Target, error) {
221
222 tgt.Address = net.JoinHostPort(tgt.IPAddress, tgt.Port)
223
223 - key := fmt.Sprintf("%s:%s", tgt.Protocol, tgt.Address)
224 - var keyLocal string
225 - if strings.HasSuffix(tgt.Protocol, "6") {
226 - keyLocal = fmt.Sprintf("%s:%s", tgt.Protocol, net.JoinHostPort(local6, tgt.Port))
227 - } else {
228 - keyLocal = fmt.Sprintf("%s:%s", tgt.Protocol, net.JoinHostPort(local4, tgt.Port))
229 - }
230 -
231 - // Filter targets that accept conns on any (0.0.0.0) and additionally on each individual network interface (a.b.c.d).
232 - // Create a target only for localhost. Assumption: any address always goes first.
233 - if set[key] || set[keyLocal] {
234 - continue
235 - }
236 - set[key] = true
237 -
224 hash, err := calcHash(tgt)
225 if err != nil {
226 continue
@@ -243,10 +229,49 @@ func (d *Discoverer) parseLocalListeners(bs []byte) ([]model.Target, error) {
229 tgt.hash = hash
230 tgt.Tags().Merge(d.Tags())
231
246 - tgts = append(tgts, &tgt)
232 + targets = append(targets, tgt)
233 + }
234 +
235 + // order: TCP, TCP6, UDP, UDP6
236 + sort.Slice(targets, func(i, j int) bool {
237 + tgt1, tgt2 := targets[i], targets[j]
238 + if tgt1.Protocol != tgt2.Protocol {
239 + return tgt1.Protocol < tgt2.Protocol
240 + }
241 +
242 + p1, _ := strconv.Atoi(targets[i].Port)
243 + p2, _ := strconv.Atoi(targets[j].Port)
244 + if p1 != p2 {
245 + return p1 < p2
246 + }
247 +
248 + return tgt1.IPAddress == local4 || tgt1.IPAddress == local6
249 + })
250 +
251 + seen := make(map[string]bool)
252 + tgts := make([]model.Target, len(targets))
253 + var n int
254 +
255 + for _, tgt := range targets {
256 + tgt := tgt
257 +
258 + proto := strings.TrimSuffix(tgt.Protocol, "6")
259 + key := tgt.Protocol + ":" + tgt.Address
260 + keyLocal4 := proto + ":" + net.JoinHostPort(local4, tgt.Port)
261 + keyLocal6 := proto + "6:" + net.JoinHostPort(local6, tgt.Port)
262 +
263 + // Filter targets that accept conns on any (0.0.0.0) and additionally on each individual network interface (a.b.c.d).
264 + // Create a target only for localhost. Assumption: any address always goes first.
265 + if seen[key] || seen[keyLocal4] || seen[keyLocal6] {
266 + continue
267 + }
268 + seen[key] = true
269 +
270 + tgts[n] = &tgt
271 + n++
272 }
273
249 - return tgts, nil
274 + return tgts[:n], nil
275 }
276
277 type localListenersExec struct {
@@ -258,11 +283,10 @@ func (e *localListenersExec) discover(ctx context.Context) ([]byte, error) {
283 execCtx, cancel := context.WithTimeout(ctx, e.timeout)
284 defer cancel()
285
261 - // TCPv4 and UPDv4 sockets in LISTEN state
286 + // TCPv4/6 and UPDv4 sockets in LISTEN state
287 // https://github.com/netdata/netdata/blob/master/src/collectors/plugins.d/local_listeners.c
288 args := []string{
289 "no-udp6",
265 - "no-tcp6",
290 "no-local",
291 "no-inbound",
292 "no-outbound",
src/go/collectors/go.d.plugin/agent/discovery/sd/discoverer/netlisteners/netlisteners_test.go
+16 -30
@@ -21,6 +21,8 @@ func TestDiscoverer_Discover(t *testing.T) {
21 cli.addListener("TCP|0.0.0.0|8125|/opt/netdata/usr/sbin/netdata -P /run/netdata/netdata.pid -D")
22 cli.addListener("TCP|192.0.2.1|8125|/opt/netdata/usr/sbin/netdata -P /run/netdata/netdata.pid -D")
23 cli.addListener("UDP|127.0.0.1|53768|/opt/netdata/usr/libexec/netdata/plugins.d/go.d.plugin 1")
24 + cli.addListener("TCP6|::|80|/usr/sbin/apache2 -k start")
25 + cli.addListener("TCP|0.0.0.0|80|/usr/sbin/apache2 -k start")
26 time.Sleep(interval * 2)
27 },
28 wantGroups: []model.TargetGroup{&targetGroup{
@@ -28,20 +30,12 @@ func TestDiscoverer_Discover(t *testing.T) {
30 source: "discoverer=net_listeners,host=localhost",
31 targets: []model.Target{
32 withHash(&target{
31 - Protocol: "UDP6",
32 - IPAddress: "::1",
33 - Port: "8125",
34 - Address: "[::1]:8125",
35 - Comm: "netdata",
36 - Cmdline: "/opt/netdata/usr/sbin/netdata -P /run/netdata/netdata.pid -D",
37 - }),
38 - withHash(&target{
39 - Protocol: "TCP6",
40 - IPAddress: "::1",
41 - Port: "8125",
42 - Address: "[::1]:8125",
43 - Comm: "netdata",
44 - Cmdline: "/opt/netdata/usr/sbin/netdata -P /run/netdata/netdata.pid -D",
33 + Protocol: "TCP",
34 + IPAddress: "127.0.0.1",
35 + Port: "80",
36 + Address: "127.0.0.1:80",
37 + Comm: "apache2",
38 + Cmdline: "/usr/sbin/apache2 -k start",
39 }),
40 withHash(&target{
41 Protocol: "TCP",
@@ -59,6 +53,14 @@ func TestDiscoverer_Discover(t *testing.T) {
53 Comm: "go.d.plugin",
54 Cmdline: "/opt/netdata/usr/libexec/netdata/plugins.d/go.d.plugin 1",
55 }),
56 + withHash(&target{
57 + Protocol: "UDP6",
58 + IPAddress: "::1",
59 + Port: "8125",
60 + Address: "[::1]:8125",
61 + Comm: "netdata",
62 + Cmdline: "/opt/netdata/usr/sbin/netdata -P /run/netdata/netdata.pid -D",
63 + }),
64 },
65 }},
66 },
@@ -85,14 +87,6 @@ func TestDiscoverer_Discover(t *testing.T) {
87 Comm: "netdata",
88 Cmdline: "/opt/netdata/usr/sbin/netdata -P /run/netdata/netdata.pid -D",
89 }),
88 - withHash(&target{
89 - Protocol: "TCP6",
90 - IPAddress: "::1",
91 - Port: "8125",
92 - Address: "[::1]:8125",
93 - Comm: "netdata",
94 - Cmdline: "/opt/netdata/usr/sbin/netdata -P /run/netdata/netdata.pid -D",
95 - }),
90 withHash(&target{
91 Protocol: "TCP",
92 IPAddress: "127.0.0.1",
@@ -127,14 +121,6 @@ func TestDiscoverer_Discover(t *testing.T) {
121 provider: "sd:net_listeners",
122 source: "discoverer=net_listeners,host=localhost",
123 targets: []model.Target{
130 - withHash(&target{
131 - Protocol: "TCP6",
132 - IPAddress: "::1",
133 - Port: "8125",
134 - Address: "[::1]:8125",
135 - Comm: "netdata",
136 - Cmdline: "/opt/netdata/usr/sbin/netdata -P /run/netdata/netdata.pid -D",
137 - }),
124 withHash(&target{
125 Protocol: "TCP",
126 IPAddress: "127.0.0.1",
src/go/collectors/go.d.plugin/config/go.d/sd/docker.conf
+6 -6
@@ -129,7 +129,7 @@ compose:
129 template: |
130 module: mysql
131 name: docker_{{.Name}}
132 - dsn: netdata@tcp({{.IPAddress}}:{{.PrivatePort}})/
132 + dsn: netdata@tcp({{.Address}})/
133 - selector: "nginx"
134 template: |
135 module: nginx
@@ -139,22 +139,22 @@ compose:
139 template: |
140 module: pgbouncer
141 name: docker_{{.Name}}
142 - dsn: postgres://netdata:postgres@{{.IPAddress}}:{{.PrivatePort}}/pgbouncer
142 + dsn: postgres://netdata:postgres@{{.Address}}/pgbouncer
143 - selector: "pika"
144 template: |
145 module: pika
146 name: docker_{{.Name}}
147 - address: redis://@{{.IPAddress}}:{{.PrivatePort}}
147 + address: redis://@{{.Address}}
148 - selector: "postgres"
149 template: |
150 module: postgres
151 name: docker_{{.Name}}
152 - dsn: postgres://netdata:postgres@{{.IPAddress}}:{{.PrivatePort}}/postgres
152 + dsn: postgres://netdata:postgres@{{.Address}}/postgres
153 - selector: "proxysql"
154 template: |
155 module: proxysql
156 name: docker_{{.Name}}
157 - dsn: stats:stats@tcp({{.IPAddress}}:{{.PrivatePort}})/
157 + dsn: stats:stats@tcp({{.Address}})/
158 - selector: "rabbitmq"
159 template: |
160 module: rabbitmq
@@ -164,7 +164,7 @@ compose:
164 template: |
165 module: redis
166 name: docker_{{.Name}}
167 - address: redis://@{{.IPAddress}}:{{.PrivatePort}}
167 + address: redis://@{{.Address}}
168 - selector: "tengine"
169 template: |
170 module: tengine
src/go/collectors/go.d.plugin/config/go.d/sd/net_listeners.conf
+6 -6
@@ -15,7 +15,7 @@ classify:
15 - tags: "activemq"
16 expr: '{{ and (eq .Port "8161") (eq .Comm "activemq") }}'
17 - tags: "apache"
18 - expr: '{{ and (eq .Port "80" "8080") (eq .Comm "apache" "httpd") }}'
18 + expr: '{{ and (eq .Port "80" "8080") (eq .Comm "apache" "apache2" "httpd") }}'
19 - tags: "bind"
20 expr: '{{ and (eq .Port "8653") (eq .Comm "bind" "named") }}'
21 - tags: "cassandra"
@@ -270,7 +270,7 @@ compose:
270 template: |
271 module: mysql
272 name: local
273 - dsn: netdata@tcp({{.IPAddress}}:{{.Port}})/
273 + dsn: netdata@tcp({{.Address}})/
274 - selector: "nginx"
275 template: |
276 - module: nginx
@@ -300,7 +300,7 @@ compose:
300 template: |
301 module: pgbouncer
302 name: local
303 - dsn: postgres://netdata:postgres@{{.IPAddress}}:{{.Port}}/pgbouncer
303 + dsn: postgres://netdata:postgres@{{.Address}}/pgbouncer
304 - selector: "pihole"
305 template: |
306 module: pihole
@@ -315,7 +315,7 @@ compose:
315 template: |
316 module: postgres
317 name: local
318 - dsn: postgresql://netdata@{{.IPAddress}}:{{.Port}}/postgres
318 + dsn: postgresql://netdata@{{.Address}}/postgres
319 - selector: "powerdns"
320 template: |
321 module: powerdns
@@ -334,7 +334,7 @@ compose:
334 template: |
335 module: proxysql
336 name: local
337 - dsn: stats:stats@tcp({{.IPAddress}}:{{.Port}})/
337 + dsn: stats:stats@tcp({{.Address}})/
338 - selector: "rabbitmq"
339 template: |
340 module: rabbitmq
@@ -347,7 +347,7 @@ compose:
347 template: |
348 module: redis
349 name: local
350 - address: redis://@{{.IPAddress}}:{{.Port}}
350 + address: redis://@{{.Address}}
351 - selector: "supervisord"
352 template: |
353 module: supervisord