Iptables 介紹與使用
連接跟蹤(conntrack)
連接跟蹤是許多網絡應用的基礎。例如,Kubernetes Service、ServiceMesh sidecar、 軟件四層負載均衡器 LVS/IPVS、Docker network、OVS、iptables 主機防火墻等等,都依賴連接跟蹤功能。
- 機器訪問外部 HTTP 服務的連接(目的端口 80)
- 外部訪問機器內 FTP 服務的連接(目的端口 21)
- 機器訪問外部 DNS 服務的連接(目的端口 53)
連接跟蹤所做的事情就是發現并跟蹤這些連接的狀態,具體包括:
- 從數據包中提取元組(tuple)信息,辨別數據流(flow)和對應的連接(connection)。
- 為所有連接維護一個狀態數據庫(conntrack table),例如連接的創建時間、發送 包數、發送字節數等等。
- 回收過期的連接(GC)。
- 為更上層的功能(例如 NAT)提供服務。
需要注意的是,連接跟蹤中所說的“連接”,概念和 TCP/IP 協議中“面向連接”(connection oriented)的“連接”并不完全相同,簡單來說:
- TCP/IP 協議中,連接是一個四層(Layer 4)的概念。TCP 是有連接的,或稱面向連接的(connection oriented),發送出去的包都要求對端應答(ACK),并且有重傳機制。UDP 是無連接的,發送的包無需對端應答,也沒有重傳機制。
- conntrack(CT) 中,一個元組(tuple)定義的一條數據流(flow )就表示一條連接(connection)。后面會看到 UDP 甚至是 ICMP 這種三層協議在 CT 中也都是有連接記錄的,但不是所有協議都會被連接跟蹤。
Netfilter
Netfilter 是 Linux 內核中一個對數據 包進行控制、修改和過濾(manipulation and filtering)的框架。它在內核協議棧中設置了若干 hook 點,以此對數據包進行攔截、過濾或其他處理。
現在提到連接跟蹤(conntrack),可能首先都會想到 Netfilter,Netfilter 只是 Linux 內核中的一種連接跟蹤實現。換句話說,只要具備了 hook 能力,能攔截到進出主機的每個包,完全可以在此基礎上自己實現一套連接跟蹤。
- 基于 BPF hook 實現數據包的攔截功能(等價于 netfilter 里面的 hook 機制)
- 在 BPF hook 的基礎上,實現一套全新的 conntrack 和 NAT 因此,即便卸載掉 Netfilter ,也不會影響 Cilium 對 Kubernetes ClusterIP、NodePort、ExternalIPs 和 LoadBalancer 等功能的支持。由于這套連接跟蹤機制是獨立于 Netfilter 的,因此它的 conntrack 和 NAT 信息也沒有 存儲在內核的(也就是 Netfilter 的)conntrack table 和 NAT table。所以常規的 conntrack/netstats/ss/lsof 等工具是看不到的,要使用 Cilium 的命令,例如:
$?cilium?bpf?nat?list
$?cilium?bpf?ct?list?global
Iptables
Iptables 是配置 Netfilter 過濾功能的用戶空間工具。netfilter 才是防火墻真正的安全框架(framework),netfilter 位于內核空間。iptables 其實是一個命令行工具,位于用戶空間,我們用這個工具操作真正的框架。Iptable 根據規則所定義的方法來處理數據包,如放行(accept)、拒絕(reject)和丟棄(drop)等。
例如當客戶端訪問服務器的web服務時,客戶端發送報文到網卡,而 tcp/ip 協議棧是屬于內核的一部分,所以,客戶端的信息會通過內核的 TCP 協議傳輸到用戶空間中的 web 服務中,而此時,客戶端報文的目標終點為 web 服務所監聽的套接字(IP:Port)上,當web服務需要響應客戶端請求時,web 服務發出的響應報文的目標終點則為客戶端,這個時候,web 服務所監聽的 IP 與端口反而變成了原點,我們說過,netfilter 才是真正的防火墻,它是內核的一部分,所以,如果我們想要防火墻能夠達到”防火”的目的,則需要在內核中設置關卡,所有進出的報文都要通過這些關卡,經過檢查后,符合放行條件的才能放行,符合阻攔條件的則需要被阻止。
iptables 的四個表分別是 filter,mangle,nat,raw,默認表是filter。
- filter 表:用來對數據包進行過濾,具體的規則要求決定如何處理一個數據包。
- nat 表:主要用來修改數據包的 IP 地址、端口號信息。
- mangle 表:主要用來修改數據包的服務類型,生存周期,為數據包設置標記,實現流量整形、策略路由等。
- raw 表:主要用來決定是否對數據包進行狀態跟蹤。
iptables 的五個鏈分別是 PREROUTING,INPUT,FORWARD,OUTPUT,POSTROUTING。
- input 鏈:當收到訪問本機地址的數據包時,將應用此鏈中的規則。
- output 鏈:當本機向外發送數據包時,將應用此鏈中的規則。
- forward 鏈:當收到需要轉發給其他地址的數據包時,將應用此鏈中的規則,注意如果需要實現forward轉發需要開啟Linux內核中的ip_forward功能。
- prerouting 鏈:在對數據包做路由選擇之前,將應用此鏈中的規則。
- postrouting 鏈:在對數據包做路由選擇之后,將應用此鏈中的規則。
表和鏈的對應關系如下圖所示:
- 到本機某進程的報文:PREROUTING –> INPUT。
- 由本機轉發的報文:PREROUTING –> FORWARD –> POSTROUTING。
- 由本機的某進程發出報文(通常為響應報文):OUTPUT –> POSTROUTING。
我們可以將數據包通過防火墻的流程總結為下圖:
查詢規則
- -t:表名
- -n:不解析IP地址
- -v:會顯示出計數器的信息,數據包的數量和大小
- -x:選項表示顯示計數器的精確值
- --line-numbers:顯示規則的序號(簡寫為--line)
- -L:鏈名
#iptables?-t?filter?-nvxL?DOCKER??--line
Chain?DOCKER?(1?references)
num??????pkts??????bytes?target?????prot?opt?in?????out?????source???????????????destination
1????????5076???321478?ACCEPT?????tcp??--??!docker0?docker0??0.0.0.0/0????????????172.17.0.2???????????tcp?dpt:8443
2???????37233?54082508?ACCEPT?????tcp??--??!docker0?docker0??0.0.0.0/0????????????172.17.0.2???????????tcp?dpt:22
3????????1712???255195?ACCEPT?????tcp??--??!docker0?docker0??0.0.0.0/0????????????172.17.0.3???????????tcp?dpt:9000
4???????????0????????0?ACCEPT?????tcp??--??!docker0?docker0??0.0.0.0/0????????????172.17.0.3???????????tcp?dpt:8000
5???????40224??6343104?ACCEPT?????tcp??--??!docker0?docker0??0.0.0.0/0????????????172.17.0.4???????????tcp?dpt:3443
6???????21034??2227009?ACCEPT?????tcp??--??!docker0?docker0??0.0.0.0/0????????????172.17.0.5???????????tcp?dpt:3306
7??????????58?????5459?ACCEPT?????tcp??--??!docker0?docker0??0.0.0.0/0????????????172.17.0.6???????????tcp?dpt:80
8?????????826????70081?ACCEPT?????tcp??--??!docker0?docker0??0.0.0.0/0????????????172.17.0.6???????????tcp?dpt:443
9????10306905?1063612492?ACCEPT?????tcp??--??!docker0?docker0??0.0.0.0/0????????????172.17.0.9???????????tcp?dpt:3306
10?????159775?12297727?ACCEPT?????tcp??--??!docker0?docker0??0.0.0.0/0????????????172.17.0.7???????????tcp?dpt:11111
增加規則
在指定表的指定鏈的尾部添加一條規則,-A 選項表示在對應鏈的末尾添加規則,省略 -t 選項時,表示默認操作 filter 表中的規則:
命令語法:iptables?-t?表名?-A?鏈名?匹配條件?-j?動作
示例:iptables?-t?filter?-A?INPUT?-s?192.168.1.146?-j?DROP
在指定表的指定鏈的首部添加一條規則,-I 選型表示在對應鏈的開頭添加規則:
命令語法:iptables?-t?表名?-I?鏈名?匹配條件?-j?動作
示例:iptables?-t?filter?-I?INPUT?-s?192.168.1.146?-j?ACCEPT
在指定表的指定鏈的指定位置添加一條規則:
命令語法:iptables?-t?表名?-I?鏈名?規則序號?匹配條件?-j?動作
示例:iptables?-t?filter?-I?INPUT?5?-s?192.168.1.146?-j?REJECT
刪除規則
按照規則序號刪除規則,刪除指定表的指定鏈的指定規則,-D 選項表示刪除對應鏈中的規則。示例表示刪除filter表中INPUT鏈中序號為3的規則。:
命令語法:iptables -t 表名?-D 鏈名?規則序號
示例:iptables -t filter?-D?INPUT?3
按照具體的匹配條件與動作刪除規則,刪除指定表的指定鏈的指定規則。示例表示刪除filter表中INPUT鏈中源地址為192.168.1.146并且動作為DROP的規則。:
命令語法:iptables?-t?表名?-D?鏈名?匹配條件?-j?動作
示例:iptables?-t?filter?-D?INPUT?-s?192.168.1.146?-j?DROP
刪除指定表的指定鏈中的所有規則,-F選項表示清空對應鏈中的規則:
命令語法:iptables -t 表名?-F?鏈名
示例:iptables -t filter -F?INPUT
修改規則
修改指定表中指定鏈的指定規則,-R 選項表示修改對應鏈中的規則,使用 -R 選項時要同時指定對應的鏈以及規則對應的序號,并且規則中原本的匹配條件不可省略。示例表示修改filter表中INPUT鏈的第3條規則,將這條規則的動作修改為ACCEPT, -s 192.168.1.146為這條規則中原本的匹配條件,如果省略此匹配條件,修改后的規則中的源地址可能會變為0.0.0.0/0:
命令語法:iptables?-t?表名?-R?鏈名?規則序號?規則原本的匹配條件?-j?動作
示例:iptables?-t?filter?-R?INPUT?3?-s?192.168.1.146?-j?ACCEPT
設置指定表的指定鏈的默認策略(默認動作):
命令語法:iptables -t 表名?-P 鏈名?動作
示例:iptables -t filter -P FORWARD?ACCEPT
保存規則
方式一
當我們對規則進行了修改以后,如果想要修改永久生效,必須使用下面命令保存規則:
service?iptables?save
當然,如果你誤操作了規則,但是并沒有保存,那么使用 service iptables restart 命令重啟 iptables 以后,規則會再次回到上次保存 /etc/sysconfig/iptables 文件時的模樣。
centos7 中,已經不再使用 init 風格的腳本啟動服務,而是使用 unit 文件,所以,在 centos7 中已經不能再使用類似 service iptables start 這樣的命令了,所以 service iptables save 也無法執行,同時,在 centos7中,使用 firewall 替代了原來的 iptables service,不過不用擔心,我們只要通過 yum 源安裝 iptables與iptables-services 即可(iptables 一般會被默認安裝,但是iptables-services 在 centos7 中一般不會被默認安裝),在centos7 中安裝完 iptables-services 后,即可像 centos6 中一樣,通過 service iptables save 命令保存規則了,規則同樣保存在 /etc/sysconfig/iptables 文件中。此處給出 centos7 中配置 iptables-service 的步驟:
#配置好yum源以后安裝iptables-service
yum?install?-y?iptables-services
#停止firewalld
systemctl?stop?firewalld
#禁止firewalld自動啟動
systemctl?disable?firewalld
#啟動iptables
systemctl?start?iptables
#將iptables設置為開機自動啟動,以后即可通過iptables-service控制iptables服務
systemctl?enable?iptables
上述配置過程只需一次,以后即可在 centos7 中使用 service iptables save 命令保存 iptables 規則了。
方式二
還可以使用另一種方法保存 iptables 規則,就是使用 iptables-save 命令。使用 iptables-save 并不能保存當前的 iptables 規則,但是可以將當前的 iptables 規則以”保存后的格式”輸出到屏幕上。
所以,我們可以使用 iptables-save 命令,再配合重定向,將規則重定向到 /etc/sysconfig/iptables 文件中即可。
iptables-save?>?/etc/sysconfig/iptables
加載規則
我們也可以將 /etc/sysconfig/iptables 中的規則重新載入為當前的iptables 規則,但是注意,未保存入 /etc/sysconfig/iptables 文件中的修改將會丟失或者被覆蓋。
使用 iptables-restore 命令可以從指定文件中重載規則,示例如下
iptables-restore?<?/etc/sysconfig/iptables
匹配條件
當規則中同時存在多個匹配條件時,多個條件之間默認存在”與”的關系,即報文必須同時滿足所有條件,才能被規則匹配。
-s 用于匹配報文的源地址,可以同時指定多個源地址,每個IP之間用逗號隔開,也可以指定為一個網段。
#示例如下
iptables?-t?filter?-I?INPUT?-s?192.168.1.111,192.168.1.118?-j?DROP
iptables?-t?filter?-I?INPUT?-s?192.168.1.0/24?-j?ACCEPT
iptables?-t?filter?-I?INPUT?!?-s?192.168.1.0/24?-j?ACCEPT
-d 用于匹配報文的目標地址,可以同時指定多個目標地址,每個 IP 之間用逗號隔開,也可以指定為一個網段。
#示例如下
iptables?-t?filter?-I?OUTPUT?-d?192.168.1.111,192.168.1.118?-j?DROP
iptables?-t?filter?-I?INPUT?-d?192.168.1.0/24?-j?ACCEPT
iptables?-t?filter?-I?INPUT?!?-d?192.168.1.0/24?-j?ACCEPT
-p 用于匹配報文的協議類型,可以匹配的協議類型 tcp、udp、udplite、icmp、esp、ah、sctp 等(centos7 中還支持 icmpv6、mh)。
#示例如下
iptables?-t?filter?-I?INPUT?-p?tcp?-s?192.168.1.146?-j?ACCEPT
iptables?-t?filter?-I?INPUT?!?-p?udp?-s?192.168.1.146?-j?ACCEPT
-i 用于匹配報文是從哪個網卡接口流入本機的,由于匹配條件只是用于匹配報文流入的網卡,所以在 OUTPUT 鏈與 POSTROUTING 鏈中不能使用此選項。
#示例如下
iptables?-t?filter?-I?INPUT?-p?icmp?-i?eth4?-j?DROP
iptables?-t?filter?-I?INPUT?-p?icmp?!?-i?eth4?-j?DROP
-o 用于匹配報文將要從哪個網卡接口流出本機,于匹配條件只是用于匹配報文流出的網卡,所以在 INPUT 鏈與 PREROUTING 鏈中不能使用此選項。
#示例如下
iptables?-t?filter?-I?OUTPUT?-p?icmp?-o?eth4?-j?DROP
iptables?-t?filter?-I?OUTPUT?-p?icmp?!?-o?eth4?-j?DROP
擴展匹配條件
tcp擴展模塊
常用的擴展匹配條件如下:
- –sport:用于匹配 tcp 協議報文的源端口,可以使用冒號指定一個連續的端口范圍。
- –dport:用于匹配 tcp 協議報文的目標端口,可以使用冒號指定一個連續的端口范圍。
- –tcp-flags:用于匹配報文的tcp頭的標志位。
- –syn:用于匹配 tcp 新建連接的請求報文,相當于使用 –tcp-flags SYN,RST,ACK,FIN SYN。
注意,-p tcp與 -m tcp 并不沖突,-p 用于匹配報文的協議,-m 用于指定擴展模塊的名稱,正好,這個擴展模塊也叫 tcp。
#示例如下
iptables?-t?filter?-I?OUTPUT?-d?192.168.1.146?-p?tcp?-m?tcp?--sport?22?-j?REJECT
iptables?-t?filter?-I?INPUT?-s?192.168.1.146?-p?tcp?-m?tcp?--dport?22:25?-j?REJECT
iptables?-t?filter?-I?INPUT?-s?192.168.1.146?-p?tcp?-m?tcp?--dport?:22?-j?REJECT
iptables?-t?filter?-I?INPUT?-s?192.168.1.146?-p?tcp?-m?tcp?--dport?80:?-j?REJECT
iptables?-t?filter?-I?OUTPUT?-d?192.168.1.146?-p?tcp?-m?tcp?!?--sport?22?-j?ACCEPT
iptables?-t?filter?-I?INPUT?-p?tcp?-m?tcp?--dport?22?--tcp-flags?SYN,ACK,FIN,RST,URG,PSH?SYN?-j?REJECT
iptables?-t?filter?-I?OUTPUT?-p?tcp?-m?tcp?--sport?22?--tcp-flags?SYN,ACK,FIN,RST,URG,PSH?SYN,ACK?-j?REJECT
iptables?-t?filter?-I?INPUT?-p?tcp?-m?tcp?--dport?22?--tcp-flags?ALL?SYN?-j?REJECT
iptables?-t?filter?-I?OUTPUT?-p?tcp?-m?tcp?--sport?22?--tcp-flags?ALL?SYN,ACK?-j?REJECT
iptables?-t?filter?-I?INPUT?-p?tcp?-m?tcp?--dport?22?--syn?-j?REJECT
udp 擴展模塊
常用的擴展匹配條件:
- –sport:匹配udp報文的源地址。
- –dport:匹配udp報文的目標地址。
#示例
iptables?-t?filter?-I?INPUT?-p?udp?-m?udp?--dport?137?-j?ACCEPT
iptables?-t?filter?-I?INPUT?-p?udp?-m?udp?--dport?137:157?-j?ACCEPT
icmp 擴展模塊
常用的擴展匹配條件:
- –icmp-type:匹配icmp報文的具體類型。
#示例
iptables?-t?filter?-I?INPUT?-p?icmp?-m?icmp?--icmp-type?8/0?-j?REJECT
iptables?-t?filter?-I?INPUT?-p?icmp?--icmp-type?8?-j?REJECT
iptables?-t?filter?-I?OUTPUT?-p?icmp?-m?icmp?--icmp-type?0/0?-j?REJECT
iptables?-t?filter?-I?OUTPUT?-p?icmp?--icmp-type?0?-j?REJECT
iptables?-t?filter?-I?INPUT?-p?icmp?--icmp-type?"echo-request"?-j?REJECT
multiport 擴展模塊
常用的擴展匹配條件如下:
- -p tcp -m multiport –sports 用于匹配報文的源端口,可以指定離散的多個端口號,端口之間用”逗號”隔開。
- -p udp -m multiport –dports 用于匹配報文的目標端口,可以指定離散的多個端口號,端口之間用”逗號”隔開。
#示例如下
iptables?-t?filter?-I?OUTPUT?-d?192.168.1.146?-p?udp?-m?multiport?--sports?137,138?-j?REJECT
iptables?-t?filter?-I?INPUT?-s?192.168.1.146?-p?tcp?-m?multiport?--dports?22,80?-j?REJECT
iptables?-t?filter?-I?INPUT?-s?192.168.1.146?-p?tcp?-m?multiport?!?--dports?22,80?-j?REJECT
iptables?-t?filter?-I?INPUT?-s?192.168.1.146?-p?tcp?-m?multiport?--dports?80:88?-j?REJECT
iptables?-t?filter?-I?INPUT?-s?192.168.1.146?-p?tcp?-m?multiport?--dports?22,80:88?-j?REJECT
iprange 模塊
包含的擴展匹配條件如下:
- –src-range:指定連續的源地址范圍。
- –dst-range:指定連續的目標地址范圍。
#示例
iptables?-t?filter?-I?INPUT?-m?iprange?--src-range?192.168.1.127-192.168.1.146?-j?DROP
iptables?-t?filter?-I?OUTPUT?-m?iprange?--dst-range?192.168.1.127-192.168.1.146?-j?DROP
iptables?-t?filter?-I?INPUT?-m?iprange?!?--src-range?192.168.1.127-192.168.1.146?-j?DROP
string 模塊
常用擴展匹配條件如下:
- –algo:指定對應的匹配算法,可用算法為bm、kmp,此選項為必需選項。
- –string:指定需要匹配的字符串
我們想要達到的目的是,如果報文中包含”OOXX”字符,我們就拒絕報文進入本機:
#示例
iptables?-t?filter?-I?INPUT?-m?string?--algo?bm?--string?"OOXX"?-j?REJECT
time 模塊
常用擴展匹配條件如下:
- –timestart:用于指定時間范圍的開始時間,不可取反。
- –timestop:用于指定時間范圍的結束時間,不可取反。
- –weekdays:用于指定”星期幾”,可取反。
- –monthdays:用于指定”幾號”,可取反。
- –datestart:用于指定日期范圍的開始日期,不可取反。
- –datestop:用于指定日期范圍的結束時間,不可取反。
#示例
iptables?-t?filter?-I?OUTPUT?-p?tcp?--dport?80?-m?time?--timestart?09:00:00?--timestop?19:00:00?-j?REJECT
iptables?-t?filter?-I?OUTPUT?-p?tcp?--dport?443?-m?time?--timestart?09:00:00?--timestop?19:00:00?-j?REJECT
iptables?-t?filter?-I?OUTPUT?-p?tcp?--dport?80??-m?time?--weekdays?6,7?-j?REJECT
iptables?-t?filter?-I?OUTPUT?-p?tcp?--dport?80??-m?time?--monthdays?22,23?-j?REJECT
iptables?-t?filter?-I?OUTPUT?-p?tcp?--dport?80??-m?time?!?--monthdays?22,23?-j?REJECT
iptables?-t?filter?-I?OUTPUT?-p?tcp?--dport?80??-m?time?--timestart?09:00:00?--timestop?18:00:00?--weekdays?6,7?-j?REJECT
iptables?-t?filter?-I?OUTPUT?-p?tcp?--dport?80??-m?time?--weekdays?5?--monthdays?22,23,24,25,26,27,28?-j?REJECT
iptables?-t?filter?-I?OUTPUT?-p?tcp?--dport?80??-m?time?--datestart?2017-12-24?--datestop?2017-12-27?-j?REJECT
connlimit 模塊
常用的擴展匹配條件如下:
- –connlimit-above:單獨使用此選項時,表示限制每個IP的鏈接數量。
- –connlimit-mask:此選項不能單獨使用,在使用–connlimit-above選項時,配合此選項,則可以針對”某類IP段內的一定數量的IP”進行連接數量的限制,如果不明白可以參考上文的詳細解釋。
#示例
iptables?-I?INPUT?-p?tcp?--dport?22?-m?connlimit?--connlimit-above?2?-j?REJECT
iptables?-I?INPUT?-p?tcp?--dport?22?-m?connlimit?--connlimit-above?20?--connlimit-mask?24?-j?REJECT
iptables?-I?INPUT?-p?tcp?--dport?22?-m?connlimit?--connlimit-above?10?--connlimit-mask?27?-j?REJECT
limit 模塊
connlimit 模塊是對連接數量進行限制的,limit 模塊是對”報文到達速率”進行限制的。用大白話說就是,如果我想要限制單位時間內流入的包的數量,就能用 limit 模塊。我們可以以秒為單位進行限制,也可以以分鐘、小時、天作為單位進行限制。常用的擴展匹配條件如下:
- –limit-burst:類比”令牌桶”算法,此選項用于指定令牌桶中令牌的最大數量。
- –limit:類比”令牌桶”算法,此選項用于指定令牌桶中生成新令牌的頻率,可用時間單位有second、minute 、hour、day。
示例表示限制外部主機對本機進行ping操作時,本機最多每6秒中放行一個ping包
#示例,注意,如下兩條規則需配合使用
#令牌桶中最多能存放3個令牌,每分鐘生成10個令牌(即6秒鐘生成一個令牌)。
iptables?-t?filter?-I?INPUT?-p?icmp?-m?limit?--limit-burst?3?--limit?10/minute?-j?ACCEPT
#默認將icmp包丟棄
iptables?-t?filter?-A?INPUT?-p?icmp?-j?REJECT
state 擴展模塊
當我們通過 http 的 url 訪問某個網站的網頁時,客戶端向服務端的 80 端口發起請求,服務端再通過 80 端口響應我們的請求,于是,作為客戶端,我們似乎應該理所應當的放行 80 端口,以便服務端回應我們的報文可以進入客戶端主機,于是,我們在客戶端放行了 80 端口,同理,當我們通過 ssh 工具遠程連接到某臺服務器時,客戶端向服務端的 22 號端口發起請求,服務端再通過 22 號端口響應我們的請求,于是我們理所應當的放行了所有 22 號端口,以便遠程主機的響應請求能夠通過防火墻,但是,作為客戶端,如果我們并沒有主動向 80 端口發起請求,也沒有主動向 22 號端口發起請求,那么其他主機通過 80 端口或者 22 號端口向我們發送數據時,我們可以接收到嗎?應該是可以的,因為我們為了收到 http 與 ssh 的響應報文,已經放行了 80 端口與 22 號端口,所以,不管是”響應”我們的報文,還是”主動發送”給我們的報文,應該都是可以通過這兩個端口的,那么仔細想想,這樣是不是不太安全呢?此時 state 擴展模塊就派上用場了。
對于 state 模塊的連接而言,”連接”其中的報文可以分為5種狀態,分別為:
- NEW:連接中的第一個包,狀態就是 NEW,我們可以理解為新連接的第一個包的狀態為 NEW。
- ESTABLISHED:我們可以把 NEW 狀態包后面的包的狀態理解為 ESTABLISHED,表示連接已建立。
- RELATED:從字面上理解 RELATED 譯為關系,但是這樣仍然不容易理解,我們舉個例子。比如 FTP 服務,FTP 服務端會建立兩個進程,一個命令進程,一個數據進程。命令進程負責服務端與客戶端之間的命令傳輸(我們可以把這個傳輸過程理解成 state 中所謂的一個”連接”,暫稱為”命令連接”)。數據進程負責服務端與客戶端之間的數據傳輸 (我們把這個過程暫稱為”數據連接”)。但是具體傳輸哪些數據,是由命令去控制的,所以,”數據連接”中的報文與”命令連接”是有”關系”的。那么,”數據連接”中的報文可能就是 RELATED 狀態,因為這些報文與”命令連接”中的報文有關系。(注:如果想要對ftp進行連接追蹤,需要單獨加載對應的內核模塊 nf_conntrack_ftp,如果想要自動加載,可以配置 /etc/sysconfig/iptables-config 文件)
- INVALID:如果一個包沒有辦法被識別,或者這個包沒有任何狀態,那么這個包的狀態就是 INVALID,我們可以主動屏蔽狀態為 INVALID 的報文。
- UNTRACKED:報文的狀態為 untracked 時,表示報文未被追蹤,當報文的狀態為 Untracked 時通常表示無法找到相關的連接。
剛才舉例中的問題即可使用 state 擴展模塊解決,我們只要放行狀態為 ESTABLISHED 的報文即可,因為如果報文的狀態為 ESTABLISHED,那么報文肯定是之前發出的報文的回應,這樣,就表示只有回應我們的報文能夠通過防火墻,如果是別人主動發送過來的新的報文,則無法通過防火墻:
iptables?-t?filter?-I?INPUT?-m?state?--state?ESTABLISHED?-j?ACCEPT
mangle 表
mangle 表的主要功能是根據規則修改數據包的一些標志位,以便其他規則或程序可以利用這種標志對數據包進行過濾或策略路由。mangle 表主要有以下 3 種操作:
- TOS:用來設置或改變數據包的服務類型域。這常用來設置網絡上的數據包如何被路由等策略。注意這個操作并不完善,有時得不所愿。它在Internet 上還不能使用,而且很多路由器不會注意到這個域值。換句話說,不要設置發往 Internet 的包,除非你打算依靠 TOS 來路由,比如用 iproute2。
- TTL:用來改變數據包的生存時間域,我們可以讓所有數據包只有一個特殊的 TTL。它的存在有 一個很好的理由,那就是我們可以欺騙一些ISP。為什么要欺騙他們呢?因為他們不愿意讓我們共享一個連接。那些 ISP 會查找一臺單獨的計算機是否使用不同的 TTL,并且以此作為判斷連接是否被共享的標志。
- MARK 用來給包設置特殊的標記。iproute 2能識別這些標記,并根據不同的標記(或沒有標記) 決定不同的路由。用這些標記我們可以做帶寬限制和基于請求的分類。
例如內網的客戶端通過 Linux 主機連入 Internet,而 Linux 主機與Internet 連接時有兩條線路,它們的網關如圖所示。現要求對內網進行策略路由,所有通過 TCP 協議訪問 80 端口的數據包都從 ChinaNet 線路出去,而所有訪問 UDP 協議 53 號端口的數據包都從 Cernet 線路出去。
iptables?-t?mangle?-A?PREROUTING?-i?eth0?-p?tcp?--dport?80?-j?MARK?--set-mark?1;
iptables?-t?mangle?-A?PREROUTING?-i?eth0?-p?udp?--dprot?53?-j?MARK?--set-mark?2;
數據包經過 PREROUTING 鏈后,將要進入路由選擇模塊,為了對其進行策略路由,執行以下兩條命令,添加相應的規則:
ip?rule?add?from?all?fwmark?1?table?10
ip?rule?add?from?all?fwmark?2?table?20
以上兩條命令表示所有標志是1的數據包使用路由表 10 進行路由,而所有標志是 2 的數據包使用路由表 20 進行路由。路由表 10 和 20 分別使用了 ChinaNet 和 Cernet 線路上的網關作為默認網關,具體設置命令如下所示:
ip?route?add?default?via?10.10.1.1?dev?eth1?table?10
ip?route?add?default?via?10.10.2.1?dev?eth2?table?20
以上兩條命令在路由表 10 和 20 上分別指定了 10.10.1.1 和 10.10.2.1 作為默認網關,它們分別位于 ChinaNet 和 Cernet 線路上。于是,使用路由表 10 的數據包將通過 ChinaNet 線路出去,而使用路由表20的數據包將通過 Cernet 線路出去。
自定義鏈
當默認鏈中的規則非常多時,不方便我們管理。想象一下,如果 INPUT 鏈中存放了 200 條規則,這 200 條規則有針對 httpd 服務的,有針對 sshd 服務的,有針對私網 IP 的,有針對公網 IP 的,假如,我們突然想要修改針對 httpd 服務的相關規則,難道我們還要從頭看一遍這 200 條規則,找出哪些規則是針對 httpd 的嗎?這顯然不合理。
所以,iptables 中,可以自定義鏈,通過自定義鏈即可解決上述問題。假設,我們自定義一條鏈,鏈名叫 IN_WEB,我們可以將所有針對 80 端口的入站規則都寫入到這條自定義鏈中,當以后想要修改針對 web 服務的入站規則時,就直接修改 IN_WEB 鏈中的規則就好了,即使默認鏈中有再多的規則,我們也不會害怕了,因為我們知道,所有針對 80 端口的入站規則都存放在IN_WEB鏈中。
創建自定義鏈
#在filter表中創建IN_WEB自定義鏈
iptables?-t?filter?-N?IN_WEB
引用自定義鏈
#在INPUT鏈中引用剛才創建的自定義鏈
iptables?-t?filter?-I?INPUT?-p?tcp?--dport?80?-j?IN_WEB
重命名自定義鏈
#將IN_WEB自定義鏈重命名為WEB
iptables?-E?IN_WEB?WEB
刪除自定義鏈
刪除自定義鏈需要滿足兩個條件:
- 自定義鏈沒有被引用。
- 自定義鏈中沒有任何規則。
#第一步:清除自定義鏈中的規則
iptables?-t?filter?-F?WEB
#第二步:刪除自定義鏈
iptables?-t?filter?-X?WEB
LOG 動作
LOG 動作默認會將報文的相關信息記錄在/var/log/message文件中,當然,我們也可以將相關信息記錄在指定的文件中,以防止 iptables 的相關信息與其他日志信息相混淆,修改 /etc/rsyslog.conf 文件(或者 /etc/syslog.conf),在 rsyslog 配置文件中添加如下配置即可:
kern.warning?/var/log/iptables.log
完成上述配置后,重啟rsyslog服務(或者syslogd):
service?rsyslog?restart
LOG 動作也有自己的選項,常用選項如下:
- –log-level 選項可以指定記錄日志的日志級別,可用級別有 emerg,alert,crit,error,warning,notice,info,debug。
- –log-prefix 選項可以給記錄到的相關信息添加”標簽”之類的信息,以便區分各種記錄到的報文信息,方便在分析時進行過濾。–log-prefix 對應的值不能超過 29 個字符。
比如,我想要將主動連接22號端口的報文的相關信息都記錄到日志中,并且把這類記錄命名為”want-in-from-port-22″,則可以使用如下命令:
iptables?-I?INPUT?-p?tcp?--dport?22?-m?state?--state?NEW?-j?LOG?--log-prefix?"want-in-from-port-22"
完成上述配置后,我在IP地址為 192.168.1.98 的客戶端機上,嘗試使用 ssh 工具連接上例中的主機,然后查看對應的日志文件(已經將日志文件設置為 /var/log/iptables.log):
參考鏈接
- https://www.zsythink.net/archives/category/%e8%bf%90%e7%bb%b4%e7%9b%b8%e5%85%b3/iptables/
- https://my.oschina.net/mojiewhy/blog/3039897
- https://www.frozentux.net/iptables-tutorial/cn/iptables-tutorial-cn-1.1.19.html#MARKTARGET
- https://mp.weixin.qq.com/s/NOxY4ZC7Cay4LCWlMkVx8A