三分鐘搞懂DN42 wiki裡面的BIRD2範例設定檔

當初知道DN42的時候,還什麼都不懂
只會抄配置,抄來了也不懂意思。經過了好幾個月,才搞懂他到底在幹嘛

我當初的癥結點,是卡在「不知道他的交互對象
一旦搞懂這些,剩下的就迎刃而解了。但我當初不知道,摸了很久才發現這點。

所以想花三分種講說明一下


路由是一個長類似這樣的資料結構(加上一些額外標記)

[1] 192.168.1.0/24 → dev eth0
[2] 192.168.2.0/24 → via 192.168.1.1
[3] 192.168.3.0/26 → dev eth0 via 169.254.42.1 

以上面的三條路由為例,假如我們 kernel 內有這三條路由,然後 kernel 依序收到以下封包,這是接下來會發生的事情:

1. 任何封包發送時,首先第一步就是決定要往哪張物理網卡送。畢竟網卡是網路連線的渠道

DstIP=192.168.1.9。查詢到路由表裡的 [1],就會把這個封包送往eth0
DstIP=192.168.2.9。查詢到路由表裡的 [2]。但是路[2]裡面沒有指明具體網卡,只有寫「請找192.168.1.1」,所以他又去找 192.168.1.1 了,匹配路由 [1]。路由[1]指定了網卡eth0,最後這個封包就會送往eth0了。這個步驟叫做遞迴查詢
DstIP=192.168.3.9。查詢到路由表裡的 [3]。但是[3]同時指定了網卡和IP。這個時候 [3]和[1] 的行為非常像,都是送入 eth0。不一樣的是下一步

2. 封包發送時,找到對應網卡以後,接下來就是填入目標的 mac address 了,這個時候不僅要查詢路由表,還要查詢 arp table
路由[1] 沒有指定IP,那麼DstIP是多少,就填入那個IP的 MAC 地址。
然而路由[3]比[1]多了「via」選項:「169.254.42.1」,那麼就會改為填入 169.254.42.1 的MAC地址

那麼我們要怎麼知道某IP的mac address呢? 電腦首先會在一個本地資料庫「arp table」裡面查詢。如果查不到,那電腦對那張網卡發出 arp request ,在區網內廣播「who has 169.254.42.1」,對面應答以後,就知道對面的 mac address,並存入本地的 arp table 「169.254.42.1 的 MAC地址是 02:5A:c3:XX:XX:XX」。

還有一種特殊情況: 網卡不是普通的 tap 類型網卡,而是 tun 網卡。比如 wireguard / openvpn(L3模式)/ tinc(L3模式) ,tun網卡沒有 L2 欄位。因此一旦確定了目標網卡,發現是tun網卡,封包就會直接出去了。忽略「via」選項

這就是路由表

簡單來說,有「dev」選項,就會送往該網卡,沒有「dev」選項,就會根據「via」選項,進行遞迴查詢,直到遇到有dev選項的路由表
有「via」選項,就會使用via選項指定的MAC地址,沒有就看DstIP的MAC地址
IP->MAC地址對應則是查ARP表,ARP查不到就發arp query

以上說明是L2設備的情況。

L3設備沒有MAC地址,所以「192.168.3.0/26 → via 169.254.42.1 dev tun0」畫線的地方是無效的

首先,BIRD有2張路由表,叫做master4和master6,分別存放ipv4和ipv6路由。
以下只會提到master4,但ipv6的東西會放master6,但我省略了

這個是wiki裡面的BIRD範例設定檔: https://wiki.dn42.dev/howto/Bird2

首先,每個protocol都是一個打交道的對象。
import代表「對面發給我的東西,塞去master4」
export代表「把master4裡面的東西,丟給對面」



第一段

protocol static {
    route OWNNET reject;

    ipv4 {
        import all;
        export none;
    };
}

route OWNNET reject: 這裡有一個靜態路由 OWNNET → unreachable
import all: 把這裡(只有一條)的路由全部丟去master4
export none: master4裡面的東西都不要進來

第二段

這次打交道的對象是linux kernel的系統路由表了

protocol kernel {
    scan time 20;

    ipv4 {
        import none;
        export filter {
            if source = RTS_STATIC then reject;
            krt_prefsrc = OWNIP;
            accept;
        };
    };
}

import none不要把系統路由表的任何東西丟進master4
export filter{XXX}: master4的東西,過filter以後丟進系統路由表
{XXX} 如果是靜態路由就拒絕。因為OWNNET是自己的內網,應該是自己配好,不用BIRD幫你塞

第三段

這裡,打交道的對象就是和你peer的人了

template bgp dnpeers {
    local as OWNAS;
    path metric 1;

    ipv4 {
        next hop self;
        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;
            } else accept;
          } else reject;
        };

        export filter { if is_valid_network() && source ~ [RTS_STATIC, RTS_BGP] then accept; else reject; };
        import limit 1000 action block;
    };
}}
這裡先不管filter,意思基本上就是:
對面發給我的全部加入master4,master4裡面的全部丟給對面
也就是互發全表的意思。

總結

綜上所述,這三段大致做這三件事:
1. 定義一條OWNNET,塞進master4
2. 對面丟給我的全部塞進master4,自己master4全部塞給對面(互發全表)
3. master4全部(OWNNET除外)塞進系統路由表

了解這些以後,還要搭配查閱BIRD文檔

當然,過濾是非常重要的一環。把不要了路由漏給別人,俗稱漏油,是十分不好的
我這裡只是大致說明DN42範例配置檔,在理想情況下的運作方式

要特別感謝soha大神的這篇文章,有很多部分是看完這篇才懂的: https://soha.moe/post/bird-bgp-kickstart.html

留言