YellowFish
    • Create new note
    • Create a note from template
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Write
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
    • Invite by email
      Invitee

      This note has no invitees

    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Note Insights
    • Engagement control
    • Transfer ownership
    • Delete this note
    • Save as template
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Versions and GitHub Sync Note Insights Sharing URL Create Help
Create Create new note Create a note from template
Menu
Options
Engagement control Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Write
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
  • Invite by email
    Invitee

    This note has no invitees

  • Publish Note

    Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

    Your note will be visible on your profile and discoverable by anyone.
    Your note is now live.
    This note is visible on your profile and discoverable online.
    Everyone on the web can find and read all notes of this public team.
    See published notes
    Unpublish note
    Please check the box to agree to the Community Guidelines.
    View profile
    Engagement control
    Commenting
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    • Everyone
    Suggest edit
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    Emoji Reply
    Enable
    Import from Dropbox Google Drive Gist Clipboard
       owned this note    owned this note      
    Published Linked with GitHub
    Subscribed
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    Subscribe
    # iptables - Book mode: https://hackmd.io/@ncnu-opensource/book [TOC] ## 防火牆 * 透過設定規則,保護我們的網路環境 * 主要功能: * 擋掉不想要的封包 * 允許想要的封包 * 轉傳封包 * 沒有防火牆: ![image](https://hackmd.io/_uploads/HkR6socra.png =60%x) * 不論是一般或是惡意主機都能連線到我的主機 * 可能會有安全問題 * 有防火牆: ![image](https://hackmd.io/_uploads/BJDqpo9rT.png =85%x) * 透過規則擋掉不想要的封包 * 只讓我們允許的封包進入 * 確保網路環境的安全 ## iptables ### 概述 * Linux 上的一種防火牆軟體 * 使用者可以下指令操作 iptables * iptables 會根據指令去操作 Linux kernel 中的 **Netfilter** 模組,來實現防火牆功能 * 因為是操作 kernel 的模組,所以使用 iptables 時需要有超級使用者權限 (加 sudo) ### 架構 * 由**表 (table)**、**鏈 (chain)**、**規則 (rule)** 組成 * iptable"s",顧名思義有多個 table * **table** 裡有幾個 **chain**,**chain** 裡可以有很多條 **rule** ![image](https://hackmd.io/_uploads/BylJl0SHa.png) ### 運作方式 ![](https://hackmd.io/_uploads/rysfezgQ6.png) * 封包在不同時機點,會由對應 table 的 chain 負責處理 * 再根據使用者在 chain 裡設置的 rule,來決定如何處理封包 ### table & chain * 不同 table 有不同的用途 * ex : 過濾封包、更改封包 IP 位址... * 各個 table 也有各自對應的 chain * 常用的 table 與對應的 chain: * filter (過濾器) * 功用:過濾封包 (同不同意讓封包通過) * 對應的 chain: * INPUT (管理進入本機的封包) * OUTPUT (管理本機送出的封包) * FORWARD (管理轉送的封包) ::: success Q&A ```=1 sudo iptables -A INPUT -j DROP ``` * 這指令是甚麼,下了會發生甚麼事? ::: * nat (位址轉換 **Network Address Translation**) * 功用:對封包**來源/目的地**的 **IP/port** 轉換 * 對應的 chain: * PREROUTING (在路由前處理規則) * POSTROUTING (在路由後處理規則) * OUTPUT (更改本機送出的封包要去哪裡) ::: success Q&A ```=1 sudo iptables -t nat -A PREROUTING \ -d {我的主機 IP} -p tcp --dport 80 \ -j DNAT --to {我的主機 IP}:8080 ``` * 這指令是甚麼,下了會發生甚麼事? ::: ![](https://i.imgur.com/zIHqiY8.png) * filter OUTPUT 和 nat OUTPUT 差異: * filter OUTPUT : 是否同意封包從本機出去 * nat OUTPUT : 更改本機送出的封包要去哪裡 :::info #### 其他少用的 table * mangle * 用於修改封包的 header * raw * 用於停止對封包的追蹤 * security * 用於設定 SELinux 對封包的處理 ::: ### 運作流程 ![image](https://hackmd.io/_uploads/ryJ4hREIT.png) > 綠色的方塊是 table,下方的白色方格是 chain * `nat PREROUTING` * 可以更改封包目的地 (ex : IP、port) * 藉此可以做到轉送封包的功能 * 就像之前講過的 ssh tunnel、proxy server * ex : 連到我的主機 8080 port 的封包,目的地 192.168.1.101 的 80 port ```=1 sudo iptables -t nat -I PREROUTING \ -p tcp --dport 8080 -j DNAT --to 192.168.1.101:80 * 路由判斷 * 決定封包要去哪裡,是要進入主機?還是轉送出去? * 根據 routing table 規則 * `sudo route -n` ![image](https://hackmd.io/_uploads/S1DxguHUa.png) * 路線 A: * 在路由判斷後,若封包要**進入本機**時會走這條 * 會先由 filter table 的 INPUT chain 來決定封包能不能進入本機 * ex : 拒絕進來主機的封包 ```=1 sudo iptables -I INPUT -j DROP ``` * 路線 B: * 在路由判斷後,若封包**沒有要進入本機**時會走這條 * 會先由 filter table 的 FORWARD chain 來決定封包能不能轉送出去 * ex : 拒絕轉送目的是 192.168.56.135 的封包 ```=1 sudo iptables -I FORWARD -d 192.168.56.135 -j DROP ``` * 路線 C: * 當封包要從**本機送出**時會走這條 * 路由判斷後可以在 nat table 的 OUTPUT chain 更改封包的目的地(不常用),再由 filter table 的 OUTPUT chain 決定封包可不可以送出去 * ex : nat OUTPUT 更改封包目的地,從 1.2.3.4 改成 8.8.8.8 ```=1 sudo iptables -t nat -I OUTPUT -d 1.2.3.4 -j DNAT --to 8.8.8.8 ``` * ex : filter OUTPUT 同意送到 192.168.1.101 的封包 ```=1 sudo iptables -I OUTPUT -d 192.168.1.101 -j ACCEPT ``` * `nat POSTROUTING` * 可以更改封包的來源 IP * 比如我在學校內網想要連到外網,需要做來源 IP 的位址轉換 (從我的內網主機 IP,換成防火牆的對外 IP),讓外網回傳封包時找得到目的地 * ex : 從學校防火牆對外網卡 (eth1) 送出的封包,都把來源 IP 換成防火牆的對外 IP (178.87.12.34) ```=1 sudo iptables -t nat -I POSTROUTING -o eth1 -j SNAT --to 178.87.12.34 ``` ### rule * 設定給 iptables 的規則,若封包符合該 rule 就會執行相應的動作 ![](https://i.imgur.com/GpE5clw.png =300x) * rule 有處理的順序性 * 若符合排在前面的 rule ,就會去執行該 rule 相應的動作,並且不會再往下繼續判斷 (類似 if , else if) #### policy * 封包的預設處理方式,如果都沒有符合的 rule 時就會執行這裡 #### target * 符合規則時要進行的動作 * 常見的 target: * ACCEPT : 允許 * REJECT : 拒絕,**會告知**發送者 * 會送 RST 封包,表示連線被拒絕 * 發送者會知道有主機存在 * DROP : 丟掉,**不會告知**發送者 * 不會回傳封包,讓發送者等到 timeout * 發送者沒辦法知道有主機存在 * 對外規則使用 DROP 會較安全 * SNAT : 修改封包的來源 IP * DNAT : 修改封包的目的 IP 和 port :::info 補充其他 target * MASQUERADE : 動態 SNAT * [REDIRECT](https://gsoc-blog.ecklm.com/iptables-redirect-vs.-dnat-vs.-tproxy/) : 更改封包的目的 port * LOG : 記錄到 log,[預設路徑](https://askubuntu.com/questions/348439/where-can-i-find-the-iptables-log-file-and-how-can-i-change-its-location) : `/var/log/kern.log` 和 `/var/log/syslog` ::: ### 指令操作 #### 查看 rule `sudo ipatables [-t table] -L [-nv --line-numbers]` * `-t` : 選擇 table,預設是 filter table * `-L` : 列出 rule * `-n` : 不把 IP 位址解析成域名,所以執行速度較快 * 一般都會使用,不然會等 dns 解析很久 * `-v` : 列出更多資訊 * `--line-numbers` : 顯示編號 (刪除 rule 時會需要這個編號) ![](https://hackmd.io/_uploads/HJChJfSxT.png) * target : 進行的動作 * prot : protocol,使用的封包協定。主要有 tcp, udp, icmp * opt : 額外選項說明 * source : 封包的來源 IP * destination : 封包的目的 IP 和 port #### 更改 policy > policy 是預設的封包處理方式 (default target),當封包都不符合設定的規則時就會依照 policy 設定的方式處理 `sudo iptables [-t table] -P <INPUT, OUTPUT, FORWARD...> <ACCEPT, DROP, ...>` * `-t` : 選擇 table * `-P` : policy,後面接 chain 和 target * 把 filter table 的 INPUT policy 更改為 DROP : ![](https://hackmd.io/_uploads/HJSpXzSla.png) * 為了安全會把 policy 改成 DROP,類似白名單 * BlueT 建議不要去改 policy,而是會在規則都確定沒問題後,在 chain 的最後面加 DROP 規則,目的是避免一些操作錯誤的情況 * 例如 ssh 連線到主機設定 iptables,用 flush 刪掉所有規則時,若 policy 為 DROP,連線就會被切掉 #### 新增rule `sudo iptables [-t table] [-A or -I] <INPUT, OUTPUT,FORWARD...> -j <ACCEPT, DROP, REJECT> [-i -o -p -s -d...]` * `-t` : 選擇 table,後面接 table 名稱 * `-A` : append,新規則加在舊規則後面,後面接 chain 名稱 * `-I` : insert,新規則加在舊規則前面,後面接 chain 名稱 * `-j` : jump,後面接動作 (target) * 以類型來分類其他參數: * 網卡 * `-i` : in interface,封包進來的網卡名稱 ```=1 sudo iptables -I INPUT -i enp0s3 -j ACCEPT ``` * `-o` : out interface,封包出去的網卡名稱 ```=1 sudo iptables -I OUTPUT -o enp0s3 -j ACCEPT ``` * IP位址 * `-s` : source address,封包來源 IP 位址 ```=1 sudo iptables -I INPUT -s 192.168.101.1 -j ACCEPT ``` * `-d` : destination address,封包目的 IP 位址 ```=1 sudo iptables -I INPUT -d 192.168.101.1 -j ACCEPT ``` * `!` : 可用在 -s 和 -d 之前,表示非該 IP ```=1 sudo iptables -I INPUT ! -d 192.168.101.1 -j DROP ``` * 協定 * `-p` : protocol,封包使用什麼協定 (tcp、udp、ICMP...) ```=1 sudo iptables -I INPUT -p ICMP -j DROP ``` * port,當 -p 指定 tcp 或 udp 時可以使用 * `--sport` : source port,封包來源 port ```=1 sudo iptables -I OUTPUT -p tcp --sport 80 -j ACCEPT ``` * `--dport` : destination port,封包目的 port ```=1 sudo iptables -I INPUT -p tcp --dport 80 -j ACCEPT ``` * 模組 * `-m` : 呼叫 iptables 的模組,ex : conntrack 模組 ```=1 sudo iptables -I OUTPUT \ -m conntrack --ctstate "ESTABLISHED,RELATED" -j ACCEPT ``` ::: info conntrack 模組 * 記錄連線的狀態: * NEW : 新建立的連線 * ESTABLISHED : 已建立的連線、NEW 封包的回應封包 * RELATED : 新的連線,但與已建立的連線相關 * ex : `ftp` `21 port` 建立連線,`20 port` 傳送資料 * INVALID : 無效,無法識別狀態的封包 * UNTRACKED : 在 raw 表已被關閉追蹤的封包 * ex : `-A PREROUTING -d 172.20.0.10/32 -p tcp -m tcp --dport 53 -j NOTRACK` * 查看 conntrack 追蹤到的封包 `sudo conntrack -L` ![image](https://hackmd.io/_uploads/S1AoIXkUT.png) * 缺點:占用記憶體空間 ::: * 組合這些參數 ```=1 sudo iptables -I INPUT \ -i enp0s3 -s 192.168.1.101 \ -p tcp --dport 80 -j ACCEPT sudo iptables -I OUTPUT \ -m conntrack --ctstate "ESTABLISHED,RELATED" -j ACCEPT ``` ::: success `-A` 和 `-I` 比較 * 一開始設定如下: ![](https://hackmd.io/_uploads/H1fYqGrla.png) * 用 `-A` 新增規則 ![](https://hackmd.io/_uploads/Bkxzp5MHxp.png) * 用 `-I` 新增規則 ![](https://hackmd.io/_uploads/HyexjGSga.png) ::: #### 刪除 rule * `-D` : Delete,刪除 chain 裡對應編號的 rule `sudo iptables [-t table] -D <INPUT,OUTPUT,FORWAED...> <rule 編號>` * `-F` : Flush,清除 chain 或 table 裡全部的 rule `sudo iptables [-t table] -F <INPUT,OUTPUT,FORWARD...>` * 不加 chain 可以刪除這個 table 的所有規則 #### 範例 ![](https://i.imgur.com/wi1hXY0.png =300x) * 環境: * 在 http server 主機上設定 iptables,對外網卡是 eth1 * `INPUT` 和 `OUTPUT` chain 的 policy 都是 `DROP` * 要求: * Good user 可以透過 eth1 網卡連線到 http server * Bad user 和其他沒提到的 user 都無法透過 eth1 網卡連線到 http server * 讓 Good user 可以透過 eth1 網卡連線到 http server :::spoiler 解答 同意 Good user 連進來 ```=1 sudo iptables -A INPUT -i eth1 -s 192.168.0.101 -j ACCEPT ``` 這樣就夠了嗎? 還要同意把封包送回去 * 做法 1 (再寫一個出去的規則) ```=1 sudo iptables -A OUTPUT -o eth1 -d 192.168.0.101 -j ACCEPT ``` * 做法 2 (用封包狀態來設定規則) ```=1 sudo iptables -A OUTPUT \ -m conntrack --ctstate "ESTABLISHED,RELATED" -j ACCEPT ``` ::: * 讓 Bad user 和其他沒提到的 user 都無法透過 eth1 網卡連線到 http server :::spoiler 解答 不用寫,因為 `INPUT` 跟 `OUTPUT` chain 的 policy (預設行為) 都是 DROP 但如果還是要寫的話... * bad user 無法透過 eth1 網卡連線到 http server ```=1 sudo iptables -A INPUT -i eth1 -s 192.168.0.102 -j DROP ``` * 其他 user 無法透過 eth1 網卡連線到 http server * 加在所有規則後面就等同於其他使用者 ```=1 sudo iptables -A INPUT -i eth1 -j DROP ``` ::: ::: info [**Stateful Firewall** vs **Stateless Firewall**](https://lin0204.blogspot.com/2017/01/blog-post_30.html) * **Stateless Firewall** 無狀態防火牆 * 不會記錄封包的狀態 * 例子: * 同意來源地為 A 或 B 的封包進入我的主機,其它都拒絕 * 本機出去的封包 policy 為 DROP * 回傳封包時需要在規則設定 **目的地為 A 或 B** 的封包要同意送出 * 特點: * 每個封包進出的規則都需要各寫一次 (如前面的做法 1) * **Stateful Firewall** 有狀態防火牆 * 會記錄封包的狀態 * 例子: * 同意來源地為 A 或 B 的封包進入我的主機,其它都拒絕 * 本機出去的封包 policy 為 DROP * 回傳封包時只要在規則設定 **連線狀態為已建立** 的封包要同意送出就好 * 特點: * 只需寫進或出其中一個的規則,另一個就可以用狀態來設定規則 (如前面的做法 2) ::: ### 儲存 iptables 設定 * iptables 不會自動保存和載入設定,關機就會消失:cry: * 保存方法: * 先把設定 save 到檔案裡,要用的時候再 restore 回去 1. `iptables-save > 設定檔` 把輸出的結果寫入到設定檔裡 (可以自己決定,不過通常會存到 `/etc/network/iptables.up.rules`) * `iptables-save` 可以輸出目前 iptables 的設定 2. `iptables-restore < 設定檔` 把設定檔的內容載入到 iptables > 直接改 iptables 設定可能會有改錯的風險 > * 如果是用 ssh 連線到主機設定 iptables,設定時不小心把 ssh 連線設定成 DROP,連線就斷了 :scream: > * 那測試規則沒問題再套用呢? ### iptables-apply * 測試新的 iptables 規則 * 會詢問使用者 y/N,選 y 就會套用,選 N 或是太長時間沒有回應就會變回舊的規則 * 用 `-t` 可以設定這個時間的長短 * 做法:先把新加的規則寫到設定檔裡,再對設定檔下 `iptables-apply` * 指令: * `sudo iptables-apply 設定檔` * 後面不加設定檔會以預設的路徑 : `/etc/network/iptables.up.rules` > 如果直接把新規則寫到設定檔去 apply,但最後 apply 失敗了需要還原,卻忘記怎麼還原成一開始的設定,設定檔就壞了 :fearful: > * 除了一開始就規劃好**一個正式設定檔**和**一個測試設定檔**,來避免改錯時無法還原之外? > * 如果可以把要測的規則,寫在另一個獨立的檔案? #### iptables-apply -c * 測試 iptables command * 把新規則先寫到原本的設定檔再去 apply,可能會有無法還原的風險,那可以先把指令寫到其他檔案裡,用 `-c` 去 apply * iptables command ![image](https://hackmd.io/_uploads/rkaxjKHLa.png) * 做法:先在新的檔案裡寫 iptables 的指令,再對新的檔案下 `iptables-apply -c` * 指令: * `sudo iptables-apply -c 檔案名` * 不加檔案名會以預設路徑 : `/etc/network/iptables.up.run` > 如果有規劃好**一個正式設定檔**和**一個測試設定檔**,有沒有辦法在 apply **測試設定檔**沒有問題後,同時寫入**正式的設定檔**? #### iptables-apply -w * 將測試後沒問題的測試設定檔,寫入正式的設定檔 * 指令: * `iptables-apply -w {被寫入的檔案} {要測試的設定檔}` * 只寫一個檔名,要測試的檔案會套用預設路徑: `/etc/network/iptables.up.rules` * 在 apply 成功後,會把後面設定檔的內容,寫到前面的設定檔 ## NAT * Network Address Translation * 內網和外網 IP 位址之間的轉換 * 只要一個外網 IP,就能讓多個內網主機可以上網 ![](https://i.imgur.com/mJC8YIa.png =120%x) Why? * IPv4 的位址數量不夠用 -> 使用內網 IP * 外網無法連線內網 IP (會找不到) -> 用 NAT 來轉換 * 有 SNAT、DNAT、MASQUERADE ![image](https://hackmd.io/_uploads/ryJ4hREIT.png) ### SNAT > Source NAT * 在路由後(POSTROUTING)將封包的來源 IP 從內網 IP 修改為 NAT 主機的外網 IP * 目的:讓外網回傳封包時能找到內網主機 #### 情境:內網主機 (192.168.1.100) 要連線到外網 (域名 tw.yahoo.com): ![](https://i.imgur.com/BbOi9ph.png =120%x) 1. 內網主機 192.168.1.100 傳遞封包給 NAT 主機 2. NAT 主機發現目的地不是內網,先透過路由轉到外網網卡 3. 因為內網和外網不能互通,所以就在 POSTROUTING chain 把來源 IP 從內網 IP 換成外網 IP,另外會在 **NAT translation table** 把這兩個來源 IP、port 的對應關係記錄起來,之後回應封包傳回來時就能知道要傳給內網的哪台主機 ![image](https://hackmd.io/_uploads/rJFXKW_Ia.png =60%x) ![image](https://hackmd.io/_uploads/BkXGtDZPa.png) 4. 外網回傳封包,目的地是 NAT 主機的外網 IP 5. 在 Prerouting chain 根據 NAT 轉譯表的紀錄更改封包目的地 6. 封包成功送給內網主機 * 範例: ```=1 sudo iptables -t nat -I POSTROUTING -o {外網網卡} -j SNAT --to {NAT 主機 IP} ``` ### MASQUERADE > 動態 SNAT * SNAT 是靜態的,必須在 rule 手動設定外網 IP * 如果外網 IP 有變動,SNAT 就需要手動去修改 (可能會很麻煩) * MASQUERADE 會自己去找能連上外網的網卡,看那個網卡的外網 IP 是什麼來當作 SNAT 的來源 IP * 範例: ```=1 sudo iptables -t nat -I POSTROUTING -o {外網網卡} -j MASQUERADE ``` ### DNAT > Destination NAT * 跟 SNAT 相反 * 在路由前(PREROUTING)將外網封包的目的 IP 從外網 IP 修改為內網主機的 IP * 目的:讓外網能主動連線到內網主機 > 除了 ssh tunnel 之外,也可以用 DNAT 的方式 #### 情境 : 你在內網主機架了 Web Server,要讓外網連進來 > 先在 NAT 設定送到 NAT 80 port 的封包,會轉送到內網主機的 80 port ![](https://i.imgur.com/Yfu3Dja.png =120%x) 1. 外網要連到內網主機的 Web Server,需要先連到 NAT 主機上 2. 當 NAT 主機接收到封包後,會在 PREROUTING chain 將目的 IP 從外網 IP 改成內網 IP,也就是變成連線到 192.168.1.210 的 80 port,另外也會在 **nat translation table** 把這兩個目的 IP、port 的對應關係記錄起來 3. 封包會路由到 192.168.1.2 這個內網網卡,然後再傳送到目的地192.168.1.210 的 80 port ![image](https://hackmd.io/_uploads/ry72DX_L6.png =60%x) * 範例: ```=1 sudo iptables -t nat -I PREROUTING \ -p tcp --dport 80 -j DNAT --to 192.168.1.210:80 ``` ### 統整 | | SNAT | DNAT | MASQUERADE | | -------- | -------- | -------- | --------| | 功用 | 更改封包的來源 IP | 更改封包的目的 IP | 動態 SNAT | | 使用場景 | 讓內網主機可以連線外網 | 讓外網能主動連到內網主機 | 不用手動更改 SNAT 設定的外網 IP | ### NAT 實作 #### 架構 ![image](https://hackmd.io/_uploads/HJKdAs7rT.png) #### 前置處理 > NAT 主機 * 網卡:橋接介面卡 & 僅限主機介面卡 * 橋接介面卡 ![image](https://hackmd.io/_uploads/SJvjJ3QSa.png =80%x) * 僅限主機介面卡 ![image](https://hackmd.io/_uploads/HJrh1h7Ba.png =80%x) * 開啟 NAT 主機的 kernel 轉送功能 (預設是關閉的) * `sudo vim /etc/sysctl.conf` 改成 `net.ipv4.ip_forward=1` ![image](https://hackmd.io/_uploads/SkWzl3mH6.png =80%x) * `sudo sysctl -p` 載入設定,讓修改立即且永久生效 (重開機也會保存) > 內網 Web Server 主機 * 網卡:主機介面卡 * 僅限主機介面卡 ![image](https://hackmd.io/_uploads/Sychx2mS6.png =80%x) * 設定 Web Server 主機的 default gateway 刪除原本的 default gateway,改成 NAT 主機 IP ```=1 sudo route del default sudo route add default gw {NAT 主機 IP} ``` 或是直接更改 default gateway 為 NAT 主機 IP ```=1 sudo ip route replace default via {NAT IP} dev {本機對外網卡} ``` ![image](https://hackmd.io/_uploads/rJKYDs7BT.png) #### iptables 設定 (On NAT) > 功能要求 1. 將內網主機要送往外網的封包,轉送到外網 2. 同意將外網回應的封包,回傳給內網主機 3. 將外網連線到 NAT 80 port 的封包,轉送到內網主機 8080 port 上的 Web Server > `INPUT`、`FORWARD`、`OUTPUT` 的 policy 都是 `ACCEPT` ![image](https://hackmd.io/_uploads/ryJ4hREIT.png) > 將 Web Server 主機要送往外網的封包,轉送到外網 * 將 Web Server 主機要送往外網的封包,轉送到外網 ```=1 sudo iptables -A FORWARD -i {lan nic} -o {wan nic} -j ACCEPT ``` * 送到外網的封包做 MASQUERADE,這樣外網才能根據外網 IP 回傳封包給 NAT 主機,NAT 主機再轉送給 Web Server 主機 ```=1 sudo iptables -t nat -A POSTROUTING -o {wan nic} -j MASQUERADE ``` > 同意將外網的回應封包,回傳給 Web Server 主機 * 同意轉送已建立、相關的連線 ```=1 sudo iptables -A FORWARD \ -m conntrack --ctstate \ "ESTABLISHED,RELATED" -j ACCEPT ``` > 將外網連線到 NAT 主機 80 port 的封包,轉送到 Web Server 主機 8080 port 上的 Apache * 將連線到 NAT 主機 80 port 的封包的目的地,改成 Web Server 主機的 8080 port ```=1 sudo iptables -t nat -A PREROUTING \ -p tcp --dport 80 \ -j DNAT --to {Web Server IP}:8080 ``` * 同意轉送目的地是內主機 8080 port 的封包 ```=1 sudo iptables -I FORWARD \ -d {Web Server IP} -p tcp --dport 8080 \ -j ACCEPT ``` :::info [tcpdump](https://www.jinnsblog.com/2020/09/linux-tcpdump-network-traffic-tutorial.html) * 封包監控工具,類似wireshark * 針對網卡、協定、IP 等資訊設定過濾條件 * 可用來測試主機是否有收到對應的封包 ![image](https://hackmd.io/_uploads/B1quaqB8T.png) ::: #### ## DMZ * Demilitarized Zone (非軍事區) * 用防火牆將內網分成兩個區塊 1. 對外開放的 **DMZ** 2. 不對外開放的 **LAN** (內網的其他主機) ![image](https://hackmd.io/_uploads/HyYHwjFHp.png) Why? * 有服務必須開放給外網使用,ex : Web Server * 但對外開放服務就會有被攻擊的風險 * 盡量減少被攻擊時的受災區域 * 把受災區域只限縮在 DMZ,而不是整個內網都淪陷 ### 做法 * 用防火牆限制外網、DMZ、LAN 三者之間的封包傳遞 ![image](https://hackmd.io/_uploads/HyJ5LJSLa.png) * 外網可以直接連線 DMZ,但不能直接連線 LAN * DMZ 可以直接連線外網,但不能直接連線 LAN * LAN 可以直接連線外網,也可以直接連線 DMZ ### DMZ 實作 > 可以回去自己做看看,擔心開三台 VM RAM 會不夠的話,可以裝 server 版 (無介面) #### 架構 * 在一台 **Firewall** 主機上設定防火牆 * **DMZ** 中有一台對外開放的 **Web Sever** 主機,80 port 上有 Apache 服務 * **LAN** 中有一台不對外開放的 **Student** 主機 * **外網** 透過連線到 **Firewall** 主機的 8080 port,可以連線到 **Web Server** 主機的 80 port * `INPUT`、`FORWARD`、`OUPUT` 的 policy 都是 `ACCEPT` #### 測試環境網卡、IP 對照 * 網卡 * 外網網卡 * wlo1 * DMZ 網卡 * virbr1 * `192.168.123.1/24` * LAN 網卡 * vribr2 * `192.168.124.1/24` * IP * Firewall 主機 * DMZ 網路 * `192.168.123.1` * LAN 網路 * `192.168.124.1` * DMZ 中的 Web Server 主機 * `192.168.123.129` #### 前置處理 * Firewall 主機開啟 kernel 轉送功能 改成 net.ipv4.ip_forward=1 ```=1 sudo vim /etc/sysctl.conf ``` 套用設定 ```=1 sudo sysctl -p ``` * 設定 DMZ 和 LAN 的 default gateway (設成 Firewall 主機 IP) ```=1 sudo route del default sudo route add default gw {Firewall IP} ``` #### 外網進來的封包 * 可以連 DMZ * 將外網連到 Firewall 8080 port 的封包,轉送到 Web Server 80 port ```=1 sudo iptables -t nat -A PREROUTING \ -i {外網網卡} -p tcp --dport 8080 \ -j DNAT --to {Web Server IP}:80 ``` * 同意該封包轉送 ```=1 sudo iptables -A FORWARD \ -i {外網網卡} -d {Web Server IP} \ -p tcp --dport 80 -j ACCEPT ``` * 不能連 LAN * 後面統一設定 #### DMZ 發出的封包 * 可以連外網 ```=1 sudo iptables -I FORWARD -i {DMZ 網卡} -o {外網網卡} -j ACCEPT sudo iptables -t nat -I POSTROUTING -o {外網網卡} -j MASQUERADE ``` * 不能連 LAN * 後面統一設定 #### LAN 發出的封包 * 可以連外網 ```bash=1 sudo iptables -I FORWARD -i {LAN 網卡} -o {外網網卡} -j ACCEPT # 出去的封包做 MASQUERADE 在前面已經設過,所以這裡就不用再設定 ``` * 可以連 DMZ * 不限制只能連到 80 port,也允許 ssh 進去等其他功能 ```=1 sudo iptables -I FORWARD -i {LAN 網卡} -o {DMZ 網卡} -j ACCEPT ``` #### 其他 * 允許轉送已建立或相關的連線 ```bash=1 sudo iptables -I FORWARD \ -m conntrack --ctstate "ESTABLISHED,RELATED" \ -j ACCEPT ``` * 拒絕其他進來 Firewall 主機的連線 ```=1 sudo iptables -A INPUT -j DROP ``` * 拒絕轉送其他連線 * 要用 `-A` 加在最後面,不然所有轉送的封包都會被 DROP 掉 ```=1 sudo iptables -A FORWARD -j DROP ``` #### 規則結果 * filter table ![image](https://hackmd.io/_uploads/SJlAle-Ua.png) * nat table ![image](https://hackmd.io/_uploads/rkBg-xbIT.png) ::: info **LAB** 環境 / 已有設定 同上 **要求** 1. 猛哥畢業專題寫了一個網站,但怕 LAN 裡的其他白目同學連上去亂搞,所以不能讓 LAN 的所有主機連到外網 IP 為 163.22.17.184 的主機 4200 port 上的網站 2. 柏瑋是助教中的老大,LAN 中只有他的主機 (192.168.124.149) 能 ssh 連線到 Firewall 主機 (其他 LAN 主機不行),這樣他不用出門就可以遠端調整防火牆的設定了 3. 柏瑋不爽黃魚很久了,所以他偷偷設定讓黃魚在 LAN 的主機 (192.168.124.196) 不能連到外網和 DMZ 4. 人在台中 (外網) 的 Wally 想透過 ssh 到 Firewall 的 8081 port,來連到他在 DMZ 的 Web Server 主機,調整他的 nginx server 的設定 **需要多加或修改哪些設定?** :::spoiler 解答 1. 拒絕轉送 LAN 主機連到外網 163.22.17.184 主機 4200 port 的封包 ```=1 sudo iptables -I FORWARD \ -i {內網網卡} -d 163.22.17.184 \ -p tcp --dport 4200 -j DROP ``` 2. 同意 LAN 中的 柏瑋主機 (192.168.124.149) ssh 到 Firewall 主機,其他 LAN 主機則拒絕 ```=1 sudo iptables -I INPUT \ -i {內網網卡} -s 192.168.124.149 \ -p tcp --dport 22 -j ACCEPT # 如果有原本的 INPUT -j DROP (拒絕連進 Firewall 的連線),可以不用打拒絕的部分 sudo iptables -A INPUT \ -i {內網網卡} -p tcp --dport 22 -j DROP ``` 3. 拒絕轉送 LAN 中的 黃魚主機 (192.168.124.196) 到 DMZ 和 外網 的封包 ```=1 sudo iptables -I FORWARD \ -i {內網網卡} -s 192.168.124.196 -j DROP ``` 4. 把外網連到 Firewall 主機 8081 port 的封包改成送到 DMZ 中 Web Server 的 22 port (ssh port),並同意轉送 ```=1 sudo iptables -I PREROUTING \ -i {外網網卡} -p tcp --dport 8081 \ -j DNAT --to {Web Server IP}:22 sudo iptables -I FORWARD \ -i {外網網卡} -d {Web Server IP} \ -p tcp --dport 22 -j ACCEPT ``` #### 規則結果 * filter table ![image](https://hackmd.io/_uploads/S1GEXl-U6.png) * nat table ![image](https://hackmd.io/_uploads/HyjtXxb86.png) ::: :::info **無介面相關補充** * [下載 ubuntu-server iso](https://ubuntu.com/download/server),並安裝虛擬機 ![image](https://hackmd.io/_uploads/ryUBBiSLa.png =80%x) * 連線測試工具,ex : 測試連到 webserver * w3m * ex : `w3m http://192.168.100.36:80` ![image](https://hackmd.io/_uploads/SJd98iSIa.png =80%x) * telnet * ex : `telnet 192.168.100.36 80` ![image](https://hackmd.io/_uploads/B1mHPoSLT.png) ::: ## 較簡易操作的防火牆 ### UFW > Uncomplicated Firewall * iptables 的簡易操作介面 * 安裝指令 : `sudo apt install ufw` * ubuntu 預設會安裝,但若沒有就下這個指令 #### 開關 ufw * 查看狀態 ```=1 sudo ufw status ``` * 詳細狀態 ```=1 sudo ufw status verbose ``` * 啟用 ufw ```=1 sudo ufw enable ``` * 關閉 ufw ```=1 sudo ufw disable ``` * 重設 ufw ```=1 sudo ufw reset ``` #### 查看規則 * 顯示目前規則 & 編號 : ```=1 sudo ufw status numbered ``` #### 設定預設規則 * 預設允許 ```=1 sudo ufw default allow ``` * 預設拒絕 ```=1 sudo ufw default deny ``` #### 設定 port 或服務規則 * 針對服務 * 允許 ssh port : ```=1 sudo ufw allow ssh ``` * 針對 port * 拒絕 22 port : ```=1 sudo ufw deny 22 ``` * 針對一個範圍的 port & protocol * 允許 TCP 6000~6007 port : ```=1 sudo ufw allow 6000:6007/tcp ``` #### 設定 IP 規則 * 單獨 IP * 允許 192.168.11.10 的所有連線 : ```=1 sudo ufw allow from 192.168.11.10 ``` * 針對網段 * 拒絕 192.168.11.0/24 的所有連線 : ```=1 sudo ufw deny from 192.168.11.0/24 ``` * 針對 IP 和 port * 拒絕某 IP 連到某 port : ```=1 sudo ufw deny from 192.168.11.7 to any port 22 ``` #### 刪除規則 * 刪除第 3 條規則 ```=1 sudo ufw delete 3 ``` ### [UIF](https://manpages.ubuntu.com/manpages/focal/en/man8/uif.8.html) > Userfriendly Iptables Frontend * 另一個簡易操作 iptables 的介面 * 以**代稱**來進行設定 * ex : 設定 bad_user 代表 `192.168.100.15`,只要是 bad_user 的封包都拒絕掉 * 預設會把 filter table 的 `INPUT` `OUTPUT` `FORWARD` chain 的 policy 改成 `DROP` * 安裝指令:`sudo apt install uif` :::spoiler 啟動初始設定介面 `sudo dpkg-reconfigure -plow uif` ::: #### 設定代稱 * 在目錄 `/etc/uif/uif-ipv4-networks.inc` * 設定 **代稱** 對應的 **IP** ![image.png](https://hackmd.io/_uploads/rkb3id7Qa.png =50%x) #### 設定規則 * 在目錄 `/etc/uif/uif.conf` * 參數: * `in` : 進來的封包 * `out` : 出去的封包 * `+` : 同意 * `-` : 拒絕 * `s` : 來源地 * `d` : 目的地 * `i` : 進來的網卡 * `o` : 出去的網卡 * 新增拒絕 bad_user (192.168.100.15) 進來的封包 ![image.png](https://hackmd.io/_uploads/SkAEFYQmT.png =50%x) * loop 對應本機網卡 lo * 對應關係寫在 `/etc/uif/uif.conf` ![image.png](https://hackmd.io/_uploads/ByB5tKmXT.png =30%x) #### 套用規則 * 用 `-c` 指定要套用的設定檔 ```=1 sudo uif -c /etc/uif/uif.conf ``` #### 印出目前規則 ```=1 sudo uif -p ``` #### 清除寫到 iptables 的規則 ```=1 sudo uif -d ``` #### uif manpage link * https://manpages.ubuntu.com/manpages/focal/en/man8/uif.8.html * https://manpages.ubuntu.com/manpages/focal/en/man5/uif.conf.5.html :::info ## 補充 ### [netfilter](https://zh.wikipedia.org/zh-tw/Netfilter) ![image](https://hackmd.io/_uploads/B1eSQO-Up.png) * Linux kernel 中的一個軟體框架 * 實際處理防火牆功能 * 使用者是透過對 iptables 下指令來操作 Netfilter -> 實現防火牆功能 * iptables 在 Netwok Layer ### [ebtables](https://linux.die.net/man/8/ebtables) * Link Layer 的防火牆 * 可以設定 MAC Address 相關的規則 * 架構和 iptables 類似 * 都有 table (表)、chain (鏈) 、rule (規則) * 用法和 rule 的結構也很相似: * 查看 * `ebtables -L` * `ebtables -L --Ln` 顯示編號 * 新增 * `ebtables [-t table] [-A chain] [rule]` * `-s` 來源地 MAC 位址 * `-d` 目的地 MAC 位址 * 刪除 * `ebtables -D [chain] [rule number]` * 處理的封包比 iptables 更底層、更原始 ### [nftables](https://hackmd.io/@0xff07/SJqzX9WnF) **概述** * 用來取代 iptables * 結合了 iptables、ip6tables、arptables 等防火牆工具 * 可以控制整個 netfilter * 類型有 `ip`、`ip6`、`inet`、`arp`、`bridge`、`netdev` * inet 同時包含 IPv4 和 IPv6,可以不用像 iptables 和 ip6tables 分開設定 * 架構也是由 table、chain 和 rule 組成 **運作流程** * 流程圖 ![image](https://hackmd.io/_uploads/Sk-RQFWIT.png) **指令** * 查看 * 查看 table、chain、rule * `sudo nft list tables` * `sudo nft list chains` * `sudo nft list ruleset` * 可以把 iptables 的指令轉為 nftables 指令 ```=1 sudo iptables-translate -A INPUT -s 192.168.1.123 -j ACCEPT # nft add rule ip filter INPUT ip saddr 192.168.1.123 counter accept ``` * 把 iptables 設定檔轉到 nftables * 輸出 iptables 設定 * `sudo iptables-save > iptables.conf` * 把設定轉換並載入到 nft 檔案 * `sudo iptables-restore-translate -f iptables.conf > ruleset.nft` * nftables 再載入 nft 設定檔 * `sudo nft -f ruleset.nft` :::

    Import from clipboard

    Paste your markdown or webpage here...

    Advanced permission required

    Your current role can only read. Ask the system administrator to acquire write and comment permission.

    This team is disabled

    Sorry, this team is disabled. You can't edit this note.

    This note is locked

    Sorry, only owner can edit this note.

    Reach the limit

    Sorry, you've reached the max length this note can be.
    Please reduce the content or divide it to more notes, thank you!

    Import from Gist

    Import from Snippet

    or

    Export to Snippet

    Are you sure?

    Do you really want to delete this note?
    All users will lose their connection.

    Create a note from template

    Create a note from template

    Oops...
    This template has been removed or transferred.
    Upgrade
    All
    • All
    • Team
    No template.

    Create a template

    Upgrade

    Delete template

    Do you really want to delete this template?
    Turn this template into a regular note and keep its content, versions, and comments.

    This page need refresh

    You have an incompatible client version.
    Refresh to update.
    New version available!
    See releases notes here
    Refresh to enjoy new features.
    Your user state has changed.
    Refresh to load new user state.

    Sign in

    Forgot password

    or

    By clicking below, you agree to our terms of service.

    Sign in via Facebook Sign in via Twitter Sign in via GitHub Sign in via Dropbox Sign in with Wallet
    Wallet ( )
    Connect another wallet

    New to HackMD? Sign up

    Help

    • English
    • 中文
    • Français
    • Deutsch
    • 日本語
    • Español
    • Català
    • Ελληνικά
    • Português
    • italiano
    • Türkçe
    • Русский
    • Nederlands
    • hrvatski jezik
    • język polski
    • Українська
    • हिन्दी
    • svenska
    • Esperanto
    • dansk

    Documents

    Help & Tutorial

    How to use Book mode

    Slide Example

    API Docs

    Edit in VSCode

    Install browser extension

    Contacts

    Feedback

    Discord

    Send us email

    Resources

    Releases

    Pricing

    Blog

    Policy

    Terms

    Privacy

    Cheatsheet

    Syntax Example Reference
    # Header Header 基本排版
    - Unordered List
    • Unordered List
    1. Ordered List
    1. Ordered List
    - [ ] Todo List
    • Todo List
    > Blockquote
    Blockquote
    **Bold font** Bold font
    *Italics font* Italics font
    ~~Strikethrough~~ Strikethrough
    19^th^ 19th
    H~2~O H2O
    ++Inserted text++ Inserted text
    ==Marked text== Marked text
    [link text](https:// "title") Link
    ![image alt](https:// "title") Image
    `Code` Code 在筆記中貼入程式碼
    ```javascript
    var i = 0;
    ```
    var i = 0;
    :smile: :smile: Emoji list
    {%youtube youtube_id %} Externals
    $L^aT_eX$ LaTeX
    :::info
    This is a alert area.
    :::

    This is a alert area.

    Versions and GitHub Sync
    Get Full History Access

    • Edit version name
    • Delete

    revision author avatar     named on  

    More Less

    Note content is identical to the latest version.
    Compare
      Choose a version
      No search result
      Version not found
    Sign in to link this note to GitHub
    Learn more
    This note is not linked with GitHub
     

    Feedback

    Submission failed, please try again

    Thanks for your support.

    On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

    Please give us some advice and help us improve HackMD.

     

    Thanks for your feedback

    Remove version name

    Do you want to remove this version name and description?

    Transfer ownership

    Transfer to
      Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

        Link with GitHub

        Please authorize HackMD on GitHub
        • Please sign in to GitHub and install the HackMD app on your GitHub repo.
        • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
        Learn more  Sign in to GitHub

        Push the note to GitHub Push to GitHub Pull a file from GitHub

          Authorize again
         

        Choose which file to push to

        Select repo
        Refresh Authorize more repos
        Select branch
        Select file
        Select branch
        Choose version(s) to push
        • Save a new version and push
        • Choose from existing versions
        Include title and tags
        Available push count

        Pull from GitHub

         
        File from GitHub
        File from HackMD

        GitHub Link Settings

        File linked

        Linked by
        File path
        Last synced branch
        Available push count

        Danger Zone

        Unlink
        You will no longer receive notification when GitHub file changes after unlink.

        Syncing

        Push failed

        Push successfully