# Linux 核心專題: 透過 Netfilter 自動過濾廣告 > 執行人: gawei1206 > [專題解說錄影](https://youtu.be/ZQmKOuNmFf8) ### Reviewed by `SuNsHiNe-75` 好奇此 Netfilter 可過濾哪些傳輸協定(如 UDP、TCP)的封包,連 QUIC 的封包都能過濾嗎? >[name=gawei1206] >關於這個問題我可能要再確認一下 ### Reviewed by `yinghuaxia` > 規則放置在特定 table 的特定 chain 裡面。當 chain 被呼叫的時候,封包會依序比對 chain 裡面的規則,根據封包的資料比對先前定義的規則內容,若封包資料與規則內容相同則進行動作,否則就繼續下一條規則的比對。 這裡所說的規則為何?而 chain 是如何被呼叫的?在什麼情況下會呼叫特定的 chain?根據封包的資料比對是比對哪些條件? >[name=gawei1206] >這邊所說的規則是用來定義如何處理封包的具體指令。每條規則包含一個符合條件和一個動作,像以下這條規則 >`$ sudo iptables -A OUTPUT -o enp3s0f1 -d 103.31.6.33 -j REJECT` >條件(-o enp3s0f1 -d 103.31.6.33):表示發送至 103.31.6.33 的封包,並且這些封包透過介面 enp3s0f1 發送 >目標動作(-j REJECT):表示拒絕這些封包 >OUTPUT : 當封包從本地主機發送出去時呼叫 ### Reviewed by `nosba0957` 封包處理是在哪個 hook 處理?還是 5 個 hook 都有對應處理? >[name=gawei1206] >這邊的是在 `NF_IP_LOCAL_OUT` ### Reviewed by `steven523` 我看去年同樣做這個主題的學員沒有成功阻擋 HTTPS 類型的廣告,請問你有嘗試用什麼方法成功阻擋過嗎 ### Reviewed by `jujuegg` 在阻擋廣告的方法中,你提到的 2 個辦法都需要得知特定廣告伺服器的網域名稱,請問現在有甚麼方法可以一次性的阻擋掉所有廣告的封包嗎? ## 簡介 在 Linux v6.8 重現[透過 Netfilter 自動過濾廣告](https://hackmd.io/@sysprog/BJb0NRYH3)實驗,並修正對應的程式碼。 ## TODO: 探討 netfilter 原理並闡述過濾廣告的策略 > 可重用去年報告的素材,但要更新到 Linux v6.8+ ### 1. Netfilter 與 iptables Netfilter 是 Linux 核心中的一個框架,用於處理封包內容修改及過濾,我們可以透過 iptables 告訴 Netfilter 如何處理接收到的或是準備發送出去的封包。 iptables 他會透過分析封包的表頭資料來進行封包的過濾,根據表頭資料與我們自己定義的規則來決定該封包是否可以進入主機或者是被丟棄。 :::danger 介紹 netfilter,應該闡述 Linux 核心的封包處理流程。參見本學期教材 [Linux 核心網路](https://hackmd.io/@rickywu0421/linux_networking_1) 不要捨近求遠,本課程教材已經整理很多關鍵概念,避免學員研讀網際網路上面一堆品質低劣的簡體中文素材。 ::: ### 2. Netfilter Hooks Netfilter 提供了 5 個 hook,當封包經過這些 hook 時我們可以對封包進行過濾或是修改內容。 `NF_IP_PRE_ROUTING` 是在做 Routing 之前的 hook `NF_IP_LOCAL_IN` 是在把封包傳遞到 local process 之前的 hook `NF_IP_FORWARD` 是在把封包傳遞到別的 network interface 之前的 hook `NF_IP_POST_ROUTING` 是在做 Routing 之後的 hook `NF_IP_LOCAL_OUT` 是從 local 往外傳遞的封包的 hook 每個 hook 的位置可以參考下圖: ```graphviz digraph "IPv4 Diagram" { rankdir=LR "Remote IN" -> "[NF_IP_PRE_ROUTING]" -> "ROUTE" ROUTE -> "[NF_IP_LOCAL_IN]" -> "local" "\ local" -> "[NF_IP_LOCAL_OUT]" -> "\ROUTE" -> "[NF_IP_POST_ROUTING]" -> "Remote Out" ROUTE -> "[NF_IP_FORWARD]" -> "[NF_IP_POST_ROUTING]" } ``` :::spoiler ``` 封包傳入--->PRE------>[ROUTE]--->FWD---------->POST------>封包傳出 | ^ | | | | | [ROUTE] v | IN OUT | ^ | | v | 本機 本機 ``` ::: ### 3. iptables Tables and Chains iptables 中有一系列的 table,並根據要用來做什麼分為不同的 table,在每個 table 中,規則被進一步組織成 chain。 這邊以 filter 來介紹,最常用的 table 之一,用來判斷是否允許一個封包通過。 filter :主要跟進出 Linux 本機的封包有關 * INPUT:與想要進入我們 Linux 本機的封包有關 * OUTPUT:與我們 Linux 本機所要送出的封包有關 * FORWARD:轉遞封包到後端的電腦有關 規則放置在特定 table 的特定 chain 裡面。當 chain 被呼叫的時候,封包會依序比對 chain 裡面的規則,根據封包的資料比對先前定義的規則內容,若封包資料與規則內容相同則進行動作,否則就繼續下一條規則的比對。 :::danger 要解釋為何過濾的條件可讓 Linux 核心處理封包時,予以生效且可持續適用。中間有非常多細節,詳見 Linux 核心文件。 ::: ### 4. 過濾廣告 在過濾廣告之前,我們要先要知道廣告是如何成現在網頁上的: 1. 請求網頁:當我們進入一個網頁時,瀏覽器會向網頁伺服器發送請求。 2. 伺服器回應:網頁伺服器回應包含網頁內容和廣告服務提供者的 URL。 3. 廣告請求:瀏覽器根據回應中的 URL 向廣告伺服器發送請求。 4. 廣告回應:廣告伺服器回傳廣告內容(如圖片、影片)。 5. 顯示廣告:瀏覽器將廣告內容嵌入網頁並顯示。 **阻擋廣告的方法** 根據上面的流程我們不難發現,只要在步驟 3 的地方多加注意,則可以將向廣告伺服器送出的請求給阻擋下來,使得廣告最後不會成現在瀏覽的網頁上,我們通過以下方法可以阻擋向廣告伺服器的請求: - 修改 `/etc/hosts` 檔案:將提供廣告服務的網域映射到本地(127.0.0.1),這樣請求就不會發送到廣告伺服器。 - 防火牆設定:使用防火牆規則來阻擋特定廣告域名的請求 ## TODO: 重現[透過 Netfilter 自動過濾廣告](https://hackmd.io/@sysprog/BJb0NRYH3)實驗 > 在 Linux v6.8+ 重現實驗,並修正對應的程式碼。紀錄相關問題 > > 更新到 6.8.0-35-generic 後不能正常開機,問題尚未解決,所以目前是在 recovery mode 上使用 ### 2020 專案 嘗試透過 [ZhuMon](https://hackmd.io/@ZhuMon/2020q1_final_project) 先前有實作過的方式將網域 mapping 到 localhost - 將網域 mapping 到 localhost 為什麼可以將廣告 block 將域名和 IP 位址進行轉換時會使用 DNS,而在這之前會從瀏覽器中找有無暫存的 IP 位址,再來確認 hosts 檔案中是否有域名的映射,在這時將網域映射到 localhost 上來阻擋廣告。 :::danger 注意用語: * file 是「檔案」,而非「文件」(document) ::: 首先我們可以更改 `/etc/hosts` 檔案,將網域映射到 localhost 上,廣告的網域可以參考 [adblock.txt](https://raw.githubusercontent.com/notracking/hosts-blocklists/master/adblock/adblock.txt),也可以觀察常用網站的廣告來源,再自行加上。 ``` 127.0.0.1 itadapi.ithome.com.tw ``` 這使得當瀏覽器嘗試訪問 `itadapi.ithome.com.tw` 時,被指向 localhost,從而阻擋廣告。 我們也可以 `ping` 看看,可以看到 `itadapi.ithome.com.tw` 確實映射到 localhost ``` $ ping itadapi.ithome.com.tw PING itadapi.ithome.com.tw (127.0.0.1) 56(84) bytes of data. 64 bytes from localhost (127.0.0.1): icmp_seq=1 ttl=64 time=0.020 ms ``` 接來我們可以看網頁上的效果,這邊以 [OP.GG](https://www.op.gg/) 當範例 原本的網站,可以看到廣告非常多 ![螢幕快照 2024-06-27 17-12-12](https://hackmd.io/_uploads/BkCFM1kDR.png) 將網域映射到 localhost 後 ![螢幕快照 2024-06-27 17-23-15](https://hackmd.io/_uploads/HylizyJw0.png) ### 2023 專案 查看去年 [ItisCaleb](https://hackmd.io/@sysprog/BJb0NRYH3) 的 [Netfilter-Adblock](https://github.com/ItisCaleb/Netfilter-Adblock),根據他的說明依序操作,但目前無法找到 libnetfilter-dev 套件並安裝 參考之前都有提到的 [Use the iptables firewall to block ads on your Linux machine](https://www.securitronlinux.com/debian-testing/use-the-iptables-firewall-to-block-ads-on-your-linux-machine/) 的作法。 從先前的敘述我們可以知道要過濾封包的話,應該要在本機向廣告伺服器發送封包後,所以這邊要對 filter table 中的 OUTPUT chain 中新增規則。 可以參考這個[規則](https://pgl.yoyo.org/as/iplist.php?ipformat=iptables&showintro=1&mimetype=plaintext)作為測試 範例: ``` $ sudo iptables -A OUTPUT -o enp3s0f1 -d 103.31.6.33 -j REJECT ``` * -A :新增加一條規則,該規則增加在原本規則的最後面。 * -o :封包所傳出的那個網路介面。 * -d :目標 IP/網域。 * -j :後面接動作,主要的動作有接受(ACCEPT)、丟棄(DROP)、拒絕(REJECT)等。 將 rule 加到指定 chain 的最後,這邊是加到 filter table 的 OUTPUT chain 中,如果封包的目標的 IP 在 table 中,則會把封包拒絕傳出。 先以 `ifconfig` 確認網路介面的名稱,再把剛剛下載下來的 script 放到 `/etc/network/if-up.d` 底下修改並啟用,我自己也有新增一些規則。 我們可以列出 filter table 已經加入的規則。 ```shell $ sudo iptables -L -n Chain INPUT (policy ACCEPT) target prot opt source destination Chain FORWARD (policy ACCEPT) target prot opt source destination Chain OUTPUT (policy ACCEPT) target prot opt source destination REJECT 0 -- 0.0.0.0/0 54.64.57.143 reject-with icmp-port-unreachable REJECT 0 -- 0.0.0.0/0 54.250.30.69 reject-with icmp-port-unreachable REJECT 0 -- 0.0.0.0/0 46.8.8.100 reject-with icmp-port-unreachable REJECT 0 -- 0.0.0.0/0 185.53.178.52 reject-with icmp-port-unreachable REJECT 0 -- 0.0.0.0/0 172.217.163.34 reject-with icmp-port-unreachable ... ``` 再 `ping` 看看加入的網域,可以看到我們與廣告網域的連線將會逾時,以這種拒絕與特定網域傳送封包的方法來達到過濾廣告的效果。 ``` $ ping 103.245.223.131 PING 103.245.223.131 (103.245.223.131) 56(84) bytes of data. ^C --- 103.245.223.131 ping statistics --- 8 packets transmitted, 0 received, 100% packet loss, time 7156ms ``` 但在以 iptables 過濾廣告這部份的效果沒有很好, :::danger 避免說「沒有很好」,應該明確說廣告數量、網址類型的落差等量化資訊,理工人說話要精準且有效。 ::: 以前面測試的網站去測試,還是會看到許多廣告,也可能是腳本中加入的規則沒有網頁上的廣告來源,後來我嘗試把網頁上的廣告網域加上,但同時也發現一個問題,對於有些網域即使我把他加入到了規則中,但卻無法阻止與他的連線,這部份可能還要再想一下原因。 :::danger 去年的報告已解釋相關原因,注意看。 ::: 參考資料: * [鳥哥-防火牆與 NAT 伺服器](https://linux.vbird.org/linux_server/centos6/0250simple_firewall.php) * [2020 年開發紀錄](https://hackmd.io/@ZhuMon/2020q1_final_project) * [2023 年開發紀錄](https://hackmd.io/@sysprog/BJb0NRYH3) * [Use the iptables firewall to block ads on your Linux machine](https://www.securitronlinux.com/debian-testing/use-the-iptables-firewall-to-block-ads-on-your-linux-machine/)