-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathip_raw.go
More file actions
120 lines (105 loc) · 2.39 KB
/
Copy pathip_raw.go
File metadata and controls
120 lines (105 loc) · 2.39 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
package rawsocket
import (
"fmt"
"net"
"sync"
"time"
)
var (
selfIP net.IP
selfIPIsV4 bool
selfOnce sync.Once
)
// addrIP extracts the net.IP from a net.Addr, or nil if the type is unknown.
func addrIP(a net.Addr) net.IP {
switch v := a.(type) {
case *net.IPAddr:
return v.IP
case *net.IPNet:
return v.IP
}
return nil
}
// getIfaceIP returns the IPv4 address of the first available network interface
// that is up and not loopback. Returns nil if none is found.
func getIfaceIP() net.IP {
ifaces, err := net.Interfaces()
if err != nil {
return nil
}
for _, i := range ifaces {
if i.Flags&net.FlagUp == 0 || i.Flags&net.FlagLoopback != 0 {
continue
}
addrs, err := i.Addrs()
if err != nil {
continue
}
for _, a := range addrs {
ip := addrIP(a)
if ip == nil || ip.IsLoopback() {
continue
}
if ip4 := ip.To4(); ip4 != nil {
return ip4
}
}
}
return nil
}
// requestIP discovers the local outbound IPv4 address by dialing a UDP socket.
// The dial target is not contacted; the kernel just picks a local source address.
func requestIP() net.IP {
conn, err := net.DialTimeout("udp", "1.1.1.1:80", 5*time.Second)
if err != nil {
return nil
}
defer conn.Close()
addr, ok := conn.LocalAddr().(*net.UDPAddr)
if !ok {
return nil
}
return addr.IP.To4()
}
// GetSelfIP returns the IPv4 address of the current machine.
// The result is computed once and cached for subsequent calls.
func GetSelfIP() net.IP {
selfOnce.Do(func() {
selfIP = requestIP()
if selfIP == nil {
selfIP = getIfaceIP()
}
if selfIP != nil {
selfIPIsV4 = selfIP.To4() != nil
}
})
return selfIP
}
// findIfaceForIP returns the first network interface whose address matches ip.
// The addr type-switch is shared by getInterfaceByIP and GetLocalMac.
func findIfaceForIP(ip net.IP) (*net.Interface, bool) {
interfaces, err := net.Interfaces()
if err != nil {
return nil, false
}
for _, iface := range interfaces {
addrs, err := iface.Addrs()
if err != nil {
continue
}
for _, addr := range addrs {
if addrIP(addr).Equal(ip) {
return &iface, true
}
}
}
return nil, false
}
// getInterfaceByIP returns the network interface whose address matches ip.
func getInterfaceByIP(ip net.IP) (*net.Interface, error) {
iface, ok := findIfaceForIP(ip)
if !ok {
return nil, fmt.Errorf("no interface found for IP address: %s", ip)
}
return iface, nil
}