github.1485827954.workers.dev/nektos/act@v0.2.63/pkg/common/outbound_ip.go (about)

     1  package common
     2  
     3  import (
     4  	"net"
     5  	"sort"
     6  	"strings"
     7  )
     8  
     9  // GetOutboundIP returns an outbound IP address of this machine.
    10  // It tries to access the internet and returns the local IP address of the connection.
    11  // If the machine cannot access the internet, it returns a preferred IP address from network interfaces.
    12  // It returns nil if no IP address is found.
    13  func GetOutboundIP() net.IP {
    14  	// See https://stackoverflow.com/a/37382208
    15  	conn, err := net.Dial("udp", "8.8.8.8:80")
    16  	if err == nil {
    17  		defer conn.Close()
    18  		return conn.LocalAddr().(*net.UDPAddr).IP
    19  	}
    20  
    21  	// So the machine cannot access the internet. Pick an IP address from network interfaces.
    22  	if ifs, err := net.Interfaces(); err == nil {
    23  		type IP struct {
    24  			net.IP
    25  			net.Interface
    26  		}
    27  		var ips []IP
    28  		for _, i := range ifs {
    29  			if addrs, err := i.Addrs(); err == nil {
    30  				for _, addr := range addrs {
    31  					var ip net.IP
    32  					switch v := addr.(type) {
    33  					case *net.IPNet:
    34  						ip = v.IP
    35  					case *net.IPAddr:
    36  						ip = v.IP
    37  					}
    38  					if ip.IsGlobalUnicast() {
    39  						ips = append(ips, IP{ip, i})
    40  					}
    41  				}
    42  			}
    43  		}
    44  		if len(ips) > 1 {
    45  			sort.Slice(ips, func(i, j int) bool {
    46  				ifi := ips[i].Interface
    47  				ifj := ips[j].Interface
    48  
    49  				// ethernet is preferred
    50  				if vi, vj := strings.HasPrefix(ifi.Name, "e"), strings.HasPrefix(ifj.Name, "e"); vi != vj {
    51  					return vi
    52  				}
    53  
    54  				ipi := ips[i].IP
    55  				ipj := ips[j].IP
    56  
    57  				// IPv4 is preferred
    58  				if vi, vj := ipi.To4() != nil, ipj.To4() != nil; vi != vj {
    59  					return vi
    60  				}
    61  
    62  				// en0 is preferred to en1
    63  				if ifi.Name != ifj.Name {
    64  					return ifi.Name < ifj.Name
    65  				}
    66  
    67  				// fallback
    68  				return ipi.String() < ipj.String()
    69  			})
    70  			return ips[0].IP
    71  		}
    72  	}
    73  
    74  	return nil
    75  }