FreeBSD の IPSec による VPN の実現は gif という仮想ネットワークインタフェイスに頼っています。これは IP データグラムの中にそのまま IP データグラムを入れるものです。当然ですが、MTU は外側の IP ヘッダの分だけ小さくなってしまいます。
# ifconfig fxp0 fxp0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu 1500 options=8<VLAN_MTU> inet A.B.C.D netmask 0xffffff00 broadcast A.B.C.255 media: Ethernet autoselect (100baseTX <full-duplex>) status: active # ifconfig gif0 gif0: flags=8051<UP,POINTOPOINT,RUNNING,MULTICAST> mtu 1280 tunnel inet A.B.C.D --> E.F.G.H inet W.X.Y.Z --> S.T.U.V netmask 0xffffffff
gif では MTU を指定する(仮想的に大きくすること)はできません。そこで、ports の net/tcpmssd をつかいます。tcpmssd は MSS を強制的に指定した値に書き換えてします divert 用デーモンです。
tcpmssd を /etc/rc.local を使ってOS起動時に起動します。
/usr/local/bin/tcpmssd -p <divertソケットの番号適当でよい> -m 1280
/etc/rc.firewall の中で、MSS を書き換えるパケットを tcpmssd に流し込むようにします。
# TCP MSS adjustment ${fwcmd} add divert <divertソケットの番号適当でよい> tcp from <VPN先のサブネット;例:192.168.88.0/24> to <こちらのサブネット;例:192.168.99.0/24> tcpflags syn out via ${iif}
この設定を双方で対称に行います
OpenVPN は MTU を設定するコマンドラインオプションがありますので、それをつけて起動します。
--tun-mtu 1500 --fragment 1300 --mssfix
本当は、この三つのオプション全部は必要ないのではないかと思うのですが、試行錯誤の過程で全部つけてしまいました。
VPNの Peer ルータの外側のアドレスが固定できない状況というのがあります。例えば、xDSL の自宅から研究室という状況では自宅側の xDSL ルータの外側のアドレスは固定できません。あるいはモバイルです。そのような状況では IPsec は設定できません。gif によるトンネルの確立や、setkey コマンドによる IP を暗号化するか否かの決定(ポリシー)等で、IP アドレスは指定されています。一方、OpenVPN の場合はサーバ/クライアントという役割があり、VPN の確立には手順がありますので、クライアント側のアドレスは流動的でもかまいません。
レイテンシに関しては IPsec に分があります。一旦、デーモンプロセスを経由する OpenVPN とカーネル内部だけで処理される IPsec ではこの差が付くのは仕方がありません。