Skip to main content
Re:Linked

接入 dn42 及 NeoNetwork

· #devops · 约 12.4k 字
本文距离上次更新已经超过 900 天。因此,其中的信息可能已经过时。

LibreHouse 建立以来的第一件大事——接入 dn42(还有 NeoNetwork),经过五个月的努力来,终于有了一定的成果
BTW,欢迎来 peer :-)

本文作者对网络工程并没有什么了解。因此,以下内容可能有不准确甚至完全错误的地方。如果你发现了文中不准确的地方,欢迎通过评论或其它方式告诉我!

在按照本文执行操作时,请务必做好相关备份工作。


什么是 dn42?

dn42 是一个私有互联网络。你可以把它理解成基于现有互联网之上,许多设备通过 VPN 方式互相连接的一个小型「互联网」。作为(大概是)世界最大的私有互联网络,目前的 dn42 (及与其互联的其它网络,例如 ChaosVPN、还有上面提到的,最近由 Neo Chen 发起的 NeoNetwork 等等)有超过三百个互相连接的 AS [1]。这些 AS 中的设备通过 Tinc/Wireguard/GRE 等方式互相连接,并通过 BGP 等协议交换彼此的路由,形成一个节点众多的网络。

它跟 Tor 这样的深网 (deepnet) 有什么不同?

与能让用户匿名访问互联网和/或深网的 Tor, I2P, ZeroNet 等不同,dn42 不是匿名网络。由于网络中的每一个 IP 地址都属于一个 AS,而所有的 AS 在 Registry 都有记录,dn42 并不能提供匿名性。在互联网 (Internet) 上也是一样。如果你用家中的光纤连接通过从百度网盘上下载了一份电影的话,百度可以通过你的 IP 知道你所使用的网络运营商 (ISP)(例如中国电信)。

为什么要连接到 dn42?

为了好玩。

如果你想尝试路由技术,dn42 可能适合你。在 dn42,你不必担心自己的路由配置错误会干掉半个互联网。要知道路由泄露或劫持已经让半个互联网爆炸 了。如果是在 dn42 上,你的配置错误最多干掉整个 dn42 网络,不过 dn42 的 NOC 们相对互联网的 NOC 大概对路由泄露也有更强的抵御能力吧(因为见多了)。至少你不需要担心一条路由配坏,身边昨天能连上 Google 的用户,一夜之间都上不去 Google 了(嘛,中国大陆用户本来也上不去 Google 的说)。

如果你想做 BGP Player,但是不喜欢繁琐的 ASN 注册过程,或者不想花钱买 ASN 或者 IP 地址,dn42 可能适合你。搞过公网 BGP 的人都明白(然而我没搞过),注册一个 ASN,买个 IP 段通常是挺麻烦的事。然而在 dn42 上,注册一个 ASN 和申请一段 IP 只需要一个 Pull Request,而且不花钱。

如果你想让路由器后面的电脑有个属于自己的 IP 地址,dn42 可能适合你。通过和别的节点 peer,你就可以接入 dn42 网络,广播自己(在 dn42 网络内)的 IP,这甚至不要求你有公网 IP 地址。当然,随着 IPv6 的普及,许多中国大陆的 ISP 也开始给用户提供全球单播 (global unicast) IPv6 地址(通常以 2001: 开头),你就不需要为了一个公网 IP 而大费周章了。

总之还是为了好玩。(笑)

如何连接到 dn42(或者 NeoNetwork 什么的)?

由于现在 dn42 和 NeoNetwork 已经互通,你只需要在这两个网络之一得到一个 AS 号,并且拿到一段 IP,就可以成为整个网络中的一部分。配置好你的 AS 号和要广播的 IP 段,并且和至少一个节点 peer,你就能接入整个网络中,访问这个网络中的任何一个节点。

那么大体上的步骤就确定了。

  1. 申请一个 ASN 和一段 IP
  2. 寻找一个可以 peer 的节点
  3. 联系节点所在 AS 的 NOC,和这个节点 peer
  4. 在欲与这个节点 peer 的设备上配置 peer 所使用的 VPN 方案及路由
  5. 确认 peer 可以通过 peer 的地址连通
  6. 确认所使用的路由协议(通常是 BGP)可以建立连接
  7. 配置 DNS

