Add health check support for http-based v2ray transport

This commit is contained in:
世界 2023-03-11 15:49:02 +08:00
parent bdc620dab1
commit 6af9c2b3ca
No known key found for this signature in database
GPG key ID: CD109927C34A63C4
7 changed files with 45 additions and 12 deletions

View file

@ -65,6 +65,8 @@ type V2RayHTTPOptions struct {
Path string `json:"path,omitempty"` Path string `json:"path,omitempty"`
Method string `json:"method,omitempty"` Method string `json:"method,omitempty"`
Headers map[string]string `json:"headers,omitempty"` Headers map[string]string `json:"headers,omitempty"`
IdleTimeout Duration `json:"idle_timeout,omitempty"`
PingTimeout Duration `json:"ping_timeout,omitempty"`
} }
type V2RayWebsocketOptions struct { type V2RayWebsocketOptions struct {
@ -78,5 +80,8 @@ type V2RayQUICOptions struct{}
type V2RayGRPCOptions struct { type V2RayGRPCOptions struct {
ServiceName string `json:"service_name,omitempty"` ServiceName string `json:"service_name,omitempty"`
IdleTimeout Duration `json:"idle_timeout,omitempty"`
PingTimeout Duration `json:"ping_timeout,omitempty"`
PermitWithoutStream bool `json:"permit_without_stream,omitempty"`
ForceLite bool `json:"-"` // for test ForceLite bool `json:"-"` // for test
} }

View file

@ -18,6 +18,7 @@ import (
"google.golang.org/grpc/backoff" "google.golang.org/grpc/backoff"
"google.golang.org/grpc/connectivity" "google.golang.org/grpc/connectivity"
"google.golang.org/grpc/credentials/insecure" "google.golang.org/grpc/credentials/insecure"
"google.golang.org/grpc/keepalive"
) )
var _ adapter.V2RayClientTransport = (*Client)(nil) var _ adapter.V2RayClientTransport = (*Client)(nil)
@ -40,6 +41,13 @@ func NewClient(ctx context.Context, dialer N.Dialer, serverAddr M.Socksaddr, opt
} else { } else {
dialOptions = append(dialOptions, grpc.WithTransportCredentials(insecure.NewCredentials())) dialOptions = append(dialOptions, grpc.WithTransportCredentials(insecure.NewCredentials()))
} }
if options.IdleTimeout > 0 {
dialOptions = append(dialOptions, grpc.WithKeepaliveParams(keepalive.ClientParameters{
Time: time.Duration(options.IdleTimeout),
Timeout: time.Duration(options.PingTimeout),
PermitWithoutStream: options.PermitWithoutStream,
}))
}
dialOptions = append(dialOptions, grpc.WithConnectParams(grpc.ConnectParams{ dialOptions = append(dialOptions, grpc.WithConnectParams(grpc.ConnectParams{
Backoff: backoff.Config{ Backoff: backoff.Config{
BaseDelay: 500 * time.Millisecond, BaseDelay: 500 * time.Millisecond,

View file

@ -5,6 +5,7 @@ import (
"net" "net"
"os" "os"
"strings" "strings"
"time"
"github.com/sagernet/sing-box/adapter" "github.com/sagernet/sing-box/adapter"
"github.com/sagernet/sing-box/common/tls" "github.com/sagernet/sing-box/common/tls"
@ -13,6 +14,7 @@ import (
N "github.com/sagernet/sing/common/network" N "github.com/sagernet/sing/common/network"
"google.golang.org/grpc" "google.golang.org/grpc"
"google.golang.org/grpc/keepalive"
gM "google.golang.org/grpc/metadata" gM "google.golang.org/grpc/metadata"
"google.golang.org/grpc/peer" "google.golang.org/grpc/peer"
) )
@ -31,6 +33,12 @@ func NewServer(ctx context.Context, options option.V2RayGRPCOptions, tlsConfig t
tlsConfig.SetNextProtos([]string{"h2"}) tlsConfig.SetNextProtos([]string{"h2"})
serverOptions = append(serverOptions, grpc.Creds(NewTLSTransportCredentials(tlsConfig))) serverOptions = append(serverOptions, grpc.Creds(NewTLSTransportCredentials(tlsConfig)))
} }
if options.IdleTimeout > 0 {
serverOptions = append(serverOptions, grpc.KeepaliveParams(keepalive.ServerParameters{
Time: time.Duration(options.IdleTimeout),
Timeout: time.Duration(options.PingTimeout),
}))
}
server := &Server{ctx, handler, grpc.NewServer(serverOptions...)} server := &Server{ctx, handler, grpc.NewServer(serverOptions...)}
RegisterGunServiceCustomNameServer(server.server, server, options.ServiceName) RegisterGunServiceCustomNameServer(server.server, server, options.ServiceName)
return server, nil return server, nil

View file

@ -7,6 +7,7 @@ import (
"net" "net"
"net/http" "net/http"
"net/url" "net/url"
"time"
"github.com/sagernet/sing-box/adapter" "github.com/sagernet/sing-box/adapter"
"github.com/sagernet/sing-box/common/tls" "github.com/sagernet/sing-box/common/tls"
@ -45,6 +46,8 @@ func NewClient(ctx context.Context, dialer N.Dialer, serverAddr M.Socksaddr, opt
} else { } else {
tlsConfig.SetNextProtos([]string{http2.NextProtoTLS}) tlsConfig.SetNextProtos([]string{http2.NextProtoTLS})
transport = &http2.Transport{ transport = &http2.Transport{
ReadIdleTimeout: time.Duration(options.IdleTimeout),
PingTimeout: time.Duration(options.PingTimeout),
DialTLSContext: func(ctx context.Context, network, addr string, cfg *tls.STDConfig) (net.Conn, error) { DialTLSContext: func(ctx context.Context, network, addr string, cfg *tls.STDConfig) (net.Conn, error) {
conn, err := dialer.DialContext(ctx, network, M.ParseSocksaddr(addr)) conn, err := dialer.DialContext(ctx, network, M.ParseSocksaddr(addr))
if err != nil { if err != nil {

View file

@ -8,6 +8,7 @@ import (
"net/url" "net/url"
"os" "os"
"strings" "strings"
"time"
"github.com/sagernet/sing-box/adapter" "github.com/sagernet/sing-box/adapter"
"github.com/sagernet/sing-box/common/tls" "github.com/sagernet/sing-box/common/tls"
@ -45,7 +46,9 @@ func NewServer(ctx context.Context, options option.V2RayGRPCOptions, tlsConfig t
tlsConfig: tlsConfig, tlsConfig: tlsConfig,
handler: handler, handler: handler,
path: fmt.Sprintf("/%s/Tun", url.QueryEscape(options.ServiceName)), path: fmt.Sprintf("/%s/Tun", url.QueryEscape(options.ServiceName)),
h2Server: new(http2.Server), h2Server: &http2.Server{
IdleTimeout: time.Duration(options.IdleTimeout),
},
} }
server.httpServer = &http.Server{ server.httpServer = &http.Server{
Handler: server, Handler: server,

View file

@ -9,6 +9,7 @@ import (
"net/http" "net/http"
"net/url" "net/url"
"strings" "strings"
"time"
"github.com/sagernet/sing-box/adapter" "github.com/sagernet/sing-box/adapter"
"github.com/sagernet/sing-box/common/tls" "github.com/sagernet/sing-box/common/tls"
@ -45,6 +46,8 @@ func NewClient(ctx context.Context, dialer N.Dialer, serverAddr M.Socksaddr, opt
} else { } else {
tlsConfig.SetNextProtos([]string{http2.NextProtoTLS}) tlsConfig.SetNextProtos([]string{http2.NextProtoTLS})
transport = &http2.Transport{ transport = &http2.Transport{
ReadIdleTimeout: time.Duration(options.IdleTimeout),
PingTimeout: time.Duration(options.PingTimeout),
DialTLSContext: func(ctx context.Context, network, addr string, cfg *tls.STDConfig) (net.Conn, error) { DialTLSContext: func(ctx context.Context, network, addr string, cfg *tls.STDConfig) (net.Conn, error) {
conn, err := dialer.DialContext(ctx, network, M.ParseSocksaddr(addr)) conn, err := dialer.DialContext(ctx, network, M.ParseSocksaddr(addr))
if err != nil { if err != nil {

View file

@ -6,6 +6,7 @@ import (
"net/http" "net/http"
"os" "os"
"strings" "strings"
"time"
"github.com/sagernet/sing-box/adapter" "github.com/sagernet/sing-box/adapter"
"github.com/sagernet/sing-box/common/tls" "github.com/sagernet/sing-box/common/tls"
@ -46,7 +47,9 @@ func NewServer(ctx context.Context, options option.V2RayHTTPOptions, tlsConfig t
ctx: ctx, ctx: ctx,
tlsConfig: tlsConfig, tlsConfig: tlsConfig,
handler: handler, handler: handler,
h2Server: new(http2.Server), h2Server: &http2.Server{
IdleTimeout: time.Duration(options.IdleTimeout),
},
host: options.Host, host: options.Host,
path: options.Path, path: options.Path,
method: options.Method, method: options.Method,