Compare commits

...

174 Commits

Author SHA1 Message Date
637a8b6ed5 refactor: udp 2022-06-09 21:16:42 +08:00
cd466f05d3 chore: reformat code 2022-06-09 21:08:46 +08:00
9a55213ddc chore: add more shadowsocks tests 2022-06-09 18:10:31 +08:00
5055542d61 chore: update dependencies 2022-06-09 18:05:45 +08:00
23063ae0b9 fix: make CodeQL happy Dreamacro 2022-06-09 17:59:17 +08:00
a7f9aa909a fix: upgrade to yaml v3 2022-06-09 17:59:17 +08:00
15ecc451f3 fix: benchmark read bytes 2022-06-09 17:58:15 +08:00
186a4cfdf3 fix: test broken on opensource repo 2022-06-09 17:58:10 +08:00
220ef9e2e2 chore: add benchmark r/w 2022-06-09 17:58:05 +08:00
7079116aa8 chore: cleanup test code 2022-06-09 17:57:59 +08:00
b9e6de45e6 chore: make linter happy 2022-06-09 17:57:53 +08:00
d3503ff940 fix: fix upgrade header detect (#2134) 2022-06-09 17:57:48 +08:00
c3f4e1ba2e fix: add length check for ssr auth_aes128_sha1 (#2129) 2022-06-09 17:57:41 +08:00
695fb64fa8 fix: vmess ws 2022-06-09 16:23:15 +08:00
d32ab9ce74 fix: 规则匹配默认策略组返回错误 2022-06-09 13:52:02 +08:00
94648989b8 fix: hysteria URI Scheme 解析问题 2022-06-09 00:22:47 +08:00
07522d3c2e chore: 修改test文件 2022-06-08 02:03:34 +08:00
c14c07d2e3 feat: 代理集支持 Hysteria 分享格式订阅解析 2022-06-08 01:50:14 +08:00
9511ccfe47 chore: refine code 2022-06-08 01:47:50 +08:00
ed17a1bf23 fix: group filter touch provider 2022-06-07 17:19:25 +08:00
2a4f2f3942 fix: hysteria dialer 2022-06-07 15:49:10 +08:00
3254eaf51c fix: hysteria parse auth 2022-06-07 15:24:46 +08:00
7941bae141 fix: hysteria parse 2022-06-07 14:53:00 +08:00
35a6666a84 feat: add hysteria 2022-06-07 13:46:54 +08:00
73d5042774 fix: some test 2022-06-07 10:45:32 +08:00
9126cbab91 fix: shadowsocks-2022 on 32-bit systems 2022-06-07 10:44:22 +08:00
f8366f6e42 fix: 代理集转换ws类型
feat: 新增grpc h2 http 等支持
2022-06-07 03:17:33 +08:00
100c9b94ba Merge branch 'dev' into Alpha 2022-06-06 23:15:33 +08:00
8343c3597e fix: doq maybe crash when use adapter 2022-06-06 21:45:08 +08:00
d31adafa11 Merge pull request #76 from nekohasekai/Alpha
feat: add support for shadowsocks 2022 ciphers
2022-06-06 20:21:01 +08:00
1acc6759e9 feat: add support for shadowsocks 2022 ciphers 2022-06-06 19:56:36 +08:00
e995003c27 Merge branch 'dev' into Alpha 2022-06-05 21:23:14 +08:00
9edee2435c chore: amd64v3 改名为amd64,amd64v2改为amd64-compatible, darwin删除v2 2022-06-05 21:23:06 +08:00
5d337b75f9 feat: proxy provider 支持V2ray格式订阅链接 2022-06-05 17:14:24 +08:00
2188fad9c1 Feature: add V2Ray subscription support to proxy provider 2022-06-05 15:59:47 +08:00
edc73f3f33 Merge remote-tracking branch 'Meta/Alpha' into Alpha
# Conflicts:
#	dns/client.go
#	dns/doh.go
#	dns/doq.go
2022-06-05 14:10:18 +08:00
ade424cbb4 chore: 调整dns interface与adapter部分 2022-06-05 13:37:00 +08:00
6e03773134 chore: 调整dns interface与adapter部分 2022-06-05 12:52:29 +08:00
4ad0294655 chore: adjust makefile 2022-06-04 21:21:42 +08:00
43d3a0c8ea chore: mix the proxy adapter and interface to dns client 2022-06-04 21:18:49 +08:00
c045a4f2a7 Chore: make hadowsocks2 lib embed 2022-06-04 20:29:33 +08:00
20611eb8dc Merge branch 'dev' into Alpha 2022-06-04 19:16:56 +08:00
8ff7e180a4 fix: 当初始化失败时,定时更新失效 2022-06-04 19:15:30 +08:00
3827e00b54 refactor: 抽离http请求方法 2022-06-04 19:14:39 +08:00
c52e689d0d fix: classical rule-set 更新未清理 2022-06-04 19:12:50 +08:00
cb517cb529 chore: 调整目录与包名一致 2022-06-04 03:25:33 +08:00
50bb620aa1 chore: 调整parseRule代码 2022-06-04 03:22:41 +08:00
c745ea63b2 chore: 优化GeoSite初始化代码 2022-06-04 02:58:14 +08:00
8e959bd245 chore: 当无tag时不输出无效日志 2022-06-03 21:00:45 +08:00
298ca42369 chore: 启动参数v,查看版本同时打印使用的tags 2022-06-03 20:23:53 +08:00
ed9b9ce3c5 refactor: 添加no_gvisor 编译tag, 剔除gvisor stack支持, 方便在arm设备上debug 2022-06-03 20:07:30 +08:00
1298d2f8b6 chore: 添加tag no_doq 编译不含doq版本, 仅减少1.5MB(macOS-arm64) 2022-06-03 18:12:06 +08:00
6e84f685ce chore: 更新geox时通过内存存储 2022-06-03 16:50:49 +08:00
1ad87cfec9 chore: 选择fallback时,当节点不可用时触发urltest 2022-06-03 13:32:11 +08:00
9e9f459c0e refactor: 优化proxy server nameserver, 当节点专用dns全部查询失败会回落到正常逻辑 2022-06-02 20:58:25 +08:00
fa3e0c726e chore: 调整解析逻辑 2022-06-02 17:03:08 +08:00
3b038310ab fix: 类型转换错误导致规则解析错误 2022-06-02 15:43:27 +08:00
6709936a8f refactor: 归类规则解析代码 2022-06-02 13:42:18 +08:00
04e5d02ab9 feat: IP-SUFFIX
eg. IP-SUFFIX,0.0.0.124/6,匹配ip二进制后四位(IP-CIDR的倒序),支持ipv6
2022-06-02 12:53:19 +08:00
1af39cb228 fix: OpenClash 回环 2022-06-01 12:32:45 +08:00
c95735f083 chore: 调整内置winTun.dll部分 2022-06-01 12:01:08 +08:00
fa2e6be05d fix: TUN file exists 2022-05-31 10:34:13 +08:00
4092a7c84b feat: proxies group URLTest api 2022-05-30 22:07:09 +08:00
58d299c737 chore: 调整geosite初始化位置 2022-05-30 21:26:41 +08:00
11ddac2b5f refactor: 逻辑规则显示效果 2022-05-30 13:58:37 +08:00
1f95c74f1e chore: 识别线程数 2022-05-29 21:04:47 +08:00
a197fbd4b5 Merge branch 'Alpha' into dev 2022-05-29 20:43:39 +08:00
708b8beadf fix: compile 2022-05-29 20:02:30 +08:00
0e1601e5b6 fix: 调整not规则判断子规则数量,逻辑规则返回payload采用解析后结果 2022-05-29 19:54:11 +08:00
c7355510a2 chore: 调整uid系统判断位置 2022-05-29 18:55:08 +08:00
1faa172944 chore: 调整uid系统判断位置 2022-05-29 18:12:43 +08:00
7a8c98cd90 refactor: 使用 netlink 获取默认网卡 2022-05-29 15:35:08 +08:00
13e907bbd0 refactor: 使用 netlink 配置 ip rule 2022-05-29 15:03:27 +08:00
39e7832676 fix: route on android 2022-05-28 23:29:22 +08:00
9b999e72ce fix: npe 2022-05-28 23:29:03 +08:00
e1a61503e4 Merge branch 'netlink' into Alpha 2022-05-28 21:59:04 +08:00
9272d02149 refactor: 合并部分android代码入linux && ip 使用netlink配置路由 2022-05-28 21:58:29 +08:00
067c02aba1 fix: 调整获取远程目的的位置 2022-05-28 20:01:27 +08:00
d0268bb9a2 chore: 降低并发查询时IPv6等待 2022-05-28 09:58:45 +08:00
fb4872ff7f fix: 关闭并发时双栈使用错误 2022-05-27 20:43:39 +08:00
2044458df9 fix: npe 2022-05-27 20:33:27 +08:00
d6df026550 chore: 更换GeoData下载地址
Signed-off-by: Meta <maze.y2b@gmail.com>
2022-05-27 18:32:23 +08:00
7858ca6cc5 fix: geox url setting 2022-05-27 12:32:59 +08:00
ac36473d13 refactor: 获取远程目的从tunnel中剔除,移至tracker 2022-05-27 09:00:48 +08:00
72fb153fe0 refactor: 优化UDP远程目标获取 2022-05-26 23:41:09 +08:00
527a602eba fix: 更新错误时未停止后续流程,日志修改 2022-05-26 23:13:36 +08:00
a71fd3b4df fix: 启动时检测provider文件是否过期,强制更新 2022-05-26 21:05:00 +08:00
2ebc0383b5 feat: RESTful API support set tcp-concurrent 2022-05-26 19:49:12 +08:00
7431001ed6 feat: RESTful API support update Geo file
and can set update url by user, eg.
geox-url:
  geoip: "http://xxxx/gepip.dat"
  mmdb: "http://xxxx/country.mmdb"
  geosite: "http://xxxx/geosite.dat"
2022-05-24 15:04:13 +08:00
149b4b5b43 feat: RESTful API support disable sniffer 2022-05-24 13:44:52 +08:00
c0eb9aac1c feat: fallback can be select by user 2022-05-24 10:17:44 +08:00
79469fc8d6 feat: uid rule support for logic and rule-set 2022-05-22 13:07:20 +08:00
948700eed6 fix: 并发dns查询,由于ipv6阻塞导致某些情况下的网络不通 2022-05-21 00:34:15 +08:00
3ab82849d4 feat: IN-TYPE rule support
eg. IN-TYPE,SOCKS/REDIR/INNER,Proxy
support list: HTTP HTTPS SOCKS SOCKS4 SOCKS5 REDIR TPROXY TUN INNER
2022-05-20 23:17:16 +08:00
0f43a19fdb refactor: new way to get interface change even for linux 2022-05-20 21:44:19 +08:00
cc1c1340a3 feat: 安卓恢复进程规则,可通过enable-process开关,默认true 2022-05-19 20:44:09 +08:00
fe25ae83df refactor: 修改sticky-session尝试逻辑 2022-05-19 20:27:26 +08:00
c787bbe0e5 fix: 热重载Tun配置 2022-05-19 19:19:19 +08:00
7aff9aac82 fix: sticky-sessions异常 2022-05-18 22:29:27 +08:00
8b09db5f7f fix: Rule-Set中不解析DNS
feat: RULE-SET支持no-resolve
2022-05-18 18:43:44 +08:00
b5623602f5 chore: Android auto-detect-interface plus 2022-05-18 12:00:57 +08:00
16b27b3a1f fix: doq过代理错误 2022-05-17 21:30:54 +08:00
8b00be9039 fix: 删除udp触发的错误逻辑 2022-05-17 21:23:28 +08:00
fa9e27c5e4 refactor: 重构失败主动健康检测 2022-05-17 21:15:14 +08:00
f4d9384603 chore: debug log print dns result 2022-05-17 18:21:18 +08:00
c4408612b3 chore: 暴露数据给前端 2022-05-17 16:47:21 +08:00
0742f7db26 refactor: 重构StickySessions 2022-05-17 13:28:54 +08:00
891c2fe899 fix: 当dns被禁用时,dns将根据general ipv6设置解析dns 2022-05-17 09:01:41 +08:00
b831eb178b chore: remove noisy log 2022-05-16 18:20:13 +08:00
962ceaa89e refactor: strategyStickySessions 2022-05-16 17:46:28 +08:00
d52b00bd34 refactor: remove useless code 2022-05-16 17:29:08 +08:00
aa0d174ccb fix: strategyStickySessions nil pointer 2022-05-16 17:06:44 +08:00
b8e9c3d55a fix: geoip ReverseMatch 2022-05-16 17:06:44 +08:00
0b4c498c93 refactor: new way to get interface for android 2022-05-16 17:06:44 +08:00
efc7c82cac feat: "!"(not) support for geosite
eg. GEOSITE,!CN,Proxy & dns.fallback-filter.geosite: ['!CN']
2022-05-15 13:16:45 +08:00
63917aa020 fix: uuid-map return failed error 2022-05-14 23:45:10 +08:00
5016f529af revert: yaml v2 2022-05-14 23:36:19 +08:00
5bd5f1bfda chore: remove Script mode residual code. 2022-05-14 13:00:33 +08:00
d4dcbce9cb chore: log show all ips when all ips shake hands failed 2022-05-13 21:43:42 +08:00
df8196a68c fix: print process path logic 2022-05-12 18:57:30 +08:00
c1631759fc feat: add strategy:sticky-sessions for LoadBalance
Signed-off-by: Meta <maze.y2b@gmail.com>
2022-05-09 18:56:36 +08:00
9e9c3c810f fixed: make log api unblocked 2022-05-09 18:54:00 +08:00
463101aec1 fix: limit load provider concurrent size 2022-05-08 22:52:46 +08:00
2072964701 revert: tls handshake timeout recovery 10s 2022-05-08 21:56:59 +08:00
aded1b78b5 chore: sniffer give the err to the caller 2022-05-08 09:09:39 +08:00
ca9c859059 Merge remote-tracking branch 'meta/Alpha' into Alpha 2022-05-08 07:59:17 +08:00
55811dae32 fix: Adjust the timing of loading proxy selection 2022-05-08 07:58:26 +08:00
7136d145f8 chore: update dependencies 2022-05-08 00:47:01 +08:00
2fbbf7519f fix: provider auto update 2022-05-08 00:04:16 +08:00
663bf4fbb0 fix: remove misjudgment 2022-05-07 12:53:13 +08:00
f0a22a4a4c chore: modify sniff error log 2022-05-07 12:44:28 +08:00
4ab91520bd refactor: reuse uuid namespace 2022-05-07 12:35:14 +08:00
980d8a2641 refactor: string map to uuidv5 2022-05-06 14:02:34 +08:00
a95d439852 chore: the uuid-map is transferred to the protocol 2022-05-06 13:28:09 +08:00
a08e39faec fix uuid match 2022-05-06 13:08:27 +08:00
b3295262c1 chore: Initialize provider ahead of time 2022-05-05 21:14:46 +08:00
27aa026568 fix: use actual metadata 2022-05-04 20:13:12 +08:00
9969e1706e fix: loadbalance group npe 2022-05-04 19:52:48 +08:00
fb58595d44 feat: Expose remote destination (udp proxy maybe domain of node) 2022-05-04 16:57:08 +08:00
bdfa16ca6f fix: wrong parameters 2022-05-04 01:04:43 +08:00
b307bcb4a9 Merge remote-tracking branch 'Meta/Alpha' into Alpha
# Conflicts:
#	listener/tun/ipstack/commons/router_linux.go
2022-05-04 01:04:11 +08:00
f26941091b fix: default router with fakeIP when tun enable 2022-05-04 00:59:04 +08:00
6cd5769ed7 fix: default router with fakeIP when tun enable 2022-05-04 00:36:44 +08:00
41adfa65b3 Merge remote-tracking branch 'Meta/Alpha' into Alpha
# Conflicts:
#	listener/tun/ipstack/commons/router_linux.go
2022-05-03 23:59:41 +08:00
3fbb7c7a2d chore: add default router when tun enable 2022-05-03 23:58:11 +08:00
0aa82c04ea chore: add default router 198.18.0.0/16 when tun enable 2022-05-03 23:28:02 +08:00
5c6f2694c7 chore: sniffer param skip-sni renamed to ship-domain, old param will be removed in the release version 2022-05-03 23:10:59 +08:00
eca7615f08 fix: patch update support tun 2022-05-03 19:31:00 +08:00
52d559bb38 feat: rule-provider support NetWork rule 2022-05-03 01:36:03 +08:00
259736390a feat: rule-provider support rules field 2022-05-03 00:53:22 +08:00
7db07630a7 fix: DNS mapping error when sniffing result is ip, Discard sniffs that result in ip 2022-05-02 22:24:14 +08:00
d617b0f447 style: uid log tidy 2022-05-02 19:52:34 +08:00
80ff5917f7 fix: The sniffer does not clean up the original address 2022-05-02 17:09:24 +08:00
b401da5eba refactor: provider init order 2022-05-02 16:47:48 +08:00
05b25c334f Merge branch 'makefile' into Alpha 2022-05-02 14:43:51 +08:00
2c5a47a275 fix: Failed to get version tag 2022-05-02 14:43:01 +08:00
b2605a9012 fix: tun dns 2022-05-02 14:21:37 +08:00
b929a19f48 refactor: Unified active health detection, supported by load balancing policy group 2022-05-02 13:50:10 +08:00
4b04faa88b fix: http sniffer return host that was handled correctly 2022-05-02 09:51:26 +08:00
5fee0b5bf1 chore: adjust pass to reject.go 2022-05-02 09:16:47 +08:00
27120fb0f5 Merge remote-tracking branch 'Meta/Alpha' into Alpha 2022-05-02 08:49:23 +08:00
0cf539fb82 chore: adjust sniffer constant 2022-05-02 08:49:18 +08:00
26a38bd8de chore: adjust sniffer constant 2022-05-02 08:46:24 +08:00
ebbce4d061 Merge remote-tracking branch 'meta/Alpha' into Alpha 2022-05-02 08:28:00 +08:00
5acd2f6c3a chore: workflow 2022-05-02 08:27:17 +08:00
fe2bc903b8 fix trojan and snell's normal udp 2022-05-02 06:28:27 +08:00
658f1f5cda fix code mistake 2022-05-02 05:34:20 +08:00
5ccc047fe4 chore: adjust sniffer err info 2022-05-02 05:17:13 +08:00
6d704b9cd1 feat: sniffer support http 2022-05-02 05:10:18 +08:00
5f957b5cf9 Merge remote-tracking branch 'Meta/Alpha' into Alpha
# Conflicts:
#	.github/workflows/prerelease.yml
#	.github/workflows/release.yaml
2022-05-02 05:01:33 +08:00
8681728b8d chore: doq parameters 2022-05-02 05:01:07 +08:00
bb1eb5979b chore: Merge alpha and beta 2022-05-02 01:14:30 +08:00
032b6a2cc5 chore: workflow 2022-05-02 00:59:41 +08:00
45a02e3439 chore: workflow 2022-05-02 00:19:28 +08:00
252 changed files with 6631 additions and 3307 deletions

View File

@ -1,11 +1,13 @@
name: Docker
on: [push]
on:
push:
branches:
- Beta
tags:
- "v*"
env:
REGISTRY: docker.io
IMAGE_NAME: '{{ env.DOCKERHUB_ACCOUNT }}/{{ env.DOCKERHUB_REPO }}'
jobs:
build:
runs-on: ubuntu-latest
@ -23,6 +25,8 @@ jobs:
- name: Setup Docker buildx
uses: docker/setup-buildx-action@v1
with:
version: latest
# Extract metadata (tags, labels) for Docker
# https://github.com/docker/metadata-action
@ -30,15 +34,15 @@ jobs:
id: meta
uses: docker/metadata-action@v3
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
images: ${{ env.REGISTRY }}/${{ secrets.DOCKERHUB_ACCOUNT }}/${{secrets.DOCKERHUB_REPO}}
- name: Log into registry ${{ env.REGISTRY }}
- name: Log into registry
if: github.event_name != 'pull_request'
uses: docker/login-action@v1
with:
registry: ${{ env.REGISTRY }}
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
username: ${{ secrets.DOCKER_HUB_USER }}
password: ${{ secrets.DOCKER_HUB_TOKEN }}
# Build and push Docker image with Buildx (don't push on PR)
# https://github.com/docker/build-push-action
@ -47,6 +51,7 @@ jobs:
uses: docker/build-push-action@v2
with:
context: .
file: ./Dockerfile
push: ${{ github.event_name != 'pull_request' }}
platforms: |
linux/386

View File

@ -1,8 +1,15 @@
name: alpha
on: [push]
name: Prerelease
on:
push:
branches:
- Alpha
- Beta
pull_request:
branches:
- Alpha
- Beta
jobs:
Build:
if: ${{ !contains(github.event.head_commit.message, '[Skip CI]') }}
runs-on: ubuntu-latest
steps:
- name: Get latest go version
@ -24,48 +31,40 @@ jobs:
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-go-
# - name: Get dependencies, run test
# run: |
# go test ./...
- name: Test
if: ${{github.ref_name=='Beta'}}
run: |
go test ./...
- name: Build
if: success()
env:
NAME: Clash.Meta
BINDIR: bin
run: make -j releases
run: make -j$(($(nproc) + 1)) releases
- name: Delete current release assets
uses: andreaswilli/delete-release-assets-action@v2.0.0
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
tag: alpha
tag: Prerelease-${{ github.ref_name }}
deleteOnlyFromDrafts: false
- name: Tag Repo
uses: richardsimko/update-tag@v1
with:
tag_name: alpha
tag_name: Prerelease-${{ github.ref_name }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Upload Alpha
uses: softprops/action-gh-release@v1
if: ${{ env.GIT_BRANCH != 'Meta' && success() }}
if: ${{ success() }}
with:
tag: ${{ github.ref }}
tag_name: alpha
tag: ${{ github.ref_name }}
tag_name: Prerelease-${{ github.ref_name }}
files: bin/*
prerelease: true
# - name: send telegram message on push
# uses: appleboy/telegram-action@master
# with:
# to: ${{ secrets.TTELEGRAM_CHAT_ID }}
# token: ${{ secrets.TELEGRAM_TOKEN }}
# message: |
# ${{ github.actor }} created commit:
# Commit message: ${{ github.event.commits[0].message }}
#
# Repository: ${{ github.repository }}
#
# See changes: https://github.com/${{ github.repository }}/commit/${{github.sha}}
generate_release_notes: true

44
.github/workflows/release.yaml vendored Normal file
View File

@ -0,0 +1,44 @@
name: Release
on:
push:
tags:
- "v*"
jobs:
Build:
runs-on: ubuntu-latest
steps:
- 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: Check out code into the Go module directory
uses: actions/checkout@v3
- name: Cache go module
uses: actions/cache@v2
with:
path: ~/go/pkg/mod
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-go-
- name: Test
run: |
go test ./...
- name: Build
if: success()
env:
NAME: Clash.Meta
BINDIR: bin
run: make -j$(($(nproc) + 1)) releases
- name: Upload Release
uses: softprops/action-gh-release@v1
if: ${{ success() && startsWith(github.ref, 'refs/tags/')}}
with:
tag: ${{ github.ref }}
files: bin/*
generate_release_notes: true

View File

@ -1,41 +1,26 @@
FROM golang:alpine as builder
ARG TARGETOS
ARG TARGETARCH
RUN apk add --no-cache make git && \
mkdir /clash-config && \
wget -O /clash-config/Country.mmdb https://raw.githubusercontent.com/Loyalsoldier/geoip/release/Country.mmdb && \
wget -O /clash-config/geosite.dat https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geosite.dat && \
wget -O /clash-config/geoip.dat https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geoip.dat
WORKDIR /clash-src
COPY . /clash-src
RUN go mod download
RUN /bin/ash -c 'set -ex && \
if [ "$TARGETARCH" == "amd64" ]; then \
GOOS=$TARGETOS GOARCH=$TARGETARCH GOAMD64=v1 make docker && \
mv ./bin/Clash.Meta-docker ./bin/clash-amd64v1 && \
GOOS=$TARGETOS GOARCH=$TARGETARCH GOAMD64=v2 make docker && \
mv ./bin/Clash.Meta-docker ./bin/clash-amd64v2 && \
GOOS=$TARGETOS GOARCH=$TARGETARCH GOAMD64=v3 make docker && \
mv ./bin/Clash.Meta-docker ./bin/clash-amd64v3 && \
ln -s clash-amd64v3 ./bin/clash-amd64v4 && \
mv check_amd64.sh ./bin/ && \
printf "#!/bin/sh\\nsh ./check_amd64.sh\\nexec ./clash-amd64v\$? \$@" > ./bin/clash && \
chmod +x ./bin/check_amd64.sh ./bin/clash; \
else \
GOOS=$TARGETOS GOARCH=$TARGETARCH make docker && \
mv ./bin/Clash.Meta-docker ./bin/clash; \
fi'
WORKDIR /clash-src
RUN go mod download &&\
make docker &&\
mv ./bin/Clash.Meta-docker /clash
FROM alpine:latest
LABEL org.opencontainers.image.source="https://github.com/MetaCubeX/Clash.Meta"
RUN apk add --no-cache ca-certificates tzdata
VOLUME ["/root/.config/clash/"]
EXPOSE 7890/tcp
COPY --from=builder /clash-config/ /root/.config/clash/
COPY --from=builder /clash-src/bin/ /
COPY --from=builder /clash /clash
RUN chmod +x /clash
ENTRYPOINT [ "/clash" ]

View File

@ -1,20 +1,26 @@
NAME=Clash.Meta
BINDIR=bin
BRANCH=$(shell git rev-parse --abbrev-ref HEAD)
BRANCH=$(shell git branch --show-current)
ifeq ($(BRANCH),Alpha)
VERSION=alpha-$(shell git rev-parse --short HEAD)
else ifeq ($(BRANCH),Beta)
VERSION=beta-$(shell git rev-parse --short HEAD)
else ifeq ($(BRANCH),)
VERSION=$(shell git describe --tags)
else
VERSION=$(shell git rev-parse --short HEAD)
endif
BUILDTIME=$(shell date -u)
GOBUILD=CGO_ENABLED=0 go build -trimpath -ldflags '-X "github.com/Dreamacro/clash/constant.Version=$(VERSION)" \
-X "github.com/Dreamacro/clash/constant.BuildTime=$(BUILDTIME)" \
-w -s -buildid='
PLATFORM_LIST = \
darwin-amd64v1 \
darwin-amd64v2 \
darwin-amd64v3 \
darwin-amd64 \
darwin-arm64 \
linux-amd64v1 \
linux-amd64v2 \
linux-amd64v3 \
linux-amd64-compatible \
linux-amd64 \
linux-armv5 \
linux-armv6 \
linux-armv7 \
@ -32,9 +38,8 @@ PLATFORM_LIST = \
WINDOWS_ARCH_LIST = \
windows-386 \
windows-amd64v1 \
windows-amd64v2 \
windows-amd64v3 \
windows-amd64-compatible \
windows-amd64 \
windows-arm64 \
windows-arm32v7
@ -43,32 +48,26 @@ all:linux-amd64 linux-arm64\
windows-amd64 windows-arm64\
docker:
$(GOBUILD) -o $(BINDIR)/$(NAME)-$@
GOAMD64=v3 $(GOBUILD) -o $(BINDIR)/$(NAME)-$@
darwin-amd64v3:
darwin-amd64:
GOARCH=amd64 GOOS=darwin GOAMD64=v3 $(GOBUILD) -o $(BINDIR)/$(NAME)-$@
darwin-amd64v2:
darwin-amd64-compatible:
GOARCH=amd64 GOOS=darwin GOAMD64=v2 $(GOBUILD) -o $(BINDIR)/$(NAME)-$@
darwin-amd64v1:
GOARCH=amd64 GOOS=darwin GOAMD64=v1 $(GOBUILD) -o $(BINDIR)/$(NAME)-$@
darwin-arm64:
GOARCH=arm64 GOOS=darwin $(GOBUILD) -o $(BINDIR)/$(NAME)-$@
linux-386:
GOARCH=386 GOOS=linux $(GOBUILD) -o $(BINDIR)/$(NAME)-$@
linux-amd64v3:
linux-amd64:
GOARCH=amd64 GOOS=linux GOAMD64=v3 $(GOBUILD) -o $(BINDIR)/$(NAME)-$@
linux-amd64v2:
linux-amd64-compatible:
GOARCH=amd64 GOOS=linux GOAMD64=v2 $(GOBUILD) -o $(BINDIR)/$(NAME)-$@
linux-amd64v1:
GOARCH=amd64 GOOS=linux GOAMD64=v1 $(GOBUILD) -o $(BINDIR)/$(NAME)-$@
linux-arm64:
GOARCH=arm64 GOOS=linux $(GOBUILD) -o $(BINDIR)/$(NAME)-$@
@ -114,15 +113,12 @@ freebsd-arm64:
windows-386:
GOARCH=386 GOOS=windows $(GOBUILD) -o $(BINDIR)/$(NAME)-$@.exe
windows-amd64v3:
windows-amd64:
GOARCH=amd64 GOOS=windows GOAMD64=v3 $(GOBUILD) -o $(BINDIR)/$(NAME)-$@.exe
windows-amd64v2:
windows-amd64-compatible:
GOARCH=amd64 GOOS=windows GOAMD64=v2 $(GOBUILD) -o $(BINDIR)/$(NAME)-$@.exe
windows-amd64v1:
GOARCH=amd64 GOOS=windows GOAMD64=v1 $(GOBUILD) -o $(BINDIR)/$(NAME)-$@.exe
windows-arm64:
GOARCH=arm64 GOOS=windows $(GOBUILD) -o $(BINDIR)/$(NAME)-$@.exe

View File

@ -14,7 +14,6 @@ import (
"github.com/Dreamacro/clash/common/queue"
"github.com/Dreamacro/clash/component/dialer"
C "github.com/Dreamacro/clash/constant"
"go.uber.org/atomic"
)

View File

@ -11,7 +11,7 @@ import (
// NewHTTPS receive CONNECT request and return ConnContext
func NewHTTPS(request *http.Request, conn net.Conn) *context.ConnContext {
metadata := parseHTTPAddr(request)
metadata.Type = C.HTTPCONNECT
metadata.Type = C.HTTPS
if ip, port, err := parseAddr(conn.RemoteAddr().String()); err == nil {
metadata.SrcIP = ip
metadata.SrcPort = port

View File

@ -2,7 +2,7 @@ package inbound
import (
C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/transport/socks5"
M "github.com/sagernet/sing/common/metadata"
)
// PacketAdapter is a UDP Packet adapter for socks/redir/tun
@ -17,8 +17,8 @@ func (s *PacketAdapter) Metadata() *C.Metadata {
}
// NewPacket is PacketAdapter generator
func NewPacket(target socks5.Addr, packet C.UDPPacket, source C.Type) *PacketAdapter {
metadata := parseSocksAddr(target)
func NewPacket(target M.Socksaddr, packet C.UDPPacket, source C.Type) *PacketAdapter {
metadata := socksAddrToMetadata(target)
metadata.NetWork = C.UDP
metadata.Type = source
if ip, port, err := parseAddr(packet.LocalAddr().String()); err == nil {

View File

@ -10,8 +10,26 @@ import (
"github.com/Dreamacro/clash/common/nnip"
C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/transport/socks5"
M "github.com/sagernet/sing/common/metadata"
)
func socksAddrToMetadata(addr M.Socksaddr) *C.Metadata {
metadata := &C.Metadata{}
switch addr.Family() {
case M.AddressFamilyIPv4:
metadata.AddrType = C.AtypIPv4
metadata.DstIP = addr.Addr
case M.AddressFamilyIPv6:
metadata.AddrType = C.AtypIPv6
metadata.DstIP = addr.Addr
case M.AddressFamilyFqdn:
metadata.AddrType = C.AtypDomainName
metadata.Host = addr.Fqdn
}
metadata.DstPort = strconv.Itoa(int(addr.Port))
return metadata
}
func parseSocksAddr(target socks5.Addr) *C.Metadata {
metadata := &C.Metadata{
AddrType: int(target[0]),

View File

@ -2,15 +2,18 @@ package outbound
import (
"context"
"crypto/sha1"
"encoding/hex"
"encoding/json"
"errors"
"net"
"regexp"
"strings"
"github.com/Dreamacro/clash/component/dialer"
C "github.com/Dreamacro/clash/constant"
"github.com/gofrs/uuid"
"github.com/sagernet/sing/common/buf"
"github.com/sagernet/sing/common/bufio"
M "github.com/sagernet/sing/common/metadata"
N "github.com/sagernet/sing/common/network"
)
type Base struct {
@ -20,6 +23,7 @@ type Base struct {
tp C.AdapterType
udp bool
rmark int
id string
}
// Name implements C.ProxyAdapter
@ -27,6 +31,20 @@ func (b *Base) Name() string {
return b.name
}
// Id implements C.ProxyAdapter
func (b *Base) Id() string {
if b.id == "" {
id, err := uuid.NewV6()
if err != nil {
b.id = b.name
} else {
b.id = id.String()
}
}
return b.id
}
// Type implements C.ProxyAdapter
func (b *Base) Type() C.AdapterType {
return b.tp
@ -37,6 +55,10 @@ func (b *Base) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) {
return c, errors.New("no support")
}
func (b *Base) DialContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (C.Conn, error) {
return nil, errors.New("no support")
}
// ListenPacketContext implements C.ProxyAdapter
func (b *Base) ListenPacketContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (C.PacketConn, error) {
return nil, errors.New("no support")
@ -61,6 +83,7 @@ func (b *Base) SupportUDP() bool {
func (b *Base) MarshalJSON() ([]byte, error) {
return json.Marshal(map[string]string{
"type": b.Type().String(),
"id": b.Id(),
})
}
@ -114,7 +137,12 @@ func NewBase(opt BaseOption) *Base {
type conn struct {
net.Conn
chain C.Chain
chain C.Chain
actualRemoteDestination string
}
func (c *conn) RemoteDestination() string {
return c.actualRemoteDestination
}
// Chains implements C.Connection
@ -128,12 +156,18 @@ func (c *conn) AppendToChains(a C.ProxyAdapter) {
}
func NewConn(c net.Conn, a C.ProxyAdapter) C.Conn {
return &conn{c, []string{a.Name()}}
return &conn{c, []string{a.Name()}, parseRemoteDestination(a.Addr())}
}
type packetConn struct {
net.PacketConn
chain C.Chain
nc N.PacketConn
chain C.Chain
actualRemoteDestination string
}
func (c *packetConn) RemoteDestination() string {
return c.actualRemoteDestination
}
// Chains implements C.Connection
@ -146,31 +180,32 @@ func (c *packetConn) AppendToChains(a C.ProxyAdapter) {
c.chain = append(c.chain, a.Name())
}
func newPacketConn(pc net.PacketConn, a C.ProxyAdapter) C.PacketConn {
return &packetConn{pc, []string{a.Name()}}
func (c *packetConn) ReadPacket(buffer *buf.Buffer) (addr M.Socksaddr, err error) {
return c.nc.ReadPacket(buffer)
}
func uuidMap(str string) string {
match, _ := regexp.MatchString(`[\da-f]{8}(-[\da-f]{4}){3}-[\da-f]{12}$`, str)
if !match {
var Nil [16]byte
h := sha1.New()
h.Write(Nil[:])
h.Write([]byte(str))
u := h.Sum(nil)[:16]
u[6] = (u[6] & 0x0f) | (5 << 4)
u[8] = u[8]&(0xff>>2) | (0x02 << 6)
buf := make([]byte, 36)
hex.Encode(buf[0:8], u[0:4])
buf[8] = '-'
hex.Encode(buf[9:13], u[4:6])
buf[13] = '-'
hex.Encode(buf[14:18], u[6:8])
buf[18] = '-'
hex.Encode(buf[19:23], u[8:10])
buf[23] = '-'
hex.Encode(buf[24:], u[10:])
return string(buf)
}
return str
func (c *packetConn) WritePacket(buffer *buf.Buffer, addr M.Socksaddr) error {
return c.nc.WritePacket(buffer, addr)
}
func newPacketConn(pc net.PacketConn, a C.ProxyAdapter) C.PacketConn {
var nc N.PacketConn
if n, isNc := pc.(N.PacketConn); isNc {
nc = n
} else {
nc = &bufio.PacketConnWrapper{PacketConn: pc}
}
return &packetConn{pc, nc, []string{a.Name()}, parseRemoteDestination(a.Addr())}
}
func parseRemoteDestination(addr string) string {
if dst, _, err := net.SplitHostPort(addr); err == nil {
return dst
} else {
if addrError, ok := err.(*net.AddrError); ok && strings.Contains(addrError.Err, "missing port") {
return dst
} else {
return ""
}
}
}

View File

@ -56,13 +56,3 @@ func NewCompatible() *Direct {
},
}
}
func NewPass() *Direct {
return &Direct{
Base: &Base{
name: "PASS",
tp: C.Pass,
udp: true,
},
}
}

View File

@ -86,7 +86,7 @@ func (h *Http) shakeHand(metadata *C.Metadata, rw io.ReadWriter) error {
},
}
//增加headers
// 增加headers
if len(h.option.Headers) != 0 {
for key, value := range h.option.Headers {
req.Header.Add(key, value)

View File

@ -0,0 +1,270 @@
package outbound
import (
"context"
"crypto/tls"
"crypto/x509"
"encoding/base64"
"errors"
"fmt"
"io/ioutil"
"net"
"regexp"
"strconv"
"time"
"github.com/Dreamacro/clash/component/dialer"
C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/log"
"github.com/lucas-clemente/quic-go"
"github.com/lucas-clemente/quic-go/congestion"
M "github.com/sagernet/sing/common/metadata"
hyCongestion "github.com/tobyxdd/hysteria/pkg/congestion"
"github.com/tobyxdd/hysteria/pkg/core"
"github.com/tobyxdd/hysteria/pkg/obfs"
"github.com/tobyxdd/hysteria/pkg/pmtud_fix"
"github.com/tobyxdd/hysteria/pkg/transport"
)
const (
mbpsToBps = 125000
minSpeedBPS = 16384
DefaultStreamReceiveWindow = 15728640 // 15 MB/s
DefaultConnectionReceiveWindow = 67108864 // 64 MB/s
DefaultMaxIncomingStreams = 1024
DefaultALPN = "hysteria"
DefaultProtocol = "udp"
)
var rateStringRegexp = regexp.MustCompile(`^(\d+)\s*([KMGT]?)([Bb])ps$`)
type Hysteria struct {
*Base
client *core.Client
clientTransport *transport.ClientTransport
}
func (h *Hysteria) DialContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (C.Conn, error) {
tcpConn, err := h.client.DialTCP(metadata.RemoteAddress(), hyDialer(func() (net.PacketConn, error) {
return dialer.ListenPacket(ctx, "udp", "", h.Base.DialOptions(opts...)...)
}))
if err != nil {
return nil, err
}
return NewConn(tcpConn, h), nil
}
func (h *Hysteria) ListenPacketContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (C.PacketConn, error) {
udpConn, err := h.client.DialUDP(hyDialer(func() (net.PacketConn, error) {
return dialer.ListenPacket(ctx, "udp", "", h.Base.DialOptions(opts...)...)
}))
if err != nil {
return nil, err
}
return newPacketConn(&hyPacketConn{udpConn}, h), nil
}
type HysteriaOption struct {
BasicOption
Name string `proxy:"name"`
Server string `proxy:"server"`
Port int `proxy:"port"`
Protocol string `proxy:"protocol,omitempty"`
Up string `proxy:"up,omitempty"`
UpMbps int `proxy:"up_mbps,omitempty"`
Down string `proxy:"down,omitempty"`
DownMbps int `proxy:"down_mbps,omitempty"`
Auth string `proxy:"auth,omitempty"`
AuthString string `proxy:"auth_str,omitempty"`
Obfs string `proxy:"obfs,omitempty"`
SNI string `proxy:"sni,omitempty"`
SkipCertVerify bool `proxy:"skip-cert-verify,omitempty"`
ALPN string `proxy:"alpn,omitempty"`
CustomCA string `proxy:"ca,omitempty"`
CustomCAString string `proxy:"ca_str,omitempty"`
ReceiveWindowConn int `proxy:"recv_window_conn,omitempty"`
ReceiveWindow int `proxy:"recv_window,omitempty"`
DisableMTUDiscovery bool `proxy:"disable_mtu_discovery,omitempty"`
}
func (c *HysteriaOption) Speed() (uint64, uint64, error) {
var up, down uint64
if len(c.Up) > 0 {
up = stringToBps(c.Up)
if up == 0 {
return 0, 0, errors.New("invalid speed format")
}
} else {
up = uint64(c.UpMbps) * mbpsToBps
}
if len(c.Down) > 0 {
down = stringToBps(c.Down)
if down == 0 {
return 0, 0, errors.New("invalid speed format")
}
} else {
down = uint64(c.DownMbps) * mbpsToBps
}
return up, down, nil
}
func NewHysteria(option HysteriaOption) (*Hysteria, error) {
clientTransport := &transport.ClientTransport{
Dialer: &net.Dialer{
Timeout: 8 * time.Second,
},
}
addr := net.JoinHostPort(option.Server, strconv.Itoa(option.Port))
serverName := option.Server
if option.SNI != "" {
serverName = option.Server
}
tlsConfig := &tls.Config{
ServerName: serverName,
InsecureSkipVerify: option.SkipCertVerify,
MinVersion: tls.VersionTLS13,
}
if len(option.ALPN) > 0 {
tlsConfig.NextProtos = []string{option.ALPN}
} else {
tlsConfig.NextProtos = []string{DefaultALPN}
}
if len(option.CustomCA) > 0 {
bs, err := ioutil.ReadFile(option.CustomCA)
if err != nil {
return nil, fmt.Errorf("hysteria %s load ca error: %w", addr, err)
}
cp := x509.NewCertPool()
if !cp.AppendCertsFromPEM(bs) {
return nil, fmt.Errorf("hysteria %s failed to parse ca_str", addr)
}
tlsConfig.RootCAs = cp
} else if option.CustomCAString != "" {
cp := x509.NewCertPool()
if !cp.AppendCertsFromPEM([]byte(option.CustomCAString)) {
return nil, fmt.Errorf("hysteria %s failed to parse ca_str", addr)
}
tlsConfig.RootCAs = cp
}
quicConfig := &quic.Config{
InitialStreamReceiveWindow: uint64(option.ReceiveWindowConn),
MaxStreamReceiveWindow: uint64(option.ReceiveWindowConn),
InitialConnectionReceiveWindow: uint64(option.ReceiveWindow),
MaxConnectionReceiveWindow: uint64(option.ReceiveWindow),
KeepAlive: true,
DisablePathMTUDiscovery: option.DisableMTUDiscovery,
EnableDatagrams: true,
}
if option.Protocol == "" {
option.Protocol = DefaultProtocol
}
if option.ReceiveWindowConn == 0 {
quicConfig.InitialStreamReceiveWindow = DefaultStreamReceiveWindow
quicConfig.MaxStreamReceiveWindow = DefaultStreamReceiveWindow
}
if option.ReceiveWindow == 0 {
quicConfig.InitialConnectionReceiveWindow = DefaultConnectionReceiveWindow
quicConfig.MaxConnectionReceiveWindow = DefaultConnectionReceiveWindow
}
if !quicConfig.DisablePathMTUDiscovery && pmtud_fix.DisablePathMTUDiscovery {
log.Infoln("hysteria: Path MTU Discovery is not yet supported on this platform")
}
var auth []byte
if option.Auth != "" {
authBytes, err := base64.StdEncoding.DecodeString(option.Auth)
if err != nil {
return nil, fmt.Errorf("hysteria %s parse auth error: %w", addr, err)
}
auth = authBytes
} else {
auth = []byte(option.AuthString)
}
var obfuscator obfs.Obfuscator
if len(option.Obfs) > 0 {
obfuscator = obfs.NewXPlusObfuscator([]byte(option.Obfs))
}
up, down, _ := option.Speed()
client, err := core.NewClient(
addr, option.Protocol, auth, tlsConfig, quicConfig, clientTransport, up, down, func(refBPS uint64) congestion.CongestionControl {
return hyCongestion.NewBrutalSender(congestion.ByteCount(refBPS))
}, obfuscator,
)
if err != nil {
return nil, fmt.Errorf("hysteria %s create error: %w", addr, err)
}
return &Hysteria{
Base: &Base{
name: option.Name,
addr: addr,
tp: C.Hysteria,
udp: true,
iface: option.Interface,
rmark: option.RoutingMark,
},
client: client,
clientTransport: clientTransport,
}, nil
}
func stringToBps(s string) uint64 {
if s == "" {
return 0
}
m := rateStringRegexp.FindStringSubmatch(s)
if m == nil {
return 0
}
var n uint64
switch m[2] {
case "K":
n = 1 << 10
case "M":
n = 1 << 20
case "G":
n = 1 << 30
case "T":
n = 1 << 40
default:
n = 1
}
v, _ := strconv.ParseUint(m[1], 10, 64)
n = v * n
if m[3] == "b" {
// Bits, need to convert to bytes
n = n >> 3
}
return n
}
type hyPacketConn struct {
core.UDPConn
}
func (c *hyPacketConn) ReadFrom(p []byte) (n int, addr net.Addr, err error) {
b, addrStr, err := c.UDPConn.ReadFrom()
if err != nil {
return
}
n = copy(p, b)
addr = M.ParseSocksaddr(addrStr).UDPAddr()
return
}
func (c *hyPacketConn) WriteTo(p []byte, addr net.Addr) (n int, err error) {
err = c.UDPConn.WriteTo(p, M.SocksaddrFromNet(addr).String())
if err != nil {
return
}
n = len(p)
return
}
type hyDialer func() (net.PacketConn, error)
func (h hyDialer) ListenPacket() (net.PacketConn, error) {
return h()
}

View File

@ -34,6 +34,16 @@ func NewReject() *Reject {
}
}
func NewPass() *Reject {
return &Reject{
Base: &Base{
name: "PASS",
tp: C.Pass,
udp: true,
},
}
}
type nopConn struct{}
func (rw *nopConn) Read(b []byte) (int, error) {

View File

@ -13,13 +13,15 @@ import (
obfs "github.com/Dreamacro/clash/transport/simple-obfs"
"github.com/Dreamacro/clash/transport/socks5"
v2rayObfs "github.com/Dreamacro/clash/transport/v2ray-plugin"
"github.com/Dreamacro/go-shadowsocks2/core"
"github.com/sagernet/sing-shadowsocks"
"github.com/sagernet/sing-shadowsocks/shadowimpl"
"github.com/sagernet/sing/common/bufio"
M "github.com/sagernet/sing/common/metadata"
)
type ShadowSocks struct {
*Base
cipher core.Cipher
method shadowsocks.Method
// obfs
obfsMode string
@ -69,9 +71,7 @@ func (ss *ShadowSocks) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, e
return nil, fmt.Errorf("%s connect error: %w", ss.addr, err)
}
}
c = ss.cipher.StreamConn(c)
_, err := c.Write(serializesSocksAddr(metadata))
return c, err
return ss.method.DialConn(c, M.ParseSocksaddr(metadata.RemoteAddress()))
}
// DialContext implements C.ProxyAdapter
@ -100,16 +100,13 @@ func (ss *ShadowSocks) ListenPacketContext(ctx context.Context, metadata *C.Meta
pc.Close()
return nil, err
}
pc = ss.cipher.PacketConn(pc)
return newPacketConn(&ssPacketConn{PacketConn: pc, rAddr: addr}, ss), nil
pc = ss.method.DialPacketConn(&bufio.BindPacketConn{PacketConn: pc, Addr: addr})
return newPacketConn(pc, ss), nil
}
func NewShadowSocks(option ShadowSocksOption) (*ShadowSocks, error) {
addr := net.JoinHostPort(option.Server, strconv.Itoa(option.Port))
cipher := option.Cipher
password := option.Password
ciph, err := core.PickCipher(cipher, nil, password)
method, err := shadowimpl.FetchMethod(option.Cipher, option.Password)
if err != nil {
return nil, fmt.Errorf("ss %s initialize error: %w", addr, err)
}
@ -162,7 +159,7 @@ func NewShadowSocks(option ShadowSocksOption) (*ShadowSocks, error) {
iface: option.Interface,
rmark: option.RoutingMark,
},
cipher: ciph,
method: method,
obfsMode: obfsMode,
v2rayOption: v2rayOption,

View File

@ -8,12 +8,11 @@ import (
"github.com/Dreamacro/clash/component/dialer"
C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/transport/shadowsocks/core"
"github.com/Dreamacro/clash/transport/shadowsocks/shadowaead"
"github.com/Dreamacro/clash/transport/shadowsocks/shadowstream"
"github.com/Dreamacro/clash/transport/ssr/obfs"
"github.com/Dreamacro/clash/transport/ssr/protocol"
"github.com/Dreamacro/go-shadowsocks2/core"
"github.com/Dreamacro/go-shadowsocks2/shadowaead"
"github.com/Dreamacro/go-shadowsocks2/shadowstream"
)
type ShadowSocksR struct {

View File

@ -99,7 +99,13 @@ func (s *Snell) ListenPacketContext(ctx context.Context, metadata *C.Metadata, o
tcpKeepAlive(c)
c = streamConn(c, streamOption{s.psk, s.version, s.addr, s.obfsOption})
return s.ListenPacketOnStreamConn(c, metadata)
err = snell.WriteUDPHeader(c, s.version)
if err != nil {
return nil, err
}
pc := snell.PacketConn(c)
return newPacketConn(pc, s), nil
}
// ListenPacketOnStreamConn implements C.ProxyAdapter

View File

@ -13,8 +13,6 @@ import (
"github.com/Dreamacro/clash/transport/gun"
"github.com/Dreamacro/clash/transport/trojan"
"github.com/Dreamacro/clash/transport/vless"
"golang.org/x/net/http2"
)
type Trojan struct {
@ -25,7 +23,7 @@ type Trojan struct {
// for gun mux
gunTLSConfig *tls.Config
gunConfig *gun.Config
transport *http2.Transport
transport *gun.TransportWrap
}
type TrojanOption struct {
@ -161,7 +159,13 @@ func (t *Trojan) ListenPacketContext(ctx context.Context, metadata *C.Metadata,
}
}
return t.ListenPacketOnStreamConn(c, metadata)
err = t.instance.WriteHeader(c, trojan.CommandUDP, serializesSocksAddr(metadata))
if err != nil {
return nil, err
}
pc := t.instance.PacketConn(c)
return newPacketConn(pc, t), err
}
// ListenPacketOnStreamConn implements C.ProxyAdapter

View File

@ -3,7 +3,6 @@ package outbound
import (
"bytes"
"crypto/tls"
xtls "github.com/xtls/go"
"net"
"strconv"
"sync"
@ -12,6 +11,7 @@ import (
"github.com/Dreamacro/clash/component/resolver"
C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/transport/socks5"
xtls "github.com/xtls/go"
)
var (

View File

@ -12,14 +12,13 @@ import (
"strconv"
"sync"
"github.com/Dreamacro/clash/common/convert"
"github.com/Dreamacro/clash/component/dialer"
"github.com/Dreamacro/clash/component/resolver"
C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/transport/gun"
"github.com/Dreamacro/clash/transport/vless"
"github.com/Dreamacro/clash/transport/vmess"
"golang.org/x/net/http2"
)
const (
@ -35,7 +34,7 @@ type Vless struct {
// for gun mux
gunTLSConfig *tls.Config
gunConfig *gun.Config
transport *http2.Transport
transport *gun.TransportWrap
}
type VlessOption struct {
@ -92,6 +91,9 @@ func (v *Vless) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) {
wsOpts.TLSConfig.ServerName = v.option.ServerName
} else if host := wsOpts.Headers.Get("Host"); host != "" {
wsOpts.TLSConfig.ServerName = host
} else {
wsOpts.Headers.Set("Host", convert.RandHost())
convert.SetUserAgent(wsOpts.Headers)
}
c, err = vmess.StreamWebsocketConn(c, wsOpts)
case "http":
@ -396,7 +398,7 @@ func NewVless(option VlessOption) (*Vless, error) {
}
}
client, err := vless.NewClient(uuidMap(option.UUID), addons, option.FlowShow)
client, err := vless.NewClient(option.UUID, addons, option.FlowShow)
if err != nil {
return nil, err
}

View File

@ -10,13 +10,12 @@ import (
"strconv"
"strings"
"github.com/Dreamacro/clash/common/convert"
"github.com/Dreamacro/clash/component/dialer"
"github.com/Dreamacro/clash/component/resolver"
C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/transport/gun"
"github.com/Dreamacro/clash/transport/vmess"
"golang.org/x/net/http2"
)
type Vmess struct {
@ -27,7 +26,7 @@ type Vmess struct {
// for gun mux
gunTLSConfig *tls.Config
gunConfig *gun.Config
transport *http2.Transport
transport *gun.TransportWrap
}
type VmessOption struct {
@ -80,12 +79,6 @@ func (v *Vmess) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) {
var err error
switch v.option.Network {
case "ws":
if v.option.WSOpts.Path == "" {
v.option.WSOpts.Path = v.option.WSPath
}
if len(v.option.WSOpts.Headers) == 0 {
v.option.WSOpts.Headers = v.option.WSHeaders
}
host, port, _ := net.SplitHostPort(v.addr)
wsOpts := &vmess.WebsocketConfig{
@ -94,14 +87,13 @@ func (v *Vmess) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) {
Path: v.option.WSOpts.Path,
MaxEarlyData: v.option.WSOpts.MaxEarlyData,
EarlyDataHeaderName: v.option.WSOpts.EarlyDataHeaderName,
Headers: make(http.Header),
}
if len(v.option.WSOpts.Headers) != 0 {
header := http.Header{}
for key, value := range v.option.WSOpts.Headers {
header.Add(key, value)
wsOpts.Headers.Add(key, value)
}
wsOpts.Headers = header
}
if v.option.TLS {
@ -116,6 +108,9 @@ func (v *Vmess) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) {
} else if host := wsOpts.Headers.Get("Host"); host != "" {
wsOpts.TLSConfig.ServerName = host
}
} else {
wsOpts.Headers.Set("Host", convert.RandHost())
convert.SetUserAgent(wsOpts.Headers)
}
c, err = vmess.StreamWebsocketConn(c, wsOpts)
case "http":
@ -135,6 +130,9 @@ func (v *Vmess) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) {
if err != nil {
return nil, err
}
} else {
http.Header(v.option.HTTPOpts.Headers).Set("Host", convert.RandHost())
convert.SetUserAgent(v.option.HTTPOpts.Headers)
}
host, _, _ := net.SplitHostPort(v.addr)
@ -276,7 +274,7 @@ func (v *Vmess) SupportUOT() bool {
func NewVmess(option VmessOption) (*Vmess, error) {
security := strings.ToLower(option.Cipher)
client, err := vmess.NewClient(vmess.Config{
UUID: uuidMap(option.UUID),
UUID: option.UUID,
AlterID: uint16(option.AlterID),
Security: security,
HostName: option.Server,

View File

@ -3,8 +3,7 @@ package outboundgroup
import (
"context"
"encoding/json"
"github.com/Dreamacro/clash/log"
"go.uber.org/atomic"
"errors"
"time"
"github.com/Dreamacro/clash/adapter/outbound"
@ -15,9 +14,9 @@ import (
type Fallback struct {
*GroupBase
disableUDP bool
failedTimes *atomic.Int32
failedTime *atomic.Int64
disableUDP bool
testUrl string
selected string
}
func (f *Fallback) Now() string {
@ -31,8 +30,7 @@ func (f *Fallback) DialContext(ctx context.Context, metadata *C.Metadata, opts .
c, err := proxy.DialContext(ctx, metadata, f.Base.DialOptions(opts...)...)
if err == nil {
c.AppendToChains(f)
f.failedTimes.Store(-1)
f.failedTime.Store(-1)
f.onDialSuccess()
} else {
f.onDialFailed()
}
@ -46,41 +44,11 @@ func (f *Fallback) ListenPacketContext(ctx context.Context, metadata *C.Metadata
pc, err := proxy.ListenPacketContext(ctx, metadata, f.Base.DialOptions(opts...)...)
if err == nil {
pc.AppendToChains(f)
f.failedTimes.Store(-1)
f.failedTime.Store(-1)
} else {
f.onDialFailed()
}
return pc, err
}
func (f *Fallback) onDialFailed() {
if f.failedTime.Load() == -1 {
log.Warnln("%s first failed", f.Name())
now := time.Now().UnixMilli()
f.failedTime.Store(now)
f.failedTimes.Store(1)
} else {
if f.failedTime.Load()-time.Now().UnixMilli() > 5*time.Second.Milliseconds() {
f.failedTimes.Store(-1)
f.failedTime.Store(-1)
} else {
failedCount := f.failedTimes.Inc()
log.Warnln("%s failed count: %d", f.Name(), failedCount)
if failedCount >= 5 {
log.Warnln("because %s failed multiple times, active health check", f.Name())
for _, proxyProvider := range f.providers {
go proxyProvider.HealthCheck()
}
f.failedTimes.Store(-1)
f.failedTime.Store(-1)
}
}
}
}
// SupportUDP implements C.ProxyAdapter
func (f *Fallback) SupportUDP() bool {
if f.disableUDP {
@ -112,13 +80,40 @@ func (f *Fallback) Unwrap(metadata *C.Metadata) C.Proxy {
func (f *Fallback) findAliveProxy(touch bool) C.Proxy {
proxies := f.GetProxies(touch)
for _, proxy := range proxies {
if proxy.Alive() {
al := proxies[0]
for i := len(proxies) - 1; i > -1; i-- {
proxy := proxies[i]
if proxy.Name() == f.selected && proxy.Alive() {
return proxy
}
if proxy.Alive() {
al = proxy
}
}
return al
}
func (f *Fallback) Set(name string) error {
var p C.Proxy
for _, proxy := range f.GetProxies(false) {
if proxy.Name() == name {
p = proxy
break
}
}
return proxies[0]
if p == nil {
return errors.New("proxy not exist")
}
f.selected = name
if !p.Alive() {
ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond*time.Duration(5000))
defer cancel()
_, _ = p.URLTest(ctx, f.testUrl)
}
return nil
}
func NewFallback(option *GroupCommonOption, providers []provider.ProxyProvider) *Fallback {
@ -133,8 +128,7 @@ func NewFallback(option *GroupCommonOption, providers []provider.ProxyProvider)
option.Filter,
providers,
}),
disableUDP: option.DisableUDP,
failedTimes: atomic.NewInt32(-1),
failedTime: atomic.NewInt64(-1),
disableUDP: option.DisableUDP,
testUrl: option.URL,
}
}

View File

@ -1,21 +1,31 @@
package outboundgroup
import (
"context"
"fmt"
"sync"
"time"
"github.com/Dreamacro/clash/adapter/outbound"
C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/constant/provider"
types "github.com/Dreamacro/clash/constant/provider"
"github.com/Dreamacro/clash/constant/provider"
"github.com/Dreamacro/clash/log"
"github.com/Dreamacro/clash/tunnel"
"github.com/dlclark/regexp2"
"sync"
"go.uber.org/atomic"
)
type GroupBase struct {
*outbound.Base
filter *regexp2.Regexp
providers []provider.ProxyProvider
versions sync.Map // map[string]uint
proxies sync.Map // map[string][]C.Proxy
filter *regexp2.Regexp
providers []provider.ProxyProvider
versions sync.Map // map[string]uint
proxies sync.Map // map[string][]C.Proxy
failedTestMux sync.Mutex
failedTimes int
failedTime time.Time
failedTesting *atomic.Bool
}
type GroupBaseOption struct {
@ -30,9 +40,10 @@ func NewGroupBase(opt GroupBaseOption) *GroupBase {
filter = regexp2.MustCompile(opt.filter, 0)
}
return &GroupBase{
Base: outbound.NewBase(opt.BaseOption),
filter: filter,
providers: opt.providers,
Base: outbound.NewBase(opt.BaseOption),
filter: filter,
providers: opt.providers,
failedTesting: atomic.NewBool(false),
}
}
@ -41,25 +52,23 @@ func (gb *GroupBase) GetProxies(touch bool) []C.Proxy {
var proxies []C.Proxy
for _, pd := range gb.providers {
if touch {
proxies = append(proxies, pd.ProxiesWithTouch()...)
} else {
proxies = append(proxies, pd.Proxies()...)
pd.Touch()
}
proxies = append(proxies, pd.Proxies()...)
}
if len(proxies) == 0 {
return append(proxies, tunnel.Proxies()["COMPATIBLE"])
}
return proxies
}
//TODO("Touch Version 没变的")
for _, pd := range gb.providers {
if pd.VehicleType() == types.Compatible {
if touch {
gb.proxies.Store(pd.Name(), pd.ProxiesWithTouch())
} else {
gb.proxies.Store(pd.Name(), pd.Proxies())
}
for _, pd := range gb.providers {
if touch {
pd.Touch()
}
if pd.VehicleType() == types.Compatible {
gb.proxies.Store(pd.Name(), pd.Proxies())
gb.versions.Store(pd.Name(), pd.Version())
continue
}
@ -70,11 +79,7 @@ func (gb *GroupBase) GetProxies(touch bool) []C.Proxy {
newProxies []C.Proxy
)
if touch {
proxies = pd.ProxiesWithTouch()
} else {
proxies = pd.Proxies()
}
proxies = pd.Proxies()
for _, p := range proxies {
if mat, _ := gb.filter.FindStringMatch(p.Name()); mat != nil {
@ -96,3 +101,89 @@ func (gb *GroupBase) GetProxies(touch bool) []C.Proxy {
}
return proxies
}
func (gb *GroupBase) URLTest(ctx context.Context, url string) (map[string]uint16, error) {
var wg sync.WaitGroup
var lock sync.Mutex
mp := map[string]uint16{}
proxies := gb.GetProxies(false)
for _, proxy := range proxies {
proxy := proxy
wg.Add(1)
go func() {
delay, err := proxy.URLTest(ctx, url)
lock.Lock()
if err == nil {
mp[proxy.Name()] = delay
}
lock.Unlock()
wg.Done()
}()
}
wg.Wait()
if len(mp) == 0 {
return mp, fmt.Errorf("get delay: all proxies timeout")
} else {
return mp, nil
}
}
func (gb *GroupBase) onDialFailed() {
if gb.failedTesting.Load() {
return
}
go func() {
gb.failedTestMux.Lock()
defer gb.failedTestMux.Unlock()
gb.failedTimes++
if gb.failedTimes == 1 {
log.Debugln("ProxyGroup: %s first failed", gb.Name())
gb.failedTime = time.Now()
} else {
if time.Since(gb.failedTime) > gb.failedTimeoutInterval() {
return
}
log.Debugln("ProxyGroup: %s failed count: %d", gb.Name(), gb.failedTimes)
if gb.failedTimes >= gb.maxFailedTimes() {
gb.failedTesting.Store(true)
log.Warnln("because %s failed multiple times, active health check", gb.Name())
wg := sync.WaitGroup{}
for _, proxyProvider := range gb.providers {
wg.Add(1)
proxyProvider := proxyProvider
go func() {
defer wg.Done()
proxyProvider.HealthCheck()
}()
}
wg.Wait()
gb.failedTesting.Store(false)
gb.failedTimes = 0
}
}
}()
}
func (gb *GroupBase) failedIntervalTime() int64 {
return 5 * time.Second.Milliseconds()
}
func (gb *GroupBase) onDialSuccess() {
if !gb.failedTesting.Load() {
gb.failedTimes = 0
}
}
func (gb *GroupBase) maxFailedTimes() int {
return 5
}
func (gb *GroupBase) failedTimeoutInterval() time.Duration {
return 5 * time.Second
}

View File

@ -6,13 +6,14 @@ import (
"errors"
"fmt"
"net"
"time"
"github.com/Dreamacro/clash/adapter/outbound"
"github.com/Dreamacro/clash/common/cache"
"github.com/Dreamacro/clash/common/murmur3"
"github.com/Dreamacro/clash/component/dialer"
C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/constant/provider"
"golang.org/x/net/publicsuffix"
)
@ -36,6 +37,10 @@ func parseStrategy(config map[string]any) string {
}
func getKey(metadata *C.Metadata) string {
if metadata == nil {
return ""
}
if metadata.Host != "" {
// ip host
if ip := net.ParseIP(metadata.Host); ip != nil {
@ -54,6 +59,16 @@ func getKey(metadata *C.Metadata) string {
return metadata.DstIP.String()
}
func getKeyWithSrcAndDst(metadata *C.Metadata) string {
dst := getKey(metadata)
src := ""
if metadata != nil {
src = metadata.SrcIP.String()
}
return fmt.Sprintf("%s%s", src, dst)
}
func jumpHash(key uint64, buckets int32) int32 {
var b, j int64
@ -71,6 +86,9 @@ func (lb *LoadBalance) DialContext(ctx context.Context, metadata *C.Metadata, op
defer func() {
if err == nil {
c.AppendToChains(lb)
lb.onDialSuccess()
} else {
lb.onDialFailed()
}
}()
@ -130,6 +148,41 @@ func strategyConsistentHashing() strategyFn {
}
}
func strategyStickySessions() strategyFn {
ttl := time.Minute * 10
maxRetry := 5
lruCache := cache.NewLRUCache[uint64, int](
cache.WithAge[uint64, int](int64(ttl.Seconds())),
cache.WithSize[uint64, int](1000))
return func(proxies []C.Proxy, metadata *C.Metadata) C.Proxy {
key := uint64(murmur3.Sum32([]byte(getKeyWithSrcAndDst(metadata))))
length := len(proxies)
idx, has := lruCache.Get(key)
if !has {
idx = int(jumpHash(key+uint64(time.Now().UnixNano()), int32(length)))
}
nowIdx := idx
for i := 1; i < maxRetry; i++ {
proxy := proxies[nowIdx]
if proxy.Alive() {
if nowIdx != idx {
lruCache.Delete(key)
lruCache.Set(key, nowIdx)
}
return proxy
} else {
nowIdx = int(jumpHash(key+uint64(time.Now().UnixNano()), int32(length)))
}
}
lruCache.Delete(key)
lruCache.Set(key, 0)
return proxies[0]
}
}
// Unwrap implements C.ProxyAdapter
func (lb *LoadBalance) Unwrap(metadata *C.Metadata) C.Proxy {
proxies := lb.GetProxies(true)
@ -138,7 +191,7 @@ func (lb *LoadBalance) Unwrap(metadata *C.Metadata) C.Proxy {
// MarshalJSON implements C.ProxyAdapter
func (lb *LoadBalance) MarshalJSON() ([]byte, error) {
all := []string{}
var all []string
for _, proxy := range lb.GetProxies(false) {
all = append(all, proxy.Name())
}
@ -155,6 +208,8 @@ func NewLoadBalance(option *GroupCommonOption, providers []provider.ProxyProvide
strategyFn = strategyConsistentHashing()
case "round-robin":
strategyFn = strategyRoundRobin()
case "sticky-sessions":
strategyFn = strategyStickySessions()
default:
return nil, fmt.Errorf("%w: %s", errStrategy, strategy)
}

View File

@ -75,8 +75,12 @@ func ParseProxyGroup(config map[string]any, proxyMap map[string]C.Proxy, provide
providers = append(providers, pd)
providersMap[groupName] = pd
} else {
if groupOption.URL == "" || groupOption.Interval == 0 {
return nil, errMissHealthCheck
if groupOption.URL == "" {
groupOption.URL = "http://www.gstatic.com/generate_204"
}
if groupOption.Interval == 0 {
groupOption.Interval = 300
}
hc := provider.NewHealthCheck(ps, groupOption.URL, uint(groupOption.Interval), groupOption.Lazy)

View File

@ -170,6 +170,11 @@ func (r *Relay) proxies(metadata *C.Metadata, touch bool) ([]C.Proxy, []C.Proxy)
return targetProxies, chainProxies
}
func (r *Relay) Addr() string {
proxies, _ := r.proxies(nil, true)
return proxies[len(proxies)-1].Addr()
}
func NewRelay(option *GroupCommonOption, providers []provider.ProxyProvider) *Relay {
return &Relay{
GroupBase: NewGroupBase(GroupBaseOption{

View File

@ -3,8 +3,6 @@ package outboundgroup
import (
"context"
"encoding/json"
"github.com/Dreamacro/clash/log"
"go.uber.org/atomic"
"time"
"github.com/Dreamacro/clash/adapter/outbound"
@ -24,12 +22,10 @@ func urlTestWithTolerance(tolerance uint16) urlTestOption {
type URLTest struct {
*GroupBase
tolerance uint16
disableUDP bool
fastNode C.Proxy
fastSingle *singledo.Single[C.Proxy]
failedTimes *atomic.Int32
failedTime *atomic.Int64
tolerance uint16
disableUDP bool
fastNode C.Proxy
fastSingle *singledo.Single[C.Proxy]
}
func (u *URLTest) Now() string {
@ -41,8 +37,7 @@ func (u *URLTest) DialContext(ctx context.Context, metadata *C.Metadata, opts ..
c, err = u.fast(true).DialContext(ctx, metadata, u.Base.DialOptions(opts...)...)
if err == nil {
c.AppendToChains(u)
u.failedTimes.Store(-1)
u.failedTime.Store(-1)
u.onDialSuccess()
} else {
u.onDialFailed()
}
@ -54,11 +49,8 @@ func (u *URLTest) ListenPacketContext(ctx context.Context, metadata *C.Metadata,
pc, err := u.fast(true).ListenPacketContext(ctx, metadata, u.Base.DialOptions(opts...)...)
if err == nil {
pc.AppendToChains(u)
u.failedTimes.Store(-1)
u.failedTime.Store(-1)
} else {
u.onDialFailed()
}
return pc, err
}
@ -123,32 +115,6 @@ func (u *URLTest) MarshalJSON() ([]byte, error) {
})
}
func (u *URLTest) onDialFailed() {
if u.failedTime.Load() == -1 {
log.Warnln("%s first failed", u.Name())
now := time.Now().UnixMilli()
u.failedTime.Store(now)
u.failedTimes.Store(1)
} else {
if u.failedTime.Load()-time.Now().UnixMilli() > 5*1000 {
u.failedTimes.Store(-1)
u.failedTime.Store(-1)
} else {
failedCount := u.failedTimes.Inc()
log.Warnln("%s failed count: %d", u.Name(), failedCount)
if failedCount >= 5 {
log.Warnln("because %s failed multiple times, active health check", u.Name())
for _, proxyProvider := range u.providers {
go proxyProvider.HealthCheck()
}
u.failedTimes.Store(-1)
u.failedTime.Store(-1)
}
}
}
}
func parseURLTestOption(config map[string]any) []urlTestOption {
opts := []urlTestOption{}
@ -171,13 +137,12 @@ func NewURLTest(option *GroupCommonOption, providers []provider.ProxyProvider, o
Interface: option.Interface,
RoutingMark: option.RoutingMark,
},
option.Filter,
providers,
}),
fastSingle: singledo.NewSingle[C.Proxy](time.Second * 10),
disableUDP: option.DisableUDP,
failedTimes: atomic.NewInt32(-1),
failedTime: atomic.NewInt64(-1),
fastSingle: singledo.NewSingle[C.Proxy](time.Second * 10),
disableUDP: option.DisableUDP,
}
for _, option := range options {

View File

@ -51,3 +51,7 @@ func tcpKeepAlive(c net.Conn) {
_ = tcp.SetKeepAlivePeriod(30 * time.Second)
}
}
type SelectAble interface {
Set(string) error
}

View File

@ -81,6 +81,13 @@ func ParseProxy(mapping map[string]any) (C.Proxy, error) {
break
}
proxy, err = outbound.NewTrojan(*trojanOption)
case "hysteria":
hyOption := &outbound.HysteriaOption{}
err = decoder.Decode(mapping, hyOption)
if err != nil {
break
}
proxy, err = outbound.NewHysteria(*hyOption)
default:
return nil, fmt.Errorf("unsupport proxy type: %s", proxyType)
}

View File

@ -16,61 +16,69 @@ var (
dirMode os.FileMode = 0o755
)
type parser = func([]byte) (any, error)
type parser[V any] func([]byte) (V, error)
type fetcher struct {
type fetcher[V any] struct {
name string
vehicle types.Vehicle
updatedAt *time.Time
ticker *time.Ticker
done chan struct{}
hash [16]byte
parser parser
onUpdate func(any)
parser parser[V]
interval time.Duration
onUpdate func(V)
}
func (f *fetcher) Name() string {
func (f *fetcher[V]) Name() string {
return f.name
}
func (f *fetcher) VehicleType() types.VehicleType {
func (f *fetcher[V]) VehicleType() types.VehicleType {
return f.vehicle.Type()
}
func (f *fetcher) Initial() (any, error) {
func (f *fetcher[V]) Initial() (V, error) {
var (
buf []byte
err error
isLocal bool
)
if stat, fErr := os.Stat(f.vehicle.Path()); fErr == nil {
buf, err = os.ReadFile(f.vehicle.Path())
modTime := stat.ModTime()
f.updatedAt = &modTime
isLocal = true
if f.interval != 0 && modTime.Add(f.interval).Before(time.Now()) {
defer func() {
log.Infoln("[Provider] %s's proxies not updated for a long time, force refresh", f.Name())
go f.Update()
}()
}
} else {
buf, err = f.vehicle.Read()
}
if err != nil {
return nil, err
return getZero[V](), err
}
proxies, err := f.parser(buf)
if err != nil {
if !isLocal {
return nil, err
return getZero[V](), err
}
// parse local file error, fallback to remote
buf, err = f.vehicle.Read()
if err != nil {
return nil, err
return getZero[V](), err
}
proxies, err = f.parser(buf)
if err != nil {
return nil, err
return getZero[V](), err
}
isLocal = false
@ -78,7 +86,7 @@ func (f *fetcher) Initial() (any, error) {
if f.vehicle.Type() != types.File && !isLocal {
if err := safeWrite(f.vehicle.Path(), buf); err != nil {
return nil, err
return getZero[V](), err
}
}
@ -92,10 +100,10 @@ func (f *fetcher) Initial() (any, error) {
return proxies, nil
}
func (f *fetcher) Update() (any, bool, error) {
func (f *fetcher[V]) Update() (V, bool, error) {
buf, err := f.vehicle.Read()
if err != nil {
return nil, false, err
return getZero[V](), false, err
}
now := time.Now()
@ -103,17 +111,17 @@ func (f *fetcher) Update() (any, bool, error) {
if bytes.Equal(f.hash[:], hash[:]) {
f.updatedAt = &now
os.Chtimes(f.vehicle.Path(), now, now)
return nil, true, nil
return getZero[V](), true, nil
}
proxies, err := f.parser(buf)
if err != nil {
return nil, false, err
return getZero[V](), false, err
}
if f.vehicle.Type() != types.File {
if err := safeWrite(f.vehicle.Path(), buf); err != nil {
return nil, false, err
return getZero[V](), false, err
}
}
@ -123,14 +131,14 @@ func (f *fetcher) Update() (any, bool, error) {
return proxies, false, nil
}
func (f *fetcher) Destroy() error {
func (f *fetcher[V]) Destroy() error {
if f.ticker != nil {
f.done <- struct{}{}
}
return nil
}
func (f *fetcher) pullLoop() {
func (f *fetcher[V]) pullLoop() {
for {
select {
case <-f.ticker.C:
@ -168,13 +176,13 @@ 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(any)) *fetcher {
func newFetcher[V any](name string, interval time.Duration, vehicle types.Vehicle, parser parser[V], onUpdate func(V)) *fetcher[V] {
var ticker *time.Ticker
if interval != 0 {
ticker = time.NewTicker(interval)
}
return &fetcher{
return &fetcher[V]{
name: name,
ticker: ticker,
vehicle: vehicle,
@ -183,3 +191,8 @@ func newFetcher(name string, interval time.Duration, vehicle types.Vehicle, pars
onUpdate: onUpdate,
}
}
func getZero[V any]() V {
var result V
return result
}

View File

@ -6,7 +6,6 @@ import (
"github.com/Dreamacro/clash/common/batch"
C "github.com/Dreamacro/clash/constant"
"go.uber.org/atomic"
)
@ -32,9 +31,7 @@ func (hc *HealthCheck) process() {
ticker := time.NewTicker(time.Duration(hc.interval) * time.Second)
go func() {
t := time.NewTicker(30 * time.Second)
<-t.C
t.Stop()
time.Sleep(30 * time.Second)
hc.check()
}()

View File

@ -4,16 +4,16 @@ import (
"encoding/json"
"errors"
"fmt"
"github.com/dlclark/regexp2"
"math"
"runtime"
"time"
"github.com/Dreamacro/clash/adapter"
"github.com/Dreamacro/clash/common/convert"
C "github.com/Dreamacro/clash/constant"
types "github.com/Dreamacro/clash/constant/provider"
"gopkg.in/yaml.v2"
"github.com/dlclark/regexp2"
"gopkg.in/yaml.v3"
)
const (
@ -24,33 +24,32 @@ type ProxySchema struct {
Proxies []map[string]any `yaml:"proxies"`
}
// for auto gc
// ProxySetProvider for auto gc
type ProxySetProvider struct {
*proxySetProvider
}
type proxySetProvider struct {
*fetcher
*fetcher[[]C.Proxy]
proxies []C.Proxy
healthCheck *HealthCheck
version uint
}
func (pp *proxySetProvider) Version() uint {
return pp.version
}
func (pp *proxySetProvider) MarshalJSON() ([]byte, error) {
return json.Marshal(map[string]any{
"name": pp.Name(),
"type": pp.Type().String(),
"vehicleType": pp.VehicleType().String(),
"proxies": pp.Proxies(),
//TODO maybe error because year value overflow
"updatedAt": pp.updatedAt,
"updatedAt": pp.updatedAt,
})
}
func (pp *proxySetProvider) Version() uint {
return pp.version
}
func (pp *proxySetProvider) Name() string {
return pp.name
}
@ -72,12 +71,7 @@ func (pp *proxySetProvider) Initial() error {
if err != nil {
return err
}
pp.onUpdate(elm)
if pp.healthCheck.auto() {
go pp.healthCheck.process()
}
return nil
}
@ -89,52 +83,148 @@ func (pp *proxySetProvider) Proxies() []C.Proxy {
return pp.proxies
}
func (pp *proxySetProvider) ProxiesWithTouch() []C.Proxy {
func (pp *proxySetProvider) Touch() {
pp.healthCheck.touch()
return pp.Proxies()
}
func (pp *proxySetProvider) setProxies(proxies []C.Proxy) {
pp.proxies = proxies
pp.healthCheck.setProxy(proxies)
if pp.healthCheck.auto() {
go pp.healthCheck.check()
defer func() { go pp.healthCheck.check() }()
}
}
func stopProxyProvider(pd *ProxySetProvider) {
pd.healthCheck.close()
pd.fetcher.Destroy()
_ = pd.fetcher.Destroy()
}
func NewProxySetProvider(name string, interval time.Duration, filter string, vehicle types.Vehicle, hc *HealthCheck) (*ProxySetProvider, error) {
//filterReg, err := regexp.Compile(filter)
filterReg, err := regexp2.Compile(filter, 0)
if err != nil {
return nil, fmt.Errorf("invalid filter regex: %w", err)
}
if hc.auto() {
go hc.process()
}
pd := &proxySetProvider{
proxies: []C.Proxy{},
healthCheck: hc,
}
onUpdate := func(elm any) {
ret := elm.([]C.Proxy)
pd.setProxies(ret)
fetcher := newFetcher[[]C.Proxy](name, interval, vehicle, proxiesParseAndFilter(filter, filterReg), proxiesOnUpdate(pd))
pd.fetcher = fetcher
wrapper := &ProxySetProvider{pd}
runtime.SetFinalizer(wrapper, stopProxyProvider)
return wrapper, nil
}
// CompatibleProvider for auto gc
type CompatibleProvider struct {
*compatibleProvider
}
type compatibleProvider struct {
name string
healthCheck *HealthCheck
proxies []C.Proxy
version uint
}
func (cp *compatibleProvider) MarshalJSON() ([]byte, error) {
return json.Marshal(map[string]any{
"name": cp.Name(),
"type": cp.Type().String(),
"vehicleType": cp.VehicleType().String(),
"proxies": cp.Proxies(),
})
}
func (cp *compatibleProvider) Version() uint {
return cp.version
}
func (cp *compatibleProvider) Name() string {
return cp.name
}
func (cp *compatibleProvider) HealthCheck() {
cp.healthCheck.check()
}
func (cp *compatibleProvider) Update() error {
return nil
}
func (cp *compatibleProvider) Initial() error {
return nil
}
func (cp *compatibleProvider) VehicleType() types.VehicleType {
return types.Compatible
}
func (cp *compatibleProvider) Type() types.ProviderType {
return types.Proxy
}
func (cp *compatibleProvider) Proxies() []C.Proxy {
return cp.proxies
}
func (cp *compatibleProvider) Touch() {
cp.healthCheck.touch()
}
func stopCompatibleProvider(pd *CompatibleProvider) {
pd.healthCheck.close()
}
func NewCompatibleProvider(name string, proxies []C.Proxy, hc *HealthCheck) (*CompatibleProvider, error) {
if len(proxies) == 0 {
return nil, errors.New("provider need one proxy at least")
}
if hc.auto() {
go hc.process()
}
pd := &compatibleProvider{
name: name,
proxies: proxies,
healthCheck: hc,
}
wrapper := &CompatibleProvider{pd}
runtime.SetFinalizer(wrapper, stopCompatibleProvider)
return wrapper, nil
}
func proxiesOnUpdate(pd *proxySetProvider) func([]C.Proxy) {
return func(elm []C.Proxy) {
pd.setProxies(elm)
if pd.version == math.MaxUint {
pd.version = 0
} else {
pd.version++
}
}
}
proxiesParseAndFilter := func(buf []byte) (any, error) {
func proxiesParseAndFilter(filter string, filterReg *regexp2.Regexp) parser[[]C.Proxy] {
return func(buf []byte) ([]C.Proxy, error) {
schema := &ProxySchema{}
if err := yaml.Unmarshal(buf, schema); err != nil {
return nil, err
proxies, err1 := convert.ConvertsV2Ray(buf)
if err1 != nil {
return nil, fmt.Errorf("%s, %w", err.Error(), err1)
}
schema.Proxies = proxies
}
if schema.Proxies == nil {
@ -164,93 +254,4 @@ func NewProxySetProvider(name string, interval time.Duration, filter string, veh
return proxies, nil
}
fetcher := newFetcher(name, interval, vehicle, proxiesParseAndFilter, onUpdate)
pd.fetcher = fetcher
wrapper := &ProxySetProvider{pd}
runtime.SetFinalizer(wrapper, stopProxyProvider)
return wrapper, nil
}
// for auto gc
type CompatibleProvider struct {
*compatibleProvider
}
type compatibleProvider struct {
name string
healthCheck *HealthCheck
proxies []C.Proxy
version uint
}
func (cp *compatibleProvider) Version() uint {
return cp.version
}
func (cp *compatibleProvider) MarshalJSON() ([]byte, error) {
return json.Marshal(map[string]any{
"name": cp.Name(),
"type": cp.Type().String(),
"vehicleType": cp.VehicleType().String(),
"proxies": cp.Proxies(),
})
}
func (cp *compatibleProvider) Name() string {
return cp.name
}
func (cp *compatibleProvider) HealthCheck() {
cp.healthCheck.check()
}
func (cp *compatibleProvider) Update() error {
return nil
}
func (cp *compatibleProvider) Initial() error {
if cp.healthCheck.auto() {
go cp.healthCheck.process()
}
return nil
}
func (cp *compatibleProvider) VehicleType() types.VehicleType {
return types.Compatible
}
func (cp *compatibleProvider) Type() types.ProviderType {
return types.Proxy
}
func (cp *compatibleProvider) Proxies() []C.Proxy {
return cp.proxies
}
func (cp *compatibleProvider) ProxiesWithTouch() []C.Proxy {
cp.healthCheck.touch()
return cp.Proxies()
}
func stopCompatibleProvider(pd *CompatibleProvider) {
pd.healthCheck.close()
}
func NewCompatibleProvider(name string, proxies []C.Proxy, hc *HealthCheck) (*CompatibleProvider, error) {
if len(proxies) == 0 {
return nil, errors.New("provider need one proxy at least")
}
pd := &compatibleProvider{
name: name,
proxies: proxies,
healthCheck: hc,
}
wrapper := &CompatibleProvider{pd}
runtime.SetFinalizer(wrapper, stopCompatibleProvider)
return wrapper, nil
}

View File

@ -2,15 +2,12 @@ package provider
import (
"context"
"github.com/Dreamacro/clash/listener/inner"
"io"
"net"
"net/http"
"net/url"
"os"
"time"
netHttp "github.com/Dreamacro/clash/common/net"
netHttp "github.com/Dreamacro/clash/component/http"
types "github.com/Dreamacro/clash/constant/provider"
)
@ -50,52 +47,16 @@ func (h *HTTPVehicle) Path() string {
func (h *HTTPVehicle) Read() ([]byte, error) {
ctx, cancel := context.WithTimeout(context.Background(), time.Second*20)
defer cancel()
uri, err := url.Parse(h.url)
resp, err := netHttp.HttpRequest(ctx, h.url, http.MethodGet, nil, nil)
if err != nil {
return nil, err
}
req, err := http.NewRequest(http.MethodGet, uri.String(), nil)
req.Header.Set("User-Agent", netHttp.UA)
if err != nil {
return nil, err
}
if user := uri.User; user != nil {
password, _ := user.Password()
req.SetBasicAuth(user.Username(), password)
}
req = req.WithContext(ctx)
transport := &http.Transport{
// from http.DefaultTransport
MaxIdleConns: 100,
IdleConnTimeout: 90 * time.Second,
TLSHandshakeTimeout: 10 * time.Second,
ExpectContinueTimeout: 1 * time.Second,
DialContext: func(ctx context.Context, network, address string) (net.Conn, error) {
conn := inner.HandleTcp(address, uri.Hostname())
return conn, nil
},
}
client := http.Client{Transport: transport}
resp, err := client.Do(req)
if err != nil {
if err != nil {
return nil, err
}
}
defer resp.Body.Close()
buf, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}
return buf, nil
}

View File

@ -14,7 +14,6 @@ func ExecCmd(cmdStr string) (string, error) {
cmd = exec.Command(args[0])
} else {
cmd = exec.Command(args[0], args[1:]...)
}
prepareBackgroundCommand(cmd)
out, err := cmd.CombinedOutput()

View File

@ -7,5 +7,4 @@ import (
)
func prepareBackgroundCommand(cmd *exec.Cmd) {
}

450
common/convert/converter.go Normal file
View File

@ -0,0 +1,450 @@
package convert
import (
"bytes"
"encoding/base64"
"encoding/json"
"fmt"
"net/url"
"strconv"
"strings"
)
var enc = base64.StdEncoding
func DecodeBase64(buf []byte) ([]byte, error) {
dBuf := make([]byte, enc.DecodedLen(len(buf)))
n, err := enc.Decode(dBuf, buf)
if err != nil {
return nil, err
}
return dBuf[:n], nil
}
// DecodeBase64StringToString decode base64 string to string
func DecodeBase64StringToString(s string) (string, error) {
dBuf, err := enc.DecodeString(s)
if err != nil {
return "", err
}
return string(dBuf), nil
}
// ConvertsV2Ray convert V2Ray subscribe proxies data to clash proxies config
func ConvertsV2Ray(buf []byte) ([]map[string]any, error) {
data, err := DecodeBase64(buf)
if err != nil {
data = buf
}
arr := strings.Split(string(data), "\n")
proxies := make([]map[string]any, 0, len(arr))
names := make(map[string]int, 200)
for _, line := range arr {
line = strings.TrimRight(line, " \r")
if line == "" {
continue
}
scheme, body, found := strings.Cut(line, "://")
if !found {
continue
}
scheme = strings.ToLower(scheme)
switch scheme {
case "hysteria":
urlHysteria, err := url.Parse(line)
if err != nil {
continue
}
query := urlHysteria.Query()
name := uniqueName(names, urlHysteria.Fragment)
hysteria := make(map[string]any, 20)
hysteria["name"] = name
hysteria["type"] = scheme
hysteria["server"] = urlHysteria.Hostname()
hysteria["port"] = urlHysteria.Port()
hysteria["sni"] = query.Get("peer")
hysteria["obfs"] = query.Get("obfs")
hysteria["alpn"] = query.Get("alpn")
hysteria["auth_str"] = query.Get("auth")
hysteria["protocol"] = query.Get("protocol")
hysteria["down_mbps"], _ = strconv.Atoi(query.Get("downmbps"))
hysteria["up_mbps"], _ = strconv.Atoi(query.Get("upmbps"))
hysteria["skip-cert-verify"], _ = strconv.ParseBool(query.Get("insecure"))
proxies = append(proxies, hysteria)
case "trojan":
urlTrojan, err := url.Parse(line)
if err != nil {
continue
}
query := urlTrojan.Query()
name := uniqueName(names, urlTrojan.Fragment)
trojan := make(map[string]any, 20)
trojan["name"] = name
trojan["type"] = scheme
trojan["server"] = urlTrojan.Hostname()
trojan["port"] = urlTrojan.Port()
trojan["password"] = urlTrojan.User.Username()
trojan["udp"] = true
trojan["skip-cert-verify"] = false
sni := query.Get("sni")
if sni != "" {
trojan["sni"] = sni
}
network := strings.ToLower(query.Get("type"))
if network != "" {
trojan["network"] = network
}
switch network {
case "ws":
headers := make(map[string]any)
wsOpts := make(map[string]any)
// headers["Host"] = RandHost()
headers["User-Agent"] = RandUserAgent()
wsOpts["path"] = query.Get("path")
wsOpts["headers"] = headers
trojan["ws-opts"] = wsOpts
case "grpc":
grpcOpts := make(map[string]any)
grpcOpts["grpc-service-name"] = query.Get("serviceName")
trojan["grpc-opts"] = grpcOpts
}
proxies = append(proxies, trojan)
case "vless":
urlVless, err := url.Parse(line)
if err != nil {
continue
}
query := urlVless.Query()
name := uniqueName(names, urlVless.Fragment)
vless := make(map[string]any, 20)
vless["name"] = name
vless["type"] = scheme
vless["server"] = urlVless.Hostname()
vless["port"] = urlVless.Port()
vless["uuid"] = urlVless.User.Username()
vless["udp"] = true
vless["skip-cert-verify"] = false
sni := query.Get("sni")
if sni != "" {
vless["servername"] = sni
}
flow := strings.ToLower(query.Get("flow"))
if flow != "" {
vless["flow"] = flow
}
network := strings.ToLower(query.Get("type"))
if network != "" {
fakeType := strings.ToLower(query.Get("headerType"))
if network == "tcp" && fakeType == "http" {
network = "http"
}
if network == "http" {
network = "h2"
}
vless["network"] = network
}
switch network {
case "http":
headers := make(map[string]any)
httpOpts := make(map[string]any)
if query.Get("method") != "" {
httpOpts["method"] = query.Get("method")
}
if query.Get("path") != "" {
httpOpts["path"] = query.Get("path")
}
headers["User-Agent"] = RandUserAgent()
httpOpts["headers"] = headers
vless["http-opts"] = httpOpts
case "h2":
headers := make(map[string]any)
h2Opts := make(map[string]any)
headers["User-Agent"] = RandUserAgent()
h2Opts["path"] = query.Get("path")
h2Opts["headers"] = headers
vless["h2-opts"] = h2Opts
case "ws":
headers := make(map[string]any)
wsOpts := make(map[string]any)
// headers["Host"] = RandHost()
headers["User-Agent"] = RandUserAgent()
wsOpts["path"] = query.Get("path")
wsOpts["headers"] = headers
vless["ws-opts"] = wsOpts
case "grpc":
grpcOpts := make(map[string]any)
grpcOpts["grpc-service-name"] = query.Get("serviceName")
vless["grpc-opts"] = grpcOpts
}
proxies = append(proxies, vless)
case "vmess":
dcBuf, err := enc.DecodeString(body)
if err != nil {
continue
}
jsonDc := json.NewDecoder(bytes.NewReader(dcBuf))
values := make(map[string]any, 20)
if jsonDc.Decode(&values) != nil {
continue
}
name := uniqueName(names, values["ps"].(string))
vmess := make(map[string]any, 20)
vmess["name"] = name
vmess["type"] = scheme
vmess["server"] = values["add"]
vmess["port"] = values["port"]
vmess["uuid"] = values["id"]
vmess["alterId"] = values["aid"]
vmess["cipher"] = "auto"
vmess["udp"] = true
vmess["skip-cert-verify"] = false
sni := values["sni"]
if sni != "" {
vmess["sni"] = sni
}
host := values["host"]
network := strings.ToLower(values["net"].(string))
vmess["network"] = network
tls := strings.ToLower(values["tls"].(string))
if tls != "" && tls != "0" && tls != "null" {
if host != nil {
vmess["servername"] = host
}
vmess["tls"] = true
}
switch network {
case "http":
headers := make(map[string]any)
httpOpts := make(map[string]any)
// headers["Host"] = RandHost()
headers["User-Agent"] = RandUserAgent()
httpOpts["method"] = values["method"]
httpOpts["path"] = values["path"]
httpOpts["headers"] = headers
vmess["http-opts"] = httpOpts
case "h2":
headers := make(map[string]any)
h2Opts := make(map[string]any)
// headers["Host"] = RandHost()
headers["User-Agent"] = RandUserAgent()
h2Opts["path"] = values["path"]
h2Opts["headers"] = headers
vmess["h2-opts"] = h2Opts
case "ws":
headers := make(map[string]any)
wsOpts := make(map[string]any)
headers["Host"] = RandHost()
headers["User-Agent"] = RandUserAgent()
if values["path"] != nil {
wsOpts["path"] = values["path"]
}
wsOpts["headers"] = headers
vmess["ws-opts"] = wsOpts
case "grpc":
grpcOpts := make(map[string]any)
grpcOpts["grpc-service-name"] = values["path"]
vmess["grpc-opts"] = grpcOpts
}
proxies = append(proxies, vmess)
case "ss":
urlSS, err := url.Parse(line)
if err != nil {
continue
}
name := uniqueName(names, urlSS.Fragment)
port := urlSS.Port()
if port == "" {
dcBuf, err := enc.DecodeString(urlSS.Host)
if err != nil {
continue
}
urlSS, err = url.Parse("ss://" + string(dcBuf))
if err != nil {
continue
}
}
var (
cipher = urlSS.User.Username()
password string
)
if password, found = urlSS.User.Password(); !found {
dcBuf, err := enc.DecodeString(cipher)
if err != nil {
continue
}
cipher, password, found = strings.Cut(string(dcBuf), ":")
if !found {
continue
}
}
ss := make(map[string]any, 20)
ss["name"] = name
ss["type"] = scheme
ss["server"] = urlSS.Hostname()
ss["port"] = urlSS.Port()
ss["cipher"] = cipher
ss["password"] = password
ss["udp"] = true
proxies = append(proxies, ss)
case "ssr":
dcBuf, err := enc.DecodeString(body)
if err != nil {
continue
}
// ssr://host:port:protocol:method:obfs:urlsafebase64pass/?obfsparam=urlsafebase64&protoparam=&remarks=urlsafebase64&group=urlsafebase64&udpport=0&uot=1
before, after, ok := strings.Cut(string(dcBuf), "/?")
if !ok {
continue
}
beforeArr := strings.Split(before, ":")
if len(beforeArr) != 6 {
continue
}
host := beforeArr[0]
port := beforeArr[1]
protocol := beforeArr[2]
method := beforeArr[3]
obfs := beforeArr[4]
password := decodeUrlSafe(urlSafe(beforeArr[5]))
query, err := url.ParseQuery(urlSafe(after))
if err != nil {
continue
}
remarks := decodeUrlSafe(query.Get("remarks"))
name := uniqueName(names, remarks)
obfsParam := decodeUrlSafe(query.Get("obfsparam"))
protocolParam := query.Get("protoparam")
ssr := make(map[string]any, 20)
ssr["name"] = name
ssr["type"] = scheme
ssr["server"] = host
ssr["port"] = port
ssr["cipher"] = method
ssr["password"] = password
ssr["obfs"] = obfs
ssr["protocol"] = protocol
ssr["udp"] = true
if obfsParam != "" {
ssr["obfs-param"] = obfsParam
}
if protocolParam != "" {
ssr["protocol-param"] = protocolParam
}
proxies = append(proxies, ssr)
}
}
if len(proxies) == 0 {
return nil, fmt.Errorf("convert v2ray subscribe error: format invalid")
}
return proxies, nil
}
func urlSafe(data string) string {
return strings.ReplaceAll(strings.ReplaceAll(data, "+", "-"), "/", "_")
}
func decodeUrlSafe(data string) string {
dcBuf, err := base64.URLEncoding.DecodeString(data)
if err != nil {
return ""
}
return string(dcBuf)
}
func uniqueName(names map[string]int, name string) string {
if index, ok := names[name]; ok {
index++
names[name] = index
name = fmt.Sprintf("%s-%02d", name, index)
} else {
index = 0
names[name] = index
}
return name
}

316
common/convert/util.go Normal file
View File

@ -0,0 +1,316 @@
package convert
import (
"encoding/base64"
"math/rand"
"net/http"
"strings"
"github.com/gofrs/uuid"
)
var hostsSuffix = []string{
"-cdn.aliyuncs.com",
".alicdn.com",
".pan.baidu.com",
".tbcache.com",
".aliyuncdn.com",
".vod.miguvideo.com",
".cibntv.net",
".myqcloud.com",
".smtcdns.com",
".alikunlun.com",
".smtcdns.net",
".apcdns.net",
".cdn-go.cn",
".cdntip.com",
".cdntips.com",
".alidayu.com",
".alidns.com",
".cdngslb.com",
".mxhichina.com",
".alibabadns.com",
}
var userAgents = []string{
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.162 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.85 Safari/537.36",
"Mozilla/5.0 (Linux; Android 7.0; Moto C Build/NRD90M.059) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36",
"Mozilla/5.0 (Linux; Android 6.0.1; SM-G532M Build/MMB29T; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/55.0.2883.91 Mobile Safari/537.36",
"Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.80 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.101 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/40.0.2214.111 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36",
"Mozilla/5.0 (Linux; Android 5.1.1; SM-J120M Build/LMY47X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36",
"Mozilla/5.0 (Windows NT 6.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.80 Safari/537.36",
"Mozilla/5.0 (Linux; Android 7.0; Moto G (5) Build/NPPS25.137-93-14) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36",
"Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.106 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36",
"Mozilla/5.0 (Linux; Android 7.0; SM-G570M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.80 Mobile Safari/537.36",
"Mozilla/5.0 (Windows NT 5.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.80 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.112 Safari/537.36",
"Mozilla/5.0 (Linux; Android 6.0; CAM-L03 Build/HUAWEICAM-L03) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36",
"Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.76 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.117 Safari/537.36",
"Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/534.3 (KHTML, like Gecko) Chrome/6.0.472.63 Safari/534.3",
"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.106 Safari/537.36",
"Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.7 (KHTML, like Gecko) Chrome/7.0.517.44 Safari/534.7",
"Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.75 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.71 Safari/537.36",
"Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.3 (KHTML, like Gecko) Chrome/6.0.472.63 Safari/534.3",
"Mozilla/5.0 (Linux; Android 8.0.0; FIG-LX3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.80 Mobile Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/40.0.2214.115 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36",
"Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.237 Safari/534.10",
"Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36",
"Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/533.2 (KHTML, like Gecko) Chrome/5.0.342.1 Safari/533.2",
"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.110 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.89 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.81 Safari/537.36",
"Mozilla/5.0 (X11; Datanyze; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.71 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.153 Safari/537.36",
"Mozilla/5.0 (Linux; Android 5.1.1; SM-J111M Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.106 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2062.120 Safari/537.36",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1700.107 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36",
"Mozilla/5.0 (Linux; Android 6.0.1; SM-J700M Build/MMB29K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36",
"Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.63 Safari/537.36",
"Mozilla/5.0 (X11; Linux i686) AppleWebKit/534.30 (KHTML, like Gecko) Slackware/Chrome/12.0.742.100 Safari/534.30",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.86 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.167 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.116 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36",
"Mozilla/5.0 (X11; Linux i686) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.100 Safari/534.30",
"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36",
"Mozilla/5.0 (Linux; Android 8.0.0; WAS-LX3 Build/HUAWEIWAS-LX3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.87 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.57 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.101 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.1805 Safari/537.36 MVisionPlayer/1.0.0.0",
"Mozilla/5.0 (Linux; Android 7.0; TRT-LX3 Build/HUAWEITRT-LX3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.89 Safari/537.36",
"Mozilla/5.0 (Linux; Android 6.0; vivo 1610 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.124 Mobile Safari/537.36",
"Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.111 Safari/537.36",
"Mozilla/5.0 (Linux; Android 4.4.2; de-de; SAMSUNG GT-I9195 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Version/1.5 Chrome/28.0.1500.94 Mobile Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.90 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.110 Safari/537.36",
"Mozilla/5.0 (Linux; Android 8.0.0; ANE-LX3 Build/HUAWEIANE-LX3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.112 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.87 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36",
"Mozilla/5.0 (X11; U; Linux i586; en-US) AppleWebKit/533.2 (KHTML, like Gecko) Chrome/5.0.342.1 Safari/533.2",
"Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.65 Safari/537.36",
"Mozilla/5.0 (Linux; Android 7.0; SM-G610M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.80 Mobile Safari/537.36",
"Mozilla/5.0 (Linux; Android 6.0.1; SM-J500M Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36",
"Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/534.7 (KHTML, like Gecko) Chrome/7.0.517.44 Safari/534.7",
"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.104 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36",
"Mozilla/5.0 (Linux; Android 6.0; vivo 1606 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.124 Mobile Safari/537.36",
"Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36",
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.135 Safari/537.36",
"Mozilla/5.0 (Linux; Android 7.0; SM-G610M Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36",
"Mozilla/5.0 (Linux; Android 7.1; vivo 1716 Build/N2G47H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.98 Mobile Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.93 Safari/537.36",
"Mozilla/5.0 (Linux; Android 7.0; SM-G570M Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36",
"Mozilla/5.0 (Windows NT 6.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36",
"Mozilla/5.0 (Linux; Android 6.0; MYA-L22 Build/HUAWEIMYA-L22) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36",
"Mozilla/5.0 (Linux; Android 5.1; A1601 Build/LMY47I) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.98 Mobile Safari/537.36",
"Mozilla/5.0 (Linux; Android 7.0; TRT-LX2 Build/HUAWEITRT-LX2; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/59.0.3071.125 Mobile Safari/537.36",
"Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36",
"Mozilla/5.0 (Windows NT 5.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36",
"Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.17 (KHTML, like Gecko) Chrome/10.0.649.0 Safari/534.17",
"Mozilla/5.0 (Linux; Android 6.0; CAM-L21 Build/HUAWEICAM-L21; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/62.0.3202.84 Mobile Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36",
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.3 Safari/534.24",
"Mozilla/5.0 (Linux; Android 7.1.2; Redmi 4X Build/N2G47H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36",
"Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.106 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36",
"Mozilla/5.0 (Linux; Android 4.4.2; SM-G7102 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36",
"Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.109 Safari/537.36",
"Mozilla/5.0 (Linux; Android 5.1; HUAWEI CUN-L22 Build/HUAWEICUN-L22; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/62.0.3202.84 Mobile Safari/537.36",
"Mozilla/5.0 (Linux; Android 5.1.1; A37fw Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36",
"Mozilla/5.0 (Linux; Android 7.0; SM-J730GM Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36",
"Mozilla/5.0 (Linux; Android 7.0; SM-G610F Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36",
"Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.101 Safari/537.36",
"Mozilla/5.0 (Linux; Android 7.1.2; Redmi Note 5A Build/N2G47H; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.111 Mobile Safari/537.36",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36",
"Mozilla/5.0 (Linux; Android 7.0; Redmi Note 4 Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.106 Safari/537.36",
"Mozilla/5.0 (Unknown; Linux) AppleWebKit/538.1 (KHTML, like Gecko) Chrome/v1.0.0 Safari/538.1",
"Mozilla/5.0 (Linux; Android 7.0; BLL-L22 Build/HUAWEIBLL-L22) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36",
"Mozilla/5.0 (Linux; Android 7.0; SM-J710F Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36",
"Mozilla/5.0 (Linux; Android 6.0.1; SM-G532M Build/MMB29T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36",
"Mozilla/5.0 (Linux; Android 7.1.1; CPH1723 Build/N6F26Q) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.98 Mobile Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.118 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.79 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.101 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.94 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.139 Safari/537.36",
"Mozilla/5.0 (Linux; Android 8.0.0; FIG-LX3 Build/HUAWEIFIG-LX3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36",
"Mozilla/5.0 (Windows; U; Windows NT 6.1; de-DE) AppleWebKit/534.17 (KHTML, like Gecko) Chrome/10.0.649.0 Safari/534.17",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.63 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.67 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.67 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.67 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.67 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.65 Safari/537.36",
"Mozilla/5.0 (Linux; Android 7.1; Mi A1 Build/N2G47H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.117 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36",
"Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/533.4 (KHTML, like Gecko) Chrome/5.0.375.99 Safari/533.4",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.125 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.89 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.111 Safari/537.36 MVisionPlayer/1.0.0.0",
"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36",
"Mozilla/5.0 (Linux; Android 5.1; A37f Build/LMY47V) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.93 Mobile Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.86 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.76 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36",
"Mozilla/5.0 (Windows NT 5.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.80 Safari/537.36",
"Mozilla/5.0 (Linux; Android 6.0.1; CPH1607 Build/MMB29M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/63.0.3239.111 Mobile Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36",
"Mozilla/5.0 (Linux; Android 6.0.1; vivo 1603 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.83 Mobile Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 Safari/537.36",
"Mozilla/5.0 (Linux; Android 6.0.1; SM-G532M Build/MMB29T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36",
"Mozilla/5.0 (Linux; Android 6.0.1; Redmi 4A Build/MMB29M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/60.0.3112.116 Mobile Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.112 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36",
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.157 Safari/537.36",
"Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.71 Safari/537.36",
"Mozilla/5.0 (Windows NT 5.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.90 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.64 Safari/537.31",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.80 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.143 Safari/537.36",
"Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.112 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.67 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.106 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36",
"Mozilla/5.0 (Linux; Android 6.0.1; SM-G532G Build/MMB29T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.83 Mobile Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.109 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.117 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.139 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.67 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.131 Safari/537.36",
"Mozilla/5.0 (Linux; Android 6.0; vivo 1713 Build/MRA58K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.124 Mobile Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.89 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.80 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.101 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.67 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36",
}
var (
hostsLen = len(hostsSuffix)
uaLen = len(userAgents)
)
func RandHost() string {
id, _ := uuid.NewV4()
base := strings.ToLower(base64.RawURLEncoding.EncodeToString(id.Bytes()))
base = strings.ReplaceAll(base, "-", "")
base = strings.ReplaceAll(base, "_", "")
buf := []byte(base)
prefix := string(buf[:3]) + "---"
prefix += string(buf[6:8]) + "-"
prefix += string(buf[len(buf)-8:])
return prefix + hostsSuffix[rand.Intn(hostsLen)]
}
func RandUserAgent() string {
return userAgents[rand.Intn(uaLen)]
}
func SetUserAgent(header http.Header) {
if header.Get("User-Agent") != "" {
return
}
userAgent := RandUserAgent()
header.Set("User-Agent", userAgent)
}

View File

@ -1,5 +0,0 @@
package net
const (
UA = "Clash"
)

View File

@ -6,10 +6,16 @@ import (
"errors"
"math/bits"
"sync"
"github.com/sagernet/sing/common/buf"
)
var defaultAllocator = NewAllocator()
func init() {
buf.DefaultAllocator = defaultAllocator
}
// Allocator for incoming frames, optimized to prevent overwriting after zeroing
type Allocator struct {
buffers []sync.Pool
@ -52,8 +58,8 @@ func (alloc *Allocator) Put(buf []byte) error {
return errors.New("allocator Put() incorrect buffer size")
}
//lint:ignore SA6002 ignore temporarily
//nolint
//lint:ignore SA6002 ignore temporarily
alloc.buffers[bits].Put(buf)
return nil
}

View File

@ -25,7 +25,6 @@ type Result[T any] struct {
}
// Do single.Do likes sync.singleFlight
//lint:ignore ST1008 it likes sync.singleFlight
func (s *Single[T]) Do(fn func() (T, error)) (v T, err error, shared bool) {
s.mux.Lock()
now := time.Now()

View File

@ -159,9 +159,19 @@ func (d *Decoder) decodeSlice(name string, data any, val reflect.Value) error {
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
}

16
common/utils/uuid.go Normal file
View File

@ -0,0 +1,16 @@
package utils
import (
"github.com/gofrs/uuid"
)
var uuidNamespace, _ = uuid.FromString("00000000-0000-0000-0000-000000000000")
// UUIDMap https://github.com/XTLS/Xray-core/issues/158#issue-783294090
func UUIDMap(str string) (uuid.UUID, error) {
u, err := uuid.FromString(str)
if err != nil {
return uuid.NewV5(uuidNamespace, str), nil
}
return u, nil
}

75
common/utils/uuid_test.go Normal file
View File

@ -0,0 +1,75 @@
package utils
import (
"reflect"
"testing"
"github.com/gofrs/uuid"
)
func TestUUIDMap(t *testing.T) {
type args struct {
str string
}
tests := []struct {
name string
args args
want uuid.UUID
wantErr bool
}{
{
name: "uuid-test-1",
args: args{
str: "82410302-039e-41b6-98b0-d964084b4170",
},
want: uuid.FromStringOrNil("82410302-039e-41b6-98b0-d964084b4170"),
wantErr: false,
},
{
name: "uuid-test-2",
args: args{
str: "88c502e6-d7eb-4c8e-8259-94cb13d83c77",
},
want: uuid.FromStringOrNil("88c502e6-d7eb-4c8e-8259-94cb13d83c77"),
wantErr: false,
},
{
name: "uuid-map-1",
args: args{
str: "123456",
},
want: uuid.FromStringOrNil("f8598425-92f2-5508-a071-4fc67f9040ac"),
wantErr: false,
},
// GENERATED BY 'xray uuid -i'
{
name: "uuid-map-2",
args: args{
str: "a9dk23bz0",
},
want: uuid.FromStringOrNil("c91481b6-fc0f-5d9e-b166-5ddf07b9c3c5"),
wantErr: false,
},
{
name: "uuid-map-2",
args: args{
str: "中文123",
},
want: uuid.FromStringOrNil("145c544c-2229-59e5-8dbb-3f33b7610d26"),
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := UUIDMap(tt.args.str)
if (err != nil) != tt.wantErr {
t.Errorf("UUIDMap() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("UUIDMap() got = %v, want %v", got, tt.want)
}
})
}
}

View File

@ -8,7 +8,6 @@ import (
"github.com/Dreamacro/clash/common/nnip"
"github.com/Dreamacro/clash/component/iface"
"github.com/insomniacslk/dhcp/dhcpv4"
)

View File

@ -6,7 +6,6 @@ import (
"syscall"
"github.com/Dreamacro/clash/component/iface"
"golang.org/x/sys/unix"
)

View File

@ -15,6 +15,7 @@ var (
dialMux sync.Mutex
actualSingleDialContext = singleDialContext
actualDualStackDialContext = dualStackDialContext
tcpConcurrent = false
DisableIPv6 = false
)
@ -76,17 +77,22 @@ func ListenPacket(ctx context.Context, network, address string, options ...Optio
func SetDial(concurrent bool) {
dialMux.Lock()
tcpConcurrent = concurrent
if concurrent {
actualSingleDialContext = concurrentSingleDialContext
actualDualStackDialContext = concurrentDualStackDialContext
} else {
actualSingleDialContext = singleDialContext
actualDualStackDialContext = concurrentDualStackDialContext
actualDualStackDialContext = dualStackDialContext
}
dialMux.Unlock()
}
func GetDial() bool {
return tcpConcurrent
}
func dialContext(ctx context.Context, network string, destination netip.Addr, port string, opt *option) (net.Conn, error) {
dialer := &net.Dialer{}
if opt.interfaceName != "" {
@ -253,7 +259,7 @@ func concurrentDialContext(ctx context.Context, network string, ips []netip.Addr
}
}
return nil, errors.New("all ip tcp shake hands failed")
return nil, fmt.Errorf("all ips %v tcp shake hands failed", ips)
}
func singleDialContext(ctx context.Context, network string, address string, opt *option) (net.Conn, error) {

View File

@ -9,7 +9,6 @@ import (
"github.com/Dreamacro/clash/component/profile/cachefile"
"github.com/Dreamacro/clash/component/trie"
"github.com/stretchr/testify/assert"
"go.etcd.io/bbolt"
)

View File

@ -3,10 +3,10 @@ package geodata
import (
"errors"
"fmt"
C "github.com/Dreamacro/clash/constant"
"strings"
"github.com/Dreamacro/clash/component/geodata/router"
C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/log"
)
@ -30,7 +30,7 @@ func (l *loader) LoadGeoSiteWithAttr(file string, siteWithAttr string) ([]*route
return nil, fmt.Errorf("empty listname in rule: %s", siteWithAttr)
}
domains, err := l.LoadSite(file, list)
domains, err := l.LoadSiteByPath(file, list)
if err != nil {
return nil, err
}
@ -59,7 +59,7 @@ func (l *loader) LoadGeoSiteWithAttr(file string, siteWithAttr string) ([]*route
}
func (l *loader) LoadGeoIP(country string) ([]*router.CIDR, error) {
return l.LoadIP(C.GeoipName, country)
return l.LoadIPByPath(C.GeoipName, country)
}
var loaders map[string]func() LoaderImplementation

View File

@ -5,8 +5,10 @@ import (
)
type LoaderImplementation interface {
LoadSite(filename, list string) ([]*router.Domain, error)
LoadIP(filename, country string) ([]*router.CIDR, error)
LoadSiteByPath(filename, list string) ([]*router.Domain, error)
LoadSiteByBytes(geositeBytes []byte, list string) ([]*router.Domain, error)
LoadIPByPath(filename, country string) ([]*router.CIDR, error)
LoadIPByBytes(geoipBytes []byte, country string) ([]*router.CIDR, error)
}
type Loader interface {

View File

@ -1,6 +1,7 @@
package memconservative
import (
"errors"
"fmt"
"runtime"
@ -13,7 +14,7 @@ type memConservativeLoader struct {
geositecache GeoSiteCache
}
func (m *memConservativeLoader) LoadIP(filename, country string) ([]*router.CIDR, error) {
func (m *memConservativeLoader) LoadIPByPath(filename, country string) ([]*router.CIDR, error) {
defer runtime.GC()
geoip, err := m.geoipcache.Unmarshal(filename, country)
if err != nil {
@ -22,7 +23,11 @@ func (m *memConservativeLoader) LoadIP(filename, country string) ([]*router.CIDR
return geoip.Cidr, nil
}
func (m *memConservativeLoader) LoadSite(filename, list string) ([]*router.Domain, error) {
func (m *memConservativeLoader) LoadIPByBytes(geoipBytes []byte, country string) ([]*router.CIDR, error) {
return nil, errors.New("memConservative do not support LoadIPByBytes")
}
func (m *memConservativeLoader) LoadSiteByPath(filename, list string) ([]*router.Domain, error) {
defer runtime.GC()
geosite, err := m.geositecache.Unmarshal(filename, list)
if err != nil {
@ -31,6 +36,10 @@ func (m *memConservativeLoader) LoadSite(filename, list string) ([]*router.Domai
return geosite.Domain, nil
}
func (m *memConservativeLoader) LoadSiteByBytes(geositeBytes []byte, list string) ([]*router.Domain, error) {
return nil, errors.New("memConservative do not support LoadSiteByBytes")
}
func newMemConservativeLoader() geodata.LoaderImplementation {
return &memConservativeLoader{make(map[string]*router.GeoIP), make(map[string]*router.GeoSite)}
}

View File

@ -33,9 +33,10 @@ func domainToMatcher(domain *Domain) (strmatcher.Matcher, error) {
type DomainMatcher struct {
matchers strmatcher.IndexMatcher
not bool
}
func NewMphMatcherGroup(domains []*Domain) (*DomainMatcher, error) {
func NewMphMatcherGroup(domains []*Domain, not bool) (*DomainMatcher, error) {
g := strmatcher.NewMphMatcherGroup()
for _, d := range domains {
matcherType, f := matcherTypeMap[d.Type]
@ -50,11 +51,12 @@ func NewMphMatcherGroup(domains []*Domain) (*DomainMatcher, error) {
g.Build()
return &DomainMatcher{
matchers: g,
not: not,
}, nil
}
// NewDomainMatcher new domain matcher.
func NewDomainMatcher(domains []*Domain) (*DomainMatcher, error) {
func NewDomainMatcher(domains []*Domain, not bool) (*DomainMatcher, error) {
g := new(strmatcher.MatcherGroup)
for _, d := range domains {
m, err := domainToMatcher(d)
@ -66,11 +68,16 @@ func NewDomainMatcher(domains []*Domain) (*DomainMatcher, error) {
return &DomainMatcher{
matchers: g,
not: not,
}, nil
}
func (m *DomainMatcher) ApplyDomain(domain string) bool {
return len(m.matchers.Match(strings.ToLower(domain))) > 0
isMatched := len(m.matchers.Match(strings.ToLower(domain))) > 0
if m.not {
isMatched = !isMatched
}
return isMatched
}
// CIDRList is an alias of []*CIDR to provide sort.Interface.
@ -322,7 +329,6 @@ func NewGeoIPMatcher(geoip *GeoIP) (*GeoIPMatcher, error) {
}
func (m *MultiGeoIPMatcher) ApplyIp(ip net.IP) bool {
for _, matcher := range m.matchers {
if matcher.Match(ip) {
return true

View File

@ -7,10 +7,11 @@
package router
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
)
const (

View File

@ -9,7 +9,6 @@ import (
"github.com/Dreamacro/clash/component/geodata"
"github.com/Dreamacro/clash/component/geodata/router"
C "github.com/Dreamacro/clash/constant"
"google.golang.org/protobuf/proto"
)
@ -29,11 +28,7 @@ func ReadAsset(file string) ([]byte, error) {
return ReadFile(C.Path.GetAssetLocation(file))
}
func loadIP(filename, country string) ([]*router.CIDR, error) {
geoipBytes, err := ReadAsset(filename)
if err != nil {
return nil, fmt.Errorf("failed to open file: %s, base error: %s", filename, err.Error())
}
func loadIP(geoipBytes []byte, country string) ([]*router.CIDR, error) {
var geoipList router.GeoIPList
if err := proto.Unmarshal(geoipBytes, &geoipList); err != nil {
return nil, err
@ -45,14 +40,10 @@ func loadIP(filename, country string) ([]*router.CIDR, error) {
}
}
return nil, fmt.Errorf("country not found in %s%s%s", filename, ": ", country)
return nil, fmt.Errorf("country %s not found", country)
}
func loadSite(filename, list string) ([]*router.Domain, error) {
geositeBytes, err := ReadAsset(filename)
if err != nil {
return nil, fmt.Errorf("failed to open file: %s, base error: %s", filename, err.Error())
}
func loadSite(geositeBytes []byte, list string) ([]*router.Domain, error) {
var geositeList router.GeoSiteList
if err := proto.Unmarshal(geositeBytes, &geositeList); err != nil {
return nil, err
@ -64,17 +55,33 @@ func loadSite(filename, list string) ([]*router.Domain, error) {
}
}
return nil, fmt.Errorf("list not found in %s%s%s", filename, ": ", list)
return nil, fmt.Errorf("list %s not found", list)
}
type standardLoader struct{}
func (d standardLoader) LoadSite(filename, list string) ([]*router.Domain, error) {
return loadSite(filename, list)
func (d standardLoader) LoadSiteByPath(filename, list string) ([]*router.Domain, error) {
geositeBytes, err := ReadAsset(filename)
if err != nil {
return nil, fmt.Errorf("failed to open file: %s, base error: %s", filename, err.Error())
}
return loadSite(geositeBytes, list)
}
func (d standardLoader) LoadIP(filename, country string) ([]*router.CIDR, error) {
return loadIP(filename, country)
func (d standardLoader) LoadSiteByBytes(geositeBytes []byte, list string) ([]*router.Domain, error) {
return loadSite(geositeBytes, list)
}
func (d standardLoader) LoadIPByPath(filename, country string) ([]*router.CIDR, error) {
geoipBytes, err := ReadAsset(filename)
if err != nil {
return nil, fmt.Errorf("failed to open file: %s, base error: %s", filename, err.Error())
}
return loadIP(geoipBytes, country)
}
func (d standardLoader) LoadIPByBytes(geoipBytes []byte, country string) ([]*router.CIDR, error) {
return loadIP(geoipBytes, country)
}
func init() {

View File

@ -1,9 +1,10 @@
package geodata
import (
"fmt"
"github.com/Dreamacro/clash/component/geodata/router"
C "github.com/Dreamacro/clash/constant"
"strings"
)
var geoLoaderName = "memconservative"
@ -21,20 +22,30 @@ func SetLoader(newLoader string) {
geoLoaderName = newLoader
}
func Verify(name string) bool {
func Verify(name string) error {
switch name {
case C.GeositeName:
_, _, err := LoadGeoSiteMatcher("CN")
return err == nil
return err
case C.GeoipName:
_, _, err := LoadGeoIPMatcher("CN")
return err == nil
return err
default:
return false
return fmt.Errorf("not support name")
}
}
func LoadGeoSiteMatcher(countryCode string) (*router.DomainMatcher, int, error) {
if len(countryCode) == 0 {
return nil, 0, fmt.Errorf("country code could not be empty")
}
not := false
if countryCode[0] == '!' {
not = true
countryCode = countryCode[1:]
}
geoLoader, err := GetGeoDataLoader(geoLoaderName)
if err != nil {
return nil, 0, err
@ -50,7 +61,7 @@ func LoadGeoSiteMatcher(countryCode string) (*router.DomainMatcher, int, error)
matcher, err := router.NewDomainMatcher(domains)
mphminimal perfect hash algorithm
*/
matcher, err := router.NewMphMatcherGroup(domains)
matcher, err := router.NewMphMatcherGroup(domains, not)
if err != nil {
return nil, 0, err
}
@ -59,12 +70,21 @@ func LoadGeoSiteMatcher(countryCode string) (*router.DomainMatcher, int, error)
}
func LoadGeoIPMatcher(country string) (*router.GeoIPMatcher, int, error) {
if len(country) == 0 {
return nil, 0, fmt.Errorf("country code could not be empty")
}
geoLoader, err := GetGeoDataLoader(geoLoaderName)
if err != nil {
return nil, 0, err
}
records, err := geoLoader.LoadGeoIP(strings.ReplaceAll(country, "!", ""))
not := false
if country[0] == '!' {
not = true
country = country[1:]
}
records, err := geoLoader.LoadGeoIP(country)
if err != nil {
return nil, 0, err
}
@ -72,7 +92,7 @@ func LoadGeoIPMatcher(country string) (*router.GeoIPMatcher, int, error) {
geoIP := &router.GeoIP{
CountryCode: country,
Cidr: records,
ReverseMatch: strings.Contains(country, "!"),
ReverseMatch: not,
}
matcher, err := router.NewGeoIPMatcher(geoIP)

64
component/http/http.go Normal file
View File

@ -0,0 +1,64 @@
package http
import (
"context"
"io"
"net"
"net/http"
URL "net/url"
"strings"
"time"
"github.com/Dreamacro/clash/listener/inner"
"github.com/Dreamacro/clash/log"
)
const (
UA = "Clash"
)
func HttpRequest(ctx context.Context, url, method string, header map[string][]string, body io.Reader) (*http.Response, error) {
method = strings.ToUpper(method)
urlRes, err := URL.Parse(url)
if err != nil {
return nil, err
}
req, err := http.NewRequest(method, urlRes.String(), body)
for k, v := range header {
for _, v := range v {
req.Header.Add(k, v)
}
}
if _, ok := header["User-Agent"]; !ok {
req.Header.Set("User-Agent", UA)
}
if err != nil {
return nil, err
}
if user := urlRes.User; user != nil {
password, _ := user.Password()
req.SetBasicAuth(user.Username(), password)
}
req = req.WithContext(ctx)
transport := &http.Transport{
// from http.DefaultTransport
MaxIdleConns: 100,
IdleConnTimeout: 30 * time.Second,
TLSHandshakeTimeout: 10 * time.Second,
ExpectContinueTimeout: 1 * time.Second,
DialContext: func(ctx context.Context, network, address string) (net.Conn, error) {
log.Infoln(urlRes.String())
conn := inner.HandleTcp(address, urlRes.Hostname())
return conn, nil
},
}
client := http.Client{Transport: transport}
return client.Do(req)
}

View File

@ -1,11 +1,11 @@
package mmdb
import (
"github.com/oschwald/geoip2-golang"
"sync"
C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/log"
"github.com/oschwald/geoip2-golang"
)
var (

View File

@ -2,17 +2,19 @@ package process
import (
"errors"
"github.com/Dreamacro/clash/common/nnip"
C "github.com/Dreamacro/clash/constant"
"net"
"net/netip"
"runtime"
"github.com/Dreamacro/clash/common/nnip"
C "github.com/Dreamacro/clash/constant"
)
var (
ErrInvalidNetwork = errors.New("invalid network")
ErrPlatformNotSupport = errors.New("not support on this platform")
ErrNotFound = errors.New("process not found")
enableFindProcess = true
)
const (
@ -20,7 +22,11 @@ const (
UDP = "udp"
)
func FindProcessName(network string, srcIP netip.Addr, srcPort int) (string, error) {
func EnableFindProcess(e bool) {
enableFindProcess = e
}
func FindProcessName(network string, srcIP netip.Addr, srcPort int) (int32, string, error) {
return findProcessName(network, srcIP, srcPort)
}
@ -33,10 +39,9 @@ func FindUid(network string, srcIP netip.Addr, srcPort int) (int32, error) {
}
func ShouldFindProcess(metadata *C.Metadata) bool {
if runtime.GOOS == "android" {
return false
}
if metadata.Process != "" || metadata.ProcessPath != "" {
if !enableFindProcess ||
metadata.Process != "" ||
metadata.ProcessPath != "" {
return false
}
for _, ip := range localIPs {

View File

@ -7,7 +7,6 @@ import (
"unsafe"
"github.com/Dreamacro/clash/common/nnip"
"golang.org/x/sys/unix"
)
@ -21,7 +20,7 @@ func resolveSocketByNetlink(network string, ip netip.Addr, srcPort int) (int32,
return 0, 0, ErrPlatformNotSupport
}
func findProcessName(network string, ip netip.Addr, port int) (string, error) {
func findProcessName(network string, ip netip.Addr, port int) (int32, string, error) {
var spath string
switch network {
case TCP:
@ -29,14 +28,14 @@ func findProcessName(network string, ip netip.Addr, port int) (string, error) {
case UDP:
spath = "net.inet.udp.pcblist_n"
default:
return "", ErrInvalidNetwork
return -1, "", ErrInvalidNetwork
}
isIPv4 := ip.Is4()
value, err := syscall.Sysctl(spath)
if err != nil {
return "", err
return -1, "", err
}
buf := []byte(value)
@ -81,10 +80,11 @@ func findProcessName(network string, ip netip.Addr, port int) (string, error) {
// xsocket_n.so_last_pid
pid := readNativeUint32(buf[so+68 : so+72])
return getExecPathFromPID(pid)
pp, err := getExecPathFromPID(pid)
return -1, pp, err
}
return "", ErrNotFound
return -1, "", ErrNotFound
}
func getExecPathFromPID(pid uint32) (string, error) {

View File

@ -25,7 +25,7 @@ func resolveSocketByNetlink(network string, ip netip.Addr, srcPort int) (int32,
return 0, 0, ErrPlatformNotSupport
}
func findProcessName(network string, ip netip.Addr, srcPort int) (string, error) {
func findProcessName(network string, ip netip.Addr, srcPort int) (int32, string, error) {
once.Do(func() {
if err := initSearcher(); err != nil {
log.Errorln("Initialize PROCESS-NAME failed: %s", err.Error())
@ -35,7 +35,7 @@ func findProcessName(network string, ip netip.Addr, srcPort int) (string, error)
})
if defaultSearcher == nil {
return "", ErrPlatformNotSupport
return -1, "", ErrPlatformNotSupport
}
var spath string
@ -46,21 +46,22 @@ func findProcessName(network string, ip netip.Addr, srcPort int) (string, error)
case UDP:
spath = "net.inet.udp.pcblist"
default:
return "", ErrInvalidNetwork
return -1, "", ErrInvalidNetwork
}
value, err := syscall.Sysctl(spath)
if err != nil {
return "", err
return -1, "", err
}
buf := []byte(value)
pid, err := defaultSearcher.Search(buf, ip, uint16(srcPort), isTCP)
if err != nil {
return "", err
return -1, "", err
}
return getExecPathFromPID(pid)
pp, err := getExecPathFromPID(pid)
return -1, pp, err
}
func getExecPathFromPID(pid uint32) (string, error) {

View File

@ -8,6 +8,8 @@ import (
"net/netip"
"os"
"path"
"path/filepath"
"runtime"
"strings"
"syscall"
"unicode"
@ -32,12 +34,13 @@ const (
pathProc = "/proc"
)
func findProcessName(network string, ip netip.Addr, srcPort int) (string, error) {
func findProcessName(network string, ip netip.Addr, srcPort int) (int32, string, error) {
inode, uid, err := resolveSocketByNetlink(network, ip, srcPort)
if err != nil {
return "", err
return -1, "", err
}
return resolveProcessNameByProcSearch(inode, uid)
pp, err := resolveProcessNameByProcSearch(inode, uid)
return uid, pp, err
}
func resolveSocketByNetlink(network string, ip netip.Addr, srcPort int) (int32, int32, error) {
@ -195,8 +198,19 @@ func resolveProcessNameByProcSearch(inode, uid int32) (string, error) {
continue
}
if bytes.Equal(buffer[:n], socket) {
return os.Readlink(path.Join(processPath, "exe"))
if runtime.GOOS == "android" {
if bytes.Equal(buffer[:n], socket) {
cmdline, err := os.ReadFile(path.Join(processPath, "cmdline"))
if err != nil {
return "", err
}
return splitCmdline(cmdline), nil
}
} else {
if bytes.Equal(buffer[:n], socket) {
return os.Readlink(path.Join(processPath, "exe"))
}
}
}
}
@ -204,6 +218,19 @@ func resolveProcessNameByProcSearch(inode, uid int32) (string, error) {
return "", fmt.Errorf("process of uid(%d),inode(%d) not found", uid, inode)
}
func splitCmdline(cmdline []byte) string {
cmdline = bytes.Trim(cmdline, " ")
idx := bytes.IndexFunc(cmdline, func(r rune) bool {
return unicode.IsControl(r) || unicode.IsSpace(r)
})
if idx == -1 {
return filepath.Base(string(cmdline))
}
return filepath.Base(string(cmdline[:idx]))
}
func isPid(s string) bool {
return strings.IndexFunc(s, func(r rune) bool {
return !unicode.IsDigit(r)

View File

@ -4,8 +4,8 @@ package process
import "net/netip"
func findProcessName(network string, ip netip.Addr, srcPort int) (string, error) {
return "", ErrPlatformNotSupport
func findProcessName(network string, ip netip.Addr, srcPort int) (int32, string, error) {
return -1, "", ErrPlatformNotSupport
}
func resolveSocketByNetlink(network string, ip netip.Addr, srcPort int) (int32, int32, error) {

View File

@ -9,7 +9,6 @@ import (
"github.com/Dreamacro/clash/common/nnip"
"github.com/Dreamacro/clash/log"
"golang.org/x/sys/windows"
)
@ -62,7 +61,7 @@ func initWin32API() error {
return nil
}
func findProcessName(network string, ip netip.Addr, srcPort int) (string, error) {
func findProcessName(network string, ip netip.Addr, srcPort int) (int32, string, error) {
once.Do(func() {
err := initWin32API()
if err != nil {
@ -86,21 +85,22 @@ func findProcessName(network string, ip netip.Addr, srcPort int) (string, error)
fn = getExUDPTable
class = udpTablePid
default:
return "", ErrInvalidNetwork
return -1, "", ErrInvalidNetwork
}
buf, err := getTransportTable(fn, family, class)
if err != nil {
return "", err
return -1, "", err
}
s := newSearcher(family == windows.AF_INET, network == TCP)
pid, err := s.Search(buf, ip, uint16(srcPort))
if err != nil {
return "", err
return -1, "", err
}
return getExecPathFromPID(pid)
pp, err := getExecPathFromPID(pid)
return -1, pp, err
}
type searcher struct {

View File

@ -8,7 +8,6 @@ import (
"github.com/Dreamacro/clash/component/profile"
C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/log"
"go.etcd.io/bbolt"
)

View File

@ -89,24 +89,39 @@ func ResolveIP(host string) (netip.Addr, error) {
// ResolveIPv4ProxyServerHost proxies server host only
func ResolveIPv4ProxyServerHost(host string) (netip.Addr, error) {
if ProxyServerHostResolver != nil {
return ResolveIPv4WithResolver(host, ProxyServerHostResolver)
if ip, err := ResolveIPv4WithResolver(host, ProxyServerHostResolver); err != nil {
return ResolveIPv4(host)
} else {
return ip, nil
}
}
return ResolveIPv4(host)
}
// ResolveIPv6ProxyServerHost proxies server host only
func ResolveIPv6ProxyServerHost(host string) (netip.Addr, error) {
if ProxyServerHostResolver != nil {
return ResolveIPv6WithResolver(host, ProxyServerHostResolver)
if ip, err := ResolveIPv6WithResolver(host, ProxyServerHostResolver); err != nil {
return ResolveIPv6(host)
} else {
return ip, nil
}
}
return ResolveIPv6(host)
}
// ResolveProxyServerHost proxies server host only
func ResolveProxyServerHost(host string) (netip.Addr, error) {
if ProxyServerHostResolver != nil {
return ResolveIPWithResolver(host, ProxyServerHostResolver)
if ip, err := ResolveIPWithResolver(host, ProxyServerHostResolver); err != nil {
return ResolveIP(host)
} else {
return ip, err
}
}
return ResolveIP(host)
}

View File

@ -7,18 +7,19 @@ import (
"strconv"
"time"
"github.com/Dreamacro/clash/component/trie"
CN "github.com/Dreamacro/clash/common/net"
"github.com/Dreamacro/clash/common/utils"
"github.com/Dreamacro/clash/component/resolver"
"github.com/Dreamacro/clash/component/trie"
C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/constant/sniffer"
"github.com/Dreamacro/clash/log"
)
var (
ErrorUnsupportedSniffer = errors.New("unsupported sniffer")
ErrorSniffFailed = errors.New("all sniffer failed")
ErrNoClue = errors.New("not enough information for making a decision")
)
var Dispatcher SnifferDispatcher
@ -27,7 +28,7 @@ type (
SnifferDispatcher struct {
enable bool
sniffers []C.Sniffer
sniffers []sniffer.Sniffer
foreDomain *trie.DomainTrie[bool]
skipSNI *trie.DomainTrie[bool]
@ -84,7 +85,6 @@ func (sd *SnifferDispatcher) replaceDomain(metadata *C.Metadata, host string) {
metadata.Host = host
metadata.DNSMode = C.DNSMapping
resolver.InsertHostByIP(metadata.DstIP, host)
metadata.DstIP = netip.Addr{}
}
func (sd *SnifferDispatcher) Enable() bool {
@ -94,16 +94,16 @@ func (sd *SnifferDispatcher) Enable() bool {
func (sd *SnifferDispatcher) sniffDomain(conn *CN.BufferedConn, metadata *C.Metadata) (string, error) {
for _, sniffer := range sd.sniffers {
if sniffer.SupportNetwork() == C.TCP {
conn.SetReadDeadline(time.Now().Add(3 * time.Second))
_ = conn.SetReadDeadline(time.Now().Add(3 * time.Second))
_, err := conn.Peek(1)
conn.SetReadDeadline(time.Time{})
_ = conn.SetReadDeadline(time.Time{})
if err != nil {
_, ok := err.(*net.OpError)
if ok {
log.Errorln("[Sniffer] [%s] Maybe read timeout, Consider adding skip", metadata.DstIP.String())
conn.Close()
log.Errorln("[Sniffer] [%s] may not have any sent data, Consider adding skip", metadata.DstIP.String())
_ = conn.Close()
}
log.Errorln("[Sniffer] %v", err)
return "", err
}
@ -116,7 +116,13 @@ func (sd *SnifferDispatcher) sniffDomain(conn *CN.BufferedConn, metadata *C.Meta
host, err := sniffer.SniffTCP(bytes)
if err != nil {
log.Debugln("[Sniffer] [%s] Sniff data failed %s", sniffer.Protocol(), metadata.DstIP)
// log.Debugln("[Sniffer] [%s] Sniff data failed %s", sniffer.Protocol(), metadata.DstIP)
continue
}
_, err = netip.ParseAddr(host)
if err == nil {
// log.Debugln("[Sniffer] [%s] Sniff data failed %s", sniffer.Protocol(), metadata.DstIP)
continue
}
@ -135,8 +141,9 @@ func NewCloseSnifferDispatcher() (*SnifferDispatcher, error) {
return &dispatcher, nil
}
func NewSnifferDispatcher(needSniffer []C.SnifferType, forceDomain *trie.DomainTrie[bool],
skipSNI *trie.DomainTrie[bool], ports *[]utils.Range[uint16]) (*SnifferDispatcher, error) {
func NewSnifferDispatcher(needSniffer []sniffer.Type, forceDomain *trie.DomainTrie[bool],
skipSNI *trie.DomainTrie[bool], ports *[]utils.Range[uint16],
) (*SnifferDispatcher, error) {
dispatcher := SnifferDispatcher{
enable: true,
foreDomain: forceDomain,
@ -157,10 +164,12 @@ func NewSnifferDispatcher(needSniffer []C.SnifferType, forceDomain *trie.DomainT
return &dispatcher, nil
}
func NewSniffer(name C.SnifferType) (C.Sniffer, error) {
func NewSniffer(name sniffer.Type) (sniffer.Sniffer, error) {
switch name {
case C.TLS:
case sniffer.TLS:
return &TLSSniffer{}, nil
case sniffer.HTTP:
return &HTTPSniffer{}, nil
default:
return nil, ErrorUnsupportedSniffer
}

View File

@ -0,0 +1,101 @@
package sniffer
import (
"bytes"
"errors"
"net"
"strings"
C "github.com/Dreamacro/clash/constant"
)
var (
// refer to https://pkg.go.dev/net/http@master#pkg-constants
methods = [...]string{"get", "post", "head", "put", "delete", "options", "connect", "patch", "trace"}
errNotHTTPMethod = errors.New("not an HTTP method")
)
type version byte
const (
HTTP1 version = iota
HTTP2
)
type HTTPSniffer struct {
version version
host string
}
func (http *HTTPSniffer) Protocol() string {
switch http.version {
case HTTP1:
return "http1"
case HTTP2:
return "http2"
default:
return "unknown"
}
}
func (http *HTTPSniffer) SupportNetwork() C.NetWork {
return C.TCP
}
func (http *HTTPSniffer) SniffTCP(bytes []byte) (string, error) {
domain, err := SniffHTTP(bytes)
if err == nil {
return *domain, nil
} else {
return "", err
}
}
func beginWithHTTPMethod(b []byte) error {
for _, m := range &methods {
if len(b) >= len(m) && strings.EqualFold(string(b[:len(m)]), m) {
return nil
}
if len(b) < len(m) {
return ErrNoClue
}
}
return errNotHTTPMethod
}
func SniffHTTP(b []byte) (*string, error) {
if err := beginWithHTTPMethod(b); err != nil {
return nil, err
}
_ = &HTTPSniffer{
version: HTTP1,
}
headers := bytes.Split(b, []byte{'\n'})
for i := 1; i < len(headers); i++ {
header := headers[i]
if len(header) == 0 {
break
}
parts := bytes.SplitN(header, []byte{':'}, 2)
if len(parts) != 2 {
continue
}
key := strings.ToLower(string(parts[0]))
if key == "host" {
rawHost := strings.ToLower(string(bytes.TrimSpace(parts[1])))
host, _, err := net.SplitHostPort(rawHost)
if err != nil {
if addrError, ok := err.(*net.AddrError); ok && strings.Contains(addrError.Err, "missing port") {
host = rawHost
} else {
return nil, err
}
}
return &host, nil
}
}
return nil, ErrNoClue
}

View File

@ -0,0 +1,3 @@
package sniffer
// TODO

View File

@ -11,11 +11,9 @@ import (
var (
errNotTLS = errors.New("not TLS header")
errNotClientHello = errors.New("not client hello")
ErrNoClue = errors.New("not enough information for making a decision")
)
type TLSSniffer struct {
}
type TLSSniffer struct{}
func (tls *TLSSniffer) Protocol() string {
return "tls"

View File

@ -2,9 +2,7 @@ package trie
import "errors"
var (
ErrorOverMaxValue = errors.New("the value don't over max value")
)
var ErrorOverMaxValue = errors.New("the value don't over max value")
type IpCidrNode struct {
Mark bool

View File

@ -1,8 +1,9 @@
package trie
import (
"github.com/Dreamacro/clash/log"
"net"
"github.com/Dreamacro/clash/log"
)
type IPV6 bool

View File

@ -49,7 +49,6 @@ func TestIpv4Search(t *testing.T) {
assert.Equal(t, false, trie.IsContain(net.ParseIP("22")))
assert.Equal(t, false, trie.IsContain(net.ParseIP("")))
}
func TestIpv6AddSuccess(t *testing.T) {
@ -96,5 +95,4 @@ func TestIpv6Search(t *testing.T) {
assert.Equal(t, true, trie.IsContainForString("2001:67c:4e8:9666::1213"))
assert.Equal(t, false, trie.IsContain(net.ParseIP("22233:22")))
}

View File

@ -4,7 +4,6 @@ import (
"container/list"
"errors"
"fmt"
"github.com/Dreamacro/clash/listener/tun/ipstack/commons"
"net"
"net/netip"
"net/url"
@ -14,14 +13,11 @@ import (
"strings"
"time"
"github.com/Dreamacro/clash/common/utils"
R "github.com/Dreamacro/clash/rule"
RP "github.com/Dreamacro/clash/rule/provider"
"github.com/Dreamacro/clash/adapter"
"github.com/Dreamacro/clash/adapter/outbound"
"github.com/Dreamacro/clash/adapter/outboundgroup"
"github.com/Dreamacro/clash/adapter/provider"
"github.com/Dreamacro/clash/common/utils"
"github.com/Dreamacro/clash/component/auth"
"github.com/Dreamacro/clash/component/dialer"
"github.com/Dreamacro/clash/component/fakeip"
@ -30,11 +26,15 @@ import (
"github.com/Dreamacro/clash/component/trie"
C "github.com/Dreamacro/clash/constant"
providerTypes "github.com/Dreamacro/clash/constant/provider"
snifferTypes "github.com/Dreamacro/clash/constant/sniffer"
"github.com/Dreamacro/clash/constant/sniffer"
"github.com/Dreamacro/clash/dns"
"github.com/Dreamacro/clash/listener/tun/ipstack/commons"
"github.com/Dreamacro/clash/log"
R "github.com/Dreamacro/clash/rules"
RP "github.com/Dreamacro/clash/rules/provider"
T "github.com/Dreamacro/clash/tunnel"
"gopkg.in/yaml.v2"
"gopkg.in/yaml.v3"
)
// General config
@ -45,11 +45,14 @@ type General struct {
UnifiedDelay bool
LogLevel log.LogLevel `json:"log-level"`
IPv6 bool `json:"ipv6"`
Interface string `json:"-"`
Interface string `json:"interface-name"`
RoutingMark int `json:"-"`
GeodataMode bool `json:"geodata-mode"`
GeodataLoader string `json:"geodata-loader"`
TCPConcurrent bool `json:"tcp-concurrent"`
EnableProcess bool `json:"enable-process"`
Tun Tun `json:"tun"`
Sniffing bool `json:"sniffing"`
}
// Inbound config
@ -96,12 +99,6 @@ type FallbackFilter struct {
GeoSite []*router.DomainMatcher `yaml:"geosite"`
}
var (
GroupsList = list.New()
ProxiesList = list.New()
ParsingProxiesCallback func(groupsList *list.List, proxiesList *list.List)
)
// Profile config
type Profile struct {
StoreSelected bool `yaml:"store-selected"`
@ -116,6 +113,7 @@ type Tun struct {
DNSHijack []netip.AddrPort `yaml:"dns-hijack" json:"dns-hijack"`
AutoRoute bool `yaml:"auto-route" json:"auto-route"`
AutoDetectInterface bool `yaml:"auto-detect-interface" json:"auto-detect-interface"`
TunAddressPrefix netip.Prefix `yaml:"-" json:"-"`
}
// IPTables config
@ -127,11 +125,10 @@ type IPTables struct {
type Sniffer struct {
Enable bool
Force bool
Sniffers []C.SnifferType
Sniffers []sniffer.Type
Reverses *trie.DomainTrie[bool]
ForceDomain *trie.DomainTrie[bool]
SkipSNI *trie.DomainTrie[bool]
SkipDomain *trie.DomainTrie[bool]
Ports *[]utils.Range[uint16]
}
@ -209,8 +206,9 @@ type RawConfig struct {
GeodataMode bool `yaml:"geodata-mode"`
GeodataLoader string `yaml:"geodata-loader"`
TCPConcurrent bool `yaml:"tcp-concurrent" json:"tcp-concurrent"`
EnableProcess bool `yaml:"enable-process" json:"enable-process"`
Sniffer SnifferRaw `yaml:"sniffer"`
Sniffer RawSniffer `yaml:"sniffer"`
ProxyProvider map[string]map[string]any `yaml:"proxy-providers"`
RuleProvider map[string]map[string]any `yaml:"rule-providers"`
Hosts map[string]string `yaml:"hosts"`
@ -219,18 +217,23 @@ type RawConfig struct {
IPTables IPTables `yaml:"iptables"`
Experimental Experimental `yaml:"experimental"`
Profile Profile `yaml:"profile"`
GeoXUrl RawGeoXUrl `yaml:"geox-url"`
Proxy []map[string]any `yaml:"proxies"`
ProxyGroup []map[string]any `yaml:"proxy-groups"`
Rule []string `yaml:"rules"`
}
type SnifferRaw struct {
type RawGeoXUrl struct {
GeoIp string `yaml:"geoip" json:"geoip"`
Mmdb string `yaml:"mmdb" json:"mmdb"`
GeoSite string `yaml:"geosite" json:"geosite"`
}
type RawSniffer struct {
Enable bool `yaml:"enable" json:"enable"`
Sniffing []string `yaml:"sniffing" json:"sniffing"`
Force bool `yaml:"force" json:"force"`
Reverse []string `yaml:"reverses" json:"reverses"`
ForceDomain []string `yaml:"force-domain" json:"force-domain"`
SkipSNI []string `yaml:"skip-sni" json:"skip-sni"`
SkipDomain []string `yaml:"skip-domain" json:"skip-domain"`
Ports []string `yaml:"port-whitelist" json:"port-whitelist"`
}
@ -260,13 +263,14 @@ func UnmarshalRawConfig(buf []byte) (*RawConfig, error) {
Proxy: []map[string]any{},
ProxyGroup: []map[string]any{},
TCPConcurrent: false,
EnableProcess: true,
Tun: RawTun{
Enable: false,
Device: "",
AutoDetectInterface: true,
Stack: C.TunGvisor,
DNSHijack: []string{"0.0.0.0:53"}, // default hijack all dns query
AutoRoute: true,
AutoRoute: false,
AutoDetectInterface: false,
},
IPTables: IPTables{
Enable: false,
@ -300,18 +304,21 @@ func UnmarshalRawConfig(buf []byte) (*RawConfig, error) {
"www.msftconnecttest.com",
},
},
Sniffer: SnifferRaw{
Sniffer: RawSniffer{
Enable: false,
Force: false,
Sniffing: []string{},
Reverse: []string{},
ForceDomain: []string{},
SkipSNI: []string{},
SkipDomain: []string{},
Ports: []string{},
},
Profile: Profile{
StoreSelected: true,
},
GeoXUrl: RawGeoXUrl{
GeoIp: "https://ghproxy.com/https://raw.githubusercontent.com/Loyalsoldier/v2ray-rules-dat/release/geoip.dat",
Mmdb: "https://ghproxy.com/https://raw.githubusercontent.com/Loyalsoldier/geoip/release/Country.mmdb",
GeoSite: "https://ghproxy.com/https://raw.githubusercontent.com/Loyalsoldier/v2ray-rules-dat/release/geosite.dat",
},
}
if err := yaml.Unmarshal(buf, rawCfg); err != nil {
@ -323,7 +330,7 @@ func UnmarshalRawConfig(buf []byte) (*RawConfig, error) {
func ParseRawConfig(rawCfg *RawConfig) (*Config, error) {
config := &Config{}
log.Infoln("Start initial configuration in progress") //Segment finished in xxm
log.Infoln("Start initial configuration in progress") // Segment finished in xxm
startTime := time.Now()
config.Experimental = &rawCfg.Experimental
config.Profile = &rawCfg.Profile
@ -335,12 +342,6 @@ func ParseRawConfig(rawCfg *RawConfig) (*Config, error) {
}
config.General = general
tunCfg, err := parseTun(rawCfg.Tun, config.General)
if err != nil {
return nil, err
}
config.Tun = tunCfg
dialer.DefaultInterface.Store(config.General.Interface)
proxies, providers, err := parseProxies(rawCfg)
@ -369,6 +370,12 @@ func ParseRawConfig(rawCfg *RawConfig) (*Config, error) {
}
config.DNS = dnsCfg
tunCfg, err := parseTun(rawCfg.Tun, config.General, dnsCfg)
if err != nil {
return nil, err
}
config.Tun = tunCfg
config.Users = parseAuthentication(rawCfg.Authentication)
config.Sniffer, err = parseSniffer(rawCfg.Sniffer)
@ -377,7 +384,7 @@ func ParseRawConfig(rawCfg *RawConfig) (*Config, error) {
}
elapsedTime := time.Since(startTime) / time.Millisecond // duration in ms
log.Infoln("Initial configuration complete, total time: %dms", elapsedTime) //Segment finished in xxm
log.Infoln("Initial configuration complete, total time: %dms", elapsedTime) // Segment finished in xxm
return config, nil
}
@ -417,6 +424,7 @@ func parseGeneral(cfg *RawConfig) (*General, error) {
GeodataMode: cfg.GeodataMode,
GeodataLoader: cfg.GeodataLoader,
TCPConcurrent: cfg.TCPConcurrent,
EnableProcess: cfg.EnableProcess,
}, nil
}
@ -428,8 +436,8 @@ func parseProxies(cfg *RawConfig) (proxies map[string]C.Proxy, providersMap map[
providersConfig := cfg.ProxyProvider
var proxyList []string
_proxiesList := list.New()
_groupsList := list.New()
proxiesList := list.New()
groupsList := list.New()
proxies["DIRECT"] = adapter.NewProxy(outbound.NewDirect())
proxies["REJECT"] = adapter.NewProxy(outbound.NewReject())
@ -449,7 +457,7 @@ func parseProxies(cfg *RawConfig) (proxies map[string]C.Proxy, providersMap map[
}
proxies[proxy.Name()] = proxy
proxyList = append(proxyList, proxy.Name())
_proxiesList.PushBack(mapping)
proxiesList.PushBack(mapping)
}
// keep the original order of ProxyGroups in config file
@ -459,7 +467,7 @@ func parseProxies(cfg *RawConfig) (proxies map[string]C.Proxy, providersMap map[
return nil, nil, fmt.Errorf("proxy group %d: missing name", idx)
}
proxyList = append(proxyList, groupName)
_groupsList.PushBack(mapping)
groupsList.PushBack(mapping)
}
// check if any loop exists and sort the ProxyGroups
@ -514,12 +522,7 @@ func parseProxies(cfg *RawConfig) (proxies map[string]C.Proxy, providersMap map[
[]providerTypes.ProxyProvider{pd},
)
proxies["GLOBAL"] = adapter.NewProxy(global)
ProxiesList = _proxiesList
GroupsList = _groupsList
if ParsingProxiesCallback != nil {
// refresh tray menu
go ParsingProxiesCallback(GroupsList, ProxiesList)
}
return proxies, providersMap, nil
}
@ -539,7 +542,6 @@ func parseRules(cfg *RawConfig, proxies map[string]C.Proxy) ([]C.Rule, map[strin
var rules []C.Rule
rulesConfig := cfg.Rule
mode := cfg.Mode
// parse rules
for idx, line := range rulesConfig {
@ -551,10 +553,6 @@ func parseRules(cfg *RawConfig, proxies map[string]C.Proxy) ([]C.Rule, map[strin
ruleName = strings.ToUpper(rule[0])
)
if mode == T.Script && ruleName != "GEOSITE" {
continue
}
l := len(rule)
if ruleName == "NOT" || ruleName == "OR" || ruleName == "AND" {
@ -583,13 +581,6 @@ func parseRules(cfg *RawConfig, proxies map[string]C.Proxy) ([]C.Rule, map[strin
}
params = trimArr(params)
if ruleName == "GEOSITE" {
if err := initGeoSite(); err != nil {
return nil, nil, fmt.Errorf("can't initial GeoSite: %s", err)
}
initMode = false
}
parsed, parseErr := R.ParseRule(ruleName, payload, target, params)
if parseErr != nil {
return nil, nil, fmt.Errorf("rules[%d] [%s] error: %s", idx, line, parseErr.Error())
@ -883,7 +874,7 @@ func parseAuthentication(rawRecords []string) []auth.AuthUser {
return users
}
func parseTun(rawTun RawTun, general *General) (*Tun, error) {
func parseTun(rawTun RawTun, general *General, dnsCfg *DNS) (*Tun, error) {
if rawTun.Enable && rawTun.AutoDetectInterface {
autoDetectInterfaceName, err := commons.GetAutoDetectInterface()
if err != nil {
@ -910,6 +901,13 @@ func parseTun(rawTun RawTun, general *General) (*Tun, error) {
dnsHijack = append(dnsHijack, addrPort)
}
var tunAddressPrefix netip.Prefix
if dnsCfg.FakeIPRange != nil {
tunAddressPrefix = *dnsCfg.FakeIPRange.IPNet()
} else {
tunAddressPrefix = netip.MustParsePrefix("198.18.0.1/16")
}
return &Tun{
Enable: rawTun.Enable,
Device: rawTun.Device,
@ -917,13 +915,13 @@ func parseTun(rawTun RawTun, general *General) (*Tun, error) {
DNSHijack: dnsHijack,
AutoRoute: rawTun.AutoRoute,
AutoDetectInterface: rawTun.AutoDetectInterface,
TunAddressPrefix: tunAddressPrefix,
}, nil
}
func parseSniffer(snifferRaw SnifferRaw) (*Sniffer, error) {
func parseSniffer(snifferRaw RawSniffer) (*Sniffer, error) {
sniffer := &Sniffer{
Enable: snifferRaw.Enable,
Force: snifferRaw.Force,
}
var ports []utils.Range[uint16]
@ -954,11 +952,11 @@ func parseSniffer(snifferRaw SnifferRaw) (*Sniffer, error) {
sniffer.Ports = &ports
loadSniffer := make(map[C.SnifferType]struct{})
loadSniffer := make(map[snifferTypes.Type]struct{})
for _, snifferName := range snifferRaw.Sniffing {
find := false
for _, snifferType := range C.SnifferList {
for _, snifferType := range snifferTypes.List {
if snifferType.String() == strings.ToUpper(snifferName) {
find = true
loadSniffer[snifferType] = struct{}{}
@ -973,7 +971,6 @@ func parseSniffer(snifferRaw SnifferRaw) (*Sniffer, error) {
for st := range loadSniffer {
sniffer.Sniffers = append(sniffer.Sniffers, st)
}
sniffer.ForceDomain = trie.New[bool]()
for _, domain := range snifferRaw.ForceDomain {
err := sniffer.ForceDomain.Insert(domain, true)
@ -982,35 +979,13 @@ func parseSniffer(snifferRaw SnifferRaw) (*Sniffer, error) {
}
}
sniffer.SkipSNI = trie.New[bool]()
for _, domain := range snifferRaw.SkipSNI {
err := sniffer.SkipSNI.Insert(domain, true)
sniffer.SkipDomain = trie.New[bool]()
for _, domain := range snifferRaw.SkipDomain {
err := sniffer.SkipDomain.Insert(domain, true)
if err != nil {
return nil, fmt.Errorf("error domian[%s] in force-domain, error:%v", domain, err)
}
}
// Compatibility, remove it when release
if strings.Contains(C.Version, "alpha") || strings.Contains(C.Version, "develop") || strings.Contains(C.Version, "1.10.0") {
log.Warnln("Sniffer param force and reverses deprecated, will be removed in the release version, see https://github.com/MetaCubeX/Clash.Meta/commit/48a01adb7a4f38974b9d9639f931d0d245aebf28")
if snifferRaw.Force {
// match all domain
sniffer.ForceDomain.Insert("+", true)
for _, domain := range snifferRaw.Reverse {
err := sniffer.SkipSNI.Insert(domain, true)
if err != nil {
return nil, fmt.Errorf("error domian[%s], error:%v", domain, err)
}
}
} else {
for _, domain := range snifferRaw.Reverse {
err := sniffer.ForceDomain.Insert(domain, true)
if err != nil {
return nil, fmt.Errorf("error domian[%s], error:%v", domain, err)
}
}
}
}
return sniffer, nil
}

View File

@ -2,20 +2,20 @@ package config
import (
"fmt"
"github.com/Dreamacro/clash/component/geodata"
"github.com/Dreamacro/clash/component/mmdb"
"io"
"net/http"
"os"
"github.com/Dreamacro/clash/component/geodata"
"github.com/Dreamacro/clash/component/mmdb"
C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/log"
)
var initMode = true
var initFlag bool
func downloadMMDB(path string) (err error) {
resp, err := http.Get("https://raw.githubusercontents.com/Loyalsoldier/geoip/release/Country.mmdb")
resp, err := http.Get(C.MmdbUrl)
if err != nil {
return
}
@ -32,7 +32,7 @@ func downloadMMDB(path string) (err error) {
}
func downloadGeoIP(path string) (err error) {
resp, err := http.Get("https://raw.githubusercontents.com/Loyalsoldier/v2ray-rules-dat/release/geoip.dat")
resp, err := http.Get(C.GeoIpUrl)
if err != nil {
return
}
@ -49,7 +49,7 @@ func downloadGeoIP(path string) (err error) {
}
func downloadGeoSite(path string) (err error) {
resp, err := http.Get("https://raw.githubusercontents.com/Loyalsoldier/v2ray-rules-dat/release/geosite.dat")
resp, err := http.Get(C.GeoSiteUrl)
if err != nil {
return
}
@ -73,9 +73,9 @@ func initGeoSite() error {
}
log.Infoln("Download GeoSite.dat finish")
}
if initMode {
if !geodata.Verify(C.GeositeName) {
log.Warnln("GeoSite.dat invalid, remove and download")
if !initFlag {
if err := geodata.Verify(C.GeositeName); err != nil {
log.Warnln("GeoSite.dat invalid, remove and download: %s", err)
if err := os.Remove(C.Path.GeoSite()); err != nil {
return fmt.Errorf("can't remove invalid GeoSite.dat: %s", err.Error())
}
@ -83,6 +83,7 @@ func initGeoSite() error {
return fmt.Errorf("can't download GeoSite.dat: %s", err.Error())
}
}
initFlag = true
}
return nil
}
@ -97,8 +98,8 @@ func initGeoIP() error {
log.Infoln("Download GeoIP.dat finish")
}
if !geodata.Verify(C.GeoipName) {
log.Warnln("GeoIP.dat invalid, remove and download")
if err := geodata.Verify(C.GeoipName); err != nil {
log.Warnln("GeoIP.dat invalid, remove and download: %s", err)
if err := os.Remove(C.Path.GeoIP()); err != nil {
return fmt.Errorf("can't remove invalid GeoIP.dat: %s", err.Error())
}
@ -159,6 +160,9 @@ func Init(dir string) error {
if !C.GeodataMode {
C.GeodataMode = rawCfg.GeodataMode
}
C.GeoIpUrl = rawCfg.GeoXUrl.GeoIp
C.GeoSiteUrl = rawCfg.GeoXUrl.GeoSite
C.MmdbUrl = rawCfg.GeoXUrl.Mmdb
// initial GeoIP
if err := initGeoIP(); err != nil {
return fmt.Errorf("can't initial GeoIP: %w", err)

81
config/updateGeo.go Normal file
View File

@ -0,0 +1,81 @@
package config
import (
"fmt"
"io/ioutil"
"net/http"
"runtime"
"github.com/Dreamacro/clash/component/geodata"
_ "github.com/Dreamacro/clash/component/geodata/standard"
C "github.com/Dreamacro/clash/constant"
"github.com/oschwald/geoip2-golang"
)
func UpdateGeoDatabases() error {
defer runtime.GC()
geoLoader, err := geodata.GetGeoDataLoader("standard")
if err != nil {
return err
}
if C.GeodataMode {
data, err := downloadForBytes(C.GeoIpUrl)
if err != nil {
return fmt.Errorf("can't download GeoIP database file: %w", err)
}
if _, err = geoLoader.LoadIPByBytes(data, "cn"); err != nil {
return fmt.Errorf("invalid GeoIP database file: %s", err)
}
if saveFile(data, C.Path.GeoIP()) != nil {
return fmt.Errorf("can't save GeoIP database file: %w", err)
}
} else {
data, err := downloadForBytes(C.MmdbUrl)
if err != nil {
return fmt.Errorf("can't download MMDB database file: %w", err)
}
instance, err := geoip2.FromBytes(data)
if err != nil {
return fmt.Errorf("invalid MMDB database file: %s", err)
}
_ = instance.Close()
if saveFile(data, C.Path.MMDB()) != nil {
return fmt.Errorf("can't save MMDB database file: %w", err)
}
}
data, err := downloadForBytes(C.GeoSiteUrl)
if err != nil {
return fmt.Errorf("can't download GeoSite database file: %w", err)
}
if _, err = geoLoader.LoadSiteByBytes(data, "cn"); err != nil {
return fmt.Errorf("invalid GeoSite database file: %s", err)
}
if saveFile(data, C.Path.GeoSite()) != nil {
return fmt.Errorf("can't save GeoSite database file: %w", err)
}
return nil
}
func downloadForBytes(url string) ([]byte, error) {
resp, err := http.Get(url)
if err != nil {
return nil, err
}
defer resp.Body.Close()
return ioutil.ReadAll(resp.Body)
}
func saveFile(bytes []byte, path string) error {
return ioutil.WriteFile(path, bytes, 0o644)
}

View File

@ -7,6 +7,8 @@ import (
"time"
"github.com/Dreamacro/clash/component/dialer"
"github.com/sagernet/sing/common/buf"
N "github.com/sagernet/sing/common/network"
)
// Adapter Type
@ -30,6 +32,7 @@ const (
Vmess
Vless
Trojan
Hysteria
)
const (
@ -41,6 +44,7 @@ const (
type Connection interface {
Chains() Chain
AppendToChains(adapter ProxyAdapter)
RemoteDestination() string
}
type Chain []string
@ -73,6 +77,7 @@ type Conn interface {
type PacketConn interface {
net.PacketConn
Connection
N.PacketConn
// Deprecate WriteWithMetadata because of remote resolve DNS cause TURN failed
// WriteWithMetadata(p []byte, metadata *Metadata) (n int, err error)
}
@ -107,6 +112,11 @@ type ProxyAdapter interface {
Unwrap(metadata *Metadata) Proxy
}
type Group interface {
URLTest(ctx context.Context, url string) (mp map[string]uint16, err error)
GetProxies(touch bool) []Proxy
}
type DelayHistory struct {
Time time.Time `json:"time"`
Delay uint16 `json:"delay"`
@ -155,6 +165,8 @@ func (at AdapterType) String() string {
return "Vless"
case Trojan:
return "Trojan"
case Hysteria:
return "Hysteria"
case Relay:
return "Relay"
@ -175,7 +187,7 @@ func (at AdapterType) String() string {
// UDPPacket contains the data of UDP packet, and offers control/info of UDP packet's source
type UDPPacket interface {
// Data get the payload of UDP Packet
Data() []byte
Data() *buf.Buffer
// WriteBack writes the payload with source IP/Port equals addr
// - variable source IP/Port is important to STUN
@ -183,8 +195,7 @@ type UDPPacket interface {
// this is important when using Fake-IP.
WriteBack(b []byte, addr net.Addr) (n int, err error)
// Drop call after packet is used, could recycle buffer in this function.
Drop()
N.PacketWriter
// LocalAddr returns the source IP/Port of packet
LocalAddr() net.Addr

View File

@ -0,0 +1,7 @@
//go:build no_doq
package features
func init() {
TAGS = append(TAGS, "no_doq")
}

View File

@ -0,0 +1,7 @@
//go:build no_gvisor
package features
func init() {
TAGS = append(TAGS, "no_gvisor")
}

View File

@ -0,0 +1,3 @@
package features
var TAGS = make([]string, 0, 0)

View File

@ -1,3 +1,8 @@
package constant
var GeodataMode bool
var (
GeodataMode bool
GeoIpUrl string
MmdbUrl string
GeoSiteUrl string
)

View File

@ -6,6 +6,8 @@ import (
"net"
"net/netip"
"strconv"
M "github.com/sagernet/sing/common/metadata"
)
// Socks addr type
@ -19,7 +21,7 @@ const (
ALLNet
HTTP Type = iota
HTTPCONNECT
HTTPS
SOCKS4
SOCKS5
REDIR
@ -49,8 +51,8 @@ func (t Type) String() string {
switch t {
case HTTP:
return "HTTP"
case HTTPCONNECT:
return "HTTP Connect"
case HTTPS:
return "HTTPS"
case SOCKS4:
return "Socks4"
case SOCKS5:
@ -68,6 +70,31 @@ func (t Type) String() string {
}
}
func ParseType(t string) (*Type, error) {
var res Type
switch t {
case "HTTP":
res = HTTP
case "HTTPS":
res = HTTPS
case "SOCKS4":
res = SOCKS4
case "SOCKS5":
res = SOCKS5
case "REDIR":
res = REDIR
case "TPROXY":
res = TPROXY
case "TUN":
res = TUN
case "INNER":
res = INNER
default:
return nil, fmt.Errorf("unknown type: %s", t)
}
return &res, nil
}
func (t Type) MarshalJSON() ([]byte, error) {
return json.Marshal(t.String())
}
@ -86,6 +113,7 @@ type Metadata struct {
Uid *int32 `json:"uid"`
Process string `json:"process"`
ProcessPath string `json:"processPath"`
RemoteDst string `json:"remoteDestination"`
}
func (m *Metadata) RemoteAddress() string {
@ -104,7 +132,7 @@ func (m *Metadata) SourceDetail() string {
if m.Process != "" && m.Uid != nil {
return fmt.Sprintf("%s(%s, uid=%d)", m.SourceAddress(), m.Process, *m.Uid)
} else if m.Uid != nil {
return fmt.Sprintf("%s(%d)", m.SourceAddress(), *m.Uid)
return fmt.Sprintf("%s(uid=%d)", m.SourceAddress(), *m.Uid)
} else if m.Process != "" {
return fmt.Sprintf("%s(%s)", m.SourceAddress(), m.Process)
} else {
@ -144,6 +172,18 @@ func (m *Metadata) UDPAddr() *net.UDPAddr {
}
}
func (m *Metadata) Socksaddr() M.Socksaddr {
port, _ := strconv.ParseUint(m.DstPort, 10, 16)
if m.Host != "" {
return M.Socksaddr{
Fqdn: m.Host,
Port: uint16(port),
}
} else {
return M.SocksaddrFromAddrPort(m.DstIP, uint16(port))
}
}
func (m *Metadata) String() string {
if m.Host != "" {
return m.Host

View File

@ -29,7 +29,6 @@ var Path = func() *path {
type path struct {
homeDir string
configFile string
scriptDir string
}
// SetHomeDir is used to set the configuration path
@ -123,23 +122,6 @@ func (p *path) GeoSite() string {
return P.Join(p.homeDir, "GeoSite.dat")
}
func (p *path) ScriptDir() string {
if len(p.scriptDir) != 0 {
return p.scriptDir
}
if dir, err := os.MkdirTemp("", Name+"-"); err == nil {
p.scriptDir = dir
} else {
p.scriptDir = P.Join(os.TempDir(), Name)
_ = os.MkdirAll(p.scriptDir, 0o644)
}
return p.scriptDir
}
func (p *path) Script() string {
return P.Join(p.ScriptDir(), "clash_script.py")
}
func (p *path) GetAssetLocation(file string) string {
return P.Join(p.homeDir, file)
}

View File

@ -1,7 +1,7 @@
package provider
import (
"github.com/Dreamacro/clash/constant"
C "github.com/Dreamacro/clash/constant"
)
// Vehicle Type
@ -65,10 +65,8 @@ type Provider interface {
// ProxyProvider interface
type ProxyProvider interface {
Provider
Proxies() []constant.Proxy
// ProxiesWithTouch is used to inform the provider that the proxy is actually being used while getting the list of proxies.
// Commonly used in DialContext and DialPacketConn
ProxiesWithTouch() []constant.Proxy
Proxies() []C.Proxy
Touch()
HealthCheck()
Version() uint
}
@ -100,7 +98,7 @@ func (rt RuleType) String() string {
type RuleProvider interface {
Provider
Behavior() RuleType
Match(*constant.Metadata) bool
Match(*C.Metadata) bool
ShouldResolveIP() bool
AsRule(adaptor string) constant.Rule
AsRule(adaptor string) C.Rule
}

View File

@ -9,14 +9,16 @@ const (
GEOIP
IPCIDR
SrcIPCIDR
IPSuffix
SrcIPSuffix
SrcPort
DstPort
Process
ProcessPath
Script
RuleSet
Network
Uid
INTYPE
MATCH
AND
OR
@ -41,6 +43,10 @@ func (rt RuleType) String() string {
return "IPCIDR"
case SrcIPCIDR:
return "SrcIPCIDR"
case IPSuffix:
return "IPSuffix"
case SrcIPSuffix:
return "SrcIPSuffix"
case SrcPort:
return "SrcPort"
case DstPort:
@ -49,8 +55,6 @@ func (rt RuleType) String() string {
return "Process"
case ProcessPath:
return "ProcessPath"
case Script:
return "Script"
case MATCH:
return "Match"
case RuleSet:
@ -59,6 +63,8 @@ func (rt RuleType) String() string {
return "Network"
case Uid:
return "Uid"
case INTYPE:
return "InType"
case AND:
return "AND"
case OR:

View File

@ -46,3 +46,11 @@ func (re *RuleExtra) NotMatchProcessName(processName string) bool {
type RuleGeoSite interface {
GetDomainMatcher() *router.DomainMatcher
}
type RuleGeoIP interface {
GetIPMatcher() *router.GeoIPMatcher
}
type RuleGroup interface {
GetRecodeSize() int
}

View File

@ -1,26 +0,0 @@
package constant
type Sniffer interface {
SupportNetwork() NetWork
SniffTCP(bytes []byte) (string, error)
Protocol() string
}
const (
TLS SnifferType = iota
)
var (
SnifferList = []SnifferType{TLS}
)
type SnifferType int
func (rt SnifferType) String() string {
switch rt {
case TLS:
return "TLS"
default:
return "Unknown"
}
}

View File

@ -0,0 +1,29 @@
package sniffer
import "github.com/Dreamacro/clash/constant"
type Sniffer interface {
SupportNetwork() constant.NetWork
SniffTCP(bytes []byte) (string, error)
Protocol() string
}
const (
TLS Type = iota
HTTP
)
var List = []Type{TLS, HTTP}
type Type int
func (rt Type) String() string {
switch rt {
case TLS:
return "TLS"
case HTTP:
return "HTTP"
default:
return "Unknown"
}
}

View File

@ -4,7 +4,6 @@ import (
"net"
C "github.com/Dreamacro/clash/constant"
"github.com/gofrs/uuid"
)

View File

@ -4,15 +4,14 @@ import (
"context"
"crypto/tls"
"fmt"
"go.uber.org/atomic"
"net"
"net/netip"
"strings"
"github.com/Dreamacro/clash/component/dialer"
"github.com/Dreamacro/clash/component/resolver"
D "github.com/miekg/dns"
"go.uber.org/atomic"
)
type client struct {
@ -55,10 +54,10 @@ func (c *client) ExchangeContext(ctx context.Context, m *D.Msg) (*D.Msg, error)
}
var conn net.Conn
if c.proxyAdapter == "" {
conn, err = dialer.DialContext(ctx, network, net.JoinHostPort(ip.String(), c.port), options...)
if c.proxyAdapter != "" {
conn, err = dialContextExtra(ctx, c.proxyAdapter, network, ip, c.port, options...)
} else {
conn, err = dialContextWithProxyAdapter(ctx, c.proxyAdapter, network, ip, c.port, options...)
conn, err = dialer.DialContext(ctx, network, net.JoinHostPort(ip.String(), c.port), options...)
}
if err != nil {

View File

@ -2,7 +2,6 @@ package dns
import (
"context"
"go.uber.org/atomic"
"net"
"net/netip"
"sync"
@ -11,8 +10,8 @@ import (
"github.com/Dreamacro/clash/component/dhcp"
"github.com/Dreamacro/clash/component/iface"
"github.com/Dreamacro/clash/component/resolver"
D "github.com/miekg/dns"
"go.uber.org/atomic"
)
const (

View File

@ -9,7 +9,6 @@ import (
"github.com/Dreamacro/clash/component/dialer"
"github.com/Dreamacro/clash/component/resolver"
D "github.com/miekg/dns"
)
@ -100,7 +99,7 @@ func newDoHClient(url string, r *Resolver, proxyAdapter string) *dohClient {
if proxyAdapter == "" {
return dialer.DialContext(ctx, "tcp", net.JoinHostPort(ip.String(), port))
} else {
return dialContextWithProxyAdapter(ctx, proxyAdapter, "tcp", ip, port)
return dialContextExtra(ctx, proxyAdapter, "tcp", ip, port)
}
},
},

View File

@ -5,13 +5,13 @@ import (
"context"
"crypto/tls"
"fmt"
"github.com/Dreamacro/clash/component/dialer"
"github.com/Dreamacro/clash/component/resolver"
"net"
"strconv"
"sync"
"time"
"github.com/Dreamacro/clash/component/dialer"
"github.com/Dreamacro/clash/component/resolver"
"github.com/Dreamacro/clash/log"
"github.com/lucas-clemente/quic-go"
D "github.com/miekg/dns"
@ -138,6 +138,8 @@ func (dc *quicClient) openSession() (quic.Connection, error) {
quicConfig := &quic.Config{
ConnectionIDLength: 12,
HandshakeIdleTimeout: time.Second * 8,
MaxIncomingStreams: 4,
MaxIdleTimeout: time.Second * 45,
}
log.Debugln("opening session to %s", dc.addr)
@ -165,17 +167,17 @@ func (dc *quicClient) openSession() (quic.Connection, error) {
return nil, err
}
} else {
conn, err := dialContextWithProxyAdapter(context.Background(), dc.proxyAdapter, "udp", ip, port)
conn, err := dialContextExtra(context.Background(), dc.proxyAdapter, "udp", ip, port)
if err != nil {
return nil, err
}
wrapConn, ok := conn.(*wrapPacketConn)
if !ok {
return nil, fmt.Errorf("quio create packet failed")
return nil, fmt.Errorf("quic create packet failed")
}
udp = wrapConn.PacketConn
udp = wrapConn
}
session, err := quic.Dial(udp, &udpAddr, host, tlsConfig, quicConfig)

View File

@ -2,6 +2,7 @@ package dns
import (
"net/netip"
"strings"
"github.com/Dreamacro/clash/component/geodata"
"github.com/Dreamacro/clash/component/geodata/router"
@ -9,7 +10,6 @@ import (
"github.com/Dreamacro/clash/component/trie"
C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/log"
"strings"
)
type fallbackIPFilter interface {

View File

@ -12,7 +12,6 @@ import (
C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/context"
"github.com/Dreamacro/clash/log"
D "github.com/miekg/dns"
)
@ -164,6 +163,7 @@ func withResolver(resolver *Resolver) handler {
msg.SetRcode(r, msg.Rcode)
msg.Authoritative = true
log.Debugln("[DNS] %s --> %s", msgToDomain(r), msgToIP(msg))
return msg, nil
}
}

16
dns/patch.go Normal file
View File

@ -0,0 +1,16 @@
package dns
import D "github.com/miekg/dns"
type LocalServer struct {
handler handler
}
// ServeMsg implement resolver.LocalServer ResolveMsg
func (s *LocalServer) ServeMsg(msg *D.Msg) (*D.Msg, error) {
return handlerWithContext(s.handler, msg)
}
func NewLocalServer(resolver *Resolver, mapper *ResolverEnhancer) *LocalServer {
return &LocalServer{handler: NewHandler(resolver, mapper)}
}

View File

@ -4,10 +4,8 @@ import (
"context"
"errors"
"fmt"
"go.uber.org/atomic"
"math/rand"
"net/netip"
"strings"
"time"
"github.com/Dreamacro/clash/common/cache"
@ -17,8 +15,8 @@ import (
"github.com/Dreamacro/clash/component/resolver"
"github.com/Dreamacro/clash/component/trie"
C "github.com/Dreamacro/clash/constant"
D "github.com/miekg/dns"
"go.uber.org/atomic"
"golang.org/x/sync/singleflight"
)
@ -83,12 +81,16 @@ func (r *Resolver) ResolveAllIP(host string) (ips []netip.Addr, err error) {
ips, err = r.resolveIP(host, D.TypeA)
ipv6s, open := <-ch
if !open && err != nil {
return nil, resolver.ErrIPNotFound
select {
case ipv6s, open := <-ch:
if !open && err != nil {
return nil, resolver.ErrIPNotFound
}
ips = append(ips, ipv6s...)
case <-time.After(1 * time.Millisecond):
// wait ipv6 result
}
ips = append(ips, ipv6s...)
return ips, nil
}
@ -232,7 +234,7 @@ func (r *Resolver) matchPolicy(m *D.Msg) []dnsClient {
return nil
}
domain := r.msgToDomain(m)
domain := msgToDomain(m)
if domain == "" {
return nil
}
@ -251,7 +253,7 @@ func (r *Resolver) shouldOnlyQueryFallback(m *D.Msg) bool {
return false
}
domain := r.msgToDomain(m)
domain := msgToDomain(m)
if domain == "" {
return false
@ -332,14 +334,6 @@ func (r *Resolver) resolveIP(host string, dnsType uint16) (ips []netip.Addr, err
return
}
func (r *Resolver) msgToDomain(msg *D.Msg) string {
if len(msg.Question) > 0 {
return strings.TrimRight(msg.Question[0].Name, ".")
}
return ""
}
func (r *Resolver) asyncExchange(ctx context.Context, client []dnsClient, msg *D.Msg) <-chan *result {
ch := make(chan *result, 1)
go func() {

View File

@ -7,7 +7,6 @@ import (
"github.com/Dreamacro/clash/common/sockopt"
"github.com/Dreamacro/clash/context"
"github.com/Dreamacro/clash/log"
D "github.com/miekg/dns"
)

View File

@ -6,6 +6,7 @@ import (
"fmt"
"net"
"net/netip"
"strings"
"time"
"github.com/Dreamacro/clash/common/cache"
@ -14,7 +15,6 @@ import (
C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/log"
"github.com/Dreamacro/clash/tunnel"
D "github.com/miekg/dns"
)
@ -116,6 +116,14 @@ func msgToIP(msg *D.Msg) []netip.Addr {
return ips
}
func msgToDomain(msg *D.Msg) string {
if len(msg.Question) > 0 {
return strings.TrimRight(msg.Question[0].Name, ".")
}
return ""
}
type wrapPacketConn struct {
net.PacketConn
rAddr net.Addr
@ -134,10 +142,19 @@ func (wpc *wrapPacketConn) RemoteAddr() net.Addr {
return wpc.rAddr
}
func dialContextWithProxyAdapter(ctx context.Context, adapterName string, network string, dstIP netip.Addr, port string, opts ...dialer.Option) (net.Conn, error) {
func (wpc *wrapPacketConn) LocalAddr() net.Addr {
if wpc.PacketConn.LocalAddr() == nil {
return &net.UDPAddr{IP: net.IPv4zero, Port: 0}
} else {
return wpc.PacketConn.LocalAddr()
}
}
func dialContextExtra(ctx context.Context, adapterName string, network string, dstIP netip.Addr, port string, opts ...dialer.Option) (net.Conn, error) {
adapter, ok := tunnel.Proxies()[adapterName]
if !ok {
return nil, fmt.Errorf("proxy adapter [%s] not found", adapterName)
opts = append(opts, dialer.WithInterface(adapterName))
adapter, _ = tunnel.Proxies()[tunnel.Direct.String()]
}
networkType := C.TCP

63
go.mod
View File

@ -3,58 +3,83 @@ module github.com/Dreamacro/clash
go 1.18
require (
github.com/Dreamacro/go-shadowsocks2 v0.1.8
github.com/dlclark/regexp2 v1.4.0
github.com/go-chi/chi/v5 v5.0.7
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.5.0
github.com/insomniacslk/dhcp v0.0.0-20220405050111-12fbdcb11b41
github.com/lucas-clemente/quic-go v0.27.0
github.com/miekg/dns v1.1.48
github.com/insomniacslk/dhcp v0.0.0-20220504074936-1ca156eafb9f
github.com/lucas-clemente/quic-go v0.27.2
github.com/miekg/dns v1.1.49
github.com/oschwald/geoip2-golang v1.7.0
github.com/sagernet/sing v0.0.0-20220609123159-a93588755159
github.com/sagernet/sing-shadowsocks v0.0.0-20220609092835-699292971c13
github.com/sirupsen/logrus v1.8.1
github.com/stretchr/testify v1.7.1
github.com/stretchr/testify v1.7.2
github.com/tobyxdd/hysteria v1.0.4
github.com/vishvananda/netlink v1.2.1-beta.2
github.com/xtls/go v0.0.0-20210920065950-d4af136d3672
go.etcd.io/bbolt v1.3.6
go.uber.org/atomic v1.9.0
go.uber.org/automaxprocs v1.5.1
golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4
golang.org/x/exp v0.0.0-20220414153411-bcd21879b8fd
golang.org/x/net v0.0.0-20220421235706-1d1ef9303861
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
golang.org/x/sys v0.0.0-20220422013727-9388b58f7150
golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e
golang.org/x/exp v0.0.0-20220608143224-64259d1afd70
golang.org/x/net v0.0.0-20220607020251-c690dde0001d
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f
golang.org/x/sys v0.0.0-20220608164250-635b8c9b7f68
golang.org/x/time v0.0.0-20220411224347-583f2d630306
golang.zx2c4.com/wireguard v0.0.0-20220407013110-ef5c587f782d
golang.zx2c4.com/wireguard/windows v0.5.4-0.20220317000008-6432784c2469
golang.zx2c4.com/wireguard v0.0.0-20220601130007-6a08d81f6bc4
golang.zx2c4.com/wireguard/windows v0.5.4-0.20220328111914-004c22c5647e
google.golang.org/protobuf v1.28.0
gopkg.in/yaml.v2 v2.4.0
gvisor.dev/gvisor v0.0.0-20220422224113-2cca6b79d9f4
gopkg.in/yaml.v3 v3.0.1
gvisor.dev/gvisor v0.0.0-20220527053002-8ab279227ac8
)
replace github.com/vishvananda/netlink => github.com/MetaCubeX/netlink v1.2.0-beta.0.20220529072258-d6853f887820
replace github.com/tobyxdd/hysteria => github.com/MetaCubeX/hysteria v1.0.5-0.20220607074613-210c46c75b15
replace github.com/lucas-clemente/quic-go => github.com/tobyxdd/quic-go v0.27.1-0.20220512040129-ed2a645d9218
require (
github.com/beorn7/perks v1.0.1 // indirect
github.com/cespare/xxhash/v2 v2.1.2 // indirect
github.com/cheekybits/genny v1.0.0 // indirect
github.com/coreos/go-iptables v0.6.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/fsnotify/fsnotify v1.5.1 // indirect
github.com/fsnotify/fsnotify v1.5.4 // indirect
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/google/btree v1.0.1 // indirect
github.com/google/gopacket v1.1.19 // indirect
github.com/hashicorp/golang-lru v0.5.4 // indirect
github.com/klauspost/cpuid/v2 v2.0.12 // indirect
github.com/kr/pretty v0.2.1 // indirect
github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40 // indirect
github.com/marten-seemann/qtls-go1-16 v0.1.5 // indirect
github.com/marten-seemann/qtls-go1-17 v0.1.1 // indirect
github.com/marten-seemann/qtls-go1-18 v0.1.1 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
github.com/nxadm/tail v1.4.8 // indirect
github.com/onsi/ginkgo v1.16.5 // indirect
github.com/oschwald/maxminddb-golang v1.9.0 // indirect
github.com/patrickmn/go-cache v2.1.0+incompatible // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/prometheus/client_golang v1.12.2 // indirect
github.com/prometheus/client_model v0.2.0 // indirect
github.com/prometheus/common v0.32.1 // indirect
github.com/prometheus/procfs v0.7.3 // indirect
github.com/txthinking/runnergroup v0.0.0-20210608031112-152c7c4432bf // indirect
github.com/txthinking/socks5 v0.0.0-20220212043548-414499347d4a // indirect
github.com/txthinking/x v0.0.0-20210326105829-476fab902fbe // indirect
github.com/u-root/uio v0.0.0-20220204230159-dac05f7d2cb4 // indirect
github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 // indirect
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 // indirect
golang.org/x/text v0.3.8-0.20220124021120-d1c84af989ab // indirect
golang.org/x/tools v0.1.10 // indirect
golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f // indirect
golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df // indirect
golang.zx2c4.com/wintun v0.0.0-20211104114900-415007cec224 // indirect
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
lukechampine.com/blake3 v1.1.7 // indirect
)
replace golang.zx2c4.com/wintun v0.0.0-20211104114900-415007cec224 => github.com/MetaCubeX/wintun-go v0.0.0-20220319102620-bbc5e6b2015e

445
go.sum
View File

@ -2,23 +2,73 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMT
cloud.google.com/go v0.31.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.37.0/go.mod h1:TS1dMSSfndXH133OKGwekG838Om/cQT0BUHV3HcBgoo=
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=
cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=
cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=
cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk=
cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=
cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc=
cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=
cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU=
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
dmitri.shuralyov.com/app/changes v0.0.0-20180602232624-0a106ad413e3/go.mod h1:Yl+fi1br7+Rr3LqpNJf1/uxUdtRUV+Tnj0o93V2B9MU=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
dmitri.shuralyov.com/html/belt v0.0.0-20180602232347-f7d459c86be0/go.mod h1:JLBrvjyP0v+ecvNYvCpyZgu5/xkfAUhi6wJj28eUfSU=
dmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1:a1inKt/atXimZ4Mv927x+r7UpyzRUf4emIoiiSC2TN4=
dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D6DFvNNtx+9ybjezNCa8XF0xaYcETyp6rHWU=
git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
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/MetaCubeX/wintun-go v0.0.0-20220319102620-bbc5e6b2015e h1:GRfT5Lf8HP7RNczKIwTYLoCh1PPuIs/sY9hj+W+3deg=
github.com/MetaCubeX/wintun-go v0.0.0-20220319102620-bbc5e6b2015e/go.mod h1:ARUuShAtcziEJ/vnZ2hgoP+zc0J7Ukcca2S/NPDoQCc=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/MetaCubeX/hysteria v1.0.5-0.20220607074613-210c46c75b15 h1:SraqLzYEGfrV8ETkVYc5evvCrn95hMFdCtcXXP8bA9Y=
github.com/MetaCubeX/hysteria v1.0.5-0.20220607074613-210c46c75b15/go.mod h1:bXVjOca4Xf3JRenwuPKu02XaOiZwejrMSlgsu/U88J4=
github.com/MetaCubeX/netlink v1.2.0-beta.0.20220529072258-d6853f887820 h1:fGKWZ25VApYnuPZoNeqdH/nZtHa2XMajwH6Yj/OgoVc=
github.com/MetaCubeX/netlink v1.2.0-beta.0.20220529072258-d6853f887820/go.mod h1:twkDnbuQxJYemMlGd4JFIcuhgX83tXhKS2B/PRMpOho=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g=
github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE=
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cheekybits/genny v1.0.0 h1:uGGa4nei+j20rOSeDeP5Of12XVm7TGUd4dJA9RDitfE=
github.com/cheekybits/genny v1.0.0/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/coreos/go-iptables v0.6.0 h1:is9qnZMPYjLd8LYqmm/qlE+wwEgJIkTYdhV3rfZo4jk=
github.com/coreos/go-iptables v0.6.0/go.mod h1:Qe8Bv2Xik5FyTXwgIbLAnv2sWSBmvWdFETJConOQ//Q=
github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
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=
@ -26,13 +76,17 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
github.com/dlclark/regexp2 v1.4.0 h1:F1rxgk7p4uKjwIQxBs9oAXe5CqrXlCduYEJvrF4u93E=
github.com/dlclark/regexp2 v1.4.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/fanliao/go-promise v0.0.0-20141029170127-1890db352a72/go.mod h1:PjfxuH4FZdUyfMdtBio2lsRr1AKEaVPwelzuHuh8Lqc=
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiDsoyrBGkyDY=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/fsnotify/fsnotify v1.5.1 h1:mZcQUHVQUQWoPXXtuf9yuEXKudkV2sx1E06UadKWpgI=
github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU=
github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI=
github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
github.com/go-chi/chi/v5 v5.0.7 h1:rDTPXLDHGATaeHvVlLcR4Qe0zftYethFucbjVQ1PxU8=
@ -42,63 +96,122 @@ github.com/go-chi/cors v1.2.1/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vz
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/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I=
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
github.com/gofrs/uuid v4.2.0+incompatible h1:yyYWMnhkhrKwwr8gAOcOCYxOOscHgDS9yZgBrnJfGa0=
github.com/gofrs/uuid v4.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4=
github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ=
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8=
github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY=
github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg=
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
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/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc=
github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/hugelgupf/socketpair v0.0.0-20190730060125-05d35a94e714/go.mod h1:2Goc3h8EklBH5mspfHFxBnEoURQCGzQQH1ga9Myjvis=
github.com/insomniacslk/dhcp v0.0.0-20220405050111-12fbdcb11b41 h1:Yg3n3AI7GoHnWt7dyjsLPU+TEuZfPAg0OdiA3MJUV6I=
github.com/insomniacslk/dhcp v0.0.0-20220405050111-12fbdcb11b41/go.mod h1:h+MxyHxRg9NH3terB1nfRIUaQEcI0XOVkdR9LNBlp8E=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
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/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU=
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
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/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.0.12 h1:p9dKCg8i4gmOxtv35DvrYoWqYzQrvEVdjQ762Y0OqZE=
github.com/klauspost/cpuid/v2 v2.0.12/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
@ -106,8 +219,8 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/pty v1.1.3/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/lucas-clemente/quic-go v0.27.0 h1:v6WY87q9zD4dKASbG8hy/LpzAVNzEQzw8sEIeloJsc4=
github.com/lucas-clemente/quic-go v0.27.0/go.mod h1:AzgQoPda7N+3IqMMMkywBKggIFo2KT6pfnlrQ2QieeI=
github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40 h1:EnfXoSqDfSNJv0VBNqY/88RNnhSGYkrHaO0mmFGbVsc=
github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40/go.mod h1:vy1vK6wD6j7xX6O6hXe621WabdtNkou2h7uRtTfRMyg=
github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI=
github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/marten-seemann/qpack v0.2.1/go.mod h1:F7Gl5L1jIgN1D11ucXefiuJS9UMVP2opoCp2jDKb7wc=
@ -117,6 +230,7 @@ github.com/marten-seemann/qtls-go1-17 v0.1.1 h1:DQjHPq+aOzUeh9/lixAGunn6rIOQyWCh
github.com/marten-seemann/qtls-go1-17 v0.1.1/go.mod h1:C2ekUKcDdz9SDWxec1N/MvcXBpaX9l3Nx67XaR84L5s=
github.com/marten-seemann/qtls-go1-18 v0.1.1 h1:qp7p7XXUFL7fpBvSS1sWD+uSqPvzNQK43DH+/qEkj0Y=
github.com/marten-seemann/qtls-go1-18 v0.1.1/go.mod h1:mJttiymBAByA49mhlNZZGrH5u1uXYZJ+RW28Py7f4m4=
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
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=
@ -126,10 +240,15 @@ github.com/mdlayher/netlink v1.1.1/go.mod h1:WTYpFb/WTvlRJAyKhZL5/uy69TDDpHHu2VZ
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/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4=
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/miekg/dns v1.1.49 h1:qe0mQU3Z/XpFeE+AEBo2rqaS1IPBJ3anmqZ4XiZJVG8=
github.com/miekg/dns v1.1.49/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo=
github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
@ -151,15 +270,45 @@ github.com/oschwald/geoip2-golang v1.7.0 h1:JW1r5AKi+vv2ujSxjKthySK3jo8w8oKWPyXs
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/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
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/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=
github.com/prometheus/client_golang v1.12.2 h1:51L9cDoUHVrXx4zWYlcLQIZ+d+VXHgqnYKkIuq4g/34=
github.com/prometheus/client_golang v1.12.2/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M=
github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc=
github.com/prometheus/common v0.32.1 h1:hWIdL3N2HoUx3B8j3YN9mWor0qhY/NlEKZEaXxuIRh4=
github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls=
github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0VU=
github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
github.com/sagernet/sing v0.0.0-20220609123159-a93588755159 h1:G3fww5jjADkHWi6yDOEzkZbQ6lnrytv0mKesBtEslxo=
github.com/sagernet/sing v0.0.0-20220609123159-a93588755159/go.mod h1:w2HnJzXKHpD6F5Z/9XlSD4qbcpHY2RSZuQnFzqgELMg=
github.com/sagernet/sing-shadowsocks v0.0.0-20220609092835-699292971c13 h1:bQN0hjTHdB7SyaD9yjEYAl+bDl/kXW9zC0xNa+LMTrA=
github.com/sagernet/sing-shadowsocks v0.0.0-20220609092835-699292971c13/go.mod h1:Fp/9+odJhtgDmiHbZClMLnxaVvmDRJxwA7u/+uXWDiQ=
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
github.com/shurcooL/component v0.0.0-20170202220835-f88ec8f54cc4/go.mod h1:XhFIlyj5a1fBNx5aJTbKoIq0mNaPvOagO+HjB3EtxrY=
github.com/shurcooL/events v0.0.0-20181021180414-410e4ca65f48/go.mod h1:5u70Mqkb5O5cxEA8nxTsgrgLehJeAw6Oc4Ab1c/P1HM=
@ -183,6 +332,9 @@ github.com/shurcooL/reactions v0.0.0-20181006231557-f2e0b4ca5b82/go.mod h1:TCR1l
github.com/shurcooL/sanitized_anchor_name v0.0.0-20170918181015-86672fcb3f95/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/shurcooL/users v0.0.0-20180125191416-49c67e49c537/go.mod h1:QJTqeLYEDaXHZDBsXlPCDqdhQuJkuw4NOtaxYe3xii4=
github.com/shurcooL/webdavfs v0.0.0-20170829043945-18c3829fa133/go.mod h1:hKmq5kWdCj2z2KEozexVbfEZIWiTjhE0+UjmZgPqehw=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
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=
@ -190,45 +342,95 @@ github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9
github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE=
github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod h1:HuIsMU8RRBOtsCgI77wP899iHVBQpCmg4ErYMZB+2IA=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/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.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1/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/stretchr/testify v1.7.2 h1:4jaiDzPyXQvSd7D0EjG45355tLlV3VOECpq10pLC+8s=
github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA=
github.com/tobyxdd/quic-go v0.27.1-0.20220512040129-ed2a645d9218 h1:0DEghzcIfYe+7HTuI+zEd/5M+5c/gcepjJWGdcPPIrc=
github.com/tobyxdd/quic-go v0.27.1-0.20220512040129-ed2a645d9218/go.mod h1:AzgQoPda7N+3IqMMMkywBKggIFo2KT6pfnlrQ2QieeI=
github.com/txthinking/runnergroup v0.0.0-20210608031112-152c7c4432bf h1:7PflaKRtU4np/epFxRXlFhlzLXZzKFrH5/I4so5Ove0=
github.com/txthinking/runnergroup v0.0.0-20210608031112-152c7c4432bf/go.mod h1:CLUSJbazqETbaR+i0YAhXBICV9TrKH93pziccMhmhpM=
github.com/txthinking/socks5 v0.0.0-20220212043548-414499347d4a h1:BOqgJ4jku0LHPDoR51RD8Mxmo0LHxCzJT/M9MemYdHo=
github.com/txthinking/socks5 v0.0.0-20220212043548-414499347d4a/go.mod h1:7NloQcrxaZYKURWph5HLxVDlIwMHJXCPkeWPtpftsIg=
github.com/txthinking/x v0.0.0-20210326105829-476fab902fbe h1:gMWxZxBFRAXqoGkwkYlPX2zvyyKNWJpxOxCrjqJkm5A=
github.com/txthinking/x v0.0.0-20210326105829-476fab902fbe/go.mod h1:WgqbSEmUYSjEV3B1qmee/PpP2NYEz4bL9/+mF1ma+s4=
github.com/u-root/uio v0.0.0-20210528114334-82958018845c/go.mod h1:LpEX5FO/cB+WF4TYGY1V5qktpaZLkKkSegbr0V4eYXA=
github.com/u-root/uio v0.0.0-20220204230159-dac05f7d2cb4 h1:hl6sK6aFgTLISijk6xIzeqnPzQcsLqqvL6vEfTPinME=
github.com/u-root/uio v0.0.0-20220204230159-dac05f7d2cb4/go.mod h1:LpEX5FO/cB+WF4TYGY1V5qktpaZLkKkSegbr0V4eYXA=
github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU=
github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM=
github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0=
github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 h1:gga7acRE695APm9hlsSMoOoE65U4/TcqNj90mc69Rlg=
github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0=
github.com/xtls/go v0.0.0-20210920065950-d4af136d3672 h1:4mkzGhKqt3JO1BWYjtD3iRFyAx4ow67hmSqOcGjuxqQ=
github.com/xtls/go v0.0.0-20210920065950-d4af136d3672/go.mod h1:YGGVbz9cOxyKFUmhW7LGaLZaMA0cPlHJinvAmVxEMSU=
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
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.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
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.5.1 h1:e1YG66Lrk73dn4qhg8WFSvhF0JuFQF0ERIp4rpuV8Qk=
go.uber.org/automaxprocs v1.5.1/go.mod h1:BF4eumQw0P9GtnuxxovUd06vwm1o18oMzFtK66vU6XU=
go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE=
golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4 h1:kUhD7nTDoI3fVd9G4ORWrbV5NY0liEs/Jg2pv5f+bBA=
golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e h1:T8NU3HyQ8ClP4SEE+KbFlg6n0NhuTsN4MyznaarGsZM=
golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20220414153411-bcd21879b8fd h1:zVFyTKZN/Q7mNRWSs1GOYnHM9NiFSJ54YVRsD0rNWT4=
golang.org/x/exp v0.0.0-20220414153411-bcd21879b8fd/go.mod h1:lgLbSvA5ygNOMpwM/9anMpWVlVJ7Z+cHWq/eFuinpGE=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
golang.org/x/exp v0.0.0-20220608143224-64259d1afd70 h1:8uGxpY2cLF9H/NSHUiEWUIBZqIcsMzMWIMPCCUkyYgc=
golang.org/x/exp v0.0.0-20220608143224-64259d1afd70/go.mod h1:yh0Ynu2b5ZUe3MQfp2nM0ecK7wsgouWTDN0FNeJuIys=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 h1:kQgndtyPBW/JIYERgdxfwMYh3AVStj88WQTlNDi2a+o=
@ -238,75 +440,134 @@ golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73r
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181029044818-c44066c5c816/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181106065722-10aee1819953/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190313220215-9f648a60d977/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190419010253-1f3472d942ba/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191007182048-72f939374954/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/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-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220421235706-1d1ef9303861 h1:yssD99+7tqHWO5Gwh81phT+67hg+KttniBr6UnEXOY8=
golang.org/x/net v0.0.0-20220421235706-1d1ef9303861/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220607020251-c690dde0001d h1:4SFsTMi4UahlKoloni7L4eYzhFRifURQLw+yv0QDCx8=
golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/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-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f h1:Ax0t5p6N38Ga0dThY21weqDEyz2oklo4IvDkpigvkD8=
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181029174526-d69651ed3497/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190316082340-a2f829d7f35f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190411185658-b44545bcd369/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190418153312-f0ce4c0180be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190606122018-79a91cf218c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/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-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200728102440-3e129f6d46b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/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=
golang.org/x/sys v0.0.0-20201009025420-dfb3f7c4e634/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201101102859-da207088b7d1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
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-20210603081109-ebe580a85c40/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-20220422013727-9388b58f7150 h1:xHms4gcpe1YE7A3yIllJXP16CMAGuqwO2lX1mTyyRRc=
golang.org/x/sys v0.0.0-20220422013727-9388b58f7150/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220608164250-635b8c9b7f68 h1:z8Hj/bl9cOV2grsOpEaQFUaly0JWN3i97mo3jXKJNp0=
golang.org/x/sys v0.0.0-20220608164250-635b8c9b7f68/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
@ -316,6 +577,8 @@ golang.org/x/text v0.3.8-0.20220124021120-d1c84af989ab h1:eHo2TTVBaAPw9lDGK2Gb9G
golang.org/x/text v0.3.8-0.20220124021120-d1c84af989ab/go.mod h1:EFNZuWvGYxIRUEX+K8UmCFwYmZjqcrnq15ZuVldZkZ0=
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20220411224347-583f2d630306 h1:+gHMid33q6pen7kv9xvT+JRinntgeXO2AeZVd0AWD3w=
golang.org/x/time v0.0.0-20220411224347-583f2d630306/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
@ -323,9 +586,44 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm
golang.org/x/tools v0.0.0-20181030000716-a0a13e073c7b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
@ -335,41 +633,109 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f h1:GGU+dLjvlC3qDwqYgL6UgRmHXhOOgns0bZu2Ty5mm6U=
golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.zx2c4.com/wireguard v0.0.0-20220407013110-ef5c587f782d h1:q4JksJ2n0fmbXC0Aj0eOs6E0AcPqnKglxWXWFqGD6x0=
golang.zx2c4.com/wireguard v0.0.0-20220407013110-ef5c587f782d/go.mod h1:bVQfyl2sCM/QIIGHpWbFGfHPuDvqnCNkT6MQLTCjO/U=
golang.zx2c4.com/wireguard/windows v0.5.4-0.20220317000008-6432784c2469 h1:SEYkJAIuYAsSAPkCffOiYLtq5brBDSI+L0mRjSsvSTY=
golang.zx2c4.com/wireguard/windows v0.5.4-0.20220317000008-6432784c2469/go.mod h1:1CeiatTZwcwSFA3cAtMm8CQoroviTldnxd7DOgM/vI4=
golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df h1:5Pf6pFKu98ODmgnpvkJ3kFUOQGGLIzLIkbzUHp47618=
golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=
golang.zx2c4.com/wintun v0.0.0-20211104114900-415007cec224 h1:Ug9qvr1myri/zFN6xL17LSCBGFDnphBBhzmILHsM5TY=
golang.zx2c4.com/wintun v0.0.0-20211104114900-415007cec224/go.mod h1:deeaetjYA+DHMHg+sMSMI58GrEteJUUzzw7en6TJQcI=
golang.zx2c4.com/wireguard v0.0.0-20220601130007-6a08d81f6bc4 h1:QlbNZ9SwDAepRQwgeWHLi3rfEMo/kVEU4SmgsNM7HmQ=
golang.zx2c4.com/wireguard v0.0.0-20220601130007-6a08d81f6bc4/go.mod h1:bVQfyl2sCM/QIIGHpWbFGfHPuDvqnCNkT6MQLTCjO/U=
golang.zx2c4.com/wireguard/windows v0.5.4-0.20220328111914-004c22c5647e h1:yV04h6Tx19uDR6LvuEbR19cDU+3QrB9LuGjtF7F5G0w=
golang.zx2c4.com/wireguard/windows v0.5.4-0.20220328111914-004c22c5647e/go.mod h1:1CeiatTZwcwSFA3cAtMm8CQoroviTldnxd7DOgM/vI4=
google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
google.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
google.golang.org/api v0.1.0/go.mod h1:UGEZY7KEX120AnNLIHFMKIo4obdJhkp2tPbaPlQx13Y=
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=
google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20181029155118-b69ba1387ce2/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20181202183823-bd91e49a0898/go.mod h1:7Ep/1NZk928CDR8SjdVbjWNpdIf6nzjE3BTgJDr2Atg=
google.golang.org/genproto v0.0.0-20190306203927-b5d61aea6440/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA=
google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio=
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw=
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
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/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
@ -377,17 +743,28 @@ gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWD
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0/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/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=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o=
gvisor.dev/gvisor v0.0.0-20220422224113-2cca6b79d9f4 h1:CSkd548jw5hmVwdJ+JuUhMtRV56oQBER7sbkIOePP2Y=
gvisor.dev/gvisor v0.0.0-20220422224113-2cca6b79d9f4/go.mod h1:tWwEcFvJavs154OdjFCw78axNrsDlz4Zh8jvPqwcpGI=
gvisor.dev/gvisor v0.0.0-20220527053002-8ab279227ac8 h1:K6RgHqNR+9t3sKVsfRFsvXryRL5kL6wtBPU5aPt1jLY=
gvisor.dev/gvisor v0.0.0-20220527053002-8ab279227ac8/go.mod h1:TIvkJD0sxe8pIob3p6T8IzxXunlp6yfgktvTNp+DGNM=
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
lukechampine.com/blake3 v1.1.7 h1:GgRMhmdsuK8+ii6UZFDL8Nb+VyMwadAgcJyfYHxG6n0=
lukechampine.com/blake3 v1.1.7/go.mod h1:tkKEOtDkNtklkXtLNEOGNq5tcV90tJiA1vAA12R78LA=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
sourcegraph.com/sourcegraph/go-diff v0.5.0/go.mod h1:kuch7UrkMzY0X+p9CRK03kfuPQ2zzQcaEFbx8wA8rck=
sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0=

View File

@ -0,0 +1,5 @@
//go:build !386 && !amd64 && !arm64 && !arm64be && !mipsle && !mips
package executor
const concurrentCount = 5

Some files were not shown because too many files have changed in this diff Show More