N1 盒子刷 Armbian 配置为软路由 & AP 方案记录

 

每一场泡沫破碎的背后, 是一茬韭菜的哭泣, 更是一群垃圾佬的狂欢~(大雾)

n1 盒子已经成了过气产物了. 但由于上次 Orange Pi 没修好, 现在树莓派又价格飞涨, arm64 的 n1 好像成了不错的替代品.(也就少了个 GPIO.)

(其实当时就应该买 n1 而不要买 Orange Pi, 但当年年少无知… 所以现在来弥补一下缺憾.)

虽说 s905 已经比不上现在最新的外贸盒子的 s905x3, 但是现在 n1 盒子的价格也和热度一起下来了, 超过 2 倍接近 3 倍的价格差异还是存在的. 所以还是选择小黄鱼 90r 入手一台全新未刮 K 码的 n1.

除了 USB 2.0, 其他方面都可谓是一个完美的玩具.

这次选择了一种新的折腾方式, 由于它有 2G 内存, 挺多的, 打算将其刷入 Armbian 后运行 Docker Openwrt. 兼作服务器和软路由使用. 在能够使用最新的 Linux 内核的同时也能运行一个纯净的 Openwrt, 作为宿舍中的软路由使用不错.(因为 5G 覆盖范围小…速度也不快.)

由于网上现有的关于 n1 的资料很多过时或不准确, 所以在此重新整理过一遍. 因为是事后写的博客所以部分步骤忘了截图, 抱歉.

0x00 降级原有系统

使用 HDMI 将斐讯 n1 连接到显示器.(但其实我使用 USB 采集卡, 更方便.)

同时连接鼠标. 上电, 直接开机. 用鼠标操作连接 Wi-Fi.

接着连续点击固件版本四次, 出现 打开 adb 的提示.

cmd 中输入 adb connect x.x.x.x, 其中 x.x.x.x 是 n1 的 IP 地址.

接着输入 adb shell reboot fastboot, 盒子应该会重启.

使用双头 USB 线连接电脑 USB 口和盒子上靠近 HDMI 的 USB 接口.

iPlay30 安装 fastboot 驱动类似的, 可以通过 Windows Update 自动安装 fastboot 驱动.

接下来需要刷入旧版的支持 USB 启动的 boot, bootloader, recovery.

1
2
3
fastboot flash bootloader N1bootloader.img
fastboot flash boot N1boot.img
fastboot flash recovery N1recovery.img

所需的三个文件点此下载.

刷完后直接 fastboot reboot, 应该会重新进入安卓系统(此时版本号没变正常, 但引导已经降级了).

0x01 制作 Linux 引导盘

你可以下载 @150balbes 编译的最新镜像: https://disk.yandex.com/d/srrtn6kpnsKz2/RK_AML_AW.

我选择的是 Debian 的无 GUI 版本, 下载下来无需解压, 可直接使用 balenaEtcher 将镜像写入 U 盘.

由于这个镜像是多个设备通用的, 需要修改一些 boot 中的文件才能启动.

U 盘写入完成后, Windows 应该能自动读取到 boot 分区.

打开 extlinux 下的 extlinux.conf 文件, 注释掉原本 rk-3399 下的 FDT 和 APPEND 两句, 取消注释结尾 aml s9xxx 下的 APPEND 一句, 并在末尾添加 FDT /dtb/amlogic/meson-gxl-s905d-phicomm-n1.dtb .

如果你怕改错, 也可以选择用以下内容替换 extlinux.conf 中所有内容.(主要是指定 dtb 文件.)

1
2
3
4
5
6
LABEL Armbian
LINUX /zImage
INITRD /uInitrd

FDT /dtb/amlogic/meson-gxl-s905d-phicomm-n1.dtb
APPEND root=LABEL=ROOTFS rootflags=data=writeback rw console=ttyAML0,115200n8 console=tty0 no_console_suspend consoleblank=0 fsck.fix=yes fsck.repair=yes net.ifnames=0

将 boot 分区下的 u-boot-s905x-s912 文件重命名为 u-boot.ext.(n1 的 SoC 是 s905d, 所以使用 s905x 的 u-boot.)

