修订示例,文档,代码;为macos实现为tun自动配置路由表功能

This commit is contained in:
e1732a364fed
2000-01-01 00:00:00 +00:00
parent dc2f9f93f9
commit d002d209c0
8 changed files with 263 additions and 10 deletions

View File

@@ -5,6 +5,8 @@ package main
// gui界面, 所属计划为 vsc 计划即versyimple client计划使用图形界面. 服务端无需gui所以我们叫client
import (
"syscall"
"github.com/e1732a364fed/ui"
_ "github.com/e1732a364fed/ui/winmanifest"
"github.com/e1732a364fed/v2ray_simple/utils"
@@ -295,6 +297,11 @@ func setupUI() {
}
filesM.AppendItem("Open github").OnClicked(openUrlFunc(weblink))
filesM.AppendItem("Check github releases").OnClicked(openUrlFunc(weblink + "releases"))
qi := filesM.AppendItem("Quit App")
qi.OnClicked(func(mi *ui.MenuItem, w *ui.Window) {
syscall.Kill(syscall.Getpid(), syscall.SIGINT) //退出app
})
var y = ui.NewMenu("Debug")
y.AppendItem("test").OnClicked(func(mi *ui.MenuItem, w *ui.Window) {
@@ -308,7 +315,7 @@ func setupUI() {
{
mainwin.OnClosing(func(*ui.Window) bool {
ui.Quit()
ui.Quit() //只是退出gui模式不会退出app
mainwin = nil
return true
})

View File

@@ -301,6 +301,23 @@ func mainFunc() (result int) {
runPreCommands()
stopGorouteCaptureSignalChan := make(chan struct{})
go func() {
osSignals := make(chan os.Signal, 1)
signal.Notify(osSignals, os.Interrupt, syscall.SIGTERM) //os.Kill cannot be trapped
select {
case <-stopGorouteCaptureSignalChan:
return
case <-osSignals:
utils.Info("Program got close signal.")
defaultMachine.Stop()
os.Exit(-1)
}
}()
defaultMachine.Start()
//没可用的listen/dial而且还无法动态更改配置
@@ -350,6 +367,8 @@ func mainFunc() (result int) {
}
{
close(stopGorouteCaptureSignalChan)
osSignals := make(chan os.Signal, 1)
signal.Notify(osSignals, os.Interrupt, syscall.SIGTERM) //os.Kill cannot be trapped
<-osSignals

View File

@@ -7,11 +7,12 @@
# 对于小白来说,下面的指导太过于高级,难以看懂,因此对于小白来说推荐全自动化的方案。
# 在macos上, 配置路由表还需要在tun设备建立之后才能进行因为tun设备的名称是无法自定义的
# 在macos上, 需要管理员权限(sudo)运行vs_gui 才能 成功自动创建tun设备
# 下面给出macos上的路由表配置指导
# 首先删除默认路由,然后将路由指向 utun3 (用户自己运行的到的名称可能不同)
# 最后将自己的服务器的ip (我们的例子是127.0.0.1请你改成实际服务器ip) 的路由指向原来的 路由器地址
# 这个方案只适用于
# 最后将自己的服务器的ip (我们的例子是 vlesss 的 127.0.0.1请你改成实际服务器ip) 的路由指向原来的 路由器地址
# sudo route delete -host default
# sudo route add default -interface utun3
@@ -22,12 +23,25 @@
# sudo route delete -host default
# sudo route add default 192.168.1.1
# 这个方案只适用于 不直连,全经过代理的情况。如果要分流直连,则需要更高级的 路由方案才行,否则会导致本地回环
# 你还可以参考 https://github.com/yangchuansheng/love-gfw/blob/master/docs/gotun2socks-macos.md
[[listen]]
protocol = "tun"
# tun Server使用 host 配置作为 tun device name (macos不设此项)
# 使用 ip 配置作为 gateway 的ip , 若不给出,默认为 10.1.0.20
# 使用 extra.tun_selfip 作为 tun向外拨号的ip, 若不给出, 默认为 10.1.0.10
# 使用 extra.tun_mask 作为 子网掩码, 若不给出, 默认为 255.255.255.0
# 如果 extra.tun_auto_route 给出vs_gui会试图自动配置路由表.
# 此时必须额外给出需要 直连的ip列表, 比如你的 代理服务器的ip地址; 如果不给出, 则不会自动配置路由表
extra.tun_auto_route = true
extra.tun_auto_route_direct_list = [ "127.0.0.1" ]
[[dial]]
protocol = "vlesss"

2
go.mod
View File

@@ -18,6 +18,7 @@ require (
github.com/pires/go-proxyproto v0.6.2
github.com/pkg/profile v1.6.0
github.com/refraction-networking/utls v1.1.5
github.com/songgao/water v0.0.0-20190725173103-fd331bda3f4b
github.com/xtaci/smux v1.5.16
github.com/yl2chen/cidranger v1.0.2
go.uber.org/atomic v1.9.0
@@ -38,7 +39,6 @@ require (
github.com/marten-seemann/qtls-go1-19 v0.1.1 // indirect
github.com/onsi/ginkgo/v2 v2.2.0 // indirect
github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 // indirect
github.com/songgao/water v0.0.0-20190725173103-fd331bda3f4b // indirect
)
require (

View File

@@ -2,7 +2,6 @@ package tun
import (
"io"
"log"
"net"
"sync"
@@ -110,16 +109,23 @@ func (h *handler) ReceiveTo(conn core.UDPConn, data []byte, addr *net.UDPAddr) e
return nil
}
// selfaddr是tun向外拨号时使用的ip; realAddr 是 tun接收数据时对外暴露的ip。
// selfaddr是tun向外拨号时使用的ip; realAddr 是 tun接收数据时对外暴露的ip。也被称为gateway
// realAddr 是在路由表中需要配置的那个ip。
// mask是子网掩码不是很重要.
// macos上的使用举例"", "10.1.0.10", "10.1.0.20", "255.255.255.0"
func CreateTun(name, selfaddr, realAddr, mask string) (tunDev io.ReadWriteCloser, err error) {
func CreateTun(name, selfaddr, realAddr, mask string) (realname string, tunDev io.ReadWriteCloser, err error) {
//macos 上无法指定tun名称
tunDev, err = tun.OpenTunDevice(name, selfaddr, realAddr, mask, nil, false)
if err == nil {
realname = tunDev.(*water.Interface).Name()
if ce := utils.CanLogInfo("created new tun device"); ce != nil {
ce.Write(zap.String("name", tunDev.(*water.Interface).Name()))
ce.Write(
zap.String("name", realname),
zap.String("gateway", realAddr),
zap.String("selfip", selfaddr),
zap.String("mask", mask),
)
}
}
/*
@@ -143,7 +149,10 @@ func ListenTun(tunDev io.ReadWriteCloser) (tcpChan <-chan netLayer.TCPRequestInf
go func() {
_, err := io.CopyBuffer(lwip, tunDev, make([]byte, utils.MTU))
if err != nil {
log.Fatalf("tun copying from tunDev to lwip failed: %v", err)
if ce := utils.CanLogWarn("tun copying from tunDev to lwip failed"); ce != nil {
ce.Write(zap.Error(err))
}
return
}
}()
tcpChan = nh.tcpChan

113
proxy/tun/route_darwin.go Normal file
View File

@@ -0,0 +1,113 @@
package tun
import (
"os/exec"
"strings"
"github.com/e1732a364fed/v2ray_simple/utils"
"go.uber.org/zap"
)
var rememberedRouterIP string
func init() {
autoRouteFunc = func(tunDevName, tunGateway, tunIP string, directList []string) {
var ok = false
params := "-nr -f inet"
out, err := exec.Command("netstat", strings.Split(params, " ")...).Output()
if err != nil {
if ce := utils.CanLogErr("auto route failed"); ce != nil {
ce.Write(zap.Error(err))
}
return
}
//log.Println(string(out))
lines := strings.Split(string(out), "\n")
for i, l := range lines {
if strings.HasPrefix(l, "Destination") {
if i < len(lines)-1 && strings.HasPrefix(lines[i+1], "default") {
str := utils.StandardizeSpaces(lines[i+1])
lines = strings.Split(str, " ")
//log.Println(lines, len(lines))
if len(lines) > 1 {
routerIP := lines[1]
if ce := utils.CanLogInfo("auto route: Your router's ip should be"); ce != nil {
ce.Write(zap.String("ip", routerIP))
}
rememberedRouterIP = routerIP
params1 := "delete -host default"
out1, err := exec.Command("route", strings.Split(params1, " ")...).Output()
//这里err只能捕获没有权限运行等错误; 如果路由表修改失败是不会返回err的
errStep:
if ce := utils.CanLogInfo("auto route delete default"); ce != nil {
ce.Write(zap.String("output", string(out1)))
}
if err != nil {
if ce := utils.CanLogErr("auto route failed"); ce != nil {
ce.Write(zap.Error(err))
}
return
}
params1 = "add default -interface " + tunDevName
out1, err = exec.Command("route", strings.Split(params1, " ")...).Output()
if err != nil {
goto errStep
}
if ce := utils.CanLogInfo("auto route add tun"); ce != nil {
ce.Write(zap.String("output", string(out1)))
}
for _, v := range directList {
params1 = "add -host " + v + " " + rememberedRouterIP
out1, err = exec.Command("route", strings.Split(params1, " ")...).Output()
if err != nil {
goto errStep
}
if ce := utils.CanLogInfo("auto route add direct"); ce != nil {
ce.Write(zap.String("output", string(out1)))
}
}
ok = true
}
}
break
}
}
if !ok {
utils.Warn("auto route failed")
}
}
autoRouteDownFunc = func(tunDevName, tunGateway, tunIP string, directList []string) {
//恢复路由表
params := "delete -host default"
out1, _ := exec.Command("route", strings.Split(params, " ")...).Output()
if ce := utils.CanLogInfo("auto route delete tun route"); ce != nil {
ce.Write(zap.String("output", string(out1)))
}
params = "add default " + rememberedRouterIP
out1, _ = exec.Command("route", strings.Split(params, " ")...).Output()
if ce := utils.CanLogInfo("auto route recover default route"); ce != nil {
ce.Write(zap.String("output", string(out1)))
}
for _, v := range directList {
params = "delete -host " + v
out1, _ = exec.Command("route", strings.Split(params, " ")...).Output()
if ce := utils.CanLogInfo("auto route delete direct"); ce != nil {
ce.Write(zap.String("output", string(out1)))
}
}
}
}

View File

@@ -1,3 +1,10 @@
// Package tun implements proxy.Server for tun device.
/*
tun Server使用 host 配置作为 tun device name
使用 ip 配置作为 gateway 的ip
使用 extra.tun_selfip 作为 tun向外拨号的ip
使用 extra.tun_mask 作为 子网掩码
*/
package tun
import (
@@ -20,6 +27,11 @@ func init() {
type ServerCreator struct{ proxy.CreatorCommonStruct }
var (
autoRouteFunc func(tunDevName, tunGateway, tunIP string, directlist []string)
autoRouteDownFunc func(tunDevName, tunGateway, tunIP string, directlist []string)
)
func (ServerCreator) URLToListenConf(url *url.URL, lc *proxy.ListenConf, format int) (*proxy.ListenConf, error) {
if lc == nil {
return nil, utils.ErrNilParameter
@@ -31,10 +43,69 @@ func (ServerCreator) URLToListenConf(url *url.URL, lc *proxy.ListenConf, format
func (ServerCreator) NewServer(lc *proxy.ListenConf) (proxy.Server, error) {
s := &Server{}
s.devName = lc.Host
s.realIP = lc.IP
if len(lc.Extra) > 0 {
if thing := lc.Extra["tun_selfip"]; thing != nil {
if str, ok := thing.(string); ok {
s.selfip = str
}
}
if thing := lc.Extra["tun_mask"]; thing != nil {
if str, ok := thing.(string); ok {
s.mask = str
}
}
if thing := lc.Extra["tun_auto_route"]; thing != nil {
if auto, autoOk := utils.AnyToBool(thing); autoOk && auto {
if thing := lc.Extra["tun_auto_route_direct_list"]; thing != nil {
if list, ok := thing.([]any); ok {
for _, v := range list {
if str, ok := v.(string); ok && str != "" {
s.autoRouteDirectList = append(s.autoRouteDirectList, str)
}
}
}
}
if len(s.autoRouteDirectList) == 0 {
utils.Warn("tun auto route set, but no direct list given. auto route will not run.")
} else {
s.autoRoute = true
}
}
}
}
return s, nil
}
func (ServerCreator) AfterCommonConfServer(ps proxy.Server) (err error) {
s := ps.(*Server)
const defaultSelfIP = "10.1.0.10"
const defaultRealIP = "10.1.0.20"
const defaultMask = "255.255.255.0"
//上面两个默认ip取自water项目给出的示例
if s.realIP == "" {
s.realIP = defaultRealIP
}
if s.selfip == "" {
s.selfip = defaultSelfIP
}
if s.mask == "" {
s.mask = defaultMask
}
return
}
type Server struct {
proxy.Base
@@ -43,6 +114,10 @@ type Server struct {
infoChan chan<- netLayer.TCPRequestInfo
udpRequestChan chan<- netLayer.UDPRequestInfo
lwipCloser io.Closer
devName, realIP, selfip, mask string
autoRoute bool
autoRouteDirectList []string
}
func (*Server) Name() string { return name }
@@ -65,18 +140,29 @@ func (s *Server) Stop() {
s.lwipCloser.Close()
close(s.infoChan)
close(s.udpRequestChan)
if s.autoRoute && autoRouteDownFunc != nil {
utils.Info("tun running auto table down")
autoRouteDownFunc(s.devName, s.realIP, s.selfip, s.autoRouteDirectList)
}
}
}
func (s *Server) StartListen(tcpRequestChan chan<- netLayer.TCPRequestInfo, udpRequestChan chan<- netLayer.UDPRequestInfo) io.Closer {
tunDev, err := tun.CreateTun("", "10.1.0.10", "10.1.0.20", "255.255.255.0")
//log.Println(s.devName, s.selfip, s.realIP, s.mask)
realname, tunDev, err := tun.CreateTun(s.devName, s.selfip, s.realIP, s.mask)
if err != nil {
if ce := utils.CanLogErr("tun listen failed"); ce != nil {
ce.Write(zap.Error(err))
}
return nil
}
s.devName = realname
if s.autoRoute && autoRouteFunc != nil {
utils.Info("tun running auto table")
autoRouteFunc(realname, s.realIP, s.selfip, s.autoRouteDirectList)
}
s.infoChan = tcpRequestChan
s.udpRequestChan = udpRequestChan

View File

@@ -106,3 +106,8 @@ func Openbrowser(url string) error {
return err
}
// https://stackoverflow.com/questions/37290693/how-to-remove-redundant-spaces-whitespace-from-a-string-in-golang
func StandardizeSpaces(s string) string {
return strings.Join(strings.Fields(s), " ")
}