Compare commits

...

287 Commits

Author SHA1 Message Date
584b81e507 [Chore] workflows 2022-04-02 19:02:43 +08:00
6596db7257 [Chore] workflows 2022-04-02 19:01:28 +08:00
908ca20afa fix: dns over proxy may due to cancel request, but proxy live status is fine 2022-04-02 18:24:11 +08:00
88e4b3575e [Chore] fallback dependency 2022-03-31 00:26:01 +08:00
559b3ff9f3 [Fix] VLESS http conn with tls false
[Chore] Upgrade Dependencies
2022-03-31 00:08:43 +08:00
127634028d Merge remote-tracking branch 'Meta/Alpha' into Alpha 2022-03-30 13:19:05 +08:00
81c5a65f23 Merge remote-tracking branch 'Pro-Plus/with-tun' into Alpha
# Conflicts:
#	README.md
#	adapter/outbound/trojan.go
#	adapter/outbound/vless.go
#	transport/trojan/trojan.go
2022-03-30 13:15:45 +08:00
591ee119c2 docs: warning 2022-03-30 13:05:46 +08:00
5b03cc56e7 Merge remote-tracking branch 'Clash-dev/dev' into Alpha 2022-03-30 12:41:16 +08:00
c4216218c8 Merge pull request #24 from MarksonHon/patch-2
Fix systemd service
2022-03-29 14:53:02 +08:00
63840b3358 Fix systemd service 2022-03-29 14:50:12 +08:00
045dd0589b fix: classical missing count 2022-03-28 21:04:50 +08:00
705311b70e [Chore]修改workflows 2022-03-28 20:52:09 +08:00
55ce40fbd1 [Chore]升级项目依赖
[Chore]隐藏TUN模式在system堆栈启动时弹窗
2022-03-28 20:44:52 +08:00
07fda93111 [Chore]升级项目依赖
[Chore]隐藏TUN模式在system堆栈启动时弹窗
2022-03-28 19:48:32 +08:00
012e044c54 [Chore]完成调试workflows 2022-03-28 19:02:51 +08:00
b323315583 [Chore]调试workflows 2022-03-28 18:58:23 +08:00
4c10d6e212 [Chore]调试workflows 2022-03-28 18:54:00 +08:00
ece3bb360a [Chore]调试workflows 2022-03-28 18:52:19 +08:00
5a7b9bdf45 [Chore]调试workflows 2022-03-28 18:49:24 +08:00
028ecb70c5 [Chore]调整workflows流程2 2022-03-28 18:44:27 +08:00
4e0b22f42d [Chore]调整workflows流程2 2022-03-28 18:41:30 +08:00
dbd27ef910 [Chore]调整workflows流程 2022-03-28 17:07:11 +08:00
ffff1418f2 [Fixed]尝试修复PASS空指针问题
[Chore]调整workflows测试
2022-03-28 16:36:34 +08:00
64a5fd02da Merge remote-tracking branch 'tun/with-tun' into Alpha 2022-03-28 10:51:59 +08:00
611ce5f5f1 [commit]
[Feat] add Pass type for support temporary skip rule set
2022-03-27 23:44:51 +08:00
0a0b8074f4 refactor: rule-set and its provider 2022-03-26 20:27:41 +08:00
f66c3b6f86 [Bilud]
正常编译
2022-03-26 16:39:50 +08:00
a3d49d1ed4 Merge remote-tracking branch 'dev/dev' into Alpha 2022-03-26 16:27:17 +08:00
0d068e7b5f [Fixed]
弃用过期函数,修复Process Name获取问题
2022-03-26 16:17:44 +08:00
24583009c4 Merge remote-tracking branch 'tun/with-tun' into Alpha 2022-03-25 14:20:05 +08:00
a593d68c42 build test 2022-03-24 23:42:49 +08:00
520657e953 [Fix] use direct to update http providers when proxy 寄 2022-03-24 12:34:45 +08:00
6c64164bee [skip ci] [Fix] ban auto set iptables when tun is enabled 2022-03-23 20:37:46 +08:00
9b4ddbed2c [skip ci] [Pre] avoid npe 2022-03-23 13:48:21 +08:00
79d984ee8e [Fix] url-test npe 2022-03-23 13:29:51 +08:00
7a54d616c4 [SKIP CI]
Merge remote-tracking branch 'Pro-Plus/with-tun' into Alpha

# Conflicts:
#	README.md
#	hub/route/server.go
2022-03-23 13:23:34 +08:00
f19b67fe9d bypass support for auto-iptables 2022-03-23 11:36:13 +08:00
91e83ea955 delete useless field 2022-03-23 10:18:26 +08:00
a375b85fa0 [skip ci]
# Conflicts:
#	.github/workflows/linter.yml
#	.github/workflows/release.yml
#	config/config.go
#	go.mod
#	go.sum
#	hub/executor/executor.go
2022-03-23 01:41:42 +08:00
4cc661920e [Fix] redir-host use host not ip 2022-03-22 23:31:23 +08:00
b5f6f26de4 Update version.go
[BUILD TEST]
2022-03-22 01:39:00 +08:00
e068563b58 Merge pull request #22 from Adlyq/Alpha-pr
[skip ci]
[Fix] skip when country code not found in GeoIP.dat
2022-03-22 00:33:02 +08:00
bf6839e5f3 Merge pull request #23 from Adlyq/Alpha-pr-iptabls
[skip ci] auto change interface for tproxy
2022-03-22 00:32:47 +08:00
e0040b7e5d [Fix] do not monitor when auto-iptables is false 2022-03-21 20:29:07 +08:00
3beb71b6e1 auto change interface for tproxy 2022-03-21 19:51:27 +08:00
668d29d91f init sequence adjustment 2022-03-21 19:47:21 +08:00
5386c3903d delete useless code 2022-03-21 18:09:36 +08:00
6a4d2b3368 Change type conversion method 2022-03-21 12:34:32 +08:00
d9d8507c8f [Fix] skip when country code not found in GeoIP.dat 2022-03-21 12:24:39 +08:00
5b7f46bc97 [skip ci][内容]
1.调整部分代码
2022-03-20 02:39:48 +08:00
d1838f663e Merge remote-tracking branch 'yaling888/with-tun' into Alpha
# Conflicts:
#	listener/tun/tun_adapter.go
2022-03-19 22:37:51 +08:00
2d1c031ce0 [skip ci][内容]
1.修复部分空指针问题
2.修改go.mod
2022-03-19 22:28:28 +08:00
e67f94b87a [内容]
同步至最新v1.10.0
2022-03-19 15:01:49 +08:00
2df890c4ee Merge remote-tracking branch 'clash/dev' into Alpha
# Conflicts:
#	Makefile
2022-03-19 14:53:47 +08:00
520256365e [内容]
1.wintun.dll 0.14.1
2022-03-19 01:54:21 +08:00
9270d3c475 [内容]
1.autoIptables 开关
2.go.mod 调整
3.processName 调整
4.makefile 调整
5.Tun模块 部分代码调整
2022-03-19 01:11:27 +08:00
c8b1050c15 Merge pull request #19 from Adlyq/Alpha-pr
[skip ci]Only prompt when interface cannot be found
2022-03-18 21:45:50 +08:00
39de5d58c8 Only prompt when interface cannot be found 2022-03-18 17:41:06 +08:00
a38f30ec3b Merge pull request #18 from Adlyq/Alpha
[Fix] Process name display for Android
2022-03-18 13:20:35 +08:00
2ea92d70f9 Merge remote-tracking branch 'upstream/Alpha' into Alpha 2022-03-18 12:38:16 +08:00
ea2e715da9 Merge remote-tracking branch 'origin/Alpha' into Alpha
# Conflicts:
#	go.mod
#	go.sum
2022-03-18 02:36:09 +08:00
1350330fe0 1.fix module package
2.fix govet error
2022-03-18 02:35:15 +08:00
317797acc8 1.fix module package
2.fix govet error
2022-03-18 01:25:59 +08:00
8766764d49 fix 2022-03-18 00:40:39 +08:00
b8d48e1618 Merge remote-tracking branch 'upstream/Alpha' into Alpha 2022-03-18 00:33:27 +08:00
f972d1fa58 update 2022-03-18 00:27:48 +08:00
df78ba8fa6 update 2022-03-18 00:24:38 +08:00
0c83575302 Merge remote-tracking branch 'upstream/Alpha' into Alpha 2022-03-18 00:10:37 +08:00
e9151bc43f update 2022-03-17 23:57:58 +08:00
68345b6a19 Merge remote-tracking branch 'upstream/Alpha' into Alpha 2022-03-17 23:40:51 +08:00
435bee0ca2 update 2022-03-17 23:24:07 +08:00
92d169ca81 [Fix] Process name display for Android 2022-03-17 20:31:16 +08:00
30f1b29257 Merge remote-tracking branch 'yaling888/with-tun' into Alpha
# Conflicts:
#	.github/workflows/codeql-analysis.yml
#	.github/workflows/linter.yml
#	.github/workflows/release.yml
#	Makefile
#	README.md
#	adapter/outbound/vless.go
#	component/geodata/memconservative/cache.go
#	component/geodata/router/condition.go
#	component/geodata/router/condition_geoip.go
#	component/geodata/standard/standard.go
#	component/geodata/utils.go
#	config/config.go
#	config/initial.go
#	constant/metadata.go
#	constant/path.go
#	constant/rule.go
#	constant/rule_extra.go
#	dns/client.go
#	dns/filters.go
#	dns/resolver.go
#	go.mod
#	go.sum
#	hub/executor/executor.go
#	hub/route/configs.go
#	listener/listener.go
#	listener/tproxy/tproxy_linux_iptables.go
#	listener/tun/dev/dev.go
#	listener/tun/dev/dev_darwin.go
#	listener/tun/dev/dev_linux.go
#	listener/tun/dev/dev_windows.go
#	listener/tun/dev/wintun/config.go
#	listener/tun/dev/wintun/dll_windows.go
#	listener/tun/dev/wintun/session_windows.go
#	listener/tun/dev/wintun/wintun_windows.go
#	listener/tun/ipstack/commons/dns.go
#	listener/tun/ipstack/gvisor/tun.go
#	listener/tun/ipstack/gvisor/tundns.go
#	listener/tun/ipstack/gvisor/utils.go
#	listener/tun/ipstack/stack_adapter.go
#	listener/tun/ipstack/system/dns.go
#	listener/tun/ipstack/system/tcp.go
#	listener/tun/ipstack/system/tun.go
#	listener/tun/tun_adapter.go
#	main.go
#	rule/common/base.go
#	rule/common/domain.go
#	rule/common/domain_keyword.go
#	rule/common/domain_suffix.go
#	rule/common/final.go
#	rule/common/geoip.go
#	rule/common/geosite.go
#	rule/common/ipcidr.go
#	rule/common/port.go
#	rule/parser.go
#	rule/process.go
#	test/go.mod
#	test/go.sum
#	transport/vless/xtls.go
#	tunnel/tunnel.go
2022-03-17 17:41:02 +08:00
c503e44324 Merge pull request #17 from Adlyq/Alpha
[Fix] Parse
2022-03-17 12:28:45 +08:00
ce509295c0 [Fix] Parse 2022-03-17 12:26:43 +08:00
f671d6a1fd [Fix] Parse 2022-03-17 12:23:50 +08:00
e194efcecb Migration: go 1.18 2022-03-17 01:51:28 +08:00
609d69191a Merge remote-tracking branch 'clash/dev' into Alpha
# Conflicts:
#	.github/workflows/docker.yml
#	adapter/outboundgroup/fallback.go
#	adapter/outboundgroup/loadbalance.go
#	adapter/outboundgroup/relay.go
#	adapter/outboundgroup/selector.go
#	adapter/outboundgroup/urltest.go
#	config/config.go
#	go.mod
#	go.sum
#	main.go
#	test/go.mod
#	test/go.sum
2022-03-17 01:41:51 +08:00
c791044ddf Merge remote-tracking branch 'origin/Alpha' into Alpha 2022-03-17 00:12:26 +08:00
dc2abe6eeb [Build test] 1.18
[Updata] wintun.dll
2022-03-17 00:12:11 +08:00
1071e3f4a3 [Build test] 1.18
[Updata] wintun.dll
2022-03-17 00:02:22 +08:00
acc249495d [Build test] 1.18 2022-03-16 23:30:29 +08:00
5a2cc9a36f [Fix] 优化geodata初始化逻辑 2022-03-16 23:09:05 +08:00
1cc6cfab9c [Fix] 优化geodata初始化逻辑 2022-03-16 23:02:16 +08:00
0183d752a0 [Fix] 优化geodata初始化逻辑 2022-03-16 22:55:18 +08:00
2f24e49ff6 [build test] 1.18 2022-03-16 21:47:00 +08:00
016862f7a5 [build test]1.18 2022-03-16 17:54:44 +08:00
c3df768f79 [build test] 2022-03-16 17:33:08 +08:00
0f2123179a [build test] 2022-03-16 17:29:09 +08:00
1034780e8e [build test] 2022-03-16 00:43:08 +08:00
f01ac69654 Merge remote-tracking branch 'clash/dev' into Alpha
# Conflicts:
#	.github/workflows/codeql-analysis.yml
#	.github/workflows/docker.yml
#	.github/workflows/linter.yml
#	.github/workflows/stale.yml
#	Makefile
#	component/dialer/dialer.go
#	config/config.go
#	constant/metadata.go
#	constant/rule.go
#	rule/common/domain.go
#	rule/common/domain_keyword.go
#	rule/common/domain_suffix.go
#	rule/common/final.go
#	rule/common/ipcidr.go
#	rule/geoip.go
#	rule/parser.go
#	rule/port.go
#	rule/process.go
2022-03-15 23:13:41 +08:00
c85305ead8 [Skip CI] 2022-03-15 22:25:33 +08:00
3e89bee524 [Skip CI] 2022-03-15 11:47:42 +08:00
68fccfacc0 [Skip CI] 2022-03-15 02:20:19 +08:00
cf52fbed65 [Skip CI] 2022-03-15 02:06:57 +08:00
a924819fbf [Fixed] rule-set of classical allow adding GEOIP 2022-03-14 21:48:36 +08:00
13c82754ff [Fixed] show rule count when parse failed 2022-03-14 21:43:58 +08:00
002163f07b [Fixed] memory leak 2022-03-13 18:35:55 +08:00
9c5b184db6 [Fixed] handle network protocol[0] panic (not pretty) 2022-03-13 18:34:49 +08:00
3ab784dd80 Merge pull request #16 from Dabrit/test
[Skip CI]README Improvements
2022-03-05 09:03:25 +08:00
f1c4d85eb3 Update README.md 2022-03-05 01:44:48 +08:00
b9fc393f95 Naming edited 2022-03-05 01:33:11 +08:00
557347d366 Merge pull request #15 from Dabrit/test
Optimize reading experience of linux users
2022-03-04 23:25:02 +08:00
a7f3b85200 Edit username to adapt Linux username naming rule 2022-03-04 22:36:15 +08:00
7550067fde [Fixed] skip maybe invaild ip data packet 2022-03-04 22:32:33 +08:00
076a0840bf [Fixed] domian or ipcidr is used before initialization 2022-03-04 22:32:25 +08:00
5ebcc526de [Fixed] match not some ip in ipcidr provider 2022-03-04 22:32:25 +08:00
3772ad8ddb Revise mismatching targets from README. 2022-03-04 22:22:49 +08:00
5ad7237fa7 Merge pull request #14 from Adlyq/Alpha
Fix the filter under proxy-group to filter other groups
2022-02-27 00:34:08 +08:00
49e25f502f Merge pull request #11 from ttyykpe/patch-1
Makefile add android-armv8
2022-02-27 00:33:58 +08:00
06942c67fd Fix the filter under proxy-group to filter other groups 2022-02-23 16:17:29 +08:00
9259c9f3ff Makefile add android-armv8 2022-02-21 18:04:38 +08:00
37cf166d14 Merge pull request #10 from Adlyq/Alpha
Full regexp support
2022-02-16 23:10:07 +08:00
27292dac0c Replace the regular implementation of the filter for proxy-providers and proxy-groups with regex2 2022-02-16 22:18:05 +08:00
847c91503b [build] 2022-02-06 05:08:11 +08:00
ca8ed0a01b [Fix]GeoSite.dat initial in logic rule 2022-02-06 04:41:34 +08:00
46dc262e8e 合并拉取请求 #9
add the doc of local build
2022-02-06 04:34:08 +08:00
7465eaafa1 [Fix]GeoSite.dat initial in logic rule 2022-02-06 04:30:54 +08:00
d70cfefde7 add the doc of local build 2022-02-06 04:02:26 +08:00
52c37f7140 Merge pull request #8 from qzi/Dev
add trojan xtls sample
2022-02-06 03:52:41 +08:00
180bce2940 add trojan xtls sample 2022-02-06 03:37:40 +08:00
4a446c4e31 [build] 2022-02-06 01:59:35 +08:00
d7f5e8d3de [Skip CI] 2022-02-06 00:56:13 +08:00
0a180eeb40 忽略geosite文件大小写 2022-02-06 00:51:37 +08:00
7ff48ea42d [build] 2022-02-05 22:05:20 +08:00
a0e44f4041 [FEAT]
1.Add geodata loader mode switch
yaml   geodata-loader: memconservative / standard
2.Add AutoIptables mode switch
yaml   auto-iptables: true
3.support trojan xtls
4.update gvisor
5.Fix process
6.Fix darwin autoRoute
2022-02-05 21:33:49 +08:00
2f6f9ebc2e Merge branch 'Dev' into Meta
# Conflicts:
#	config/config.go
2022-02-05 19:30:12 +08:00
28a1475f66 [FEAT] Add geodata loader mode switch 2022-02-05 02:42:49 +08:00
c28f42d823 [FEAT] Add geodata loader mode switch 2022-02-05 00:51:06 +08:00
2bf34c766e [Feat]
support trojan xtls
change geodataloader mode as memconservative
2022-02-04 23:33:36 +08:00
35b19c3d7f Merge branch 'Dev' into Feature
# Conflicts:
#	Makefile
2022-02-04 18:44:35 +08:00
90e6ed4612 [Fixed] Fixed clash process name is Clash.Meta 2022-02-04 17:38:06 +08:00
ae5a790510 [Fixed] Abnormal rule when host is ip addr 2022-02-04 17:38:06 +08:00
3b277aa8ec [Feat]
update gvisor
Chore: use "-m mark --mark" instead of "-m owner --uid-owner"
2022-02-04 06:11:24 +08:00
176eb3926b Merge remote-tracking branch 'pro-plus/plus-pro' into Feature
# Conflicts:
#	.github/workflows/Alpha.yml
#	.github/workflows/codeql-analysis.yml
#	.github/workflows/docker.yml
#	.github/workflows/linter.yml
#	.github/workflows/stale.yml
#	Makefile
#	README.md
#	adapter/outbound/vless.go
#	component/dialer/dialer.go
#	component/geodata/geodata.go
#	component/geodata/router/condition.go
#	config/config.go
#	config/initial.go
#	constant/metadata.go
#	constant/path.go
#	constant/rule.go
#	constant/rule_extra.go
#	dns/filters.go
#	go.mod
#	go.sum
#	hub/executor/executor.go
#	hub/route/configs.go
#	listener/listener.go
#	listener/tun/dev/dev.go
#	listener/tun/dev/dev_darwin.go
#	listener/tun/dev/dev_linux.go
#	listener/tun/dev/dev_windows.go
#	listener/tun/dev/dev_windows_extra.go
#	listener/tun/dev/wintun/dll_windows.go
#	listener/tun/dev/wintun/session_windows.go
#	listener/tun/ipstack/gvisor/tun.go
#	listener/tun/ipstack/gvisor/tundns.go
#	listener/tun/ipstack/stack_adapter.go
#	listener/tun/ipstack/system/tun.go
#	listener/tun/tun_adapter.go
#	main.go
#	rule/base.go
#	rule/common/process.go
#	rule/geoip.go
#	rule/parser.go
#	rule/port.go
#	test/go.mod
#	test/go.sum
#	test/vless_test.go
#	transport/vless/xtls.go
#	tunnel/tunnel.go
2022-02-04 05:30:21 +08:00
776728fb30 [Feat]
update gvisor
Chore: use "-m mark --mark" instead of "-m owner --uid-owner"
2022-02-04 04:47:40 +08:00
a732e1a603 Merge remote-tracking branch 'clash/dev' into Dev 2022-02-04 02:40:15 +08:00
1cdaf782ba Merge remote-tracking branch 'clash/dev' into Feature 2022-02-04 02:38:32 +08:00
f1157d0a09 Chore: use "-m mark --mark" instead of "-m owner --uid-owner" 2022-02-02 21:59:44 +08:00
f376409041 Chore: upgrade gvisor 2022-02-01 02:00:10 +08:00
45b3afdd33 Fix: new version golangci-lint check 2022-01-30 01:49:27 +08:00
875fdb3a5b Revert "Chore: upgrade gvisor version"
This reverts commit d633e3d96e.
2022-01-30 00:45:02 +08:00
25e115d042 Feature: process condition for rules 2022-01-28 22:52:35 +08:00
d633e3d96e Chore: upgrade gvisor version 2022-01-28 22:42:58 +08:00
6e9d837a7d Merge from remote branch 2022-01-28 19:51:40 +08:00
63b9d66365 [Feat]
1.Add DNS over QUIC support
2.Replace Country.mmdb with GeoIP.dat
3.build with Alpha tag
2022-01-27 12:45:11 +08:00
be0fadc09e [Feat]
1.Add DNS over QUIC support
2.Replace Country.mmdb with GeoIP.dat
3.build with Alpha tag
2022-01-27 12:25:53 +08:00
76dccebbf6 github action build config 2022-01-26 21:35:18 +08:00
cd5b735973 [Refactor] logic rule parse 2022-01-26 21:34:49 +08:00
9e4e1482d9 [chore] Replace Country.mmdb with GeoIP.dat 2022-01-26 12:01:14 +08:00
9974fba56e Update dev.yml 2022-01-25 21:59:48 +08:00
4bd5764c4e Update Makefile 2022-01-25 21:47:11 +08:00
deeab8b45f [test] dev build 2022-01-25 21:34:06 +08:00
af30664c51 [test] dev build 2022-01-25 21:12:49 +08:00
6962f0b7e1 [update] dev build 2022-01-25 20:54:56 +08:00
6e5859d1bf [update] dev build 2022-01-25 20:53:07 +08:00
87ca93b979 Update build.yaml 2022-01-25 20:40:03 +08:00
11052d8f77 github action add build
(cherry picked from commit bdec838673767977c14191861ac1b9a8291e2ffc)
2022-01-25 20:33:30 +08:00
a5ce62db33 Merge branch 'clash-dev' into Dev 2022-01-25 15:05:24 +08:00
2f8e575308 [Fixed] modified RULE-SET supported rule 2022-01-23 18:35:48 +08:00
62b70725ef [Fixed] GEOSITE rule load fail 2022-01-23 18:27:44 +08:00
8595d6c2e9 [Feature]
1.Add Network rule, match network type(TCP/UDP)
2.Add logic rules(NOT,OR,AND)
-AND,((DOMAIN,baidu.com),(NETWORK,UDP)),REJECT

(cherry picked from commit d7092e2e37f2c48282c878edea1b2ebc2912b09a)
2022-01-22 22:37:07 +08:00
03b956b7a3 [Fixed] auto-route support use ip route 2022-01-22 13:24:31 +08:00
e5c99cbee7 modify gitignore 2022-01-21 22:39:00 +08:00
58a47e1835 [Style] clear unless notes 2022-01-21 22:38:28 +08:00
daf83eb6f7 [Fixed] select group crash 2022-01-21 22:38:02 +08:00
bb68b59c9a Merge pull request #7 from CHIZI-0618/DnsHijack
Fix DnsHijack default value bug.
2022-01-21 18:27:26 +08:00
c3cfa3d6cd Fix DnsHijack default value bug. 2022-01-21 18:11:21 +08:00
b15344ec78 [Refactor]
1.allow maybe empty group
2.use COMPATIBLE(DIRECT alias) when proxy group is empty
3.http provider pass through tunnel
2022-01-18 21:09:36 +08:00
56c38890f9 Merge from remote branch[ssh] 2022-01-18 10:05:06 +08:00
daae846db3 Merge from remote branch 2022-01-18 09:51:20 +08:00
ee6c1871a9 [Refactor] lazy loading geosite.bat 2022-01-11 22:17:24 +08:00
00e44cd141 [Style] Modify the default configuration, tun config delete default hijack dns and modify auto-route to false. modify NameServer to 223.5.5.5 and 119.29.29.29 by Skyxim 2022-01-09 00:36:05 +08:00
4ab986cccb [Refactor] gvisor support hijack dns list
dns-hijack:
 - 1.1.1.1
 - 8.8.8.8:53
 - tcp://1.1.1.1:53
 - udp://223.5.5.5
 - 10.0.0.1:5353
