Lan Tian @ Blog

在 Traceroute 里膜 拜大佬

Traceroute 是常用的检查网络状况的工具之一,会显示你操作的电脑到指定服务器的网络路径上经过的每一个路由器的 IP 地址,类似于这样:

插图

可以看到后两跳的 IP 显示出了对应的域名,这个域名就是 IP 的反向解析记录。反向解析记录在 DNS 服务器中以类似 4.3.2.1.in-addr.arpa 域名的 PTR 记录形式存在。更多的信息可以参考《在 DN42 中设置 IP 反向解析》这篇文章。

然而,PTR 记录并不一定要设置成实际的域名,可以设置成任意的字符串,只要“和域名长得像”即可。利用这一点,我们可以在一段 Traceroute 中的每一跳上写一句话,整段就组成了完整的文章,类似下图:

插图

本文均在 DN42 网络中完成,如果你已经加入了 DN42 网络,可以 ping、traceroute 通文中的 IP。但本文并不局限于 DN42,如果你有可以自己控制反向解析的公网或内网 IP 段,也可以用相同的方法完成设置。

准备路由

第一步是设置一批路由器,让它们依次把某个 IP 对应的数据包层层转发下去,从而在 Traceroute 中产生一条较长、足以写文章的路径。

最原始的方法,就是找几台路由器,用网线串联起来。但是首先,我得有这么多路由器;另外,我还得把它们连入 DN42。

进一步想,Linux 也具有路由功能,也可以在一台服务器上开几台 Linux 虚拟机,分别分配 IP 地址,然后在每台上面运行:

ip route add [目标 IP]/32 via [下一个虚拟机的 IP]

目标 IP 的流量就会经过每一台虚拟机转发,产生一段路径。

接下来就要考虑怎么开这些虚拟机了。我的 Kimsufi 服务器上有 ESXi,用 Alpine Linux 开一排虚拟机也不是很占资源,但是如果这样操作,就需要手动配置好几台(本例中是 5 台)虚拟机,太麻烦了!

换一种思路:Docker 实际上就是一个对 LXC 容器的管理工具,而 LXC 容器都拥有独立的网络命名空间,可以独立设置自己的 IP、路由信息,在这个用途中完全可以代替完整的 Linux 虚拟机。

接下来就开始制作 Docker 镜像了。大致思路是基于 Alpine 镜像,然后在启动时运行如下脚本:

#!/bin/sh
echo Target IP is $TARGET_IP
THIS_IP=$(ip addr show dev eth0 | grep inet | cut -d' ' -f6 | cut -d'/' -f1)
echo My IP is $THIS_IP
NEXT_IP=$(echo $THIS_IP | awk -F. '{print $1 "." $2 "." $3 "." $4 + 1}')
if [ $THIS_IP == $NEXT_IP ]; then
    echo I\'m the target, listening
else
    echo Routing $TARGET_IP to $NEXT_IP
    ip route add $TARGET_IP/32 via $NEXT_IP
fi
ping 127.0.0.1 -q

最后一行的 ping 是让容器一直运行下去,不要退出。完整的 Dockerfile 可以在 https://github.com/xddxdd/dockerfiles/tree/master/route-next 看到。

然后是生成对应的 docker-compose.yml 以便统一管理,示例可以在上述 Repo 中看到。也可以用上述 Repo 中的 mk-compose.py 工具来快速生成 docker-compose.yml,但是生成完后仍需手工修改 network 中的网段信息。

然后把它传到服务器上 docker-compose up -d 启动这批容器。

最后,在运行 Docker 的服务器上执行这条命令:

ip route add 172.22.76.102/32 via 172.22.76.98

把流量传入第一个 Docker 容器。这时 Traceroute 一下,可以看到数据包的路径:

插图

准备文章

由于 PTR 记录只能存在英文,因此我们要先找一篇英文短文。由于 8 月 17 快到了,我选了这样一篇文章:

One should uphold his country’s interest with his life, he should not
do things just to pursue his personal gains and he should not evade
responsibilities for fear of personal loss.

由于上面数据包的路径上总共有 5 跳,因此将文章拆分成 5 段,并删除 PTR 记录中不允许存在的标点符号:

  • one should uphold his country s interest with his life
  • he should not do things
  • just to pursue his personal gains
  • and he should not evade responsibilities
  • for fear of personal loss

