解决 Shadowsocks Windows 在线配置更新失败的问题

Shadowsocks Windows 已经超过一年没有更新,最近在使用 Shadowsocks Windows 的在线配置订阅 SIP008 链接时,提示更新失败。

打开日志显示如下:

2023-10-23 20:51:11.9093|WARN|Shadowsocks.Controller.ShadowsocksController|System.Net.Http.HttpRequestException: 发送请求时出错。 ---> System.Net.WebException: 请求被中止: 未能创建 SSL/TLS 安全通道。
   在 System.Net.HttpWebRequest.EndGetResponse(IAsyncResult asyncResult)
   在 System.Net.Http.HttpClientHandler.GetResponseCallback(IAsyncResult ar)
   --- 内部异常堆栈跟踪的结尾 ---
   在 System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   在 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   在 Shadowsocks.Controller.Service.OnlineConfigResolver.<GetOnline>d__0.MoveNext()
--- 引发异常的上一位置中堆栈跟踪的末尾 ---
   在 System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   在 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   在 Shadowsocks.Controller.ShadowsocksController.<UpdateOnlineConfigInternal>d__109.MoveNext()
--- 引发异常的上一位置中堆栈跟踪的末尾 ---
   在 System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   在 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   在 Shadowsocks.Controller.ShadowsocksController.<UpdateOnlineConfig>d__110.MoveNext()

可以看出是 SSL/TLS 的原因,尝试一下发现是订阅地址开启了强制 TLS1.3,Shadowsocks Windows 支持的 TLS 版本太低。

测试发现 Shadowsocks Windows 获取订阅链接只支持 TLS1.0。

解决方法:

  1. 降低提供订阅链接服务器的 TLS 版本,但是需要知道的是 TLS1.0 以及不再安全,降低有风险

  2. 本地开启代理把订阅链接转为HTTP,这里使用 Golang 写了一个简单的代理

package main

import (
    "fmt"
    "log"
    "net/http"
    "net/http/httputil"
    "net/url"
    "strings"
)

func handleRequestAndRedirect(res http.ResponseWriter, req *http.Request) {
    // 获取原始请求的路径
    path := req.URL.Path

    if path == "/favicon.ico" {
        return
    }

    parts := strings.SplitN(path, "/", 3)

    domain := parts[1]

    path = "/" + parts[2]

    // 去掉前缀的 "/localhost:8080"
    targetURL := "https://" + domain

    // 解析目标 URL
    target, err := url.Parse(targetURL)
    if err != nil {
        log.Fatal(err)
    }

    // 创建反向代理
    proxy := httputil.NewSingleHostReverseProxy(target)
    // 修改请求头
    req.URL.Host = target.Host
    req.URL.Scheme = target.Scheme
    req.Header.Set("X-Forwarded-Host", req.Header.Get("Host"))
    req.Host = target.Host
    req.URL.Path = path
    // 转发请求至目标 URL
    proxy.ServeHTTP(res, req)
}

func main() {
    // 创建处理函数
    http.HandleFunc("/", handleRequestAndRedirect)

    // 启动服务并监听端口
    fmt.Println("Starting server on port 10086...")
    log.Fatal(http.ListenAndServe("localhost:10086", nil))
}

运行 golang 代码,然后将订阅链接 https:// 替换成 http://localhost:10086/ 然后更新,以后每次更新前都需要先运行 golang 代码。