向 boot 分区中添加 create-mbr-linux.sh 文件. 写入以下内容.(准备创建 mbr 用的脚本)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#!/bin/sh
echo "Start script create MBR and filesystem"
DEV_EMMC=/dev/mmcblk1
echo "Start backup u-boot default"
dd if="${DEV_EMMC}" of=/boot/u-boot-default.img bs=1M count=4
echo "Start create MBR and partittion"
parted -s "${DEV_EMMC}" mklabel msdos
parted -s "${DEV_EMMC}" mkpart primary fat32 700M 828M
parted -s "${DEV_EMMC}" mkpart primary ext4 829M 100%
echo "Start restore u-boot"
dd if=/boot/u-boot-default.img of="${DEV_EMMC}" conv=fsync bs=1 count=442
dd if=/boot/u-boot-default.img of="${DEV_EMMC}" conv=fsync bs=512 skip=1 seek=1
sync
echo "Done"
exit 0

启动盘准备至此完成.

0x02 引导进入 Linux 并写入 emmc

进入安卓后, 使用 adb connect x.x.x.x && adb reboot update 重启进入引导模式.

在输入命令后快速插入 U 盘到 HDMI 旁边的 USB 接口, 系统将从 U 盘引导启动. 不要在安卓重启之前/运行时插入 U 盘, 会导致 ext4 权限混乱.

如果启动进入 recovery, 则代表没有读取到 U盘, 可以断电开机后重复 adb 指令进入引导过程.

启动 Linux 后执行一些必要设置后, 以 root 登入.

依次执行 /boot/create-mbr-linux.shinstall-aml.sh 两个文件.

稍等片刻, 如果执行过程没有出错, 就可以断电并拔掉 U 盘, 再次重启进入 emmc 中的 Linux 系统.

p.s.: 此处由于 n1 默认的引导方式很奇怪, 是没有 mbr 分区表的, 所以有可能导致直接运行安装脚本失败. 所以先要使用 create-mbr-linux.sh 的脚本创建一个分区表再安装.

0x03 修复 Linux 高平均负载 BUG

运行 dtc -I dtb -O dts -o n1.dts /boot/dtb/amlogic/meson-gxl-s905d-phicomm-n1.dtb 反编译 dtb 文件.

使用 vim 修改 n1.dts 文件.

注释掉 interrupt-controller@9880 下面的 phandle = < 0x21 >;

1
2
3
4
5
6
7
8
9
10
interrupt-controller@9880 {
compatible = "amlogic,meson-gpio-intc\0amlogic,meson-gxl-gpio-intc";
reg = < 0x00 0x9880 0x00 0x10 >;
interrupt-controller;
#interrupt-cells = < 0x02 >;
amlogic,channel-interrupts = < 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 >;
status = "okay";
<!-- 注释掉下面这行 -->
#phandle = < 0x21 >;
};

之后重新编译覆盖重启, 即可解决问题.

1
2
3
4
dtc -I dts -O dtb -o n1.dtb n1.dts
sudo cp /boot/dtb/amlogic/meson-gxl-s905d-phicomm-n1.dtb /boot/dtb/amlogic/meson-gxl-s905d-phicomm-n1.dtb.bak
sudo cp n1.dtb /boot/dtb/amlogic/meson-gxl-s905d-phicomm-n1.dtb
sudo reboot

0x04 安装 Docker 并换源

不赘述, 恩山也有教程: https://www.right.com.cn/forum/forum.php?mod=viewthread&tid=430903.

0x05 启动无线热点

输入 sudo armbian-config 选择 Network - Hotspot. 等待相关包安装完成后退出.

编辑 /etc/default/hostapd 文件. 取消注释 DAEMON_CONF="/etc/hostapd.conf" 这一行.

执行 sudo systemctl enable hostapd 确定开机时 hostapd 会自动启动.

用下面的内容替换原本的 /etc/hostapd.conf 文件. (默认为 5G 频段, 修改 hw_mode 和 channel 可转为 2.4G 频段.)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# Wi-Fi 名字
ssid=Armbian_N1
interface=wlan0
# a for Wi-Fi 5G, g for Wi-Fi 2.4G
hw_mode=a
channel=44
driver=nl80211

logger_syslog=0
logger_syslog_level=0
wmm_enabled=1
wpa=2
preamble=1

# Wi-Fi 密码
wpa_passphrase=n1wifipassword
wpa_key_mgmt=WPA-PSK
wpa_pairwise=TKIP
rsn_pairwise=CCMP
auth_algs=1
macaddr_acl=0
country_code=CN

## IEEE 802.11n (就算不用 2.4G Wi-Fi 也不要注释掉!)
ieee80211n=1
ht_capab=[HT40+][SHORT-GI-20][SHORT-GI-40][DSSS_CCK-40]
#ieee80211d=1
## IEEE 802.11n

