mirror of
https://github.com/SagerNet/sing-box.git
synced 2024-12-26 13:15:39 +08:00
Implement TCP and ICMP rejects
This commit is contained in:
parent
e1eeb0d7e0
commit
d4b23cc0ab
|
@ -34,6 +34,7 @@ type Router interface {
|
||||||
FakeIPStore() FakeIPStore
|
FakeIPStore() FakeIPStore
|
||||||
|
|
||||||
ConnectionRouter
|
ConnectionRouter
|
||||||
|
PreMatch(metadata InboundContext) error
|
||||||
ConnectionRouterEx
|
ConnectionRouterEx
|
||||||
|
|
||||||
GeoIPReader() *geoip.Reader
|
GeoIPReader() *geoip.Reader
|
||||||
|
|
|
@ -34,7 +34,10 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
RuleActionRejectMethodDefault = "default"
|
RuleActionRejectMethodDefault = "default"
|
||||||
RuleActionRejectMethodPortUnreachable = "port-unreachable"
|
RuleActionRejectMethodReset = "reset"
|
||||||
RuleActionRejectMethodDrop = "drop"
|
RuleActionRejectMethodNetworkUnreachable = "network-unreachable"
|
||||||
|
RuleActionRejectMethodHostUnreachable = "host-unreachable"
|
||||||
|
RuleActionRejectMethodPortUnreachable = "port-unreachable"
|
||||||
|
RuleActionRejectMethodDrop = "drop"
|
||||||
)
|
)
|
||||||
|
|
|
@ -404,9 +404,15 @@ func (t *TUN) Close() error {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *TUN) PrepareConnection(source M.Socksaddr, destination M.Socksaddr) error {
|
func (t *TUN) PrepareConnection(network string, source M.Socksaddr, destination M.Socksaddr) error {
|
||||||
// TODO: implement rejects
|
return t.router.PreMatch(adapter.InboundContext{
|
||||||
return nil
|
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) {
|
func (t *TUN) NewConnectionEx(ctx context.Context, conn net.Conn, source M.Socksaddr, destination M.Socksaddr, onClose N.CloseHandlerFunc) {
|
||||||
|
|
|
@ -136,23 +136,29 @@ type DNSRouteActionOptions struct {
|
||||||
ClientSubnet *AddrPrefix `json:"client_subnet,omitempty"`
|
ClientSubnet *AddrPrefix `json:"client_subnet,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type RejectActionOptions struct {
|
type _RejectActionOptions struct {
|
||||||
Method RejectMethod `json:"method,omitempty"`
|
Method string `json:"method,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type RejectMethod string
|
type RejectActionOptions _RejectActionOptions
|
||||||
|
|
||||||
func (m *RejectMethod) UnmarshalJSON(bytes []byte) error {
|
func (r *RejectActionOptions) UnmarshalJSON(bytes []byte) error {
|
||||||
err := json.Unmarshal(bytes, (*string)(m))
|
err := json.Unmarshal(bytes, (*_RejectActionOptions)(r))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
switch *m {
|
switch r.Method {
|
||||||
case C.RuleActionRejectMethodDefault, C.RuleActionRejectMethodPortUnreachable, C.RuleActionRejectMethodDrop:
|
case "", C.RuleActionRejectMethodDefault:
|
||||||
return nil
|
r.Method = C.RuleActionRejectMethodDefault
|
||||||
|
case C.RuleActionRejectMethodReset,
|
||||||
|
C.RuleActionRejectMethodNetworkUnreachable,
|
||||||
|
C.RuleActionRejectMethodHostUnreachable,
|
||||||
|
C.RuleActionRejectMethodPortUnreachable,
|
||||||
|
C.RuleActionRejectMethodDrop:
|
||||||
default:
|
default:
|
||||||
return E.New("unknown reject method: " + *m)
|
return E.New("unknown reject method: " + r.Method)
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type RouteActionSniff struct {
|
type RouteActionSniff struct {
|
||||||
|
|
|
@ -21,7 +21,6 @@ import (
|
||||||
"github.com/sagernet/sing-box/route/rule"
|
"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-tun"
|
|
||||||
"github.com/sagernet/sing-vmess"
|
"github.com/sagernet/sing-vmess"
|
||||||
"github.com/sagernet/sing/common"
|
"github.com/sagernet/sing/common"
|
||||||
"github.com/sagernet/sing/common/buf"
|
"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) {
|
if deadline.NeedAdditionalReadDeadline(conn) {
|
||||||
conn = deadline.NewConn(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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -108,16 +107,7 @@ func (r *Router) routeConnection(ctx context.Context, conn net.Conn, metadata ad
|
||||||
selectReturn = true
|
selectReturn = true
|
||||||
case *rule.RuleActionReject:
|
case *rule.RuleActionReject:
|
||||||
buf.ReleaseMulti(buffers)
|
buf.ReleaseMulti(buffers)
|
||||||
var rejectErr error
|
N.CloseOnHandshakeFailure(conn, onClose, action.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)
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -236,7 +226,7 @@ func (r *Router) routePacketConnection(ctx context.Context, conn N.PacketConn, m
|
||||||
conn = deadline.NewPacketConn(bufio.NewNetPacketConn(conn))
|
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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -306,8 +296,23 @@ func (r *Router) routePacketConnection(ctx context.Context, conn N.PacketConn, m
|
||||||
return nil
|
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(
|
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,
|
inputConn net.Conn, inputPacketConn N.PacketConn, ruleIndex int,
|
||||||
) (selectedRule adapter.Rule, selectedRuleIndex int, buffers []*buf.Buffer, fatalErr error) {
|
) (selectedRule adapter.Rule, selectedRuleIndex int, buffers []*buf.Buffer, fatalErr error) {
|
||||||
if r.processSearcher != nil && metadata.ProcessInfo == nil {
|
if r.processSearcher != nil && metadata.ProcessInfo == nil {
|
||||||
|
@ -370,7 +375,7 @@ func (r *Router) matchRule(
|
||||||
|
|
||||||
//nolint:staticcheck
|
//nolint:staticcheck
|
||||||
if metadata.InboundOptions != common.DefaultValue[option.InboundOptions]() {
|
if metadata.InboundOptions != common.DefaultValue[option.InboundOptions]() {
|
||||||
if metadata.InboundOptions.SniffEnabled {
|
if !preMatch && metadata.InboundOptions.SniffEnabled {
|
||||||
newBuffers, newErr := r.actionSniff(ctx, metadata, &rule.RuleActionSniff{
|
newBuffers, newErr := r.actionSniff(ctx, metadata, &rule.RuleActionSniff{
|
||||||
OverrideDestination: metadata.InboundOptions.SniffOverrideDestination,
|
OverrideDestination: metadata.InboundOptions.SniffOverrideDestination,
|
||||||
Timeout: time.Duration(metadata.InboundOptions.SniffTimeout),
|
Timeout: time.Duration(metadata.InboundOptions.SniffTimeout),
|
||||||
|
@ -415,15 +420,28 @@ match:
|
||||||
if !matched {
|
if !matched {
|
||||||
break
|
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) {
|
switch action := currentRule.Action().(type) {
|
||||||
case *rule.RuleActionSniff:
|
case *rule.RuleActionSniff:
|
||||||
newBuffers, newErr := r.actionSniff(ctx, metadata, action, inputConn, inputPacketConn)
|
if !preMatch {
|
||||||
if newErr != nil {
|
newBuffers, newErr := r.actionSniff(ctx, metadata, action, inputConn, inputPacketConn)
|
||||||
fatalErr = newErr
|
if newErr != nil {
|
||||||
return
|
fatalErr = newErr
|
||||||
|
return
|
||||||
|
}
|
||||||
|
buffers = append(buffers, newBuffers...)
|
||||||
|
} else {
|
||||||
|
selectedRule = currentRule
|
||||||
|
selectedRuleIndex = currentRuleIndex
|
||||||
|
break match
|
||||||
}
|
}
|
||||||
buffers = append(buffers, newBuffers...)
|
|
||||||
case *rule.RuleActionResolve:
|
case *rule.RuleActionResolve:
|
||||||
fatalErr = r.actionResolve(ctx, metadata, action)
|
fatalErr = r.actionResolve(ctx, metadata, action)
|
||||||
if fatalErr != nil {
|
if fatalErr != nil {
|
||||||
|
@ -436,7 +454,7 @@ match:
|
||||||
}
|
}
|
||||||
ruleIndex = currentRuleIndex
|
ruleIndex = currentRuleIndex
|
||||||
}
|
}
|
||||||
if metadata.Destination.Addr.IsUnspecified() {
|
if !preMatch && metadata.Destination.Addr.IsUnspecified() {
|
||||||
newBuffers, newErr := r.actionSniff(ctx, metadata, &rule.RuleActionSniff{}, inputConn, inputPacketConn)
|
newBuffers, newErr := r.actionSniff(ctx, metadata, &rule.RuleActionSniff{}, inputConn, inputPacketConn)
|
||||||
if newErr != nil {
|
if newErr != nil {
|
||||||
fatalErr = newErr
|
fatalErr = newErr
|
||||||
|
|
|
@ -2,7 +2,9 @@ package rule
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net/netip"
|
"net/netip"
|
||||||
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/sagernet/sing-box/adapter"
|
"github.com/sagernet/sing-box/adapter"
|
||||||
|
@ -10,6 +12,7 @@ import (
|
||||||
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-dns"
|
"github.com/sagernet/sing-dns"
|
||||||
|
"github.com/sagernet/sing-tun"
|
||||||
E "github.com/sagernet/sing/common/exceptions"
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
F "github.com/sagernet/sing/common/format"
|
F "github.com/sagernet/sing/common/format"
|
||||||
)
|
)
|
||||||
|
@ -22,10 +25,10 @@ func NewRuleAction(action option.RuleAction) (adapter.RuleAction, error) {
|
||||||
UDPDisableDomainUnmapping: action.RouteOptions.UDPDisableDomainUnmapping,
|
UDPDisableDomainUnmapping: action.RouteOptions.UDPDisableDomainUnmapping,
|
||||||
}, nil
|
}, nil
|
||||||
case C.RuleActionTypeReturn:
|
case C.RuleActionTypeReturn:
|
||||||
return &RuleActionReject{}, nil
|
return &RuleActionReturn{}, nil
|
||||||
case C.RuleActionTypeReject:
|
case C.RuleActionTypeReject:
|
||||||
return &RuleActionReject{
|
return &RuleActionReject{
|
||||||
Method: string(action.RejectOptions.Method),
|
Method: action.RejectOptions.Method,
|
||||||
}, nil
|
}, nil
|
||||||
case C.RuleActionTypeHijackDNS:
|
case C.RuleActionTypeHijackDNS:
|
||||||
return &RuleActionHijackDNS{}, nil
|
return &RuleActionHijackDNS{}, nil
|
||||||
|
@ -58,7 +61,7 @@ func NewDNSRuleAction(action option.DNSRuleAction) adapter.RuleAction {
|
||||||
return &RuleActionReturn{}
|
return &RuleActionReturn{}
|
||||||
case C.RuleActionTypeReject:
|
case C.RuleActionTypeReject:
|
||||||
return &RuleActionReject{
|
return &RuleActionReject{
|
||||||
Method: string(action.RejectOptions.Method),
|
Method: action.RejectOptions.Method,
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
panic(F.ToString("unknown rule action: ", action.Action))
|
panic(F.ToString("unknown rule action: ", action.Action))
|
||||||
|
@ -118,6 +121,23 @@ func (r *RuleActionReject) String() string {
|
||||||
return F.ToString("reject(", r.Method, ")")
|
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{}
|
type RuleActionHijackDNS struct{}
|
||||||
|
|
||||||
func (r *RuleActionHijackDNS) Type() string {
|
func (r *RuleActionHijackDNS) Type() string {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user