返回
Featured image of post Dn42网络 初次尝试

Dn42网络 初次尝试

网络就像一片浩瀚的海洋,多多探索总能发现许多有趣的东西,最近本来想着注册一个ASN,并学习与实践一下BGP,但是注册一个公网的ASN需要一笔钱,并且在公网中配置路由一旦出错可能还会造成严重的后果(除此之外,个人身份注册的ASN还有实名上网之忧),在查询资料的时候了解到了DN42这个实验网络。并且在Lan Tian的博客中看到了非常详细的教程,于是决定公网ASN的注册先放一边,从DN42开始BGP学习与折腾之路。

入坑DN42

网络就像一片浩瀚的海洋,多多探索总能发现许多有趣的东西,最近本来想着注册一个ASN,并学习与实践一下BGP,但是注册一个公网的ASN需要一笔钱,并且在公网中配置路由一旦出错可能还会造成严重的后果(除此之外,个人身份注册的ASN还有实名上网之忧),在查询资料的时候了解到了DN42这个实验网络。 并且在Lan Tian的博客中看到了非常详细的教程,于是决定公网ASN的注册先放一边,从DN42开始BGP学习与折腾之路。

DN42 全称 Decentralized Network 42(42 号去中心网络)。DN42 的目的是模拟一个互联网。它使用了大量在目前互联网骨干上应用的技术(例如 BGP 和递归 DNS),可以很好地模拟一个真实的网络环境

注册部分蓝天的博客DN42的wiki以及这篇文章都有详细的介绍,我这里就不再赘述了。

填好信息发起合并请求后的一到两天内,管理员就会把提交的信息合并进入主分支。

我的ASN是AS4242420945,欢迎各位大佬来和我peer(虽然我现在自己都不是特别熟悉)

建立内网

在peer他人之前还是先把自己的网络给整明白了,我的计划是使用wireguard建立一个接近全网状的网络,为什么说是“接近”,因为考虑到我有部分没有公网ip的设备在未来可能也要接入这个网络,所以并不是还是需要依靠部分节点来作为中继。

初期使用五台服务器建立ASN内部网络(可以把他们都看成网络中的路由器,因为它们都需要开启包转发功能,可以进行转发)

网络内部服务器之间的连接

首先尝试让网络内部的机器直接或间接连接,我的网络地址范围是 172.20.210.0/26,即 172.20.210.0 - 172.20.210.63 这一段的地址,那么给下面的五个节点分配ip如下:

lax-1(洛杉矶) 172.20.210.1

lax-2(洛杉矶) 172.20.210.2

icn-1(首尔) 172.20.210.3

hkg-1(香港) 172.20.210.4

ovb-1(新西伯利亚) 172.20.210.5

首先这五台机器都得装好了wireguard

老内核的话先更新内核(可能还得使用backports源):

  1. 使用backports源 更新

    echo "deb http://deb.debian.org/debian $(lsb_release -sc)-backports main" | tee /etc/apt/sources.list.d/backports.list
    
    apt update
    
    apt -t $(lsb_release -sc)-backports install linux-image-$(dpkg --print-architecture) linux-headers-$(dpkg --print-architecture) --install-recommends -y
    
    apt install net-tools iproute2 wireguard
    
  2. 手动下载安装

    wget https://kernel.ubuntu.com/~kernel-ppa/mainline/v5.10.63/amd64/linux-headers-5.10.63-051063-generic_5.10.63-051063.202109080732_amd64.deb
    wget https://kernel.ubuntu.com/~kernel-ppa/mainline/v5.10.63/amd64/linux-headers-5.10.63-051063_5.10.63-051063.202109080732_all.deb
    wget https://kernel.ubuntu.com/~kernel-ppa/mainline/v5.10.63/amd64/linux-image-unsigned-5.10.63-051063-generic_5.10.63-051063.202109080732_amd64.deb
    wget https://kernel.ubuntu.com/~kernel-ppa/mainline/v5.10.63/amd64/linux-modules-5.10.63-051063-generic_5.10.63-051063.202109080732_amd64.deb
    dpkg -i *.deb
    

