悠笙の开发日记
type: channel
link: https://www.iyoroy.cn/
description: 悠笙的个人小站
items: DN42&OneManISP - 共存环境下的OSPF源地址故障排除
items: 2025羊城杯初赛WriteUp
items: DN42&OneManISP - 使用VRF实现公网BGP和DN42共用一台机器
items: 通过PBR为双网卡VPS配置多出口路由
items: OneManISP - Ep.2 向世界宣告我们自己的IP段
items: OneManISP - Ep.1 注册一个ASN
items: DN42探究日记 - Ep.4 配置BGP Communities
items: DN42探究日记 - Ep.3 在DN42中注册域名并搭建权威DNS
items: DN42探究日记 - Ep.2 通过OSPF搭建内部网络并启用iBGP
items: DN42探究日记 - Ep.1 加入DN42网络

DN42&OneManISP - 共存环境下的OSPF源地址故障排除
type: item
date: 2025-10-29T12:42:00+00:00
description: 前情提要 正如这个系列的上文所说，因为VRF方案太过于隔离，导致我部署在HKG节点（172.20.234.225）的DNS服务无法被DN42网络所访问，查阅资料得知可以通过设置veth或者NAT地址转发的方式来实现，但是因为现有的资料比较少，最终还是放弃了VRF这个方案。 结构分析 这次我打算将DN42和公网BGP的路由都放入系统的主路由表，然后再分开导出，通过过滤器来区分是否应该导出。同时，为了更加直观，我将DN42部分的配置和公网（以下简称inet）部分的配置分别单独存放，再由主配置文件引入。同时，因为kernel部分配置一个路由表只应该存在一个，因此合并DN42和inet的kernel部分，仅保留一个。 经过多次优化和修改，我最终的目录结构如下： /etc/bird/ ├─envvars ├─bird.conf: Bird主配置文件，负责定义基本信息（ASN、IP等），引入下面的子配置 ├─kernel.conf: 内核配置，负责将路由导入系统路由表 ├─dn42 | ├─defs.conf: DN42的函数定义，如is_self_dn42_net()这类 | ├─ibgp.conf: DN42 iBGP模板 | ├─rpki.conf: DN42 RPKI路由验证 | ├─ospf.conf: DN42 OSPF内网 | ├─static.conf: DN42静态路由 | ├─ebgp.conf: DN42 Peer模板 | ├─ibgp | | └<ibgp configs>: DN42 iBGP各个节点的配置 | ├─ospf | | └backbone.conf: OSPF区域 | ├─peers | | └<ibgp configs>: DN42 Peer各个节点的配置 ├─inet | ├─peer.conf: 公网Peer | ├─ixp.conf: 公网IXP接入 | ├─defs.conf: 公网部分的函数定义，如is_self_inet_v6() | ├─upstream.conf: 公网上游 | └static.conf: 公网静态路由 将定义函数的部分单独拿出来是因为我需要在kernel.conf的过滤器中引用，因此单独拿出来以便于提前include。 完成后分别填入对应配置，然后由写好include关系，birdc configure后发现也成功跑起来了。于是乎告一段落...吗? 发现问题 运行一段时间后，我突然发现通过我的内网设备Ping HKG节点无法Ping通，通过HKG节点Ping我的其他内部节点也无法Ping通。奇怪的是，外部AS可以通过我的HKG节点Ping到我的其他节点或者其他外部AS，我的内部节点也可以通过HKG节点Ping到其他不直接相连的节点（如：226(NKG)->225(HKG)->229(LAX)）。 通过ip route get <内网其他节点地址>发现： root@iYoRoyNetworkHKG:/etc/bird# ip route get 172.20.234.226 172.20.234.226 via 172.20.234.226 dev dn42_nkg src 23.149.120.51 uid 0 cache 看出问题了吗？src地址本来应该是HKG节点自己的DN42地址（OSPF部分stub网卡配置的），但是这里显示的却是HKG节点的公网地址。 尝试通过birdc s r for 172.20.234.226读取bird学习到的路由： root@iYoRoyNetworkHKGBGP:/etc/bird/dn42/ospf# birdc s r for 172.20.234.226 BIRD 2.17.1 ready. Table master4: 172.20.234.226/32 unicast [dn42_ospf_iyoroynet_v4 00:30:29.307] * I (150/50) [172.20.234.226] via 172.20.234.226 on dn42_nkg onlink 看起来貌似一切正常...? 理论上来说，虽然DN42的源IP和正常的不太一样，但是DN42在导出到内核的时候改写了krt_prefsrc来告诉内核正确的源地址，理论上不应该出现这样的问题： protocol kernel kernel_v4{ ipv4 { import none; export filter { if source = RTS_STATIC then reject; + if is_valid_dn42_network() then krt_prefsrc = DN42_OWNIP; accept; }; }; } proto…

