🍀 借助 Github Actions 解决 Github DNS 污染问题

前言

Github 国内问题

国内网络访问 Github 速度过慢的原因有许多,但其中最直接的原因是其 CDN 域名遭到 DNS 污染,导致我们无法连接使用 GitHub 的加速服务,因此访问速度缓慢或访问不了。

什么是 DNS 污染

DNS 污染,是指一些刻意或无意制造出来的数据包,把域名指向不正确的 IP 地址阻碍了网络访问。我们默认从目标网址的最近 CDN 节点获取内容,但当节点过远或 DNS 指向错误时,就会造成访问速度过慢或无法访问等问题。

有哪些解决方案?

  1. 使用 VPN 进行科学上网,当然大部分的 VPN 并不是免费的。
  2. 查找 Github 正确的 DNS IP,然后借助于 SwitchHosts 配置 Host。

方案

在之前的章节中,我们简单介绍了国内 Github DNS 问题以及解决方案。毫无疑问第一种方案是能有效解决大部分国内资源被墙的问题。但作为IT技术爱好者,我更喜欢尝试用第二种方案来解决 Github 问题。

初步验证

  1. 在一台已经科学上网的电脑上,通过 nslookup github.com 找出正确的 Github IP。

    bash 复制代码
      nslookup github.com
    
    
      Server:    192.168.1.1
      Address:   192.168.1.1#53
    
      Non-authoritative answer:
      Name:  github.com
      Address: 20.205.243.166
  2. 在另一台无法访问 Github 电脑上,通过 SwitchHosts 如下配置,终于可以正常访问。

相关问题

虽然我们已经通过实践验证了第二种方案的可行性,但仍然有不少的问题有待解决:

  1. 上述验证阶段,我们通过 nslookup github.com 获取的 DNS IP,但 Github 域名所解析的 DNS 是随着时间而不断变化的,那怎么解决呢?

    关于这一点,我们想到了 Github Actions, 借助于它,我们不仅可以正确解析 Github DNS IP, 我们还可以设置 cron 定期自动查询 (比如每2小时查询一次)。Perfect!

  2. 解决了 Github DNS IP 定期自动更新问题,那我们如何在自己的电脑上配置 Github Host, 难道每一次 DNS IP 的变更,都需要手动重新配置吗?

    其实并不需要这么麻烦,我可以借助于 SwitchHosts 这款软件的远程 Host 的配置来实现,同时它还可以帮我们定期同步远程的 Host。

  3. 还有一个比较棘手的问题,当我们借助于 Github Actions 定期生成 Github 正确的 Host 文件供 SwitchHosts 配置远程的 Host 时。如果当时 Github 本身相关域名不可访问,那本机的 SwitchHosts 又如何访问该域名下远程的 Host 文件呢?

    确实这一点,有点像鸡生蛋还是蛋生鸡的问题。怎么解决呢,我们打算借助大神提供的 Github Actions, 将 Github 生成 Host 的整个仓库,同步到 Gitee 上, 同时生成 Gitee Pages,以便 SwitchHosts 获取和配置远程的 Gitee 的 Github DNS Host 文件。

梳理思路

  1. 编写 ZX nslookup 查询 Github DNS,生成 host 文件 的脚本
  2. 编写 Github Workflow 定时执行,并创建 Github Pages 的配置
  3. 编写 Github Workflow 同步 Github git 仓库部署到 Gitee 的配置
  4. 编写 Github Workflow 创建 Gitee git 仓库 Gitee Pages 的配置
  5. 使用 本机 SwitchHost 配置远程 Github/Gitee DNS host,并设置定时刷新

实施

编写 ZX 脚本

  • 执行 nslookup 查询 Github DNS,并将其生成 host 文件

    javascript 复制代码
    #!/usr/bin/env zx
    
    const writer = async arr => {
      let temp = {}
      const list = []
    
      for (const url of arr) {
        if (/^\.*\//.test(url)) {
          list.push(temp = {
            file: path.resolve(url),
            contents: [],
            content: '',
          })
          continue
        }
    
        if (temp.contents) {
          temp.contents.push(url)
        }
      }
    
      for (const temp of list) {
        temp.content = await updater(temp.contents)
      }
    
      for (const temp of list) {
        fs.ensureFileSync(temp.file)
        fs.writeFile(temp.file, temp.content)
      }
    }
    
    const updater = async arr => {
      const templates = []
      const datetime = new Date().toUTCString()
    
      templates.push(`# Update: ${datetime}\n`)
    
      for (const url of arr) {
        if (url) {
          const ip = await nslookup(url)
          const dns = `${ip}\t\t${url}`
    
          if (ip) {
            templates.push(dns)
          }
        }
      }
    
      templates.sort((next, prev) => {
        const nexts = next.split(/\s/)
        const prevs = prev.split(/\s/)
        return nexts[0].length < prevs[0].length ? -1 : 1
      })
    
      return templates.join('\n')
    }
    
    const nslookup = async url => {
      try {
        const regex = new RegExp(`.*Name:\\s*[\\S]+\\s*Address:\\s*([0-9.]+)\\s*.*`, 'ims')
        const dns = (await $`nslookup ${url}`).stdout
        const ip = dns.replace(regex, '$1')
    
        if (!/\d+\.\d+\.\d+\.\d+/.test(ip)) {
          return ''
        }
    
        if (ip === '127.0.0.1') {
          return ''
        }
    
        if (ip === '0.0.0.0') {
          return ''
        }
    
        if (ip) {
          return ip
        }
      } catch {}
    
      return ''
    }
    
    // Github 相关域名,仅摘录部分
    writer([
      './public/host.txt',
      'github.blog',
      'github.com',
      'github.io',
       ...
    ])
  • host 文件范例

    bash 复制代码
      # Update: Sat, 18 May 2024 00:00:38 GMT
    
      192.0.66.2          github.blog 
      140.82.116.4        github.com
      185.199.111.153     github.io