再开启了ip包转发,并关闭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=2" >> /etc/sysctl.conf
echo "net.ipv4.conf.all.rp_filter=2" >> /etc/sysctl.conf
sysctl -p

然后启动wireguard接口,注意,在每两台建立连接的服务器之间都要创建一个接口,我一开始配置的时候采用了一个配置文件中写上所有其他的Peer对象的方式,但是这样是有问题的,如果我们需要路由目的地址在我们的内部网络之外的数据包时,如果采用了单一接口的方式,那么所有的Peer中的Alllowips都是0.0.0.0/0,这里的路由会出现问题。而分成多个接口时,wireguard可以只负责传输数据,路由(接口选择)在数据包进入wireguard的接口之前就进行。

注意,务必加上Table=off 避免wg-quick修改路由,在这里,wireguard只应该负责传输数据。

wireguard的配置方式有多种,我尝试了其中的两种:

  1. wg的接口另外分配链路本地地址,单独将dn42地址绑定到dummy接口lo接口

    这种情况下,我们可以将两个链路本地地址分别绑定在wireguard两端的端点上,并将dn42地址绑定到dummy接口或者lo接口上,下面是我的配置文件:

    wireguard和bird的配置文件如下:

     [Interface]
     Address = fe80::3/64
     ListenPort = 50000
     PrivateKey = 
     MTU = 1420
     PostUp = ip addr add dev %i 169.254.3.4/32 peer 169.254.4.3/32
     Table = off
     [Peer]
     PublicKey = 
     AllowedIPs = 0.0.0.0/0, ::/0
     Endpoint = hkg1:50000
     PersistentKeepalive = 16
    

    之后创建dummy接口并绑定地址

    ip link del dummy
    ip link add dummy type dummy
    ip addr add 172.20.210.3/32 dev dummy
    ip addr add fde5:2a75:1037::3/128 dev dummy
    ip link set dummy up
    

    在所有服务器的wireguard都启动后,服务器之间已经建立了直接或间接地连接,但是此时还没有路由规则,我们需要来设置路由。

  2. wg的接口直接分配dn42地址,详见howto/wireguard的wg-quick部分,其实多个接口是可以绑定同一个ip的,和绑定链路本地地址的区别就是在bird中设置neighbor的时候需要使用对方的DN42地址,这种方式可能也需要添加一个dummy接口,方便导出路由。(也许有其他的方法,不过我还没找到。)

    [Interface]
    ListenPort = 50001
    PrivateKey = [privatekey]
    PostUp = ip addr add 172.20.210.1/32 peer 172.20.210.2/32 dev %i
    PostUp = ip addr add fde5:2a75:1037::1/128 peer fde5:2a75:1037::2/128 dev %i
    Table = off
    [Peer]
    PublicKey = [pubkey]
    AllowedIPs = 0.0.0.0/0, ::/0
    Endpoint = icn1:50001
    PersistentKeepalive = 16
    

网络内部的路由

现在asn内部的节点是可以直接互联了,但是他们当前的连接方式是直接连接,而不是像现实中采取一条最佳的路径(如延迟最低),并且如果我们需要动态的加入一些只和部分节点连接的节点时,这个网络内的其他节点会找不到到新节点的路径,所以我们还需要使用内部的动态路由协议。

路由软件使用 bird2,先apt-get install bird2进行安装,因为是初次接触bird,所以这里踩了很多的坑,最终才产出了一个“勉强能用,但是不知道有什么问题“的网络。

ospf

首先尝试使用ospf来进行网络内部的动态路由。

这部分可以参考下面的文章:

bird2的配置文件如下:

bird的配置如下(我强烈怀疑里面还有哪里存在未发现的问题…) 参考 BIRD 与 BGP 的新手开场

log "/var/log/bird.log" all;

router id 172.20.210.5;
define LOCAL_ASN = 4242420945;

protocol device {};

protocol kernel {
    ipv4 {
        import none;
        export filter {
            if source = RTS_STATIC then reject;
            # 设置连接的源ip为节点ip,不设置的时候默认使用peer节点的ip(169.254.x.x)
            krt_prefsrc = 172.20.210.5;
            accept;
        };
    };
};

