Compare commits
26 Commits
Author | SHA1 | Date | |
---|---|---|---|
5dd94c8298 | |||
412b44a981 | |||
aef4dd3fe7 | |||
6a92c6af4e | |||
e010940b61 | |||
2c9a4d276a | |||
4dfba73e5c | |||
c282d662ca | |||
b3d7594813 | |||
dd9bdf4e2f | |||
275cc7edf3 | |||
8c9e0b3884 | |||
30d4668008 | |||
02333a859a | |||
f9cc1cc363 | |||
fb7d340233 | |||
6a661bff0c | |||
d1dd21417b | |||
b866f06414 | |||
9683c297a7 | |||
f6c7281bb7 | |||
83bfe521b1 | |||
b52d0c16e9 | |||
132a6a6a2f | |||
03e4b5d525 | |||
a0221bf897 |
8
.github/workflows/codeql-analysis.yml
vendored
8
.github/workflows/codeql-analysis.yml
vendored
@ -1,8 +1,8 @@
|
||||
name: "CodeQL"
|
||||
name: CodeQL
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ master, dev ]
|
||||
branches: [master, dev]
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
@ -12,11 +12,11 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
language: [ 'go' ]
|
||||
language: ['go']
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v1
|
||||
|
10
.github/workflows/docker.yml
vendored
10
.github/workflows/docker.yml
vendored
@ -13,7 +13,7 @@ jobs:
|
||||
steps:
|
||||
|
||||
- name: Check out code into the Go module directory
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
@ -49,14 +49,16 @@ jobs:
|
||||
platforms: linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64
|
||||
push: true
|
||||
tags: 'dreamacro/clash:dev,ghcr.io/dreamacro/clash:dev'
|
||||
cache-from: type=gha
|
||||
cache-to: type=gha,mode=max
|
||||
|
||||
- name: Get all docker tags
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
uses: actions/github-script@v4
|
||||
uses: actions/github-script@v6
|
||||
id: tags
|
||||
with:
|
||||
script: |
|
||||
const ref = `${context.payload.ref.replace(/\/?refs\/tags\//, '')}`
|
||||
const ref = context.payload.ref.replace(/\/?refs\/tags\//, '')
|
||||
const tags = [
|
||||
'dreamacro/clash:latest',
|
||||
`dreamacro/clash:${ref}`,
|
||||
@ -74,3 +76,5 @@ jobs:
|
||||
platforms: linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64
|
||||
push: true
|
||||
tags: ${{steps.tags.outputs.result}}
|
||||
cache-from: type=gha
|
||||
cache-to: type=gha,mode=max
|
||||
|
16
.github/workflows/linter.yml
vendored
16
.github/workflows/linter.yml
vendored
@ -4,9 +4,19 @@ jobs:
|
||||
lint:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Get latest go version
|
||||
id: version
|
||||
run: |
|
||||
echo ::set-output name=go_version::$(curl -s https://raw.githubusercontent.com/actions/go-versions/main/versions-manifest.json | grep -oE '"version": "[0-9]{1}.[0-9]{1,}(.[0-9]{1,})?"' | head -1 | cut -d':' -f2 | sed 's/ //g; s/"//g')
|
||||
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: ${{ steps.version.outputs.go_version }}
|
||||
|
||||
- name: golangci-lint
|
||||
uses: golangci/golangci-lint-action@v2
|
||||
uses: golangci/golangci-lint-action@v3
|
||||
with:
|
||||
version: latest
|
||||
args: --disable-all -E govet -E gofumpt -E megacheck ./...
|
||||
|
6
.github/workflows/release.yml
vendored
6
.github/workflows/release.yml
vendored
@ -15,12 +15,14 @@ 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
|
||||
with:
|
||||
path: ~/go/pkg/mod
|
||||
path: |
|
||||
~/go/pkg/mod
|
||||
~/.cache/go-build
|
||||
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-go-
|
||||
|
2
.github/workflows/stale.yml
vendored
2
.github/workflows/stale.yml
vendored
@ -11,7 +11,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/stale@v4
|
||||
- uses: actions/stale@v5
|
||||
with:
|
||||
stale-issue-message: 'This issue is stale because it has been open 60 days with no activity. Remove stale label or comment or this will be closed in 5 days'
|
||||
days-before-stale: 60
|
||||
|
16
.golangci.yaml
Normal file
16
.golangci.yaml
Normal file
@ -0,0 +1,16 @@
|
||||
linters:
|
||||
disable-all: true
|
||||
enable:
|
||||
- gofumpt
|
||||
- staticcheck
|
||||
- govet
|
||||
- gci
|
||||
|
||||
linters-settings:
|
||||
gci:
|
||||
sections:
|
||||
- standard
|
||||
- prefix(github.com/Dreamacro/clash)
|
||||
- default
|
||||
staticcheck:
|
||||
go: '1.18'
|
@ -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"]
|
||||
|
22
Makefile
22
Makefile
@ -8,9 +8,11 @@ GOBUILD=CGO_ENABLED=0 go build -trimpath -ldflags '-X "github.com/Dreamacro/clas
|
||||
|
||||
PLATFORM_LIST = \
|
||||
darwin-amd64 \
|
||||
darwin-amd64-v3 \
|
||||
darwin-arm64 \
|
||||
linux-386 \
|
||||
linux-amd64 \
|
||||
linux-amd64-v3 \
|
||||
linux-armv5 \
|
||||
linux-armv6 \
|
||||
linux-armv7 \
|
||||
@ -23,11 +25,13 @@ PLATFORM_LIST = \
|
||||
linux-mips64le \
|
||||
freebsd-386 \
|
||||
freebsd-amd64 \
|
||||
freebsd-amd64-v3 \
|
||||
freebsd-arm64
|
||||
|
||||
WINDOWS_ARCH_LIST = \
|
||||
windows-386 \
|
||||
windows-amd64 \
|
||||
windows-amd64-v3 \
|
||||
windows-arm64 \
|
||||
windows-arm32v7
|
||||
|
||||
@ -39,6 +43,9 @@ docker:
|
||||
darwin-amd64:
|
||||
GOARCH=amd64 GOOS=darwin $(GOBUILD) -o $(BINDIR)/$(NAME)-$@
|
||||
|
||||
darwin-amd64-v3:
|
||||
GOARCH=amd64 GOOS=darwin GOAMD64=v3 $(GOBUILD) -o $(BINDIR)/$(NAME)-$@
|
||||
|
||||
darwin-arm64:
|
||||
GOARCH=arm64 GOOS=darwin $(GOBUILD) -o $(BINDIR)/$(NAME)-$@
|
||||
|
||||
@ -48,6 +55,9 @@ linux-386:
|
||||
linux-amd64:
|
||||
GOARCH=amd64 GOOS=linux $(GOBUILD) -o $(BINDIR)/$(NAME)-$@
|
||||
|
||||
linux-amd64-v3:
|
||||
GOARCH=amd64 GOOS=linux GOAMD64=v3 $(GOBUILD) -o $(BINDIR)/$(NAME)-$@
|
||||
|
||||
linux-armv5:
|
||||
GOARCH=arm GOOS=linux GOARM=5 $(GOBUILD) -o $(BINDIR)/$(NAME)-$@
|
||||
|
||||
@ -84,6 +94,9 @@ freebsd-386:
|
||||
freebsd-amd64:
|
||||
GOARCH=amd64 GOOS=freebsd $(GOBUILD) -o $(BINDIR)/$(NAME)-$@
|
||||
|
||||
freebsd-amd64-v3:
|
||||
GOARCH=amd64 GOOS=freebsd GOAMD64=v3 $(GOBUILD) -o $(BINDIR)/$(NAME)-$@
|
||||
|
||||
freebsd-arm64:
|
||||
GOARCH=arm64 GOOS=freebsd $(GOBUILD) -o $(BINDIR)/$(NAME)-$@
|
||||
|
||||
@ -93,6 +106,9 @@ windows-386:
|
||||
windows-amd64:
|
||||
GOARCH=amd64 GOOS=windows $(GOBUILD) -o $(BINDIR)/$(NAME)-$@.exe
|
||||
|
||||
windows-amd64-v3:
|
||||
GOARCH=amd64 GOOS=windows GOAMD64=v3 $(GOBUILD) -o $(BINDIR)/$(NAME)-$@.exe
|
||||
|
||||
windows-arm64:
|
||||
GOARCH=arm64 GOOS=windows $(GOBUILD) -o $(BINDIR)/$(NAME)-$@.exe
|
||||
|
||||
@ -114,7 +130,11 @@ all-arch: $(PLATFORM_LIST) $(WINDOWS_ARCH_LIST)
|
||||
releases: $(gz_releases) $(zip_releases)
|
||||
|
||||
lint:
|
||||
golangci-lint run --disable-all -E govet -E gofumpt -E megacheck ./...
|
||||
GOOS=darwin golangci-lint run ./...
|
||||
GOOS=windows golangci-lint run ./...
|
||||
GOOS=linux golangci-lint run ./...
|
||||
GOOS=freebsd golangci-lint run ./...
|
||||
GOOS=openbsd golangci-lint run ./...
|
||||
|
||||
clean:
|
||||
rm $(BINDIR)/*
|
||||
|
@ -91,7 +91,7 @@ func (p *Proxy) MarshalJSON() ([]byte, error) {
|
||||
return inner, err
|
||||
}
|
||||
|
||||
mapping := map[string]interface{}{}
|
||||
mapping := map[string]any{}
|
||||
json.Unmarshal(inner, &mapping)
|
||||
mapping["history"] = p.DelayHistory()
|
||||
mapping["name"] = p.Name()
|
||||
|
@ -136,6 +136,7 @@ func NewHttp(option HttpOption) *Http {
|
||||
addr: net.JoinHostPort(option.Server, strconv.Itoa(option.Port)),
|
||||
tp: C.Http,
|
||||
iface: option.Interface,
|
||||
rmark: option.RoutingMark,
|
||||
},
|
||||
user: option.UserName,
|
||||
pass: option.Password,
|
||||
|
@ -29,14 +29,14 @@ type ShadowSocks struct {
|
||||
|
||||
type ShadowSocksOption struct {
|
||||
BasicOption
|
||||
Name string `proxy:"name"`
|
||||
Server string `proxy:"server"`
|
||||
Port int `proxy:"port"`
|
||||
Password string `proxy:"password"`
|
||||
Cipher string `proxy:"cipher"`
|
||||
UDP bool `proxy:"udp,omitempty"`
|
||||
Plugin string `proxy:"plugin,omitempty"`
|
||||
PluginOpts map[string]interface{} `proxy:"plugin-opts,omitempty"`
|
||||
Name string `proxy:"name"`
|
||||
Server string `proxy:"server"`
|
||||
Port int `proxy:"port"`
|
||||
Password string `proxy:"password"`
|
||||
Cipher string `proxy:"cipher"`
|
||||
UDP bool `proxy:"udp,omitempty"`
|
||||
Plugin string `proxy:"plugin,omitempty"`
|
||||
PluginOpts map[string]any `proxy:"plugin-opts,omitempty"`
|
||||
}
|
||||
|
||||
type simpleObfsOption struct {
|
||||
@ -160,6 +160,7 @@ func NewShadowSocks(option ShadowSocksOption) (*ShadowSocks, error) {
|
||||
tp: C.Shadowsocks,
|
||||
udp: option.UDP,
|
||||
iface: option.Interface,
|
||||
rmark: option.RoutingMark,
|
||||
},
|
||||
cipher: ciph,
|
||||
|
||||
|
@ -92,6 +92,12 @@ func (ssr *ShadowSocksR) ListenPacketContext(ctx context.Context, metadata *C.Me
|
||||
}
|
||||
|
||||
func NewShadowSocksR(option ShadowSocksROption) (*ShadowSocksR, error) {
|
||||
// SSR protocol compatibility
|
||||
// https://github.com/Dreamacro/clash/pull/2056
|
||||
if option.Cipher == "none" {
|
||||
option.Cipher = "dummy"
|
||||
}
|
||||
|
||||
addr := net.JoinHostPort(option.Server, strconv.Itoa(option.Port))
|
||||
cipher := option.Cipher
|
||||
password := option.Password
|
||||
@ -103,13 +109,14 @@ func NewShadowSocksR(option ShadowSocksROption) (*ShadowSocksR, error) {
|
||||
ivSize int
|
||||
key []byte
|
||||
)
|
||||
|
||||
if option.Cipher == "dummy" {
|
||||
ivSize = 0
|
||||
key = core.Kdf(option.Password, 16)
|
||||
} else {
|
||||
ciph, ok := coreCiph.(*core.StreamCipher)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("%s is not dummy or a supported stream cipher in ssr", cipher)
|
||||
return nil, fmt.Errorf("%s is not none or a supported stream cipher in ssr", cipher)
|
||||
}
|
||||
ivSize = ciph.IVSize()
|
||||
key = ciph.Key
|
||||
@ -142,6 +149,7 @@ func NewShadowSocksR(option ShadowSocksROption) (*ShadowSocksR, error) {
|
||||
tp: C.ShadowsocksR,
|
||||
udp: option.UDP,
|
||||
iface: option.Interface,
|
||||
rmark: option.RoutingMark,
|
||||
},
|
||||
cipher: coreCiph,
|
||||
obfs: obfs,
|
||||
|
@ -23,13 +23,13 @@ type Snell struct {
|
||||
|
||||
type SnellOption struct {
|
||||
BasicOption
|
||||
Name string `proxy:"name"`
|
||||
Server string `proxy:"server"`
|
||||
Port int `proxy:"port"`
|
||||
Psk string `proxy:"psk"`
|
||||
UDP bool `proxy:"udp,omitempty"`
|
||||
Version int `proxy:"version,omitempty"`
|
||||
ObfsOpts map[string]interface{} `proxy:"obfs-opts,omitempty"`
|
||||
Name string `proxy:"name"`
|
||||
Server string `proxy:"server"`
|
||||
Port int `proxy:"port"`
|
||||
Psk string `proxy:"psk"`
|
||||
UDP bool `proxy:"udp,omitempty"`
|
||||
Version int `proxy:"version,omitempty"`
|
||||
ObfsOpts map[string]any `proxy:"obfs-opts,omitempty"`
|
||||
}
|
||||
|
||||
type streamOption struct {
|
||||
@ -142,6 +142,7 @@ func NewSnell(option SnellOption) (*Snell, error) {
|
||||
tp: C.Snell,
|
||||
udp: option.UDP,
|
||||
iface: option.Interface,
|
||||
rmark: option.RoutingMark,
|
||||
},
|
||||
psk: psk,
|
||||
obfsOption: obfsOption,
|
||||
|
@ -154,6 +154,7 @@ func NewSocks5(option Socks5Option) *Socks5 {
|
||||
tp: C.Socks5,
|
||||
udp: option.UDP,
|
||||
iface: option.Interface,
|
||||
rmark: option.RoutingMark,
|
||||
},
|
||||
user: option.UserName,
|
||||
pass: option.Password,
|
||||
|
@ -173,6 +173,7 @@ func NewTrojan(option TrojanOption) (*Trojan, error) {
|
||||
tp: C.Trojan,
|
||||
udp: option.UDP,
|
||||
iface: option.Interface,
|
||||
rmark: option.RoutingMark,
|
||||
},
|
||||
instance: trojan.New(tOption),
|
||||
option: &option,
|
||||
|
@ -280,6 +280,7 @@ func NewVmess(option VmessOption) (*Vmess, error) {
|
||||
tp: C.Vmess,
|
||||
udp: option.UDP,
|
||||
iface: option.Interface,
|
||||
rmark: option.RoutingMark,
|
||||
},
|
||||
client: client,
|
||||
option: &option,
|
||||
|
@ -59,7 +59,7 @@ func (f *Fallback) MarshalJSON() ([]byte, error) {
|
||||
for _, proxy := range f.proxies(false) {
|
||||
all = append(all, proxy.Name())
|
||||
}
|
||||
return json.Marshal(map[string]interface{}{
|
||||
return json.Marshal(map[string]any{
|
||||
"type": f.Type().String(),
|
||||
"now": f.Now(),
|
||||
"all": all,
|
||||
@ -73,7 +73,7 @@ func (f *Fallback) Unwrap(metadata *C.Metadata) C.Proxy {
|
||||
}
|
||||
|
||||
func (f *Fallback) proxies(touch bool) []C.Proxy {
|
||||
elm, _, _ := f.single.Do(func() (interface{}, error) {
|
||||
elm, _, _ := f.single.Do(func() (any, error) {
|
||||
return getProvidersProxies(f.providers, touch), nil
|
||||
})
|
||||
|
||||
|
@ -29,7 +29,7 @@ type LoadBalance struct {
|
||||
|
||||
var errStrategy = errors.New("unsupported strategy")
|
||||
|
||||
func parseStrategy(config map[string]interface{}) string {
|
||||
func parseStrategy(config map[string]any) string {
|
||||
if elm, ok := config["strategy"]; ok {
|
||||
if strategy, ok := elm.(string); ok {
|
||||
return strategy
|
||||
@ -140,7 +140,7 @@ func (lb *LoadBalance) Unwrap(metadata *C.Metadata) C.Proxy {
|
||||
}
|
||||
|
||||
func (lb *LoadBalance) proxies(touch bool) []C.Proxy {
|
||||
elm, _, _ := lb.single.Do(func() (interface{}, error) {
|
||||
elm, _, _ := lb.single.Do(func() (any, error) {
|
||||
return getProvidersProxies(lb.providers, touch), nil
|
||||
})
|
||||
|
||||
@ -153,7 +153,7 @@ func (lb *LoadBalance) MarshalJSON() ([]byte, error) {
|
||||
for _, proxy := range lb.proxies(false) {
|
||||
all = append(all, proxy.Name())
|
||||
}
|
||||
return json.Marshal(map[string]interface{}{
|
||||
return json.Marshal(map[string]any{
|
||||
"type": lb.Type().String(),
|
||||
"all": all,
|
||||
})
|
||||
|
@ -31,7 +31,7 @@ type GroupCommonOption struct {
|
||||
DisableUDP bool `group:"disable-udp,omitempty"`
|
||||
}
|
||||
|
||||
func ParseProxyGroup(config map[string]interface{}, proxyMap map[string]C.Proxy, providersMap map[string]types.ProxyProvider) (C.ProxyAdapter, error) {
|
||||
func ParseProxyGroup(config map[string]any, proxyMap map[string]C.Proxy, providersMap map[string]types.ProxyProvider) (C.ProxyAdapter, error) {
|
||||
decoder := structure.NewDecoder(structure.Option{TagName: "group", WeaklyTypedInput: true})
|
||||
|
||||
groupOption := &GroupCommonOption{
|
||||
|
@ -72,14 +72,14 @@ func (r *Relay) MarshalJSON() ([]byte, error) {
|
||||
for _, proxy := range r.rawProxies(false) {
|
||||
all = append(all, proxy.Name())
|
||||
}
|
||||
return json.Marshal(map[string]interface{}{
|
||||
return json.Marshal(map[string]any{
|
||||
"type": r.Type().String(),
|
||||
"all": all,
|
||||
})
|
||||
}
|
||||
|
||||
func (r *Relay) rawProxies(touch bool) []C.Proxy {
|
||||
elm, _, _ := r.single.Do(func() (interface{}, error) {
|
||||
elm, _, _ := r.single.Do(func() (any, error) {
|
||||
return getProvidersProxies(r.providers, touch), nil
|
||||
})
|
||||
|
||||
|
@ -54,7 +54,7 @@ func (s *Selector) MarshalJSON() ([]byte, error) {
|
||||
all = append(all, proxy.Name())
|
||||
}
|
||||
|
||||
return json.Marshal(map[string]interface{}{
|
||||
return json.Marshal(map[string]any{
|
||||
"type": s.Type().String(),
|
||||
"now": s.Now(),
|
||||
"all": all,
|
||||
@ -83,7 +83,7 @@ func (s *Selector) Unwrap(metadata *C.Metadata) C.Proxy {
|
||||
}
|
||||
|
||||
func (s *Selector) selectedProxy(touch bool) C.Proxy {
|
||||
elm, _, _ := s.single.Do(func() (interface{}, error) {
|
||||
elm, _, _ := s.single.Do(func() (any, error) {
|
||||
proxies := getProvidersProxies(s.providers, touch)
|
||||
for _, proxy := range proxies {
|
||||
if proxy.Name() == s.selected {
|
||||
|
@ -58,7 +58,7 @@ func (u *URLTest) Unwrap(metadata *C.Metadata) C.Proxy {
|
||||
}
|
||||
|
||||
func (u *URLTest) proxies(touch bool) []C.Proxy {
|
||||
elm, _, _ := u.single.Do(func() (interface{}, error) {
|
||||
elm, _, _ := u.single.Do(func() (any, error) {
|
||||
return getProvidersProxies(u.providers, touch), nil
|
||||
})
|
||||
|
||||
@ -66,7 +66,7 @@ func (u *URLTest) proxies(touch bool) []C.Proxy {
|
||||
}
|
||||
|
||||
func (u *URLTest) fast(touch bool) C.Proxy {
|
||||
elm, _, _ := u.fastSingle.Do(func() (interface{}, error) {
|
||||
elm, _, _ := u.fastSingle.Do(func() (any, error) {
|
||||
proxies := u.proxies(touch)
|
||||
fast := proxies[0]
|
||||
min := fast.LastDelay()
|
||||
@ -114,14 +114,14 @@ func (u *URLTest) MarshalJSON() ([]byte, error) {
|
||||
for _, proxy := range u.proxies(false) {
|
||||
all = append(all, proxy.Name())
|
||||
}
|
||||
return json.Marshal(map[string]interface{}{
|
||||
return json.Marshal(map[string]any{
|
||||
"type": u.Type().String(),
|
||||
"now": u.Now(),
|
||||
"all": all,
|
||||
})
|
||||
}
|
||||
|
||||
func parseURLTestOption(config map[string]interface{}) []urlTestOption {
|
||||
func parseURLTestOption(config map[string]any) []urlTestOption {
|
||||
opts := []urlTestOption{}
|
||||
|
||||
// tolerance
|
||||
|
@ -8,7 +8,7 @@ import (
|
||||
C "github.com/Dreamacro/clash/constant"
|
||||
)
|
||||
|
||||
func ParseProxy(mapping map[string]interface{}) (C.Proxy, error) {
|
||||
func ParseProxy(mapping map[string]any) (C.Proxy, error) {
|
||||
decoder := structure.NewDecoder(structure.Option{TagName: "proxy", WeaklyTypedInput: true})
|
||||
proxyType, existType := mapping["type"].(string)
|
||||
if !existType {
|
||||
|
@ -16,7 +16,7 @@ var (
|
||||
dirMode os.FileMode = 0o755
|
||||
)
|
||||
|
||||
type parser = func([]byte) (interface{}, error)
|
||||
type parser = func([]byte) (any, error)
|
||||
|
||||
type fetcher struct {
|
||||
name string
|
||||
@ -26,7 +26,7 @@ type fetcher struct {
|
||||
done chan struct{}
|
||||
hash [16]byte
|
||||
parser parser
|
||||
onUpdate func(interface{})
|
||||
onUpdate func(any)
|
||||
}
|
||||
|
||||
func (f *fetcher) Name() string {
|
||||
@ -37,7 +37,7 @@ func (f *fetcher) VehicleType() types.VehicleType {
|
||||
return f.vehicle.Type()
|
||||
}
|
||||
|
||||
func (f *fetcher) Initial() (interface{}, error) {
|
||||
func (f *fetcher) Initial() (any, error) {
|
||||
var (
|
||||
buf []byte
|
||||
err error
|
||||
@ -92,7 +92,7 @@ func (f *fetcher) Initial() (interface{}, error) {
|
||||
return proxies, nil
|
||||
}
|
||||
|
||||
func (f *fetcher) Update() (interface{}, bool, error) {
|
||||
func (f *fetcher) Update() (any, bool, error) {
|
||||
buf, err := f.vehicle.Read()
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
@ -168,7 +168,7 @@ func safeWrite(path string, buf []byte) error {
|
||||
return os.WriteFile(path, buf, fileMode)
|
||||
}
|
||||
|
||||
func newFetcher(name string, interval time.Duration, vehicle types.Vehicle, parser parser, onUpdate func(interface{})) *fetcher {
|
||||
func newFetcher(name string, interval time.Duration, vehicle types.Vehicle, parser parser, onUpdate func(any)) *fetcher {
|
||||
var ticker *time.Ticker
|
||||
if interval != 0 {
|
||||
ticker = time.NewTicker(interval)
|
||||
|
@ -62,7 +62,7 @@ func (hc *HealthCheck) check() {
|
||||
b, _ := batch.New(context.Background(), batch.WithConcurrencyNum(10))
|
||||
for _, proxy := range hc.proxies {
|
||||
p := proxy
|
||||
b.Go(p.Name(), func() (interface{}, error) {
|
||||
b.Go(p.Name(), func() (any, error) {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), defaultURLTestTimeout)
|
||||
defer cancel()
|
||||
p.URLTest(ctx, hc.url)
|
||||
|
@ -28,7 +28,7 @@ type proxyProviderSchema struct {
|
||||
HealthCheck healthCheckSchema `provider:"health-check,omitempty"`
|
||||
}
|
||||
|
||||
func ParseProxyProvider(name string, mapping map[string]interface{}) (types.ProxyProvider, error) {
|
||||
func ParseProxyProvider(name string, mapping map[string]any) (types.ProxyProvider, error) {
|
||||
decoder := structure.NewDecoder(structure.Option{TagName: "provider", WeaklyTypedInput: true})
|
||||
|
||||
schema := &proxyProviderSchema{
|
||||
|
@ -20,7 +20,7 @@ const (
|
||||
)
|
||||
|
||||
type ProxySchema struct {
|
||||
Proxies []map[string]interface{} `yaml:"proxies"`
|
||||
Proxies []map[string]any `yaml:"proxies"`
|
||||
}
|
||||
|
||||
// for auto gc
|
||||
@ -35,7 +35,7 @@ type proxySetProvider struct {
|
||||
}
|
||||
|
||||
func (pp *proxySetProvider) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(map[string]interface{}{
|
||||
return json.Marshal(map[string]any{
|
||||
"name": pp.Name(),
|
||||
"type": pp.Type().String(),
|
||||
"vehicleType": pp.VehicleType().String(),
|
||||
@ -111,12 +111,12 @@ func NewProxySetProvider(name string, interval time.Duration, filter string, veh
|
||||
healthCheck: hc,
|
||||
}
|
||||
|
||||
onUpdate := func(elm interface{}) {
|
||||
onUpdate := func(elm any) {
|
||||
ret := elm.([]C.Proxy)
|
||||
pd.setProxies(ret)
|
||||
}
|
||||
|
||||
proxiesParseAndFilter := func(buf []byte) (interface{}, error) {
|
||||
proxiesParseAndFilter := func(buf []byte) (any, error) {
|
||||
schema := &ProxySchema{}
|
||||
|
||||
if err := yaml.Unmarshal(buf, schema); err != nil {
|
||||
@ -169,7 +169,7 @@ type compatibleProvider struct {
|
||||
}
|
||||
|
||||
func (cp *compatibleProvider) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(map[string]interface{}{
|
||||
return json.Marshal(map[string]any{
|
||||
"name": cp.Name(),
|
||||
"type": cp.Type().String(),
|
||||
"vehicleType": cp.VehicleType().String(),
|
||||
|
@ -8,7 +8,7 @@ import (
|
||||
type Option = func(b *Batch)
|
||||
|
||||
type Result struct {
|
||||
Value interface{}
|
||||
Value any
|
||||
Err error
|
||||
}
|
||||
|
||||
@ -38,7 +38,7 @@ type Batch struct {
|
||||
cancel func()
|
||||
}
|
||||
|
||||
func (b *Batch) Go(key string, fn func() (interface{}, error)) {
|
||||
func (b *Batch) Go(key string, fn func() (any, error)) {
|
||||
b.wg.Add(1)
|
||||
go func() {
|
||||
defer b.wg.Done()
|
||||
|
@ -14,11 +14,11 @@ func TestBatch(t *testing.T) {
|
||||
b, _ := New(context.Background())
|
||||
|
||||
now := time.Now()
|
||||
b.Go("foo", func() (interface{}, error) {
|
||||
b.Go("foo", func() (any, error) {
|
||||
time.Sleep(time.Millisecond * 100)
|
||||
return "foo", nil
|
||||
})
|
||||
b.Go("bar", func() (interface{}, error) {
|
||||
b.Go("bar", func() (any, error) {
|
||||
time.Sleep(time.Millisecond * 150)
|
||||
return "bar", nil
|
||||
})
|
||||
@ -45,7 +45,7 @@ func TestBatchWithConcurrencyNum(t *testing.T) {
|
||||
now := time.Now()
|
||||
for i := 0; i < 7; i++ {
|
||||
idx := i
|
||||
b.Go(strconv.Itoa(idx), func() (interface{}, error) {
|
||||
b.Go(strconv.Itoa(idx), func() (any, error) {
|
||||
time.Sleep(time.Millisecond * 100)
|
||||
return strconv.Itoa(idx), nil
|
||||
})
|
||||
@ -64,12 +64,12 @@ func TestBatchWithConcurrencyNum(t *testing.T) {
|
||||
func TestBatchContext(t *testing.T) {
|
||||
b, ctx := New(context.Background())
|
||||
|
||||
b.Go("error", func() (interface{}, error) {
|
||||
b.Go("error", func() (any, error) {
|
||||
time.Sleep(time.Millisecond * 100)
|
||||
return nil, errors.New("test error")
|
||||
})
|
||||
|
||||
b.Go("ctx", func() (interface{}, error) {
|
||||
b.Go("ctx", func() (any, error) {
|
||||
<-ctx.Done()
|
||||
return nil, ctx.Err()
|
||||
})
|
||||
|
10
common/cache/cache.go
vendored
10
common/cache/cache.go
vendored
@ -18,11 +18,11 @@ type cache struct {
|
||||
|
||||
type element struct {
|
||||
Expired time.Time
|
||||
Payload interface{}
|
||||
Payload any
|
||||
}
|
||||
|
||||
// Put element in Cache with its ttl
|
||||
func (c *cache) Put(key interface{}, payload interface{}, ttl time.Duration) {
|
||||
func (c *cache) Put(key any, payload any, ttl time.Duration) {
|
||||
c.mapping.Store(key, &element{
|
||||
Payload: payload,
|
||||
Expired: time.Now().Add(ttl),
|
||||
@ -30,7 +30,7 @@ func (c *cache) Put(key interface{}, payload interface{}, ttl time.Duration) {
|
||||
}
|
||||
|
||||
// Get element in Cache, and drop when it expired
|
||||
func (c *cache) Get(key interface{}) interface{} {
|
||||
func (c *cache) Get(key any) any {
|
||||
item, exist := c.mapping.Load(key)
|
||||
if !exist {
|
||||
return nil
|
||||
@ -45,7 +45,7 @@ func (c *cache) Get(key interface{}) interface{} {
|
||||
}
|
||||
|
||||
// GetWithExpire element in Cache with Expire Time
|
||||
func (c *cache) GetWithExpire(key interface{}) (payload interface{}, expired time.Time) {
|
||||
func (c *cache) GetWithExpire(key any) (payload any, expired time.Time) {
|
||||
item, exist := c.mapping.Load(key)
|
||||
if !exist {
|
||||
return
|
||||
@ -60,7 +60,7 @@ func (c *cache) GetWithExpire(key interface{}) (payload interface{}, expired tim
|
||||
}
|
||||
|
||||
func (c *cache) cleanup() {
|
||||
c.mapping.Range(func(k, v interface{}) bool {
|
||||
c.mapping.Range(func(k, v any) bool {
|
||||
key := k.(string)
|
||||
elm := v.(*element)
|
||||
if time.Since(elm.Expired) > 0 {
|
||||
|
34
common/cache/lrucache.go
vendored
34
common/cache/lrucache.go
vendored
@ -12,7 +12,7 @@ import (
|
||||
type Option func(*LruCache)
|
||||
|
||||
// EvictCallback is used to get a callback when a cache entry is evicted
|
||||
type EvictCallback = func(key interface{}, value interface{})
|
||||
type EvictCallback = func(key any, value any)
|
||||
|
||||
// WithEvict set the evict callback
|
||||
func WithEvict(cb EvictCallback) Option {
|
||||
@ -57,7 +57,7 @@ type LruCache struct {
|
||||
maxAge int64
|
||||
maxSize int
|
||||
mu sync.Mutex
|
||||
cache map[interface{}]*list.Element
|
||||
cache map[any]*list.Element
|
||||
lru *list.List // Front is least-recent
|
||||
updateAgeOnGet bool
|
||||
staleReturn bool
|
||||
@ -68,7 +68,7 @@ type LruCache struct {
|
||||
func NewLRUCache(options ...Option) *LruCache {
|
||||
lc := &LruCache{
|
||||
lru: list.New(),
|
||||
cache: make(map[interface{}]*list.Element),
|
||||
cache: make(map[any]*list.Element),
|
||||
}
|
||||
|
||||
for _, option := range options {
|
||||
@ -78,9 +78,9 @@ func NewLRUCache(options ...Option) *LruCache {
|
||||
return lc
|
||||
}
|
||||
|
||||
// Get returns the interface{} representation of a cached response and a bool
|
||||
// Get returns the any representation of a cached response and a bool
|
||||
// set to true if the key was found.
|
||||
func (c *LruCache) Get(key interface{}) (interface{}, bool) {
|
||||
func (c *LruCache) Get(key any) (any, bool) {
|
||||
entry := c.get(key)
|
||||
if entry == nil {
|
||||
return nil, false
|
||||
@ -90,11 +90,11 @@ func (c *LruCache) Get(key interface{}) (interface{}, bool) {
|
||||
return value, true
|
||||
}
|
||||
|
||||
// GetWithExpire returns the interface{} representation of a cached response,
|
||||
// GetWithExpire returns the any representation of a cached response,
|
||||
// a time.Time Give expected expires,
|
||||
// and a bool set to true if the key was found.
|
||||
// This method will NOT check the maxAge of element and will NOT update the expires.
|
||||
func (c *LruCache) GetWithExpire(key interface{}) (interface{}, time.Time, bool) {
|
||||
func (c *LruCache) GetWithExpire(key any) (any, time.Time, bool) {
|
||||
entry := c.get(key)
|
||||
if entry == nil {
|
||||
return nil, time.Time{}, false
|
||||
@ -104,7 +104,7 @@ func (c *LruCache) GetWithExpire(key interface{}) (interface{}, time.Time, bool)
|
||||
}
|
||||
|
||||
// Exist returns if key exist in cache but not put item to the head of linked list
|
||||
func (c *LruCache) Exist(key interface{}) bool {
|
||||
func (c *LruCache) Exist(key any) bool {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
|
||||
@ -112,8 +112,8 @@ func (c *LruCache) Exist(key interface{}) bool {
|
||||
return ok
|
||||
}
|
||||
|
||||
// Set stores the interface{} representation of a response for a given key.
|
||||
func (c *LruCache) Set(key interface{}, value interface{}) {
|
||||
// Set stores the any representation of a response for a given key.
|
||||
func (c *LruCache) Set(key any, value any) {
|
||||
expires := int64(0)
|
||||
if c.maxAge > 0 {
|
||||
expires = time.Now().Unix() + c.maxAge
|
||||
@ -121,9 +121,9 @@ func (c *LruCache) Set(key interface{}, value interface{}) {
|
||||
c.SetWithExpire(key, value, time.Unix(expires, 0))
|
||||
}
|
||||
|
||||
// SetWithExpire stores the interface{} representation of a response for a given key and given expires.
|
||||
// SetWithExpire stores the any representation of a response for a given key and given expires.
|
||||
// The expires time will round to second.
|
||||
func (c *LruCache) SetWithExpire(key interface{}, value interface{}, expires time.Time) {
|
||||
func (c *LruCache) SetWithExpire(key any, value any, expires time.Time) {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
|
||||
@ -155,7 +155,7 @@ func (c *LruCache) CloneTo(n *LruCache) {
|
||||
defer n.mu.Unlock()
|
||||
|
||||
n.lru = list.New()
|
||||
n.cache = make(map[interface{}]*list.Element)
|
||||
n.cache = make(map[any]*list.Element)
|
||||
|
||||
for e := c.lru.Front(); e != nil; e = e.Next() {
|
||||
elm := e.Value.(*entry)
|
||||
@ -163,7 +163,7 @@ func (c *LruCache) CloneTo(n *LruCache) {
|
||||
}
|
||||
}
|
||||
|
||||
func (c *LruCache) get(key interface{}) *entry {
|
||||
func (c *LruCache) get(key any) *entry {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
|
||||
@ -188,7 +188,7 @@ func (c *LruCache) get(key interface{}) *entry {
|
||||
}
|
||||
|
||||
// Delete removes the value associated with a key.
|
||||
func (c *LruCache) Delete(key interface{}) {
|
||||
func (c *LruCache) Delete(key any) {
|
||||
c.mu.Lock()
|
||||
|
||||
if le, ok := c.cache[key]; ok {
|
||||
@ -217,7 +217,7 @@ func (c *LruCache) deleteElement(le *list.Element) {
|
||||
}
|
||||
|
||||
type entry struct {
|
||||
key interface{}
|
||||
value interface{}
|
||||
key any
|
||||
value any
|
||||
expires int64
|
||||
}
|
||||
|
2
common/cache/lrucache_test.go
vendored
2
common/cache/lrucache_test.go
vendored
@ -126,7 +126,7 @@ func TestExist(t *testing.T) {
|
||||
|
||||
func TestEvict(t *testing.T) {
|
||||
temp := 0
|
||||
evict := func(key interface{}, value interface{}) {
|
||||
evict := func(key any, value any) {
|
||||
temp = key.(int) + value.(int)
|
||||
}
|
||||
|
||||
|
30
common/net/relay.go
Normal file
30
common/net/relay.go
Normal file
@ -0,0 +1,30 @@
|
||||
package net
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net"
|
||||
"time"
|
||||
|
||||
"github.com/Dreamacro/clash/common/pool"
|
||||
)
|
||||
|
||||
// Relay copies between left and right bidirectionally.
|
||||
func Relay(leftConn, rightConn net.Conn) {
|
||||
ch := make(chan error)
|
||||
|
||||
go func() {
|
||||
buf := pool.Get(pool.RelayBufferSize)
|
||||
// Wrapping to avoid using *net.TCPConn.(ReadFrom)
|
||||
// See also https://github.com/Dreamacro/clash/pull/1209
|
||||
_, err := io.CopyBuffer(WriteOnlyWriter{Writer: leftConn}, ReadOnlyReader{Reader: rightConn}, buf)
|
||||
pool.Put(buf)
|
||||
leftConn.SetReadDeadline(time.Now())
|
||||
ch <- err
|
||||
}()
|
||||
|
||||
buf := pool.Get(pool.RelayBufferSize)
|
||||
io.CopyBuffer(WriteOnlyWriter{Writer: rightConn}, ReadOnlyReader{Reader: leftConn}, buf)
|
||||
pool.Put(buf)
|
||||
rightConn.SetReadDeadline(time.Now())
|
||||
<-ch
|
||||
}
|
@ -1,3 +1,3 @@
|
||||
package observable
|
||||
|
||||
type Iterable <-chan interface{}
|
||||
type Iterable <-chan any
|
||||
|
@ -9,8 +9,8 @@ import (
|
||||
"go.uber.org/atomic"
|
||||
)
|
||||
|
||||
func iterator(item []interface{}) chan interface{} {
|
||||
ch := make(chan interface{})
|
||||
func iterator(item []any) chan any {
|
||||
ch := make(chan any)
|
||||
go func() {
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
for _, elm := range item {
|
||||
@ -22,7 +22,7 @@ func iterator(item []interface{}) chan interface{} {
|
||||
}
|
||||
|
||||
func TestObservable(t *testing.T) {
|
||||
iter := iterator([]interface{}{1, 2, 3, 4, 5})
|
||||
iter := iterator([]any{1, 2, 3, 4, 5})
|
||||
src := NewObservable(iter)
|
||||
data, err := src.Subscribe()
|
||||
assert.Nil(t, err)
|
||||
@ -34,7 +34,7 @@ func TestObservable(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestObservable_MultiSubscribe(t *testing.T) {
|
||||
iter := iterator([]interface{}{1, 2, 3, 4, 5})
|
||||
iter := iterator([]any{1, 2, 3, 4, 5})
|
||||
src := NewObservable(iter)
|
||||
ch1, _ := src.Subscribe()
|
||||
ch2, _ := src.Subscribe()
|
||||
@ -42,7 +42,7 @@ func TestObservable_MultiSubscribe(t *testing.T) {
|
||||
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(2)
|
||||
waitCh := func(ch <-chan interface{}) {
|
||||
waitCh := func(ch <-chan any) {
|
||||
for range ch {
|
||||
count.Inc()
|
||||
}
|
||||
@ -55,7 +55,7 @@ func TestObservable_MultiSubscribe(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestObservable_UnSubscribe(t *testing.T) {
|
||||
iter := iterator([]interface{}{1, 2, 3, 4, 5})
|
||||
iter := iterator([]any{1, 2, 3, 4, 5})
|
||||
src := NewObservable(iter)
|
||||
data, err := src.Subscribe()
|
||||
assert.Nil(t, err)
|
||||
@ -65,7 +65,7 @@ func TestObservable_UnSubscribe(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestObservable_SubscribeClosedSource(t *testing.T) {
|
||||
iter := iterator([]interface{}{1})
|
||||
iter := iterator([]any{1})
|
||||
src := NewObservable(iter)
|
||||
data, _ := src.Subscribe()
|
||||
<-data
|
||||
@ -75,14 +75,14 @@ func TestObservable_SubscribeClosedSource(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestObservable_UnSubscribeWithNotExistSubscription(t *testing.T) {
|
||||
sub := Subscription(make(chan interface{}))
|
||||
iter := iterator([]interface{}{1})
|
||||
sub := Subscription(make(chan any))
|
||||
iter := iterator([]any{1})
|
||||
src := NewObservable(iter)
|
||||
src.UnSubscribe(sub)
|
||||
}
|
||||
|
||||
func TestObservable_SubscribeGoroutineLeak(t *testing.T) {
|
||||
iter := iterator([]interface{}{1, 2, 3, 4, 5})
|
||||
iter := iterator([]any{1, 2, 3, 4, 5})
|
||||
src := NewObservable(iter)
|
||||
max := 100
|
||||
|
||||
@ -94,7 +94,7 @@ func TestObservable_SubscribeGoroutineLeak(t *testing.T) {
|
||||
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(max)
|
||||
waitCh := func(ch <-chan interface{}) {
|
||||
waitCh := func(ch <-chan any) {
|
||||
for range ch {
|
||||
}
|
||||
wg.Done()
|
||||
@ -115,7 +115,7 @@ func TestObservable_SubscribeGoroutineLeak(t *testing.T) {
|
||||
}
|
||||
|
||||
func Benchmark_Observable_1000(b *testing.B) {
|
||||
ch := make(chan interface{})
|
||||
ch := make(chan any)
|
||||
o := NewObservable(ch)
|
||||
num := 1000
|
||||
|
||||
|
@ -4,14 +4,14 @@ import (
|
||||
"sync"
|
||||
)
|
||||
|
||||
type Subscription <-chan interface{}
|
||||
type Subscription <-chan any
|
||||
|
||||
type Subscriber struct {
|
||||
buffer chan interface{}
|
||||
buffer chan any
|
||||
once sync.Once
|
||||
}
|
||||
|
||||
func (s *Subscriber) Emit(item interface{}) {
|
||||
func (s *Subscriber) Emit(item any) {
|
||||
s.buffer <- item
|
||||
}
|
||||
|
||||
@ -27,7 +27,7 @@ func (s *Subscriber) Close() {
|
||||
|
||||
func newSubscriber() *Subscriber {
|
||||
sub := &Subscriber{
|
||||
buffer: make(chan interface{}, 200),
|
||||
buffer: make(chan any, 200),
|
||||
}
|
||||
return sub
|
||||
}
|
||||
|
@ -17,7 +17,7 @@ type Picker struct {
|
||||
|
||||
once sync.Once
|
||||
errOnce sync.Once
|
||||
result interface{}
|
||||
result any
|
||||
err error
|
||||
}
|
||||
|
||||
@ -43,7 +43,7 @@ func WithTimeout(ctx context.Context, timeout time.Duration) (*Picker, context.C
|
||||
|
||||
// Wait blocks until all function calls from the Go method have returned,
|
||||
// then returns the first nil error result (if any) from them.
|
||||
func (p *Picker) Wait() interface{} {
|
||||
func (p *Picker) Wait() any {
|
||||
p.wg.Wait()
|
||||
if p.cancel != nil {
|
||||
p.cancel()
|
||||
@ -58,7 +58,7 @@ func (p *Picker) Error() error {
|
||||
|
||||
// Go calls the given function in a new goroutine.
|
||||
// The first call to return a nil error cancels the group; its result will be returned by Wait.
|
||||
func (p *Picker) Go(f func() (interface{}, error)) {
|
||||
func (p *Picker) Go(f func() (any, error)) {
|
||||
p.wg.Add(1)
|
||||
|
||||
go func() {
|
||||
|
@ -8,8 +8,8 @@ import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func sleepAndSend(ctx context.Context, delay int, input interface{}) func() (interface{}, error) {
|
||||
return func() (interface{}, error) {
|
||||
func sleepAndSend(ctx context.Context, delay int, input any) func() (any, error) {
|
||||
return func() (any, error) {
|
||||
timer := time.NewTimer(time.Millisecond * time.Duration(delay))
|
||||
select {
|
||||
case <-timer.C:
|
||||
|
@ -23,7 +23,7 @@ func NewAllocator() *Allocator {
|
||||
alloc.buffers = make([]sync.Pool, 17) // 1B -> 64K
|
||||
for k := range alloc.buffers {
|
||||
i := k
|
||||
alloc.buffers[k].New = func() interface{} {
|
||||
alloc.buffers[k].New = func() any {
|
||||
return make([]byte, 1<<uint32(i))
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ import (
|
||||
"sync"
|
||||
)
|
||||
|
||||
var bufferPool = sync.Pool{New: func() interface{} { return &bytes.Buffer{} }}
|
||||
var bufferPool = sync.Pool{New: func() any { return &bytes.Buffer{} }}
|
||||
|
||||
func GetBuffer() *bytes.Buffer {
|
||||
return bufferPool.Get().(*bytes.Buffer)
|
||||
|
@ -6,12 +6,12 @@ import (
|
||||
|
||||
// Queue is a simple concurrent safe queue
|
||||
type Queue struct {
|
||||
items []interface{}
|
||||
items []any
|
||||
lock sync.RWMutex
|
||||
}
|
||||
|
||||
// Put add the item to the queue.
|
||||
func (q *Queue) Put(items ...interface{}) {
|
||||
func (q *Queue) Put(items ...any) {
|
||||
if len(items) == 0 {
|
||||
return
|
||||
}
|
||||
@ -22,7 +22,7 @@ func (q *Queue) Put(items ...interface{}) {
|
||||
}
|
||||
|
||||
// Pop returns the head of items.
|
||||
func (q *Queue) Pop() interface{} {
|
||||
func (q *Queue) Pop() any {
|
||||
if len(q.items) == 0 {
|
||||
return nil
|
||||
}
|
||||
@ -35,7 +35,7 @@ func (q *Queue) Pop() interface{} {
|
||||
}
|
||||
|
||||
// Last returns the last of item.
|
||||
func (q *Queue) Last() interface{} {
|
||||
func (q *Queue) Last() any {
|
||||
if len(q.items) == 0 {
|
||||
return nil
|
||||
}
|
||||
@ -47,8 +47,8 @@ func (q *Queue) Last() interface{} {
|
||||
}
|
||||
|
||||
// Copy get the copy of queue.
|
||||
func (q *Queue) Copy() []interface{} {
|
||||
items := []interface{}{}
|
||||
func (q *Queue) Copy() []any {
|
||||
items := []any{}
|
||||
q.lock.RLock()
|
||||
items = append(items, q.items...)
|
||||
q.lock.RUnlock()
|
||||
@ -66,6 +66,6 @@ func (q *Queue) Len() int64 {
|
||||
// New is a constructor for a new concurrent safe queue.
|
||||
func New(hint int64) *Queue {
|
||||
return &Queue{
|
||||
items: make([]interface{}, 0, hint),
|
||||
items: make([]any, 0, hint),
|
||||
}
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ import (
|
||||
|
||||
type call struct {
|
||||
wg sync.WaitGroup
|
||||
val interface{}
|
||||
val any
|
||||
err error
|
||||
}
|
||||
|
||||
@ -20,13 +20,13 @@ type Single struct {
|
||||
}
|
||||
|
||||
type Result struct {
|
||||
Val interface{}
|
||||
Val any
|
||||
Err error
|
||||
}
|
||||
|
||||
// Do single.Do likes sync.singleFlight
|
||||
//lint:ignore ST1008 it likes sync.singleFlight
|
||||
func (s *Single) Do(fn func() (interface{}, error)) (v interface{}, err error, shared bool) {
|
||||
func (s *Single) Do(fn func() (any, error)) (v any, err error, shared bool) {
|
||||
s.mux.Lock()
|
||||
now := time.Now()
|
||||
if now.Before(s.last.Add(s.wait)) {
|
||||
|
@ -13,7 +13,7 @@ func TestBasic(t *testing.T) {
|
||||
single := NewSingle(time.Millisecond * 30)
|
||||
foo := 0
|
||||
shardCount := atomic.NewInt32(0)
|
||||
call := func() (interface{}, error) {
|
||||
call := func() (any, error) {
|
||||
foo++
|
||||
time.Sleep(time.Millisecond * 5)
|
||||
return nil, nil
|
||||
@ -40,7 +40,7 @@ func TestBasic(t *testing.T) {
|
||||
func TestTimer(t *testing.T) {
|
||||
single := NewSingle(time.Millisecond * 30)
|
||||
foo := 0
|
||||
call := func() (interface{}, error) {
|
||||
call := func() (any, error) {
|
||||
foo++
|
||||
return nil, nil
|
||||
}
|
||||
@ -56,7 +56,7 @@ func TestTimer(t *testing.T) {
|
||||
func TestReset(t *testing.T) {
|
||||
single := NewSingle(time.Millisecond * 30)
|
||||
foo := 0
|
||||
call := func() (interface{}, error) {
|
||||
call := func() (any, error) {
|
||||
foo++
|
||||
return nil, nil
|
||||
}
|
||||
|
@ -1,5 +1,4 @@
|
||||
//go:build !linux
|
||||
// +build !linux
|
||||
|
||||
package sockopt
|
||||
|
||||
|
@ -28,8 +28,8 @@ func NewDecoder(option Option) *Decoder {
|
||||
return &Decoder{option: &option}
|
||||
}
|
||||
|
||||
// Decode transform a map[string]interface{} to a struct
|
||||
func (d *Decoder) Decode(src map[string]interface{}, dst interface{}) error {
|
||||
// Decode transform a map[string]any to a struct
|
||||
func (d *Decoder) Decode(src map[string]any, dst any) error {
|
||||
if reflect.TypeOf(dst).Kind() != reflect.Ptr {
|
||||
return fmt.Errorf("Decode must recive a ptr struct")
|
||||
}
|
||||
@ -45,12 +45,8 @@ func (d *Decoder) Decode(src map[string]interface{}, dst interface{}) error {
|
||||
}
|
||||
|
||||
tag := field.Tag.Get(d.option.TagName)
|
||||
str := strings.SplitN(tag, ",", 2)
|
||||
key := str[0]
|
||||
omitempty := false
|
||||
if len(str) > 1 {
|
||||
omitempty = str[1] == "omitempty"
|
||||
}
|
||||
key, omitKey, found := strings.Cut(tag, ",")
|
||||
omitempty := found && omitKey == "omitempty"
|
||||
|
||||
value, ok := src[key]
|
||||
if !ok || value == nil {
|
||||
@ -68,7 +64,7 @@ func (d *Decoder) Decode(src map[string]interface{}, dst interface{}) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *Decoder) decode(name string, data interface{}, val reflect.Value) error {
|
||||
func (d *Decoder) decode(name string, data any, val reflect.Value) error {
|
||||
switch val.Kind() {
|
||||
case reflect.Int:
|
||||
return d.decodeInt(name, data, val)
|
||||
@ -89,12 +85,14 @@ func (d *Decoder) decode(name string, data interface{}, val reflect.Value) error
|
||||
}
|
||||
}
|
||||
|
||||
func (d *Decoder) decodeInt(name string, data interface{}, val reflect.Value) (err error) {
|
||||
func (d *Decoder) decodeInt(name string, data any, val reflect.Value) (err error) {
|
||||
dataVal := reflect.ValueOf(data)
|
||||
kind := dataVal.Kind()
|
||||
switch {
|
||||
case kind == reflect.Int:
|
||||
val.SetInt(dataVal.Int())
|
||||
case kind == reflect.Float64 && d.option.WeaklyTypedInput:
|
||||
val.SetInt(int64(dataVal.Float()))
|
||||
case kind == reflect.String && d.option.WeaklyTypedInput:
|
||||
var i int64
|
||||
i, err = strconv.ParseInt(dataVal.String(), 0, val.Type().Bits())
|
||||
@ -112,7 +110,7 @@ func (d *Decoder) decodeInt(name string, data interface{}, val reflect.Value) (e
|
||||
return err
|
||||
}
|
||||
|
||||
func (d *Decoder) decodeString(name string, data interface{}, val reflect.Value) (err error) {
|
||||
func (d *Decoder) decodeString(name string, data any, val reflect.Value) (err error) {
|
||||
dataVal := reflect.ValueOf(data)
|
||||
kind := dataVal.Kind()
|
||||
switch {
|
||||
@ -129,7 +127,7 @@ func (d *Decoder) decodeString(name string, data interface{}, val reflect.Value)
|
||||
return err
|
||||
}
|
||||
|
||||
func (d *Decoder) decodeBool(name string, data interface{}, val reflect.Value) (err error) {
|
||||
func (d *Decoder) decodeBool(name string, data any, val reflect.Value) (err error) {
|
||||
dataVal := reflect.ValueOf(data)
|
||||
kind := dataVal.Kind()
|
||||
switch {
|
||||
@ -146,7 +144,7 @@ func (d *Decoder) decodeBool(name string, data interface{}, val reflect.Value) (
|
||||
return err
|
||||
}
|
||||
|
||||
func (d *Decoder) decodeSlice(name string, data interface{}, val reflect.Value) error {
|
||||
func (d *Decoder) decodeSlice(name string, data any, val reflect.Value) error {
|
||||
dataVal := reflect.Indirect(reflect.ValueOf(data))
|
||||
valType := val.Type()
|
||||
valElemType := valType.Elem()
|
||||
@ -161,9 +159,19 @@ func (d *Decoder) decodeSlice(name string, data interface{}, val reflect.Value)
|
||||
for valSlice.Len() <= i {
|
||||
valSlice = reflect.Append(valSlice, reflect.Zero(valElemType))
|
||||
}
|
||||
currentField := valSlice.Index(i)
|
||||
|
||||
fieldName := fmt.Sprintf("%s[%d]", name, i)
|
||||
if currentData == nil {
|
||||
// in weakly type mode, null will convert to zero value
|
||||
if d.option.WeaklyTypedInput {
|
||||
continue
|
||||
}
|
||||
// in non-weakly type mode, null will convert to nil if element's zero value is nil, otherwise return an error
|
||||
if elemKind := valElemType.Kind(); elemKind == reflect.Map || elemKind == reflect.Slice {
|
||||
continue
|
||||
}
|
||||
return fmt.Errorf("'%s' can not be null", fieldName)
|
||||
}
|
||||
currentField := valSlice.Index(i)
|
||||
if err := d.decode(fieldName, currentData, currentField); err != nil {
|
||||
return err
|
||||
}
|
||||
@ -173,7 +181,7 @@ func (d *Decoder) decodeSlice(name string, data interface{}, val reflect.Value)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *Decoder) decodeMap(name string, data interface{}, val reflect.Value) error {
|
||||
func (d *Decoder) decodeMap(name string, data any, val reflect.Value) error {
|
||||
valType := val.Type()
|
||||
valKeyType := valType.Key()
|
||||
valElemType := valType.Elem()
|
||||
@ -245,7 +253,7 @@ func (d *Decoder) decodeMapFromMap(name string, dataVal reflect.Value, val refle
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *Decoder) decodeStruct(name string, data interface{}, val reflect.Value) error {
|
||||
func (d *Decoder) decodeStruct(name string, data any, val reflect.Value) error {
|
||||
dataVal := reflect.Indirect(reflect.ValueOf(data))
|
||||
|
||||
// If the type of the value to write to and the data match directly,
|
||||
@ -273,7 +281,7 @@ func (d *Decoder) decodeStructFromMap(name string, dataVal, val reflect.Value) e
|
||||
}
|
||||
|
||||
dataValKeys := make(map[reflect.Value]struct{})
|
||||
dataValKeysUnused := make(map[interface{}]struct{})
|
||||
dataValKeysUnused := make(map[any]struct{})
|
||||
for _, dataValKey := range dataVal.MapKeys() {
|
||||
dataValKeys[dataValKey] = struct{}{}
|
||||
dataValKeysUnused[dataValKey.Interface()] = struct{}{}
|
||||
@ -398,7 +406,7 @@ func (d *Decoder) decodeStructFromMap(name string, dataVal, val reflect.Value) e
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *Decoder) setInterface(name string, data interface{}, val reflect.Value) (err error) {
|
||||
func (d *Decoder) setInterface(name string, data any, val reflect.Value) (err error) {
|
||||
dataVal := reflect.ValueOf(data)
|
||||
val.Set(dataVal)
|
||||
return nil
|
||||
|
@ -27,7 +27,7 @@ type BazOptional struct {
|
||||
}
|
||||
|
||||
func TestStructure_Basic(t *testing.T) {
|
||||
rawMap := map[string]interface{}{
|
||||
rawMap := map[string]any{
|
||||
"foo": 1,
|
||||
"bar": "test",
|
||||
"extra": false,
|
||||
@ -45,7 +45,7 @@ func TestStructure_Basic(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestStructure_Slice(t *testing.T) {
|
||||
rawMap := map[string]interface{}{
|
||||
rawMap := map[string]any{
|
||||
"foo": 1,
|
||||
"bar": []string{"one", "two"},
|
||||
}
|
||||
@ -62,7 +62,7 @@ func TestStructure_Slice(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestStructure_Optional(t *testing.T) {
|
||||
rawMap := map[string]interface{}{
|
||||
rawMap := map[string]any{
|
||||
"foo": 1,
|
||||
}
|
||||
|
||||
@ -77,7 +77,7 @@ func TestStructure_Optional(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestStructure_MissingKey(t *testing.T) {
|
||||
rawMap := map[string]interface{}{
|
||||
rawMap := map[string]any{
|
||||
"foo": 1,
|
||||
}
|
||||
|
||||
@ -87,14 +87,14 @@ func TestStructure_MissingKey(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestStructure_ParamError(t *testing.T) {
|
||||
rawMap := map[string]interface{}{}
|
||||
rawMap := map[string]any{}
|
||||
s := Baz{}
|
||||
err := decoder.Decode(rawMap, s)
|
||||
assert.NotNilf(t, err, "should throw error: %#v", s)
|
||||
}
|
||||
|
||||
func TestStructure_SliceTypeError(t *testing.T) {
|
||||
rawMap := map[string]interface{}{
|
||||
rawMap := map[string]any{
|
||||
"foo": 1,
|
||||
"bar": []int{1, 2},
|
||||
}
|
||||
@ -105,7 +105,7 @@ func TestStructure_SliceTypeError(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestStructure_WeakType(t *testing.T) {
|
||||
rawMap := map[string]interface{}{
|
||||
rawMap := map[string]any{
|
||||
"foo": "1",
|
||||
"bar": []int{1},
|
||||
}
|
||||
@ -122,7 +122,7 @@ func TestStructure_WeakType(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestStructure_Nest(t *testing.T) {
|
||||
rawMap := map[string]interface{}{
|
||||
rawMap := map[string]any{
|
||||
"foo": 1,
|
||||
}
|
||||
|
||||
@ -137,3 +137,45 @@ func TestStructure_Nest(t *testing.T) {
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, s.BazOptional, goal)
|
||||
}
|
||||
|
||||
func TestStructure_SliceNilValue(t *testing.T) {
|
||||
rawMap := map[string]any{
|
||||
"foo": 1,
|
||||
"bar": []any{"bar", nil},
|
||||
}
|
||||
|
||||
goal := &BazSlice{
|
||||
Foo: 1,
|
||||
Bar: []string{"bar", ""},
|
||||
}
|
||||
|
||||
s := &BazSlice{}
|
||||
err := weakTypeDecoder.Decode(rawMap, s)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, goal.Bar, s.Bar)
|
||||
|
||||
s = &BazSlice{}
|
||||
err = decoder.Decode(rawMap, s)
|
||||
assert.NotNil(t, err)
|
||||
}
|
||||
|
||||
func TestStructure_SliceNilValueComplex(t *testing.T) {
|
||||
rawMap := map[string]any{
|
||||
"bar": []any{map[string]any{"bar": "foo"}, nil},
|
||||
}
|
||||
|
||||
s := &struct {
|
||||
Bar []map[string]any `test:"bar"`
|
||||
}{}
|
||||
|
||||
err := decoder.Decode(rawMap, s)
|
||||
assert.Nil(t, err)
|
||||
assert.Nil(t, s.Bar[1])
|
||||
|
||||
ss := &struct {
|
||||
Bar []Baz `test:"bar"`
|
||||
}{}
|
||||
|
||||
err = decoder.Decode(rawMap, ss)
|
||||
assert.NotNil(t, err)
|
||||
}
|
||||
|
@ -36,7 +36,7 @@ func NewAuthenticator(users []AuthUser) Authenticator {
|
||||
au.storage.Store(user.User, user.Pass)
|
||||
}
|
||||
usernames := make([]string, 0, len(users))
|
||||
au.storage.Range(func(key, value interface{}) bool {
|
||||
au.storage.Range(func(key, value any) bool {
|
||||
usernames = append(usernames, key.(string))
|
||||
return true
|
||||
})
|
||||
|
@ -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
|
||||
|
@ -1,5 +1,4 @@
|
||||
//go:build !linux && !darwin
|
||||
// +build !linux,!darwin
|
||||
|
||||
package dialer
|
||||
|
||||
|
@ -38,6 +38,7 @@ func DialContext(ctx context.Context, network, address string, options ...Option
|
||||
func ListenPacket(ctx context.Context, network, address string, options ...Option) (net.PacketConn, error) {
|
||||
cfg := &option{
|
||||
interfaceName: DefaultInterface.Load(),
|
||||
routingMark: int(DefaultRoutingMark.Load()),
|
||||
}
|
||||
|
||||
for _, o := range DefaultOptions {
|
||||
@ -69,6 +70,7 @@ func ListenPacket(ctx context.Context, network, address string, options ...Optio
|
||||
func dialContext(ctx context.Context, network string, destination net.IP, port string, options []Option) (net.Conn, error) {
|
||||
opt := &option{
|
||||
interfaceName: DefaultInterface.Load(),
|
||||
routingMark: int(DefaultRoutingMark.Load()),
|
||||
}
|
||||
|
||||
for _, o := range DefaultOptions {
|
||||
|
@ -1,5 +1,4 @@
|
||||
//go:build linux
|
||||
// +build linux
|
||||
|
||||
package dialer
|
||||
|
||||
|
@ -1,5 +1,4 @@
|
||||
//go:build !linux
|
||||
// +build !linux
|
||||
|
||||
package dialer
|
||||
|
||||
|
@ -3,8 +3,9 @@ package dialer
|
||||
import "go.uber.org/atomic"
|
||||
|
||||
var (
|
||||
DefaultOptions []Option
|
||||
DefaultInterface = atomic.NewString("")
|
||||
DefaultOptions []Option
|
||||
DefaultInterface = atomic.NewString("")
|
||||
DefaultRoutingMark = atomic.NewInt32(0)
|
||||
)
|
||||
|
||||
type option struct {
|
||||
|
@ -1,5 +1,4 @@
|
||||
//go:build !darwin && !dragonfly && !freebsd && !linux && !netbsd && !openbsd && !solaris && !windows
|
||||
// +build !darwin,!dragonfly,!freebsd,!linux,!netbsd,!openbsd,!solaris,!windows
|
||||
|
||||
package dialer
|
||||
|
||||
|
@ -1,5 +1,4 @@
|
||||
//go:build darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
|
||||
// +build darwin dragonfly freebsd linux netbsd openbsd solaris
|
||||
|
||||
package dialer
|
||||
|
||||
|
@ -23,7 +23,7 @@ var (
|
||||
var interfaces = singledo.NewSingle(time.Second * 20)
|
||||
|
||||
func ResolveInterface(name string) (*Interface, error) {
|
||||
value, err, _ := interfaces.Do(func() (interface{}, error) {
|
||||
value, err, _ := interfaces.Do(func() (any, error) {
|
||||
ifaces, err := net.Interfaces()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -6,17 +6,17 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
type Factory = func(context.Context) (interface{}, error)
|
||||
type Factory = func(context.Context) (any, error)
|
||||
|
||||
type entry struct {
|
||||
elm interface{}
|
||||
elm any
|
||||
time time.Time
|
||||
}
|
||||
|
||||
type Option func(*pool)
|
||||
|
||||
// WithEvict set the evict callback
|
||||
func WithEvict(cb func(interface{})) Option {
|
||||
func WithEvict(cb func(any)) Option {
|
||||
return func(p *pool) {
|
||||
p.evict = cb
|
||||
}
|
||||
@ -32,7 +32,7 @@ func WithAge(maxAge int64) Option {
|
||||
// WithSize defined max size of Pool
|
||||
func WithSize(maxSize int) Option {
|
||||
return func(p *pool) {
|
||||
p.ch = make(chan interface{}, maxSize)
|
||||
p.ch = make(chan any, maxSize)
|
||||
}
|
||||
}
|
||||
|
||||
@ -42,13 +42,13 @@ type Pool struct {
|
||||
}
|
||||
|
||||
type pool struct {
|
||||
ch chan interface{}
|
||||
ch chan any
|
||||
factory Factory
|
||||
evict func(interface{})
|
||||
evict func(any)
|
||||
maxAge int64
|
||||
}
|
||||
|
||||
func (p *pool) GetContext(ctx context.Context) (interface{}, error) {
|
||||
func (p *pool) GetContext(ctx context.Context) (any, error) {
|
||||
now := time.Now()
|
||||
for {
|
||||
select {
|
||||
@ -68,11 +68,11 @@ func (p *pool) GetContext(ctx context.Context) (interface{}, error) {
|
||||
}
|
||||
}
|
||||
|
||||
func (p *pool) Get() (interface{}, error) {
|
||||
func (p *pool) Get() (any, error) {
|
||||
return p.GetContext(context.Background())
|
||||
}
|
||||
|
||||
func (p *pool) Put(item interface{}) {
|
||||
func (p *pool) Put(item any) {
|
||||
e := &entry{
|
||||
elm: item,
|
||||
time: time.Now(),
|
||||
@ -100,7 +100,7 @@ func recycle(p *Pool) {
|
||||
|
||||
func New(factory Factory, options ...Option) *Pool {
|
||||
p := &pool{
|
||||
ch: make(chan interface{}, 10),
|
||||
ch: make(chan any, 10),
|
||||
factory: factory,
|
||||
}
|
||||
|
||||
|
@ -10,7 +10,7 @@ import (
|
||||
|
||||
func lg() Factory {
|
||||
initial := -1
|
||||
return func(context.Context) (interface{}, error) {
|
||||
return func(context.Context) (any, error) {
|
||||
initial++
|
||||
return initial, nil
|
||||
}
|
||||
@ -34,7 +34,7 @@ func TestPool_MaxSize(t *testing.T) {
|
||||
size := 5
|
||||
pool := New(g, WithSize(size))
|
||||
|
||||
items := []interface{}{}
|
||||
items := []any{}
|
||||
|
||||
for i := 0; i < size; i++ {
|
||||
item, _ := pool.Get()
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
@ -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])
|
||||
inode, uid := unpackSocketDiagResponse(&messages[0])
|
||||
if inode < 0 || uid < 0 {
|
||||
return 0, 0, fmt.Errorf("invalid inode(%d) or uid(%d)", inode, uid)
|
||||
}
|
||||
|
||||
return int(uid), int(inode), nil
|
||||
return inode, uid, 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
|
||||
}
|
||||
|
@ -1,8 +1,4 @@
|
||||
//go:build !darwin && !linux && !windows && (!freebsd || !amd64)
|
||||
// +build !darwin
|
||||
// +build !linux
|
||||
// +build !windows
|
||||
// +build !freebsd !amd64
|
||||
|
||||
package process
|
||||
|
||||
|
@ -3,7 +3,6 @@ package process
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
@ -175,7 +174,7 @@ func newSearcher(isV4, isTCP bool) *searcher {
|
||||
func getTransportTable(fn uintptr, family int, class int) ([]byte, error) {
|
||||
for size, buf := uint32(8), make([]byte, 8); ; {
|
||||
ptr := unsafe.Pointer(&buf[0])
|
||||
err, _, _ := syscall.Syscall6(fn, 6, uintptr(ptr), uintptr(unsafe.Pointer(&size)), 0, uintptr(family), uintptr(class), 0)
|
||||
err, _, _ := syscall.SyscallN(fn, uintptr(ptr), uintptr(unsafe.Pointer(&size)), 0, uintptr(family), uintptr(class), 0)
|
||||
|
||||
switch err {
|
||||
case 0:
|
||||
@ -210,15 +209,15 @@ func getExecPathFromPID(pid uint32) (string, error) {
|
||||
|
||||
buf := make([]uint16, syscall.MAX_LONG_PATH)
|
||||
size := uint32(len(buf))
|
||||
r1, _, err := syscall.Syscall6(
|
||||
queryProcName, 4,
|
||||
r1, _, err := syscall.SyscallN(
|
||||
queryProcName,
|
||||
uintptr(h),
|
||||
uintptr(1),
|
||||
uintptr(unsafe.Pointer(&buf[0])),
|
||||
uintptr(unsafe.Pointer(&size)),
|
||||
0, 0)
|
||||
)
|
||||
if r1 == 0 {
|
||||
return "", err
|
||||
}
|
||||
return filepath.Base(syscall.UTF16ToString(buf[:size])), nil
|
||||
return syscall.UTF16ToString(buf[:size]), nil
|
||||
}
|
||||
|
12
component/resolver/defaults.go
Normal file
12
component/resolver/defaults.go
Normal file
@ -0,0 +1,12 @@
|
||||
//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
|
||||
|
||||
package resolver
|
||||
|
||||
import _ "unsafe"
|
||||
|
||||
//go:linkname defaultNS net.defaultNS
|
||||
var defaultNS []string
|
||||
|
||||
func init() {
|
||||
defaultNS = []string{"114.114.114.114:53", "8.8.8.8:53"}
|
||||
}
|
@ -51,7 +51,7 @@ func ValidAndSplitDomain(domain string) ([]string, bool) {
|
||||
// 3. subdomain.*.example.com
|
||||
// 4. .example.com
|
||||
// 5. +.example.com
|
||||
func (t *DomainTrie) Insert(domain string, data interface{}) error {
|
||||
func (t *DomainTrie) Insert(domain string, data any) error {
|
||||
parts, valid := ValidAndSplitDomain(domain)
|
||||
if !valid {
|
||||
return ErrInvalidDomain
|
||||
@ -68,7 +68,7 @@ func (t *DomainTrie) Insert(domain string, data interface{}) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *DomainTrie) insert(parts []string, data interface{}) {
|
||||
func (t *DomainTrie) insert(parts []string, data any) {
|
||||
node := t.root
|
||||
// reverse storage domain part to save space
|
||||
for i := len(parts) - 1; i >= 0; i-- {
|
||||
|
@ -3,7 +3,7 @@ package trie
|
||||
// Node is the trie's node
|
||||
type Node struct {
|
||||
children map[string]*Node
|
||||
Data interface{}
|
||||
Data any
|
||||
}
|
||||
|
||||
func (n *Node) getChild(s string) *Node {
|
||||
@ -18,7 +18,7 @@ func (n *Node) addChild(s string, child *Node) {
|
||||
n.children[s] = child
|
||||
}
|
||||
|
||||
func newNode(data interface{}) *Node {
|
||||
func newNode(data any) *Node {
|
||||
return &Node{
|
||||
Data: data,
|
||||
children: map[string]*Node{},
|
||||
|
@ -29,10 +29,11 @@ import (
|
||||
type General struct {
|
||||
Inbound
|
||||
Controller
|
||||
Mode T.TunnelMode `json:"mode"`
|
||||
LogLevel log.LogLevel `json:"log-level"`
|
||||
IPv6 bool `json:"ipv6"`
|
||||
Interface string `json:"-"`
|
||||
Mode T.TunnelMode `json:"mode"`
|
||||
LogLevel log.LogLevel `json:"log-level"`
|
||||
IPv6 bool `json:"ipv6"`
|
||||
Interface string `json:"-"`
|
||||
RoutingMark int `json:"-"`
|
||||
}
|
||||
|
||||
// Inbound
|
||||
@ -137,15 +138,16 @@ type RawConfig struct {
|
||||
ExternalUI string `yaml:"external-ui"`
|
||||
Secret string `yaml:"secret"`
|
||||
Interface string `yaml:"interface-name"`
|
||||
RoutingMark int `yaml:"routing-mark"`
|
||||
|
||||
ProxyProvider map[string]map[string]interface{} `yaml:"proxy-providers"`
|
||||
Hosts map[string]string `yaml:"hosts"`
|
||||
DNS RawDNS `yaml:"dns"`
|
||||
Experimental Experimental `yaml:"experimental"`
|
||||
Profile Profile `yaml:"profile"`
|
||||
Proxy []map[string]interface{} `yaml:"proxies"`
|
||||
ProxyGroup []map[string]interface{} `yaml:"proxy-groups"`
|
||||
Rule []string `yaml:"rules"`
|
||||
ProxyProvider map[string]map[string]any `yaml:"proxy-providers"`
|
||||
Hosts map[string]string `yaml:"hosts"`
|
||||
DNS RawDNS `yaml:"dns"`
|
||||
Experimental Experimental `yaml:"experimental"`
|
||||
Profile Profile `yaml:"profile"`
|
||||
Proxy []map[string]any `yaml:"proxies"`
|
||||
ProxyGroup []map[string]any `yaml:"proxy-groups"`
|
||||
Rule []string `yaml:"rules"`
|
||||
}
|
||||
|
||||
// Parse config
|
||||
@ -168,8 +170,8 @@ func UnmarshalRawConfig(buf []byte) (*RawConfig, error) {
|
||||
LogLevel: log.INFO,
|
||||
Hosts: map[string]string{},
|
||||
Rule: []string{},
|
||||
Proxy: []map[string]interface{}{},
|
||||
ProxyGroup: []map[string]interface{}{},
|
||||
Proxy: []map[string]any{},
|
||||
ProxyGroup: []map[string]any{},
|
||||
DNS: RawDNS{
|
||||
Enable: false,
|
||||
UseHosts: true,
|
||||
@ -265,10 +267,11 @@ func parseGeneral(cfg *RawConfig) (*General, error) {
|
||||
ExternalUI: cfg.ExternalUI,
|
||||
Secret: cfg.Secret,
|
||||
},
|
||||
Mode: cfg.Mode,
|
||||
LogLevel: cfg.LogLevel,
|
||||
IPv6: cfg.IPv6,
|
||||
Interface: cfg.Interface,
|
||||
Mode: cfg.Mode,
|
||||
LogLevel: cfg.LogLevel,
|
||||
IPv6: cfg.IPv6,
|
||||
Interface: cfg.Interface,
|
||||
RoutingMark: cfg.RoutingMark,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@ -627,11 +630,10 @@ func parseDNS(rawCfg *RawConfig, hosts *trie.DomainTrie) (*DNS, error) {
|
||||
}
|
||||
|
||||
func parseAuthentication(rawRecords []string) []auth.AuthUser {
|
||||
users := make([]auth.AuthUser, 0)
|
||||
users := []auth.AuthUser{}
|
||||
for _, line := range rawRecords {
|
||||
userData := strings.SplitN(line, ":", 2)
|
||||
if len(userData) == 2 {
|
||||
users = append(users, auth.AuthUser{User: userData[0], Pass: userData[1]})
|
||||
if user, pass, found := strings.Cut(line, ":"); found {
|
||||
users = append(users, auth.AuthUser{User: user, Pass: pass})
|
||||
}
|
||||
}
|
||||
return users
|
||||
|
@ -18,13 +18,13 @@ func trimArr(arr []string) (r []string) {
|
||||
// Check if ProxyGroups form DAG(Directed Acyclic Graph), and sort all ProxyGroups by dependency order.
|
||||
// Meanwhile, record the original index in the config file.
|
||||
// If loop is detected, return an error with location of loop.
|
||||
func proxyGroupsDagSort(groupsConfig []map[string]interface{}) error {
|
||||
func proxyGroupsDagSort(groupsConfig []map[string]any) error {
|
||||
type graphNode struct {
|
||||
indegree int
|
||||
// topological order
|
||||
topo int
|
||||
// the original data in `groupsConfig`
|
||||
data map[string]interface{}
|
||||
data map[string]any
|
||||
// `outdegree` and `from` are used in loop locating
|
||||
outdegree int
|
||||
option *outboundgroup.GroupCommonOption
|
||||
|
@ -21,7 +21,7 @@ const (
|
||||
type DNSMode int
|
||||
|
||||
// UnmarshalYAML unserialize EnhancedMode with yaml
|
||||
func (e *DNSMode) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||
func (e *DNSMode) UnmarshalYAML(unmarshal func(any) error) error {
|
||||
var tp string
|
||||
if err := unmarshal(&tp); err != nil {
|
||||
return err
|
||||
@ -35,7 +35,7 @@ func (e *DNSMode) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||
}
|
||||
|
||||
// MarshalYAML serialize EnhancedMode with yaml
|
||||
func (e DNSMode) MarshalYAML() (interface{}, error) {
|
||||
func (e DNSMode) MarshalYAML() (any, error) {
|
||||
return e.String(), nil
|
||||
}
|
||||
|
||||
|
@ -63,15 +63,16 @@ func (t Type) MarshalJSON() ([]byte, error) {
|
||||
|
||||
// Metadata is used to store connection address
|
||||
type Metadata struct {
|
||||
NetWork NetWork `json:"network"`
|
||||
Type Type `json:"type"`
|
||||
SrcIP net.IP `json:"sourceIP"`
|
||||
DstIP net.IP `json:"destinationIP"`
|
||||
SrcPort string `json:"sourcePort"`
|
||||
DstPort string `json:"destinationPort"`
|
||||
AddrType int `json:"-"`
|
||||
Host string `json:"host"`
|
||||
DNSMode DNSMode `json:"dnsMode"`
|
||||
NetWork NetWork `json:"network"`
|
||||
Type Type `json:"type"`
|
||||
SrcIP net.IP `json:"sourceIP"`
|
||||
DstIP net.IP `json:"destinationIP"`
|
||||
SrcPort string `json:"sourcePort"`
|
||||
DstPort string `json:"destinationPort"`
|
||||
AddrType int `json:"-"`
|
||||
Host string `json:"host"`
|
||||
DNSMode DNSMode `json:"dnsMode"`
|
||||
ProcessPath string `json:"processPath"`
|
||||
}
|
||||
|
||||
func (m *Metadata) RemoteAddress() string {
|
||||
|
@ -11,6 +11,7 @@ const (
|
||||
SrcPort
|
||||
DstPort
|
||||
Process
|
||||
ProcessPath
|
||||
MATCH
|
||||
)
|
||||
|
||||
@ -36,6 +37,8 @@ func (rt RuleType) String() string {
|
||||
return "DstPort"
|
||||
case Process:
|
||||
return "Process"
|
||||
case ProcessPath:
|
||||
return "ProcessPath"
|
||||
case MATCH:
|
||||
return "Match"
|
||||
default:
|
||||
@ -49,4 +52,5 @@ type Rule interface {
|
||||
Adapter() string
|
||||
Payload() string
|
||||
ShouldResolveIP() bool
|
||||
ShouldFindProcess() bool
|
||||
}
|
||||
|
@ -117,7 +117,7 @@ func (r *Resolver) ExchangeContext(ctx context.Context, m *D.Msg) (msg *D.Msg, e
|
||||
func (r *Resolver) exchangeWithoutCache(ctx context.Context, m *D.Msg) (msg *D.Msg, err error) {
|
||||
q := m.Question[0]
|
||||
|
||||
ret, err, shared := r.group.Do(q.String(), func() (result interface{}, err error) {
|
||||
ret, err, shared := r.group.Do(q.String(), func() (result any, err error) {
|
||||
defer func() {
|
||||
if err != nil {
|
||||
return
|
||||
@ -153,7 +153,7 @@ func (r *Resolver) batchExchange(ctx context.Context, clients []dnsClient, m *D.
|
||||
fast, ctx := picker.WithTimeout(ctx, resolver.DefaultDNSTimeout)
|
||||
for _, client := range clients {
|
||||
r := client
|
||||
fast.Go(func() (interface{}, error) {
|
||||
fast.Go(func() (any, error) {
|
||||
m, err := r.ExchangeContext(ctx, m)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
31
go.mod
31
go.mod
@ -1,37 +1,38 @@
|
||||
module github.com/Dreamacro/clash
|
||||
|
||||
go 1.17
|
||||
go 1.18
|
||||
|
||||
require (
|
||||
github.com/Dreamacro/go-shadowsocks2 v0.1.7
|
||||
github.com/Dreamacro/go-shadowsocks2 v0.1.8
|
||||
github.com/go-chi/chi/v5 v5.0.7
|
||||
github.com/go-chi/cors v1.2.0
|
||||
github.com/go-chi/cors v1.2.1
|
||||
github.com/go-chi/render v1.0.1
|
||||
github.com/gofrs/uuid v4.2.0+incompatible
|
||||
github.com/gorilla/websocket v1.4.2
|
||||
github.com/insomniacslk/dhcp v0.0.0-20211214070828-5297eed8f489
|
||||
github.com/miekg/dns v1.1.45
|
||||
github.com/oschwald/geoip2-golang v1.5.0
|
||||
github.com/gorilla/websocket v1.5.0
|
||||
github.com/insomniacslk/dhcp v0.0.0-20220504074936-1ca156eafb9f
|
||||
github.com/miekg/dns v1.1.48
|
||||
github.com/oschwald/geoip2-golang v1.7.0
|
||||
github.com/sirupsen/logrus v1.8.1
|
||||
github.com/stretchr/testify v1.7.0
|
||||
github.com/stretchr/testify v1.7.1
|
||||
go.etcd.io/bbolt v1.3.6
|
||||
go.uber.org/atomic v1.9.0
|
||||
go.uber.org/automaxprocs v1.4.0
|
||||
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3
|
||||
golang.org/x/net v0.0.0-20211216030914-fe4d6282115f
|
||||
go.uber.org/automaxprocs v1.5.1
|
||||
golang.org/x/crypto v0.0.0-20220507011949-2cf3adece122
|
||||
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
|
||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e
|
||||
golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6
|
||||
gopkg.in/yaml.v2 v2.4.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/oschwald/maxminddb-golang v1.8.0 // indirect
|
||||
github.com/kr/text v0.2.0 // indirect
|
||||
github.com/oschwald/maxminddb-golang v1.9.0 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/u-root/uio v0.0.0-20210528114334-82958018845c // indirect
|
||||
golang.org/x/mod v0.4.2 // indirect
|
||||
golang.org/x/text v0.3.6 // indirect
|
||||
golang.org/x/text v0.3.7 // indirect
|
||||
golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
|
||||
)
|
||||
|
70
go.sum
70
go.sum
@ -1,13 +1,14 @@
|
||||
github.com/Dreamacro/go-shadowsocks2 v0.1.7 h1:8CtbE1HoPPMfrQZGXmlluq6dO2lL31W6WRRE8fabc4Q=
|
||||
github.com/Dreamacro/go-shadowsocks2 v0.1.7/go.mod h1:8p5G4cAj5ZlXwUR+Ww63gfSikr8kvw8uw3TDwLAJpUc=
|
||||
github.com/Dreamacro/go-shadowsocks2 v0.1.8 h1:Ixejp5JscEc866gAvm/l6TFd7BOBvDviKgwb1quWw3g=
|
||||
github.com/Dreamacro/go-shadowsocks2 v0.1.8/go.mod h1:51y4Q6tJoCE7e8TmYXcQRqfoxPfE9Cvn79V6pB6Df7Y=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/fanliao/go-promise v0.0.0-20141029170127-1890db352a72/go.mod h1:PjfxuH4FZdUyfMdtBio2lsRr1AKEaVPwelzuHuh8Lqc=
|
||||
github.com/go-chi/chi/v5 v5.0.7 h1:rDTPXLDHGATaeHvVlLcR4Qe0zftYethFucbjVQ1PxU8=
|
||||
github.com/go-chi/chi/v5 v5.0.7/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
|
||||
github.com/go-chi/cors v1.2.0 h1:tV1g1XENQ8ku4Bq3K9ub2AtgG+p16SmzeMSGTwrOKdE=
|
||||
github.com/go-chi/cors v1.2.0/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vzc58=
|
||||
github.com/go-chi/cors v1.2.1 h1:xEC8UT3Rlp2QuWNEr4Fs/c2EAGVKBwy/1vHx3bppil4=
|
||||
github.com/go-chi/cors v1.2.1/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vzc58=
|
||||
github.com/go-chi/render v1.0.1 h1:4/5tis2cKaNdnv9zFLfXzcquC9HbeZgCnxGnKrltBS8=
|
||||
github.com/go-chi/render v1.0.1/go.mod h1:pq4Rr7HbnsdaeHagklXub+p6Wd16Af5l9koip1OvJns=
|
||||
github.com/gofrs/uuid v4.2.0+incompatible h1:yyYWMnhkhrKwwr8gAOcOCYxOOscHgDS9yZgBrnJfGa0=
|
||||
@ -18,21 +19,19 @@ github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw
|
||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
|
||||
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
|
||||
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/hugelgupf/socketpair v0.0.0-20190730060125-05d35a94e714/go.mod h1:2Goc3h8EklBH5mspfHFxBnEoURQCGzQQH1ga9Myjvis=
|
||||
github.com/insomniacslk/dhcp v0.0.0-20211214070828-5297eed8f489 h1:jhdHqd7DxBrzfuFSoPxjD6nUVaV/1RIn9aHA0WCf/as=
|
||||
github.com/insomniacslk/dhcp v0.0.0-20211214070828-5297eed8f489/go.mod h1:h+MxyHxRg9NH3terB1nfRIUaQEcI0XOVkdR9LNBlp8E=
|
||||
github.com/insomniacslk/dhcp v0.0.0-20220504074936-1ca156eafb9f h1:l1QCwn715k8nYkj4Ql50rzEog3WnMdrd4YYMMwemxEo=
|
||||
github.com/insomniacslk/dhcp v0.0.0-20220504074936-1ca156eafb9f/go.mod h1:h+MxyHxRg9NH3terB1nfRIUaQEcI0XOVkdR9LNBlp8E=
|
||||
github.com/jsimonetti/rtnetlink v0.0.0-20190606172950-9527aa82566a/go.mod h1:Oz+70psSo5OFh8DBl0Zv2ACw7Esh6pPUphlvZG9x7uw=
|
||||
github.com/jsimonetti/rtnetlink v0.0.0-20200117123717-f846d4f6c1f4/go.mod h1:WGuG/smIU4J/54PblvSbh+xvCZmpJnFgr3ds6Z55XMQ=
|
||||
github.com/jsimonetti/rtnetlink v0.0.0-20201009170750-9c6f07d100c1/go.mod h1:hqoO/u39cqLeBLebZ8fWdE96O7FxrAsRYhnVOdgHxok=
|
||||
github.com/jsimonetti/rtnetlink v0.0.0-20201110080708-d2c240429e6c/go.mod h1:huN4d1phzjhlOsNIjFsw2SVRbwIHj3fJDMEU2SDPTmg=
|
||||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/mdlayher/ethernet v0.0.0-20190606142754-0394541c37b7/go.mod h1:U6ZQobyTjI/tJyq2HG+i/dfSoFUt8/aZCM+GKtmFk/Y=
|
||||
github.com/mdlayher/netlink v0.0.0-20190409211403-11939a169225/go.mod h1:eQB3mZE4aiYnlUsyGGCOpPETfdQq4Jhsgf1fk3cwQaA=
|
||||
github.com/mdlayher/netlink v1.0.0/go.mod h1:KxeJAFOFLG6AjpyDkQ/iIhxygIUKD+vcwqcnu43w/+M=
|
||||
@ -40,14 +39,15 @@ github.com/mdlayher/netlink v1.1.0/go.mod h1:H4WCitaheIsdF9yOYu8CFmCgQthAPIWZmcK
|
||||
github.com/mdlayher/netlink v1.1.1/go.mod h1:WTYpFb/WTvlRJAyKhZL5/uy69TDDpHHu2VZmb2XgV7o=
|
||||
github.com/mdlayher/raw v0.0.0-20190606142536-fef19f00fc18/go.mod h1:7EpbotpCmVZcu+KCX4g9WaRNuu11uyhiW7+Le1dKawg=
|
||||
github.com/mdlayher/raw v0.0.0-20191009151244-50f2db8cc065/go.mod h1:7EpbotpCmVZcu+KCX4g9WaRNuu11uyhiW7+Le1dKawg=
|
||||
github.com/miekg/dns v1.1.45 h1:g5fRIhm9nx7g8osrAvgb16QJfmyMsyOCb+J7LSv+Qzk=
|
||||
github.com/miekg/dns v1.1.45/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME=
|
||||
github.com/oschwald/geoip2-golang v1.5.0 h1:igg2yQIrrcRccB1ytFXqBfOHCjXWIoMv85lVJ1ONZzw=
|
||||
github.com/oschwald/geoip2-golang v1.5.0/go.mod h1:xdvYt5xQzB8ORWFqPnqMwZpCpgNagttWdoZLlJQzg7s=
|
||||
github.com/oschwald/maxminddb-golang v1.8.0 h1:Uh/DSnGoxsyp/KYbY1AuP0tYEwfs0sCph9p/UMXK/Hk=
|
||||
github.com/oschwald/maxminddb-golang v1.8.0/go.mod h1:RXZtst0N6+FY/3qCNmZMBApR19cdQj43/NM9VkrNAis=
|
||||
github.com/miekg/dns v1.1.48 h1:Ucfr7IIVyMBz4lRE8qmGUuZ4Wt3/ZGu9hmcMT3Uu4tQ=
|
||||
github.com/miekg/dns v1.1.48/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME=
|
||||
github.com/oschwald/geoip2-golang v1.7.0 h1:JW1r5AKi+vv2ujSxjKthySK3jo8w8oKWPyXsw+Qs/S8=
|
||||
github.com/oschwald/geoip2-golang v1.7.0/go.mod h1:mdI/C7iK7NVMcIDDtf4bCKMJ7r0o7UwGeCo9eiitCMQ=
|
||||
github.com/oschwald/maxminddb-golang v1.9.0 h1:tIk4nv6VT9OiPyrnDAfJS1s1xKDQMZOsGojab6EjC1Y=
|
||||
github.com/oschwald/maxminddb-golang v1.9.0/go.mod h1:TK+s/Z2oZq0rSl4PSeAEoP0bgm82Cp5HyvYbt8K3zLY=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g=
|
||||
github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
|
||||
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||
@ -55,10 +55,9 @@ github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/u-root/uio v0.0.0-20210528114334-82958018845c h1:BFvcl34IGnw8yvJi8hlqLFo9EshRInwWBs2M5fGWzQA=
|
||||
github.com/u-root/uio v0.0.0-20210528114334-82958018845c/go.mod h1:LpEX5FO/cB+WF4TYGY1V5qktpaZLkKkSegbr0V4eYXA=
|
||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
@ -66,14 +65,13 @@ go.etcd.io/bbolt v1.3.6 h1:/ecaJf0sk1l4l6V4awd65v2C3ILy7MSj+s/x1ADCIMU=
|
||||
go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4=
|
||||
go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
|
||||
go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||
go.uber.org/automaxprocs v1.4.0 h1:CpDZl6aOlLhReez+8S3eEotD7Jx0Os++lemPlMULQP0=
|
||||
go.uber.org/automaxprocs v1.4.0/go.mod h1:/mTEdr7LvHhs0v7mjdxDreTz1OG5zdZGqgOnhWiR/+Q=
|
||||
go.uber.org/automaxprocs v1.5.1 h1:e1YG66Lrk73dn4qhg8WFSvhF0JuFQF0ERIp4rpuV8Qk=
|
||||
go.uber.org/automaxprocs v1.5.1/go.mod h1:BF4eumQw0P9GtnuxxovUd06vwm1o18oMzFtK66vU6XU=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20210317152858-513c2a44f670/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
||||
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3 h1:0es+/5331RGQPcXlMfP+WrnIIS6dNnNRe0WB02W0F4M=
|
||||
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.0.0-20220507011949-2cf3adece122 h1:NvGWuYG8dkDHFSKksI1P9faiVJ9rayE6l0+ouWVIDs8=
|
||||
golang.org/x/crypto v0.0.0-20220507011949-2cf3adece122/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
@ -86,12 +84,10 @@ golang.org/x/net v0.0.0-20191007182048-72f939374954/go.mod h1:z5CRVTTTmAJ677TzLL
|
||||
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||
golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211216030914-fe4d6282115f h1:hEYJvxw1lSnWIl8X9ofsYMklzaDs90JI2az5YMd4fPM=
|
||||
golang.org/x/net v0.0.0-20211216030914-fe4d6282115f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4 h1:HVyaeDAYux4pnY+D/SiwmLOR36ewZ4iGQIIrtnuCjFA=
|
||||
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
@ -104,7 +100,6 @@ golang.org/x/sys v0.0.0-20190606122018-79a91cf218c4/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191224085550-c709ea063b76/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
@ -115,15 +110,15 @@ golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210525143221-35b2ab0089ea/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e h1:fLOSk5Q00efkSvAm+4xcoXD+RRmLmmulPn5I3Y9F2EM=
|
||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6 h1:nonptSpoQ4vQjyraW20DXPAglgQfVnM9ZC6MmNLMR60=
|
||||
golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
@ -136,9 +131,8 @@ golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1N
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
|
@ -162,6 +162,7 @@ func updateGeneral(general *config.General, force bool) {
|
||||
resolver.DisableIPv6 = !general.IPv6
|
||||
|
||||
dialer.DefaultInterface.Store(general.Interface)
|
||||
dialer.DefaultRoutingMark.Store(int32(general.RoutingMark))
|
||||
|
||||
iface.FlushCache()
|
||||
|
||||
|
@ -115,10 +115,10 @@ func authentication(next http.Handler) http.Handler {
|
||||
}
|
||||
|
||||
header := r.Header.Get("Authorization")
|
||||
text := strings.SplitN(header, " ", 2)
|
||||
bearer, token, found := strings.Cut(header, " ")
|
||||
|
||||
hasInvalidHeader := text[0] != "Bearer"
|
||||
hasInvalidSecret := len(text) != 2 || text[1] != serverSecret
|
||||
hasInvalidHeader := bearer != "Bearer"
|
||||
hasInvalidSecret := !found || token != serverSecret
|
||||
if hasInvalidHeader || hasInvalidSecret {
|
||||
render.Status(r, http.StatusUnauthorized)
|
||||
render.JSON(w, r, ErrUnauthorized)
|
||||
@ -208,16 +208,27 @@ func getLogs(w http.ResponseWriter, r *http.Request) {
|
||||
render.Status(r, http.StatusOK)
|
||||
}
|
||||
|
||||
ch := make(chan log.Event, 1024)
|
||||
sub := log.Subscribe()
|
||||
defer log.UnSubscribe(sub)
|
||||
buf := &bytes.Buffer{}
|
||||
var err error
|
||||
for elm := range sub {
|
||||
buf.Reset()
|
||||
log := elm.(*log.Event)
|
||||
|
||||
go func() {
|
||||
for elm := range sub {
|
||||
log := elm.(log.Event)
|
||||
select {
|
||||
case ch <- log:
|
||||
default:
|
||||
}
|
||||
}
|
||||
close(ch)
|
||||
}()
|
||||
|
||||
for log := range ch {
|
||||
if log.LogLevel < level {
|
||||
continue
|
||||
}
|
||||
buf.Reset()
|
||||
|
||||
if err := json.NewEncoder(buf).Encode(Log{
|
||||
Type: log.Type(),
|
||||
@ -226,6 +237,7 @@ func getLogs(w http.ResponseWriter, r *http.Request) {
|
||||
break
|
||||
}
|
||||
|
||||
var err error
|
||||
if wsConn == nil {
|
||||
_, err = w.Write(buf.Bytes())
|
||||
w.(http.Flusher).Flush()
|
||||
|
@ -61,6 +61,12 @@ func HandleConn(c net.Conn, in chan<- C.ConnContext, cache *cache.Cache) {
|
||||
|
||||
request.RequestURI = ""
|
||||
|
||||
if isUpgradeRequest(request) {
|
||||
handleUpgrade(conn, request, in)
|
||||
|
||||
return // hijack connection
|
||||
}
|
||||
|
||||
removeHopByHopHeaders(request.Header)
|
||||
removeExtraHTTPHostPort(request)
|
||||
|
||||
@ -103,7 +109,7 @@ func authenticate(request *http.Request, cache *cache.Cache) *http.Response {
|
||||
return resp
|
||||
}
|
||||
|
||||
var authed interface{}
|
||||
var authed any
|
||||
if authed = cache.Get(credential); authed == nil {
|
||||
user, pass, err := decodeBasicProxyAuthorization(credential)
|
||||
authed = err == nil && authenticator.Verify(user, pass)
|
||||
|
61
listener/http/upgrade.go
Normal file
61
listener/http/upgrade.go
Normal file
@ -0,0 +1,61 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
"net"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/Dreamacro/clash/adapter/inbound"
|
||||
N "github.com/Dreamacro/clash/common/net"
|
||||
C "github.com/Dreamacro/clash/constant"
|
||||
"github.com/Dreamacro/clash/transport/socks5"
|
||||
)
|
||||
|
||||
func isUpgradeRequest(req *http.Request) bool {
|
||||
return strings.EqualFold(req.Header.Get("Connection"), "Upgrade")
|
||||
}
|
||||
|
||||
func handleUpgrade(conn net.Conn, request *http.Request, in chan<- C.ConnContext) {
|
||||
defer conn.Close()
|
||||
|
||||
removeProxyHeaders(request.Header)
|
||||
removeExtraHTTPHostPort(request)
|
||||
|
||||
address := request.Host
|
||||
if _, _, err := net.SplitHostPort(address); err != nil {
|
||||
address = net.JoinHostPort(address, "80")
|
||||
}
|
||||
|
||||
dstAddr := socks5.ParseAddr(address)
|
||||
if dstAddr == nil {
|
||||
return
|
||||
}
|
||||
|
||||
left, right := net.Pipe()
|
||||
|
||||
in <- inbound.NewHTTP(dstAddr, conn.RemoteAddr(), right)
|
||||
|
||||
bufferedLeft := N.NewBufferedConn(left)
|
||||
defer bufferedLeft.Close()
|
||||
|
||||
err := request.Write(bufferedLeft)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
resp, err := http.ReadResponse(bufferedLeft.Reader(), request)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
removeProxyHeaders(resp.Header)
|
||||
|
||||
err = resp.Write(conn)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if resp.StatusCode == http.StatusSwitchingProtocols {
|
||||
N.Relay(bufferedLeft, conn)
|
||||
}
|
||||
}
|
@ -8,15 +8,21 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
// removeHopByHopHeaders remove Proxy-* headers
|
||||
func removeProxyHeaders(header http.Header) {
|
||||
header.Del("Proxy-Connection")
|
||||
header.Del("Proxy-Authenticate")
|
||||
header.Del("Proxy-Authorization")
|
||||
}
|
||||
|
||||
// removeHopByHopHeaders remove hop-by-hop header
|
||||
func removeHopByHopHeaders(header http.Header) {
|
||||
// Strip hop-by-hop header based on RFC:
|
||||
// http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html#sec13.5.1
|
||||
// https://www.mnot.net/blog/2011/07/11/what_proxies_must_do
|
||||
|
||||
header.Del("Proxy-Connection")
|
||||
header.Del("Proxy-Authenticate")
|
||||
header.Del("Proxy-Authorization")
|
||||
removeProxyHeaders(header)
|
||||
|
||||
header.Del("TE")
|
||||
header.Del("Trailers")
|
||||
header.Del("Transfer-Encoding")
|
||||
@ -65,10 +71,10 @@ func decodeBasicProxyAuthorization(credential string) (string, string, error) {
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
login := strings.Split(string(plain), ":")
|
||||
if len(login) != 2 {
|
||||
user, pass, found := strings.Cut(string(plain), ":")
|
||||
if !found {
|
||||
return "", "", errors.New("invalid login")
|
||||
}
|
||||
|
||||
return login[0], login[1], nil
|
||||
return user, pass, nil
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -37,7 +37,7 @@ func parserPacket(conn net.Conn) (socks5.Addr, error) {
|
||||
// Call getorigdst() from linux/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
|
||||
func getorigdst(fd uintptr) (socks5.Addr, error) {
|
||||
raw := syscall.RawSockaddrInet4{}
|
||||
siz := unsafe.Sizeof(raw)
|
||||
siz := uint32(unsafe.Sizeof(raw))
|
||||
if err := socketcall(GETSOCKOPT, fd, syscall.IPPROTO_IP, SO_ORIGINAL_DST, uintptr(unsafe.Pointer(&raw)), uintptr(unsafe.Pointer(&siz)), 0); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -1,5 +1,4 @@
|
||||
//go:build linux && !386
|
||||
// +build linux,!386
|
||||
|
||||
package redir
|
||||
|
||||
|
@ -1,5 +1,4 @@
|
||||
//go:build !darwin && !linux && !freebsd
|
||||
// +build !darwin,!linux,!freebsd
|
||||
|
||||
package redir
|
||||
|
||||
|
@ -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)
|
||||
|
@ -1,5 +1,4 @@
|
||||
//go:build linux
|
||||
// +build linux
|
||||
|
||||
package tproxy
|
||||
|
||||
|
@ -1,5 +1,4 @@
|
||||
//go:build !linux
|
||||
// +build !linux
|
||||
|
||||
package tproxy
|
||||
|
||||
|
@ -1,5 +1,4 @@
|
||||
//go:build linux
|
||||
// +build linux
|
||||
|
||||
package tproxy
|
||||
|
||||
|
@ -1,5 +1,4 @@
|
||||
//go:build !linux
|
||||
// +build !linux
|
||||
|
||||
package tproxy
|
||||
|
||||
|
@ -25,7 +25,7 @@ const (
|
||||
type LogLevel int
|
||||
|
||||
// UnmarshalYAML unserialize LogLevel with yaml
|
||||
func (l *LogLevel) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||
func (l *LogLevel) UnmarshalYAML(unmarshal func(any) error) error {
|
||||
var tp string
|
||||
unmarshal(&tp)
|
||||
level, exist := LogLevelMapping[tp]
|
||||
@ -54,7 +54,7 @@ func (l LogLevel) MarshalJSON() ([]byte, error) {
|
||||
}
|
||||
|
||||
// MarshalYAML serialize LogLevel with yaml
|
||||
func (l LogLevel) MarshalYAML() (interface{}, error) {
|
||||
func (l LogLevel) MarshalYAML() (any, error) {
|
||||
return l.String(), nil
|
||||
}
|
||||
|
||||
|
18
log/log.go
18
log/log.go
@ -10,7 +10,7 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
logCh = make(chan interface{})
|
||||
logCh = make(chan any)
|
||||
source = observable.NewObservable(logCh)
|
||||
level = INFO
|
||||
)
|
||||
@ -29,31 +29,31 @@ func (e *Event) Type() string {
|
||||
return e.LogLevel.String()
|
||||
}
|
||||
|
||||
func Infoln(format string, v ...interface{}) {
|
||||
func Infoln(format string, v ...any) {
|
||||
event := newLog(INFO, format, v...)
|
||||
logCh <- event
|
||||
print(event)
|
||||
}
|
||||
|
||||
func Warnln(format string, v ...interface{}) {
|
||||
func Warnln(format string, v ...any) {
|
||||
event := newLog(WARNING, format, v...)
|
||||
logCh <- event
|
||||
print(event)
|
||||
}
|
||||
|
||||
func Errorln(format string, v ...interface{}) {
|
||||
func Errorln(format string, v ...any) {
|
||||
event := newLog(ERROR, format, v...)
|
||||
logCh <- event
|
||||
print(event)
|
||||
}
|
||||
|
||||
func Debugln(format string, v ...interface{}) {
|
||||
func Debugln(format string, v ...any) {
|
||||
event := newLog(DEBUG, format, v...)
|
||||
logCh <- event
|
||||
print(event)
|
||||
}
|
||||
|
||||
func Fatalln(format string, v ...interface{}) {
|
||||
func Fatalln(format string, v ...any) {
|
||||
log.Fatalf(format, v...)
|
||||
}
|
||||
|
||||
@ -74,7 +74,7 @@ func SetLevel(newLevel LogLevel) {
|
||||
level = newLevel
|
||||
}
|
||||
|
||||
func print(data *Event) {
|
||||
func print(data Event) {
|
||||
if data.LogLevel < level {
|
||||
return
|
||||
}
|
||||
@ -91,8 +91,8 @@ func print(data *Event) {
|
||||
}
|
||||
}
|
||||
|
||||
func newLog(logLevel LogLevel, format string, v ...interface{}) *Event {
|
||||
return &Event{
|
||||
func newLog(logLevel LogLevel, format string, v ...any) Event {
|
||||
return Event{
|
||||
LogLevel: logLevel,
|
||||
Payload: fmt.Sprintf(format, v...),
|
||||
}
|
||||
|
2
main.go
2
main.go
@ -46,7 +46,7 @@ func init() {
|
||||
}
|
||||
|
||||
func main() {
|
||||
maxprocs.Set(maxprocs.Logger(func(string, ...interface{}) {}))
|
||||
maxprocs.Set(maxprocs.Logger(func(string, ...any) {}))
|
||||
if version {
|
||||
fmt.Printf("Clash %s %s %s with %s %s\n", C.Version, runtime.GOOS, runtime.GOARCH, runtime.Version(), C.BuildTime)
|
||||
return
|
||||
|
@ -34,6 +34,10 @@ func (d *Domain) ShouldResolveIP() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (d *Domain) ShouldFindProcess() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func NewDomain(domain string, adapter string) *Domain {
|
||||
return &Domain{
|
||||
domain: strings.ToLower(domain),
|
||||
|
@ -35,6 +35,10 @@ func (dk *DomainKeyword) ShouldResolveIP() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (dk *DomainKeyword) ShouldFindProcess() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func NewDomainKeyword(keyword string, adapter string) *DomainKeyword {
|
||||
return &DomainKeyword{
|
||||
keyword: strings.ToLower(keyword),
|
||||
|
@ -35,6 +35,10 @@ func (ds *DomainSuffix) ShouldResolveIP() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (ds *DomainSuffix) ShouldFindProcess() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func NewDomainSuffix(suffix string, adapter string) *DomainSuffix {
|
||||
return &DomainSuffix{
|
||||
suffix: strings.ToLower(suffix),
|
||||
|
@ -28,6 +28,10 @@ func (f *Match) ShouldResolveIP() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (f *Match) ShouldFindProcess() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func NewMatch(adapter string) *Match {
|
||||
return &Match{
|
||||
adapter: adapter,
|
||||
|
@ -42,6 +42,10 @@ func (g *GEOIP) ShouldResolveIP() bool {
|
||||
return !g.noResolveIP
|
||||
}
|
||||
|
||||
func (g *GEOIP) ShouldFindProcess() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func NewGEOIP(country string, adapter string, noResolveIP bool) *GEOIP {
|
||||
geoip := &GEOIP{
|
||||
country: country,
|
||||
|
@ -54,6 +54,10 @@ func (i *IPCIDR) ShouldResolveIP() bool {
|
||||
return !i.noResolveIP
|
||||
}
|
||||
|
||||
func (i *IPCIDR) ShouldFindProcess() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func NewIPCIDR(s string, adapter string, opts ...IPCIDROption) (*IPCIDR, error) {
|
||||
_, ipnet, err := net.ParseCIDR(s)
|
||||
if err != nil {
|
||||
|
@ -32,7 +32,9 @@ func ParseRule(tp, payload, target string, params []string) (C.Rule, error) {
|
||||
case "DST-PORT":
|
||||
parsed, parseErr = NewPort(payload, target, false)
|
||||
case "PROCESS-NAME":
|
||||
parsed, parseErr = NewProcess(payload, target)
|
||||
parsed, parseErr = NewProcess(payload, target, true)
|
||||
case "PROCESS-PATH":
|
||||
parsed, parseErr = NewProcess(payload, target, false)
|
||||
case "MATCH":
|
||||
parsed = NewMatch(target)
|
||||
default:
|
||||
|
@ -38,6 +38,10 @@ func (p *Port) ShouldResolveIP() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (p *Port) ShouldFindProcess() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func NewPort(port string, adapter string, isSource bool) (*Port, error) {
|
||||
_, err := strconv.ParseUint(port, 10, 16)
|
||||
if err != nil {
|
||||
|
@ -1,21 +1,16 @@
|
||||
package rules
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/Dreamacro/clash/common/cache"
|
||||
"github.com/Dreamacro/clash/component/process"
|
||||
C "github.com/Dreamacro/clash/constant"
|
||||
"github.com/Dreamacro/clash/log"
|
||||
)
|
||||
|
||||
var processCache = cache.NewLRUCache(cache.WithAge(2), cache.WithSize(64))
|
||||
|
||||
type Process struct {
|
||||
adapter string
|
||||
process string
|
||||
adapter string
|
||||
process string
|
||||
nameOnly bool
|
||||
}
|
||||
|
||||
func (ps *Process) RuleType() C.RuleType {
|
||||
@ -23,26 +18,11 @@ func (ps *Process) RuleType() C.RuleType {
|
||||
}
|
||||
|
||||
func (ps *Process) Match(metadata *C.Metadata) bool {
|
||||
key := fmt.Sprintf("%s:%s:%s", metadata.NetWork.String(), metadata.SrcIP.String(), metadata.SrcPort)
|
||||
cached, hit := processCache.Get(key)
|
||||
if !hit {
|
||||
srcPort, err := strconv.Atoi(metadata.SrcPort)
|
||||
if err != nil {
|
||||
processCache.Set(key, "")
|
||||
return false
|
||||
}
|
||||
|
||||
name, err := process.FindProcessName(metadata.NetWork.String(), metadata.SrcIP, srcPort)
|
||||
if err != nil {
|
||||
log.Debugln("[Rule] find process name %s error: %s", C.Process.String(), err.Error())
|
||||
}
|
||||
|
||||
processCache.Set(key, name)
|
||||
|
||||
cached = name
|
||||
if ps.nameOnly {
|
||||
return strings.EqualFold(filepath.Base(metadata.ProcessPath), ps.process)
|
||||
}
|
||||
|
||||
return strings.EqualFold(cached.(string), ps.process)
|
||||
return strings.EqualFold(metadata.ProcessPath, ps.process)
|
||||
}
|
||||
|
||||
func (ps *Process) Adapter() string {
|
||||
@ -57,9 +37,14 @@ func (ps *Process) ShouldResolveIP() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func NewProcess(process string, adapter string) (*Process, error) {
|
||||
func (ps *Process) ShouldFindProcess() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func NewProcess(process string, adapter string, nameOnly bool) (*Process, error) {
|
||||
return &Process{
|
||||
adapter: adapter,
|
||||
process: process,
|
||||
adapter: adapter,
|
||||
process: process,
|
||||
nameOnly: nameOnly,
|
||||
}, nil
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user