OpenBSD で PF ルールによる MAP-E 動作
コンテンツ
OpenBSD で MAP-E 方式の IPv4 over IPv6 を動作させるためのメモ。前回はカーネルにパッチをあて PF の動作に修正を加えていたが、PF ルールを工夫することでおおむね MAP-E 動作を実現する。
PF のオプション probability を利用して、NAT で使用するポート番号を MAP-E の port set に制限する。なお、カーネルの動作が原因で、この方法では一部の ICMP が利用できない。
オプション probability の必要性
MAP-E 動作には NAT で使用されるポート番号をクライアント毎に排他的に割り当てられるポート集合に制限する必要がある。ポート集合は複数のポート区間(5376-5439, 9472-9535, …, 62720-62783 など)であり、通常の PF ルールでは使用ポート番号を複数の区間に制限することはできない。
通常の PF ルールでも単一のポート区間に制限することはできる。単一のポート区間では使用できるポート数が少ないため、同一アドレスに並列接続が必要なサイトなどとの通信に不具合が発生する可能性がある。
そこで複数ポート区間毎に NAT ルールを作成して、各 NAT ルールが等確率で適用されるように PF を設定できれば、利用可能なポート集合を全て使うことができる。このルールが適用される確率を設定する際にオプション probability を利用する。
具体的な probability 設定方法
ここでは MAP-E で利用可能なポート集合が15区間で、各区間64ポートであるとする。
このポート区間それぞれに対して NAT ルールを作成して、それが適用される確率が 1/15 となるように設定すれば良い。
ただし、PF では最後に match したルールが有効になるので、単純に各ルールの match 確率を 1/15 としては、そのルールが適用される可能性は 1/15 とならない。実際、全てのルールの match 確率を 1/15 (約 6.7%)とすると最初のルールが適用される(最初のポート区間が使用される)確率は約 2.5% となる。これは最初のルールが適用されるには最初のルールに match し、かつ以降全てのルールに unmatch する必要があるからである。
|
|
2.5376026178153164 | 6.666666666666667 |
このように match 確率の設定は一見難しそうではあるが、実は N 個のルールがあり、 各ルールが適用される確率を 1/N としたい場合、 i 番目のルールの match 確率を 1/i と設定すれば良い。
確率設定の考え方
次が成立し、i 番目のルールに着目すると i 番目以降のルールの match/unmatch のみを考慮すれば良いことに着目する。
i 番目のルールが適用される if and only if i 番目のルールに match し、 i+1,..,N 番目のルールに unmatch
そこで次のように帰納的に考える。今 (i+1) 番目から N 番目のルールのどれかに match する確率が (N-i)/N となるように (i+1) 番目から N 番目のルールの match 確率が設定できているとする。
このとき i 番目の match 確率を p_i とすると i 番目が適用される確率は
p_i * (1 - (N-i)/N) = p_i * i / N
となる。よって p_i = 1/i と設定すれば i 番目が適用する確率は 1/N となる。
また、このとき i 番目から N 番目のルールのどれか match する確率は
p_i + (1 - p_i) * (N-i) / N = (N-i)/N + p_i * i/N = (N-(i-i)) / N
となり、次のステップの帰納仮説が成立する。
なお、最初のステップの i = N は自明に成立する。
PF ルール の生成と適用
多数の NAT ルールが必要となるのでスクリプトでルールを作成して PF の Anchor として適用する。
ルール生成
生成スクリプト
次は PSID offset = 4, PSID length = 6, PSID = 20 として PF ルールを生成するスクリプトである。
|
|
生成ルール例
|
|
ルール適用
生成したファイルを別ファイル /etc/pf-map-e-nat.conf
などに保存して、メイン設定ファイル pf.conf
から anchor として読み込む。
|
|
Anchor を利用することで多数の NAT ルールを別ファイルに管理でき、また anchor 適用時に一箇所でフィルターオプションを指定することで各ルールにフィルターオプションを指定する必要がなくなる。
ICMP について
今回の方法では IPv4 ICMP Echo 通信(ping)ができない。これはそもそものカーネルの動作として ICMP Echo パケットはルールで指定したポート制限が反映されないためである。
次はカーネルソースコードの該当箇所である。
|
|
ICMP Echo の場合はポートの範囲が 1 から 65535 に固定される。この動作を変更するにはカーネルに手を加える必要がある。
作成者 Toru Mano
最終更新時刻 2023-01-01 (c70d5a1)