それマグで!

知識はカップより、マグでゆっくり頂きます。 takuya_1stのブログ

習慣に早くから配慮した者は、 おそらく人生の実りも大きい。

linuxのipコマンドでgretap を作って通信してみる

gretap を作る

GRE Tap でイーサネット・フレームを転送するVPNを作ってみたい。

wg0 でL2-VPNはできると思う。

wg に L2-VPN機能がないので、 wg 上に ip bridge で gre tap を構成すればいい。

wireguardではL2はサポートされていなので、WG上にGRETAPでL2転送をかけてみたらいいと思う。ただし、iPhoneiOSではgreを使えないので、どんな手段を用いてもリモートからGoogle Homeを呼び出しはできないと思う。iphoneL2TPをするならwigreguardは使えない

もっとかんたんに、L2トンネルを使うのなら、softetherOpenVPNを使うしかない。

GRE tap を体験するために、Linux仮想マシンを作る。

仮想マシンをつくると流石に重いので、LXCを使ってコンテナを使うことにする。

netnsがあるので、netns でやれば良いわけですが。netnsあまり使ってないので、lxc でやります。

docker でやってもいいですが、dockerはデフォルトでネットワークがついてきたり、モジュールがなかったりして面倒なので、フルで仮想マシンとして動作するLXCでやることにしました。

ホスト・マシン

今回、すべての構成をUbuntu/DebianのLXCでやっています。

ホストマシンには、Ubuntu 20.04 を使いました。LXCをインストールして使えるようにしておきます。

sudo snap install lxd
sudo lxd init 

インストールしたら、ストレージを設定して コンテナが作成できるように設定します。それで準備完了です。

実験する4台の接続

ざっとみて4台いるわけですよ。

m01 と m02 の間をGRETAPで接続します。

c01 から c02 へ GRETAPのトンネル経由で抜けるように作っていきます。

f:id:takuya_1st:20211229152827p:plain

トンネルをどの経路の上に作るかがポイントです。

GRETAPをwg0の上に作ればwireguardをつかったL2とんね、IPSecを使えばIPsec上にL2トンネル。どこの経路で作るかで呼び方は代わると思う。

今回は、単純に ブリッジでm01/m02 を接続して、ブリッジを経由したGREトンネルを作りたいと思う。

詳細な接続

具体的に作るには、複雑な構成になる。

今回作ったネットワーク構成を詳細に書き込むとこんな感じ。 f:id:takuya_1st:20211229152841p:plain

veth0/brige がややこしい。vethでは、veth ペアを作る。verthは両端がペアで作られる。今回は。片方をLXCへ、もう一方をブリッジに入れる。

疎通テスト用にIPも多めに割振ってるのでちょっとややこしい。

ブリッジとvethの接続について

br0 の接続

次のように作った、このbr0 の接続について。

f:id:takuya_1st:20211229152905p:plain:w320

vethを使ってbr0へ

br0 をホスト側に作成、vethペアを2本作成、そしてbr0に突っ込む

veth のペアの一方はLXCへ

f:id:takuya_1st:20211229152918p:plain:w320

verhを作ったら、もう一方をホスト側の制御から外し、LXC制御を渡す。LXC側にアサインしたら、ホスト側からは見えなくなる。

ブリッジは、vethペア作成、LXCのコンテナへ突っ込む、ブリッジへ接続する。この繰り返しで作っていく。

コンテナ間のブリッジbr0/br1/br2

コンテナ間のブリッジは、ホスト側に作るので、ホスト側から見える。

次の図の、br1 はホスト側に存在する。

f:id:takuya_1st:20211229152931p:plain:w320

lxc コンテナ作成・起動

コンテナのネットワークは自分で作っていくので、ネットワークを持たないコンテナを作る。「ネットワークなしコンテナ」を作成すると、LXCから注意が出るが、意図した動作なので、注意は無視しておく。

lxc launch ubuntu:20.04 m01;
lxc launch ubuntu:20.04 m02;
lxc launch ubuntu:20.04 c01;
lxc launch ubuntu:20.04 c02;
# lxc restart m01
# lxc restart m02
# lxc restart c01
# lxc restart c02

