/
addresses.go
76 lines (69 loc) · 2 KB
/
addresses.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
// 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
}