瀏覽代碼

Implement TCP and ICMP rejects

世界 1 年之前
父節點
當前提交
4da652ff02
共有 8 個文件被更改,包括 97 次插入43 次删除
  1. 1 0
      adapter/router.go
  2. 6 3
      constant/rule.go
  3. 1 1
      go.mod
  4. 2 2
      go.sum
  5. 9 3
      inbound/tun.go
  6. 15 9
      option/rule_action.go
  7. 40 22
      route/route.go
  8. 23 3
      route/rule/rule_action.go

+ 1 - 0
adapter/router.go

@@ -34,6 +34,7 @@ type Router interface {
 	FakeIPStore() FakeIPStore
 
 	ConnectionRouter
+	PreMatch(metadata InboundContext) error
 	ConnectionRouterEx
 
 	GeoIPReader() *geoip.Reader

+ 6 - 3
constant/rule.go

@@ -33,7 +33,10 @@ const (
 )
 
 const (
-	RuleActionRejectMethodDefault         = "default"
-	RuleActionRejectMethodPortUnreachable = "port-unreachable"
-	RuleActionRejectMethodDrop            = "drop"
+	RuleActionRejectMethodDefault            = "default"
+	RuleActionRejectMethodReset              = "reset"
+	RuleActionRejectMethodNetworkUnreachable = "network-unreachable"
+	RuleActionRejectMethodHostUnreachable    = "host-unreachable"
+	RuleActionRejectMethodPortUnreachable    = "port-unreachable"
+	RuleActionRejectMethodDrop               = "drop"
 )

+ 1 - 1
go.mod

@@ -34,7 +34,7 @@ require (
 	github.com/sagernet/sing-shadowsocks v0.2.7
 	github.com/sagernet/sing-shadowsocks2 v0.2.0
 	github.com/sagernet/sing-shadowtls v0.1.4
-	github.com/sagernet/sing-tun v0.4.0-rc.4.0.20241021153919-9ae45181180d
+	github.com/sagernet/sing-tun v0.4.0-rc.4.0.20241022132441-8ae8c915af9e
 	github.com/sagernet/sing-vmess v0.1.12
 	github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7
 	github.com/sagernet/utls v1.6.7

+ 2 - 2
go.sum

@@ -129,8 +129,8 @@ github.com/sagernet/sing-shadowsocks2 v0.2.0 h1:wpZNs6wKnR7mh1wV9OHwOyUr21VkS3wK
 github.com/sagernet/sing-shadowsocks2 v0.2.0/go.mod h1:RnXS0lExcDAovvDeniJ4IKa2IuChrdipolPYWBv9hWQ=
 github.com/sagernet/sing-shadowtls v0.1.4 h1:aTgBSJEgnumzFenPvc+kbD9/W0PywzWevnVpEx6Tw3k=
 github.com/sagernet/sing-shadowtls v0.1.4/go.mod h1:F8NBgsY5YN2beQavdgdm1DPlhaKQlaL6lpDdcBglGK4=
-github.com/sagernet/sing-tun v0.4.0-rc.4.0.20241021153919-9ae45181180d h1:zWcIQM3eAKJGzy7zhqkO7zm7ZI890OdR4vSwx2mevS0=
-github.com/sagernet/sing-tun v0.4.0-rc.4.0.20241021153919-9ae45181180d/go.mod h1:Xhv+Mz2nE7HZTwResni8EtTa7AMJz/S6uQLT5lV23M8=
+github.com/sagernet/sing-tun v0.4.0-rc.4.0.20241022132441-8ae8c915af9e h1:dKvwQKyNc6/tfwsCU3vlvZo1zwGC9ztsJ3qiQghhBpA=
+github.com/sagernet/sing-tun v0.4.0-rc.4.0.20241022132441-8ae8c915af9e/go.mod h1:ZDv85YIANyV7ZTuHx9Vn3dBiEBjuOnebVrL7ccXC9CM=
 github.com/sagernet/sing-vmess v0.1.12 h1:2gFD8JJb+eTFMoa8FIVMnknEi+vCSfaiTXTfEYAYAPg=
 github.com/sagernet/sing-vmess v0.1.12/go.mod h1:luTSsfyBGAc9VhtCqwjR+dt1QgqBhuYBCONB/POhF8I=
 github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7 h1:DImB4lELfQhplLTxeq2z31Fpv8CQqqrUwTbrIRumZqQ=

+ 9 - 3
inbound/tun.go

@@ -405,9 +405,15 @@ func (t *TUN) Close() error {
 	)
 }
 
-func (t *TUN) PrepareConnection(source M.Socksaddr, destination M.Socksaddr) error {
-	// TODO: implement rejects
-	return nil
+func (t *TUN) PrepareConnection(network string, source M.Socksaddr, destination M.Socksaddr) error {
+	return t.router.PreMatch(adapter.InboundContext{
+		Inbound:        t.tag,
+		InboundType:    C.TypeTun,
+		Network:        network,
+		Source:         source,
+		Destination:    destination,
+		InboundOptions: t.inboundOptions,
+	})
 }
 
 func (t *TUN) NewConnectionEx(ctx context.Context, conn net.Conn, source M.Socksaddr, destination M.Socksaddr, onClose N.CloseHandlerFunc) {

+ 15 - 9
option/rule_action.go

@@ -136,23 +136,29 @@ type DNSRouteActionOptions struct {
 	ClientSubnet *AddrPrefix `json:"client_subnet,omitempty"`
 }
 
-type RejectActionOptions struct {
-	Method RejectMethod `json:"method,omitempty"`
+type _RejectActionOptions struct {
+	Method string `json:"method,omitempty"`
 }
 
-type RejectMethod string
+type RejectActionOptions _RejectActionOptions
 
-func (m *RejectMethod) UnmarshalJSON(bytes []byte) error {
-	err := json.Unmarshal(bytes, (*string)(m))
+func (r *RejectActionOptions) UnmarshalJSON(bytes []byte) error {
+	err := json.Unmarshal(bytes, (*_RejectActionOptions)(r))
 	if err != nil {
 		return err
 	}
-	switch *m {
-	case C.RuleActionRejectMethodDefault, C.RuleActionRejectMethodPortUnreachable, C.RuleActionRejectMethodDrop:
-		return nil
+	switch r.Method {
+	case "", C.RuleActionRejectMethodDefault:
+		r.Method = C.RuleActionRejectMethodDefault
+	case C.RuleActionRejectMethodReset,
+		C.RuleActionRejectMethodNetworkUnreachable,
+		C.RuleActionRejectMethodHostUnreachable,
+		C.RuleActionRejectMethodPortUnreachable,
+		C.RuleActionRejectMethodDrop:
 	default:
-		return E.New("unknown reject method: " + *m)
+		return E.New("unknown reject method: " + r.Method)
 	}
+	return nil
 }
 
 type RouteActionSniff struct {

+ 40 - 22
route/route.go

@@ -21,7 +21,6 @@ import (
 	"github.com/sagernet/sing-box/route/rule"
 	"github.com/sagernet/sing-dns"
 	"github.com/sagernet/sing-mux"
-	"github.com/sagernet/sing-tun"
 	"github.com/sagernet/sing-vmess"
 	"github.com/sagernet/sing/common"
 	"github.com/sagernet/sing/common/buf"
@@ -89,7 +88,7 @@ func (r *Router) routeConnection(ctx context.Context, conn net.Conn, metadata ad
 	if deadline.NeedAdditionalReadDeadline(conn) {
 		conn = deadline.NewConn(conn)
 	}
-	selectedRule, _, buffers, err := r.matchRule(ctx, &metadata, conn, nil, -1)
+	selectedRule, _, buffers, err := r.matchRule(ctx, &metadata, false, conn, nil, -1)
 	if err != nil {
 		return err
 	}
@@ -108,16 +107,7 @@ func (r *Router) routeConnection(ctx context.Context, conn net.Conn, metadata ad
 			selectReturn = true
 		case *rule.RuleActionReject:
 			buf.ReleaseMulti(buffers)
-			var rejectErr error
-			switch action.Method {
-			case C.RuleActionRejectMethodDefault:
-				rejectErr = os.ErrClosed
-			case C.RuleActionRejectMethodPortUnreachable:
-				rejectErr = syscall.ECONNREFUSED
-			case C.RuleActionRejectMethodDrop:
-				rejectErr = tun.ErrDrop
-			}
-			N.CloseOnHandshakeFailure(conn, onClose, rejectErr)
+			N.CloseOnHandshakeFailure(conn, onClose, action.Error())
 			return nil
 		}
 	}
@@ -236,7 +226,7 @@ func (r *Router) routePacketConnection(ctx context.Context, conn N.PacketConn, m
 		conn = deadline.NewPacketConn(bufio.NewNetPacketConn(conn))
 	}*/
 
-	selectedRule, _, buffers, err := r.matchRule(ctx, &metadata, nil, conn, -1)
+	selectedRule, _, buffers, err := r.matchRule(ctx, &metadata, false, nil, conn, -1)
 	if err != nil {
 		return err
 	}
@@ -306,8 +296,23 @@ func (r *Router) routePacketConnection(ctx context.Context, conn N.PacketConn, m
 	return nil
 }
 
+func (r *Router) PreMatch(metadata adapter.InboundContext) error {
+	selectedRule, _, _, err := r.matchRule(r.ctx, &metadata, true, nil, nil, -1)
+	if err != nil {
+		return err
+	}
+	if selectedRule == nil {
+		return nil
+	}
+	rejectAction, isReject := selectedRule.Action().(*rule.RuleActionReject)
+	if !isReject {
+		return nil
+	}
+	return rejectAction.Error()
+}
+
 func (r *Router) matchRule(
-	ctx context.Context, metadata *adapter.InboundContext,
+	ctx context.Context, metadata *adapter.InboundContext, preMatch bool,
 	inputConn net.Conn, inputPacketConn N.PacketConn, ruleIndex int,
 ) (selectedRule adapter.Rule, selectedRuleIndex int, buffers []*buf.Buffer, fatalErr error) {
 	if r.processSearcher != nil && metadata.ProcessInfo == nil {
@@ -370,7 +375,7 @@ func (r *Router) matchRule(
 
 	//nolint:staticcheck
 	if metadata.InboundOptions != common.DefaultValue[option.InboundOptions]() {
-		if metadata.InboundOptions.SniffEnabled {
+		if !preMatch && metadata.InboundOptions.SniffEnabled {
 			newBuffers, newErr := r.actionSniff(ctx, metadata, &rule.RuleActionSniff{
 				OverrideDestination: metadata.InboundOptions.SniffOverrideDestination,
 				Timeout:             time.Duration(metadata.InboundOptions.SniffTimeout),
@@ -415,15 +420,28 @@ match:
 		if !matched {
 			break
 		}
-		r.logger.DebugContext(ctx, "match[", currentRuleIndex, "] ", currentRule, " => ", currentRule.Action())
+		if !preMatch {
+			r.logger.DebugContext(ctx, "match[", currentRuleIndex, "] ", currentRule, " => ", currentRule.Action())
+		} else {
+			switch currentRule.Action().Type() {
+			case C.RuleActionTypeReject, C.RuleActionTypeResolve:
+				r.logger.DebugContext(ctx, "pre-match[", currentRuleIndex, "] ", currentRule, " => ", currentRule.Action())
+			}
+		}
 		switch action := currentRule.Action().(type) {
 		case *rule.RuleActionSniff:
-			newBuffers, newErr := r.actionSniff(ctx, metadata, action, inputConn, inputPacketConn)
-			if newErr != nil {
-				fatalErr = newErr
-				return
+			if !preMatch {
+				newBuffers, newErr := r.actionSniff(ctx, metadata, action, inputConn, inputPacketConn)
+				if newErr != nil {
+					fatalErr = newErr
+					return
+				}
+				buffers = append(buffers, newBuffers...)
+			} else {
+				selectedRule = currentRule
+				selectedRuleIndex = currentRuleIndex
+				break match
 			}
-			buffers = append(buffers, newBuffers...)
 		case *rule.RuleActionResolve:
 			fatalErr = r.actionResolve(ctx, metadata, action)
 			if fatalErr != nil {
@@ -436,7 +454,7 @@ match:
 		}
 		ruleIndex = currentRuleIndex
 	}
-	if metadata.Destination.Addr.IsUnspecified() {
+	if !preMatch && metadata.Destination.Addr.IsUnspecified() {
 		newBuffers, newErr := r.actionSniff(ctx, metadata, &rule.RuleActionSniff{}, inputConn, inputPacketConn)
 		if newErr != nil {
 			fatalErr = newErr

+ 23 - 3
route/rule/rule_action.go

@@ -2,7 +2,9 @@ package rule
 
 import (
 	"net/netip"
+	"os"
 	"strings"
+	"syscall"
 	"time"
 
 	"github.com/sagernet/sing-box/adapter"
@@ -10,6 +12,7 @@ import (
 	C "github.com/sagernet/sing-box/constant"
 	"github.com/sagernet/sing-box/option"
 	"github.com/sagernet/sing-dns"
+	"github.com/sagernet/sing-tun"
 	E "github.com/sagernet/sing/common/exceptions"
 	F "github.com/sagernet/sing/common/format"
 )
@@ -22,10 +25,10 @@ func NewRuleAction(action option.RuleAction) (adapter.RuleAction, error) {
 			UDPDisableDomainUnmapping: action.RouteOptions.UDPDisableDomainUnmapping,
 		}, nil
 	case C.RuleActionTypeReturn:
-		return &RuleActionReject{}, nil
+		return &RuleActionReturn{}, nil
 	case C.RuleActionTypeReject:
 		return &RuleActionReject{
-			Method: string(action.RejectOptions.Method),
+			Method: action.RejectOptions.Method,
 		}, nil
 	case C.RuleActionTypeHijackDNS:
 		return &RuleActionHijackDNS{}, nil
@@ -58,7 +61,7 @@ func NewDNSRuleAction(action option.DNSRuleAction) adapter.RuleAction {
 		return &RuleActionReturn{}
 	case C.RuleActionTypeReject:
 		return &RuleActionReject{
-			Method: string(action.RejectOptions.Method),
+			Method: action.RejectOptions.Method,
 		}
 	default:
 		panic(F.ToString("unknown rule action: ", action.Action))
@@ -118,6 +121,23 @@ func (r *RuleActionReject) String() string {
 	return F.ToString("reject(", r.Method, ")")
 }
 
+func (r *RuleActionReject) Error() error {
+	switch r.Method {
+	case C.RuleActionRejectMethodReset:
+		return os.ErrClosed
+	case C.RuleActionRejectMethodNetworkUnreachable:
+		return syscall.ENETUNREACH
+	case C.RuleActionRejectMethodHostUnreachable:
+		return syscall.EHOSTUNREACH
+	case C.RuleActionRejectMethodDefault, C.RuleActionRejectMethodPortUnreachable:
+		return syscall.ECONNREFUSED
+	case C.RuleActionRejectMethodDrop:
+		return tun.ErrDrop
+	default:
+		panic(F.ToString("unknown reject method: ", r.Method))
+	}
+}
+
 type RuleActionHijackDNS struct{}
 
 func (r *RuleActionHijackDNS) Type() string {