br0 を作成

sudo ip link add name veth1 type veth peer name veth1-br
sudo ip link add name veth2 type veth peer name veth2-br
sudo ip link add br0 type bridge
sudo ip link set veth1-br master br0
sudo ip link set veth2-br master br0
lxc config device add m01 eth0 nic nictype=physical parent=veth1
lxc config device add m02 eth0 nic nictype=physical parent=veth2

br1 を作成

sudo ip link add name veth10 type veth peer name veth10-br
sudo ip link add name veth11 type veth peer name veth11-br
lxc config device add m01 eth1 nic nictype=physical parent=veth10
lxc config device add c01 eth0 nic nictype=physical parent=veth11
sudo ip link add br1 type bridge
sudo ip link set veth10-br master  br1
sudo ip link set veth11-br master  br1

br2 を作成

sudo ip link add name veth20 type veth peer name veth20-br
sudo ip link add name veth21 type veth peer name veth21-br
lxc config device add m02 eth1 nic nictype=physical parent=veth20
lxc config device add c02 eth0 nic nictype=physical parent=veth21
sudo ip link add br2 type bridge
sudo ip link set veth20-br master br2
sudo ip link set veth21-br master br2

アドレスをわり付け

sudo ip addr add 10.1.0.254/24 dev br0
lxc exec m01 -- ip addr add 10.1.0.1/24 dev eth0
lxc exec m02 -- ip addr add 10.1.0.2/24 dev eth0
sudo ip addr add 172.16.101.254/24 dev br1
lxc exec c01 -- ip addr add 172.16.101.2/24 dev eth0
sudo ip addr add 172.16.102.254/24 dev br2
lxc exec c02 -- ip addr add 172.16.102.2/24 dev eth0

リンクアップ(忘れがち。忘れると動かないので注意)

sudo ip link set br0 up
sudo ip link set veth1-br up
sudo ip link set veth2-br up
sudo ip link set br1 up
sudo ip link set veth10-br up
sudo ip link set veth11-br up
sudo ip link set br2 up
sudo ip link set veth20-br up
sudo ip link set veth21-br up
lxc exec m01 ip link set eth0 up
lxc exec m01 ip link set eth1 up
lxc exec m02 ip link set eth0 up
lxc exec m02 ip link set eth1 up
lxc exec c01 ip link set eth0 up
lxc exec c02 ip link set eth0 up

up を忘れると、通信できない。通信できず、経路が悪いのか設定が悪いのか分からずに、嵌まり込むので注意する。事前にしっかりとlink up しておく。 とくにvethでは両端をUPしていくので注意。

vethのup はめんどくさいけど、漏れなくダブりなく設定を頑張る。

ブリッジに入れたnic間の通信許可

sudo sysctl net.bridge.bridge-nf-call-iptables=0

ブリッジ・インタフェースは、iptablesで制御されてしまうので、それを外しバカ・ハブ(ダムハブ)として動作させる.この処理はなくても動くと思う。

コンテナ内部 ブリッジ br-gre01 作成

lxc exec m01 ip link add br-gre01 type bridge
lxc exec m01 ip link set eth1 master br-gre01
lxc exec m01 ip link set br-gre01 up
lxc exec m01 ip addr add 172.16.101.1/24 dev br-gre01

gretap を作ったらブリッジに入れて共有するので作っておく。

コンテナ内部 ブリッジ br-gre02 作成

lxc exec m02 ip link add br-gre02 type bridge
lxc exec m02 ip link set br-gre02 up
lxc exec m02 ip link set eth1 master br-gre02
lxc exec m02 ip addr add 172.16.102.1/24 dev br-gre02

gretap を作ったらブリッジに入れて共有するので作っておく。

動作チェック

ping -c 1 10.1.0.254
ping -c 1 172.16.101.254
ping -c 1 172.16.102.254
lxc exec m01 -- ping -c 1 10.1.0.254
lxc exec m01 -- ping -c 1 172.16.101.254
lxc exec m01 -- ping -c 1 172.16.101.2
lxc exec m02 -- ping -c 1 10.1.0.254
lxc exec m02 -- ping -c 1 172.16.102.254
lxc exec m02 -- ping -c 1 172.16.102.2