然后把空格全部换成英文句点:

  • one.should.uphold.his.country.s.interest.with.his.life
  • he.should.not.do.things
  • just.to.pursue.his.personal.gains
  • and.he.should.not.evade.responsibilities
  • for.fear.of.personal.loss

然后一句一句填到路径上各个 IP 的 PTR 反向解析记录里:

插图

保存,等待 DNS 生效后:

插图

你在 Traceroute 中就可以看到一篇文章了。

在 DN42 中设置 IPv6 反向解析

DN42 全称 Decentralized Network 42(42 号去中心网络),是一个大型的 VPN 网络。但是与其它传统 VPN 不同的是,DN42 使用了大量在互联网骨干上应用的技术(例如 BGP),可以很好的模拟一个真实的网络环境。

我在先前的一篇文章中加入了 DN42 网络,并在另一篇文章中注册了自己的域名,设置了自己的 DNS 服务器。然后,我在这一篇文章设置了 IPv4 的反向解析。当时由于 DN42 Wiki 上的信息有点问题,导致我当时认为不能设置 IPv6 反向解析,但经过我尝试后发现是可以的。

因为设置的是大体相同的东西,所以本文会和之前 IPv4 的文章有比较多的内容重复(复制粘贴)。

设置 IP 段的解析服务器

第一步是将自己所有的 IP 段解析到自己的 DNS 服务器上,我的服务器是 ns[1-2].lantian.dn42,可以全填。

在 IPv4 文中我直接用了原先的设置,但是因为我 IPv6 的 DNS 设置有问题,不得不改,因此只能发一次 Pull Request 修改 IPv6 的 DNS 服务器,并顺手把 IPv4 的也改了。

在 git clone 下 DN42 的数据文件后,在自己的 IP 段文件中添加这样一句话:

nserver:            ns1.lantian.dn42
nserver:            ns2.lantian.dn42

整个文件就看起来像这个样子:

inet6num:           fdbc:f9dc:67ad:0000:0000:0000:0000:0000 - fdbc:f9dc:67ad:ffff:ffff:ffff:ffff:ffff
netname:            LANTIAN-IPV6
descr:              Peer with me at b980120@hotmail.com
country:            CN
admin-c:            LANTIAN-DN42
tech-c:             LANTIAN-DN42
mnt-by:             LANTIAN-MNT
nserver:            ns1.lantian.dn42
nserver:            ns2.lantian.dn42
status:             ASSIGNED
cidr:               fdbc:f9dc:67ad::/48
source:             DN42

接下来 git add,git commit,发 Pull Request 等待合并,等待递归 DNS 生效等等。

设置 PowerDNS

在等待的同时,就可以把解析服务器先搭起来。首先按照这篇文章,我们已经有了一个 PowerDNS 的服务器。而解析 IP,其实类似于解析一个特殊的域名。

因为 IPv6 地址够多,DN42 中人手一个 /48 块,因此不存在像 IPv4 一样,需要根据 IP 段的大小加上“/29”等内容。IPv6 的特殊域名就是 “[IP 顺序反过来].ip6.arpa”。例如我的 fdbc:f9dc:67ad::/48 对应的就是 d.a.7.6.c.d.9.f.c.b.d.f.ip6.arpa。

将这个域名添加到 PowerDNS 中,如图:

插图

然后就是为每个 IP 设置自己的反向解析记录,即 PTR 记录。例如 fdbc:f9dc:67ad::8b:c606:ba01 的就是 1.0.a.b.6.0.6.c.b.8.0.0.0.0.0.0.0.0.0.0.d.a.7.6.c.d.9.f.c.b.d.f.ip6.arpa,如图填写:

插图

但是这样手动转换很容易少 0,出现问题。偷懒的办法是找一台 Linux 或 Mac 机器运行 dig -x fdbc:f9dc:67ad::8b:c606:ba01,出现如图输出:

插图

其中 QUESTION SECTION 下面就会出现 IPv6 地址对应的 PTR 记录名:

;; QUESTION SECTION:
;1.0.a.b.6.0.6.c.b.8.0.0.0.0.0.0.0.0.0.0.d.a.7.6.c.d.9.f.c.b.d.f.ip6.arpa. IN PTR

此例中即为 1.0.a.b.6.0.6.c.b.8.0.0.0.0.0.0.0.0.0.0.d.a.7.6.c.d.9.f.c.b.d.f.ip6.arpa。

等待 DN42 的递归 DNS 生效之后,就可以用 dig -x [IP 地址] @172.23.0.53 的命令查询反向记录了。

在 DN42 中设置 IP 反向解析

DN42 全称 Decentralized Network 42(42 号去中心网络),是一个大型的 VPN 网络。但是与其它传统 VPN 不同的是,DN42 使用了大量在互联网骨干上应用的技术(例如 BGP),可以很好的模拟一个真实的网络环境。

我在先前的一篇文章中加入了 DN42 网络,并在另一篇文章中注册了自己的域名,设置了自己的 DNS 服务器。有了 DNS 服务器,我们就可以给自己的 IP 也设置上反向解析记录。反向解析记录的主要用途是反垃圾邮件,以及在 ping、traceroute 等网络工具中或许能好看一点。

设置 IP 段的解析服务器

第一步是将自己所有的 IP 段解析到自己的 DNS 服务器上,我的服务器是 ns[1-3].lantian.dn42,理论上可以全填,但是由于 DN42 现在修改配置需要发 Pull Request,流程比较长,我就保留了最初注册这个 IP 时设置的 DNS 服务器,只有 ns1.lantian.dn42。

在 git clone 下 DN42 的数据文件后,在自己的 IP 段文件中添加这样一句话:

nserver:            ns1.lantian.dn42

整个文件就看起来像这个样子:

inetnum:            172.22.76.184 - 172.22.76.191
netname:            LANTIAN-IPV4
remarks:            Peer with me at b980120@hotmail.com
descr:              Peer with me at b980120@hotmail.com
country:            CN
admin-c:            LANTIAN-DN42
tech-c:             LANTIAN-DN42
mnt-by:             LANTIAN-MNT
nserver:            ns1.lantian.dn42
status:             ASSIGNED
cidr:               172.22.76.184/29
source:             DN42

接下来 git add,git commit,发 Pull Request 等待合并,等待递归 DNS 生效等等。

设置 PowerDNS

在等待的同时,就可以把解析服务器先搭起来。首先按照这篇文章,我们已经有了一个 PowerDNS 的服务器。而解析 IP,其实类似于解析一个特殊的域名。

对于 /24 的 IP 段,这个特殊的域名就是 [IP 顺序反过来].in-addr.arpa,例如 192.168.0.0/24 的就是 0.168.192.in-addr.arpa。但多数 DN42 用户用不到 /24,只注册了 /26 至 /29 的 IP 段,就需要把 IP 最后一位连上“/26”等一起处理。以我的 IP 段 172.22.76.184/29 为例,对应域名就是 184/29.76.22.172.in-addr.arpa。

将这个域名添加到 PowerDNS 中,如图:

插图

然后就是为每个 IP 设置自己的反向解析记录,即 PTR 记录。例如 172.22.76.185 的就是 185.184/29.76.22.172.in-addr.arpa,如图填写:

插图

等待 DN42 的递归 DNS 生效之后,就可以用 dig -x [IP 地址] @172.23.0.53 的命令查询反向记录了,类似下图:

插图

另外 DN42 的 IPv6 反向解析可以在这篇文章看到。

在 DN42 中注册自己的域名

DN42 全称 Decentralized Network 42(42 号去中心网络),是一个大型的 VPN 网络。但是与其它传统 VPN 不同的是,DN42 使用了大量在互联网骨干上应用的技术(例如 BGP),可以很好的模拟一个真实的网络环境。