需要什么?

  1. 至少一台能保持长期在线的设备。不一定要有公网 IP,但是有的话自然更好。
  2. 这台设备的 root 权限。
  3. 时间 :-)

开始我们的路由战争

笔者最近在看 Date A Live,这中二气息满满的标题还请各位不要介意。

本章节会详细介绍如何完成这一系列过程。各位亦可参考 dn42 的 Getting Started 页面。

申请 ASN 和 IP 段

这里我们将对 dn42 和 NeoNetwork 的注册方法均进行介绍。不过,你只需要在与 dn42 互联的网络中的其中一个网络有 AS 号和 IP(甚至不一定要是同一个网络中的),就可以和所有网络互通。

对于 dn42...

本段部分内容来自 这里

dn42 的 registry 在这里。你需要在这个 Gogs 实例上注册一个帐号,并向 registry 所在的 repo 发送一个 Pull Request。

你需要在以下位置各添加一个条目( <ITEM>处的内容根据你的喜好自行填写):

  • maintainer,也就是 data/mntner/<YOURNAME>-MNT
  • person,也就是 data/person/<YOURNAME>-DN42
  • AS 号,也就是 data/aut-num/AS<YOURASN>
    • dn42 目前使用的 AS 号范围是 4242420000-4242423999。
  • IP 段,也就是data/inetnum/<PREFIX>_<LENGTH> (IPv4) 和 data/inet6num/<PREFIX>_<LENGTH> (IPv6)
    • 对于 IPv6,dn42 目前使用的地址范围是 fd00::/8,这是 RFC4193 中的本地单播地址 (ULA)。 一般申请一个 /48 段即可(形如 fd00:dead:beef::/48)。dn42 建议随机生成一个(这是 RFC4193 里的规范),不过也许你也可以自定义一个,只要不冲突的话 :-)
    • 对于 IPv4,你可以在这里找到尚未被占用的 IP 段。一般申请一个 /27 或 /28 段即可。你也可以选择像 LibreHouse 一样不在 dn42 申请 IPv4,而是在 NeoNetwork 申请 IPv4 来用。

内部文件格式可以参考相同文件夹的其它条目,亦可参考 LibreHouse 当时的 Pull Request

对于 NeoNetwork...

NeoNetwork 的 registry 在这里。你需要在 GitHub 上注册一个帐号,并向 registry 所在的 repo 发送一个 Pull Request。

类似于 dn42,你需要在以下位置各添加一个条目:

  • entity,也就是 entity/<YOURNAME>
  • AS 号,也就是 asn/AS<YOURASN>
    • 你也可以沿用在 dn42 得到的 AS 号。
  • 节点信息,也就是 node/<NODENAME>
  • IP 段,也就是 route/<PREFIX>.<LENGTH> (IPv4) 和 route6/<PREFIX>.<LENGTH> (IPv6)
    • 对于 IPv6,NeoNetwork 目前使用的地址范围是 fd10:127::/16
    • 对于 IPv4,NeoNetwork 目前使用的地址范围是 10.127.0.0/16

寻找可以 peer 的节点

为了连接到网络上,你需要和网络内的至少一个节点 peer。ping 延迟更低的节点自然更好。dn42 有一个 peerfinder 可以帮助你找到离你的服务器较近的一些节点。NeoNetwork 的话,去找各个 NOC 问一下吧。LibreHouse 是在 dn42 和 burble(dn42 内最大 AS 吧,大概算是)peer 了,在 NeoNetwork 也和数个节点有 peer。

和这个节点 peer

找到节点之后,要商量具体的 peer 方式。目前比较流行的有以下几种:

  • Wireguard - 今年早些时候进了内核,被 Linus Torvalds 盛赞 "It's a work of art" 的 VPN。配置也比较舒服。
  • GRE - 配置超级简单(甚至不需要预共享密钥)。不过请注意部分云服务提供商(例如 Google Cloud)会屏蔽 GRE 连接。
  • Tinc - 过去比较常用的 VPN 方案。不过逐渐被上两种所替代了。

