github.com/newrelic/go-agent@v3.26.0+incompatible/internal/utilization/addresses.go (about)

     1  // Copyright 2020 New Relic Corporation. All rights reserved.
     2  // SPDX-License-Identifier: Apache-2.0
     3  
     4  package utilization
     5  
     6  import (
     7  	"fmt"
     8  	"net"
     9  )
    10  
    11  func nonlocalIPAddressesByInterface() (map[string][]string, error) {
    12  	ifaces, err := net.Interfaces()
    13  	if err != nil {
    14  		return nil, err
    15  	}
    16  	ips := make(map[string][]string, len(ifaces))
    17  	for _, ifc := range ifaces {
    18  		addrs, err := ifc.Addrs()
    19  		if err != nil {
    20  			continue
    21  		}
    22  		for _, addr := range addrs {
    23  			var ip net.IP
    24  			switch iptype := addr.(type) {
    25  			case *net.IPAddr:
    26  				ip = iptype.IP
    27  			case *net.IPNet:
    28  				ip = iptype.IP
    29  			case *net.TCPAddr:
    30  				ip = iptype.IP
    31  			case *net.UDPAddr:
    32  				ip = iptype.IP
    33  			}
    34  			if nil != ip && !ip.IsLoopback() && !ip.IsUnspecified() {
    35  				ips[ifc.Name] = append(ips[ifc.Name], ip.String())
    36  			}
    37  		}
    38  	}
    39  	return ips, nil
    40  }
    41  
    42  // utilizationIPs gathers IP address which may help identify this entity. This
    43  // code chooses all IPs from the interface which contains the IP of a UDP
    44  // connection with NR.  This approach has the following advantages:
    45  // * Matches the behavior of the Java agent.
    46  // * Reports fewer IPs to lower linking burden on infrastructure backend.
    47  // * The UDP connection interface is more likely to contain unique external IPs.
    48  func utilizationIPs() ([]string, error) {
    49  	// Port choice designed to match
    50  	// https://source.datanerd.us/java-agent/java_agent/blob/master/newrelic-agent/src/main/java/com/newrelic/agent/config/Hostname.java#L110
    51  	conn, err := net.Dial("udp", "newrelic.com:10002")
    52  	if err != nil {
    53  		return nil, err
    54  	}
    55  	defer conn.Close()
    56  
    57  	addr, ok := conn.LocalAddr().(*net.UDPAddr)
    58  
    59  	if !ok || nil == addr || addr.IP.IsLoopback() || addr.IP.IsUnspecified() {
    60  		return nil, fmt.Errorf("unexpected connection address: %v", conn.LocalAddr())
    61  	}
    62  	outboundIP := addr.IP.String()
    63  
    64  	ipsByInterface, err := nonlocalIPAddressesByInterface()
    65  	if err != nil {
    66  		return nil, err
    67  	}
    68  	for _, ips := range ipsByInterface {
    69  		for _, ip := range ips {
    70  			if ip == outboundIP {
    71  				return ips, nil
    72  			}
    73  		}
    74  	}
    75  	return nil, nil
    76  }