我在先前的一篇文章中加入了 DN42 网络,并连接了大部分自己拥有的 VPS。(剩下几台是没有 Tun/Tap 的 OpenVZ VPS,无法加入)之前我就知道 DN42 拥有自己的域名体系,例如 DN42 的 Wiki 站(https://wiki.dn42.us/Home)就可以在 DN42 中以 https://internal.dn42 的域名访问,但是之前没有时间去完成域名注册,并且当时对 DN42 的了解还不够。这个月我完成了域名注册,就来分享一下过程。

搭建权威 DNS 服务器

权威 DNS 服务器,就是指管理某个域名记录的服务器。例如本站主域名 lantian.pub 的权威服务器是 lv3ns[1-4].ffdns.net,就是 CloudXNS。在互联网上注册域名时,我们可以用现成的 CloudXNS、Cloudflare 等免费 DNS 服务,但是在 DN42 中,虽然有人提供这样的服务,但是需要在 IRC 上与他们交流申请,我觉得太麻烦,就干脆自建了。

Linux 下自建 DNS 一般使用 Bind 或 PowerDNS 两款软件。Bind 以文件形式保存 DNS 记录,跨服务器同步有些麻烦,而 PowerDNS 不仅可以用文件保存,还可以用 MySQL 等数据库形式保存,同时自己也提供记录同步功能。

由于我配置 PowerDNS 自带的记录同步功能总是失败,查不出原因,我就干脆设置了 MySQL 主从复制来进行同步。

搭建 DNS:设置 MySQL 主从同步

首先,在每台服务器中安装一个 MySQL,并且在 my.cnf 设置上这些内容:

# 每台服务器的编号,随便设置,但不能重复
server-id=1
# 每台服务器的名称,设置后可以在 phpMyAdmin 中看到从服务器的名字
report-host=Master
# MySQL 日志文件的位置,主从复制的核心文件
log_bin=mysql-bin
log_error=mysql-bin.err

然后用 phpMyAdmin 登录主 MySQL 服务器,在“Replication / 主从复制”页面将这台服务器设置为 Master / 主服务器,并创建一个用于主从复制的用户(拥有 REPLICATION SLAVE 和 REPLICATION CLIENT 权限)。由于这一步我已经做过了,所以我没法截图。

设置完后你应该可以看到类似这样的状态:

插图

其中的“File / 文件名”就是日志文件名,“Position / 位置”就是当前记录的行数。记下这两个值。

然后,关闭所有服务器上的 MySQL,用 rsync 之类方法把数据库复制到从服务器上,覆盖掉各自的数据目录,再打开所有的 MySQL。如果是没什么数据库写入操作的站,例如个人小博客,可以尝试不关主服务器 MySQL,但是可能会造成复制出去的数据损坏。

然后,用 phpMyAdmin 登录从 MySQL 服务器。因为 phpMyAdmin 在设置从服务器时有奇怪的 bug,所以我没用它的向导来设置,而是直接执行 SQL:

change master to master_host='服务器 IP',
master_user='主从复制用户名',
master_password='主从复制用户密码',
master_log_file='主服务器日志文件名',
master_log_pos=主服务器记录行数;
start slave;

然后进入“Replication / 主从复制”页面,点击“See slave status table / 查看从服务器状态表”,确认 Slave_IO_Running 和 Slave_SQL_Running 均为 Yes,主从同步就已经开始了。

插图

搭建 DNS:设置 PowerDNS

设置完数据库,我们就可以设置 PowerDNS 了。先在 MySQL 给 PowerDNS 建立一个用户和数据库。因为我是 Docker 用户,所以在主服务器上,直接用 docker-compose 下载镜像并启动:

powerdns:

image: psitrax/powerdns
container_name: powerdns
restart: always
entrypoint: "/entrypoint.sh --cache-ttl=120 --master=yes --slave=yes"
environment:
  - MYSQL_HOST=数据库服务器地址
  - MYSQL_USER=数据库用户名
  - MYSQL_PASS=数据库密码
  - MYSQL_DB=数据库名字
ports:
  - "DN42 内的 IP 地址:53:53"
  - "DN42 内的 IP 地址:53:53/udp"

然后 PowerDNS 可能会启动失败,提示在创建 comments 表时某些列过长。这是因为 MySQL 的一些配置被修改了,导致数据表的行为发生了变化,而这些列最长可达 64000 Bytes,修改后的数据表存不下。

解决这个问题不需要再改数据库配置,只需要把 64000 改小,例如 16000,然后手动创建表即可:

CREATE TABLE domains (
  id                    INT AUTO_INCREMENT,
  name                  VARCHAR(255) NOT NULL,
  master                VARCHAR(128) DEFAULT NULL,
  last_check            INT DEFAULT NULL,
  type                  VARCHAR(6) NOT NULL,
  notified_serial       INT DEFAULT NULL,
  account               VARCHAR(40) DEFAULT NULL,
  PRIMARY KEY (id)
) Engine=InnoDB;

CREATE UNIQUE INDEX name_index ON domains(name);

CREATE TABLE records (
  id                    INT AUTO_INCREMENT,
  domain_id             INT DEFAULT NULL,
  name                  VARCHAR(255) DEFAULT NULL,
  type                  VARCHAR(10) DEFAULT NULL,
  content               VARCHAR(64000) DEFAULT NULL,
  ttl                   INT DEFAULT NULL,
  prio                  INT DEFAULT NULL,
  change_date           INT DEFAULT NULL,
  disabled              TINYINT(1) DEFAULT 0,
  ordername             VARCHAR(255) BINARY DEFAULT NULL,
  auth                  TINYINT(1) DEFAULT 1,
  PRIMARY KEY (id)
) Engine=InnoDB;

CREATE INDEX nametype_index ON records(name,type);
CREATE INDEX domain_id ON records(domain_id);
CREATE INDEX recordorder ON records (domain_id, ordername);

CREATE TABLE supermasters (
  ip                    VARCHAR(64) NOT NULL,
  nameserver            VARCHAR(255) NOT NULL,
  account               VARCHAR(40) NOT NULL,
  PRIMARY KEY (ip, nameserver)
) Engine=InnoDB;

CREATE TABLE comments (
  id                    INT AUTO_INCREMENT,
  domain_id             INT NOT NULL,
  name                  VARCHAR(255) NOT NULL,
  type                  VARCHAR(10) NOT NULL,
  modified_at           INT NOT NULL,
  account               VARCHAR(40) NOT NULL,
  comment               VARCHAR(16000) NOT NULL,
  PRIMARY KEY (id)
) Engine=InnoDB;

CREATE INDEX comments_domain_id_idx ON comments (domain_id);
CREATE INDEX comments_name_type_idx ON comments (name, type);
CREATE INDEX comments_order_idx ON comments (domain_id, modified_at);

CREATE TABLE domainmetadata (
  id                    INT AUTO_INCREMENT,
  domain_id             INT NOT NULL,
  kind                  VARCHAR(32),
  content               TEXT,
  PRIMARY KEY (id)
) Engine=InnoDB;

CREATE INDEX domainmetadata_idx ON domainmetadata (domain_id, kind);

CREATE TABLE cryptokeys (
  id                    INT AUTO_INCREMENT,
  domain_id             INT NOT NULL,
  flags                 INT NOT NULL,
  active                BOOL,
  content               TEXT,
  PRIMARY KEY(id)
) Engine=InnoDB;

CREATE INDEX domainidindex ON cryptokeys(domain_id);

CREATE TABLE tsigkeys (
  id                    INT AUTO_INCREMENT,
  name                  VARCHAR(255),
  algorithm             VARCHAR(50),
  secret                VARCHAR(255),
  PRIMARY KEY (id)
) Engine=InnoDB;

CREATE UNIQUE INDEX namealgoindex ON tsigkeys(name, algorithm);

这下 PowerDNS 就能成功启动了,但是它还没有任何记录。

搭建 DNS:安装 PowerAdmin

PowerAdmin 是一个 PowerDNS 的控制面板,可以去 https://github.com/poweradmin/poweradmin 下载安装。安装过程只需要跟着向导走即可,在此略过。

安装完后,进入主界面:

插图

点“Add Master Zone / 添加主区域”,这里是添加你要解析的域名的地方。在“Zone Name / 域名”中填入域名,然后直接确定。

返回主界面,点“List Zones / 域名列表”,点击域名左边的编辑按钮进行管理,进入如下界面,这里以我的 DN42 域名 lantian.dn42 为例:

插图

最开始装完 PowerAdmin 之后,创建的 SOA 记录开头可能是没有类似 ns1.lantian.dn42 一类的内容的,这样的 SOA 记录就不符合规范。我的 SOA 记录是“ns1.lantian.dn42 lantian.lantian.dn42 0 28800 7200 604800 60”,解释如下:

  • ns1.lantian.dn42:主要 DNS 服务器的名字,一般就是你现在在操作的服务器之后要取的域名。
  • lantian.lantian.dn42:DNS 服务器管理者的邮箱,但是 @ 符号被句点代替了,例如这里就是 lantian@lantian.dn42。在 DN42 中不一定需要真实地址。
  • 0:记录编号,如果使用 AXFR 等进行 DNS 记录同步,从 DNS 服务器可能会根据这个编号判断记录有没有更改。我们使用 MySQL 主从复制,所以这里不重要。这里设置为 0 代表 PowerDNS 会自动管理这一项,无需人工操作。
  • 28800:刷新时间,AXFR 从服务器两次拉取的间隔,同样不重要。
  • 7200:重试时间,AXFR 从服务器拉取失败后,再次拉取的时间,同样不重要。
  • 604800:过期时间,AXFR 从服务器拉取失败后,最多用先前最后一次拉取成功的记录继续提供服务这么长时间,之后停止应答。同样不重要。
  • 60:最小 TTL,所有记录的最小刷新时间,至少过了这么长时间才会刷新。

点击 SOA 记录左边的编辑按钮,对应着设置好,保存。

接下来要设置 NS 记录,指明你的域名由这几台 DNS 服务器提供服务。我这次设置 3 台服务器,分别是 ns[1-3].lantian.dn42,需要分别创建相应的 NS 记录,这样填写即可:

插图

一一提交即可。

最后设置 A 记录 指明域名指向某台服务器,这样填写即可:

插图

主 PowerDNS 服务器到此设置完成。因为设置了 MySQL 主从同步,所以你的配置也已经同步到了其它服务器上,在相应的服务器上安装 PowerDNS 即可。

最后 dig 一下自己的服务器测试:

插图

在 DN42 注册域名

DN42 最近进行了一次升级,弃用了原来的 Monotone 管理界面,改用 Git 管理。首先去 https://git.dn42.us/explore/repos 上面注册一个账号,Fork dn42/registry,Clone 到本地。

首先,DN42 要求 Git Commit 经过 GPG 数字签名。我在 Mac 上使用的软件是 GPG Keychain,Windows / Linux 下使用什么软件我并不了解。大致流程是:创建密钥,将公钥提交到 SKS 等公开 GPG 服务器上供查询,然后复制下 Fingerprint。

然后设置 git,打开自动签名每次 commit 的功能:

git config --global user.signingKey [你的 Fingerprint]
git config --global commit.gpgSign true

因为我是 DN42 老用户,已经有了自己的 MNT Handle,就打开 data/mntner/LANTIAN-MNT,加入相应的指纹信息,类似如下:

mntner:             LANTIAN-MNT
admin-c:            LANTIAN-DN42
tech-c:             LANTIAN-DN42
mnt-by:             LANTIAN-MNT
source:             DN42
auth:               pgp-fingerprint 23067C13B6AEBDD7C0BB567327F31700E751EC22

然后创建 data/dns/lantian.dn42:

domain:             lantian.dn42
admin-c:            LANTIAN-DN42
tech-c:             LANTIAN-DN42
mnt-by:             LANTIAN-MNT
nserver:            ns1.lantian.dn42 172.22.76.186
nserver:            ns1.lantian.dn42 fdbc:f9dc:67ad::8b:c606:ba01
nserver:            ns2.lantian.dn42 172.22.76.185
nserver:            ns2.lantian.dn42 fdbc:f9dc:67ad::dd:c85a:8a93
nserver:            ns3.lantian.dn42 172.22.76.187
nserver:            ns3.lantian.dn42 fdbc:f9dc:67ad::18:ca0f:741d
status:             CONNECT
source:             DN42

然后 git add,git commit,git push,然后发 Pull Request 等待合并,并根据管理员的提示修改可能出现的错误。

插图

因为 DN42 中采用 Anycast DNS,每个人都能建立递归 DNS 服务器,而每个人从中心库拉取配置的频率不一,因此可能要等最长一个星期的时间,你的域名才能生效。

插图

到此 DN42 域名就注册成功了,接下来就可以在上面配置网站、邮件、IRC、游戏服务器等等了。

加入 DN42 实验网络

DN42 全称 Decentralized Network 42(42 号去中心网络),是一个大型的 VPN 网络。但是与其它传统 VPN 不同的是,DN42 使用了大量在互联网骨干上应用的技术(例如 BGP),可以很好的模拟一个真实的网络环境。

正因为它的真实,使用 DN42 的门槛比较高。你要扮演一个 ISP(互联网服务提供商),注册一个 ASN 号码,注册 IPv4 和 IPv6 的地址池,并且使用 BGP 在自己的服务器上广播它们。你还要和其它的用户联系,和他们做 Peering(对接),一步步进入完整的 DN42 网络。

DN42 在 172.20.0.0/14 和 fd00::/8 上运行,而这两个 IP 段都是分配给内网使用的。换句话说,你在 DN42 上怎么折腾,都不会影响到服务器其它的互联网连接。

DN42 官方提供了很详细的注册 ASN 和 IP 的教程,只需一步一步照着做就可以,因此本文不会涉及该方面。本文的重点在地址池的广播和与其它用户的 Peering 上面。本文假定读者已经完成了 ASN、地址池的注册和设置,如图所示:

插图

首先,登录上你自己的服务器、VPS、OpenWRT 路由器、树莓派或者是其它什么有固定 IP,可以长时间在线,并且运行 Linux 的东西。我使用的系统是 Debian 9,因此如果你使用 CentOS、Arch Linux 之类的系统,一些软件包的名称和配置文件的位置可能会不同。

使用 OpenVPN 与其它用户 Peering

第一步当然是安装 OpenVPN,我们同时安装 Supervisor 方便管理:

apt-get install openvpn supervisor
update-rc.d openvpn disable #禁止 OpenVPN 开机自启动,全部交由 Supervisor 管理

然后生成一个预共享密钥用于 OpenVPN 的 P2P 互联:

openvpn --genrsa --secret [名称].key

之后,你就要联系其它已经接入 DN42 网络的用户。绝大多数情况下,你不知道你可以和谁 Peer,因此你可以访问 DN42 PingFinder,这个网站可以测量你的服务器到各个 DN42 用户服务器的延迟,方便你挑选延迟低的服务器来联系其管理员。大多数服务器集中在美国和欧洲,亚太地区只有日本和新加坡有寥寥几台,导致我的香港 VPS 有点懵逼。

插图

插图

还有一点要注意,你可以和不止一个人进行 Peer,就像在真实网络中一样。中国电信不可能只和中国联通连接吧?它还要连接其它国家的运营商。DN42 网络同理。你大可以一口气和离你服务器近的几个人全部发邮件联系,并且同时和他们所有人 Peer。

总之,你决定好了要和谁 Peer。现在你要和他交换以下信息:

  1. 双方服务器的公网 IP,和 OpenVPN P2P 模式连接的端口
  2. 双方服务器在 DN42 内的 IP
  3. 双方的 DN42 AS 编号
  4. OpenVPN 的预共享密钥

然后双方同时在服务器上安装这样一份 OpenVPN 配置文件:

proto       udp
mode        p2p
remote      [对方真实 IP]
rport       [对方端口号]
local       [我方真实 IP]
lport       [我方端口号]
dev-type    tun
tun-ipv6
resolv-retry infinite
dev         [Linux 虚拟网卡名称,可随便起]
comp-lzo
persist-key
persist-tun
cipher aes-256-cbc
ifconfig-ipv6 [我方 DN42 IPv6] [对方 DN42 IPv6]
ifconfig [我方 DN42 IPv4] [对方 DN42 IPv4]
secret [前面生成的预共享密钥的位置].key

并且都 openvpn --config [配置文件路径] 运行起来,互相 Ping 通对方的 DN42 IP,互联的第一步就成功了。

/etc/supervisor/conf.d 里放一份配置文件:

[program:[自己起个名字]]
command=openvpn --config [配置文件路径]
autostart=true
autorestart=true

然后 supervisorctl reload,你以后就可以用 Supervisor 来控制这个连接了。

使用 Bird 进行 BGP 宣告

连接 VPN 类似于在真实世界中两个 ISP 之间拉上了网线。接下来,两个 ISP 要互相告诉对方自己能连接到哪些 IP,这个过程称为 BGP 宣告。比较常用的 BGP 软件是 Bird,因此先安装它:

apt-get install bird

DN42 官方有提供 Bird 的配置文件示例,但是有点小问题,让我走了一些弯路。首先,还是按照官方教程把配置文件都创建好。注意,配置文件中有些地方需要替换成自己的 AS 和 IP 段。

然后,假设你已经和另一名用户建立了 VPN 连接。在 /etc/bird/peers4/ 文件夹里建立一个配置文件,内容如下:

protocol bgp [自定义名称] from dnpeers {
  neighbor [对方 DN42 IPv4] as [对方 AS 号];
  direct;
};

相比官方文件多了一行 direct。没有这行 direct,Bird 就运行在 Multihop 模式下,有可能会出现 Bird 把对方宣告的路由全部标记成 unreachable 的情况。

同理,在 /etc/bird/peers6/ 里建立类似的配置文件,只要将上面的 IPv4 换成 IPv6 地址即可。完成后,执行 birdc configure && birdc6 configure 来重新加载配置。

执行 birdc show protocol 可以查看连接情况:

插图

最后的 Established 表明两台服务器已经成功建立 BGP 连接。如果出现 Idle,就必须把配置里的 direct 去掉。但是这又意味着有可能无法正常将对应的 IP 段路由到对方。这个问题我目前没有解决办法。

执行 birdc show route 可以查看 BGP 宣告过来的路由表:

插图

Ping 一下 172.23.0.53 或者 fd42:d42:d42:53::1(官方 DNS 服务器地址),连通了就代表你成功加入了 DN42 网络!

使用 ZeroTier One 多服务器互联

之前的 BGP 连接都是与其它用户进行连接。但是如果你有多台服务器,你也可以把它们互联起来,然后分别和距离较近的其它用户互联,组成一张大网。

一般的方法是服务器之间两两设置 OpenVPN P2P,但是麻烦不说,经常会因为路由表而出现问题,例如出现 A 连上 B,B 连上 C,C 连上 A,但是 B 连不上 A,C 连不上 B,A 连不上 C;或者是 A、B 能连 C,但 A、B 不能互联之类的诡异问题。这是因为 OpenVPN 对于多条链接建立了多个虚拟网卡,如果路由表设置不当,数据包走错网卡,就会“迷路”,出现诡异情况。

更加简单的方法自然是我之前写了两篇文章介绍的 ZeroTier One 了!所有服务器互联使用一张虚拟网卡,不再出现走错路的情况;另外中心管理之类的优点我就不再重复了。

首先自然是创建一个 ZeroTier 网络,并且把你从 DN42 拿到的 IP 段填入 Managed Routes 里:

插图

把你的 IPv4 段填入 IPv4 Auto Assign 里,让 ZeroTier 自动为你的服务器分配 IP 地址:

插图

并且把 IPv6 段填入 IPv6 Auto Assign 的 Auto Assign from Range 里。注意不需要启用 RFC4193 或者 6PLANE 的地址分配。

插图

然后在每台服务器上装好 ZeroTier One 并且加入网络:

插图

如果你有一些服务器的 IP 已经在之前的 Peering 过程中定好了,就应该在 ZeroTier 的面板上配置相同的 IP,防止冲突。可以用 Managed IP 的加号来添加自定义 IP,使用 IP 地址旁的垃圾桶来删除。

配置完成,测试各台服务器可以 Ping 通,接下来就按照上面的 Bird BGP 宣告教程进行就可以了。对方 IPv4 地址即为其它服务器分配到的 IP,而对方 AS 号这里直接填写自己的 AS 号就可以了。

记得开启系统的数据包转发功能,否则没有直接和外界 Peer 的服务器可能连不上 DN42 网络。

如何与我 Peering

如果你想加入 DN42 网络,可以找我 Peering,请阅读这篇文章,按照文中步骤操作。你也可以直接在这里评论。

(注:我不会在这里直接回复你的评论。我会向你填写的邮箱发送邮件来进行沟通。)