Linux Kernel Netfilter and Firewall

Linux Kernel Netfilter と iptables/nftables 包括的技術ガイド

本ドキュメントは、Linux カーネルの Netfilter フレームワーク、コネクショントラッキング、iptables、nftables、および関連するファイアウォール技術について、アーキテクチャ、設定、チューニング、実践的なデプロイ戦略を含め、詳細に解説するものである。


目次

  1. はじめに
  2. Netfilter フレームワークアーキテクチャ
  3. フックポイントの詳細
  4. コネクショントラッキング (conntrack)
  5. iptables 詳解
  6. nftables: 次世代フレームワーク
  7. ネットワークアドレス変換 (NAT)
  8. パケットフィルタリングルールとベストプラクティス
  9. ステートフルファイアウォール設定
  10. レート制限とコネクション制限
  11. ログ機能 (LOG, NFLOG)
  12. ipset による効率的なマッチング
  13. ebtables とブリッジフィルタリング
  14. nf_tables BPF 統合
  15. Firewalld と ufw フロントエンド
  16. コネクショントラッキングチューニング
  17. 実践的ファイアウォール設定例
  18. ツールとユーティリティ
  19. トラブルシューティングとデバッグ
  20. まとめ

1. はじめに

Linux カーネルの Netfilter フレームワークは、あらゆるオペレーティングシステムの中で最も強力で柔軟なパケットフィルタリング・操作システムの一つである。ファイアウォール、ネットワークアドレス変換 (NAT)、パケットマングリング、コネクショントラッキングの基盤を Linux に提供している。本ガイドでは、Netfilter とそのユーザースペースツールである iptables および nftables について包括的かつ詳細に解説する。

1.1 歴史的背景

Linux のパケットフィルタリングは複数の世代を経て進化してきた:

世代ツールカーネルバージョン
第1世代ipfwadmLinux 2.01996
第2世代ipchainsLinux 2.21999
第3世代iptables/NetfilterLinux 2.42001
第4世代nftablesLinux 3.132014

各世代でアーキテクチャ、パフォーマンス、ユーザビリティが大幅に改善された。iptables は依然として広く使用されているが、nftables が最新技術であり、新規デプロイメントに推奨される。

1.2 Netfilter の重要性

Netfilter は以下の用途で不可欠なインフラストラクチャである:

  • ネットワークセキュリティ: 不要なトラフィックのフィルタリング、不正アクセス防止
  • NAT: プライベートネットワークからのパブリック IP アドレス共有
  • トラフィックシェーピング: QoS のためのパケットマーキングと分類
  • ロードバランシング: バックエンドサーバー間のコネクション分散
  • 監査: コンプライアンスとフォレンジックのためのログ記録
  • コンテナネットワーキング: Kubernetes、Docker 等は Netfilter に大きく依存

1.3 カーネルモジュール

# Netfilter 関連モジュール一覧
lsmod | grep -E "nf_|nft_|xt_|ip_|ipt_|ip6t_|ebt_"

# 主要モジュール:
# nf_conntrack         - コネクショントラッキングコア
# nf_nat               - NAT コア
# nf_tables            - nftables コア
# nf_defrag_ipv4       - IPv4 デフラグメンテーション
# nf_defrag_ipv6       - IPv6 デフラグメンテーション
# ip_tables            - iptables コア
# ip6_tables           - ip6tables コア
# iptable_filter       - filter テーブル
# iptable_nat          - nat テーブル
# iptable_mangle       - mangle テーブル
# iptable_raw          - raw テーブル

2. Netfilter フレームワークアーキテクチャ

2.1 全体アーキテクチャ

Netfilter は Linux カーネルのネットワークスタック内のフックとして実装されている。これらのフックにより、カーネルモジュールはパケットがネットワークスタックの特定のポイントを通過する際に呼び出されるコールバック関数を登録できる。

                                 ユーザースペース
                              +------------------+
                              |  アプリケーション  |
                              |  (ソケット)       |
                              +--------+---------+
                                       |
=======================================|============================
                                       |      カーネルスペース
                              +--------v---------+
                              |  ローカルプロセス   |
                              |  への配送          |
                              +--------+---------+
                                       |
           +-----------+      +--------v---------+      +-----------+
           |           |      |                  |      |           |
受信     ->| PREROUTING|----->| ルーティング判断  |----->| INPUT     |--> ローカル
パケット   | フック     |      |                  |      | フック     |   プロセス
           +-----------+      +--------+---------+      +-----------+
                                       |
                                       | (転送パケット)
                                       |
                              +--------v---------+
                              |  FORWARD フック   |
                              +--------+---------+
                                       |
           +-----------+      +--------v---------+
           |           |      |                  |
ローカル ->| OUTPUT    |----->| ルーティング判断  |---+
プロセス   | フック     |      |                  |   |
           +-----------+      +------------------+   |
                                                     |
                              +------------------+   |
                              |                  |<--+
                         <----| POSTROUTING      |
           送信               | フック            |
           パケット            +------------------+

2.2 フックシステム

/* Netfilter フック定義 */
enum nf_inet_hooks {
    NF_INET_PRE_ROUTING   = 0,  /* パケット受信直後 */
    NF_INET_LOCAL_IN      = 1,  /* ローカル配送前 */
    NF_INET_FORWARD       = 2,  /* 転送パケット */
    NF_INET_LOCAL_OUT     = 3,  /* ローカル生成パケット */
    NF_INET_POST_ROUTING  = 4,  /* パケット送信直前 */
    NF_INET_NUMHOOKS      = 5
};

/* フック関数の戻り値 */
#define NF_DROP   0   /* パケットを破棄 */
#define NF_ACCEPT 1   /* パケットを受け入れ */
#define NF_STOLEN 2   /* フック関数がパケットを消費 */
#define NF_QUEUE  3   /* ユーザースペースにキュー */
#define NF_REPEAT 4   /* このフック関数を再度呼び出し */
#define NF_STOP   5   /* フック走査を停止 */

2.3 フック登録の例

#include <linux/module.h>
#include <linux/netfilter.h>
#include <linux/netfilter_ipv4.h>
#include <linux/ip.h>

static unsigned int my_hook_fn(void *priv,
                                struct sk_buff *skb,
                                const struct nf_hook_state *state)
{
    struct iphdr *iph;

    if (!skb)
        return NF_ACCEPT;

    iph = ip_hdr(skb);

    /* 10.0.0.1 からのパケットを破棄 */
    if (iph->saddr == htonl(0x0A000001)) {
        printk(KERN_INFO "netfilter: 10.0.0.1 からのパケットを破棄\n");
        return NF_DROP;
    }

    return NF_ACCEPT;
}

static struct nf_hook_ops my_nf_ops = {
    .hook     = my_hook_fn,
    .pf       = NFPROTO_IPV4,
    .hooknum  = NF_INET_PRE_ROUTING,
    .priority = NF_IP_PRI_FIRST,
};

static int __init my_module_init(void)
{
    return nf_register_net_hook(&init_net, &my_nf_ops);
}

static void __exit my_module_exit(void)
{
    nf_unregister_net_hook(&init_net, &my_nf_ops);
}

module_init(my_module_init);
module_exit(my_module_exit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Netfilter フックの例");

2.4 優先度システム

enum nf_ip_hook_priorities {
    NF_IP_PRI_FIRST              = INT_MIN,
    NF_IP_PRI_RAW_BEFORE_DEFRAG = -450,
    NF_IP_PRI_CONNTRACK_DEFRAG  = -400,
    NF_IP_PRI_RAW               = -300,   /* raw テーブル */
    NF_IP_PRI_SELINUX_FIRST     = -225,
    NF_IP_PRI_CONNTRACK         = -200,   /* コネクショントラッキング */
    NF_IP_PRI_MANGLE            = -150,   /* mangle テーブル */
    NF_IP_PRI_NAT_DST           = -100,   /* DNAT */
    NF_IP_PRI_FILTER            = 0,      /* filter テーブル */
    NF_IP_PRI_SECURITY          = 50,     /* security テーブル */
    NF_IP_PRI_NAT_SRC           = 100,    /* SNAT */
    NF_IP_PRI_CONNTRACK_HELPER  = 300,
    NF_IP_PRI_CONNTRACK_CONFIRM = INT_MAX,
};

各フックポイントでのテーブル評価順序:

PREROUTING:  raw(-300) -> conntrack(-200) -> mangle(-150) -> nat/DNAT(-100)
INPUT:       mangle(-150) -> filter(0) -> security(50) -> nat(100)
FORWARD:     mangle(-150) -> filter(0) -> security(50)
OUTPUT:      raw(-300) -> conntrack(-200) -> mangle(-150) -> nat(-100) -> filter(0) -> security(50)
POSTROUTING: mangle(-150) -> nat/SNAT(100)

2.5 sk_buff 構造体

/* sk_buff (ソケットバッファ) - パケットを表現する基本データ構造 */
struct sk_buff {
    struct sk_buff      *next;
    struct sk_buff      *prev;
    ktime_t             tstamp;          /* タイムスタンプ */
    struct net_device   *dev;            /* ネットワークデバイス */
    unsigned char       *head;           /* バッファ先頭 */
    unsigned char       *data;           /* データ先頭 */
    unsigned char       *tail;           /* データ末尾 */
    unsigned char       *end;            /* バッファ末尾 */
    unsigned int        len;             /* データ長 */
    struct nf_conntrack *nfct;           /* conntrack エントリ */
    __u32               mark;            /* パケットマーク */
    __u32               priority;        /* QoS 優先度 */
    __u16               protocol;        /* L3 プロトコル */
};

3. フックポイントの詳細

3.1 PREROUTING

ルーティング判断前に受信パケットが最初に処理されるフック。

# DNAT: ポート 8080 を内部サーバーに転送
iptables -t nat -A PREROUTING -p tcp --dport 8080 \
  -j DNAT --to-destination 192.168.1.100:80

# ポリシールーティング用にマーク
iptables -t mangle -A PREROUTING -s 10.0.1.0/24 -j MARK --set-mark 1

# 高スループットトラフィックのコネクショントラッキングをスキップ
iptables -t raw -A PREROUTING -p udp --dport 53 -j NOTRACK

3.2 INPUT

ローカルマシン宛のパケットを処理する。

# 確立済み・関連コネクションを許可
iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

# 管理ネットワークからの SSH を許可
iptables -A INPUT -p tcp --dport 22 -s 10.0.0.0/8 -j ACCEPT

# HTTP/HTTPS を許可
iptables -A INPUT -p tcp -m multiport --dports 80,443 -j ACCEPT

# ICMP を許可
iptables -A INPUT -p icmp --icmp-type echo-request -j ACCEPT

# ループバックを許可
iptables -A INPUT -i lo -j ACCEPT

# その他を拒否
iptables -A INPUT -j DROP

3.3 FORWARD

マシンを経由して転送されるパケットを処理する (ip_forward=1 が必要)。

# IP フォワーディングを有効化
sysctl -w net.ipv4.ip_forward=1

# 内部から外部への転送を許可
iptables -A FORWARD -i eth1 -o eth0 -j ACCEPT

# 確立済みの戻りトラフィックを許可
iptables -A FORWARD -i eth0 -o eth1 \
  -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

# デフォルトで転送を拒否
iptables -P FORWARD DROP

3.4 OUTPUT

ローカルプロセスが生成したパケットを処理する。

# DNS の送信を許可
iptables -A OUTPUT -p udp --dport 53 -j ACCEPT
iptables -A OUTPUT -p tcp --dport 53 -j ACCEPT

# HTTP/HTTPS の送信を許可
iptables -A OUTPUT -p tcp -m multiport --dports 80,443 -j ACCEPT

# 確立済みコネクションを許可
iptables -A OUTPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

# ループバックを許可
iptables -A OUTPUT -o lo -j ACCEPT

# その他を拒否
iptables -A OUTPUT -j DROP

3.5 POSTROUTING

パケットがネットワークインターフェースを離れる前の最後のフック。

# 静的 IP での SNAT
iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -o eth0 \
  -j SNAT --to-source 203.0.113.1

# 動的 IP での MASQUERADE
iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -o eth0 -j MASQUERADE

3.6 パケットフロー全体像

=== ローカルプロセス宛の受信パケット ===
NIC -> PREROUTING(raw->conntrack->mangle->nat) -> ルーティング(ローカル)
    -> INPUT(mangle->filter->security->nat) -> ローカルプロセス

=== 転送パケット ===
NIC -> PREROUTING(raw->conntrack->mangle->nat) -> ルーティング(転送)
    -> FORWARD(mangle->filter->security) -> POSTROUTING(mangle->nat) -> NIC

=== ローカル生成パケット ===
プロセス -> OUTPUT(raw->conntrack->mangle->nat->filter->security)
    -> ルーティング -> POSTROUTING(mangle->nat) -> NIC

4. コネクショントラッキング (conntrack)

4.1 コネクショントラッキングの仕組み

conntrack システムはファイアウォールを通過するすべてのコネクションの状態を追跡する:

         新しいパケット到着
               |
               v
    +------------------------+
    | conntrack ハッシュテーブル |
    | で検索                   |
    +----------+-------------+
               |
        +------+------+
        |             |
    見つかった     見つからない
        |             |
        v             v
  エントリ更新    新規エントリ作成
  (タイムスタンプ、 state=NEW で
   カウンタ)

4.2 コネクション状態

状態説明
NEWコネクションの最初のパケット (TCP では SYN)
ESTABLISHED双方向のトラフィックが確認された
RELATED既存コネクションに関連する新規コネクション (FTP データ、ICMP エラー)
INVALID既知のコネクションに属さず、有効でないパケット
UNTRACKEDトラッキングから明示的に除外されたパケット

4.3 conntrack テーブル操作

# 追跡中のコネクション一覧
conntrack -L

# 出力例:
# tcp  6 431999 ESTABLISHED src=192.168.1.100 dst=93.184.216.34
#   sport=54321 dport=443 src=93.184.216.34 dst=203.0.113.1
#   sport=443 dport=54321 [ASSURED] mark=0 use=1

# コネクション数
conntrack -C

# プロトコルと状態でフィルタ
conntrack -L -p tcp --state ESTABLISHED
conntrack -L -p tcp --state TIME_WAIT

# 特定のコネクションを削除
conntrack -D -s 192.168.1.100 -d 93.184.216.34 -p tcp --dport 443

# 全エントリをフラッシュ
conntrack -F

# リアルタイムイベント監視
conntrack -E
#     [NEW] tcp  6 120 SYN_SENT src=192.168.1.100 dst=10.0.0.1 ...
#  [UPDATE] tcp  6 432000 ESTABLISHED src=192.168.1.100 dst=10.0.0.1 ...
# [DESTROY] tcp  6 src=192.168.1.100 dst=10.0.0.1 ...

# CPU ごとの統計
conntrack -S

4.4 conntrack 内部構造

/* コネクショントラッキングタプル */
struct nf_conntrack_tuple {
    struct nf_conntrack_man src;  /* 送信元: IP + ポート */
    struct {
        union nf_inet_addr u3;    /* 宛先 IP */
        union {
            __be16 all;
            struct { __be16 port; } tcp;
            struct { __be16 port; } udp;
            struct { u_int8_t type, code; } icmp;
        } u;
        u_int8_t protonum;  /* プロトコル番号 */
        u_int8_t dir;        /* 方向 */
    } dst;
};

/* コネクションエントリ */
struct nf_conn {
    struct nf_conntrack_tuple_hash tuplehash[IP_CT_DIR_MAX];
    unsigned long status;     /* ステータスビット */
    u32 timeout;              /* タイムアウト値 */
    struct nf_ct_ext *ext;    /* 拡張: NAT、ヘルパー等 */
};

4.5 コネクショントラッキングヘルパー

ヘルパーは、アプリケーションデータに IP/ポート情報を埋め込むプロトコルを処理する:

# プロトコルヘルパーのロード
modprobe nf_conntrack_ftp
modprobe nf_conntrack_sip
modprobe nf_conntrack_tftp
modprobe nf_conntrack_h323

# 明示的なヘルパー割り当て (カーネル 4.7 以降推奨)
iptables -t raw -A PREROUTING -p tcp --dport 21 -j CT --helper ftp
iptables -t raw -A OUTPUT -p tcp --dport 21 -j CT --helper ftp

# 非標準ポートの FTP
modprobe nf_conntrack_ftp ports=21,2121

# ロード済みヘルパーの確認
cat /proc/net/nf_conntrack_helper

4.6 TCP 状態マシン

  クライアント        conntrack 状態          サーバー
    |---SYN-------->  SYN_SENT                |
    |<--SYN/ACK----  SYN_RECV                 |
    |---ACK-------->  ESTABLISHED             |
    |<===DATA=====>  ESTABLISHED              |
    |---FIN-------->  FIN_WAIT                |
    |<--ACK---------  CLOSE_WAIT              |
    |<--FIN---------  LAST_ACK                |
    |---ACK-------->  TIME_WAIT (120秒)       |
    |                 CLOSE (エントリ削除)      |

5. iptables 詳解

5.1 アーキテクチャ: テーブル、チェーン、ルール

+-------------------------------------------------------------------+
| raw テーブル (優先度: -300)                                        |
|   チェーン: PREROUTING, OUTPUT                                     |
|   目的: コネクショントラッキングのバイパス (NOTRACK)                 |
+-------------------------------------------------------------------+
| mangle テーブル (優先度: -150)                                     |
|   チェーン: PREROUTING, INPUT, FORWARD, OUTPUT, POSTROUTING       |
|   目的: パケットヘッダ変更 (TTL, TOS, MARK)                       |
+-------------------------------------------------------------------+
| nat テーブル (優先度: -100 DNAT / +100 SNAT)                      |
|   チェーン: PREROUTING, INPUT, OUTPUT, POSTROUTING                |
|   目的: ネットワークアドレス変換                                    |
+-------------------------------------------------------------------+
| filter テーブル (優先度: 0) -- デフォルト                           |
|   チェーン: INPUT, FORWARD, OUTPUT                                 |
|   目的: パケットフィルタリング (ACCEPT/DROP/REJECT)                |
+-------------------------------------------------------------------+
| security テーブル (優先度: 50)                                     |
|   チェーン: INPUT, FORWARD, OUTPUT                                 |
|   目的: SELinux/MAC セキュリティコンテキスト                        |
+-------------------------------------------------------------------+

5.2 filter テーブル

# ルール一覧表示
iptables -L -n -v --line-numbers

# デフォルトポリシー設定
iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT ACCEPT

# 基本的なフィルタリングルール
iptables -A INPUT -i lo -j ACCEPT
iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
iptables -A INPUT -p tcp --dport 22 -s 10.0.0.0/8 -j ACCEPT
iptables -A INPUT -p tcp -m multiport --dports 80,443 -j ACCEPT

5.3 nat テーブル

# SNAT (送信元 NAT)
iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -o eth0 \
  -j SNAT --to-source 203.0.113.1

# DNAT (宛先 NAT / ポートフォワーディング)
iptables -t nat -A PREROUTING -p tcp --dport 80 -i eth0 \
  -j DNAT --to-destination 192.168.1.10:8080

# MASQUERADE (動的 SNAT)
iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -o ppp0 -j MASQUERADE

# REDIRECT (透過プロキシ)
iptables -t nat -A PREROUTING -p tcp --dport 80 \
  -j REDIRECT --to-ports 3128

5.4 mangle テーブル

# SSH の TOS 設定
iptables -t mangle -A OUTPUT -p tcp --dport 22 \
  -j TOS --set-tos Minimize-Delay

# VoIP の DSCP 設定
iptables -t mangle -A POSTROUTING -p udp --dport 5060 \
  -j DSCP --set-dscp-class EF

# TTL 変更
iptables -t mangle -A PREROUTING -i eth0 -j TTL --ttl-set 64

# ポリシールーティング用マーキング
iptables -t mangle -A PREROUTING -s 10.0.1.0/24 -j MARK --set-mark 0x1

# PPPoE/VPN 用 MSS クランプ
iptables -t mangle -A FORWARD -p tcp --tcp-flags SYN,RST SYN \
  -j TCPMSS --clamp-mss-to-pmtu

5.5 raw テーブル

# DNS のコネクショントラッキングをスキップ
iptables -t raw -A PREROUTING -p udp --dport 53 -j NOTRACK
iptables -t raw -A OUTPUT -p udp --sport 53 -j NOTRACK

# ヘルパーの割り当て
iptables -t raw -A PREROUTING -p tcp --dport 21 -j CT --helper ftp

5.6 マッチ拡張

# TCP フラグマッチ
iptables -A INPUT -p tcp --tcp-flags ALL SYN -j ACCEPT     # SYN のみ
iptables -A INPUT -p tcp --tcp-flags ALL NONE -j DROP       # NULL スキャン
iptables -A INPUT -p tcp --tcp-flags ALL ALL -j DROP        # XMAS スキャン
iptables -A INPUT -p tcp --tcp-flags SYN,FIN SYN,FIN -j DROP

# conntrack 状態
iptables -A INPUT -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT
iptables -A INPUT -m conntrack --ctstate INVALID -j DROP

# マルチポート
iptables -A INPUT -p tcp -m multiport --dports 80,443,8080,8443 -j ACCEPT

# IP 範囲
iptables -A INPUT -m iprange --src-range 10.0.0.1-10.0.0.100 -j ACCEPT

# MAC アドレス
iptables -A INPUT -m mac --mac-source 00:11:22:33:44:55 -j ACCEPT

# 時間ベース
iptables -A INPUT -p tcp --dport 22 \
  -m time --timestart 09:00 --timestop 17:00 \
  --weekdays Mon,Tue,Wed,Thu,Fri -j ACCEPT

# 文字列マッチ
iptables -A INPUT -p tcp --dport 80 \
  -m string --algo bm --string "cmd.exe" -j DROP

# レート制限
iptables -A INPUT -p icmp --icmp-type echo-request \
  -m limit --limit 1/s --limit-burst 4 -j ACCEPT

# コネクション数制限 (送信元あたり)
iptables -A INPUT -p tcp --dport 80 \
  -m connlimit --connlimit-above 50 --connlimit-mask 32 -j DROP

# ハッシュ制限 (送信元あたりのレート制限)
iptables -A INPUT -p tcp --dport 22 \
  -m hashlimit --hashlimit-name ssh --hashlimit-above 3/min \
  --hashlimit-burst 3 --hashlimit-mode srcip -j DROP

# オーナー (OUTPUT チェーンのみ)
iptables -A OUTPUT -m owner --uid-owner 1000 -j ACCEPT

# recent モジュール (ブルートフォース防御)
iptables -A INPUT -p tcp --dport 22 -m recent --set --name SSH
iptables -A INPUT -p tcp --dport 22 -m recent --update \
  --seconds 60 --hitcount 4 --name SSH -j DROP

# コメント
iptables -A INPUT -p tcp --dport 22 -j ACCEPT \
  -m comment --comment "SSH アクセスを許可"

5.7 ターゲット拡張

# REJECT (エラー応答を返す)
iptables -A INPUT -p tcp --dport 23 -j REJECT --reject-with tcp-reset
iptables -A INPUT -p udp -j REJECT --reject-with icmp-port-unreachable

# LOG (カーネルログ)
iptables -A INPUT -j LOG --log-prefix "IPT-DROP: " --log-level 4

# NFLOG (netfilter ログ)
iptables -A INPUT -j NFLOG --nflog-group 1 --nflog-prefix "INPUT-DROP"

# MARK (パケットマーク)
iptables -t mangle -A PREROUTING -s 10.0.0.0/8 -j MARK --set-mark 1

# CONNMARK (コネクションマーク)
iptables -t mangle -A PREROUTING -j CONNMARK --restore-mark
iptables -t mangle -A POSTROUTING -j CONNMARK --save-mark

# TPROXY (透過プロキシ)
iptables -t mangle -A PREROUTING -p tcp --dport 80 \
  -j TPROXY --on-port 3128 --tproxy-mark 0x1/0x1

# NFQUEUE (ユーザースペースでの処理)
iptables -A FORWARD -j NFQUEUE --queue-num 0

5.8 ユーザー定義チェーン

# チェーン構造の整理
iptables -N TCP_SERVICES
iptables -N UDP_SERVICES
iptables -N ICMP_RULES
iptables -N SYN_FLOOD

# SYN フラッド防御
iptables -A SYN_FLOOD -m limit --limit 50/s --limit-burst 100 -j RETURN
iptables -A SYN_FLOOD -j LOG --log-prefix "SYN-FLOOD: "
iptables -A SYN_FLOOD -j DROP

# TCP サービス
iptables -A TCP_SERVICES -p tcp --dport 22 -j ACCEPT
iptables -A TCP_SERVICES -p tcp --dport 80 -j ACCEPT
iptables -A TCP_SERVICES -p tcp --dport 443 -j ACCEPT
iptables -A TCP_SERVICES -j RETURN

# UDP サービス
iptables -A UDP_SERVICES -p udp --dport 53 -j ACCEPT
iptables -A UDP_SERVICES -p udp --dport 123 -j ACCEPT
iptables -A UDP_SERVICES -j RETURN

# ICMP ルール
iptables -A ICMP_RULES -p icmp --icmp-type echo-request \
  -m limit --limit 5/s -j ACCEPT
iptables -A ICMP_RULES -p icmp --icmp-type destination-unreachable -j ACCEPT
iptables -A ICMP_RULES -p icmp --icmp-type time-exceeded -j ACCEPT
iptables -A ICMP_RULES -j DROP

# INPUT チェーンに接続
iptables -A INPUT -i lo -j ACCEPT
iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
iptables -A INPUT -m conntrack --ctstate INVALID -j DROP
iptables -A INPUT -p tcp --syn -j SYN_FLOOD
iptables -A INPUT -p tcp -m conntrack --ctstate NEW -j TCP_SERVICES
iptables -A INPUT -p udp -m conntrack --ctstate NEW -j UDP_SERVICES
iptables -A INPUT -p icmp -j ICMP_RULES
iptables -A INPUT -j LOG --log-prefix "INPUT-DROP: "
iptables -A INPUT -j DROP

5.9 IPv6 (ip6tables)

ip6tables -A INPUT -i lo -j ACCEPT
ip6tables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

# ICMPv6 は IPv6 の動作に不可欠 -- すべてブロックしてはいけない
ip6tables -A INPUT -p ipv6-icmp --icmpv6-type echo-request -j ACCEPT
ip6tables -A INPUT -p ipv6-icmp --icmpv6-type echo-reply -j ACCEPT
ip6tables -A INPUT -p ipv6-icmp --icmpv6-type router-solicitation -j ACCEPT
ip6tables -A INPUT -p ipv6-icmp --icmpv6-type router-advertisement -j ACCEPT
ip6tables -A INPUT -p ipv6-icmp --icmpv6-type neighbour-solicitation -j ACCEPT
ip6tables -A INPUT -p ipv6-icmp --icmpv6-type neighbour-advertisement -j ACCEPT

ip6tables -A INPUT -p tcp -m multiport --dports 22,80,443 -j ACCEPT
ip6tables -P INPUT DROP
ip6tables -P FORWARD DROP
ip6tables -P OUTPUT ACCEPT

6. nftables: 次世代フレームワーク

6.1 なぜ nftables なのか

nftables は iptables、ip6tables、arptables、ebtables を単一の統一フレームワークで置き換える:

機能iptablesnftables
IPv4/IPv6 の処理別々のツール統一 (inet ファミリー)
構文固定的なマッチ/ターゲット柔軟な式
アトミックなルール更新不可 (ルール単位)可能 (トランザクション)
マッチごとのカーネルモジュール必要不要 (組み込み VM)
パフォーマンス線形ルール評価セット、マップ、連結
ルールセット一覧複数コマンドnft list ruleset のみ
カーネル内 VMなしあり (nf_tables VM)
インクリメンタル更新不可可能

6.2 nftables アーキテクチャ

ユーザースペース:  nft コマンド  <-->  libnftnl  <-->  nfnetlink (netlink)
                                                           |
カーネル:                                             nf_tables
                                                     (バイトコード VM)
                                                           |
                                                     Netfilter フック

nftables はカーネル内の仮想マシンで、ユーザールールからコンパイルされたバイトコードを実行する。

6.3 基本的な nftables 構文

# テーブル作成 (ファミリー: ip, ip6, inet, arp, bridge, netdev)
nft add table inet filter

# チェーン作成 (ベースチェーン: フックと優先度を指定)
nft add chain inet filter input \
  '{ type filter hook input priority 0; policy drop; }'
nft add chain inet filter forward \
  '{ type filter hook forward priority 0; policy drop; }'
nft add chain inet filter output \
  '{ type filter hook output priority 0; policy accept; }'

# ルール追加
nft add rule inet filter input iif lo accept
nft add rule inet filter input ct state established,related accept
nft add rule inet filter input ct state invalid drop
nft add rule inet filter input tcp dport 22 accept
nft add rule inet filter input tcp dport { 80, 443 } accept
nft add rule inet filter input ip protocol icmp accept
nft add rule inet filter input ip6 nexthdr icmpv6 accept

# ルールセット全体を表示
nft list ruleset

# 特定テーブルを表示
nft list table inet filter

# ルールセットをフラッシュ
nft flush ruleset

# 特定ルールを削除 (ハンドルで指定)
nft -a list chain inet filter input   # ハンドル番号を確認
nft delete rule inet filter input handle 42

6.4 nftables 設定ファイル

#!/usr/sbin/nft -f
# /etc/nftables.conf

flush ruleset

table inet filter {
    chain input {
        type filter hook input priority 0; policy drop;

        # ループバック
        iif lo accept

        # コネクショントラッキング
        ct state established,related accept
        ct state invalid drop

        # ICMP / ICMPv6
        ip protocol icmp icmp type {
            echo-request, echo-reply,
            destination-unreachable, time-exceeded
        } accept

        ip6 nexthdr icmpv6 icmpv6 type {
            echo-request, echo-reply,
            nd-router-solicit, nd-router-advert,
            nd-neighbor-solicit, nd-neighbor-advert
        } accept

        # SSH
        tcp dport 22 accept

        # HTTP/HTTPS
        tcp dport { 80, 443 } accept

        # ログと破棄
        counter log prefix "INPUT-DROP: " drop
    }

    chain forward {
        type filter hook forward priority 0; policy drop;
        ct state established,related accept
        ct state invalid drop
    }

    chain output {
        type filter hook output priority 0; policy accept;
    }
}

table inet nat {
    chain prerouting {
        type nat hook prerouting priority -100;
    }

    chain postrouting {
        type nat hook postrouting priority 100;
        oifname "eth0" masquerade
    }
}

6.5 セットとマップ

nftables の最も強力な機能の一つ:

# 名前付きセット
nft add set inet filter allowed_ips '{ type ipv4_addr; }'
nft add element inet filter allowed_ips '{ 10.0.0.1, 10.0.0.2, 10.0.0.3 }'
nft add rule inet filter input ip saddr @allowed_ips accept

# 匿名セット (インライン)
nft add rule inet filter input tcp dport { 22, 80, 443, 8080 } accept

# インターバルセット (CIDR 範囲)
nft add set inet filter internal_nets '{ type ipv4_addr; flags interval; }'
nft add element inet filter internal_nets \
  '{ 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16 }'
nft add rule inet filter input ip saddr @internal_nets accept

# 連結セット (多次元マッチング)
nft add set inet filter allowed_services \
  '{ type ipv4_addr . inet_proto . inet_service; }'
nft add element inet filter allowed_services \
  '{ 10.0.0.1 . tcp . 22, 10.0.0.2 . tcp . 80 }'
nft add rule inet filter input ip saddr . ip protocol . tcp dport \
  @allowed_services accept

# マップ (判定マップ)
nft add map inet filter port_policy \
  '{ type inet_service : verdict; }'
nft add element inet filter port_policy \
  '{ 22 : accept, 80 : accept, 443 : accept, 23 : drop }'
nft add rule inet filter input tcp dport vmap @port_policy

# 動的セット (ルールにより自動的に追加)
nft add set inet filter blocked_hosts \
  '{ type ipv4_addr; flags dynamic, timeout; timeout 1h; size 65536; }'
nft add rule inet filter input tcp dport 22 \
  meter ssh_meter '{ ip saddr limit rate 3/minute burst 5 packets }' accept
nft add rule inet filter input tcp dport 22 \
  add @blocked_hosts '{ ip saddr timeout 1h }' drop

6.6 カウンターとクォータ

# 名前付きカウンター
nft add counter inet filter http_counter
nft add rule inet filter input tcp dport 80 counter name http_counter accept

# インラインカウンター
nft add rule inet filter input tcp dport 443 counter accept

# クォータ
nft add quota inet filter web_quota '{ over 1 gbytes }'
nft add rule inet filter input tcp dport 80 quota name web_quota drop

6.7 nftables による NAT

table inet nat {
    chain prerouting {
        type nat hook prerouting priority dstnat;

        # DNAT / ポートフォワーディング
        tcp dport 8080 dnat to 192.168.1.100:80
        tcp dport 8443 dnat to 192.168.1.100:443

        # マップを使用したロードバランシング
        tcp dport 80 dnat to numgen inc mod 3 map {
            0 : 192.168.1.10,
            1 : 192.168.1.11,
            2 : 192.168.1.12
        }
    }

    chain postrouting {
        type nat hook postrouting priority srcnat;

        # SNAT
        ip saddr 192.168.1.0/24 oifname "eth0" snat to 203.0.113.1

        # マスカレード
        oifname "eth0" masquerade
    }
}

6.8 iptables から nftables への移行

# iptables ルールを nftables 形式に変換
iptables-save > /tmp/iptables-rules.txt
iptables-restore-translate -f /tmp/iptables-rules.txt > /etc/nftables.conf

# 個別ルールの変換
iptables-translate -A INPUT -p tcp --dport 22 -j ACCEPT
# 出力: nft add rule ip filter INPUT tcp dport 22 counter accept

# バックエンドの確認
iptables -V
# iptables v1.8.7 (nf_tables)  <-- nftables バックエンド
# iptables v1.8.7 (legacy)     <-- レガシーバックエンド

7. ネットワークアドレス変換 (NAT)

7.1 NAT の種類

+------------------------------------------------------------------+
|  SNAT (送信元 NAT)                                                |
|  - 送信パケットの送信元 IP/ポートを変更                             |
|  - POSTROUTING で適用                                             |
|  - 用途: プライベートネットワークからのインターネットアクセス         |
+------------------------------------------------------------------+
|  DNAT (宛先 NAT)                                                  |
|  - 受信パケットの宛先 IP/ポートを変更                               |
|  - PREROUTING で適用                                              |
|  - 用途: ポートフォワーディング、ロードバランシング                   |
+------------------------------------------------------------------+
|  MASQUERADE                                                       |
|  - インターフェースの現在の IP を使用する動的 SNAT                   |
|  - POSTROUTING で適用                                             |
|  - 用途: 動的 IP (DHCP, PPPoE)                                   |
+------------------------------------------------------------------+
|  REDIRECT                                                         |
|  - ローカルマシンのポートにリダイレクト                              |
|  - 用途: 透過プロキシ                                              |
+------------------------------------------------------------------+

7.2 SNAT 設定

# iptables SNAT
iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -o eth0 \
  -j SNAT --to-source 203.0.113.1

# ポート範囲付き SNAT
iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -o eth0 \
  -j SNAT --to-source 203.0.113.1:1024-65535

# nftables SNAT
nft add rule inet nat postrouting ip saddr 192.168.1.0/24 \
  oifname "eth0" snat to 203.0.113.1

7.3 DNAT 設定

# ポートフォワーディング
iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 80 \
  -j DNAT --to-destination 192.168.1.10:8080

# 転送も許可する必要がある
iptables -A FORWARD -i eth0 -o eth1 -p tcp --dport 8080 \
  -d 192.168.1.10 -m conntrack --ctstate NEW -j ACCEPT
iptables -A FORWARD -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

# nftables DNAT
nft add rule inet nat prerouting iifname "eth0" tcp dport 80 \
  dnat to 192.168.1.10:8080

# ロードバランシング DNAT
nft add rule inet nat prerouting tcp dport 80 \
  dnat to numgen inc mod 3 map \
  '{ 0 : 192.168.1.10, 1 : 192.168.1.11, 2 : 192.168.1.12 }'

7.4 MASQUERADE

# MASQUERADE (送信インターフェースの IP を使用)
iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -o eth0 -j MASQUERADE

# nftables
nft add rule inet nat postrouting oifname "eth0" masquerade

7.5 ヘアピン NAT (NAT リフレクション)

LAN 内からパブリック IP で内部サーバーにアクセスする:

# 標準 DNAT (既に設定済み)
iptables -t nat -A PREROUTING -d 203.0.113.1 -p tcp --dport 80 \
  -j DNAT --to-destination 192.168.1.10:80

# ヘアピン SNAT: 内部ネットワークから DNAT 経由で
# 内部サーバーに行くトラフィックの送信元をマスカレード
iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -d 192.168.1.10 \
  -p tcp --dport 80 -j MASQUERADE

8. パケットフィルタリングルールとベストプラクティス

8.1 ルール順序の原則

  1. 具体的なルールを先に: 広範なルールより狭いマッチを先に配置
  2. 頻度の高いマッチを早く: 平均評価時間を短縮
  3. ステートフルルールを最初に: ESTABLISHED,RELATED はほとんどのトラフィックにマッチ
  4. INVALID を早期に破棄: 不正パケットを早期に除去
  5. デフォルト拒否: ポリシーを DROP に設定し、必要なトラフィックのみ明示的に許可

8.2 多層防御戦略

#!/bin/bash
# defense-in-depth.sh - 多層防御ファイアウォール

# ルールリセット
iptables -F
iptables -X
iptables -t nat -F
iptables -t mangle -F

# デフォルトポリシー
iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT DROP

# === 第1層: アンチスプーフィング ===
iptables -A INPUT -i eth0 -s 127.0.0.0/8 -j DROP
iptables -A INPUT -i eth0 -s 10.0.0.0/8 -j DROP      # eth0 が WAN の場合
iptables -A INPUT -i eth0 -s 172.16.0.0/12 -j DROP
iptables -A INPUT -i eth0 -s 192.168.0.0/16 -j DROP
iptables -A INPUT -i eth0 -s 0.0.0.0/8 -j DROP
iptables -A INPUT -i eth0 -s 224.0.0.0/4 -j DROP

# === 第2層: 不正パケットフィルタリング ===
iptables -A INPUT -m conntrack --ctstate INVALID -j DROP
iptables -A INPUT -p tcp --tcp-flags ALL NONE -j DROP     # NULL スキャン
iptables -A INPUT -p tcp --tcp-flags ALL ALL -j DROP      # XMAS スキャン
iptables -A INPUT -p tcp --tcp-flags SYN,FIN SYN,FIN -j DROP
iptables -A INPUT -p tcp --tcp-flags SYN,RST SYN,RST -j DROP
iptables -A INPUT -f -j DROP                               # フラグメント

# === 第3層: レート制限 ===
iptables -A INPUT -p tcp --syn -m limit --limit 25/s \
  --limit-burst 50 -j ACCEPT
iptables -A INPUT -p icmp --icmp-type echo-request \
  -m limit --limit 2/s --limit-burst 5 -j ACCEPT

# === 第4層: ステートフル検査 ===
iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
iptables -A INPUT -i lo -j ACCEPT

# === 第5層: サービス固有ルール ===
iptables -A INPUT -p tcp --dport 22 -s 10.0.0.0/8 -j ACCEPT
iptables -A INPUT -p tcp -m multiport --dports 80,443 -j ACCEPT

# === 第6層: ログと最終破棄 ===
iptables -A INPUT -j LOG --log-prefix "INPUT-DROP: " \
  --log-level 4 -m limit --limit 5/min
iptables -A INPUT -j DROP

# === OUTPUT ルール ===
iptables -A OUTPUT -o lo -j ACCEPT
iptables -A OUTPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
iptables -A OUTPUT -p udp --dport 53 -j ACCEPT
iptables -A OUTPUT -p tcp -m multiport --dports 80,443 -j ACCEPT
iptables -A OUTPUT -p tcp --dport 22 -j ACCEPT
iptables -A OUTPUT -p icmp -j ACCEPT
iptables -A OUTPUT -j LOG --log-prefix "OUTPUT-DROP: " --log-level 4
iptables -A OUTPUT -j DROP

9. ステートフルファイアウォール設定

9.1 ステートフル vs ステートレス

ステートレス: 各パケットを独立に評価
  - パケットヘッダ (送信元/宛先 IP、ポート、フラグ) のみ参照
  - 新規トラフィックと戻りトラフィックを区別できない
  - 応答ポートを明示的に開放する必要がある

ステートフル: コネクション状態を追跡
  - コネクションテーブル (conntrack) を維持
  - 戻りトラフィックを自動的に許可
  - 不正パケットを検出可能
  - 複雑なプロトコル (FTP, SIP) を処理可能

9.2 完全なステートフルファイアウォール

#!/bin/bash
# stateful-firewall.sh

# リセット
iptables -F
iptables -X
iptables -t nat -F
iptables -t mangle -F

# デフォルトポリシー
iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT ACCEPT

# ループバック
iptables -A INPUT -i lo -j ACCEPT
iptables -A OUTPUT -o lo -j ACCEPT

# コネクショントラッキング (ステートフルフィルタリングの核)
iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
iptables -A FORWARD -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

# INVALID を破棄
iptables -A INPUT -m conntrack --ctstate INVALID -j DROP
iptables -A FORWARD -m conntrack --ctstate INVALID -j DROP

# 許可するサービスへの新規コネクション
iptables -A INPUT -p tcp --dport 22 -m conntrack --ctstate NEW -j ACCEPT
iptables -A INPUT -p tcp --dport 80 -m conntrack --ctstate NEW -j ACCEPT
iptables -A INPUT -p tcp --dport 443 -m conntrack --ctstate NEW -j ACCEPT

# ICMP
iptables -A INPUT -p icmp --icmp-type echo-request \
  -m conntrack --ctstate NEW -j ACCEPT

9.3 FTP のコネクショントラッキング

# FTP は制御 (21) とデータ接続を分離する
modprobe nf_conntrack_ftp

# ヘルパーの割り当て
iptables -t raw -A PREROUTING -p tcp --dport 21 -j CT --helper ftp

# FTP 制御コネクションを許可
iptables -A INPUT -p tcp --dport 21 -m conntrack --ctstate NEW -j ACCEPT

# RELATED コネクション (FTP データ) は
# -m conntrack --ctstate ESTABLISHED,RELATED のルールでカバー済み
# ヘルパーがデータコネクションを制御コネクションの RELATED としてマーク

9.4 コネクションライフタイムの追跡

# デフォルトタイムアウト確認
sysctl -a | grep "net.netfilter.nf_conntrack_tcp_timeout"
# net.netfilter.nf_conntrack_tcp_timeout_established = 432000 (5日)
# net.netfilter.nf_conntrack_tcp_timeout_syn_sent = 120
# net.netfilter.nf_conntrack_tcp_timeout_syn_recv = 60
# net.netfilter.nf_conntrack_tcp_timeout_fin_wait = 120
# net.netfilter.nf_conntrack_tcp_timeout_time_wait = 120
# net.netfilter.nf_conntrack_tcp_timeout_close = 10

# UDP タイムアウト
# net.netfilter.nf_conntrack_udp_timeout = 30
# net.netfilter.nf_conntrack_udp_timeout_stream = 120

10. レート制限とコネクション制限

10.1 limit マッチ

# 基本的なレート制限
# トークンバケット: 補充レート = 3/分、バケットサイズ = 5
iptables -A INPUT -p icmp --icmp-type echo-request \
  -m limit --limit 3/min --limit-burst 5 -j ACCEPT
iptables -A INPUT -p icmp --icmp-type echo-request -j DROP

# ログのレート制限 (ログ溢れ防止)
iptables -A INPUT -j LOG --log-prefix "DROP: " \
  -m limit --limit 5/min --limit-burst 10
iptables -A INPUT -j DROP

# SYN フラッド防御
iptables -A INPUT -p tcp --syn -m limit --limit 25/s --limit-burst 50 -j ACCEPT
iptables -A INPUT -p tcp --syn -j DROP

10.2 hashlimit マッチ

送信元ごとのレート制限 (グローバルな limit よりはるかに有用):

# 送信元ごとの SSH レート制限
iptables -A INPUT -p tcp --dport 22 \
  -m hashlimit \
  --hashlimit-name ssh_limit \
  --hashlimit-above 3/min \
  --hashlimit-burst 3 \
  --hashlimit-mode srcip \
  --hashlimit-htable-expire 60000 \
  -j DROP

# 送信元ごとの HTTP コネクションレート
iptables -A INPUT -p tcp --dport 80 \
  -m hashlimit \
  --hashlimit-name http_rate \
  --hashlimit-above 50/sec \
  --hashlimit-burst 100 \
  --hashlimit-mode srcip \
  -j DROP

# hashlimit 状態の確認
cat /proc/net/ipt_hashlimit/ssh_limit

10.3 connlimit マッチ

送信元ごとの同時コネクション数を制限:

# 送信元 IP あたり最大 50 HTTP コネクション
iptables -A INPUT -p tcp --dport 80 \
  -m connlimit --connlimit-above 50 --connlimit-mask 32 -j REJECT

# 送信元 IP あたり最大 3 SSH コネクション
iptables -A INPUT -p tcp --dport 22 \
  -m connlimit --connlimit-above 3 --connlimit-mask 32 -j DROP

# /24 サブネットあたり最大 200 コネクション
iptables -A INPUT -p tcp --dport 443 \
  -m connlimit --connlimit-above 200 --connlimit-mask 24 -j DROP

10.4 nftables でのレート制限

# 送信元ごとのレート制限 (メーター使用)
nft add rule inet filter input tcp dport 22 \
  meter ssh_meter '{ ip saddr limit rate 3/minute burst 5 packets }' accept

# 送信元ごとのバイトレート制限
nft add rule inet filter input ip saddr != 127.0.0.1 \
  meter bandwidth '{ ip saddr limit rate over 10 mbytes/second }' drop

# コネクション数制限
nft add rule inet filter input tcp dport 80 \
  meter http_conn '{ ip saddr ct count over 50 }' reject

10.5 レート制限とコネクション制限の組み合わせ

# 包括的な DDoS 緩和
iptables -N RATE_LIMIT

# SYN レート制限
iptables -A RATE_LIMIT -p tcp --syn \
  -m hashlimit --hashlimit-name syn_rate \
  --hashlimit-above 30/sec --hashlimit-burst 50 \
  --hashlimit-mode srcip -j DROP

# コネクション制限
iptables -A RATE_LIMIT -p tcp \
  -m connlimit --connlimit-above 100 --connlimit-mask 32 -j DROP

# 全体パケットレート
iptables -A RATE_LIMIT -m hashlimit \
  --hashlimit-name pkt_rate \
  --hashlimit-above 200/sec --hashlimit-burst 500 \
  --hashlimit-mode srcip -j DROP

iptables -A RATE_LIMIT -j RETURN

# INPUT に適用
iptables -A INPUT -j RATE_LIMIT

11. ログ機能 (LOG, NFLOG)

11.1 LOG ターゲット

LOG はパケット情報をカーネルログ (dmesg/syslog) に送信する:

# 基本的なログ
iptables -A INPUT -j LOG --log-prefix "IPT-INPUT: " --log-level 4

# ログレベル (syslog 重要度):
# 0 = emerg, 1 = alert, 2 = crit, 3 = err
# 4 = warning, 5 = notice, 6 = info, 7 = debug

# 詳細情報付きログ
iptables -A INPUT -j LOG \
  --log-prefix "DROP: " \
  --log-level 4 \
  --log-tcp-sequence \
  --log-tcp-options \
  --log-ip-options \
  --log-uid

# レート制限付きログ (ログ溢れ防止)
iptables -A INPUT -m limit --limit 5/min --limit-burst 10 \
  -j LOG --log-prefix "INPUT-DROP: "
iptables -A INPUT -j DROP

# カーネルログ出力例:
# IPT-INPUT: IN=eth0 OUT= MAC=00:11:22:33:44:55:66:77:88:99:aa:bb:08:00
# SRC=10.0.0.1 DST=192.168.1.1 LEN=60 TOS=0x00 PREC=0x00 TTL=64
# ID=12345 DF PROTO=TCP SPT=54321 DPT=22 WINDOW=29200 RES=0x00 SYN URGP=0

11.2 ログを別ファイルに転送

# /etc/rsyslog.d/iptables.conf
:msg, startswith, "IPT-" /var/log/iptables.log
& stop

:msg, startswith, "DROP:" /var/log/iptables.log
& stop

# rsyslog 再起動
systemctl restart rsyslog

# logrotate 設定
# /etc/logrotate.d/iptables
/var/log/iptables.log {
    daily
    rotate 30
    compress
    delaycompress
    missingok
    notifempty
    create 0640 root adm
}

11.3 NFLOG ターゲット

NFLOG は netlink マルチキャストグループを使用した柔軟なログを提供する:

# NFLOG グループ 1 に送信
iptables -A INPUT -j NFLOG \
  --nflog-group 1 \
  --nflog-prefix "INPUT" \
  --nflog-threshold 10 \
  --nflog-range 128

# グループ番号で異なるログストリームを分離
iptables -A INPUT -j NFLOG --nflog-group 1 --nflog-prefix "INPUT"
iptables -A FORWARD -j NFLOG --nflog-group 2 --nflog-prefix "FORWARD"
iptables -A OUTPUT -j NFLOG --nflog-group 3 --nflog-prefix "OUTPUT"

11.4 ulogd2 (ユーザースペースログデーモン)

# ulogd2 インストール
apt install ulogd2    # Debian/Ubuntu
yum install ulogd     # RHEL/CentOS

# /etc/ulogd.conf 設定例
[global]
logfile="/var/log/ulogd/ulogd.log"
stack=log1:NFLOG,base1:BASE,ifi1:IFINDEX,ip2str1:IP2STR,print1:PRINTPKT,emu1:LOGEMU
stack=log2:NFLOG,base1:BASE,ifi1:IFINDEX,ip2str1:IP2STR,json1:JSON,file1:JSON_FILE

[log1]
group=1

[log2]
group=2

[emu1]
file="/var/log/ulogd/syslogemu.log"
sync=1

[file1]
file="/var/log/ulogd/ulogd.json"
sync=1

# ulogd 起動
systemctl enable --now ulogd

11.5 nftables でのログ

# nftables ログ
nft add rule inet filter input counter log prefix \"INPUT-DROP: \" level warn drop

# レート制限付きログ
nft add rule inet filter input limit rate 5/minute log prefix \"RATE-LIMITED: \" drop

# NFLOG
nft add rule inet filter input log group 1 prefix \"INPUT\" accept

12. ipset による効率的なマッチング

12.1 ipset の概要

ipset は、大量の IP アドレス、ネットワーク、ポートの組み合わせに対する効率的なマッチングのために、カーネルメモリ内にデータ構造を作成する:

# パフォーマンス比較:
# 10,000 個の個別 iptables ルール: O(n) 線形走査
# 10,000 エントリの ipset: O(1) ハッシュ検索

12.2 ipset タイプ

タイプ説明
hash:ipIP アドレスのセット
hash:netCIDR ネットワークのセット
hash:ip,portIP+ポートの組み合わせ
hash:net,portネットワーク+ポートの組み合わせ
hash:ip,port,ipIP+ポート+IP タプル
hash:macMAC アドレスのセット
bitmap:ipIP アドレス範囲のビットマップ
bitmap:portポート番号のビットマップ
list:set他のセットのリスト

12.3 ipset の使用法

# ブロック IP セットを作成
ipset create blocked_hosts hash:ip hashsize 4096 maxelem 100000
ipset add blocked_hosts 10.0.0.1
ipset add blocked_hosts 10.0.0.2

# iptables で使用
iptables -A INPUT -m set --match-set blocked_hosts src -j DROP

# タイムアウト付きセット (エントリが自動失効)
ipset create temp_block hash:ip timeout 3600
ipset add temp_block 10.0.0.1 timeout 1800  # 30分で上書き

# ネットワークセット
ipset create trusted_nets hash:net
ipset add trusted_nets 10.0.0.0/8
ipset add trusted_nets 172.16.0.0/12
ipset add trusted_nets 192.168.0.0/16
iptables -A INPUT -m set --match-set trusted_nets src -j ACCEPT

# IP+ポートセット
ipset create allowed_services hash:ip,port
ipset add allowed_services 10.0.0.1,tcp:22
ipset add allowed_services 10.0.0.1,tcp:80
iptables -A INPUT -m set --match-set allowed_services src,dst -j ACCEPT

# 国別ブロック
ipset create country_cn hash:net hashsize 4096 maxelem 100000
# GeoIP データベースから投入
while read cidr; do
  ipset add country_cn "$cidr"
done < /usr/share/GeoIP/cn.zone
iptables -A INPUT -m set --match-set country_cn src -j DROP

# セット内容の表示
ipset list blocked_hosts

# 保存と復元
ipset save > /etc/ipset.conf
ipset restore < /etc/ipset.conf

# アトミックなセット入れ替え (ダウンタイムなしの更新)
ipset create blocked_hosts_new hash:ip
# ... 新セットを投入 ...
ipset swap blocked_hosts blocked_hosts_new
ipset destroy blocked_hosts_new

# メンバーシップテスト
ipset test blocked_hosts 10.0.0.1

12.4 nftables でのセット (ipset の代替)

# nftables の名前付きセット
nft add set inet filter blocked_hosts '{ type ipv4_addr; flags timeout; }'
nft add element inet filter blocked_hosts '{ 10.0.0.1 timeout 1h, 10.0.0.2 }'
nft add rule inet filter input ip saddr @blocked_hosts drop

# ネットワークセット
nft add set inet filter trusted_nets '{ type ipv4_addr; flags interval; }'
nft add element inet filter trusted_nets '{ 10.0.0.0/8, 172.16.0.0/12 }'

# 動的セット (自動投入)
nft add set inet filter dyn_blocked \
  '{ type ipv4_addr; flags dynamic, timeout; timeout 1h; }'
nft add rule inet filter input tcp dport 22 \
  meter ssh_fail '{ ip saddr limit rate over 5/minute }' \
  add @dyn_blocked '{ ip saddr }' drop

13. ebtables とブリッジフィルタリング

13.1 概要

ebtables は Ethernet (レイヤー 2) レベルでのトラフィックをフィルタリングし、主にブリッジデバイスで使用される。

13.2 ebtables コマンド

# ブリッジフィルタリングルール一覧
ebtables -L --Ln

# MAC アドレスでフィルタ
ebtables -A FORWARD -s 00:11:22:33:44:55 -j DROP

# VLAN でフィルタ
ebtables -A FORWARD -p 802_1Q --vlan-id 100 -j ACCEPT

# ARP フィルタリング
ebtables -A FORWARD -p ARP --arp-opcode Request \
  --arp-ip-src 192.168.1.0/24 -j ACCEPT
ebtables -A FORWARD -p ARP -j DROP

# MAC スプーフィング防止
ebtables -A FORWARD -s ! 00:11:22:33:44:55 -i eth1 -j DROP

13.3 nftables でのブリッジフィルタリング

# nftables bridge ファミリー
nft add table bridge filter
nft add chain bridge filter forward \
  '{ type filter hook forward priority 0; policy accept; }'

# MAC でフィルタ
nft add rule bridge filter forward ether saddr 00:11:22:33:44:55 drop

# VLAN でフィルタ
nft add rule bridge filter forward vlan id 100 accept

13.4 br_netfilter モジュール

# ブリッジトラフィックに iptables フィルタリングを有効化
modprobe br_netfilter

# sysctl 設定
sysctl -w net.bridge.bridge-nf-call-iptables=1
sysctl -w net.bridge.bridge-nf-call-ip6tables=1
sysctl -w net.bridge.bridge-nf-call-arptables=1

# Kubernetes ネットワーキングが正しく動作するために必要
# コンテナトラフィックはブリッジを経由することが多い

14. nf_tables BPF 統合

14.1 概要

nftables は高度なパケット処理のために BPF (Berkeley Packet Filter) および eBPF と統合できる:

+-------------------+     +------------------+
|  nftables ルール   |     |  BPF プログラム   |
|  (nf_tables VM)   |     |  (eBPF VM)       |
+--------+----------+     +--------+---------+
         |                          |
         v                          v
    Netfilter フック           XDP / TC フック
         |                          |
         v                          v
    +----+--------------------------+----+
    |    Linux カーネルネットワークスタック |
    +------------------------------------+

14.2 eBPF と XDP

// XDP プログラムによる高性能パケットフィルタリング
// コンパイル: clang -O2 -target bpf -c xdp_filter.c -o xdp_filter.o

#include <linux/bpf.h>
#include <linux/if_ether.h>
#include <linux/ip.h>

SEC("xdp")
int xdp_filter(struct xdp_md *ctx)
{
    void *data_end = (void *)(long)ctx->data_end;
    void *data = (void *)(long)ctx->data;

    struct ethhdr *eth = data;
    if ((void *)(eth + 1) > data_end)
        return XDP_PASS;

    if (eth->h_proto != __constant_htons(ETH_P_IP))
        return XDP_PASS;

    struct iphdr *ip = (void *)(eth + 1);
    if ((void *)(ip + 1) > data_end)
        return XDP_PASS;

    // 10.0.0.1 からのトラフィックを破棄
    if (ip->saddr == __constant_htonl(0x0A000001))
        return XDP_DROP;

    return XDP_PASS;
}

char _license[] SEC("license") = "GPL";
# XDP プログラムのロード
ip link set dev eth0 xdpgeneric obj xdp_filter.o sec xdp

# アンロード
ip link set dev eth0 xdpgeneric off

14.3 パフォーマンス比較

処理速度 (パケット/秒、概算):
  iptables (線形ルール):        約 100-500万 pps
  nftables (セット使用):        約 500-1500万 pps
  eBPF/XDP (ネイティブドライバ): 約 2000-1億 pps
  eBPF/XDP (汎用):             約 500-2000万 pps

15. Firewalld と ufw フロントエンド

15.1 Firewalld

Firewalld はゾーンベースの設定を持つ動的ファイアウォールマネージャーである:

# 状態確認
firewall-cmd --state
systemctl status firewalld

# ゾーン一覧
firewall-cmd --get-zones

# アクティブゾーン
firewall-cmd --get-active-zones

# デフォルトゾーン設定
firewall-cmd --set-default-zone=public

# ゾーン設定表示
firewall-cmd --zone=public --list-all

# サービス追加 (一時的)
firewall-cmd --zone=public --add-service=http
firewall-cmd --zone=public --add-service=https

# サービス追加 (永続的)
firewall-cmd --zone=public --add-service=http --permanent
firewall-cmd --zone=public --add-service=https --permanent
firewall-cmd --reload

# ポート追加
firewall-cmd --zone=public --add-port=8080/tcp --permanent

# リッチルール (複雑なフィルタリング)
firewall-cmd --zone=public --add-rich-rule='
  rule family="ipv4"
  source address="10.0.0.0/8"
  service name="ssh"
  accept' --permanent

firewall-cmd --zone=public --add-rich-rule='
  rule family="ipv4"
  source address="192.168.1.0/24"
  port protocol="tcp" port="3306"
  accept' --permanent

# レート制限
firewall-cmd --zone=public --add-rich-rule='
  rule family="ipv4"
  service name="ssh"
  accept
  limit value="3/m"' --permanent

# ポートフォワーディング
firewall-cmd --zone=public --add-forward-port=\
port=80:proto=tcp:toport=8080:toaddr=192.168.1.10 --permanent

# マスカレード
firewall-cmd --zone=public --add-masquerade --permanent

# 変更を反映
firewall-cmd --reload

# カスタムサービス作成
cat > /etc/firewalld/services/myapp.xml << 'EOF'
<?xml version="1.0" encoding="utf-8"?>
<service>
  <short>MyApp</short>
  <description>カスタムアプリケーション</description>
  <port protocol="tcp" port="8080"/>
  <port protocol="tcp" port="8443"/>
</service>
EOF
firewall-cmd --reload
firewall-cmd --zone=public --add-service=myapp --permanent

15.2 ufw (Uncomplicated Firewall)

# 有効化/無効化
ufw enable
ufw disable

# 状態確認
ufw status verbose
ufw status numbered

# デフォルトポリシー
ufw default deny incoming
ufw default allow outgoing

# サービス許可
ufw allow ssh
ufw allow http
ufw allow https
ufw allow 8080/tcp

# 送信元指定で許可
ufw allow from 10.0.0.0/8 to any port 22

# ポート範囲
ufw allow 5000:5100/tcp

# 拒否
ufw deny from 10.0.0.1

# ルール削除
ufw delete allow http
ufw delete 5   # ルール番号指定

# レート制限 (30秒以内に6回以上の接続でブロック)
ufw limit ssh

# ログ
ufw logging on
ufw logging medium  # low, medium, high, full

# リセット
ufw reset

# ルーティングルール (転送用)
ufw route allow in on eth1 out on eth0 from 192.168.1.0/24

15.3 Firewalld と ufw の比較

機能firewalldufw
バックエンドnftables/iptablesiptables
ゾーンサポートありなし
動的リロードありなし
リッチルールあり限定的
D-Bus APIありなし
GUIfirewall-configgufw
ディストリビューションRHEL/Fedora/SUSEDebian/Ubuntu
複雑さ

16. コネクショントラッキングチューニング

16.1 主要パラメータ

# conntrack テーブルの最大エントリ数
sysctl net.netfilter.nf_conntrack_max
# デフォルト: 65536 (RAM による)

# 推奨: エントリあたり約256バイト、利用可能な RAM に合わせてスケール
# 1GB RAM の場合: 262144 エントリ (約64MB)
sysctl -w net.netfilter.nf_conntrack_max=262144

# ハッシュテーブルサイズ (バケット) - モジュールロード時に設定
echo "options nf_conntrack hashsize=65536" > /etc/modprobe.d/nf_conntrack.conf
# 経験則: hashsize = nf_conntrack_max / 4

# 現在のハッシュサイズ確認
cat /proc/sys/net/netfilter/nf_conntrack_buckets

# 現在の使用状況
cat /proc/sys/net/netfilter/nf_conntrack_count

16.2 タイムアウトチューニング

# TCP タイムアウト (秒)
sysctl -w net.netfilter.nf_conntrack_tcp_timeout_established=86400  # 1日
sysctl -w net.netfilter.nf_conntrack_tcp_timeout_syn_sent=30
sysctl -w net.netfilter.nf_conntrack_tcp_timeout_syn_recv=30
sysctl -w net.netfilter.nf_conntrack_tcp_timeout_fin_wait=30
sysctl -w net.netfilter.nf_conntrack_tcp_timeout_close_wait=30
sysctl -w net.netfilter.nf_conntrack_tcp_timeout_last_ack=15
sysctl -w net.netfilter.nf_conntrack_tcp_timeout_time_wait=30
sysctl -w net.netfilter.nf_conntrack_tcp_timeout_close=5

# UDP タイムアウト
sysctl -w net.netfilter.nf_conntrack_udp_timeout=30
sysctl -w net.netfilter.nf_conntrack_udp_timeout_stream=60

# ICMP タイムアウト
sysctl -w net.netfilter.nf_conntrack_icmp_timeout=15

# 汎用タイムアウト
sysctl -w net.netfilter.nf_conntrack_generic_timeout=120

16.3 パフォーマンスチューニング

# /etc/sysctl.d/99-conntrack.conf

# conntrack テーブルサイズを増加
net.netfilter.nf_conntrack_max = 524288

# TCP チューニング
net.netfilter.nf_conntrack_tcp_timeout_established = 86400
net.netfilter.nf_conntrack_tcp_timeout_time_wait = 30
net.netfilter.nf_conntrack_tcp_timeout_close_wait = 30
net.netfilter.nf_conntrack_tcp_timeout_fin_wait = 30

# TCP ルーズトラッキングを有効化
net.netfilter.nf_conntrack_tcp_loose = 1

# TCP ウィンドウトラッキングを寛容に
net.netfilter.nf_conntrack_tcp_be_liberal = 1

# conntrack ヘルパーの自動ロードを無効化 (セキュリティ)
net.netfilter.nf_conntrack_helper = 0

# アカウンティングを有効化 (コネクションごとのバイト/パケットカウンター)
net.netfilter.nf_conntrack_acct = 1

# タイムスタンプを有効化
net.netfilter.nf_conntrack_timestamp = 1

# 適用
sysctl -p /etc/sysctl.d/99-conntrack.conf

16.4 conntrack モニタリング

# テーブル使用状況の確認
echo "$(cat /proc/sys/net/netfilter/nf_conntrack_count) / \
$(cat /proc/sys/net/netfilter/nf_conntrack_max)"

# CPU ごとの統計
conntrack -S
# cpu=0  found=1234 invalid=56 insert=789 insert_failed=0 drop=0
#        early_drop=0 error=0 search_restart=12

# 監視すべき主要メトリクス:
# - drop: テーブル満杯によるパケット破棄 (重大)
# - insert_failed: エントリ挿入失敗 (テーブル満杯)
# - early_drop: 空きを作るためにエントリを早期削除
# - search_restart: ハッシュテーブルリサイズによる再検索

# watch で監視
watch -n 1 'conntrack -C; conntrack -S'

# テーブル容量アラート
CURRENT=$(cat /proc/sys/net/netfilter/nf_conntrack_count)
MAX=$(cat /proc/sys/net/netfilter/nf_conntrack_max)
USAGE=$((CURRENT * 100 / MAX))
if [ "$USAGE" -gt 80 ]; then
  echo "警告: conntrack テーブル使用率 ${USAGE}%"
fi

16.5 コネクショントラッキングのバイパス

ステートフル検査を必要としない高スループットサービス向け:

# 特定トラフィックのトラッキングをスキップ
iptables -t raw -A PREROUTING -p udp --dport 53 -j NOTRACK
iptables -t raw -A OUTPUT -p udp --sport 53 -j NOTRACK

# UNTRACKED トラフィックは両方向で明示的に許可する必要がある
iptables -A INPUT -p udp --dport 53 -m conntrack --ctstate UNTRACKED -j ACCEPT
iptables -A OUTPUT -p udp --sport 53 -m conntrack --ctstate UNTRACKED -j ACCEPT

# nftables での同等設定
nft add rule inet raw prerouting udp dport 53 notrack
nft add rule inet raw output udp sport 53 notrack

17. 実践的ファイアウォール設定例

17.1 Web サーバーファイアウォール

#!/bin/bash
# web-server-firewall.sh - 本番 Web サーバー用

# リセット
iptables -F
iptables -X
iptables -t nat -F
iptables -t mangle -F
iptables -t raw -F

# デフォルトポリシー
iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT ACCEPT

# === ループバック ===
iptables -A INPUT -i lo -j ACCEPT

# === コネクショントラッキング ===
iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
iptables -A INPUT -m conntrack --ctstate INVALID -j DROP

# === スキャン防御 ===
iptables -A INPUT -p tcp --tcp-flags ALL NONE -j DROP
iptables -A INPUT -p tcp --tcp-flags ALL ALL -j DROP
iptables -A INPUT -p tcp --tcp-flags SYN,FIN SYN,FIN -j DROP
iptables -A INPUT -p tcp --tcp-flags SYN,RST SYN,RST -j DROP

# === SYN フラッド防御 ===
iptables -A INPUT -p tcp --syn -m limit --limit 50/s --limit-burst 100 -j ACCEPT
iptables -A INPUT -p tcp --syn -j DROP

# === SSH (レート制限、管理ネットワークのみ) ===
iptables -A INPUT -p tcp --dport 22 -s 10.0.0.0/8 \
  -m conntrack --ctstate NEW \
  -m hashlimit --hashlimit-name ssh --hashlimit-above 5/min \
  --hashlimit-burst 5 --hashlimit-mode srcip -j DROP
iptables -A INPUT -p tcp --dport 22 -s 10.0.0.0/8 \
  -m conntrack --ctstate NEW -j ACCEPT

# === HTTP/HTTPS ===
iptables -A INPUT -p tcp -m multiport --dports 80,443 \
  -m conntrack --ctstate NEW -j ACCEPT

# === ICMP ===
iptables -A INPUT -p icmp --icmp-type echo-request \
  -m limit --limit 5/s --limit-burst 10 -j ACCEPT
iptables -A INPUT -p icmp --icmp-type destination-unreachable -j ACCEPT
iptables -A INPUT -p icmp --icmp-type time-exceeded -j ACCEPT

# === モニタリング (オプション) ===
iptables -A INPUT -p tcp --dport 9100 -s 10.0.0.0/8 -j ACCEPT

# === ログ ===
iptables -A INPUT -m limit --limit 5/min \
  -j LOG --log-prefix "INPUT-DROP: " --log-level 4
iptables -A INPUT -j DROP

# === ルール保存 ===
iptables-save > /etc/iptables/rules.v4

17.2 ゲートウェイ/ルーターファイアウォール

#!/bin/bash
# gateway-firewall.sh
# 2インターフェースゲートウェイ: eth0 (WAN), eth1 (LAN 192.168.1.0/24)

# フォワーディング有効化
sysctl -w net.ipv4.ip_forward=1
sysctl -w net.ipv4.conf.all.rp_filter=1

# リセット
iptables -F
iptables -X
iptables -t nat -F
iptables -t mangle -F

# デフォルトポリシー
iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT ACCEPT

# === NAT ===
iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -o eth0 -j MASQUERADE

# === ポートフォワーディング ===
iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 80 \
  -j DNAT --to-destination 192.168.1.10:80
iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 443 \
  -j DNAT --to-destination 192.168.1.10:443

# === INPUT (ゲートウェイ自体) ===
iptables -A INPUT -i lo -j ACCEPT
iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
iptables -A INPUT -m conntrack --ctstate INVALID -j DROP

# SSH
iptables -A INPUT -p tcp --dport 22 -j ACCEPT

# LAN からの DNS/DHCP
iptables -A INPUT -i eth1 -p udp -m multiport --dports 53,67 -j ACCEPT
iptables -A INPUT -i eth1 -p tcp --dport 53 -j ACCEPT

# ICMP
iptables -A INPUT -p icmp --icmp-type echo-request \
  -m limit --limit 5/s -j ACCEPT

# === FORWARD ===
# LAN -> WAN (無制限)
iptables -A FORWARD -i eth1 -o eth0 -s 192.168.1.0/24 -j ACCEPT

# WAN -> LAN (確立済み + ポートフォワード)
iptables -A FORWARD -i eth0 -o eth1 \
  -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

# ポートフォワードされたトラフィック
iptables -A FORWARD -i eth0 -o eth1 -p tcp -d 192.168.1.10 \
  -m multiport --dports 80,443 -m conntrack --ctstate NEW -j ACCEPT

# === MSS クランプ (PPPoE で重要) ===
iptables -t mangle -A FORWARD -p tcp --tcp-flags SYN,RST SYN \
  -j TCPMSS --clamp-mss-to-pmtu

# ログ
iptables -A INPUT -m limit --limit 5/min \
  -j LOG --log-prefix "GW-INPUT-DROP: "
iptables -A FORWARD -m limit --limit 5/min \
  -j LOG --log-prefix "GW-FWD-DROP: "
iptables -A INPUT -j DROP
iptables -A FORWARD -j DROP

17.3 nftables 完全設定

#!/usr/sbin/nft -f
# /etc/nftables.conf - サーバー完全設定

flush ruleset

define WAN_IF = eth0
define LAN_IF = eth1
define LAN_NET = 192.168.1.0/24
define MGMT_NET = 10.0.0.0/8

table inet filter {
    # ブルートフォース防御用の動的セット
    set blocked_ssh {
        type ipv4_addr
        flags dynamic, timeout
        timeout 15m
        size 65536
    }

    chain input {
        type filter hook input priority 0; policy drop;

        # ループバック
        iif lo accept

        # コネクショントラッキング
        ct state established,related accept
        ct state invalid counter drop

        # スキャン防御
        tcp flags & (fin|syn|rst|psh|ack|urg) == 0x0 counter drop
        tcp flags syn,fin / syn,fin counter drop

        # 動的ブロック付きレート制限 SSH
        ip saddr @blocked_ssh counter drop
        tcp dport 22 ct state new \
            meter ssh_meter { ip saddr limit rate over 5/minute } \
            add @blocked_ssh { ip saddr } counter drop
        tcp dport 22 ip saddr $MGMT_NET ct state new accept

        # Web サービス
        tcp dport { 80, 443 } ct state new accept

        # ICMP
        ip protocol icmp icmp type {
            echo-request, destination-unreachable, time-exceeded
        } limit rate 10/second accept

        # ICMPv6
        ip6 nexthdr icmpv6 icmpv6 type {
            echo-request, echo-reply,
            nd-router-solicit, nd-router-advert,
            nd-neighbor-solicit, nd-neighbor-advert
        } accept

        # モニタリング
        tcp dport 9100 ip saddr $MGMT_NET accept

        # ログと破棄
        limit rate 5/minute counter log prefix "INPUT-DROP: " drop
    }

    chain forward {
        type filter hook forward priority 0; policy drop;
        ct state established,related accept
        ct state invalid drop

        # LAN -> WAN
        iifname $LAN_IF oifname $WAN_IF ip saddr $LAN_NET accept

        # ポートフォワード
        iifname $WAN_IF oifname $LAN_IF ip daddr 192.168.1.10 \
            tcp dport { 80, 443 } ct state new accept

        limit rate 5/minute log prefix "FORWARD-DROP: " drop
    }

    chain output {
        type filter hook output priority 0; policy accept;
    }
}

table inet nat {
    chain prerouting {
        type nat hook prerouting priority dstnat;
        iifname $WAN_IF tcp dport 80 dnat to 192.168.1.10:80
        iifname $WAN_IF tcp dport 443 dnat to 192.168.1.10:443
    }

    chain postrouting {
        type nat hook postrouting priority srcnat;
        oifname $WAN_IF ip saddr $LAN_NET masquerade
    }
}

table inet mangle {
    chain forward {
        type filter hook forward priority mangle;
        # MSS クランプ
        tcp flags syn / syn,rst tcp option maxseg size set rt mtu
    }
}

17.4 Docker/Kubernetes ファイアウォールの考慮事項

# Docker は独自の iptables ルールをコンテナネットワーキング用に追加する
# Docker が追加したルールの確認
iptables -L -n -v -t nat    # DOCKER チェーン
iptables -L -n -v -t filter # DOCKER-USER チェーン

# カスタムルールは DOCKER-USER チェーンに追加する
# (DOCKER チェーンではなく)
iptables -I DOCKER-USER -i eth0 -s 10.0.0.0/8 \
  -p tcp --dport 8080 -j ACCEPT
iptables -I DOCKER-USER -i eth0 -j DROP

# Kubernetes では kube-proxy が iptables ルールを管理
# 主要な Kubernetes チェーン:
# KUBE-SERVICES        - Service ClusterIP 処理
# KUBE-NODEPORTS       - NodePort サービス処理
# KUBE-POSTROUTING     - Pod 送信の SNAT
# KUBE-SVC-*           - サービスごとのチェーン
# KUBE-SEP-*           - エンドポイントごとのチェーン

18. ツールとユーティリティ

18.1 iptables-save と iptables-restore

# 現在のルールを保存
iptables-save > /etc/iptables/rules.v4
ip6tables-save > /etc/iptables/rules.v6

# ルールを復元
iptables-restore < /etc/iptables/rules.v4
ip6tables-restore < /etc/iptables/rules.v6

# ルールテスト (ロックアウト時の自動復元)
iptables-restore --test < new_rules.v4

# アトミック復元 (全ルールが一度に適用)
iptables-restore -n < additional_rules.v4  # フラッシュなし

# 保存形式の例:
# *filter
# :INPUT DROP [0:0]
# :FORWARD DROP [0:0]
# :OUTPUT ACCEPT [0:0]
# -A INPUT -i lo -j ACCEPT
# -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
# COMMIT

# 永続化 (Debian/Ubuntu)
apt install iptables-persistent
netfilter-persistent save
netfilter-persistent reload

# 永続化 (RHEL/CentOS)
yum install iptables-services
systemctl enable iptables
service iptables save

18.2 nft コマンドリファレンス

# ルールセット全体を表示
nft list ruleset
nft list ruleset -a    # ハンドル番号表示

# エクスポート/インポート
nft list ruleset > /etc/nftables.conf
nft -f /etc/nftables.conf

# JSON 出力
nft -j list ruleset > ruleset.json

# テーブル操作
nft add table inet filter
nft delete table inet filter
nft flush table inet filter
nft list tables

# チェーン操作
nft add chain inet filter input \
  '{ type filter hook input priority 0; policy drop; }'
nft flush chain inet filter input

# ルール操作
nft add rule inet filter input tcp dport 22 accept
nft insert rule inet filter input position 0 tcp dport 22 accept
nft delete rule inet filter input handle 42

# 変更の監視
nft monitor

# 設定の検証 (適用なし)
nft -c -f /etc/nftables.conf

18.3 conntrack コマンド

# コネクション一覧
conntrack -L
conntrack -L -p tcp
conntrack -L -p udp

# コネクション数
conntrack -C

# 状態でフィルタ
conntrack -L -p tcp --state ESTABLISHED

# アドレスでフィルタ
conntrack -L -s 192.168.1.100

# コネクション削除
conntrack -D -p tcp --dport 80
conntrack -D -s 10.0.0.1

# 全フラッシュ
conntrack -F

# リアルタイム監視
conntrack -E
conntrack -E -e NEW
conntrack -E -e DESTROY

# 統計
conntrack -S

# 出力形式
conntrack -L -o extended
conntrack -L -o xml

18.4 その他の有用なツール

# 利用可能なモジュール確認
ls /lib/modules/$(uname -r)/kernel/net/netfilter/

# nfacct (Netfilter アカウンティング)
nfacct add http_traffic
iptables -A INPUT -p tcp --dport 80 -m nfacct --nfacct-name http_traffic
nfacct get http_traffic

# tcpdump (パケットキャプチャ)
tcpdump -i eth0 -n 'tcp port 80'

# ss (ソケット統計)
ss -tuln          # リスニングソケット
ss -tupn          # 接続済みソケット + プロセス
ss -s             # サマリー統計

19. トラブルシューティングとデバッグ

19.1 よくある問題

# 問題: ルール適用後に SSH からロックアウト
# 防止策: 自動復元メカニズムを使用してテスト
at now + 5 minutes <<< "iptables -F; iptables -P INPUT ACCEPT"
# ルールが正しく動作したら: atrm <ジョブID>

# 問題: conntrack テーブル満杯
# 症状: パケット破棄、dmesg に "nf_conntrack: table full"
dmesg | grep "nf_conntrack: table full"
sysctl -w net.netfilter.nf_conntrack_max=524288

# 問題: 重複ルール
iptables-save | sort | uniq -d

# 問題: ルールがマッチしない
# カウンターを確認:
iptables -L -n -v   # ゼロのパケット/バイトカウンターを探す

19.2 TRACE によるパケットトレース

# iptables TRACE ターゲット (raw テーブルのみ)
iptables -t raw -A PREROUTING -p tcp --dport 80 -s 10.0.0.1 -j TRACE
iptables -t raw -A OUTPUT -p tcp --sport 80 -d 10.0.0.1 -j TRACE

# トレース出力をカーネルログで確認
dmesg | grep "TRACE:"
journalctl -k | grep "TRACE:"

# トレースロギングの有効化
modprobe nf_log_ipv4
sysctl -w net.netfilter.nf_log.2=nf_log_ipv4

# nftables でのトレース
nft add rule inet raw prerouting tcp dport 80 ip saddr 10.0.0.1 \
  meta nftrace set 1
nft monitor trace

19.3 デバッグチェックリスト

# 1. ルールがロードされているか確認
iptables -L -n -v --line-numbers
nft list ruleset

# 2. パケットカウンターの確認 (ルールがマッチしているか)
iptables -L -n -v | grep -v "0     0"

# 3. コネクショントラッキングの確認
conntrack -L | grep <問題のIP>
conntrack -C  # テーブルが容量に近いか

# 4. カーネルログのドロップ/エラー確認
dmesg | tail -50
journalctl -k --since "5 minutes ago"

# 5. フォワーディングが有効か確認
sysctl net.ipv4.ip_forward
cat /proc/sys/net/ipv4/ip_forward

# 6. NAT ルールの確認
iptables -t nat -L -n -v

# 7. 接続性テスト
ping -c 1 <対象>
traceroute <対象>
nc -zv <ホスト> <ポート>
curl -v http://<ホスト>/

# 8. パケットキャプチャ
tcpdump -i eth0 -n host 10.0.0.1 and port 80

# 9. 競合するファイアウォールツールの確認
systemctl status firewalld
systemctl status ufw
iptables -L | grep -i docker

# 10. カーネルモジュールの確認
lsmod | grep nf_conntrack
lsmod | grep nf_nat
lsmod | grep nf_tables

19.4 パフォーマンストラブルシューティング

# softirq 負荷の確認 (高 softirq = パケット/ルールが多すぎる)
cat /proc/softirqs | grep NET

# conntrack パフォーマンスの確認
conntrack -S
# 注意: drop > 0, early_drop > 0, search_restart が高い場合

# ルール評価パフォーマンス
# パケットカウンター付きリストでホットルールを特定
iptables -L -n -v -x | head -50

# nftables ルール統計
nft list ruleset -s

20. まとめ

20.1 重要概念のサマリー

Netfilter フレームワークは Linux カーネルにおける包括的なパケット処理インフラストラクチャを提供する:

  • 5 つのフックポイント (PREROUTING, INPUT, FORWARD, OUTPUT, POSTROUTING) がパケットフロー全体を制御
  • コネクショントラッキングがステートフル検査を可能にし、ルールをシンプルかつ安全に
  • iptables が成熟した理解しやすいインターフェースを提供 (テーブル/チェーン/ルール構造)
  • nftables が現代的な代替として、より高いパフォーマンス、アトミック更新、統一された IPv4/IPv6 処理を実現
  • NAT (SNAT, DNAT, MASQUERADE) がアドレス変換による複雑なネットワークトポロジーを実現
  • ipset と nftables セットが大規模データセットに対する効率的なマッチングを提供
  • ログ機能 (LOG, NFLOG, ulogd2) が包括的なトラフィック監査を実現
  • フロントエンドツール (firewalld, ufw) が一般的な設定を簡素化

20.2 ベストプラクティスのまとめ

  1. デフォルト拒否: 常にデフォルトポリシーを DROP に設定
  2. ステートフルを優先: NEW コネクションの前に ESTABLISHED,RELATED を処理
  3. INVALID を早期に破棄: リソース消費前に不正パケットを除去
  4. レート制限: フラッドやブルートフォースから保護
  5. nftables を使用: 新規デプロイメントでは iptables より nftables を推奨
  6. 戦略的にログ: ログ溢れ防止のためレート制限を適用
  7. 安全にテスト: リモートルールテスト時は at(1) で自動復元を使用
  8. conntrack を監視: テーブル使用率を監視し必要に応じてチューニング
  9. セットを使用: 大量の IP/ポートリストには ipset または nftables セット
  10. ルールを文書化: コメントでルールの目的を説明
  11. 保存とバージョン管理: ファイアウォールルールをバージョン管理に保存
  12. 関心事の分離: カスタムチェーンで論理的にグループ化

20.3 移行パス

現在の状態              推奨アクション
--------------         ------------------
ファイアウォールなし  -> nftables で基本ルールを実装
iptables (レガシー)  -> nftables への移行を計画
iptables-nft         -> 既に nftables バックエンドを使用中
nftables             -> 現状維持、セット/マップで最適化
firewalld            -> RHEL/ゾーンモデルを使用中ならそのまま
ufw                  -> シンプルなサーバー設定なら継続使用

20.4 参考リソース


本ドキュメントは Linux カーネル 6.x 時点の Netfilter を対象としている。機能やインターフェースはカーネルバージョンやディストリビューションによって異なる場合がある。