2022-01-09 00:35:45 +08:00
64869d0f17 [Fixed] Remove the Linux automatic routing configuration Change the name of the Linux network card to utun 2022-01-08 16:57:59 +08:00
7f0368da66 [Style] Adjust delete routes on macos 2022-01-08 16:55:02 +08:00
4f1b227ca2 [Style] Positive health check 2022-01-08 09:23:49 +08:00
16abba385a [Style] Adjust the routing table of tun on mac 2022-01-07 22:40:05 +08:00
75b5f633cd [Fixed] Positive health check multithreading is not safe 2022-01-07 12:58:40 +08:00
8ae68552a6 [Fixed] Stupid mistakes 2022-01-06 10:49:50 +08:00
d35d6c9ac9 [Fixed] Stupid mistakes 2022-01-06 10:49:26 +08:00
a832cfdb65 [Fixed] compatible cfw 2022-01-05 19:28:54 +08:00
951a5a0eb5 [update]readme 2022-01-05 18:45:32 +08:00
89609cc4a2 [update]readme 2022-01-05 17:04:56 +08:00
bfb976bbdc [test]Add name filter to proxy group 2022-01-05 12:19:49 +08:00
a15d2535f1 升级版本号 2022-01-05 11:41:17 +08:00
610c79570a make tun config compatible with premium 2022-01-05 11:24:00 +08:00
051c81518c make tun config compatible with premium 2022-01-05 01:56:35 +08:00
0209efd423 Revert "make tun config compatible with premium"
This reverts commit ba6fdd2962.
2022-01-05 01:56:05 +08:00
ba6fdd2962 make tun config compatible with premium 2022-01-05 01:50:43 +08:00
c14dd79e69 Merge from remote branch 2022-01-05 01:46:37 +08:00
9475799615 make tun config compatible with premium 2022-01-05 00:33:42 +08:00
14917c8af1 merge clash 1.9.0 2022-01-04 17:58:50 +08:00
3bb32d12e0 Merge remote-tracking branch 'clash/dev' into Meta
# Conflicts:
#	.github/workflows/docker.yml
#	dns/server.go
#	go.mod
#	go.sum
#	hub/executor/executor.go
#	test/go.mod
#	test/go.sum
2022-01-04 17:31:07 +08:00
013b839678 [Fix] Linux Tun 2021-12-27 07:09:45 +08:00
a06382cebc [test] 2021-12-27 06:44:17 +08:00
ebc3f36236 [fix]autoIptables 2021-12-27 03:29:14 +08:00
e2a0437685 [fix] 2021-12-27 03:16:48 +08:00
82c8e02d02 [Style] Add User-Agent for provider request 2021-12-26 22:26:53 +08:00
a210ec4197 [Feature] 添加unified-delay boolean 控制延迟测试,默认为false,当设置true时忽略握手延迟,将统一延迟结果,从而利于不同协议的url-test 2021-12-26 21:20:41 +08:00
0b72395704 Merge pull request #5 from xsxun/patch-1
Update vless.go, fix udp blocked
2021-12-20 18:13:43 +08:00
8955107d6b Update vless.go 2021-12-20 12:59:06 +08:00
69aef9cec0 [Fixed] Configure tun interface on linux 2021-12-11 22:34:45 +08:00
9e44e21406 [Fixed] launch resolver an enhancer when tun mode 2021-12-09 23:00:54 +08:00
b0fdd8dc47 [Fixed] Add retry to open tun 2021-12-09 22:52:32 +08:00
e92ef587bb [Fixed] The array may be sent out of bounds 2021-12-09 22:52:32 +08:00
5657aa50cf Merge from remote branch 2021-12-09 21:38:24 +08:00
7d17d53a8f [readme] 2021-12-09 17:54:53 +08:00
58ef4ddbba [Fixed]Meaningless pointer 2021-12-07 20:49:39 +08:00
a78b89d16e Revert: Revert Redir-Host, please add fallback dns and append proxy adapter
DNS pass proxy use:
- protocol://ip:port#AdapterName
- protocol://ip:port/query#AdapterName

