mirror of
https://github.com/e1732a364fed/v2ray_simple.git
synced 2025-12-24 13:27:56 +08:00
修订代码, 文档
This commit is contained in:
@@ -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 函数
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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/
|
||||
|
||||
@@ -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后面跟一个等号
|
||||
}
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -216,6 +216,10 @@ func hotLoadDialConfForRuntime(conf []*proxy.DialConf) {
|
||||
defaultOutClient = outClient
|
||||
}
|
||||
allClients = append(allClients, outClient)
|
||||
if tag := outClient.GetTag(); tag != "" {
|
||||
routingEnv.ClientsTagMap[tag] = outClient
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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
26
main.go
@@ -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),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user