ここまでで、通信経路と仮想デバイス接続が間違ってないか確認する。

ネットワークとコンテナが間違ってる通信ができない。そのときは、一つずつミスを探してやり直し。

連続したlxc exec -- command を、複数行をまとめてコピペすると動かないので注意する。

greptap を作って通信する。

gre を作成 して ブリッジに入れる

lxc exec m01 -- ip link add name gre01 type gretap remote 10.1.0.2
lxc exec m02 -- ip link add name gre02 type gretap remote 10.1.0.1
lxc exec m01 -- ip link set gre01 master br-gre01
lxc exec m02 -- ip link set gre02 master br-gre02
lxc exec m01 -- ip link set gre01 up
lxc exec m02 -- ip link set gre02 up
lxc exec m01 -- ip link set gre01 mtu 1450
lxc exec m02 -- ip link set gre02 mtu 1450

gre0は予約されているので、別名にした。

ここも、lxc exec -- command に注意する。複数行をまとめてコピペすると、改行が -- で吸収されてしまう。なので、まとめてコピペせずに1行ずつやる

gre 経由の通信を確認

sudo ip addr add 172.16.101.253/24 dev br2
lxc exec m02 -- ip addr add 172.16.101.3/24 dev br-gre02
lxc exec c02 -- ip addr add 172.16.101.4/24 dev eth0

疎通を確認

lxc exec m01 -- ping -c 1 172.16.101.253
lxc exec m01 -- ping -c 1 172.16.101.3
lxc exec m01 -- ping -c 1 172.16.101.4
lxc exec c01 -- ping -c 1 172.16.101.253
lxc exec c01 -- ping -c 1 172.16.101.3
lxc exec c01 -- ping -c 1 172.16.101.4

c01 と c02 が通信できたらイーサネットフレームが転送されている。pingの応答が来たら成功。

DHCP がgretap 経由で転送されているか確認

pingの他にも dhcp などを試してパケットを確認しておく

ホスト側からブリッジの通信を見つつ

sudo tcpdump -i br2

別のターミナルを立ち上げてDHCPパケットを流して見る。

lxc exec c01 -- dhclient -4 -v eth0
lxc exec c01 -- dhclient -6 -v eth0

tcpdump でパケットが確認できたら無事にGRETAPできていると言える。

ubuntuを使った理由はここで、tcpdump は最初からインストール済みでコンテナが作成される。

ARPの確認

arp キャッシュを見てみる。ip neigh で隣接しているMACアドレスが分かる。ここに出てきていてればOKである。

takuya@raspi-ubuntu:~$ lxc exec c01 -- ip neigh
172.16.101.254 dev eth0 lladdr 3e:0a:df:7d:f4:52 STALE
172.16.101.1 dev eth0 lladdr 16:9a:f2:ba:c1:f0 STALE
172.16.101.253 dev eth0 lladdr 3e:0a:df:7d:f4:52 STALE
172.16.101.4 dev eth0 lladdr f6:ca:27:f5:91:cc STALE
172.16.101.3 dev eth0 lladdr c6:2c:d0:0e:4e:1b STALE

ARPが抜けてるか確認

tcpdump -i br1 arp
lxc exec m02 tcpdump -i br-gre02 arp

ARPが抜けてない場合は、arptablesをオフにする必要があるかもしれない。

mDNSが使えるかチェック

mDNSは、ubuntuなら最初から稼働しているはずなのでチェックしておく

lxc exec c01 -- ping c02.local

ubuntu 以外だと、avahi-daemon を入れる必要があり、仮想マシンを外部ネットワークへ接続する必要があるので、ubuntu 以外をコンテナに使うとめんどくさいんだよね。

wireguardの場合

veth1-br0-verth1 の部分が、wg0 の wireguardネットワークになるだけで動くはずである。まだ試してない。

今回使ったもの

です。

openwrt でやる場合

WRTで実験するなら、opkg install kmod-gregreを足してやる必要がある。kmod-gre を足すと、デフォルトで gretap0 が生えてくる

参考資料