文章目錄
-
- 功能描述
- 功能實作
- 源碼
- 輸出結果
- 作者簡介
- 源碼和文檔
功能描述
通過netfilter實作資料封包的解析,檢視所有資料包内容,類似于wireshark檢視資料流的功能。我們通常用的tcpdump指令,采用了libpcap庫,底層用的是AF_PACKET協定,該協定會将資料封包拷貝一份(核心到應用層零拷貝)到應用層。
但AF_PACKET會将所有資料拷貝,比較耗性能,在開發過程中我們往往隻需要檢視關鍵資訊,比如端口、ip、url等,這裡我們實作基于netfilter架構将資料封包輸出到核心日志,檢視資料互動的整個流程,當然後續可以自己加以完善,結合netlink或者共享記憶體将資料上報到應用層程序,實作資料審計。
功能實作
- 添加一個核心子產品
- 核心子產品注冊netfilter鈎子函數,用于攔截資料封包
- 鈎子函數中對封包的基本資訊解析,比如ip、端口、協定等
- 資料輸出,将data部分輸出到日志,并支援ascii顯示
源碼
#include <linux/init.h>
#include <linux/module.h>
#include <linux/version.h>
#include <linux/netfilter.h>
#include <net/netfilter/nf_conntrack.h>
#include <linux/skbuff.h>
#include <net/ip.h>
#include <linux/types.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("openwrt");
MODULE_DESCRIPTION("pkt_capture");
#define MAX_CAPTURE_DATA_LEN 1500
void dump_l4_data(u_int8_t *data, u_int32_t len){
int i;
int j;
int tmp_index = 0;
u_int8_t tmp_data[32] = {0};
for (i = 0; i < len && i < MAX_CAPTURE_DATA_LEN; i++){
if (i % 16 == 0){
if (i != 0){
for (j = 0; j < 16; j++)
printk(KERN_CONT "%02X ", tmp_data[j]);
printk(KERN_CONT "%s", " ");
for (j = 0; j < 16; j++){
if (tmp_data[j] > 32 && tmp_data[j] <= 127)
printk(KERN_CONT "%c", tmp_data[j]);
else
printk(KERN_CONT "%c", '.');
}
printk(KERN_CONT "\n");
}
tmp_index = 0;
}
tmp_data[tmp_index++] = data[i];
}
printk(KERN_CONT"\n");
}
static u_int32_t pkt_capture_hook(void *priv, struct sk_buff *skb, const struct nf_hook_state *state) {
struct nf_conn *ct = (struct nf_conn *)skb->_nfct;
struct udphdr * udph = NULL;
struct tcphdr * tcph = NULL;
struct iphdr *iph = NULL;
if(ct == NULL || !nf_ct_is_confirmed(ct)) {
return NF_ACCEPT;
}
iph = ip_hdr(skb);
if (!iph)
return NF_ACCEPT;
u_int8_t *l4_data = NULL;
u_int32_t l4_len = 0;
u_int16_t sport = 0;
u_int16_t dport = 0;
switch (iph->protocol){
case IPPROTO_UDP:
udph = (struct udphdr *)(iph + 1);
sport = htons(udph->source);
dport = htons(udph->dest);
break;
case IPPROTO_TCP:
tcph = (struct tcphdr *)(iph + 1);
dport = htons(tcph->dest);
sport = htons(tcph->source);
break;
default:
printk("ignore proto %d\n", iph->protocol);
return NF_ACCEPT;
}
printk(KERN_CONT"%-6s %pI4:%-6u-->%pI4:%-6u\n", iph->protocol == IPPROTO_UDP ? "UDP": "TCP",
&iph->saddr, sport, &iph->daddr, dport);
dump_l4_data(skb->data, skb->len);
return NF_ACCEPT;
}
static struct nf_hook_ops pkt_capture_ops[] __read_mostly = {
{
.hook = pkt_capture_hook,
.pf = PF_INET,
.hooknum = NF_INET_FORWARD,
.priority = NF_IP_PRI_MANGLE + 1,
},
};
static int __init pkt_capture_init(void)
{
nf_register_net_hooks(&init_net, pkt_capture_ops, ARRAY_SIZE(pkt_capture_ops));
return 0;
}
static void pkt_capture_exit(void)
{
nf_unregister_net_hooks(&init_net, pkt_capture_ops, ARRAY_SIZE(pkt_capture_ops));
return ;
}
module_init(pkt_capture_init);
module_exit(pkt_capture_exit);
輸出結果
作者簡介
OpenWrt應用過濾插件作者(應用過濾用于控制app聯網,可以過濾遊戲、視訊、聊天等幾百款app)
從事嵌入式Linux開發近10年,主要負責路由器網通産品研發,精通OpenWrt系統,包括luci、消息機制、核心子產品等。擅長子產品:路由器上網行為管理、智能流控、上網認證、防火牆、虛拟伺服器、多wan負載均衡等
開源作品位址:
https://github.com/destan19/OpenAppFilter
源碼和文檔
關注微信公衆号可以擷取更多技術文檔、固件、源碼等
微信掃碼關注: