借助AI的力量,将 ZYNQ 开发板改造成一个虚拟专用网络网关

注意:规则限制,部分单词存在混淆,本文仅用于阅读,如果要实际复现,可以求助 AI。

一块 ZYNQ 开发板摆在面前,已经很久没有被正式使用过了------没有项目,没有任务,也没有需求。它性能很差,外设很少,似乎没有什么利用价值,但就这样放着吃灰还是太可惜了,我决定给它找点事情做。

一个想法比较现实:把它做成一台网络代理服务器,为局域网内其它设备提供流量中转。但是这一次,相比于自己动手操作,我想尝试一下 AI 的力量。

1. 工具支持

这块板子的管理通道只有一条 USB 转串口线(COM27,115200bps)(其实还有网口,如果SSH也算管理通道的话),所以整个尝试其实是在验证一套新工具链,aka. AI 闭环调试的可能性:

  • DeepSeekV4 Flash 正式版:本次尝试的 AI 模型,承担全部侦察、排错、命令执行与本文撰写;
  • Reasonix:为 DeepSeek 系列模型适配的 Agent 框架,负责把模型能力编排为可执行的工作流;
  • ser2mcp:Reasonix 的 MCP 串口插件,把串口封装成 uart_open / uart_exchange / uart_expect / uart_read / uart_send_file 等十几个工具。AI 通过它直接与硬件对话,加快调试效率。

也就是说,从侦察到部署的每一个环节,都是由这套工具链完成的:AI 负责全部执行,人类只提供方向和关键决策。下面进入正题。

2. 板端环境

板子信息:ARMv7 双核(Zynq)、512MB 内存、基于 initramfs 的 Buildroot 精简系统------根文件系统在内存里,没有包管理器,没有 python,没有 ssh。存储只有一张 32GB 的 TF 卡(vfat,挂载在 /mnt)。

通过网络恢复脚本配置好静态 IP(192.168.8.117/24)之后,第一件事是确认内核能力。通过串口发了一组侦察命令:

bash 复制代码
uname -a; uname -m; free -m; df -h
zcat /proc/config.gz | grep -iE 'CONFIG_(TUN|WIIRE7GUARD|NETFILTER)'
ls /lib/modules/6.12.0-xilinx/kernel/
which iptables nft sshd python wget

结果给所有"常规方案"判了死刑:

检查项 结果 影响
TUN 设备 CONFIG_TUN is not set,无 /dev/net/tun Wiire7Guard、OpenVPN、SoftEther 全部不可用
netfilter CONFIG_NETFILTER is not set iptables/nftables/NAT 不存在,透明代理不可行
内核模块 仅 USB gadget 系列 没有可加载的网络模块
软件环境 busybox(wget 不带 https)、glibc 连下载软件都要想办法

问题一:内核不支持任何隧道与过滤机制,经典网络隧道路线从物理上被堵死。

解法是改变路线:放弃"内核级隧道",改用纯用户态代理网关------在板子上跑一个代理服务,局域网设备把代理指向板子,由板子完成流量转发。这条路线不依赖任何内核特性。

3. 第一次实现:microsocks,以及 OpenWrt 的新 ipk 格式

最初的方案是 microsocks------一个极简的 SOCKS5 服务器。板子虽然是 Buildroot,但可以借用 OpenWrt 24.10.5 官方仓库的 arm_cortex-a9_neon 预编译 ipk,动态库依赖则复用早先 samba 部署过程留下的 musl loader(ld-musl-armhf.so.1)。

问题二:ipk 解包失败。 ar x 报 "invalid ar magic",tar xzf 报不支持 -z。检查文件头才发现,OpenWrt 24.10 的 ipk 格式改成了"gzip 压缩的 tar"(不再是最早的 ar 归档),而板上的 busybox 恰好不支持 tar -z。解法是绕开参数,用管道:

sh 复制代码
gzip -dc microsocks_1.0.5-r2_arm_cortex-a9_neon.ipk | tar xf -

microsocks 跑起来后,PC 通过 curl --socks5 验证,出口 IP 变成了板子的公网 IP------TCP 中转成功。

4. 需求升级:接入订阅节点,并且要支持 UDP

此时需求发生了变化:人类提供了一份网络代理订阅(v22rayN 格式、31 个节点),希望把订阅挂到板子上,让局域网设备通过板子接入这些节点转发流量,而且 TCP/UDP 都要可用 。microsocks 不支持 UDP(没有 SOCKS5 UDP ASSOCIATE),于是换成 xray-core

  • Go 静态编译,armv7 预编译二进制直接运行,零依赖、不碰系统文件;
  • 一个进程同时提供 SOCKS5 入站(含 UDP)、订阅节点出站、路由;
  • 架构变为:局域网设备 → 板子 SOCKS5(:1080) → 订阅节点 → 互联网。

#mermaid-svg-18Lctq2Tb2LSKUrG{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-18Lctq2Tb2LSKUrG .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-18Lctq2Tb2LSKUrG .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-18Lctq2Tb2LSKUrG .error-icon{fill:#552222;}#mermaid-svg-18Lctq2Tb2LSKUrG .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-18Lctq2Tb2LSKUrG .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-18Lctq2Tb2LSKUrG .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-18Lctq2Tb2LSKUrG .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-18Lctq2Tb2LSKUrG .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-18Lctq2Tb2LSKUrG .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-18Lctq2Tb2LSKUrG .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-18Lctq2Tb2LSKUrG .marker{fill:#333333;stroke:#333333;}#mermaid-svg-18Lctq2Tb2LSKUrG .marker.cross{stroke:#333333;}#mermaid-svg-18Lctq2Tb2LSKUrG svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-18Lctq2Tb2LSKUrG p{margin:0;}#mermaid-svg-18Lctq2Tb2LSKUrG .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-18Lctq2Tb2LSKUrG .cluster-label text{fill:#333;}#mermaid-svg-18Lctq2Tb2LSKUrG .cluster-label span{color:#333;}#mermaid-svg-18Lctq2Tb2LSKUrG .cluster-label span p{background-color:transparent;}#mermaid-svg-18Lctq2Tb2LSKUrG .label text,#mermaid-svg-18Lctq2Tb2LSKUrG span{fill:#333;color:#333;}#mermaid-svg-18Lctq2Tb2LSKUrG .node rect,#mermaid-svg-18Lctq2Tb2LSKUrG .node circle,#mermaid-svg-18Lctq2Tb2LSKUrG .node ellipse,#mermaid-svg-18Lctq2Tb2LSKUrG .node polygon,#mermaid-svg-18Lctq2Tb2LSKUrG .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-18Lctq2Tb2LSKUrG .rough-node .label text,#mermaid-svg-18Lctq2Tb2LSKUrG .node .label text,#mermaid-svg-18Lctq2Tb2LSKUrG .image-shape .label,#mermaid-svg-18Lctq2Tb2LSKUrG .icon-shape .label{text-anchor:middle;}#mermaid-svg-18Lctq2Tb2LSKUrG .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-18Lctq2Tb2LSKUrG .rough-node .label,#mermaid-svg-18Lctq2Tb2LSKUrG .node .label,#mermaid-svg-18Lctq2Tb2LSKUrG .image-shape .label,#mermaid-svg-18Lctq2Tb2LSKUrG .icon-shape .label{text-align:center;}#mermaid-svg-18Lctq2Tb2LSKUrG .node.clickable{cursor:pointer;}#mermaid-svg-18Lctq2Tb2LSKUrG .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-18Lctq2Tb2LSKUrG .arrowheadPath{fill:#333333;}#mermaid-svg-18Lctq2Tb2LSKUrG .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-18Lctq2Tb2LSKUrG .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-18Lctq2Tb2LSKUrG .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-18Lctq2Tb2LSKUrG .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-18Lctq2Tb2LSKUrG .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-18Lctq2Tb2LSKUrG .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-18Lctq2Tb2LSKUrG .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-18Lctq2Tb2LSKUrG .cluster text{fill:#333;}#mermaid-svg-18Lctq2Tb2LSKUrG .cluster span{color:#333;}#mermaid-svg-18Lctq2Tb2LSKUrG div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-18Lctq2Tb2LSKUrG .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-18Lctq2Tb2LSKUrG rect.text{fill:none;stroke-width:0;}#mermaid-svg-18Lctq2Tb2LSKUrG .icon-shape,#mermaid-svg-18Lctq2Tb2LSKUrG .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-18Lctq2Tb2LSKUrG .icon-shape p,#mermaid-svg-18Lctq2Tb2LSKUrG .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-18Lctq2Tb2LSKUrG .icon-shape .label rect,#mermaid-svg-18Lctq2Tb2LSKUrG .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-18Lctq2Tb2LSKUrG .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-18Lctq2Tb2LSKUrG .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-18Lctq2Tb2LSKUrG :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 板子 /mnt/vpn
局域网
SOCKS5 :1080
手机/PC
xray-core
代理节点 outbound
direct
远端节点
互联网

但把 35MB 的二进制弄到板子上,本身就是一个问题。

5. 传输难题:板子没有 https,PC 被防火墙挡

问题三:busybox wget 不支持 https,GitHub 上的 xray 下载不了;从 PC 起 http 服务让板子来拉,又被 Windows 防火墙拦在门外;走串口传 35MB,按 115200bps 计算需要约 40 分钟。

解法是给板子装一个 sshd:从 OpenWrt 官方仓库(http)拉取 dropbear ipk,用同一个 musl loader 运行,公钥认证后,PC 用 ssh root@板子 "cat > 文件" < 本地文件 管道方式传输。35MB 几分钟传完,MD5 校验一致。这个"顺手"部署的 dropbear 后来成了整个调试过程的传输生命线。

6. 订阅解析:三个隐蔽的 bug

订阅是 base64 包裹的 31 条 vless:// 链接。AI 写了一个转换脚本(convert_sub.py),把订阅解析成 xray 的 outbounds 配置。这个过程被三个 bug 依次教做人:

问题四:URL 的 # fragment 污染了 query 参数。 vless://uuid@host:port?type=ws&host=www.example.com#节点名 这类链接中,# 后面的节点名被拼进了 Host 参数,导致握手全部失败。解法:解析 query 前先 split('#')

问题五:xray v26 强制 vless 用户显式声明 "encryption": "none" 不写的话直接启动失败,报错信息很明确,补上字段即可。这是新版本协议校验收紧的结果。

问题六:PC 防火墙拦截了 xray 的出站。 为快速选点,AI 一度在 PC 本地起 xray 批量测试节点,结果全部超时,而 Python 直连节点端口却正常------排查后确认是 Windows 防火墙拦了 xray.exe 的出站。解法不是去改防火墙(需要管理员权限),而是把测试全部搬到板端:板端没有防火墙,一切顺利。

7. UDP:薛定谔的节点

TCP 很快全绿:节点逐个验证,目标站点返回 200。UDP 却是另一回事------同一份订阅里,有的节点 UDP 转发超时,换一条节点立刻通了。这是订阅服务商的能力差异,与板子无关。最终默认节点确定为 Akari Networks 线路,验证链路如下:
上游 DNS 订阅节点 板端 xray 局域网客户端 上游 DNS 订阅节点 板端 xray 局域网客户端 #mermaid-svg-igyvjRObpjiQ98Iw{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-igyvjRObpjiQ98Iw .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-igyvjRObpjiQ98Iw .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-igyvjRObpjiQ98Iw .error-icon{fill:#552222;}#mermaid-svg-igyvjRObpjiQ98Iw .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-igyvjRObpjiQ98Iw .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-igyvjRObpjiQ98Iw .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-igyvjRObpjiQ98Iw .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-igyvjRObpjiQ98Iw .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-igyvjRObpjiQ98Iw .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-igyvjRObpjiQ98Iw .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-igyvjRObpjiQ98Iw .marker{fill:#333333;stroke:#333333;}#mermaid-svg-igyvjRObpjiQ98Iw .marker.cross{stroke:#333333;}#mermaid-svg-igyvjRObpjiQ98Iw svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-igyvjRObpjiQ98Iw p{margin:0;}#mermaid-svg-igyvjRObpjiQ98Iw .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-igyvjRObpjiQ98Iw text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-igyvjRObpjiQ98Iw .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-igyvjRObpjiQ98Iw .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-igyvjRObpjiQ98Iw .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-igyvjRObpjiQ98Iw .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-igyvjRObpjiQ98Iw #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-igyvjRObpjiQ98Iw .sequenceNumber{fill:white;}#mermaid-svg-igyvjRObpjiQ98Iw #sequencenumber{fill:#333;}#mermaid-svg-igyvjRObpjiQ98Iw #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-igyvjRObpjiQ98Iw .messageText{fill:#333;stroke:none;}#mermaid-svg-igyvjRObpjiQ98Iw .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-igyvjRObpjiQ98Iw .labelText,#mermaid-svg-igyvjRObpjiQ98Iw .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-igyvjRObpjiQ98Iw .loopText,#mermaid-svg-igyvjRObpjiQ98Iw .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-igyvjRObpjiQ98Iw .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-igyvjRObpjiQ98Iw .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-igyvjRObpjiQ98Iw .noteText,#mermaid-svg-igyvjRObpjiQ98Iw .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-igyvjRObpjiQ98Iw .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-igyvjRObpjiQ98Iw .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-igyvjRObpjiQ98Iw .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-igyvjRObpjiQ98Iw .actorPopupMenu{position:absolute;}#mermaid-svg-igyvjRObpjiQ98Iw .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-igyvjRObpjiQ98Iw .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-igyvjRObpjiQ98Iw .actor-man circle,#mermaid-svg-igyvjRObpjiQ98Iw line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-igyvjRObpjiQ98Iw :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} SOCKS5 UDP ASSOCIATE UDP over VLESS/WS DNS query (53/UDP) DNS response relay back UDP reply

最终验证结果:

  • TCP:curl --socks5-hostname ...:1080 https://www.example.com → 200
  • UDP:SOCKS5 UDP ASSOCIATE + DNS 查询 → 收到响应
  • 出口:板子通过订阅节点转发流量,出口 IP 为节点 IP

8. 部署脚本的收尾:两个小坑

成果物要交付给人类使用,就必须处理板子的"个性":

问题七:板端没有 pkill busybox 编译时没给 pkill 建符号链接,pkill -f 'xray run' 一直静默失败,导致多次调试中 xray 进程残留、端口被多个实例共享监听(内核 SO_REUSEPORT 还会把请求随机分发到旧实例,造成出口 IP 漂移的假象)。排查后发现进程全部存活、端口多重监听,最终把脚本里的进程管理改成通用的 kill $(ps w | grep ... | awk '{print $1}') 列表方式。

问题八:busybox tar 不支持 -z 使用手册中的解压命令必须是 gzip -dc 包.tar.gz | tar xf -,而不是 tar xzf

9. 成果共享

整个尝试沉淀为一个可直接复用的部署包 zynq_vpn_artifacts.tar.gz(约 20MB),结构如下:

复制代码
zynq_vpn/
├── xray/            # xray-core 二进制 + geo 库
├── start-vpn.sh     # 启停/状态/切节点(相对路径,任意目录可用)
├── net-up.sh        # 恢复静态 IP + DNS(参数化)
├── setup.sh         # 部署检查 + 可选写 DNS
├── config.sample.json
├── tools/convert_sub.py   # PC 端:订阅链接 → config.json(随机密码)
└── README.md        # 使用手册

如果你手头有同样架构的板子(ARMv7 Linux,内核有没有 TUN 都无所谓),三步即可用起来:

sh 复制代码
# 1) PC 端生成配置(需 Python3)
python convert_sub.py <你的订阅链接> -o config.json --pass <自设密码>

# 2) 板端解压部署
gzip -dc zynq_vpn_artifacts.tar.gz | tar xf -
cd zynq_vpn && sh net-up.sh <板子IP> <网关IP> && sh setup.sh --dns 223.5.5.5

# 3) 上传 config.json 到 xray/ 目录后启动
sh start-vpn.sh start        # 切节点: sh start-vpn.sh node <N>

下载链接:百度网盘

包内不包含任何订阅凭据------订阅链接、节点地址、uuid 均需自行生成,convert_sub.py 默认生成随机代理密码。

10. 一些体会

这次尝试中,真正花时间的不是"敲命令",而是判断:内核不支持隧道,是硬改内核还是换路线?订阅节点不通,是配置问题还是节点问题?UDP 超时,是板子的问题还是服务商的问题?这些问题每一个都可能把方向带偏,而工具链的价值在于让"尝试-验证"的循环足够快------一条命令、一个锚点等待、一个出口 IP 对比,几秒钟就能排除一个假设。

如果你也有一块吃灰的板子和一个 COM 口,ser2mcp 这类工具值得一试:串口不再是"人的终端",而是 AI 可以反复、精确、低摩擦操作的外设。


声明:本文由 DeepSeekV4 Flash 编写,包括上述所有命令的执行、问题的排查与方案的验证。文中订阅链接、节点地址等私人信息均已隐去。

相关推荐
sunneo1 小时前
每周精选GitCode开源项目
人工智能
sinovoip1 小时前
香蕉派BPI-M7S开源单板计算机采用瑞芯微RK3588s芯片设计,与树莓派产品尺寸一样
人工智能·开源·业界资讯
数据百晓通1 小时前
2026 智能体重构数据治理:全链路 AI、云生态、场景嵌入赛道解析
大数据·运维·人工智能
特立独行的猫a1 小时前
小鸿 AI新玩法:面向 AI Agent 的通用语音交互硬件技术方案
人工智能·atomgit·小鸿ai·贾维斯
Elivs1 小时前
RMSNorm函数
人工智能·算法·机器学习
2401_832298101 小时前
AI安全与全球治理:构建可控可信的智能发展新秩序
人工智能
Akir.weiwen1 小时前
跨层禁止:机器如何拦截非法语义绑定
人工智能·设计规范·语义
xiakq2 小时前
2026 年八大 LLM API 横评:DeepSeek V4 vs GPT-4o vs Claude vs Gemini
人工智能·gpt·ai·claude
u0103055272 小时前
Java图像处理实战指南
人工智能·1024程序员节