WireguardでOSPF

# WireguardでOSPF

## env

- node1: ConoHa VPS メモリ 512MB/CPU 1Core
    - Global-ip: 198.51.100.1/24(例[^KEY1])
    - lan-ip: 172.17.0.1/27(例) -- ConohaLAN
    - vpn-ip: 172.18.0.31/24(例)
    - OS: Almalinux9
        <details><summary>view detail</summary>
        
        ```sh:node1:sh$
        $ grep PRETTY_NAME /etc/os-release
        PRETTY_NAME="AlmaLinux 9.5 (Teal Serval)"
        ```
        
        ```sh:node1:sh$
        $ uname -r
        5.14.0-503.16.1.el9_5.x86_64
        ```
        
        ```sh:node1:sh$
        $ dnf info wireguard-tools frr
        Last metadata expiration check: 0:03:07 ago on Tue Dec 31 02:54:01 2024.
        Installed Packages
        Name         : frr
        Version      : 8.5.3
        Release      : 4.el9
        Architecture : x86_64
        Size         : 22 M
        Source       : frr-8.5.3-4.el9.src.rpm
        Repository   : @System
        From repo    : appstream
        Summary      : Routing daemon
        URL          : http://www.frrouting.org
        License      : GPLv2+
        
        Name         : wireguard-tools
        Version      : 1.0.20210914
        Release      : 3.el9
        Architecture : x86_64
        Size         : 289 k
        Source       : wireguard-tools-1.0.20210914-3.el9.src.rpm
        Repository   : @System
        From repo    : appstream
        Summary      : Fast, modern, secure VPN tunnel
        URL          : https://www.wireguard.com/
        License      : GPL-2.0-only

        ```
        </details>
- node2: ConoHa VPS メモリ 4GB/CPU 4Core
    - Global-ip: 203.0.113.1/24(例[^KEY1])
    - lan-ip: 172.17.0.2/27(例) -- ConohaLAN
    - vpn-ip: 172.18.0.32/24(例)
    - OS: Almalinux9
        <details><summary>view detail</summary>
        
        ```sh:node2:sh$
        $ grep PRETTY_NAME /etc/os-release
        PRETTY_NAME="AlmaLinux 9.5 (Teal Serval)"
        ```
        
        ```sh:node2:sh$
        $ uname -r
        5.14.0-503.16.1.el9_5.x86_64
        ```
        
        ```sh:node2:sh$
        $ dnf info wireguard-tools frr
        Last metadata expiration check: 0:01:30 ago on Tue Dec 31 02:53:46 2024.
        Installed Packages
        Name         : frr
        Version      : 8.5.3
        Release      : 4.el9
        Architecture : x86_64
        Size         : 22 M
        Source       : frr-8.5.3-4.el9.src.rpm
        Repository   : @System
        From repo    : appstream
        Summary      : Routing daemon
        URL          : http://www.frrouting.org
        License      : GPLv2+
        
        Name         : wireguard-tools
        Version      : 1.0.20210914
        Release      : 3.el9
        Architecture : x86_64
        Size         : 289 k
        Source       : wireguard-tools-1.0.20210914-3.el9.src.rpm
        Repository   : @System
        From repo    : appstream
        Summary      : Fast, modern, secure VPN tunnel
        URL          : https://www.wireguard.com/
        License      : GPL-2.0-only

        ```
        </details>

```

--------+---[Internet]----+--------
        |                 |
        |(eth0)           |(eth0)
    +-------+         +-------+
    | node1 |         | node2 |
    +-------+         +-------+
        |(eth1)           |(eth1)
        |                 | 
--------+------[LAN]------+--------

```

