File: addresses.go

package info (click to toggle)
golang-github-newrelic-go-agent 3.15.2-9
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, forky, sid, trixie
  • size: 8,356 kB
  • sloc: sh: 65; makefile: 6
file content (76 lines) | stat: -rw-r--r-- 2,045 bytes parent folder | download | duplicates (2)
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
// Copyright 2020 New Relic Corporation. All rights reserved.
// SPDX-License-Identifier: Apache-2.0

package utilization

import (
	"fmt"
	"net"
)

func nonlocalIPAddressesByInterface() (map[string][]string, error) {
	ifaces, err := net.Interfaces()
	if err != nil {
		return nil, err
	}
	ips := make(map[string][]string, len(ifaces))
	for _, ifc := range ifaces {
		addrs, err := ifc.Addrs()
		if err != nil {
			continue
		}
		for _, addr := range addrs {
			var ip net.IP
			switch iptype := addr.(type) {
			case *net.IPAddr:
				ip = iptype.IP
			case *net.IPNet:
				ip = iptype.IP
			case *net.TCPAddr:
				ip = iptype.IP
			case *net.UDPAddr:
				ip = iptype.IP
			}
			if nil != ip && !ip.IsLoopback() && !ip.IsUnspecified() {
				ips[ifc.Name] = append(ips[ifc.Name], ip.String())
			}
		}
	}
	return ips, nil
}

// utilizationIPs gathers IP address which may help identify this entity. This
// code chooses all IPs from the interface which contains the IP of a UDP
// connection with NR.  This approach has the following advantages:
// * Matches the behavior of the Java agent.
// * Reports fewer IPs to lower linking burden on infrastructure backend.
// * The UDP connection interface is more likely to contain unique external IPs.
func utilizationIPs() ([]string, error) {
	// Port choice designed to match
	// https://source.datanerd.us/java-agent/java_agent/blob/master/newrelic-agent/src/main/java/com/newrelic/agent/config/Hostname.java#L110
	conn, err := net.Dial("udp", "newrelic.com:10002")
	if err != nil {
		return nil, err
	}
	defer conn.Close()

	addr, ok := conn.LocalAddr().(*net.UDPAddr)

	if !ok || nil == addr || addr.IP.IsLoopback() || addr.IP.IsUnspecified() {
		return nil, fmt.Errorf("unexpected connection address: %v", conn.LocalAddr())
	}
	outboundIP := addr.IP.String()

	ipsByInterface, err := nonlocalIPAddressesByInterface()
	if err != nil {
		return nil, err
	}
	for _, ips := range ipsByInterface {
		for _, ip := range ips {
			if ip == outboundIP {
				return ips, nil
			}
		}
	}
	return nil, nil
}