diff --git a/.github/workflows/Alpha.yml b/.github/workflows/Alpha.yml index b9bc254d..40d59658 100644 --- a/.github/workflows/Alpha.yml +++ b/.github/workflows/Alpha.yml @@ -15,7 +15,7 @@ jobs: go-version: ${{ steps.version.outputs.go_version }} - name: Check out code into the Go module directory - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Cache go module uses: actions/cache@v2 diff --git a/.golangci.yaml b/.golangci.yaml new file mode 100644 index 00000000..efe91527 --- /dev/null +++ b/.golangci.yaml @@ -0,0 +1,14 @@ +linters: + disable-all: true + enable: + - gofumpt + - megacheck + - govet + - gci + +linters-settings: + gci: + sections: + - standard + - prefix(github.com/Dreamacro/clash) + - default diff --git a/Dockerfile b/Dockerfile index 90a651b9..6e67d5d4 100644 --- a/Dockerfile +++ b/Dockerfile @@ -12,7 +12,7 @@ RUN go mod download && \ FROM alpine:latest LABEL org.opencontainers.image.source="https://github.com/Dreamacro/clash" -RUN apk add --no-cache ca-certificates +RUN apk add --no-cache ca-certificates tzdata COPY --from=builder /Country.mmdb /root/.config/clash/ COPY --from=builder /clash / ENTRYPOINT ["/clash"] diff --git a/component/dialer/bind_darwin.go b/component/dialer/bind_darwin.go index bf51b305..57e09bb5 100644 --- a/component/dialer/bind_darwin.go +++ b/component/dialer/bind_darwin.go @@ -4,9 +4,9 @@ import ( "net" "syscall" - "golang.org/x/sys/unix" - "github.com/Dreamacro/clash/component/iface" + + "golang.org/x/sys/unix" ) type controlFn = func(network, address string, c syscall.RawConn) error diff --git a/component/process/process_darwin.go b/component/process/process_darwin.go index 7e4baf74..7870b227 100644 --- a/component/process/process_darwin.go +++ b/component/process/process_darwin.go @@ -3,7 +3,6 @@ package process import ( "encoding/binary" "net" - "path/filepath" "syscall" "unsafe" @@ -96,7 +95,7 @@ func getExecPathFromPID(pid uint32) (string, error) { return "", errno } - return filepath.Base(unix.ByteSliceToString(buf)), nil + return unix.ByteSliceToString(buf), nil } func readNativeUint32(b []byte) uint32 { diff --git a/component/process/process_freebsd_amd64.go b/component/process/process_freebsd_amd64.go index bf84ce5b..f3e64646 100644 --- a/component/process/process_freebsd_amd64.go +++ b/component/process/process_freebsd_amd64.go @@ -4,7 +4,6 @@ import ( "encoding/binary" "fmt" "net" - "path/filepath" "strconv" "strings" "sync" @@ -77,7 +76,7 @@ func getExecPathFromPID(pid uint32) (string, error) { return "", errno } - return filepath.Base(string(buf[:size-1])), nil + return string(buf[:size-1]), nil } func readNativeUint32(b []byte) uint32 { diff --git a/component/process/process_linux.go b/component/process/process_linux.go index be758a69..d70a2922 100644 --- a/component/process/process_linux.go +++ b/component/process/process_linux.go @@ -4,12 +4,12 @@ import ( "bytes" "encoding/binary" "fmt" - "io" "net" "os" "path" - "path/filepath" + "strings" "syscall" + "unicode" "unsafe" "github.com/Dreamacro/clash/common/pool" @@ -25,17 +25,6 @@ var nativeEndian = func() binary.ByteOrder { return binary.LittleEndian }() -type ( - SocketResolver func(network string, ip net.IP, srcPort int) (inode, uid int, err error) - ProcessNameResolver func(inode, uid int) (name string, err error) -) - -// export for android -var ( - DefaultSocketResolver SocketResolver = resolveSocketByNetlink - DefaultProcessNameResolver ProcessNameResolver = resolveProcessNameByProcSearch -) - const ( sizeOfSocketDiagRequest = syscall.SizeofNlMsghdr + 8 + 48 socketDiagByFamily = 20 @@ -43,15 +32,15 @@ const ( ) func findProcessName(network string, ip net.IP, srcPort int) (string, error) { - inode, uid, err := DefaultSocketResolver(network, ip, srcPort) + inode, uid, err := resolveSocketByNetlink(network, ip, srcPort) if err != nil { return "", err } - return DefaultProcessNameResolver(inode, uid) + return resolveProcessNameByProcSearch(inode, uid) } -func resolveSocketByNetlink(network string, ip net.IP, srcPort int) (int, int, error) { +func resolveSocketByNetlink(network string, ip net.IP, srcPort int) (int32, int32, error) { var family byte var protocol byte @@ -74,13 +63,12 @@ func resolveSocketByNetlink(network string, ip net.IP, srcPort int) (int, int, e socket, err := syscall.Socket(syscall.AF_NETLINK, syscall.SOCK_DGRAM, syscall.NETLINK_INET_DIAG) if err != nil { - return 0, 0, err + return 0, 0, fmt.Errorf("dial netlink: %w", err) } defer syscall.Close(socket) - syscall.SetNonblock(socket, true) - syscall.SetsockoptTimeval(socket, syscall.SOL_SOCKET, syscall.SO_SNDTIMEO, &syscall.Timeval{Usec: 50}) - syscall.SetsockoptTimeval(socket, syscall.SOL_SOCKET, syscall.SO_RCVTIMEO, &syscall.Timeval{Usec: 50}) + syscall.SetsockoptTimeval(socket, syscall.SOL_SOCKET, syscall.SO_SNDTIMEO, &syscall.Timeval{Usec: 100}) + syscall.SetsockoptTimeval(socket, syscall.SOL_SOCKET, syscall.SO_RCVTIMEO, &syscall.Timeval{Usec: 100}) if err := syscall.Connect(socket, &syscall.SockaddrNetlink{ Family: syscall.AF_NETLINK, @@ -92,7 +80,7 @@ func resolveSocketByNetlink(network string, ip net.IP, srcPort int) (int, int, e } if _, err := syscall.Write(socket, req); err != nil { - return 0, 0, err + return 0, 0, fmt.Errorf("write request: %w", err) } rb := pool.Get(pool.RelayBufferSize) @@ -100,24 +88,27 @@ func resolveSocketByNetlink(network string, ip net.IP, srcPort int) (int, int, e n, err := syscall.Read(socket, rb) if err != nil { - return 0, 0, err + return 0, 0, fmt.Errorf("read response: %w", err) } messages, err := syscall.ParseNetlinkMessage(rb[:n]) if err != nil { - return 0, 0, err + return 0, 0, fmt.Errorf("parse netlink message: %w", err) } else if len(messages) == 0 { - return 0, 0, io.ErrUnexpectedEOF + return 0, 0, fmt.Errorf("unexcepted netlink response") } message := messages[0] if message.Header.Type&syscall.NLMSG_ERROR != 0 { - return 0, 0, syscall.ESRCH + return 0, 0, fmt.Errorf("netlink message: NLMSG_ERROR") } uid, inode := unpackSocketDiagResponse(&messages[0]) + if uid < 0 || inode < 0 { + return 0, 0, fmt.Errorf("invalid uid(%d) or inode(%d)", uid, inode) + } - return int(uid), int(inode), nil + return uid, inode, nil } func packSocketDiagRequest(family, protocol byte, source net.IP, sourcePort uint16) []byte { @@ -155,20 +146,20 @@ func packSocketDiagRequest(family, protocol byte, source net.IP, sourcePort uint return buf } -func unpackSocketDiagResponse(msg *syscall.NetlinkMessage) (inode, uid uint32) { +func unpackSocketDiagResponse(msg *syscall.NetlinkMessage) (inode, uid int32) { if len(msg.Data) < 72 { return 0, 0 } data := msg.Data - uid = nativeEndian.Uint32(data[64:68]) - inode = nativeEndian.Uint32(data[68:72]) + uid = int32(nativeEndian.Uint32(data[64:68])) + inode = int32(nativeEndian.Uint32(data[68:72])) return } -func resolveProcessNameByProcSearch(inode, uid int) (string, error) { +func resolveProcessNameByProcSearch(inode, uid int32) (string, error) { files, err := os.ReadDir(pathProc) if err != nil { return "", err @@ -205,38 +196,16 @@ func resolveProcessNameByProcSearch(inode, uid int) (string, error) { } if bytes.Equal(buffer[:n], socket) { - cmdline, err := os.ReadFile(path.Join(processPath, "cmdline")) - if err != nil { - return "", err - } - - return splitCmdline(cmdline), nil + return os.Readlink(path.Join(processPath, "exe")) } } } - return "", syscall.ESRCH -} - -func splitCmdline(cmdline []byte) string { - indexOfEndOfString := len(cmdline) - - for i, c := range cmdline { - if c == 0 { - indexOfEndOfString = i - break - } - } - - return filepath.Base(string(cmdline[:indexOfEndOfString])) + return "", fmt.Errorf("process of uid(%d),inode(%d) not found", uid, inode) } func isPid(s string) bool { - for _, s := range s { - if s < '0' || s > '9' { - return false - } - } - - return true + return strings.IndexFunc(s, func(r rune) bool { + return !unicode.IsDigit(r) + }) == -1 } diff --git a/component/process/process_windows.go b/component/process/process_windows.go index 834bc824..e2fb96ca 100644 --- a/component/process/process_windows.go +++ b/component/process/process_windows.go @@ -3,7 +3,6 @@ package process import ( "fmt" "net" - "path/filepath" "sync" "syscall" "unsafe" @@ -220,5 +219,5 @@ func getExecPathFromPID(pid uint32) (string, error) { if r1 == 0 { return "", err } - return filepath.Base(syscall.UTF16ToString(buf[:size])), nil + return syscall.UTF16ToString(buf[:size]), nil } diff --git a/config/config.go b/config/config.go index 9cc0b3bf..947b8400 100644 --- a/config/config.go +++ b/config/config.go @@ -176,6 +176,7 @@ type RawConfig struct { GeodataMode string `yaml:"geodata-mode"` GeodataLoader string `yaml:"geodata-loader"` AutoIptables bool `yaml:"auto-iptables"` + RoutingMark int `yaml:"routing-mark"` ProxyProvider map[string]map[string]interface{} `yaml:"proxy-providers"` RuleProvider map[string]map[string]interface{} `yaml:"rule-providers"` @@ -240,7 +241,7 @@ func UnmarshalRawConfig(buf []byte) (*RawConfig, error) { }, NameServer: []string{ "223.5.5.5", - "119.29.29", + "119.29.29.29", }, FakeIPFilter: []string{ "dns.msftnsci.com", @@ -351,6 +352,7 @@ func parseGeneral(cfg *RawConfig) (*General, error) { Interface: cfg.Interface, GeodataLoader: cfg.GeodataLoader, AutoIptables: cfg.AutoIptables, + RoutingMark: cfg.RoutingMark, }, nil } diff --git a/constant/metadata.go b/constant/metadata.go index 73a49973..eba63c0a 100644 --- a/constant/metadata.go +++ b/constant/metadata.go @@ -83,6 +83,7 @@ type Metadata struct { Host string `json:"host"` Process string `json:"process"` DNSMode DNSMode `json:"dnsMode"` + ProcessPath string `json:"processPath"` } func (m *Metadata) RemoteAddress() string { diff --git a/constant/rule.go b/constant/rule.go index 2efc2010..fdb11a72 100644 --- a/constant/rule.go +++ b/constant/rule.go @@ -12,6 +12,7 @@ const ( SrcPort DstPort Process + ProcessPath Script RuleSet Network @@ -46,6 +47,8 @@ func (rt RuleType) String() string { return "DstPort" case Process: return "Process" + case ProcessPath: + return "ProcessPath" case Script: return "Script" case MATCH: @@ -71,5 +74,6 @@ type Rule interface { Adapter() string Payload() string ShouldResolveIP() bool + ShouldFindProcess() bool RuleExtra() *RuleExtra } diff --git a/hub/executor/executor.go b/hub/executor/executor.go index 7783bd41..9f7b9fdb 100644 --- a/hub/executor/executor.go +++ b/hub/executor/executor.go @@ -232,6 +232,7 @@ func updateGeneral(general *config.General, Tun *config.Tun, force bool) { } dialer.DefaultInterface.Store(general.Interface) + dialer.DefaultRoutingMark.Store(int32(general.RoutingMark)) log.Infoln("Use interface name: %s", general.Interface) diff --git a/listener/http/proxy.go b/listener/http/proxy.go index 23a73739..becb3673 100644 --- a/listener/http/proxy.go +++ b/listener/http/proxy.go @@ -19,7 +19,12 @@ func HandleConn(c net.Conn, in chan<- C.ConnContext, cache *cache.Cache) { client := newClient(c.RemoteAddr(), in) defer client.CloseIdleConnections() - conn := N.NewBufferedConn(c) + var conn *N.BufferedConn + if bufConn, ok := c.(*N.BufferedConn); ok { + conn = bufConn + } else { + conn = N.NewBufferedConn(c) + } keepAlive := true trusted := cache == nil // disable authenticate if cache is nil diff --git a/listener/mixed/mixed.go b/listener/mixed/mixed.go index 8fd4f990..57fd055e 100644 --- a/listener/mixed/mixed.go +++ b/listener/mixed/mixed.go @@ -64,6 +64,8 @@ func New(addr string, in chan<- C.ConnContext) (*Listener, error) { } func handleConn(conn net.Conn, in chan<- C.ConnContext, cache *cache.Cache) { + conn.(*net.TCPConn).SetKeepAlive(true) + bufConn := N.NewBufferedConn(conn) head, err := bufConn.Peek(1) if err != nil { diff --git a/listener/socks/tcp.go b/listener/socks/tcp.go index 29016f5b..7cce32ee 100644 --- a/listener/socks/tcp.go +++ b/listener/socks/tcp.go @@ -61,6 +61,7 @@ func New(addr string, in chan<- C.ConnContext) (*Listener, error) { } func handleSocks(conn net.Conn, in chan<- C.ConnContext) { + conn.(*net.TCPConn).SetKeepAlive(true) bufConn := N.NewBufferedConn(conn) head, err := bufConn.Peek(1) if err != nil { @@ -84,9 +85,6 @@ func HandleSocks4(conn net.Conn, in chan<- C.ConnContext) { conn.Close() return } - if c, ok := conn.(*net.TCPConn); ok { - c.SetKeepAlive(true) - } in <- inbound.NewSocket(socks5.ParseAddr(addr), conn, C.SOCKS4) } @@ -96,9 +94,6 @@ func HandleSocks5(conn net.Conn, in chan<- C.ConnContext) { conn.Close() return } - if c, ok := conn.(*net.TCPConn); ok { - c.SetKeepAlive(true) - } if command == socks5.CmdUDPAssociate { defer conn.Close() io.Copy(io.Discard, conn) diff --git a/rule/common/domain.go b/rule/common/domain.go index 31aa0f5b..9a3a65bc 100644 --- a/rule/common/domain.go +++ b/rule/common/domain.go @@ -39,6 +39,10 @@ func (d *Domain) RuleExtra() *C.RuleExtra { return d.ruleExtra } +func (d *Domain) ShouldFindProcess() bool { + return false +} + func NewDomain(domain string, adapter string, ruleExtra *C.RuleExtra) *Domain { return &Domain{ domain: strings.ToLower(domain), diff --git a/rule/common/domain_keyword.go b/rule/common/domain_keyword.go index 90819b9d..80f4313f 100644 --- a/rule/common/domain_keyword.go +++ b/rule/common/domain_keyword.go @@ -36,11 +36,15 @@ func (dk *DomainKeyword) ShouldResolveIP() bool { return false } +func (dk *DomainKeyword) ShouldFindProcess() bool { + return false +} + func (dk *DomainKeyword) RuleExtra() *C.RuleExtra { return dk.ruleExtra } -func NewDomainKeyword(keyword string, adapter string, ruleExtra *C.RuleExtra) *DomainKeyword { +func NewDomainKeyword(keyword string, adapter string) *DomainKeyword { return &DomainKeyword{ keyword: strings.ToLower(keyword), adapter: adapter, diff --git a/rule/common/domain_suffix.go b/rule/common/domain_suffix.go index d577e721..5bd6041e 100644 --- a/rule/common/domain_suffix.go +++ b/rule/common/domain_suffix.go @@ -40,6 +40,11 @@ func (ds *DomainSuffix) RuleExtra() *C.RuleExtra { return ds.ruleExtra } + +func (ds *DomainSuffix) ShouldFindProcess() bool { + return false +} + func NewDomainSuffix(suffix string, adapter string, ruleExtra *C.RuleExtra) *DomainSuffix { return &DomainSuffix{ suffix: strings.ToLower(suffix), diff --git a/rule/common/final.go b/rule/common/final.go index 1cdd20f1..7f7cf6eb 100644 --- a/rule/common/final.go +++ b/rule/common/final.go @@ -29,6 +29,10 @@ func (f *Match) ShouldResolveIP() bool { return false } +func (f *Match) ShouldFindProcess() bool { + return false +} + func (f *Match) RuleExtra() *C.RuleExtra { return f.ruleExtra } diff --git a/rule/common/ipcidr.go b/rule/common/ipcidr.go index 7f7f437d..a777b869 100644 --- a/rule/common/ipcidr.go +++ b/rule/common/ipcidr.go @@ -55,6 +55,10 @@ func (i *IPCIDR) ShouldResolveIP() bool { return !i.noResolveIP } +func (i *IPCIDR) ShouldFindProcess() bool { + return false +} + func (i *IPCIDR) RuleExtra() *C.RuleExtra { return i.ruleExtra } diff --git a/rule/parser.go b/rule/parser.go index a125027c..e415b6b7 100644 --- a/rule/parser.go +++ b/rule/parser.go @@ -1,4 +1,4 @@ -package rule +package rules import ( "fmt" @@ -42,7 +42,9 @@ func ParseRule(tp, payload, target string, params []string) (C.Rule, error) { case "DST-PORT": parsed, parseErr = RC.NewPort(payload, target, false, ruleExtra) case "PROCESS-NAME": - parsed, parseErr = RC.NewProcess(payload, target, ruleExtra) + parsed, parseErr = RC.NewProcess(payload, target, true,ruleExtra) + case "PROCESS-PATH": + parsed, parseErr = RC.NewProcess(payload, target, false,ruleExtra) case "MATCH": parsed = RC.NewMatch(target, ruleExtra) case "RULE-SET": diff --git a/test/config/vmess-aead.json b/test/config/vmess-aead.json deleted file mode 100644 index 27bc4757..00000000 --- a/test/config/vmess-aead.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "inbounds": [ - { - "port": 10002, - "listen": "0.0.0.0", - "protocol": "vmess", - "settings": { - "clients": [ - { - "id": "b831381d-6324-4d53-ad4f-8cda48b30811", - "alterId": 0 - } - ] - }, - "streamSettings": { - "network": "tcp" - } - } - ], - "outbounds": [ - { - "protocol": "freedom" - } - ], - "log": { - "loglevel": "debug" - } -} \ No newline at end of file diff --git a/test/config/vmess-grpc.json b/test/config/vmess-grpc.json index 22e11763..178e0685 100644 --- a/test/config/vmess-grpc.json +++ b/test/config/vmess-grpc.json @@ -7,8 +7,7 @@ "settings": { "clients": [ { - "id": "b831381d-6324-4d53-ad4f-8cda48b30811", - "alterId": 32 + "id": "b831381d-6324-4d53-ad4f-8cda48b30811" } ] }, diff --git a/test/config/vmess-http.json b/test/config/vmess-http.json index aa6c6c8e..90550c35 100644 --- a/test/config/vmess-http.json +++ b/test/config/vmess-http.json @@ -7,8 +7,7 @@ "settings": { "clients": [ { - "id": "b831381d-6324-4d53-ad4f-8cda48b30811", - "alterId": 32 + "id": "b831381d-6324-4d53-ad4f-8cda48b30811" } ] }, diff --git a/test/config/vmess-http2.json b/test/config/vmess-http2.json index 48873731..c6916a1b 100644 --- a/test/config/vmess-http2.json +++ b/test/config/vmess-http2.json @@ -7,8 +7,7 @@ "settings": { "clients": [ { - "id": "b831381d-6324-4d53-ad4f-8cda48b30811", - "alterId": 32 + "id": "b831381d-6324-4d53-ad4f-8cda48b30811" } ] }, diff --git a/test/config/vmess-tls.json b/test/config/vmess-tls.json index ae2fa489..17e87d66 100644 --- a/test/config/vmess-tls.json +++ b/test/config/vmess-tls.json @@ -7,8 +7,7 @@ "settings": { "clients": [ { - "id": "b831381d-6324-4d53-ad4f-8cda48b30811", - "alterId": 32 + "id": "b831381d-6324-4d53-ad4f-8cda48b30811" } ] }, diff --git a/test/config/vmess-ws-0rtt.json b/test/config/vmess-ws-0rtt.json index 7e2876d0..c22909bf 100644 --- a/test/config/vmess-ws-0rtt.json +++ b/test/config/vmess-ws-0rtt.json @@ -7,8 +7,7 @@ "settings": { "clients": [ { - "id": "b831381d-6324-4d53-ad4f-8cda48b30811", - "alterId": 32 + "id": "b831381d-6324-4d53-ad4f-8cda48b30811" } ] }, diff --git a/test/config/vmess-ws-tls.json b/test/config/vmess-ws-tls.json index dda1e0c9..14278f3d 100644 --- a/test/config/vmess-ws-tls.json +++ b/test/config/vmess-ws-tls.json @@ -7,8 +7,7 @@ "settings": { "clients": [ { - "id": "b831381d-6324-4d53-ad4f-8cda48b30811", - "alterId": 32 + "id": "b831381d-6324-4d53-ad4f-8cda48b30811" } ] }, diff --git a/test/config/vmess-ws.json b/test/config/vmess-ws.json index 94ace4e3..2bcb604d 100644 --- a/test/config/vmess-ws.json +++ b/test/config/vmess-ws.json @@ -7,8 +7,7 @@ "settings": { "clients": [ { - "id": "b831381d-6324-4d53-ad4f-8cda48b30811", - "alterId": 32 + "id": "b831381d-6324-4d53-ad4f-8cda48b30811" } ] }, diff --git a/test/config/vmess.json b/test/config/vmess.json index bcf53cd8..1a8f9355 100644 --- a/test/config/vmess.json +++ b/test/config/vmess.json @@ -7,8 +7,7 @@ "settings": { "clients": [ { - "id": "b831381d-6324-4d53-ad4f-8cda48b30811", - "alterId": 32 + "id": "b831381d-6324-4d53-ad4f-8cda48b30811" } ] }, diff --git a/test/vmess_test.go b/test/vmess_test.go index b1d21e5f..a8704bf0 100644 --- a/test/vmess_test.go +++ b/test/vmess_test.go @@ -34,51 +34,12 @@ func TestClash_Vmess(t *testing.T) { }) proxy, err := outbound.NewVmess(outbound.VmessOption{ - Name: "vmess", - Server: localIP.String(), - Port: 10002, - UUID: "b831381d-6324-4d53-ad4f-8cda48b30811", - Cipher: "auto", - AlterID: 32, - UDP: true, - }) - if err != nil { - assert.FailNow(t, err.Error()) - } - - time.Sleep(waitTime) - testSuit(t, proxy) -} - -func TestClash_VmessAEAD(t *testing.T) { - configPath := C.Path.Resolve("vmess-aead.json") - - cfg := &container.Config{ - Image: ImageVmess, - ExposedPorts: defaultExposedPorts, - } - hostCfg := &container.HostConfig{ - PortBindings: defaultPortBindings, - Binds: []string{fmt.Sprintf("%s:/etc/v2ray/config.json", configPath)}, - } - - id, err := startContainer(cfg, hostCfg, "vmess-aead") - if err != nil { - assert.FailNow(t, err.Error()) - } - - t.Cleanup(func() { - cleanContainer(id) - }) - - proxy, err := outbound.NewVmess(outbound.VmessOption{ - Name: "vmess", - Server: localIP.String(), - Port: 10002, - UUID: "b831381d-6324-4d53-ad4f-8cda48b30811", - Cipher: "auto", - AlterID: 0, - UDP: true, + Name: "vmess", + Server: localIP.String(), + Port: 10002, + UUID: "b831381d-6324-4d53-ad4f-8cda48b30811", + Cipher: "auto", + UDP: true, }) if err != nil { assert.FailNow(t, err.Error()) @@ -114,7 +75,6 @@ func TestClash_VmessTLS(t *testing.T) { Port: 10002, UUID: "b831381d-6324-4d53-ad4f-8cda48b30811", Cipher: "auto", - AlterID: 32, TLS: true, SkipCertVerify: true, ServerName: "example.org", @@ -154,7 +114,6 @@ func TestClash_VmessHTTP2(t *testing.T) { Port: 10002, UUID: "b831381d-6324-4d53-ad4f-8cda48b30811", Cipher: "auto", - AlterID: 32, Network: "h2", TLS: true, SkipCertVerify: true, @@ -197,7 +156,6 @@ func TestClash_VmessHTTP(t *testing.T) { Port: 10002, UUID: "b831381d-6324-4d53-ad4f-8cda48b30811", Cipher: "auto", - AlterID: 32, Network: "http", UDP: true, HTTPOpts: outbound.HTTPOptions{ @@ -250,7 +208,6 @@ func TestClash_VmessWebsocket(t *testing.T) { Port: 10002, UUID: "b831381d-6324-4d53-ad4f-8cda48b30811", Cipher: "auto", - AlterID: 32, Network: "ws", UDP: true, }) @@ -288,7 +245,6 @@ func TestClash_VmessWebsocketTLS(t *testing.T) { Port: 10002, UUID: "b831381d-6324-4d53-ad4f-8cda48b30811", Cipher: "auto", - AlterID: 32, Network: "ws", TLS: true, SkipCertVerify: true, @@ -328,7 +284,6 @@ func TestClash_VmessGrpc(t *testing.T) { Port: 10002, UUID: "b831381d-6324-4d53-ad4f-8cda48b30811", Cipher: "auto", - AlterID: 32, Network: "grpc", TLS: true, SkipCertVerify: true, @@ -370,7 +325,6 @@ func TestClash_VmessWebsocket0RTT(t *testing.T) { Port: 10002, UUID: "b831381d-6324-4d53-ad4f-8cda48b30811", Cipher: "auto", - AlterID: 32, Network: "ws", UDP: true, ServerName: "example.org", @@ -411,7 +365,6 @@ func TestClash_VmessWebsocketXray0RTT(t *testing.T) { Port: 10002, UUID: "b831381d-6324-4d53-ad4f-8cda48b30811", Cipher: "auto", - AlterID: 32, Network: "ws", UDP: true, ServerName: "example.org", diff --git a/tunnel/tunnel.go b/tunnel/tunnel.go index c321e9e7..6643bc95 100644 --- a/tunnel/tunnel.go +++ b/tunnel/tunnel.go @@ -6,11 +6,13 @@ import ( R "github.com/Dreamacro/clash/rule/common" "net" "runtime" + "strconv" "sync" "time" "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" C "github.com/Dreamacro/clash/constant" "github.com/Dreamacro/clash/constant/provider" @@ -329,6 +331,7 @@ func match(metadata *C.Metadata) (C.Proxy, C.Rule, error) { defer configMux.RUnlock() var resolved bool + var processFound bool if node := resolver.DefaultHosts.Search(metadata.Host); node != nil { ip := node.Data.(net.IP) @@ -351,6 +354,21 @@ func match(metadata *C.Metadata) (C.Proxy, C.Rule, error) { resolved = true } + if !processFound && rule.ShouldFindProcess() { + processFound = true + + srcPort, err := strconv.Atoi(metadata.SrcPort) + if err == nil { + path, err := P.FindProcessName(metadata.NetWork.String(), metadata.SrcIP, srcPort) + if err != nil { + log.Debugln("[Process] find process %s: %v", metadata.String(), err) + } else { + log.Debugln("[Process] %s from process %s", metadata.String(), path) + metadata.ProcessPath = path + } + } + } + if rule.Match(metadata) { adapter, ok := proxies[rule.Adapter()] if !ok {