Skip to content

Commit

Permalink
Implement TCP and ICMP rejects
Browse files Browse the repository at this point in the history
  • Loading branch information
nekohasekai committed Oct 22, 2024
1 parent 0b5c32a commit 45b8deb
Show file tree
Hide file tree
Showing 9 changed files with 98 additions and 45 deletions.
1 change: 1 addition & 0 deletions adapter/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ type Router interface {
FakeIPStore() FakeIPStore

ConnectionRouter
PreMatch(metadata InboundContext) error
ConnectionRouterEx

GeoIPReader() *geoip.Reader
Expand Down
9 changes: 6 additions & 3 deletions constant/rule.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
)
3 changes: 2 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -56,6 +56,7 @@ require (
)

//replace github.com/sagernet/sing => ../sing
replace github.com/sagernet/sing-tun => ../sing-tun

require (
github.com/ajg/form v1.5.1 // indirect
Expand Down
2 changes: 0 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -129,8 +129,6 @@ 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-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=
Expand Down
12 changes: 9 additions & 3 deletions inbound/tun.go
Original file line number Diff line number Diff line change
Expand Up @@ -393,9 +393,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) {
Expand Down
24 changes: 15 additions & 9 deletions option/rule_action.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
64 changes: 41 additions & 23 deletions route/route.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package route
import (
"context"
"errors"
"github.com/sagernet/sing/common/bufio/deadline"
"net"
"net/netip"
"os"
Expand All @@ -22,11 +21,11 @@ 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"
"github.com/sagernet/sing/common/bufio"
"github.com/sagernet/sing/common/bufio/deadline"
E "github.com/sagernet/sing/common/exceptions"
F "github.com/sagernet/sing/common/format"
M "github.com/sagernet/sing/common/metadata"
Expand Down Expand Up @@ -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
}
Expand All @@ -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
}
}
Expand Down Expand Up @@ -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
}
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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),
Expand Down Expand Up @@ -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 {
Expand All @@ -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
Expand Down
26 changes: 23 additions & 3 deletions route/rule/rule_action.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,17 @@ package rule

import (
"net/netip"
"os"
"strings"
"syscall"
"time"

"github.com/sagernet/sing-box/adapter"
"github.com/sagernet/sing-box/common/sniff"
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"
)
Expand All @@ -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
Expand Down Expand Up @@ -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))
Expand Down Expand Up @@ -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 {
Expand Down
2 changes: 1 addition & 1 deletion test/clash_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
"crypto/md5"
"crypto/rand"
"errors"
"github.com/docker/docker/api/types/image"
"io"
"net"
_ "net/http/pprof"
Expand All @@ -18,6 +17,7 @@ import (
"github.com/sagernet/sing/common/control"
F "github.com/sagernet/sing/common/format"

"github.com/docker/docker/api/types/image"
"github.com/docker/docker/client"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
Expand Down

0 comments on commit 45b8deb

Please sign in to comment.