mirror of
https://github.com/shtorm-7/sing-box-extended.git
synced 2026-07-08 09:13:17 +03:00
Compare commits
12 Commits
v1.1-beta7
...
v1.1-beta8
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8ce244dd04 | ||
|
|
0f57b93925 | ||
|
|
c90a77a185 | ||
|
|
c6586f19fa | ||
|
|
cbab86ae38 | ||
|
|
17b5f031f1 | ||
|
|
b00b6b9e25 | ||
|
|
fb6b3b0401 | ||
|
|
22ea878fe9 | ||
|
|
abe3dc6039 | ||
|
|
852829b9dc | ||
|
|
407509c985 |
3
Makefile
3
Makefile
@@ -64,6 +64,7 @@ test:
|
|||||||
cd test && \
|
cd test && \
|
||||||
go mod tidy && \
|
go mod tidy && \
|
||||||
go test -v -tags "$(TAGS_TEST)" .
|
go test -v -tags "$(TAGS_TEST)" .
|
||||||
|
|
||||||
test_stdio:
|
test_stdio:
|
||||||
@go test -v ./... && \
|
@go test -v ./... && \
|
||||||
cd test && \
|
cd test && \
|
||||||
@@ -71,7 +72,7 @@ test_stdio:
|
|||||||
go test -v -tags "$(TAGS_TEST),force_stdio" .
|
go test -v -tags "$(TAGS_TEST),force_stdio" .
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -rf bin dist
|
rm -rf bin dist sing-box
|
||||||
rm -f $(shell go env GOPATH)/sing-box
|
rm -f $(shell go env GOPATH)/sing-box
|
||||||
|
|
||||||
update:
|
update:
|
||||||
|
|||||||
@@ -38,13 +38,25 @@ type myUpstreamHandlerWrapper struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (w *myUpstreamHandlerWrapper) NewConnection(ctx context.Context, conn net.Conn, metadata M.Metadata) error {
|
func (w *myUpstreamHandlerWrapper) NewConnection(ctx context.Context, conn net.Conn, metadata M.Metadata) error {
|
||||||
w.metadata.Destination = metadata.Destination
|
myMetadata := w.metadata
|
||||||
return w.connectionHandler(ctx, conn, w.metadata)
|
if metadata.Source.IsValid() {
|
||||||
|
myMetadata.Source = metadata.Source
|
||||||
|
}
|
||||||
|
if metadata.Destination.IsValid() {
|
||||||
|
myMetadata.Destination = metadata.Destination
|
||||||
|
}
|
||||||
|
return w.connectionHandler(ctx, conn, myMetadata)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *myUpstreamHandlerWrapper) NewPacketConnection(ctx context.Context, conn N.PacketConn, metadata M.Metadata) error {
|
func (w *myUpstreamHandlerWrapper) NewPacketConnection(ctx context.Context, conn N.PacketConn, metadata M.Metadata) error {
|
||||||
w.metadata.Destination = metadata.Destination
|
myMetadata := w.metadata
|
||||||
return w.packetHandler(ctx, conn, w.metadata)
|
if metadata.Source.IsValid() {
|
||||||
|
myMetadata.Source = metadata.Source
|
||||||
|
}
|
||||||
|
if metadata.Destination.IsValid() {
|
||||||
|
myMetadata.Destination = metadata.Destination
|
||||||
|
}
|
||||||
|
return w.packetHandler(ctx, conn, myMetadata)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *myUpstreamHandlerWrapper) NewError(ctx context.Context, err error) {
|
func (w *myUpstreamHandlerWrapper) NewError(ctx context.Context, err error) {
|
||||||
@@ -78,13 +90,23 @@ func NewUpstreamContextHandler(
|
|||||||
|
|
||||||
func (w *myUpstreamContextHandlerWrapper) NewConnection(ctx context.Context, conn net.Conn, metadata M.Metadata) error {
|
func (w *myUpstreamContextHandlerWrapper) NewConnection(ctx context.Context, conn net.Conn, metadata M.Metadata) error {
|
||||||
myMetadata := ContextFrom(ctx)
|
myMetadata := ContextFrom(ctx)
|
||||||
myMetadata.Destination = metadata.Destination
|
if metadata.Source.IsValid() {
|
||||||
|
myMetadata.Source = metadata.Source
|
||||||
|
}
|
||||||
|
if metadata.Destination.IsValid() {
|
||||||
|
myMetadata.Destination = metadata.Destination
|
||||||
|
}
|
||||||
return w.connectionHandler(ctx, conn, *myMetadata)
|
return w.connectionHandler(ctx, conn, *myMetadata)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *myUpstreamContextHandlerWrapper) NewPacketConnection(ctx context.Context, conn N.PacketConn, metadata M.Metadata) error {
|
func (w *myUpstreamContextHandlerWrapper) NewPacketConnection(ctx context.Context, conn N.PacketConn, metadata M.Metadata) error {
|
||||||
myMetadata := ContextFrom(ctx)
|
myMetadata := ContextFrom(ctx)
|
||||||
myMetadata.Destination = metadata.Destination
|
if metadata.Source.IsValid() {
|
||||||
|
myMetadata.Source = metadata.Source
|
||||||
|
}
|
||||||
|
if metadata.Destination.IsValid() {
|
||||||
|
myMetadata.Destination = metadata.Destination
|
||||||
|
}
|
||||||
return w.packetHandler(ctx, conn, *myMetadata)
|
return w.packetHandler(ctx, conn, *myMetadata)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -146,7 +146,7 @@ func (d *DefaultDialer) DialContext(ctx context.Context, network string, address
|
|||||||
case N.NetworkUDP:
|
case N.NetworkUDP:
|
||||||
return d.udpDialer.DialContext(ctx, network, address.String())
|
return d.udpDialer.DialContext(ctx, network, address.String())
|
||||||
}
|
}
|
||||||
return d.dialer.DialContext(ctx, network, address.Unwrap().String())
|
return d.dialer.DialContext(ctx, network, address.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *DefaultDialer) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
|
func (d *DefaultDialer) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import (
|
|||||||
M "github.com/sagernet/sing/common/metadata"
|
M "github.com/sagernet/sing/common/metadata"
|
||||||
N "github.com/sagernet/sing/common/network"
|
N "github.com/sagernet/sing/common/network"
|
||||||
"github.com/sagernet/sing/common/rw"
|
"github.com/sagernet/sing/common/rw"
|
||||||
|
"github.com/sagernet/sing/common/task"
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewConnection(ctx context.Context, router adapter.Router, errorHandler E.Handler, logger log.ContextLogger, conn net.Conn, metadata adapter.InboundContext) error {
|
func NewConnection(ctx context.Context, router adapter.Router, errorHandler E.Handler, logger log.ContextLogger, conn net.Conn, metadata adapter.InboundContext) error {
|
||||||
@@ -25,14 +26,21 @@ func NewConnection(ctx context.Context, router adapter.Router, errorHandler E.Ha
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
var stream net.Conn
|
var group task.Group
|
||||||
for {
|
group.Append0(func(ctx context.Context) error {
|
||||||
stream, err = session.Accept()
|
var stream net.Conn
|
||||||
if err != nil {
|
for {
|
||||||
return err
|
stream, err = session.Accept()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
go newConnection(ctx, router, errorHandler, logger, stream, metadata)
|
||||||
}
|
}
|
||||||
go newConnection(ctx, router, errorHandler, logger, stream, metadata)
|
})
|
||||||
}
|
group.Cleanup(func() {
|
||||||
|
session.Close()
|
||||||
|
})
|
||||||
|
return group.Run(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
func newConnection(ctx context.Context, router adapter.Router, errorHandler E.Handler, logger log.ContextLogger, stream net.Conn, metadata adapter.InboundContext) {
|
func newConnection(ctx context.Context, router adapter.Router, errorHandler E.Handler, logger log.ContextLogger, stream net.Conn, metadata adapter.InboundContext) {
|
||||||
|
|||||||
@@ -28,11 +28,5 @@ type Info struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func FindProcessInfo(searcher Searcher, ctx context.Context, network string, source netip.AddrPort, destination netip.AddrPort) (*Info, error) {
|
func FindProcessInfo(searcher Searcher, ctx context.Context, network string, source netip.AddrPort, destination netip.AddrPort) (*Info, error) {
|
||||||
info, err := findProcessInfo(searcher, ctx, network, source, destination)
|
return findProcessInfo(searcher, ctx, network, source, destination)
|
||||||
if err != nil {
|
|
||||||
if source.Addr().Is4In6() {
|
|
||||||
info, err = findProcessInfo(searcher, ctx, network, netip.AddrPortFrom(netip.AddrFrom4(source.Addr().As4()), source.Port()), destination)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return info, err
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,8 +36,8 @@ func (l *Listener) Accept() (net.Conn, error) {
|
|||||||
}
|
}
|
||||||
if header != nil {
|
if header != nil {
|
||||||
return &bufio.AddrConn{Conn: conn, Metadata: M.Metadata{
|
return &bufio.AddrConn{Conn: conn, Metadata: M.Metadata{
|
||||||
Source: M.SocksaddrFromNet(header.SourceAddr),
|
Source: M.SocksaddrFromNet(header.SourceAddr).Unwrap(),
|
||||||
Destination: M.SocksaddrFromNet(header.DestinationAddr),
|
Destination: M.SocksaddrFromNet(header.DestinationAddr).Unwrap(),
|
||||||
}}, nil
|
}}, nil
|
||||||
}
|
}
|
||||||
return conn, nil
|
return conn, nil
|
||||||
|
|||||||
@@ -2,14 +2,11 @@ package redir
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"net"
|
|
||||||
"net/netip"
|
"net/netip"
|
||||||
"os"
|
|
||||||
"strconv"
|
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
|
"github.com/sagernet/sing/common/control"
|
||||||
E "github.com/sagernet/sing/common/exceptions"
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
F "github.com/sagernet/sing/common/format"
|
|
||||||
M "github.com/sagernet/sing/common/metadata"
|
M "github.com/sagernet/sing/common/metadata"
|
||||||
|
|
||||||
"golang.org/x/sys/unix"
|
"golang.org/x/sys/unix"
|
||||||
@@ -32,6 +29,18 @@ func TProxy(fd uintptr, isIPv6 bool) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TProxyWriteBack() control.Func {
|
||||||
|
return func(network, address string, conn syscall.RawConn) error {
|
||||||
|
return control.Raw(conn, func(fd uintptr) error {
|
||||||
|
if M.ParseSocksaddr(address).Addr.Is6() {
|
||||||
|
return syscall.SetsockoptInt(int(fd), syscall.SOL_IPV6, unix.IPV6_TRANSPARENT, 1)
|
||||||
|
} else {
|
||||||
|
return syscall.SetsockoptInt(int(fd), syscall.SOL_IP, syscall.IP_TRANSPARENT, 1)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func GetOriginalDestinationFromOOB(oob []byte) (netip.AddrPort, error) {
|
func GetOriginalDestinationFromOOB(oob []byte) (netip.AddrPort, error) {
|
||||||
controlMessages, err := unix.ParseSocketControlMessage(oob)
|
controlMessages, err := unix.ParseSocketControlMessage(oob)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -46,79 +55,3 @@ func GetOriginalDestinationFromOOB(oob []byte) (netip.AddrPort, error) {
|
|||||||
}
|
}
|
||||||
return netip.AddrPort{}, E.New("not found")
|
return netip.AddrPort{}, E.New("not found")
|
||||||
}
|
}
|
||||||
|
|
||||||
func DialUDP(lAddr *net.UDPAddr, rAddr *net.UDPAddr) (*net.UDPConn, error) {
|
|
||||||
rSockAddr, err := udpAddrToSockAddr(rAddr)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
lSockAddr, err := udpAddrToSockAddr(lAddr)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
fd, err := syscall.Socket(udpAddrFamily(lAddr, rAddr), syscall.SOCK_DGRAM, 0)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = syscall.SetsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1); err != nil {
|
|
||||||
syscall.Close(fd)
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = syscall.SetsockoptInt(fd, syscall.SOL_IP, syscall.IP_TRANSPARENT, 1); err != nil {
|
|
||||||
syscall.Close(fd)
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = syscall.Bind(fd, lSockAddr); err != nil {
|
|
||||||
syscall.Close(fd)
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = syscall.Connect(fd, rSockAddr); err != nil {
|
|
||||||
syscall.Close(fd)
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
fdFile := os.NewFile(uintptr(fd), F.ToString("net-udp-dial-", rAddr))
|
|
||||||
defer fdFile.Close()
|
|
||||||
|
|
||||||
c, err := net.FileConn(fdFile)
|
|
||||||
if err != nil {
|
|
||||||
syscall.Close(fd)
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return c.(*net.UDPConn), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func udpAddrToSockAddr(addr *net.UDPAddr) (syscall.Sockaddr, error) {
|
|
||||||
switch {
|
|
||||||
case addr.IP.To4() != nil:
|
|
||||||
ip := [4]byte{}
|
|
||||||
copy(ip[:], addr.IP.To4())
|
|
||||||
|
|
||||||
return &syscall.SockaddrInet4{Addr: ip, Port: addr.Port}, nil
|
|
||||||
|
|
||||||
default:
|
|
||||||
ip := [16]byte{}
|
|
||||||
copy(ip[:], addr.IP.To16())
|
|
||||||
|
|
||||||
zoneID, err := strconv.ParseUint(addr.Zone, 10, 32)
|
|
||||||
if err != nil {
|
|
||||||
zoneID = 0
|
|
||||||
}
|
|
||||||
|
|
||||||
return &syscall.SockaddrInet6{Addr: ip, Port: addr.Port, ZoneId: uint32(zoneID)}, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func udpAddrFamily(lAddr, rAddr *net.UDPAddr) int {
|
|
||||||
if (lAddr == nil || lAddr.IP.To4() != nil) && (rAddr == nil || lAddr.IP.To4() != nil) {
|
|
||||||
return syscall.AF_INET
|
|
||||||
}
|
|
||||||
return syscall.AF_INET6
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -3,19 +3,20 @@
|
|||||||
package redir
|
package redir
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net"
|
|
||||||
"net/netip"
|
"net/netip"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
|
"github.com/sagernet/sing/common/control"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TProxy(fd uintptr, isIPv6 bool) error {
|
func TProxy(fd uintptr, isIPv6 bool) error {
|
||||||
return os.ErrInvalid
|
return os.ErrInvalid
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TProxyWriteBack() control.Func {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func GetOriginalDestinationFromOOB(oob []byte) (netip.AddrPort, error) {
|
func GetOriginalDestinationFromOOB(oob []byte) (netip.AddrPort, error) {
|
||||||
return netip.AddrPort{}, os.ErrInvalid
|
return netip.AddrPort{}, os.ErrInvalid
|
||||||
}
|
}
|
||||||
|
|
||||||
func DialUDP(lAddr *net.UDPAddr, rAddr *net.UDPAddr) (*net.UDPConn, error) {
|
|
||||||
return nil, os.ErrInvalid
|
|
||||||
}
|
|
||||||
|
|||||||
50
common/tls/mkcert.go
Normal file
50
common/tls/mkcert.go
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
package tls
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/rand"
|
||||||
|
"crypto/rsa"
|
||||||
|
"crypto/tls"
|
||||||
|
"crypto/x509"
|
||||||
|
"crypto/x509/pkix"
|
||||||
|
"encoding/pem"
|
||||||
|
"math/big"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func GenerateKeyPair(serverName string) (*tls.Certificate, error) {
|
||||||
|
key, err := rsa.GenerateKey(rand.Reader, 2048)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
serialNumber, err := rand.Int(rand.Reader, new(big.Int).Lsh(big.NewInt(1), 128))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
template := &x509.Certificate{
|
||||||
|
SerialNumber: serialNumber,
|
||||||
|
NotBefore: time.Now().Add(time.Hour * -1),
|
||||||
|
NotAfter: time.Now().Add(time.Hour),
|
||||||
|
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
|
||||||
|
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
|
||||||
|
BasicConstraintsValid: true,
|
||||||
|
Subject: pkix.Name{
|
||||||
|
CommonName: serverName,
|
||||||
|
},
|
||||||
|
DNSNames: []string{serverName},
|
||||||
|
}
|
||||||
|
publicDer, err := x509.CreateCertificate(rand.Reader, template, template, key.Public(), key)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
privateDer, err := x509.MarshalPKCS8PrivateKey(key)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
publicPem := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: publicDer})
|
||||||
|
privPem := pem.EncodeToMemory(&pem.Block{Type: "PRIVATE KEY", Bytes: privateDer})
|
||||||
|
keyPair, err := tls.X509KeyPair(publicPem, privPem)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &keyPair, err
|
||||||
|
}
|
||||||
@@ -34,6 +34,8 @@ func (c *STDServerConfig) SetNextProtos(nextProto []string) {
|
|||||||
c.config.NextProtos = nextProto
|
c.config.NextProtos = nextProto
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var errInsecureUnused = E.New("tls: insecure unused")
|
||||||
|
|
||||||
func newSTDServer(ctx context.Context, logger log.Logger, options option.InboundTLSOptions) (ServerConfig, error) {
|
func newSTDServer(ctx context.Context, logger log.Logger, options option.InboundTLSOptions) (ServerConfig, error) {
|
||||||
if !options.Enabled {
|
if !options.Enabled {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
@@ -46,6 +48,9 @@ func newSTDServer(ctx context.Context, logger log.Logger, options option.Inbound
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
if options.Insecure {
|
||||||
|
return nil, errInsecureUnused
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
tlsConfig = &tls.Config{}
|
tlsConfig = &tls.Config{}
|
||||||
}
|
}
|
||||||
@@ -102,17 +107,23 @@ func newSTDServer(ctx context.Context, logger log.Logger, options option.Inbound
|
|||||||
}
|
}
|
||||||
key = content
|
key = content
|
||||||
}
|
}
|
||||||
if certificate == nil {
|
if certificate == nil && key == nil && options.Insecure {
|
||||||
return nil, E.New("missing certificate")
|
tlsConfig.GetCertificate = func(info *tls.ClientHelloInfo) (*tls.Certificate, error) {
|
||||||
|
return GenerateKeyPair(info.ServerName)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if certificate == nil {
|
||||||
|
return nil, E.New("missing certificate")
|
||||||
|
} else if key == nil {
|
||||||
|
return nil, E.New("missing key")
|
||||||
|
}
|
||||||
|
|
||||||
|
keyPair, err := tls.X509KeyPair(certificate, key)
|
||||||
|
if err != nil {
|
||||||
|
return nil, E.Cause(err, "parse x509 key pair")
|
||||||
|
}
|
||||||
|
tlsConfig.Certificates = []tls.Certificate{keyPair}
|
||||||
}
|
}
|
||||||
if key == nil {
|
|
||||||
return nil, E.New("missing key")
|
|
||||||
}
|
|
||||||
keyPair, err := tls.X509KeyPair(certificate, key)
|
|
||||||
if err != nil {
|
|
||||||
return nil, E.Cause(err, "parse x509 key pair")
|
|
||||||
}
|
|
||||||
tlsConfig.Certificates = []tls.Certificate{keyPair}
|
|
||||||
}
|
}
|
||||||
return &STDServerConfig{
|
return &STDServerConfig{
|
||||||
config: tlsConfig,
|
config: tlsConfig,
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
package constant
|
package constant
|
||||||
|
|
||||||
var Version = "1.1-beta6"
|
var Version = "1.1-beta8"
|
||||||
|
|||||||
@@ -1,3 +1,20 @@
|
|||||||
|
#### 1.1-beta8
|
||||||
|
|
||||||
|
* Fix leaks on close
|
||||||
|
* Improve websocket writer
|
||||||
|
* Refine tproxy write back
|
||||||
|
* Refine 4in6 processing
|
||||||
|
* Fix shadowsocks plugins
|
||||||
|
* Fix missing source address from transport connection
|
||||||
|
* Fix fqdn socks5 outbound connection
|
||||||
|
* Fix read source address from grpc-go
|
||||||
|
|
||||||
|
#### 1.0.5
|
||||||
|
|
||||||
|
* Fix missing source address from transport connection
|
||||||
|
* Fix fqdn socks5 outbound connection
|
||||||
|
* Fix read source address from grpc-go
|
||||||
|
|
||||||
#### 1.1-beta7
|
#### 1.1-beta7
|
||||||
|
|
||||||
* Add v2ray mux and XUDP support for VMess inbound
|
* Add v2ray mux and XUDP support for VMess inbound
|
||||||
|
|||||||
@@ -95,7 +95,9 @@
|
|||||||
| cn | 17.8M | 140.3M |
|
| cn | 17.8M | 140.3M |
|
||||||
| cn (Loyalsoldier) | 74.3M | 246.7M |
|
| cn (Loyalsoldier) | 74.3M | 246.7M |
|
||||||
|
|
||||||
#### Shadowsocks benchmark
|
#### Benchmark
|
||||||
|
|
||||||
|
##### Shadowsocks
|
||||||
|
|
||||||
| / | none | aes-128-gcm | 2022-blake3-aes-128-gcm |
|
| / | none | aes-128-gcm | 2022-blake3-aes-128-gcm |
|
||||||
|------------------------------------|:---------:|:-----------:|:-----------------------:|
|
|------------------------------------|:---------:|:-----------:|:-----------------------:|
|
||||||
@@ -103,6 +105,13 @@
|
|||||||
| shadowsocks-rust (v1.15.0-alpha.5) | 10.7 Gbps | / | 9.36 Gbps |
|
| shadowsocks-rust (v1.15.0-alpha.5) | 10.7 Gbps | / | 9.36 Gbps |
|
||||||
| sing-box | 29.0 Gbps | / | 11.8 Gbps |
|
| sing-box | 29.0 Gbps | / | 11.8 Gbps |
|
||||||
|
|
||||||
|
##### VMess
|
||||||
|
|
||||||
|
| / | TCP | HTTP | H2 TLS | WebSocket TLS | gRPC TLS |
|
||||||
|
|--------------------|:---------:|:---------:|:---------:|:-------------:|:---------:|
|
||||||
|
| v2ray-core (5.1.0) | 7.86 GBps | 2.86 Gbps | 1.83 Gbps | 2.36 Gbps | 2.43 Gbps |
|
||||||
|
| sing-box | 7.96 Gbps | 8.09 Gbps | 6.11 Gbps | 8.02 Gbps | 6.35 Gbps |
|
||||||
|
|
||||||
#### License
|
#### License
|
||||||
|
|
||||||
| / | License |
|
| / | License |
|
||||||
|
|||||||
@@ -45,10 +45,6 @@ sing-box version
|
|||||||
It is also recommended to use systemd to manage sing-box service,
|
It is also recommended to use systemd to manage sing-box service,
|
||||||
see [Linux server installation example](./examples/linux-server-installation).
|
see [Linux server installation example](./examples/linux-server-installation).
|
||||||
|
|
||||||
## Contributors
|
|
||||||
|
|
||||||
[](https://github.com/sagernet/sing-box/graphs/contributors)
|
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -25,13 +25,13 @@ go install -v -tags with_clash_api github.com/sagernet/sing-box/cmd/sing-box@lat
|
|||||||
| 构建标志 | 描述 |
|
| 构建标志 | 描述 |
|
||||||
|------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||||
| `with_quic` | 启用 QUIC 支持,参阅 [QUIC 和 HTTP3 DNS 传输层](./configuration/dns/server),[Naive 入站](./configuration/inbound/naive),[Hysteria 入站](./configuration/inbound/hysteria),[Hysteria 出站](./configuration/outbound/hysteria) 和 [V2Ray 传输层#QUIC](./configuration/shared/v2ray-transport#quic)。 |
|
| `with_quic` | 启用 QUIC 支持,参阅 [QUIC 和 HTTP3 DNS 传输层](./configuration/dns/server),[Naive 入站](./configuration/inbound/naive),[Hysteria 入站](./configuration/inbound/hysteria),[Hysteria 出站](./configuration/outbound/hysteria) 和 [V2Ray 传输层#QUIC](./configuration/shared/v2ray-transport#quic)。 |
|
||||||
| `with_grpc` | 启用标准 gRPCuTLS](https://github.com/refraction-networking/utls) 支持, 参阅 [TLS](./configuration/shared/tls#utls)。 |
|
| `with_grpc` | 启用标准 gRPC 支持,参阅 [V2Ray 传输层#gRPC](./configuration/shared/v2ray-transport#grpc)。 |
|
||||||
| `with_acme` | 启用 ACME TLS 证书签发支持,参阅 [TLS](./configuration/shared/tls)。 |
|
|
||||||
| `with_clash_api` | 启用 Clash api 支 支持,参阅 [V2Ray 传输层#gRPC](./configuration/shared/v2ray-transport#grpc)。 |
|
|
||||||
| `with_wireguard` | 启用 WireGuard 支持,参阅 [WireGuard 出站](./configuration/outbound/wireguard)。 |
|
| `with_wireguard` | 启用 WireGuard 支持,参阅 [WireGuard 出站](./configuration/outbound/wireguard)。 |
|
||||||
| `with_shadowsocksr` | 启用 ShadowsocksR 支持,参阅 [ShadowsocksR 出站](./configuration/outbound/shadowsocksr)。 |
|
| `with_shadowsocksr` | 启用 ShadowsocksR 支持,参阅 [ShadowsocksR 出站](./configuration/outbound/shadowsocksr)。 |
|
||||||
| `with_ech` | 启用 TLS ECH 扩展支持,参阅 [TLS](./configuration/shared/tls#ech)。 |
|
| `with_ech` | 启用 TLS ECH 扩展支持,参阅 [TLS](./configuration/shared/tls#ech)。 |
|
||||||
| `with_utls` | 启用 [持,参阅 [实验性](./configuration/experimental#clash-api-fields)。 |
|
| `with_utls` | 启用 uTLS 支持,参阅 [实验性](./configuration/experimental#clash-api-fields)。 |
|
||||||
|
| `with_acme` | 启用 ACME TLS 证书签发支持,参阅 [TLS](./configuration/shared/tls)。 |
|
||||||
|
| `with_clash_api` | 启用 Clash API 支持,参阅 [实验性](./configuration/experimental#clash-api-fields)。 |
|
||||||
| `with_gvisor` | 启用 gVisor 支持,参阅 [Tun 入站](./configuration/inbound/tun#stack) 和 [WireGuard 出站](./configuration/outbound/wireguard#system_interface)。 |
|
| `with_gvisor` | 启用 gVisor 支持,参阅 [Tun 入站](./configuration/inbound/tun#stack) 和 [WireGuard 出站](./configuration/outbound/wireguard#system_interface)。 |
|
||||||
| `with_embedded_tor` (需要 CGO) | 启用 嵌入式 Tor 支持,参阅 [Tor 出站](./configuration/outbound/tor)。 |
|
| `with_embedded_tor` (需要 CGO) | 启用 嵌入式 Tor 支持,参阅 [Tor 出站](./configuration/outbound/tor)。 |
|
||||||
| `with_lwip` (需要 CGO) | 启用 LWIP Tun 栈支持,参阅 [Tun 入站](./configuration/inbound/tun#stack)。 |
|
| `with_lwip` (需要 CGO) | 启用 LWIP Tun 栈支持,参阅 [Tun 入站](./configuration/inbound/tun#stack)。 |
|
||||||
@@ -42,13 +42,9 @@ go install -v -tags with_clash_api github.com/sagernet/sing-box/cmd/sing-box@lat
|
|||||||
sing-box version
|
sing-box version
|
||||||
```
|
```
|
||||||
|
|
||||||
同时推荐使用 Systemd 来管理 sing-box 服务器实例。
|
同时推荐使用 systemd 来管理 sing-box 服务器实例。
|
||||||
参阅 [Linux 服务器安装示例](./examples/linux-server-installation)。
|
参阅 [Linux 服务器安装示例](./examples/linux-server-installation)。
|
||||||
|
|
||||||
## 贡献者
|
|
||||||
|
|
||||||
[](https://github.com/sagernet/sing-box/graphs/contributors)
|
|
||||||
|
|
||||||
## 授权
|
## 授权
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|||||||
14
go.mod
14
go.mod
@@ -23,21 +23,21 @@ require (
|
|||||||
github.com/pires/go-proxyproto v0.6.2
|
github.com/pires/go-proxyproto v0.6.2
|
||||||
github.com/refraction-networking/utls v1.1.2
|
github.com/refraction-networking/utls v1.1.2
|
||||||
github.com/sagernet/quic-go v0.0.0-20220818150011-de611ab3e2bb
|
github.com/sagernet/quic-go v0.0.0-20220818150011-de611ab3e2bb
|
||||||
github.com/sagernet/sing v0.0.0-20220921101604-86d7d510231f
|
github.com/sagernet/sing v0.0.0-20220925112014-b12b8b7fd220
|
||||||
github.com/sagernet/sing-dns v0.0.0-20220915084601-812e0864b45b
|
github.com/sagernet/sing-dns v0.0.0-20220915084601-812e0864b45b
|
||||||
github.com/sagernet/sing-shadowsocks v0.0.0-20220819002358-7461bb09a8f6
|
github.com/sagernet/sing-shadowsocks v0.0.0-20220819002358-7461bb09a8f6
|
||||||
github.com/sagernet/sing-tun v0.0.0-20220922083325-80ee99472704
|
github.com/sagernet/sing-tun v0.0.0-20220925112147-6bad0c2380ca
|
||||||
github.com/sagernet/sing-vmess v0.0.0-20220921140858-b6a1bdee672f
|
github.com/sagernet/sing-vmess v0.0.0-20220925083655-063bc85ea685
|
||||||
github.com/sagernet/smux v0.0.0-20220831015742-e0f1988e3195
|
github.com/sagernet/smux v0.0.0-20220831015742-e0f1988e3195
|
||||||
github.com/sagernet/websocket v0.0.0-20220913015213-615516348b4e
|
github.com/sagernet/websocket v0.0.0-20220913015213-615516348b4e
|
||||||
github.com/spf13/cobra v1.5.0
|
github.com/spf13/cobra v1.5.0
|
||||||
github.com/stretchr/testify v1.8.0
|
github.com/stretchr/testify v1.8.0
|
||||||
go.etcd.io/bbolt v1.3.6
|
go.etcd.io/bbolt v1.3.6
|
||||||
go.uber.org/atomic v1.10.0
|
go.uber.org/atomic v1.10.0
|
||||||
go4.org/netipx v0.0.0-20220812043211-3cc044ffd68d
|
go4.org/netipx v0.0.0-20220925034521-797b0c90d8ab
|
||||||
golang.org/x/crypto v0.0.0-20220919173607-35f4265a4bc0
|
golang.org/x/crypto v0.0.0-20220924013350-4ba4fb4dd9e7
|
||||||
golang.org/x/net v0.0.0-20220909164309-bea034e7d591
|
golang.org/x/net v0.0.0-20220923203811-8be639271d50
|
||||||
golang.org/x/sys v0.0.0-20220913120320-3275c407cedc
|
golang.org/x/sys v0.0.0-20220919091848-fb04ddd9f9c8
|
||||||
golang.zx2c4.com/wireguard v0.0.0-20220829161405-d1d08426b27b
|
golang.zx2c4.com/wireguard v0.0.0-20220829161405-d1d08426b27b
|
||||||
google.golang.org/grpc v1.49.0
|
google.golang.org/grpc v1.49.0
|
||||||
google.golang.org/protobuf v1.28.1
|
google.golang.org/protobuf v1.28.1
|
||||||
|
|||||||
28
go.sum
28
go.sum
@@ -145,16 +145,16 @@ github.com/sagernet/quic-go v0.0.0-20220818150011-de611ab3e2bb h1:wc0yQ+SBn4TaTY
|
|||||||
github.com/sagernet/quic-go v0.0.0-20220818150011-de611ab3e2bb/go.mod h1:MIccjRKnPTjWwAOpl+AUGWOkzyTd9tERytudxu+1ra4=
|
github.com/sagernet/quic-go v0.0.0-20220818150011-de611ab3e2bb/go.mod h1:MIccjRKnPTjWwAOpl+AUGWOkzyTd9tERytudxu+1ra4=
|
||||||
github.com/sagernet/sing v0.0.0-20220812082120-05f9836bff8f/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY=
|
github.com/sagernet/sing v0.0.0-20220812082120-05f9836bff8f/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY=
|
||||||
github.com/sagernet/sing v0.0.0-20220817130738-ce854cda8522/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY=
|
github.com/sagernet/sing v0.0.0-20220817130738-ce854cda8522/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY=
|
||||||
github.com/sagernet/sing v0.0.0-20220921101604-86d7d510231f h1:GX416thAwyc0vHBOal/qplvdhFgYO2dHD5GqADCJ0Ig=
|
github.com/sagernet/sing v0.0.0-20220925112014-b12b8b7fd220 h1:fQk/BHOeHw5murjeNTdmkXmDy9cMlbubRINRH7GDuu4=
|
||||||
github.com/sagernet/sing v0.0.0-20220921101604-86d7d510231f/go.mod h1:x3NHUeJBQwV75L51zwmLKQdLtRvR+M4PmXkfQtU1vIY=
|
github.com/sagernet/sing v0.0.0-20220925112014-b12b8b7fd220/go.mod h1:5/u6RMDMoGIkSNtrZb41kJvyIFg3Ysn69P3WiAu8m0c=
|
||||||
github.com/sagernet/sing-dns v0.0.0-20220915084601-812e0864b45b h1:cXCMNJ9heZ+c6l+qUcku60x9KyXo4SOAaJfg/6spOmU=
|
github.com/sagernet/sing-dns v0.0.0-20220915084601-812e0864b45b h1:cXCMNJ9heZ+c6l+qUcku60x9KyXo4SOAaJfg/6spOmU=
|
||||||
github.com/sagernet/sing-dns v0.0.0-20220915084601-812e0864b45b/go.mod h1:SrvWLfOSlnFmH32CWXicfilAGgIXR0VjrH6yRbuXYww=
|
github.com/sagernet/sing-dns v0.0.0-20220915084601-812e0864b45b/go.mod h1:SrvWLfOSlnFmH32CWXicfilAGgIXR0VjrH6yRbuXYww=
|
||||||
github.com/sagernet/sing-shadowsocks v0.0.0-20220819002358-7461bb09a8f6 h1:JJfDeYYhWunvtxsU/mOVNTmFQmnzGx9dY034qG6G3g4=
|
github.com/sagernet/sing-shadowsocks v0.0.0-20220819002358-7461bb09a8f6 h1:JJfDeYYhWunvtxsU/mOVNTmFQmnzGx9dY034qG6G3g4=
|
||||||
github.com/sagernet/sing-shadowsocks v0.0.0-20220819002358-7461bb09a8f6/go.mod h1:EX3RbZvrwAkPI2nuGa78T2iQXmrkT+/VQtskjou42xM=
|
github.com/sagernet/sing-shadowsocks v0.0.0-20220819002358-7461bb09a8f6/go.mod h1:EX3RbZvrwAkPI2nuGa78T2iQXmrkT+/VQtskjou42xM=
|
||||||
github.com/sagernet/sing-tun v0.0.0-20220922083325-80ee99472704 h1:DOQQXQbB2gq4n2FuMHrL07HRs2naCCsuiu/9l1JFb9A=
|
github.com/sagernet/sing-tun v0.0.0-20220925112147-6bad0c2380ca h1:Owgx9izFNYyMyUZ61td+mL3vumBhJz4zNismYlCyQbw=
|
||||||
github.com/sagernet/sing-tun v0.0.0-20220922083325-80ee99472704/go.mod h1:5AhPUv9jWDQ3pv3Mj78SL/1TSjhoaj6WNASxRKLqXqM=
|
github.com/sagernet/sing-tun v0.0.0-20220925112147-6bad0c2380ca/go.mod h1:ftP5VXlp3RJO5+WS3mPFk7jB9B/K/QrPEZX3BUORGQY=
|
||||||
github.com/sagernet/sing-vmess v0.0.0-20220921140858-b6a1bdee672f h1:xyJ3Wbibcug4DxLi/FCHX2Td667SfieyZv645b8+eEE=
|
github.com/sagernet/sing-vmess v0.0.0-20220925083655-063bc85ea685 h1:AZzFNRR/ZwMTceUQ1b/mxx6oyKqmFymdMn/yleJmoVM=
|
||||||
github.com/sagernet/sing-vmess v0.0.0-20220921140858-b6a1bdee672f/go.mod h1:bwhAdSNET1X+j9DOXGj9NIQR39xgcWIk1rOQ9lLD+gM=
|
github.com/sagernet/sing-vmess v0.0.0-20220925083655-063bc85ea685/go.mod h1:bwhAdSNET1X+j9DOXGj9NIQR39xgcWIk1rOQ9lLD+gM=
|
||||||
github.com/sagernet/smux v0.0.0-20220831015742-e0f1988e3195 h1:5VBIbVw9q7aKbrFdT83mjkyvQ+VaRsQ6yflTepfln38=
|
github.com/sagernet/smux v0.0.0-20220831015742-e0f1988e3195 h1:5VBIbVw9q7aKbrFdT83mjkyvQ+VaRsQ6yflTepfln38=
|
||||||
github.com/sagernet/smux v0.0.0-20220831015742-e0f1988e3195/go.mod h1:yedWtra8nyGJ+SyI+ziwuaGMzBatbB10P1IOOZbbSK8=
|
github.com/sagernet/smux v0.0.0-20220831015742-e0f1988e3195/go.mod h1:yedWtra8nyGJ+SyI+ziwuaGMzBatbB10P1IOOZbbSK8=
|
||||||
github.com/sagernet/websocket v0.0.0-20220913015213-615516348b4e h1:7uw2njHFGE+VpWamge6o56j2RWk4omF6uLKKxMmcWvs=
|
github.com/sagernet/websocket v0.0.0-20220913015213-615516348b4e h1:7uw2njHFGE+VpWamge6o56j2RWk4omF6uLKKxMmcWvs=
|
||||||
@@ -188,16 +188,16 @@ go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9i
|
|||||||
go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw=
|
go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw=
|
||||||
go.uber.org/zap v1.22.0 h1:Zcye5DUgBloQ9BaT4qc9BnjOFog5TvBSAGkJ3Nf70c0=
|
go.uber.org/zap v1.22.0 h1:Zcye5DUgBloQ9BaT4qc9BnjOFog5TvBSAGkJ3Nf70c0=
|
||||||
go.uber.org/zap v1.22.0/go.mod h1:H4siCOZOrAolnUPJEkfaSjDqyP+BDS0DdDWzwcgt3+U=
|
go.uber.org/zap v1.22.0/go.mod h1:H4siCOZOrAolnUPJEkfaSjDqyP+BDS0DdDWzwcgt3+U=
|
||||||
go4.org/netipx v0.0.0-20220812043211-3cc044ffd68d h1:ggxwEf5eu0l8v+87VhX1czFh8zJul3hK16Gmruxn7hw=
|
go4.org/netipx v0.0.0-20220925034521-797b0c90d8ab h1:+yW1yrZ09EYNu1spCUOHBBNRbrLnfmutwyhbhCv3b6Q=
|
||||||
go4.org/netipx v0.0.0-20220812043211-3cc044ffd68d/go.mod h1:tgPU4N2u9RByaTN3NC2p9xOzyFpte4jYwsIIRF7XlSc=
|
go4.org/netipx v0.0.0-20220925034521-797b0c90d8ab/go.mod h1:tgPU4N2u9RByaTN3NC2p9xOzyFpte4jYwsIIRF7XlSc=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
golang.org/x/crypto v0.0.0-20190404164418-38d8ce5564a5/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
|
golang.org/x/crypto v0.0.0-20190404164418-38d8ce5564a5/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
|
||||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
|
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
|
||||||
golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
golang.org/x/crypto v0.0.0-20220919173607-35f4265a4bc0 h1:a5Yg6ylndHHYJqIPrdq0AhvR6KTvDTAvgBtaidhEevY=
|
golang.org/x/crypto v0.0.0-20220924013350-4ba4fb4dd9e7 h1:WJywXQVIb56P2kAvXeMGTIgQ1ZHQxR60+F9dLsodECc=
|
||||||
golang.org/x/crypto v0.0.0-20220919173607-35f4265a4bc0/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
golang.org/x/crypto v0.0.0-20220924013350-4ba4fb4dd9e7/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e h1:+WEEuIdZHnUeJJmEUjyYC2gfUMj69yZXw17EnHg/otA=
|
golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e h1:+WEEuIdZHnUeJJmEUjyYC2gfUMj69yZXw17EnHg/otA=
|
||||||
golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e/go.mod h1:Kr81I6Kryrl9sr8s2FK3vxD90NdsKWRuOIl2O4CvYbA=
|
golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e/go.mod h1:Kr81I6Kryrl9sr8s2FK3vxD90NdsKWRuOIl2O4CvYbA=
|
||||||
@@ -229,8 +229,8 @@ golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qx
|
|||||||
golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
golang.org/x/net v0.0.0-20211111160137-58aab5ef257a/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.0.0-20211111160137-58aab5ef257a/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
golang.org/x/net v0.0.0-20220630215102-69896b714898/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
golang.org/x/net v0.0.0-20220630215102-69896b714898/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||||
golang.org/x/net v0.0.0-20220909164309-bea034e7d591 h1:D0B/7al0LLrVC8aWF4+oxpv/m8bc7ViFfVS8/gXGdqI=
|
golang.org/x/net v0.0.0-20220923203811-8be639271d50 h1:vKyz8L3zkd+xrMeIaBsQ/MNVPVFSffdaU3ZyYlBGFnI=
|
||||||
golang.org/x/net v0.0.0-20220909164309-bea034e7d591/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
|
golang.org/x/net v0.0.0-20220923203811-8be639271d50/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
|
||||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
@@ -264,8 +264,8 @@ golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBc
|
|||||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220731174439-a90be440212d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220731174439-a90be440212d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220913120320-3275c407cedc h1:dpclq5m2YrqPGStKmtw7IcNbKLfbIqKXvNxDJKdIKYc=
|
golang.org/x/sys v0.0.0-20220919091848-fb04ddd9f9c8 h1:h+EGohizhe9XlX18rfpa8k8RAc5XyaeamM+0VHRd4lc=
|
||||||
golang.org/x/sys v0.0.0-20220913120320-3275c407cedc/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220919091848-fb04ddd9f9c8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
|
|||||||
@@ -141,13 +141,13 @@ func (a *myInboundAdapter) createMetadata(conn net.Conn, metadata adapter.Inboun
|
|||||||
metadata.SniffOverrideDestination = a.listenOptions.SniffOverrideDestination
|
metadata.SniffOverrideDestination = a.listenOptions.SniffOverrideDestination
|
||||||
metadata.DomainStrategy = dns.DomainStrategy(a.listenOptions.DomainStrategy)
|
metadata.DomainStrategy = dns.DomainStrategy(a.listenOptions.DomainStrategy)
|
||||||
if !metadata.Source.IsValid() {
|
if !metadata.Source.IsValid() {
|
||||||
metadata.Source = M.SocksaddrFromNet(conn.RemoteAddr())
|
metadata.Source = M.SocksaddrFromNet(conn.RemoteAddr()).Unwrap()
|
||||||
}
|
}
|
||||||
if !metadata.Destination.IsValid() {
|
if !metadata.Destination.IsValid() {
|
||||||
metadata.Destination = M.SocksaddrFromNet(conn.LocalAddr())
|
metadata.Destination = M.SocksaddrFromNet(conn.LocalAddr()).Unwrap()
|
||||||
}
|
}
|
||||||
if tcpConn, isTCP := common.Cast[*net.TCPConn](conn); isTCP {
|
if tcpConn, isTCP := common.Cast[*net.TCPConn](conn); isTCP {
|
||||||
metadata.OriginDestination = M.SocksaddrFromNet(tcpConn.LocalAddr())
|
metadata.OriginDestination = M.SocksaddrFromNet(tcpConn.LocalAddr()).Unwrap()
|
||||||
}
|
}
|
||||||
return metadata
|
return metadata
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ func (a *myInboundAdapter) loopUDPIn() {
|
|||||||
metadata.SniffEnabled = a.listenOptions.SniffEnabled
|
metadata.SniffEnabled = a.listenOptions.SniffEnabled
|
||||||
metadata.SniffOverrideDestination = a.listenOptions.SniffOverrideDestination
|
metadata.SniffOverrideDestination = a.listenOptions.SniffOverrideDestination
|
||||||
metadata.DomainStrategy = dns.DomainStrategy(a.listenOptions.DomainStrategy)
|
metadata.DomainStrategy = dns.DomainStrategy(a.listenOptions.DomainStrategy)
|
||||||
metadata.Source = M.SocksaddrFromNetIP(addr)
|
metadata.Source = M.SocksaddrFromNetIP(addr).Unwrap()
|
||||||
metadata.OriginDestination = a.udpAddr
|
metadata.OriginDestination = a.udpAddr
|
||||||
err = a.packetHandler.NewPacket(a.ctx, packetService, buffer, metadata)
|
err = a.packetHandler.NewPacket(a.ctx, packetService, buffer, metadata)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -86,7 +86,7 @@ func (a *myInboundAdapter) loopUDPOOBIn() {
|
|||||||
metadata.SniffEnabled = a.listenOptions.SniffEnabled
|
metadata.SniffEnabled = a.listenOptions.SniffEnabled
|
||||||
metadata.SniffOverrideDestination = a.listenOptions.SniffOverrideDestination
|
metadata.SniffOverrideDestination = a.listenOptions.SniffOverrideDestination
|
||||||
metadata.DomainStrategy = dns.DomainStrategy(a.listenOptions.DomainStrategy)
|
metadata.DomainStrategy = dns.DomainStrategy(a.listenOptions.DomainStrategy)
|
||||||
metadata.Source = M.SocksaddrFromNetIP(addr)
|
metadata.Source = M.SocksaddrFromNetIP(addr).Unwrap()
|
||||||
metadata.OriginDestination = a.udpAddr
|
metadata.OriginDestination = a.udpAddr
|
||||||
err = a.oobPacketHandler.NewPacket(a.ctx, packetService, buffer, oob[:oobN], metadata)
|
err = a.oobPacketHandler.NewPacket(a.ctx, packetService, buffer, oob[:oobN], metadata)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -112,7 +112,7 @@ func (a *myInboundAdapter) loopUDPInThreadSafe() {
|
|||||||
metadata.SniffEnabled = a.listenOptions.SniffEnabled
|
metadata.SniffEnabled = a.listenOptions.SniffEnabled
|
||||||
metadata.SniffOverrideDestination = a.listenOptions.SniffOverrideDestination
|
metadata.SniffOverrideDestination = a.listenOptions.SniffOverrideDestination
|
||||||
metadata.DomainStrategy = dns.DomainStrategy(a.listenOptions.DomainStrategy)
|
metadata.DomainStrategy = dns.DomainStrategy(a.listenOptions.DomainStrategy)
|
||||||
metadata.Source = M.SocksaddrFromNetIP(addr)
|
metadata.Source = M.SocksaddrFromNetIP(addr).Unwrap()
|
||||||
metadata.OriginDestination = a.udpAddr
|
metadata.OriginDestination = a.udpAddr
|
||||||
err = a.packetHandler.NewPacket(a.ctx, packetService, buffer, metadata)
|
err = a.packetHandler.NewPacket(a.ctx, packetService, buffer, metadata)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -140,7 +140,7 @@ func (a *myInboundAdapter) loopUDPOOBInThreadSafe() {
|
|||||||
metadata.SniffEnabled = a.listenOptions.SniffEnabled
|
metadata.SniffEnabled = a.listenOptions.SniffEnabled
|
||||||
metadata.SniffOverrideDestination = a.listenOptions.SniffOverrideDestination
|
metadata.SniffOverrideDestination = a.listenOptions.SniffOverrideDestination
|
||||||
metadata.DomainStrategy = dns.DomainStrategy(a.listenOptions.DomainStrategy)
|
metadata.DomainStrategy = dns.DomainStrategy(a.listenOptions.DomainStrategy)
|
||||||
metadata.Source = M.SocksaddrFromNetIP(addr)
|
metadata.Source = M.SocksaddrFromNetIP(addr).Unwrap()
|
||||||
metadata.OriginDestination = a.udpAddr
|
metadata.OriginDestination = a.udpAddr
|
||||||
err = a.oobPacketHandler.NewPacket(a.ctx, packetService, buffer, oob[:oobN], metadata)
|
err = a.oobPacketHandler.NewPacket(a.ctx, packetService, buffer, oob[:oobN], metadata)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -261,9 +261,9 @@ func (h *Hysteria) acceptStream(ctx context.Context, conn quic.Connection, strea
|
|||||||
metadata.SniffEnabled = h.listenOptions.SniffEnabled
|
metadata.SniffEnabled = h.listenOptions.SniffEnabled
|
||||||
metadata.SniffOverrideDestination = h.listenOptions.SniffOverrideDestination
|
metadata.SniffOverrideDestination = h.listenOptions.SniffOverrideDestination
|
||||||
metadata.DomainStrategy = dns.DomainStrategy(h.listenOptions.DomainStrategy)
|
metadata.DomainStrategy = dns.DomainStrategy(h.listenOptions.DomainStrategy)
|
||||||
metadata.Source = M.SocksaddrFromNet(conn.RemoteAddr())
|
metadata.Source = M.SocksaddrFromNet(conn.RemoteAddr()).Unwrap()
|
||||||
metadata.OriginDestination = M.SocksaddrFromNet(conn.LocalAddr())
|
metadata.OriginDestination = M.SocksaddrFromNet(conn.LocalAddr()).Unwrap()
|
||||||
metadata.Destination = M.ParseSocksaddrHostPort(request.Host, request.Port)
|
metadata.Destination = M.ParseSocksaddrHostPort(request.Host, request.Port).Unwrap()
|
||||||
|
|
||||||
if !request.UDP {
|
if !request.UDP {
|
||||||
err = hysteria.WriteServerResponse(stream, hysteria.ServerResponse{
|
err = hysteria.WriteServerResponse(stream, hysteria.ServerResponse{
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ func (t *TProxy) Start() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (t *TProxy) NewConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error {
|
func (t *TProxy) NewConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error {
|
||||||
metadata.Destination = M.SocksaddrFromNet(conn.LocalAddr())
|
metadata.Destination = M.SocksaddrFromNet(conn.LocalAddr()).Unwrap()
|
||||||
return t.newConnection(ctx, conn, metadata)
|
return t.newConnection(ctx, conn, metadata)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -84,14 +84,15 @@ func (t *TProxy) NewPacket(ctx context.Context, conn N.PacketConn, buffer *buf.B
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return E.Cause(err, "get tproxy destination")
|
return E.Cause(err, "get tproxy destination")
|
||||||
}
|
}
|
||||||
metadata.Destination = M.SocksaddrFromNetIP(destination)
|
metadata.Destination = M.SocksaddrFromNetIP(destination).Unwrap()
|
||||||
t.udpNat.NewContextPacket(ctx, metadata.Source.AddrPort(), buffer, adapter.UpstreamMetadata(metadata), func(natConn N.PacketConn) (context.Context, N.PacketWriter) {
|
t.udpNat.NewContextPacket(ctx, metadata.Source.AddrPort(), buffer, adapter.UpstreamMetadata(metadata), func(natConn N.PacketConn) (context.Context, N.PacketWriter) {
|
||||||
return adapter.WithContext(log.ContextWithNewID(ctx), &metadata), &tproxyPacketWriter{source: natConn}
|
return adapter.WithContext(log.ContextWithNewID(ctx), &metadata), &tproxyPacketWriter{ctx: ctx, source: natConn, destination: metadata.Destination}
|
||||||
})
|
})
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type tproxyPacketWriter struct {
|
type tproxyPacketWriter struct {
|
||||||
|
ctx context.Context
|
||||||
source N.PacketConn
|
source N.PacketConn
|
||||||
destination M.Socksaddr
|
destination M.Socksaddr
|
||||||
conn *net.UDPConn
|
conn *net.UDPConn
|
||||||
@@ -99,25 +100,27 @@ type tproxyPacketWriter struct {
|
|||||||
|
|
||||||
func (w *tproxyPacketWriter) WritePacket(buffer *buf.Buffer, destination M.Socksaddr) error {
|
func (w *tproxyPacketWriter) WritePacket(buffer *buf.Buffer, destination M.Socksaddr) error {
|
||||||
defer buffer.Release()
|
defer buffer.Release()
|
||||||
var udpConn *net.UDPConn
|
if w.destination == destination && w.conn != nil {
|
||||||
|
_, err := w.conn.WriteToUDPAddrPort(buffer.Bytes(), M.AddrPortFromNet(w.source.LocalAddr()))
|
||||||
|
if err == nil {
|
||||||
|
w.conn = nil
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
var listener net.ListenConfig
|
||||||
|
listener.Control = control.Append(listener.Control, control.ReuseAddr())
|
||||||
|
listener.Control = control.Append(listener.Control, redir.TProxyWriteBack())
|
||||||
|
packetConn, err := listener.ListenPacket(w.ctx, "udp", destination.String())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
udpConn := packetConn.(*net.UDPConn)
|
||||||
if w.destination == destination {
|
if w.destination == destination {
|
||||||
if w.conn != nil {
|
w.conn = udpConn
|
||||||
udpConn = w.conn
|
} else {
|
||||||
}
|
defer udpConn.Close()
|
||||||
}
|
}
|
||||||
if udpConn == nil {
|
return common.Error(udpConn.WriteToUDPAddrPort(buffer.Bytes(), M.AddrPortFromNet(w.source.LocalAddr())))
|
||||||
var err error
|
|
||||||
udpConn, err = redir.DialUDP(destination.UDPAddr(), M.SocksaddrFromNet(w.source.LocalAddr()).UDPAddr())
|
|
||||||
if err != nil {
|
|
||||||
return E.Cause(err, "tproxy udp write back")
|
|
||||||
}
|
|
||||||
if w.destination == destination {
|
|
||||||
w.conn = udpConn
|
|
||||||
} else {
|
|
||||||
defer udpConn.Close()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return common.Error(udpConn.Write(buffer.Bytes()))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *tproxyPacketWriter) Close() error {
|
func (w *tproxyPacketWriter) Close() error {
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package option
|
|||||||
type InboundTLSOptions struct {
|
type InboundTLSOptions struct {
|
||||||
Enabled bool `json:"enabled,omitempty"`
|
Enabled bool `json:"enabled,omitempty"`
|
||||||
ServerName string `json:"server_name,omitempty"`
|
ServerName string `json:"server_name,omitempty"`
|
||||||
|
Insecure bool `json:"insecure,omitempty"`
|
||||||
ALPN Listable[string] `json:"alpn,omitempty"`
|
ALPN Listable[string] `json:"alpn,omitempty"`
|
||||||
MinVersion string `json:"min_version,omitempty"`
|
MinVersion string `json:"min_version,omitempty"`
|
||||||
MaxVersion string `json:"max_version,omitempty"`
|
MaxVersion string `json:"max_version,omitempty"`
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ type Hysteria struct {
|
|||||||
recvBPS uint64
|
recvBPS uint64
|
||||||
connAccess sync.Mutex
|
connAccess sync.Mutex
|
||||||
conn quic.Connection
|
conn quic.Connection
|
||||||
|
rawConn net.Conn
|
||||||
udpAccess sync.RWMutex
|
udpAccess sync.RWMutex
|
||||||
udpSessions map[uint32]chan *hysteria.UDPMessage
|
udpSessions map[uint32]chan *hysteria.UDPMessage
|
||||||
udpDefragger hysteria.Defragger
|
udpDefragger hysteria.Defragger
|
||||||
@@ -149,7 +150,6 @@ func (h *Hysteria) offer(ctx context.Context) (quic.Connection, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
h.conn = conn
|
|
||||||
if common.Contains(h.network, N.NetworkUDP) {
|
if common.Contains(h.network, N.NetworkUDP) {
|
||||||
for _, session := range h.udpSessions {
|
for _, session := range h.udpSessions {
|
||||||
close(session)
|
close(session)
|
||||||
@@ -201,6 +201,8 @@ func (h *Hysteria) offerNew(ctx context.Context) (quic.Connection, error) {
|
|||||||
return nil, E.New("remote error: ", serverHello.Message)
|
return nil, E.New("remote error: ", serverHello.Message)
|
||||||
}
|
}
|
||||||
quicConn.SetCongestionControl(hysteria.NewBrutalSender(congestion.ByteCount(serverHello.RecvBPS)))
|
quicConn.SetCongestionControl(hysteria.NewBrutalSender(congestion.ByteCount(serverHello.RecvBPS)))
|
||||||
|
h.conn = quicConn
|
||||||
|
h.rawConn = udpConn
|
||||||
return quicConn, nil
|
return quicConn, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -240,6 +242,7 @@ func (h *Hysteria) Close() error {
|
|||||||
defer h.udpAccess.Unlock()
|
defer h.udpAccess.Unlock()
|
||||||
if h.conn != nil {
|
if h.conn != nil {
|
||||||
h.conn.CloseWithError(0, "")
|
h.conn.CloseWithError(0, "")
|
||||||
|
h.rawConn.Close()
|
||||||
}
|
}
|
||||||
for _, session := range h.udpSessions {
|
for _, session := range h.udpSessions {
|
||||||
close(session)
|
close(session)
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ func (h *Socks) DialContext(ctx context.Context, network string, destination M.S
|
|||||||
default:
|
default:
|
||||||
return nil, E.Extend(N.ErrUnknownNetwork, network)
|
return nil, E.Extend(N.ErrUnknownNetwork, network)
|
||||||
}
|
}
|
||||||
if destination.IsFqdn() {
|
if h.resolve && destination.IsFqdn() {
|
||||||
addrs, err := h.router.LookupDefault(ctx, destination.Fqdn)
|
addrs, err := h.router.LookupDefault(ctx, destination.Fqdn)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|||||||
@@ -103,6 +103,10 @@ func (h *Trojan) NewPacketConnection(ctx context.Context, conn N.PacketConn, met
|
|||||||
return NewPacketConnection(ctx, h, conn, metadata)
|
return NewPacketConnection(ctx, h, conn, metadata)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (h *Trojan) Close() error {
|
||||||
|
return common.Close(h.multiplexDialer, h.transport)
|
||||||
|
}
|
||||||
|
|
||||||
type trojanDialer Trojan
|
type trojanDialer Trojan
|
||||||
|
|
||||||
func (h *trojanDialer) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
|
func (h *trojanDialer) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
|
||||||
|
|||||||
@@ -74,10 +74,6 @@ func NewVLESS(ctx context.Context, router adapter.Router, logger log.ContextLogg
|
|||||||
return outbound, nil
|
return outbound, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *VLESS) Close() error {
|
|
||||||
return common.Close(h.transport)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *VLESS) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
|
func (h *VLESS) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
|
||||||
ctx, metadata := adapter.AppendContext(ctx)
|
ctx, metadata := adapter.AppendContext(ctx)
|
||||||
metadata.Outbound = h.tag
|
metadata.Outbound = h.tag
|
||||||
@@ -145,3 +141,7 @@ func (h *VLESS) NewConnection(ctx context.Context, conn net.Conn, metadata adapt
|
|||||||
func (h *VLESS) NewPacketConnection(ctx context.Context, conn N.PacketConn, metadata adapter.InboundContext) error {
|
func (h *VLESS) NewPacketConnection(ctx context.Context, conn N.PacketConn, metadata adapter.InboundContext) error {
|
||||||
return NewPacketConnection(ctx, h, conn, metadata)
|
return NewPacketConnection(ctx, h, conn, metadata)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (h *VLESS) Close() error {
|
||||||
|
return common.Close(h.transport)
|
||||||
|
}
|
||||||
|
|||||||
@@ -96,7 +96,7 @@ func NewVMess(ctx context.Context, router adapter.Router, logger log.ContextLogg
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (h *VMess) Close() error {
|
func (h *VMess) Close() error {
|
||||||
return common.Close(h.transport)
|
return common.Close(h.multiplexDialer, h.transport)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *VMess) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
|
func (h *VMess) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
|
||||||
|
|||||||
@@ -162,9 +162,8 @@ func (w *WireGuard) Start() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (w *WireGuard) Close() error {
|
func (w *WireGuard) Close() error {
|
||||||
return common.Close(
|
if w.device != nil {
|
||||||
w.tunDevice,
|
w.device.Close()
|
||||||
common.PtrOrNil(w.device),
|
}
|
||||||
common.PtrOrNil(w.bind),
|
return common.Close(w.tunDevice)
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -59,13 +59,13 @@ func NewIPCIDRItem(isSource bool, prefixStrings []string) (*IPCIDRItem, error) {
|
|||||||
|
|
||||||
func (r *IPCIDRItem) Match(metadata *adapter.InboundContext) bool {
|
func (r *IPCIDRItem) Match(metadata *adapter.InboundContext) bool {
|
||||||
if r.isSource {
|
if r.isSource {
|
||||||
return r.match(metadata.Source.Addr)
|
return r.ipSet.Contains(metadata.Source.Addr)
|
||||||
} else {
|
} else {
|
||||||
if metadata.Destination.IsIP() {
|
if metadata.Destination.IsIP() {
|
||||||
return r.match(metadata.Destination.Addr)
|
return r.ipSet.Contains(metadata.Destination.Addr)
|
||||||
} else {
|
} else {
|
||||||
for _, address := range metadata.DestinationAddresses {
|
for _, address := range metadata.DestinationAddresses {
|
||||||
if r.match(address) {
|
if r.ipSet.Contains(address) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -74,14 +74,6 @@ func (r *IPCIDRItem) Match(metadata *adapter.InboundContext) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *IPCIDRItem) match(address netip.Addr) bool {
|
|
||||||
if address.Is4In6() {
|
|
||||||
return r.ipSet.Contains(netip.AddrFrom4(address.As4()))
|
|
||||||
} else {
|
|
||||||
return r.ipSet.Contains(address)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *IPCIDRItem) String() string {
|
func (r *IPCIDRItem) String() string {
|
||||||
return r.description
|
return r.description
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,9 +15,14 @@ import (
|
|||||||
"github.com/sagernet/sing/protocol/socks"
|
"github.com/sagernet/sing/protocol/socks"
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
"go.uber.org/goleak"
|
||||||
)
|
)
|
||||||
|
|
||||||
func startInstance(t *testing.T, options option.Options) {
|
func TestMain(m *testing.M) {
|
||||||
|
goleak.VerifyTestMain(m)
|
||||||
|
}
|
||||||
|
|
||||||
|
func startInstance(t *testing.T, options option.Options) *box.Box {
|
||||||
if debug.Enabled {
|
if debug.Enabled {
|
||||||
options.Log = &option.LogOptions{
|
options.Log = &option.LogOptions{
|
||||||
Level: "trace",
|
Level: "trace",
|
||||||
@@ -27,10 +32,12 @@ func startInstance(t *testing.T, options option.Options) {
|
|||||||
Level: "warning",
|
Level: "warning",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// ctx := context.Background()
|
||||||
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
var instance *box.Box
|
var instance *box.Box
|
||||||
var err error
|
var err error
|
||||||
for retry := 0; retry < 3; retry++ {
|
for retry := 0; retry < 3; retry++ {
|
||||||
instance, err = box.New(context.Background(), options)
|
instance, err = box.New(ctx, options)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
err = instance.Start()
|
err = instance.Start()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -42,7 +49,9 @@ func startInstance(t *testing.T, options option.Options) {
|
|||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
t.Cleanup(func() {
|
t.Cleanup(func() {
|
||||||
instance.Close()
|
instance.Close()
|
||||||
|
cancel()
|
||||||
})
|
})
|
||||||
|
return instance
|
||||||
}
|
}
|
||||||
|
|
||||||
func testSuit(t *testing.T, clientPort uint16, testPort uint16) {
|
func testSuit(t *testing.T, clientPort uint16, testPort uint16) {
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
|
||||||
_ "net/http/pprof"
|
_ "net/http/pprof"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
"sync"
|
"sync"
|
||||||
@@ -39,6 +38,7 @@ const (
|
|||||||
ImageShadowTLS = "ghcr.io/ihciah/shadow-tls:latest"
|
ImageShadowTLS = "ghcr.io/ihciah/shadow-tls:latest"
|
||||||
ImageShadowsocksR = "teddysun/shadowsocks-r:latest"
|
ImageShadowsocksR = "teddysun/shadowsocks-r:latest"
|
||||||
ImageXRayCore = "teddysun/xray:latest"
|
ImageXRayCore = "teddysun/xray:latest"
|
||||||
|
ImageShadowsocksLegacy = "mritd/shadowsocks:latest"
|
||||||
)
|
)
|
||||||
|
|
||||||
var allImages = []string{
|
var allImages = []string{
|
||||||
@@ -53,6 +53,7 @@ var allImages = []string{
|
|||||||
ImageShadowTLS,
|
ImageShadowTLS,
|
||||||
ImageShadowsocksR,
|
ImageShadowsocksR,
|
||||||
ImageXRayCore,
|
ImageXRayCore,
|
||||||
|
ImageShadowsocksLegacy,
|
||||||
}
|
}
|
||||||
|
|
||||||
var localIP = netip.MustParseAddr("127.0.0.1")
|
var localIP = netip.MustParseAddr("127.0.0.1")
|
||||||
@@ -101,12 +102,6 @@ func init() {
|
|||||||
|
|
||||||
io.Copy(io.Discard, imageStream)
|
io.Copy(io.Discard, imageStream)
|
||||||
}
|
}
|
||||||
go func() {
|
|
||||||
err = http.ListenAndServe("0.0.0.0:8965", nil)
|
|
||||||
if err != nil {
|
|
||||||
log.Debug(err)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func newPingPongPair() (chan []byte, chan []byte, func(t *testing.T) error) {
|
func newPingPongPair() (chan []byte, chan []byte, func(t *testing.T) error) {
|
||||||
|
|||||||
@@ -10,10 +10,11 @@ require (
|
|||||||
github.com/docker/docker v20.10.18+incompatible
|
github.com/docker/docker v20.10.18+incompatible
|
||||||
github.com/docker/go-connections v0.4.0
|
github.com/docker/go-connections v0.4.0
|
||||||
github.com/gofrs/uuid v4.3.0+incompatible
|
github.com/gofrs/uuid v4.3.0+incompatible
|
||||||
github.com/sagernet/sing v0.0.0-20220916071326-834794b006ea
|
github.com/sagernet/sing v0.0.0-20220921101604-86d7d510231f
|
||||||
github.com/sagernet/sing-shadowsocks v0.0.0-20220819002358-7461bb09a8f6
|
github.com/sagernet/sing-shadowsocks v0.0.0-20220819002358-7461bb09a8f6
|
||||||
github.com/spyzhov/ajson v0.7.1
|
github.com/spyzhov/ajson v0.7.1
|
||||||
github.com/stretchr/testify v1.8.0
|
github.com/stretchr/testify v1.8.0
|
||||||
|
go.uber.org/goleak v1.2.0
|
||||||
golang.org/x/net v0.0.0-20220909164309-bea034e7d591
|
golang.org/x/net v0.0.0-20220909164309-bea034e7d591
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -67,8 +68,8 @@ require (
|
|||||||
github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 // indirect
|
github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 // indirect
|
||||||
github.com/sagernet/quic-go v0.0.0-20220818150011-de611ab3e2bb // indirect
|
github.com/sagernet/quic-go v0.0.0-20220818150011-de611ab3e2bb // indirect
|
||||||
github.com/sagernet/sing-dns v0.0.0-20220915084601-812e0864b45b // indirect
|
github.com/sagernet/sing-dns v0.0.0-20220915084601-812e0864b45b // indirect
|
||||||
github.com/sagernet/sing-tun v0.0.0-20220916073459-0032242c9617 // indirect
|
github.com/sagernet/sing-tun v0.0.0-20220922083325-80ee99472704 // indirect
|
||||||
github.com/sagernet/sing-vmess v0.0.0-20220917033734-9b634758039d // indirect
|
github.com/sagernet/sing-vmess v0.0.0-20220923035311-d70afe4ab2c9 // indirect
|
||||||
github.com/sagernet/smux v0.0.0-20220831015742-e0f1988e3195 // indirect
|
github.com/sagernet/smux v0.0.0-20220831015742-e0f1988e3195 // indirect
|
||||||
github.com/sagernet/websocket v0.0.0-20220913015213-615516348b4e // indirect
|
github.com/sagernet/websocket v0.0.0-20220913015213-615516348b4e // indirect
|
||||||
github.com/sirupsen/logrus v1.9.0 // indirect
|
github.com/sirupsen/logrus v1.9.0 // indirect
|
||||||
@@ -78,7 +79,7 @@ require (
|
|||||||
go.uber.org/multierr v1.6.0 // indirect
|
go.uber.org/multierr v1.6.0 // indirect
|
||||||
go.uber.org/zap v1.22.0 // indirect
|
go.uber.org/zap v1.22.0 // indirect
|
||||||
go4.org/netipx v0.0.0-20220812043211-3cc044ffd68d // indirect
|
go4.org/netipx v0.0.0-20220812043211-3cc044ffd68d // indirect
|
||||||
golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90 // indirect
|
golang.org/x/crypto v0.0.0-20220919173607-35f4265a4bc0 // indirect
|
||||||
golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e // indirect
|
golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e // indirect
|
||||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect
|
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect
|
||||||
golang.org/x/sys v0.0.0-20220913120320-3275c407cedc // indirect
|
golang.org/x/sys v0.0.0-20220913120320-3275c407cedc // indirect
|
||||||
|
|||||||
20
test/go.sum
20
test/go.sum
@@ -165,16 +165,16 @@ github.com/sagernet/quic-go v0.0.0-20220818150011-de611ab3e2bb h1:wc0yQ+SBn4TaTY
|
|||||||
github.com/sagernet/quic-go v0.0.0-20220818150011-de611ab3e2bb/go.mod h1:MIccjRKnPTjWwAOpl+AUGWOkzyTd9tERytudxu+1ra4=
|
github.com/sagernet/quic-go v0.0.0-20220818150011-de611ab3e2bb/go.mod h1:MIccjRKnPTjWwAOpl+AUGWOkzyTd9tERytudxu+1ra4=
|
||||||
github.com/sagernet/sing v0.0.0-20220812082120-05f9836bff8f/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY=
|
github.com/sagernet/sing v0.0.0-20220812082120-05f9836bff8f/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY=
|
||||||
github.com/sagernet/sing v0.0.0-20220817130738-ce854cda8522/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY=
|
github.com/sagernet/sing v0.0.0-20220817130738-ce854cda8522/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY=
|
||||||
github.com/sagernet/sing v0.0.0-20220916071326-834794b006ea h1:ZAWvZdeByPBBz3Vs+w3Erbh+DDo7D4biokoPhXl0nNU=
|
github.com/sagernet/sing v0.0.0-20220921101604-86d7d510231f h1:GX416thAwyc0vHBOal/qplvdhFgYO2dHD5GqADCJ0Ig=
|
||||||
github.com/sagernet/sing v0.0.0-20220916071326-834794b006ea/go.mod h1:x3NHUeJBQwV75L51zwmLKQdLtRvR+M4PmXkfQtU1vIY=
|
github.com/sagernet/sing v0.0.0-20220921101604-86d7d510231f/go.mod h1:x3NHUeJBQwV75L51zwmLKQdLtRvR+M4PmXkfQtU1vIY=
|
||||||
github.com/sagernet/sing-dns v0.0.0-20220915084601-812e0864b45b h1:cXCMNJ9heZ+c6l+qUcku60x9KyXo4SOAaJfg/6spOmU=
|
github.com/sagernet/sing-dns v0.0.0-20220915084601-812e0864b45b h1:cXCMNJ9heZ+c6l+qUcku60x9KyXo4SOAaJfg/6spOmU=
|
||||||
github.com/sagernet/sing-dns v0.0.0-20220915084601-812e0864b45b/go.mod h1:SrvWLfOSlnFmH32CWXicfilAGgIXR0VjrH6yRbuXYww=
|
github.com/sagernet/sing-dns v0.0.0-20220915084601-812e0864b45b/go.mod h1:SrvWLfOSlnFmH32CWXicfilAGgIXR0VjrH6yRbuXYww=
|
||||||
github.com/sagernet/sing-shadowsocks v0.0.0-20220819002358-7461bb09a8f6 h1:JJfDeYYhWunvtxsU/mOVNTmFQmnzGx9dY034qG6G3g4=
|
github.com/sagernet/sing-shadowsocks v0.0.0-20220819002358-7461bb09a8f6 h1:JJfDeYYhWunvtxsU/mOVNTmFQmnzGx9dY034qG6G3g4=
|
||||||
github.com/sagernet/sing-shadowsocks v0.0.0-20220819002358-7461bb09a8f6/go.mod h1:EX3RbZvrwAkPI2nuGa78T2iQXmrkT+/VQtskjou42xM=
|
github.com/sagernet/sing-shadowsocks v0.0.0-20220819002358-7461bb09a8f6/go.mod h1:EX3RbZvrwAkPI2nuGa78T2iQXmrkT+/VQtskjou42xM=
|
||||||
github.com/sagernet/sing-tun v0.0.0-20220916073459-0032242c9617 h1:fNTNmylhB/UjoBLusmrFu2B1fat4OCkDkQXTgrE7ZsE=
|
github.com/sagernet/sing-tun v0.0.0-20220922083325-80ee99472704 h1:DOQQXQbB2gq4n2FuMHrL07HRs2naCCsuiu/9l1JFb9A=
|
||||||
github.com/sagernet/sing-tun v0.0.0-20220916073459-0032242c9617/go.mod h1:5AhPUv9jWDQ3pv3Mj78SL/1TSjhoaj6WNASxRKLqXqM=
|
github.com/sagernet/sing-tun v0.0.0-20220922083325-80ee99472704/go.mod h1:5AhPUv9jWDQ3pv3Mj78SL/1TSjhoaj6WNASxRKLqXqM=
|
||||||
github.com/sagernet/sing-vmess v0.0.0-20220917033734-9b634758039d h1:/GNWxSrQj4chFYk2jahIXNPdvUa9DW8IdgyqYFbq9oQ=
|
github.com/sagernet/sing-vmess v0.0.0-20220923035311-d70afe4ab2c9 h1:w7JlEa4xHXuuPTL3Opb+Z5f/l66SYi54rSfobzuxSF8=
|
||||||
github.com/sagernet/sing-vmess v0.0.0-20220917033734-9b634758039d/go.mod h1:u66Vv7NHXJWfeAmhh7JuJp/cwxmuQlM56QoZ7B7Mmd0=
|
github.com/sagernet/sing-vmess v0.0.0-20220923035311-d70afe4ab2c9/go.mod h1:bwhAdSNET1X+j9DOXGj9NIQR39xgcWIk1rOQ9lLD+gM=
|
||||||
github.com/sagernet/smux v0.0.0-20220831015742-e0f1988e3195 h1:5VBIbVw9q7aKbrFdT83mjkyvQ+VaRsQ6yflTepfln38=
|
github.com/sagernet/smux v0.0.0-20220831015742-e0f1988e3195 h1:5VBIbVw9q7aKbrFdT83mjkyvQ+VaRsQ6yflTepfln38=
|
||||||
github.com/sagernet/smux v0.0.0-20220831015742-e0f1988e3195/go.mod h1:yedWtra8nyGJ+SyI+ziwuaGMzBatbB10P1IOOZbbSK8=
|
github.com/sagernet/smux v0.0.0-20220831015742-e0f1988e3195/go.mod h1:yedWtra8nyGJ+SyI+ziwuaGMzBatbB10P1IOOZbbSK8=
|
||||||
github.com/sagernet/websocket v0.0.0-20220913015213-615516348b4e h1:7uw2njHFGE+VpWamge6o56j2RWk4omF6uLKKxMmcWvs=
|
github.com/sagernet/websocket v0.0.0-20220913015213-615516348b4e h1:7uw2njHFGE+VpWamge6o56j2RWk4omF6uLKKxMmcWvs=
|
||||||
@@ -205,8 +205,9 @@ go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqe
|
|||||||
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||||
go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ=
|
go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ=
|
||||||
go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
|
go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
|
||||||
go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI=
|
|
||||||
go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
|
go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
|
||||||
|
go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk=
|
||||||
|
go.uber.org/goleak v1.2.0/go.mod h1:XJYK+MuIchqpmGmUSAzotztawfKvYLUIgg7guXrwVUo=
|
||||||
go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4=
|
go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4=
|
||||||
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
|
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
|
||||||
go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw=
|
go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw=
|
||||||
@@ -220,8 +221,8 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U
|
|||||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
|
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
|
||||||
golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90 h1:Y/gsMcFOcR+6S6f3YeMKl5g+dZMEWqcz5Czj/GWYbkM=
|
golang.org/x/crypto v0.0.0-20220919173607-35f4265a4bc0 h1:a5Yg6ylndHHYJqIPrdq0AhvR6KTvDTAvgBtaidhEevY=
|
||||||
golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
golang.org/x/crypto v0.0.0-20220919173607-35f4265a4bc0/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e h1:+WEEuIdZHnUeJJmEUjyYC2gfUMj69yZXw17EnHg/otA=
|
golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e h1:+WEEuIdZHnUeJJmEUjyYC2gfUMj69yZXw17EnHg/otA=
|
||||||
golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e/go.mod h1:Kr81I6Kryrl9sr8s2FK3vxD90NdsKWRuOIl2O4CvYbA=
|
golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e/go.mod h1:Kr81I6Kryrl9sr8s2FK3vxD90NdsKWRuOIl2O4CvYbA=
|
||||||
@@ -229,6 +230,7 @@ golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTk
|
|||||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||||
|
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 h1:VLliZ0d+/avPrXXH+OakdXhpJuEoBZuwh1m2j7U6Iug=
|
||||||
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
|
|||||||
@@ -107,3 +107,64 @@ func TestMuxCoolClient(t *testing.T) {
|
|||||||
})
|
})
|
||||||
testSuit(t, clientPort, testPort)
|
testSuit(t, clientPort, testPort)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestMuxCoolSelf(t *testing.T) {
|
||||||
|
user := newUUID()
|
||||||
|
startInstance(t, option.Options{
|
||||||
|
Inbounds: []option.Inbound{
|
||||||
|
{
|
||||||
|
Type: C.TypeMixed,
|
||||||
|
Tag: "mixed-in",
|
||||||
|
MixedOptions: option.HTTPMixedInboundOptions{
|
||||||
|
ListenOptions: option.ListenOptions{
|
||||||
|
Listen: option.ListenAddress(netip.IPv4Unspecified()),
|
||||||
|
ListenPort: clientPort,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Type: C.TypeVMess,
|
||||||
|
VMessOptions: option.VMessInboundOptions{
|
||||||
|
ListenOptions: option.ListenOptions{
|
||||||
|
Listen: option.ListenAddress(netip.IPv4Unspecified()),
|
||||||
|
ListenPort: serverPort,
|
||||||
|
},
|
||||||
|
Users: []option.VMessUser{
|
||||||
|
{
|
||||||
|
Name: "sekai",
|
||||||
|
UUID: user.String(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Outbounds: []option.Outbound{
|
||||||
|
{
|
||||||
|
Type: C.TypeDirect,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Type: C.TypeVMess,
|
||||||
|
Tag: "vmess-out",
|
||||||
|
VMessOptions: option.VMessOutboundOptions{
|
||||||
|
ServerOptions: option.ServerOptions{
|
||||||
|
Server: "127.0.0.1",
|
||||||
|
ServerPort: serverPort,
|
||||||
|
},
|
||||||
|
UUID: user.String(),
|
||||||
|
PacketEncoding: "xudp",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Route: &option.RouteOptions{
|
||||||
|
Rules: []option.Rule{
|
||||||
|
{
|
||||||
|
DefaultOptions: option.DefaultRule{
|
||||||
|
Inbound: []string{"mixed-in"},
|
||||||
|
Outbound: "vmess-out",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
testSuit(t, clientPort, testPort)
|
||||||
|
}
|
||||||
|
|||||||
@@ -17,6 +17,10 @@ var muxProtocols = []mux.Protocol{
|
|||||||
mux.ProtocolSMux,
|
mux.ProtocolSMux,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestVMessSMux(t *testing.T) {
|
||||||
|
testVMessMux(t, mux.ProtocolSMux.String())
|
||||||
|
}
|
||||||
|
|
||||||
func TestShadowsocksMux(t *testing.T) {
|
func TestShadowsocksMux(t *testing.T) {
|
||||||
for _, protocol := range muxProtocols {
|
for _, protocol := range muxProtocols {
|
||||||
t.Run(protocol.String(), func(t *testing.T) {
|
t.Run(protocol.String(), func(t *testing.T) {
|
||||||
@@ -25,14 +29,6 @@ func TestShadowsocksMux(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestVMessMux(t *testing.T) {
|
|
||||||
for _, protocol := range muxProtocols {
|
|
||||||
t.Run(protocol.String(), func(t *testing.T) {
|
|
||||||
testVMessMux(t, protocol.String())
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func testShadowsocksMux(t *testing.T, protocol string) {
|
func testShadowsocksMux(t *testing.T, protocol string) {
|
||||||
method := shadowaead_2022.List[0]
|
method := shadowaead_2022.List[0]
|
||||||
password := mkBase64(t, 16)
|
password := mkBase64(t, 16)
|
||||||
|
|||||||
63
test/ss_plugin_test.go
Normal file
63
test/ss_plugin_test.go
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/netip"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
C "github.com/sagernet/sing-box/constant"
|
||||||
|
"github.com/sagernet/sing-box/option"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestShadowsocksObfs(t *testing.T) {
|
||||||
|
for _, mode := range []string{
|
||||||
|
"http", "tls",
|
||||||
|
} {
|
||||||
|
t.Run("obfs-local "+mode, func(t *testing.T) {
|
||||||
|
testShadowsocksPlugin(t, "obfs-local", "obfs="+mode, "--plugin obfs-server --plugin-opts obfs="+mode)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestShadowsocksV2RayPlugin(t *testing.T) {
|
||||||
|
testShadowsocksPlugin(t, "v2ray-plugin", "", "--plugin v2ray-plugin --plugin-opts=server")
|
||||||
|
}
|
||||||
|
|
||||||
|
func testShadowsocksPlugin(t *testing.T, name string, opts string, args string) {
|
||||||
|
startDockerContainer(t, DockerOptions{
|
||||||
|
Image: ImageShadowsocksLegacy,
|
||||||
|
Ports: []uint16{serverPort, testPort},
|
||||||
|
Env: []string{
|
||||||
|
"SS_MODULE=ss-server",
|
||||||
|
"SS_CONFIG=-s 0.0.0.0 -u -p 10000 -m chacha20-ietf-poly1305 -k FzcLbKs2dY9mhL " + args,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
startInstance(t, option.Options{
|
||||||
|
Inbounds: []option.Inbound{
|
||||||
|
{
|
||||||
|
Type: C.TypeMixed,
|
||||||
|
MixedOptions: option.HTTPMixedInboundOptions{
|
||||||
|
ListenOptions: option.ListenOptions{
|
||||||
|
Listen: option.ListenAddress(netip.IPv4Unspecified()),
|
||||||
|
ListenPort: clientPort,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Outbounds: []option.Outbound{
|
||||||
|
{
|
||||||
|
Type: C.TypeShadowsocks,
|
||||||
|
ShadowsocksOptions: option.ShadowsocksOutboundOptions{
|
||||||
|
ServerOptions: option.ServerOptions{
|
||||||
|
Server: "127.0.0.1",
|
||||||
|
ServerPort: serverPort,
|
||||||
|
},
|
||||||
|
Method: "chacha20-ietf-poly1305",
|
||||||
|
Password: "FzcLbKs2dY9mhL",
|
||||||
|
Plugin: name,
|
||||||
|
PluginOptions: opts,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
testSuitSimple(t, clientPort, testPort)
|
||||||
|
}
|
||||||
@@ -18,7 +18,7 @@ func newUUID() uuid.UUID {
|
|||||||
return user
|
return user
|
||||||
}
|
}
|
||||||
|
|
||||||
func _TestVMessAuto(t *testing.T) {
|
func TestVMessAuto(t *testing.T) {
|
||||||
security := "auto"
|
security := "auto"
|
||||||
t.Run("self", func(t *testing.T) {
|
t.Run("self", func(t *testing.T) {
|
||||||
testVMessSelf(t, security, 0, false, false, false)
|
testVMessSelf(t, security, 0, false, false, false)
|
||||||
|
|||||||
@@ -462,7 +462,7 @@ func (c *PacketConn) ReadPacket(buffer *buf.Buffer) (destination M.Socksaddr, er
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
err = common.Error(buffer.Write(msg.Data))
|
err = common.Error(buffer.Write(msg.Data))
|
||||||
destination = M.ParseSocksaddrHostPort(msg.Host, msg.Port)
|
destination = M.ParseSocksaddrHostPort(msg.Host, msg.Port).Unwrap()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -473,14 +473,14 @@ func (c *PacketConn) ReadPacketThreadSafe() (buffer *buf.Buffer, destination M.S
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
buffer = buf.As(msg.Data)
|
buffer = buf.As(msg.Data)
|
||||||
destination = M.ParseSocksaddrHostPort(msg.Host, msg.Port)
|
destination = M.ParseSocksaddrHostPort(msg.Host, msg.Port).Unwrap()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *PacketConn) WritePacket(buffer *buf.Buffer, destination M.Socksaddr) error {
|
func (c *PacketConn) WritePacket(buffer *buf.Buffer, destination M.Socksaddr) error {
|
||||||
return WriteUDPMessage(c.session, UDPMessage{
|
return WriteUDPMessage(c.session, UDPMessage{
|
||||||
SessionID: c.sessionId,
|
SessionID: c.sessionId,
|
||||||
Host: destination.Unwrap().AddrString(),
|
Host: destination.AddrString(),
|
||||||
Port: destination.Port,
|
Port: destination.Port,
|
||||||
FragCount: 1,
|
FragCount: 1,
|
||||||
Data: buffer.Bytes(),
|
Data: buffer.Bytes(),
|
||||||
|
|||||||
@@ -19,7 +19,10 @@ func init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func newObfsLocal(pluginOpts Args, router adapter.Router, dialer N.Dialer, serverAddr M.Socksaddr) (Plugin, error) {
|
func newObfsLocal(pluginOpts Args, router adapter.Router, dialer N.Dialer, serverAddr M.Socksaddr) (Plugin, error) {
|
||||||
var plugin ObfsLocal
|
plugin := &ObfsLocal{
|
||||||
|
dialer: dialer,
|
||||||
|
serverAddr: serverAddr,
|
||||||
|
}
|
||||||
mode := "http"
|
mode := "http"
|
||||||
if obfsMode, loaded := pluginOpts.Get("obfs"); loaded {
|
if obfsMode, loaded := pluginOpts.Get("obfs"); loaded {
|
||||||
mode = obfsMode
|
mode = obfsMode
|
||||||
@@ -35,7 +38,7 @@ func newObfsLocal(pluginOpts Args, router adapter.Router, dialer N.Dialer, serve
|
|||||||
return nil, E.New("unknown obfs mode ", mode)
|
return nil, E.New("unknown obfs mode ", mode)
|
||||||
}
|
}
|
||||||
plugin.port = F.ToString(serverAddr.Port)
|
plugin.port = F.ToString(serverAddr.Port)
|
||||||
return &plugin, nil
|
return plugin, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type ObfsLocal struct {
|
type ObfsLocal struct {
|
||||||
|
|||||||
@@ -2,12 +2,15 @@ package sip003
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"net"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
"github.com/sagernet/sing-box/adapter"
|
"github.com/sagernet/sing-box/adapter"
|
||||||
"github.com/sagernet/sing-box/common/tls"
|
"github.com/sagernet/sing-box/common/tls"
|
||||||
C "github.com/sagernet/sing-box/constant"
|
C "github.com/sagernet/sing-box/constant"
|
||||||
"github.com/sagernet/sing-box/option"
|
"github.com/sagernet/sing-box/option"
|
||||||
"github.com/sagernet/sing-box/transport/v2ray"
|
"github.com/sagernet/sing-box/transport/v2ray"
|
||||||
|
"github.com/sagernet/sing-vmess"
|
||||||
E "github.com/sagernet/sing/common/exceptions"
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
M "github.com/sagernet/sing/common/metadata"
|
M "github.com/sagernet/sing/common/metadata"
|
||||||
N "github.com/sagernet/sing/common/network"
|
N "github.com/sagernet/sing/common/network"
|
||||||
@@ -56,6 +59,7 @@ func newV2RayPlugin(pluginOpts Args, router adapter.Router, dialer N.Dialer, ser
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var mux int
|
||||||
var transportOptions option.V2RayTransportOptions
|
var transportOptions option.V2RayTransportOptions
|
||||||
switch mode {
|
switch mode {
|
||||||
case "websocket":
|
case "websocket":
|
||||||
@@ -68,6 +72,15 @@ func newV2RayPlugin(pluginOpts Args, router adapter.Router, dialer N.Dialer, ser
|
|||||||
Path: path,
|
Path: path,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
if muxOpt, loaded := pluginOpts.Get("mux"); loaded {
|
||||||
|
muxVal, err := strconv.Atoi(muxOpt)
|
||||||
|
if err != nil {
|
||||||
|
return nil, E.Cause(err, "parse mux value")
|
||||||
|
}
|
||||||
|
mux = muxVal
|
||||||
|
} else {
|
||||||
|
mux = 1
|
||||||
|
}
|
||||||
case "quic":
|
case "quic":
|
||||||
transportOptions = option.V2RayTransportOptions{
|
transportOptions = option.V2RayTransportOptions{
|
||||||
Type: C.V2RayTransportTypeQUIC,
|
Type: C.V2RayTransportTypeQUIC,
|
||||||
@@ -76,5 +89,28 @@ func newV2RayPlugin(pluginOpts Args, router adapter.Router, dialer N.Dialer, ser
|
|||||||
return nil, E.New("v2ray-plugin: unknown mode: " + mode)
|
return nil, E.New("v2ray-plugin: unknown mode: " + mode)
|
||||||
}
|
}
|
||||||
|
|
||||||
return v2ray.NewClientTransport(context.Background(), dialer, serverAddr, transportOptions, tlsClient)
|
transport, err := v2ray.NewClientTransport(context.Background(), dialer, serverAddr, transportOptions, tlsClient)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if mux > 0 {
|
||||||
|
return &v2rayMuxWrapper{transport}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return transport, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ Plugin = (*v2rayMuxWrapper)(nil)
|
||||||
|
|
||||||
|
type v2rayMuxWrapper struct {
|
||||||
|
adapter.V2RayClientTransport
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *v2rayMuxWrapper) DialContext(ctx context.Context) (net.Conn, error) {
|
||||||
|
conn, err := w.V2RayClientTransport.DialContext(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return vmess.NewMuxConnWrapper(conn, vmess.MuxDestination), nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/sagernet/sing-box/adapter"
|
"github.com/sagernet/sing-box/adapter"
|
||||||
"github.com/sagernet/sing-box/common/tls"
|
"github.com/sagernet/sing-box/common/tls"
|
||||||
@@ -13,6 +14,8 @@ import (
|
|||||||
|
|
||||||
"google.golang.org/grpc"
|
"google.golang.org/grpc"
|
||||||
"google.golang.org/grpc/credentials"
|
"google.golang.org/grpc/credentials"
|
||||||
|
gM "google.golang.org/grpc/metadata"
|
||||||
|
"google.golang.org/grpc/peer"
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ adapter.V2RayServerTransport = (*Server)(nil)
|
var _ adapter.V2RayServerTransport = (*Server)(nil)
|
||||||
@@ -41,7 +44,22 @@ func NewServer(ctx context.Context, options option.V2RayGRPCOptions, tlsConfig t
|
|||||||
func (s *Server) Tun(server GunService_TunServer) error {
|
func (s *Server) Tun(server GunService_TunServer) error {
|
||||||
ctx, cancel := context.WithCancel(s.ctx)
|
ctx, cancel := context.WithCancel(s.ctx)
|
||||||
conn := NewGRPCConn(server, cancel)
|
conn := NewGRPCConn(server, cancel)
|
||||||
go s.handler.NewConnection(ctx, conn, M.Metadata{})
|
var metadata M.Metadata
|
||||||
|
if remotePeer, loaded := peer.FromContext(server.Context()); loaded {
|
||||||
|
metadata.Source = M.SocksaddrFromNet(remotePeer.Addr)
|
||||||
|
}
|
||||||
|
if grpcMetadata, loaded := gM.FromIncomingContext(server.Context()); loaded {
|
||||||
|
forwardFrom := strings.Join(grpcMetadata.Get("X-Forwarded-For"), ",")
|
||||||
|
if forwardFrom != "" {
|
||||||
|
for _, from := range strings.Split(forwardFrom, ",") {
|
||||||
|
originAddr := M.ParseSocksaddr(from)
|
||||||
|
if originAddr.IsValid() {
|
||||||
|
metadata.Source = originAddr.Unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
go s.handler.NewConnection(ctx, conn, metadata)
|
||||||
<-ctx.Done()
|
<-ctx.Done()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,8 +25,9 @@ type Client struct {
|
|||||||
serverAddr M.Socksaddr
|
serverAddr M.Socksaddr
|
||||||
tlsConfig *tls.STDConfig
|
tlsConfig *tls.STDConfig
|
||||||
quicConfig *quic.Config
|
quicConfig *quic.Config
|
||||||
conn quic.Connection
|
|
||||||
connAccess sync.Mutex
|
connAccess sync.Mutex
|
||||||
|
conn quic.Connection
|
||||||
|
rawConn net.Conn
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewClient(ctx context.Context, dialer N.Dialer, serverAddr M.Socksaddr, options option.V2RayQUICOptions, tlsConfig tls.Config) (adapter.V2RayClientTransport, error) {
|
func NewClient(ctx context.Context, dialer N.Dialer, serverAddr M.Socksaddr, options option.V2RayQUICOptions, tlsConfig tls.Config) (adapter.V2RayClientTransport, error) {
|
||||||
@@ -64,7 +65,6 @@ func (c *Client) offer() (quic.Connection, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
c.conn = conn
|
|
||||||
return conn, nil
|
return conn, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -80,6 +80,8 @@ func (c *Client) offerNew() (quic.Connection, error) {
|
|||||||
packetConn.Close()
|
packetConn.Close()
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
c.conn = quicConn
|
||||||
|
c.rawConn = udpConn
|
||||||
return quicConn, nil
|
return quicConn, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -94,3 +96,7 @@ func (c *Client) DialContext(ctx context.Context) (net.Conn, error) {
|
|||||||
}
|
}
|
||||||
return &hysteria.StreamWrapper{Conn: conn, Stream: stream}, nil
|
return &hysteria.StreamWrapper{Conn: conn, Stream: stream}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Client) Close() error {
|
||||||
|
return common.Close(c.conn, c.rawConn)
|
||||||
|
}
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ func (c *Client) DialContext(ctx context.Context) (net.Conn, error) {
|
|||||||
if c.maxEarlyData <= 0 {
|
if c.maxEarlyData <= 0 {
|
||||||
conn, response, err := c.dialer.DialContext(ctx, c.uri, c.headers)
|
conn, response, err := c.dialer.DialContext(ctx, c.uri, c.headers)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return &WebsocketConn{Conn: conn}, nil
|
return &WebsocketConn{Conn: conn, Writer: &Writer{conn, false}}, nil
|
||||||
}
|
}
|
||||||
return nil, wrapDialError(response, err)
|
return nil, wrapDialError(response, err)
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -10,16 +10,26 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
C "github.com/sagernet/sing-box/constant"
|
C "github.com/sagernet/sing-box/constant"
|
||||||
|
"github.com/sagernet/sing/common/buf"
|
||||||
E "github.com/sagernet/sing/common/exceptions"
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
"github.com/sagernet/websocket"
|
"github.com/sagernet/websocket"
|
||||||
)
|
)
|
||||||
|
|
||||||
type WebsocketConn struct {
|
type WebsocketConn struct {
|
||||||
*websocket.Conn
|
*websocket.Conn
|
||||||
|
*Writer
|
||||||
remoteAddr net.Addr
|
remoteAddr net.Addr
|
||||||
reader io.Reader
|
reader io.Reader
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func NewServerConn(wsConn *websocket.Conn, remoteAddr net.Addr) *WebsocketConn {
|
||||||
|
return &WebsocketConn{
|
||||||
|
Conn: wsConn,
|
||||||
|
remoteAddr: remoteAddr,
|
||||||
|
Writer: &Writer{wsConn, true},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (c *WebsocketConn) Close() error {
|
func (c *WebsocketConn) Close() error {
|
||||||
err := c.WriteControl(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, ""), time.Now().Add(C.TCPTimeout))
|
err := c.WriteControl(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, ""), time.Now().Add(C.TCPTimeout))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -47,14 +57,6 @@ func (c *WebsocketConn) Read(b []byte) (n int, err error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *WebsocketConn) Write(b []byte) (n int, err error) {
|
|
||||||
err = wrapError(c.WriteMessage(websocket.BinaryMessage, b))
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
return len(b), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *WebsocketConn) RemoteAddr() net.Addr {
|
func (c *WebsocketConn) RemoteAddr() net.Addr {
|
||||||
if c.remoteAddr != nil {
|
if c.remoteAddr != nil {
|
||||||
return c.remoteAddr
|
return c.remoteAddr
|
||||||
@@ -66,6 +68,10 @@ func (c *WebsocketConn) SetDeadline(t time.Time) error {
|
|||||||
return os.ErrInvalid
|
return os.ErrInvalid
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *WebsocketConn) FrontHeadroom() int {
|
||||||
|
return frontHeadroom
|
||||||
|
}
|
||||||
|
|
||||||
type EarlyWebsocketConn struct {
|
type EarlyWebsocketConn struct {
|
||||||
*Client
|
*Client
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
@@ -90,9 +96,9 @@ func (c *EarlyWebsocketConn) Write(b []byte) (n int, err error) {
|
|||||||
conn *websocket.Conn
|
conn *websocket.Conn
|
||||||
response *http.Response
|
response *http.Response
|
||||||
)
|
)
|
||||||
if len(earlyData) > int(c.maxEarlyData) {
|
if len(b) > int(c.maxEarlyData) {
|
||||||
earlyData = earlyData[:c.maxEarlyData]
|
earlyData = b[:c.maxEarlyData]
|
||||||
lateData = lateData[c.maxEarlyData:]
|
lateData = b[c.maxEarlyData:]
|
||||||
} else {
|
} else {
|
||||||
earlyData = b
|
earlyData = b
|
||||||
}
|
}
|
||||||
@@ -111,7 +117,7 @@ func (c *EarlyWebsocketConn) Write(b []byte) (n int, err error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, wrapDialError(response, err)
|
return 0, wrapDialError(response, err)
|
||||||
}
|
}
|
||||||
c.conn = &WebsocketConn{Conn: conn}
|
c.conn = &WebsocketConn{Conn: conn, Writer: &Writer{conn, false}}
|
||||||
close(c.create)
|
close(c.create)
|
||||||
if len(lateData) > 0 {
|
if len(lateData) > 0 {
|
||||||
_, err = c.conn.Write(lateData)
|
_, err = c.conn.Write(lateData)
|
||||||
@@ -122,6 +128,46 @@ func (c *EarlyWebsocketConn) Write(b []byte) (n int, err error) {
|
|||||||
return len(b), nil
|
return len(b), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *EarlyWebsocketConn) WriteBuffer(buffer *buf.Buffer) error {
|
||||||
|
if c.conn != nil {
|
||||||
|
return c.conn.WriteBuffer(buffer)
|
||||||
|
}
|
||||||
|
var (
|
||||||
|
earlyData []byte
|
||||||
|
lateData []byte
|
||||||
|
conn *websocket.Conn
|
||||||
|
response *http.Response
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
if buffer.Len() > int(c.maxEarlyData) {
|
||||||
|
earlyData = buffer.Bytes()[:c.maxEarlyData]
|
||||||
|
lateData = buffer.Bytes()[c.maxEarlyData:]
|
||||||
|
} else {
|
||||||
|
earlyData = buffer.Bytes()
|
||||||
|
}
|
||||||
|
if len(earlyData) > 0 {
|
||||||
|
earlyDataString := base64.RawURLEncoding.EncodeToString(earlyData)
|
||||||
|
if c.earlyDataHeaderName == "" {
|
||||||
|
conn, response, err = c.dialer.DialContext(c.ctx, c.uri+earlyDataString, c.headers)
|
||||||
|
} else {
|
||||||
|
headers := c.headers.Clone()
|
||||||
|
headers.Set(c.earlyDataHeaderName, earlyDataString)
|
||||||
|
conn, response, err = c.dialer.DialContext(c.ctx, c.uri, headers)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
conn, response, err = c.dialer.DialContext(c.ctx, c.uri, c.headers)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return wrapDialError(response, err)
|
||||||
|
}
|
||||||
|
c.conn = &WebsocketConn{Conn: conn, Writer: &Writer{conn, false}}
|
||||||
|
close(c.create)
|
||||||
|
if len(lateData) > 0 {
|
||||||
|
_, err = c.conn.Write(lateData)
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
func (c *EarlyWebsocketConn) Close() error {
|
func (c *EarlyWebsocketConn) Close() error {
|
||||||
if c.conn == nil {
|
if c.conn == nil {
|
||||||
return nil
|
return nil
|
||||||
@@ -164,6 +210,10 @@ func (c *EarlyWebsocketConn) SetWriteDeadline(t time.Time) error {
|
|||||||
return c.conn.SetWriteDeadline(t)
|
return c.conn.SetWriteDeadline(t)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *EarlyWebsocketConn) FrontHeadroom() int {
|
||||||
|
return frontHeadroom
|
||||||
|
}
|
||||||
|
|
||||||
func wrapError(err error) error {
|
func wrapError(err error) error {
|
||||||
if websocket.IsCloseError(err, websocket.CloseNormalClosure) {
|
if websocket.IsCloseError(err, websocket.CloseNormalClosure) {
|
||||||
return io.EOF
|
return io.EOF
|
||||||
|
|||||||
6
transport/v2raywebsocket/mask.go
Normal file
6
transport/v2raywebsocket/mask.go
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
package v2raywebsocket
|
||||||
|
|
||||||
|
import _ "unsafe"
|
||||||
|
|
||||||
|
//go:linkname maskBytes github.com/sagernet/websocket.maskBytes
|
||||||
|
func maskBytes(key [4]byte, pos int, b []byte) int
|
||||||
@@ -108,10 +108,7 @@ func (s *Server) ServeHTTP(writer http.ResponseWriter, request *http.Request) {
|
|||||||
}
|
}
|
||||||
var metadata M.Metadata
|
var metadata M.Metadata
|
||||||
metadata.Source = sHttp.SourceAddress(request)
|
metadata.Source = sHttp.SourceAddress(request)
|
||||||
conn = &WebsocketConn{
|
conn = NewServerConn(wsConn, metadata.Source.TCPAddr())
|
||||||
Conn: wsConn,
|
|
||||||
remoteAddr: metadata.Source.TCPAddr(),
|
|
||||||
}
|
|
||||||
if len(earlyData) > 0 {
|
if len(earlyData) > 0 {
|
||||||
conn = bufio.NewCachedConn(conn, buf.As(earlyData))
|
conn = bufio.NewCachedConn(conn, buf.As(earlyData))
|
||||||
}
|
}
|
||||||
|
|||||||
73
transport/v2raywebsocket/writer.go
Normal file
73
transport/v2raywebsocket/writer.go
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
package v2raywebsocket
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/binary"
|
||||||
|
"math/rand"
|
||||||
|
|
||||||
|
"github.com/sagernet/sing/common"
|
||||||
|
"github.com/sagernet/sing/common/buf"
|
||||||
|
"github.com/sagernet/websocket"
|
||||||
|
)
|
||||||
|
|
||||||
|
const frontHeadroom = 14
|
||||||
|
|
||||||
|
type Writer struct {
|
||||||
|
*websocket.Conn
|
||||||
|
isServer bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *Writer) Write(p []byte) (n int, err error) {
|
||||||
|
err = w.Conn.WriteMessage(websocket.BinaryMessage, p)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return len(p), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *Writer) WriteBuffer(buffer *buf.Buffer) error {
|
||||||
|
defer buffer.Release()
|
||||||
|
|
||||||
|
var payloadBitLength int
|
||||||
|
dataLen := buffer.Len()
|
||||||
|
data := buffer.Bytes()
|
||||||
|
if dataLen < 126 {
|
||||||
|
payloadBitLength = 1
|
||||||
|
} else if dataLen < 65536 {
|
||||||
|
payloadBitLength = 3
|
||||||
|
} else {
|
||||||
|
payloadBitLength = 9
|
||||||
|
}
|
||||||
|
|
||||||
|
var headerLen int
|
||||||
|
headerLen += 1 // FIN / RSV / OPCODE
|
||||||
|
headerLen += payloadBitLength
|
||||||
|
if !w.isServer {
|
||||||
|
headerLen += 4 // MASK KEY
|
||||||
|
}
|
||||||
|
|
||||||
|
header := buffer.ExtendHeader(headerLen)
|
||||||
|
header[0] = websocket.BinaryMessage | 1<<7
|
||||||
|
if w.isServer {
|
||||||
|
header[1] = 0
|
||||||
|
} else {
|
||||||
|
header[1] = 1 << 7
|
||||||
|
}
|
||||||
|
|
||||||
|
if dataLen < 126 {
|
||||||
|
header[1] |= byte(dataLen)
|
||||||
|
} else if dataLen < 65536 {
|
||||||
|
header[1] |= 126
|
||||||
|
binary.BigEndian.PutUint16(header[2:], uint16(dataLen))
|
||||||
|
} else {
|
||||||
|
header[1] |= 127
|
||||||
|
binary.BigEndian.PutUint64(header[2:], uint64(dataLen))
|
||||||
|
}
|
||||||
|
|
||||||
|
if !w.isServer {
|
||||||
|
maskKey := rand.Uint32()
|
||||||
|
binary.BigEndian.PutUint32(header[1+payloadBitLength:], maskKey)
|
||||||
|
maskBytes(*(*[4]byte)(header[1+payloadBitLength:]), 0, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
return common.Error(w.Conn.NetConn().Write(buffer.Bytes()))
|
||||||
|
}
|
||||||
@@ -20,6 +20,7 @@ type ClientBind struct {
|
|||||||
peerAddr M.Socksaddr
|
peerAddr M.Socksaddr
|
||||||
connAccess sync.Mutex
|
connAccess sync.Mutex
|
||||||
conn *wireConn
|
conn *wireConn
|
||||||
|
done chan struct{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewClientBind(ctx context.Context, dialer N.Dialer, peerAddr M.Socksaddr) *ClientBind {
|
func NewClientBind(ctx context.Context, dialer N.Dialer, peerAddr M.Socksaddr) *ClientBind {
|
||||||
@@ -63,6 +64,12 @@ func (c *ClientBind) connect() (*wireConn, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *ClientBind) Open(port uint16) (fns []conn.ReceiveFunc, actualPort uint16, err error) {
|
func (c *ClientBind) Open(port uint16) (fns []conn.ReceiveFunc, actualPort uint16, err error) {
|
||||||
|
select {
|
||||||
|
case <-c.done:
|
||||||
|
err = net.ErrClosed
|
||||||
|
return
|
||||||
|
default:
|
||||||
|
}
|
||||||
return []conn.ReceiveFunc{c.receive}, 0, nil
|
return []conn.ReceiveFunc{c.receive}, 0, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -75,7 +82,12 @@ func (c *ClientBind) receive(b []byte) (n int, ep conn.Endpoint, err error) {
|
|||||||
n, err = udpConn.Read(b)
|
n, err = udpConn.Read(b)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
udpConn.Close()
|
udpConn.Close()
|
||||||
err = &wireError{err}
|
select {
|
||||||
|
case <-c.done:
|
||||||
|
default:
|
||||||
|
err = &wireError{err}
|
||||||
|
}
|
||||||
|
return
|
||||||
}
|
}
|
||||||
ep = Endpoint(c.peerAddr)
|
ep = Endpoint(c.peerAddr)
|
||||||
return
|
return
|
||||||
@@ -85,6 +97,16 @@ func (c *ClientBind) Close() error {
|
|||||||
c.connAccess.Lock()
|
c.connAccess.Lock()
|
||||||
defer c.connAccess.Unlock()
|
defer c.connAccess.Unlock()
|
||||||
common.Close(common.PtrOrNil(c.conn))
|
common.Close(common.PtrOrNil(c.conn))
|
||||||
|
if c.done == nil {
|
||||||
|
c.done = make(chan struct{})
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
select {
|
||||||
|
case <-c.done:
|
||||||
|
return net.ErrClosed
|
||||||
|
default:
|
||||||
|
close(c.done)
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -35,7 +35,6 @@ type StackDevice struct {
|
|||||||
events chan tun.Event
|
events chan tun.Event
|
||||||
outbound chan *stack.PacketBuffer
|
outbound chan *stack.PacketBuffer
|
||||||
dispatcher stack.NetworkDispatcher
|
dispatcher stack.NetworkDispatcher
|
||||||
done chan struct{}
|
|
||||||
addr4 tcpip.Address
|
addr4 tcpip.Address
|
||||||
addr6 tcpip.Address
|
addr6 tcpip.Address
|
||||||
}
|
}
|
||||||
@@ -51,7 +50,6 @@ func NewStackDevice(localAddresses []netip.Prefix, mtu uint32) (*StackDevice, er
|
|||||||
mtu: mtu,
|
mtu: mtu,
|
||||||
events: make(chan tun.Event, 1),
|
events: make(chan tun.Event, 1),
|
||||||
outbound: make(chan *stack.PacketBuffer, 256),
|
outbound: make(chan *stack.PacketBuffer, 256),
|
||||||
done: make(chan struct{}),
|
|
||||||
}
|
}
|
||||||
err := ipStack.CreateNIC(defaultNIC, (*wireEndpoint)(tunDevice))
|
err := ipStack.CreateNIC(defaultNIC, (*wireEndpoint)(tunDevice))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -193,11 +191,11 @@ func (w *StackDevice) Events() chan tun.Event {
|
|||||||
|
|
||||||
func (w *StackDevice) Close() error {
|
func (w *StackDevice) Close() error {
|
||||||
select {
|
select {
|
||||||
case <-w.done:
|
case <-w.events:
|
||||||
return os.ErrClosed
|
return os.ErrClosed
|
||||||
default:
|
default:
|
||||||
|
close(w.events)
|
||||||
}
|
}
|
||||||
close(w.done)
|
|
||||||
w.stack.Close()
|
w.stack.Close()
|
||||||
for _, endpoint := range w.stack.CleanupEndpoints() {
|
for _, endpoint := range w.stack.CleanupEndpoints() {
|
||||||
endpoint.Abort()
|
endpoint.Abort()
|
||||||
|
|||||||
@@ -106,5 +106,11 @@ func (w *SystemDevice) Events() chan wgTun.Event {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (w *SystemDevice) Close() error {
|
func (w *SystemDevice) Close() error {
|
||||||
|
select {
|
||||||
|
case <-w.events:
|
||||||
|
return os.ErrClosed
|
||||||
|
default:
|
||||||
|
close(w.events)
|
||||||
|
}
|
||||||
return w.device.Close()
|
return w.device.Close()
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user