首页
iYoRoy DN42 Network
关于
友情链接
推荐
悠笙の喵罐头
Search
1
Docker下中心化部署EasyTier
1,436 阅读
2
给Android 4.9内核添加KernelSU支持
958 阅读
3
记一次为Android 4.9内核的ROM启用erofs支持
280 阅读
4
在TrueNAS上使用Docker安装1Panel
259 阅读
5
为黑群晖迁移RR引导盘
236 阅读
Android
运维
NAS
开发
网络技术
专题向研究
DN42
个人ISP
CTF
登录
Search
标签搜索
网络技术
Linux
BGP
BIRD
C&C++
DN42
Android
Docker
AOSP
Windows
MSVC
内部路由协议
OSPF
iBGP
Clearnet
ASN
服务
DNS
TrueNAS
Web
神楽悠笙
累计撰写
21
篇文章
累计收到
10
条评论
首页
栏目
Android
运维
NAS
开发
网络技术
专题向研究
DN42
个人ISP
CTF
页面
iYoRoy DN42 Network
关于
友情链接
推荐
悠笙の喵罐头
搜索到
21
篇与
的结果
DN42探究日记 - Ep.3 在DN42中注册域名并搭建权威DNS
写在前面 本人是BGP小白,文章中可能会存在不严谨内容/小白理解/低级错误,请诸位大佬们手下留情。若发现存在问题,您愿意的话可以邮件联系我,我会在第一时间更正。如果您不能接受,建议现在就关闭此文章。 假设你已经加入了DN42,并且能够正常收发路由表并且访问到DN42内的IP 起因 在调试网络的时候发现Ping或traceroute别人的DN42 IP都能显示出来反向解析的域名,能知道路由经过了哪些节点而不是单纯的看IP(如下图),非常一目了然,让别人一眼就看出来你绕路了(逃), 因此打算自己也注册一个DN42域名并搭建权威DNS服务。 查阅了蓝天大佬的这篇文章,他使用了PowerDNS+MySQL主从同步方案,但是我的服务器性能较差(只有1核心1GB内存),因此打算使用KnotDNS作为DNS服务器,用标准区域传输协议(AXFR/IXFR)实现主从同步。 准备工作 {alert type="warning"} 本章及后续章节中提到的域名和IP均为我自己的域名和IP,实际部署时请换成你自己的;文章中尖括号括起来的值需要按你的需求修改 {/alert} 挑选一个自己心仪的域名:yori.dn42,并且计划在三台机器上部署DNS服务器: 172.20.234.225, fd18:3e15:61d0::1, ns1.yori.dn42 172.20.234.227, fd18:3e15:61d0::3, ns2.yori.dn42 172.20.234.229, fd18:3e15:61d0::5, ns3.yori.dn42 其中,ns1.yori.dn42作为主服务器,ns2、ns3作为从服务器。 安装KnotDNS 如果系统的53端口被systemd-resolvd之类的进程占用了,就先将其禁用: systemctl stop systemd-resolved systemctl disable systemd-resolved unlink /etc/resolv.conf echo "nameserver 8.8.8.8" > /etc/resolv.conf 我使用的是Debian12系统,因此使用APT安装: apt install knot knot-dnsutils -y 设置KnotDNS自启动: systemctl enable knot 配置KnotDNS 创建key 首先创建一个key用于同步: keymgr -t key_knsupdate 将输出部分复制下来: # hmac-sha256:key_knsupdate:<your secret> key: - id: key_knsupdate algorithm: hmac-sha256 secret: <your secret> 编辑配置文件 主服务器 编辑/etc/knot/knot.conf,填入如下内容: server: rundir: "/run/knot" user: knot:knot automatic-acl: on listen: [ <监听地址1>@53, <监听地址2>@53, ... ] log: - target: syslog any: info database: storage: "/var/lib/knot" ### 此处粘贴上一步生成的Key # hmac-sha256:key_knsupdate:<your secret> key: - id: key_knsupdate algorithm: hmac-sha256 secret: <your secret> remote: - id: <1号DNS服务器ID> address: <1号DNS服务器IP>@53 - id: <2号DNS服务器ID> address: <2号DNS服务器IP>@53 - id: <3号DNS服务器ID> address: <3号DNS服务器IP>@53 acl: - id: acl_slave key: key_knsupdate action: transfer - id: acl_master key: key_knsupdate action: notify - id: acl_knsupdate key: key_knsupdate action: update template: - id: default storage: "/var/lib/knot" file: "%s.zone" zone: - domain: <DN42 域名> notify: [ <从服务器1ID>, <从服务器2ID> ] acl: [ acl_slave, acl_knsupdate ] - domain: <IPv4反向解析域名> notify: [ <从服务器1ID>, <从服务器2ID> ] acl: [ acl_slave, acl_knsupdate ] - domain: <IPv6反向解析域名> notify: [ <从服务器1ID>, <从服务器2ID> ] acl: [ acl_slave, acl_knsupdate ] 其中,监听地址需要填写本机的DN42 IPv4和DN42 IPv6,如果需要本地调试可再加上127.0.0.1和localhost等内网IP 从服务器ID即remote里设置的服务器的ID,你选定哪台(哪些)机器作为从服务器就填写哪台(哪些)服务器的ID remote中的address可以填写内网地址或者DN42 IPv4或者DN42 IPv6,仅用于同步主从服务器。如果使用内网地址请将地址加到监听列表中 template中设置了将Zone文件存储在/var/lib/knot下 IPv4反向解析域名按照你申请的IPv4段填写,遵循RFC 2317规定的格式,如我的IPv4段是172.20.234.224/28,我的IPv4反向解析域名应该为224/28.234.20.172.in-addr.arpa,即将IPv4的最后一段225/28看作一个整体,剩下的按照点来分隔,再将各个部分倒序拼接,最后加上.in-addr.arpa IPv6反向解析域名按照你申请的IPv6段填写,遵循RFC 3152规定的格式,如我的IPv6段是fd18:3e15:61d0::/48,我的IPv6反向解析域名应该为0.d.1.6.5.1.e.3.8.1.d.f.ip6.arpa,即将地址块中的各个字符倒序拼接,最后加上.in-addr.arpa。如果有0需要补全。 {collapse} {collapse-item label="示例"} server: rundir: "/run/knot" user: knot:knot automatic-acl: on listen: [ 172.20.234.225@53, fd18:3e15:61d0::1@53, localhost@53, 127.0.0.2@53 ] log: - target: syslog any: info database: storage: "/var/lib/knot" # hmac-sha256:key_knsupdate:dyE7/N3CLTE5IFKfpBK0Gaij6aPnXkv/4sp1gUORlsk= key: - id: key_knsupdate algorithm: hmac-sha256 secret: dyE7/N3CLTE5IFKfpBK0Gaij6aPnXkv/4sp1gUORlsk= remote: - id: 225 # 主服务器 address: 172.20.234.225@53 - id: 227 # 从服务器 address: 172.20.234.227@53 - id: 229 # 从服务器 address: 172.20.234.229@53 acl: - id: acl_slave key: key_knsupdate action: transfer - id: acl_master key: key_knsupdate action: notify - id: acl_knsupdate key: key_knsupdate action: update template: - id: default storage: "/var/lib/knot" file: "%s.zone" zone: - domain: yori.dn42 notify: [ 227, 229 ] acl: [ acl_slave, acl_knsupdate ] - domain: 224/28.234.20.172.in-addr.arpa notify: [ 227, 229 ] acl: [ acl_slave, acl_knsupdate ] - domain: 0.d.1.6.5.1.e.3.8.1.d.f.ip6.arpa notify: [ 227, 229 ] acl: [ acl_slave, acl_knsupdate ] # # Secondary zone # - domain: example.net # master: primary {/collapse-item} {/collapse} 从服务器 从服务器的大致内容和主服务器相同,只需要将监听地址改成从服务器的地址,并且将zone部分配置修改一下: --- a/knot.conf +++ b/knot.conf zone: - domain: <DN42 域名> - notify: [ <从服务器1ID>, <从服务器2ID> ] - acl: [ acl_slave, acl_knsupdate ] + master: <主服务器ID> + zonefile-load: whole + acl: acl_master - domain: <IPv4反向解析域名> - notify: [ <从服务器1ID>, <从服务器2ID> ] - acl: [ acl_slave, acl_knsupdate ] + master: <主服务器ID> + zonefile-load: whole + acl: acl_master - domain: <IPv6反向解析域名> - notify: [ <从服务器1ID>, <从服务器2ID> ] - acl: [ acl_slave, acl_knsupdate ] + master: <主服务器ID> + zonefile-load: whole + acl: acl_master 主服务器ID即remote里设置的服务器的ID,你选定哪台机器作为主服务器就填写哪台服务器的ID {collapse} {collapse-item label="样例"} server: rundir: "/run/knot" user: knot:knot automatic-acl: on listen: [ 172.20.234.227@53, fd18:3e15:61d0::3@53, localhost@53, 127.0.0.1@53 ] log: - target: syslog any: info database: storage: "/var/lib/knot" # hmac-sha256:key_knsupdate:<key> key: - id: key_knsupdate algorithm: hmac-sha256 secret: <key> remote: - id: 225 address: 172.20.234.225@53 - id: 227 address: 172.20.234.227@53 - id: 229 address: 172.20.234.229@53 acl: - id: acl_slave key: key_knsupdate action: transfer - id: acl_master key: key_knsupdate action: notify - id: acl_knsupdate key: key_knsupdate action: update template: - id: default storage: "/var/lib/knot" file: "%s.zone" zone: - domain: yori.dn42 master: 225 zonefile-load: whole acl: acl_master - domain: 224/28.234.20.172.in-addr.arpa master: 225 zonefile-load: whole acl: acl_master - domain: 0.d.1.6.5.1.e.3.8.1.d.f.ip6.arpa master: 225 zonefile-load: whole acl: acl_master {/collapse-item} {/collapse} 编写完配置文件后运行如下指令重启KnotDNS: systemctl restart knot 编辑Zone区域文件 此章节中的记录值(非主机名)若需要填写域名,除了特殊说明外,都请遵循RFC 1034规范填写FQDN格式。此章节中的所有配置均在主DNS服务器上完成 DN42域名 进入/var/lib/knot,创建文件<dn42域名>.zone SOA记录 域名的第一条记录必须为SOA记录,SOA记录是起始授权记录,记录了域名的一些基本信息如主要NS服务器地址。填入如下内容: @ <TTL> SOA <主要NS服务器地址> <联系人邮件> <记录编号> <AXFR刷新时间> <AXFR重试时间> <AXFR过期时间> <最小TTL> @表示是当前域名本身,不用修改 TTL: 当前SOA记录的TTL值 主要NS服务器地址: 当前域名的主要权威NS服务器地址,可以是域名内的解析值,如我的主要NS服务器是172.20.234.225,我打算使用ns1.yori.dn42.指向此地址,那么此处可填写ns1.yori.dn42. 联系人邮件: 邮箱地址,并且用.代替@,如我的邮箱是
[email protected]
,那么此处可填写i.iyoroy.cn 记录编号: 一个10位数字,遵循RFC 1912,表示Zone文件的版本号。其他DNS服务器在获取SOA后发现序列号增加了就会重新拉取新的记录。一般使用日期+编号的方式编码,因此此项值应该在每次修改后递增。 AXFR刷新时间: AXFR从服务器两次拉取的间隔 AXFR重试时间: AXFR从服务器拉取失败后重试时间 AXFR过期时间: AXFR从服务器拉取失败后,最多用先前最后一次拉取成功的记录继续提供服务这么长时间,之后停止应答 最小TTL: 当前整个域名的最小TTL值,所有记录的最小刷新时间,至少过了这么长时间才会刷新 {collapse} {collapse-item label="样例"} ; SOA @ 3600 SOA ns1.yori.dn42. i.iyoroy.cn. 2025072705 60 60 1800 60 {/collapse-item} {/collapse} NS记录 @ <TTL> NS <NS服务器1> @ <TTL> NS <NS服务器2> @ <TTL> NS <NS服务器3> 根据你的实际情况填写,有几台服务器就填写几条记录。 {collapse} {collapse-item label="样例"} ; NS @ 3600 NS ns1.yori.dn42. @ 3600 NS ns2.yori.dn42. @ 3600 NS ns3.yori.dn42. {/collapse-item} {/collapse} A、AAAA、CNAME等记录 按照如下格式填写即可: <主机名> <TTL> <类型> <记录值> 如果你的NS服务器值指向了你自己的DN42域名的主机,请务必为其添加A类型或者AAAA类型的解析记录 {collapse} {collapse-item label="样例"} ; A ns1 600 A 172.20.234.225 ns2 600 A 172.20.234.227 ns3 600 A 172.20.234.229 hkg-cn.node 600 A 172.20.234.225 nkg-cn.node 600 A 172.20.234.226 tyo-jp.node 600 A 172.20.234.227 hfe-cn.node 600 A 172.20.234.228 lax-us.node 600 A 172.20.234.229 ; AAAA ns1 600 AAAA fd18:3e15:61d0::1 ns2 600 AAAA fd18:3e15:61d0::3 ns3 600 AAAA fd18:3e15:61d0::5 hkg-cn.node 600 AAAA fd18:3e15:61d0::1 nkg-cn.node 600 AAAA fd18:3e15:61d0::2 tyo-jp.node 600 AAAA fd18:3e15:61d0::3 hfe-cn.node 600 AAAA fd18:3e15:61d0::4 lax-us.node 600 AAAA fd18:3e15:61d0::5 {/collapse-item} {collapse-item label="完整样例"} /var/lib/knot/yori.dn42.zone ; SOA @ 3600 SOA ns1.yori.dn42. i.iyoroy.cn. 2025072705 60 60 1800 60 ; NS @ 3600 NS ns1.yori.dn42. @ 3600 NS ns2.yori.dn42. @ 3600 NS ns3.yori.dn42. ; A ns1 600 A 172.20.234.225 ns2 600 A 172.20.234.227 ns3 600 A 172.20.234.229 hkg-cn.node 600 A 172.20.234.225 nkg-cn.node 600 A 172.20.234.226 tyo-jp.node 600 A 172.20.234.227 hfe-cn.node 600 A 172.20.234.228 lax-us.node 600 A 172.20.234.229 ; AAAA ns1 600 AAAA fd18:3e15:61d0::1 ns2 600 AAAA fd18:3e15:61d0::3 ns3 600 AAAA fd18:3e15:61d0::5 hkg-cn.node 600 AAAA fd18:3e15:61d0::1 nkg-cn.node 600 AAAA fd18:3e15:61d0::2 tyo-jp.node 600 AAAA fd18:3e15:61d0::3 hfe-cn.node 600 AAAA fd18:3e15:61d0::4 lax-us.node 600 AAAA fd18:3e15:61d0::5 {/collapse-item} {/collapse} IPv4反向解析域名 在/var/lib/knot下创建文件<IPv4反向解析域名>.in-addr.arpa,并用_代替/。如我的IPv4段是172.20.234.224/28,我的IPv4反向解析域名是224/28.234.20.172.in-addr.arpa,那么此处文件名为224_28.234.20.172.in-addr.arpa.zone。填入解析记录: ; SOA @ <TTL> SOA <主要NS服务器地址> <联系人邮件> <记录编号> <AXFR刷新时间> <AXFR重试时间> <AXFR过期时间> <最小TTL> ; NS @ <TTL> NS <NS服务器1> @ <TTL> NS <NS服务器2> @ <TTL> NS <NS服务器3> ; PTR <IPv4地址最后一位> <TTL> PTR <反向解析DNS值> <IPv4地址最后一位> <TTL> PTR <反向解析DNS值> <IPv4地址最后一位> <TTL> PTR <反向解析DNS值> ... SOA和NS记录和上方相同 IPv4地址最后一位: 你给设备绑定的DN42 IPv4地址四段中的最后一段,如我的HK节点分配的172.20.234.225地址,那么此处就填写`225 {collapse} {collapse-item label="样例"} 224_28.234.20.172.in-addr.arpa.zone ; SOA @ 3600 SOA ns1.yori.dn42. i.iyoroy.cn. 2025072802 60 60 1800 60 ; NS @ 3600 NS ns1.yori.dn42. @ 3600 NS ns2.yori.dn42. @ 3600 NS ns3.yori.dn42. ; PTR 225 600 PTR hkg-cn.node.yori.dn42. 226 600 PTR nkg-cn.node.yori.dn42. 227 600 PTR tyo-jp.node.yori.dn42. 228 600 PTR hfe-cn.node.yori.dn42. 229 600 PTR lax-us.node.yori.dn42. {/collapse-item} {/collapse} 你可能会疑惑为何需要带上CIDR掩码,这与Clearnet中常见的、按八位组倒序的格式(如234.20.172.in-addr.arpa)不同;以及如果你尝试本地测试,你会发现直接测试你自己的IP地址的反解会失败。 原因在于DN42的分布式注册机制:单个区域文件无法覆盖你的地址段的所有反向查询入口点(即每个具体IP地址对应的.in-addr.arpa名称)。为了解决这个问题,DN42官方DNS会在你的PR被合并后,在其权威DNS服务器上为你的地址段添加CNAME重定向,将单个IP的PTR记录指向你的带CIDR的格式,如下: ~$ dig PTR 225.234.20.172.in-addr.arpa +short 225.224/28.234.20.172.in-addr.arpa. # <-- Registry 添加的 CNAME (重定向) hkg-cn.node.yori.dn42. # <-- DNS 返回的最终 PTR 记录 当外部解析器查询某个具体IP (如172.20.234.225) 的反向记录时(查询225.234.20.172.in-addr.arpa),官方DNS会返回一个CNAME记录,将其指向CIDR的区域名称下的具体记录(225.224/28.234.20.172.in-addr.arpa)。最终,PTR 记录由你配置的权威 DNS 服务器提供。 IPv6反向解析域名 在/var/lib/knot下创建文件<IPv6反向解析域名>.in-addr.arpa。如我的IPv6段是fd18:3e15:61d0::/48,我的IPv6反向解析域名是0.d.1.6.5.1.e.3.8.1.d.f.ip6.arpa,那么此处文件名为0.d.1.6.5.1.e.3.8.1.d.f.ip6.arpa.zone。填入解析记录: ; SOA @ <TTL> SOA <主要NS服务器地址> <联系人邮件> <记录编号> <AXFR刷新时间> <AXFR重试时间> <AXFR过期时间> <最小TTL> ; NS @ <TTL> NS <NS服务器1> @ <TTL> NS <NS服务器2> @ <TTL> NS <NS服务器3> ; PTR <最后20字符反向序列> <TTL> PTR <反向解析DNS值> <最后20字符反向序列> <TTL> PTR <反向解析DNS值> <最后20字符反向序列> <TTL> PTR <反向解析DNS值> ... SOA和NS记录处理方式同上 PTR的主机名,需要你将主机IPv6地址移除/48前缀后的80位部分展开为20个十六进制字符,并倒序排列这些字符并用点分隔。如我的香港节点IPv6是fd18:3e15:61d0::1,展开就是fd18:3e15:61d0:0000:0000:0000:0000:0001,此处主机名就填写1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0 {collapse} {collapse-item label="样例"} 0.d.1.6.5.1.e.3.8.1.d.f.ip6.arpa.zone ; SOA @ 3600 SOA ns1.yori.dn42. i.iyoroy.cn. 2025072802 60 60 1800 60 ; NS @ 3600 NS ns1.yori.dn42. @ 3600 NS ns2.yori.dn42. @ 3600 NS ns3.yori.dn42. ; PTR 1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0 600 PTR hkg-cn.node.yori.dn42. 2.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0 600 PTR nkg-cn.node.yori.dn42. 3.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0 600 PTR tyo-jp.node.yori.dn42. 4.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0 600 PTR hfe-cn.node.yori.dn42. 5.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0 600 PTR lax-us.node.yori.dn42. {/collapse-item} {/collapse} 验证设置 全部保存后在每台DNS服务器上都运行一次knot reload重载,不出意外的话应该能看到从服务器同步了主服务器的zone文件,此时通过dig或者nslookup指定服务器查询应该能查到解析记录了 注册 域名 克隆下DN42 Registry,进入data/dns,新建文件<你打算注册的域名>,填入如下内容: domain: <你打算注册的域名> admin-c: <管理员NIC句柄> tech-c: <技术人员NIC句柄> mnt-by: <维护者> nserver: <NS1服务器域名> <NS1服务器IP> nserver: <NS2服务器域名> <NS2服务器IP> nserver: <NS3服务器域名> <NS3服务器IP> ... source: DN42 admin-c、tech-c、mnt-by请参考DN42探究日记 - Ep.1 加入DN42网络 {collapse} {collapse-item label="样例"} data/dns/yori.dn42 domain: yori.dn42 admin-c: IYOROY-DN42 tech-c: IYOROY-DN42 mnt-by: IYOROY-MNT nserver: ns1.yori.dn42 172.20.234.225 nserver: ns1.yori.dn42 fd18:3e15:61d0::1 nserver: ns2.yori.dn42 172.20.234.227 nserver: ns2.yori.dn42 fd18:3e15:61d0::3 nserver: ns3.yori.dn42 172.20.234.229 nserver: ns3.yori.dn42 fd18:3e15:61d0::5 source: DN42 {/collapse-item} {/collapse} IPv4反向解析域名 进入data/inetnum,找到你注册的地址块,加nserver字段,填写为你自己的DNS服务器: nserver: <你的DNS服务器地址> nserver: <你的DNS服务器地址> ... {collapse} {collapse-item label="样例"} diff --git a/data/inetnum/172.20.234.224_28 b/data/inetnum/172.20.234.224_28 index 50c800945..5ad60e23d 100644 --- a/data/inetnum/172.20.234.224_28 +++ b/data/inetnum/172.20.234.224_28 @@ -8,3 +8,6 @@ tech-c: IYOROY-DN42 mnt-by: IYOROY-MNT status: ASSIGNED source: DN42 +nserver: ns1.yori.dn42 +nserver: ns2.yori.dn42 +nserver: ns3.yori.dn42 {/collapse-item} {/collapse} IPv6反向解析域名 进入data/inet6num,找到你注册的地址块,加nserver字段,填写为你自己的DNS服务器: nserver: <你的DNS服务器地址> nserver: <你的DNS服务器地址> ... {collapse} {collapse-item label="样例"} diff --git a/data/inet6num/fd18:3e15:61d0::_48 b/data/inet6num/fd18:3e15:61d0::_48 index 53f0de06d..1ae067b00 100644 --- a/data/inet6num/fd18:3e15:61d0::_48 +++ b/data/inet6num/fd18:3e15:61d0::_48 @@ -8,3 +8,6 @@ tech-c: IYOROY-DN42 mnt-by: IYOROY-MNT status: ASSIGNED source: DN42 +nserver: ns1.yori.dn42 +nserver: ns2.yori.dn42 +nserver: ns3.yori.dn42 {/collapse-item} {/collapse} 提交PR,等待合并 填写完后推送并提交Pull Request。因为DN42中人人都可以建立递归DNS,DNS配置完全生效可能要一周左右。虽然我实测合并后半天以内公共DNS(172.20.0.53)就已经能查询到我的记录了 特别感谢たのしい大佬,让我明白了DN42中IPv4反向解析与公网的不同之处 参考文章: https://www.haiyun.me/archives/1398.html https://www.jianshu.com/p/7d69ec2976c7 https://www.potat0.cc/posts/20220726/Register_DN42_Domain/ https://bbs.csdn.net/topics/393775423 https://blog.snorlax.blue/knot-reverse-dns-kickstart/ http://www.kkdlabs.jp/dns/automatic-dnssec-signing-by-knot-dns/ https://lantian.pub/article/modify-website/register-own-domain-in-dn42.lantian/ https://datatracker.ietf.org/doc/html/rfc2317 https://datatracker.ietf.org/doc/html/rfc3152 https://datatracker.ietf.org/doc/html/rfc1912#section-2.2
2025年08月03日
34 阅读
0 评论
1 点赞
DN42探究日记 - Ep.2 通过OSPF搭建内部网络并启用iBGP
写在前面 本人是BGP小白,文章中可能会存在不严谨内容/小白理解/低级错误,请诸位大佬们手下留情。若发现存在问题,您愿意的话可以邮件联系我,我会在第一时间更正。如果您不能接受,建议现在就关闭此文章。 本文更新日志 {timeline} {timeline-item color="#50BFFF"} 2025年7月22日:文章第一版发布,使用VXLAN over WireGuard隧道 {/timeline-item} {timeline-item color="#50BFFF"} 2025年7月25日:更新隧道方案,使用type ptp;以支持直接通过WireGuard传输OSPF流量(特别感谢Nuro Trance大佬指导!) {/timeline-item} {timeline-item color="#50BFFF"} 2025年8月8日:添加iBGP部分的解释和配置 {/timeline-item} {timeline-item color="#4F9E28"} 2025年8月27日:更新节点拓扑结构图 {/timeline-item} {/timeline} 为什么需要内部路由 当节点数量增多,我们需要一个合适的方式处理自己AS的内部路由。因为BGP路由只负责将数据包路由到AS,这就导致了一个问题:假如我有A、B两个节点都与别人peer,但是在路由器看来这两台设备同属于一个AS,从A节点发出的请求回包可能被回到B上。这个时候,如果没有做内部路由,则A会无法收到回包。因此,我们需要保证自家内网各个设备之间都能连通。常见的几种方式如下: 通过ZeroTier等组网工具:这种方式较为简单,只需要在每个节点上配置一个客户端即可实现各个节点之间的P2P连接。 通过WireGuard等P2P工具手动建立$\frac{n(n+1)}{2}$条隧道,效果同1,但是节点一多工作量呈指数级上升 通过WireGuard等P2P工具手动建立<$\frac{n(n+1)}{2}$条隧道,再通过OSPF、Babel等内网寻路协议建立内网路由,优点是较为灵活,易于后期添加新节点,缺点就是较为危险,容易配置错误引爆DN42。 因此我决定冒险一下 节点拓扑 如图,其中A-F分别代表6个不同的节点: graph LR A[A<br>172.20.234.225<br>fd18:3e15:61d0::1] B[B<br>172.20.234.226<br>fd18:3e15:61d0::2] C[C<br>172.20.234.227<br>fd18:3e15:61d0::3] D[D<br>172.20.234.228<br>fd18:3e15:61d0::4] E[E<br>172.20.234.229<br>fd18:3e15:61d0::5] F[F<br>172.20.234.230<br>fd18:3e15:61d0::6] C <--> F C <--> E E <--> A C <--> A A <--> D A <--> F F <--> B D <--> B C <--> D D <--> F 更新Bird2至v2.16及以上 因为我希望使用IPv6 Link-Local地址传递IPv4的OSPF数据,而Bird在2.16及以后才支持这项功能,因此需要更新至v2.16。如果你不希望更新,可以先跳过此步骤。 使用以下指令安装最新版本的Bird2: sudo apt update && sudo apt -y install apt-transport-https ca-certificates wget lsb-release sudo wget -O /usr/share/keyrings/cznic-labs-pkg.gpg https://pkg.labs.nic.cz/gpg echo "deb [signed-by=/usr/share/keyrings/cznic-labs-pkg.gpg] https://pkg.labs.nic.cz/bird2 $(lsb_release -sc) main" | sudo tee /etc/apt/sources.list.d/cznic-labs-bird2.list sudo apt update && sudo apt install bird2 -y 配置隧道 [Interface] PrivateKey = <本地WireGuard私钥> ListenPort = <监听端口> Table = off Address = <IPv6 LLA>/64 PostUp = sysctl -w net.ipv6.conf.%i.autoconf=0 [Peer] PublicKey = <对端公钥> Endpoint = <对端公网接入点> AllowedIPs = 10.0.0.0/8, 172.20.0.0/14, 172.31.0.0/16, fd00::/8, fe00::/8, ff02::5 ff02::5是OSPFv3路由器专用的链路本地范围组播地址,需要添加进AllowedIPs。 如果你正在使用v2.16以前的Bird,请再为隧道配置一个IPv4地址,不一定非要是DN42 IPv4,其他私有地址也可以。请参考: {collapse} {collapse-item label="包含IPv4的WireGuard配置示例"} [Interface] PrivateKey = <本地WireGuard私钥> ListenPort = <监听端口> Table = off Address = <IPv6 LLA>/64 PostUp = ip addr add 100.64.0.225/32 peer 100.64.0.226/32 dev %i PostUp = sysctl -w net.ipv6.conf.%i.autoconf=0 [Peer] PublicKey = <对端公钥> Endpoint = <对端公网接入点> AllowedIPs = 10.0.0.0/8, 172.20.0.0/14, 100.64.0.0/16, 172.31.0.0/16, fd00::/8, fe00::/8, ff02::5 请将100.64.0.225、100.64.0.226替换为你本机的IPv4和对端的IPv4,并且记得加入AllowedIPs。 {/collapse-item} {/collapse} 启用OSPF 默认你已经配置好了如上一篇文章所写的bird基础配置 在/etc/bird下新建一个名为ospf.conf的文件,填入如下内容: protocol ospf v3 <name> { ipv4 { import where is_self_net() && source != RTS_BGP; export where is_self_net() && source != RTS_BGP; }; include "/etc/bird/ospf/*"; }; protocol ospf v3 <name> { ipv6 { import where is_self_net_v6() && source != RTS_BGP; export where is_self_net_v6() && source != RTS_BGP; }; include "/etc/bird/ospf/*"; }; 理论上来说应该使用OSPF v2处理IPv4,但是因为需要通过IPv6 LLA地址通信IPv4,因此此处IPv4也使用OSPF v3。 过滤规则保证只有本网段内的路由能够通过OSPF传递,并且过滤掉外部BGP协议的路由 千万不要随意使用import all;export all;,有可能会导致路由劫持并影响到整个DN42网络。OSPF只应该处理网段内部的路由。 {collapse} {collapse-item label="配置示例"} /etc/bird/ospf.conf protocol ospf v3 dn42_iyoroynet_ospf { ipv4 { import where is_self_net() && source != RTS_BGP; export where is_self_net() && source != RTS_BGP; }; include "/etc/bird/ospf/*"; }; protocol ospf v3 dn42_iyoroynet_ospf6 { ipv6 { import where is_self_net_v6() && source != RTS_BGP; export where is_self_net_v6() && source != RTS_BGP; }; include "/etc/bird/ospf/*"; }; {/collapse-item} {/collapse} 接着,新建/etc/bird/ospf文件夹,在其中创建area配置文件(如:/etc/bird/ospf/0.conf),填写区域信息: area 0.0.0.0 { interface "<DN42 dummy网卡>" { stub; }; interface "<wg0网卡名称>" { cost 80; # 按照你的网络情况修改 type ptp; }; interface "<wg1网卡名称>" { cost 100; # 按照你的网络情况修改 type ptp; }; # 以此类推 }; 0.0.0.0区域代表骨干网 此处dummy网卡指上一篇文章中所写的DN42虚拟网卡 cost值本应该是用于开销计算,但在DN42这种对带宽要求不大而对延迟较为敏感的场景下可以直接填写延迟,OSPF会自动走开销值之和最短的路由。 {collapse} {collapse-item label="配置示例"} /etc/bird/ospf/0.conf area 0.0.0.0 { interface "dn42" { stub; }; interface "dn42_hkg" { cost 80; type ptp; }; interface "dn42_hfe" { cost 150; type ptp; }; interface "dn42_lax"{ cost 100; type ptp; }; }; {/collapse-item} {/collapse} 最后,打开/etc/bird/bird.conf,在末尾引入OSPF的配置文件: include "ospf.conf"; 运行birdc configure,然后birdc show protocols应该就能看到OSPF的状态是Running了。如果不是,请检查配置步骤是否出错。 此时,在非直连的两台机器上互相ping应该就能通了: 配置iBGP 在从多个地点建立对等连接之前,您的各个节点必须首先完整掌握自身网络的拓扑结构。除了所有外部 BGP 连接外,这还需要配置另一个关键组件:内部 BGP(即 iBGP)。 必要性 iBGP可以保证AS内部所有运行BGP的路由器都能获知到达外部目的地的完整BGP路由信息,进而确保: 内部路由器可以选择最优的出口路径。 流量能够被正确地引导到负责连接特定外部网络的边界路由器。 即使存在多个边界路由器连接到同一个外部网络,内部路由器也能根据策略选择最佳出口。 相比于在AS内部使用默认路由指向边界路由器,iBGP提供了精确的外部路由信息,使得内部路由器能做出更智能的转发决策。 缺点与解决方案 为了防止路由信息在AS内部无控制地扩散导致环路,iBGP路由器不会将从某个iBGP邻居学到的路由再通告给其他iBGP邻居,这就要求传统的iBGP要求在同一个AS内所有运行iBGP的路由器之间必须建立全网状的iBGP邻居关系(Full Mesh)。(还是要建立$\frac{n(n+1)}{2}$条连接 ,没办法。不过OSPF起来之后iBGP配置还是比配置隧道简单的 ) 解决方案就是: 使用路由反射器(Route Reflector, RR): 由RR路由器管理整个AS内部所有的路由信息,缺点就是RR路由器故障将会导致整个网络瘫痪(这很不Decentralized) 通过BGP联盟(BGP Confederation) 搭建内部网络: 将AS内的路由器虚拟成一个个子AS,再把各个路由器之间的连接当作BGP处理,最后向外传递的时候抹去内部AS的路由路径。 后面两种方案我没有尝试过,下面是一些可能有用的参考文章。本文着重讨论iBGP的配置。 DN42 实验网络介绍及注册教程(2022-12 更新) - Lan Tian @ Blog Bird 配置 BGP Confederation,及模拟 Confederation(2020-06-07 更新) - Lan Tian @ Blog 编写iBGP配置文件 在/etc/bird下新建文件ibgp.conf,填入如下内容: template bgp ibgpeers { local as OWNAS; ipv4 { import where source = RTS_BGP && is_valid_network() && !is_self_net(); export where source = RTS_BGP && is_valid_network() && !is_self_net(); next hop self; extended next hop; }; ipv6 { import where source = RTS_BGP && is_valid_network_v6() && !is_self_net_v6(); export where source = RTS_BGP && is_valid_network_v6() && !is_self_net_v6(); next hop self; }; }; include "ibgp/*"; 导入和导出规则确保iBGP仅处理BGP协议学到的路由,并且过滤掉IGP的路由防止环回 next hop self是必须的,指示 BIRD 在向 iBGP 邻居导出路由时,将下一跳重写为边界路由器自身的IP地址(而非原始的外部下一跳)。因为内部路由器无法直接访问外部邻居地址,若不重写则会被认定为地址不可达。重写后,内部路由器只需通过 IGP 路由将流量送至边界路由器,由边界路由器完成最终的外部转发。 因为我希望使用IPv6地址建立MP-BGP,通过IPv6路由IPv4,因此在IPv4中启用了extended next hop 接着创建/etc/bird/ibgp文件夹,在其中为每台节点都创建一个iBGP Peer配置文件: protocol bgp 'dn42_ibgp_<节点>' from ibgpeers{ neighbor <对应节点的IPv6 ULA地址> as OWNAS; }; {collapse} {collapse-item label="样例"} /etc/bird/ibgp/hkg.conf: protocol bgp 'dn42_ibgp_HKG' from ibgpeers{ neighbor fd18:3e15:61d0::1 as OWNAS; }; {/collapse-item} {/collapse} 注意:每个节点上都需要建立(n-1)个iBGP连接,保证和AS内其他所有机器都建立连接,这也是为什么需要使用ULA地址 使用ULA地址确保即使两个节点之间的WireGuard断开,iBGP仍然能通过OSPF建立的内部路由建立,否则将会导致整个内部网络的崩溃 最后,在/etc/bird/bird.conf中加入对ibgp.conf的引入: include "ibgp.conf"; 并运行birdc configure应用配置即可。 参考文章: BIRD 与 BGP 的新手开场 - 海上的宫殿 萌新入坑 DN42 之 —— 基于 tailscale + vxlan + OSPF 的组网 – 米露小窝 使用 Bird2 配置 WireGuard + OSPF 实现网络的高可用 | bs' realm DN42 实验网络介绍及注册教程(2022-12 更新) - Lan Tian @ Blog 如何引爆 DN42 网络(2023-05-12 更新) - Lan Tian @ Blog Bird 配置 BGP Confederation,及模拟 Confederation(2020-06-07 更新) - Lan Tian @ Blog 深入解析OSPF路径开销、优先级和计时器 - 51CTO New release 2.16 | BIRD Internet Routing Daemon 第一章·第二节 如何在 Linux 上安装最新版本的 BIRD? | BIRD 中文文档 [DN42] 使用 OSPF ptp 搭建内网与IBGP配置 – Xe_iu's Blog | Xe_iu的杂物间 [译] dn42 多服务器环境中的 iBGP 与 IGP 配置 | liuzhen932 的小窝
2025年07月22日
109 阅读
1 评论
1 点赞
DN42探究日记 - Ep.1 加入DN42网络
写在前面 本人是BGP小白,文章中可能会存在不严谨内容/小白理解/低级错误,请诸位大佬们手下留情。若发现存在问题,您愿意的话可以邮件联系我,我会在第一时间更正。如果您不能接受,建议现在就关闭此文章。 欢迎与我建立对等连接!详情请查看:iYoRoy DN42 Network 想研究BGP,奈何租一个ASN和IP段实在是太贵了,又怕自己因为配置错误干掉半个互联网,因此决定研究一下DN42这个虚拟的网络。DN42是个大型去中心化网络,使用BGP协议建立路由,和当今互联网的结构很相像,因此适合用于BGP等网络技术学习。在DN42中,每个人都将扮演ISP(网络服务提供商)的角色,和其他用户Peer,以加入并参与建设整个DN42网络。DN42运行在172.20.0.0/14和fd00::/8上,这两个地址都是内网地址,因此不会影响到正常的互联网。 注册 你需要会使用基础的git指令、GPG、Linux,并且最好启用GPG签名Commit。 有Git使用基础的话可以参考我的commit:Add AS4242422024 · d1f9046ecb - registry - dn42 git Fork并克隆DN42注册表Git仓库 在dn42 git注册一个账号,并且Fork dn42/registry仓库。Clone下Fork出来的仓库并进入。 注册联系人 在data/person下创建文件<昵称>-DN42,填入如下内容: person: <姓名> e-mail: <邮箱> pgp-fingerprint: <GPG密钥指纹> nic-hdl: <NIC 句柄> mnt-by: <维护者> source: DN42 person: 名称 e-mail: 邮箱 pgp-fingerprint: GPG密钥指纹,会被用于一些认证服务 nic-hdl: NIC句柄,指向文件本身,直接填写当前文件名即可 mnt-by: 由谁维护,指向下文注册维护者一节中的维护者信息 source: 来源,保持DN42即可 www: 可选,可填网页地址 {collapse} {collapse-item label="示例"} data/person/IYOROY-DN42 @ dn42/registry@master person: Kagura iYoRoy e-mail:
[email protected]
www: https://www.iyoroy.cn pgp-fingerprint: 3ECCFFDEC2CB4CB8DA8089BE9AF2F2E03CE8FD67 nic-hdl: IYOROY-DN42 mnt-by: IYOROY-MNT source: DN42 {/collapse-item} {/collapse} 注册维护者 创建文件data/mntner/<昵称>-MNT,并填入如下内容: mntner: <昵称>-MNT admin-c: <联系人> tech-c: <联系人> auth: <验证方式> mnt-by: <维护者> source: DN42 mntner: 维护者名称,一般与文件名相同即可 admin-c: 管理员联系信息,指向person文件夹中的文件,这里填上文注册联系人一节里的文件名即可 tech-c: 技术人员联系信息,指向person文件夹中的文件,这里填上文注册联系人一节里的文件名即可 auth: 验证方式,支持pgp或者ssh-key mnt-by: 由谁维护,一般指向文件名本身即可 source: 来源,保持DN42即可 {collapse} {collapse-item label="示例"} data/mntner/IYOROY-MNT @ dn42/registry@master mntner: IYOROY-MNT admin-c: IYOROY-DN42 tech-c: IYOROY-DN42 auth: pgp-fingerprint 3ECCFFDEC2CB4CB8DA8089BE9AF2F2E03CE8FD67 mnt-by: IYOROY-MNT source: DN42 {/collapse-item} {/collapse} 注册ASN 在公网上,4200000000 - 4294967294为ASN保留范围。DN42使用了4242420000 - 4242429999,而目前开放注册的是4242420000 - 4242423999。官方不建议自己寻找可用ASN,而是推荐使用Burble的DN42 Free ASN Explorer,从中选取可用的ASN注册。 找好心仪的ASN后在data/aut-num创建<ASN,包含AS字母>文件,填写如下内容: aut-num: <ASN> as-name: <自治系统名称> descr: <自治系统描述> admin-c: <管理员NIC句柄> tech-c: <技术人员NIC句柄> mnt-by: <维护者> source: DN42 aut-num: 你选择的ASN,包含AS前缀。应该是AS424242xxxx的样式 as-name: 自治系统名称 descr: 自治系统描述,可以有空格 admin-c: 管理员联系信息,指向person文件夹中的文件,这里填上文注册联系人一节里的文件名即可 tech-c: 技术人员联系信息,指向person文件夹中的文件,这里填上文注册联系人一节里的文件名即可 mnt-by: 由谁维护,指向上文创建维护者一节中的文件名 source: 来源,保持DN42即可 {collapse} {collapse-item label="示例"} data/aut-num/AS4242422024 @ dn42/registry@master aut-num: AS4242422024 as-name: IYOROYNET-AS-DN42 descr: iYoRoy DN42 Network admin-c: IYOROY-DN42 tech-c: IYOROY-DN42 mnt-by: IYOROY-MNT source: DN42 {/collapse-item} {/collapse} 注册IPv4地址块并添加路由 如果你不想要注册IPv4,可以忽略本节 官方提供了一个用于检索可用地址块的工具:DN42 Free IPv4 Explorer 。同样不建议手动指定,而是建议用检索工具检索出来的可用地址块。 DN42同样面临IPv4地址短缺,所以请尽量按需注册。一般而言,一个/27地址块包含30个IPv4地址就够用了,如果是小型网络可以申请/28(14个可用地址)和/29(6个可用地址)。能直接申请的地址块最大是/26,也就是62个地址,若申请/25、/24则需要提交申请然后等待审核。详情可参考:DN42 实验网络介绍及注册教程(2022-12 更新) - Lan Tian @ Blog 选定你的IPv4地址块,然后在data/inetnum创建一个文件,命名为IPv4地址块的CIDR格式,并使用_代替/(如:我申请的IPv4地址块为172.20.234.224/28,则文件名为172.20.234.224_28),填入内容: inetnum: <IPv4地址块第一个地址> - <IPv4地址块最后一个地址> cidr: <IPv4地址块CIDR格式> netname: <IPv4地址块名称> descr: <IPv4地址块描述> country: <IPv4地址块所属国家代码> admin-c: <管理员NIC句柄> tech-c: <技术人员NIC句柄> mnt-by: <维护者> status: ASSIGNED source: DN42 inetnum: IPv4地址范围,从第一个地址到最后一个地址,中间用-连接 cidr: IPv4地址块CIDR格式,不需要用_代替/ netname: IPv4地址块名称,自行填写即可,无特殊要求 descr: IPv4地址块描述,中间可以有空格 country: ISO 3166中的两字符国家代码,中国就填CN admin-c: 管理员联系信息,指向person文件夹中的文件,这里填上文注册联系人一节里的文件名即可 tech-c: 技术人员联系信息,指向person文件夹中的文件,这里填上文注册联系人一节里的文件名即可 mnt-by: 由谁维护,指向上文创建维护者一节中的文件名 status: 状态,保存ASSIGNED即可 source: 来源,保持DN42即可 {collapse} {collapse-item label="示例"} data/inetnum/172.20.234.224_28 @ dn42/registry@master inetnum: 172.20.234.224 - 172.20.234.239 cidr: 172.20.234.224/28 netname: IYOROYNET-DN42-V4 descr: iYoRoy DN42 Network IPv4 Block country: CN admin-c: IYOROY-DN42 tech-c: IYOROY-DN42 mnt-by: IYOROY-MNT status: ASSIGNED source: DN42 {/collapse-item} {/collapse} 接着,在data/route下同样创建一个名为IPv4地址块的 CIDR 格式,并使用_代替/的文件,填入内容: route: <IPv4地址CIDR格式> origin: <ASN> max-length: <IPv4掩码> mnt-by: <维护者> source: DN42 route: IPv4地址块,填写CIDR格式,无需转换/ origin: ASN,需要带AS max-lenth: 前缀长度(Prefix Length),即CIDR格式中/后面的数字 mnt-by: 由谁维护,指向上文创建维护者一节中的文件名 source: 来源,保持DN42即可 {collapse} {collapse-item label="示例"} data/route/172.20.234.224_28 @ dn42/registry@master route: 172.20.234.224/28 origin: AS4242422024 max-length: 28 mnt-by: IYOROY-MNT source: DN42 {/collapse-item} {/collapse} 注册IPv6地址块并添加路由 如果你不想要注册IPv6,可以忽略本节 同样使用官方工具检索可用IPv6:DN42 Free IPv6 Explorer 。 选定地址块后在data/inet6num下创建名为IPv6地址块的CIDR格式,并使用_代替/的文件(如:我的IPv6地址块为fd18:3e15:61d0::/48,则文件名fd18:3e15:61d0::_48),填入内容: inet6num: <IPv6地址块第一个地址> - <IPv6地址块最后一个地址> cidr: <IPv6地址块CIDR格式> netname: <IPv6地址块名称> descr: <IPv6地址块描述> country: <IPv6地址块所属国家代码> admin-c: <管理员NIC句柄> tech-c: <技术人员NIC句柄> mnt-by: <维护者> status: ASSIGNED source: DN42 inet6num: IPv6地址范围,从第一个地址到最后一个地址,不可使用::简写,中间用-连接。也就是说,比如我的地址块是fd18:3e15:61d0::/48,我需要填入fd18:3e15:61d0:0000:0000:0000:0000:0000 - fd18:3e15:61d0:ffff:ffff:ffff:ffff:ffff。 cidr: IPv6地址块CIDR格式,不需要用_代替/ netname: IPv6地址块名称,自行填写即可,无特殊要求 descr: IPv6地址块描述,中间可以有空格 country: ISO 3166中的两字符国家代码,中国就填CN admin-c: 管理员联系信息,指向person文件夹中的文件,这里填上文注册联系人一节里的文件名即可 tech-c: 技术人员联系信息,指向person文件夹中的文件,这里填上文注册联系人一节里的文件名即可 mnt-by: 由谁维护,指向上文创建维护者一节中的文件名 status: 状态,保存ASSIGNED即可 source: 来源,保持DN42即可 {collapse} {collapse-item label="示例"} data/inet6num/fd18:3e15:61d0::_48 @ dn42/registry@master inet6num: fd18:3e15:61d0:0000:0000:0000:0000:0000 - fd18:3e15:61d0:ffff:ffff:ffff:ffff:ffff cidr: fd18:3e15:61d0::/48 netname: IYOROYNET-DN42-V6 descr: iYoRoy DN42 Network IPv6 Block country: CN admin-c: IYOROY-DN42 tech-c: IYOROY-DN42 mnt-by: IYOROY-MNT status: ASSIGNED source: DN42 {/collapse-item} {/collapse} 接着,在data/route6下同样创建一个名为IPv6地址块的 CIDR 格式,并使用_代替/的文件,填入内容: route6: <IPv6地址CIDR格式> origin: <ASN> max-length: <IPv6掩码> mnt-by: <维护者> source: DN42 route6: IPv6地址块,填写CIDR格式,无需转换/ origin: ASN,需要带AS max-lenth: 前缀长度(Prefix Length),即CIDR格式中/后面的数字 mnt-by: 由谁维护,指向上文创建维护者一节中的文件名 source: 来源,保持DN42即可 {collapse} {collapse-item label="示例"} data/route6/fd18:3e15:61d0::_48 @ dn42/registry@master route6: fd18:3e15:61d0::/48 origin: AS4242422024 max-length: 48 mnt-by: IYOROY-MNT source: DN42 {/collapse-item} {/collapse} 创建并上传commit,提交PR 最好使用GPG签名你的commit并且在dn42 git里上传你的公钥 填完上述信息,回到仓库根目录下,运行脚本./fmt-my-stuff <维护者>自动格式化配置文件。注意:此处<维护者>是上文注册维护者章节中的mntner的值。接着按照正常git commit流程git add data/、git commit -S -m "<commit-msg>"创建commit,git push origin master推送,接着,来到dn42 git网页端,打开你Fork的仓库并提交Pull Request即可。 如果配置有问题,自动审查机器人和管理员会告知你,请耐心按照要求修改并且合并到原来的commit中,不要新开commit,推荐add后使用git commit --amend指令。修改完直接强制推送(git push origin master --force) 即可。 DN42 Registry 的工作语言是英语。请使用英语完成全部流程,以免出现不必要的麻烦。 配置Bird 首先安装bird,以Ubuntu22.04为例: apt install bird2 -y 如果要一并安装后续使用的WireGuard,就再加上wireguard、wireguard-tools软件包: apt install bird2 wireguard wireguard-tools -y 编写配置文件 bird.conf 修改/etc/bird/bird.conf: define OWNAS = <AS 号>; define OWNIP = <DN42 IPv4 地址>; define OWNIPv6 = <DN42 IPv6 地址>; define OWNNET = <DN42 IPv4 地址块, CIDR 格式>; define OWNNETv6 = <DN42 IPv6 地址块, CIDR 格式>; define OWNNETSET = [ <DN42 IPv4 地址块, CIDR 格式>+ ]; define OWNNETSETv6 = [ <DN42 IPv6 地址块, CIDR 格式>+ ]; router id OWNIP; protocol device { scan time 10; } function is_self_net() { return net ~ OWNNETSET; } function is_self_net_v6() { return net ~ OWNNETSETv6; } function is_valid_network() { return net ~ [ 172.20.0.0/14{21,29}, # dn42 172.20.0.0/24{28,32}, # dn42 Anycast 172.21.0.0/24{28,32}, # dn42 Anycast 172.22.0.0/24{28,32}, # dn42 Anycast 172.23.0.0/24{28,32}, # dn42 Anycast 172.31.0.0/16+, # ChaosVPN 10.100.0.0/14+, # ChaosVPN 10.127.0.0/16{16,32}, # neonetwork 10.0.0.0/8{15,24} # Freifunk.net ]; } function is_valid_network_v6() { return net ~ [ fd00::/8{44,64} # ULA address space as per RFC 4193 ]; } protocol kernel { scan time 20; ipv6 { import none; export filter { if source = RTS_STATIC then reject; krt_prefsrc = OWNIPv6; accept; }; }; }; protocol kernel { scan time 20; ipv4 { import none; export filter { if source = RTS_STATIC then reject; krt_prefsrc = OWNIP; accept; }; }; } protocol static { route OWNNET reject; ipv4 { import all; export none; }; } protocol static { route OWNNETv6 reject; ipv6 { import all; export none; }; } include "rpki.conf"; include "ebgp.conf"; 此处OWNIP和OWNIPV6参数意为本机的DN42 IPv4和IPv6地址,不是地址块的地址,比如我申请到的地址段是172.20.234.224/28,我给A机器分配了172.20.234.225,则OWNIP为172.20.234.225,IPv6同理。 rpki.conf 你可能在其他教程里看到过使用定时任务+重载Bird的更新ROA方案,此处配置RPKI则是另一种配置ROA的方式。 创建/etc/bird/rpki.conf,填写如下内容: roa4 table dn42_roa; roa6 table dn42_roa_v6; protocol rpki dn42_rpki_akix { roa4 { table dn42_roa; }; roa6 { table dn42_roa_v6; }; remote "<rpki服务器地址>" port 8082; # change it refresh 30; retry 5; expire 600; } RPKI服务器可以使用我朋友的AkaereIX提供的服务:rpki.akae.re {collapse} {collapse-item label="样例"} roa4 table dn42_roa; roa6 table dn42_roa_v6; protocol rpki dn42_rpki_akix { roa4 { table dn42_roa; }; roa6 { table dn42_roa_v6; }; remote "rpki.akae.re" port 8082; refresh 30; retry 5; expire 600; } {/collapse-item} {/collapse} ebgp.conf 创建/etc/bird/ebgp.conf,填入如下内容: template bgp dnpeers { local as OWNAS; path metric 1; ipv4 { import filter { if is_valid_network() && !is_self_net() then { if (roa_check(dn42_roa, net, bgp_path.last) != ROA_VALID) then { print "[dn42] ROA check failed for ", net, " ASN ", bgp_path.last; reject; } accept; } reject; }; export filter { if is_valid_network() && source ~ [RTS_STATIC, RTS_BGP] then accept; reject; }; import limit 1000 action block; }; ipv6 { import filter { if is_valid_network_v6() && !is_self_net_v6() then { if (roa_check(dn42_roa_v6, net, bgp_path.last) != ROA_VALID) then { print "[dn42] ROA check failed for ", net, " ASN ", bgp_path.last; reject; } accept; } reject; }; export filter { if is_valid_network_v6() && source ~ [RTS_STATIC, RTS_BGP] then accept; reject; }; import limit 1000 action block; }; } include "peers/*"; 此配置项定义了DN42内部互相peer的模板,并且引用/etc/bird/peers下的所有配置文件,之后我们peer的时候就只需要在这里按照模板创建配置文件并编写即可。 创建/etc/bird/peers文件夹用作后续peer。 系统配置 内核 因为每个节点都可能会作为其他节点的路由器使用,因此需要打开Linux内核数据包转发;同时因为使用了WireGuard,并不是通过物理网卡转发,因此需要关闭rp_filter严格模式。 echo "net.ipv4.ip_forward=1" >> /etc/sysctl.conf echo "net.ipv6.conf.default.forwarding=1" >> /etc/sysctl.conf echo "net.ipv6.conf.all.forwarding=1" >> /etc/sysctl.conf echo "net.ipv4.conf.default.rp_filter=0" >> /etc/sysctl.conf echo "net.ipv4.conf.all.rp_filter=0" >> /etc/sysctl.conf sysctl -p DN42虚拟网卡 因为MP-BGP通常使用LLA地址建立BGP,因此我们需要在系统里设置一个dummy网卡并绑定我们给这台机器分配的DN42 IP。运行以下指令: ip link add dn42 type dummy ip addr add <你给这这台机器分配的DN42 IPv4> dev dn42 ip addr add <你给这这台机器分配的DN42 IPv6> dev dn42 如果需要持久化配置,可以参考以下三种方式: {tabs} {tabs-pane label="systemd-networkd"} tee /etc/systemd/network/10-dn42.netdev > /dev/null <<EOF [NetDev] Name=dn42 Kind=dummy EOF tee /etc/systemd/network/20-dn42.network > /dev/null <<EOF [Match] Name=dn42 [Network] Address=<你给这台机器分配的DN42 IPv4>/32 Address=<你给这台机器分配的DN42 IPv6>/128 EOF systemctl enable systemd-networkd systemctl restart systemd-networkd {/tabs-pane} {tabs-pane label="netplan"} tee /etc/netplan/99-dn42.yaml > /dev/null <<EOF network: version: 2 renderer: networkd ethernets: dn42: match: name: dn42 addresses: - <你给这台机器分配的DN42 IPv4>/32 - "<你给这台机器分配的DN42 IPv6>/128" accept-ra: no EOF netplan apply {/tabs-pane} {tabs-pane label="/etc/network/interfaces"} tee -a /etc/network/interfaces > /dev/null <<EOF auto dn42 iface dn42 inet static address <你给这台机器分配的DN42 IPv4> netmask 255.255.255.255 iface dn42 inet6 static address <你给这台机器分配的DN42 IPv6>/128 EOF ifup dn42 {/tabs-pane} {/tabs} 与其他成员Peer 对新手较友好的应该就是Potat0大佬的自助Peer服务了,详情可参考他的DN42 Network页面。按照指引找到他的自动对等连接机器人,按照要求在机器人上注册你的账号,需要提供你的DN42 ASN、上文注册时Maintainer里记录的邮箱(这也是为什么在注册的时候最好需要填邮箱,很多验证服务都会使用),并且用该邮箱接收验证码,然后按照机器人的要求建立peer即可。以下是我通过Bot建立peer的过程,全程使用Ubuntu22.04系统的香港VPS操作。 安装WireGuard apt install wireguard wireguard-tools -y 注:现在的软件包管理一般会在安装wireguard的时候自动安装wireguard-tools以使用wg-quick指令。 生成密钥对 wg genkey | tee privatekey | wg pubkey > publickey 记下privatekey、publickey中的内容,代表私钥和公钥 建立Peer 一般而言有两种建立Peer的模式,即使用MP-BGP(Multiprotocol BGP,多协议BGP)和不使用MP-BGP。个人感觉MP-BGP更为常用,因为其配置较为简单。两种配置稍有不同,请根据你的需求参考。 使用MP-BGP 与Peer对方交换信息 你需要提供对方以下信息,同时你也需要知道对方的以下信息: 公钥 公网地址(非DN42地址) 公网WireGuard端口,一般是监听对方ASN的后5位 DN42 ASN LLA(Link-Local Address)地址,一般而言是fe80::<对方ASN后4位> 是否支持ENH(Extended Next Hop),注意,若使用v6交换路由而不启用ENH则无法交换v4路由 也有时会将公网地址和公网wg端口放在一起称作Endpoint。 配置WireGuard 在/etc/wireguard下创建一个配置文件,名称随意,但是我的命名习惯是dn42-<对方ASN后4位>.conf,其中dn42-xxxx即为隧道名。往文件内填入如下内容: [Interface] PrivateKey = <上文「生成密钥对」章节生成的私钥> ListenPort = <公网WireGuard监听端口> Table = off Address = <你的LLA地址>/64 PostUp = sysctl -w net.ipv6.conf.%i.autoconf=0 [Peer] PublicKey = <对方给你的公钥> Endpoint = <对方的Endpoint,即IP:端口> AllowedIPs = 10.0.0.0/8, 172.20.0.0/14, 172.31.0.0/16, fd00::/8, fe00::/8 编辑完成后保存,运行: wg-quick up <隧道名> 即可启动wg隧道。使用wg show <隧道名>即可查看连接状态。直接运行wg可查看所有隧道状态 如果需要让隧道开机自启动,可以运行: systemctl enable wg-quick@<隧道名> 配置Bird2的Peer部分 在/etc/bird/peers下新建文件<名称>.conf,填入如下内容: protocol bgp <BGP会话名称> from dnpeers{ neighbor <对方LLA地址> % '<WireGuard隧道名>' as <对方ASN,不带AS前缀>; }; 如果使用使用了Extended next hop(如上图交换信息时协商的),则配置: protocol bgp <BGP会话名称> from dnpeers{ neighbor <对方LLA地址> % '<WireGuard隧道名>' as <对方ASN,不带AS前缀>; ipv4{ extended next hop; }; }; 应用配置 运行birdc configure(或者birdc c,等同)重载Bird配置,然后运行birdc show protocols(或者birdc s p,等同)即可查看当前建立的BGP连接。 root@hkg2-202501092021514df2f0:~# birdc show protocols BIRD 2.0.12 ready. Name Proto Table State Since Info device1 Device --- up 07:24:14.255 static1 Static dn42_roa up 07:24:14.255 static2 Static dn42_roa_v6 up 07:24:14.255 kernel1 Kernel master6 up 07:24:14.255 kernel2 Kernel master4 up 07:24:14.255 static3 Static master4 up 07:24:14.255 static4 Static master6 up 07:24:14.255 dn42-0298 BGP --- up 08:03:13.347 Established dn42-1816 BGP --- up 07:53:05.028 Established 不使用MP-BGP 与Peer对方交换信息 你需要提供对方以下信息,同时你也需要知道对方的以下信息: 公钥 公网地址(非DN42地址) 公网WireGuard端口,一般是监听对方ASN的后5位 DN42 ASN DN42 IP,如果交换IPv4路由则需要IPv4地址,如果交换IPv6路由则需要IPv6地址 也有时会将公网地址和公网wg端口放在一起称作Endpoint。 配置WireGuard 在/etc/wireguard下创建一个配置文件,名称随意,但是我的命名习惯是dn42-<对方ASN后4位>.conf,其中dn42-xxxx即为隧道名。往文件内填入如下内容: [Interface] PrivateKey = <上文「生成密钥对」章节生成的私钥> ListenPort = <公网WireGuard监听端口> Table = off PostUp = ip addr add <LLA>/64 dev %i PostUp = ip addr add <本地DN42 IPv6> dev %i PostUp = ip addr add <本地DN42 IPv4> peer <对方DN42 IPv4> dev %i PostUp = sysctl -w net.ipv6.conf.%i.autoconf=0 [Peer] PublicKey = <对方给你的公钥> Endpoint = <对方的Endpoint,即IP:端口> AllowedIPs = 10.0.0.0/8, 172.20.0.0/14, 172.31.0.0/16, fd00::/8, fe00::/8 编辑完成后保存,运行: wg-quick up <隧道名> 即可启动wg隧道。使用wg show <隧道名>即可查看连接状态。直接运行wg可查看所有隧道状态 如果需要让隧道开机自启动,可以运行: systemctl enable wg-quick@<隧道名> 配置Bird2的Peer部分 在/etc/bird/peers下新建文件<名称>.conf,填入如下内容: protocol bgp <v4BGP会话名称> from dnpeers{ neighbor <对方DN42 IPv4地址> as <对方ASN,不带AS前缀>; direct; ipv6{ import none; export none; }; }; protocol bgp <v6BGP会话名称> from dnpeers{ neighbor <对方DN42 IPv6地址> % '<WireGuard隧道名称>' as <对方ASN,不带AS前缀>; direct; ipv4{ import none; export none; }; }; 应用配置 运行birdc configure(或者birdc c,等同)重载Bird配置,然后运行birdc show protocols(或者birdc s p,等同)即可查看当前建立的BGP连接。 自此,我们成功加入了DN42网络。要想让网络更加稳定,我们可以与更多用户进行Peer,建立多条BGP线路以防止其中部分节点瘫痪导致失联。你可以加入DN42非官方tg交流群获取更多信息。 如果出现BGP Established但是无法Ping通DN42内部IP的情况,请检查bird.conf中设置的IP和dummy网卡分配的IP或WireGuard中的本地IP是否相同。 配置DNS DN42内有自己的公共DNS,泛播地址为172.20.0.53,并且也能解析正常互联网的域名。要想能够访问以dn42结尾的内部域名,需要将这个地址放到resolv.conf最上面: nameserver 172.20.0.53 nameserver 223.5.5.5 #下面是正常的DNS服务器配置 之后就可以解析DN42内部域名啦,同时ping、traceroute、mtr等命令查询内部IP时也能显示出来rDNS的解析结果。 欢迎与我建立对等连接!详情请查看:iYoRoy DN42 Network 参考文章: https://blog.baoshuo.ren/post/dn42-network/ https://dn42.dev/howto/Bird2#example-configuration https://dn42.eu/howto/wireguard https://blog.udon.eu.org/archives/dbf21067.html https://blog.byteloid.one/2025/06/02/babeld-over-wireguard/ https://blog.wcysite.com/2021/%E8%B8%A9%E5%9D%91DN42-p2-peer/ https://blog.chs.pub/p/23-14-joindn42/ https://www.cnblogs.com/FengZeng666/p/15583434.html
2025年06月28日
102 阅读
3 评论
1 点赞
跨平台服务编写日记 Ep.2 进程间通讯(IPC)
前情提要 上一篇文章实现了统一的日志管理,这篇文章来实现进程间消息通讯,即IPC。 分析 Windows 在Windows下,主要通过管道(Pipe)实现进程间通讯。管道又分为命名管道(Named Pipe)和匿名管道(Anonymous Pipe)。其中,匿名管道是单向的,通常在父进程和子进程之间通讯[2]。而命名管道则可以是单向管道或双工管道,并且支持一对多通讯[3]。顾名思义,识别命名管道的唯一方式是它的名称,因此两个进程只要都连接到同一个名字的命名管道即可实现通信。 我们需要实现进程间的双向通讯,因此采用命名管道。大致思路就是:进程作为伺服模式,也就是接收端启动时创建一个线程,创建一个命名管道并监听管道内消息。当管道被连接时从中读取管道内数据;当进程作为发送端启动时尝试连接到同一个名称的管道,并写入消息内容。 Linux 在Linux下通常使用socket进行进程间通讯。不过不同于监听端口,进程间通讯一般会选择监听一个sock文件[5],常见的服务类应用如docker daemon、mysql都是通过这种方式。 因此,大致思路如下:作为伺服模式启动的进程创建一个socket监听,并等待从中接收消息;发送端连接到socket套接字并发送消息。和上文命名管道的名称类似,socket套接字会映射一个唯一的.sock文件,发送方只要打开这个文件即可发送消息。(实际上打开方式不是常规的打开文件,而是用socket专用的打开方式[5]) 代码实现 初始化 为了实现共用一套主代码,我使用了和上一篇文章中一样的通过宏定义区分系统类型的方案,将Windows和Linux的代码分别写在service-windows.h和service-linux.h两个头文件中: #ifdef _WIN32 #include "service-windows.h" #elif defined(__linux__) #include "service-linux.h" #endif 当接收端进程启动时,创建一个线程处理收信息(使用std::thread作为多线程库): thread_bind = std::thread(bind_thread_main); 监听部分 Windows 在Windows下,只要尝试从指定名称的命名管道读取数据即可。其中,因为设置了管道为等待模式(即下文中CreateNamedPipe的第三个参数DWORD dwPipeMode中设置了PIPE_WAIT),ConnectNamedPipe会是阻塞模式,因此不用担心不断循环造成的性能损失。 void bind_thread_main() { while (!exit_requested.load()) { HANDLE hPipe = CreateNamedPipe( PIPE_NAME, PIPE_ACCESS_DUPLEX, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, PIPE_UNLIMITED_INSTANCES, 1024, // Output buffer size 1024, // Input buffer size 0, // Default timeout NULL); if (hPipe == INVALID_HANDLE_VALUE) { service_log.push(LEVEL_WARN, "Failed to create pipe: %d", GetLastError()); continue; } if (ConnectNamedPipe(hPipe, NULL) || GetLastError() == ERROR_PIPE_CONNECTED) { char buffer[1024]; DWORD bytesRead; if (ReadFile(hPipe, buffer, sizeof(buffer) - 1, &bytesRead, NULL)) { buffer[bytesRead] = '\0'; m_queueMsg.push(buffer); service_log.push(LEVEL_VERBOSE, "Message received: %s", buffer); } FlushFileBuffers(hPipe); DisconnectNamedPipe(hPipe); CloseHandle(hPipe); } else { CloseHandle(hPipe); } } } Linux 为了防止创建失败,在创建前会先尝试删除没有清理干净的sock文件,即代码中unlink(SOCKET_PATH)。SOCKET_PATH为全局变量,定义了套接字文件的路径。创建套接字时,指定family为AF_UNIX代表创建UNIX套接字,即.sock文件的这种类型(如果是网络套接字就是AF_INET)。timeval这段代码设置了一个超时限制,当accept函数等待时间超过设置的SOCKET_TIMEOUT超时时间(单位秒)后会自动结束阻塞并返回错误信息。创建完套接字后按照正常流程设置绑定和监听即可。 void bind_thread_main() { unlink(SOCKET_PATH); int server_fd = socket(AF_UNIX, SOCK_STREAM, 0); if (server_fd == -1) { service_log.push(LEVEL_FATAL, "Failed to create socket"); exit_requested.store(true); return; } struct timeval tv; tv.tv_sec = SOCKET_TIMEOUT; tv.tv_usec = 0; setsockopt(server_fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)); sockaddr_un addr{}; addr.sun_family = AF_UNIX; strncpy(addr.sun_path, SOCKET_PATH, sizeof(addr.sun_path) - 1); if (bind(server_fd, (sockaddr*)&addr, sizeof(addr)) == -1) { service_log.push(LEVEL_FATAL, "Bind failed"); close(server_fd); exit_requested.store(true); return; } if (listen(server_fd, 5) == -1) { service_log.push(LEVEL_FATAL, "Listen failed"); close(server_fd); exit_requested.store(true); return; } while (!exit_requested.load()) { int client_fd = accept(server_fd, nullptr, nullptr); if (client_fd != -1) { char buffer[1024]; int bytes_read = read(client_fd, buffer, sizeof(buffer) - 1); if (bytes_read > 0) { buffer[bytes_read] = '\0'; m_queueMsg.push(buffer); service_log.push(LEVEL_VERBOSE, "Message received: %s", buffer); } close(client_fd); } else { if (errno == EWOULDBLOCK || errno == EAGAIN) { continue; } service_log.push(LEVEL_WARN, "Failed to accept socket connection"); } } } 当读取到消息后,两份代码都会将消息保存至阻塞队列m_queueMsg中。 发送部分 Windows 打开指定管道并写入消息内容即可: bool send_message(const std::string& msg) { if (!WaitNamedPipe(PIPE_NAME, NMPWAIT_WAIT_FOREVER)) { service_log.push(LEVEL_ERROR, "Failed to find valid pipe: %d", GetLastError()); return false; } HANDLE hPipe = CreateFile( PIPE_NAME, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); if (hPipe == INVALID_HANDLE_VALUE) { service_log.push(LEVEL_ERROR, "Failed to connect: %d", GetLastError()); return false; } DWORD bytesWritten; if (WriteFile(hPipe, msg.c_str(), (DWORD)msg.size(), &bytesWritten, NULL)) { service_log.push(LEVEL_VERBOSE, "Message sent: %s", msg.c_str()); CloseHandle(hPipe); return true; } else { service_log.push(LEVEL_ERROR, "Message (%s) send failed: %d", msg.c_str(),GetLastError()); CloseHandle(hPipe); return false; } } Linux 同理,连接套接字,发送数据: bool send_message(const std::string& msg) { int sock = socket(AF_UNIX, SOCK_STREAM, 0); if (sock == -1) { service_log.push(LEVEL_ERROR, "Failed to create socket"); return false; } sockaddr_un addr{}; addr.sun_family = AF_UNIX; strncpy(addr.sun_path, SOCKET_PATH, sizeof(addr.sun_path) - 1); if (connect(sock, (sockaddr*)&addr, sizeof(addr)) == -1) { service_log.push(LEVEL_ERROR, "Connect failed"); close(sock); return false; } if (write(sock, msg.c_str(), msg.size()) == -1) { service_log.push(LEVEL_ERROR, "Message send failed: %s", msg.c_str()); close(sock); return false; } else { service_log.push(LEVEL_VERBOSE, "Message sent success: %s", msg.c_str()); close(sock); return true; } } 清理 Windows下没什么需要清理的,Linux下删除套接字文件即可: unlink(SOCKET_PATH); 效果示意图 Windows Linux 样例代码下载: IPCTest.zip 参考文章: https://learn.microsoft.com/zh-cn/windows/win32/ipc/pipes https://learn.microsoft.com/zh-cn/windows/win32/ipc/anonymous-pipes https://learn.microsoft.com/zh-cn/windows/win32/ipc/named-pipes https://www.cnblogs.com/alantu2018/p/8493809.html https://blog.csdn.net/dog250/article/details/100998838
2025年05月19日
86 阅读
0 评论
1 点赞
为博客启用Cloudflare SaaS接入实现国际分流
虽然Cloudflare CDN在国内访问速度不尽人意,但是用作国际线路的解析内容还是很够用的。然而Cloudflare很早就取消了CNAME接入的方式,因此本文主要讨论通过SaaS接入,因此需要一张信用卡激活Cloudflare SaaS。 准备材料 有效信用卡,需要有卡号、安全码,或者绑定了信用卡的PayPal。若不超过100个自定义主机名的限制则不会产生扣费。 回退域名,和正常访问的域名不能是同一个(Cloudflare接入需要) 正常访问域名 为了实现分大陆、境外地区单独解析,用作正常访问的域名不可以通过Cloudflare接入。 本文正常访问的域名为:www.iyoroy.cn,回退域名为nekonya.cloud。 过程 回退域名接入 注册一个Cloudflare账户,按照官方教程将域名的DNS改到Cloudflare: Plan选择Free计划即可: 按照要求修改NS记录: 等到NS记录生效,即可通过Cloudflare管理回退域DNS。 绑定信用卡,启用SaaS 进入回退域名的Cloudflare控制台,打开左侧SSL/TLS-自定义主机名,点击启用Cloudflare for SaaS: 填入你的信用卡信息并保存。接着激活SaaS计划: 创建回退域的解析、设置自定义主机名 进入左侧DNS-记录,创建一条解析,指向你的源服务器: 此处我的回退域为cname.nekonya.cloud,解析类型是CNAME,但是A、AAAA记录是也是完全可以的。记得要打开Cloudflare代理以使用CF的CDN。 接着,进入左侧SSL/TLS-自定义主机名,回退源填刚刚添加的那条回退域下的解析,即cname.nekonya.cloud: 接着点击添加自定义主机名,并填写需要被访问的域名: 证书验证方法推荐TXT记录,这样可以使用DCV委派(详见下文设置DCV委派章节)。 接着需要验证域名所有权,按照要求填写TXT记录(我已经配置过了,因此创建一条test做演示): 因为下文要通过DCV验证获取证书,此处并没有添加证书相应记录。若不使用DCV委派,则将证书相关记录也这样设置解析。 {alert type="warning"} 注:在添加证书记录时务必不要刷新整个页面,不然解析记录内容会变。请使用选项内的刷新按钮。 {/alert} 待主机名状态变为有效后即可删除这条(也许是几条)解析。 设置DCV委派 找到下方自定义主机名的 DCV 委派,复制其中提供的解析值,到你的访问域名控制台,添加一条CNAME记录,主机名为_acme-challenge.www(此处和你的访问域名有关,我的访问域名是www.iyoroy.cn因此就是www。若是其他域名如test.iyoroy.cn,就填写_acme-challenge.test),记录值为Cloudflare提供的解析值前面加上你的hostname,即test.iyoroy.cn.xxxxxxx.dcv.cloudflare.com。 设置CNAME解析 进入你的访问域名控制台,为你要访问的域名添加相应解析记录。需要保证境外解析出来的内容是上文设置的回退源: 如果正常,那么就能看到证书状态和域名状态都是有效: 可以看到:,测试时境外已经切换到Cloudflare:
2025年05月15日
201 阅读
4 评论
1 点赞
1
2
3
...
5