シンプルなステートフルファイアウォール

提供: ArchWiki
ナビゲーションに移動 検索に移動

関連記事

このページでは iptables を使ってステートフルファイアウォールを設定する方法を説明します。また、ルールの意味と理由の説明も行います。シンプルに説明するため、大きく2つのセクションにページは分かれています。最初のセクションではシングルマシンのためのファイアウォールを扱い、2番目のセクションでは最初のセクションのファイアウォールに加えて NAT ゲートウェイを設定します。

警告: 記述されているルールは順番通りに実行してください。リモートマシンにログインしている場合、ルールを設定している間にマシンから閉めだされてしまう可能性があります。以下の手順に従うのはローカルでログインしている場合に限ります。サンプル設定ファイルを使うことでこの問題を回避することが可能です。

前提要件

ノート: iptables のサポートを有効にしてカーネルがコンパイルされている必要があります。Arch Linux の標準カーネルには iptables のサポートが含まれています。

まず、ユーザーランドユーティリティ iptables をインストールしてください。もしくは既にインストール済みかどうか確認してください。

この記事では iptables のルールセットが全く存在しないことを前提としています。現在のルールセットをチェックして、ルールが存在しないことを確認するには、次を実行:

# iptables-save
# Generated by iptables-save v1.4.19.1 on Thu Aug  1 19:28:53 2013
*filter
:INPUT ACCEPT [50:3763]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [30:3472]
COMMIT
# Completed on Thu Aug  1 19:28:53 2013

もしくは

# iptables -nvL --line-numbers
Chain INPUT (policy ACCEPT 156 packets, 12541 bytes)
num   pkts bytes target     prot opt in     out     source               destination

Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
num   pkts bytes target     prot opt in     out     source               destination

Chain OUTPUT (policy ACCEPT 82 packets, 8672 bytes)
num   pkts bytes target     prot opt in     out     source               destination

ルールが存在する場合、デフォルトのルールセットをロードすることでルールをリセットすることが可能です:

# iptables-restore < /etc/iptables/empty.rules

もしくは、Iptables#ルールをリセットする を参照。

シングルマシン用のファイアウォール

ノート: iptables はチェインの上から下の順番でルールを処理していくため、よくヒットするルールをチェインの初めに置くことを推奨します。もちろん、実行されるロジックによって制約は出て来ます。また、ルールにはランタイムコストもあるため、バイト/パケット数のカウンタだけを見てルールの順番を並び替えるのは賢いとは言えません。

必要なチェインの作成

基本的なセットアップとして、2つのユーザー定義チェインを作成し、それを使ってファイアウォールのポートを開きます。

# iptables -N TCP
# iptables -N UDP

もちろんチェインの名前は何でもかまいません。ここでは後のルールで使用するプロトコルに沿うように名前を決めています。

FORWARD チェイン

マシンを NAT ゲートウェイとしてセットアップしたい場合、#NAT ゲートウェイの設定を見て下さい。シングルマシンの場合、FORWARD チェインのポリシーをとりあえず DROP に設定して先に進みます:

# iptables -P FORWARD DROP

OUTPUT チェイン

送信トラフィックはフィルタリングしません。セットアップがとても複雑になってしまい、いろいろと考える必要が出てくるからです。ここではシンプルに、OUTPUT ポリシーを ACCEPT に設定します。

# iptables -P OUTPUT ACCEPT

INPUT チェイン

上記のチェインと同じように、勝手にルールを通過してしまわないように INPUT チェインのデフォルトポリシーは DROP に設定します。セキュアなファイアウォールを設定するときは、全てのトラフィックをドロップしてから、許可するトラフィックを指定するのがベストです。

警告: SSH でログインしている場合、以下の設定をすると SSH セッションが即座に切断されます。切断されないようにするには: (1) 下の INPUT チェインのルールを先に追加 (それでセッションが開いたままになります), (2) インバウンド SSH を許可するルールを追加 (接続が終了した場合に再接続できるようにするため) (3) ポリシーを設定。
# iptables -P INPUT DROP

