修订代码,文档, 示例

This commit is contained in:
e1732a364fed
2022-05-01 09:32:00 +08:00
parent a07a57fdd8
commit efb2ee0010
11 changed files with 75 additions and 41 deletions

View File

@@ -1,8 +1,5 @@
package grpcSimple package grpcSimple
// Modified from: https://github.com/Dreamacro/clash/blob/master/transport/gun/gun.go
// License: MIT
import ( import (
"bufio" "bufio"
"crypto/tls" "crypto/tls"
@@ -174,8 +171,6 @@ func (c *Client) GetCommonConn(underlay net.Conn) (any, error) {
} }
func (c *Client) ProcessWhenFull(underlay any) {}
func (c *Client) DialSubConn(underlay any) (net.Conn, error) { func (c *Client) DialSubConn(underlay any) (net.Conn, error) {
if underlay == nil { if underlay == nil {

View File

@@ -11,6 +11,9 @@ import (
"github.com/e1732a364fed/v2ray_simple/utils" "github.com/e1732a364fed/v2ray_simple/utils"
) )
// Modified from: https://github.com/Dreamacro/clash/blob/master/transport/gun/gun.go
// License: MIT
func commonWrite(b []byte) *bytes.Buffer { func commonWrite(b []byte) *bytes.Buffer {
protobufHeader := [binary.MaxVarintLen64 + 1]byte{0x0A} protobufHeader := [binary.MaxVarintLen64 + 1]byte{0x0A}
varuintSize := binary.PutUvarint(protobufHeader[1:], uint64(len(b))) varuintSize := binary.PutUvarint(protobufHeader[1:], uint64(len(b)))
@@ -58,7 +61,7 @@ func (c *commonPart) Read(b []byte) (n int, err error) {
protobufPayloadLen, err := binary.ReadUvarint(c.br) protobufPayloadLen, err := binary.ReadUvarint(c.br)
if err != nil { if err != nil {
return 0, utils.ErrInErr{ErrDesc: "binary.ReadUvarint failed", ErrDetail: err, ExtraIs: []error{utils.ErrInvalidData}} return 0, utils.ErrInErr{ErrDesc: "grpc Read, binary.ReadUvarint failed", ErrDetail: err, ExtraIs: []error{utils.ErrInvalidData}}
} }
size := int(protobufPayloadLen) size := int(protobufPayloadLen)

View File

@@ -122,7 +122,7 @@ func (s *Server) StartHandle(underlay net.Conn, newSubConnChan chan net.Conn, fa
var buf *bytes.Buffer var buf *bytes.Buffer
sc := &netLayer.IOWrapper{ respConn := &netLayer.IOWrapper{
Reader: rq.Body, Reader: rq.Body,
Writer: rw, Writer: rw,
CloseChan: make(chan struct{}), CloseChan: make(chan struct{}),
@@ -130,7 +130,7 @@ func (s *Server) StartHandle(underlay net.Conn, newSubConnChan chan net.Conn, fa
fm := httpLayer.FallbackMeta{ fm := httpLayer.FallbackMeta{
Path: p, Path: p,
Conn: sc, Conn: respConn,
} }
// 如果使用 rq.Write 那么实际上就是回落到 http1.1, 只有用 http2.Transport.RoundTrip 才是 h2 请求 // 如果使用 rq.Write 那么实际上就是回落到 http1.1, 只有用 http2.Transport.RoundTrip 才是 h2 请求
@@ -141,9 +141,9 @@ func (s *Server) StartHandle(underlay net.Conn, newSubConnChan chan net.Conn, fa
buf = utils.GetBuf() buf = utils.GetBuf()
rq.Write(buf) rq.Write(buf)
sc.FirstWriteChan = make(chan struct{}) respConn.FirstWriteChan = make(chan struct{})
fm.FirstBuffer = buf fm.H1RequestBuf = buf
} else { } else {
fm.IsH2 = true fm.IsH2 = true
@@ -156,7 +156,7 @@ func (s *Server) StartHandle(underlay net.Conn, newSubConnChan chan net.Conn, fa
fallbackConnChan <- fm fallbackConnChan <- fm
<-sc.CloseChan <-respConn.CloseChan
} }

View File

@@ -57,7 +57,7 @@ func (s *Server) Handshake(underlay net.Conn) (net.Conn, error) {
//我们目前只支持 ws on http1.1 //我们目前只支持 ws on http1.1
var rp httpLayer.RequestParser var rp httpLayer.H1RequestParser
re := rp.ReadAndParse(underlay) re := rp.ReadAndParse(underlay)
if re != nil { if re != nil {
if re == httpLayer.ErrNotHTTP_Request { if re == httpLayer.ErrNotHTTP_Request {
@@ -77,10 +77,10 @@ func (s *Server) Handshake(underlay net.Conn) (net.Conn, error) {
if rp.Method != "GET" || s.Thepath != rp.Path { if rp.Method != "GET" || s.Thepath != rp.Path {
return httpLayer.FallbackMeta{ return httpLayer.FallbackMeta{
Conn: underlay, Conn: underlay,
FirstBuffer: optionalFirstBuffer, H1RequestBuf: optionalFirstBuffer,
Path: rp.Path, Path: rp.Path,
Method: rp.Method, Method: rp.Method,
}, httpLayer.ErrShouldFallback }, httpLayer.ErrShouldFallback
} }

View File

@@ -354,12 +354,19 @@ func mainFunc() (result int) {
} }
} }
//如果在非linux系统 上仅设置了tproxy则会遇到下面情况
if len(tproxyList) == 0 {
if !(defaultInServer != nil || len(allServers) > 0) {
configFileQualifiedToRun = false
}
}
} }
} }
} }
//没配置可用的listen或者dial而且还无法动态更改配置 //没可用的listen或者dial而且还无法动态更改配置
if !configFileQualifiedToRun && !isFlexible() { if !configFileQualifiedToRun && !isFlexible() {
utils.Error("No valid proxy settings available, nor cli or apiServer feature enabled, exit now.") utils.Error("No valid proxy settings available, nor cli or apiServer feature enabled, exit now.")
return -1 return -1

View File

@@ -5,7 +5,7 @@ host = "0.0.0.0"
port = 4434 port = 4434
version = 0 version = 0
insecure = true insecure = true
fallback = ":80" fallback = "udp://127.0.0.1:80" #试图回落到 nginx的 无tls 的 udp的 http3 服务端口 (目前尚未支持quic的回落功能请期待)
cert = "cert.pem" cert = "cert.pem"
key = "cert.key" key = "cert.key"
advancedLayer = "quic" advancedLayer = "quic"

View File

@@ -7,7 +7,7 @@ host = "0.0.0.0"
port = 4433 port = 4433
version = 0 version = 0
insecure = true insecure = true
fallback = ":80" # 默认回落地址.ip必须是本机ip(可以省略ip而只写端口,程序会默认补全127.0.0.1), 或者unix domain socket的文件名/路径, 或者 udp://127.0.0.1:80 这种url格式。 用udp以试图回落到 nginx的 无tls 的 http3 服务端口) fallback = ":80" # 默认回落地址.ip必须是本机ip(可以省略ip而只写端口,程序会默认补全127.0.0.1), 或者unix domain socket的文件名/路径, 或者 udp://127.0.0.1:80 这种url格式。 用udp以试图回落到 nginx的 无tls 的 udp的 http3 服务端口,适用于 quic的情况
#cert = "cert.pem" # 这里既可以默认放在程序本身目录下,也可以指定完整路径 #cert = "cert.pem" # 这里既可以默认放在程序本身目录下,也可以指定完整路径
#key = "cert.key" # 如果 cert和key中 有一项没给出, 或者文件不存在, 就会自动在内存中生成随机证书, #key = "cert.key" # 如果 cert和key中 有一项没给出, 或者文件不存在, 就会自动在内存中生成随机证书,

View File

@@ -13,10 +13,13 @@ import (
"golang.org/x/exp/slices" "golang.org/x/exp/slices"
) )
//观察v2ray的实现在没有header时还会添加一个 Date 这个v2ray的文档里没提 /*
// https://www.v2fly.org/config/transport/tcp.html#noneheaderobject 观察v2ray的实现在没有header时还会添加一个 Date 这个v2ray的文档里没提
//
// transport/internet/headers/http/http.go v2ray文档: https://www.v2fly.org/config/transport/tcp.html#noneheaderobject
相关 v2ray代码: transport/internet/headers/http/http.go
*/
type RequestHeader struct { type RequestHeader struct {
Version string `toml:"version"` //默认值为 "1.1" Version string `toml:"version"` //默认值为 "1.1"
@@ -90,7 +93,7 @@ func (hh *HeaderPreset) AssignDefaultValue() {
func (h *HeaderPreset) ReadRequest(underlay net.Conn) (err error, leftBuf *bytes.Buffer) { func (h *HeaderPreset) ReadRequest(underlay net.Conn) (err error, leftBuf *bytes.Buffer) {
var rp RequestParser var rp H1RequestParser
err = rp.ReadAndParse(underlay) err = rp.ReadAndParse(underlay)
if err != nil { if err != nil {
return return

View File

@@ -16,6 +16,7 @@ import (
"errors" "errors"
"io" "io"
"net" "net"
"strings"
"github.com/e1732a364fed/v2ray_simple/utils" "github.com/e1732a364fed/v2ray_simple/utils"
@@ -72,13 +73,34 @@ type RequestErr struct {
Method string Method string
} }
func (pe *RequestErr) Error() string { func (e *RequestErr) Is(err error) bool {
return "InvaidRequest " + pe.Method + "," + pe.Path if err == nil {
return false
}
if re, ok := err.(*RequestErr); ok && re != nil {
return (e.Path == re.Path && e.Method == re.Path)
}
if err == utils.ErrInvalidData {
return true
}
return false
} }
// RequestParser被用于 预读一个链接判断该连接是否是有效的http请求, func (pe *RequestErr) Error() string {
var sb strings.Builder
sb.WriteString("InvaidRequest ")
sb.WriteString(pe.Method)
sb.WriteString(",")
sb.WriteString(pe.Path)
return sb.String()
}
// H1RequestParser被用于 预读一个链接判断该连接是否是有效的http请求,
// 并将VersionPathMethod 记录在结构中. // 并将VersionPathMethod 记录在结构中.
type RequestParser struct { //
// 只能过滤 http 0.9, 1.0 和 1.1. 无法过滤h2和h3.
type H1RequestParser struct {
Version string Version string
Path string Path string
Method string Method string
@@ -88,7 +110,7 @@ type RequestParser struct {
// 尝试读取数据并解析HTTP请求, 解析道道 数据会存入 RequestParser 结构中. // 尝试读取数据并解析HTTP请求, 解析道道 数据会存入 RequestParser 结构中.
//如果读取错误,会返回该错误; 如果读到的不是HTTP请求返回 ErrNotHTTP_Request; //如果读取错误,会返回该错误; 如果读到的不是HTTP请求返回 ErrNotHTTP_Request;
func (rhr *RequestParser) ReadAndParse(r io.Reader) error { func (rhr *H1RequestParser) ReadAndParse(r io.Reader) error {
bs := utils.GetPacket() bs := utils.GetPacket()
n, e := r.Read(bs) n, e := r.Read(bs)
@@ -109,10 +131,10 @@ func (rhr *RequestParser) ReadAndParse(r io.Reader) error {
// http level fallback metadata // http level fallback metadata
type FallbackMeta struct { type FallbackMeta struct {
net.Conn net.Conn
FirstBuffer *bytes.Buffer H1RequestBuf *bytes.Buffer
Path string Path string
Method string Method string
IsH2 bool IsH2 bool
H2Request *http.Request H2Request *http.Request
} }

View File

@@ -346,7 +346,7 @@ func handleNewIncomeConnection(inServer proxy.Server, defaultClientForThis proxy
newiics := iics newiics := iics
newiics.theRequestPath = fallbackMeta.Path newiics.theRequestPath = fallbackMeta.Path
newiics.theFallbackFirstBuffer = fallbackMeta.FirstBuffer newiics.theFallbackFirstBuffer = fallbackMeta.H1RequestBuf
newiics.wrappedConn = fallbackMeta.Conn newiics.wrappedConn = fallbackMeta.Conn
newiics.isFallbackH2 = fallbackMeta.IsH2 newiics.isFallbackH2 = fallbackMeta.IsH2
newiics.fallbackH2Request = fallbackMeta.H2Request newiics.fallbackH2Request = fallbackMeta.H2Request
@@ -383,7 +383,7 @@ func handleNewIncomeConnection(inServer proxy.Server, defaultClientForThis proxy
meta := wsConn.(httpLayer.FallbackMeta) meta := wsConn.(httpLayer.FallbackMeta)
iics.theRequestPath = meta.Path iics.theRequestPath = meta.Path
iics.theFallbackFirstBuffer = meta.FirstBuffer iics.theFallbackFirstBuffer = meta.H1RequestBuf
iics.wrappedConn = meta.Conn iics.wrappedConn = meta.Conn
if ce := utils.CanLogDebug("Single AdvLayer Check failed, will fallback."); ce != nil { if ce := utils.CanLogDebug("Single AdvLayer Check failed, will fallback."); ce != nil {

View File

@@ -17,6 +17,7 @@ type ByteWriter interface {
Write(p []byte) (n int, err error) Write(p []byte) (n int, err error)
} }
//optionally read from OptionalReader
type ReadWrapper struct { type ReadWrapper struct {
io.Reader io.Reader
OptionalReader io.Reader OptionalReader io.Reader
@@ -47,6 +48,7 @@ type DummyReadCloser struct {
ReadCount int ReadCount int
} }
// ReadCount -= 1 at each call.
//if ReadCount<0, return 0, io.EOF //if ReadCount<0, return 0, io.EOF
func (d *DummyReadCloser) Read(p []byte) (int, error) { func (d *DummyReadCloser) Read(p []byte) (int, error) {
d.ReadCount -= 1 d.ReadCount -= 1
@@ -68,6 +70,7 @@ type DummyWriteCloser struct {
WriteCount int WriteCount int
} }
// WriteCount -= 1 at each call.
//if WriteCount<0, return 0, io.EOF //if WriteCount<0, return 0, io.EOF
func (d *DummyWriteCloser) Write(p []byte) (int, error) { func (d *DummyWriteCloser) Write(p []byte) (int, error) {
d.WriteCount -= 1 d.WriteCount -= 1
@@ -86,10 +89,12 @@ func (DummyWriteCloser) Close() error {
return nil return nil
} }
//先从Old读若SwitchChan被关闭, 立刻改为从New读
type ReadSwitcher struct { type ReadSwitcher struct {
Old, New io.Reader Old, New io.Reader //non-nil
SwitchChan chan struct{} //non-nil
io.Closer io.Closer
SwitchChan chan struct{}
readOnce sync.Once readOnce sync.Once
@@ -129,7 +134,6 @@ func (d *ReadSwitcher) Read(p []byte) (int, error) {
} }
} }
//return nil
func (d *ReadSwitcher) Close() error { func (d *ReadSwitcher) Close() error {
if d.Closer != nil { if d.Closer != nil {
return d.Closer.Close() return d.Closer.Close()
@@ -137,10 +141,11 @@ func (d *ReadSwitcher) Close() error {
return nil return nil
} }
//先向Old写若SwitchChan被关闭, 改为向New写
type WriteSwitcher struct { type WriteSwitcher struct {
Old, New io.Writer Old, New io.Writer //non-nil
SwitchChan chan struct{} //non-nil
io.Closer io.Closer
SwitchChan chan struct{}
} }
func (d *WriteSwitcher) Write(p []byte) (int, error) { func (d *WriteSwitcher) Write(p []byte) (int, error) {
@@ -154,7 +159,6 @@ func (d *WriteSwitcher) Write(p []byte) (int, error) {
} }
} }
//return nil
func (d *WriteSwitcher) Close() error { func (d *WriteSwitcher) Close() error {
if d.Closer != nil { if d.Closer != nil {
return d.Closer.Close() return d.Closer.Close()