Add proxy support for ICMP echo request

This commit is contained in:
世界
2025-02-17 22:00:57 +08:00
parent 44fafcef73
commit f84129ca79
26 changed files with 676 additions and 163 deletions

View File

@@ -16,6 +16,7 @@ import (
"github.com/sagernet/sing-box/option"
R "github.com/sagernet/sing-box/route/rule"
"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"
@@ -113,6 +114,9 @@ func (r *Router) routeConnection(ctx context.Context, conn net.Conn, metadata ad
}
case *R.RuleActionReject:
buf.ReleaseMulti(buffers)
if action.Method == C.RuleActionRejectMethodReply {
return E.New("reject method `reply` is not supported for TCP connections")
}
return action.Error(ctx)
case *R.RuleActionHijackDNS:
for _, buffer := range buffers {
@@ -228,6 +232,9 @@ func (r *Router) routePacketConnection(ctx context.Context, conn N.PacketConn, m
}
case *R.RuleActionReject:
N.ReleaseMultiPacketBuffer(packetBuffers)
if action.Method == C.RuleActionRejectMethodReply {
return E.New("reject method `reply` is not supported for UDP connections")
}
return action.Error(ctx)
case *R.RuleActionHijackDNS:
return r.hijackDNSPacket(ctx, conn, packetBuffers, metadata, onClose)
@@ -259,19 +266,47 @@ func (r *Router) routePacketConnection(ctx context.Context, conn N.PacketConn, m
return nil
}
func (r *Router) PreMatch(metadata adapter.InboundContext) error {
func (r *Router) PreMatch(metadata adapter.InboundContext, routeContext tun.DirectRouteContext, timeout time.Duration) (tun.DirectRouteDestination, error) {
selectedRule, _, _, _, err := r.matchRule(r.ctx, &metadata, true, nil, nil)
if err != nil {
return err
return nil, err
}
if selectedRule == nil {
return nil
if selectedRule != nil {
switch action := selectedRule.Action().(type) {
case *R.RuleActionReject:
switch metadata.Network {
case N.NetworkTCP:
if action.Method == C.RuleActionRejectMethodReply {
return nil, E.New("reject method `reply` is not supported for TCP connections")
}
case N.NetworkUDP:
if action.Method == C.RuleActionRejectMethodReply {
return nil, E.New("reject method `reply` is not supported for UDP connections")
}
}
return nil, action.Error(context.Background())
case *R.RuleActionRoute:
if routeContext == nil {
return nil, nil
}
outbound, loaded := r.outbound.Outbound(action.Outbound)
if !loaded {
return nil, E.New("outbound not found: ", action.Outbound)
}
if !common.Contains(outbound.Network(), metadata.Network) {
return nil, E.New(metadata.Network, " is not supported by outbound: ", action.Outbound)
}
return outbound.(adapter.DirectRouteOutbound).NewDirectRouteConnection(metadata, routeContext, timeout)
}
}
rejectAction, isReject := selectedRule.Action().(*R.RuleActionReject)
if !isReject {
return nil
if selectedRule != nil || metadata.Network != N.NetworkICMP {
return nil, nil
}
return rejectAction.Error(context.Background())
defaultOutbound := r.outbound.Default()
if !common.Contains(defaultOutbound.Network(), metadata.Network) {
return nil, E.New(metadata.Network, " is not supported by default outbound: ", defaultOutbound.Tag())
}
return defaultOutbound.(adapter.DirectRouteOutbound).NewDirectRouteConnection(metadata, routeContext, timeout)
}
func (r *Router) matchRule(
@@ -464,7 +499,7 @@ match:
fatalErr = newErr
return
}
} else {
} else if metadata.Network != N.NetworkICMP {
selectedRule = currentRule
selectedRuleIndex = currentRuleIndex
break match
@@ -478,8 +513,7 @@ match:
actionType := currentRule.Action().Type()
if actionType == C.RuleActionTypeRoute ||
actionType == C.RuleActionTypeReject ||
actionType == C.RuleActionTypeHijackDNS ||
(actionType == C.RuleActionTypeSniff && preMatch) {
actionType == C.RuleActionTypeHijackDNS {
selectedRule = currentRule
selectedRuleIndex = currentRuleIndex
break match

View File

@@ -6,7 +6,6 @@ import (
"net/netip"
"strings"
"sync"
"syscall"
"time"
"github.com/sagernet/sing-box/adapter"
@@ -325,9 +324,11 @@ func (r *RuleActionReject) Error(ctx context.Context) error {
var returnErr error
switch r.Method {
case C.RuleActionRejectMethodDefault:
returnErr = &RejectedError{syscall.ECONNREFUSED}
returnErr = &RejectedError{tun.ErrReset}
case C.RuleActionRejectMethodDrop:
return &RejectedError{tun.ErrDrop}
case C.RuleActionRejectMethodReply:
return nil
default:
panic(F.ToString("unknown reject method: ", r.Method))
}