Compare commits

...

10 Commits

Author SHA1 Message Date
世界
6ce4e31fc8 documentation: Update changelog 2023-04-22 08:26:09 +08:00
世界
d2d4faf520 Revert LRU cache changes 2023-04-22 08:23:49 +08:00
世界
438de36749 Make v2ray http2 conn public 2023-04-22 08:14:55 +08:00
世界
df0eef770e Fix http response check
Co-authored-by: armv9 <48624112+arm64v8a@users.noreply.github.com>
2023-04-22 08:14:55 +08:00
世界
bbdd495ed5 Fix v2ray-plugin TLS server name
Co-authored-by: armv9 <48624112+arm64v8a@users.noreply.github.com>
2023-04-21 17:48:36 +08:00
世界
d686172854 Fix grpc lite request host
Co-authored-by: armv9 <48624112+arm64v8a@users.noreply.github.com>
2023-04-21 17:48:36 +08:00
H1JK
e1d96cb64e Add BaseContext to http servers 2023-04-21 17:48:29 +08:00
H1JK
d5f94b65b7 Fix gRPC service name escape 2023-04-21 17:48:29 +08:00
Hellojack
ec2d0b6b3c Remove TLS requirement for gRPC client 2023-04-21 17:48:29 +08:00
世界
3a92bf993d platform: Add UsePlatformAutoDetectInterfaceControl 2023-04-21 17:47:17 +08:00
24 changed files with 104 additions and 74 deletions

View File

@@ -1,6 +1,6 @@
#### 1.2.4
#### 1.2.6
* Fixes and improvements
* Fix bugs and update dependencies
#### 1.2.3

View File