选择其中比较方便的一个就好。

然后,你们还需要得到以下的信息:

  • 双方的 AS 号
  • 双方使用的路由协议(通常是 BGP)
  • 双方端点所使用的 IP。
    • 有时候会直接使用你在 dn42/NeoNetwork 的 IP,有时候则是使用一组 link-local address(或者其它的地址)。这里其实可以使用任意的 IP,但考虑到防止冲突的原则通常会使用前二者。
    • 如果不支持 MBGP 的话(例如 bird 1.6),对于 IPv4 和 IPv6 要分别协商 IP,如果支持的话,IPv4 和 IPv6 选一个就好。当然,如果只需要 IPv4(或 IPv6)的 peer 的话,只协商 IPv4(或 IPv6)的 IP 就好。
  • 双方在互联网 (Internet) 上的公网 IP(有时候可能只需要一方的 IP)
  • peer 方案的相关信息
    • 对于 Wireguard,双方所监听的端口及 Wireguard 公钥
    • 对于 GRE,什么都不需要(是的,什么都不需要)
    • 对于其它方案,则可能需要其它的资讯

配置 peer 方案

这里介绍 Wireguard 和 GRE 配置的方法之一。许多其它方式亦可达到同样效果,这里不再赘述。

示例设备的信息如下:

  • 操作系统 Debian 10.4
  • 公网域名 me.example.com (非必须,对方需要知道)
  • 公网 IP 39.39.39.39 (对方需要知道,不过通常可以从域名拿到)
  • AS 号 4242424239 (对方需要知道)
  • 使用的 dn42 IP:
    • 10.127.39.39 (IPv4)
    • fd00:3939:3939:3939::1 (IPv6)
  • 使用的端点 IP: (对方需要知道)
    • 169.254.39.39/32
    • fe80::3939/64
    • (这里 /32/64 的含义,请见下文 FAQ)

欲 peer 节点的信息如下:

  • 公网域名 it.example.com
  • 公网 IP 73.73.73.73
  • AS 号 4242424273
  • 使用的端点 IP:
    • 169.254.73.73/32
    • fe80::7373/64

我们决定把和它 peer 所使用的 interface 叫做 myfirstint.

使用 systemd-networkd 配置 Wireguard

首先安装 Wireguard 并启用此内核模块(sudo modprobe wireguard)。

为了配置 Wireguard,我们需要:

  • 一个用于监听连接的端口
  • 一组用于 Wireguard 的公钥/私钥

我们需要对方告知自己的:

  • 监听连接的端口
  • Wireguard 的公钥

在示例中,我们使用 40001 作为 Wireguard 的连接监听端口,对方使用 40002 作为 Wireguard 的连接监听端口,公钥为 rcPNWjI0tPAVRr09TNxC8B+PhqSHRPnD3lPOxgkW01U=

使用 wg genkey(由软件包 wireguard-tools 提供)生成一个用于 Wireguard 的私钥:

$ wg genkey
qJRZlE1QreqHNokgpmaFdkKALUxXthTmpmzbewFv53k=

再算出它的公钥:

$ echo qJRZlE1QreqHNokgpmaFdkKALUxXthTmpmzbewFv53k= | wg pubkey
2XAkuvLmBH1SB+G6o0v4OuUC4N34pB9848s/sL5ciCA=

把这个公钥(2XA...CA=)和监听端口(40001)提供给对方。

之后就是 systemd-networkd 的配置时间了:

# /etc/systemd/network/myfirstint.netdev
[NetDev]
Name=myfirstint
Kind=wireguard
Description=My first peer

[WireGuard]
PrivateKey = qJRZlE1QreqHNokgpmaFdkKALUxXthTmpmzbewFv53k=
ListenPort = 40001

[WireGuardPeer]
PublicKey = rcPNWjI0tPAVRr09TNxC8B+PhqSHRPnD3lPOxgkW01U=
Endpoint = it.example.com:40002
AllowedIPs = 0.0.0.0/0,::/0
# /etc/systemd/network/myfirstint.network
[Match]
Name=myfirstint

[Address]
Address=169.254.39.39/32
Peer=169.254.73.73/32