配置 Workflow

  • 编写 Github Workflow 定时执行,并创建 Github Pages 的配置

    yml 复制代码
        name: update github dns ip
    
        on:
          schedule:
            - cron: '0 */2 * * *' # 每隔两小时自动执行
    
        jobs:
          github-host:
            runs-on: ubuntu-latest # ubuntu 运行环境
            steps:
              - name: Checkout
                uses: actions/checkout@v4 # 检出仓库 main 主分支
    
              - name: Set pnpm
                uses: pnpm/action-setup@v3 # 安装 pnpm,版本 8
                with:
                  version: 8
                  
              - name: Set nodejs
                uses: actions/setup-node@v4 # 安装 node,版本 20
                with:
                  node-version: 20
                  registry-url: https://registry.npmjs.org/
                  cache: 'pnpm'
    
              - name: Install dependencies # 安装依赖
                run: pnpm install
    
              - name: Building scripts # 运行构建,创建 public/host 文件
                run: pnpm build
    
              - name: Deploy to GitHub Pages
                uses: peaceiris/actions-gh-pages@v4 # 创建 Github Pages
                with:
                  publish_dir: ./public
                  user_name: ${{ secrets.MY_USER_NAME }}
                  user_email: ${{ secrets.MY_USER_EMAIL }}
                  github_token: ${{ secrets.GITHUB_TOKEN }}
                  
  • 编写 Github Workflow 同步 Github git 仓库部署到 Gitee 的配置,主要借助于大神的 Yikun/hub-mirror-action@master 实现的

    yml 复制代码
        name: update github dns ip
    
        on:
          schedule:
            - cron: '0 */2 * * *' # 每隔两小时自动执行
    
        jobs:
           push-gitee-repo:
            runs-on: ubuntu-latest
            needs: github-host
            steps:
              - name: Add And Push Gitee
                uses: Yikun/hub-mirror-action@master
                with:
                  src: github/dns-host
                  dst: gitee/dns-host
                  dst_key: ${{ secrets.GITEE_PRIVATE_KEY }}
                  dst_token: ${{ secrets.GITEE_PERSONAL_TOKEN }}
                  static_list: 'github'
                  force_update: true
                  account_type: org
                  
  • 编写 Github Workflow 创建 Gitee git 仓库 Gitee Pages 的配置,主要借助于大神的 yanglbme/gitee-pages-action@main 实现的

    yml 复制代码
        name: update github dns ip
    
        on:
          schedule:
            - cron: '0 */2 * * *' # 每隔两小时自动执行
    
        jobs:
          deploy-gitee-repo:
            runs-on: ubuntu-latest
            needs: push-gitee-repo
            steps:
              - name: Deploy Gitee Pages
                uses: yanglbme/gitee-pages-action@main
                with:
                  gitee-username: ${{ secrets.GITEE_USERNAME }}
                  gitee-password: ${{ secrets.GITEE_PASSWORD }}
                  gitee-repo: dns-host/github
                  branch: gh-pages
                  

配置 SwitchHost

  • https://dns-host.github.io/github/host.txt
  • https://dns-host.gitee.io/github/host.txt (目前 Gitee 已暂停 Pages 服务)
  • https://gitee.com/dns-host/github/raw/gh-pages/host.txt (推荐)

资源

Git repo

https://github.com/dns-host/github
https://gitee.com/dns-host/github

Git host

https://github.com/dns-host/github/blob/gh-pages/host.txt
https://gitee.com/dns-host/github/blob/gh-pages/host.txt

Git io

https://dns-host.github.io/github/host.txt
https://dns-host.gitee.io/github/host.txt

相关推荐
小白学习日记37 分钟前
【复习】HTML常用标签<table>
前端·html
john_hjy40 分钟前
11. 异步编程
运维·服务器·javascript
风清扬_jd1 小时前
Chromium 中JavaScript Fetch API接口c++代码实现(二)
javascript·c++·chrome
丁总学Java1 小时前
微信小程序-npm支持-如何使用npm包
前端·微信小程序·npm·node.js
yanlele1 小时前
前瞻 - 盘点 ES2025 已经定稿的语法规范
前端·javascript·代码规范
It'sMyGo1 小时前
Javascript数组研究09_Array.prototype[Symbol.unscopables]
开发语言·javascript·原型模式
懒羊羊大王呀2 小时前
CSS——属性值计算
前端·css
xgq2 小时前
使用File System Access API 直接读写本地文件
前端·javascript·面试
李是啥也不会2 小时前
数组的概念
javascript
用户3157476081352 小时前
前端之路-了解原型和原型链
前端