mirror of
https://github.com/e1732a364fed/v2ray_simple.git
synced 2025-12-24 13:27:56 +08:00
修订文档,示例,添加 heap 泛型代码.
This commit is contained in:
14
README.md
14
README.md
@@ -19,7 +19,10 @@ verysimple项目大大简化了 转发机制,能提高运行速度。本项目
|
||||
|
||||
规定,编译出的文件名必须以 verysimple 开头.
|
||||
|
||||
verysimple 研发了一些新技术,可以加速。
|
||||
verysimple 研发了一些新技术,可以加速,目前基本上是全网最快。
|
||||
|
||||
vs的主要亮点是 全协议readv加速,lazy技术,vless v1,hysteria 阻控,更广泛等utls支持,交互模式等。
|
||||
|
||||
|
||||
为了不吓跑小白,目前 本 README 把安装、使用方式 放在了前面,如果你要直接阅读本作的技术介绍部分,点击跳转 -> [创新点](#创新点)
|
||||
|
||||
@@ -221,6 +224,7 @@ openssl req -new -x509 -days 7305 -key cert.key -out cert.pem
|
||||
## 创新点
|
||||
|
||||
本作有不少创新点,如下
|
||||
|
||||
### 协议
|
||||
|
||||
实现了vless协议(v0,v1)和vlesss(即vless+tcp+tls),
|
||||
@@ -420,6 +424,14 @@ https://github.com/hahahrfool/v2ray_simple/discussions
|
||||
|
||||
有贡献想法的同学,阅读 [CONTRIBUTING](CONTRIBUTING.md) 或者issue中的【开发者贡献指南】.
|
||||
|
||||
#### 开发者入门指导:
|
||||
|
||||
首先学会使用verysimple,熟读本 README.md 和 examples/ 下的配置文件
|
||||
|
||||
之后读 version.go 文件里的 注释,对本作结构有一个认识。然后读 proxy/doc.go 理解 VSI模型。
|
||||
|
||||
之后就可以在go doc中选择自己感兴趣的地方阅读了。
|
||||
|
||||
## 本项目所使用的开源协议
|
||||
|
||||
MIT协议,即你用的时候也要附带一个MIT文件,然后作者不承担任何责任、义务、后果。
|
||||
|
||||
@@ -7,7 +7,8 @@ host = "0.0.0.0"
|
||||
port = 4433
|
||||
version = 0
|
||||
insecure = true
|
||||
fallback = ":80" #默认回落地址.必须是本机ip, 或者unix domain socket的文件名/路径
|
||||
fallback = ":80" # 默认回落地址.ip必须是本机ip(可以省略ip而只写端口,程序会默认补全127.0.0.1), 或者unix domain socket的文件名/路径, 或者 udp://127.0.0.1:80 这种url格式。 (用udp以试图回落到 nginx的 无tls 的 http3 服务端口)
|
||||
|
||||
cert = "cert.pem" # 这里既可以默认放在程序本身目录下,也可以指定完整路径
|
||||
key = "cert.key"
|
||||
|
||||
|
||||
15
main.go
15
main.go
@@ -286,7 +286,7 @@ func main() {
|
||||
}
|
||||
}
|
||||
|
||||
//非阻塞.
|
||||
//非阻塞. 在main函数中被调用。也可以在 test代码中直接使用 listenSer 函数 来手动开启新的转发流程。
|
||||
// 若 not_temporary 为true, 则生成的listener将会被添加到 listenerArray 中
|
||||
func listenSer(inServer proxy.Server, defaultOutClientForThis proxy.Client, not_temporary bool) (thisListener net.Listener) {
|
||||
|
||||
@@ -411,6 +411,8 @@ type incomingInserverConnState struct {
|
||||
|
||||
// handleNewIncomeConnection 会处理 网络层至高级层的数据,
|
||||
// 然后将代理层的处理发往 handshakeInserver_and_passToOutClient 函数。
|
||||
//
|
||||
// 在 listenSer 中被调用。
|
||||
func handleNewIncomeConnection(inServer proxy.Server, defaultClientForThis proxy.Client, thisLocalConnectionInstance net.Conn, forbidDNS_orRoute bool) {
|
||||
|
||||
iics := incomingInserverConnState{
|
||||
@@ -593,6 +595,7 @@ startPass:
|
||||
handshakeInserver_and_passToOutClient(iics)
|
||||
}
|
||||
|
||||
//被 handshakeInserver_and_passToOutClient 调用
|
||||
func handshakeInserver(iics *incomingInserverConnState) (wlc io.ReadWriteCloser, udp_wlc netLayer.MsgConn, targetAddr netLayer.Addr, err error) {
|
||||
inServer := iics.inServer
|
||||
wrappedConn := iics.wrappedConn
|
||||
@@ -708,6 +711,8 @@ func handshakeInserver(iics *incomingInserverConnState) (wlc io.ReadWriteCloser,
|
||||
|
||||
// 本函数 处理inServer的代理层数据,并在试图处理 分流和回落后,将流量导向目标,并开始Copy。
|
||||
// iics 不使用指针, 因为iics不能公用,因为 在多路复用时 iics.wrappedConn 是会变化的。
|
||||
//
|
||||
//被 handleNewIncomeConnection 调用。
|
||||
func handshakeInserver_and_passToOutClient(iics incomingInserverConnState) {
|
||||
|
||||
if iics.shouldFallback {
|
||||
@@ -729,6 +734,7 @@ func handshakeInserver_and_passToOutClient(iics incomingInserverConnState) {
|
||||
|
||||
}
|
||||
|
||||
// 被 passToOutClient 调用
|
||||
func checkfallback(iics incomingInserverConnState) (targetAddr netLayer.Addr, wlc io.ReadWriteCloser) {
|
||||
//先检查 mainFallback,如果mainFallback中各项都不满足 或者根本没有 mainFallback 再检查 defaultFallback
|
||||
|
||||
@@ -805,6 +811,7 @@ func checkfallback(iics incomingInserverConnState) (targetAddr netLayer.Addr, wl
|
||||
return
|
||||
}
|
||||
|
||||
//被 handshakeInserver_and_passToOutClient 和 handshakeInserver 的innerMux部分 调用,会调用 dialClient_andRelay
|
||||
func passToOutClient(iics incomingInserverConnState, err error, gotoFallback bool, wlc io.ReadWriteCloser, udp_wlc netLayer.MsgConn, targetAddr netLayer.Addr) {
|
||||
|
||||
wrappedConn := iics.wrappedConn
|
||||
@@ -1021,8 +1028,9 @@ func passToOutClient(iics incomingInserverConnState, err error, gotoFallback boo
|
||||
dialClient_andRelay(iics, targetAddr, client, isTlsLazy_clientEnd, wlc, udp_wlc)
|
||||
}
|
||||
|
||||
//dialClient 对实际client进行拨号,处理传输层, tls层, 高级层等所有层级后,进行代理层握手
|
||||
// result = 0 表示拨号成功, result = -1 表示 拨号失败, result = 1 表示 拨号成功并处理了转发阶段(用于lazy和mux )
|
||||
//dialClient 对实际client进行拨号,处理传输层, tls层, 高级层等所有层级后,进行代理层握手。
|
||||
// result = 0 表示拨号成功, result = -1 表示 拨号失败, result = 1 表示 拨号成功 并 已经自行处理了转发阶段(用于lazy和mux )。
|
||||
// 在 dialClient_andRelay 中被调用。
|
||||
func dialClient(targetAddr netLayer.Addr,
|
||||
client proxy.Client,
|
||||
baseLocalConn,
|
||||
@@ -1403,6 +1411,7 @@ advLayerStep:
|
||||
return
|
||||
} //dialClient
|
||||
|
||||
//在 dialClient 中调用
|
||||
func dialInnerMux(client proxy.Client, wrc io.ReadWriteCloser, innerProxyName string, targetAddr netLayer.Addr, isudp bool) (realwrc io.ReadWriteCloser, realudp_wrc netLayer.MsgConn, result int) {
|
||||
smuxSession := client.GetClientInnerMuxSession(wrc)
|
||||
if smuxSession == nil {
|
||||
|
||||
@@ -19,11 +19,14 @@ import (
|
||||
"github.com/hahahrfool/v2ray_simple/utils"
|
||||
)
|
||||
|
||||
//使用 ecc p256 方式生成证书
|
||||
func GenerateRandomeCert_Key() ([]byte, []byte) {
|
||||
//ecc p256
|
||||
|
||||
max := new(big.Int).Lsh(big.NewInt(1), 128)
|
||||
serialNumber, _ := rand.Int(rand.Reader, max)
|
||||
|
||||
//可参考 https://blog.ideawand.com/2017/11/22/build-certificate-that-support-Subject-Alternative-Name-SAN/
|
||||
|
||||
subject := pkix.Name{
|
||||
Country: []string{"ZZ"},
|
||||
Province: []string{"asfdsdaf"},
|
||||
@@ -69,6 +72,7 @@ func GenerateRandomeCert_Key() ([]byte, []byte) {
|
||||
*/
|
||||
}
|
||||
|
||||
// 会调用 GenerateRandomeCert_Key 来生成证书,并生成包含该证书的 []tls.Certificate
|
||||
func GenerateRandomTLSCert() []tls.Certificate {
|
||||
|
||||
tlsCert, err := tls.X509KeyPair(GenerateRandomeCert_Key())
|
||||
@@ -79,6 +83,7 @@ func GenerateRandomTLSCert() []tls.Certificate {
|
||||
|
||||
}
|
||||
|
||||
// 会调用 GenerateRandomeCert_Key 来生成证书,并输出到文件
|
||||
func GenerateRandomCertKeyFiles(cfn, kfn string) error {
|
||||
|
||||
cb, kb := GenerateRandomeCert_Key()
|
||||
@@ -105,7 +110,7 @@ func GenerateRandomCertKeyFiles(cfn, kfn string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
//如 certFile, keyFile 有一项没给出,则会自动生成随机证书
|
||||
//若 certFile, keyFile 有一项没给出,则会自动生成随机证书
|
||||
func GetCertArrayFromFile(certFile, keyFile string) (certArray []tls.Certificate, err error) {
|
||||
if certFile != "" && keyFile != "" {
|
||||
cert, err := tls.LoadX509KeyPair(utils.GetFilePath(certFile), utils.GetFilePath(keyFile))
|
||||
|
||||
@@ -74,11 +74,11 @@ func TrimSlice[T any](a []T, deleteIndex int) []T {
|
||||
//实际上 golang.org/x/exp/slices 的 Delete 函数也可以, 不过我还是觉得我自己的好理解一些
|
||||
}
|
||||
|
||||
func GetMapSortedKeySlice[K constraints.Ordered, V any](flags map[K]V) []K {
|
||||
result := make([]K, len(flags))
|
||||
func GetMapSortedKeySlice[K constraints.Ordered, V any](theMap map[K]V) []K {
|
||||
result := make([]K, len(theMap))
|
||||
|
||||
i := 0
|
||||
for f := range flags {
|
||||
for f := range theMap {
|
||||
result[i] = f
|
||||
i++
|
||||
}
|
||||
|
||||
132
utils/algo_heap.go
Normal file
132
utils/algo_heap.go
Normal file
@@ -0,0 +1,132 @@
|
||||
package utils
|
||||
|
||||
// Copyright 2009 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//就是把 container/heap 的代码改成了泛型实现, 并使用了数组来存储数据。
|
||||
// 性能来说应该比原来包高一些,因为少了 interface打包和解包 的损耗。
|
||||
// 之所以有这个转换,是打算优化一下smux中相关shaper。
|
||||
|
||||
// The Heap type describes the requirements
|
||||
// for a type using the routines in this package.
|
||||
// Any type that implements it may be used as a
|
||||
// min-heap with the following invariants (established after
|
||||
// Init has been called or if the data is empty or sorted):
|
||||
//
|
||||
// !h.Less(j, i) for 0 <= i < h.Len() and 2*i+1 <= j <= 2*i+2 and j < h.Len()
|
||||
//
|
||||
// Note that Push and Pop in this interface are for package heap's
|
||||
// implementation to call. To add and remove things from the heap,
|
||||
// use heap.Push and heap.Pop.
|
||||
//
|
||||
// 实际上我们这个包装已经类似 优先队列了, 至于如何优先取决于 LessFunc
|
||||
type Heap[T any] struct {
|
||||
LessFunc func(i, j int, a []T) bool
|
||||
|
||||
Array []T
|
||||
}
|
||||
|
||||
// Init establishes the heap invariants required by the other routines in this package.
|
||||
// Init is idempotent with respect to the heap invariants
|
||||
// and may be called whenever the heap invariants may have been invalidated.
|
||||
// The complexity is O(n) where n = h.Len().
|
||||
func (h *Heap[T]) Init() {
|
||||
// heapify
|
||||
n := h.Len()
|
||||
for i := n/2 - 1; i >= 0; i-- {
|
||||
h.down(i, n)
|
||||
}
|
||||
}
|
||||
|
||||
func (h *Heap[T]) Len() int {
|
||||
return len(h.Array)
|
||||
}
|
||||
|
||||
func (h *Heap[T]) rawPush(x T) {
|
||||
h.Array = append(h.Array, x)
|
||||
}
|
||||
|
||||
func (h *Heap[T]) rawPop() T {
|
||||
old := h.Array
|
||||
n := len(old)
|
||||
x := old[n-1]
|
||||
h.Array = old[0 : n-1]
|
||||
return x
|
||||
}
|
||||
|
||||
func (h *Heap[T]) swap(i, j int) {
|
||||
|
||||
h.Array[i], h.Array[j] = h.Array[j], h.Array[i]
|
||||
}
|
||||
|
||||
// Push pushes the element x onto the heap.
|
||||
// The complexity is O(log n) where n = h.Len().
|
||||
func (h *Heap[T]) Push(x T) {
|
||||
h.rawPush(x)
|
||||
h.up(h.Len() - 1)
|
||||
}
|
||||
|
||||
// Pop removes and returns the minimum element (according to Less) from the heap.
|
||||
// The complexity is O(log n) where n = h.Len().
|
||||
// Pop is equivalent to Remove(h, 0).
|
||||
func (h *Heap[T]) Pop() T {
|
||||
n := h.Len() - 1
|
||||
h.swap(0, n)
|
||||
h.down(0, n)
|
||||
return h.rawPop()
|
||||
}
|
||||
|
||||
// Remove removes and returns the element at index i from the heap.
|
||||
// The complexity is O(log n) where n = h.Len().
|
||||
func (h *Heap[T]) Remove(i int) T {
|
||||
n := h.Len() - 1
|
||||
if n != i {
|
||||
h.swap(i, n)
|
||||
if !h.down(i, n) {
|
||||
h.up(i)
|
||||
}
|
||||
}
|
||||
return h.Pop()
|
||||
}
|
||||
|
||||
// Fix re-establishes the heap ordering after the element at index i has changed its value.
|
||||
// Changing the value of the element at index i and then calling Fix is equivalent to,
|
||||
// but less expensive than, calling Remove(h, i) followed by a Push of the new value.
|
||||
// The complexity is O(log n) where n = h.Len().
|
||||
func (h *Heap[T]) Fix(i int) {
|
||||
if !h.down(i, h.Len()) {
|
||||
h.up(i)
|
||||
}
|
||||
}
|
||||
|
||||
func (h *Heap[T]) up(j int) {
|
||||
for {
|
||||
i := (j - 1) / 2 // parent
|
||||
if i == j || !h.LessFunc(j, i, h.Array) {
|
||||
break
|
||||
}
|
||||
h.swap(i, j)
|
||||
j = i
|
||||
}
|
||||
}
|
||||
|
||||
func (h *Heap[T]) down(i0, n int) bool {
|
||||
i := i0
|
||||
for {
|
||||
j1 := 2*i + 1
|
||||
if j1 >= n || j1 < 0 { // j1 < 0 after int overflow
|
||||
break
|
||||
}
|
||||
j := j1 // left child
|
||||
if j2 := j1 + 1; j2 < n && h.LessFunc(j2, j1, h.Array) {
|
||||
j = j2 // = 2*i + 2 // right child
|
||||
}
|
||||
if !h.LessFunc(j, i, h.Array) {
|
||||
break
|
||||
}
|
||||
h.swap(i, j)
|
||||
i = j
|
||||
}
|
||||
return i > i0
|
||||
}
|
||||
@@ -25,9 +25,9 @@ Structure 本项目结构
|
||||
|
||||
main -> proxy.Standard(配置文件) -> netLayer-> tlsLayer -> httpLayer -> advLayer -> proxy.
|
||||
|
||||
main中,读取配置文件,生成 Dail、Listen 、 RoutePolicy 和 Fallback等 对象后,开始监听;
|
||||
main.go 中,读取配置文件,生成 Dail、Listen 、 RoutePolicy 和 Fallback等 对象后,开始监听,并顺便选择性打开交互模式和 apiServer;
|
||||
|
||||
具体调用链 是 listenSer -> handleNewIncomeConnection -> handshakeInserver_and_passToOutClient -> dialClient
|
||||
具体 转发过程 的 调用链 是 listenSer -> handleNewIncomeConnection -> handshakeInserver_and_passToOutClient -> handshakeInserver -> passToOutClient -> (checkfallback) -> dialClient_andRelay -> dialClient , netLayer.Relay / netLayer.RelayUDP
|
||||
|
||||
用 netLayer操纵路由,用tlsLayer嗅探tls,用httpLayer操纵回落,可选经过ws/grpc, 然后都搞好后,传到proxy,然后就开始转发
|
||||
|
||||
|
||||
Reference in New Issue
Block a user