2025羊城杯初赛WriteUp
type: item
date: 2025-10-12T02:50:00+00:00
description: GD1 通过文件描述可知这是Godot Engine编写的游戏。使用GDRE工具打开，可找到游戏逻辑： extends Node @export var mob_scene: PackedScene var score var a = "000001101000000001100101000010000011000001100111000010000100000001110000000100100011000100100000000001100111000100010111000001100110000100000101000001110000000010001001000100010100000001000101000100010111000001010011000010010111000010000000000001010000000001000101000010000001000100000110000100010101000100010010000001110101000100000111000001000101000100010100000100000100000001001000000001110110000001111001000001000101000100011001000001010111000010000111000010010000000001010110000001101000000100000001000010000011000100100101" func _ready(): pass func _process(delta: float) -> void : pass func game_over(): $ScoreTimer.stop() $MobTimer.stop() $HUD.show_game_over() func new_game(): score = 0 $Player.start($StartPosition.position) $StartTimer.start() $HUD.update_score(score) $HUD.show_message("Get Ready") get_tree().call_group("mobs", "queue_free") func _on_mob_timer_timeout(): var mob = mob_scene.instantiate() var mob_spawn_location = $MobPath / MobSpawnLocation mob_spawn_location.progress_ratio = randf() var direction = mob_spawn_location.rotation + PI / 2 mob.position = mob_spawn_location.position direction += randf_range( - PI / 4, PI / 4) mob.rotation = direction var velocity = Vector2(randf_range(150.0, 250.0), 0.0) mob.linear_velocity = velocity.rotated(direction) add_child(mob) func _on_score_timer_timeout(): score += 1 $HUD.update_score(score) if score == 7906: var result = "" for i in range(0, a.length(), 12): var bin_chunk = a.substr(i, 12) var hundreds = bin_chunk.substr(0, 4).bin_to_int() var tens = bin_chunk.substr(4, 4).bin_to_int() var units = bin_chunk.substr(8, 4).bin_to_int() var ascii_value = hundreds * 100 + tens * 10 + units result += String.chr(ascii_value) $HUD.show_message(result) func _on_start_timer_timeout(): $MobTimer.start() $ScoreTimer.start() 发现当得分到达7906时会调用一个解密算法，将数组a的数据解密然后打印。尝试按照逻辑编写解密程序： #include <iostream> #include <st…