[Address]
Address=fe80::3939/64

# 如果地址在同一个网段中则不必写 Peer= 一行

然后 systemctl restart systemd-networkd 即可。

使用 /etc/network/interfaces 配置 GRE

其实 GRE 也可以用 systemd-networkd 配置。至于为什么这里没有那么做,是因为如果要用 systemd-networkd 配置 GRE 的话,需要修改当前连接到互联网所用 interface 的配置文件(例如 eth0.network),而对它进行修改容易导致网络中断。如果是在本机可能还好,对于那些没有正经 VNC,只能通过 SSH 连接的 VPS 服务商,断网就是灾难。

除了对方的 IP 之外,我们还需要一条在前文中没有提到的内容:

  • 本机连接到互联网所用 interface(例如 eth0)的本地地址。在家庭网络中通常是 192.168.x.x,在大型企业网络中通常是 10.x.x.x,在 VPS 上则有可能是 172.x.x.x 等。这里我们假设它是 172.39.3.9

这大概也是 systemd-networkd 需要修改 eth0.network 这类文件的原因。

/etc/network/interfaces 插入如下内容:

# /etc/network/interfaces
auto myfirstint
iface myfirstint inet tunnel
        address 169.254.39.39
        dstaddr 169.254.73.73
        mode gre
        netmask 32
        endpoint 73.73.73.73
        local 172.39.3.9
        ttl 255
iface myfirstint inet6 manual
        up ip addr add fe80::3939 peer fd80::7373 dev $IFACE

确认 peer 可以连通

首先启动我们所设置的 VPN:

  • 如果用 systemd-networkd 配置,运行 systemctl restart systemd-networkd
  • 如果用 /etc/network/interface 配置,运行 ifup myfirstint

查看 interface 是否被创建:

ip link

然后试着 ping 就好:

ping 169.254.73.72 -I myfirstint

配置路由:bird.conf

这里的配置只需要进行一次。在后续的 peer 过程中可跳过此步骤。

bird、FRRouting 及 Cisco 相关套件均可用于路由配置。这里我们使用 bird 2.0。为什么用了 Bird 2 呢?基于以下原因:

  • 试过 FRRouting,坑太多,文档太少,印象不好。
  • bird 2.0 支持 M-BGP

总之首先:

apt-get install bird2

对于 bird.conf ,各位可以直接抄 dn42 wiki 提供的配置文件。相对 bird 1.6 把 IPv4 和 IPv6 放在一起写的情况,bird 2 将 IPv4 和 IPv6 分开,所以稍微要长一些。

基本上后面照抄,修改开头的几行就可以:

define OWNAS =  <OWNAS>;               # AS 号
define OWNIP =  <OWNIP>;               # IPv4 地址
define OWNIPv6 = <OWNIPv6>;            # IPv6 地址
define OWNNET = <OWNNET>;              # 欲广播的 IPv4 网络段
define OWNNETv6 = <OWNNETv6>;          # 欲广播的 IPv6 网络段
define OWNNETSET = [<OWNNET>+];        # 欲广播的 IPv4 网络段,集合格式
define OWNNETSETv6 = [<OWNNETv6>+];    # 欲广播的 IPv6 网络段,集合格式

几件注意事项:

关于 ROA

ROA (Route Origin Validation),这里暂译为「路由来源认证」。它可以指定一个 IP 段只能由特定 AS 广播(这时,由其它 AS 广播的此段 IP 信息会被忽略),以及只能广播到特定的前缀长度(这时,过于具体的广播就会被忽略)。BGP 是相当依赖于信任的协议。如果没有 ROA 的保护,恶意的或失误的 BGP 广播可能会造成中间人攻击或严重的网络中断。

dn42 提供的 bird2 配置默认开启了 ROA。为了应用 ROA,你需要下载相关的数据(例如由 burble 生成的 dn42 ROA 文件,在这里)并且定期更新。

你也可以不使用 ROA。如果这样的话,记得把配置文件中与 ROA 相关的地方删除(大概有三处)。

如果你只广播 IPv4 / IPv6...

