linux 核心程式設計是我大三網絡安全這門課中黃老師講解的,這個簡單的防火牆是當時的實驗作業,由 netfilter 相關的知識實作,理論部分參考了一些《Linux網絡程式設計》的内容,這本書的下載下傳位址 https://www.jb51.net/books/626304.html
雖然現在的工作還用不到相關的技術,但是越來越覺得 netfilter 在開發安全工具方面有很多優勢,它可以把資料包過濾、網絡位址轉換和基于協定類型的連接配接跟蹤等在核心層面實作,是以現在把這個小執行個體翻出來溫故而知新,完整的代碼在 https://github.com/BEIWO778/netfilter-firewall
netfilter 是在 Linux 核心中一組鈎子,這些鈎子允許在網絡協定棧中使用核心子產品來注冊回調函數,可以處理協定棧中經過鈎子的每一個封包。是以可以利用它來實作許多功能,如過濾封包,修改封包等。netfilter 的架構就是在整個網絡流程的若幹位置放置了一些檢測點(HOOK),而在每個檢測點上登記了一些處理函數進行處理。在 IPv4 的協定棧中,netfilter 在 IP 資料包的路線上仔細選取了 5 個挂接點(HOOK)。這 5 個點中,在合适的位置對 NF_HOOK() 宏函數進行了調用,這 5 個點的含義如下所述
NF IP PRE ROUTING:剛剛進入網絡層而沒有進行路由之前的網絡資料會通過此點(進行完版本号、校驗和等檢測)
NF_IP_FORWARD:在接收到的網絡資料向另一個網卡進行轉發之前通過此點
NF IP_POST_ROUTING:任何馬上要通過網絡裝置出去的包通過此檢測點,這是 netfilter 的最後一個設定檢測的點,内置的目的位址轉換功能(包括位址僞裝)在此點進行
NF _IP_LOCAL_IN:在接收到的封包做路由,确定是本機接收的封包之後
NF_ IP LOCAL_OUT:在本地封包做發送路由之前
這個小執行個體就是處理 NF_IP_LOCAL_IN 這個檢測點,對 Linux 主機接收的資料包進行過濾。而對于使用者與核心之間通信功能,則使用 sockopt 來實作,5 個挂接點書中的流程圖如下:

在網上沖浪又找到一個更詳細的圖:
頭檔案初始化一些狀态宏,設定驅動程式處理的最小值與最大值,然後在這之間設定防火牆不同功能的編号,盡量設定大一點避免與核心中某些指令值重複。結構體則用于存儲防火牆的過濾規則資訊
firewall/filter/fwfilter.h
過濾網絡封包功能的實作主要使用 hookLocalIn 函數。ban ping 功能的實作是如果檢測到是 ICMP 資料包,并且設定了禁用 ping 指令規則,則丢棄該 ICMP 資料包
ban port 功能的實作是如果設定了禁用端口規則,并且源端口符合使用者設定的端口,則丢棄發往該端口的所有的資料包
ban ip 功能的實作是如果設定了禁用 ip 規則,并且源 ip 位址符合,丢棄該源 ip 發送的資料包
從《Linux網絡程式設計》書中截取的這三個功能流程圖
核心空間和使用者空間的通信則是使用 hookSockoptSet() 函數和 hookSockoptGet() 函數,hookSockoptSet() 函數擷取使用者空間的指令資訊,主要用到 copy_from_user() 函數,複制使用者空間的資料到核心子產品,然後按照使用者的指令執行過濾規則
hookSockoptGet() 函數将核心子產品的防火牆的規則情況傳輸給使用者空間,主要用到 copy_to_user() 函數,複制核心空間的資料到使用者空間
get_status() 函數分别擷取目前防火牆三個功能的狀态,若有禁止的 ip 或端口則列印出來詳細禁止資訊
改變 ping 規則時函數将目前 ping 狀态取反,再把資訊傳到核心
改變 ip 規則函數,首先判斷目前是否有 ip 已封禁,若目前無封禁 ip,則改變 ip 狀态,由使用者輸入需封禁 ip,這裡需要注意使用 inet_addr 函數轉換 ip 格式。若目前已有封禁 ip,則直接取消封禁,再把資訊傳到核心
改變端口規則函數,首先判斷目前是否有端口已封禁,若目前無封禁端口,則改變端口狀态,由使用者輸入需封禁端口。若目前已有封禁端口,則直接取消封禁,再把資訊傳到核心
編譯核心的 Makefile 檔案中指定核心子產品的編譯檔案和頭檔案路徑,編譯子產品的名稱,目前子產品的路徑
firewall/filter/Makefile
在 /firewall/filter 路徑下編譯、加載核心
在 /firewall/app 路徑下編譯應用層測試代碼,運作應用層程式
vps 版本為 ubuntu 18.04,核心版本為 4.15.0-136-generic,程式運作效果就不測試了,再補充一點核心中列印使用 printk() 函數,dmesg 指令可以得到核心中列印的資訊,他們可以配合着進行簡單的核心調試
範師傅對于 netfilter 防火牆和 iptables 防火牆的了解我一直記着,覺得很形象生動,這裡給大家參考,iptables 就是自行車的腳踏闆,netfilter 就是自行車輪子,自行車動起來底層都是使用了輪子推進,即防火牆的底層都是使用 netfilter 來進行資料包過濾
核心程式設計很依賴核心版本,經常網上的代碼因為核心版本問題跑不起來,聽說 ebpf 可以解決這個問題,打算學習一下
參考文章:
https://www.ebpf.top/post/iptalbes_ebpf/