TL

Conntrack:ステートフルファイアウォールの内部

なぜ戻りパケットを許可ルール無しで通せるのかが腑に落ちます。フロー単位で接続を追跡する仕組みと、NAT との連携、そして本番で詰まるテーブル枯渇まで原理から押さえます。

応用conntrackファイアウォールNATnetfilteriptables状態追跡最終更新: 2026-06-21
TL;DR要点だけ先に
  • 1.ステートフルファイアウォールはパケット単位でなくフロー単位で判定する。接続追跡(conntrack)がフローの状態を表に持ち、戻りパケットを ESTABLISHED として自動許可する。
  • 2.状態は NEW/ESTABLISHED/RELATED/INVALID の4種。RELATED は FTP データ接続や ICMP エラーなど、別フローだが既存接続に紐づくものを通す。
  • 3.NAT は conntrack エントリにアドレス変換を記録して往復で一貫変換する。エントリ数には上限があり、超えると新規接続が落ちる(テーブル枯渇)。

パケット単位ではなく「フロー単位」で判定する

素朴なファイアウォールは1パケットずつヘッダを見て許可・拒否を決めます。だが TCP は双方向です。クライアントの発信を許可すると、サーバーからの戻りパケットも通さねばならない。これをパケット単位の静的ルールで書くと「外向きの新規接続は許可、内向きは戻りだけ許可」を手作業で対称に記述する羽目になり、ポート範囲ごとに穴を開けることになって破綻します。

ステートフルファイアウォール はこの問題を、判定の単位を フロー(コネクション) に引き上げて解決します。一度通した発信を「接続」として記憶し、その接続に属する戻りパケットを自動で許可する。Linux では netfilter の 接続追跡(connection tracking, conntrack) サブシステムがこの記憶を担います。フロー単位という発想の前提として、TCP/UDP の双方向性は /network/tcp-udp/ を参照してください。

conntrack は何を覚えているのか

conntrack はカーネル内に コネクション追跡テーブル を持ち、観測したフローを1エントリとして登録します。フローの同一性は概ね次の5要素(5タプル)で決まります。

  • プロトコル(TCP/UDP/ICMP など)
  • 送信元IP・送信元ポート
  • 宛先IP・宛先ポート

各エントリは「往路(original)」と「復路(reply)」の2方向タプルを持ちます。復路タプルは往路を反転させたもので、これにより戻りパケットが来たとき「どのフローの戻りか」を逆引きできます。最初のパケットが入ると netfilter のフックでエントリが仮登録され、フロー終了やタイムアウトで除去されます。

conntrack は『判定』ではなく『分類』

conntrack 自体はパケットを通す/落とすを決めません。各パケットに「このフローの状態は ESTABLISHED だ」というラベルを付けるだけです。許可・拒否を決めるのは、そのラベルを参照するファイアウォールルール(iptables/nftables)側です。追跡と判定は分離されています。

状態:NEW / ESTABLISHED / RELATED / INVALID

ルールが参照する ctstate(接続状態)は4種類です。これは TCP のハンドシェイク状態とは別の、netfilter から見たフローの分類である点に注意してください。

状態意味典型例
NEWそのフローで初めて観測したパケット。テーブルに往路エントリが作られるクライアントが送る最初の SYN
ESTABLISHED既存エントリに往復どちらかで合致するパケット確立後のデータ、サーバーからの戻り全般
RELATED別フローだが既存接続に論理的に紐づくパケットFTP のデータ接続、ICMP エラー(Port Unreachable 等)
INVALIDどのエントリにも合致せず状態整合もしないパケット確立前の素の ACK、寿命切れフローの遅延パケット

実務のファイアウォールはこの分類を使い、たった2行で「発信は許可、戻りは自動許可」を実現します。

# 確立済み・関連フローの戻りパケットは無条件で通す(戻り用に穴を開けない)
iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
# 不整合パケットは捨てる
iptables -A INPUT -m conntrack --ctstate INVALID -j DROP
# 以降、NEW の着信だけをサービスごとに個別許可すればよい
iptables -A INPUT -p tcp --dport 22 -m conntrack --ctstate NEW -j ACCEPT
RELATED が無いと FTP もエラーも通らない

アクティブFTPはデータ転送用に別ポートで新しい接続を張ります。これは5タプルが違うので単独では NEW です。conntrack のヘルパ(ALG)が制御接続のやり取りを覗いてデータ接続を予約し、それを RELATED として扱うことで穴を開けずに通します。同様に「宛先不達」などの ICMP エラーは元フローを参照する RELATED であり、これを落とすと PMTUD 失敗などの不可解な不具合を招きます。

TCP の状態はもっと細かく追う

TCP については conntrack はさらに内部状態(SYN_SENT, SYN_RECV, ESTABLISHED, FIN_WAIT, TIME_WAIT など)を独立に持ち、フラグの整合性を検査します。例えばハンドシェイク前に届いた裸の ACK は INVALID 扱いになります。これにより、確立シーケンスを踏まない注入パケットを弾けます。conntrack の TCP 状態は TCP プロトコル本来の状態機械を模した別実装であり、両者を混同しないことが重要です。本来の状態遷移は /network/tcp-state-machine/ を参照してください。

状態ごとにタイムアウトが設定され、確立済み TCP は既定で非常に長い(数日規模)一方、UDP は応答が無いと短時間(数十秒〜数分)で消えます。UDP は本来コネクションレスですが、conntrack は往復タプルの観測でフローを擬似的に張り、戻りを通します。

NAT との連携

NAT は conntrack の上に構築されます。アドレス・ポート変換は フローの最初のパケット に対してだけ決定され、その変換内容が conntrack エントリに刻まれます。以後のパケットは状態照合でエントリに合致し、記録済みの変換が往復で一貫適用されます。

