參考:
國內加速訪問Github的辦法,超級簡單 - 擴展迷Extfans的文章 - 知乎
https://zhuanlan.zhihu.com/p/65154116
html
手動改來改去太麻煩了,因而寫了個 Go 程序來自動更新。node
/***************************************************************************** 文件: github_hosts_speed.go 描述: 獲取 github 相關域名的 ip 地址 做者: solym ymwh@foxmail.com 版本: 2020.04.27 日期: 2020年4月27日 歷史: *****************************************************************************/ package main import ( "bufio" "bytes" "fmt" "io/ioutil" "net/http" "os" "runtime" json "github.com/json-iterator/go" ) func httpGetRequest(url string) ([]byte, error) { // 建立一個請求 req, err := http.NewRequest("GET", url, nil) if err != nil { return nil, err } // 設置頭,模擬火狐瀏覽器 req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:75.0) Gecko/20100101 Firefox/75.0") req.Header.Set("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8") req.Header.Set("Accept-Language", "zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2") req.Header.Set("Connection", "keep-alive") req.Header.Set("Upgrade-Insecure-Requests", "1") req.Header.Set("Pragma", "no-cache") req.Header.Set("Cache-Control", "no-cache") // 執行請求結果 resp, err := http.DefaultClient.Do(req) if err != nil { return nil, err } defer resp.Body.Close() // 獲取返回結果 data, err := ioutil.ReadAll(resp.Body) if resp.StatusCode != 200 || err != nil { return nil, fmt.Errorf("請求失敗:[%d] %v", resp.StatusCode, err) } return data, nil } func getPublicIP() (string, error) { // 經過訪問 http://pv.sohu.com/cityjson 來獲取 // var returnCitySN = {"cip": "111.196.240.67", "cid": "110000", "cname": "北京市"}; data, err := httpGetRequest("http://pv.sohu.com/cityjson") if err != nil { return "", err } if i := bytes.IndexByte(data, '{'); i > 0 { data = data[i:] any := json.Get(data, "cip") return any.ToString(), nil } else { return "", fmt.Errorf("格式不正確:%s", string(data)) } } func getIPAddressOfDomain(domain, myip string) (string, error) { // 經過 119.29.29.29 的 接口獲取最合適的 IP url := "http://119.29.29.29/d?dn=" + domain + "&ip=" + myip data, err := httpGetRequest(url) if err != nil { return "", err } // 可能會有多個 IP 返回,只要第一個 // 185.199.109.154;185.199.110.154;185.199.111.154;185.199.108.154 if i := bytes.IndexByte(data, ';'); i > 6 { data = data[0:i] } return string(data), nil } func main() { // 一、獲取本機的公網IP myip, err := getPublicIP() if err != nil { fmt.Println("獲取公網 IP 地址失敗:", err) return } // 二、獲取域名對應的IP地址 domainlist := []string{ "github.global.ssl.fastly.net", "github.com", "assets-cdn.github.com", "documentcloud.github.com", "gist.github.com", "help.github.com", "nodeload.github.com", "raw.github.com", "status.github.com", "training.github.com", "www.github.com", "avatars0.githubusercontent.com", "avatars1.githubusercontent.com", "github.githubassets.com", "github-production-release-asset-2e65be.s3.amazonaws.com", "api.github.com", "user-images.githubusercontent.com", "raw.githubusercontent.com", "gist.githubusercontent.com", "camo.githubusercontent.com", "avatars2.githubusercontent.com", "avatars3.githubusercontent.com", "avatars4.githubusercontent.com", "avatars5.githubusercontent.com", "avatars6.githubusercontent.com", "avatars8.githubusercontent.com", "github.io", "avatars7.githubusercontent.com", } // 域名IP映射表 domaintoipaddr := make(map[string]string) for _, domain := range domainlist { ipaddr, err := getIPAddressOfDomain(domain, myip) if err != nil { fmt.Println("錯誤:", err, domain) continue } fmt.Println(ipaddr, domain) domaintoipaddr[domain] = ipaddr } // 三、更新 hosts 文件 hostspath := "/etc/hosts" if runtime.GOOS == "windows" { // 這裏應該先經過環境變量 windir 或 SystemRoot 獲取路徑 hostspath = "C:/Windows/System32/drivers/etc/hosts" } // 讀取 hosts 文件 hostsdata, err := ioutil.ReadFile(hostspath) if err != nil { fmt.Println(err) return } // 逐行讀取並更新 hostsreader := bufio.NewReader(bytes.NewReader(hostsdata)) hostsbuffer := bytes.NewBuffer(nil) hostswriter := bufio.NewWriter(hostsbuffer) line, err := hostsreader.ReadSlice('\n') for ; err == nil; line, err = hostsreader.ReadSlice('\n') { // 分割爲多個部分 fields := bytes.Fields(line) // 多是 # xxx xxxx // 127.0.0.1 localhost # xxxxx // 等多種形勢 if len(fields) < 2 || fields[0][0] == byte('#') { hostswriter.Write(line) continue } // 若是域名存在,則替換 domain := string(fields[1]) if ipaddr, ok := domaintoipaddr[domain]; ok { fields[0] = []byte(ipaddr) line = bytes.Join(fields, []byte(" ")) // 將映射表內的刪除 delete(domaintoipaddr, domain) } hostswriter.Write(line) } // 將不存在 Hosts 中的加入 hostswriter.WriteString("\n# github speed\n") for domain := range domaintoipaddr { hostswriter.WriteString(fmt.Sprintln(domaintoipaddr[domain], domain)) } hostswriter.Flush() // 寫入到 hosts 文件,這裏應該須要管理員權限 err = ioutil.WriteFile(hostspath, hostsbuffer.Bytes(), os.ModePerm) if err != nil { fmt.Println("寫入更新失敗:", err) return } // 還須要刷新下 DNS 緩存,這裏就直接給個提示好了 fmt.Println("更新 hosts 文件完成,須要刷新 DNS 緩存請參考下面命令") fmt.Println("Windows 請執行命令: ipconfig /flushdns") fmt.Println("Linux 請執行命令: sudo service nscd restart") fmt.Println(" 或: sudo service restart") fmt.Println(" 或: sudo systemctl restart network") fmt.Println(" 或: sudo /etc/init.d/networking restart") fmt.Println("MacOS 請執行命令: sudo killall -HUP mDNSResponder") fmt.Println(" Yosemite: sudo discoveryutil udnsflushcaches") fmt.Println(" Snow Leopard: sudo dscacheutil -flushcache") fmt.Println("Leopard and below: sudo lookupd -flushcache") }