Posted on Sun Dec 02 15:07:40 +0900 2012 by nabeken
安価な3G回線経由のGRE over IPSec (+NATトラバーサル)でOpenBSD 5.1同士を接続してみました。 3G回線はrdomain 1に隔離し、greのみをrdomain 0へ追加する構成にしました。
3G回線(バックアップ回線)は月額980円の イオンSIM をb-mobile WiFi刺し、用意しました。 OpenBSD 5.1では870円で購入した GW-USNano2 を装着し、無線LANへ接続しました。
前回の記事 では無線LAN I/Fをデフォルトのrdomain 0に所属させたまま、VPNエンドポイントへのスタティックルーティング を登録する手法を紹介しました。しかし、この手法では問題がありました。 gwはNAPTで各サービスへトラフィックを転送しています。VPNエンドポイントもそのサービスを利用しています。 この手法ではVPNエンドポイントからの通信で戻りが非対称(IPアドレスも変わってしまう)になってしまうため、 実運用には使えませんでした。
この問題を回避するため、rdomain(Routing Domain)によるルーティングテーブルの分離を行ないました。 OpenBSDの場合は特定のプロセスをrdomainにattachするだけでなく、ネットワークインターフェースもrdomainにattachすることもできます。 (FreeBSDだとVIMAGEのほうが近い。Linuxではnamespaceによってネットワークスタックを分離できるようです。)
バックアップ回線用のネットワークインターフェースを別rdomainに収容することで既存ルーティング に影響を与えずにネットワークを拡張できます。さらに素晴しいことに、OpenBSDのgif(4)やgre(4)は outer(encapしたトラフィックのI/F)のrdomainとinner(encapする前のトラフィックのI/F)のrdomainを別々に指定できます。 つまり、トンネルのための回線は既存ルーティングに影響を与えないようにしつつ、トンネルで運ぶ対象のトラフィック は既存ルーティングに載せることができます。
最終的な構成は以下を目指します。この上にBirdでOSPFを流します。3G回線を通るgreはコストを上げておき、 平常時はPPPoE経由のOpenVPNにトラフィックが流れるようにします。:
+----------+ GRE(outer) over IPSec w/ nat-t | ipsec-gw |----------(via 3G)----------+ +--+----+--+ | | | | urtwn0 rdomain 1 | | OpenVPN +------+-----+ ------------------------- | +------(via PPPoE)-------+ openbsd-gw | rdomain 0 | tun0 +------------+ | | gre0 +------------------------------------+ GRE(inner)
ipsec-gwは固定IPv4アドレスが振られています。 openbsd-gwは非固定IPv4アドレスによるNAT配下にいる想定です。
OpenBSDのrdomainは Virtualizing the OpenBSD Routing Table が詳しいです。
OpenBSD 5.1ではrdomainはIPv4のみです(参考: rtable vs rdomain)。 参考によれば、作業中とのことなので、遠くないリリースでは対応すると思われます。 今回の構成ではtunneldomainだけがrdomain対象なので、GREで通すIPv6パケットは問題なく通過します。
無線LANのNICはurtwn(4)を使用しました。
# dmesg | grep urtwn urtwn0 at uhub0 port 1 "Planex Communications Inc. GW-USNano2" rev 2.00/2.00 addr 2 urtwn0: MAC/BB RTL8188CUS, RF 6052 1T1R, address 00:XX:XX:XX:XX:XX # cat /etc/hostname.urtwn0 nwid hogehoge wpakey secret rdomain 1 dhcp
こうすることで、DHCPによって取得したデフォルトゲートウェイはrdomain 1へ入ります。 このままでは /etc/resolv.conf は上書きされてしまいます。5.1のdhclientには ignoreオプションが入っていないため、 /etc/dhclient.conf で予めDNSサーバを指定しておきます。
# cat /etc/dhclient.conf supersede domain-name-servers 8.8.8.8; request subnet-mask, broadcast-address, time-offset, routers, domain-name;
GREとIPSecを以下のように構成します。
+----------+ (gre0: 192.168.0.1/32) +------------+ | ipsec-gw +-----------------------------------------------+ openbsd-gw | +----------+ (gre0: 192.168.0.2/32) +------------+ (lo1: 10.0.0.1/32) (lo1: 10.0.0.2/32) | | +-----------------------[ IPSec ]--------------------------+
それぞれのlo1にGREの終端のためにIPアドレスを振ります。ここではまだ起動させません。
ipsec-gw# cat /etc/hostname.lo1 inet 10.0.0.2/32 ipsec-gw# cat /etc/hostname.gre0 tunnel 10.0.0.2 10.0.0.1 192.168.0.2 192.168.0.1 netmask 255.255.255.255 ipsec-gw# cat /etc/hostname.enc0 up openbsd-gw# cat /etc/hostname.lo1 rdomain 1 inet 10.0.0.1/32 openbsd-gw# cat /etc/hostname.gre0 tunneldomain 1 tunnel 10.0.0.1 10.0.0.2 192.168.0.1 192.168.0.2 netmask 255.255.255.255
enc(4) をrdomain 1に作成します。
openbsd-gw# cat /etc/hostname.enc1 rdomain 1 up
ipsec-gw, openbsd-gw共通として:
gre0はskip
set skip on { lo0, gre0 }
ipsec-gwでは:
enc0はskip
set skip on { enc0 }
不特定多数からのesp/udpを許可
NAT-T(NATトラバーサル)ではudpにカプセル化されるので併せて許可します。
pass in on $ext_if proto udp from any to ($ext_if) port { isakmp, ipsec-nat-t } pass in on $ext_if proto esp from any to ($ext_if)
openbsd-gwでは:
enc1はskip
set skip on { enc1 }
ipsec-gwから/へのesp/udpを許可
ipsec_gw = "X.X.X.X" pass out on $ext_if proto udp from ($ext_if) to $ipsec_gw port { isakmp, ipsec-nat-t } pass out on $ext_if proto esp from ($ext_if) to $ipsec_gw
設定したら pfctl -ef /etc/pf.conf しておきます。
GREを通しておきます。
ipsec-gw# sh /etc/netstart enc0 ipsec-gw# sh /etc/netstart lo1 ipsec-gw# sh /etc/netstart gre0 ipsec-gw# ifconfig lo1 lo1: flags=8049<UP,LOOPBACK,RUNNING,MULTICAST> mtu 33152 priority: 0 groups: lo inet6 fe80::1%lo1 prefixlen 64 scopeid 0xe inet 10.0.0.2 netmask 0xffffffff ipsec-gw# ifconfig gre0 gre0: flags=9011<UP,POINTOPOINT,LINK0,MULTICAST> mtu 1476 priority: 0 groups: gre physical address inet 10.0.0.2 --> 10.0.0.1 inet6 fe80::xxxx:xxxx:xxxx:xxxx%gre0 -> prefixlen 64 scopeid 0xf inet 192.168.0.2 --> 192.168.0.1 netmask 0xffffffff openbsd-gw# sh /etc/netstart enc1 openbsd-gw# sh /etc/netstart lo1 openbsd-gw# sh /etc/netstart gre0 openbsd-gw# ifconfig enc1 enc1: flags=20041<UP,RUNNING,NOINET6> rdomain 1 priority: 0 groups: enc status: active openbsd-gw# ifconfig lo1 lo1: flags=28049<UP,LOOPBACK,RUNNING,MULTICAST,NOINET6> rdomain 1 mtu 33152 priority: 0 groups: lo inet 10.0.0.1 netmask 0xffffffff openbsd-gw# ifconfig gre0 gre0: flags=9011<UP,POINTOPOINT,LINK0,MULTICAST> mtu 1476 priority: 0 groups: gre physical address inet 10.0.0.1 --> 10.0.0.2 rdomain 1 inet6 fe80::yyyy:yyyy:yyyy:yyyy%gre0 -> prefixlen 64 scopeid 0x25 inet 192.168.0.1 --> 192.168.0.2 netmask 0xffffffff
ipsec.conf(5) を用意します。
ipsec-gw# cat /etc/ipsec.conf ike passive esp proto gre from 10.0.0.2/32 to 10.0.0.1/32 peer any srcid ipsec-gw.example.com psk secret openbsd-gw# cat /etc/ipsec.conf ipsec_gw = "X.X.X.X" me = "10.0.0.1" remote = "10.0.0.2" ike dynamic esp proto gre from $me/32 to $remote/32 peer $ipsec_gw psk secret
デバッグのため、まずは手でisakmpd(8)を動かします。
ipsec-gw# isakmpd -K -d -v ipsec-gw# ipsecctl -f /etc/ipsec.conf openbsd-gw# route -T 1 exec isakmpd -K -d -v openbsd-gw# route -T 1 exec ipsecctl -f /etc/ipsec.conf
疎通を確認します。
ipsec-gw# ping -c 5 192.168.0.1 openbsd-gw# ping -c 5 192.168.0.2 // このpingはrdomain 0から通ることに注意
うまくいけばphase 2が完了し、FLOWが確立しているはずです。
ipsec-gw# ipsecctl -sa FLOWS: flow esp in from 10.0.0.1 to 10.0.0.2 peer Z.Z.Z.Z srcid ipsec-gw.example.com dstid openbsd-gw.localdomain type use flow esp out from 10.0.0.2 to 10.0.0.1 peer Z.Z.Z.Z srcid ipsec-gw.example.com dstid openbsd-gw.localdomain type require SAD: esp tunnel from Z.Z.Z.Z to X.X.X.X spi 0x03212efb auth hmac-sha2-256 enc aes esp tunnel from X.X.X.X to Z.Z.Z.Z spi 0xae7c067e auth hmac-sha2-256 enc aes openbsd-gw# route -T 1 exec ipsecctl -sa FLOWS: flow esp in from 10.0.0.2 to 10.0.0.1 peer X.X.X.X srcid openbsd-gw.localdomain dstid ipsec-gw.example.com type use flow esp out from 10.0.0.1 to 10.0.0.2 peer X.X.X.X srcid openbsd-gw.localdomain dstid ipsec-gw.example.com type require SAD: esp tunnel from Y.Y.Y.Y to X.X.X.X spi 0x03212efb auth hmac-sha2-256 enc aes esp tunnel from X.X.X.X to X.X.X.X spi 0xae7c067e auth hmac-sha2-256 enc aes
忘れずに起動スクリプトに仕込んでおきます。
ipsec-gw# echo ipsec=\"YES\" >> /etc/rc.conf.local ipsec-gw# echo isakmpd_flags=\"-K\" >> /etc/rc.conf.local openbsd-gw# echo 'route -T 1 exec isakmpd -K' >> /etc/rc.local openbsd-gw# echo 'route -T 1 exec ipsecctl -f /etc/ipsec.conf' >> /etc/rc.local
上で用意したgreをcost 50としてOSPFに突っ込みます(birdのデフォルトコスト値は10) 。 適当なエリアに以下のinterfaceを追加します。
# ipsec-gw interface "gre0" { hello 10; dead 40; priority 100; cost 50; }; # openbsd-gw interface "gre0" { hello 10; dead 40; priority 0; cost 50; };
再起動し、neighborが確立していることを確認します(tun0はPPPoE経由のOpenVPN)。
# ipsec-gw bird> show ospf neighbors TKNETWORKS: Router ID Pri State DTime Interface Router IP 10.0.5.10 1 full/bdr 00:38 tun0 fe80::yyyy:yyyy:yyyy:yyyy 10.0.5.10 0 full/ptp 00:38 gre0 fe80::xxxx:xxxx:xxxx:xxxx # openbsd-gw bird> show ospf neighbors TKNETWORKS: Router ID Pri State DTime Interface Router IP 10.7.15.10 100 full/dr 00:37 tun0 fe80::xxxx:xxxx:xxxx:xxxx 10.7.15.10 100 full/ptp 00:37 gre0 fe80::yyyy:yyyy:yyyy:yyyy
お待ちかねの経路切り替えを観察します。OpenVPNとbirdでリンクアップ検知の設定をまだ詰めていないため復旧時間がやや長いです。
icmp_seq=4まではPPPoE経由のOpenVPNを通っています。ここで、 openbsd-gw 側のOpenVPNを落します。 その結果が Host is down になっています。無事にicmp_seq=39からは3G回線経由に切り替わっています。 すぐにOpenVPNをstartさせ、icmp_seq=98で元の状態に収束しているのが確認できました。
openbsd-gw# ping6 2001:db8::1 PING6(56=40+8+8 bytes) 2001:380:6dc:7aa::2 --> 2001:db8::1 16 bytes from 2001:db8::1, icmp_seq=0 hlim=64 time=4.612 ms 16 bytes from 2001:db8::1, icmp_seq=1 hlim=64 time=4.758 ms 16 bytes from 2001:db8::1, icmp_seq=2 hlim=64 time=4.414 ms 16 bytes from 2001:db8::1, icmp_seq=3 hlim=64 time=4.224 ms 16 bytes from 2001:db8::1, icmp_seq=4 hlim=64 time=4.703 ms ping6: sendmsg: Host is down ping6: wrote 2001:db8::1 16 chars, ret=-1 ping6: sendmsg: Host is down ping6: wrote 2001:db8::1 16 chars, ret=-1 ping6: sendmsg: Host is down ping6: wrote 2001:db8::1 16 chars, ret=-1 ping6: sendmsg: Host is down ping6: wrote 2001:db8::1 16 chars, ret=-1 ping6: sendmsg: Host is down ping6: wrote 2001:db8::1 16 chars, ret=-1 ping6: sendmsg: Host is down ping6: wrote 2001:db8::1 16 chars, ret=-1 ping6: sendmsg: Host is down ping6: wrote 2001:db8::1 16 chars, ret=-1 ping6: sendmsg: Host is down ping6: wrote 2001:db8::1 16 chars, ret=-1 16 bytes from 2001:db8::1, icmp_seq=39 hlim=64 time=3988.44 ms 16 bytes from 2001:db8::1, icmp_seq=40 hlim=64 time=3968.82 ms 16 bytes from 2001:db8::1, icmp_seq=41 hlim=64 time=4470.2 ms 16 bytes from 2001:db8::1, icmp_seq=42 hlim=64 time=4390.02 ms 16 bytes from 2001:db8::1, icmp_seq=43 hlim=64 time=3469.87 ms 16 bytes from 2001:db8::1, icmp_seq=44 hlim=64 time=2740.37 ms 16 bytes from 2001:db8::1, icmp_seq=45 hlim=64 time=1750.51 ms 16 bytes from 2001:db8::1, icmp_seq=46 hlim=64 time=831.138 ms 16 bytes from 2001:db8::1, icmp_seq=47 hlim=64 time=411.364 ms 16 bytes from 2001:db8::1, icmp_seq=48 hlim=64 time=441.882 ms 16 bytes from 2001:db8::1, icmp_seq=49 hlim=64 time=642.324 ms 16 bytes from 2001:db8::1, icmp_seq=50 hlim=64 time=972.566 ms 16 bytes from 2001:db8::1, icmp_seq=51 hlim=64 time=1262.94 ms 16 bytes from 2001:db8::1, icmp_seq=52 hlim=64 time=1283.34 ms 16 bytes from 2001:db8::1, icmp_seq=53 hlim=64 time=1293.71 ms 16 bytes from 2001:db8::1, icmp_seq=54 hlim=64 time=1294.96 ms 16 bytes from 2001:db8::1, icmp_seq=55 hlim=64 time=1304.32 ms 16 bytes from 2001:db8::1, icmp_seq=56 hlim=64 time=1477.74 ms 16 bytes from 2001:db8::1, icmp_seq=57 hlim=64 time=1255.12 ms 16 bytes from 2001:db8::1, icmp_seq=58 hlim=64 time=705.29 ms 16 bytes from 2001:db8::1, icmp_seq=59 hlim=64 time=145.904 ms 16 bytes from 2001:db8::1, icmp_seq=60 hlim=64 time=156.342 ms 16 bytes from 2001:db8::1, icmp_seq=61 hlim=64 time=146.49 ms 16 bytes from 2001:db8::1, icmp_seq=62 hlim=64 time=236.893 ms 16 bytes from 2001:db8::1, icmp_seq=63 hlim=64 time=285.795 ms 16 bytes from 2001:db8::1, icmp_seq=64 hlim=64 time=147.682 ms 16 bytes from 2001:db8::1, icmp_seq=65 hlim=64 time=148.085 ms 16 bytes from 2001:db8::1, icmp_seq=66 hlim=64 time=138.578 ms 16 bytes from 2001:db8::1, icmp_seq=67 hlim=64 time=148.899 ms 16 bytes from 2001:db8::1, icmp_seq=68 hlim=64 time=289.307 ms 16 bytes from 2001:db8::1, icmp_seq=69 hlim=64 time=149.47 ms 16 bytes from 2001:db8::1, icmp_seq=70 hlim=64 time=149.384 ms 16 bytes from 2001:db8::1, icmp_seq=71 hlim=64 time=150.285 ms 16 bytes from 2001:db8::1, icmp_seq=72 hlim=64 time=150.676 ms 16 bytes from 2001:db8::1, icmp_seq=73 hlim=64 time=151.024 ms 16 bytes from 2001:db8::1, icmp_seq=74 hlim=64 time=148.4 ms 16 bytes from 2001:db8::1, icmp_seq=75 hlim=64 time=152.07 ms 16 bytes from 2001:db8::1, icmp_seq=76 hlim=64 time=152.222 ms 16 bytes from 2001:db8::1, icmp_seq=77 hlim=64 time=152.889 ms 16 bytes from 2001:db8::1, icmp_seq=78 hlim=64 time=153.04 ms 16 bytes from 2001:db8::1, icmp_seq=79 hlim=64 time=163.178 ms 16 bytes from 2001:db8::1, icmp_seq=80 hlim=64 time=273.66 ms 16 bytes from 2001:db8::1, icmp_seq=81 hlim=64 time=173.819 ms 16 bytes from 2001:db8::1, icmp_seq=82 hlim=64 time=144.435 ms 16 bytes from 2001:db8::1, icmp_seq=83 hlim=64 time=144.619 ms 16 bytes from 2001:db8::1, icmp_seq=84 hlim=64 time=145.237 ms 16 bytes from 2001:db8::1, icmp_seq=85 hlim=64 time=235.374 ms 16 bytes from 2001:db8::1, icmp_seq=86 hlim=64 time=145.794 ms 16 bytes from 2001:db8::1, icmp_seq=87 hlim=64 time=144.179 ms 16 bytes from 2001:db8::1, icmp_seq=88 hlim=64 time=146.573 ms 16 bytes from 2001:db8::1, icmp_seq=89 hlim=64 time=157.132 ms 16 bytes from 2001:db8::1, icmp_seq=90 hlim=64 time=147.372 ms 16 bytes from 2001:db8::1, icmp_seq=91 hlim=64 time=307.801 ms 16 bytes from 2001:db8::1, icmp_seq=92 hlim=64 time=148.159 ms 16 bytes from 2001:db8::1, icmp_seq=93 hlim=64 time=148.573 ms 16 bytes from 2001:db8::1, icmp_seq=94 hlim=64 time=148.974 ms 16 bytes from 2001:db8::1, icmp_seq=95 hlim=64 time=446.143 ms 16 bytes from 2001:db8::1, icmp_seq=96 hlim=64 time=149.767 ms 16 bytes from 2001:db8::1, icmp_seq=97 hlim=64 time=49.931 ms 16 bytes from 2001:db8::1, icmp_seq=98 hlim=64 time=4.134 ms 16 bytes from 2001:db8::1, icmp_seq=99 hlim=64 time=4.699 ms 16 bytes from 2001:db8::1, icmp_seq=100 hlim=64 time=4.104 ms 16 bytes from 2001:db8::1, icmp_seq=101 hlim=64 time=4.151 ms 16 bytes from 2001:db8::1, icmp_seq=102 hlim=64 time=4.384 ms 16 bytes from 2001:db8::1, icmp_seq=103 hlim=64 time=4.352 ms
さくらのVPS上のOpenBSDをハブにすることで、PPPoEと3G回線を組み合せた構成が作れました。