Skip to content

Commit 8518d70

Browse files
feat: improve GetOutboundIP (#1707)
Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
1 parent d3dfde0 commit 8518d70

File tree

1 file changed

+63
-9
lines changed

1 file changed

+63
-9
lines changed

pkg/common/outbound_ip.go

+63-9
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,74 @@ package common
22

33
import (
44
"net"
5-
6-
log "github.com/sirupsen/logrus"
5+
"sort"
6+
"strings"
77
)
88

9-
// https://stackoverflow.com/a/37382208
10-
// Get preferred outbound ip of this machine
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.
1113
func GetOutboundIP() net.IP {
14+
// See https://stackoverflow.com/a/37382208
1215
conn, err := net.Dial("udp", "8.8.8.8:80")
13-
if err != nil {
14-
log.Fatal(err)
16+
if err == nil {
17+
defer conn.Close()
18+
return conn.LocalAddr().(*net.UDPAddr).IP
1519
}
16-
defer conn.Close()
1720

18-
localAddr := conn.LocalAddr().(*net.UDPAddr)
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+
}
1973

20-
return localAddr.IP
74+
return nil
2175
}

0 commit comments

Comments
 (0)