はじめに
iptablesがよくわかっていないので勉強した時のメモ
学習教材:
https://straypenguin.winfield-net.com/iptables.html
構造
テーブル(filter,nat,mangle)
組み込まれているチェーンは、テーブルの種類によって異なる。
チェーン(PREROUTING, INPUT, OUTPUT, FORWARD, POSTROUTINGおよびユーザ定義チェーン)
ルールのまとまりによるフィルタリングアルゴリズム。
ルール(ACCEPT, DROP, REJECT, LOG, RETURN, TOS, TTL, MARK, DNAT, SNAT, MASQUERADE, QUEUE, REDIRECTなど)
「パケットがこれこれだったら、そいつをこう操作せよ」 という指示。設定できるルールはチェーンによって異なる。例えばDNATは、natテーブルPREROUTINGチェーンなどに登録する
主なコマンド
ルール操作
-t table: テーブルを指定。デフォルトではfilterテーブル
-A chain rule: chainにruleをappend
-D chain rule: chainのruleをdelete。numberでも指定可能
-I chain rule_number rule: chainにruleをnumber位置にinsert。rule_numberのデフォルト値は0。
-R chain rule_number new_rule: rule_numberの位置のruleをnew_ruleでreplace
チェーン操作
-N new_chain_name: New。チェーンを作成(ex. ip6tables -t filter -N new_chain_name
)
-P chain policy: chainの基本Policyをセット。ルールでドロップして残りは受け入れる (ACCEPT) か、ルールでアクセプトして残りを拒否する (DROP) かのいずれか。ユーザ定義チェーンには使えない
[-t table] -X [chain]: 指定したchain(ユーザ定義に限る)を削除
[-t table] -L [chain] [options]: chainにあるruleをリスト出力
実験
ip6tables -t filter -L などで、確かにChainが出てきた。
ip6tables -t filter -N my_new_chain で、chainを追加できた
ip6tables -t filter -A my_new_chain で、ruleを追加できた(こんなに空っぽでも追加できるのか)
また、Ubuntuで、
iptables -t filter -A INPUT -p tcp --dport 8080 -j DROP
を実行したら、ちゃんとLANの別のマシンから8080へアクセスしようとしたら、アクセスできなかった。
さらに、iptables -t filter -L -v
で、パケット数を見てみたら、LANの別のマシンからアクセスするたびに増えていっていた。
なお、変更は基本的にすべて、再起動で消えるらしい。また、SSH先のUbuntuで作業している場合(私の場合はそう)、うっかり閉め出されるといけないので、作業している時は、
(sleep 300 && iptables -F) & などをしておくと安全らしい(SSH先のUbuntuは私の場合は、別室にあるので、マシンのある部屋まで行って直接再起動すればよいので不要そう)
sudo iptables -A OUTPUT -p udp --dport 53 -j DROP
したら、ちゃんとDNS解決ができなくなった。
sudo ip6tables -t filter -L | grep Chain
Chain INPUT (policy ACCEPT)
Chain FORWARD (policy DROP)
Chain OUTPUT (policy ACCEPT)
Chain DOCKER (1 references)
Chain DOCKER-ISOLATION-STAGE-1 (1 references)
Chain DOCKER-ISOLATION-STAGE-2 (1 references)
Chain DOCKER-USER (1 references)
sudo ip6tables -t nat -L | grep Chain
Chain PREROUTING (policy ACCEPT)
Chain INPUT (policy ACCEPT)
Chain OUTPUT (policy ACCEPT)
Chain POSTROUTING (policy ACCEPT)
Chain DOCKER (2 references)
sudo ip6tables -t mangle -L | grep Chain
Chain PREROUTING (policy ACCEPT)
Chain INPUT (policy ACCEPT)
Chain FORWARD (policy ACCEPT)
Chain OUTPUT (policy ACCEPT)
Chain POSTROUTING (policy ACCEPT)
Dockerと名前の入ったもの以外はデフォルトの模様。
ルール操作
条件 -j 動作または他のユーザ定義チェーン[オプション]
"!" を挟むと意味を反転 (否定) できる。
-p [!] protocol tcp, udp, icmp, all のいずれか。all は「ありとあらゆるプロトコル」ではなく、tcp, udp, icmp を指す。指定無しは all と同じ
-s [!] address[/mask] 送信元アドレス。ネットマスクは4オクテット書式、CIDR書式とも可
-d [!] address[/mask] 宛先アドレス
-i [!] interface[+] 入ってくるインターフェイス。eth+ などとすると eth0, eth1.. .にマッチ
-o [!] interface[+] 出て行くインターフェイス
動作(ジャンプターゲット)の主なもの
ACCEPT: 受け入れる
DROP: 黙って捨てる
テーブルとチェーンの仕様
filterテーブル
INPUT, FORWARDチェーン
どちらもPCに到達してくるパケットが該当。
INPUTは、そのPCが終端のパケット。
FORWARDは、つぎのデバイスへ転送する必要があるパケット。
OUTPUTチェーン
そのPCで発生して、外へ出ていくパケット。なお、FORWARDの結果、次のマシンへ転送することになった場合、一見そのPCから出ていっているようにも見えるが、この場合はOUTPUTチェーンは利用されない(あくまでOUTPUTは、そのPCが作成したパケットのみに対応する)。
コラム(静的ルーティングCRUD)
どのIPアドレスは、どの
create
ip route add /<サブネットマスク> [dev <デバイス名>] via <デフォルトゲートウェイ>
例: ip route add 172.17.0.0/16 dev eth0 via 192.168.1.70
read
ip route
update
不可能。消して作るしかないらしい
delete
ip route delete 172.17.0.0/16 dev eth0 via 192.168.1.70
delete 以外については、条件文となるもよう。
ただ、viaは無視されているかも。
NATテーブル
PREROUTING、OUTPUT、POSTROUTINGチェーン
PREROUTING、POSTROUTINGは、外から来たパケットに関するチェーン。
PREROUTINGはルーティングの前、POSTROUTINGはルーティングの後。
すなわち、PREROUTING、ルーティング、POSTROUTINGの順番。
具体的な用途としては、
- PREROUTING
宛先NAT(DNAT) - POSTROUTING
送信元NAT(SNAT)、マスカレード
OUTPUTは、自分のマシンが生成したパケットに関するチェーン。
具体的な用途としては、
- OUTPUT
ローカルでの宛先NAT(DNAT)
例:ルーターに設定して、内部のネットワークからのパケットのL3ヘッダのソースIPアドレスを、ルーターが送信する送信元インターフェースのIPアドレスに変換する(NATゲートウェイ)。
# 内部ネットワーク (192.168.1.0/24) を外部ネットワークにNATする
iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -o eth0 -j MASQUERADE
例:外部からの特定のサービスへのリクエストを内部サーバへ転送する(ポートフォワード)
# 外部ポート80のリクエストを内部サーバ192.168.1.100:80に転送
iptables -t nat -A PREROUTING -p tcp --dport 80 -j DNAT --to-destination 192.168.1.100:80