@@ -5,6 +5,7 @@ import (
)
type PlatformInterface interface {
UsePlatformAutoDetectInterfaceControl() bool
AutoDetectInterfaceControl(fd int32) error
OpenTun(options TunOptions) (int32, error)
WriteLog(message string)

View File

@@ -15,6 +15,7 @@ import (
type Interface interface {
Initialize(ctx context.Context, router adapter.Router) error
UsePlatformAutoDetectInterfaceControl() bool
AutoDetectInterfaceControl() control.Func
OpenTun(options *tun.Options, platformOptions option.TunPlatformOptions) (tun.Tun, error)
UsePlatformDefaultInterfaceMonitor() bool

View File

@@ -68,6 +68,10 @@ func (w *platformInterfaceWrapper) Initialize(ctx context.Context, router adapte
return nil
}
func (w *platformInterfaceWrapper) UsePlatformAutoDetectInterfaceControl() bool {
return w.iif.UsePlatformAutoDetectInterfaceControl()
}
func (w *platformInterfaceWrapper) AutoDetectInterfaceControl() control.Func {
return func(network, address string, conn syscall.RawConn) error {
return control.Raw(conn, func(fd uintptr) error {

8
go.mod
View File

@@ -25,11 +25,11 @@ require (
github.com/sagernet/gomobile v0.0.0-20230413023804-244d7ff07035
github.com/sagernet/quic-go v0.0.0-20230202071646-a8c8afb18b32
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691
github.com/sagernet/sing v0.2.4-0.20230418095640-3b5e6c1812d3
github.com/sagernet/sing-dns v0.1.5-0.20230418025317-8a132998b322
github.com/sagernet/sing-shadowsocks v0.2.2-0.20230418025154-6114beeeba6d
github.com/sagernet/sing v0.2.4
github.com/sagernet/sing-dns v0.1.5-0.20230415085626-111ecf799dfc
github.com/sagernet/sing-shadowsocks v0.2.2-0.20230417102954-f77257340507
github.com/sagernet/sing-shadowtls v0.1.2-0.20230417103049-4f682e05f19b
github.com/sagernet/sing-tun v0.1.4-0.20230419061614-d744d03d9302
github.com/sagernet/sing-tun v0.1.4
github.com/sagernet/sing-vmess v0.1.5-0.20230417103030-8c3070ae3fb3
github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37
github.com/sagernet/tfo-go v0.0.0-20230303015439-ffcfd8c41cf9

16
go.sum
View File

@@ -111,16 +111,16 @@ github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 h1:5Th31OC6yj8byL
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691/go.mod h1:B8lp4WkQ1PwNnrVMM6KyuFR20pU8jYBD+A4EhJovEXU=
github.com/sagernet/sing v0.0.0-20220817130738-ce854cda8522/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY=
github.com/sagernet/sing v0.1.8/go.mod h1:jt1w2u7lJQFFSGLiRrRIs5YWmx4kAPfWuOejuDW9qMk=
github.com/sagernet/sing v0.2.4-0.20230418095640-3b5e6c1812d3 h1:dkH6SEs3yZlUjSXUAn64LUlFAfAgJqiThaWiBKWJ0Q0=
github.com/sagernet/sing v0.2.4-0.20230418095640-3b5e6c1812d3/go.mod h1:Ta8nHnDLAwqySzKhGoKk4ZIB+vJ3GTKj7UPrWYvM+4w=
github.com/sagernet/sing-dns v0.1.5-0.20230418025317-8a132998b322 h1:UDSeJZ2xB3dj1lySnM5LpF48dGlphGstw2BqtkJwcZI=
github.com/sagernet/sing-dns v0.1.5-0.20230418025317-8a132998b322/go.mod h1:2wjxSr1Gbecq9A0ESA9cnR399tQTcpCZEOGytekb+qI=
github.com/sagernet/sing-shadowsocks v0.2.2-0.20230418025154-6114beeeba6d h1:UUxtLujzp5jmtOXqXpSOGvHwHSZcBveKVDzRJ4GlnFU=
github.com/sagernet/sing-shadowsocks v0.2.2-0.20230418025154-6114beeeba6d/go.mod h1:Co3PJXcaZoLwHGBfT0rbSnn9C7ywc41zVYWtDeoeI/Q=
github.com/sagernet/sing v0.2.4 h1:gC8BR5sglbJZX23RtMyFa8EETP9YEUADhfbEzU1yVbo=
github.com/sagernet/sing v0.2.4/go.mod h1:Ta8nHnDLAwqySzKhGoKk4ZIB+vJ3GTKj7UPrWYvM+4w=
github.com/sagernet/sing-dns v0.1.5-0.20230415085626-111ecf799dfc h1:hmbuqKv48SAjiKPoqtJGvS5pEHVPZjTHq9CPwQY2cZ4=
github.com/sagernet/sing-dns v0.1.5-0.20230415085626-111ecf799dfc/go.mod h1:ZKuuqgsHRxDahYrzgSgy4vIAGGuKPlIf4hLcNzYzLkY=
github.com/sagernet/sing-shadowsocks v0.2.2-0.20230417102954-f77257340507 h1:bAHZCdWqJkb8LEW98+YsMVDXGRMUVjka8IC+St6ot88=
github.com/sagernet/sing-shadowsocks v0.2.2-0.20230417102954-f77257340507/go.mod h1:UJjvQGw0lyYaDGIDvUraL16fwaAEH1WFw1Y6sUcMPog=
github.com/sagernet/sing-shadowtls v0.1.2-0.20230417103049-4f682e05f19b h1:ouW/6IDCrxkBe19YSbdCd7buHix7b+UZ6BM4Zz74XF4=
github.com/sagernet/sing-shadowtls v0.1.2-0.20230417103049-4f682e05f19b/go.mod h1:oG8bPerYI6cZ74KquY3DvA7ynECyrILPBnce6wtBqeI=
github.com/sagernet/sing-tun v0.1.4-0.20230419061614-d744d03d9302 h1:aPb0T2HQRTG2t7fEwLvFLZSXmhmnBh+SMs2NufhmrsI=
github.com/sagernet/sing-tun v0.1.4-0.20230419061614-d744d03d9302/go.mod h1:bvcVzlf9q9dgxt8qKluW+zOXCFoN1+SpBG3sHTq8/9Q=
github.com/sagernet/sing-tun v0.1.4 h1:Fa6kgvuM2fPbPu3R97S8L8NgaD5lJq3wQorNuTb5oqo=
github.com/sagernet/sing-tun v0.1.4/go.mod h1:7BrtP7NMp9FK5oVsZWg92b7yFrD+sM2+udapFurReyw=
github.com/sagernet/sing-vmess v0.1.5-0.20230417103030-8c3070ae3fb3 h1:BHOnxrbC929JonuKqFdJ7ZbDp7zs4oTlH5KFvKtWu9U=
github.com/sagernet/sing-vmess v0.1.5-0.20230417103030-8c3070ae3fb3/go.mod h1:yKrAr+dqZd64DxBXCHWrYicp+n4qbqO73mtwv3dck8U=
github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37 h1:HuE6xSwco/Xed8ajZ+coeYLmioq0Qp1/Z2zczFaV8as=

View File

@@ -53,7 +53,7 @@ func NewDirect(ctx context.Context, router adapter.Router, logger log.ContextLog
} else {
udpTimeout = int64(C.UDPTimeout.Seconds())
}
inbound.udpNat = udpnat.New[netip.AddrPort](ctx, udpTimeout, adapter.NewUpstreamContextHandler(inbound.newConnection, inbound.newPacketConnection, inbound))
inbound.udpNat = udpnat.New[netip.AddrPort](udpTimeout, adapter.NewUpstreamContextHandler(inbound.newConnection, inbound.newPacketConnection, inbound))
inbound.connHandler = inbound
inbound.packetHandler = inbound
inbound.packetUpstream = inbound.udpNat

View File

@@ -90,6 +90,9 @@ func (n *Naive) Start() error {
n.httpServer = &http.Server{
Handler: n,
TLSConfig: tlsConfig,
BaseContext: func(listener net.Listener) context.Context {
return n.ctx
},
}
go func() {
var sErr error

View File

@@ -64,11 +64,11 @@ func newShadowsocks(ctx context.Context, router adapter.Router, logger log.Conte
var err error
switch {
case options.Method == shadowsocks.MethodNone:
inbound.service = shadowsocks.NewNoneService(ctx, options.UDPTimeout, inbound.upstreamContextHandler())
inbound.service = shadowsocks.NewNoneService(options.UDPTimeout, inbound.upstreamContextHandler())
case common.Contains(shadowaead.List, options.Method):
inbound.service, err = shadowaead.NewService(ctx, options.Method, nil, options.Password, udpTimeout, inbound.upstreamContextHandler())
inbound.service, err = shadowaead.NewService(options.Method, nil, options.Password, udpTimeout, inbound.upstreamContextHandler())
case common.Contains(shadowaead_2022.List, options.Method):
inbound.service, err = shadowaead_2022.NewServiceWithPassword(ctx, options.Method, options.Password, udpTimeout, inbound.upstreamContextHandler(), router.TimeFunc())
inbound.service, err = shadowaead_2022.NewServiceWithPassword(options.Method, options.Password, udpTimeout, inbound.upstreamContextHandler(), router.TimeFunc())
default:
err = E.New("unsupported method: ", options.Method)
}

View File

@@ -53,7 +53,6 @@ func newShadowsocksMulti(ctx context.Context, router adapter.Router, logger log.
return nil, E.New("unsupported method: " + options.Method)
}
service, err := shadowaead_2022.NewMultiServiceWithPassword[int](
ctx,
options.Method,
options.Password,
udpTimeout,

View File

@@ -50,7 +50,6 @@ func newShadowsocksRelay(ctx context.Context, router adapter.Router, logger log.
udpTimeout = int64(C.UDPTimeout.Seconds())
}
service, err := shadowaead_2022.NewRelayServiceWithPassword[int](
ctx,
options.Method,
options.Password,
udpTimeout,

View File

@@ -45,7 +45,7 @@ func NewTProxy(ctx context.Context, router adapter.Router, logger log.ContextLog
}
tproxy.connHandler = tproxy
tproxy.oobPacketHandler = tproxy
tproxy.udpNat = udpnat.New[netip.AddrPort](ctx, udpTimeout, tproxy.upstreamContextHandler())
tproxy.udpNat = udpnat.New[netip.AddrPort](udpTimeout, tproxy.upstreamContextHandler())
tproxy.packetUpstream = tproxy.udpNat
return tproxy
}

View File

@@ -167,7 +167,7 @@ func (t *Tun) Start() error {
UDPTimeout: t.udpTimeout,
Handler: t,
Logger: t.logger,
UnderPlatform: t.platformInterface != nil,
ForwarderBindInterface: t.platformInterface != nil,
})
if err != nil {
return err

View File

@@ -111,7 +111,7 @@ func NewRouter(
defaultMark: options.DefaultMark,
platformInterface: platformInterface,
}
router.dnsClient = dns.NewClient(ctx, dnsOptions.DNSClientOptions.DisableCache, dnsOptions.DNSClientOptions.DisableExpire, router.dnsLogger)
router.dnsClient = dns.NewClient(dnsOptions.DNSClientOptions.DisableCache, dnsOptions.DNSClientOptions.DisableExpire, router.dnsLogger)
for i, ruleOptions := range options.Rules {
routeRule, err := NewRule(router, router.logger, ruleOptions)
if err != nil {
@@ -823,7 +823,7 @@ func (r *Router) AutoDetectInterface() bool {
}
func (r *Router) AutoDetectInterfaceFunc() control.Func {
if r.platformInterface != nil {
if r.platformInterface != nil && r.platformInterface.UsePlatformAutoDetectInterfaceControl() {
return r.platformInterface.AutoDetectInterfaceControl()
} else {
return control.BindToInterfaceFunc(r.InterfaceFinder(), func(network string, address string) (interfaceName string, interfaceIndex int) {

View File

@@ -45,6 +45,7 @@ func newV2RayPlugin(pluginOpts Args, router adapter.Router, dialer N.Dialer, ser
if hostOpt, loaded := pluginOpts.Get("host"); loaded {
host = hostOpt
tlsOptions.ServerName = hostOpt
}
if pathOpt, loaded := pluginOpts.Get("path"); loaded {
path = pathOpt

View File

@@ -48,9 +48,6 @@ func NewClientTransport(ctx context.Context, dialer N.Dialer, serverAddr M.Socks
case C.V2RayTransportTypeHTTP:
return v2rayhttp.NewClient(ctx, dialer, serverAddr, options.HTTPOptions, tlsConfig)
case C.V2RayTransportTypeGRPC:
if tlsConfig == nil {
return nil, C.ErrTLSRequired
}
return NewGRPCClient(ctx, dialer, serverAddr, options.GRPCOptions, tlsConfig)
case C.V2RayTransportTypeWebsocket:
return v2raywebsocket.NewClient(ctx, dialer, serverAddr, options.WebsocketOptions, tlsConfig), nil

View File

@@ -36,7 +36,9 @@ type Client struct {
func NewClient(ctx context.Context, dialer N.Dialer, serverAddr M.Socksaddr, options option.V2RayGRPCOptions, tlsConfig tls.Config) (adapter.V2RayClientTransport, error) {
var dialOptions []grpc.DialOption
if tlsConfig != nil {
tlsConfig.SetNextProtos([]string{http2.NextProtoTLS})
if len(tlsConfig.NextProtos()) == 0 {
tlsConfig.SetNextProtos([]string{http2.NextProtoTLS})
}
dialOptions = append(dialOptions, grpc.WithTransportCredentials(NewTLSTransportCredentials(tlsConfig)))
} else {
dialOptions = append(dialOptions, grpc.WithTransportCredentials(insecure.NewCredentials()))

View File

@@ -2,7 +2,6 @@ package v2raygrpclite
import (
"context"
"fmt"
"io"
"net"
"net/http"
@@ -13,6 +12,7 @@ import (
"github.com/sagernet/sing-box/common/tls"
"github.com/sagernet/sing-box/option"
"github.com/sagernet/sing-box/transport/v2rayhttp"
E "github.com/sagernet/sing/common/exceptions"
M "github.com/sagernet/sing/common/metadata"
N "github.com/sagernet/sing/common/network"
@@ -31,71 +31,83 @@ type Client struct {
ctx context.Context
dialer N.Dialer
serverAddr M.Socksaddr
transport http.RoundTripper
transport *http2.Transport
options option.V2RayGRPCOptions
url *url.URL
}
func NewClient(ctx context.Context, dialer N.Dialer, serverAddr M.Socksaddr, options option.V2RayGRPCOptions, tlsConfig tls.Config) adapter.V2RayClientTransport {
var transport http.RoundTripper
if tlsConfig == nil {
transport = &http.Transport{
DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
return dialer.DialContext(ctx, network, M.ParseSocksaddr(addr))
},
}
var host string
if tlsConfig != nil && tlsConfig.ServerName() != "" {
host = M.ParseSocksaddrHostPort(tlsConfig.ServerName(), serverAddr.Port).String()
} else {
tlsConfig.SetNextProtos([]string{http2.NextProtoTLS})
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) {
conn, err := dialer.DialContext(ctx, network, M.ParseSocksaddr(addr))
if err != nil {
return nil, err
}
return tls.ClientHandshake(ctx, conn, tlsConfig)
},
}
host = serverAddr.String()
}
return &Client{
client := &Client{
ctx: ctx,
dialer: dialer,
serverAddr: serverAddr,
options: options,
transport: transport,
transport: &http2.Transport{
ReadIdleTimeout: time.Duration(options.IdleTimeout),
PingTimeout: time.Duration(options.PingTimeout),
DisableCompression: true,
},
url: &url.URL{
Scheme: "https",
Host: serverAddr.String(),
Path: fmt.Sprintf("/%s/Tun", url.QueryEscape(options.ServiceName)),
Scheme: "https",
Host: host,
Path: "/" + options.ServiceName + "/Tun",
RawPath: "/" + url.PathEscape(options.ServiceName) + "/Tun",
},
}
if tlsConfig == nil {
client.transport.DialTLSContext = func(ctx context.Context, network, addr string, cfg *tls.STDConfig) (net.Conn, error) {
return dialer.DialContext(ctx, network, M.ParseSocksaddr(addr))
}
} else {
if len(tlsConfig.NextProtos()) == 0 {
tlsConfig.SetNextProtos([]string{http2.NextProtoTLS})
}
client.transport.DialTLSContext = func(ctx context.Context, network, addr string, cfg *tls.STDConfig) (net.Conn, error) {
conn, err := dialer.DialContext(ctx, network, M.ParseSocksaddr(addr))
if err != nil {
return nil, err
}
return tls.ClientHandshake(ctx, conn, tlsConfig)
}
}
return client
}
func (c *Client) DialContext(ctx context.Context) (net.Conn, error) {
pipeInReader, pipeInWriter := io.Pipe()
request := &http.Request{
Method: http.MethodPost,
Body: pipeInReader,
URL: c.url,
Proto: "HTTP/2",
ProtoMajor: 2,
Header: defaultClientHeader,
Method: http.MethodPost,
Body: pipeInReader,
URL: c.url,
Header: defaultClientHeader,
}
request = request.WithContext(ctx)
conn := newLateGunConn(pipeInWriter)
go func() {
response, err := c.transport.RoundTrip(request)
if err == nil {
conn.setup(response.Body, nil)
} else {
if err != nil {
conn.setup(nil, err)
} else if response.StatusCode != 200 {
response.Body.Close()
conn.setup(nil, E.New("unexpected status: ", response.StatusCode, " ", response.Status))
} else {
conn.setup(response.Body, nil)
}
}()
return conn, nil
}
func (c *Client) Close() error {
v2rayhttp.CloseIdleConnections(c.transport)
if c.transport != nil {
v2rayhttp.CloseIdleConnections(c.transport)
}
return nil
}

View File

@@ -117,6 +117,7 @@ func (c *GunConn) WriteBuffer(buffer *buf.Buffer) error {
dataLen := buffer.Len()
varLen := rw.UVariantLen(uint64(dataLen))
header := buffer.ExtendHeader(6 + varLen)
_ = header[6]
header[0] = 0x00
binary.BigEndian.PutUint32(header[1:5], uint32(1+varLen+dataLen))
header[5] = 0x0A

View File

@@ -2,10 +2,8 @@ package v2raygrpclite
import (
"context"
"fmt"
"net"
"net/http"
"net/url"
"os"
"strings"
"time"
@@ -45,13 +43,16 @@ func NewServer(ctx context.Context, options option.V2RayGRPCOptions, tlsConfig t
server := &Server{
tlsConfig: tlsConfig,
handler: handler,
path: fmt.Sprintf("/%s/Tun", url.QueryEscape(options.ServiceName)),
path: "/" + options.ServiceName + "/Tun",
h2Server: &http2.Server{
IdleTimeout: time.Duration(options.IdleTimeout),
},
}
server.httpServer = &http.Server{
Handler: server,
BaseContext: func(net.Listener) context.Context {
return ctx
},
}
server.h2cHandler = h2c.NewHandler(server, server.h2Server)
return server, nil

View File

@@ -43,7 +43,9 @@ func NewClient(ctx context.Context, dialer N.Dialer, serverAddr M.Socksaddr, opt
},
}
} else {
tlsConfig.SetNextProtos([]string{http2.NextProtoTLS})
if len(tlsConfig.NextProtos()) == 0 {
tlsConfig.SetNextProtos([]string{http2.NextProtoTLS})
}
transport = &http2.Transport{
ReadIdleTimeout: time.Duration(options.IdleTimeout),
PingTimeout: time.Duration(options.PingTimeout),
@@ -137,15 +139,16 @@ func (c *Client) dialHTTP2(ctx context.Context) (net.Conn, error) {
default:
request.Host = c.host[rand.Intn(hostLen)]
}
conn := newLateHTTPConn(pipeInWriter)
conn := NewLateHTTPConn(pipeInWriter)
go func() {
response, err := c.transport.RoundTrip(request)
if err != nil {
conn.setup(nil, err)
conn.Setup(nil, err)
} else if response.StatusCode != 200 {
conn.setup(nil, E.New("unexpected status: ", response.StatusCode, " ", response.Status))
response.Body.Close()
conn.Setup(nil, E.New("unexpected status: ", response.StatusCode, " ", response.Status))
} else {
conn.setup(response.Body, nil)
conn.Setup(response.Body, nil)
}
}()
return conn, nil

View File

@@ -140,14 +140,14 @@ func NewHTTPConn(reader io.Reader, writer io.Writer) HTTP2Conn {
}
}
func newLateHTTPConn(writer io.Writer) *HTTP2Conn {
func NewLateHTTPConn(writer io.Writer) *HTTP2Conn {
return &HTTP2Conn{
create: make(chan struct{}),
writer: writer,
}
}
func (c *HTTP2Conn) setup(reader io.Reader, err error) {
func (c *HTTP2Conn) Setup(reader io.Reader, err error) {
c.reader = reader
c.err = err
close(c.create)

View File

@@ -70,6 +70,9 @@ func NewServer(ctx context.Context, options option.V2RayHTTPOptions, tlsConfig t
Handler: server,
ReadHeaderTimeout: C.TCPTimeout,
MaxHeaderBytes: http.DefaultMaxHeaderBytes,
BaseContext: func(net.Listener) context.Context {
return ctx
},
}
server.h2cHandler = h2c.NewHandler(server, server.h2Server)
return server, nil

View File

@@ -52,6 +52,9 @@ func NewServer(ctx context.Context, options option.V2RayWebsocketOptions, tlsCon
Handler: server,
ReadHeaderTimeout: C.TCPTimeout,
MaxHeaderBytes: http.DefaultMaxHeaderBytes,
BaseContext: func(net.Listener) context.Context {
return ctx
},
}
return server, nil
}