DN42&OneManISP - 使用VRF实现公网BGP和DN42共用一台机器
type: item
date: 2025-09-16T14:47:00+00:00
description: 背景 目前同一区域内公网BGP和DN42分别用了一台VPS，也就是说同一个区域需要两台机器。从群友那里得知了VRF，便想着通过VRF实现同一台机器同时处理公网BGP并加入DN42。 注意：VRF方案因为其隔离性，会导致DN42无法访问主机的服务。如果你需要在服务器上跑诸如DNS之类的服务给DN42用，你可能需要再单独配置端口转发或者veth，但是不在本文讨论范围内。（这也是我实际生产环境最终还是没有采用VRF的原因） VRF的优点 虽然说DN42使用的IP段是私有地址，并且它的ASN用的都是内部ASN，理论上不会和公网BGP相互干扰，但是如果共用同一张路由表，可能会造成路由污染、管理复杂等问题。 VRF（Virtual Routing and Forwarding，虚拟路由转发）可以实现在一台机器上创建多个路由表，也就是说我们可以通过它将DN42的路由单独放到一个路由表里，以实现将DN42路由表和公网路由表相隔离。这么做的优点有： 绝对的安全与策略隔离：DN42路由表和公网路由表相隔离，从根本上杜绝了路由泄露的可能性。 清晰的运维管理：可以使用birdc show route table t_dn42和birdc show route table t_inet来分别查看和调试两张完全独立的路由表，一目了然。 故障域隔离：若果DN42的某个对等体发生Flap，这些影响将被完全限制在dn42的路由表内，不会消耗公网实例的路由计算资源，也不会影响公网的转发性能。 更符合现代网络设计理念：在现代网络工程中，为不同的路由域（生产、测试、客户、合作伙伴）使用VRF是标准做法。它将你的设备逻辑上划分成了多个虚拟路由器。 配置 系统部分 创建VRF设备 使用以下指令创建一个名为dn42-vrf的VRF设备并关联到系统的1042号路由表： ip link add dn42-vrf type vrf table 1042 ip link set dev dn42-vrf up # 启用 路由表号可以按照你自己的喜好修改，但是请避开以下几个保留路由表编号： 名称 ID 说明 unspec 0 未指定，基本不用 main 254 主路由表，大多数普通路由都放在这里 default 253 一般不用，保留 local 255 本机路由表，存放127.0.0.1/8、本机 IP、广播地址等，不能改 将现有的相应网卡关联到VRF 按照我目前的DN42网络为例，有若干WireGuard网卡和一个dummy网卡是用于DN42的，因此将这几个网卡都关联到VRF中： ip link set dev <网卡名> master dn42-vrf 需要注意的是，网卡关联到VRF之后可能会丢失地址，因此需要重新为其添加一次地址，如： ip addr add 172.20.234.225 dev dn42 完成之后，通过ip a应该能看到对应网卡的master是dn42-vrf： 156: dn42: <BROADCAST,NOARP,UP,LOWER_UP> mtu 1500 qdisc noqueue master dn42-vrf state UNKNOWN group default qlen 1000 link/ether b6:f5:28:ed:23:04 brd ff:ff:ff:ff:ff:ff inet 172.20.234.225/32 scope global dn42 valid_lft forever preferred_lft forever inet6 fd18:3e15:61d0::1/128 scope global valid_lft forever preferred_lft forever inet6 fe80::b4f5:28ff:feed:2304/64 scope link valid_lft forever preferred_lft forever 持久化 我使用了ifupdown来实现开机自动加载dummy网卡和VRF设备。 对于VRF设备，创建文件/etc/network/interfaces.d/01-dn42-vrf并填入： auto dn42-vrf iface dn42-vrf inet manual pre-up ip link add $IFACE type vrf table 1042 up ip link set dev $IFACE up post-down ip link del $IFACE 然后使用ifup dn42-vrf启动。 对于dummy网卡，创建文件/etc/network/interfaces.d/90-dn42并填入： auto dn42 iface dn42 inet static…

