修订文档,示例,添加 heap 泛型代码.

This commit is contained in:
hahahrfool
2022-04-15 23:51:46 +08:00
parent 47d83216a6
commit 6dc171e74a
7 changed files with 171 additions and 12 deletions

View File

@@ -19,7 +19,10 @@ verysimple项目大大简化了 转发机制,能提高运行速度。本项目
规定,编译出的文件名必须以 verysimple 开头.
verysimple 研发了一些新技术,可以加速。
verysimple 研发了一些新技术,可以加速,目前基本上是全网最快
vs的主要亮点是 全协议readv加速lazy技术vless v1hysteria 阻控更广泛等utls支持交互模式等。
为了不吓跑小白,目前 本 README 把安装、使用方式 放在了前面,如果你要直接阅读本作的技术介绍部分,点击跳转 -> [创新点](#创新点)
@@ -221,6 +224,7 @@ openssl req -new -x509 -days 7305 -key cert.key -out cert.pem
## 创新点
本作有不少创新点,如下
### 协议
实现了vless协议v0v1和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文件然后作者不承担任何责任、义务、后果。

View File

@@ -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
View File

@@ -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 {

View File

@@ -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))

View File

@@ -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
View 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
}

View File

@@ -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然后就开始转发