### IEEE 802.11ac
ieee80211ac=1
vht_capab=[MAX-MPDU-3895][SHORT-GI-80][SU-BEAMFORMEE]
vht_oper_chwidth=1
vht_oper_centr_freq_seg0_idx=42
### IEEE 802.11ac

# controlling enabled
ctrl_interface=/var/run/hostapd
ctrl_interface_group=0

再编辑 /etc/network/interfaces 设置 iface wlan0 inet manual

输入 sudo systemctl disable NetworkManager 禁用 Debian 自带的网络管理.

sudo reboot 重启设备后, 发现手机可以搜索到 Wi-Fi. 加入时会卡在获取 IP 地址的地方, 但可以通过静态地址的方式连接. 代表热点设置正常.

(p.s. 如果热点出现异常, 可以通过运行 sudo hostapd -d /etc/hostapd.conf 来手动尝试启动热点查看错误信息. 也可以通过 ps -ef | grep hostapd 查看 hostapd 是否正常运行.)

(p.s.s. 发现一个很神奇的问题, 如果不设置 IEEE 802.11n 中的 ht_capab=[HT40+], 则无法启动 Wi-Fi 5G 80MHz 频段, 会报错 Could not set channel for kernel driver 之后退出. 查询 hostapd 相关文档也暂时未发现其原因. 只不过现在的配置已经可以正常启动 5G 80MHz Wi-Fi (433 Mbps).)

0x06 运行基于 Docker 的 OpenWRT

执行 sudo docker import https://downloads.openwrt.org/releases/21.02.0/targets/armvirt/64/openwrt-21.02.0-armvirt-64-default-rootfs.tar.gz openwrt:21.02.0 导入官方的 OpenWRT Docker 镜像.

打开网卡 eth0 的混杂模式, 用于给主机的单个网卡分配多个 MAC 地址. sudo ip link set eth0 promisc on

接下来是设置 OpenWRT 和主机的网络.

先摘取一段 Docker Docs 上对 macvlan 的描述:

Some applications, especially legacy applications or applications which monitor network traffic, expect to be directly connected to the physical network. In this type of situation, you can use the macvlan network driver to assign a MAC address to each container’s virtual network interface, making it appear to be a physical network interface directly connected to the physical network. In this case, you need to designate a physical interface on your Docker host to use for the macvlan, as well as the subnet and gateway of the macvlan. You can even isolate your macvlan networks using different physical network interfaces.

再摘取一段 Docker Docs 上对于 bridge 的描述:

In terms of Docker, a bridge network uses a software bridge which allows containers connected to the same bridge network to communicate, while providing isolation from containers which are not connected to that bridge network. The Docker bridge driver automatically installs rules in the host machine so that containers on different bridge networks cannot communicate directly with each other.

我采用的方法是通过 macvlan 将 Armbian 主机上的 eth0 网卡传递给 OpenWRT 使用, OpenWRT 将 eth0 作为 wan, 从上级路由通过 dhcp 的方法获得 ip 地址. 同时创建一个 bridge LAN, 打通 OpenWRT 中的 LAN 和 Armbian 中的 LAN.

  1. 创建 bridge-lan 接口.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    vim /etc/network/interfaces.d/bridge

    # 写入以下内容, 此例中 OpenWRT 地址为 10.10.10.1, Armbian 地址为 10.10.10.2
    auto br-lan
    iface br-lan inet static
    address 10.10.10.2
    netmask 255.255.255.0
    dns-nameserver 10.10.10.1
    gateway 10.168.10.1
    bridge_ports wlan0
  2. 修改 hostapd 配置, 取消注释 bridge=br-lan 一行

  3. 创建 Docker 网络.

1
2
3
4
5
6
7
8
9
10
11
12
# 创建 LAN 网络 lanet
docker network create -d bridge --subnet 10.10.10.0/24 --gateway=10.10.10.1 -o "com.docker.network.bridge.name=br-lan" lanet

# 创建 WAN 网络 wanet
docker network create -d macvlan --subnet=192.168.1.0/24 --gateway=192.168.1.1 -o parent=eth0 wanet

# 启动 Docker 容器
docker run -d --name op --privileged openwrt:21.02.0 /sbin/init

# 连接 WAN 和 LAN
docker network connect wanet op
docker network connect lanet op

0x06 直接在 Armbian 上设置 NAT 并安装 DHCP 服务器, 实现路由器功能

本来的设想是把盒子做成一个常见的路由器一样, 接入网线之后自动通过 DHCP 从上级路由获取 IP 地址, 或者 PPPoE 拨号上网. 然后再给连接的设备分配内网 ip 地址.

可能是我自己对 docker 的网络配置理解的也还不是很透彻, 我发现在配置 macvlan 的时候, 必须要配置上级路由的网段和网关.(我觉得应该是 Docker 需要使用这些信息设置系统防火墙和路由表, 而 Docker 又不能直接从 DHCP 获取相关信息, 所以无解. 这是我的猜测, 不知道实际上是不是这样.) 当然也可能是我没有找到正确的配置方法. 但无论如何, 这和从 DHCP 服务器获取相关信息的本意不符.

故更换方案, 不用 OpenWRT. 直接设置 Armbian 完成软路由的相关功能.

  1. 安装 DHCP 服务器 dnsmasq, 并设置 dnsmasq 为开机启动

    sudo apt-get install dnsmasq

    sudo systemctl enable dnsmasq

  2. 设置 wlan0 接口

    1
    2
    3
    4
    5
    6
    7
    8
    sudo vim /etc/network/interfaces  # 编辑网络接口

    # 将 wlan0 相关的设置改为以下内容
    allow-hotplug wlan0
    iface wlan0 inet static

    address 10.0.0.1
    netmask 255.255.255.0
  3. 编辑 dnsmasq 配置文件

    1
    2
    3
    4
    5
    6
    sudo vim /etc/dnsmasq.conf  # 编辑配置文件

    # 写入以下内容
    interface=wlan0
    dhcp-range=10.0.0.2,10.0.0.100,12h
    dhcp-option=6,10.0.0.1

    意为在 wlan0 这个接口上提供服务, 地址池为 10.0.0.2 - 10.0.0.100, 租期 12 小时, 网关为 10.0.0.1

  4. 永久允许内核转发, 编辑/etc/sysctl.conf 文件, 加入下面一行.

    net.ipv4.ip_forward=1

  5. 设置 iptables 地址转换(NAT) 和允许转发, 需要添加到开机启动项

    1
    2
    3
    4
    5
    6
    7
    sudo vim /etc/rc.local  # 编辑开机启动文件

    # 在 exit 0 前添加下面几行, 依次用于配置 NAT, 传入连接和传出连接
    iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
    # 只有对方响应的连接才会被接受, eth0 不能向 wlan0 主动发送请求
    iptables -A FORWARD -i eth0 -o wlan0 -m state --state RELATED,ESTABLISHED -j ACCEPT
    iptables -A FORWARD -i wlan0 -o eth0 -j ACCEPT
  6. 重启设备, 连接 n1 发出的 Wi-Fi, 此时应该已经可以正常上网了.

0x07 配置 ipv6 地址(桥接模式)

在高校使用 ipv6 连接互联网是无需登录且免费的, 所以配置一下 ipv6 桥接.

(但事实上我选择了 0x07.1 中的方案)

  1. 让 Armbian 在 eth0 上获取 ipv6 地址

    理论上 Debian 应该会自动获取 ipv6 global 地址, 可以通过 ifconfig 查看, 如果没有可以尝试在 /etc/network/interfaces 下 eth0 的配置中添加一行iface eth0 inet6 auto

    但由于南大的教育网实在是过于奇葩, 导致 Armbian 不能获取到 ipv6 地址. 我采用的 workaround 的是强行手动设置 ipv6 地址.

    1
    2
    3
    4
    sudo ifconfig eth0 inet6 add 2001:250:5002:8000::2:d666/64
    # ping 所有路由器的多播地址, 获取的地址用于设置网关
    ping6 ff02::2%eth0
    sudo route -A inet6 add default gw fe80::1251:72ff:fe1b:249f dev eth0
  2. 参考 http://www.dohooe.com/2017/02/26/455.html 中完成设置.

0x07.1 配置 ipv6 代理免费上网

虽然高校的 ipv6 地址可以免费上网, 但实际上现在很多网站都还不支持 ipv6 地址.

所以我选择使用 ipv6 代理 ipv4 地址的方法来配置网络, 这样的好处有两个:

  1. 可以从南大内网通过代理直接访问到我家里的内网资源
  2. 可以免费访问所有的 ipv4 及 ipv6 网站.

本来打算是用 SSH Tunnel 完成功能, 但是 SSH 隧道的性能好像比较差, 连接也不稳定, 而且不支持透明代理(比如远程桌面就不能走 socks5 代理).