通过PBR为双网卡VPS配置多出口路由
type: item
date: 2025-09-14T09:07:00+00:00
description: 水文警告 背景 从朋友那里弄到一台深港IEPL机器，有两个网卡eth0和eth1，但是默认都走eth0，eth1没有配置路由。 我打算通过metric实现粗略的分流再通过PBR实现按照规则的路由配置。 配置 机器默认由cloudinit配置了网卡： # This file is generated from information provided by the datasource. Changes # to it will not persist across an instance reboot. To disable cloud-init's # network configuration capabilities, write a file # /etc/cloud/cloud.cfg.d/99-disable-network-config.cfg with the following: # network: {config: disabled} network: version: 2 ethernets: eth0: addresses: - 10.10.1.31/16 gateway4: 10.10.0.1 match: macaddress: bc:24:11:f8:42:7a nameservers: addresses: - 223.5.5.5 - 119.29.29.29 search: - [数据删除] set-name: eth0 eth1: addresses: - 10.20.1.31/16 - [数据删除]/64 gateway4: 10.20.0.1 gateway6: fe80::be24:11ff:fe80:66bb match: macaddress: bc:24:11:50:96:0a nameservers: addresses: - 223.5.5.5 - 119.29.29.29 search: - [数据删除] set-name: eth1 备份一份配置之后加上metric： # This file is generated from information provided by the datasource. Changes # to it will not persist across an instance reboot. To disable cloud-init's # network configuration capabilities, write a file # /etc/cloud/cloud.cfg.d/99-disable-network-config.cfg with the following: # network: {config: disabled} network: version: 2 ethernets: eth0: addresses: - 10.10.1.31/16 gateway4: 10.10.0.1 match: macaddress: bc:24:11:f8:42:7a nameservers: addresses: - 223.5.5.5 - 119.29.29.29 search: - [数据删除] set-name: eth0 + routes: + - to: "default" + via: "10.10.0.1" + # 设置 metric=50，作为备选出口 + metric: 50 eth1: addresses: - 10.20.1.31/16 - [数据删除]/64 gateway4: 10.20.0.1 gateway6: fe80::be24:11ff:fe80:66bb match: macaddress: bc:24:11:50:96:0a nameservers: addresses: - 223.5.5.5 - 119.29.29.29 search: - [数据删除] set-name: eth1 + routes: + - to: "default" + via: "10.20.0.1" + # 设置 metric=25，作为优先出口 + metric: 25 编写PBR配置： # /etc/netplan/90-pbr.yaml network: version: 2 ethernets: eth0: routes: - to: default via: 10.10.0.1 table: 10 routing-policy: - from: 10.10.0.0/16 table: 10 - to: 202.46.[数据删除]/32 table: 10 eth1: routes: - to:…

