mirror of
https://github.com/e1732a364fed/v2ray_simple.git
synced 2025-10-08 10:10:27 +08:00
全面修订代码;完成 grpcSimple包;使用 tag选择编译quic 和 grpc
grpcSimple包的服务端和客户端现在都已完成,且兼容v2ray等内核。 grpcSimple包 简洁、高效,更加科学。暂不支持multiMode。 若 grpc_full 给出,则使用grpc包,否则默认使用 grpcSimple包。 若 noquic给出,则不使用 quic,否则 默认使用 quic。 修复 ws early 失效问题;
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
![GoVersion][10] [![GoDoc][1]][2] [![MIT licensed][3]][4] [![Go Report Card][5]][6] [![Downloads][7]][8] [![release][9]][8]
|
||||
|
||||
[1]: https://godoc.org/github.com/e1732a364fed/v2ray_simple?status.svg
|
||||
[2]: https://godoc.org/github.com/e1732a364fed/v2ray_simple
|
||||
[1]: https://pkg.go.dev/badge/github.com/e1732a364fed/v2ray_simple.svg
|
||||
[2]: https://pkg.go.dev/github.com/e1732a364fed/v2ray_simple#section-readme
|
||||
[3]: https://img.shields.io/badge/license-MIT-blue.svg
|
||||
[4]: LICENSE
|
||||
[5]: https://goreportcard.com/badge/github.com/e1732a364fed/v2ray_simple
|
||||
|
@@ -4,7 +4,6 @@ package advLayer
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
@@ -13,10 +12,11 @@ import (
|
||||
"github.com/e1732a364fed/v2ray_simple/utils"
|
||||
)
|
||||
|
||||
var ErrPreviousFull = errors.New("previous conn full")
|
||||
//var ErrPreviousFull = errors.New("previous conn full")
|
||||
|
||||
var ProtocolsMap = make(map[string]Creator)
|
||||
|
||||
//为了避免黑客攻击,我们固定earlydata最大值为2048
|
||||
var MaxEarlyDataLen = 2048 //for ws early data
|
||||
|
||||
func PrintAllProtocolNames() {
|
||||
@@ -31,6 +31,9 @@ type Creator interface {
|
||||
//NewClientFromURL(url *url.URL) (Client, error)
|
||||
NewClientFromConf(conf *Conf) (Client, error)
|
||||
NewServerFromConf(conf *Conf) (Server, error)
|
||||
|
||||
GetDefaultAlpn() (alpn string, mustUse bool)
|
||||
PackageID() string
|
||||
}
|
||||
|
||||
type Conf struct {
|
||||
@@ -45,12 +48,12 @@ type Conf struct {
|
||||
}
|
||||
|
||||
type Client interface {
|
||||
GetPath() string
|
||||
IsMux() bool //quic and grpc. if IsMux, then Client is a MuxClient, or it's a SingleClient
|
||||
IsEarly() bool //is 0-rtt or not.
|
||||
|
||||
IsSuper() bool // quic handles transport layer dialing and tls layer handshake directly.
|
||||
|
||||
GetPath() string
|
||||
IsEarly() bool //is 0-rtt or not.
|
||||
|
||||
}
|
||||
|
||||
// ws (h1.1)
|
||||
@@ -68,6 +71,7 @@ type MuxClient interface {
|
||||
// If IsSuper, underlay should be nil;
|
||||
//
|
||||
// If not IsSuper and underlay == nil, it will return error if it can't find any extablished connection.
|
||||
// Usually underlay is tls.Conn.
|
||||
GetCommonConn(underlay net.Conn) (conn any, err error)
|
||||
|
||||
DialSubConn(underlay any) (net.Conn, error)
|
||||
@@ -76,11 +80,11 @@ type MuxClient interface {
|
||||
}
|
||||
|
||||
type Server interface {
|
||||
IsMux() bool //quic and grpc. if IsMux, then Server is a MuxServer, or it's a SingleServer
|
||||
IsSuper() bool //quic
|
||||
|
||||
GetPath() string //for ws and grpc
|
||||
|
||||
IsMux() bool //quic and grpc. if IsMux, then Server is a MuxServer, or it's a SingleServer
|
||||
|
||||
IsSuper() bool //quic
|
||||
}
|
||||
|
||||
//ws
|
||||
|
@@ -166,12 +166,14 @@ func (c *streamClient) multitun_withName(ctx context.Context, name string, opts
|
||||
type Client struct {
|
||||
ServerAddr netLayer.Addr
|
||||
Path string
|
||||
ismulti bool
|
||||
}
|
||||
|
||||
func NewClient(addr netLayer.Addr, path string) (*Client, error) {
|
||||
func NewClient(addr netLayer.Addr, path string, ismulti bool) (*Client, error) {
|
||||
return &Client{
|
||||
ServerAddr: addr,
|
||||
Path: path,
|
||||
ismulti: ismulti,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -211,7 +213,7 @@ func (c *Client) DialSubConn(underlay any) (net.Conn, error) {
|
||||
return nil, utils.ErrNilParameter
|
||||
}
|
||||
if cc, ok := underlay.(ClientConn); ok {
|
||||
return DialNewSubConn(c.Path, cc, &c.ServerAddr, false)
|
||||
return DialNewSubConn(c.Path, cc, &c.ServerAddr, c.ismulti)
|
||||
} else {
|
||||
return nil, utils.ErrInvalidParameter
|
||||
}
|
||||
|
@@ -24,7 +24,9 @@ https://github.com/v2fly/v2ray-core/pull/757
|
||||
*/
|
||||
package grpc
|
||||
|
||||
import "github.com/e1732a364fed/v2ray_simple/advLayer"
|
||||
import (
|
||||
"github.com/e1732a364fed/v2ray_simple/advLayer"
|
||||
)
|
||||
|
||||
func init() {
|
||||
advLayer.ProtocolsMap["grpc"] = Creator{}
|
||||
@@ -32,8 +34,27 @@ func init() {
|
||||
|
||||
type Creator struct{}
|
||||
|
||||
func (Creator) PackageID() string {
|
||||
return "grpc"
|
||||
}
|
||||
|
||||
func (Creator) GetDefaultAlpn() (alpn string, mustUse bool) {
|
||||
// v2ray 和 xray 的grpc 因为没有自己处理tls,直接用grpc包处理的tls,而grpc包对alpn有严格要求, 要用h2.
|
||||
return "h2", true
|
||||
}
|
||||
|
||||
func (Creator) NewClientFromConf(conf *advLayer.Conf) (advLayer.Client, error) {
|
||||
return NewClient(conf.Addr, conf.Path)
|
||||
grpc_multi := false
|
||||
if extra := conf.Extra; len(extra) > 0 {
|
||||
if thing := extra["grpc_multi"]; thing != nil {
|
||||
if use_multi, ok := thing.(bool); ok {
|
||||
grpc_multi = use_multi
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return NewClient(conf.Addr, conf.Path, grpc_multi)
|
||||
}
|
||||
|
||||
func (Creator) NewServerFromConf(conf *advLayer.Conf) (advLayer.Server, error) {
|
||||
|
@@ -5,20 +5,19 @@ package grpcSimple
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/e1732a364fed/v2ray_simple/utils"
|
||||
"go.uber.org/atomic"
|
||||
"go.uber.org/zap"
|
||||
"golang.org/x/net/http2"
|
||||
)
|
||||
|
||||
@@ -26,9 +25,10 @@ var (
|
||||
ErrInvalidLength = errors.New("invalid length")
|
||||
)
|
||||
|
||||
var defaultHeader = http.Header{
|
||||
var defaultClientHeader = http.Header{
|
||||
"content-type": []string{"application/grpc"},
|
||||
"user-agent": []string{"grpc-go/1.36.0"},
|
||||
"user-agent": []string{"grpc-go/1.41.0"},
|
||||
"Te": []string{"trailers"},
|
||||
}
|
||||
|
||||
//implements net.Conn
|
||||
@@ -44,7 +44,9 @@ type ClientConn struct {
|
||||
br *bufio.Reader
|
||||
|
||||
// deadlines
|
||||
deadline *time.Timer
|
||||
timeouter
|
||||
|
||||
client *Client
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
@@ -52,7 +54,7 @@ type Config struct {
|
||||
Host string
|
||||
}
|
||||
|
||||
func (g *ClientConn) initRequest() {
|
||||
func (g *ClientConn) handshake() {
|
||||
response, err := g.transport.RoundTrip(g.request)
|
||||
if err != nil {
|
||||
g.err = err
|
||||
@@ -61,15 +63,33 @@ func (g *ClientConn) initRequest() {
|
||||
}
|
||||
|
||||
if !g.close.Load() {
|
||||
//log.Println("response headers", response.Header)
|
||||
|
||||
if ct := response.Header.Get("Content-Type"); ct != "application/grpc" {
|
||||
if ce := utils.CanLogWarn("GRPC Client got wrong Content-Type"); ce != nil {
|
||||
ce.Write(zap.String("type", ct))
|
||||
}
|
||||
|
||||
g.client.cachedTransport = nil
|
||||
|
||||
response.Body.Close()
|
||||
return
|
||||
}
|
||||
|
||||
g.response = response
|
||||
g.br = bufio.NewReader(response.Body)
|
||||
} else {
|
||||
|
||||
g.client.cachedTransport = nil
|
||||
|
||||
response.Body.Close()
|
||||
}
|
||||
}
|
||||
|
||||
func (g *ClientConn) Read(b []byte) (n int, err error) {
|
||||
g.once.Do(g.initRequest)
|
||||
|
||||
g.once.Do(g.handshake)
|
||||
|
||||
if g.err != nil {
|
||||
return 0, g.err
|
||||
}
|
||||
@@ -133,6 +153,10 @@ func (g *ClientConn) Write(b []byte) (n int, err error) {
|
||||
if err == io.ErrClosedPipe && g.err != nil {
|
||||
err = g.err
|
||||
}
|
||||
if err != nil {
|
||||
g.client.dealErr(err)
|
||||
|
||||
}
|
||||
|
||||
return len(b), err
|
||||
}
|
||||
@@ -146,110 +170,101 @@ func (g *ClientConn) Close() error {
|
||||
return g.writer.Close()
|
||||
}
|
||||
|
||||
func (g *ClientConn) LocalAddr() net.Addr { return nil }
|
||||
func (g *ClientConn) RemoteAddr() net.Addr { return nil }
|
||||
func (g *ClientConn) SetReadDeadline(t time.Time) error { return g.SetDeadline(t) }
|
||||
func (g *ClientConn) SetWriteDeadline(t time.Time) error { return g.SetDeadline(t) }
|
||||
|
||||
func (g *ClientConn) SetDeadline(t time.Time) error {
|
||||
d := time.Until(t)
|
||||
if g.deadline != nil {
|
||||
g.deadline.Reset(d)
|
||||
return nil
|
||||
}
|
||||
g.deadline = time.AfterFunc(d, func() {
|
||||
g.Close()
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
const tlsTimeout = time.Second * 5
|
||||
|
||||
func NewHTTP2Client(
|
||||
rawTCPConn net.Conn,
|
||||
tlsConfig *tls.Config,
|
||||
) *http2.Transport {
|
||||
type Client struct {
|
||||
Config
|
||||
|
||||
dialFunc := func(_, _ string, cfg *tls.Config) (net.Conn, error) {
|
||||
curBaseConn net.Conn //一般为 tlsConn
|
||||
|
||||
cn := tls.Client(rawTCPConn, cfg)
|
||||
theRequest http.Request
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), tlsTimeout)
|
||||
defer cancel()
|
||||
if err := cn.HandshakeContext(ctx); err != nil {
|
||||
rawTCPConn.Close()
|
||||
return nil, err
|
||||
}
|
||||
state := cn.ConnectionState()
|
||||
if p := state.NegotiatedProtocol; p != http2.NextProtoTLS {
|
||||
cn.Close()
|
||||
return nil, utils.ErrInErr{
|
||||
ErrDesc: "grpcHardcore, http2: unexpected ALPN protocol",
|
||||
ErrDetail: utils.ErrInvalidData,
|
||||
Data: p,
|
||||
}
|
||||
}
|
||||
return cn, nil
|
||||
cachedTransport *http2.Transport
|
||||
|
||||
path string
|
||||
}
|
||||
|
||||
return &http2.Transport{
|
||||
DialTLS: dialFunc,
|
||||
TLSClientConfig: tlsConfig,
|
||||
func (g *Client) dealErr(err error) {
|
||||
//use of closed connection
|
||||
if strings.Contains(err.Error(), "use of closed") {
|
||||
g.cachedTransport = nil
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Client) GetPath() string {
|
||||
return c.ServiceName
|
||||
}
|
||||
|
||||
func (c *Client) IsSuper() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (c *Client) IsMux() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (c *Client) IsEarly() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// 由于 本包应用了 http2包, 无法获取特定连接, 所以返回 underlay 本身
|
||||
func (c *Client) GetCommonConn(underlay net.Conn) (any, error) {
|
||||
|
||||
if underlay == nil {
|
||||
if c.cachedTransport != nil {
|
||||
return c.cachedTransport, nil
|
||||
} else {
|
||||
return nil, nil
|
||||
}
|
||||
} else {
|
||||
return underlay, nil
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Client) ProcessWhenFull(underlay any) {}
|
||||
|
||||
func (c *Client) DialSubConn(underlay any) (net.Conn, error) {
|
||||
|
||||
if underlay == nil {
|
||||
return nil, utils.ErrNilParameter
|
||||
}
|
||||
|
||||
var transport *http2.Transport
|
||||
|
||||
if t, ok := underlay.(*http2.Transport); ok && t != nil {
|
||||
transport = t
|
||||
} else {
|
||||
transport = &http2.Transport{
|
||||
DialTLS: func(_, _ string, cfg *tls.Config) (net.Conn, error) {
|
||||
return underlay.(net.Conn), nil
|
||||
},
|
||||
AllowHTTP: false,
|
||||
DisableCompression: true,
|
||||
PingTimeout: 0,
|
||||
}
|
||||
}
|
||||
|
||||
func StreamGunWithTransport(transport *http2.Transport, cfg *Config) (net.Conn, error) {
|
||||
serviceName := "GunService"
|
||||
if cfg.ServiceName != "" {
|
||||
serviceName = cfg.ServiceName
|
||||
c.cachedTransport = transport
|
||||
}
|
||||
|
||||
reader, writer := io.Pipe()
|
||||
request := &http.Request{
|
||||
Method: http.MethodPost,
|
||||
Body: reader,
|
||||
URL: &url.URL{
|
||||
Scheme: "https",
|
||||
Host: cfg.Host,
|
||||
Path: fmt.Sprintf("/%s/Tun", serviceName),
|
||||
// for unescape path
|
||||
Opaque: fmt.Sprintf("//%s/%s/Tun", cfg.Host, serviceName),
|
||||
},
|
||||
Proto: "HTTP/2",
|
||||
ProtoMajor: 2,
|
||||
ProtoMinor: 0,
|
||||
Header: defaultHeader,
|
||||
}
|
||||
|
||||
request := c.theRequest
|
||||
request.Body = reader
|
||||
|
||||
conn := &ClientConn{
|
||||
request: request,
|
||||
request: &request,
|
||||
transport: transport,
|
||||
writer: writer,
|
||||
close: atomic.NewBool(false),
|
||||
client: c,
|
||||
}
|
||||
|
||||
go conn.once.Do(conn.initRequest)
|
||||
return conn, nil
|
||||
}
|
||||
|
||||
func GetNewClientStream(conn net.Conn, tlsConfig *tls.Config, cfg *Config) (net.Conn, error) {
|
||||
|
||||
transport := NewHTTP2Client(conn, tlsConfig)
|
||||
return StreamGunWithTransport(transport, cfg)
|
||||
}
|
||||
|
||||
func GetNewClientStream_withTlsConn(conn net.Conn, cfg *Config) (net.Conn, error) {
|
||||
|
||||
transport := &http2.Transport{
|
||||
DialTLS: func(_, _ string, cfg *tls.Config) (net.Conn, error) {
|
||||
return conn, nil
|
||||
conn.timeouter = timeouter{
|
||||
closeFunc: func() {
|
||||
conn.Close()
|
||||
},
|
||||
AllowHTTP: false,
|
||||
DisableCompression: true,
|
||||
PingTimeout: 0,
|
||||
}
|
||||
return StreamGunWithTransport(transport, cfg)
|
||||
|
||||
go conn.once.Do(conn.handshake) //necessary
|
||||
|
||||
return conn, nil
|
||||
}
|
||||
|
@@ -1,7 +0,0 @@
|
||||
// Package grpcHardcore implements grpc tunnel without importing google.golang.org/grpc.
|
||||
//
|
||||
//Reference
|
||||
//
|
||||
// https://github.com/Dreamacro/clash/blob/master/transport/gun/gun.go, which is under MIT license
|
||||
//
|
||||
package grpcSimple
|
79
advLayer/grpcSimple/grpcSimple.go
Normal file
79
advLayer/grpcSimple/grpcSimple.go
Normal file
@@ -0,0 +1,79 @@
|
||||
// Package grpcHardcore implements grpc tunnel without importing google.golang.org/grpc.
|
||||
//
|
||||
//Reference
|
||||
//
|
||||
// https://github.com/Dreamacro/clash/blob/master/transport/gun/gun.go, which is under MIT license
|
||||
//
|
||||
// 在 clash的客户端实现 的 基础上 继续用 golang的 http2包 实现了 grpc 的 基本服务端,并改进了 原代码。
|
||||
//
|
||||
// grpcSimple包 比grpc包 小很多,替代grpc包的话,可以减小 4MB 左右的可执行文件大小。但是目前不支持 multiMode。
|
||||
//
|
||||
// grpcSimple包 是很棒 很有用的 实现,未来可以添加 针对 grpc的ServiceName的回落。
|
||||
package grpcSimple
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
||||
"github.com/e1732a364fed/v2ray_simple/advLayer"
|
||||
)
|
||||
|
||||
func init() {
|
||||
advLayer.ProtocolsMap["grpc"] = Creator{}
|
||||
}
|
||||
|
||||
type Creator struct{}
|
||||
|
||||
func (Creator) PackageID() string {
|
||||
return "grpcSimple"
|
||||
}
|
||||
|
||||
func (Creator) GetDefaultAlpn() (alpn string, mustUse bool) {
|
||||
// v2ray 和 xray 的grpc 因为没有自己处理tls,直接用grpc包处理的tls,而grpc包对alpn有严格要求, 要用h2.
|
||||
return "h2", true
|
||||
}
|
||||
|
||||
func (Creator) NewClientFromConf(conf *advLayer.Conf) (advLayer.Client, error) {
|
||||
|
||||
serviceName := "GunService"
|
||||
if conf.Path != "" {
|
||||
serviceName = conf.Path
|
||||
}
|
||||
|
||||
c := &Client{
|
||||
Config: Config{
|
||||
ServiceName: serviceName,
|
||||
Host: conf.Host,
|
||||
},
|
||||
path: fmt.Sprintf("/%s/Tun", conf.Path),
|
||||
}
|
||||
|
||||
c.theRequest = http.Request{
|
||||
Method: http.MethodPost,
|
||||
URL: &url.URL{
|
||||
Scheme: "https",
|
||||
Host: c.Host,
|
||||
Path: c.path,
|
||||
// for unescape path
|
||||
Opaque: fmt.Sprintf("//%s/%s/Tun", c.Host, c.ServiceName),
|
||||
},
|
||||
Proto: "HTTP/2",
|
||||
ProtoMajor: 2,
|
||||
ProtoMinor: 0,
|
||||
Header: defaultClientHeader,
|
||||
}
|
||||
return c, nil
|
||||
}
|
||||
|
||||
func (Creator) NewServerFromConf(conf *advLayer.Conf) (advLayer.Server, error) {
|
||||
s := &Server{
|
||||
Config: Config{
|
||||
ServiceName: conf.Path,
|
||||
Host: conf.Host,
|
||||
},
|
||||
path: fmt.Sprintf("/%s/Tun", conf.Path),
|
||||
}
|
||||
|
||||
return s, nil
|
||||
}
|
@@ -1 +1,169 @@
|
||||
package grpcSimple
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"encoding/binary"
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
"sync"
|
||||
|
||||
"github.com/e1732a364fed/v2ray_simple/utils"
|
||||
"go.uber.org/zap"
|
||||
"golang.org/x/net/http2"
|
||||
)
|
||||
|
||||
type Server struct {
|
||||
Config
|
||||
|
||||
http2.Server
|
||||
|
||||
path string
|
||||
}
|
||||
|
||||
func (s *Server) GetPath() string {
|
||||
return s.ServiceName
|
||||
}
|
||||
|
||||
func (*Server) IsMux() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (*Server) IsSuper() bool {
|
||||
return false
|
||||
}
|
||||
func (s *Server) StartHandle(underlay net.Conn, newSubConnChan chan net.Conn) {
|
||||
go s.Server.ServeConn(underlay, &http2.ServeConnOpts{
|
||||
Handler: http.HandlerFunc(func(rw http.ResponseWriter, rq *http.Request) {
|
||||
|
||||
//log.Println("request headers", rq.Header)
|
||||
|
||||
//TODO: support fallback
|
||||
|
||||
if rq.URL.Path != s.path {
|
||||
if ce := utils.CanLogWarn("grpc Server got wrong path"); ce != nil {
|
||||
ce.Write(zap.String("path", rq.URL.Path))
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if ct := rq.Header.Get("Content-Type"); ct != "application/grpc" {
|
||||
if ce := utils.CanLogWarn("GRPC Server got wrong Content-Type"); ce != nil {
|
||||
ce.Write(zap.String("type", ct))
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
//https://dzone.com/articles/learning-about-the-headers-used-for-grpc-over-http
|
||||
|
||||
headerMap := rw.Header()
|
||||
headerMap.Add("Content-Type", "application/grpc") //necessary
|
||||
rw.WriteHeader(http.StatusOK)
|
||||
|
||||
cc := make(chan int)
|
||||
sc := &ServerConn{
|
||||
br: bufio.NewReader(rq.Body),
|
||||
Writer: rw,
|
||||
Closer: rq.Body,
|
||||
closeChan: cc,
|
||||
}
|
||||
|
||||
sc.timeouter = timeouter{
|
||||
closeFunc: func() {
|
||||
sc.Close()
|
||||
},
|
||||
}
|
||||
newSubConnChan <- sc
|
||||
<-cc //necessary
|
||||
}),
|
||||
})
|
||||
}
|
||||
|
||||
type ServerConn struct {
|
||||
io.Closer
|
||||
io.Writer
|
||||
|
||||
remain int
|
||||
br *bufio.Reader
|
||||
|
||||
once sync.Once
|
||||
closeChan chan int
|
||||
|
||||
timeouter
|
||||
}
|
||||
|
||||
func (g *ServerConn) Close() error {
|
||||
g.once.Do(func() {
|
||||
close(g.closeChan)
|
||||
g.Closer.Close()
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *ServerConn) Read(b []byte) (n int, err error) {
|
||||
|
||||
if g.remain > 0 {
|
||||
|
||||
size := g.remain
|
||||
if len(b) < size {
|
||||
size = len(b)
|
||||
}
|
||||
|
||||
n, err = io.ReadFull(g.br, b[:size])
|
||||
g.remain -= n
|
||||
return
|
||||
}
|
||||
|
||||
_, err = g.br.Discard(6)
|
||||
if err != nil {
|
||||
|
||||
return 0, err
|
||||
}
|
||||
|
||||
protobufPayloadLen, err := binary.ReadUvarint(g.br)
|
||||
if err != nil {
|
||||
return 0, ErrInvalidLength
|
||||
}
|
||||
|
||||
size := int(protobufPayloadLen)
|
||||
if len(b) < size {
|
||||
size = len(b)
|
||||
}
|
||||
|
||||
n, err = io.ReadFull(g.br, b[:size])
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
remain := int(protobufPayloadLen) - n
|
||||
if remain > 0 {
|
||||
g.remain = remain
|
||||
}
|
||||
return n, nil
|
||||
}
|
||||
|
||||
func (g *ServerConn) Write(b []byte) (n int, err error) {
|
||||
|
||||
protobufHeader := [binary.MaxVarintLen64 + 1]byte{0x0A}
|
||||
varuintSize := binary.PutUvarint(protobufHeader[1:], uint64(len(b)))
|
||||
grpcHeader := make([]byte, 5)
|
||||
grpcPayloadLen := uint32(varuintSize + 1 + len(b))
|
||||
binary.BigEndian.PutUint32(grpcHeader[1:5], grpcPayloadLen)
|
||||
|
||||
buf := utils.GetBuf()
|
||||
defer utils.PutBuf(buf)
|
||||
buf.Write(grpcHeader)
|
||||
buf.Write(protobufHeader[:varuintSize+1])
|
||||
buf.Write(b)
|
||||
|
||||
_, err = g.Writer.Write(buf.Bytes())
|
||||
|
||||
if err == nil {
|
||||
g.Writer.(http.Flusher).Flush() //necessary
|
||||
|
||||
}
|
||||
|
||||
return len(b), err
|
||||
}
|
||||
|
42
advLayer/grpcSimple/timeouter.go
Normal file
42
advLayer/grpcSimple/timeouter.go
Normal file
@@ -0,0 +1,42 @@
|
||||
package grpcSimple
|
||||
|
||||
import (
|
||||
"net"
|
||||
"time"
|
||||
)
|
||||
|
||||
type timeouter struct {
|
||||
deadline *time.Timer
|
||||
|
||||
closeFunc func()
|
||||
}
|
||||
|
||||
func (g *timeouter) LocalAddr() net.Addr { return nil }
|
||||
func (g *timeouter) RemoteAddr() net.Addr { return nil }
|
||||
func (g *timeouter) SetReadDeadline(t time.Time) error { return g.SetDeadline(t) }
|
||||
func (g *timeouter) SetWriteDeadline(t time.Time) error { return g.SetDeadline(t) }
|
||||
|
||||
func (g *timeouter) SetDeadline(t time.Time) error {
|
||||
|
||||
var d time.Duration
|
||||
|
||||
if g.deadline != nil {
|
||||
|
||||
if t == (time.Time{}) {
|
||||
g.deadline.Stop()
|
||||
return nil
|
||||
}
|
||||
|
||||
g.deadline.Reset(d)
|
||||
return nil
|
||||
} else {
|
||||
if t == (time.Time{}) {
|
||||
return nil
|
||||
}
|
||||
d = time.Until(t)
|
||||
|
||||
}
|
||||
|
||||
g.deadline = time.AfterFunc(d, g.closeFunc)
|
||||
return nil
|
||||
}
|
@@ -57,6 +57,7 @@ func CloseConn(baseC any) {
|
||||
}
|
||||
|
||||
var (
|
||||
//h3
|
||||
DefaultAlpnList = []string{"h3"}
|
||||
|
||||
common_ListenConfig = quic.Config{
|
||||
@@ -78,6 +79,14 @@ var (
|
||||
|
||||
type Creator struct{}
|
||||
|
||||
func (Creator) GetDefaultAlpn() (alpn string, mustUse bool) {
|
||||
return "h3", false
|
||||
}
|
||||
|
||||
func (Creator) PackageID() string {
|
||||
return "quic"
|
||||
}
|
||||
|
||||
func (Creator) NewClientFromConf(conf *advLayer.Conf) (advLayer.Client, error) {
|
||||
var alpn []string
|
||||
if conf.TlsConf != nil {
|
||||
|
@@ -15,9 +15,6 @@ import (
|
||||
"github.com/gobwas/ws/wsutil"
|
||||
)
|
||||
|
||||
//为了避免黑客攻击,我们固定earlydata最大值为2048
|
||||
const MaxEarlyDataLen = 2048
|
||||
|
||||
//implements advLayer.Client
|
||||
type Client struct {
|
||||
requestURL *url.URL //因为调用gobwas/ws.Dialer.Upgrade 时要传入url,所以我们直接提供包装好的即可
|
||||
|
@@ -28,12 +28,13 @@ type Server struct {
|
||||
}
|
||||
|
||||
// 这里默认: 传入的path必须 以 "/" 为前缀. 本函数 不对此进行任何检查.
|
||||
func NewServer(path string, headers map[string][]string) *Server {
|
||||
func NewServer(path string, headers map[string][]string, UseEarlyData bool) *Server {
|
||||
|
||||
return &Server{
|
||||
//upgrader: upgrader,
|
||||
Thepath: path,
|
||||
headers: headers,
|
||||
UseEarlyData: UseEarlyData,
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -48,5 +48,11 @@ func (Creator) NewClientFromConf(conf *advLayer.Conf) (advLayer.Client, error) {
|
||||
}
|
||||
|
||||
func (Creator) NewServerFromConf(conf *advLayer.Conf) (advLayer.Server, error) {
|
||||
return NewServer(conf.Path, conf.Headers), nil
|
||||
return NewServer(conf.Path, conf.Headers, conf.IsEarly), nil
|
||||
}
|
||||
func (Creator) GetDefaultAlpn() (alpn string, mustUse bool) {
|
||||
return
|
||||
}
|
||||
func (Creator) PackageID() string {
|
||||
return "ws"
|
||||
}
|
||||
|
@@ -46,7 +46,7 @@ func TestWs(t *testing.T) {
|
||||
return
|
||||
}
|
||||
|
||||
s := ws.NewServer(wsPath, nil)
|
||||
s := ws.NewServer(wsPath, nil, false)
|
||||
|
||||
wsConn, err := s.Handshake(nil, conn)
|
||||
if err != nil {
|
||||
|
8
adv_grpc.go
Normal file
8
adv_grpc.go
Normal file
@@ -0,0 +1,8 @@
|
||||
//go:build grpc_full
|
||||
|
||||
package v2ray_simple
|
||||
|
||||
import _ "github.com/e1732a364fed/v2ray_simple/advLayer/grpc"
|
||||
|
||||
//默认使用 grpcSimple,除非编译时 使用 grpc_full 这个 tag, 才会使用 grpc 包。
|
||||
// go build -tags=grpc_full
|
5
adv_grpcSimple.go
Normal file
5
adv_grpcSimple.go
Normal file
@@ -0,0 +1,5 @@
|
||||
//go:build !grpc_full
|
||||
|
||||
package v2ray_simple
|
||||
|
||||
import _ "github.com/e1732a364fed/v2ray_simple/advLayer/grpcSimple"
|
7
adv_quic.go
Normal file
7
adv_quic.go
Normal file
@@ -0,0 +1,7 @@
|
||||
//go:build !noquic
|
||||
|
||||
package v2ray_simple
|
||||
|
||||
import _ "github.com/e1732a364fed/v2ray_simple/advLayer/quic"
|
||||
|
||||
// 如果不引用 quic,go build 编译出的可执行文件 的大小 可以减小 2MB 。
|
@@ -9,7 +9,6 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/asaskevich/govalidator"
|
||||
"github.com/e1732a364fed/v2ray_simple/advLayer/quic"
|
||||
"github.com/e1732a364fed/v2ray_simple/netLayer"
|
||||
"github.com/e1732a364fed/v2ray_simple/proxy"
|
||||
"github.com/e1732a364fed/v2ray_simple/proxy/trojan"
|
||||
@@ -80,41 +79,6 @@ func init() {
|
||||
},
|
||||
})
|
||||
|
||||
cliCmdList = append(cliCmdList, CliCmd{
|
||||
"调节hy手动挡", func() {
|
||||
var arr = []string{"加速", "减速", "当前状态", "讲解"}
|
||||
|
||||
Select := promptui.Select{
|
||||
Label: "请选择",
|
||||
Items: arr,
|
||||
}
|
||||
|
||||
for {
|
||||
i, result, err := Select.Run()
|
||||
|
||||
if err != nil {
|
||||
fmt.Printf("Prompt failed %v\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Printf("你选择了 %s\n", result)
|
||||
|
||||
switch i {
|
||||
case 0:
|
||||
quic.TheCustomRate -= 0.1
|
||||
fmt.Printf("调好了!当前rate %f\n", quic.TheCustomRate)
|
||||
case 1:
|
||||
quic.TheCustomRate += 0.1
|
||||
fmt.Printf("调好了!当前rate %f\n", quic.TheCustomRate)
|
||||
case 2:
|
||||
fmt.Printf("当前rate %f\n", quic.TheCustomRate)
|
||||
case 3:
|
||||
fmt.Printf("rate越小越加速, rate越大越减速. 最小0.2最大1.5。实际速度倍率为 1.5/rate \n")
|
||||
}
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
type CliCmd struct {
|
||||
|
49
cmd/verysimple/cli_quic.go
Normal file
49
cmd/verysimple/cli_quic.go
Normal file
@@ -0,0 +1,49 @@
|
||||
//go:build !noquic
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/e1732a364fed/v2ray_simple/advLayer/quic"
|
||||
"github.com/manifoldco/promptui"
|
||||
)
|
||||
|
||||
func init() {
|
||||
|
||||
cliCmdList = append(cliCmdList, CliCmd{
|
||||
"调节hy手动挡", func() {
|
||||
var arr = []string{"加速", "减速", "当前状态", "讲解"}
|
||||
|
||||
Select := promptui.Select{
|
||||
Label: "请选择",
|
||||
Items: arr,
|
||||
}
|
||||
|
||||
for {
|
||||
i, result, err := Select.Run()
|
||||
|
||||
if err != nil {
|
||||
fmt.Printf("Prompt failed %v\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Printf("你选择了 %s\n", result)
|
||||
|
||||
switch i {
|
||||
case 0:
|
||||
quic.TheCustomRate -= 0.1
|
||||
fmt.Printf("调好了!当前rate %f\n", quic.TheCustomRate)
|
||||
case 1:
|
||||
quic.TheCustomRate += 0.1
|
||||
fmt.Printf("调好了!当前rate %f\n", quic.TheCustomRate)
|
||||
case 2:
|
||||
fmt.Printf("当前rate %f\n", quic.TheCustomRate)
|
||||
case 3:
|
||||
fmt.Printf("rate越小越加速, rate越大越减速. 最小0.2最大1.5。实际速度倍率为 1.5/rate \n")
|
||||
}
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
}
|
@@ -14,6 +14,7 @@ import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
|
||||
"github.com/e1732a364fed/v2ray_simple/advLayer"
|
||||
"github.com/e1732a364fed/v2ray_simple/netLayer"
|
||||
)
|
||||
|
||||
@@ -22,7 +23,13 @@ const delimiter = "===============================\n"
|
||||
var Version string = "[version_undefined]" //版本号可由 -ldflags "-X 'main.Version=v1.x.x'" 指定, 本项目的Makefile就是用这种方式确定版本号
|
||||
|
||||
func versionStr() string {
|
||||
return fmt.Sprintf("verysimple %s, %s %s %s", Version, runtime.Version(), runtime.GOOS, runtime.GOARCH)
|
||||
//verysimple 可以用 noquic, grpc_full tag 来选择性加载 advLayer的一些包,所以需要注明编译使用了哪些包
|
||||
var advList []string
|
||||
for _, c := range advLayer.ProtocolsMap {
|
||||
advList = append(advList, c.PackageID())
|
||||
}
|
||||
|
||||
return fmt.Sprintf("verysimple %s, %s %s %s, with advLayer packages: %v", Version, runtime.Version(), runtime.GOOS, runtime.GOARCH, advList)
|
||||
}
|
||||
|
||||
func printVersion_simple() {
|
||||
|
@@ -5,7 +5,7 @@ port = 10800
|
||||
|
||||
|
||||
[[dial]]
|
||||
protocol = "trojans" # 还是,为了简便,直接加了尾缀s 表示使用tls. 虽然trojan强制tls, 但是我们很灵活, 自行可以选择是否开启tls.
|
||||
protocol = "trojans" # 还是,为了简便,直接加了尾缀s 表示使用tls. 虽然trojan强制tls, 但是vs很灵活, 自行可以选择是否开启tls.
|
||||
uuid = "a684455c-b14f-11ea-bf0d-42010aaa0003" # trojan的"password",我们填写到uuid项里. 实际上trojan这个password不要求格式, 所以你可以乱写,甚至可以写成一个中文字符串, 不过我们作为示例就统一用 示例的uuid了
|
||||
ip = "127.0.0.1"
|
||||
host = "your-domain-name.com" # trojan-go 的服务端要求指定一个sni 并与服务端的配置相匹配, 否则会trojan-go 会拒绝连接
|
||||
@@ -13,6 +13,9 @@ port = 4434
|
||||
insecure = true
|
||||
utls = true
|
||||
|
||||
#advancedLayer = "ws"
|
||||
#path = "/ohmygod_verysimple_is_very_simple"
|
||||
#early = true # websocket early data 功能 (即0-rtt)
|
||||
#use_mux = true # 只需要客户端指明 use_mux 即可开启mux, 服务端自动适配.
|
||||
|
||||
# 备注: trojan 也是一样可以应用 ws/grpc/quic 的,具体你只要参考对应示例文件即可,然后把 vlesss 改成 trojans 即可.
|
@@ -8,6 +8,9 @@ insecure = true
|
||||
fallback = ":80"
|
||||
cert = "cert.pem"
|
||||
key = "cert.key"
|
||||
#advancedLayer = "ws"
|
||||
#path = "/ohmygod_verysimple_is_very_simple"
|
||||
#early = true
|
||||
|
||||
[[dial]]
|
||||
protocol = "direct"
|
||||
|
4
go.mod
4
go.mod
@@ -16,8 +16,10 @@ require (
|
||||
github.com/refraction-networking/utls v1.0.0
|
||||
github.com/xtaci/smux v1.5.16
|
||||
github.com/yl2chen/cidranger v1.0.2
|
||||
go.uber.org/atomic v1.7.0
|
||||
go.uber.org/zap v1.21.0
|
||||
golang.org/x/exp v0.0.0-20220407100705-7b9b53b0aca4
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2
|
||||
golang.org/x/sys v0.0.0-20220315194320-039c03cc5b86
|
||||
gonum.org/v1/gonum v0.11.0
|
||||
google.golang.org/grpc v1.45.0
|
||||
@@ -37,11 +39,9 @@ require (
|
||||
github.com/marten-seemann/qtls-go1-18 v0.1.1 // indirect
|
||||
github.com/nxadm/tail v1.4.8 // indirect
|
||||
github.com/onsi/ginkgo v1.16.4 // indirect
|
||||
go.uber.org/atomic v1.7.0 // indirect
|
||||
go.uber.org/multierr v1.6.0 // indirect
|
||||
golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd // indirect
|
||||
golang.org/x/mod v0.6.0-dev.0.20211013180041-c96bc1413d57 // indirect
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 // indirect
|
||||
golang.org/x/text v0.3.7 // indirect
|
||||
golang.org/x/tools v0.1.9 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
|
||||
|
21
main.go
21
main.go
@@ -21,8 +21,6 @@ import (
|
||||
"github.com/e1732a364fed/v2ray_simple/tlsLayer"
|
||||
"github.com/e1732a364fed/v2ray_simple/utils"
|
||||
|
||||
_ "github.com/e1732a364fed/v2ray_simple/advLayer/grpc"
|
||||
_ "github.com/e1732a364fed/v2ray_simple/advLayer/quic"
|
||||
_ "github.com/e1732a364fed/v2ray_simple/advLayer/ws"
|
||||
|
||||
_ "github.com/e1732a364fed/v2ray_simple/proxy/dokodemo"
|
||||
@@ -1030,6 +1028,8 @@ func dialClient(targetAddr netLayer.Addr,
|
||||
|
||||
advLayerHandshakeStep:
|
||||
|
||||
//var firstPayloadAlreadyDealt bool
|
||||
|
||||
if adv != "" {
|
||||
switch adv {
|
||||
case "quic":
|
||||
@@ -1116,7 +1116,11 @@ advLayerHandshakeStep:
|
||||
//若配置了 MaxEarlyDataLen,则我们先读一段;
|
||||
edBuf := utils.GetPacket()
|
||||
edBuf = edBuf[:advLayer.MaxEarlyDataLen]
|
||||
|
||||
wlc.SetReadDeadline(time.Now().Add(proxy.FirstPayloadTimeout))
|
||||
n, e := wlc.Read(edBuf)
|
||||
wlc.SetReadDeadline(time.Time{})
|
||||
|
||||
if e != nil {
|
||||
if ce := utils.CanLogErr("failed to read ws early data"); ce != nil {
|
||||
ce.Write(zap.Error(e))
|
||||
@@ -1124,8 +1128,12 @@ advLayerHandshakeStep:
|
||||
result = -1
|
||||
return
|
||||
}
|
||||
if n > 0 {
|
||||
//firstPayloadAlreadyDealt = true
|
||||
ed = edBuf[:n]
|
||||
|
||||
}
|
||||
|
||||
if ce := utils.CanLogDebug("will send early data"); ce != nil {
|
||||
ce.Write(
|
||||
zap.Int("len", n),
|
||||
@@ -1165,11 +1173,16 @@ advLayerHandshakeStep:
|
||||
//udp但是有innermux时 依然用handshake, 而不是 EstablishUDPChannel
|
||||
var firstPayload []byte
|
||||
|
||||
if !hasInnerMux { //如果有内层mux,要在dialInnerProxy函数里再读
|
||||
//读取firstPayload
|
||||
if !hasInnerMux {
|
||||
//如果有内层mux,要在dialInnerProxy函数里再读, 而不是在这里读
|
||||
|
||||
firstPayload = utils.GetMTU()
|
||||
|
||||
wlc.SetReadDeadline(time.Now().Add(proxy.FirstPayloadTimeout))
|
||||
n, err := wlc.Read(firstPayload)
|
||||
wlc.SetReadDeadline(time.Time{})
|
||||
|
||||
if err != nil {
|
||||
|
||||
if !errors.Is(err, os.ErrDeadlineExceeded) {
|
||||
@@ -1194,7 +1207,7 @@ advLayerHandshakeStep:
|
||||
}
|
||||
|
||||
}
|
||||
wlc.SetReadDeadline(time.Time{})
|
||||
|
||||
firstPayload = firstPayload[:n]
|
||||
}
|
||||
|
||||
|
@@ -37,16 +37,8 @@ func (addr *Addr) Dial() (net.Conn, error) {
|
||||
|
||||
tcp:
|
||||
|
||||
//dialer := &net.Dialer{
|
||||
// Timeout: time.Second * 16,
|
||||
//}
|
||||
//本以为直接用 DialTCP 可以加速拨号,结果发现go官方包内部依然还是把地址转换回字符串再拨号
|
||||
|
||||
//另外,为了为以后支持 tproxy、bindToDevice、SO_MARK 作准备,我们还是要选择性使用 net.Dialer.
|
||||
|
||||
//fastopen 不予支持, 因为自己客户端在重重网关之下,不可能让层层网关都支持tcp fast open;
|
||||
// 而自己的远程节点的话因为本来网速就很快, 也不需要fastopen,总之 因为木桶原理,慢的地方在我们层层网关, 所以fastopen 意义不大.
|
||||
|
||||
if addr.IP != nil {
|
||||
if addr.IP.To4() == nil {
|
||||
if !machineCanConnectToIpv6 {
|
||||
|
@@ -1,9 +1,9 @@
|
||||
/*
|
||||
Package netLayer contains definitions in network layer AND transport layer.
|
||||
|
||||
本包有 geoip, geosite, udp, readv, splice, relay, route, dns 等相关功能。
|
||||
本包有 geoip, geosite, route, udp, readv, splice, relay, dns, listen/dial/sockopt 等相关功能。
|
||||
|
||||
以后如果要添加 kcp 或 raw socket 等底层协议时,或者要控制tcp/udp拨号的细节时,也要在此包里实现.
|
||||
以后如果要添加 kcp 或 raw socket 等底层协议时,也要在此包里实现.
|
||||
|
||||
*/
|
||||
package netLayer
|
||||
@@ -54,7 +54,12 @@ func HasIpv6Interface() bool {
|
||||
// According to godoc, If ip is not an IPv4 address, To4 returns nil.
|
||||
// This means it's ipv6
|
||||
if ipnet.IP.To4() == nil {
|
||||
utils.Debug("Has Ipv6Interface!")
|
||||
|
||||
if ce := utils.CanLogDebug("Has Ipv6Interface!"); ce != nil {
|
||||
ce.Write()
|
||||
} else {
|
||||
log.Println("Has Ipv6Interface!")
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
@@ -154,6 +154,7 @@ func ReadBuffersFrom(c io.Reader, rawReadConn syscall.RawConn, mr utils.MultiRea
|
||||
return
|
||||
}
|
||||
|
||||
// if r!=0, then it means c can be used in readv. 1 means syscall.RawConn, 2 means utils.MultiReader
|
||||
func IsConnGoodForReadv(c net.Conn) (r int, rawReadConn syscall.RawConn, mr utils.MultiReader) {
|
||||
rawReadConn = GetRawConn(c)
|
||||
var ok bool
|
||||
|
@@ -10,6 +10,10 @@ type Sockopt struct {
|
||||
TProxy bool `toml:"tproxy"`
|
||||
Somark int `toml:"mark"`
|
||||
Device string `toml:"device"`
|
||||
|
||||
//fastopen 不予支持, 因为自己客户端在重重网关之下,不可能让层层网关都支持tcp fast open;
|
||||
// 而自己的远程节点的话因为本来网速就很快, 也不需要fastopen,总之 因为木桶原理,慢的地方在我们层层网关, 所以fastopen 意义不大.
|
||||
|
||||
}
|
||||
|
||||
//net.TCPListener, net.UnixListener
|
||||
@@ -32,5 +36,3 @@ func SetSockOptForListener(tcplistener ListenerWithFile, sockopt *Sockopt, isudp
|
||||
defer fileDescriptorSource.Close()
|
||||
SetSockOpt(int(fileDescriptorSource.Fd()), sockopt, isudp, isipv6)
|
||||
}
|
||||
|
||||
//SetSockOpt 是平台相关的.
|
||||
|
@@ -3,5 +3,6 @@
|
||||
|
||||
package netLayer
|
||||
|
||||
//SetSockOpt 是平台相关的.
|
||||
func SetSockOpt(fd int, sockopt *Sockopt, isudp bool, isipv6 bool) {
|
||||
}
|
||||
|
@@ -296,6 +296,7 @@ func (*ProxyCommonStruct) GetServerInnerMuxSession(wlc io.ReadWriteCloser) *smux
|
||||
zap.Error(err),
|
||||
)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
return smuxSession
|
||||
}
|
||||
@@ -319,6 +320,7 @@ func (pcs *ProxyCommonStruct) GetClientInnerMuxSession(wrc io.ReadWriteCloser) *
|
||||
zap.Error(err),
|
||||
)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
pcs.innermux = smuxSession
|
||||
return smuxSession
|
||||
@@ -429,8 +431,11 @@ func (s *ProxyCommonStruct) GetAdvServer() advLayer.Server {
|
||||
}
|
||||
|
||||
func (s *ProxyCommonStruct) InitAdvLayer() {
|
||||
if s.AdvancedL == "" {
|
||||
switch s.AdvancedL {
|
||||
case "":
|
||||
return
|
||||
case "quic":
|
||||
s.setNetwork("udp")
|
||||
}
|
||||
|
||||
creator := advLayer.ProtocolsMap[s.AdvancedL]
|
||||
|
@@ -4,68 +4,57 @@ import (
|
||||
"net"
|
||||
"net/url"
|
||||
|
||||
"github.com/e1732a364fed/v2ray_simple/httpLayer"
|
||||
"github.com/e1732a364fed/v2ray_simple/advLayer"
|
||||
"github.com/e1732a364fed/v2ray_simple/tlsLayer"
|
||||
)
|
||||
|
||||
func updateAlpnListByAdvLayer(com ProxyCommon, alpnList []string) (result []string) {
|
||||
result = alpnList
|
||||
|
||||
if adv := com.AdvancedLayer(); adv != "" {
|
||||
if creator := advLayer.ProtocolsMap[adv]; creator != nil {
|
||||
if alpn, must := creator.GetDefaultAlpn(); must {
|
||||
has_alpn := false
|
||||
|
||||
for _, a := range alpnList {
|
||||
if a == alpn {
|
||||
has_alpn = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !has_alpn {
|
||||
result = append([]string{alpn}, alpnList...)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
//use dc.Host, dc.Insecure, dc.Utls, dc.Alpn.
|
||||
func prepareTLS_forClient(com ProxyCommon, dc *DialConf) error {
|
||||
alpnList := dc.Alpn
|
||||
alpnList := updateAlpnListByAdvLayer(com, dc.Alpn)
|
||||
|
||||
clic := com.getCommon()
|
||||
if clic == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
switch com.AdvancedLayer() {
|
||||
case "quic":
|
||||
clic.setNetwork("udp")
|
||||
return nil
|
||||
case "grpc":
|
||||
has_h2 := false
|
||||
for _, a := range alpnList {
|
||||
if a == httpLayer.H2_Str {
|
||||
has_h2 = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !has_h2 {
|
||||
alpnList = append([]string{httpLayer.H2_Str}, alpnList...)
|
||||
}
|
||||
}
|
||||
clic.setTLS_Client(tlsLayer.NewClient(dc.Host, dc.Insecure, dc.Utls, alpnList))
|
||||
return nil
|
||||
}
|
||||
|
||||
//use lc.Host, lc.TLSCert, lc.TLSKey, lc.Insecure, lc.Alpn.
|
||||
func prepareTLS_forServer(com ProxyCommon, lc *ListenConf) error {
|
||||
// 这里直接不检查 字符串就直接传给 tlsLayer.NewServer
|
||||
// 所以要求 cert和 key 不在程序本身目录 的话,就要给出完整路径
|
||||
|
||||
serc := com.getCommon()
|
||||
if serc == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
alpnList := lc.Alpn
|
||||
switch com.AdvancedLayer() {
|
||||
case "quic":
|
||||
|
||||
serc.setNetwork("udp")
|
||||
return nil
|
||||
|
||||
case "grpc":
|
||||
has_h2 := false
|
||||
for _, a := range alpnList {
|
||||
if a == httpLayer.H2_Str {
|
||||
has_h2 = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !has_h2 {
|
||||
alpnList = append([]string{httpLayer.H2_Str}, alpnList...)
|
||||
}
|
||||
}
|
||||
alpnList := updateAlpnListByAdvLayer(com, lc.Alpn)
|
||||
|
||||
tlsserver, err := tlsLayer.NewServer(lc.Host, lc.TLSCert, lc.TLSKey, lc.Insecure, alpnList)
|
||||
if err == nil {
|
||||
|
Reference in New Issue
Block a user