学习了 Linux netfilter 钩子执行过程,接下来在内核模块里实现一个自定义的 netfilter
钩子。
netfilter 的网络包处理流程
下图比较详细地描述了 iptables 和 ebtables 的规则执行时机:
图片来源:wikimedia
自定义钩子实验:谁在连接我
如上图,网络层中有 5 条规则链:PREROUTING、INPUT、FORWARD、OUTPUT、POSTROUTING。我们可以忽略 raw、mangle、nat、filter 等表的定义,因为在内核 netfilter 框架里是没有这些表的概念的;这几张表的定义都存在于 iptables 中。
为了记录是谁尝试跟我进行 TCP 连接,需要在 hook 中判断当前网络包是不是 TCP SYN 包;
该 hook 需要放在 PREROUTING 或者 INPUT 链中。自定义 hook 的代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
unsigned int who_connect_me_hook(void *priv,
struct sk_buff *skb,
const struct nf_hook_state *state)
{
__be32 saddr, daddr;
struct iphdr *iphdr;
struct tcphdr *tcphdr;
// 从 skb 中获取 IP 协议头
iphdr = (struct iphdr *)skb_network_header(skb);
saddr = iphdr->saddr;
daddr = iphdr->daddr;
if (iphdr->protocol == IPPROTO_TCP) {
// 从 skb 中获取 TCP 协议头
tcphdr = (struct tcphdr *)skb_transport_header(skb);
if (tcphdr->syn) { // 判断是不是 SYN 包
// 将源 IP 和源端口打印出来
printk(KERN_INFO "[who_connect_me] [%pI4:%d -> %pI4:%d]\n",
(unsigned char *)(&saddr), ntohs(tcphdr->source),
(unsigned char *)(&daddr), ntohs(tcphdr->dest));
}
}
return NF_ACCEPT;
}
|
最终效果如下:
源代码:github.com/Asphaltt/kernel-module-fun
总结
纸上得来终觉浅,绝知此事要躬行。