Fix log for rejected connections

This commit is contained in:
世界 2025-06-20 13:12:49 +08:00
parent 9b8ab3e61e
commit cba0e46aba
No known key found for this signature in database
GPG Key ID: CD109927C34A63C4
6 changed files with 48 additions and 31 deletions

2
go.mod
View File

@ -33,7 +33,7 @@ require (
github.com/sagernet/sing-shadowsocks v0.2.8 github.com/sagernet/sing-shadowsocks v0.2.8
github.com/sagernet/sing-shadowsocks2 v0.2.1 github.com/sagernet/sing-shadowsocks2 v0.2.1
github.com/sagernet/sing-shadowtls v0.2.0 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/sing-vmess v0.2.3
github.com/sagernet/smux v1.5.34-mod.2 github.com/sagernet/smux v1.5.34-mod.2
github.com/sagernet/utls v1.6.7 github.com/sagernet/utls v1.6.7

4
go.sum
View File

@ -133,8 +133,8 @@ github.com/sagernet/sing-shadowsocks2 v0.2.1 h1:dWV9OXCeFPuYGHb6IRqlSptVnSzOelnq
github.com/sagernet/sing-shadowsocks2 v0.2.1/go.mod h1:RnXS0lExcDAovvDeniJ4IKa2IuChrdipolPYWBv9hWQ= 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 h1:cLKe4OAOFwuhmAIuPLj//CIL7Q9js+pIDardhJ+/osk=
github.com/sagernet/sing-shadowtls v0.2.0/go.mod h1:agU+Fw5X+xnWVyRHyFthoZCX3MfWKCFPm4JUf+1oaxo= 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.9 h1:uP8O4Q7U9QesjWumgxd2S9fjT3c6aEPWl5RB6uBdVB8=
github.com/sagernet/sing-tun v0.6.8/go.mod h1:fisFCbC4Vfb6HqQNcwPJi2CDK2bf0Xapyz3j3t4cnHE= 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 h1:z6Ym8dnZG7k1fP3+54vz8G0tvRVJeOoTFFeUPwXTD44=
github.com/sagernet/sing-vmess v0.2.3/go.mod h1:jDAZ0A0St1zVRkyvhAPRySOFfhC+4SQtO5VYyeFotgA= github.com/sagernet/sing-vmess v0.2.3/go.mod h1:jDAZ0A0St1zVRkyvhAPRySOFfhC+4SQtO5VYyeFotgA=
github.com/sagernet/smux v1.5.34-mod.2 h1:gkmBjIjlJ2zQKpLigOkFur5kBKdV6bNRoFu2WkltRQ4= github.com/sagernet/smux v1.5.34-mod.2 h1:gkmBjIjlJ2zQKpLigOkFur5kBKdV6bNRoFu2WkltRQ4=

View File

@ -2,15 +2,14 @@ package route
import ( import (
"context" "context"
"errors"
"net" "net"
"time" "time"
"github.com/sagernet/sing-box/adapter" "github.com/sagernet/sing-box/adapter"
C "github.com/sagernet/sing-box/constant" C "github.com/sagernet/sing-box/constant"
dnsOutbound "github.com/sagernet/sing-box/protocol/dns" 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-dns"
"github.com/sagernet/sing-tun"
"github.com/sagernet/sing/common/buf" "github.com/sagernet/sing/common/buf"
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"
@ -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) { 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) 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")) router.dnsLogger.ErrorContext(ctx, E.Cause(err, "process packet connection"))
} }
} }

View File

