diff --git a/Makefile b/Makefile index cdb093a..c173c51 100644 --- a/Makefile +++ b/Makefile @@ -7,6 +7,7 @@ # # for embedding geoip file: # make tags="embed_geoip" macm1 +# # 目前发布版直接使用go1.18编译,你如果想编译出相同文件,也要使用go1.18才行 BUILD_VERSION := v1.0.7 diff --git a/main.go b/main.go index 306361b..d5afd1e 100644 --- a/main.go +++ b/main.go @@ -31,6 +31,7 @@ const ( standardMode v2rayCompatibleMode ) +const tlslazy_willuseSystemCall = runtime.GOOS == "linux" || runtime.GOOS == "darwin" var ( configFileName string @@ -216,12 +217,12 @@ func main() { func listenSer(listener net.Listener, inServer proxy.Server) { - theFunc := func(conn net.Conn) { + handleFunc := func(conn net.Conn) { handleNewIncomeConnection(inServer, conn) } network := inServer.Network() - err := netLayer.ListenAndAccept(network, inServer.AddrStr(), theFunc) + err := netLayer.ListenAndAccept(network, inServer.AddrStr(), handleFunc) if err == nil { if utils.CanLogInfo() { @@ -700,7 +701,18 @@ afterLocalServerHandshake: } if utils.CanLogDebug() { - /* + + if netLayer.UseReadv { + go func() { + n, e := netLayer.TryCopy(wrc, wlc) + log.Println("本地->远程 转发结束", realTargetAddr.String(), n, e) + }() + + n, e := netLayer.TryCopy(wlc, wrc) + log.Println("远程->本地 转发结束", realTargetAddr.String(), n, e) + + } else { + go func() { n, e := io.Copy(wrc, wlc) log.Println("本地->远程 转发结束", realTargetAddr.String(), n, e) @@ -708,27 +720,15 @@ afterLocalServerHandshake: n, e := io.Copy(wlc, wrc) log.Println("远程->本地 转发结束", realTargetAddr.String(), n, e) - */ - go func() { - n, e := netLayer.TryCopy(wrc, wlc) - log.Println("本地->远程 转发结束", realTargetAddr.String(), n, e) - }() - - n, e := netLayer.TryCopy(wlc, wrc) - log.Println("远程->本地 转发结束", realTargetAddr.String(), n, e) + } } else { - //如果两个都是 *net.TCPConn或uds, 则Copy会自动进行splice/sendfile,无需额外处理 - //go io.Copy(wrc, wlc) - //io.Copy(wlc, wrc) netLayer.Relay(wlc, wrc) } } -var tlslazy_willuseSystemCall = runtime.GOOS == "linux" || runtime.GOOS == "darwin" - // tryRawCopy 尝试能否直接对拷,对拷 直接使用 原始 TCPConn,也就是裸奔转发 // 如果在linux上,则和 xtls的splice 含义相同. 在其他系统时,与xtls-direct含义相同。 // 我们内部先 使用 DetectConn进行过滤分析,然后再判断进化为splice 或者退化为普通拷贝 diff --git a/netLayer/addr.go b/netLayer/addr.go index e97a19b..c4a28ca 100644 --- a/netLayer/addr.go +++ b/netLayer/addr.go @@ -28,22 +28,26 @@ type Addr struct { Network string } +func RandPortStr() string { + return strconv.Itoa(rand.Intn(60000) + 4096) +} + func GetRandLocalAddr() string { - return "0.0.0.0:" + strconv.Itoa(rand.Intn(60000)+4096) + return "0.0.0.0:" + RandPortStr() } func NewAddrFromUDPAddr(addr *net.UDPAddr) *Addr { return &Addr{ - IP: addr.IP, - Port: addr.Port, - //IsUDP: true, + IP: addr.IP, + Port: addr.Port, Network: "udp", } } +//addrStr格式一般为 host:port 的格式;如果不含冒号,将直接认为该字符串是域名或文件名 func NewAddr(addrStr string) (*Addr, error) { if !strings.Contains(addrStr, ":") { - //如果 是unix domain socket + //unix domain socket, 或者域名默认端口的情况 return &Addr{Name: addrStr}, nil } diff --git a/netLayer/readv.go b/netLayer/readv.go index dade77a..a6e2ba7 100644 --- a/netLayer/readv.go +++ b/netLayer/readv.go @@ -26,7 +26,7 @@ func GetRawConn(reader io.Reader) syscall.RawConn { } // 用于读端实现了 readv但是写端的情况,比如 从socks5读取 数据, 等裸协议的情况 -// 小贴士:将该 net.Buffers 写入io.Writer的话,只需使用 其WriteTo方法。 +// 小贴士:将该 net.Buffers 写入io.Writer的话,只需使用 其WriteTo方法, 即可自动适配writev。 /* 使用方式 diff --git a/netLayer/relay.go b/netLayer/relay.go index 1fa6643..ea029f2 100644 --- a/netLayer/relay.go +++ b/netLayer/relay.go @@ -21,7 +21,7 @@ func init() { } -//这里认为能 splice 或 sendfile的 都算 +//这里认为能 splice 或 sendfile的 都算,具体可参考go标准代码的实现, 总之就是tcp和uds可以 func CanSplice(r interface{}) bool { if _, ok := r.(*net.TCPConn); ok { @@ -90,7 +90,7 @@ copy: return io.Copy(writeConn, readConn) } -// 类似TryCopy,但是只会读写一次 +// 类似TryCopy,但是只会读写一次; 因为只读写一次,所以没办法splice func TryCopyOnce(writeConn io.Writer, readConn io.Reader) (allnum int64, err error) { var mr utils.MultiReader var buffers net.Buffers @@ -100,12 +100,6 @@ func TryCopyOnce(writeConn io.Writer, readConn io.Reader) (allnum int64, err err log.Println("TryCopy", reflect.TypeOf(readConn), "->", reflect.TypeOf(writeConn)) } - if SystemCanSplice && CanSplice(readConn) && CanSplice(writeConn) { - if utils.CanLogDebug() { - log.Println("copying with splice") - } - goto copy - } // 不全 支持splice的话,我们就考虑 read端 可 readv 的情况 // 连readv都不让 那就直接 经典拷贝 if !UseReadv { @@ -136,16 +130,22 @@ classic: if utils.CanLogDebug() { log.Println("copying with classic method") } -copy: - //Copy内部实现 会自动进行splice, 若无splice实现则直接使用原始方法 “循环读取 并 写入” - return io.Copy(writeConn, readConn) + bs := utils.GetPacket() + n, e := readConn.Read(bs) + if e != nil { + return 0, e + } + n, e = writeConn.Write(bs[:n]) + utils.PutPacket(bs) + return int64(n), e } // 从conn1读取 写入到 conn2,并同时从 conn2读取写入conn1 // 阻塞 // 返回从 conn1读取 写入到 conn2的数据 // UseReadv==true 时 内部使用 TryCopy 进行拷贝 +// 会自动优选 splice,readv,不行则使用经典拷贝 func Relay(conn1, conn2 io.ReadWriter) (int64, error) { if UseReadv { @@ -157,31 +157,3 @@ func Relay(conn1, conn2 io.ReadWriter) (int64, error) { return io.Copy(conn2, conn1) } } - -// 阻塞. -func RelayUDP(putter UDP_Putter, extractor UDP_Extractor) { - - go func() { - for { - raddr, bs, err := extractor.GetNewUDPRequest() - if err != nil { - break - } - err = putter.WriteUDPRequest(raddr, bs) - if err != nil { - break - } - } - }() - - for { - raddr, bs, err := putter.GetNewUDPResponse() - if err != nil { - break - } - err = extractor.WriteUDPResponse(raddr, bs) - if err != nil { - break - } - } -} diff --git a/netLayer/udp_relay.go b/netLayer/udp_relay.go index 16ce8a8..e8208b9 100644 --- a/netLayer/udp_relay.go +++ b/netLayer/udp_relay.go @@ -11,6 +11,35 @@ const ( ) //本文件内含 一些 转发 udp 数据的 接口与方法 + +// 阻塞. +func RelayUDP(putter UDP_Putter, extractor UDP_Extractor) { + + go func() { + for { + raddr, bs, err := extractor.GetNewUDPRequest() + if err != nil { + break + } + err = putter.WriteUDPRequest(raddr, bs) + if err != nil { + break + } + } + }() + + for { + raddr, bs, err := putter.GetNewUDPResponse() + if err != nil { + break + } + err = extractor.WriteUDPResponse(raddr, bs) + if err != nil { + break + } + } +} + //////////////////// 接口 //////////////////// type UDPRequestReader interface { diff --git a/proxy/vless/vless.go b/proxy/vless/vless.go index b9af818..8ee8fea 100644 --- a/proxy/vless/vless.go +++ b/proxy/vless/vless.go @@ -36,11 +36,11 @@ type UserConn struct { remainFirstBufLen int //记录读取握手包头时读到的buf的长度. 如果我们读超过了这个部分的话,实际上我们就可以不再使用 optionalReader 读取, 而是直接从Conn读取 - uuid [16]byte - convertedStr string - version int - isUDP bool - isServerEnd bool //for v0 + uuid [16]byte + convertedUUIDStr string + version int + isUDP bool + isServerEnd bool //for v0 // udpUnreadPart 不为空,则表示上一次读取没读完整个包(给Read传入的buf太小),须接着读 udpUnreadPart []byte //for udp @@ -55,11 +55,11 @@ func (uc *UserConn) GetProtocolVersion() int { return uc.version } func (uc *UserConn) GetIdentityStr() string { - if uc.convertedStr == "" { - uc.convertedStr = proxy.UUIDToStr(uc.uuid) + if uc.convertedUUIDStr == "" { + uc.convertedUUIDStr = proxy.UUIDToStr(uc.uuid) } - return uc.convertedStr + return uc.convertedUUIDStr } //如果是udp,则是多线程不安全的,如果是tcp,则安不安全看底层的链接。 diff --git a/proxy/vless/vless_test.go b/proxy/vless/vless_test.go index 3b0a7f9..86e1fe5 100644 --- a/proxy/vless/vless_test.go +++ b/proxy/vless/vless_test.go @@ -15,11 +15,11 @@ import ( ) func TestVLess0(t *testing.T) { - testVLess(0, "9527", t) + testVLess(0, netLayer.RandPortStr(), t) } func TestVLess1(t *testing.T) { - testVLess(1, "9538", t) + testVLess(1, netLayer.RandPortStr(), t) } func testVLess(version int, port string, t *testing.T) { @@ -115,7 +115,7 @@ func testVLess(version int, port string, t *testing.T) { } func TestVLess0_udp(t *testing.T) { - testVLessUDP(0, "9638", t) + testVLessUDP(0, netLayer.RandPortStr(), t) } //func TestVLess1_udp(t *testing.T) { diff --git a/tlsLayer/tls_test.go b/tlsLayer/tls_test.go index 8082f4e..cd557d0 100644 --- a/tlsLayer/tls_test.go +++ b/tlsLayer/tls_test.go @@ -14,7 +14,7 @@ import ( ) func TestVlesss(t *testing.T) { - testTls("vlesss", "9507", t) + testTls("vlesss", netLayer.RandPortStr(), t) } func testTls(protocol string, port string, t *testing.T) { diff --git a/utils/pool.go b/utils/pool.go index c417e8f..5705d32 100644 --- a/utils/pool.go +++ b/utils/pool.go @@ -46,10 +46,12 @@ func init() { } } +//从Pool中获取一个 *bytes.Buffer func GetBuf() *bytes.Buffer { return bufPool.Get().(*bytes.Buffer) } +//将 buf 放回 Pool func PutBuf(buf *bytes.Buffer) { buf.Reset() bufPool.Put(buf) @@ -73,12 +75,12 @@ func PutPacket(bs []byte) { standardPacketPool.Put(bs[:c]) } +// 从Pool中获取一个 StandardBytesLength 长度的 []byte func GetMTU() []byte { return standardBytesPool.Get().([]byte)[:StandardBytesLength] } -// 从pool中获取 []byte, 在 size <= StandardBytesLength 时有最佳性能 -// 否则会直接调用 GetPacket +// 从pool中获取 []byte, 根据给出长度不同,来源于的Pool会不同. func GetBytes(size int) []byte { if size <= StandardBytesLength { bs := standardBytesPool.Get().([]byte) @@ -89,7 +91,7 @@ func GetBytes(size int) []byte { } -// 根据bs长度 选择放入各种pool中, 只有cap>=1500 才会被处理 +// 根据bs长度 选择放入各种pool中, 只有 cap(bs)>=1500 才会被处理 func PutBytes(bs []byte) { c := cap(bs) if c < StandardBytesLength { diff --git a/utils/utils.go b/utils/utils.go index d1d1d69..1591b22 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -1,7 +1,7 @@ -// Package utils provides utils that needed by all packages of verysimle +// Package utils provides utils that needed by all sub-packages in verysimle package utils -//具体实现见 readv_*.go +//具体实现见 readv_*.go; 用 GetReadVReader() 函数来获取本平台的对应实现。 type MultiReader interface { Init([][]byte) Read(fd uintptr) int32 diff --git a/vless_v1.md b/vless_v1.md index 985c9bb..6fb35c2 100644 --- a/vless_v1.md +++ b/vless_v1.md @@ -1,5 +1,8 @@ # vless v1 +目前v1仍然处于研发当中。建议先用v0,等v1完全出炉了再说,本文只是理论探索,实际代码暂未完整实现所有的设计. +## 握手协议格式 + 具体我的探讨还可以查看 https://github.com/v2fly/v2ray-core/discussions/1655 总的来说 vless v1 简化了一些流程, 约定永远使用tls(与trojan相同),并重点考虑 非多路复用的 udp over tcp的 fullcone实现。 diff --git a/ws/conn.go b/ws/conn.go index d7afa3c..82c9943 100644 --- a/ws/conn.go +++ b/ws/conn.go @@ -54,7 +54,7 @@ func (c *Conn) Read(p []byte) (int, error) { return n, e } c.remainLenForLastFrame -= int64(n) - // 这里之所以可以放心 减去 n,不怕减成负的,是因为 r的代码里 在读取一帧的数据时,用到了 io.LimitedReader, 一帧的读取长度的上限已被限定,直到 该帧完全被读完为止 + // 这里之所以可以放心 减去 n,不怕减成负的,是因为 wsutil.Reader 的代码里 在读取一帧的数据时,用到了 io.LimitedReader, 一帧的读取长度的上限已被限定,直到 该帧完全被读完为止 return n, nil } diff --git a/ws/ws_test.go b/ws/ws_test.go index 5682430..1418cf8 100644 --- a/ws/ws_test.go +++ b/ws/ws_test.go @@ -1,16 +1,19 @@ -package ws +package ws_test import ( "bytes" "crypto/rand" "net" "testing" + + "github.com/hahahrfool/v2ray_simple/netLayer" + "github.com/hahahrfool/v2ray_simple/ws" ) // ws基本读写功能测试. // 分别测试写入短数据和长数据 func TestWs(t *testing.T) { - listenAddr := "127.0.0.1:7777" + listenAddr := netLayer.GetRandLocalAddr() listener, err := net.Listen("tcp", listenAddr) if err != nil { t.Log(err) @@ -35,7 +38,7 @@ func TestWs(t *testing.T) { return } - s := NewServer(wsPath) + s := ws.NewServer(wsPath) wsConn, err := s.Handshake(conn) if err != nil { @@ -64,7 +67,7 @@ func TestWs(t *testing.T) { } }() - cli, err := NewClient(listenAddr, wsPath) + cli, err := ws.NewClient(listenAddr, wsPath) if err != nil { t.Log(err) t.FailNow()