OneManISP - Ep.2 向世界宣告我们自己的IP段
type: item
date: 2025-08-20T15:59:00+00:00
description: 前言 上文我们已经成功注册了一个ASN并且拿到了一段IPv6地址，这次我们就来将这段地址广播给全世界。 在RIPE Database设置子网对象 需要注意的是，公网允许广播的最小IPv6前缀是/48，也就是说你如果只有一个/48地址你无法将其拆成更小的段。所以我后来又单独租用了一段/40，打算将其拆成多个/48来广播。 我获取到的IPv6为2a14:7583:f200::/40，打算拆出来2a14:7583:f203::/48用于给Vultr使用。如果你不需要拆段，请直接跳转到「创建路由信息」一节 拆段 首先打开Create "inet6num" object - RIPE Database，填入如下内容： inet6num: 打算拆出来的IP段，CIDR格式 netname: 网络名称 country: IP段所属国家，需要符合ISO 3166标准（RIPE DB里可以直接选择） admin-c: 上文创建的Role对象的主键值 tech-c: 上文创建的Role对象的主键值 status: ASSIGNED即可 此步骤将你获得的地址拆出来一个小的/48地址块。 创建路由信息 打开Create "route6" object - RIPE Database，填入如下内容： route6: 填写你打算广播播的IPv6地址块的CIDR格式 origin: 填写你申请到的ASN，包含AS前缀 此步骤声明允许你的ASN使用这段地址段来发BGP路由。 申请VPS的BGP Session接入 此次我使用的是Vultr家的机器，他们家的BGP Session算是很新手友好的了，有一套自己的验证系统；并且上游良好的过滤器保证了一般情况下即使发送了错误的路由表也不会影响到公网。 （此处我配置的时候忘记截图了，可以参考一下宝硕大佬的文章 年轻人的第一个 ASN 中的 申请 Vultr 的 BGP 广播功能 章节） 进入BGP - Vultr.com，选择Get Started之后按照要求填写你的ASN信息和IPv6地址块。LOA（Letter Of Authorization，授权信）可参考以下模板：LOA-template.docx（因为发现网上查到的都是以公司的名义写的，因此以个人名义重新写了一份） 完成后系统会自动创建一条工单，并且能看到我们的ASN和IP地址块处于待验证的状态： 点击Start，系统会向注册Role时填写的abuse-mailbox邮箱发送一封验证邮件： 收到的邮件如图所示： 其中，上面那个链接代表同意授权Vultr广播你的IP段，下面那个则是不同意。我们点击上面那个之后会进入Vultr的网页： 再点击Approve Announcement即可。ASN和IP段都需要验证一次。 接着，等待Vultr的工作人员审核完成后来到VPS的控制台，就能看到我们的BGP选项卡了，其中可以得到上游的信息： 此处不得不称赞一下Vultr的工单效率，我平均从创建工单申请授权到完成只花了10分钟左右。（反观之前在iFog GmbH，平均工作日工单回复时间1天左右实在是好太多了） 其他厂商的VPS大概都是这么个流程，你需要告诉工作人员你要播的ASN和IP段，在验证完所有权之后工作人员会为你配置对应的BGP Session。 广播！ 你应该已经从上游那里得到了以下信息： 上游的ASN 上游用于BGP Session的地址 （可选）密码 我用的操作系统是Debian12 Bookworm，使用Bird2作为路由软件，并且按照这篇文章中「更新Bird2至v2.16及以上」章节更新Bird2至最新版。Vultr那边给我的上游ASN是64515，上游用于BGP Session的地址是2001:19f0:ffff::1，VPS用于BGP Session的地址是2001:19f0:0006:0ff5:5400:05ff:fe96:881f。 我的Bird2配置文件修改自DN42中的配置文件： log syslog all; define OWNAS = 205369; # 自己的ASN define OWNIPv6 = 2a14:7583:f203::1; # 给机器绑定的单个IPv6地址 define OWNNETv6 = 2a14:7583:f203::/48; # 打算播的网段 define OWNNETSETv6 = [ 2a14:7583:f203::/48+ ]; # 打算播的网段集合 router id 45.77.x.x; # 路由器ID，这里使用VPS的公网IPv4 protocol device { scan time 10; } function is_self_net_v6() { return net ~ OWNNETSETv6;…

