Compare commits

..

18 Commits

Author SHA1 Message Date
世界
fbb01555c8 documentation: Update changelog 2023-04-19 22:05:54 +08:00
世界
3c217fea63 Improve VLESS request 2023-04-19 22:00:05 +08:00
世界
a02c676d33 Update badtls 2023-04-19 22:00:05 +08:00
世界
c2ae261c8d Add deadline interface 2023-04-19 22:00:05 +08:00
世界
1fe69cc08c shadowsocks: Multi-user support for legacy AEAD inbound
Signed-off-by: wwqgtxx <wwqgtxx@gmail.com>
2023-04-19 22:00:05 +08:00
世界
dacb885930 Add headers option for HTTP outbound 2023-04-19 22:00:05 +08:00
世界
31682c313b URLTest improvements 2023-04-19 21:59:59 +08:00
世界
6fd73131cb Fix wireguard reconnect 2023-04-19 21:59:58 +08:00
世界
f3ff76abcc Use HTTPS URLTest source 2023-04-19 21:59:58 +08:00
H1JK
d9757bfaff Add BaseContext to http servers 2023-04-19 21:59:58 +08:00
H1JK
9d97ed6220 Fix gRPC service name escape 2023-04-19 21:59:58 +08:00
Hellojack
054211d091 Remove TLS requirement for gRPC client 2023-04-19 21:59:51 +08:00
世界
69b92810d6 clash-api: Add Clash.Meta APIs 2023-04-19 21:59:51 +08:00
世界
ea23267ced clash api: download clash-dashboard if external-ui directory is empty 2023-04-19 21:59:51 +08:00
世界
bbe2b1ab09 Add multi-peer support for wireguard outbound 2023-04-19 21:59:51 +08:00
世界
d3530a54fb Add fakeip support 2023-04-19 21:59:47 +08:00
世界
c238df9309 Add L3 routing support 2023-04-19 21:59:47 +08:00
世界
a223262678 Add dns reverse mapping 2023-04-19 21:59:47 +08:00
56 changed files with 426 additions and 1071 deletions

3
box.go
View File