# 如果采用了单独创建dummy绑定dn42的方式,需要下面这个协议
# direct 协议用来直接从内核的网络设备上获取地址和路由,并将其导入到 BIRD 的路由表中
protocol direct {
    ipv4; # 启用 ipv4 channel,否则不会收集 IPv4 路由
    ipv6; # 启用 ipv6 channel,同上

    interface "dummy";
    # 如果不写这个参数,那么 BIRD 会默认使用所有网络设备
    # 参数后面用逗号分隔不同的匹配字符
    # “*”表示通配符
    # 更详细的参数参照官方文档
    # https://bird.network.cz/?get_doc&v=20&f=bird-3.html#proto-iface
}

//ospf v3支持v6,但是需要开两个会话

protocol ospf v3 aospf {

  ipv4 {
        import all;
        export where source ~ [ RTS_DEVICE, RTS_STATIC ];
  };
        area 0 {
                # Add this interface clause for each local interface connecting to local routers
                interface "icn1" {
                        tx length 1420;
                        # Cost of 1 is safe for this because it's just a local jumper to another router which has cost
                        cost 10;
                        # Use PtP is going to a Mikrotik Router. BIRD and Mikrotik dont speak the same PTMP
                        # Use PtMP if going to other BIRD instances
                        # Use Broadcast for special scenarios that make sense, such as at a supernode.
                        type ptp;
                };
        };
}
protocol ospf v3 aospf_6 {
  ipv6 {
        import all;
        export where source ~ [ RTS_DEVICE, RTS_STATIC ];
  };
        area 0 {
                interface "icn1" {
                        tx length 1420;
                        cost 10;
                        type ptp;
                };
        };
}

各台服务器上都设置好bird之后,使用systemctl start bird启动服务,之后便可以试试 birdc show ospf neighbors 查看直接相连的邻居,或者 birdc show route 查看一下路由,或者干脆是mtr一下看看实际的路径,在我的配置中存在一个节点只和网络中的部分相连,可以看到通过ospf配置后,其他节点也可以与其间接相连了。

另外可以尝试修改cost,看看路径会发生什么变化,如下图,我修改了lax1~lax2的开销,强制让两台离得很近的服务器绕路连接: lax1-hkg1-icn1-lax2,在实际使用中我将cost设置为了服务器间的延迟。

BGP互联

在整理好了内部网络之后,我们便可以尝试和他人peer了,这样才能算是真正加入了dn42网络,关于bird bgp的配置,wiki里面提供了比较详细的介绍,我就不再重复了。官方模板提供了充足的过滤检查规则,避免你一不小心导出了错误的信息劫持网络的路由。

我采取的对接方法是:

  1. 双方使用wireguard建立连接,两端分配链路本地地址,dn42的地址则分配给dummy接口

    wireguard中的配置如下

    PostUp = ip addr add dev %i [本机链路本地地址]/32 peer [对方的机器的链路本地地址]/32
    PostDown = ip addr del dev %i [本机链路本地地址]/32 peer [对方的机器的链路本地地址]/32
    
  2. 在bird的配置文件中将peer的neighbor ip设置为对方的链路本地地址

  3. 双方启动bird,通过bird来配置dn42 ip的路由

另外还可以使用dn42 ip peer或者使用ipv6 link local地址peer,可以参考这篇文章.

peer之后没多久,便能在一些查看DN42网络图的网站上看见自己的as号了(前提是你peer的人能够到达dn42网络的较中心的位置),如图,我通过peer一个接入了不少网络的as4242422032得以访问到DN42网络的大多数地方,这点和现实中的网络非常像。

之后我们可以尝试ping一下dn42网络中的一些服务看看能否正常连接,比如

Service Name IP
Authoritative Service ns1.burble.dn42 172.20.129.1 fd42:4242:2601:ac53::1
Recursive Service dns.burble.dn42 172.20.129.2 fd42:4242:2601:ac53::53
DNS64 Service dns64.burble.dn42 fd42:4242:2601:ac53::64

BGP信息在内部的传输

