Fix lint errors
This commit is contained in:
@@ -30,7 +30,8 @@ type Store struct {
|
|||||||
certificatePaths []string
|
certificatePaths []string
|
||||||
certificateDirectoryPaths []string
|
certificateDirectoryPaths []string
|
||||||
watcher *fswatch.Watcher
|
watcher *fswatch.Watcher
|
||||||
platform storePlatform
|
//nolint:unused // populated only on darwin && cgo via the storePlatform embed.
|
||||||
|
platform storePlatform
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewStore(ctx context.Context, logger logger.Logger, options option.CertificateOptions) (*Store, error) {
|
func NewStore(ctx context.Context, logger logger.Logger, options option.CertificateOptions) (*Store, error) {
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
package certificate
|
package certificate
|
||||||
|
|
||||||
|
//nolint:unused // referenced by Store.platform; populated only in store_darwin.go.
|
||||||
type storePlatform struct{}
|
type storePlatform struct{}
|
||||||
|
|
||||||
func (s *Store) updatePlatformLocked(_ []byte) error {
|
func (s *Store) updatePlatformLocked(_ []byte) error {
|
||||||
|
|||||||
@@ -532,7 +532,7 @@ func TestAppleTransportRoundTripHTTPS(t *testing.T) {
|
|||||||
}
|
}
|
||||||
var normalizedValues []string
|
var normalizedValues []string
|
||||||
for _, value := range observed.values {
|
for _, value := range observed.values {
|
||||||
for _, part := range strings.Split(value, ",") {
|
for part := range strings.SplitSeq(value, ",") {
|
||||||
normalizedValues = append(normalizedValues, strings.TrimSpace(part))
|
normalizedValues = append(normalizedValues, strings.TrimSpace(part))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -687,7 +687,7 @@ func TestAppleTransportCancellationRecovery(t *testing.T) {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
for index := 0; index < appleHTTPRecoveryLoops; index++ {
|
for index := range appleHTTPRecoveryLoops {
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond)
|
ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond)
|
||||||
request := newAppleHTTPRequestWithContext(t, ctx, http.MethodGet, server.URL("/block"), nil)
|
request := newAppleHTTPRequestWithContext(t, ctx, http.MethodGet, server.URL("/block"), nil)
|
||||||
response, err := transport.RoundTrip(request)
|
response, err := transport.RoundTrip(request)
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptrace"
|
"net/http/httptrace"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
"slices"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
@@ -513,10 +514,7 @@ func (r *directionRunner) swapIntervalProbeValues() []float64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (r *directionRunner) setResponsivenessWindow(currentInterval int) {
|
func (r *directionRunner) setResponsivenessWindow(currentInterval int) {
|
||||||
lower := currentInterval - settings.movingAvgDistance + 1
|
lower := max(currentInterval-settings.movingAvgDistance+1, 0)
|
||||||
if lower < 0 {
|
|
||||||
lower = 0
|
|
||||||
}
|
|
||||||
r.probeMu.Lock()
|
r.probeMu.Lock()
|
||||||
r.responsivenessWindow = &intervalWindow{lower: lower, upper: currentInterval}
|
r.responsivenessWindow = &intervalWindow{lower: lower, upper: currentInterval}
|
||||||
r.probeMu.Unlock()
|
r.probeMu.Unlock()
|
||||||
@@ -529,10 +527,7 @@ func (r *directionRunner) recordThroughput(interval int, bps float64) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (r *directionRunner) setThroughputWindow(currentInterval int) {
|
func (r *directionRunner) setThroughputWindow(currentInterval int) {
|
||||||
lower := currentInterval - settings.movingAvgDistance + 1
|
lower := max(currentInterval-settings.movingAvgDistance+1, 0)
|
||||||
if lower < 0 {
|
|
||||||
lower = 0
|
|
||||||
}
|
|
||||||
r.probeMu.Lock()
|
r.probeMu.Lock()
|
||||||
r.throughputWindow = &intervalWindow{lower: lower, upper: currentInterval}
|
r.throughputWindow = &intervalWindow{lower: lower, upper: currentInterval}
|
||||||
r.probeMu.Unlock()
|
r.probeMu.Unlock()
|
||||||
@@ -956,7 +951,7 @@ func measureIdleLatency(ctx context.Context, factory MeasurementClientFactory, c
|
|||||||
maxProbeBytes = measurement.bytes
|
maxProbeBytes = measurement.bytes
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sort.Slice(latencies, func(i, j int) bool { return latencies[i] < latencies[j] })
|
slices.Sort(latencies)
|
||||||
return int32(latencies[len(latencies)/2]), maxProbeBytes, nil
|
return int32(latencies[len(latencies)/2]), maxProbeBytes, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -109,12 +109,12 @@ type schCredentials struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type tlsParameters struct {
|
type tlsParameters struct {
|
||||||
cAlpnIds uint32
|
_ uint32 // cAlpnIds
|
||||||
rgstrAlpnIds uintptr
|
_ uintptr // rgstrAlpnIds
|
||||||
grbitDisabledProtocols uint32
|
grbitDisabledProtocols uint32
|
||||||
cDisabledCrypto uint32
|
_ uint32 // cDisabledCrypto
|
||||||
pDisabledCrypto uintptr
|
_ uintptr // pDisabledCrypto
|
||||||
dwFlags uint32
|
_ uint32 // dwFlags
|
||||||
}
|
}
|
||||||
|
|
||||||
type secPkgContextStreamSizes struct {
|
type secPkgContextStreamSizes struct {
|
||||||
|
|||||||
+3
-7
@@ -5,6 +5,7 @@ package tls
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
|
"slices"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/sagernet/sing-box/adapter"
|
"github.com/sagernet/sing-box/adapter"
|
||||||
@@ -70,13 +71,8 @@ func startACME(ctx context.Context, logger logger.Logger, options option.Inbound
|
|||||||
Logger: zapLogger,
|
Logger: zapLogger,
|
||||||
}
|
}
|
||||||
profile := options.Profile
|
profile := options.Profile
|
||||||
if profile == "" && acmeServer == certmagic.LetsEncryptProductionCA {
|
if profile == "" && acmeServer == certmagic.LetsEncryptProductionCA && slices.ContainsFunc(options.Domain, certmagic.SubjectIsIP) {
|
||||||
for _, domain := range options.Domain {
|
profile = "shortlived"
|
||||||
if certmagic.SubjectIsIP(domain) {
|
|
||||||
profile = "shortlived"
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
acmeConfig := certmagic.ACMEIssuer{
|
acmeConfig := certmagic.ACMEIssuer{
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ var (
|
|||||||
|
|
||||||
func TestAppleClientHandshakeAppliesALPNAndVersion(t *testing.T) {
|
func TestAppleClientHandshakeAppliesALPNAndVersion(t *testing.T) {
|
||||||
serverCertificate, serverCertificatePEM := newAppleTestCertificate(t, "localhost")
|
serverCertificate, serverCertificatePEM := newAppleTestCertificate(t, "localhost")
|
||||||
for index := 0; index < appleTLSSuccessHandshakeLoops; index++ {
|
for index := range appleTLSSuccessHandshakeLoops {
|
||||||
serverResult, serverAddress := startAppleTLSTestServer(t, &stdtls.Config{
|
serverResult, serverAddress := startAppleTLSTestServer(t, &stdtls.Config{
|
||||||
Certificates: []stdtls.Certificate{serverCertificate},
|
Certificates: []stdtls.Certificate{serverCertificate},
|
||||||
MinVersion: stdtls.VersionTLS12,
|
MinVersion: stdtls.VersionTLS12,
|
||||||
@@ -201,7 +201,7 @@ func TestAppleClientHandshakeRecoversAfterFailure(t *testing.T) {
|
|||||||
|
|
||||||
for _, testCase := range testCases {
|
for _, testCase := range testCases {
|
||||||
t.Run(testCase.name, func(t *testing.T) {
|
t.Run(testCase.name, func(t *testing.T) {
|
||||||
for index := 0; index < appleTLSFailureRecoveryLoops; index++ {
|
for index := range appleTLSFailureRecoveryLoops {
|
||||||
failedResult, failedAddress := startAppleTLSTestServer(t, testCase.serverConfig)
|
failedResult, failedAddress := startAppleTLSTestServer(t, testCase.serverConfig)
|
||||||
failedConn, err := newAppleTestClientConn(t, failedAddress, testCase.clientOptions)
|
failedConn, err := newAppleTestClientConn(t, failedAddress, testCase.clientOptions)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
@@ -271,7 +271,7 @@ func TestAppleClientConfigCloneWithInlineCertificate(t *testing.T) {
|
|||||||
t.Fatalf("Clone shares ALPN slice with original: %v", nextProtos)
|
t.Fatalf("Clone shares ALPN slice with original: %v", nextProtos)
|
||||||
}
|
}
|
||||||
|
|
||||||
for index := 0; index < appleTLSFailureRecoveryLoops; index++ {
|
for index := range appleTLSFailureRecoveryLoops {
|
||||||
serverResult, serverAddress := startAppleTLSTestServer(t, &stdtls.Config{
|
serverResult, serverAddress := startAppleTLSTestServer(t, &stdtls.Config{
|
||||||
Certificates: []stdtls.Certificate{serverCertificate},
|
Certificates: []stdtls.Certificate{serverCertificate},
|
||||||
MinVersion: stdtls.VersionTLS12,
|
MinVersion: stdtls.VersionTLS12,
|
||||||
|
|||||||
@@ -3,79 +3,16 @@ package tls
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"net"
|
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/sagernet/sing-box/adapter"
|
"github.com/sagernet/sing-box/adapter"
|
||||||
C "github.com/sagernet/sing-box/constant"
|
|
||||||
"github.com/sagernet/sing-box/option"
|
"github.com/sagernet/sing-box/option"
|
||||||
E "github.com/sagernet/sing/common/exceptions"
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
"github.com/sagernet/sing/common/ntp"
|
|
||||||
"github.com/sagernet/sing/service"
|
"github.com/sagernet/sing/service"
|
||||||
)
|
)
|
||||||
|
|
||||||
type systemTLSConfig struct {
|
|
||||||
serverName string
|
|
||||||
nextProtos []string
|
|
||||||
handshakeTimeout time.Duration
|
|
||||||
minVersion uint16
|
|
||||||
maxVersion uint16
|
|
||||||
insecure bool
|
|
||||||
anchorOnly bool
|
|
||||||
certificatePublicKeySHA256 [][]byte
|
|
||||||
timeFunc func() time.Time
|
|
||||||
store adapter.CertificateStore
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *systemTLSConfig) ServerName() string {
|
|
||||||
return c.serverName
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *systemTLSConfig) SetServerName(serverName string) {
|
|
||||||
c.serverName = serverName
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *systemTLSConfig) NextProtos() []string {
|
|
||||||
return c.nextProtos
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *systemTLSConfig) SetNextProtos(nextProto []string) {
|
|
||||||
c.nextProtos = append([]string(nil), nextProto...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *systemTLSConfig) HandshakeTimeout() time.Duration {
|
|
||||||
return c.handshakeTimeout
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *systemTLSConfig) SetHandshakeTimeout(timeout time.Duration) {
|
|
||||||
c.handshakeTimeout = timeout
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *systemTLSConfig) STDConfig() (*STDConfig, error) {
|
|
||||||
return nil, E.New("STDConfig is unsupported for the system TLS engine")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *systemTLSConfig) Client(conn net.Conn) (Conn, error) {
|
|
||||||
return nil, os.ErrInvalid
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *systemTLSConfig) clone() systemTLSConfig {
|
|
||||||
return systemTLSConfig{
|
|
||||||
serverName: c.serverName,
|
|
||||||
nextProtos: append([]string(nil), c.nextProtos...),
|
|
||||||
handshakeTimeout: c.handshakeTimeout,
|
|
||||||
minVersion: c.minVersion,
|
|
||||||
maxVersion: c.maxVersion,
|
|
||||||
insecure: c.insecure,
|
|
||||||
anchorOnly: c.anchorOnly,
|
|
||||||
certificatePublicKeySHA256: append([][]byte(nil), c.certificatePublicKeySHA256...),
|
|
||||||
timeFunc: c.timeFunc,
|
|
||||||
store: c.store,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type SystemTLSValidated struct {
|
type SystemTLSValidated struct {
|
||||||
MinVersion uint16
|
MinVersion uint16
|
||||||
MaxVersion uint16
|
MaxVersion uint16
|
||||||
@@ -165,38 +102,6 @@ func resolveSystemAnchors(ctx context.Context, options option.OutboundTLSOptions
|
|||||||
return nil, store.ExclusiveAnchors(), store, nil
|
return nil, store.ExclusiveAnchors(), store, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func newSystemTLSConfig(ctx context.Context, serverAddress string, options option.OutboundTLSOptions, allowEmptyServerName bool, engineName string) (systemTLSConfig, SystemTLSValidated, error) {
|
|
||||||
validated, err := ValidateSystemTLSOptions(ctx, options, engineName)
|
|
||||||
if err != nil {
|
|
||||||
return systemTLSConfig{}, SystemTLSValidated{}, err
|
|
||||||
}
|
|
||||||
var serverName string
|
|
||||||
if options.ServerName != "" {
|
|
||||||
serverName = options.ServerName
|
|
||||||
} else if serverAddress != "" {
|
|
||||||
serverName = serverAddress
|
|
||||||
}
|
|
||||||
if serverName == "" && !options.Insecure && !allowEmptyServerName {
|
|
||||||
return systemTLSConfig{}, SystemTLSValidated{}, errMissingServerName
|
|
||||||
}
|
|
||||||
handshakeTimeout := C.TCPTimeout
|
|
||||||
if options.HandshakeTimeout > 0 {
|
|
||||||
handshakeTimeout = options.HandshakeTimeout.Build()
|
|
||||||
}
|
|
||||||
return systemTLSConfig{
|
|
||||||
serverName: serverName,
|
|
||||||
nextProtos: append([]string(nil), options.ALPN...),
|
|
||||||
handshakeTimeout: handshakeTimeout,
|
|
||||||
minVersion: validated.MinVersion,
|
|
||||||
maxVersion: validated.MaxVersion,
|
|
||||||
insecure: options.Insecure || len(options.CertificatePublicKeySHA256) > 0,
|
|
||||||
anchorOnly: validated.Exclusive,
|
|
||||||
certificatePublicKeySHA256: append([][]byte(nil), options.CertificatePublicKeySHA256...),
|
|
||||||
timeFunc: ntp.TimeFuncFromContext(ctx),
|
|
||||||
store: validated.Store,
|
|
||||||
}, validated, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func verifySystemTLSPeer(roots *x509.CertPool, serverName string, timeFunc func() time.Time, peerCertificates []*x509.Certificate) error {
|
func verifySystemTLSPeer(roots *x509.CertPool, serverName string, timeFunc func() time.Time, peerCertificates []*x509.Certificate) error {
|
||||||
if len(peerCertificates) == 0 {
|
if len(peerCertificates) == 0 {
|
||||||
return E.New("no peer certificates")
|
return E.New("no peer certificates")
|
||||||
|
|||||||
@@ -0,0 +1,108 @@
|
|||||||
|
//go:build (darwin && cgo) || windows
|
||||||
|
|
||||||
|
package tls
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"net"
|
||||||
|
"os"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/sagernet/sing-box/adapter"
|
||||||
|
C "github.com/sagernet/sing-box/constant"
|
||||||
|
"github.com/sagernet/sing-box/option"
|
||||||
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
|
"github.com/sagernet/sing/common/ntp"
|
||||||
|
)
|
||||||
|
|
||||||
|
type systemTLSConfig struct {
|
||||||
|
serverName string
|
||||||
|
nextProtos []string
|
||||||
|
handshakeTimeout time.Duration
|
||||||
|
minVersion uint16
|
||||||
|
maxVersion uint16
|
||||||
|
insecure bool
|
||||||
|
anchorOnly bool
|
||||||
|
certificatePublicKeySHA256 [][]byte
|
||||||
|
timeFunc func() time.Time
|
||||||
|
store adapter.CertificateStore
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *systemTLSConfig) ServerName() string {
|
||||||
|
return c.serverName
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *systemTLSConfig) SetServerName(serverName string) {
|
||||||
|
c.serverName = serverName
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *systemTLSConfig) NextProtos() []string {
|
||||||
|
return c.nextProtos
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *systemTLSConfig) SetNextProtos(nextProto []string) {
|
||||||
|
c.nextProtos = append([]string(nil), nextProto...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *systemTLSConfig) HandshakeTimeout() time.Duration {
|
||||||
|
return c.handshakeTimeout
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *systemTLSConfig) SetHandshakeTimeout(timeout time.Duration) {
|
||||||
|
c.handshakeTimeout = timeout
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *systemTLSConfig) STDConfig() (*STDConfig, error) {
|
||||||
|
return nil, E.New("STDConfig is unsupported for the system TLS engine")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *systemTLSConfig) Client(conn net.Conn) (Conn, error) {
|
||||||
|
return nil, os.ErrInvalid
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *systemTLSConfig) clone() systemTLSConfig {
|
||||||
|
return systemTLSConfig{
|
||||||
|
serverName: c.serverName,
|
||||||
|
nextProtos: append([]string(nil), c.nextProtos...),
|
||||||
|
handshakeTimeout: c.handshakeTimeout,
|
||||||
|
minVersion: c.minVersion,
|
||||||
|
maxVersion: c.maxVersion,
|
||||||
|
insecure: c.insecure,
|
||||||
|
anchorOnly: c.anchorOnly,
|
||||||
|
certificatePublicKeySHA256: append([][]byte(nil), c.certificatePublicKeySHA256...),
|
||||||
|
timeFunc: c.timeFunc,
|
||||||
|
store: c.store,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func newSystemTLSConfig(ctx context.Context, serverAddress string, options option.OutboundTLSOptions, allowEmptyServerName bool, engineName string) (systemTLSConfig, SystemTLSValidated, error) {
|
||||||
|
validated, err := ValidateSystemTLSOptions(ctx, options, engineName)
|
||||||
|
if err != nil {
|
||||||
|
return systemTLSConfig{}, SystemTLSValidated{}, err
|
||||||
|
}
|
||||||
|
var serverName string
|
||||||
|
if options.ServerName != "" {
|
||||||
|
serverName = options.ServerName
|
||||||
|
} else if serverAddress != "" {
|
||||||
|
serverName = serverAddress
|
||||||
|
}
|
||||||
|
if serverName == "" && !options.Insecure && !allowEmptyServerName {
|
||||||
|
return systemTLSConfig{}, SystemTLSValidated{}, errMissingServerName
|
||||||
|
}
|
||||||
|
handshakeTimeout := C.TCPTimeout
|
||||||
|
if options.HandshakeTimeout > 0 {
|
||||||
|
handshakeTimeout = options.HandshakeTimeout.Build()
|
||||||
|
}
|
||||||
|
return systemTLSConfig{
|
||||||
|
serverName: serverName,
|
||||||
|
nextProtos: append([]string(nil), options.ALPN...),
|
||||||
|
handshakeTimeout: handshakeTimeout,
|
||||||
|
minVersion: validated.MinVersion,
|
||||||
|
maxVersion: validated.MaxVersion,
|
||||||
|
insecure: options.Insecure || len(options.CertificatePublicKeySHA256) > 0,
|
||||||
|
anchorOnly: validated.Exclusive,
|
||||||
|
certificatePublicKeySHA256: append([][]byte(nil), options.CertificatePublicKeySHA256...),
|
||||||
|
timeFunc: ntp.TimeFuncFromContext(ctx),
|
||||||
|
store: validated.Store,
|
||||||
|
}, validated, nil
|
||||||
|
}
|
||||||
@@ -1110,7 +1110,7 @@ func TestWindowsClientMultipleRoundtrips(t *testing.T) {
|
|||||||
clientConn, serverDone := startWindowsEchoServer(t, stdtls.VersionTLS12)
|
clientConn, serverDone := startWindowsEchoServer(t, stdtls.VersionTLS12)
|
||||||
defer clientConn.Close()
|
defer clientConn.Close()
|
||||||
|
|
||||||
for i := 0; i < 100; i++ {
|
for i := range 100 {
|
||||||
payload := []byte("msg" + string(rune('A'+(i%26))))
|
payload := []byte("msg" + string(rune('A'+(i%26))))
|
||||||
_, err := clientConn.Write(payload)
|
_, err := clientConn.Write(payload)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -1148,7 +1148,7 @@ func TestWindowsClientConcurrentReadWrite(t *testing.T) {
|
|||||||
readErr := make(chan error, 1)
|
readErr := make(chan error, 1)
|
||||||
readBack := make(chan []byte, messageCount)
|
readBack := make(chan []byte, messageCount)
|
||||||
go func() {
|
go func() {
|
||||||
for i := 0; i < messageCount; i++ {
|
for range messageCount {
|
||||||
reply := make([]byte, messageSize)
|
reply := make([]byte, messageSize)
|
||||||
_, err := io.ReadFull(clientConn, reply)
|
_, err := io.ReadFull(clientConn, reply)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -1171,7 +1171,7 @@ func TestWindowsClientConcurrentReadWrite(t *testing.T) {
|
|||||||
if readResult != nil {
|
if readResult != nil {
|
||||||
t.Fatal(readResult)
|
t.Fatal(readResult)
|
||||||
}
|
}
|
||||||
for i := 0; i < messageCount; i++ {
|
for i := range messageCount {
|
||||||
got := <-readBack
|
got := <-readBack
|
||||||
if !bytes.Equal(payloads[i], got) {
|
if !bytes.Equal(payloads[i], got) {
|
||||||
t.Fatalf("iteration %d: payload mismatch", i)
|
t.Fatalf("iteration %d: payload mismatch", i)
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
//go:build linux || darwin || (windows && (amd64 || 386))
|
||||||
|
|
||||||
package tlsspoof
|
package tlsspoof
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
//go:build linux || darwin || (windows && (amd64 || 386))
|
||||||
|
|
||||||
package tlsspoof
|
package tlsspoof
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -94,18 +96,6 @@ func buildSpoofFrame(method Method, src, dst netip.AddrPort, sendNext, receiveNe
|
|||||||
return buildTCPSegment(src, dst, packetInfo, payload), nil
|
return buildTCPSegment(src, dst, packetInfo, payload), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// buildSpoofTCPSegment returns a TCP segment without an IP header, for
|
|
||||||
// platforms where the kernel synthesises the IP header (darwin IPv6).
|
|
||||||
func buildSpoofTCPSegment(method Method, src, dst netip.AddrPort, sendNext, receiveNext, timestamp uint32, payload []byte) ([]byte, error) {
|
|
||||||
packetInfo, err := resolveSpoofPacketInfo(method, sendNext, receiveNext, timestamp, nil, payload)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
segment := make([]byte, tcpHeaderLen+len(packetInfo.options)+len(payload))
|
|
||||||
encodeTCP(segment, 0, src, dst, packetInfo, payload)
|
|
||||||
return segment, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func resolveSpoofPacketInfo(method Method, sendNext, receiveNext, timestamp uint32, tcpOptions, payload []byte) (spoofPacketInfo, error) {
|
func resolveSpoofPacketInfo(method Method, sendNext, receiveNext, timestamp uint32, tcpOptions, payload []byte) (spoofPacketInfo, error) {
|
||||||
packetInfo := spoofPacketInfo{seqNum: sendNext, ackNum: receiveNext}
|
packetInfo := spoofPacketInfo{seqNum: sendNext, ackNum: receiveNext}
|
||||||
switch method {
|
switch method {
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package tlsspoof
|
||||||
|
|
||||||
|
import "net/netip"
|
||||||
|
|
||||||
|
// buildSpoofTCPSegment returns a TCP segment without an IP header, for
|
||||||
|
// platforms where the kernel synthesises the IP header (darwin IPv6).
|
||||||
|
func buildSpoofTCPSegment(method Method, src, dst netip.AddrPort, sendNext, receiveNext, timestamp uint32, payload []byte) ([]byte, error) {
|
||||||
|
packetInfo, err := resolveSpoofPacketInfo(method, sendNext, receiveNext, timestamp, nil, payload)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
segment := make([]byte, tcpHeaderLen+len(packetInfo.options)+len(payload))
|
||||||
|
encodeTCP(segment, 0, src, dst, packetInfo, payload)
|
||||||
|
return segment, nil
|
||||||
|
}
|
||||||
@@ -1,3 +1,5 @@
|
|||||||
|
//go:build linux || darwin || (windows && (amd64 || 386))
|
||||||
|
|
||||||
package tlsspoof
|
package tlsspoof
|
||||||
|
|
||||||
// realClientHello is a captured Chrome ClientHello for github.com.
|
// realClientHello is a captured Chrome ClientHello for github.com.
|
||||||
|
|||||||
@@ -72,14 +72,14 @@ func TestIntegrationRecvAbortsOnClose(t *testing.T) {
|
|||||||
func TestIntegrationConcurrentOpen(t *testing.T) {
|
func TestIntegrationConcurrentOpen(t *testing.T) {
|
||||||
errCh := make(chan error, 2)
|
errCh := make(chan error, 2)
|
||||||
handles := make(chan *Handle, 2)
|
handles := make(chan *Handle, 2)
|
||||||
for i := 0; i < 2; i++ {
|
for range 2 {
|
||||||
go func() {
|
go func() {
|
||||||
h, err := Open(nil, LayerNetwork, 0, FlagSendOnly)
|
h, err := Open(nil, LayerNetwork, 0, FlagSendOnly)
|
||||||
handles <- h
|
handles <- h
|
||||||
errCh <- err
|
errCh <- err
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
for i := 0; i < 2; i++ {
|
for range 2 {
|
||||||
err := <-errCh
|
err := <-errCh
|
||||||
h := <-handles
|
h := <-handles
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ type Address struct {
|
|||||||
Timestamp int64
|
Timestamp int64
|
||||||
bits uint32
|
bits uint32
|
||||||
Reserved2 uint32
|
Reserved2 uint32
|
||||||
union [64]byte
|
_ [64]byte
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ [80]byte = [unsafe.Sizeof(Address{})]byte{}
|
var _ [80]byte = [unsafe.Sizeof(Address{})]byte{}
|
||||||
|
|||||||
+2
-8
@@ -61,10 +61,7 @@ type ClientOptions struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func NewClient(options ClientOptions) *Client {
|
func NewClient(options ClientOptions) *Client {
|
||||||
cacheCapacity := options.CacheCapacity
|
cacheCapacity := max(options.CacheCapacity, 1024)
|
||||||
if cacheCapacity < 1024 {
|
|
||||||
cacheCapacity = 1024
|
|
||||||
}
|
|
||||||
client := &Client{
|
client := &Client{
|
||||||
ctx: options.Context,
|
ctx: options.Context,
|
||||||
timeout: options.Timeout,
|
timeout: options.Timeout,
|
||||||
@@ -426,10 +423,7 @@ func (c *Client) loadResponse(question dns.Question, transport adapter.DNSTransp
|
|||||||
c.cache.Remove(key)
|
c.cache.Remove(key)
|
||||||
return nil, 0, false
|
return nil, 0, false
|
||||||
}
|
}
|
||||||
nowTTL := int(expireAt.Sub(timeNow).Seconds())
|
nowTTL := max(int(expireAt.Sub(timeNow).Seconds()), 0)
|
||||||
if nowTTL < 0 {
|
|
||||||
nowTTL = 0
|
|
||||||
}
|
|
||||||
response = response.Copy()
|
response = response.Copy()
|
||||||
normalizeTTL(response, uint32(nowTTL))
|
normalizeTTL(response, uint32(nowTTL))
|
||||||
return response, nowTTL, false
|
return response, nowTTL, false
|
||||||
|
|||||||
@@ -1011,33 +1011,6 @@ func lookupDNSRuleSetMetadata(router adapter.Router, tag string, metadataOverrid
|
|||||||
return ruleSet.Metadata(), nil
|
return ruleSet.Metadata(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func referencedDNSRuleSetTags(rules []option.DNSRule) []string {
|
|
||||||
tagMap := make(map[string]bool)
|
|
||||||
var walkRule func(rule option.DNSRule)
|
|
||||||
walkRule = func(rule option.DNSRule) {
|
|
||||||
switch rule.Type {
|
|
||||||
case "", C.RuleTypeDefault:
|
|
||||||
for _, tag := range rule.DefaultOptions.RuleSet {
|
|
||||||
tagMap[tag] = true
|
|
||||||
}
|
|
||||||
case C.RuleTypeLogical:
|
|
||||||
for _, subRule := range rule.LogicalOptions.Rules {
|
|
||||||
walkRule(subRule)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for _, rule := range rules {
|
|
||||||
walkRule(rule)
|
|
||||||
}
|
|
||||||
tags := make([]string, 0, len(tagMap))
|
|
||||||
for tag := range tagMap {
|
|
||||||
if tag != "" {
|
|
||||||
tags = append(tags, tag)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return tags
|
|
||||||
}
|
|
||||||
|
|
||||||
func validateLegacyDNSModeDisabledRules(router adapter.Router, rules []option.DNSRule, metadataOverrides map[string]adapter.RuleSetMetadata) error {
|
func validateLegacyDNSModeDisabledRules(router adapter.Router, rules []option.DNSRule, metadataOverrides map[string]adapter.RuleSetMetadata) error {
|
||||||
var seenEvaluate bool
|
var seenEvaluate bool
|
||||||
for i, rule := range rules {
|
for i, rule := range rules {
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"net"
|
"net"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
"strings"
|
|
||||||
"sync"
|
"sync"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
@@ -113,14 +112,6 @@ func (r *fakeRouter) RuleSet(tag string) (adapter.RuleSet, bool) {
|
|||||||
return ruleSet, loaded
|
return ruleSet, loaded
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *fakeRouter) setRuleSet(tag string, ruleSet adapter.RuleSet) {
|
|
||||||
r.access.Lock()
|
|
||||||
defer r.access.Unlock()
|
|
||||||
if r.ruleSets == nil {
|
|
||||||
r.ruleSets = make(map[string]adapter.RuleSet)
|
|
||||||
}
|
|
||||||
r.ruleSets[tag] = ruleSet
|
|
||||||
}
|
|
||||||
func (r *fakeRouter) Rules() []adapter.Rule { return nil }
|
func (r *fakeRouter) Rules() []adapter.Rule { return nil }
|
||||||
func (r *fakeRouter) NeedFindProcess() bool { return false }
|
func (r *fakeRouter) NeedFindProcess() bool { return false }
|
||||||
func (r *fakeRouter) NeedFindNeighbor() bool { return false }
|
func (r *fakeRouter) NeedFindNeighbor() bool { return false }
|
||||||
@@ -210,12 +201,6 @@ func (s *fakeRuleSet) updateMetadata(metadata adapter.RuleSetMetadata) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *fakeRuleSet) snapshotCallbacks() []adapter.RuleSetUpdateCallback {
|
|
||||||
s.access.Lock()
|
|
||||||
defer s.access.Unlock()
|
|
||||||
return s.callbacks.Array()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *fakeRuleSet) refCount() int {
|
func (s *fakeRuleSet) refCount() int {
|
||||||
s.access.Lock()
|
s.access.Lock()
|
||||||
defer s.access.Unlock()
|
defer s.access.Unlock()
|
||||||
@@ -322,26 +307,6 @@ func newTestRouterWithContextAndLogger(t *testing.T, ctx context.Context, rules
|
|||||||
return router
|
return router
|
||||||
}
|
}
|
||||||
|
|
||||||
func waitForLogMessageContaining(t *testing.T, entries <-chan log.Entry, done <-chan struct{}, substring string) log.Entry {
|
|
||||||
t.Helper()
|
|
||||||
timeout := time.After(time.Second)
|
|
||||||
for {
|
|
||||||
select {
|
|
||||||
case entry, ok := <-entries:
|
|
||||||
if !ok {
|
|
||||||
t.Fatal("log subscription closed")
|
|
||||||
}
|
|
||||||
if strings.Contains(entry.Message, substring) {
|
|
||||||
return entry
|
|
||||||
}
|
|
||||||
case <-done:
|
|
||||||
t.Fatal("log subscription closed")
|
|
||||||
case <-timeout:
|
|
||||||
t.Fatalf("timed out waiting for log message containing %q", substring)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func fixedQuestion(name string, qType uint16) mDNS.Question {
|
func fixedQuestion(name string, qType uint16) mDNS.Question {
|
||||||
return mDNS.Question{
|
return mDNS.Question{
|
||||||
Name: mDNS.Fqdn(name),
|
Name: mDNS.Fqdn(name),
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
//go:build darwin && !cgo
|
||||||
|
|
||||||
|
package local
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
|
|
||||||
|
mDNS "github.com/miekg/dns"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (t *Transport) systemExchange(ctx context.Context, message *mDNS.Msg) (*mDNS.Msg, error) {
|
||||||
|
return nil, E.New(`local DNS server requires CGO on darwin, rebuild with CGO_ENABLED=1`)
|
||||||
|
}
|
||||||
@@ -374,10 +374,6 @@ func (b *profileBuilder) emitLocation() uint64 {
|
|||||||
return id
|
return id
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *profileBuilder) addMapping(lo uint64, hi uint64, offset uint64, file string, buildID string) {
|
|
||||||
b.addMappingEntry(lo, hi, offset, file, buildID, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *profileBuilder) addMappingEntry(lo uint64, hi uint64, offset uint64, file string, buildID string, fake bool) {
|
func (b *profileBuilder) addMappingEntry(lo uint64, hi uint64, offset uint64, file string, buildID string, fake bool) {
|
||||||
b.mem = append(b.mem, memMap{
|
b.mem = append(b.mem, memMap{
|
||||||
start: uintptr(lo),
|
start: uintptr(lo),
|
||||||
|
|||||||
@@ -14,7 +14,10 @@ func isExecutable(protection int32) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (b *profileBuilder) readMapping() {
|
func (b *profileBuilder) readMapping() {
|
||||||
if !machVMInfo(b.addMapping) {
|
added := machVMInfo(func(lo, hi, offset uint64, file, buildID string) {
|
||||||
|
b.addMappingEntry(lo, hi, offset, file, buildID, false)
|
||||||
|
})
|
||||||
|
if !added {
|
||||||
b.addMappingEntry(0, 0, 0, "", "", true)
|
b.addMappingEntry(0, 0, 0, "", "", true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,9 @@ import "os"
|
|||||||
|
|
||||||
func (b *profileBuilder) readMapping() {
|
func (b *profileBuilder) readMapping() {
|
||||||
data, _ := os.ReadFile("/proc/self/maps")
|
data, _ := os.ReadFile("/proc/self/maps")
|
||||||
stdParseProcSelfMaps(data, b.addMapping)
|
stdParseProcSelfMaps(data, func(lo, hi, offset uint64, file, buildID string) {
|
||||||
|
b.addMappingEntry(lo, hi, offset, file, buildID, false)
|
||||||
|
})
|
||||||
if len(b.mem) == 0 {
|
if len(b.mem) == 0 {
|
||||||
b.addMappingEntry(0, 0, 0, "", "", true)
|
b.addMappingEntry(0, 0, 0, "", "", true)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -320,7 +320,7 @@ func writeHeapProto(w io.Writer, profile []memProfileRecord, rate int64, default
|
|||||||
var locs []uint64
|
var locs []uint64
|
||||||
for _, record := range profile {
|
for _, record := range profile {
|
||||||
hideRuntime := true
|
hideRuntime := true
|
||||||
for tries := 0; tries < 2; tries++ {
|
for range 2 {
|
||||||
stk := record.Stack
|
stk := record.Stack
|
||||||
if hideRuntime {
|
if hideRuntime {
|
||||||
for i, addr := range stk {
|
for i, addr := range stk {
|
||||||
|
|||||||
@@ -1,10 +1,5 @@
|
|||||||
package libbox
|
package libbox
|
||||||
|
|
||||||
import (
|
|
||||||
"net"
|
|
||||||
"net/netip"
|
|
||||||
)
|
|
||||||
|
|
||||||
type NeighborEntry struct {
|
type NeighborEntry struct {
|
||||||
Address string
|
Address string
|
||||||
MacAddress string
|
MacAddress string
|
||||||
@@ -23,31 +18,3 @@ type NeighborSubscription struct {
|
|||||||
func (s *NeighborSubscription) Close() {
|
func (s *NeighborSubscription) Close() {
|
||||||
close(s.done)
|
close(s.done)
|
||||||
}
|
}
|
||||||
|
|
||||||
func tableToIterator(table map[netip.Addr]net.HardwareAddr) NeighborEntryIterator {
|
|
||||||
entries := make([]*NeighborEntry, 0, len(table))
|
|
||||||
for address, mac := range table {
|
|
||||||
entries = append(entries, &NeighborEntry{
|
|
||||||
Address: address.String(),
|
|
||||||
MacAddress: mac.String(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return &neighborEntryIterator{entries}
|
|
||||||
}
|
|
||||||
|
|
||||||
type neighborEntryIterator struct {
|
|
||||||
entries []*NeighborEntry
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i *neighborEntryIterator) HasNext() bool {
|
|
||||||
return len(i.entries) > 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i *neighborEntryIterator) Next() *NeighborEntry {
|
|
||||||
if len(i.entries) == 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
entry := i.entries[0]
|
|
||||||
i.entries = i.entries[1:]
|
|
||||||
return entry
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -0,0 +1,36 @@
|
|||||||
|
//go:build linux || darwin
|
||||||
|
|
||||||
|
package libbox
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net"
|
||||||
|
"net/netip"
|
||||||
|
)
|
||||||
|
|
||||||
|
func tableToIterator(table map[netip.Addr]net.HardwareAddr) NeighborEntryIterator {
|
||||||
|
entries := make([]*NeighborEntry, 0, len(table))
|
||||||
|
for address, mac := range table {
|
||||||
|
entries = append(entries, &NeighborEntry{
|
||||||
|
Address: address.String(),
|
||||||
|
MacAddress: mac.String(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return &neighborEntryIterator{entries}
|
||||||
|
}
|
||||||
|
|
||||||
|
type neighborEntryIterator struct {
|
||||||
|
entries []*NeighborEntry
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *neighborEntryIterator) HasNext() bool {
|
||||||
|
return len(i.entries) > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *neighborEntryIterator) Next() *NeighborEntry {
|
||||||
|
if len(i.entries) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
entry := i.entries[0]
|
||||||
|
i.entries = i.entries[1:]
|
||||||
|
return entry
|
||||||
|
}
|
||||||
@@ -3,6 +3,7 @@ package option
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
"slices"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
E "github.com/sagernet/sing/common/exceptions"
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
@@ -59,12 +60,7 @@ func hasAnyJSONKey(ctx context.Context, content []byte, keys ...string) (bool, e
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
for _, key := range keys {
|
return slices.ContainsFunc(keys, object.ContainsKey), nil
|
||||||
if object.ContainsKey(key) {
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func inspectRouteRuleAction(ctx context.Context, content []byte) (string, RouteActionOptions, error) {
|
func inspectRouteRuleAction(ctx context.Context, content []byte) (string, RouteActionOptions, error) {
|
||||||
|
|||||||
@@ -220,20 +220,20 @@ func parseISCDhcpd(file *os.File, ipToMAC map[netip.Addr]net.HardwareAddr, ipToH
|
|||||||
if !inLease {
|
if !inLease {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if strings.HasPrefix(line, "hardware ethernet ") {
|
if rest, ok := strings.CutPrefix(line, "hardware ethernet "); ok {
|
||||||
macString := strings.TrimSuffix(strings.TrimPrefix(line, "hardware ethernet "), ";")
|
macString := strings.TrimSuffix(rest, ";")
|
||||||
parsed, macErr := net.ParseMAC(macString)
|
parsed, macErr := net.ParseMAC(macString)
|
||||||
if macErr == nil {
|
if macErr == nil {
|
||||||
currentMAC = parsed
|
currentMAC = parsed
|
||||||
}
|
}
|
||||||
} else if strings.HasPrefix(line, "client-hostname ") {
|
} else if rest, ok := strings.CutPrefix(line, "client-hostname "); ok {
|
||||||
hostname := strings.TrimSuffix(strings.TrimPrefix(line, "client-hostname "), ";")
|
hostname := strings.TrimSuffix(rest, ";")
|
||||||
hostname = strings.Trim(hostname, "\"")
|
hostname = strings.Trim(hostname, "\"")
|
||||||
if hostname != "" {
|
if hostname != "" {
|
||||||
currentHostname = hostname
|
currentHostname = hostname
|
||||||
}
|
}
|
||||||
} else if strings.HasPrefix(line, "binding state ") {
|
} else if rest, ok := strings.CutPrefix(line, "binding state "); ok {
|
||||||
state := strings.TrimSuffix(strings.TrimPrefix(line, "binding state "), ";")
|
state := strings.TrimSuffix(rest, ";")
|
||||||
currentActive = state == "active"
|
currentActive = state == "active"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package rule
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"net/netip"
|
"net/netip"
|
||||||
|
"slices"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/sagernet/sing-box/adapter"
|
"github.com/sagernet/sing-box/adapter"
|
||||||
@@ -84,12 +85,7 @@ func (r *IPCIDRItem) Match(metadata *adapter.InboundContext) bool {
|
|||||||
// does not expose any address answers for matching.
|
// does not expose any address answers for matching.
|
||||||
return metadata.IPCIDRAcceptEmpty
|
return metadata.IPCIDRAcceptEmpty
|
||||||
}
|
}
|
||||||
for _, address := range addresses {
|
return slices.ContainsFunc(addresses, r.ipSet.Contains)
|
||||||
if r.ipSet.Contains(address) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
if metadata.Destination.IsIP() {
|
if metadata.Destination.IsIP() {
|
||||||
return r.ipSet.Contains(metadata.Destination.Addr)
|
return r.ipSet.Contains(metadata.Destination.Addr)
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package rule
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"regexp"
|
"regexp"
|
||||||
|
"slices"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/sagernet/sing-box/adapter"
|
"github.com/sagernet/sing-box/adapter"
|
||||||
@@ -42,10 +43,8 @@ func (r *PackageNameRegexItem) Match(metadata *adapter.InboundContext) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
for _, matcher := range r.matchers {
|
for _, matcher := range r.matchers {
|
||||||
for _, packageName := range metadata.ProcessInfo.AndroidPackageNames {
|
if slices.ContainsFunc(metadata.ProcessInfo.AndroidPackageNames, matcher.MatchString) {
|
||||||
if matcher.MatchString(packageName) {
|
return true
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package rule
|
package rule
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"slices"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/sagernet/sing-box/adapter"
|
"github.com/sagernet/sing-box/adapter"
|
||||||
@@ -31,10 +32,8 @@ func (r *DNSResponseRecordItem) Match(metadata *adapter.InboundContext) bool {
|
|||||||
}
|
}
|
||||||
records := r.selector(metadata.DNSResponse)
|
records := r.selector(metadata.DNSResponse)
|
||||||
for _, expected := range r.records {
|
for _, expected := range r.records {
|
||||||
for _, record := range records {
|
if slices.ContainsFunc(records, expected.Match) {
|
||||||
if expected.Match(record) {
|
return true
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
|
|||||||
@@ -769,7 +769,6 @@ func TestDNSAddressLimitIgnoresDestinationAddresses(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, testCase := range testCases {
|
for _, testCase := range testCases {
|
||||||
testCase := testCase
|
|
||||||
t.Run(testCase.name, func(t *testing.T) {
|
t.Run(testCase.name, func(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
rule := dnsRuleForTest(func(rule *abstractDefaultRule) {
|
rule := dnsRuleForTest(func(rule *abstractDefaultRule) {
|
||||||
@@ -825,7 +824,6 @@ func TestDNSLegacyAddressLimitPreLookupDefersDirectRules(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, testCase := range testCases {
|
for _, testCase := range testCases {
|
||||||
testCase := testCase
|
|
||||||
t.Run(testCase.name, func(t *testing.T) {
|
t.Run(testCase.name, func(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
@@ -925,7 +923,6 @@ func TestDNSLegacyInvertAddressLimitPreLookupRegression(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, testCase := range testCases {
|
for _, testCase := range testCases {
|
||||||
testCase := testCase
|
|
||||||
t.Run(testCase.name, func(t *testing.T) {
|
t.Run(testCase.name, func(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
"slices"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
@@ -113,13 +114,8 @@ func NewCertificateProvider(ctx context.Context, logger log.ContextLogger, tag s
|
|||||||
}
|
}
|
||||||
|
|
||||||
profile := options.Profile
|
profile := options.Profile
|
||||||
if profile == "" && acmeServer == certmagic.LetsEncryptProductionCA {
|
if profile == "" && acmeServer == certmagic.LetsEncryptProductionCA && slices.ContainsFunc(options.Domain, certmagic.SubjectIsIP) {
|
||||||
for _, domain := range options.Domain {
|
profile = "shortlived"
|
||||||
if certmagic.SubjectIsIP(domain) {
|
|
||||||
profile = "shortlived"
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
acmeIssuer := certmagic.ACMEIssuer{
|
acmeIssuer := certmagic.ACMEIssuer{
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ type Service struct {
|
|||||||
timerConfig timerConfig
|
timerConfig timerConfig
|
||||||
adaptiveTimer *adaptiveTimer
|
adaptiveTimer *adaptiveTimer
|
||||||
lastReportTime atomic.Int64
|
lastReportTime atomic.Int64
|
||||||
|
//nolint:unused // touched only on darwin && cgo via writeOOMDraft/discardOOMDraft.
|
||||||
draftCancelled atomic.Bool
|
draftCancelled atomic.Bool
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -84,37 +85,3 @@ func (s *Service) writeOOMReport(memoryUsage uint64) {
|
|||||||
s.logger.Info("OOM report saved")
|
s.logger.Info("OOM report saved")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) writeOOMDraft(memoryUsage uint64) {
|
|
||||||
if s.draftCancelled.Load() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
reporter := service.FromContext[OOMReporter](s.ctx)
|
|
||||||
if reporter == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
err := reporter.WriteDraft(memoryUsage)
|
|
||||||
if s.draftCancelled.Load() {
|
|
||||||
reporter.DiscardDraft()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
s.logger.Warn("failed to write OOM draft: ", err)
|
|
||||||
} else {
|
|
||||||
s.logger.Warn("OOM draft saved")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Service) discardOOMDraft() {
|
|
||||||
s.draftCancelled.Store(true)
|
|
||||||
reporter := service.FromContext[OOMReporter](s.ctx)
|
|
||||||
if reporter == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
err := reporter.DiscardDraft()
|
|
||||||
if err != nil {
|
|
||||||
s.logger.Warn("failed to discard OOM draft: ", err)
|
|
||||||
} else {
|
|
||||||
s.logger.Info("OOM draft discarded")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ import (
|
|||||||
"github.com/sagernet/sing-box/adapter"
|
"github.com/sagernet/sing-box/adapter"
|
||||||
"github.com/sagernet/sing/common/byteformats"
|
"github.com/sagernet/sing/common/byteformats"
|
||||||
E "github.com/sagernet/sing/common/exceptions"
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
|
"github.com/sagernet/sing/service"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -103,3 +104,37 @@ func goMemoryPressureCallback(status C.ulong) {
|
|||||||
s.adaptiveTimer.notifyPressure()
|
s.adaptiveTimer.notifyPressure()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Service) writeOOMDraft(memoryUsage uint64) {
|
||||||
|
if s.draftCancelled.Load() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
reporter := service.FromContext[OOMReporter](s.ctx)
|
||||||
|
if reporter == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err := reporter.WriteDraft(memoryUsage)
|
||||||
|
if s.draftCancelled.Load() {
|
||||||
|
reporter.DiscardDraft()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
s.logger.Warn("failed to write OOM draft: ", err)
|
||||||
|
} else {
|
||||||
|
s.logger.Warn("OOM draft saved")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) discardOOMDraft() {
|
||||||
|
s.draftCancelled.Store(true)
|
||||||
|
reporter := service.FromContext[OOMReporter](s.ctx)
|
||||||
|
if reporter == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err := reporter.DiscardDraft()
|
||||||
|
if err != nil {
|
||||||
|
s.logger.Warn("failed to discard OOM draft: ", err)
|
||||||
|
} else {
|
||||||
|
s.logger.Info("OOM draft discarded")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -134,15 +134,6 @@ func (t *adaptiveTimer) start() {
|
|||||||
t.startLocked()
|
t.startLocked()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *adaptiveTimer) notifyPressure() {
|
|
||||||
t.access.Lock()
|
|
||||||
t.startLocked()
|
|
||||||
t.forceMinInterval = true
|
|
||||||
t.pendingPressureBaseline = true
|
|
||||||
t.access.Unlock()
|
|
||||||
t.poll()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *adaptiveTimer) startLocked() {
|
func (t *adaptiveTimer) startLocked() {
|
||||||
if t.timer != nil {
|
if t.timer != nil {
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
//go:build darwin && cgo
|
||||||
|
|
||||||
|
package oomkiller
|
||||||
|
|
||||||
|
func (t *adaptiveTimer) notifyPressure() {
|
||||||
|
t.access.Lock()
|
||||||
|
t.startLocked()
|
||||||
|
t.forceMinInterval = true
|
||||||
|
t.pendingPressureBaseline = true
|
||||||
|
t.access.Unlock()
|
||||||
|
t.poll()
|
||||||
|
}
|
||||||
@@ -210,10 +210,7 @@ func (s *Service) refreshLoop() {
|
|||||||
waitDuration = minimumRenewRetryDelay
|
waitDuration = minimumRenewRetryDelay
|
||||||
} else {
|
} else {
|
||||||
refreshAt := leaf.NotAfter.Add(-s.effectiveRenewBefore(leaf))
|
refreshAt := leaf.NotAfter.Add(-s.effectiveRenewBefore(leaf))
|
||||||
waitDuration = refreshAt.Sub(s.timeFunc())
|
waitDuration = max(refreshAt.Sub(s.timeFunc()), minimumRenewRetryDelay)
|
||||||
if waitDuration < minimumRenewRetryDelay {
|
|
||||||
waitDuration = minimumRenewRetryDelay
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
timer := time.NewTimer(waitDuration)
|
timer := time.NewTimer(waitDuration)
|
||||||
|
|||||||
Reference in New Issue
Block a user