如果只需要 IPv4 或 IPv6 的广播,可以把不需要的地方删除掉,不过 router id 一行需要保留(即使你只广播 IPv6),并且应该填入一个 IPv4 地址(不一定必须是你所使用的地址)。

配置路由:/etc/bird/peers

如果是 BGP 协议,dn42 提供的配置模板依旧可用,照抄即可:

# /etc/bird/peers/myfirstpeer
protocol bgp myfirstpeer from dnpeers {
        neighbor 169.254.73.73%myfirstint as 4242424273;
}

protocol bgp myfirstpeer_v6 from dnpeers {
        neighbor fe80::7373%myfirstint as 4242424273;
}

如果双方都启用了 M-BGP,这里只填写一个即可建立 IPv4 + IPv6 的路由会话。如果 VPN 是按照上述配置进行的,那么 %myfirstint 部分通常是可以省略的。

确认所使用的路由协议(通常是 BGP)可以建立连接

(请切换到 root。)

首先,重新加载路由配置:

birdc configure   # 或 birdc c

通过以下命令,可以查看各个路由配置的状态:

birdc show protocol  # 或 birdc s p
Name       Proto      Table      State  Since         Info
device1    Device     ---        up     2020-05-13
kernel1    Kernel     master6    up     2020-05-13
kernel2    Kernel     master4    up     2020-05-13
static1    Static     master4    up     2020-05-13
static2    Static     master6    up     2020-05-13
myfirstpeer BGP        ---        up     2020-05-13    Established
myfirstpeer_v6 BGP        ---        up     2020-05-13    Established

如果你看到新加入的 peer 右侧显示的是 "Established",那么恭喜!你的 peer 已经完成并且双方可以通讯。如果不是 Established,可能代表路由或 VPN 配置出现了问题。请根据 bird 的提示信息进行错误排查。

通过以下命令,可以查看某条路由配置的详细信息:

birdc show protocol all myfirstpeer # 或 birdc s p a myfirstpeer

FAQ

IP 后面的 /32 是什么意思?

这种类似 1.2.3.4/16 的条目出于 CIDR。它可以表示一个地址以及包括此地址在内的一个网络段。在设置 IP 地址时,这个地址代表欲设置的 IP,这个网络段则表示此 IP 所在的网络。 举个例子。如果在上文中你设置的地址是:

192.168.1.3/25

这代表这么几件事:

  • 你设置的 IP 是 192.168.1.3
  • 这个 IP 所在的网络是 192.168.1.0 - 192.168.1.127,共 2^(32-25) = 2 ^ 7 = 128 个地址。

同时,系统会设置一条 scope link 的路由使得到达这些地址的包使用这个 IP 作为默认源 IP(为什么是默认?因为它可能会被覆盖),从这个 interface 发出。于是,ip route 的执行结果会有一行大概长这样:

192.168.1.3/25 dev this-interface proto kernel scope link src 192.168.1.3

而 peer 也相当于加了一条特别的路由。例如上文的示例配置会产生这样的一条路由,把所有目标为 169.254.73.73 的包从 myfirstint 这个 interface 发出,源 IP 默认是 169.254.39.39ip route 中会出现大概这个样子的一行:

169.254.73.73 dev myfirstint proto kernel scope link src 169.254.39.39

为什么上文 IPv4 要写一行 peer?因为 169.254.39.39/32 所在的网络(169.254.39.39 - 169.254.39.39)不包含 169.254.73.73。所以需要添加一行 peer 告诉系统如何到达这个 IP。为什么上文 IPv6 配置时没有写 peer?因为 fe80::3939/64 指代的网络(fe80:0:0:0:0:0:0:0 - fe80:0:0:0:ffff:ffff:ffff:ffff)包括 fe80::7373/64,所以系统已经知道如何到达 fe80::7373

结语

在第一个 peer 完成后,不久这个新的 AS 就会出现在这里这里或者许多 dn42/NeoNetwork NOC 的 looking glass 上。

这篇很长的 peering 教程到这里大概就告一段落了。六月又要到了,中国大陆的网络服务又到了一年好几度的维护期,希望各位的网络连接安好。

参考来源

  1. https://map42.0x7f.cc/

评论



LIKE