mirror of
https://github.com/Control-D-Inc/ctrld.git
synced 2026-09-29 13:51:51 +02:00
cmd/cli: extend list of valid interfaces for MacOS
By parsing "networksetup -listallhardwareports" output to get list of available hardware ports.
This commit is contained in:
1 parent
82e0d4b0c4
commit
5f4a399850
5 files changed
+80
-20
No files matched your search
+27
-17
@@ -43,22 +43,32 @@ func networkServiceName(ifaceName string, r io.Reader) string {
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
// validInterface reports whether the *net.Interface is a valid one, which includes en0 -> en10.
|
// validInterface reports whether the *net.Interface is a valid one.
|
||||||
// - en0: physical wireless
|
func validInterface(iface *net.Interface, validIfacesMap map[string]struct{}) bool {
|
||||||
// - en1: Thunderbolt 1
|
_, ok := validIfacesMap[iface.Name]
|
||||||
// - en2: Thunderbolt 2
|
return ok
|
||||||
// - en3: Thunderbolt 3
|
}
|
||||||
// - en4: Thunderbolt 4
|
|
||||||
// - ...
|
func validInterfacesMap() map[string]struct{} {
|
||||||
// - en10: iPad
|
b, err := exec.Command("networksetup", "-listallhardwareports").Output()
|
||||||
//
|
if err != nil {
|
||||||
// For full list, see: https://unix.stackexchange.com/questions/603506/what-are-these-ifconfig-interfaces-on-macos
|
return nil
|
||||||
func validInterface(iface *net.Interface) bool {
|
|
||||||
switch iface.Name {
|
|
||||||
case "en0", "en1", "en2", "en3", "en4", "en5",
|
|
||||||
"en6", "en7", "en8", "en9", "en10":
|
|
||||||
return true
|
|
||||||
default:
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
return parseListAllHardwarePorts(bytes.NewReader(b))
|
||||||
|
}
|
||||||
|
|
||||||
|
// parseListAllHardwarePorts parses output of "networksetup -listallhardwareports"
|
||||||
|
// and returns map presents all hardware ports.
|
||||||
|
func parseListAllHardwarePorts(r io.Reader) map[string]struct{} {
|
||||||
|
m := make(map[string]struct{})
|
||||||
|
scanner := bufio.NewScanner(r)
|
||||||
|
for scanner.Scan() {
|
||||||
|
line := scanner.Text()
|
||||||
|
after, ok := strings.CutPrefix(line, "Device: ")
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
m[after] = struct{}{}
|
||||||
|
}
|
||||||
|
return m
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
package cli
|
package cli
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"maps"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
@@ -57,3 +58,47 @@ func Test_networkServiceName(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const listallhardwareportsOutput = `
|
||||||
|
Hardware Port: Ethernet Adapter (en6)
|
||||||
|
Device: en6
|
||||||
|
Ethernet Address: 3a:3e:fc:1e:ab:41
|
||||||
|
|
||||||
|
Hardware Port: Ethernet Adapter (en7)
|
||||||
|
Device: en7
|
||||||
|
Ethernet Address: 3a:3e:fc:1e:ab:42
|
||||||
|
|
||||||
|
Hardware Port: Thunderbolt Bridge
|
||||||
|
Device: bridge0
|
||||||
|
Ethernet Address: 36:21:bb:3a:7a:40
|
||||||
|
|
||||||
|
Hardware Port: Wi-Fi
|
||||||
|
Device: en0
|
||||||
|
Ethernet Address: a0:78:17:68:56:3f
|
||||||
|
|
||||||
|
Hardware Port: Thunderbolt 1
|
||||||
|
Device: en1
|
||||||
|
Ethernet Address: 36:21:bb:3a:7a:40
|
||||||
|
|
||||||
|
Hardware Port: Thunderbolt 2
|
||||||
|
Device: en2
|
||||||
|
Ethernet Address: 36:21:bb:3a:7a:44
|
||||||
|
|
||||||
|
VLAN Configurations
|
||||||
|
===================
|
||||||
|
`
|
||||||
|
|
||||||
|
func Test_parseListAllHardwarePorts(t *testing.T) {
|
||||||
|
expected := map[string]struct{}{
|
||||||
|
"en0": {},
|
||||||
|
"en1": {},
|
||||||
|
"en2": {},
|
||||||
|
"en6": {},
|
||||||
|
"en7": {},
|
||||||
|
"bridge0": {},
|
||||||
|
}
|
||||||
|
m := parseListAllHardwarePorts(strings.NewReader(listallhardwareportsOutput))
|
||||||
|
if !maps.Equal(m, expected) {
|
||||||
|
t.Errorf("unexpected output, want: %v, got: %v", expected, m)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,4 +6,6 @@ import "net"
|
|||||||
|
|
||||||
func patchNetIfaceName(iface *net.Interface) error { return nil }
|
func patchNetIfaceName(iface *net.Interface) error { return nil }
|
||||||
|
|
||||||
func validInterface(iface *net.Interface) bool { return true }
|
func validInterface(iface *net.Interface, validIfacesMap map[string]struct{}) bool { return true }
|
||||||
|
|
||||||
|
func validInterfacesMap() map[string]struct{} { return nil }
|
||||||
@@ -10,7 +10,7 @@ func patchNetIfaceName(iface *net.Interface) error {
|
|||||||
|
|
||||||
// validInterface reports whether the *net.Interface is a valid one.
|
// validInterface reports whether the *net.Interface is a valid one.
|
||||||
// On Windows, only physical interfaces are considered valid.
|
// On Windows, only physical interfaces are considered valid.
|
||||||
func validInterface(iface *net.Interface) bool {
|
func validInterface(iface *net.Interface, validIfacesMap map[string]struct{}) bool {
|
||||||
if iface == nil {
|
if iface == nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@@ -19,3 +19,5 @@ func validInterface(iface *net.Interface) bool {
|
|||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func validInterfacesMap() map[string]struct{} { return nil }
|
||||||
+2
-1
@@ -868,13 +868,14 @@ func canBeLocalUpstream(addr string) bool {
|
|||||||
// the interface that matches excludeIfaceName. The context is used to clarify the
|
// the interface that matches excludeIfaceName. The context is used to clarify the
|
||||||
// log message when error happens.
|
// log message when error happens.
|
||||||
func withEachPhysicalInterfaces(excludeIfaceName, context string, f func(i *net.Interface) error) {
|
func withEachPhysicalInterfaces(excludeIfaceName, context string, f func(i *net.Interface) error) {
|
||||||
|
validIfacesMap := validInterfacesMap()
|
||||||
interfaces.ForeachInterface(func(i interfaces.Interface, prefixes []netip.Prefix) {
|
interfaces.ForeachInterface(func(i interfaces.Interface, prefixes []netip.Prefix) {
|
||||||
// Skip loopback/virtual interface.
|
// Skip loopback/virtual interface.
|
||||||
if i.IsLoopback() || len(i.HardwareAddr) == 0 {
|
if i.IsLoopback() || len(i.HardwareAddr) == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// Skip invalid interface.
|
// Skip invalid interface.
|
||||||
if !validInterface(i.Interface) {
|
if !validInterface(i.Interface, validIfacesMap) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
netIface := i.Interface
|
netIface := i.Interface
|
||||||
|
|||||||
Reference in new issue
Block a user