修订代码,文档,注释

This commit is contained in:
hahahrfool
2022-03-27 14:09:53 +08:00
parent 8ace3832d8
commit e9c9467a72
9 changed files with 83 additions and 42 deletions

View File

@@ -75,9 +75,16 @@ vless v1协议还处在开发阶段我随时可能新增、修改定义。
另外上面说的是承载数据支持udp我们协议的底层传输方式也是全面支持udp的。也就是说可以用udp传输vless数据然后vless里面还可以传输 udp的承载数据。 另外上面说的是承载数据支持udp我们协议的底层传输方式也是全面支持udp的。也就是说可以用udp传输vless数据然后vless里面还可以传输 udp的承载数据。
底层用udp传输的话可以理解为 比 v2ray的mkcp传输方式 更低级的模式直接用udp传输, 不加任何控制。所以可能丢包,不过肯定是更快的。
### tls lazy encrypt (splice) ### tls lazy encrypt (splice)
在最新代码里,还实现了 双向 tls lazy encrypt, 即另一种 xtls的 splice的实现底层也是会调用splice本包为了加以区分就把这种方式叫做 tls lazy encrypt **注意因为技术实现不同该功能不兼容xtls。**, 因为为了能够在tls包外进行过滤我们需要做很多工作所以技术实现与xtls是不一样的
**lazy功能是对标xtls的但是不兼容xtls你用lazy的话两端必须全用verysimple**
在最新代码里,实现了 双向 tls lazy encrypt, 即另一种 xtls的 splice的实现底层也是会调用splice本包为了加以区分就把这种方式叫做 tls lazy encrypt。
tls lazy encrypt 特性 运行时可以用 -lazy 参数打开(服务端客户端都要打开),然后可以用 -pdd 参数 打印 tls 探测输出 tls lazy encrypt 特性 运行时可以用 -lazy 参数打开(服务端客户端都要打开),然后可以用 -pdd 参数 打印 tls 探测输出
@@ -107,7 +114,7 @@ tls lazy encrypt 特性 运行时可以用 -lazy 参数打开(服务端客户
关于splice的一个现有“降速”问题也要看看linux 的 forward配置问题我们这里也是会存在的 https://github.com/XTLS/Xray-core/discussions/59 关于splice的一个现有“降速”问题也要看看linux 的 forward配置问题我们这里也是会存在的 https://github.com/XTLS/Xray-core/discussions/59
**注意因为技术实现不同该功能不兼容xtls。**, 因为为了能够在tls包外进行过滤我们需要做很多工作所以技术实现与xtls是不一样的。
#### 总结 tls lazy encrypt 技术优点 #### 总结 tls lazy encrypt 技术优点

44
main.go
View File

@@ -267,7 +267,7 @@ type incomingInserverConnState struct {
//这里说的多路复用基本指的就是grpc; 如果是 vless内嵌 mux.cool 的话不属于这种情况. //这里说的多路复用基本指的就是grpc; 如果是 vless内嵌 mux.cool 的话不属于这种情况.
// 要区分 多路复用的包装 是在vless等代理验证 的外部还是内部 // 要区分 多路复用的包装 是在 vless等代理的握手验证 的外部 还是 内部
baseLocalConn, wrappedConn net.Conn baseLocalConn, wrappedConn net.Conn
cachedRemoteAddr string cachedRemoteAddr string
@@ -281,20 +281,12 @@ type incomingInserverConnState struct {
shouldFallback bool shouldFallback bool
theFallbackFirstBuffer *bytes.Buffer theFallbackFirstBuffer *bytes.Buffer
isTlsLazyServerEnd bool
} }
func canLazyEncryptServer(inServer proxy.Server) bool { // handleNewIncomeConnection 会处理 网络层至高级层的数据,
//grpc 这种多路复用的链接是绝对无法开启 lazy的, ws 理论上也只有服务端发向客户端的链接 内嵌tls时可以lazy暂不考虑 // 然后将代理层的处理发往 handshakeInserver_and_passToOutClient 函数。
return inServer.IsUseTLS() && inServer.AdvancedLayer() == ""
}
func canLazyEncryptClient(outClient proxy.Client) bool {
//grpc 这种多路复用的链接是绝对无法开启 lazy的, ws 理论上也只有服务端发向客户端的链接 内嵌tls时可以lazy暂不考虑
return outClient.IsUseTLS() && outClient.AdvancedLayer() == ""
}
func handleNewIncomeConnection(inServer proxy.Server, thisLocalConnectionInstance net.Conn) { func handleNewIncomeConnection(inServer proxy.Server, thisLocalConnectionInstance net.Conn) {
iics := incomingInserverConnState{ iics := incomingInserverConnState{
@@ -302,6 +294,8 @@ func handleNewIncomeConnection(inServer proxy.Server, thisLocalConnectionInstanc
inServer: inServer, inServer: inServer,
} }
iics.isTlsLazyServerEnd = tls_lazy_encrypt && canLazyEncryptServer(inServer)
wrappedConn := thisLocalConnectionInstance wrappedConn := thisLocalConnectionInstance
if utils.CanLogInfo() { if utils.CanLogInfo() {
@@ -318,7 +312,7 @@ func handleNewIncomeConnection(inServer proxy.Server, thisLocalConnectionInstanc
if inServer.IsUseTLS() { if inServer.IsUseTLS() {
if tls_lazy_encrypt && canLazyEncryptServer(inServer) { if iics.isTlsLazyServerEnd {
iics.inServerTlsRawReadRecorder = tlsLayer.NewRecorder() iics.inServerTlsRawReadRecorder = tlsLayer.NewRecorder()
iics.inServerTlsRawReadRecorder.StopRecord() //先不记录因为一开始是我们自己的tls握手包没有意义 iics.inServerTlsRawReadRecorder.StopRecord() //先不记录因为一开始是我们自己的tls握手包没有意义
@@ -338,7 +332,7 @@ func handleNewIncomeConnection(inServer proxy.Server, thisLocalConnectionInstanc
return return
} }
if tls_lazy_encrypt && canLazyEncryptServer(inServer) { if iics.isTlsLazyServerEnd {
//此时已经握手完毕,可以记录了 //此时已经握手完毕,可以记录了
iics.inServerTlsRawReadRecorder.StartRecord() iics.inServerTlsRawReadRecorder.StartRecord()
} }
@@ -630,15 +624,15 @@ afterLocalServerHandshake:
// 而在服务端探测时,因为 客户端传来的连接 包了 tls所以要在tls解包后, vless 解包后,再进行判断; // 而在服务端探测时,因为 客户端传来的连接 包了 tls所以要在tls解包后, vless 解包后,再进行判断;
// 所以总之都是要在 inServer 判断 wlc; 总之,含义就是,去检索“用户承载数据”的来源 // 所以总之都是要在 inServer 判断 wlc; 总之,含义就是,去检索“用户承载数据”的来源
if tls_lazy_encrypt && !(!isServerEnd && routedToDirect) { isTlsLazy_clientEnd := tls_lazy_encrypt && canLazyEncryptClient(client)
if isTlsLazy_clientEnd || iics.isTlsLazyServerEnd {
if (!isServerEnd && canLazyEncryptClient(client)) || (isServerEnd && canLazyEncryptServer(inServer)) {
if tlsLayer.PDD { if tlsLayer.PDD {
log.Println("loading TLS SniffConn", !isServerEnd) log.Println("loading TLS SniffConn", isTlsLazy_clientEnd, iics.isTlsLazyServerEnd)
} }
wlc = tlsLayer.NewSniffConn(iics.baseLocalConn, wlc, !isServerEnd, tls_lazy_secure) wlc = tlsLayer.NewSniffConn(iics.baseLocalConn, wlc, isTlsLazy_clientEnd, tls_lazy_secure)
}
} }
@@ -698,7 +692,7 @@ afterLocalServerHandshake:
} }
} else { } else {
if !(tls_lazy_encrypt && canLazyEncryptServer(inServer)) { //lazy_encrypt情况比较特殊 if !(iics.isTlsLazyServerEnd) { //lazy_encrypt情况比较特殊
defer wrappedConn.Close() defer wrappedConn.Close()
} }
@@ -759,7 +753,7 @@ afterLocalServerHandshake:
} }
if utils.CanLogInfo() { if utils.CanLogInfo() {
log.Println(client.Name(), iics.cachedRemoteAddr, " want to dial ", proxy.GetFullName(client), targetAddr.UrlString()) log.Println(client.Name(), iics.cachedRemoteAddr, " request ", targetAddr.UrlString(), "through", proxy.GetVSI_url(client))
} }
@@ -809,7 +803,7 @@ afterLocalServerHandshake:
if client.IsUseTLS() { //即客户端 if client.IsUseTLS() { //即客户端
if tls_lazy_encrypt && canLazyEncryptClient(client) { if isTlsLazy_clientEnd {
if tls_lazy_secure { if tls_lazy_secure {
// 如果使用secure办法则我们每次不能先拨号而是要detect用户的首包后再拨号 // 如果使用secure办法则我们每次不能先拨号而是要detect用户的首包后再拨号
@@ -936,7 +930,7 @@ advLayerStep:
if !routedToDirect && tls_lazy_encrypt { if !routedToDirect && tls_lazy_encrypt {
// 我们加了回落之后,就无法确定 “未使用tls的outClient 一定是在服务端” 了 // 我们加了回落之后,就无法确定 “未使用tls的outClient 一定是在服务端” 了
if !isServerEnd && canLazyEncryptClient(client) { if isTlsLazy_clientEnd {
if client.IsUseTLS() { if client.IsUseTLS() {
//必须是 UserClient //必须是 UserClient
@@ -946,7 +940,7 @@ advLayerStep:
} }
} }
} else if canLazyEncryptServer(inServer) { } else if iics.isTlsLazyServerEnd {
// 最新代码已经确认使用uuid 作为 “特殊指令”所以要求Server必须是一个 proxy.UserServer // 最新代码已经确认使用uuid 作为 “特殊指令”所以要求Server必须是一个 proxy.UserServer
// 否则将无法开启splice功能。这是为了防止0-rtt 探测; // 否则将无法开启splice功能。这是为了防止0-rtt 探测;

View File

@@ -199,9 +199,14 @@ func (a *Addr) String() string {
//返回以url表示的 地址. unix的话文件名若带斜杠则会被转义 //返回以url表示的 地址. unix的话文件名若带斜杠则会被转义
func (a *Addr) UrlString() string { func (a *Addr) UrlString() string {
str := a.String() if a.Network != "" {
return a.Network + "://" + url.PathEscape(a.String())
} else {
return "tcp://" + a.String()
}
return a.Network + "://" + url.PathEscape(str)
} }
func (a *Addr) GetNetIPAddr() (na netip.Addr) { func (a *Addr) GetNetIPAddr() (na netip.Addr) {
@@ -214,11 +219,12 @@ func (a *Addr) GetNetIPAddr() (na netip.Addr) {
return return
} }
func (a *Addr) ToUDPAddr() *net.UDPAddr { func (a *Addr) IsUDP() bool {
switch a.Network { return IsStrUDP_network(a.Network)
case "udp", "udp4", "udp6": }
default: func (a *Addr) ToUDPAddr() *net.UDPAddr {
if !a.IsUDP() {
return nil return nil
} }
@@ -343,3 +349,11 @@ func UDPAddr2AddrPort(ua *net.UDPAddr) netip.AddrPort {
a, _ := netip.AddrFromSlice(ua.IP) a, _ := netip.AddrFromSlice(ua.IP)
return netip.AddrPortFrom(a, uint16(ua.Port)) return netip.AddrPortFrom(a, uint16(ua.Port))
} }
func IsStrUDP_network(s string) bool {
switch s {
case "udp", "udp4", "udp6":
return true
}
return false
}

View File

@@ -39,6 +39,7 @@ func loopAccept(listener net.Listener, acceptFunc func(net.Conn)) {
} }
// ListenAndAccept 试图监听 所有类型的网络包括tcp, udp 和 unix domain socket. // ListenAndAccept 试图监听 所有类型的网络包括tcp, udp 和 unix domain socket.
//
// 非阻塞在自己的goroutine中监听. // 非阻塞在自己的goroutine中监听.
func ListenAndAccept(network, addr string, acceptFunc func(net.Conn)) error { func ListenAndAccept(network, addr string, acceptFunc func(net.Conn)) error {
switch network { switch network {

View File

@@ -63,9 +63,9 @@ func TryReadFrom_withSplice(classicWriter io.Writer, maySpliceConn net.Conn, r i
/* /*
分多钟情况, 分多钟情况,
1. underlay直接是基础连接underlay_canSpliceDirectly且现在直接 CanDirectWrite 就是true, 此时直接 splice 1. underlay直接是基础连接underlay_canSpliceDirectly且现在直接 canDirectFunc 就是true, 此时直接 splice
2. underlay直接是基础连接underlay_canSpliceDirectly但现在的连接阶段还不能直接直连此时要读写一次然后判断一次直到 CanDirectWrite 变成 true 2. underlay直接是基础连接underlay_canSpliceDirectly但现在的连接阶段还不能直接直连此时要读写一次然后判断一次直到 canDirectFunc 变成 true
3. underlay 不是基础连接,但是 是 Splicerunderlay_canSpliceEventually且此时我们先等待 underlay已经处于 可直连状态,然后再确保 CanDirectWrite 返回true 3. underlay 不是基础连接,但是 是 Splicerunderlay_canSpliceEventually且此时我们先等待 underlay已经处于 可直连状态, 即 splicer.CanSplice()变成 true,然后再确保 canDirectFunc 返回true
4. underlay啥也不是直接经典拷贝。 4. underlay啥也不是直接经典拷贝。
*/ */
@@ -77,7 +77,7 @@ func TryReadFrom_withSplice(classicWriter io.Writer, maySpliceConn net.Conn, r i
panic("uc.underlayIsBasic, but can't cast to ReadFrom") panic("uc.underlayIsBasic, but can't cast to ReadFrom")
} }
} else { } else {
//循环读写,直到 uc.CanDirectWrite() 和 underlay_canSpliceEventually 变为true //循环读写,直到 canDirectFunc 和 splicer.CanSplice() 都为true
buf := utils.GetPacket() buf := utils.GetPacket()
defer utils.PutPacket(buf) defer utils.PutPacket(buf)

View File

@@ -55,8 +55,13 @@ type Server interface {
// 这里认为, tcp/udp/kcp/raw_socket 是FirstName具体的协议名称是 LastName, 中间层是 MiddleName // 这里认为, tcp/udp/kcp/raw_socket 是FirstName具体的协议名称是 LastName, 中间层是 MiddleName
// An Example of a full name: tcp+tls+ws+vless // An Example of a full name: tcp+tls+ws+vless
func GetFullName(pc ProxyCommon) string { func GetFullName(pc ProxyCommon) string {
return pc.Network() + pc.MiddleName() + pc.Name() return pc.Network() + pc.MiddleName() + pc.Name()
}
// return GetFullName(pc) + "://" + pc.AddrStr()
func GetVSI_url(pc ProxyCommon) string {
return GetFullName(pc) + "://" + pc.AddrStr()
} }
@@ -64,7 +69,7 @@ func GetFullName(pc ProxyCommon) string {
// 一个 ProxyCommon 会内嵌proxy以及上面各层的所有信息; // 一个 ProxyCommon 会内嵌proxy以及上面各层的所有信息;
type ProxyCommon interface { type ProxyCommon interface {
Name() string //代理协议名称, 如vless Name() string //代理协议名称, 如vless
MiddleName() string //其它VSI层 所使用的协议,如 +tls+ws MiddleName() string //其它VSI层 所使用的协议,前后被加了加号,如 +tls+ws+
Stop() Stop()

View File

@@ -174,7 +174,7 @@ func (c *Client) Handshake(underlay net.Conn, target *netLayer.Addr) (io.ReadWri
Conn: underlay, Conn: underlay,
uuid: *c.user, uuid: *c.user,
version: c.version, version: c.version,
isUDP: target.Network == "udp", isUDP: target.IsUDP(),
underlayIsBasic: netLayer.IsBasicConn(underlay), underlayIsBasic: netLayer.IsBasicConn(underlay),
}, err }, err
} }

View File

@@ -359,7 +359,7 @@ realPart:
remainFirstBufLen: readbuf.Len(), remainFirstBufLen: readbuf.Len(),
uuid: thisUUIDBytes, uuid: thisUUIDBytes,
version: int(version), version: int(version),
isUDP: addr.Network == "udp", isUDP: addr.IsUDP(),
underlayIsBasic: netLayer.IsBasicConn(underlay), underlayIsBasic: netLayer.IsBasicConn(underlay),
isServerEnd: true, isServerEnd: true,
}, addr, nil }, addr, nil

View File

@@ -15,6 +15,26 @@ import (
const tlslazy_willuseSystemCall = runtime.GOOS == "linux" || runtime.GOOS == "darwin" const tlslazy_willuseSystemCall = runtime.GOOS == "linux" || runtime.GOOS == "darwin"
func canLazyEncryptServer(inServer proxy.Server) bool {
//grpc 这种多路复用的链接是绝对无法开启 lazy的, ws 理论上也只有服务端发向客户端的链接 内嵌tls时可以lazy暂不考虑
return inServer.IsUseTLS() && inServer.AdvancedLayer() == ""
}
func canLazyEncryptClient(outClient proxy.Client) bool {
//grpc 这种多路复用的链接是绝对无法开启 lazy的, ws 理论上也只有服务端发向客户端的链接 内嵌tls时可以lazy暂不考虑
return outClient.IsUseTLS() && outClient.AdvancedLayer() == ""
}
func canTargetAddr_tlsLazy(addr *netLayer.Addr) bool {
switch addr.Network {
case "tcp", "tcp4", "tcp6", "unix":
return true
}
return false
}
// tryRawCopy 尝试能否直接对拷,对拷 直接使用 原始 TCPConn也就是裸奔转发 // tryRawCopy 尝试能否直接对拷,对拷 直接使用 原始 TCPConn也就是裸奔转发
// 如果在linux上则和 xtls的splice 含义相同. 在其他系统时与xtls-direct含义相同。 // 如果在linux上则和 xtls的splice 含义相同. 在其他系统时与xtls-direct含义相同。
// 我们内部先 使用 DetectConn进行过滤分析然后再判断进化为splice 或者退化为普通拷贝 // 我们内部先 使用 DetectConn进行过滤分析然后再判断进化为splice 或者退化为普通拷贝