Chore: merge branch 'with-tun' into plus-pro

This commit is contained in:
yaling888 2022-05-09 01:56:32 +08:00
commit 934babca85
6 changed files with 67 additions and 95 deletions

View File

@ -20,10 +20,18 @@ jobs:
- name: Check out code into the Go module directory
uses: actions/checkout@v3
- name: Go cache paths
id: go-cache-paths
run: |
echo "::set-output name=go-build::$(go env GOCACHE)"
echo "::set-output name=go-mod::$(go env GOMODCACHE)"
- name: Cache go module
uses: actions/cache@v2
with:
path: ~/go/pkg/mod
path: |
${{ steps.go-cache-paths.outputs.go-mod }}
${{ steps.go-cache-paths.outputs.go-build }}
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-go-
@ -92,6 +100,8 @@ jobs:
with:
files: bin/*
draft: true
prerelease: true
generate_release_notes: true
- name: Delete workflow runs
uses: GitRML/delete-workflow-runs@main

View File

@ -40,7 +40,7 @@ Documentations are now moved to [GitHub Wiki](https://github.com/Dreamacro/clash
A root CA certificate is required, the
MITM proxy server will generate a CA certificate file and a CA private key file in your Clash home directory, you can use your own certificate replace it.
Need to install and trust the CA certificate on the client device, open this URL http://mitm.clash/cert.crt by the web browser to install the CA certificate, the host name 'mitm.clash' was always been hijacked.
Need to install and trust the CA certificate on the client device, open this URL [http://mitm.clash/cert.crt](http://mitm.clash/cert.crt) by the web browser to install the CA certificate, the host name 'mitm.clash' was always been hijacked.
NOTE: this feature cannot work on tls pinning
@ -329,9 +329,21 @@ $ systemctl start clash
```
### Display Process name
Add field `Process` to `Metadata` and prepare to get process name for Restful API `GET /connections`.
To display process name online by click [https://yaling888.github.io/yacd/](https://yaling888.github.io/yacd/).
To display process name in GUI please use https://yaling888.github.io/yacd/.
You can download the [Dashboard](https://github.com/yaling888/yacd/archive/gh-pages.zip) into Clash home directory:
```shell
cd ~/.config/clash
curl -LJ https://github.com/yaling888/yacd/archive/gh-pages.zip -o dashboard.zip
unzip dashboard.zip
```
Add to config file:
```yaml
external-controller: 127.0.0.1:9090
external-ui: dashboard
```
Open [http://127.0.0.1:9090/ui/](http://127.0.0.1:9090/ui/) by web browser.
## Development
If you want to build an application that uses clash as a library, check out the the [GitHub Wiki](https://github.com/Dreamacro/clash/wiki/use-clash-as-a-library)

View File

@ -2,32 +2,21 @@ package outbound
import (
"context"
"errors"
"net"
"time"
"github.com/Dreamacro/clash/component/dialer"
"github.com/Dreamacro/clash/component/trie"
C "github.com/Dreamacro/clash/constant"
)
var (
errIgnored = errors.New("not match in mitm host lists")
httpProxyClient = NewHttp(HttpOption{})
rewriteHosts *trie.DomainTrie[bool]
)
type Mitm struct {
*Base
serverAddr *net.TCPAddr
httpProxyClient *Http
}
// DialContext implements C.ProxyAdapter
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
}
c, err := net.DialTCP("tcp", nil, m.serverAddr)
if err != nil {
return nil, err
@ -38,7 +27,7 @@ func (m *Mitm) DialContext(_ context.Context, metadata *C.Metadata, _ ...dialer.
metadata.Type = C.MITM
hc, err := httpProxyClient.StreamConn(c, metadata)
hc, err := m.httpProxyClient.StreamConn(c, metadata)
if err != nil {
_ = c.Close()
return nil, err
@ -55,9 +44,6 @@ func NewMitm(serverAddr string) *Mitm {
tp: C.Mitm,
},
serverAddr: tcpAddr,
httpProxyClient: NewHttp(HttpOption{}),
}
}
func UpdateRewriteHosts(hosts *trie.DomainTrie[bool]) {
rewriteHosts = hosts
}

View File

@ -8,7 +8,6 @@ import (
"sync"
"github.com/Dreamacro/clash/adapter"
"github.com/Dreamacro/clash/adapter/outbound"
"github.com/Dreamacro/clash/adapter/outboundgroup"
"github.com/Dreamacro/clash/component/auth"
"github.com/Dreamacro/clash/component/dialer"
@ -339,8 +338,7 @@ func updateIPTables(cfg *config.Config) {
}
func updateMitm(mitm *config.Mitm) {
outbound.UpdateRewriteHosts(mitm.Hosts)
tunnel.UpdateRewrites(mitm.Rules)
tunnel.UpdateRewrites(mitm.Hosts, mitm.Rules)
}
func Shutdown() {

View File

@ -1,37 +0,0 @@
package rewrites
import (
"regexp"
"testing"
"github.com/Dreamacro/clash/constant"
"github.com/stretchr/testify/assert"
)
func TestParseRewrite(t *testing.T) {
line0 := `^https?://example\.com/resource1/3/ url reject-dict`
line1 := `^https?://example\.com/(resource2)/ url 307 https://example.com/new-$1`
line2 := `^https?://example\.com/resource4/ url request-header (\r\n)User-Agent:.+(\r\n) request-header $1User-Agent: Fuck-Who$2`
line3 := `should be error`
c0, err0 := ParseRewrite(line0)
c1, err1 := ParseRewrite(line1)
c2, err2 := ParseRewrite(line2)
_, err3 := ParseRewrite(line3)
assert.NotNil(t, err3)
assert.Nil(t, err0)
assert.Equal(t, c0.RuleType(), constant.MitmRejectDict)
assert.Nil(t, err1)
assert.Equal(t, c1.RuleType(), constant.Mitm307)
assert.Equal(t, c1.URLRegx(), regexp.MustCompile(`^https?://example\.com/(resource2)/`))
assert.Equal(t, c1.RulePayload(), "https://example.com/new-$1")
assert.Nil(t, err2)
assert.Equal(t, c2.RuleType(), constant.MitmRequestHeader)
assert.Equal(t, c2.RuleRegx(), regexp.MustCompile(`(\r\n)User-Agent:.+(\r\n)`))
assert.Equal(t, c2.RulePayload(), "$1User-Agent: Fuck-Who$2")
}

View File

@ -11,11 +11,13 @@ import (
"sync"
"time"
A "github.com/Dreamacro/clash/adapter"
"github.com/Dreamacro/clash/adapter/inbound"
"github.com/Dreamacro/clash/component/nat"
P "github.com/Dreamacro/clash/component/process"
"github.com/Dreamacro/clash/component/resolver"
S "github.com/Dreamacro/clash/component/script"
"github.com/Dreamacro/clash/component/trie"
C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/constant/provider"
icontext "github.com/Dreamacro/clash/context"
@ -28,9 +30,10 @@ var (
udpQueue = make(chan *inbound.PacketAdapter, 200)
natTable = nat.New()
rules []C.Rule
rewrites C.RewriteRule
proxies = make(map[string]C.Proxy)
providers map[string]provider.ProxyProvider
rewrites C.RewriteRule
rewriteHosts *trie.DomainTrie[bool]
configMux sync.RWMutex
// Outbound Rule
@ -39,8 +42,8 @@ var (
// default timeout for UDP session
udpTimeout = 60 * time.Second
// mitmOutbound mitm proxy adapter
mitmOutbound C.ProxyAdapter
// mitmProxy mitm proxy
mitmProxy C.Proxy
)
func init() {
@ -99,7 +102,7 @@ func SetMode(m TunnelMode) {
// SetMitmOutbound set the MITM outbound
func SetMitmOutbound(outbound C.ProxyAdapter) {
mitmOutbound = outbound
mitmProxy = A.NewProxy(outbound)
}
// Rewrites return all rewrites
@ -108,9 +111,10 @@ func Rewrites() C.RewriteRule {
}
// UpdateRewrites handle update rewrites
func UpdateRewrites(newRewrites C.RewriteRule) {
func UpdateRewrites(hosts *trie.DomainTrie[bool], rules C.RewriteRule) {
configMux.Lock()
rewrites = newRewrites
rewriteHosts = hosts
rewrites = rules
configMux.Unlock()
}
@ -179,7 +183,7 @@ func preHandleMetadata(metadata *C.Metadata) error {
if err != nil {
log.Debugln("[Process] find process %s: %v", metadata.String(), err)
} else {
log.Debugln("[Process] %s from process %s", metadata.String(), path)
// log.Debugln("[Process] %s from process %s", metadata.String(), path)
metadata.Process = filepath.Base(path)
metadata.ProcessPath = path
}
@ -189,6 +193,12 @@ func preHandleMetadata(metadata *C.Metadata) error {
}
func resolveMetadata(_ C.PlainContext, metadata *C.Metadata) (proxy C.Proxy, rule C.Rule, err error) {
if metadata.NetWork == C.TCP && mitmProxy != nil && metadata.Type != C.MITM &&
((rewriteHosts != nil && rewriteHosts.Search(metadata.String()) != nil) || metadata.DstPort == "80") {
proxy = mitmProxy
return
}
switch mode {
case Direct:
proxy = proxies["DIRECT"]
@ -310,29 +320,20 @@ func handleTCPConn(connCtx C.ConnContext) {
return
}
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 {
remoteConn = statistic.NewSniffing(remoteConn, metadata, nil)
defer func(remoteConn C.Conn) {
_ = remoteConn.Close()
}(remoteConn)
handleSocket(connCtx, remoteConn)
return
}
}
proxy, rule, err := resolveMetadata(connCtx, metadata)
if err != nil {
log.Warnln("[Metadata] parse failed: %s", err.Error())
return
}
remoteConn, err := proxy.DialContext(ctx, metadata.Pure())
mtd := metadata
if proxy != mitmProxy {
mtd = metadata.Pure()
}
ctx, cancel := context.WithTimeout(context.Background(), C.DefaultTCPTimeout)
defer cancel()
remoteConn, err := proxy.DialContext(ctx, mtd)
if err != nil {
if rule == nil {
log.Warnln("[TCP] dial %s to %s error: %s", proxy.Name(), metadata.RemoteAddress(), err.Error())
@ -342,7 +343,7 @@ func handleTCPConn(connCtx C.ConnContext) {
return
}
if remoteConn.Chains().Last() != "REJECT" {
if remoteConn.Chains().Last() != "REJECT" && proxy != mitmProxy {
remoteConn = statistic.NewTCPTracker(remoteConn, statistic.DefaultManager, metadata, rule)
}
@ -351,6 +352,8 @@ func handleTCPConn(connCtx C.ConnContext) {
}(remoteConn)
switch true {
case proxy == mitmProxy:
break
case rule != nil:
log.Infoln("[TCP] %s(%s) --> %s match %s(%s) using %s", metadata.SourceAddress(), metadata.Process, metadata.RemoteAddress(), rule.RuleType().String(), rule.Payload(), remoteConn.Chains().String())
case mode == Script: