把 IFU 接进现有系统
1. 集成方式总览
| 方式 | 传输 | 默认监听 | 特点 |
|---|---|---|---|
| HTTP | TCP | 0.0.0.0:42101 |
POST / 下发命令;GET /health、GET /capabilities 查询;/admin/* 管理;/console/ 本机控制台 |
| TCP | TCP | 0.0.0.0:42102 |
每行一条 JSON 命令(NDJSON),长连接 |
| UDP | UDP | 0.0.0.0:42103 |
单包一条 JSON 命令;同时承载设备发现协议 |
三种传输共用同一命令契约:同一命令在任一传输上的参数校验、MAC 守卫、响应结构完全一致。
2. 接口清单
| 接口 / 命令 | 协议 | 方法 | 鉴权 | 用途 |
|---|---|---|---|---|
/health |
HTTP | GET | 免认证 | 健康检查 |
/capabilities |
HTTP | GET | 免认证 | 能力清单 |
/ |
HTTP | POST | 见第 3 节 | 下发命令 |
/console/ |
HTTP | GET | 页面免认证 | 本机 Web 控制台(go:embed 内嵌静态资源,与 42101 共用端口、不新增进程;页内管理请求各自鉴权) |
/admin/status |
HTTP | GET | 需认证 | 内核运行状态汇总(版本、运行时长、插件就绪比、能力可用比、注册命令数、三端口、认证方式) |
/admin/commands |
HTTP | GET | 需认证 | 命令清单(由插件 manifest 派生,含命令作用 desc 与用法 usage、参数与结果 schema,供控制台渲染「功能测试」表单并动态说明命令) |
/admin/plugins |
HTTP | GET | 需认证 | 插件清单 |
/admin/plugins/start |
HTTP | POST | 需认证 | 启动插件(?id=) |
/admin/plugins/stop |
HTTP | POST | 需认证 | 停止插件(?id=) |
/admin/plugins/enable |
HTTP | POST | 需认证 | 持久启用插件(?id=) |
/admin/plugins/disable |
HTTP | POST | 需认证 | 持久禁用插件(?id=) |
/admin/plugins/install |
HTTP | POST | 需认证 | 上传安装插件(报文体为插件包) |
/admin/plugins/remove |
HTTP | POST | 需认证 | 卸载插件(?id=) |
/admin/reload |
HTTP | POST | 需认证 | 重新扫描加载插件目录 |
/admin/doctor |
HTTP | GET | 需认证 | 触发指定插件能力探测(?id=) |
/blob/{id} |
HTTP | GET | 需认证 | 下载插件上报的大对象(截图 / 文件内容 / 日志导出),内容流式返回;id 不合法 → 400,不存在 / 过期 / 未收齐 → 404 |
| 命令接口 | TCP / UDP | - | 见第 3 节 | 与 HTTP POST / 同一契约 |
3. 认证
按顺序判定,命中即放行:
| 顺序 | 凭据 | 适用范围 |
|---|---|---|
| 1 | mTLS 客户端证书 | 需 TLS 的 HTTP / TCP |
| 2 | 应用层 HMAC 签名 | HTTP / TCP / UDP 三层通用 |
| 3 | 访问令牌 | HTTP 用请求头 X-Auth-Token;TCP / UDP 用报文字段 token |
| 4 | 回环免认证 | 仅命令端点;管理端点(/admin/*)不适用 |
- 令牌首次启动自动生成,写入配置文件
auth.token。 - 回环来源(
127.0.0.1/::1)免认证,但叠加 Origin / Referer / Host 校验;高危命令(power.*、screen.*、input.*、clipboard.*、process.kill、timesync.set、notify.toast)即使来自回环也强制认证。内核会把内置默认清单与config.json的auth.high_risk_commands做并集合并,因此覆盖安装后新增的高危命令自动生效、无需手改配置;可在配置里追加自定义项,但不能靠删配置项缩小保护范围。 - 管理端点(
/admin/*)无论来源一律要求令牌或证书,不接受回环免认证——否则任意网页都能借浏览器发起跨站请求来操作插件。 - 免认证端点:
GET /health、GET /capabilities;/console/页面本身为静态资源不鉴权,页内每个管理请求仍需令牌。
HMAC 签名三字段:sig(HMAC-SHA256,base64url 无填充)、ts(Unix 秒)、nonce(16 字节 base64url,同窗口内不重复)。
待签字符串:
FOXAGENT-HMAC-V1
其中 canonicalBody 是报文剔除 sig/ts/nonce 后重新序列化的结果;scope 命令请求为命令名,管理端点为「方法 + 空格 + 完整请求目标(含查询串)」。
4. 请求参数
所有命令均为扁平 JSON,核心字段:
| 字段 | 类型 | 必选 | 说明 |
|---|---|---|---|
cmd |
string | ✅ | 命令名 |
mac |
string | ✅ | 目标 MAC;all 表示广播。支持 aa:bb:cc:dd:ee:ff / aa-bb-.. / aabb.. / all |
token |
string | 非回环 | 访问令牌(HTTP 走请求头,此处可省) |
value |
int | 按命令 | 音量 0–100 |
mode |
string | 按命令 | 枚举模式:sleep/hibernate;on/off/toggle |
text |
string | 按命令 | 键盘输入 / 剪贴板内容 |
key / mods |
string / []string | 按命令 | 按键名;修饰键 ctrl/shift/alt/win |
x / y |
int | 按命令 | 鼠标屏幕坐标 |
button |
string | 按命令 | left/right/middle(默认 left) |
scroll |
int | 按命令 | 滚轮格数(正=上滚) |
传输细节:HTTP POST /,Content-Type: application/json,上限 4KB;TCP 每行一条 JSON 以
结尾,单行上限 4KB;UDP 单包上限 2048 字节。
5. 命令表
| 插件 | 能力 | 命令 | 参数 | 响应 data |
|---|---|---|---|---|
fox.power |
power |
power.off |
mac,delay,message |
- |
fox.power |
power |
power.reboot |
mac,delay,message |
- |
fox.power |
power |
power.abort |
mac |
{"aborted":true} |
fox.power |
power |
power.uptime |
mac |
{"seconds":123456,"boot_time":" |
fox.power |
power |
power.suspend |
mac,mode |
- |
fox.volume |
volume |
volume.get |
mac |
{"volume":50,"muted":false} |
fox.volume |
volume |
volume.set |
mac,value |
- |
fox.volume |
volume |
volume.mute |
mac,mode |
{"muted":true} |
fox.volume |
volume |
volume.up |
mac,step |
{"volume":55} |
fox.volume |
volume |
volume.down |
mac,step |
{"volume":45} |
fox.screen |
screen |
screen.off / screen.on / screen.lock |
mac |
- |
fox.input |
keyboard |
input.key.tap |
mac,key,mods |
- |
fox.input |
keyboard |
input.key.type |
mac,text |
- |
fox.input |
keyboard |
input.key.hold |
mac,key,duration,mods |
- |
fox.input |
mouse |
input.mouse.move |
mac,x,y |
- |
fox.input |
mouse |
input.mouse.move_relative |
mac,dx,dy |
- |
fox.input |
mouse |
input.mouse.click |
mac,button,count |
- |
fox.input |
mouse |
input.mouse.scroll |
mac,scroll,horizontal |
- |
fox.input |
mouse |
input.mouse.drag |
mac,from_x,from_y,to_x,to_y,button,duration |
- |
fox.input |
mouse |
input.cursor |
mac |
{"x":960,"y":540} |
fox.input |
mouse |
input.screen_size |
mac |
{"width":1920,"height":1080} |
fox.clipboard |
clipboard |
clipboard.write |
mac,text |
- |
fox.clipboard |
clipboard |
clipboard.read |
mac |
{"text":"..."} |
fox.clipboard |
clipboard |
clipboard.clear |
mac |
- |
fox.clipboard |
clipboard |
clipboard.format |
mac |
{"formats":["CF_UNICODETEXT"]} |
fox.discovery |
discovery |
(无命令,应答 UDP 发现) | - | - |
fox.sysinfo |
sysinfo |
sysinfo.get |
mac,item |
JSON 字符串(系统 / CPU / 内存 / 磁盘 / 网卡) |
fox.process |
process |
process.list |
mac,filter,sort,top |
JSON 字符串(进程数组) |
fox.process |
process |
process.kill |
mac,pid,force |
{"pid":1234,"name":"notepad.exe","killed":true} |
fox.timesync |
timesync |
timesync.get |
mac |
{"unix_time":1790561280,"unix_nano":...,"timezone":"Local","rfc3339":"..."} |
fox.timesync |
timesync |
timesync.set |
mac,unix_time,dry_run |
{"applied":true,"offset_seconds":30,"rfc3339":"..."} |
fox.notify |
notify |
notify.toast |
mac,title,message,level,timeout_ms |
{"shown":true,"timeout_ms":10000} |
fox.disk |
disk |
disk.list |
mac |
JSON 字符串(分区用量与告警) |
fox.screenshot |
screenshot |
screen.capture |
mac,display,format,quality,scale |
JSON 字符串(含 blob_id,经 GET /blob/{id} 下载) |
fox.file |
file |
file.list |
mac,path,limit |
JSON 字符串(条目与统计) |
fox.file |
file |
file.stat |
mac,path |
JSON 字符串(元信息,≤16MB 含 sha256) |
fox.file |
file |
file.read |
mac,path,encoding,max_bytes |
JSON 字符串(≤512KB 内联,超过含 blob_id) |
fox.log |
log |
log.list |
mac |
JSON 字符串(日志文件清单) |
fox.log |
log |
log.tail |
mac,file,lines,filter |
JSON 字符串(尾部行与统计) |
fox.log |
log |
log.export |
mac,file |
JSON 字符串(含 blob_id,经 GET /blob/{id} 下载) |
大结果(
screen.capture/file.read超限时 /log.export)不放在返回体里,只回blob_id等引用, 内容经GET /blob/{id}流式下载(需认证,见第 2 节)。原因:内核读插件 stdout 有单行 1MB 上限。
5.1 设备发现(UDP 专用)
请求:
{"type":"discovery","action":"ping","timestamp":1758500000}
响应:
{"type":"discovery","action":"pong","mac":"00:e0:4c:82:84:54","response_time":0,"timestamp":1758500001,
"hostname":"DESKTOP-ABC","os":"windows","arch":"amd64","kernel_version":"4.3.0","protocol_version":1,"uptime_seconds":123456}
pong载荷字段:type、action、mac、response_time、timestamp,以及只读的hostname/os/arch/kernel_version/protocol_version/uptime_seconds(后 6 项为本版新增)。mac为本机真实物理网卡 MAC(自动排除虚拟网卡);探测失败回退为00:00:00:00:00:00。- 本机不执行任何校时:请求里的
timestamp仅作对端比对用、被本机忽略,pong里的timestamp是本机应答时刻。发现通道是无副作用的应答通道(UDP 分支不经认证层),不改变任何系统状态;如需校准目标机时钟,请改用经认证的timesync.set命令(见第 5 节命令表)。
6. 返回值
{
"status": "success | error | skipped",
"message": "人类可读信息",
"data": { }
}
| 状态 | 含义 |
|---|---|
success |
执行成功 |
error |
执行失败,message 含原因(含能力不可用原因) |
skipped |
MAC 不匹配,未执行 |
7. 错误码
HTTP 层
| 场景 | 响应 |
|---|---|
| 请求体为空 / JSON 非法 | 400 |
| 请求体超限(HTTP >4KB) | 413 请求体过大(上限 4096 字节) |
| 方法不允许 | 405 |
| 未认证 / 令牌错误 | 401 认证失败:Token 缺失或无效 |
插件协议层(不外露,仅内核日志)
| 错误码 | 含义 |
|---|---|
-32700 |
JSON 解析错误 |
-32601 |
方法 / 命令不存在 |
-32602 |
参数无效(协议层) |
-32001 |
命令参数非法(业务层,内核 schema 校验产出) |
-32002 |
命令不可用(能力缺失) |
业务响应示例
| 情况 | 响应 |
|---|---|
| 缺少必填参数 | {"status":"error","message":"参数 mac 非法:缺少必填参数 mac"} |
| MAC 不匹配 | {"status":"skipped","message":"命令已跳过:目标 MAC 与本机不匹配"} |
| 本机 MAC 无法确定 | {"status":"error","message":"MAC地址获取失败: 未找到有效的网络接口"} |
| 插件未运行 | {"status":"error","message":"..."},需先 fox-agent plugin start |
8. 调用示例
# 设置音量 30(命令端点,回环免 Token)
curl -X POST http://localhost:42101/ -H "Content-Type: application/json"
-d '{"cmd":"volume.set","mac":"all","value":30}'
# 组合键 Ctrl+Shift+Tab(input.key.tap 属高危命令,即便回环也需带 Token)
curl -X POST http://localhost:42101/ -H "Content-Type: application/json"
-H "X-Auth-Token: "
-d '{"cmd":"input.key.tap","mac":"all","key":"tab","mods":["ctrl","shift"]}'
# 写入剪贴板(clipboard.write 属高危命令,即便回环也需带 Token)
curl -X POST http://localhost:42101/ -H "Content-Type: application/json"
-H "X-Auth-Token: "
-d '{"cmd":"clipboard.write","mac":"all","text":"内容"}'
# 非回环:携带 Token
curl -X POST http://192.168.1.10:42101/
-H "Content-Type: application/json"
-H "X-Auth-Token: "
-d '{"cmd":"power.reboot","mac":"aa:bb:cc:dd:ee:ff"}'
# 查询能力清单(免认证)
curl http://localhost:42101/capabilities
# TCP:每行一条命令
echo '{"cmd":"volume.get","mac":"all"}' | nc 127.0.0.1 42102
# 管理:查看插件清单(管理端点不接受回环免认证,必须带 Token)
curl -H "X-Auth-Token: " http://localhost:42101/admin/plugins
# 管理:内核状态汇总
curl -H "X-Auth-Token: " http://localhost:42101/admin/status
# 管理:命令清单(含命令作用、用法、参数与结果 schema,可当插件文档读)
curl -H "X-Auth-Token: " http://localhost:42101/admin/commands
本机 Web 控制台直接用浏览器打开
http://127.0.0.1:42101/console/即可;页面本身免认证,首次进入后把auth.token粘进登录框,后续页内管理请求会自动带上该令牌。
9. 集成注意事项
- 连接数 / 超时:TCP 为长连接,单行上限 4KB;UDP 单包上限 2048 字节,超限请拆包或改用 TCP。
- 心跳与发现:无插件处理发现请求时内核不回包,调用方应以超时判定「对端不存在」;建议超时 1–2 秒。
- 签名防重放:
nonce在同一时间窗内只能用一次,重复即拒绝。 - 时钟:启用 HMAC 时调用方与终端时钟须同步,否则会表现为「签名无效」。
- 不降级原则:报文一旦出现
sig/ts/nonce,就必须验签通过,不允许「签名无效退回令牌」。 - 能力先行:对接前先读
/capabilities,据此决定可调用范围;能力不可用时命令会直接失败并给出原因。