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 }