Buffalo wmr-300のVLAN

ついこの間、ルーターに使っていたTVBOXのemmcが物理的に壊れて再構築することになりました。fsckで修復を試みたのですが、lxcのファイルがかなり壊れて修復不可能だったのでファイルシステムを再構築してクリーンインストールを試みました。ところがしばらくするとファイルシステムがread-onlyになってしましい、syslogにもファイルシステムのエラーが記録されてました。とりあえずはインターネットにつなぐルーターなので、余っているfon2405eで急場を凌ぎました。

同スペックの余っているTVBOXがあるので、それを使うことにしたのですが、元のルーターには複雑な設定になっており、そう簡単には復旧できません。LANポートが一つなのでVLANの設定、firewall、IPフォン用のsiproxd、WiFi用のfreeradiusとsnmpログのcactiと他にTinc、StrongSwan、WireguardのVPNとDDNSの設定と盛りだくさんです。急場凌ぎならfonでもいいのですが、メモリが32MBのため、freeradiusはちょっと無理そうです。そこでwmr-300なのですが64MBのメモリがあるので、バックアップ用のルータとして適任と思われるのですが、一つ問題がありました。OpenWrtの初期値でVLANが使えません。もともとLANポートが1つしかないので必要ないと言えばそれまでですが、MediatekのポピュラーのCPUなのでVLANが使えます。

そこで試行錯誤でVLANを使えるようにしました。fonの時もそうだったのですが、物理的のLANポートを探すことから始めます。物理ポートと違うポートにするとまず繋がりません。VLANを設定するには次の3つのファイルを編集します。

/etc/board.d/02_network: wmr-300-16Mを追加しました。wmr-300-16Mはwmr-300のSPIフラッシュを16MBに換装したものです。

ramips_setup_interfaces()
{
        local board="$1"

        case $board in
        ...
        
         wmr-300-16M)
                ucidef_add_switch "switch0" \
                        "4:lan" "6@eth0"
                ;;
        *)
                RT3X5X=`cat /proc/cpuinfo | egrep "(RT3.5|RT5350)"`
        ...

/etc/board.json: VLANのトポロジーを定義しているようです。追加します。

        ....
        "switch": {
                "switch0": {
                        "enable": true,
                        "reset": true,
                        "ports": [
                                {
                                        "num": 4,
                                        "role": "lan",
                                },
                                {
                                        "num": 6,
                                        "device": "eth0",
                                        "need_tag": false,
                                        "want_untag": false
                                }
                        ],
                        "roles": [
                                {
                                        "role": "lan",
                                        "ports": "4 6t",
                                        "device": "eth0.1"
                                },
                        ]
                }
        },
        ....

/etc/config/network: VLANの設定です

config switch
        option name 'switch0'
        option reset '1'
        option enable_vlan '1'

config switch_vlan
        option device 'switch0'
        option vlan '1'
        option vid '1'
        option ports '4 6t'

これでVLANが使えるようになりました。

WireGuard with bridge interface?

色々調べてみてもWireGuardはLayer 3なのでTapデバイスは使えない。それゆえブリッジは無理っていう結論なのですが、調べてみるとなんとなくできそうなサイトが見つかりました。

GRE tunneling adds an additional GRE header between the inside and outside IP headers. In theory, GRE could encapsulate any Layer 3 protocol with a valid Ethernet type, unlike IPIP, which can only encapsulate IP.

An introduction to Linux virtual interfaces: Tunnels

2つのネットワークを同一ネットワークとして使うにはTunデバイスではなくTapデバイスを使います。WireGuardではTapデバイスが使えないのですが、サイトによると鍵はGRETAPを使うことです。そこが少し混乱するのですがIPv6で動くようです。これを使うにはカーネルモジュールのbr_netfilterをブート時にロードしておく必要があります。私のルーターで調べてみると、

br_netfilter           28672  0
bridge                233472  1 br_netfilter
ipv6                  622592  77 bridge,br_netfilter,wireguard

このようになっておりIPv6にbr_netfilterがリンクしています。そのあとはWireGuardのwg0.confでタップデバイスを立ち上げてブリッジインターフェースにリンクするという方法をとります。

PostUp = ip link add name gretap1 type gretap local 192.168.92.1 remote 192.168.178.1 
PostUp = ip link set gretap1 up
PostUp = ip link set gretap1 master br0

Tinc VPNではTapデバイスが使えるので簡単に同じネットワーク同士を繋ぐことができるのですが、WireGuardでも同様のことができるかもしれません。

OpenWrt

この情報をもとに早速OpenWrtで試してみました。機種はなんでも良いのですが先日、大量生産したOpenWrt化したfon2405eがあるのでそれを使いました。なかなか思うようにいかずOpenWrtのフォーラム等で検索して何度かトライしたらできました。

