@@ -2,20 +2,74 @@ package common
2
2
3
3
import (
4
4
"net"
5
-
6
- log "github.com/sirupsen/logrus "
5
+ "sort"
6
+ "strings "
7
7
)
8
8
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.
11
13
func GetOutboundIP () net.IP {
14
+ // See https://stackoverflow.com/a/37382208
12
15
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
15
19
}
16
- defer conn .Close ()
17
20
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
+ }
19
73
20
- return localAddr . IP
74
+ return nil
21
75
}
0 commit comments