Lambdaカクテル

京都在住Webエンジニアの日記です

Invite link for Scalaわいわいランド

FreeBSD11.1とDS-lite(IIJmio)でIPv6ルータを作った(ルーティング&NAT66編)

FreeBSDマシンでIPv6ルータを作るお話です

前回はコチラ↓

windymelt.hatenablog.com

IPv6ルーティングとNAT66

FreeBSDマシンがIPv6ネットワークに接続できるようになったので,IPv6パケットをルーティングできるようにする(目標1,IPv6ルーティング).また,LAN側にはローカルなアドレスを配布し,外からは見えなくする(目標2,NAT66).

ここでigb0はLAN側のNICであり,em0はインターネット側のNICであり,<LOCAL-ULA>はローカルネットワークでゲートウェイとして使うユニークローカルアドレス(ULA)である.ここではfdda:f0f7:c6cc::1とした.

ユニークローカルアドレスとは,IPv4でいうところのプライベートアドレスで,閉じたネットワークで自由に使ってよいものである.ULAはfc00::/7の範囲で使うことができ,グローバルインターネットではルーティングされない.

ルータ情報を配布するrtadvdpfをインストールする.

# pkg install rtadvd pf

rc.conf に設定を追加する.

# rc.conf

# IPv6ゲートウェイとして振る舞うようにする
ipv6_gateway_enable="YES"

# IPv6ゲートウェイとして振る舞うようにするとRAを受信しなくなるので,em0では受信できるようにする
ipv6_cpe_wanif="em0"

# LAN側のNICにはアドレスを静的に設定し,ルータ広告を受信しない設定にする
ifconfig_igb0_ipv6="inet6 <LOCAL_ULA> -accept-rtadv"

# Router Advertisement Daemonをigb0で起動する
rtadvd_enable="YES"
rtadvd_interfaces="igb0"

# Packet FilterにNAT66を行わせるために起動する
pf_enable="YES"

ipv6_cpe_wanifを指定しているのは,ゲートウェイになったときにRAを受信しなくなる挙動を回避させるためである.自分はこの情報をなかなか見付けられなかったので苦労した.

調べたところによれば,-no-radrifconfig_em0_ipv6=...に追記しておくことで同等の挙動を確保できるかもしれない.*1

ifconfig_igb0_ipv6-accept-rtadvを指定している箇所に注意してほしい.頭にハイフンが付いている.これはRA(Router Advertisement)を受信しないという意味であり,accept-rtadvがRAを受信させるという意味であるのと対をなすオプションである.

rtadvdは,ルータ広告メッセージを発するデーモンで,IPv6で言うところのDHCPサーバにあたる(が,実際にアドレスを配ることはない).

rtadvdの設定

rtadvdの設定を行う.デフォルトの設定ファイルは/etc/rtadvd.confである. ここで,<LOCAL_ULA_PREFIX><LOCAL_ULA>が属するプレフィックスで, fdda:f0f7:c6cc::に設定している.

default:\
        :raflags#0:mtu#auto:
igb0:\
        :addr0="<LOCAL_ULA_PREFIX>":prefixlen#64:tc=default:

冒頭2行は優先度は標準であることと,MTUは自動であることを宣言している. 3..4行目では,igb0というNICについての設定であることと,広告するアドレスのプレフィックスと,プレフィックスが64ビットであることを宣言している.tcはterm capabilityの略らしいが,細かい事が分からなかった.

rtadvdには,割り当てるアドレスの詳細を設定しない.IPv6はSLAACと呼ばれるアルゴリズムにより,プレフィックスを受け取れば,MACアドレスなどを用いて静的にアドレスを決定できるからである.

Packet filterの設定

IPv6で行うNAT技術の1つにNAT66がある.IPv6からIPv6へとNATを行うのでNAT66である.

NAT66を設定するためにpfを使うことができる.pfはパケットのフィルタリング全般に使えるツールであり,しばしばファイヤウォールとして使われる.

/etc/pf.conf を設定する.冒頭3行は,単なるマクロの定義を行っている.上から,

  • インターネットに接続されているNICの名前
  • LAN側インターフェイスに割り当てられたプレフィックス
  • <OUTER_ADDR>はインターネットに接続されているNICに割り当てられたユニキャストアドレス

である.4行目でNATの設定を行い,後の行は

  • ループバックインターフェイスではパケットフィルタを無視すること
  • 名前解決用のポートを開放すること(後でDS-liteのためにローカルDNSを使うため)
  • こちらから出ていくパケットとその返答は通すこと

を指定している.

onu_if="em0"
int_ipp="<LOCAL_ULA_PREFIX>/64"
onu_ip="<OUTER_ADDR>"
nat on $onu_if inet6 from $int_ipp to any -> $onu_ip

set skip on lo0

pass in proto tcp to any port name
pass out all keep state

ここで再起動し,LAN側NICにハブなどを介してホストを接続させてみる.

LAN側NICに接続したホストがULAを割り当てられており,2001:4860:4860::8888(Google Public DNS IPv6)などにpingできるか確認する.これが疎通できたらルーティングできている.

正しくIPv6 DNSアドレスを指定しておけば,LANに接続したホストで(IPv6 onlyだが)インターネットが可能になるはずである.自分の環境では,うまくIPv6 DNSアドレスを獲得できなかったので,Google Public DNS IPv6を指定したところ,インターネットが使えるようになった.

次回はDS-liteでIPv4インターネットに接続できるようにする.

★記事をRTしてもらえると喜びます
Webアプリケーション開発関連の記事を投稿しています.読者になってみませんか?