/
mac_address_detector.go
128 lines (105 loc) · 3.49 KB
/
mac_address_detector.go
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
121
122
123
124
125
126
127
128
package net
import (
"encoding/json"
gonet "net"
"path"
"strings"
bosherr "github.com/cloudfoundry/bosh-utils/errors"
boshsys "github.com/cloudfoundry/bosh-utils/system"
)
//go:generate counterfeiter . MACAddressDetector
type MACAddressDetector interface {
DetectMacAddresses() (map[string]string, error)
}
const (
ifaliasPrefix = "bosh-interface"
)
type linuxMacAddressDetector struct {
fs boshsys.FileSystem
}
type windowsMacAddressDetector struct {
interfacesFunction func() ([]gonet.Interface, error)
runner boshsys.CmdRunner
}
type netAdapter struct {
Name string
MacAddress string
}
func NewLinuxMacAddressDetector(fs boshsys.FileSystem) MACAddressDetector {
return linuxMacAddressDetector{
fs: fs,
}
}
func NewWindowsMacAddressDetector(runner boshsys.CmdRunner, interfacesFunction func() ([]gonet.Interface, error)) MACAddressDetector {
return windowsMacAddressDetector{
interfacesFunction: interfacesFunction,
runner: runner,
}
}
func (d linuxMacAddressDetector) DetectMacAddresses() (map[string]string, error) {
addresses := map[string]string{}
filePaths, err := d.fs.Glob("/sys/class/net/*")
if err != nil {
return addresses, bosherr.WrapError(err, "Getting file list from /sys/class/net")
}
var macAddress string
var ifalias string
for _, filePath := range filePaths {
isPhysicalDevice := d.fs.FileExists(path.Join(filePath, "device"))
// For third-party networking plugin case that the physical interface is used as bridge
// interface and a virtual interface is created to replace it, the virtual interface needs
// to be included in the detected result.
// The virtual interface has an ifalias that has the prefix "bosh-interface"
hasBoshPrefix := false
ifalias, err = d.fs.ReadFileString(path.Join(filePath, "ifalias"))
if err == nil {
hasBoshPrefix = strings.HasPrefix(ifalias, ifaliasPrefix)
}
if isPhysicalDevice || hasBoshPrefix {
macAddress, err = d.fs.ReadFileString(path.Join(filePath, "address"))
if err != nil {
return addresses, bosherr.WrapError(err, "Reading mac address from file")
}
macAddress = strings.Trim(macAddress, "\n")
interfaceName := path.Base(filePath)
addresses[macAddress] = interfaceName
}
}
return addresses, nil
}
func (d windowsMacAddressDetector) DetectMacAddresses() (map[string]string, error) {
ifs, err := d.interfacesFunction()
if err != nil {
return nil, bosherr.WrapError(err, "Detecting Mac Addresses")
}
macs := make(map[string]string, len(ifs))
var netAdapters []netAdapter
stdout, stderr, _, err := d.runner.RunCommand("powershell", "-Command", "Get-NetAdapter | Select MacAddress,Name | ConvertTo-Json")
if err != nil {
return nil, bosherr.WrapErrorf(err, "Getting visible adapters: %s", stderr)
}
err = json.Unmarshal([]byte(stdout), &netAdapters)
if err != nil {
var singularNetAdapter netAdapter
err = json.Unmarshal([]byte(stdout), &singularNetAdapter)
if err != nil {
return nil, bosherr.WrapError(err, "Parsing Get-NetAdapter output")
}
netAdapters = append(netAdapters, singularNetAdapter)
}
for _, f := range ifs {
if adapterVisible(netAdapters, f.HardwareAddr.String(), f.Name) {
macs[f.HardwareAddr.String()] = f.Name
}
}
return macs, nil
}
func adapterVisible(netAdapters []netAdapter, macAddress string, adapterName string) bool {
for _, adapter := range netAdapters {
adapterMac, _ := gonet.ParseMAC(adapter.MacAddress)
if adapter.Name == adapterName && adapterMac.String() == macAddress {
return true
}
}
return false
}