所以转为使用常见的魔法工具 v2Ray.

  1. 准备一台有 ipv4 和 ipv6 地址的服务器.(如果你没有, 还是推荐使用上面的 ipv6 桥接.)

    运行代理服务器. 参考配置文件如下. 注意其中的 listen: “[::]” 表明监听 ipv6 地址.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    {
    "inbounds": [{
    "port": 9000,
    "listen": "[::]",
    "protocol": "vmess",
    "settings": {
    "clients": [
    {
    "id": "c95f3ab6-62c2-4426-8027-7833c7ba2e86",
    "level": 1,
    "alterId": 0
    }
    ]
    }
    }],
    "outbounds": [{
    "protocol": "freedom",
    "settings": {}
    }]
    }

    具体的搭建过程不再赘述.

  2. 在 Armbian 机器上运行代理客户端. sudo apt install v2ray

    写出我的配置文件作为参考

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    {
    "inbounds":[
    // 以下的这个 inbound 是为了我的手机, 平板可以直接通过内网连接到服务器使用的(中转). 不需要的可以删去.
    {
    "port": 8503,
    "listen": "172.26.73.226",
    "protocol": "vmess",
    "settings": {
    "clients": [{
    "id": "c95f3ab6-62c2-4426-8027-7833c7ba2e86",
    "level": 1,
    "alterId": 0
    }]
    }
    },
    {
    "port":12315,
    "protocol":"dokodemo-door",
    "settings":{
    "network":"tcp,udp",
    "followRedirect":true
    },
    "sniffing":{
    "enabled":true,
    "destOverride":[
    "http",
    "tls"
    ]
    }
    }
    ],
    "outbounds":[
    // outbounds 中的第一次为默认代理
    {
    "tag":"proxy",
    "protocol":"vmess",
    "settings":{
    "vnext":[
    {
    // 以下四个变量是服务器相关配置, 记得更改!
    "address":"ipv6.xxxxx.com",
    "port":9000,
    "users":[
    {
    "id":"c95f3ab6-62c2-4426-8027-7833c7ba2e86",
    "alterId":0
    }
    ]
    }
    ]
    }
    },
    {
    "protocol": "freedom",
    "settings": {},
    "tag": "direct"
    }
    ],
    "routing":{
    "domainStrategy":"IPOnDemand",
    "rules":[
    // 学校的 172 网段内网不走代理
    // Armbian 的 10 网段内网不走代理
    // 其余一律代理
    {
    "type":"field",
    "outboundTag":"direct",
    "ip":[
    "10.0.0.0/8",
    "172.0.0.0/8"
    ]
    }
    ]
    }
    }

    配置完成后运行 sudo systemctl enable v2ray && sudo systemctl start v2ray 启动.

  3. 配置网关. 在 /etc/rc.local 文件中的 exit 0 前添加下面几行

    1
    2
    3
    4
    5
    iptables -t nat -N V2RAY
    # 只允许内网使用透明代理
    iptables -t nat -A V2RAY -p tcp -s 10.0.0.0/24 -j REDIRECT --to-ports 12315
    iptables -t nat -A V2RAY -p udp -s 10.0.0.0/24 -j REDIRECT --to-ports 12315
    iptables -t nat -A PREROUTING -p all -j V2RAY
  4. 重启. 连接到 Armbian 发出的 Wi-Fi, 无需登录即可上网.

0x08 大功告成!

可以在大学同时拥有一台用来折腾的服务器和获得像在家一样的网络环境啦. :P

附 0x00 Armbian 蓝牙驱动问题

@150balbes 编译的最新镜像默认情况下蓝牙无法驱动, 需要替换 dtb 文件.

所需的 dtb 文件: https://www.right.com.cn/forum/forum.php?mod=viewthread&tid=4057309

启动蓝牙方法: https://www.right.com.cn/forum/thread-517710-1-1.html

这里也给出 dtb 文件的下载链接: https://pan.lyc8503.net/Public/%E5%9B%BA%E4%BB%B6/n1/meson-gxl-s905d-phicomm-n1.dtb

如果需要启动蓝牙直接下载并覆盖 /boot/dtb/amlogic/meson-gxl-s905d-phicomm-n1.dtb 即可.(注意备份!)

亲测替换后蓝牙可以正常运行, Armbian 运行状态完美.

本文采用 CC BY-NC-SA 4.0 许可协议发布.

作者: lyc8503, 文章链接: https://blog.lyc8503.net/post/phicomm-n1/
如果本文给你带来了帮助或让你觉得有趣, 可以考虑赞助我¬_¬