あらゆるネットワークインターフェイスから受信されたパケットは全て INPUT チェインをまず通過します (パケットの送信先が対象のマシンになっている場合)。このチェインの中では、問題ないと思われるパケットだけを許可するようにします。

INPUT チェインにはまず、確立済みの接続に属するトラフィックや、ICMP エラーまたはエコー応答 (ping されたときにホストが返すパケット) などの接続に関連する正当なトラフィックを許可するルールを追加します。ICMPInternet Control Message Protocol の略です。ICMP メッセージは輻輳制御や MTU にとても重要なので、このルールによって通してやります。

The connection state ESTABLISHED implies that either another rule previously allowed the initial (--ctstate NEW) connection attempt or the connection was already active (for example an active remote SSH connection) when setting the rule:

# iptables -A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT

次のルールでは "loopback" (lo) インターフェイスからのトラフィックを全て許可します。多くのアプリケーションやサービスで必須となります。

ノート: You can add more trusted interfaces here such as "eth1" if you do not want/need the traffic filtered by the firewall, but be warned that if you have a NAT setup that redirects any kind of traffic to this interface from anywhere else in the network (let's say a router), it'll get through, regardless of any other settings you may have.
# iptables -A INPUT -i lo -j ACCEPT

The third rule will drop all traffic with an "INVALID" state match. Traffic can fall into four "state" categories: NEW, ESTABLISHED, RELATED or INVALID and this is what makes this a "stateful" firewall rather than a less secure "stateless" one. States are tracked using the "nf_conntrack_*" kernel modules which are loaded automatically by the kernel as you add rules.

ノート:
  • This rule will drop all packets with invalid headers or checksums, invalid TCP flags, invalid ICMP messages (such as a port unreachable when we did not send anything to the host), and out of sequence packets which can be caused by sequence prediction or other similar attacks. The "DROP" target will drop a packet without any response, contrary to REJECT which politely refuses the packet. We use DROP because there is no proper "REJECT" response to packets that are INVALID, and we do not want to acknowledge that we received these packets.
  • ICMPv6 Neighbor Discovery packets remain untracked, and will always be classified "INVALID" though they are not corrupted or the like. Keep this in mind, and accept them before this rule! iptables -A INPUT -p 41 -j ACCEPT
# iptables -A INPUT -m conntrack --ctstate INVALID -j DROP

The next rule will accept all new incoming ICMP echo requests, also known as pings. Only the first packet will count as NEW, the rest will be handled by the RELATED,ESTABLISHED rule. Since the computer is not a router, no other ICMP traffic with state NEW needs to be allowed.

# iptables -A INPUT -p icmp --icmp-type 8 -m conntrack --ctstate NEW -j ACCEPT

Now we attach the TCP and UDP chains to the INPUT chain to handle all new incoming connections. Once a connection is accepted by either TCP or UDP chain, it is handled by the RELATED/ESTABLISHED traffic rule. The TCP and UDP chains will either accept new incoming connections, or politely reject them. New TCP connections must be started with SYN packets.

ノート: NEW but not SYN is the only invalid TCP flag not covered by the INVALID state. The reason is because they are rarely malicious packets, and they should not just be dropped. Instead, we simply do not accept them, so they are rejected with a TCP RST by the next rule.
# iptables -A INPUT -p udp -m conntrack --ctstate NEW -j UDP
# iptables -A INPUT -p tcp --syn -m conntrack --ctstate NEW -j TCP

We reject TCP connections with TCP RST packets and UDP streams with ICMP port unreachable messages if the ports are not opened. This imitates default Linux behavior (RFC compliant), and it allows the sender to quickly close the connection and clean up.

# iptables -A INPUT -p udp -j REJECT --reject-with icmp-port-unreachable
# iptables -A INPUT -p tcp -j REJECT --reject-with tcp-rst

For other protocols, we add a final rule to the INPUT chain to reject all remaining incoming traffic with icmp protocol unreachable messages. This imitates Linux's default behavior.

# iptables -A INPUT -j REJECT --reject-with icmp-proto-unreachable

iptables.rules のサンプルファイル

上記のコマンドを全て実行した時に作成される iptables.rules ファイルの例:

/etc/iptables/iptables.rules
# Generated by iptables-save v1.4.18 on Sun Mar 17 14:21:12 2013
*filter
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [0:0]
:TCP - [0:0]
:UDP - [0:0]
-A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -m conntrack --ctstate INVALID -j DROP
-A INPUT -p icmp -m icmp --icmp-type 8 -m conntrack --ctstate NEW -j ACCEPT
-A INPUT -p udp -m conntrack --ctstate NEW -j UDP
-A INPUT -p tcp --tcp-flags FIN,SYN,RST,ACK SYN -m conntrack --ctstate NEW -j TCP
-A INPUT -p udp -j REJECT --reject-with icmp-port-unreachable
-A INPUT -p tcp -j REJECT --reject-with tcp-reset
-A INPUT -j REJECT --reject-with icmp-proto-unreachable
COMMIT
# Completed on Sun Mar 17 14:21:12 2013

このファイルは次のコマンドで生成できます:

# iptables-save > /etc/iptables/iptables.rules

and can be used to continue with the following sections. If you are setting up the firewall remotely via SSH, append the following rule to allow new SSH connections before continuing (adjust port as required):

-A TCP -p tcp --dport 22 -j ACCEPT

TCP と UDP チェイン

The TCP and UDP chains contain rules for accepting new incoming TCP connections and UDP streams to specific ports.

ノート: This is where you need to add rules to accept incoming connections, such as SSH, HTTP or other services that you want to access remotely.

接続要求でポートを開く

ウェブサーバーへの TCP 接続を許可するには (ポート 80):

# iptables -A TCP -p tcp --dport 80 -j ACCEPT

ウェブサーバーへの TCP 接続 (HTTPS) を許可するには (ポート 443):

# iptables -A TCP -p tcp --dport 443 -j ACCEPT

SSH のリモート接続を許可するには (ポート 22):

# iptables -A TCP -p tcp --dport 22 -j ACCEPT

DNS サーバーへの UDP ストリームを許可するには (ポート 53):

# iptables -A UDP -p udp --dport 53 -j ACCEPT

複数のポートにマッチするような、高度なルールについては man iptables を見て下さい。

ポートノッキング

Port knocking is a method to externally open ports that, by default, the firewall keeps closed. It works by requiring connection attempts to a series of predefined closed ports. When the correct sequence of port "knocks" (connection attempts) is received, the firewall opens certain port(s) to allow a connection. See Port Knocking for more information.

なりすまし攻撃からの防護

ノート: 現在 rp_filter はデフォルトで /usr/lib/sysctl.d/50-default.conf1 に設定されているため、以下の手順は必要ありません。

Blocking reserved local addresses incoming from the internet or local network is normally done through setting rp_filter (Reverse Path Filter) in sysctl to 1. To do so, add the following line to your /etc/sysctl.d/90-firewall.conf file (see sysctl for details) to enable source address verification which is built into Linux kernel itself. The verification by the kernel will handle spoofing better than individual iptables rules for each case.

net.ipv4.conf.all.rp_filter=1

Only when asynchronous routing or rp_filter=0 is used, extra checks are necessary:

# iptables -I INPUT ! -i lo -s 127.0.0.0/8 -j DROP

コンピュータを"隠匿"する

If you are running a desktop machine, it might be a good idea to block some incoming requests.

ping リクエストのブロック

A 'Ping' request is an ICMP packet sent to the destination address to ensure connectivity between the devices. If your network works well, you can safely block all ping requests. It is important to note that this does not actually hide your computer — any packet sent to you is rejected, so you will still show up in a simple nmap "ping scan" of an IP range.

This is rudimentary "protection" and makes life difficult when debugging issues in the future. You should only do this for education purposes.

To block echo requests, add the following line to your /etc/sysctl.d/90-firewall.conf file (see sysctl for details):

net.ipv4.icmp_echo_ignore_all = 1

Rate-limiting is a better way to control possible abuse. This first method implements a global limit (ie, only X packets per minute for all source addresses):

# iptables -A INPUT -p icmp --icmp-type echo-request -m limit --limit 30/min --limit-burst 8 -j ACCEPT
# iptables -A INPUT -p icmp --icmp-type echo-request -j DROP

Or using the 'recent' module, you can impose a limit per source address:

# iptables -A INPUT -p icmp --icmp-type echo-request -m recent --name ping_limiter --set
# iptables -A INPUT -p icmp --icmp-type echo-request -m recent --name ping_limiter --update --hitcount 6 --seconds 4 -j DROP
# iptables -A INPUT -p icmp --icmp-type echo-request -j ACCEPT

If you choose to use either the rate limiting or the source limiting rules the PING rule that already exists in the INPUT chain needs to be deleted. This can be done as shown below, or alternatively don't use it in the first place.

# iptables -D INPUT -p icmp --icmp-type 8 -m conntrack --ctstate NEW -j ACCEPT

Next you need to decide where you wish to place the rate limiting or source limiting rules. If you place the rules below the RELATED,ESTABLISHED rule then you will be counting and limiting new ping connections, not each ping sent to your machine. If you place them before the RELATED,ESTABLISHED rule then these rules will count and limit each ping sent to your machine, not each ping connection made.

More information is in the iptables man page, or reading the docs and examples on the webpage http://snowman.net/projects/ipt_recent/

ポートスキャナを騙す

ノート: This opens you up to a form of DoS. An attack can send packets with spoofed IPs and get them blocked from connecting to your services.

Port scans are used by attackers to identify open ports on your computer. This allows them to identify and fingerprint your running services and possibly launch exploits against them.

The INVALID state rule will take care of every type of port scan except UDP, ACK and SYN scans (-sU, -sA and -sS in nmap respectively).

ACK scans are not used to identify open ports, but to identify ports filtered by a firewall. Due to the SYN check for all TCP connections with the state NEW, every single packet sent by an ACK scan will be correctly rejected by a TCP RST packet. Some firewalls drop these packets instead, and this allows an attacker to map out the firewall rules.

The recent module can be used to trick the remaining two types of port scans. The recent module is used to add hosts to a "recent" list which can be used to fingerprint and stop certain types of attacks. Current recent lists can be viewed in /proc/net/xt_recent/.

SYN スキャン

In a SYN scan, the port scanner sends SYN packet to every port. Closed ports return a TCP RST packet, or get dropped by a strict firewall. Open ports return a SYN ACK packet regardless of the presence of a firewall.

The recent module can be used to keep track of hosts with rejected connection attempts and return a TCP RST for any SYN packet they send to open ports as if the port was closed. If an open port is the first to be scanned, a SYN ACK will still be returned, so running applications such as ssh on non-standard ports is required for this to work consistently.

First, insert a rule at the top of the TCP chain. This rule responds with a TCP RST to any host that got onto the TCP-PORTSCAN list in the past sixty seconds. The --update switch causes the recent list to be updated, meaning the 60 second counter is reset.

# iptables -I TCP -p tcp -m recent --update --seconds 60 --name TCP-PORTSCAN -j REJECT --reject-with tcp-rst

Next, the rule for rejecting TCP packets need to be modified to add hosts with rejected packets to the TCP-PORTSCAN list.

# iptables -D INPUT -p tcp -j REJECT --reject-with tcp-rst
# iptables -A INPUT -p tcp -m recent --set --name TCP-PORTSCAN -j REJECT --reject-with tcp-rst
UDP スキャン

UDP port scans are similar to TCP SYN scans except that UDP is a "connectionless" protocol. There are no handshakes or acknowledgements. Instead, the scanner sends UDP packets to each UDP port. Closed ports should return ICMP port unreachable messages, and open ports do not return a response. Since UDP is not a "reliable" protocol, the scanner has no way of knowing if packets were lost, and has to do multiple checks for each port that does not return a response.

The Linux kernel sends out ICMP port unreachable messages very slowly, so a full UDP scan against a Linux machine would take over 10 hours. However, common ports could still be identified, so applying the same countermeasures against UDP scans as SYN scans is a good idea.

First, add a rule to reject packets from hosts on the UDP-PORTSCAN list to the top of the UDP chain.

# iptables -I UDP -p udp -m recent --update --seconds 60 --name UDP-PORTSCAN -j REJECT --reject-with icmp-port-unreachable

Next, modify the reject packets rule for UDP:

# iptables -D INPUT -p udp -j REJECT --reject-with icmp-port-unreachable
# iptables -A INPUT -p udp -m recent --set --name UDP-PORTSCAN -j REJECT --reject-with icmp-port-unreachable
最終的なルールのリストア

If either or both of the portscanning tricks above were used the final default rule is no longer the last rule in the INPUT chain. It needs to be the last rule otherwise it will intercept the trick port scanner rules you just added and they will never be used. Simply delete the rule (-D), then add it once again using append (-A) which will place it at the end of the chain.

# iptables -D INPUT -j REJECT --reject-with icmp-proto-unreachable
# iptables -A INPUT -j REJECT --reject-with icmp-proto-unreachable

他の攻撃からの防護

関連するカーネルパラメータは sysctl#TCP/IP スタックの防御 に載っています。

ブルートフォース攻撃

Unfortunately, bruteforce attacks on services accessible via an external IP address are common. One reason for this is that the attacks are easy to do with the many tools available. Fortunately, there are a number of ways to protect the services against them. One is the use of appropriate iptables rules which activate and blacklist an IP after a set number of packets attempt to initiate a connection. Another is the use of specialised daemons that monitor the logfiles for failed attempts and blacklist accordingly.

警告: Using an IP blacklist will stop trivial attacks but it relies on an additional daemon and successful logging (the partition containing /var can become full, especially if an attacker is pounding on the server). Additionally, if the attacker knows your IP address, they can send packets with a spoofed source header and get you locked out of the server. SSH keys provide an elegant solution to the problem of brute forcing without these problems.

Two packages that ban IPs after too many password failures are Fail2ban or, for sshd in particular, Sshguard. These two applications update iptables rules to reject future connections from blacklisted IP addresses.

The following rules give an example configuration to mitigate SSH bruteforce attacks using iptables.

# iptables -N IN_SSH
# iptables -A INPUT -p tcp --dport ssh -m conntrack --ctstate NEW -j IN_SSH
# iptables -A IN_SSH -m recent --name sshbf --rttl --rcheck --hitcount 3 --seconds 10 -j DROP
# iptables -A IN_SSH -m recent --name sshbf --rttl --rcheck --hitcount 4 --seconds 1800 -j DROP 
# iptables -A IN_SSH -m recent --name sshbf --set -j ACCEPT

Most of the options should be self-explanatory, they allow for three connection packets in ten seconds. Further tries in that time will blacklist the IP. The next rule adds a quirk by allowing a total of four attempts in 30 minutes. This is done because some bruteforce attacks are actually performed slow and not in a burst of attempts. The rules employ a number of additional options. To read more about them, check the original reference for this example: compilefailure.blogspot.com

Using the above rules, now ensure that:

# iptables -A INPUT -p tcp --dport ssh -m conntrack --ctstate NEW -j IN_SSH

is in an appropriate position in the iptables.rules file.

This arrangement works for the IN_SSH rule if you followed this entire wiki so far:

*
-A INPUT -p icmp -m icmp --icmp-type 8 -m conntrack --ctstate NEW -j ACCEPT
-A INPUT -p tcp --dport 22 -m conntrack --ctstate NEW -j IN_SSH
-A INPUT -p udp -m conntrack --ctstate NEW -j UDP
*

The above rules can, of course, be used to protect any service, though protecting the SSH daemon is probably the most often required one.

ヒント: For self-testing the rules after setup, the actual blacklist happening can slow the test making it difficult to fine-tune parameters. One can watch the incoming attempts via cat /proc/net/xt_recent/sshbf. To unblock the own IP during testing, root is needed # echo / > /proc/net/xt_recent/sshbf

ルールの保存

ルールセットの設定が完了したら、ハードドライブに保存して、マシンを起動する度にロードされるようにします。

ルールの設定を保存する場所は systemd のユニットファイルで指定します:

iptables=/etc/iptables/iptables.rules
ip6tables=/etc/iptables/ip6tables.rules

次のコマンドでルールを保存します:

# iptables-save > /etc/iptables/iptables.rules

そして iptables デーモンを有効化して、起動時にルールがロードされるようにしてください。

ルールが正しくロードされているか確認するには次のコマンドを使用:

# systemctl start iptables.service && systemctl status iptables.service

IPv6

IPv6 を使用しない場合 (ほとんどの ISP は IPv6 をサポートしていません)、無効化したほうが良いでしょう。

Otherwise, you should enable the firewall rules for IPv6. After copying the IPv4 rules as a base:

# cp /etc/iptables/iptables.rules /etc/iptables/ip6tables.rules

the first step is to change IPs referenced in the rules from IPv4 format to IPv6 format.

Next, a few of the rules (built as example in this article for IPv4) have to be adapted. IPv6 obtained a new ICMPv6 protocol, replacing ICMP. Hence, the reject error return codes --reject-with icmp-port-unreachable and --reject-with icmp-proto-unreachable have to be converted to ICMPv6 codes.

The available ICMPv6 error codes are listed in RFC 4443, which specifies connection attempts blocked by a firewall rule should use --reject-with icmp6-adm-prohibited. Doing so will basically inform the remote system that the connection was rejected by a firewall, rather than a listening service.

If it is preferred not to explicitly inform about the existence of a firewall filter, the packet may also be rejected without the message:

 -A INPUT -j REJECT

The above will reject with the default return error of --reject-with-icmp6-port-unreachable. You should note though, that identifying a firewall is a basic feature of port scanning applications and most will identify it regardless.

In the next step make sure the protocol and extension are changed to be IPv6 appropriate for the rule regarding all new incoming ICMP echo requests (pings):

# ip6tables -A INPUT -p icmpv6 --icmpv6-type 128 -m conntrack --ctstate NEW -j ACCEPT

Netfilter conntrack does not appear to track ICMPv6 Neighbor Discovery Protocol (the IPv6 equivalent of ARP), so we need to allow ICMPv6 traffic regardless of state for all directly attached subnets. The following should be inserted after dropping --ctstate INVALID, but before any other DROP or REJECT targets, along with a corresponding line for each directly attached subnet:

# ip6tables -A INPUT -s fe80::/10 -p icmpv6 -j ACCEPT

Since there is no kernel reverse path filter for IPv6, you may want to enable one in ip6tables with the following, the first rule is necessary to retain usually needed link local ICMPv6 unicasts:

# ip6tables -t raw -A PREROUTING -p icmpv6 -s fe80::/10 -j ACCEPT
# ip6tables -t raw -A PREROUTING -m rpfilter -j ACCEPT
# ip6tables -t raw -A PREROUTING -j DROP

After the configuration is done, enable the ip6tables service, it is meant to run in parallel to iptables.

NAT ゲートウェイの設定

This section of the guide deals with NAT gateways. It is assumed that you already read the first part of the guide and set up the INPUT, OUTPUT, TCP and UDP chains like described above. All rules so far have been created in the filter table. In this section, we will also have to use the nat table.

フィルターテーブルの設定

必要なチェインの作成

In our setup, we will use another two chains in the filter table, the fw-interfaces and fw-open chains. Create them with the commands

# iptables -N fw-interfaces
# iptables -N fw-open

FORWARD チェインの設定

Setting up the FORWARD chain is similar to the INPUT chain in the first section.

Now we set up a rule with the conntrack match, identical to the one in the INPUT chain:

# iptables -A FORWARD -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT

The next step is to enable forwarding for trusted interfaces and to make all packets pass the fw-open chain.

# iptables -A FORWARD -j fw-interfaces 
# iptables -A FORWARD -j fw-open 

The remaining packets are denied with an ICMP message:

# iptables -A FORWARD -j REJECT --reject-with icmp-host-unreachable
# iptables -P FORWARD DROP

fw-interfaces と fw-open チェインの設定

The meaning of the fw-interfaces and fw-open chains is explained later, when we deal with the POSTROUTING and PREROUTING chains in the nat table, respectively.

nat テーブルの設定

All over this section, we assume that the outgoing interface (the one with the public internet IP) is ppp0. Keep in mind that you have to change the name in all following rules if your outgoing interface has another name.

POSTROUTING チェインの設定

Now, we have to define who is allowed to connect to the internet. Let's assume we have the subnet 192.168.0.0/24 (which means all addresses that are of the form 192.168.0.*) on eth0. We first need to accept the machines on this interface in the FORWARD table, that is why we created the fw-interfaces chain above:

# iptables -A fw-interfaces -i eth0 -j ACCEPT

Now, we have to alter all outgoing packets so that they have our public IP address as the source address, instead of the local LAN address. To do this, we use the MASQUERADE target:

# iptables -t nat -A POSTROUTING -s 192.168.0.0/24 -o ppp0 -j MASQUERADE

Do not forget the -o ppp0 parameter above. If you omit it, your network will be screwed up.

Let's assume we have another subnet, 10.3.0.0/16 (which means all addresses 10.3.*.*), on the interface eth1. We add the same rules as above again:

# iptables -A fw-interfaces -i eth1 -j ACCEPT
# iptables -t nat -A POSTROUTING -s 10.3.0.0/16 -o ppp0 -j MASQUERADE

The last step is to enable IP Forwarding (if it is not already enabled):

# echo 1 > /proc/sys/net/ipv4/ip_forward

Then edit the relevant line in /etc/sysctl.d/90-firewall.conf so it persists through reboot (see sysctl for details):

net.ipv4.ip_forward = 1

Machines from these subnets can now use your new NAT machine as their gateway. Note that you may want to set up a DNS and DHCP server like dnsmasq or a combination of bind and dhcpd to simplify network settings DNS resolution on the client machines. This is not the topic of this guide.

PREROUTING チェインの設定

Sometimes, we want to change the address of an incoming packet from the gateway to a LAN machine. To do this, we use the fw-open chain defined above, as well as the PREROUTING chain in the nat table in the following two simple examples.

First, we want to change all incoming SSH packets (port 22) to the ssh server of the machine 192.168.0.5:

# iptables -t nat -A PREROUTING -i ppp0 -p tcp --dport 22 -j DNAT --to 192.168.0.5
# iptables -A fw-open -d 192.168.0.5 -p tcp --dport 22 -j ACCEPT

The second example will show you how to change packets to a different port than the incoming port. We want to change any incoming connection on port 8000 to our web server on 192.168.0.6, port 80:

# iptables -t nat -A PREROUTING -i ppp0 -p tcp --dport 8000 -j DNAT --to 192.168.0.6:80
# iptables -A fw-open -d 192.168.0.6 -p tcp --dport 80 -j ACCEPT

The same setup also works with udp packets.

ルールの保存

ルールを保存してください:

# iptables-save > /etc/iptables/iptables.rules

そして iptables デーモンを有効にすることで、起動時にルールがロードされるようにします。

参照