From e732ea3c3b71df73786b84a6e696388fa388fbb6 Mon Sep 17 00:00:00 2001 From: hahahrfool <75717694+hahahrfool@users.noreply.github.com> Date: Fri, 1 Apr 2022 12:31:47 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E8=AE=A2=E4=BB=A3=E7=A0=81;=E4=BF=AE?= =?UTF-8?q?=E5=A4=8Dloglevel=E4=B8=BAdebug=E6=97=B6=E5=A4=B1=E6=95=88?= =?UTF-8?q?=E9=97=AE=E9=A2=98;dns=E8=AF=B7=E6=B1=82=E5=8A=A0=E9=94=81,?= =?UTF-8?q?=E5=B7=B2=E7=BB=8F=E5=8F=AF=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api_draft.md | 18 ++++++++ examples/multi.client.toml | 3 ++ go.mod | 25 ++++++++++- go.sum | 3 ++ grpc/grpc.go | 3 +- httpLayer/httpLayer.go | 2 +- main.go | 62 +++++++++++++++++--------- netLayer/dns.go | 91 +++++++++++++++++++++++++++----------- proxy/doc.go | 32 ++++++++------ proxy/vless/client.go | 1 + proxy/vless/vless_test.go | 2 +- quic/quic.go | 2 +- tlsLayer/tlsLayer.go | 2 +- utils/log.go | 2 +- ws/conn.go | 12 +++-- ws/server.go | 2 +- ws/ws_test.go | 8 ++++ 17 files changed, 192 insertions(+), 78 deletions(-) create mode 100644 api_draft.md diff --git a/api_draft.md b/api_draft.md new file mode 100644 index 0000000..925f995 --- /dev/null +++ b/api_draft.md @@ -0,0 +1,18 @@ + + +api草案: + +使用restful api + basic auth + +功能列表 +1. 生成toml配置文件功能 +2. 查看本次程序开始运行起所使用的流量(双向) +3. 查看自某一天开始所用掉的总流量 +4. 动态插入一个 新 inServer / outClient; +5. 动态修改 某个 inServer/outClient 的 uuid +6. 动态调节 hy手动挡阻控模式 的发送速率 +7. 动态删除一个 inServer /outClient +8. 动态控制每一个 inServer / outClient 的网速 + +坚决抵制添加其它花哨的专门供机场主使用的功能。你们机场主有不给我们开发者钱,凭啥给你干活。 + diff --git a/examples/multi.client.toml b/examples/multi.client.toml index d9dbaef..5f71ca9 100644 --- a/examples/multi.client.toml +++ b/examples/multi.client.toml @@ -9,6 +9,9 @@ default_uuid = "a684455c-b14f-11ea-bf0d-42010aaa0003" [dns] + +# dns解析仅仅是为了能够精准分流, 如果你不需要分流, 没有自定义dns需求,则不需要dns模块 + servers = [ "udp://114.114.114.114:53" # 如果把该url指向我们dokodemo监听的端口,就可以达到通过节点请求dns的目的. ] diff --git a/go.mod b/go.mod index 411d9a8..172bb9f 100644 --- a/go.mod +++ b/go.mod @@ -43,7 +43,30 @@ require ( golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 // indirect gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect - gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect ) replace github.com/lucas-clemente/quic-go => github.com/tobyxdd/quic-go v0.25.1-0.20220224051149-310bd1bfaf1f + +retract v1.1.1 + +retract v1.1.0 + +retract v1.0.9 + +retract v1.0.8 + +retract v1.0.7 + +retract v1.0.6 + +retract v1.0.5 + +retract v1.0.4 + +retract v1.0.3 + +retract v1.0.2 + +retract v1.0.1 + +retract v1.0.0 diff --git a/go.sum b/go.sum index 2feeba6..6d76af4 100644 --- a/go.sum +++ b/go.sum @@ -12,6 +12,7 @@ github.com/BurntSushi/toml v1.0.0 h1:dtDWrepsVPfW9H/4y7dDgFc2MBUSeJhlaDtK13CxFlU github.com/BurntSushi/toml v1.0.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= +github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g= @@ -142,6 +143,7 @@ github.com/onsi/gomega v1.13.0/go.mod h1:lRk9szgn8TxENtWd0Tp4c3wjlRfMTMH27I+3Je4 github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8= github.com/oschwald/maxminddb-golang v1.8.0 h1:Uh/DSnGoxsyp/KYbY1AuP0tYEwfs0sCph9p/UMXK/Hk= github.com/oschwald/maxminddb-golang v1.8.0/go.mod h1:RXZtst0N6+FY/3qCNmZMBApR19cdQj43/NM9VkrNAis= +github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/profile v1.6.0 h1:hUDfIISABYI59DyeB3OTay/HxSRwTQ8rB/H83k6r5dM= github.com/pkg/profile v1.6.0/go.mod h1:qBsxPvzyUincmltOk6iyRVxHYg4adc0OFOv72ZdLa18= @@ -202,6 +204,7 @@ go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI= go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= diff --git a/grpc/grpc.go b/grpc/grpc.go index 0a8eee8..c2c3679 100644 --- a/grpc/grpc.go +++ b/grpc/grpc.go @@ -1,5 +1,4 @@ -/* -Package grpc implements methods for grpc +/*Package grpc implements methods for grpc 从stream.proto 生成 stream.pb.go 和 stream_grpc.pb.go: diff --git a/httpLayer/httpLayer.go b/httpLayer/httpLayer.go index 62c0335..7bec416 100644 --- a/httpLayer/httpLayer.go +++ b/httpLayer/httpLayer.go @@ -1,5 +1,5 @@ /* -Package httpLayer 提供http层的一些方法和定义. +Package httpLayer provides methods and definitions for http layer 比如fallback一般由httpLayer处理 */ diff --git a/main.go b/main.go index 29cf46e..3df2f45 100644 --- a/main.go +++ b/main.go @@ -321,7 +321,6 @@ func listenSer(inServer proxy.Server, defaultOutClientForThis proxy.Client) { ce.Write( zap.String("protocol", proxy.GetFullName(inServer)), - zap.String("network", inServer.Network()), zap.String("addr", inServer.AddrStr()), ) //log.Printf("%s is listening %s on %s\n", , , ) @@ -342,7 +341,6 @@ func listenSer(inServer proxy.Server, defaultOutClientForThis proxy.Client) { ce.Write( zap.String("protocol", proxy.GetFullName(inServer)), - zap.String("network", inServer.Network()), zap.String("addr", inServer.AddrStr()), ) //log.Printf("%s is listening %s on %s\n", proxy.GetFullName(inServer), network, inServer.AddrStr()) @@ -744,20 +742,33 @@ afterLocalServerHandshake: ////////////////////////////// DNS解析阶段 ///////////////////////////////////// + //dns解析会试图解析域名并将ip放入 targetAddr中 + // 因为在direct时,netLayer.Addr 拨号时,会优先选用ip拨号,而且我们下面的分流阶段 如果使用ip的话, + // 可以利用geoip文件, 可以做到国别分流. + if dnsMachine != nil && (targetAddr.Name != "" && len(targetAddr.IP) == 0) && targetAddr.Network != "unix" { - //log.Println("will query", targetAddr.Name) + + if ce := utils.CanLogDebug("querying"); ce != nil { + ce.Write(zap.String("domain", targetAddr.Name)) + } + ip := dnsMachine.Query(targetAddr.Name, dns.TypeA) if ip == nil { ip = dnsMachine.Query(targetAddr.Name, dns.TypeAAAA) } if ip != nil { targetAddr.IP = ip + + if ce2 := utils.CanLogDebug("dns query result"); ce2 != nil { + ce2.Write(zap.String("domain", targetAddr.Name), zap.String("ip", ip.String())) + } } } ////////////////////////////// 分流阶段 ///////////////////////////////////// var client proxy.Client = iics.defaultClient + routed := false //尝试分流, 获取到真正要发向 的 outClient if routePolicy != nil && !inServer.CantRoute() { @@ -768,8 +779,7 @@ afterLocalServerHandshake: } if ce := utils.CanLogDebug("try routing"); ce != nil { - //log.Printf("try routing %v\n", desc) - ce.Write(zap.Any("desc", desc)) + ce.Write(zap.Any("source", desc)) } outtag := routePolicy.GetOutTag(desc) @@ -777,9 +787,9 @@ afterLocalServerHandshake: if outtag == "direct" { client = directClient iics.routedToDirect = true + routed = true if ce := utils.CanLogInfo("routed to direct"); ce != nil { - //log.Printf("routed to direct %s\n", targetAddr.UrlString()) ce.Write( zap.String("target", targetAddr.UrlString()), ) @@ -789,17 +799,29 @@ afterLocalServerHandshake: if tagC, ok := clientsTagMap[outtag]; ok { client = tagC - if ce := utils.CanLogInfo("routed to"); ce != nil { - //log.Printf("routed to %s %s\n", outtag, proxy.GetFullName(client)) + routed = true + if ce := utils.CanLogInfo("routed"); ce != nil { ce.Write( - zap.String("outtag", outtag), - zap.String("client", proxy.GetFullName(client)), + zap.Any("source", desc), + zap.String("to outtag", outtag), + zap.String("P", proxy.GetFullName(client)), + zap.String("addr", client.AddrStr()), ) } } } } + if !routed { + if ce := utils.CanLogDebug("not routed, using default"); ce != nil { + ce.Write( + zap.Any("source", targetAddr.String()), + zap.String("client", proxy.GetFullName(client)), + zap.String("addr", client.AddrStr()), + ) + } + } + ////////////////////////////// 特殊处理阶段 ///////////////////////////////////// // 下面几段用于处理 tls lazy @@ -999,13 +1021,14 @@ func dialClient(iics incomingInserverConnState, targetAddr netLayer.Addr, client if ce := utils.CanLogDebug("request isn't the appointed domain"); ce != nil { if uniqueTestDomain != "" && uniqueTestDomain != targetAddr.Name { + ce.Write( zap.String("request", targetAddr.String()), zap.String("uniqueTestDomain", uniqueTestDomain), ) + return nil, utils.NumErr{N: 1, Prefix: "dialClient err, "} } - return nil, utils.NumErr{N: 1, Prefix: "dialClient err, "} } if ce := utils.CanLogInfo("Request"); ce != nil { @@ -1100,7 +1123,10 @@ func dialClient(iics incomingInserverConnState, targetAddr netLayer.Addr, client tlsConn, err := client.GetTLS_Client().Handshake(clientConn) if err != nil { - log.Printf("failed in handshake outClient tls %s, Reason: %s\n", targetAddr.String(), err) + if ce := utils.CanLogErr("failed in handshake outClient tls"); ce != nil { + ce.Write(zap.String("target", targetAddr.String()), zap.Error(err)) + } + return nil, utils.NumErr{N: 4, Prefix: "dialClient err, "} } @@ -1118,7 +1144,6 @@ advLayerStep: clientConn, err = client.DialSubConnFunc()(dailedCommonConn) if err != nil { if ce := utils.CanLogErr("DialSubConnFunc failed"); ce != nil { - //log.Printf("DialSubConnFunc failed, %s\n", err) ce.Write( zap.Error(err), ) @@ -1130,7 +1155,6 @@ advLayerStep: grpcClientConn, err = grpc.ClientHandshake(clientConn, &realTargetAddr) if err != nil { if ce := utils.CanLogErr("grpc.ClientHandshake failed"); ce != nil { - //log.Printf("grpc.ClientHandshake failed, %s\n", err) ce.Write(zap.Error(err)) } @@ -1146,7 +1170,6 @@ advLayerStep: clientConn, err = grpc.DialNewSubConn(client.Path(), grpcClientConn, &realTargetAddr) if err != nil { if ce := utils.CanLogErr("grpc.DialNewSubConn failed"); ce != nil { - //log.Printf("grpc.DialNewSubConn failed,%s\n", err) ce.Write(zap.Error(err)) @@ -1171,8 +1194,7 @@ advLayerStep: edBuf = edBuf[:ws.MaxEarlyDataLen] n, e := wlc.Read(edBuf) if e != nil { - if ce := utils.CanLogErr("reading ws early data"); ce != nil { - //log.Printf("err when reading ws early data %s\n", e) + if ce := utils.CanLogErr("failed to read ws early data"); ce != nil { ce.Write(zap.Error(e)) } return nil, utils.NumErr{N: 7, Prefix: "dialClient err, "} @@ -1195,11 +1217,9 @@ advLayerStep: wc, err = wsClient.Handshake(clientConn) } - //wc, err := wsClient.Handshake(clientConn, ed) + if err != nil { if ce := utils.CanLogErr("failed in handshake ws"); ce != nil { - //log.Printf("failed in handshake ws to %s , Reason: %s\n", targetAddr.String(), err) - ce.Write( zap.String("target", targetAddr.String()), zap.Error(err), @@ -1217,8 +1237,6 @@ advLayerStep: wrc, err := client.Handshake(clientConn, targetAddr) if err != nil { if ce := utils.CanLogErr("failed in handshake"); ce != nil { - //log.Printf("failed in handshake to %s , Reason: %s\n", targetAddr.String(), err) - ce.Write( zap.String("target", targetAddr.String()), zap.Error(err), diff --git a/netLayer/dns.go b/netLayer/dns.go index abf36d1..de5aa9d 100644 --- a/netLayer/dns.go +++ b/netLayer/dns.go @@ -3,6 +3,7 @@ package netLayer import ( "net" "net/netip" + "strings" "sync" "github.com/hahahrfool/v2ray_simple/utils" @@ -10,12 +11,28 @@ import ( "go.uber.org/zap" ) -func DNSQuery(domain string, dns_type uint16, conn *dns.Conn, recursionCount int) net.IP { +var globalDnsQueryMutex sync.Mutex + +//domain必须是 dns.Fqdn 函数 包过的, 本函数不检查是否包过。如果不包过就传入,会报错。 +// dns_type 为 miekg/dns 包中定义的类型, 如 TypeA, TypeAAAA, TypeCNAME. +// conn是一个建立好的 dns.Conn, 必须非空, 本函数不检查. +// theMux是与 conn相匹配的mutex, 这是为了防止同时有多个请求导致无法对口;内部若判断为nil,会主动使用一个全局mux. +// recursionCount 使用者统一填0 即可,用于内部 遇到cname时进一步查询时防止无限递归. +func DNSQuery(domain string, dns_type uint16, conn *dns.Conn, theMux *sync.Mutex, recursionCount int) net.IP { m := new(dns.Msg) m.SetQuestion((domain), dns_type) //为了更快,不使用 dns.Fqdn, 请调用之前先确保ok c := new(dns.Client) + if theMux == nil { + theMux = &globalDnsQueryMutex + } + + theMux.Lock() + r, _, err := c.ExchangeWithConn(m, conn) + + theMux.Unlock() + if r == nil { if ce := utils.CanLogErr("dns query read err"); ce != nil { ce.Write(zap.Error(err)) @@ -56,44 +73,52 @@ func DNSQuery(domain string, dns_type uint16, conn *dns.Conn, recursionCount int if recursionCount > 2 { //不准循环递归,否则就是bug;因为有可能两个域名cname相互指向对方,好坏 - if ce := utils.CanLogDebug("dns query got cname bug recursionCount>2"); ce != nil { - ce.Write(zap.String("query", domain), zap.String("target", aa.Target)) + if ce := utils.CanLogDebug("dns query got cname but recursionCount>2"); ce != nil { + ce.Write(zap.String("query", domain), zap.String("cname", aa.Target)) } return nil } - return DNSQuery(aa.Target, dns_type, conn, recursionCount+1) + return DNSQuery(dns.Fqdn(aa.Target), dns_type, conn, theMux, recursionCount+1) } } return nil } +// 给 miekg/dns.Conn 加一个互斥锁, 可保证同一时间仅有一个请求发生 +// 这样就不会造成并发时的混乱 +type DnsConn struct { + *dns.Conn + mutex sync.Mutex +} + //dns machine维持与多个dns服务器的连接(最好是udp这种无状态的),并可以发起dns请求 // 会缓存dns记录 type DNSMachine struct { - DefaultConn *dns.Conn - conns map[string]*dns.Conn + DefaultConn DnsConn + conns map[string]*DnsConn cache map[string]net.IP SpecialIPPollicy map[string][]netip.Addr SpecialServerPollicy map[string]string //domain -> dns server name 的map - mux sync.RWMutex + mutex sync.RWMutex //读写 conns, cache, SpecialIPPollicy, SpecialServerPollicy 时所使用的 mutex + } -//并不初始化所有内部成员 -func NewDnsMachine(defaultAddr *Addr) *DNSMachine { +//并不初始化所有内部成员, 只是创建并拨个号,若为nil则号也不拨 +func NewDnsMachine(defaultDnsServerAddr *Addr) *DNSMachine { var dm DNSMachine - if defaultAddr != nil { + if defaultDnsServerAddr != nil { var conn net.Conn var err error - if defaultAddr.IsUDP() { - conn, err = net.DialUDP("udp", nil, defaultAddr.ToUDPAddr()) + if defaultDnsServerAddr.IsUDP() { + conn, err = net.DialUDP("udp", nil, defaultDnsServerAddr.ToUDPAddr()) } else { - conn, err = defaultAddr.Dial() + conn, err = defaultDnsServerAddr.Dial() } if err != nil { @@ -104,15 +129,15 @@ func NewDnsMachine(defaultAddr *Addr) *DNSMachine { dc := new(dns.Conn) dc.Conn = conn - dm.DefaultConn = dc + dm.DefaultConn.Conn = dc } return &dm } func (dm *DNSMachine) SetDefaultConn(c net.Conn) { - dm.DefaultConn = new(dns.Conn) - dm.DefaultConn.Conn = c + dm.DefaultConn.Conn = new(dns.Conn) + dm.DefaultConn.Conn.Conn = c } //name为该dns服务器的名称 @@ -120,28 +145,38 @@ func (dm *DNSMachine) AddConnForServer(name string, c net.Conn) { dc := new(dns.Conn) dc.Conn = c if dm.conns == nil { - dm.conns = make(map[string]*dns.Conn) + dm.conns = map[string]*DnsConn{} } - dm.conns[name] = dc + dcc := &DnsConn{Conn: dc} + dm.conns[name] = dcc } +//传入的domain必须是不带尾缀点号的domain, 即没有包过 Fqdn func (dm *DNSMachine) Query(domain string, dns_type uint16) (ip net.IP) { + var cacheHit bool defer func() { - if len(ip) > 0 { - //log.Println("will add to cache", domain, ip) + if cacheHit { + return + } - dm.mux.Lock() + if len(ip) > 0 { + if ce := utils.CanLogDebug("will add to dns cache"); ce != nil { + ce.Write(zap.String("domain", domain)) + } + + dm.mutex.Lock() if dm.cache == nil { dm.cache = make(map[string]net.IP) } + domain = strings.TrimSuffix(domain, ".") dm.cache[domain] = ip - dm.mux.Unlock() + dm.mutex.Unlock() } }() - dm.mux.RLock() - defer dm.mux.RUnlock() + dm.mutex.RLock() + defer dm.mutex.RUnlock() //先从 cache找,有就直接返回 //然后, @@ -152,6 +187,10 @@ func (dm *DNSMachine) Query(domain string, dns_type uint16) (ip net.IP) { if dm.cache != nil { if ip = dm.cache[domain]; ip != nil { + cacheHit = true + if ce := utils.CanLogDebug("hit dns cache"); ce != nil { + ce.Write(zap.String("domain", domain)) + } return } } @@ -180,7 +219,7 @@ func (dm *DNSMachine) Query(domain string, dns_type uint16) (ip net.IP) { } } - theDNSServerConn := dm.DefaultConn + theDNSServerConn := &dm.DefaultConn if dm.conns != nil && dm.SpecialServerPollicy != nil { if sn := dm.SpecialServerPollicy[domain]; sn != "" { @@ -192,5 +231,5 @@ func (dm *DNSMachine) Query(domain string, dns_type uint16) (ip net.IP) { } domain = dns.Fqdn(domain) - return DNSQuery(domain, dns_type, theDNSServerConn, 0) + return DNSQuery(domain, dns_type, theDNSServerConn.Conn, &theDNSServerConn.mutex, 0) } diff --git a/proxy/doc.go b/proxy/doc.go index 101e23f..4d179f7 100644 --- a/proxy/doc.go +++ b/proxy/doc.go @@ -1,4 +1,4 @@ -/*Package proxy 定义了代理转发所需的必备组件. +/*Package proxy defines necessary components for proxy. Layer Definition @@ -24,21 +24,25 @@ New Model - VSI 新的VSI 模型 那么我们verysimple实际上就是 基于 “层” 的架构,或称 可分层结构. - 9 | tcp data - -------------------- - 8 | vless/trojan/socks5 - -------------------- - 7 | ws/grpc - -------------------- - 6 | http - -------------------- - 5 | tls - -------------------- - 4 | tcp - -------------------- + 9 | client real tcp data + ---------------------------------------- + 8 | vless/trojan/socks5 + ---------------------------------------- + 7 | ws/grpc/quic + ---------------------------------------- + 6 | http (headers) + ---------------------------------------- + 5 | tls + ---------------------------------------- + 4 | tcp/udp/unix domain socket + ---------------------------------------- -基本上5-8层都是可控的. +基本上5-8层都是可控的.第四层也可以给出一些参数进行控制,比如在tproxy时。 + +实际上quic属于一种超级协议,横跨传输层一直到高级层,不过为了分类方便,这里认为它也是一种 高级层. + +也就是说,如果遇到横跨多个层的协议,我们认为它属于其中最高的层级。 对应的理想配置文件应该如下. diff --git a/proxy/vless/client.go b/proxy/vless/client.go index 7b76687..7fe17e6 100644 --- a/proxy/vless/client.go +++ b/proxy/vless/client.go @@ -121,6 +121,7 @@ func (c *Client) Handshake(underlay net.Conn, target netLayer.Addr) (io.ReadWrit //log.Println("尝试拨号 Cmd_CRUMFURS 信道") + //这段代码明显有问题,如果直接dial的话,那就是脱离tls的裸协议,所以这里以后需要处理一下 UMFURS_conn, err := target.Dial() if err != nil { if ce := utils.CanLogErr("尝试拨号 Cmd_CRUMFURS 信道时发生错误"); ce != nil { diff --git a/proxy/vless/vless_test.go b/proxy/vless/vless_test.go index f3567ad..beade95 100644 --- a/proxy/vless/vless_test.go +++ b/proxy/vless/vless_test.go @@ -160,7 +160,7 @@ func testVLessUDP(version int, port string, t *testing.T) { count := 0 for { - t.Log(" udp for! ") + //t.Log(" udp for! ") // 读取数据 readNum, remoteAddr, err := fakeRealUDPServerListener.ReadFromUDP(readbuf) if err != nil { diff --git a/quic/quic.go b/quic/quic.go index 90ad20d..adc1ac1 100644 --- a/quic/quic.go +++ b/quic/quic.go @@ -1,4 +1,4 @@ -//Package quic 实现高级层中的quic +//Package quic defines functions to listen and dial quic, with some customizable congestion settings. package quic import ( diff --git a/tlsLayer/tlsLayer.go b/tlsLayer/tlsLayer.go index c331ba1..37b9c9c 100644 --- a/tlsLayer/tlsLayer.go +++ b/tlsLayer/tlsLayer.go @@ -1,5 +1,5 @@ /* -Package tlsLayer 提供tls层的各种支持. 也包括tls流量的嗅探功能 +Package tlsLayer provides support for tlsLayer, including sniffing. */ package tlsLayer diff --git a/utils/log.go b/utils/log.go index 39b8232..6c1d2b3 100644 --- a/utils/log.go +++ b/utils/log.go @@ -1,4 +1,4 @@ -// Package utils provides utils that needed by all sub-packages in verysimle +// Package utils provides utilities that is used in all sub-packages in verysimple package utils import ( diff --git a/ws/conn.go b/ws/conn.go index 5246cba..f53bfe5 100644 --- a/ws/conn.go +++ b/ws/conn.go @@ -47,7 +47,7 @@ func (c *Conn) Read(p []byte) (int, error) { // https://www.rfc-editor.org/rfc/rfc6455#section-5.2 // (使用了 Extended payload length 字段) // 肯定会有多读的情况,此时如果一次用 wsutil.ReadServerBinary()的话,那么服务器缓存就超大,不可能如此实现 - // (wsutil.ReadServerBinary内部使用了 io.ReadAll, 而ReadAll是会无限增长内存的 + // ( wsutil.ReadServerBinary内部使用了 io.ReadAll, 而ReadAll是会无限增长内存的 ) // 所以我们肯定要分段读, 直接用 wsutil.Reader.Read 即可, 但是每个Read前必须要有 NextFrame调用 // //关于读 的完整过程,建议参考 ws/example.autoban.go 里的 wsHandler 函数 @@ -70,7 +70,6 @@ func (c *Conn) Read(p []byte) (int, error) { } if h.OpCode.IsControl() { //log.Println("Got control frame") - //return 0, nil // 控制帧已经在我们的 OnIntermediate 里被处理了, 直接读取下一个数据即可 return c.Read(p) @@ -88,8 +87,7 @@ func (c *Conn) Read(p []byte) (int, error) { OpPong OpCode = 0xa */ - //log.Println("OpCode not Binary", h.OpCode) - return 0, utils.ErrInErr{ErrDesc: "ws OpCode not Binary", Data: h.OpCode} + return 0, utils.ErrInErr{ErrDesc: "ws OpCode not OpBinary/OpContinuation", Data: h.OpCode} } //log.Println("Read next frame header ok,", h.Length, c.r.State.Fragmented(), "givenbuf len", len(p)) @@ -102,9 +100,9 @@ func (c *Conn) Read(p []byte) (int, error) { // 但是后来发现,只有 fragmented的情况下,才会处理EOF,否则还是会传递到我们这里 // 也就是说,websocket虽然一个数据帧可以超大,但是 还有一种 分片功能,而如果不分片的话,gobwas就不处理EOF - //经过实测,如果数据比较小的话,就不会分片,此时就会出现EOF; 如果数据比较大,比如 4327,就要分片 + //经过实测,如果数据比较小的话,就不会分片,此时就会出现EOF; 如果数据比较大,比如 4327,某客户端就可能选择分片 - //这种产生EOF的情况,时 gobwas/ws包的一种特性,这样可以说每一次读取都能有明确的EOF边界,便于使用 io.ReadAll + //这种产生EOF的情况,是 gobwas/ws包的一种特性,这样可以说每一次读取都能有明确的EOF边界,便于使用 io.ReadAll n, e := c.r.Read(p) //log.Println("read data result", e, n, h.Length) @@ -169,7 +167,7 @@ func (c *Conn) ReadFrom(r io.Reader) (written int64, err error) { if rt, ok := c.Conn.(io.ReaderFrom); ok { return rt.ReadFrom(r) } else { - panic("uc.underlayIsBasic, but can't cast to ReadFrom") + panic("ws.Conn underlayIsBasic, but can't cast to ReadFrom") } } diff --git a/ws/server.go b/ws/server.go index 38e2495..0a1792f 100644 --- a/ws/server.go +++ b/ws/server.go @@ -16,7 +16,7 @@ import ( ) // 2048 /3 = 682.6666 , -// 683 * 4 = 2732 +// 683 * 4 = 2732, 若你不信,运行 we_test.go中的 TestBase64Len const MaxEarlyDataLen_Base64 = 2732 type Server struct { diff --git a/ws/ws_test.go b/ws/ws_test.go index 1214132..57e74b0 100644 --- a/ws/ws_test.go +++ b/ws/ws_test.go @@ -3,6 +3,7 @@ package ws_test import ( "bytes" "crypto/rand" + "encoding/base64" "net" "testing" @@ -10,6 +11,13 @@ import ( "github.com/hahahrfool/v2ray_simple/ws" ) +func TestBase64Len(t *testing.T) { + var arr [2048]byte + str := base64.StdEncoding.EncodeToString(arr[:]) + t.Log(len(str)) //2732 + //t.Log((str)) //一堆A后面跟一个等号 +} + // ws基本读写功能测试. // 分别测试写入短数据和长数据 func TestWs(t *testing.T) {