Merge tag 'v1.14.0'

This commit is contained in:
Shtorm
2026-09-04 01:08:30 +03:00
987 changed files with 141481 additions and 11302 deletions
+1 -1
View File
@@ -121,7 +121,7 @@ func (h *Inbound) UpdateUsers(users []option.SSHUser) {
h.service.UpdateUsers(users)
}
func (h *Inbound) NewConnectionEx(ctx context.Context, conn net.Conn, metadata adapter.InboundContext, onClose N.CloseHandlerFunc) {
func (h *Inbound) NewConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext, onClose N.CloseHandlerFunc) {
metadata.Inbound = h.Tag()
metadata.InboundType = h.Type()
serverConn, channels, requests, err := ssh.NewServerConn(conn, h.serverConfig)
+36 -8
View File
@@ -23,6 +23,7 @@ import (
"github.com/sagernet/sing/common/logger"
M "github.com/sagernet/sing/common/metadata"
N "github.com/sagernet/sing/common/network"
"github.com/sagernet/sing/service/filemanager"
"golang.org/x/crypto/ssh"
)
@@ -35,13 +36,15 @@ var _ adapter.InterfaceUpdateListener = (*Outbound)(nil)
type Outbound struct {
outbound.Adapter
ctx context.Context
logger logger.ContextLogger
dialer N.Dialer
serverAddr M.Socksaddr
user string
hostKey []ssh.PublicKey
hostKeyAlgorithms []string
cipher []string
mac []string
kexAlgorithm []string
clientVersion string
authMethod []ssh.AuthMethod
clientAccess sync.Mutex
@@ -56,12 +59,14 @@ func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextL
}
outbound := &Outbound{
Adapter: outbound.NewAdapterWithDialerOptions(C.TypeSSH, tag, []string{N.NetworkTCP}, options.DialerOptions),
ctx: ctx,
logger: logger,
dialer: outboundDialer,
serverAddr: options.ServerOptions.Build(),
user: options.User,
hostKeyAlgorithms: options.HostKeyAlgorithms,
cipher: options.Cipher,
mac: options.MAC,
kexAlgorithm: options.KexAlgorithm,
clientVersion: options.ClientVersion,
}
if outbound.serverAddr.Port == 0 {
@@ -82,7 +87,7 @@ func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextL
privateKey = []byte(strings.Join(options.PrivateKey, "\n"))
} else {
var err error
privateKey, err = os.ReadFile(os.ExpandEnv(options.PrivateKeyPath))
privateKey, err = filemanager.ReadFile(ctx, os.ExpandEnv(options.PrivateKeyPath))
if err != nil {
return nil, E.Cause(err, "read private key")
}
@@ -121,7 +126,7 @@ func randomVersion() string {
return version
}
func (s *Outbound) connect() (*ssh.Client, error) {
func (s *Outbound) connect(ctx context.Context) (client *ssh.Client, err error) {
if s.client != nil {
return s.client, nil
}
@@ -133,10 +138,24 @@ func (s *Outbound) connect() (*ssh.Client, error) {
return s.client, nil
}
conn, err := s.dialer.DialContext(s.ctx, N.NetworkTCP, s.serverAddr)
conn, err := s.dialer.DialContext(ctx, N.NetworkTCP, s.serverAddr)
if err != nil {
return nil, err
}
if ctx.Done() != nil {
handshakeConn := conn
stopContext := context.AfterFunc(ctx, func() {
_ = handshakeConn.Close()
})
defer func() {
if !stopContext() {
s.client = nil
s.clientConn = nil
client = nil
err = ctx.Err()
}
}()
}
config := &ssh.ClientConfig{
User: s.user,
Auth: s.authMethod,
@@ -155,13 +174,22 @@ func (s *Outbound) connect() (*ssh.Client, error) {
return E.New("host key mismatch, server send ", key.Type(), " ", base64.StdEncoding.EncodeToString(serverKey))
},
}
if len(s.cipher) > 0 {
config.Ciphers = s.cipher
}
if len(s.mac) > 0 {
config.MACs = s.mac
}
if len(s.kexAlgorithm) > 0 {
config.KeyExchanges = s.kexAlgorithm
}
clientConn, chans, reqs, err := ssh.NewClientConn(conn, s.serverAddr.Addr.String(), config)
if err != nil {
conn.Close()
return nil, E.Cause(err, "connect to ssh server")
}
client := ssh.NewClient(clientConn, chans, reqs)
client = ssh.NewClient(clientConn, chans, reqs)
s.clientConn = conn
s.client = client
@@ -178,7 +206,7 @@ func (s *Outbound) connect() (*ssh.Client, error) {
return client, nil
}
func (s *Outbound) InterfaceUpdated() {
func (s *Outbound) InterfaceUpdated(ctx context.Context) {
common.Close(s.clientConn)
}
@@ -187,7 +215,7 @@ func (s *Outbound) Close() error {
}
func (s *Outbound) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
client, err := s.connect()
client, err := s.connect(ctx)
if err != nil {
return nil, err
}