Linux
Network

FWMARKを使ってport80, 443のみにDS-Liteを適用する

More than 1 year has passed since last update.

概要

以前このような記事を書きました。

しばらくして次のような問題が出てきました。

  • iproute2 4.xでこの書式を受け付けなくなった (Debian jessie->stretchでメジャーバージョンが上がった)
  • キャリアグレードNATは提供する側の都合で仕様がかわる
    • 長時間張りっぱなしのセッションは、データが流れないとCGN側で切られるけどこちら側からは切れたように見えない
    • IMAPクライアント立ち上げっぱなしとかで困る
    • sshに関しては特別扱いされるようになったっぽい
  • 出口IPがサービスによってはBANされてることがある

これに対し、「80, 443以外はDS-Lite使うのをやめたら」という助言を知人よりいただいたので、それを実践してみました。

トンネルインターフェースの作成

以前の記事にあるままです。そちらを参考にしてください。できあがったインターフェースはip5tnl1という名前とします。

Netfilterのmark機能

Linux Advanced Routing & Traffic Control HOWTOのChapter 11が詳しいです。

特定のルールにマッチするパケットに対し、記号を付けることができます。32bitの値でビット単位に意味を持たせることができます(CONFIG_IP_ROUTE_FWMARK)。今回はこの機能を活用します。

送信先ポート番号が80, 443のパケットにマークを付ける

iptables -A PREROUTING -i br0 -t mangle -p tcp --dport 80 -j MARK --set-mark 2
iptables -A PREROUTING -i br0 -t mangle -p tcp --dport 443 -j MARK --set-mark 2

物理デバイスbr0のPREROUTINGチェイン、mangleテーブルにMARKモジュールを使って0x002(2ビット目)を立てます。送信先ポート80, 443に対してこれらを適用します。

マークとテーブル、ルーティングの定義

# mark 0x02に対しポリシールーティングテーブル3番を適用
ip rule add fwmark 2 table 3 
# ポリシールーティングテーブル3番のデフォルトゲートウェイをトンネリングデバイスに設定
ip route add default dev ip6tnl1 table 3 

これで80, 443ポートへのすべての通信はip6tnl経由で出ていくことになります。

例外を設定する

ただ、すべての通信がうまくはいかないことがあります。先に述べた「アドレスがBANされている」ようなケースです。

自分の場合、DHCPで特定のMACアドレスを持つハードウェアに対し固定アドレスを割り当てているので、そういった機器が利用するサービスがBANされているようなケースに、次のようなルールの追加で対処しています。

iptables -A PREROUTING -i br0 -t mangle -p tcp -s 192.168.xx.yy \
 -j MARK --set-mark 0 

このルールは先の--set-mark 2の後に来るように記述します。ルールは-Aオプションで追加した順序で適用されるので、すべてのソースIPアドレスが2とマーキングされたあと、指定したソースIPアドレスのパケットすべてのマーキングを0に設定しなおします。
これにより、ここで指定したIPアドレスの通信のみ、通常のルーティングに従うことになります。

雑感

なんだかんだでThe Linux Documentation Project(LDP)その翻訳(JF)は頼りになります。JFはここ何年もアクティビティが非常に低いですが、今でも役に立つ情報はあります。ただ、リンク切れにだけ気を付けてください。