Files
v2ray_simple/netLayer/interface_darwin.go
e1732a364fed e00aa2452f 修订代码
2022-12-23 17:34:45 +08:00

258 lines
6.0 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package netLayer
import (
"errors"
"net"
"strings"
"syscall"
"github.com/e1732a364fed/v2ray_simple/utils"
"go.uber.org/zap"
"golang.org/x/net/route"
)
func init() {
SetSystemDNS = setSystemDNS
GetSystemDNS = getSystemDNS
ToggleSystemProxy = toggleSystemProxy
GetSystemProxyState = getSystemProxyState
}
/*
我们的auto route使用纯命令行方式。
sing-box 使用了另一种系统级别的方式。使用了
golang.org/x/net/route
下面给出一些参考
https://github.com/libp2p/go-netroute
https://github.com/jackpal/gateway/issues/27
https://github.com/GameXG/gonet/blob/master/route/route_windows.go
除了 GetGateway之外还可以使用更多其他代码
*/
func GetGateway() (ip net.IP, index int, err error) {
var rib []byte
rib, err = route.FetchRIB(syscall.AF_INET, syscall.NET_RT_DUMP, 0)
if err != nil {
return
}
var msgs []route.Message
msgs, err = route.ParseRIB(syscall.NET_RT_DUMP, rib)
if err != nil {
return
}
for _, m := range msgs {
switch m := m.(type) {
case *route.RouteMessage:
switch sa := m.Addrs[syscall.RTAX_GATEWAY].(type) {
case *route.Inet4Addr:
ip = net.IPv4(sa.IP[0], sa.IP[1], sa.IP[2], sa.IP[3])
case *route.Inet6Addr:
ip = make(net.IP, net.IPv6len)
copy(ip, sa.IP[:])
}
index = m.Index
return
}
}
err = errors.New("no gateway")
return
}
// out, err = exec.Command("netstat", "-nr", "-f", "inet").Output()
// if err != nil {
// if ce := utils.CanLogErr("auto route failed"); ce != nil {
// ce.Write(zap.Error(err))
// }
// return
// }
// startLineIndex := -1
// fields := strings.Split(string(out), "\n")
// for i, l := range fields {
// if strings.HasPrefix(l, "Destination") {
// if i < len(fields)-1 && strings.HasPrefix(fields[i+1], "default") {
// startLineIndex = i + 1
// }
// break
// }
// }
// if startLineIndex < 0 {
// utils.Warn("auto route failed, parse netstat output failed,1")
// return
// }
// str := utils.StandardizeSpaces(fields[startLineIndex])
// fields = strings.Split(str, " ")
// if len(fields) <= 1 {
// utils.Warn("auto route failed, parse netstat output failed,2")
// return
// }
// routerIP := fields[1]
func GetHardwarePortByInterfaceName(str string) string {
searchStr := "Device: " + str
//List All Network Hardware on a Mac via Command Line
out, err := utils.LogRunCmd("networksetup", "-listallhardwareports")
if err == nil {
lines := strings.Split(out, "\n")
for i, l := range lines {
if l == searchStr {
l = lines[i-1]
return strings.TrimPrefix(l, "Hardware Port: ")
}
}
}
return ""
}
// helper func, call GetGateway and GetDeviceNameIndex
func GetGatewayDeviceName() (string, error) {
_, idx, err := GetGateway()
if err != nil {
return "", err
}
return GetDeviceNameIndex(idx), nil
}
// helper func, call GetGatewayDeviceName and utils.GetDarwinNetAdapterNameByInterfaceName.
//
// hardwarePort 和 interface的名称不同hardwareport是 Wi-Fi, 而interface.Name 是 en0
func GetDefaultHardwarePort() (string, error) {
n, e := GetGatewayDeviceName()
if e != nil {
return "", utils.ErrInErr{ErrDetail: e, ErrDesc: "GetGatewayDeviceName failed"}
}
return GetHardwarePortByInterfaceName(n), nil
}
func setSystemDNS(dns string) {
hardwareportStr, err := GetDefaultHardwarePort()
if err != nil {
if ce := utils.CanLogErr("SetSystemDNS: call GetDefaultHardwarePort failed"); ce != nil {
ce.Write(zap.Error(err))
}
return
}
utils.LogRunCmd("networksetup", "-setdnsservers", hardwareportStr, dns)
}
/*
darwin 获取wifi名称
/System/Library/PrivateFrameworks/Apple80211.framework/Versions/Current/Resources/airport -I | grep ' SSID:' | awk '{print $2}'
*/
func getSystemDNS() (result []string) {
hardwareportStr, err := GetDefaultHardwarePort()
if err != nil {
if ce := utils.CanLogErr("GetSystemDNS: call GetDefaultHardwarePort failed"); ce != nil {
ce.Write(zap.Error(err))
}
return
}
out, e := utils.LogRunCmd("networksetup", "-getdnsservers", hardwareportStr)
if e != nil {
return
}
out = strings.TrimRight(out, "\n")
result = strings.Split(out, "\n")
return
}
func toggleSystemProxy(isSocks5 bool, addr, port string, enable bool) {
//我们使用命令行方式。
//todo: 还可以参考 https://github.com/getlantern/sysproxy 这里用了另一种实现还用到elevate
hardwareportStr, err := GetDefaultHardwarePort()
if err != nil {
if ce := utils.CanLogErr("ToggleSystemProxy: call GetDefaultHardwarePort failed"); ce != nil {
ce.Write(zap.Error(err))
}
return
}
if isSocks5 {
if enable {
utils.LogRunCmd("networksetup", "-setsocksfirewallproxy", hardwareportStr, addr, port)
} else {
utils.LogRunCmd("networksetup", "-setsocksfirewallproxystate", hardwareportStr, "off")
}
} else {
if enable {
utils.LogRunCmd("networksetup", "-setwebproxy", hardwareportStr, addr, port)
utils.LogRunCmd("networksetup", "-setsecurewebproxy", hardwareportStr, addr, port)
} else {
utils.LogRunCmd("networksetup", "-setwebproxystate", hardwareportStr, "off")
utils.LogRunCmd("networksetup", "-setsecurewebproxystate", hardwareportStr, "off")
}
}
}
func getSystemProxyState(isSocks5 bool) (ok, enabled bool, addr, port string) {
hardwareportStr, err := GetDefaultHardwarePort()
if err != nil {
if ce := utils.CanLogErr("ToggleSystemProxy: call GetDefaultHardwarePort failed"); ce != nil {
ce.Write(zap.Error(err))
}
return
}
var out string
if isSocks5 {
var e error
out, e = utils.LogRunCmd("networksetup", "-getsocksfirewallproxy", hardwareportStr)
if e != nil {
return
}
ok = true
} else {
var e error
out, e = utils.LogRunCmd("networksetup", "-getwebproxy", hardwareportStr)
if e != nil {
return
}
ok = true
}
strs := strings.Split(out, "\n")
if len(strs) < 1 {
return
}
if strings.Contains(strs[0], "Yes") {
enabled = true
}
if len(strs) < 3 {
return
}
if strings.Contains(strs[1], "Server: ") {
addr = strings.TrimPrefix(strs[1], "Server: ")
}
if strings.Contains(strs[2], "Port: ") {
port = strings.TrimPrefix(strs[2], "Port: ")
}
return
}