前書き

IPv6シングルスタックネットワークを作ると、IPv4のみのサーバーに接続できなくなる。
NAT64を使うことで、IPv6アドレスを使ってIPv4サーバーに接続できるようにすることができる。
ただし、NAT64を行うルーターはIPv6とIPv4のデュアルスタックであることが必要。
OpenWRTにjoolとknot-resolverをインストールして、LAN内をシングルスタックで済むようにする。

ここではknot-resolverを使いますが、それなりにストレージを消費しますので、unboundのほうがよいかもしれません。
NanoPi R2S を使っていますが、SquashFS 標準の割り当て容量では不足しました。 ext4版を使ってストレージいっぱいまで領域を拡張して使っています。

パッケージのインストール

  • jool-tools-netfilter
  • knot-resolver

※ほかのパッケージは依存関係で自動的にインストールされる。

パッケージバージョン

# jool --version
(Xtables disabled)
4.1.6.1
# kresd --version
Knot Resolver, version 5.5.3

jool

joolを使って、NAT64を実装する。

サービスの停止

# service jool stop

設定ファイルのバックアップ

# mv /etc/jool/jool-nat64.conf.json /etc/jool/jool-nat64.conf.json.bk

設定ファイル

# vi /etc/jool/jool-nat64.conf.json
{
	"instance": "nat64-minimal",
	"framework": "netfilter",

	"global": {
		"pool6": "64:ff9b::/96"
	}
}
# vi /etc/config/jool
config jool 'general'
        option enabled '1'

config jool 'nat64'
        option enabled '1'

config jool 'siit'
        option enabled '0'

サービスの開始

# service jool start

knot-resolver

knot-resolverを使ってDNS64を実装します。

# vi /etc/init.d/kresd

編集前

        # knot-resolver config
        procd_append_param command -c "$CONFIGFILE"
        procd_append_param command -a "0.0.0.0#53"
        procd_append_param command -a "::0#53"
        procd_set_param nice '-5'
        procd_close_instance

編集後

        # knot-resolver config
        procd_append_param command -c "$CONFIGFILE"
        procd_append_param command -c "/etc/knot-resolver/kresd.conf"
        procd_append_param command -a "0.0.0.0#53"
        procd_append_param command -a "::0#53"
        procd_set_param nice '-5'
        procd_close_instance
# vi /etc/knot-resolver/kresd.conf
-- Enable DNS64
modules = { 'dns64' }
-- DNS64 Reconfigure
-- dns64.config({ prefix = '64:ff9b::' })

このままだとknot-resolverが自らDNSサーバーへ問い合わせますが、ISPが提供するDNSサーバに転送したい場合は、同ファイルに以下の設定を入れておきます。(私の環境では、HGWのアドレスを設定するときにDNSSECを有効にするとダメだったので、以下の例は使用しない例です。)

policy.add(policy.all(policy.STUB({'192.168.1.1'})))

"STUB"の部分を"FORWARD"にするとDNSSECをを有効にし、DNS over TLSを使用したい場合は"TLS_FORWARD"を使用します。詳しくは、 https://knot-resolver.readthedocs.io/en/stable/modules-policy.html をご確認ください。

DnsmasqのDNSサーバを無効にしてknot-resolverを有効にする

# uci set dhcp.@dnsmasq[0].port='0'
# uci commit dhcp
# service dnsmasq restart
# service kresd restart

確認

# jool instance display
(Xtables disabled)
+--------------------+-----------------+-----------+
|          Namespace |            Name | Framework |
+--------------------+-----------------+-----------+
|           10db2440 |   nat64-minimal | netfilter |
+--------------------+-----------------+-----------+
# jool --instance "nat64-minimal" global display
(Xtables disabled)
  manually-enabled: true
  pool6: 64:ff9b::/96
  lowest-ipv6-mtu: 1280
  logging-debug: false
  zeroize-traffic-class: false
  override-tos: false
  tos: 0
  mtu-plateaus: 65535,32000,17914,8166,4352,2002,1492,1006,508,296,68
  address-dependent-filtering: false
  drop-externally-initiated-tcp: false
  drop-icmpv6-info: false
  source-icmpv6-errors-better: true
  f-args: 11 (0b1011): SrcAddr:1 SrcPort:0 DstAddr:1 DstPort:1
  handle-rst-during-fin-rcv: false
  tcp-est-timeout: 2:00:00 (HH:MM:SS)
  tcp-trans-timeout: 0:04:00 (HH:MM:SS)
  udp-timeout: 0:05:00 (HH:MM:SS)
  icmp-timeout: 0:01:00 (HH:MM:SS)
  logging-bib: false
  logging-session: false
  maximum-simultaneous-opens: 10
  ss-enabled: false
  ss-flush-asap: true
  ss-flush-deadline: 2000
  ss-capacity: 512
  ss-max-payload: 1452

問題なく動作しているようであれば、端末へのIPv4アドレスの割り当てを停止します。端末にIPv6アドレスのみ割当たっている状態で、IPv4のWebページを開くことができれば完了です。 https://ipv6.test-ipv6.com/ などを使って、デュアルスタックの環境として動作してるか確認するとよいです。

セッションテーブル

NAT64のセッションテーブルを確認するコマンド

jool --instance "nat64-minimal" session display

パフォーマンスの改善

NanoPi R2S を使っているのですが、NAT64だと特定の通信相手との通信が異常に遅くなるという問題が発生しました。この辺MTUなど調査してみたのですがよくわからず。WAN側インターフェースのオフロードを無効にしたらなんかよくなったので記載しておきます。

# ethtool --offload eth0 lro off
# ethtool --offload eth0 gro off

設定状況は、次のコマンドで確認ができます。

# ethtool --show-offload eth0 | grep receive-offload

追伸(2023/04/17)

knot-resolverからunboundに乗り換えた。別の機能が使いたくてknot-resolverを使っていたのですが、その必要がなくなったのと、コメントでも言及があったので。

luci-app-unbound パッケージを入れると、LuCI(WebUI)から設定できて便利。

参考資料