Repository navigation
Releases: nomdn/ipw-cn
Release list
Release v4.2.0
[v4.2.0] - 2026-10-25
DNSSEC 从不可用变为可用、请求级解析能力同步 EO 特供、全站文档图灯箱、SEO 与部署链路整体升级。
✨ 新功能
- DNSSEC 验证重写:默认解析器内置境外 DO 友好列表(1.1.1.1 / 8.8.8.8 等,IPv4/IPv6 双栈 14 地址);新增 DNSKEY 自验签(TLD 与无 A 记录域名可验);DS 与 A 并行查询;解析器不支持 DNSSEC 时给出配置提示
- SSL 检查新增 SAN 字段:返回证书全部主体别名(DNS + IP)
- IndexNow 接入:key 静态文件 + 提交端点(GET 全量 / POST 增量)+ 部署后自动向 Bing/Yandex 提交 sitemap
- 文档图灯箱:全站文档图片点击放大(el-image-viewer),支持多图切换、滚轮缩放、旋转、Esc 关闭、路由切换自动关闭
- 高级选项输入规整:DNS 服务器填纯域名自动补全为
https://域名/dns-query,缺 scheme/路径/端口的写法自动补齐 - EO 特供获得请求级解析:
dns=/dns4=/dns6=/resolve=全套参数与主线对齐,DialContext DNS 接管 + SSRF 预检同源 - ipdb 后台初始化:首次启动不再被 450MB 下载阻塞,服务降级运行、库就绪一个上线一个
- DNSSEC 原理文档:/dnssec 页新增原理介绍、验证链图(OpenAI 风)与字段说明
🛠 修复
- DNSSEC「一直用不了」:国内公共解析器带 DO 位也不返回 RRSIG(根因,实测 6 家);TLD/无 A 记录域没有验签路径;DS 只在失败路径查询——三项全修
- 构建 EBUSY 静默失败:运行中的服务锁住
.output导致产物不更新,.gitignore同步补齐 agent 工具目录 - 内置中间件:h3 不解码路径
%2F,带协议头的拨测目标经兜底转发必然拼坏——已与 fiber 语义对齐 - /ipv6 空壳页:改为服务端 301(消除无 h1/无 title 的低质量页)
- sitemap:全站显式枚举 + 权重标注
- whois 摘除自定义解析后回归系统解析器;EO 同步
⚡ 优化(ipdb)
- 条件下载(ETag/Last-Modified):日更不再全量重拉 450MB
- 单文件下载超时 60s → 10 分钟(大文件慢链路不再必然失败)
- bilibili 并行查询 + 负缓存 + singleflight(/v1/location 首查 292ms → 复查 1.7ms)
- 数据库加载器原子换指针:日更重载零服务真空窗
⚠️ 行为变化
/v1/whois不再接受dns=参数(静默忽略)/ipv6改为服务端 301 到/location- DNSSEC 默认走境外解析器:网络屏蔽/劫持这些 UDP 53 时需配置
dnssec-server - 部署/构建前需停掉 3000/4000 端口的服务进程(EBUSY 会静默失败,本次已验证此坑)
配置文件说明
Release 附带两份配置文件(.example 后缀用于标识,需重命名后使用):
| 发布文件 | 重命名为 | 放置位置 |
|---|---|---|
setting.json.example |
setting.json |
主程序(后端测试节点)同目录 |
middleware.setting.json.example |
setting.json |
middleware-go/ 目录 |
# 后端测试节点
cp setting.json.example setting.json
# 独立中间件
cp middleware.setting.json.example middleware-go/setting.jsonWhat's Changed
- feat. 可以一键清空输入框 by @Linming-XHL in #37
- chore(deps): bump source-map-js from 1.2.1 to 1.2.2 in /docs by @dependabot[bot] in #40
- chore(deps): bump shell-quote from 1.10.0 to 1.12.0 in /frontend-ssr by @dependabot[bot] in #38
Full Changelog: v4.1.0...v4.2.0
Release v4.1.0
v4.1.0 — 2026-10-17
拨测接口现在支持请求级的 DNS 服务器与强制解析,参数从 URL query 一路透传到节点拨号层,不改节点全局配置、不动 hosts。
新增
请求级 DNS 服务器
| 参数 | 作用 | 示例 |
|---|---|---|
dns= |
两栈通用,默认解析服务器 | dns=1.1.1.1:53,8.8.8.8:53 |
dns4= / dns6= |
按地址族覆盖 dns |
dns6=[2400:3200::1]:53 |
支持 ip:port 与 DoH 地址,逗号分隔多个;参数非法返回 400。
请求级强制解析
| 参数 | 说明 |
|---|---|
resolve= |
两栈通用,域名:IP 或 域名:域名 |
resolve4= / resolve6= |
按地址族覆盖 resolve |
目标是 IP 时直接连,目标是域名时当作新 host 再解析一跳(不会循环)。
前端
- 工具页新增「高级选项」面板:通用
dns/resolve各一行,下方按 IPv4 / IPv6 分列 - 单栈页(tcping / speed 的 v4、v6)只渲染本栈一列;dns / whois 页隐藏 resolve
- 开发模式注入本地调试节点并排在列表首位
变更
- 缓存键:带请求级参数时不再绕过共享缓存,改为按固定字段顺序拼进键(
;dns=...;resolve=...);空参数时键逐字节不变,升级不让旧缓存失效 - 中间件透传:
middleware-go与 Nuxt 内置中间件路由的 query 透传从 tcping / speed 扩展到全部接口(detail / ssl / dns / whois 同样支持),WS 通道生效 - SSRF:出站校验改为可注入解析器,预检与实际拨号同源
修复
tcping对字面 IP 目标未做私网拦截,现在与 HTTP 拨测一致(SSRF开启时拦)- 强制解析命中时
measureDNSTime仍兜底查配置 DNS,耗时报出虚假值,现返回 0
升级注意
节点与中间件需一起升级 —— 中间件不透传 query 时,前端参数到不了节点(表现为静默失效,不报错)。
无 breaking change:不填参数时行为与 v4.0.x 完全一致。
配置文件说明
Release 附带两份配置文件(.example 后缀用于标识,需重命名后使用):
| 发布文件 | 重命名为 | 放置位置 |
|---|---|---|
setting.json.example |
setting.json |
主程序(后端测试节点)同目录 |
middleware.setting.json.example |
setting.json |
middleware-go/ 目录 |
# 后端测试节点
cp setting.json.example setting.json
# 独立中间件
cp middleware.setting.json.example middleware-go/setting.jsonWhat's Changed
- chore(deps): bump devalue from 5.9.2 to 5.9.4 in /frontend-ssr by @dependabot[bot] in #36
- chore(deps): bump hono from 4.13.5 to 4.13.7 in /serverless/lemon-getip by @dependabot[bot] in #35
Full Changelog: v4.0.2...v4.1.0
Release v4.0.2
fix(node): ASN WHOIS 支持多 RIR 解析,补 ASN 库兜底与缓存键归一化
本次修改修复了部分IP无法通过WHOIS获取信息的BUG
配置文件说明
Release 附带两份配置文件(.example 后缀用于标识,需重命名后使用):
| 发布文件 | 重命名为 | 放置位置 |
|---|---|---|
setting.json.example |
setting.json |
主程序(后端测试节点)同目录 |
middleware.setting.json.example |
setting.json |
middleware-go/ 目录 |
# 后端测试节点
cp setting.json.example setting.json
# 独立中间件
cp middleware.setting.json.example middleware-go/setting.jsonFull Changelog: v4.0.1...v4.0.2
Release v4.0.1
fix:布尔开关统一成同时识别字符串,布尔,"no"和"yes"
配置文件说明
Release 附带两份配置文件(.example 后缀用于标识,需重命名后使用):
| 发布文件 | 重命名为 | 放置位置 |
|---|---|---|
setting.json.example |
setting.json |
主程序(后端测试节点)同目录 |
middleware.setting.json.example |
setting.json |
middleware-go/ 目录 |
# 后端测试节点
cp setting.json.example setting.json
# 独立中间件
cp middleware.setting.json.example middleware-go/setting.jsonFull Changelog: v4.0.0...v4.0.1
Release v4.0.0
ipw-cn v4.0.0
范围
v3.7.0..031c1e8,12 提交 / 20 文件 / +1828 −712。
对外接口零改动——前端、中间件、收集中心都不用动。
破坏性 / 需留意
| 项 | 旧 | 新 |
|---|---|---|
| 缓存 TTL(成功) | 5 分钟 | 30 秒 |
| 缓存 TTL(失败) | 30 秒(后台协程硬删) | 5 秒(条目标记惰性判定) |
| tcping 失败判定 | 只看 IP 带 Error: |
或 Success == 0 |
| WS 通道的失败结果 | 缓存 5 分钟 | 5 秒 |
| 访问日志 | gin 默认格式 | fiber logger 转 slog 结构化字段 |
install.sh 的 ipdb 默认 |
启用 [Y/n] |
不启用 [y/N] |
install.sh 的 WS 默认地址 |
1 个中间件 | 2 个(多活) |
| systemd unit 路径写法 | 加引号 | 裸写(安装目录含空格会被拒) |
| 非 root 运行 | 直接报错退出 | 可用(新增能力,无兼容负担) |
新增
- 非 root 安装:
install.sh询问是否改用systemd --user(y 降级 / n 取消);
contribute.sh保持零交互、非 root 直接静默降级为--user - 配置项
max-response-body(默认 32MB,按解压后计)与memory-limit
(缺省取 cgroup 限额 90%),两者均可热更新 src/resources.go:资源上限解析与应用,支持32MB/8M/1g后缀- 补齐 fiber 不带的访问日志与 panic 兜底(logger 在外、recover 在内)
- 前端节点清单新增「河南 安阳 联通」;README 新增「贡献节点」章节
修复
- 响应体内存放大(OOM 根因):resty 的
AutoParseResponseMiddleware在Get()内部就把
整个响应体读进堆 → 拨测请求统一走SetDoNotParseResponse(true),响应体只做流式计数。
实测峰值 RSS 300MB → 15.2MB - zstd 解压器收紧:窗口上限 8MB(原来按帧头声明值预分配,
max-response-body拦不住) - 去掉"每次失败挂一个 30s 后
Delete(key)的协程"(失效前读到的仍是失败值) - tcping "拨号全失败"漏判为成功;WS 入口的失败结果不失效
- fiber 迁移三个坑:
c.Params()零拷贝覆盖 raw 串(strings.Clone);通配符值不带前导斜杠
(显式补/);c.IP()未开EnableIPValidation返回空串 - 前端 ASN 页重复的
AS前缀、index.ts的labletypo、setting.json.example行尾逗号
重构
- HTTP 层 gin → Fiber v3,
- 可信代理:未配置
trusted-proxies等同信任所有;EnableIPValidation常开
配置文件说明
Release 附带两份配置文件(.example 后缀用于标识,需重命名后使用):
| 发布文件 | 重命名为 | 放置位置 |
|---|---|---|
setting.json.example |
setting.json |
主程序(后端测试节点)同目录 |
middleware.setting.json.example |
setting.json |
middleware-go/ 目录 |
# 后端测试节点
cp setting.json.example setting.json
# 独立中间件
cp middleware.setting.json.example middleware-go/setting.jsonWhat's Changed
- chore(deps): bump vite from 5.4.14 to 5.4.21 in /docs by @dependabot[bot] in #34
Full Changelog: v3.7.0...v4.0.0
Release v3.7.0
ipw-cn v3.7.0 · 2026-09-25
v3.6.3 → v3.7.0 · 8 个提交 · 56 个文件(+2005 / −754)
节点侧
新增
- 新增
GET /info,GET /收缩为存活探针。/只回{"status":"ok"},版本号与能力清单移到新增的/info(免鉴权、注册在/v1组之外、不计入统计)。原端点被负载均衡、OTA 就绪探测与运维 curl 直接打,混入版本号等于向公网公开节点版本。
修复
- DNS:撤除 DoH 端点的私网 / 回环拦截。节点上自建内网 DoH(
127.0.0.1/10.x)是合理部署,堵私网会直接打死功能;该配置又需管理员凭据才能修改,不构成匿名可达攻击面(对应 CodeQLgo/request-forgery#24 按误报处理)。新增validServers/validateServerAddr,非法地址在SetDNSServer入口即丢弃并告警,全部非法时保留原配置;UDP 形式同样不禁止私有地址。 - DNS:负响应不再当错误抛出。8 个
ResolveXxxRecord收敛到resolveTyped;解析器已应答(哪怕Rcode非 Success,如NXDOMAIN/SERVFAIL)改为透出Rcode/RcodeText—— 负响应是业务结论,此前会被上层回 500。 - WHOIS:补注册局 referral 追踪。
.top这类 TLD 的 whois 服务器只回一层 referral、不再返回完整记录,原实现拿到的是空壳结果并超时。新增queryWhoisRegistry/chaseReferral/extractReferralServer/normalizeReferralValue:先查注册局拿到权威服务器,再追一层取回完整记录;happyEyeballsWhoisQuery补 parent context 使整条链路可取消。 - EdgeOne 特供副本:同步主线的
Rcode透出与地址格式校验。此前把Rcode非 Success 当错误抛出,查不存在的域名在上层被回 500,前端把「域名不存在」显示成「节点故障」;保留 EO 特有形态(DoH / UDP 单地址互相兜底、耗时透出、ResolveIP)。
文档站
新增
- 4 篇 API 文档(
api/ip/{locate,myip,query}、api/whois/query):按自有接口实测重写,给出可直接执行的公开实例(节点直连 +middleware-1转发),另设 1.2 节引导到拨测控制台取用已部署的节点与中间件。 - 4 篇技术文档(
tls/dns_dig/code_getip/check_userip_ipv4_ipv6),正文首行徽标一律标「转载」。 - 补回 9 张原始配图,置于
public/doc/同名覆盖(wayback 仅存 1 张,实际取自arquivo.pt)。
变更
- 文档导航收敛到单一组件。抽出
app/components/DocMenu.vue作为全站唯一实现,/doc与/doc/**两个页面与窄屏抽屉共用(原先两页各有一份内联菜单,已删);宽屏布局与桌面端行为不变。 - 窄屏文档导航改由左侧抽屉承载(≤768px 隐藏文档页自身的 260px 侧栏;
size 80%、分组默认展开、:key重挂避免停在首次开合状态、选中后自动收起);非文档路由的抽屉只留一个「文档」链接作为入口。 - 文档路由不渲染页脚(阅读页不该被备案 / 版权块打断,窄屏下也避免与抽屉抢滚动区)。
- 首屏性能:Element Plus 去掉整库
dist/index.css,改走@element-plus/nuxt按需引入(仅额外显式引入theme-chalk的暗色变量文件);shiki由静态 import 改动态 import,引擎与语言 / 主题注册表约 160KB 移出首屏关键路径。 - 可访问性:补
html lang="zh-CN";纯图标菜单项补aria-label(返回首页 / 切换主题);logo 改装饰性(alt="",可访问名由外层链接提供,避免宽屏下与站名被读两遍);正文链接补下划线(绿#3EAF7C与正文对比度不足,须有非颜色的视觉区分);页脚公安备案链接补v-if,未配置时不渲染空链接。 - 域名自有化:全站
ipw.cn映射到自有域名(站点nipw.cn;取本机 IP 用test./4./6.wsmdn.top),7 篇正文与 6 个 svg 图层名同步替换;纯文本接口的示例代码相应重写。 - 构建配置:移除
better-sqlite3(原生模块,构建环境常需现场编译),dayjs/lodash-unified加入build.transpile。 - 下线三个节点(
cn-shenzhen、cn-wuhan-chinatelecom、呼和浩特 WS 节点),按行注释保留备查,不再派发。
修复
- 根页本机 IP 查询:去掉 ofetch 默认重试(
retry:false),并由串行改为各自消费、先到先上屏,不再等 shiki 高亮与最慢一项;utils/middleware.ts与对应 server route 同样关闭默认重试。 - DNS 结果表列溢出:失败行原本同时渲染「记录数 / 耗时 / TTL」三格导致
colspan溢出、整表多出 3 列;新增hasData()让后三格与失败态互斥,列数守恒。 - 暗色模式根元素规则失效:作用于
<html>自身的规则从被 scoped@import的style.css上移到app.vue的非 scoped 块(scope 属性会让根元素规则永不匹配)。 - 抽屉内链接样式:改用直接子选择器(
> a),不再把文档菜单里的<a>吃成整行大按钮。 - Serverless 部署支持范围的表述与仓库内实际实现对齐;
/info拆分后正文同步。
配置文件说明
Release 附带两份配置文件(.example 后缀用于标识,需重命名后使用):
| 发布文件 | 重命名为 | 放置位置 |
|---|---|---|
setting.json.example |
setting.json |
主程序(后端测试节点)同目录 |
middleware.setting.json.example |
setting.json |
middleware-go/ 目录 |
# 后端测试节点
cp setting.json.example setting.json
# 独立中间件
cp middleware.setting.json.example middleware-go/setting.jsonFull Changelog: v3.6.3...v3.7.0
Release v3.6.3
fix:修复Linux下OTA下载的二进制无法执行
配置文件说明
Release 附带两份配置文件(.example 后缀用于标识,需重命名后使用):
| 发布文件 | 重命名为 | 放置位置 |
|---|---|---|
setting.json.example |
setting.json |
主程序(后端测试节点)同目录 |
middleware.setting.json.example |
setting.json |
middleware-go/ 目录 |
# 后端测试节点
cp setting.json.example setting.json
# 独立中间件
cp middleware.setting.json.example middleware-go/setting.jsonFull Changelog: v3.6.2...v3.6.3
Release v3.6.2
V3.6.2(相对 V3.6.1)
仅 1 个提交、1 个文件:src/report.go(+3 / -1)
- 类型:
fix(report) - 改动:
nodeIsProbeType白名单补齐location,与中心侧store.go对齐 - 根因修复:节点侧白名单原漏
location,导致节点转发/自发 location 查询只累加到统计(request_stats全收 → 大盘有 Location 统计),明细(probe_results)被!isProbeType挡掉不报 → 出现「大盘有、明细没有」 - 影响:补齐后 location 进入明细上报,是线上 location 明细空白的直接修复(之前业务拨测没落库即此因)
配置文件说明
Release 附带两份配置文件(.example 后缀用于标识,需重命名后使用):
| 发布文件 | 重命名为 | 放置位置 |
|---|---|---|
setting.json.example |
setting.json |
主程序(后端测试节点)同目录 |
middleware.setting.json.example |
setting.json |
middleware-go/ 目录 |
# 后端测试节点
cp setting.json.example setting.json
# 独立中间件
cp middleware.setting.json.example middleware-go/setting.jsonFull Changelog: v3.6.1...v3.6.2
Release v3.6.1
V3.6.1(相对 V3.6.0)
提交区间 v3.6.0..v3.6.1,共 8 个文件改动(435 增 / 2107 删,删量主要来自 pnpm-lock 瘦身)。
节点相关(影响二进制 / 部署)
| 文件 | 改动 |
|---|---|
install.sh (+35) |
交互改造:DNS 留空即自动探测;WS 预设指向收集中心 wss://boce-api.api-ipw.wsmdn.top/ws;注册 key 留空自动生成;NODE_ID 提到分支外并明文回显 |
middleware-go/ws.go (+13) |
WS 已知帧(report/config_result/ota_result)显式丢弃,不再落 default 刷日志,减少噪声告警 |
文档 / SSR 前端(不影响节点二进制)
docs/guide/deploy-middleware.md:部署文档更新frontend-ssr/*:站点配置(config/index.ts、app.vue、index.ts)——清空 ICP / 公安号、改 siteUrl、加百度站点验证 meta;依赖 bump(devalue、hono、vitest)serverless/lemon-getip:依赖 lock 更新
配置文件说明
Release 附带两份配置文件(.example 后缀用于标识,需重命名后使用):
| 发布文件 | 重命名为 | 放置位置 |
|---|---|---|
setting.json.example |
setting.json |
主程序(后端测试节点)同目录 |
middleware.setting.json.example |
setting.json |
middleware-go/ 目录 |
# 后端测试节点
cp setting.json.example setting.json
# 独立中间件
cp middleware.setting.json.example middleware-go/setting.jsonWhat's Changed
- chore(deps): bump @vitest/mocker and vitest in /serverless/lemon-getip by @dependabot[bot] in #32
- chore(deps): bump devalue from 5.9.0 to 5.9.2 in /frontend-ssr by @dependabot[bot] in #33
- chore(deps): bump hono from 4.12.34 to 4.13.5 in /serverless/lemon-getip by @dependabot[bot] in #31
Full Changelog: v3.6.0...v3.6.1
Release v3.6.0
配置文件说明
Lemon IPW 节点 v3.6.0
主题:节点从「被动执行拨测」进化为「可被远程运维的边缘单元」——收集中心可对节点运行时配置读写、按能力清单协商下发指令、并推送 OTA 升级。
破坏性变更
- OTA 模型反转:节点不再定期查 GitHub Release 自更新,改为「收集中心下发、节点执行」的一次性任务(WS
ota/ HTTPPOST /v1/ota),升级时机由管理员掌握。 node-ota/NODE_OTA键名保留,但语义反转:过去"true"表示启用自更新;现在缺省即为允许(收集中心可下发),只有显式配"false"/0/no/off才禁用——禁用时节点拒绝一切 OTA 指令并回传原因,适合只读容器 / 编排托管。install.sh不再询问是否启用 OTA 自更新。- 远端配置覆盖范围收紧:
access-token/report-token无条件禁止远端覆盖(含收集中心托管配置),始终以节点本地ENV > setting.json为准,避免「远端写错一次、节点永久失联且无法远程修回」。本地PATCH /v1/config不受此限。
升级影响:此前依赖自更新的节点,升级后不会再自动跟进新版本,需在收集中心控制台显式下发 OTA。只读容器 / 编排托管场景请在节点侧设
node-ota=false。
新增
- 运行时配置接口:
GET/PATCH /v1/config(?persist=true写回本地文件)、POST /v1/config/refresh,WS 同款type=config。凭据类键遮蔽为***回显,应答带secretKeys/restartRequiredKeys/remoteProtectedKeys/protectedIgnored。 - 能力清单协议(capabilities):节点在 register 与
GET /上报probe/report/config/ota,收集中心三态门控——明确不含则拒绝,空(老节点未上报)视为「未知」仍尝试,不把「未知」误判成「不支持」。 - WS 连接热更新:
ws-url改为按 URL 维护独立连接协程、多退少补,改址无需重启;node-id/node-key仍需重启。 - OTA 升级(下发形态):支持
url直发或version+ 资产基址,可选sha256强校验;流程单飞 → 下载 → 校验 → 预检 → 原子替换 → 重启,失败回滚.old;进度经ota_result回报accepted → downloading → verifying → installing → restarting。 node-ota支持运行时热改:该开关纳入运行时配置(PATCH /v1/config或 WS 下发即时生效,改后立即按新值判定后续指令,无需重启);非法字面值(非true/1/yes/on/false/0/no/off)会报unknown且不覆盖原值,避免手滑把开关锁死。- EO 边缘函数补齐上报通道:从
src/report.go提取、裁掉 WS 分支,只走POST <report-url>/report;GET /同步回报版本与能力。 - 优雅停机:显式持有
http.Server,收到退出信号先Shutdown释放端口再退出。 - 文档站扩章:新增《节点 API 与协议参考》《公开 API(/api/v1)》《功能总览》,侧边栏挂载。
修复
block-private-ips启动期忽略setting.json:原只读 ENV,与全仓「env > setting.json」口径不一致,现改为viper.ReadInConfig()后解析。- 上报循环「启动即定型」:原启动期无通道就不启动,热更新出通道后无人上报,现改为常驻循环。
- 换址收敛吃掉配置应答:改为应答后延迟异步收敛,避免控制台只看到超时。
构建 / CI
src/Dockerfile新增VERSION/COMMIT/BUILD_TIME构建参数;docker.yml注入,镜像与 Release 二进制同源可追溯。.gitignore补文档站构建中间产物。
Release 附带两份配置文件(.example 后缀用于标识,需重命名后使用):
| 发布文件 | 重命名为 | 放置位置 |
|---|---|---|
setting.json.example |
setting.json |
主程序(后端测试节点)同目录 |
middleware.setting.json.example |
setting.json |
middleware-go/ 目录 |
# 后端测试节点
cp setting.json.example setting.json
# 独立中间件
cp middleware.setting.json.example middleware-go/setting.jsonFull Changelog: v3.5.0...v3.6.0