sure as:
- tls://1.1.1.1:853#DNS
2021-12-06 22:45:59 +08:00
833b43a538 Fixed: Does RuleSet resolve ip logic modification 2021-12-06 21:47:22 +08:00
8df3efe932 [Fix] 修正因xray服务端alpn参数为http/1.1而导致无法连接的问题 2021-12-06 00:19:03 +08:00
645c3154d6 [Fix] 修正因xray服务端alpn参数为http/1.1而导致无法连接的问题 2021-12-05 03:51:26 +08:00
a847d7b58d [Fix] 修正因xray服务端alpn参数为http/1.1而导致无法连接的问题 2021-12-05 02:18:58 +08:00
37ea8aff5c README 2021-12-05 00:48:35 +08:00
cb4ce8be6a Makefile 2021-12-04 21:43:33 +08:00
a85395e777 readme 2021-12-04 20:50:57 +08:00
819b29956b readme 2021-12-04 20:40:09 +08:00
eb999b3bf1 fix AutoIptables 2021-12-04 19:59:41 +08:00
8580ee8898 [style] 2021-12-04 17:41:13 +08:00
58552447ef [fix]Linux TProxy 2021-12-04 14:34:01 +08:00
23ca356447 Fixed: Modify the trigger condition, only if it fails successively 2021-12-04 00:16:39 +08:00
fae65b97ec fix Makefile 2021-12-03 22:13:05 +08:00
99f0231a9b style 2021-12-03 21:54:45 +08:00
edf1bb476d test 2021-12-03 20:38:40 +08:00
5c53243e81 Experimental: Positive health testing 2021-12-03 14:35:21 +08:00
b99b4ad15f Fixed:Rule-Set Supported RuleExtra 2021-12-02 23:32:30 +08:00
6369921364 Merge pull request #4 from Skyxim/meta
Feature:Supported Rule-Set
2021-12-02 23:17:02 +08:00
c6f923041f Feature:Supported Rule-Set 2021-12-02 22:56:17 +08:00
53eb3f15bb Revert "[fix]code"
This reverts commit 0431969a73.
2021-12-02 20:08:34 +08:00
b15a7c8b6f Revert "[test]"
This reverts commit bf6bfdd930.
2021-12-02 20:08:28 +08:00
038f973f90 Merge remote-tracking branch 'origin/Meta' into Meta
# Conflicts:
#	tunnel/tunnel.go
2021-12-02 18:06:47 +08:00
bf6bfdd930 [test] 2021-12-02 18:06:14 +08:00
0431969a73 [fix]code 2021-12-02 03:39:37 +08:00
c7b257b188 [style] 2021-12-01 19:25:32 +08:00
885f69b81d [style] 2021-12-01 17:08:44 +08:00
cb52682790 [style] 2021-12-01 16:51:31 +08:00
c65835d9e4 [style] embed_wintun.dll 2021-11-30 18:00:19 +08:00
92bb026f70 [style] embed_wintun.dll 2021-11-30 17:58:21 +08:00
c22c7efd07 [fix] embed_windows 2021-11-27 22:10:37 +08:00
e4b30dacd4 [fix] embed_windows 2021-11-27 21:51:38 +08:00
353ae30839 [test] embed_windows 2021-11-27 21:36:10 +08:00
828ff82ff2 [test] embed_windows 2021-11-27 21:23:34 +08:00
35cf39e415 Revert "[test] rule providers"
This reverts commit 078389f4f6.
2021-11-26 00:57:41 +08:00
340efef2d8 Revert "[test] rule providers"
This reverts commit 14af94205c.
2021-11-26 00:57:36 +08:00
796eb5c95c Revert "[test] rule providers"
This reverts commit d4cc650633.
2021-11-26 00:57:33 +08:00
0f2b87497b Revert "[fix]code"
This reverts commit 06e9243fda.
2021-11-26 00:57:29 +08:00
06e9243fda [fix]code 2021-11-26 00:27:00 +08:00
d4cc650633 [test] rule providers 2021-11-25 23:33:06 +08:00
14af94205c [test] rule providers 2021-11-25 23:20:08 +08:00
078389f4f6 [test] rule providers 2021-11-25 23:14:31 +08:00
cad18b7529 [fix] rule providers 2021-11-25 21:52:07 +08:00
aeddc8eb1d fix proxies callback 2021-11-21 16:57:22 +08:00
f7393509a3 fix python310 2021-11-21 15:09:22 +08:00
8e641a4e31 Fix: should return io.EOF immediately 2021-11-20 23:01:22 +08:00
223de1f3fd [update]version 2021-11-18 23:54:20 +08:00
1fb2bc07d7 [update]readme 2021-11-17 19:55:14 +08:00
eb57d246cf [test]tun 2021-11-17 19:35:34 +08:00
0001a1b844 [Fix]Vless tls must not be true 2021-11-17 19:09:01 +08:00
b20e202321 [Fix]Vless tls must not be true 2021-11-17 17:56:24 +08:00
900e852525 [test] 2021-11-17 16:03:47 +08:00
1f3968bd50 [test]core 1.8 2021-11-17 15:00:32 +08:00
5d510eb5aa [test]core 1.8 2021-11-16 20:08:52 +08:00
3d246d5150 Merge from remote branch 2021-11-14 20:25:22 +08:00
3686446919 Fix: resolver dial context options 2021-11-12 11:05:02 +08:00
a412745314 Merge from remote branch 2021-11-11 00:54:43 +08:00
d0c23998d2 Fix: resolver dial context udp 2021-11-11 00:53:42 +08:00
038cc1f6b5 Merge from remote branch 2021-11-09 21:12:08 +08:00
6bd186d3c0 Merge from remote branch 2021-11-09 21:11:38 +08:00
4c6bb7178b Feature: resolve ip with proxy adapter 2021-11-09 19:44:16 +08:00
cec14db4a8 Merge pull request #1 from Dreamacro/master
更新
2021-11-09 16:14:04 +08:00
53287d597b Chore: use custom buffer pool for lwIP stack 2021-11-04 18:33:11 +08:00
964bbe1957 Chore: adjust all udp alloc size
Chore: adjust all udp alloc size
2021-11-04 00:44:16 +08:00
c824ace2d7 Wintun: use new swdevice-based API for upcoming Wintun 0.14 2021-11-03 15:10:31 +08:00
78cef7df59 Chore: move "geodata" to package "component" 2021-10-29 00:52:44 +08:00
62b3ebe49f Chore: update dependencies 2021-10-28 13:35:27 +08:00
ff420ed2ee Merge from remote branch 2021-10-28 12:30:30 +08:00
d1568325e6 Merge from remote branch 2021-10-28 12:30:02 +08:00
5a27df899f Chore: script built 2021-10-27 23:10:11 +08:00
ab12b440aa Merge remote branch 2021-10-21 22:40:07 +08:00
4b614090f8 Merge remote branch 2021-10-21 22:37:30 +08:00
63d07db4bf Chore: script built 2021-10-21 20:22:23 +08:00
cbea46b0c8 Merge remote branch 2021-10-15 14:14:51 +08:00
c0e9d69163 Feature: add mode script 2021-10-15 14:11:14 +08:00
d29d824da8 Improve: avoid bufconn twice (#1650) 2021-09-30 04:11:37 +08:00
862174d21b Feature: add lwIP TCP/IP stack to tun listener 2021-09-30 04:05:52 +08:00
125 changed files with 4500 additions and 962 deletions

View File

@ -1,76 +0,0 @@
name: Bug report
description: Create a report to help us improve
title: "[Bug] "
body:
- type: checkboxes
id: ensure
attributes:
label: Verify steps
description: "
在提交之前,请确认
Please verify that you've followed these steps
"
options:
- label: "
如果你可以自己 debug 并解决的话,提交 PR 吧
Is this something you can **debug and fix**? Send a pull request! Bug fixes and documentation fixes are welcome.
"
required: true
- label: "
我已经在 [Issue Tracker](……/) 中找过我要提出的问题
I have searched on the [issue tracker](……/) for a related issue.
"
required: true
- label: "
我已经使用 dev 分支版本测试过,问题依旧存在
I have tested using the dev branch, and the issue still exists.
"
required: true
- label: "
我已经仔细看过 [Documentation](https://github.com/Dreamacro/clash/wiki/) 并无法自行解决问题
I have read the [documentation](https://github.com/Dreamacro/clash/wiki/) and was unable to solve the issue.
"
required: true
- label: "
这是 Clash 核心的问题,并非我所使用的 Clash 衍生版本(如 OpenClash、KoolClash 等)的特定问题
This is an issue of the Clash core *per se*, not to the derivatives of Clash, like OpenClash or KoolClash.
"
required: true
- type: input
attributes:
label: Clash version
validations:
required: true
- type: dropdown
id: os
attributes:
label: What OS are you seeing the problem on?
multiple: true
options:
- macOS
- Windows
- Linux
- OpenBSD/FreeBSD
- type: textarea
attributes:
render: yaml
label: "Clash config"
description: "
在下方附上 Clash core 脱敏后配置文件的内容
Paste the Clash core configuration below.
"
validations:
required: true
- type: textarea
attributes:
render: shell
label: Clash log
description: "
在下方附上 Clash Core 的日志log level 使用 DEBUG
Paste the Clash core log below with the log level set to `DEBUG`.
"
- type: textarea
attributes:
label: Description
validations:
required: true

View File

@ -1,6 +0,0 @@
blank_issues_enabled: false
contact_links:
- name: Get help in GitHub Discussions
url: https://github.com/Dreamacro/clash/discussions
about: Have a question? Not sure if your issue affects everyone reproducibly? The quickest way to get help is on Clash's GitHub Discussions!

View File

@ -1,36 +0,0 @@
name: Feature request
description: Suggest an idea for this project
title: "[Feature] "
body:
- type: checkboxes
id: ensure
attributes:
label: Verify steps
description: "
在提交之前,请确认
Please verify that you've followed these steps
"
options:
- label: "
我已经在 [Issue Tracker](……/) 中找过我要提出的请求
I have searched on the [issue tracker](……/) for a related feature request.
"
required: true
- label: "
我已经仔细看过 [Documentation](https://github.com/Dreamacro/clash/wiki/) 并无法自行解决问题
I have read the [documentation](https://github.com/Dreamacro/clash/wiki/) and was unable to solve the issue.
"
required: true
- type: textarea
attributes:
label: Description
description: 请详细、清晰地表达你要提出的论述,例如这个问题如何影响到你?你想实现什么功能?目前 Clash Core 的行为是什麽?
validations:
required: true
- type: textarea
attributes:
label: Possible Solution
description: "
此项非必须,但是如果你有想法的话欢迎提出。
Not obligatory, but suggest a fix/reason for the bug, or ideas how to implement the addition or change
"

20
.github/workflows/build.yaml vendored Normal file
View File

@ -0,0 +1,20 @@
name: Build All
on:
workflow_dispatch:
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Set up Go
uses: actions/setup-go@v1
with:
go-version: 1.18
- name: Check out code
uses: actions/checkout@v1
- name: Build
run: make all
- name: Release
uses: softprops/action-gh-release@v1
with:
files: bin/*
draft: true

View File

@ -1,29 +0,0 @@
name: CodeQL
on:
push:
branches: [ rm ]
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
language: ['go']
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Initialize CodeQL
uses: github/codeql-action/init@v1
with:
languages: ${{ matrix.language }}
- name: Autobuild
uses: github/codeql-action/autobuild@v1
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v1

View File

@ -1,76 +0,0 @@
name: Publish Docker Image
on:
push:
branches:
- rm
tags:
- '*'
jobs:
build:
name: Build
runs-on: ubuntu-latest
steps:
- name: Check out code into the Go module directory
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Set up QEMU
uses: docker/setup-qemu-action@v1
with:
platforms: all
- name: Set up docker buildx
id: buildx
uses: docker/setup-buildx-action@v1
with:
version: latest
- name: Login to DockerHub
uses: docker/login-action@v1
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Login to Github Package
uses: docker/login-action@v1
with:
registry: ghcr.io
username: Dreamacro
password: ${{ secrets.PACKAGE_TOKEN }}
- name: Build dev branch and push
if: github.ref == 'refs/heads/dev'
uses: docker/build-push-action@v2
with:
context: .
platforms: linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64
push: true
tags: 'dreamacro/clash:dev,ghcr.io/dreamacro/clash:dev'
- name: Get all docker tags
if: startsWith(github.ref, 'refs/tags/')
uses: actions/github-script@v6
id: tags
with:
script: |
const ref = context.payload.ref.replace(/\/?refs\/tags\//, '')
const tags = [
'dreamacro/clash:latest',
`dreamacro/clash:${ref}`,
'ghcr.io/dreamacro/clash:latest',
`ghcr.io/dreamacro/clash:${ref}`
]
return tags.join(',')
result-encoding: string
- name: Build release and push
if: startsWith(github.ref, 'refs/tags/')
uses: docker/build-push-action@v2
with:
context: .
platforms: linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64
push: true
tags: ${{steps.tags.outputs.result}}

View File

@ -1,22 +0,0 @@
name: Linter
on: [push, pull_request]
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Get latest go version
id: version
run: |
echo ::set-output name=go_version::$(curl -s https://raw.githubusercontent.com/actions/go-versions/main/versions-manifest.json | grep -oE '"version": "[0-9]{1}.[0-9]{1,}(.[0-9]{1,})?"' | head -1 | cut -d':' -f2 | sed 's/ //g; s/"//g')
- name: Setup Go
uses: actions/setup-go@v2
with:
go-version: ${{ steps.version.outputs.go_version }}
- name: golangci-lint
uses: golangci/golangci-lint-action@v3
with:
version: latest

View File

@ -1,14 +1,14 @@
name: Release
on: [push]
jobs:
build:
Feature-build:
if: ${{ !contains(github.event.head_commit.message, '[Skip CI]') }}
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:
@ -24,53 +24,48 @@ jobs:
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-go-
- name: Get dependencies, run test
run: |
go test ./...
- name: SSH connection to Actions
uses: P3TERX/ssh2actions@v1.0.0
if: github.actor == github.repository_owner && contains(github.event.head_commit.message, '[ssh]')
# - name: Get dependencies, run test
# run: |
# go test ./...
- name: Build
#if: startsWith(github.ref, 'refs/tags/')
if: success()
env:
NAME: clash
NAME: Clash.Meta
BINDIR: bin
run: make -j releases
- name: Prepare upload
run: |
echo "FILE_DATE=_$(date +"%Y%m%d%H%M")" >> $GITHUB_ENV
echo "FILE_SHA=$(git describe --tags --always 2>/dev/null)" >> $GITHUB_ENV
- name: Upload files to Artifacts
uses: actions/upload-artifact@v2
- name: Delete current release assets
uses: andreaswilli/delete-release-assets-action@v2.0.0
with:
name: clash_${{ env.FILE_SHA }}${{ env.FILE_DATE }}
path: |
bin/*
github_token: ${{ secrets.GITHUB_TOKEN }}
tag: alpha
deleteOnlyFromDrafts: false
- name: Tag Repo
uses: richardsimko/update-tag@v1
with:
tag_name: v1.10.0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Upload Release
uses: softprops/action-gh-release@v1
if: startsWith(github.ref, 'refs/tags/')
if: ${{ env.GIT_BRANCH == 'Meta' && success() }}
with:
tag: ${{ github.ref }}
tag_name: v1.10.0
files: bin/*
draft: true
prerelease: false
- name: Delete workflow runs
uses: GitRML/delete-workflow-runs@main
- name: send telegram message on push
uses: appleboy/telegram-action@master
with:
retain_days: 1
keep_minimum_runs: 2
to: ${{ secrets.TTELEGRAM_CHAT_ID }}
token: ${{ secrets.TELEGRAM_TOKEN }}
message: |
${{ github.actor }} created commit:
Commit message: ${{ github.event.commits[0].message }}
- name: Remove old Releases
uses: dev-drprasad/delete-older-releases@v0.2.0
if: startsWith(github.ref, 'refs/tags/') && !cancelled()
with:
keep_latest: 1
delete_tags: true
delete_tag_pattern: tun
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Repository: ${{ github.repository }}
See changes: https://github.com/${{ github.repository }}/commit/${{github.sha}}

View File

@ -1,19 +0,0 @@
name: Mark stale issues and pull requests
on:
push:
branches:
- rm
jobs:
stale:
runs-on: ubuntu-latest
steps:
- uses: actions/stale@v5
with:
stale-issue-message: 'This issue is stale because it has been open 60 days with no activity. Remove stale label or comment or this will be closed in 5 days'
days-before-stale: 60
days-before-close: 5

2
.gitignore vendored
View File

@ -23,3 +23,5 @@ vendor
# test suite
test/config/cache*
/output
/.vscode

View File

@ -1,63 +1,77 @@
NAME=clash
NAME=Clash.Meta
BINDIR=bin
VERSION=$(shell git describe --tags --always 2>/dev/null || date +%F)
BRANCH=$(shell git rev-parse --abbrev-ref HEAD)
VERSION=$(shell git describe --tags || echo "unknown version")
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-amd64 \
darwin-amd64-v3 \
darwin-amd64v1 \
darwin-amd64v2 \
darwin-amd64v3 \
darwin-arm64 \
linux-386 \
linux-amd64 \
linux-amd64-v3 \
linux-amd64v1 \
linux-amd64v2 \
linux-amd64v3 \
linux-armv5 \
linux-armv6 \
linux-armv7 \
linux-arm64 \
linux-mips64 \
linux-mips64le \
linux-mips-softfloat \
linux-mips-hardfloat \
linux-mipsle-softfloat \
linux-mipsle-hardfloat \
linux-mips64 \
linux-mips64le \
android-arm64 \
freebsd-386 \
freebsd-amd64 \
freebsd-amd64-v3 \
freebsd-arm64
WINDOWS_ARCH_LIST = \
windows-386 \
windows-amd64 \
windows-amd64-v3 \
windows-amd64v1 \
windows-amd64v2 \
windows-amd64v3 \
windows-arm64 \
windows-arm32v7
windows-arm32v7
all: linux-amd64 darwin-amd64 windows-amd64 # Most used
all:linux-amd64 linux-arm64\
darwin-amd64 darwin-arm64\
windows-amd64 windows-arm64\
docker:
$(GOBUILD) -o $(BINDIR)/$(NAME)-$@
darwin-amd64:
GOARCH=amd64 GOOS=darwin $(GOBUILD) -o $(BINDIR)/$(NAME)-$@
darwin-amd64-v3:
darwin-amd64v3:
GOARCH=amd64 GOOS=darwin GOAMD64=v3 $(GOBUILD) -o $(BINDIR)/$(NAME)-$@
darwin-amd64v2:
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-amd64:
GOARCH=amd64 GOOS=linux $(GOBUILD) -o $(BINDIR)/$(NAME)-$@
linux-amd64-v3:
linux-amd64v3:
GOARCH=amd64 GOOS=linux GOAMD64=v3 $(GOBUILD) -o $(BINDIR)/$(NAME)-$@
linux-amd64v2:
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)-$@
linux-armv5:
GOARCH=arm GOOS=linux GOARM=5 $(GOBUILD) -o $(BINDIR)/$(NAME)-$@
@ -67,9 +81,6 @@ linux-armv6:
linux-armv7:
GOARCH=arm GOOS=linux GOARM=7 $(GOBUILD) -o $(BINDIR)/$(NAME)-$@
linux-arm64:
GOARCH=arm64 GOOS=linux $(GOBUILD) -o $(BINDIR)/$(NAME)-$@
linux-mips-softfloat:
GOARCH=mips GOMIPS=softfloat GOOS=linux $(GOBUILD) -o $(BINDIR)/$(NAME)-$@
@ -88,13 +99,13 @@ linux-mips64:
linux-mips64le:
GOARCH=mips64le GOOS=linux $(GOBUILD) -o $(BINDIR)/$(NAME)-$@
android-arm64:
GOARCH=arm64 GOOS=android $(GOBUILD) -o $(BINDIR)/$(NAME)-$@
freebsd-386:
GOARCH=386 GOOS=freebsd $(GOBUILD) -o $(BINDIR)/$(NAME)-$@
freebsd-amd64:
GOARCH=amd64 GOOS=freebsd $(GOBUILD) -o $(BINDIR)/$(NAME)-$@
freebsd-amd64-v3:
GOARCH=amd64 GOOS=freebsd GOAMD64=v3 $(GOBUILD) -o $(BINDIR)/$(NAME)-$@
freebsd-arm64:
@ -103,12 +114,15 @@ freebsd-arm64:
windows-386:
GOARCH=386 GOOS=windows $(GOBUILD) -o $(BINDIR)/$(NAME)-$@.exe
windows-amd64:
GOARCH=amd64 GOOS=windows $(GOBUILD) -o $(BINDIR)/$(NAME)-$@.exe
windows-amd64-v3:
windows-amd64v3:
GOARCH=amd64 GOOS=windows GOAMD64=v3 $(GOBUILD) -o $(BINDIR)/$(NAME)-$@.exe
windows-amd64v2:
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
@ -136,4 +150,4 @@ lint:
golangci-lint run ./...
clean:
rm -rf $(BINDIR)/*
rm $(BINDIR)/*

BIN
Meta.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 79 KiB

264
README.md
View File

@ -1,23 +1,20 @@
<h1 align="center">
<img src="https://github.com/Dreamacro/clash/raw/master/docs/logo.png" alt="Clash" width="200">
<br>Clash<br>
<img src="Meta.png" alt="Meta Kennel" width="200">
<br>Meta Kernel<br>
</h1>
<h4 align="center">A rule-based tunnel in Go.</h4>
<h3 align="center">Another Clash Kernel.</h3>
<p align="center">
<a href="https://github.com/Dreamacro/clash/actions">
<img src="https://img.shields.io/github/workflow/status/Dreamacro/clash/Go?style=flat-square" alt="Github Actions">
</a>
<a href="https://goreportcard.com/report/github.com/Dreamacro/clash">
<img src="https://goreportcard.com/badge/github.com/Dreamacro/clash?style=flat-square">
<a href="https://goreportcard.com/report/github.com/Clash-Mini/Clash.Meta">
<img src="https://goreportcard.com/badge/github.com/Clash-Mini/Clash.Meta?style=flat-square">
</a>
<img src="https://img.shields.io/github/go-mod/go-version/Dreamacro/clash?style=flat-square">
<a href="https://github.com/Dreamacro/clash/releases">
<img src="https://img.shields.io/github/release/Dreamacro/clash/all.svg?style=flat-square">
<a href="https://github.com/Clash-Mini/Clash.Meta/releases">
<img src="https://img.shields.io/github/release/Clash-Mini/Clash.Meta/all.svg?style=flat-square">
</a>
<a href="https://github.com/Dreamacro/clash/releases/tag/premium">
<img src="https://img.shields.io/badge/release-Premium-00b4f0?style=flat-square">
<a href="https://github.com/Clash-Mini/Clash.Meta">
<img src="https://img.shields.io/badge/release-Meta-00b4f0?style=flat-square">
</a>
</p>
@ -36,72 +33,82 @@
Documentations are now moved to [GitHub Wiki](https://github.com/Dreamacro/clash/wiki).
## Advanced usage for this branch
### DNS configuration
Support resolve ip with a proxy tunnel.
Support `geosite` with `fallback-filter`.
Use curl -X POST controllerip:port/cache/fakeip/flush to flush persistence fakeip
```yaml
dns:
enable: true
use-hosts: true
ipv6: false
enhanced-mode: fake-ip
fake-ip-range: 198.18.0.1/16
listen: 127.0.0.1:6868
default-nameserver:
- 119.29.29.29
- 114.114.114.114
nameserver:
- https://doh.pub/dns-query
- tls://223.5.5.5:853
fallback:
- 'https://1.0.0.1/dns-query#Proxy' # append the proxy adapter name to the end of DNS URL with '#' prefix.
- 'tls://8.8.4.4:853#Proxy'
fallback-filter:
geoip: false
geosite:
- gfw # `geosite` filter only use fallback server to resolve ip, prevent DNS leaks to untrusted DNS providers.
domain:
- +.example.com
ipcidr:
- 0.0.0.0/32
```
Restore `Redir remote resolution`.
Support resolve ip with a `Proxy Tunnel`.
```yaml
proxy-groups:
- name: DNS
type: url-test
use:
- HK
url: http://cp.cloudflare.com
interval: 180
lazy: true
```
```yaml
dns:
enable: true
use-hosts: true
ipv6: false
enhanced-mode: redir-host
fake-ip-range: 198.18.0.1/16
listen: 127.0.0.1:6868
default-nameserver:
- 119.29.29.29
- 114.114.114.114
nameserver:
- https://doh.pub/dns-query
- tls://223.5.5.5:853
fallback:
- 'https://1.0.0.1/dns-query#DNS' # append the proxy adapter name or group name to the end of DNS URL with '#' prefix.
- 'tls://8.8.4.4:853#DNS'
fallback-filter:
geoip: false
geosite:
- gfw # `geosite` filter only use fallback server to resolve ip, prevent DNS leaks to unsafe DNS providers.
domain:
- +.example.com
ipcidr:
- 0.0.0.0/32
```
### TUN configuration
Supports macOS, Linux and Windows.
On Windows, you should download the [Wintun](https://www.wintun.net) driver and copy `wintun.dll` into the system32 directory.
Built-in [Wintun](https://www.wintun.net) driver.
```yaml
# Enable the TUN listener
tun:
enable: true
stack: gvisor # System or gVisor
# device: tun://utun8 # or fd://xxx, it's optional
stack: gvisor # only gvisor
dns-hijack:
- 0.0.0.0:53 # hijack all public
- 0.0.0.0:53 # additional dns server listen on TUN
auto-route: true # auto set global route
```
### Rules configuration
- Support rule `GEOSITE`.
- Support rule-providers `RULE-SET`.
- Support `multiport` condition for rule `SRC-PORT` and `DST-PORT`.
- Support `network` condition for all rules.
- Support `process` condition for all rules.
- Support source IPCIDR condition for all rules, just append to the end.
The `GEOIP` databases via [https://github.com/Loyalsoldier/geoip](https://raw.githubusercontent.com/Loyalsoldier/geoip/release/Country.mmdb).
The `GEOSITE` databases via [https://github.com/Loyalsoldier/v2ray-rules-dat](https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geosite.dat).
- The `GEOSITE` databases via https://github.com/Loyalsoldier/v2ray-rules-dat.
```yaml
rules:
# network condition for all rules
- DOMAIN-SUFFIX,example.com,DIRECT,tcp
- DOMAIN-SUFFIX,example.com,REJECT,udp
# process condition for all rules (add 'P:' prefix)
- DOMAIN-SUFFIX,example.com,REJECT,P:Google Chrome Helper
# network(tcp/udp) condition for all rules
- DOMAIN-SUFFIX,bilibili.com,DIRECT,tcp
- DOMAIN-SUFFIX,bilibili.com,REJECT,udp
# multiport condition for rules SRC-PORT and DST-PORT
- DST-PORT,123/136/137-139,DIRECT,udp
@ -115,59 +122,94 @@ rules:
- GEOSITE,youtube,PROXY
- GEOSITE,geolocation-cn,DIRECT
- GEOSITE,geolocation-!cn,PROXY
# source IPCIDR condition for all rules in gateway proxy
#- GEOSITE,geolocation-!cn,REJECT,192.168.1.88/32,192.168.1.99/32
- GEOIP,telegram,PROXY,no-resolve
- GEOIP,lan,DIRECT,no-resolve
- GEOIP,cn,DIRECT
- GEOIP,telegram,PROXY,no-resolve
- GEOIP,private,DIRECT,no-resolve
- GEOIP,cn,DIRECT
- MATCH,PROXY
```
### Proxies configuration
Support outbound protocol `VLESS`.
Support `Trojan` with XTLS.
Active health detection `urltest / fallback` (based on tcp handshake, multiple failures within a limited time will actively trigger health detection to use the node)
Currently XTLS only supports TCP transport.
Support `Policy Group Filter`
```yaml
proxy-groups:
- name: 🚀 HK Group
type: select
use:
- ALL
filter: 'HK'
- name: 🚀 US Group
type: select
use:
- ALL
filter: 'US'
proxy-providers:
ALL:
type: http
url: "xxxxx"
interval: 3600
path: "xxxxx"
health-check:
enable: true
interval: 600
url: http://www.gstatic.com/generate_204
```
Support outbound transport protocol `VLESS`.
The XTLS support (TCP/UDP) transport by the XRAY-CORE.
```yaml
proxies:
# VLESS
- name: "vless-tls"
- name: "vless"
type: vless
server: server
port: 443
uuid: uuid
network: tcp
servername: example.com
servername: example.com # AKA SNI
# flow: xtls-rprx-direct # xtls-rprx-origin # enable XTLS
# skip-cert-verify: true
- name: "vless-ws"
type: vless
server: server
port: 443
uuid: uuid
tls: true
udp: true
network: ws
servername: example.com # priority over wss host
# skip-cert-verify: true
- name: "vless-xtls"
ws-opts:
path: /path
headers: { Host: example.com, Edge: "12a00c4.fm.huawei.com:82897" }
- name: "vless-grpc"
type: vless
server: server
port: 443
uuid: uuid
network: tcp
servername: example.com
flow: xtls-rprx-direct # or xtls-rprx-origin
# flow-show: true # print the XTLS direction log
# udp: true
# skip-cert-verify: true
# Trojan
- name: "trojan-xtls"
type: trojan
server: server
port: 443
password: yourpsk
network: tcp
flow: xtls-rprx-direct # or xtls-rprx-origin
# flow-show: true # print the XTLS direction log
# udp: true
# sni: example.com # aka server name
tls: true
udp: true
network: grpc
servername: example.com # priority over wss host
# skip-cert-verify: true
grpc-opts:
grpc-service-name: grpcname
```
### IPTABLES configuration
@ -181,45 +223,73 @@ iptables:
enable: true # default is false
inbound-interface: eth0 # detect the inbound interface, default is 'lo'
```
Run Clash as a daemon.
Create the systemd configuration file at /etc/systemd/system/clash.service:
```shell
### General installation guide for Linux
+ Create user given name `clash-meta`
+ Download and decompress pre-built binaries from [releases](https://github.com/MetaCubeX/Clash.Meta/releases)
+ Rename executable file to `Clash-Meta` and move to `/usr/local/bin/`
+ Create folder `/etc/Clash-Meta/` as working directory
Run Meta Kernel by user `clash-meta` as a daemon.
Create the systemd configuration file at `/etc/systemd/system/Clash-Meta.service`:
```
[Unit]
Description=Clash daemon, A rule-based proxy in Go.
After=network.target
Description=Clash-Meta Daemon, Another Clash Kernel.
After=network.target NetworkManager.service systemd-networkd.service iwd.service
[Service]
Type=simple
User=clash-meta
Group=clash-meta
LimitNPROC=500
LimitNOFILE=1000000
CapabilityBoundingSet=cap_net_admin
AmbientCapabilities=cap_net_admin
Restart=always
ExecStart=/usr/local/bin/clash -d /etc/clash
ExecStartPre=/usr/bin/sleep 1s
ExecStart=/usr/local/bin/Clash-Meta -d /etc/Clash-Meta
[Install]
WantedBy=multi-user.target
```
Launch clashd on system startup with:
```shell
$ systemctl enable clash
$ systemctl enable Clash-Meta
```
Launch clashd immediately with:
```shell
$ systemctl start clash
$ systemctl start Clash-Meta
```
### Display Process name
Add field `Process` to `Metadata` and prepare to get process name for Restful API `GET /connections`.
To display process name in GUI please use https://yaling888.github.io/yacd/.
Clash add field `Process` to `Metadata` and prepare to get process name for Restful API `GET /connections`.
To display process name in GUI please use [Dashboard For Meta](https://github.com/Clash-Mini/Dashboard).
![img.png](https://github.com/Clash-Mini/Dashboard/raw/master/View/Dashboard-Process.png)
## Development
If you want to build an application that uses clash as a library, check out the the [GitHub Wiki](https://github.com/Dreamacro/clash/wiki/use-clash-as-a-library)
If you want to build an application that uses clash as a library, check out the
the [GitHub Wiki](https://github.com/Dreamacro/clash/wiki/use-clash-as-a-library)
## Credits
* [Dreamacro/clash](https://github.com/Dreamacro/clash)
* [riobard/go-shadowsocks2](https://github.com/riobard/go-shadowsocks2)
* [v2ray/v2ray-core](https://github.com/v2ray/v2ray-core)
* [WireGuard/wireguard-go](https://github.com/WireGuard/wireguard-go)
* [yaling888/clash-plus-pro](https://github.com/yaling888/clash)
## License

View File

@ -7,6 +7,7 @@ import (
"net"
"net/http"
"net/url"
"strings"
"time"
"github.com/Dreamacro/clash/common/queue"
@ -16,6 +17,8 @@ import (
"go.uber.org/atomic"
)
var UnifiedDelay = atomic.NewBool(false)
type Proxy struct {
C.ProxyAdapter
history *queue.Queue
@ -37,7 +40,11 @@ func (p *Proxy) Dial(metadata *C.Metadata) (C.Conn, error) {
// DialContext implements C.ProxyAdapter
func (p *Proxy) DialContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (C.Conn, error) {
conn, err := p.ProxyAdapter.DialContext(ctx, metadata, opts...)
p.alive.Store(err == nil)
wasCancel := false
if err != nil {
wasCancel = strings.Contains(err.Error(), "operation was canceled")
}
p.alive.Store(err == nil || wasCancel)
return conn, err
}
@ -114,6 +121,8 @@ func (p *Proxy) URLTest(ctx context.Context, url string) (t uint16, err error) {
}
}()
unifiedDelay := UnifiedDelay.Load()
addr, err := urlToMetadata(url)
if err != nil {
return
@ -150,11 +159,19 @@ func (p *Proxy) URLTest(ctx context.Context, url string) (t uint16, err error) {
},
}
defer client.CloseIdleConnections()
resp, err := client.Do(req)
if err != nil {
return
}
if unifiedDelay {
start = time.Now()
resp, err = client.Do(req)
if err != nil {
return
}
}
resp.Body.Close()
t = uint16(time.Since(start) / time.Millisecond)
return

View File

@ -20,3 +20,26 @@ func NewSocket(target socks5.Addr, conn net.Conn, source C.Type) *context.ConnCo
return context.NewConnContext(conn, metadata)
}
func NewInner(conn net.Conn, dst string, host string) *context.ConnContext {
metadata := &C.Metadata{}
metadata.NetWork = C.TCP
metadata.Type = C.INNER
metadata.DNSMode = C.DNSMapping
metadata.Host = host
metadata.AddrType = C.AtypDomainName
metadata.Process = C.ClashName
if ip, port, err := parseAddr(dst); err == nil {
metadata.DstPort = port
if host == "" {
metadata.DstIP = ip
if ip.To4() == nil {
metadata.AddrType = C.AtypIPv6
} else {
metadata.AddrType = C.AtypIPv4
}
}
}
return context.NewConnContext(conn, metadata)
}

View File

@ -46,3 +46,23 @@ func NewDirect() *Direct {
},
}
}
func NewCompatible() *Direct {
return &Direct{
Base: &Base{
name: "COMPATIBLE",
tp: C.Compatible,
udp: true,
},
}
}
func NewPass() *Direct {
return &Direct{
Base: &Base{
name: "Pass",
tp: C.Pass,
udp: true,
},
}
}

View File

@ -2,8 +2,11 @@ package outbound
import (
"bytes"
"crypto/tls"
xtls "github.com/xtls/go"
"net"
"strconv"
"sync"
"time"
"github.com/Dreamacro/clash/component/resolver"
@ -11,6 +14,12 @@ import (
"github.com/Dreamacro/clash/transport/socks5"
)
var (
globalClientSessionCache tls.ClientSessionCache
globalClientXSessionCache xtls.ClientSessionCache
once sync.Once
)
func tcpKeepAlive(c net.Conn) {
if tcp, ok := c.(*net.TCPConn); ok {
tcp.SetKeepAlive(true)
@ -18,6 +27,20 @@ func tcpKeepAlive(c net.Conn) {
}
}
func getClientSessionCache() tls.ClientSessionCache {
once.Do(func() {
globalClientSessionCache = tls.NewLRUClientSessionCache(128)
})
return globalClientSessionCache
}
func getClientXSessionCache() xtls.ClientSessionCache {
once.Do(func() {
globalClientXSessionCache = xtls.NewLRUClientSessionCache(128)
})
return globalClientXSessionCache
}
func serializesSocksAddr(metadata *C.Metadata) []byte {
var buf [][]byte
aType := uint8(metadata.AddrType)

View File

@ -46,6 +46,7 @@ type VlessOption struct {
UUID string `proxy:"uuid"`
Flow string `proxy:"flow,omitempty"`
FlowShow bool `proxy:"flow-show,omitempty"`
TLS bool `proxy:"tls,omitempty"`
UDP bool `proxy:"udp,omitempty"`
Network string `proxy:"network,omitempty"`
HTTPOpts HTTPOptions `proxy:"http-opts,omitempty"`
@ -62,12 +63,6 @@ func (v *Vless) 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{
@ -98,7 +93,6 @@ func (v *Vless) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) {
} else if host := wsOpts.Headers.Get("Host"); host != "" {
wsOpts.TLSConfig.ServerName = host
}
c, err = vmess.StreamWebsocketConn(c, wsOpts)
case "http":
// readability first, so just copy default TLS logic
@ -166,7 +160,7 @@ func (v *Vless) streamTLSOrXTLSConn(conn net.Conn, isH2 bool) (net.Conn, error)
return vless.StreamXTLSConn(conn, &xtlsOpts)
} else {
} else if v.option.TLS {
tlsOpts := vmess.TLSConfig{
Host: host,
SkipCertVerify: v.option.SkipCertVerify,
@ -182,6 +176,8 @@ func (v *Vless) streamTLSOrXTLSConn(conn net.Conn, isH2 bool) (net.Conn, error)
return vmess.StreamTLSConn(conn, &tlsOpts)
}
return conn, nil
}
func (v *Vless) isXTLSEnabled() bool {
@ -287,29 +283,40 @@ func parseVlessAddr(metadata *C.Metadata) *vless.DstAddr {
type vlessPacketConn struct {
net.Conn
rAddr net.Addr
cache [2]byte
remain int
mux sync.Mutex
cache [2]byte
}
func (vc *vlessPacketConn) WriteTo(b []byte, addr net.Addr) (int, error) {
func (c *vlessPacketConn) writePacket(payload []byte) (int, error) {
binary.BigEndian.PutUint16(c.cache[:], uint16(len(payload)))
if _, err := c.Conn.Write(c.cache[:]); err != nil {
return 0, err
}
return c.Conn.Write(payload)
}
func (c *vlessPacketConn) WriteTo(b []byte, addr net.Addr) (int, error) {
total := len(b)
if total == 0 {
return 0, nil
}
if total < maxLength {
return vc.writePacket(b)
if total <= maxLength {
return c.writePacket(b)
}
offset := 0
for {
for offset < total {
cursor := offset + maxLength
if cursor > total {
cursor = total
}
n, err := vc.writePacket(b[offset:cursor])
n, err := c.writePacket(b[offset:cursor])
if err != nil {
return offset + n, err
}
@ -323,33 +330,32 @@ func (vc *vlessPacketConn) WriteTo(b []byte, addr net.Addr) (int, error) {
return total, nil
}
func (vc *vlessPacketConn) ReadFrom(b []byte) (int, net.Addr, error) {
vc.mux.Lock()
defer vc.mux.Unlock()
func (c *vlessPacketConn) ReadFrom(b []byte) (int, net.Addr, error) {
c.mux.Lock()
defer c.mux.Unlock()
if vc.remain != 0 {
if c.remain > 0 {
length := len(b)
if length > vc.remain {
length = vc.remain
if c.remain < length {
length = c.remain
}
n, err := vc.Conn.Read(b[:length])
n, err := c.Conn.Read(b[:length])
if err != nil {
return 0, vc.rAddr, err
return 0, c.rAddr, err
}
vc.remain -= n
return n, vc.rAddr, nil
c.remain -= n
return n, c.rAddr, nil
}
if _, err := vc.Conn.Read(b[:2]); err != nil {
return 0, vc.rAddr, err
if _, err := c.Conn.Read(b[:2]); err != nil {
return 0, c.rAddr, err
}
total := int(binary.BigEndian.Uint16(b[:2]))
if total == 0 {
return 0, vc.rAddr, nil
return 0, c.rAddr, nil
}
length := len(b)
@ -357,23 +363,13 @@ func (vc *vlessPacketConn) ReadFrom(b []byte) (int, net.Addr, error) {
length = total
}
if _, err := io.ReadFull(vc.Conn, b[:length]); err != nil {
return 0, vc.rAddr, errors.New("read packet error")
if _, err := io.ReadFull(c.Conn, b[:length]); err != nil {
return 0, c.rAddr, errors.New("read packet error")
}
vc.remain = total - length
c.remain = total - length
return length, vc.rAddr, nil
}
func (vc *vlessPacketConn) writePacket(payload []byte) (int, error) {
binary.BigEndian.PutUint16(vc.cache[:], uint16(len(payload)))
if _, err := vc.Conn.Write(vc.cache[:]); err != nil {
return 0, err
}
return vc.Conn.Write(payload)
return length, c.rAddr, nil
}
func NewVless(option VlessOption) (*Vless, error) {

View File

@ -1,6 +1,8 @@
package outboundgroup
import (
"github.com/Dreamacro/clash/tunnel"
"github.com/dlclark/regexp2"
"time"
C "github.com/Dreamacro/clash/constant"
@ -11,7 +13,7 @@ const (
defaultGetProxiesDuration = time.Second * 5
)
func getProvidersProxies(providers []provider.ProxyProvider, touch bool) []C.Proxy {
func getProvidersProxies(providers []provider.ProxyProvider, touch bool, filter string) []C.Proxy {
proxies := []C.Proxy{}
for _, provider := range providers {
if touch {
@ -20,5 +22,34 @@ func getProvidersProxies(providers []provider.ProxyProvider, touch bool) []C.Pro
proxies = append(proxies, provider.Proxies()...)
}
}
return proxies
var filterReg *regexp2.Regexp = nil
var matchedProxies []C.Proxy
if len(filter) > 0 {
//filterReg = regexp.MustCompile(filter)
filterReg = regexp2.MustCompile(filter, 0)
for _, p := range proxies {
if p.Type() < 8 {
matchedProxies = append(matchedProxies, p)
}
//if filterReg.MatchString(p.Name()) {
if mat, _ := filterReg.FindStringMatch(p.Name()); mat != nil {
matchedProxies = append(matchedProxies, p)
}
}
if len(matchedProxies) > 0 {
return matchedProxies
} else {
return append([]C.Proxy{}, tunnel.Proxies()["COMPATIBLE"])
}
} else {
if len(proxies) == 0 {
return append(proxies, tunnel.Proxies()["COMPATIBLE"])
} else {
return proxies
}
}
}

View File

@ -3,6 +3,9 @@ package outboundgroup
import (
"context"
"encoding/json"
"github.com/Dreamacro/clash/log"
"go.uber.org/atomic"
"time"
"github.com/Dreamacro/clash/adapter/outbound"
"github.com/Dreamacro/clash/common/singledo"
@ -13,9 +16,12 @@ import (
type Fallback struct {
*outbound.Base
disableUDP bool
single *singledo.Single
providers []provider.ProxyProvider
disableUDP bool
filter string
single *singledo.Single
providers []provider.ProxyProvider
failedTimes *atomic.Int32
failedTime *atomic.Int64
}
func (f *Fallback) Now() string {
@ -29,7 +35,12 @@ 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)
} else {
f.onDialFailed()
}
return c, err
}
@ -39,10 +50,41 @@ 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 {
@ -55,7 +97,7 @@ func (f *Fallback) SupportUDP() bool {
// MarshalJSON implements C.ProxyAdapter
func (f *Fallback) MarshalJSON() ([]byte, error) {
var all []string
all := []string{}
for _, proxy := range f.proxies(false) {
all = append(all, proxy.Name())
}
@ -74,7 +116,7 @@ func (f *Fallback) Unwrap(metadata *C.Metadata) C.Proxy {
func (f *Fallback) proxies(touch bool) []C.Proxy {
elm, _, _ := f.single.Do(func() (any, error) {
return getProvidersProxies(f.providers, touch), nil
return getProvidersProxies(f.providers, touch, f.filter), nil
})
return elm.([]C.Proxy)
@ -99,8 +141,11 @@ func NewFallback(option *GroupCommonOption, providers []provider.ProxyProvider)
Interface: option.Interface,
RoutingMark: option.RoutingMark,
}),
single: singledo.NewSingle(defaultGetProxiesDuration),
providers: providers,
disableUDP: option.DisableUDP,
single: singledo.NewSingle(defaultGetProxiesDuration),
providers: providers,
disableUDP: option.DisableUDP,
filter: option.Filter,
failedTimes: atomic.NewInt32(-1),
failedTime: atomic.NewInt64(-1),
}
}

View File

@ -23,6 +23,7 @@ type LoadBalance struct {
*outbound.Base
disableUDP bool
single *singledo.Single
filter string
providers []provider.ProxyProvider
strategyFn strategyFn
}
@ -141,7 +142,7 @@ func (lb *LoadBalance) Unwrap(metadata *C.Metadata) C.Proxy {
func (lb *LoadBalance) proxies(touch bool) []C.Proxy {
elm, _, _ := lb.single.Do(func() (any, error) {
return getProvidersProxies(lb.providers, touch), nil
return getProvidersProxies(lb.providers, touch, lb.filter), nil
})
return elm.([]C.Proxy)
@ -149,7 +150,7 @@ func (lb *LoadBalance) proxies(touch bool) []C.Proxy {
// MarshalJSON implements C.ProxyAdapter
func (lb *LoadBalance) MarshalJSON() ([]byte, error) {
var all []string
all := []string{}
for _, proxy := range lb.proxies(false) {
all = append(all, proxy.Name())
}
@ -180,5 +181,6 @@ func NewLoadBalance(option *GroupCommonOption, providers []provider.ProxyProvide
providers: providers,
strategyFn: strategyFn,
disableUDP: option.DisableUDP,
filter: option.Filter,
}, nil
}

View File

@ -29,6 +29,7 @@ type GroupCommonOption struct {
Interval int `group:"interval,omitempty"`
Lazy bool `group:"lazy,omitempty"`
DisableUDP bool `group:"disable-udp,omitempty"`
Filter string `group:"filter,omitempty"`
}
func ParseProxyGroup(config map[string]any, proxyMap map[string]C.Proxy, providersMap map[string]types.ProxyProvider) (C.ProxyAdapter, error) {
@ -95,6 +96,8 @@ func ParseProxyGroup(config map[string]any, proxyMap map[string]C.Proxy, provide
return nil, err
}
providers = append(providers, list...)
} else {
groupOption.Filter = ""
}
var group C.ProxyAdapter

View File

@ -16,13 +16,14 @@ type Relay struct {
*outbound.Base
single *singledo.Single
providers []provider.ProxyProvider
filter string
}
// DialContext implements C.ProxyAdapter
func (r *Relay) DialContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (C.Conn, error) {
var proxies []C.Proxy
for _, proxy := range r.proxies(metadata, true) {
if proxy.Type() != C.Direct {
if proxy.Type() != C.Direct && proxy.Type() != C.Compatible {
proxies = append(proxies, proxy)
}
}
@ -68,7 +69,7 @@ func (r *Relay) DialContext(ctx context.Context, metadata *C.Metadata, opts ...d
// MarshalJSON implements C.ProxyAdapter
func (r *Relay) MarshalJSON() ([]byte, error) {
var all []string
all := []string{}
for _, proxy := range r.rawProxies(false) {
all = append(all, proxy.Name())
}
@ -80,7 +81,7 @@ func (r *Relay) MarshalJSON() ([]byte, error) {
func (r *Relay) rawProxies(touch bool) []C.Proxy {
elm, _, _ := r.single.Do(func() (any, error) {
return getProvidersProxies(r.providers, touch), nil
return getProvidersProxies(r.providers, touch, r.filter), nil
})
return elm.([]C.Proxy)
@ -110,5 +111,6 @@ func NewRelay(option *GroupCommonOption, providers []provider.ProxyProvider) *Re
}),
single: singledo.NewSingle(defaultGetProxiesDuration),
providers: providers,
filter: option.Filter,
}
}

View File

@ -17,6 +17,7 @@ type Selector struct {
disableUDP bool
single *singledo.Single
selected string
filter string
providers []provider.ProxyProvider
}
@ -49,8 +50,8 @@ func (s *Selector) SupportUDP() bool {
// MarshalJSON implements C.ProxyAdapter
func (s *Selector) MarshalJSON() ([]byte, error) {
var all []string
for _, proxy := range getProvidersProxies(s.providers, false) {
all := []string{}
for _, proxy := range getProvidersProxies(s.providers, false, s.filter) {
all = append(all, proxy.Name())
}
@ -66,7 +67,7 @@ func (s *Selector) Now() string {
}
func (s *Selector) Set(name string) error {
for _, proxy := range getProvidersProxies(s.providers, false) {
for _, proxy := range getProvidersProxies(s.providers, false, s.filter) {
if proxy.Name() == name {
s.selected = name
s.single.Reset()
@ -78,13 +79,13 @@ func (s *Selector) Set(name string) error {
}
// Unwrap implements C.ProxyAdapter
func (s *Selector) Unwrap(metadata *C.Metadata) C.Proxy {
func (s *Selector) Unwrap(*C.Metadata) C.Proxy {
return s.selectedProxy(true)
}
func (s *Selector) selectedProxy(touch bool) C.Proxy {
elm, _, _ := s.single.Do(func() (any, error) {
proxies := getProvidersProxies(s.providers, touch)
proxies := getProvidersProxies(s.providers, touch, s.filter)
for _, proxy := range proxies {
if proxy.Name() == s.selected {
return proxy, nil
@ -98,7 +99,6 @@ func (s *Selector) selectedProxy(touch bool) C.Proxy {
}
func NewSelector(option *GroupCommonOption, providers []provider.ProxyProvider) *Selector {
selected := providers[0].Proxies()[0].Name()
return &Selector{
Base: outbound.NewBase(outbound.BaseOption{
Name: option.Name,
@ -108,7 +108,8 @@ func NewSelector(option *GroupCommonOption, providers []provider.ProxyProvider)
}),
single: singledo.NewSingle(defaultGetProxiesDuration),
providers: providers,
selected: selected,
selected: "COMPATIBLE",
disableUDP: option.DisableUDP,
filter: option.Filter,
}
}

View File

@ -3,6 +3,8 @@ package outboundgroup
import (
"context"
"encoding/json"
"github.com/Dreamacro/clash/log"
"go.uber.org/atomic"
"time"
"github.com/Dreamacro/clash/adapter/outbound"
@ -22,12 +24,15 @@ func urlTestWithTolerance(tolerance uint16) urlTestOption {
type URLTest struct {
*outbound.Base
tolerance uint16
disableUDP bool
fastNode C.Proxy
single *singledo.Single
fastSingle *singledo.Single
providers []provider.ProxyProvider
tolerance uint16
disableUDP bool
fastNode C.Proxy
filter string
single *singledo.Single
fastSingle *singledo.Single
providers []provider.ProxyProvider
failedTimes *atomic.Int32
failedTime *atomic.Int64
}
func (u *URLTest) Now() string {
@ -39,6 +44,10 @@ 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)
} else {
u.onDialFailed()
}
return c, err
}
@ -48,18 +57,22 @@ 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
}
// Unwrap implements C.ProxyAdapter
func (u *URLTest) Unwrap(metadata *C.Metadata) C.Proxy {
func (u *URLTest) Unwrap(*C.Metadata) C.Proxy {
return u.fast(true)
}
func (u *URLTest) proxies(touch bool) []C.Proxy {
elm, _, _ := u.single.Do(func() (any, error) {
return getProvidersProxies(u.providers, touch), nil
return getProvidersProxies(u.providers, touch, u.filter), nil
})
return elm.([]C.Proxy)
@ -110,7 +123,7 @@ func (u *URLTest) SupportUDP() bool {
// MarshalJSON implements C.ProxyAdapter
func (u *URLTest) MarshalJSON() ([]byte, error) {
var all []string
all := []string{}
for _, proxy := range u.proxies(false) {
all = append(all, proxy.Name())
}
@ -121,6 +134,32 @@ 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{}
@ -142,10 +181,13 @@ func NewURLTest(option *GroupCommonOption, providers []provider.ProxyProvider, o
Interface: option.Interface,
RoutingMark: option.RoutingMark,
}),
single: singledo.NewSingle(defaultGetProxiesDuration),
fastSingle: singledo.NewSingle(time.Second * 10),
providers: providers,
disableUDP: option.DisableUDP,
single: singledo.NewSingle(defaultGetProxiesDuration),
fastSingle: singledo.NewSingle(time.Second * 10),
providers: providers,
disableUDP: option.DisableUDP,
filter: option.Filter,
failedTimes: atomic.NewInt32(-1),
failedTime: atomic.NewInt64(-1),
}
for _, option := range options {

View File

@ -4,7 +4,7 @@ import (
"encoding/json"
"errors"
"fmt"
"regexp"
"github.com/dlclark/regexp2"
"runtime"
"time"
@ -40,7 +40,8 @@ func (pp *proxySetProvider) MarshalJSON() ([]byte, error) {
"type": pp.Type().String(),
"vehicleType": pp.VehicleType().String(),
"proxies": pp.Proxies(),
"updatedAt": pp.updatedAt,
//TODO maybe error because year value overflow
"updatedAt": pp.updatedAt,
})
}
@ -67,6 +68,10 @@ func (pp *proxySetProvider) Initial() error {
}
pp.onUpdate(elm)
if pp.healthCheck.auto() {
go pp.healthCheck.process()
}
return nil
}
@ -97,15 +102,12 @@ func stopProxyProvider(pd *ProxySetProvider) {
}
func NewProxySetProvider(name string, interval time.Duration, filter string, vehicle types.Vehicle, hc *HealthCheck) (*ProxySetProvider, error) {
filterReg, err := regexp.Compile(filter)
//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,
@ -129,7 +131,9 @@ func NewProxySetProvider(name string, interval time.Duration, filter string, veh
proxies := []C.Proxy{}
for idx, mapping := range schema.Proxies {
if name, ok := mapping["name"]; ok && len(filter) > 0 && !filterReg.MatchString(name.(string)) {
name, ok := mapping["name"]
mat, _ := filterReg.FindStringMatch(name.(string))
if ok && len(filter) > 0 && mat == nil {
continue
}
proxy, err := adapter.ParseProxy(mapping)
@ -190,6 +194,10 @@ func (cp *compatibleProvider) Update() error {
}
func (cp *compatibleProvider) Initial() error {
if cp.healthCheck.auto() {
go cp.healthCheck.process()
}
return nil
}
@ -219,10 +227,6 @@ func NewCompatibleProvider(name string, proxies []C.Proxy, hc *HealthCheck) (*Co
return nil, errors.New("provider need one proxy at least")
}
if hc.auto() {
go hc.process()
}
pd := &compatibleProvider{
name: name,
proxies: proxies,

View File

@ -2,6 +2,8 @@ package provider
import (
"context"
"github.com/Dreamacro/clash/component/dialer"
"github.com/Dreamacro/clash/listener/inner"
"io"
"net"
"net/http"
@ -9,7 +11,7 @@ import (
"os"
"time"
"github.com/Dreamacro/clash/component/dialer"
netHttp "github.com/Dreamacro/clash/common/net"
types "github.com/Dreamacro/clash/constant/provider"
)
@ -56,6 +58,8 @@ func (h *HTTPVehicle) Read() ([]byte, error) {
}
req, err := http.NewRequest(http.MethodGet, uri.String(), nil)
req.Header.Set("user-agent", netHttp.UA)
if err != nil {
return nil, err
}
@ -74,14 +78,21 @@ func (h *HTTPVehicle) Read() ([]byte, error) {
TLSHandshakeTimeout: 10 * time.Second,
ExpectContinueTimeout: 1 * time.Second,
DialContext: func(ctx context.Context, network, address string) (net.Conn, error) {
return dialer.DialContext(ctx, network, address)
conn := inner.HandleTcp(address, uri.Hostname())
return conn, nil
},
}
client := http.Client{Transport: transport}
resp, err := client.Do(req)
if err != nil {
return nil, err
transport.DialContext = func(ctx context.Context, network, address string) (net.Conn, error) {
return dialer.DialContext(ctx, network, address)
}
resp, err = client.Do(req)
if err != nil {
return nil, err
}
}
defer resp.Body.Close()

View File

@ -14,8 +14,9 @@ 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()
if err != nil {
return "", fmt.Errorf("%v, %s", err, string(out))

11
common/cmd/cmd_other.go Normal file
View File

@ -0,0 +1,11 @@
//go:build !windows
package cmd
import (
"os/exec"
)
func prepareBackgroundCommand(cmd *exec.Cmd) {
}

12
common/cmd/cmd_windows.go Normal file
View File

@ -0,0 +1,12 @@
//go:build windows
package cmd
import (
"os/exec"
"syscall"
)
func prepareBackgroundCommand(cmd *exec.Cmd) {
cmd.SysProcAttr = &syscall.SysProcAttr{HideWindow: true}
}

View File

@ -0,0 +1,56 @@
package collections
import "sync"
type (
stack struct {
top *node
length int
lock *sync.RWMutex
}
node struct {
value interface{}
prev *node
}
)
// NewStack Create a new stack
func NewStack() *stack {
return &stack{nil, 0, &sync.RWMutex{}}
}
// Len Return the number of items in the stack
func (this *stack) Len() int {
return this.length
}
// Peek View the top item on the stack
func (this *stack) Peek() interface{} {
if this.length == 0 {
return nil
}
return this.top.value
}
// Pop the top item of the stack and return it
func (this *stack) Pop() interface{} {
this.lock.Lock()
defer this.lock.Unlock()
if this.length == 0 {
return nil
}
n := this.top
this.top = n.prev
this.length--
return n.value
}
// Push a value onto the top of the stack
func (this *stack) Push(value interface{}) {
this.lock.Lock()
defer this.lock.Unlock()
n := &node{value, this.top}
this.top = n
this.length++
}

5
common/net/http.go Normal file
View File

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

46
common/net/tcpip.go Normal file
View File

@ -0,0 +1,46 @@
package net
import (
"fmt"
"net"
"strings"
)
func SplitNetworkType(s string) (string, string, error) {
var (
shecme string
hostPort string
)
result := strings.Split(s, "://")
if len(result) == 2 {
shecme = result[0]
hostPort = result[1]
} else if len(result) == 1 {
hostPort = result[0]
} else {
return "", "", fmt.Errorf("tcp/udp style error")
}
if len(shecme) == 0 {
shecme = "udp"
}
if shecme != "tcp" && shecme != "udp" {
return "", "", fmt.Errorf("scheme should be tcp:// or udp://")
} else {
return shecme, hostPort, nil
}
}
func SplitHostPort(s string) (host, port string, hasPort bool, err error) {
temp := s
hasPort = true
if !strings.Contains(s, ":") && !strings.Contains(s, "]:") {
temp += ":0"
hasPort = false
}
host, port, err = net.SplitHostPort(temp)
return
}

View File

@ -3,6 +3,7 @@ package geodata
import (
"errors"
"fmt"
C "github.com/Dreamacro/clash/constant"
"strings"
"github.com/Dreamacro/clash/component/geodata/router"
@ -14,7 +15,7 @@ type loader struct {
}
func (l *loader) LoadGeoSite(list string) ([]*router.Domain, error) {
return l.LoadGeoSiteWithAttr("geosite.dat", list)
return l.LoadGeoSiteWithAttr(C.GeositeName, list)
}
func (l *loader) LoadGeoSiteWithAttr(file string, siteWithAttr string) ([]*router.Domain, error) {
@ -58,7 +59,7 @@ func (l *loader) LoadGeoSiteWithAttr(file string, siteWithAttr string) ([]*route
}
func (l *loader) LoadGeoIP(country string) ([]*router.CIDR, error) {
return l.LoadIP("geoip.dat", country)
return l.LoadIP(C.GeoipName, country)
}
var loaders map[string]func() LoaderImplementation

View File

@ -8,7 +8,6 @@ import (
"github.com/Dreamacro/clash/component/geodata/router"
C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/log"
"google.golang.org/protobuf/proto"
)

View File

@ -1,7 +1,10 @@
package router
import (
"encoding/binary"
"fmt"
"net"
"sort"
"strings"
"github.com/Dreamacro/clash/component/geodata/strmatcher"
@ -69,3 +72,279 @@ func NewDomainMatcher(domains []*Domain) (*DomainMatcher, error) {
func (m *DomainMatcher) ApplyDomain(domain string) bool {
return len(m.matchers.Match(strings.ToLower(domain))) > 0
}
// CIDRList is an alias of []*CIDR to provide sort.Interface.
type CIDRList []*CIDR
// Len implements sort.Interface.
func (l *CIDRList) Len() int {
return len(*l)
}
// Less implements sort.Interface.
func (l *CIDRList) Less(i int, j int) bool {
ci := (*l)[i]
cj := (*l)[j]
if len(ci.Ip) < len(cj.Ip) {
return true
}
if len(ci.Ip) > len(cj.Ip) {
return false
}
for k := 0; k < len(ci.Ip); k++ {
if ci.Ip[k] < cj.Ip[k] {
return true
}
if ci.Ip[k] > cj.Ip[k] {
return false
}
}
return ci.Prefix < cj.Prefix
}
// Swap implements sort.Interface.
func (l *CIDRList) Swap(i int, j int) {
(*l)[i], (*l)[j] = (*l)[j], (*l)[i]
}
type ipv6 struct {
a uint64
b uint64
}
type GeoIPMatcher struct {
countryCode string
reverseMatch bool
ip4 []uint32
prefix4 []uint8
ip6 []ipv6
prefix6 []uint8
}
func normalize4(ip uint32, prefix uint8) uint32 {
return (ip >> (32 - prefix)) << (32 - prefix)
}
func normalize6(ip ipv6, prefix uint8) ipv6 {
if prefix <= 64 {
ip.a = (ip.a >> (64 - prefix)) << (64 - prefix)
ip.b = 0
} else {
ip.b = (ip.b >> (128 - prefix)) << (128 - prefix)
}
return ip
}
func (m *GeoIPMatcher) Init(cidrs []*CIDR) error {
ip4Count := 0
ip6Count := 0
for _, cidr := range cidrs {
ip := cidr.Ip
switch len(ip) {
case 4:
ip4Count++
case 16:
ip6Count++
default:
return fmt.Errorf("unexpect ip length: %d", len(ip))
}
}
cidrList := CIDRList(cidrs)
sort.Sort(&cidrList)
m.ip4 = make([]uint32, 0, ip4Count)
m.prefix4 = make([]uint8, 0, ip4Count)
m.ip6 = make([]ipv6, 0, ip6Count)
m.prefix6 = make([]uint8, 0, ip6Count)
for _, cidr := range cidrs {
ip := cidr.Ip
prefix := uint8(cidr.Prefix)
switch len(ip) {
case 4:
m.ip4 = append(m.ip4, normalize4(binary.BigEndian.Uint32(ip), prefix))
m.prefix4 = append(m.prefix4, prefix)
case 16:
ip6 := ipv6{
a: binary.BigEndian.Uint64(ip[0:8]),
b: binary.BigEndian.Uint64(ip[8:16]),
}
ip6 = normalize6(ip6, prefix)
m.ip6 = append(m.ip6, ip6)
m.prefix6 = append(m.prefix6, prefix)
}
}
return nil
}
func (m *GeoIPMatcher) SetReverseMatch(isReverseMatch bool) {
m.reverseMatch = isReverseMatch
}
func (m *GeoIPMatcher) match4(ip uint32) bool {
if len(m.ip4) == 0 {
return false
}
if ip < m.ip4[0] {
return false
}
size := uint32(len(m.ip4))
l := uint32(0)
r := size
for l < r {
x := ((l + r) >> 1)
if ip < m.ip4[x] {
r = x
continue
}
nip := normalize4(ip, m.prefix4[x])
if nip == m.ip4[x] {
return true
}
l = x + 1
}
return l > 0 && normalize4(ip, m.prefix4[l-1]) == m.ip4[l-1]
}
func less6(a ipv6, b ipv6) bool {
return a.a < b.a || (a.a == b.a && a.b < b.b)
}
func (m *GeoIPMatcher) match6(ip ipv6) bool {
if len(m.ip6) == 0 {
return false
}
if less6(ip, m.ip6[0]) {
return false
}
size := uint32(len(m.ip6))
l := uint32(0)
r := size
for l < r {
x := (l + r) / 2
if less6(ip, m.ip6[x]) {
r = x
continue
}
if normalize6(ip, m.prefix6[x]) == m.ip6[x] {
return true
}
l = x + 1
}
return l > 0 && normalize6(ip, m.prefix6[l-1]) == m.ip6[l-1]
}
// Match returns true if the given ip is included by the GeoIP.
func (m *GeoIPMatcher) Match(ip net.IP) bool {
switch len(ip) {
case 4:
if m.reverseMatch {
return !m.match4(binary.BigEndian.Uint32(ip))
}
return m.match4(binary.BigEndian.Uint32(ip))
case 16:
if m.reverseMatch {
return !m.match6(ipv6{
a: binary.BigEndian.Uint64(ip[0:8]),
b: binary.BigEndian.Uint64(ip[8:16]),
})
}
return m.match6(ipv6{
a: binary.BigEndian.Uint64(ip[0:8]),
b: binary.BigEndian.Uint64(ip[8:16]),
})
default:
return false
}
}
// GeoIPMatcherContainer is a container for GeoIPMatchers. It keeps unique copies of GeoIPMatcher by country code.
type GeoIPMatcherContainer struct {
matchers []*GeoIPMatcher
}
// Add adds a new GeoIP set into the container.
// If the country code of GeoIP is not empty, GeoIPMatcherContainer will try to find an existing one, instead of adding a new one.
func (c *GeoIPMatcherContainer) Add(geoip *GeoIP) (*GeoIPMatcher, error) {
if len(geoip.CountryCode) > 0 {
for _, m := range c.matchers {
if m.countryCode == geoip.CountryCode && m.reverseMatch == geoip.ReverseMatch {
return m, nil
}
}
}
m := &GeoIPMatcher{
countryCode: geoip.CountryCode,
reverseMatch: geoip.ReverseMatch,
}
if err := m.Init(geoip.Cidr); err != nil {
return nil, err
}
if len(geoip.CountryCode) > 0 {
c.matchers = append(c.matchers, m)
}
return m, nil
}
var globalGeoIPContainer GeoIPMatcherContainer
type MultiGeoIPMatcher struct {
matchers []*GeoIPMatcher
}
func NewGeoIPMatcher(geoip *GeoIP) (*GeoIPMatcher, error) {
matcher, err := globalGeoIPContainer.Add(geoip)
if err != nil {
return nil, err
}
return matcher, nil
}
func (m *MultiGeoIPMatcher) ApplyIp(ip net.IP) bool {
for _, matcher := range m.matchers {
if matcher.Match(ip) {
return true
}
}
return false
}
func NewMultiGeoIPMatcher(geoips []*GeoIP) (*MultiGeoIPMatcher, error) {
var matchers []*GeoIPMatcher
for _, geoip := range geoips {
matcher, err := globalGeoIPContainer.Add(geoip)
if err != nil {
return nil, err
}
matchers = append(matchers, matcher)
}
matcher := &MultiGeoIPMatcher{
matchers: matchers,
}
return matcher, nil
}

View File

@ -2,10 +2,36 @@ package geodata
import (
"github.com/Dreamacro/clash/component/geodata/router"
C "github.com/Dreamacro/clash/constant"
"strings"
)
var geoLoaderName = "memconservative"
// geoLoaderName = "standard"
func LoaderName() string {
return geoLoaderName
}
func SetLoader(newLoader string) {
geoLoaderName = newLoader
}
func Verify(name string) bool {
switch name {
case C.GeositeName:
_, _, err := LoadGeoSiteMatcher("CN")
return err == nil
case C.GeoipName:
_, _, err := LoadGeoIPMatcher("CN")
return err == nil
default:
return false
}
}
func LoadGeoSiteMatcher(countryCode string) (*router.DomainMatcher, int, error) {
geoLoaderName := "standard"
geoLoader, err := GetGeoDataLoader(geoLoaderName)
if err != nil {
return nil, 0, err
@ -28,3 +54,28 @@ func LoadGeoSiteMatcher(countryCode string) (*router.DomainMatcher, int, error)
return matcher, len(domains), nil
}
func LoadGeoIPMatcher(country string) (*router.GeoIPMatcher, int, error) {
geoLoader, err := GetGeoDataLoader(geoLoaderName)
if err != nil {
return nil, 0, err
}
records, err := geoLoader.LoadGeoIP(strings.ReplaceAll(country, "!", ""))
if err != nil {
return nil, 0, err
}
geoIP := &router.GeoIP{
CountryCode: country,
Cidr: records,
ReverseMatch: strings.Contains(country, "!"),
}
matcher, err := router.NewGeoIPMatcher(geoIP)
if err != nil {
return nil, 0, err
}
return matcher, len(records), nil
}

View File

@ -1,12 +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

@ -0,0 +1,230 @@
package process
import (
"bytes"
"encoding/binary"
"fmt"
"net"
"os"
"path"
"path/filepath"
"strings"
"syscall"
"unicode"
"unsafe"
"github.com/Dreamacro/clash/common/pool"
)
// from https://github.com/vishvananda/netlink/blob/bca67dfc8220b44ef582c9da4e9172bf1c9ec973/nl/nl_linux.go#L52-L62
var nativeEndian = func() binary.ByteOrder {
var x uint32 = 0x01020304
if *(*byte)(unsafe.Pointer(&x)) == 0x01 {
return binary.BigEndian
}
return binary.LittleEndian
}()
const (
sizeOfSocketDiagRequest = syscall.SizeofNlMsghdr + 8 + 48
socketDiagByFamily = 20
pathProc = "/proc"
)
func findProcessName(network string, ip net.IP, srcPort int) (string, error) {
inode, uid, err := resolveSocketByNetlink(network, ip, srcPort)
if err != nil {
return "", err
}
return resolveProcessNameByProcSearch(inode, uid)
}
func resolveSocketByNetlink(network string, ip net.IP, srcPort int) (int32, int32, error) {
var family byte
var protocol byte
switch network {
case TCP:
protocol = syscall.IPPROTO_TCP
case UDP:
protocol = syscall.IPPROTO_UDP
default:
return 0, 0, ErrInvalidNetwork
}
if ip.To4() != nil {
family = syscall.AF_INET
} else {
family = syscall.AF_INET6
}
req := packSocketDiagRequest(family, protocol, ip, uint16(srcPort))
socket, err := syscall.Socket(syscall.AF_NETLINK, syscall.SOCK_DGRAM, syscall.NETLINK_INET_DIAG)
if err != nil {
return 0, 0, fmt.Errorf("dial netlink: %w", err)
}
defer syscall.Close(socket)
syscall.SetsockoptTimeval(socket, syscall.SOL_SOCKET, syscall.SO_SNDTIMEO, &syscall.Timeval{Usec: 100})
syscall.SetsockoptTimeval(socket, syscall.SOL_SOCKET, syscall.SO_RCVTIMEO, &syscall.Timeval{Usec: 100})
if err := syscall.Connect(socket, &syscall.SockaddrNetlink{
Family: syscall.AF_NETLINK,
Pad: 0,
Pid: 0,
Groups: 0,
}); err != nil {
return 0, 0, err
}
if _, err := syscall.Write(socket, req); err != nil {
return 0, 0, fmt.Errorf("write request: %w", err)
}
rb := pool.Get(pool.RelayBufferSize)
defer pool.Put(rb)
n, err := syscall.Read(socket, rb)
if err != nil {
return 0, 0, fmt.Errorf("read response: %w", err)
}
messages, err := syscall.ParseNetlinkMessage(rb[:n])
if err != nil {
return 0, 0, fmt.Errorf("parse netlink message: %w", err)
} else if len(messages) == 0 {
return 0, 0, fmt.Errorf("unexcepted netlink response")
}
message := messages[0]
if message.Header.Type&syscall.NLMSG_ERROR != 0 {
return 0, 0, fmt.Errorf("netlink message: NLMSG_ERROR")
}
uid, inode := unpackSocketDiagResponse(&messages[0])
if uid < 0 || inode < 0 {
return 0, 0, fmt.Errorf("invalid uid(%d) or inode(%d)", uid, inode)
}
return uid, inode, nil
}
func packSocketDiagRequest(family, protocol byte, source net.IP, sourcePort uint16) []byte {
s := make([]byte, 16)
if v4 := source.To4(); v4 != nil {
copy(s, v4)
} else {
copy(s, source)
}
buf := make([]byte, sizeOfSocketDiagRequest)
nativeEndian.PutUint32(buf[0:4], sizeOfSocketDiagRequest)
nativeEndian.PutUint16(buf[4:6], socketDiagByFamily)
nativeEndian.PutUint16(buf[6:8], syscall.NLM_F_REQUEST|syscall.NLM_F_DUMP)
nativeEndian.PutUint32(buf[8:12], 0)
nativeEndian.PutUint32(buf[12:16], 0)
buf[16] = family
buf[17] = protocol
buf[18] = 0
buf[19] = 0
nativeEndian.PutUint32(buf[20:24], 0xFFFFFFFF)
binary.BigEndian.PutUint16(buf[24:26], sourcePort)
binary.BigEndian.PutUint16(buf[26:28], 0)
copy(buf[28:44], s)
copy(buf[44:60], net.IPv6zero)
nativeEndian.PutUint32(buf[60:64], 0)
nativeEndian.PutUint64(buf[64:72], 0xFFFFFFFFFFFFFFFF)
return buf
}
func unpackSocketDiagResponse(msg *syscall.NetlinkMessage) (inode, uid int32) {
if len(msg.Data) < 72 {
return 0, 0
}
data := msg.Data
uid = int32(nativeEndian.Uint32(data[64:68]))
inode = int32(nativeEndian.Uint32(data[68:72]))
return
}
func resolveProcessNameByProcSearch(inode, uid int32) (string, error) {
files, err := os.ReadDir(pathProc)
if err != nil {
return "", err
}
buffer := make([]byte, syscall.PathMax)
socket := []byte(fmt.Sprintf("socket:[%d]", inode))
for _, f := range files {
if !f.IsDir() || !isPid(f.Name()) {
continue
}
info, err := f.Info()
if err != nil {
return "", err
}
if info.Sys().(*syscall.Stat_t).Uid != uint32(uid) {
continue
}
processPath := path.Join(pathProc, f.Name())
fdPath := path.Join(processPath, "fd")
fds, err := os.ReadDir(fdPath)
if err != nil {
continue
}
for _, fd := range fds {
n, err := syscall.Readlink(path.Join(fdPath, fd.Name()), buffer)
if err != nil {
continue
}
if bytes.Equal(buffer[:n], socket) {
cmdline, err := os.ReadFile(path.Join(processPath, "cmdline"))
if err != nil {
return "", err
}
return splitCmdline(cmdline), nil
}
}
}
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)
}) == -1
}

View File

@ -1,3 +1,5 @@
//go:build !android
package process
import (

View File

@ -174,7 +174,7 @@ func newSearcher(isV4, isTCP bool) *searcher {
func getTransportTable(fn uintptr, family int, class int) ([]byte, error) {
for size, buf := uint32(8), make([]byte, 8); ; {
ptr := unsafe.Pointer(&buf[0])
err, _, _ := syscall.Syscall6(fn, 6, uintptr(ptr), uintptr(unsafe.Pointer(&size)), 0, uintptr(family), uintptr(class), 0)
err, _, _ := syscall.SyscallN(fn, uintptr(ptr), uintptr(unsafe.Pointer(&size)), 0, uintptr(family), uintptr(class), 0)
switch err {
case 0:
@ -209,8 +209,8 @@ func getExecPathFromPID(pid uint32) (string, error) {
buf := make([]uint16, syscall.MAX_LONG_PATH)
size := uint32(len(buf))
r1, _, err := syscall.Syscall6(
queryProcName, 4,
r1, _, err := syscall.SyscallN(
queryProcName,
uintptr(h),
uintptr(1),
uintptr(unsafe.Pointer(&buf[0])),

View File

@ -0,0 +1,44 @@
package trie
import "errors"
var (
ErrorOverMaxValue = errors.New("the value don't over max value")
)
type IpCidrNode struct {
Mark bool
child map[uint32]*IpCidrNode
maxValue uint32
}
func NewIpCidrNode(mark bool, maxValue uint32) *IpCidrNode {
ipCidrNode := &IpCidrNode{
Mark: mark,
child: map[uint32]*IpCidrNode{},
maxValue: maxValue,
}
return ipCidrNode
}
func (n *IpCidrNode) addChild(value uint32) error {
if value > n.maxValue {
return ErrorOverMaxValue
}
n.child[value] = NewIpCidrNode(false, n.maxValue)
return nil
}
func (n *IpCidrNode) hasChild(value uint32) bool {
return n.getChild(value) != nil
}
func (n *IpCidrNode) getChild(value uint32) *IpCidrNode {
if value <= n.maxValue {
return n.child[value]
}
return nil
}

View File

@ -0,0 +1,255 @@
package trie
import (
"github.com/Dreamacro/clash/log"
"net"
)
type IPV6 bool
const (
ipv4GroupMaxValue = 0xFF
ipv6GroupMaxValue = 0xFFFF
)
type IpCidrTrie struct {
ipv4Trie *IpCidrNode
ipv6Trie *IpCidrNode
}
func NewIpCidrTrie() *IpCidrTrie {
return &IpCidrTrie{
ipv4Trie: NewIpCidrNode(false, ipv4GroupMaxValue),
ipv6Trie: NewIpCidrNode(false, ipv6GroupMaxValue),
}
}
func (trie *IpCidrTrie) AddIpCidr(ipCidr *net.IPNet) error {
subIpCidr, subCidr, isIpv4, err := ipCidrToSubIpCidr(ipCidr)
if err != nil {
return err
}
for _, sub := range subIpCidr {
addIpCidr(trie, isIpv4, sub, subCidr/8)
}
return nil
}
func (trie *IpCidrTrie) AddIpCidrForString(ipCidr string) error {
_, ipNet, err := net.ParseCIDR(ipCidr)
if err != nil {
return err
}
return trie.AddIpCidr(ipNet)
}
func (trie *IpCidrTrie) IsContain(ip net.IP) bool {
ip, isIpv4 := checkAndConverterIp(ip)
if ip == nil {
return false
}
var groupValues []uint32
var ipCidrNode *IpCidrNode
if isIpv4 {
ipCidrNode = trie.ipv4Trie
for _, group := range ip {
groupValues = append(groupValues, uint32(group))
}
} else {
ipCidrNode = trie.ipv6Trie
for i := 0; i < len(ip); i += 2 {
groupValues = append(groupValues, getIpv6GroupValue(ip[i], ip[i+1]))
}
}
return search(ipCidrNode, groupValues) != nil
}
func (trie *IpCidrTrie) IsContainForString(ipString string) bool {
return trie.IsContain(net.ParseIP(ipString))
}
func ipCidrToSubIpCidr(ipNet *net.IPNet) ([]net.IP, int, bool, error) {
maskSize, _ := ipNet.Mask.Size()
var (
ipList []net.IP
newMaskSize int
isIpv4 bool
err error
)
ip, isIpv4 := checkAndConverterIp(ipNet.IP)
ipList, newMaskSize, err = subIpCidr(ip, maskSize, isIpv4)
return ipList, newMaskSize, isIpv4, err
}
func subIpCidr(ip net.IP, maskSize int, isIpv4 bool) ([]net.IP, int, error) {
var subIpCidrList []net.IP
groupSize := 8
if !isIpv4 {
groupSize = 16
}
if maskSize%groupSize == 0 {
return append(subIpCidrList, ip), maskSize, nil
}
lastByteMaskSize := maskSize % 8
lastByteMaskIndex := maskSize / 8
subIpCidrNum := 0xFF >> lastByteMaskSize
for i := 0; i <= subIpCidrNum; i++ {
subIpCidr := make([]byte, len(ip))
copy(subIpCidr, ip)
subIpCidr[lastByteMaskIndex] += byte(i)
subIpCidrList = append(subIpCidrList, subIpCidr)
}
newMaskSize := (lastByteMaskIndex + 1) * 8
if !isIpv4 {
newMaskSize = (lastByteMaskIndex/2 + 1) * 16
}
return subIpCidrList, newMaskSize, nil
}
func addIpCidr(trie *IpCidrTrie, isIpv4 bool, ip net.IP, groupSize int) {
if isIpv4 {
addIpv4Cidr(trie, ip, groupSize)
} else {
addIpv6Cidr(trie, ip, groupSize)
}
}
func addIpv4Cidr(trie *IpCidrTrie, ip net.IP, groupSize int) {
preNode := trie.ipv4Trie
node := preNode.getChild(uint32(ip[0]))
if node == nil {
err := preNode.addChild(uint32(ip[0]))
if err != nil {
return
}
node = preNode.getChild(uint32(ip[0]))
}
for i := 1; i < groupSize; i++ {
if node.Mark {
return
}
groupValue := uint32(ip[i])
if !node.hasChild(groupValue) {
err := node.addChild(groupValue)
if err != nil {
log.Errorln(err.Error())
}
}
preNode = node
node = node.getChild(groupValue)
if node == nil {
err := preNode.addChild(uint32(ip[i-1]))
if err != nil {
return
}
node = preNode.getChild(uint32(ip[i-1]))
}
}
node.Mark = true
cleanChild(node)
}
func addIpv6Cidr(trie *IpCidrTrie, ip net.IP, groupSize int) {
preNode := trie.ipv6Trie
node := preNode.getChild(getIpv6GroupValue(ip[0], ip[1]))
if node == nil {
err := preNode.addChild(getIpv6GroupValue(ip[0], ip[1]))
if err != nil {
return
}
node = preNode.getChild(getIpv6GroupValue(ip[0], ip[1]))
}
for i := 2; i < groupSize; i += 2 {
if node.Mark {
return
}
groupValue := getIpv6GroupValue(ip[i], ip[i+1])
if !node.hasChild(groupValue) {
err := node.addChild(groupValue)
if err != nil {
log.Errorln(err.Error())
}
}
preNode = node
node = node.getChild(groupValue)
if node == nil {
err := preNode.addChild(getIpv6GroupValue(ip[i-2], ip[i-1]))
if err != nil {
return
}
node = preNode.getChild(getIpv6GroupValue(ip[i-2], ip[i-1]))
}
}
node.Mark = true
cleanChild(node)
}
func getIpv6GroupValue(high, low byte) uint32 {
return (uint32(high) << 8) | uint32(low)
}
func cleanChild(node *IpCidrNode) {
for i := uint32(0); i < uint32(len(node.child)); i++ {
delete(node.child, i)
}
}
func search(root *IpCidrNode, groupValues []uint32) *IpCidrNode {
node := root.getChild(groupValues[0])
if node == nil || node.Mark {
return node
}
for _, value := range groupValues[1:] {
if !node.hasChild(value) {
return nil
}
node = node.getChild(value)
if node == nil || node.Mark {
return node
}
}
return nil
}
// return net.IP To4 or To16 and is ipv4
func checkAndConverterIp(ip net.IP) (net.IP, bool) {
ipResult := ip.To4()
if ipResult == nil {
ipResult = ip.To16()
if ipResult == nil {
return nil, false
}
return ipResult, false
}
return ipResult, true
}

100
component/trie/trie_test.go Normal file
View File

@ -0,0 +1,100 @@
package trie
import (
"net"
"testing"
)
import "github.com/stretchr/testify/assert"
func TestIpv4AddSuccess(t *testing.T) {
trie := NewIpCidrTrie()
err := trie.AddIpCidrForString("10.0.0.2/16")
assert.Equal(t, nil, err)
}
func TestIpv4AddFail(t *testing.T) {
trie := NewIpCidrTrie()
err := trie.AddIpCidrForString("333.00.23.2/23")
assert.IsType(t, new(net.ParseError), err)
err = trie.AddIpCidrForString("22.3.34.2/222")
assert.IsType(t, new(net.ParseError), err)
err = trie.AddIpCidrForString("2.2.2.2")
assert.IsType(t, new(net.ParseError), err)
}
func TestIpv4Search(t *testing.T) {
trie := NewIpCidrTrie()
// Boundary testing
assert.NoError(t, trie.AddIpCidrForString("149.154.160.0/20"))
assert.Equal(t, true, trie.IsContainForString("149.154.160.0"))
assert.Equal(t, true, trie.IsContainForString("149.154.175.255"))
assert.Equal(t, false, trie.IsContainForString("149.154.176.0"))
assert.Equal(t, false, trie.IsContainForString("149.154.159.255"))
assert.NoError(t, trie.AddIpCidrForString("129.2.36.0/16"))
assert.NoError(t, trie.AddIpCidrForString("10.2.36.0/18"))
assert.NoError(t, trie.AddIpCidrForString("16.2.23.0/24"))
assert.NoError(t, trie.AddIpCidrForString("11.2.13.2/26"))
assert.NoError(t, trie.AddIpCidrForString("55.5.6.3/8"))
assert.NoError(t, trie.AddIpCidrForString("66.23.25.4/6"))
assert.Equal(t, true, trie.IsContainForString("129.2.3.65"))
assert.Equal(t, false, trie.IsContainForString("15.2.3.1"))
assert.Equal(t, true, trie.IsContainForString("11.2.13.1"))
assert.Equal(t, true, trie.IsContainForString("55.0.0.0"))
assert.Equal(t, true, trie.IsContainForString("64.0.0.0"))
assert.Equal(t, false, trie.IsContainForString("128.0.0.0"))
assert.Equal(t, false, trie.IsContain(net.ParseIP("22")))
assert.Equal(t, false, trie.IsContain(net.ParseIP("")))
}
func TestIpv6AddSuccess(t *testing.T) {
trie := NewIpCidrTrie()
err := trie.AddIpCidrForString("2001:0db8:02de:0000:0000:0000:0000:0e13/32")
assert.Equal(t, nil, err)
err = trie.AddIpCidrForString("2001:1db8:f2de::0e13/18")
assert.Equal(t, nil, err)
}
func TestIpv6AddFail(t *testing.T) {
trie := NewIpCidrTrie()
err := trie.AddIpCidrForString("2001::25de::cade/23")
assert.IsType(t, new(net.ParseError), err)
err = trie.AddIpCidrForString("2001:0fa3:25de::cade/222")
assert.IsType(t, new(net.ParseError), err)
err = trie.AddIpCidrForString("2001:0fa3:25de::cade")
assert.IsType(t, new(net.ParseError), err)
}
func TestIpv6Search(t *testing.T) {
trie := NewIpCidrTrie()
// Boundary testing
assert.NoError(t, trie.AddIpCidrForString("2a0a:f280::/32"))
assert.Equal(t, true, trie.IsContainForString("2a0a:f280:0000:0000:0000:0000:0000:0000"))
assert.Equal(t, true, trie.IsContainForString("2a0a:f280:ffff:ffff:ffff:ffff:ffff:ffff"))
assert.Equal(t, false, trie.IsContainForString("2a0a:f279:ffff:ffff:ffff:ffff:ffff:ffff"))
assert.Equal(t, false, trie.IsContainForString("2a0a:f281:0000:0000:0000:0000:0000:0000"))
assert.NoError(t, trie.AddIpCidrForString("2001:b28:f23d:f001::e/128"))
assert.NoError(t, trie.AddIpCidrForString("2001:67c:4e8:f002::e/12"))
assert.NoError(t, trie.AddIpCidrForString("2001:b28:f23d:f003::e/96"))
assert.NoError(t, trie.AddIpCidrForString("2001:67c:4e8:f002::a/32"))
assert.NoError(t, trie.AddIpCidrForString("2001:67c:4e8:f004::a/60"))
assert.NoError(t, trie.AddIpCidrForString("2001:b28:f23f:f005::a/64"))
assert.Equal(t, true, trie.IsContainForString("2001:b28:f23d:f001::e"))
assert.Equal(t, false, trie.IsContainForString("2222::fff2"))
assert.Equal(t, true, trie.IsContainForString("2000::ffa0"))
assert.Equal(t, true, trie.IsContainForString("2001:b28:f23f:f005:5662::"))
assert.Equal(t, true, trie.IsContainForString("2001:67c:4e8:9666::1213"))
assert.Equal(t, false, trie.IsContain(net.ParseIP("22233:22")))
}

View File

@ -1,14 +1,18 @@
package config
import (
"container/list"
"errors"
"fmt"
R "github.com/Dreamacro/clash/rule"
RP "github.com/Dreamacro/clash/rule/provider"
"net"
"net/netip"
"net/url"
"os"
"runtime"
"strings"
"time"
"github.com/Dreamacro/clash/adapter"
"github.com/Dreamacro/clash/adapter/outbound"
@ -25,7 +29,6 @@ import (
"github.com/Dreamacro/clash/dns"
"github.com/Dreamacro/clash/listener/tun/ipstack/commons"
"github.com/Dreamacro/clash/log"
R "github.com/Dreamacro/clash/rule"
T "github.com/Dreamacro/clash/tunnel"
"gopkg.in/yaml.v2"
@ -35,11 +38,14 @@ import (
type General struct {
Inbound
Controller
Mode T.TunnelMode `json:"mode"`
LogLevel log.LogLevel `json:"log-level"`
IPv6 bool `json:"ipv6"`
Interface string `json:"-"`
RoutingMark int `json:"-"`
Mode T.TunnelMode `json:"mode"`
UnifiedDelay bool
LogLevel log.LogLevel `json:"log-level"`
IPv6 bool `json:"ipv6"`
Interface string `json:"-"`
RoutingMark int `json:"-"`
GeodataMode bool `json:"geodata-mode"`
GeodataLoader string `json:"geodata-loader"`
}
// Inbound config
@ -86,6 +92,12 @@ 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"`
@ -101,10 +113,17 @@ type Tun struct {
AutoRoute bool `yaml:"auto-route" json:"auto-route"`
}
// Script config
type Script struct {
MainCode string `yaml:"code" json:"code"`
ShortcutsCode map[string]string `yaml:"shortcuts" json:"shortcuts"`
}
// IPTables config
type IPTables struct {
Enable bool `yaml:"enable" json:"enable"`
InboundInterface string `yaml:"inbound-interface" json:"inbound-interface"`
Enable bool `yaml:"enable" json:"enable"`
InboundInterface string `yaml:"inbound-interface" json:"inbound-interface"`
Bypass []string `yaml:"bypass" json:"bypass"`
}
// Experimental config
@ -112,17 +131,18 @@ type Experimental struct{}
// Config is clash config manager
type Config struct {
General *General
Tun *Tun
IPTables *IPTables
DNS *DNS
Experimental *Experimental
Hosts *trie.DomainTrie
Profile *Profile
Rules []C.Rule
Users []auth.AuthUser
Proxies map[string]C.Proxy
Providers map[string]providerTypes.ProxyProvider
General *General
Tun *Tun
IPTables *IPTables
DNS *DNS
Experimental *Experimental
Hosts *trie.DomainTrie
Profile *Profile
Rules []C.Rule
Users []auth.AuthUser
Proxies map[string]C.Proxy
Providers map[string]providerTypes.ProxyProvider
RuleProviders map[string]*providerTypes.RuleProvider
}
type RawDNS struct {
@ -167,6 +187,7 @@ type RawConfig struct {
AllowLan bool `yaml:"allow-lan"`
BindAddress string `yaml:"bind-address"`
Mode T.TunnelMode `yaml:"mode"`
UnifiedDelay bool `yaml:"unified-delay"`
LogLevel log.LogLevel `yaml:"log-level"`
IPv6 bool `yaml:"ipv6"`
ExternalController string `yaml:"external-controller"`
@ -174,8 +195,11 @@ type RawConfig struct {
Secret string `yaml:"secret"`
Interface string `yaml:"interface-name"`
RoutingMark int `yaml:"routing-mark"`
GeodataMode bool `yaml:"geodata-mode"`
GeodataLoader string `yaml:"geodata-loader"`
ProxyProvider map[string]map[string]any `yaml:"proxy-providers"`
RuleProvider map[string]map[string]any `yaml:"rule-providers"`
Hosts map[string]string `yaml:"hosts"`
DNS RawDNS `yaml:"dns"`
Tun RawTun `yaml:"tun"`
@ -203,6 +227,9 @@ func UnmarshalRawConfig(buf []byte) (*RawConfig, error) {
AllowLan: false,
BindAddress: "*",
Mode: T.Rule,
GeodataMode: C.GeodataMode,
GeodataLoader: "memconservative",
UnifiedDelay: false,
Authentication: []string{},
LogLevel: log.INFO,
Hosts: map[string]string{},
@ -219,6 +246,7 @@ func UnmarshalRawConfig(buf []byte) (*RawConfig, error) {
IPTables: IPTables{
Enable: false,
InboundInterface: "lo",
Bypass: []string{},
},
DNS: RawDNS{
Enable: false,
@ -234,11 +262,18 @@ func UnmarshalRawConfig(buf []byte) (*RawConfig, error) {
DefaultNameserver: []string{
"114.114.114.114",
"223.5.5.5",
"8.8.8.8",
"1.0.0.1",
},
NameServer: []string{ // default if user not set
NameServer: []string{
"https://doh.pub/dns-query",
"tls://223.5.5.5:853",
},
FakeIPFilter: []string{
"dns.msftnsci.com",
"www.msftnsci.com",
"www.msftconnecttest.com",
},
},
Profile: Profile{
StoreSelected: true,
@ -254,7 +289,8 @@ 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
startTime := time.Now()
config.Experimental = &rawCfg.Experimental
config.Profile = &rawCfg.Profile
config.IPTables = &rawCfg.IPTables
@ -280,11 +316,12 @@ func ParseRawConfig(rawCfg *RawConfig) (*Config, error) {
config.Proxies = proxies
config.Providers = providers
rules, err := parseRules(rawCfg, proxies)
rules, ruleProviders, err := parseRules(rawCfg, proxies)
if err != nil {
return nil, err
}
config.Rules = rules
config.RuleProviders = ruleProviders
hosts, err := parseHosts(rawCfg)
if err != nil {
@ -300,12 +337,14 @@ func ParseRawConfig(rawCfg *RawConfig) (*Config, error) {
config.Users = parseAuthentication(rawCfg.Authentication)
elapsedTime := time.Since(startTime) / time.Millisecond // duration in ms
log.Infoln("Initial configuration complete, total time: %dms", elapsedTime) //Segment finished in xxm
return config, nil
}
func parseGeneral(cfg *RawConfig) (*General, error) {
externalUI := cfg.ExternalUI
geodata.SetLoader(cfg.GeodataLoader)
// checkout externalUI exist
if externalUI != "" {
externalUI = C.Path.Resolve(externalUI)
@ -330,11 +369,14 @@ func parseGeneral(cfg *RawConfig) (*General, error) {
ExternalUI: cfg.ExternalUI,
Secret: cfg.Secret,
},
Mode: cfg.Mode,
LogLevel: cfg.LogLevel,
IPv6: cfg.IPv6,
Interface: cfg.Interface,
RoutingMark: cfg.RoutingMark,
UnifiedDelay: cfg.UnifiedDelay,
Mode: cfg.Mode,
LogLevel: cfg.LogLevel,
IPv6: cfg.IPv6,
Interface: cfg.Interface,
RoutingMark: cfg.RoutingMark,
GeodataMode: cfg.GeodataMode,
GeodataLoader: cfg.GeodataLoader,
}, nil
}
@ -346,9 +388,13 @@ func parseProxies(cfg *RawConfig) (proxies map[string]C.Proxy, providersMap map[
providersConfig := cfg.ProxyProvider
var proxyList []string
_proxiesList := list.New()
_groupsList := list.New()
proxies["DIRECT"] = adapter.NewProxy(outbound.NewDirect())
proxies["REJECT"] = adapter.NewProxy(outbound.NewReject())
proxies["COMPATIBLE"] = adapter.NewProxy(outbound.NewCompatible())
proxies["PASS"] = adapter.NewProxy(outbound.NewPass())
proxyList = append(proxyList, "DIRECT", "REJECT")
// parse proxy
@ -363,6 +409,7 @@ func parseProxies(cfg *RawConfig) (proxies map[string]C.Proxy, providersMap map[
}
proxies[proxy.Name()] = proxy
proxyList = append(proxyList, proxy.Name())
_proxiesList.PushBack(mapping)
}
// keep the original order of ProxyGroups in config file
@ -372,6 +419,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)
}
// check if any loop exists and sort the ProxyGroups
@ -393,13 +441,6 @@ func parseProxies(cfg *RawConfig) (proxies map[string]C.Proxy, providersMap map[
providersMap[name] = pd
}
for _, proxyProvider := range providersMap {
log.Infoln("Start initial provider %s", proxyProvider.Name())
if err := proxyProvider.Initial(); err != nil {
return nil, nil, fmt.Errorf("initial proxy provider %s error: %w", proxyProvider.Name(), err)
}
}
// parse proxy group
for idx, mapping := range groupsConfig {
group, err := outboundgroup.ParseProxyGroup(mapping, proxies, providersMap)
@ -415,20 +456,11 @@ func parseProxies(cfg *RawConfig) (proxies map[string]C.Proxy, providersMap map[
proxies[groupName] = adapter.NewProxy(group)
}
// initial compatible provider
for _, pd := range providersMap {
if pd.VehicleType() != providerTypes.Compatible {
continue
}
log.Infoln("Start initial compatible provider %s", pd.Name())
if err := pd.Initial(); err != nil {
return nil, nil, err
}
}
var ps []C.Proxy
for _, v := range proxyList {
if proxies[v].Type() == C.Pass {
continue
}
ps = append(ps, proxies[v])
}
hc := provider.NewHealthCheck(ps, "", 0, true)
@ -442,13 +474,32 @@ 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
}
func parseRules(cfg *RawConfig, proxies map[string]C.Proxy) ([]C.Rule, error) {
rulesConfig := cfg.Rule
func parseRules(cfg *RawConfig, proxies map[string]C.Proxy) ([]C.Rule, map[string]*providerTypes.RuleProvider, error) {
ruleProviders := map[string]*providerTypes.RuleProvider{}
log.Infoln("Geodata Loader mode: %s", geodata.LoaderName())
// parse rule provider
for name, mapping := range cfg.RuleProvider {
rp, err := RP.ParseRuleProvider(name, mapping)
if err != nil {
return nil, nil, err
}
ruleProviders[name] = &rp
RP.SetRuleProvider(rp)
}
var rules []C.Rule
rulesConfig := cfg.Rule
mode := cfg.Mode
// parse rules
for idx, line := range rulesConfig {
@ -460,45 +511,58 @@ func parseRules(cfg *RawConfig, proxies map[string]C.Proxy) ([]C.Rule, error) {
ruleName = strings.ToUpper(rule[0])
)
if mode == T.Script && ruleName != "GEOSITE" {
continue
}
l := len(rule)
if l < 2 {
return nil, fmt.Errorf("rules[%d] [%s] error: format invalid", idx, line)
if ruleName == "NOT" || ruleName == "OR" || ruleName == "AND" {
target = rule[l-1]
payload = strings.Join(rule[1:l-1], ",")
} else {
if l < 2 {
return nil, nil, fmt.Errorf("rules[%d] [%s] error: format invalid", idx, line)
}
if l < 4 {
rule = append(rule, make([]string, 4-l)...)
}
if ruleName == "MATCH" {
l = 2
}
if l >= 3 {
l = 3
payload = rule[1]
}
target = rule[l-1]
params = rule[l:]
}
if l < 4 {
rule = append(rule, make([]string, 4-l)...)
}
if ruleName == "MATCH" {
l = 2
}
if l >= 3 {
l = 3
payload = rule[1]
}
target = rule[l-1]
params = rule[l:]
if _, ok := proxies[target]; !ok {
return nil, fmt.Errorf("rules[%d] [%s] error: proxy [%s] not found", idx, line, target)
if _, ok := proxies[target]; mode != T.Script && !ok {
return nil, nil, fmt.Errorf("rules[%d] [%s] error: proxy [%s] not found", idx, line, target)
}
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, fmt.Errorf("rules[%d] [%s] error: %s", idx, line, parseErr.Error())
return nil, nil, fmt.Errorf("rules[%d] [%s] error: %s", idx, line, parseErr.Error())
}
rules = append(rules, parsed)
if mode != T.Script {
rules = append(rules, parsed)
}
}
runtime.GC()
return rules, nil
return rules, ruleProviders, nil
}
func parseHosts(cfg *RawConfig) (*trie.DomainTrie, error) {
@ -570,6 +634,9 @@ func parseNameServer(servers []string) ([]dns.NameServer, error) {
case "dhcp":
addr = u.Host
dnsNetType = "dhcp" // UDP from DHCP
case "quic":
addr, err = hostWithDefaultPort(u.Host, "784")
dnsNetType = "quic" // DNS over QUIC
default:
return nil, fmt.Errorf("DNS NameServer[%d] unsupport scheme: %s", idx, u.Scheme)
}
@ -624,6 +691,11 @@ func parseFallbackIPCIDR(ips []string) ([]*net.IPNet, error) {
func parseFallbackGeoSite(countries []string, rules []C.Rule) ([]*router.DomainMatcher, error) {
var sites []*router.DomainMatcher
if len(countries) > 0 {
if err := initGeoSite(); err != nil {
return nil, fmt.Errorf("can't initial GeoSite: %s", err)
}
}
for _, country := range countries {
found := false
@ -761,7 +833,7 @@ func parseDNS(rawCfg *RawConfig, hosts *trie.DomainTrie, rules []C.Rule) (*DNS,
}
func parseAuthentication(rawRecords []string) []auth.AuthUser {
users := []auth.AuthUser{}
var users []auth.AuthUser
for _, line := range rawRecords {
if user, pass, found := strings.Cut(line, ":"); found {
users = append(users, auth.AuthUser{User: user, Pass: pass})
@ -774,7 +846,9 @@ func parseTun(rawTun RawTun, general *General) (*Tun, error) {
if (rawTun.Enable || general.TProxyPort != 0) && general.Interface == "" {
autoDetectInterfaceName, err := commons.GetAutoDetectInterface()
if err != nil || autoDetectInterfaceName == "" {
return nil, fmt.Errorf("can not find auto detect interface: %w. you must be detect `interface-name` if tun set to enable or `tproxy-port` isn't zore", err)
log.Warnln("Can not find auto detect interface.[%s]", err)
} else {
log.Warnln("Auto detect interface: %s", autoDetectInterfaceName)
}
general.Interface = autoDetectInterfaceName

View File

@ -2,17 +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/mmdb"
C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/log"
)
var initMode = true
func downloadMMDB(path string) (err error) {
resp, err := http.Get("https://cdn.jsdelivr.net/gh/Loyalsoldier/geoip@release/Country.mmdb")
resp, err := http.Get("https://raw.githubusercontents.com/Loyalsoldier/geoip/release/Country.mmdb")
if err != nil {
return
}
@ -28,7 +31,84 @@ func downloadMMDB(path string) (err error) {
return err
}
func initMMDB() error {
func downloadGeoIP(path string) (err error) {
resp, err := http.Get("https://raw.githubusercontents.com/Loyalsoldier/v2ray-rules-dat/release/geoip.dat")
if err != nil {
return
}
defer resp.Body.Close()
f, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY, 0o644)
if err != nil {
return err
}
defer f.Close()
_, err = io.Copy(f, resp.Body)
return err
}
func downloadGeoSite(path string) (err error) {
resp, err := http.Get("https://raw.githubusercontents.com/Loyalsoldier/v2ray-rules-dat/release/geosite.dat")
if err != nil {
return
}
defer resp.Body.Close()
f, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY, 0o644)
if err != nil {
return err
}
defer f.Close()
_, err = io.Copy(f, resp.Body)
return err
}
func initGeoSite() error {
if _, err := os.Stat(C.Path.GeoSite()); os.IsNotExist(err) {
log.Infoln("Can't find GeoSite.dat, start download")
if err := downloadGeoSite(C.Path.GeoSite()); err != nil {
return fmt.Errorf("can't download GeoSite.dat: %s", err.Error())
}
log.Infoln("Download GeoSite.dat finish")
}
if initMode {
if !geodata.Verify(C.GeositeName) {
log.Warnln("GeoSite.dat invalid, remove and download")
if err := os.Remove(C.Path.GeoSite()); err != nil {
return fmt.Errorf("can't remove invalid GeoSite.dat: %s", err.Error())
}
if err := downloadGeoSite(C.Path.GeoSite()); err != nil {
return fmt.Errorf("can't download GeoSite.dat: %s", err.Error())
}
}
}
return nil
}
func initGeoIP() error {
if C.GeodataMode {
if _, err := os.Stat(C.Path.GeoIP()); os.IsNotExist(err) {
log.Infoln("Can't find GeoIP.dat, start download")
if err := downloadGeoIP(C.Path.GeoIP()); err != nil {
return fmt.Errorf("can't download GeoIP.dat: %s", err.Error())
}
log.Infoln("Download GeoIP.dat finish")
}
if !geodata.Verify(C.GeoipName) {
log.Warnln("GeoIP.dat invalid, remove and download")
if err := os.Remove(C.Path.GeoIP()); err != nil {
return fmt.Errorf("can't remove invalid GeoIP.dat: %s", err.Error())
}
if err := downloadGeoIP(C.Path.GeoIP()); err != nil {
return fmt.Errorf("can't download GeoIP.dat: %s", err.Error())
}
}
return nil
}
if _, err := os.Stat(C.Path.MMDB()); os.IsNotExist(err) {
log.Infoln("Can't find MMDB, start download")
if err := downloadMMDB(C.Path.MMDB()); err != nil {
@ -50,65 +130,6 @@ func initMMDB() error {
return nil
}
//func downloadGeoIP(path string) (err error) {
// resp, err := http.Get("https://cdn.jsdelivr.net/gh/Loyalsoldier/v2ray-rules-dat@release/geoip.dat")
// if err != nil {
// return
// }
// defer resp.Body.Close()
//
// f, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY, 0644)
// if err != nil {
// return err
// }
// defer f.Close()
// _, err = io.Copy(f, resp.Body)
//
// return err
//}
func downloadGeoSite(path string) (err error) {
resp, err := http.Get("https://cdn.jsdelivr.net/gh/Loyalsoldier/v2ray-rules-dat@release/geosite.dat")
if err != nil {
return
}
defer resp.Body.Close()
f, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY, 0o644)
if err != nil {
return err
}
defer f.Close()
_, err = io.Copy(f, resp.Body)
return err
}
//
//func initGeoIP() error {
// if _, err := os.Stat(C.Path.GeoIP()); os.IsNotExist(err) {
// log.Infoln("Can't find GeoIP.dat, start download")
// if err := downloadGeoIP(C.Path.GeoIP()); err != nil {
// return fmt.Errorf("can't download GeoIP.dat: %s", err.Error())
// }
// log.Infoln("Download GeoIP.dat finish")
// }
//
// return nil
//}
func initGeoSite() error {
if _, err := os.Stat(C.Path.GeoSite()); os.IsNotExist(err) {
log.Infoln("Can't find GeoSite.dat, start download")
if err := downloadGeoSite(C.Path.GeoSite()); err != nil {
return fmt.Errorf("can't download GeoSite.dat: %s", err.Error())
}
log.Infoln("Download GeoSite.dat finish")
}
return nil
}
// Init prepare necessary files
func Init(dir string) error {
// initial homedir
@ -128,20 +149,20 @@ func Init(dir string) error {
f.Write([]byte(`mixed-port: 7890`))
f.Close()
}
//// initial GeoIP
//if err := initGeoIP(); err != nil {
// return fmt.Errorf("can't initial GeoIP: %w", err)
//}
// initial mmdb
if err := initMMDB(); err != nil {
return fmt.Errorf("can't initial MMDB: %w", err)
buf, _ := os.ReadFile(C.Path.Config())
rawCfg, err := UnmarshalRawConfig(buf)
if err != nil {
log.Errorln(err.Error())
fmt.Printf("configuration file %s test failed\n", C.Path.Config())
os.Exit(1)
}
if !C.GeodataMode {
C.GeodataMode = rawCfg.GeodataMode
}
// initial GeoIP
if err := initGeoIP(); err != nil {
return fmt.Errorf("can't initial GeoIP: %w", err)
}
// initial GeoSite
if err := initGeoSite(); err != nil {
return fmt.Errorf("can't initial GeoSite: %w", err)
}
return nil
}

View File

@ -13,6 +13,14 @@ import (
const (
Direct AdapterType = iota
Reject
Compatible
Pass
Relay
Selector
Fallback
URLTest
LoadBalance
Shadowsocks
ShadowsocksR
@ -22,12 +30,6 @@ const (
Vmess
Vless
Trojan
Relay
Selector
Fallback
URLTest
LoadBalance
)
const (
@ -129,7 +131,10 @@ func (at AdapterType) String() string {
return "Direct"
case Reject:
return "Reject"
case Compatible:
return "Compatible"
case Pass:
return "Pass"
case Shadowsocks:
return "Shadowsocks"
case ShadowsocksR:

3
constant/geodata.go Normal file
View File

@ -0,0 +1,3 @@
package constant
var GeodataMode bool

View File

@ -2,6 +2,7 @@ package constant
import (
"encoding/json"
"fmt"
"net"
"strconv"
)
@ -23,6 +24,7 @@ const (
REDIR
TPROXY
TUN
INNER
)
type NetWork int
@ -58,6 +60,8 @@ func (t Type) String() string {
return "TProxy"
case TUN:
return "Tun"
case INNER:
return "Inner"
default:
return "Unknown"
}
@ -90,6 +94,18 @@ func (m *Metadata) SourceAddress() string {
return net.JoinHostPort(m.SrcIP.String(), m.SrcPort)
}
func (m *Metadata) SourceDetail() string {
if m.Process != "" {
return fmt.Sprintf("%s(%s)", m.SourceAddress(), m.Process)
} else {
if m.Type == INNER {
return fmt.Sprintf("[Clash]")
}
return fmt.Sprintf("%s", m.SourceAddress())
}
}
func (m *Metadata) Resolved() bool {
return m.DstIP != nil
}

View File

@ -1,13 +1,20 @@
package constant
import (
"io/ioutil"
"os"
P "path"
"path/filepath"
"strings"
)
const Name = "clash"
var (
GeositeName = "GeoSite.dat"
GeoipName = "GeoIP.dat"
)
// Path is used to get the configuration path
var Path = func() *path {
homeDir, err := os.UserHomeDir()
@ -22,6 +29,7 @@ var Path = func() *path {
type path struct {
homeDir string
configFile string
scriptDir string
}
// SetHomeDir is used to set the configuration path
@ -47,11 +55,25 @@ func (p *path) Resolve(path string) string {
if !filepath.IsAbs(path) {
return filepath.Join(p.HomeDir(), path)
}
return path
}
func (p *path) MMDB() string {
files, err := ioutil.ReadDir(p.homeDir)
if err != nil {
return ""
}
for _, fi := range files {
if fi.IsDir() {
// 目录则直接跳过
continue
} else {
if strings.EqualFold(fi.Name(), "Country.mmdb") {
GeoipName = fi.Name()
return P.Join(p.homeDir, fi.Name())
}
}
}
return P.Join(p.homeDir, "Country.mmdb")
}
@ -64,13 +86,69 @@ func (p *path) Cache() string {
}
func (p *path) GeoIP() string {
return P.Join(p.homeDir, "geoip.dat")
files, err := ioutil.ReadDir(p.homeDir)
if err != nil {
return ""
}
for _, fi := range files {
if fi.IsDir() {
// 目录则直接跳过
continue
} else {
if strings.EqualFold(fi.Name(), "GeoIP.dat") {
GeoipName = fi.Name()
return P.Join(p.homeDir, fi.Name())
}
}
}
return P.Join(p.homeDir, "GeoIP.dat")
}
func (p *path) GeoSite() string {
return P.Join(p.homeDir, "geosite.dat")
files, err := ioutil.ReadDir(p.homeDir)
if err != nil {
return ""
}
for _, fi := range files {
if fi.IsDir() {
// 目录则直接跳过
continue
} else {
if strings.EqualFold(fi.Name(), "GeoSite.dat") {
GeositeName = fi.Name()
return P.Join(p.homeDir, fi.Name())
}
}
}
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)
}
func (p *path) GetExecutableFullPath() string {
exePath, err := os.Executable()
if err != nil {
return "clash"
}
res, _ := filepath.EvalSymlinks(exePath)
return res
}

View File

@ -13,7 +13,13 @@ const (
DstPort
Process
ProcessPath
Script
RuleSet
Network
MATCH
AND
OR
NOT
)
type RuleType int
@ -42,8 +48,20 @@ func (rt RuleType) String() string {
return "Process"
case ProcessPath:
return "ProcessPath"
case Script:
return "Script"
case MATCH:
return "Match"
case RuleSet:
return "RuleSet"
case Network:
return "Network"
case AND:
return "AND"
case OR:
return "OR"
case NOT:
return "NOT"
default:
return "Unknown"
}
@ -55,7 +73,7 @@ type Rule interface {
Adapter() string
Payload() string
ShouldResolveIP() bool
ShouldFindProcess() bool
RuleExtra() *RuleExtra
SetRuleExtra(re *RuleExtra)
ShouldFindProcess() bool
}

View File

@ -1,6 +1,8 @@
package constant
var (
Version = "unknown version"
Meta = true
Version = "1.10.0"
BuildTime = "unknown time"
ClashName = "Clash.Meta"
)

View File

@ -63,7 +63,7 @@ func (dc *dohClient) newRequest(m *D.Msg) (*http.Request, error) {
return req, nil
}
func (dc *dohClient) doRequest(req *http.Request) (msg *D.Msg, err error) {
func (dc *dohClient) doRequest(req *http.Request) (*D.Msg, error) {
client := &http.Client{Transport: dc.transport}
resp, err := client.Do(req)
if err != nil {
@ -75,7 +75,7 @@ func (dc *dohClient) doRequest(req *http.Request) (msg *D.Msg, err error) {
if err != nil {
return nil, err
}
msg = &D.Msg{}
msg := &D.Msg{}
err = msg.Unpack(buf)
return msg, err
}

View File

@ -1,12 +1,14 @@
package dns
import (
"net"
"strings"
"github.com/Dreamacro/clash/component/geodata"
"github.com/Dreamacro/clash/component/geodata/router"
"github.com/Dreamacro/clash/component/mmdb"
"github.com/Dreamacro/clash/component/trie"
C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/log"
"net"
"strings"
)
type fallbackIPFilter interface {
@ -17,9 +19,42 @@ type geoipFilter struct {
code string
}
var geoIPMatcher *router.GeoIPMatcher
func (gf *geoipFilter) Match(ip net.IP) bool {
record, _ := mmdb.Instance().Country(ip)
return !strings.EqualFold(record.Country.IsoCode, gf.code) && !ip.IsPrivate()
if !C.GeodataMode {
record, _ := mmdb.Instance().Country(ip)
return !strings.EqualFold(record.Country.IsoCode, gf.code) && !ip.IsPrivate()
}
if geoIPMatcher == nil {
countryCode := "cn"
geoLoader, err := geodata.GetGeoDataLoader(geodata.LoaderName())
if err != nil {
log.Errorln("[GeoIPFilter] GetGeoDataLoader error: %s", err.Error())
return false
}
records, err := geoLoader.LoadGeoIP(countryCode)
if err != nil {
log.Errorln("[GeoIPFilter] LoadGeoIP error: %s", err.Error())
return false
}
geoIP := &router.GeoIP{
CountryCode: countryCode,
Cidr: records,
ReverseMatch: false,
}
geoIPMatcher, err = router.NewGeoIPMatcher(geoIP)
if err != nil {
log.Errorln("[GeoIPFilter] NewGeoIPMatcher error: %s", err.Error())
return false
}
}
return !geoIPMatcher.Match(ip)
}
type ipnetFilter struct {

146
dns/quic.go Normal file
View File

@ -0,0 +1,146 @@
package dns
import (
"bytes"
"context"
"crypto/tls"
"fmt"
"sync"
"time"
"github.com/Dreamacro/clash/log"
"github.com/lucas-clemente/quic-go"
D "github.com/miekg/dns"
)
const NextProtoDQ = "doq-i00"
var bytesPool = sync.Pool{New: func() interface{} { return &bytes.Buffer{} }}
type quicClient struct {
addr string
session quic.Session
sync.RWMutex // protects session and bytesPool
}
func (dc *quicClient) Exchange(m *D.Msg) (msg *D.Msg, err error) {
return dc.ExchangeContext(context.Background(), m)
}
func (dc *quicClient) ExchangeContext(ctx context.Context, m *D.Msg) (msg *D.Msg, err error) {
stream, err := dc.openStream(ctx)
if err != nil {
return nil, fmt.Errorf("failed to open new stream to %s", dc.addr)
}
buf, err := m.Pack()
if err != nil {
return nil, err
}
_, err = stream.Write(buf)
if err != nil {
return nil, err
}
// The client MUST send the DNS query over the selected stream, and MUST
// indicate through the STREAM FIN mechanism that no further data will
// be sent on that stream.
// stream.Close() -- closes the write-direction of the stream.
_ = stream.Close()
respBuf := bytesPool.Get().(*bytes.Buffer)
defer bytesPool.Put(respBuf)
defer respBuf.Reset()
n, err := respBuf.ReadFrom(stream)
if err != nil && n == 0 {
return nil, err
}
reply := new(D.Msg)
err = reply.Unpack(respBuf.Bytes())
if err != nil {
return nil, err
}
return reply, nil
}
func isActive(s quic.Session) bool {
select {
case <-s.Context().Done():
return false
default:
return true
}
}
// getSession - opens or returns an existing quic.Session
// useCached - if true and cached session exists, return it right away
// otherwise - forcibly creates a new session
func (dc *quicClient) getSession() (quic.Session, error) {
var session quic.Session
dc.RLock()
session = dc.session
if session != nil && isActive(session) {
dc.RUnlock()
return session, nil
}
if session != nil {
// we're recreating the session, let's create a new one
_ = session.CloseWithError(0, "")
}
dc.RUnlock()
dc.Lock()
defer dc.Unlock()
var err error
session, err = dc.openSession()
if err != nil {
// This does not look too nice, but QUIC (or maybe quic-go)
// doesn't seem stable enough.
// Maybe retransmissions aren't fully implemented in quic-go?
// Anyways, the simple solution is to make a second try when
// it fails to open the QUIC session.
session, err = dc.openSession()
if err != nil {
return nil, err
}
}
dc.session = session
return session, nil
}
func (dc *quicClient) openSession() (quic.Session, error) {
tlsConfig := &tls.Config{
InsecureSkipVerify: true,
NextProtos: []string{
"http/1.1", "h2", NextProtoDQ,
},
SessionTicketsDisabled: false,
}
quicConfig := &quic.Config{
ConnectionIDLength: 12,
HandshakeIdleTimeout: time.Second * 8,
}
log.Debugln("opening session to %s", dc.addr)
session, err := quic.DialAddrContext(context.Background(), dc.addr, tlsConfig, quicConfig)
if err != nil {
return nil, fmt.Errorf("failed to open QUIC session: %w", err)
}
return session, nil
}
func (dc *quicClient) openStream(ctx context.Context) (quic.Stream, error) {
session, err := dc.getSession()
if err != nil {
return nil, err
}
// open a new stream
return session.OpenStreamSync(ctx)
}

View File

@ -242,9 +242,8 @@ func (r *Resolver) ipExchange(ctx context.Context, m *D.Msg) (msg *D.Msg, err er
if res.Error == nil {
if ips := msgToIP(res.Msg); len(ips) != 0 {
if !r.shouldIPFallback(ips[0]) {
msg = res.Msg // no need to wait for fallback result
err = res.Error
return msg, err
msg, err = res.Msg, res.Error // no need to wait for fallback result
return
}
}
}

View File

@ -61,6 +61,9 @@ func transform(servers []NameServer, resolver *Resolver) []dnsClient {
case "dhcp":
ret = append(ret, newDHCPClient(s.Addr))
continue
case "quic":
ret = append(ret, &quicClient{addr: s.Addr})
continue
}
host, port, _ := net.SplitHostPort(s.Addr)

29
go.mod
View File

@ -4,24 +4,26 @@ go 1.18
require (
github.com/Dreamacro/go-shadowsocks2 v0.1.7
github.com/dlclark/regexp2 v1.4.0
github.com/go-chi/chi/v5 v5.0.7
github.com/go-chi/cors v1.2.0
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-20220119180841-3c283ff8b7dd
github.com/lucas-clemente/quic-go v0.26.0
github.com/miekg/dns v1.1.47
github.com/oschwald/geoip2-golang v1.6.1
github.com/oschwald/geoip2-golang v1.7.0
github.com/sirupsen/logrus v1.8.1
github.com/stretchr/testify v1.7.1
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.4.0
golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd
golang.org/x/net v0.0.0-20220225172249-27dd8689420f
golang.org/x/crypto v0.0.0-20220321153916-2c7772ba3064
golang.org/x/net v0.0.0-20220325170049-de3da57026de
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
golang.org/x/sys v0.0.0-20220315194320-039c03cc5b86
golang.org/x/sys v0.0.0-20220330033206-e17cdc41300f
golang.org/x/time v0.0.0-20220224211638-0e9765cccd65
golang.zx2c4.com/wireguard v0.0.0-20220318042302-193cf8d6a5d6
golang.zx2c4.com/wireguard/windows v0.5.4-0.20220317000008-6432784c2469
@ -31,16 +33,27 @@ require (
)
require (
github.com/cheekybits/genny v1.0.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/fsnotify/fsnotify v1.5.1 // indirect
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect
github.com/google/btree v1.0.1 // indirect
github.com/kr/pretty v0.2.1 // indirect
github.com/oschwald/maxminddb-golang v1.8.0 // 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/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/pmezard/go-difflib v1.0.0 // indirect
github.com/u-root/uio v0.0.0-20210528114334-82958018845c // indirect
golang.org/x/mod v0.5.1 // indirect
github.com/u-root/uio v0.0.0-20220204230159-dac05f7d2cb4 // 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.9 // indirect
golang.org/x/tools v0.1.10 // indirect
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // 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-20200313102051-9f266ea9e77c // indirect
)
replace golang.zx2c4.com/wintun v0.0.0-20211104114900-415007cec224 => github.com/MetaCubeX/wintun-go v0.0.0-20220319102620-bbc5e6b2015e

262
go.sum
View File

@ -1,18 +1,71 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
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=
dmitri.shuralyov.com/app/changes v0.0.0-20180602232624-0a106ad413e3/go.mod h1:Yl+fi1br7+Rr3LqpNJf1/uxUdtRUV+Tnj0o93V2B9MU=
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.7 h1:8CtbE1HoPPMfrQZGXmlluq6dO2lL31W6WRRE8fabc4Q=
github.com/Dreamacro/go-shadowsocks2 v0.1.7/go.mod h1:8p5G4cAj5ZlXwUR+Ww63gfSikr8kvw8uw3TDwLAJpUc=
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/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/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/cheekybits/genny v1.0.0 h1:uGGa4nei+j20rOSeDeP5Of12XVm7TGUd4dJA9RDitfE=
github.com/cheekybits/genny v1.0.0/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
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=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
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/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/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=
github.com/go-chi/chi/v5 v5.0.7/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
github.com/go-chi/cors v1.2.0 h1:tV1g1XENQ8ku4Bq3K9ub2AtgG+p16SmzeMSGTwrOKdE=
github.com/go-chi/cors v1.2.0/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vzc58=
github.com/go-chi/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-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/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.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.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.2/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.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=
@ -22,23 +75,49 @@ github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.5.2/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/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
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/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/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-20220119180841-3c283ff8b7dd h1:efcJu2Vzz6DoSq245deWNzTz6l/gsqdphm3FjmI88/g=
github.com/insomniacslk/dhcp v0.0.0-20220119180841-3c283ff8b7dd/go.mod h1:h+MxyHxRg9NH3terB1nfRIUaQEcI0XOVkdR9LNBlp8E=
github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU=
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/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
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=
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.26.0 h1:ALBQXr9UJ8A1LyzvceX4jd9QFsHvlI0RR6BkV16o00A=
github.com/lucas-clemente/quic-go v0.26.0/go.mod h1:AzgQoPda7N+3IqMMMkywBKggIFo2KT6pfnlrQ2QieeI=
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=
github.com/marten-seemann/qtls-go1-16 v0.1.5 h1:o9JrYPPco/Nukd/HpOHMHZoBDXQqoNtUCmny98/1uqQ=
github.com/marten-seemann/qtls-go1-16 v0.1.5/go.mod h1:gNpI2Ol+lRS3WwSOtIUUtRwZEQMXjYK+dQSBFbethAk=
github.com/marten-seemann/qtls-go1-17 v0.1.1 h1:DQjHPq+aOzUeh9/lixAGunn6rIOQyWChPSI4+hgW7jc=
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/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=
github.com/mdlayher/netlink v1.0.0/go.mod h1:KxeJAFOFLG6AjpyDkQ/iIhxygIUKD+vcwqcnu43w/+M=
@ -46,47 +125,122 @@ github.com/mdlayher/netlink v1.1.0/go.mod h1:H4WCitaheIsdF9yOYu8CFmCgQthAPIWZmcK
github.com/mdlayher/netlink v1.1.1/go.mod h1:WTYpFb/WTvlRJAyKhZL5/uy69TDDpHHu2VZmb2XgV7o=
github.com/mdlayher/raw v0.0.0-20190606142536-fef19f00fc18/go.mod h1:7EpbotpCmVZcu+KCX4g9WaRNuu11uyhiW7+Le1dKawg=
github.com/mdlayher/raw v0.0.0-20191009151244-50f2db8cc065/go.mod h1:7EpbotpCmVZcu+KCX4g9WaRNuu11uyhiW7+Le1dKawg=
github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4=
github.com/miekg/dns v1.1.47 h1:J9bWiXbqMbnZPcY8Qi2E3EWIBsIm6MZzzJB9VRg5gL8=
github.com/miekg/dns v1.1.47/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME=
github.com/oschwald/geoip2-golang v1.6.1 h1:GKxT3yaWWNXSb7vj6D7eoJBns+lGYgx08QO0UcNm0YY=
github.com/oschwald/geoip2-golang v1.6.1/go.mod h1:xdvYt5xQzB8ORWFqPnqMwZpCpgNagttWdoZLlJQzg7s=
github.com/oschwald/maxminddb-golang v1.8.0 h1:Uh/DSnGoxsyp/KYbY1AuP0tYEwfs0sCph9p/UMXK/Hk=
github.com/oschwald/maxminddb-golang v1.8.0/go.mod h1:RXZtst0N6+FY/3qCNmZMBApR19cdQj43/NM9VkrNAis=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
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=
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
github.com/onsi/ginkgo v1.16.2/go.mod h1:CObGmKUOKaSC0RjmoAK7tKyn4Azo5P2IWuoMnvwxz1E=
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
github.com/onsi/gomega v1.13.0 h1:7lLHu94wT9Ij0o6EWWclhu0aOh32VxhkwEJvzuWPeak=
github.com/onsi/gomega v1.13.0/go.mod h1:lRk9szgn8TxENtWd0Tp4c3wjlRfMTMH27I+3Je41yGY=
github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8=
github.com/oschwald/geoip2-golang v1.7.0 h1:JW1r5AKi+vv2ujSxjKthySK3jo8w8oKWPyXsw+Qs/S8=
github.com/oschwald/geoip2-golang v1.7.0/go.mod h1:mdI/C7iK7NVMcIDDtf4bCKMJ7r0o7UwGeCo9eiitCMQ=
github.com/oschwald/maxminddb-golang v1.9.0 h1:tIk4nv6VT9OiPyrnDAfJS1s1xKDQMZOsGojab6EjC1Y=
github.com/oschwald/maxminddb-golang v1.9.0/go.mod h1:TK+s/Z2oZq0rSl4PSeAEoP0bgm82Cp5HyvYbt8K3zLY=
github.com/pkg/errors v0.8.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/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
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=
github.com/shurcooL/github_flavored_markdown v0.0.0-20181002035957-2122de532470/go.mod h1:2dOwnU2uBioM+SGy2aZoq1f/Sd1l9OkAeAUvjSyvgU0=
github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk=
github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ=
github.com/shurcooL/gofontwoff v0.0.0-20180329035133-29b52fc0a18d/go.mod h1:05UtEgK5zq39gLST6uB0cf3NEHjETfB4Fgr3Gx5R9Vw=
github.com/shurcooL/gopherjslib v0.0.0-20160914041154-feb6d3990c2c/go.mod h1:8d3azKNyqcHP1GaQE/c6dDgjkgSx2BZ4IoEi4F1reUI=
github.com/shurcooL/highlight_diff v0.0.0-20170515013008-09bb4053de1b/go.mod h1:ZpfEhSmds4ytuByIcDnOLkTHGUI6KNqRNPDLHDk+mUU=
github.com/shurcooL/highlight_go v0.0.0-20181028180052-98c3abbbae20/go.mod h1:UDKB5a1T23gOMUJrI+uSuH0VRDStOiUVSjBTRDVBVag=
github.com/shurcooL/home v0.0.0-20181020052607-80b7ffcb30f9/go.mod h1:+rgNQw2P9ARFAs37qieuu7ohDNQ3gds9msbT2yn85sg=
github.com/shurcooL/htmlg v0.0.0-20170918183704-d01228ac9e50/go.mod h1:zPn1wHpTIePGnXSHpsVPWEktKXHr6+SS6x/IKRb7cpw=
github.com/shurcooL/httperror v0.0.0-20170206035902-86b7830d14cc/go.mod h1:aYMfkZ6DWSJPJ6c4Wwz3QtW22G7mf/PEgaB9k/ik5+Y=
github.com/shurcooL/httpfs v0.0.0-20171119174359-809beceb2371/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg=
github.com/shurcooL/httpgzip v0.0.0-20180522190206-b1c53ac65af9/go.mod h1:919LwcH0M7/W4fcZ0/jy0qGght1GIhqyS/EgWGH2j5Q=
github.com/shurcooL/issues v0.0.0-20181008053335-6292fdc1e191/go.mod h1:e2qWDig5bLteJ4fwvDAc2NHzqFEthkqn7aOZAOpj+PQ=
github.com/shurcooL/issuesapp v0.0.0-20180602232740-048589ce2241/go.mod h1:NPpHK2TI7iSaM0buivtFUc9offApnI0Alt/K8hcHy0I=
github.com/shurcooL/notifications v0.0.0-20181007000457-627ab5aea122/go.mod h1:b5uSkrEVM1jQUspwbixRBhaIjIzL2xazXp6kntxYle0=
github.com/shurcooL/octicon v0.0.0-20181028054416-fa4f57f9efb2/go.mod h1:eWdoE5JD4R5UVWDucdOPg1g2fqQRq78IQa9zlOV1vpQ=
github.com/shurcooL/reactions v0.0.0-20181006231557-f2e0b4ca5b82/go.mod h1:TCR1lToEk4d2s07G3XGfz2QrgHXg4RJBvjrOozvoWfk=
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.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=
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
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/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.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/u-root/uio v0.0.0-20210528114334-82958018845c h1:BFvcl34IGnw8yvJi8hlqLFo9EshRInwWBs2M5fGWzQA=
github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA=
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/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.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.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/automaxprocs v1.4.0 h1:CpDZl6aOlLhReez+8S3eEotD7Jx0Os++lemPlMULQP0=
go.uber.org/automaxprocs v1.4.0/go.mod h1:/mTEdr7LvHhs0v7mjdxDreTz1OG5zdZGqgOnhWiR/+Q=
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-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-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-20210317152858-513c2a44f670/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd h1:XcWmESyNjXJMLahc3mqVQJcgSTDxFxhETVlfk9uGc38=
golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220321153916-2c7772ba3064 h1:S25/rfnfsMVgORT4/J61MJ7rdyseOZOyvLIrZEZ7s6s=
golang.org/x/crypto v0.0.0-20220321153916-2c7772ba3064/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
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/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.5.1 h1:OJxoQ/rynoF0dcCdI7cLPktw/hR2cueqYfjm43oqK38=
golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 h1:kQgndtyPBW/JIYERgdxfwMYh3AVStj88WQTlNDi2a+o=
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
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-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-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
@ -94,74 +248,144 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL
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-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200707034311-ab3426394381/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-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220225172249-27dd8689420f h1:oA4XRj0qtSt8Yo1Zms0CUlsT3KG69V2UGQWPBxujDmc=
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220325170049-de3da57026de h1:pZB1TWnKi+o4bENlbzAgLrEbY4RMYmUIRobMcSmfeYc=
golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
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/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-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-20210220032951-036812b2e83c/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-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-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-20190606122018-79a91cf218c4/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-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-20191224085550-c709ea063b76/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/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-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-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-20220315194320-039c03cc5b86 h1:A9i04dxx7Cribqbs8jf3FQLogkL/CV2YN7hj9KWJCkc=
golang.org/x/sys v0.0.0-20220315194320-039c03cc5b86/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220330033206-e17cdc41300f h1:rlezHXNlxYWvBCzNses9Dlc7nGFaNMJeqLolcmQSSZY=
golang.org/x/sys v0.0.0-20220330033206-e17cdc41300f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.8-0.20220124021120-d1c84af989ab h1:eHo2TTVBaAPw9lDGK2Gb9GyPMXT6g7O63W6sx3ylbzU=
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-20220224211638-0e9765cccd65 h1:M73Iuj3xbbb9Uk1DYhzydthsj6oOd6l9bpuFcNoUvTs=
golang.org/x/time v0.0.0-20220224211638-0e9765cccd65/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
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-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-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
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=
golang.org/x/tools v0.1.9 h1:j9KsMiaP1c3B0OTQGth0/k+miLGTgLsAFUCrF2vLcF8=
golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
golang.org/x/tools v0.1.10 h1:QjFRCZxdOhBJ/UNgnBZLbNV13DlbnK0quyivTnXJM20=
golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
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 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
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-20220318042302-193cf8d6a5d6 h1:kgBK1EGuTIYbwoKROmsoV0FQp08gnCcVa110A4Unqhk=
golang.zx2c4.com/wireguard v0.0.0-20220318042302-193cf8d6a5d6/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=
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/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/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/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/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.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
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/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/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=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
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.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 h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o=
gvisor.dev/gvisor v0.0.0-20220326024801-5d1f3d24cb84 h1:nENO+rT8Nx+Vtp/VK+K7g9VpHdvJwJYCFgdN5yaoAzA=
gvisor.dev/gvisor v0.0.0-20220326024801-5d1f3d24cb84/go.mod h1:tWwEcFvJavs154OdjFCw78axNrsDlz4Zh8jvPqwcpGI=
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=
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

@ -12,6 +12,7 @@ import (
"github.com/Dreamacro/clash/adapter/outboundgroup"
"github.com/Dreamacro/clash/component/auth"
"github.com/Dreamacro/clash/component/dialer"
G "github.com/Dreamacro/clash/component/geodata"
"github.com/Dreamacro/clash/component/iface"
"github.com/Dreamacro/clash/component/profile"
"github.com/Dreamacro/clash/component/profile/cachefile"
@ -71,25 +72,24 @@ func ApplyConfig(cfg *config.Config, force bool) {
mux.Lock()
defer mux.Unlock()
log.SetLevel(log.DEBUG)
updateUsers(cfg.Users)
updateProxies(cfg.Proxies, cfg.Providers)
updateRules(cfg.Rules)
updateHosts(cfg.Hosts)
updateProfile(cfg)
updateRules(cfg.Rules, cfg.RuleProviders)
updateDNS(cfg.DNS, cfg.Tun)
updateGeneral(cfg.General, force)
updateIPTables(cfg)
updateTun(cfg.Tun, cfg.DNS)
updateExperimental(cfg)
updateHosts(cfg.Hosts)
loadProvider(cfg.RuleProviders, cfg.Providers)
updateProfile(cfg)
log.SetLevel(cfg.General.LogLevel)
}
func GetGeneral() *config.General {
ports := P.GetPorts()
authenticator := []string{}
var authenticator []string
if auth := authStore.Authenticator(); auth != nil {
authenticator = auth.Users()
}
@ -105,9 +105,10 @@ func GetGeneral() *config.General {
AllowLan: P.AllowLan(),
BindAddress: P.BindAddress(),
},
Mode: tunnel.Mode(),
LogLevel: log.Level(),
IPv6: !resolver.DisableIPv6,
Mode: tunnel.Mode(),
LogLevel: log.Level(),
IPv6: !resolver.DisableIPv6,
GeodataLoader: G.LoaderName(),
}
return general
@ -176,33 +177,62 @@ func updateProxies(proxies map[string]C.Proxy, providers map[string]provider.Pro
tunnel.UpdateProxies(proxies, providers)
}
func updateRules(rules []C.Rule) {
tunnel.UpdateRules(rules)
func updateRules(rules []C.Rule, ruleProviders map[string]*provider.RuleProvider) {
tunnel.UpdateRules(rules, ruleProviders)
}
func loadProvider(ruleProviders map[string]*provider.RuleProvider, proxyProviders map[string]provider.ProxyProvider) {
load := func(pv provider.Provider) {
if pv.VehicleType() == provider.Compatible {
log.Infoln("Start initial compatible provider %s", pv.Name())
} else {
log.Infoln("Start initial provider %s", (pv).Name())
}
if err := (pv).Initial(); err != nil {
switch pv.Type() {
case provider.Proxy:
{
log.Warnln("initial proxy provider %s error: %v", (pv).Name(), err)
}
case provider.Rule:
{
log.Warnln("initial rule provider %s error: %v", (pv).Name(), err)
}
}
}
}
for _, proxyProvider := range proxyProviders {
load(proxyProvider)
}
for _, ruleProvider := range ruleProviders {
load(*ruleProvider)
}
}
func updateTun(tun *config.Tun, dns *config.DNS) {
var tunAddressPrefix string
if dns.FakeIPRange != nil {
tunAddressPrefix = dns.FakeIPRange.IPNet().String()
}
P.ReCreateTun(tun, tunAddressPrefix, tunnel.TCPIn(), tunnel.UDPIn())
P.ReCreateTun(tun, dns, tunnel.TCPIn(), tunnel.UDPIn())
}
func updateGeneral(general *config.General, force bool) {
log.SetLevel(general.LogLevel)
tunnel.SetMode(general.Mode)
resolver.DisableIPv6 = !general.IPv6
adapter.UnifiedDelay.Store(general.UnifiedDelay)
dialer.DefaultInterface.Store(general.Interface)
if dialer.DefaultInterface.Load() != "" {
log.Infoln("Use interface name: %s", general.Interface)
}
if general.RoutingMark > 0 || (general.RoutingMark == 0 && general.TProxyPort == 0) {
dialer.DefaultRoutingMark.Store(int32(general.RoutingMark))
if general.RoutingMark > 0 {
log.Infoln("Use routing mark: %#x", general.RoutingMark)
}
dialer.DefaultRoutingMark.Store(int32(general.RoutingMark))
if general.RoutingMark > 0 {
log.Infoln("Use routing mark: %#x", general.RoutingMark)
}
iface.FlushCache()
@ -211,6 +241,9 @@ func updateGeneral(general *config.General, force bool) {
return
}
geodataLoader := general.GeodataLoader
G.SetLoader(geodataLoader)
allowLan := general.AllowLan
P.SetAllowLan(allowLan)
@ -286,8 +319,14 @@ func updateIPTables(cfg *config.Config) {
}
}()
if cfg.Tun.Enable {
err = fmt.Errorf("when tun is enabled, iptables cannot be set automatically")
return
}
var (
inboundInterface = "lo"
bypass = iptables.Bypass
tProxyPort = cfg.General.TProxyPort
dnsCfg = cfg.DNS
)
@ -304,13 +343,13 @@ func updateIPTables(cfg *config.Config) {
_, dnsPortStr, err := net.SplitHostPort(dnsCfg.Listen)
if err != nil {
err = fmt.Errorf("DNS server must be enable")
err = fmt.Errorf("DNS server must be correct")
return
}
dnsPort, err := strconv.ParseUint(dnsPortStr, 10, 16)
if err != nil {
err = fmt.Errorf("DNS server must be enable")
err = fmt.Errorf("DNS server must be correct")
return
}
@ -322,7 +361,7 @@ func updateIPTables(cfg *config.Config) {
dialer.DefaultRoutingMark.Store(2158)
}
err = tproxy.SetTProxyIPTables(inboundInterface, uint16(tProxyPort), uint16(dnsPort))
err = tproxy.SetTProxyIPTables(inboundInterface, bypass, uint16(tProxyPort), uint16(dnsPort))
if err != nil {
return
}

View File

@ -75,3 +75,54 @@ func findProviderByName(next http.Handler) http.Handler {
next.ServeHTTP(w, r.WithContext(ctx))
})
}
func ruleProviderRouter() http.Handler {
r := chi.NewRouter()
r.Get("/", getRuleProviders)
r.Route("/{name}", func(r chi.Router) {
r.Use(parseRuleProviderName, findRuleProviderByName)
r.Put("/", updateRuleProvider)
})
return r
}
func getRuleProviders(w http.ResponseWriter, r *http.Request) {
ruleProviders := tunnel.RuleProviders()
render.JSON(w, r, render.M{
"providers": ruleProviders,
})
}
func updateRuleProvider(w http.ResponseWriter, r *http.Request) {
provider := r.Context().Value(CtxKeyProvider).(*provider.RuleProvider)
if err := (*provider).Update(); err != nil {
render.Status(r, http.StatusServiceUnavailable)
render.JSON(w, r, newError(err.Error()))
}
render.NoContent(w, r)
}
func parseRuleProviderName(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
name := getEscapeParam(r, "name")
ctx := context.WithValue(r.Context(), CtxKeyProviderName, name)
next.ServeHTTP(w, r.WithContext(ctx))
})
}
func findRuleProviderByName(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
name := r.Context().Value(CtxKeyProviderName).(string)
providers := tunnel.RuleProviders()
provider, exist := providers[name]
if !exist {
render.Status(r, http.StatusNotFound)
render.JSON(w, r, ErrNotFound)
return
}
ctx := context.WithValue(r.Context(), CtxKeyProvider, provider)
next.ServeHTTP(w, r.WithContext(ctx))
})
}

View File

@ -17,6 +17,10 @@ import (
"github.com/go-chi/render"
)
var (
SwitchProxiesCallback func(sGroup string, sProxy string)
)
func proxyRouter() http.Handler {
r := chi.NewRouter()
r.Get("/", getProxies)
@ -93,6 +97,10 @@ func updateProxy(w http.ResponseWriter, r *http.Request) {
}
cachefile.Cache().SetSelected(proxy.Name(), req.Name)
if SwitchProxiesCallback != nil {
// refresh tray menu
go SwitchProxiesCallback(proxy.Name(), req.Name)
}
render.NoContent(w, r)
}

View File

@ -23,7 +23,6 @@ type Rule struct {
func getRules(w http.ResponseWriter, r *http.Request) {
rawRules := tunnel.Rules()
rules := []Rule{}
for _, rule := range rawRules {
rules = append(rules, Rule{
@ -31,6 +30,7 @@ func getRules(w http.ResponseWriter, r *http.Request) {
Payload: rule.Payload(),
Proxy: rule.Adapter(),
})
}
render.JSON(w, r, render.M{

16
hub/route/script.go Normal file
View File

@ -0,0 +1,16 @@
package route
import (
"github.com/go-chi/chi/v5"
"net/http"
)
func scriptRouter() http.Handler {
r := chi.NewRouter()
r.Get("/", getScript)
return r
}
func getScript(writer http.ResponseWriter, request *http.Request) {
writer.WriteHeader(http.StatusMethodNotAllowed)
}

View File

@ -71,6 +71,8 @@ func Start(addr string, secret string) {
r.Mount("/rules", ruleRouter())
r.Mount("/connections", connectionRouter())
r.Mount("/providers/proxies", proxyProviderRouter())
r.Mount("/providers/rules", ruleProviderRouter())
r.Mount("/script", scriptRouter())
r.Mount("/cache", cacheRouter())
})
@ -131,7 +133,7 @@ func authentication(next http.Handler) http.Handler {
}
func hello(w http.ResponseWriter, r *http.Request) {
render.JSON(w, r, render.M{"hello": "clash with tun"})
render.JSON(w, r, render.M{"hello": "clash.meta"})
}
func traffic(w http.ResponseWriter, r *http.Request) {
@ -241,5 +243,5 @@ func getLogs(w http.ResponseWriter, r *http.Request) {
}
func version(w http.ResponseWriter, r *http.Request) {
render.JSON(w, r, render.M{"version": C.Version})
render.JSON(w, r, render.M{"meta": C.Meta, "version": C.Version})
}

20
listener/inner/tcp.go Normal file
View File

@ -0,0 +1,20 @@
package inner
import (
"github.com/Dreamacro/clash/adapter/inbound"
C "github.com/Dreamacro/clash/constant"
"net"
)
var tcpIn chan<- C.ConnContext
func New(in chan<- C.ConnContext) {
tcpIn = in
}
func HandleTcp(dst string, host string) net.Conn {
conn1, conn2 := net.Pipe()
context := inbound.NewInner(conn2, dst, host)
tcpIn <- context
return conn1
}

View File

@ -2,6 +2,7 @@ package proxy
import (
"fmt"
"github.com/Dreamacro/clash/listener/inner"
"net"
"os"
"strconv"
@ -95,6 +96,7 @@ func ReCreateHTTP(port int, tcpIn chan<- C.ConnContext) {
httpListener, err = http.New(addr, tcpIn)
if err != nil {
log.Errorln("Start HTTP server error: %s", err.Error())
return
}
@ -111,6 +113,7 @@ func ReCreateSocks(port int, tcpIn chan<- C.ConnContext, udpIn chan<- *inbound.P
log.Errorln("Start SOCKS server error: %s", err.Error())
}
}()
inner.New(tcpIn)
addr := genAddr(bindAddress, port, allowLan)
@ -307,7 +310,7 @@ func ReCreateMixed(port int, tcpIn chan<- C.ConnContext, udpIn chan<- *inbound.P
log.Infoln("Mixed(http+socks) proxy listening at: %s", mixedListener.Address())
}
func ReCreateTun(tunConf *config.Tun, tunAddressPrefix string, tcpIn chan<- C.ConnContext, udpIn chan<- *inbound.PacketAdapter) {
func ReCreateTun(tunConf *config.Tun, dnsCfg *config.DNS, tcpIn chan<- C.ConnContext, udpIn chan<- *inbound.PacketAdapter) {
tunMux.Lock()
defer tunMux.Unlock()
@ -327,8 +330,10 @@ func ReCreateTun(tunConf *config.Tun, tunAddressPrefix string, tcpIn chan<- C.Co
if !tunConf.Enable {
return
}
tunStackListener, err = tun.New(tunConf, tunAddressPrefix, tcpIn, udpIn)
tunStackListener, err = tun.New(tunConf, dnsCfg, tcpIn, udpIn)
if err != nil {
log.Warnln("Failed to start TUN interface: %s", err.Error())
}
}
// GetPorts return the ports of proxy servers

View File

@ -3,6 +3,7 @@ package tproxy
import (
"errors"
"fmt"
"net"
"runtime"
"github.com/Dreamacro/clash/common/cmd"
@ -21,9 +22,8 @@ const (
PROXY_ROUTE_TABLE = "0x2d0"
)
func SetTProxyIPTables(ifname string, tport uint16, dport uint16) error {
var err error
if err = execCmd("iptables -V"); err != nil {
func SetTProxyIPTables(ifname string, bypass []string, tport uint16, dport uint16) error {
if _, err := cmd.ExecCmd("iptables -V"); err != nil {
return fmt.Errorf("current operations system [%s] are not support iptables or command iptables does not exist", runtime.GOOS)
}
@ -61,7 +61,7 @@ func SetTProxyIPTables(ifname string, tport uint16, dport uint16) error {
execCmd("iptables -t mangle -A clash_prerouting -p udp --dport 53 -j ACCEPT")
execCmd("iptables -t mangle -A clash_prerouting -p tcp --dport 53 -j ACCEPT")
execCmd("iptables -t mangle -A clash_prerouting -m addrtype --dst-type LOCAL -j RETURN")
addLocalnetworkToChain("clash_prerouting")
addLocalnetworkToChain("clash_prerouting", bypass)
execCmd("iptables -t mangle -A clash_prerouting -p tcp -m socket -j clash_divert")
execCmd("iptables -t mangle -A clash_prerouting -p udp -m socket -j clash_divert")
execCmd(fmt.Sprintf("iptables -t mangle -A clash_prerouting -p tcp -j TPROXY --on-port %d --tproxy-mark %s/%s", tProxyPort, PROXY_FWMARK, PROXY_FWMARK))
@ -84,7 +84,7 @@ func SetTProxyIPTables(ifname string, tport uint16, dport uint16) error {
execCmd("iptables -t mangle -A clash_output -p tcp --dport 53 -j ACCEPT")
execCmd("iptables -t mangle -A clash_output -m addrtype --dst-type LOCAL -j RETURN")
execCmd("iptables -t mangle -A clash_output -m addrtype --dst-type BROADCAST -j RETURN")
addLocalnetworkToChain("clash_output")
addLocalnetworkToChain("clash_output", bypass)
execCmd(fmt.Sprintf("iptables -t mangle -A clash_output -p tcp -j MARK --set-mark %s", PROXY_FWMARK))
execCmd(fmt.Sprintf("iptables -t mangle -A clash_output -p udp -j MARK --set-mark %s", PROXY_FWMARK))
execCmd(fmt.Sprintf("iptables -t mangle -I OUTPUT -o %s -j clash_output", interfaceName))
@ -113,7 +113,7 @@ func CleanupTProxyIPTables() {
dialer.DefaultRoutingMark.Store(0)
}
if err := execCmd("iptables -t mangle -L clash_divert"); err != nil {
if _, err := cmd.ExecCmd("iptables -t mangle -L clash_divert"); err != nil {
return
}
@ -159,7 +159,15 @@ func CleanupTProxyIPTables() {
dnsPort = 0
}
func addLocalnetworkToChain(chain string) {
func addLocalnetworkToChain(chain string, bypass []string) {
for _, bp := range bypass {
_, _, err := net.ParseCIDR(bp)
if err != nil {
log.Warnln("[IPTABLES] %s", err)
continue
}
execCmd(fmt.Sprintf("iptables -t mangle -A %s -d %s -j RETURN", chain, bp))
}
execCmd(fmt.Sprintf("iptables -t mangle -A %s -d 0.0.0.0/8 -j RETURN", chain))
execCmd(fmt.Sprintf("iptables -t mangle -A %s -d 10.0.0.0/8 -j RETURN", chain))
execCmd(fmt.Sprintf("iptables -t mangle -A %s -d 100.64.0.0/10 -j RETURN", chain))
@ -177,13 +185,11 @@ func addLocalnetworkToChain(chain string) {
execCmd(fmt.Sprintf("iptables -t mangle -A %s -d 255.255.255.255/32 -j RETURN", chain))
}
func execCmd(cmdStr string) error {
func execCmd(cmdStr string) {
log.Debugln("[IPTABLES] %s", cmdStr)
_, err := cmd.ExecCmd(cmdStr)
if err != nil {
log.Warnln("[IPTABLES] exec cmd: %v", err)
}
return err
}

View File

@ -8,7 +8,7 @@ import (
func init() {
guid, _ := windows.GUIDFromString("{330EAEF8-7578-5DF2-D97B-8DADC0EA85CB}")
tun.WintunTunnelType = "Clash"
tun.WintunTunnelType = "Meta"
tun.WintunStaticRequestedGUID = &guid
}

View File

@ -0,0 +1,94 @@
/* SPDX-License-Identifier: MIT
*
* Copyright (C) 2017-2021 WireGuard LLC. All Rights Reserved.
*/
package wintun
import (
"fmt"
"golang.zx2c4.com/wintun/embed_dll"
"golang.zx2c4.com/wireguard/windows/driver/memmod"
"sync"
"sync/atomic"
"unsafe"
)
func newLazyDLL(name string, onLoad func(d *lazyDLL)) *lazyDLL {
return &lazyDLL{Name: name, onLoad: onLoad}
}
func (d *lazyDLL) NewProc(name string) *lazyProc {
return &lazyProc{dll: d, Name: name}
}
type lazyProc struct {
Name string
mu sync.Mutex
dll *lazyDLL
addr uintptr
}
func (p *lazyProc) Find() error {
if atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&p.addr))) != nil {
return nil
}
p.mu.Lock()
defer p.mu.Unlock()
if p.addr != 0 {
return nil
}
err := p.dll.Load()
if err != nil {
return fmt.Errorf("Error loading %v DLL: %w", p.dll.Name, err)
}
addr, err := p.nameToAddr()
if err != nil {
return fmt.Errorf("Error getting %v address: %w", p.Name, err)
}
atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&p.addr)), unsafe.Pointer(addr))
return nil
}
func (p *lazyProc) Addr() uintptr {
err := p.Find()
if err != nil {
panic(err)
}
return p.addr
}
type lazyDLL struct {
Name string
mu sync.Mutex
module *memmod.Module
onLoad func(d *lazyDLL)
}
func (d *lazyDLL) Load() error {
if atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&d.module))) != nil {
return nil
}
d.mu.Lock()
defer d.mu.Unlock()
if d.module != nil {
return nil
}
module, err := memmod.LoadLibrary(embed_dll.DDlContent)
if err != nil {
return fmt.Errorf("unable to load library: %w", err)
}
atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&d.module)), unsafe.Pointer(module))
if d.onLoad != nil {
d.onLoad(d)
}
return nil
}
func (p *lazyProc) nameToAddr() (uintptr, error) {
return p.dll.module.ProcAddressByName(p.Name)
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,21 @@
package embed_dll
// Copyright 2020 MeshStep Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// See the License for the specific language governing permissions and
// limitations under the License.
import (
_ "embed"
)
//go:embed x86/wintun.dll
var DDlContent []byte

View File

@ -0,0 +1,21 @@
package embed_dll
// Copyright 2020 MeshStep Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// See the License for the specific language governing permissions and
// limitations under the License.
import (
_ "embed"
)
//go:embed amd64/wintun.dll
var DDlContent []byte

View File

@ -0,0 +1,21 @@
package embed_dll
// Copyright 2020 MeshStep Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// See the License for the specific language governing permissions and
// limitations under the License.
import (
_ "embed"
)
//go:embed arm/wintun.dll
var DDlContent []byte

View File

@ -0,0 +1,21 @@
package embed_dll
// Copyright 2020 MeshStep Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// See the License for the specific language governing permissions and
// limitations under the License.
import (
_ "embed"
)
//go:embed arm64/wintun.dll
var DDlContent []byte

Binary file not shown.

View File

@ -0,0 +1,8 @@
module golang.zx2c4.com/wintun
go 1.18
require (
golang.org/x/sys v0.0.0-20220318055525-2edf467146b5
golang.zx2c4.com/wireguard/windows v0.5.3
)

View File

@ -0,0 +1,17 @@
github.com/MetaCubeX/Clash.Meta v1.9.1 h1:jHZhVRBxFuaCRBN9vxB/FL5R16wY4kIgNqjszdXPeLs=
github.com/MetaCubeX/Clash.Meta v1.9.1/go.mod h1:/I4cSh+PcgmtS5SEnFp8RANL6aVRd3i9YOult+mKLhU=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20220317061510-51cd9980dadf h1:Fm4IcnUL803i92qDlmB0obyHmosDrxZWxJL3gIeNqOw=
golang.org/x/sys v0.0.0-20220317061510-51cd9980dadf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.zx2c4.com/wireguard/windows v0.5.3 h1:On6j2Rpn3OEMXqBq00QEDC7bWSZrPIHKIus8eIuExIE=
golang.zx2c4.com/wireguard/windows v0.5.3/go.mod h1:9TEe8TJmtwyQebdFwAkEWOPr3prrtqm+REGFifP60hI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=

View File

@ -0,0 +1,11 @@
//go:build windows
// +build windows
// Modified from: https://git.zx2c4.com/wireguard-go/tree/tun/wintun
/* SPDX-License-Identifier: MIT
*
* Copyright (C) 2019-2021 WireGuard LLC. All Rights Reserved.
*/
package wintun

View File

@ -0,0 +1,90 @@
/* SPDX-License-Identifier: MIT
*
* Copyright (C) 2017-2021 WireGuard LLC. All Rights Reserved.
*/
package wintun
import (
"syscall"
"unsafe"
"golang.org/x/sys/windows"
)
type Session struct {
handle uintptr
}
const (
PacketSizeMax = 0xffff // Maximum packet size
RingCapacityMin = 0x20000 // Minimum ring capacity (128 kiB)
RingCapacityMax = 0x4000000 // Maximum ring capacity (64 MiB)
)
// Packet with data
type Packet struct {
Next *Packet // Pointer to next packet in queue
Size uint32 // Size of packet (max WINTUN_MAX_IP_PACKET_SIZE)
Data *[PacketSizeMax]byte // Pointer to layer 3 IPv4 or IPv6 packet
}
var (
procWintunAllocateSendPacket = modwintun.NewProc("WintunAllocateSendPacket")
procWintunEndSession = modwintun.NewProc("WintunEndSession")
procWintunGetReadWaitEvent = modwintun.NewProc("WintunGetReadWaitEvent")
procWintunReceivePacket = modwintun.NewProc("WintunReceivePacket")
procWintunReleaseReceivePacket = modwintun.NewProc("WintunReleaseReceivePacket")
procWintunSendPacket = modwintun.NewProc("WintunSendPacket")
procWintunStartSession = modwintun.NewProc("WintunStartSession")
)
func (wintun *Adapter) StartSession(capacity uint32) (session Session, err error) {
r0, _, e1 := syscall.Syscall(procWintunStartSession.Addr(), 2, uintptr(wintun.handle), uintptr(capacity), 0)
if r0 == 0 {
err = e1
} else {
session = Session{r0}
}
return
}
func (session Session) End() {
syscall.Syscall(procWintunEndSession.Addr(), 1, session.handle, 0, 0)
session.handle = 0
}
func (session Session) ReadWaitEvent() (handle windows.Handle) {
r0, _, _ := syscall.Syscall(procWintunGetReadWaitEvent.Addr(), 1, session.handle, 0, 0)
handle = windows.Handle(r0)
return
}
func (session Session) ReceivePacket() (packet []byte, err error) {
var packetSize uint32
r0, _, e1 := syscall.Syscall(procWintunReceivePacket.Addr(), 2, session.handle, uintptr(unsafe.Pointer(&packetSize)), 0)
if r0 == 0 {
err = e1
return
}
packet = unsafe.Slice((*byte)(unsafe.Pointer(r0)), packetSize)
return
}
func (session Session) ReleaseReceivePacket(packet []byte) {
syscall.Syscall(procWintunReleaseReceivePacket.Addr(), 2, session.handle, uintptr(unsafe.Pointer(&packet[0])), 0)
}
func (session Session) AllocateSendPacket(packetSize int) (packet []byte, err error) {
r0, _, e1 := syscall.Syscall(procWintunAllocateSendPacket.Addr(), 2, session.handle, uintptr(packetSize), 0)
if r0 == 0 {
err = e1
return
}
packet = unsafe.Slice((*byte)(unsafe.Pointer(r0)), packetSize)
return
}
func (session Session) SendPacket(packet []byte) {
syscall.Syscall(procWintunSendPacket.Addr(), 2, session.handle, uintptr(unsafe.Pointer(&packet[0])), 0)
}

View File

@ -0,0 +1,152 @@
//go:build windows
/* SPDX-License-Identifier: MIT
*
* Copyright (C) 2017-2021 WireGuard LLC. All Rights Reserved.
*/
package wintun
import (
"log"
"runtime"
"syscall"
"unsafe"
"golang.org/x/sys/windows"
)
type loggerLevel int
const (
logInfo loggerLevel = iota
logWarn
logErr
)
const AdapterNameMax = 128
type Adapter struct {
handle uintptr
}
var (
modwintun = newLazyDLL("wintun.dll", setupLogger)
procWintunCreateAdapter = modwintun.NewProc("WintunCreateAdapter")
procWintunOpenAdapter = modwintun.NewProc("WintunOpenAdapter")
procWintunCloseAdapter = modwintun.NewProc("WintunCloseAdapter")
procWintunDeleteDriver = modwintun.NewProc("WintunDeleteDriver")
procWintunGetAdapterLUID = modwintun.NewProc("WintunGetAdapterLUID")
procWintunGetRunningDriverVersion = modwintun.NewProc("WintunGetRunningDriverVersion")
)
type TimestampedWriter interface {
WriteWithTimestamp(p []byte, ts int64) (n int, err error)
}
func logMessage(level loggerLevel, timestamp uint64, msg *uint16) int {
if tw, ok := log.Default().Writer().(TimestampedWriter); ok {
tw.WriteWithTimestamp([]byte(log.Default().Prefix()+windows.UTF16PtrToString(msg)), (int64(timestamp)-116444736000000000)*100)
} else {
log.Println(windows.UTF16PtrToString(msg))
}
return 0
}
func setupLogger(dll *lazyDLL) {
var callback uintptr
if runtime.GOARCH == "386" {
callback = windows.NewCallback(func(level loggerLevel, timestampLow, timestampHigh uint32, msg *uint16) int {
return logMessage(level, uint64(timestampHigh)<<32|uint64(timestampLow), msg)
})
} else if runtime.GOARCH == "arm" {
callback = windows.NewCallback(func(level loggerLevel, _, timestampLow, timestampHigh uint32, msg *uint16) int {
return logMessage(level, uint64(timestampHigh)<<32|uint64(timestampLow), msg)
})
} else if runtime.GOARCH == "amd64" || runtime.GOARCH == "arm64" {
callback = windows.NewCallback(logMessage)
}
syscall.Syscall(dll.NewProc("WintunSetLogger").Addr(), 1, callback, 0, 0)
}
func closeAdapter(wintun *Adapter) {
syscall.Syscall(procWintunCloseAdapter.Addr(), 1, wintun.handle, 0, 0)
}
// CreateAdapter creates a Wintun adapter. name is the cosmetic name of the adapter.
// tunnelType represents the type of adapter and should be "Wintun". requestedGUID is
// the GUID of the created network adapter, which then influences NLA generation
// deterministically. If it is set to nil, the GUID is chosen by the system at random,
// and hence a new NLA entry is created for each new adapter.
func CreateAdapter(name string, tunnelType string, requestedGUID *windows.GUID) (wintun *Adapter, err error) {
var name16 *uint16
name16, err = windows.UTF16PtrFromString(name)
if err != nil {
return
}
var tunnelType16 *uint16
tunnelType16, err = windows.UTF16PtrFromString(tunnelType)
if err != nil {
return
}
r0, _, e1 := syscall.Syscall(procWintunCreateAdapter.Addr(), 3, uintptr(unsafe.Pointer(name16)), uintptr(unsafe.Pointer(tunnelType16)), uintptr(unsafe.Pointer(requestedGUID)))
if r0 == 0 {
err = e1
return
}
wintun = &Adapter{handle: r0}
runtime.SetFinalizer(wintun, closeAdapter)
return
}
// OpenAdapter opens an existing Wintun adapter by name.
func OpenAdapter(name string) (wintun *Adapter, err error) {
var name16 *uint16
name16, err = windows.UTF16PtrFromString(name)
if err != nil {
return
}
r0, _, e1 := syscall.Syscall(procWintunOpenAdapter.Addr(), 1, uintptr(unsafe.Pointer(name16)), 0, 0)
if r0 == 0 {
err = e1
return
}
wintun = &Adapter{handle: r0}
runtime.SetFinalizer(wintun, closeAdapter)
return
}
// Close closes a Wintun adapter.
func (wintun *Adapter) Close() (err error) {
runtime.SetFinalizer(wintun, nil)
r1, _, e1 := syscall.Syscall(procWintunCloseAdapter.Addr(), 1, wintun.handle, 0, 0)
if r1 == 0 {
err = e1
}
return
}
// Uninstall removes the driver from the system if no drivers are currently in use.
func Uninstall() (err error) {
r1, _, e1 := syscall.Syscall(procWintunDeleteDriver.Addr(), 0, 0, 0, 0)
if r1 == 0 {
err = e1
}
return
}
// RunningVersion returns the version of the loaded driver.
func RunningVersion() (version uint32, err error) {
r0, _, e1 := syscall.Syscall(procWintunGetRunningDriverVersion.Addr(), 0, 0, 0, 0)
version = uint32(r0)
if version == 0 {
err = e1
}
return
}
// LUID returns the LUID of the adapter.
func (wintun *Adapter) LUID() (luid uint64) {
syscall.Syscall(procWintunGetAdapterLUID.Addr(), 2, uintptr(wintun.handle), uintptr(unsafe.Pointer(&luid)), 0)
return
}

View File

@ -5,7 +5,6 @@ import (
"time"
"github.com/Dreamacro/clash/component/resolver"
D "github.com/miekg/dns"
)

View File

@ -24,7 +24,7 @@ func ipv4MaskString(bits int) string {
return fmt.Sprintf("%d.%d.%d.%d", m[0], m[1], m[2], m[3])
}
func defaultInterfaceChangeMonitor() {
func DefaultInterfaceChangeMonitor(cb func(ifName string)) {
t := time.NewTicker(defaultInterfaceMonitorDuration)
defer t.Stop()
@ -43,6 +43,9 @@ func defaultInterfaceChangeMonitor() {
}
dialer.DefaultInterface.Store(interfaceName)
if cb != nil {
cb(interfaceName)
}
log.Warnln("[TUN] default interface changed by monitor, %s => %s", old, interfaceName)
}

View File

@ -54,7 +54,7 @@ func configInterfaceRouting(interfaceName string, addr netip.Prefix) error {
}
}
go defaultInterfaceChangeMonitor()
go DefaultInterfaceChangeMonitor(nil)
return execRouterCmd("add", "-inet6", "2000::/3", interfaceName)
}

