Chore: delay reject
This commit is contained in:
parent
3c07ba6b56
commit
045b67524c
@ -3,6 +3,8 @@ package outbound
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
|
"net"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/Dreamacro/clash/component/dialer"
|
"github.com/Dreamacro/clash/component/dialer"
|
||||||
"github.com/Dreamacro/clash/component/trie"
|
"github.com/Dreamacro/clash/component/trie"
|
||||||
@ -12,50 +14,50 @@ import (
|
|||||||
var (
|
var (
|
||||||
errIgnored = errors.New("not match in mitm host lists")
|
errIgnored = errors.New("not match in mitm host lists")
|
||||||
httpProxyClient = NewHttp(HttpOption{})
|
httpProxyClient = NewHttp(HttpOption{})
|
||||||
|
rewriteHosts *trie.DomainTrie[bool]
|
||||||
MiddlemanRewriteHosts *trie.DomainTrie[bool]
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type Mitm struct {
|
type Mitm struct {
|
||||||
*Base
|
*Base
|
||||||
serverAddr string
|
serverAddr *net.TCPAddr
|
||||||
}
|
}
|
||||||
|
|
||||||
// DialContext implements C.ProxyAdapter
|
// DialContext implements C.ProxyAdapter
|
||||||
func (m *Mitm) DialContext(ctx context.Context, metadata *C.Metadata, _ ...dialer.Option) (C.Conn, error) {
|
func (m *Mitm) DialContext(_ context.Context, metadata *C.Metadata, _ ...dialer.Option) (C.Conn, error) {
|
||||||
if MiddlemanRewriteHosts == nil {
|
if (rewriteHosts == nil || rewriteHosts.Search(metadata.String()) == nil) && metadata.DstPort != "80" {
|
||||||
return nil, errIgnored
|
return nil, errIgnored
|
||||||
}
|
}
|
||||||
|
|
||||||
if MiddlemanRewriteHosts.Search(metadata.String()) == nil && metadata.DstPort != "80" {
|
c, err := net.DialTCP("tcp", nil, m.serverAddr)
|
||||||
return nil, errIgnored
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_ = c.SetKeepAlive(true)
|
||||||
|
_ = c.SetKeepAlivePeriod(60 * time.Second)
|
||||||
|
|
||||||
metadata.Type = C.MITM
|
metadata.Type = C.MITM
|
||||||
|
|
||||||
c, err := dialer.DialContext(ctx, "tcp", m.serverAddr, []dialer.Option{dialer.WithInterface(""), dialer.WithRoutingMark(0), dialer.WithDirect()}...)
|
hc, err := httpProxyClient.StreamConn(c, metadata)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
_ = c.Close()
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
tcpKeepAlive(c)
|
return NewConn(hc, m), nil
|
||||||
|
|
||||||
defer safeConnClose(c, err)
|
|
||||||
|
|
||||||
c, err = httpProxyClient.StreamConn(c, metadata)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return NewConn(c, m), nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewMitm(serverAddr string) *Mitm {
|
func NewMitm(serverAddr string) *Mitm {
|
||||||
|
tcpAddr, _ := net.ResolveTCPAddr("tcp", serverAddr)
|
||||||
return &Mitm{
|
return &Mitm{
|
||||||
Base: &Base{
|
Base: &Base{
|
||||||
name: "Mitm",
|
name: "Mitm",
|
||||||
tp: C.Mitm,
|
tp: C.Mitm,
|
||||||
},
|
},
|
||||||
serverAddr: serverAddr,
|
serverAddr: tcpAddr,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func UpdateRewriteHosts(hosts *trie.DomainTrie[bool]) {
|
||||||
|
rewriteHosts = hosts
|
||||||
|
}
|
||||||
|
@ -6,16 +6,43 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/Dreamacro/clash/common/cache"
|
||||||
"github.com/Dreamacro/clash/component/dialer"
|
"github.com/Dreamacro/clash/component/dialer"
|
||||||
C "github.com/Dreamacro/clash/constant"
|
C "github.com/Dreamacro/clash/constant"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
rejectCountLimit = 50
|
||||||
|
rejectDelay = time.Second * 35
|
||||||
|
)
|
||||||
|
|
||||||
|
var rejectCounter = cache.NewLRUCache[string, int](cache.WithAge[string, int](15), cache.WithStale[string, int](false), cache.WithSize[string, int](512))
|
||||||
|
|
||||||
type Reject struct {
|
type Reject struct {
|
||||||
*Base
|
*Base
|
||||||
}
|
}
|
||||||
|
|
||||||
// DialContext implements C.ProxyAdapter
|
// DialContext implements C.ProxyAdapter
|
||||||
func (r *Reject) DialContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (C.Conn, error) {
|
func (r *Reject) DialContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (C.Conn, error) {
|
||||||
|
key := metadata.RemoteAddress()
|
||||||
|
|
||||||
|
count, existed := rejectCounter.Get(key)
|
||||||
|
if !existed {
|
||||||
|
count = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
count = count + 1
|
||||||
|
|
||||||
|
rejectCounter.Set(key, count)
|
||||||
|
|
||||||
|
if count > rejectCountLimit {
|
||||||
|
c, _ := net.Pipe()
|
||||||
|
|
||||||
|
_ = c.SetDeadline(time.Now().Add(rejectDelay))
|
||||||
|
|
||||||
|
return NewConn(c, r), nil
|
||||||
|
}
|
||||||
|
|
||||||
return NewConn(&nopConn{}, r), nil
|
return NewConn(&nopConn{}, r), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -333,7 +333,7 @@ func updateIPTables(cfg *config.Config) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func updateMitm(mitm *config.Mitm) {
|
func updateMitm(mitm *config.Mitm) {
|
||||||
outbound.MiddlemanRewriteHosts = mitm.Hosts
|
outbound.UpdateRewriteHosts(mitm.Hosts)
|
||||||
tunnel.UpdateRewrites(mitm.Rules)
|
tunnel.UpdateRewrites(mitm.Rules)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -347,11 +347,11 @@ func ReCreateTun(tunConf *config.Tun, tunAddressPrefix *netip.Prefix, tcpIn chan
|
|||||||
tunAddressPrefix = lastTunAddressPrefix
|
tunAddressPrefix = lastTunAddressPrefix
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if tunStackListener != nil {
|
||||||
if !hasTunConfigChange(tunConf, tunAddressPrefix) {
|
if !hasTunConfigChange(tunConf, tunAddressPrefix) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if tunStackListener != nil {
|
|
||||||
_ = tunStackListener.Close()
|
_ = tunStackListener.Close()
|
||||||
tunStackListener = nil
|
tunStackListener = nil
|
||||||
lastTunConf = nil
|
lastTunConf = nil
|
||||||
@ -388,9 +388,9 @@ func ReCreateMitm(port int, tcpIn chan<- C.ConnContext) {
|
|||||||
if mitmListener.RawAddress() == addr {
|
if mitmListener.RawAddress() == addr {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
tunnel.MitmOutbound = nil
|
|
||||||
_ = mitmListener.Close()
|
_ = mitmListener.Close()
|
||||||
mitmListener = nil
|
mitmListener = nil
|
||||||
|
tunnel.SetMitmOutbound(nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
if portIsZero(addr) {
|
if portIsZero(addr) {
|
||||||
@ -442,7 +442,7 @@ func ReCreateMitm(port int, tcpIn chan<- C.ConnContext) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
tunnel.MitmOutbound = outbound.NewMitm(mitmListener.Address())
|
tunnel.SetMitmOutbound(outbound.NewMitm(mitmListener.Address()))
|
||||||
|
|
||||||
log.Infoln("Mitm proxy listening at: %s", mitmListener.Address())
|
log.Infoln("Mitm proxy listening at: %s", mitmListener.Address())
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,6 @@
|
|||||||
package rewrites
|
package rewrites
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"fmt"
|
|
||||||
"image"
|
|
||||||
"image/color"
|
|
||||||
"image/draw"
|
|
||||||
"image/png"
|
|
||||||
"regexp"
|
"regexp"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
@ -41,16 +35,3 @@ func TestParseRewrite(t *testing.T) {
|
|||||||
assert.Equal(t, c2.RuleRegx(), regexp.MustCompile(`(\r\n)User-Agent:.+(\r\n)`))
|
assert.Equal(t, c2.RuleRegx(), regexp.MustCompile(`(\r\n)User-Agent:.+(\r\n)`))
|
||||||
assert.Equal(t, c2.RulePayload(), "$1User-Agent: Fuck-Who$2")
|
assert.Equal(t, c2.RulePayload(), "$1User-Agent: Fuck-Who$2")
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test1PxPNG(t *testing.T) {
|
|
||||||
m := image.NewRGBA(image.Rect(0, 0, 1, 1))
|
|
||||||
|
|
||||||
draw.Draw(m, m.Bounds(), &image.Uniform{C: color.Transparent}, image.Point{}, draw.Src)
|
|
||||||
|
|
||||||
buf := &bytes.Buffer{}
|
|
||||||
|
|
||||||
assert.Nil(t, png.Encode(buf, m))
|
|
||||||
|
|
||||||
fmt.Printf("len: %d\n", buf.Len())
|
|
||||||
fmt.Printf("% #x\n", buf.Bytes())
|
|
||||||
}
|
|
||||||
|
@ -38,8 +38,8 @@ var (
|
|||||||
// default timeout for UDP session
|
// default timeout for UDP session
|
||||||
udpTimeout = 60 * time.Second
|
udpTimeout = 60 * time.Second
|
||||||
|
|
||||||
// MitmOutbound mitm proxy adapter
|
// mitmOutbound mitm proxy adapter
|
||||||
MitmOutbound C.ProxyAdapter
|
mitmOutbound C.ProxyAdapter
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
@ -96,6 +96,11 @@ func SetMode(m TunnelMode) {
|
|||||||
mode = m
|
mode = m
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetMitmOutbound set the MITM outbound
|
||||||
|
func SetMitmOutbound(outbound C.ProxyAdapter) {
|
||||||
|
mitmOutbound = outbound
|
||||||
|
}
|
||||||
|
|
||||||
// Rewrites return all rewrites
|
// Rewrites return all rewrites
|
||||||
func Rewrites() C.RewriteRule {
|
func Rewrites() C.RewriteRule {
|
||||||
return rewrites
|
return rewrites
|
||||||
@ -302,9 +307,11 @@ func handleTCPConn(connCtx C.ConnContext) {
|
|||||||
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), C.DefaultTCPTimeout)
|
ctx, cancel := context.WithTimeout(context.Background(), C.DefaultTCPTimeout)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
if MitmOutbound != nil && metadata.Type != C.MITM {
|
|
||||||
if remoteConn, err1 := MitmOutbound.DialContext(ctx, metadata); err1 == nil {
|
if mitmOutbound != nil && metadata.Type != C.MITM {
|
||||||
|
if remoteConn, err1 := mitmOutbound.DialContext(ctx, metadata); err1 == nil {
|
||||||
remoteConn = statistic.NewSniffing(remoteConn, metadata, nil)
|
remoteConn = statistic.NewSniffing(remoteConn, metadata, nil)
|
||||||
|
|
||||||
defer func(remoteConn C.Conn) {
|
defer func(remoteConn C.Conn) {
|
||||||
_ = remoteConn.Close()
|
_ = remoteConn.Close()
|
||||||
}(remoteConn)
|
}(remoteConn)
|
||||||
@ -329,7 +336,11 @@ func handleTCPConn(connCtx C.ConnContext) {
|
|||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if remoteConn.Chains().Last() != "REJECT" {
|
||||||
remoteConn = statistic.NewTCPTracker(remoteConn, statistic.DefaultManager, metadata, rule)
|
remoteConn = statistic.NewTCPTracker(remoteConn, statistic.DefaultManager, metadata, rule)
|
||||||
|
}
|
||||||
|
|
||||||
defer func(remoteConn C.Conn) {
|
defer func(remoteConn C.Conn) {
|
||||||
_ = remoteConn.Close()
|
_ = remoteConn.Close()
|
||||||
}(remoteConn)
|
}(remoteConn)
|
||||||
|
Reference in New Issue
Block a user