阿里云服务器 IPv6 网络问题排查记录

137 阅读2分钟

发现

  • 上一次被挖矿病毒攻击了以后,重启了一下服务器,发现之前跑的一个签到脚本 fansMedalHelper 失效了

    报错截图.png

    关键错误是 asyncio.exceptions.TimeoutError

排查

  • 一开始以为是代码本身或者

  • curl 一下 api,能够访问

    curl https://app.bilibili.com/x/v2/account/mine
    # {"code":-400,"message":"-400","ttl":1}
    
  • 但是对应的域名 ping 不通

    ping app.bilibili.com
    # PING app.bilibili.com(240e:bf:b800:4300:1::13 (240e:bf:b800:4300:1::13)) 56 data bytes
    # ^C
    # --- app.bilibili.com ping statistics ---
    # 7 packets transmitted, 0 received, 100% packet loss, time 6154ms
    

    试了一下百度发现也 ping 不通了

    ping www.baidu.com
    # PING www.baidu.com(240e:83:205:5a:0:ff:b05f:346b (240e:83:205:5a:0:ff:b05f:346b)) 56 data bytes
    # ^C
    # --- www.baidu.com ping statistics ---
    # 5 packets transmitted, 0 received, 100% packet loss, time 4093ms
    

    不过主域名可以 ping 通

    ping baidu.com
    # PING baidu.com (110.242.68.66) 56(84) bytes of data.
    # 64 bytes from 110.242.68.66 (110.242.68.66): icmp_seq=1 ttl=51 time=15.1 ms
    # 64 bytes from 110.242.68.66 (110.242.68.66): icmp_seq=2 ttl=51 time=15.0 ms
    # 64 bytes from 110.242.68.66 (110.242.68.66): icmp_seq=3 ttl=51 time=15.0 ms
    # ...
    
  • 听听 GPT 怎么说

    gpt的回答1.png

    查看了一下自己服务器的 ipv6 网关详情,发现确实没有开通公网带宽

    公网带宽.png

    但是之前为什么没开 ipv6 的公网带宽脚本也能正常运行呢?这个问题到最后也没有弄明白,总之先解决问题吧。

解决

还是问 GPT,它给了两种方案:

  1. 强制服务使用 IPv4 访问 url。由于脚本使用的是 aiohttp,所以可以直接配置,例如可以参考下面的代码:
from aiohttp import ClientSession, ClientTimeout, TCPConnector
import asyncio
import socket


async def fetch(url):
    timeout = ClientTimeout(total=30, connect=10)
    connector = TCPConnector(family=socket.AF_INET)  # 强制使用 IPv4

    async with ClientSession(timeout=timeout, connector=connector) as session:
        try:
            async with session.get(url) as response:
                return await response.text()
        except Exception as e:
            print(f"Error: {e}")


async def main():
    result = await fetch('https://www.baidu.com')
    print(result)

asyncio.run(main())

将源代码的 src/user.py 修改为

from aiohttp import ClientSession, ClientTimeout, TCPConnector
...
import socket
class BiliUser:
  def __init__(...):
      ...
      connector = TCPConnector(family=socket.AF_INET)  # 强制使用 IPv4
      self.session = ClientSession(timeout=ClientTimeout(total=3), trust_env = True, connector=connector)
      ...
  ...
...

不过这样做的话,后续每次更新代码都要留意冲突,比较麻烦

  1. 禁用 IPv6。既然没开公网带宽,那干脆就不要用了。
  • 首先打开 /etc/sysctl.conf 文件

    sudo vim /etc/sysctl.conf
    
  • 然后修改以下内容(0 表示启用 ipv6,1 表示禁用 ipv6)

    net.ipv6.conf.all.disable_ipv6=1
    net.ipv6.conf.default.disable_ipv6=1
    net.ipv6.conf.lo.disable_ipv6=1
    net.ipv6.conf.eth0.disable_ipv6=1
    

    改完后重启一下就可以用了

  • 至于为什么不直接删除 IPv6 网关,虽然它无法访问公网 IPv6,但是它可以访问私网的 IPv6。总之免费的东西就先留着,万一之后有用处呢