mirror of
https://github.com/e1732a364fed/v2ray_simple.git
synced 2025-10-12 20:20:17 +08:00
修订代码,文档,注释
This commit is contained in:
11
README.md
11
README.md
@@ -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 技术优点
|
||||||
|
|
||||||
|
46
main.go
46
main.go
@@ -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,16 +624,16 @@ 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 (!isServerEnd && canLazyEncryptClient(client)) || (isServerEnd && canLazyEncryptServer(inServer)) {
|
if isTlsLazy_clientEnd || iics.isTlsLazyServerEnd {
|
||||||
if tlsLayer.PDD {
|
|
||||||
log.Println("loading TLS SniffConn", !isServerEnd)
|
|
||||||
}
|
|
||||||
|
|
||||||
wlc = tlsLayer.NewSniffConn(iics.baseLocalConn, wlc, !isServerEnd, tls_lazy_secure)
|
if tlsLayer.PDD {
|
||||||
|
log.Println("loading TLS SniffConn", isTlsLazy_clientEnd, iics.isTlsLazyServerEnd)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
wlc = tlsLayer.NewSniffConn(iics.baseLocalConn, wlc, isTlsLazy_clientEnd, tls_lazy_secure)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//如果目标是udp则要分情况讨论
|
//如果目标是udp则要分情况讨论
|
||||||
@@ -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 探测;
|
||||||
|
@@ -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
|
||||||
|
}
|
||||||
|
@@ -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 {
|
||||||
|
@@ -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 不是基础连接,但是 是 Splicer(underlay_canSpliceEventually),且此时我们先等待 underlay已经处于 可直连状态,然后再确保 CanDirectWrite 返回true
|
3. underlay 不是基础连接,但是 是 Splicer(underlay_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)
|
||||||
|
@@ -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()
|
||||||
|
|
||||||
|
@@ -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
|
||||||
}
|
}
|
||||||
|
@@ -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
|
||||||
|
20
tls_lazy.go
20
tls_lazy.go
@@ -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 或者退化为普通拷贝
|
||||||
|
Reference in New Issue
Block a user