:::note info
Conohaプライベートネットワーク
[ドキュメント](https://support.conoha.jp/v/privatenetwork/)
各VPSは上記手順に則り、LAN(local-area-network)を構築済みです。
--> それぞれ `eth1` として使用可能な状態にセットアップ済み
:::

:::note warn
IPアドレスなどの設定値は実際の値とは異なります
一部情報に<ruby>齟齬<rp>(</rp><rt>そご</rt><rp>)</rp></ruby>がある場合があります。
:::


## install

RHEL系なので `dnf install -y wireguard-tools frr` でインストール（細かくは書きません。割愛します。）

```sh:sh$
sudo dnf install -y wireguard-tools frr
```

- /etc/frr/daemons
    - `ospfd=yes`
- firewall-cmd
    ```sh
    sudo firewall-cmd --permanent --change-interface=wg1 --zone=trusted
    sudo firewall-cmd --permanent --add-protocol=ospf --zone=trusted
    sudo firewall-cmd --permanent --add-masquerade --zone=trusted
    sudo firewall-cmd --reloads
    ```
- sysctl
    - /etc/sysctl.conf
    - /etc/sysctl.d/99-sysctl.conf
    ```sh
    sudo sysctl -w net.ipv4.ip_forward=1
    ```

    <details><summary>wireguard kernel-module(kmod)がインストールされなかった場合の追加作業(メモ書き)</summary>

    ```sh:sh$ epelとelrepoを使用可能にする
    sudo dnf install -y epel-release elrepo-release
    ```
    
    ```sh:sh$ elrepoを参照させ、kmod-wireguardを入れる
    sudo dnf install -y --enablerepo=elrepo kmod-wireguard wireguard-tools
    ```
    
    </details>


## ospf(frr) on eth1

- 設定方法は基本的にCiscoと同じ
- IPアドレスはOS側(`nmtui`)で実施。（`nmcli`で設定される方は各自調べてください）
- frrの設定(`sudo vtysh`)は専用モードに入って実施
    - `passive-interface default` 設定しない場合は `ip ospf passive` 不要

    ```sh:sh$
    sudo vtysh
    ```

    ```cisco_ios:vtysh#
    conf t
    ```
    
    <details><summary>view frr config</summary>

    ```cisco_ios:node1:vtysh(config)#
    router ospf
     passive-interface default
     network 198.51.100.1/32 area 0.0.0.0
     network 172.17.0.0/27 area 0.0.0.0
    exit
    interface eth1
     ip ospf mtu-ignore
     ip ospf priority 128
     no ip ospf passive
    end
    ```
    
    ```cisco_ios:node2:vtysh(config)#
    router ospf
     passive-interface default
     network 203.0.113.1/32 area 0.0.0.0
     network 172.17.0.0/27 area 0.0.0.0
    exit
    interface eth1
     ip ospf mtu-ignore
     ip ospf priority 64
     no ip ospf passive
    end
    ```

    </details>
    
    ```cisco_ios:node1:vtysh#(DR,BDR選出されればOK)
    # sh ip ospf nei
    Neighbor ID     Pri State           Up Time         Dead Time Address         Interface                        RXmtL RqstL DBsmL
    198.51.100.1   64 Full/Backup     1w2d07h           38.238s 172.17.0.１      eth1:172.17.0.2                      0     0     0
    ```
    
    ```cisco_ios:node2:vtysh#(DR,BDR選出されればOK)
    # sh ip ospf nei
    Neighbor ID     Pri State           Up Time         Dead Time Address         Interface                        RXmtL RqstL DBsmL
    198.51.100.1   128 Full/DR     1w2d07h           37.029s 172.17.0.2      eth1:172.17.0.1                      0     0     0
    ```

Wireguard絡まない部分はすんなり行くはず。  

## wireguard

- <ruby>PSK<rp>(</rp><rt>Pre Shared Key</rt><rp>)</rp></ruby>は面倒なので省略（作成は`wg genpsk`）
    - `[Peer]`セクションの中に`PresharedKey = `項目作ってそこに`wg genpsk`の結果をペタペタ
    <details><summary>details</summary>

    ```conf
    [Interface]
    PrivateKey =
    Address =
    PreUp =
    PostUp =
    PreDown =
    PostDown =
    DNS =
    MTU =
    ～略～

    [Peer]
    PublicKey =
    PresharedKey = `wg genpsk`の結果をペタペタ
    
    [Peer]
    PublicKey =
    PresharedKey = `wg genpsk`の結果をペタペタ
    ```
    
    </details>
    - PSKはノード(ホスト)毎に作成（使い回さない）
- `wg genkey`, `wg pubkey`で鍵生成
- わからんときは この記事[^KEY2]みて

```sh:sh$
wgkey=$(wg genkey); wgpub=$(echo ${wgkey} | wg pubkey); echo -e "key: ${wgkey}\npub: ${wgpub}"
```

<details><summary>view sample</summary>

```sh:sh$
$ wgkey=$(wg genkey); wgpub=$(echo ${wgkey} | wg pubkey); echo -e "key: ${wgkey}\npub: ${wgpub}"
key: 7Jt3HeFk73nEQPMYi5YNrrUuTJRq8CY47qbyrcTwa3w=
pub: dhtlZ4aL+CsKqCNmhT//yW1nvBw+4/1FOKEPIsPc7XU=
```
</details>

### 作成した鍵を設定ファイルに組み込む

- サーバ公開鍵は設定ファイルにコメントとして残しておく（後ほど `wg-quick wg1 up` したあとに `wg show` することでも見れるけど）
- 設定ファイル中の `%i` 変数には vpnのinterface名(この例だと`wg1`が入る)
- ospf trafficを流す為に `ip link set %i multicast on` 追加(ospfは`224.0.0.5`と`224.0.0.6`を使用)
- vpn interfaces name(`wg1`)は各ノードで揃えなくていいローカルの値（node1はwg0, node2はwg1とかでもOk）
- node2側の設定にPostUp, PostDownが入ってるけど不要（後々VRRP組んでやろうと思ってた名残）
- AllowedIPsについてはrouting追加するくらいかと思っていたが、この記事[^KEY3]で書いてあることが正しそう
:::note alert
<b>AllowedIPs = 0.0.0.0/0</b>
サーバ側(node1)で `AllowedIPs = 0.0.0.0/0` とかすると死ぬ（設定しているSSHとかも落ちるかも）
`AllowedIPs = 0.0.0.0/0` するのはあくまでもクライアント側(node2)だけ

:::

:::note warn
<b>AllowedIPs = 172.18.0.31/32, 224.0.0.0/4</b>
サーバ側(node1)で `224.0.0.0/4` を AllowedIPs に入れてあげないと、ospfのHelloPacketとか通らないので、必ずいれる
（入れないと下記ログが永遠と出力される）

<details><summary>view sample log</summary>

```
2024/12/31 02:13:59.503 OSPF: [S5P8P-AJE73][EC 100663299] *** sendmsg in ospf_write failed to 224.0.0.5, id 26638, off 0, len 68, interface wg1, mtu 1420: Required key not available
```

</details>

:::

:::note warn
<b>AllowedIPs Multiple </b> 
複数のPeerに対し同じセグメント設定はできないのかもしれない。
（一番最後に設定したPeerの224.0.0.0/4だけ反映される）
経路情報は`ip -4 route delete 224.0.0.0/4 dev wg1` とかすれば消えてくれるけど、`wg show`では設定ファイルの最後のPeerしか`allowed ips`に載っていなかった。

<details><summary>details</summary>

```conf:sh$ sudo cat /etc/wireguard/wg1.conf
[Interface]
PrivateKey = xxxxxxxxxxxxxxxxxxxx
# PublicKey = xxxxxxxxxxxxxxxxxxxx
Address = 172.xx.xx.xx/25
# PreUp = 
PostUp = ip link set %i multicast on; ip link set %i arp on; ip -4 route delete 224.0.0.0/4 dev %i
PreDown = ip link set %i multicast off; ip link set %i arp off
# PostDown = 
DNS = 1.1.1.1, 1.0.0.1
MTU = 1500

[Peer]
# node1
PublicKey = xxxxxxxxxxxxxxxxxxxx
PersistentKeepalive = 10
AllowedIPs = 172.xx.xx.xx/32, 224.0.0.0/4
Endpoint = node1.example.net:51820

[Peer]
# node2
PublicKey = xxxxxxxxxxxxxxxxxxxx
PersistentKeepalive = 10
AllowedIPs = 172.xx.xx.xx/32, 224.0.0.0/4
Endpoint = node2.example.net:51820

```

```sh:sh$ sudo wg show
interface: wg1
  public key: xxxxxxxxxxxxxxxxxxxx
  private key: (hidden)
  listening port: 65535

peer: xxxxxxxxxxxxxxxxxxxx
  endpoint: 192.0.2.1:51820
  allowed ips: 172.xx.xx.xx/32, 224.0.0.0/4
  latest handshake: 31 seconds ago
  transfer: 7.25 KiB received, 11.25 KiB sent
  persistent keepalive: every 10 seconds

peer: xxxxxxxxxxxxxxxxxxxx
  endpoint: 203.0.113.1:51820
  allowed ips: 172.xx.xx.xx/32
  transfer: 0 B received, 56.66 KiB sent
  persistent keepalive: every 10 seconds
$
```

</details>

つまりルーターとしての使用はできないってこと！？
:::


<details><summary>view sample config</summary>

```conf:node1:/etc/wireguard/wg1.conf 
[Interface]
PrivateKey = xxxxx_SERVER-SECRET_xxxxxxxxxxxxxxx=
# PublicKey = xxxxx_SERVER-PUBKEY_xxxxxxxxxxxxxxx=
# #で始まる行はコメント行として扱われる
Address = 172.18.0.31/24
ListenPort = 51820
PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE; ip link set %i multicast on
PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE; ip link set %i multicast off

[Peer]
# node2
PublicKey = xxxxx_CLIENT-PUBKEY_xxxxxxxxxxxxxxx=
PersistentKeepalive = 10
AllowedIPs = 172.18.0.32/32, 224.0.0.0/4
```

```conf:node2:/etc/wireguard/wg1.conf
[Interface]
PrivateKey = xxxxx_CLIENT-SECRET_xxxxxxxxxxxxxxx=
# PublicKey = xxxxx_CLIENT-PUBKEY_xxxxxxxxxxxxxxx=
# #で始まる行はコメント行として扱われる
Address = 172.18.0.32/24
ListenPort = 51820
PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE
DNS = 1.1.1.1, 1.0.0.1

[Peer]
# node1
PublicKey = xxxxx_SERVER-PUBKEY_xxxxxxxxxxxxxxx=
AllowedIPs = 172.18.0.31/32
Endpoint = 172.17.0.1:51820
PersistentKeepalive = 10
```
</details>

### wg1起動(有効化)

- 起動している場合は downしてからupで再起動させる
- 初回起動とかなら up だけでいい
- wg1が落ちてるときに down を行うと`Cannot find device "wg1"`が出力されるが無視

```sh:sh$
sudo wg-quick down wg1
sudo wg-quick up wg1
```

<details><summary>view sample log</summary>

```sh:node1:sh$
$ sudo wg-quick up wg1
[#] ip link add wg1 type wireguard
[#] wg setconf wg1 /dev/fd/63
[#] ip -4 address add 172.18.0.31/24 dev wg1
[#] ip link set mtu 1420 up dev wg1
[#] ip -4 route add 224.0.0.0/4 dev wg1
[#] iptables -A FORWARD -i wg1 -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE; ip link set wg1 multicast on
```

```sh:node2:sh$
$ sudo wg-quick up wg1
[#] ip link add wg1 type wireguard
[#] wg setconf wg1 /dev/fd/63
[#] ip -4 address add 172.18.0.32/24 dev wg1
[#] ip link set mtu 1420 up dev wg1
[#] resolvconf -a wg1 -m 0 -x
[#] ip -4 route add 224.0.0.0/4 dev wg1
[#] iptables -A FORWARD -i wg1 -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
```

</details>

### wg確認

- 接続できているものは `transfer` の received/sent値が増加する
- 逆に失敗しているものは サンプルの CLIENT2 のようになる

<details><summary>view sample</summary>

```sh:node1:sh$
$ sudo wg show
interface: wg1
  public key: xxxxx_SERVER-PUBKEY_xxxxxxxxxxxxxxx=
  private key: (hidden)
  listening port: 51821

peer: xxxxx_CLIENT1-PUBKEY_xxxxxxxxxxxxxxx=
  endpoint: 192.0.2.0:51820
  allowed ips: 172.18.0.32/32
  latest handshake: 13 seconds ago
  transfer: 37.61 KiB received, 10.62 KiB sent
  persistent keepalive: every 10 seconds

peer: xxxxx_CLIENT2-PUBKEY_xxxxxxxxxxxxxxx=
  allowed ips: 172.18.0.33/32
  persistent keepalive: every 10 seconds
```

</details>

## ospf(frr) on wg1

- 設定方法は基本的にeth1と同じ

<details><summary>view frr config</summary>

```cisco_ios:node1:vtysh(config)#
router ospf
 passive-interface default
 network 172.18.0.0/24 area 0.0.0.0
exit
interface wg1
 ip ospf mtu-ignore
 multicast
 no ip ospf passive
end
```

```cisco_ios:node2:vtysh(config)#
router ospf
 passive-interface default
 network 172.18.0.0/24 area 0.0.0.0
exit
interface wg1
 ip ospf mtu-ignore
 multicast
 no ip ospf passive
end
```

</details>

- うまく行っていればospf張れる
- 張れない場合は [AllowedIPs = 224.0.0.0/4](#作成した鍵を設定ファイルに組み込む) を設定したか確認してみてください
- 張れるまで 10sec~くらいかかる
    - ospf hello timerがデフォルト10sなのが原因
    - 気にならないのであればそのまま
    - 障害検知を早めたいのであれば、bfd使用推奨

    <details><summary>details</summary>

    ```cisco_ios:vtysh(config)#
    int wg1
     ip ospf bfd
    end
    ```
    
    ```cisco_ios:vtysh#
    # sh bfd peer
    BFD Peers:
        peer 172.18.0.32 vrf default interface wg1
                ID: 1735588754
                Remote ID: 1735588759
                Active mode
                Status: up
                Uptime: 2 minute(s), 39 second(s)
                Diagnostics: ok
                Remote diagnostics: ok
                Peer Type: dynamic
                RTT min/avg/max: 0/0/0 usec
                Local timers:
                        Detect-multiplier: 3
                        Receive interval: 300ms
                        Transmission interval: 300ms
                        Echo receive interval: 50ms
                        Echo transmission interval: disabled
                Remote timers:
                        Detect-multiplier: 3
                        Receive interval: 300ms
                        Transmission interval: 300ms
                        Echo receive interval: 50ms

    ```
    
    </details>


```cisco_ios:node1:vtysh#
# show ip ospf neighbor

Neighbor ID     Pri State           Up Time         Dead Time Address         Interface                        RXmtL RqstL DBsmL
198.51.100.1   64 Full/Backup     1w2d09h           38.834s 172.17.0.2      eth1:172.17.0.1                      0     0     0
198.51.100.1    1 Full/-          2h28m57s          38.732s 172.18.0.32     wg1:172.18.0.31                     0     0     0
```

```cisco_ios:node2:vtysh#
# show ip ospf neighbor

Neighbor ID     Pri State           Up Time         Dead Time Address         Interface                        RXmtL RqstL DBsmL
203.0.113.1   128 Full/DR         1w2d09h           36.943s 172.17.0.1      eth1:172.17.0.2                      0     0     0
203.0.113.1     1 Full/-          2h30m49s          30.827s 172.18.0.31     wg1:172.18.0.32                     0     0     0
```

## 状態確認

- vtysh入って `show ip ospf neighbor`でospf隣接状態確認可能
- vtysh入って `show ip ospf database`でospfDB確認可能
- vtysh入って `show ip route`で経路情報確認可能
    - 行頭に`O`ついているのがOSPFで受け取った経路
    - type3(`O IA`)とかtype5(`O E2`)とかはおそらくciscoと同じ
- BFDはvtysh入って `show bfd peer`
- linux shellで `ip r`で経路情報確認可能
    - `ip route show`

## 今後について

- BGPを自宅サーバとVPS間で張りたい
    - local-as ならランニングコストかからないし
    - global-as は逸般の人だけで...
    - 個人で取る必要今のところないかな








[^KEY1]: テストネットワーク用アドレス IPv4アドレスにおけるテストネットワーク用アドレスは、192.0.2.0/24[^specialipv4_1], 198.51.100.0/24[^specialipv4_2], 203.0.113.0/24[^specialipv4_3] の3ブロックです。
[^KEY2]: https://gihyo.jp/admin/serial/01/ubuntu-recipe/0614
[^KEY3]: https://zenn.dev/motisan/articles/20221230_wireguard02
[^specialipv4_1]: https://ja.ipshu.com/ipv4/192.0.2.0
[^specialipv4_2]: https://ja.ipshu.com/ipv4/198.51.100.0
[^specialipv4_3]: https://ja.ipshu.com/ipv4/203.0.113.0