(几乎)无感的校园网 VPN 开源方案
(几乎)无感的校园网 VPN 开源方案
在校园网环境中,有些资源必须走校园网内的 DNS 或代理访问,而其他流量则希望走普通代理。 为了实现 clash 和 EasierConnect 的同时运行,并且尽可能减少重复操作,笔者对 EasierConnect 进行修改, 使其可以通过 Clash 覆写功能和 HTTP API 自动切换策略组节点。
最终达到的效果是:
- 本地 SOCKS5 代理,由 EasierConnect 提供。
- Clash 中创建一个校园网策略组,用于控制校园网内资源的访问。
- 自动在登录后将 EasierConnect 设置为策略组节点;在关闭时切换回 DIRECT 以避免可能的问题。
使用 Clash 覆写功能添加本地 SOCKS5 和校园网规则
大多数 Clash 客户端支持通过配置文件覆写代理组和规则,可以快速添加新的节点和策略组:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
proxies:
- name: "EasierConnect"
type: socks5
server: 127.0.0.1
port: 1080
proxy-groups:
- name: "NJU"
type: select
proxies:
- "EasierConnect"
- "DIRECT"
rules:
- 'IP-CIDR,114.212.0.0/16,NJU'
- 'DOMAIN-SUFFIX,nju.edu.cn,NJU'
修改 EasierConnect 源码,通过 Clash HTTP API 切换策略节点
EasierConnect 本身提供了 SOCKS5 服务,但无法自动通知 Clash 切换策略组节点。笔者修改了源代码,实现:
- 登录 VPN 后调用 Clash HTTP API 设置策略组节点为
EasierConnect
。 - 程序退出或异常时恢复
DIRECT
节点,保证校园网访问不受影响。
修改核心逻辑
- 新增
utils/clash.go
工具函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
func SetClashProxy(group string, proxyName string) {
defer func() {
if r := recover(); r != nil {
log.Printf("SetClashProxy recovered from panic: %v", r)
}
}()
url := fmt.Sprintf("%s/proxies/%s", clashAPIHost, group)
reqBody, _ := json.Marshal(ClashRequest{Name: proxyName})
req, err := http.NewRequest(http.MethodPut, url, bytes.NewBuffer(reqBody))
if err != nil {
log.Printf("SetClashProxy new request error: %v", err)
return
}
req.Header.Set("Content-Type", "application/json")
if clashSecret != "" {
req.Header.Set("Authorization", "Bearer "+clashSecret)
}
client := http.Client{Timeout: 3 * time.Second}
resp, err := client.Do(req)
if err != nil {
log.Printf("SetClashProxy error: %v", err)
return
}
defer resp.Body.Close()
log.Printf("SetClashProxy success: group=%s, proxy=%s (status=%d)", group, proxyName, resp.StatusCode)
}
- 修改
main.go
,在登录成功后和程序退出时调用
1
2
utils.SetClashProxy("NJU", "EasierConnect") // 登录后
defer utils.SetClashProxy("NJU", "DIRECT") // 退出时恢复
注意,启用这个功能需要开启 clash 核心的外部控制。
硬编码个人信息
运行 EasierConnect 需要指定账号密码等个人信息,虽然可以通过外部脚本传入参数来指定,但既然已经修改了源代码,不妨直接将个人信息硬编码为程序的默认值。
如果后续我有公开的打算,会考虑修改为从外部 config 文件读取这些信息。
结语
这个方案仅仅是一个折中的策略,在所有提供 IPV6 的地方笔者均推荐使用 tailscale。
总之,通过这套方案,在网络环境极端糟糕的地方(比如某为的茶思屋)也可以实现几乎无感和无副作用的连接校园网了,而且还不用担心 ITSC 查水表(但也许会被深信服查)。
当然,这个方案还是有不尽人意的地方,比如某些仅校内 DNS 才能查询的域名是无法访问的,但笔者要去享受国庆假期了,所以挖个坑之后忍不了了再填。
本文由作者按照 CC BY 4.0 进行授权