@ -16,7 +16,7 @@ import (
"github.com/sagernet/sing-box/common/sniff" "github.com/sagernet/sing-box/common/sniff"
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/route/rule" R "github.com/sagernet/sing-box/route/rule"
"github.com/sagernet/sing-dns" "github.com/sagernet/sing-dns"
"github.com/sagernet/sing-mux" "github.com/sagernet/sing-mux"
"github.com/sagernet/sing-vmess" "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) err := r.routeConnection(ctx, conn, metadata, onClose)
if err != nil { if err != nil {
N.CloseOnHandshakeFailure(conn, onClose, err) N.CloseOnHandshakeFailure(conn, onClose, err)
if E.IsClosedOrCanceled(err) { if E.IsClosedOrCanceled(err) || R.IsRejected(err) {
r.logger.DebugContext(ctx, "connection closed: ", err) r.logger.DebugContext(ctx, "connection closed: ", err)
} else { } else {
r.logger.ErrorContext(ctx, err) 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 var selectedOutbound adapter.Outbound
if selectedRule != nil { if selectedRule != nil {
switch action := selectedRule.Action().(type) { switch action := selectedRule.Action().(type) {
case *rule.RuleActionRoute: case *R.RuleActionRoute:
var loaded bool var loaded bool
selectedOutbound, loaded = r.outbound.Outbound(action.Outbound) selectedOutbound, loaded = r.outbound.Outbound(action.Outbound)
if !loaded { if !loaded {
@ -112,11 +112,11 @@ func (r *Router) routeConnection(ctx context.Context, conn net.Conn, metadata ad
buf.ReleaseMulti(buffers) buf.ReleaseMulti(buffers)
return E.New("TCP is not supported by outbound: ", selectedOutbound.Tag()) return E.New("TCP is not supported by outbound: ", selectedOutbound.Tag())
} }
case *rule.RuleActionReject: case *R.RuleActionReject:
buf.ReleaseMulti(buffers) buf.ReleaseMulti(buffers)
N.CloseOnHandshakeFailure(conn, onClose, action.Error(ctx)) N.CloseOnHandshakeFailure(conn, onClose, action.Error(ctx))
return nil return nil
case *rule.RuleActionHijackDNS: case *R.RuleActionHijackDNS:
for _, buffer := range buffers { for _, buffer := range buffers {
conn = bufio.NewCachedConn(conn, buffer) conn = bufio.NewCachedConn(conn, buffer)
} }
@ -154,7 +154,7 @@ func (r *Router) RoutePacketConnection(ctx context.Context, conn N.PacketConn, m
})) }))
if err != nil { if err != nil {
conn.Close() conn.Close()
if E.IsClosedOrCanceled(err) { if E.IsClosedOrCanceled(err) || R.IsRejected(err) {
r.logger.DebugContext(ctx, "connection closed: ", err) r.logger.DebugContext(ctx, "connection closed: ", err)
} else { } else {
r.logger.ErrorContext(ctx, err) 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) err := r.routePacketConnection(ctx, conn, metadata, onClose)
if err != nil { if err != nil {
N.CloseOnHandshakeFailure(conn, onClose, err) N.CloseOnHandshakeFailure(conn, onClose, err)
if E.IsClosedOrCanceled(err) { if E.IsClosedOrCanceled(err) || R.IsRejected(err) {
r.logger.DebugContext(ctx, "connection closed: ", err) r.logger.DebugContext(ctx, "connection closed: ", err)
} else { } else {
r.logger.ErrorContext(ctx, err) r.logger.ErrorContext(ctx, err)
@ -217,7 +217,7 @@ func (r *Router) routePacketConnection(ctx context.Context, conn N.PacketConn, m
var selectReturn bool var selectReturn bool
if selectedRule != nil { if selectedRule != nil {
switch action := selectedRule.Action().(type) { switch action := selectedRule.Action().(type) {
case *rule.RuleActionRoute: case *R.RuleActionRoute:
var loaded bool var loaded bool
selectedOutbound, loaded = r.outbound.Outbound(action.Outbound) selectedOutbound, loaded = r.outbound.Outbound(action.Outbound)
if !loaded { if !loaded {
@ -228,11 +228,11 @@ func (r *Router) routePacketConnection(ctx context.Context, conn N.PacketConn, m
N.ReleaseMultiPacketBuffer(packetBuffers) N.ReleaseMultiPacketBuffer(packetBuffers)
return E.New("UDP is not supported by outbound: ", selectedOutbound.Tag()) return E.New("UDP is not supported by outbound: ", selectedOutbound.Tag())
} }
case *rule.RuleActionReject: case *R.RuleActionReject:
N.ReleaseMultiPacketBuffer(packetBuffers) N.ReleaseMultiPacketBuffer(packetBuffers)
N.CloseOnHandshakeFailure(conn, onClose, action.Error(ctx)) N.CloseOnHandshakeFailure(conn, onClose, action.Error(ctx))
return nil return nil
case *rule.RuleActionHijackDNS: case *R.RuleActionHijackDNS:
r.hijackDNSPacket(ctx, conn, packetBuffers, metadata, onClose) r.hijackDNSPacket(ctx, conn, packetBuffers, metadata, onClose)
return nil return nil
} }
@ -271,7 +271,7 @@ func (r *Router) PreMatch(metadata adapter.InboundContext) error {
if selectedRule == nil { if selectedRule == nil {
return nil return nil
} }
rejectAction, isReject := selectedRule.Action().(*rule.RuleActionReject) rejectAction, isReject := selectedRule.Action().(*R.RuleActionReject)
if !isReject { if !isReject {
return nil return nil
} }
@ -346,7 +346,7 @@ func (r *Router) matchRule(
//nolint:staticcheck //nolint:staticcheck
if metadata.InboundOptions != common.DefaultValue[option.InboundOptions]() { if metadata.InboundOptions != common.DefaultValue[option.InboundOptions]() {
if !preMatch && metadata.InboundOptions.SniffEnabled { 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, OverrideDestination: metadata.InboundOptions.SniffOverrideDestination,
Timeout: time.Duration(metadata.InboundOptions.SniffTimeout), Timeout: time.Duration(metadata.InboundOptions.SniffTimeout),
}, inputConn, inputPacketConn, nil) }, inputConn, inputPacketConn, nil)
@ -361,7 +361,7 @@ func (r *Router) matchRule(
} }
} }
if dns.DomainStrategy(metadata.InboundOptions.DomainStrategy) != dns.DomainStrategyAsIS { 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), Strategy: dns.DomainStrategy(metadata.InboundOptions.DomainStrategy),
}) })
if fatalErr != nil { if fatalErr != nil {
@ -398,11 +398,11 @@ match:
} }
} }
} }
var routeOptions *rule.RuleActionRouteOptions var routeOptions *R.RuleActionRouteOptions
switch action := currentRule.Action().(type) { switch action := currentRule.Action().(type) {
case *rule.RuleActionRoute: case *R.RuleActionRoute:
routeOptions = &action.RuleActionRouteOptions routeOptions = &action.RuleActionRouteOptions
case *rule.RuleActionRouteOptions: case *R.RuleActionRouteOptions:
routeOptions = action routeOptions = action
} }
if routeOptions != nil { if routeOptions != nil {
@ -448,7 +448,7 @@ match:
} }
} }
switch action := currentRule.Action().(type) { switch action := currentRule.Action().(type) {
case *rule.RuleActionSniff: case *R.RuleActionSniff:
if !preMatch { if !preMatch {
newBuffer, newPacketBuffers, newErr := r.actionSniff(ctx, metadata, action, inputConn, inputPacketConn, buffers) newBuffer, newPacketBuffers, newErr := r.actionSniff(ctx, metadata, action, inputConn, inputPacketConn, buffers)
if newErr != nil { if newErr != nil {
@ -465,7 +465,7 @@ match:
selectedRuleIndex = currentRuleIndex selectedRuleIndex = currentRuleIndex
break match break match
} }
case *rule.RuleActionResolve: case *R.RuleActionResolve:
fatalErr = r.actionResolve(ctx, metadata, action) fatalErr = r.actionResolve(ctx, metadata, action)
if fatalErr != nil { if fatalErr != nil {
return return
@ -485,7 +485,7 @@ match:
} }
func (r *Router) actionSniff( 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, inputConn net.Conn, inputPacketConn N.PacketConn, inputBuffers []*buf.Buffer,
) (buffer *buf.Buffer, packetBuffers []*N.PacketBuffer, fatalErr error) { ) (buffer *buf.Buffer, packetBuffers []*N.PacketBuffer, fatalErr error) {
if sniff.Skip(metadata) { if sniff.Skip(metadata) {
@ -645,7 +645,7 @@ func (r *Router) actionSniff(
return 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() { if metadata.Destination.IsFqdn() {
metadata.DNSServer = action.Server metadata.DNSServer = action.Server
addresses, err := r.Lookup(adapter.WithContext(ctx, metadata), metadata.Destination.Fqdn, action.Strategy) addresses, err := r.Lookup(adapter.WithContext(ctx, metadata), metadata.Destination.Fqdn, action.Strategy)

View File

@ -170,7 +170,7 @@ func (r *Router) Exchange(ctx context.Context, message *mDNS.Msg) (*mDNS.Msg, er
Question: []mDNS.Question{message.Question[0]}, Question: []mDNS.Question{message.Question[0]},
}, nil }, nil
case C.RuleActionRejectMethodDrop: 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: case C.RuleActionRejectMethodDefault:
return nil, nil return nil, nil
case C.RuleActionRejectMethodDrop: case C.RuleActionRejectMethodDrop:
return nil, tun.ErrDrop return nil, &R.RejectedError{Cause: tun.ErrDrop}
} }
} }
} }

View File

@ -2,6 +2,7 @@ package rule
import ( import (
"context" "context"
"errors"
"net/netip" "net/netip"
"strings" "strings"
"sync" "sync"
@ -250,6 +251,23 @@ func (r *RuleActionDirect) String() string {
return "direct" + r.description 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 { type RuleActionReject struct {
Method string Method string
NoDrop bool NoDrop bool
@ -273,9 +291,9 @@ func (r *RuleActionReject) Error(ctx context.Context) error {
var returnErr error var returnErr error
switch r.Method { switch r.Method {
case C.RuleActionRejectMethodDefault: case C.RuleActionRejectMethodDefault:
returnErr = syscall.ECONNREFUSED returnErr = &RejectedError{syscall.ECONNREFUSED}
case C.RuleActionRejectMethodDrop: case C.RuleActionRejectMethodDrop:
return tun.ErrDrop return &RejectedError{tun.ErrDrop}
default: default:
panic(F.ToString("unknown reject method: ", r.Method)) panic(F.ToString("unknown reject method: ", r.Method))
} }
@ -293,7 +311,7 @@ func (r *RuleActionReject) Error(ctx context.Context) error {
if ctx != nil { if ctx != nil {
r.logger.DebugContext(ctx, "dropped due to flooding") r.logger.DebugContext(ctx, "dropped due to flooding")
} }
return tun.ErrDrop return &RejectedError{tun.ErrDrop}
} }
return returnErr return returnErr
} }