├── .gitignore ├── README.md ├── cmd └── ascf │ ├── build.bat │ └── main.go ├── hosts.go ├── http302.go ├── log.go ├── lookup.go └── tcpproxy.go /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | *.exe 3 | cmd/ascf/builds 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## 简介 2 | 这是一个临时性修复Steam社区的小工具,就叫它AnotherSteamCommunityFix(简称ASCF)吧~ 3 | ASCF是由Go语言写的,所以它可以运行在几乎任何系统平台上! 4 | 5 | ASCF会修改hosts文件,把steamcommunity.com域名指向本地(127.0.0.1),然后程序会监听本地的80和443端口。 6 | 当程序退出时(按Ctrl+C退出),它会把hosts恢复原样。 7 | 8 | ## 下载地址 9 | * [Github Release](https://github.com/zyfworks/AnotherSteamCommunityFix/releases) 10 | * [百度云网盘分流下载](https://pan.baidu.com/s/1nvBW8qP) 11 | 12 | ## 注意事项 13 | * 访问Steam社区时必须保持该程序运行! 14 | * 如果出现闪退,请使用管理员权限启动,并确保系统中没有其他程序占用80和443端口。 15 | * 您可以通过运行参数`-ip=xxx.xxx.xxx.xxx`令程序强制使用这个IP地址来连接。 16 | * 第一次使用前请先清空hosts文件中和steamcommunity.com相关的条目。 17 | * 树莓派2及以上请使用ascf_Linux_ARMv7、树莓派1请使用ascf_linux_ARMv6、64位ARM平台请使用ascf_linux_ARMv8。 18 | 19 | ## Linux/macOS使用指南 20 | 1. 下载并解压缩 21 | 2. 打开终端(Terminal),进入到ascf程序目录: 22 | 如ascf程序在 /User/Makazeu/Downloads/ascf_darwin_amd64/文件夹中,那么在终端中输入: 23 | ```cd /User/Makazeu/Downloads/ascf_darwin_amd64/``` 24 | 3. 赋予程序可执行权限,在终端中输入命令: 25 | ```chmod +x ./ascf``` 26 | 4. 使用root用户(管理员用户)运行程序,在终端中输入: 27 | ```sudo ./ascf``` 28 | 输入root用户密码后,看程序是否运行。 29 | 因为程序涉及到hosts文件修改,需要高权限,所以你需要输入root密码 30 | 5. 若程序已经成功运行,此时就不要关闭终端窗口了,否则程序就会退出!试下Steam社区能否正常打开。 31 | 6. 一切都没问题后,在终端窗口中退出程序(按Ctrl+C),然后以后台的方式运行程序,输入 32 | ```nohup sudo ./ascf &``` 33 | 7. 之后就可以关闭终端窗口了,此时程序在后台运行。现在steamcommunity.com可以打开咯! 34 | -------------------------------------------------------------------------------- /cmd/ascf/build.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | set Version=1.2.3 3 | echo v%Version% 4 | 5 | md builds 6 | 7 | set goos=windows 8 | set goarch=amd64 9 | echo goos=windows, goarch=amd64 10 | go build 11 | md builds\ascf_v%Version%_Windows_x64 12 | move ascf.exe builds\ascf_v%Version%_Windows_x64 13 | 14 | set goos=windows 15 | set goarch=386 16 | echo goos=windows, goarch=386 17 | go build 18 | md builds\ascf_v%Version%_Windows_x86 19 | move ascf.exe builds\ascf_v%Version%_Windows_x86 20 | 21 | set goos=darwin 22 | set goarch=amd64 23 | echo goos=darwin, goarch=amd64 24 | go build 25 | md builds\ascf_v%Version%_macOS_x64 26 | move ascf builds\ascf_v%Version%_macOS_x64 27 | 28 | set goos=darwin 29 | set goarch=386 30 | echo goos=darwin, goarch=386 31 | go build 32 | md builds\ascf_v%Version%_macOS_x86 33 | move ascf builds\ascf_v%Version%_macOS_x86 34 | 35 | set goos=linux 36 | set goarch=amd64 37 | echo goos=linux, goarch=amd64 38 | go build 39 | md builds\ascf_v%Version%_Linux_x64 40 | move ascf builds\ascf_v%Version%_Linux_x64 41 | 42 | set goos=linux 43 | set goarch=386 44 | echo goos=linux, goarch=386 45 | go build 46 | md builds\ascf_v%Version%_Linux_x86 47 | move ascf builds\ascf_v%Version%_Linux_x86 48 | 49 | set goos=linux 50 | set goarch=arm 51 | set goarm=6 52 | echo goos=linux, goarch=arm, goarm=6 53 | go build 54 | md builds\ascf_v%Version%_Linux_ARMv6 55 | move ascf builds\ascf_v%Version%_Linux_ARMv6 56 | 57 | set goos=linux 58 | set goarch=arm 59 | set goarm=7 60 | echo goos=linux, goarch=arm, goarm=7 61 | go build 62 | md builds\ascf_v%Version%_Linux_ARMv7 63 | move ascf builds\ascf_v%Version%_Linux_ARMv7 64 | 65 | set goos=linux 66 | set goarch=arm64 67 | echo goos=linux, goarch=arm64, goarm=8 68 | go build 69 | md builds\ascf_v%Version%_Linux_ARMv8 70 | move ascf builds\ascf_v%Version%_Linux_ARMv8 71 | 72 | pause -------------------------------------------------------------------------------- /cmd/ascf/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "fmt" 6 | "log" 7 | "net/http" 8 | "os" 9 | "os/signal" 10 | "runtime" 11 | "time" 12 | 13 | "github.com/bitly/go-simplejson" 14 | ascf "github.com/zyfworks/AnotherSteamCommunityFix" 15 | ) 16 | 17 | var ( 18 | version = "1.2.3" 19 | domainName = "steamcommunity.com" 20 | defaultIP = "184.26.221.151" // 日本東京都 Akamai CDN 21 | dnsList = map[string]string{ 22 | "OpenDNS_1": "208.67.222.222:5353", 23 | "OpenDNS_2": "208.67.220.220:443", 24 | "OpenDNS_2-fs": "208.67.220.123:443", 25 | } 26 | 27 | fixedIP string 28 | ) 29 | 30 | func init() { 31 | flag.StringVar(&fixedIP, "ip", "", "手动指定IP地址") 32 | flag.Parse() 33 | log.SetFlags(log.Lshortfile) 34 | } 35 | 36 | func main() { 37 | sayHello() 38 | checkVersion() 39 | addHosts() 40 | 41 | interrupt := make(chan os.Signal) 42 | signal.Notify(interrupt, os.Kill) 43 | signal.Notify(interrupt, os.Interrupt) 44 | 45 | log.Println("正在获取IP地址,请稍候~") 46 | var ipAddr string 47 | if len(fixedIP) == 0 { 48 | // name resolution by DNS 49 | address, err := ascf.DnsLookUp(domainName, dnsList) 50 | if err == nil && address != nil { 51 | ipAddr = address.String() 52 | log.Println("域名解析成功:", ipAddr) 53 | goto Start 54 | } 55 | // online lookup via http 56 | address, err = ascf.HttpLookup(domainName) 57 | if err == nil && address != nil { 58 | ipAddr = address.String() 59 | log.Println("获取IP地址成功:", ipAddr) 60 | goto Start 61 | } 62 | // using preset ip address 63 | ipAddr = defaultIP 64 | log.Println("获取IP地址失败,使用备用IP地址:", ipAddr) 65 | } else { 66 | ipAddr = fixedIP 67 | log.Println("使用手动指定的IP地址:", ipAddr) 68 | } 69 | 70 | Start: 71 | fmt.Println("\n程序已启动,请不要关闭该窗口!") 72 | fmt.Println() 73 | fmt.Println("对于Mac和Linux用户,使用nohup命令运行程序可使其在后台运行。\n" + 74 | "\t└─ 在终端中进入程序所在目录后执行 “nohup sudo ./ascf &”即可。") 75 | 76 | go ascf.StartServingHTTPSRedirect() 77 | go ascf.StartServingTCPProxy(":443", ipAddr+":443") 78 | 79 | select { 80 | case <-interrupt: 81 | removeHosts() 82 | } 83 | } 84 | 85 | func addHosts() { 86 | if err := ascf.AddHosts("127.0.0.1", domainName); err != nil { 87 | log.Fatal(err) 88 | } 89 | } 90 | 91 | func removeHosts() { 92 | if err := ascf.RemoveHosts("127.0.0.1", domainName); err != nil { 93 | log.Fatal(err) 94 | } 95 | } 96 | 97 | func sayHello() { 98 | fmt.Printf("~ 欢迎使用AnotherSteamCommunityFix v%s ~\n", version) 99 | fmt.Println("Author: Makazeu [ Steam: Makazeu | Weibo: @Makazeu ]") 100 | fmt.Println() 101 | } 102 | 103 | func checkVersion() { 104 | platform := runtime.GOOS + "_" + runtime.GOARCH 105 | client := &http.Client{Timeout: 5 * time.Second} 106 | r, err := client.Get("https://up.w21.win/update?" + 107 | "name=ascf&platform=" + platform + "&version=" + version) 108 | if err != nil { 109 | return 110 | } 111 | defer r.Body.Close() 112 | 113 | json, err := simplejson.NewFromReader(r.Body) 114 | if err != nil { 115 | return 116 | } 117 | isOK, err := json.Get("ok").Bool() 118 | if err != nil || !isOK { 119 | return 120 | } 121 | 122 | newVersion, err := json.Get("version").String() 123 | if err != nil { 124 | return 125 | } 126 | if newVersion != version { 127 | fmt.Println("检测到新版本:" + newVersion + ",下载地址: https://steamcn.com/t339641-1-1") 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /hosts.go: -------------------------------------------------------------------------------- 1 | package AnotherSteamCommunityFix 2 | 3 | import ( 4 | "errors" 5 | "github.com/zyfworks/goodhosts" 6 | ) 7 | 8 | func AddHosts(ip string, hostEntries ...string) error { 9 | hosts, err := goodhosts.NewHosts() 10 | if err != nil { 11 | return err 12 | } 13 | 14 | if !hosts.IsWritable() { 15 | return errors.New("hosts文件不可写,请以更高的权限运行") 16 | } 17 | 18 | if err = hosts.Add(ip, hostEntries...); err != nil { 19 | return err 20 | } 21 | 22 | return hosts.Flush() 23 | } 24 | 25 | func RemoveHosts(ip string, hostEntries ...string) error { 26 | hosts, err := goodhosts.NewHosts() 27 | if err != nil { 28 | return err 29 | } 30 | 31 | if !hosts.IsWritable() { 32 | return errors.New("hosts文件不可写,请以更高的权限运行") 33 | } 34 | 35 | if err = hosts.Remove(ip, hostEntries...); err != nil { 36 | return err 37 | } 38 | 39 | return hosts.Flush() 40 | } 41 | -------------------------------------------------------------------------------- /http302.go: -------------------------------------------------------------------------------- 1 | package AnotherSteamCommunityFix 2 | 3 | import ( 4 | "net" 5 | "net/http" 6 | ) 7 | 8 | func redirectHTTPS(w http.ResponseWriter, req *http.Request) { 9 | target := "https://" + req.Host + req.URL.Path 10 | if len(req.URL.RawQuery) > 0 { 11 | target += "?" + req.URL.RawQuery 12 | } 13 | http.Redirect(w, req, target, http.StatusFound) 14 | } 15 | 16 | func StartServingHTTPSRedirect() { 17 | server := &Server{ 18 | http.Server{ 19 | Addr: ":80", 20 | Handler: http.HandlerFunc(redirectHTTPS), 21 | }, 22 | } 23 | fatalLogger.Fatal(server.ListenAndServe()) 24 | } 25 | 26 | type Server struct { 27 | http.Server 28 | } 29 | 30 | func (srv *Server) ListenAndServe() error { 31 | addr := srv.Addr 32 | if addr == "" { 33 | addr = ":http" 34 | } 35 | ln, err := net.Listen("tcp4", addr) 36 | if err != nil { 37 | return err 38 | } 39 | return srv.Serve(tcpKeepAliveListener{ln.(*net.TCPListener)}) 40 | } 41 | 42 | type tcpKeepAliveListener struct { 43 | *net.TCPListener 44 | } 45 | -------------------------------------------------------------------------------- /log.go: -------------------------------------------------------------------------------- 1 | package AnotherSteamCommunityFix 2 | 3 | import ( 4 | "log" 5 | "os" 6 | ) 7 | 8 | var fatalLogger *log.Logger 9 | 10 | func init() { 11 | fatalLogger = log.New(os.Stderr, "\n程序发生错误,已退出!\n", log.Lshortfile) 12 | } 13 | -------------------------------------------------------------------------------- /lookup.go: -------------------------------------------------------------------------------- 1 | package AnotherSteamCommunityFix 2 | 3 | import ( 4 | "errors" 5 | "log" 6 | "math/rand" 7 | "net" 8 | "net/http" 9 | "time" 10 | 11 | "github.com/bitly/go-simplejson" 12 | "github.com/miekg/dns" 13 | ) 14 | 15 | const RETRY = 5 16 | 17 | func init() { 18 | rand.Seed(time.Now().UnixNano()) 19 | } 20 | 21 | func DnsLookUp(domainName string, dnsList map[string]string) (net.IP, error) { 22 | client := &dns.Client{Net: "tcp"} 23 | msg := &dns.Msg{} 24 | msg.SetQuestion(domainName+".", dns.TypeA) 25 | 26 | for dnsName, dnsAddress := range dnsList { 27 | for i := 1; i <= RETRY; i++ { 28 | r, t, err := client.Exchange(msg, dnsAddress) 29 | if err == nil && len(r.Answer) > 0 { 30 | log.Printf("使用%s解析域名成功,耗时: %v\n", dnsName, t) 31 | return r.Answer[rand.Int()%len(r.Answer)].(*dns.A).A, nil 32 | } 33 | } 34 | log.Printf("使用%s解析域名失败...", dnsName) 35 | } 36 | return nil, errors.New("域名解析失败") 37 | } 38 | 39 | func HttpLookup(domain string) (net.IP, error) { 40 | client := &http.Client{Timeout: 15 * time.Second} 41 | r, err := client.Get("https://dns-api.org/A/" + domain) 42 | if err != nil { 43 | return nil, err 44 | } 45 | defer r.Body.Close() 46 | 47 | var ip string 48 | json, err := simplejson.NewFromReader(r.Body) 49 | if err != nil { 50 | return nil, err 51 | } 52 | arr, err := json.Array() 53 | if err != nil { 54 | return nil, err 55 | } 56 | for i := range arr { 57 | ans := json.GetIndex(i) 58 | ip, err = ans.Get("value").String() 59 | if err == nil { 60 | return net.ParseIP(ip), nil 61 | } 62 | } 63 | 64 | return nil, errors.New("could not get the IP address") 65 | } 66 | -------------------------------------------------------------------------------- /tcpproxy.go: -------------------------------------------------------------------------------- 1 | package AnotherSteamCommunityFix 2 | 3 | import ( 4 | "io" 5 | "log" 6 | "net" 7 | "time" 8 | ) 9 | 10 | func handleConn(conn net.Conn, remote string) { 11 | defer conn.Close() 12 | 13 | remoteConn, err := net.DialTimeout("tcp", remote, 15*time.Second) 14 | if err != nil { 15 | log.Println("dial remote error:", err) 16 | return 17 | } 18 | defer remoteConn.Close() 19 | 20 | go io.Copy(conn, remoteConn) 21 | io.Copy(remoteConn, conn) 22 | } 23 | 24 | func StartServingTCPProxy(local, remote string) { 25 | listener, err := net.Listen("tcp4", local) 26 | if err != nil { 27 | fatalLogger.Fatal("listen tcp error:", err) 28 | } 29 | 30 | for { 31 | conn, err := listener.Accept() 32 | if err != nil { 33 | log.Println("accept tcp error:", err) 34 | } 35 | go handleConn(conn, remote) 36 | } 37 | } 38 | --------------------------------------------------------------------------------