OneManISP - Ep.1 注册一个ASN
type: item
date: 2025-08-18T09:49:00+00:00
description: 写在前面 本文记录了我在RIPE NCC申请ASN的完整过程，内容适合入门者参考，若有错误欢迎邮件联系我，我会在第一时间更正。 既然已经在DN42上学习了基本的BGP概念，不玩玩公网的有点说不过去吧（ 基本概念 目前公网ASN和IP资源分配由世界上5个 区域互联网注册管理机构（Regional Internet registry, RIR） 管理： ARIN: 负责管理北美地区 RIPE NCC: 负责管理欧洲地区 APNIC: 亚洲地区 LACNIC: 拉丁美洲地区 AfriNIC: 非洲地区 RIR不直接对个人用户提供服务，而是通过将资源授权给 本地互联网注册管理机构（Local Internet Registry, LIR） ，再由LIR授权给个人。当然，个人用户也可以注册成为LIR，但是这一般而言一般是不划算的。 如果你愿意每年交几千美元作为会费的话当我没说。 其中，对个人申请比较友好的是RIPE NCC，其次是ARIN和APNIC。相较于RIPE NCC，APNIC的费用普遍要高30%左右；并且RIPE NCC提供了一套在线管理系统，用户可以自己修改信息、查询进度，而在APNIC则需要联系LIR处理。综合而言，我选择在RIPE NCC申请ASN。 申请到的资源（ASN、IP都算）一般分为两种： PA（Provider Aggregatable）资源: 属于LIR，由LIR注册授权给你用的资源 PI（Provider Independent）资源: 属于你自己的资源，一般而言价格较高 准备阶段 选择一个LIR 上网查询LIR Service，可以找到很多提供这类服务的商家。目前RIPE NCC会向PI资源收取一年50EUR的管理费用，也就是说一般而言LIR注册ASN的费用不会低于50EUR（截至文章发布，大概60USD）一年。此处我选择的群友推荐的NoPKT LLC，价格算是比较合理的并且随ASN附赠一段/48 PA IPv6地址，实测下号速度也很快，从提交完材料到下号只用了半天。 准备材料 身份证明 个人：提供身份证或者护照都可以（我提供的身份证正反面照片） 企业：提供有效的营业执照 若申请人为未成年人，通常需要其法定监护人提供书面同意书并履行相应监护职责。所有提交的文件应确保真实有效，且必须是原件或经过公证的副本。 联系信息 通信地址，被用于登记在RIPE Database 技术人员邮箱 滥用举报邮箱 技术要求证明 欧洲范围内的BGP服务商开具的账单，可以选择Vultr、BuyVM、iFog、V.PS等。 注：Vultr是先用后付制，每月初出账单。如果你着急备好材料，建议选择其他家。 两个你打算接入的上游的ASN（实际上审核方不会严格验证你填写的上游ASN，因此可以随意填写，但建议填写一些常见的公开ASN以显得合理，不用过多纠结。 甚至填我的也行 ） 注册RIPE DB账户并创建条目 打开RIPE Database并注册一个账户。此处填写姓名时建议填写你自己的真实姓名的拼音，并且强制要求开启2FA，请提前在手机上安装TOTP软件。 创建Role对象和Maintainer对象 打开Create role and maintainer pair - RIPE Database，创建一个role对象。 此处role为一个抽象概念，用来描述一个团队、部门或者职能角色的联系方式，代指一个角色，比如 NOC (Network Operations Center)、Abuse Team、Hostmaster 等。 mntner: maintainer对象的标识符，可包含大小写字母、数字、-_。例如我填写的是IYOROY-MNT role: role对象的名称，可包含大小写字母、数字、][)(._"*@,&:!'+/-。例如我填写的是IYOROY-NETWORK-NOC address: 此role对象的办公地址 e-mail: 此role的电子邮件地址 填写完成后SUBMIT即可创建role对象和maintainer对象。请记录下返回的主键名称，一般以-RIPE结尾，后续修改信息及提交到LIR需要用到。 此处maintainer对象标识符和role对象有所区别，前者意为谁有权限维护数据库中的对象（即写入/修改/删除权限控制），是维护者实体。关于RIPE Database中各个概念之间的归属，可参考文章后部的示意图。 添加滥用举报邮箱 打开Query - RIPE Database，查询刚刚获得的role主键名称，可以查询到刚刚创建的条目。点击右侧Update Object。 点击e-mail栏右侧的加号，创建一个abuse-mailbox属性，并且填入你的滥用举报邮箱： SUBMIT保存。 注：RIPE会定时检查滥用举报邮箱是否…

DN42探究日记 - Ep.4 配置BGP Communities
type: item
date: 2025-08-17T15:43:00+00:00
description: 写在前面 本人是BGP小白，文章中可能会存在不严谨内容/小白理解/低级错误，请诸位大佬们手下留情。若发现存在问题，您愿意的话可以邮件联系我，我会在第一时间更正。如果您不能接受，建议现在就关闭此文章。 什么是BGP Communities TL;DR: BGP Communities给路由“打标签”，其他人可以通过这个标签实现路由优选 这个概念对于刚入坑的小白 （比如我） 来说可能比较陌生，可能不理解它是干吗用的 简单来说，BGP Communities是一种标记路由的机制，类似于给路由打标签。它允许网络管理员给通过BGP传播的路由附加一个或多个“标签”（即社区值）。这些标签本身并不改变路由的路径属性（如AS_PATH、LOCAL_PREF、MED等），但它们提供了一种信号机制，用于向本AS内或下游对等AS中的其他路由器指示应该对该路由执行何种策略或处理。BGP Communities可以用来： 简化策略配置: 网络内部或下游 AS 的路由器只需配置基于社区值的策略（如设置LOCAL_PREF、添加NO_EXPORT、应用路由图等），无需知道具体的前缀细节。这使得策略更集中、更易管理、更不易出错 传达策略意图给下游AS: 可以将社区值附加在它通告给下游客户或对等AS的路由上。这些社区值传达了对这些路由应如何处理的要求或建议，如根据不同地理位置、不同延迟和带宽来进行路由优选等 在AS内部协调策: 在大型AS内部，IBGP全互联或使用路由反射器时，可以在 AS 边缘路由器（接收 EBGP 路由或重分发路由的路由器）给路由打上社区值，AS内部的核心路由器或路由反射器可以识别这些社区值，并应用相应的内部策略（如设置LOCAL_PREF、MED、决定是否向某些IBGP对等体通告、打上其他社区等），而无需在每个内部路由器上配置复杂的基于前缀的策略 DN42中有一套自己的Communities规范，详情可参考：BGP-communities - DN42 Wiki 配置 本文大致思路和方案来源于Xe_iu大佬，仅针对地理位置信息添加BGP Communities并进行优选。一般来说这样就足够了。（还有个原因是其他的我还没太搞明白） 注意: 我们应该只对自己的AS添加地理位置信息相关的BGP Communities，不应当对邻居传递来的路由添加相关条目。若对邻居的路由加上自己的地区Communities则会造成伪造路由起源，引发路由劫持。下游可能会误判流量路径，将本应直连的流量绕道至你的网络，增加延迟的同时大量消耗你的网络的流量。（Large Communities除外，Large Community有一套验证机制可以防止此类事情发生，但是不在本文讨论范围内） 思路已经很明白了，在导出路由时我们需要先验证是否是我们自己的路由，如果是则为路由打上communities标签即可。DN42官方给的样例配置中已经写好了两个函数is_self_net()和is_self_net_v6()用于检查是否是自己的路由，因此编写配置文件部分就很简单了。 为路由添加Communities 首先我们需要在节点配置文件开头定义好当前节点的地理区域信息，详情请查询BGP-communities - DN42 Wiki： define DN42_REGION = 52; # 52代表亚洲东部地区 define DN42_COUNTRY= 1344; # 1344代表香港 请将上述数值按照你的节点地理位置情况修改 随后在dnpeers模板中修改导出的过滤器： }; export filter { - if is_valid_network() && source ~ [RTS_STATIC, RTS_BGP] then accept; + if is_valid_network() && source ~ [RTS_STATIC, RTS_BGP] then{ + if (is_self_net()) then { # 检查是否是自己的路由 + bgp_community.add((64511, DN42_REGION)); # 打上大洲级别的区域信息 + bgp_community.add((64511, DN42_COUNTRY)); # 打上国家/地区信息 + } + accept; + } reject; }; import limit 1000 action block; 在导出时检查，如果是自己的路由则按照上面设置的DN42_REGION和DN42_COUNTRY为该路由设置bgp_community。其中，64511是专门为地理标签（Region/Country）保留的公共AS号标识符，直接照抄即可。在IPv6的导出规则中也如法炮制，不过将is_self_ne…

DN42探究日记 - Ep.3 在DN42中注册域名并搭建权威DNS
type: item
date: 2025-08-03T13:22:00+00:00
description: 写在前面 本人是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反向解析域名> noti…

DN42探究日记 - Ep.2 通过OSPF搭建内部网络并启用iBGP
type: item
date: 2025-07-22T05:46:00+00:00
description: 写在前面 本人是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。 因此我决定冒险一下 节点拓扑 graph LR A[HKG 172.20.234.225 fd18:3e15:61d0::1] B[NKG 172.20.234.226 fd18:3e15:61d0::2] C[TYO 172.20.234.227 fd18:3e15:61d0::3] D[LAX 172.20.234.229 fd18:3e15:61d0::5] B <--> A C <--> A A <--> D C <--> D 更新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以前的Bi…

DN42探究日记 - Ep.1 加入DN42网络
type: item
date: 2025-06-28T13:19:00+00:00
description: 写在前面 本人是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: i@iyoroy.cn 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-n…