内側 192.168.0.10:51000 ──► (NAT) ──► 203.0.113.1:40001 ──► 宛先サーバー
   往路: src=192.168.0.10:51000 dst=server:443  を
   復路: dst=203.0.113.1:40001         に書き換えて記録
   戻り: src=server:443 dst=203.0.113.1:40001 を
         エントリ逆引きで dst=192.168.0.10:51000 へ復元

つまり PAT/マスカレードで「ポートで端末を見分ける」あの対応表の正体が、conntrack エントリそのものです。NAT の外形的な振る舞いとポートフォワーディングは /network/nat/ に、対称NATで直結が破綻する理由は /network/nat-traversal-hole-punching/ にまとめています。

NAT があると conntrack は実質必須

変換の一貫性はエントリの存在に依存します。エントリが消える・作られないと、戻りパケットの逆変換ができず通信が片方向で死にます。だから NAT ルータでは conntrack を無効化できず、エントリ数が直接スケール上限になります。

ステートレスにしたい高速経路(ルーティングのみで NAT 不要なトラフィック)には notrack(raw テーブルで追跡対象から除外)を使い、conntrack の負荷とエントリ消費を避ける設計も取られます。

テーブル枯渇:本番で最も刺さる罠

conntrack テーブルにはエントリ数の上限(nf_conntrack_max)があります。エントリはハッシュテーブルで管理され、上限に達すると 新規フローのパケットがドロップ され、ログに nf_conntrack: table full, dropping packet が出ます。既存接続は生きているのに新規接続だけが落ちるため、「一部のユーザーだけ繋がらない」という再現性の低い障害として現れます。

枯渇しやすいのは次のような状況です。

  • 短命接続を大量に張る構成(ロードバランサ配下、リバースプロキシ、ベンチマーク)
  • UDP フラッドや SYN フラッド。確立しないフローでもエントリは消費される
  • タイムアウトが長く、消えないエントリが積み上がる(特に既定の長い TCP ESTABLISHED)
# 現在のエントリ数と上限を確認
sysctl net.netfilter.nf_conntrack_count net.netfilter.nf_conntrack_max

# 状態の偏りを集計(どの状態のフローが溜まっているか)
conntrack -L 2>/dev/null | awk '{print $1, $4}' | sort | uniq -c | sort -rn | head

# 上限とハッシュバケットを引き上げる(メモリと引き換え)
sysctl -w net.netfilter.nf_conntrack_max=1048576
echo 262144 > /sys/module/nf_conntrack/parameters/hashsize
上限を上げるだけでは直らないことがある

枯渇の根本がタイムアウト設計や攻撃トラフィックなら、nf_conntrack_max を増やしてもメモリを食い潰すだけで遅延を招きます。確立済み TCP のタイムアウト短縮、不要フローの早期 INVALID ドロップ、攻撃元のレート制限、そして「追跡が本当に要らない経路」の notrack 化を併用するのが筋です。エントリ1件あたり数百バイトを消費するため、100万エントリは無視できないメモリ量になります。

試験・面接で問われる要点

「ステートフルが戻りを通せる理由は」→ conntrack が往復タプルを記録し ESTABLISHED と分類するから。「RELATED とは」→ 別フローだが既存接続に紐づくもの(FTPデータ、ICMPエラー)。「NAT と conntrack の関係は」→ 変換は初回パケットで決定しエントリに記録、往復で一貫適用。「table full の症状は」→ 既存は生き新規だけ落ちる。この4点を即答できれば上級。

まとめ

ステートフルファイアウォールの核心は、判定単位をパケットからフローへ引き上げ、その状態を conntrack という表に外出しした点にあります。NEW で発信を覚え、ESTABLISHED/RELATED で戻りと関連フローを自動許可し、INVALID で不整合を弾く。NAT はこの表に変換を相乗りさせて往復の一貫性を担保します。そして表である以上、エントリ数という有限資源を持ち、それが枯渇すると新規接続だけが静かに落ちる――この性質を理解しているかどうかが、ステートフルな経路の障害切り分けを分けます。

ネットワーク Article

Conntrack:ステートフルファイアウォールの内部を実務で読む

TL;DRは入口です。実際に選ぶ・使う段階では、何を解決するか、何と比較するか、導入後にどこで詰まるかまで見る必要があります。

解決すること

conntrack

比較で見る軸

難易度: advanced / カテゴリ: ネットワーク / タグ数: 6

導入後に効く点

状態は NEW/ESTABLISHED/RELATED/INVALID の4種。RELATED は FTP データ接続や ICMP エラーなど、別フローだが既存接続に紐づくものを通す。

先に潰すリスク

用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。

数字・仕様の読み方
難易度
advanced
カテゴリ
ネットワーク
タグ数
6

判断チェックリスト

  • 自社の用途が「conntrack / ファイアウォール」に近いか確認する。
  • 強みである「ステートフルファイアウォールはパケット単位でなくフロー単位で判定する。接続追跡(conntrack)がフローの状態を表に持ち、戻りパケットを ESTABLISHED として自動許可する。」が本当に評価軸になるか確認する。
  • 注意点の「用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。」を運用で吸収できるか確認する。
  • 公開値や仕様値は、対象プラン・対象機種・対象リージョンまで確認する。
  • 既存システム、ID、ネットワーク、監視、バックアップとの接続方法を先に洗い出す。
  • 小さく試してから、本番移行、権限設計、障害時手順、コスト監視を決める。

次に確認する観点

conntrackファイアウォールNATnetfilteriptablesconntrackファイアウォールNAT
参考: 公式情報