View File

@ -42,7 +42,7 @@ func configInterfaceRouting(interfaceName string, addr netip.Prefix) error {
}
}
go defaultInterfaceChangeMonitor()
go DefaultInterfaceChangeMonitor(nil)
return nil
}

View File

@ -204,7 +204,7 @@ startOver:
wintunInterfaceName = dev.Name()
go defaultInterfaceChangeMonitor()
go DefaultInterfaceChangeMonitor(nil)
return nil
}

View File

@ -2,11 +2,6 @@ package tun
import (
"fmt"
"net/netip"
"net/url"
"runtime"
"strings"
"github.com/Dreamacro/clash/adapter/inbound"
"github.com/Dreamacro/clash/common/cmd"
"github.com/Dreamacro/clash/component/process"
@ -21,10 +16,19 @@ import (
"github.com/Dreamacro/clash/listener/tun/ipstack/gvisor/option"
"github.com/Dreamacro/clash/listener/tun/ipstack/system"
"github.com/Dreamacro/clash/log"
"net/netip"
"net/url"
"runtime"
"strings"
)
// New TunAdapter
func New(tunConf *config.Tun, tunAddressPrefix string, tcpIn chan<- C.ConnContext, udpIn chan<- *inbound.PacketAdapter) (ipstack.Stack, error) {
func New(tunConf *config.Tun, dnsConf *config.DNS, tcpIn chan<- C.ConnContext, udpIn chan<- *inbound.PacketAdapter) (ipstack.Stack, error) {
var tunAddressPrefix string
if dnsConf.FakeIPRange != nil {
tunAddressPrefix = dnsConf.FakeIPRange.IPNet().String()
}
var (
tunAddress, _ = netip.ParsePrefix(tunAddressPrefix)
devName = tunConf.Device
@ -49,6 +53,7 @@ func New(tunConf *config.Tun, tunAddressPrefix string, tcpIn chan<- C.ConnContex
process.AppendLocalIPs(tunAddress.Masked().Addr().Next().AsSlice())
// open tun device
tunDevice, err = parseDevice(devName, uint32(mtu))
if err != nil {
return nil, fmt.Errorf("can't open tun: %w", err)
@ -107,11 +112,11 @@ func New(tunConf *config.Tun, tunAddressPrefix string, tcpIn chan<- C.ConnContex
func generateDeviceName() string {
switch runtime.GOOS {
case "darwin":
return tun.Driver + "://utun"
return tun.Driver + "://Meta"
case "windows":
return tun.Driver + "://Clash"
return tun.Driver + "://Meta"
default:
return tun.Driver + "://clash0"
return tun.Driver + "://Meta"
}
}
@ -146,6 +151,7 @@ func setAtLatest(stackType C.TUNStack, devName string) {
switch runtime.GOOS {
case "windows":
_, _ = cmd.ExecCmd("ipconfig /renew")
case "linux":
// _, _ = cmd.ExecCmd("sysctl -w net.ipv4.ip_forward=1")
// _, _ = cmd.ExecCmd("sysctl -w net.ipv4.conf.all.forwarding = 1")

View File

@ -97,3 +97,9 @@ func newLog(logLevel LogLevel, format string, v ...any) *Event {
Payload: fmt.Sprintf(format, v...),
}
}
func PrintLog(logLevel LogLevel, format string, v ...interface{}) {
event := newLog(logLevel, format, v...)
logCh <- event
print(event)
}

View File

@ -22,6 +22,7 @@ var (
flagset map[string]bool
version bool
testConfig bool
geodataMode bool
homeDir string
configFile string
externalUI string
@ -35,6 +36,7 @@ func init() {
flag.StringVar(&externalUI, "ext-ui", "", "override external ui directory")
flag.StringVar(&externalController, "ext-ctl", "", "override external controller address")
flag.StringVar(&secret, "secret", "", "override secret for RESTful API")
flag.BoolVar(&geodataMode, "m", false, "set geodata mode")
flag.BoolVar(&version, "v", false, "show current version of clash")
flag.BoolVar(&testConfig, "t", false, "test configuration and exit")
flag.Parse()
@ -48,7 +50,7 @@ func init() {
func main() {
_, _ = maxprocs.Set(maxprocs.Logger(func(string, ...any) {}))
if version {
fmt.Printf("Clash with tun deveice %s %s %s with %s %s\n", C.Version, runtime.GOOS, runtime.GOARCH, runtime.Version(), C.BuildTime)
fmt.Printf("Clash Meta %s %s %s with %s %s\n", C.Version, runtime.GOOS, runtime.GOARCH, runtime.Version(), C.BuildTime)
return
}
@ -71,6 +73,10 @@ func main() {
C.SetConfig(configFile)
}
if geodataMode {
C.GeodataMode = true
}
if err := config.Init(C.Path.HomeDir()); err != nil {
log.Fatalln("Initial configuration directory error: %s", err.Error())
}

View File

@ -1,4 +1,4 @@
package rules
package common
import (
"errors"
@ -30,6 +30,10 @@ func (b *Base) ShouldFindProcess() bool {
return false
}
func (b *Base) ShouldResolveIP() bool {
return false
}
func HasNoResolve(params []string) bool {
for _, p := range params {
if p == noResolve {
@ -39,7 +43,7 @@ func HasNoResolve(params []string) bool {
return false
}
func findNetwork(params []string) C.NetWork {
func FindNetwork(params []string) C.NetWork {
for _, p := range params {
if strings.EqualFold(p, "tcp") {
return C.TCP
@ -50,7 +54,7 @@ func findNetwork(params []string) C.NetWork {
return C.ALLNet
}
func findSourceIPs(params []string) []*net.IPNet {
func FindSourceIPs(params []string) []*net.IPNet {
var ips []*net.IPNet
for _, p := range params {
if p == noResolve || len(p) < 7 {
@ -69,7 +73,7 @@ func findSourceIPs(params []string) []*net.IPNet {
return nil
}
func findProcessName(params []string) []string {
func FindProcessName(params []string) []string {
var processNames []string
for _, p := range params {
if strings.HasPrefix(p, "P:") {

View File

@ -1,4 +1,4 @@
package rules
package common
import (
"strings"
@ -31,10 +31,6 @@ func (d *Domain) Payload() string {
return d.domain
}
func (d *Domain) ShouldResolveIP() bool {
return false
}
func NewDomain(domain string, adapter string) *Domain {
return &Domain{
Base: &Base{},

View File

@ -1,4 +1,4 @@
package rules
package common
import (
"strings"
@ -32,10 +32,6 @@ func (dk *DomainKeyword) Payload() string {
return dk.keyword
}
func (dk *DomainKeyword) ShouldResolveIP() bool {
return false
}
func NewDomainKeyword(keyword string, adapter string) *DomainKeyword {
return &DomainKeyword{
Base: &Base{},

View File

@ -1,4 +1,4 @@
package rules
package common
import (
"strings"
@ -32,10 +32,6 @@ func (ds *DomainSuffix) Payload() string {
return ds.suffix
}
func (ds *DomainSuffix) ShouldResolveIP() bool {
return false
}
func NewDomainSuffix(suffix string, adapter string) *DomainSuffix {
return &DomainSuffix{
Base: &Base{},

View File

@ -1,4 +1,4 @@
package rules
package common
import (
C "github.com/Dreamacro/clash/constant"
@ -25,10 +25,6 @@ func (f *Match) Payload() string {
return ""
}
func (f *Match) ShouldResolveIP() bool {
return false
}
func NewMatch(adapter string) *Match {
return &Match{
Base: &Base{},

95
rule/common/geoip.go Normal file
View File

@ -0,0 +1,95 @@
package common
import (
"fmt"
"github.com/Dreamacro/clash/component/geodata"
"github.com/Dreamacro/clash/component/geodata/router"
"strings"
"github.com/Dreamacro/clash/component/mmdb"
"github.com/Dreamacro/clash/component/resolver"
C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/log"
)
type GEOIP struct {
*Base
country string
adapter string
noResolveIP bool
geoIPMatcher *router.GeoIPMatcher
}
func (g *GEOIP) RuleType() C.RuleType {
return C.GEOIP
}
func (g *GEOIP) Match(metadata *C.Metadata) bool {
ip := metadata.DstIP
if ip == nil {
return false
}
if strings.EqualFold(g.country, "LAN") {
return ip.IsPrivate() ||
ip.IsUnspecified() ||
ip.IsLoopback() ||
ip.IsMulticast() ||
ip.IsLinkLocalUnicast() ||
resolver.IsFakeBroadcastIP(ip)
}
if !C.GeodataMode {
record, _ := mmdb.Instance().Country(ip)
return strings.EqualFold(record.Country.IsoCode, g.country)
}
return g.geoIPMatcher.Match(ip)
}
func (g *GEOIP) Adapter() string {
return g.adapter
}
func (g *GEOIP) Payload() string {
return g.country
}
func (g *GEOIP) ShouldResolveIP() bool {
return !g.noResolveIP
}
func (g *GEOIP) GetCountry() string {
return g.country
}
func (g *GEOIP) GetIPMatcher() *router.GeoIPMatcher {
return g.geoIPMatcher
}
func NewGEOIP(country string, adapter string, noResolveIP bool) (*GEOIP, error) {
if !C.GeodataMode {
geoip := &GEOIP{
Base: &Base{},
country: country,
adapter: adapter,
noResolveIP: noResolveIP,
}
return geoip, nil
}
geoIPMatcher, recordsCount, err := geodata.LoadGeoIPMatcher(country)
if err != nil {
return nil, fmt.Errorf("[GeoIP] %s", err.Error())
}
log.Infoln("Start initial GeoIP rule %s => %s, records: %d", country, adapter, recordsCount)
geoip := &GEOIP{
Base: &Base{},
country: country,
adapter: adapter,
noResolveIP: noResolveIP,
geoIPMatcher: geoIPMatcher,
}
return geoip, nil
}
var _ C.Rule = (*GEOIP)(nil)

View File

@ -1,13 +1,15 @@
package rules
package common
import (
"fmt"
"github.com/Dreamacro/clash/component/geodata"
"github.com/Dreamacro/clash/component/geodata/router"
_ "github.com/Dreamacro/clash/component/geodata/standard"
C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/log"
_ "github.com/Dreamacro/clash/component/geodata/memconservative"
_ "github.com/Dreamacro/clash/component/geodata/standard"
)
type GEOSITE struct {
@ -38,10 +40,6 @@ func (gs *GEOSITE) Payload() string {
return gs.country
}
func (gs *GEOSITE) ShouldResolveIP() bool {
return false
}
func (gs *GEOSITE) GetDomainMatcher() *router.DomainMatcher {
return gs.matcher
}

View File

@ -1,4 +1,4 @@
package rules
package common
import (
"net"

View File

@ -0,0 +1,48 @@
package common
import (
"fmt"
C "github.com/Dreamacro/clash/constant"
"strings"
)
type NetworkType struct {
*Base
network C.NetWork
adapter string
}
func NewNetworkType(network, adapter string) (*NetworkType, error) {
var netType C.NetWork
switch strings.ToUpper(network) {
case "TCP":
netType = C.TCP
break
case "UDP":
netType = C.UDP
break
default:
return nil, fmt.Errorf("unsupported network type, only TCP/UDP")
}
return &NetworkType{
Base: &Base{},
network: netType,
adapter: adapter,
}, nil
}
func (n *NetworkType) RuleType() C.RuleType {
return C.Network
}
func (n *NetworkType) Match(metadata *C.Metadata) bool {
return n.network == metadata.NetWork
}
func (n *NetworkType) Adapter() string {
return n.adapter
}
func (n *NetworkType) Payload() string {
return n.network.String()
}

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