Iptables教程

iptables 是一個配置 Linux 內核 防火牆 的命令行工具。

初學者剛看到iptables,會感到很複雜,原因是 iptables 功能實在是太強大了。本文會從基本概念、使用上做介紹,讀者看完後再去看 iptables 命令就能理解其含義了。

本文環境:

PC: Ubuntu18

iptables操作均在docker上進行。docker上的系統為centos6.9。

更新時間:2020.6.26

工作原理

基本組成

想要掌握 iptables ,需要了解其原理。

iptables 組成:

Tables -> Chains -> Rules

表 (tables):

filter
nat
mangle
raw

每個 tables 有多個鏈 (Chains)


(圖片來自: //phoenixnap.com/)

其中鏈是可以自定義新建的,後文會介紹。

最終我們會對某個鏈添加 規則(rules) 。下面是一條由具體的指令,包含了 tables、chains、rules:

# 禁止172.18.0.3訪問
iptables -t filter -A INPUT -s "172.18.0.3" -j DROP

注: -t filter指的是指定對filter表操作,可以省略,默認就是 filter 表。本條指令看不懂也沒有關係,後文還會出現。

功能介紹

下面介紹各個表、鏈的基本功能。我們實際使用最多的是Filter表、NAT表,所以本文主要也是介紹這2個表。

Filter表

Filter表示iptables的默認表,如果沒有自定義表,那麼就默認使用filter表,它具有以下三種內建鏈:

  • INPUT鏈 – 處理來自外部的數據。
  • OUTPUT鏈 – 處理向外發送的數據。
  • FORWARD鏈 – 將數據轉發到本機的其他網卡設備上。

NAT表

NAT表有三種內建鏈:

  • PREROUTING鏈 – 處理剛到達本機並在路由轉發前的數據包。它會轉換數據包中的目標IP地址(destination ip address),通常用於DNAT(destination NAT)。
  • POSTROUTING鏈 – 處理即將離開本機的數據包。它會轉換數據包中的源IP地址(source ip address),通常用於SNAT(source NAT)。
  • OUTPUT鏈 – 處理本機產生的數據包。

Mangle表

Mangle表用於指定如何處理數據包。它能改變TCP頭中的QoS位。Mangle表具有5個內建鏈:

  • PREROUTING
  • OUTPUT
  • FORWARD
  • INPUT
  • POSTROUTING

Raw表

Raw表用於處理異常,它具有2個內建鏈:

  • PREROUTING chain
  • OUTPUT chain

數據包流向

下圖簡要描述了網路數據包通過 iptables 的過程:

(來自//wiki.archlinux.org/)

1、數據經由互聯網到達 nat 表的 PREROUTING

2、數據到達 filter表的INPUT

3、數據到達 本機

4、數據經由 filter表的OUTPUT

5、數據經由 nat 表的 POSTROUTING

6、數據到達互聯網。

7、我們也可以在數據到達 nat 表的 PREROUTING後,使用 filter表的FORWARD進行轉發。

理解數據包流向很重要,這樣我們就能很清楚的知道在哪個表哪個鏈增加對應的規則。

安裝iptables

iptables在大多數Linux系統上默認安裝,可以在命令行輸入iptables --version查看:

iptables --version
iptables v1.6.1

如果沒有該命令,可以自行安裝:

# ubuntu
sudo apt-get install iptables
sudo apt-get install iptables-persistent

# centos6
sudo yum –y install iptables-services

# centos7
# 在CentOS 7中,iptables替換為firewalld。
# 要安裝iptables,首先您需要停止firewalld。輸入以下命令:
sudo systemctl stop firewalld
sudo systemctl disable firewalld
sudo systemctl mask firewalld
# 接下來,安裝並啟用iptables。首先,使用以下命令安裝iptables服務軟體包:
sudo yum –y install iptables-services
sudo systemctl enable iptables
sudo systemctl start iptables

如果需要在 docker 上體驗 iptables :

# pull
docker pull daocloud.io/library/centos:centos6.9
docker tag daocloud.io/library/centos:centos6.9 centos6.9
# 啟動需要加上 -privileged
docker run -it --privileged --name centos-1  centos6.9 /bin/bash
# 安裝iptables
yum install initscripts

配置命令

iptables命令參數非常多。我們分為:配置命令、匹配條件、動作選項、模組選項,這樣便於記憶。

  • 配置命令 指的ACDIF等命令,都是大寫開頭的簡稱,且一般不可省略,例如-A新增規則、-D刪除規則。

  • 匹配條件 一般是小寫,例如-t指定table,-i指定網卡介面,這些條件一般是可選的。

  • 動作選項 指的是-j指定的動作,可選值有:DROP、ACCEPT等。

  • 模組選項 指的是-m指定的參數。

本節主要介紹配置命令。

iptables配置命令如下所示:

iptables [option] CHAIN_rule [-j target]

以下是一些常用iptables選項的列表:

  • –A, ––append 將規則添加到鏈中(最後)。
  • –I, ––insert 將規則添加到給定位置的鏈中。
  • –C, ––check 尋找符合鏈條要求的規則。
  • –D, ––delete 從鏈中刪除指定的規則。
  • –F, ––flush 刪除對應表的所有規則,慎重使用
  • –L, ––list 連鎖顯示所有規則。
  • –v, ––verbose 使用列表選項時顯示更多資訊。
  • -P, --policy 設置鏈的默認策略(policy)
  • -N, --new 創建用戶自定義鏈
  • -X, --delete-chain 刪除用戶自定義鏈
  • -E, --rename-chain 重命名用戶自定義鏈

iptables區分大小寫,因此請確保使用正確的選項。更多參數可以輸入iptables --help查看。

查看規則(-L)

# 查看filter表的規則
iptables –L

# 同iptables –L
# -t條件指定table
iptables -t filter –L

上述命令執行後,系統顯示鏈條的狀態。輸出將列出三個鏈:

Chain INPUT (policy ACCEPT)
target     prot opt source               destination         
DROP       all  --  172.18.0.4           anywhere            
DROP       all  --  172.18.0.5           anywhere           

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination         

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination

FORWARD、OUTPUT為空,沒有定義規則;INPUT有三條規則:禁止來自 172.18.0.4 -172.18.0.5 任何協議的請求,相當於加了黑名單。

# 更詳細的輸出
# -n 以數字的形式展示地址和埠
# -v 啰嗦模式
# --line-numbers 列印鏈的序號,後面刪除需要用到該序號。最先添加的規則序號最小
iptables -vnL --line-numbers

輸出示例:

Chain INPUT (policy ACCEPT 9 packets, 621 bytes)
num   pkts bytes target     prot opt in     out     source               destination       
1        0     0 DROP       all  --  eth0   *       172.18.0.4           0.0.0.0/0         
2        0     0 DROP       all  --  eth0   *       172.18.0.5           0.0.0.0/0         

...

新增規則(-A)

-A <鏈名>
    APPEND,追加一條規則(放到最後)

示例:

# -i條件指定網卡介面
# -s條件指定數據包的源地址
# -j指定動作選項為DROP,丟棄數據
iptables -A INPUT -i eth0 -s 172.18.0.3 -j DROP

上面的命令會在 filter 表的 INPUT 鏈里追加一條規則:對於來自172.18.0.3經由 eth0介面的數據,直接丟棄。

我們可以在另一台機器 172.18.0.3訪問當前機器:

$ ping 172.18.0.2
PING 172.18.0.2 (172.18.0.2) 56(84) bytes of data.
...

發現訪問被拒絕了。

# 將eth0的數據路由到eht1
iptables -A FORWARD -i eth0 -o eth1 -j ACCEPT

刪除規則(-D)

可以按規則號或者規則內容匹配。默認filter表。

-D <鏈名> <規則號碼 | 具體規則內容>
    DELETE,刪除一條規則

先查看規則:

$ iptables -L --line-numbers
Chain INPUT (policy ACCEPT)
num  target     prot opt source               destination         
1    DROP       all  --  172.18.0.4           anywhere            
2    DROP       all  --  172.18.0.5           anywhere            
3    DROP       all  --  172.18.0.6           anywhere
4    DROP       all  --  172.18.0.3           anywhere
...

1、按規則號(num)刪除規則3:

將刪除 filter 表 INPUT 鏈中的第三條規則(不管它的內容是什麼)

$ iptables -D INPUT 3

$ iptables -L --line-numbers
Chain INPUT (policy ACCEPT)
num  target     prot opt source               destination         
1    DROP       all  --  172.18.0.4           anywhere            
2    DROP       all  --  172.18.0.5           anywhere            
3    DROP       all  --  172.18.0.3           anywhere
...

2、按內容匹配刪除:

​ 刪除 filter 表 INPUT 鏈中內容為-s 172.18.0.5 -i eth0 -j DROP的規則 (不管其位置在哪裡)

$ iptables -D INPUT -s 172.18.0.5 -i eth0 -j DROP

$ iptables -L --line-numbers
Chain INPUT (policy ACCEPT)
num  target     prot opt source               destination         
1    DROP       all  --  172.18.0.4           anywhere            
2    DROP       all  --  172.18.0.3           anywhere
...

建議還是指定規則號刪除,以免誤刪。

插入規則(-I)

最終也是實現規則的新增。需要指定規則號,默認的規則號是1,也就是插入到第1條。默認filter表。

-I <鏈名> [規則號碼]
    INSERT,插入一條規則
$ iptables -I INPUT 3 -s 172.18.0.6  -j DROP

$ iptables -L --line-numbers
Chain INPUT (policy ACCEPT)
num  target     prot opt source               destination         
1    DROP       all  --  172.18.0.4           anywhere            
2    DROP       all  --  172.18.0.3           anywhere            
3    DROP       all  --  172.18.0.6           anywhere
...

注意:

  • 規則號碼必須緊跟著 -I INPUT
  • 規則號碼如果預設,那麼就是1,插入的規則成為第1條規則。
  • 規則號碼最大值是已有規則數+1。

小結:-A是在所有的規則的最後面增加規則,而-I可以在任意位置增加規則。

替換規則(-R)

-R <鏈名> <規則號碼> <具體規則內容>
    REPLACE,替換一條規則

命令格式和-I類似。

$ iptables -R INPUT 3 -s 172.18.0.6 -j ACCEPT
$ iptables -L --line-numbers
Chain INPUT (policy ACCEPT)
num  target     prot opt source               destination         
1    DROP       all  --  172.18.0.4           anywhere            
2    DROP       all  --  172.18.0.3           anywhere            
3    ACCEPT     all  --  172.18.0.6           anywhere
... 

設置默認規則(-P)

用於某個鏈的默認規則。當數據包沒有被規則列表裡的任何規則匹配到時,按此默認規則處理。可選值: DROP、ACCEPT。

-P <鏈名> <動作>
    POLICY,設置某個鏈的默認規則

兩種默認策略導致的不同結果:

  • 默認策略DROP,需要逐條允許。一般伺服器上都是這麼設置的,僅開放部分埠或者白名單,其他全部拒絕。
  • 默認策略ACCEPT,需要逐條拒絕。

配置默認鏈策略為拒絕:

iptables -P INPUT DROP 
iptables -P FORWARD DROP 
iptables -P OUTPUT DROP 

如果防火牆之前沒有任何配置,當上面的命令執行後,如果你當前是使用ssh連接的伺服器,你會發現你被踢出來了,然後連不上了。。。

所以:遠程設置時不要一開始就寫這幾句默認策略,會把自己踢出伺服器,應該最後設定

清除規則(-F)

清除所有規則。可以指定表、鏈。默認filter表。

iptables -F

將清除fliter錶鏈中所有規則,但並不影響 -P 設置的默認規則。其它示例:

# 清空 filter 表 INPUT 鏈中的所有規則
iptables -t filter -F INPUT
  • -P 設置了 DROP 後,使用 -F 一定要小心。因為相當於把所有ACCEPT的都清除了,會導致ssh連接不上。
  • 如果不寫鏈名,默認清空某表裡所有鏈里的所有規則。

保存規則

用iptables命令寫的規則都是立即生效的,但只是臨時的。

我們可以使用iptables-save查看系統現在有哪些規則。該命令不同於iptables -L,可以列印出所有的規則,而且與我們輸入的是一樣的:

$ iptables-save

# Generated by iptables-save v1.4.7 on Thu Jun 25 10:53:55 2020
*nat
:PREROUTING ACCEPT [3817:370531]
:INPUT ACCEPT [2:168]
:OUTPUT ACCEPT [56:3864]
:POSTROUTING ACCEPT [112:7728]
:DOCKER_OUTPUT - [0:0]
:DOCKER_POSTROUTING - [0:0]
-A PREROUTING -p tcp -m tcp --dport 80 -j DNAT --to-destination 172.18.0.3:80 
-A PREROUTING -p tcp -m tcp --dport 81 -j DNAT --to-destination 172.18.0.3:80 
... 
*filter
:INPUT ACCEPT [3278:275037]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [3278:275037]
...

該命令執行後並不會保存,我們可以直觀的看到各表有哪些鏈、哪些規則。需要注意的是列印出的規則省略了iptables -t xxx命令。

CentOS6.9可以使用service iptables save命令保存臨時防火牆規則:

$ service iptables save
iptables: Saving firewall rules to /etc/sysconfig/iptables:[  OK  ]

該命令保存的內容就是我們使用iptables-save列印出來的內容。

如果系統使用的systemd,上述的操作可能無效。

其他系統參考:

匹配條件選項

-p 協議類型 (–protocol)

用於指定規則的協議,如tcp, udp, icmp等,可以使用all來指定所有協議。如果不指定-p參數,則默認是all值。

也可以使用協議名(如tcp),或者是協議值(比如6代表tcp)來指定協議。映射關係請查看/etc/protocols

# 禁止目標IP的ping協議
iptables -A INPUT -s 172.18.0.3 -p icmp  -j DROP

注意:因為禁用了從172.18.0.3(簡稱B機器)來的icmp協議,那麼當前機器也不能ping通機器B,原因是收不到響應數據。但是機器B確實能收到請求,可以在機器B上執行抓包tcpdump -i eth0 icmp

-s 源地址 (–source)

用於指定數據包的源地址。參數可以使IP地址、網路地址、主機名。例如:

  • -s 192.168.0.1 匹配來自 192.168.0.1 的數據包
  • -s 192.168.1.0/24 匹配來自 192.168.1.0/24 網路的數據包
  • -s 192.168.0.0/16 匹配來自 192.168.0.0/16 網路的數據包
  • ! -s 192.168.1.101除這個IP外

如果不指定-s參數,就代表所有地址。

192.168.1.10/24代表192.168.1.0-192.168.1.255網段,24表示網路號佔用24位二進位,剩餘8位二進位可以表示 2^8位主機。可以使用//www.sojson.com/convert/subnetmask.html 工具計算網段。

-d 目的地址 (–destination)

用於指定目的地址。參數和-s相同。

例如:

  • -d 202.106.0.20 匹配去往 202.106.0.20 的數據包
  • -d 202.106.0.0/16 匹配去往 202.106.0.0/16 網路的數據包
  • -d www.abc.com 匹配去往域名 www.abc.com 的數據包

-j 執行目標 (–jump)

用於指定target。可能的值是ACCEPT, DROP, QUEUE, RETURN。也可以指定鏈(Chain)作為目標。後文會細講。

-i 輸入介面 (–in-interface)

用於指定要處理來自哪個介面的數據包,這些數據包即將進入INPUT, FORWARD, PREROUTE鏈。

例如:

  • -i eth0指定了要處理經由eth0進入的數據包。
  • 如果不指定-i參數,那麼將處理進入所有介面的數據包。
  • 如果出現! -i eth0,那麼將處理所有經由eth0以外的介面進入的數據包。
  • 如果出現-i eth +,那麼將處理所有經由eth開頭的介面進入的數據包。

-o 輸出 (–out-interface)

用於指定數據包由哪個介面輸出,這些數據包即將進入FORWARD, OUTPUT, POSTROUTING鏈。

  • 如果不指定-o選項,那麼系統上的所有介面都可以作為輸出介面。
  • 如果出現! -o eth0,那麼將從eth0以外的介面輸出。
  • 如果出現-i eth +,那麼將僅從eth開頭的介面輸出。

–sport 源埠 (–source-port)

針對-p tcp 或者 -p udp,不可單獨使用。

可以指定埠號或者埠名稱,例如–sport 22–sport ssh/etc/services文件描述了上述映射關係。但從性能上講,使用埠號更好。

使用冒號可以匹配埠範圍,如–sport 22:100

例如:

--sport 1000       匹配源埠是 1000 的數據包
--sport 1000:3000  匹配源埠是 1000-3000 的數據包(含1000、3000)
--sport :3000      匹配源埠是 3000 以下的數據包(含 3000)
--sport 1000:      匹配源埠是 1000 以上的數據包(含 1000)
# 允許外部的來自80埠的數據訪問本地伺服器
iptables -A INPUT -p tcp --sport 80 -j ACCEPT

–dport 目的埠 (–destination-port)

針對-p tcp 或者 -p udp。參數和–sport類似。

# 允許外部數據訪問本地伺服器80埠
iptables -A INPUT -p tcp --dport 80 -j ACCEPT

–tcp-flags TCP標誌

針對-p tcp 。可以指定由逗號分隔的多個參數。有效值可以是:SYN, ACK, FIN, RST, URG, PSH。可以使用ALL或者NONE

-–icmp-type ICMP類型

針對-p icmp

  • –icmp-type 0 表示 pong
  • –icmp-type 8 表示 ping

動作選項

-j參數支援下列動作選項:

  • ACCEPT
  • DROP
  • DNAT
  • SNAT
  • MASQUERADE
  • RETURN

ACCEPT

允許數據包通過本鏈而不攔截它。

例如:

# 允許來源地址為 172.18.0.3 的數據包進入本機
iptables -A INPUT -s 172.18.0.3 -j ACCEPT

DROP

阻止數據包通過本鏈,直接丟棄它。

例如:

# 阻止來源地址為 172.18.0.3 的數據包通過本機
iptables -A INPUT -s 172.18.0.3 -j DROP

DNAT

目的地址轉換。

1、原理:在路由前(PREROUTING)將來自外網訪問網關公網ip及對應埠的目的ip及埠修改為內部伺服器的ip及埠,實現發布內部伺服器。

2、應用場景:發布內部主機服務。

3、設置DNAT:網關主機上設置。

DNAT 支援轉換為單 IP,也支援轉換到 IP 地址池(一組連續的 IP 地址)。

編寫防火牆規則:

-j DNAT --to-destination 內網服務ip:埠

--to-destination等同於--to

例如:

# 把流入eth0 要訪問 TCP/80 的數據包目的地址轉發到 172.18.0.3
iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 80 -j DNAT --to 172.18.0.3

# 把從 eth0 進來的要訪問 TCP/81 的數據包目的地址改為 172.18.0.3:80
iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 81 -j DNAT --to 172.18.0.3:80
    
# 把從 eth0 進來的要訪問 TCP/80 的數據包目的地址改為地址池 172.18.0.3-172.18.0.10
iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 80 -j DNAT --to 172.18.0.3-172.18.0.10

DNAT作用於PREROUTING鏈,如果寫POSTOUTING,會報錯。

SNAT

源地址轉換。

1、原理:在路由器後(POSTROUTING)將內網的ip地址修改為外網網卡的ip地址。

2、應用場景:共享內部主機上網。

3、設置SNAT:網關主機進行設置。

源地址轉換即內網地址向外訪問時,發起訪問的內網ip地址轉換為指定的ip地址(可指定具體的服務以及相應的埠或埠範圍),這可以使內網中使用保留ip地址的主機訪問外部網路,即內網的多部主機可以通過一個有效的公網ip地址訪問外部網路。

SNAT 支援轉換為單 IP,也支援轉換到 IP 地址池(一組連續的 IP 地址)。

-j SNAT --to IP[-IP][:埠-埠](nat 表的 POSTROUTING 鏈)

例如:

# 將 172.18.0.3 的原地址修改為 172.18.0.2
iptables -t nat -A POSTROUTING -p tcp --dport 80 -d 172.18.0.3 -j SNAT  --to 172.18.0.2 

iptables -t nat -A POSTROUTING -p tcp --dport 80 -d 172.18.0.3 -j MASQUERADE 

# 將內網 172.18.0.1/24 的原地址修改為 1.1.1.1
iptables -t nat -A POSTROUTING -d 172.18.0.1/24  -j SNAT --to 1.1.1.1

# 同上,只不過修改成一個地址池裡的 IP
iptables -t nat -A POSTROUTING -d 172.18.0.1/24  -j SNAT --to 1.1.1.1-1.1.1.10

MASQUERADE

動態源地址轉換(動態 IP 的情況下使用)。

上面的小節里,配置SNAT的時候:

iptables -t nat -A POSTROUTING -p tcp --dport 80 -d 172.18.0.3 -j SNAT  --to 172.18.0.2

需要指定映射的目標地址-to 172.18.0.2。也可以使用MASQUERADE動態獲取:

iptables -t nat -A POSTROUTING -p tcp --dport 80 -d 172.18.0.3 -j MASQUERADE

如果IP地址不是固定的,使用這種方式會比較方便。

RETURN

返回主鏈繼續匹配。

比如:

# 如果請求的目標地址是本機的地址, 那麼將請求轉到 DOCKER 鏈處理
iptables -t nat -A PREROUTING -m addrtype --dst-type LOCAL -j DOCKER

# 由 docker0 設備傳入的請求 DOCKER 鏈會返回上一層處理
iptables -t nat -A DOCKER -i docker0 -j RETURN

這兩條規則將改變原有的數據包流向,會在 PREROUTING 前增加一個 DOCKER 鏈:

上圖詳見: 理解 Docker 網路(一) — Docker 對 宿主機網路環境的影響

模組選項

-m參數支援模組選項。

  • state: 按包狀態匹配
  • mac: 按來源 MAC 匹配
  • limit: 按包速率匹配
  • multiport: 多埠匹配
  • iprange: 按IP範圍匹配
  • string 按字元串限定

state

按包狀態匹配。

格式:

-m state --state 狀態

狀態:NEW、RELATED、ESTABLISHED、INVALID

  • NEW:新建連接請求的數據包,且該數據包沒有和任何已有連接相關聯。
  • ESTABLISHED:該連接是某NEW狀態連接的回包,也就是完成了連接的雙向關聯。
  • RELATED:衍生態,與 conntrack 關聯。簡而言之,A連接已經是ESTABLISHED,而B連接如果與A連接相關,那麼B連接就是RELATED。
  • INVALID:匹配那些無法識別或沒有任何狀態的數據包。這可能是由於系統記憶體不足或收到不屬於任何已知連接的ICMP錯誤消息,也就是垃圾包,一般情況下我們都會DROP此類狀態的包。

例如:

# 拒絕訪問防火牆的新數據包,但允許響應連接或與已有連接相關的數據包
iptables -A INPUT -p tcp -m state --state NEW -j DROP
iptables -A INPUT -p tcp -m state --state ESTABLISHED,RELATED -j ACCEPT

conntrack

按包狀態匹配。conntrack是state的擴展版本(內核版本>=2.5開始支援),包括狀態參數也是基本相同。

狀態:NEW、RELATED、ESTABLISHED、INVALID、UNTRACKED 。前面的幾個上一節介紹了,這裡說一下UNTRACKED。

  • UNTRACKED : 這是一種特殊狀態,或者說並不是狀態。它是管理員在raw表中,為連接設置NOTRACK規則後的狀態。這樣做,便於提高包過濾效率以及降低負載。
-m conntrack --ctstate 狀態

示例:

# FORWARD 鏈的請求如果目標是 docker0 所在的網段, 而且已經建立的連接或者和已建立連接相關那麼接受請求
iptables -A FORWARD -o docker0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT

mac

匹配某個 MAC 地址。

格式:

-m mac --mac-source MAC

例如:

# 阻斷來自某 MAC 地址的數據包通過本機
iptables -A FORWARD -m --mac-source xx:xx:xx:xx:xx:xx -j DROP

注意:MAC 地址不過路由,不要試圖去匹配路由後面的某個 MAC 地址。

limit

啟用limit擴展,限制速度。用一定速率去匹配數據包。

格式:

-m limit --limit 匹配速率 [--burst 緩衝數量]
-m limit --limit 25/minute: 允許最多每分鐘25個連接
-m limit --limit-burst 100: 當達到100個連接後,才啟用上述25/minute限制

例如:

iptables -A FORWARD -d 192.168.0.1 -m limit --limit 50/s -j ACCEPT
iptables -A FORWARD -d 192.168.0.1 -j DROP

注意:limit 僅僅是用一定的速率去匹配數據包,並非 限制

multiport

一次性匹配多個埠,可以區分源埠,目的埠或不指定埠。

格式:

-m multiport <--sports|--dports|--ports> 埠1[,埠2,..,埠n]

例如:

iptables -A INPUT -p tcp -m multiports --ports 21,22,25,80,110 -j ACCEPT

注意:必須與 -p 參數一起使用。

iprange

指定IP範圍。

格式:

-m iprange --src-range
-m iprange --dst-range

示例:

# 過濾源地址範圍
iptables -A INPUT -m iprange --src-range 192.168.1.2-192.168.1.7 -j DROP

# 過濾目標地址範圍
iptables -A INPUT -m iprange --dst-range 192.168.1.2-192.168.1.7 -j DROP

string

按字元串限定。格式:

-m string --string "STRING" --algo kmp 指定字元串本身

其中--algo 指定匹配演算法:bm或kmp。

addrtype

按地址類型匹配。格式:

-m addrtype --dst-type 地址類型

支援的地址類型:

  • UNSPEC
  • UNICAST
  • LOCAL 匹配本機地址
  • BROADCAST 匹配廣播地址
  • ANYCAST
  • MULTICAST
  • BLACKHOLE
  • UNREACHABLE
  • PROHIBIT
  • THROW
  • NAT
  • XRESOLVE

使用iptables -m addrtype --help可以查看類型列表。地址類型部落客也沒有完全明白都是什麼作用,後面遇到了再補。

示例:

# 如果請求的目標地址是本機的地址, 那麼將請求轉到 DOCKER 鏈處理
iptables -t nat -A PREROUTING -m addrtype --dst-type LOCAL -j DOCKER

自定義鏈

iptables的默認鏈就已經能夠滿足我們了,為什麼還需要自定義鏈呢?原因如下:

當默認鏈中的規則非常多時,不方便我們管理。

例如,如果INPUT鏈中存放了幾十條規則,這幾十條規則有針對http服務的,有針對sshd服務的,有針對私網IP的,有針對公網IP的,假如,我們突然想要修改針對http服務的相關規則,難道我們還要從頭看一遍這幾十條規則,找出哪些規則是針對http的嗎?這顯然不合理。

所以,iptables中,可以自定義鏈,通過自定義鏈即可解決上述問題。

現在,我們自定義一個名為 WEB 的鏈,實現:

  • 轉發當前機器80埠流量到172.18.0.3:80
  • 80埠流量交由WEB管理;且禁止IP: 192.168.2.194 訪問80埠

為了實現上面的規則,需要分別在filter表和nat表增加 自定義鏈 WEB:

# *filter
# 新建WEB鏈
iptables -t filter -N WEB
# WEB鏈增加一條規則:禁止IP:  192.168.2.194 訪問80埠
iptables -t filter -A WEB -s 192.168.2.194 -j DROP
# 80埠流量使用WEB鏈規則處理
iptables -t filter -A INPUT -p tcp --dport 80 -j WEB

# *nat
# 新建WEB鏈
iptables -t nat -N WEB
# 埠轉發
iptables -t nat -A WEB -p tcp --dport 80 -j DNAT --to 172.18.0.3:80
# tcp:80埠PREROUTING、POSTROUTING流量交由WEB處理
iptables -t nat -A PREROUTING -p tcp --dport 80 -j WEB


iptables -t nat -A POSTROUTING -p tcp --dport 80 -j SNAT -d 172.18.0.3 --to 172.18.0.2 

查看生成的規則:

$ iptables-save

*nat
:PREROUTING ACCEPT [1:73]
:INPUT ACCEPT [0:0]
:OUTPUT ACCEPT [1:72]
:POSTROUTING ACCEPT [1:72]
:WEB - [0:0]
-A PREROUTING -p tcp -m tcp --dport 80 -j WEB 
-A POSTROUTING -d 172.18.0.3/32 -p tcp -m tcp --dport 80 -j SNAT --to-source 172.18.0.2 
-A WEB -p tcp -m tcp --dport 80 -j DNAT --to-destination 172.18.0.3:80 
COMMIT

*filter
:INPUT ACCEPT [1:97]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [1:72]
:WEB - [0:0]
-A INPUT -i lo -j ACCEPT 
-A INPUT -p tcp -m tcp --dport 80 -j WEB 
-A WEB -s 192.168.2.194/32 -j DROP

常見規則示例

啟用環迴流量

允許來自您自己的系統(本地主機)的流量:

iptables -A INPUT -i lo -j ACCEPT

此命令將防火牆配置為接受localhost(lo)介面(-i)的通訊現在,源自系統的所有內容都將通過防火牆。需要設置此規則,以允許應用程式與localhost介面通訊。

簡易防火牆

該規則默認拒絕所有INPUT鏈,允許:

  • loop迴環網卡流量
  • 連接狀態為RELATED,ESTABLISHED的連接
  • 80, 22, 21 埠
iptables -F
iptables -A INPUT -i lo -j ACCEPT
iptables -A INPUT -m state --state RELATED,ESTABLISHED  -j ACCEPT
iptables -A INPUT -p tcp --dport 80 -j ACCEPT
iptables -A INPUT -p tcp --dport 22 -j ACCEPT
iptables -P INPUT DROP

註:如果設置了默認規則iptables -P OUTPUT DROP,那麼對應的ACCEPT需要增加-A OUTPUT的指令:

iptables -A INPUT -i lo -j ACCEPT
iptables -A OUTPUT -i lo -j ACCEPT
iptables -A INPUT -m state --state RELATED,ESTABLISHED  -j ACCEPT
iptables -A OUTPUT -m state --state RELATED,ESTABLISHED  -j ACCEPT
iptables -A INPUT -p tcp --dport 80 -j ACCEPT
iptables -A OUTPUT -p tcp --dport 80 -j ACCEPT
iptables -A INPUT -p tcp --dport 22 -j ACCEPT
iptables -A OUTPUT -p tcp --dport 22 -j ACCEPT
iptables -P INPUT DROP
iptables -P OUTPUT DROP

IP黑名單

禁止172.18.0.3訪問。

iptables -A INPUT -i eth0 -s 172.18.0.3 -j DROP

埠轉發

172.18.0.2 機器80埠流量轉發到 172.18.0.3 機器80埠。這樣很簡單的實現了流量轉發。需要在
172.18.0.2 機器配置規則:

# iptables -t nat -F
# 流入當前機器80埠tcp流量轉發到172.18.0.3:80
iptables -t nat -A PREROUTING -p tcp --dport 80 -j DNAT --to 172.18.0.3:80

# 流出當前機器80埠tcp流量源地址修改為172.18.0.2
iptables -t nat -A POSTROUTING -p tcp --dport 80 -d 172.18.0.3 -j SNAT --to 172.18.0.2 
# 或者使用下面的命令: 目標IP地址自動獲取
# iptables -t nat -A POSTROUTING -p tcp --dport 80 -d 172.18.0.3 -j MASQUERADE

docker防火牆配置

安裝docker後會在宿主機增加規則,實現埠映射、docker內部連接外網。

NAT 表改動的解析如下:

# DOCKER 鏈
:DOCKER - [0:0]

# 如果請求的目標地址是本機的地址, 那麼將請求轉到 DOCKER 鏈處理
-A PREROUTING -m addrtype --dst-type LOCAL -j DOCKER

# 如果請求的目標地址不匹配 127.0.0.0/8, 並且目標地址屬於本機地址, 那麼將請求跳轉到 DOCKER 鏈處理
-A OUTPUT ! -d 127.0.0.0/8 -m addrtype --dst-type LOCAL -j DOCKER

# 對於來自於 172.17.0.0/16 的請求, 目標地址不是 docker0 所在的網段的地址, POSTROUTING 鏈將會將該請求偽裝成宿主機的請求轉發到外網
-A POSTROUTING -s 172.17.0.0/16 ! -o docker0 -j MASQUERADE

# 由 docker0 設備傳入的請求 DOCKER 鏈會返回上一層處理
-A DOCKER -i docker0 -j RETURN

FILTER 表改動的解析如下:

# DOCKER 鏈
:DOCKER - [0:0]

# DOCKER-ISOLATION-STAGE-1 鏈
:DOCKER-ISOLATION-STAGE-1 - [0:0]

# DOCKER-ISOLATION-STAGE-2 鏈
:DOCKER-ISOLATION-STAGE-2 - [0:0]

# DOCKER-USER 鏈
:DOCKER-USER - [0:0]

# FORWARD 鏈的請求跳轉到 DOCKER-USER 鏈處理
-A FORWARD -j DOCKER-USER

# FORWARD 鏈的請求跳轉到 DOCKER-ISOLATION-STAGE-1 鏈處理
-A FORWARD -j DOCKER-ISOLATION-STAGE-1

# FORWARD 鏈的請求如果目標是 docker0 所在的網段, 而且已經建立的連接或者和已建立連接相關那麼接受請求
-A FORWARD -o docker0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT

# FORWARD 鏈請求目標是 docker0 所在的網段, 那麼跳轉到 DOCKER 鏈處理
-A FORWARD -o docker0 -j DOCKER

# FORWARD 鏈的請求來自於 docker0 所在網段, 而且目標網段不是 docker0 所在網段, 那麼接收請求.
-A FORWARD -i docker0 ! -o docker0 -j ACCEPT

# FORWARD 鏈的請求來自於 docker0 所在網段, 而且目標網段也是 docker0 所在網段, 那麼接收請求
-A FORWARD -i docker0 -o docker0 -j ACCEPT

# DOCKER-ISOLATION-STAGE-1 鏈的請求如果來自 docker0 所在網段, 而且目標網段不屬於 docker0 所在網段, 那麼跳轉到 DOCKER-ISOLATION-STAGE-2 處理
-A DOCKER-ISOLATION-STAGE-1 -i docker0 ! -o docker0 -j DOCKER-ISOLATION-STAGE-2

# DOCKER-ISOLATION-STAGE-1 鏈未處理的請求返回到上一層繼續處理
-A DOCKER-ISOLATION-STAGE-1 -j RETURN

# DOCKER-ISOLATION-STAGE-2 鏈的請求如果目標的網段為 docker0 所在網段則丟棄請求
-A DOCKER-ISOLATION-STAGE-2 -o docker0 -j DROP

# DOCKER-ISOLATION-STAGE-2 鏈未處理的請求返回到上一層繼續處理
-A DOCKER-ISOLATION-STAGE-2 -j RETURN

# DOCKER-USER 鏈未處理的請求返回到上一層繼續處理
-A DOCKER-USER -j RETURN

可以結合理解的 iptables 知識,對著注釋看一遍,,可加深理解。

安裝 Docker 後 Docker 添加了 DOCKER, DOCKER-USER, DOCKER-ISOLATION-STAGE-1, DOCKER-ISOLATION-STAGE-2 四條鏈,如圖:

本小節來源:理解 Docker 網路(一) — Docker 對 宿主機網路環境的影響,作者 若即,感謝作者的分享。

總結

一直都想整理 iptables ,但是每次都沒有靜下心研究。之前也看過這個,但是時間一長就忘記了。這次趁著假期把 iptables 相關的知識都整理了,也拓展了之前未曾接觸過的:例如模組選項、DNAT、SNAT等等,回頭再去看 25個iptables常用示例 ,不會再像看天書那樣了。

iptables 功能真是太強大了,實現了常用的IP屏蔽、數據包轉發、埠轉發等功能。docker就是基於iptables實現埠轉發的。

本文涉及知識點特別多,建議初學者先全文先看一遍,然後再細看,這樣可以加深理解。文中給了很多示例,讀者最好可以在電腦上實踐一下。

參考

1、iptables (簡體中文) – ArchWiki
//wiki.archlinux.org/index.php/Iptables_(簡體中文)

2、iptables詳細教程:基礎、架構、清空規則、追加規則、應用實例 – Lesca 技術宅
//lesca.me/archives/iptables-tutorial-structures-configuratios-examples.html

3、25個iptables常用示例 | 《Linux就該這麼學》
//www.linuxprobe.com/25-iptables-common-examples.html

4、兩小時玩轉iptables.ppt

//kdocs.cn/l/sQ2wks924

5、看了那麼多iptables的教程,這篇教程還是比較全面易懂的 – 91雲(91yun.co)
//www.91yun.co/archives/1690

6、iptables詳解(10):iptables自定義鏈 – wanstack – 部落格園
//www.cnblogs.com/wanstack/p/8393282.html

7、同區域網下的 Iptables DNAT
//wsfdl.com/踩坑雜記/2017/01/12/iptables_snat.html

8、Linux通過iptables埠轉發訪問內網伺服器上的內網服務 – 看天部落格
//hi.ktsee.com/635.html

9、理解 Docker 網路(一) — Docker 對 宿主機網路環境的影響_若即的專欄-CSDN部落格_docker訪問宿主機網路
//blog.csdn.net/qq_17004327/article/details/88630194

Tags: