mirror of
https://github.com/e1732a364fed/v2ray_simple.git
synced 2025-09-28 13:42:08 +08:00
258 lines
6.0 KiB
Go
258 lines
6.0 KiB
Go
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
|
||
}
|