まずは802.11sの暗号なしのメッシュネットワークを作ります。次にWireGuardのネットワークを作ります。この時問題なのがWireGuardの設定をするとパケットが全てDefualt Gatewayに流れてしまい接続ができなくなるので、手動でルーティングから削除します。OpenWrtのリポジトリからGretapのパッケージをインストールして/etc/config/networkの設定をします。

packages

gre - 1-11
kmod-gre - 4.14.195-1
kmod-gre6 - 4.14.195-1
kmod-br-netfilter - 4.14.195-1

WireGuard (interface)

Firewall

General SettingsのInputを有効にしないとなぜか繋がりません。

/etc/config/network

'''

config interface 'lan'
	option type 'bridge'
	option proto 'static'
	option ipaddr '192.168.1.17'
	option netmask '255.255.255.192'
	option ip6assign '60'
	option gateway '192.168.1.1'
	list dns '8.8.8.8'
	list dns '1.1.1.1'
	option macaddr 'xx:xx:xx:xx:xx:xx'
	option ifname 'eth0.1 gre4t-gt'


...

config interface 'mesh'
	option proto 'static'
	option netmask '255.255.255.0'
	option ipaddr '10.101.0.17'

config interface 'wg'
	option proto 'wireguard'
	option private_key 'xxxxxxxxxxxxxxxx'
	option listen_port '8889'
	list addresses '192.168.2.17/26'

config wireguard_wg
	option public_key 'xxxxxxxxxxxxxxxx'
	option persistent_keepalive '25'
	option endpoint_port '8888'
	option endpoint_host '10.101.0.14'
	list allowed_ips '192.168.2.0/26'
	list allowed_ips '10.101.0.0/24'
	list allowed_ips '192.168.1.0/26'

config interface 'gt'
    option type 'bridge'
	option proto 'gretap'
	option ipaddr '192.168.2.17'
	option peeraddr '192.168.2.14'
	#option force_link '1'
	#option mtu '1500'
    option delegate '0'

ルーティングの修正

ip r del 10.101.0.14 via 192.168.1.1
ip r del 192.168.2.14 via 192.168.1.1

追記

firewallの追加です。

/etc/firewall.user

iptables -A FORWARD -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu;

routingの問題はOpenWrt仕様の特有の問題なので、それを回避するためにInterfacesの設定ではDefault GWの設定はしません。その代わりにあまり良い方法とは言えませんがrc.localで設定します。

/etc/rc.local

sleep 20
ip route add default via 192.168.1.1 dev br-lan

exit 0

追記1.1

OpenWrtのソースを眺めていたら、隠し設定があるらしいことに気がつきました。検索して調べてみると公式HPでも記述がありました。Wireguardをデフォルトルート以外で使うときはこの設定(option nohostroute '1')を使えば良さそうです。

  • https://openwrt.org/docs/guide-user/network/tunneling_interface_protocols

/etc/config/network (例)

onfig interface 'wg'
	option proto 'wireguard'
	option private_key 'xxxxxxxxxxxxxxxx'
	option listen_port '8001'
	option nohostroute '1'
	list addresses '192.168.2.6/26'

config wireguard_wg
	option endpoint_port '8000'
	option public_key 'xxxxxxxxxxxxxxxx'
	option endpoint_host '10.200.0.100'
	option persistent_keepalive '25'
	option nohostroute '1'
	list allowed_ips '192.168.1.0/26'
	list allowed_ips '192.168.2.0/26'

config interface 'gt'
	option type 'bridge'
	option proto 'gretap'
	option ipaddr '192.168.2.6'
	option peeraddr '192.168.2.5'
	option nohostroute '1'
	option delegate '0'

追記2

Firewallルールを少し変えてみました。

General settingsのInputをrejectにした場合、greプロトコルを通すためにiptablesのルールを追加します。

/etc/firewall.user

iptables -I INPUT -p gre -j ACCEPT
iptables -A FORWARD -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu;

さらにOpenWrtのパッケージをインストールします。

opkg install kmod-ipt-nat-extra

参考

  • https://notes.superlogical.ch/pages/note_wg/nolayer2/
  • https://openwrt.org/docs/guide-user/network/tunneling_interface_protocols
  • https://forum.openwrt.org/t/setup-fastest-pseudowire-protocol/36219/11
  • https://forum.openwrt.org/t/solved-gretap-tunnel-with-vlan-802-1q-tagging/20742/2
  • https://backreference.org/2013/07/23/gre-bridging-ipsec-and-nfqueue/
  • https://developers.redhat.com/blog/2019/05/17/an-introduction-to-linux-virtual-interfaces-tunnels/
  • https://medium.com/@david.waiting/a-beginners-guide-to-generic-routing-encapsulation-fb2b4fb63abb
  • https://forum.archive.openwrt.org/viewtopic.php?id=59150