iptables工作原理及iptables命令行使用介紹
iptables原理
iptables中的五鏈
實際上,iptables 只是一個操作 Linux 內核 Netfilter 子系統的“界面”。顧名思義,Netfilter 子系統的作用,就是 Linux 內核裏擋在“網卡”和“用戶態進程”之間的一道“防火牆”。它 們的關係,可以用如下的示意圖來表示:
圖片來自張磊極客時間專欄(侵刪)
可以看到,這幅示意圖中,IP 包“一進一出”的兩條路徑上,有幾個關鍵的“檢查點”,它們 正是 Netfilter 設置“防火牆”的地方。在 iptables 中,這些“檢查點”(每個檢查點都可以設置iptables規則對數據包進行過濾或修改)被稱爲:鏈 (Chain)。這是因爲這些“檢查點”對應的 iptables 規則,是按照定義順序依次進行匹配 的。這些“檢查點”的具體工作原理,可以用如下所示的示意圖進行描述:
可以看到,當一個 IP 包通過網卡進入主機之後,它就進入了 Netfilter 定義的流入路徑(Input Path)裏。在這個路徑中,IP 包要經過路由表路由來決定下一步的去向。而在這次路由之前,Netfilter 設 置了一個名叫 PREROUTING 的“檢查點”。在 Linux 內核的實現裏,所謂“檢查點”實際上 就是內核網絡協議棧代碼裏的 Hook(比如,在執行路由判斷的代碼之前,內核會先調用 PREROUTING 的 Hook)。
而在經過路由之後,IP 包的去向就分爲了兩種:
- 第一種,繼續在本機處理;
- 第二種,被轉發到其他目的地。
數據包在Linux內核的流轉過程
- 當一個數據包進入網卡時,數據包首先進入PREROUTING鏈, 內核根據數據包目的IP判斷是否需要轉發出去。
- 如果數據包就是進入本機的,數據包就會沿着圖繼續向上層協議棧流動,這時候,數據包將繼續向上層協議棧流動。在它進入傳輸層之前,Netfilter 會設置一個名叫 INPUT 的“檢查點”。到這裏,數據包流入路徑(Input Path) 結束。接下來,這個 數據包通過傳輸層進入用戶空間,交給用戶進程處理。而處理完成後,用戶進程會 通過本機發出返回的 數據包。這時候,這個數據包就進入了流出路徑(Output Path)。此時,數據包首先還是會經過主機的路由表進行路由。路由結束後,Netfilter 就會設置一個名叫 OUTPUT 的“檢查點”。然後,在 OUTPUT 之後,再設置一個名叫 POSTROUTING“檢查點”。在流出路徑設置兩個檢查點的原因見下方黃色字體。
- 如果數據包是要轉發出去的,且內核允許轉發,在這種情況下,這個 數據包不會進入傳輸層,而是會繼續在網絡層流動,從而進入到轉發路徑 (Forward Path)。在轉發路徑中,Netfilter 會設置一個名叫 FORWARD 的“檢查點”。而在 FORWARD“檢查點”完成後,IP 包就會來到流出路徑。而轉發的 IP 包由於目的地已經確定,它就不會再經過路由,也自然不會經過 OUTPUT,而是會直接來到 POSTROUTING“檢 查點”。
上述五條鏈,其實就是五個檢查點,那麼爲什麼要設置這五個檢查點呢?我猜是因爲每個檢查點針對的數據包的作用域不一樣,如下表所示。
鏈名 | 作用域 |
---|---|
PREOUTING | 所有進入本機的數據包 |
INPUT | 繼續在本機處理,向上層協議棧流入的數據包,交由本機進程處理 |
FORWARD | 被轉發到其他目的地的數據包 |
OUTPUT | 經過本機進程處理流出的數據包 |
POSTROUTING | 所有流出本機的數據包(包括從從Forward Path流出的數據包以及從Output Path流出的數據包) |
POSTROUTING 的作用,其實就是上述兩條路徑(Output Path和Forward Path),最終匯聚在一起的“最終檢查點”,對兩條路徑上的數據包進行統一的檢查和處理。
**總結:**上文涉及到了三條路徑Input Path、Output Path、Forward Path來詳細說明數據包的流轉過程,在這個流轉過程中設置了一些檢查點(chain),使得用戶可以在這些檢查點上設置一定的規則來將匹配到的數據包進行處理。
iptables的四表
建議將上圖原圖鏈接打開,放大觀看。前文所講的就是上圖綠色的部分,也就是Network Layer中的iptables工作流程,每一個白色的“檢查點”上,還有一個綠色的“標籤”,比如:raw、 nat、filter 等等。在 iptables 裏,這些標籤叫作:表。比如,同樣是 OUTPUT 這個“檢查點”,filter Output 和 nat Output 在 iptables 裏的語法和參數,就完全不一樣,實現的功能也完全不同。
每個表的功能如下所示:
名稱 | 功能 |
---|---|
filter | 一般的過濾功能,這個是默認的 table |
nat | 用於nat功能(端口映射,地址映射等),這個表格主要在進行來源與目的之 IP 或 port 的轉換,與 Linux 本機較無關,主要與 Linux 主機後的局域網絡內計算機較有相關 |
mangle | 主要功能是根據規則修改數據包的一些標誌位,以便其他規則或程序可以利用這種標誌對數據包進行過濾或策略路由。簡單來講就是給數據包打標籤。 |
raw | 涉及到數據包的跟蹤處理功能,設置raw時一般是爲了不再讓iptables做數據包的鏈接跟蹤處理,即設置NOTRACK動作提高性能 |
raw表中所說的跟蹤狀態指的是被跟蹤連接的四種不同狀態有關的。它們分別是NEW,ESTABLISHED,RELATED和INVALID。具體請看參考文獻,此處不再細說。
下圖所示是Netfilter中表和鏈的對應關係。表的處理優先級:raw>mangle>nat>filter。
總結: iptables 表的作用,就是在某個具體的“檢查點”(比如 Output)上,按順序執行幾個不同的檢查動作(比如,先執行 nat,再執行 filter),在這些檢查動作中包含了一系列的iptables規則,匹配到相應規則的數據包則會執行相應的處理動作。以上就是iptables中的四表五鏈,有錯誤,歡迎指正。
iptables命令掌握
iptables命令語法
iptables -t table command chain rules -j target
- table ------- 指定表名(raw表、mangle表、nat表、filter表)
- command ------- 對鏈的操作命令(-A:追加規則(最下面進行追加規則)、-I:插入(一般在相應的哪條規則前後插入))
- chain ------- 鏈名(prerouting鏈、forward鏈、input鏈、output鏈、postrouting鏈,以及若干自定義鏈)
- rules ------- 定義一系列的規則來選擇匹配到的數據包,比如可以通過協議,端口號,等等來匹配過濾數據包。
- target ------- 對rules匹配到的數據包進行處理,比如接收請求,丟棄請求等等。
-j jump,指的是跳轉到何種動作上。
table
表選項用於指定命令應用於哪個iptables內置表,iptables內置包括:filter表、nat表、mangle表和raw表
使用的參數爲: -t + 表名,如果不使用-t參數,默認是使用filter表
command
- -P或–policy + <鏈名>: 定義默認策略
- -L或–list + <鏈名>: 查看iptables規則列表
- -A或–append + <鏈名>: 在規則列表的最後增加1條規則
- -I或–insert + <鏈名>: 在指定的位置插入1條規則
- -D或–delete + <鏈名> + number: 從規則列表中刪除1條規則
- -R或–replace + <鏈名> + number: 替換規則列表中的某條規則
- -F或–flush + <鏈名> :清除所有制定的規則
- -X或–delete-chain + <用戶自定義的鏈名>: 刪除表中所有規則(注意:無法清空默認規則)
- -Z或–zero + <鏈名> :將表中數據包計數器和流量計數器歸零
- -N或 --new-chain + <用戶自定義的鏈名>:新建一個用戶自定義的鏈,且鏈名必須跟內置那些鏈名不同
實例:
清除iptables規則:
iptables -F
#清除所有制定的規則
iptables -X
#清除用戶自定義的chain
iptables -Z
#將所有流量統計歸0
但是並非執行後就萬事大吉了。你仍然需要檢查規則是不是真的清空了,因爲有的linux發行版上這個命令不會清除NAT表中的規則,此時只能手動清除:iptables -t NAT -F
chain
默認五條鏈
自定義鏈
rules
rules主要是制定一定的規則,匹配到符合規則的數據包,進行處理。
基本匹配條件:
匹配條件當中出現"!"是取反的意思
- -s --source + <源地址或子網>: 指定數據包匹配的源地址。
iptables -A OUTPUT -s 192.168.1.1
#指定該規則與源地址爲192.168.1.1的數據包匹配。
iptables -A OUTPUT -s 192.168.0.0/24
#指定該規則與源地址爲192.168.0.0/24子網下的網絡包匹配
iptables -A OUTPUT -s ! 203.16.1.89
#指定該規則將與 除來自源地址 203.16.1.89 外的任何信息包匹配。
- -d --destination + <目標地址或子網>: 指定數據包匹配的目標地址
- -i --in-interface + <網絡接口名>: 指定數據包從哪個網絡接口進入,如ppp0、eth0和eth1等。注意:該參數只能用於INPUT、FORWARD、PREROUTING這三個鏈
- -o --out-interface + <網絡接口名>: 指定數據包從哪塊網絡接口輸出,如ppp0、eth0和eth1等。注意:該參數只應用於FORWARD、OUTPUT、POSTROUTING鏈
- -p --protocol + < 協議類型>: 指定數據包匹配的協議, 如tcp, udp, icmp, icmpv6, udplite,esp, ah, sctp等。
擴展匹配條件:
man iptables-extensions
查看幫助文檔
隱式擴展
在使用-p選項指明瞭特定的協議時,無需再用-m選項 指明擴展模塊的擴展機制,不需要手動加載擴展模塊
- tcp協議的擴展選項
--source-port, --sport port[:port]:匹配報文源端口, 可爲端口範圍
--destination-port,--dport port[:port]:匹配報文目標 端口,可爲範圍
--tcp-flags mask comp
mask 需檢查的標誌位列表,用,分隔 例如 SYN,ACK,FIN,RST;
comp 在mask列表中必須爲1的標誌位列表,無指定則必須爲0,用,分隔
實例:
--tcp-flags SYN,ACK,FIN,RST SYN
#表示要檢查 的標誌位爲SYN,ACK,FIN,RST四個,其中SYN必須爲1,餘下的必須爲0
- udp協議的擴展選項
--source-port, --sport port[:port]:匹配報文的 源端口;可以是端口範圍
--destination-port,--dport port[:port]:匹配報 文的目標端口;可以是端口範圍
顯示擴展
必須使用-m選項指明要調用的擴展模塊的擴展 機制,要手動加載擴展模塊
-m matchname
1.multiport擴展
iptables -A INPUT -s 172.16.0.0/16 -d 172.16.100.10 -p tcp -m multiport --dports 20:22,80 -j ACCEPT
#以離散方式定義多端口匹配,最多指定15個端口,用","分隔。
#上述命令中表明源地址爲172.16.0.0/16,目標地址爲172.16.100.10的數據包中,目的端口爲20-22範圍之間的以及80號端口,都接收。
#":"表示一個範圍,比如20:22,表示是20到22之間的所有端口。
2.iprange擴展
--src-range from[-to] 源IP地址範圍
--dst-range from[-to] 目標IP地址範圍
#實例
iptables -A INPUT -d 172.16.100.10 -p tcp --dport 80 -m iprange --src-range 172.16.100.5172.16.100.10 -j DROP
#指明連續的(但一般不是整個網絡)ip地址範圍
3.mac擴展
#實例:
iptables -A INPUT -s 172.16.0.100 -j REJECT
#指明源MAC地址
4.string擴展
#對報文中的應用層數據做字符串模式匹配檢測
--algo {bm|kmp}:字符串匹配檢測算法
bm:Boyer-Moore
kmp:Knuth-Pratt-Morris
--from offset 開始偏移
--to offset 結束偏移
--string pattern:要檢測的字符串模式
#實例
iptables -A OUTPUT -s 172.16.100.10 -d 0/0 -p tcp --sport 80 -m string --algo bm --string “google" -j REJECT
5.time擴展
根據將報文到達的時間與指定的時間範圍進行匹配
--datestart YYYY[-MM[-DD[Thh[:mm[:ss]]]]]
--datestop YYYY[-MM[-DD[Thh[:mm[:ss]]]]]
--timestart hh:mm[:ss]
--timestop hh:mm[:ss]
--monthdays day[,day...]
--weekdays day[,day...]
#實例:
iptables -A INPUT -s 172.16.0.0/16 -d 172.16.100.10 -p tcp --dport 80 -m time --timestart 14:30 --timestop 18:30 --weekdays Sat,Sun --kerneltz -j DROP
6.connlimit擴展
根據每客戶端IP做併發連接數數量匹配,可防止CC(Challenge Collapsar挑戰黑洞)攻擊,通常分別與默認的拒絕或允許策略配合使用。
--connlimit-upto n:連接的數量小於等於n時匹配
--connlimit-above n:連接的數量大於n時匹配
#示例:
iptables -A INPUT -d 172.16.100.10 -p tcp --dport 22 -m connlimit --connlimit-above 2 -j REJECT
7.limit擴展
基於收發報文的速率做匹配 令牌桶過濾器
--limit rate[/second|/minute|/hour|/day]
--limit-burst number
示例:
iptables -I INPUT -d 172.16.100.10 -p icmp --icmptype 8 -m limit --limit 3/minute --limit-burst 5 -j ACCEPT
8.state擴展
根據”連接追蹤機制“去檢查連接的狀態,較耗資源 ,狀態有如下幾種:
- NEW:新發出請求;連接追蹤信息庫中不存在此連接的 相關信息條目,因此,將其識別爲第一次發出的請求
- ESTABLISHED:NEW狀態之後,連接追蹤信息庫中爲 其建立的條目失效之前期間內所進行的通信狀態
- RELATED:新發起的但與已有連接相關聯的連接,如: ftp協議中的數據連接與命令連接之間的關係
- INVALID:無效的連接,如flag標記不正確
- UNTRACKED:未進行追蹤的連接,如raw表中關閉追蹤
CentOS7 需要加載模塊: modprobe nf_conntrack
--state state
#示例:
iptables -A INPUT -d 172.16.100.10 -p tcp -m multiport -dports 22,80 -m state --state NEW,ESTABLISHED -j ACCEPT
9.comment擴展
爲任何規則添加註釋(最多256個字符),主要是爲了解釋說明該規則。
iptables -A INPUT -i eth1 -m comment --comment "my local LAN"
target
target可以是一個"動作",target也能是一個"自定義鏈",當target爲一個動作時,表示報文按照指定的動作處理,當target爲自定義鏈時,表示報文由自定義鏈中的規則處理。具體見下文中自定義鏈的使用。
targetname | 解釋說明 |
---|---|
ACCEPT | 接受數據包 |
DROP | 丟棄數據包 |
REDIRECT | 通過改變目標IP和端口,將接受的包轉發至不同端口 --to-ports port[-port] |
SNAT | 源地址轉換,即改變數據包的源地址。 |
DNAT | 目標地址轉換,即改變數據包的目的地址。 |
MASQUERADE | MASQUERADE是用發送數據的網卡上的IP來替換源IP,因此,對於那些IP不固定的場合,比如撥號網絡或者通過dhcp分配IP的情況下,就得用MASQUERADE。效果和SNAT相似。 |
LOG | 日誌功能,將符合規則的數據包的相關信息記錄在日誌中,以便管理員的分析和排錯 |
NOTRACK | 取消跟蹤功能,一般用於在raw表設置,提高WEB服務器的效率。 |
常見問題
- SNAT 和 MASQUERADE 的區別:SNAT 是明確指定修改的源地址,而 MASQUERADE 會自動獲取出口接口(根據路由表)的 IP 地址。性能方面比 SNAT 幾乎忽略不計,而無需明確指定 IP 地址,所以在 DHCP 和 PPPOE 的動態 IP 環境下(也就是IP不固定的時候)使用特別方便。
iptables -t nat -A POSTROUTING -o $WAN -j MASQUERADE
iptables -t nat -A POSTROUTING -o $WAN -j SNAT --to-source $IP
- DNAT 和 REDIRECT 的區別:這組動作和上面的剛好相反,是用來修改目的地址的。DNAT 是明確指定修改的目的地址,而 REDIRECT 會把要轉發的包的目的地址改寫爲入口接口的 IP 地址。
iptables -t nat -A PREROUTING -i $WAN -p tcp --dport 80 -j REDIRECT --to-ports 3128
iptables -t nat -A PREROUTING -i $WAN -p tcp --dport 80 -j DNAT --to-destination $IP --to-ports 3128
iptables命令案例
開啓路由轉發功能
1.直接配置到內存中,但是隻是當前生效
echo 1 > /proc/sys/net/ipv4/ip_forward
2.寫到配置文件當中
cat <<EOF > /etc/sysctl.d/forward.conf
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
net.ipv4.ip_forward = 1
EOF
sysctl --system
#加載/etc/sysctl.d/*.conf配置文件
#net.ipv4.ip_forward標識着是否轉發,爲1代表開啓轉發功能
#net.bridge.bridge-nf-call-iptables 標誌着二層網橋的包是否被主機的iptables過濾,爲1代表也就意味着二層的網橋在轉發包時也會被iptables的FORWARD規則所過濾,爲0即iptables不對bridge的數據進行處理。
設置自定義鏈
爲什麼還需要自定義鏈呢?
原因如下:
當默認鏈中的規則非常多時,不方便我們管理。
想象一下,如果INPUT鏈中存放了200條規則,這200條規則有針對httpd服務的,有針對sshd服務的,有針對私網IP的,有針對公網IP的,假如,我們突然想要修改針對httpd服務的相關規則,難道我們還要從頭看一遍這200條規則,找出哪些規則是針對httpd的嗎?這顯然不合理。
所以,iptables中,可以自定義鏈,通過自定義鏈即可解決上述問題。
設置自定義鏈有以下幾個步驟:
- 創建自定義鏈
- 在自定義鏈中配置規則
- 在默認鏈中引用自定義鏈
示例如下:
示例來自朱雙印的博客,連接在文章下文,侵刪
1.創建一條名爲IN_WEB的自定義鏈。
2.在這條自定義鏈上設置一定的規則。
3.現在,自定義鏈中已經有了一些規則,但是目前,這些規則無法匹配到任何報文,因爲我們並沒有在任何默認鏈中引用它。既然IN_WEB鏈是爲了針對web服務的入站規則而創建的,那麼這些規則應該去匹配入站的報文,所以,我們應該用INPUT鏈去引用它。當然,自定義鏈在哪裏創建,應該被哪條默認鏈引用,取決於實際的工作場景,因爲此處示例的規則是匹配入站報文,所以在INPUT鏈中引用自定義鏈。
前文提到過,自定義鏈可以作爲target進行跳轉
這種自定義鏈的做法在K8s的網絡模型中,以及service的實現方式上都有一定的體現。
配置NAT
nat表的target: SNAT MASQUERADE DNAT REDIRECT
SNAT:一般用於固定IP
--to-source [ipaddr[-ipaddr]][:port[-port]]
--random
#示例:
iptables -t nat -A POSTROUTING -s 10.0.1.0/24 ! – d 10.0.1.0/24 -j SNAT --to-source 172.18.100.6-172.18.100.9
MASQUERADE:用於動態ip環境中,如撥號網絡
--to-ports port[-port]
--random
#示例:
iptables -t nat -A POSTROUTING -s 10.0.1.0/24 ! – d 10.0.1.0/24 -j MASQUERADE
DNAT:
--to-destination [ipaddr[-ipaddr]][:port[-port]]
#示例
iptables -t nat -A PREROUTING -s 0/0 -d 172.18.100.6 -p tcp --dport 80 -j DNAT --to-destination 10.0.1.22:8080
REDIRECT
使用REDIRECT動作可以在本機上進行端口映射,REDIRECT規則只能定義在PREROUTING鏈或者OUTPUT鏈中。
--to-ports port[-port]
#示例:
iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-ports 8080
#當別的機器訪問本機的80端口時,報文會被重定向到本機的8080端口上。
iptables規則查看
iptables -L
#這種命令輸出的
iptables-save
#該條命令會將iptables規則輸出到標準輸出,其輸出的形式和當初添加的形式是一樣的,這樣就讓熟悉iptables命令的人很好識別出來。
參考文獻
-
張磊,極客時間專欄《深入剖析Kubernetes》
-
鳥哥linux私房菜