diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 025fe845..921929fe 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -468,11 +468,11 @@ jobs: - name: Setup Xcode stable if: matrix.if && github.ref == 'refs/heads/main-next' run: |- - sudo xcode-select -s /Applications/Xcode_16.2.app + sudo xcode-select -s /Applications/Xcode_16.4.app - name: Setup Xcode beta if: matrix.if && github.ref == 'refs/heads/dev-next' run: |- - sudo xcode-select -s /Applications/Xcode_16.2.app + sudo xcode-select -s /Applications/Xcode_16.4.app - name: Set tag if: matrix.if run: |- diff --git a/Makefile b/Makefile index ea633673..0561fa3c 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ NAME = sing-box COMMIT = $(shell git rev-parse --short HEAD) -TAGS_GO120 = with_gvisor,with_dhcp,with_wireguard,with_reality_server,with_clash_api,with_quic,with_utls +TAGS_GO120 = with_gvisor,with_dhcp,with_wireguard,with_reality_server,with_clash_api,with_quic,with_utls,with_acme TAGS_GO121 = with_ech TAGS ?= $(TAGS_GO118),$(TAGS_GO120),$(TAGS_GO121) TAGS_TEST ?= with_gvisor,with_quic,with_wireguard,with_grpc,with_ech,with_utls,with_reality_server diff --git a/adapter/inbound.go b/adapter/inbound.go index 2ba8205c..4c40da24 100644 --- a/adapter/inbound.go +++ b/adapter/inbound.go @@ -55,11 +55,11 @@ type InboundContext struct { // sniffer - Protocol string - Domain string - Client string - SniffContext any - PacketSniffError error + Protocol string + Domain string + Client string + SniffContext any + SniffError error // cache diff --git a/clients/android b/clients/android index eb2e13a6..7f1fa971 160000 --- a/clients/android +++ b/clients/android @@ -1 +1 @@ -Subproject commit eb2e13a6f9a8c03a35ae672395ccab0a6bdcd954 +Subproject commit 7f1fa971e3c7bbc504c2bd455f4e813a562990cb diff --git a/clients/apple b/clients/apple index ae5818ee..f7883b0f 160000 --- a/clients/apple +++ b/clients/apple @@ -1 +1 @@ -Subproject commit ae5818ee5a24af965dc91f80bffa16e1e6c109c1 +Subproject commit f7883b0f3ec26c449cba26b3b1a692f070f5424d diff --git a/common/tls/acme.go b/common/tls/acme.go index 08b24ed2..52172c9c 100644 --- a/common/tls/acme.go +++ b/common/tls/acme.go @@ -5,13 +5,13 @@ package tls import ( "context" "crypto/tls" - "os" "strings" "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/logger" "github.com/caddyserver/certmagic" "github.com/libdns/alidns" @@ -37,7 +37,38 @@ func (w *acmeWrapper) Close() error { return nil } -func startACME(ctx context.Context, options option.InboundACMEOptions) (*tls.Config, adapter.Service, error) { +type acmeLogWriter struct { + logger logger.Logger +} + +func (w *acmeLogWriter) Write(p []byte) (n int, err error) { + logLine := strings.ReplaceAll(string(p), " ", ": ") + switch { + case strings.HasPrefix(logLine, "error: "): + w.logger.Error(logLine[7:]) + case strings.HasPrefix(logLine, "warn: "): + w.logger.Warn(logLine[6:]) + case strings.HasPrefix(logLine, "info: "): + w.logger.Info(logLine[6:]) + case strings.HasPrefix(logLine, "debug: "): + w.logger.Debug(logLine[7:]) + default: + w.logger.Debug(logLine) + } + return len(p), nil +} + +func (w *acmeLogWriter) Sync() error { + return nil +} + +func encoderConfig() zapcore.EncoderConfig { + config := zap.NewProductionEncoderConfig() + config.TimeKey = zapcore.OmitKey + return config +} + +func startACME(ctx context.Context, logger logger.Logger, options option.InboundACMEOptions) (*tls.Config, adapter.Service, error) { var acmeServer string switch options.Provider { case "", "letsencrypt": @@ -58,14 +89,15 @@ func startACME(ctx context.Context, options option.InboundACMEOptions) (*tls.Con } else { storage = certmagic.Default.Storage } + zapLogger := zap.New(zapcore.NewCore( + zapcore.NewConsoleEncoder(encoderConfig()), + &acmeLogWriter{logger: logger}, + zap.DebugLevel, + )) config := &certmagic.Config{ DefaultServerName: options.DefaultServerName, Storage: storage, - Logger: zap.New(zapcore.NewCore( - zapcore.NewConsoleEncoder(zap.NewProductionEncoderConfig()), - os.Stderr, - zap.InfoLevel, - )), + Logger: zapLogger, } acmeConfig := certmagic.ACMEIssuer{ CA: acmeServer, @@ -75,7 +107,7 @@ func startACME(ctx context.Context, options option.InboundACMEOptions) (*tls.Con DisableTLSALPNChallenge: options.DisableTLSALPNChallenge, AltHTTPPort: int(options.AlternativeHTTPPort), AltTLSALPNPort: int(options.AlternativeTLSPort), - Logger: config.Logger, + Logger: zapLogger, } if dnsOptions := options.DNS01Challenge; dnsOptions != nil && dnsOptions.Provider != "" { var solver certmagic.DNS01Solver @@ -103,6 +135,7 @@ func startACME(ctx context.Context, options option.InboundACMEOptions) (*tls.Con GetConfigForCert: func(certificate certmagic.Certificate) (*certmagic.Config, error) { return config, nil }, + Logger: zapLogger, }) config = certmagic.New(cache, *config) var tlsConfig *tls.Config diff --git a/common/tls/acme_stub.go b/common/tls/acme_stub.go index d97d0540..f32f9e8d 100644 --- a/common/tls/acme_stub.go +++ b/common/tls/acme_stub.go @@ -9,8 +9,9 @@ import ( "github.com/sagernet/sing-box/adapter" "github.com/sagernet/sing-box/option" E "github.com/sagernet/sing/common/exceptions" + "github.com/sagernet/sing/common/logger" ) -func startACME(ctx context.Context, options option.InboundACMEOptions) (*tls.Config, adapter.Service, error) { +func startACME(ctx context.Context, logger logger.Logger, options option.InboundACMEOptions) (*tls.Config, adapter.Service, error) { return nil, nil, E.New(`ACME is not included in this build, rebuild with -tags with_acme`) } diff --git a/common/tls/std_server.go b/common/tls/std_server.go index 949521d7..27986003 100644 --- a/common/tls/std_server.go +++ b/common/tls/std_server.go @@ -157,7 +157,7 @@ func NewSTDServer(ctx context.Context, logger log.Logger, options option.Inbound var err error if options.ACME != nil && len(options.ACME.Domain) > 0 { //nolint:staticcheck - tlsConfig, acmeService, err = startACME(ctx, common.PtrValueOrDefault(options.ACME)) + tlsConfig, acmeService, err = startACME(ctx, logger, common.PtrValueOrDefault(options.ACME)) if err != nil { return nil, err } diff --git a/docs/changelog.md b/docs/changelog.md index 8f995cfd..d5f4a586 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -2,6 +2,13 @@ icon: material/alert-decagram --- +### 1.11.15 + +* Fixes and improvements + +_We are temporarily unable to update sing-box apps on the App Store because the reviewer mistakenly found that we +violated the rules (TestFlight users are not affected)._ + ### 1.11.14 * Fixes and improvements diff --git a/docs/configuration/experimental/clash-api.md b/docs/configuration/experimental/clash-api.md index 7425143e..d471ea87 100644 --- a/docs/configuration/experimental/clash-api.md +++ b/docs/configuration/experimental/clash-api.md @@ -63,7 +63,7 @@ icon: material/new-box { "external_controller": "0.0.0.0:9090", "external_ui": "dashboard" - // external_ui_download_detour: "direct" + // "external_ui_download_detour": "direct" } ``` diff --git a/docs/configuration/experimental/clash-api.zh.md b/docs/configuration/experimental/clash-api.zh.md index b3d8aeaf..8193cd87 100644 --- a/docs/configuration/experimental/clash-api.zh.md +++ b/docs/configuration/experimental/clash-api.zh.md @@ -63,7 +63,7 @@ icon: material/new-box { "external_controller": "0.0.0.0:9090", "external_ui": "dashboard" - // external_ui_download_detour: "direct" + // "external_ui_download_detour": "direct" } ``` diff --git a/go.mod b/go.mod index f0133cd0..7ab9011b 100644 --- a/go.mod +++ b/go.mod @@ -31,13 +31,13 @@ require ( github.com/sagernet/quic-go v0.49.0-beta.1 github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 github.com/sagernet/sing v0.6.10 - github.com/sagernet/sing-dns v0.4.5 + github.com/sagernet/sing-dns v0.4.6 github.com/sagernet/sing-mux v0.3.2 - github.com/sagernet/sing-quic v0.4.3 + github.com/sagernet/sing-quic v0.4.4 github.com/sagernet/sing-shadowsocks v0.2.8 github.com/sagernet/sing-shadowsocks2 v0.2.1 github.com/sagernet/sing-shadowtls v0.2.0 - github.com/sagernet/sing-tun v0.6.8 + github.com/sagernet/sing-tun v0.6.9 github.com/sagernet/sing-vmess v0.2.3 github.com/sagernet/smux v1.5.34-mod.2 github.com/sagernet/utls v1.6.7 diff --git a/go.sum b/go.sum index 2c993bce..59c43167 100644 --- a/go.sum +++ b/go.sum @@ -141,16 +141,16 @@ github.com/sagernet/sing v0.6.10 h1:Jey1tePgH9bjFuK1fQI3D9T+bPOQ4SdHMjuS4sYjDv4= github.com/sagernet/sing v0.6.10/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak= github.com/sagernet/sing-mux v0.3.2 h1:meZVFiiStvHThb/trcpAkCrmtJOuItG5Dzl1RRP5/NE= github.com/sagernet/sing-mux v0.3.2/go.mod h1:pht8iFY4c9Xltj7rhVd208npkNaeCxzyXCgulDPLUDA= -github.com/sagernet/sing-quic v0.4.3 h1:OZ/kGvSzjtYg+t0DY3F606hlT5LeiQQXDxfBopcRryQ= -github.com/sagernet/sing-quic v0.4.3/go.mod h1:tqPa0/Wqa19MkkSlKVZZX5sHxtiDR9BROcn4ufcbVdY= +github.com/sagernet/sing-quic v0.4.4 h1:qqOCLnzHbqKkj/wBcXEI3rhSyqoGlqDdv2S6mz2d/JA= +github.com/sagernet/sing-quic v0.4.4/go.mod h1:tqPa0/Wqa19MkkSlKVZZX5sHxtiDR9BROcn4ufcbVdY= github.com/sagernet/sing-shadowsocks v0.2.8 h1:PURj5PRoAkqeHh2ZW205RWzN9E9RtKCVCzByXruQWfE= github.com/sagernet/sing-shadowsocks v0.2.8/go.mod h1:lo7TWEMDcN5/h5B8S0ew+r78ZODn6SwVaFhvB6H+PTI= github.com/sagernet/sing-shadowsocks2 v0.2.1 h1:dWV9OXCeFPuYGHb6IRqlSptVnSzOelnqqs2gQ2/Qioo= github.com/sagernet/sing-shadowsocks2 v0.2.1/go.mod h1:RnXS0lExcDAovvDeniJ4IKa2IuChrdipolPYWBv9hWQ= github.com/sagernet/sing-shadowtls v0.2.0 h1:cLKe4OAOFwuhmAIuPLj//CIL7Q9js+pIDardhJ+/osk= github.com/sagernet/sing-shadowtls v0.2.0/go.mod h1:agU+Fw5X+xnWVyRHyFthoZCX3MfWKCFPm4JUf+1oaxo= -github.com/sagernet/sing-tun v0.6.8 h1:tr+LKHe09C2I9GfNuB2vnzaZm+ekoNlAhLLrdiLjtAA= -github.com/sagernet/sing-tun v0.6.8/go.mod h1:fisFCbC4Vfb6HqQNcwPJi2CDK2bf0Xapyz3j3t4cnHE= +github.com/sagernet/sing-tun v0.6.9 h1:uP8O4Q7U9QesjWumgxd2S9fjT3c6aEPWl5RB6uBdVB8= +github.com/sagernet/sing-tun v0.6.9/go.mod h1:fisFCbC4Vfb6HqQNcwPJi2CDK2bf0Xapyz3j3t4cnHE= github.com/sagernet/sing-vmess v0.2.3 h1:z6Ym8dnZG7k1fP3+54vz8G0tvRVJeOoTFFeUPwXTD44= github.com/sagernet/sing-vmess v0.2.3/go.mod h1:jDAZ0A0St1zVRkyvhAPRySOFfhC+4SQtO5VYyeFotgA= github.com/sagernet/smux v1.5.34-mod.2 h1:gkmBjIjlJ2zQKpLigOkFur5kBKdV6bNRoFu2WkltRQ4= diff --git a/protocol/vless/inbound.go b/protocol/vless/inbound.go index a977f739..f9e505a8 100644 --- a/protocol/vless/inbound.go +++ b/protocol/vless/inbound.go @@ -205,6 +205,10 @@ func (h *inboundTransportHandler) NewConnectionEx(ctx context.Context, conn net. var metadata adapter.InboundContext metadata.Source = source metadata.Destination = destination + //nolint:staticcheck + metadata.InboundDetour = h.listener.ListenOptions().Detour + //nolint:staticcheck + metadata.InboundOptions = h.listener.ListenOptions().InboundOptions h.logger.InfoContext(ctx, "inbound connection from ", metadata.Source) (*Inbound)(h).NewConnectionEx(ctx, conn, metadata, onClose) } diff --git a/protocol/vmess/inbound.go b/protocol/vmess/inbound.go index 0b8c96c6..706beb17 100644 --- a/protocol/vmess/inbound.go +++ b/protocol/vmess/inbound.go @@ -219,6 +219,10 @@ func (h *inboundTransportHandler) NewConnectionEx(ctx context.Context, conn net. var metadata adapter.InboundContext metadata.Source = source metadata.Destination = destination + //nolint:staticcheck + metadata.InboundDetour = h.listener.ListenOptions().Detour + //nolint:staticcheck + metadata.InboundOptions = h.listener.ListenOptions().InboundOptions h.logger.InfoContext(ctx, "inbound connection from ", metadata.Source) (*Inbound)(h).NewConnectionEx(ctx, conn, metadata, onClose) } diff --git a/route/dns.go b/route/dns.go index 8d57c646..6545ce04 100644 --- a/route/dns.go +++ b/route/dns.go @@ -2,15 +2,14 @@ package route import ( "context" - "errors" "net" "time" "github.com/sagernet/sing-box/adapter" C "github.com/sagernet/sing-box/constant" dnsOutbound "github.com/sagernet/sing-box/protocol/dns" + R "github.com/sagernet/sing-box/route/rule" "github.com/sagernet/sing-dns" - "github.com/sagernet/sing-tun" "github.com/sagernet/sing/common/buf" E "github.com/sagernet/sing/common/exceptions" M "github.com/sagernet/sing/common/metadata" @@ -58,7 +57,7 @@ func (r *Router) hijackDNSPacket(ctx context.Context, conn N.PacketConn, packetB func ExchangeDNSPacket(ctx context.Context, router *Router, conn N.PacketConn, buffer *buf.Buffer, metadata adapter.InboundContext, destination M.Socksaddr) { err := exchangeDNSPacket(ctx, router, conn, buffer, metadata, destination) - if err != nil && !errors.Is(err, tun.ErrDrop) && !E.IsClosedOrCanceled(err) { + if err != nil && !R.IsRejected(err) && !E.IsClosedOrCanceled(err) { router.dnsLogger.ErrorContext(ctx, E.Cause(err, "process packet connection")) } } diff --git a/route/route.go b/route/route.go index 9d60f598..023e62cb 100644 --- a/route/route.go +++ b/route/route.go @@ -16,7 +16,7 @@ import ( "github.com/sagernet/sing-box/common/sniff" C "github.com/sagernet/sing-box/constant" "github.com/sagernet/sing-box/option" - "github.com/sagernet/sing-box/route/rule" + R "github.com/sagernet/sing-box/route/rule" "github.com/sagernet/sing-dns" "github.com/sagernet/sing-mux" "github.com/sagernet/sing-vmess" @@ -51,7 +51,7 @@ func (r *Router) RouteConnectionEx(ctx context.Context, conn net.Conn, metadata err := r.routeConnection(ctx, conn, metadata, onClose) if err != nil { N.CloseOnHandshakeFailure(conn, onClose, err) - if E.IsClosedOrCanceled(err) { + if E.IsClosedOrCanceled(err) || R.IsRejected(err) { r.logger.DebugContext(ctx, "connection closed: ", err) } else { r.logger.ErrorContext(ctx, err) @@ -101,7 +101,7 @@ func (r *Router) routeConnection(ctx context.Context, conn net.Conn, metadata ad var selectedOutbound adapter.Outbound if selectedRule != nil { switch action := selectedRule.Action().(type) { - case *rule.RuleActionRoute: + case *R.RuleActionRoute: var loaded bool selectedOutbound, loaded = r.outbound.Outbound(action.Outbound) if !loaded { @@ -112,11 +112,11 @@ func (r *Router) routeConnection(ctx context.Context, conn net.Conn, metadata ad buf.ReleaseMulti(buffers) return E.New("TCP is not supported by outbound: ", selectedOutbound.Tag()) } - case *rule.RuleActionReject: + case *R.RuleActionReject: buf.ReleaseMulti(buffers) N.CloseOnHandshakeFailure(conn, onClose, action.Error(ctx)) return nil - case *rule.RuleActionHijackDNS: + case *R.RuleActionHijackDNS: for _, buffer := range buffers { conn = bufio.NewCachedConn(conn, buffer) } @@ -154,7 +154,7 @@ func (r *Router) RoutePacketConnection(ctx context.Context, conn N.PacketConn, m })) if err != nil { conn.Close() - if E.IsClosedOrCanceled(err) { + if E.IsClosedOrCanceled(err) || R.IsRejected(err) { r.logger.DebugContext(ctx, "connection closed: ", err) } else { r.logger.ErrorContext(ctx, err) @@ -171,7 +171,7 @@ func (r *Router) RoutePacketConnectionEx(ctx context.Context, conn N.PacketConn, err := r.routePacketConnection(ctx, conn, metadata, onClose) if err != nil { N.CloseOnHandshakeFailure(conn, onClose, err) - if E.IsClosedOrCanceled(err) { + if E.IsClosedOrCanceled(err) || R.IsRejected(err) { r.logger.DebugContext(ctx, "connection closed: ", err) } else { r.logger.ErrorContext(ctx, err) @@ -217,7 +217,7 @@ func (r *Router) routePacketConnection(ctx context.Context, conn N.PacketConn, m var selectReturn bool if selectedRule != nil { switch action := selectedRule.Action().(type) { - case *rule.RuleActionRoute: + case *R.RuleActionRoute: var loaded bool selectedOutbound, loaded = r.outbound.Outbound(action.Outbound) if !loaded { @@ -228,11 +228,11 @@ func (r *Router) routePacketConnection(ctx context.Context, conn N.PacketConn, m N.ReleaseMultiPacketBuffer(packetBuffers) return E.New("UDP is not supported by outbound: ", selectedOutbound.Tag()) } - case *rule.RuleActionReject: + case *R.RuleActionReject: N.ReleaseMultiPacketBuffer(packetBuffers) N.CloseOnHandshakeFailure(conn, onClose, action.Error(ctx)) return nil - case *rule.RuleActionHijackDNS: + case *R.RuleActionHijackDNS: r.hijackDNSPacket(ctx, conn, packetBuffers, metadata, onClose) return nil } @@ -271,7 +271,7 @@ func (r *Router) PreMatch(metadata adapter.InboundContext) error { if selectedRule == nil { return nil } - rejectAction, isReject := selectedRule.Action().(*rule.RuleActionReject) + rejectAction, isReject := selectedRule.Action().(*R.RuleActionReject) if !isReject { return nil } @@ -346,7 +346,7 @@ func (r *Router) matchRule( //nolint:staticcheck if metadata.InboundOptions != common.DefaultValue[option.InboundOptions]() { if !preMatch && metadata.InboundOptions.SniffEnabled { - newBuffer, newPackerBuffers, newErr := r.actionSniff(ctx, metadata, &rule.RuleActionSniff{ + newBuffer, newPackerBuffers, newErr := r.actionSniff(ctx, metadata, &R.RuleActionSniff{ OverrideDestination: metadata.InboundOptions.SniffOverrideDestination, Timeout: time.Duration(metadata.InboundOptions.SniffTimeout), }, inputConn, inputPacketConn, nil) @@ -361,7 +361,7 @@ func (r *Router) matchRule( } } if dns.DomainStrategy(metadata.InboundOptions.DomainStrategy) != dns.DomainStrategyAsIS { - fatalErr = r.actionResolve(ctx, metadata, &rule.RuleActionResolve{ + fatalErr = r.actionResolve(ctx, metadata, &R.RuleActionResolve{ Strategy: dns.DomainStrategy(metadata.InboundOptions.DomainStrategy), }) if fatalErr != nil { @@ -398,11 +398,11 @@ match: } } } - var routeOptions *rule.RuleActionRouteOptions + var routeOptions *R.RuleActionRouteOptions switch action := currentRule.Action().(type) { - case *rule.RuleActionRoute: + case *R.RuleActionRoute: routeOptions = &action.RuleActionRouteOptions - case *rule.RuleActionRouteOptions: + case *R.RuleActionRouteOptions: routeOptions = action } if routeOptions != nil { @@ -451,7 +451,7 @@ match: } } switch action := currentRule.Action().(type) { - case *rule.RuleActionSniff: + case *R.RuleActionSniff: if !preMatch { newBuffer, newPacketBuffers, newErr := r.actionSniff(ctx, metadata, action, inputConn, inputPacketConn, buffers) if newErr != nil { @@ -468,7 +468,7 @@ match: selectedRuleIndex = currentRuleIndex break match } - case *rule.RuleActionResolve: + case *R.RuleActionResolve: fatalErr = r.actionResolve(ctx, metadata, action) if fatalErr != nil { return @@ -488,7 +488,7 @@ match: } func (r *Router) actionSniff( - ctx context.Context, metadata *adapter.InboundContext, action *rule.RuleActionSniff, + ctx context.Context, metadata *adapter.InboundContext, action *R.RuleActionSniff, inputConn net.Conn, inputPacketConn N.PacketConn, inputBuffers []*buf.Buffer, ) (buffer *buf.Buffer, packetBuffers []*N.PacketBuffer, fatalErr error) { if sniff.Skip(metadata) { @@ -501,6 +501,9 @@ func (r *Router) actionSniff( if inputConn != nil { if len(action.StreamSniffers) == 0 && len(action.PacketSniffers) > 0 { return + } else if metadata.SniffError != nil && !errors.Is(metadata.SniffError, sniff.ErrNeedMoreData) { + r.logger.DebugContext(ctx, "packet sniff skipped due to previous error: ", metadata.SniffError) + return } var streamSniffers []sniff.StreamSniffer if len(action.StreamSniffers) > 0 { @@ -525,6 +528,7 @@ func (r *Router) actionSniff( action.Timeout, streamSniffers..., ) + metadata.SniffError = err if err == nil { //goland:noinspection GoDeprecation if action.OverrideDestination && M.IsDomainName(metadata.Domain) { @@ -549,8 +553,8 @@ func (r *Router) actionSniff( } else if inputPacketConn != nil { if len(action.PacketSniffers) == 0 && len(action.StreamSniffers) > 0 { return - } else if metadata.PacketSniffError != nil && !errors.Is(metadata.PacketSniffError, sniff.ErrNeedMoreData) { - r.logger.DebugContext(ctx, "packet sniff skipped due to previous error: ", metadata.PacketSniffError) + } else if metadata.SniffError != nil && !errors.Is(metadata.SniffError, sniff.ErrNeedMoreData) { + r.logger.DebugContext(ctx, "packet sniff skipped due to previous error: ", metadata.SniffError) return } var packetSniffers []sniff.PacketSniffer @@ -597,7 +601,7 @@ func (r *Router) actionSniff( return } } else { - if len(packetBuffers) > 0 || metadata.PacketSniffError != nil { + if len(packetBuffers) > 0 || metadata.SniffError != nil { err = sniff.PeekPacket( ctx, metadata, @@ -617,7 +621,7 @@ func (r *Router) actionSniff( Destination: destination, } packetBuffers = append(packetBuffers, packetBuffer) - metadata.PacketSniffError = err + metadata.SniffError = err if errors.Is(err, sniff.ErrNeedMoreData) { // TODO: replace with generic message when there are more multi-packet protocols r.logger.DebugContext(ctx, "attempt to sniff fragmented QUIC client hello") @@ -648,7 +652,7 @@ func (r *Router) actionSniff( return } -func (r *Router) actionResolve(ctx context.Context, metadata *adapter.InboundContext, action *rule.RuleActionResolve) error { +func (r *Router) actionResolve(ctx context.Context, metadata *adapter.InboundContext, action *R.RuleActionResolve) error { if metadata.Destination.IsFqdn() { metadata.DNSServer = action.Server addresses, err := r.Lookup(adapter.WithContext(ctx, metadata), metadata.Destination.Fqdn, action.Strategy) diff --git a/route/route_dns.go b/route/route_dns.go index 0e22cdfa..c5aced09 100644 --- a/route/route_dns.go +++ b/route/route_dns.go @@ -170,7 +170,7 @@ func (r *Router) Exchange(ctx context.Context, message *mDNS.Msg) (*mDNS.Msg, er Question: []mDNS.Question{message.Question[0]}, }, nil case C.RuleActionRejectMethodDrop: - return nil, tun.ErrDrop + return nil, &R.RejectedError{Cause: tun.ErrDrop} } } } @@ -289,7 +289,7 @@ func (r *Router) Lookup(ctx context.Context, domain string, strategy dns.DomainS case C.RuleActionRejectMethodDefault: return nil, nil case C.RuleActionRejectMethodDrop: - return nil, tun.ErrDrop + return nil, &R.RejectedError{Cause: tun.ErrDrop} } } } diff --git a/route/rule/rule_action.go b/route/rule/rule_action.go index 6246c7be..bf06bc5e 100644 --- a/route/rule/rule_action.go +++ b/route/rule/rule_action.go @@ -2,6 +2,7 @@ package rule import ( "context" + "errors" "net/netip" "strings" "sync" @@ -255,6 +256,23 @@ func (r *RuleActionDirect) String() string { return "direct" + r.description } +type RejectedError struct { + Cause error +} + +func (r *RejectedError) Error() string { + return "rejected" +} + +func (r *RejectedError) Unwrap() error { + return r.Cause +} + +func IsRejected(err error) bool { + var rejected *RejectedError + return errors.As(err, &rejected) +} + type RuleActionReject struct { Method string NoDrop bool @@ -278,9 +296,9 @@ func (r *RuleActionReject) Error(ctx context.Context) error { var returnErr error switch r.Method { case C.RuleActionRejectMethodDefault: - returnErr = syscall.ECONNREFUSED + returnErr = &RejectedError{syscall.ECONNREFUSED} case C.RuleActionRejectMethodDrop: - return tun.ErrDrop + return &RejectedError{tun.ErrDrop} default: panic(F.ToString("unknown reject method: ", r.Method)) } @@ -298,7 +316,7 @@ func (r *RuleActionReject) Error(ctx context.Context) error { if ctx != nil { r.logger.DebugContext(ctx, "dropped due to flooding") } - return tun.ErrDrop + return &RejectedError{tun.ErrDrop} } return returnErr } diff --git a/transport/v2rayhttp/conn.go b/transport/v2rayhttp/conn.go index e066503d..b339a753 100644 --- a/transport/v2rayhttp/conn.go +++ b/transport/v2rayhttp/conn.go @@ -31,6 +31,9 @@ type HTTPConn struct { } func NewHTTP1Conn(conn net.Conn, request *http.Request) *HTTPConn { + if request.Header.Get("Host") == "" { + request.Header.Set("Host", request.Host) + } return &HTTPConn{ Conn: conn, request: request, @@ -89,9 +92,6 @@ func (c *HTTPConn) writeRequest(payload []byte) error { if err != nil { return err } - if c.request.Header.Get("Host") == "" { - c.request.Header.Set("Host", c.request.Host) - } for key, value := range c.request.Header { _, err = writer.Write([]byte(F.ToString(key, ": ", strings.Join(value, ", "), CRLF))) if err != nil {