在建立了bgp连接之后我们又会发现一个新的问题——bgp获得的路由信息只在建立了bgp连接的服务器上可用,网络中的其他服务器无法通过ospf获取到其他网络路由。 这时正常的 bgp获取的路由不应该使用igp在网络中传播,因为ospf在网络内传输路由的时候会丢失bgp的aspath等信息,如果网络中的另一台服务器和另外一个网络中的服务器建立了bgp会话,对方又没做ROA限制,那么你的其他网络的路由也会以你的ASN为起点传输出去,这样相当于把别人的路由给劫持掉了。关于BGP中存在的一些隐患可以查看 如何引爆 DN42 网络

于是我们需要一个方法来解决内部的路由传播。

ipv4 的链路本地地址没有作用域的概念,所有地址都是属于主机的

蓝天提供了模拟confederation来在内部传播bgp的路由,不过我打算先从简单的开始,先使用ibgp,需要注意的是,为了避免出现环路,路由器不会向其他路由器发送从同一个AS下的路由器收到的BGP路由,所以我们要让网络中的所有路由器(服务器)都与所有的边界路由器(与其他AS建立BGP会话的服务器)建立起BGP会话,这样才能够让网络中的所有服务器都收到跨ASN的路由信息,另外提一点,由于我们在内网使用了OSPF,所以建立BGP会话并不需要建立一个直接连接的隧道,间接连接也是可以的。

iBGP

这部分参考了: Multiple servers on dn42: iBGP and IGPs

在 bird.conf 中添加一个模板

template bgp IBGP {
    local as OWNAS;
    multihop; # 因为我们用了ospf, ibgp的邻居可能是间接连接的,所以改为使用multihop

    ipv4 {
        next hop self; # 边界的路由器需要加上这个一个, 修改路由的下一条。
        # Optional cost, e.g. based off latency
        cost 50;

        import all;
        export all; # 非边界路由器可以设置为none
    };

    ipv6 {
        next hop self;
        cost 50;

        import all;
        export all;
    };
}

并在配置文件后面追加 include "/etc/bird/ibgps/*";

再新建一个ibgps文件夹,里面存放边界路由器相关的配置,如 lax1.conf: (放多个邻居在这个文件中也是可以的),边界路由器和内部的路由器都要设置ibgp,邻居ip设置为对方的ip即可,内部的路由会由ospf负责。

protocol bgp lax1 from IBGP {
 neighbor 172.20.210.1 as 4242420945;
}

image-20210915112121161
image-20210915112121161

重启bird之后再尝试在我们内部的服务器上ping dns42网络内部其他asn内的ip,比如 ping 172.20.129.1,此时已经能得到回应了。之后在网络内的每一台服务器都配置了与边界服务器的bgp会话,由此,整个网络才算真正接入到了DN42中。

尝试由新加坡trace到dn42内的权威域名服务器。

后记

之前BGP、IGP这些概念不过是书本上抽象的知识,直到这次加入DN42网络,我才第一次在实际中使用到了这些协议,不过目前我的配置还基本上是"知其然,不知其所以然",很多配置都来源于照抄网上的资料,并没有真正弄明白为什么要这样写(可能存在BUG都不自知)。另外对于这些路由协议我依旧只有一个模糊的认识,缺少系统性的学习,接触到这些之后才发觉自己在网络方面的知识还是相当的匮乏,还有相当多的东西要学习,这些都需要在之后的实践中慢慢补足。在配置好BGP后,我又参考骏马金龙的第7章 DNS & bind从基础到深入为我的网络设置好了正向与反向解析。

另外,欢迎来和我peer~

ASN 4242420945

目前接入点有:

  • 洛杉矶
  • 首尔
  • 香港
  • 新西伯利亚

发邮件到 aoyou945@gmail.com 或者评论都可以。

参考

https://weiti.org/dn42/2018/01/13/ibgp-bgp-within-as4242423905

https://jlu5.com/blog/dn42-multiple-servers-ibgp-igps

wireguard配置

https://miaotony.xyz/2021/03/25/Server_DN42/

https://idndx.com/ospf-over-wireguard/

https://blog.kintone.io/entry/bird

踩坑DN42注册

Licensed under CC BY-NC-SA 4.0
最后更新于 Sep 16, 2021 23:10 +0800
comments powered by Disqus
本站访客数:
Built with Hugo
Theme Stack designed by Jimmy