修订代码, 文档

This commit is contained in:
e1732a364fed
2022-05-01 12:22:46 +08:00
parent efb2ee0010
commit afe9068ca2
11 changed files with 65 additions and 36 deletions

View File

@@ -11,10 +11,8 @@ import (
)
// 实现 net.Conn, io.ReaderFrom, utils.MultiWriter, netLayer.Splicer
// 因为 gobwas/ws 不包装conn在写入和读取二进制时需要使用 较为底层的函数才行并未被提供标准的Read和Write
// 因为 gobwas/ws 不包装conn在写入和读取二进制时需要使用 较为底层的函数才行并未被提供标准的Read和Write
// 因此我们包装一下统一使用Read和Write函数 来读写 二进制数据。因为我们这里是代理,
// 所以我们默认 抛弃 websocket的 数据帧 长度。
// 如果以后考虑与 vless v1的 udp 相结合的话,则数据包长度 不能丢弃,需要使用另外的实现。
type Conn struct {
net.Conn
first_nextFrameCalled bool
@@ -48,7 +46,7 @@ func (c *Conn) Read(p []byte) (int, error) {
// (使用了 Extended payload length 字段)
// 肯定会有多读的情况,此时如果一次用 wsutil.ReadServerBinary()的话,那么服务器缓存就超大,不可能如此实现
// ( wsutil.ReadServerBinary内部使用了 io.ReadAll, 而ReadAll是会无限增长内存的 )
// 所以我们肯定要分段读, 直接用 wsutil.Reader.Read 即可, 但是每个Read前必须要有 NextFrame调用
// 所以我们肯定要分段读, 直接用 wsutil.Reader.Read 即可, 注意 每个Read前必须要有 NextFrame调用
//
//关于读 的完整过程,建议参考 ws/example.autoban.go 里的 wsHandler 函数

View File

@@ -14,7 +14,7 @@ import (
"go.uber.org/zap"
)
// 2048 /3 = 682.6666 ,
// 2048 /3 = 682.6666... (682 又 三分之二),
// 683 * 4 = 2732, 若你不信,运行 we_test.go中的 TestBase64Len
const MaxEarlyDataLen_Base64 = 2732
@@ -91,11 +91,12 @@ func (s *Server) Handshake(underlay net.Conn) (net.Conn, error) {
//因为我们vs的架构先统一监听tcp然后再调用Handshake函数
// 所以我们不能直接用http.Handle, 这也彰显了 用 gobwas/ws 包的好处
// 给Upgrader提供的 OnRequest 专门用于过滤 path, 也不需要我们的 httpLayer 去过滤
// 给Upgrader提供的 OnRequest 专门用于过滤 path, 也不一定 需要我们的 httpLayer 去过滤
// 我们的 httpLayer 的 过滤方法仍然是最安全的,可以杜绝 所有非法数据;
// 而 ws.Upgrader.Upgrade 使用了 readLine 函数。如果客户提供一个非法的超长的一行的话,它就会陷入泥淖
// 这个以后 可以先用 httpLayer的过滤方法过滤掉后再用 MultiReader组装回来提供给 upgrader.Upgrade
//我们这里就是先用 httpLayer 过滤 再和 buffer一起传入 ws 包
// ReadBufferSize默认是 4096已经够大
OnRequest: func(uri []byte) error {
@@ -178,14 +179,11 @@ func (s *Server) Handshake(underlay net.Conn) (net.Conn, error) {
return nil, err
}
//log.Println("thePotentialEarlyData", len(thePotentialEarlyData))
theConn := &Conn{
Conn: underlay,
underlayIsBasic: netLayer.IsBasicConn(underlay),
state: ws.StateServerSide,
//w: wsutil.NewWriter(underlay, ws.StateServerSide, ws.OpBinary),
r: wsutil.NewServerSideReader(underlay),
r: wsutil.NewServerSideReader(underlay),
}
//不想客户端;服务端是不怕客户端在握手阶段传来任何多余数据的
// 因为我们还没实现 0-rtt

View File

@@ -23,7 +23,7 @@ HTTP/1.1 101 Switching Protocols
Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk=
Sec-WebSocket-Protocol: chat
总之一个websocket的请求头直接就是一个 合法的http请求头所以也没必要额外包一个http连接
总之一个websocket的请求头直接就是一个 合法的http请求头所以也没必要额外包一个http
直接使用tcp/tls 连接即可。
websocket 库比较 https://yalantis.com/blog/how-to-build-websockets-in-go/

View File

@@ -15,6 +15,9 @@ func TestBase64Len(t *testing.T) {
var arr [2048]byte
str := base64.StdEncoding.EncodeToString(arr[:])
t.Log(len(str)) //2732
if len(str) != ws.MaxEarlyDataLen_Base64 {
t.FailNow()
}
//t.Log((str)) //一堆A后面跟一个等号
}

View File

@@ -669,7 +669,9 @@ func interactively_hotRemoveServerOrClient() {
will_delete_index = int(theInt)
if will_delete_dial {
allClients[will_delete_index].Stop()
doomedClient := allClients[will_delete_index]
delete(routingEnv.ClientsTagMap, doomedClient.GetTag())
doomedClient.Stop()
allClients = utils.TrimSlice(allClients, will_delete_index)
}
if will_delete_listen {

View File

@@ -216,6 +216,10 @@ func hotLoadDialConfForRuntime(conf []*proxy.DialConf) {
defaultOutClient = outClient
}
allClients = append(allClients, outClient)
if tag := outClient.GetTag(); tag != "" {
routingEnv.ClientsTagMap[tag] = outClient
}
}
}

View File

@@ -50,7 +50,14 @@ const (
defaultLogFile = "vs_log"
)
func initRouteEnv() {
routingEnv.ClientsTagMap = make(map[string]proxy.Client)
}
func init() {
initRouteEnv()
flag.StringVar(&configFileName, "c", "client.toml", "config file name")
flag.BoolVar(&startPProf, "pp", false, "pprof")
flag.BoolVar(&startMProf, "mp", false, "memory pprof")
@@ -94,9 +101,16 @@ func mainFunc() (result int) {
defer func() {
if r := recover(); r != nil {
if ce := utils.CanLogFatal("Captured panic!"); ce != nil {
stack := debug.Stack()
stackStr := string(stack)
log.Println(stackStr)
ce.Write(
zap.Any("err:", r),
zap.String("stacktrace", string(debug.Stack())),
zap.String("stacktrace", stackStr),
)
} else {
log.Fatalln("panic captured!", r, "\n", string(debug.Stack()))
@@ -244,6 +258,8 @@ func mainFunc() (result int) {
routingEnv, Default_uuid = proxy.LoadEnvFromStandardConf(&standardConf)
initRouteEnv()
//虽然标准模式支持多个Server目前先只考虑一个
//多个Server存在的话则必须要用 tag指定路由; 然后我们需在预先阶段就判断好tag指定的路由
@@ -273,9 +289,9 @@ func mainFunc() (result int) {
}
allServers = append(allServers, thisServer)
if tag := thisServer.GetTag(); tag != "" {
vs.ServersTagMap[tag] = thisServer
}
//if tag := thisServer.GetTag(); tag != "" {
// vs.ServersTagMap[tag] = thisServer
//}
}
}
@@ -314,7 +330,7 @@ func mainFunc() (result int) {
allClients = append(allClients, thisClient)
if tag := thisClient.GetTag(); tag != "" {
vs.ClientsTagMap[tag] = thisClient
routingEnv.ClientsTagMap[tag] = thisClient
}
}

26
main.go
View File

@@ -44,9 +44,6 @@ var (
var (
DirectClient, _, _ = proxy.ClientFromURL(proxy.DirectName + "://")
ServersTagMap = make(map[string]proxy.Server)
ClientsTagMap = make(map[string]proxy.Client)
Tls_lazy_encrypt bool
Tls_lazy_secure bool
)
@@ -774,18 +771,21 @@ func passToOutClient(iics incomingInserverConnState, isfallback bool, wlc net.Co
}
} else {
if tagC, ok := ClientsTagMap[outtag]; ok {
client = tagC
routed = true
if ce := utils.CanLogInfo("Route"); ce != nil {
ce.Write(
zap.String("to outtag", outtag),
zap.String("with addr", client.AddrStr()),
zap.String("and protocol", proxy.GetFullName(client)),
zap.Any("for source", desc),
)
if len(iics.RoutingEnv.ClientsTagMap) > 0 {
if tagC, ok := iics.RoutingEnv.ClientsTagMap[outtag]; ok {
client = tagC
routed = true
if ce := utils.CanLogInfo("Route"); ce != nil {
ce.Write(
zap.String("to outtag", outtag),
zap.String("with addr", client.AddrStr()),
zap.String("and protocol", proxy.GetFullName(client)),
zap.Any("for source", desc),
)
}
}
}
}
}

View File

@@ -4,7 +4,7 @@ import "testing"
func TestGeosite(t *testing.T) {
//DownloadCommunity_DomainListFiles()
// 这个需要从github下载所以如果你的网无法访问gituhb的话是会失败的, 所以就先不测了,否则再怨我说go test不通过. 我已经试了好使.
// 这个需要从github下载所以如果你的网无法访问gituhb的话是会失败的, 所以就不在代码里下载了,否则再怨我说go test不通过. 我已经试了好使.
err := LoadGeositeFiles()
if err != nil {

View File

@@ -118,7 +118,9 @@ func (ul *UDPListener) run() {
for {
buf := utils.GetPacket()
n, raddr, err := conn.ReadFromUDP(buf)
if ul.isclosed {
return
}
go func(theraddr *net.UDPAddr, thebuf []byte) {
addrport := UDPAddr2AddrPort(theraddr)
var oldConn *UDPConn
@@ -129,6 +131,9 @@ func (ul *UDPListener) run() {
if oldConn == nil {
oldConn = ul.newConn(raddr, addrport)
if ul.isclosed {
return
}
ul.newConnChan <- oldConn //此时 ul 的 Accept的调用者就会收到一个新Conn
}

View File

@@ -9,13 +9,16 @@ import (
//used in real relay progress. See source code of v2ray_simple for details.
type RoutingEnv struct {
RoutePolicy *netLayer.RoutePolicy
MainFallback *httpLayer.ClassicFallback
DnsMachine *netLayer.DNSMachine
RoutePolicy *netLayer.RoutePolicy
MainFallback *httpLayer.ClassicFallback
DnsMachine *netLayer.DNSMachine
ClientsTagMap map[string]Client //用于分流到某个tag的Client, 所以需要知道所有的client
}
func LoadEnvFromStandardConf(standardConf *StandardConf) (routingEnv RoutingEnv, Default_uuid string) {
routingEnv.ClientsTagMap = make(map[string]Client)
if len(standardConf.Fallbacks) != 0 {
routingEnv.MainFallback = httpLayer.NewClassicFallbackFromConfList(standardConf.Fallbacks)
}