@@ -62,7 +62,6 @@ func New(options Options) (*Box, error) {
defaultLogWriter = io.Discard
}
logFactory, err := log.New(log.Options{
Context: ctx,
Options: common.PtrValueOrDefault(options.Log),
Observable: needClashAPI,
DefaultWriter: defaultLogWriter,
@@ -143,7 +142,7 @@ func New(options Options) (*Box, error) {
preServices := make(map[string]adapter.Service)
postServices := make(map[string]adapter.Service)
if needClashAPI {
clashServer, err := experimental.NewClashServer(ctx, router, logFactory.(log.ObservableFactory), common.PtrValueOrDefault(options.Experimental.ClashAPI))
clashServer, err := experimental.NewClashServer(router, logFactory.(log.ObservableFactory), common.PtrValueOrDefault(options.Experimental.ClashAPI))
if err != nil {
return nil, E.Cause(err, "create clash api server")
}

44
cmd/sing-box/debug.go Normal file
View File

@@ -0,0 +1,44 @@
//go:build debug
package main
import (
"encoding/json"
"net/http"
_ "net/http/pprof"
"runtime"
"runtime/debug"
"github.com/sagernet/sing-box/common/badjson"
"github.com/sagernet/sing-box/log"
"github.com/dustin/go-humanize"
)
func init() {
http.HandleFunc("/debug/gc", func(writer http.ResponseWriter, request *http.Request) {
writer.WriteHeader(http.StatusNoContent)
go debug.FreeOSMemory()
})
http.HandleFunc("/debug/memory", func(writer http.ResponseWriter, request *http.Request) {
var memStats runtime.MemStats
runtime.ReadMemStats(&memStats)
var memObject badjson.JSONObject
memObject.Put("heap", humanize.IBytes(memStats.HeapInuse))
memObject.Put("stack", humanize.IBytes(memStats.StackInuse))
memObject.Put("idle", humanize.IBytes(memStats.HeapIdle-memStats.HeapReleased))
memObject.Put("goroutines", runtime.NumGoroutine())
memObject.Put("rss", rusageMaxRSS())
encoder := json.NewEncoder(writer)
encoder.SetIndent("", " ")
encoder.Encode(memObject)
})
go func() {
err := http.ListenAndServe("0.0.0.0:8964", nil)
if err != nil {
log.Debug(err)
}
}()
}

View File

@@ -1,4 +1,6 @@
package box
//go:build debug
package main
import (
"runtime"

View File

@@ -1,6 +1,6 @@
//go:build !linux
//go:build debug && !linux
package box
package main
func rusageMaxRSS() float64 {
return -1

View File

@@ -28,10 +28,9 @@ type Client struct {
maxConnections int
minStreams int
maxStreams int
paddingEnabled bool
}
func NewClient(ctx context.Context, dialer N.Dialer, protocol Protocol, maxConnections int, minStreams int, maxStreams int, paddingEnabled bool) (*Client, error) {
func NewClient(ctx context.Context, dialer N.Dialer, protocol Protocol, maxConnections int, minStreams int, maxStreams int) *Client {
return &Client{
ctx: ctx,
dialer: dialer,
@@ -39,11 +38,10 @@ func NewClient(ctx context.Context, dialer N.Dialer, protocol Protocol, maxConne
maxConnections: maxConnections,
minStreams: minStreams,
maxStreams: maxStreams,
paddingEnabled: paddingEnabled,
}, nil
}
}
func NewClientWithOptions(ctx context.Context, dialer N.Dialer, options option.MultiplexOptions) (*Client, error) {
func NewClientWithOptions(ctx context.Context, dialer N.Dialer, options option.MultiplexOptions) (N.Dialer, error) {
if !options.Enabled {
return nil, nil
}
@@ -54,7 +52,7 @@ func NewClientWithOptions(ctx context.Context, dialer N.Dialer, options option.M
if err != nil {
return nil, err
}
return NewClient(ctx, dialer, protocol, options.MaxConnections, options.MinStreams, options.MaxStreams, options.Padding)
return NewClient(ctx, dialer, protocol, options.MaxConnections, options.MinStreams, options.MaxStreams), nil
}
func (c *Client) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
@@ -122,16 +120,17 @@ func (c *Client) offer() (abstractSession, error) {
sessions = append(sessions, element.Value)
element = element.Next()
}
session := common.MinBy(common.Filter(sessions, abstractSession.CanTakeNewRequest), abstractSession.NumStreams)
if session == nil {
sLen := len(sessions)
if sLen == 0 {
return c.offerNew()
}
session := common.MinBy(sessions, abstractSession.NumStreams)
numStreams := session.NumStreams()
if numStreams == 0 {
return session, nil
}
if c.maxConnections > 0 {
if len(sessions) >= c.maxConnections || numStreams < c.minStreams {
if sLen >= c.maxConnections || numStreams < c.minStreams {
return session, nil
}
} else {
@@ -147,19 +146,10 @@ func (c *Client) offerNew() (abstractSession, error) {
if err != nil {
return nil, err
}
var version byte
if c.paddingEnabled {
version = Version1
if vectorisedWriter, isVectorised := bufio.CreateVectorisedWriter(conn); isVectorised {
conn = &vectorisedProtocolConn{protocolConn{Conn: conn, protocol: c.protocol}, vectorisedWriter}
} else {
version = Version0
}
conn = newProtocolConn(conn, Request{
Version: version,
Protocol: c.protocol,
PaddingEnabled: c.paddingEnabled,
})
if c.paddingEnabled {
conn = newPaddingConn(conn)
conn = &protocolConn{Conn: conn, protocol: c.protocol}
}
session, err := c.protocol.newClient(conn)
if err != nil {
@@ -169,15 +159,6 @@ func (c *Client) offerNew() (abstractSession, error) {
return session, nil
}
func (c *Client) Reset() {
c.access.Lock()
defer c.access.Unlock()
for _, session := range c.connections.Array() {
session.Close()
}
c.connections.Init()
}
func (c *Client) Close() error {
c.access.Lock()
defer c.access.Unlock()
@@ -224,7 +205,7 @@ func (c *ClientConn) Write(b []byte) (n int, err error) {
Network: N.NetworkTCP,
Destination: c.destination,
}
_buffer := buf.StackNewSize(streamRequestLen(request) + len(b))
_buffer := buf.StackNewSize(requestLen(request) + len(b))
defer common.KeepAlive(_buffer)
buffer := common.Dup(_buffer)
defer buffer.Release()
@@ -318,7 +299,7 @@ func (c *ClientPacketConn) writeRequest(payload []byte) (n int, err error) {
Network: N.NetworkUDP,
Destination: c.destination,
}
rLen := streamRequestLen(request)
rLen := requestLen(request)
if len(payload) > 0 {
rLen += 2 + len(payload)
}
@@ -463,7 +444,7 @@ func (c *ClientPacketAddrConn) writeRequest(payload []byte, destination M.Socksa
Destination: c.destination,
PacketAddr: true,
}
rLen := streamRequestLen(request)
rLen := requestLen(request)
if len(payload) > 0 {
rLen += M.SocksaddrSerializer.AddrPortLen(destination) + 2 + len(payload)
}

View File

@@ -1,235 +0,0 @@
package mux
import (
"context"
"crypto/tls"
"io"
"net"
"net/http"
"net/url"
"os"
"time"
"github.com/sagernet/sing-box/transport/v2rayhttp"
"github.com/sagernet/sing/common/atomic"
"github.com/sagernet/sing/common/buf"
"github.com/sagernet/sing/common/bufio"
E "github.com/sagernet/sing/common/exceptions"
N "github.com/sagernet/sing/common/network"
"golang.org/x/net/http2"
)
const idleTimeout = 30 * time.Second
var _ abstractSession = (*H2MuxServerSession)(nil)
type H2MuxServerSession struct {
server http2.Server
active atomic.Int32
conn net.Conn
inbound chan net.Conn
done chan struct{}
}
func NewH2MuxServer(conn net.Conn) *H2MuxServerSession {
session := &H2MuxServerSession{
conn: conn,
inbound: make(chan net.Conn),
done: make(chan struct{}),
server: http2.Server{
IdleTimeout: idleTimeout,
},
}
go func() {
session.server.ServeConn(conn, &http2.ServeConnOpts{
Handler: session,
})
_ = session.Close()
}()
return session
}
func (s *H2MuxServerSession) ServeHTTP(writer http.ResponseWriter, request *http.Request) {
s.active.Add(1)
defer s.active.Add(-1)
writer.WriteHeader(http.StatusOK)
conn := newHTTP2Wrapper(&v2rayhttp.ServerHTTPConn{
HTTP2Conn: v2rayhttp.NewHTTPConn(request.Body, writer),
Flusher: writer.(http.Flusher),
})
s.inbound <- conn
select {
case <-conn.done:
case <-s.done:
}
}
func (s *H2MuxServerSession) Open() (net.Conn, error) {
return nil, os.ErrInvalid
}
func (s *H2MuxServerSession) Accept() (net.Conn, error) {
select {
case conn := <-s.inbound:
return conn, nil
case <-s.done:
return nil, os.ErrClosed
}
}
func (s *H2MuxServerSession) NumStreams() int {
return int(s.active.Load())
}
func (s *H2MuxServerSession) Close() error {
select {
case <-s.done:
default:
close(s.done)
}
return s.conn.Close()
}
func (s *H2MuxServerSession) IsClosed() bool {
select {
case <-s.done:
return true
default:
return false
}
}
func (s *H2MuxServerSession) CanTakeNewRequest() bool {
return false
}
type h2MuxConnWrapper struct {
N.ExtendedConn
done chan struct{}
}
func newHTTP2Wrapper(conn net.Conn) *h2MuxConnWrapper {
return &h2MuxConnWrapper{
ExtendedConn: bufio.NewExtendedConn(conn),
done: make(chan struct{}),
}
}
func (w *h2MuxConnWrapper) Write(p []byte) (n int, err error) {
select {
case <-w.done:
return 0, net.ErrClosed
default:
}
return w.ExtendedConn.Write(p)
}
func (w *h2MuxConnWrapper) WriteBuffer(buffer *buf.Buffer) error {
select {
case <-w.done:
return net.ErrClosed
default:
}
return w.ExtendedConn.WriteBuffer(buffer)
}
func (w *h2MuxConnWrapper) Close() error {
select {
case <-w.done:
default:
close(w.done)
}
return w.ExtendedConn.Close()
}
func (w *h2MuxConnWrapper) Upstream() any {
return w.ExtendedConn
}
var _ abstractSession = (*H2MuxClientSession)(nil)
type H2MuxClientSession struct {
transport *http2.Transport
clientConn *http2.ClientConn
done chan struct{}
}
func NewH2MuxClient(conn net.Conn) (*H2MuxClientSession, error) {
session := &H2MuxClientSession{
transport: &http2.Transport{
DialTLSContext: func(ctx context.Context, network, addr string, cfg *tls.Config) (net.Conn, error) {
return conn, nil
},
ReadIdleTimeout: idleTimeout,
},
done: make(chan struct{}),
}
session.transport.ConnPool = session
clientConn, err := session.transport.NewClientConn(conn)
if err != nil {
return nil, err
}
session.clientConn = clientConn
return session, nil
}
func (s *H2MuxClientSession) GetClientConn(req *http.Request, addr string) (*http2.ClientConn, error) {
return s.clientConn, nil
}
func (s *H2MuxClientSession) MarkDead(conn *http2.ClientConn) {
s.Close()
}
func (s *H2MuxClientSession) Open() (net.Conn, error) {
pipeInReader, pipeInWriter := io.Pipe()
request := &http.Request{
Method: http.MethodConnect,
Body: pipeInReader,
URL: &url.URL{Scheme: "https", Host: "localhost"},
}
conn := v2rayhttp.NewLateHTTPConn(pipeInWriter)
go func() {
response, err := s.transport.RoundTrip(request)
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 (s *H2MuxClientSession) Accept() (net.Conn, error) {
return nil, os.ErrInvalid
}
func (s *H2MuxClientSession) NumStreams() int {
return s.clientConn.State().StreamsActive
}
func (s *H2MuxClientSession) Close() error {
select {
case <-s.done:
default:
close(s.done)
}
return s.clientConn.Close()
}
func (s *H2MuxClientSession) IsClosed() bool {
select {
case <-s.done:
return true
default:
}
return s.clientConn.State().Closed
}
func (s *H2MuxClientSession) CanTakeNewRequest() bool {
return s.clientConn.CanTakeNewRequest()
}

View File

@@ -1,240 +0,0 @@
package mux
import (
"encoding/binary"
"io"
"math/rand"
"net"
"github.com/sagernet/sing/common"
"github.com/sagernet/sing/common/buf"
"github.com/sagernet/sing/common/bufio"
N "github.com/sagernet/sing/common/network"
"github.com/sagernet/sing/common/rw"
)
const kFirstPaddings = 16
type paddingConn struct {
N.ExtendedConn
writer N.VectorisedWriter
readPadding int
writePadding int
readRemaining int
paddingRemaining int
}
func newPaddingConn(conn net.Conn) net.Conn {
writer, isVectorised := bufio.CreateVectorisedWriter(conn)
if isVectorised {
return &vectorisedPaddingConn{
paddingConn{
ExtendedConn: bufio.NewExtendedConn(conn),
writer: bufio.NewVectorisedWriter(conn),
},
writer,
}
} else {
return &paddingConn{
ExtendedConn: bufio.NewExtendedConn(conn),
writer: bufio.NewVectorisedWriter(conn),
}
}
}
func (c *paddingConn) Read(p []byte) (n int, err error) {
if c.readRemaining > 0 {
if len(p) > c.readRemaining {
p = p[:c.readRemaining]
}
n, err = c.ExtendedConn.Read(p)
if err != nil {
return
}
c.readRemaining -= n
return
}
if c.paddingRemaining > 0 {
err = rw.SkipN(c.ExtendedConn, c.paddingRemaining)
if err != nil {
return
}
c.paddingRemaining = 0
}
if c.readPadding < kFirstPaddings {
var paddingHdr []byte
if len(p) >= 4 {
paddingHdr = p[:4]
} else {
_paddingHdr := make([]byte, 4)
defer common.KeepAlive(_paddingHdr)
paddingHdr = common.Dup(_paddingHdr)
}
_, err = io.ReadFull(c.ExtendedConn, paddingHdr)
if err != nil {
return
}
originalDataSize := int(binary.BigEndian.Uint16(paddingHdr[:2]))
paddingLen := int(binary.BigEndian.Uint16(paddingHdr[2:]))
if len(p) > originalDataSize {
p = p[:originalDataSize]
}
n, err = c.ExtendedConn.Read(p)
if err != nil {
return
}
c.readPadding++
c.readRemaining = originalDataSize - n
c.paddingRemaining = paddingLen
return
}
return c.ExtendedConn.Read(p)
}
func (c *paddingConn) Write(p []byte) (n int, err error) {
for pLen := len(p); pLen > 0; {
var data []byte
if pLen > 65535 {
data = p[:65535]
p = p[65535:]
pLen -= 65535
} else {
data = p
pLen = 0
}
var writeN int
writeN, err = c.write(data)
n += writeN
if err != nil {
break
}
}
return n, err
}
func (c *paddingConn) write(p []byte) (n int, err error) {
if c.writePadding < kFirstPaddings {
paddingLen := 256 + rand.Intn(512)
_buffer := buf.StackNewSize(4 + len(p) + paddingLen)
defer common.KeepAlive(_buffer)
buffer := common.Dup(_buffer)
defer buffer.Release()
header := buffer.Extend(4)
binary.BigEndian.PutUint16(header[:2], uint16(len(p)))
binary.BigEndian.PutUint16(header[2:], uint16(paddingLen))
common.Must1(buffer.Write(p))
buffer.Extend(paddingLen)
_, err = c.ExtendedConn.Write(buffer.Bytes())
if err == nil {
n = len(p)
}
c.writePadding++
return
}
return c.ExtendedConn.Write(p)
}
func (c *paddingConn) ReadBuffer(buffer *buf.Buffer) error {
p := buffer.FreeBytes()
if c.readRemaining > 0 {
if len(p) > c.readRemaining {
p = p[:c.readRemaining]
}
n, err := c.ExtendedConn.Read(p)
if err != nil {
return err
}
c.readRemaining -= n
buffer.Truncate(n)
return nil
}
if c.paddingRemaining > 0 {
err := rw.SkipN(c.ExtendedConn, c.paddingRemaining)
if err != nil {
return err
}
c.paddingRemaining = 0
}
if c.readPadding < kFirstPaddings {
var paddingHdr []byte
if len(p) >= 4 {
paddingHdr = p[:4]
} else {
_paddingHdr := make([]byte, 4)
defer common.KeepAlive(_paddingHdr)
paddingHdr = common.Dup(_paddingHdr)
}
_, err := io.ReadFull(c.ExtendedConn, paddingHdr)
if err != nil {
return err
}
originalDataSize := int(binary.BigEndian.Uint16(paddingHdr[:2]))
paddingLen := int(binary.BigEndian.Uint16(paddingHdr[2:]))
if len(p) > originalDataSize {
p = p[:originalDataSize]
}
n, err := c.ExtendedConn.Read(p)
if err != nil {
return err
}
c.readPadding++
c.readRemaining = originalDataSize - n
c.paddingRemaining = paddingLen
buffer.Truncate(n)
return nil
}
return c.ExtendedConn.ReadBuffer(buffer)
}
func (c *paddingConn) WriteBuffer(buffer *buf.Buffer) error {
if c.writePadding < kFirstPaddings {
bufferLen := buffer.Len()
if bufferLen > 65535 {
return common.Error(c.Write(buffer.Bytes()))
}
paddingLen := 256 + rand.Intn(512)
header := buffer.ExtendHeader(4)
binary.BigEndian.PutUint16(header[:2], uint16(bufferLen))
binary.BigEndian.PutUint16(header[2:], uint16(paddingLen))
buffer.Extend(paddingLen)
c.writePadding++
}
return c.ExtendedConn.WriteBuffer(buffer)
}
func (c *paddingConn) FrontHeadroom() int {
return 4 + 256 + 1024
}
type vectorisedPaddingConn struct {
paddingConn
writer N.VectorisedWriter
}
func (c *vectorisedPaddingConn) WriteVectorised(buffers []*buf.Buffer) error {
if c.writePadding < kFirstPaddings {
bufferLen := buf.LenMulti(buffers)
if bufferLen > 65535 {
defer buf.ReleaseMulti(buffers)
for _, buffer := range buffers {
_, err := c.Write(buffer.Bytes())
if err != nil {
return err
}
}
return nil
}
paddingLen := 256 + rand.Intn(512)
header := buf.NewSize(4)
common.Must(
binary.Write(header, binary.BigEndian, uint16(bufferLen)),
binary.Write(header, binary.BigEndian, uint16(paddingLen)),
)
c.writePadding++
padding := buf.NewSize(paddingLen)
padding.Extend(paddingLen)
buffers = append(append([]*buf.Buffer{header}, buffers...), padding)
}
return c.writer.WriteVectorised(buffers)
}

View File

@@ -3,7 +3,6 @@ package mux
import (
"encoding/binary"
"io"
"math/rand"
"net"
C "github.com/sagernet/sing-box/constant"
@@ -26,7 +25,6 @@ var Destination = M.Socksaddr{
const (
ProtocolSMux Protocol = iota
ProtocolYAMux
ProtocolH2Mux
)
type Protocol byte
@@ -37,10 +35,8 @@ func ParseProtocol(name string) (Protocol, error) {
return ProtocolSMux, nil
case "yamux":
return ProtocolYAMux, nil
case "h2mux":
return ProtocolH2Mux, nil
default:
return ProtocolSMux, E.New("unknown multiplex protocol: ", name)
return ProtocolYAMux, E.New("unknown multiplex protocol: ", name)
}
}
@@ -53,13 +49,7 @@ func (p Protocol) newServer(conn net.Conn) (abstractSession, error) {
}
return &smuxSession{session}, nil
case ProtocolYAMux:
session, err := yamux.Server(conn, yaMuxConfig())
if err != nil {
return nil, err
}
return &yamuxSession{session}, nil
case ProtocolH2Mux:
return NewH2MuxServer(conn), nil
return yamux.Server(conn, yaMuxConfig())
default:
panic("unknown protocol")
}
@@ -74,13 +64,7 @@ func (p Protocol) newClient(conn net.Conn) (abstractSession, error) {
}
return &smuxSession{session}, nil
case ProtocolYAMux:
session, err := yamux.Client(conn, yaMuxConfig())
if err != nil {
return nil, err
}
return &yamuxSession{session}, nil
case ProtocolH2Mux:
return NewH2MuxClient(conn)
return yamux.Client(conn, yaMuxConfig())
default:
panic("unknown protocol")
}
@@ -106,22 +90,17 @@ func (p Protocol) String() string {
return "smux"
case ProtocolYAMux:
return "yamux"
case ProtocolH2Mux:
return "h2mux"
default:
return "unknown"
}
}
const (
Version0 = iota
Version1
version0 = 0
)
type Request struct {
Version byte
Protocol Protocol
PaddingEnabled bool
Protocol Protocol
}
func ReadRequest(reader io.Reader) (*Request, error) {
@@ -129,60 +108,22 @@ func ReadRequest(reader io.Reader) (*Request, error) {
if err != nil {
return nil, err
}
if version < Version0 || version > Version1 {
if version != version0 {
return nil, E.New("unsupported version: ", version)
}
protocol, err := rw.ReadByte(reader)
if err != nil {
return nil, err
}
var paddingEnabled bool
if version == Version1 {
err = binary.Read(reader, binary.BigEndian, &paddingEnabled)
if err != nil {
return nil, err
}
if paddingEnabled {
var paddingLen uint16
err = binary.Read(reader, binary.BigEndian, &paddingLen)
if err != nil {
return nil, err
}
err = rw.SkipN(reader, int(paddingLen))
if err != nil {
return nil, err
}
}
if protocol > byte(ProtocolYAMux) {
return nil, E.New("unsupported protocol: ", protocol)
}
return &Request{Version: version, Protocol: Protocol(protocol), PaddingEnabled: paddingEnabled}, nil
return &Request{Protocol: Protocol(protocol)}, nil
}
func EncodeRequest(request Request, payload []byte) *buf.Buffer {
var requestLen int
requestLen += 2
var paddingLen uint16
if request.Version == Version1 {
requestLen += 1
if request.PaddingEnabled {
requestLen += 2
paddingLen = uint16(256 + rand.Intn(512))
requestLen += int(paddingLen)
}
}
buffer := buf.NewSize(requestLen + len(payload))
common.Must(
buffer.WriteByte(request.Version),
buffer.WriteByte(byte(request.Protocol)),
)
if request.Version == Version1 {
common.Must(binary.Write(buffer, binary.BigEndian, request.PaddingEnabled))
if request.PaddingEnabled {
common.Must(binary.Write(buffer, binary.BigEndian, paddingLen))
buffer.Extend(int(paddingLen))
}
}
common.Must1(buffer.Write(payload))
return buffer
func EncodeRequest(buffer *buf.Buffer, request Request) {
buffer.WriteByte(version0)
buffer.WriteByte(byte(request.Protocol))
}
const (
@@ -219,7 +160,7 @@ func ReadStreamRequest(reader io.Reader) (*StreamRequest, error) {
return &StreamRequest{network, destination, udpAddr}, nil
}
func streamRequestLen(request StreamRequest) int {
func requestLen(request StreamRequest) int {
var rLen int
rLen += 1 // version
rLen += 2 // flags

View File

@@ -22,9 +22,6 @@ func NewConnection(ctx context.Context, router adapter.Router, errorHandler E.Ha
if err != nil {
return err
}
if request.PaddingEnabled {
conn = newPaddingConn(conn)
}
session, err := request.Protocol.newServer(conn)
if err != nil {
return err

View File

@@ -4,12 +4,11 @@ import (
"io"
"net"
"github.com/sagernet/sing/common"
"github.com/sagernet/sing/common/buf"
"github.com/sagernet/sing/common/bufio"
N "github.com/sagernet/sing/common/network"
"github.com/sagernet/smux"
"github.com/hashicorp/yamux"
)
type abstractSession interface {
@@ -18,7 +17,6 @@ type abstractSession interface {
NumStreams() int
Close() error
IsClosed() bool
CanTakeNewRequest() bool
}
var _ abstractSession = (*smuxSession)(nil)
@@ -35,49 +33,25 @@ func (s *smuxSession) Accept() (net.Conn, error) {
return s.AcceptStream()
}
func (s *smuxSession) CanTakeNewRequest() bool {
return true
}
type yamuxSession struct {
*yamux.Session
}
func (y *yamuxSession) CanTakeNewRequest() bool {
return true
}
type protocolConn struct {
net.Conn
request Request
protocol Protocol
protocolWritten bool
}
func newProtocolConn(conn net.Conn, request Request) net.Conn {
writer, isVectorised := bufio.CreateVectorisedWriter(conn)
if isVectorised {
return &vectorisedProtocolConn{
protocolConn{
Conn: conn,
request: request,
},
writer,
}
} else {
return &protocolConn{
Conn: conn,
request: request,
}
}
}
func (c *protocolConn) Write(p []byte) (n int, err error) {
if c.protocolWritten {
return c.Conn.Write(p)
}
buffer := EncodeRequest(c.request, p)
_buffer := buf.StackNewSize(2 + len(p))
defer common.KeepAlive(_buffer)
buffer := common.Dup(_buffer)
defer buffer.Release()
EncodeRequest(buffer, Request{
Protocol: c.protocol,
})
common.Must(common.Error(buffer.Write(p)))
n, err = c.Conn.Write(buffer.Bytes())
buffer.Release()
if err == nil {
n--
}
@@ -98,14 +72,20 @@ func (c *protocolConn) Upstream() any {
type vectorisedProtocolConn struct {
protocolConn
writer N.VectorisedWriter
N.VectorisedWriter
}
func (c *vectorisedProtocolConn) WriteVectorised(buffers []*buf.Buffer) error {
if c.protocolWritten {
return c.writer.WriteVectorised(buffers)
return c.VectorisedWriter.WriteVectorised(buffers)
}
c.protocolWritten = true
buffer := EncodeRequest(c.request, nil)
return c.writer.WriteVectorised(append([]*buf.Buffer{buffer}, buffers...))
_buffer := buf.StackNewSize(2)
defer common.KeepAlive(_buffer)
buffer := common.Dup(_buffer)
defer buffer.Release()
EncodeRequest(buffer, Request{
Protocol: c.protocol,
})
return c.VectorisedWriter.WriteVectorised(append([]*buf.Buffer{buffer}, buffers...))
}

View File

@@ -3,13 +3,40 @@ package constant
import (
"os"
"path/filepath"
"strings"
"github.com/sagernet/sing/common/rw"
)
const dirName = "sing-box"
var resourcePaths []string
var (
basePath string
tempPath string
resourcePaths []string
)
func BasePath(name string) string {
if basePath == "" || strings.HasPrefix(name, "/") {
return name
}
return filepath.Join(basePath, name)
}
func CreateTemp(pattern string) (*os.File, error) {
if tempPath == "" {
tempPath = os.TempDir()
}
return os.CreateTemp(tempPath, pattern)
}
func SetBasePath(path string) {
basePath = path
}
func SetTempPath(path string) {
tempPath = path
}
func FindPath(name string) (string, bool) {
name = os.ExpandEnv(name)

View File

@@ -10,7 +10,6 @@ import (
)
func applyDebugOptions(options option.DebugOptions) {
applyDebugListenOption(options)
if options.GCPercent != nil {
debug.SetGCPercent(*options.GCPercent)
}

View File

@@ -10,7 +10,6 @@ import (
)
func applyDebugOptions(options option.DebugOptions) {
applyDebugListenOption(options)
if options.GCPercent != nil {
debug.SetGCPercent(*options.GCPercent)
}

View File

@@ -1,67 +0,0 @@
package box
import (
"net/http"
"net/http/pprof"
"runtime"
"runtime/debug"
"github.com/sagernet/sing-box/common/badjson"
"github.com/sagernet/sing-box/common/json"
"github.com/sagernet/sing-box/log"
"github.com/sagernet/sing-box/option"
E "github.com/sagernet/sing/common/exceptions"
"github.com/dustin/go-humanize"
"github.com/go-chi/chi/v5"
)
var debugHTTPServer *http.Server
func applyDebugListenOption(options option.DebugOptions) {
if debugHTTPServer != nil {
debugHTTPServer.Close()
debugHTTPServer = nil
}
if options.Listen == "" {
return
}
r := chi.NewMux()
r.Route("/debug", func(r chi.Router) {
r.Get("/gc", func(writer http.ResponseWriter, request *http.Request) {
writer.WriteHeader(http.StatusNoContent)
go debug.FreeOSMemory()
})
r.Get("/memory", func(writer http.ResponseWriter, request *http.Request) {
var memStats runtime.MemStats
runtime.ReadMemStats(&memStats)
var memObject badjson.JSONObject
memObject.Put("heap", humanize.IBytes(memStats.HeapInuse))
memObject.Put("stack", humanize.IBytes(memStats.StackInuse))
memObject.Put("idle", humanize.IBytes(memStats.HeapIdle-memStats.HeapReleased))
memObject.Put("goroutines", runtime.NumGoroutine())
memObject.Put("rss", rusageMaxRSS())
encoder := json.NewEncoder(writer)
encoder.SetIndent("", " ")
encoder.Encode(memObject)
})
r.HandleFunc("/pprof", pprof.Index)
r.HandleFunc("/pprof/*", pprof.Index)
r.HandleFunc("/pprof/cmdline", pprof.Cmdline)
r.HandleFunc("/pprof/profile", pprof.Profile)
r.HandleFunc("/pprof/symbol", pprof.Symbol)
r.HandleFunc("/pprof/trace", pprof.Trace)
})
debugHTTPServer = &http.Server{
Addr: options.Listen,
Handler: r,
}
go func() {
err := debugHTTPServer.ListenAndServe()
if err != nil && !E.IsClosed(err) {
log.Error(E.Cause(err, "serve debug HTTP server"))
}
}()
}

View File

@@ -1,16 +1,3 @@
#### 1.3-beta9
* Improve multiplex **1**
* Fixes and improvements
*1*:
Added new `h2mux` multiplex protocol and `padding` multiplex option, see [Multiplex](/configuration/shared/multiplex).
#### 1.2.6
* Fix bugs and update dependencies
#### 1.3-beta8
* Fix `system` tun stack for ios
@@ -20,7 +7,7 @@ Added new `h2mux` multiplex protocol and `padding` multiplex option, see [Multip
*1:
This is an incompatible update for XUDP in VLESS if vision flow is enabled.
As in Xray, this is an incompatible update for XUDP in VLESS if vision flow is enabled.
#### 1.3-beta7

View File

@@ -10,8 +10,7 @@
"protocol": "smux",
"max_connections": 4,
"min_streams": 4,
"max_streams": 0,
"padding": false
"max_streams": 0
}
```
@@ -29,7 +28,6 @@ Multiplex protocol.
|----------|------------------------------------|
| smux | https://github.com/xtaci/smux |
| yamux | https://github.com/hashicorp/yamux |
| h2mux | https://golang.org/x/net/http2 |
SMux is used by default.
@@ -50,12 +48,3 @@ Conflict with `max_streams`.
Maximum multiplexed streams in a connection before opening a new connection.
Conflict with `max_connections` and `min_streams`.
#### padding
!!! info
Requires sing-box server version 1.3-beta9 or later.
Enable padding.

View File

@@ -28,7 +28,6 @@
|-------|------------------------------------|
| smux | https://github.com/xtaci/smux |
| yamux | https://github.com/hashicorp/yamux |
| h2mux | https://golang.org/x/net/http2 |
默认使用 SMux。
@@ -48,13 +47,4 @@
在打开新连接之前,连接中的最大多路复用流数量。
`max_connections``min_streams` 冲突。
#### padding
!!! info
需要 sing-box 服务器版本 1.3-beta9 或更高。
启用填充。
`max_connections``min_streams` 冲突。

View File

@@ -1,7 +1,6 @@
package experimental
import (
"context"
"os"
"github.com/sagernet/sing-box/adapter"
@@ -9,7 +8,7 @@ import (
"github.com/sagernet/sing-box/option"
)
type ClashServerConstructor = func(ctx context.Context, router adapter.Router, logFactory log.ObservableFactory, options option.ClashAPIOptions) (adapter.ClashServer, error)
type ClashServerConstructor = func(router adapter.Router, logFactory log.ObservableFactory, options option.ClashAPIOptions) (adapter.ClashServer, error)
var clashServerConstructor ClashServerConstructor
@@ -17,9 +16,9 @@ func RegisterClashServerConstructor(constructor ClashServerConstructor) {
clashServerConstructor = constructor
}
func NewClashServer(ctx context.Context, router adapter.Router, logFactory log.ObservableFactory, options option.ClashAPIOptions) (adapter.ClashServer, error) {
func NewClashServer(router adapter.Router, logFactory log.ObservableFactory, options option.ClashAPIOptions) (adapter.ClashServer, error) {
if clashServerConstructor == nil {
return nil, os.ErrInvalid
}
return clashServerConstructor(ctx, router, logFactory, options)
return clashServerConstructor(router, logFactory, options)
}

View File

@@ -23,7 +23,6 @@ import (
E "github.com/sagernet/sing/common/exceptions"
F "github.com/sagernet/sing/common/format"
N "github.com/sagernet/sing/common/network"
"github.com/sagernet/sing/service/filemanager"
"github.com/sagernet/websocket"
"github.com/go-chi/chi/v5"
@@ -38,7 +37,6 @@ func init() {
var _ adapter.ClashServer = (*Server)(nil)
type Server struct {
ctx context.Context
router adapter.Router
logger log.Logger
httpServer *http.Server
@@ -55,11 +53,10 @@ type Server struct {
externalUIDownloadDetour string
}
func NewServer(ctx context.Context, router adapter.Router, logFactory log.ObservableFactory, options option.ClashAPIOptions) (adapter.ClashServer, error) {
func NewServer(router adapter.Router, logFactory log.ObservableFactory, options option.ClashAPIOptions) (adapter.ClashServer, error) {
trafficManager := trafficontrol.NewManager()
chiRouter := chi.NewRouter()
server := &Server{
ctx: ctx,
router: router,
logger: logFactory.NewLogger("clash-api"),
httpServer: &http.Server{
@@ -85,7 +82,7 @@ func NewServer(ctx context.Context, router adapter.Router, logFactory log.Observ
if foundPath, loaded := C.FindPath(cachePath); loaded {
cachePath = foundPath
} else {
cachePath = filemanager.BasePath(ctx, cachePath)
cachePath = C.BasePath(cachePath)
}
server.cacheFilePath = cachePath
}
@@ -116,7 +113,7 @@ func NewServer(ctx context.Context, router adapter.Router, logFactory log.Observ
server.setupMetaAPI(r)
})
if options.ExternalUI != "" {
server.externalUI = filemanager.BasePath(ctx, os.ExpandEnv(options.ExternalUI))
server.externalUI = C.BasePath(os.ExpandEnv(options.ExternalUI))
chiRouter.Group(func(r chi.Router) {
fs := http.StripPrefix("/ui", http.FileServer(http.Dir(server.externalUI)))
r.Get("/ui", http.RedirectHandler("/ui/", http.StatusTemporaryRedirect).ServeHTTP)

View File

@@ -12,11 +12,11 @@ import (
"time"
"github.com/sagernet/sing-box/adapter"
C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing/common"
E "github.com/sagernet/sing/common/exceptions"
M "github.com/sagernet/sing/common/metadata"
N "github.com/sagernet/sing/common/network"
"github.com/sagernet/sing/service/filemanager"
)
func (s *Server) checkAndDownloadExternalUI() {
@@ -79,7 +79,7 @@ func (s *Server) downloadExternalUI() error {
}
func (s *Server) downloadZIP(name string, body io.Reader, output string) error {
tempFile, err := filemanager.CreateTemp(s.ctx, name)
tempFile, err := C.CreateTemp(name)
if err != nil {
return err
}
@@ -112,7 +112,7 @@ func (s *Server) downloadZIP(name string, body io.Reader, output string) error {
return err
}
savePath := filepath.Join(saveDirectory, pathElements[len(pathElements)-1])
err = downloadZIPEntry(s.ctx, file, savePath)
err = downloadZIPEntry(file, savePath)
if err != nil {
return err
}
@@ -120,8 +120,8 @@ func (s *Server) downloadZIP(name string, body io.Reader, output string) error {
return nil
}
func downloadZIPEntry(ctx context.Context, zipFile *zip.File, savePath string) error {
saveFile, err := filemanager.Create(ctx, savePath)
func downloadZIPEntry(zipFile *zip.File, savePath string) error {
saveFile, err := os.Create(savePath)
if err != nil {
return err
}

View File

@@ -27,27 +27,3 @@ func RedirectStderr(path string) error {
stderrFile = outputFile
return nil
}
func RedirectStderrAsUser(path string, uid, gid int) error {
if stats, err := os.Stat(path); err == nil && stats.Size() > 0 {
_ = os.Rename(path, path+".old")
}
outputFile, err := os.Create(path)
if err != nil {
return err
}
err = outputFile.Chown(uid, gid)
if err != nil {
outputFile.Close()
os.Remove(outputFile.Name())
return err
}
err = unix.Dup2(int(outputFile.Fd()), int(os.Stderr.Fd()))
if err != nil {
outputFile.Close()
os.Remove(outputFile.Name())
return err
}
stderrFile = outputFile
return nil
}

View File

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

View File

@@ -15,7 +15,6 @@ 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

@@ -16,7 +16,6 @@ import (
"github.com/sagernet/sing/common/control"
E "github.com/sagernet/sing/common/exceptions"
N "github.com/sagernet/sing/common/network"
"github.com/sagernet/sing/service/filemanager"
)
type BoxService struct {
@@ -31,7 +30,6 @@ func NewService(configContent string, platformInterface PlatformInterface) (*Box
return nil, err
}
ctx, cancel := context.WithCancel(context.Background())
ctx = filemanager.WithDefault(ctx, sBasePath, sTempPath, sUserID, sGroupID)
instance, err := box.New(box.Options{
Context: ctx,
Options: options,
@@ -70,10 +68,6 @@ 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 {

View File

@@ -1,31 +1,17 @@
package libbox
import (
"os"
C "github.com/sagernet/sing-box/constant"
"github.com/dustin/go-humanize"
)
var (
sBasePath string
sTempPath string
sUserID int
sGroupID int
)
func SetBasePath(path string) {
C.SetBasePath(path)
}
func Setup(basePath string, tempPath string, userID int, groupID int) {
sBasePath = basePath
sTempPath = tempPath
sUserID = userID
sGroupID = groupID
if sUserID == -1 {
sUserID = os.Getuid()
}
if sGroupID == -1 {
sGroupID = os.Getgid()
}
func SetTempPath(path string) {
C.SetTempPath(path)
}
func Version() string {

14
go.mod
View File

@@ -25,17 +25,17 @@ 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
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 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-shadowtls v0.1.2-0.20230417103049-4f682e05f19b
github.com/sagernet/sing-tun v0.1.5-0.20230422121432-209ec123ca7b
github.com/sagernet/sing-tun v0.1.4-0.20230419061614-d744d03d9302
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
github.com/sagernet/utls v0.0.0-20230309024959-6732c2ab36f2
github.com/sagernet/websocket v0.0.0-20220913015213-615516348b4e
github.com/sagernet/wireguard-go v0.0.0-20230420044414-a7bac1754e77
github.com/sagernet/wireguard-go v0.0.0-20221116151939-c99467f53f2c
github.com/spf13/cobra v1.7.0
github.com/stretchr/testify v1.8.2
go.etcd.io/bbolt v1.3.7
@@ -48,7 +48,7 @@ require (
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230215201556-9c5414ab4bde
google.golang.org/grpc v1.54.0
google.golang.org/protobuf v1.30.0
gvisor.dev/gvisor v0.0.0-20230415003630-3981d5d5e523
gvisor.dev/gvisor v0.0.0-20220901235040-6ca97ef2ce1c
)
//replace github.com/sagernet/sing => ../sing
@@ -85,7 +85,7 @@ require (
go.uber.org/multierr v1.6.0 // indirect
golang.org/x/mod v0.8.0 // indirect
golang.org/x/text v0.9.0 // indirect
golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 // indirect
golang.org/x/time v0.0.0-20191024005414-555d28b269f0 // indirect
golang.org/x/tools v0.6.0 // indirect
google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f // indirect
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect

28
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 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 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-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.5-0.20230422121432-209ec123ca7b h1:9NsciSJGwzdkXwVvT2c2g+RvkTVkANeBLr2l+soJ7LM=
github.com/sagernet/sing-tun v0.1.5-0.20230422121432-209ec123ca7b/go.mod h1:DD7Ce2Gt0GFc6I/1+Uw4D/aUlBsGqrQsC52CMK/V818=
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-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=
@@ -131,8 +131,8 @@ github.com/sagernet/utls v0.0.0-20230309024959-6732c2ab36f2 h1:kDUqhc9Vsk5HJuhfI
github.com/sagernet/utls v0.0.0-20230309024959-6732c2ab36f2/go.mod h1:JKQMZq/O2qnZjdrt+B57olmfgEmLtY9iiSIEYtWvoSM=
github.com/sagernet/websocket v0.0.0-20220913015213-615516348b4e h1:7uw2njHFGE+VpWamge6o56j2RWk4omF6uLKKxMmcWvs=
github.com/sagernet/websocket v0.0.0-20220913015213-615516348b4e/go.mod h1:45TUl8+gH4SIKr4ykREbxKWTxkDlSzFENzctB1dVRRY=
github.com/sagernet/wireguard-go v0.0.0-20230420044414-a7bac1754e77 h1:g6QtRWQ2dKX7EQP++1JLNtw4C2TNxd4/ov8YUpOPOSo=
github.com/sagernet/wireguard-go v0.0.0-20230420044414-a7bac1754e77/go.mod h1:pJDdXzZIwJ+2vmnT0TKzmf8meeum+e2mTDSehw79eE0=
github.com/sagernet/wireguard-go v0.0.0-20221116151939-c99467f53f2c h1:vK2wyt9aWYHHvNLWniwijBu/n4pySypiKRhN32u/JGo=
github.com/sagernet/wireguard-go v0.0.0-20221116151939-c99467f53f2c/go.mod h1:euOmN6O5kk9dQmgSS8Df4psAl3TCjxOz0NW60EWkSaI=
github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I=
github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
@@ -208,8 +208,8 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 h1:vVKdlvoWBphwdxWKrFZEuM0kGgGLxUOYcY4U/2Vjg44=
golang.org/x/time v0.0.0-20220210224613-90d013bbcef8/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0 h1:/5xXl8Y5W96D+TtHSlonuFqGHIWVuyCkGJLwGh9JJFs=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
@@ -236,7 +236,7 @@ gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gvisor.dev/gvisor v0.0.0-20230415003630-3981d5d5e523 h1:zUQYeyyPLnSR6yMvLSOmLH37xDWCZ7BqlpE69fE5K3Q=
gvisor.dev/gvisor v0.0.0-20230415003630-3981d5d5e523/go.mod h1:pzr6sy8gDLfVmDAg8OYrlKvGEHw5C3PGTiBXBTCx76Q=
gvisor.dev/gvisor v0.0.0-20220901235040-6ca97ef2ce1c h1:m5lcgWnL3OElQNVyp3qcncItJ2c0sQlSGjYK2+nJTA4=
gvisor.dev/gvisor v0.0.0-20220901235040-6ca97ef2ce1c/go.mod h1:TIvkJD0sxe8pIob3p6T8IzxXunlp6yfgktvTNp+DGNM=
lukechampine.com/blake3 v1.1.7 h1:GgRMhmdsuK8+ii6UZFDL8Nb+VyMwadAgcJyfYHxG6n0=
lukechampine.com/blake3 v1.1.7/go.mod h1:tkKEOtDkNtklkXtLNEOGNq5tcV90tJiA1vAA12R78LA=

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](udpTimeout, adapter.NewUpstreamContextHandler(inbound.newConnection, inbound.newPacketConnection, inbound))
inbound.udpNat = udpnat.New[netip.AddrPort](ctx, udpTimeout, adapter.NewUpstreamContextHandler(inbound.newConnection, inbound.newPacketConnection, inbound))
inbound.connHandler = inbound
inbound.packetHandler = inbound
inbound.packetUpstream = inbound.udpNat

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(options.UDPTimeout, inbound.upstreamContextHandler())
inbound.service = shadowsocks.NewNoneService(ctx, options.UDPTimeout, inbound.upstreamContextHandler())
case common.Contains(shadowaead.List, options.Method):
inbound.service, err = shadowaead.NewService(options.Method, nil, options.Password, udpTimeout, inbound.upstreamContextHandler())
inbound.service, err = shadowaead.NewService(ctx, options.Method, nil, options.Password, udpTimeout, inbound.upstreamContextHandler())
case common.Contains(shadowaead_2022.List, options.Method):
inbound.service, err = shadowaead_2022.NewServiceWithPassword(options.Method, options.Password, udpTimeout, inbound.upstreamContextHandler(), router.TimeFunc())
inbound.service, err = shadowaead_2022.NewServiceWithPassword(ctx, options.Method, options.Password, udpTimeout, inbound.upstreamContextHandler(), router.TimeFunc())
default:
err = E.New("unsupported method: ", options.Method)
}

View File

@@ -57,6 +57,7 @@ func newShadowsocksMulti(ctx context.Context, router adapter.Router, logger log.
)
if common.Contains(shadowaead_2022.List, options.Method) {
service, err = shadowaead_2022.NewMultiServiceWithPassword[int](
ctx,
options.Method,
options.Password,
udpTimeout,
@@ -65,6 +66,7 @@ func newShadowsocksMulti(ctx context.Context, router adapter.Router, logger log.
)
} else if common.Contains(shadowaead.List, options.Method) {
service, err = shadowaead.NewMultiService[int](
ctx,
options.Method,
udpTimeout,
adapter.NewUpstreamContextHandler(inbound.newConnection, inbound.newPacketConnection, inbound))

View File

@@ -50,6 +50,7 @@ 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](udpTimeout, tproxy.upstreamContextHandler())
tproxy.udpNat = udpnat.New[netip.AddrPort](ctx, udpTimeout, tproxy.upstreamContextHandler())
tproxy.packetUpstream = tproxy.udpNat
return tproxy
}

View File

@@ -177,8 +177,7 @@ func (t *Tun) Start() error {
Router: tunRouter,
Handler: t,
Logger: t.logger,
ForwarderBindInterface: t.platformInterface != nil,
InterfaceFinder: t.router.InterfaceFinder(),
UnderPlatform: t.platformInterface != nil,
})
if err != nil {
return err

View File

@@ -3,8 +3,6 @@
package include
import (
"context"
"github.com/sagernet/sing-box/adapter"
"github.com/sagernet/sing-box/experimental"
"github.com/sagernet/sing-box/log"
@@ -13,7 +11,7 @@ import (
)
func init() {
experimental.RegisterClashServerConstructor(func(ctx context.Context, router adapter.Router, logFactory log.ObservableFactory, options option.ClashAPIOptions) (adapter.ClashServer, error) {
experimental.RegisterClashServerConstructor(func(router adapter.Router, logFactory log.ObservableFactory, options option.ClashAPIOptions) (adapter.ClashServer, error) {
return nil, E.New(`clash api is not included in this build, rebuild with -tags with_clash_api`)
})
}

View File

@@ -1,15 +1,14 @@
package log
import (
"context"
"io"
"os"
"time"
C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/option"
"github.com/sagernet/sing/common"
E "github.com/sagernet/sing/common/exceptions"
"github.com/sagernet/sing/service/filemanager"
)
type factoryWithFile struct {
@@ -37,7 +36,6 @@ func (f *observableFactoryWithFile) Close() error {
}
type Options struct {
Context context.Context
Options option.LogOptions
Observable bool
DefaultWriter io.Writer
@@ -67,7 +65,7 @@ func New(options Options) (Factory, error) {
logWriter = os.Stdout
default:
var err error
logFile, err = filemanager.OpenFile(options.Context, logOptions.Output, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0o644)
logFile, err = os.OpenFile(C.BasePath(logOptions.Output), os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0o644)
if err != nil {
return nil, err
}

View File

@@ -7,7 +7,6 @@ import (
)
type DebugOptions struct {
Listen string `json:"listen,omitempty"`
GCPercent *int `json:"gc_percent,omitempty"`
MaxStack *int `json:"max_stack,omitempty"`
MaxThreads *int `json:"max_threads,omitempty"`

View File

@@ -150,5 +150,4 @@ type MultiplexOptions struct {
MaxConnections int `json:"max_connections,omitempty"`
MinStreams int `json:"min_streams,omitempty"`
MaxStreams int `json:"max_streams,omitempty"`
Padding bool `json:"padding,omitempty"`
}

View File

@@ -30,7 +30,7 @@ type Shadowsocks struct {
serverAddr M.Socksaddr
plugin sip003.Plugin
uotClient *uot.Client
multiplexDialer *mux.Client
multiplexDialer N.Dialer
}
func NewShadowsocks(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.ShadowsocksOutboundOptions) (*Shadowsocks, error) {
@@ -127,15 +127,8 @@ func (h *Shadowsocks) NewPacketConnection(ctx context.Context, conn N.PacketConn
return NewPacketConnection(ctx, h, conn, metadata)
}
func (h *Shadowsocks) InterfaceUpdated() error {
if h.multiplexDialer != nil {
h.multiplexDialer.Reset()
}
return nil
}
func (h *Shadowsocks) Close() error {
return common.Close(common.PtrOrNil(h.multiplexDialer))
return common.Close(h.multiplexDialer)
}
var _ N.Dialer = (*shadowsocksDialer)(nil)

View File

@@ -27,7 +27,7 @@ type Trojan struct {
dialer N.Dialer
serverAddr M.Socksaddr
key [56]byte
multiplexDialer *mux.Client
multiplexDialer N.Dialer
tlsConfig tls.Config
transport adapter.V2RayClientTransport
}
@@ -103,15 +103,8 @@ func (h *Trojan) NewPacketConnection(ctx context.Context, conn N.PacketConn, met
return NewPacketConnection(ctx, h, conn, metadata)
}
func (h *Trojan) InterfaceUpdated() error {
if h.multiplexDialer != nil {
h.multiplexDialer.Reset()
}
return nil
}
func (h *Trojan) Close() error {
return common.Close(common.PtrOrNil(h.multiplexDialer), h.transport)
return common.Close(h.multiplexDialer, h.transport)
}
type trojanDialer Trojan

View File

@@ -27,7 +27,7 @@ type VMess struct {
dialer N.Dialer
client *vmess.Client
serverAddr M.Socksaddr
multiplexDialer *mux.Client
multiplexDialer N.Dialer
tlsConfig tls.Config
transport adapter.V2RayClientTransport
packetAddr bool
@@ -97,15 +97,8 @@ func NewVMess(ctx context.Context, router adapter.Router, logger log.ContextLogg
return outbound, nil
}
func (h *VMess) InterfaceUpdated() error {
if h.multiplexDialer != nil {
h.multiplexDialer.Reset()
}
return nil
}
func (h *VMess) Close() error {
return common.Close(common.PtrOrNil(h.multiplexDialer), h.transport)
return common.Close(h.multiplexDialer, h.transport)
}
func (h *VMess) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {

View File

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

View File

@@ -18,7 +18,6 @@ import (
E "github.com/sagernet/sing/common/exceptions"
M "github.com/sagernet/sing/common/metadata"
"github.com/sagernet/sing/common/rw"
"github.com/sagernet/sing/service/filemanager"
)
func (r *Router) GeoIPReader() *geoip.Reader {
@@ -52,7 +51,7 @@ func (r *Router) prepareGeoIPDatabase() error {
geoPath = foundPath
}
}
geoPath = filemanager.BasePath(r.ctx, geoPath)
geoPath = C.BasePath(geoPath)
if rw.FileExists(geoPath) {
geoReader, codes, err := geoip.Open(geoPath)
if err == nil {
@@ -96,7 +95,7 @@ func (r *Router) prepareGeositeDatabase() error {
geoPath = foundPath
}
}
geoPath = filemanager.BasePath(r.ctx, geoPath)
geoPath = C.BasePath(geoPath)
if !rw.FileExists(geoPath) {
r.logger.Warn("geosite database not exists: ", geoPath)
var err error
@@ -143,10 +142,10 @@ func (r *Router) downloadGeoIPDatabase(savePath string) error {
}
if parentDir := filepath.Dir(savePath); parentDir != "" {
filemanager.MkdirAll(r.ctx, parentDir, 0o755)
os.MkdirAll(parentDir, 0o755)
}
saveFile, err := filemanager.Create(r.ctx, savePath)
saveFile, err := os.OpenFile(savePath, os.O_CREATE|os.O_WRONLY, 0o644)
if err != nil {
return E.Cause(err, "open output file: ", downloadURL)
}
@@ -191,10 +190,10 @@ func (r *Router) downloadGeositeDatabase(savePath string) error {
}
if parentDir := filepath.Dir(savePath); parentDir != "" {
filemanager.MkdirAll(r.ctx, parentDir, 0o755)
os.MkdirAll(parentDir, 0o755)
}
saveFile, err := filemanager.Create(r.ctx, savePath)
saveFile, err := os.OpenFile(savePath, os.O_CREATE|os.O_WRONLY, 0o644)
if err != nil {
return E.Cause(err, "open output file: ", downloadURL)
}

View File

@@ -9,9 +9,9 @@ replace github.com/sagernet/sing-box => ../
require (
github.com/docker/docker v20.10.18+incompatible
github.com/docker/go-connections v0.4.0
github.com/gofrs/uuid/v5 v5.0.0
github.com/sagernet/sing v0.2.4
github.com/sagernet/sing-shadowsocks v0.2.2-0.20230417102954-f77257340507
github.com/gofrs/uuid v4.4.0+incompatible
github.com/sagernet/sing v0.2.4-0.20230418025125-f196b4303e31
github.com/sagernet/sing-shadowsocks v0.2.2-0.20230418025154-6114beeeba6d
github.com/spyzhov/ajson v0.7.1
github.com/stretchr/testify v1.8.2
go.uber.org/goleak v1.2.0
@@ -21,7 +21,7 @@ require (
require (
berty.tech/go-libtor v1.0.385 // indirect
github.com/Dreamacro/clash v1.15.0 // indirect
github.com/Microsoft/go-winio v0.6.0 // indirect
github.com/Microsoft/go-winio v0.5.1 // indirect
github.com/ajg/form v1.5.1 // indirect
github.com/andybalholm/brotli v1.0.5 // indirect
github.com/caddyserver/certmagic v0.17.2 // indirect
@@ -36,6 +36,7 @@ require (
github.com/go-chi/cors v1.2.1 // indirect
github.com/go-chi/render v1.0.2 // indirect
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect
github.com/gofrs/uuid/v5 v5.0.0 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/mock v1.6.0 // indirect
github.com/golang/protobuf v1.5.2 // indirect
@@ -50,7 +51,7 @@ require (
github.com/logrusorgru/aurora v2.0.3+incompatible // indirect
github.com/mholt/acmez v1.1.0 // indirect
github.com/miekg/dns v1.1.53 // indirect
github.com/moby/term v0.0.0-20221205130635-1aeaba878587 // indirect
github.com/moby/term v0.0.0-20221105221325-4eb28fa6025c // indirect
github.com/morikuni/aec v1.0.0 // indirect
github.com/onsi/ginkgo/v2 v2.2.0 // indirect
github.com/ooni/go-libtor v1.1.7 // indirect
@@ -70,15 +71,15 @@ require (
github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 // indirect
github.com/sagernet/quic-go v0.0.0-20230202071646-a8c8afb18b32 // indirect
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 // indirect
github.com/sagernet/sing-dns v0.1.5-0.20230415085626-111ecf799dfc // indirect
github.com/sagernet/sing-shadowtls v0.1.2-0.20230417103049-4f682e05f19b // indirect
github.com/sagernet/sing-tun v0.1.5-0.20230422121432-209ec123ca7b // indirect
github.com/sagernet/sing-vmess v0.1.5-0.20230417103030-8c3070ae3fb3 // indirect
github.com/sagernet/sing-dns v0.1.5-0.20230418025317-8a132998b322 // indirect
github.com/sagernet/sing-shadowtls v0.1.0 // indirect
github.com/sagernet/sing-tun v0.1.4-0.20230419061614-d744d03d9302 // indirect
github.com/sagernet/sing-vmess v0.1.3 // indirect
github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37 // indirect
github.com/sagernet/tfo-go v0.0.0-20230303015439-ffcfd8c41cf9 // indirect
github.com/sagernet/utls v0.0.0-20230309024959-6732c2ab36f2 // indirect
github.com/sagernet/websocket v0.0.0-20220913015213-615516348b4e // indirect
github.com/sagernet/wireguard-go v0.0.0-20230420044414-a7bac1754e77 // indirect
github.com/sagernet/wireguard-go v0.0.0-20221116151939-c99467f53f2c // indirect
github.com/sirupsen/logrus v1.9.0 // indirect
github.com/u-root/uio v0.0.0-20230220225925-ffce2a382923 // indirect
github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 // indirect
@@ -92,12 +93,15 @@ require (
golang.org/x/mod v0.8.0 // indirect
golang.org/x/sys v0.7.0 // indirect
golang.org/x/text v0.9.0 // indirect
golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 // indirect
golang.org/x/time v0.0.0-20191024005414-555d28b269f0 // indirect
golang.org/x/tools v0.6.0 // indirect
google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f // indirect
google.golang.org/grpc v1.54.0 // indirect
google.golang.org/protobuf v1.30.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
gvisor.dev/gvisor v0.0.0-20230415003630-3981d5d5e523 // indirect
gotest.tools/v3 v3.4.0 // indirect
gvisor.dev/gvisor v0.0.0-20220901235040-6ca97ef2ce1c // indirect
lukechampine.com/blake3 v1.1.7 // indirect
)
//replace github.com/sagernet/sing => ../../sing

View File

@@ -3,8 +3,8 @@ berty.tech/go-libtor v1.0.385/go.mod h1:9swOOQVb+kmvuAlsgWUK/4c52pm69AdbJsxLzk+f
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8=
github.com/Dreamacro/clash v1.15.0 h1:mlpD950VEggXZBNahV66hyKDRxcczkj3vymoAt78KyE=
github.com/Dreamacro/clash v1.15.0/go.mod h1:WNH69bN11LiAdgdSr4hpkEuXVMfBbWyhEKMCTx9BtNE=
github.com/Microsoft/go-winio v0.6.0 h1:slsWYD/zyx7lCXoZVlvQrj0hPTM1HI4+v1sIda2yDvg=
github.com/Microsoft/go-winio v0.6.0/go.mod h1:cTAf44im0RAYeL23bpB+fzCyDH2MJiz2BO69KH/soAE=
github.com/Microsoft/go-winio v0.5.1 h1:aPJp2QD7OOrhO5tQXqQoGSJc+DjDtWTGLOmNyAm6FgY=
github.com/Microsoft/go-winio v0.5.1/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84=
github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU=
github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY=
github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs=
@@ -43,6 +43,8 @@ github.com/go-chi/render v1.0.2 h1:4ER/udB0+fMWB2Jlf15RV3F4A2FDuYi/9f+lFttR/Lg=
github.com/go-chi/render v1.0.2/go.mod h1:/gr3hVkmYR0YlEy3LxCuVRFzEu9Ruok+gFqbIofjao0=
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I=
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
github.com/gofrs/uuid v4.4.0+incompatible h1:3qXRTX8/NbyulANqlc0lchS1gqAVxRgsuW1YrTJupqA=
github.com/gofrs/uuid v4.4.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
github.com/gofrs/uuid/v5 v5.0.0 h1:p544++a97kEL+svbcFbCQVM9KFu0Yo25UoISXGNNH9M=
github.com/gofrs/uuid/v5 v5.0.0/go.mod h1:CDOjlDMVAtN56jqyRUZh58JT31Tiw7/oQyEXZV+9bD8=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
@@ -82,8 +84,8 @@ github.com/mholt/acmez v1.1.0 h1:IQ9CGHKOHokorxnffsqDvmmE30mDenO1lptYZ1AYkHY=
github.com/mholt/acmez v1.1.0/go.mod h1:zwo5+fbLLTowAX8o8ETfQzbDtwGEXnPhkmGdKIP+bgs=
github.com/miekg/dns v1.1.53 h1:ZBkuHr5dxHtB1caEOlZTLPo7D3L3TWckgUUs/RHfDxw=
github.com/miekg/dns v1.1.53/go.mod h1:uInx36IzPl7FYnDcMeVWxj9byh7DutNykX4G9Sj60FY=
github.com/moby/term v0.0.0-20221205130635-1aeaba878587 h1:HfkjXDfhgVaN5rmueG8cL8KKeFNecRCXFhaJ2qZ5SKA=
github.com/moby/term v0.0.0-20221205130635-1aeaba878587/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y=
github.com/moby/term v0.0.0-20221105221325-4eb28fa6025c h1:RC8WMpjonrBfyAh6VN/POIPtYD5tRAq0qMqCRjQNK+g=
github.com/moby/term v0.0.0-20221105221325-4eb28fa6025c/go.mod h1:9OcmHNQQUTbk4XCffrLgN1NEKc2mh5u++biHVrvHsSU=
github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
@@ -126,18 +128,18 @@ 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 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.5-0.20230422121432-209ec123ca7b h1:9NsciSJGwzdkXwVvT2c2g+RvkTVkANeBLr2l+soJ7LM=
github.com/sagernet/sing-tun v0.1.5-0.20230422121432-209ec123ca7b/go.mod h1:DD7Ce2Gt0GFc6I/1+Uw4D/aUlBsGqrQsC52CMK/V818=
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/sing v0.2.4-0.20230418025125-f196b4303e31 h1:qgq8jeY/rbnY9NwYXByO//AP0ByIxnsKUxQx1tOB3W0=
github.com/sagernet/sing v0.2.4-0.20230418025125-f196b4303e31/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-shadowtls v0.1.0 h1:05MYce8aR5xfKIn+y7xRFsdKhKt44QZTSEQW+lG5IWQ=
github.com/sagernet/sing-shadowtls v0.1.0/go.mod h1:Kn1VUIprdkwCgkS6SXYaLmIpKzQbqBIKJBMY+RvBhYc=
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-vmess v0.1.3 h1:q/+tsF46dvvapL6CpQBgPHJ6nQrDUZqEtLHCbsjO7iM=
github.com/sagernet/sing-vmess v0.1.3/go.mod h1:GVXqAHwe9U21uS+Voh4YBIrADQyE4F9v0ayGSixSQAE=
github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37 h1:HuE6xSwco/Xed8ajZ+coeYLmioq0Qp1/Z2zczFaV8as=
github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37/go.mod h1:3skNSftZDJWTGVtVaM2jfbce8qHnmH/AGDRe62iNOg0=
github.com/sagernet/tfo-go v0.0.0-20230303015439-ffcfd8c41cf9 h1:2ItpW1nMNkPzmBTxV0/eClCklHrFSQMnUGcpUmJxVeE=
@@ -146,8 +148,9 @@ github.com/sagernet/utls v0.0.0-20230309024959-6732c2ab36f2 h1:kDUqhc9Vsk5HJuhfI
github.com/sagernet/utls v0.0.0-20230309024959-6732c2ab36f2/go.mod h1:JKQMZq/O2qnZjdrt+B57olmfgEmLtY9iiSIEYtWvoSM=
github.com/sagernet/websocket v0.0.0-20220913015213-615516348b4e h1:7uw2njHFGE+VpWamge6o56j2RWk4omF6uLKKxMmcWvs=
github.com/sagernet/websocket v0.0.0-20220913015213-615516348b4e/go.mod h1:45TUl8+gH4SIKr4ykREbxKWTxkDlSzFENzctB1dVRRY=
github.com/sagernet/wireguard-go v0.0.0-20230420044414-a7bac1754e77 h1:g6QtRWQ2dKX7EQP++1JLNtw4C2TNxd4/ov8YUpOPOSo=
github.com/sagernet/wireguard-go v0.0.0-20230420044414-a7bac1754e77/go.mod h1:pJDdXzZIwJ+2vmnT0TKzmf8meeum+e2mTDSehw79eE0=
github.com/sagernet/wireguard-go v0.0.0-20221116151939-c99467f53f2c h1:vK2wyt9aWYHHvNLWniwijBu/n4pySypiKRhN32u/JGo=
github.com/sagernet/wireguard-go v0.0.0-20221116151939-c99467f53f2c/go.mod h1:euOmN6O5kk9dQmgSS8Df4psAl3TCjxOz0NW60EWkSaI=
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=
github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/spyzhov/ajson v0.7.1 h1:1MDIlPc6x0zjNtpa7tDzRAyFAvRX+X8ZsvtYz5lZg6A=
@@ -155,6 +158,7 @@ github.com/spyzhov/ajson v0.7.1/go.mod h1:63V+CGM6f1Bu/p4nLIN8885ojBdt88TbLoSFzy
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
@@ -214,10 +218,13 @@ golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@@ -236,12 +243,13 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 h1:vVKdlvoWBphwdxWKrFZEuM0kGgGLxUOYcY4U/2Vjg44=
golang.org/x/time v0.0.0-20220210224613-90d013bbcef8/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0 h1:/5xXl8Y5W96D+TtHSlonuFqGHIWVuyCkGJLwGh9JJFs=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
@@ -264,7 +272,8 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gotest.tools/v3 v3.4.0 h1:ZazjZUfuVeZGLAmlKKuyv3IKP5orXcwtOwDQH6YVr6o=
gvisor.dev/gvisor v0.0.0-20230415003630-3981d5d5e523 h1:zUQYeyyPLnSR6yMvLSOmLH37xDWCZ7BqlpE69fE5K3Q=
gvisor.dev/gvisor v0.0.0-20230415003630-3981d5d5e523/go.mod h1:pzr6sy8gDLfVmDAg8OYrlKvGEHw5C3PGTiBXBTCx76Q=
gotest.tools/v3 v3.4.0/go.mod h1:CtbdzLSsqVhDgMtKsx03ird5YTGB3ar27v0u/yKBW5g=
gvisor.dev/gvisor v0.0.0-20220901235040-6ca97ef2ce1c h1:m5lcgWnL3OElQNVyp3qcncItJ2c0sQlSGjYK2+nJTA4=
gvisor.dev/gvisor v0.0.0-20220901235040-6ca97ef2ce1c/go.mod h1:TIvkJD0sxe8pIob3p6T8IzxXunlp6yfgktvTNp+DGNM=
lukechampine.com/blake3 v1.1.7 h1:GgRMhmdsuK8+ii6UZFDL8Nb+VyMwadAgcJyfYHxG6n0=
lukechampine.com/blake3 v1.1.7/go.mod h1:tkKEOtDkNtklkXtLNEOGNq5tcV90tJiA1vAA12R78LA=

View File

@@ -18,40 +18,18 @@ var muxProtocols = []mux.Protocol{
}
func TestVMessSMux(t *testing.T) {
testVMessMux(t, option.MultiplexOptions{
Enabled: true,
Protocol: mux.ProtocolSMux.String(),
})
testVMessMux(t, mux.ProtocolSMux.String())
}
func TestShadowsocksMux(t *testing.T) {
for _, protocol := range muxProtocols {
t.Run(protocol.String(), func(t *testing.T) {
testShadowsocksMux(t, option.MultiplexOptions{
Enabled: true,
Protocol: protocol.String(),
})
testShadowsocksMux(t, protocol.String())
})
}
}
func TestShadowsockH2Mux(t *testing.T) {
testShadowsocksMux(t, option.MultiplexOptions{
Enabled: true,
Protocol: mux.ProtocolH2Mux.String(),
Padding: true,
})
}
func TestShadowsockSMuxPadding(t *testing.T) {
testShadowsocksMux(t, option.MultiplexOptions{
Enabled: true,
Protocol: mux.ProtocolSMux.String(),
Padding: true,
})
}
func testShadowsocksMux(t *testing.T, options option.MultiplexOptions) {
func testShadowsocksMux(t *testing.T, protocol string) {
method := shadowaead_2022.List[0]
password := mkBase64(t, 16)
startInstance(t, option.Options{
@@ -90,9 +68,12 @@ func testShadowsocksMux(t *testing.T, options option.MultiplexOptions) {
Server: "127.0.0.1",
ServerPort: serverPort,
},
Method: method,
Password: password,
MultiplexOptions: &options,
Method: method,
Password: password,
MultiplexOptions: &option.MultiplexOptions{
Enabled: true,
Protocol: protocol,
},
},
},
},
@@ -110,7 +91,7 @@ func testShadowsocksMux(t *testing.T, options option.MultiplexOptions) {
testSuit(t, clientPort, testPort)
}
func testVMessMux(t *testing.T, options option.MultiplexOptions) {
func testVMessMux(t *testing.T, protocol string) {
user, _ := uuid.NewV4()
startInstance(t, option.Options{
Inbounds: []option.Inbound{
@@ -151,9 +132,12 @@ func testVMessMux(t *testing.T, options option.MultiplexOptions) {
Server: "127.0.0.1",
ServerPort: serverPort,
},
Security: "auto",
UUID: user.String(),
Multiplex: &options,
Security: "auto",
UUID: user.String(),
Multiplex: &option.MultiplexOptions{
Enabled: true,
Protocol: protocol,
},
},
},
},

View File

@@ -19,7 +19,7 @@ func TestUDPNatClose(t *testing.T) {
defer cancel()
connCtx, connCancel := common.ContextWithCancelCause(context.Background())
defer connCancel(net.ErrClosed)
service := udpnat.New[int](1, &testUDPNatCloseHandler{connCancel})
service := udpnat.New[int](ctx, 1, &testUDPNatCloseHandler{connCancel})
service.NewPacket(ctx, 0, buf.As([]byte("Hello")), M.Metadata{}, func(natConn N.PacketConn) N.PacketWriter {
return &testPacketWriter{}
})

View File

@@ -45,7 +45,6 @@ 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

@@ -12,7 +12,6 @@ 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"
@@ -34,16 +33,9 @@ type Client struct {
transport *http2.Transport
options option.V2RayGRPCOptions
url *url.URL
host string
}
func NewClient(ctx context.Context, dialer N.Dialer, serverAddr M.Socksaddr, options option.V2RayGRPCOptions, tlsConfig tls.Config) adapter.V2RayClientTransport {
var host string
if tlsConfig != nil && tlsConfig.ServerName() != "" {
host = M.ParseSocksaddrHostPort(tlsConfig.ServerName(), serverAddr.Port).String()
} else {
host = serverAddr.String()
}
client := &Client{
ctx: ctx,
dialer: dialer,
@@ -60,7 +52,6 @@ func NewClient(ctx context.Context, dialer N.Dialer, serverAddr M.Socksaddr, opt
Path: "/" + options.ServiceName + "/Tun",
RawPath: "/" + url.PathEscape(options.ServiceName) + "/Tun",
},
host: host,
}
if tlsConfig == nil {
@@ -90,19 +81,15 @@ func (c *Client) DialContext(ctx context.Context) (net.Conn, error) {
Body: pipeInReader,
URL: c.url,
Header: defaultClientHeader,
Host: c.host,
}
request = request.WithContext(ctx)
conn := newLateGunConn(pipeInWriter)
go func() {
response, err := c.transport.RoundTrip(request)
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 {
if err == nil {
conn.setup(response.Body, nil)
} else {
conn.setup(nil, err)
}
}()
return conn, nil

View File

@@ -139,16 +139,15 @@ 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 {
response.Body.Close()
conn.Setup(nil, E.New("unexpected status: ", response.StatusCode, " ", response.Status))
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)
@@ -199,13 +199,13 @@ func (c *HTTP2Conn) NeedAdditionalReadDeadline() bool {
type ServerHTTPConn struct {
HTTP2Conn
Flusher http.Flusher
flusher http.Flusher
}
func (c *ServerHTTPConn) Write(b []byte) (n int, err error) {
n, err = c.writer.Write(b)
if err == nil {
c.Flusher.Flush()
c.flusher.Flush()
}
return
}
@@ -246,11 +246,6 @@ func (w *HTTP2ConnWrapper) CloseWrapper() {
w.closed = true
}
func (w *HTTP2ConnWrapper) Close() error {
w.CloseWrapper()
return w.ExtendedConn.Close()
}
func (w *HTTP2ConnWrapper) Upstream() any {
return w.ExtendedConn
}

View File

@@ -101,7 +101,7 @@ func (c *ClientBind) Open(port uint16) (fns []conn.ReceiveFunc, actualPort uint1
return []conn.ReceiveFunc{c.receive}, 0, nil
}
func (c *ClientBind) receive(packets [][]byte, sizes []int, eps []conn.Endpoint) (count int, err error) {
func (c *ClientBind) receive(b []byte) (n int, ep conn.Endpoint, err error) {
udpConn, err := c.connect()
if err != nil {
select {
@@ -113,26 +113,22 @@ func (c *ClientBind) receive(packets [][]byte, sizes []int, eps []conn.Endpoint)
err = nil
return
}
n, addr, err := udpConn.ReadFrom(packets[0])
n, addr, err := udpConn.ReadFrom(b)
if err != nil {
udpConn.Close()
select {
case <-c.done:
default:
c.errorHandler.NewError(context.Background(), E.Cause(err, "read packet"))
err = nil
}
return
}
sizes[0] = n
if n > 3 {
b := packets[0]
b[1] = 0
b[2] = 0
b[3] = 0
}
eps[0] = Endpoint(M.SocksaddrFromNet(addr))
count = 1
ep = Endpoint(M.SocksaddrFromNet(addr))
return
}
@@ -159,39 +155,32 @@ func (c *ClientBind) SetMark(mark uint32) error {
return nil
}
func (c *ClientBind) Send(bufs [][]byte, ep conn.Endpoint) error {
func (c *ClientBind) Send(b []byte, ep conn.Endpoint) error {
udpConn, err := c.connect()
if err != nil {
return err
}
destination := M.Socksaddr(ep.(Endpoint))
for _, b := range bufs {
if len(b) > 3 {
reserved, loaded := c.reservedForEndpoint[destination]
if !loaded {
reserved = c.reserved
}
b[1] = reserved[0]
b[2] = reserved[1]
b[3] = reserved[2]
}
_, err = udpConn.WriteTo(b, destination)
if err != nil {
udpConn.Close()
return err
if len(b) > 3 {
reserved, loaded := c.reservedForEndpoint[destination]
if !loaded {
reserved = c.reserved
}
b[1] = reserved[0]
b[2] = reserved[1]
b[3] = reserved[2]
}
return nil
_, err = udpConn.WriteTo(b, destination)
if err != nil {
udpConn.Close()
}
return err
}
func (c *ClientBind) ParseEndpoint(s string) (conn.Endpoint, error) {
return Endpoint(M.ParseSocksaddr(s)), nil
}
func (c *ClientBind) BatchSize() int {
return 1
}
type wireConn struct {
net.PacketConn
access sync.Mutex

View File

@@ -26,24 +26,23 @@ func NewNATDevice(upstream Device, ipRewrite bool) NatDevice {
return wrapper
}
func (d *natDeviceWrapper) Read(bufs [][]byte, sizes []int, offset int) (count int, err error) {
func (d *natDeviceWrapper) Read(p []byte, offset int) (int, error) {
select {
case packet := <-d.outbound:
defer packet.Release()
sizes[0] = copy(bufs[0][offset:], packet.Bytes())
return 1, nil
return copy(p[offset:], packet.Bytes()), nil
default:
}
return d.Device.Read(bufs, sizes, offset)
return d.Device.Read(p, offset)
}
func (d *natDeviceWrapper) Write(bufs [][]byte, offset int) (count int, err error) {
packet := bufs[0][offset:]
func (d *natDeviceWrapper) Write(p []byte, offset int) (int, error) {
packet := p[offset:]
handled, err := d.mapping.WritePacket(packet)
if handled {
return 1, err
return len(packet), err
}
return d.Device.Write(bufs, offset)
return d.Device.Write(p, offset)
}
func (d *natDeviceWrapper) CreateDestination(session tun.RouteSession, conn tun.RouteContext) tun.DirectDestination {

View File

@@ -9,7 +9,7 @@ import (
"gvisor.dev/gvisor/pkg/tcpip/stack"
)
func (d *natDestinationWrapper) WritePacketBuffer(buffer stack.PacketBufferPtr) error {
func (d *natDestinationWrapper) WritePacketBuffer(buffer *stack.PacketBuffer) error {
defer buffer.DecRef()
if d.device.writer != nil {
d.device.writer.RewritePacketBuffer(buffer)

View File

@@ -35,7 +35,7 @@ type StackDevice struct {
stack *stack.Stack
mtu uint32
events chan wgTun.Event
outbound chan stack.PacketBufferPtr
outbound chan *stack.PacketBuffer
packetOutbound chan *buf.Buffer
done chan struct{}
dispatcher stack.NetworkDispatcher
@@ -55,7 +55,7 @@ func NewStackDevice(localAddresses []netip.Prefix, mtu uint32, ipRewrite bool) (
stack: ipStack,
mtu: mtu,
events: make(chan wgTun.Event, 1),
outbound: make(chan stack.PacketBufferPtr, 256),
outbound: make(chan *stack.PacketBuffer, 256),
packetOutbound: make(chan *buf.Buffer, 256),
done: make(chan struct{}),
mapping: tun.NewNatMapping(ipRewrite),
@@ -171,60 +171,49 @@ func (w *StackDevice) File() *os.File {
return nil
}
func (w *StackDevice) Read(bufs [][]byte, sizes []int, offset int) (count int, err error) {
func (w *StackDevice) Read(p []byte, offset int) (n int, err error) {
select {
case packetBuffer, ok := <-w.outbound:
if !ok {
return 0, os.ErrClosed
}
defer packetBuffer.DecRef()
p := bufs[0]
p = p[offset:]
n := 0
for _, slice := range packetBuffer.AsSlices() {
n += copy(p[n:], slice)
}
sizes[0] = n
count = 1
return
case packet := <-w.packetOutbound:
defer packet.Release()
sizes[0] = copy(bufs[0][offset:], packet.Bytes())
count = 1
n = copy(p[offset:], packet.Bytes())
return
case <-w.done:
return 0, os.ErrClosed
}
}
func (w *StackDevice) Write(bufs [][]byte, offset int) (count int, err error) {
for _, b := range bufs {
b = b[offset:]
if len(b) == 0 {
continue
}
handled, err := w.mapping.WritePacket(b)
if handled {
count++
if err != nil {
return count, err
}
continue
}
var networkProtocol tcpip.NetworkProtocolNumber
switch header.IPVersion(b) {
case header.IPv4Version:
networkProtocol = header.IPv4ProtocolNumber
case header.IPv6Version:
networkProtocol = header.IPv6ProtocolNumber
}
packetBuffer := stack.NewPacketBuffer(stack.PacketBufferOptions{
Payload: bufferv2.MakeWithData(b),
})
w.dispatcher.DeliverNetworkPacket(networkProtocol, packetBuffer)
packetBuffer.DecRef()
count++
func (w *StackDevice) Write(p []byte, offset int) (n int, err error) {
p = p[offset:]
if len(p) == 0 {
return
}
handled, err := w.mapping.WritePacket(p)
if handled {
return len(p), err
}
var networkProtocol tcpip.NetworkProtocolNumber
switch header.IPVersion(p) {
case header.IPv4Version:
networkProtocol = header.IPv4ProtocolNumber
case header.IPv6Version:
networkProtocol = header.IPv6ProtocolNumber
}
packetBuffer := stack.NewPacketBuffer(stack.PacketBufferOptions{
Payload: bufferv2.MakeWithData(p),
})
defer packetBuffer.DecRef()
w.dispatcher.DeliverNetworkPacket(networkProtocol, packetBuffer)
n = len(p)
return
}
@@ -240,7 +229,7 @@ func (w *StackDevice) Name() (string, error) {
return "sing-box", nil
}
func (w *StackDevice) Events() <-chan wgTun.Event {
func (w *StackDevice) Events() chan wgTun.Event {
return w.events
}
@@ -259,10 +248,6 @@ func (w *StackDevice) Close() error {
return nil
}
func (w *StackDevice) BatchSize() int {
return 1
}
func (w *StackDevice) CreateDestination(session tun.RouteSession, conn tun.RouteContext) tun.DirectDestination {
w.mapping.CreateSession(session, conn)
return &stackNatDestination{
@@ -284,7 +269,7 @@ func (d *stackNatDestination) WritePacket(buffer *buf.Buffer) error {
return nil
}
func (d *stackNatDestination) WritePacketBuffer(buffer stack.PacketBufferPtr) error {
func (d *stackNatDestination) WritePacketBuffer(buffer *stack.PacketBuffer) error {
if d.device.writer != nil {
d.device.writer.RewritePacketBuffer(buffer)
}
@@ -336,7 +321,7 @@ func (ep *wireEndpoint) ARPHardwareType() header.ARPHardwareType {
return header.ARPHardwareNone
}
func (ep *wireEndpoint) AddHeader(buffer stack.PacketBufferPtr) {
func (ep *wireEndpoint) AddHeader(buffer *stack.PacketBuffer) {
}
func (ep *wireEndpoint) WritePackets(list stack.PacketBufferList) (int, tcpip.Error) {

View File

@@ -27,6 +27,14 @@ type SystemDevice struct {
addr6 netip.Addr
}
/*func (w *SystemDevice) NewEndpoint() (stack.LinkEndpoint, error) {
gTun, isGTun := w.device.(tun.GVisorTun)
if !isGTun {
return nil, tun.ErrGVisorUnsupported
}
return gTun.NewEndpoint()
}*/
func NewSystemDevice(router adapter.Router, interfaceName string, localPrefixes []netip.Prefix, mtu uint32) (*SystemDevice, error) {
var inet4Addresses []netip.Prefix
var inet6Addresses []netip.Prefix
@@ -95,23 +103,12 @@ func (w *SystemDevice) File() *os.File {
return nil
}
func (w *SystemDevice) Read(bufs [][]byte, sizes []int, offset int) (count int, err error) {
sizes[0], err = w.device.Read(bufs[0][offset-tun.PacketOffset:])
if err == nil {
count = 1
}
return
func (w *SystemDevice) Read(p []byte, offset int) (int, error) {
return w.device.Read(p[offset-tun.PacketOffset:])
}
func (w *SystemDevice) Write(bufs [][]byte, offset int) (count int, err error) {
for _, b := range bufs {
_, err = w.device.Write(b[offset:])
if err != nil {
return
}
count++
}
return
func (w *SystemDevice) Write(p []byte, offset int) (int, error) {
return w.device.Write(p[offset:])
}
func (w *SystemDevice) Flush() error {
@@ -126,14 +123,10 @@ func (w *SystemDevice) Name() (string, error) {
return w.name, nil
}
func (w *SystemDevice) Events() <-chan wgTun.Event {
func (w *SystemDevice) Events() chan wgTun.Event {
return w.events
}
func (w *SystemDevice) Close() error {
return w.device.Close()
}
func (w *SystemDevice) BatchSize() int {
return 1
}

View File

@@ -0,0 +1,95 @@
package wireguard
import (
"io"
"github.com/sagernet/sing/common/buf"
E "github.com/sagernet/sing/common/exceptions"
M "github.com/sagernet/sing/common/metadata"
N "github.com/sagernet/sing/common/network"
"github.com/sagernet/wireguard-go/conn"
)
var _ conn.Bind = (*ServerBind)(nil)
type ServerBind struct {
inbound chan serverPacket
done chan struct{}
writeBack N.PacketWriter
}
func NewServerBind(writeBack N.PacketWriter) *ServerBind {
return &ServerBind{
inbound: make(chan serverPacket, 256),
done: make(chan struct{}),
writeBack: writeBack,
}
}
func (s *ServerBind) Abort() error {
select {
case <-s.done:
return io.ErrClosedPipe
default:
close(s.done)
}
return nil
}
type serverPacket struct {
buffer *buf.Buffer
source M.Socksaddr
}
func (s *ServerBind) Open(port uint16) (fns []conn.ReceiveFunc, actualPort uint16, err error) {
fns = []conn.ReceiveFunc{s.receive}
return
}
func (s *ServerBind) receive(b []byte) (n int, ep conn.Endpoint, err error) {
select {
case packet := <-s.inbound:
defer packet.buffer.Release()
n = copy(b, packet.buffer.Bytes())
ep = Endpoint(packet.source)
return
case <-s.done:
err = io.ErrClosedPipe
return
}
}
func (s *ServerBind) WriteIsThreadUnsafe() {
}
func (s *ServerBind) WritePacket(buffer *buf.Buffer, destination M.Socksaddr) error {
select {
case s.inbound <- serverPacket{
buffer: buffer,
source: destination,
}:
return nil
case <-s.done:
return io.ErrClosedPipe
}
}
func (s *ServerBind) Close() error {
return nil
}
func (s *ServerBind) SetMark(mark uint32) error {
return nil
}
func (s *ServerBind) Send(b []byte, ep conn.Endpoint) error {
return s.writeBack.WritePacket(buf.As(b), M.Socksaddr(ep.(Endpoint)))
}
func (s *ServerBind) ParseEndpoint(addr string) (conn.Endpoint, error) {
destination := M.ParseSocksaddr(addr)
if !destination.IsValid() || destination.Port == 0 {
return nil, E.New("invalid endpoint: ", addr)
}
return Endpoint(destination), nil
}