Chore: merge branch 'with-tun' into plus-pro
This commit is contained in:
commit
9ffcc9e352
@ -3,6 +3,8 @@ package outbound
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"net"
|
||||
"time"
|
||||
|
||||
"github.com/Dreamacro/clash/component/dialer"
|
||||
"github.com/Dreamacro/clash/component/trie"
|
||||
@ -12,50 +14,50 @@ import (
|
||||
var (
|
||||
errIgnored = errors.New("not match in mitm host lists")
|
||||
httpProxyClient = NewHttp(HttpOption{})
|
||||
|
||||
MiddlemanRewriteHosts *trie.DomainTrie[bool]
|
||||
rewriteHosts *trie.DomainTrie[bool]
|
||||
)
|
||||
|
||||
type Mitm struct {
|
||||
*Base
|
||||
serverAddr string
|
||||
serverAddr *net.TCPAddr
|
||||
}
|
||||
|
||||
// DialContext implements C.ProxyAdapter
|
||||
func (m *Mitm) DialContext(ctx context.Context, metadata *C.Metadata, _ ...dialer.Option) (C.Conn, error) {
|
||||
if MiddlemanRewriteHosts == nil {
|
||||
func (m *Mitm) DialContext(_ context.Context, metadata *C.Metadata, _ ...dialer.Option) (C.Conn, error) {
|
||||
if (rewriteHosts == nil || rewriteHosts.Search(metadata.String()) == nil) && metadata.DstPort != "80" {
|
||||
return nil, errIgnored
|
||||
}
|
||||
|
||||
if MiddlemanRewriteHosts.Search(metadata.String()) == nil && metadata.DstPort != "80" {
|
||||
return nil, errIgnored
|
||||
c, err := net.DialTCP("tcp", nil, m.serverAddr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
_ = c.SetKeepAlive(true)
|
||||
_ = c.SetKeepAlivePeriod(60 * time.Second)
|
||||
|
||||
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 {
|
||||
_ = c.Close()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tcpKeepAlive(c)
|
||||
|
||||
defer safeConnClose(c, err)
|
||||
|
||||
c, err = httpProxyClient.StreamConn(c, metadata)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return NewConn(c, m), nil
|
||||
return NewConn(hc, m), nil
|
||||
}
|
||||
|
||||
func NewMitm(serverAddr string) *Mitm {
|
||||
tcpAddr, _ := net.ResolveTCPAddr("tcp", serverAddr)
|
||||
return &Mitm{
|
||||
Base: &Base{
|
||||
name: "Mitm",
|
||||
tp: C.Mitm,
|
||||
},
|
||||
serverAddr: serverAddr,
|
||||
serverAddr: tcpAddr,
|
||||
}
|
||||
}
|
||||
|
||||
func UpdateRewriteHosts(hosts *trie.DomainTrie[bool]) {
|
||||
rewriteHosts = hosts
|
||||
}
|
||||
|
@ -6,16 +6,43 @@ import (
|
||||
"net"
|
||||
"time"
|
||||
|
||||
"github.com/Dreamacro/clash/common/cache"
|
||||
"github.com/Dreamacro/clash/component/dialer"
|
||||
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 {
|
||||
*Base
|
||||
}
|
||||
|
||||
// DialContext implements C.ProxyAdapter
|
||||
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
|
||||
}
|
||||
|
||||
|
@ -339,7 +339,7 @@ func updateIPTables(cfg *config.Config) {
|
||||
}
|
||||
|
||||
func updateMitm(mitm *config.Mitm) {
|
||||
outbound.MiddlemanRewriteHosts = mitm.Hosts
|
||||
outbound.UpdateRewriteHosts(mitm.Hosts)
|
||||
tunnel.UpdateRewrites(mitm.Rules)
|
||||
}
|
||||
|
||||
|
@ -71,7 +71,10 @@ type Ports struct {
|
||||
func GetTunConf() config.Tun {
|
||||
if lastTunConf == nil {
|
||||
return config.Tun{
|
||||
Enable: false,
|
||||
Enable: false,
|
||||
Stack: C.TunGvisor,
|
||||
DNSHijack: []netip.AddrPort{netip.MustParseAddrPort("0.0.0.0:53")},
|
||||
AutoRoute: true,
|
||||
}
|
||||
}
|
||||
return *lastTunConf
|
||||
@ -347,17 +350,18 @@ func ReCreateTun(tunConf *config.Tun, tunAddressPrefix *netip.Prefix, tcpIn chan
|
||||
tunAddressPrefix = lastTunAddressPrefix
|
||||
}
|
||||
|
||||
if !hasTunConfigChange(tunConf, tunAddressPrefix) {
|
||||
return
|
||||
}
|
||||
|
||||
if tunStackListener != nil {
|
||||
if !hasTunConfigChange(tunConf, tunAddressPrefix) {
|
||||
return
|
||||
}
|
||||
|
||||
_ = tunStackListener.Close()
|
||||
tunStackListener = nil
|
||||
lastTunConf = nil
|
||||
lastTunAddressPrefix = nil
|
||||
}
|
||||
|
||||
lastTunConf = tunConf
|
||||
lastTunAddressPrefix = tunAddressPrefix
|
||||
|
||||
if !tunConf.Enable {
|
||||
return
|
||||
}
|
||||
@ -366,9 +370,6 @@ func ReCreateTun(tunConf *config.Tun, tunAddressPrefix *netip.Prefix, tcpIn chan
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
lastTunConf = tunConf
|
||||
lastTunAddressPrefix = tunAddressPrefix
|
||||
}
|
||||
|
||||
func ReCreateMitm(port int, tcpIn chan<- C.ConnContext) {
|
||||
@ -388,9 +389,9 @@ func ReCreateMitm(port int, tcpIn chan<- C.ConnContext) {
|
||||
if mitmListener.RawAddress() == addr {
|
||||
return
|
||||
}
|
||||
tunnel.MitmOutbound = nil
|
||||
_ = mitmListener.Close()
|
||||
mitmListener = nil
|
||||
tunnel.SetMitmOutbound(nil)
|
||||
}
|
||||
|
||||
if portIsZero(addr) {
|
||||
@ -442,7 +443,7 @@ func ReCreateMitm(port int, tcpIn chan<- C.ConnContext) {
|
||||
return
|
||||
}
|
||||
|
||||
tunnel.MitmOutbound = outbound.NewMitm(mitmListener.Address())
|
||||
tunnel.SetMitmOutbound(outbound.NewMitm(mitmListener.Address()))
|
||||
|
||||
log.Infoln("Mitm proxy listening at: %s", mitmListener.Address())
|
||||
}
|
||||
|
@ -1,12 +1,6 @@
|
||||
package rewrites
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"image"
|
||||
"image/color"
|
||||
"image/draw"
|
||||
"image/png"
|
||||
"regexp"
|
||||
"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.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())
|
||||
}
|
||||
|
@ -39,8 +39,8 @@ var (
|
||||
// default timeout for UDP session
|
||||
udpTimeout = 60 * time.Second
|
||||
|
||||
// MitmOutbound mitm proxy adapter
|
||||
MitmOutbound C.ProxyAdapter
|
||||
// mitmOutbound mitm proxy adapter
|
||||
mitmOutbound C.ProxyAdapter
|
||||
)
|
||||
|
||||
func init() {
|
||||
@ -97,6 +97,11 @@ func SetMode(m TunnelMode) {
|
||||
mode = m
|
||||
}
|
||||
|
||||
// SetMitmOutbound set the MITM outbound
|
||||
func SetMitmOutbound(outbound C.ProxyAdapter) {
|
||||
mitmOutbound = outbound
|
||||
}
|
||||
|
||||
// Rewrites return all rewrites
|
||||
func Rewrites() C.RewriteRule {
|
||||
return rewrites
|
||||
@ -307,9 +312,11 @@ func handleTCPConn(connCtx C.ConnContext) {
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), C.DefaultTCPTimeout)
|
||||
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)
|
||||
|
||||
defer func(remoteConn C.Conn) {
|
||||
_ = remoteConn.Close()
|
||||
}(remoteConn)
|
||||
@ -334,7 +341,11 @@ func handleTCPConn(connCtx C.ConnContext) {
|
||||
}
|
||||
return
|
||||
}
|
||||
remoteConn = statistic.NewTCPTracker(remoteConn, statistic.DefaultManager, metadata, rule)
|
||||
|
||||
if remoteConn.Chains().Last() != "REJECT" {
|
||||
remoteConn = statistic.NewTCPTracker(remoteConn, statistic.DefaultManager, metadata, rule)
|
||||
}
|
||||
|
||||
defer func(remoteConn C.Conn) {
|
||||
_ = remoteConn.Close()
|
||||
}(remoteConn)
|
||||
|
Reference in New Issue
Block a user