PFでNAT64 - OpenBSD 5.1

※ はてなブログから技術ネタを移動しました
※ [初稿](http://qpshinqp.hateblo.jp/entry/20120829/1346238280)：2012-08-29

NAT64とは、DNS64と組み合わせることにより、IPv6 onlyネットワークからもIPv4のサービスにアクセスできるようにする機能のこと。これをサーバ上で実現する方法としては、

- linuxnat64
- Ecdysis (linux)
- Ecdysis (pf patch for OpenBSD 4.6)
- Tayga
- PF (OpenBSD 5.1)

がある。今回はPF (OpenBSD 5.1)を使った。
以下、上記それぞれについて少々。

### linuxnat64

linuxnat64はちょっと前までsourceforgeから利用可能だったみたいですが、今はなくなってしまいました。探してみたところ、簡単には見つからないみたいです。私は、知り合いからソースコードを貰いました。少なくとも、Ubuntu 10.04.3 x64では動くみたいです。

### Ecdysis (linux)

[Ecdysis: open-source nat64](http://ecdysis.viagenie.ca/)から利用可能です。ただ、ネット上や知人からの情報だと、linuxではうまく動かない(tcp seqがずれたり、chksumがおかしかったりpayloadが壊れたり)という噂を聴いたので不安になりました。
実際にインストールしてみたところだと、はじめはping6は通るけど、wgetが時々失敗するという現象に遭遇しました。しばらくすると安定して動き始めたのですが、不具合の原因はいまいちわかっていません。うまく動くこともあるようです。

### Ecdysis (pf patch for OpenBSD 4.6)

すでにkernel patch済なisoが[Ecdysis: open-source nat64](http://ecdysis.viagenie.ca/download.html)の最下にあります。これは導入しやすそうな気がしますが、試していません。

### Tayga

これはstatelessなNAT64で、今回の要件にマッチしていないので使いませんでした。stateless NATというのは、変換前のIPアドレスと変換後のIPアドレスが1対1対応するとかなんだかそういう感じだったと思います。

### PF (OpenBSD 5.1)

聞いたところによると、Ecdysisの開発者がコードを書きなおしてOpenBSDのカーネルに機能をマージしたものらしい。スマート。設定は簡単。今回使ったのはこれ。

## NAT64の設定

### OpenBSD 5.1のセットアップ

インストーラisoは[OpenBSD: Mirrors](http://www.openbsd.org/ftp.html)から辿ると落とせます。私は、[http://ftp.jaist.ac.jp/pub/OpenBSD/5.1/amd64/](http://ftp.jaist.ac.jp/pub/OpenBSD/5.1/amd64/)のinstall51.isoを使いました。
[OpenBSD FAQ: Installation Guide](http://www.openbsd.org/faq/faq4.html)このへんでも見るといいです。インストーラの指示に従うだけですが、Ubuntuしかインストールしたことない人にとってはちょっと難しいかもしれません。
この辺はもしかすると少しはわかりやすいかもしれない。[OpenBSDのインストール方法詳細メモ(1) - 情報科学屋さんを目指す人のメモ（FC2ブログ版）](http://did2.blog64.fc2.com/blog-entry-255.html)

### NICの設定

用意すべきは

- 1つ以上のNIC
- IPv6アドレス
- IPv4アドレス
- prefix長が96以下のIPv6 prefix

です。これらが確保できたら、 /etc/hostname. を編集してIPアドレス等の設定をします。
は該当するインターフェース名です。(e.g. bnx0, em0)

```/etc/hostname.em0
inet 192.0.43.10 255.255.240.0
inet6 2001:500:88:200::10 64
!route add -net default 192.0.43.1
!route add -inet6 default 2001:500:88:200::1
```
`192.0.43.10`はNAT64をするマシンのIPv4アドレス
`2001:500:88:200::10`はそのIPv6アドレス
`192.0.43.1`はNAT64マシンがいるセグメントのdefault gateway
`2001:500:88:200::1`もdefault gateway
意味を考えて、適宜自分の環境にあわせて読み替えてください。
/etc/hostname.の編集が終わったら、

```shell-session
# /etc/netstart
```

で設定を反映。

### pfの設定

デフォルトでは/etc/pf.confが設定ファイルです。
これに以下のような行を追加してください。

```/etc/pf.conf
# nat64
pass in quick inet6 to 2001:500:88:200::10
pass in quick inet to 192.0.43.10
pass in inet af-to inet6 from 2001:500:88:200::10 to 2001:500:88:ff64::/96
pass in inet af-to inet6 from 2001:500:88:200::10
pass in inet6 af-to inet from 192.0.43.10 to 0.0.0.0/0
pass in inet6 af-to inet from 192.0.43.10
```
ただし、これをやると他のインターフェースにも影響を与えるかもしれないので、`set skip on em1` でルール適用除外したり、af-toルールの適用条件に on em0 加えるなどして調整してください。
各行の意味は、
1. 64変換すべきではない、自分(NAT64マシン)宛のパケットは自分の方に受理してあとの64変換ルールを適用しない
2. 同上
3. `2001:500:88:200::10`に設定されたインターフェースに`2001:500:88:ff64::/96`宛のパケットが届いたら、宛先アドレスの下位32ビットからIPv4アドレスを取り出し、そのIPv4アドレス宛てのパケットへと変換する(NAT64の動作)
4. ようわからん
5. `192.0.43.10`に設定されたインターフェースに届いたパケットの送信元IPv4アドレスを`2001:500:88:ff64::`の下位32ビットに埋め込み、IPv6パケットに変換する(NAT64の動作)。
6. ようわからん。

ちなみに、`2001:500:88:ff64::/96`はNAT64の変換用プレフィックス
こんな感じで動いています。af-toっていうのが肝心ですね。私にはよくわかっていない部分もあります。
気になる人は、[OpenBSD manual pages](http://www.openbsd.org/cgi-bin/man.cgi?query=pf.conf&manpath=OpenBSD%20Current&sektion=5&format=html)でも見てください。


*2013/02/24 追記*
現在検証したところ, `pf.conf`はもっとシンプルに書けるようです。

```/etc/hostname.em0
inet6 2001:0DB8:100::2 64
```
```/etc/hostname.em1
inet 192.0.2.2 255.255.255.240
```
```/etc/pf.conf
pass in quick inet to 192.0.2.2
pass in quick inet6 to 2001:0DB8:100::2
pass in inet6 from any to 2001:0DB8:64::/96 af-to inet from 192.0.2.64/28 to 0.0.0.0/0
```
この例では, nat64マシンの

- 実IPv4アドレスが`192.0.2.2/28`
- 実IPv6アドレスが`2001:0DB8:100::2/64`
- nat64変換先IPv4アドレスプールが`192.0.2.64/28`
- nat64変換元IPv6プレフィックスが`2001:0DB8:64::/96`

という条件下でnat64トランスレーションを行なっています。

`/etc/pf.conf`の各行の意味は,

1. 実IPv4アドレス宛のパケットには変換ルールを適用せずにnat64マシンが受け取る
2. 実IPv6アドレス宛のパケットには変換ルールを適用せずにnat64マシンが受け取る
3. 送信元IPv6アドレスが任意で, 送信先IPv6アドレスが`2001:0DB8:64::/96` (変換元プレフィックス) のIPv6パケットは, 宛先IPv6アドレスの下位32bitに埋め込まれた本来の(designated)宛先IPv4アドレスを取り出し, 宛先IPv4アドレスを抽出したIPv4アドレスに, 送信元アドレスを`192.0.2.16/28` (変換先アドレスプール)のいずれかのアドレスに変換して転送する

と言ったところです。pfのnat64はステートフルなので, inet6 (IPv6) -> inet (IPv4)の変換ルールを書いておけば, NATテーブルを参照することで戻り(inet -> inet6)の変換も行えることから, 特にinet -> inet6の変換ルールを明記する必要性はありません。

あとはルーターには`2001:0DB8:64::/96`のnext-hopを`2001:0DB8:100::2`とする経路を書いておけば, nat64が使えるはずです。
*追記ここまで*


設定が書けたら、

```shell-session
# pfctl -Fa -f /etc/pf.conf
```
でルール適用。基本的にはこれで完成です。
実際にこのNAT64を使うためには、

- DNS64を建て
- DHCPv6にDNS64の設定を入れ
- ルーターで`2001:500:88:ff64::/96`プレフィックスのNext hopをNAT64機(`2001:500:88:200::10`)へ向ける

といったことが必要になるはずですね。他にも必要な作業が抜けているかもしれないですけど、気づいた方はご指摘ください。