# `iptables` 基本介紹 > 以下紀錄自己學習 `iptables` 的筆記~ 資料透過網路傳輸時,會被切割成一個一個的封包,封包裡面除了含有要傳送的 data,也含有這個封包的資訊,像是 souce address、protocol 等等資訊。 而說到 Linux 的防火牆,就會提到 `iptables`。當封包進到 `iptables` 裡面,`iptables` 就會查看這個封包的資訊,並依據我們設定的防火牆規則對這個封包做處理。 以下簡單介紹 `iptables` 和它的指令~ ## Linux Firewall ![linux firewall](https://hackmd.io/_uploads/S1rLh1vr1g.png) `netfilter` 是運行在 kernel space 的,所以使用者沒辦法直接對他做操作;而 `iptables` 則是運行在 user space 的工具,使用者可以透過 `iptables` 對 `netfilter` 做設定。 從上面那張圖可以看到 `iptables` 其實是比較舊版的,且 `iptables` 是專門負責 IPv4 的 packet filtering 和 network address translation(NAT);IPv6 的部分則由 `ip6tables` 負責,另外還有 `ebtables` 和 `arptables` 分別負責 ethernet bridge frame table 和 address resolution protocol table。 而 Linux kernel 自 3.13 版開始,就改成使用 `nftables`。一個 `nftables` 的功能就涵蓋了舊版的四個工具的功能。 而 OpenWRT 則是自 22.03 版以後,預設上改成使用 `nftables`。 ## `iptables` 組成 ### Table、Chain、以及 Rule ![tables, chains, rules in iptables](https://hackmd.io/_uploads/r1cXtgPHkg.png) 上圖是一個很簡單的示意圖,`iptables` 裡面會有一個一個的 tables,每個 table 則會由多個 chains 所組成,而這些 chains 則由多個 rules 所構成。 - 依據對封包做的操作的不同,會有不同的 table,像是負責 network address translation 的 nat table、或負責封包過濾的 filter table - Chain 則是依據封包處理流程的不同階段所命名,像是在做 routing 之前(`PREROUTING` chain)、或者是處理完 routing 之後(`POSTROUTING` chain)。 - Rule 就是我們所設定的防火牆規則。 - 每個 rule 都會有 target,target 就是要對這個封包做什麼「操作」。 - 當封包進入一個 chain,++就會開始從該 chain 的第一條 rule 開始依序比對++,假如該封包符合了第一個 rule,那就會對這個封包執行第一個 rule 所指定的「操作」,然後可能就會到下一個 chain 或被丟棄。 ++假如前面的 rule 都沒有符合,那就會去比對下一條 rule++,依此類推。 - 最後,可以看到 chain 裡面不一定要有 rule,但一定要有 policy。Policy 跟 rule 一樣都會有 taget。前面有提到,封包一旦進入一個 chain,就會開始依序從第一個 rule 做比對,若有符合某個 rule,那就執行該 rule 的 target。但萬一全部的 rule 都比對過了,但都沒符合,或者是該 chain 裡面沒有半條 rule,那該怎麼處理這封包呢?這時候就是看該 chain 的 policy 的 target 為何,就會對封包執行 policy 的 target。 以 NAT table 為例,這個 table 的功能是對封包做 network address translation,那這個 table 有 `PREROUTING` chain 和 `POSTROUTING` chain,所以封包在 `PREROUTING` 和 `POSTROUTING` 階段會進入 NAT table 的 `PREROUTING` chain 和 `POSTROUTING` chain,並且依序比對這些 chain 裡面的 rule, ![packets and iptables](https://hackmd.io/_uploads/r17y5lwHke.png) 上圖是個簡單的示意圖說明若一個封包進到 `iptables` 的處理流程。 封包的處理流程主要依據不同的階段劃分,這裡簡單的用 Stage I、Stage II、以及 Stage III 作說明(後面會提到確切的流程)。 前面有提到,chain 的命名是依據封包處理的階段所命名,所以 stage I 會由某些 table 的 chain I 所組成,而 stage II 則由另一些 table 的 chain II 所組成,依此類推。 封包在每個 stage 會依序去執行不同 table 的 chain。一旦符合該 chain 的某個 rule,就執行該 rule 的 target。上圖列出了兩個最常見的 target:`ACCEPT` 和 `DROP`。`ACCEPT` 就是讓這封包通過,`DROP` 則是丟掉這個封包。 所以在上面的示意圖可看到,一旦封包符合了 rule,且該 rule 的 target 是 `ACCEPT`,那這個封包就會到下一個 chain,==**而不會繼續比對同一個 chain 後面的 rule**==。==所以 rule 的順序在 `iptables` 是很重要的一件事==!倘若 target 是 `DROP`,就會丟棄該封包、不再對它做處理。 ### Rule 的順序很重要! ![rule order is important](https://hackmd.io/_uploads/H19q1Wwryl.png) 前面有提到,封包一旦進入一個 chain,就會依序去比對該 chain 的 rule,倘若符合某個 rule,就會執行該 rule 指定的 target。 所以再提醒一次~rule 的順序在 `iptables` 是很重要的~若順序錯誤,可能就達不到自己想要的效果! 此外,依據封包執行的結果,大致可將 target 分成兩類:terminating target 和 non-terminating target。 - Terminating target: - 大部分的 target 都屬於這類,像是最常見的 `ACCEPT` 和 `DROP`。執行了這類的 target 後,封包就不會繼續比對同一個 chain 後續的 rule。例如,若是 `ACCEPT`,那封包就會到下一個 chain。 - Non-terminating target: - 這類型的 target 執行後,還是會繼續比對後面的 rule,像是 `LOG`,顧名思義就是會記錄到 log。 ### `iptables` 的 Tables 和 Chains ![Slide41](https://hackmd.io/_uploads/rJdTMPu5yx.png) 目前 `iptables` 內有這五個 tables,但可能會因 kernel 的 configuration 不同而有些許差異: - `filter` table - 最主要負責防火牆功能的 table,也是預設的 table,負責封包過濾的功能,像是 `ACCEPT`(接受)封包,或 `DROP`(丟掉)封包。 - `nat` table - 主要負責處理 network address translation(NAT),像是更改封包的 source address(SNAT)、或是更改封包的 destination address(DNAT)。 - `mangle` table - 此 table 的功能主要是修改封包的 header,像是修改 Time-To-Live(TTL)欄位、Quality of Service(QoS)欄位。此外,也能藉由 `MARK` target 對封包做標記。 - `raw` table - `raw` table 的主要功能是將不需要做 connection tracking(連線追蹤)的封包做 `NOTRACK`,這樣這些封包就不會被 connection tracking,而可以減少 `netfilter` 的負擔。 - 由於若要將封包設定為 `NOTRACK`,就必須要在封包進到 `iptables` 時盡早對其做處理,所以在封包的 `PREROUTING` 和 `OUTPUT` 階段第一個經過的 table 就是 `raw` table(後面會有張整個流程的示意圖)。 - `security` table - 此 table 是用在 Mandatory Access Control(MAC)networking rules。通常是 kernel 有啟用 Linux Security Modules(LSM),這個 table 才會有作用。有用到 LSM 的包括 Security Enhanced Linux(SELinux)。 - MAC 會透過對封包標示 Security Label 來控制是否可存取系統資源,所以此 table 主要的 target 就是對封包做 `SECMARK` 或 `CONNSECMARK` 標示,後續再由像是 SELinux 決定是否允許此封包存取系統。 - 當 `filter` table 的 chain 比對完之後,就會馬上比對 `security` table 的 chain。 :::info ![Slide42](https://hackmd.io/_uploads/rk0dUIOBJe.png) 如果是使用 OpenWRT 的話,OpenWRT 預設使用的 table 是 filter table、nat table、以及 mangle table。 若想要使用 raw table 的話,記得在編譯 kernel 前就要做好設定~ 像是用 `make menuconfig`: - `Kernel modules` - `Netfilter Extensions` - `<*> kmod-ipt-raw` ::: ![Slide44](https://hackmd.io/_uploads/SJCazDdcye.png) 內建的 chain 總共有五個,分別代表封包處理的五個階段: - `PREROUTING` - 封包從 network interface 進入,並且在做 routing decision 之前的階段。 - 做完 routing decision 之後會決定這個封包其目的地是本機、還是只是經過本機。 - 若封包的目的地是本機,那就會進入 `INPUT` chain。 - 若封包只是經過本機、目的地不是本機,那就會進入 `FORWARD` chain。 - `INPUT` - 當封包通過 `PREROUTING` chain,且路由決策判斷其目的地是本機,就會進入 `INPUT` chain,可以在這裡決定本機是否要接受此封包。 - `FORWARD` - 只是經過本機的封包、目的地不是本機。 - 通過 `FORWARD` chain 後會進入 `POSTROUTING`。 - `OUTPUT` - 由本機發出的封包,進入 `iptables` 的第一個階段就是 `OUTPUT` chain。 - 通過 `OUTPUT` chain 後會進入 `POSTROUTING` chain。 - `POSTROUTING` - 若只是經過本機而目的地非本機的封包、以及由本機發出的封包,在離開 network interface 之前的最後一個階段就是 `POSTROUTING` chain。 - 可以在這個階段修改封包的 source address(`SNAT` 或 `MASQUERADE`)。 ![Slide40](https://hackmd.io/_uploads/BJphGvOc1g.png) 每個 table 所內建的 chain。 <!-- 依上面幾張 slides 所示,`iptables` 的 table 有 filter table、nat table、mangle table、以及 raw table。 - Filter table - 最主要負責防火牆功能的 table,也就是負責封包過濾的功能,像是要 `ACCEPT` 某封包,或 `DROP` 某封包。 - 此 table 含有的 chain 的名稱:`INPUT`、`FORWARD`、`OUTPUT` - Nat table - 此 table 主要負責處理 network address translation(NAT),像是更改封包的 source address(SNAT)、或是更改封包的 destination address(DNAT)。 - 此 table 含有的 chain 的名稱:`PREROUTING`、`OUTPUT`、`POSTROUTING` - Mangle table - 此 table 含有的 chain 的名稱:`PREROUTING`、`INPUT`、`FORWARD`、`OUTPUT`、`POSTROUTING` - Raw table - 此 table 含有的 chain 的名稱:`PREROUTING`、`OUTPUT` --> ### 封包處理流程 <!-- ![Slide44](https://hackmd.io/_uploads/SkFWAUd9kg.png) --> ![Slide45](https://hackmd.io/_uploads/H1G-IsgsJe.png) 上圖是 `iptables` 的封包處理流程的簡單示意圖~ ++假如封包從某個 network interface 進來(incoming packet),且目的地是本機(local processing),那這個封包就會經過++: 1. raw table 的 `PREROUTING` chain - 決定此封包是否要做 connection tracking 2. mangle table 的 `PREROUTING` chain 3. nat table 的 `PREROUTING` chain - `PREROUTING` 的 nat table 有可能會做 destination NAT、以變更目的地 address 4. 做 routing decision 判斷此封包目的地是本機(送往 `INPUT` chain)、或者是要被轉發到某個 network interface(送往 `FORWARD` chain) 5. mangle table 的 `INPUT` chain 6. filter table 的 `INPUT` chain - 決定哪些封包可以進入本機 7. security table 的 `INPUT` chain 8. 送到本機(local procession) ++假如某個封包從 network interface 進來(incoming packet),但他的目的地不是本機、只是經過,最終會由某個 interface 出去(outgoing packet),那這個封包就會經過++: 1. raw table 的 `PREROUTING` chain 2. mangle table 的 `PREROUTING` chain 3. nat table 的 `PREROUTING` chain - `PREROUTING` 的 nat table 有可能會做 destination NAT、以變更目的地 address 4. 做 routing decision 判斷此封包目的地是本機(送往 `INPUT` chain)、或者是要被轉發到某個 network interface(送往 `FORWARD` chain) 6. mangle table 的 `FORWARD` chain 7. filter table 的 `FORWARD` chain 8. security table 的 `FORWARD` chain 9. mangle table 的 `POSTROUTING` chain 10. nat table 的 `POSTROUTING` chain - 在 `POSTROUTING` chain 的 nat table 可能會做 `SNAT` 或 `MASQUERADE` 以變更封包的 source address - `SNAT` 是將封包的 source address 修改成固定的 IP address。 - `MASQUERADE` 則是將封包的 source address 修改成他要出去的 network interface 的 IP address。 11. 由 network interface 出去(outgoing packet) ++假如某個封包是由本機產生(locally generated packet),然後經由 network interface 出去(outgoing packet),那這個封包就會經過++: 1. 本機產生的封包會先進行 routing decision,以決定走哪條路由,之後才進入 `OUTPUT` chain 2. raw table 的 `OUTPUT` chain - 決定本機發出的封包是否要做 connection tracking 3. mangle table 的 `OUTPUT` chain 4. nat table 的 `OUTPUT` chain - `OUTPUT` chain 的 nat table 有可能會做 destination nat,更改封包的目的地。 5. filter table 的 `OUTPUT` chain 6. security table 的 `OUTPUT` chain 7. 在經過 `OUTPUT` chain,準備進入 `POSTROUTING` chain 之前,會先進行 re-route check,再重新計算一次路由 - 由於 `OUTPUT` chain 的 nat table 有可能會更改 destination address,所以才會需要再重新計算一次路由 :::info PS. 若封包是由 `FORWARD` chain 到 `POSTROUTING` chain,那就不會做 re-route check。 因為這樣子的封包,其流程是 `PREROUTING` -> routing decision -> `FORWARD` -> `POSTROUTING`。 這樣的封包只有可能在 `PREROUTING` chain 的 nat table 才有可能做 destination nat 更改目的地 address,當他結束 `PREROUTING` chain 後就會做 routing decision,而 `FORWARD` chain 裡面並沒有 nat table,不可能更改目的地 address,所以在進入 `POSTROUTING` chain 前就不用做 re-route check。 ::: 8. mangle table 的 `POSTROUTING` chain 9. nat table 的 `POSTROUTING` chain - 在 `POSTROUTING` chain 的 nat table 可能會做 `SNAT` 或 `MASQUERADE` 以變更封包的 source address - `SNAT` 是將封包的 source address 修改成固定的 IP address。 - `MASQUERADE` 則是將封包的 source address 修改成他要出去的 network interface 的 IP address。 10. 由 network interface 出去(outgoing packet) ## 一些常用的 `iptables` 指令 ![Slide46](https://hackmd.io/_uploads/BkzllXw91e.png) 接下來簡單介紹一些比較常見的 `iptables` 指令~若要看更詳細的內容可以用 `man iptables` 指令查看。 上圖中第一類的指令是在指定的 table 中指定的 chain 做添加(`A` ppend)、刪除(`D` elete)、插入(`I` nsert)規則的指令。 - `-A`:新添加的規則會放在指定的 table 的指定的 chain 的==最後面==。 - `-D`:刪除某個規則, - `-I`:將新的規則插入指定的 table 的指定的 chain 的指定的位子, 第二類的指令則可以新增(`-N`)或刪除(`-X`)使用者自訂義的 chain。 第三個指令則是可以設定指定的 table 的指定的 chain 的 policy。 最後一個則是可以列出指定的 table 的規則。 :::info 在設定 `iptables` 的時候都要有 root user 的權限,所以若是一般使用者的話記得指令前面都要加個 `sudo`。 ::: :::info 以上幾個指令,若沒有指定 table 的話,預設都會是對 filter table 做設定喔~ ::: ![Slide47](https://hackmd.io/_uploads/S1rWlmw5kx.png) 這張 slide 簡單介紹怎麼設定一個規則(後面會介紹幾個我自己有用過的規則~看例子應該會更好懂~) 首先~我們可以指定這條規則的參數,像是: - `-p [!]protocol_name`:指定某個 protocol 的封包。若有加 `!` 則會變成指定「非」某某 protocol 的封包。 - `-s [!]address[/mask]`:source address 是某某 address 的封包。 - `-d [!]address[/mask]`:destination address 是某某 address 的封包。 - `-j target`:符合這條規則的封包,要對他做的操作。 - `-g chain`:符合這條規則的封包,跳到指定的 chain。 - `-i [!]interface_name`:從某個 interface 進來的封包。 - `-o [!]interface_name`:要從某個 interface 出去的封包。 我們也要設定若某個封包符合規則,那要對這個封包做什麼操作(Target),像是: - `ACCEPT`:讓這個封包通過 - `DROP`:把這個封包丟掉,不處理它 - `REJECT`:類似 `DROP`,但還會送封包回去說這個封包被拒絕 - `MASQUERADE`:將封包的 source address 改成他要出去的 interface 的 IP address - `SNAT`:跟 `MASQUERADE` 一樣都會修改封包的 souce address,但 `SNAT` 是設定固定的 IP,`MASQUERADE` 則是依據指定的 network interface 的 IP 做設定。 接下來介紹幾個自己有設定過的 `iptables` 指令~ ![Slide48](https://hackmd.io/_uploads/SkSWxXP9yx.png) 這個指令的功能是: - 添加一個規則到 `nat` table 的 `POSTROUTING` chain 的最後一個位子 - 這個規則是說,只要是從 `enp1s0` 這個 network interface 出去的封包,都對他們做 `MASQUERADE`,也就將他們的 source address 改成 `enp1s0` network interface 的 IP address ![Slide49](https://hackmd.io/_uploads/H1HWg7P5ye.png) 這個指令的功能是: - 添加一個規則到 `filter` table 的 `INPUT` chain 的最後一個位子 - PS. 若沒有指定 table 的話~都是對 `filter` table 做操作喔 - 這個規則是說,只要是 ICMP protocol 的封包,都讓他們通過 ![Slide50](https://hackmd.io/_uploads/ryUWxXwqJg.png) 這個指令的功能是: - 添加一個規則到 `filter` table 的 `FORWARD` chain 的最後一個位子 - 這個規則是說,只要是從 `enx256e` 這個 network interface 進來、且會從 `enp1s0` 這個 network interface 出去的封包,都讓他們通過 ![Slide51](https://hackmd.io/_uploads/SkUZx7DqJl.png) 這個指令的功能是: - 添加一個規則到 `filter` table 的 `FORWARD` chain 的最後一個位子 - 這個規則是說,只要是從 `enp1s0` 這個 network interface 進來、且會從 `enx256e` 這個 network interface 出去的封包,且若這些封包的狀態(`state`)是已建立(`ESTABLISHED`)連線的狀態,就讓這些封包通過 ![Slide51](https://hackmd.io/_uploads/rJKiJQO5yx.png) 前面用 `iptables` 指令所設定的規則,在每次重開機後都不會存在,若希望能保留每次設定的規則,可以用 `iptables-persistent` 這個工具。 安裝 `iptables-persistent`: ```shell $ sudo apt install iptables-persistent ``` 每次設定完規則後就用以下指令儲存規則: ```shell $ sudo netfilter-persistent save ``` 這樣的話規則就會被儲存在以下檔案,並且在每次開機時都將其載入: ```terminal /etc/iptables/rules.v4 /etc/iptables/rules.v6 ``` 此外,順便介紹另一個與 `iptables -L -n` 類似的指令,會將 `iptables` 的規則依序印出來: ```shell $ sudo iptables-save ``` ## 用 `iptables` 設定接受/拒絕 ssh 連線 若想簡單練習 `iptables` 的話,可以練習設定是否要接受/拒絕 ssh 連線~ 若是 Ubuntu Desktop,需要先安裝 ssh server 這樣才能讓別人用 ssh 連進來,在 Ubuntu 的話主要都是安裝 `openssh-server`: ```shell $ sudo apt update $ sudo apt install openssh-server ``` 用以下指令確認確認 `openssh-server` 是 `active (running)`: ```shell $ systemctl status ssh ``` ![image](https://hackmd.io/_uploads/Sk1YgaFsyx.png) :::info 如果 Ubuntu 是虛擬機,且是 VirtualBox 虛擬機的話,記得要先對Ubuntu 虛擬機設定 `Bridged Adaptor`,且 `Name` 選擇 MacBook 連到 Wi-Fi 的 interface `en0`,這樣我的 Ubuntu 虛擬機就會跟我的 MacBook 在同一個 LAN 內: ![image](https://hackmd.io/_uploads/B18vWTFo1x.png) ::: 首先,我的 MacBook 透過 Wi-Fi 介面被分配到的 IP 是 192.168.50.180: ![image](https://hackmd.io/_uploads/Hk75WpKs1x.png) Ubuntu 虛擬機被分配到的則是 192.168.50.241: ![image](https://hackmd.io/_uploads/SkejbaKs1l.png) ### 設定 `iptables` 允許/拒絕 ssh 連線 由於 `ssh` 通常都是用 Transmission Control Protocol (TCP),且 ssh server 是監聽 port 22。所以若要允許/拒絕別人用 ssh 連過來,就要對 `iptables` 的 `filter` table 的 `INPUT` chain 設定說,若有封包是用 TCP protocol、且該封包的 destination port 是 22,我們就接受/拒絕。 如果是要接受所有 ssh 連線,就做以下設定: ```iptables iptables -t filter -A INPUT -p tcp --dport 22 -j ACCEPT ``` - `-t filter -A INPUT`:在 filter table 的 `INPUT` chain 添加(`A` ppend)新的規則 - `-p tcp --dport 22 -j ACCEPT`:對於使用 `tcp` protocol 且 destination port 是 22 的封包,允許這樣的封包通過 若要拒絕所有 ssh 連線,可以做以下設定: ```iptables sudo iptables -t filter -A INPUT -p tcp --dport 22 -j DROP ``` 或 ```iptables sudo iptables -t filter -A INPUT -p tcp --dport 22 -j REJECT ``` - `DROP` 就是丟掉這封包不理他,發送 ssh 連線請求的 client 端會過一陣子得到 timed out 的訊息 - `REJECT` 則會發送一個拒絕的封包,讓發出 ssh 連線請求的 client 知道被拒絕了 ### Test 1 - `DROP` ssh 連線 若用 `iptables` 將 ssh 連線請求的封包設定為 `DROP`,並且用 `tcpdump` 查看是否有封包進來: ![image](https://hackmd.io/_uploads/SkYJfatjJx.png) 可以看到 MacBook 嘗試連過去時,並沒有收到被拒絕的訊息,而是過一段時間後出現 `Operation timed out` 的訊息,因為 Ubuntu 虛擬機的防火牆把這個封包丟掉而不處理它: ![image](https://hackmd.io/_uploads/rkbbMaYo1g.png) ### Test 2 - `REJECT` ssh 連線 若用 `iptables` 將 ssh 連線請求的封包設定為 `REJECT`: ![image](https://hackmd.io/_uploads/ryxVf6KsJx.png) 可以看到 MacBook 發送 ssh 連線請求後,會收到 `Connection refused` 的訊息: ![image](https://hackmd.io/_uploads/BkXSMpYoye.png) ### Test 3 - 只允許特定 IP 的 ssh 連線 接下來,在 LAN 裡面多加一個新的裝置,也就是我的 Marvell ESPRESSObin v7 開發板~他被分配到的 IP 是 192.168.50.141: ![image](https://hackmd.io/_uploads/HyQOfTYske.png) 假設要設定只允許我的開發板的 IP 可以 ssh 連到 Ubuntu 虛擬機,不允許其他的 IP 來進來,就需要依序對 Ubuntu 虛擬機做以下設定: 1. 允許 192.168.50.141 的 ssh 連線請求: ```iptables iptables -t filter -A INPUT -p tcp --dport 22 -s 192.168.50.141 -j ACCEPT ``` 2. 其他的 ssh 連線請求全部都拒絕: ```iptables iptables -t filter -A INPUT -p tcp --dport 22 -j REJECT ``` 這時候 rule 的順序就很重要!如果這兩條規則設定的順序反了,那封包一進到 `INPUT` chain 的 filter table 就會先比對到「拒絕所有 ssh 連線請求的規則」,所以會連來自 192.168.50.141 的連線請求都一併拒絕喔~ 以下是測試的結果~左上角的視窗是對 Ubuntu 虛擬機做 `iptables` 的設定,右下角的視窗則是開發板可以 ssh 連過去: ![image](https://hackmd.io/_uploads/rJQTzTFsyg.png) 我的 MacBook 被拒絕,無法 ssh 連過去~ ![image](https://hackmd.io/_uploads/HkPRzTts1x.png) 若將這兩條規則的順序設反了,那就會連開發板都沒辦法連過去喔: ![image](https://hackmd.io/_uploads/S1_JmTYike.png) ![image](https://hackmd.io/_uploads/Hkye76tjyx.png) ## 其他 `iptables` 相關設定 - [WAN Ping 基本介紹與設定](https://hackmd.io/@cpt/wan_ping) - [DMZ Host 基本介紹與設定](https://hackmd.io/@cpt/dmz_host) ## References - https://linux.die.net/man/8/iptables - https://linux.vbird.org/linux_server/rocky9/0180firewall.php - https://stuffphilwrites.com/2014/09/iptables-processing-flowchart/ - https://homes.di.unimi.it/sisop/qemu/iptables-tutorial.pdf - https://lewestech.com/mirrors/www.iptables.info/en/structure-of-iptables.html - https://gist.github.com/nerdalert/a1687ae4da1cc44a437d - https://man7.org/linux/man-pages/man8/iptables.8.html - http://www.faqs.org/docs/iptables/mangletable.html - https://docs.redhat.com/en/documentation/red_hat_enterprise_linux/6/html/security_guide/sect-security_guide-iptables#sect-Security_Guide-IPTables - https://www.digitalocean.com/community/tutorials/a-deep-dive-into-iptables-and-netfilter-architecture - https://en.wikipedia.org/wiki/Secure_Shell