分类目录归档:享受过程

Manjaro Linux 抢救记

2024 年中秋适逢台风贝碧嘉来袭(熟悉的开头:D),强降水给小区带来的树倒、停电等一系列灾害,我的装了洗手.jpgManjaro 系统的 N100 小主机在 226 天的 uptime 后终于趁着停电休息了一把。供电恢复后通过 openVPN 、智能家居 app 发现路由器、 IoT 设备都已重新上线,困惑的是唯独这台小主机仍然处于失联状态。等到节后回来便研究了一番。以下全程感谢 @wzyboy 再一次的不吝指导。

接上显示器和外设开机发现,系统已经处于 emergency mode 状态。此时遇到的第一个坑是,emergency mode 的第一行提示 “loadkmap short read”,加上按一些字母键都没有反应(此时实为输入密码状态,但无回显),由于对 emergency mode 不熟悉使我和 gpt 误认为键盘映射出现问题。实际上此时只要输入 root 的密码就可以登录系统。

以 root 登录后输入 dmesg 查看内核输出的启动信息,发现在正常启动过程中有以下看起来很关键的报错:

intel_ish_ipc: ishtp-ish timed out waiting for fw-initiated reset
intel_ish_ipc: ISH: hw start failed.

于是一阵搜索,越搜越觉得困惑和茫然,是不是内核 bug,是不是硬件损坏…gpt 也小心翼翼地建议在 grub 启动项中屏蔽 ish 有关硬件,满怀希望地保存后重启,问题依旧。

emergency mode 中,系统很明确地提示要用 journalctl -xb 命令去查看启动日志,于是很仔细地查看这一千七百八行日志,这里我边看边在想,和 dmesg 不同的是阻塞正常启动的关键错误信息可能不会按时间顺序出现在日志的最后面,但仍会以不同颜色的字体标出。

仔细观察日志后发现与 /etc/fstab 有关的挂载错误,却没被我放在心上。我知道挂载一个不存在的分区会引起启动问题,因此在 /etc/fstab 中设置了 nofail 来长期把一移动硬盘挂载在系统中。虽然排错时移动硬盘未插入,不至于影响正常启动吧?所以又错过了奇点,从别的角度甚至是 USB Live CD 的 chroot 等方式试图修复系统。等到回过头继续从 journalctl -xb 日志侦错时,还是觉得大致记下报错的分区 UUID 去 /etc/fstab 看一眼吧。这一看才发现该 UUID 所对应的是一个未设置 nofail 、已经被合并了进 / 了的、不存在的分区,因为操作时间久远且一直未重启才忽略了该问题,注释该行,问题解决。

在排错的过程中,因为系统设置了中文导致 emergency mode 的字体全变成方块,这个问题在我首次接触 debian 时也遇到过,不过此次学到了通过设置变量 export LANG=C 的方法强制 fallback 到比 en_US.UTF-8 还基本的 locale 来避免中文显示问题。甚至还了解到了有趣的 Linux tty 勉强型中文字体——戴着有限字符空间的镣铐跳起支持中文的舞。又让我想起了一些汉化版 FC 游戏因 ROM 空间不足而被迫实施的一些奇技淫巧。

Linux 启动排错可能使人更有机会了解 “Linux 系统是怎么编排硬件的” 。而我一直想象的一个场景是:把桌面环境的 Linux 自行配置成家用路由器——通过安装 pppoe 、 upnp 等软件包来实现家用路由器功能;配置多网卡、网桥、路由表等来实现 WAN-LAN 口转发等,这样的场景想必更有挑战,也会使人更加了解 “Linux 系统是怎么编排网络的” 。

iOS Surge 加载 wireguard 配置打通 tailscale

Wireguard 是新一代的轻量级、易于配置、简洁优雅的 VPN 协议。 tailscale 是底层利用了 wireguard 协议和 UDP 打洞等方式,把天南地北的主机去中心化地连为虚拟局域网的商业产品。 tailscale 有很大的免费使用额度(3 用户 100 终端,2024.2),在各大操作系统平台上都有配置简单的客户端。但在 iOS 上启动会占用独占性的 VPN 接口,和 Surge 产生了互斥。最贴身的 iPhone 设备不能接入自己的 tailscale 网络是很可惜的,于是 2024 年的春节档就着手准备解决这个问题。

这个问题有很多解决途径,iPhone 开启 tailscale app 之后借助 tailscale 的 exit node 功能把所有流量交给别的设备分流处理算一种(落选原因:5G 速度大于家宽上传),Surge 等 app 除了 wireguard 外还支持的 socks 、 ssh 等协议也算一种(落选原因:不想暴露任何 TCP 端口)。家里有一台常开的 N100 低功耗处理器小主机,装好了 Linux 操作系统,当然要充分利用这个资源,顺便还能把该主机上挂载的移动硬盘以 smb 协议共享为 “网盘” 来使用。

由于 Surge 支持 “分离配置” 特性,就算是遇到不能修改的订阅的配置也可以通过 “自定义主配置文件”加载 “订阅配置的某些段落”来实现自由定制某些规则。正是在这种情况下,只要再写一个 wireguard 专用的配置文件,变成 “自定义主配置文件”+“订阅配置”+“wireguard 专用配置” 即可,关键段落如下:

[Proxy]
#!include subscription.conf, wireguard.conf
[WireGuard name]
#!include wireguard.conf
[Rule]
IP-CIDR,10.0.0.1/32,wireguard,no-resolve #内网主机 wireguard 的对端地址
IP-CIDR,192.168.1.0/24,wireguard,no-resolve #内网主机所在的家庭内网 LAN 段,可访问家庭局域网
IP-CIDR,100.64.0.0/10,wireguard,no-resolve #tailscale 段,如果嫌大可以精确到主机/32

Surge 中 wireguard 配置和官方配置没什么差别,section-name 所指定的名字要和主配置、 wireguard 配置中 [WireGuard name]里的 name 相对应;peerallow-ips 的值如需填多个地址段要用双引号包裹,如 allow-ips = "0.0.0.0/0, ::0/0"

由于该内网小主机一开始经考虑被设置为内网设备而非软路由,所以在(有公网 IPv4 地址的)主路由上通过转发规则把公网来的 wireguard 的 UDP 包转发到内网小主机。主机上通过 wg 自带的命令生成公私密钥对,填入 Surge 的 wireguard 配置中,wg-quick up wg0 启动服务后 iPhone 即可访问主机上的服务,连接成功。

2024.3.8 更新方案:通过主路由器端口转发的方式把公网来的 UDP 转发到小主机,更新为直连小主机的 ipv6 地址(在主路由中用 ip6tables 放行对应端口)。使用 ddns 工具同时更新主机的 ipv6 、 ipv4 地址,ipv4 则是主路由器的公网 ipv4 地址并 fallback 到上述端口转发方案。

到这里只实现了 wireguard 的两个对端互连,要让 iPhone 访问内网主机所在的家庭局域网 192.168.1.0/24,除了上文中提到的在 Surge 主配置文件 [Rule]中将指定网段流量导向 wireguard,还要在内网主机上通过 iptables 让内网主机把 wireguard 流量转发到家庭局域网。在网上的很多 wireguard 教程里,内网主机端的 PostUp(也就 wireguard 服务启动后执行的命令)是这样写的:

iptables -A FORWARD -i wg0 -o eth0 -j ACCEPT;
iptables -A FORWARD -i eth0 -o wg0 -j ACCEPT;
iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE;

这三句话可能以不同的形式(网卡名称,地址段等)出现,但实质相同,实现了内网主机 wireguard 网卡 wg0 、物理网卡 eth0 互联互通和 NAT 的规则。如无特殊,PostDown 则是写入相对应的 iptables 删除命令(把-A 换成-D)。重要的是开启 Linux 内核包转发,编辑 /etc/sysctl.conf, 将 net.ipv4.ip_forward 的值从 0  改为 1 。然后 sysctl -p  生效。

在解决了访问内网主机物理局域网段的访问问题后,我想进一步访问内网主机所在的 tailscale 虚拟局域网,实现方法也很简单并可以按照以上步骤如法炮制:把上述 iptables 命令中的物理网卡 eth0 改为 tailscale 的虚拟网卡名 tailscale0 ,再写三句命令追加在 PostUp 的后面,PostDown 也同样追加,重启 wg0 即可生效。最后 systemctl enable wg-quick@wg0wg0 加入开机自启动服务。

最后,幸亏路由器支持 NAT Loopback(又称 NAT hair pinning),也就是 IPv4 的网关会自动识别并修正 “目标写着路由器公网 IP,实际上得往内网去” 的请求,使得以上所有基于 “iPhone 在公网” 的设定到了内网也能正常运作。(如不支持 Loopback 可能需要内网自定义 DNS,使得目标服务器在公网解析出公网 IP,在内网解析出内网 IP)最终结构如下: